From 92690302bb939d18973a1d3ae2f6ed9b59644dd2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 1 Dec 2019 13:49:38 -0800 Subject: [PATCH 0001/1185] updates --- train.py | 1 + 1 file changed, 1 insertion(+) diff --git a/train.py b/train.py index ad3286560e..59e936191a 100644 --- a/train.py +++ b/train.py @@ -43,6 +43,7 @@ # Overwrite hyp with hyp*.txt (optional) f = glob.glob('hyp*.txt') if f: + print('Using %s' % f) for k, v in zip(hyp.keys(), np.loadtxt(f[0])): hyp[k] = v From d6a7a614dc35120a7704a979d171cc967510b978 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 1 Dec 2019 13:51:55 -0800 Subject: [PATCH 0002/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 59e936191a..67996e4e2e 100644 --- a/train.py +++ b/train.py @@ -43,7 +43,7 @@ # Overwrite hyp with hyp*.txt (optional) f = glob.glob('hyp*.txt') if f: - print('Using %s' % f) + print('Using %s' % f[0]) for k, v in zip(hyp.keys(), np.loadtxt(f[0])): hyp[k] = v From e637ae44ddb2f0ebd0db34972cbd08fc6e1f4f75 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 1 Dec 2019 14:06:11 -0800 Subject: [PATCH 0003/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 67996e4e2e..5a46c66816 100644 --- a/train.py +++ b/train.py @@ -24,7 +24,7 @@ hyp = {'giou': 3.31, # giou loss gain 'cls': 42.4, # cls loss gain 'cls_pw': 1.0, # cls BCELoss positive_weight - 'obj': 52.0, # obj loss gain (*=img_size/320 if img_size != 320) + 'obj': 52.0, # obj loss gain (*=img_size/416 if img_size != 416) 'obj_pw': 1.0, # obj BCELoss positive_weight 'iou_t': 0.213, # iou training threshold 'lr0': 0.00261, # initial learning rate (SGD=1E-3, Adam=9E-5) From 3d91731519dcbea9a1a2047817ba83ce1441358f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 1 Dec 2019 14:07:09 -0800 Subject: [PATCH 0004/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 5a46c66816..617cd51893 100644 --- a/train.py +++ b/train.py @@ -20,7 +20,7 @@ best = wdir + 'best.pt' results_file = 'results.txt' -# Hyperparameters (k-series, 57.7 mAP yolov3-spp-416) https://github.com/ultralytics/yolov3/issues/310 +# Hyperparameters (results68: 59.2 mAP@0.5 yolov3-spp-416) https://github.com/ultralytics/yolov3/issues/310 hyp = {'giou': 3.31, # giou loss gain 'cls': 42.4, # cls loss gain 'cls_pw': 1.0, # cls BCELoss positive_weight From 93a70d958a1138b082f7b5c29c550b7d383f56f3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 2 Dec 2019 11:31:19 -0800 Subject: [PATCH 0005/1185] updates --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 617cd51893..a13433cadc 100644 --- a/train.py +++ b/train.py @@ -404,8 +404,8 @@ def prebias(): if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--epochs', type=int, default=273) # 500200 batches at bs 16, 117263 images = 273 epochs - parser.add_argument('--batch-size', type=int, default=32) # effective bs = batch_size * accumulate = 16 * 4 = 64 - parser.add_argument('--accumulate', type=int, default=2, help='batches to accumulate before optimizing') + parser.add_argument('--batch-size', type=int, default=16) # effective bs = batch_size * accumulate = 16 * 4 = 64 + parser.add_argument('--accumulate', type=int, default=4, help='batches to accumulate before optimizing') parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='cfg file path') parser.add_argument('--data', type=str, default='data/coco.data', help='*.data file path') parser.add_argument('--multi-scale', action='store_true', help='adjust (67% - 150%) img_size every 10 batches') From d68a59bffcbfbbe5df488c89104fa10f127de23c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 2 Dec 2019 14:23:20 -0800 Subject: [PATCH 0006/1185] updates --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 632f8d7cfc..040a9a572c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -53,13 +53,13 @@ COPY . /usr/src/app # sudo nvidia-docker run --ipc=host ultralytics/yolov3:v0 python3 detect.py # Run with local directory access -# sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco ultralytics/yolov3:v0 python3 train.py +# sudo nvidia-docker run --ipc=host -it -v "$(pwd)"/coco:/usr/src/coco ultralytics/yolov3:v0 # Pull and Run with local directory access -# export tag=ultralytics/yolov3:v0 && sudo docker pull $tag && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $tag +# export t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t # Build and Push -# export tag=ultralytics/yolov3:v0 && sudo docker build -t $tag . && sudo docker push $tag +# export t=ultralytics/yolov3:v0 && sudo docker build -t $t . && sudo docker push $t # Kill all # sudo docker kill "$(sudo docker ps -q)" From ebb4d4c884fd7cbc086fce15f361ccb149a834de Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 2 Dec 2019 14:31:04 -0800 Subject: [PATCH 0007/1185] updates --- utils/datasets.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 340cfdb85a..b54eee64f9 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -523,23 +523,6 @@ def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5): cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR, dst=img) # no return needed -# def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5): # original version -# # SV augmentation by 50% -# img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # hue, sat, val -# -# S = img_hsv[:, :, 1].astype(np.float32) # saturation -# V = img_hsv[:, :, 2].astype(np.float32) # value -# -# a = random.uniform(-1, 1) * sgain + 1 -# b = random.uniform(-1, 1) * vgain + 1 -# S *= a -# V *= b -# -# img_hsv[:, :, 1] = S if a < 1 else S.clip(None, 255) -# img_hsv[:, :, 2] = V if b < 1 else V.clip(None, 255) -# cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR, dst=img) # no return needed - - def load_mosaic(self, index): # loads images in a mosaic From cba3120ca6171c9e470cbb4ca857a12aafb31b7e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 2 Dec 2019 15:26:36 -0800 Subject: [PATCH 0008/1185] updates --- utils/datasets.py | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index b54eee64f9..dc12421b0c 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -411,6 +411,7 @@ def __getitem__(self, index): img_path = self.img_files[index] label_path = self.label_files[index] + hyp = self.hyp mosaic = True and self.augment # load 4 images at a time into a mosaic (only during training) if mosaic: # Load mosaic @@ -444,17 +445,16 @@ def __getitem__(self, index): labels[:, 4] = ratio[1] * h * (x[:, 2] + x[:, 4] / 2) + pad[1] if self.augment: - # Augment colorspace - augment_hsv(img, hgain=self.hyp['hsv_h'], sgain=self.hyp['hsv_s'], vgain=self.hyp['hsv_v']) - # Augment imagespace - g = 0.0 if mosaic else 1.0 # do not augment mosaics - hyp = self.hyp - img, labels = random_affine(img, labels, - degrees=hyp['degrees'] * g, - translate=hyp['translate'] * g, - scale=hyp['scale'] * g, - shear=hyp['shear'] * g) + if not mosaic: + img, labels = random_affine(img, labels, + degrees=hyp['degrees'], + translate=hyp['translate'], + scale=hyp['scale'], + shear=hyp['shear']) + + # Augment colorspace + augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) # Apply cutouts # if random.random() < 0.9: @@ -573,21 +573,18 @@ def load_mosaic(self, index): labels = np.zeros((0, 5), dtype=np.float32) labels4.append(labels) + # Concat/clip labels if len(labels4): labels4 = np.concatenate(labels4, 0) + np.clip(labels4[:, 1:], 0, 2 * s, out=labels4[:, 1:]) - # hyp = self.hyp - # img4, labels4 = random_affine(img4, labels4, - # degrees=hyp['degrees'], - # translate=hyp['translate'], - # scale=hyp['scale'], - # shear=hyp['shear']) - - # Center crop - a = s // 2 - img4 = img4[a:a + s, a:a + s] - if len(labels4): - labels4[:, 1:] -= a + # Augment + img4, labels4 = random_affine(img4, labels4, + degrees=self.hyp['degrees'], + translate=self.hyp['translate'], + scale=self.hyp['scale'], + shear=self.hyp['shear'], + border=-s // 2) # border to remove return img4, labels4 @@ -626,13 +623,12 @@ def letterbox(img, new_shape=(416, 416), color=(128, 128, 128), return img, ratio, (dw, dh) -def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10): +def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, border=0): # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) # https://medium.com/uruvideo/dataset-augmentation-with-random-homographies-a8f4b44830d4 if targets is None: # targets = [cls, xyxy] targets = [] - border = 0 # width of added border (optional) height = img.shape[0] + border * 2 width = img.shape[1] + border * 2 From cadd2f75ff5108818048cf48af8a5e8558acf6ee Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 2 Dec 2019 16:46:15 -0800 Subject: [PATCH 0009/1185] updates --- requirements.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index a475a45c38..bb6e49e91f 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,16 @@ -# pip3 install -U -r requirements.txt +# pip install -U -r requirements.txt numpy opencv-python torch >= 1.3 matplotlib pycocotools tqdm -tb-nightly -future Pillow +# Tensorboard pip requirements ------------------------------------------------- +# tb-nightly +# future + # Equivalent conda commands ---------------------------------------------------- # conda update -n base -c defaults conda # conda install -yc anaconda future numpy opencv matplotlib tqdm pillow From 0fe246f3995dc77367d6c8d6158c9112ff8a309f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 2 Dec 2019 18:22:21 -0800 Subject: [PATCH 0010/1185] updates --- utils/utils.py | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 1208398822..3984d20b6e 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -1,4 +1,5 @@ import glob +import math import os import random import shutil @@ -10,8 +11,8 @@ import numpy as np import torch import torch.nn as nn +import torchvision from tqdm import tqdm -import math from . import torch_utils # , google_utils @@ -503,7 +504,6 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): # Box (center x, center y, width, height) to (x1, y1, x2, y2) pred[:, :4] = xywh2xyxy(pred[:, :4]) - # pred[:, 4] *= class_conf # improves mAP from 0.549 to 0.551 # Detections ordered as (x1y1x2y2, obj_conf, class_conf, class_pred) pred = torch.cat((pred[:, :5], class_conf.unsqueeze(1), class_pred), 1) @@ -511,8 +511,21 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): # Get detections sorted by decreasing confidence scores pred = pred[(-pred[:, 4]).argsort()] + # Set NMS method https://github.com/ultralytics/yolov3/issues/679 + # 'OR', 'AND', 'MERGE', 'VISION', 'VISION_BATCHED' + method = 'MERGE' if conf_thres <= 0.01 else 'VISION' # MERGE is highest mAP, VISION is fastest + + # Batched NMS + if method == 'VISION_BATCHED': + i = torchvision.ops.boxes.batched_nms(boxes=pred[:, :4], + scores=pred[:, 4], + idxs=pred[:, 6], + iou_threshold=nms_thres) + output[image_i] = pred[i] + continue + + # Non-maximum suppression det_max = [] - nms_style = 'MERGE' # 'OR' (default), 'AND', 'MERGE' (experimental) for c in pred[:, -1].unique(): dc = pred[pred[:, -1] == c] # select class c n = len(dc) @@ -520,10 +533,13 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): det_max.append(dc) # No NMS required if only 1 prediction continue elif n > 500: - dc = dc[:500] # limit to first 100 boxes: https://github.com/ultralytics/yolov3/issues/117 + dc = dc[:500] # limit to first 500 boxes: https://github.com/ultralytics/yolov3/issues/117 + + if method == 'VISION': + i = torchvision.ops.boxes.nms(dc[:, :4], dc[:, 4], nms_thres) + det_max.append(dc[i]) - # Non-maximum suppression - if nms_style == 'OR': # default + elif method == 'OR': # default # METHOD1 # ind = list(range(len(dc))) # while len(ind): @@ -540,14 +556,14 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes dc = dc[1:][iou < nms_thres] # remove ious > threshold - elif nms_style == 'AND': # requires overlap, single boxes erased + elif method == 'AND': # requires overlap, single boxes erased while len(dc) > 1: iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes if iou.max() > 0.5: det_max.append(dc[:1]) dc = dc[1:][iou < nms_thres] # remove ious > threshold - elif nms_style == 'MERGE': # weighted mixture box + elif method == 'MERGE': # weighted mixture box while len(dc): if len(dc) == 1: det_max.append(dc) @@ -558,7 +574,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): det_max.append(dc[:1]) dc = dc[i == 0] - elif nms_style == 'SOFT': # soft-NMS https://arxiv.org/abs/1704.04503 + elif method == 'SOFT': # soft-NMS https://arxiv.org/abs/1704.04503 sigma = 0.5 # soft-nms sigma parameter while len(dc): if len(dc) == 1: From 1e9ddc5a90057d39fb47af52737dd24e99db2f07 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 2 Dec 2019 19:44:10 -0800 Subject: [PATCH 0011/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 3984d20b6e..ae02b9f99d 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -584,7 +584,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes dc = dc[1:] dc[:, 4] *= torch.exp(-iou ** 2 / sigma) # decay confidences - # dc = dc[dc[:, 4] > nms_thres] # new line per https://github.com/ultralytics/yolov3/issues/362 + dc = dc[dc[:, 4] > conf_thres] # https://github.com/ultralytics/yolov3/issues/362 if len(det_max): det_max = torch.cat(det_max) # concatenate From f6caec195de20d48c9a3634edcf5a46ab7ff291e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 3 Dec 2019 12:32:43 -0800 Subject: [PATCH 0012/1185] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 7b4d9efdc6..701ff54c27 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,20 +7,19 @@ assignees: '' --- -**Describe the bug** +## 🐛 Bug A clear and concise description of what the bug is. -**To Reproduce** +## To Reproduce Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error +1. +2. +3. -**Expected behavior** +## Expected behavior A clear and concise description of what you expected to happen. -**Screenshots** +## Environment If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** @@ -32,5 +31,5 @@ If applicable, add screenshots to help explain your problem. - OS: [e.g. iOS8.1] - Version [e.g. 22] -**Additional context** +## Additional context Add any other context about the problem here. From 89e908dbb315f152ec066bc44f7de852876f2f79 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 3 Dec 2019 12:35:00 -0800 Subject: [PATCH 0013/1185] Update issue templates --- .github/ISSUE_TEMPLATE/feature_request.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 11fc491ef1..be8fea82d4 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -7,14 +7,21 @@ assignees: '' --- -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] +## 🚀 Feature + -**Describe the solution you'd like** -A clear and concise description of what you want to happen. +## Motivation -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. + -**Additional context** -Add any other context or screenshots about the feature request here. +## Pitch + + + +## Alternatives + + + +## Additional context + + From 384b2990997df9519221b5cb499fe165ac286bca Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 3 Dec 2019 12:35:57 -0800 Subject: [PATCH 0014/1185] Update issue templates --- .github/ISSUE_TEMPLATE/--bug-report.md | 35 +++++++++++++++++++++ .github/ISSUE_TEMPLATE/--feature-request.md | 27 ++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/--bug-report.md create mode 100644 .github/ISSUE_TEMPLATE/--feature-request.md diff --git a/.github/ISSUE_TEMPLATE/--bug-report.md b/.github/ISSUE_TEMPLATE/--bug-report.md new file mode 100644 index 0000000000..7a58967586 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/--bug-report.md @@ -0,0 +1,35 @@ +--- +name: "\U0001F41BBug report" +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +## 🐛 Bug +A clear and concise description of what the bug is. + +## To Reproduce +Steps to reproduce the behavior: +1. +2. +3. + +## Expected behavior +A clear and concise description of what you expected to happen. + +## Environment +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhoneXS] + - OS: [e.g. iOS8.1] + - Version [e.g. 22] + +## Additional context +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/--feature-request.md b/.github/ISSUE_TEMPLATE/--feature-request.md new file mode 100644 index 0000000000..b16020d201 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/--feature-request.md @@ -0,0 +1,27 @@ +--- +name: "\U0001F680Feature request" +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +## 🚀 Feature + + +## Motivation + + + +## Pitch + + + +## Alternatives + + + +## Additional context + + From 7bd828859c9b5dba07526829b545aff883489376 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 3 Dec 2019 12:36:26 -0800 Subject: [PATCH 0015/1185] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 35 ----------------------- .github/ISSUE_TEMPLATE/feature_request.md | 27 ----------------- 2 files changed, 62 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 701ff54c27..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: bug -assignees: '' - ---- - -## 🐛 Bug -A clear and concise description of what the bug is. - -## To Reproduce -Steps to reproduce the behavior: -1. -2. -3. - -## Expected behavior -A clear and concise description of what you expected to happen. - -## Environment -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhoneXS] - - OS: [e.g. iOS8.1] - - Version [e.g. 22] - -## Additional context -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index be8fea82d4..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: enhancement -assignees: '' - ---- - -## 🚀 Feature - - -## Motivation - - - -## Pitch - - - -## Alternatives - - - -## Additional context - - From c865d93403cefae822eac363490c4e6dcb1d1389 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 3 Dec 2019 12:50:04 -0800 Subject: [PATCH 0016/1185] updates --- README.md | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 87633b2d41..879b4b7f95 100755 --- a/README.md +++ b/README.md @@ -153,12 +153,93 @@ YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |512 |16.6
YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |608 |16.6
33.1
37.0
**40.9** |35.4
58.2
60.7
**60.9** ```bash -$ python3 test.py --save-json --img-size 608 --nms-thres 0.7 --weights ultralytics68.pt +$ python3 test.py --save-json --img-size 608 --nms-thres 0.5 --weights ultralytics68.pt + Namespace(batch_size=16, cfg='cfg/yolov3-spp.cfg', conf_thres=0.001, data='data/coco.data', device='1', img_size=608, iou_thres=0.5, nms_thres=0.7, save_json=True, weights='ultralytics68.pt') Using CUDA device0 _CudaDeviceProperties(name='GeForce RTX 2080 Ti', total_memory=11019MB) Class Images Targets P R mAP@0.5 F1: 100%|███████████████████████████████████████████████████████████████████████████████████| 313/313 [09:46<00:00, 1.09it/s] - all 5e+03 3.58e+04 0.0481 0.829 0.589 0.0894 + all 5e+03 3.58e+04 0.0823 0.798 0.595 0.145 + person 5e+03 1.09e+04 0.0999 0.903 0.771 0.18 + bicycle 5e+03 316 0.0491 0.782 0.56 0.0925 + car 5e+03 1.67e+03 0.0552 0.845 0.646 0.104 + motorcycle 5e+03 391 0.11 0.847 0.704 0.194 + airplane 5e+03 131 0.099 0.947 0.878 0.179 + bus 5e+03 261 0.142 0.874 0.825 0.244 + train 5e+03 212 0.152 0.863 0.806 0.258 + truck 5e+03 352 0.0849 0.682 0.514 0.151 + boat 5e+03 475 0.0498 0.787 0.504 0.0937 + traffic light 5e+03 516 0.0304 0.752 0.516 0.0584 + fire hydrant 5e+03 83 0.144 0.916 0.882 0.248 + stop sign 5e+03 84 0.0833 0.917 0.809 0.153 + parking meter 5e+03 59 0.0607 0.695 0.611 0.112 + bench 5e+03 473 0.0294 0.685 0.363 0.0564 + bird 5e+03 469 0.0521 0.716 0.524 0.0972 + cat 5e+03 195 0.252 0.908 0.78 0.395 + dog 5e+03 223 0.192 0.883 0.829 0.315 + horse 5e+03 305 0.121 0.911 0.843 0.214 + sheep 5e+03 321 0.114 0.854 0.724 0.201 + cow 5e+03 384 0.105 0.849 0.695 0.187 + elephant 5e+03 284 0.184 0.944 0.912 0.308 + bear 5e+03 53 0.358 0.925 0.875 0.516 + zebra 5e+03 277 0.176 0.935 0.858 0.297 + giraffe 5e+03 170 0.171 0.959 0.892 0.29 + backpack 5e+03 384 0.0426 0.708 0.392 0.0803 + umbrella 5e+03 392 0.0672 0.878 0.65 0.125 + handbag 5e+03 483 0.0238 0.629 0.242 0.0458 + tie 5e+03 297 0.0419 0.805 0.599 0.0797 + suitcase 5e+03 310 0.0823 0.855 0.628 0.15 + frisbee 5e+03 109 0.126 0.872 0.796 0.221 + skis 5e+03 282 0.0473 0.748 0.454 0.089 + snowboard 5e+03 92 0.0579 0.804 0.559 0.108 + sports ball 5e+03 236 0.057 0.733 0.622 0.106 + kite 5e+03 399 0.087 0.852 0.645 0.158 + baseball bat 5e+03 125 0.0496 0.776 0.603 0.0932 + baseball glove 5e+03 139 0.0511 0.734 0.563 0.0956 + skateboard 5e+03 218 0.0655 0.844 0.73 0.122 + surfboard 5e+03 266 0.0709 0.827 0.651 0.131 + tennis racket 5e+03 183 0.0694 0.858 0.759 0.128 + bottle 5e+03 966 0.0484 0.812 0.513 0.0914 + wine glass 5e+03 366 0.0735 0.738 0.543 0.134 + cup 5e+03 897 0.0637 0.788 0.538 0.118 + fork 5e+03 234 0.0411 0.662 0.487 0.0774 + knife 5e+03 291 0.0334 0.557 0.292 0.0631 + spoon 5e+03 253 0.0281 0.621 0.307 0.0537 + bowl 5e+03 620 0.0624 0.795 0.514 0.116 + banana 5e+03 371 0.052 0.83 0.41 0.0979 + apple 5e+03 158 0.0293 0.741 0.262 0.0564 + sandwich 5e+03 160 0.0913 0.725 0.522 0.162 + orange 5e+03 189 0.0382 0.688 0.32 0.0723 + broccoli 5e+03 332 0.0513 0.88 0.445 0.097 + carrot 5e+03 346 0.0398 0.766 0.362 0.0757 + hot dog 5e+03 164 0.0958 0.646 0.494 0.167 + pizza 5e+03 224 0.0886 0.875 0.699 0.161 + donut 5e+03 237 0.0925 0.827 0.64 0.166 + cake 5e+03 241 0.0658 0.71 0.539 0.12 + chair 5e+03 1.62e+03 0.0432 0.793 0.489 0.0819 + couch 5e+03 236 0.118 0.801 0.584 0.205 + potted plant 5e+03 431 0.0373 0.852 0.505 0.0714 + bed 5e+03 195 0.149 0.846 0.693 0.253 + dining table 5e+03 634 0.0546 0.82 0.49 0.102 + toilet 5e+03 179 0.161 0.95 0.81 0.275 + tv 5e+03 257 0.0922 0.903 0.79 0.167 + laptop 5e+03 237 0.127 0.869 0.744 0.222 + mouse 5e+03 95 0.0648 0.863 0.732 0.12 + remote 5e+03 241 0.0436 0.788 0.535 0.0827 + keyboard 5e+03 117 0.0668 0.923 0.755 0.125 + cell phone 5e+03 291 0.0364 0.704 0.436 0.0692 + microwave 5e+03 88 0.154 0.841 0.743 0.261 + oven 5e+03 142 0.0618 0.803 0.576 0.115 + toaster 5e+03 11 0.0565 0.636 0.191 0.104 + sink 5e+03 211 0.0439 0.853 0.544 0.0835 + refrigerator 5e+03 107 0.0791 0.907 0.742 0.145 + book 5e+03 1.08e+03 0.0399 0.667 0.233 0.0753 + clock 5e+03 292 0.0542 0.836 0.733 0.102 + vase 5e+03 353 0.0675 0.799 0.591 0.125 + scissors 5e+03 56 0.0397 0.75 0.461 0.0755 + teddy bear 5e+03 245 0.0995 0.882 0.669 0.179 + hair drier 5e+03 11 0.00508 0.0909 0.0475 0.00962 + toothbrush 5e+03 77 0.0371 0.74 0.418 0.0706 Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.40882 Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.60026 From 896fd6d02541b5299c17d8a232b9952da2cf7fe7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 3 Dec 2019 12:52:19 -0800 Subject: [PATCH 0017/1185] updates --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 879b4b7f95..4973a2316c 100755 --- a/README.md +++ b/README.md @@ -261,4 +261,4 @@ Using CUDA device0 _CudaDeviceProperties(name='GeForce RTX 2080 Ti', total_memor # Contact -Issues should be raised directly in the repository. For additional questions or comments please email Glenn Jocher at glenn.jocher@ultralytics.com or visit us at https://contact.ultralytics.com. +**Issues should be raised directly in the repository.** For additional questions or comments please email Glenn Jocher at glenn.jocher@ultralytics.com or visit us at https://contact.ultralytics.com. From 0dd0fa7938f605833c85084f7f184445ca0b6fee Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 3 Dec 2019 13:34:22 -0800 Subject: [PATCH 0018/1185] updates --- utils/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index ae02b9f99d..f7b8018725 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -449,7 +449,8 @@ def build_targets(model, targets): # Class tcls.append(c) if c.shape[0]: # if any targets - assert c.max() <= model.nc, 'Target classes exceed model classes' + assert c.max() <= model.nc, 'Model accepts %g classes labeled from 0-%g, however you supplied a label %g. \ + See https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' % (model.nc, model.nc - 1, c.max()) return tcls, tbox, indices, av From fcdbd3ee350cf631c73d13df937a3487fe2464b1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 3 Dec 2019 13:49:20 -0800 Subject: [PATCH 0019/1185] updates --- utils/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index f7b8018725..fe143fdbd7 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -449,8 +449,9 @@ def build_targets(model, targets): # Class tcls.append(c) if c.shape[0]: # if any targets - assert c.max() <= model.nc, 'Model accepts %g classes labeled from 0-%g, however you supplied a label %g. \ - See https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' % (model.nc, model.nc - 1, c.max()) + assert c.max() < model.nc, 'Model accepts %g classes labeled from 0-%g, however you labelled a class %g. ' \ + 'See https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' % ( + model.nc, model.nc - 1, c.max()) return tcls, tbox, indices, av From cae901c2da791166ce766aa42139298f794d772f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 3 Dec 2019 15:34:20 -0800 Subject: [PATCH 0020/1185] updates --- models.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/models.py b/models.py index 6401ab6cc7..17ff234f41 100755 --- a/models.py +++ b/models.py @@ -51,6 +51,7 @@ def create_modules(module_defs, img_size, arc): elif mdef['type'] == 'upsample': modules = nn.Upsample(scale_factor=int(mdef['stride']), mode='nearest') + # modules = Upsample(scale_factor=int(mdef['stride'])) elif mdef['type'] == 'route': # nn.Sequential() placeholder for 'route' layer layers = [int(x) for x in mdef['layers'].split(',')] @@ -141,6 +142,16 @@ def forward(self, x): return x.mul_(F.softplus(x).tanh()) +class Upsample(nn.Module): + def __init__(self, scale_factor): + super(Upsample, self).__init__() + self.scale = scale_factor + + def forward(self, x): + h, w = x.shape[2:] + return F.interpolate(x, size=(int(h * self.scale), int(w * self.scale))) + + class YOLOLayer(nn.Module): def __init__(self, anchors, nc, img_size, yolo_index, arc): super(YOLOLayer, self).__init__() From b9fa92d3f79f2dff2a97edc79914b66ae0ecfc63 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 3 Dec 2019 17:22:58 -0800 Subject: [PATCH 0021/1185] updates --- models.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/models.py b/models.py index 17ff234f41..6159d77612 100755 --- a/models.py +++ b/models.py @@ -185,18 +185,19 @@ def forward(self, p, img_size, var=None): elif ONNX_EXPORT: # Constants CAN NOT BE BROADCAST, ensure correct shape! - ngu = self.ng.repeat((1, self.na * self.nx * self.ny, 1)) - grid_xy = self.grid_xy.repeat((1, self.na, 1, 1, 1)).view((1, -1, 2)) - anchor_wh = self.anchor_wh.repeat((1, 1, self.nx, self.ny, 1)).view((1, -1, 2)) / ngu + m = self.na * self.nx * self.ny + ngu = self.ng.repeat((1, m, 1)) + grid_xy = self.grid_xy.repeat((1, self.na, 1, 1, 1)).view(1, m, 2) + anchor_wh = self.anchor_wh.repeat((1, 1, self.nx, self.ny, 1)).view(1, m, 2) / ngu - p = p.view(-1, 5 + self.nc) + p = p.view(m, 5 + self.nc) xy = torch.sigmoid(p[..., 0:2]) + grid_xy[0] # x, y wh = torch.exp(p[..., 2:4]) * anchor_wh[0] # width, height p_conf = torch.sigmoid(p[:, 4:5]) # Conf p_cls = F.softmax(p[:, 5:85], 1) * p_conf # SSD-like conf return torch.cat((xy / ngu[0], wh, p_conf, p_cls), 1).t() - # p = p.view(1, -1, 5 + self.nc) + # p = p.view(1, m, 5 + self.nc) # xy = torch.sigmoid(p[..., 0:2]) + grid_xy # x, y # wh = torch.exp(p[..., 2:4]) * anchor_wh # width, height # p_conf = torch.sigmoid(p[..., 4:5]) # Conf @@ -278,7 +279,7 @@ def forward(self, x, var=None): elif ONNX_EXPORT: output = torch.cat(output, 1) # cat 3 layers 85 x (507, 2028, 8112) to 85 x 10647 nc = self.module_list[self.yolo_layers[0]].nc # number of classes - return output[5:5 + nc].t(), output[:4].t() # ONNX scores, boxes + return output[5:5 + nc].t(), output[0:4].t() # ONNX scores, boxes else: io, p = list(zip(*output)) # inference output, training output return torch.cat(io, 1), p From 24247450e22d86f6ccac14ad6e63e68d1d94ad78 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Dec 2019 09:07:38 -0800 Subject: [PATCH 0022/1185] updates --- cfg/yolov3-tiny-3cls.cfg | 182 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 cfg/yolov3-tiny-3cls.cfg diff --git a/cfg/yolov3-tiny-3cls.cfg b/cfg/yolov3-tiny-3cls.cfg new file mode 100644 index 0000000000..97c3720f2f --- /dev/null +++ b/cfg/yolov3-tiny-3cls.cfg @@ -0,0 +1,182 @@ +[net] +# Testing +batch=1 +subdivisions=1 +# Training +# batch=64 +# subdivisions=2 +width=416 +height=416 +channels=3 +momentum=0.9 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.001 +burn_in=1000 +max_batches = 500200 +policy=steps +steps=400000,450000 +scales=.1,.1 + +[convolutional] +batch_normalize=1 +filters=16 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=1 + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=1 +pad=1 +activation=leaky + +########### + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=24 +activation=linear + + + +[yolo] +mask = 3,4,5 +anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 +classes=3 +num=6 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 8 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=24 +activation=linear + +[yolo] +mask = 0,1,2 +anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 +classes=3 +num=6 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 From 31b49cf8701cfe7eac37599431b79e2c3320b155 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Dec 2019 10:36:39 -0800 Subject: [PATCH 0023/1185] updates --- utils/datasets.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index dc12421b0c..b97ef7b494 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -576,15 +576,19 @@ def load_mosaic(self, index): # Concat/clip labels if len(labels4): labels4 = np.concatenate(labels4, 0) - np.clip(labels4[:, 1:], 0, 2 * s, out=labels4[:, 1:]) - - # Augment - img4, labels4 = random_affine(img4, labels4, - degrees=self.hyp['degrees'], - translate=self.hyp['translate'], - scale=self.hyp['scale'], - shear=self.hyp['shear'], - border=-s // 2) # border to remove + # np.clip(labels4[:, 1:], 0, 2 * s, out=labels4[:, 1:]) # use before random_affine + np.clip(labels4[:, 1:], s / 2, 1.5 * s, out=labels4[:, 1:]) + labels4[:, 1:] -= s / 2 + + img4 = img4[s // 2: int(s * 1.5), s // 2:int(s * 1.5)] + + # # Augment + # img4, labels4 = random_affine(img4, labels4, + # degrees=self.hyp['degrees'], + # translate=self.hyp['translate'], + # scale=self.hyp['scale'], + # shear=self.hyp['shear'], + # border=-s // 2) # border to remove return img4, labels4 From d2a9cc662ce9e2c0f204c27f8f85c940869d16d2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Dec 2019 11:19:17 -0800 Subject: [PATCH 0024/1185] updates --- utils/datasets.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index b97ef7b494..c3fdaea4a8 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -576,19 +576,19 @@ def load_mosaic(self, index): # Concat/clip labels if len(labels4): labels4 = np.concatenate(labels4, 0) - # np.clip(labels4[:, 1:], 0, 2 * s, out=labels4[:, 1:]) # use before random_affine - np.clip(labels4[:, 1:], s / 2, 1.5 * s, out=labels4[:, 1:]) - labels4[:, 1:] -= s / 2 - - img4 = img4[s // 2: int(s * 1.5), s // 2:int(s * 1.5)] - - # # Augment - # img4, labels4 = random_affine(img4, labels4, - # degrees=self.hyp['degrees'], - # translate=self.hyp['translate'], - # scale=self.hyp['scale'], - # shear=self.hyp['shear'], - # border=-s // 2) # border to remove + np.clip(labels4[:, 1:], 0, 2 * s, out=labels4[:, 1:]) # use before random_affine + # np.clip(labels4[:, 1:], s / 2, 1.5 * s, out=labels4[:, 1:]) + # labels4[:, 1:] -= s / 2 + + # img4 = img4[s // 2: int(s * 1.5), s // 2:int(s * 1.5)] + + # Augment + img4, labels4 = random_affine(img4, labels4, + degrees=self.hyp['degrees'], + translate=self.hyp['translate'], + scale=self.hyp['scale'], + shear=self.hyp['shear'], + border=-s // 2) # border to remove return img4, labels4 From 5a14f54b2dda80a3c79867cd487b3d08e9393b53 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Dec 2019 14:24:09 -0800 Subject: [PATCH 0025/1185] updates --- utils/datasets.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index c3fdaea4a8..97bf12348b 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -376,14 +376,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r # Cache images into memory for faster training (~5GB) if cache_images and augment: # if training for i in tqdm(range(min(len(self.img_files), 10000)), desc='Reading images'): # max 10k images - img_path = self.img_files[i] - img = cv2.imread(img_path) # BGR - assert img is not None, 'Image Not Found ' + img_path - r = self.img_size / max(img.shape) # size ratio - if self.augment and r < 1: # if training (NOT testing), downsize to inference shape - h, w = img.shape[:2] - img = cv2.resize(img, (int(w * r), int(h * r)), interpolation=cv2.INTER_LINEAR) # or INTER_AREA - self.imgs[i] = img + self.imgs[i] = load_image(self, i) # Detect corrupted images https://medium.com/joelthchao/programmatically-detect-corrupted-image-8c1b2006c3d3 detect_corrupted_images = False From 54daa69adb48f4766f33c274740dcfe43957f808 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Dec 2019 15:10:16 -0800 Subject: [PATCH 0026/1185] updates --- detect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detect.py b/detect.py index 5a7fb59b19..2593406cf5 100644 --- a/detect.py +++ b/detect.py @@ -43,7 +43,7 @@ def detect(save_txt=False, save_img=False): # Export mode if ONNX_EXPORT: img = torch.zeros((1, 3) + img_size) # (1, 3, 320, 192) - torch.onnx.export(model, img, 'weights/export.onnx', verbose=False, opset_version=11) + torch.onnx.export(model, img, 'weights/export.onnx', verbose=False, opset_version=10) # Validate exported model import onnx From a2dc8a6b5a113d8b4fd5bab7540030e404f5a8bf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Dec 2019 15:15:23 -0800 Subject: [PATCH 0027/1185] updates --- train.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/train.py b/train.py index a13433cadc..5a22990736 100644 --- a/train.py +++ b/train.py @@ -199,9 +199,11 @@ def train(): # Dataloader batch_size = min(batch_size, len(dataset)) + nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 16]) + print('Using %g dataloader workers' % nw) dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, - num_workers=min([os.cpu_count(), batch_size if batch_size > 1 else 0, 16]), + num_workers=nw, shuffle=not opt.rect, # Shuffle=True unless rectangular training is used pin_memory=True, collate_fn=dataset.collate_fn) From 0a04eb9ff10aff8e29169af2dab4ea5084082013 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Dec 2019 15:15:42 -0800 Subject: [PATCH 0028/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 5a22990736..9aa6f6836a 100644 --- a/train.py +++ b/train.py @@ -199,7 +199,7 @@ def train(): # Dataloader batch_size = min(batch_size, len(dataset)) - nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 16]) + nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 16]) # number of workers print('Using %g dataloader workers' % nw) dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, From e27b124828642198581512d42b14f0afe181ecd5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Dec 2019 17:50:52 -0800 Subject: [PATCH 0029/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 6159d77612..7cc82b5892 100755 --- a/models.py +++ b/models.py @@ -194,7 +194,7 @@ def forward(self, p, img_size, var=None): xy = torch.sigmoid(p[..., 0:2]) + grid_xy[0] # x, y wh = torch.exp(p[..., 2:4]) * anchor_wh[0] # width, height p_conf = torch.sigmoid(p[:, 4:5]) # Conf - p_cls = F.softmax(p[:, 5:85], 1) * p_conf # SSD-like conf + p_cls = F.softmax(p[:, 5:5 + self.nc], 1) * p_conf # SSD-like conf return torch.cat((xy / ngu[0], wh, p_conf, p_cls), 1).t() # p = p.view(1, m, 5 + self.nc) From 7f6bb9a39fc17edacb67caec95ac8010f693b3af Mon Sep 17 00:00:00 2001 From: Yonghye Kwon Date: Thu, 5 Dec 2019 16:02:10 +0900 Subject: [PATCH 0030/1185] efficient calling test dataloader during training (#688) * efficient calling test dataloader efficient calling test dataloader * efficient calling test dataloader during training efficient calling test dataloader during training * Update test.py * Update train.py * Update train.py --- test.py | 23 +++++++++++++---------- train.py | 21 +++++++++++++++++---- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/test.py b/test.py index 92c6c948bb..d7a9fbf51b 100644 --- a/test.py +++ b/test.py @@ -17,7 +17,9 @@ def test(cfg, conf_thres=0.001, nms_thres=0.5, save_json=False, - model=None): + model=None, + names=None, + dataloader=None): # Initialize/load model and set device if model is None: device = torch_utils.select_device(opt.device, batch_size=batch_size) @@ -40,15 +42,16 @@ def test(cfg, verbose = False # Configure run - data = parse_data_cfg(data) - nc = int(data['classes']) # number of classes - test_path = data['valid'] # path to test images - names = load_classes(data['names']) # class names - - # Dataloader - dataset = LoadImagesAndLabels(test_path, img_size, batch_size) - batch_size = min(batch_size, len(dataset)) - dataloader = DataLoader(dataset, + if (dataloader and names) is None: + data = parse_data_cfg(data) + nc = int(data['classes']) # number of classes + test_path = data['valid'] # path to test images + names = load_classes(data['names']) # class names + + # Dataloader + dataset = LoadImagesAndLabels(test_path, img_size, batch_size) + batch_size = min(batch_size, len(dataset)) + dataloader = DataLoader(dataset, batch_size=batch_size, num_workers=min([os.cpu_count(), batch_size if batch_size > 1 else 0, 16]), pin_memory=True, diff --git a/train.py b/train.py index 9aa6f6836a..0ec33b8696 100644 --- a/train.py +++ b/train.py @@ -73,7 +73,10 @@ def train(): data_dict = parse_data_cfg(data) train_path = data_dict['train'] nc = int(data_dict['classes']) # number of classes - + names = load_classes(data_dict['names']) + + test_path = data_dict['valid'] # path to test images + # Remove previous results for f in glob.glob('*_batch*.jpg') + glob.glob(results_file): os.remove(f) @@ -196,7 +199,9 @@ def train(): image_weights=opt.img_weights, cache_labels=True if epochs > 10 else False, cache_images=False if opt.prebias else opt.cache_images) - + + dataset_test = LoadImagesAndLabels(test_path, img_size, batch_size) + # Dataloader batch_size = min(batch_size, len(dataset)) nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 16]) # number of workers @@ -207,6 +212,12 @@ def train(): shuffle=not opt.rect, # Shuffle=True unless rectangular training is used pin_memory=True, collate_fn=dataset.collate_fn) + dataloader_test = DataLoader(dataset_test, + batch_size=batch_size, + num_workers=min([os.cpu_count(), batch_size if batch_size > 1 else 0, 16]), + pin_memory=True, + collate_fn=dataloader_test.collate_fn) + # Start training model.nc = nc # attach number of classes to model @@ -316,12 +327,14 @@ def train(): if not (opt.notest or (opt.nosave and epoch < 10)) or final_epoch: with torch.no_grad(): results, maps = test.test(cfg, - data, + data = None, batch_size=batch_size, img_size=opt.img_size, model=model, conf_thres=0.001 if final_epoch and epoch > 0 else 0.1, # 0.1 for speed - save_json=final_epoch and epoch > 0 and 'coco.data' in data) + save_json=final_epoch and epoch > 0 and 'coco.data' in data, + names = names, + dataloader = dataloader_test) # Write epoch results with open(results_file, 'a') as f: From 63c2736c1267d197fa342cf1ac976451678b3065 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Dec 2019 23:02:32 -0800 Subject: [PATCH 0031/1185] updates --- test.py | 20 +++++++++++--------- train.py | 26 ++++++++++++++++++-------- utils/datasets.py | 30 ++++++++++++++++-------------- 3 files changed, 45 insertions(+), 31 deletions(-) diff --git a/test.py b/test.py index 92c6c948bb..9ffa82e280 100644 --- a/test.py +++ b/test.py @@ -17,7 +17,8 @@ def test(cfg, conf_thres=0.001, nms_thres=0.5, save_json=False, - model=None): + model=None, + dataloader=None): # Initialize/load model and set device if model is None: device = torch_utils.select_device(opt.device, batch_size=batch_size) @@ -46,13 +47,14 @@ def test(cfg, names = load_classes(data['names']) # class names # Dataloader - dataset = LoadImagesAndLabels(test_path, img_size, batch_size) - batch_size = min(batch_size, len(dataset)) - dataloader = DataLoader(dataset, - batch_size=batch_size, - num_workers=min([os.cpu_count(), batch_size if batch_size > 1 else 0, 16]), - pin_memory=True, - collate_fn=dataset.collate_fn) + if dataloader is None: + dataset = LoadImagesAndLabels(test_path, img_size, batch_size, rect=True) + batch_size = min(batch_size, len(dataset)) + dataloader = DataLoader(dataset, + batch_size=batch_size, + num_workers=min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8]), + pin_memory=True, + collate_fn=dataset.collate_fn) seen = 0 model.eval() @@ -167,7 +169,7 @@ def test(cfg, # Save JSON if save_json and map and len(jdict): - imgIds = [int(Path(x).stem.split('_')[-1]) for x in dataset.img_files] + imgIds = [int(Path(x).stem.split('_')[-1]) for x in dataloader.dataset.img_files] with open('results.json', 'w') as file: json.dump(jdict, file) diff --git a/train.py b/train.py index 9aa6f6836a..b7d87f6faa 100644 --- a/train.py +++ b/train.py @@ -72,6 +72,7 @@ def train(): # Configure run data_dict = parse_data_cfg(data) train_path = data_dict['train'] + test_path = data_dict['valid'] nc = int(data_dict['classes']) # number of classes # Remove previous results @@ -187,19 +188,17 @@ def train(): model.yolo_layers = model.module.yolo_layers # move yolo layer indices to top level # Dataset - dataset = LoadImagesAndLabels(train_path, - img_size, - batch_size, + dataset = LoadImagesAndLabels(train_path, img_size, batch_size, augment=True, hyp=hyp, # augmentation hyperparameters rect=opt.rect, # rectangular training image_weights=opt.img_weights, - cache_labels=True if epochs > 10 else False, - cache_images=False if opt.prebias else opt.cache_images) + cache_labels=epochs > 10, + cache_images=opt.cache_images and not opt.prebias) # Dataloader batch_size = min(batch_size, len(dataset)) - nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 16]) # number of workers + nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8]) # number of workers print('Using %g dataloader workers' % nw) dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, @@ -208,13 +207,23 @@ def train(): pin_memory=True, collate_fn=dataset.collate_fn) + # Test Dataloader + if not opt.prebias: + testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, img_size, batch_size, hyp=hyp, + cache_labels=True, + cache_images=opt.cache_images), + batch_size=batch_size, + num_workers=nw, + pin_memory=True, + collate_fn=dataset.collate_fn) + # Start training + nb = len(dataloader) model.nc = nc # attach number of classes to model model.arc = opt.arc # attach yolo architecture model.hyp = hyp # attach hyperparameters to model model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) # attach class weights torch_utils.model_info(model, report='summary') # 'full' or 'summary' - nb = len(dataloader) maps = np.zeros(nc) # mAP per class # torch.autograd.set_detect_anomaly(True) results = (0, 0, 0, 0, 0, 0, 0) # 'P', 'R', 'mAP', 'F1', 'val GIoU', 'val Objectness', 'val Classification' @@ -321,7 +330,8 @@ def train(): img_size=opt.img_size, model=model, conf_thres=0.001 if final_epoch and epoch > 0 else 0.1, # 0.1 for speed - save_json=final_epoch and epoch > 0 and 'coco.data' in data) + save_json=final_epoch and epoch > 0 and 'coco.data' in data, + dataloader=testloader) # Write epoch results with open(results_file, 'a') as f: diff --git a/utils/datasets.py b/utils/datasets.py index 97bf12348b..0a4ad7c7b0 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -255,7 +255,7 @@ def __len__(self): class LoadImagesAndLabels(Dataset): # for training/testing - def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, rect=True, image_weights=False, + def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, cache_labels=False, cache_images=False): path = str(Path(path)) # os-agnostic with open(path, 'r') as f: @@ -319,7 +319,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r self.labels = [np.zeros((0, 5))] * n extract_bounding_boxes = False create_datasubset = False - pbar = tqdm(self.label_files, desc='Reading labels') + pbar = tqdm(self.label_files, desc='Caching labels') nm, nf, ne, ns = 0, 0, 0, 0 # number missing, number found, number empty, number datasubset for i, file in enumerate(pbar): try: @@ -370,13 +370,17 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r ne += 1 # print('empty labels for image %s' % self.img_files[i]) # file empty # os.system("rm '%s' '%s'" % (self.img_files[i], self.label_files[i])) # remove - pbar.desc = 'Reading labels (%g found, %g missing, %g empty for %g images)' % (nf, nm, ne, n) + pbar.desc = 'Caching labels (%g found, %g missing, %g empty for %g images)' % (nf, nm, ne, n) assert nf > 0, 'No labels found. Recommend correcting image and label paths.' - # Cache images into memory for faster training (~5GB) - if cache_images and augment: # if training - for i in tqdm(range(min(len(self.img_files), 10000)), desc='Reading images'): # max 10k images + # Cache images into memory for faster training (WARNING: Large datasets may exceed system RAM) + if cache_images: # if training + gb = 0 # Gigabytes of cached images + pbar = tqdm(range(len(self.img_files)), desc='Caching images') + for i in pbar: # max 10k images self.imgs[i] = load_image(self, i) + gb += self.imgs[i].nbytes + pbar.desc = 'Caching images (%.1fGB)' % (gb / 1E9) # Detect corrupted images https://medium.com/joelthchao/programmatically-detect-corrupted-image-8c1b2006c3d3 detect_corrupted_images = False @@ -503,10 +507,10 @@ def load_image(self, index): img_path = self.img_files[index] img = cv2.imread(img_path) # BGR assert img is not None, 'Image Not Found ' + img_path - r = self.img_size / max(img.shape) # size ratio - if self.augment: # if training (NOT testing), downsize to inference shape + r = self.img_size / max(img.shape) # resize image to img_size + if (r < 1) or ((r > 1) and self.augment): # always resize down, only resize up if training with augmentation h, w = img.shape[:2] - img = cv2.resize(img, (int(w * r), int(h * r)), interpolation=cv2.INTER_LINEAR) # _LINEAR fastest + return cv2.resize(img, (int(w * r), int(h * r)), interpolation=cv2.INTER_LINEAR) # _LINEAR fastest return img @@ -569,13 +573,11 @@ def load_mosaic(self, index): # Concat/clip labels if len(labels4): labels4 = np.concatenate(labels4, 0) - np.clip(labels4[:, 1:], 0, 2 * s, out=labels4[:, 1:]) # use before random_affine - # np.clip(labels4[:, 1:], s / 2, 1.5 * s, out=labels4[:, 1:]) - # labels4[:, 1:] -= s / 2 - - # img4 = img4[s // 2: int(s * 1.5), s // 2:int(s * 1.5)] + # np.clip(labels4[:, 1:] - s / 2, 0, s, out=labels4[:, 1:]) # use with center crop + np.clip(labels4[:, 1:], 0, 2 * s, out=labels4[:, 1:]) # use with random_affine # Augment + # img4 = img4[s // 2: int(s * 1.5), s // 2:int(s * 1.5)] # center crop (WARNING, requires box pruning) img4, labels4 = random_affine(img4, labels4, degrees=self.hyp['degrees'], translate=self.hyp['translate'], From 2421f3e252395d038a7be6f3c0b5cb6a78a92b45 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Dec 2019 00:17:27 -0800 Subject: [PATCH 0032/1185] updates --- utils/datasets.py | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 0a4ad7c7b0..4d87f28f8e 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -758,24 +758,28 @@ def reduce_img_size(path='../data/sm4/images', img_size=1024): # from utils.dat print('WARNING: image failure %s' % f) -def convert_images2bmp(): - # cv2.imread() jpg at 230 img/s, *.bmp at 400 img/s - for path in ['../coco/images/val2014/', '../coco/images/train2014/']: - folder = os.sep + Path(path).name - output = path.replace(folder, folder + 'bmp') - create_folder(output) - - for f in tqdm(glob.glob('%s*.jpg' % path)): - save_name = f.replace('.jpg', '.bmp').replace(folder, folder + 'bmp') - cv2.imwrite(save_name, cv2.imread(f)) - - for label_path in ['../coco/trainvalno5k.txt', '../coco/5k.txt']: - with open(label_path, 'r') as file: - lines = file.read() - lines = lines.replace('2014/', '2014bmp/').replace('.jpg', '.bmp').replace( - '/Users/glennjocher/PycharmProjects/', '../') - with open(label_path.replace('5k', '5k_bmp'), 'w') as file: - file.write(lines) +def convert_images2bmp(): # from utils.datasets import *; convert_images2bmp() + # Save images + formats = [x.lower() for x in img_formats] + [x.upper() for x in img_formats] + # for path in ['../coco/images/val2014', '../coco/images/train2014']: + for path in ['../data/sm4/images', '../data/sm4/background']: + create_folder(path + 'bmp') + for ext in formats: # ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.dng'] + for f in tqdm(glob.glob('%s/*%s' % (path, ext)), desc='Converting %s' % ext): + cv2.imwrite(f.replace(ext.lower(), '.bmp').replace(path, path + 'bmp'), cv2.imread(f)) + + # Save labels + # for path in ['../coco/trainvalno5k.txt', '../coco/5k.txt']: + for file in ['../data/sm4/out_train.txt', '../data/sm4/out_test.txt']: + with open(file, 'r') as f: + lines = f.read() + # lines = f.read().replace('2014/', '2014bmp/') # coco + lines = lines.replace('/images', '/imagesbmp') + lines = lines.replace('/background', '/backgroundbmp') + for ext in formats: + lines = lines.replace(ext, '.bmp') + with open(file.replace('.txt', 'bmp.txt'), 'w') as f: + f.write(lines) def imagelist2folder(path='data/coco_64img.txt'): # from utils.datasets import *; imagelist2folder() From 035faa669423ebc72a7179a0589126f4c91e064b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Dec 2019 00:35:07 -0800 Subject: [PATCH 0033/1185] updates --- utils/datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/datasets.py b/utils/datasets.py index 4d87f28f8e..ef706812ed 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -508,7 +508,7 @@ def load_image(self, index): img = cv2.imread(img_path) # BGR assert img is not None, 'Image Not Found ' + img_path r = self.img_size / max(img.shape) # resize image to img_size - if (r < 1) or ((r > 1) and self.augment): # always resize down, only resize up if training with augmentation + if self.augment and (r != 1): # always resize down, only resize up if training with augmentation h, w = img.shape[:2] return cv2.resize(img, (int(w * r), int(h * r)), interpolation=cv2.INTER_LINEAR) # _LINEAR fastest return img From d08cdad4af8a24debf552c2b3144d616e9b7b98a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Dec 2019 11:01:10 -0800 Subject: [PATCH 0034/1185] updates --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 4973a2316c..9f1fd365a4 100755 --- a/README.md +++ b/README.md @@ -241,18 +241,18 @@ Using CUDA device0 _CudaDeviceProperties(name='GeForce RTX 2080 Ti', total_memor hair drier 5e+03 11 0.00508 0.0909 0.0475 0.00962 toothbrush 5e+03 77 0.0371 0.74 0.418 0.0706 - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.40882 - Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.60026 - Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.44551 - Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.24343 - Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.45024 - Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.51362 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.32644 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.53629 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.59343 - Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.42207 - Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.63985 - Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.70688 + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.409 + Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.600 + Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.446 + Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.243 + Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.450 + Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.514 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.326 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.536 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.593 + Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.422 + Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.640 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.707 ``` # Citation From 6340074c2a1890100007cf66cb71e6a07b1531b8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Dec 2019 20:24:42 -0800 Subject: [PATCH 0035/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index fe143fdbd7..0c2c206682 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -359,7 +359,7 @@ def compute_loss(p, targets, model): # predictions, targets, model # GIoU pxy = torch.sigmoid(ps[:, 0:2]) # pxy = pxy * s - (s - 1) / 2, s = 1.5 (scale_xy) - pbox = torch.cat((pxy, torch.exp(ps[:, 2:4]).clamp(max=1E4) * anchor_vec[i]), 1) # predicted box + pbox = torch.cat((pxy, torch.exp(ps[:, 2:4]).clamp(max=1E3) * anchor_vec[i]), 1) # predicted box giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation lbox += (1.0 - giou).mean() # giou loss From d00a91aa1b4be561a3c135fe44fecb47e933d932 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 11:02:02 -0800 Subject: [PATCH 0036/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 0c2c206682..a289ea55b0 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -464,7 +464,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): (x1, y1, x2, y2, object_conf, class_conf, class) """ - min_wh, max_wh = 2, 30000 # (pixels) minimum and maximium box width and height + min_wh, max_wh = 2, 10000 # (pixels) minimum and maximium box width and height output = [None] * len(prediction) for image_i, pred in enumerate(prediction): From 61e3fc1f8e53ed541d6a8dc905e59a4611dc5335 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 12:56:22 -0800 Subject: [PATCH 0037/1185] updates --- models.py | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/models.py b/models.py index 7cc82b5892..b61e398b82 100755 --- a/models.py +++ b/models.py @@ -440,29 +440,21 @@ def attempt_download(weights): msg = weights + ' missing, download from https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0' if weights and not os.path.isfile(weights): file = Path(weights).name - - if file == 'yolov3-spp.weights': - gdrive_download(id='16lYS4bcIdM2HdmyJBVDOvt3Trx6N3W2R', name=weights) - elif file == 'yolov3.weights': - gdrive_download(id='1uTlyDWlnaqXcsKOktP5aH_zRDbfcDp-y', name=weights) - elif file == 'yolov3-tiny.weights': - gdrive_download(id='1CCF-iNIIkYesIDzaPvdwlcf7H9zSsKZQ', name=weights) - elif file == 'yolov3-spp.pt': - gdrive_download(id='1f6Ovy3BSq2wYq4UfvFUpxJFNDFfrIDcR', name=weights) - elif file == 'yolov3.pt': - gdrive_download(id='1SHNFyoe5Ni8DajDNEqgB2oVKBb_NoEad', name=weights) - elif file == 'yolov3-tiny.pt': - gdrive_download(id='10m_3MlpQwRtZetQxtksm9jqHrPTHZ6vo', name=weights) - elif file == 'darknet53.conv.74': - gdrive_download(id='1WUVBid-XuoUBmvzBVUCBl_ELrzqwA8dJ', name=weights) - elif file == 'yolov3-tiny.conv.15': - gdrive_download(id='1Bw0kCpplxUqyRYAJr9RY9SGnOJbo9nEj', name=weights) - elif file == 'ultralytics49.pt': - gdrive_download(id='158g62Vs14E3aj7oPVPuEnNZMKFNgGyNq', name=weights) - elif file == 'ultralytics68.pt': - gdrive_download(id='1Jm8kqnMdMGUUxGo8zMFZMJ0eaPwLkxSG', name=weights) - else: - try: # download from pjreddie.com + d = {'yolov3-spp.weights': '16lYS4bcIdM2HdmyJBVDOvt3Trx6N3W2R', + 'yolov3.weights': '1uTlyDWlnaqXcsKOktP5aH_zRDbfcDp-y', + 'yolov3-tiny.weights': '1CCF-iNIIkYesIDzaPvdwlcf7H9zSsKZQ', + 'yolov3-spp.pt': '1f6Ovy3BSq2wYq4UfvFUpxJFNDFfrIDcR', + 'yolov3.pt': '1SHNFyoe5Ni8DajDNEqgB2oVKBb_NoEad', + 'yolov3-tiny.pt': '10m_3MlpQwRtZetQxtksm9jqHrPTHZ6vo', + 'darknet53.conv.74': '1WUVBid-XuoUBmvzBVUCBl_ELrzqwA8dJ', + 'yolov3-tiny.conv.15': '1Bw0kCpplxUqyRYAJr9RY9SGnOJbo9nEj', + 'ultralytics49.pt': '158g62Vs14E3aj7oPVPuEnNZMKFNgGyNq', + 'ultralytics68.pt': '1Jm8kqnMdMGUUxGo8zMFZMJ0eaPwLkxSG'} + + if weights in d: + gdrive_download(id=d[weights], name=weights) + else: # download from pjreddie.com + try: url = 'https://pjreddie.com/media/files/' + file print('Downloading ' + url) os.system('curl -f ' + url + ' -o ' + weights) From 6067b226050ac14d651ef1b0f40069a38bf8404f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 13:30:14 -0800 Subject: [PATCH 0038/1185] updates --- utils/google_utils.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/utils/google_utils.py b/utils/google_utils.py index 303265b4a6..fc2bc34f83 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -23,12 +23,18 @@ def gdrive_download(id='1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO', name='coco.zip'): "curl -Lb ./cookie -s \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=%s\" -o %s" % ( id, name), 'rm ./cookie'] - [os.system(x) for x in s] # run commands + r = sum([os.system(x) for x in s]) # run commands, get return zeros # Attempt small file download if not os.path.exists(name): # file size < 40MB s = 'curl -f -L -o %s https://drive.google.com/uc?export=download&id=%s' % (name, id) - os.system(s) + r = os.system(s) + + # Check for errors + if r != 0: + os.system('rm ' + name) # remove partial downloads + print('ERROR: Download failure. ') + return # Unzip if archive if name.endswith('.zip'): From ef133382c5ac2c1b5704b113c25c5cbf4786a7ce Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 13:44:13 -0800 Subject: [PATCH 0039/1185] updates --- models.py | 28 +++++++++++++--------------- utils/google_utils.py | 7 ++++--- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/models.py b/models.py index b61e398b82..6dd1aa6fd5 100755 --- a/models.py +++ b/models.py @@ -436,10 +436,11 @@ def convert(cfg='cfg/yolov3-spp.cfg', weights='weights/yolov3-spp.weights'): def attempt_download(weights): # Attempt to download pretrained weights if not found locally + file = Path(weights).name + msg = weights + ' missing, try downloading from https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0' + r = 1 # error value - msg = weights + ' missing, download from https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0' if weights and not os.path.isfile(weights): - file = Path(weights).name d = {'yolov3-spp.weights': '16lYS4bcIdM2HdmyJBVDOvt3Trx6N3W2R', 'yolov3.weights': '1uTlyDWlnaqXcsKOktP5aH_zRDbfcDp-y', 'yolov3-tiny.weights': '1CCF-iNIIkYesIDzaPvdwlcf7H9zSsKZQ', @@ -451,17 +452,14 @@ def attempt_download(weights): 'ultralytics49.pt': '158g62Vs14E3aj7oPVPuEnNZMKFNgGyNq', 'ultralytics68.pt': '1Jm8kqnMdMGUUxGo8zMFZMJ0eaPwLkxSG'} - if weights in d: - gdrive_download(id=d[weights], name=weights) + if file in d: + r = gdrive_download(id=d[file], name=weights) else: # download from pjreddie.com - try: - url = 'https://pjreddie.com/media/files/' + file - print('Downloading ' + url) - os.system('curl -f ' + url + ' -o ' + weights) - except IOError: - print(msg) - os.system('rm ' + weights) # remove partial downloads - - if os.path.getsize(weights) < 5E6: # weights < 5MB (too small), download failed - os.remove(weights) # delete corrupted weightsfile - assert os.path.exists(weights), msg # download missing weights from Google Drive + url = 'https://pjreddie.com/media/files/' + file + print('Downloading ' + url) + r = os.system('curl -f ' + url + ' -o ' + weights) + + # Error check + if not (r == 0 and os.path.exists(weights) and os.path.getsize(weights) > 1E6): # weights exist and > 1MB + os.system('rm ' + weights) # remove partial downloads + raise Exception(msg) diff --git a/utils/google_utils.py b/utils/google_utils.py index fc2bc34f83..92fde590bc 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -30,11 +30,11 @@ def gdrive_download(id='1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO', name='coco.zip'): s = 'curl -f -L -o %s https://drive.google.com/uc?export=download&id=%s' % (name, id) r = os.system(s) - # Check for errors + # Error check if r != 0: os.system('rm ' + name) # remove partial downloads - print('ERROR: Download failure. ') - return + print('ERROR: Download failure ') + return r # Unzip if archive if name.endswith('.zip'): @@ -43,6 +43,7 @@ def gdrive_download(id='1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO', name='coco.zip'): os.remove(name) # remove zip to free space print('Done (%.1fs)' % (time.time() - t)) + return r def upload_blob(bucket_name, source_file_name, destination_blob_name): From c702916495000e93809d55683f2603d9975f847a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 13:47:17 -0800 Subject: [PATCH 0040/1185] updates --- models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index 6dd1aa6fd5..bbc1c057ae 100755 --- a/models.py +++ b/models.py @@ -436,10 +436,9 @@ def convert(cfg='cfg/yolov3-spp.cfg', weights='weights/yolov3-spp.weights'): def attempt_download(weights): # Attempt to download pretrained weights if not found locally - file = Path(weights).name msg = weights + ' missing, try downloading from https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0' - r = 1 # error value + r = 1 # error value if weights and not os.path.isfile(weights): d = {'yolov3-spp.weights': '16lYS4bcIdM2HdmyJBVDOvt3Trx6N3W2R', 'yolov3.weights': '1uTlyDWlnaqXcsKOktP5aH_zRDbfcDp-y', @@ -452,6 +451,7 @@ def attempt_download(weights): 'ultralytics49.pt': '158g62Vs14E3aj7oPVPuEnNZMKFNgGyNq', 'ultralytics68.pt': '1Jm8kqnMdMGUUxGo8zMFZMJ0eaPwLkxSG'} + file = Path(weights).name if file in d: r = gdrive_download(id=d[file], name=weights) else: # download from pjreddie.com From 3bd00360bcd8b8473b217d46dab643399c0ac1fe Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 13:50:16 -0800 Subject: [PATCH 0041/1185] updates --- models.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/models.py b/models.py index bbc1c057ae..b14310808a 100755 --- a/models.py +++ b/models.py @@ -438,7 +438,6 @@ def attempt_download(weights): # Attempt to download pretrained weights if not found locally msg = weights + ' missing, try downloading from https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0' - r = 1 # error value if weights and not os.path.isfile(weights): d = {'yolov3-spp.weights': '16lYS4bcIdM2HdmyJBVDOvt3Trx6N3W2R', 'yolov3.weights': '1uTlyDWlnaqXcsKOktP5aH_zRDbfcDp-y', @@ -459,7 +458,7 @@ def attempt_download(weights): print('Downloading ' + url) r = os.system('curl -f ' + url + ' -o ' + weights) - # Error check - if not (r == 0 and os.path.exists(weights) and os.path.getsize(weights) > 1E6): # weights exist and > 1MB - os.system('rm ' + weights) # remove partial downloads - raise Exception(msg) + # Error check + if not (r == 0 and os.path.exists(weights) and os.path.getsize(weights) > 1E6): # weights exist and > 1MB + os.system('rm ' + weights) # remove partial downloads + raise Exception(msg) From 5e747f8da97eecd246865466a88c9771dabfe703 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 14:13:07 -0800 Subject: [PATCH 0042/1185] updates --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index bb6e49e91f..0c1c92560f 100755 --- a/requirements.txt +++ b/requirements.txt @@ -13,7 +13,7 @@ Pillow # Equivalent conda commands ---------------------------------------------------- # conda update -n base -c defaults conda -# conda install -yc anaconda future numpy opencv matplotlib tqdm pillow -# conda install -yc conda-forge scikit-image pycocotools tensorboard +# conda install -yc anaconda numpy opencv matplotlib tqdm pillow future +# conda install -yc conda-forge scikit-image pycocotools onnx tensorboard # conda install -yc spyder-ide spyder-line-profiler # conda install -yc pytorch pytorch torchvision From af8af1ce6868540ca31c895151f145b1d76402c6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 16:35:15 -0800 Subject: [PATCH 0043/1185] updates --- models.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/models.py b/models.py index b14310808a..330f4621dd 100755 --- a/models.py +++ b/models.py @@ -51,7 +51,6 @@ def create_modules(module_defs, img_size, arc): elif mdef['type'] == 'upsample': modules = nn.Upsample(scale_factor=int(mdef['stride']), mode='nearest') - # modules = Upsample(scale_factor=int(mdef['stride'])) elif mdef['type'] == 'route': # nn.Sequential() placeholder for 'route' layer layers = [int(x) for x in mdef['layers'].split(',')] @@ -142,16 +141,6 @@ def forward(self, x): return x.mul_(F.softplus(x).tanh()) -class Upsample(nn.Module): - def __init__(self, scale_factor): - super(Upsample, self).__init__() - self.scale = scale_factor - - def forward(self, x): - h, w = x.shape[2:] - return F.interpolate(x, size=(int(h * self.scale), int(w * self.scale))) - - class YOLOLayer(nn.Module): def __init__(self, anchors, nc, img_size, yolo_index, arc): super(YOLOLayer, self).__init__() From ddaadf1bf99c4c0097ee11dc1e7a5f537e282bca Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 17:24:15 -0800 Subject: [PATCH 0044/1185] updates --- data/get_coco_dataset_gdrive.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/data/get_coco_dataset_gdrive.sh b/data/get_coco_dataset_gdrive.sh index c965e4871f..f280516f29 100755 --- a/data/get_coco_dataset_gdrive.sh +++ b/data/get_coco_dataset_gdrive.sh @@ -1,6 +1,4 @@ #!/bin/bash -# https://stackoverflow.com/questions/48133080/how-to-download-a-google-drive-url-via-curl-or-wget/48133859 - # Zip coco folder # zip -r coco.zip coco # tar -czvf coco.tar.gz coco From 4988397458f48520276426435ae18f29afcfbc9c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 17:31:07 -0800 Subject: [PATCH 0045/1185] updates --- Dockerfile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 040a9a572c..4738ad58e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,10 +36,9 @@ WORKDIR /usr/src/app COPY . /usr/src/app # Copy weights -#RUN python3 -c "from utils.google_utils import *; \ -# gdrive_download(id='18xqvs_uwAqfTXp-LJCYLYNHBOcrwbrp0', name='weights/darknet53.conv.74'); \ -# gdrive_download(id='1oPCHKsM2JpM-zgyepQciGli9X0MTsJCO', name='weights/yolov3-spp.weights'); \ -# gdrive_download(id='1vFlbJ_dXPvtwaLLOu-twnjK4exdFiQ73', name='weights/yolov3-spp.pt)" +#RUN python3 -c "from models import *; \ +#attempt_download('weights/yolov3.pt'); \ +#attempt_download('weights/yolov3-spp.pt')" # --------------------------------------------------- Extras Below --------------------------------------------------- From f2d47c125608523d2e8f65d4a2db475c154f9b56 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 17:33:17 -0800 Subject: [PATCH 0046/1185] updates --- weights/download_yolov3_weights.sh | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/weights/download_yolov3_weights.sh b/weights/download_yolov3_weights.sh index 0568cb8772..a6f709b5c2 100644 --- a/weights/download_yolov3_weights.sh +++ b/weights/download_yolov3_weights.sh @@ -1,20 +1,25 @@ #!/bin/bash # make '/weights' directory if it does not exist and cd into it -mkdir -p weights && cd weights +# mkdir -p weights && cd weights # copy darknet weight files, continue '-c' if partially downloaded -wget -c https://pjreddie.com/media/files/yolov3.weights -wget -c https://pjreddie.com/media/files/yolov3-tiny.weights -wget -c https://pjreddie.com/media/files/yolov3-spp.weights +# wget -c https://pjreddie.com/media/files/yolov3.weights +# wget -c https://pjreddie.com/media/files/yolov3-tiny.weights +# wget -c https://pjreddie.com/media/files/yolov3-spp.weights # yolov3 pytorch weights # download from Google Drive: https://drive.google.com/drive/folders/1uxgUBemJVw9wZsdpboYbzUN4bcRhsuAI # darknet53 weights (first 75 layers only) -wget -c https://pjreddie.com/media/files/darknet53.conv.74 +# wget -c https://pjreddie.com/media/files/darknet53.conv.74 # yolov3-tiny weights from darknet (first 16 layers only) # ./darknet partial cfg/yolov3-tiny.cfg yolov3-tiny.weights yolov3-tiny.conv.15 15 # mv yolov3-tiny.conv.15 ../ +# new method +python3 -c "from models import *; +attempt_download('weights/yolov3.pt'); +attempt_download('weights/yolov3-spp.pt')" + From 115b3333714d46c187c1d9355f24b0ec4bd5500f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 17:33:32 -0800 Subject: [PATCH 0047/1185] updates --- weights/download_yolov3_weights.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/weights/download_yolov3_weights.sh b/weights/download_yolov3_weights.sh index a6f709b5c2..8b96a1e098 100644 --- a/weights/download_yolov3_weights.sh +++ b/weights/download_yolov3_weights.sh @@ -22,4 +22,3 @@ python3 -c "from models import *; attempt_download('weights/yolov3.pt'); attempt_download('weights/yolov3-spp.pt')" - From a066a7b8eaf2f18cc54495d119af57b1aff2f901 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 19:05:51 -0800 Subject: [PATCH 0048/1185] updates --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index b7d87f6faa..3feb68b9dd 100644 --- a/train.py +++ b/train.py @@ -321,8 +321,8 @@ def train(): if opt.prebias: print_model_biases(model) else: - # Calculate mAP (always test final epoch, skip first 10 if opt.nosave) - if not (opt.notest or (opt.nosave and epoch < 10)) or final_epoch: + # Calculate mAP + if not opt.notest or final_epoch: with torch.no_grad(): results, maps = test.test(cfg, data, From 2c0985f36646a311d4a439ab62c27d7922bab7ef Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Dec 2019 23:58:47 -0800 Subject: [PATCH 0049/1185] updates --- train.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/train.py b/train.py index 3feb68b9dd..434daba3ea 100644 --- a/train.py +++ b/train.py @@ -21,24 +21,24 @@ results_file = 'results.txt' # Hyperparameters (results68: 59.2 mAP@0.5 yolov3-spp-416) https://github.com/ultralytics/yolov3/issues/310 -hyp = {'giou': 3.31, # giou loss gain - 'cls': 42.4, # cls loss gain +hyp = {'giou': 3.54, # giou loss gain + 'cls': 37.4, # cls loss gain 'cls_pw': 1.0, # cls BCELoss positive_weight - 'obj': 52.0, # obj loss gain (*=img_size/416 if img_size != 416) + 'obj': 64.3, # obj loss gain (*=img_size/416 if img_size != 416) 'obj_pw': 1.0, # obj BCELoss positive_weight - 'iou_t': 0.213, # iou training threshold - 'lr0': 0.00261, # initial learning rate (SGD=1E-3, Adam=9E-5) + 'iou_t': 0.225, # iou training threshold + 'lr0': 0.00579, # initial learning rate (SGD=1E-3, Adam=9E-5) 'lrf': -4., # final LambdaLR learning rate = lr0 * (10 ** lrf) - 'momentum': 0.949, # SGD momentum - 'weight_decay': 0.000489, # optimizer weight decay + 'momentum': 0.937, # SGD momentum + 'weight_decay': 0.000484, # optimizer weight decay 'fl_gamma': 0.5, # focal loss gamma - 'hsv_h': 0.0103, # image HSV-Hue augmentation (fraction) - 'hsv_s': 0.691, # image HSV-Saturation augmentation (fraction) - 'hsv_v': 0.433, # image HSV-Value augmentation (fraction) - 'degrees': 1.43, # image rotation (+/- deg) - 'translate': 0.0663, # image translation (+/- fraction) + 'hsv_h': 0.0138, # image HSV-Hue augmentation (fraction) + 'hsv_s': 0.678, # image HSV-Saturation augmentation (fraction) + 'hsv_v': 0.36, # image HSV-Value augmentation (fraction) + 'degrees': 1.98, # image rotation (+/- deg) + 'translate': 0.0779, # image translation (+/- fraction) 'scale': 0.11, # image scale (+/- gain) - 'shear': 0.384} # image shear (+/- deg) + 'shear': 0.641} # image shear (+/- deg) # Overwrite hyp with hyp*.txt (optional) f = glob.glob('hyp*.txt') From d5176e4fc41c6b3b71a59daf2ca17f6c65deab21 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 7 Dec 2019 00:01:18 -0800 Subject: [PATCH 0050/1185] updates --- train.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/train.py b/train.py index 434daba3ea..a8dc6106cb 100644 --- a/train.py +++ b/train.py @@ -21,6 +21,7 @@ results_file = 'results.txt' # Hyperparameters (results68: 59.2 mAP@0.5 yolov3-spp-416) https://github.com/ultralytics/yolov3/issues/310 + hyp = {'giou': 3.54, # giou loss gain 'cls': 37.4, # cls loss gain 'cls_pw': 1.0, # cls BCELoss positive_weight @@ -37,7 +38,7 @@ 'hsv_v': 0.36, # image HSV-Value augmentation (fraction) 'degrees': 1.98, # image rotation (+/- deg) 'translate': 0.0779, # image translation (+/- fraction) - 'scale': 0.11, # image scale (+/- gain) + 'scale': 0.10, # image scale (+/- gain) 'shear': 0.641} # image shear (+/- deg) # Overwrite hyp with hyp*.txt (optional) From bb54408f73b1dab4fbb0a11db429058755090388 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 7 Dec 2019 00:05:37 -0800 Subject: [PATCH 0051/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index a8dc6106cb..40fcee3341 100644 --- a/train.py +++ b/train.py @@ -432,7 +432,7 @@ def prebias(): parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') parser.add_argument('--img-weights', action='store_true', help='select training images by weight') parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') - parser.add_argument('--weights', type=str, default='weights/ultralytics49.pt', help='initial weights') + parser.add_argument('--weights', type=str, default='weights/ultralytics68.pt', help='initial weights') parser.add_argument('--arc', type=str, default='default', help='yolo architecture') # defaultpw, uCE, uBCE parser.add_argument('--prebias', action='store_true', help='transfer-learn yolo biases prior to training') parser.add_argument('--name', default='', help='renames results.txt to results_name.txt if supplied') From c631cc2156a5b6b49eb79b59fa99c5d870796dce Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 7 Dec 2019 00:10:14 -0800 Subject: [PATCH 0052/1185] updates --- data/coco_32img.data | 6 - data/coco_32img.txt | 32 --- data/coco_500img.txt | 500 ------------------------------------------ data/coco_500val.data | 6 - data/coco_500val.txt | 500 ------------------------------------------ 5 files changed, 1044 deletions(-) delete mode 100644 data/coco_32img.data delete mode 100644 data/coco_32img.txt delete mode 100644 data/coco_500img.txt delete mode 100644 data/coco_500val.data delete mode 100644 data/coco_500val.txt diff --git a/data/coco_32img.data b/data/coco_32img.data deleted file mode 100644 index 8fceee7ffe..0000000000 --- a/data/coco_32img.data +++ /dev/null @@ -1,6 +0,0 @@ -classes=80 -train=./data/coco_32img.txt -valid=./data/coco_32img.txt -names=data/coco.names -backup=backup/ -eval=coco diff --git a/data/coco_32img.txt b/data/coco_32img.txt deleted file mode 100644 index 75b86be856..0000000000 --- a/data/coco_32img.txt +++ /dev/null @@ -1,32 +0,0 @@ -../coco/images/train2014/COCO_train2014_000000000009.jpg -../coco/images/train2014/COCO_train2014_000000000025.jpg -../coco/images/train2014/COCO_train2014_000000000030.jpg -../coco/images/train2014/COCO_train2014_000000000034.jpg -../coco/images/train2014/COCO_train2014_000000000036.jpg -../coco/images/train2014/COCO_train2014_000000000049.jpg -../coco/images/train2014/COCO_train2014_000000000061.jpg -../coco/images/train2014/COCO_train2014_000000000064.jpg -../coco/images/train2014/COCO_train2014_000000000071.jpg -../coco/images/train2014/COCO_train2014_000000000072.jpg -../coco/images/train2014/COCO_train2014_000000000077.jpg -../coco/images/train2014/COCO_train2014_000000000078.jpg -../coco/images/train2014/COCO_train2014_000000000081.jpg -../coco/images/train2014/COCO_train2014_000000000086.jpg -../coco/images/train2014/COCO_train2014_000000000089.jpg -../coco/images/train2014/COCO_train2014_000000000092.jpg -../coco/images/train2014/COCO_train2014_000000000094.jpg -../coco/images/train2014/COCO_train2014_000000000109.jpg -../coco/images/train2014/COCO_train2014_000000000110.jpg -../coco/images/train2014/COCO_train2014_000000000113.jpg -../coco/images/train2014/COCO_train2014_000000000127.jpg -../coco/images/train2014/COCO_train2014_000000000138.jpg -../coco/images/train2014/COCO_train2014_000000000142.jpg -../coco/images/train2014/COCO_train2014_000000000144.jpg -../coco/images/train2014/COCO_train2014_000000000149.jpg -../coco/images/train2014/COCO_train2014_000000000151.jpg -../coco/images/train2014/COCO_train2014_000000000154.jpg -../coco/images/train2014/COCO_train2014_000000000165.jpg -../coco/images/train2014/COCO_train2014_000000000194.jpg -../coco/images/train2014/COCO_train2014_000000000201.jpg -../coco/images/train2014/COCO_train2014_000000000247.jpg -../coco/images/train2014/COCO_train2014_000000000260.jpg diff --git a/data/coco_500img.txt b/data/coco_500img.txt deleted file mode 100644 index 5d578ab2ac..0000000000 --- a/data/coco_500img.txt +++ /dev/null @@ -1,500 +0,0 @@ -../coco/images/train2014/COCO_train2014_000000000009.jpg -../coco/images/train2014/COCO_train2014_000000000025.jpg -../coco/images/train2014/COCO_train2014_000000000030.jpg -../coco/images/train2014/COCO_train2014_000000000034.jpg -../coco/images/train2014/COCO_train2014_000000000036.jpg -../coco/images/train2014/COCO_train2014_000000000049.jpg -../coco/images/train2014/COCO_train2014_000000000061.jpg -../coco/images/train2014/COCO_train2014_000000000064.jpg -../coco/images/train2014/COCO_train2014_000000000071.jpg -../coco/images/train2014/COCO_train2014_000000000072.jpg -../coco/images/train2014/COCO_train2014_000000000077.jpg -../coco/images/train2014/COCO_train2014_000000000078.jpg -../coco/images/train2014/COCO_train2014_000000000081.jpg -../coco/images/train2014/COCO_train2014_000000000086.jpg -../coco/images/train2014/COCO_train2014_000000000089.jpg -../coco/images/train2014/COCO_train2014_000000000092.jpg -../coco/images/train2014/COCO_train2014_000000000094.jpg -../coco/images/train2014/COCO_train2014_000000000109.jpg -../coco/images/train2014/COCO_train2014_000000000110.jpg -../coco/images/train2014/COCO_train2014_000000000113.jpg -../coco/images/train2014/COCO_train2014_000000000127.jpg -../coco/images/train2014/COCO_train2014_000000000138.jpg -../coco/images/train2014/COCO_train2014_000000000142.jpg -../coco/images/train2014/COCO_train2014_000000000144.jpg -../coco/images/train2014/COCO_train2014_000000000149.jpg -../coco/images/train2014/COCO_train2014_000000000151.jpg -../coco/images/train2014/COCO_train2014_000000000154.jpg -../coco/images/train2014/COCO_train2014_000000000165.jpg -../coco/images/train2014/COCO_train2014_000000000194.jpg -../coco/images/train2014/COCO_train2014_000000000201.jpg -../coco/images/train2014/COCO_train2014_000000000247.jpg -../coco/images/train2014/COCO_train2014_000000000260.jpg -../coco/images/train2014/COCO_train2014_000000000263.jpg -../coco/images/train2014/COCO_train2014_000000000307.jpg -../coco/images/train2014/COCO_train2014_000000000308.jpg -../coco/images/train2014/COCO_train2014_000000000309.jpg -../coco/images/train2014/COCO_train2014_000000000312.jpg -../coco/images/train2014/COCO_train2014_000000000315.jpg -../coco/images/train2014/COCO_train2014_000000000321.jpg -../coco/images/train2014/COCO_train2014_000000000322.jpg -../coco/images/train2014/COCO_train2014_000000000326.jpg -../coco/images/train2014/COCO_train2014_000000000332.jpg -../coco/images/train2014/COCO_train2014_000000000349.jpg -../coco/images/train2014/COCO_train2014_000000000368.jpg -../coco/images/train2014/COCO_train2014_000000000370.jpg -../coco/images/train2014/COCO_train2014_000000000382.jpg -../coco/images/train2014/COCO_train2014_000000000384.jpg -../coco/images/train2014/COCO_train2014_000000000389.jpg -../coco/images/train2014/COCO_train2014_000000000394.jpg -../coco/images/train2014/COCO_train2014_000000000404.jpg -../coco/images/train2014/COCO_train2014_000000000419.jpg -../coco/images/train2014/COCO_train2014_000000000431.jpg -../coco/images/train2014/COCO_train2014_000000000436.jpg -../coco/images/train2014/COCO_train2014_000000000438.jpg -../coco/images/train2014/COCO_train2014_000000000443.jpg -../coco/images/train2014/COCO_train2014_000000000446.jpg -../coco/images/train2014/COCO_train2014_000000000450.jpg -../coco/images/train2014/COCO_train2014_000000000471.jpg -../coco/images/train2014/COCO_train2014_000000000490.jpg -../coco/images/train2014/COCO_train2014_000000000491.jpg -../coco/images/train2014/COCO_train2014_000000000510.jpg -../coco/images/train2014/COCO_train2014_000000000514.jpg -../coco/images/train2014/COCO_train2014_000000000529.jpg -../coco/images/train2014/COCO_train2014_000000000531.jpg -../coco/images/train2014/COCO_train2014_000000000532.jpg -../coco/images/train2014/COCO_train2014_000000000540.jpg -../coco/images/train2014/COCO_train2014_000000000542.jpg -../coco/images/train2014/COCO_train2014_000000000560.jpg -../coco/images/train2014/COCO_train2014_000000000562.jpg -../coco/images/train2014/COCO_train2014_000000000572.jpg -../coco/images/train2014/COCO_train2014_000000000575.jpg -../coco/images/train2014/COCO_train2014_000000000581.jpg -../coco/images/train2014/COCO_train2014_000000000584.jpg -../coco/images/train2014/COCO_train2014_000000000595.jpg -../coco/images/train2014/COCO_train2014_000000000597.jpg -../coco/images/train2014/COCO_train2014_000000000605.jpg -../coco/images/train2014/COCO_train2014_000000000612.jpg -../coco/images/train2014/COCO_train2014_000000000620.jpg -../coco/images/train2014/COCO_train2014_000000000625.jpg -../coco/images/train2014/COCO_train2014_000000000629.jpg -../coco/images/train2014/COCO_train2014_000000000634.jpg -../coco/images/train2014/COCO_train2014_000000000643.jpg -../coco/images/train2014/COCO_train2014_000000000650.jpg -../coco/images/train2014/COCO_train2014_000000000656.jpg -../coco/images/train2014/COCO_train2014_000000000659.jpg -../coco/images/train2014/COCO_train2014_000000000670.jpg -../coco/images/train2014/COCO_train2014_000000000671.jpg -../coco/images/train2014/COCO_train2014_000000000673.jpg -../coco/images/train2014/COCO_train2014_000000000681.jpg -../coco/images/train2014/COCO_train2014_000000000684.jpg -../coco/images/train2014/COCO_train2014_000000000690.jpg -../coco/images/train2014/COCO_train2014_000000000706.jpg -../coco/images/train2014/COCO_train2014_000000000714.jpg -../coco/images/train2014/COCO_train2014_000000000716.jpg -../coco/images/train2014/COCO_train2014_000000000722.jpg -../coco/images/train2014/COCO_train2014_000000000723.jpg -../coco/images/train2014/COCO_train2014_000000000731.jpg -../coco/images/train2014/COCO_train2014_000000000735.jpg -../coco/images/train2014/COCO_train2014_000000000753.jpg -../coco/images/train2014/COCO_train2014_000000000754.jpg -../coco/images/train2014/COCO_train2014_000000000762.jpg -../coco/images/train2014/COCO_train2014_000000000781.jpg -../coco/images/train2014/COCO_train2014_000000000790.jpg -../coco/images/train2014/COCO_train2014_000000000795.jpg -../coco/images/train2014/COCO_train2014_000000000797.jpg -../coco/images/train2014/COCO_train2014_000000000801.jpg -../coco/images/train2014/COCO_train2014_000000000813.jpg -../coco/images/train2014/COCO_train2014_000000000821.jpg -../coco/images/train2014/COCO_train2014_000000000825.jpg -../coco/images/train2014/COCO_train2014_000000000828.jpg -../coco/images/train2014/COCO_train2014_000000000839.jpg -../coco/images/train2014/COCO_train2014_000000000853.jpg -../coco/images/train2014/COCO_train2014_000000000882.jpg -../coco/images/train2014/COCO_train2014_000000000897.jpg -../coco/images/train2014/COCO_train2014_000000000901.jpg -../coco/images/train2014/COCO_train2014_000000000902.jpg -../coco/images/train2014/COCO_train2014_000000000908.jpg -../coco/images/train2014/COCO_train2014_000000000909.jpg -../coco/images/train2014/COCO_train2014_000000000913.jpg -../coco/images/train2014/COCO_train2014_000000000925.jpg -../coco/images/train2014/COCO_train2014_000000000927.jpg -../coco/images/train2014/COCO_train2014_000000000934.jpg -../coco/images/train2014/COCO_train2014_000000000941.jpg -../coco/images/train2014/COCO_train2014_000000000943.jpg -../coco/images/train2014/COCO_train2014_000000000955.jpg -../coco/images/train2014/COCO_train2014_000000000960.jpg -../coco/images/train2014/COCO_train2014_000000000965.jpg -../coco/images/train2014/COCO_train2014_000000000977.jpg -../coco/images/train2014/COCO_train2014_000000000982.jpg -../coco/images/train2014/COCO_train2014_000000000984.jpg -../coco/images/train2014/COCO_train2014_000000000996.jpg -../coco/images/train2014/COCO_train2014_000000001006.jpg -../coco/images/train2014/COCO_train2014_000000001011.jpg -../coco/images/train2014/COCO_train2014_000000001014.jpg -../coco/images/train2014/COCO_train2014_000000001025.jpg -../coco/images/train2014/COCO_train2014_000000001036.jpg -../coco/images/train2014/COCO_train2014_000000001053.jpg -../coco/images/train2014/COCO_train2014_000000001059.jpg -../coco/images/train2014/COCO_train2014_000000001072.jpg -../coco/images/train2014/COCO_train2014_000000001084.jpg -../coco/images/train2014/COCO_train2014_000000001085.jpg -../coco/images/train2014/COCO_train2014_000000001090.jpg -../coco/images/train2014/COCO_train2014_000000001098.jpg -../coco/images/train2014/COCO_train2014_000000001099.jpg -../coco/images/train2014/COCO_train2014_000000001102.jpg -../coco/images/train2014/COCO_train2014_000000001107.jpg -../coco/images/train2014/COCO_train2014_000000001108.jpg -../coco/images/train2014/COCO_train2014_000000001122.jpg -../coco/images/train2014/COCO_train2014_000000001139.jpg -../coco/images/train2014/COCO_train2014_000000001144.jpg -../coco/images/train2014/COCO_train2014_000000001145.jpg -../coco/images/train2014/COCO_train2014_000000001155.jpg -../coco/images/train2014/COCO_train2014_000000001166.jpg -../coco/images/train2014/COCO_train2014_000000001168.jpg -../coco/images/train2014/COCO_train2014_000000001183.jpg -../coco/images/train2014/COCO_train2014_000000001200.jpg -../coco/images/train2014/COCO_train2014_000000001204.jpg -../coco/images/train2014/COCO_train2014_000000001213.jpg -../coco/images/train2014/COCO_train2014_000000001216.jpg -../coco/images/train2014/COCO_train2014_000000001224.jpg -../coco/images/train2014/COCO_train2014_000000001232.jpg -../coco/images/train2014/COCO_train2014_000000001237.jpg -../coco/images/train2014/COCO_train2014_000000001238.jpg -../coco/images/train2014/COCO_train2014_000000001261.jpg -../coco/images/train2014/COCO_train2014_000000001264.jpg -../coco/images/train2014/COCO_train2014_000000001271.jpg -../coco/images/train2014/COCO_train2014_000000001282.jpg -../coco/images/train2014/COCO_train2014_000000001295.jpg -../coco/images/train2014/COCO_train2014_000000001298.jpg -../coco/images/train2014/COCO_train2014_000000001306.jpg -../coco/images/train2014/COCO_train2014_000000001307.jpg -../coco/images/train2014/COCO_train2014_000000001308.jpg -../coco/images/train2014/COCO_train2014_000000001311.jpg -../coco/images/train2014/COCO_train2014_000000001315.jpg -../coco/images/train2014/COCO_train2014_000000001319.jpg -../coco/images/train2014/COCO_train2014_000000001323.jpg -../coco/images/train2014/COCO_train2014_000000001330.jpg -../coco/images/train2014/COCO_train2014_000000001332.jpg -../coco/images/train2014/COCO_train2014_000000001350.jpg -../coco/images/train2014/COCO_train2014_000000001355.jpg -../coco/images/train2014/COCO_train2014_000000001359.jpg -../coco/images/train2014/COCO_train2014_000000001360.jpg -../coco/images/train2014/COCO_train2014_000000001366.jpg -../coco/images/train2014/COCO_train2014_000000001375.jpg -../coco/images/train2014/COCO_train2014_000000001381.jpg -../coco/images/train2014/COCO_train2014_000000001386.jpg -../coco/images/train2014/COCO_train2014_000000001390.jpg -../coco/images/train2014/COCO_train2014_000000001392.jpg -../coco/images/train2014/COCO_train2014_000000001397.jpg -../coco/images/train2014/COCO_train2014_000000001401.jpg -../coco/images/train2014/COCO_train2014_000000001403.jpg -../coco/images/train2014/COCO_train2014_000000001407.jpg -../coco/images/train2014/COCO_train2014_000000001408.jpg -../coco/images/train2014/COCO_train2014_000000001424.jpg -../coco/images/train2014/COCO_train2014_000000001431.jpg -../coco/images/train2014/COCO_train2014_000000001451.jpg -../coco/images/train2014/COCO_train2014_000000001453.jpg -../coco/images/train2014/COCO_train2014_000000001455.jpg -../coco/images/train2014/COCO_train2014_000000001488.jpg -../coco/images/train2014/COCO_train2014_000000001496.jpg -../coco/images/train2014/COCO_train2014_000000001497.jpg -../coco/images/train2014/COCO_train2014_000000001501.jpg -../coco/images/train2014/COCO_train2014_000000001505.jpg -../coco/images/train2014/COCO_train2014_000000001507.jpg -../coco/images/train2014/COCO_train2014_000000001510.jpg -../coco/images/train2014/COCO_train2014_000000001515.jpg -../coco/images/train2014/COCO_train2014_000000001518.jpg -../coco/images/train2014/COCO_train2014_000000001522.jpg -../coco/images/train2014/COCO_train2014_000000001523.jpg -../coco/images/train2014/COCO_train2014_000000001526.jpg -../coco/images/train2014/COCO_train2014_000000001527.jpg -../coco/images/train2014/COCO_train2014_000000001536.jpg -../coco/images/train2014/COCO_train2014_000000001548.jpg -../coco/images/train2014/COCO_train2014_000000001558.jpg -../coco/images/train2014/COCO_train2014_000000001562.jpg -../coco/images/train2014/COCO_train2014_000000001569.jpg -../coco/images/train2014/COCO_train2014_000000001579.jpg -../coco/images/train2014/COCO_train2014_000000001580.jpg -../coco/images/train2014/COCO_train2014_000000001586.jpg -../coco/images/train2014/COCO_train2014_000000001589.jpg -../coco/images/train2014/COCO_train2014_000000001596.jpg -../coco/images/train2014/COCO_train2014_000000001611.jpg -../coco/images/train2014/COCO_train2014_000000001622.jpg -../coco/images/train2014/COCO_train2014_000000001625.jpg -../coco/images/train2014/COCO_train2014_000000001637.jpg -../coco/images/train2014/COCO_train2014_000000001639.jpg -../coco/images/train2014/COCO_train2014_000000001645.jpg -../coco/images/train2014/COCO_train2014_000000001670.jpg -../coco/images/train2014/COCO_train2014_000000001674.jpg -../coco/images/train2014/COCO_train2014_000000001681.jpg -../coco/images/train2014/COCO_train2014_000000001688.jpg -../coco/images/train2014/COCO_train2014_000000001697.jpg -../coco/images/train2014/COCO_train2014_000000001706.jpg -../coco/images/train2014/COCO_train2014_000000001709.jpg -../coco/images/train2014/COCO_train2014_000000001712.jpg -../coco/images/train2014/COCO_train2014_000000001720.jpg -../coco/images/train2014/COCO_train2014_000000001732.jpg -../coco/images/train2014/COCO_train2014_000000001737.jpg -../coco/images/train2014/COCO_train2014_000000001756.jpg -../coco/images/train2014/COCO_train2014_000000001762.jpg -../coco/images/train2014/COCO_train2014_000000001764.jpg -../coco/images/train2014/COCO_train2014_000000001771.jpg -../coco/images/train2014/COCO_train2014_000000001774.jpg -../coco/images/train2014/COCO_train2014_000000001777.jpg -../coco/images/train2014/COCO_train2014_000000001781.jpg -../coco/images/train2014/COCO_train2014_000000001785.jpg -../coco/images/train2014/COCO_train2014_000000001786.jpg -../coco/images/train2014/COCO_train2014_000000001790.jpg -../coco/images/train2014/COCO_train2014_000000001792.jpg -../coco/images/train2014/COCO_train2014_000000001804.jpg -../coco/images/train2014/COCO_train2014_000000001810.jpg -../coco/images/train2014/COCO_train2014_000000001811.jpg -../coco/images/train2014/COCO_train2014_000000001813.jpg -../coco/images/train2014/COCO_train2014_000000001815.jpg -../coco/images/train2014/COCO_train2014_000000001822.jpg -../coco/images/train2014/COCO_train2014_000000001837.jpg -../coco/images/train2014/COCO_train2014_000000001864.jpg -../coco/images/train2014/COCO_train2014_000000001875.jpg -../coco/images/train2014/COCO_train2014_000000001877.jpg -../coco/images/train2014/COCO_train2014_000000001888.jpg -../coco/images/train2014/COCO_train2014_000000001895.jpg -../coco/images/train2014/COCO_train2014_000000001900.jpg -../coco/images/train2014/COCO_train2014_000000001902.jpg -../coco/images/train2014/COCO_train2014_000000001906.jpg -../coco/images/train2014/COCO_train2014_000000001907.jpg -../coco/images/train2014/COCO_train2014_000000001911.jpg -../coco/images/train2014/COCO_train2014_000000001912.jpg -../coco/images/train2014/COCO_train2014_000000001915.jpg -../coco/images/train2014/COCO_train2014_000000001924.jpg -../coco/images/train2014/COCO_train2014_000000001926.jpg -../coco/images/train2014/COCO_train2014_000000001941.jpg -../coco/images/train2014/COCO_train2014_000000001942.jpg -../coco/images/train2014/COCO_train2014_000000001943.jpg -../coco/images/train2014/COCO_train2014_000000001947.jpg -../coco/images/train2014/COCO_train2014_000000001958.jpg -../coco/images/train2014/COCO_train2014_000000001966.jpg -../coco/images/train2014/COCO_train2014_000000001994.jpg -../coco/images/train2014/COCO_train2014_000000001999.jpg -../coco/images/train2014/COCO_train2014_000000002001.jpg -../coco/images/train2014/COCO_train2014_000000002007.jpg -../coco/images/train2014/COCO_train2014_000000002024.jpg -../coco/images/train2014/COCO_train2014_000000002055.jpg -../coco/images/train2014/COCO_train2014_000000002056.jpg -../coco/images/train2014/COCO_train2014_000000002066.jpg -../coco/images/train2014/COCO_train2014_000000002068.jpg -../coco/images/train2014/COCO_train2014_000000002072.jpg -../coco/images/train2014/COCO_train2014_000000002083.jpg -../coco/images/train2014/COCO_train2014_000000002089.jpg -../coco/images/train2014/COCO_train2014_000000002093.jpg -../coco/images/train2014/COCO_train2014_000000002106.jpg -../coco/images/train2014/COCO_train2014_000000002114.jpg -../coco/images/train2014/COCO_train2014_000000002135.jpg -../coco/images/train2014/COCO_train2014_000000002148.jpg -../coco/images/train2014/COCO_train2014_000000002150.jpg -../coco/images/train2014/COCO_train2014_000000002178.jpg -../coco/images/train2014/COCO_train2014_000000002184.jpg -../coco/images/train2014/COCO_train2014_000000002193.jpg -../coco/images/train2014/COCO_train2014_000000002197.jpg -../coco/images/train2014/COCO_train2014_000000002209.jpg -../coco/images/train2014/COCO_train2014_000000002211.jpg -../coco/images/train2014/COCO_train2014_000000002217.jpg -../coco/images/train2014/COCO_train2014_000000002229.jpg -../coco/images/train2014/COCO_train2014_000000002232.jpg -../coco/images/train2014/COCO_train2014_000000002244.jpg -../coco/images/train2014/COCO_train2014_000000002258.jpg -../coco/images/train2014/COCO_train2014_000000002270.jpg -../coco/images/train2014/COCO_train2014_000000002276.jpg -../coco/images/train2014/COCO_train2014_000000002278.jpg -../coco/images/train2014/COCO_train2014_000000002279.jpg -../coco/images/train2014/COCO_train2014_000000002280.jpg -../coco/images/train2014/COCO_train2014_000000002281.jpg -../coco/images/train2014/COCO_train2014_000000002283.jpg -../coco/images/train2014/COCO_train2014_000000002284.jpg -../coco/images/train2014/COCO_train2014_000000002296.jpg -../coco/images/train2014/COCO_train2014_000000002309.jpg -../coco/images/train2014/COCO_train2014_000000002337.jpg -../coco/images/train2014/COCO_train2014_000000002342.jpg -../coco/images/train2014/COCO_train2014_000000002347.jpg -../coco/images/train2014/COCO_train2014_000000002349.jpg -../coco/images/train2014/COCO_train2014_000000002369.jpg -../coco/images/train2014/COCO_train2014_000000002372.jpg -../coco/images/train2014/COCO_train2014_000000002374.jpg -../coco/images/train2014/COCO_train2014_000000002377.jpg -../coco/images/train2014/COCO_train2014_000000002389.jpg -../coco/images/train2014/COCO_train2014_000000002400.jpg -../coco/images/train2014/COCO_train2014_000000002402.jpg -../coco/images/train2014/COCO_train2014_000000002411.jpg -../coco/images/train2014/COCO_train2014_000000002415.jpg -../coco/images/train2014/COCO_train2014_000000002429.jpg -../coco/images/train2014/COCO_train2014_000000002444.jpg -../coco/images/train2014/COCO_train2014_000000002445.jpg -../coco/images/train2014/COCO_train2014_000000002446.jpg -../coco/images/train2014/COCO_train2014_000000002448.jpg -../coco/images/train2014/COCO_train2014_000000002451.jpg -../coco/images/train2014/COCO_train2014_000000002459.jpg -../coco/images/train2014/COCO_train2014_000000002466.jpg -../coco/images/train2014/COCO_train2014_000000002470.jpg -../coco/images/train2014/COCO_train2014_000000002471.jpg -../coco/images/train2014/COCO_train2014_000000002496.jpg -../coco/images/train2014/COCO_train2014_000000002498.jpg -../coco/images/train2014/COCO_train2014_000000002531.jpg -../coco/images/train2014/COCO_train2014_000000002536.jpg -../coco/images/train2014/COCO_train2014_000000002543.jpg -../coco/images/train2014/COCO_train2014_000000002544.jpg -../coco/images/train2014/COCO_train2014_000000002545.jpg -../coco/images/train2014/COCO_train2014_000000002555.jpg -../coco/images/train2014/COCO_train2014_000000002559.jpg -../coco/images/train2014/COCO_train2014_000000002560.jpg -../coco/images/train2014/COCO_train2014_000000002563.jpg -../coco/images/train2014/COCO_train2014_000000002567.jpg -../coco/images/train2014/COCO_train2014_000000002570.jpg -../coco/images/train2014/COCO_train2014_000000002575.jpg -../coco/images/train2014/COCO_train2014_000000002583.jpg -../coco/images/train2014/COCO_train2014_000000002585.jpg -../coco/images/train2014/COCO_train2014_000000002591.jpg -../coco/images/train2014/COCO_train2014_000000002602.jpg -../coco/images/train2014/COCO_train2014_000000002606.jpg -../coco/images/train2014/COCO_train2014_000000002608.jpg -../coco/images/train2014/COCO_train2014_000000002614.jpg -../coco/images/train2014/COCO_train2014_000000002618.jpg -../coco/images/train2014/COCO_train2014_000000002619.jpg -../coco/images/train2014/COCO_train2014_000000002623.jpg -../coco/images/train2014/COCO_train2014_000000002624.jpg -../coco/images/train2014/COCO_train2014_000000002639.jpg -../coco/images/train2014/COCO_train2014_000000002644.jpg -../coco/images/train2014/COCO_train2014_000000002645.jpg -../coco/images/train2014/COCO_train2014_000000002658.jpg -../coco/images/train2014/COCO_train2014_000000002664.jpg -../coco/images/train2014/COCO_train2014_000000002672.jpg -../coco/images/train2014/COCO_train2014_000000002686.jpg -../coco/images/train2014/COCO_train2014_000000002687.jpg -../coco/images/train2014/COCO_train2014_000000002691.jpg -../coco/images/train2014/COCO_train2014_000000002693.jpg -../coco/images/train2014/COCO_train2014_000000002697.jpg -../coco/images/train2014/COCO_train2014_000000002703.jpg -../coco/images/train2014/COCO_train2014_000000002732.jpg -../coco/images/train2014/COCO_train2014_000000002742.jpg -../coco/images/train2014/COCO_train2014_000000002752.jpg -../coco/images/train2014/COCO_train2014_000000002754.jpg -../coco/images/train2014/COCO_train2014_000000002755.jpg -../coco/images/train2014/COCO_train2014_000000002758.jpg -../coco/images/train2014/COCO_train2014_000000002770.jpg -../coco/images/train2014/COCO_train2014_000000002774.jpg -../coco/images/train2014/COCO_train2014_000000002776.jpg -../coco/images/train2014/COCO_train2014_000000002782.jpg -../coco/images/train2014/COCO_train2014_000000002823.jpg -../coco/images/train2014/COCO_train2014_000000002833.jpg -../coco/images/train2014/COCO_train2014_000000002842.jpg -../coco/images/train2014/COCO_train2014_000000002843.jpg -../coco/images/train2014/COCO_train2014_000000002849.jpg -../coco/images/train2014/COCO_train2014_000000002860.jpg -../coco/images/train2014/COCO_train2014_000000002886.jpg -../coco/images/train2014/COCO_train2014_000000002892.jpg -../coco/images/train2014/COCO_train2014_000000002896.jpg -../coco/images/train2014/COCO_train2014_000000002902.jpg -../coco/images/train2014/COCO_train2014_000000002907.jpg -../coco/images/train2014/COCO_train2014_000000002931.jpg -../coco/images/train2014/COCO_train2014_000000002951.jpg -../coco/images/train2014/COCO_train2014_000000002963.jpg -../coco/images/train2014/COCO_train2014_000000002964.jpg -../coco/images/train2014/COCO_train2014_000000002982.jpg -../coco/images/train2014/COCO_train2014_000000002983.jpg -../coco/images/train2014/COCO_train2014_000000002989.jpg -../coco/images/train2014/COCO_train2014_000000002992.jpg -../coco/images/train2014/COCO_train2014_000000002998.jpg -../coco/images/train2014/COCO_train2014_000000003000.jpg -../coco/images/train2014/COCO_train2014_000000003003.jpg -../coco/images/train2014/COCO_train2014_000000003008.jpg -../coco/images/train2014/COCO_train2014_000000003040.jpg -../coco/images/train2014/COCO_train2014_000000003048.jpg -../coco/images/train2014/COCO_train2014_000000003076.jpg -../coco/images/train2014/COCO_train2014_000000003077.jpg -../coco/images/train2014/COCO_train2014_000000003080.jpg -../coco/images/train2014/COCO_train2014_000000003118.jpg -../coco/images/train2014/COCO_train2014_000000003124.jpg -../coco/images/train2014/COCO_train2014_000000003131.jpg -../coco/images/train2014/COCO_train2014_000000003148.jpg -../coco/images/train2014/COCO_train2014_000000003157.jpg -../coco/images/train2014/COCO_train2014_000000003160.jpg -../coco/images/train2014/COCO_train2014_000000003178.jpg -../coco/images/train2014/COCO_train2014_000000003197.jpg -../coco/images/train2014/COCO_train2014_000000003219.jpg -../coco/images/train2014/COCO_train2014_000000003220.jpg -../coco/images/train2014/COCO_train2014_000000003224.jpg -../coco/images/train2014/COCO_train2014_000000003225.jpg -../coco/images/train2014/COCO_train2014_000000003234.jpg -../coco/images/train2014/COCO_train2014_000000003236.jpg -../coco/images/train2014/COCO_train2014_000000003242.jpg -../coco/images/train2014/COCO_train2014_000000003249.jpg -../coco/images/train2014/COCO_train2014_000000003259.jpg -../coco/images/train2014/COCO_train2014_000000003264.jpg -../coco/images/train2014/COCO_train2014_000000003270.jpg -../coco/images/train2014/COCO_train2014_000000003272.jpg -../coco/images/train2014/COCO_train2014_000000003276.jpg -../coco/images/train2014/COCO_train2014_000000003286.jpg -../coco/images/train2014/COCO_train2014_000000003293.jpg -../coco/images/train2014/COCO_train2014_000000003305.jpg -../coco/images/train2014/COCO_train2014_000000003314.jpg -../coco/images/train2014/COCO_train2014_000000003320.jpg -../coco/images/train2014/COCO_train2014_000000003321.jpg -../coco/images/train2014/COCO_train2014_000000003325.jpg -../coco/images/train2014/COCO_train2014_000000003348.jpg -../coco/images/train2014/COCO_train2014_000000003353.jpg -../coco/images/train2014/COCO_train2014_000000003361.jpg -../coco/images/train2014/COCO_train2014_000000003365.jpg -../coco/images/train2014/COCO_train2014_000000003366.jpg -../coco/images/train2014/COCO_train2014_000000003375.jpg -../coco/images/train2014/COCO_train2014_000000003386.jpg -../coco/images/train2014/COCO_train2014_000000003389.jpg -../coco/images/train2014/COCO_train2014_000000003398.jpg -../coco/images/train2014/COCO_train2014_000000003412.jpg -../coco/images/train2014/COCO_train2014_000000003432.jpg -../coco/images/train2014/COCO_train2014_000000003442.jpg -../coco/images/train2014/COCO_train2014_000000003457.jpg -../coco/images/train2014/COCO_train2014_000000003461.jpg -../coco/images/train2014/COCO_train2014_000000003464.jpg -../coco/images/train2014/COCO_train2014_000000003474.jpg -../coco/images/train2014/COCO_train2014_000000003478.jpg -../coco/images/train2014/COCO_train2014_000000003481.jpg -../coco/images/train2014/COCO_train2014_000000003483.jpg -../coco/images/train2014/COCO_train2014_000000003493.jpg -../coco/images/train2014/COCO_train2014_000000003511.jpg -../coco/images/train2014/COCO_train2014_000000003514.jpg -../coco/images/train2014/COCO_train2014_000000003517.jpg -../coco/images/train2014/COCO_train2014_000000003518.jpg -../coco/images/train2014/COCO_train2014_000000003521.jpg -../coco/images/train2014/COCO_train2014_000000003528.jpg -../coco/images/train2014/COCO_train2014_000000003532.jpg -../coco/images/train2014/COCO_train2014_000000003535.jpg -../coco/images/train2014/COCO_train2014_000000003538.jpg -../coco/images/train2014/COCO_train2014_000000003579.jpg -../coco/images/train2014/COCO_train2014_000000003602.jpg -../coco/images/train2014/COCO_train2014_000000003613.jpg -../coco/images/train2014/COCO_train2014_000000003623.jpg -../coco/images/train2014/COCO_train2014_000000003628.jpg -../coco/images/train2014/COCO_train2014_000000003637.jpg -../coco/images/train2014/COCO_train2014_000000003668.jpg -../coco/images/train2014/COCO_train2014_000000003671.jpg -../coco/images/train2014/COCO_train2014_000000003682.jpg -../coco/images/train2014/COCO_train2014_000000003685.jpg -../coco/images/train2014/COCO_train2014_000000003713.jpg -../coco/images/train2014/COCO_train2014_000000003729.jpg -../coco/images/train2014/COCO_train2014_000000003735.jpg -../coco/images/train2014/COCO_train2014_000000003737.jpg -../coco/images/train2014/COCO_train2014_000000003745.jpg -../coco/images/train2014/COCO_train2014_000000003751.jpg -../coco/images/train2014/COCO_train2014_000000003764.jpg -../coco/images/train2014/COCO_train2014_000000003770.jpg -../coco/images/train2014/COCO_train2014_000000003782.jpg -../coco/images/train2014/COCO_train2014_000000003789.jpg -../coco/images/train2014/COCO_train2014_000000003804.jpg -../coco/images/train2014/COCO_train2014_000000003812.jpg -../coco/images/train2014/COCO_train2014_000000003823.jpg -../coco/images/train2014/COCO_train2014_000000003827.jpg -../coco/images/train2014/COCO_train2014_000000003830.jpg -../coco/images/train2014/COCO_train2014_000000003860.jpg -../coco/images/train2014/COCO_train2014_000000003862.jpg -../coco/images/train2014/COCO_train2014_000000003866.jpg -../coco/images/train2014/COCO_train2014_000000003870.jpg -../coco/images/train2014/COCO_train2014_000000003877.jpg diff --git a/data/coco_500val.data b/data/coco_500val.data deleted file mode 100644 index 4edf9ed352..0000000000 --- a/data/coco_500val.data +++ /dev/null @@ -1,6 +0,0 @@ -classes=80 -train=./data/coco_500img.txt -valid=./data/coco_500val.txt -names=data/coco.names -backup=backup/ -eval=coco diff --git a/data/coco_500val.txt b/data/coco_500val.txt deleted file mode 100644 index 443fb5fcae..0000000000 --- a/data/coco_500val.txt +++ /dev/null @@ -1,500 +0,0 @@ -../coco/images/val2014/COCO_val2014_000000000164.jpg -../coco/images/val2014/COCO_val2014_000000000192.jpg -../coco/images/val2014/COCO_val2014_000000000283.jpg -../coco/images/val2014/COCO_val2014_000000000397.jpg -../coco/images/val2014/COCO_val2014_000000000589.jpg -../coco/images/val2014/COCO_val2014_000000000599.jpg -../coco/images/val2014/COCO_val2014_000000000711.jpg -../coco/images/val2014/COCO_val2014_000000000757.jpg -../coco/images/val2014/COCO_val2014_000000000764.jpg -../coco/images/val2014/COCO_val2014_000000000872.jpg -../coco/images/val2014/COCO_val2014_000000001063.jpg -../coco/images/val2014/COCO_val2014_000000001554.jpg -../coco/images/val2014/COCO_val2014_000000001667.jpg -../coco/images/val2014/COCO_val2014_000000001700.jpg -../coco/images/val2014/COCO_val2014_000000001869.jpg -../coco/images/val2014/COCO_val2014_000000002124.jpg -../coco/images/val2014/COCO_val2014_000000002261.jpg -../coco/images/val2014/COCO_val2014_000000002621.jpg -../coco/images/val2014/COCO_val2014_000000002684.jpg -../coco/images/val2014/COCO_val2014_000000002764.jpg -../coco/images/val2014/COCO_val2014_000000002894.jpg -../coco/images/val2014/COCO_val2014_000000002972.jpg -../coco/images/val2014/COCO_val2014_000000003035.jpg -../coco/images/val2014/COCO_val2014_000000003084.jpg -../coco/images/val2014/COCO_val2014_000000003103.jpg -../coco/images/val2014/COCO_val2014_000000003109.jpg -../coco/images/val2014/COCO_val2014_000000003134.jpg -../coco/images/val2014/COCO_val2014_000000003209.jpg -../coco/images/val2014/COCO_val2014_000000003244.jpg -../coco/images/val2014/COCO_val2014_000000003326.jpg -../coco/images/val2014/COCO_val2014_000000003337.jpg -../coco/images/val2014/COCO_val2014_000000003661.jpg -../coco/images/val2014/COCO_val2014_000000003711.jpg -../coco/images/val2014/COCO_val2014_000000003779.jpg -../coco/images/val2014/COCO_val2014_000000003865.jpg -../coco/images/val2014/COCO_val2014_000000004079.jpg -../coco/images/val2014/COCO_val2014_000000004092.jpg -../coco/images/val2014/COCO_val2014_000000004283.jpg -../coco/images/val2014/COCO_val2014_000000004296.jpg -../coco/images/val2014/COCO_val2014_000000004392.jpg -../coco/images/val2014/COCO_val2014_000000004742.jpg -../coco/images/val2014/COCO_val2014_000000004754.jpg -../coco/images/val2014/COCO_val2014_000000004764.jpg -../coco/images/val2014/COCO_val2014_000000005038.jpg -../coco/images/val2014/COCO_val2014_000000005060.jpg -../coco/images/val2014/COCO_val2014_000000005124.jpg -../coco/images/val2014/COCO_val2014_000000005178.jpg -../coco/images/val2014/COCO_val2014_000000005205.jpg -../coco/images/val2014/COCO_val2014_000000005443.jpg -../coco/images/val2014/COCO_val2014_000000005652.jpg -../coco/images/val2014/COCO_val2014_000000005723.jpg -../coco/images/val2014/COCO_val2014_000000005804.jpg -../coco/images/val2014/COCO_val2014_000000006074.jpg -../coco/images/val2014/COCO_val2014_000000006091.jpg -../coco/images/val2014/COCO_val2014_000000006153.jpg -../coco/images/val2014/COCO_val2014_000000006213.jpg -../coco/images/val2014/COCO_val2014_000000006497.jpg -../coco/images/val2014/COCO_val2014_000000006789.jpg -../coco/images/val2014/COCO_val2014_000000006847.jpg -../coco/images/val2014/COCO_val2014_000000007241.jpg -../coco/images/val2014/COCO_val2014_000000007256.jpg -../coco/images/val2014/COCO_val2014_000000007281.jpg -../coco/images/val2014/COCO_val2014_000000007795.jpg -../coco/images/val2014/COCO_val2014_000000007867.jpg -../coco/images/val2014/COCO_val2014_000000007873.jpg -../coco/images/val2014/COCO_val2014_000000007899.jpg -../coco/images/val2014/COCO_val2014_000000008010.jpg -../coco/images/val2014/COCO_val2014_000000008179.jpg -../coco/images/val2014/COCO_val2014_000000008190.jpg -../coco/images/val2014/COCO_val2014_000000008204.jpg -../coco/images/val2014/COCO_val2014_000000008350.jpg -../coco/images/val2014/COCO_val2014_000000008493.jpg -../coco/images/val2014/COCO_val2014_000000008853.jpg -../coco/images/val2014/COCO_val2014_000000009105.jpg -../coco/images/val2014/COCO_val2014_000000009156.jpg -../coco/images/val2014/COCO_val2014_000000009217.jpg -../coco/images/val2014/COCO_val2014_000000009270.jpg -../coco/images/val2014/COCO_val2014_000000009286.jpg -../coco/images/val2014/COCO_val2014_000000009548.jpg -../coco/images/val2014/COCO_val2014_000000009553.jpg -../coco/images/val2014/COCO_val2014_000000009727.jpg -../coco/images/val2014/COCO_val2014_000000009908.jpg -../coco/images/val2014/COCO_val2014_000000010114.jpg -../coco/images/val2014/COCO_val2014_000000010249.jpg -../coco/images/val2014/COCO_val2014_000000010395.jpg -../coco/images/val2014/COCO_val2014_000000010400.jpg -../coco/images/val2014/COCO_val2014_000000010463.jpg -../coco/images/val2014/COCO_val2014_000000010613.jpg -../coco/images/val2014/COCO_val2014_000000010764.jpg -../coco/images/val2014/COCO_val2014_000000010779.jpg -../coco/images/val2014/COCO_val2014_000000010928.jpg -../coco/images/val2014/COCO_val2014_000000011099.jpg -../coco/images/val2014/COCO_val2014_000000011181.jpg -../coco/images/val2014/COCO_val2014_000000011184.jpg -../coco/images/val2014/COCO_val2014_000000011197.jpg -../coco/images/val2014/COCO_val2014_000000011320.jpg -../coco/images/val2014/COCO_val2014_000000011721.jpg -../coco/images/val2014/COCO_val2014_000000011813.jpg -../coco/images/val2014/COCO_val2014_000000012014.jpg -../coco/images/val2014/COCO_val2014_000000012047.jpg -../coco/images/val2014/COCO_val2014_000000012085.jpg -../coco/images/val2014/COCO_val2014_000000012115.jpg -../coco/images/val2014/COCO_val2014_000000012166.jpg -../coco/images/val2014/COCO_val2014_000000012230.jpg -../coco/images/val2014/COCO_val2014_000000012370.jpg -../coco/images/val2014/COCO_val2014_000000012375.jpg -../coco/images/val2014/COCO_val2014_000000012448.jpg -../coco/images/val2014/COCO_val2014_000000012543.jpg -../coco/images/val2014/COCO_val2014_000000012744.jpg -../coco/images/val2014/COCO_val2014_000000012897.jpg -../coco/images/val2014/COCO_val2014_000000012966.jpg -../coco/images/val2014/COCO_val2014_000000012993.jpg -../coco/images/val2014/COCO_val2014_000000013004.jpg -../coco/images/val2014/COCO_val2014_000000013333.jpg -../coco/images/val2014/COCO_val2014_000000013357.jpg -../coco/images/val2014/COCO_val2014_000000013774.jpg -../coco/images/val2014/COCO_val2014_000000014029.jpg -../coco/images/val2014/COCO_val2014_000000014056.jpg -../coco/images/val2014/COCO_val2014_000000014108.jpg -../coco/images/val2014/COCO_val2014_000000014135.jpg -../coco/images/val2014/COCO_val2014_000000014226.jpg -../coco/images/val2014/COCO_val2014_000000014306.jpg -../coco/images/val2014/COCO_val2014_000000014591.jpg -../coco/images/val2014/COCO_val2014_000000014629.jpg -../coco/images/val2014/COCO_val2014_000000014756.jpg -../coco/images/val2014/COCO_val2014_000000014874.jpg -../coco/images/val2014/COCO_val2014_000000014990.jpg -../coco/images/val2014/COCO_val2014_000000015386.jpg -../coco/images/val2014/COCO_val2014_000000015559.jpg -../coco/images/val2014/COCO_val2014_000000015599.jpg -../coco/images/val2014/COCO_val2014_000000015709.jpg -../coco/images/val2014/COCO_val2014_000000015735.jpg -../coco/images/val2014/COCO_val2014_000000015751.jpg -../coco/images/val2014/COCO_val2014_000000015883.jpg -../coco/images/val2014/COCO_val2014_000000015953.jpg -../coco/images/val2014/COCO_val2014_000000015956.jpg -../coco/images/val2014/COCO_val2014_000000015968.jpg -../coco/images/val2014/COCO_val2014_000000015987.jpg -../coco/images/val2014/COCO_val2014_000000016030.jpg -../coco/images/val2014/COCO_val2014_000000016076.jpg -../coco/images/val2014/COCO_val2014_000000016228.jpg -../coco/images/val2014/COCO_val2014_000000016241.jpg -../coco/images/val2014/COCO_val2014_000000016257.jpg -../coco/images/val2014/COCO_val2014_000000016327.jpg -../coco/images/val2014/COCO_val2014_000000016410.jpg -../coco/images/val2014/COCO_val2014_000000016574.jpg -../coco/images/val2014/COCO_val2014_000000016716.jpg -../coco/images/val2014/COCO_val2014_000000016928.jpg -../coco/images/val2014/COCO_val2014_000000016995.jpg -../coco/images/val2014/COCO_val2014_000000017235.jpg -../coco/images/val2014/COCO_val2014_000000017379.jpg -../coco/images/val2014/COCO_val2014_000000017667.jpg -../coco/images/val2014/COCO_val2014_000000017755.jpg -../coco/images/val2014/COCO_val2014_000000018295.jpg -../coco/images/val2014/COCO_val2014_000000018358.jpg -../coco/images/val2014/COCO_val2014_000000018476.jpg -../coco/images/val2014/COCO_val2014_000000018750.jpg -../coco/images/val2014/COCO_val2014_000000018783.jpg -../coco/images/val2014/COCO_val2014_000000019025.jpg -../coco/images/val2014/COCO_val2014_000000019042.jpg -../coco/images/val2014/COCO_val2014_000000019129.jpg -../coco/images/val2014/COCO_val2014_000000019176.jpg -../coco/images/val2014/COCO_val2014_000000019491.jpg -../coco/images/val2014/COCO_val2014_000000019890.jpg -../coco/images/val2014/COCO_val2014_000000019923.jpg -../coco/images/val2014/COCO_val2014_000000020001.jpg -../coco/images/val2014/COCO_val2014_000000020038.jpg -../coco/images/val2014/COCO_val2014_000000020175.jpg -../coco/images/val2014/COCO_val2014_000000020268.jpg -../coco/images/val2014/COCO_val2014_000000020273.jpg -../coco/images/val2014/COCO_val2014_000000020349.jpg -../coco/images/val2014/COCO_val2014_000000020553.jpg -../coco/images/val2014/COCO_val2014_000000020788.jpg -../coco/images/val2014/COCO_val2014_000000020912.jpg -../coco/images/val2014/COCO_val2014_000000020947.jpg -../coco/images/val2014/COCO_val2014_000000020972.jpg -../coco/images/val2014/COCO_val2014_000000021161.jpg -../coco/images/val2014/COCO_val2014_000000021483.jpg -../coco/images/val2014/COCO_val2014_000000021588.jpg -../coco/images/val2014/COCO_val2014_000000021639.jpg -../coco/images/val2014/COCO_val2014_000000021644.jpg -../coco/images/val2014/COCO_val2014_000000021645.jpg -../coco/images/val2014/COCO_val2014_000000021671.jpg -../coco/images/val2014/COCO_val2014_000000021746.jpg -../coco/images/val2014/COCO_val2014_000000021839.jpg -../coco/images/val2014/COCO_val2014_000000022002.jpg -../coco/images/val2014/COCO_val2014_000000022129.jpg -../coco/images/val2014/COCO_val2014_000000022191.jpg -../coco/images/val2014/COCO_val2014_000000022215.jpg -../coco/images/val2014/COCO_val2014_000000022341.jpg -../coco/images/val2014/COCO_val2014_000000022492.jpg -../coco/images/val2014/COCO_val2014_000000022563.jpg -../coco/images/val2014/COCO_val2014_000000022660.jpg -../coco/images/val2014/COCO_val2014_000000022705.jpg -../coco/images/val2014/COCO_val2014_000000023017.jpg -../coco/images/val2014/COCO_val2014_000000023309.jpg -../coco/images/val2014/COCO_val2014_000000023411.jpg -../coco/images/val2014/COCO_val2014_000000023754.jpg -../coco/images/val2014/COCO_val2014_000000023802.jpg -../coco/images/val2014/COCO_val2014_000000023981.jpg -../coco/images/val2014/COCO_val2014_000000023995.jpg -../coco/images/val2014/COCO_val2014_000000024112.jpg -../coco/images/val2014/COCO_val2014_000000024247.jpg -../coco/images/val2014/COCO_val2014_000000024396.jpg -../coco/images/val2014/COCO_val2014_000000024776.jpg -../coco/images/val2014/COCO_val2014_000000024924.jpg -../coco/images/val2014/COCO_val2014_000000025096.jpg -../coco/images/val2014/COCO_val2014_000000025191.jpg -../coco/images/val2014/COCO_val2014_000000025252.jpg -../coco/images/val2014/COCO_val2014_000000025293.jpg -../coco/images/val2014/COCO_val2014_000000025360.jpg -../coco/images/val2014/COCO_val2014_000000025595.jpg -../coco/images/val2014/COCO_val2014_000000025685.jpg -../coco/images/val2014/COCO_val2014_000000025807.jpg -../coco/images/val2014/COCO_val2014_000000025864.jpg -../coco/images/val2014/COCO_val2014_000000025989.jpg -../coco/images/val2014/COCO_val2014_000000026026.jpg -../coco/images/val2014/COCO_val2014_000000026430.jpg -../coco/images/val2014/COCO_val2014_000000026432.jpg -../coco/images/val2014/COCO_val2014_000000026534.jpg -../coco/images/val2014/COCO_val2014_000000026560.jpg -../coco/images/val2014/COCO_val2014_000000026564.jpg -../coco/images/val2014/COCO_val2014_000000026671.jpg -../coco/images/val2014/COCO_val2014_000000026690.jpg -../coco/images/val2014/COCO_val2014_000000026734.jpg -../coco/images/val2014/COCO_val2014_000000026799.jpg -../coco/images/val2014/COCO_val2014_000000026907.jpg -../coco/images/val2014/COCO_val2014_000000026908.jpg -../coco/images/val2014/COCO_val2014_000000026946.jpg -../coco/images/val2014/COCO_val2014_000000027530.jpg -../coco/images/val2014/COCO_val2014_000000027610.jpg -../coco/images/val2014/COCO_val2014_000000027620.jpg -../coco/images/val2014/COCO_val2014_000000027787.jpg -../coco/images/val2014/COCO_val2014_000000027789.jpg -../coco/images/val2014/COCO_val2014_000000027874.jpg -../coco/images/val2014/COCO_val2014_000000027946.jpg -../coco/images/val2014/COCO_val2014_000000027975.jpg -../coco/images/val2014/COCO_val2014_000000028022.jpg -../coco/images/val2014/COCO_val2014_000000028039.jpg -../coco/images/val2014/COCO_val2014_000000028273.jpg -../coco/images/val2014/COCO_val2014_000000028540.jpg -../coco/images/val2014/COCO_val2014_000000028702.jpg -../coco/images/val2014/COCO_val2014_000000028820.jpg -../coco/images/val2014/COCO_val2014_000000028874.jpg -../coco/images/val2014/COCO_val2014_000000029019.jpg -../coco/images/val2014/COCO_val2014_000000029030.jpg -../coco/images/val2014/COCO_val2014_000000029170.jpg -../coco/images/val2014/COCO_val2014_000000029308.jpg -../coco/images/val2014/COCO_val2014_000000029393.jpg -../coco/images/val2014/COCO_val2014_000000029524.jpg -../coco/images/val2014/COCO_val2014_000000029577.jpg -../coco/images/val2014/COCO_val2014_000000029648.jpg -../coco/images/val2014/COCO_val2014_000000029656.jpg -../coco/images/val2014/COCO_val2014_000000029697.jpg -../coco/images/val2014/COCO_val2014_000000029709.jpg -../coco/images/val2014/COCO_val2014_000000029719.jpg -../coco/images/val2014/COCO_val2014_000000030034.jpg -../coco/images/val2014/COCO_val2014_000000030062.jpg -../coco/images/val2014/COCO_val2014_000000030383.jpg -../coco/images/val2014/COCO_val2014_000000030470.jpg -../coco/images/val2014/COCO_val2014_000000030548.jpg -../coco/images/val2014/COCO_val2014_000000030668.jpg -../coco/images/val2014/COCO_val2014_000000030793.jpg -../coco/images/val2014/COCO_val2014_000000030843.jpg -../coco/images/val2014/COCO_val2014_000000030998.jpg -../coco/images/val2014/COCO_val2014_000000031151.jpg -../coco/images/val2014/COCO_val2014_000000031164.jpg -../coco/images/val2014/COCO_val2014_000000031176.jpg -../coco/images/val2014/COCO_val2014_000000031247.jpg -../coco/images/val2014/COCO_val2014_000000031392.jpg -../coco/images/val2014/COCO_val2014_000000031521.jpg -../coco/images/val2014/COCO_val2014_000000031542.jpg -../coco/images/val2014/COCO_val2014_000000031817.jpg -../coco/images/val2014/COCO_val2014_000000032081.jpg -../coco/images/val2014/COCO_val2014_000000032193.jpg -../coco/images/val2014/COCO_val2014_000000032331.jpg -../coco/images/val2014/COCO_val2014_000000032464.jpg -../coco/images/val2014/COCO_val2014_000000032510.jpg -../coco/images/val2014/COCO_val2014_000000032524.jpg -../coco/images/val2014/COCO_val2014_000000032625.jpg -../coco/images/val2014/COCO_val2014_000000032677.jpg -../coco/images/val2014/COCO_val2014_000000032715.jpg -../coco/images/val2014/COCO_val2014_000000032947.jpg -../coco/images/val2014/COCO_val2014_000000032964.jpg -../coco/images/val2014/COCO_val2014_000000033006.jpg -../coco/images/val2014/COCO_val2014_000000033055.jpg -../coco/images/val2014/COCO_val2014_000000033158.jpg -../coco/images/val2014/COCO_val2014_000000033243.jpg -../coco/images/val2014/COCO_val2014_000000033345.jpg -../coco/images/val2014/COCO_val2014_000000033499.jpg -../coco/images/val2014/COCO_val2014_000000033561.jpg -../coco/images/val2014/COCO_val2014_000000033830.jpg -../coco/images/val2014/COCO_val2014_000000033835.jpg -../coco/images/val2014/COCO_val2014_000000033924.jpg -../coco/images/val2014/COCO_val2014_000000034056.jpg -../coco/images/val2014/COCO_val2014_000000034114.jpg -../coco/images/val2014/COCO_val2014_000000034137.jpg -../coco/images/val2014/COCO_val2014_000000034183.jpg -../coco/images/val2014/COCO_val2014_000000034193.jpg -../coco/images/val2014/COCO_val2014_000000034299.jpg -../coco/images/val2014/COCO_val2014_000000034452.jpg -../coco/images/val2014/COCO_val2014_000000034689.jpg -../coco/images/val2014/COCO_val2014_000000034877.jpg -../coco/images/val2014/COCO_val2014_000000034892.jpg -../coco/images/val2014/COCO_val2014_000000034930.jpg -../coco/images/val2014/COCO_val2014_000000035012.jpg -../coco/images/val2014/COCO_val2014_000000035222.jpg -../coco/images/val2014/COCO_val2014_000000035326.jpg -../coco/images/val2014/COCO_val2014_000000035368.jpg -../coco/images/val2014/COCO_val2014_000000035474.jpg -../coco/images/val2014/COCO_val2014_000000035498.jpg -../coco/images/val2014/COCO_val2014_000000035738.jpg -../coco/images/val2014/COCO_val2014_000000035826.jpg -../coco/images/val2014/COCO_val2014_000000035940.jpg -../coco/images/val2014/COCO_val2014_000000035966.jpg -../coco/images/val2014/COCO_val2014_000000036049.jpg -../coco/images/val2014/COCO_val2014_000000036252.jpg -../coco/images/val2014/COCO_val2014_000000036508.jpg -../coco/images/val2014/COCO_val2014_000000036522.jpg -../coco/images/val2014/COCO_val2014_000000036539.jpg -../coco/images/val2014/COCO_val2014_000000036563.jpg -../coco/images/val2014/COCO_val2014_000000037038.jpg -../coco/images/val2014/COCO_val2014_000000037629.jpg -../coco/images/val2014/COCO_val2014_000000037675.jpg -../coco/images/val2014/COCO_val2014_000000037846.jpg -../coco/images/val2014/COCO_val2014_000000037865.jpg -../coco/images/val2014/COCO_val2014_000000037907.jpg -../coco/images/val2014/COCO_val2014_000000037988.jpg -../coco/images/val2014/COCO_val2014_000000038031.jpg -../coco/images/val2014/COCO_val2014_000000038190.jpg -../coco/images/val2014/COCO_val2014_000000038252.jpg -../coco/images/val2014/COCO_val2014_000000038296.jpg -../coco/images/val2014/COCO_val2014_000000038465.jpg -../coco/images/val2014/COCO_val2014_000000038488.jpg -../coco/images/val2014/COCO_val2014_000000038531.jpg -../coco/images/val2014/COCO_val2014_000000038539.jpg -../coco/images/val2014/COCO_val2014_000000038645.jpg -../coco/images/val2014/COCO_val2014_000000038685.jpg -../coco/images/val2014/COCO_val2014_000000038825.jpg -../coco/images/val2014/COCO_val2014_000000039322.jpg -../coco/images/val2014/COCO_val2014_000000039480.jpg -../coco/images/val2014/COCO_val2014_000000039697.jpg -../coco/images/val2014/COCO_val2014_000000039731.jpg -../coco/images/val2014/COCO_val2014_000000039743.jpg -../coco/images/val2014/COCO_val2014_000000039785.jpg -../coco/images/val2014/COCO_val2014_000000039961.jpg -../coco/images/val2014/COCO_val2014_000000040426.jpg -../coco/images/val2014/COCO_val2014_000000040485.jpg -../coco/images/val2014/COCO_val2014_000000040681.jpg -../coco/images/val2014/COCO_val2014_000000040686.jpg -../coco/images/val2014/COCO_val2014_000000040886.jpg -../coco/images/val2014/COCO_val2014_000000041119.jpg -../coco/images/val2014/COCO_val2014_000000041147.jpg -../coco/images/val2014/COCO_val2014_000000041322.jpg -../coco/images/val2014/COCO_val2014_000000041373.jpg -../coco/images/val2014/COCO_val2014_000000041550.jpg -../coco/images/val2014/COCO_val2014_000000041635.jpg -../coco/images/val2014/COCO_val2014_000000041867.jpg -../coco/images/val2014/COCO_val2014_000000041872.jpg -../coco/images/val2014/COCO_val2014_000000041924.jpg -../coco/images/val2014/COCO_val2014_000000042137.jpg -../coco/images/val2014/COCO_val2014_000000042279.jpg -../coco/images/val2014/COCO_val2014_000000042492.jpg -../coco/images/val2014/COCO_val2014_000000042576.jpg -../coco/images/val2014/COCO_val2014_000000042661.jpg -../coco/images/val2014/COCO_val2014_000000042743.jpg -../coco/images/val2014/COCO_val2014_000000042805.jpg -../coco/images/val2014/COCO_val2014_000000042837.jpg -../coco/images/val2014/COCO_val2014_000000043165.jpg -../coco/images/val2014/COCO_val2014_000000043218.jpg -../coco/images/val2014/COCO_val2014_000000043261.jpg -../coco/images/val2014/COCO_val2014_000000043404.jpg -../coco/images/val2014/COCO_val2014_000000043542.jpg -../coco/images/val2014/COCO_val2014_000000043605.jpg -../coco/images/val2014/COCO_val2014_000000043614.jpg -../coco/images/val2014/COCO_val2014_000000043673.jpg -../coco/images/val2014/COCO_val2014_000000043816.jpg -../coco/images/val2014/COCO_val2014_000000043850.jpg -../coco/images/val2014/COCO_val2014_000000044220.jpg -../coco/images/val2014/COCO_val2014_000000044269.jpg -../coco/images/val2014/COCO_val2014_000000044309.jpg -../coco/images/val2014/COCO_val2014_000000044478.jpg -../coco/images/val2014/COCO_val2014_000000044536.jpg -../coco/images/val2014/COCO_val2014_000000044559.jpg -../coco/images/val2014/COCO_val2014_000000044575.jpg -../coco/images/val2014/COCO_val2014_000000044612.jpg -../coco/images/val2014/COCO_val2014_000000044677.jpg -../coco/images/val2014/COCO_val2014_000000044699.jpg -../coco/images/val2014/COCO_val2014_000000044823.jpg -../coco/images/val2014/COCO_val2014_000000044989.jpg -../coco/images/val2014/COCO_val2014_000000045094.jpg -../coco/images/val2014/COCO_val2014_000000045176.jpg -../coco/images/val2014/COCO_val2014_000000045197.jpg -../coco/images/val2014/COCO_val2014_000000045367.jpg -../coco/images/val2014/COCO_val2014_000000045392.jpg -../coco/images/val2014/COCO_val2014_000000045433.jpg -../coco/images/val2014/COCO_val2014_000000045463.jpg -../coco/images/val2014/COCO_val2014_000000045550.jpg -../coco/images/val2014/COCO_val2014_000000045574.jpg -../coco/images/val2014/COCO_val2014_000000045627.jpg -../coco/images/val2014/COCO_val2014_000000045685.jpg -../coco/images/val2014/COCO_val2014_000000045728.jpg -../coco/images/val2014/COCO_val2014_000000046252.jpg -../coco/images/val2014/COCO_val2014_000000046269.jpg -../coco/images/val2014/COCO_val2014_000000046329.jpg -../coco/images/val2014/COCO_val2014_000000046805.jpg -../coco/images/val2014/COCO_val2014_000000046869.jpg -../coco/images/val2014/COCO_val2014_000000046919.jpg -../coco/images/val2014/COCO_val2014_000000046924.jpg -../coco/images/val2014/COCO_val2014_000000047008.jpg -../coco/images/val2014/COCO_val2014_000000047131.jpg -../coco/images/val2014/COCO_val2014_000000047226.jpg -../coco/images/val2014/COCO_val2014_000000047263.jpg -../coco/images/val2014/COCO_val2014_000000047395.jpg -../coco/images/val2014/COCO_val2014_000000047552.jpg -../coco/images/val2014/COCO_val2014_000000047570.jpg -../coco/images/val2014/COCO_val2014_000000047720.jpg -../coco/images/val2014/COCO_val2014_000000047775.jpg -../coco/images/val2014/COCO_val2014_000000047886.jpg -../coco/images/val2014/COCO_val2014_000000048504.jpg -../coco/images/val2014/COCO_val2014_000000048564.jpg -../coco/images/val2014/COCO_val2014_000000048668.jpg -../coco/images/val2014/COCO_val2014_000000048731.jpg -../coco/images/val2014/COCO_val2014_000000048739.jpg -../coco/images/val2014/COCO_val2014_000000048791.jpg -../coco/images/val2014/COCO_val2014_000000048840.jpg -../coco/images/val2014/COCO_val2014_000000048905.jpg -../coco/images/val2014/COCO_val2014_000000048910.jpg -../coco/images/val2014/COCO_val2014_000000048924.jpg -../coco/images/val2014/COCO_val2014_000000048956.jpg -../coco/images/val2014/COCO_val2014_000000049075.jpg -../coco/images/val2014/COCO_val2014_000000049236.jpg -../coco/images/val2014/COCO_val2014_000000049676.jpg -../coco/images/val2014/COCO_val2014_000000049881.jpg -../coco/images/val2014/COCO_val2014_000000049985.jpg -../coco/images/val2014/COCO_val2014_000000050100.jpg -../coco/images/val2014/COCO_val2014_000000050145.jpg -../coco/images/val2014/COCO_val2014_000000050177.jpg -../coco/images/val2014/COCO_val2014_000000050324.jpg -../coco/images/val2014/COCO_val2014_000000050331.jpg -../coco/images/val2014/COCO_val2014_000000050481.jpg -../coco/images/val2014/COCO_val2014_000000050485.jpg -../coco/images/val2014/COCO_val2014_000000050493.jpg -../coco/images/val2014/COCO_val2014_000000050746.jpg -../coco/images/val2014/COCO_val2014_000000050844.jpg -../coco/images/val2014/COCO_val2014_000000050896.jpg -../coco/images/val2014/COCO_val2014_000000051249.jpg -../coco/images/val2014/COCO_val2014_000000051250.jpg -../coco/images/val2014/COCO_val2014_000000051289.jpg -../coco/images/val2014/COCO_val2014_000000051314.jpg -../coco/images/val2014/COCO_val2014_000000051339.jpg -../coco/images/val2014/COCO_val2014_000000051461.jpg -../coco/images/val2014/COCO_val2014_000000051476.jpg -../coco/images/val2014/COCO_val2014_000000052005.jpg -../coco/images/val2014/COCO_val2014_000000052020.jpg -../coco/images/val2014/COCO_val2014_000000052290.jpg -../coco/images/val2014/COCO_val2014_000000052314.jpg -../coco/images/val2014/COCO_val2014_000000052425.jpg -../coco/images/val2014/COCO_val2014_000000052575.jpg -../coco/images/val2014/COCO_val2014_000000052871.jpg -../coco/images/val2014/COCO_val2014_000000052982.jpg -../coco/images/val2014/COCO_val2014_000000053139.jpg -../coco/images/val2014/COCO_val2014_000000053183.jpg -../coco/images/val2014/COCO_val2014_000000053263.jpg -../coco/images/val2014/COCO_val2014_000000053491.jpg -../coco/images/val2014/COCO_val2014_000000053503.jpg -../coco/images/val2014/COCO_val2014_000000053580.jpg -../coco/images/val2014/COCO_val2014_000000053616.jpg -../coco/images/val2014/COCO_val2014_000000053907.jpg -../coco/images/val2014/COCO_val2014_000000053949.jpg -../coco/images/val2014/COCO_val2014_000000054301.jpg -../coco/images/val2014/COCO_val2014_000000054334.jpg -../coco/images/val2014/COCO_val2014_000000054490.jpg -../coco/images/val2014/COCO_val2014_000000054527.jpg -../coco/images/val2014/COCO_val2014_000000054533.jpg -../coco/images/val2014/COCO_val2014_000000054603.jpg -../coco/images/val2014/COCO_val2014_000000054643.jpg -../coco/images/val2014/COCO_val2014_000000054679.jpg -../coco/images/val2014/COCO_val2014_000000054723.jpg -../coco/images/val2014/COCO_val2014_000000054959.jpg -../coco/images/val2014/COCO_val2014_000000055167.jpg -../coco/images/val2014/COCO_val2014_000000056137.jpg -../coco/images/val2014/COCO_val2014_000000056326.jpg -../coco/images/val2014/COCO_val2014_000000056541.jpg -../coco/images/val2014/COCO_val2014_000000056562.jpg -../coco/images/val2014/COCO_val2014_000000056624.jpg -../coco/images/val2014/COCO_val2014_000000056633.jpg -../coco/images/val2014/COCO_val2014_000000056724.jpg -../coco/images/val2014/COCO_val2014_000000056739.jpg -../coco/images/val2014/COCO_val2014_000000057027.jpg -../coco/images/val2014/COCO_val2014_000000057091.jpg -../coco/images/val2014/COCO_val2014_000000057095.jpg -../coco/images/val2014/COCO_val2014_000000057100.jpg -../coco/images/val2014/COCO_val2014_000000057149.jpg -../coco/images/val2014/COCO_val2014_000000057238.jpg -../coco/images/val2014/COCO_val2014_000000057359.jpg -../coco/images/val2014/COCO_val2014_000000057454.jpg -../coco/images/val2014/COCO_val2014_000000058001.jpg -../coco/images/val2014/COCO_val2014_000000058157.jpg -../coco/images/val2014/COCO_val2014_000000058223.jpg From e6ae688bd3fad74455d5b0e28010ee3258dca001 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 7 Dec 2019 00:55:36 -0800 Subject: [PATCH 0053/1185] updates --- utils/datasets.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/utils/datasets.py b/utils/datasets.py index ef706812ed..c82abea4b6 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -782,6 +782,26 @@ def convert_images2bmp(): # from utils.datasets import *; convert_images2bmp() f.write(lines) +def recursive_dataset2bmp(dataset='../data/sm4_bmp'): # from utils.datasets import *; recursive_dataset2bmp() + # Converts dataset to bmp (for faster training) + formats = [x.lower() for x in img_formats] + [x.upper() for x in img_formats] + for a, b, files in os.walk(dataset): + for file in tqdm(files, desc=a): + p = a + '/' + file + s = Path(file).suffix + if s == '.txt': # replace text + with open(p, 'r') as f: + lines = f.read() + for f in formats: + lines = lines.replace(f, '.bmp') + with open(p, 'w') as f: + f.write(lines) + elif s in formats: # replace image + cv2.imwrite(p.replace(s, '.bmp'), cv2.imread(p)) + if s != '.bmp': + os.system("rm '%s'" % p) + + def imagelist2folder(path='data/coco_64img.txt'): # from utils.datasets import *; imagelist2folder() # Copies all the images in a text file (list of images) into a folder create_folder(path[:-4]) From 55ba979816caa2a728eb117cdfce73a74c801f19 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 7 Dec 2019 01:26:41 -0800 Subject: [PATCH 0054/1185] updates --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 40fcee3341..e22789ee02 100644 --- a/train.py +++ b/train.py @@ -37,8 +37,8 @@ 'hsv_s': 0.678, # image HSV-Saturation augmentation (fraction) 'hsv_v': 0.36, # image HSV-Value augmentation (fraction) 'degrees': 1.98, # image rotation (+/- deg) - 'translate': 0.0779, # image translation (+/- fraction) - 'scale': 0.10, # image scale (+/- gain) + 'translate': 0.05, # image translation (+/- fraction) + 'scale': 0.05, # image scale (+/- gain) 'shear': 0.641} # image shear (+/- deg) # Overwrite hyp with hyp*.txt (optional) From 562ec851027b9771934fd02bb672df0cb549cdea Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 7 Dec 2019 15:02:35 -0800 Subject: [PATCH 0055/1185] updates --- cfg/yolov3s-18a320.cfg | 821 ---------------------------------------- cfg/yolov3s-30a320.cfg | 821 ---------------------------------------- cfg/yolov3s-3a320.cfg | 821 ---------------------------------------- cfg/yolov3s-9a320.cfg | 821 ---------------------------------------- cfg/yolov3s-9a416ms.cfg | 821 ---------------------------------------- cfg/yolov3s-9a512.cfg | 821 ---------------------------------------- cfg/yolov3s-9a512ms.cfg | 821 ---------------------------------------- 7 files changed, 5747 deletions(-) delete mode 100644 cfg/yolov3s-18a320.cfg delete mode 100644 cfg/yolov3s-30a320.cfg delete mode 100644 cfg/yolov3s-3a320.cfg delete mode 100644 cfg/yolov3s-9a320.cfg delete mode 100644 cfg/yolov3s-9a416ms.cfg delete mode 100644 cfg/yolov3s-9a512.cfg delete mode 100644 cfg/yolov3s-9a512ms.cfg diff --git a/cfg/yolov3s-18a320.cfg b/cfg/yolov3s-18a320.cfg deleted file mode 100644 index 1f39f4ef89..0000000000 --- a/cfg/yolov3s-18a320.cfg +++ /dev/null @@ -1,821 +0,0 @@ -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=510 -activation=linear - - -[yolo] -mask = 12,13,14,15,16,17 -anchors = 7,8, 11,20, 27,15, 20,36, 50,29, 28,60, 61,61, 99,39, 43,99, 98,91, 66,148, 180,68, 139,135, 104,210, 285,92, 205,173, 186,274, 302,212 -classes=80 -num=18 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=510 -activation=linear - - -[yolo] -mask = 6,7,8,9,10,11 -anchors = 7,8, 11,20, 27,15, 20,36, 50,29, 28,60, 61,61, 99,39, 43,99, 98,91, 66,148, 180,68, 139,135, 104,210, 285,92, 205,173, 186,274, 302,212 -classes=80 -num=18 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=510 -activation=linear - - -[yolo] -mask = 0,1,2,3,4,5 -anchors = 7,8, 11,20, 27,15, 20,36, 50,29, 28,60, 61,61, 99,39, 43,99, 98,91, 66,148, 180,68, 139,135, 104,210, 285,92, 205,173, 186,274, 302,212 -classes=80 -num=18 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3s-30a320.cfg b/cfg/yolov3s-30a320.cfg deleted file mode 100644 index d5cb7bad22..0000000000 --- a/cfg/yolov3s-30a320.cfg +++ /dev/null @@ -1,821 +0,0 @@ -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=850 -activation=linear - - -[yolo] -mask = 20,21,22,23,24,25,26,27,28,29 -anchors = 6,7, 9,18, 17,10, 21,22, 14,33, 36,15, 22,51, 34,34, 59,24, 32,74, 51,49, 90,38, 41,105, 67,72, 144,48, 54,148, 106,79, 81,109, 211,63, 107,147, 81,200, 149,112, 297,73, 152,187, 214,135, 121,264, 220,206, 299,153, 211,291, 309,230 -classes=80 -num=30 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=850 -activation=linear - - -[yolo] -mask = 10,11,12,13,14,15,16,17,18,19 -anchors = 6,7, 9,18, 17,10, 21,22, 14,33, 36,15, 22,51, 34,34, 59,24, 32,74, 51,49, 90,38, 41,105, 67,72, 144,48, 54,148, 106,79, 81,109, 211,63, 107,147, 81,200, 149,112, 297,73, 152,187, 214,135, 121,264, 220,206, 299,153, 211,291, 309,230 -classes=80 -num=30 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=850 -activation=linear - - -[yolo] -mask = 0,1,2,3,4,5,6,7,8,9 -anchors = 6,7, 9,18, 17,10, 21,22, 14,33, 36,15, 22,51, 34,34, 59,24, 32,74, 51,49, 90,38, 41,105, 67,72, 144,48, 54,148, 106,79, 81,109, 211,63, 107,147, 81,200, 149,112, 297,73, 152,187, 214,135, 121,264, 220,206, 299,153, 211,291, 309,230 -classes=80 -num=30 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3s-3a320.cfg b/cfg/yolov3s-3a320.cfg deleted file mode 100644 index 79897398ae..0000000000 --- a/cfg/yolov3s-3a320.cfg +++ /dev/null @@ -1,821 +0,0 @@ -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=85 -activation=linear - - -[yolo] -mask = 2 -anchors = 16,30, 62,45, 156,198 -classes=80 -num=3 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=85 -activation=linear - - -[yolo] -mask = 1 -anchors = 16,30, 62,45, 156,198 -classes=80 -num=3 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=85 -activation=linear - - -[yolo] -mask = 0 -anchors = 16,30, 62,45, 156,198 -classes=80 -num=3 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3s-9a320.cfg b/cfg/yolov3s-9a320.cfg deleted file mode 100644 index 0200180dd5..0000000000 --- a/cfg/yolov3s-9a320.cfg +++ /dev/null @@ -1,821 +0,0 @@ -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 9,11, 25,27, 33,63, 71,43, 62,120, 135,86, 123,199, 257,100, 264,223 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 9,11, 25,27, 33,63, 71,43, 62,120, 135,86, 123,199, 257,100, 264,223 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 9,11, 25,27, 33,63, 71,43, 62,120, 135,86, 123,199, 257,100, 264,223 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3s-9a416ms.cfg b/cfg/yolov3s-9a416ms.cfg deleted file mode 100644 index 2433e4c4fb..0000000000 --- a/cfg/yolov3s-9a416ms.cfg +++ /dev/null @@ -1,821 +0,0 @@ -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 13,13, 24,41, 62,38, 52,96, 135,80, 105,182, 269,141, 201,320, 445,292 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 13,13, 24,41, 62,38, 52,96, 135,80, 105,182, 269,141, 201,320, 445,292 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 13,13, 24,41, 62,38, 52,96, 135,80, 105,182, 269,141, 201,320, 445,292 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3s-9a512.cfg b/cfg/yolov3s-9a512.cfg deleted file mode 100644 index 25912121b0..0000000000 --- a/cfg/yolov3s-9a512.cfg +++ /dev/null @@ -1,821 +0,0 @@ -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 15,17, 39,44, 55,107, 109,65, 101,203, 203,134, 396,154, 209,324, 434,348 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 15,17, 39,44, 55,107, 109,65, 101,203, 203,134, 396,154, 209,324, 434,348 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 15,17, 39,44, 55,107, 109,65, 101,203, 203,134, 396,154, 209,324, 434,348 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3s-9a512ms.cfg b/cfg/yolov3s-9a512ms.cfg deleted file mode 100644 index ae44c5979a..0000000000 --- a/cfg/yolov3s-9a512ms.cfg +++ /dev/null @@ -1,821 +0,0 @@ -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 15,16, 32,48, 84,50, 63,118, 170,103, 128,225, 334,175, 246,394, 548,359 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 15,16, 32,48, 84,50, 63,118, 170,103, 128,225, 334,175, 246,394, 548,359 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 15,16, 32,48, 84,50, 63,118, 170,103, 128,225, 334,175, 246,394, 548,359 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 From 91b5fb3c9fc2fa9906ec3114b7ff609992d0dc6f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 7 Dec 2019 15:04:29 -0800 Subject: [PATCH 0056/1185] updates --- data/coco_1000img.data | 6 - data/coco_1000img.txt | 1000 ---------------------------------------- data/coco_1000val.data | 6 - data/coco_1000val.txt | 1000 ---------------------------------------- data/coco_1k5k.data | 6 - 5 files changed, 2018 deletions(-) delete mode 100644 data/coco_1000img.data delete mode 100644 data/coco_1000img.txt delete mode 100644 data/coco_1000val.data delete mode 100644 data/coco_1000val.txt delete mode 100644 data/coco_1k5k.data diff --git a/data/coco_1000img.data b/data/coco_1000img.data deleted file mode 100644 index 958c45c4fe..0000000000 --- a/data/coco_1000img.data +++ /dev/null @@ -1,6 +0,0 @@ -classes=80 -train=./data/coco_1000img.txt -valid=./data/coco_1000img.txt -names=data/coco.names -backup=backup/ -eval=coco diff --git a/data/coco_1000img.txt b/data/coco_1000img.txt deleted file mode 100644 index a6d6143eae..0000000000 --- a/data/coco_1000img.txt +++ /dev/null @@ -1,1000 +0,0 @@ -../coco/images/train2014/COCO_train2014_000000000009.jpg -../coco/images/train2014/COCO_train2014_000000000025.jpg -../coco/images/train2014/COCO_train2014_000000000030.jpg -../coco/images/train2014/COCO_train2014_000000000034.jpg -../coco/images/train2014/COCO_train2014_000000000036.jpg -../coco/images/train2014/COCO_train2014_000000000049.jpg -../coco/images/train2014/COCO_train2014_000000000061.jpg -../coco/images/train2014/COCO_train2014_000000000064.jpg -../coco/images/train2014/COCO_train2014_000000000071.jpg -../coco/images/train2014/COCO_train2014_000000000072.jpg -../coco/images/train2014/COCO_train2014_000000000077.jpg -../coco/images/train2014/COCO_train2014_000000000078.jpg -../coco/images/train2014/COCO_train2014_000000000081.jpg -../coco/images/train2014/COCO_train2014_000000000086.jpg -../coco/images/train2014/COCO_train2014_000000000089.jpg -../coco/images/train2014/COCO_train2014_000000000092.jpg -../coco/images/train2014/COCO_train2014_000000000094.jpg -../coco/images/train2014/COCO_train2014_000000000109.jpg -../coco/images/train2014/COCO_train2014_000000000110.jpg -../coco/images/train2014/COCO_train2014_000000000113.jpg -../coco/images/train2014/COCO_train2014_000000000127.jpg -../coco/images/train2014/COCO_train2014_000000000138.jpg -../coco/images/train2014/COCO_train2014_000000000142.jpg -../coco/images/train2014/COCO_train2014_000000000144.jpg -../coco/images/train2014/COCO_train2014_000000000149.jpg -../coco/images/train2014/COCO_train2014_000000000151.jpg -../coco/images/train2014/COCO_train2014_000000000154.jpg -../coco/images/train2014/COCO_train2014_000000000165.jpg -../coco/images/train2014/COCO_train2014_000000000194.jpg -../coco/images/train2014/COCO_train2014_000000000201.jpg -../coco/images/train2014/COCO_train2014_000000000247.jpg -../coco/images/train2014/COCO_train2014_000000000260.jpg -../coco/images/train2014/COCO_train2014_000000000263.jpg -../coco/images/train2014/COCO_train2014_000000000307.jpg -../coco/images/train2014/COCO_train2014_000000000308.jpg -../coco/images/train2014/COCO_train2014_000000000309.jpg -../coco/images/train2014/COCO_train2014_000000000312.jpg -../coco/images/train2014/COCO_train2014_000000000315.jpg -../coco/images/train2014/COCO_train2014_000000000321.jpg -../coco/images/train2014/COCO_train2014_000000000322.jpg -../coco/images/train2014/COCO_train2014_000000000326.jpg -../coco/images/train2014/COCO_train2014_000000000332.jpg -../coco/images/train2014/COCO_train2014_000000000349.jpg -../coco/images/train2014/COCO_train2014_000000000368.jpg -../coco/images/train2014/COCO_train2014_000000000370.jpg -../coco/images/train2014/COCO_train2014_000000000382.jpg -../coco/images/train2014/COCO_train2014_000000000384.jpg -../coco/images/train2014/COCO_train2014_000000000389.jpg -../coco/images/train2014/COCO_train2014_000000000394.jpg -../coco/images/train2014/COCO_train2014_000000000404.jpg -../coco/images/train2014/COCO_train2014_000000000419.jpg -../coco/images/train2014/COCO_train2014_000000000431.jpg -../coco/images/train2014/COCO_train2014_000000000436.jpg -../coco/images/train2014/COCO_train2014_000000000438.jpg -../coco/images/train2014/COCO_train2014_000000000443.jpg -../coco/images/train2014/COCO_train2014_000000000446.jpg -../coco/images/train2014/COCO_train2014_000000000450.jpg -../coco/images/train2014/COCO_train2014_000000000471.jpg -../coco/images/train2014/COCO_train2014_000000000490.jpg -../coco/images/train2014/COCO_train2014_000000000491.jpg -../coco/images/train2014/COCO_train2014_000000000510.jpg -../coco/images/train2014/COCO_train2014_000000000514.jpg -../coco/images/train2014/COCO_train2014_000000000529.jpg -../coco/images/train2014/COCO_train2014_000000000531.jpg -../coco/images/train2014/COCO_train2014_000000000532.jpg -../coco/images/train2014/COCO_train2014_000000000540.jpg -../coco/images/train2014/COCO_train2014_000000000542.jpg -../coco/images/train2014/COCO_train2014_000000000560.jpg -../coco/images/train2014/COCO_train2014_000000000562.jpg -../coco/images/train2014/COCO_train2014_000000000572.jpg -../coco/images/train2014/COCO_train2014_000000000575.jpg -../coco/images/train2014/COCO_train2014_000000000581.jpg -../coco/images/train2014/COCO_train2014_000000000584.jpg -../coco/images/train2014/COCO_train2014_000000000595.jpg -../coco/images/train2014/COCO_train2014_000000000597.jpg -../coco/images/train2014/COCO_train2014_000000000605.jpg -../coco/images/train2014/COCO_train2014_000000000612.jpg -../coco/images/train2014/COCO_train2014_000000000620.jpg -../coco/images/train2014/COCO_train2014_000000000625.jpg -../coco/images/train2014/COCO_train2014_000000000629.jpg -../coco/images/train2014/COCO_train2014_000000000634.jpg -../coco/images/train2014/COCO_train2014_000000000643.jpg -../coco/images/train2014/COCO_train2014_000000000650.jpg -../coco/images/train2014/COCO_train2014_000000000656.jpg -../coco/images/train2014/COCO_train2014_000000000659.jpg -../coco/images/train2014/COCO_train2014_000000000670.jpg -../coco/images/train2014/COCO_train2014_000000000671.jpg -../coco/images/train2014/COCO_train2014_000000000673.jpg -../coco/images/train2014/COCO_train2014_000000000681.jpg -../coco/images/train2014/COCO_train2014_000000000684.jpg -../coco/images/train2014/COCO_train2014_000000000690.jpg -../coco/images/train2014/COCO_train2014_000000000706.jpg -../coco/images/train2014/COCO_train2014_000000000714.jpg -../coco/images/train2014/COCO_train2014_000000000716.jpg -../coco/images/train2014/COCO_train2014_000000000722.jpg -../coco/images/train2014/COCO_train2014_000000000723.jpg -../coco/images/train2014/COCO_train2014_000000000731.jpg -../coco/images/train2014/COCO_train2014_000000000735.jpg -../coco/images/train2014/COCO_train2014_000000000753.jpg -../coco/images/train2014/COCO_train2014_000000000754.jpg -../coco/images/train2014/COCO_train2014_000000000762.jpg -../coco/images/train2014/COCO_train2014_000000000781.jpg -../coco/images/train2014/COCO_train2014_000000000790.jpg -../coco/images/train2014/COCO_train2014_000000000795.jpg -../coco/images/train2014/COCO_train2014_000000000797.jpg -../coco/images/train2014/COCO_train2014_000000000801.jpg -../coco/images/train2014/COCO_train2014_000000000813.jpg -../coco/images/train2014/COCO_train2014_000000000821.jpg -../coco/images/train2014/COCO_train2014_000000000825.jpg -../coco/images/train2014/COCO_train2014_000000000828.jpg -../coco/images/train2014/COCO_train2014_000000000839.jpg -../coco/images/train2014/COCO_train2014_000000000853.jpg -../coco/images/train2014/COCO_train2014_000000000882.jpg -../coco/images/train2014/COCO_train2014_000000000897.jpg -../coco/images/train2014/COCO_train2014_000000000901.jpg -../coco/images/train2014/COCO_train2014_000000000902.jpg -../coco/images/train2014/COCO_train2014_000000000908.jpg -../coco/images/train2014/COCO_train2014_000000000909.jpg -../coco/images/train2014/COCO_train2014_000000000913.jpg -../coco/images/train2014/COCO_train2014_000000000925.jpg -../coco/images/train2014/COCO_train2014_000000000927.jpg -../coco/images/train2014/COCO_train2014_000000000934.jpg -../coco/images/train2014/COCO_train2014_000000000941.jpg -../coco/images/train2014/COCO_train2014_000000000943.jpg -../coco/images/train2014/COCO_train2014_000000000955.jpg -../coco/images/train2014/COCO_train2014_000000000960.jpg -../coco/images/train2014/COCO_train2014_000000000965.jpg -../coco/images/train2014/COCO_train2014_000000000977.jpg -../coco/images/train2014/COCO_train2014_000000000982.jpg -../coco/images/train2014/COCO_train2014_000000000984.jpg -../coco/images/train2014/COCO_train2014_000000000996.jpg -../coco/images/train2014/COCO_train2014_000000001006.jpg -../coco/images/train2014/COCO_train2014_000000001011.jpg -../coco/images/train2014/COCO_train2014_000000001014.jpg -../coco/images/train2014/COCO_train2014_000000001025.jpg -../coco/images/train2014/COCO_train2014_000000001036.jpg -../coco/images/train2014/COCO_train2014_000000001053.jpg -../coco/images/train2014/COCO_train2014_000000001059.jpg -../coco/images/train2014/COCO_train2014_000000001072.jpg -../coco/images/train2014/COCO_train2014_000000001084.jpg -../coco/images/train2014/COCO_train2014_000000001085.jpg -../coco/images/train2014/COCO_train2014_000000001090.jpg -../coco/images/train2014/COCO_train2014_000000001098.jpg -../coco/images/train2014/COCO_train2014_000000001099.jpg -../coco/images/train2014/COCO_train2014_000000001102.jpg -../coco/images/train2014/COCO_train2014_000000001107.jpg -../coco/images/train2014/COCO_train2014_000000001108.jpg -../coco/images/train2014/COCO_train2014_000000001122.jpg -../coco/images/train2014/COCO_train2014_000000001139.jpg -../coco/images/train2014/COCO_train2014_000000001144.jpg -../coco/images/train2014/COCO_train2014_000000001145.jpg -../coco/images/train2014/COCO_train2014_000000001155.jpg -../coco/images/train2014/COCO_train2014_000000001166.jpg -../coco/images/train2014/COCO_train2014_000000001168.jpg -../coco/images/train2014/COCO_train2014_000000001183.jpg -../coco/images/train2014/COCO_train2014_000000001200.jpg -../coco/images/train2014/COCO_train2014_000000001204.jpg -../coco/images/train2014/COCO_train2014_000000001213.jpg -../coco/images/train2014/COCO_train2014_000000001216.jpg -../coco/images/train2014/COCO_train2014_000000001224.jpg -../coco/images/train2014/COCO_train2014_000000001232.jpg -../coco/images/train2014/COCO_train2014_000000001237.jpg -../coco/images/train2014/COCO_train2014_000000001238.jpg -../coco/images/train2014/COCO_train2014_000000001261.jpg -../coco/images/train2014/COCO_train2014_000000001264.jpg -../coco/images/train2014/COCO_train2014_000000001271.jpg -../coco/images/train2014/COCO_train2014_000000001282.jpg -../coco/images/train2014/COCO_train2014_000000001295.jpg -../coco/images/train2014/COCO_train2014_000000001298.jpg -../coco/images/train2014/COCO_train2014_000000001306.jpg -../coco/images/train2014/COCO_train2014_000000001307.jpg -../coco/images/train2014/COCO_train2014_000000001308.jpg -../coco/images/train2014/COCO_train2014_000000001311.jpg -../coco/images/train2014/COCO_train2014_000000001315.jpg -../coco/images/train2014/COCO_train2014_000000001319.jpg -../coco/images/train2014/COCO_train2014_000000001323.jpg -../coco/images/train2014/COCO_train2014_000000001330.jpg -../coco/images/train2014/COCO_train2014_000000001332.jpg -../coco/images/train2014/COCO_train2014_000000001350.jpg -../coco/images/train2014/COCO_train2014_000000001355.jpg -../coco/images/train2014/COCO_train2014_000000001359.jpg -../coco/images/train2014/COCO_train2014_000000001360.jpg -../coco/images/train2014/COCO_train2014_000000001366.jpg -../coco/images/train2014/COCO_train2014_000000001375.jpg -../coco/images/train2014/COCO_train2014_000000001381.jpg -../coco/images/train2014/COCO_train2014_000000001386.jpg -../coco/images/train2014/COCO_train2014_000000001390.jpg -../coco/images/train2014/COCO_train2014_000000001392.jpg -../coco/images/train2014/COCO_train2014_000000001397.jpg -../coco/images/train2014/COCO_train2014_000000001401.jpg -../coco/images/train2014/COCO_train2014_000000001403.jpg -../coco/images/train2014/COCO_train2014_000000001407.jpg -../coco/images/train2014/COCO_train2014_000000001408.jpg -../coco/images/train2014/COCO_train2014_000000001424.jpg -../coco/images/train2014/COCO_train2014_000000001431.jpg -../coco/images/train2014/COCO_train2014_000000001451.jpg -../coco/images/train2014/COCO_train2014_000000001453.jpg -../coco/images/train2014/COCO_train2014_000000001455.jpg -../coco/images/train2014/COCO_train2014_000000001488.jpg -../coco/images/train2014/COCO_train2014_000000001496.jpg -../coco/images/train2014/COCO_train2014_000000001497.jpg -../coco/images/train2014/COCO_train2014_000000001501.jpg -../coco/images/train2014/COCO_train2014_000000001505.jpg -../coco/images/train2014/COCO_train2014_000000001507.jpg -../coco/images/train2014/COCO_train2014_000000001510.jpg -../coco/images/train2014/COCO_train2014_000000001515.jpg -../coco/images/train2014/COCO_train2014_000000001518.jpg -../coco/images/train2014/COCO_train2014_000000001522.jpg -../coco/images/train2014/COCO_train2014_000000001523.jpg -../coco/images/train2014/COCO_train2014_000000001526.jpg -../coco/images/train2014/COCO_train2014_000000001527.jpg -../coco/images/train2014/COCO_train2014_000000001536.jpg -../coco/images/train2014/COCO_train2014_000000001548.jpg -../coco/images/train2014/COCO_train2014_000000001558.jpg -../coco/images/train2014/COCO_train2014_000000001562.jpg -../coco/images/train2014/COCO_train2014_000000001569.jpg -../coco/images/train2014/COCO_train2014_000000001579.jpg -../coco/images/train2014/COCO_train2014_000000001580.jpg -../coco/images/train2014/COCO_train2014_000000001586.jpg -../coco/images/train2014/COCO_train2014_000000001589.jpg -../coco/images/train2014/COCO_train2014_000000001596.jpg -../coco/images/train2014/COCO_train2014_000000001611.jpg -../coco/images/train2014/COCO_train2014_000000001622.jpg -../coco/images/train2014/COCO_train2014_000000001625.jpg -../coco/images/train2014/COCO_train2014_000000001637.jpg -../coco/images/train2014/COCO_train2014_000000001639.jpg -../coco/images/train2014/COCO_train2014_000000001645.jpg -../coco/images/train2014/COCO_train2014_000000001670.jpg -../coco/images/train2014/COCO_train2014_000000001674.jpg -../coco/images/train2014/COCO_train2014_000000001681.jpg -../coco/images/train2014/COCO_train2014_000000001688.jpg -../coco/images/train2014/COCO_train2014_000000001697.jpg -../coco/images/train2014/COCO_train2014_000000001706.jpg -../coco/images/train2014/COCO_train2014_000000001709.jpg -../coco/images/train2014/COCO_train2014_000000001712.jpg -../coco/images/train2014/COCO_train2014_000000001720.jpg -../coco/images/train2014/COCO_train2014_000000001732.jpg -../coco/images/train2014/COCO_train2014_000000001737.jpg -../coco/images/train2014/COCO_train2014_000000001756.jpg -../coco/images/train2014/COCO_train2014_000000001762.jpg -../coco/images/train2014/COCO_train2014_000000001764.jpg -../coco/images/train2014/COCO_train2014_000000001771.jpg -../coco/images/train2014/COCO_train2014_000000001774.jpg -../coco/images/train2014/COCO_train2014_000000001777.jpg -../coco/images/train2014/COCO_train2014_000000001781.jpg -../coco/images/train2014/COCO_train2014_000000001785.jpg -../coco/images/train2014/COCO_train2014_000000001786.jpg -../coco/images/train2014/COCO_train2014_000000001790.jpg -../coco/images/train2014/COCO_train2014_000000001792.jpg -../coco/images/train2014/COCO_train2014_000000001804.jpg -../coco/images/train2014/COCO_train2014_000000001810.jpg -../coco/images/train2014/COCO_train2014_000000001811.jpg -../coco/images/train2014/COCO_train2014_000000001813.jpg -../coco/images/train2014/COCO_train2014_000000001815.jpg -../coco/images/train2014/COCO_train2014_000000001822.jpg -../coco/images/train2014/COCO_train2014_000000001837.jpg -../coco/images/train2014/COCO_train2014_000000001864.jpg -../coco/images/train2014/COCO_train2014_000000001875.jpg -../coco/images/train2014/COCO_train2014_000000001877.jpg -../coco/images/train2014/COCO_train2014_000000001888.jpg -../coco/images/train2014/COCO_train2014_000000001895.jpg -../coco/images/train2014/COCO_train2014_000000001900.jpg -../coco/images/train2014/COCO_train2014_000000001902.jpg -../coco/images/train2014/COCO_train2014_000000001906.jpg -../coco/images/train2014/COCO_train2014_000000001907.jpg -../coco/images/train2014/COCO_train2014_000000001911.jpg -../coco/images/train2014/COCO_train2014_000000001912.jpg -../coco/images/train2014/COCO_train2014_000000001915.jpg -../coco/images/train2014/COCO_train2014_000000001924.jpg -../coco/images/train2014/COCO_train2014_000000001926.jpg -../coco/images/train2014/COCO_train2014_000000001941.jpg -../coco/images/train2014/COCO_train2014_000000001942.jpg -../coco/images/train2014/COCO_train2014_000000001943.jpg -../coco/images/train2014/COCO_train2014_000000001947.jpg -../coco/images/train2014/COCO_train2014_000000001958.jpg -../coco/images/train2014/COCO_train2014_000000001966.jpg -../coco/images/train2014/COCO_train2014_000000001994.jpg -../coco/images/train2014/COCO_train2014_000000001999.jpg -../coco/images/train2014/COCO_train2014_000000002001.jpg -../coco/images/train2014/COCO_train2014_000000002007.jpg -../coco/images/train2014/COCO_train2014_000000002024.jpg -../coco/images/train2014/COCO_train2014_000000002055.jpg -../coco/images/train2014/COCO_train2014_000000002056.jpg -../coco/images/train2014/COCO_train2014_000000002066.jpg -../coco/images/train2014/COCO_train2014_000000002068.jpg -../coco/images/train2014/COCO_train2014_000000002072.jpg -../coco/images/train2014/COCO_train2014_000000002083.jpg -../coco/images/train2014/COCO_train2014_000000002089.jpg -../coco/images/train2014/COCO_train2014_000000002093.jpg -../coco/images/train2014/COCO_train2014_000000002106.jpg -../coco/images/train2014/COCO_train2014_000000002114.jpg -../coco/images/train2014/COCO_train2014_000000002135.jpg -../coco/images/train2014/COCO_train2014_000000002148.jpg -../coco/images/train2014/COCO_train2014_000000002150.jpg -../coco/images/train2014/COCO_train2014_000000002178.jpg -../coco/images/train2014/COCO_train2014_000000002184.jpg -../coco/images/train2014/COCO_train2014_000000002193.jpg -../coco/images/train2014/COCO_train2014_000000002197.jpg -../coco/images/train2014/COCO_train2014_000000002209.jpg -../coco/images/train2014/COCO_train2014_000000002211.jpg -../coco/images/train2014/COCO_train2014_000000002217.jpg -../coco/images/train2014/COCO_train2014_000000002229.jpg -../coco/images/train2014/COCO_train2014_000000002232.jpg -../coco/images/train2014/COCO_train2014_000000002244.jpg -../coco/images/train2014/COCO_train2014_000000002258.jpg -../coco/images/train2014/COCO_train2014_000000002270.jpg -../coco/images/train2014/COCO_train2014_000000002276.jpg -../coco/images/train2014/COCO_train2014_000000002278.jpg -../coco/images/train2014/COCO_train2014_000000002279.jpg -../coco/images/train2014/COCO_train2014_000000002280.jpg -../coco/images/train2014/COCO_train2014_000000002281.jpg -../coco/images/train2014/COCO_train2014_000000002283.jpg -../coco/images/train2014/COCO_train2014_000000002284.jpg -../coco/images/train2014/COCO_train2014_000000002296.jpg -../coco/images/train2014/COCO_train2014_000000002309.jpg -../coco/images/train2014/COCO_train2014_000000002337.jpg -../coco/images/train2014/COCO_train2014_000000002342.jpg -../coco/images/train2014/COCO_train2014_000000002347.jpg -../coco/images/train2014/COCO_train2014_000000002349.jpg -../coco/images/train2014/COCO_train2014_000000002369.jpg -../coco/images/train2014/COCO_train2014_000000002372.jpg -../coco/images/train2014/COCO_train2014_000000002374.jpg -../coco/images/train2014/COCO_train2014_000000002377.jpg -../coco/images/train2014/COCO_train2014_000000002389.jpg -../coco/images/train2014/COCO_train2014_000000002400.jpg -../coco/images/train2014/COCO_train2014_000000002402.jpg -../coco/images/train2014/COCO_train2014_000000002411.jpg -../coco/images/train2014/COCO_train2014_000000002415.jpg -../coco/images/train2014/COCO_train2014_000000002429.jpg -../coco/images/train2014/COCO_train2014_000000002444.jpg -../coco/images/train2014/COCO_train2014_000000002445.jpg -../coco/images/train2014/COCO_train2014_000000002446.jpg -../coco/images/train2014/COCO_train2014_000000002448.jpg -../coco/images/train2014/COCO_train2014_000000002451.jpg -../coco/images/train2014/COCO_train2014_000000002459.jpg -../coco/images/train2014/COCO_train2014_000000002466.jpg -../coco/images/train2014/COCO_train2014_000000002470.jpg -../coco/images/train2014/COCO_train2014_000000002471.jpg -../coco/images/train2014/COCO_train2014_000000002496.jpg -../coco/images/train2014/COCO_train2014_000000002498.jpg -../coco/images/train2014/COCO_train2014_000000002531.jpg -../coco/images/train2014/COCO_train2014_000000002536.jpg -../coco/images/train2014/COCO_train2014_000000002543.jpg -../coco/images/train2014/COCO_train2014_000000002544.jpg -../coco/images/train2014/COCO_train2014_000000002545.jpg -../coco/images/train2014/COCO_train2014_000000002555.jpg -../coco/images/train2014/COCO_train2014_000000002559.jpg -../coco/images/train2014/COCO_train2014_000000002560.jpg -../coco/images/train2014/COCO_train2014_000000002563.jpg -../coco/images/train2014/COCO_train2014_000000002567.jpg -../coco/images/train2014/COCO_train2014_000000002570.jpg -../coco/images/train2014/COCO_train2014_000000002575.jpg -../coco/images/train2014/COCO_train2014_000000002583.jpg -../coco/images/train2014/COCO_train2014_000000002585.jpg -../coco/images/train2014/COCO_train2014_000000002591.jpg -../coco/images/train2014/COCO_train2014_000000002602.jpg -../coco/images/train2014/COCO_train2014_000000002606.jpg -../coco/images/train2014/COCO_train2014_000000002608.jpg -../coco/images/train2014/COCO_train2014_000000002614.jpg -../coco/images/train2014/COCO_train2014_000000002618.jpg -../coco/images/train2014/COCO_train2014_000000002619.jpg -../coco/images/train2014/COCO_train2014_000000002623.jpg -../coco/images/train2014/COCO_train2014_000000002624.jpg -../coco/images/train2014/COCO_train2014_000000002639.jpg -../coco/images/train2014/COCO_train2014_000000002644.jpg -../coco/images/train2014/COCO_train2014_000000002645.jpg -../coco/images/train2014/COCO_train2014_000000002658.jpg -../coco/images/train2014/COCO_train2014_000000002664.jpg -../coco/images/train2014/COCO_train2014_000000002672.jpg -../coco/images/train2014/COCO_train2014_000000002686.jpg -../coco/images/train2014/COCO_train2014_000000002687.jpg -../coco/images/train2014/COCO_train2014_000000002691.jpg -../coco/images/train2014/COCO_train2014_000000002693.jpg -../coco/images/train2014/COCO_train2014_000000002697.jpg -../coco/images/train2014/COCO_train2014_000000002703.jpg -../coco/images/train2014/COCO_train2014_000000002732.jpg -../coco/images/train2014/COCO_train2014_000000002742.jpg -../coco/images/train2014/COCO_train2014_000000002752.jpg -../coco/images/train2014/COCO_train2014_000000002754.jpg -../coco/images/train2014/COCO_train2014_000000002755.jpg -../coco/images/train2014/COCO_train2014_000000002758.jpg -../coco/images/train2014/COCO_train2014_000000002770.jpg -../coco/images/train2014/COCO_train2014_000000002774.jpg -../coco/images/train2014/COCO_train2014_000000002776.jpg -../coco/images/train2014/COCO_train2014_000000002782.jpg -../coco/images/train2014/COCO_train2014_000000002823.jpg -../coco/images/train2014/COCO_train2014_000000002833.jpg -../coco/images/train2014/COCO_train2014_000000002842.jpg -../coco/images/train2014/COCO_train2014_000000002843.jpg -../coco/images/train2014/COCO_train2014_000000002849.jpg -../coco/images/train2014/COCO_train2014_000000002860.jpg -../coco/images/train2014/COCO_train2014_000000002886.jpg -../coco/images/train2014/COCO_train2014_000000002892.jpg -../coco/images/train2014/COCO_train2014_000000002896.jpg -../coco/images/train2014/COCO_train2014_000000002902.jpg -../coco/images/train2014/COCO_train2014_000000002907.jpg -../coco/images/train2014/COCO_train2014_000000002931.jpg -../coco/images/train2014/COCO_train2014_000000002951.jpg -../coco/images/train2014/COCO_train2014_000000002963.jpg -../coco/images/train2014/COCO_train2014_000000002964.jpg -../coco/images/train2014/COCO_train2014_000000002982.jpg -../coco/images/train2014/COCO_train2014_000000002983.jpg -../coco/images/train2014/COCO_train2014_000000002989.jpg -../coco/images/train2014/COCO_train2014_000000002992.jpg -../coco/images/train2014/COCO_train2014_000000002998.jpg -../coco/images/train2014/COCO_train2014_000000003000.jpg -../coco/images/train2014/COCO_train2014_000000003003.jpg -../coco/images/train2014/COCO_train2014_000000003008.jpg -../coco/images/train2014/COCO_train2014_000000003040.jpg -../coco/images/train2014/COCO_train2014_000000003048.jpg -../coco/images/train2014/COCO_train2014_000000003076.jpg -../coco/images/train2014/COCO_train2014_000000003077.jpg -../coco/images/train2014/COCO_train2014_000000003080.jpg -../coco/images/train2014/COCO_train2014_000000003118.jpg -../coco/images/train2014/COCO_train2014_000000003124.jpg -../coco/images/train2014/COCO_train2014_000000003131.jpg -../coco/images/train2014/COCO_train2014_000000003148.jpg -../coco/images/train2014/COCO_train2014_000000003157.jpg -../coco/images/train2014/COCO_train2014_000000003160.jpg -../coco/images/train2014/COCO_train2014_000000003178.jpg -../coco/images/train2014/COCO_train2014_000000003197.jpg -../coco/images/train2014/COCO_train2014_000000003219.jpg -../coco/images/train2014/COCO_train2014_000000003220.jpg -../coco/images/train2014/COCO_train2014_000000003224.jpg -../coco/images/train2014/COCO_train2014_000000003225.jpg -../coco/images/train2014/COCO_train2014_000000003234.jpg -../coco/images/train2014/COCO_train2014_000000003236.jpg -../coco/images/train2014/COCO_train2014_000000003242.jpg -../coco/images/train2014/COCO_train2014_000000003249.jpg -../coco/images/train2014/COCO_train2014_000000003259.jpg -../coco/images/train2014/COCO_train2014_000000003264.jpg -../coco/images/train2014/COCO_train2014_000000003270.jpg -../coco/images/train2014/COCO_train2014_000000003272.jpg -../coco/images/train2014/COCO_train2014_000000003276.jpg -../coco/images/train2014/COCO_train2014_000000003286.jpg -../coco/images/train2014/COCO_train2014_000000003293.jpg -../coco/images/train2014/COCO_train2014_000000003305.jpg -../coco/images/train2014/COCO_train2014_000000003314.jpg -../coco/images/train2014/COCO_train2014_000000003320.jpg -../coco/images/train2014/COCO_train2014_000000003321.jpg -../coco/images/train2014/COCO_train2014_000000003325.jpg -../coco/images/train2014/COCO_train2014_000000003348.jpg -../coco/images/train2014/COCO_train2014_000000003353.jpg -../coco/images/train2014/COCO_train2014_000000003361.jpg -../coco/images/train2014/COCO_train2014_000000003365.jpg -../coco/images/train2014/COCO_train2014_000000003366.jpg -../coco/images/train2014/COCO_train2014_000000003375.jpg -../coco/images/train2014/COCO_train2014_000000003386.jpg -../coco/images/train2014/COCO_train2014_000000003389.jpg -../coco/images/train2014/COCO_train2014_000000003398.jpg -../coco/images/train2014/COCO_train2014_000000003412.jpg -../coco/images/train2014/COCO_train2014_000000003432.jpg -../coco/images/train2014/COCO_train2014_000000003442.jpg -../coco/images/train2014/COCO_train2014_000000003457.jpg -../coco/images/train2014/COCO_train2014_000000003461.jpg -../coco/images/train2014/COCO_train2014_000000003464.jpg -../coco/images/train2014/COCO_train2014_000000003474.jpg -../coco/images/train2014/COCO_train2014_000000003478.jpg -../coco/images/train2014/COCO_train2014_000000003481.jpg -../coco/images/train2014/COCO_train2014_000000003483.jpg -../coco/images/train2014/COCO_train2014_000000003493.jpg -../coco/images/train2014/COCO_train2014_000000003511.jpg -../coco/images/train2014/COCO_train2014_000000003514.jpg -../coco/images/train2014/COCO_train2014_000000003517.jpg -../coco/images/train2014/COCO_train2014_000000003518.jpg -../coco/images/train2014/COCO_train2014_000000003521.jpg -../coco/images/train2014/COCO_train2014_000000003528.jpg -../coco/images/train2014/COCO_train2014_000000003532.jpg -../coco/images/train2014/COCO_train2014_000000003535.jpg -../coco/images/train2014/COCO_train2014_000000003538.jpg -../coco/images/train2014/COCO_train2014_000000003579.jpg -../coco/images/train2014/COCO_train2014_000000003602.jpg -../coco/images/train2014/COCO_train2014_000000003613.jpg -../coco/images/train2014/COCO_train2014_000000003623.jpg -../coco/images/train2014/COCO_train2014_000000003628.jpg -../coco/images/train2014/COCO_train2014_000000003637.jpg -../coco/images/train2014/COCO_train2014_000000003668.jpg -../coco/images/train2014/COCO_train2014_000000003671.jpg -../coco/images/train2014/COCO_train2014_000000003682.jpg -../coco/images/train2014/COCO_train2014_000000003685.jpg -../coco/images/train2014/COCO_train2014_000000003713.jpg -../coco/images/train2014/COCO_train2014_000000003729.jpg -../coco/images/train2014/COCO_train2014_000000003735.jpg -../coco/images/train2014/COCO_train2014_000000003737.jpg -../coco/images/train2014/COCO_train2014_000000003745.jpg -../coco/images/train2014/COCO_train2014_000000003751.jpg -../coco/images/train2014/COCO_train2014_000000003764.jpg -../coco/images/train2014/COCO_train2014_000000003770.jpg -../coco/images/train2014/COCO_train2014_000000003782.jpg -../coco/images/train2014/COCO_train2014_000000003789.jpg -../coco/images/train2014/COCO_train2014_000000003804.jpg -../coco/images/train2014/COCO_train2014_000000003812.jpg -../coco/images/train2014/COCO_train2014_000000003823.jpg -../coco/images/train2014/COCO_train2014_000000003827.jpg -../coco/images/train2014/COCO_train2014_000000003830.jpg -../coco/images/train2014/COCO_train2014_000000003860.jpg -../coco/images/train2014/COCO_train2014_000000003862.jpg -../coco/images/train2014/COCO_train2014_000000003866.jpg -../coco/images/train2014/COCO_train2014_000000003870.jpg -../coco/images/train2014/COCO_train2014_000000003877.jpg -../coco/images/train2014/COCO_train2014_000000003897.jpg -../coco/images/train2014/COCO_train2014_000000003899.jpg -../coco/images/train2014/COCO_train2014_000000003911.jpg -../coco/images/train2014/COCO_train2014_000000003915.jpg -../coco/images/train2014/COCO_train2014_000000003917.jpg -../coco/images/train2014/COCO_train2014_000000003920.jpg -../coco/images/train2014/COCO_train2014_000000003935.jpg -../coco/images/train2014/COCO_train2014_000000003967.jpg -../coco/images/train2014/COCO_train2014_000000003982.jpg -../coco/images/train2014/COCO_train2014_000000003988.jpg -../coco/images/train2014/COCO_train2014_000000003992.jpg -../coco/images/train2014/COCO_train2014_000000003995.jpg -../coco/images/train2014/COCO_train2014_000000003999.jpg -../coco/images/train2014/COCO_train2014_000000004020.jpg -../coco/images/train2014/COCO_train2014_000000004032.jpg -../coco/images/train2014/COCO_train2014_000000004038.jpg -../coco/images/train2014/COCO_train2014_000000004042.jpg -../coco/images/train2014/COCO_train2014_000000004051.jpg -../coco/images/train2014/COCO_train2014_000000004057.jpg -../coco/images/train2014/COCO_train2014_000000004065.jpg -../coco/images/train2014/COCO_train2014_000000004068.jpg -../coco/images/train2014/COCO_train2014_000000004080.jpg -../coco/images/train2014/COCO_train2014_000000004129.jpg -../coco/images/train2014/COCO_train2014_000000004130.jpg -../coco/images/train2014/COCO_train2014_000000004131.jpg -../coco/images/train2014/COCO_train2014_000000004132.jpg -../coco/images/train2014/COCO_train2014_000000004138.jpg -../coco/images/train2014/COCO_train2014_000000004139.jpg -../coco/images/train2014/COCO_train2014_000000004140.jpg -../coco/images/train2014/COCO_train2014_000000004159.jpg -../coco/images/train2014/COCO_train2014_000000004172.jpg -../coco/images/train2014/COCO_train2014_000000004173.jpg -../coco/images/train2014/COCO_train2014_000000004180.jpg -../coco/images/train2014/COCO_train2014_000000004189.jpg -../coco/images/train2014/COCO_train2014_000000004201.jpg -../coco/images/train2014/COCO_train2014_000000004208.jpg -../coco/images/train2014/COCO_train2014_000000004219.jpg -../coco/images/train2014/COCO_train2014_000000004239.jpg -../coco/images/train2014/COCO_train2014_000000004244.jpg -../coco/images/train2014/COCO_train2014_000000004245.jpg -../coco/images/train2014/COCO_train2014_000000004259.jpg -../coco/images/train2014/COCO_train2014_000000004260.jpg -../coco/images/train2014/COCO_train2014_000000004278.jpg -../coco/images/train2014/COCO_train2014_000000004282.jpg -../coco/images/train2014/COCO_train2014_000000004289.jpg -../coco/images/train2014/COCO_train2014_000000004309.jpg -../coco/images/train2014/COCO_train2014_000000004318.jpg -../coco/images/train2014/COCO_train2014_000000004319.jpg -../coco/images/train2014/COCO_train2014_000000004322.jpg -../coco/images/train2014/COCO_train2014_000000004331.jpg -../coco/images/train2014/COCO_train2014_000000004360.jpg -../coco/images/train2014/COCO_train2014_000000004376.jpg -../coco/images/train2014/COCO_train2014_000000004377.jpg -../coco/images/train2014/COCO_train2014_000000004385.jpg -../coco/images/train2014/COCO_train2014_000000004394.jpg -../coco/images/train2014/COCO_train2014_000000004404.jpg -../coco/images/train2014/COCO_train2014_000000004410.jpg -../coco/images/train2014/COCO_train2014_000000004415.jpg -../coco/images/train2014/COCO_train2014_000000004421.jpg -../coco/images/train2014/COCO_train2014_000000004424.jpg -../coco/images/train2014/COCO_train2014_000000004426.jpg -../coco/images/train2014/COCO_train2014_000000004428.jpg -../coco/images/train2014/COCO_train2014_000000004441.jpg -../coco/images/train2014/COCO_train2014_000000004442.jpg -../coco/images/train2014/COCO_train2014_000000004444.jpg -../coco/images/train2014/COCO_train2014_000000004462.jpg -../coco/images/train2014/COCO_train2014_000000004463.jpg -../coco/images/train2014/COCO_train2014_000000004471.jpg -../coco/images/train2014/COCO_train2014_000000004477.jpg -../coco/images/train2014/COCO_train2014_000000004478.jpg -../coco/images/train2014/COCO_train2014_000000004488.jpg -../coco/images/train2014/COCO_train2014_000000004489.jpg -../coco/images/train2014/COCO_train2014_000000004490.jpg -../coco/images/train2014/COCO_train2014_000000004502.jpg -../coco/images/train2014/COCO_train2014_000000004508.jpg -../coco/images/train2014/COCO_train2014_000000004527.jpg -../coco/images/train2014/COCO_train2014_000000004535.jpg -../coco/images/train2014/COCO_train2014_000000004537.jpg -../coco/images/train2014/COCO_train2014_000000004546.jpg -../coco/images/train2014/COCO_train2014_000000004549.jpg -../coco/images/train2014/COCO_train2014_000000004555.jpg -../coco/images/train2014/COCO_train2014_000000004567.jpg -../coco/images/train2014/COCO_train2014_000000004571.jpg -../coco/images/train2014/COCO_train2014_000000004574.jpg -../coco/images/train2014/COCO_train2014_000000004575.jpg -../coco/images/train2014/COCO_train2014_000000004578.jpg -../coco/images/train2014/COCO_train2014_000000004579.jpg -../coco/images/train2014/COCO_train2014_000000004587.jpg -../coco/images/train2014/COCO_train2014_000000004595.jpg -../coco/images/train2014/COCO_train2014_000000004608.jpg -../coco/images/train2014/COCO_train2014_000000004616.jpg -../coco/images/train2014/COCO_train2014_000000004622.jpg -../coco/images/train2014/COCO_train2014_000000004624.jpg -../coco/images/train2014/COCO_train2014_000000004642.jpg -../coco/images/train2014/COCO_train2014_000000004647.jpg -../coco/images/train2014/COCO_train2014_000000004662.jpg -../coco/images/train2014/COCO_train2014_000000004673.jpg -../coco/images/train2014/COCO_train2014_000000004684.jpg -../coco/images/train2014/COCO_train2014_000000004694.jpg -../coco/images/train2014/COCO_train2014_000000004702.jpg -../coco/images/train2014/COCO_train2014_000000004704.jpg -../coco/images/train2014/COCO_train2014_000000004705.jpg -../coco/images/train2014/COCO_train2014_000000004706.jpg -../coco/images/train2014/COCO_train2014_000000004711.jpg -../coco/images/train2014/COCO_train2014_000000004714.jpg -../coco/images/train2014/COCO_train2014_000000004716.jpg -../coco/images/train2014/COCO_train2014_000000004719.jpg -../coco/images/train2014/COCO_train2014_000000004739.jpg -../coco/images/train2014/COCO_train2014_000000004741.jpg -../coco/images/train2014/COCO_train2014_000000004761.jpg -../coco/images/train2014/COCO_train2014_000000004762.jpg -../coco/images/train2014/COCO_train2014_000000004785.jpg -../coco/images/train2014/COCO_train2014_000000004794.jpg -../coco/images/train2014/COCO_train2014_000000004796.jpg -../coco/images/train2014/COCO_train2014_000000004809.jpg -../coco/images/train2014/COCO_train2014_000000004820.jpg -../coco/images/train2014/COCO_train2014_000000004823.jpg -../coco/images/train2014/COCO_train2014_000000004827.jpg -../coco/images/train2014/COCO_train2014_000000004830.jpg -../coco/images/train2014/COCO_train2014_000000004834.jpg -../coco/images/train2014/COCO_train2014_000000004843.jpg -../coco/images/train2014/COCO_train2014_000000004844.jpg -../coco/images/train2014/COCO_train2014_000000004859.jpg -../coco/images/train2014/COCO_train2014_000000004876.jpg -../coco/images/train2014/COCO_train2014_000000004880.jpg -../coco/images/train2014/COCO_train2014_000000004885.jpg -../coco/images/train2014/COCO_train2014_000000004888.jpg -../coco/images/train2014/COCO_train2014_000000004891.jpg -../coco/images/train2014/COCO_train2014_000000004893.jpg -../coco/images/train2014/COCO_train2014_000000004901.jpg -../coco/images/train2014/COCO_train2014_000000004903.jpg -../coco/images/train2014/COCO_train2014_000000004904.jpg -../coco/images/train2014/COCO_train2014_000000004920.jpg -../coco/images/train2014/COCO_train2014_000000004931.jpg -../coco/images/train2014/COCO_train2014_000000004947.jpg -../coco/images/train2014/COCO_train2014_000000004956.jpg -../coco/images/train2014/COCO_train2014_000000004963.jpg -../coco/images/train2014/COCO_train2014_000000004968.jpg -../coco/images/train2014/COCO_train2014_000000004970.jpg -../coco/images/train2014/COCO_train2014_000000004971.jpg -../coco/images/train2014/COCO_train2014_000000004978.jpg -../coco/images/train2014/COCO_train2014_000000004981.jpg -../coco/images/train2014/COCO_train2014_000000004984.jpg -../coco/images/train2014/COCO_train2014_000000004993.jpg -../coco/images/train2014/COCO_train2014_000000005005.jpg -../coco/images/train2014/COCO_train2014_000000005010.jpg -../coco/images/train2014/COCO_train2014_000000005011.jpg -../coco/images/train2014/COCO_train2014_000000005016.jpg -../coco/images/train2014/COCO_train2014_000000005018.jpg -../coco/images/train2014/COCO_train2014_000000005021.jpg -../coco/images/train2014/COCO_train2014_000000005028.jpg -../coco/images/train2014/COCO_train2014_000000005046.jpg -../coco/images/train2014/COCO_train2014_000000005073.jpg -../coco/images/train2014/COCO_train2014_000000005083.jpg -../coco/images/train2014/COCO_train2014_000000005085.jpg -../coco/images/train2014/COCO_train2014_000000005086.jpg -../coco/images/train2014/COCO_train2014_000000005088.jpg -../coco/images/train2014/COCO_train2014_000000005094.jpg -../coco/images/train2014/COCO_train2014_000000005095.jpg -../coco/images/train2014/COCO_train2014_000000005099.jpg -../coco/images/train2014/COCO_train2014_000000005111.jpg -../coco/images/train2014/COCO_train2014_000000005113.jpg -../coco/images/train2014/COCO_train2014_000000005115.jpg -../coco/images/train2014/COCO_train2014_000000005131.jpg -../coco/images/train2014/COCO_train2014_000000005139.jpg -../coco/images/train2014/COCO_train2014_000000005140.jpg -../coco/images/train2014/COCO_train2014_000000005142.jpg -../coco/images/train2014/COCO_train2014_000000005151.jpg -../coco/images/train2014/COCO_train2014_000000005152.jpg -../coco/images/train2014/COCO_train2014_000000005156.jpg -../coco/images/train2014/COCO_train2014_000000005165.jpg -../coco/images/train2014/COCO_train2014_000000005169.jpg -../coco/images/train2014/COCO_train2014_000000005172.jpg -../coco/images/train2014/COCO_train2014_000000005174.jpg -../coco/images/train2014/COCO_train2014_000000005180.jpg -../coco/images/train2014/COCO_train2014_000000005198.jpg -../coco/images/train2014/COCO_train2014_000000005210.jpg -../coco/images/train2014/COCO_train2014_000000005215.jpg -../coco/images/train2014/COCO_train2014_000000005219.jpg -../coco/images/train2014/COCO_train2014_000000005237.jpg -../coco/images/train2014/COCO_train2014_000000005244.jpg -../coco/images/train2014/COCO_train2014_000000005253.jpg -../coco/images/train2014/COCO_train2014_000000005256.jpg -../coco/images/train2014/COCO_train2014_000000005259.jpg -../coco/images/train2014/COCO_train2014_000000005260.jpg -../coco/images/train2014/COCO_train2014_000000005263.jpg -../coco/images/train2014/COCO_train2014_000000005277.jpg -../coco/images/train2014/COCO_train2014_000000005288.jpg -../coco/images/train2014/COCO_train2014_000000005294.jpg -../coco/images/train2014/COCO_train2014_000000005303.jpg -../coco/images/train2014/COCO_train2014_000000005312.jpg -../coco/images/train2014/COCO_train2014_000000005313.jpg -../coco/images/train2014/COCO_train2014_000000005324.jpg -../coco/images/train2014/COCO_train2014_000000005326.jpg -../coco/images/train2014/COCO_train2014_000000005335.jpg -../coco/images/train2014/COCO_train2014_000000005336.jpg -../coco/images/train2014/COCO_train2014_000000005339.jpg -../coco/images/train2014/COCO_train2014_000000005340.jpg -../coco/images/train2014/COCO_train2014_000000005344.jpg -../coco/images/train2014/COCO_train2014_000000005345.jpg -../coco/images/train2014/COCO_train2014_000000005355.jpg -../coco/images/train2014/COCO_train2014_000000005359.jpg -../coco/images/train2014/COCO_train2014_000000005360.jpg -../coco/images/train2014/COCO_train2014_000000005362.jpg -../coco/images/train2014/COCO_train2014_000000005368.jpg -../coco/images/train2014/COCO_train2014_000000005373.jpg -../coco/images/train2014/COCO_train2014_000000005376.jpg -../coco/images/train2014/COCO_train2014_000000005377.jpg -../coco/images/train2014/COCO_train2014_000000005383.jpg -../coco/images/train2014/COCO_train2014_000000005396.jpg -../coco/images/train2014/COCO_train2014_000000005424.jpg -../coco/images/train2014/COCO_train2014_000000005425.jpg -../coco/images/train2014/COCO_train2014_000000005430.jpg -../coco/images/train2014/COCO_train2014_000000005434.jpg -../coco/images/train2014/COCO_train2014_000000005435.jpg -../coco/images/train2014/COCO_train2014_000000005453.jpg -../coco/images/train2014/COCO_train2014_000000005459.jpg -../coco/images/train2014/COCO_train2014_000000005469.jpg -../coco/images/train2014/COCO_train2014_000000005471.jpg -../coco/images/train2014/COCO_train2014_000000005472.jpg -../coco/images/train2014/COCO_train2014_000000005482.jpg -../coco/images/train2014/COCO_train2014_000000005483.jpg -../coco/images/train2014/COCO_train2014_000000005505.jpg -../coco/images/train2014/COCO_train2014_000000005508.jpg -../coco/images/train2014/COCO_train2014_000000005522.jpg -../coco/images/train2014/COCO_train2014_000000005554.jpg -../coco/images/train2014/COCO_train2014_000000005557.jpg -../coco/images/train2014/COCO_train2014_000000005559.jpg -../coco/images/train2014/COCO_train2014_000000005564.jpg -../coco/images/train2014/COCO_train2014_000000005574.jpg -../coco/images/train2014/COCO_train2014_000000005587.jpg -../coco/images/train2014/COCO_train2014_000000005589.jpg -../coco/images/train2014/COCO_train2014_000000005608.jpg -../coco/images/train2014/COCO_train2014_000000005612.jpg -../coco/images/train2014/COCO_train2014_000000005614.jpg -../coco/images/train2014/COCO_train2014_000000005615.jpg -../coco/images/train2014/COCO_train2014_000000005619.jpg -../coco/images/train2014/COCO_train2014_000000005620.jpg -../coco/images/train2014/COCO_train2014_000000005632.jpg -../coco/images/train2014/COCO_train2014_000000005638.jpg -../coco/images/train2014/COCO_train2014_000000005641.jpg -../coco/images/train2014/COCO_train2014_000000005643.jpg -../coco/images/train2014/COCO_train2014_000000005649.jpg -../coco/images/train2014/COCO_train2014_000000005667.jpg -../coco/images/train2014/COCO_train2014_000000005669.jpg -../coco/images/train2014/COCO_train2014_000000005678.jpg -../coco/images/train2014/COCO_train2014_000000005683.jpg -../coco/images/train2014/COCO_train2014_000000005684.jpg -../coco/images/train2014/COCO_train2014_000000005688.jpg -../coco/images/train2014/COCO_train2014_000000005689.jpg -../coco/images/train2014/COCO_train2014_000000005692.jpg -../coco/images/train2014/COCO_train2014_000000005699.jpg -../coco/images/train2014/COCO_train2014_000000005700.jpg -../coco/images/train2014/COCO_train2014_000000005701.jpg -../coco/images/train2014/COCO_train2014_000000005703.jpg -../coco/images/train2014/COCO_train2014_000000005715.jpg -../coco/images/train2014/COCO_train2014_000000005736.jpg -../coco/images/train2014/COCO_train2014_000000005740.jpg -../coco/images/train2014/COCO_train2014_000000005745.jpg -../coco/images/train2014/COCO_train2014_000000005755.jpg -../coco/images/train2014/COCO_train2014_000000005756.jpg -../coco/images/train2014/COCO_train2014_000000005757.jpg -../coco/images/train2014/COCO_train2014_000000005769.jpg -../coco/images/train2014/COCO_train2014_000000005782.jpg -../coco/images/train2014/COCO_train2014_000000005785.jpg -../coco/images/train2014/COCO_train2014_000000005809.jpg -../coco/images/train2014/COCO_train2014_000000005811.jpg -../coco/images/train2014/COCO_train2014_000000005823.jpg -../coco/images/train2014/COCO_train2014_000000005828.jpg -../coco/images/train2014/COCO_train2014_000000005830.jpg -../coco/images/train2014/COCO_train2014_000000005832.jpg -../coco/images/train2014/COCO_train2014_000000005862.jpg -../coco/images/train2014/COCO_train2014_000000005882.jpg -../coco/images/train2014/COCO_train2014_000000005883.jpg -../coco/images/train2014/COCO_train2014_000000005903.jpg -../coco/images/train2014/COCO_train2014_000000005906.jpg -../coco/images/train2014/COCO_train2014_000000005907.jpg -../coco/images/train2014/COCO_train2014_000000005913.jpg -../coco/images/train2014/COCO_train2014_000000005915.jpg -../coco/images/train2014/COCO_train2014_000000005916.jpg -../coco/images/train2014/COCO_train2014_000000005917.jpg -../coco/images/train2014/COCO_train2014_000000005933.jpg -../coco/images/train2014/COCO_train2014_000000005946.jpg -../coco/images/train2014/COCO_train2014_000000005947.jpg -../coco/images/train2014/COCO_train2014_000000005962.jpg -../coco/images/train2014/COCO_train2014_000000005967.jpg -../coco/images/train2014/COCO_train2014_000000005991.jpg -../coco/images/train2014/COCO_train2014_000000005994.jpg -../coco/images/train2014/COCO_train2014_000000006004.jpg -../coco/images/train2014/COCO_train2014_000000006010.jpg -../coco/images/train2014/COCO_train2014_000000006016.jpg -../coco/images/train2014/COCO_train2014_000000006026.jpg -../coco/images/train2014/COCO_train2014_000000006031.jpg -../coco/images/train2014/COCO_train2014_000000006041.jpg -../coco/images/train2014/COCO_train2014_000000006042.jpg -../coco/images/train2014/COCO_train2014_000000006051.jpg -../coco/images/train2014/COCO_train2014_000000006053.jpg -../coco/images/train2014/COCO_train2014_000000006057.jpg -../coco/images/train2014/COCO_train2014_000000006066.jpg -../coco/images/train2014/COCO_train2014_000000006068.jpg -../coco/images/train2014/COCO_train2014_000000006075.jpg -../coco/images/train2014/COCO_train2014_000000006101.jpg -../coco/images/train2014/COCO_train2014_000000006107.jpg -../coco/images/train2014/COCO_train2014_000000006120.jpg -../coco/images/train2014/COCO_train2014_000000006140.jpg -../coco/images/train2014/COCO_train2014_000000006146.jpg -../coco/images/train2014/COCO_train2014_000000006148.jpg -../coco/images/train2014/COCO_train2014_000000006151.jpg -../coco/images/train2014/COCO_train2014_000000006155.jpg -../coco/images/train2014/COCO_train2014_000000006160.jpg -../coco/images/train2014/COCO_train2014_000000006178.jpg -../coco/images/train2014/COCO_train2014_000000006182.jpg -../coco/images/train2014/COCO_train2014_000000006190.jpg -../coco/images/train2014/COCO_train2014_000000006197.jpg -../coco/images/train2014/COCO_train2014_000000006200.jpg -../coco/images/train2014/COCO_train2014_000000006216.jpg -../coco/images/train2014/COCO_train2014_000000006225.jpg -../coco/images/train2014/COCO_train2014_000000006229.jpg -../coco/images/train2014/COCO_train2014_000000006230.jpg -../coco/images/train2014/COCO_train2014_000000006233.jpg -../coco/images/train2014/COCO_train2014_000000006241.jpg -../coco/images/train2014/COCO_train2014_000000006247.jpg -../coco/images/train2014/COCO_train2014_000000006253.jpg -../coco/images/train2014/COCO_train2014_000000006262.jpg -../coco/images/train2014/COCO_train2014_000000006263.jpg -../coco/images/train2014/COCO_train2014_000000006268.jpg -../coco/images/train2014/COCO_train2014_000000006270.jpg -../coco/images/train2014/COCO_train2014_000000006287.jpg -../coco/images/train2014/COCO_train2014_000000006293.jpg -../coco/images/train2014/COCO_train2014_000000006295.jpg -../coco/images/train2014/COCO_train2014_000000006318.jpg -../coco/images/train2014/COCO_train2014_000000006327.jpg -../coco/images/train2014/COCO_train2014_000000006332.jpg -../coco/images/train2014/COCO_train2014_000000006334.jpg -../coco/images/train2014/COCO_train2014_000000006336.jpg -../coco/images/train2014/COCO_train2014_000000006338.jpg -../coco/images/train2014/COCO_train2014_000000006339.jpg -../coco/images/train2014/COCO_train2014_000000006352.jpg -../coco/images/train2014/COCO_train2014_000000006355.jpg -../coco/images/train2014/COCO_train2014_000000006357.jpg -../coco/images/train2014/COCO_train2014_000000006358.jpg -../coco/images/train2014/COCO_train2014_000000006363.jpg -../coco/images/train2014/COCO_train2014_000000006364.jpg -../coco/images/train2014/COCO_train2014_000000006379.jpg -../coco/images/train2014/COCO_train2014_000000006380.jpg -../coco/images/train2014/COCO_train2014_000000006406.jpg -../coco/images/train2014/COCO_train2014_000000006407.jpg -../coco/images/train2014/COCO_train2014_000000006409.jpg -../coco/images/train2014/COCO_train2014_000000006414.jpg -../coco/images/train2014/COCO_train2014_000000006421.jpg -../coco/images/train2014/COCO_train2014_000000006422.jpg -../coco/images/train2014/COCO_train2014_000000006424.jpg -../coco/images/train2014/COCO_train2014_000000006428.jpg -../coco/images/train2014/COCO_train2014_000000006432.jpg -../coco/images/train2014/COCO_train2014_000000006447.jpg -../coco/images/train2014/COCO_train2014_000000006451.jpg -../coco/images/train2014/COCO_train2014_000000006464.jpg -../coco/images/train2014/COCO_train2014_000000006465.jpg -../coco/images/train2014/COCO_train2014_000000006481.jpg -../coco/images/train2014/COCO_train2014_000000006488.jpg -../coco/images/train2014/COCO_train2014_000000006489.jpg -../coco/images/train2014/COCO_train2014_000000006491.jpg -../coco/images/train2014/COCO_train2014_000000006512.jpg -../coco/images/train2014/COCO_train2014_000000006517.jpg -../coco/images/train2014/COCO_train2014_000000006518.jpg -../coco/images/train2014/COCO_train2014_000000006520.jpg -../coco/images/train2014/COCO_train2014_000000006522.jpg -../coco/images/train2014/COCO_train2014_000000006531.jpg -../coco/images/train2014/COCO_train2014_000000006539.jpg -../coco/images/train2014/COCO_train2014_000000006541.jpg -../coco/images/train2014/COCO_train2014_000000006560.jpg -../coco/images/train2014/COCO_train2014_000000006562.jpg -../coco/images/train2014/COCO_train2014_000000006572.jpg -../coco/images/train2014/COCO_train2014_000000006578.jpg -../coco/images/train2014/COCO_train2014_000000006586.jpg -../coco/images/train2014/COCO_train2014_000000006590.jpg -../coco/images/train2014/COCO_train2014_000000006595.jpg -../coco/images/train2014/COCO_train2014_000000006599.jpg -../coco/images/train2014/COCO_train2014_000000006602.jpg -../coco/images/train2014/COCO_train2014_000000006603.jpg -../coco/images/train2014/COCO_train2014_000000006627.jpg -../coco/images/train2014/COCO_train2014_000000006631.jpg -../coco/images/train2014/COCO_train2014_000000006632.jpg -../coco/images/train2014/COCO_train2014_000000006640.jpg -../coco/images/train2014/COCO_train2014_000000006647.jpg -../coco/images/train2014/COCO_train2014_000000006651.jpg -../coco/images/train2014/COCO_train2014_000000006664.jpg -../coco/images/train2014/COCO_train2014_000000006675.jpg -../coco/images/train2014/COCO_train2014_000000006692.jpg -../coco/images/train2014/COCO_train2014_000000006709.jpg -../coco/images/train2014/COCO_train2014_000000006710.jpg -../coco/images/train2014/COCO_train2014_000000006715.jpg -../coco/images/train2014/COCO_train2014_000000006721.jpg -../coco/images/train2014/COCO_train2014_000000006725.jpg -../coco/images/train2014/COCO_train2014_000000006730.jpg -../coco/images/train2014/COCO_train2014_000000006733.jpg -../coco/images/train2014/COCO_train2014_000000006744.jpg -../coco/images/train2014/COCO_train2014_000000006747.jpg -../coco/images/train2014/COCO_train2014_000000006749.jpg -../coco/images/train2014/COCO_train2014_000000006753.jpg -../coco/images/train2014/COCO_train2014_000000006760.jpg -../coco/images/train2014/COCO_train2014_000000006764.jpg -../coco/images/train2014/COCO_train2014_000000006765.jpg -../coco/images/train2014/COCO_train2014_000000006773.jpg -../coco/images/train2014/COCO_train2014_000000006777.jpg -../coco/images/train2014/COCO_train2014_000000006780.jpg -../coco/images/train2014/COCO_train2014_000000006790.jpg -../coco/images/train2014/COCO_train2014_000000006792.jpg -../coco/images/train2014/COCO_train2014_000000006800.jpg -../coco/images/train2014/COCO_train2014_000000006809.jpg -../coco/images/train2014/COCO_train2014_000000006811.jpg -../coco/images/train2014/COCO_train2014_000000006819.jpg -../coco/images/train2014/COCO_train2014_000000006824.jpg -../coco/images/train2014/COCO_train2014_000000006842.jpg -../coco/images/train2014/COCO_train2014_000000006846.jpg -../coco/images/train2014/COCO_train2014_000000006860.jpg -../coco/images/train2014/COCO_train2014_000000006862.jpg -../coco/images/train2014/COCO_train2014_000000006873.jpg -../coco/images/train2014/COCO_train2014_000000006901.jpg -../coco/images/train2014/COCO_train2014_000000006914.jpg -../coco/images/train2014/COCO_train2014_000000006920.jpg -../coco/images/train2014/COCO_train2014_000000006935.jpg -../coco/images/train2014/COCO_train2014_000000006936.jpg -../coco/images/train2014/COCO_train2014_000000006941.jpg -../coco/images/train2014/COCO_train2014_000000006943.jpg -../coco/images/train2014/COCO_train2014_000000006945.jpg -../coco/images/train2014/COCO_train2014_000000006957.jpg -../coco/images/train2014/COCO_train2014_000000006964.jpg -../coco/images/train2014/COCO_train2014_000000006973.jpg -../coco/images/train2014/COCO_train2014_000000006981.jpg -../coco/images/train2014/COCO_train2014_000000006990.jpg -../coco/images/train2014/COCO_train2014_000000006996.jpg -../coco/images/train2014/COCO_train2014_000000006998.jpg -../coco/images/train2014/COCO_train2014_000000007022.jpg -../coco/images/train2014/COCO_train2014_000000007028.jpg -../coco/images/train2014/COCO_train2014_000000007035.jpg -../coco/images/train2014/COCO_train2014_000000007040.jpg -../coco/images/train2014/COCO_train2014_000000007048.jpg -../coco/images/train2014/COCO_train2014_000000007049.jpg -../coco/images/train2014/COCO_train2014_000000007069.jpg -../coco/images/train2014/COCO_train2014_000000007090.jpg -../coco/images/train2014/COCO_train2014_000000007095.jpg -../coco/images/train2014/COCO_train2014_000000007103.jpg -../coco/images/train2014/COCO_train2014_000000007104.jpg -../coco/images/train2014/COCO_train2014_000000007116.jpg -../coco/images/train2014/COCO_train2014_000000007123.jpg -../coco/images/train2014/COCO_train2014_000000007124.jpg -../coco/images/train2014/COCO_train2014_000000007129.jpg -../coco/images/train2014/COCO_train2014_000000007139.jpg -../coco/images/train2014/COCO_train2014_000000007143.jpg -../coco/images/train2014/COCO_train2014_000000007145.jpg -../coco/images/train2014/COCO_train2014_000000007150.jpg -../coco/images/train2014/COCO_train2014_000000007159.jpg -../coco/images/train2014/COCO_train2014_000000007167.jpg -../coco/images/train2014/COCO_train2014_000000007174.jpg -../coco/images/train2014/COCO_train2014_000000007179.jpg -../coco/images/train2014/COCO_train2014_000000007201.jpg -../coco/images/train2014/COCO_train2014_000000007205.jpg -../coco/images/train2014/COCO_train2014_000000007220.jpg -../coco/images/train2014/COCO_train2014_000000007221.jpg -../coco/images/train2014/COCO_train2014_000000007224.jpg -../coco/images/train2014/COCO_train2014_000000007228.jpg -../coco/images/train2014/COCO_train2014_000000007232.jpg -../coco/images/train2014/COCO_train2014_000000007239.jpg -../coco/images/train2014/COCO_train2014_000000007247.jpg -../coco/images/train2014/COCO_train2014_000000007251.jpg -../coco/images/train2014/COCO_train2014_000000007275.jpg -../coco/images/train2014/COCO_train2014_000000007277.jpg -../coco/images/train2014/COCO_train2014_000000007307.jpg -../coco/images/train2014/COCO_train2014_000000007318.jpg -../coco/images/train2014/COCO_train2014_000000007319.jpg -../coco/images/train2014/COCO_train2014_000000007357.jpg -../coco/images/train2014/COCO_train2014_000000007361.jpg -../coco/images/train2014/COCO_train2014_000000007367.jpg -../coco/images/train2014/COCO_train2014_000000007393.jpg -../coco/images/train2014/COCO_train2014_000000007396.jpg -../coco/images/train2014/COCO_train2014_000000007420.jpg -../coco/images/train2014/COCO_train2014_000000007424.jpg -../coco/images/train2014/COCO_train2014_000000007452.jpg -../coco/images/train2014/COCO_train2014_000000007455.jpg -../coco/images/train2014/COCO_train2014_000000007476.jpg -../coco/images/train2014/COCO_train2014_000000007489.jpg -../coco/images/train2014/COCO_train2014_000000007498.jpg -../coco/images/train2014/COCO_train2014_000000007500.jpg -../coco/images/train2014/COCO_train2014_000000007503.jpg -../coco/images/train2014/COCO_train2014_000000007504.jpg -../coco/images/train2014/COCO_train2014_000000007510.jpg -../coco/images/train2014/COCO_train2014_000000007517.jpg -../coco/images/train2014/COCO_train2014_000000007524.jpg -../coco/images/train2014/COCO_train2014_000000007535.jpg -../coco/images/train2014/COCO_train2014_000000007539.jpg -../coco/images/train2014/COCO_train2014_000000007544.jpg -../coco/images/train2014/COCO_train2014_000000007558.jpg -../coco/images/train2014/COCO_train2014_000000007567.jpg -../coco/images/train2014/COCO_train2014_000000007583.jpg -../coco/images/train2014/COCO_train2014_000000007584.jpg -../coco/images/train2014/COCO_train2014_000000007594.jpg -../coco/images/train2014/COCO_train2014_000000007596.jpg -../coco/images/train2014/COCO_train2014_000000007601.jpg -../coco/images/train2014/COCO_train2014_000000007603.jpg diff --git a/data/coco_1000val.data b/data/coco_1000val.data deleted file mode 100644 index 726906b298..0000000000 --- a/data/coco_1000val.data +++ /dev/null @@ -1,6 +0,0 @@ -classes=80 -train=./data/coco_1000img.txt -valid=./data/coco_1000val.txt -names=data/coco.names -backup=backup/ -eval=coco diff --git a/data/coco_1000val.txt b/data/coco_1000val.txt deleted file mode 100644 index dd97b56856..0000000000 --- a/data/coco_1000val.txt +++ /dev/null @@ -1,1000 +0,0 @@ -../coco/images/val2014/COCO_val2014_000000000164.jpg -../coco/images/val2014/COCO_val2014_000000000192.jpg -../coco/images/val2014/COCO_val2014_000000000283.jpg -../coco/images/val2014/COCO_val2014_000000000397.jpg -../coco/images/val2014/COCO_val2014_000000000589.jpg -../coco/images/val2014/COCO_val2014_000000000599.jpg -../coco/images/val2014/COCO_val2014_000000000711.jpg -../coco/images/val2014/COCO_val2014_000000000757.jpg -../coco/images/val2014/COCO_val2014_000000000764.jpg -../coco/images/val2014/COCO_val2014_000000000872.jpg -../coco/images/val2014/COCO_val2014_000000001063.jpg -../coco/images/val2014/COCO_val2014_000000001554.jpg -../coco/images/val2014/COCO_val2014_000000001667.jpg -../coco/images/val2014/COCO_val2014_000000001700.jpg -../coco/images/val2014/COCO_val2014_000000001869.jpg -../coco/images/val2014/COCO_val2014_000000002124.jpg -../coco/images/val2014/COCO_val2014_000000002261.jpg -../coco/images/val2014/COCO_val2014_000000002621.jpg -../coco/images/val2014/COCO_val2014_000000002684.jpg -../coco/images/val2014/COCO_val2014_000000002764.jpg -../coco/images/val2014/COCO_val2014_000000002894.jpg -../coco/images/val2014/COCO_val2014_000000002972.jpg -../coco/images/val2014/COCO_val2014_000000003035.jpg -../coco/images/val2014/COCO_val2014_000000003084.jpg -../coco/images/val2014/COCO_val2014_000000003103.jpg -../coco/images/val2014/COCO_val2014_000000003109.jpg -../coco/images/val2014/COCO_val2014_000000003134.jpg -../coco/images/val2014/COCO_val2014_000000003209.jpg -../coco/images/val2014/COCO_val2014_000000003244.jpg -../coco/images/val2014/COCO_val2014_000000003326.jpg -../coco/images/val2014/COCO_val2014_000000003337.jpg -../coco/images/val2014/COCO_val2014_000000003661.jpg -../coco/images/val2014/COCO_val2014_000000003711.jpg -../coco/images/val2014/COCO_val2014_000000003779.jpg -../coco/images/val2014/COCO_val2014_000000003865.jpg -../coco/images/val2014/COCO_val2014_000000004079.jpg -../coco/images/val2014/COCO_val2014_000000004092.jpg -../coco/images/val2014/COCO_val2014_000000004283.jpg -../coco/images/val2014/COCO_val2014_000000004296.jpg -../coco/images/val2014/COCO_val2014_000000004392.jpg -../coco/images/val2014/COCO_val2014_000000004742.jpg -../coco/images/val2014/COCO_val2014_000000004754.jpg -../coco/images/val2014/COCO_val2014_000000004764.jpg -../coco/images/val2014/COCO_val2014_000000005038.jpg -../coco/images/val2014/COCO_val2014_000000005060.jpg -../coco/images/val2014/COCO_val2014_000000005124.jpg -../coco/images/val2014/COCO_val2014_000000005178.jpg -../coco/images/val2014/COCO_val2014_000000005205.jpg -../coco/images/val2014/COCO_val2014_000000005443.jpg -../coco/images/val2014/COCO_val2014_000000005652.jpg -../coco/images/val2014/COCO_val2014_000000005723.jpg -../coco/images/val2014/COCO_val2014_000000005804.jpg -../coco/images/val2014/COCO_val2014_000000006074.jpg -../coco/images/val2014/COCO_val2014_000000006091.jpg -../coco/images/val2014/COCO_val2014_000000006153.jpg -../coco/images/val2014/COCO_val2014_000000006213.jpg -../coco/images/val2014/COCO_val2014_000000006497.jpg -../coco/images/val2014/COCO_val2014_000000006789.jpg -../coco/images/val2014/COCO_val2014_000000006847.jpg -../coco/images/val2014/COCO_val2014_000000007241.jpg -../coco/images/val2014/COCO_val2014_000000007256.jpg -../coco/images/val2014/COCO_val2014_000000007281.jpg -../coco/images/val2014/COCO_val2014_000000007795.jpg -../coco/images/val2014/COCO_val2014_000000007867.jpg -../coco/images/val2014/COCO_val2014_000000007873.jpg -../coco/images/val2014/COCO_val2014_000000007899.jpg -../coco/images/val2014/COCO_val2014_000000008010.jpg -../coco/images/val2014/COCO_val2014_000000008179.jpg -../coco/images/val2014/COCO_val2014_000000008190.jpg -../coco/images/val2014/COCO_val2014_000000008204.jpg -../coco/images/val2014/COCO_val2014_000000008350.jpg -../coco/images/val2014/COCO_val2014_000000008493.jpg -../coco/images/val2014/COCO_val2014_000000008853.jpg -../coco/images/val2014/COCO_val2014_000000009105.jpg -../coco/images/val2014/COCO_val2014_000000009156.jpg -../coco/images/val2014/COCO_val2014_000000009217.jpg -../coco/images/val2014/COCO_val2014_000000009270.jpg -../coco/images/val2014/COCO_val2014_000000009286.jpg -../coco/images/val2014/COCO_val2014_000000009548.jpg -../coco/images/val2014/COCO_val2014_000000009553.jpg -../coco/images/val2014/COCO_val2014_000000009727.jpg -../coco/images/val2014/COCO_val2014_000000009908.jpg -../coco/images/val2014/COCO_val2014_000000010114.jpg -../coco/images/val2014/COCO_val2014_000000010249.jpg -../coco/images/val2014/COCO_val2014_000000010395.jpg -../coco/images/val2014/COCO_val2014_000000010400.jpg -../coco/images/val2014/COCO_val2014_000000010463.jpg -../coco/images/val2014/COCO_val2014_000000010613.jpg -../coco/images/val2014/COCO_val2014_000000010764.jpg -../coco/images/val2014/COCO_val2014_000000010779.jpg -../coco/images/val2014/COCO_val2014_000000010928.jpg -../coco/images/val2014/COCO_val2014_000000011099.jpg -../coco/images/val2014/COCO_val2014_000000011181.jpg -../coco/images/val2014/COCO_val2014_000000011184.jpg -../coco/images/val2014/COCO_val2014_000000011197.jpg -../coco/images/val2014/COCO_val2014_000000011320.jpg -../coco/images/val2014/COCO_val2014_000000011721.jpg -../coco/images/val2014/COCO_val2014_000000011813.jpg -../coco/images/val2014/COCO_val2014_000000012014.jpg -../coco/images/val2014/COCO_val2014_000000012047.jpg -../coco/images/val2014/COCO_val2014_000000012085.jpg -../coco/images/val2014/COCO_val2014_000000012115.jpg -../coco/images/val2014/COCO_val2014_000000012166.jpg -../coco/images/val2014/COCO_val2014_000000012230.jpg -../coco/images/val2014/COCO_val2014_000000012370.jpg -../coco/images/val2014/COCO_val2014_000000012375.jpg -../coco/images/val2014/COCO_val2014_000000012448.jpg -../coco/images/val2014/COCO_val2014_000000012543.jpg -../coco/images/val2014/COCO_val2014_000000012744.jpg -../coco/images/val2014/COCO_val2014_000000012897.jpg -../coco/images/val2014/COCO_val2014_000000012966.jpg -../coco/images/val2014/COCO_val2014_000000012993.jpg -../coco/images/val2014/COCO_val2014_000000013004.jpg -../coco/images/val2014/COCO_val2014_000000013333.jpg -../coco/images/val2014/COCO_val2014_000000013357.jpg -../coco/images/val2014/COCO_val2014_000000013774.jpg -../coco/images/val2014/COCO_val2014_000000014029.jpg -../coco/images/val2014/COCO_val2014_000000014056.jpg -../coco/images/val2014/COCO_val2014_000000014108.jpg -../coco/images/val2014/COCO_val2014_000000014135.jpg -../coco/images/val2014/COCO_val2014_000000014226.jpg -../coco/images/val2014/COCO_val2014_000000014306.jpg -../coco/images/val2014/COCO_val2014_000000014591.jpg -../coco/images/val2014/COCO_val2014_000000014629.jpg -../coco/images/val2014/COCO_val2014_000000014756.jpg -../coco/images/val2014/COCO_val2014_000000014874.jpg -../coco/images/val2014/COCO_val2014_000000014990.jpg -../coco/images/val2014/COCO_val2014_000000015386.jpg -../coco/images/val2014/COCO_val2014_000000015559.jpg -../coco/images/val2014/COCO_val2014_000000015599.jpg -../coco/images/val2014/COCO_val2014_000000015709.jpg -../coco/images/val2014/COCO_val2014_000000015735.jpg -../coco/images/val2014/COCO_val2014_000000015751.jpg -../coco/images/val2014/COCO_val2014_000000015883.jpg -../coco/images/val2014/COCO_val2014_000000015953.jpg -../coco/images/val2014/COCO_val2014_000000015956.jpg -../coco/images/val2014/COCO_val2014_000000015968.jpg -../coco/images/val2014/COCO_val2014_000000015987.jpg -../coco/images/val2014/COCO_val2014_000000016030.jpg -../coco/images/val2014/COCO_val2014_000000016076.jpg -../coco/images/val2014/COCO_val2014_000000016228.jpg -../coco/images/val2014/COCO_val2014_000000016241.jpg -../coco/images/val2014/COCO_val2014_000000016257.jpg -../coco/images/val2014/COCO_val2014_000000016327.jpg -../coco/images/val2014/COCO_val2014_000000016410.jpg -../coco/images/val2014/COCO_val2014_000000016574.jpg -../coco/images/val2014/COCO_val2014_000000016716.jpg -../coco/images/val2014/COCO_val2014_000000016928.jpg -../coco/images/val2014/COCO_val2014_000000016995.jpg -../coco/images/val2014/COCO_val2014_000000017235.jpg -../coco/images/val2014/COCO_val2014_000000017379.jpg -../coco/images/val2014/COCO_val2014_000000017667.jpg -../coco/images/val2014/COCO_val2014_000000017755.jpg -../coco/images/val2014/COCO_val2014_000000018295.jpg -../coco/images/val2014/COCO_val2014_000000018358.jpg -../coco/images/val2014/COCO_val2014_000000018476.jpg -../coco/images/val2014/COCO_val2014_000000018750.jpg -../coco/images/val2014/COCO_val2014_000000018783.jpg -../coco/images/val2014/COCO_val2014_000000019025.jpg -../coco/images/val2014/COCO_val2014_000000019042.jpg -../coco/images/val2014/COCO_val2014_000000019129.jpg -../coco/images/val2014/COCO_val2014_000000019176.jpg -../coco/images/val2014/COCO_val2014_000000019491.jpg -../coco/images/val2014/COCO_val2014_000000019890.jpg -../coco/images/val2014/COCO_val2014_000000019923.jpg -../coco/images/val2014/COCO_val2014_000000020001.jpg -../coco/images/val2014/COCO_val2014_000000020038.jpg -../coco/images/val2014/COCO_val2014_000000020175.jpg -../coco/images/val2014/COCO_val2014_000000020268.jpg -../coco/images/val2014/COCO_val2014_000000020273.jpg -../coco/images/val2014/COCO_val2014_000000020349.jpg -../coco/images/val2014/COCO_val2014_000000020553.jpg -../coco/images/val2014/COCO_val2014_000000020788.jpg -../coco/images/val2014/COCO_val2014_000000020912.jpg -../coco/images/val2014/COCO_val2014_000000020947.jpg -../coco/images/val2014/COCO_val2014_000000020972.jpg -../coco/images/val2014/COCO_val2014_000000021161.jpg -../coco/images/val2014/COCO_val2014_000000021483.jpg -../coco/images/val2014/COCO_val2014_000000021588.jpg -../coco/images/val2014/COCO_val2014_000000021639.jpg -../coco/images/val2014/COCO_val2014_000000021644.jpg -../coco/images/val2014/COCO_val2014_000000021645.jpg -../coco/images/val2014/COCO_val2014_000000021671.jpg -../coco/images/val2014/COCO_val2014_000000021746.jpg -../coco/images/val2014/COCO_val2014_000000021839.jpg -../coco/images/val2014/COCO_val2014_000000022002.jpg -../coco/images/val2014/COCO_val2014_000000022129.jpg -../coco/images/val2014/COCO_val2014_000000022191.jpg -../coco/images/val2014/COCO_val2014_000000022215.jpg -../coco/images/val2014/COCO_val2014_000000022341.jpg -../coco/images/val2014/COCO_val2014_000000022492.jpg -../coco/images/val2014/COCO_val2014_000000022563.jpg -../coco/images/val2014/COCO_val2014_000000022660.jpg -../coco/images/val2014/COCO_val2014_000000022705.jpg -../coco/images/val2014/COCO_val2014_000000023017.jpg -../coco/images/val2014/COCO_val2014_000000023309.jpg -../coco/images/val2014/COCO_val2014_000000023411.jpg -../coco/images/val2014/COCO_val2014_000000023754.jpg -../coco/images/val2014/COCO_val2014_000000023802.jpg -../coco/images/val2014/COCO_val2014_000000023981.jpg -../coco/images/val2014/COCO_val2014_000000023995.jpg -../coco/images/val2014/COCO_val2014_000000024112.jpg -../coco/images/val2014/COCO_val2014_000000024247.jpg -../coco/images/val2014/COCO_val2014_000000024396.jpg -../coco/images/val2014/COCO_val2014_000000024776.jpg -../coco/images/val2014/COCO_val2014_000000024924.jpg -../coco/images/val2014/COCO_val2014_000000025096.jpg -../coco/images/val2014/COCO_val2014_000000025191.jpg -../coco/images/val2014/COCO_val2014_000000025252.jpg -../coco/images/val2014/COCO_val2014_000000025293.jpg -../coco/images/val2014/COCO_val2014_000000025360.jpg -../coco/images/val2014/COCO_val2014_000000025595.jpg -../coco/images/val2014/COCO_val2014_000000025685.jpg -../coco/images/val2014/COCO_val2014_000000025807.jpg -../coco/images/val2014/COCO_val2014_000000025864.jpg -../coco/images/val2014/COCO_val2014_000000025989.jpg -../coco/images/val2014/COCO_val2014_000000026026.jpg -../coco/images/val2014/COCO_val2014_000000026430.jpg -../coco/images/val2014/COCO_val2014_000000026432.jpg -../coco/images/val2014/COCO_val2014_000000026534.jpg -../coco/images/val2014/COCO_val2014_000000026560.jpg -../coco/images/val2014/COCO_val2014_000000026564.jpg -../coco/images/val2014/COCO_val2014_000000026671.jpg -../coco/images/val2014/COCO_val2014_000000026690.jpg -../coco/images/val2014/COCO_val2014_000000026734.jpg -../coco/images/val2014/COCO_val2014_000000026799.jpg -../coco/images/val2014/COCO_val2014_000000026907.jpg -../coco/images/val2014/COCO_val2014_000000026908.jpg -../coco/images/val2014/COCO_val2014_000000026946.jpg -../coco/images/val2014/COCO_val2014_000000027530.jpg -../coco/images/val2014/COCO_val2014_000000027610.jpg -../coco/images/val2014/COCO_val2014_000000027620.jpg -../coco/images/val2014/COCO_val2014_000000027787.jpg -../coco/images/val2014/COCO_val2014_000000027789.jpg -../coco/images/val2014/COCO_val2014_000000027874.jpg -../coco/images/val2014/COCO_val2014_000000027946.jpg -../coco/images/val2014/COCO_val2014_000000027975.jpg -../coco/images/val2014/COCO_val2014_000000028022.jpg -../coco/images/val2014/COCO_val2014_000000028039.jpg -../coco/images/val2014/COCO_val2014_000000028273.jpg -../coco/images/val2014/COCO_val2014_000000028540.jpg -../coco/images/val2014/COCO_val2014_000000028702.jpg -../coco/images/val2014/COCO_val2014_000000028820.jpg -../coco/images/val2014/COCO_val2014_000000028874.jpg -../coco/images/val2014/COCO_val2014_000000029019.jpg -../coco/images/val2014/COCO_val2014_000000029030.jpg -../coco/images/val2014/COCO_val2014_000000029170.jpg -../coco/images/val2014/COCO_val2014_000000029308.jpg -../coco/images/val2014/COCO_val2014_000000029393.jpg -../coco/images/val2014/COCO_val2014_000000029524.jpg -../coco/images/val2014/COCO_val2014_000000029577.jpg -../coco/images/val2014/COCO_val2014_000000029648.jpg -../coco/images/val2014/COCO_val2014_000000029656.jpg -../coco/images/val2014/COCO_val2014_000000029697.jpg -../coco/images/val2014/COCO_val2014_000000029709.jpg -../coco/images/val2014/COCO_val2014_000000029719.jpg -../coco/images/val2014/COCO_val2014_000000030034.jpg -../coco/images/val2014/COCO_val2014_000000030062.jpg -../coco/images/val2014/COCO_val2014_000000030383.jpg -../coco/images/val2014/COCO_val2014_000000030470.jpg -../coco/images/val2014/COCO_val2014_000000030548.jpg -../coco/images/val2014/COCO_val2014_000000030668.jpg -../coco/images/val2014/COCO_val2014_000000030793.jpg -../coco/images/val2014/COCO_val2014_000000030843.jpg -../coco/images/val2014/COCO_val2014_000000030998.jpg -../coco/images/val2014/COCO_val2014_000000031151.jpg -../coco/images/val2014/COCO_val2014_000000031164.jpg -../coco/images/val2014/COCO_val2014_000000031176.jpg -../coco/images/val2014/COCO_val2014_000000031247.jpg -../coco/images/val2014/COCO_val2014_000000031392.jpg -../coco/images/val2014/COCO_val2014_000000031521.jpg -../coco/images/val2014/COCO_val2014_000000031542.jpg -../coco/images/val2014/COCO_val2014_000000031817.jpg -../coco/images/val2014/COCO_val2014_000000032081.jpg -../coco/images/val2014/COCO_val2014_000000032193.jpg -../coco/images/val2014/COCO_val2014_000000032331.jpg -../coco/images/val2014/COCO_val2014_000000032464.jpg -../coco/images/val2014/COCO_val2014_000000032510.jpg -../coco/images/val2014/COCO_val2014_000000032524.jpg -../coco/images/val2014/COCO_val2014_000000032625.jpg -../coco/images/val2014/COCO_val2014_000000032677.jpg -../coco/images/val2014/COCO_val2014_000000032715.jpg -../coco/images/val2014/COCO_val2014_000000032947.jpg -../coco/images/val2014/COCO_val2014_000000032964.jpg -../coco/images/val2014/COCO_val2014_000000033006.jpg -../coco/images/val2014/COCO_val2014_000000033055.jpg -../coco/images/val2014/COCO_val2014_000000033158.jpg -../coco/images/val2014/COCO_val2014_000000033243.jpg -../coco/images/val2014/COCO_val2014_000000033345.jpg -../coco/images/val2014/COCO_val2014_000000033499.jpg -../coco/images/val2014/COCO_val2014_000000033561.jpg -../coco/images/val2014/COCO_val2014_000000033830.jpg -../coco/images/val2014/COCO_val2014_000000033835.jpg -../coco/images/val2014/COCO_val2014_000000033924.jpg -../coco/images/val2014/COCO_val2014_000000034056.jpg -../coco/images/val2014/COCO_val2014_000000034114.jpg -../coco/images/val2014/COCO_val2014_000000034137.jpg -../coco/images/val2014/COCO_val2014_000000034183.jpg -../coco/images/val2014/COCO_val2014_000000034193.jpg -../coco/images/val2014/COCO_val2014_000000034299.jpg -../coco/images/val2014/COCO_val2014_000000034452.jpg -../coco/images/val2014/COCO_val2014_000000034689.jpg -../coco/images/val2014/COCO_val2014_000000034877.jpg -../coco/images/val2014/COCO_val2014_000000034892.jpg -../coco/images/val2014/COCO_val2014_000000034930.jpg -../coco/images/val2014/COCO_val2014_000000035012.jpg -../coco/images/val2014/COCO_val2014_000000035222.jpg -../coco/images/val2014/COCO_val2014_000000035326.jpg -../coco/images/val2014/COCO_val2014_000000035368.jpg -../coco/images/val2014/COCO_val2014_000000035474.jpg -../coco/images/val2014/COCO_val2014_000000035498.jpg -../coco/images/val2014/COCO_val2014_000000035738.jpg -../coco/images/val2014/COCO_val2014_000000035826.jpg -../coco/images/val2014/COCO_val2014_000000035940.jpg -../coco/images/val2014/COCO_val2014_000000035966.jpg -../coco/images/val2014/COCO_val2014_000000036049.jpg -../coco/images/val2014/COCO_val2014_000000036252.jpg -../coco/images/val2014/COCO_val2014_000000036508.jpg -../coco/images/val2014/COCO_val2014_000000036522.jpg -../coco/images/val2014/COCO_val2014_000000036539.jpg -../coco/images/val2014/COCO_val2014_000000036563.jpg -../coco/images/val2014/COCO_val2014_000000037038.jpg -../coco/images/val2014/COCO_val2014_000000037629.jpg -../coco/images/val2014/COCO_val2014_000000037675.jpg -../coco/images/val2014/COCO_val2014_000000037846.jpg -../coco/images/val2014/COCO_val2014_000000037865.jpg -../coco/images/val2014/COCO_val2014_000000037907.jpg -../coco/images/val2014/COCO_val2014_000000037988.jpg -../coco/images/val2014/COCO_val2014_000000038031.jpg -../coco/images/val2014/COCO_val2014_000000038190.jpg -../coco/images/val2014/COCO_val2014_000000038252.jpg -../coco/images/val2014/COCO_val2014_000000038296.jpg -../coco/images/val2014/COCO_val2014_000000038465.jpg -../coco/images/val2014/COCO_val2014_000000038488.jpg -../coco/images/val2014/COCO_val2014_000000038531.jpg -../coco/images/val2014/COCO_val2014_000000038539.jpg -../coco/images/val2014/COCO_val2014_000000038645.jpg -../coco/images/val2014/COCO_val2014_000000038685.jpg -../coco/images/val2014/COCO_val2014_000000038825.jpg -../coco/images/val2014/COCO_val2014_000000039322.jpg -../coco/images/val2014/COCO_val2014_000000039480.jpg -../coco/images/val2014/COCO_val2014_000000039697.jpg -../coco/images/val2014/COCO_val2014_000000039731.jpg -../coco/images/val2014/COCO_val2014_000000039743.jpg -../coco/images/val2014/COCO_val2014_000000039785.jpg -../coco/images/val2014/COCO_val2014_000000039961.jpg -../coco/images/val2014/COCO_val2014_000000040426.jpg -../coco/images/val2014/COCO_val2014_000000040485.jpg -../coco/images/val2014/COCO_val2014_000000040681.jpg -../coco/images/val2014/COCO_val2014_000000040686.jpg -../coco/images/val2014/COCO_val2014_000000040886.jpg -../coco/images/val2014/COCO_val2014_000000041119.jpg -../coco/images/val2014/COCO_val2014_000000041147.jpg -../coco/images/val2014/COCO_val2014_000000041322.jpg -../coco/images/val2014/COCO_val2014_000000041373.jpg -../coco/images/val2014/COCO_val2014_000000041550.jpg -../coco/images/val2014/COCO_val2014_000000041635.jpg -../coco/images/val2014/COCO_val2014_000000041867.jpg -../coco/images/val2014/COCO_val2014_000000041872.jpg -../coco/images/val2014/COCO_val2014_000000041924.jpg -../coco/images/val2014/COCO_val2014_000000042137.jpg -../coco/images/val2014/COCO_val2014_000000042279.jpg -../coco/images/val2014/COCO_val2014_000000042492.jpg -../coco/images/val2014/COCO_val2014_000000042576.jpg -../coco/images/val2014/COCO_val2014_000000042661.jpg -../coco/images/val2014/COCO_val2014_000000042743.jpg -../coco/images/val2014/COCO_val2014_000000042805.jpg -../coco/images/val2014/COCO_val2014_000000042837.jpg -../coco/images/val2014/COCO_val2014_000000043165.jpg -../coco/images/val2014/COCO_val2014_000000043218.jpg -../coco/images/val2014/COCO_val2014_000000043261.jpg -../coco/images/val2014/COCO_val2014_000000043404.jpg -../coco/images/val2014/COCO_val2014_000000043542.jpg -../coco/images/val2014/COCO_val2014_000000043605.jpg -../coco/images/val2014/COCO_val2014_000000043614.jpg -../coco/images/val2014/COCO_val2014_000000043673.jpg -../coco/images/val2014/COCO_val2014_000000043816.jpg -../coco/images/val2014/COCO_val2014_000000043850.jpg -../coco/images/val2014/COCO_val2014_000000044220.jpg -../coco/images/val2014/COCO_val2014_000000044269.jpg -../coco/images/val2014/COCO_val2014_000000044309.jpg -../coco/images/val2014/COCO_val2014_000000044478.jpg -../coco/images/val2014/COCO_val2014_000000044536.jpg -../coco/images/val2014/COCO_val2014_000000044559.jpg -../coco/images/val2014/COCO_val2014_000000044575.jpg -../coco/images/val2014/COCO_val2014_000000044612.jpg -../coco/images/val2014/COCO_val2014_000000044677.jpg -../coco/images/val2014/COCO_val2014_000000044699.jpg -../coco/images/val2014/COCO_val2014_000000044823.jpg -../coco/images/val2014/COCO_val2014_000000044989.jpg -../coco/images/val2014/COCO_val2014_000000045094.jpg -../coco/images/val2014/COCO_val2014_000000045176.jpg -../coco/images/val2014/COCO_val2014_000000045197.jpg -../coco/images/val2014/COCO_val2014_000000045367.jpg -../coco/images/val2014/COCO_val2014_000000045392.jpg -../coco/images/val2014/COCO_val2014_000000045433.jpg -../coco/images/val2014/COCO_val2014_000000045463.jpg -../coco/images/val2014/COCO_val2014_000000045550.jpg -../coco/images/val2014/COCO_val2014_000000045574.jpg -../coco/images/val2014/COCO_val2014_000000045627.jpg -../coco/images/val2014/COCO_val2014_000000045685.jpg -../coco/images/val2014/COCO_val2014_000000045728.jpg -../coco/images/val2014/COCO_val2014_000000046252.jpg -../coco/images/val2014/COCO_val2014_000000046269.jpg -../coco/images/val2014/COCO_val2014_000000046329.jpg -../coco/images/val2014/COCO_val2014_000000046805.jpg -../coco/images/val2014/COCO_val2014_000000046869.jpg -../coco/images/val2014/COCO_val2014_000000046919.jpg -../coco/images/val2014/COCO_val2014_000000046924.jpg -../coco/images/val2014/COCO_val2014_000000047008.jpg -../coco/images/val2014/COCO_val2014_000000047131.jpg -../coco/images/val2014/COCO_val2014_000000047226.jpg -../coco/images/val2014/COCO_val2014_000000047263.jpg -../coco/images/val2014/COCO_val2014_000000047395.jpg -../coco/images/val2014/COCO_val2014_000000047552.jpg -../coco/images/val2014/COCO_val2014_000000047570.jpg -../coco/images/val2014/COCO_val2014_000000047720.jpg -../coco/images/val2014/COCO_val2014_000000047775.jpg -../coco/images/val2014/COCO_val2014_000000047886.jpg -../coco/images/val2014/COCO_val2014_000000048504.jpg -../coco/images/val2014/COCO_val2014_000000048564.jpg -../coco/images/val2014/COCO_val2014_000000048668.jpg -../coco/images/val2014/COCO_val2014_000000048731.jpg -../coco/images/val2014/COCO_val2014_000000048739.jpg -../coco/images/val2014/COCO_val2014_000000048791.jpg -../coco/images/val2014/COCO_val2014_000000048840.jpg -../coco/images/val2014/COCO_val2014_000000048905.jpg -../coco/images/val2014/COCO_val2014_000000048910.jpg -../coco/images/val2014/COCO_val2014_000000048924.jpg -../coco/images/val2014/COCO_val2014_000000048956.jpg -../coco/images/val2014/COCO_val2014_000000049075.jpg -../coco/images/val2014/COCO_val2014_000000049236.jpg -../coco/images/val2014/COCO_val2014_000000049676.jpg -../coco/images/val2014/COCO_val2014_000000049881.jpg -../coco/images/val2014/COCO_val2014_000000049985.jpg -../coco/images/val2014/COCO_val2014_000000050100.jpg -../coco/images/val2014/COCO_val2014_000000050145.jpg -../coco/images/val2014/COCO_val2014_000000050177.jpg -../coco/images/val2014/COCO_val2014_000000050324.jpg -../coco/images/val2014/COCO_val2014_000000050331.jpg -../coco/images/val2014/COCO_val2014_000000050481.jpg -../coco/images/val2014/COCO_val2014_000000050485.jpg -../coco/images/val2014/COCO_val2014_000000050493.jpg -../coco/images/val2014/COCO_val2014_000000050746.jpg -../coco/images/val2014/COCO_val2014_000000050844.jpg -../coco/images/val2014/COCO_val2014_000000050896.jpg -../coco/images/val2014/COCO_val2014_000000051249.jpg -../coco/images/val2014/COCO_val2014_000000051250.jpg -../coco/images/val2014/COCO_val2014_000000051289.jpg -../coco/images/val2014/COCO_val2014_000000051314.jpg -../coco/images/val2014/COCO_val2014_000000051339.jpg -../coco/images/val2014/COCO_val2014_000000051461.jpg -../coco/images/val2014/COCO_val2014_000000051476.jpg -../coco/images/val2014/COCO_val2014_000000052005.jpg -../coco/images/val2014/COCO_val2014_000000052020.jpg -../coco/images/val2014/COCO_val2014_000000052290.jpg -../coco/images/val2014/COCO_val2014_000000052314.jpg -../coco/images/val2014/COCO_val2014_000000052425.jpg -../coco/images/val2014/COCO_val2014_000000052575.jpg -../coco/images/val2014/COCO_val2014_000000052871.jpg -../coco/images/val2014/COCO_val2014_000000052982.jpg -../coco/images/val2014/COCO_val2014_000000053139.jpg -../coco/images/val2014/COCO_val2014_000000053183.jpg -../coco/images/val2014/COCO_val2014_000000053263.jpg -../coco/images/val2014/COCO_val2014_000000053491.jpg -../coco/images/val2014/COCO_val2014_000000053503.jpg -../coco/images/val2014/COCO_val2014_000000053580.jpg -../coco/images/val2014/COCO_val2014_000000053616.jpg -../coco/images/val2014/COCO_val2014_000000053907.jpg -../coco/images/val2014/COCO_val2014_000000053949.jpg -../coco/images/val2014/COCO_val2014_000000054301.jpg -../coco/images/val2014/COCO_val2014_000000054334.jpg -../coco/images/val2014/COCO_val2014_000000054490.jpg -../coco/images/val2014/COCO_val2014_000000054527.jpg -../coco/images/val2014/COCO_val2014_000000054533.jpg -../coco/images/val2014/COCO_val2014_000000054603.jpg -../coco/images/val2014/COCO_val2014_000000054643.jpg -../coco/images/val2014/COCO_val2014_000000054679.jpg -../coco/images/val2014/COCO_val2014_000000054723.jpg -../coco/images/val2014/COCO_val2014_000000054959.jpg -../coco/images/val2014/COCO_val2014_000000055167.jpg -../coco/images/val2014/COCO_val2014_000000056137.jpg -../coco/images/val2014/COCO_val2014_000000056326.jpg -../coco/images/val2014/COCO_val2014_000000056541.jpg -../coco/images/val2014/COCO_val2014_000000056562.jpg -../coco/images/val2014/COCO_val2014_000000056624.jpg -../coco/images/val2014/COCO_val2014_000000056633.jpg -../coco/images/val2014/COCO_val2014_000000056724.jpg -../coco/images/val2014/COCO_val2014_000000056739.jpg -../coco/images/val2014/COCO_val2014_000000057027.jpg -../coco/images/val2014/COCO_val2014_000000057091.jpg -../coco/images/val2014/COCO_val2014_000000057095.jpg -../coco/images/val2014/COCO_val2014_000000057100.jpg -../coco/images/val2014/COCO_val2014_000000057149.jpg -../coco/images/val2014/COCO_val2014_000000057238.jpg -../coco/images/val2014/COCO_val2014_000000057359.jpg -../coco/images/val2014/COCO_val2014_000000057454.jpg -../coco/images/val2014/COCO_val2014_000000058001.jpg -../coco/images/val2014/COCO_val2014_000000058157.jpg -../coco/images/val2014/COCO_val2014_000000058223.jpg -../coco/images/val2014/COCO_val2014_000000058232.jpg -../coco/images/val2014/COCO_val2014_000000058344.jpg -../coco/images/val2014/COCO_val2014_000000058522.jpg -../coco/images/val2014/COCO_val2014_000000058636.jpg -../coco/images/val2014/COCO_val2014_000000058800.jpg -../coco/images/val2014/COCO_val2014_000000058949.jpg -../coco/images/val2014/COCO_val2014_000000059009.jpg -../coco/images/val2014/COCO_val2014_000000059202.jpg -../coco/images/val2014/COCO_val2014_000000059393.jpg -../coco/images/val2014/COCO_val2014_000000059652.jpg -../coco/images/val2014/COCO_val2014_000000060010.jpg -../coco/images/val2014/COCO_val2014_000000060049.jpg -../coco/images/val2014/COCO_val2014_000000060126.jpg -../coco/images/val2014/COCO_val2014_000000060128.jpg -../coco/images/val2014/COCO_val2014_000000060448.jpg -../coco/images/val2014/COCO_val2014_000000060548.jpg -../coco/images/val2014/COCO_val2014_000000060677.jpg -../coco/images/val2014/COCO_val2014_000000060760.jpg -../coco/images/val2014/COCO_val2014_000000060823.jpg -../coco/images/val2014/COCO_val2014_000000060859.jpg -../coco/images/val2014/COCO_val2014_000000060899.jpg -../coco/images/val2014/COCO_val2014_000000061171.jpg -../coco/images/val2014/COCO_val2014_000000061503.jpg -../coco/images/val2014/COCO_val2014_000000061520.jpg -../coco/images/val2014/COCO_val2014_000000061531.jpg -../coco/images/val2014/COCO_val2014_000000061564.jpg -../coco/images/val2014/COCO_val2014_000000061658.jpg -../coco/images/val2014/COCO_val2014_000000061693.jpg -../coco/images/val2014/COCO_val2014_000000061717.jpg -../coco/images/val2014/COCO_val2014_000000061836.jpg -../coco/images/val2014/COCO_val2014_000000062041.jpg -../coco/images/val2014/COCO_val2014_000000062060.jpg -../coco/images/val2014/COCO_val2014_000000062198.jpg -../coco/images/val2014/COCO_val2014_000000062200.jpg -../coco/images/val2014/COCO_val2014_000000062220.jpg -../coco/images/val2014/COCO_val2014_000000062623.jpg -../coco/images/val2014/COCO_val2014_000000062726.jpg -../coco/images/val2014/COCO_val2014_000000062875.jpg -../coco/images/val2014/COCO_val2014_000000063047.jpg -../coco/images/val2014/COCO_val2014_000000063114.jpg -../coco/images/val2014/COCO_val2014_000000063488.jpg -../coco/images/val2014/COCO_val2014_000000063671.jpg -../coco/images/val2014/COCO_val2014_000000063715.jpg -../coco/images/val2014/COCO_val2014_000000063804.jpg -../coco/images/val2014/COCO_val2014_000000063882.jpg -../coco/images/val2014/COCO_val2014_000000063939.jpg -../coco/images/val2014/COCO_val2014_000000063965.jpg -../coco/images/val2014/COCO_val2014_000000064155.jpg -../coco/images/val2014/COCO_val2014_000000064189.jpg -../coco/images/val2014/COCO_val2014_000000064196.jpg -../coco/images/val2014/COCO_val2014_000000064495.jpg -../coco/images/val2014/COCO_val2014_000000064610.jpg -../coco/images/val2014/COCO_val2014_000000064693.jpg -../coco/images/val2014/COCO_val2014_000000064746.jpg -../coco/images/val2014/COCO_val2014_000000064760.jpg -../coco/images/val2014/COCO_val2014_000000064796.jpg -../coco/images/val2014/COCO_val2014_000000064865.jpg -../coco/images/val2014/COCO_val2014_000000064915.jpg -../coco/images/val2014/COCO_val2014_000000065074.jpg -../coco/images/val2014/COCO_val2014_000000065124.jpg -../coco/images/val2014/COCO_val2014_000000065258.jpg -../coco/images/val2014/COCO_val2014_000000065267.jpg -../coco/images/val2014/COCO_val2014_000000065430.jpg -../coco/images/val2014/COCO_val2014_000000065465.jpg -../coco/images/val2014/COCO_val2014_000000065942.jpg -../coco/images/val2014/COCO_val2014_000000066001.jpg -../coco/images/val2014/COCO_val2014_000000066064.jpg -../coco/images/val2014/COCO_val2014_000000066072.jpg -../coco/images/val2014/COCO_val2014_000000066239.jpg -../coco/images/val2014/COCO_val2014_000000066243.jpg -../coco/images/val2014/COCO_val2014_000000066355.jpg -../coco/images/val2014/COCO_val2014_000000066412.jpg -../coco/images/val2014/COCO_val2014_000000066423.jpg -../coco/images/val2014/COCO_val2014_000000066427.jpg -../coco/images/val2014/COCO_val2014_000000066502.jpg -../coco/images/val2014/COCO_val2014_000000066519.jpg -../coco/images/val2014/COCO_val2014_000000066561.jpg -../coco/images/val2014/COCO_val2014_000000066700.jpg -../coco/images/val2014/COCO_val2014_000000066717.jpg -../coco/images/val2014/COCO_val2014_000000066879.jpg -../coco/images/val2014/COCO_val2014_000000067178.jpg -../coco/images/val2014/COCO_val2014_000000067207.jpg -../coco/images/val2014/COCO_val2014_000000067218.jpg -../coco/images/val2014/COCO_val2014_000000067412.jpg -../coco/images/val2014/COCO_val2014_000000067532.jpg -../coco/images/val2014/COCO_val2014_000000067590.jpg -../coco/images/val2014/COCO_val2014_000000067660.jpg -../coco/images/val2014/COCO_val2014_000000067686.jpg -../coco/images/val2014/COCO_val2014_000000067704.jpg -../coco/images/val2014/COCO_val2014_000000067776.jpg -../coco/images/val2014/COCO_val2014_000000067948.jpg -../coco/images/val2014/COCO_val2014_000000067953.jpg -../coco/images/val2014/COCO_val2014_000000068059.jpg -../coco/images/val2014/COCO_val2014_000000068204.jpg -../coco/images/val2014/COCO_val2014_000000068205.jpg -../coco/images/val2014/COCO_val2014_000000068409.jpg -../coco/images/val2014/COCO_val2014_000000068435.jpg -../coco/images/val2014/COCO_val2014_000000068520.jpg -../coco/images/val2014/COCO_val2014_000000068546.jpg -../coco/images/val2014/COCO_val2014_000000068674.jpg -../coco/images/val2014/COCO_val2014_000000068745.jpg -../coco/images/val2014/COCO_val2014_000000069009.jpg -../coco/images/val2014/COCO_val2014_000000069077.jpg -../coco/images/val2014/COCO_val2014_000000069196.jpg -../coco/images/val2014/COCO_val2014_000000069356.jpg -../coco/images/val2014/COCO_val2014_000000069568.jpg -../coco/images/val2014/COCO_val2014_000000069577.jpg -../coco/images/val2014/COCO_val2014_000000069698.jpg -../coco/images/val2014/COCO_val2014_000000070493.jpg -../coco/images/val2014/COCO_val2014_000000070896.jpg -../coco/images/val2014/COCO_val2014_000000071023.jpg -../coco/images/val2014/COCO_val2014_000000071123.jpg -../coco/images/val2014/COCO_val2014_000000071241.jpg -../coco/images/val2014/COCO_val2014_000000071301.jpg -../coco/images/val2014/COCO_val2014_000000071345.jpg -../coco/images/val2014/COCO_val2014_000000071451.jpg -../coco/images/val2014/COCO_val2014_000000071673.jpg -../coco/images/val2014/COCO_val2014_000000071826.jpg -../coco/images/val2014/COCO_val2014_000000071986.jpg -../coco/images/val2014/COCO_val2014_000000072004.jpg -../coco/images/val2014/COCO_val2014_000000072020.jpg -../coco/images/val2014/COCO_val2014_000000072052.jpg -../coco/images/val2014/COCO_val2014_000000072281.jpg -../coco/images/val2014/COCO_val2014_000000072368.jpg -../coco/images/val2014/COCO_val2014_000000072737.jpg -../coco/images/val2014/COCO_val2014_000000072797.jpg -../coco/images/val2014/COCO_val2014_000000072860.jpg -../coco/images/val2014/COCO_val2014_000000073009.jpg -../coco/images/val2014/COCO_val2014_000000073039.jpg -../coco/images/val2014/COCO_val2014_000000073239.jpg -../coco/images/val2014/COCO_val2014_000000073467.jpg -../coco/images/val2014/COCO_val2014_000000073491.jpg -../coco/images/val2014/COCO_val2014_000000073588.jpg -../coco/images/val2014/COCO_val2014_000000073729.jpg -../coco/images/val2014/COCO_val2014_000000073973.jpg -../coco/images/val2014/COCO_val2014_000000074037.jpg -../coco/images/val2014/COCO_val2014_000000074137.jpg -../coco/images/val2014/COCO_val2014_000000074268.jpg -../coco/images/val2014/COCO_val2014_000000074434.jpg -../coco/images/val2014/COCO_val2014_000000074789.jpg -../coco/images/val2014/COCO_val2014_000000074963.jpg -../coco/images/val2014/COCO_val2014_000000075033.jpg -../coco/images/val2014/COCO_val2014_000000075372.jpg -../coco/images/val2014/COCO_val2014_000000075527.jpg -../coco/images/val2014/COCO_val2014_000000075646.jpg -../coco/images/val2014/COCO_val2014_000000075713.jpg -../coco/images/val2014/COCO_val2014_000000075775.jpg -../coco/images/val2014/COCO_val2014_000000075786.jpg -../coco/images/val2014/COCO_val2014_000000075886.jpg -../coco/images/val2014/COCO_val2014_000000076087.jpg -../coco/images/val2014/COCO_val2014_000000076257.jpg -../coco/images/val2014/COCO_val2014_000000076521.jpg -../coco/images/val2014/COCO_val2014_000000076572.jpg -../coco/images/val2014/COCO_val2014_000000076844.jpg -../coco/images/val2014/COCO_val2014_000000077178.jpg -../coco/images/val2014/COCO_val2014_000000077181.jpg -../coco/images/val2014/COCO_val2014_000000077184.jpg -../coco/images/val2014/COCO_val2014_000000077396.jpg -../coco/images/val2014/COCO_val2014_000000077400.jpg -../coco/images/val2014/COCO_val2014_000000077415.jpg -../coco/images/val2014/COCO_val2014_000000078565.jpg -../coco/images/val2014/COCO_val2014_000000078701.jpg -../coco/images/val2014/COCO_val2014_000000078843.jpg -../coco/images/val2014/COCO_val2014_000000078929.jpg -../coco/images/val2014/COCO_val2014_000000079084.jpg -../coco/images/val2014/COCO_val2014_000000079188.jpg -../coco/images/val2014/COCO_val2014_000000079544.jpg -../coco/images/val2014/COCO_val2014_000000079566.jpg -../coco/images/val2014/COCO_val2014_000000079588.jpg -../coco/images/val2014/COCO_val2014_000000079689.jpg -../coco/images/val2014/COCO_val2014_000000080104.jpg -../coco/images/val2014/COCO_val2014_000000080172.jpg -../coco/images/val2014/COCO_val2014_000000080219.jpg -../coco/images/val2014/COCO_val2014_000000080300.jpg -../coco/images/val2014/COCO_val2014_000000080395.jpg -../coco/images/val2014/COCO_val2014_000000080522.jpg -../coco/images/val2014/COCO_val2014_000000080714.jpg -../coco/images/val2014/COCO_val2014_000000080737.jpg -../coco/images/val2014/COCO_val2014_000000080747.jpg -../coco/images/val2014/COCO_val2014_000000081000.jpg -../coco/images/val2014/COCO_val2014_000000081081.jpg -../coco/images/val2014/COCO_val2014_000000081100.jpg -../coco/images/val2014/COCO_val2014_000000081287.jpg -../coco/images/val2014/COCO_val2014_000000081394.jpg -../coco/images/val2014/COCO_val2014_000000081552.jpg -../coco/images/val2014/COCO_val2014_000000082157.jpg -../coco/images/val2014/COCO_val2014_000000082252.jpg -../coco/images/val2014/COCO_val2014_000000082259.jpg -../coco/images/val2014/COCO_val2014_000000082367.jpg -../coco/images/val2014/COCO_val2014_000000082431.jpg -../coco/images/val2014/COCO_val2014_000000082456.jpg -../coco/images/val2014/COCO_val2014_000000082794.jpg -../coco/images/val2014/COCO_val2014_000000082807.jpg -../coco/images/val2014/COCO_val2014_000000082846.jpg -../coco/images/val2014/COCO_val2014_000000082847.jpg -../coco/images/val2014/COCO_val2014_000000082889.jpg -../coco/images/val2014/COCO_val2014_000000082981.jpg -../coco/images/val2014/COCO_val2014_000000083036.jpg -../coco/images/val2014/COCO_val2014_000000083065.jpg -../coco/images/val2014/COCO_val2014_000000083142.jpg -../coco/images/val2014/COCO_val2014_000000083275.jpg -../coco/images/val2014/COCO_val2014_000000083557.jpg -../coco/images/val2014/COCO_val2014_000000084073.jpg -../coco/images/val2014/COCO_val2014_000000084447.jpg -../coco/images/val2014/COCO_val2014_000000084463.jpg -../coco/images/val2014/COCO_val2014_000000084592.jpg -../coco/images/val2014/COCO_val2014_000000084674.jpg -../coco/images/val2014/COCO_val2014_000000084762.jpg -../coco/images/val2014/COCO_val2014_000000084870.jpg -../coco/images/val2014/COCO_val2014_000000084929.jpg -../coco/images/val2014/COCO_val2014_000000084980.jpg -../coco/images/val2014/COCO_val2014_000000085101.jpg -../coco/images/val2014/COCO_val2014_000000085292.jpg -../coco/images/val2014/COCO_val2014_000000085353.jpg -../coco/images/val2014/COCO_val2014_000000085674.jpg -../coco/images/val2014/COCO_val2014_000000085813.jpg -../coco/images/val2014/COCO_val2014_000000086011.jpg -../coco/images/val2014/COCO_val2014_000000086133.jpg -../coco/images/val2014/COCO_val2014_000000086136.jpg -../coco/images/val2014/COCO_val2014_000000086215.jpg -../coco/images/val2014/COCO_val2014_000000086220.jpg -../coco/images/val2014/COCO_val2014_000000086249.jpg -../coco/images/val2014/COCO_val2014_000000086320.jpg -../coco/images/val2014/COCO_val2014_000000086357.jpg -../coco/images/val2014/COCO_val2014_000000086429.jpg -../coco/images/val2014/COCO_val2014_000000086467.jpg -../coco/images/val2014/COCO_val2014_000000086483.jpg -../coco/images/val2014/COCO_val2014_000000086646.jpg -../coco/images/val2014/COCO_val2014_000000086755.jpg -../coco/images/val2014/COCO_val2014_000000086839.jpg -../coco/images/val2014/COCO_val2014_000000086848.jpg -../coco/images/val2014/COCO_val2014_000000086877.jpg -../coco/images/val2014/COCO_val2014_000000087038.jpg -../coco/images/val2014/COCO_val2014_000000087244.jpg -../coco/images/val2014/COCO_val2014_000000087354.jpg -../coco/images/val2014/COCO_val2014_000000087387.jpg -../coco/images/val2014/COCO_val2014_000000087489.jpg -../coco/images/val2014/COCO_val2014_000000087503.jpg -../coco/images/val2014/COCO_val2014_000000087617.jpg -../coco/images/val2014/COCO_val2014_000000087638.jpg -../coco/images/val2014/COCO_val2014_000000087740.jpg -../coco/images/val2014/COCO_val2014_000000087875.jpg -../coco/images/val2014/COCO_val2014_000000088360.jpg -../coco/images/val2014/COCO_val2014_000000088507.jpg -../coco/images/val2014/COCO_val2014_000000088560.jpg -../coco/images/val2014/COCO_val2014_000000088846.jpg -../coco/images/val2014/COCO_val2014_000000088859.jpg -../coco/images/val2014/COCO_val2014_000000088902.jpg -../coco/images/val2014/COCO_val2014_000000089027.jpg -../coco/images/val2014/COCO_val2014_000000089258.jpg -../coco/images/val2014/COCO_val2014_000000089285.jpg -../coco/images/val2014/COCO_val2014_000000089359.jpg -../coco/images/val2014/COCO_val2014_000000089378.jpg -../coco/images/val2014/COCO_val2014_000000089391.jpg -../coco/images/val2014/COCO_val2014_000000089487.jpg -../coco/images/val2014/COCO_val2014_000000089618.jpg -../coco/images/val2014/COCO_val2014_000000089670.jpg -../coco/images/val2014/COCO_val2014_000000090003.jpg -../coco/images/val2014/COCO_val2014_000000090062.jpg -../coco/images/val2014/COCO_val2014_000000090155.jpg -../coco/images/val2014/COCO_val2014_000000090208.jpg -../coco/images/val2014/COCO_val2014_000000090351.jpg -../coco/images/val2014/COCO_val2014_000000090476.jpg -../coco/images/val2014/COCO_val2014_000000090594.jpg -../coco/images/val2014/COCO_val2014_000000090753.jpg -../coco/images/val2014/COCO_val2014_000000090754.jpg -../coco/images/val2014/COCO_val2014_000000090864.jpg -../coco/images/val2014/COCO_val2014_000000091079.jpg -../coco/images/val2014/COCO_val2014_000000091341.jpg -../coco/images/val2014/COCO_val2014_000000091402.jpg -../coco/images/val2014/COCO_val2014_000000091517.jpg -../coco/images/val2014/COCO_val2014_000000091520.jpg -../coco/images/val2014/COCO_val2014_000000091612.jpg -../coco/images/val2014/COCO_val2014_000000091716.jpg -../coco/images/val2014/COCO_val2014_000000091766.jpg -../coco/images/val2014/COCO_val2014_000000091857.jpg -../coco/images/val2014/COCO_val2014_000000091899.jpg -../coco/images/val2014/COCO_val2014_000000091912.jpg -../coco/images/val2014/COCO_val2014_000000092093.jpg -../coco/images/val2014/COCO_val2014_000000092124.jpg -../coco/images/val2014/COCO_val2014_000000092679.jpg -../coco/images/val2014/COCO_val2014_000000092683.jpg -../coco/images/val2014/COCO_val2014_000000092939.jpg -../coco/images/val2014/COCO_val2014_000000092985.jpg -../coco/images/val2014/COCO_val2014_000000093175.jpg -../coco/images/val2014/COCO_val2014_000000093236.jpg -../coco/images/val2014/COCO_val2014_000000093331.jpg -../coco/images/val2014/COCO_val2014_000000093434.jpg -../coco/images/val2014/COCO_val2014_000000093607.jpg -../coco/images/val2014/COCO_val2014_000000093806.jpg -../coco/images/val2014/COCO_val2014_000000093964.jpg -../coco/images/val2014/COCO_val2014_000000094012.jpg -../coco/images/val2014/COCO_val2014_000000094033.jpg -../coco/images/val2014/COCO_val2014_000000094046.jpg -../coco/images/val2014/COCO_val2014_000000094052.jpg -../coco/images/val2014/COCO_val2014_000000094055.jpg -../coco/images/val2014/COCO_val2014_000000094501.jpg -../coco/images/val2014/COCO_val2014_000000094619.jpg -../coco/images/val2014/COCO_val2014_000000094746.jpg -../coco/images/val2014/COCO_val2014_000000094795.jpg -../coco/images/val2014/COCO_val2014_000000094846.jpg -../coco/images/val2014/COCO_val2014_000000095062.jpg -../coco/images/val2014/COCO_val2014_000000095063.jpg -../coco/images/val2014/COCO_val2014_000000095227.jpg -../coco/images/val2014/COCO_val2014_000000095441.jpg -../coco/images/val2014/COCO_val2014_000000095551.jpg -../coco/images/val2014/COCO_val2014_000000095670.jpg -../coco/images/val2014/COCO_val2014_000000095770.jpg -../coco/images/val2014/COCO_val2014_000000096110.jpg -../coco/images/val2014/COCO_val2014_000000096288.jpg -../coco/images/val2014/COCO_val2014_000000096327.jpg -../coco/images/val2014/COCO_val2014_000000096351.jpg -../coco/images/val2014/COCO_val2014_000000096618.jpg -../coco/images/val2014/COCO_val2014_000000096654.jpg -../coco/images/val2014/COCO_val2014_000000096762.jpg -../coco/images/val2014/COCO_val2014_000000096769.jpg -../coco/images/val2014/COCO_val2014_000000096998.jpg -../coco/images/val2014/COCO_val2014_000000097017.jpg -../coco/images/val2014/COCO_val2014_000000097048.jpg -../coco/images/val2014/COCO_val2014_000000097080.jpg -../coco/images/val2014/COCO_val2014_000000097240.jpg -../coco/images/val2014/COCO_val2014_000000097479.jpg -../coco/images/val2014/COCO_val2014_000000097577.jpg -../coco/images/val2014/COCO_val2014_000000097610.jpg -../coco/images/val2014/COCO_val2014_000000097656.jpg -../coco/images/val2014/COCO_val2014_000000097667.jpg -../coco/images/val2014/COCO_val2014_000000097682.jpg -../coco/images/val2014/COCO_val2014_000000097748.jpg -../coco/images/val2014/COCO_val2014_000000097868.jpg -../coco/images/val2014/COCO_val2014_000000097899.jpg -../coco/images/val2014/COCO_val2014_000000098018.jpg -../coco/images/val2014/COCO_val2014_000000098043.jpg -../coco/images/val2014/COCO_val2014_000000098095.jpg -../coco/images/val2014/COCO_val2014_000000098194.jpg -../coco/images/val2014/COCO_val2014_000000098280.jpg -../coco/images/val2014/COCO_val2014_000000098283.jpg -../coco/images/val2014/COCO_val2014_000000098599.jpg -../coco/images/val2014/COCO_val2014_000000098872.jpg -../coco/images/val2014/COCO_val2014_000000099026.jpg -../coco/images/val2014/COCO_val2014_000000099260.jpg -../coco/images/val2014/COCO_val2014_000000099389.jpg -../coco/images/val2014/COCO_val2014_000000099707.jpg -../coco/images/val2014/COCO_val2014_000000099961.jpg -../coco/images/val2014/COCO_val2014_000000099996.jpg -../coco/images/val2014/COCO_val2014_000000100000.jpg -../coco/images/val2014/COCO_val2014_000000100006.jpg -../coco/images/val2014/COCO_val2014_000000100083.jpg -../coco/images/val2014/COCO_val2014_000000100166.jpg -../coco/images/val2014/COCO_val2014_000000100187.jpg -../coco/images/val2014/COCO_val2014_000000100245.jpg -../coco/images/val2014/COCO_val2014_000000100343.jpg -../coco/images/val2014/COCO_val2014_000000100428.jpg -../coco/images/val2014/COCO_val2014_000000100582.jpg -../coco/images/val2014/COCO_val2014_000000100723.jpg -../coco/images/val2014/COCO_val2014_000000100726.jpg -../coco/images/val2014/COCO_val2014_000000100909.jpg -../coco/images/val2014/COCO_val2014_000000101059.jpg -../coco/images/val2014/COCO_val2014_000000101145.jpg -../coco/images/val2014/COCO_val2014_000000101567.jpg -../coco/images/val2014/COCO_val2014_000000101623.jpg -../coco/images/val2014/COCO_val2014_000000101703.jpg -../coco/images/val2014/COCO_val2014_000000101884.jpg -../coco/images/val2014/COCO_val2014_000000101948.jpg -../coco/images/val2014/COCO_val2014_000000102331.jpg -../coco/images/val2014/COCO_val2014_000000102421.jpg -../coco/images/val2014/COCO_val2014_000000102439.jpg -../coco/images/val2014/COCO_val2014_000000102446.jpg -../coco/images/val2014/COCO_val2014_000000102461.jpg -../coco/images/val2014/COCO_val2014_000000102466.jpg -../coco/images/val2014/COCO_val2014_000000102478.jpg -../coco/images/val2014/COCO_val2014_000000102594.jpg -../coco/images/val2014/COCO_val2014_000000102598.jpg -../coco/images/val2014/COCO_val2014_000000102665.jpg -../coco/images/val2014/COCO_val2014_000000102707.jpg -../coco/images/val2014/COCO_val2014_000000102848.jpg -../coco/images/val2014/COCO_val2014_000000102906.jpg -../coco/images/val2014/COCO_val2014_000000103122.jpg -../coco/images/val2014/COCO_val2014_000000103255.jpg -../coco/images/val2014/COCO_val2014_000000103272.jpg -../coco/images/val2014/COCO_val2014_000000103379.jpg -../coco/images/val2014/COCO_val2014_000000103413.jpg -../coco/images/val2014/COCO_val2014_000000103431.jpg -../coco/images/val2014/COCO_val2014_000000103509.jpg -../coco/images/val2014/COCO_val2014_000000103538.jpg -../coco/images/val2014/COCO_val2014_000000103667.jpg -../coco/images/val2014/COCO_val2014_000000103747.jpg -../coco/images/val2014/COCO_val2014_000000103931.jpg -../coco/images/val2014/COCO_val2014_000000104002.jpg -../coco/images/val2014/COCO_val2014_000000104455.jpg -../coco/images/val2014/COCO_val2014_000000104486.jpg -../coco/images/val2014/COCO_val2014_000000104494.jpg -../coco/images/val2014/COCO_val2014_000000104495.jpg -../coco/images/val2014/COCO_val2014_000000104893.jpg -../coco/images/val2014/COCO_val2014_000000104965.jpg -../coco/images/val2014/COCO_val2014_000000105040.jpg -../coco/images/val2014/COCO_val2014_000000105102.jpg -../coco/images/val2014/COCO_val2014_000000105156.jpg -../coco/images/val2014/COCO_val2014_000000105264.jpg -../coco/images/val2014/COCO_val2014_000000105291.jpg -../coco/images/val2014/COCO_val2014_000000105367.jpg -../coco/images/val2014/COCO_val2014_000000105647.jpg -../coco/images/val2014/COCO_val2014_000000105668.jpg -../coco/images/val2014/COCO_val2014_000000105711.jpg -../coco/images/val2014/COCO_val2014_000000105866.jpg -../coco/images/val2014/COCO_val2014_000000105973.jpg -../coco/images/val2014/COCO_val2014_000000106096.jpg -../coco/images/val2014/COCO_val2014_000000106120.jpg -../coco/images/val2014/COCO_val2014_000000106314.jpg -../coco/images/val2014/COCO_val2014_000000106351.jpg -../coco/images/val2014/COCO_val2014_000000106641.jpg -../coco/images/val2014/COCO_val2014_000000106661.jpg -../coco/images/val2014/COCO_val2014_000000106757.jpg -../coco/images/val2014/COCO_val2014_000000106793.jpg -../coco/images/val2014/COCO_val2014_000000106849.jpg -../coco/images/val2014/COCO_val2014_000000107004.jpg -../coco/images/val2014/COCO_val2014_000000107123.jpg -../coco/images/val2014/COCO_val2014_000000107183.jpg -../coco/images/val2014/COCO_val2014_000000107227.jpg -../coco/images/val2014/COCO_val2014_000000107244.jpg -../coco/images/val2014/COCO_val2014_000000107304.jpg -../coco/images/val2014/COCO_val2014_000000107542.jpg -../coco/images/val2014/COCO_val2014_000000107741.jpg -../coco/images/val2014/COCO_val2014_000000107831.jpg -../coco/images/val2014/COCO_val2014_000000107839.jpg -../coco/images/val2014/COCO_val2014_000000108051.jpg -../coco/images/val2014/COCO_val2014_000000108152.jpg -../coco/images/val2014/COCO_val2014_000000108212.jpg -../coco/images/val2014/COCO_val2014_000000108380.jpg -../coco/images/val2014/COCO_val2014_000000108408.jpg -../coco/images/val2014/COCO_val2014_000000108531.jpg -../coco/images/val2014/COCO_val2014_000000108761.jpg -../coco/images/val2014/COCO_val2014_000000108864.jpg -../coco/images/val2014/COCO_val2014_000000109055.jpg -../coco/images/val2014/COCO_val2014_000000109092.jpg -../coco/images/val2014/COCO_val2014_000000109178.jpg -../coco/images/val2014/COCO_val2014_000000109216.jpg -../coco/images/val2014/COCO_val2014_000000109231.jpg -../coco/images/val2014/COCO_val2014_000000109308.jpg -../coco/images/val2014/COCO_val2014_000000109486.jpg -../coco/images/val2014/COCO_val2014_000000109819.jpg -../coco/images/val2014/COCO_val2014_000000109869.jpg -../coco/images/val2014/COCO_val2014_000000110313.jpg -../coco/images/val2014/COCO_val2014_000000110389.jpg -../coco/images/val2014/COCO_val2014_000000110562.jpg -../coco/images/val2014/COCO_val2014_000000110617.jpg -../coco/images/val2014/COCO_val2014_000000110638.jpg -../coco/images/val2014/COCO_val2014_000000110881.jpg -../coco/images/val2014/COCO_val2014_000000110884.jpg -../coco/images/val2014/COCO_val2014_000000110951.jpg -../coco/images/val2014/COCO_val2014_000000111004.jpg -../coco/images/val2014/COCO_val2014_000000111014.jpg -../coco/images/val2014/COCO_val2014_000000111024.jpg -../coco/images/val2014/COCO_val2014_000000111076.jpg -../coco/images/val2014/COCO_val2014_000000111179.jpg -../coco/images/val2014/COCO_val2014_000000111590.jpg -../coco/images/val2014/COCO_val2014_000000111593.jpg -../coco/images/val2014/COCO_val2014_000000111878.jpg -../coco/images/val2014/COCO_val2014_000000112298.jpg -../coco/images/val2014/COCO_val2014_000000112388.jpg -../coco/images/val2014/COCO_val2014_000000112394.jpg -../coco/images/val2014/COCO_val2014_000000112440.jpg -../coco/images/val2014/COCO_val2014_000000112751.jpg -../coco/images/val2014/COCO_val2014_000000112818.jpg -../coco/images/val2014/COCO_val2014_000000112820.jpg -../coco/images/val2014/COCO_val2014_000000112830.jpg -../coco/images/val2014/COCO_val2014_000000112928.jpg -../coco/images/val2014/COCO_val2014_000000113139.jpg -../coco/images/val2014/COCO_val2014_000000113173.jpg -../coco/images/val2014/COCO_val2014_000000113313.jpg -../coco/images/val2014/COCO_val2014_000000113440.jpg -../coco/images/val2014/COCO_val2014_000000113559.jpg -../coco/images/val2014/COCO_val2014_000000113570.jpg -../coco/images/val2014/COCO_val2014_000000113579.jpg -../coco/images/val2014/COCO_val2014_000000113590.jpg -../coco/images/val2014/COCO_val2014_000000113757.jpg -../coco/images/val2014/COCO_val2014_000000113977.jpg -../coco/images/val2014/COCO_val2014_000000114033.jpg -../coco/images/val2014/COCO_val2014_000000114055.jpg -../coco/images/val2014/COCO_val2014_000000114090.jpg -../coco/images/val2014/COCO_val2014_000000114147.jpg -../coco/images/val2014/COCO_val2014_000000114239.jpg -../coco/images/val2014/COCO_val2014_000000114503.jpg -../coco/images/val2014/COCO_val2014_000000114907.jpg -../coco/images/val2014/COCO_val2014_000000114926.jpg -../coco/images/val2014/COCO_val2014_000000115069.jpg -../coco/images/val2014/COCO_val2014_000000115070.jpg -../coco/images/val2014/COCO_val2014_000000115128.jpg -../coco/images/val2014/COCO_val2014_000000115870.jpg -../coco/images/val2014/COCO_val2014_000000115898.jpg -../coco/images/val2014/COCO_val2014_000000115930.jpg -../coco/images/val2014/COCO_val2014_000000116226.jpg -../coco/images/val2014/COCO_val2014_000000116556.jpg -../coco/images/val2014/COCO_val2014_000000116667.jpg -../coco/images/val2014/COCO_val2014_000000116696.jpg -../coco/images/val2014/COCO_val2014_000000116936.jpg -../coco/images/val2014/COCO_val2014_000000117014.jpg -../coco/images/val2014/COCO_val2014_000000117037.jpg -../coco/images/val2014/COCO_val2014_000000117125.jpg -../coco/images/val2014/COCO_val2014_000000117127.jpg -../coco/images/val2014/COCO_val2014_000000117191.jpg diff --git a/data/coco_1k5k.data b/data/coco_1k5k.data deleted file mode 100644 index a466df4ab2..0000000000 --- a/data/coco_1k5k.data +++ /dev/null @@ -1,6 +0,0 @@ -classes=80 -train=./data/coco_1000img.txt -valid=./data/5k.txt -names=data/coco.names -backup=backup/ -eval=coco From 0147b5036ebc19e2c90b134f5f18ff14ebff8ffe Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 7 Dec 2019 15:05:00 -0800 Subject: [PATCH 0057/1185] updates --- Dockerfile | 2 +- cfg/yolov3-spp-matrix.cfg | 1115 +++++++++++++++++++++++++++++++++++++ cfg/yolov3-spp3.cfg | 870 +++++++++++++++++++++++++++++ 3 files changed, 1986 insertions(+), 1 deletion(-) create mode 100644 cfg/yolov3-spp-matrix.cfg create mode 100644 cfg/yolov3-spp3.cfg diff --git a/Dockerfile b/Dockerfile index 4738ad58e0..84893a50dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -58,7 +58,7 @@ COPY . /usr/src/app # export t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t # Build and Push -# export t=ultralytics/yolov3:v0 && sudo docker build -t $t . && sudo docker push $t +# export t=ultralytics/yolov3:v112 && sudo docker build -t $t . && sudo docker push $t # Kill all # sudo docker kill "$(sudo docker ps -q)" diff --git a/cfg/yolov3-spp-matrix.cfg b/cfg/yolov3-spp-matrix.cfg new file mode 100644 index 0000000000..14befdba52 --- /dev/null +++ b/cfg/yolov3-spp-matrix.cfg @@ -0,0 +1,1115 @@ +[net] +# Testing +# batch=1 +# subdivisions=1 +# Training +batch=64 +subdivisions=16 +width=416 +height=416 +channels=3 +momentum=0.9 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.001 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=32 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +# Downsample + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +# Downsample + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +# Downsample + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +###################### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 + +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +# 89 +[yolo] +mask = 6,7,8 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 +classes=80 +num=27 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 61 + + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +# 101 +[yolo] +mask = 3,4,5 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 +classes=80 +num=27 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + + + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 36 + + + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +# 113 +[yolo] +mask = 0,1,2 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 +classes=80 +num=27 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + +################## + +[route] +layers = 110 + +# 115 +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +# 116 +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride_x=1 +stride_y=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 9,10,11 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 +classes=80 +num=27 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + + + +[route] +layers = 110 + +# 121 +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +# 122 +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride_x=2 +stride_y=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 12,13,14 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 +classes=80 +num=27 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + +################## + +[route] +layers = 98 + +[convolutional] +share_index=115 +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +share_index=116 +batch_normalize=1 +filters=128 +size=1 +stride_x=1 +stride_y=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 15,16,17 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 +classes=80 +num=27 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + + + +[route] +layers = 98 + +[convolutional] +share_index=121 +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +share_index=122 +batch_normalize=1 +filters=128 +size=1 +stride_x=2 +stride_y=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 18,19,20 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 +classes=80 +num=27 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + +################## + +[route] +layers = 86 + +[convolutional] +share_index=115 +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +share_index=116 +batch_normalize=1 +filters=128 +size=1 +stride_x=1 +stride_y=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 21,22,23 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 +classes=80 +num=27 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + + + +[route] +layers = 86 + +[convolutional] +share_index=121 +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +share_index=122 +batch_normalize=1 +filters=128 +size=1 +stride_x=2 +stride_y=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 24,25,26 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 +classes=80 +num=27 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 \ No newline at end of file diff --git a/cfg/yolov3-spp3.cfg b/cfg/yolov3-spp3.cfg new file mode 100644 index 0000000000..ea601054fd --- /dev/null +++ b/cfg/yolov3-spp3.cfg @@ -0,0 +1,870 @@ +[net] +# Testing +batch=1 +subdivisions=1 +# Training +# batch=64 +# subdivisions=16 +width=608 +height=608 +channels=3 +momentum=0.9 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.001 +burn_in=1000 +max_batches = 120200 +policy=steps +steps=70000,100000 +scales=.1,.1 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=32 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +# Downsample + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +# Downsample + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +# Downsample + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +###################### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 + +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 6,7,8 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 61 + + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 + +### End SPP ### + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 3,4,5 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + + + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 36 + + + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 + +### End SPP ### + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 0,1,2 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 From 6fd450c9047d495552e6e57bd1d30c49fd17d71f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 7 Dec 2019 15:06:38 -0800 Subject: [PATCH 0058/1185] updates --- Dockerfile | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index 84893a50dd..f53dc69236 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,23 +43,15 @@ COPY . /usr/src/app # --------------------------------------------------- Extras Below --------------------------------------------------- -# Build -# rm -rf yolov3 # Warning: remove existing -# git clone https://github.com/ultralytics/yolov3 && cd yolov3 && python3 detect.py -# sudo docker image prune -af && sudo docker build -t ultralytics/yolov3:v0 . +# Build and Push +# export t=ultralytics/yolov3:v0 && sudo docker build -t $t . && sudo docker push $t # Run # sudo nvidia-docker run --ipc=host ultralytics/yolov3:v0 python3 detect.py -# Run with local directory access -# sudo nvidia-docker run --ipc=host -it -v "$(pwd)"/coco:/usr/src/coco ultralytics/yolov3:v0 - # Pull and Run with local directory access # export t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t -# Build and Push -# export t=ultralytics/yolov3:v112 && sudo docker build -t $t . && sudo docker push $t - # Kill all # sudo docker kill "$(sudo docker ps -q)" From 1f943e886f1bd0a95764c30b941d812291824a63 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 7 Dec 2019 15:17:29 -0800 Subject: [PATCH 0059/1185] updates --- train.py | 1 - 1 file changed, 1 deletion(-) diff --git a/train.py b/train.py index e22789ee02..ef45c5dddf 100644 --- a/train.py +++ b/train.py @@ -114,7 +114,6 @@ def train(): try: chkpt['model'] = {k: v for k, v in chkpt['model'].items() if model.state_dict()[k].numel() == v.numel()} model.load_state_dict(chkpt['model'], strict=False) - # model.load_state_dict(chkpt['model']) except KeyError as e: s = "%s is not compatible with %s. Specify --weights '' or specify a --cfg compatible with %s. " \ "See https://github.com/ultralytics/yolov3/issues/657" % (opt.weights, opt.cfg, opt.weights) From b81beb0f5f0cf74c2ec8065ce9bde78c2c4e1841 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 7 Dec 2019 22:55:26 -0800 Subject: [PATCH 0060/1185] updates --- train.py | 1 + 1 file changed, 1 insertion(+) diff --git a/train.py b/train.py index ef45c5dddf..ff02e154c9 100644 --- a/train.py +++ b/train.py @@ -210,6 +210,7 @@ def train(): # Test Dataloader if not opt.prebias: testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, img_size, batch_size, hyp=hyp, + rect=True, cache_labels=True, cache_images=opt.cache_images), batch_size=batch_size, From f373764e4d4376e469f20dab527dd3444c0a5fa8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 12:26:31 -0800 Subject: [PATCH 0061/1185] updates --- utils/datasets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index c82abea4b6..3f1e17991d 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -677,8 +677,8 @@ def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, # xy = np.concatenate((x - w / 2, y - h / 2, x + w / 2, y + h / 2)).reshape(4, n).T # reject warped points outside of image - xy[:, [0, 2]] = xy[:, [0, 2]].clip(0, width) - xy[:, [1, 3]] = xy[:, [1, 3]].clip(0, height) + np.clip(xy[:, [0, 2]], 0, width, out=xy[:, [0, 2]]) + np.clip(xy[:, [1, 3]], 0, height, out=xy[:, [1, 3]]) w = xy[:, 2] - xy[:, 0] h = xy[:, 3] - xy[:, 1] area = w * h From 638ecbe894e4890473d0f1628c6f8d5179f96974 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 13:04:40 -0800 Subject: [PATCH 0062/1185] updates --- utils/datasets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 3f1e17991d..c82abea4b6 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -677,8 +677,8 @@ def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, # xy = np.concatenate((x - w / 2, y - h / 2, x + w / 2, y + h / 2)).reshape(4, n).T # reject warped points outside of image - np.clip(xy[:, [0, 2]], 0, width, out=xy[:, [0, 2]]) - np.clip(xy[:, [1, 3]], 0, height, out=xy[:, [1, 3]]) + xy[:, [0, 2]] = xy[:, [0, 2]].clip(0, width) + xy[:, [1, 3]] = xy[:, [1, 3]].clip(0, height) w = xy[:, 2] - xy[:, 0] h = xy[:, 3] - xy[:, 1] area = w * h From 01d9d551c3d623e36d2643c89fe804ab93b47bc4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 15:35:13 -0800 Subject: [PATCH 0063/1185] updates --- utils/datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/datasets.py b/utils/datasets.py index c82abea4b6..74967b74bc 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -683,7 +683,7 @@ def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, h = xy[:, 3] - xy[:, 1] area = w * h area0 = (targets[:, 3] - targets[:, 1]) * (targets[:, 4] - targets[:, 2]) - ar = np.maximum(w / (h + 1e-16), h / (w + 1e-16)) + ar = np.maximum(w / (h + 1e-16), h / (w + 1e-16)) # aspect ratio i = (w > 4) & (h > 4) & (area / (area0 + 1e-16) > 0.1) & (ar < 10) targets = targets[i] From b81c17aa9f1cd901c5be923bff68893bb5a9be3c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 16:02:55 -0800 Subject: [PATCH 0064/1185] updates --- utils/utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index a289ea55b0..c33ccc70ae 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -427,12 +427,11 @@ def build_targets(model, targets): a = torch.arange(na).view((-1, 1)).repeat([1, nt]).view(-1) t = targets.repeat([na, 1]) gwh = gwh.repeat([na, 1]) - iou = iou.view(-1) # use all ious # reject anchors below iou_thres (OPTIONAL, increases P, lowers R) reject = True if reject: - j = iou > model.hyp['iou_t'] # iou threshold hyperparameter + j = iou.view(-1) > model.hyp['iou_t'] # iou threshold hyperparameter t, a, gwh = t[j], a[j], gwh[j] # Indices From 29e60e50e556c0d3565a95b9df051c6feceb3be9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 16:16:16 -0800 Subject: [PATCH 0065/1185] updates --- models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/models.py b/models.py index 330f4621dd..528ede9816 100755 --- a/models.py +++ b/models.py @@ -167,7 +167,9 @@ def forward(self, p, img_size, var=None): create_grids(self, img_size, (nx, ny), p.device, p.dtype) # p.view(bs, 255, 13, 13) -- > (bs, 3, 13, 13, 85) # (bs, anchors, grid, grid, classes + xywh) - p = p.view(bs, self.na, self.nc + 5, self.ny, self.nx).permute(0, 1, 3, 4, 2).contiguous() # prediction + # p = p.view(bs, self.na, self.nc + 5, self.ny, self.nx).permute(0, 1, 3, 4, 2).contiguous() # prediction + # https://discuss.pytorch.org/t/in-pytorch-0-4-is-it-recommended-to-use-reshape-than-view-when-it-is-possible/17034 + p = p.reshape(bs, self.na, self.nc + 5, self.ny, self.nx).permute(0, 1, 3, 4, 2) # prediction if self.training: return p From ea2076a6d272bc1b7597b737d37449b7b46a6a9c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 16:20:27 -0800 Subject: [PATCH 0066/1185] updates --- utils/gcp.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index fad46c543f..f39d3a646c 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -3,9 +3,8 @@ # New VM rm -rf sample_data yolov3 darknet apex coco cocoapi knife knifec git clone https://github.com/ultralytics/yolov3 -# git clone https://github.com/AlexeyAB/darknet && cd darknet && make GPU=1 CUDNN=1 CUDNN_HALF=1 OPENCV=0 && wget -c https://pjreddie.com/media/files/darknet53.conv.74 && cd .. git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex -sudo conda install -y -c conda-forge scikit-image pycocotools # tensorboard +conda install -yc conda-forge scikit-image pycocotools python3 -c " from yolov3.utils.google_utils import gdrive_download gdrive_download('1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO','coco.zip')" From 3953d5c8b0a1b2bdd64599ea06c50a7ebf259508 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 16:21:57 -0800 Subject: [PATCH 0067/1185] updates --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0c1c92560f..a6d8b92eb7 100755 --- a/requirements.txt +++ b/requirements.txt @@ -13,7 +13,7 @@ Pillow # Equivalent conda commands ---------------------------------------------------- # conda update -n base -c defaults conda -# conda install -yc anaconda numpy opencv matplotlib tqdm pillow future +# conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython future # conda install -yc conda-forge scikit-image pycocotools onnx tensorboard # conda install -yc spyder-ide spyder-line-profiler # conda install -yc pytorch pytorch torchvision From 0fa4e498c1749d7b599672679d993d51355964dd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 16:34:01 -0800 Subject: [PATCH 0068/1185] updates --- train.py | 4 ++-- utils/gcp.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/train.py b/train.py index ff02e154c9..4f96e291a0 100644 --- a/train.py +++ b/train.py @@ -417,10 +417,10 @@ def prebias(): if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--epochs', type=int, default=273) # 500200 batches at bs 16, 117263 images = 273 epochs - parser.add_argument('--batch-size', type=int, default=16) # effective bs = batch_size * accumulate = 16 * 4 = 64 + parser.add_argument('--batch-size', type=int, default=1) # effective bs = batch_size * accumulate = 16 * 4 = 64 parser.add_argument('--accumulate', type=int, default=4, help='batches to accumulate before optimizing') parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='cfg file path') - parser.add_argument('--data', type=str, default='data/coco.data', help='*.data file path') + parser.add_argument('--data', type=str, default='data/coco_64img.data', help='*.data file path') parser.add_argument('--multi-scale', action='store_true', help='adjust (67% - 150%) img_size every 10 batches') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') parser.add_argument('--rect', action='store_true', help='rectangular training') diff --git a/utils/gcp.sh b/utils/gcp.sh index f39d3a646c..c898ab60f5 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -4,10 +4,10 @@ rm -rf sample_data yolov3 darknet apex coco cocoapi knife knifec git clone https://github.com/ultralytics/yolov3 git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex -conda install -yc conda-forge scikit-image pycocotools +sudo conda install -yc conda-forge scikit-image pycocotools python3 -c " from yolov3.utils.google_utils import gdrive_download -gdrive_download('1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO','coco.zip')" +gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco.zip')" sudo shutdown # Re-clone From 267367b10514e3c7fd2e932abe2d187e6ae42380 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 16:34:27 -0800 Subject: [PATCH 0069/1185] updates --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 4f96e291a0..ff02e154c9 100644 --- a/train.py +++ b/train.py @@ -417,10 +417,10 @@ def prebias(): if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--epochs', type=int, default=273) # 500200 batches at bs 16, 117263 images = 273 epochs - parser.add_argument('--batch-size', type=int, default=1) # effective bs = batch_size * accumulate = 16 * 4 = 64 + parser.add_argument('--batch-size', type=int, default=16) # effective bs = batch_size * accumulate = 16 * 4 = 64 parser.add_argument('--accumulate', type=int, default=4, help='batches to accumulate before optimizing') parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='cfg file path') - parser.add_argument('--data', type=str, default='data/coco_64img.data', help='*.data file path') + parser.add_argument('--data', type=str, default='data/coco.data', help='*.data file path') parser.add_argument('--multi-scale', action='store_true', help='adjust (67% - 150%) img_size every 10 batches') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') parser.add_argument('--rect', action='store_true', help='rectangular training') From b759356d2f8db9ad7f5cb38f5df2af20a770d7d1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 16:36:52 -0800 Subject: [PATCH 0070/1185] updates --- utils/gcp.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index c898ab60f5..cd840a3519 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # New VM -rm -rf sample_data yolov3 darknet apex coco cocoapi knife knifec +rm -rf sample_data yolov3 git clone https://github.com/ultralytics/yolov3 git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex sudo conda install -yc conda-forge scikit-image pycocotools From 50866ddaa991433efcf3a6c10944e85e22f6638f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 16:44:33 -0800 Subject: [PATCH 0071/1185] updates --- utils/gcp.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index cd840a3519..d382dff055 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -5,10 +5,8 @@ rm -rf sample_data yolov3 git clone https://github.com/ultralytics/yolov3 git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex sudo conda install -yc conda-forge scikit-image pycocotools -python3 -c " -from yolov3.utils.google_utils import gdrive_download -gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco.zip')" -sudo shutdown +python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco.zip')" +sudo reboot # Re-clone rm -rf yolov3 # Warning: remove existing From b913d1ab55921127824efe3020bdcb878a5cea3b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 17:00:13 -0800 Subject: [PATCH 0072/1185] updates --- utils/datasets.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 74967b74bc..18e25a157b 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -101,8 +101,8 @@ def __next__(self): # Padded resize img = letterbox(img0, new_shape=self.img_size)[0] - # Normalize RGB - img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB + # Convert + img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 img = np.ascontiguousarray(img, dtype=np.float16 if self.half else np.float32) # uint8 to fp16/fp32 img /= 255.0 # 0 - 255 to 0.0 - 1.0 @@ -174,8 +174,8 @@ def __next__(self): # Padded resize img = letterbox(img0, new_shape=self.img_size)[0] - # Normalize RGB - img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB + # Convert + img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 img = np.ascontiguousarray(img, dtype=np.float16 if self.half else np.float32) # uint8 to fp16/fp32 img /= 255.0 # 0 - 255 to 0.0 - 1.0 @@ -243,9 +243,9 @@ def __next__(self): # Stack img = np.stack(img, 0) - # Normalize RGB - img = img[:, :, :, ::-1].transpose(0, 3, 1, 2) # BGR to RGB - img = np.ascontiguousarray(img, dtype=np.float16 if self.half else np.float32) # uint8 to fp16/fp32 + # Convert + img = img[:, :, :, ::-1].transpose(0, 3, 1, 2) # BGR to RGB, to 3x416x416, uint8 to float32 + img = np.ascontiguousarray(img, dtype=np.float16 if self.half else np.float32) img /= 255.0 # 0 - 255 to 0.0 - 1.0 return self.sources, img, img0, None @@ -485,7 +485,7 @@ def __getitem__(self, index): if nL: labels_out[:, 1:] = torch.from_numpy(labels) - # Normalize + # Convert img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 img = np.ascontiguousarray(img, dtype=np.float32) # uint8 to float32 img /= 255.0 # 0 - 255 to 0.0 - 1.0 From 4942aacef963515797bee84df89ae4b54f75e903 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 17:19:42 -0800 Subject: [PATCH 0073/1185] updates --- utils/utils.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index c33ccc70ae..bfba712c08 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -406,6 +406,7 @@ def build_targets(model, targets): nt = len(targets) tcls, tbox, indices, av = [], [], [], [] multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) + reject, use_all_anchors = True, True for i in model.yolo_layers: # get number of grid points and anchor vec for this yolo layer if multi_gpu: @@ -419,17 +420,15 @@ def build_targets(model, targets): if nt: iou = torch.stack([wh_iou(x, gwh) for x in anchor_vec], 0) - use_best_anchor = False - if use_best_anchor: - iou, a = iou.max(0) # best iou and anchor - else: # use all anchors + if use_all_anchors: na = len(anchor_vec) # number of anchors a = torch.arange(na).view((-1, 1)).repeat([1, nt]).view(-1) t = targets.repeat([na, 1]) gwh = gwh.repeat([na, 1]) + else: # use best anchor only + iou, a = iou.max(0) # best iou and anchor # reject anchors below iou_thres (OPTIONAL, increases P, lowers R) - reject = True if reject: j = iou.view(-1) > model.hyp['iou_t'] # iou threshold hyperparameter t, a, gwh = t[j], a[j], gwh[j] From e35397ee41c085eecaf75e286005982ba6ef4884 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 17:52:44 -0800 Subject: [PATCH 0074/1185] updates --- README.md | 2 +- test.py | 2 +- train.py | 2 +- utils/datasets.py | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9f1fd365a4..66ba387af0 100755 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ GPUs | `batch_size` | images/sec | epoch time | epoch cost K80 | 64 (32x2) | 11 | 175 min | $0.58 T4 | 64 (32x2) | 40 | 49 min | $0.29 T4 x2 | 64 (64x1) | 61 | 32 min | $0.36 -V100 | 64 (32x2) | 115 | 17 min | $0.24 +V100 | 64 (32x2) | 122 | 16 min | $0.23 V100 x2 | 64 (64x1) | 150 | 13 min | $0.36 2080Ti | 64 (32x2) | 81 | 24 min | - 2080Ti x2 | 64 (64x1) | 140 | 14 min | - diff --git a/test.py b/test.py index 9ffa82e280..f1145f306c 100644 --- a/test.py +++ b/test.py @@ -64,8 +64,8 @@ def test(cfg, loss = torch.zeros(3) jdict, stats, ap, ap_class = [], [], [], [] for batch_i, (imgs, targets, paths, shapes) in enumerate(tqdm(dataloader, desc=s)): + imgs = imgs.to(device).float() / 255.0 # uint8 to float32, 0 - 255 to 0.0 - 1.0 targets = targets.to(device) - imgs = imgs.to(device) _, _, height, width = imgs.shape # batch size, channels, height, width # Plot images with bounding boxes diff --git a/train.py b/train.py index ff02e154c9..0c4b56bc15 100644 --- a/train.py +++ b/train.py @@ -251,7 +251,7 @@ def train(): pbar = tqdm(enumerate(dataloader), total=nb) # progress bar for i, (imgs, targets, paths, _) in pbar: # batch ------------------------------------------------------------- ni = i + nb * epoch # number integrated batches (since train start) - imgs = imgs.to(device) + imgs = imgs.to(device).float() / 255.0 # uint8 to float32, 0 - 255 to 0.0 - 1.0 targets = targets.to(device) # Multi-Scale training diff --git a/utils/datasets.py b/utils/datasets.py index 18e25a157b..e5daa630a7 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -487,8 +487,7 @@ def __getitem__(self, index): # Convert img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 - img = np.ascontiguousarray(img, dtype=np.float32) # uint8 to float32 - img /= 255.0 # 0 - 255 to 0.0 - 1.0 + img = np.ascontiguousarray(img) return torch.from_numpy(img), labels_out, img_path, ((h, w), (ratio, pad)) From 61c3cb9ecf0f6ba17cb2473fb84804a0779ee0b4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 17:57:23 -0800 Subject: [PATCH 0075/1185] updates --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 0c4b56bc15..ef991e2eea 100644 --- a/train.py +++ b/train.py @@ -199,7 +199,6 @@ def train(): # Dataloader batch_size = min(batch_size, len(dataset)) nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8]) # number of workers - print('Using %g dataloader workers' % nw) dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, num_workers=nw, @@ -224,11 +223,12 @@ def train(): model.arc = opt.arc # attach yolo architecture model.hyp = hyp # attach hyperparameters to model model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) # attach class weights - torch_utils.model_info(model, report='summary') # 'full' or 'summary' maps = np.zeros(nc) # mAP per class # torch.autograd.set_detect_anomaly(True) results = (0, 0, 0, 0, 0, 0, 0) # 'P', 'R', 'mAP', 'F1', 'val GIoU', 'val Objectness', 'val Classification' t0 = time.time() + torch_utils.model_info(model, report='summary') # 'full' or 'summary' + print('Using %g dataloader workers' % nw) print('Starting %s for %g epochs...' % ('prebias' if opt.prebias else 'training', epochs)) for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ model.train() From d603ac8e694a3d7f1d8c777a47c5f049917e4b7e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 18:08:19 -0800 Subject: [PATCH 0076/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 528ede9816..cf95a95985 100755 --- a/models.py +++ b/models.py @@ -162,7 +162,7 @@ def forward(self, p, img_size, var=None): if ONNX_EXPORT: bs = 1 # batch size else: - bs, ny, nx = p.shape[0], p.shape[-2], p.shape[-1] + bs, _, ny, nx = p.shape # bs, 255, 13, 13 if (self.nx, self.ny) != (nx, ny): create_grids(self, img_size, (nx, ny), p.device, p.dtype) From ca5da3dfe08244fc26712e14d3e4771c97ddf192 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 18:30:10 -0800 Subject: [PATCH 0077/1185] updates --- models.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/models.py b/models.py index cf95a95985..8a3460daab 100755 --- a/models.py +++ b/models.py @@ -167,9 +167,7 @@ def forward(self, p, img_size, var=None): create_grids(self, img_size, (nx, ny), p.device, p.dtype) # p.view(bs, 255, 13, 13) -- > (bs, 3, 13, 13, 85) # (bs, anchors, grid, grid, classes + xywh) - # p = p.view(bs, self.na, self.nc + 5, self.ny, self.nx).permute(0, 1, 3, 4, 2).contiguous() # prediction - # https://discuss.pytorch.org/t/in-pytorch-0-4-is-it-recommended-to-use-reshape-than-view-when-it-is-possible/17034 - p = p.reshape(bs, self.na, self.nc + 5, self.ny, self.nx).permute(0, 1, 3, 4, 2) # prediction + p = p.view(bs, self.na, self.nc + 5, self.ny, self.nx).permute(0, 1, 3, 4, 2).contiguous() # prediction if self.training: return p From 35177c0e47f18cfaa6841266d15bd422a83331ca Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 18:30:36 -0800 Subject: [PATCH 0078/1185] updates --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 66ba387af0..301fef52d4 100755 --- a/README.md +++ b/README.md @@ -74,12 +74,13 @@ HS**V** Intensity | +/- 50% ## Speed https://cloud.google.com/deep-learning-vm/ -**Machine type:** n1-standard-8 (8 vCPUs, 30 GB memory) +**Machine type:** [n1-standard-16](https://cloud.google.com/compute/docs/machine-types) (16 vCPUs, 60 GB memory) **CPU platform:** Intel Skylake **GPUs:** K80 ($0.20/hr), T4 ($0.35/hr), V100 ($0.83/hr) CUDA with [Nvidia Apex](https://github.com/NVIDIA/apex) FP16/32 -**HDD:** 100 GB SSD +**HDD:** 1 TB SSD **Dataset:** COCO train 2014 (117,263 images) -**Model:** `yolov3-spp.cfg` +**Model:** `yolov3-spp.cfg` +**Command:** `python3 train.py --img 416 --batch 32 --accum 2` GPUs | `batch_size` | images/sec | epoch time | epoch cost --- |---| --- | --- | --- @@ -87,7 +88,7 @@ K80 | 64 (32x2) | 11 | 175 min | $0.58 T4 | 64 (32x2) | 40 | 49 min | $0.29 T4 x2 | 64 (64x1) | 61 | 32 min | $0.36 V100 | 64 (32x2) | 122 | 16 min | $0.23 -V100 x2 | 64 (64x1) | 150 | 13 min | $0.36 +V100 x2 | 64 (64x1) | 178 | 11 min | $0.31 2080Ti | 64 (32x2) | 81 | 24 min | - 2080Ti x2 | 64 (64x1) | 140 | 14 min | - From 194b39618760acd4b669275c677280e7a986ef54 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 19:22:33 -0800 Subject: [PATCH 0079/1185] updates --- README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 301fef52d4..959a5a6180 100755 --- a/README.md +++ b/README.md @@ -82,15 +82,12 @@ https://cloud.google.com/deep-learning-vm/ **Model:** `yolov3-spp.cfg` **Command:** `python3 train.py --img 416 --batch 32 --accum 2` -GPUs | `batch_size` | images/sec | epoch time | epoch cost ---- |---| --- | --- | --- -K80 | 64 (32x2) | 11 | 175 min | $0.58 -T4 | 64 (32x2) | 40 | 49 min | $0.29 -T4 x2 | 64 (64x1) | 61 | 32 min | $0.36 -V100 | 64 (32x2) | 122 | 16 min | $0.23 -V100 x2 | 64 (64x1) | 178 | 11 min | $0.31 -2080Ti | 64 (32x2) | 81 | 24 min | - -2080Ti x2 | 64 (64x1) | 140 | 14 min | - +GPU |n| `--batch --accum` | img/s | epoch
time | epoch
cost +--- |--- |--- |--- |--- |--- +K80 |1| 32 x 2 | 11 | 175 min | $0.58 +T4 |1
2| 32 x 2
64 x 1 | 41
61 | 48 min
32 min | $0.28
$0.36 +V100 |1
2| 32 x 2
64 x 1 | 122
**178** | 16 min
**11 min** | **$0.23**
$0.31 +2080Ti |1
2| 32 x 2
64 x 1 | 81
140 | 24 min
14 min | -
- # Inference From 1bf717ef9cf325828bd95efba01dabbe90f3d7eb Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 19:26:03 -0800 Subject: [PATCH 0080/1185] updates --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 959a5a6180..e532d6b163 100755 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ HS**V** Intensity | +/- 50% ## Speed https://cloud.google.com/deep-learning-vm/ -**Machine type:** [n1-standard-16](https://cloud.google.com/compute/docs/machine-types) (16 vCPUs, 60 GB memory) +**Machine type:** preemptible [n1-standard-16](https://cloud.google.com/compute/docs/machine-types) (16 vCPUs, 60 GB memory) **CPU platform:** Intel Skylake **GPUs:** K80 ($0.20/hr), T4 ($0.35/hr), V100 ($0.83/hr) CUDA with [Nvidia Apex](https://github.com/NVIDIA/apex) FP16/32 **HDD:** 1 TB SSD From 37fa9afaff4be124aa573f5d30d316ea783a5aab Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 19:58:10 -0800 Subject: [PATCH 0081/1185] updates --- utils/torch_utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index ecbcd3063f..d984dfca48 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -101,6 +101,7 @@ def load_classifier(name='resnet101', n=2): from collections import defaultdict from torch.optim import Optimizer + class Lookahead(Optimizer): def __init__(self, optimizer, k=5, alpha=0.5): self.optimizer = optimizer @@ -165,4 +166,4 @@ def load_state_dict(self, state_dict): def add_param_group(self, param_group): param_group["counter"] = 0 - self.optimizer.add_param_group(param_group) \ No newline at end of file + self.optimizer.add_param_group(param_group) From 2300cb964a343458d0727b81aea5500f2b03a899 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 19:58:42 -0800 Subject: [PATCH 0082/1185] updates --- utils/datasets.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index e5daa630a7..cf43d655b5 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -578,10 +578,10 @@ def load_mosaic(self, index): # Augment # img4 = img4[s // 2: int(s * 1.5), s // 2:int(s * 1.5)] # center crop (WARNING, requires box pruning) img4, labels4 = random_affine(img4, labels4, - degrees=self.hyp['degrees'], - translate=self.hyp['translate'], - scale=self.hyp['scale'], - shear=self.hyp['shear'], + degrees=self.hyp['degrees'] * 0, + translate=self.hyp['translate'] * 0, + scale=self.hyp['scale'] * 0, + shear=self.hyp['shear'] * 0, border=-s // 2) # border to remove return img4, labels4 From 239199647456db6b5bcf6b40530161341b18ad88 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Dec 2019 20:15:25 -0800 Subject: [PATCH 0083/1185] updates --- utils/utils.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index bfba712c08..49791a0d3e 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -334,10 +334,11 @@ def compute_loss(p, targets, model): # predictions, targets, model tcls, tbox, indices, anchor_vec = build_targets(model, targets) h = model.hyp # hyperparameters arc = model.arc # # (default, uCE, uBCE) detection architectures + red = 'mean' # Loss reduction (sum or mean) # Define criteria - BCEcls = nn.BCEWithLogitsLoss(pos_weight=ft([h['cls_pw']])) - BCEobj = nn.BCEWithLogitsLoss(pos_weight=ft([h['obj_pw']])) + BCEcls = nn.BCEWithLogitsLoss(pos_weight=ft([h['cls_pw']]), reduction=red) + BCEobj = nn.BCEWithLogitsLoss(pos_weight=ft([h['obj_pw']]), reduction=red) BCE = nn.BCEWithLogitsLoss() CE = nn.CrossEntropyLoss() # weight=model.class_weights @@ -346,13 +347,16 @@ def compute_loss(p, targets, model): # predictions, targets, model BCEcls, BCEobj, BCE, CE = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g), FocalLoss(BCE, g), FocalLoss(CE, g) # Compute losses + np, ng = 0, 0 # number grid points, targets for i, pi in enumerate(p): # layer index, layer predictions b, a, gj, gi = indices[i] # image, anchor, gridy, gridx tobj = torch.zeros_like(pi[..., 0]) # target obj + np += tobj.numel() # Compute losses nb = len(b) if nb: # number of targets + ng += nb ps = pi[b, a, gj, gi] # prediction subset corresponding to targets tobj[b, a, gj, gi] = 1.0 # obj # ps[:, 2:4] = torch.sigmoid(ps[:, 2:4]) # wh power loss (uncomment) @@ -360,8 +364,8 @@ def compute_loss(p, targets, model): # predictions, targets, model # GIoU pxy = torch.sigmoid(ps[:, 0:2]) # pxy = pxy * s - (s - 1) / 2, s = 1.5 (scale_xy) pbox = torch.cat((pxy, torch.exp(ps[:, 2:4]).clamp(max=1E3) * anchor_vec[i]), 1) # predicted box - giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation - lbox += (1.0 - giou).mean() # giou loss + giou = 1.0 - bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation + lbox += giou.sum() if red == 'sum' else giou.mean() # giou loss if 'default' in arc and model.nc > 1: # cls loss (only if multiple classes) t = torch.zeros_like(ps[:, 5:]) # targets @@ -396,6 +400,11 @@ def compute_loss(p, targets, model): # predictions, targets, model lbox *= h['giou'] lobj *= h['obj'] lcls *= h['cls'] + if red == 'sum': + lbox *= 3 / ng + lobj *= 3 / np + lcls *= 3 / ng / model.nc + loss = lbox + lobj + lcls return loss, torch.cat((lbox, lobj, lcls, loss)).detach() From 07c1fafba832ef83fca70576e04cef48686f72a1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Dec 2019 13:17:30 -0800 Subject: [PATCH 0084/1185] updates --- models.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/models.py b/models.py index 8a3460daab..066fe0ca06 100755 --- a/models.py +++ b/models.py @@ -22,12 +22,12 @@ def create_modules(module_defs, img_size, arc): if mdef['type'] == 'convolutional': bn = int(mdef['batch_normalize']) filters = int(mdef['filters']) - kernel_size = int(mdef['size']) + size = int(mdef['size']) stride = int(mdef['stride']) if 'stride' in mdef else (int(mdef['stride_y']), int(mdef['stride_x'])) - pad = (kernel_size - 1) // 2 if int(mdef['pad']) else 0 + pad = (size - 1) // 2 if int(mdef['pad']) else 0 modules.add_module('Conv2d', nn.Conv2d(in_channels=output_filters[-1], out_channels=filters, - kernel_size=kernel_size, + kernel_size=size, stride=stride, padding=pad, bias=not bn)) @@ -40,10 +40,10 @@ def create_modules(module_defs, img_size, arc): modules.add_module('activation', Swish()) elif mdef['type'] == 'maxpool': - kernel_size = int(mdef['size']) + size = int(mdef['size']) stride = int(mdef['stride']) - maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=int((kernel_size - 1) // 2)) - if kernel_size == 2 and stride == 1: # yolov3-tiny + maxpool = nn.MaxPool2d(kernel_size=size, stride=stride, padding=int((size - 1) // 2)) + if size == 2 and stride == 1: # yolov3-tiny modules.add_module('ZeroPad2d', nn.ZeroPad2d((0, 1, 0, 1))) modules.add_module('MaxPool2d', maxpool) else: From 3bfbab7afd5850b4f21b73dd3184374f47eb1d98 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Dec 2019 13:25:34 -0800 Subject: [PATCH 0085/1185] updates --- models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/models.py b/models.py index 066fe0ca06..bff616e00f 100755 --- a/models.py +++ b/models.py @@ -30,6 +30,7 @@ def create_modules(module_defs, img_size, arc): kernel_size=size, stride=stride, padding=pad, + groups=int(mdef['groups']) if 'groups' in mdef else 1, bias=not bn)) if bn: modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.1)) From a6980a0f1491f9c1019f5095c6551d3f083f71f9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Dec 2019 13:37:58 -0800 Subject: [PATCH 0086/1185] updates --- utils/parse_config.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/utils/parse_config.py b/utils/parse_config.py index 23581a51d2..1c2dbbcdc5 100644 --- a/utils/parse_config.py +++ b/utils/parse_config.py @@ -23,6 +23,12 @@ def parse_model_cfg(path): else: mdefs[-1][key] = val.strip() + # Print cfg fields + # f = [] + # for x in mdefs[1:]: + # [f.append(k) for k in x if k not in f] + # print(len(f), f) + return mdefs From 8c5ebdf05546857a91870ac69f70d44c92b614a5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Dec 2019 13:39:35 -0800 Subject: [PATCH 0087/1185] updates --- cfg/csresnext50-panet-spp.cfg | 1018 +++++++++++++++++++++++++++++++++ 1 file changed, 1018 insertions(+) create mode 100644 cfg/csresnext50-panet-spp.cfg diff --git a/cfg/csresnext50-panet-spp.cfg b/cfg/csresnext50-panet-spp.cfg new file mode 100644 index 0000000000..ece11221e4 --- /dev/null +++ b/cfg/csresnext50-panet-spp.cfg @@ -0,0 +1,1018 @@ +[net] +# Testing +#batch=1 +#subdivisions=1 +# Training +batch=64 +subdivisions=16 +width=416 +height=416 +channels=3 +momentum=0.9 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.001 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +#19:104x104 38:52x52 65:26x26 80:13x13 for 416 + +[convolutional] +batch_normalize=1 +filters=64 +size=7 +stride=2 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +# 1-1 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +groups=32 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=linear + +[shortcut] +from=-4 +activation=leaky + +# 1-2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +groups=32 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=linear + +[shortcut] +from=-4 +activation=leaky + +# 1-3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +groups=32 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=linear + +[shortcut] +from=-4 +activation=leaky + +# 1-T + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-16 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +groups=32 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=linear + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=linear + +# 2-1 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +groups=32 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=linear + +[shortcut] +from=-4 +activation=leaky + +# 2-2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +groups=32 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=linear + +[shortcut] +from=-4 +activation=leaky + +# 2-3 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +groups=32 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=linear + +[shortcut] +from=-4 +activation=leaky + +# 2-T + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-16 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +groups=32 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=linear + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=linear + +# 3-1 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +groups=32 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=linear + +[shortcut] +from=-4 +activation=leaky + +# 3-2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +groups=32 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=linear + +[shortcut] +from=-4 +activation=leaky + +# 3-3 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +groups=32 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=linear + +[shortcut] +from=-4 +activation=leaky + +# 3-4 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +groups=32 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=linear + +[shortcut] +from=-4 +activation=leaky + +# 3-5 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +groups=32 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=linear + +[shortcut] +from=-4 +activation=leaky + +# 3-T + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-24 + +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +groups=32 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=leaky + +# 4-1 + +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +groups=32 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=linear + +[shortcut] +from=-4 +activation=leaky + +# 4-2 + +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +groups=32 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=linear + +[shortcut] +from=-4 +activation=leaky + +# 4-T + +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-12 + +[convolutional] +batch_normalize=1 +filters=2048 +size=1 +stride=1 +pad=1 +activation=leaky + +########################## + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = 65 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = 38 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +########################## + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 0,1,2 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=256 +activation=leaky + +[route] +layers = -1, -16 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 3,4,5 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=512 +activation=leaky + +[route] +layers = -1, -37 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 6,7,8 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 From f430ddb103ae55e616292b7e157f97d2277cc922 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Dec 2019 13:49:50 -0800 Subject: [PATCH 0088/1185] updates --- utils/parse_config.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/utils/parse_config.py b/utils/parse_config.py index 1c2dbbcdc5..962aa07b68 100644 --- a/utils/parse_config.py +++ b/utils/parse_config.py @@ -23,11 +23,18 @@ def parse_model_cfg(path): else: mdefs[-1][key] = val.strip() - # Print cfg fields - # f = [] - # for x in mdefs[1:]: - # [f.append(k) for k in x if k not in f] + # Check all fields are supported + supported = ['type', 'batch_normalize', 'filters', 'size', 'stride', 'pad', 'activation', 'layers', 'groups', + 'from', 'mask', 'anchors', 'classes', 'num', 'jitter', 'ignore_thresh', 'truth_thresh', 'random', + 'stride_x', 'stride_y'] + + f = [] + for x in mdefs[1:]: + [f.append(k) for k in x if k not in f] # print(len(f), f) + for x in f: + assert x in supported, "Unsupported field '%s' in %s. See https://github.com/ultralytics/yolov3/issues/631" % \ + (x, path) return mdefs From 86588f15796a47faa2deb572da0bc62d15fe6c9c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Dec 2019 14:20:36 -0800 Subject: [PATCH 0089/1185] updates --- cfg/csresnext50-panet-spp.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cfg/csresnext50-panet-spp.cfg b/cfg/csresnext50-panet-spp.cfg index ece11221e4..4cff3c37c6 100644 --- a/cfg/csresnext50-panet-spp.cfg +++ b/cfg/csresnext50-panet-spp.cfg @@ -76,7 +76,7 @@ activation=leaky [convolutional] batch_normalize=1 -filters=128 +filters=64 size=1 stride=1 pad=1 @@ -107,7 +107,7 @@ activation=leaky [convolutional] batch_normalize=1 -filters=128 +filters=64 size=1 stride=1 pad=1 @@ -138,7 +138,7 @@ activation=leaky [convolutional] batch_normalize=1 -filters=128 +filters=64 size=1 stride=1 pad=1 From 2201cb40231b5f6c2847b20223b04b241a7a74ec Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Dec 2019 15:54:46 -0800 Subject: [PATCH 0090/1185] updates --- utils/parse_config.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/utils/parse_config.py b/utils/parse_config.py index 962aa07b68..36f943bfd6 100644 --- a/utils/parse_config.py +++ b/utils/parse_config.py @@ -28,13 +28,11 @@ def parse_model_cfg(path): 'from', 'mask', 'anchors', 'classes', 'num', 'jitter', 'ignore_thresh', 'truth_thresh', 'random', 'stride_x', 'stride_y'] - f = [] + f = [] # fields for x in mdefs[1:]: [f.append(k) for k in x if k not in f] - # print(len(f), f) - for x in f: - assert x in supported, "Unsupported field '%s' in %s. See https://github.com/ultralytics/yolov3/issues/631" % \ - (x, path) + u = [x for x in f if x not in supported] # unsupported fields + assert not any(u), "Unsupported fields %s in %s. See https://github.com/ultralytics/yolov3/issues/631" % (u, path) return mdefs From bb1a87d77f2c366b30b72202686276d1c4c522de Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 10 Dec 2019 18:04:24 -0800 Subject: [PATCH 0091/1185] updates --- utils/parse_config.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/utils/parse_config.py b/utils/parse_config.py index 36f943bfd6..8ecf644147 100644 --- a/utils/parse_config.py +++ b/utils/parse_config.py @@ -1,10 +1,17 @@ +import os + import numpy as np def parse_model_cfg(path): - # Parses the yolo-v3 layer configuration file and returns module definitions - file = open(path, 'r') - lines = file.read().split('\n') + # Parse the yolo *.cfg file and return module definitions path may be 'cfg/yolov3.cfg', 'yolov3.cfg', or 'yolov3' + if not path.endswith('.cfg'): # add .cfg suffix if omitted + path += '.cfg' + if not os.path.exists(path) and not path.startswith('cfg' + os.sep): # add cfg/ prefix if omitted + path = 'cfg' + os.sep + path + + with open(path, 'r') as f: + lines = f.read().split('\n') lines = [x for x in lines if x and not x.startswith('#')] lines = [x.rstrip().lstrip() for x in lines] # get rid of fringe whitespaces mdefs = [] # module definitions From 9f24c12c14c137873df4b31b9d5f6b5856d40604 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 10 Dec 2019 18:25:14 -0800 Subject: [PATCH 0092/1185] updates --- utils/parse_config.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/utils/parse_config.py b/utils/parse_config.py index 8ecf644147..5d3c20fb52 100644 --- a/utils/parse_config.py +++ b/utils/parse_config.py @@ -7,7 +7,7 @@ def parse_model_cfg(path): # Parse the yolo *.cfg file and return module definitions path may be 'cfg/yolov3.cfg', 'yolov3.cfg', or 'yolov3' if not path.endswith('.cfg'): # add .cfg suffix if omitted path += '.cfg' - if not os.path.exists(path) and not path.startswith('cfg' + os.sep): # add cfg/ prefix if omitted + if not os.path.exists(path) and os.path.exists('cfg' + os.sep + path): # add cfg/ prefix if omitted path = 'cfg' + os.sep + path with open(path, 'r') as f: @@ -46,10 +46,13 @@ def parse_model_cfg(path): def parse_data_cfg(path): # Parses the data configuration file - options = dict() - with open(path, 'r') as fp: - lines = fp.readlines() + if not os.path.exists(path) and os.path.exists('data' + os.sep + path): # add data/ prefix if omitted + path = 'data' + os.sep + path + + with open(path, 'r') as f: + lines = f.readlines() + options = dict() for line in lines: line = line.strip() if line == '' or line.startswith('#'): From a6f87a28e7595e71752583fb41340f9d1105d75f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 10 Dec 2019 20:02:58 -0800 Subject: [PATCH 0093/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 49791a0d3e..ab3795d56f 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -970,7 +970,7 @@ def plot_results(start=0, stop=0): # from utils.utils import *; plot_results() y = results[i, x] if i in [0, 1, 2, 5, 6, 7]: y[y == 0] = np.nan # dont show zero loss values - ax[i].plot(x, y, marker='.', label=f.replace('.txt', '')) + ax[i].plot(x, y, marker='.', label=Path(f).stem) ax[i].set_title(s[i]) if i in [5, 6, 7]: # share train and val loss y axes ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) From 5f912d3add4b4cc5e4165b3814580c4e497bdd04 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Dec 2019 11:53:23 -0800 Subject: [PATCH 0094/1185] updates --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e532d6b163..5a0dae9e74 100755 --- a/README.md +++ b/README.md @@ -136,12 +136,13 @@ Success: converted 'weights/yolov3-spp.pt' to 'converted.weights' # mAP -- `test.py --weights weights/yolov3.weights` tests official YOLOv3 weights. -- `test.py --weights weights/last.pt` tests latest checkpoint. -- mAPs on COCO2014 using pycocotools. -- mAP@0.5 run at `--nms-thres 0.5`, mAP@0.5...0.95 run at `--nms-thres 0.7`. -- YOLOv3-SPP ultralytics is `ultralytics68.pt` with `yolov3-spp.cfg`. -- Darknet results published in https://arxiv.org/abs/1804.02767. +```bash +python3 test.py --weights ... --cfg ... +``` + +- mAP@0.5 run at `--nms-thres 0.5`, mAP@0.5...0.95 run at `--nms-thres 0.7` +- YOLOv3-SPP ultralytics is `ultralytics68.pt` with `yolov3-spp.cfg` +- Darknet results: https://arxiv.org/abs/1804.02767 |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 --- | --- | --- | --- From 1a22bf921137bd4c0a8028a4f54e38f42f0db851 Mon Sep 17 00:00:00 2001 From: Thomas Havlik Date: Wed, 11 Dec 2019 14:17:53 -0600 Subject: [PATCH 0095/1185] added coco/ to .dockerignore (#701) --- .dockerignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..a4e26c8c6d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +# prevent data from being added to build context +coco/ From 25a11972d6414e7f5641368c432bdf70e841a862 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Dec 2019 12:19:47 -0800 Subject: [PATCH 0096/1185] Update .dockerignore --- .dockerignore | 217 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 215 insertions(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index a4e26c8c6d..ce28aaba50 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,215 @@ -# prevent data from being added to build context -coco/ +# Repo-specific DockerIgnore ------------------------------------------------------------------------------------------- +.git +.cache +.idea +runs +output +coco + +data/samples/* +!data/samples/zidane.jpg +!data/samples/bus.jpg +**/results*.txt + +# Neural Network weights ----------------------------------------------------------------------------------------------- +**/*.weights +**/*.pt +**/*.onnx +**/*.mlmodel +**/darknet53.conv.74 +**/yolov3-tiny.conv.15 + + +# Below Copied From .gitignore ----------------------------------------------------------------------------------------- +# Below Copied From .gitignore ----------------------------------------------------------------------------------------- + + +# GitHub Python GitIgnore ---------------------------------------------------------------------------------------------- +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + + +# https://github.com/github/gitignore/blob/master/Global/macOS.gitignore ----------------------------------------------- + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon +Icon? + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + + +# https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/* +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries +.html # Bokeh Plots +.pg # TensorFlow Frozen Graphs +.avi # videos + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +# CMake +cmake-build-debug/ +cmake-build-release/ + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties From 96a94b8cb9d44a52ba75bec537fb6332109d7516 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Dec 2019 13:21:39 -0800 Subject: [PATCH 0097/1185] updates --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 5a0dae9e74..3592188144 100755 --- a/README.md +++ b/README.md @@ -254,6 +254,15 @@ Using CUDA device0 _CudaDeviceProperties(name='GeForce RTX 2080 Ti', total_memor Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.707 ``` +# Reproduce Our Results + +This command reproduces our mAP results above training `yolov3-spp.cfg` from scratch. + +```bash +$ python3 train.py --weights '' --cfg yolov3-spp.cfg --epochs 273 --batch 16 --accum 4 --multi --pre +``` + + # Citation [![DOI](https://zenodo.org/badge/146165888.svg)](https://zenodo.org/badge/latestdoi/146165888) From 2ca4517813ce8c5f413a5acbab340ba73af5f4f5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Dec 2019 13:25:35 -0800 Subject: [PATCH 0098/1185] updates --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3592188144..7be2d9ad47 100755 --- a/README.md +++ b/README.md @@ -256,12 +256,11 @@ Using CUDA device0 _CudaDeviceProperties(name='GeForce RTX 2080 Ti', total_memor # Reproduce Our Results -This command reproduces our mAP results above training `yolov3-spp.cfg` from scratch. - +This command reproduces our mAP results above by training `yolov3-spp.cfg` from scratch. Training takes about one week on a 2080Ti. ```bash $ python3 train.py --weights '' --cfg yolov3-spp.cfg --epochs 273 --batch 16 --accum 4 --multi --pre ``` - + # Citation From db0e5cba6fd9582a9b518f9b296100cbdec6a10a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Dec 2019 13:30:54 -0800 Subject: [PATCH 0099/1185] updates --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7be2d9ad47..bf0bb28769 100755 --- a/README.md +++ b/README.md @@ -256,7 +256,7 @@ Using CUDA device0 _CudaDeviceProperties(name='GeForce RTX 2080 Ti', total_memor # Reproduce Our Results -This command reproduces our mAP results above by training `yolov3-spp.cfg` from scratch. Training takes about one week on a 2080Ti. +This command trains `yolov3-spp.cfg` from scratch to our mAP above. Training takes about one week on a 2080Ti. ```bash $ python3 train.py --weights '' --cfg yolov3-spp.cfg --epochs 273 --batch 16 --accum 4 --multi --pre ``` From 8d8daff390e846f2559e4eb6e7b2ae0921115a58 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Dec 2019 13:40:11 -0800 Subject: [PATCH 0100/1185] updates --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index bf0bb28769..c86115909b 100755 --- a/README.md +++ b/README.md @@ -262,6 +262,13 @@ $ python3 train.py --weights '' --cfg yolov3-spp.cfg --epochs 273 --batch 16 --a ``` +# Reproduce Our Environment + +To access an up-to-date working environment (with all dependencies including CUDA/CUDNN, Python and PyTorch preinstalled), consider a: + +- **GCP** Deep Learning VM with $300 free credit offer: See our [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) +- **Google Colab Notebook** with 12 hours of free GPU time: [Google Colab Notebook](https://colab.research.google.com/drive/1G8T-VFxQkjDe4idzN8F-hbIBqkkkQnxw) +- **Docker Image** from https://hub.docker.com/r/ultralytics/yolov3. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) # Citation [![DOI](https://zenodo.org/badge/146165888.svg)](https://zenodo.org/badge/latestdoi/146165888) From b87bfa32c36f582d21ac3da7b21d9d9178d339ba Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 12 Dec 2019 13:56:56 -0800 Subject: [PATCH 0101/1185] updates --- detect.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/detect.py b/detect.py index 2593406cf5..6da45c3b41 100644 --- a/detect.py +++ b/detect.py @@ -125,6 +125,8 @@ def detect(save_txt=False, save_img=False): # Stream results if view_img: cv2.imshow(p, im0) + if cv2.waitKey(1) == ord('q'): # q to quit + raise StopIteration # Save results (image with detections) if save_img: From 3f06fe6b125aaa7d9e53a6b8c5806b47f82eadcd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 11:05:05 -0800 Subject: [PATCH 0102/1185] updates --- test.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test.py b/test.py index f1145f306c..a7001312d4 100644 --- a/test.py +++ b/test.py @@ -24,6 +24,10 @@ def test(cfg, device = torch_utils.select_device(opt.device, batch_size=batch_size) verbose = True + # Remove previous + for f in glob.glob('test_batch*.jpg'): + os.remove(f) + # Initialize model model = Darknet(cfg, img_size).to(device) @@ -36,7 +40,7 @@ def test(cfg, if torch.cuda.device_count() > 1: model = nn.DataParallel(model) - else: + else: # called by train.py device = next(model.parameters()).device # get model device verbose = False From 1bb738c83f363fdb654a2a5892b5675e35487a4a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 11:49:29 -0800 Subject: [PATCH 0103/1185] updates --- train.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/train.py b/train.py index ef991e2eea..4fece80718 100644 --- a/train.py +++ b/train.py @@ -321,18 +321,16 @@ def train(): final_epoch = epoch + 1 == epochs if opt.prebias: print_model_biases(model) - else: - # Calculate mAP - if not opt.notest or final_epoch: - with torch.no_grad(): - results, maps = test.test(cfg, - data, - batch_size=batch_size, - img_size=opt.img_size, - model=model, - conf_thres=0.001 if final_epoch and epoch > 0 else 0.1, # 0.1 for speed - save_json=final_epoch and epoch > 0 and 'coco.data' in data, - dataloader=testloader) + elif not opt.notest or final_epoch: # Calculate mAP + with torch.no_grad(): + results, maps = test.test(cfg, + data, + batch_size=batch_size, + img_size=opt.img_size, + model=model, + conf_thres=0.001 if final_epoch else 0.1, # 0.1 for speed + save_json=final_epoch and 'coco.data' in data and model.nc == 80, + dataloader=testloader) # Write epoch results with open(results_file, 'a') as f: From 074a9250d8d53b75b7203b31cd603fd96f4df1fe Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 12:27:52 -0800 Subject: [PATCH 0104/1185] updates --- utils/datasets.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index cf43d655b5..2da23e6400 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -320,7 +320,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r extract_bounding_boxes = False create_datasubset = False pbar = tqdm(self.label_files, desc='Caching labels') - nm, nf, ne, ns = 0, 0, 0, 0 # number missing, number found, number empty, number datasubset + nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate for i, file in enumerate(pbar): try: with open(file, 'r') as f: @@ -333,6 +333,9 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r assert l.shape[1] == 5, '> 5 label columns: %s' % file assert (l >= 0).all(), 'negative labels: %s' % file assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels: %s' % file + if np.unique(l, axis=0).shape[0] < l.shape[0]: # duplicate rows + nd += 1 # print('WARNING: duplicate rows in %s' % self.label_files[i]) # duplicate rows + self.labels[i] = l nf += 1 # file found @@ -370,7 +373,8 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r ne += 1 # print('empty labels for image %s' % self.img_files[i]) # file empty # os.system("rm '%s' '%s'" % (self.img_files[i], self.label_files[i])) # remove - pbar.desc = 'Caching labels (%g found, %g missing, %g empty for %g images)' % (nf, nm, ne, n) + pbar.desc = 'Caching labels (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( + nf, nm, ne, nd, n) assert nf > 0, 'No labels found. Recommend correcting image and label paths.' # Cache images into memory for faster training (WARNING: Large datasets may exceed system RAM) From 9c36d5efcd05453ddcbf66045133e7ddd0fcbdfc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 14:03:17 -0800 Subject: [PATCH 0105/1185] updates --- utils/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index ab3795d56f..128742628e 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -89,7 +89,8 @@ def coco80_to_coco91_class(): # converts 80-index (val2014) to 91-index (paper) # https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/ # a = np.loadtxt('data/coco.names', dtype='str', delimiter='\n') # b = np.loadtxt('data/coco_paper.names', dtype='str', delimiter='\n') - # x = [list(a[i] == b).index(True) + 1 for i in range(80)] # darknet to coco + # x1 = [list(a[i] == b).index(True) + 1 for i in range(80)] # darknet to coco + # x2 = [list(b[i] == a).index(True) if any(b[i] == a) else None for i in range(91)] # coco to darknet x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] From dbbe406ac628df4fce391c3d9e021b485347453f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 15:47:48 -0800 Subject: [PATCH 0106/1185] updates --- .gitignore | 2 - data/5k.txt | 5000 ------------------------------------------- data/coco_16img.txt | 32 +- data/coco_1cls.txt | 10 +- data/coco_1img.txt | 2 +- data/coco_64img.txt | 128 +- 6 files changed, 86 insertions(+), 5088 deletions(-) delete mode 100644 data/5k.txt diff --git a/.gitignore b/.gitignore index 9ff1a3756e..2ea8d615e0 100755 --- a/.gitignore +++ b/.gitignore @@ -29,8 +29,6 @@ data/* !data/coco_*.txt !data/coco_*.txt !data/trainvalno5k.shapes -!data/5k.shapes -!data/5k.txt !data/*.sh pycocotools/* diff --git a/data/5k.txt b/data/5k.txt deleted file mode 100644 index ad8c50511e..0000000000 --- a/data/5k.txt +++ /dev/null @@ -1,5000 +0,0 @@ -../coco/images/val2014/COCO_val2014_000000000164.jpg -../coco/images/val2014/COCO_val2014_000000000192.jpg -../coco/images/val2014/COCO_val2014_000000000283.jpg -../coco/images/val2014/COCO_val2014_000000000397.jpg -../coco/images/val2014/COCO_val2014_000000000589.jpg -../coco/images/val2014/COCO_val2014_000000000599.jpg -../coco/images/val2014/COCO_val2014_000000000711.jpg -../coco/images/val2014/COCO_val2014_000000000757.jpg -../coco/images/val2014/COCO_val2014_000000000764.jpg -../coco/images/val2014/COCO_val2014_000000000872.jpg -../coco/images/val2014/COCO_val2014_000000001063.jpg -../coco/images/val2014/COCO_val2014_000000001554.jpg -../coco/images/val2014/COCO_val2014_000000001667.jpg -../coco/images/val2014/COCO_val2014_000000001700.jpg -../coco/images/val2014/COCO_val2014_000000001869.jpg -../coco/images/val2014/COCO_val2014_000000002124.jpg -../coco/images/val2014/COCO_val2014_000000002261.jpg -../coco/images/val2014/COCO_val2014_000000002621.jpg -../coco/images/val2014/COCO_val2014_000000002684.jpg -../coco/images/val2014/COCO_val2014_000000002764.jpg -../coco/images/val2014/COCO_val2014_000000002894.jpg -../coco/images/val2014/COCO_val2014_000000002972.jpg -../coco/images/val2014/COCO_val2014_000000003035.jpg -../coco/images/val2014/COCO_val2014_000000003084.jpg -../coco/images/val2014/COCO_val2014_000000003103.jpg -../coco/images/val2014/COCO_val2014_000000003109.jpg -../coco/images/val2014/COCO_val2014_000000003134.jpg -../coco/images/val2014/COCO_val2014_000000003209.jpg -../coco/images/val2014/COCO_val2014_000000003244.jpg -../coco/images/val2014/COCO_val2014_000000003326.jpg -../coco/images/val2014/COCO_val2014_000000003337.jpg -../coco/images/val2014/COCO_val2014_000000003661.jpg -../coco/images/val2014/COCO_val2014_000000003711.jpg -../coco/images/val2014/COCO_val2014_000000003779.jpg -../coco/images/val2014/COCO_val2014_000000003865.jpg -../coco/images/val2014/COCO_val2014_000000004079.jpg -../coco/images/val2014/COCO_val2014_000000004092.jpg -../coco/images/val2014/COCO_val2014_000000004283.jpg -../coco/images/val2014/COCO_val2014_000000004296.jpg -../coco/images/val2014/COCO_val2014_000000004392.jpg -../coco/images/val2014/COCO_val2014_000000004742.jpg -../coco/images/val2014/COCO_val2014_000000004754.jpg -../coco/images/val2014/COCO_val2014_000000004764.jpg -../coco/images/val2014/COCO_val2014_000000005038.jpg -../coco/images/val2014/COCO_val2014_000000005060.jpg -../coco/images/val2014/COCO_val2014_000000005124.jpg -../coco/images/val2014/COCO_val2014_000000005178.jpg -../coco/images/val2014/COCO_val2014_000000005205.jpg -../coco/images/val2014/COCO_val2014_000000005443.jpg -../coco/images/val2014/COCO_val2014_000000005652.jpg -../coco/images/val2014/COCO_val2014_000000005723.jpg -../coco/images/val2014/COCO_val2014_000000005804.jpg -../coco/images/val2014/COCO_val2014_000000006074.jpg -../coco/images/val2014/COCO_val2014_000000006091.jpg -../coco/images/val2014/COCO_val2014_000000006153.jpg -../coco/images/val2014/COCO_val2014_000000006213.jpg -../coco/images/val2014/COCO_val2014_000000006497.jpg -../coco/images/val2014/COCO_val2014_000000006789.jpg -../coco/images/val2014/COCO_val2014_000000006847.jpg -../coco/images/val2014/COCO_val2014_000000007241.jpg -../coco/images/val2014/COCO_val2014_000000007256.jpg -../coco/images/val2014/COCO_val2014_000000007281.jpg -../coco/images/val2014/COCO_val2014_000000007795.jpg -../coco/images/val2014/COCO_val2014_000000007867.jpg -../coco/images/val2014/COCO_val2014_000000007873.jpg -../coco/images/val2014/COCO_val2014_000000007899.jpg -../coco/images/val2014/COCO_val2014_000000008010.jpg -../coco/images/val2014/COCO_val2014_000000008179.jpg -../coco/images/val2014/COCO_val2014_000000008190.jpg -../coco/images/val2014/COCO_val2014_000000008204.jpg -../coco/images/val2014/COCO_val2014_000000008350.jpg -../coco/images/val2014/COCO_val2014_000000008493.jpg -../coco/images/val2014/COCO_val2014_000000008853.jpg -../coco/images/val2014/COCO_val2014_000000009105.jpg -../coco/images/val2014/COCO_val2014_000000009156.jpg -../coco/images/val2014/COCO_val2014_000000009217.jpg -../coco/images/val2014/COCO_val2014_000000009270.jpg -../coco/images/val2014/COCO_val2014_000000009286.jpg -../coco/images/val2014/COCO_val2014_000000009548.jpg -../coco/images/val2014/COCO_val2014_000000009553.jpg -../coco/images/val2014/COCO_val2014_000000009727.jpg -../coco/images/val2014/COCO_val2014_000000009908.jpg -../coco/images/val2014/COCO_val2014_000000010114.jpg -../coco/images/val2014/COCO_val2014_000000010249.jpg -../coco/images/val2014/COCO_val2014_000000010395.jpg -../coco/images/val2014/COCO_val2014_000000010400.jpg -../coco/images/val2014/COCO_val2014_000000010463.jpg -../coco/images/val2014/COCO_val2014_000000010613.jpg -../coco/images/val2014/COCO_val2014_000000010764.jpg -../coco/images/val2014/COCO_val2014_000000010779.jpg -../coco/images/val2014/COCO_val2014_000000010928.jpg -../coco/images/val2014/COCO_val2014_000000011099.jpg -../coco/images/val2014/COCO_val2014_000000011181.jpg -../coco/images/val2014/COCO_val2014_000000011184.jpg -../coco/images/val2014/COCO_val2014_000000011197.jpg -../coco/images/val2014/COCO_val2014_000000011320.jpg -../coco/images/val2014/COCO_val2014_000000011721.jpg -../coco/images/val2014/COCO_val2014_000000011813.jpg -../coco/images/val2014/COCO_val2014_000000012014.jpg -../coco/images/val2014/COCO_val2014_000000012047.jpg -../coco/images/val2014/COCO_val2014_000000012085.jpg -../coco/images/val2014/COCO_val2014_000000012115.jpg -../coco/images/val2014/COCO_val2014_000000012166.jpg -../coco/images/val2014/COCO_val2014_000000012230.jpg -../coco/images/val2014/COCO_val2014_000000012370.jpg -../coco/images/val2014/COCO_val2014_000000012375.jpg -../coco/images/val2014/COCO_val2014_000000012448.jpg -../coco/images/val2014/COCO_val2014_000000012543.jpg -../coco/images/val2014/COCO_val2014_000000012744.jpg -../coco/images/val2014/COCO_val2014_000000012897.jpg -../coco/images/val2014/COCO_val2014_000000012966.jpg -../coco/images/val2014/COCO_val2014_000000012993.jpg -../coco/images/val2014/COCO_val2014_000000013004.jpg -../coco/images/val2014/COCO_val2014_000000013333.jpg -../coco/images/val2014/COCO_val2014_000000013357.jpg -../coco/images/val2014/COCO_val2014_000000013774.jpg -../coco/images/val2014/COCO_val2014_000000014029.jpg -../coco/images/val2014/COCO_val2014_000000014056.jpg -../coco/images/val2014/COCO_val2014_000000014108.jpg -../coco/images/val2014/COCO_val2014_000000014135.jpg -../coco/images/val2014/COCO_val2014_000000014226.jpg -../coco/images/val2014/COCO_val2014_000000014306.jpg -../coco/images/val2014/COCO_val2014_000000014591.jpg -../coco/images/val2014/COCO_val2014_000000014629.jpg -../coco/images/val2014/COCO_val2014_000000014756.jpg -../coco/images/val2014/COCO_val2014_000000014874.jpg -../coco/images/val2014/COCO_val2014_000000014990.jpg -../coco/images/val2014/COCO_val2014_000000015386.jpg -../coco/images/val2014/COCO_val2014_000000015559.jpg -../coco/images/val2014/COCO_val2014_000000015599.jpg -../coco/images/val2014/COCO_val2014_000000015709.jpg -../coco/images/val2014/COCO_val2014_000000015735.jpg -../coco/images/val2014/COCO_val2014_000000015751.jpg -../coco/images/val2014/COCO_val2014_000000015883.jpg -../coco/images/val2014/COCO_val2014_000000015953.jpg -../coco/images/val2014/COCO_val2014_000000015956.jpg -../coco/images/val2014/COCO_val2014_000000015968.jpg -../coco/images/val2014/COCO_val2014_000000015987.jpg -../coco/images/val2014/COCO_val2014_000000016030.jpg -../coco/images/val2014/COCO_val2014_000000016076.jpg -../coco/images/val2014/COCO_val2014_000000016228.jpg -../coco/images/val2014/COCO_val2014_000000016241.jpg -../coco/images/val2014/COCO_val2014_000000016257.jpg -../coco/images/val2014/COCO_val2014_000000016327.jpg -../coco/images/val2014/COCO_val2014_000000016410.jpg -../coco/images/val2014/COCO_val2014_000000016574.jpg -../coco/images/val2014/COCO_val2014_000000016716.jpg -../coco/images/val2014/COCO_val2014_000000016928.jpg -../coco/images/val2014/COCO_val2014_000000016995.jpg -../coco/images/val2014/COCO_val2014_000000017235.jpg -../coco/images/val2014/COCO_val2014_000000017379.jpg -../coco/images/val2014/COCO_val2014_000000017667.jpg -../coco/images/val2014/COCO_val2014_000000017755.jpg -../coco/images/val2014/COCO_val2014_000000018295.jpg -../coco/images/val2014/COCO_val2014_000000018358.jpg -../coco/images/val2014/COCO_val2014_000000018476.jpg -../coco/images/val2014/COCO_val2014_000000018750.jpg -../coco/images/val2014/COCO_val2014_000000018783.jpg -../coco/images/val2014/COCO_val2014_000000019025.jpg -../coco/images/val2014/COCO_val2014_000000019042.jpg -../coco/images/val2014/COCO_val2014_000000019129.jpg -../coco/images/val2014/COCO_val2014_000000019176.jpg -../coco/images/val2014/COCO_val2014_000000019491.jpg -../coco/images/val2014/COCO_val2014_000000019890.jpg -../coco/images/val2014/COCO_val2014_000000019923.jpg -../coco/images/val2014/COCO_val2014_000000020001.jpg -../coco/images/val2014/COCO_val2014_000000020038.jpg -../coco/images/val2014/COCO_val2014_000000020175.jpg -../coco/images/val2014/COCO_val2014_000000020268.jpg -../coco/images/val2014/COCO_val2014_000000020273.jpg -../coco/images/val2014/COCO_val2014_000000020349.jpg -../coco/images/val2014/COCO_val2014_000000020553.jpg -../coco/images/val2014/COCO_val2014_000000020788.jpg -../coco/images/val2014/COCO_val2014_000000020912.jpg -../coco/images/val2014/COCO_val2014_000000020947.jpg -../coco/images/val2014/COCO_val2014_000000020972.jpg -../coco/images/val2014/COCO_val2014_000000021161.jpg -../coco/images/val2014/COCO_val2014_000000021483.jpg -../coco/images/val2014/COCO_val2014_000000021588.jpg -../coco/images/val2014/COCO_val2014_000000021639.jpg -../coco/images/val2014/COCO_val2014_000000021644.jpg -../coco/images/val2014/COCO_val2014_000000021645.jpg -../coco/images/val2014/COCO_val2014_000000021671.jpg -../coco/images/val2014/COCO_val2014_000000021746.jpg -../coco/images/val2014/COCO_val2014_000000021839.jpg -../coco/images/val2014/COCO_val2014_000000022002.jpg -../coco/images/val2014/COCO_val2014_000000022129.jpg -../coco/images/val2014/COCO_val2014_000000022191.jpg -../coco/images/val2014/COCO_val2014_000000022215.jpg -../coco/images/val2014/COCO_val2014_000000022341.jpg -../coco/images/val2014/COCO_val2014_000000022492.jpg -../coco/images/val2014/COCO_val2014_000000022563.jpg -../coco/images/val2014/COCO_val2014_000000022660.jpg -../coco/images/val2014/COCO_val2014_000000022705.jpg -../coco/images/val2014/COCO_val2014_000000023017.jpg -../coco/images/val2014/COCO_val2014_000000023309.jpg -../coco/images/val2014/COCO_val2014_000000023411.jpg -../coco/images/val2014/COCO_val2014_000000023754.jpg -../coco/images/val2014/COCO_val2014_000000023802.jpg -../coco/images/val2014/COCO_val2014_000000023981.jpg -../coco/images/val2014/COCO_val2014_000000023995.jpg -../coco/images/val2014/COCO_val2014_000000024112.jpg -../coco/images/val2014/COCO_val2014_000000024247.jpg -../coco/images/val2014/COCO_val2014_000000024396.jpg -../coco/images/val2014/COCO_val2014_000000024776.jpg -../coco/images/val2014/COCO_val2014_000000024924.jpg -../coco/images/val2014/COCO_val2014_000000025096.jpg -../coco/images/val2014/COCO_val2014_000000025191.jpg -../coco/images/val2014/COCO_val2014_000000025252.jpg -../coco/images/val2014/COCO_val2014_000000025293.jpg -../coco/images/val2014/COCO_val2014_000000025360.jpg -../coco/images/val2014/COCO_val2014_000000025595.jpg -../coco/images/val2014/COCO_val2014_000000025685.jpg -../coco/images/val2014/COCO_val2014_000000025807.jpg -../coco/images/val2014/COCO_val2014_000000025864.jpg -../coco/images/val2014/COCO_val2014_000000025989.jpg -../coco/images/val2014/COCO_val2014_000000026026.jpg -../coco/images/val2014/COCO_val2014_000000026430.jpg -../coco/images/val2014/COCO_val2014_000000026432.jpg -../coco/images/val2014/COCO_val2014_000000026534.jpg -../coco/images/val2014/COCO_val2014_000000026560.jpg -../coco/images/val2014/COCO_val2014_000000026564.jpg -../coco/images/val2014/COCO_val2014_000000026671.jpg -../coco/images/val2014/COCO_val2014_000000026690.jpg -../coco/images/val2014/COCO_val2014_000000026734.jpg -../coco/images/val2014/COCO_val2014_000000026799.jpg -../coco/images/val2014/COCO_val2014_000000026907.jpg -../coco/images/val2014/COCO_val2014_000000026908.jpg -../coco/images/val2014/COCO_val2014_000000026946.jpg -../coco/images/val2014/COCO_val2014_000000027530.jpg -../coco/images/val2014/COCO_val2014_000000027610.jpg -../coco/images/val2014/COCO_val2014_000000027620.jpg -../coco/images/val2014/COCO_val2014_000000027787.jpg -../coco/images/val2014/COCO_val2014_000000027789.jpg -../coco/images/val2014/COCO_val2014_000000027874.jpg -../coco/images/val2014/COCO_val2014_000000027946.jpg -../coco/images/val2014/COCO_val2014_000000027975.jpg -../coco/images/val2014/COCO_val2014_000000028022.jpg -../coco/images/val2014/COCO_val2014_000000028039.jpg -../coco/images/val2014/COCO_val2014_000000028273.jpg -../coco/images/val2014/COCO_val2014_000000028540.jpg -../coco/images/val2014/COCO_val2014_000000028702.jpg -../coco/images/val2014/COCO_val2014_000000028820.jpg -../coco/images/val2014/COCO_val2014_000000028874.jpg -../coco/images/val2014/COCO_val2014_000000029019.jpg -../coco/images/val2014/COCO_val2014_000000029030.jpg -../coco/images/val2014/COCO_val2014_000000029170.jpg -../coco/images/val2014/COCO_val2014_000000029308.jpg -../coco/images/val2014/COCO_val2014_000000029393.jpg -../coco/images/val2014/COCO_val2014_000000029524.jpg -../coco/images/val2014/COCO_val2014_000000029577.jpg -../coco/images/val2014/COCO_val2014_000000029648.jpg -../coco/images/val2014/COCO_val2014_000000029656.jpg -../coco/images/val2014/COCO_val2014_000000029697.jpg -../coco/images/val2014/COCO_val2014_000000029709.jpg -../coco/images/val2014/COCO_val2014_000000029719.jpg -../coco/images/val2014/COCO_val2014_000000030034.jpg -../coco/images/val2014/COCO_val2014_000000030062.jpg -../coco/images/val2014/COCO_val2014_000000030383.jpg -../coco/images/val2014/COCO_val2014_000000030470.jpg -../coco/images/val2014/COCO_val2014_000000030548.jpg -../coco/images/val2014/COCO_val2014_000000030668.jpg -../coco/images/val2014/COCO_val2014_000000030793.jpg -../coco/images/val2014/COCO_val2014_000000030843.jpg -../coco/images/val2014/COCO_val2014_000000030998.jpg -../coco/images/val2014/COCO_val2014_000000031151.jpg -../coco/images/val2014/COCO_val2014_000000031164.jpg -../coco/images/val2014/COCO_val2014_000000031176.jpg -../coco/images/val2014/COCO_val2014_000000031247.jpg -../coco/images/val2014/COCO_val2014_000000031392.jpg -../coco/images/val2014/COCO_val2014_000000031521.jpg -../coco/images/val2014/COCO_val2014_000000031542.jpg -../coco/images/val2014/COCO_val2014_000000031817.jpg -../coco/images/val2014/COCO_val2014_000000032081.jpg -../coco/images/val2014/COCO_val2014_000000032193.jpg -../coco/images/val2014/COCO_val2014_000000032331.jpg -../coco/images/val2014/COCO_val2014_000000032464.jpg -../coco/images/val2014/COCO_val2014_000000032510.jpg -../coco/images/val2014/COCO_val2014_000000032524.jpg -../coco/images/val2014/COCO_val2014_000000032625.jpg -../coco/images/val2014/COCO_val2014_000000032677.jpg -../coco/images/val2014/COCO_val2014_000000032715.jpg -../coco/images/val2014/COCO_val2014_000000032947.jpg -../coco/images/val2014/COCO_val2014_000000032964.jpg -../coco/images/val2014/COCO_val2014_000000033006.jpg -../coco/images/val2014/COCO_val2014_000000033055.jpg -../coco/images/val2014/COCO_val2014_000000033158.jpg -../coco/images/val2014/COCO_val2014_000000033243.jpg -../coco/images/val2014/COCO_val2014_000000033345.jpg -../coco/images/val2014/COCO_val2014_000000033499.jpg -../coco/images/val2014/COCO_val2014_000000033561.jpg -../coco/images/val2014/COCO_val2014_000000033830.jpg -../coco/images/val2014/COCO_val2014_000000033835.jpg -../coco/images/val2014/COCO_val2014_000000033924.jpg -../coco/images/val2014/COCO_val2014_000000034056.jpg -../coco/images/val2014/COCO_val2014_000000034114.jpg -../coco/images/val2014/COCO_val2014_000000034137.jpg -../coco/images/val2014/COCO_val2014_000000034183.jpg -../coco/images/val2014/COCO_val2014_000000034193.jpg -../coco/images/val2014/COCO_val2014_000000034299.jpg -../coco/images/val2014/COCO_val2014_000000034452.jpg -../coco/images/val2014/COCO_val2014_000000034689.jpg -../coco/images/val2014/COCO_val2014_000000034877.jpg -../coco/images/val2014/COCO_val2014_000000034892.jpg -../coco/images/val2014/COCO_val2014_000000034930.jpg -../coco/images/val2014/COCO_val2014_000000035012.jpg -../coco/images/val2014/COCO_val2014_000000035222.jpg -../coco/images/val2014/COCO_val2014_000000035326.jpg -../coco/images/val2014/COCO_val2014_000000035368.jpg -../coco/images/val2014/COCO_val2014_000000035474.jpg -../coco/images/val2014/COCO_val2014_000000035498.jpg -../coco/images/val2014/COCO_val2014_000000035738.jpg -../coco/images/val2014/COCO_val2014_000000035826.jpg -../coco/images/val2014/COCO_val2014_000000035940.jpg -../coco/images/val2014/COCO_val2014_000000035966.jpg -../coco/images/val2014/COCO_val2014_000000036049.jpg -../coco/images/val2014/COCO_val2014_000000036252.jpg -../coco/images/val2014/COCO_val2014_000000036508.jpg -../coco/images/val2014/COCO_val2014_000000036522.jpg -../coco/images/val2014/COCO_val2014_000000036539.jpg -../coco/images/val2014/COCO_val2014_000000036563.jpg -../coco/images/val2014/COCO_val2014_000000037038.jpg -../coco/images/val2014/COCO_val2014_000000037629.jpg -../coco/images/val2014/COCO_val2014_000000037675.jpg -../coco/images/val2014/COCO_val2014_000000037846.jpg -../coco/images/val2014/COCO_val2014_000000037865.jpg -../coco/images/val2014/COCO_val2014_000000037907.jpg -../coco/images/val2014/COCO_val2014_000000037988.jpg -../coco/images/val2014/COCO_val2014_000000038031.jpg -../coco/images/val2014/COCO_val2014_000000038190.jpg -../coco/images/val2014/COCO_val2014_000000038252.jpg -../coco/images/val2014/COCO_val2014_000000038296.jpg -../coco/images/val2014/COCO_val2014_000000038465.jpg -../coco/images/val2014/COCO_val2014_000000038488.jpg -../coco/images/val2014/COCO_val2014_000000038531.jpg -../coco/images/val2014/COCO_val2014_000000038539.jpg -../coco/images/val2014/COCO_val2014_000000038645.jpg -../coco/images/val2014/COCO_val2014_000000038685.jpg -../coco/images/val2014/COCO_val2014_000000038825.jpg -../coco/images/val2014/COCO_val2014_000000039322.jpg -../coco/images/val2014/COCO_val2014_000000039480.jpg -../coco/images/val2014/COCO_val2014_000000039697.jpg -../coco/images/val2014/COCO_val2014_000000039731.jpg -../coco/images/val2014/COCO_val2014_000000039743.jpg -../coco/images/val2014/COCO_val2014_000000039785.jpg -../coco/images/val2014/COCO_val2014_000000039961.jpg -../coco/images/val2014/COCO_val2014_000000040426.jpg -../coco/images/val2014/COCO_val2014_000000040485.jpg -../coco/images/val2014/COCO_val2014_000000040681.jpg -../coco/images/val2014/COCO_val2014_000000040686.jpg -../coco/images/val2014/COCO_val2014_000000040886.jpg -../coco/images/val2014/COCO_val2014_000000041119.jpg -../coco/images/val2014/COCO_val2014_000000041147.jpg -../coco/images/val2014/COCO_val2014_000000041322.jpg -../coco/images/val2014/COCO_val2014_000000041373.jpg -../coco/images/val2014/COCO_val2014_000000041550.jpg -../coco/images/val2014/COCO_val2014_000000041635.jpg -../coco/images/val2014/COCO_val2014_000000041867.jpg -../coco/images/val2014/COCO_val2014_000000041872.jpg -../coco/images/val2014/COCO_val2014_000000041924.jpg -../coco/images/val2014/COCO_val2014_000000042137.jpg -../coco/images/val2014/COCO_val2014_000000042279.jpg -../coco/images/val2014/COCO_val2014_000000042492.jpg -../coco/images/val2014/COCO_val2014_000000042576.jpg -../coco/images/val2014/COCO_val2014_000000042661.jpg -../coco/images/val2014/COCO_val2014_000000042743.jpg -../coco/images/val2014/COCO_val2014_000000042805.jpg -../coco/images/val2014/COCO_val2014_000000042837.jpg -../coco/images/val2014/COCO_val2014_000000043165.jpg -../coco/images/val2014/COCO_val2014_000000043218.jpg -../coco/images/val2014/COCO_val2014_000000043261.jpg -../coco/images/val2014/COCO_val2014_000000043404.jpg -../coco/images/val2014/COCO_val2014_000000043542.jpg -../coco/images/val2014/COCO_val2014_000000043605.jpg -../coco/images/val2014/COCO_val2014_000000043614.jpg -../coco/images/val2014/COCO_val2014_000000043673.jpg -../coco/images/val2014/COCO_val2014_000000043816.jpg -../coco/images/val2014/COCO_val2014_000000043850.jpg -../coco/images/val2014/COCO_val2014_000000044220.jpg -../coco/images/val2014/COCO_val2014_000000044269.jpg -../coco/images/val2014/COCO_val2014_000000044309.jpg -../coco/images/val2014/COCO_val2014_000000044478.jpg -../coco/images/val2014/COCO_val2014_000000044536.jpg -../coco/images/val2014/COCO_val2014_000000044559.jpg -../coco/images/val2014/COCO_val2014_000000044575.jpg -../coco/images/val2014/COCO_val2014_000000044612.jpg -../coco/images/val2014/COCO_val2014_000000044677.jpg -../coco/images/val2014/COCO_val2014_000000044699.jpg -../coco/images/val2014/COCO_val2014_000000044823.jpg -../coco/images/val2014/COCO_val2014_000000044989.jpg -../coco/images/val2014/COCO_val2014_000000045094.jpg -../coco/images/val2014/COCO_val2014_000000045176.jpg -../coco/images/val2014/COCO_val2014_000000045197.jpg -../coco/images/val2014/COCO_val2014_000000045367.jpg -../coco/images/val2014/COCO_val2014_000000045392.jpg -../coco/images/val2014/COCO_val2014_000000045433.jpg -../coco/images/val2014/COCO_val2014_000000045463.jpg -../coco/images/val2014/COCO_val2014_000000045550.jpg -../coco/images/val2014/COCO_val2014_000000045574.jpg -../coco/images/val2014/COCO_val2014_000000045627.jpg -../coco/images/val2014/COCO_val2014_000000045685.jpg -../coco/images/val2014/COCO_val2014_000000045728.jpg -../coco/images/val2014/COCO_val2014_000000046252.jpg -../coco/images/val2014/COCO_val2014_000000046269.jpg -../coco/images/val2014/COCO_val2014_000000046329.jpg -../coco/images/val2014/COCO_val2014_000000046805.jpg -../coco/images/val2014/COCO_val2014_000000046869.jpg -../coco/images/val2014/COCO_val2014_000000046919.jpg -../coco/images/val2014/COCO_val2014_000000046924.jpg -../coco/images/val2014/COCO_val2014_000000047008.jpg -../coco/images/val2014/COCO_val2014_000000047131.jpg -../coco/images/val2014/COCO_val2014_000000047226.jpg -../coco/images/val2014/COCO_val2014_000000047263.jpg -../coco/images/val2014/COCO_val2014_000000047395.jpg -../coco/images/val2014/COCO_val2014_000000047552.jpg -../coco/images/val2014/COCO_val2014_000000047570.jpg -../coco/images/val2014/COCO_val2014_000000047720.jpg -../coco/images/val2014/COCO_val2014_000000047775.jpg -../coco/images/val2014/COCO_val2014_000000047886.jpg -../coco/images/val2014/COCO_val2014_000000048504.jpg -../coco/images/val2014/COCO_val2014_000000048564.jpg -../coco/images/val2014/COCO_val2014_000000048668.jpg -../coco/images/val2014/COCO_val2014_000000048731.jpg -../coco/images/val2014/COCO_val2014_000000048739.jpg -../coco/images/val2014/COCO_val2014_000000048791.jpg -../coco/images/val2014/COCO_val2014_000000048840.jpg -../coco/images/val2014/COCO_val2014_000000048905.jpg -../coco/images/val2014/COCO_val2014_000000048910.jpg -../coco/images/val2014/COCO_val2014_000000048924.jpg -../coco/images/val2014/COCO_val2014_000000048956.jpg -../coco/images/val2014/COCO_val2014_000000049075.jpg -../coco/images/val2014/COCO_val2014_000000049236.jpg -../coco/images/val2014/COCO_val2014_000000049676.jpg -../coco/images/val2014/COCO_val2014_000000049881.jpg -../coco/images/val2014/COCO_val2014_000000049985.jpg -../coco/images/val2014/COCO_val2014_000000050100.jpg -../coco/images/val2014/COCO_val2014_000000050145.jpg -../coco/images/val2014/COCO_val2014_000000050177.jpg -../coco/images/val2014/COCO_val2014_000000050324.jpg -../coco/images/val2014/COCO_val2014_000000050331.jpg -../coco/images/val2014/COCO_val2014_000000050481.jpg -../coco/images/val2014/COCO_val2014_000000050485.jpg -../coco/images/val2014/COCO_val2014_000000050493.jpg -../coco/images/val2014/COCO_val2014_000000050746.jpg -../coco/images/val2014/COCO_val2014_000000050844.jpg -../coco/images/val2014/COCO_val2014_000000050896.jpg -../coco/images/val2014/COCO_val2014_000000051249.jpg -../coco/images/val2014/COCO_val2014_000000051250.jpg -../coco/images/val2014/COCO_val2014_000000051289.jpg -../coco/images/val2014/COCO_val2014_000000051314.jpg -../coco/images/val2014/COCO_val2014_000000051339.jpg -../coco/images/val2014/COCO_val2014_000000051461.jpg -../coco/images/val2014/COCO_val2014_000000051476.jpg -../coco/images/val2014/COCO_val2014_000000052005.jpg -../coco/images/val2014/COCO_val2014_000000052020.jpg -../coco/images/val2014/COCO_val2014_000000052290.jpg -../coco/images/val2014/COCO_val2014_000000052314.jpg -../coco/images/val2014/COCO_val2014_000000052425.jpg -../coco/images/val2014/COCO_val2014_000000052575.jpg -../coco/images/val2014/COCO_val2014_000000052871.jpg -../coco/images/val2014/COCO_val2014_000000052982.jpg -../coco/images/val2014/COCO_val2014_000000053139.jpg -../coco/images/val2014/COCO_val2014_000000053183.jpg -../coco/images/val2014/COCO_val2014_000000053263.jpg -../coco/images/val2014/COCO_val2014_000000053491.jpg -../coco/images/val2014/COCO_val2014_000000053503.jpg -../coco/images/val2014/COCO_val2014_000000053580.jpg -../coco/images/val2014/COCO_val2014_000000053616.jpg -../coco/images/val2014/COCO_val2014_000000053907.jpg -../coco/images/val2014/COCO_val2014_000000053949.jpg -../coco/images/val2014/COCO_val2014_000000054301.jpg -../coco/images/val2014/COCO_val2014_000000054334.jpg -../coco/images/val2014/COCO_val2014_000000054490.jpg -../coco/images/val2014/COCO_val2014_000000054527.jpg -../coco/images/val2014/COCO_val2014_000000054533.jpg -../coco/images/val2014/COCO_val2014_000000054603.jpg -../coco/images/val2014/COCO_val2014_000000054643.jpg -../coco/images/val2014/COCO_val2014_000000054679.jpg -../coco/images/val2014/COCO_val2014_000000054723.jpg -../coco/images/val2014/COCO_val2014_000000054959.jpg -../coco/images/val2014/COCO_val2014_000000055167.jpg -../coco/images/val2014/COCO_val2014_000000056137.jpg -../coco/images/val2014/COCO_val2014_000000056326.jpg -../coco/images/val2014/COCO_val2014_000000056541.jpg -../coco/images/val2014/COCO_val2014_000000056562.jpg -../coco/images/val2014/COCO_val2014_000000056624.jpg -../coco/images/val2014/COCO_val2014_000000056633.jpg -../coco/images/val2014/COCO_val2014_000000056724.jpg -../coco/images/val2014/COCO_val2014_000000056739.jpg -../coco/images/val2014/COCO_val2014_000000057027.jpg -../coco/images/val2014/COCO_val2014_000000057091.jpg -../coco/images/val2014/COCO_val2014_000000057095.jpg -../coco/images/val2014/COCO_val2014_000000057100.jpg -../coco/images/val2014/COCO_val2014_000000057149.jpg -../coco/images/val2014/COCO_val2014_000000057238.jpg -../coco/images/val2014/COCO_val2014_000000057359.jpg -../coco/images/val2014/COCO_val2014_000000057454.jpg -../coco/images/val2014/COCO_val2014_000000058001.jpg -../coco/images/val2014/COCO_val2014_000000058157.jpg -../coco/images/val2014/COCO_val2014_000000058223.jpg -../coco/images/val2014/COCO_val2014_000000058232.jpg -../coco/images/val2014/COCO_val2014_000000058344.jpg -../coco/images/val2014/COCO_val2014_000000058522.jpg -../coco/images/val2014/COCO_val2014_000000058636.jpg -../coco/images/val2014/COCO_val2014_000000058800.jpg -../coco/images/val2014/COCO_val2014_000000058949.jpg -../coco/images/val2014/COCO_val2014_000000059009.jpg -../coco/images/val2014/COCO_val2014_000000059202.jpg -../coco/images/val2014/COCO_val2014_000000059393.jpg -../coco/images/val2014/COCO_val2014_000000059652.jpg -../coco/images/val2014/COCO_val2014_000000060010.jpg -../coco/images/val2014/COCO_val2014_000000060049.jpg -../coco/images/val2014/COCO_val2014_000000060126.jpg -../coco/images/val2014/COCO_val2014_000000060128.jpg -../coco/images/val2014/COCO_val2014_000000060448.jpg -../coco/images/val2014/COCO_val2014_000000060548.jpg -../coco/images/val2014/COCO_val2014_000000060677.jpg -../coco/images/val2014/COCO_val2014_000000060760.jpg -../coco/images/val2014/COCO_val2014_000000060823.jpg -../coco/images/val2014/COCO_val2014_000000060859.jpg -../coco/images/val2014/COCO_val2014_000000060899.jpg -../coco/images/val2014/COCO_val2014_000000061171.jpg -../coco/images/val2014/COCO_val2014_000000061503.jpg -../coco/images/val2014/COCO_val2014_000000061520.jpg -../coco/images/val2014/COCO_val2014_000000061531.jpg -../coco/images/val2014/COCO_val2014_000000061564.jpg -../coco/images/val2014/COCO_val2014_000000061658.jpg -../coco/images/val2014/COCO_val2014_000000061693.jpg -../coco/images/val2014/COCO_val2014_000000061717.jpg -../coco/images/val2014/COCO_val2014_000000061836.jpg -../coco/images/val2014/COCO_val2014_000000062041.jpg -../coco/images/val2014/COCO_val2014_000000062060.jpg -../coco/images/val2014/COCO_val2014_000000062198.jpg -../coco/images/val2014/COCO_val2014_000000062200.jpg -../coco/images/val2014/COCO_val2014_000000062220.jpg -../coco/images/val2014/COCO_val2014_000000062623.jpg -../coco/images/val2014/COCO_val2014_000000062726.jpg -../coco/images/val2014/COCO_val2014_000000062875.jpg -../coco/images/val2014/COCO_val2014_000000063047.jpg -../coco/images/val2014/COCO_val2014_000000063114.jpg -../coco/images/val2014/COCO_val2014_000000063488.jpg -../coco/images/val2014/COCO_val2014_000000063671.jpg -../coco/images/val2014/COCO_val2014_000000063715.jpg -../coco/images/val2014/COCO_val2014_000000063804.jpg -../coco/images/val2014/COCO_val2014_000000063882.jpg -../coco/images/val2014/COCO_val2014_000000063939.jpg -../coco/images/val2014/COCO_val2014_000000063965.jpg -../coco/images/val2014/COCO_val2014_000000064155.jpg -../coco/images/val2014/COCO_val2014_000000064189.jpg -../coco/images/val2014/COCO_val2014_000000064196.jpg -../coco/images/val2014/COCO_val2014_000000064495.jpg -../coco/images/val2014/COCO_val2014_000000064610.jpg -../coco/images/val2014/COCO_val2014_000000064693.jpg -../coco/images/val2014/COCO_val2014_000000064746.jpg -../coco/images/val2014/COCO_val2014_000000064760.jpg -../coco/images/val2014/COCO_val2014_000000064796.jpg -../coco/images/val2014/COCO_val2014_000000064865.jpg -../coco/images/val2014/COCO_val2014_000000064915.jpg -../coco/images/val2014/COCO_val2014_000000065074.jpg -../coco/images/val2014/COCO_val2014_000000065124.jpg -../coco/images/val2014/COCO_val2014_000000065258.jpg -../coco/images/val2014/COCO_val2014_000000065267.jpg -../coco/images/val2014/COCO_val2014_000000065430.jpg -../coco/images/val2014/COCO_val2014_000000065465.jpg -../coco/images/val2014/COCO_val2014_000000065942.jpg -../coco/images/val2014/COCO_val2014_000000066001.jpg -../coco/images/val2014/COCO_val2014_000000066064.jpg -../coco/images/val2014/COCO_val2014_000000066072.jpg -../coco/images/val2014/COCO_val2014_000000066239.jpg -../coco/images/val2014/COCO_val2014_000000066243.jpg -../coco/images/val2014/COCO_val2014_000000066355.jpg -../coco/images/val2014/COCO_val2014_000000066412.jpg -../coco/images/val2014/COCO_val2014_000000066423.jpg -../coco/images/val2014/COCO_val2014_000000066427.jpg -../coco/images/val2014/COCO_val2014_000000066502.jpg -../coco/images/val2014/COCO_val2014_000000066519.jpg -../coco/images/val2014/COCO_val2014_000000066561.jpg -../coco/images/val2014/COCO_val2014_000000066700.jpg -../coco/images/val2014/COCO_val2014_000000066717.jpg -../coco/images/val2014/COCO_val2014_000000066879.jpg -../coco/images/val2014/COCO_val2014_000000067178.jpg -../coco/images/val2014/COCO_val2014_000000067207.jpg -../coco/images/val2014/COCO_val2014_000000067218.jpg -../coco/images/val2014/COCO_val2014_000000067412.jpg -../coco/images/val2014/COCO_val2014_000000067532.jpg -../coco/images/val2014/COCO_val2014_000000067590.jpg -../coco/images/val2014/COCO_val2014_000000067660.jpg -../coco/images/val2014/COCO_val2014_000000067686.jpg -../coco/images/val2014/COCO_val2014_000000067704.jpg -../coco/images/val2014/COCO_val2014_000000067776.jpg -../coco/images/val2014/COCO_val2014_000000067948.jpg -../coco/images/val2014/COCO_val2014_000000067953.jpg -../coco/images/val2014/COCO_val2014_000000068059.jpg -../coco/images/val2014/COCO_val2014_000000068204.jpg -../coco/images/val2014/COCO_val2014_000000068205.jpg -../coco/images/val2014/COCO_val2014_000000068409.jpg -../coco/images/val2014/COCO_val2014_000000068435.jpg -../coco/images/val2014/COCO_val2014_000000068520.jpg -../coco/images/val2014/COCO_val2014_000000068546.jpg -../coco/images/val2014/COCO_val2014_000000068674.jpg -../coco/images/val2014/COCO_val2014_000000068745.jpg -../coco/images/val2014/COCO_val2014_000000069009.jpg -../coco/images/val2014/COCO_val2014_000000069077.jpg -../coco/images/val2014/COCO_val2014_000000069196.jpg -../coco/images/val2014/COCO_val2014_000000069356.jpg -../coco/images/val2014/COCO_val2014_000000069568.jpg -../coco/images/val2014/COCO_val2014_000000069577.jpg -../coco/images/val2014/COCO_val2014_000000069698.jpg -../coco/images/val2014/COCO_val2014_000000070493.jpg -../coco/images/val2014/COCO_val2014_000000070896.jpg -../coco/images/val2014/COCO_val2014_000000071023.jpg -../coco/images/val2014/COCO_val2014_000000071123.jpg -../coco/images/val2014/COCO_val2014_000000071241.jpg -../coco/images/val2014/COCO_val2014_000000071301.jpg -../coco/images/val2014/COCO_val2014_000000071345.jpg -../coco/images/val2014/COCO_val2014_000000071451.jpg -../coco/images/val2014/COCO_val2014_000000071673.jpg -../coco/images/val2014/COCO_val2014_000000071826.jpg -../coco/images/val2014/COCO_val2014_000000071986.jpg -../coco/images/val2014/COCO_val2014_000000072004.jpg -../coco/images/val2014/COCO_val2014_000000072020.jpg -../coco/images/val2014/COCO_val2014_000000072052.jpg -../coco/images/val2014/COCO_val2014_000000072281.jpg -../coco/images/val2014/COCO_val2014_000000072368.jpg -../coco/images/val2014/COCO_val2014_000000072737.jpg -../coco/images/val2014/COCO_val2014_000000072797.jpg -../coco/images/val2014/COCO_val2014_000000072860.jpg -../coco/images/val2014/COCO_val2014_000000073009.jpg -../coco/images/val2014/COCO_val2014_000000073039.jpg -../coco/images/val2014/COCO_val2014_000000073239.jpg -../coco/images/val2014/COCO_val2014_000000073467.jpg -../coco/images/val2014/COCO_val2014_000000073491.jpg -../coco/images/val2014/COCO_val2014_000000073588.jpg -../coco/images/val2014/COCO_val2014_000000073729.jpg -../coco/images/val2014/COCO_val2014_000000073973.jpg -../coco/images/val2014/COCO_val2014_000000074037.jpg -../coco/images/val2014/COCO_val2014_000000074137.jpg -../coco/images/val2014/COCO_val2014_000000074268.jpg -../coco/images/val2014/COCO_val2014_000000074434.jpg -../coco/images/val2014/COCO_val2014_000000074789.jpg -../coco/images/val2014/COCO_val2014_000000074963.jpg -../coco/images/val2014/COCO_val2014_000000075033.jpg -../coco/images/val2014/COCO_val2014_000000075372.jpg -../coco/images/val2014/COCO_val2014_000000075527.jpg -../coco/images/val2014/COCO_val2014_000000075646.jpg -../coco/images/val2014/COCO_val2014_000000075713.jpg -../coco/images/val2014/COCO_val2014_000000075775.jpg -../coco/images/val2014/COCO_val2014_000000075786.jpg -../coco/images/val2014/COCO_val2014_000000075886.jpg -../coco/images/val2014/COCO_val2014_000000076087.jpg -../coco/images/val2014/COCO_val2014_000000076257.jpg -../coco/images/val2014/COCO_val2014_000000076521.jpg -../coco/images/val2014/COCO_val2014_000000076572.jpg -../coco/images/val2014/COCO_val2014_000000076844.jpg -../coco/images/val2014/COCO_val2014_000000077178.jpg -../coco/images/val2014/COCO_val2014_000000077181.jpg -../coco/images/val2014/COCO_val2014_000000077184.jpg -../coco/images/val2014/COCO_val2014_000000077396.jpg -../coco/images/val2014/COCO_val2014_000000077400.jpg -../coco/images/val2014/COCO_val2014_000000077415.jpg -../coco/images/val2014/COCO_val2014_000000078565.jpg -../coco/images/val2014/COCO_val2014_000000078701.jpg -../coco/images/val2014/COCO_val2014_000000078843.jpg -../coco/images/val2014/COCO_val2014_000000078929.jpg -../coco/images/val2014/COCO_val2014_000000079084.jpg -../coco/images/val2014/COCO_val2014_000000079188.jpg -../coco/images/val2014/COCO_val2014_000000079544.jpg -../coco/images/val2014/COCO_val2014_000000079566.jpg -../coco/images/val2014/COCO_val2014_000000079588.jpg -../coco/images/val2014/COCO_val2014_000000079689.jpg -../coco/images/val2014/COCO_val2014_000000080104.jpg -../coco/images/val2014/COCO_val2014_000000080172.jpg -../coco/images/val2014/COCO_val2014_000000080219.jpg -../coco/images/val2014/COCO_val2014_000000080300.jpg -../coco/images/val2014/COCO_val2014_000000080395.jpg -../coco/images/val2014/COCO_val2014_000000080522.jpg -../coco/images/val2014/COCO_val2014_000000080714.jpg -../coco/images/val2014/COCO_val2014_000000080737.jpg -../coco/images/val2014/COCO_val2014_000000080747.jpg -../coco/images/val2014/COCO_val2014_000000081000.jpg -../coco/images/val2014/COCO_val2014_000000081081.jpg -../coco/images/val2014/COCO_val2014_000000081100.jpg -../coco/images/val2014/COCO_val2014_000000081287.jpg -../coco/images/val2014/COCO_val2014_000000081394.jpg -../coco/images/val2014/COCO_val2014_000000081552.jpg -../coco/images/val2014/COCO_val2014_000000082157.jpg -../coco/images/val2014/COCO_val2014_000000082252.jpg -../coco/images/val2014/COCO_val2014_000000082259.jpg -../coco/images/val2014/COCO_val2014_000000082367.jpg -../coco/images/val2014/COCO_val2014_000000082431.jpg -../coco/images/val2014/COCO_val2014_000000082456.jpg -../coco/images/val2014/COCO_val2014_000000082794.jpg -../coco/images/val2014/COCO_val2014_000000082807.jpg -../coco/images/val2014/COCO_val2014_000000082846.jpg -../coco/images/val2014/COCO_val2014_000000082847.jpg -../coco/images/val2014/COCO_val2014_000000082889.jpg -../coco/images/val2014/COCO_val2014_000000082981.jpg -../coco/images/val2014/COCO_val2014_000000083036.jpg -../coco/images/val2014/COCO_val2014_000000083065.jpg -../coco/images/val2014/COCO_val2014_000000083142.jpg -../coco/images/val2014/COCO_val2014_000000083275.jpg -../coco/images/val2014/COCO_val2014_000000083557.jpg -../coco/images/val2014/COCO_val2014_000000084073.jpg -../coco/images/val2014/COCO_val2014_000000084447.jpg -../coco/images/val2014/COCO_val2014_000000084463.jpg -../coco/images/val2014/COCO_val2014_000000084592.jpg -../coco/images/val2014/COCO_val2014_000000084674.jpg -../coco/images/val2014/COCO_val2014_000000084762.jpg -../coco/images/val2014/COCO_val2014_000000084870.jpg -../coco/images/val2014/COCO_val2014_000000084929.jpg -../coco/images/val2014/COCO_val2014_000000084980.jpg -../coco/images/val2014/COCO_val2014_000000085101.jpg -../coco/images/val2014/COCO_val2014_000000085292.jpg -../coco/images/val2014/COCO_val2014_000000085353.jpg -../coco/images/val2014/COCO_val2014_000000085674.jpg -../coco/images/val2014/COCO_val2014_000000085813.jpg -../coco/images/val2014/COCO_val2014_000000086011.jpg -../coco/images/val2014/COCO_val2014_000000086133.jpg -../coco/images/val2014/COCO_val2014_000000086136.jpg -../coco/images/val2014/COCO_val2014_000000086215.jpg -../coco/images/val2014/COCO_val2014_000000086220.jpg -../coco/images/val2014/COCO_val2014_000000086249.jpg -../coco/images/val2014/COCO_val2014_000000086320.jpg -../coco/images/val2014/COCO_val2014_000000086357.jpg -../coco/images/val2014/COCO_val2014_000000086429.jpg -../coco/images/val2014/COCO_val2014_000000086467.jpg -../coco/images/val2014/COCO_val2014_000000086483.jpg -../coco/images/val2014/COCO_val2014_000000086646.jpg -../coco/images/val2014/COCO_val2014_000000086755.jpg -../coco/images/val2014/COCO_val2014_000000086839.jpg -../coco/images/val2014/COCO_val2014_000000086848.jpg -../coco/images/val2014/COCO_val2014_000000086877.jpg -../coco/images/val2014/COCO_val2014_000000087038.jpg -../coco/images/val2014/COCO_val2014_000000087244.jpg -../coco/images/val2014/COCO_val2014_000000087354.jpg -../coco/images/val2014/COCO_val2014_000000087387.jpg -../coco/images/val2014/COCO_val2014_000000087489.jpg -../coco/images/val2014/COCO_val2014_000000087503.jpg -../coco/images/val2014/COCO_val2014_000000087617.jpg -../coco/images/val2014/COCO_val2014_000000087638.jpg -../coco/images/val2014/COCO_val2014_000000087740.jpg -../coco/images/val2014/COCO_val2014_000000087875.jpg -../coco/images/val2014/COCO_val2014_000000088360.jpg -../coco/images/val2014/COCO_val2014_000000088507.jpg -../coco/images/val2014/COCO_val2014_000000088560.jpg -../coco/images/val2014/COCO_val2014_000000088846.jpg -../coco/images/val2014/COCO_val2014_000000088859.jpg -../coco/images/val2014/COCO_val2014_000000088902.jpg -../coco/images/val2014/COCO_val2014_000000089027.jpg -../coco/images/val2014/COCO_val2014_000000089258.jpg -../coco/images/val2014/COCO_val2014_000000089285.jpg -../coco/images/val2014/COCO_val2014_000000089359.jpg -../coco/images/val2014/COCO_val2014_000000089378.jpg -../coco/images/val2014/COCO_val2014_000000089391.jpg -../coco/images/val2014/COCO_val2014_000000089487.jpg -../coco/images/val2014/COCO_val2014_000000089618.jpg -../coco/images/val2014/COCO_val2014_000000089670.jpg -../coco/images/val2014/COCO_val2014_000000090003.jpg -../coco/images/val2014/COCO_val2014_000000090062.jpg -../coco/images/val2014/COCO_val2014_000000090155.jpg -../coco/images/val2014/COCO_val2014_000000090208.jpg -../coco/images/val2014/COCO_val2014_000000090351.jpg -../coco/images/val2014/COCO_val2014_000000090476.jpg -../coco/images/val2014/COCO_val2014_000000090594.jpg -../coco/images/val2014/COCO_val2014_000000090753.jpg -../coco/images/val2014/COCO_val2014_000000090754.jpg -../coco/images/val2014/COCO_val2014_000000090864.jpg -../coco/images/val2014/COCO_val2014_000000091079.jpg -../coco/images/val2014/COCO_val2014_000000091341.jpg -../coco/images/val2014/COCO_val2014_000000091402.jpg -../coco/images/val2014/COCO_val2014_000000091517.jpg -../coco/images/val2014/COCO_val2014_000000091520.jpg -../coco/images/val2014/COCO_val2014_000000091612.jpg -../coco/images/val2014/COCO_val2014_000000091716.jpg -../coco/images/val2014/COCO_val2014_000000091766.jpg -../coco/images/val2014/COCO_val2014_000000091857.jpg -../coco/images/val2014/COCO_val2014_000000091899.jpg -../coco/images/val2014/COCO_val2014_000000091912.jpg -../coco/images/val2014/COCO_val2014_000000092093.jpg -../coco/images/val2014/COCO_val2014_000000092124.jpg -../coco/images/val2014/COCO_val2014_000000092679.jpg -../coco/images/val2014/COCO_val2014_000000092683.jpg -../coco/images/val2014/COCO_val2014_000000092939.jpg -../coco/images/val2014/COCO_val2014_000000092985.jpg -../coco/images/val2014/COCO_val2014_000000093175.jpg -../coco/images/val2014/COCO_val2014_000000093236.jpg -../coco/images/val2014/COCO_val2014_000000093331.jpg -../coco/images/val2014/COCO_val2014_000000093434.jpg -../coco/images/val2014/COCO_val2014_000000093607.jpg -../coco/images/val2014/COCO_val2014_000000093806.jpg -../coco/images/val2014/COCO_val2014_000000093964.jpg -../coco/images/val2014/COCO_val2014_000000094012.jpg -../coco/images/val2014/COCO_val2014_000000094033.jpg -../coco/images/val2014/COCO_val2014_000000094046.jpg -../coco/images/val2014/COCO_val2014_000000094052.jpg -../coco/images/val2014/COCO_val2014_000000094055.jpg -../coco/images/val2014/COCO_val2014_000000094501.jpg -../coco/images/val2014/COCO_val2014_000000094619.jpg -../coco/images/val2014/COCO_val2014_000000094746.jpg -../coco/images/val2014/COCO_val2014_000000094795.jpg -../coco/images/val2014/COCO_val2014_000000094846.jpg -../coco/images/val2014/COCO_val2014_000000095062.jpg -../coco/images/val2014/COCO_val2014_000000095063.jpg -../coco/images/val2014/COCO_val2014_000000095227.jpg -../coco/images/val2014/COCO_val2014_000000095441.jpg -../coco/images/val2014/COCO_val2014_000000095551.jpg -../coco/images/val2014/COCO_val2014_000000095670.jpg -../coco/images/val2014/COCO_val2014_000000095770.jpg -../coco/images/val2014/COCO_val2014_000000096110.jpg -../coco/images/val2014/COCO_val2014_000000096288.jpg -../coco/images/val2014/COCO_val2014_000000096327.jpg -../coco/images/val2014/COCO_val2014_000000096351.jpg -../coco/images/val2014/COCO_val2014_000000096618.jpg -../coco/images/val2014/COCO_val2014_000000096654.jpg -../coco/images/val2014/COCO_val2014_000000096762.jpg -../coco/images/val2014/COCO_val2014_000000096769.jpg -../coco/images/val2014/COCO_val2014_000000096998.jpg -../coco/images/val2014/COCO_val2014_000000097017.jpg -../coco/images/val2014/COCO_val2014_000000097048.jpg -../coco/images/val2014/COCO_val2014_000000097080.jpg -../coco/images/val2014/COCO_val2014_000000097240.jpg -../coco/images/val2014/COCO_val2014_000000097479.jpg -../coco/images/val2014/COCO_val2014_000000097577.jpg -../coco/images/val2014/COCO_val2014_000000097610.jpg -../coco/images/val2014/COCO_val2014_000000097656.jpg -../coco/images/val2014/COCO_val2014_000000097667.jpg -../coco/images/val2014/COCO_val2014_000000097682.jpg -../coco/images/val2014/COCO_val2014_000000097748.jpg -../coco/images/val2014/COCO_val2014_000000097868.jpg -../coco/images/val2014/COCO_val2014_000000097899.jpg -../coco/images/val2014/COCO_val2014_000000098018.jpg -../coco/images/val2014/COCO_val2014_000000098043.jpg -../coco/images/val2014/COCO_val2014_000000098095.jpg -../coco/images/val2014/COCO_val2014_000000098194.jpg -../coco/images/val2014/COCO_val2014_000000098280.jpg -../coco/images/val2014/COCO_val2014_000000098283.jpg -../coco/images/val2014/COCO_val2014_000000098599.jpg -../coco/images/val2014/COCO_val2014_000000098872.jpg -../coco/images/val2014/COCO_val2014_000000099026.jpg -../coco/images/val2014/COCO_val2014_000000099260.jpg -../coco/images/val2014/COCO_val2014_000000099389.jpg -../coco/images/val2014/COCO_val2014_000000099707.jpg -../coco/images/val2014/COCO_val2014_000000099961.jpg -../coco/images/val2014/COCO_val2014_000000099996.jpg -../coco/images/val2014/COCO_val2014_000000100000.jpg -../coco/images/val2014/COCO_val2014_000000100006.jpg -../coco/images/val2014/COCO_val2014_000000100083.jpg -../coco/images/val2014/COCO_val2014_000000100166.jpg -../coco/images/val2014/COCO_val2014_000000100187.jpg -../coco/images/val2014/COCO_val2014_000000100245.jpg -../coco/images/val2014/COCO_val2014_000000100343.jpg -../coco/images/val2014/COCO_val2014_000000100428.jpg -../coco/images/val2014/COCO_val2014_000000100582.jpg -../coco/images/val2014/COCO_val2014_000000100723.jpg -../coco/images/val2014/COCO_val2014_000000100726.jpg -../coco/images/val2014/COCO_val2014_000000100909.jpg -../coco/images/val2014/COCO_val2014_000000101059.jpg -../coco/images/val2014/COCO_val2014_000000101145.jpg -../coco/images/val2014/COCO_val2014_000000101567.jpg -../coco/images/val2014/COCO_val2014_000000101623.jpg -../coco/images/val2014/COCO_val2014_000000101703.jpg -../coco/images/val2014/COCO_val2014_000000101884.jpg -../coco/images/val2014/COCO_val2014_000000101948.jpg -../coco/images/val2014/COCO_val2014_000000102331.jpg -../coco/images/val2014/COCO_val2014_000000102421.jpg -../coco/images/val2014/COCO_val2014_000000102439.jpg -../coco/images/val2014/COCO_val2014_000000102446.jpg -../coco/images/val2014/COCO_val2014_000000102461.jpg -../coco/images/val2014/COCO_val2014_000000102466.jpg -../coco/images/val2014/COCO_val2014_000000102478.jpg -../coco/images/val2014/COCO_val2014_000000102594.jpg -../coco/images/val2014/COCO_val2014_000000102598.jpg -../coco/images/val2014/COCO_val2014_000000102665.jpg -../coco/images/val2014/COCO_val2014_000000102707.jpg -../coco/images/val2014/COCO_val2014_000000102848.jpg -../coco/images/val2014/COCO_val2014_000000102906.jpg -../coco/images/val2014/COCO_val2014_000000103122.jpg -../coco/images/val2014/COCO_val2014_000000103255.jpg -../coco/images/val2014/COCO_val2014_000000103272.jpg -../coco/images/val2014/COCO_val2014_000000103379.jpg -../coco/images/val2014/COCO_val2014_000000103413.jpg -../coco/images/val2014/COCO_val2014_000000103431.jpg -../coco/images/val2014/COCO_val2014_000000103509.jpg -../coco/images/val2014/COCO_val2014_000000103538.jpg -../coco/images/val2014/COCO_val2014_000000103667.jpg -../coco/images/val2014/COCO_val2014_000000103747.jpg -../coco/images/val2014/COCO_val2014_000000103931.jpg -../coco/images/val2014/COCO_val2014_000000104002.jpg -../coco/images/val2014/COCO_val2014_000000104455.jpg -../coco/images/val2014/COCO_val2014_000000104486.jpg -../coco/images/val2014/COCO_val2014_000000104494.jpg -../coco/images/val2014/COCO_val2014_000000104495.jpg -../coco/images/val2014/COCO_val2014_000000104893.jpg -../coco/images/val2014/COCO_val2014_000000104965.jpg -../coco/images/val2014/COCO_val2014_000000105040.jpg -../coco/images/val2014/COCO_val2014_000000105102.jpg -../coco/images/val2014/COCO_val2014_000000105156.jpg -../coco/images/val2014/COCO_val2014_000000105264.jpg -../coco/images/val2014/COCO_val2014_000000105291.jpg -../coco/images/val2014/COCO_val2014_000000105367.jpg -../coco/images/val2014/COCO_val2014_000000105647.jpg -../coco/images/val2014/COCO_val2014_000000105668.jpg -../coco/images/val2014/COCO_val2014_000000105711.jpg -../coco/images/val2014/COCO_val2014_000000105866.jpg -../coco/images/val2014/COCO_val2014_000000105973.jpg -../coco/images/val2014/COCO_val2014_000000106096.jpg -../coco/images/val2014/COCO_val2014_000000106120.jpg -../coco/images/val2014/COCO_val2014_000000106314.jpg -../coco/images/val2014/COCO_val2014_000000106351.jpg -../coco/images/val2014/COCO_val2014_000000106641.jpg -../coco/images/val2014/COCO_val2014_000000106661.jpg -../coco/images/val2014/COCO_val2014_000000106757.jpg -../coco/images/val2014/COCO_val2014_000000106793.jpg -../coco/images/val2014/COCO_val2014_000000106849.jpg -../coco/images/val2014/COCO_val2014_000000107004.jpg -../coco/images/val2014/COCO_val2014_000000107123.jpg -../coco/images/val2014/COCO_val2014_000000107183.jpg -../coco/images/val2014/COCO_val2014_000000107227.jpg -../coco/images/val2014/COCO_val2014_000000107244.jpg -../coco/images/val2014/COCO_val2014_000000107304.jpg -../coco/images/val2014/COCO_val2014_000000107542.jpg -../coco/images/val2014/COCO_val2014_000000107741.jpg -../coco/images/val2014/COCO_val2014_000000107831.jpg -../coco/images/val2014/COCO_val2014_000000107839.jpg -../coco/images/val2014/COCO_val2014_000000108051.jpg -../coco/images/val2014/COCO_val2014_000000108152.jpg -../coco/images/val2014/COCO_val2014_000000108212.jpg -../coco/images/val2014/COCO_val2014_000000108380.jpg -../coco/images/val2014/COCO_val2014_000000108408.jpg -../coco/images/val2014/COCO_val2014_000000108531.jpg -../coco/images/val2014/COCO_val2014_000000108761.jpg -../coco/images/val2014/COCO_val2014_000000108864.jpg -../coco/images/val2014/COCO_val2014_000000109055.jpg -../coco/images/val2014/COCO_val2014_000000109092.jpg -../coco/images/val2014/COCO_val2014_000000109178.jpg -../coco/images/val2014/COCO_val2014_000000109216.jpg -../coco/images/val2014/COCO_val2014_000000109231.jpg -../coco/images/val2014/COCO_val2014_000000109308.jpg -../coco/images/val2014/COCO_val2014_000000109486.jpg -../coco/images/val2014/COCO_val2014_000000109819.jpg -../coco/images/val2014/COCO_val2014_000000109869.jpg -../coco/images/val2014/COCO_val2014_000000110313.jpg -../coco/images/val2014/COCO_val2014_000000110389.jpg -../coco/images/val2014/COCO_val2014_000000110562.jpg -../coco/images/val2014/COCO_val2014_000000110617.jpg -../coco/images/val2014/COCO_val2014_000000110638.jpg -../coco/images/val2014/COCO_val2014_000000110881.jpg -../coco/images/val2014/COCO_val2014_000000110884.jpg -../coco/images/val2014/COCO_val2014_000000110951.jpg -../coco/images/val2014/COCO_val2014_000000111004.jpg -../coco/images/val2014/COCO_val2014_000000111014.jpg -../coco/images/val2014/COCO_val2014_000000111024.jpg -../coco/images/val2014/COCO_val2014_000000111076.jpg -../coco/images/val2014/COCO_val2014_000000111179.jpg -../coco/images/val2014/COCO_val2014_000000111590.jpg -../coco/images/val2014/COCO_val2014_000000111593.jpg -../coco/images/val2014/COCO_val2014_000000111878.jpg -../coco/images/val2014/COCO_val2014_000000112298.jpg -../coco/images/val2014/COCO_val2014_000000112388.jpg -../coco/images/val2014/COCO_val2014_000000112394.jpg -../coco/images/val2014/COCO_val2014_000000112440.jpg -../coco/images/val2014/COCO_val2014_000000112751.jpg -../coco/images/val2014/COCO_val2014_000000112818.jpg -../coco/images/val2014/COCO_val2014_000000112820.jpg -../coco/images/val2014/COCO_val2014_000000112830.jpg -../coco/images/val2014/COCO_val2014_000000112928.jpg -../coco/images/val2014/COCO_val2014_000000113139.jpg -../coco/images/val2014/COCO_val2014_000000113173.jpg -../coco/images/val2014/COCO_val2014_000000113313.jpg -../coco/images/val2014/COCO_val2014_000000113440.jpg -../coco/images/val2014/COCO_val2014_000000113559.jpg -../coco/images/val2014/COCO_val2014_000000113570.jpg -../coco/images/val2014/COCO_val2014_000000113579.jpg -../coco/images/val2014/COCO_val2014_000000113590.jpg -../coco/images/val2014/COCO_val2014_000000113757.jpg -../coco/images/val2014/COCO_val2014_000000113977.jpg -../coco/images/val2014/COCO_val2014_000000114033.jpg -../coco/images/val2014/COCO_val2014_000000114055.jpg -../coco/images/val2014/COCO_val2014_000000114090.jpg -../coco/images/val2014/COCO_val2014_000000114147.jpg -../coco/images/val2014/COCO_val2014_000000114239.jpg -../coco/images/val2014/COCO_val2014_000000114503.jpg -../coco/images/val2014/COCO_val2014_000000114907.jpg -../coco/images/val2014/COCO_val2014_000000114926.jpg -../coco/images/val2014/COCO_val2014_000000115069.jpg -../coco/images/val2014/COCO_val2014_000000115070.jpg -../coco/images/val2014/COCO_val2014_000000115128.jpg -../coco/images/val2014/COCO_val2014_000000115870.jpg -../coco/images/val2014/COCO_val2014_000000115898.jpg -../coco/images/val2014/COCO_val2014_000000115930.jpg -../coco/images/val2014/COCO_val2014_000000116226.jpg -../coco/images/val2014/COCO_val2014_000000116556.jpg -../coco/images/val2014/COCO_val2014_000000116667.jpg -../coco/images/val2014/COCO_val2014_000000116696.jpg -../coco/images/val2014/COCO_val2014_000000116936.jpg -../coco/images/val2014/COCO_val2014_000000117014.jpg -../coco/images/val2014/COCO_val2014_000000117037.jpg -../coco/images/val2014/COCO_val2014_000000117125.jpg -../coco/images/val2014/COCO_val2014_000000117127.jpg -../coco/images/val2014/COCO_val2014_000000117191.jpg -../coco/images/val2014/COCO_val2014_000000117201.jpg -../coco/images/val2014/COCO_val2014_000000117237.jpg -../coco/images/val2014/COCO_val2014_000000117404.jpg -../coco/images/val2014/COCO_val2014_000000117527.jpg -../coco/images/val2014/COCO_val2014_000000117718.jpg -../coco/images/val2014/COCO_val2014_000000117725.jpg -../coco/images/val2014/COCO_val2014_000000117786.jpg -../coco/images/val2014/COCO_val2014_000000117899.jpg -../coco/images/val2014/COCO_val2014_000000118401.jpg -../coco/images/val2014/COCO_val2014_000000118546.jpg -../coco/images/val2014/COCO_val2014_000000118579.jpg -../coco/images/val2014/COCO_val2014_000000118740.jpg -../coco/images/val2014/COCO_val2014_000000118788.jpg -../coco/images/val2014/COCO_val2014_000000118956.jpg -../coco/images/val2014/COCO_val2014_000000119232.jpg -../coco/images/val2014/COCO_val2014_000000119233.jpg -../coco/images/val2014/COCO_val2014_000000119445.jpg -../coco/images/val2014/COCO_val2014_000000119617.jpg -../coco/images/val2014/COCO_val2014_000000119785.jpg -../coco/images/val2014/COCO_val2014_000000119964.jpg -../coco/images/val2014/COCO_val2014_000000120248.jpg -../coco/images/val2014/COCO_val2014_000000120380.jpg -../coco/images/val2014/COCO_val2014_000000120682.jpg -../coco/images/val2014/COCO_val2014_000000120767.jpg -../coco/images/val2014/COCO_val2014_000000120935.jpg -../coco/images/val2014/COCO_val2014_000000120964.jpg -../coco/images/val2014/COCO_val2014_000000121112.jpg -../coco/images/val2014/COCO_val2014_000000121417.jpg -../coco/images/val2014/COCO_val2014_000000121503.jpg -../coco/images/val2014/COCO_val2014_000000121591.jpg -../coco/images/val2014/COCO_val2014_000000121633.jpg -../coco/images/val2014/COCO_val2014_000000121817.jpg -../coco/images/val2014/COCO_val2014_000000121826.jpg -../coco/images/val2014/COCO_val2014_000000121849.jpg -../coco/images/val2014/COCO_val2014_000000122039.jpg -../coco/images/val2014/COCO_val2014_000000122166.jpg -../coco/images/val2014/COCO_val2014_000000122213.jpg -../coco/images/val2014/COCO_val2014_000000122229.jpg -../coco/images/val2014/COCO_val2014_000000122239.jpg -../coco/images/val2014/COCO_val2014_000000122266.jpg -../coco/images/val2014/COCO_val2014_000000122300.jpg -../coco/images/val2014/COCO_val2014_000000122458.jpg -../coco/images/val2014/COCO_val2014_000000122589.jpg -../coco/images/val2014/COCO_val2014_000000122678.jpg -../coco/images/val2014/COCO_val2014_000000122747.jpg -../coco/images/val2014/COCO_val2014_000000123070.jpg -../coco/images/val2014/COCO_val2014_000000123125.jpg -../coco/images/val2014/COCO_val2014_000000123220.jpg -../coco/images/val2014/COCO_val2014_000000123244.jpg -../coco/images/val2014/COCO_val2014_000000123469.jpg -../coco/images/val2014/COCO_val2014_000000123570.jpg -../coco/images/val2014/COCO_val2014_000000123622.jpg -../coco/images/val2014/COCO_val2014_000000123627.jpg -../coco/images/val2014/COCO_val2014_000000123867.jpg -../coco/images/val2014/COCO_val2014_000000123964.jpg -../coco/images/val2014/COCO_val2014_000000124013.jpg -../coco/images/val2014/COCO_val2014_000000124018.jpg -../coco/images/val2014/COCO_val2014_000000124072.jpg -../coco/images/val2014/COCO_val2014_000000124128.jpg -../coco/images/val2014/COCO_val2014_000000124157.jpg -../coco/images/val2014/COCO_val2014_000000124243.jpg -../coco/images/val2014/COCO_val2014_000000124246.jpg -../coco/images/val2014/COCO_val2014_000000124647.jpg -../coco/images/val2014/COCO_val2014_000000125051.jpg -../coco/images/val2014/COCO_val2014_000000125070.jpg -../coco/images/val2014/COCO_val2014_000000125072.jpg -../coco/images/val2014/COCO_val2014_000000125228.jpg -../coco/images/val2014/COCO_val2014_000000125286.jpg -../coco/images/val2014/COCO_val2014_000000125322.jpg -../coco/images/val2014/COCO_val2014_000000125476.jpg -../coco/images/val2014/COCO_val2014_000000125645.jpg -../coco/images/val2014/COCO_val2014_000000125815.jpg -../coco/images/val2014/COCO_val2014_000000125983.jpg -../coco/images/val2014/COCO_val2014_000000126064.jpg -../coco/images/val2014/COCO_val2014_000000126098.jpg -../coco/images/val2014/COCO_val2014_000000126216.jpg -../coco/images/val2014/COCO_val2014_000000126229.jpg -../coco/images/val2014/COCO_val2014_000000126253.jpg -../coco/images/val2014/COCO_val2014_000000126299.jpg -../coco/images/val2014/COCO_val2014_000000126833.jpg -../coco/images/val2014/COCO_val2014_000000126895.jpg -../coco/images/val2014/COCO_val2014_000000127135.jpg -../coco/images/val2014/COCO_val2014_000000127170.jpg -../coco/images/val2014/COCO_val2014_000000127192.jpg -../coco/images/val2014/COCO_val2014_000000127476.jpg -../coco/images/val2014/COCO_val2014_000000127496.jpg -../coco/images/val2014/COCO_val2014_000000127514.jpg -../coco/images/val2014/COCO_val2014_000000127520.jpg -../coco/images/val2014/COCO_val2014_000000127576.jpg -../coco/images/val2014/COCO_val2014_000000127775.jpg -../coco/images/val2014/COCO_val2014_000000127801.jpg -../coco/images/val2014/COCO_val2014_000000127955.jpg -../coco/images/val2014/COCO_val2014_000000128119.jpg -../coco/images/val2014/COCO_val2014_000000128644.jpg -../coco/images/val2014/COCO_val2014_000000128748.jpg -../coco/images/val2014/COCO_val2014_000000128849.jpg -../coco/images/val2014/COCO_val2014_000000129062.jpg -../coco/images/val2014/COCO_val2014_000000129362.jpg -../coco/images/val2014/COCO_val2014_000000129566.jpg -../coco/images/val2014/COCO_val2014_000000129735.jpg -../coco/images/val2014/COCO_val2014_000000130076.jpg -../coco/images/val2014/COCO_val2014_000000130516.jpg -../coco/images/val2014/COCO_val2014_000000130555.jpg -../coco/images/val2014/COCO_val2014_000000130579.jpg -../coco/images/val2014/COCO_val2014_000000130613.jpg -../coco/images/val2014/COCO_val2014_000000130651.jpg -../coco/images/val2014/COCO_val2014_000000130663.jpg -../coco/images/val2014/COCO_val2014_000000130699.jpg -../coco/images/val2014/COCO_val2014_000000130712.jpg -../coco/images/val2014/COCO_val2014_000000130849.jpg -../coco/images/val2014/COCO_val2014_000000131115.jpg -../coco/images/val2014/COCO_val2014_000000131138.jpg -../coco/images/val2014/COCO_val2014_000000131207.jpg -../coco/images/val2014/COCO_val2014_000000131276.jpg -../coco/images/val2014/COCO_val2014_000000131431.jpg -../coco/images/val2014/COCO_val2014_000000132001.jpg -../coco/images/val2014/COCO_val2014_000000132042.jpg -../coco/images/val2014/COCO_val2014_000000132143.jpg -../coco/images/val2014/COCO_val2014_000000132182.jpg -../coco/images/val2014/COCO_val2014_000000132223.jpg -../coco/images/val2014/COCO_val2014_000000132272.jpg -../coco/images/val2014/COCO_val2014_000000132375.jpg -../coco/images/val2014/COCO_val2014_000000132389.jpg -../coco/images/val2014/COCO_val2014_000000132510.jpg -../coco/images/val2014/COCO_val2014_000000132540.jpg -../coco/images/val2014/COCO_val2014_000000132686.jpg -../coco/images/val2014/COCO_val2014_000000132861.jpg -../coco/images/val2014/COCO_val2014_000000132992.jpg -../coco/images/val2014/COCO_val2014_000000133233.jpg -../coco/images/val2014/COCO_val2014_000000133237.jpg -../coco/images/val2014/COCO_val2014_000000133244.jpg -../coco/images/val2014/COCO_val2014_000000133251.jpg -../coco/images/val2014/COCO_val2014_000000133279.jpg -../coco/images/val2014/COCO_val2014_000000133485.jpg -../coco/images/val2014/COCO_val2014_000000133571.jpg -../coco/images/val2014/COCO_val2014_000000133611.jpg -../coco/images/val2014/COCO_val2014_000000133999.jpg -../coco/images/val2014/COCO_val2014_000000134001.jpg -../coco/images/val2014/COCO_val2014_000000134112.jpg -../coco/images/val2014/COCO_val2014_000000134133.jpg -../coco/images/val2014/COCO_val2014_000000134167.jpg -../coco/images/val2014/COCO_val2014_000000134198.jpg -../coco/images/val2014/COCO_val2014_000000134223.jpg -../coco/images/val2014/COCO_val2014_000000134537.jpg -../coco/images/val2014/COCO_val2014_000000134542.jpg -../coco/images/val2014/COCO_val2014_000000134935.jpg -../coco/images/val2014/COCO_val2014_000000135029.jpg -../coco/images/val2014/COCO_val2014_000000135266.jpg -../coco/images/val2014/COCO_val2014_000000135356.jpg -../coco/images/val2014/COCO_val2014_000000135579.jpg -../coco/images/val2014/COCO_val2014_000000135670.jpg -../coco/images/val2014/COCO_val2014_000000135671.jpg -../coco/images/val2014/COCO_val2014_000000135785.jpg -../coco/images/val2014/COCO_val2014_000000135900.jpg -../coco/images/val2014/COCO_val2014_000000135975.jpg -../coco/images/val2014/COCO_val2014_000000136008.jpg -../coco/images/val2014/COCO_val2014_000000136181.jpg -../coco/images/val2014/COCO_val2014_000000136285.jpg -../coco/images/val2014/COCO_val2014_000000136400.jpg -../coco/images/val2014/COCO_val2014_000000136458.jpg -../coco/images/val2014/COCO_val2014_000000136501.jpg -../coco/images/val2014/COCO_val2014_000000136552.jpg -../coco/images/val2014/COCO_val2014_000000136644.jpg -../coco/images/val2014/COCO_val2014_000000136718.jpg -../coco/images/val2014/COCO_val2014_000000136740.jpg -../coco/images/val2014/COCO_val2014_000000136780.jpg -../coco/images/val2014/COCO_val2014_000000136793.jpg -../coco/images/val2014/COCO_val2014_000000136870.jpg -../coco/images/val2014/COCO_val2014_000000136915.jpg -../coco/images/val2014/COCO_val2014_000000137211.jpg -../coco/images/val2014/COCO_val2014_000000137265.jpg -../coco/images/val2014/COCO_val2014_000000137271.jpg -../coco/images/val2014/COCO_val2014_000000137294.jpg -../coco/images/val2014/COCO_val2014_000000137300.jpg -../coco/images/val2014/COCO_val2014_000000137301.jpg -../coco/images/val2014/COCO_val2014_000000137395.jpg -../coco/images/val2014/COCO_val2014_000000137451.jpg -../coco/images/val2014/COCO_val2014_000000137507.jpg -../coco/images/val2014/COCO_val2014_000000137595.jpg -../coco/images/val2014/COCO_val2014_000000137658.jpg -../coco/images/val2014/COCO_val2014_000000137678.jpg -../coco/images/val2014/COCO_val2014_000000137727.jpg -../coco/images/val2014/COCO_val2014_000000137803.jpg -../coco/images/val2014/COCO_val2014_000000137993.jpg -../coco/images/val2014/COCO_val2014_000000138070.jpg -../coco/images/val2014/COCO_val2014_000000138075.jpg -../coco/images/val2014/COCO_val2014_000000138397.jpg -../coco/images/val2014/COCO_val2014_000000138517.jpg -../coco/images/val2014/COCO_val2014_000000138573.jpg -../coco/images/val2014/COCO_val2014_000000138589.jpg -../coco/images/val2014/COCO_val2014_000000138648.jpg -../coco/images/val2014/COCO_val2014_000000138814.jpg -../coco/images/val2014/COCO_val2014_000000138937.jpg -../coco/images/val2014/COCO_val2014_000000139140.jpg -../coco/images/val2014/COCO_val2014_000000139141.jpg -../coco/images/val2014/COCO_val2014_000000139260.jpg -../coco/images/val2014/COCO_val2014_000000139294.jpg -../coco/images/val2014/COCO_val2014_000000139436.jpg -../coco/images/val2014/COCO_val2014_000000139440.jpg -../coco/images/val2014/COCO_val2014_000000139623.jpg -../coco/images/val2014/COCO_val2014_000000139871.jpg -../coco/images/val2014/COCO_val2014_000000140006.jpg -../coco/images/val2014/COCO_val2014_000000140043.jpg -../coco/images/val2014/COCO_val2014_000000140068.jpg -../coco/images/val2014/COCO_val2014_000000140087.jpg -../coco/images/val2014/COCO_val2014_000000140197.jpg -../coco/images/val2014/COCO_val2014_000000140203.jpg -../coco/images/val2014/COCO_val2014_000000140388.jpg -../coco/images/val2014/COCO_val2014_000000140661.jpg -../coco/images/val2014/COCO_val2014_000000140664.jpg -../coco/images/val2014/COCO_val2014_000000140686.jpg -../coco/images/val2014/COCO_val2014_000000140696.jpg -../coco/images/val2014/COCO_val2014_000000140987.jpg -../coco/images/val2014/COCO_val2014_000000141197.jpg -../coco/images/val2014/COCO_val2014_000000141211.jpg -../coco/images/val2014/COCO_val2014_000000141509.jpg -../coco/images/val2014/COCO_val2014_000000141517.jpg -../coco/images/val2014/COCO_val2014_000000141574.jpg -../coco/images/val2014/COCO_val2014_000000141634.jpg -../coco/images/val2014/COCO_val2014_000000141673.jpg -../coco/images/val2014/COCO_val2014_000000141760.jpg -../coco/images/val2014/COCO_val2014_000000141795.jpg -../coco/images/val2014/COCO_val2014_000000141807.jpg -../coco/images/val2014/COCO_val2014_000000141849.jpg -../coco/images/val2014/COCO_val2014_000000142092.jpg -../coco/images/val2014/COCO_val2014_000000142189.jpg -../coco/images/val2014/COCO_val2014_000000142318.jpg -../coco/images/val2014/COCO_val2014_000000142537.jpg -../coco/images/val2014/COCO_val2014_000000142941.jpg -../coco/images/val2014/COCO_val2014_000000142949.jpg -../coco/images/val2014/COCO_val2014_000000143125.jpg -../coco/images/val2014/COCO_val2014_000000143143.jpg -../coco/images/val2014/COCO_val2014_000000143174.jpg -../coco/images/val2014/COCO_val2014_000000143217.jpg -../coco/images/val2014/COCO_val2014_000000143236.jpg -../coco/images/val2014/COCO_val2014_000000143479.jpg -../coco/images/val2014/COCO_val2014_000000143644.jpg -../coco/images/val2014/COCO_val2014_000000143653.jpg -../coco/images/val2014/COCO_val2014_000000143671.jpg -../coco/images/val2014/COCO_val2014_000000143737.jpg -../coco/images/val2014/COCO_val2014_000000143769.jpg -../coco/images/val2014/COCO_val2014_000000143792.jpg -../coco/images/val2014/COCO_val2014_000000143931.jpg -../coco/images/val2014/COCO_val2014_000000144003.jpg -../coco/images/val2014/COCO_val2014_000000144058.jpg -../coco/images/val2014/COCO_val2014_000000144200.jpg -../coco/images/val2014/COCO_val2014_000000144228.jpg -../coco/images/val2014/COCO_val2014_000000144539.jpg -../coco/images/val2014/COCO_val2014_000000144985.jpg -../coco/images/val2014/COCO_val2014_000000145093.jpg -../coco/images/val2014/COCO_val2014_000000145101.jpg -../coco/images/val2014/COCO_val2014_000000145227.jpg -../coco/images/val2014/COCO_val2014_000000145295.jpg -../coco/images/val2014/COCO_val2014_000000145408.jpg -../coco/images/val2014/COCO_val2014_000000145520.jpg -../coco/images/val2014/COCO_val2014_000000145597.jpg -../coco/images/val2014/COCO_val2014_000000145620.jpg -../coco/images/val2014/COCO_val2014_000000145750.jpg -../coco/images/val2014/COCO_val2014_000000145781.jpg -../coco/images/val2014/COCO_val2014_000000145824.jpg -../coco/images/val2014/COCO_val2014_000000145831.jpg -../coco/images/val2014/COCO_val2014_000000146193.jpg -../coco/images/val2014/COCO_val2014_000000146253.jpg -../coco/images/val2014/COCO_val2014_000000146570.jpg -../coco/images/val2014/COCO_val2014_000000146614.jpg -../coco/images/val2014/COCO_val2014_000000146627.jpg -../coco/images/val2014/COCO_val2014_000000146667.jpg -../coco/images/val2014/COCO_val2014_000000146730.jpg -../coco/images/val2014/COCO_val2014_000000146830.jpg -../coco/images/val2014/COCO_val2014_000000146837.jpg -../coco/images/val2014/COCO_val2014_000000146961.jpg -../coco/images/val2014/COCO_val2014_000000147030.jpg -../coco/images/val2014/COCO_val2014_000000147058.jpg -../coco/images/val2014/COCO_val2014_000000147101.jpg -../coco/images/val2014/COCO_val2014_000000147128.jpg -../coco/images/val2014/COCO_val2014_000000147409.jpg -../coco/images/val2014/COCO_val2014_000000147556.jpg -../coco/images/val2014/COCO_val2014_000000147921.jpg -../coco/images/val2014/COCO_val2014_000000148170.jpg -../coco/images/val2014/COCO_val2014_000000148188.jpg -../coco/images/val2014/COCO_val2014_000000148458.jpg -../coco/images/val2014/COCO_val2014_000000148542.jpg -../coco/images/val2014/COCO_val2014_000000148568.jpg -../coco/images/val2014/COCO_val2014_000000148719.jpg -../coco/images/val2014/COCO_val2014_000000148792.jpg -../coco/images/val2014/COCO_val2014_000000148955.jpg -../coco/images/val2014/COCO_val2014_000000149052.jpg -../coco/images/val2014/COCO_val2014_000000149268.jpg -../coco/images/val2014/COCO_val2014_000000149329.jpg -../coco/images/val2014/COCO_val2014_000000149469.jpg -../coco/images/val2014/COCO_val2014_000000149568.jpg -../coco/images/val2014/COCO_val2014_000000149767.jpg -../coco/images/val2014/COCO_val2014_000000149890.jpg -../coco/images/val2014/COCO_val2014_000000150026.jpg -../coco/images/val2014/COCO_val2014_000000150080.jpg -../coco/images/val2014/COCO_val2014_000000150267.jpg -../coco/images/val2014/COCO_val2014_000000150301.jpg -../coco/images/val2014/COCO_val2014_000000150317.jpg -../coco/images/val2014/COCO_val2014_000000150320.jpg -../coco/images/val2014/COCO_val2014_000000150417.jpg -../coco/images/val2014/COCO_val2014_000000150538.jpg -../coco/images/val2014/COCO_val2014_000000150763.jpg -../coco/images/val2014/COCO_val2014_000000150843.jpg -../coco/images/val2014/COCO_val2014_000000150874.jpg -../coco/images/val2014/COCO_val2014_000000150888.jpg -../coco/images/val2014/COCO_val2014_000000151005.jpg -../coco/images/val2014/COCO_val2014_000000151159.jpg -../coco/images/val2014/COCO_val2014_000000151558.jpg -../coco/images/val2014/COCO_val2014_000000151585.jpg -../coco/images/val2014/COCO_val2014_000000151657.jpg -../coco/images/val2014/COCO_val2014_000000151704.jpg -../coco/images/val2014/COCO_val2014_000000151733.jpg -../coco/images/val2014/COCO_val2014_000000151790.jpg -../coco/images/val2014/COCO_val2014_000000151911.jpg -../coco/images/val2014/COCO_val2014_000000151962.jpg -../coco/images/val2014/COCO_val2014_000000151970.jpg -../coco/images/val2014/COCO_val2014_000000151988.jpg -../coco/images/val2014/COCO_val2014_000000152000.jpg -../coco/images/val2014/COCO_val2014_000000152192.jpg -../coco/images/val2014/COCO_val2014_000000152208.jpg -../coco/images/val2014/COCO_val2014_000000152245.jpg -../coco/images/val2014/COCO_val2014_000000152330.jpg -../coco/images/val2014/COCO_val2014_000000152340.jpg -../coco/images/val2014/COCO_val2014_000000152499.jpg -../coco/images/val2014/COCO_val2014_000000152751.jpg -../coco/images/val2014/COCO_val2014_000000153011.jpg -../coco/images/val2014/COCO_val2014_000000153038.jpg -../coco/images/val2014/COCO_val2014_000000153061.jpg -../coco/images/val2014/COCO_val2014_000000153094.jpg -../coco/images/val2014/COCO_val2014_000000153231.jpg -../coco/images/val2014/COCO_val2014_000000153300.jpg -../coco/images/val2014/COCO_val2014_000000153486.jpg -../coco/images/val2014/COCO_val2014_000000153520.jpg -../coco/images/val2014/COCO_val2014_000000153563.jpg -../coco/images/val2014/COCO_val2014_000000153578.jpg -../coco/images/val2014/COCO_val2014_000000153697.jpg -../coco/images/val2014/COCO_val2014_000000153822.jpg -../coco/images/val2014/COCO_val2014_000000153896.jpg -../coco/images/val2014/COCO_val2014_000000154004.jpg -../coco/images/val2014/COCO_val2014_000000154053.jpg -../coco/images/val2014/COCO_val2014_000000154095.jpg -../coco/images/val2014/COCO_val2014_000000154363.jpg -../coco/images/val2014/COCO_val2014_000000154423.jpg -../coco/images/val2014/COCO_val2014_000000154520.jpg -../coco/images/val2014/COCO_val2014_000000154705.jpg -../coco/images/val2014/COCO_val2014_000000154854.jpg -../coco/images/val2014/COCO_val2014_000000155035.jpg -../coco/images/val2014/COCO_val2014_000000155087.jpg -../coco/images/val2014/COCO_val2014_000000155131.jpg -../coco/images/val2014/COCO_val2014_000000155142.jpg -../coco/images/val2014/COCO_val2014_000000155443.jpg -../coco/images/val2014/COCO_val2014_000000155671.jpg -../coco/images/val2014/COCO_val2014_000000155811.jpg -../coco/images/val2014/COCO_val2014_000000155861.jpg -../coco/images/val2014/COCO_val2014_000000156025.jpg -../coco/images/val2014/COCO_val2014_000000156292.jpg -../coco/images/val2014/COCO_val2014_000000156466.jpg -../coco/images/val2014/COCO_val2014_000000156636.jpg -../coco/images/val2014/COCO_val2014_000000156756.jpg -../coco/images/val2014/COCO_val2014_000000156834.jpg -../coco/images/val2014/COCO_val2014_000000156924.jpg -../coco/images/val2014/COCO_val2014_000000157109.jpg -../coco/images/val2014/COCO_val2014_000000157352.jpg -../coco/images/val2014/COCO_val2014_000000157365.jpg -../coco/images/val2014/COCO_val2014_000000157465.jpg -../coco/images/val2014/COCO_val2014_000000157592.jpg -../coco/images/val2014/COCO_val2014_000000157756.jpg -../coco/images/val2014/COCO_val2014_000000157938.jpg -../coco/images/val2014/COCO_val2014_000000158227.jpg -../coco/images/val2014/COCO_val2014_000000158272.jpg -../coco/images/val2014/COCO_val2014_000000158412.jpg -../coco/images/val2014/COCO_val2014_000000158494.jpg -../coco/images/val2014/COCO_val2014_000000158563.jpg -../coco/images/val2014/COCO_val2014_000000158583.jpg -../coco/images/val2014/COCO_val2014_000000158660.jpg -../coco/images/val2014/COCO_val2014_000000158795.jpg -../coco/images/val2014/COCO_val2014_000000158999.jpg -../coco/images/val2014/COCO_val2014_000000159269.jpg -../coco/images/val2014/COCO_val2014_000000159282.jpg -../coco/images/val2014/COCO_val2014_000000159377.jpg -../coco/images/val2014/COCO_val2014_000000159458.jpg -../coco/images/val2014/COCO_val2014_000000159606.jpg -../coco/images/val2014/COCO_val2014_000000159791.jpg -../coco/images/val2014/COCO_val2014_000000159981.jpg -../coco/images/val2014/COCO_val2014_000000160025.jpg -../coco/images/val2014/COCO_val2014_000000160185.jpg -../coco/images/val2014/COCO_val2014_000000160276.jpg -../coco/images/val2014/COCO_val2014_000000160345.jpg -../coco/images/val2014/COCO_val2014_000000160556.jpg -../coco/images/val2014/COCO_val2014_000000160580.jpg -../coco/images/val2014/COCO_val2014_000000160607.jpg -../coco/images/val2014/COCO_val2014_000000160772.jpg -../coco/images/val2014/COCO_val2014_000000160828.jpg -../coco/images/val2014/COCO_val2014_000000160886.jpg -../coco/images/val2014/COCO_val2014_000000160941.jpg -../coco/images/val2014/COCO_val2014_000000161044.jpg -../coco/images/val2014/COCO_val2014_000000161060.jpg -../coco/images/val2014/COCO_val2014_000000161185.jpg -../coco/images/val2014/COCO_val2014_000000161231.jpg -../coco/images/val2014/COCO_val2014_000000161308.jpg -../coco/images/val2014/COCO_val2014_000000161781.jpg -../coco/images/val2014/COCO_val2014_000000161799.jpg -../coco/images/val2014/COCO_val2014_000000161810.jpg -../coco/images/val2014/COCO_val2014_000000161820.jpg -../coco/images/val2014/COCO_val2014_000000161861.jpg -../coco/images/val2014/COCO_val2014_000000161875.jpg -../coco/images/val2014/COCO_val2014_000000161990.jpg -../coco/images/val2014/COCO_val2014_000000162280.jpg -../coco/images/val2014/COCO_val2014_000000162445.jpg -../coco/images/val2014/COCO_val2014_000000162459.jpg -../coco/images/val2014/COCO_val2014_000000162530.jpg -../coco/images/val2014/COCO_val2014_000000162561.jpg -../coco/images/val2014/COCO_val2014_000000162580.jpg -../coco/images/val2014/COCO_val2014_000000162855.jpg -../coco/images/val2014/COCO_val2014_000000163012.jpg -../coco/images/val2014/COCO_val2014_000000163020.jpg -../coco/images/val2014/COCO_val2014_000000163138.jpg -../coco/images/val2014/COCO_val2014_000000163219.jpg -../coco/images/val2014/COCO_val2014_000000163260.jpg -../coco/images/val2014/COCO_val2014_000000163290.jpg -../coco/images/val2014/COCO_val2014_000000163316.jpg -../coco/images/val2014/COCO_val2014_000000163543.jpg -../coco/images/val2014/COCO_val2014_000000163775.jpg -../coco/images/val2014/COCO_val2014_000000164121.jpg -../coco/images/val2014/COCO_val2014_000000164366.jpg -../coco/images/val2014/COCO_val2014_000000164420.jpg -../coco/images/val2014/COCO_val2014_000000164440.jpg -../coco/images/val2014/COCO_val2014_000000164568.jpg -../coco/images/val2014/COCO_val2014_000000164835.jpg -../coco/images/val2014/COCO_val2014_000000164983.jpg -../coco/images/val2014/COCO_val2014_000000165035.jpg -../coco/images/val2014/COCO_val2014_000000165056.jpg -../coco/images/val2014/COCO_val2014_000000165157.jpg -../coco/images/val2014/COCO_val2014_000000165172.jpg -../coco/images/val2014/COCO_val2014_000000165353.jpg -../coco/images/val2014/COCO_val2014_000000165522.jpg -../coco/images/val2014/COCO_val2014_000000165752.jpg -../coco/images/val2014/COCO_val2014_000000165937.jpg -../coco/images/val2014/COCO_val2014_000000166320.jpg -../coco/images/val2014/COCO_val2014_000000166557.jpg -../coco/images/val2014/COCO_val2014_000000166565.jpg -../coco/images/val2014/COCO_val2014_000000166642.jpg -../coco/images/val2014/COCO_val2014_000000166645.jpg -../coco/images/val2014/COCO_val2014_000000166896.jpg -../coco/images/val2014/COCO_val2014_000000167044.jpg -../coco/images/val2014/COCO_val2014_000000167128.jpg -../coco/images/val2014/COCO_val2014_000000167152.jpg -../coco/images/val2014/COCO_val2014_000000167452.jpg -../coco/images/val2014/COCO_val2014_000000167583.jpg -../coco/images/val2014/COCO_val2014_000000167598.jpg -../coco/images/val2014/COCO_val2014_000000168031.jpg -../coco/images/val2014/COCO_val2014_000000168129.jpg -../coco/images/val2014/COCO_val2014_000000168353.jpg -../coco/images/val2014/COCO_val2014_000000168367.jpg -../coco/images/val2014/COCO_val2014_000000168455.jpg -../coco/images/val2014/COCO_val2014_000000168832.jpg -../coco/images/val2014/COCO_val2014_000000168837.jpg -../coco/images/val2014/COCO_val2014_000000168909.jpg -../coco/images/val2014/COCO_val2014_000000169076.jpg -../coco/images/val2014/COCO_val2014_000000169226.jpg -../coco/images/val2014/COCO_val2014_000000169505.jpg -../coco/images/val2014/COCO_val2014_000000169700.jpg -../coco/images/val2014/COCO_val2014_000000169757.jpg -../coco/images/val2014/COCO_val2014_000000169800.jpg -../coco/images/val2014/COCO_val2014_000000170015.jpg -../coco/images/val2014/COCO_val2014_000000170072.jpg -../coco/images/val2014/COCO_val2014_000000170173.jpg -../coco/images/val2014/COCO_val2014_000000170190.jpg -../coco/images/val2014/COCO_val2014_000000170194.jpg -../coco/images/val2014/COCO_val2014_000000170208.jpg -../coco/images/val2014/COCO_val2014_000000170278.jpg -../coco/images/val2014/COCO_val2014_000000170346.jpg -../coco/images/val2014/COCO_val2014_000000170401.jpg -../coco/images/val2014/COCO_val2014_000000170411.jpg -../coco/images/val2014/COCO_val2014_000000170442.jpg -../coco/images/val2014/COCO_val2014_000000170739.jpg -../coco/images/val2014/COCO_val2014_000000170813.jpg -../coco/images/val2014/COCO_val2014_000000170914.jpg -../coco/images/val2014/COCO_val2014_000000170950.jpg -../coco/images/val2014/COCO_val2014_000000170955.jpg -../coco/images/val2014/COCO_val2014_000000171335.jpg -../coco/images/val2014/COCO_val2014_000000171483.jpg -../coco/images/val2014/COCO_val2014_000000171548.jpg -../coco/images/val2014/COCO_val2014_000000171733.jpg -../coco/images/val2014/COCO_val2014_000000171942.jpg -../coco/images/val2014/COCO_val2014_000000172087.jpg -../coco/images/val2014/COCO_val2014_000000172616.jpg -../coco/images/val2014/COCO_val2014_000000172710.jpg -../coco/images/val2014/COCO_val2014_000000172877.jpg -../coco/images/val2014/COCO_val2014_000000172935.jpg -../coco/images/val2014/COCO_val2014_000000172946.jpg -../coco/images/val2014/COCO_val2014_000000173081.jpg -../coco/images/val2014/COCO_val2014_000000173166.jpg -../coco/images/val2014/COCO_val2014_000000173401.jpg -../coco/images/val2014/COCO_val2014_000000173434.jpg -../coco/images/val2014/COCO_val2014_000000173533.jpg -../coco/images/val2014/COCO_val2014_000000173565.jpg -../coco/images/val2014/COCO_val2014_000000173693.jpg -../coco/images/val2014/COCO_val2014_000000173737.jpg -../coco/images/val2014/COCO_val2014_000000173832.jpg -../coco/images/val2014/COCO_val2014_000000173897.jpg -../coco/images/val2014/COCO_val2014_000000174018.jpg -../coco/images/val2014/COCO_val2014_000000174425.jpg -../coco/images/val2014/COCO_val2014_000000174679.jpg -../coco/images/val2014/COCO_val2014_000000174690.jpg -../coco/images/val2014/COCO_val2014_000000174904.jpg -../coco/images/val2014/COCO_val2014_000000175570.jpg -../coco/images/val2014/COCO_val2014_000000175612.jpg -../coco/images/val2014/COCO_val2014_000000175825.jpg -../coco/images/val2014/COCO_val2014_000000175908.jpg -../coco/images/val2014/COCO_val2014_000000175948.jpg -../coco/images/val2014/COCO_val2014_000000176288.jpg -../coco/images/val2014/COCO_val2014_000000176362.jpg -../coco/images/val2014/COCO_val2014_000000176606.jpg -../coco/images/val2014/COCO_val2014_000000176696.jpg -../coco/images/val2014/COCO_val2014_000000176701.jpg -../coco/images/val2014/COCO_val2014_000000176744.jpg -../coco/images/val2014/COCO_val2014_000000176828.jpg -../coco/images/val2014/COCO_val2014_000000176906.jpg -../coco/images/val2014/COCO_val2014_000000177069.jpg -../coco/images/val2014/COCO_val2014_000000177149.jpg -../coco/images/val2014/COCO_val2014_000000177166.jpg -../coco/images/val2014/COCO_val2014_000000177173.jpg -../coco/images/val2014/COCO_val2014_000000177375.jpg -../coco/images/val2014/COCO_val2014_000000177452.jpg -../coco/images/val2014/COCO_val2014_000000177575.jpg -../coco/images/val2014/COCO_val2014_000000177802.jpg -../coco/images/val2014/COCO_val2014_000000177838.jpg -../coco/images/val2014/COCO_val2014_000000177856.jpg -../coco/images/val2014/COCO_val2014_000000177953.jpg -../coco/images/val2014/COCO_val2014_000000178084.jpg -../coco/images/val2014/COCO_val2014_000000178671.jpg -../coco/images/val2014/COCO_val2014_000000178810.jpg -../coco/images/val2014/COCO_val2014_000000179069.jpg -../coco/images/val2014/COCO_val2014_000000179112.jpg -../coco/images/val2014/COCO_val2014_000000179200.jpg -../coco/images/val2014/COCO_val2014_000000179229.jpg -../coco/images/val2014/COCO_val2014_000000179273.jpg -../coco/images/val2014/COCO_val2014_000000179392.jpg -../coco/images/val2014/COCO_val2014_000000179430.jpg -../coco/images/val2014/COCO_val2014_000000179487.jpg -../coco/images/val2014/COCO_val2014_000000179500.jpg -../coco/images/val2014/COCO_val2014_000000179578.jpg -../coco/images/val2014/COCO_val2014_000000179611.jpg -../coco/images/val2014/COCO_val2014_000000179642.jpg -../coco/images/val2014/COCO_val2014_000000179765.jpg -../coco/images/val2014/COCO_val2014_000000179930.jpg -../coco/images/val2014/COCO_val2014_000000180011.jpg -../coco/images/val2014/COCO_val2014_000000180154.jpg -../coco/images/val2014/COCO_val2014_000000180289.jpg -../coco/images/val2014/COCO_val2014_000000180479.jpg -../coco/images/val2014/COCO_val2014_000000180541.jpg -../coco/images/val2014/COCO_val2014_000000180830.jpg -../coco/images/val2014/COCO_val2014_000000180917.jpg -../coco/images/val2014/COCO_val2014_000000181256.jpg -../coco/images/val2014/COCO_val2014_000000181296.jpg -../coco/images/val2014/COCO_val2014_000000181303.jpg -../coco/images/val2014/COCO_val2014_000000181359.jpg -../coco/images/val2014/COCO_val2014_000000181449.jpg -../coco/images/val2014/COCO_val2014_000000181485.jpg -../coco/images/val2014/COCO_val2014_000000181572.jpg -../coco/images/val2014/COCO_val2014_000000181586.jpg -../coco/images/val2014/COCO_val2014_000000181714.jpg -../coco/images/val2014/COCO_val2014_000000181745.jpg -../coco/images/val2014/COCO_val2014_000000181969.jpg -../coco/images/val2014/COCO_val2014_000000182021.jpg -../coco/images/val2014/COCO_val2014_000000182155.jpg -../coco/images/val2014/COCO_val2014_000000182240.jpg -../coco/images/val2014/COCO_val2014_000000182362.jpg -../coco/images/val2014/COCO_val2014_000000182369.jpg -../coco/images/val2014/COCO_val2014_000000182398.jpg -../coco/images/val2014/COCO_val2014_000000182483.jpg -../coco/images/val2014/COCO_val2014_000000182523.jpg -../coco/images/val2014/COCO_val2014_000000182681.jpg -../coco/images/val2014/COCO_val2014_000000182874.jpg -../coco/images/val2014/COCO_val2014_000000183187.jpg -../coco/images/val2014/COCO_val2014_000000183199.jpg -../coco/images/val2014/COCO_val2014_000000183217.jpg -../coco/images/val2014/COCO_val2014_000000183348.jpg -../coco/images/val2014/COCO_val2014_000000183359.jpg -../coco/images/val2014/COCO_val2014_000000183364.jpg -../coco/images/val2014/COCO_val2014_000000183469.jpg -../coco/images/val2014/COCO_val2014_000000183571.jpg -../coco/images/val2014/COCO_val2014_000000183701.jpg -../coco/images/val2014/COCO_val2014_000000183716.jpg -../coco/images/val2014/COCO_val2014_000000183843.jpg -../coco/images/val2014/COCO_val2014_000000184276.jpg -../coco/images/val2014/COCO_val2014_000000184359.jpg -../coco/images/val2014/COCO_val2014_000000184590.jpg -../coco/images/val2014/COCO_val2014_000000185095.jpg -../coco/images/val2014/COCO_val2014_000000185156.jpg -../coco/images/val2014/COCO_val2014_000000185303.jpg -../coco/images/val2014/COCO_val2014_000000185366.jpg -../coco/images/val2014/COCO_val2014_000000185397.jpg -../coco/images/val2014/COCO_val2014_000000185472.jpg -../coco/images/val2014/COCO_val2014_000000185559.jpg -../coco/images/val2014/COCO_val2014_000000185620.jpg -../coco/images/val2014/COCO_val2014_000000185621.jpg -../coco/images/val2014/COCO_val2014_000000185697.jpg -../coco/images/val2014/COCO_val2014_000000185721.jpg -../coco/images/val2014/COCO_val2014_000000185756.jpg -../coco/images/val2014/COCO_val2014_000000185802.jpg -../coco/images/val2014/COCO_val2014_000000185890.jpg -../coco/images/val2014/COCO_val2014_000000185916.jpg -../coco/images/val2014/COCO_val2014_000000185988.jpg -../coco/images/val2014/COCO_val2014_000000186079.jpg -../coco/images/val2014/COCO_val2014_000000186125.jpg -../coco/images/val2014/COCO_val2014_000000186413.jpg -../coco/images/val2014/COCO_val2014_000000186422.jpg -../coco/images/val2014/COCO_val2014_000000186637.jpg -../coco/images/val2014/COCO_val2014_000000186788.jpg -../coco/images/val2014/COCO_val2014_000000186873.jpg -../coco/images/val2014/COCO_val2014_000000186977.jpg -../coco/images/val2014/COCO_val2014_000000186991.jpg -../coco/images/val2014/COCO_val2014_000000187036.jpg -../coco/images/val2014/COCO_val2014_000000187054.jpg -../coco/images/val2014/COCO_val2014_000000187199.jpg -../coco/images/val2014/COCO_val2014_000000187236.jpg -../coco/images/val2014/COCO_val2014_000000187249.jpg -../coco/images/val2014/COCO_val2014_000000187349.jpg -../coco/images/val2014/COCO_val2014_000000187424.jpg -../coco/images/val2014/COCO_val2014_000000187513.jpg -../coco/images/val2014/COCO_val2014_000000187533.jpg -../coco/images/val2014/COCO_val2014_000000188084.jpg -../coco/images/val2014/COCO_val2014_000000188109.jpg -../coco/images/val2014/COCO_val2014_000000188132.jpg -../coco/images/val2014/COCO_val2014_000000188311.jpg -../coco/images/val2014/COCO_val2014_000000188346.jpg -../coco/images/val2014/COCO_val2014_000000188439.jpg -../coco/images/val2014/COCO_val2014_000000188460.jpg -../coco/images/val2014/COCO_val2014_000000188534.jpg -../coco/images/val2014/COCO_val2014_000000188592.jpg -../coco/images/val2014/COCO_val2014_000000188616.jpg -../coco/images/val2014/COCO_val2014_000000188667.jpg -../coco/images/val2014/COCO_val2014_000000188852.jpg -../coco/images/val2014/COCO_val2014_000000188918.jpg -../coco/images/val2014/COCO_val2014_000000188948.jpg -../coco/images/val2014/COCO_val2014_000000189067.jpg -../coco/images/val2014/COCO_val2014_000000189078.jpg -../coco/images/val2014/COCO_val2014_000000189203.jpg -../coco/images/val2014/COCO_val2014_000000189305.jpg -../coco/images/val2014/COCO_val2014_000000189365.jpg -../coco/images/val2014/COCO_val2014_000000189368.jpg -../coco/images/val2014/COCO_val2014_000000189371.jpg -../coco/images/val2014/COCO_val2014_000000189427.jpg -../coco/images/val2014/COCO_val2014_000000189436.jpg -../coco/images/val2014/COCO_val2014_000000189566.jpg -../coco/images/val2014/COCO_val2014_000000189634.jpg -../coco/images/val2014/COCO_val2014_000000189714.jpg -../coco/images/val2014/COCO_val2014_000000190204.jpg -../coco/images/val2014/COCO_val2014_000000190395.jpg -../coco/images/val2014/COCO_val2014_000000190432.jpg -../coco/images/val2014/COCO_val2014_000000190441.jpg -../coco/images/val2014/COCO_val2014_000000190546.jpg -../coco/images/val2014/COCO_val2014_000000190595.jpg -../coco/images/val2014/COCO_val2014_000000190700.jpg -../coco/images/val2014/COCO_val2014_000000190753.jpg -../coco/images/val2014/COCO_val2014_000000190767.jpg -../coco/images/val2014/COCO_val2014_000000190776.jpg -../coco/images/val2014/COCO_val2014_000000190841.jpg -../coco/images/val2014/COCO_val2014_000000190853.jpg -../coco/images/val2014/COCO_val2014_000000191013.jpg -../coco/images/val2014/COCO_val2014_000000191096.jpg -../coco/images/val2014/COCO_val2014_000000191117.jpg -../coco/images/val2014/COCO_val2014_000000191169.jpg -../coco/images/val2014/COCO_val2014_000000191296.jpg -../coco/images/val2014/COCO_val2014_000000191300.jpg -../coco/images/val2014/COCO_val2014_000000191390.jpg -../coco/images/val2014/COCO_val2014_000000191533.jpg -../coco/images/val2014/COCO_val2014_000000191761.jpg -../coco/images/val2014/COCO_val2014_000000191919.jpg -../coco/images/val2014/COCO_val2014_000000192007.jpg -../coco/images/val2014/COCO_val2014_000000192153.jpg -../coco/images/val2014/COCO_val2014_000000192154.jpg -../coco/images/val2014/COCO_val2014_000000192212.jpg -../coco/images/val2014/COCO_val2014_000000192440.jpg -../coco/images/val2014/COCO_val2014_000000192479.jpg -../coco/images/val2014/COCO_val2014_000000192607.jpg -../coco/images/val2014/COCO_val2014_000000192716.jpg -../coco/images/val2014/COCO_val2014_000000192730.jpg -../coco/images/val2014/COCO_val2014_000000192788.jpg -../coco/images/val2014/COCO_val2014_000000192817.jpg -../coco/images/val2014/COCO_val2014_000000192834.jpg -../coco/images/val2014/COCO_val2014_000000193015.jpg -../coco/images/val2014/COCO_val2014_000000193108.jpg -../coco/images/val2014/COCO_val2014_000000193245.jpg -../coco/images/val2014/COCO_val2014_000000193271.jpg -../coco/images/val2014/COCO_val2014_000000193332.jpg -../coco/images/val2014/COCO_val2014_000000193380.jpg -../coco/images/val2014/COCO_val2014_000000193405.jpg -../coco/images/val2014/COCO_val2014_000000193661.jpg -../coco/images/val2014/COCO_val2014_000000193798.jpg -../coco/images/val2014/COCO_val2014_000000193881.jpg -../coco/images/val2014/COCO_val2014_000000194158.jpg -../coco/images/val2014/COCO_val2014_000000194306.jpg -../coco/images/val2014/COCO_val2014_000000194704.jpg -../coco/images/val2014/COCO_val2014_000000194790.jpg -../coco/images/val2014/COCO_val2014_000000194875.jpg -../coco/images/val2014/COCO_val2014_000000195079.jpg -../coco/images/val2014/COCO_val2014_000000195267.jpg -../coco/images/val2014/COCO_val2014_000000195271.jpg -../coco/images/val2014/COCO_val2014_000000195281.jpg -../coco/images/val2014/COCO_val2014_000000195798.jpg -../coco/images/val2014/COCO_val2014_000000195851.jpg -../coco/images/val2014/COCO_val2014_000000195897.jpg -../coco/images/val2014/COCO_val2014_000000196085.jpg -../coco/images/val2014/COCO_val2014_000000196141.jpg -../coco/images/val2014/COCO_val2014_000000196295.jpg -../coco/images/val2014/COCO_val2014_000000196311.jpg -../coco/images/val2014/COCO_val2014_000000196313.jpg -../coco/images/val2014/COCO_val2014_000000196355.jpg -../coco/images/val2014/COCO_val2014_000000196415.jpg -../coco/images/val2014/COCO_val2014_000000196453.jpg -../coco/images/val2014/COCO_val2014_000000196681.jpg -../coco/images/val2014/COCO_val2014_000000196754.jpg -../coco/images/val2014/COCO_val2014_000000196798.jpg -../coco/images/val2014/COCO_val2014_000000196852.jpg -../coco/images/val2014/COCO_val2014_000000197022.jpg -../coco/images/val2014/COCO_val2014_000000197097.jpg -../coco/images/val2014/COCO_val2014_000000197191.jpg -../coco/images/val2014/COCO_val2014_000000197266.jpg -../coco/images/val2014/COCO_val2014_000000197278.jpg -../coco/images/val2014/COCO_val2014_000000197528.jpg -../coco/images/val2014/COCO_val2014_000000197609.jpg -../coco/images/val2014/COCO_val2014_000000197652.jpg -../coco/images/val2014/COCO_val2014_000000197683.jpg -../coco/images/val2014/COCO_val2014_000000197796.jpg -../coco/images/val2014/COCO_val2014_000000197918.jpg -../coco/images/val2014/COCO_val2014_000000198075.jpg -../coco/images/val2014/COCO_val2014_000000198139.jpg -../coco/images/val2014/COCO_val2014_000000198223.jpg -../coco/images/val2014/COCO_val2014_000000198367.jpg -../coco/images/val2014/COCO_val2014_000000198464.jpg -../coco/images/val2014/COCO_val2014_000000198495.jpg -../coco/images/val2014/COCO_val2014_000000198641.jpg -../coco/images/val2014/COCO_val2014_000000198645.jpg -../coco/images/val2014/COCO_val2014_000000198752.jpg -../coco/images/val2014/COCO_val2014_000000198805.jpg -../coco/images/val2014/COCO_val2014_000000198811.jpg -../coco/images/val2014/COCO_val2014_000000199125.jpg -../coco/images/val2014/COCO_val2014_000000199203.jpg -../coco/images/val2014/COCO_val2014_000000199358.jpg -../coco/images/val2014/COCO_val2014_000000199389.jpg -../coco/images/val2014/COCO_val2014_000000199437.jpg -../coco/images/val2014/COCO_val2014_000000199449.jpg -../coco/images/val2014/COCO_val2014_000000199481.jpg -../coco/images/val2014/COCO_val2014_000000199575.jpg -../coco/images/val2014/COCO_val2014_000000199602.jpg -../coco/images/val2014/COCO_val2014_000000199771.jpg -../coco/images/val2014/COCO_val2014_000000199951.jpg -../coco/images/val2014/COCO_val2014_000000200109.jpg -../coco/images/val2014/COCO_val2014_000000200252.jpg -../coco/images/val2014/COCO_val2014_000000200267.jpg -../coco/images/val2014/COCO_val2014_000000200296.jpg -../coco/images/val2014/COCO_val2014_000000200457.jpg -../coco/images/val2014/COCO_val2014_000000200572.jpg -../coco/images/val2014/COCO_val2014_000000200638.jpg -../coco/images/val2014/COCO_val2014_000000200667.jpg -../coco/images/val2014/COCO_val2014_000000200703.jpg -../coco/images/val2014/COCO_val2014_000000200720.jpg -../coco/images/val2014/COCO_val2014_000000200725.jpg -../coco/images/val2014/COCO_val2014_000000200739.jpg -../coco/images/val2014/COCO_val2014_000000201111.jpg -../coco/images/val2014/COCO_val2014_000000201220.jpg -../coco/images/val2014/COCO_val2014_000000201348.jpg -../coco/images/val2014/COCO_val2014_000000201452.jpg -../coco/images/val2014/COCO_val2014_000000201646.jpg -../coco/images/val2014/COCO_val2014_000000201676.jpg -../coco/images/val2014/COCO_val2014_000000201918.jpg -../coco/images/val2014/COCO_val2014_000000201934.jpg -../coco/images/val2014/COCO_val2014_000000201970.jpg -../coco/images/val2014/COCO_val2014_000000202138.jpg -../coco/images/val2014/COCO_val2014_000000202339.jpg -../coco/images/val2014/COCO_val2014_000000202503.jpg -../coco/images/val2014/COCO_val2014_000000202658.jpg -../coco/images/val2014/COCO_val2014_000000202797.jpg -../coco/images/val2014/COCO_val2014_000000202799.jpg -../coco/images/val2014/COCO_val2014_000000202944.jpg -../coco/images/val2014/COCO_val2014_000000203061.jpg -../coco/images/val2014/COCO_val2014_000000203095.jpg -../coco/images/val2014/COCO_val2014_000000203299.jpg -../coco/images/val2014/COCO_val2014_000000203382.jpg -../coco/images/val2014/COCO_val2014_000000203416.jpg -../coco/images/val2014/COCO_val2014_000000203460.jpg -../coco/images/val2014/COCO_val2014_000000203483.jpg -../coco/images/val2014/COCO_val2014_000000203661.jpg -../coco/images/val2014/COCO_val2014_000000203845.jpg -../coco/images/val2014/COCO_val2014_000000203846.jpg -../coco/images/val2014/COCO_val2014_000000204036.jpg -../coco/images/val2014/COCO_val2014_000000204098.jpg -../coco/images/val2014/COCO_val2014_000000204232.jpg -../coco/images/val2014/COCO_val2014_000000204256.jpg -../coco/images/val2014/COCO_val2014_000000204360.jpg -../coco/images/val2014/COCO_val2014_000000204448.jpg -../coco/images/val2014/COCO_val2014_000000204502.jpg -../coco/images/val2014/COCO_val2014_000000204935.jpg -../coco/images/val2014/COCO_val2014_000000205222.jpg -../coco/images/val2014/COCO_val2014_000000205251.jpg -../coco/images/val2014/COCO_val2014_000000205258.jpg -../coco/images/val2014/COCO_val2014_000000205289.jpg -../coco/images/val2014/COCO_val2014_000000205300.jpg -../coco/images/val2014/COCO_val2014_000000205409.jpg -../coco/images/val2014/COCO_val2014_000000205594.jpg -../coco/images/val2014/COCO_val2014_000000205605.jpg -../coco/images/val2014/COCO_val2014_000000205676.jpg -../coco/images/val2014/COCO_val2014_000000205776.jpg -../coco/images/val2014/COCO_val2014_000000205782.jpg -../coco/images/val2014/COCO_val2014_000000205911.jpg -../coco/images/val2014/COCO_val2014_000000206025.jpg -../coco/images/val2014/COCO_val2014_000000206027.jpg -../coco/images/val2014/COCO_val2014_000000206135.jpg -../coco/images/val2014/COCO_val2014_000000206271.jpg -../coco/images/val2014/COCO_val2014_000000206411.jpg -../coco/images/val2014/COCO_val2014_000000206770.jpg -../coco/images/val2014/COCO_val2014_000000206958.jpg -../coco/images/val2014/COCO_val2014_000000207041.jpg -../coco/images/val2014/COCO_val2014_000000207059.jpg -../coco/images/val2014/COCO_val2014_000000207060.jpg -../coco/images/val2014/COCO_val2014_000000207180.jpg -../coco/images/val2014/COCO_val2014_000000207205.jpg -../coco/images/val2014/COCO_val2014_000000207323.jpg -../coco/images/val2014/COCO_val2014_000000207507.jpg -../coco/images/val2014/COCO_val2014_000000207509.jpg -../coco/images/val2014/COCO_val2014_000000207585.jpg -../coco/images/val2014/COCO_val2014_000000207634.jpg -../coco/images/val2014/COCO_val2014_000000207670.jpg -../coco/images/val2014/COCO_val2014_000000207898.jpg -../coco/images/val2014/COCO_val2014_000000207925.jpg -../coco/images/val2014/COCO_val2014_000000208012.jpg -../coco/images/val2014/COCO_val2014_000000208283.jpg -../coco/images/val2014/COCO_val2014_000000208311.jpg -../coco/images/val2014/COCO_val2014_000000208376.jpg -../coco/images/val2014/COCO_val2014_000000208417.jpg -../coco/images/val2014/COCO_val2014_000000208524.jpg -../coco/images/val2014/COCO_val2014_000000208663.jpg -../coco/images/val2014/COCO_val2014_000000208793.jpg -../coco/images/val2014/COCO_val2014_000000209007.jpg -../coco/images/val2014/COCO_val2014_000000209015.jpg -../coco/images/val2014/COCO_val2014_000000209142.jpg -../coco/images/val2014/COCO_val2014_000000209162.jpg -../coco/images/val2014/COCO_val2014_000000209286.jpg -../coco/images/val2014/COCO_val2014_000000209441.jpg -../coco/images/val2014/COCO_val2014_000000209530.jpg -../coco/images/val2014/COCO_val2014_000000209733.jpg -../coco/images/val2014/COCO_val2014_000000209773.jpg -../coco/images/val2014/COCO_val2014_000000209808.jpg -../coco/images/val2014/COCO_val2014_000000209864.jpg -../coco/images/val2014/COCO_val2014_000000210299.jpg -../coco/images/val2014/COCO_val2014_000000210374.jpg -../coco/images/val2014/COCO_val2014_000000210408.jpg -../coco/images/val2014/COCO_val2014_000000210439.jpg -../coco/images/val2014/COCO_val2014_000000210457.jpg -../coco/images/val2014/COCO_val2014_000000210458.jpg -../coco/images/val2014/COCO_val2014_000000210520.jpg -../coco/images/val2014/COCO_val2014_000000210671.jpg -../coco/images/val2014/COCO_val2014_000000210749.jpg -../coco/images/val2014/COCO_val2014_000000210855.jpg -../coco/images/val2014/COCO_val2014_000000210883.jpg -../coco/images/val2014/COCO_val2014_000000211063.jpg -../coco/images/val2014/COCO_val2014_000000211163.jpg -../coco/images/val2014/COCO_val2014_000000211186.jpg -../coco/images/val2014/COCO_val2014_000000211192.jpg -../coco/images/val2014/COCO_val2014_000000211215.jpg -../coco/images/val2014/COCO_val2014_000000211498.jpg -../coco/images/val2014/COCO_val2014_000000211775.jpg -../coco/images/val2014/COCO_val2014_000000212054.jpg -../coco/images/val2014/COCO_val2014_000000212072.jpg -../coco/images/val2014/COCO_val2014_000000212077.jpg -../coco/images/val2014/COCO_val2014_000000212080.jpg -../coco/images/val2014/COCO_val2014_000000212166.jpg -../coco/images/val2014/COCO_val2014_000000212346.jpg -../coco/images/val2014/COCO_val2014_000000212470.jpg -../coco/images/val2014/COCO_val2014_000000212559.jpg -../coco/images/val2014/COCO_val2014_000000212647.jpg -../coco/images/val2014/COCO_val2014_000000212688.jpg -../coco/images/val2014/COCO_val2014_000000212739.jpg -../coco/images/val2014/COCO_val2014_000000212817.jpg -../coco/images/val2014/COCO_val2014_000000213033.jpg -../coco/images/val2014/COCO_val2014_000000213224.jpg -../coco/images/val2014/COCO_val2014_000000213359.jpg -../coco/images/val2014/COCO_val2014_000000213361.jpg -../coco/images/val2014/COCO_val2014_000000213434.jpg -../coco/images/val2014/COCO_val2014_000000213758.jpg -../coco/images/val2014/COCO_val2014_000000213830.jpg -../coco/images/val2014/COCO_val2014_000000213843.jpg -../coco/images/val2014/COCO_val2014_000000213961.jpg -../coco/images/val2014/COCO_val2014_000000214274.jpg -../coco/images/val2014/COCO_val2014_000000214306.jpg -../coco/images/val2014/COCO_val2014_000000214853.jpg -../coco/images/val2014/COCO_val2014_000000214961.jpg -../coco/images/val2014/COCO_val2014_000000215062.jpg -../coco/images/val2014/COCO_val2014_000000215255.jpg -../coco/images/val2014/COCO_val2014_000000215259.jpg -../coco/images/val2014/COCO_val2014_000000215394.jpg -../coco/images/val2014/COCO_val2014_000000215408.jpg -../coco/images/val2014/COCO_val2014_000000215471.jpg -../coco/images/val2014/COCO_val2014_000000215554.jpg -../coco/images/val2014/COCO_val2014_000000215565.jpg -../coco/images/val2014/COCO_val2014_000000215579.jpg -../coco/images/val2014/COCO_val2014_000000215708.jpg -../coco/images/val2014/COCO_val2014_000000215812.jpg -../coco/images/val2014/COCO_val2014_000000215826.jpg -../coco/images/val2014/COCO_val2014_000000216096.jpg -../coco/images/val2014/COCO_val2014_000000216198.jpg -../coco/images/val2014/COCO_val2014_000000216235.jpg -../coco/images/val2014/COCO_val2014_000000216581.jpg -../coco/images/val2014/COCO_val2014_000000216710.jpg -../coco/images/val2014/COCO_val2014_000000216837.jpg -../coco/images/val2014/COCO_val2014_000000216841.jpg -../coco/images/val2014/COCO_val2014_000000217016.jpg -../coco/images/val2014/COCO_val2014_000000217269.jpg -../coco/images/val2014/COCO_val2014_000000217285.jpg -../coco/images/val2014/COCO_val2014_000000217303.jpg -../coco/images/val2014/COCO_val2014_000000217562.jpg -../coco/images/val2014/COCO_val2014_000000217951.jpg -../coco/images/val2014/COCO_val2014_000000218220.jpg -../coco/images/val2014/COCO_val2014_000000218310.jpg -../coco/images/val2014/COCO_val2014_000000218404.jpg -../coco/images/val2014/COCO_val2014_000000218439.jpg -../coco/images/val2014/COCO_val2014_000000218678.jpg -../coco/images/val2014/COCO_val2014_000000218687.jpg -../coco/images/val2014/COCO_val2014_000000218926.jpg -../coco/images/val2014/COCO_val2014_000000218947.jpg -../coco/images/val2014/COCO_val2014_000000219075.jpg -../coco/images/val2014/COCO_val2014_000000219170.jpg -../coco/images/val2014/COCO_val2014_000000219393.jpg -../coco/images/val2014/COCO_val2014_000000219514.jpg -../coco/images/val2014/COCO_val2014_000000219578.jpg -../coco/images/val2014/COCO_val2014_000000219657.jpg -../coco/images/val2014/COCO_val2014_000000220041.jpg -../coco/images/val2014/COCO_val2014_000000220182.jpg -../coco/images/val2014/COCO_val2014_000000220215.jpg -../coco/images/val2014/COCO_val2014_000000220307.jpg -../coco/images/val2014/COCO_val2014_000000220511.jpg -../coco/images/val2014/COCO_val2014_000000220808.jpg -../coco/images/val2014/COCO_val2014_000000221000.jpg -../coco/images/val2014/COCO_val2014_000000221094.jpg -../coco/images/val2014/COCO_val2014_000000221155.jpg -../coco/images/val2014/COCO_val2014_000000221303.jpg -../coco/images/val2014/COCO_val2014_000000221561.jpg -../coco/images/val2014/COCO_val2014_000000221605.jpg -../coco/images/val2014/COCO_val2014_000000221620.jpg -../coco/images/val2014/COCO_val2014_000000221669.jpg -../coco/images/val2014/COCO_val2014_000000221708.jpg -../coco/images/val2014/COCO_val2014_000000221882.jpg -../coco/images/val2014/COCO_val2014_000000222043.jpg -../coco/images/val2014/COCO_val2014_000000222317.jpg -../coco/images/val2014/COCO_val2014_000000222407.jpg -../coco/images/val2014/COCO_val2014_000000222494.jpg -../coco/images/val2014/COCO_val2014_000000222863.jpg -../coco/images/val2014/COCO_val2014_000000222903.jpg -../coco/images/val2014/COCO_val2014_000000223032.jpg -../coco/images/val2014/COCO_val2014_000000223276.jpg -../coco/images/val2014/COCO_val2014_000000223289.jpg -../coco/images/val2014/COCO_val2014_000000223314.jpg -../coco/images/val2014/COCO_val2014_000000223414.jpg -../coco/images/val2014/COCO_val2014_000000223747.jpg -../coco/images/val2014/COCO_val2014_000000223777.jpg -../coco/images/val2014/COCO_val2014_000000223930.jpg -../coco/images/val2014/COCO_val2014_000000224093.jpg -../coco/images/val2014/COCO_val2014_000000224111.jpg -../coco/images/val2014/COCO_val2014_000000224222.jpg -../coco/images/val2014/COCO_val2014_000000224238.jpg -../coco/images/val2014/COCO_val2014_000000224523.jpg -../coco/images/val2014/COCO_val2014_000000224693.jpg -../coco/images/val2014/COCO_val2014_000000224724.jpg -../coco/images/val2014/COCO_val2014_000000224742.jpg -../coco/images/val2014/COCO_val2014_000000224848.jpg -../coco/images/val2014/COCO_val2014_000000225175.jpg -../coco/images/val2014/COCO_val2014_000000225312.jpg -../coco/images/val2014/COCO_val2014_000000225518.jpg -../coco/images/val2014/COCO_val2014_000000225537.jpg -../coco/images/val2014/COCO_val2014_000000225603.jpg -../coco/images/val2014/COCO_val2014_000000225867.jpg -../coco/images/val2014/COCO_val2014_000000225916.jpg -../coco/images/val2014/COCO_val2014_000000226154.jpg -../coco/images/val2014/COCO_val2014_000000226220.jpg -../coco/images/val2014/COCO_val2014_000000226408.jpg -../coco/images/val2014/COCO_val2014_000000226417.jpg -../coco/images/val2014/COCO_val2014_000000226419.jpg -../coco/images/val2014/COCO_val2014_000000226496.jpg -../coco/images/val2014/COCO_val2014_000000226498.jpg -../coco/images/val2014/COCO_val2014_000000226571.jpg -../coco/images/val2014/COCO_val2014_000000226579.jpg -../coco/images/val2014/COCO_val2014_000000226588.jpg -../coco/images/val2014/COCO_val2014_000000226662.jpg -../coco/images/val2014/COCO_val2014_000000226744.jpg -../coco/images/val2014/COCO_val2014_000000226848.jpg -../coco/images/val2014/COCO_val2014_000000226917.jpg -../coco/images/val2014/COCO_val2014_000000226967.jpg -../coco/images/val2014/COCO_val2014_000000227032.jpg -../coco/images/val2014/COCO_val2014_000000227048.jpg -../coco/images/val2014/COCO_val2014_000000227125.jpg -../coco/images/val2014/COCO_val2014_000000227220.jpg -../coco/images/val2014/COCO_val2014_000000227227.jpg -../coco/images/val2014/COCO_val2014_000000227413.jpg -../coco/images/val2014/COCO_val2014_000000227468.jpg -../coco/images/val2014/COCO_val2014_000000227511.jpg -../coco/images/val2014/COCO_val2014_000000227656.jpg -../coco/images/val2014/COCO_val2014_000000227709.jpg -../coco/images/val2014/COCO_val2014_000000227741.jpg -../coco/images/val2014/COCO_val2014_000000228011.jpg -../coco/images/val2014/COCO_val2014_000000228013.jpg -../coco/images/val2014/COCO_val2014_000000228197.jpg -../coco/images/val2014/COCO_val2014_000000228558.jpg -../coco/images/val2014/COCO_val2014_000000228746.jpg -../coco/images/val2014/COCO_val2014_000000228771.jpg -../coco/images/val2014/COCO_val2014_000000229000.jpg -../coco/images/val2014/COCO_val2014_000000229221.jpg -../coco/images/val2014/COCO_val2014_000000229234.jpg -../coco/images/val2014/COCO_val2014_000000229286.jpg -../coco/images/val2014/COCO_val2014_000000229383.jpg -../coco/images/val2014/COCO_val2014_000000229387.jpg -../coco/images/val2014/COCO_val2014_000000229553.jpg -../coco/images/val2014/COCO_val2014_000000229631.jpg -../coco/images/val2014/COCO_val2014_000000229713.jpg -../coco/images/val2014/COCO_val2014_000000230040.jpg -../coco/images/val2014/COCO_val2014_000000230265.jpg -../coco/images/val2014/COCO_val2014_000000230432.jpg -../coco/images/val2014/COCO_val2014_000000230450.jpg -../coco/images/val2014/COCO_val2014_000000230454.jpg -../coco/images/val2014/COCO_val2014_000000230615.jpg -../coco/images/val2014/COCO_val2014_000000230619.jpg -../coco/images/val2014/COCO_val2014_000000230679.jpg -../coco/images/val2014/COCO_val2014_000000230701.jpg -../coco/images/val2014/COCO_val2014_000000230739.jpg -../coco/images/val2014/COCO_val2014_000000230780.jpg -../coco/images/val2014/COCO_val2014_000000230964.jpg -../coco/images/val2014/COCO_val2014_000000231364.jpg -../coco/images/val2014/COCO_val2014_000000231450.jpg -../coco/images/val2014/COCO_val2014_000000231508.jpg -../coco/images/val2014/COCO_val2014_000000231991.jpg -../coco/images/val2014/COCO_val2014_000000232073.jpg -../coco/images/val2014/COCO_val2014_000000232088.jpg -../coco/images/val2014/COCO_val2014_000000232121.jpg -../coco/images/val2014/COCO_val2014_000000232287.jpg -../coco/images/val2014/COCO_val2014_000000232453.jpg -../coco/images/val2014/COCO_val2014_000000232597.jpg -../coco/images/val2014/COCO_val2014_000000232610.jpg -../coco/images/val2014/COCO_val2014_000000232865.jpg -../coco/images/val2014/COCO_val2014_000000233042.jpg -../coco/images/val2014/COCO_val2014_000000233090.jpg -../coco/images/val2014/COCO_val2014_000000233305.jpg -../coco/images/val2014/COCO_val2014_000000233315.jpg -../coco/images/val2014/COCO_val2014_000000233327.jpg -../coco/images/val2014/COCO_val2014_000000233376.jpg -../coco/images/val2014/COCO_val2014_000000233446.jpg -../coco/images/val2014/COCO_val2014_000000233556.jpg -../coco/images/val2014/COCO_val2014_000000233567.jpg -../coco/images/val2014/COCO_val2014_000000233727.jpg -../coco/images/val2014/COCO_val2014_000000233919.jpg -../coco/images/val2014/COCO_val2014_000000233950.jpg -../coco/images/val2014/COCO_val2014_000000233961.jpg -../coco/images/val2014/COCO_val2014_000000233968.jpg -../coco/images/val2014/COCO_val2014_000000234182.jpg -../coco/images/val2014/COCO_val2014_000000234251.jpg -../coco/images/val2014/COCO_val2014_000000234370.jpg -../coco/images/val2014/COCO_val2014_000000234463.jpg -../coco/images/val2014/COCO_val2014_000000234766.jpg -../coco/images/val2014/COCO_val2014_000000234779.jpg -../coco/images/val2014/COCO_val2014_000000234928.jpg -../coco/images/val2014/COCO_val2014_000000235124.jpg -../coco/images/val2014/COCO_val2014_000000235239.jpg -../coco/images/val2014/COCO_val2014_000000235380.jpg -../coco/images/val2014/COCO_val2014_000000235575.jpg -../coco/images/val2014/COCO_val2014_000000235788.jpg -../coco/images/val2014/COCO_val2014_000000235790.jpg -../coco/images/val2014/COCO_val2014_000000235791.jpg -../coco/images/val2014/COCO_val2014_000000235839.jpg -../coco/images/val2014/COCO_val2014_000000235933.jpg -../coco/images/val2014/COCO_val2014_000000236010.jpg -../coco/images/val2014/COCO_val2014_000000236068.jpg -../coco/images/val2014/COCO_val2014_000000236323.jpg -../coco/images/val2014/COCO_val2014_000000236535.jpg -../coco/images/val2014/COCO_val2014_000000236714.jpg -../coco/images/val2014/COCO_val2014_000000236766.jpg -../coco/images/val2014/COCO_val2014_000000236874.jpg -../coco/images/val2014/COCO_val2014_000000236945.jpg -../coco/images/val2014/COCO_val2014_000000236951.jpg -../coco/images/val2014/COCO_val2014_000000236985.jpg -../coco/images/val2014/COCO_val2014_000000237230.jpg -../coco/images/val2014/COCO_val2014_000000237277.jpg -../coco/images/val2014/COCO_val2014_000000237316.jpg -../coco/images/val2014/COCO_val2014_000000237357.jpg -../coco/images/val2014/COCO_val2014_000000237476.jpg -../coco/images/val2014/COCO_val2014_000000237723.jpg -../coco/images/val2014/COCO_val2014_000000237777.jpg -../coco/images/val2014/COCO_val2014_000000237920.jpg -../coco/images/val2014/COCO_val2014_000000237984.jpg -../coco/images/val2014/COCO_val2014_000000238389.jpg -../coco/images/val2014/COCO_val2014_000000238573.jpg -../coco/images/val2014/COCO_val2014_000000238598.jpg -../coco/images/val2014/COCO_val2014_000000238700.jpg -../coco/images/val2014/COCO_val2014_000000238806.jpg -../coco/images/val2014/COCO_val2014_000000239145.jpg -../coco/images/val2014/COCO_val2014_000000239148.jpg -../coco/images/val2014/COCO_val2014_000000239318.jpg -../coco/images/val2014/COCO_val2014_000000239656.jpg -../coco/images/val2014/COCO_val2014_000000240102.jpg -../coco/images/val2014/COCO_val2014_000000240393.jpg -../coco/images/val2014/COCO_val2014_000000240403.jpg -../coco/images/val2014/COCO_val2014_000000240739.jpg -../coco/images/val2014/COCO_val2014_000000240754.jpg -../coco/images/val2014/COCO_val2014_000000240903.jpg -../coco/images/val2014/COCO_val2014_000000240918.jpg -../coco/images/val2014/COCO_val2014_000000240960.jpg -../coco/images/val2014/COCO_val2014_000000241113.jpg -../coco/images/val2014/COCO_val2014_000000241187.jpg -../coco/images/val2014/COCO_val2014_000000241291.jpg -../coco/images/val2014/COCO_val2014_000000241319.jpg -../coco/images/val2014/COCO_val2014_000000241396.jpg -../coco/images/val2014/COCO_val2014_000000241517.jpg -../coco/images/val2014/COCO_val2014_000000241638.jpg -../coco/images/val2014/COCO_val2014_000000241677.jpg -../coco/images/val2014/COCO_val2014_000000241728.jpg -../coco/images/val2014/COCO_val2014_000000241868.jpg -../coco/images/val2014/COCO_val2014_000000241889.jpg -../coco/images/val2014/COCO_val2014_000000241948.jpg -../coco/images/val2014/COCO_val2014_000000242073.jpg -../coco/images/val2014/COCO_val2014_000000242100.jpg -../coco/images/val2014/COCO_val2014_000000242189.jpg -../coco/images/val2014/COCO_val2014_000000242246.jpg -../coco/images/val2014/COCO_val2014_000000242422.jpg -../coco/images/val2014/COCO_val2014_000000242423.jpg -../coco/images/val2014/COCO_val2014_000000242523.jpg -../coco/images/val2014/COCO_val2014_000000242911.jpg -../coco/images/val2014/COCO_val2014_000000242934.jpg -../coco/images/val2014/COCO_val2014_000000242945.jpg -../coco/images/val2014/COCO_val2014_000000242972.jpg -../coco/images/val2014/COCO_val2014_000000243134.jpg -../coco/images/val2014/COCO_val2014_000000243190.jpg -../coco/images/val2014/COCO_val2014_000000243213.jpg -../coco/images/val2014/COCO_val2014_000000243331.jpg -../coco/images/val2014/COCO_val2014_000000243442.jpg -../coco/images/val2014/COCO_val2014_000000243569.jpg -../coco/images/val2014/COCO_val2014_000000243699.jpg -../coco/images/val2014/COCO_val2014_000000243775.jpg -../coco/images/val2014/COCO_val2014_000000243825.jpg -../coco/images/val2014/COCO_val2014_000000243857.jpg -../coco/images/val2014/COCO_val2014_000000244005.jpg -../coco/images/val2014/COCO_val2014_000000244050.jpg -../coco/images/val2014/COCO_val2014_000000244167.jpg -../coco/images/val2014/COCO_val2014_000000244246.jpg -../coco/images/val2014/COCO_val2014_000000244344.jpg -../coco/images/val2014/COCO_val2014_000000244571.jpg -../coco/images/val2014/COCO_val2014_000000244665.jpg -../coco/images/val2014/COCO_val2014_000000245102.jpg -../coco/images/val2014/COCO_val2014_000000245173.jpg -../coco/images/val2014/COCO_val2014_000000245242.jpg -../coco/images/val2014/COCO_val2014_000000245426.jpg -../coco/images/val2014/COCO_val2014_000000245852.jpg -../coco/images/val2014/COCO_val2014_000000246014.jpg -../coco/images/val2014/COCO_val2014_000000246233.jpg -../coco/images/val2014/COCO_val2014_000000246308.jpg -../coco/images/val2014/COCO_val2014_000000246425.jpg -../coco/images/val2014/COCO_val2014_000000246522.jpg -../coco/images/val2014/COCO_val2014_000000246649.jpg -../coco/images/val2014/COCO_val2014_000000246672.jpg -../coco/images/val2014/COCO_val2014_000000246686.jpg -../coco/images/val2014/COCO_val2014_000000247057.jpg -../coco/images/val2014/COCO_val2014_000000247123.jpg -../coco/images/val2014/COCO_val2014_000000247234.jpg -../coco/images/val2014/COCO_val2014_000000247306.jpg -../coco/images/val2014/COCO_val2014_000000247407.jpg -../coco/images/val2014/COCO_val2014_000000247788.jpg -../coco/images/val2014/COCO_val2014_000000247839.jpg -../coco/images/val2014/COCO_val2014_000000248069.jpg -../coco/images/val2014/COCO_val2014_000000248089.jpg -../coco/images/val2014/COCO_val2014_000000248112.jpg -../coco/images/val2014/COCO_val2014_000000248224.jpg -../coco/images/val2014/COCO_val2014_000000248231.jpg -../coco/images/val2014/COCO_val2014_000000248235.jpg -../coco/images/val2014/COCO_val2014_000000248276.jpg -../coco/images/val2014/COCO_val2014_000000248314.jpg -../coco/images/val2014/COCO_val2014_000000248631.jpg -../coco/images/val2014/COCO_val2014_000000249219.jpg -../coco/images/val2014/COCO_val2014_000000249295.jpg -../coco/images/val2014/COCO_val2014_000000249599.jpg -../coco/images/val2014/COCO_val2014_000000250205.jpg -../coco/images/val2014/COCO_val2014_000000250282.jpg -../coco/images/val2014/COCO_val2014_000000250301.jpg -../coco/images/val2014/COCO_val2014_000000250313.jpg -../coco/images/val2014/COCO_val2014_000000250370.jpg -../coco/images/val2014/COCO_val2014_000000250427.jpg -../coco/images/val2014/COCO_val2014_000000250629.jpg -../coco/images/val2014/COCO_val2014_000000250745.jpg -../coco/images/val2014/COCO_val2014_000000250766.jpg -../coco/images/val2014/COCO_val2014_000000250794.jpg -../coco/images/val2014/COCO_val2014_000000250917.jpg -../coco/images/val2014/COCO_val2014_000000250924.jpg -../coco/images/val2014/COCO_val2014_000000250939.jpg -../coco/images/val2014/COCO_val2014_000000251019.jpg -../coco/images/val2014/COCO_val2014_000000251044.jpg -../coco/images/val2014/COCO_val2014_000000251195.jpg -../coco/images/val2014/COCO_val2014_000000251330.jpg -../coco/images/val2014/COCO_val2014_000000251367.jpg -../coco/images/val2014/COCO_val2014_000000251857.jpg -../coco/images/val2014/COCO_val2014_000000251888.jpg -../coco/images/val2014/COCO_val2014_000000251920.jpg -../coco/images/val2014/COCO_val2014_000000252008.jpg -../coco/images/val2014/COCO_val2014_000000252101.jpg -../coco/images/val2014/COCO_val2014_000000252292.jpg -../coco/images/val2014/COCO_val2014_000000252388.jpg -../coco/images/val2014/COCO_val2014_000000252403.jpg -../coco/images/val2014/COCO_val2014_000000252444.jpg -../coco/images/val2014/COCO_val2014_000000252549.jpg -../coco/images/val2014/COCO_val2014_000000252625.jpg -../coco/images/val2014/COCO_val2014_000000252748.jpg -../coco/images/val2014/COCO_val2014_000000252857.jpg -../coco/images/val2014/COCO_val2014_000000252911.jpg -../coco/images/val2014/COCO_val2014_000000253036.jpg -../coco/images/val2014/COCO_val2014_000000253452.jpg -../coco/images/val2014/COCO_val2014_000000253630.jpg -../coco/images/val2014/COCO_val2014_000000253688.jpg -../coco/images/val2014/COCO_val2014_000000253742.jpg -../coco/images/val2014/COCO_val2014_000000253843.jpg -../coco/images/val2014/COCO_val2014_000000254164.jpg -../coco/images/val2014/COCO_val2014_000000254167.jpg -../coco/images/val2014/COCO_val2014_000000254454.jpg -../coco/images/val2014/COCO_val2014_000000254568.jpg -../coco/images/val2014/COCO_val2014_000000254589.jpg -../coco/images/val2014/COCO_val2014_000000254653.jpg -../coco/images/val2014/COCO_val2014_000000254711.jpg -../coco/images/val2014/COCO_val2014_000000254864.jpg -../coco/images/val2014/COCO_val2014_000000254931.jpg -../coco/images/val2014/COCO_val2014_000000254986.jpg -../coco/images/val2014/COCO_val2014_000000255244.jpg -../coco/images/val2014/COCO_val2014_000000255315.jpg -../coco/images/val2014/COCO_val2014_000000255529.jpg -../coco/images/val2014/COCO_val2014_000000255578.jpg -../coco/images/val2014/COCO_val2014_000000255649.jpg -../coco/images/val2014/COCO_val2014_000000255928.jpg -../coco/images/val2014/COCO_val2014_000000256003.jpg -../coco/images/val2014/COCO_val2014_000000256095.jpg -../coco/images/val2014/COCO_val2014_000000256145.jpg -../coco/images/val2014/COCO_val2014_000000256407.jpg -../coco/images/val2014/COCO_val2014_000000256470.jpg -../coco/images/val2014/COCO_val2014_000000256529.jpg -../coco/images/val2014/COCO_val2014_000000256547.jpg -../coco/images/val2014/COCO_val2014_000000256566.jpg -../coco/images/val2014/COCO_val2014_000000256590.jpg -../coco/images/val2014/COCO_val2014_000000256668.jpg -../coco/images/val2014/COCO_val2014_000000256771.jpg -../coco/images/val2014/COCO_val2014_000000256838.jpg -../coco/images/val2014/COCO_val2014_000000256859.jpg -../coco/images/val2014/COCO_val2014_000000256945.jpg -../coco/images/val2014/COCO_val2014_000000257046.jpg -../coco/images/val2014/COCO_val2014_000000257137.jpg -../coco/images/val2014/COCO_val2014_000000257336.jpg -../coco/images/val2014/COCO_val2014_000000257471.jpg -../coco/images/val2014/COCO_val2014_000000257660.jpg -../coco/images/val2014/COCO_val2014_000000257870.jpg -../coco/images/val2014/COCO_val2014_000000257941.jpg -../coco/images/val2014/COCO_val2014_000000258023.jpg -../coco/images/val2014/COCO_val2014_000000258209.jpg -../coco/images/val2014/COCO_val2014_000000258509.jpg -../coco/images/val2014/COCO_val2014_000000258588.jpg -../coco/images/val2014/COCO_val2014_000000258628.jpg -../coco/images/val2014/COCO_val2014_000000259099.jpg -../coco/images/val2014/COCO_val2014_000000259112.jpg -../coco/images/val2014/COCO_val2014_000000259335.jpg -../coco/images/val2014/COCO_val2014_000000259342.jpg -../coco/images/val2014/COCO_val2014_000000259408.jpg -../coco/images/val2014/COCO_val2014_000000259665.jpg -../coco/images/val2014/COCO_val2014_000000259952.jpg -../coco/images/val2014/COCO_val2014_000000260166.jpg -../coco/images/val2014/COCO_val2014_000000260307.jpg -../coco/images/val2014/COCO_val2014_000000260370.jpg -../coco/images/val2014/COCO_val2014_000000260470.jpg -../coco/images/val2014/COCO_val2014_000000260595.jpg -../coco/images/val2014/COCO_val2014_000000260686.jpg -../coco/images/val2014/COCO_val2014_000000260818.jpg -../coco/images/val2014/COCO_val2014_000000260922.jpg -../coco/images/val2014/COCO_val2014_000000261182.jpg -../coco/images/val2014/COCO_val2014_000000261273.jpg -../coco/images/val2014/COCO_val2014_000000261346.jpg -../coco/images/val2014/COCO_val2014_000000261787.jpg -../coco/images/val2014/COCO_val2014_000000262162.jpg -../coco/images/val2014/COCO_val2014_000000262200.jpg -../coco/images/val2014/COCO_val2014_000000262228.jpg -../coco/images/val2014/COCO_val2014_000000262235.jpg -../coco/images/val2014/COCO_val2014_000000262325.jpg -../coco/images/val2014/COCO_val2014_000000262347.jpg -../coco/images/val2014/COCO_val2014_000000262509.jpg -../coco/images/val2014/COCO_val2014_000000262651.jpg -../coco/images/val2014/COCO_val2014_000000262677.jpg -../coco/images/val2014/COCO_val2014_000000262810.jpg -../coco/images/val2014/COCO_val2014_000000262895.jpg -../coco/images/val2014/COCO_val2014_000000262900.jpg -../coco/images/val2014/COCO_val2014_000000262987.jpg -../coco/images/val2014/COCO_val2014_000000263425.jpg -../coco/images/val2014/COCO_val2014_000000263505.jpg -../coco/images/val2014/COCO_val2014_000000264013.jpg -../coco/images/val2014/COCO_val2014_000000264540.jpg -../coco/images/val2014/COCO_val2014_000000264683.jpg -../coco/images/val2014/COCO_val2014_000000264737.jpg -../coco/images/val2014/COCO_val2014_000000264819.jpg -../coco/images/val2014/COCO_val2014_000000265063.jpg -../coco/images/val2014/COCO_val2014_000000265374.jpg -../coco/images/val2014/COCO_val2014_000000265574.jpg -../coco/images/val2014/COCO_val2014_000000265579.jpg -../coco/images/val2014/COCO_val2014_000000265611.jpg -../coco/images/val2014/COCO_val2014_000000265851.jpg -../coco/images/val2014/COCO_val2014_000000265916.jpg -../coco/images/val2014/COCO_val2014_000000266115.jpg -../coco/images/val2014/COCO_val2014_000000266160.jpg -../coco/images/val2014/COCO_val2014_000000266176.jpg -../coco/images/val2014/COCO_val2014_000000266491.jpg -../coco/images/val2014/COCO_val2014_000000267076.jpg -../coco/images/val2014/COCO_val2014_000000267112.jpg -../coco/images/val2014/COCO_val2014_000000267115.jpg -../coco/images/val2014/COCO_val2014_000000267127.jpg -../coco/images/val2014/COCO_val2014_000000267224.jpg -../coco/images/val2014/COCO_val2014_000000267321.jpg -../coco/images/val2014/COCO_val2014_000000267521.jpg -../coco/images/val2014/COCO_val2014_000000267537.jpg -../coco/images/val2014/COCO_val2014_000000267844.jpg -../coco/images/val2014/COCO_val2014_000000267875.jpg -../coco/images/val2014/COCO_val2014_000000267972.jpg -../coco/images/val2014/COCO_val2014_000000267998.jpg -../coco/images/val2014/COCO_val2014_000000268224.jpg -../coco/images/val2014/COCO_val2014_000000268322.jpg -../coco/images/val2014/COCO_val2014_000000268378.jpg -../coco/images/val2014/COCO_val2014_000000268400.jpg -../coco/images/val2014/COCO_val2014_000000268435.jpg -../coco/images/val2014/COCO_val2014_000000268469.jpg -../coco/images/val2014/COCO_val2014_000000268539.jpg -../coco/images/val2014/COCO_val2014_000000268541.jpg -../coco/images/val2014/COCO_val2014_000000268710.jpg -../coco/images/val2014/COCO_val2014_000000268882.jpg -../coco/images/val2014/COCO_val2014_000000268885.jpg -../coco/images/val2014/COCO_val2014_000000268941.jpg -../coco/images/val2014/COCO_val2014_000000268987.jpg -../coco/images/val2014/COCO_val2014_000000269280.jpg -../coco/images/val2014/COCO_val2014_000000269311.jpg -../coco/images/val2014/COCO_val2014_000000269866.jpg -../coco/images/val2014/COCO_val2014_000000269867.jpg -../coco/images/val2014/COCO_val2014_000000269975.jpg -../coco/images/val2014/COCO_val2014_000000270001.jpg -../coco/images/val2014/COCO_val2014_000000270244.jpg -../coco/images/val2014/COCO_val2014_000000270474.jpg -../coco/images/val2014/COCO_val2014_000000270515.jpg -../coco/images/val2014/COCO_val2014_000000270544.jpg -../coco/images/val2014/COCO_val2014_000000270593.jpg -../coco/images/val2014/COCO_val2014_000000270702.jpg -../coco/images/val2014/COCO_val2014_000000270918.jpg -../coco/images/val2014/COCO_val2014_000000271017.jpg -../coco/images/val2014/COCO_val2014_000000271117.jpg -../coco/images/val2014/COCO_val2014_000000271240.jpg -../coco/images/val2014/COCO_val2014_000000271359.jpg -../coco/images/val2014/COCO_val2014_000000271546.jpg -../coco/images/val2014/COCO_val2014_000000271681.jpg -../coco/images/val2014/COCO_val2014_000000271785.jpg -../coco/images/val2014/COCO_val2014_000000271820.jpg -../coco/images/val2014/COCO_val2014_000000271900.jpg -../coco/images/val2014/COCO_val2014_000000272008.jpg -../coco/images/val2014/COCO_val2014_000000272015.jpg -../coco/images/val2014/COCO_val2014_000000272117.jpg -../coco/images/val2014/COCO_val2014_000000272129.jpg -../coco/images/val2014/COCO_val2014_000000272188.jpg -../coco/images/val2014/COCO_val2014_000000272212.jpg -../coco/images/val2014/COCO_val2014_000000272615.jpg -../coco/images/val2014/COCO_val2014_000000272635.jpg -../coco/images/val2014/COCO_val2014_000000272718.jpg -../coco/images/val2014/COCO_val2014_000000272728.jpg -../coco/images/val2014/COCO_val2014_000000272880.jpg -../coco/images/val2014/COCO_val2014_000000272889.jpg -../coco/images/val2014/COCO_val2014_000000273118.jpg -../coco/images/val2014/COCO_val2014_000000273188.jpg -../coco/images/val2014/COCO_val2014_000000273246.jpg -../coco/images/val2014/COCO_val2014_000000273323.jpg -../coco/images/val2014/COCO_val2014_000000273442.jpg -../coco/images/val2014/COCO_val2014_000000273450.jpg -../coco/images/val2014/COCO_val2014_000000273493.jpg -../coco/images/val2014/COCO_val2014_000000273494.jpg -../coco/images/val2014/COCO_val2014_000000273579.jpg -../coco/images/val2014/COCO_val2014_000000273617.jpg -../coco/images/val2014/COCO_val2014_000000273688.jpg -../coco/images/val2014/COCO_val2014_000000273712.jpg -../coco/images/val2014/COCO_val2014_000000273728.jpg -../coco/images/val2014/COCO_val2014_000000273855.jpg -../coco/images/val2014/COCO_val2014_000000274066.jpg -../coco/images/val2014/COCO_val2014_000000274083.jpg -../coco/images/val2014/COCO_val2014_000000274292.jpg -../coco/images/val2014/COCO_val2014_000000274470.jpg -../coco/images/val2014/COCO_val2014_000000274629.jpg -../coco/images/val2014/COCO_val2014_000000274957.jpg -../coco/images/val2014/COCO_val2014_000000275270.jpg -../coco/images/val2014/COCO_val2014_000000275496.jpg -../coco/images/val2014/COCO_val2014_000000275843.jpg -../coco/images/val2014/COCO_val2014_000000275863.jpg -../coco/images/val2014/COCO_val2014_000000276149.jpg -../coco/images/val2014/COCO_val2014_000000276215.jpg -../coco/images/val2014/COCO_val2014_000000276239.jpg -../coco/images/val2014/COCO_val2014_000000276720.jpg -../coco/images/val2014/COCO_val2014_000000276804.jpg -../coco/images/val2014/COCO_val2014_000000276840.jpg -../coco/images/val2014/COCO_val2014_000000276863.jpg -../coco/images/val2014/COCO_val2014_000000277025.jpg -../coco/images/val2014/COCO_val2014_000000277046.jpg -../coco/images/val2014/COCO_val2014_000000277051.jpg -../coco/images/val2014/COCO_val2014_000000277162.jpg -../coco/images/val2014/COCO_val2014_000000277172.jpg -../coco/images/val2014/COCO_val2014_000000277227.jpg -../coco/images/val2014/COCO_val2014_000000277518.jpg -../coco/images/val2014/COCO_val2014_000000277542.jpg -../coco/images/val2014/COCO_val2014_000000277614.jpg -../coco/images/val2014/COCO_val2014_000000277622.jpg -../coco/images/val2014/COCO_val2014_000000277694.jpg -../coco/images/val2014/COCO_val2014_000000277984.jpg -../coco/images/val2014/COCO_val2014_000000278321.jpg -../coco/images/val2014/COCO_val2014_000000278435.jpg -../coco/images/val2014/COCO_val2014_000000278582.jpg -../coco/images/val2014/COCO_val2014_000000278760.jpg -../coco/images/val2014/COCO_val2014_000000278822.jpg -../coco/images/val2014/COCO_val2014_000000278843.jpg -../coco/images/val2014/COCO_val2014_000000278848.jpg -../coco/images/val2014/COCO_val2014_000000278967.jpg -../coco/images/val2014/COCO_val2014_000000278977.jpg -../coco/images/val2014/COCO_val2014_000000279024.jpg -../coco/images/val2014/COCO_val2014_000000279027.jpg -../coco/images/val2014/COCO_val2014_000000279154.jpg -../coco/images/val2014/COCO_val2014_000000279259.jpg -../coco/images/val2014/COCO_val2014_000000279521.jpg -../coco/images/val2014/COCO_val2014_000000279730.jpg -../coco/images/val2014/COCO_val2014_000000279784.jpg -../coco/images/val2014/COCO_val2014_000000279850.jpg -../coco/images/val2014/COCO_val2014_000000280007.jpg -../coco/images/val2014/COCO_val2014_000000280017.jpg -../coco/images/val2014/COCO_val2014_000000280036.jpg -../coco/images/val2014/COCO_val2014_000000280293.jpg -../coco/images/val2014/COCO_val2014_000000280530.jpg -../coco/images/val2014/COCO_val2014_000000280736.jpg -../coco/images/val2014/COCO_val2014_000000280766.jpg -../coco/images/val2014/COCO_val2014_000000281019.jpg -../coco/images/val2014/COCO_val2014_000000281163.jpg -../coco/images/val2014/COCO_val2014_000000281377.jpg -../coco/images/val2014/COCO_val2014_000000281500.jpg -../coco/images/val2014/COCO_val2014_000000281508.jpg -../coco/images/val2014/COCO_val2014_000000281601.jpg -../coco/images/val2014/COCO_val2014_000000281609.jpg -../coco/images/val2014/COCO_val2014_000000281676.jpg -../coco/images/val2014/COCO_val2014_000000281722.jpg -../coco/images/val2014/COCO_val2014_000000281733.jpg -../coco/images/val2014/COCO_val2014_000000282143.jpg -../coco/images/val2014/COCO_val2014_000000282229.jpg -../coco/images/val2014/COCO_val2014_000000282231.jpg -../coco/images/val2014/COCO_val2014_000000282698.jpg -../coco/images/val2014/COCO_val2014_000000282790.jpg -../coco/images/val2014/COCO_val2014_000000283012.jpg -../coco/images/val2014/COCO_val2014_000000283097.jpg -../coco/images/val2014/COCO_val2014_000000283101.jpg -../coco/images/val2014/COCO_val2014_000000283113.jpg -../coco/images/val2014/COCO_val2014_000000283254.jpg -../coco/images/val2014/COCO_val2014_000000283261.jpg -../coco/images/val2014/COCO_val2014_000000283380.jpg -../coco/images/val2014/COCO_val2014_000000283438.jpg -../coco/images/val2014/COCO_val2014_000000283441.jpg -../coco/images/val2014/COCO_val2014_000000283495.jpg -../coco/images/val2014/COCO_val2014_000000283642.jpg -../coco/images/val2014/COCO_val2014_000000283653.jpg -../coco/images/val2014/COCO_val2014_000000283659.jpg -../coco/images/val2014/COCO_val2014_000000283890.jpg -../coco/images/val2014/COCO_val2014_000000283940.jpg -../coco/images/val2014/COCO_val2014_000000283977.jpg -../coco/images/val2014/COCO_val2014_000000284160.jpg -../coco/images/val2014/COCO_val2014_000000284253.jpg -../coco/images/val2014/COCO_val2014_000000284426.jpg -../coco/images/val2014/COCO_val2014_000000284698.jpg -../coco/images/val2014/COCO_val2014_000000284749.jpg -../coco/images/val2014/COCO_val2014_000000284789.jpg -../coco/images/val2014/COCO_val2014_000000285106.jpg -../coco/images/val2014/COCO_val2014_000000285160.jpg -../coco/images/val2014/COCO_val2014_000000285302.jpg -../coco/images/val2014/COCO_val2014_000000285433.jpg -../coco/images/val2014/COCO_val2014_000000285799.jpg -../coco/images/val2014/COCO_val2014_000000285929.jpg -../coco/images/val2014/COCO_val2014_000000285961.jpg -../coco/images/val2014/COCO_val2014_000000286119.jpg -../coco/images/val2014/COCO_val2014_000000286146.jpg -../coco/images/val2014/COCO_val2014_000000286285.jpg -../coco/images/val2014/COCO_val2014_000000286458.jpg -../coco/images/val2014/COCO_val2014_000000286503.jpg -../coco/images/val2014/COCO_val2014_000000286654.jpg -../coco/images/val2014/COCO_val2014_000000286708.jpg -../coco/images/val2014/COCO_val2014_000000286719.jpg -../coco/images/val2014/COCO_val2014_000000286813.jpg -../coco/images/val2014/COCO_val2014_000000286907.jpg -../coco/images/val2014/COCO_val2014_000000286994.jpg -../coco/images/val2014/COCO_val2014_000000287035.jpg -../coco/images/val2014/COCO_val2014_000000287396.jpg -../coco/images/val2014/COCO_val2014_000000287484.jpg -../coco/images/val2014/COCO_val2014_000000287506.jpg -../coco/images/val2014/COCO_val2014_000000287550.jpg -../coco/images/val2014/COCO_val2014_000000287570.jpg -../coco/images/val2014/COCO_val2014_000000288114.jpg -../coco/images/val2014/COCO_val2014_000000288229.jpg -../coco/images/val2014/COCO_val2014_000000288313.jpg -../coco/images/val2014/COCO_val2014_000000288799.jpg -../coco/images/val2014/COCO_val2014_000000288933.jpg -../coco/images/val2014/COCO_val2014_000000289128.jpg -../coco/images/val2014/COCO_val2014_000000289172.jpg -../coco/images/val2014/COCO_val2014_000000289194.jpg -../coco/images/val2014/COCO_val2014_000000289201.jpg -../coco/images/val2014/COCO_val2014_000000289337.jpg -../coco/images/val2014/COCO_val2014_000000289474.jpg -../coco/images/val2014/COCO_val2014_000000289497.jpg -../coco/images/val2014/COCO_val2014_000000289633.jpg -../coco/images/val2014/COCO_val2014_000000289716.jpg -../coco/images/val2014/COCO_val2014_000000289949.jpg -../coco/images/val2014/COCO_val2014_000000289960.jpg -../coco/images/val2014/COCO_val2014_000000289995.jpg -../coco/images/val2014/COCO_val2014_000000290165.jpg -../coco/images/val2014/COCO_val2014_000000290170.jpg -../coco/images/val2014/COCO_val2014_000000290196.jpg -../coco/images/val2014/COCO_val2014_000000290231.jpg -../coco/images/val2014/COCO_val2014_000000290477.jpg -../coco/images/val2014/COCO_val2014_000000290515.jpg -../coco/images/val2014/COCO_val2014_000000290602.jpg -../coco/images/val2014/COCO_val2014_000000290659.jpg -../coco/images/val2014/COCO_val2014_000000291380.jpg -../coco/images/val2014/COCO_val2014_000000291404.jpg -../coco/images/val2014/COCO_val2014_000000291588.jpg -../coco/images/val2014/COCO_val2014_000000291589.jpg -../coco/images/val2014/COCO_val2014_000000291742.jpg -../coco/images/val2014/COCO_val2014_000000291784.jpg -../coco/images/val2014/COCO_val2014_000000291866.jpg -../coco/images/val2014/COCO_val2014_000000291930.jpg -../coco/images/val2014/COCO_val2014_000000292032.jpg -../coco/images/val2014/COCO_val2014_000000292206.jpg -../coco/images/val2014/COCO_val2014_000000292330.jpg -../coco/images/val2014/COCO_val2014_000000292363.jpg -../coco/images/val2014/COCO_val2014_000000292446.jpg -../coco/images/val2014/COCO_val2014_000000292456.jpg -../coco/images/val2014/COCO_val2014_000000292493.jpg -../coco/images/val2014/COCO_val2014_000000292649.jpg -../coco/images/val2014/COCO_val2014_000000292822.jpg -../coco/images/val2014/COCO_val2014_000000292916.jpg -../coco/images/val2014/COCO_val2014_000000292931.jpg -../coco/images/val2014/COCO_val2014_000000292945.jpg -../coco/images/val2014/COCO_val2014_000000292990.jpg -../coco/images/val2014/COCO_val2014_000000292995.jpg -../coco/images/val2014/COCO_val2014_000000293002.jpg -../coco/images/val2014/COCO_val2014_000000293071.jpg -../coco/images/val2014/COCO_val2014_000000293133.jpg -../coco/images/val2014/COCO_val2014_000000293296.jpg -../coco/images/val2014/COCO_val2014_000000293333.jpg -../coco/images/val2014/COCO_val2014_000000293452.jpg -../coco/images/val2014/COCO_val2014_000000293574.jpg -../coco/images/val2014/COCO_val2014_000000293785.jpg -../coco/images/val2014/COCO_val2014_000000293895.jpg -../coco/images/val2014/COCO_val2014_000000294035.jpg -../coco/images/val2014/COCO_val2014_000000294119.jpg -../coco/images/val2014/COCO_val2014_000000294209.jpg -../coco/images/val2014/COCO_val2014_000000294284.jpg -../coco/images/val2014/COCO_val2014_000000294593.jpg -../coco/images/val2014/COCO_val2014_000000294958.jpg -../coco/images/val2014/COCO_val2014_000000295016.jpg -../coco/images/val2014/COCO_val2014_000000295059.jpg -../coco/images/val2014/COCO_val2014_000000295124.jpg -../coco/images/val2014/COCO_val2014_000000295269.jpg -../coco/images/val2014/COCO_val2014_000000295574.jpg -../coco/images/val2014/COCO_val2014_000000295683.jpg -../coco/images/val2014/COCO_val2014_000000295728.jpg -../coco/images/val2014/COCO_val2014_000000295769.jpg -../coco/images/val2014/COCO_val2014_000000295837.jpg -../coco/images/val2014/COCO_val2014_000000296014.jpg -../coco/images/val2014/COCO_val2014_000000296032.jpg -../coco/images/val2014/COCO_val2014_000000296136.jpg -../coco/images/val2014/COCO_val2014_000000296255.jpg -../coco/images/val2014/COCO_val2014_000000296492.jpg -../coco/images/val2014/COCO_val2014_000000296564.jpg -../coco/images/val2014/COCO_val2014_000000296745.jpg -../coco/images/val2014/COCO_val2014_000000296825.jpg -../coco/images/val2014/COCO_val2014_000000296897.jpg -../coco/images/val2014/COCO_val2014_000000296988.jpg -../coco/images/val2014/COCO_val2014_000000297037.jpg -../coco/images/val2014/COCO_val2014_000000297074.jpg -../coco/images/val2014/COCO_val2014_000000297269.jpg -../coco/images/val2014/COCO_val2014_000000297444.jpg -../coco/images/val2014/COCO_val2014_000000297520.jpg -../coco/images/val2014/COCO_val2014_000000297578.jpg -../coco/images/val2014/COCO_val2014_000000297736.jpg -../coco/images/val2014/COCO_val2014_000000297830.jpg -../coco/images/val2014/COCO_val2014_000000297956.jpg -../coco/images/val2014/COCO_val2014_000000297970.jpg -../coco/images/val2014/COCO_val2014_000000297976.jpg -../coco/images/val2014/COCO_val2014_000000298067.jpg -../coco/images/val2014/COCO_val2014_000000298252.jpg -../coco/images/val2014/COCO_val2014_000000298461.jpg -../coco/images/val2014/COCO_val2014_000000298493.jpg -../coco/images/val2014/COCO_val2014_000000298691.jpg -../coco/images/val2014/COCO_val2014_000000298732.jpg -../coco/images/val2014/COCO_val2014_000000298736.jpg -../coco/images/val2014/COCO_val2014_000000298809.jpg -../coco/images/val2014/COCO_val2014_000000299044.jpg -../coco/images/val2014/COCO_val2014_000000299074.jpg -../coco/images/val2014/COCO_val2014_000000299409.jpg -../coco/images/val2014/COCO_val2014_000000299492.jpg -../coco/images/val2014/COCO_val2014_000000299553.jpg -../coco/images/val2014/COCO_val2014_000000300008.jpg -../coco/images/val2014/COCO_val2014_000000300055.jpg -../coco/images/val2014/COCO_val2014_000000300090.jpg -../coco/images/val2014/COCO_val2014_000000300124.jpg -../coco/images/val2014/COCO_val2014_000000300155.jpg -../coco/images/val2014/COCO_val2014_000000300330.jpg -../coco/images/val2014/COCO_val2014_000000300403.jpg -../coco/images/val2014/COCO_val2014_000000300472.jpg -../coco/images/val2014/COCO_val2014_000000300701.jpg -../coco/images/val2014/COCO_val2014_000000300705.jpg -../coco/images/val2014/COCO_val2014_000000300791.jpg -../coco/images/val2014/COCO_val2014_000000300814.jpg -../coco/images/val2014/COCO_val2014_000000301135.jpg -../coco/images/val2014/COCO_val2014_000000301221.jpg -../coco/images/val2014/COCO_val2014_000000301266.jpg -../coco/images/val2014/COCO_val2014_000000301397.jpg -../coco/images/val2014/COCO_val2014_000000301746.jpg -../coco/images/val2014/COCO_val2014_000000301756.jpg -../coco/images/val2014/COCO_val2014_000000301765.jpg -../coco/images/val2014/COCO_val2014_000000301837.jpg -../coco/images/val2014/COCO_val2014_000000301956.jpg -../coco/images/val2014/COCO_val2014_000000301971.jpg -../coco/images/val2014/COCO_val2014_000000301981.jpg -../coco/images/val2014/COCO_val2014_000000302094.jpg -../coco/images/val2014/COCO_val2014_000000302110.jpg -../coco/images/val2014/COCO_val2014_000000302137.jpg -../coco/images/val2014/COCO_val2014_000000302185.jpg -../coco/images/val2014/COCO_val2014_000000302193.jpg -../coco/images/val2014/COCO_val2014_000000302243.jpg -../coco/images/val2014/COCO_val2014_000000302298.jpg -../coco/images/val2014/COCO_val2014_000000302302.jpg -../coco/images/val2014/COCO_val2014_000000302318.jpg -../coco/images/val2014/COCO_val2014_000000302405.jpg -../coco/images/val2014/COCO_val2014_000000302452.jpg -../coco/images/val2014/COCO_val2014_000000302572.jpg -../coco/images/val2014/COCO_val2014_000000302710.jpg -../coco/images/val2014/COCO_val2014_000000302997.jpg -../coco/images/val2014/COCO_val2014_000000303006.jpg -../coco/images/val2014/COCO_val2014_000000303253.jpg -../coco/images/val2014/COCO_val2014_000000303305.jpg -../coco/images/val2014/COCO_val2014_000000303314.jpg -../coco/images/val2014/COCO_val2014_000000303549.jpg -../coco/images/val2014/COCO_val2014_000000303550.jpg -../coco/images/val2014/COCO_val2014_000000303556.jpg -../coco/images/val2014/COCO_val2014_000000303590.jpg -../coco/images/val2014/COCO_val2014_000000303937.jpg -../coco/images/val2014/COCO_val2014_000000304159.jpg -../coco/images/val2014/COCO_val2014_000000304186.jpg -../coco/images/val2014/COCO_val2014_000000304220.jpg -../coco/images/val2014/COCO_val2014_000000304252.jpg -../coco/images/val2014/COCO_val2014_000000304347.jpg -../coco/images/val2014/COCO_val2014_000000304390.jpg -../coco/images/val2014/COCO_val2014_000000304409.jpg -../coco/images/val2014/COCO_val2014_000000304812.jpg -../coco/images/val2014/COCO_val2014_000000304815.jpg -../coco/images/val2014/COCO_val2014_000000304827.jpg -../coco/images/val2014/COCO_val2014_000000305000.jpg -../coco/images/val2014/COCO_val2014_000000305343.jpg -../coco/images/val2014/COCO_val2014_000000305368.jpg -../coco/images/val2014/COCO_val2014_000000305480.jpg -../coco/images/val2014/COCO_val2014_000000305526.jpg -../coco/images/val2014/COCO_val2014_000000305803.jpg -../coco/images/val2014/COCO_val2014_000000305962.jpg -../coco/images/val2014/COCO_val2014_000000305978.jpg -../coco/images/val2014/COCO_val2014_000000306281.jpg -../coco/images/val2014/COCO_val2014_000000306395.jpg -../coco/images/val2014/COCO_val2014_000000306426.jpg -../coco/images/val2014/COCO_val2014_000000306585.jpg -../coco/images/val2014/COCO_val2014_000000306603.jpg -../coco/images/val2014/COCO_val2014_000000306855.jpg -../coco/images/val2014/COCO_val2014_000000306914.jpg -../coco/images/val2014/COCO_val2014_000000306952.jpg -../coco/images/val2014/COCO_val2014_000000306972.jpg -../coco/images/val2014/COCO_val2014_000000307206.jpg -../coco/images/val2014/COCO_val2014_000000307209.jpg -../coco/images/val2014/COCO_val2014_000000307438.jpg -../coco/images/val2014/COCO_val2014_000000307523.jpg -../coco/images/val2014/COCO_val2014_000000307531.jpg -../coco/images/val2014/COCO_val2014_000000307564.jpg -../coco/images/val2014/COCO_val2014_000000307873.jpg -../coco/images/val2014/COCO_val2014_000000307993.jpg -../coco/images/val2014/COCO_val2014_000000308156.jpg -../coco/images/val2014/COCO_val2014_000000308339.jpg -../coco/images/val2014/COCO_val2014_000000308441.jpg -../coco/images/val2014/COCO_val2014_000000308512.jpg -../coco/images/val2014/COCO_val2014_000000308543.jpg -../coco/images/val2014/COCO_val2014_000000308587.jpg -../coco/images/val2014/COCO_val2014_000000308759.jpg -../coco/images/val2014/COCO_val2014_000000308785.jpg -../coco/images/val2014/COCO_val2014_000000308900.jpg -../coco/images/val2014/COCO_val2014_000000308907.jpg -../coco/images/val2014/COCO_val2014_000000309044.jpg -../coco/images/val2014/COCO_val2014_000000309302.jpg -../coco/images/val2014/COCO_val2014_000000309452.jpg -../coco/images/val2014/COCO_val2014_000000309495.jpg -../coco/images/val2014/COCO_val2014_000000309530.jpg -../coco/images/val2014/COCO_val2014_000000309655.jpg -../coco/images/val2014/COCO_val2014_000000309692.jpg -../coco/images/val2014/COCO_val2014_000000309696.jpg -../coco/images/val2014/COCO_val2014_000000309775.jpg -../coco/images/val2014/COCO_val2014_000000309993.jpg -../coco/images/val2014/COCO_val2014_000000310008.jpg -../coco/images/val2014/COCO_val2014_000000310094.jpg -../coco/images/val2014/COCO_val2014_000000310196.jpg -../coco/images/val2014/COCO_val2014_000000310202.jpg -../coco/images/val2014/COCO_val2014_000000310524.jpg -../coco/images/val2014/COCO_val2014_000000310545.jpg -../coco/images/val2014/COCO_val2014_000000310622.jpg -../coco/images/val2014/COCO_val2014_000000310705.jpg -../coco/images/val2014/COCO_val2014_000000310858.jpg -../coco/images/val2014/COCO_val2014_000000311015.jpg -../coco/images/val2014/COCO_val2014_000000311081.jpg -../coco/images/val2014/COCO_val2014_000000311295.jpg -../coco/images/val2014/COCO_val2014_000000311303.jpg -../coco/images/val2014/COCO_val2014_000000311465.jpg -../coco/images/val2014/COCO_val2014_000000311904.jpg -../coco/images/val2014/COCO_val2014_000000311961.jpg -../coco/images/val2014/COCO_val2014_000000312081.jpg -../coco/images/val2014/COCO_val2014_000000312144.jpg -../coco/images/val2014/COCO_val2014_000000312192.jpg -../coco/images/val2014/COCO_val2014_000000312278.jpg -../coco/images/val2014/COCO_val2014_000000312289.jpg -../coco/images/val2014/COCO_val2014_000000312416.jpg -../coco/images/val2014/COCO_val2014_000000312544.jpg -../coco/images/val2014/COCO_val2014_000000312559.jpg -../coco/images/val2014/COCO_val2014_000000312890.jpg -../coco/images/val2014/COCO_val2014_000000313034.jpg -../coco/images/val2014/COCO_val2014_000000313057.jpg -../coco/images/val2014/COCO_val2014_000000313162.jpg -../coco/images/val2014/COCO_val2014_000000313321.jpg -../coco/images/val2014/COCO_val2014_000000313557.jpg -../coco/images/val2014/COCO_val2014_000000313588.jpg -../coco/images/val2014/COCO_val2014_000000313593.jpg -../coco/images/val2014/COCO_val2014_000000313916.jpg -../coco/images/val2014/COCO_val2014_000000313922.jpg -../coco/images/val2014/COCO_val2014_000000314023.jpg -../coco/images/val2014/COCO_val2014_000000314027.jpg -../coco/images/val2014/COCO_val2014_000000314147.jpg -../coco/images/val2014/COCO_val2014_000000314440.jpg -../coco/images/val2014/COCO_val2014_000000314616.jpg -../coco/images/val2014/COCO_val2014_000000314812.jpg -../coco/images/val2014/COCO_val2014_000000314992.jpg -../coco/images/val2014/COCO_val2014_000000315219.jpg -../coco/images/val2014/COCO_val2014_000000315249.jpg -../coco/images/val2014/COCO_val2014_000000315281.jpg -../coco/images/val2014/COCO_val2014_000000315564.jpg -../coco/images/val2014/COCO_val2014_000000315601.jpg -../coco/images/val2014/COCO_val2014_000000315621.jpg -../coco/images/val2014/COCO_val2014_000000315744.jpg -../coco/images/val2014/COCO_val2014_000000315792.jpg -../coco/images/val2014/COCO_val2014_000000315824.jpg -../coco/images/val2014/COCO_val2014_000000315962.jpg -../coco/images/val2014/COCO_val2014_000000316000.jpg -../coco/images/val2014/COCO_val2014_000000316015.jpg -../coco/images/val2014/COCO_val2014_000000316138.jpg -../coco/images/val2014/COCO_val2014_000000316147.jpg -../coco/images/val2014/COCO_val2014_000000316254.jpg -../coco/images/val2014/COCO_val2014_000000316359.jpg -../coco/images/val2014/COCO_val2014_000000316400.jpg -../coco/images/val2014/COCO_val2014_000000316438.jpg -../coco/images/val2014/COCO_val2014_000000316505.jpg -../coco/images/val2014/COCO_val2014_000000316617.jpg -../coco/images/val2014/COCO_val2014_000000316704.jpg -../coco/images/val2014/COCO_val2014_000000316879.jpg -../coco/images/val2014/COCO_val2014_000000317033.jpg -../coco/images/val2014/COCO_val2014_000000317320.jpg -../coco/images/val2014/COCO_val2014_000000317325.jpg -../coco/images/val2014/COCO_val2014_000000317424.jpg -../coco/images/val2014/COCO_val2014_000000317560.jpg -../coco/images/val2014/COCO_val2014_000000317622.jpg -../coco/images/val2014/COCO_val2014_000000317898.jpg -../coco/images/val2014/COCO_val2014_000000318124.jpg -../coco/images/val2014/COCO_val2014_000000318200.jpg -../coco/images/val2014/COCO_val2014_000000318314.jpg -../coco/images/val2014/COCO_val2014_000000318566.jpg -../coco/images/val2014/COCO_val2014_000000318618.jpg -../coco/images/val2014/COCO_val2014_000000318645.jpg -../coco/images/val2014/COCO_val2014_000000318671.jpg -../coco/images/val2014/COCO_val2014_000000318722.jpg -../coco/images/val2014/COCO_val2014_000000318837.jpg -../coco/images/val2014/COCO_val2014_000000319055.jpg -../coco/images/val2014/COCO_val2014_000000319073.jpg -../coco/images/val2014/COCO_val2014_000000319579.jpg -../coco/images/val2014/COCO_val2014_000000319616.jpg -../coco/images/val2014/COCO_val2014_000000319617.jpg -../coco/images/val2014/COCO_val2014_000000319654.jpg -../coco/images/val2014/COCO_val2014_000000319677.jpg -../coco/images/val2014/COCO_val2014_000000319687.jpg -../coco/images/val2014/COCO_val2014_000000319721.jpg -../coco/images/val2014/COCO_val2014_000000319726.jpg -../coco/images/val2014/COCO_val2014_000000320078.jpg -../coco/images/val2014/COCO_val2014_000000320203.jpg -../coco/images/val2014/COCO_val2014_000000320461.jpg -../coco/images/val2014/COCO_val2014_000000320480.jpg -../coco/images/val2014/COCO_val2014_000000320482.jpg -../coco/images/val2014/COCO_val2014_000000320696.jpg -../coco/images/val2014/COCO_val2014_000000320832.jpg -../coco/images/val2014/COCO_val2014_000000320893.jpg -../coco/images/val2014/COCO_val2014_000000320978.jpg -../coco/images/val2014/COCO_val2014_000000321079.jpg -../coco/images/val2014/COCO_val2014_000000321118.jpg -../coco/images/val2014/COCO_val2014_000000321176.jpg -../coco/images/val2014/COCO_val2014_000000321258.jpg -../coco/images/val2014/COCO_val2014_000000321476.jpg -../coco/images/val2014/COCO_val2014_000000321647.jpg -../coco/images/val2014/COCO_val2014_000000321804.jpg -../coco/images/val2014/COCO_val2014_000000322174.jpg -../coco/images/val2014/COCO_val2014_000000322352.jpg -../coco/images/val2014/COCO_val2014_000000322594.jpg -../coco/images/val2014/COCO_val2014_000000322724.jpg -../coco/images/val2014/COCO_val2014_000000322829.jpg -../coco/images/val2014/COCO_val2014_000000322845.jpg -../coco/images/val2014/COCO_val2014_000000322895.jpg -../coco/images/val2014/COCO_val2014_000000323128.jpg -../coco/images/val2014/COCO_val2014_000000323186.jpg -../coco/images/val2014/COCO_val2014_000000323291.jpg -../coco/images/val2014/COCO_val2014_000000323564.jpg -../coco/images/val2014/COCO_val2014_000000323751.jpg -../coco/images/val2014/COCO_val2014_000000323758.jpg -../coco/images/val2014/COCO_val2014_000000323799.jpg -../coco/images/val2014/COCO_val2014_000000323853.jpg -../coco/images/val2014/COCO_val2014_000000323919.jpg -../coco/images/val2014/COCO_val2014_000000323925.jpg -../coco/images/val2014/COCO_val2014_000000323930.jpg -../coco/images/val2014/COCO_val2014_000000324040.jpg -../coco/images/val2014/COCO_val2014_000000324135.jpg -../coco/images/val2014/COCO_val2014_000000324203.jpg -../coco/images/val2014/COCO_val2014_000000324497.jpg -../coco/images/val2014/COCO_val2014_000000324500.jpg -../coco/images/val2014/COCO_val2014_000000324595.jpg -../coco/images/val2014/COCO_val2014_000000324774.jpg -../coco/images/val2014/COCO_val2014_000000324776.jpg -../coco/images/val2014/COCO_val2014_000000324789.jpg -../coco/images/val2014/COCO_val2014_000000324872.jpg -../coco/images/val2014/COCO_val2014_000000325027.jpg -../coco/images/val2014/COCO_val2014_000000325153.jpg -../coco/images/val2014/COCO_val2014_000000325157.jpg -../coco/images/val2014/COCO_val2014_000000325211.jpg -../coco/images/val2014/COCO_val2014_000000325328.jpg -../coco/images/val2014/COCO_val2014_000000325410.jpg -../coco/images/val2014/COCO_val2014_000000325587.jpg -../coco/images/val2014/COCO_val2014_000000325623.jpg -../coco/images/val2014/COCO_val2014_000000325736.jpg -../coco/images/val2014/COCO_val2014_000000325907.jpg -../coco/images/val2014/COCO_val2014_000000326128.jpg -../coco/images/val2014/COCO_val2014_000000326230.jpg -../coco/images/val2014/COCO_val2014_000000326308.jpg -../coco/images/val2014/COCO_val2014_000000326368.jpg -../coco/images/val2014/COCO_val2014_000000326462.jpg -../coco/images/val2014/COCO_val2014_000000326959.jpg -../coco/images/val2014/COCO_val2014_000000327149.jpg -../coco/images/val2014/COCO_val2014_000000327323.jpg -../coco/images/val2014/COCO_val2014_000000327383.jpg -../coco/images/val2014/COCO_val2014_000000327413.jpg -../coco/images/val2014/COCO_val2014_000000327433.jpg -../coco/images/val2014/COCO_val2014_000000327617.jpg -../coco/images/val2014/COCO_val2014_000000327665.jpg -../coco/images/val2014/COCO_val2014_000000327845.jpg -../coco/images/val2014/COCO_val2014_000000327857.jpg -../coco/images/val2014/COCO_val2014_000000327872.jpg -../coco/images/val2014/COCO_val2014_000000327892.jpg -../coco/images/val2014/COCO_val2014_000000328068.jpg -../coco/images/val2014/COCO_val2014_000000328098.jpg -../coco/images/val2014/COCO_val2014_000000328374.jpg -../coco/images/val2014/COCO_val2014_000000328462.jpg -../coco/images/val2014/COCO_val2014_000000328464.jpg -../coco/images/val2014/COCO_val2014_000000328499.jpg -../coco/images/val2014/COCO_val2014_000000328551.jpg -../coco/images/val2014/COCO_val2014_000000328757.jpg -../coco/images/val2014/COCO_val2014_000000328791.jpg -../coco/images/val2014/COCO_val2014_000000328838.jpg -../coco/images/val2014/COCO_val2014_000000329375.jpg -../coco/images/val2014/COCO_val2014_000000329379.jpg -../coco/images/val2014/COCO_val2014_000000329421.jpg -../coco/images/val2014/COCO_val2014_000000329447.jpg -../coco/images/val2014/COCO_val2014_000000329486.jpg -../coco/images/val2014/COCO_val2014_000000329533.jpg -../coco/images/val2014/COCO_val2014_000000330065.jpg -../coco/images/val2014/COCO_val2014_000000330248.jpg -../coco/images/val2014/COCO_val2014_000000330515.jpg -../coco/images/val2014/COCO_val2014_000000330734.jpg -../coco/images/val2014/COCO_val2014_000000330931.jpg -../coco/images/val2014/COCO_val2014_000000331097.jpg -../coco/images/val2014/COCO_val2014_000000331196.jpg -../coco/images/val2014/COCO_val2014_000000331242.jpg -../coco/images/val2014/COCO_val2014_000000331307.jpg -../coco/images/val2014/COCO_val2014_000000331349.jpg -../coco/images/val2014/COCO_val2014_000000331372.jpg -../coco/images/val2014/COCO_val2014_000000331403.jpg -../coco/images/val2014/COCO_val2014_000000331627.jpg -../coco/images/val2014/COCO_val2014_000000331667.jpg -../coco/images/val2014/COCO_val2014_000000331959.jpg -../coco/images/val2014/COCO_val2014_000000332025.jpg -../coco/images/val2014/COCO_val2014_000000332407.jpg -../coco/images/val2014/COCO_val2014_000000332502.jpg -../coco/images/val2014/COCO_val2014_000000332545.jpg -../coco/images/val2014/COCO_val2014_000000332570.jpg -../coco/images/val2014/COCO_val2014_000000332582.jpg -../coco/images/val2014/COCO_val2014_000000332627.jpg -../coco/images/val2014/COCO_val2014_000000332852.jpg -../coco/images/val2014/COCO_val2014_000000332908.jpg -../coco/images/val2014/COCO_val2014_000000333014.jpg -../coco/images/val2014/COCO_val2014_000000333034.jpg -../coco/images/val2014/COCO_val2014_000000333101.jpg -../coco/images/val2014/COCO_val2014_000000333114.jpg -../coco/images/val2014/COCO_val2014_000000333150.jpg -../coco/images/val2014/COCO_val2014_000000333156.jpg -../coco/images/val2014/COCO_val2014_000000333167.jpg -../coco/images/val2014/COCO_val2014_000000333303.jpg -../coco/images/val2014/COCO_val2014_000000333436.jpg -../coco/images/val2014/COCO_val2014_000000333565.jpg -../coco/images/val2014/COCO_val2014_000000333756.jpg -../coco/images/val2014/COCO_val2014_000000333808.jpg -../coco/images/val2014/COCO_val2014_000000333845.jpg -../coco/images/val2014/COCO_val2014_000000333924.jpg -../coco/images/val2014/COCO_val2014_000000334015.jpg -../coco/images/val2014/COCO_val2014_000000334062.jpg -../coco/images/val2014/COCO_val2014_000000334471.jpg -../coco/images/val2014/COCO_val2014_000000334483.jpg -../coco/images/val2014/COCO_val2014_000000334675.jpg -../coco/images/val2014/COCO_val2014_000000334760.jpg -../coco/images/val2014/COCO_val2014_000000335081.jpg -../coco/images/val2014/COCO_val2014_000000335177.jpg -../coco/images/val2014/COCO_val2014_000000335328.jpg -../coco/images/val2014/COCO_val2014_000000335587.jpg -../coco/images/val2014/COCO_val2014_000000335610.jpg -../coco/images/val2014/COCO_val2014_000000335644.jpg -../coco/images/val2014/COCO_val2014_000000335774.jpg -../coco/images/val2014/COCO_val2014_000000335800.jpg -../coco/images/val2014/COCO_val2014_000000335814.jpg -../coco/images/val2014/COCO_val2014_000000335861.jpg -../coco/images/val2014/COCO_val2014_000000335887.jpg -../coco/images/val2014/COCO_val2014_000000335976.jpg -../coco/images/val2014/COCO_val2014_000000335992.jpg -../coco/images/val2014/COCO_val2014_000000336171.jpg -../coco/images/val2014/COCO_val2014_000000336309.jpg -../coco/images/val2014/COCO_val2014_000000336427.jpg -../coco/images/val2014/COCO_val2014_000000336464.jpg -../coco/images/val2014/COCO_val2014_000000336629.jpg -../coco/images/val2014/COCO_val2014_000000336949.jpg -../coco/images/val2014/COCO_val2014_000000337035.jpg -../coco/images/val2014/COCO_val2014_000000337246.jpg -../coco/images/val2014/COCO_val2014_000000337274.jpg -../coco/images/val2014/COCO_val2014_000000337563.jpg -../coco/images/val2014/COCO_val2014_000000337653.jpg -../coco/images/val2014/COCO_val2014_000000337666.jpg -../coco/images/val2014/COCO_val2014_000000337827.jpg -../coco/images/val2014/COCO_val2014_000000338044.jpg -../coco/images/val2014/COCO_val2014_000000338098.jpg -../coco/images/val2014/COCO_val2014_000000338105.jpg -../coco/images/val2014/COCO_val2014_000000338428.jpg -../coco/images/val2014/COCO_val2014_000000338532.jpg -../coco/images/val2014/COCO_val2014_000000338562.jpg -../coco/images/val2014/COCO_val2014_000000338581.jpg -../coco/images/val2014/COCO_val2014_000000338678.jpg -../coco/images/val2014/COCO_val2014_000000338826.jpg -../coco/images/val2014/COCO_val2014_000000339022.jpg -../coco/images/val2014/COCO_val2014_000000339202.jpg -../coco/images/val2014/COCO_val2014_000000339356.jpg -../coco/images/val2014/COCO_val2014_000000339470.jpg -../coco/images/val2014/COCO_val2014_000000339678.jpg -../coco/images/val2014/COCO_val2014_000000339740.jpg -../coco/images/val2014/COCO_val2014_000000339823.jpg -../coco/images/val2014/COCO_val2014_000000339943.jpg -../coco/images/val2014/COCO_val2014_000000340451.jpg -../coco/images/val2014/COCO_val2014_000000340529.jpg -../coco/images/val2014/COCO_val2014_000000340654.jpg -../coco/images/val2014/COCO_val2014_000000340737.jpg -../coco/images/val2014/COCO_val2014_000000340778.jpg -../coco/images/val2014/COCO_val2014_000000340781.jpg -../coco/images/val2014/COCO_val2014_000000340930.jpg -../coco/images/val2014/COCO_val2014_000000341230.jpg -../coco/images/val2014/COCO_val2014_000000341397.jpg -../coco/images/val2014/COCO_val2014_000000341725.jpg -../coco/images/val2014/COCO_val2014_000000341775.jpg -../coco/images/val2014/COCO_val2014_000000341778.jpg -../coco/images/val2014/COCO_val2014_000000342006.jpg -../coco/images/val2014/COCO_val2014_000000342142.jpg -../coco/images/val2014/COCO_val2014_000000342387.jpg -../coco/images/val2014/COCO_val2014_000000342762.jpg -../coco/images/val2014/COCO_val2014_000000343059.jpg -../coco/images/val2014/COCO_val2014_000000343157.jpg -../coco/images/val2014/COCO_val2014_000000343193.jpg -../coco/images/val2014/COCO_val2014_000000343315.jpg -../coco/images/val2014/COCO_val2014_000000343458.jpg -../coco/images/val2014/COCO_val2014_000000343504.jpg -../coco/images/val2014/COCO_val2014_000000343543.jpg -../coco/images/val2014/COCO_val2014_000000343680.jpg -../coco/images/val2014/COCO_val2014_000000343753.jpg -../coco/images/val2014/COCO_val2014_000000343967.jpg -../coco/images/val2014/COCO_val2014_000000344045.jpg -../coco/images/val2014/COCO_val2014_000000344197.jpg -../coco/images/val2014/COCO_val2014_000000344488.jpg -../coco/images/val2014/COCO_val2014_000000344498.jpg -../coco/images/val2014/COCO_val2014_000000344730.jpg -../coco/images/val2014/COCO_val2014_000000344862.jpg -../coco/images/val2014/COCO_val2014_000000344897.jpg -../coco/images/val2014/COCO_val2014_000000344903.jpg -../coco/images/val2014/COCO_val2014_000000345136.jpg -../coco/images/val2014/COCO_val2014_000000345211.jpg -../coco/images/val2014/COCO_val2014_000000345224.jpg -../coco/images/val2014/COCO_val2014_000000345261.jpg -../coco/images/val2014/COCO_val2014_000000345469.jpg -../coco/images/val2014/COCO_val2014_000000345711.jpg -../coco/images/val2014/COCO_val2014_000000345998.jpg -../coco/images/val2014/COCO_val2014_000000346337.jpg -../coco/images/val2014/COCO_val2014_000000346642.jpg -../coco/images/val2014/COCO_val2014_000000346645.jpg -../coco/images/val2014/COCO_val2014_000000346865.jpg -../coco/images/val2014/COCO_val2014_000000346940.jpg -../coco/images/val2014/COCO_val2014_000000347377.jpg -../coco/images/val2014/COCO_val2014_000000347390.jpg -../coco/images/val2014/COCO_val2014_000000347506.jpg -../coco/images/val2014/COCO_val2014_000000347630.jpg -../coco/images/val2014/COCO_val2014_000000347724.jpg -../coco/images/val2014/COCO_val2014_000000347747.jpg -../coco/images/val2014/COCO_val2014_000000347768.jpg -../coco/images/val2014/COCO_val2014_000000347772.jpg -../coco/images/val2014/COCO_val2014_000000347819.jpg -../coco/images/val2014/COCO_val2014_000000347848.jpg -../coco/images/val2014/COCO_val2014_000000347982.jpg -../coco/images/val2014/COCO_val2014_000000348091.jpg -../coco/images/val2014/COCO_val2014_000000348140.jpg -../coco/images/val2014/COCO_val2014_000000348216.jpg -../coco/images/val2014/COCO_val2014_000000348263.jpg -../coco/images/val2014/COCO_val2014_000000348306.jpg -../coco/images/val2014/COCO_val2014_000000348474.jpg -../coco/images/val2014/COCO_val2014_000000348524.jpg -../coco/images/val2014/COCO_val2014_000000348571.jpg -../coco/images/val2014/COCO_val2014_000000348701.jpg -../coco/images/val2014/COCO_val2014_000000348791.jpg -../coco/images/val2014/COCO_val2014_000000348913.jpg -../coco/images/val2014/COCO_val2014_000000348973.jpg -../coco/images/val2014/COCO_val2014_000000349185.jpg -../coco/images/val2014/COCO_val2014_000000349310.jpg -../coco/images/val2014/COCO_val2014_000000349402.jpg -../coco/images/val2014/COCO_val2014_000000349469.jpg -../coco/images/val2014/COCO_val2014_000000349480.jpg -../coco/images/val2014/COCO_val2014_000000349485.jpg -../coco/images/val2014/COCO_val2014_000000349489.jpg -../coco/images/val2014/COCO_val2014_000000349616.jpg -../coco/images/val2014/COCO_val2014_000000349622.jpg -../coco/images/val2014/COCO_val2014_000000349822.jpg -../coco/images/val2014/COCO_val2014_000000350075.jpg -../coco/images/val2014/COCO_val2014_000000350084.jpg -../coco/images/val2014/COCO_val2014_000000350388.jpg -../coco/images/val2014/COCO_val2014_000000350405.jpg -../coco/images/val2014/COCO_val2014_000000350447.jpg -../coco/images/val2014/COCO_val2014_000000350463.jpg -../coco/images/val2014/COCO_val2014_000000350467.jpg -../coco/images/val2014/COCO_val2014_000000350491.jpg -../coco/images/val2014/COCO_val2014_000000350648.jpg -../coco/images/val2014/COCO_val2014_000000350668.jpg -../coco/images/val2014/COCO_val2014_000000350675.jpg -../coco/images/val2014/COCO_val2014_000000350694.jpg -../coco/images/val2014/COCO_val2014_000000350851.jpg -../coco/images/val2014/COCO_val2014_000000351081.jpg -../coco/images/val2014/COCO_val2014_000000351149.jpg -../coco/images/val2014/COCO_val2014_000000351183.jpg -../coco/images/val2014/COCO_val2014_000000351557.jpg -../coco/images/val2014/COCO_val2014_000000351590.jpg -../coco/images/val2014/COCO_val2014_000000351683.jpg -../coco/images/val2014/COCO_val2014_000000351787.jpg -../coco/images/val2014/COCO_val2014_000000351840.jpg -../coco/images/val2014/COCO_val2014_000000352005.jpg -../coco/images/val2014/COCO_val2014_000000352334.jpg -../coco/images/val2014/COCO_val2014_000000352478.jpg -../coco/images/val2014/COCO_val2014_000000352481.jpg -../coco/images/val2014/COCO_val2014_000000352538.jpg -../coco/images/val2014/COCO_val2014_000000352760.jpg -../coco/images/val2014/COCO_val2014_000000353027.jpg -../coco/images/val2014/COCO_val2014_000000353028.jpg -../coco/images/val2014/COCO_val2014_000000353096.jpg -../coco/images/val2014/COCO_val2014_000000353298.jpg -../coco/images/val2014/COCO_val2014_000000353300.jpg -../coco/images/val2014/COCO_val2014_000000353411.jpg -../coco/images/val2014/COCO_val2014_000000353666.jpg -../coco/images/val2014/COCO_val2014_000000353964.jpg -../coco/images/val2014/COCO_val2014_000000354061.jpg -../coco/images/val2014/COCO_val2014_000000354242.jpg -../coco/images/val2014/COCO_val2014_000000354460.jpg -../coco/images/val2014/COCO_val2014_000000354929.jpg -../coco/images/val2014/COCO_val2014_000000355000.jpg -../coco/images/val2014/COCO_val2014_000000355123.jpg -../coco/images/val2014/COCO_val2014_000000355256.jpg -../coco/images/val2014/COCO_val2014_000000355263.jpg -../coco/images/val2014/COCO_val2014_000000355441.jpg -../coco/images/val2014/COCO_val2014_000000355450.jpg -../coco/images/val2014/COCO_val2014_000000355817.jpg -../coco/images/val2014/COCO_val2014_000000355871.jpg -../coco/images/val2014/COCO_val2014_000000355919.jpg -../coco/images/val2014/COCO_val2014_000000356002.jpg -../coco/images/val2014/COCO_val2014_000000356043.jpg -../coco/images/val2014/COCO_val2014_000000356092.jpg -../coco/images/val2014/COCO_val2014_000000356236.jpg -../coco/images/val2014/COCO_val2014_000000356351.jpg -../coco/images/val2014/COCO_val2014_000000356368.jpg -../coco/images/val2014/COCO_val2014_000000356379.jpg -../coco/images/val2014/COCO_val2014_000000356406.jpg -../coco/images/val2014/COCO_val2014_000000356456.jpg -../coco/images/val2014/COCO_val2014_000000356505.jpg -../coco/images/val2014/COCO_val2014_000000356612.jpg -../coco/images/val2014/COCO_val2014_000000357279.jpg -../coco/images/val2014/COCO_val2014_000000357335.jpg -../coco/images/val2014/COCO_val2014_000000357475.jpg -../coco/images/val2014/COCO_val2014_000000357529.jpg -../coco/images/val2014/COCO_val2014_000000357743.jpg -../coco/images/val2014/COCO_val2014_000000357829.jpg -../coco/images/val2014/COCO_val2014_000000357916.jpg -../coco/images/val2014/COCO_val2014_000000357944.jpg -../coco/images/val2014/COCO_val2014_000000358191.jpg -../coco/images/val2014/COCO_val2014_000000358231.jpg -../coco/images/val2014/COCO_val2014_000000358389.jpg -../coco/images/val2014/COCO_val2014_000000358652.jpg -../coco/images/val2014/COCO_val2014_000000358750.jpg -../coco/images/val2014/COCO_val2014_000000358763.jpg -../coco/images/val2014/COCO_val2014_000000358833.jpg -../coco/images/val2014/COCO_val2014_000000358901.jpg -../coco/images/val2014/COCO_val2014_000000359118.jpg -../coco/images/val2014/COCO_val2014_000000359126.jpg -../coco/images/val2014/COCO_val2014_000000359239.jpg -../coco/images/val2014/COCO_val2014_000000359276.jpg -../coco/images/val2014/COCO_val2014_000000359303.jpg -../coco/images/val2014/COCO_val2014_000000359442.jpg -../coco/images/val2014/COCO_val2014_000000359677.jpg -../coco/images/val2014/COCO_val2014_000000359791.jpg -../coco/images/val2014/COCO_val2014_000000359947.jpg -../coco/images/val2014/COCO_val2014_000000360128.jpg -../coco/images/val2014/COCO_val2014_000000360263.jpg -../coco/images/val2014/COCO_val2014_000000360346.jpg -../coco/images/val2014/COCO_val2014_000000360512.jpg -../coco/images/val2014/COCO_val2014_000000360564.jpg -../coco/images/val2014/COCO_val2014_000000360661.jpg -../coco/images/val2014/COCO_val2014_000000360700.jpg -../coco/images/val2014/COCO_val2014_000000360730.jpg -../coco/images/val2014/COCO_val2014_000000360926.jpg -../coco/images/val2014/COCO_val2014_000000361027.jpg -../coco/images/val2014/COCO_val2014_000000361029.jpg -../coco/images/val2014/COCO_val2014_000000361085.jpg -../coco/images/val2014/COCO_val2014_000000361157.jpg -../coco/images/val2014/COCO_val2014_000000361180.jpg -../coco/images/val2014/COCO_val2014_000000361221.jpg -../coco/images/val2014/COCO_val2014_000000361265.jpg -../coco/images/val2014/COCO_val2014_000000361268.jpg -../coco/images/val2014/COCO_val2014_000000361321.jpg -../coco/images/val2014/COCO_val2014_000000361341.jpg -../coco/images/val2014/COCO_val2014_000000361386.jpg -../coco/images/val2014/COCO_val2014_000000361660.jpg -../coco/images/val2014/COCO_val2014_000000361730.jpg -../coco/images/val2014/COCO_val2014_000000361751.jpg -../coco/images/val2014/COCO_val2014_000000361804.jpg -../coco/images/val2014/COCO_val2014_000000361819.jpg -../coco/images/val2014/COCO_val2014_000000361831.jpg -../coco/images/val2014/COCO_val2014_000000361885.jpg -../coco/images/val2014/COCO_val2014_000000361923.jpg -../coco/images/val2014/COCO_val2014_000000362026.jpg -../coco/images/val2014/COCO_val2014_000000362159.jpg -../coco/images/val2014/COCO_val2014_000000362189.jpg -../coco/images/val2014/COCO_val2014_000000362483.jpg -../coco/images/val2014/COCO_val2014_000000362869.jpg -../coco/images/val2014/COCO_val2014_000000362971.jpg -../coco/images/val2014/COCO_val2014_000000363403.jpg -../coco/images/val2014/COCO_val2014_000000363461.jpg -../coco/images/val2014/COCO_val2014_000000363508.jpg -../coco/images/val2014/COCO_val2014_000000363522.jpg -../coco/images/val2014/COCO_val2014_000000363831.jpg -../coco/images/val2014/COCO_val2014_000000363875.jpg -../coco/images/val2014/COCO_val2014_000000364079.jpg -../coco/images/val2014/COCO_val2014_000000364145.jpg -../coco/images/val2014/COCO_val2014_000000364188.jpg -../coco/images/val2014/COCO_val2014_000000364399.jpg -../coco/images/val2014/COCO_val2014_000000364429.jpg -../coco/images/val2014/COCO_val2014_000000364493.jpg -../coco/images/val2014/COCO_val2014_000000364567.jpg -../coco/images/val2014/COCO_val2014_000000364589.jpg -../coco/images/val2014/COCO_val2014_000000364757.jpg -../coco/images/val2014/COCO_val2014_000000365094.jpg -../coco/images/val2014/COCO_val2014_000000365103.jpg -../coco/images/val2014/COCO_val2014_000000365121.jpg -../coco/images/val2014/COCO_val2014_000000365207.jpg -../coco/images/val2014/COCO_val2014_000000365214.jpg -../coco/images/val2014/COCO_val2014_000000365317.jpg -../coco/images/val2014/COCO_val2014_000000365485.jpg -../coco/images/val2014/COCO_val2014_000000365511.jpg -../coco/images/val2014/COCO_val2014_000000365540.jpg -../coco/images/val2014/COCO_val2014_000000365618.jpg -../coco/images/val2014/COCO_val2014_000000365822.jpg -../coco/images/val2014/COCO_val2014_000000365983.jpg -../coco/images/val2014/COCO_val2014_000000366031.jpg -../coco/images/val2014/COCO_val2014_000000366111.jpg -../coco/images/val2014/COCO_val2014_000000366178.jpg -../coco/images/val2014/COCO_val2014_000000366199.jpg -../coco/images/val2014/COCO_val2014_000000366569.jpg -../coco/images/val2014/COCO_val2014_000000366576.jpg -../coco/images/val2014/COCO_val2014_000000366611.jpg -../coco/images/val2014/COCO_val2014_000000366615.jpg -../coco/images/val2014/COCO_val2014_000000366867.jpg -../coco/images/val2014/COCO_val2014_000000367087.jpg -../coco/images/val2014/COCO_val2014_000000367205.jpg -../coco/images/val2014/COCO_val2014_000000367452.jpg -../coco/images/val2014/COCO_val2014_000000367509.jpg -../coco/images/val2014/COCO_val2014_000000367558.jpg -../coco/images/val2014/COCO_val2014_000000367571.jpg -../coco/images/val2014/COCO_val2014_000000367582.jpg -../coco/images/val2014/COCO_val2014_000000367608.jpg -../coco/images/val2014/COCO_val2014_000000367626.jpg -../coco/images/val2014/COCO_val2014_000000367673.jpg -../coco/images/val2014/COCO_val2014_000000367843.jpg -../coco/images/val2014/COCO_val2014_000000367893.jpg -../coco/images/val2014/COCO_val2014_000000367953.jpg -../coco/images/val2014/COCO_val2014_000000368038.jpg -../coco/images/val2014/COCO_val2014_000000368096.jpg -../coco/images/val2014/COCO_val2014_000000368222.jpg -../coco/images/val2014/COCO_val2014_000000368367.jpg -../coco/images/val2014/COCO_val2014_000000368648.jpg -../coco/images/val2014/COCO_val2014_000000368752.jpg -../coco/images/val2014/COCO_val2014_000000369185.jpg -../coco/images/val2014/COCO_val2014_000000369294.jpg -../coco/images/val2014/COCO_val2014_000000369309.jpg -../coco/images/val2014/COCO_val2014_000000369675.jpg -../coco/images/val2014/COCO_val2014_000000369685.jpg -../coco/images/val2014/COCO_val2014_000000369776.jpg -../coco/images/val2014/COCO_val2014_000000369840.jpg -../coco/images/val2014/COCO_val2014_000000369887.jpg -../coco/images/val2014/COCO_val2014_000000369997.jpg -../coco/images/val2014/COCO_val2014_000000370233.jpg -../coco/images/val2014/COCO_val2014_000000370279.jpg -../coco/images/val2014/COCO_val2014_000000370315.jpg -../coco/images/val2014/COCO_val2014_000000370331.jpg -../coco/images/val2014/COCO_val2014_000000370388.jpg -../coco/images/val2014/COCO_val2014_000000370513.jpg -../coco/images/val2014/COCO_val2014_000000370602.jpg -../coco/images/val2014/COCO_val2014_000000370701.jpg -../coco/images/val2014/COCO_val2014_000000370749.jpg -../coco/images/val2014/COCO_val2014_000000370839.jpg -../coco/images/val2014/COCO_val2014_000000370929.jpg -../coco/images/val2014/COCO_val2014_000000371289.jpg -../coco/images/val2014/COCO_val2014_000000371326.jpg -../coco/images/val2014/COCO_val2014_000000371497.jpg -../coco/images/val2014/COCO_val2014_000000371552.jpg -../coco/images/val2014/COCO_val2014_000000371822.jpg -../coco/images/val2014/COCO_val2014_000000371841.jpg -../coco/images/val2014/COCO_val2014_000000371948.jpg -../coco/images/val2014/COCO_val2014_000000371973.jpg -../coco/images/val2014/COCO_val2014_000000372230.jpg -../coco/images/val2014/COCO_val2014_000000372362.jpg -../coco/images/val2014/COCO_val2014_000000372433.jpg -../coco/images/val2014/COCO_val2014_000000372471.jpg -../coco/images/val2014/COCO_val2014_000000372494.jpg -../coco/images/val2014/COCO_val2014_000000372580.jpg -../coco/images/val2014/COCO_val2014_000000372718.jpg -../coco/images/val2014/COCO_val2014_000000372855.jpg -../coco/images/val2014/COCO_val2014_000000373007.jpg -../coco/images/val2014/COCO_val2014_000000373060.jpg -../coco/images/val2014/COCO_val2014_000000373119.jpg -../coco/images/val2014/COCO_val2014_000000373140.jpg -../coco/images/val2014/COCO_val2014_000000373193.jpg -../coco/images/val2014/COCO_val2014_000000373255.jpg -../coco/images/val2014/COCO_val2014_000000373284.jpg -../coco/images/val2014/COCO_val2014_000000373375.jpg -../coco/images/val2014/COCO_val2014_000000373440.jpg -../coco/images/val2014/COCO_val2014_000000373571.jpg -../coco/images/val2014/COCO_val2014_000000373705.jpg -../coco/images/val2014/COCO_val2014_000000373988.jpg -../coco/images/val2014/COCO_val2014_000000374111.jpg -../coco/images/val2014/COCO_val2014_000000374241.jpg -../coco/images/val2014/COCO_val2014_000000374641.jpg -../coco/images/val2014/COCO_val2014_000000374702.jpg -../coco/images/val2014/COCO_val2014_000000374734.jpg -../coco/images/val2014/COCO_val2014_000000374886.jpg -../coco/images/val2014/COCO_val2014_000000375063.jpg -../coco/images/val2014/COCO_val2014_000000375180.jpg -../coco/images/val2014/COCO_val2014_000000375198.jpg -../coco/images/val2014/COCO_val2014_000000375211.jpg -../coco/images/val2014/COCO_val2014_000000375317.jpg -../coco/images/val2014/COCO_val2014_000000375530.jpg -../coco/images/val2014/COCO_val2014_000000375763.jpg -../coco/images/val2014/COCO_val2014_000000375902.jpg -../coco/images/val2014/COCO_val2014_000000375914.jpg -../coco/images/val2014/COCO_val2014_000000376059.jpg -../coco/images/val2014/COCO_val2014_000000376187.jpg -../coco/images/val2014/COCO_val2014_000000376233.jpg -../coco/images/val2014/COCO_val2014_000000376295.jpg -../coco/images/val2014/COCO_val2014_000000376307.jpg -../coco/images/val2014/COCO_val2014_000000376358.jpg -../coco/images/val2014/COCO_val2014_000000376441.jpg -../coco/images/val2014/COCO_val2014_000000376667.jpg -../coco/images/val2014/COCO_val2014_000000376677.jpg -../coco/images/val2014/COCO_val2014_000000376751.jpg -../coco/images/val2014/COCO_val2014_000000376900.jpg -../coco/images/val2014/COCO_val2014_000000376996.jpg -../coco/images/val2014/COCO_val2014_000000377003.jpg -../coco/images/val2014/COCO_val2014_000000377060.jpg -../coco/images/val2014/COCO_val2014_000000377080.jpg -../coco/images/val2014/COCO_val2014_000000377355.jpg -../coco/images/val2014/COCO_val2014_000000377595.jpg -../coco/images/val2014/COCO_val2014_000000377723.jpg -../coco/images/val2014/COCO_val2014_000000377867.jpg -../coco/images/val2014/COCO_val2014_000000377882.jpg -../coco/images/val2014/COCO_val2014_000000377984.jpg -../coco/images/val2014/COCO_val2014_000000378099.jpg -../coco/images/val2014/COCO_val2014_000000378139.jpg -../coco/images/val2014/COCO_val2014_000000378284.jpg -../coco/images/val2014/COCO_val2014_000000378403.jpg -../coco/images/val2014/COCO_val2014_000000378448.jpg -../coco/images/val2014/COCO_val2014_000000378652.jpg -../coco/images/val2014/COCO_val2014_000000378712.jpg -../coco/images/val2014/COCO_val2014_000000378727.jpg -../coco/images/val2014/COCO_val2014_000000378831.jpg -../coco/images/val2014/COCO_val2014_000000379022.jpg -../coco/images/val2014/COCO_val2014_000000379070.jpg -../coco/images/val2014/COCO_val2014_000000379108.jpg -../coco/images/val2014/COCO_val2014_000000379162.jpg -../coco/images/val2014/COCO_val2014_000000379332.jpg -../coco/images/val2014/COCO_val2014_000000379476.jpg -../coco/images/val2014/COCO_val2014_000000379584.jpg -../coco/images/val2014/COCO_val2014_000000379605.jpg -../coco/images/val2014/COCO_val2014_000000379837.jpg -../coco/images/val2014/COCO_val2014_000000379869.jpg -../coco/images/val2014/COCO_val2014_000000380088.jpg -../coco/images/val2014/COCO_val2014_000000380106.jpg -../coco/images/val2014/COCO_val2014_000000380299.jpg -../coco/images/val2014/COCO_val2014_000000380414.jpg -../coco/images/val2014/COCO_val2014_000000380609.jpg -../coco/images/val2014/COCO_val2014_000000380639.jpg -../coco/images/val2014/COCO_val2014_000000380698.jpg -../coco/images/val2014/COCO_val2014_000000380756.jpg -../coco/images/val2014/COCO_val2014_000000380892.jpg -../coco/images/val2014/COCO_val2014_000000381031.jpg -../coco/images/val2014/COCO_val2014_000000381060.jpg -../coco/images/val2014/COCO_val2014_000000381213.jpg -../coco/images/val2014/COCO_val2014_000000381527.jpg -../coco/images/val2014/COCO_val2014_000000381551.jpg -../coco/images/val2014/COCO_val2014_000000381709.jpg -../coco/images/val2014/COCO_val2014_000000382088.jpg -../coco/images/val2014/COCO_val2014_000000382333.jpg -../coco/images/val2014/COCO_val2014_000000382715.jpg -../coco/images/val2014/COCO_val2014_000000382717.jpg -../coco/images/val2014/COCO_val2014_000000382855.jpg -../coco/images/val2014/COCO_val2014_000000383039.jpg -../coco/images/val2014/COCO_val2014_000000383065.jpg -../coco/images/val2014/COCO_val2014_000000383073.jpg -../coco/images/val2014/COCO_val2014_000000383087.jpg -../coco/images/val2014/COCO_val2014_000000383339.jpg -../coco/images/val2014/COCO_val2014_000000383341.jpg -../coco/images/val2014/COCO_val2014_000000383384.jpg -../coco/images/val2014/COCO_val2014_000000383462.jpg -../coco/images/val2014/COCO_val2014_000000384012.jpg -../coco/images/val2014/COCO_val2014_000000384040.jpg -../coco/images/val2014/COCO_val2014_000000384188.jpg -../coco/images/val2014/COCO_val2014_000000384333.jpg -../coco/images/val2014/COCO_val2014_000000384348.jpg -../coco/images/val2014/COCO_val2014_000000384527.jpg -../coco/images/val2014/COCO_val2014_000000384554.jpg -../coco/images/val2014/COCO_val2014_000000384827.jpg -../coco/images/val2014/COCO_val2014_000000385057.jpg -../coco/images/val2014/COCO_val2014_000000385320.jpg -../coco/images/val2014/COCO_val2014_000000385346.jpg -../coco/images/val2014/COCO_val2014_000000385580.jpg -../coco/images/val2014/COCO_val2014_000000385779.jpg -../coco/images/val2014/COCO_val2014_000000385877.jpg -../coco/images/val2014/COCO_val2014_000000385997.jpg -../coco/images/val2014/COCO_val2014_000000386119.jpg -../coco/images/val2014/COCO_val2014_000000386134.jpg -../coco/images/val2014/COCO_val2014_000000386187.jpg -../coco/images/val2014/COCO_val2014_000000386224.jpg -../coco/images/val2014/COCO_val2014_000000386457.jpg -../coco/images/val2014/COCO_val2014_000000386585.jpg -../coco/images/val2014/COCO_val2014_000000386661.jpg -../coco/images/val2014/COCO_val2014_000000386707.jpg -../coco/images/val2014/COCO_val2014_000000386755.jpg -../coco/images/val2014/COCO_val2014_000000386786.jpg -../coco/images/val2014/COCO_val2014_000000386929.jpg -../coco/images/val2014/COCO_val2014_000000387150.jpg -../coco/images/val2014/COCO_val2014_000000387244.jpg -../coco/images/val2014/COCO_val2014_000000387369.jpg -../coco/images/val2014/COCO_val2014_000000387383.jpg -../coco/images/val2014/COCO_val2014_000000387387.jpg -../coco/images/val2014/COCO_val2014_000000387551.jpg -../coco/images/val2014/COCO_val2014_000000387576.jpg -../coco/images/val2014/COCO_val2014_000000387655.jpg -../coco/images/val2014/COCO_val2014_000000387696.jpg -../coco/images/val2014/COCO_val2014_000000387776.jpg -../coco/images/val2014/COCO_val2014_000000387850.jpg -../coco/images/val2014/COCO_val2014_000000388009.jpg -../coco/images/val2014/COCO_val2014_000000388325.jpg -../coco/images/val2014/COCO_val2014_000000388413.jpg -../coco/images/val2014/COCO_val2014_000000388464.jpg -../coco/images/val2014/COCO_val2014_000000388677.jpg -../coco/images/val2014/COCO_val2014_000000388721.jpg -../coco/images/val2014/COCO_val2014_000000388881.jpg -../coco/images/val2014/COCO_val2014_000000388903.jpg -../coco/images/val2014/COCO_val2014_000000389056.jpg -../coco/images/val2014/COCO_val2014_000000389316.jpg -../coco/images/val2014/COCO_val2014_000000389340.jpg -../coco/images/val2014/COCO_val2014_000000389378.jpg -../coco/images/val2014/COCO_val2014_000000389604.jpg -../coco/images/val2014/COCO_val2014_000000389622.jpg -../coco/images/val2014/COCO_val2014_000000389644.jpg -../coco/images/val2014/COCO_val2014_000000389738.jpg -../coco/images/val2014/COCO_val2014_000000389753.jpg -../coco/images/val2014/COCO_val2014_000000389843.jpg -../coco/images/val2014/COCO_val2014_000000390017.jpg -../coco/images/val2014/COCO_val2014_000000390068.jpg -../coco/images/val2014/COCO_val2014_000000390137.jpg -../coco/images/val2014/COCO_val2014_000000390238.jpg -../coco/images/val2014/COCO_val2014_000000390246.jpg -../coco/images/val2014/COCO_val2014_000000390322.jpg -../coco/images/val2014/COCO_val2014_000000390585.jpg -../coco/images/val2014/COCO_val2014_000000390685.jpg -../coco/images/val2014/COCO_val2014_000000390689.jpg -../coco/images/val2014/COCO_val2014_000000390769.jpg -../coco/images/val2014/COCO_val2014_000000390795.jpg -../coco/images/val2014/COCO_val2014_000000390902.jpg -../coco/images/val2014/COCO_val2014_000000391225.jpg -../coco/images/val2014/COCO_val2014_000000391365.jpg -../coco/images/val2014/COCO_val2014_000000391463.jpg -../coco/images/val2014/COCO_val2014_000000391689.jpg -../coco/images/val2014/COCO_val2014_000000391862.jpg -../coco/images/val2014/COCO_val2014_000000391940.jpg -../coco/images/val2014/COCO_val2014_000000391978.jpg -../coco/images/val2014/COCO_val2014_000000392004.jpg -../coco/images/val2014/COCO_val2014_000000392251.jpg -../coco/images/val2014/COCO_val2014_000000392364.jpg -../coco/images/val2014/COCO_val2014_000000392392.jpg -../coco/images/val2014/COCO_val2014_000000392753.jpg -../coco/images/val2014/COCO_val2014_000000392981.jpg -../coco/images/val2014/COCO_val2014_000000393031.jpg -../coco/images/val2014/COCO_val2014_000000393282.jpg -../coco/images/val2014/COCO_val2014_000000393372.jpg -../coco/images/val2014/COCO_val2014_000000393497.jpg -../coco/images/val2014/COCO_val2014_000000393674.jpg -../coco/images/val2014/COCO_val2014_000000393692.jpg -../coco/images/val2014/COCO_val2014_000000393794.jpg -../coco/images/val2014/COCO_val2014_000000393874.jpg -../coco/images/val2014/COCO_val2014_000000394132.jpg -../coco/images/val2014/COCO_val2014_000000394157.jpg -../coco/images/val2014/COCO_val2014_000000394352.jpg -../coco/images/val2014/COCO_val2014_000000394559.jpg -../coco/images/val2014/COCO_val2014_000000394611.jpg -../coco/images/val2014/COCO_val2014_000000394677.jpg -../coco/images/val2014/COCO_val2014_000000395180.jpg -../coco/images/val2014/COCO_val2014_000000395290.jpg -../coco/images/val2014/COCO_val2014_000000395463.jpg -../coco/images/val2014/COCO_val2014_000000395531.jpg -../coco/images/val2014/COCO_val2014_000000395634.jpg -../coco/images/val2014/COCO_val2014_000000395665.jpg -../coco/images/val2014/COCO_val2014_000000395717.jpg -../coco/images/val2014/COCO_val2014_000000395723.jpg -../coco/images/val2014/COCO_val2014_000000395801.jpg -../coco/images/val2014/COCO_val2014_000000396167.jpg -../coco/images/val2014/COCO_val2014_000000396178.jpg -../coco/images/val2014/COCO_val2014_000000396369.jpg -../coco/images/val2014/COCO_val2014_000000396526.jpg -../coco/images/val2014/COCO_val2014_000000396736.jpg -../coco/images/val2014/COCO_val2014_000000396997.jpg -../coco/images/val2014/COCO_val2014_000000397322.jpg -../coco/images/val2014/COCO_val2014_000000397475.jpg -../coco/images/val2014/COCO_val2014_000000398007.jpg -../coco/images/val2014/COCO_val2014_000000398045.jpg -../coco/images/val2014/COCO_val2014_000000398119.jpg -../coco/images/val2014/COCO_val2014_000000398222.jpg -../coco/images/val2014/COCO_val2014_000000398438.jpg -../coco/images/val2014/COCO_val2014_000000398450.jpg -../coco/images/val2014/COCO_val2014_000000398519.jpg -../coco/images/val2014/COCO_val2014_000000398604.jpg -../coco/images/val2014/COCO_val2014_000000398606.jpg -../coco/images/val2014/COCO_val2014_000000398637.jpg -../coco/images/val2014/COCO_val2014_000000398753.jpg -../coco/images/val2014/COCO_val2014_000000398866.jpg -../coco/images/val2014/COCO_val2014_000000398905.jpg -../coco/images/val2014/COCO_val2014_000000399205.jpg -../coco/images/val2014/COCO_val2014_000000399545.jpg -../coco/images/val2014/COCO_val2014_000000399567.jpg -../coco/images/val2014/COCO_val2014_000000399655.jpg -../coco/images/val2014/COCO_val2014_000000399741.jpg -../coco/images/val2014/COCO_val2014_000000399744.jpg -../coco/images/val2014/COCO_val2014_000000399822.jpg -../coco/images/val2014/COCO_val2014_000000399832.jpg -../coco/images/val2014/COCO_val2014_000000399865.jpg -../coco/images/val2014/COCO_val2014_000000399991.jpg -../coco/images/val2014/COCO_val2014_000000400044.jpg -../coco/images/val2014/COCO_val2014_000000400046.jpg -../coco/images/val2014/COCO_val2014_000000400189.jpg -../coco/images/val2014/COCO_val2014_000000400202.jpg -../coco/images/val2014/COCO_val2014_000000400317.jpg -../coco/images/val2014/COCO_val2014_000000400975.jpg -../coco/images/val2014/COCO_val2014_000000400976.jpg -../coco/images/val2014/COCO_val2014_000000401028.jpg -../coco/images/val2014/COCO_val2014_000000401088.jpg -../coco/images/val2014/COCO_val2014_000000401092.jpg -../coco/images/val2014/COCO_val2014_000000401124.jpg -../coco/images/val2014/COCO_val2014_000000401320.jpg -../coco/images/val2014/COCO_val2014_000000401384.jpg -../coco/images/val2014/COCO_val2014_000000401425.jpg -../coco/images/val2014/COCO_val2014_000000401591.jpg -../coco/images/val2014/COCO_val2014_000000401860.jpg -../coco/images/val2014/COCO_val2014_000000401892.jpg -../coco/images/val2014/COCO_val2014_000000402000.jpg -../coco/images/val2014/COCO_val2014_000000402334.jpg -../coco/images/val2014/COCO_val2014_000000402717.jpg -../coco/images/val2014/COCO_val2014_000000402723.jpg -../coco/images/val2014/COCO_val2014_000000402867.jpg -../coco/images/val2014/COCO_val2014_000000402887.jpg -../coco/images/val2014/COCO_val2014_000000402909.jpg -../coco/images/val2014/COCO_val2014_000000403087.jpg -../coco/images/val2014/COCO_val2014_000000403180.jpg -../coco/images/val2014/COCO_val2014_000000403315.jpg -../coco/images/val2014/COCO_val2014_000000403378.jpg -../coco/images/val2014/COCO_val2014_000000403639.jpg -../coco/images/val2014/COCO_val2014_000000403675.jpg -../coco/images/val2014/COCO_val2014_000000403950.jpg -../coco/images/val2014/COCO_val2014_000000403975.jpg -../coco/images/val2014/COCO_val2014_000000404027.jpg -../coco/images/val2014/COCO_val2014_000000404601.jpg -../coco/images/val2014/COCO_val2014_000000404602.jpg -../coco/images/val2014/COCO_val2014_000000404886.jpg -../coco/images/val2014/COCO_val2014_000000404889.jpg -../coco/images/val2014/COCO_val2014_000000405062.jpg -../coco/images/val2014/COCO_val2014_000000405104.jpg -../coco/images/val2014/COCO_val2014_000000405226.jpg -../coco/images/val2014/COCO_val2014_000000405306.jpg -../coco/images/val2014/COCO_val2014_000000405530.jpg -../coco/images/val2014/COCO_val2014_000000405970.jpg -../coco/images/val2014/COCO_val2014_000000406053.jpg -../coco/images/val2014/COCO_val2014_000000406211.jpg -../coco/images/val2014/COCO_val2014_000000406217.jpg -../coco/images/val2014/COCO_val2014_000000406417.jpg -../coco/images/val2014/COCO_val2014_000000406451.jpg -../coco/images/val2014/COCO_val2014_000000406841.jpg -../coco/images/val2014/COCO_val2014_000000406848.jpg -../coco/images/val2014/COCO_val2014_000000406976.jpg -../coco/images/val2014/COCO_val2014_000000407017.jpg -../coco/images/val2014/COCO_val2014_000000407259.jpg -../coco/images/val2014/COCO_val2014_000000407443.jpg -../coco/images/val2014/COCO_val2014_000000407524.jpg -../coco/images/val2014/COCO_val2014_000000407650.jpg -../coco/images/val2014/COCO_val2014_000000407945.jpg -../coco/images/val2014/COCO_val2014_000000407948.jpg -../coco/images/val2014/COCO_val2014_000000407960.jpg -../coco/images/val2014/COCO_val2014_000000408120.jpg -../coco/images/val2014/COCO_val2014_000000408208.jpg -../coco/images/val2014/COCO_val2014_000000408255.jpg -../coco/images/val2014/COCO_val2014_000000408336.jpg -../coco/images/val2014/COCO_val2014_000000408534.jpg -../coco/images/val2014/COCO_val2014_000000408774.jpg -../coco/images/val2014/COCO_val2014_000000408830.jpg -../coco/images/val2014/COCO_val2014_000000408873.jpg -../coco/images/val2014/COCO_val2014_000000409100.jpg -../coco/images/val2014/COCO_val2014_000000409115.jpg -../coco/images/val2014/COCO_val2014_000000409181.jpg -../coco/images/val2014/COCO_val2014_000000409542.jpg -../coco/images/val2014/COCO_val2014_000000409725.jpg -../coco/images/val2014/COCO_val2014_000000409964.jpg -../coco/images/val2014/COCO_val2014_000000410068.jpg -../coco/images/val2014/COCO_val2014_000000410576.jpg -../coco/images/val2014/COCO_val2014_000000410583.jpg -../coco/images/val2014/COCO_val2014_000000410587.jpg -../coco/images/val2014/COCO_val2014_000000410612.jpg -../coco/images/val2014/COCO_val2014_000000410724.jpg -../coco/images/val2014/COCO_val2014_000000411187.jpg -../coco/images/val2014/COCO_val2014_000000411188.jpg -../coco/images/val2014/COCO_val2014_000000411405.jpg -../coco/images/val2014/COCO_val2014_000000411768.jpg -../coco/images/val2014/COCO_val2014_000000411774.jpg -../coco/images/val2014/COCO_val2014_000000411821.jpg -../coco/images/val2014/COCO_val2014_000000412015.jpg -../coco/images/val2014/COCO_val2014_000000412204.jpg -../coco/images/val2014/COCO_val2014_000000412240.jpg -../coco/images/val2014/COCO_val2014_000000412364.jpg -../coco/images/val2014/COCO_val2014_000000412437.jpg -../coco/images/val2014/COCO_val2014_000000412464.jpg -../coco/images/val2014/COCO_val2014_000000412510.jpg -../coco/images/val2014/COCO_val2014_000000412551.jpg -../coco/images/val2014/COCO_val2014_000000412592.jpg -../coco/images/val2014/COCO_val2014_000000412604.jpg -../coco/images/val2014/COCO_val2014_000000412753.jpg -../coco/images/val2014/COCO_val2014_000000413339.jpg -../coco/images/val2014/COCO_val2014_000000413341.jpg -../coco/images/val2014/COCO_val2014_000000413616.jpg -../coco/images/val2014/COCO_val2014_000000413822.jpg -../coco/images/val2014/COCO_val2014_000000413839.jpg -../coco/images/val2014/COCO_val2014_000000413950.jpg -../coco/images/val2014/COCO_val2014_000000413959.jpg -../coco/images/val2014/COCO_val2014_000000414122.jpg -../coco/images/val2014/COCO_val2014_000000414216.jpg -../coco/images/val2014/COCO_val2014_000000414261.jpg -../coco/images/val2014/COCO_val2014_000000414289.jpg -../coco/images/val2014/COCO_val2014_000000414661.jpg -../coco/images/val2014/COCO_val2014_000000414698.jpg -../coco/images/val2014/COCO_val2014_000000414857.jpg -../coco/images/val2014/COCO_val2014_000000415020.jpg -../coco/images/val2014/COCO_val2014_000000415163.jpg -../coco/images/val2014/COCO_val2014_000000415393.jpg -../coco/images/val2014/COCO_val2014_000000415434.jpg -../coco/images/val2014/COCO_val2014_000000415585.jpg -../coco/images/val2014/COCO_val2014_000000415770.jpg -../coco/images/val2014/COCO_val2014_000000415798.jpg -../coco/images/val2014/COCO_val2014_000000415841.jpg -../coco/images/val2014/COCO_val2014_000000415882.jpg -../coco/images/val2014/COCO_val2014_000000415885.jpg -../coco/images/val2014/COCO_val2014_000000415958.jpg -../coco/images/val2014/COCO_val2014_000000416059.jpg -../coco/images/val2014/COCO_val2014_000000416088.jpg -../coco/images/val2014/COCO_val2014_000000416385.jpg -../coco/images/val2014/COCO_val2014_000000416405.jpg -../coco/images/val2014/COCO_val2014_000000416467.jpg -../coco/images/val2014/COCO_val2014_000000416489.jpg -../coco/images/val2014/COCO_val2014_000000416660.jpg -../coco/images/val2014/COCO_val2014_000000416668.jpg -../coco/images/val2014/COCO_val2014_000000416885.jpg -../coco/images/val2014/COCO_val2014_000000417416.jpg -../coco/images/val2014/COCO_val2014_000000417727.jpg -../coco/images/val2014/COCO_val2014_000000417846.jpg -../coco/images/val2014/COCO_val2014_000000417946.jpg -../coco/images/val2014/COCO_val2014_000000417965.jpg -../coco/images/val2014/COCO_val2014_000000418226.jpg -../coco/images/val2014/COCO_val2014_000000418275.jpg -../coco/images/val2014/COCO_val2014_000000418288.jpg -../coco/images/val2014/COCO_val2014_000000418533.jpg -../coco/images/val2014/COCO_val2014_000000418548.jpg -../coco/images/val2014/COCO_val2014_000000418565.jpg -../coco/images/val2014/COCO_val2014_000000418961.jpg -../coco/images/val2014/COCO_val2014_000000419216.jpg -../coco/images/val2014/COCO_val2014_000000419371.jpg -../coco/images/val2014/COCO_val2014_000000419379.jpg -../coco/images/val2014/COCO_val2014_000000419386.jpg -../coco/images/val2014/COCO_val2014_000000419558.jpg -../coco/images/val2014/COCO_val2014_000000419848.jpg -../coco/images/val2014/COCO_val2014_000000420059.jpg -../coco/images/val2014/COCO_val2014_000000420230.jpg -../coco/images/val2014/COCO_val2014_000000420339.jpg -../coco/images/val2014/COCO_val2014_000000420546.jpg -../coco/images/val2014/COCO_val2014_000000420610.jpg -../coco/images/val2014/COCO_val2014_000000420882.jpg -../coco/images/val2014/COCO_val2014_000000420929.jpg -../coco/images/val2014/COCO_val2014_000000421361.jpg -../coco/images/val2014/COCO_val2014_000000421401.jpg -../coco/images/val2014/COCO_val2014_000000421673.jpg -../coco/images/val2014/COCO_val2014_000000422424.jpg -../coco/images/val2014/COCO_val2014_000000422432.jpg -../coco/images/val2014/COCO_val2014_000000422536.jpg -../coco/images/val2014/COCO_val2014_000000422622.jpg -../coco/images/val2014/COCO_val2014_000000422706.jpg -../coco/images/val2014/COCO_val2014_000000422778.jpg -../coco/images/val2014/COCO_val2014_000000422833.jpg -../coco/images/val2014/COCO_val2014_000000422870.jpg -../coco/images/val2014/COCO_val2014_000000423005.jpg -../coco/images/val2014/COCO_val2014_000000423048.jpg -../coco/images/val2014/COCO_val2014_000000423104.jpg -../coco/images/val2014/COCO_val2014_000000423123.jpg -../coco/images/val2014/COCO_val2014_000000423172.jpg -../coco/images/val2014/COCO_val2014_000000423189.jpg -../coco/images/val2014/COCO_val2014_000000423337.jpg -../coco/images/val2014/COCO_val2014_000000423613.jpg -../coco/images/val2014/COCO_val2014_000000423617.jpg -../coco/images/val2014/COCO_val2014_000000423715.jpg -../coco/images/val2014/COCO_val2014_000000423740.jpg -../coco/images/val2014/COCO_val2014_000000424147.jpg -../coco/images/val2014/COCO_val2014_000000424155.jpg -../coco/images/val2014/COCO_val2014_000000424192.jpg -../coco/images/val2014/COCO_val2014_000000424247.jpg -../coco/images/val2014/COCO_val2014_000000424293.jpg -../coco/images/val2014/COCO_val2014_000000424378.jpg -../coco/images/val2014/COCO_val2014_000000424392.jpg -../coco/images/val2014/COCO_val2014_000000424633.jpg -../coco/images/val2014/COCO_val2014_000000424975.jpg -../coco/images/val2014/COCO_val2014_000000425303.jpg -../coco/images/val2014/COCO_val2014_000000425324.jpg -../coco/images/val2014/COCO_val2014_000000425371.jpg -../coco/images/val2014/COCO_val2014_000000425388.jpg -../coco/images/val2014/COCO_val2014_000000425462.jpg -../coco/images/val2014/COCO_val2014_000000425475.jpg -../coco/images/val2014/COCO_val2014_000000425526.jpg -../coco/images/val2014/COCO_val2014_000000425848.jpg -../coco/images/val2014/COCO_val2014_000000425870.jpg -../coco/images/val2014/COCO_val2014_000000425948.jpg -../coco/images/val2014/COCO_val2014_000000425973.jpg -../coco/images/val2014/COCO_val2014_000000426070.jpg -../coco/images/val2014/COCO_val2014_000000426075.jpg -../coco/images/val2014/COCO_val2014_000000426377.jpg -../coco/images/val2014/COCO_val2014_000000426532.jpg -../coco/images/val2014/COCO_val2014_000000426795.jpg -../coco/images/val2014/COCO_val2014_000000426852.jpg -../coco/images/val2014/COCO_val2014_000000426917.jpg -../coco/images/val2014/COCO_val2014_000000427223.jpg -../coco/images/val2014/COCO_val2014_000000427500.jpg -../coco/images/val2014/COCO_val2014_000000427561.jpg -../coco/images/val2014/COCO_val2014_000000427782.jpg -../coco/images/val2014/COCO_val2014_000000427965.jpg -../coco/images/val2014/COCO_val2014_000000428178.jpg -../coco/images/val2014/COCO_val2014_000000428231.jpg -../coco/images/val2014/COCO_val2014_000000428234.jpg -../coco/images/val2014/COCO_val2014_000000428248.jpg -../coco/images/val2014/COCO_val2014_000000428366.jpg -../coco/images/val2014/COCO_val2014_000000428562.jpg -../coco/images/val2014/COCO_val2014_000000428812.jpg -../coco/images/val2014/COCO_val2014_000000428867.jpg -../coco/images/val2014/COCO_val2014_000000429293.jpg -../coco/images/val2014/COCO_val2014_000000429369.jpg -../coco/images/val2014/COCO_val2014_000000429718.jpg -../coco/images/val2014/COCO_val2014_000000429924.jpg -../coco/images/val2014/COCO_val2014_000000429996.jpg -../coco/images/val2014/COCO_val2014_000000430056.jpg -../coco/images/val2014/COCO_val2014_000000430073.jpg -../coco/images/val2014/COCO_val2014_000000430238.jpg -../coco/images/val2014/COCO_val2014_000000430286.jpg -../coco/images/val2014/COCO_val2014_000000430467.jpg -../coco/images/val2014/COCO_val2014_000000430518.jpg -../coco/images/val2014/COCO_val2014_000000430583.jpg -../coco/images/val2014/COCO_val2014_000000430590.jpg -../coco/images/val2014/COCO_val2014_000000430744.jpg -../coco/images/val2014/COCO_val2014_000000430788.jpg -../coco/images/val2014/COCO_val2014_000000430875.jpg -../coco/images/val2014/COCO_val2014_000000430973.jpg -../coco/images/val2014/COCO_val2014_000000431047.jpg -../coco/images/val2014/COCO_val2014_000000431236.jpg -../coco/images/val2014/COCO_val2014_000000431257.jpg -../coco/images/val2014/COCO_val2014_000000431464.jpg -../coco/images/val2014/COCO_val2014_000000431472.jpg -../coco/images/val2014/COCO_val2014_000000431521.jpg -../coco/images/val2014/COCO_val2014_000000431573.jpg -../coco/images/val2014/COCO_val2014_000000431594.jpg -../coco/images/val2014/COCO_val2014_000000431615.jpg -../coco/images/val2014/COCO_val2014_000000431671.jpg -../coco/images/val2014/COCO_val2014_000000431727.jpg -../coco/images/val2014/COCO_val2014_000000431742.jpg -../coco/images/val2014/COCO_val2014_000000432125.jpg -../coco/images/val2014/COCO_val2014_000000432160.jpg -../coco/images/val2014/COCO_val2014_000000432276.jpg -../coco/images/val2014/COCO_val2014_000000432534.jpg -../coco/images/val2014/COCO_val2014_000000432898.jpg -../coco/images/val2014/COCO_val2014_000000433075.jpg -../coco/images/val2014/COCO_val2014_000000433554.jpg -../coco/images/val2014/COCO_val2014_000000433714.jpg -../coco/images/val2014/COCO_val2014_000000433804.jpg -../coco/images/val2014/COCO_val2014_000000433845.jpg -../coco/images/val2014/COCO_val2014_000000433883.jpg -../coco/images/val2014/COCO_val2014_000000433892.jpg -../coco/images/val2014/COCO_val2014_000000433963.jpg -../coco/images/val2014/COCO_val2014_000000433980.jpg -../coco/images/val2014/COCO_val2014_000000434006.jpg -../coco/images/val2014/COCO_val2014_000000434060.jpg -../coco/images/val2014/COCO_val2014_000000434219.jpg -../coco/images/val2014/COCO_val2014_000000434410.jpg -../coco/images/val2014/COCO_val2014_000000434488.jpg -../coco/images/val2014/COCO_val2014_000000434580.jpg -../coco/images/val2014/COCO_val2014_000000434622.jpg -../coco/images/val2014/COCO_val2014_000000434657.jpg -../coco/images/val2014/COCO_val2014_000000434787.jpg -../coco/images/val2014/COCO_val2014_000000434898.jpg -../coco/images/val2014/COCO_val2014_000000434915.jpg -../coco/images/val2014/COCO_val2014_000000435205.jpg -../coco/images/val2014/COCO_val2014_000000435206.jpg -../coco/images/val2014/COCO_val2014_000000435359.jpg -../coco/images/val2014/COCO_val2014_000000435391.jpg -../coco/images/val2014/COCO_val2014_000000435466.jpg -../coco/images/val2014/COCO_val2014_000000435533.jpg -../coco/images/val2014/COCO_val2014_000000435569.jpg -../coco/images/val2014/COCO_val2014_000000435598.jpg -../coco/images/val2014/COCO_val2014_000000435671.jpg -../coco/images/val2014/COCO_val2014_000000435703.jpg -../coco/images/val2014/COCO_val2014_000000435707.jpg -../coco/images/val2014/COCO_val2014_000000435742.jpg -../coco/images/val2014/COCO_val2014_000000435820.jpg -../coco/images/val2014/COCO_val2014_000000435823.jpg -../coco/images/val2014/COCO_val2014_000000435910.jpg -../coco/images/val2014/COCO_val2014_000000436044.jpg -../coco/images/val2014/COCO_val2014_000000436203.jpg -../coco/images/val2014/COCO_val2014_000000436350.jpg -../coco/images/val2014/COCO_val2014_000000436413.jpg -../coco/images/val2014/COCO_val2014_000000436603.jpg -../coco/images/val2014/COCO_val2014_000000436653.jpg -../coco/images/val2014/COCO_val2014_000000436694.jpg -../coco/images/val2014/COCO_val2014_000000436696.jpg -../coco/images/val2014/COCO_val2014_000000436738.jpg -../coco/images/val2014/COCO_val2014_000000437284.jpg -../coco/images/val2014/COCO_val2014_000000437298.jpg -../coco/images/val2014/COCO_val2014_000000437303.jpg -../coco/images/val2014/COCO_val2014_000000437393.jpg -../coco/images/val2014/COCO_val2014_000000437459.jpg -../coco/images/val2014/COCO_val2014_000000437720.jpg -../coco/images/val2014/COCO_val2014_000000437923.jpg -../coco/images/val2014/COCO_val2014_000000438103.jpg -../coco/images/val2014/COCO_val2014_000000438220.jpg -../coco/images/val2014/COCO_val2014_000000438807.jpg -../coco/images/val2014/COCO_val2014_000000438851.jpg -../coco/images/val2014/COCO_val2014_000000438985.jpg -../coco/images/val2014/COCO_val2014_000000438999.jpg -../coco/images/val2014/COCO_val2014_000000439015.jpg -../coco/images/val2014/COCO_val2014_000000439339.jpg -../coco/images/val2014/COCO_val2014_000000439522.jpg -../coco/images/val2014/COCO_val2014_000000439651.jpg -../coco/images/val2014/COCO_val2014_000000439777.jpg -../coco/images/val2014/COCO_val2014_000000440043.jpg -../coco/images/val2014/COCO_val2014_000000440062.jpg -../coco/images/val2014/COCO_val2014_000000440226.jpg -../coco/images/val2014/COCO_val2014_000000440299.jpg -../coco/images/val2014/COCO_val2014_000000440486.jpg -../coco/images/val2014/COCO_val2014_000000440500.jpg -../coco/images/val2014/COCO_val2014_000000440617.jpg -../coco/images/val2014/COCO_val2014_000000440646.jpg -../coco/images/val2014/COCO_val2014_000000440706.jpg -../coco/images/val2014/COCO_val2014_000000440779.jpg -../coco/images/val2014/COCO_val2014_000000441009.jpg -../coco/images/val2014/COCO_val2014_000000441072.jpg -../coco/images/val2014/COCO_val2014_000000441156.jpg -../coco/images/val2014/COCO_val2014_000000441211.jpg -../coco/images/val2014/COCO_val2014_000000441247.jpg -../coco/images/val2014/COCO_val2014_000000441496.jpg -../coco/images/val2014/COCO_val2014_000000441500.jpg -../coco/images/val2014/COCO_val2014_000000441695.jpg -../coco/images/val2014/COCO_val2014_000000441788.jpg -../coco/images/val2014/COCO_val2014_000000441824.jpg -../coco/images/val2014/COCO_val2014_000000441863.jpg -../coco/images/val2014/COCO_val2014_000000441969.jpg -../coco/images/val2014/COCO_val2014_000000441974.jpg -../coco/images/val2014/COCO_val2014_000000442128.jpg -../coco/images/val2014/COCO_val2014_000000442210.jpg -../coco/images/val2014/COCO_val2014_000000442223.jpg -../coco/images/val2014/COCO_val2014_000000442323.jpg -../coco/images/val2014/COCO_val2014_000000442387.jpg -../coco/images/val2014/COCO_val2014_000000442417.jpg -../coco/images/val2014/COCO_val2014_000000442523.jpg -../coco/images/val2014/COCO_val2014_000000442539.jpg -../coco/images/val2014/COCO_val2014_000000442746.jpg -../coco/images/val2014/COCO_val2014_000000442822.jpg -../coco/images/val2014/COCO_val2014_000000442877.jpg -../coco/images/val2014/COCO_val2014_000000442952.jpg -../coco/images/val2014/COCO_val2014_000000443313.jpg -../coco/images/val2014/COCO_val2014_000000443334.jpg -../coco/images/val2014/COCO_val2014_000000443343.jpg -../coco/images/val2014/COCO_val2014_000000443361.jpg -../coco/images/val2014/COCO_val2014_000000443498.jpg -../coco/images/val2014/COCO_val2014_000000443537.jpg -../coco/images/val2014/COCO_val2014_000000443591.jpg -../coco/images/val2014/COCO_val2014_000000443723.jpg -../coco/images/val2014/COCO_val2014_000000443797.jpg -../coco/images/val2014/COCO_val2014_000000443969.jpg -../coco/images/val2014/COCO_val2014_000000444236.jpg -../coco/images/val2014/COCO_val2014_000000444304.jpg -../coco/images/val2014/COCO_val2014_000000444390.jpg -../coco/images/val2014/COCO_val2014_000000444495.jpg -../coco/images/val2014/COCO_val2014_000000444626.jpg -../coco/images/val2014/COCO_val2014_000000444746.jpg -../coco/images/val2014/COCO_val2014_000000444755.jpg -../coco/images/val2014/COCO_val2014_000000444879.jpg -../coco/images/val2014/COCO_val2014_000000444888.jpg -../coco/images/val2014/COCO_val2014_000000445009.jpg -../coco/images/val2014/COCO_val2014_000000445014.jpg -../coco/images/val2014/COCO_val2014_000000445200.jpg -../coco/images/val2014/COCO_val2014_000000445267.jpg -../coco/images/val2014/COCO_val2014_000000445512.jpg -../coco/images/val2014/COCO_val2014_000000445567.jpg -../coco/images/val2014/COCO_val2014_000000445594.jpg -../coco/images/val2014/COCO_val2014_000000445602.jpg -../coco/images/val2014/COCO_val2014_000000445643.jpg -../coco/images/val2014/COCO_val2014_000000446324.jpg -../coco/images/val2014/COCO_val2014_000000446358.jpg -../coco/images/val2014/COCO_val2014_000000446623.jpg -../coco/images/val2014/COCO_val2014_000000446990.jpg -../coco/images/val2014/COCO_val2014_000000447208.jpg -../coco/images/val2014/COCO_val2014_000000447242.jpg -../coco/images/val2014/COCO_val2014_000000447354.jpg -../coco/images/val2014/COCO_val2014_000000447378.jpg -../coco/images/val2014/COCO_val2014_000000447501.jpg -../coco/images/val2014/COCO_val2014_000000447779.jpg -../coco/images/val2014/COCO_val2014_000000448053.jpg -../coco/images/val2014/COCO_val2014_000000448114.jpg -../coco/images/val2014/COCO_val2014_000000448117.jpg -../coco/images/val2014/COCO_val2014_000000448236.jpg -../coco/images/val2014/COCO_val2014_000000448256.jpg -../coco/images/val2014/COCO_val2014_000000448278.jpg -../coco/images/val2014/COCO_val2014_000000448511.jpg -../coco/images/val2014/COCO_val2014_000000448690.jpg -../coco/images/val2014/COCO_val2014_000000448786.jpg -../coco/images/val2014/COCO_val2014_000000448923.jpg -../coco/images/val2014/COCO_val2014_000000448998.jpg -../coco/images/val2014/COCO_val2014_000000449031.jpg -../coco/images/val2014/COCO_val2014_000000449338.jpg -../coco/images/val2014/COCO_val2014_000000449392.jpg -../coco/images/val2014/COCO_val2014_000000449412.jpg -../coco/images/val2014/COCO_val2014_000000449432.jpg -../coco/images/val2014/COCO_val2014_000000449466.jpg -../coco/images/val2014/COCO_val2014_000000449485.jpg -../coco/images/val2014/COCO_val2014_000000449522.jpg -../coco/images/val2014/COCO_val2014_000000449872.jpg -../coco/images/val2014/COCO_val2014_000000449888.jpg -../coco/images/val2014/COCO_val2014_000000449903.jpg -../coco/images/val2014/COCO_val2014_000000449976.jpg -../coco/images/val2014/COCO_val2014_000000449981.jpg -../coco/images/val2014/COCO_val2014_000000450098.jpg -../coco/images/val2014/COCO_val2014_000000450355.jpg -../coco/images/val2014/COCO_val2014_000000450458.jpg -../coco/images/val2014/COCO_val2014_000000450559.jpg -../coco/images/val2014/COCO_val2014_000000450596.jpg -../coco/images/val2014/COCO_val2014_000000450655.jpg -../coco/images/val2014/COCO_val2014_000000450695.jpg -../coco/images/val2014/COCO_val2014_000000451014.jpg -../coco/images/val2014/COCO_val2014_000000451120.jpg -../coco/images/val2014/COCO_val2014_000000451305.jpg -../coco/images/val2014/COCO_val2014_000000451345.jpg -../coco/images/val2014/COCO_val2014_000000451440.jpg -../coco/images/val2014/COCO_val2014_000000451468.jpg -../coco/images/val2014/COCO_val2014_000000451679.jpg -../coco/images/val2014/COCO_val2014_000000451683.jpg -../coco/images/val2014/COCO_val2014_000000452195.jpg -../coco/images/val2014/COCO_val2014_000000452218.jpg -../coco/images/val2014/COCO_val2014_000000452308.jpg -../coco/images/val2014/COCO_val2014_000000452461.jpg -../coco/images/val2014/COCO_val2014_000000452516.jpg -../coco/images/val2014/COCO_val2014_000000452611.jpg -../coco/images/val2014/COCO_val2014_000000452618.jpg -../coco/images/val2014/COCO_val2014_000000452676.jpg -../coco/images/val2014/COCO_val2014_000000452759.jpg -../coco/images/val2014/COCO_val2014_000000452947.jpg -../coco/images/val2014/COCO_val2014_000000453040.jpg -../coco/images/val2014/COCO_val2014_000000453104.jpg -../coco/images/val2014/COCO_val2014_000000453162.jpg -../coco/images/val2014/COCO_val2014_000000453166.jpg -../coco/images/val2014/COCO_val2014_000000453755.jpg -../coco/images/val2014/COCO_val2014_000000453926.jpg -../coco/images/val2014/COCO_val2014_000000454161.jpg -../coco/images/val2014/COCO_val2014_000000454414.jpg -../coco/images/val2014/COCO_val2014_000000454561.jpg -../coco/images/val2014/COCO_val2014_000000454741.jpg -../coco/images/val2014/COCO_val2014_000000454750.jpg -../coco/images/val2014/COCO_val2014_000000455299.jpg -../coco/images/val2014/COCO_val2014_000000455325.jpg -../coco/images/val2014/COCO_val2014_000000455343.jpg -../coco/images/val2014/COCO_val2014_000000455355.jpg -../coco/images/val2014/COCO_val2014_000000455365.jpg -../coco/images/val2014/COCO_val2014_000000455384.jpg -../coco/images/val2014/COCO_val2014_000000455395.jpg -../coco/images/val2014/COCO_val2014_000000455414.jpg -../coco/images/val2014/COCO_val2014_000000455515.jpg -../coco/images/val2014/COCO_val2014_000000455557.jpg -../coco/images/val2014/COCO_val2014_000000455675.jpg -../coco/images/val2014/COCO_val2014_000000455750.jpg -../coco/images/val2014/COCO_val2014_000000455767.jpg -../coco/images/val2014/COCO_val2014_000000456015.jpg -../coco/images/val2014/COCO_val2014_000000456143.jpg -../coco/images/val2014/COCO_val2014_000000456420.jpg -../coco/images/val2014/COCO_val2014_000000456725.jpg -../coco/images/val2014/COCO_val2014_000000457217.jpg -../coco/images/val2014/COCO_val2014_000000457230.jpg -../coco/images/val2014/COCO_val2014_000000457262.jpg -../coco/images/val2014/COCO_val2014_000000457271.jpg -../coco/images/val2014/COCO_val2014_000000457436.jpg -../coco/images/val2014/COCO_val2014_000000457717.jpg -../coco/images/val2014/COCO_val2014_000000457901.jpg -../coco/images/val2014/COCO_val2014_000000458054.jpg -../coco/images/val2014/COCO_val2014_000000458103.jpg -../coco/images/val2014/COCO_val2014_000000458275.jpg -../coco/images/val2014/COCO_val2014_000000458846.jpg -../coco/images/val2014/COCO_val2014_000000458953.jpg -../coco/images/val2014/COCO_val2014_000000459164.jpg -../coco/images/val2014/COCO_val2014_000000459400.jpg -../coco/images/val2014/COCO_val2014_000000459590.jpg -../coco/images/val2014/COCO_val2014_000000459733.jpg -../coco/images/val2014/COCO_val2014_000000459757.jpg -../coco/images/val2014/COCO_val2014_000000459933.jpg -../coco/images/val2014/COCO_val2014_000000460022.jpg -../coco/images/val2014/COCO_val2014_000000460053.jpg -../coco/images/val2014/COCO_val2014_000000460129.jpg -../coco/images/val2014/COCO_val2014_000000460147.jpg -../coco/images/val2014/COCO_val2014_000000460149.jpg -../coco/images/val2014/COCO_val2014_000000460251.jpg -../coco/images/val2014/COCO_val2014_000000460461.jpg -../coco/images/val2014/COCO_val2014_000000460652.jpg -../coco/images/val2014/COCO_val2014_000000460676.jpg -../coco/images/val2014/COCO_val2014_000000460684.jpg -../coco/images/val2014/COCO_val2014_000000460757.jpg -../coco/images/val2014/COCO_val2014_000000460812.jpg -../coco/images/val2014/COCO_val2014_000000460967.jpg -../coco/images/val2014/COCO_val2014_000000461007.jpg -../coco/images/val2014/COCO_val2014_000000461123.jpg -../coco/images/val2014/COCO_val2014_000000461275.jpg -../coco/images/val2014/COCO_val2014_000000461278.jpg -../coco/images/val2014/COCO_val2014_000000461331.jpg -../coco/images/val2014/COCO_val2014_000000461681.jpg -../coco/images/val2014/COCO_val2014_000000461898.jpg -../coco/images/val2014/COCO_val2014_000000461953.jpg -../coco/images/val2014/COCO_val2014_000000461993.jpg -../coco/images/val2014/COCO_val2014_000000462213.jpg -../coco/images/val2014/COCO_val2014_000000462241.jpg -../coco/images/val2014/COCO_val2014_000000462315.jpg -../coco/images/val2014/COCO_val2014_000000462330.jpg -../coco/images/val2014/COCO_val2014_000000462466.jpg -../coco/images/val2014/COCO_val2014_000000462629.jpg -../coco/images/val2014/COCO_val2014_000000462677.jpg -../coco/images/val2014/COCO_val2014_000000462953.jpg -../coco/images/val2014/COCO_val2014_000000462978.jpg -../coco/images/val2014/COCO_val2014_000000462982.jpg -../coco/images/val2014/COCO_val2014_000000463037.jpg -../coco/images/val2014/COCO_val2014_000000463084.jpg -../coco/images/val2014/COCO_val2014_000000463283.jpg -../coco/images/val2014/COCO_val2014_000000463303.jpg -../coco/images/val2014/COCO_val2014_000000463398.jpg -../coco/images/val2014/COCO_val2014_000000463452.jpg -../coco/images/val2014/COCO_val2014_000000463555.jpg -../coco/images/val2014/COCO_val2014_000000463898.jpg -../coco/images/val2014/COCO_val2014_000000463913.jpg -../coco/images/val2014/COCO_val2014_000000464248.jpg -../coco/images/val2014/COCO_val2014_000000464390.jpg -../coco/images/val2014/COCO_val2014_000000465087.jpg -../coco/images/val2014/COCO_val2014_000000465588.jpg -../coco/images/val2014/COCO_val2014_000000465692.jpg -../coco/images/val2014/COCO_val2014_000000465715.jpg -../coco/images/val2014/COCO_val2014_000000465735.jpg -../coco/images/val2014/COCO_val2014_000000465822.jpg -../coco/images/val2014/COCO_val2014_000000465887.jpg -../coco/images/val2014/COCO_val2014_000000465986.jpg -../coco/images/val2014/COCO_val2014_000000466005.jpg -../coco/images/val2014/COCO_val2014_000000466347.jpg -../coco/images/val2014/COCO_val2014_000000466456.jpg -../coco/images/val2014/COCO_val2014_000000466570.jpg -../coco/images/val2014/COCO_val2014_000000466583.jpg -../coco/images/val2014/COCO_val2014_000000467022.jpg -../coco/images/val2014/COCO_val2014_000000467116.jpg -../coco/images/val2014/COCO_val2014_000000467138.jpg -../coco/images/val2014/COCO_val2014_000000467477.jpg -../coco/images/val2014/COCO_val2014_000000467540.jpg -../coco/images/val2014/COCO_val2014_000000467705.jpg -../coco/images/val2014/COCO_val2014_000000467726.jpg -../coco/images/val2014/COCO_val2014_000000467821.jpg -../coco/images/val2014/COCO_val2014_000000467951.jpg -../coco/images/val2014/COCO_val2014_000000467990.jpg -../coco/images/val2014/COCO_val2014_000000468012.jpg -../coco/images/val2014/COCO_val2014_000000468129.jpg -../coco/images/val2014/COCO_val2014_000000468178.jpg -../coco/images/val2014/COCO_val2014_000000468354.jpg -../coco/images/val2014/COCO_val2014_000000468736.jpg -../coco/images/val2014/COCO_val2014_000000468954.jpg -../coco/images/val2014/COCO_val2014_000000469085.jpg -../coco/images/val2014/COCO_val2014_000000469088.jpg -../coco/images/val2014/COCO_val2014_000000469096.jpg -../coco/images/val2014/COCO_val2014_000000469119.jpg -../coco/images/val2014/COCO_val2014_000000469356.jpg -../coco/images/val2014/COCO_val2014_000000469424.jpg -../coco/images/val2014/COCO_val2014_000000469634.jpg -../coco/images/val2014/COCO_val2014_000000469857.jpg -../coco/images/val2014/COCO_val2014_000000469961.jpg -../coco/images/val2014/COCO_val2014_000000469982.jpg -../coco/images/val2014/COCO_val2014_000000470070.jpg -../coco/images/val2014/COCO_val2014_000000470161.jpg -../coco/images/val2014/COCO_val2014_000000470173.jpg -../coco/images/val2014/COCO_val2014_000000470313.jpg -../coco/images/val2014/COCO_val2014_000000470370.jpg -../coco/images/val2014/COCO_val2014_000000470513.jpg -../coco/images/val2014/COCO_val2014_000000470746.jpg -../coco/images/val2014/COCO_val2014_000000471205.jpg -../coco/images/val2014/COCO_val2014_000000471394.jpg -../coco/images/val2014/COCO_val2014_000000471488.jpg -../coco/images/val2014/COCO_val2014_000000471858.jpg -../coco/images/val2014/COCO_val2014_000000471869.jpg -../coco/images/val2014/COCO_val2014_000000471893.jpg -../coco/images/val2014/COCO_val2014_000000472034.jpg -../coco/images/val2014/COCO_val2014_000000472078.jpg -../coco/images/val2014/COCO_val2014_000000472088.jpg -../coco/images/val2014/COCO_val2014_000000472160.jpg -../coco/images/val2014/COCO_val2014_000000472211.jpg -../coco/images/val2014/COCO_val2014_000000472643.jpg -../coco/images/val2014/COCO_val2014_000000472691.jpg -../coco/images/val2014/COCO_val2014_000000472762.jpg -../coco/images/val2014/COCO_val2014_000000472821.jpg -../coco/images/val2014/COCO_val2014_000000473015.jpg -../coco/images/val2014/COCO_val2014_000000473075.jpg -../coco/images/val2014/COCO_val2014_000000473109.jpg -../coco/images/val2014/COCO_val2014_000000473124.jpg -../coco/images/val2014/COCO_val2014_000000473171.jpg -../coco/images/val2014/COCO_val2014_000000473406.jpg -../coco/images/val2014/COCO_val2014_000000473415.jpg -../coco/images/val2014/COCO_val2014_000000473839.jpg -../coco/images/val2014/COCO_val2014_000000474003.jpg -../coco/images/val2014/COCO_val2014_000000474021.jpg -../coco/images/val2014/COCO_val2014_000000474028.jpg -../coco/images/val2014/COCO_val2014_000000474078.jpg -../coco/images/val2014/COCO_val2014_000000474110.jpg -../coco/images/val2014/COCO_val2014_000000474170.jpg -../coco/images/val2014/COCO_val2014_000000474246.jpg -../coco/images/val2014/COCO_val2014_000000474344.jpg -../coco/images/val2014/COCO_val2014_000000474384.jpg -../coco/images/val2014/COCO_val2014_000000474410.jpg -../coco/images/val2014/COCO_val2014_000000474600.jpg -../coco/images/val2014/COCO_val2014_000000474609.jpg -../coco/images/val2014/COCO_val2014_000000474906.jpg -../coco/images/val2014/COCO_val2014_000000475208.jpg -../coco/images/val2014/COCO_val2014_000000475229.jpg -../coco/images/val2014/COCO_val2014_000000475244.jpg -../coco/images/val2014/COCO_val2014_000000475398.jpg -../coco/images/val2014/COCO_val2014_000000475413.jpg -../coco/images/val2014/COCO_val2014_000000475572.jpg -../coco/images/val2014/COCO_val2014_000000475586.jpg -../coco/images/val2014/COCO_val2014_000000475879.jpg -../coco/images/val2014/COCO_val2014_000000475906.jpg -../coco/images/val2014/COCO_val2014_000000475944.jpg -../coco/images/val2014/COCO_val2014_000000476120.jpg -../coco/images/val2014/COCO_val2014_000000476172.jpg -../coco/images/val2014/COCO_val2014_000000476282.jpg -../coco/images/val2014/COCO_val2014_000000476300.jpg -../coco/images/val2014/COCO_val2014_000000476335.jpg -../coco/images/val2014/COCO_val2014_000000476339.jpg -../coco/images/val2014/COCO_val2014_000000476398.jpg -../coco/images/val2014/COCO_val2014_000000476455.jpg -../coco/images/val2014/COCO_val2014_000000476491.jpg -../coco/images/val2014/COCO_val2014_000000476647.jpg -../coco/images/val2014/COCO_val2014_000000476704.jpg -../coco/images/val2014/COCO_val2014_000000476856.jpg -../coco/images/val2014/COCO_val2014_000000476873.jpg -../coco/images/val2014/COCO_val2014_000000476925.jpg -../coco/images/val2014/COCO_val2014_000000477172.jpg -../coco/images/val2014/COCO_val2014_000000477305.jpg -../coco/images/val2014/COCO_val2014_000000477477.jpg -../coco/images/val2014/COCO_val2014_000000477623.jpg -../coco/images/val2014/COCO_val2014_000000477805.jpg -../coco/images/val2014/COCO_val2014_000000478120.jpg -../coco/images/val2014/COCO_val2014_000000478136.jpg -../coco/images/val2014/COCO_val2014_000000478184.jpg -../coco/images/val2014/COCO_val2014_000000478433.jpg -../coco/images/val2014/COCO_val2014_000000478490.jpg -../coco/images/val2014/COCO_val2014_000000478522.jpg -../coco/images/val2014/COCO_val2014_000000478621.jpg -../coco/images/val2014/COCO_val2014_000000478664.jpg -../coco/images/val2014/COCO_val2014_000000478874.jpg -../coco/images/val2014/COCO_val2014_000000479008.jpg -../coco/images/val2014/COCO_val2014_000000479078.jpg -../coco/images/val2014/COCO_val2014_000000479099.jpg -../coco/images/val2014/COCO_val2014_000000479334.jpg -../coco/images/val2014/COCO_val2014_000000479557.jpg -../coco/images/val2014/COCO_val2014_000000479597.jpg -../coco/images/val2014/COCO_val2014_000000479912.jpg -../coco/images/val2014/COCO_val2014_000000479938.jpg -../coco/images/val2014/COCO_val2014_000000479948.jpg -../coco/images/val2014/COCO_val2014_000000480075.jpg -../coco/images/val2014/COCO_val2014_000000480215.jpg -../coco/images/val2014/COCO_val2014_000000480345.jpg -../coco/images/val2014/COCO_val2014_000000480379.jpg -../coco/images/val2014/COCO_val2014_000000480472.jpg -../coco/images/val2014/COCO_val2014_000000480726.jpg -../coco/images/val2014/COCO_val2014_000000481327.jpg -../coco/images/val2014/COCO_val2014_000000481398.jpg -../coco/images/val2014/COCO_val2014_000000481404.jpg -../coco/images/val2014/COCO_val2014_000000481446.jpg -../coco/images/val2014/COCO_val2014_000000481890.jpg -../coco/images/val2014/COCO_val2014_000000482007.jpg -../coco/images/val2014/COCO_val2014_000000482021.jpg -../coco/images/val2014/COCO_val2014_000000482476.jpg -../coco/images/val2014/COCO_val2014_000000482477.jpg -../coco/images/val2014/COCO_val2014_000000482487.jpg -../coco/images/val2014/COCO_val2014_000000482605.jpg -../coco/images/val2014/COCO_val2014_000000482667.jpg -../coco/images/val2014/COCO_val2014_000000482707.jpg -../coco/images/val2014/COCO_val2014_000000482735.jpg -../coco/images/val2014/COCO_val2014_000000482774.jpg -../coco/images/val2014/COCO_val2014_000000482799.jpg -../coco/images/val2014/COCO_val2014_000000482951.jpg -../coco/images/val2014/COCO_val2014_000000483179.jpg -../coco/images/val2014/COCO_val2014_000000483389.jpg -../coco/images/val2014/COCO_val2014_000000483531.jpg -../coco/images/val2014/COCO_val2014_000000483564.jpg -../coco/images/val2014/COCO_val2014_000000483587.jpg -../coco/images/val2014/COCO_val2014_000000483849.jpg -../coco/images/val2014/COCO_val2014_000000483994.jpg -../coco/images/val2014/COCO_val2014_000000484066.jpg -../coco/images/val2014/COCO_val2014_000000484215.jpg -../coco/images/val2014/COCO_val2014_000000484225.jpg -../coco/images/val2014/COCO_val2014_000000484321.jpg -../coco/images/val2014/COCO_val2014_000000484397.jpg -../coco/images/val2014/COCO_val2014_000000484531.jpg -../coco/images/val2014/COCO_val2014_000000484674.jpg -../coco/images/val2014/COCO_val2014_000000484978.jpg -../coco/images/val2014/COCO_val2014_000000485139.jpg -../coco/images/val2014/COCO_val2014_000000485483.jpg -../coco/images/val2014/COCO_val2014_000000485485.jpg -../coco/images/val2014/COCO_val2014_000000485673.jpg -../coco/images/val2014/COCO_val2014_000000485740.jpg -../coco/images/val2014/COCO_val2014_000000486112.jpg -../coco/images/val2014/COCO_val2014_000000486175.jpg -../coco/images/val2014/COCO_val2014_000000486232.jpg -../coco/images/val2014/COCO_val2014_000000486568.jpg -../coco/images/val2014/COCO_val2014_000000486576.jpg -../coco/images/val2014/COCO_val2014_000000486580.jpg -../coco/images/val2014/COCO_val2014_000000486632.jpg -../coco/images/val2014/COCO_val2014_000000486788.jpg -../coco/images/val2014/COCO_val2014_000000486803.jpg -../coco/images/val2014/COCO_val2014_000000486991.jpg -../coco/images/val2014/COCO_val2014_000000487222.jpg -../coco/images/val2014/COCO_val2014_000000487282.jpg -../coco/images/val2014/COCO_val2014_000000487391.jpg -../coco/images/val2014/COCO_val2014_000000487630.jpg -../coco/images/val2014/COCO_val2014_000000487659.jpg -../coco/images/val2014/COCO_val2014_000000487698.jpg -../coco/images/val2014/COCO_val2014_000000487702.jpg -../coco/images/val2014/COCO_val2014_000000487720.jpg -../coco/images/val2014/COCO_val2014_000000488075.jpg -../coco/images/val2014/COCO_val2014_000000488250.jpg -../coco/images/val2014/COCO_val2014_000000488360.jpg -../coco/images/val2014/COCO_val2014_000000488385.jpg -../coco/images/val2014/COCO_val2014_000000488386.jpg -../coco/images/val2014/COCO_val2014_000000488522.jpg -../coco/images/val2014/COCO_val2014_000000488664.jpg -../coco/images/val2014/COCO_val2014_000000488723.jpg -../coco/images/val2014/COCO_val2014_000000488736.jpg -../coco/images/val2014/COCO_val2014_000000488979.jpg -../coco/images/val2014/COCO_val2014_000000489019.jpg -../coco/images/val2014/COCO_val2014_000000489235.jpg -../coco/images/val2014/COCO_val2014_000000489266.jpg -../coco/images/val2014/COCO_val2014_000000489304.jpg -../coco/images/val2014/COCO_val2014_000000489344.jpg -../coco/images/val2014/COCO_val2014_000000489475.jpg -../coco/images/val2014/COCO_val2014_000000489764.jpg -../coco/images/val2014/COCO_val2014_000000489940.jpg -../coco/images/val2014/COCO_val2014_000000490022.jpg -../coco/images/val2014/COCO_val2014_000000490051.jpg -../coco/images/val2014/COCO_val2014_000000490105.jpg -../coco/images/val2014/COCO_val2014_000000490171.jpg -../coco/images/val2014/COCO_val2014_000000490286.jpg -../coco/images/val2014/COCO_val2014_000000490306.jpg -../coco/images/val2014/COCO_val2014_000000490338.jpg -../coco/images/val2014/COCO_val2014_000000490491.jpg -../coco/images/val2014/COCO_val2014_000000490505.jpg -../coco/images/val2014/COCO_val2014_000000490702.jpg -../coco/images/val2014/COCO_val2014_000000490860.jpg -../coco/images/val2014/COCO_val2014_000000490952.jpg -../coco/images/val2014/COCO_val2014_000000491169.jpg -../coco/images/val2014/COCO_val2014_000000491336.jpg -../coco/images/val2014/COCO_val2014_000000491377.jpg -../coco/images/val2014/COCO_val2014_000000491408.jpg -../coco/images/val2014/COCO_val2014_000000491449.jpg -../coco/images/val2014/COCO_val2014_000000491481.jpg -../coco/images/val2014/COCO_val2014_000000491835.jpg -../coco/images/val2014/COCO_val2014_000000491836.jpg -../coco/images/val2014/COCO_val2014_000000491965.jpg -../coco/images/val2014/COCO_val2014_000000491985.jpg -../coco/images/val2014/COCO_val2014_000000492246.jpg -../coco/images/val2014/COCO_val2014_000000492323.jpg -../coco/images/val2014/COCO_val2014_000000492363.jpg -../coco/images/val2014/COCO_val2014_000000492407.jpg -../coco/images/val2014/COCO_val2014_000000492524.jpg -../coco/images/val2014/COCO_val2014_000000492605.jpg -../coco/images/val2014/COCO_val2014_000000492785.jpg -../coco/images/val2014/COCO_val2014_000000492805.jpg -../coco/images/val2014/COCO_val2014_000000493132.jpg -../coco/images/val2014/COCO_val2014_000000493196.jpg -../coco/images/val2014/COCO_val2014_000000493206.jpg -../coco/images/val2014/COCO_val2014_000000493273.jpg -../coco/images/val2014/COCO_val2014_000000493279.jpg -../coco/images/val2014/COCO_val2014_000000493509.jpg -../coco/images/val2014/COCO_val2014_000000493772.jpg -../coco/images/val2014/COCO_val2014_000000493799.jpg -../coco/images/val2014/COCO_val2014_000000493814.jpg -../coco/images/val2014/COCO_val2014_000000494085.jpg -../coco/images/val2014/COCO_val2014_000000494144.jpg -../coco/images/val2014/COCO_val2014_000000494320.jpg -../coco/images/val2014/COCO_val2014_000000494438.jpg -../coco/images/val2014/COCO_val2014_000000494578.jpg -../coco/images/val2014/COCO_val2014_000000494620.jpg -../coco/images/val2014/COCO_val2014_000000494731.jpg -../coco/images/val2014/COCO_val2014_000000494869.jpg -../coco/images/val2014/COCO_val2014_000000495090.jpg -../coco/images/val2014/COCO_val2014_000000495125.jpg -../coco/images/val2014/COCO_val2014_000000495491.jpg -../coco/images/val2014/COCO_val2014_000000495519.jpg -../coco/images/val2014/COCO_val2014_000000495734.jpg -../coco/images/val2014/COCO_val2014_000000495852.jpg -../coco/images/val2014/COCO_val2014_000000496152.jpg -../coco/images/val2014/COCO_val2014_000000496267.jpg -../coco/images/val2014/COCO_val2014_000000496324.jpg -../coco/images/val2014/COCO_val2014_000000496360.jpg -../coco/images/val2014/COCO_val2014_000000496379.jpg -../coco/images/val2014/COCO_val2014_000000496409.jpg -../coco/images/val2014/COCO_val2014_000000496450.jpg -../coco/images/val2014/COCO_val2014_000000496554.jpg -../coco/images/val2014/COCO_val2014_000000496687.jpg -../coco/images/val2014/COCO_val2014_000000497099.jpg -../coco/images/val2014/COCO_val2014_000000497312.jpg -../coco/images/val2014/COCO_val2014_000000497348.jpg -../coco/images/val2014/COCO_val2014_000000497351.jpg -../coco/images/val2014/COCO_val2014_000000497443.jpg -../coco/images/val2014/COCO_val2014_000000497488.jpg -../coco/images/val2014/COCO_val2014_000000497907.jpg -../coco/images/val2014/COCO_val2014_000000497928.jpg -../coco/images/val2014/COCO_val2014_000000498274.jpg -../coco/images/val2014/COCO_val2014_000000498346.jpg -../coco/images/val2014/COCO_val2014_000000498392.jpg -../coco/images/val2014/COCO_val2014_000000498650.jpg -../coco/images/val2014/COCO_val2014_000000498709.jpg -../coco/images/val2014/COCO_val2014_000000498765.jpg -../coco/images/val2014/COCO_val2014_000000498802.jpg -../coco/images/val2014/COCO_val2014_000000498807.jpg -../coco/images/val2014/COCO_val2014_000000499093.jpg -../coco/images/val2014/COCO_val2014_000000499105.jpg -../coco/images/val2014/COCO_val2014_000000499255.jpg -../coco/images/val2014/COCO_val2014_000000499313.jpg -../coco/images/val2014/COCO_val2014_000000499391.jpg -../coco/images/val2014/COCO_val2014_000000499393.jpg -../coco/images/val2014/COCO_val2014_000000499537.jpg -../coco/images/val2014/COCO_val2014_000000499755.jpg -../coco/images/val2014/COCO_val2014_000000499802.jpg -../coco/images/val2014/COCO_val2014_000000499810.jpg -../coco/images/val2014/COCO_val2014_000000500062.jpg -../coco/images/val2014/COCO_val2014_000000500139.jpg -../coco/images/val2014/COCO_val2014_000000500175.jpg -../coco/images/val2014/COCO_val2014_000000500464.jpg -../coco/images/val2014/COCO_val2014_000000500514.jpg -../coco/images/val2014/COCO_val2014_000000500723.jpg -../coco/images/val2014/COCO_val2014_000000500829.jpg -../coco/images/val2014/COCO_val2014_000000500878.jpg -../coco/images/val2014/COCO_val2014_000000500965.jpg -../coco/images/val2014/COCO_val2014_000000501116.jpg -../coco/images/val2014/COCO_val2014_000000501122.jpg -../coco/images/val2014/COCO_val2014_000000501229.jpg -../coco/images/val2014/COCO_val2014_000000501242.jpg -../coco/images/val2014/COCO_val2014_000000501527.jpg -../coco/images/val2014/COCO_val2014_000000501790.jpg -../coco/images/val2014/COCO_val2014_000000501824.jpg -../coco/images/val2014/COCO_val2014_000000501835.jpg -../coco/images/val2014/COCO_val2014_000000502168.jpg -../coco/images/val2014/COCO_val2014_000000502336.jpg -../coco/images/val2014/COCO_val2014_000000502854.jpg -../coco/images/val2014/COCO_val2014_000000502895.jpg -../coco/images/val2014/COCO_val2014_000000502910.jpg -../coco/images/val2014/COCO_val2014_000000503097.jpg -../coco/images/val2014/COCO_val2014_000000503202.jpg -../coco/images/val2014/COCO_val2014_000000503207.jpg -../coco/images/val2014/COCO_val2014_000000503233.jpg -../coco/images/val2014/COCO_val2014_000000503467.jpg -../coco/images/val2014/COCO_val2014_000000503522.jpg -../coco/images/val2014/COCO_val2014_000000503772.jpg -../coco/images/val2014/COCO_val2014_000000503823.jpg -../coco/images/val2014/COCO_val2014_000000503826.jpg -../coco/images/val2014/COCO_val2014_000000503951.jpg -../coco/images/val2014/COCO_val2014_000000503972.jpg -../coco/images/val2014/COCO_val2014_000000503983.jpg -../coco/images/val2014/COCO_val2014_000000504074.jpg -../coco/images/val2014/COCO_val2014_000000504152.jpg -../coco/images/val2014/COCO_val2014_000000504341.jpg -../coco/images/val2014/COCO_val2014_000000504353.jpg -../coco/images/val2014/COCO_val2014_000000504452.jpg -../coco/images/val2014/COCO_val2014_000000504559.jpg -../coco/images/val2014/COCO_val2014_000000504711.jpg -../coco/images/val2014/COCO_val2014_000000504733.jpg -../coco/images/val2014/COCO_val2014_000000504790.jpg -../coco/images/val2014/COCO_val2014_000000505014.jpg -../coco/images/val2014/COCO_val2014_000000505040.jpg -../coco/images/val2014/COCO_val2014_000000505043.jpg -../coco/images/val2014/COCO_val2014_000000505132.jpg -../coco/images/val2014/COCO_val2014_000000505344.jpg -../coco/images/val2014/COCO_val2014_000000505516.jpg -../coco/images/val2014/COCO_val2014_000000505528.jpg -../coco/images/val2014/COCO_val2014_000000505650.jpg -../coco/images/val2014/COCO_val2014_000000505733.jpg -../coco/images/val2014/COCO_val2014_000000505739.jpg -../coco/images/val2014/COCO_val2014_000000505754.jpg -../coco/images/val2014/COCO_val2014_000000505792.jpg -../coco/images/val2014/COCO_val2014_000000505814.jpg -../coco/images/val2014/COCO_val2014_000000505862.jpg -../coco/images/val2014/COCO_val2014_000000505945.jpg -../coco/images/val2014/COCO_val2014_000000505967.jpg -../coco/images/val2014/COCO_val2014_000000506335.jpg -../coco/images/val2014/COCO_val2014_000000506357.jpg -../coco/images/val2014/COCO_val2014_000000506449.jpg -../coco/images/val2014/COCO_val2014_000000506515.jpg -../coco/images/val2014/COCO_val2014_000000506569.jpg -../coco/images/val2014/COCO_val2014_000000506587.jpg -../coco/images/val2014/COCO_val2014_000000506707.jpg -../coco/images/val2014/COCO_val2014_000000506736.jpg -../coco/images/val2014/COCO_val2014_000000507037.jpg -../coco/images/val2014/COCO_val2014_000000507180.jpg -../coco/images/val2014/COCO_val2014_000000507668.jpg -../coco/images/val2014/COCO_val2014_000000507684.jpg -../coco/images/val2014/COCO_val2014_000000507783.jpg -../coco/images/val2014/COCO_val2014_000000507927.jpg -../coco/images/val2014/COCO_val2014_000000507935.jpg -../coco/images/val2014/COCO_val2014_000000508119.jpg -../coco/images/val2014/COCO_val2014_000000508230.jpg -../coco/images/val2014/COCO_val2014_000000508443.jpg -../coco/images/val2014/COCO_val2014_000000508586.jpg -../coco/images/val2014/COCO_val2014_000000508811.jpg -../coco/images/val2014/COCO_val2014_000000508822.jpg -../coco/images/val2014/COCO_val2014_000000508985.jpg -../coco/images/val2014/COCO_val2014_000000509185.jpg -../coco/images/val2014/COCO_val2014_000000509258.jpg -../coco/images/val2014/COCO_val2014_000000509379.jpg -../coco/images/val2014/COCO_val2014_000000509388.jpg -../coco/images/val2014/COCO_val2014_000000509423.jpg -../coco/images/val2014/COCO_val2014_000000509526.jpg -../coco/images/val2014/COCO_val2014_000000509577.jpg -../coco/images/val2014/COCO_val2014_000000509695.jpg -../coco/images/val2014/COCO_val2014_000000509855.jpg -../coco/images/val2014/COCO_val2014_000000510343.jpg -../coco/images/val2014/COCO_val2014_000000510593.jpg -../coco/images/val2014/COCO_val2014_000000510707.jpg -../coco/images/val2014/COCO_val2014_000000510791.jpg -../coco/images/val2014/COCO_val2014_000000510798.jpg -../coco/images/val2014/COCO_val2014_000000510864.jpg -../coco/images/val2014/COCO_val2014_000000510942.jpg -../coco/images/val2014/COCO_val2014_000000511076.jpg -../coco/images/val2014/COCO_val2014_000000511236.jpg -../coco/images/val2014/COCO_val2014_000000511403.jpg -../coco/images/val2014/COCO_val2014_000000512070.jpg -../coco/images/val2014/COCO_val2014_000000512112.jpg -../coco/images/val2014/COCO_val2014_000000512145.jpg -../coco/images/val2014/COCO_val2014_000000512248.jpg -../coco/images/val2014/COCO_val2014_000000512254.jpg -../coco/images/val2014/COCO_val2014_000000512307.jpg -../coco/images/val2014/COCO_val2014_000000512337.jpg -../coco/images/val2014/COCO_val2014_000000512463.jpg -../coco/images/val2014/COCO_val2014_000000512479.jpg -../coco/images/val2014/COCO_val2014_000000512630.jpg -../coco/images/val2014/COCO_val2014_000000512722.jpg -../coco/images/val2014/COCO_val2014_000000512776.jpg -../coco/images/val2014/COCO_val2014_000000512911.jpg -../coco/images/val2014/COCO_val2014_000000512912.jpg -../coco/images/val2014/COCO_val2014_000000513073.jpg -../coco/images/val2014/COCO_val2014_000000513129.jpg -../coco/images/val2014/COCO_val2014_000000513342.jpg -../coco/images/val2014/COCO_val2014_000000513497.jpg -../coco/images/val2014/COCO_val2014_000000513507.jpg -../coco/images/val2014/COCO_val2014_000000513585.jpg -../coco/images/val2014/COCO_val2014_000000513681.jpg -../coco/images/val2014/COCO_val2014_000000514180.jpg -../coco/images/val2014/COCO_val2014_000000514241.jpg -../coco/images/val2014/COCO_val2014_000000514525.jpg -../coco/images/val2014/COCO_val2014_000000514540.jpg -../coco/images/val2014/COCO_val2014_000000514586.jpg -../coco/images/val2014/COCO_val2014_000000514682.jpg -../coco/images/val2014/COCO_val2014_000000514913.jpg -../coco/images/val2014/COCO_val2014_000000514990.jpg -../coco/images/val2014/COCO_val2014_000000515077.jpg -../coco/images/val2014/COCO_val2014_000000515176.jpg -../coco/images/val2014/COCO_val2014_000000515226.jpg -../coco/images/val2014/COCO_val2014_000000515289.jpg -../coco/images/val2014/COCO_val2014_000000515350.jpg -../coco/images/val2014/COCO_val2014_000000515485.jpg -../coco/images/val2014/COCO_val2014_000000515531.jpg -../coco/images/val2014/COCO_val2014_000000515727.jpg -../coco/images/val2014/COCO_val2014_000000515760.jpg -../coco/images/val2014/COCO_val2014_000000515777.jpg -../coco/images/val2014/COCO_val2014_000000515779.jpg -../coco/images/val2014/COCO_val2014_000000515904.jpg -../coco/images/val2014/COCO_val2014_000000515993.jpg -../coco/images/val2014/COCO_val2014_000000516026.jpg -../coco/images/val2014/COCO_val2014_000000516316.jpg -../coco/images/val2014/COCO_val2014_000000516318.jpg -../coco/images/val2014/COCO_val2014_000000516476.jpg -../coco/images/val2014/COCO_val2014_000000516775.jpg -../coco/images/val2014/COCO_val2014_000000516804.jpg -../coco/images/val2014/COCO_val2014_000000516805.jpg -../coco/images/val2014/COCO_val2014_000000516867.jpg -../coco/images/val2014/COCO_val2014_000000516893.jpg -../coco/images/val2014/COCO_val2014_000000516913.jpg -../coco/images/val2014/COCO_val2014_000000516916.jpg -../coco/images/val2014/COCO_val2014_000000517318.jpg -../coco/images/val2014/COCO_val2014_000000517443.jpg -../coco/images/val2014/COCO_val2014_000000517596.jpg -../coco/images/val2014/COCO_val2014_000000517619.jpg -../coco/images/val2014/COCO_val2014_000000517737.jpg -../coco/images/val2014/COCO_val2014_000000517821.jpg -../coco/images/val2014/COCO_val2014_000000517987.jpg -../coco/images/val2014/COCO_val2014_000000518039.jpg -../coco/images/val2014/COCO_val2014_000000518109.jpg -../coco/images/val2014/COCO_val2014_000000518213.jpg -../coco/images/val2014/COCO_val2014_000000518234.jpg -../coco/images/val2014/COCO_val2014_000000518324.jpg -../coco/images/val2014/COCO_val2014_000000518365.jpg -../coco/images/val2014/COCO_val2014_000000518584.jpg -../coco/images/val2014/COCO_val2014_000000518716.jpg -../coco/images/val2014/COCO_val2014_000000518729.jpg -../coco/images/val2014/COCO_val2014_000000518818.jpg -../coco/images/val2014/COCO_val2014_000000518850.jpg -../coco/images/val2014/COCO_val2014_000000518914.jpg -../coco/images/val2014/COCO_val2014_000000518968.jpg -../coco/images/val2014/COCO_val2014_000000519055.jpg -../coco/images/val2014/COCO_val2014_000000519271.jpg -../coco/images/val2014/COCO_val2014_000000519316.jpg -../coco/images/val2014/COCO_val2014_000000519387.jpg -../coco/images/val2014/COCO_val2014_000000519542.jpg -../coco/images/val2014/COCO_val2014_000000519565.jpg -../coco/images/val2014/COCO_val2014_000000519611.jpg -../coco/images/val2014/COCO_val2014_000000519649.jpg -../coco/images/val2014/COCO_val2014_000000519874.jpg -../coco/images/val2014/COCO_val2014_000000520009.jpg -../coco/images/val2014/COCO_val2014_000000520109.jpg -../coco/images/val2014/COCO_val2014_000000520147.jpg -../coco/images/val2014/COCO_val2014_000000520338.jpg -../coco/images/val2014/COCO_val2014_000000520524.jpg -../coco/images/val2014/COCO_val2014_000000521142.jpg -../coco/images/val2014/COCO_val2014_000000521259.jpg -../coco/images/val2014/COCO_val2014_000000521359.jpg -../coco/images/val2014/COCO_val2014_000000521540.jpg -../coco/images/val2014/COCO_val2014_000000521613.jpg -../coco/images/val2014/COCO_val2014_000000521634.jpg -../coco/images/val2014/COCO_val2014_000000521669.jpg -../coco/images/val2014/COCO_val2014_000000521689.jpg -../coco/images/val2014/COCO_val2014_000000521943.jpg -../coco/images/val2014/COCO_val2014_000000522163.jpg -../coco/images/val2014/COCO_val2014_000000522613.jpg -../coco/images/val2014/COCO_val2014_000000522622.jpg -../coco/images/val2014/COCO_val2014_000000522702.jpg -../coco/images/val2014/COCO_val2014_000000522791.jpg -../coco/images/val2014/COCO_val2014_000000522940.jpg -../coco/images/val2014/COCO_val2014_000000523100.jpg -../coco/images/val2014/COCO_val2014_000000523137.jpg -../coco/images/val2014/COCO_val2014_000000523230.jpg -../coco/images/val2014/COCO_val2014_000000523517.jpg -../coco/images/val2014/COCO_val2014_000000524002.jpg -../coco/images/val2014/COCO_val2014_000000524064.jpg -../coco/images/val2014/COCO_val2014_000000524173.jpg -../coco/images/val2014/COCO_val2014_000000524263.jpg -../coco/images/val2014/COCO_val2014_000000524333.jpg -../coco/images/val2014/COCO_val2014_000000524533.jpg -../coco/images/val2014/COCO_val2014_000000524536.jpg -../coco/images/val2014/COCO_val2014_000000524656.jpg -../coco/images/val2014/COCO_val2014_000000524742.jpg -../coco/images/val2014/COCO_val2014_000000524799.jpg -../coco/images/val2014/COCO_val2014_000000524992.jpg -../coco/images/val2014/COCO_val2014_000000525021.jpg -../coco/images/val2014/COCO_val2014_000000525087.jpg -../coco/images/val2014/COCO_val2014_000000525118.jpg -../coco/images/val2014/COCO_val2014_000000525170.jpg -../coco/images/val2014/COCO_val2014_000000525373.jpg -../coco/images/val2014/COCO_val2014_000000525667.jpg -../coco/images/val2014/COCO_val2014_000000525849.jpg -../coco/images/val2014/COCO_val2014_000000525927.jpg -../coco/images/val2014/COCO_val2014_000000525971.jpg -../coco/images/val2014/COCO_val2014_000000526040.jpg -../coco/images/val2014/COCO_val2014_000000526089.jpg -../coco/images/val2014/COCO_val2014_000000526341.jpg -../coco/images/val2014/COCO_val2014_000000526342.jpg -../coco/images/val2014/COCO_val2014_000000526371.jpg -../coco/images/val2014/COCO_val2014_000000526418.jpg -../coco/images/val2014/COCO_val2014_000000526560.jpg -../coco/images/val2014/COCO_val2014_000000527407.jpg -../coco/images/val2014/COCO_val2014_000000527447.jpg -../coco/images/val2014/COCO_val2014_000000527535.jpg -../coco/images/val2014/COCO_val2014_000000527558.jpg -../coco/images/val2014/COCO_val2014_000000527573.jpg -../coco/images/val2014/COCO_val2014_000000527644.jpg -../coco/images/val2014/COCO_val2014_000000527704.jpg -../coco/images/val2014/COCO_val2014_000000527750.jpg -../coco/images/val2014/COCO_val2014_000000527961.jpg -../coco/images/val2014/COCO_val2014_000000528314.jpg -../coco/images/val2014/COCO_val2014_000000528386.jpg -../coco/images/val2014/COCO_val2014_000000528411.jpg -../coco/images/val2014/COCO_val2014_000000528643.jpg -../coco/images/val2014/COCO_val2014_000000528738.jpg -../coco/images/val2014/COCO_val2014_000000528980.jpg -../coco/images/val2014/COCO_val2014_000000529004.jpg -../coco/images/val2014/COCO_val2014_000000529065.jpg -../coco/images/val2014/COCO_val2014_000000529215.jpg -../coco/images/val2014/COCO_val2014_000000529235.jpg -../coco/images/val2014/COCO_val2014_000000529270.jpg -../coco/images/val2014/COCO_val2014_000000529455.jpg -../coco/images/val2014/COCO_val2014_000000529494.jpg -../coco/images/val2014/COCO_val2014_000000529597.jpg -../coco/images/val2014/COCO_val2014_000000529668.jpg -../coco/images/val2014/COCO_val2014_000000529907.jpg -../coco/images/val2014/COCO_val2014_000000529944.jpg -../coco/images/val2014/COCO_val2014_000000530013.jpg -../coco/images/val2014/COCO_val2014_000000530052.jpg -../coco/images/val2014/COCO_val2014_000000530220.jpg -../coco/images/val2014/COCO_val2014_000000530461.jpg -../coco/images/val2014/COCO_val2014_000000530620.jpg -../coco/images/val2014/COCO_val2014_000000530624.jpg -../coco/images/val2014/COCO_val2014_000000530630.jpg -../coco/images/val2014/COCO_val2014_000000530854.jpg -../coco/images/val2014/COCO_val2014_000000531000.jpg -../coco/images/val2014/COCO_val2014_000000531111.jpg -../coco/images/val2014/COCO_val2014_000000531189.jpg -../coco/images/val2014/COCO_val2014_000000531563.jpg -../coco/images/val2014/COCO_val2014_000000531569.jpg -../coco/images/val2014/COCO_val2014_000000532009.jpg -../coco/images/val2014/COCO_val2014_000000532085.jpg -../coco/images/val2014/COCO_val2014_000000532126.jpg -../coco/images/val2014/COCO_val2014_000000532129.jpg -../coco/images/val2014/COCO_val2014_000000532159.jpg -../coco/images/val2014/COCO_val2014_000000532212.jpg -../coco/images/val2014/COCO_val2014_000000532690.jpg -../coco/images/val2014/COCO_val2014_000000532695.jpg -../coco/images/val2014/COCO_val2014_000000532773.jpg -../coco/images/val2014/COCO_val2014_000000532827.jpg -../coco/images/val2014/COCO_val2014_000000532867.jpg -../coco/images/val2014/COCO_val2014_000000533097.jpg -../coco/images/val2014/COCO_val2014_000000533261.jpg -../coco/images/val2014/COCO_val2014_000000533434.jpg -../coco/images/val2014/COCO_val2014_000000533511.jpg -../coco/images/val2014/COCO_val2014_000000533517.jpg -../coco/images/val2014/COCO_val2014_000000533532.jpg -../coco/images/val2014/COCO_val2014_000000533688.jpg -../coco/images/val2014/COCO_val2014_000000533816.jpg -../coco/images/val2014/COCO_val2014_000000534018.jpg -../coco/images/val2014/COCO_val2014_000000534349.jpg -../coco/images/val2014/COCO_val2014_000000534377.jpg -../coco/images/val2014/COCO_val2014_000000534601.jpg -../coco/images/val2014/COCO_val2014_000000534639.jpg -../coco/images/val2014/COCO_val2014_000000534679.jpg -../coco/images/val2014/COCO_val2014_000000534988.jpg -../coco/images/val2014/COCO_val2014_000000535156.jpg -../coco/images/val2014/COCO_val2014_000000535198.jpg -../coco/images/val2014/COCO_val2014_000000535226.jpg -../coco/images/val2014/COCO_val2014_000000535242.jpg -../coco/images/val2014/COCO_val2014_000000535591.jpg -../coco/images/val2014/COCO_val2014_000000535858.jpg -../coco/images/val2014/COCO_val2014_000000535889.jpg -../coco/images/val2014/COCO_val2014_000000535952.jpg -../coco/images/val2014/COCO_val2014_000000535997.jpg -../coco/images/val2014/COCO_val2014_000000536028.jpg -../coco/images/val2014/COCO_val2014_000000536154.jpg -../coco/images/val2014/COCO_val2014_000000536486.jpg -../coco/images/val2014/COCO_val2014_000000536517.jpg -../coco/images/val2014/COCO_val2014_000000536795.jpg -../coco/images/val2014/COCO_val2014_000000536879.jpg -../coco/images/val2014/COCO_val2014_000000537025.jpg -../coco/images/val2014/COCO_val2014_000000537280.jpg -../coco/images/val2014/COCO_val2014_000000537369.jpg -../coco/images/val2014/COCO_val2014_000000537604.jpg -../coco/images/val2014/COCO_val2014_000000537620.jpg -../coco/images/val2014/COCO_val2014_000000537636.jpg -../coco/images/val2014/COCO_val2014_000000537802.jpg -../coco/images/val2014/COCO_val2014_000000537954.jpg -../coco/images/val2014/COCO_val2014_000000538005.jpg -../coco/images/val2014/COCO_val2014_000000538153.jpg -../coco/images/val2014/COCO_val2014_000000538259.jpg -../coco/images/val2014/COCO_val2014_000000538451.jpg -../coco/images/val2014/COCO_val2014_000000538463.jpg -../coco/images/val2014/COCO_val2014_000000538589.jpg -../coco/images/val2014/COCO_val2014_000000538595.jpg -../coco/images/val2014/COCO_val2014_000000538596.jpg -../coco/images/val2014/COCO_val2014_000000538741.jpg -../coco/images/val2014/COCO_val2014_000000538775.jpg -../coco/images/val2014/COCO_val2014_000000538976.jpg -../coco/images/val2014/COCO_val2014_000000539224.jpg -../coco/images/val2014/COCO_val2014_000000539251.jpg -../coco/images/val2014/COCO_val2014_000000539453.jpg -../coco/images/val2014/COCO_val2014_000000539551.jpg -../coco/images/val2014/COCO_val2014_000000539678.jpg -../coco/images/val2014/COCO_val2014_000000539975.jpg -../coco/images/val2014/COCO_val2014_000000540098.jpg -../coco/images/val2014/COCO_val2014_000000540107.jpg -../coco/images/val2014/COCO_val2014_000000540172.jpg -../coco/images/val2014/COCO_val2014_000000540186.jpg -../coco/images/val2014/COCO_val2014_000000540209.jpg -../coco/images/val2014/COCO_val2014_000000540264.jpg -../coco/images/val2014/COCO_val2014_000000540372.jpg -../coco/images/val2014/COCO_val2014_000000540414.jpg -../coco/images/val2014/COCO_val2014_000000540483.jpg -../coco/images/val2014/COCO_val2014_000000540502.jpg -../coco/images/val2014/COCO_val2014_000000540816.jpg -../coco/images/val2014/COCO_val2014_000000540860.jpg -../coco/images/val2014/COCO_val2014_000000540912.jpg -../coco/images/val2014/COCO_val2014_000000541071.jpg -../coco/images/val2014/COCO_val2014_000000541197.jpg -../coco/images/val2014/COCO_val2014_000000541279.jpg -../coco/images/val2014/COCO_val2014_000000541474.jpg -../coco/images/val2014/COCO_val2014_000000541550.jpg -../coco/images/val2014/COCO_val2014_000000541773.jpg -../coco/images/val2014/COCO_val2014_000000541879.jpg -../coco/images/val2014/COCO_val2014_000000541991.jpg -../coco/images/val2014/COCO_val2014_000000542101.jpg -../coco/images/val2014/COCO_val2014_000000542234.jpg -../coco/images/val2014/COCO_val2014_000000542509.jpg -../coco/images/val2014/COCO_val2014_000000542611.jpg -../coco/images/val2014/COCO_val2014_000000542676.jpg -../coco/images/val2014/COCO_val2014_000000542792.jpg -../coco/images/val2014/COCO_val2014_000000543112.jpg -../coco/images/val2014/COCO_val2014_000000543118.jpg -../coco/images/val2014/COCO_val2014_000000543203.jpg -../coco/images/val2014/COCO_val2014_000000543220.jpg -../coco/images/val2014/COCO_val2014_000000543281.jpg -../coco/images/val2014/COCO_val2014_000000543492.jpg -../coco/images/val2014/COCO_val2014_000000543581.jpg -../coco/images/val2014/COCO_val2014_000000543660.jpg -../coco/images/val2014/COCO_val2014_000000543676.jpg -../coco/images/val2014/COCO_val2014_000000543696.jpg -../coco/images/val2014/COCO_val2014_000000543782.jpg -../coco/images/val2014/COCO_val2014_000000544044.jpg -../coco/images/val2014/COCO_val2014_000000544071.jpg -../coco/images/val2014/COCO_val2014_000000544140.jpg -../coco/images/val2014/COCO_val2014_000000544597.jpg -../coco/images/val2014/COCO_val2014_000000544607.jpg -../coco/images/val2014/COCO_val2014_000000544611.jpg -../coco/images/val2014/COCO_val2014_000000544644.jpg -../coco/images/val2014/COCO_val2014_000000545289.jpg -../coco/images/val2014/COCO_val2014_000000545407.jpg -../coco/images/val2014/COCO_val2014_000000545475.jpg -../coco/images/val2014/COCO_val2014_000000545583.jpg -../coco/images/val2014/COCO_val2014_000000545597.jpg -../coco/images/val2014/COCO_val2014_000000545734.jpg -../coco/images/val2014/COCO_val2014_000000545756.jpg -../coco/images/val2014/COCO_val2014_000000545788.jpg -../coco/images/val2014/COCO_val2014_000000545958.jpg -../coco/images/val2014/COCO_val2014_000000546188.jpg -../coco/images/val2014/COCO_val2014_000000546226.jpg -../coco/images/val2014/COCO_val2014_000000546229.jpg -../coco/images/val2014/COCO_val2014_000000546388.jpg -../coco/images/val2014/COCO_val2014_000000546424.jpg -../coco/images/val2014/COCO_val2014_000000546524.jpg -../coco/images/val2014/COCO_val2014_000000546569.jpg -../coco/images/val2014/COCO_val2014_000000546622.jpg -../coco/images/val2014/COCO_val2014_000000546649.jpg -../coco/images/val2014/COCO_val2014_000000546667.jpg -../coco/images/val2014/COCO_val2014_000000546760.jpg -../coco/images/val2014/COCO_val2014_000000546782.jpg -../coco/images/val2014/COCO_val2014_000000546962.jpg -../coco/images/val2014/COCO_val2014_000000547137.jpg -../coco/images/val2014/COCO_val2014_000000547383.jpg -../coco/images/val2014/COCO_val2014_000000547519.jpg -../coco/images/val2014/COCO_val2014_000000547583.jpg -../coco/images/val2014/COCO_val2014_000000547738.jpg -../coco/images/val2014/COCO_val2014_000000547790.jpg -../coco/images/val2014/COCO_val2014_000000547858.jpg -../coco/images/val2014/COCO_val2014_000000548090.jpg -../coco/images/val2014/COCO_val2014_000000548126.jpg -../coco/images/val2014/COCO_val2014_000000548339.jpg -../coco/images/val2014/COCO_val2014_000000548795.jpg -../coco/images/val2014/COCO_val2014_000000548882.jpg -../coco/images/val2014/COCO_val2014_000000549063.jpg -../coco/images/val2014/COCO_val2014_000000549171.jpg -../coco/images/val2014/COCO_val2014_000000549242.jpg -../coco/images/val2014/COCO_val2014_000000549351.jpg -../coco/images/val2014/COCO_val2014_000000549410.jpg -../coco/images/val2014/COCO_val2014_000000549518.jpg -../coco/images/val2014/COCO_val2014_000000549713.jpg -../coco/images/val2014/COCO_val2014_000000549936.jpg -../coco/images/val2014/COCO_val2014_000000550001.jpg -../coco/images/val2014/COCO_val2014_000000550322.jpg -../coco/images/val2014/COCO_val2014_000000550432.jpg -../coco/images/val2014/COCO_val2014_000000550597.jpg -../coco/images/val2014/COCO_val2014_000000550627.jpg -../coco/images/val2014/COCO_val2014_000000550722.jpg -../coco/images/val2014/COCO_val2014_000000550862.jpg -../coco/images/val2014/COCO_val2014_000000551129.jpg -../coco/images/val2014/COCO_val2014_000000551243.jpg -../coco/images/val2014/COCO_val2014_000000551336.jpg -../coco/images/val2014/COCO_val2014_000000551669.jpg -../coco/images/val2014/COCO_val2014_000000552507.jpg -../coco/images/val2014/COCO_val2014_000000552837.jpg -../coco/images/val2014/COCO_val2014_000000553074.jpg -../coco/images/val2014/COCO_val2014_000000553165.jpg -../coco/images/val2014/COCO_val2014_000000553253.jpg -../coco/images/val2014/COCO_val2014_000000553306.jpg -../coco/images/val2014/COCO_val2014_000000553353.jpg -../coco/images/val2014/COCO_val2014_000000553443.jpg -../coco/images/val2014/COCO_val2014_000000553522.jpg -../coco/images/val2014/COCO_val2014_000000553664.jpg -../coco/images/val2014/COCO_val2014_000000554037.jpg -../coco/images/val2014/COCO_val2014_000000554100.jpg -../coco/images/val2014/COCO_val2014_000000554255.jpg -../coco/images/val2014/COCO_val2014_000000554266.jpg -../coco/images/val2014/COCO_val2014_000000554291.jpg -../coco/images/val2014/COCO_val2014_000000554302.jpg -../coco/images/val2014/COCO_val2014_000000554340.jpg -../coco/images/val2014/COCO_val2014_000000554347.jpg -../coco/images/val2014/COCO_val2014_000000554537.jpg -../coco/images/val2014/COCO_val2014_000000554595.jpg -../coco/images/val2014/COCO_val2014_000000554607.jpg -../coco/images/val2014/COCO_val2014_000000554618.jpg -../coco/images/val2014/COCO_val2014_000000554625.jpg -../coco/images/val2014/COCO_val2014_000000554711.jpg -../coco/images/val2014/COCO_val2014_000000554727.jpg -../coco/images/val2014/COCO_val2014_000000554767.jpg -../coco/images/val2014/COCO_val2014_000000554978.jpg -../coco/images/val2014/COCO_val2014_000000555035.jpg -../coco/images/val2014/COCO_val2014_000000555110.jpg -../coco/images/val2014/COCO_val2014_000000555180.jpg -../coco/images/val2014/COCO_val2014_000000555197.jpg -../coco/images/val2014/COCO_val2014_000000555267.jpg -../coco/images/val2014/COCO_val2014_000000555322.jpg -../coco/images/val2014/COCO_val2014_000000555412.jpg -../coco/images/val2014/COCO_val2014_000000555456.jpg -../coco/images/val2014/COCO_val2014_000000556091.jpg -../coco/images/val2014/COCO_val2014_000000556178.jpg -../coco/images/val2014/COCO_val2014_000000556193.jpg -../coco/images/val2014/COCO_val2014_000000556278.jpg -../coco/images/val2014/COCO_val2014_000000556562.jpg -../coco/images/val2014/COCO_val2014_000000556633.jpg -../coco/images/val2014/COCO_val2014_000000556641.jpg -../coco/images/val2014/COCO_val2014_000000556653.jpg -../coco/images/val2014/COCO_val2014_000000556751.jpg -../coco/images/val2014/COCO_val2014_000000556758.jpg -../coco/images/val2014/COCO_val2014_000000557016.jpg -../coco/images/val2014/COCO_val2014_000000557402.jpg -../coco/images/val2014/COCO_val2014_000000557556.jpg -../coco/images/val2014/COCO_val2014_000000557564.jpg -../coco/images/val2014/COCO_val2014_000000557595.jpg -../coco/images/val2014/COCO_val2014_000000557720.jpg -../coco/images/val2014/COCO_val2014_000000557731.jpg -../coco/images/val2014/COCO_val2014_000000557785.jpg -../coco/images/val2014/COCO_val2014_000000557896.jpg -../coco/images/val2014/COCO_val2014_000000557916.jpg -../coco/images/val2014/COCO_val2014_000000557923.jpg -../coco/images/val2014/COCO_val2014_000000557965.jpg -../coco/images/val2014/COCO_val2014_000000557977.jpg -../coco/images/val2014/COCO_val2014_000000558539.jpg -../coco/images/val2014/COCO_val2014_000000558587.jpg -../coco/images/val2014/COCO_val2014_000000558661.jpg -../coco/images/val2014/COCO_val2014_000000558784.jpg -../coco/images/val2014/COCO_val2014_000000558864.jpg -../coco/images/val2014/COCO_val2014_000000558955.jpg -../coco/images/val2014/COCO_val2014_000000558976.jpg -../coco/images/val2014/COCO_val2014_000000559047.jpg -../coco/images/val2014/COCO_val2014_000000559348.jpg -../coco/images/val2014/COCO_val2014_000000559656.jpg -../coco/images/val2014/COCO_val2014_000000559778.jpg -../coco/images/val2014/COCO_val2014_000000559790.jpg -../coco/images/val2014/COCO_val2014_000000560000.jpg -../coco/images/val2014/COCO_val2014_000000560227.jpg -../coco/images/val2014/COCO_val2014_000000560235.jpg -../coco/images/val2014/COCO_val2014_000000560279.jpg -../coco/images/val2014/COCO_val2014_000000560373.jpg -../coco/images/val2014/COCO_val2014_000000560626.jpg -../coco/images/val2014/COCO_val2014_000000560662.jpg -../coco/images/val2014/COCO_val2014_000000560721.jpg -../coco/images/val2014/COCO_val2014_000000560911.jpg -../coco/images/val2014/COCO_val2014_000000561027.jpg -../coco/images/val2014/COCO_val2014_000000561337.jpg -../coco/images/val2014/COCO_val2014_000000561357.jpg -../coco/images/val2014/COCO_val2014_000000561399.jpg -../coco/images/val2014/COCO_val2014_000000561570.jpg -../coco/images/val2014/COCO_val2014_000000561619.jpg -../coco/images/val2014/COCO_val2014_000000561698.jpg -../coco/images/val2014/COCO_val2014_000000562101.jpg -../coco/images/val2014/COCO_val2014_000000562227.jpg -../coco/images/val2014/COCO_val2014_000000562557.jpg -../coco/images/val2014/COCO_val2014_000000562582.jpg -../coco/images/val2014/COCO_val2014_000000562708.jpg -../coco/images/val2014/COCO_val2014_000000562805.jpg -../coco/images/val2014/COCO_val2014_000000562834.jpg -../coco/images/val2014/COCO_val2014_000000562875.jpg -../coco/images/val2014/COCO_val2014_000000562906.jpg -../coco/images/val2014/COCO_val2014_000000562943.jpg -../coco/images/val2014/COCO_val2014_000000562994.jpg -../coco/images/val2014/COCO_val2014_000000563015.jpg -../coco/images/val2014/COCO_val2014_000000563641.jpg -../coco/images/val2014/COCO_val2014_000000563665.jpg -../coco/images/val2014/COCO_val2014_000000563730.jpg -../coco/images/val2014/COCO_val2014_000000563871.jpg -../coco/images/val2014/COCO_val2014_000000564109.jpg -../coco/images/val2014/COCO_val2014_000000564127.jpg -../coco/images/val2014/COCO_val2014_000000564129.jpg -../coco/images/val2014/COCO_val2014_000000564289.jpg -../coco/images/val2014/COCO_val2014_000000564317.jpg -../coco/images/val2014/COCO_val2014_000000564366.jpg -../coco/images/val2014/COCO_val2014_000000564934.jpg -../coco/images/val2014/COCO_val2014_000000564940.jpg -../coco/images/val2014/COCO_val2014_000000565239.jpg -../coco/images/val2014/COCO_val2014_000000565389.jpg -../coco/images/val2014/COCO_val2014_000000565479.jpg -../coco/images/val2014/COCO_val2014_000000565543.jpg -../coco/images/val2014/COCO_val2014_000000565597.jpg -../coco/images/val2014/COCO_val2014_000000565670.jpg -../coco/images/val2014/COCO_val2014_000000565691.jpg -../coco/images/val2014/COCO_val2014_000000565693.jpg -../coco/images/val2014/COCO_val2014_000000565761.jpg -../coco/images/val2014/COCO_val2014_000000565877.jpg -../coco/images/val2014/COCO_val2014_000000565957.jpg -../coco/images/val2014/COCO_val2014_000000566027.jpg -../coco/images/val2014/COCO_val2014_000000566038.jpg -../coco/images/val2014/COCO_val2014_000000566103.jpg -../coco/images/val2014/COCO_val2014_000000566135.jpg -../coco/images/val2014/COCO_val2014_000000566298.jpg -../coco/images/val2014/COCO_val2014_000000566518.jpg -../coco/images/val2014/COCO_val2014_000000566538.jpg -../coco/images/val2014/COCO_val2014_000000566644.jpg -../coco/images/val2014/COCO_val2014_000000566908.jpg -../coco/images/val2014/COCO_val2014_000000566941.jpg -../coco/images/val2014/COCO_val2014_000000567093.jpg -../coco/images/val2014/COCO_val2014_000000567171.jpg -../coco/images/val2014/COCO_val2014_000000567205.jpg -../coco/images/val2014/COCO_val2014_000000567315.jpg -../coco/images/val2014/COCO_val2014_000000567340.jpg -../coco/images/val2014/COCO_val2014_000000567383.jpg -../coco/images/val2014/COCO_val2014_000000567686.jpg -../coco/images/val2014/COCO_val2014_000000567801.jpg -../coco/images/val2014/COCO_val2014_000000567812.jpg -../coco/images/val2014/COCO_val2014_000000567877.jpg -../coco/images/val2014/COCO_val2014_000000567886.jpg -../coco/images/val2014/COCO_val2014_000000568082.jpg -../coco/images/val2014/COCO_val2014_000000568131.jpg -../coco/images/val2014/COCO_val2014_000000568132.jpg -../coco/images/val2014/COCO_val2014_000000568195.jpg -../coco/images/val2014/COCO_val2014_000000568259.jpg -../coco/images/val2014/COCO_val2014_000000568265.jpg -../coco/images/val2014/COCO_val2014_000000568337.jpg -../coco/images/val2014/COCO_val2014_000000568555.jpg -../coco/images/val2014/COCO_val2014_000000568623.jpg -../coco/images/val2014/COCO_val2014_000000568653.jpg -../coco/images/val2014/COCO_val2014_000000568675.jpg -../coco/images/val2014/COCO_val2014_000000568717.jpg -../coco/images/val2014/COCO_val2014_000000568956.jpg -../coco/images/val2014/COCO_val2014_000000568961.jpg -../coco/images/val2014/COCO_val2014_000000569001.jpg -../coco/images/val2014/COCO_val2014_000000569272.jpg -../coco/images/val2014/COCO_val2014_000000569273.jpg -../coco/images/val2014/COCO_val2014_000000569319.jpg -../coco/images/val2014/COCO_val2014_000000569432.jpg -../coco/images/val2014/COCO_val2014_000000569437.jpg -../coco/images/val2014/COCO_val2014_000000569972.jpg -../coco/images/val2014/COCO_val2014_000000569976.jpg -../coco/images/val2014/COCO_val2014_000000570188.jpg -../coco/images/val2014/COCO_val2014_000000570456.jpg -../coco/images/val2014/COCO_val2014_000000570471.jpg -../coco/images/val2014/COCO_val2014_000000570680.jpg -../coco/images/val2014/COCO_val2014_000000570688.jpg -../coco/images/val2014/COCO_val2014_000000571012.jpg -../coco/images/val2014/COCO_val2014_000000571497.jpg -../coco/images/val2014/COCO_val2014_000000571550.jpg -../coco/images/val2014/COCO_val2014_000000571584.jpg -../coco/images/val2014/COCO_val2014_000000571635.jpg -../coco/images/val2014/COCO_val2014_000000571636.jpg -../coco/images/val2014/COCO_val2014_000000571746.jpg -../coco/images/val2014/COCO_val2014_000000571931.jpg -../coco/images/val2014/COCO_val2014_000000572017.jpg -../coco/images/val2014/COCO_val2014_000000572042.jpg -../coco/images/val2014/COCO_val2014_000000572051.jpg -../coco/images/val2014/COCO_val2014_000000572090.jpg -../coco/images/val2014/COCO_val2014_000000572233.jpg -../coco/images/val2014/COCO_val2014_000000572303.jpg -../coco/images/val2014/COCO_val2014_000000572347.jpg -../coco/images/val2014/COCO_val2014_000000572408.jpg -../coco/images/val2014/COCO_val2014_000000572517.jpg -../coco/images/val2014/COCO_val2014_000000572802.jpg -../coco/images/val2014/COCO_val2014_000000572850.jpg -../coco/images/val2014/COCO_val2014_000000573058.jpg -../coco/images/val2014/COCO_val2014_000000573067.jpg -../coco/images/val2014/COCO_val2014_000000573209.jpg -../coco/images/val2014/COCO_val2014_000000573363.jpg -../coco/images/val2014/COCO_val2014_000000573791.jpg -../coco/images/val2014/COCO_val2014_000000573853.jpg -../coco/images/val2014/COCO_val2014_000000573877.jpg -../coco/images/val2014/COCO_val2014_000000574108.jpg -../coco/images/val2014/COCO_val2014_000000574411.jpg -../coco/images/val2014/COCO_val2014_000000574413.jpg -../coco/images/val2014/COCO_val2014_000000574454.jpg -../coco/images/val2014/COCO_val2014_000000574509.jpg -../coco/images/val2014/COCO_val2014_000000574725.jpg -../coco/images/val2014/COCO_val2014_000000574823.jpg -../coco/images/val2014/COCO_val2014_000000574988.jpg -../coco/images/val2014/COCO_val2014_000000575020.jpg -../coco/images/val2014/COCO_val2014_000000575079.jpg -../coco/images/val2014/COCO_val2014_000000575081.jpg -../coco/images/val2014/COCO_val2014_000000575194.jpg -../coco/images/val2014/COCO_val2014_000000575428.jpg -../coco/images/val2014/COCO_val2014_000000575624.jpg -../coco/images/val2014/COCO_val2014_000000575957.jpg -../coco/images/val2014/COCO_val2014_000000576070.jpg -../coco/images/val2014/COCO_val2014_000000576085.jpg -../coco/images/val2014/COCO_val2014_000000576566.jpg -../coco/images/val2014/COCO_val2014_000000576629.jpg -../coco/images/val2014/COCO_val2014_000000576654.jpg -../coco/images/val2014/COCO_val2014_000000576704.jpg -../coco/images/val2014/COCO_val2014_000000576714.jpg -../coco/images/val2014/COCO_val2014_000000576820.jpg -../coco/images/val2014/COCO_val2014_000000576857.jpg -../coco/images/val2014/COCO_val2014_000000576955.jpg -../coco/images/val2014/COCO_val2014_000000576981.jpg -../coco/images/val2014/COCO_val2014_000000577128.jpg -../coco/images/val2014/COCO_val2014_000000577160.jpg -../coco/images/val2014/COCO_val2014_000000577161.jpg -../coco/images/val2014/COCO_val2014_000000577169.jpg -../coco/images/val2014/COCO_val2014_000000577212.jpg -../coco/images/val2014/COCO_val2014_000000577385.jpg -../coco/images/val2014/COCO_val2014_000000577522.jpg -../coco/images/val2014/COCO_val2014_000000577584.jpg -../coco/images/val2014/COCO_val2014_000000577847.jpg -../coco/images/val2014/COCO_val2014_000000577877.jpg -../coco/images/val2014/COCO_val2014_000000577912.jpg -../coco/images/val2014/COCO_val2014_000000577924.jpg -../coco/images/val2014/COCO_val2014_000000578225.jpg -../coco/images/val2014/COCO_val2014_000000578237.jpg -../coco/images/val2014/COCO_val2014_000000578341.jpg -../coco/images/val2014/COCO_val2014_000000578344.jpg -../coco/images/val2014/COCO_val2014_000000578427.jpg -../coco/images/val2014/COCO_val2014_000000578871.jpg -../coco/images/val2014/COCO_val2014_000000578878.jpg -../coco/images/val2014/COCO_val2014_000000579003.jpg -../coco/images/val2014/COCO_val2014_000000579240.jpg -../coco/images/val2014/COCO_val2014_000000579321.jpg -../coco/images/val2014/COCO_val2014_000000579337.jpg -../coco/images/val2014/COCO_val2014_000000579548.jpg -../coco/images/val2014/COCO_val2014_000000579885.jpg -../coco/images/val2014/COCO_val2014_000000579902.jpg -../coco/images/val2014/COCO_val2014_000000580027.jpg -../coco/images/val2014/COCO_val2014_000000580029.jpg -../coco/images/val2014/COCO_val2014_000000580294.jpg -../coco/images/val2014/COCO_val2014_000000580540.jpg -../coco/images/val2014/COCO_val2014_000000580608.jpg -../coco/images/val2014/COCO_val2014_000000580693.jpg -../coco/images/val2014/COCO_val2014_000000580720.jpg -../coco/images/val2014/COCO_val2014_000000580870.jpg -../coco/images/val2014/COCO_val2014_000000580975.jpg -../coco/images/val2014/COCO_val2014_000000581332.jpg -../coco/images/val2014/COCO_val2014_000000581593.jpg -../coco/images/val2014/COCO_val2014_000000581655.jpg -../coco/images/val2014/COCO_val2014_000000581731.jpg -../coco/images/val2014/COCO_val2014_000000581781.jpg -../coco/images/val2014/COCO_val2014_000000581887.jpg -../coco/images/val2014/COCO_val2014_000000581899.jpg diff --git a/data/coco_16img.txt b/data/coco_16img.txt index 03d84a2726..e7bb74c037 100644 --- a/data/coco_16img.txt +++ b/data/coco_16img.txt @@ -1,16 +1,16 @@ -../coco/images/train2014/COCO_train2014_000000000009.jpg -../coco/images/train2014/COCO_train2014_000000000025.jpg -../coco/images/train2014/COCO_train2014_000000000030.jpg -../coco/images/train2014/COCO_train2014_000000000034.jpg -../coco/images/train2014/COCO_train2014_000000000036.jpg -../coco/images/train2014/COCO_train2014_000000000049.jpg -../coco/images/train2014/COCO_train2014_000000000061.jpg -../coco/images/train2014/COCO_train2014_000000000064.jpg -../coco/images/train2014/COCO_train2014_000000000071.jpg -../coco/images/train2014/COCO_train2014_000000000072.jpg -../coco/images/train2014/COCO_train2014_000000000077.jpg -../coco/images/train2014/COCO_train2014_000000000078.jpg -../coco/images/train2014/COCO_train2014_000000000081.jpg -../coco/images/train2014/COCO_train2014_000000000086.jpg -../coco/images/train2014/COCO_train2014_000000000089.jpg -../coco/images/train2014/COCO_train2014_000000000092.jpg +../coco/images/COCO_train2014_000000000009.jpg +../coco/images/COCO_train2014_000000000025.jpg +../coco/images/COCO_train2014_000000000030.jpg +../coco/images/COCO_train2014_000000000034.jpg +../coco/images/COCO_train2014_000000000036.jpg +../coco/images/COCO_train2014_000000000049.jpg +../coco/images/COCO_train2014_000000000061.jpg +../coco/images/COCO_train2014_000000000064.jpg +../coco/images/COCO_train2014_000000000071.jpg +../coco/images/COCO_train2014_000000000072.jpg +../coco/images/COCO_train2014_000000000077.jpg +../coco/images/COCO_train2014_000000000078.jpg +../coco/images/COCO_train2014_000000000081.jpg +../coco/images/COCO_train2014_000000000086.jpg +../coco/images/COCO_train2014_000000000089.jpg +../coco/images/COCO_train2014_000000000092.jpg diff --git a/data/coco_1cls.txt b/data/coco_1cls.txt index aea1ea87eb..956293ca97 100644 --- a/data/coco_1cls.txt +++ b/data/coco_1cls.txt @@ -1,5 +1,5 @@ -../coco/images/val2014/COCO_val2014_000000013992.jpg -../coco/images/val2014/COCO_val2014_000000047226.jpg -../coco/images/val2014/COCO_val2014_000000050324.jpg -../coco/images/val2014/COCO_val2014_000000121497.jpg -../coco/images/val2014/COCO_val2014_000000001464.jpg +../coco/images/COCO_val2014_000000013992.jpg +../coco/images/COCO_val2014_000000047226.jpg +../coco/images/COCO_val2014_000000050324.jpg +../coco/images/COCO_val2014_000000121497.jpg +../coco/images/COCO_val2014_000000001464.jpg diff --git a/data/coco_1img.txt b/data/coco_1img.txt index 85defa2913..a0fbd05467 100644 --- a/data/coco_1img.txt +++ b/data/coco_1img.txt @@ -1 +1 @@ -../coco/images/val2014/COCO_val2014_000000581886.jpg +../coco/images/COCO_val2014_000000581886.jpg diff --git a/data/coco_64img.txt b/data/coco_64img.txt index 306ff3b4e8..b8b44f7b08 100644 --- a/data/coco_64img.txt +++ b/data/coco_64img.txt @@ -1,64 +1,64 @@ -../coco/images/train2014/COCO_train2014_000000000009.jpg -../coco/images/train2014/COCO_train2014_000000000025.jpg -../coco/images/train2014/COCO_train2014_000000000030.jpg -../coco/images/train2014/COCO_train2014_000000000034.jpg -../coco/images/train2014/COCO_train2014_000000000036.jpg -../coco/images/train2014/COCO_train2014_000000000049.jpg -../coco/images/train2014/COCO_train2014_000000000061.jpg -../coco/images/train2014/COCO_train2014_000000000064.jpg -../coco/images/train2014/COCO_train2014_000000000071.jpg -../coco/images/train2014/COCO_train2014_000000000072.jpg -../coco/images/train2014/COCO_train2014_000000000077.jpg -../coco/images/train2014/COCO_train2014_000000000078.jpg -../coco/images/train2014/COCO_train2014_000000000081.jpg -../coco/images/train2014/COCO_train2014_000000000086.jpg -../coco/images/train2014/COCO_train2014_000000000089.jpg -../coco/images/train2014/COCO_train2014_000000000092.jpg -../coco/images/train2014/COCO_train2014_000000000094.jpg -../coco/images/train2014/COCO_train2014_000000000109.jpg -../coco/images/train2014/COCO_train2014_000000000110.jpg -../coco/images/train2014/COCO_train2014_000000000113.jpg -../coco/images/train2014/COCO_train2014_000000000127.jpg -../coco/images/train2014/COCO_train2014_000000000138.jpg -../coco/images/train2014/COCO_train2014_000000000142.jpg -../coco/images/train2014/COCO_train2014_000000000144.jpg -../coco/images/train2014/COCO_train2014_000000000149.jpg -../coco/images/train2014/COCO_train2014_000000000151.jpg -../coco/images/train2014/COCO_train2014_000000000154.jpg -../coco/images/train2014/COCO_train2014_000000000165.jpg -../coco/images/train2014/COCO_train2014_000000000194.jpg -../coco/images/train2014/COCO_train2014_000000000201.jpg -../coco/images/train2014/COCO_train2014_000000000247.jpg -../coco/images/train2014/COCO_train2014_000000000260.jpg -../coco/images/train2014/COCO_train2014_000000000263.jpg -../coco/images/train2014/COCO_train2014_000000000307.jpg -../coco/images/train2014/COCO_train2014_000000000308.jpg -../coco/images/train2014/COCO_train2014_000000000309.jpg -../coco/images/train2014/COCO_train2014_000000000312.jpg -../coco/images/train2014/COCO_train2014_000000000315.jpg -../coco/images/train2014/COCO_train2014_000000000321.jpg -../coco/images/train2014/COCO_train2014_000000000322.jpg -../coco/images/train2014/COCO_train2014_000000000326.jpg -../coco/images/train2014/COCO_train2014_000000000332.jpg -../coco/images/train2014/COCO_train2014_000000000349.jpg -../coco/images/train2014/COCO_train2014_000000000368.jpg -../coco/images/train2014/COCO_train2014_000000000370.jpg -../coco/images/train2014/COCO_train2014_000000000382.jpg -../coco/images/train2014/COCO_train2014_000000000384.jpg -../coco/images/train2014/COCO_train2014_000000000389.jpg -../coco/images/train2014/COCO_train2014_000000000394.jpg -../coco/images/train2014/COCO_train2014_000000000404.jpg -../coco/images/train2014/COCO_train2014_000000000419.jpg -../coco/images/train2014/COCO_train2014_000000000431.jpg -../coco/images/train2014/COCO_train2014_000000000436.jpg -../coco/images/train2014/COCO_train2014_000000000438.jpg -../coco/images/train2014/COCO_train2014_000000000443.jpg -../coco/images/train2014/COCO_train2014_000000000446.jpg -../coco/images/train2014/COCO_train2014_000000000450.jpg -../coco/images/train2014/COCO_train2014_000000000471.jpg -../coco/images/train2014/COCO_train2014_000000000490.jpg -../coco/images/train2014/COCO_train2014_000000000491.jpg -../coco/images/train2014/COCO_train2014_000000000510.jpg -../coco/images/train2014/COCO_train2014_000000000514.jpg -../coco/images/train2014/COCO_train2014_000000000529.jpg -../coco/images/train2014/COCO_train2014_000000000531.jpg +../coco/images/COCO_train2014_000000000009.jpg +../coco/images/COCO_train2014_000000000025.jpg +../coco/images/COCO_train2014_000000000030.jpg +../coco/images/COCO_train2014_000000000034.jpg +../coco/images/COCO_train2014_000000000036.jpg +../coco/images/COCO_train2014_000000000049.jpg +../coco/images/COCO_train2014_000000000061.jpg +../coco/images/COCO_train2014_000000000064.jpg +../coco/images/COCO_train2014_000000000071.jpg +../coco/images/COCO_train2014_000000000072.jpg +../coco/images/COCO_train2014_000000000077.jpg +../coco/images/COCO_train2014_000000000078.jpg +../coco/images/COCO_train2014_000000000081.jpg +../coco/images/COCO_train2014_000000000086.jpg +../coco/images/COCO_train2014_000000000089.jpg +../coco/images/COCO_train2014_000000000092.jpg +../coco/images/COCO_train2014_000000000094.jpg +../coco/images/COCO_train2014_000000000109.jpg +../coco/images/COCO_train2014_000000000110.jpg +../coco/images/COCO_train2014_000000000113.jpg +../coco/images/COCO_train2014_000000000127.jpg +../coco/images/COCO_train2014_000000000138.jpg +../coco/images/COCO_train2014_000000000142.jpg +../coco/images/COCO_train2014_000000000144.jpg +../coco/images/COCO_train2014_000000000149.jpg +../coco/images/COCO_train2014_000000000151.jpg +../coco/images/COCO_train2014_000000000154.jpg +../coco/images/COCO_train2014_000000000165.jpg +../coco/images/COCO_train2014_000000000194.jpg +../coco/images/COCO_train2014_000000000201.jpg +../coco/images/COCO_train2014_000000000247.jpg +../coco/images/COCO_train2014_000000000260.jpg +../coco/images/COCO_train2014_000000000263.jpg +../coco/images/COCO_train2014_000000000307.jpg +../coco/images/COCO_train2014_000000000308.jpg +../coco/images/COCO_train2014_000000000309.jpg +../coco/images/COCO_train2014_000000000312.jpg +../coco/images/COCO_train2014_000000000315.jpg +../coco/images/COCO_train2014_000000000321.jpg +../coco/images/COCO_train2014_000000000322.jpg +../coco/images/COCO_train2014_000000000326.jpg +../coco/images/COCO_train2014_000000000332.jpg +../coco/images/COCO_train2014_000000000349.jpg +../coco/images/COCO_train2014_000000000368.jpg +../coco/images/COCO_train2014_000000000370.jpg +../coco/images/COCO_train2014_000000000382.jpg +../coco/images/COCO_train2014_000000000384.jpg +../coco/images/COCO_train2014_000000000389.jpg +../coco/images/COCO_train2014_000000000394.jpg +../coco/images/COCO_train2014_000000000404.jpg +../coco/images/COCO_train2014_000000000419.jpg +../coco/images/COCO_train2014_000000000431.jpg +../coco/images/COCO_train2014_000000000436.jpg +../coco/images/COCO_train2014_000000000438.jpg +../coco/images/COCO_train2014_000000000443.jpg +../coco/images/COCO_train2014_000000000446.jpg +../coco/images/COCO_train2014_000000000450.jpg +../coco/images/COCO_train2014_000000000471.jpg +../coco/images/COCO_train2014_000000000490.jpg +../coco/images/COCO_train2014_000000000491.jpg +../coco/images/COCO_train2014_000000000510.jpg +../coco/images/COCO_train2014_000000000514.jpg +../coco/images/COCO_train2014_000000000529.jpg +../coco/images/COCO_train2014_000000000531.jpg From 0a489bc1c3dc2cb43029f3028ede2719797d7d08 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 16:21:03 -0800 Subject: [PATCH 0107/1185] updates --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2ea8d615e0..518a16be0e 100755 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,6 @@ data/* !data/coco.data !data/coco_*.data !data/coco_*.txt -!data/coco_*.txt !data/trainvalno5k.shapes !data/*.sh From 6b8425b9ec21740c3a8fb9d22e57221accadc709 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 17:31:27 -0800 Subject: [PATCH 0108/1185] updates --- data/get_coco2017.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100755 data/get_coco2017.sh diff --git a/data/get_coco2017.sh b/data/get_coco2017.sh new file mode 100755 index 0000000000..6569e3798d --- /dev/null +++ b/data/get_coco2017.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Zip coco folder +# zip -r coco.zip coco +# tar -czvf coco.tar.gz coco + +# Download labels from Google Drive, accepting presented query +filename="coco2017labels.zip" +fileid="1cXZR_ckHki6nddOmcysCuuJFM--T-Q6L" +curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" > /dev/null +curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}" -o ${filename} +rm ./cookie ./$filename + +# Unzip labels +unzip -q ${filename} # for coco.zip +# tar -xzf ${filename} # for coco.tar.gz + +# Download images +cd coco/images +wget -c http://images.cocodataset.org/zips/train2017.zip +wget -c http://images.cocodataset.org/zips/val2017.zip + +# Unzip images +unzip -q train2017.zip +unzip -q val2017.zip + +# (optional) Delete zip files +rm -rf *.zip + +# cd out +cd ../.. + From 4b368b704b07cd9dcdee7a80120cb808a72b1a45 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 17:34:19 -0800 Subject: [PATCH 0109/1185] updates --- data/get_coco2017.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/get_coco2017.sh b/data/get_coco2017.sh index 6569e3798d..beff2dcfd8 100755 --- a/data/get_coco2017.sh +++ b/data/get_coco2017.sh @@ -8,7 +8,7 @@ filename="coco2017labels.zip" fileid="1cXZR_ckHki6nddOmcysCuuJFM--T-Q6L" curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" > /dev/null curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}" -o ${filename} -rm ./cookie ./$filename +rm ./cookie # Unzip labels unzip -q ${filename} # for coco.zip @@ -24,7 +24,7 @@ unzip -q train2017.zip unzip -q val2017.zip # (optional) Delete zip files -rm -rf *.zip +rm -rf *.zip ../*.zip # cd out cd ../.. From a4bdb8ce2ee401cd6922c3e65273f24d0a27c372 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 17:46:42 -0800 Subject: [PATCH 0110/1185] updates --- data/get_coco2017.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/get_coco2017.sh b/data/get_coco2017.sh index beff2dcfd8..ba24151d17 100755 --- a/data/get_coco2017.sh +++ b/data/get_coco2017.sh @@ -13,6 +13,7 @@ rm ./cookie # Unzip labels unzip -q ${filename} # for coco.zip # tar -xzf ${filename} # for coco.tar.gz +rm ${filename} # Download images cd coco/images @@ -24,7 +25,7 @@ unzip -q train2017.zip unzip -q val2017.zip # (optional) Delete zip files -rm -rf *.zip ../*.zip +rm -rf *.zip # cd out cd ../.. From 0465500b37717881ecc8d03d438e6c6e2ec8e223 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 18:52:08 -0800 Subject: [PATCH 0111/1185] updates --- data/5k.shapes | 5000 -- data/coco.data | 6 - data/{coco_1img.data => coco1.data} | 0 data/coco1.txt | 1 + data/coco16.data | 4 + data/coco16.txt | 16 + data/coco1cls.data | 4 + data/coco1cls.txt | 16 + data/coco2017.data | 4 + data/coco64.data | 4 + data/coco64.txt | 64 + data/coco_16img.data | 6 - data/coco_16img.txt | 16 - data/coco_1cls.data | 6 - data/coco_1cls.txt | 5 - data/coco_1img.txt | 1 - data/coco_64img.data | 6 - data/coco_64img.txt | 64 - data/get_coco2014.sh | 33 + data/get_coco_dataset.sh | 39 - data/get_coco_dataset_gdrive.sh | 17 - data/trainvalno5k.shapes | 117263 ------------------------- utils/datasets.py | 2 +- utils/utils.py | 2 +- 24 files changed, 148 insertions(+), 122431 deletions(-) delete mode 100644 data/5k.shapes delete mode 100644 data/coco.data rename data/{coco_1img.data => coco1.data} (100%) create mode 100644 data/coco1.txt create mode 100644 data/coco16.data create mode 100644 data/coco16.txt create mode 100644 data/coco1cls.data create mode 100644 data/coco1cls.txt create mode 100644 data/coco2017.data create mode 100644 data/coco64.data create mode 100644 data/coco64.txt delete mode 100644 data/coco_16img.data delete mode 100644 data/coco_16img.txt delete mode 100644 data/coco_1cls.data delete mode 100644 data/coco_1cls.txt delete mode 100644 data/coco_1img.txt delete mode 100644 data/coco_64img.data delete mode 100644 data/coco_64img.txt create mode 100755 data/get_coco2014.sh delete mode 100755 data/get_coco_dataset.sh delete mode 100755 data/get_coco_dataset_gdrive.sh delete mode 100644 data/trainvalno5k.shapes diff --git a/data/5k.shapes b/data/5k.shapes deleted file mode 100644 index d4d57b67e9..0000000000 --- a/data/5k.shapes +++ /dev/null @@ -1,5000 +0,0 @@ -640 480 -640 480 -428 640 -640 480 -640 480 -640 407 -640 480 -640 427 -500 343 -621 640 -480 640 -640 427 -424 640 -640 480 -640 424 -640 480 -640 427 -500 375 -640 480 -640 479 -427 640 -640 480 -640 425 -640 480 -400 338 -480 640 -640 428 -640 640 -640 338 -640 480 -640 427 -640 384 -480 640 -640 480 -640 426 -425 640 -512 640 -640 415 -640 480 -640 319 -640 426 -640 427 -640 364 -640 480 -480 640 -558 640 -640 528 -612 612 -481 640 -640 427 -640 360 -457 640 -640 427 -480 640 -459 640 -640 425 -640 521 -640 424 -640 513 -480 640 -640 346 -640 361 -640 427 -500 332 -640 427 -640 427 -640 443 -500 333 -640 427 -640 480 -640 430 -640 428 -640 337 -640 640 -640 480 -480 640 -424 640 -640 640 -500 331 -640 427 -500 375 -640 480 -480 640 -426 640 -500 476 -427 640 -640 446 -640 427 -640 424 -532 640 -640 572 -640 320 -640 424 -500 375 -640 427 -500 395 -480 640 -333 500 -640 360 -640 319 -640 480 -640 427 -640 425 -640 480 -640 428 -640 480 -427 640 -480 640 -640 480 -640 426 -640 427 -500 333 -375 500 -640 480 -640 457 -640 480 -640 425 -612 612 -640 480 -640 427 -640 480 -640 426 -640 640 -640 451 -500 500 -427 640 -640 478 -640 480 -640 480 -640 427 -640 427 -640 481 -640 427 -427 640 -480 640 -640 480 -513 640 -640 408 -640 426 -379 640 -640 440 -640 425 -424 640 -640 427 -480 640 -640 359 -640 427 -427 640 -512 640 -461 640 -478 640 -640 480 -427 640 -640 427 -493 640 -500 347 -500 403 -640 525 -640 478 -640 371 -640 406 -640 480 -333 500 -640 480 -500 334 -531 640 -640 480 -500 375 -640 480 -640 480 -479 640 -500 375 -426 640 -500 375 -640 404 -640 425 -640 427 -640 480 -500 333 -640 480 -640 480 -500 375 -480 640 -640 425 -480 640 -640 457 -640 480 -640 640 -640 414 -500 375 -480 640 -426 640 -640 427 -482 640 -333 500 -500 362 -640 427 -640 427 -640 478 -640 480 -640 424 -640 480 -480 640 -640 480 -612 612 -480 640 -375 500 -640 480 -480 640 -400 515 -640 524 -640 480 -500 426 -640 426 -426 640 -640 428 -640 427 -640 427 -612 612 -640 427 -640 426 -640 426 -480 640 -427 640 -640 427 -640 626 -500 375 -640 427 -459 640 -500 413 -640 426 -640 480 -640 278 -640 480 -640 480 -640 426 -640 480 -480 640 -640 383 -640 480 -640 480 -481 640 -480 640 -640 480 -619 640 -640 483 -640 480 -640 368 -500 375 -459 640 -480 640 -427 640 -426 640 -640 480 -500 375 -640 424 -375 500 -640 427 -427 640 -427 640 -640 480 -640 427 -640 426 -333 640 -360 640 -640 383 -427 640 -640 390 -640 640 -500 378 -426 640 -640 322 -334 640 -375 500 -640 480 -426 640 -640 426 -500 375 -426 640 -612 612 -458 640 -480 640 -427 640 -640 419 -500 375 -427 640 -345 500 -500 333 -640 480 -640 480 -640 480 -640 550 -640 480 -480 640 -427 640 -640 480 -480 640 -500 375 -612 612 -375 500 -640 480 -640 427 -640 360 -480 640 -600 550 -639 640 -425 640 -640 480 -612 612 -576 640 -500 375 -512 640 -640 360 -640 480 -640 426 -640 426 -612 612 -640 480 -640 427 -427 640 -640 451 -640 480 -640 480 -640 415 -426 640 -640 426 -640 448 -640 480 -500 375 -640 480 -480 640 -640 427 -640 407 -640 528 -640 519 -640 431 -478 640 -640 427 -640 427 -500 500 -640 427 -640 427 -640 413 -640 478 -500 375 -640 424 -640 480 -640 388 -640 480 -500 375 -640 428 -426 640 -473 640 -480 640 -640 347 -640 478 -640 480 -500 379 -640 426 -640 437 -640 427 -640 427 -640 480 -480 640 -426 640 -425 500 -500 333 -500 500 -640 480 -640 428 -640 480 -640 396 -500 480 -640 427 -640 418 -640 480 -640 426 -333 500 -640 426 -640 480 -640 480 -640 424 -472 640 -425 640 -640 401 -640 624 -612 612 -640 426 -640 428 -640 425 -640 480 -500 374 -640 480 -480 640 -427 640 -640 301 -640 480 -640 480 -480 640 -480 640 -500 375 -640 480 -640 480 -640 427 -640 512 -640 373 -480 640 -500 333 -480 640 -640 427 -500 372 -640 480 -640 480 -375 500 -640 360 -640 428 -612 612 -640 480 -480 640 -640 427 -427 640 -500 375 -640 360 -480 640 -640 480 -480 640 -640 480 -480 640 -640 425 -480 640 -640 470 -491 640 -640 426 -612 612 -640 480 -640 428 -480 320 -640 427 -640 480 -640 480 -640 427 -640 480 -640 362 -640 415 -334 500 -640 640 -640 554 -640 427 -640 427 -640 480 -640 426 -640 365 -640 574 -465 640 -424 640 -640 480 -640 427 -425 640 -640 428 -426 640 -640 480 -640 480 -478 640 -640 480 -640 425 -480 640 -640 428 -480 640 -640 427 -480 640 -640 428 -640 426 -345 415 -640 427 -640 480 -640 419 -640 478 -456 640 -640 427 -640 193 -640 360 -500 375 -640 480 -640 458 -480 640 -612 612 -640 478 -640 480 -480 640 -640 426 -640 427 -480 640 -640 481 -640 427 -375 500 -500 375 -640 427 -640 425 -640 360 -500 343 -640 427 -640 480 -640 391 -634 640 -640 425 -500 429 -333 500 -426 640 -640 480 -640 428 -640 547 -375 500 -432 354 -640 480 -640 480 -500 334 -640 480 -375 500 -640 480 -640 427 -360 640 -640 480 -640 426 -640 480 -640 427 -640 483 -640 480 -640 480 -640 425 -450 303 -640 480 -640 334 -640 425 -401 640 -640 427 -500 375 -640 424 -640 338 -640 561 -266 640 -640 428 -640 459 -375 500 -400 300 -640 480 -640 480 -640 427 -480 640 -375 500 -640 480 -640 480 -640 480 -480 640 -424 640 -480 640 -426 640 -640 429 -640 480 -424 640 -640 480 -640 480 -640 426 -640 307 -500 375 -640 390 -640 480 -465 640 -640 480 -640 480 -480 640 -640 424 -480 640 -640 360 -640 480 -640 427 -640 439 -640 427 -640 453 -640 480 -480 640 -640 433 -640 480 -640 478 -640 480 -500 436 -426 640 -640 360 -612 612 -640 480 -612 612 -640 425 -430 640 -640 480 -480 640 -500 500 -640 263 -640 480 -640 427 -640 478 -640 418 -640 378 -640 427 -640 512 -512 640 -640 505 -481 640 -640 426 -480 640 -500 375 -640 426 -640 478 -640 425 -370 500 -500 333 -640 427 -383 640 -640 427 -640 480 -500 375 -500 375 -478 640 -500 379 -427 640 -640 480 -480 640 -438 640 -640 480 -375 500 -431 640 -500 281 -500 311 -500 400 -640 427 -640 427 -640 480 -640 426 -640 480 -427 640 -478 640 -480 640 -640 428 -640 478 -640 480 -640 480 -640 483 -428 500 -640 428 -640 427 -640 426 -640 425 -640 427 -500 375 -640 480 -640 480 -640 640 -640 457 -640 428 -640 480 -480 640 -640 480 -640 499 -480 640 -640 480 -640 359 -500 333 -480 640 -427 640 -375 500 -640 480 -480 640 -640 480 -480 640 -640 480 -640 480 -640 360 -640 360 -640 480 -640 438 -426 640 -480 640 -640 480 -375 500 -640 480 -640 480 -500 333 -640 640 -479 640 -640 360 -640 427 -640 245 -640 480 -612 612 -640 601 -640 454 -640 427 -640 480 -448 336 -640 480 -640 604 -640 480 -500 333 -640 480 -640 427 -640 480 -500 333 -640 480 -480 640 -640 424 -640 424 -640 480 -500 332 -480 640 -640 427 -480 640 -640 403 -609 640 -640 480 -640 480 -412 500 -640 425 -640 428 -640 427 -500 336 -640 474 -640 480 -640 428 -500 375 -640 480 -640 480 -640 366 -480 640 -640 481 -640 480 -375 500 -640 480 -480 640 -640 424 -640 425 -344 500 -500 375 -640 480 -640 487 -640 389 -640 427 -500 375 -640 426 -640 426 -500 375 -640 447 -504 640 -426 640 -640 480 -640 480 -480 640 -640 428 -640 427 -640 427 -640 480 -640 425 -640 427 -640 429 -357 500 -640 480 -640 480 -447 640 -500 357 -479 640 -640 483 -480 640 -640 425 -426 640 -640 426 -640 428 -427 640 -639 640 -640 427 -640 355 -640 480 -640 414 -360 640 -640 427 -640 480 -424 640 -640 413 -500 338 -640 423 -480 640 -338 500 -640 439 -640 425 -640 428 -265 500 -640 427 -640 595 -640 480 -640 400 -639 640 -640 640 -500 400 -500 375 -640 434 -640 480 -480 640 -640 480 -640 400 -500 375 -640 427 -640 430 -640 480 -640 480 -640 640 -640 480 -640 590 -640 480 -640 426 -500 326 -640 427 -640 480 -600 400 -640 392 -640 480 -640 480 -640 360 -640 480 -640 425 -612 612 -240 320 -480 640 -480 640 -500 375 -640 427 -640 480 -375 500 -640 427 -640 429 -500 375 -428 640 -500 487 -640 480 -640 427 -640 533 -640 640 -640 480 -500 326 -640 480 -640 427 -640 480 -426 640 -640 480 -640 480 -480 640 -640 491 -640 427 -500 333 -500 375 -472 640 -506 640 -640 425 -500 375 -640 426 -432 640 -640 426 -333 500 -500 357 -640 461 -375 500 -640 438 -640 427 -500 332 -640 375 -640 480 -500 333 -640 480 -612 612 -640 427 -640 428 -640 480 -640 423 -640 480 -640 426 -640 426 -640 548 -640 480 -640 427 -427 640 -640 427 -640 428 -640 478 -640 480 -457 640 -640 459 -640 480 -640 435 -400 267 -640 480 -611 640 -640 480 -640 427 -640 480 -640 480 -640 429 -640 427 -640 480 -500 333 -480 640 -480 640 -427 640 -427 640 -480 640 -640 384 -640 427 -426 640 -640 360 -640 573 -578 640 -640 480 -640 426 -480 640 -640 429 -640 480 -640 426 -480 640 -334 500 -640 427 -640 347 -640 481 -640 427 -640 480 -427 640 -640 480 -640 480 -640 480 -640 480 -500 400 -640 480 -640 426 -640 425 -425 640 -427 640 -640 480 -425 640 -480 640 -640 484 -480 640 -640 426 -640 427 -640 425 -640 640 -640 480 -426 640 -640 429 -480 640 -640 427 -480 640 -640 427 -640 480 -426 640 -640 480 -640 426 -640 425 -426 640 -640 470 -640 480 -640 360 -640 480 -640 480 -640 480 -500 281 -640 480 -640 427 -640 427 -640 427 -640 423 -640 425 -640 427 -500 333 -480 640 -457 640 -640 427 -640 480 -425 640 -600 448 -640 425 -640 480 -640 480 -480 640 -640 425 -640 426 -640 427 -640 361 -640 480 -500 375 -640 487 -480 640 -500 375 -640 426 -500 375 -500 396 -500 332 -375 500 -640 400 -640 480 -480 640 -640 424 -640 480 -427 640 -368 640 -640 425 -640 428 -612 612 -480 640 -640 282 -640 428 -500 342 -640 440 -500 334 -640 426 -500 333 -640 427 -640 428 -500 333 -640 640 -500 374 -640 426 -640 425 -429 640 -640 433 -480 640 -640 490 -500 400 -640 480 -640 360 -640 480 -612 612 -640 393 -640 480 -480 640 -480 640 -640 426 -428 640 -640 456 -640 470 -420 266 -640 426 -480 640 -640 427 -640 640 -640 426 -506 640 -640 478 -640 425 -640 480 -640 480 -640 480 -640 512 -500 475 -612 612 -640 640 -480 640 -640 427 -640 427 -640 460 -613 640 -480 640 -480 640 -640 314 -640 480 -480 640 -640 424 -640 427 -640 480 -640 480 -458 640 -640 427 -640 443 -640 428 -640 427 -424 640 -640 427 -426 640 -640 457 -427 640 -640 427 -640 480 -480 640 -640 480 -335 500 -480 640 -640 425 -640 360 -429 640 -640 425 -640 427 -640 394 -491 640 -640 480 -640 480 -429 640 -640 484 -640 458 -333 500 -640 480 -480 640 -388 640 -640 425 -640 480 -640 427 -640 427 -640 480 -500 333 -640 428 -640 480 -640 479 -640 513 -425 640 -500 334 -375 500 -427 640 -480 640 -640 549 -640 480 -640 480 -640 428 -358 500 -640 428 -480 640 -480 640 -640 403 -640 361 -640 424 -640 359 -408 408 -640 374 -283 500 -640 427 -640 321 -640 424 -640 480 -500 357 -640 480 -640 426 -427 640 -640 480 -640 427 -640 416 -640 426 -640 480 -426 640 -640 480 -640 480 -375 500 -640 284 -640 424 -640 480 -640 480 -640 480 -640 366 -640 526 -480 640 -480 640 -460 640 -640 480 -640 302 -640 428 -640 428 -640 359 -612 612 -500 281 -640 427 -640 427 -640 480 -640 480 -640 427 -640 427 -478 640 -500 333 -640 360 -640 429 -640 480 -366 640 -424 640 -640 359 -500 338 -640 427 -640 427 -640 354 -640 480 -640 424 -478 640 -640 360 -427 640 -427 640 -428 640 -427 640 -640 423 -640 388 -431 640 -491 640 -640 426 -640 428 -640 427 -640 480 -640 360 -640 428 -427 640 -333 500 -640 480 -431 640 -640 426 -640 426 -640 427 -640 423 -425 640 -480 640 -640 480 -396 640 -640 480 -640 427 -640 504 -640 426 -480 640 -375 500 -427 640 -428 640 -640 480 -640 360 -640 424 -640 428 -479 640 -640 360 -426 640 -427 640 -640 512 -640 426 -640 520 -480 640 -500 333 -500 352 -640 473 -426 640 -640 427 -640 427 -640 480 -500 375 -640 427 -640 412 -640 480 -500 333 -640 404 -640 426 -500 375 -509 640 -640 480 -640 371 -500 375 -640 480 -640 436 -640 298 -640 480 -640 480 -640 427 -640 425 -640 428 -640 480 -640 426 -640 427 -640 539 -640 480 -427 640 -425 640 -640 360 -640 480 -640 480 -640 427 -612 612 -640 427 -480 640 -640 349 -375 500 -640 480 -640 441 -379 640 -500 375 -640 480 -640 426 -612 612 -640 427 -480 640 -613 449 -640 640 -640 549 -640 424 -640 480 -500 332 -500 333 -640 352 -640 427 -480 640 -640 480 -640 480 -640 480 -612 612 -426 640 -640 353 -426 640 -640 428 -640 488 -427 640 -640 480 -385 640 -375 500 -424 640 -500 333 -640 476 -640 479 -386 640 -640 480 -486 500 -640 360 -640 427 -640 480 -640 478 -640 480 -640 480 -640 480 -640 480 -500 399 -500 375 -640 427 -640 426 -640 501 -374 500 -640 480 -640 427 -640 427 -457 640 -457 640 -427 640 -640 427 -640 427 -500 375 -427 640 -640 480 -640 416 -640 464 -500 375 -640 480 -640 480 -640 480 -640 480 -640 423 -480 640 -640 427 -640 360 -640 360 -428 640 -503 640 -640 428 -640 427 -640 427 -500 333 -426 640 -429 640 -427 640 -640 400 -500 332 -480 640 -500 266 -500 357 -360 640 -640 427 -427 640 -640 480 -640 425 -612 612 -424 640 -640 427 -427 640 -640 426 -640 640 -640 480 -640 428 -500 375 -612 612 -500 333 -640 426 -640 480 -500 333 -640 428 -640 428 -480 640 -640 512 -640 365 -375 500 -640 427 -640 229 -640 480 -640 480 -640 480 -640 440 -640 428 -640 427 -480 640 -428 640 -500 375 -640 422 -640 427 -480 640 -480 640 -640 427 -500 375 -640 427 -587 640 -640 427 -500 400 -640 492 -500 375 -640 360 -427 640 -480 640 -640 478 -640 427 -480 640 -640 480 -640 425 -640 480 -640 427 -640 427 -640 427 -640 383 -640 364 -640 480 -640 349 -480 640 -640 426 -640 480 -335 500 -640 480 -640 480 -640 427 -640 480 -640 480 -478 640 -640 426 -640 426 -640 427 -640 480 -640 426 -427 640 -426 640 -640 480 -640 436 -426 640 -427 640 -425 640 -640 427 -640 406 -640 480 -612 612 -640 426 -425 640 -480 640 -480 640 -640 493 -375 500 -640 422 -640 426 -361 640 -640 427 -640 427 -640 504 -640 428 -640 480 -640 510 -640 480 -640 514 -640 424 -640 480 -480 640 -640 427 -640 480 -640 426 -640 480 -640 427 -640 432 -427 640 -640 439 -640 512 -640 480 -488 364 -427 640 -640 349 -375 500 -640 426 -640 427 -480 640 -500 332 -640 480 -640 424 -640 480 -333 500 -500 351 -640 480 -640 480 -640 480 -640 428 -640 428 -427 640 -640 427 -640 480 -426 640 -640 425 -640 512 -640 480 -478 640 -640 480 -640 501 -640 427 -460 500 -500 322 -640 480 -640 480 -480 640 -640 480 -500 333 -640 424 -640 424 -612 612 -640 426 -640 480 -640 480 -640 500 -427 640 -640 427 -500 375 -640 480 -500 354 -400 302 -480 640 -640 427 -512 640 -387 640 -640 457 -426 640 -640 427 -640 480 -640 427 -480 640 -640 427 -480 640 -640 480 -640 426 -640 640 -426 640 -425 640 -640 436 -640 358 -640 426 -640 480 -612 612 -480 640 -640 480 -640 355 -500 333 -573 640 -640 360 -640 426 -640 480 -640 480 -640 426 -640 480 -426 640 -640 480 -640 427 -640 427 -640 427 -640 426 -612 612 -480 640 -640 425 -640 480 -500 355 -640 380 -640 427 -353 500 -640 427 -427 640 -640 426 -640 480 -640 427 -640 418 -478 640 -640 425 -500 399 -640 480 -640 427 -600 402 -500 330 -640 425 -640 428 -640 427 -480 640 -509 640 -640 429 -458 640 -480 640 -640 425 -640 427 -640 427 -640 425 -640 427 -612 612 -500 381 -640 426 -427 640 -640 480 -640 478 -640 480 -640 480 -640 480 -640 480 -427 640 -480 640 -640 640 -640 361 -480 640 -640 480 -640 427 -640 408 -640 480 -640 480 -480 640 -480 640 -640 572 -640 440 -640 480 -500 346 -640 636 -500 334 -640 498 -640 426 -424 640 -640 480 -426 640 -500 333 -480 640 -353 480 -500 375 -640 373 -640 426 -480 640 -640 424 -640 480 -640 425 -500 335 -500 333 -640 478 -640 451 -480 640 -640 427 -383 640 -474 640 -640 360 -640 427 -426 640 -640 427 -500 431 -640 427 -640 480 -500 375 -640 480 -640 480 -640 480 -640 480 -640 480 -640 426 -640 480 -640 425 -518 640 -640 424 -640 430 -480 640 -640 425 -500 375 -375 500 -500 375 -480 320 -640 426 -640 480 -375 500 -500 375 -478 640 -612 612 -640 437 -640 425 -640 424 -640 480 -640 574 -640 427 -500 333 -399 640 -640 480 -427 640 -640 462 -480 640 -640 426 -640 429 -640 360 -640 458 -640 427 -640 603 -640 480 -640 384 -427 640 -375 500 -513 640 -640 496 -640 478 -640 480 -640 480 -500 375 -640 426 -480 640 -640 480 -640 426 -640 427 -640 478 -640 640 -640 427 -640 608 -640 480 -639 640 -427 640 -640 343 -640 479 -640 640 -427 640 -640 398 -480 640 -640 432 -426 640 -500 375 -480 640 -640 480 -640 480 -480 640 -640 480 -500 375 -640 425 -640 480 -500 335 -500 375 -591 640 -640 427 -640 428 -427 640 -426 640 -640 425 -600 420 -423 640 -640 478 -500 404 -640 426 -552 346 -640 431 -640 229 -640 427 -640 480 -640 480 -500 375 -500 316 -439 500 -480 640 -640 427 -427 640 -480 640 -640 424 -640 480 -640 480 -640 480 -429 640 -640 427 -640 426 -640 480 -426 640 -640 480 -640 438 -640 427 -640 480 -640 429 -425 640 -500 375 -500 375 -640 480 -480 640 -640 424 -500 375 -640 480 -426 640 -640 451 -640 480 -640 480 -640 575 -480 640 -640 451 -640 425 -640 401 -640 457 -424 640 -640 480 -332 500 -323 640 -640 480 -640 480 -480 640 -640 289 -640 480 -640 426 -640 457 -640 480 -640 426 -640 480 -640 444 -640 480 -480 640 -427 640 -640 480 -640 480 -640 471 -480 640 -640 427 -525 525 -375 500 -640 348 -500 334 -640 480 -500 375 -425 640 -640 425 -640 427 -640 480 -640 427 -640 428 -500 391 -640 480 -640 427 -640 427 -640 480 -640 359 -640 640 -500 333 -640 426 -640 442 -612 612 -640 427 -457 640 -640 427 -640 512 -640 614 -640 361 -640 480 -500 375 -640 428 -640 480 -500 391 -640 425 -500 375 -640 428 -640 425 -612 612 -640 480 -640 628 -640 528 -640 425 -640 480 -640 480 -640 478 -480 640 -427 640 -427 640 -640 451 -427 640 -640 480 -640 427 -640 480 -640 480 -640 427 -640 424 -640 480 -640 455 -640 480 -640 428 -336 500 -640 480 -480 640 -500 383 -459 640 -640 427 -640 456 -375 500 -640 480 -500 375 -500 281 -640 425 -480 640 -640 424 -640 361 -507 640 -334 500 -640 480 -500 400 -640 427 -640 426 -640 426 -640 319 -480 640 -420 640 -640 427 -480 640 -640 427 -427 640 -500 375 -640 640 -640 480 -320 480 -640 361 -500 400 -640 427 -500 376 -429 640 -500 381 -640 427 -640 426 -640 563 -640 480 -640 480 -640 429 -640 512 -640 480 -500 375 -640 480 -640 426 -424 640 -480 640 -544 640 -612 612 -640 480 -640 427 -500 333 -640 427 -640 480 -500 357 -339 500 -640 425 -640 406 -640 480 -500 370 -640 480 -640 484 -640 316 -640 480 -640 426 -480 640 -425 640 -640 427 -480 640 -640 480 -640 425 -480 640 -640 321 -640 436 -480 640 -640 480 -640 426 -640 480 -640 507 -640 480 -640 469 -500 333 -640 426 -640 480 -640 478 -640 426 -640 427 -640 425 -640 453 -640 427 -427 640 -480 360 -640 427 -500 332 -640 427 -375 500 -640 480 -500 334 -600 402 -640 480 -500 375 -480 640 -320 240 -640 427 -640 480 -640 480 -480 640 -640 427 -640 480 -640 427 -500 375 -640 427 -640 480 -477 640 -612 612 -640 481 -640 488 -480 640 -640 427 -640 480 -500 375 -640 425 -640 480 -640 455 -640 480 -500 332 -640 480 -500 375 -640 427 -640 427 -640 480 -640 480 -640 282 -335 500 -500 375 -640 427 -640 480 -640 480 -640 480 -640 480 -427 640 -333 500 -640 426 -640 351 -640 425 -478 640 -400 346 -500 393 -500 375 -640 511 -500 375 -480 640 -640 427 -640 426 -640 426 -640 480 -427 640 -640 427 -640 427 -640 640 -640 480 -640 427 -640 427 -640 340 -428 640 -640 233 -640 524 -385 289 -640 427 -640 640 -640 435 -360 450 -338 450 -640 351 -457 640 -500 375 -640 427 -640 427 -640 363 -640 426 -640 480 -640 444 -640 638 -640 383 -385 308 -375 500 -426 640 -640 550 -480 640 -448 336 -640 426 -640 427 -480 640 -640 420 -640 640 -640 523 -640 383 -500 377 -640 427 -375 500 -640 232 -427 640 -478 640 -640 424 -481 640 -640 427 -640 480 -500 332 -640 426 -640 480 -427 640 -500 337 -640 476 -640 480 -640 480 -428 640 -640 480 -500 375 -640 313 -640 426 -640 425 -640 480 -640 426 -375 500 -426 640 -640 480 -500 333 -500 375 -612 612 -500 227 -640 478 -640 428 -640 427 -640 425 -428 640 -500 375 -640 427 -500 333 -640 480 -480 640 -480 640 -640 425 -640 428 -640 480 -640 480 -480 640 -640 428 -640 428 -640 480 -640 427 -480 640 -640 480 -640 427 -496 640 -480 640 -640 583 -480 640 -640 332 -427 640 -480 640 -640 480 -640 426 -473 640 -299 300 -640 360 -640 427 -640 480 -640 466 -640 480 -426 640 -500 333 -640 480 -457 640 -480 640 -640 480 -480 640 -640 480 -640 480 -640 479 -640 640 -640 480 -640 457 -640 426 -640 426 -640 361 -480 640 -640 640 -640 424 -640 384 -500 410 -640 426 -500 375 -500 375 -640 480 -426 640 -500 334 -640 480 -500 371 -640 428 -640 427 -640 427 -640 480 -640 480 -640 480 -640 425 -640 480 -500 375 -640 480 -561 640 -500 333 -640 480 -427 640 -640 427 -640 427 -640 426 -640 480 -500 375 -640 480 -640 427 -639 640 -375 500 -424 640 -640 514 -375 500 -640 427 -640 479 -335 500 -640 472 -500 375 -500 375 -427 640 -500 375 -612 612 -640 478 -418 640 -640 318 -640 294 -640 462 -480 640 -500 375 -640 461 -640 393 -640 480 -640 360 -375 500 -480 640 -640 480 -640 427 -640 455 -640 325 -640 480 -640 480 -430 640 -480 640 -500 375 -640 342 -640 480 -640 426 -458 640 -500 375 -413 640 -640 427 -640 393 -640 409 -640 414 -640 480 -640 426 -640 425 -640 480 -640 480 -640 494 -640 427 -480 640 -640 481 -375 500 -640 427 -640 427 -427 640 -500 333 -640 484 -640 480 -612 612 -480 640 -480 640 -640 426 -640 427 -640 480 -640 368 -407 640 -480 640 -334 500 -500 375 -375 500 -640 428 -424 640 -640 425 -640 427 -640 425 -480 640 -480 640 -640 424 -480 640 -640 426 -386 640 -640 480 -640 640 -640 640 -480 640 -640 427 -640 428 -500 332 -640 478 -640 427 -375 500 -640 480 -640 480 -500 375 -640 480 -640 470 -480 640 -480 640 -640 427 -440 330 -640 480 -640 366 -640 359 -500 340 -640 480 -640 479 -500 333 -430 430 -553 371 -500 375 -640 513 -640 426 -640 511 -375 500 -429 640 -640 427 -274 500 -640 424 -640 480 -640 428 -500 375 -640 458 -640 480 -640 221 -428 640 -480 640 -640 425 -500 375 -425 640 -267 400 -640 427 -640 427 -640 424 -480 640 -640 480 -640 480 -480 640 -640 428 -426 640 -500 375 -640 480 -480 640 -500 334 -640 454 -584 640 -480 384 -640 427 -640 480 -480 640 -640 425 -480 640 -640 480 -640 612 -500 333 -333 500 -640 480 -640 427 -640 480 -480 640 -640 425 -640 480 -640 427 -640 480 -640 436 -640 426 -640 480 -600 402 -640 451 -427 640 -640 422 -640 427 -640 424 -640 480 -640 640 -640 480 -512 640 -640 480 -500 334 -480 640 -640 427 -640 427 -500 375 -480 640 -640 480 -640 512 -640 320 -640 427 -640 427 -612 612 -640 480 -375 500 -427 640 -429 640 -428 640 -640 480 -640 427 -480 640 -640 395 -640 454 -478 640 -640 431 -640 480 -428 640 -640 338 -500 333 -426 640 -640 427 -426 640 -640 427 -418 640 -640 425 -480 640 -640 425 -640 426 -640 360 -120 120 -500 335 -640 426 -640 426 -640 480 -638 640 -640 427 -480 640 -480 640 -500 375 -427 640 -640 503 -640 428 -640 308 -640 480 -640 480 -640 480 -480 640 -533 640 -640 481 -500 333 -500 375 -640 426 -640 425 -640 467 -640 480 -640 426 -427 640 -640 428 -640 480 -640 480 -640 480 -640 363 -375 500 -427 640 -640 425 -426 640 -480 640 -426 640 -640 480 -640 430 -640 300 -640 427 -375 500 -640 428 -375 500 -455 310 -640 427 -500 459 -640 481 -478 640 -640 480 -480 640 -640 480 -500 375 -640 480 -640 426 -640 480 -640 427 -640 480 -640 457 -425 640 -640 480 -640 406 -640 480 -480 640 -500 375 -500 388 -640 480 -448 640 -640 480 -434 640 -640 426 -500 333 -500 326 -640 480 -640 480 -640 480 -640 425 -640 480 -640 427 -640 426 -640 361 -640 480 -640 519 -500 375 -640 480 -500 375 -382 500 -640 480 -640 480 -640 428 -640 480 -612 612 -333 500 -640 512 -612 612 -612 612 -500 375 -640 480 -640 480 -640 349 -413 500 -640 480 -640 425 -640 390 -640 426 -640 359 -335 500 -640 640 -426 640 -640 468 -640 513 -640 465 -640 480 -500 375 -456 640 -480 640 -640 480 -640 480 -426 640 -500 250 -503 640 -500 375 -640 311 -640 460 -480 640 -640 480 -512 640 -480 640 -427 640 -534 640 -480 640 -480 640 -640 425 -480 640 -617 640 -640 427 -640 480 -478 640 -640 480 -640 305 -500 375 -640 425 -640 428 -640 480 -500 281 -480 640 -512 640 -480 360 -640 466 -480 640 -612 612 -640 480 -640 480 -333 500 -640 427 -640 480 -427 640 -640 480 -640 640 -640 480 -640 427 -640 474 -375 500 -640 480 -600 402 -640 480 -640 480 -640 427 -640 480 -500 375 -640 480 -500 375 -635 514 -448 640 -640 435 -428 640 -426 640 -612 612 -500 411 -640 480 -381 500 -640 480 -427 640 -480 640 -640 429 -640 480 -375 500 -640 480 -640 428 -480 640 -480 640 -640 512 -425 640 -478 640 -500 375 -500 375 -403 403 -427 640 -640 360 -480 640 -500 333 -640 360 -640 480 -640 426 -375 500 -500 348 -640 423 -375 500 -640 307 -428 640 -640 480 -640 480 -640 480 -640 418 -375 500 -640 427 -428 640 -640 427 -640 361 -500 375 -640 427 -640 480 -640 427 -425 640 -640 292 -640 360 -640 480 -500 375 -640 480 -500 485 -640 424 -640 480 -640 480 -640 428 -480 640 -640 436 -640 480 -428 640 -640 424 -457 640 -500 332 -640 480 -429 640 -640 429 -428 640 -640 429 -640 426 -640 640 -640 426 -480 640 -640 467 -640 427 -640 480 -500 333 -640 427 -500 338 -640 480 -326 500 -640 465 -640 480 -640 480 -640 423 -640 428 -500 333 -457 640 -375 500 -640 427 -640 425 -640 480 -640 427 -640 428 -500 462 -640 347 -640 400 -480 640 -640 427 -640 427 -640 480 -375 500 -640 475 -403 303 -428 640 -640 480 -640 293 -640 427 -427 640 -640 450 -640 480 -480 640 -640 480 -640 427 -612 612 -640 360 -500 357 -480 640 -640 480 -640 443 -481 640 -640 480 -640 428 -427 640 -640 427 -612 612 -480 640 -425 640 -333 500 -640 427 -640 480 -640 427 -640 424 -640 427 -640 480 -500 400 -500 332 -640 480 -500 375 -500 400 -500 375 -427 640 -443 640 -427 640 -480 640 -640 427 -640 478 -640 480 -640 480 -640 427 -640 425 -640 425 -640 480 -640 408 -480 640 -640 480 -640 480 -612 612 -500 333 -640 420 -480 640 -640 355 -640 480 -640 424 -500 375 -640 480 -640 320 -640 427 -640 480 -427 640 -320 240 -500 333 -389 640 -640 457 -480 640 -427 640 -500 375 -428 640 -640 427 -427 640 -640 425 -640 427 -640 427 -640 408 -640 512 -640 426 -640 426 -640 471 -640 428 -500 375 -640 429 -640 480 -640 480 -500 375 -640 489 -640 425 -640 427 -640 365 -640 480 -479 640 -500 375 -640 427 -640 427 -640 424 -640 480 -640 480 -640 640 -640 460 -640 640 -500 375 -480 640 -426 640 -500 375 -640 524 -640 480 -484 640 -339 329 -640 424 -640 478 -640 432 -640 427 -500 375 -640 426 -473 640 -640 624 -429 640 -480 640 -640 400 -472 640 -506 640 -480 640 -300 500 -375 500 -640 480 -612 612 -640 426 -426 640 -640 480 -640 480 -640 480 -640 427 -379 640 -332 500 -500 333 -640 480 -640 359 -640 333 -640 428 -500 333 -640 480 -640 426 -640 427 -640 368 -640 640 -500 332 -640 428 -640 480 -640 480 -480 640 -640 640 -640 505 -640 400 -480 640 -640 359 -640 480 -640 427 -640 640 -640 427 -640 480 -447 640 -640 480 -500 375 -427 640 -427 640 -426 640 -640 480 -640 360 -500 334 -612 612 -640 480 -640 427 -640 493 -390 500 -427 640 -640 425 -500 303 -640 480 -612 612 -429 640 -640 466 -427 640 -640 480 -640 480 -640 457 -640 427 -617 640 -640 429 -639 640 -640 427 -640 486 -640 271 -480 640 -500 375 -640 427 -480 640 -640 425 -427 640 -640 427 -640 479 -512 640 -434 640 -640 480 -640 480 -478 640 -640 427 -480 640 -640 431 -640 480 -640 427 -612 612 -427 640 -640 427 -640 428 -500 375 -500 375 -640 427 -640 480 -640 427 -500 344 -640 480 -640 480 -640 360 -461 640 -640 428 -427 640 -640 480 -640 366 -375 500 -499 500 -640 425 -640 427 -640 427 -640 425 -500 384 -640 427 -640 480 -640 640 -480 640 -484 640 -640 480 -640 424 -640 427 -426 640 -427 640 -640 424 -640 480 -640 480 -640 480 -613 640 -640 493 -640 427 -480 640 -480 640 -640 426 -640 425 -500 375 -640 480 -500 375 -640 480 -640 478 -480 640 -640 480 -640 480 -480 640 -480 640 -640 480 -640 427 -640 480 -640 458 -640 480 -640 480 -500 333 -640 425 -640 480 -640 427 -500 375 -480 640 -585 640 -480 640 -500 375 -480 640 -427 640 -500 375 -640 640 -500 375 -640 426 -500 375 -640 480 -640 329 -640 427 -427 640 -640 480 -640 286 -640 427 -640 593 -441 640 -640 640 -640 480 -500 367 -480 640 -417 640 -500 375 -640 480 -426 640 -640 454 -427 640 -586 640 -640 480 -427 640 -640 384 -640 427 -640 480 -427 640 -640 450 -640 480 -539 640 -640 427 -429 640 -500 333 -640 503 -640 427 -480 640 -500 333 -394 500 -640 427 -424 640 -640 480 -640 480 -640 426 -640 425 -500 336 -480 640 -612 612 -429 640 -640 478 -640 511 -500 333 -640 427 -640 480 -480 640 -375 500 -640 443 -640 468 -640 427 -480 640 -544 640 -640 424 -640 480 -500 344 -480 640 -640 428 -640 480 -611 640 -640 434 -640 360 -640 471 -640 343 -640 426 -640 497 -640 480 -427 640 -640 480 -640 477 -640 480 -640 480 -640 424 -375 500 -640 427 -640 480 -480 640 -640 424 -640 480 -500 375 -500 334 -640 425 -640 399 -640 425 -640 416 -640 360 -640 480 -640 480 -640 427 -640 480 -640 426 -500 333 -480 640 -640 309 -640 480 -500 379 -428 640 -640 480 -640 478 -640 326 -640 300 -640 480 -640 480 -640 480 -500 350 -640 448 -480 640 -427 640 -500 375 -640 480 -481 640 -640 427 -640 412 -640 427 -640 427 -640 480 -640 427 -500 375 -333 500 -640 427 -640 426 -640 360 -500 439 -640 426 -640 441 -640 427 -640 480 -427 640 -427 640 -500 333 -427 640 -640 480 -640 567 -640 360 -640 373 -640 425 -320 240 -640 480 -427 640 -640 480 -640 427 -480 640 -500 375 -640 424 -425 640 -640 478 -640 480 -427 640 -640 399 -558 640 -426 640 -640 427 -359 640 -640 480 -500 375 -640 480 -640 447 -640 512 -640 480 -640 480 -612 612 -612 612 -640 588 -640 480 -640 427 -640 439 -640 480 -426 640 -640 480 -480 640 -427 640 -640 424 -500 319 -375 500 -640 427 -640 427 -640 480 -640 478 -640 480 -480 640 -640 480 -640 428 -480 640 -640 426 -375 500 -640 478 -279 430 -512 640 -640 267 -640 640 -640 427 -640 457 -427 640 -640 317 -640 481 -480 640 -500 400 -640 480 -480 640 -640 426 -640 427 -375 500 -640 429 -640 480 -375 500 -640 427 -500 375 -640 428 -500 333 -479 640 -333 500 -640 427 -612 612 -640 480 -480 640 -640 640 -640 511 -640 480 -640 480 -640 428 -428 640 -640 480 -640 427 -640 479 -640 458 -640 480 -640 428 -640 427 -640 427 -500 500 -640 427 -640 481 -640 425 -640 638 -640 449 -426 640 -640 480 -640 427 -640 428 -500 281 -640 428 -640 428 -640 480 -500 375 -500 333 -640 427 -500 375 -500 375 -640 427 -640 428 -428 640 -640 427 -640 404 -480 640 -500 333 -640 429 -640 480 -480 640 -427 640 -640 480 -640 426 -454 640 -413 640 -500 375 -640 427 -640 480 -375 500 -640 480 -640 427 -640 480 -640 444 -640 480 -480 640 -640 236 -480 640 -640 428 -640 428 -640 363 -640 480 -640 427 -640 480 -640 480 -395 640 -640 337 -640 427 -640 427 -640 426 -640 414 -640 425 -640 368 -640 427 -500 315 -640 480 -555 640 -500 333 -640 427 -500 334 -485 640 -640 428 -640 480 -640 428 -640 428 -433 640 -640 426 -640 427 -510 640 -640 480 -480 640 -640 480 -640 480 -640 480 -640 470 -640 427 -640 480 -640 426 -640 522 -640 426 -640 426 -640 427 -425 640 -640 483 -640 427 -640 388 -426 640 -424 640 -360 640 -640 428 -640 480 -640 360 -640 515 -640 512 -640 452 -480 640 -427 640 -640 480 -640 480 -640 480 -640 480 -503 640 -480 640 -640 428 -500 331 -427 640 -640 427 -640 480 -640 428 -612 612 -640 480 -640 428 -426 640 -640 538 -500 337 -640 423 -640 480 -640 480 -427 640 -640 480 -500 375 -640 480 -640 480 -640 480 -640 480 -612 612 -640 406 -640 592 -500 330 -640 480 -640 480 -631 640 -500 375 -427 640 -640 480 -640 428 -640 430 -500 332 -640 480 -640 361 -460 640 -640 512 -425 640 -480 640 -640 480 -640 480 -640 480 -500 370 -640 425 -640 360 -640 263 -640 427 -640 427 -640 640 -640 427 -428 640 -640 427 -480 640 -612 612 -333 500 -640 427 -480 640 -640 640 -612 612 -640 480 -640 480 -640 428 -375 500 -640 456 -640 521 -640 427 -640 480 -427 640 -500 343 -640 640 -480 640 -640 480 -480 640 -640 480 -640 480 -481 640 -640 480 -427 369 -640 480 -426 640 -640 480 -500 375 -640 481 -480 640 -600 450 -500 375 -640 480 -640 427 -435 500 -640 427 -640 480 -423 640 -640 480 -640 427 -500 338 -480 640 -640 420 -500 333 -640 425 -640 427 -500 374 -640 480 -640 427 -500 333 -612 612 -640 480 -640 447 -240 320 -640 480 -640 480 -640 427 -640 427 -640 480 -427 640 -640 427 -500 375 -640 505 -640 457 -640 428 -640 480 -337 500 -640 542 -483 640 -640 360 -640 380 -640 428 -424 640 -427 640 -612 612 -500 471 -640 480 -512 640 -640 429 -640 428 -640 640 -640 426 -612 612 -640 427 -500 375 -640 447 -427 640 -640 640 -402 640 -640 480 -640 478 -500 375 -640 285 -506 640 -640 480 -640 425 -640 480 -640 563 -500 375 -640 427 -640 427 -480 640 -640 480 -480 640 -425 640 -500 375 -640 389 -640 480 -640 417 -640 270 -640 427 -500 333 -640 480 -640 480 -568 640 -640 427 -640 480 -640 360 -500 400 -640 425 -640 457 -426 640 -640 480 -640 428 -640 426 -640 426 -640 426 -640 427 -640 617 -500 333 -640 427 -640 426 -500 333 -640 427 -640 480 -640 480 -640 480 -640 426 -428 640 -640 480 -640 428 -640 403 -640 427 -459 500 -640 428 -500 334 -640 480 -640 468 -640 426 -640 477 -510 640 -375 500 -484 640 -640 552 -375 500 -500 375 -640 427 -640 480 -640 426 -480 640 -640 425 -640 437 -640 428 -640 480 -640 480 -640 480 -640 429 -640 427 -640 480 -333 500 -640 398 -612 612 -640 428 -640 427 -508 640 -429 640 -640 427 -500 333 -480 640 -640 480 -640 425 -640 427 -640 480 -427 640 -640 425 -480 640 -544 640 -640 640 -428 640 -640 427 -640 450 -640 425 -375 500 -640 482 -640 426 -519 640 -640 480 -500 375 -640 428 -500 375 -640 360 -640 427 -640 480 -500 375 -375 500 -640 425 -640 362 -401 500 -640 480 -640 427 -640 426 -640 480 -427 640 -640 512 -640 424 -640 480 -480 640 -427 640 -640 428 -640 428 -640 478 -480 640 -640 427 -640 480 -334 500 -640 480 -640 427 -640 241 -480 640 -640 427 -640 427 -640 480 -640 424 -640 548 -427 640 -425 640 -427 640 -640 426 -640 432 -427 640 -640 530 -283 424 -640 480 -640 480 -640 553 -640 442 -373 500 -482 640 -640 480 -640 480 -375 500 -640 360 -640 427 -640 480 -640 427 -640 480 -640 480 -640 427 -427 640 -369 500 -500 375 -640 480 -480 640 -424 640 -640 360 -640 427 -640 479 -480 640 -429 640 -640 480 -640 428 -640 480 -454 640 -428 640 -427 640 -480 640 -428 640 -640 360 -640 480 -426 640 -526 640 -480 640 -640 480 -640 480 -500 333 -640 428 -640 480 -640 640 -640 480 -640 480 -500 375 -640 480 -640 452 -640 473 -640 626 -481 640 -500 375 -640 480 -412 640 -640 427 -500 375 -640 478 -457 640 -640 427 -640 480 -640 427 -640 480 -640 403 -640 561 -500 375 -640 424 -640 480 -640 427 -427 640 -640 480 -425 640 -612 612 -640 427 -500 500 -640 480 -640 427 -640 480 -640 424 -640 480 -640 320 -640 480 -640 425 -375 500 -640 428 -640 427 -640 427 -640 478 -480 640 -640 480 -640 426 -640 427 -612 612 -640 480 -640 480 -500 333 -640 427 -427 640 -640 480 -427 640 -640 478 -640 428 -480 640 -640 425 -478 640 -640 480 -640 426 -480 640 -500 456 -640 428 -640 428 -640 426 -500 375 -640 428 -640 425 -640 360 -640 427 -426 640 -500 486 -640 480 -640 427 -513 640 -480 640 -476 640 -625 426 -640 360 -640 640 -640 427 -640 427 -457 640 -500 375 -640 425 -640 426 -612 612 -428 640 -500 333 -640 427 -470 640 -500 333 -341 500 -640 480 -640 480 -640 427 -640 480 -640 432 -640 426 -640 480 -427 640 -640 480 -640 480 -494 640 -640 424 -375 500 -640 427 -502 640 -434 640 -612 612 -500 375 -640 480 -640 480 -640 480 -375 500 -640 429 -640 480 -640 427 -500 375 -375 500 -640 486 -500 375 -640 427 -640 427 -640 400 -640 480 -424 640 -640 640 -478 640 -640 478 -500 311 -640 400 -640 480 -640 427 -612 612 -640 480 -640 429 -640 427 -480 640 -640 480 -500 375 -640 640 -640 479 -500 375 -640 480 -640 480 -640 427 -640 480 -640 436 -640 480 -640 480 -640 480 -640 480 -375 500 -332 500 -480 640 -640 427 -428 640 -640 480 -640 481 -640 480 -640 428 -640 277 -478 640 -640 396 -427 640 -640 480 -640 426 -640 480 -385 289 -484 640 -612 612 -640 480 -426 640 -640 425 -640 427 -640 427 -640 426 -640 427 -488 640 -346 500 -640 427 -640 480 -640 480 -335 500 -500 333 -640 428 -427 640 -426 640 -640 554 -427 640 -640 426 -640 427 -640 448 -640 480 -640 480 -640 480 -640 480 -640 480 -640 425 -640 480 -640 424 -480 640 -640 425 -480 640 -640 473 -427 640 -640 425 -480 640 -640 457 -640 428 -640 427 -480 640 -640 427 -640 461 -640 425 -500 374 -640 426 -490 640 -640 427 -480 640 -500 375 -640 427 -500 400 -640 480 -640 480 -640 511 -640 480 -640 480 -640 480 -640 427 -640 455 -640 480 -640 604 -640 425 -640 480 -640 427 -640 361 -480 640 -500 373 -640 480 -640 427 -612 612 -640 399 -640 640 -640 640 -480 640 -640 426 -640 427 -317 500 -500 375 -480 640 -640 480 -333 500 -640 480 -640 428 -640 480 -640 480 -640 360 -640 480 -640 488 -640 424 -480 640 -639 640 -640 429 -640 480 -286 409 -640 480 -640 430 -480 640 -604 640 -375 500 -640 425 -500 335 -500 375 -640 480 -640 480 -640 636 -500 191 -640 426 -640 640 -640 480 -640 427 -640 322 -640 425 -640 426 -478 640 -640 480 -500 375 -480 640 -640 427 -640 480 -612 612 -333 500 -640 428 -640 640 -640 425 -612 612 -640 360 -640 424 -640 480 -480 640 -640 400 -640 427 -500 333 -640 480 -500 375 -640 480 -640 475 -600 400 -640 426 -480 640 -480 640 -427 640 -640 427 -500 375 -427 640 -640 356 -500 333 -426 640 -640 480 -640 311 -640 480 -640 480 -640 427 -375 500 -640 360 -640 427 -640 480 -640 427 -640 480 -500 381 -333 500 -500 485 -640 480 -640 480 -640 428 -480 640 -640 427 -640 480 -640 480 -640 427 -446 640 -496 500 -500 375 -640 640 -640 427 -640 424 -640 480 -640 480 -640 473 -413 500 -640 442 -640 427 -500 332 -640 480 -640 513 -640 480 -640 554 -640 480 -640 464 -640 480 -640 427 -640 494 -612 612 -312 504 -640 480 -480 640 -640 396 -334 500 -640 480 -500 375 -640 427 -640 480 -375 500 -640 480 -640 454 -640 427 -640 444 -640 426 -375 500 -428 640 -500 375 -640 428 -293 448 -640 478 -424 640 -640 480 -640 431 -640 640 -640 424 -640 480 -425 640 -640 427 -640 424 -640 480 -500 375 -640 426 -640 480 -427 640 -500 287 -336 500 -640 426 -640 428 -640 480 -500 375 -640 425 -640 402 -640 480 -640 480 -640 480 -640 427 -640 427 -533 640 -640 480 -640 427 -426 640 -640 608 -640 427 -426 640 -640 427 -500 333 -600 400 -640 480 -399 500 -640 480 -375 500 -478 640 -640 425 -640 480 -640 425 -480 640 -640 480 -640 516 -500 375 -640 426 -409 500 -429 640 -640 424 -332 500 -500 400 -640 433 -640 581 -640 425 -492 640 -480 640 -303 640 -428 640 -640 427 -640 427 -640 427 -640 427 -640 427 -640 427 -640 458 -640 480 -500 281 -640 427 -427 640 -640 557 -591 640 -640 379 -640 426 -480 640 -640 427 -480 640 -375 500 -640 491 -640 480 -480 640 -640 480 -640 480 -640 427 -640 427 -427 640 -612 612 -500 298 -640 427 -640 480 -640 480 -640 428 -640 418 -540 640 -640 488 -640 480 -640 399 -640 427 -640 426 -640 512 -640 428 -640 428 -640 480 -360 640 -640 428 -480 640 -500 376 -375 500 -629 489 -640 580 -640 480 -640 335 -394 500 -640 480 -640 480 -640 480 -640 428 -640 480 -640 538 -480 640 -640 428 -640 427 -640 480 -640 427 -640 480 -480 640 -640 427 -485 640 -478 640 -640 428 -640 428 -640 427 -640 376 -640 423 -426 640 -640 425 -640 427 -640 427 -427 640 -640 425 -612 612 -500 375 -478 640 -500 334 -480 640 -640 480 -640 480 -640 418 -500 375 -640 427 -640 424 -640 480 -640 480 -392 500 -640 427 -500 500 -640 640 -640 483 -640 424 -640 426 -640 480 -360 640 -480 640 -640 429 -640 489 -640 427 -427 640 -640 374 -640 426 -480 640 -500 375 -427 640 -640 485 -640 427 -640 427 -640 480 -640 341 -640 480 -500 375 -640 427 -640 480 -631 640 -640 428 -480 640 -425 640 -640 427 -480 640 -640 480 -424 640 -640 360 -640 480 -500 375 -640 427 -427 640 -640 425 -414 500 -480 640 -640 426 -334 500 -375 500 -640 428 -640 478 -480 640 -640 425 -480 640 -426 640 -640 425 -640 480 -640 441 -512 640 -612 612 -430 640 -640 569 -480 640 -640 427 -640 426 -333 500 -640 480 -640 427 -640 480 -640 600 -640 427 -480 640 -640 427 -640 426 -640 458 -640 431 -640 427 -640 426 -426 640 -640 640 -640 480 -640 426 -640 426 -500 345 -500 375 -640 480 -500 333 -640 480 -640 640 -640 559 -640 427 -640 427 -500 333 -640 480 -640 480 -593 640 -500 447 -640 483 -640 427 -480 640 -500 371 -640 320 -640 480 -640 428 -640 480 -640 427 -640 425 -429 640 -640 266 -640 470 -640 360 -427 640 -430 640 -640 426 -426 640 -640 426 -640 450 -480 640 -427 640 -640 480 -500 333 -427 640 -640 427 -425 640 -640 480 -612 612 -640 427 -512 640 -640 480 -640 427 -640 480 -640 367 -439 640 -428 640 -640 360 -480 640 -427 640 -640 538 -640 480 -640 428 -640 425 -640 428 -640 408 -640 453 -640 440 -640 428 -612 612 -640 427 -640 640 -640 480 -640 428 -640 480 -427 640 -640 424 -640 427 -500 375 -426 640 -500 334 -480 640 -640 427 -480 640 -424 640 -640 427 -479 640 -480 640 -640 426 -480 640 -500 375 -500 356 -331 500 -500 334 -500 281 -426 640 -365 480 -480 640 -640 480 -500 366 -640 469 -640 427 -606 640 -640 607 -429 640 -354 500 -640 480 -640 426 -640 424 -640 479 -417 500 -640 480 -639 640 -640 427 -640 426 -640 640 -640 480 -480 640 -640 480 -332 500 -640 428 -640 428 -500 375 -640 480 -640 427 -640 425 -480 640 -480 640 -640 480 -640 427 -500 334 -480 640 -640 480 -640 513 -480 640 -640 427 -640 427 -500 375 -480 640 -427 640 -640 427 -480 640 -640 480 -640 480 -500 375 -640 427 -500 375 -500 375 -478 640 -480 640 -426 640 -612 612 -640 427 -640 521 -640 480 -640 427 -640 424 -259 500 -640 480 -640 480 -640 480 -640 429 -500 412 -640 426 -332 500 -480 640 -640 480 -640 426 -640 457 -640 480 -640 480 -640 207 -480 640 -480 640 -480 640 -640 468 -640 458 -457 640 -640 427 -640 480 -640 480 -511 640 -480 640 -500 490 -640 471 -640 480 -435 500 -640 428 -500 375 -640 437 -640 480 -640 427 -427 640 -640 480 -640 480 -500 333 -640 480 -640 427 -640 480 -640 426 -418 640 -640 480 -640 480 -480 640 -640 425 -640 424 -640 405 -640 427 -640 428 -640 480 -427 640 -427 640 -640 540 -640 496 -480 640 -640 427 -640 428 -429 640 -640 447 -500 375 -427 640 -640 480 -423 640 -640 480 -640 480 -639 640 -640 426 -426 640 -640 481 -425 640 -469 640 -426 640 -427 640 -640 360 -500 375 -640 480 -480 640 -640 389 -640 480 -640 433 -640 427 -640 421 -640 427 -640 425 -640 478 -500 375 -640 425 -640 427 -427 640 -288 352 -500 375 -427 640 -640 480 -500 375 -640 478 -640 427 -640 480 -426 640 -528 640 -640 429 -640 427 -640 478 -480 640 -640 426 -500 375 -427 640 -480 640 -449 640 -640 480 -640 480 -640 426 -640 480 -453 640 -640 480 -500 332 -640 475 -640 428 -640 480 -640 505 -480 640 -500 375 -500 375 -640 427 -640 426 -640 480 -428 640 -640 554 -480 640 -500 363 -480 204 -640 427 -480 640 -612 612 -640 425 -640 480 -427 640 -640 480 -356 500 -500 375 -640 480 -500 497 -429 640 -640 480 -480 640 -500 375 -640 427 -427 640 -640 466 -640 436 -640 480 -427 640 -480 640 -394 640 -393 640 -500 191 -640 457 -640 550 -640 411 -488 640 -640 320 -640 480 -621 640 -640 428 -425 640 -500 333 -640 480 -640 425 -640 427 -640 401 -640 480 -500 375 -374 640 -640 427 -640 480 -640 427 -640 446 -640 480 -640 427 -640 480 -427 640 -640 425 -640 480 -339 500 -640 391 -500 375 -640 427 -480 640 -640 283 -640 640 -640 428 -338 500 -640 427 -640 640 -426 640 -640 480 -640 480 -640 404 -640 480 -640 427 -640 427 -640 426 -640 480 -640 425 -500 334 -640 424 -640 426 -640 361 -640 360 -640 480 -640 427 -640 480 -640 428 -640 596 -640 426 -640 480 -500 355 -456 640 -640 425 -640 480 -640 427 -640 480 -530 640 -640 425 -375 500 -475 640 -640 481 -640 426 -640 425 -425 640 -640 428 -640 387 -480 640 -640 427 -640 427 -640 576 -640 427 -640 480 -640 480 -359 640 -640 480 -500 400 -500 374 -480 640 -480 640 -640 389 -640 456 -427 640 -640 480 -640 427 -612 612 -500 375 -640 427 -640 480 -640 640 -640 480 -500 339 -640 480 -640 427 -640 427 -500 243 -640 459 -426 640 -425 640 -640 360 -511 640 -640 414 -640 480 -640 426 -640 361 -640 253 -640 428 -640 459 -640 480 -480 360 -640 547 -500 376 -640 480 -640 480 -426 640 -480 640 -428 640 -640 428 -640 480 -480 640 -640 426 -640 426 -640 427 -640 360 -640 425 -640 427 -640 427 -640 477 -481 640 -500 333 -640 424 -640 480 -640 427 -408 500 -640 379 -480 640 -640 480 -640 509 -372 500 -640 414 -500 500 -640 428 -640 426 -500 375 -480 640 -612 612 -640 426 -640 480 -640 427 -640 480 -640 480 -640 480 -426 640 -500 375 -640 480 -640 388 -427 640 -640 430 -640 480 -640 427 -500 375 -640 424 -640 478 -425 640 -640 480 -612 612 -335 500 -640 428 -480 640 -640 480 -481 640 -640 425 -640 436 -640 512 -640 640 -640 424 -640 480 -427 640 -640 480 -640 480 -640 480 -640 469 -640 428 -640 427 -640 480 -640 479 -640 480 -640 285 -424 640 -480 640 -640 360 -640 480 -612 612 -640 480 -500 375 -428 640 -640 480 -640 427 -640 424 -427 640 -640 480 -640 480 -500 376 -640 425 -640 480 -640 426 -478 640 -500 375 -500 426 -640 480 -478 640 -427 640 -640 427 -640 480 -480 384 -428 640 -640 638 -500 375 -640 427 -640 400 -640 415 -500 334 -640 480 -480 640 -480 640 -640 480 -640 427 -500 375 -640 480 -500 375 -640 428 -640 480 -640 360 -500 375 -428 640 -640 360 -640 480 -427 640 -640 400 -640 429 -640 480 -640 480 -640 416 -426 640 -640 480 -640 383 -426 640 -640 428 -640 480 -640 478 -640 480 -640 480 -503 640 -333 500 -640 574 -480 640 -500 375 -640 480 -375 500 -480 640 -640 480 -375 500 -640 480 -640 639 -640 427 -428 640 -640 429 -480 640 -640 512 -640 427 -428 640 -480 640 -640 639 -640 427 -640 480 -640 400 -424 640 -640 424 -500 419 -640 480 -427 640 -640 477 -640 425 -640 419 -500 375 -640 480 -500 374 -640 480 -426 640 -425 640 -640 426 -640 427 -500 333 -375 500 -480 640 -640 426 -640 427 -640 427 -640 521 -640 427 -640 427 -640 427 -500 333 -640 393 -469 640 -427 640 -640 427 -480 640 -640 480 -500 375 -640 427 -640 427 -427 640 -640 480 -612 612 -640 428 -640 480 -500 375 -640 480 -640 640 -418 640 -640 457 -640 480 -375 500 -640 480 -640 480 -640 480 -426 640 -480 640 -480 640 -480 640 -480 640 -480 640 -640 427 -640 498 -640 480 -500 371 -640 480 -556 640 -490 350 -640 427 -640 443 -480 640 -416 640 -640 384 -640 321 -480 640 -480 640 -640 425 -640 480 -640 496 -513 640 -640 478 -640 480 -640 480 diff --git a/data/coco.data b/data/coco.data deleted file mode 100644 index d248a4cd73..0000000000 --- a/data/coco.data +++ /dev/null @@ -1,6 +0,0 @@ -classes=80 -train=../coco/trainvalno5k.txt -valid=../coco/5k.txt -names=data/coco.names -backup=backup/ -eval=coco diff --git a/data/coco_1img.data b/data/coco1.data similarity index 100% rename from data/coco_1img.data rename to data/coco1.data diff --git a/data/coco1.txt b/data/coco1.txt new file mode 100644 index 0000000000..268042e732 --- /dev/null +++ b/data/coco1.txt @@ -0,0 +1 @@ +../coco/images/train2017/000000109622.jpg diff --git a/data/coco16.data b/data/coco16.data new file mode 100644 index 0000000000..d382734894 --- /dev/null +++ b/data/coco16.data @@ -0,0 +1,4 @@ +classes=80 +train=data/coco16.txt +valid=data/coco16.txt +names=data/coco.names diff --git a/data/coco16.txt b/data/coco16.txt new file mode 100644 index 0000000000..4fb69e997a --- /dev/null +++ b/data/coco16.txt @@ -0,0 +1,16 @@ +../coco/images/train2017/000000109622.jpg +../coco/images/train2017/000000160694.jpg +../coco/images/train2017/000000308590.jpg +../coco/images/train2017/000000327573.jpg +../coco/images/train2017/000000062929.jpg +../coco/images/train2017/000000512793.jpg +../coco/images/train2017/000000371735.jpg +../coco/images/train2017/000000148118.jpg +../coco/images/train2017/000000309856.jpg +../coco/images/train2017/000000141882.jpg +../coco/images/train2017/000000318783.jpg +../coco/images/train2017/000000337760.jpg +../coco/images/train2017/000000298197.jpg +../coco/images/train2017/000000042421.jpg +../coco/images/train2017/000000328898.jpg +../coco/images/train2017/000000458856.jpg diff --git a/data/coco1cls.data b/data/coco1cls.data new file mode 100644 index 0000000000..509721f93c --- /dev/null +++ b/data/coco1cls.data @@ -0,0 +1,4 @@ +classes=1 +train=data/coco1cls.txt +valid=data/coco1cls.txt +names=data/coco.names diff --git a/data/coco1cls.txt b/data/coco1cls.txt new file mode 100644 index 0000000000..8702573935 --- /dev/null +++ b/data/coco1cls.txt @@ -0,0 +1,16 @@ +../coco/images/train2017/000000000901.jpg +../coco/images/train2017/000000001464.jpg +../coco/images/train2017/000000003220.jpg +../coco/images/train2017/000000003365.jpg +../coco/images/train2017/000000004772.jpg +../coco/images/train2017/000000009987.jpg +../coco/images/train2017/000000010498.jpg +../coco/images/train2017/000000012455.jpg +../coco/images/train2017/000000013992.jpg +../coco/images/train2017/000000014125.jpg +../coco/images/train2017/000000016314.jpg +../coco/images/train2017/000000016670.jpg +../coco/images/train2017/000000018412.jpg +../coco/images/train2017/000000021212.jpg +../coco/images/train2017/000000021826.jpg +../coco/images/train2017/000000030566.jpg diff --git a/data/coco2017.data b/data/coco2017.data new file mode 100644 index 0000000000..c946005678 --- /dev/null +++ b/data/coco2017.data @@ -0,0 +1,4 @@ +classes=80 +train=../coco/train2017.txt +valid=../coco/val2017.txt +names=data/coco.names diff --git a/data/coco64.data b/data/coco64.data new file mode 100644 index 0000000000..159489acb4 --- /dev/null +++ b/data/coco64.data @@ -0,0 +1,4 @@ +classes=80 +train=data/coco64.txt +valid=data/coco64.txt +names=data/coco.names diff --git a/data/coco64.txt b/data/coco64.txt new file mode 100644 index 0000000000..7dbc28fcec --- /dev/null +++ b/data/coco64.txt @@ -0,0 +1,64 @@ +../coco/images/train2017/000000109622.jpg +../coco/images/train2017/000000160694.jpg +../coco/images/train2017/000000308590.jpg +../coco/images/train2017/000000327573.jpg +../coco/images/train2017/000000062929.jpg +../coco/images/train2017/000000512793.jpg +../coco/images/train2017/000000371735.jpg +../coco/images/train2017/000000148118.jpg +../coco/images/train2017/000000309856.jpg +../coco/images/train2017/000000141882.jpg +../coco/images/train2017/000000318783.jpg +../coco/images/train2017/000000337760.jpg +../coco/images/train2017/000000298197.jpg +../coco/images/train2017/000000042421.jpg +../coco/images/train2017/000000328898.jpg +../coco/images/train2017/000000458856.jpg +../coco/images/train2017/000000073824.jpg +../coco/images/train2017/000000252846.jpg +../coco/images/train2017/000000459590.jpg +../coco/images/train2017/000000273650.jpg +../coco/images/train2017/000000331311.jpg +../coco/images/train2017/000000156326.jpg +../coco/images/train2017/000000262985.jpg +../coco/images/train2017/000000253580.jpg +../coco/images/train2017/000000447976.jpg +../coco/images/train2017/000000378077.jpg +../coco/images/train2017/000000259913.jpg +../coco/images/train2017/000000424553.jpg +../coco/images/train2017/000000000612.jpg +../coco/images/train2017/000000267625.jpg +../coco/images/train2017/000000566012.jpg +../coco/images/train2017/000000196664.jpg +../coco/images/train2017/000000363331.jpg +../coco/images/train2017/000000057992.jpg +../coco/images/train2017/000000520047.jpg +../coco/images/train2017/000000453903.jpg +../coco/images/train2017/000000162083.jpg +../coco/images/train2017/000000268516.jpg +../coco/images/train2017/000000277436.jpg +../coco/images/train2017/000000189744.jpg +../coco/images/train2017/000000041128.jpg +../coco/images/train2017/000000527728.jpg +../coco/images/train2017/000000465269.jpg +../coco/images/train2017/000000246833.jpg +../coco/images/train2017/000000076784.jpg +../coco/images/train2017/000000323715.jpg +../coco/images/train2017/000000560463.jpg +../coco/images/train2017/000000006263.jpg +../coco/images/train2017/000000094701.jpg +../coco/images/train2017/000000521359.jpg +../coco/images/train2017/000000302903.jpg +../coco/images/train2017/000000047559.jpg +../coco/images/train2017/000000480583.jpg +../coco/images/train2017/000000050025.jpg +../coco/images/train2017/000000084512.jpg +../coco/images/train2017/000000508913.jpg +../coco/images/train2017/000000093708.jpg +../coco/images/train2017/000000070493.jpg +../coco/images/train2017/000000539270.jpg +../coco/images/train2017/000000474402.jpg +../coco/images/train2017/000000209842.jpg +../coco/images/train2017/000000028820.jpg +../coco/images/train2017/000000154257.jpg +../coco/images/train2017/000000342499.jpg diff --git a/data/coco_16img.data b/data/coco_16img.data deleted file mode 100644 index 2843a88400..0000000000 --- a/data/coco_16img.data +++ /dev/null @@ -1,6 +0,0 @@ -classes=80 -train=./data/coco_16img.txt -valid=./data/coco_16img.txt -names=data/coco.names -backup=backup/ -eval=coco diff --git a/data/coco_16img.txt b/data/coco_16img.txt deleted file mode 100644 index e7bb74c037..0000000000 --- a/data/coco_16img.txt +++ /dev/null @@ -1,16 +0,0 @@ -../coco/images/COCO_train2014_000000000009.jpg -../coco/images/COCO_train2014_000000000025.jpg -../coco/images/COCO_train2014_000000000030.jpg -../coco/images/COCO_train2014_000000000034.jpg -../coco/images/COCO_train2014_000000000036.jpg -../coco/images/COCO_train2014_000000000049.jpg -../coco/images/COCO_train2014_000000000061.jpg -../coco/images/COCO_train2014_000000000064.jpg -../coco/images/COCO_train2014_000000000071.jpg -../coco/images/COCO_train2014_000000000072.jpg -../coco/images/COCO_train2014_000000000077.jpg -../coco/images/COCO_train2014_000000000078.jpg -../coco/images/COCO_train2014_000000000081.jpg -../coco/images/COCO_train2014_000000000086.jpg -../coco/images/COCO_train2014_000000000089.jpg -../coco/images/COCO_train2014_000000000092.jpg diff --git a/data/coco_1cls.data b/data/coco_1cls.data deleted file mode 100644 index a19e3c0f2a..0000000000 --- a/data/coco_1cls.data +++ /dev/null @@ -1,6 +0,0 @@ -classes=1 -train=./data/coco_1cls.txt -valid=./data/coco_1cls.txt -names=data/coco.names -backup=backup/ -eval=coco diff --git a/data/coco_1cls.txt b/data/coco_1cls.txt deleted file mode 100644 index 956293ca97..0000000000 --- a/data/coco_1cls.txt +++ /dev/null @@ -1,5 +0,0 @@ -../coco/images/COCO_val2014_000000013992.jpg -../coco/images/COCO_val2014_000000047226.jpg -../coco/images/COCO_val2014_000000050324.jpg -../coco/images/COCO_val2014_000000121497.jpg -../coco/images/COCO_val2014_000000001464.jpg diff --git a/data/coco_1img.txt b/data/coco_1img.txt deleted file mode 100644 index a0fbd05467..0000000000 --- a/data/coco_1img.txt +++ /dev/null @@ -1 +0,0 @@ -../coco/images/COCO_val2014_000000581886.jpg diff --git a/data/coco_64img.data b/data/coco_64img.data deleted file mode 100644 index 633d08b916..0000000000 --- a/data/coco_64img.data +++ /dev/null @@ -1,6 +0,0 @@ -classes=80 -train=./data/coco_64img.txt -valid=./data/coco_64img.txt -names=data/coco.names -backup=backup/ -eval=coco diff --git a/data/coco_64img.txt b/data/coco_64img.txt deleted file mode 100644 index b8b44f7b08..0000000000 --- a/data/coco_64img.txt +++ /dev/null @@ -1,64 +0,0 @@ -../coco/images/COCO_train2014_000000000009.jpg -../coco/images/COCO_train2014_000000000025.jpg -../coco/images/COCO_train2014_000000000030.jpg -../coco/images/COCO_train2014_000000000034.jpg -../coco/images/COCO_train2014_000000000036.jpg -../coco/images/COCO_train2014_000000000049.jpg -../coco/images/COCO_train2014_000000000061.jpg -../coco/images/COCO_train2014_000000000064.jpg -../coco/images/COCO_train2014_000000000071.jpg -../coco/images/COCO_train2014_000000000072.jpg -../coco/images/COCO_train2014_000000000077.jpg -../coco/images/COCO_train2014_000000000078.jpg -../coco/images/COCO_train2014_000000000081.jpg -../coco/images/COCO_train2014_000000000086.jpg -../coco/images/COCO_train2014_000000000089.jpg -../coco/images/COCO_train2014_000000000092.jpg -../coco/images/COCO_train2014_000000000094.jpg -../coco/images/COCO_train2014_000000000109.jpg -../coco/images/COCO_train2014_000000000110.jpg -../coco/images/COCO_train2014_000000000113.jpg -../coco/images/COCO_train2014_000000000127.jpg -../coco/images/COCO_train2014_000000000138.jpg -../coco/images/COCO_train2014_000000000142.jpg -../coco/images/COCO_train2014_000000000144.jpg -../coco/images/COCO_train2014_000000000149.jpg -../coco/images/COCO_train2014_000000000151.jpg -../coco/images/COCO_train2014_000000000154.jpg -../coco/images/COCO_train2014_000000000165.jpg -../coco/images/COCO_train2014_000000000194.jpg -../coco/images/COCO_train2014_000000000201.jpg -../coco/images/COCO_train2014_000000000247.jpg -../coco/images/COCO_train2014_000000000260.jpg -../coco/images/COCO_train2014_000000000263.jpg -../coco/images/COCO_train2014_000000000307.jpg -../coco/images/COCO_train2014_000000000308.jpg -../coco/images/COCO_train2014_000000000309.jpg -../coco/images/COCO_train2014_000000000312.jpg -../coco/images/COCO_train2014_000000000315.jpg -../coco/images/COCO_train2014_000000000321.jpg -../coco/images/COCO_train2014_000000000322.jpg -../coco/images/COCO_train2014_000000000326.jpg -../coco/images/COCO_train2014_000000000332.jpg -../coco/images/COCO_train2014_000000000349.jpg -../coco/images/COCO_train2014_000000000368.jpg -../coco/images/COCO_train2014_000000000370.jpg -../coco/images/COCO_train2014_000000000382.jpg -../coco/images/COCO_train2014_000000000384.jpg -../coco/images/COCO_train2014_000000000389.jpg -../coco/images/COCO_train2014_000000000394.jpg -../coco/images/COCO_train2014_000000000404.jpg -../coco/images/COCO_train2014_000000000419.jpg -../coco/images/COCO_train2014_000000000431.jpg -../coco/images/COCO_train2014_000000000436.jpg -../coco/images/COCO_train2014_000000000438.jpg -../coco/images/COCO_train2014_000000000443.jpg -../coco/images/COCO_train2014_000000000446.jpg -../coco/images/COCO_train2014_000000000450.jpg -../coco/images/COCO_train2014_000000000471.jpg -../coco/images/COCO_train2014_000000000490.jpg -../coco/images/COCO_train2014_000000000491.jpg -../coco/images/COCO_train2014_000000000510.jpg -../coco/images/COCO_train2014_000000000514.jpg -../coco/images/COCO_train2014_000000000529.jpg -../coco/images/COCO_train2014_000000000531.jpg diff --git a/data/get_coco2014.sh b/data/get_coco2014.sh new file mode 100755 index 0000000000..37335aeb57 --- /dev/null +++ b/data/get_coco2014.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Zip coco folder +# zip -r coco.zip coco +# tar -czvf coco.tar.gz coco + +# Download labels from Google Drive, accepting presented query +filename="coco2014labels.zip" +fileid="1s6-CmF5_SElM28r52P1OUrCcuXZN-SFo" + +curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" > /dev/null +curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}" -o ${filename} +rm ./cookie + +# Unzip labels +unzip -q ${filename} # for coco.zip +# tar -xzf ${filename} # for coco.tar.gz +rm ${filename} + +# Download images +cd coco/images +wget -c http://images.cocodataset.org/zips/train2014.zip +wget -c http://images.cocodataset.org/zips/val2014.zip + +# Unzip images +unzip -q train2014.zip +unzip -q val2014.zip + +# (optional) Delete zip files +rm -rf *.zip + +# cd out +cd ../.. + diff --git a/data/get_coco_dataset.sh b/data/get_coco_dataset.sh deleted file mode 100755 index b6b4fc9a1e..0000000000 --- a/data/get_coco_dataset.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -# CREDIT: https://github.com/pjreddie/darknet/tree/master/scripts/get_coco_dataset.sh - -# Clone COCO API -git clone https://github.com/pdollar/coco && cd coco - -# Download Images -mkdir images && cd images -wget -c https://pjreddie.com/media/files/train2014.zip -wget -c https://pjreddie.com/media/files/val2014.zip - -# Unzip -unzip -q train2014.zip -unzip -q val2014.zip - -# (optional) Delete zip files -rm -rf *.zip - -cd .. - -# Download COCO Metadata -wget -c https://pjreddie.com/media/files/instances_train-val2014.zip -wget -c https://pjreddie.com/media/files/coco/5k.part -wget -c https://pjreddie.com/media/files/coco/trainvalno5k.part -wget -c https://pjreddie.com/media/files/coco/labels.tgz -tar xzf labels.tgz -unzip -q instances_train-val2014.zip - -# Set Up Image Lists -paste <(awk "{print \"$PWD\"}" <5k.part) 5k.part | tr -d '\t' > 5k.txt -paste <(awk "{print \"$PWD\"}" trainvalno5k.txt - -# get xview training data -# wget -O train_images.tgz 'https://d307kc0mrhucc3.cloudfront.net/train_images.tgz?Expires=1530124049&Signature=JrQoxipmsETvb7eQHCfDFUO-QEHJGAayUv0i-ParmS-1hn7hl9D~bzGuHWG82imEbZSLUARTtm0wOJ7EmYMGmG5PtLKz9H5qi6DjoSUuFc13NQ-~6yUhE~NfPaTnehUdUMCa3On2wl1h1ZtRG~0Jq1P-AJbpe~oQxbyBrs1KccaMa7FK4F4oMM6sMnNgoXx8-3O77kYw~uOpTMFmTaQdHln6EztW0Lx17i57kK3ogbSUpXgaUTqjHCRA1dWIl7PY1ngQnLslkLhZqmKcaL-BvWf0ZGjHxCDQBpnUjIlvMu5NasegkwD9Jjc0ClgTxsttSkmbapVqaVC8peR0pO619Q__&Key-Pair-Id=APKAIKGDJB5C3XUL2DXQ' -# tar -xvzf train_images.tgz -# sudo rm -rf train_images/._* -# lastly convert each .tif to a .bmp for faster loading in cv2 - -# ./coco/images/train2014/COCO_train2014_000000167126.jpg # corrupted image diff --git a/data/get_coco_dataset_gdrive.sh b/data/get_coco_dataset_gdrive.sh deleted file mode 100755 index f280516f29..0000000000 --- a/data/get_coco_dataset_gdrive.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# Zip coco folder -# zip -r coco.zip coco -# tar -czvf coco.tar.gz coco - -# Set fileid and filename -filename="coco.zip" -fileid="1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph" # coco.zip - -# Download from Google Drive, accepting presented query -curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" > /dev/null -curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}" -o ${filename} -rm ./cookie - -# Unzip -unzip -q ${filename} # for coco.zip -# tar -xzf ${filename} # for coco.tar.gz diff --git a/data/trainvalno5k.shapes b/data/trainvalno5k.shapes deleted file mode 100644 index 855a0700e6..0000000000 --- a/data/trainvalno5k.shapes +++ /dev/null @@ -1,117263 +0,0 @@ -640 480 -640 426 -640 428 -640 425 -481 640 -381 500 -640 488 -480 640 -640 426 -427 640 -500 375 -612 612 -640 425 -512 640 -640 480 -640 427 -640 427 -640 416 -640 480 -416 640 -640 481 -640 573 -480 640 -640 480 -640 428 -480 640 -427 640 -640 536 -640 480 -640 428 -640 424 -500 333 -591 640 -640 480 -640 426 -600 600 -640 427 -640 427 -640 480 -640 481 -640 427 -640 480 -640 480 -480 640 -480 640 -640 480 -446 640 -640 480 -640 611 -426 640 -640 480 -640 389 -427 640 -640 480 -640 480 -480 640 -640 480 -640 427 -500 495 -500 313 -640 480 -360 640 -427 640 -640 480 -640 480 -640 425 -640 484 -460 312 -423 640 -427 640 -640 513 -473 500 -640 426 -640 480 -640 248 -640 480 -640 480 -480 640 -640 446 -640 427 -427 640 -500 375 -640 427 -640 472 -640 425 -640 427 -640 427 -640 481 -480 640 -612 612 -640 480 -428 640 -500 333 -640 480 -640 457 -359 640 -640 480 -640 361 -426 640 -429 640 -640 427 -612 612 -640 422 -500 332 -640 360 -640 360 -640 393 -512 640 -640 480 -640 431 -640 575 -640 480 -640 427 -640 427 -460 640 -640 427 -612 612 -327 500 -640 512 -392 500 -612 612 -640 480 -500 375 -640 360 -480 640 -427 640 -640 480 -640 369 -480 640 -480 640 -480 640 -427 640 -640 480 -640 480 -640 427 -612 612 -640 419 -640 427 -640 428 -640 480 -640 480 -443 640 -640 532 -640 480 -424 640 -640 424 -640 453 -640 424 -427 640 -640 480 -640 480 -500 332 -500 274 -640 359 -640 480 -480 640 -480 640 -480 640 -640 435 -640 427 -640 463 -640 522 -640 335 -640 480 -640 480 -640 492 -426 640 -480 640 -640 428 -500 333 -480 640 -640 426 -640 482 -480 640 -518 600 -640 480 -480 640 -640 419 -640 498 -640 480 -427 640 -612 612 -500 374 -640 428 -640 463 -640 480 -640 480 -480 640 -640 427 -354 500 -640 480 -428 640 -640 428 -640 480 -640 428 -640 428 -600 464 -500 375 -640 427 -612 612 -424 640 -427 640 -427 640 -612 612 -640 480 -640 425 -640 480 -500 375 -640 480 -480 640 -640 480 -640 480 -640 427 -640 480 -500 337 -500 335 -640 258 -640 480 -640 425 -640 562 -500 419 -640 427 -333 500 -482 500 -640 427 -640 427 -612 612 -640 480 -640 480 -500 333 -640 640 -500 375 -640 518 -640 480 -640 425 -640 426 -640 494 -640 427 -640 480 -480 640 -500 375 -640 427 -640 424 -640 480 -640 480 -640 480 -640 278 -458 640 -640 430 -640 480 -500 500 -640 640 -375 500 -564 640 -640 480 -500 353 -640 413 -473 640 -640 480 -640 427 -500 375 -640 233 -550 640 -500 333 -640 427 -640 332 -640 425 -640 426 -640 544 -640 480 -640 453 -640 640 -480 252 -500 375 -640 480 -640 480 -640 480 -640 429 -640 426 -640 480 -640 480 -480 640 -640 425 -375 500 -640 480 -640 427 -640 428 -640 462 -640 480 -428 640 -640 427 -480 640 -427 640 -501 640 -482 640 -640 427 -500 333 -640 480 -500 299 -640 463 -640 480 -640 427 -640 480 -640 480 -640 480 -640 480 -375 500 -426 640 -500 333 -640 345 -640 480 -640 580 -640 480 -428 640 -640 427 -333 500 -640 480 -640 480 -640 626 -640 428 -640 427 -640 480 -640 427 -400 500 -640 427 -500 375 -640 478 -640 480 -640 480 -640 427 -640 427 -640 427 -640 480 -500 500 -640 427 -640 360 -637 640 -481 640 -427 640 -640 426 -427 640 -640 427 -640 428 -480 640 -640 454 -609 609 -425 640 -426 640 -424 640 -427 640 -640 480 -640 427 -332 500 -640 478 -427 640 -427 640 -427 640 -640 480 -640 427 -640 480 -640 427 -640 427 -427 640 -640 376 -640 443 -640 480 -640 429 -640 480 -640 428 -640 640 -640 323 -640 480 -320 240 -640 480 -511 640 -640 408 -640 480 -500 375 -640 480 -500 297 -549 640 -500 358 -536 640 -480 640 -640 480 -640 383 -640 427 -640 480 -640 428 -640 480 -640 480 -640 482 -640 426 -640 427 -640 427 -425 640 -500 492 -640 512 -426 640 -640 383 -612 612 -640 427 -640 423 -427 640 -640 463 -480 640 -640 426 -640 427 -640 512 -480 640 -640 427 -455 640 -424 640 -533 640 -640 519 -640 421 -500 375 -640 427 -640 427 -640 443 -640 459 -640 480 -640 480 -427 640 -434 640 -500 335 -640 368 -612 612 -640 427 -640 479 -640 427 -640 480 -640 429 -640 480 -482 640 -512 640 -640 448 -640 408 -640 480 -640 480 -640 480 -612 612 -640 426 -500 392 -640 427 -640 480 -640 426 -640 640 -640 512 -640 427 -427 640 -612 612 -640 427 -640 480 -640 505 -427 640 -427 640 -640 480 -500 316 -640 482 -362 500 -500 500 -640 569 -640 638 -640 427 -480 640 -427 640 -640 427 -640 480 -640 480 -640 480 -640 425 -480 640 -500 443 -640 480 -640 427 -640 480 -640 480 -640 480 -640 427 -640 480 -640 480 -640 427 -500 333 -400 500 -480 640 -640 480 -516 640 -640 480 -500 333 -640 409 -350 233 -640 374 -640 401 -386 500 -640 480 -640 425 -640 426 -640 480 -640 480 -640 480 -640 426 -640 480 -640 480 -640 480 -640 428 -640 554 -427 640 -640 426 -483 640 -640 480 -640 480 -640 429 -425 640 -640 133 -333 500 -640 424 -480 640 -640 480 -640 480 -640 480 -458 640 -428 640 -640 361 -370 640 -360 480 -640 386 -640 426 -640 480 -640 480 -640 427 -640 427 -640 480 -500 375 -640 427 -640 572 -640 481 -640 414 -612 612 -640 480 -640 457 -640 480 -640 480 -500 375 -428 640 -480 640 -640 480 -640 427 -640 480 -640 480 -640 428 -640 424 -640 376 -640 480 -640 480 -640 640 -640 478 -480 640 -640 480 -438 640 -480 640 -429 640 -640 438 -640 427 -640 427 -640 480 -640 480 -425 640 -640 506 -640 426 -640 480 -640 427 -427 640 -640 481 -640 480 -500 334 -640 426 -375 500 -640 480 -640 425 -640 425 -500 331 -640 512 -480 640 -640 480 -640 480 -640 427 -640 480 -640 480 -640 480 -640 480 -640 480 -640 360 -640 640 -640 458 -640 480 -640 507 -640 480 -640 480 -526 640 -427 640 -640 480 -640 480 -429 640 -640 480 -427 640 -500 375 -640 428 -640 640 -640 480 -640 415 -640 480 -640 480 -612 612 -427 640 -640 480 -640 480 -478 640 -640 480 -640 565 -480 640 -374 500 -500 331 -640 427 -424 640 -640 350 -640 424 -612 612 -640 427 -640 427 -640 427 -612 612 -640 472 -500 375 -640 480 -640 480 -480 640 -640 480 -640 426 -640 480 -375 500 -640 438 -640 480 -640 494 -640 426 -428 640 -640 480 -500 366 -640 480 -500 375 -640 480 -640 519 -640 426 -640 480 -480 640 -640 480 -640 425 -640 425 -640 478 -640 424 -480 640 -478 640 -640 480 -640 427 -640 444 -480 640 -640 481 -640 480 -640 385 -640 480 -427 640 -640 480 -640 360 -640 480 -640 569 -640 480 -640 426 -640 474 -425 640 -640 347 -375 500 -640 425 -640 640 -640 467 -640 427 -427 640 -427 640 -640 480 -640 413 -640 480 -640 425 -640 371 -585 640 -640 480 -400 317 -640 432 -640 427 -640 480 -640 480 -640 346 -640 427 -640 426 -640 471 -500 333 -640 438 -640 426 -640 480 -333 500 -640 480 -640 426 -640 480 -500 333 -640 427 -480 640 -500 375 -640 480 -640 427 -438 640 -640 427 -640 480 -640 482 -640 568 -640 640 -640 480 -500 375 -640 427 -640 425 -640 426 -640 428 -640 480 -612 612 -640 480 -640 427 -640 480 -640 426 -640 427 -640 361 -612 612 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -640 469 -396 500 -640 427 -640 480 -500 375 -640 425 -600 400 -640 427 -480 640 -375 500 -425 640 -427 640 -640 480 -640 427 -480 640 -640 361 -640 473 -480 640 -640 480 -640 433 -427 640 -640 467 -640 429 -640 431 -640 427 -640 478 -640 480 -500 333 -425 640 -640 425 -612 612 -640 427 -640 482 -500 363 -378 500 -640 480 -640 426 -640 427 -640 424 -640 427 -640 439 -640 427 -340 640 -640 480 -640 428 -640 427 -640 480 -419 640 -616 640 -640 423 -640 459 -500 467 -640 427 -640 640 -640 361 -640 640 -640 427 -640 438 -426 640 -620 640 -500 364 -640 480 -640 427 -640 443 -457 640 -640 478 -640 417 -640 640 -640 383 -640 390 -640 427 -640 426 -640 413 -640 480 -640 480 -500 369 -640 457 -640 480 -640 427 -375 500 -500 377 -640 480 -640 427 -427 640 -500 491 -640 480 -640 480 -612 612 -640 425 -640 428 -640 480 -640 503 -640 425 -500 333 -480 640 -480 640 -640 480 -500 333 -486 640 -640 427 -640 428 -375 500 -375 500 -640 425 -640 512 -640 427 -640 427 -480 640 -491 640 -640 427 -640 428 -640 427 -640 480 -427 640 -640 463 -427 640 -640 427 -333 500 -480 640 -640 480 -612 612 -480 640 -480 640 -640 426 -640 427 -640 427 -640 433 -640 480 -500 332 -612 612 -640 480 -640 480 -640 476 -640 388 -427 640 -640 353 -640 426 -428 640 -640 457 -640 424 -640 427 -475 500 -426 640 -640 640 -640 480 -640 480 -640 480 -500 471 -640 480 -640 480 -640 481 -480 640 -640 480 -428 640 -443 640 -640 426 -427 640 -640 427 -500 375 -425 640 -640 359 -640 406 -640 427 -500 328 -640 480 -640 426 -640 238 -640 429 -640 480 -640 473 -640 424 -640 383 -640 480 -480 640 -640 480 -640 426 -640 426 -640 322 -414 330 -640 425 -500 346 -640 226 -478 640 -612 612 -556 640 -500 333 -333 500 -640 426 -640 427 -640 427 -640 379 -426 640 -640 427 -427 640 -640 428 -640 480 -428 640 -500 375 -333 500 -640 427 -640 428 -640 426 -480 640 -640 427 -281 500 -500 375 -640 480 -476 640 -640 480 -612 612 -640 506 -640 427 -640 434 -640 480 -640 480 -480 640 -500 375 -640 426 -335 500 -375 500 -640 480 -429 640 -375 500 -640 442 -640 480 -480 640 -640 388 -640 427 -640 480 -640 427 -640 404 -427 640 -482 640 -640 424 -640 418 -500 498 -640 202 -640 426 -640 428 -640 495 -640 422 -640 428 -480 640 -640 427 -640 480 -640 480 -375 500 -640 441 -640 463 -640 480 -480 640 -424 640 -427 640 -640 425 -640 426 -400 500 -500 375 -640 427 -640 420 -640 469 -640 455 -640 480 -640 427 -640 480 -640 509 -480 640 -640 426 -640 418 -640 480 -640 427 -640 480 -640 503 -640 480 -640 426 -640 481 -640 427 -480 640 -640 427 -500 375 -640 480 -640 480 -640 360 -640 426 -480 640 -640 428 -640 480 -640 640 -326 500 -373 500 -425 640 -519 640 -500 375 -500 375 -640 478 -640 478 -500 375 -640 480 -640 472 -508 503 -640 427 -640 480 -512 640 -640 562 -500 375 -480 640 -640 480 -427 640 -640 411 -640 520 -640 480 -640 428 -431 500 -640 426 -424 640 -640 480 -640 480 -500 334 -640 427 -640 309 -480 640 -427 640 -640 442 -480 640 -640 428 -640 410 -640 428 -640 480 -480 640 -640 427 -385 640 -427 640 -480 640 -488 640 -480 640 -500 339 -640 454 -612 612 -640 353 -380 472 -480 640 -640 448 -640 449 -640 640 -375 500 -640 480 -427 640 -480 640 -500 375 -640 435 -640 480 -640 480 -591 400 -640 427 -640 425 -640 424 -424 640 -640 427 -640 411 -640 427 -640 480 -640 427 -426 640 -500 375 -640 501 -640 428 -426 640 -640 480 -640 480 -640 427 -479 640 -640 427 -640 424 -500 375 -427 640 -427 640 -640 480 -500 375 -500 375 -640 461 -424 640 -640 640 -640 426 -640 480 -427 640 -640 480 -640 426 -640 425 -640 346 -480 640 -640 378 -478 640 -640 425 -426 640 -640 419 -640 480 -640 480 -640 480 -640 417 -640 427 -427 640 -640 427 -502 640 -480 640 -640 343 -640 480 -640 637 -500 376 -640 393 -490 490 -500 375 -640 426 -427 640 -480 640 -500 435 -640 453 -640 427 -428 640 -640 480 -427 640 -640 422 -640 480 -640 480 -640 480 -640 428 -640 426 -640 480 -500 333 -424 640 -640 480 -640 430 -480 640 -640 481 -640 480 -480 640 -640 489 -470 313 -431 640 -640 360 -640 427 -500 371 -640 426 -640 480 -480 640 -427 640 -640 480 -425 640 -640 480 -640 480 -640 480 -640 427 -640 492 -500 375 -582 640 -640 427 -500 332 -428 640 -320 640 -640 480 -426 640 -425 640 -500 375 -320 480 -640 425 -640 425 -640 427 -640 424 -640 480 -597 398 -640 425 -640 431 -640 426 -612 612 -640 425 -640 427 -640 358 -640 427 -640 480 -640 429 -640 425 -640 427 -500 335 -500 251 -428 640 -640 356 -640 425 -640 427 -640 480 -640 427 -640 360 -640 415 -640 480 -604 453 -480 640 -500 287 -334 500 -640 428 -640 427 -640 480 -640 480 -375 500 -640 428 -480 640 -640 427 -640 425 -640 427 -640 480 -480 640 -500 375 -640 425 -480 640 -640 426 -640 480 -640 427 -640 480 -640 426 -640 458 -481 640 -640 480 -427 640 -640 427 -640 429 -425 640 -640 480 -640 480 -640 433 -500 410 -640 424 -640 480 -500 375 -500 333 -640 480 -640 428 -500 404 -640 427 -640 427 -640 425 -500 375 -640 425 -640 461 -640 480 -640 427 -427 640 -612 612 -640 427 -640 480 -333 500 -428 640 -640 426 -612 612 -640 391 -640 480 -351 490 -640 360 -640 480 -640 480 -640 480 -480 640 -480 640 -640 448 -640 427 -500 375 -640 480 -640 480 -640 480 -640 484 -640 425 -640 284 -640 480 -640 480 -442 500 -640 381 -640 480 -465 640 -429 640 -640 480 -500 334 -640 427 -423 640 -612 640 -640 480 -640 480 -500 332 -640 469 -426 640 -640 456 -640 425 -375 500 -640 273 -640 480 -333 500 -379 640 -422 640 -640 427 -332 500 -640 427 -500 375 -500 375 -640 427 -640 426 -500 375 -640 400 -640 360 -640 425 -500 400 -640 633 -480 640 -640 426 -640 480 -640 480 -640 426 -427 640 -640 469 -640 425 -640 480 -640 424 -500 500 -640 360 -640 436 -640 427 -316 640 -640 427 -640 427 -470 351 -640 480 -640 480 -640 502 -640 443 -500 333 -640 480 -640 480 -640 427 -640 360 -640 480 -375 500 -475 640 -640 427 -640 427 -640 427 -640 427 -640 426 -640 427 -640 468 -333 500 -427 640 -640 400 -640 427 -480 640 -640 480 -480 640 -478 640 -640 427 -640 480 -478 640 -640 424 -640 426 -640 416 -640 453 -640 480 -500 420 -640 480 -640 480 -640 426 -375 500 -500 349 -640 416 -640 427 -500 375 -427 640 -640 426 -640 480 -375 500 -640 426 -640 425 -612 612 -640 480 -640 480 -500 186 -640 480 -480 640 -640 427 -640 640 -478 640 -640 427 -480 639 -500 327 -640 428 -426 640 -640 360 -433 640 -427 640 -640 475 -478 640 -640 480 -640 470 -640 480 -500 334 -640 427 -640 427 -491 640 -640 480 -640 478 -623 640 -640 480 -491 640 -500 333 -640 426 -640 427 -640 427 -640 424 -640 423 -640 430 -500 333 -640 480 -640 354 -500 334 -640 479 -640 427 -640 360 -640 428 -375 500 -640 480 -640 480 -640 424 -640 427 -480 640 -640 480 -480 640 -640 424 -640 480 -640 480 -500 376 -640 357 -640 427 -640 426 -612 612 -640 425 -612 612 -640 480 -640 427 -640 512 -425 640 -640 640 -640 449 -640 480 -333 500 -500 443 -640 431 -640 425 -500 391 -640 458 -480 640 -471 640 -640 480 -640 479 -640 426 -640 426 -500 375 -640 480 -612 612 -640 480 -480 640 -500 371 -429 640 -426 640 -465 335 -640 384 -426 640 -473 500 -640 426 -640 433 -480 640 -640 480 -640 480 -640 442 -640 480 -640 437 -640 640 -427 640 -640 480 -640 426 -640 427 -640 423 -480 640 -640 448 -640 480 -640 426 -640 360 -640 480 -427 640 -640 427 -640 479 -640 480 -500 352 -640 478 -427 640 -640 480 -640 427 -640 482 -474 640 -640 480 -640 425 -640 367 -480 320 -640 480 -640 480 -640 427 -640 480 -640 425 -500 375 -500 195 -480 640 -432 500 -500 386 -640 427 -640 468 -427 640 -589 640 -640 480 -640 480 -480 640 -425 640 -640 427 -640 429 -640 425 -500 333 -640 427 -640 360 -426 640 -640 480 -640 480 -640 427 -640 354 -640 428 -640 480 -480 640 -612 612 -640 424 -424 640 -640 426 -500 289 -480 640 -612 612 -500 333 -640 360 -640 426 -500 375 -640 480 -427 640 -640 640 -640 427 -640 480 -640 428 -521 640 -640 480 -640 480 -640 427 -640 365 -640 510 -640 427 -480 640 -640 427 -640 360 -640 425 -640 480 -640 427 -640 487 -456 640 -640 480 -640 448 -640 425 -640 427 -427 640 -640 376 -640 427 -640 427 -640 426 -640 480 -640 427 -500 375 -612 612 -500 334 -640 480 -333 500 -640 640 -516 640 -500 375 -500 375 -375 500 -500 329 -612 612 -640 640 -480 640 -426 640 -500 375 -500 332 -640 480 -640 435 -640 427 -640 480 -640 426 -426 640 -640 428 -640 480 -334 500 -427 640 -640 428 -500 375 -489 640 -640 426 -612 612 -480 640 -480 640 -349 640 -640 480 -640 426 -478 640 -640 332 -640 544 -640 474 -396 312 -640 425 -640 480 -640 425 -640 480 -640 383 -513 640 -640 427 -500 375 -424 640 -375 500 -427 640 -640 480 -444 640 -500 375 -640 480 -640 480 -640 480 -480 640 -375 500 -640 427 -640 427 -640 480 -500 375 -425 640 -480 640 -640 428 -640 426 -480 640 -640 427 -480 640 -640 426 -424 640 -426 640 -640 427 -640 425 -333 500 -640 426 -640 427 -640 427 -480 640 -427 640 -640 368 -427 640 -640 480 -640 512 -640 480 -640 553 -640 480 -640 640 -640 360 -359 640 -344 500 -640 480 -640 640 -640 416 -375 500 -612 612 -640 427 -612 612 -640 398 -612 612 -640 480 -640 510 -612 612 -640 480 -640 480 -640 480 -640 427 -640 403 -427 640 -640 427 -480 640 -640 480 -427 640 -500 500 -426 640 -496 640 -375 500 -640 480 -640 480 -640 427 -640 424 -640 427 -640 480 -500 333 -640 480 -640 480 -640 427 -374 500 -457 640 -640 428 -640 427 -334 500 -335 500 -640 480 -640 480 -640 428 -332 500 -640 480 -640 480 -640 480 -500 375 -640 433 -640 427 -640 478 -640 507 -640 480 -640 480 -640 428 -640 480 -640 186 -333 500 -640 427 -640 480 -640 478 -640 421 -640 282 -375 500 -640 480 -480 640 -640 480 -640 480 -640 480 -480 640 -640 427 -640 427 -480 229 -640 426 -640 427 -451 640 -640 480 -500 375 -640 427 -491 500 -415 640 -427 640 -640 427 -375 500 -640 480 -640 427 -640 424 -640 427 -640 426 -640 427 -640 427 -640 425 -640 634 -640 360 -500 375 -640 480 -640 424 -640 426 -640 427 -640 483 -500 333 -634 640 -432 640 -640 480 -640 480 -427 640 -426 640 -640 427 -640 480 -375 500 -640 386 -640 425 -640 428 -640 428 -640 480 -640 426 -427 640 -640 428 -603 640 -640 427 -500 332 -480 640 -342 500 -640 496 -640 480 -612 612 -427 640 -500 448 -414 640 -459 640 -434 640 -640 473 -640 480 -640 480 -640 480 -500 375 -478 640 -640 480 -640 480 -640 480 -640 428 -450 640 -640 427 -640 511 -375 500 -500 375 -640 427 -640 640 -335 500 -640 359 -640 480 -640 480 -640 428 -640 425 -480 640 -426 640 -640 480 -640 565 -640 427 -640 480 -640 426 -640 381 -512 640 -484 640 -640 426 -640 640 -640 480 -481 640 -427 640 -640 596 -640 480 -640 428 -640 429 -640 427 -512 640 -480 640 -427 640 -375 500 -612 612 -640 480 -640 427 -640 360 -612 612 -478 640 -640 419 -640 429 -640 426 -640 480 -640 427 -640 451 -640 480 -480 640 -640 465 -640 480 -425 640 -436 640 -478 640 -640 426 -640 554 -640 480 -640 480 -500 391 -640 426 -640 427 -640 431 -427 640 -640 425 -640 426 -640 411 -480 640 -640 425 -465 640 -640 467 -640 427 -640 480 -510 640 -480 640 -640 422 -640 427 -640 388 -640 480 -640 480 -458 640 -640 480 -480 640 -640 480 -233 247 -640 480 -428 640 -640 427 -640 360 -424 640 -640 478 -640 380 -640 360 -640 425 -500 280 -480 640 -640 426 -640 426 -640 480 -640 480 -640 463 -640 352 -640 480 -427 640 -612 612 -640 426 -480 360 -640 480 -500 375 -640 425 -640 480 -427 640 -500 334 -500 377 -640 425 -500 392 -425 640 -500 334 -333 500 -640 480 -640 480 -640 408 -427 338 -502 640 -500 375 -640 427 -640 640 -640 414 -640 512 -640 427 -640 428 -640 409 -500 375 -500 375 -640 426 -640 478 -640 427 -640 480 -640 480 -640 403 -640 461 -640 503 -640 425 -640 425 -640 457 -425 640 -427 640 -375 500 -333 500 -480 640 -640 480 -640 426 -640 480 -640 448 -640 427 -640 427 -375 500 -640 427 -500 375 -640 427 -640 427 -640 480 -640 427 -428 640 -640 426 -640 480 -300 169 -512 640 -640 480 -640 426 -640 428 -640 480 -640 323 -640 427 -480 640 -640 427 -640 427 -500 400 -428 640 -640 360 -640 480 -427 640 -475 640 -640 480 -333 500 -612 612 -640 480 -640 351 -640 562 -640 480 -640 427 -480 640 -612 612 -640 309 -640 427 -640 480 -480 640 -640 480 -424 640 -640 480 -640 427 -640 425 -640 480 -640 480 -640 480 -478 640 -478 640 -612 612 -640 426 -640 480 -556 640 -500 375 -640 425 -640 480 -480 640 -375 500 -640 427 -480 640 -426 640 -640 427 -640 426 -640 480 -480 640 -640 427 -480 640 -375 500 -640 472 -480 640 -640 427 -640 427 -640 480 -360 270 -640 480 -500 333 -333 500 -640 375 -640 360 -640 480 -427 640 -480 640 -640 428 -480 640 -427 640 -640 512 -640 480 -640 383 -640 369 -640 428 -640 345 -640 424 -612 612 -413 640 -640 442 -500 281 -500 481 -640 480 -480 640 -640 361 -500 332 -500 375 -500 375 -640 427 -500 375 -640 480 -640 429 -640 480 -500 375 -640 407 -640 427 -640 480 -640 480 -640 360 -640 426 -640 480 -500 333 -640 480 -640 425 -640 480 -640 479 -640 386 -383 640 -472 314 -480 640 -640 513 -640 516 -640 428 -500 375 -640 480 -640 480 -640 425 -480 640 -480 640 -591 640 -640 425 -640 480 -500 375 -640 427 -356 480 -640 360 -640 428 -500 333 -480 640 -640 360 -640 480 -640 457 -500 333 -640 427 -300 201 -360 640 -640 640 -640 478 -500 332 -640 480 -640 427 -640 640 -480 640 -640 427 -640 640 -640 480 -640 480 -640 427 -500 375 -640 480 -640 444 -640 427 -640 427 -640 410 -500 375 -619 640 -640 429 -500 277 -399 640 -427 640 -640 421 -640 428 -640 429 -480 640 -480 640 -320 240 -640 427 -640 427 -640 427 -640 426 -640 606 -480 640 -640 451 -640 427 -640 428 -640 360 -640 484 -500 500 -640 482 -640 427 -640 480 -640 424 -640 427 -480 640 -426 640 -640 480 -412 640 -640 480 -640 427 -640 406 -640 480 -500 375 -640 506 -640 480 -640 480 -640 415 -480 640 -640 480 -419 640 -429 640 -640 453 -640 427 -480 640 -500 333 -640 427 -640 480 -640 480 -640 428 -480 640 -640 411 -640 360 -640 429 -500 375 -640 480 -640 427 -640 640 -612 612 -640 480 -612 612 -640 481 -640 496 -376 640 -640 480 -640 431 -640 480 -640 426 -424 640 -500 486 -640 480 -640 480 -640 426 -500 325 -640 458 -640 383 -480 640 -640 369 -640 480 -640 424 -480 640 -500 333 -640 459 -424 640 -612 612 -461 640 -480 640 -375 500 -375 500 -640 423 -640 427 -640 480 -640 428 -640 388 -427 640 -640 480 -333 500 -640 423 -640 427 -640 388 -640 480 -500 375 -640 427 -500 333 -427 640 -640 427 -640 320 -640 429 -640 292 -640 424 -640 480 -640 428 -480 640 -640 408 -640 480 -640 407 -640 419 -640 426 -500 500 -375 500 -640 427 -480 640 -640 427 -640 480 -640 480 -640 161 -640 426 -500 455 -640 427 -640 480 -640 385 -640 479 -640 424 -500 375 -640 480 -640 480 -640 480 -640 480 -640 359 -640 429 -640 472 -480 640 -640 480 -500 332 -640 427 -640 625 -640 480 -640 416 -480 640 -640 385 -366 500 -426 640 -478 640 -431 640 -640 427 -640 427 -375 500 -640 427 -480 640 -640 427 -640 476 -308 233 -480 640 -640 480 -500 376 -640 427 -612 612 -500 376 -640 427 -640 427 -640 480 -640 406 -425 640 -640 480 -640 363 -640 480 -640 424 -640 426 -279 640 -480 640 -640 428 -640 427 -640 383 -640 427 -428 640 -640 425 -640 512 -640 417 -631 640 -640 427 -427 640 -480 640 -640 427 -443 448 -441 640 -640 429 -612 612 -612 612 -640 429 -640 421 -361 640 -640 425 -491 640 -640 480 -321 479 -640 427 -640 447 -429 640 -640 480 -640 480 -640 480 -426 640 -454 640 -640 361 -427 640 -640 480 -426 640 -640 423 -480 640 -612 612 -640 425 -640 520 -640 594 -640 404 -640 427 -640 480 -640 424 -640 427 -640 427 -480 640 -640 396 -640 426 -640 428 -640 585 -640 426 -427 640 -334 500 -480 640 -480 640 -640 427 -500 375 -427 640 -640 424 -375 500 -640 424 -480 640 -350 233 -424 640 -640 427 -640 640 -640 424 -640 427 -640 428 -350 450 -640 480 -640 429 -640 428 -385 500 -640 429 -640 471 -640 480 -500 375 -640 362 -640 427 -612 612 -640 341 -640 427 -640 439 -500 375 -500 333 -500 397 -480 640 -427 640 -375 500 -640 427 -640 480 -640 480 -640 480 -426 640 -640 480 -375 500 -640 480 -640 480 -480 640 -427 640 -640 441 -427 640 -640 512 -500 375 -640 427 -640 428 -640 640 -640 360 -480 640 -500 355 -640 480 -640 480 -480 640 -640 480 -640 327 -640 427 -640 427 -500 375 -566 640 -422 640 -500 312 -640 480 -640 480 -427 640 -480 640 -500 487 -427 640 -427 640 -478 640 -640 426 -640 427 -640 427 -335 500 -500 333 -640 480 -640 428 -640 463 -640 480 -640 427 -640 424 -640 480 -640 480 -640 524 -480 640 -640 480 -612 612 -427 640 -640 427 -640 480 -500 359 -640 425 -640 427 -640 379 -640 480 -640 480 -395 640 -640 427 -640 424 -640 480 -640 480 -612 612 -356 500 -640 359 -640 480 -640 411 -480 640 -640 479 -480 640 -640 427 -480 640 -640 426 -640 427 -640 480 -210 640 -640 597 -640 528 -640 427 -640 431 -640 427 -480 640 -640 480 -480 640 -640 480 -640 569 -480 640 -640 428 -640 480 -500 500 -500 375 -640 426 -640 480 -304 640 -480 640 -640 480 -640 640 -375 500 -500 314 -512 640 -444 640 -426 640 -289 350 -640 435 -640 480 -640 625 -427 640 -500 375 -640 354 -480 640 -640 599 -640 424 -480 640 -500 332 -640 428 -500 335 -640 480 -640 324 -640 480 -640 427 -640 359 -640 480 -640 494 -640 464 -640 494 -640 428 -640 358 -640 427 -640 326 -423 640 -500 375 -640 480 -440 640 -640 426 -361 640 -426 640 -640 480 -480 640 -640 426 -427 640 -640 480 -640 486 -640 611 -640 480 -640 425 -590 397 -612 612 -640 427 -477 358 -500 311 -480 640 -640 480 -640 425 -500 144 -640 427 -640 436 -425 640 -334 500 -640 512 -640 427 -480 640 -640 480 -640 480 -424 640 -640 431 -640 490 -335 479 -500 333 -480 640 -480 640 -426 640 -640 424 -640 528 -640 359 -640 480 -480 640 -640 480 -640 480 -480 640 -500 331 -480 640 -640 428 -640 511 -640 427 -480 640 -500 335 -480 640 -425 640 -426 640 -640 375 -425 640 -408 500 -640 425 -500 375 -640 424 -500 375 -640 480 -427 640 -640 485 -640 480 -427 640 -640 480 -640 283 -593 640 -425 640 -640 427 -480 640 -640 413 -480 640 -640 428 -640 541 -480 640 -640 425 -640 406 -480 640 -480 640 -640 480 -600 600 -640 431 -640 425 -640 426 -500 354 -640 428 -500 328 -640 480 -640 427 -640 426 -394 500 -640 429 -640 425 -480 640 -500 485 -640 480 -640 480 -480 640 -500 375 -640 480 -464 640 -640 427 -640 480 -427 640 -612 612 -411 600 -640 480 -640 427 -427 640 -640 428 -500 376 -640 425 -640 482 -640 427 -640 480 -640 480 -640 480 -640 480 -480 640 -415 600 -640 595 -640 480 -640 425 -640 428 -640 427 -478 640 -424 640 -640 427 -640 314 -640 441 -640 387 -640 640 -640 427 -330 500 -427 640 -480 640 -427 640 -500 333 -480 640 -640 480 -640 426 -480 640 -640 537 -640 481 -640 426 -527 640 -480 640 -640 360 -413 640 -640 427 -640 480 -640 640 -640 480 -640 479 -640 414 -640 480 -640 489 -427 640 -496 640 -640 428 -620 450 -640 639 -500 333 -640 480 -640 431 -640 480 -375 500 -479 640 -426 640 -640 480 -640 480 -640 426 -500 375 -489 640 -500 334 -427 640 -612 612 -640 425 -640 360 -640 425 -640 427 -640 480 -640 478 -640 480 -480 640 -640 478 -500 332 -640 429 -359 640 -640 429 -640 480 -480 640 -640 480 -640 480 -640 360 -451 640 -640 428 -480 640 -640 480 -640 480 -640 424 -640 427 -640 426 -640 480 -361 500 -640 480 -640 501 -625 330 -427 640 -640 424 -640 425 -640 424 -640 426 -640 454 -428 640 -640 427 -612 612 -640 480 -333 500 -612 612 -500 329 -335 500 -640 428 -640 480 -640 480 -640 426 -640 480 -640 426 -480 640 -640 391 -640 409 -640 426 -500 375 -640 640 -640 472 -427 640 -480 640 -640 640 -640 480 -640 480 -480 640 -640 480 -640 427 -500 281 -480 640 -640 428 -429 640 -500 375 -640 501 -500 375 -480 640 -480 640 -419 640 -640 480 -640 427 -375 500 -640 480 -427 640 -500 375 -640 513 -640 480 -640 480 -424 640 -640 314 -640 360 -500 375 -500 375 -478 640 -612 612 -480 640 -640 480 -480 640 -427 640 -640 426 -640 640 -612 612 -424 640 -500 333 -640 480 -426 640 -640 480 -640 480 -640 480 -640 427 -480 640 -500 333 -640 427 -640 424 -640 409 -640 541 -640 489 -640 480 -359 500 -640 427 -640 480 -640 425 -640 413 -479 640 -428 640 -640 480 -640 480 -640 427 -432 500 -640 480 -640 480 -640 429 -500 392 -640 374 -640 424 -640 480 -640 450 -640 496 -500 375 -427 640 -480 640 -480 640 -640 424 -640 480 -478 640 -640 426 -640 360 -427 640 -500 269 -474 640 -500 375 -375 500 -640 480 -500 375 -640 557 -640 361 -500 375 -640 427 -640 427 -640 480 -360 640 -427 640 -612 612 -640 427 -640 426 -375 500 -640 560 -640 332 -612 612 -640 477 -480 640 -640 480 -435 640 -375 500 -640 428 -640 398 -640 428 -375 500 -640 426 -640 428 -640 480 -551 640 -640 480 -640 480 -480 640 -640 480 -480 640 -480 640 -640 480 -640 427 -640 426 -500 381 -640 480 -640 480 -480 640 -640 425 -640 427 -427 640 -500 346 -427 640 -640 276 -640 480 -480 640 -640 480 -640 508 -344 640 -640 480 -640 401 -640 427 -349 640 -640 480 -575 575 -480 640 -640 480 -640 427 -640 424 -500 375 -333 500 -640 480 -640 409 -640 480 -480 640 -640 478 -378 500 -640 480 -521 640 -500 335 -640 426 -433 640 -640 449 -640 480 -640 480 -640 596 -500 375 -480 640 -640 426 -640 428 -640 480 -640 439 -640 427 -458 640 -640 426 -640 480 -640 428 -407 500 -500 375 -640 507 -640 480 -640 480 -640 480 -640 427 -480 640 -640 480 -640 427 -333 500 -378 640 -612 612 -640 640 -427 640 -640 426 -336 500 -640 480 -375 500 -640 427 -640 426 -640 571 -640 427 -640 426 -640 480 -640 427 -480 640 -375 500 -640 480 -640 480 -480 640 -640 441 -333 500 -640 338 -478 640 -379 500 -640 480 -640 500 -503 640 -640 360 -554 640 -427 640 -640 427 -500 500 -500 344 -640 426 -640 427 -640 517 -640 480 -640 428 -500 400 -640 424 -480 640 -640 424 -640 480 -640 426 -347 500 -359 500 -427 640 -640 426 -429 640 -640 426 -640 360 -640 427 -640 427 -640 480 -640 280 -640 414 -640 640 -500 375 -428 640 -429 500 -640 480 -640 480 -640 427 -640 426 -640 480 -640 480 -425 640 -640 309 -640 419 -421 640 -640 480 -428 640 -333 500 -640 426 -480 640 -640 480 -426 640 -640 500 -640 480 -640 427 -427 640 -480 640 -640 480 -640 391 -264 500 -500 375 -640 427 -640 427 -640 398 -640 480 -640 480 -640 425 -500 375 -499 640 -640 360 -500 375 -640 480 -426 640 -640 480 -504 640 -640 480 -500 375 -640 427 -640 480 -480 640 -640 429 -335 500 -478 640 -640 427 -640 480 -640 480 -640 427 -640 480 -640 427 -640 427 -500 375 -500 400 -640 480 -500 333 -500 375 -480 640 -427 640 -640 451 -640 336 -500 395 -640 301 -640 426 -500 375 -404 640 -640 480 -640 640 -640 427 -500 335 -640 458 -426 640 -612 612 -640 575 -638 640 -640 424 -640 478 -640 480 -640 480 -425 640 -428 640 -612 612 -427 640 -500 336 -640 424 -640 508 -640 551 -300 176 -640 426 -640 480 -612 612 -640 478 -640 427 -640 428 -640 480 -640 449 -640 438 -640 427 -500 375 -640 424 -578 640 -640 480 -640 279 -640 480 -640 480 -640 427 -640 427 -426 640 -640 427 -640 429 -427 640 -640 480 -640 480 -640 544 -480 640 -640 480 -640 482 -640 193 -640 480 -640 538 -640 480 -418 339 -640 480 -640 427 -480 640 -640 427 -640 427 -640 427 -640 436 -612 612 -640 427 -640 480 -480 640 -640 427 -426 640 -640 426 -500 375 -640 426 -427 640 -640 428 -500 333 -640 480 -640 480 -640 480 -640 426 -612 612 -640 426 -640 426 -640 427 -640 426 -407 640 -640 480 -640 480 -640 428 -427 640 -480 640 -640 467 -640 481 -640 480 -360 640 -640 497 -640 480 -612 612 -640 427 -640 427 -640 497 -640 480 -640 640 -640 480 -375 500 -640 427 -640 480 -640 460 -640 427 -640 413 -640 427 -640 424 -480 640 -480 640 -500 384 -500 375 -480 640 -640 428 -640 480 -500 375 -500 375 -640 427 -500 375 -640 480 -640 427 -480 640 -640 427 -640 480 -640 467 -640 427 -640 359 -640 360 -640 427 -640 480 -326 500 -640 471 -494 640 -640 411 -640 480 -640 373 -640 425 -480 640 -640 480 -640 427 -640 365 -421 640 -640 427 -640 480 -612 612 -333 500 -640 427 -500 333 -360 640 -640 480 -640 480 -640 359 -640 387 -640 453 -612 612 -640 360 -640 586 -500 375 -640 480 -640 428 -640 426 -640 480 -640 480 -640 428 -375 500 -462 640 -640 427 -567 640 -596 440 -449 640 -640 480 -480 640 -640 483 -640 426 -457 640 -512 640 -427 640 -640 438 -471 640 -640 480 -425 640 -640 427 -480 640 -640 427 -640 480 -640 480 -333 500 -480 640 -640 480 -640 480 -500 375 -640 427 -640 480 -640 417 -427 640 -500 375 -375 500 -640 429 -640 480 -640 480 -640 640 -640 480 -640 480 -480 640 -640 427 -640 309 -640 480 -480 640 -640 424 -426 640 -640 425 -640 481 -500 375 -640 427 -612 612 -640 480 -240 180 -640 478 -640 426 -640 427 -348 500 -640 640 -640 589 -640 480 -500 375 -640 427 -640 444 -640 350 -480 640 -640 427 -640 480 -427 640 -612 612 -480 640 -640 480 -640 480 -640 428 -640 427 -480 640 -640 425 -640 428 -640 426 -640 424 -640 480 -500 375 -640 480 -640 427 -640 427 -427 640 -375 500 -334 500 -640 480 -640 424 -500 346 -640 427 -640 429 -640 434 -640 428 -500 375 -640 426 -500 439 -640 427 -375 500 -640 480 -426 640 -640 554 -640 478 -640 427 -458 640 -640 480 -600 593 -413 640 -640 432 -640 480 -640 427 -640 481 -486 640 -640 427 -500 420 -640 427 -640 480 -329 640 -500 375 -612 612 -427 640 -640 427 -500 353 -640 364 -640 435 -640 480 -640 426 -640 479 -500 375 -640 480 -640 549 -640 480 -640 425 -640 463 -640 478 -640 459 -640 512 -640 428 -480 640 -640 425 -480 640 -640 480 -640 427 -500 490 -513 640 -640 426 -640 428 -640 426 -640 439 -425 640 -612 612 -640 480 -480 640 -640 480 -640 480 -640 427 -640 478 -640 428 -640 425 -640 480 -640 427 -640 428 -500 332 -480 640 -640 419 -640 480 -640 480 -640 430 -640 480 -375 500 -640 358 -367 640 -640 427 -640 480 -640 425 -640 427 -480 640 -640 427 -640 427 -640 439 -640 424 -640 480 -500 334 -640 427 -612 612 -480 640 -500 333 -640 427 -640 480 -357 500 -640 427 -484 640 -500 375 -426 640 -640 480 -640 478 -640 480 -640 480 -500 375 -640 480 -640 428 -426 640 -606 640 -482 640 -640 426 -640 480 -434 640 -426 640 -640 426 -375 500 -640 426 -640 361 -480 640 -640 400 -500 375 -484 640 -640 412 -640 427 -640 433 -612 612 -448 302 -640 480 -480 640 -640 440 -314 500 -640 392 -640 480 -474 640 -480 640 -640 574 -640 425 -640 427 -640 457 -640 425 -640 428 -640 480 -640 480 -640 479 -640 427 -500 375 -640 539 -480 640 -640 480 -480 640 -428 640 -480 640 -640 480 -640 480 -640 480 -640 480 -480 640 -480 640 -500 375 -640 480 -640 480 -640 429 -640 424 -500 375 -383 640 -640 480 -500 335 -640 480 -500 375 -384 640 -612 612 -640 480 -640 480 -640 480 -640 480 -419 640 -640 512 -400 300 -639 640 -640 427 -640 480 -424 640 -427 640 -640 480 -480 640 -426 640 -640 427 -640 427 -640 623 -640 521 -375 500 -640 426 -640 426 -640 427 -640 426 -500 306 -500 423 -640 428 -640 431 -640 427 -640 427 -640 634 -640 480 -640 378 -500 375 -640 427 -640 427 -500 370 -427 640 -640 427 -640 429 -640 427 -640 480 -640 424 -640 426 -640 480 -640 480 -426 640 -640 428 -640 480 -640 415 -640 427 -640 427 -640 480 -480 640 -640 427 -640 478 -480 640 -640 427 -500 333 -640 427 -640 486 -428 640 -640 424 -640 426 -640 480 -640 426 -640 480 -640 480 -419 500 -640 360 -427 640 -640 427 -640 422 -640 480 -640 480 -500 334 -425 640 -512 640 -640 427 -640 480 -480 640 -426 640 -640 480 -640 480 -500 375 -393 640 -640 425 -640 583 -640 500 -640 480 -535 640 -640 480 -640 480 -512 640 -426 640 -640 426 -375 500 -480 640 -640 480 -427 640 -640 427 -431 640 -640 427 -640 427 -375 500 -640 427 -640 429 -640 457 -640 383 -640 428 -640 521 -640 480 -640 427 -428 640 -640 427 -480 640 -640 424 -640 480 -640 640 -640 361 -640 427 -640 480 -500 377 -640 360 -640 428 -640 512 -640 424 -480 640 -640 480 -640 426 -640 427 -640 465 -640 480 -424 640 -640 427 -640 360 -640 611 -453 640 -427 640 -640 426 -375 500 -640 480 -640 426 -480 640 -612 612 -640 429 -375 500 -640 359 -640 640 -427 640 -500 333 -480 640 -612 612 -375 500 -274 500 -640 478 -640 428 -337 500 -640 454 -426 640 -320 240 -480 640 -486 466 -640 480 -575 432 -640 480 -640 574 -500 375 -469 640 -500 332 -333 500 -426 640 -640 480 -640 426 -640 427 -640 360 -640 427 -640 480 -500 375 -640 427 -500 358 -640 457 -428 640 -529 640 -512 640 -500 333 -640 383 -640 480 -640 457 -512 640 -640 427 -640 480 -640 423 -640 480 -640 427 -518 640 -480 640 -333 500 -640 428 -640 480 -640 426 -640 360 -480 640 -640 640 -500 375 -640 481 -480 640 -640 480 -640 427 -640 480 -640 413 -640 480 -428 640 -640 480 -640 428 -480 640 -494 640 -640 360 -640 480 -480 640 -424 640 -614 640 -500 300 -640 480 -640 599 -640 480 -640 427 -640 426 -640 463 -427 640 -640 480 -640 426 -640 427 -462 640 -640 480 -640 478 -640 426 -500 246 -427 640 -640 428 -640 360 -412 500 -640 425 -500 375 -500 375 -640 426 -640 480 -640 443 -640 480 -640 427 -640 427 -640 429 -640 361 -640 427 -426 640 -640 480 -636 640 -500 375 -640 427 -640 425 -640 435 -640 428 -640 428 -640 427 -480 640 -640 427 -640 480 -640 427 -640 501 -640 517 -640 480 -626 640 -640 359 -640 425 -640 429 -640 480 -640 423 -640 480 -640 424 -477 640 -640 427 -640 427 -640 480 -640 480 -640 425 -640 427 -500 373 -500 375 -640 480 -640 428 -640 633 -640 480 -640 427 -640 457 -640 480 -640 543 -640 480 -640 496 -640 287 -640 480 -480 640 -640 480 -640 480 -640 639 -640 446 -640 480 -500 375 -640 480 -640 480 -640 480 -500 375 -640 480 -640 427 -640 425 -640 428 -640 426 -640 480 -640 431 -640 427 -640 480 -640 440 -640 480 -640 480 -480 640 -640 480 -427 640 -640 489 -425 640 -640 427 -640 480 -640 480 -640 455 -640 359 -500 375 -480 640 -640 419 -480 640 -427 640 -640 480 -640 425 -640 425 -640 480 -336 500 -640 329 -640 480 -640 427 -640 480 -478 640 -612 612 -480 640 -501 640 -640 426 -427 640 -500 375 -640 427 -500 358 -425 640 -640 480 -640 480 -500 375 -640 412 -640 430 -567 640 -375 500 -476 640 -640 426 -612 612 -500 400 -426 640 -479 640 -480 640 -640 480 -480 640 -500 298 -640 480 -640 478 -640 480 -640 576 -426 640 -478 640 -640 640 -500 375 -640 483 -640 640 -424 640 -480 640 -480 640 -640 425 -640 427 -640 480 -640 480 -442 640 -500 375 -640 427 -640 480 -640 480 -640 480 -427 640 -640 426 -400 312 -640 480 -500 375 -480 640 -640 478 -640 426 -480 640 -640 480 -640 480 -640 480 -500 375 -426 640 -612 612 -640 478 -640 640 -335 500 -640 427 -640 426 -426 640 -640 427 -333 500 -640 449 -375 500 -640 480 -640 480 -427 640 -640 428 -640 480 -640 480 -640 480 -612 612 -359 640 -640 478 -640 427 -640 425 -640 426 -428 640 -640 388 -640 480 -480 640 -480 640 -640 427 -640 427 -640 480 -480 640 -640 427 -427 640 -640 311 -640 475 -500 333 -427 640 -640 429 -480 640 -426 640 -640 454 -640 480 -640 426 -571 640 -640 480 -427 640 -640 640 -640 480 -428 640 -640 448 -480 640 -640 428 -640 480 -640 480 -640 427 -480 640 -480 640 -500 375 -640 427 -640 480 -640 464 -500 485 -640 424 -640 480 -640 491 -480 640 -500 404 -640 640 -480 640 -640 427 -640 427 -480 640 -640 480 -640 480 -560 560 -480 640 -640 360 -640 457 -640 480 -612 612 -640 640 -612 612 -640 109 -500 245 -640 427 -640 425 -640 424 -640 480 -612 612 -640 400 -640 427 -500 333 -640 427 -640 424 -426 640 -640 397 -479 640 -640 425 -640 480 -428 640 -640 491 -427 640 -640 480 -492 500 -640 480 -606 640 -640 480 -640 482 -640 427 -333 500 -640 425 -640 424 -375 500 -640 427 -640 360 -640 480 -640 432 -640 457 -640 480 -640 480 -640 547 -640 455 -640 427 -640 479 -640 423 -612 612 -640 427 -500 375 -640 480 -640 427 -640 426 -500 500 -640 428 -640 427 -640 426 -640 425 -480 640 -640 426 -640 427 -640 427 -640 461 -428 640 -640 425 -640 427 -640 429 -640 480 -640 427 -500 281 -407 640 -383 640 -418 640 -500 332 -337 500 -640 547 -500 395 -640 480 -640 361 -612 612 -640 554 -640 427 -466 640 -612 612 -500 369 -640 427 -640 480 -640 480 -640 427 -500 375 -640 480 -640 426 -640 480 -500 375 -640 478 -640 480 -480 640 -579 640 -125 166 -640 426 -640 428 -556 640 -480 640 -634 640 -640 429 -640 480 -640 480 -640 424 -503 640 -480 640 -640 427 -640 360 -640 427 -640 480 -640 480 -640 480 -500 375 -640 427 -600 400 -640 409 -640 427 -640 512 -640 480 -375 500 -640 427 -640 480 -640 427 -640 426 -640 427 -409 640 -640 640 -640 428 -640 480 -640 480 -640 427 -500 333 -480 640 -427 640 -640 640 -425 640 -403 640 -640 427 -612 612 -360 270 -640 427 -640 480 -640 429 -640 427 -425 640 -640 425 -640 480 -576 640 -640 427 -480 360 -458 500 -640 478 -480 640 -640 479 -640 427 -640 480 -640 425 -640 504 -500 295 -375 500 -640 427 -640 399 -500 375 -640 425 -354 500 -640 427 -640 429 -640 479 -640 484 -480 640 -640 427 -500 375 -481 640 -640 407 -480 640 -432 640 -640 480 -500 375 -640 480 -640 514 -640 480 -640 428 -375 500 -640 480 -640 427 -640 480 -640 426 -640 480 -503 640 -640 427 -640 381 -640 480 -375 500 -500 348 -600 600 -640 427 -500 375 -640 426 -500 375 -640 427 -426 640 -640 480 -640 427 -640 428 -640 440 -640 360 -427 640 -640 426 -375 500 -480 640 -427 640 -640 427 -640 353 -500 355 -331 500 -640 480 -427 640 -640 426 -640 444 -492 640 -640 480 -640 421 -640 480 -480 640 -640 480 -640 428 -640 427 -500 333 -640 480 -640 426 -480 640 -480 640 -640 491 -328 500 -640 638 -640 480 -640 474 -640 426 -640 427 -434 640 -427 640 -375 500 -640 480 -640 427 -457 640 -640 426 -375 500 -640 426 -427 640 -640 426 -640 480 -640 426 -640 426 -640 428 -640 480 -640 427 -640 436 -640 426 -480 640 -640 480 -640 480 -640 427 -500 332 -640 401 -500 375 -640 427 -640 428 -517 640 -500 333 -640 480 -640 425 -500 375 -480 640 -640 480 -425 640 -640 426 -640 424 -640 640 -310 640 -640 425 -640 518 -500 375 -612 612 -640 480 -480 640 -640 424 -640 427 -640 480 -428 640 -500 375 -640 427 -640 480 -640 425 -480 640 -480 640 -640 427 -640 427 -640 428 -480 640 -640 480 -640 480 -309 500 -640 480 -640 457 -640 480 -640 480 -640 480 -640 424 -640 480 -640 633 -425 640 -612 612 -640 427 -500 375 -480 640 -640 504 -640 455 -640 480 -324 500 -640 480 -640 426 -640 427 -500 332 -640 408 -640 480 -640 480 -640 427 -640 427 -500 375 -640 480 -640 428 -640 426 -612 612 -640 414 -640 518 -640 359 -640 424 -480 640 -640 480 -500 334 -640 463 -640 412 -500 332 -640 426 -640 427 -640 480 -640 480 -426 640 -500 400 -480 640 -500 375 -448 299 -426 640 -427 640 -500 418 -640 480 -640 427 -640 426 -640 480 -334 500 -640 427 -640 478 -500 333 -500 375 -640 427 -640 435 -640 480 -500 332 -500 379 -640 425 -640 480 -640 480 -640 484 -512 640 -640 480 -480 640 -375 500 -640 426 -640 379 -640 484 -640 426 -640 427 -640 426 -480 640 -333 500 -640 461 -426 640 -640 480 -640 425 -427 640 -500 441 -427 640 -333 500 -640 223 -612 612 -640 480 -500 332 -640 480 -427 640 -640 480 -640 426 -480 640 -612 612 -480 640 -640 428 -640 480 -640 425 -640 480 -640 427 -640 480 -640 426 -640 480 -640 427 -640 496 -640 480 -640 471 -500 375 -640 480 -640 427 -640 480 -427 640 -640 427 -640 427 -640 427 -549 640 -640 640 -640 480 -640 329 -640 480 -640 427 -640 471 -640 480 -640 425 -500 375 -640 483 -375 500 -640 480 -640 427 -640 480 -640 425 -480 640 -640 426 -640 360 -480 640 -640 427 -427 640 -640 383 -640 427 -428 640 -640 427 -600 400 -640 506 -640 640 -640 477 -640 384 -500 333 -640 480 -419 640 -640 480 -640 480 -640 361 -612 612 -480 640 -640 425 -640 359 -634 640 -640 427 -640 427 -500 326 -427 640 -640 426 -375 500 -640 480 -640 480 -640 640 -480 640 -640 480 -640 633 -640 480 -480 640 -640 480 -640 480 -640 480 -640 360 -500 375 -480 640 -640 480 -640 640 -625 640 -640 481 -640 425 -640 425 -565 640 -480 640 -640 427 -426 640 -461 640 -640 480 -640 480 -448 500 -426 640 -375 500 -427 640 -500 375 -640 483 -640 359 -640 475 -640 480 -640 279 -640 480 -480 640 -640 424 -333 500 -612 612 -500 375 -500 358 -640 428 -640 480 -640 480 -640 425 -640 480 -467 640 -640 480 -640 457 -480 640 -640 611 -500 281 -612 612 -640 427 -640 421 -640 480 -480 640 -426 640 -640 640 -640 480 -640 431 -640 480 -640 426 -640 480 -500 500 -640 426 -500 376 -640 360 -410 270 -640 427 -426 640 -470 640 -640 480 -640 444 -332 500 -640 480 -507 640 -480 640 -640 424 -640 480 -427 640 -640 480 -640 480 -500 335 -640 480 -640 427 -640 508 -640 433 -640 466 -499 500 -640 640 -480 640 -640 264 -537 640 -640 480 -640 425 -482 640 -640 533 -640 394 -480 640 -640 359 -640 427 -500 332 -480 640 -640 426 -640 558 -640 425 -640 427 -640 427 -427 640 -427 640 -500 376 -640 428 -640 640 -640 480 -425 640 -640 424 -640 394 -375 500 -640 426 -640 425 -640 480 -640 427 -500 375 -640 318 -640 480 -640 427 -640 427 -640 427 -640 640 -640 424 -640 457 -500 332 -640 480 -640 457 -640 480 -640 432 -640 480 -640 480 -640 480 -612 612 -500 333 -640 480 -640 461 -428 640 -476 500 -640 480 -500 350 -427 640 -640 427 -640 480 -426 640 -480 640 -427 640 -640 480 -640 480 -640 427 -640 480 -640 392 -640 512 -426 640 -500 376 -640 425 -640 426 -640 480 -640 427 -640 480 -640 360 -640 481 -640 460 -640 427 -640 428 -640 427 -640 427 -640 480 -640 480 -640 427 -500 414 -400 300 -478 640 -640 521 -640 426 -640 425 -640 443 -640 427 -448 640 -500 375 -480 640 -640 427 -500 332 -424 640 -480 640 -640 406 -640 426 -359 640 -500 333 -480 640 -640 480 -640 483 -640 426 -640 426 -640 426 -640 424 -640 541 -640 426 -640 480 -500 375 -500 375 -427 640 -640 420 -640 480 -640 427 -612 612 -427 640 -332 500 -640 427 -640 480 -640 516 -640 480 -483 640 -426 640 -640 427 -640 428 -511 640 -640 480 -640 480 -425 640 -640 426 -640 427 -500 375 -500 376 -640 480 -480 640 -640 480 -640 480 -640 480 -640 427 -640 480 -640 480 -426 640 -640 480 -640 425 -612 612 -640 427 -640 427 -640 427 -640 480 -480 640 -426 640 -427 640 -640 427 -500 375 -640 360 -480 640 -640 428 -493 640 -640 480 -478 640 -640 425 -500 375 -640 426 -375 500 -640 480 -501 640 -640 427 -640 361 -640 640 -640 544 -640 425 -640 428 -500 375 -640 425 -427 640 -333 500 -640 428 -640 427 -640 480 -500 332 -640 478 -640 480 -464 640 -500 375 -640 427 -640 427 -480 640 -640 161 -640 480 -640 640 -640 480 -640 427 -640 480 -640 480 -640 480 -640 480 -612 612 -500 375 -640 427 -640 458 -640 425 -640 409 -640 509 -640 460 -640 427 -640 412 -418 500 -640 221 -640 480 -640 427 -428 640 -640 427 -640 549 -500 375 -640 291 -640 426 -480 640 -640 428 -640 425 -640 428 -640 427 -500 375 -640 425 -640 480 -640 480 -480 640 -640 346 -375 500 -423 640 -640 480 -596 640 -640 427 -640 427 -593 640 -640 493 -640 479 -640 480 -640 479 -500 375 -640 426 -300 400 -640 480 -500 375 -640 424 -480 640 -640 429 -456 640 -375 500 -640 426 -504 640 -640 480 -640 456 -640 492 -500 375 -640 471 -480 640 -480 640 -640 359 -640 480 -640 427 -426 640 -375 500 -640 480 -500 382 -640 480 -427 640 -640 480 -427 640 -640 480 -640 429 -640 480 -640 480 -640 424 -640 480 -640 480 -640 428 -500 334 -640 480 -640 480 -480 640 -640 507 -640 478 -640 460 -640 426 -640 403 -480 640 -640 427 -640 427 -427 640 -640 427 -640 416 -427 640 -300 225 -640 423 -332 500 -640 458 -500 357 -640 480 -612 612 -640 383 -640 350 -640 480 -309 640 -640 480 -640 426 -640 511 -459 640 -549 640 -640 428 -640 480 -640 480 -426 640 -640 384 -640 425 -640 444 -640 426 -640 480 -640 480 -480 640 -640 480 -640 480 -640 427 -640 427 -640 416 -640 479 -500 375 -640 480 -640 480 -640 480 -640 360 -640 402 -481 640 -640 480 -334 500 -640 480 -640 480 -640 480 -640 427 -640 360 -640 427 -480 640 -612 612 -640 427 -640 428 -640 427 -550 640 -612 612 -640 427 -375 500 -500 333 -500 375 -480 640 -640 427 -640 428 -640 480 -427 640 -640 426 -640 480 -478 640 -480 640 -640 480 -640 480 -640 428 -640 480 -640 480 -640 512 -640 480 -500 375 -640 427 -640 428 -480 640 -640 428 -576 384 -640 480 -640 480 -640 480 -423 640 -640 380 -640 436 -334 500 -427 640 -640 427 -640 480 -426 640 -480 640 -640 453 -375 500 -640 426 -408 640 -640 428 -640 424 -427 640 -640 484 -598 415 -640 425 -640 427 -640 480 -640 430 -640 427 -640 480 -640 480 -500 375 -640 428 -640 427 -426 640 -640 438 -450 640 -640 389 -482 640 -480 640 -640 442 -640 448 -500 334 -640 640 -640 421 -500 333 -628 640 -500 392 -640 480 -500 375 -500 333 -426 640 -640 425 -640 427 -640 427 -640 427 -500 375 -628 640 -640 480 -333 500 -640 480 -500 313 -640 427 -640 480 -640 426 -640 480 -640 424 -640 393 -640 426 -640 480 -640 427 -612 612 -500 375 -500 333 -500 375 -480 640 -640 427 -427 640 -480 640 -640 427 -500 250 -640 426 -640 480 -640 480 -640 427 -440 640 -426 640 -480 640 -640 480 -425 283 -640 401 -640 480 -640 427 -640 423 -425 640 -493 640 -640 430 -640 427 -640 406 -375 500 -640 504 -612 612 -500 375 -640 480 -640 458 -640 365 -640 428 -375 500 -640 480 -500 375 -640 480 -428 640 -640 408 -640 480 -500 375 -640 480 -606 400 -640 425 -428 640 -480 640 -640 480 -427 640 -640 426 -640 424 -375 500 -640 425 -640 486 -640 427 -500 430 -640 640 -640 640 -640 480 -640 543 -640 480 -640 480 -640 427 -640 427 -640 640 -640 427 -640 426 -640 541 -640 461 -640 427 -640 480 -640 427 -640 612 -612 612 -640 536 -427 640 -640 427 -640 459 -427 640 -640 418 -500 375 -358 640 -333 500 -427 640 -640 427 -640 427 -410 423 -427 640 -640 425 -640 360 -640 479 -640 480 -640 425 -640 427 -640 426 -640 427 -554 640 -640 414 -640 480 -640 480 -431 640 -640 480 -480 640 -640 446 -427 640 -640 373 -612 612 -640 480 -640 360 -409 640 -427 640 -640 480 -640 480 -426 640 -640 480 -640 412 -640 380 -640 426 -332 500 -640 426 -425 640 -500 375 -640 480 -500 333 -640 358 -640 427 -640 427 -427 640 -480 640 -612 612 -500 281 -640 427 -640 365 -500 375 -640 480 -640 480 -426 640 -471 640 -640 426 -640 480 -480 640 -500 375 -480 640 -480 640 -640 427 -640 427 -480 640 -640 426 -640 427 -640 480 -640 480 -640 428 -640 480 -640 480 -425 640 -640 494 -640 427 -640 480 -640 480 -640 480 -640 427 -640 426 -640 480 -640 426 -426 640 -640 480 -640 360 -480 640 -640 440 -640 480 -640 425 -500 375 -640 427 -457 640 -640 478 -640 427 -640 427 -640 427 -640 480 -553 640 -426 640 -640 433 -425 640 -640 472 -427 640 -427 640 -640 424 -640 427 -500 400 -640 456 -640 427 -500 332 -640 640 -428 640 -426 640 -480 640 -612 612 -640 427 -640 427 -606 640 -640 575 -640 426 -640 480 -640 480 -640 426 -640 480 -640 426 -640 480 -640 423 -640 480 -640 427 -640 480 -640 480 -352 500 -640 480 -640 360 -640 479 -640 413 -290 438 -427 640 -640 480 -375 500 -425 640 -640 480 -640 514 -640 360 -640 426 -480 640 -640 640 -640 370 -640 480 -500 434 -500 375 -427 640 -480 640 -640 427 -640 549 -640 426 -640 426 -640 427 -640 455 -640 424 -500 375 -427 640 -640 480 -640 425 -600 600 -426 640 -640 519 -640 480 -640 427 -640 480 -334 500 -640 355 -640 427 -500 334 -429 640 -640 480 -640 480 -500 375 -640 426 -331 500 -640 449 -500 375 -640 426 -640 424 -640 480 -640 427 -640 480 -640 460 -640 629 -428 640 -640 480 -640 448 -480 640 -500 332 -640 425 -428 640 -461 640 -640 480 -500 375 -640 423 -640 368 -332 500 -480 640 -640 432 -640 640 -640 427 -612 612 -333 500 -640 480 -640 480 -385 500 -500 281 -512 640 -640 526 -640 429 -480 640 -500 375 -640 426 -480 640 -480 640 -607 640 -640 479 -427 640 -640 431 -640 480 -640 480 -640 425 -640 480 -640 426 -640 480 -640 426 -640 480 -640 640 -640 426 -480 640 -427 640 -640 480 -640 427 -640 480 -640 480 -640 424 -640 480 -640 424 -640 480 -640 427 -640 364 -640 480 -640 427 -640 456 -640 427 -281 500 -480 640 -320 212 -480 640 -640 429 -640 428 -640 364 -640 418 -640 427 -640 478 -640 439 -640 426 -640 426 -640 427 -640 480 -500 446 -640 480 -640 480 -640 427 -478 640 -640 426 -640 386 -640 433 -375 500 -640 480 -500 333 -640 424 -480 640 -500 375 -640 480 -429 640 -500 375 -500 358 -640 480 -640 458 -480 640 -640 444 -640 481 -640 480 -487 500 -640 480 -480 640 -355 500 -640 360 -425 640 -333 500 -640 480 -375 500 -640 427 -640 426 -640 563 -500 371 -640 454 -640 425 -640 426 -640 427 -640 480 -500 334 -428 640 -640 481 -640 480 -640 480 -500 396 -640 440 -426 640 -438 640 -427 640 -456 640 -640 427 -640 480 -640 480 -640 427 -640 448 -500 332 -640 424 -640 480 -533 640 -375 500 -640 480 -640 439 -428 640 -612 612 -500 375 -640 480 -640 480 -480 640 -500 398 -640 437 -640 481 -640 480 -640 480 -640 480 -640 427 -458 640 -458 640 -640 427 -640 386 -500 375 -640 480 -480 640 -640 427 -640 480 -640 500 -640 437 -640 463 -427 640 -640 640 -612 612 -640 427 -612 612 -612 612 -640 428 -640 425 -640 463 -355 500 -640 480 -500 279 -640 424 -500 375 -640 425 -500 320 -640 410 -640 480 -640 427 -640 427 -640 480 -292 500 -640 427 -640 426 -480 640 -500 375 -500 333 -640 480 -640 427 -640 427 -500 375 -640 427 -500 307 -640 360 -640 428 -640 480 -640 359 -640 423 -640 424 -640 480 -640 480 -640 424 -640 427 -640 449 -640 383 -640 640 -640 426 -640 517 -426 640 -500 333 -426 640 -640 478 -640 426 -640 478 -443 640 -640 425 -426 640 -427 640 -480 640 -375 500 -640 480 -640 427 -375 500 -640 165 -480 640 -640 427 -640 480 -640 427 -640 480 -640 379 -640 425 -640 480 -640 389 -640 427 -640 427 -396 640 -375 500 -441 640 -640 480 -640 480 -640 480 -640 478 -289 500 -640 480 -640 435 -640 426 -640 480 -640 288 -500 333 -600 451 -640 480 -480 640 -640 480 -500 375 -640 640 -640 480 -640 427 -425 640 -640 427 -640 427 -600 252 -640 424 -640 640 -640 426 -640 427 -640 426 -500 440 -424 640 -480 640 -640 480 -424 640 -640 480 -640 427 -640 480 -640 427 -640 480 -436 640 -640 427 -512 640 -640 181 -640 426 -427 640 -500 375 -612 612 -640 512 -640 496 -640 427 -640 388 -640 480 -427 640 -500 375 -640 428 -640 481 -640 632 -640 480 -640 480 -640 512 -481 640 -640 480 -640 425 -427 640 -640 428 -480 320 -333 500 -640 427 -640 480 -640 428 -425 640 -480 640 -640 408 -640 480 -640 427 -337 640 -500 375 -500 333 -500 375 -640 480 -640 413 -640 424 -640 480 -640 426 -640 588 -480 640 -500 333 -427 640 -640 425 -500 375 -500 281 -480 245 -373 299 -640 480 -427 640 -640 427 -640 431 -640 425 -500 375 -603 640 -479 640 -612 612 -640 427 -640 488 -640 480 -640 333 -640 428 -457 640 -640 480 -640 427 -640 480 -500 375 -427 640 -500 375 -469 640 -640 429 -480 640 -640 425 -427 640 -640 424 -640 482 -640 427 -640 423 -640 480 -426 640 -335 500 -640 559 -640 428 -479 640 -640 480 -640 426 -640 480 -640 480 -640 426 -640 468 -480 640 -375 500 -640 480 -640 480 -480 640 -640 427 -640 427 -375 500 -640 326 -640 480 -480 640 -640 480 -521 640 -640 480 -640 426 -640 480 -640 476 -612 612 -500 375 -428 640 -640 480 -640 424 -480 640 -640 427 -640 428 -640 425 -640 427 -500 375 -640 424 -640 481 -640 480 -640 427 -640 423 -640 425 -534 640 -640 480 -393 640 -640 425 -640 480 -640 480 -480 640 -640 419 -640 458 -640 483 -640 426 -500 375 -640 361 -640 480 -640 430 -640 426 -640 426 -640 480 -500 375 -640 480 -640 480 -427 640 -500 333 -427 640 -640 476 -640 426 -640 480 -640 429 -640 426 -640 433 -479 640 -640 427 -400 640 -427 640 -640 480 -640 428 -640 427 -480 640 -500 375 -640 421 -640 427 -500 315 -500 333 -640 427 -500 375 -480 640 -640 426 -612 612 -640 425 -333 500 -500 336 -640 424 -612 612 -640 426 -640 480 -427 640 -640 360 -640 427 -640 427 -427 640 -640 275 -419 640 -640 480 -500 375 -640 428 -500 333 -480 640 -640 480 -427 640 -640 480 -369 640 -640 414 -640 480 -640 427 -375 500 -454 640 -560 640 -640 427 -640 480 -640 425 -640 457 -640 479 -480 640 -424 640 -640 425 -640 428 -640 480 -480 640 -640 426 -640 480 -640 427 -427 640 -640 427 -459 640 -640 480 -640 425 -375 500 -640 466 -640 480 -500 347 -640 426 -640 448 -458 640 -375 500 -436 640 -640 360 -391 640 -460 500 -640 427 -500 375 -640 480 -500 375 -500 332 -317 500 -639 640 -512 640 -640 427 -428 640 -473 640 -480 640 -427 640 -640 427 -640 480 -640 478 -426 640 -480 640 -640 434 -640 479 -640 480 -640 480 -500 341 -640 480 -640 480 -500 375 -640 427 -640 425 -395 640 -640 480 -640 375 -640 480 -640 428 -640 560 -640 640 -640 480 -500 333 -640 395 -640 448 -510 640 -640 424 -500 334 -640 515 -480 640 -640 480 -500 375 -405 640 -640 416 -640 513 -640 466 -471 640 -640 398 -640 480 -450 338 -640 433 -640 427 -640 480 -640 428 -640 486 -640 478 -640 427 -640 438 -427 640 -640 427 -640 480 -500 470 -480 640 -428 640 -400 640 -640 375 -500 375 -333 500 -640 424 -640 427 -640 427 -640 480 -500 375 -640 400 -640 443 -500 376 -640 527 -640 480 -480 640 -500 333 -640 480 -640 426 -640 358 -480 640 -640 436 -640 480 -500 333 -610 427 -640 480 -425 640 -375 500 -640 427 -640 640 -640 511 -640 426 -612 612 -640 478 -640 480 -640 422 -640 428 -640 480 -448 336 -500 375 -640 480 -640 473 -640 478 -640 427 -427 640 -500 375 -640 480 -640 426 -375 500 -640 480 -424 640 -480 640 -640 425 -640 480 -640 480 -640 426 -640 427 -500 375 -640 384 -640 480 -640 522 -640 428 -640 360 -640 549 -640 427 -640 427 -480 640 -640 421 -500 331 -640 480 -500 315 -640 480 -640 427 -480 640 -640 493 -640 480 -640 359 -480 640 -640 427 -427 640 -640 361 -640 480 -640 480 -500 327 -640 427 -640 453 -426 640 -480 640 -640 427 -370 500 -640 536 -500 403 -640 480 -150 200 -640 640 -448 600 -481 640 -640 427 -480 640 -427 640 -640 320 -500 301 -640 427 -480 640 -612 612 -640 480 -640 428 -640 427 -640 458 -375 500 -640 427 -640 480 -500 333 -640 429 -480 640 -640 478 -640 480 -640 480 -640 480 -640 480 -480 640 -500 375 -640 427 -640 427 -640 426 -640 425 -640 427 -640 640 -500 375 -612 612 -500 375 -480 640 -640 428 -425 251 -640 206 -640 424 -480 640 -640 473 -420 169 -640 480 -640 427 -640 480 -640 429 -640 452 -481 640 -427 640 -621 640 -425 640 -427 640 -640 399 -640 467 -640 456 -640 428 -427 640 -640 480 -640 427 -500 375 -640 425 -640 330 -640 640 -640 427 -640 480 -640 442 -640 480 -386 500 -640 426 -612 612 -640 511 -640 428 -640 426 -500 375 -640 383 -640 427 -427 640 -464 500 -640 427 -640 512 -633 640 -640 218 -500 375 -640 427 -640 480 -500 375 -640 606 -640 480 -640 457 -640 429 -640 481 -500 397 -640 480 -640 423 -480 640 -640 480 -640 426 -640 427 -428 640 -480 640 -500 339 -500 375 -480 640 -640 426 -640 480 -640 466 -427 640 -500 269 -640 429 -640 427 -426 640 -429 640 -640 480 -640 424 -640 427 -640 432 -640 480 -640 426 -640 481 -480 640 -640 426 -640 480 -640 480 -500 333 -426 640 -500 333 -640 480 -375 500 -480 640 -640 427 -427 640 -640 427 -640 480 -640 512 -640 484 -612 612 -640 480 -407 640 -640 554 -640 427 -640 429 -640 480 -640 425 -612 612 -640 425 -640 478 -603 640 -480 640 -640 418 -500 375 -640 385 -480 640 -640 480 -500 375 -640 478 -640 480 -428 640 -480 640 -336 500 -480 640 -640 428 -500 375 -640 629 -640 459 -640 425 -480 640 -640 480 -640 461 -640 480 -640 480 -640 480 -640 480 -500 375 -500 375 -408 500 -480 640 -640 528 -640 480 -640 428 -480 640 -640 617 -425 640 -500 376 -500 424 -500 333 -333 500 -640 426 -640 449 -640 427 -640 427 -640 480 -640 481 -640 480 -640 480 -640 480 -640 480 -640 480 -500 333 -640 359 -480 640 -447 640 -451 640 -640 640 -640 376 -479 640 -640 427 -640 427 -500 333 -640 426 -500 375 -640 480 -334 500 -427 640 -640 427 -640 480 -640 420 -612 612 -640 426 -640 480 -640 609 -612 612 -640 480 -640 466 -403 640 -500 336 -640 425 -360 265 -640 480 -640 480 -640 480 -640 476 -640 480 -500 375 -640 480 -640 480 -640 425 -480 640 -640 480 -640 478 -640 480 -640 480 -640 480 -427 640 -500 375 -640 480 -640 426 -640 424 -640 427 -640 472 -640 480 -281 500 -500 333 -640 429 -640 480 -640 434 -500 375 -640 427 -640 640 -640 364 -640 480 -500 500 -640 439 -500 371 -640 640 -424 640 -500 395 -640 480 -427 640 -640 357 -640 480 -640 424 -640 480 -359 640 -640 512 -640 426 -640 480 -640 573 -640 480 -640 427 -426 640 -640 360 -640 426 -640 480 -640 480 -640 425 -640 428 -612 612 -612 612 -640 400 -480 640 -640 480 -427 640 -640 480 -640 627 -640 516 -640 427 -640 427 -640 480 -640 424 -640 427 -500 333 -640 480 -500 375 -500 333 -612 612 -640 480 -480 640 -500 375 -640 480 -640 427 -640 419 -500 375 -640 425 -640 480 -480 640 -640 428 -640 464 -612 612 -640 480 -640 427 -640 480 -489 640 -640 480 -640 459 -427 640 -640 376 -640 427 -640 480 -640 512 -640 427 -640 392 -342 500 -640 480 -640 480 -640 426 -640 480 -640 425 -640 478 -640 480 -640 351 -333 500 -640 427 -640 480 -604 640 -640 480 -512 640 -640 481 -640 480 -500 485 -457 640 -640 480 -640 427 -640 427 -640 427 -640 480 -640 426 -480 640 -480 640 -640 480 -640 480 -480 640 -480 320 -640 334 -500 375 -640 427 -640 480 -423 640 -640 453 -480 640 -586 640 -640 480 -500 329 -640 480 -375 500 -640 476 -500 311 -640 458 -427 640 -452 640 -500 373 -640 640 -333 500 -612 612 -640 480 -640 428 -640 427 -500 333 -640 426 -426 640 -640 425 -426 640 -640 427 -421 640 -640 640 -500 336 -640 480 -335 500 -640 480 -333 500 -640 428 -406 640 -640 462 -640 480 -640 480 -640 428 -640 427 -640 427 -640 480 -321 640 -612 612 -612 612 -500 375 -480 640 -640 480 -640 425 -612 612 -480 640 -640 427 -390 640 -426 640 -640 427 -640 480 -500 375 -640 480 -640 402 -500 375 -480 640 -640 480 -640 427 -640 480 -640 429 -640 427 -640 425 -640 480 -640 428 -371 640 -640 486 -640 480 -640 480 -427 640 -640 428 -480 640 -500 375 -640 480 -640 420 -480 640 -640 427 -640 428 -500 375 -612 612 -640 480 -439 640 -640 474 -640 428 -435 580 -640 640 -480 640 -333 500 -640 480 -427 640 -333 500 -640 480 -640 426 -480 640 -640 306 -640 427 -640 359 -480 640 -424 640 -480 640 -640 427 -640 427 -640 427 -640 480 -640 480 -424 640 -640 480 -640 492 -640 425 -500 375 -486 640 -640 501 -427 640 -500 375 -427 640 -640 427 -446 500 -455 640 -640 426 -640 480 -361 640 -500 334 -427 640 -640 461 -640 427 -640 480 -640 427 -640 480 -500 500 -640 323 -640 428 -640 480 -640 480 -640 340 -640 428 -640 488 -447 500 -500 355 -480 640 -480 360 -480 640 -359 640 -480 640 -640 422 -640 480 -640 433 -640 496 -640 480 -640 425 -425 640 -640 394 -640 427 -640 480 -640 426 -640 480 -640 427 -640 428 -500 400 -480 640 -640 401 -353 500 -640 426 -338 500 -640 427 -480 640 -480 640 -640 426 -428 640 -480 640 -500 333 -640 484 -357 500 -640 480 -640 480 -640 480 -640 426 -375 500 -334 500 -640 480 -427 640 -640 427 -640 360 -640 480 -640 480 -640 480 -640 427 -426 640 -640 512 -640 428 -640 432 -640 426 -640 426 -640 480 -640 427 -426 640 -425 392 -640 476 -640 480 -640 427 -500 375 -375 500 -500 375 -640 426 -500 382 -640 480 -640 640 -480 640 -640 480 -603 640 -640 425 -320 240 -480 640 -480 640 -375 500 -640 471 -427 640 -500 335 -640 480 -640 480 -640 640 -427 640 -640 426 -640 427 -426 640 -640 481 -640 401 -500 375 -482 640 -640 480 -352 288 -640 512 -500 485 -640 498 -640 422 -640 480 -427 640 -427 640 -426 640 -374 500 -500 332 -640 493 -375 500 -640 480 -429 640 -640 470 -640 480 -640 623 -640 361 -500 383 -640 480 -640 425 -640 427 -640 426 -640 359 -424 640 -640 480 -640 480 -640 427 -640 423 -480 640 -640 427 -640 428 -640 427 -438 640 -640 426 -640 480 -640 480 -640 427 -640 427 -500 333 -640 480 -640 480 -640 480 -640 427 -480 640 -640 428 -640 427 -640 427 -640 427 -640 427 -640 427 -640 426 -640 427 -640 425 -640 480 -640 480 -640 427 -640 426 -424 640 -500 375 -640 427 -640 375 -566 640 -640 480 -640 425 -427 640 -640 480 -612 612 -640 480 -640 480 -640 480 -640 427 -424 640 -640 480 -640 480 -640 480 -640 480 -612 612 -427 640 -640 480 -640 640 -480 640 -640 480 -640 480 -640 415 -612 612 -640 425 -640 439 -640 480 -640 512 -640 428 -640 480 -640 427 -640 542 -640 480 -640 461 -640 480 -427 640 -640 480 -426 640 -478 640 -500 375 -332 500 -640 480 -640 427 -640 480 -640 426 -640 575 -640 480 -640 387 -640 426 -640 480 -612 612 -640 428 -351 500 -640 427 -480 640 -640 424 -640 360 -480 640 -480 640 -640 417 -500 380 -640 480 -480 640 -480 640 -640 427 -612 612 -640 480 -500 333 -640 465 -640 426 -640 426 -310 500 -640 480 -640 431 -480 640 -640 480 -500 375 -640 480 -338 409 -640 416 -640 414 -640 427 -640 426 -640 424 -369 640 -640 640 -640 427 -640 427 -640 480 -640 480 -640 427 -640 496 -612 612 -427 640 -427 640 -427 640 -640 394 -640 404 -640 424 -480 640 -640 427 -427 640 -610 406 -640 427 -301 290 -640 427 -640 462 -640 428 -480 640 -640 480 -612 612 -640 480 -640 480 -612 612 -640 480 -500 375 -333 500 -640 427 -640 458 -640 480 -500 335 -640 480 -427 640 -640 480 -333 500 -588 640 -640 478 -480 640 -640 427 -640 427 -427 640 -640 429 -640 480 -640 426 -500 333 -640 480 -640 427 -640 480 -640 480 -640 428 -425 640 -375 500 -640 480 -640 359 -640 480 -640 471 -640 480 -640 427 -640 480 -640 640 -480 640 -640 424 -640 489 -640 494 -480 640 -375 500 -640 427 -480 640 -362 640 -500 375 -480 640 -427 640 -640 480 -640 427 -479 640 -500 375 -426 640 -640 425 -640 428 -640 428 -640 427 -640 426 -640 480 -640 428 -480 640 -640 480 -640 480 -480 640 -640 201 -640 480 -480 640 -640 480 -640 434 -500 375 -640 429 -423 640 -427 640 -640 480 -640 425 -640 409 -640 480 -640 480 -640 433 -640 430 -480 640 -640 435 -640 426 -640 480 -640 360 -500 375 -640 427 -640 461 -640 426 -640 480 -640 480 -640 359 -500 334 -640 480 -640 480 -640 512 -640 343 -640 483 -640 336 -640 426 -640 480 -640 427 -640 424 -640 466 -500 332 -612 612 -640 361 -500 305 -640 465 -640 480 -492 500 -640 480 -640 473 -640 409 -640 480 -640 428 -640 427 -640 486 -465 640 -640 425 -640 496 -640 513 -640 348 -500 500 -640 512 -478 640 -640 480 -640 427 -413 640 -640 419 -640 426 -500 375 -640 428 -640 349 -427 640 -640 430 -640 480 -374 500 -640 481 -500 375 -640 480 -640 427 -640 427 -640 426 -640 426 -640 409 -640 480 -640 480 -500 382 -480 640 -640 425 -640 480 -640 428 -640 480 -480 640 -640 427 -500 333 -640 480 -640 480 -428 640 -640 383 -640 480 -640 600 -640 424 -500 375 -480 640 -640 429 -500 334 -500 375 -640 359 -640 430 -480 640 -640 459 -640 427 -640 294 -375 500 -480 640 -640 481 -640 427 -612 612 -640 425 -640 428 -500 346 -640 427 -640 427 -640 480 -640 480 -640 426 -375 500 -480 640 -427 640 -640 426 -500 333 -375 500 -424 640 -640 429 -640 427 -424 640 -640 425 -640 480 -640 380 -640 419 -640 480 -640 359 -640 464 -640 428 -640 427 -640 427 -481 640 -640 414 -500 373 -640 427 -640 426 -418 640 -640 426 -416 640 -640 480 -640 427 -640 462 -640 480 -640 481 -640 360 -640 359 -427 640 -640 426 -426 640 -640 427 -640 425 -640 482 -481 640 -612 612 -640 424 -524 640 -640 427 -640 427 -640 480 -480 640 -640 439 -640 341 -360 640 -640 429 -640 480 -500 375 -480 640 -640 427 -640 379 -640 424 -480 320 -427 640 -640 360 -640 427 -640 480 -427 640 -640 480 -640 480 -479 640 -640 480 -640 427 -428 640 -640 426 -429 640 -640 425 -640 427 -478 640 -640 480 -640 427 -480 640 -640 530 -640 427 -480 640 -480 640 -640 480 -640 480 -640 426 -425 640 -640 427 -640 480 -640 427 -640 480 -480 640 -640 429 -600 400 -640 428 -426 640 -640 480 -640 480 -427 640 -427 640 -462 640 -360 270 -364 500 -640 640 -612 612 -640 480 -640 480 -480 498 -500 382 -640 427 -612 612 -640 422 -640 426 -500 333 -640 427 -640 561 -640 480 -431 640 -640 480 -640 480 -480 640 -480 640 -640 480 -640 480 -640 432 -640 480 -500 375 -640 480 -640 483 -480 640 -480 640 -480 640 -640 185 -640 424 -640 480 -500 375 -640 480 -480 640 -640 426 -640 427 -427 640 -640 426 -500 476 -426 640 -480 640 -500 273 -480 640 -640 429 -427 640 -500 300 -500 400 -498 640 -640 480 -640 480 -640 480 -640 640 -640 480 -640 426 -375 500 -640 480 -640 425 -427 640 -640 480 -375 500 -640 427 -500 334 -640 429 -427 640 -480 640 -640 427 -640 428 -375 500 -526 640 -500 375 -640 480 -640 480 -640 423 -612 612 -640 452 -640 496 -500 375 -500 375 -383 640 -500 375 -640 427 -612 612 -640 480 -640 480 -612 612 -479 640 -640 430 -640 266 -424 640 -640 480 -640 480 -375 500 -500 333 -565 640 -640 480 -427 640 -500 375 -640 480 -425 640 -640 480 -640 480 -640 427 -640 480 -640 443 -500 583 -640 359 -480 640 -640 479 -640 480 -612 612 -640 427 -478 640 -640 480 -427 640 -640 427 -640 427 -640 427 -640 427 -640 489 -640 640 -640 480 -640 454 -640 360 -500 375 -640 427 -640 360 -640 523 -478 640 -425 640 -640 427 -423 500 -640 427 -425 283 -480 640 -640 376 -500 375 -426 640 -428 640 -640 480 -640 400 -640 427 -640 427 -640 431 -424 640 -640 480 -640 640 -500 333 -490 640 -640 480 -373 640 -640 480 -500 375 -640 426 -640 480 -640 480 -640 480 -640 426 -640 471 -640 426 -640 427 -640 427 -375 500 -640 427 -640 426 -426 640 -640 478 -640 480 -640 397 -480 640 -640 424 -640 428 -427 640 -480 640 -480 640 -640 480 -640 427 -640 480 -640 360 -640 512 -640 436 -640 428 -640 477 -434 640 -640 480 -500 375 -640 348 -640 480 -640 480 -640 480 -500 375 -427 640 -640 426 -424 640 -640 511 -640 433 -640 512 -640 411 -640 427 -640 480 -640 427 -640 427 -640 444 -640 480 -640 480 -640 427 -334 500 -640 354 -640 480 -500 332 -640 480 -640 427 -330 450 -640 427 -427 640 -640 480 -450 394 -480 640 -640 480 -361 640 -640 430 -640 480 -640 469 -640 480 -640 424 -640 429 -640 640 -640 478 -500 446 -375 500 -426 640 -612 612 -491 640 -500 333 -640 480 -640 484 -500 333 -640 480 -640 480 -640 393 -640 480 -640 480 -640 480 -500 375 -500 333 -640 480 -640 480 -500 429 -500 375 -640 480 -384 500 -425 640 -640 427 -640 428 -640 480 -640 480 -640 427 -640 480 -640 480 -640 480 -640 426 -480 640 -428 640 -428 640 -612 612 -427 640 -640 480 -640 428 -427 640 -427 640 -640 439 -640 426 -480 640 -426 640 -640 427 -640 478 -640 426 -640 428 -640 480 -640 427 -640 436 -640 480 -640 383 -640 512 -612 612 -500 334 -640 428 -640 363 -640 426 -640 426 -640 480 -640 427 -640 425 -640 458 -640 480 -640 358 -640 480 -500 333 -640 447 -640 320 -384 640 -640 427 -500 640 -640 428 -640 427 -383 640 -427 640 -427 640 -640 480 -640 363 -640 393 -494 640 -500 331 -640 427 -612 612 -640 480 -640 434 -640 480 -640 427 -500 375 -640 427 -500 375 -640 480 -640 424 -640 480 -640 427 -640 427 -640 483 -640 480 -640 480 -480 640 -640 426 -500 333 -480 640 -640 480 -640 480 -428 640 -500 335 -612 612 -640 480 -559 640 -640 481 -500 375 -431 640 -640 480 -640 425 -640 427 -500 333 -479 640 -640 480 -640 427 -640 480 -640 427 -640 480 -640 425 -640 412 -640 452 -640 480 -640 427 -640 640 -480 640 -640 473 -480 640 -375 500 -640 480 -640 480 -640 480 -640 426 -640 480 -500 335 -640 480 -640 427 -480 640 -451 640 -640 427 -480 640 -640 480 -640 425 -640 426 -640 427 -429 640 -640 429 -426 640 -640 424 -640 480 -640 480 -640 424 -640 452 -640 427 -640 480 -640 480 -640 427 -640 480 -425 640 -640 360 -427 640 -640 425 -640 427 -640 427 -640 344 -640 433 -359 640 -427 640 -500 333 -480 640 -448 640 -640 427 -640 427 -640 426 -640 438 -640 480 -480 640 -640 426 -640 361 -640 500 -640 428 -640 478 -640 480 -500 333 -427 640 -640 428 -640 360 -640 427 -478 640 -332 500 -640 480 -640 427 -640 480 -480 640 -640 427 -498 640 -640 466 -640 474 -333 500 -640 480 -426 640 -640 628 -500 334 -640 427 -640 427 -640 480 -640 427 -640 425 -421 210 -500 333 -640 427 -640 392 -640 428 -640 480 -640 480 -640 480 -640 426 -387 387 -640 493 -640 463 -426 640 -640 480 -480 640 -640 640 -640 426 -640 640 -500 419 -409 640 -640 480 -480 640 -640 480 -640 481 -640 428 -640 426 -640 480 -640 480 -640 516 -375 500 -500 375 -500 375 -480 640 -640 391 -640 480 -480 640 -640 427 -640 480 -427 640 -526 640 -640 425 -640 480 -640 436 -640 508 -612 612 -500 375 -500 333 -640 429 -480 318 -480 640 -480 640 -640 427 -640 428 -640 467 -500 375 -640 428 -427 640 -640 449 -323 500 -640 437 -480 640 -640 480 -640 478 -480 640 -500 336 -640 480 -425 640 -612 612 -478 640 -612 612 -426 640 -640 604 -640 483 -640 478 -640 431 -640 481 -640 480 -425 640 -640 424 -557 640 -480 640 -640 456 -640 480 -640 424 -480 640 -480 640 -640 427 -320 240 -640 428 -640 640 -640 259 -640 360 -640 427 -640 494 -640 480 -427 640 -427 640 -360 360 -480 640 -640 480 -640 480 -640 463 -640 480 -427 640 -640 425 -640 424 -640 480 -640 640 -640 428 -640 425 -640 425 -640 480 -640 480 -640 480 -640 424 -640 440 -640 480 -640 480 -640 426 -500 393 -640 480 -640 480 -480 640 -640 430 -480 640 -500 335 -500 333 -481 640 -500 375 -640 427 -640 564 -640 480 -426 640 -640 426 -640 480 -463 640 -640 480 -640 480 -612 612 -500 375 -640 427 -640 496 -640 427 -478 640 -640 427 -640 427 -375 500 -640 427 -500 375 -359 640 -640 351 -640 421 -480 640 -640 426 -640 427 -640 428 -640 639 -640 480 -640 378 -480 640 -640 424 -640 427 -480 640 -480 640 -500 373 -427 640 -640 480 -640 480 -500 375 -640 480 -640 432 -640 506 -640 427 -640 480 -480 640 -640 480 -480 640 -640 480 -640 487 -640 481 -480 640 -640 427 -640 426 -640 524 -500 333 -426 640 -640 480 -450 640 -640 528 -640 532 -640 463 -640 416 -640 480 -640 480 -640 468 -335 500 -640 480 -375 500 -614 640 -640 427 -640 479 -640 452 -640 427 -500 375 -640 427 -500 417 -640 481 -375 500 -640 480 -640 480 -640 480 -640 427 -506 640 -640 426 -640 480 -640 428 -480 640 -640 480 -640 480 -640 480 -640 427 -500 392 -640 504 -640 427 -480 640 -640 427 -640 428 -480 640 -640 426 -640 481 -640 434 -640 480 -375 500 -640 480 -640 480 -480 640 -640 451 -640 426 -640 480 -640 480 -640 640 -446 640 -640 426 -640 360 -500 333 -500 394 -640 426 -427 640 -640 427 -640 640 -640 480 -640 427 -640 480 -640 513 -426 640 -500 333 -640 480 -640 480 -480 640 -640 426 -480 640 -500 333 -333 500 -640 480 -640 426 -640 427 -640 428 -480 640 -640 426 -640 480 -640 479 -500 368 -415 640 -426 640 -640 426 -526 640 -640 480 -640 480 -500 302 -425 640 -426 640 -640 480 -458 640 -374 500 -630 640 -640 425 -640 480 -427 640 -640 427 -640 480 -640 480 -480 640 -640 480 -640 480 -640 427 -640 480 -640 480 -426 640 -640 424 -534 640 -428 640 -640 427 -500 375 -640 425 -640 496 -640 360 -640 480 -640 428 -640 480 -640 478 -424 640 -640 497 -640 427 -640 480 -640 564 -640 428 -480 640 -640 468 -500 333 -500 333 -640 428 -640 427 -441 640 -427 640 -500 375 -640 481 -640 480 -640 427 -486 640 -640 480 -640 428 -640 426 -612 612 -640 480 -640 427 -640 480 -427 640 -640 418 -332 500 -640 425 -640 480 -640 394 -640 480 -500 374 -500 500 -612 612 -427 640 -425 640 -427 640 -640 480 -640 480 -640 444 -612 612 -640 427 -640 430 -640 426 -500 333 -640 480 -640 426 -612 612 -478 640 -640 426 -394 500 -451 500 -425 640 -640 427 -426 640 -640 424 -424 640 -480 640 -480 640 -640 480 -640 428 -640 504 -640 424 -640 554 -640 480 -428 640 -500 375 -609 640 -640 439 -640 360 -640 561 -480 640 -478 640 -500 375 -481 640 -640 483 -421 640 -640 427 -518 640 -480 640 -640 480 -640 466 -640 394 -426 640 -480 640 -640 491 -640 426 -640 480 -500 375 -427 640 -640 440 -500 375 -480 640 -640 480 -640 502 -427 640 -511 640 -612 612 -640 439 -640 428 -640 426 -640 427 -425 640 -640 427 -469 640 -640 427 -480 640 -480 640 -640 426 -500 333 -640 404 -447 500 -640 427 -640 421 -500 334 -512 640 -640 427 -426 640 -640 480 -640 457 -427 640 -440 640 -427 640 -640 480 -426 640 -640 427 -640 426 -500 375 -500 500 -640 429 -640 427 -640 413 -375 500 -640 427 -480 640 -640 639 -640 480 -500 375 -640 480 -426 640 -427 640 -427 640 -640 427 -334 500 -640 428 -640 427 -640 480 -640 426 -427 640 -640 427 -500 375 -640 360 -640 427 -427 640 -500 375 -429 640 -640 480 -500 333 -640 425 -480 640 -612 612 -640 480 -640 480 -640 514 -402 640 -640 416 -500 333 -640 427 -640 424 -640 480 -640 427 -640 427 -640 427 -640 480 -500 375 -640 427 -640 480 -500 366 -360 480 -640 426 -640 444 -499 640 -612 612 -480 640 -465 640 -640 480 -480 640 -640 427 -360 480 -640 427 -426 640 -640 427 -640 474 -478 640 -375 500 -640 480 -500 398 -425 640 -500 332 -640 427 -500 331 -640 426 -500 373 -640 480 -640 480 -640 424 -480 360 -426 640 -500 333 -640 478 -426 640 -640 427 -640 427 -480 640 -640 640 -640 480 -640 428 -500 478 -427 640 -640 453 -640 480 -500 375 -612 612 -640 640 -640 427 -640 427 -640 427 -427 640 -640 482 -500 333 -640 369 -640 361 -424 640 -288 216 -640 424 -640 428 -400 500 -640 480 -640 427 -640 396 -640 429 -500 365 -375 500 -426 640 -443 640 -640 427 -640 480 -612 612 -427 640 -640 429 -640 428 -640 215 -396 640 -437 640 -640 426 -440 640 -640 480 -640 480 -640 480 -333 500 -500 332 -640 398 -640 480 -500 375 -480 640 -640 426 -640 480 -640 480 -640 428 -640 480 -640 424 -640 427 -640 480 -640 426 -500 333 -612 612 -640 480 -428 640 -427 640 -640 480 -238 640 -480 640 -640 428 -640 480 -398 500 -640 428 -634 640 -640 481 -480 640 -500 332 -640 230 -500 375 -640 480 -640 480 -640 480 -500 346 -640 427 -640 354 -640 480 -640 428 -500 332 -640 480 -640 427 -640 428 -612 612 -640 480 -480 640 -640 427 -640 466 -640 429 -640 426 -479 640 -640 504 -640 336 -415 640 -640 427 -640 428 -640 480 -640 427 -382 640 -640 480 -640 480 -332 500 -640 480 -640 428 -640 426 -640 427 -334 500 -640 473 -640 427 -640 480 -425 640 -640 425 -640 426 -640 383 -500 375 -640 480 -500 375 -469 640 -500 281 -640 480 -640 480 -640 425 -640 478 -640 464 -640 480 -640 428 -480 640 -640 539 -640 428 -640 427 -640 427 -480 640 -640 480 -640 480 -640 480 -480 640 -640 428 -640 427 -640 480 -640 427 -425 640 -500 346 -480 640 -500 293 -466 640 -427 640 -640 480 -640 427 -500 334 -640 640 -500 333 -480 640 -640 480 -444 500 -640 429 -500 333 -640 640 -438 640 -436 640 -480 640 -640 382 -640 480 -640 570 -480 640 -640 480 -612 612 -428 640 -640 480 -640 444 -640 480 -640 360 -640 391 -480 640 -640 426 -640 480 -640 480 -640 480 -640 425 -612 612 -375 500 -640 480 -640 480 -500 375 -500 333 -640 480 -500 375 -427 640 -640 480 -640 426 -640 400 -640 429 -640 428 -640 426 -500 375 -480 640 -400 500 -640 429 -480 640 -480 320 -640 360 -612 612 -640 360 -640 426 -640 426 -427 640 -640 425 -424 640 -640 427 -640 427 -640 426 -612 612 -427 640 -640 425 -640 480 -640 428 -640 425 -640 427 -640 427 -640 351 -640 427 -500 335 -381 500 -425 640 -640 358 -640 424 -500 375 -640 483 -640 480 -478 640 -353 640 -640 427 -640 360 -612 612 -612 612 -640 427 -640 480 -426 640 -640 427 -640 426 -480 640 -640 480 -640 427 -640 360 -640 480 -500 334 -640 480 -640 480 -640 441 -640 425 -640 512 -640 376 -640 360 -640 480 -500 454 -500 375 -640 480 -480 640 -445 640 -640 429 -640 425 -425 640 -640 425 -640 480 -500 357 -612 612 -480 640 -640 434 -640 427 -640 401 -332 500 -640 426 -640 427 -640 478 -500 334 -640 478 -640 480 -640 469 -640 426 -640 424 -640 480 -640 480 -640 480 -640 423 -640 427 -640 427 -640 480 -500 375 -640 428 -375 500 -640 427 -640 480 -640 480 -640 480 -473 615 -640 478 -640 480 -442 287 -480 640 -640 423 -640 427 -500 375 -640 480 -640 480 -640 480 -640 480 -640 436 -640 425 -500 375 -485 640 -640 427 -612 612 -480 640 -640 521 -612 612 -640 393 -640 456 -640 480 -500 375 -640 429 -640 480 -640 425 -640 480 -640 429 -640 427 -500 354 -480 640 -640 480 -640 420 -640 480 -480 640 -640 480 -500 375 -500 375 -375 500 -640 480 -640 475 -426 640 -640 426 -640 427 -640 480 -500 332 -640 427 -640 360 -480 640 -480 640 -640 428 -640 418 -476 640 -640 440 -375 500 -640 478 -640 432 -460 613 -640 480 -408 640 -640 424 -640 480 -407 500 -427 640 -640 427 -640 424 -640 640 -640 480 -640 486 -612 612 -640 403 -640 480 -640 425 -640 426 -640 402 -512 640 -640 640 -360 640 -427 640 -640 375 -640 480 -635 640 -640 480 -640 428 -640 421 -437 640 -640 426 -640 480 -500 356 -480 640 -640 480 -640 427 -640 427 -640 426 -640 480 -640 469 -640 426 -640 271 -640 389 -640 462 -640 464 -640 480 -640 434 -640 480 -640 480 -375 500 -640 152 -480 640 -640 640 -640 436 -480 640 -500 375 -453 640 -500 334 -426 640 -427 640 -375 500 -640 423 -640 427 -640 332 -640 427 -640 480 -640 426 -427 640 -426 640 -500 375 -640 428 -640 480 -449 640 -640 427 -640 411 -640 428 -640 428 -640 427 -501 640 -427 640 -500 375 -556 640 -640 480 -640 470 -612 612 -640 427 -427 640 -640 427 -466 640 -640 424 -640 425 -512 640 -640 480 -640 370 -640 480 -640 427 -640 480 -640 427 -480 640 -640 426 -640 426 -480 640 -640 480 -640 480 -375 500 -640 457 -640 427 -640 426 -427 640 -640 480 -640 480 -640 344 -640 528 -500 375 -640 485 -375 500 -640 413 -640 427 -640 480 -500 333 -640 427 -335 500 -580 440 -640 427 -640 480 -500 318 -640 427 -480 640 -640 429 -640 410 -456 640 -640 427 -640 480 -395 640 -426 640 -427 640 -427 640 -640 426 -427 640 -427 640 -640 427 -640 428 -640 427 -268 402 -640 462 -612 612 -640 480 -640 480 -640 383 -640 427 -640 409 -640 427 -640 427 -640 479 -640 427 -427 640 -640 480 -428 640 -640 427 -640 480 -427 640 -500 400 -426 640 -640 317 -640 480 -480 640 -500 375 -640 427 -480 640 -640 480 -480 640 -640 480 -640 483 -500 426 -612 612 -428 640 -640 426 -640 429 -490 488 -500 375 -640 480 -640 424 -640 480 -640 427 -640 427 -640 408 -640 403 -640 426 -640 556 -640 480 -612 612 -480 640 -480 640 -426 640 -480 640 -640 427 -375 500 -640 424 -640 427 -500 375 -480 640 -640 425 -640 480 -640 418 -640 428 -640 480 -640 479 -640 468 -539 640 -640 480 -491 500 -640 357 -427 640 -640 480 -480 640 -640 480 -426 640 -640 429 -480 640 -426 640 -640 427 -640 375 -500 499 -640 427 -480 640 -426 640 -500 333 -640 286 -640 480 -302 640 -427 640 -640 425 -500 333 -429 640 -640 483 -640 391 -640 355 -640 360 -480 640 -500 334 -640 467 -500 375 -640 480 -640 360 -640 428 -500 332 -640 427 -640 427 -640 426 -480 640 -465 640 -640 426 -640 423 -640 426 -640 480 -500 375 -640 640 -500 375 -500 375 -640 426 -640 418 -424 640 -478 640 -640 427 -640 429 -640 480 -640 476 -480 640 -640 511 -640 427 -427 640 -500 351 -640 427 -640 480 -640 480 -640 480 -480 640 -640 480 -640 374 -640 592 -640 480 -640 427 -375 500 -487 363 -640 461 -640 427 -640 425 -500 375 -640 480 -314 375 -640 427 -375 500 -640 480 -640 360 -639 640 -640 512 -640 453 -640 427 -640 480 -640 448 -375 500 -640 480 -426 640 -640 480 -500 375 -640 426 -640 480 -640 446 -640 383 -480 640 -640 457 -427 640 -640 464 -480 640 -640 480 -640 540 -640 426 -640 480 -640 480 -480 640 -640 428 -480 640 -612 612 -640 425 -480 360 -333 500 -640 440 -426 640 -612 612 -480 640 -640 427 -516 640 -640 480 -367 640 -480 640 -640 426 -480 640 -640 480 -640 480 -640 459 -640 480 -640 374 -640 459 -640 427 -480 640 -500 281 -640 427 -505 640 -640 480 -480 640 -640 480 -640 480 -421 640 -478 640 -640 428 -640 480 -640 480 -640 480 -640 436 -500 333 -640 500 -400 600 -640 427 -640 428 -375 500 -427 640 -596 640 -425 640 -640 427 -500 375 -500 220 -640 388 -480 640 -640 427 -640 360 -640 480 -640 640 -640 480 -640 610 -640 480 -425 640 -427 640 -640 512 -640 440 -640 480 -500 375 -500 249 -427 640 -640 480 -640 427 -424 640 -640 484 -482 640 -600 400 -640 423 -428 640 -640 427 -640 480 -480 542 -640 471 -640 640 -640 424 -640 427 -640 480 -640 425 -548 640 -640 455 -640 360 -429 640 -640 480 -333 500 -640 480 -488 640 -480 640 -640 444 -640 480 -640 481 -640 480 -427 640 -640 427 -425 640 -640 480 -612 612 -375 500 -640 483 -427 640 -500 335 -640 480 -640 426 -640 480 -377 500 -640 496 -640 427 -640 425 -640 426 -640 360 -640 427 -500 422 -640 426 -640 480 -640 480 -640 360 -500 375 -480 640 -480 640 -480 640 -612 612 -374 500 -500 357 -640 338 -640 428 -640 480 -640 360 -640 238 -640 427 -640 481 -640 359 -640 427 -400 261 -640 434 -500 333 -640 427 -640 480 -500 400 -640 481 -640 427 -640 429 -375 500 -640 640 -332 500 -640 434 -640 426 -640 426 -478 640 -640 466 -640 427 -480 640 -427 640 -640 427 -640 427 -640 415 -640 427 -480 640 -640 480 -500 457 -640 480 -496 500 -500 375 -471 486 -500 375 -640 480 -480 640 -640 480 -640 480 -500 333 -427 640 -480 640 -396 640 -500 375 -363 500 -640 480 -480 640 -640 480 -500 330 -612 612 -580 640 -640 480 -640 640 -640 360 -640 478 -640 411 -500 333 -500 331 -640 480 -640 480 -427 640 -640 427 -500 375 -640 427 -500 374 -480 640 -640 427 -640 480 -640 427 -500 296 -640 480 -640 480 -335 500 -500 375 -427 640 -640 480 -640 632 -500 375 -640 551 -640 427 -640 480 -640 365 -640 425 -640 524 -640 480 -640 427 -640 426 -424 640 -640 427 -640 427 -427 640 -426 640 -640 351 -640 480 -640 480 -640 427 -427 640 -640 425 -640 512 -424 640 -640 488 -640 426 -640 480 -640 493 -480 640 -640 428 -425 640 -640 480 -640 480 -640 426 -640 427 -640 426 -500 375 -640 427 -640 426 -500 375 -640 480 -640 360 -500 375 -600 448 -640 428 -500 375 -429 640 -640 426 -640 424 -640 631 -640 427 -612 612 -640 384 -640 480 -640 361 -640 480 -427 640 -640 428 -640 427 -500 217 -640 503 -500 265 -640 427 -640 480 -500 375 -640 427 -500 333 -512 640 -640 320 -500 375 -480 640 -418 640 -640 480 -500 375 -500 400 -640 413 -640 426 -640 285 -480 640 -480 360 -640 425 -640 640 -612 612 -480 640 -640 640 -640 457 -640 427 -500 375 -640 424 -500 332 -599 640 -640 427 -398 640 -640 427 -640 360 -640 425 -480 640 -640 426 -640 480 -640 480 -640 428 -640 416 -640 425 -640 480 -640 480 -640 356 -486 640 -640 427 -640 414 -640 425 -640 480 -640 481 -640 464 -425 640 -427 640 -640 430 -640 445 -640 423 -480 640 -640 396 -433 640 -640 480 -640 480 -640 480 -640 427 -640 457 -376 500 -640 427 -640 480 -640 428 -640 360 -640 427 -640 480 -640 480 -640 447 -640 427 -424 640 -640 425 -640 425 -600 600 -511 640 -640 469 -640 480 -640 427 -480 640 -640 427 -640 480 -640 480 -640 427 -640 360 -640 480 -480 640 -612 612 -333 500 -640 347 -640 480 -500 333 -640 424 -640 480 -640 360 -640 480 -640 640 -480 640 -640 427 -640 480 -640 512 -612 612 -439 640 -640 425 -424 640 -500 334 -500 376 -475 640 -640 426 -640 479 -461 640 -640 431 -640 427 -480 640 -640 480 -427 640 -640 426 -640 478 -640 428 -640 480 -500 323 -480 640 -640 480 -480 640 -375 500 -640 480 -640 480 -640 480 -612 612 -640 427 -640 283 -640 427 -500 375 -640 480 -640 427 -480 640 -427 640 -640 427 -478 640 -512 640 -640 426 -640 640 -640 427 -640 480 -640 427 -480 640 -427 640 -640 427 -640 429 -427 640 -640 480 -640 423 -640 427 -500 375 -640 425 -640 480 -640 503 -500 375 -480 640 -640 426 -640 480 -640 550 -640 447 -640 428 -640 427 -480 640 -500 358 -640 427 -640 514 -500 334 -640 480 -640 359 -640 480 -480 640 -500 353 -427 640 -640 427 -480 640 -640 427 -640 480 -375 500 -491 640 -640 425 -640 480 -612 612 -640 427 -640 427 -332 500 -640 427 -640 428 -500 309 -612 612 -640 249 -480 640 -640 480 -358 640 -640 480 -478 640 -480 640 -640 425 -427 640 -640 512 -640 425 -640 480 -640 426 -612 612 -427 640 -427 640 -640 480 -480 640 -427 640 -640 384 -424 640 -428 640 -480 640 -480 640 -640 480 -640 427 -640 593 -640 480 -640 617 -640 360 -640 480 -640 438 -640 425 -640 422 -480 640 -500 375 -640 426 -640 427 -640 427 -640 480 -640 431 -640 425 -640 427 -640 427 -640 428 -640 424 -640 503 -640 480 -640 425 -640 427 -426 640 -428 640 -640 426 -640 361 -426 640 -375 500 -640 480 -500 375 -640 361 -640 640 -630 640 -480 640 -640 480 -480 640 -640 480 -640 427 -640 480 -530 640 -640 480 -640 428 -640 427 -500 325 -480 640 -433 640 -640 427 -640 452 -640 480 -640 480 -640 427 -640 480 -640 480 -640 480 -480 640 -640 480 -640 424 -640 426 -427 640 -640 480 -640 426 -640 414 -375 500 -640 428 -640 427 -480 640 -640 640 -640 480 -640 427 -640 427 -640 427 -500 375 -640 427 -640 480 -480 640 -500 390 -640 427 -617 640 -640 480 -640 480 -427 640 -500 375 -640 427 -640 454 -480 640 -640 427 -640 424 -640 426 -640 425 -500 333 -640 480 -640 268 -640 404 -480 640 -640 424 -640 427 -640 429 -640 361 -600 400 -640 426 -500 351 -640 480 -640 480 -640 424 -640 360 -427 640 -640 449 -640 480 -640 480 -640 427 -375 500 -640 427 -640 359 -640 471 -640 480 -500 327 -640 427 -427 640 -427 640 -612 612 -640 480 -640 429 -427 640 -427 640 -640 426 -640 426 -640 424 -480 640 -500 375 -428 640 -480 640 -640 599 -333 500 -640 427 -640 360 -612 612 -640 480 -640 594 -640 480 -480 640 -640 426 -640 427 -640 480 -500 376 -480 640 -500 375 -426 640 -640 426 -640 480 -640 360 -600 450 -612 612 -486 640 -640 480 -512 640 -427 640 -640 480 -480 640 -640 426 -489 640 -640 480 -475 355 -480 640 -375 500 -480 640 -426 640 -480 640 -640 361 -536 640 -500 375 -480 640 -375 500 -640 427 -640 640 -640 421 -500 473 -640 428 -369 640 -640 480 -375 500 -500 375 -640 480 -640 480 -640 480 -640 422 -640 425 -640 480 -640 480 -480 640 -640 427 -640 427 -640 425 -426 640 -640 427 -500 312 -640 263 -480 640 -640 480 -640 640 -375 500 -640 463 -640 480 -640 456 -640 480 -500 375 -640 425 -427 640 -640 426 -500 329 -640 480 -500 375 -640 427 -640 480 -640 427 -640 547 -640 426 -480 640 -640 427 -640 418 -640 328 -480 640 -640 480 -640 427 -500 255 -640 427 -480 640 -480 640 -640 409 -640 480 -428 640 -375 500 -500 333 -640 480 -606 640 -640 480 -640 434 -640 464 -640 429 -640 427 -480 640 -640 426 -640 369 -640 426 -640 366 -640 426 -640 480 -375 500 -500 375 -640 480 -640 426 -640 480 -640 480 -640 420 -395 640 -612 612 -640 480 -640 426 -480 640 -640 427 -500 375 -460 640 -640 412 -640 427 -640 480 -473 600 -640 640 -612 612 -640 480 -640 404 -640 480 -640 480 -640 526 -500 363 -640 414 -640 400 -640 427 -640 427 -640 427 -640 480 -640 480 -640 427 -640 515 -498 640 -640 472 -640 480 -480 640 -640 415 -333 500 -640 480 -640 461 -640 426 -640 406 -640 512 -428 640 -640 427 -640 480 -640 480 -640 628 -640 427 -427 640 -426 640 -640 427 -640 427 -640 480 -640 424 -554 640 -480 640 -640 415 -640 426 -480 640 -500 334 -500 375 -640 427 -640 466 -640 427 -640 428 -427 640 -640 428 -640 427 -640 480 -640 480 -640 360 -640 426 -640 480 -500 333 -500 356 -640 360 -640 480 -640 427 -480 640 -640 480 -640 592 -612 612 -640 480 -640 479 -640 466 -640 429 -640 480 -612 612 -640 512 -479 640 -640 480 -640 480 -640 480 -640 427 -640 480 -500 349 -640 523 -640 480 -640 480 -640 483 -640 428 -399 500 -500 375 -640 427 -640 381 -640 480 -640 427 -640 426 -640 393 -640 426 -565 640 -480 640 -640 426 -480 640 -480 640 -454 640 -573 640 -640 480 -640 427 -480 640 -640 427 -640 480 -497 500 -640 427 -640 360 -500 375 -640 427 -640 425 -480 640 -640 428 -426 640 -500 491 -480 640 -374 500 -640 480 -640 425 -360 480 -640 480 -612 612 -640 480 -640 349 -375 500 -640 425 -640 360 -640 427 -640 427 -428 640 -640 480 -425 640 -375 500 -640 359 -640 480 -500 375 -427 640 -640 429 -640 480 -640 480 -640 480 -640 470 -434 640 -500 375 -640 425 -640 305 -640 427 -640 480 -426 640 -360 640 -640 480 -375 500 -480 640 -478 640 -640 480 -595 640 -640 428 -640 480 -480 640 -640 480 -500 281 -640 480 -500 333 -640 427 -640 428 -500 191 -409 640 -640 480 -425 640 -640 512 -640 480 -640 426 -640 427 -640 424 -640 427 -640 427 -640 480 -640 480 -640 476 -640 536 -640 480 -640 480 -640 480 -500 375 -640 427 -640 480 -500 500 -640 480 -640 340 -640 480 -640 480 -426 640 -640 473 -500 333 -640 480 -640 470 -640 427 -640 502 -640 426 -640 298 -640 480 -480 640 -640 480 -640 480 -640 480 -640 426 -612 612 -500 375 -640 429 -500 338 -500 375 -640 480 -500 375 -492 640 -640 427 -640 429 -640 599 -640 480 -338 450 -640 480 -640 480 -640 359 -500 366 -640 424 -428 640 -640 480 -640 427 -640 480 -500 333 -500 375 -640 425 -480 640 -426 640 -640 346 -640 480 -640 480 -640 480 -612 612 -428 640 -640 427 -399 640 -356 500 -427 640 -640 480 -640 480 -640 480 -640 640 -640 480 -640 441 -640 480 -500 375 -480 640 -612 612 -500 375 -640 441 -640 427 -640 427 -640 427 -427 640 -640 424 -480 640 -640 427 -500 392 -640 427 -427 640 -640 512 -640 480 -486 640 -640 480 -640 453 -640 425 -640 480 -640 428 -479 640 -640 480 -640 480 -375 500 -480 640 -640 427 -490 640 -480 640 -640 424 -427 640 -640 426 -640 426 -333 500 -375 500 -427 640 -640 424 -480 640 -500 333 -640 426 -640 480 -640 471 -632 640 -640 480 -640 421 -640 480 -640 352 -640 427 -480 640 -640 426 -640 480 -640 459 -640 480 -640 427 -427 640 -640 480 -640 443 -640 428 -640 480 -640 480 -485 640 -427 640 -640 427 -640 424 -640 640 -640 480 -640 427 -640 427 -640 406 -640 493 -640 480 -612 612 -500 375 -640 466 -640 422 -640 434 -640 428 -640 427 -640 427 -640 480 -640 425 -454 640 -640 338 -640 427 -500 334 -640 363 -640 426 -457 640 -640 427 -640 478 -428 640 -500 375 -640 480 -360 640 -640 427 -640 427 -480 640 -640 480 -640 424 -640 360 -640 414 -640 437 -640 480 -640 428 -500 375 -480 640 -480 640 -427 640 -448 300 -486 640 -500 375 -500 400 -640 449 -640 415 -427 640 -640 428 -640 480 -640 480 -427 640 -500 333 -500 341 -500 375 -500 375 -640 480 -640 427 -640 512 -640 427 -480 640 -640 480 -500 334 -640 427 -640 424 -640 426 -640 427 -480 640 -480 640 -640 426 -640 427 -640 480 -640 429 -480 640 -640 480 -640 427 -612 612 -500 333 -640 427 -612 612 -500 375 -640 427 -426 640 -640 428 -640 480 -550 640 -500 375 -334 500 -427 640 -640 480 -640 480 -463 640 -367 500 -640 427 -640 438 -500 331 -612 612 -640 480 -500 291 -600 400 -640 427 -427 640 -640 480 -640 480 -375 500 -640 428 -640 427 -500 176 -640 427 -640 425 -640 597 -640 427 -640 480 -480 640 -640 640 -640 480 -425 640 -500 375 -456 640 -640 427 -640 426 -640 519 -640 411 -375 500 -640 427 -428 640 -428 640 -640 463 -640 561 -640 361 -427 640 -640 480 -640 426 -640 480 -522 640 -640 512 -640 480 -640 480 -640 508 -640 480 -640 427 -439 640 -640 360 -640 499 -640 479 -640 480 -640 640 -640 427 -640 480 -640 427 -425 640 -375 500 -500 357 -500 375 -418 640 -640 425 -386 500 -640 426 -640 480 -640 438 -640 480 -640 429 -640 480 -500 332 -427 640 -640 424 -293 500 -425 640 -612 612 -640 546 -640 481 -640 433 -612 612 -640 480 -640 489 -640 480 -480 640 -640 480 -428 640 -328 480 -640 423 -640 426 -480 640 -640 480 -470 640 -640 425 -640 480 -640 480 -612 612 -640 480 -448 500 -575 640 -640 425 -640 480 -427 640 -640 480 -640 480 -640 480 -345 640 -640 427 -500 331 -427 640 -640 427 -640 480 -640 640 -640 478 -478 640 -640 426 -640 480 -640 480 -640 427 -640 480 -640 427 -640 640 -640 480 -640 425 -427 640 -500 375 -480 640 -500 375 -500 375 -629 640 -640 480 -640 426 -640 480 -640 427 -640 426 -480 640 -640 425 -500 375 -640 480 -640 480 -480 640 -640 426 -640 425 -640 427 -426 640 -480 640 -424 640 -640 406 -640 272 -640 480 -640 480 -424 640 -427 640 -640 480 -440 640 -375 500 -640 426 -429 640 -383 640 -640 480 -612 612 -640 426 -640 480 -640 428 -640 480 -640 480 -640 425 -640 480 -428 640 -427 640 -640 480 -640 480 -640 480 -640 427 -640 425 -640 424 -640 480 -640 430 -640 480 -640 359 -640 480 -499 500 -640 480 -640 480 -640 478 -640 360 -640 427 -640 512 -640 415 -640 480 -640 480 -612 612 -640 214 -640 426 -640 481 -640 427 -459 640 -640 427 -480 640 -480 640 -640 480 -430 640 -640 480 -640 426 -640 480 -478 640 -640 423 -640 480 -640 480 -506 640 -640 480 -640 427 -383 640 -640 425 -640 427 -500 375 -335 500 -640 480 -199 640 -640 428 -640 428 -640 480 -640 480 -480 640 -640 425 -500 375 -640 426 -500 500 -640 480 -640 427 -640 480 -640 572 -640 427 -640 424 -640 438 -500 500 -640 427 -640 423 -640 480 -640 220 -640 428 -480 640 -640 480 -640 429 -375 500 -333 500 -640 480 -640 400 -640 426 -640 429 -640 480 -640 480 -640 426 -640 428 -500 375 -640 480 -427 640 -480 640 -375 500 -500 357 -480 640 -352 640 -640 473 -640 480 -640 480 -640 427 -640 454 -640 427 -640 529 -640 480 -640 427 -640 640 -640 480 -640 352 -640 320 -640 543 -640 558 -640 480 -640 426 -640 426 -500 375 -480 640 -640 480 -640 480 -500 375 -640 427 -640 424 -500 333 -640 478 -640 427 -640 480 -640 428 -640 480 -640 428 -640 427 -500 375 -640 480 -640 425 -480 640 -435 640 -640 428 -640 379 -640 480 -640 272 -427 640 -640 426 -640 424 -640 428 -500 375 -640 480 -640 428 -640 410 -640 480 -640 426 -341 500 -640 427 -640 427 -424 640 -640 595 -640 480 -640 427 -640 425 -640 324 -640 427 -640 425 -640 480 -480 640 -480 640 -500 500 -640 427 -640 413 -640 427 -640 426 -640 428 -640 480 -640 444 -448 336 -640 426 -445 500 -500 375 -480 640 -640 427 -640 493 -500 334 -338 500 -480 640 -480 640 -640 480 -640 480 -640 640 -640 390 -640 480 -640 398 -640 504 -640 480 -640 534 -480 640 -640 480 -640 480 -640 480 -640 480 -640 427 -425 640 -375 500 -640 426 -640 430 -640 597 -500 375 -640 480 -640 474 -640 640 -500 333 -640 426 -640 428 -640 480 -640 436 -640 458 -480 640 -480 640 -426 640 -428 640 -500 345 -640 360 -640 360 -640 480 -375 500 -640 427 -500 333 -480 640 -640 480 -425 640 -640 478 -558 640 -640 410 -640 425 -428 640 -640 426 -480 640 -640 427 -471 640 -640 469 -640 427 -640 480 -640 480 -640 480 -375 500 -429 640 -640 480 -369 336 -640 443 -480 640 -640 478 -333 500 -640 428 -640 481 -640 427 -640 480 -640 428 -640 480 -640 482 -375 500 -640 512 -640 480 -640 480 -640 426 -640 640 -640 480 -640 438 -640 480 -640 427 -531 640 -480 640 -640 478 -640 425 -640 425 -640 427 -640 426 -640 431 -612 612 -411 640 -500 375 -640 427 -640 498 -640 480 -640 420 -500 376 -427 640 -640 425 -431 640 -521 640 -640 428 -480 640 -375 500 -640 427 -640 480 -640 427 -500 375 -480 640 -541 640 -640 480 -640 432 -500 364 -640 480 -500 333 -504 378 -523 640 -640 489 -640 360 -640 480 -480 640 -640 427 -640 427 -480 640 -640 427 -640 427 -500 333 -640 480 -640 427 -640 400 -640 426 -640 480 -640 425 -425 640 -640 480 -427 640 -640 541 -640 491 -640 426 -480 640 -480 640 -564 640 -640 478 -424 640 -335 500 -500 377 -640 426 -640 428 -640 430 -640 478 -640 429 -640 427 -332 500 -361 640 -640 457 -640 480 -640 427 -640 427 -640 361 -640 480 -640 480 -640 427 -480 640 -640 428 -640 424 -640 426 -480 640 -426 640 -640 426 -640 592 -640 480 -640 480 -640 480 -480 640 -640 423 -640 480 -640 480 -383 640 -500 375 -640 489 -640 480 -500 375 -640 480 -500 333 -480 640 -640 363 -427 640 -640 480 -640 426 -640 479 -427 640 -640 435 -333 500 -640 426 -640 427 -640 478 -640 441 -640 480 -480 640 -640 427 -427 640 -640 640 -500 376 -427 640 -640 426 -640 426 -640 424 -640 459 -640 457 -640 437 -640 480 -640 480 -640 399 -640 480 -480 640 -640 480 -640 480 -640 393 -375 500 -427 640 -640 480 -640 427 -640 480 -640 427 -500 375 -480 640 -480 640 -640 425 -500 387 -640 429 -640 480 -478 640 -480 640 -640 426 -500 333 -500 375 -640 480 -640 429 -640 480 -426 640 -427 640 -480 640 -500 332 -640 480 -480 640 -640 426 -640 432 -486 640 -428 640 -640 429 -640 459 -393 640 -640 425 -427 640 -640 428 -548 640 -640 411 -489 500 -640 427 -640 414 -640 427 -480 640 -500 344 -480 640 -640 503 -428 640 -500 375 -500 375 -640 444 -640 427 -500 375 -640 424 -456 640 -612 612 -375 500 -427 640 -500 333 -640 480 -640 480 -640 480 -640 480 -640 425 -640 512 -582 640 -480 640 -640 480 -640 515 -500 369 -640 428 -640 480 -478 640 -640 427 -500 332 -577 640 -500 375 -444 640 -640 453 -640 360 -640 633 -640 383 -640 480 -640 427 -640 406 -500 357 -480 640 -640 424 -640 480 -640 480 -579 640 -640 480 -640 480 -640 427 -450 338 -640 480 -640 356 -514 640 -425 567 -640 480 -600 400 -427 640 -640 431 -640 480 -640 426 -640 480 -640 426 -612 612 -640 480 -480 640 -468 640 -640 480 -640 443 -640 427 -425 640 -640 519 -480 640 -333 500 -427 640 -640 427 -428 640 -640 425 -640 425 -640 480 -640 480 -640 480 -500 375 -640 425 -480 640 -640 491 -640 486 -480 640 -500 375 -640 427 -640 428 -640 308 -640 365 -479 640 -500 333 -512 640 -640 480 -640 480 -640 480 -640 361 -640 427 -640 480 -554 640 -500 332 -640 427 -640 425 -640 512 -640 480 -500 375 -375 500 -640 448 -640 426 -305 480 -612 612 -375 500 -640 452 -640 425 -640 480 -640 427 -640 428 -640 426 -500 332 -640 425 -640 360 -612 612 -480 640 -640 429 -428 640 -500 375 -640 413 -640 480 -640 427 -500 375 -476 640 -640 480 -640 480 -640 427 -640 480 -345 500 -500 375 -480 640 -640 427 -640 427 -640 360 -392 640 -500 375 -640 427 -574 640 -640 428 -640 427 -640 438 -500 375 -640 424 -480 640 -640 427 -640 427 -500 375 -640 427 -640 425 -640 425 -480 640 -640 477 -640 480 -640 424 -640 494 -640 424 -333 500 -453 640 -500 375 -610 407 -612 612 -640 428 -426 640 -375 500 -640 480 -640 427 -425 640 -640 427 -640 640 -449 401 -640 426 -427 640 -640 429 -640 428 -600 400 -640 640 -640 464 -500 375 -640 427 -640 427 -640 480 -640 360 -480 640 -640 425 -525 525 -426 640 -640 427 -500 375 -640 427 -640 427 -425 640 -480 640 -640 573 -630 450 -640 480 -612 612 -640 480 -480 640 -640 506 -640 425 -640 405 -360 640 -640 480 -640 622 -640 425 -375 500 -640 427 -612 612 -640 457 -568 640 -640 480 -640 427 -640 426 -480 640 -427 640 -640 427 -640 428 -640 400 -640 480 -480 640 -640 428 -480 640 -480 640 -480 640 -599 640 -640 480 -640 480 -640 426 -640 478 -640 480 -640 427 -640 425 -375 500 -640 480 -375 500 -607 640 -375 500 -640 480 -640 434 -638 640 -493 500 -640 480 -640 506 -640 427 -640 427 -463 640 -640 360 -640 427 -640 619 -640 484 -375 500 -640 480 -538 640 -500 333 -640 429 -500 375 -500 488 -640 428 -640 427 -438 640 -640 480 -640 393 -640 427 -640 480 -500 330 -640 572 -500 366 -640 480 -640 425 -640 424 -640 478 -500 381 -640 427 -640 480 -640 399 -640 499 -640 426 -640 402 -375 500 -479 640 -500 335 -640 428 -640 428 -500 375 -640 480 -500 341 -640 483 -640 361 -424 640 -640 480 -640 427 -640 483 -640 427 -640 424 -640 480 -640 424 -480 640 -640 640 -427 640 -400 300 -640 480 -375 500 -640 480 -640 429 -500 332 -323 486 -640 480 -640 273 -640 427 -640 466 -640 506 -640 463 -640 480 -640 480 -640 640 -427 640 -640 480 -426 640 -640 480 -640 456 -480 640 -640 480 -640 480 -500 376 -500 375 -640 480 -480 640 -640 383 -640 480 -640 480 -420 640 -640 480 -640 427 -374 500 -640 471 -612 612 -640 480 -640 427 -640 480 -500 375 -640 480 -640 480 -640 427 -640 452 -640 402 -640 352 -640 427 -500 375 -640 480 -375 500 -640 640 -640 464 -427 640 -500 296 -376 500 -640 544 -480 640 -640 480 -500 332 -640 426 -640 426 -640 463 -640 426 -640 466 -640 480 -371 500 -500 640 -500 375 -333 500 -640 480 -500 333 -240 193 -480 640 -426 640 -640 424 -640 480 -640 480 -480 640 -571 640 -480 640 -640 640 -640 480 -375 500 -640 427 -428 640 -640 472 -640 428 -640 480 -377 500 -480 640 -640 426 -500 333 -480 640 -640 360 -640 478 -431 640 -536 640 -640 426 -640 424 -612 612 -480 640 -427 640 -640 480 -640 480 -640 427 -427 640 -425 640 -640 427 -500 375 -436 640 -640 427 -640 437 -333 500 -480 640 -612 612 -559 640 -640 427 -640 426 -640 480 -640 400 -640 406 -640 358 -640 424 -500 315 -640 426 -640 480 -640 427 -640 480 -640 424 -427 640 -398 500 -640 480 -500 313 -640 360 -640 480 -640 360 -640 480 -640 427 -640 426 -480 640 -640 456 -500 346 -500 475 -640 427 -640 427 -640 414 -428 640 -640 428 -428 640 -500 332 -426 640 -640 427 -480 640 -640 480 -640 480 -500 375 -500 375 -640 307 -640 480 -480 640 -640 472 -640 426 -426 640 -640 428 -427 640 -480 640 -480 640 -340 500 -640 480 -640 428 -640 502 -640 480 -640 457 -640 552 -640 359 -640 428 -500 375 -640 480 -480 640 -500 310 -524 640 -640 427 -640 427 -640 480 -500 375 -478 640 -640 480 -426 640 -640 433 -375 500 -640 616 -640 428 -640 480 -640 480 -500 334 -427 640 -640 429 -640 427 -640 480 -640 480 -640 480 -640 427 -640 480 -573 640 -427 640 -640 480 -640 427 -500 375 -640 480 -500 373 -478 640 -640 429 -371 500 -480 640 -640 440 -640 425 -640 480 -500 375 -427 640 -500 332 -427 640 -640 480 -334 500 -640 427 -640 427 -640 480 -428 640 -375 500 -640 427 -640 383 -427 640 -500 333 -640 427 -500 375 -427 640 -640 480 -640 425 -640 427 -640 427 -640 427 -640 358 -500 375 -640 427 -640 480 -640 480 -478 640 -480 640 -640 360 -640 480 -640 427 -480 640 -333 500 -640 427 -640 512 -640 480 -500 334 -480 640 -640 427 -583 640 -480 640 -640 480 -640 426 -640 427 -640 512 -480 640 -640 427 -640 480 -640 625 -462 640 -640 480 -640 480 -640 339 -640 427 -500 341 -640 427 -640 462 -500 375 -640 427 -500 375 -375 500 -640 427 -640 478 -640 480 -435 640 -640 426 -640 427 -427 640 -640 448 -640 426 -500 375 -640 426 -640 480 -640 427 -375 500 -640 427 -500 375 -488 640 -640 480 -640 426 -640 640 -480 640 -320 240 -640 483 -640 426 -640 489 -640 426 -640 359 -473 500 -640 480 -640 433 -612 612 -640 428 -640 457 -500 375 -413 500 -640 474 -640 458 -427 640 -375 500 -421 640 -640 427 -476 640 -568 640 -640 426 -640 425 -424 640 -500 324 -640 480 -640 427 -640 426 -500 375 -426 640 -640 480 -640 427 -375 500 -640 426 -640 640 -640 425 -640 480 -640 480 -640 480 -640 427 -612 612 -640 413 -640 480 -500 333 -640 498 -640 427 -302 500 -640 354 -424 640 -427 640 -480 640 -640 492 -428 640 -640 496 -640 428 -612 612 -480 640 -640 483 -640 480 -640 480 -640 480 -640 479 -640 427 -640 425 -640 426 -640 428 -500 375 -640 429 -640 429 -500 375 -480 640 -390 293 -480 640 -640 425 -444 640 -640 640 -500 375 -640 480 -640 427 -640 427 -500 499 -500 334 -640 480 -414 640 -500 375 -640 478 -486 640 -640 480 -478 640 -640 359 -640 480 -480 640 -640 480 -640 427 -640 480 -640 640 -500 500 -414 310 -640 428 -600 469 -640 459 -500 375 -640 480 -449 600 -640 427 -640 480 -480 640 -640 428 -640 426 -640 480 -426 640 -640 480 -640 424 -640 433 -640 480 -640 480 -640 434 -375 500 -640 480 -500 334 -640 428 -640 427 -427 640 -640 480 -640 480 -640 427 -640 427 -640 480 -640 480 -500 363 -640 480 -640 480 -480 640 -640 480 -640 480 -640 480 -480 640 -640 480 -480 640 -640 480 -640 427 -500 281 -640 427 -426 640 -478 640 -640 480 -640 480 -640 427 -640 427 -573 640 -640 297 -500 333 -640 428 -640 480 -640 640 -480 640 -640 494 -640 427 -640 480 -428 640 -640 427 -427 640 -640 480 -500 375 -640 427 -500 372 -432 640 -640 426 -427 640 -640 427 -429 640 -640 393 -478 640 -640 426 -640 426 -500 332 -499 500 -640 484 -640 640 -640 424 -375 500 -500 375 -640 428 -640 426 -427 640 -500 333 -640 426 -612 612 -640 480 -640 427 -640 360 -640 480 -640 480 -539 640 -615 310 -480 640 -640 640 -640 453 -427 640 -640 513 -640 427 -640 480 -640 480 -640 403 -612 612 -500 375 -640 480 -640 427 -640 640 -640 480 -640 427 -480 640 -640 480 -640 480 -640 483 -640 480 -640 427 -500 375 -640 480 -640 490 -612 612 -612 612 -500 375 -640 478 -480 640 -480 640 -640 480 -640 480 -426 640 -640 478 -640 480 -640 425 -640 512 -426 640 -640 383 -640 427 -640 480 -458 640 -640 510 -480 640 -640 478 -640 426 -640 480 -640 427 -640 480 -640 412 -640 480 -640 428 -640 480 -640 426 -640 480 -500 375 -640 392 -640 427 -640 427 -480 640 -600 400 -640 426 -640 479 -640 425 -640 480 -640 480 -486 640 -426 640 -640 427 -640 426 -640 425 -640 360 -640 426 -427 640 -334 500 -500 375 -640 427 -640 427 -640 480 -581 640 -640 480 -640 480 -480 640 -640 427 -640 480 -640 427 -640 425 -640 480 -480 640 -640 427 -640 422 -640 426 -640 480 -480 640 -640 480 -640 480 -640 427 -640 360 -640 480 -640 427 -426 640 -542 640 -640 480 -640 482 -640 428 -480 640 -640 424 -375 500 -480 640 -427 640 -640 480 -640 480 -640 427 -640 427 -640 427 -427 640 -500 375 -480 640 -640 480 -375 500 -640 427 -640 480 -640 495 -640 409 -640 427 -640 480 -640 425 -640 361 -375 500 -480 640 -480 640 -500 500 -640 361 -480 640 -500 332 -640 427 -500 375 -480 640 -640 388 -500 375 -640 366 -640 480 -426 640 -640 428 -640 427 -640 428 -424 640 -500 375 -612 612 -640 480 -640 512 -640 427 -640 428 -480 640 -640 425 -640 480 -640 434 -640 451 -500 334 -640 430 -500 375 -640 480 -640 516 -640 480 -427 640 -480 640 -640 480 -640 425 -640 480 -640 480 -640 427 -640 427 -640 427 -640 480 -640 480 -640 381 -640 480 -640 401 -500 335 -640 361 -640 425 -429 640 -480 640 -512 640 -427 640 -640 640 -480 640 -500 375 -640 427 -480 640 -640 480 -640 429 -375 500 -640 506 -428 640 -640 427 -640 480 -640 577 -500 375 -640 559 -640 360 -480 640 -640 427 -612 612 -640 428 -640 512 -480 640 -640 424 -511 640 -500 375 -480 640 -640 429 -640 480 -640 640 -500 375 -640 426 -640 427 -640 481 -640 396 -640 426 -640 480 -500 375 -500 333 -480 640 -454 640 -333 500 -640 480 -640 447 -640 480 -640 427 -640 480 -640 480 -640 427 -640 200 -500 375 -640 480 -640 480 -640 427 -640 425 -640 427 -640 478 -426 640 -640 427 -357 500 -640 424 -640 480 -640 425 -640 426 -640 426 -640 480 -500 375 -480 640 -640 414 -500 346 -640 427 -478 640 -640 349 -640 427 -640 427 -640 638 -640 427 -512 640 -640 378 -640 425 -640 425 -500 375 -375 500 -640 425 -640 427 -640 480 -640 395 -640 348 -640 480 -640 480 -427 640 -500 375 -640 426 -500 340 -375 500 -640 480 -640 480 -640 480 -426 640 -480 640 -326 640 -640 427 -640 483 -640 424 -640 515 -640 425 -640 391 -480 640 -640 360 -640 427 -612 612 -640 424 -465 640 -480 640 -640 426 -494 500 -640 478 -640 427 -640 427 -640 427 -480 640 -640 558 -640 480 -500 334 -640 429 -640 480 -640 426 -640 506 -640 480 -640 640 -640 480 -640 480 -500 375 -640 427 -640 426 -640 426 -612 612 -640 428 -640 480 -640 480 -640 426 -427 640 -640 428 -640 427 -640 427 -640 480 -640 427 -640 480 -640 427 -612 612 -640 480 -640 480 -425 640 -640 427 -640 424 -640 427 -480 640 -640 480 -640 425 -500 332 -640 427 -640 640 -375 500 -427 640 -500 375 -640 480 -640 427 -500 334 -427 640 -424 640 -427 640 -640 339 -640 480 -640 427 -500 333 -481 640 -200 150 -640 480 -425 640 -640 480 -428 640 -640 480 -640 512 -600 400 -640 428 -640 480 -640 359 -428 640 -612 612 -640 480 -640 425 -640 480 -500 334 -429 640 -640 425 -640 427 -419 640 -640 480 -426 640 -612 612 -640 427 -640 427 -640 458 -375 500 -428 640 -500 375 -640 427 -480 640 -640 480 -480 640 -640 480 -500 375 -640 427 -480 640 -640 457 -500 333 -640 480 -640 483 -640 294 -640 427 -375 500 -640 480 -640 426 -640 427 -640 427 -640 426 -640 208 -640 424 -290 640 -640 480 -640 480 -640 480 -400 600 -640 424 -640 426 -640 480 -426 640 -640 426 -640 480 -427 640 -427 640 -640 480 -480 640 -640 441 -366 640 -640 427 -640 426 -500 375 -480 640 -375 500 -640 449 -640 480 -640 427 -457 640 -640 428 -480 640 -430 640 -480 640 -600 450 -640 453 -640 480 -640 238 -640 480 -640 428 -640 424 -500 375 -640 185 -640 427 -335 500 -640 478 -640 427 -427 640 -500 333 -640 480 -428 640 -640 480 -640 427 -386 640 -640 457 -640 480 -640 433 -640 429 -640 427 -640 480 -640 478 -640 480 -612 612 -640 428 -640 323 -640 439 -640 480 -640 493 -640 480 -427 640 -640 427 -640 455 -640 480 -640 425 -640 427 -375 500 -500 333 -640 480 -640 480 -640 480 -427 640 -480 640 -640 436 -375 500 -427 640 -640 427 -426 640 -457 640 -640 359 -640 480 -640 583 -640 424 -500 375 -441 640 -640 425 -640 426 -640 360 -427 640 -640 441 -640 426 -640 480 -640 427 -612 612 -640 425 -640 425 -640 427 -640 427 -640 480 -360 237 -375 500 -480 640 -524 640 -640 408 -427 640 -612 612 -640 480 -428 640 -640 480 -640 480 -640 426 -500 357 -500 364 -500 375 -640 423 -640 480 -640 427 -612 612 -640 484 -640 423 -544 640 -640 427 -640 480 -500 375 -500 500 -425 640 -426 640 -500 333 -480 640 -640 427 -402 640 -640 424 -341 280 -640 427 -640 512 -640 480 -640 491 -480 640 -640 480 -500 375 -640 480 -640 400 -500 333 -426 640 -640 427 -640 480 -500 375 -500 400 -500 375 -375 500 -640 479 -640 406 -640 514 -427 640 -640 222 -500 375 -459 640 -480 640 -640 425 -500 375 -640 427 -640 539 -640 425 -640 448 -640 427 -426 640 -500 323 -640 327 -427 640 -359 640 -640 428 -640 426 -640 425 -425 640 -424 640 -500 379 -427 640 -640 427 -375 500 -640 480 -640 480 -640 468 -640 480 -427 640 -640 480 -640 480 -640 426 -640 428 -640 426 -640 426 -640 480 -640 480 -640 403 -332 500 -500 333 -426 640 -640 458 -480 640 -500 375 -446 640 -640 480 -640 480 -640 384 -500 375 -640 426 -640 478 -500 375 -640 479 -500 375 -500 311 -640 543 -640 427 -500 375 -640 412 -480 640 -480 640 -375 500 -640 427 -640 427 -480 640 -640 426 -640 424 -480 640 -640 451 -640 427 -640 640 -640 448 -640 480 -640 480 -640 427 -640 427 -640 512 -640 480 -480 640 -640 481 -640 417 -640 425 -500 375 -640 563 -640 427 -640 426 -640 427 -640 427 -640 459 -640 459 -640 480 -640 438 -429 640 -640 545 -640 426 -612 612 -640 480 -640 428 -640 424 -640 427 -635 640 -640 417 -640 427 -480 360 -500 375 -500 375 -640 417 -640 360 -427 640 -500 375 -480 640 -640 389 -640 480 -640 480 -640 443 -640 427 -640 427 -640 427 -640 442 -512 640 -640 480 -494 640 -640 427 -612 612 -640 427 -612 612 -500 500 -640 427 -640 427 -640 427 -640 424 -480 640 -640 429 -640 356 -640 442 -640 458 -640 434 -640 427 -640 427 -480 640 -488 640 -640 480 -640 452 -427 640 -640 428 -640 425 -500 375 -427 640 -640 426 -640 480 -428 640 -483 640 -640 480 -640 429 -640 428 -640 480 -640 412 -640 427 -500 375 -427 640 -500 473 -640 640 -640 480 -640 427 -640 480 -640 429 -640 427 -426 640 -424 640 -640 400 -640 479 -640 490 -640 480 -480 640 -640 480 -500 333 -640 457 -640 427 -640 480 -428 640 -640 480 -640 425 -500 375 -640 279 -500 228 -640 480 -640 480 -640 480 -500 500 -640 456 -640 536 -500 375 -640 427 -640 478 -426 640 -480 640 -480 640 -500 400 -640 480 -480 640 -640 351 -640 480 -640 480 -640 427 -640 427 -640 480 -612 612 -640 360 -640 360 -640 332 -640 480 -500 349 -500 333 -640 386 -382 500 -500 375 -480 640 -614 640 -640 418 -500 375 -640 428 -640 640 -640 359 -640 480 -640 464 -541 640 -500 375 -640 426 -640 480 -640 427 -640 613 -500 349 -640 425 -500 375 -640 480 -480 640 -630 640 -640 427 -640 480 -640 480 -640 480 -500 375 -400 600 -500 375 -640 457 -640 461 -640 480 -640 480 -640 337 -512 640 -640 425 -427 640 -640 443 -640 640 -612 612 -500 375 -640 480 -640 425 -640 480 -640 428 -427 640 -640 512 -375 500 -480 640 -640 480 -640 524 -640 640 -640 480 -640 428 -640 480 -428 640 -640 363 -640 480 -640 445 -428 640 -640 480 -640 257 -640 281 -640 426 -426 640 -640 480 -640 425 -500 375 -640 426 -427 640 -375 500 -640 427 -640 359 -640 423 -640 427 -640 426 -640 480 -480 640 -640 480 -640 483 -640 480 -640 427 -640 427 -640 425 -640 359 -640 429 -604 640 -640 427 -500 500 -640 360 -640 480 -640 456 -640 485 -500 290 -640 480 -640 480 -480 640 -640 480 -640 426 -640 489 -478 640 -640 427 -640 427 -640 480 -640 480 -484 640 -640 480 -433 640 -640 480 -612 612 -640 480 -640 480 -480 640 -480 500 -426 640 -640 457 -640 425 -427 640 -640 480 -426 640 -487 640 -640 425 -421 640 -500 328 -375 500 -640 480 -335 500 -640 427 -640 427 -640 571 -376 500 -612 612 -500 500 -640 243 -640 479 -640 480 -533 640 -333 500 -640 639 -425 640 -640 516 -640 427 -480 640 -612 612 -640 426 -640 480 -480 640 -427 640 -640 428 -500 314 -640 480 -640 427 -427 640 -640 480 -500 309 -640 480 -480 640 -640 479 -640 427 -640 480 -640 480 -600 450 -640 428 -640 480 -480 640 -640 426 -640 480 -640 480 -640 427 -640 388 -428 640 -426 640 -500 375 -640 427 -640 480 -640 396 -640 480 -640 480 -640 426 -640 427 -640 427 -640 480 -640 480 -640 400 -640 427 -640 277 -500 333 -640 480 -640 424 -640 480 -640 480 -640 379 -640 480 -479 640 -375 500 -640 427 -498 640 -640 427 -480 640 -480 640 -640 427 -640 480 -427 640 -480 640 -640 480 -640 316 -640 427 -500 375 -640 427 -640 427 -458 640 -500 333 -500 499 -620 441 -640 425 -640 480 -640 448 -500 331 -528 640 -640 425 -480 640 -640 427 -193 225 -640 381 -640 427 -640 427 -640 430 -640 482 -640 469 -640 386 -640 425 -427 640 -640 480 -640 640 -640 480 -640 481 -425 640 -375 500 -640 427 -500 332 -640 427 -640 480 -640 480 -640 393 -427 640 -480 640 -640 427 -640 427 -480 640 -640 480 -640 502 -640 425 -500 375 -500 205 -502 640 -426 640 -640 480 -640 480 -640 428 -640 480 -640 427 -640 480 -640 428 -499 500 -500 373 -480 640 -480 640 -640 427 -640 480 -640 480 -640 427 -640 426 -640 640 -640 424 -640 427 -500 335 -640 480 -640 360 -640 480 -640 428 -640 483 -640 427 -640 557 -640 426 -640 478 -426 640 -640 480 -640 427 -427 640 -640 480 -480 640 -640 423 -640 459 -427 640 -500 333 -640 427 -500 375 -640 399 -612 612 -640 480 -640 480 -640 480 -500 375 -640 480 -500 310 -640 480 -640 425 -500 269 -612 612 -640 360 -640 480 -640 419 -640 427 -500 332 -640 480 -375 500 -500 357 -480 640 -640 427 -152 205 -640 426 -500 375 -640 424 -427 640 -640 427 -640 427 -480 640 -640 427 -640 480 -640 442 -480 640 -427 640 -500 333 -632 640 -500 337 -640 428 -375 500 -436 640 -640 428 -500 333 -640 480 -480 640 -640 480 -640 480 -640 360 -640 480 -640 466 -480 640 -640 427 -360 480 -640 480 -640 427 -500 348 -480 640 -640 426 -457 640 -640 427 -640 480 -640 480 -480 640 -640 426 -640 427 -360 640 -640 606 -612 612 -640 480 -640 480 -442 640 -640 427 -427 640 -640 428 -640 480 -640 480 -640 457 -612 612 -640 427 -500 375 -640 512 -640 480 -500 375 -640 428 -426 640 -640 480 -640 480 -640 480 -640 480 -640 480 -480 640 -640 459 -640 426 -480 640 -640 425 -550 365 -640 359 -640 480 -640 480 -640 480 -640 427 -640 427 -640 425 -640 415 -464 640 -424 640 -640 480 -428 640 -640 353 -640 426 -640 427 -640 461 -640 378 -640 427 -640 254 -640 424 -640 424 -380 640 -427 640 -640 427 -640 427 -500 333 -640 480 -640 430 -427 640 -640 480 -612 612 -334 500 -640 427 -640 433 -640 480 -500 375 -640 427 -640 313 -478 640 -640 481 -480 640 -640 427 -529 640 -640 480 -640 480 -478 640 -640 448 -640 640 -640 427 -640 496 -640 480 -640 428 -640 480 -640 391 -640 427 -640 590 -500 167 -640 505 -427 640 -640 480 -640 480 -612 612 -640 329 -640 425 -612 612 -640 478 -640 360 -427 640 -640 465 -640 634 -640 636 -640 429 -427 640 -640 427 -640 480 -640 427 -480 640 -640 427 -640 480 -640 480 -357 500 -492 640 -640 360 -612 612 -640 480 -427 640 -427 640 -480 640 -640 429 -500 375 -500 375 -600 445 -500 314 -640 480 -640 428 -500 374 -640 426 -480 640 -640 482 -640 425 -640 480 -640 430 -546 640 -640 427 -640 480 -640 480 -640 480 -640 480 -415 500 -640 473 -640 480 -500 352 -640 428 -612 612 -640 477 -640 480 -640 480 -503 640 -480 640 -640 427 -480 640 -500 375 -640 480 -564 640 -424 640 -427 640 -640 426 -640 500 -640 480 -640 321 -612 612 -640 480 -640 360 -640 537 -640 428 -500 375 -640 427 -500 332 -376 500 -631 640 -373 500 -427 640 -640 427 -640 425 -640 427 -428 640 -500 375 -500 332 -640 480 -640 480 -640 424 -333 500 -640 424 -640 471 -640 478 -500 333 -640 414 -640 427 -640 480 -426 640 -640 427 -427 640 -427 640 -640 424 -640 480 -640 320 -640 480 -640 477 -427 640 -640 427 -640 457 -640 640 -612 612 -480 640 -500 332 -640 384 -427 640 -640 427 -640 433 -640 395 -640 480 -350 400 -500 375 -426 640 -640 427 -600 487 -500 375 -427 640 -427 640 -640 270 -640 480 -480 640 -375 500 -500 375 -640 479 -640 480 -375 500 -640 480 -640 354 -509 640 -480 640 -640 434 -487 640 -640 427 -480 640 -640 426 -640 428 -500 333 -640 427 -640 425 -500 375 -500 375 -640 427 -640 429 -640 458 -480 640 -477 640 -640 428 -640 427 -480 640 -640 427 -640 427 -640 480 -640 359 -640 391 -480 640 -640 425 -427 640 -640 640 -640 425 -640 616 -640 480 -360 640 -640 480 -640 480 -500 375 -427 640 -498 640 -640 432 -457 640 -640 480 -640 480 -640 427 -640 361 -640 380 -640 480 -640 479 -640 480 -640 494 -640 427 -640 428 -480 640 -427 640 -640 427 -640 427 -640 480 -640 480 -500 375 -640 425 -640 486 -640 480 -640 427 -640 467 -640 480 -426 640 -640 427 -640 401 -640 427 -640 429 -426 640 -640 480 -640 480 -480 640 -640 427 -640 413 -640 303 -640 427 -640 480 -640 441 -500 375 -334 500 -640 424 -640 426 -640 480 -640 426 -640 360 -427 640 -427 640 -500 371 -640 472 -640 314 -600 480 -427 640 -500 375 -480 640 -445 500 -640 480 -612 612 -482 294 -427 640 -640 427 -427 640 -640 425 -360 640 -640 480 -426 640 -539 640 -480 640 -500 375 -640 480 -493 640 -640 426 -426 640 -640 512 -640 364 -640 622 -500 375 -616 640 -640 425 -375 500 -640 359 -640 480 -640 480 -640 480 -640 426 -427 640 -640 449 -640 512 -640 425 -640 427 -640 425 -480 640 -480 640 -640 480 -640 480 -640 640 -640 438 -640 428 -640 346 -640 513 -480 640 -363 640 -424 640 -640 480 -640 480 -640 452 -640 512 -640 425 -500 375 -640 427 -640 427 -640 427 -640 427 -480 640 -640 451 -640 424 -640 478 -640 408 -640 427 -426 640 -640 348 -640 427 -640 360 -640 480 -640 469 -640 480 -640 480 -640 360 -500 375 -612 612 -500 375 -427 640 -640 425 -482 640 -640 480 -640 216 -640 480 -480 640 -640 427 -480 640 -640 478 -640 427 -640 426 -640 480 -640 480 -640 617 -640 427 -640 425 -640 466 -640 480 -640 480 -612 612 -427 640 -612 612 -640 383 -640 480 -426 640 -640 480 -500 375 -640 486 -640 640 -425 640 -612 612 -640 427 -640 438 -640 427 -640 426 -640 427 -480 640 -480 640 -427 640 -480 640 -640 480 -640 427 -612 612 -640 413 -640 480 -480 640 -500 486 -427 640 -640 427 -640 428 -640 426 -640 360 -640 427 -640 434 -418 640 -640 459 -640 481 -640 480 -612 612 -640 480 -640 480 -535 640 -640 480 -640 359 -480 640 -640 427 -640 404 -426 640 -640 480 -640 427 -640 478 -428 640 -640 427 -640 428 -640 427 -428 640 -640 568 -640 425 -428 640 -640 427 -640 480 -428 640 -640 426 -480 640 -500 375 -640 427 -640 480 -640 480 -640 424 -500 375 -640 512 -640 480 -480 640 -472 500 -448 640 -640 480 -640 427 -640 426 -640 427 -640 533 -640 480 -640 512 -640 480 -640 382 -640 424 -640 428 -500 375 -640 426 -640 428 -640 480 -640 427 -640 360 -480 640 -427 640 -640 480 -640 480 -640 426 -640 403 -640 480 -640 426 -640 480 -500 375 -640 372 -640 480 -640 480 -640 480 -500 375 -640 480 -361 500 -500 375 -640 480 -640 427 -640 428 -640 427 -640 480 -426 640 -640 480 -640 427 -640 424 -640 493 -640 426 -500 333 -640 448 -605 640 -500 333 -640 480 -500 500 -640 427 -426 640 -640 625 -640 419 -640 480 -640 478 -640 427 -640 427 -640 480 -640 427 -640 360 -640 427 -640 427 -443 460 -640 480 -500 333 -479 640 -640 381 -500 375 -640 480 -640 480 -360 640 -640 409 -427 640 -640 480 -640 480 -640 426 -640 425 -640 480 -640 480 -640 480 -425 640 -480 640 -640 427 -640 427 -640 480 -640 478 -640 426 -375 500 -640 427 -424 640 -640 427 -612 612 -640 253 -427 640 -425 640 -640 601 -500 366 -360 640 -425 640 -612 612 -640 425 -640 536 -424 640 -500 341 -500 339 -427 640 -640 427 -640 361 -640 480 -640 480 -290 359 -640 482 -427 640 -640 427 -640 427 -427 640 -640 480 -451 640 -640 480 -640 427 -640 427 -640 480 -480 640 -640 512 -640 480 -426 640 -640 360 -640 427 -500 375 -640 480 -612 612 -640 480 -640 400 -640 383 -640 480 -640 640 -500 333 -500 375 -375 500 -640 480 -640 481 -612 612 -640 304 -640 480 -640 480 -480 640 -640 480 -640 427 -500 383 -640 480 -500 383 -640 477 -612 612 -640 480 -426 640 -640 425 -640 480 -612 612 -480 640 -375 500 -640 480 -612 612 -640 428 -500 375 -640 454 -640 480 -640 457 -640 481 -640 359 -612 612 -427 640 -375 500 -375 500 -640 425 -640 404 -612 612 -427 640 -500 334 -640 383 -640 480 -400 300 -640 479 -457 640 -640 432 -333 500 -640 480 -640 480 -427 640 -375 500 -480 640 -640 427 -640 427 -640 425 -640 428 -500 375 -640 427 -469 640 -640 480 -640 480 -640 480 -427 640 -375 500 -333 500 -609 640 -640 427 -640 480 -612 612 -640 506 -373 500 -480 640 -640 480 -640 512 -500 380 -640 480 -612 612 -612 612 -640 427 -640 391 -640 469 -640 481 -640 434 -640 427 -640 480 -375 500 -640 427 -640 325 -640 595 -640 538 -640 512 -640 427 -640 480 -450 300 -640 427 -640 427 -500 375 -640 426 -640 426 -640 480 -640 424 -640 427 -640 482 -640 480 -640 427 -640 513 -640 427 -480 640 -480 640 -427 640 -370 640 -640 480 -640 426 -640 480 -640 427 -480 640 -640 427 -640 425 -640 427 -640 480 -612 612 -335 500 -640 412 -480 640 -480 640 -439 640 -500 382 -640 616 -640 480 -427 640 -640 427 -640 427 -500 189 -438 640 -480 640 -640 426 -640 480 -640 480 -640 427 -500 375 -500 333 -530 640 -640 424 -480 640 -426 640 -426 640 -640 428 -640 426 -640 425 -375 500 -640 424 -500 333 -427 640 -427 640 -435 640 -640 483 -640 315 -640 427 -427 640 -640 360 -640 512 -640 383 -375 500 -478 640 -640 340 -640 426 -640 428 -640 427 -640 480 -250 312 -640 480 -640 427 -640 431 -640 425 -640 426 -640 428 -640 490 -500 375 -640 427 -640 480 -480 640 -640 427 -427 640 -640 427 -480 640 -612 612 -512 640 -640 428 -500 357 -640 480 -640 480 -640 427 -427 640 -640 427 -640 427 -640 427 -640 425 -640 480 -640 480 -612 612 -640 480 -428 640 -500 375 -640 537 -500 333 -640 480 -383 640 -500 375 -370 277 -640 427 -640 404 -640 451 -640 483 -500 375 -640 426 -480 640 -640 427 -480 640 -375 500 -640 427 -640 480 -640 425 -640 366 -428 640 -640 452 -640 426 -425 640 -640 361 -640 381 -640 428 -500 375 -640 360 -426 640 -500 334 -640 427 -500 375 -640 424 -640 427 -500 375 -640 428 -375 500 -640 424 -480 640 -480 640 -375 500 -640 427 -640 480 -640 475 -427 640 -640 423 -640 427 -640 480 -480 640 -640 423 -354 640 -600 450 -480 640 -612 612 -640 427 -375 500 -640 421 -640 408 -480 640 -480 640 -500 375 -640 427 -640 480 -640 360 -640 480 -640 480 -640 640 -640 480 -378 640 -480 640 -375 500 -640 426 -640 423 -375 500 -640 426 -640 425 -500 375 -480 640 -360 640 -640 425 -422 640 -640 427 -640 480 -481 640 -427 640 -640 427 -640 214 -640 426 -500 281 -640 485 -640 425 -640 425 -640 480 -500 375 -640 427 -375 500 -640 480 -640 427 -427 640 -640 513 -640 480 -382 500 -640 428 -640 480 -640 480 -640 564 -640 427 -483 640 -500 321 -640 480 -500 333 -500 347 -480 640 -333 500 -640 427 -640 426 -612 612 -640 427 -640 480 -478 640 -640 427 -640 479 -640 478 -640 427 -640 427 -640 425 -640 457 -333 500 -632 640 -480 640 -640 428 -500 334 -640 363 -452 640 -640 480 -427 640 -640 425 -640 480 -500 486 -640 480 -426 640 -640 381 -426 640 -640 428 -640 481 -640 453 -375 500 -500 338 -640 427 -640 424 -640 480 -640 640 -640 480 -500 375 -640 326 -640 446 -640 427 -376 342 -640 427 -640 512 -500 375 -640 427 -480 640 -640 426 -640 426 -426 640 -640 427 -640 426 -640 427 -640 427 -640 360 -597 640 -640 427 -640 427 -640 480 -640 353 -640 447 -640 427 -368 500 -480 640 -640 425 -640 480 -500 332 -640 480 -640 480 -333 500 -640 426 -640 426 -640 426 -640 480 -500 375 -640 480 -640 427 -404 500 -640 480 -500 375 -640 400 -640 446 -640 233 -480 640 -427 640 -500 375 -640 425 -640 436 -640 480 -320 240 -640 480 -640 451 -640 405 -593 395 -427 640 -640 379 -640 480 -640 427 -432 640 -640 425 -640 427 -640 428 -640 480 -480 640 -500 375 -640 450 -640 480 -428 640 -426 640 -640 419 -375 500 -640 480 -640 427 -640 480 -640 456 -640 436 -500 500 -427 640 -640 427 -334 500 -640 566 -612 612 -640 445 -500 375 -480 640 -640 424 -640 480 -640 434 -640 427 -500 375 -640 480 -480 640 -500 333 -480 640 -640 425 -640 480 -640 480 -334 500 -640 480 -428 640 -640 480 -640 427 -480 320 -480 640 -640 355 -640 411 -500 375 -640 425 -461 615 -640 486 -480 640 -640 427 -640 480 -640 427 -640 373 -500 341 -640 427 -640 480 -640 427 -424 640 -640 480 -640 425 -640 480 -640 208 -640 543 -640 434 -640 480 -428 640 -500 375 -640 480 -640 480 -640 466 -500 375 -640 480 -500 384 -640 426 -640 427 -640 424 -640 480 -640 480 -500 500 -640 427 -480 640 -640 428 -640 427 -640 481 -500 439 -640 458 -640 426 -500 375 -640 425 -640 437 -640 469 -640 426 -640 427 -480 640 -640 480 -640 425 -640 427 -640 481 -640 428 -640 480 -640 426 -612 612 -640 480 -500 476 -500 416 -640 427 -640 450 -424 640 -640 480 -640 428 -640 426 -425 640 -640 479 -640 480 -640 427 -640 427 -426 640 -360 640 -640 425 -519 640 -640 427 -640 441 -640 640 -468 640 -375 500 -500 375 -640 397 -640 480 -427 640 -500 375 -427 640 -500 375 -640 449 -640 215 -640 480 -640 479 -640 480 -640 480 -640 509 -500 375 -427 640 -640 425 -640 428 -640 480 -640 480 -640 480 -640 638 -640 480 -640 480 -640 480 -640 348 -640 454 -640 430 -640 480 -427 640 -640 425 -640 480 -640 400 -426 640 -640 457 -640 427 -398 500 -640 480 -640 480 -427 640 -640 427 -480 640 -640 428 -640 480 -640 427 -640 427 -640 480 -500 313 -640 427 -332 500 -480 640 -640 480 -424 640 -640 480 -480 640 -480 640 -427 640 -423 640 -640 427 -428 640 -640 479 -640 480 -459 640 -640 480 -640 427 -640 480 -500 375 -640 426 -640 480 -640 427 -640 423 -640 480 -640 640 -426 640 -640 427 -500 375 -500 333 -640 428 -640 480 -640 426 -375 500 -640 427 -640 360 -640 481 -640 426 -500 431 -640 427 -640 480 -640 424 -640 399 -640 426 -640 452 -427 640 -334 500 -333 500 -314 500 -640 326 -349 640 -640 407 -526 640 -640 426 -434 640 -640 427 -426 640 -500 333 -640 425 -640 480 -640 480 -640 427 -640 436 -640 360 -482 484 -500 375 -640 480 -427 640 -500 375 -640 426 -500 334 -640 588 -427 640 -640 480 -640 425 -640 426 -640 480 -358 373 -344 500 -640 427 -561 640 -500 375 -426 640 -427 640 -640 480 -522 640 -640 480 -500 359 -640 640 -640 480 -640 480 -640 480 -475 640 -500 376 -640 427 -640 480 -640 411 -640 480 -640 486 -500 368 -500 375 -640 392 -640 429 -478 640 -640 480 -334 500 -640 428 -640 432 -612 612 -640 427 -640 480 -383 640 -640 480 -640 480 -539 640 -427 640 -640 480 -480 640 -640 424 -640 426 -640 426 -480 640 -500 375 -480 640 -640 360 -640 426 -640 426 -640 426 -640 427 -640 424 -640 383 -430 500 -640 480 -600 450 -500 375 -640 480 -640 427 -640 640 -640 426 -640 480 -640 480 -500 333 -426 640 -333 500 -640 480 -640 426 -500 332 -480 640 -640 480 -640 480 -426 640 -640 480 -500 375 -480 640 -500 208 -640 478 -612 612 -640 631 -640 480 -500 364 -640 640 -640 305 -449 640 -640 409 -640 426 -640 480 -640 480 -640 427 -640 427 -640 422 -426 640 -640 480 -640 428 -481 640 -500 375 -640 337 -640 480 -500 374 -640 480 -640 416 -500 375 -640 427 -640 427 -480 640 -427 640 -640 436 -640 480 -428 640 -426 640 -640 446 -640 592 -640 480 -640 360 -640 427 -640 480 -375 500 -640 427 -375 500 -333 500 -640 428 -427 640 -640 480 -500 375 -640 360 -600 400 -480 640 -500 331 -640 475 -640 427 -500 375 -640 427 -640 425 -426 640 -640 381 -640 427 -243 360 -480 640 -500 400 -640 480 -640 480 -640 359 -640 427 -640 426 -640 640 -640 427 -640 425 -640 454 -640 425 -640 427 -640 480 -439 640 -640 480 -640 480 -640 480 -639 640 -640 333 -640 480 -427 640 -640 480 -640 435 -640 480 -640 480 -640 478 -640 480 -640 445 -500 334 -640 480 -640 428 -640 427 -640 427 -500 375 -640 425 -640 429 -640 480 -640 427 -472 640 -640 480 -640 360 -640 424 -640 361 -640 480 -640 431 -640 426 -640 428 -640 480 -500 333 -640 427 -640 425 -640 425 -640 480 -486 640 -426 640 -640 480 -500 375 -480 640 -640 480 -427 640 -640 479 -640 409 -640 480 -640 480 -640 427 -640 480 -640 427 -427 640 -500 375 -480 640 -427 640 -500 375 -640 480 -640 481 -500 357 -640 480 -375 500 -640 425 -640 480 -480 640 -640 480 -640 457 -640 480 -424 640 -640 383 -640 480 -640 492 -640 480 -640 480 -427 640 -480 640 -640 427 -428 640 -640 427 -640 480 -640 480 -640 427 -612 612 -640 480 -640 425 -640 427 -427 640 -480 640 -640 480 -500 375 -500 366 -640 480 -640 484 -500 375 -640 427 -640 480 -640 420 -500 333 -640 480 -640 385 -640 426 -640 427 -500 325 -640 500 -427 640 -640 426 -640 480 -500 376 -640 480 -500 375 -640 427 -555 640 -640 427 -640 404 -480 640 -640 480 -427 640 -541 640 -640 359 -640 427 -427 640 -640 427 -640 426 -640 427 -600 600 -640 424 -640 427 -640 424 -640 480 -480 640 -640 480 -640 495 -500 375 -640 479 -500 376 -640 489 -333 500 -490 640 -500 375 -640 628 -640 427 -640 427 -640 433 -640 427 -640 424 -640 480 -416 500 -640 569 -428 640 -480 640 -480 640 -427 640 -640 450 -427 640 -500 375 -640 427 -500 375 -640 480 -640 427 -640 434 -640 424 -640 426 -640 425 -640 480 -440 640 -640 480 -640 425 -640 480 -500 375 -640 480 -640 480 -640 480 -480 640 -500 426 -640 480 -640 480 -640 480 -640 484 -480 640 -640 471 -426 640 -427 640 -640 427 -500 375 -640 480 -640 426 -640 479 -640 427 -481 640 -640 428 -480 640 -640 480 -640 427 -640 640 -640 428 -500 333 -640 427 -640 424 -333 500 -640 424 -640 478 -640 480 -640 427 -480 640 -640 428 -640 480 -640 480 -331 500 -426 640 -640 424 -640 427 -640 360 -640 424 -427 640 -640 480 -480 640 -640 427 -640 360 -640 393 -640 428 -640 427 -640 424 -333 500 -480 640 -640 424 -640 640 -640 426 -640 429 -640 426 -640 599 -640 480 -480 640 -640 480 -640 408 -375 500 -640 430 -425 640 -640 426 -375 500 -427 640 -640 480 -640 427 -426 640 -640 396 -480 640 -640 360 -640 599 -640 479 -640 425 -480 640 -640 480 -640 480 -640 427 -640 427 -640 427 -425 500 -480 640 -640 448 -383 640 -640 480 -427 640 -640 480 -425 640 -640 477 -640 427 -333 500 -640 480 -500 375 -500 333 -640 427 -640 534 -640 480 -640 426 -640 480 -640 426 -640 480 -500 377 -640 480 -480 640 -640 480 -640 429 -640 426 -480 640 -640 478 -640 360 -500 333 -640 480 -640 428 -425 640 -640 480 -640 480 -500 375 -612 612 -500 333 -640 480 -640 479 -640 376 -640 480 -640 508 -640 425 -640 427 -500 467 -500 375 -294 500 -640 640 -640 480 -433 640 -480 640 -640 640 -500 351 -640 427 -640 427 -640 334 -640 428 -429 640 -457 640 -640 480 -500 436 -500 356 -640 425 -612 612 -500 493 -305 640 -640 480 -640 480 -640 480 -640 427 -640 427 -510 640 -424 640 -470 300 -640 480 -640 466 -640 480 -640 480 -640 360 -640 427 -408 640 -480 320 -640 427 -640 480 -500 375 -495 640 -500 379 -426 640 -640 480 -640 426 -640 513 -500 375 -479 640 -640 480 -500 375 -640 478 -480 640 -500 375 -640 480 -640 429 -500 375 -427 640 -640 427 -640 426 -640 425 -640 609 -640 360 -594 447 -640 443 -640 427 -500 375 -640 480 -640 426 -500 375 -640 480 -612 612 -500 375 -640 481 -640 360 -480 640 -640 478 -631 640 -640 427 -640 480 -640 477 -640 480 -640 480 -429 640 -500 375 -640 571 -640 640 -640 480 -640 427 -640 426 -640 524 -640 480 -640 427 -640 394 -612 612 -640 421 -640 426 -480 640 -640 480 -640 640 -457 640 -640 427 -640 248 -427 640 -640 480 -640 426 -427 640 -500 400 -500 375 -640 480 -500 376 -640 506 -640 480 -512 640 -640 480 -640 427 -640 480 -640 427 -480 640 -427 640 -640 425 -500 379 -640 361 -426 640 -500 375 -640 480 -478 640 -640 427 -484 640 -640 427 -500 375 -455 640 -480 640 -500 335 -640 396 -326 500 -640 427 -640 426 -640 425 -549 640 -640 480 -640 426 -640 480 -427 640 -640 424 -640 480 -425 640 -480 640 -640 329 -640 480 -480 640 -500 384 -400 400 -640 480 -640 424 -640 386 -640 360 -640 427 -640 480 -640 427 -640 480 -640 426 -640 480 -480 640 -427 640 -500 375 -640 540 -640 428 -640 425 -640 427 -640 480 -333 500 -563 640 -640 640 -626 526 -640 428 -640 480 -640 427 -640 360 -500 331 -427 640 -640 423 -640 483 -426 640 -640 480 -640 480 -640 480 -427 640 -640 427 -640 640 -500 375 -640 360 -518 640 -426 640 -640 458 -640 427 -640 427 -640 480 -640 593 -640 522 -375 500 -481 640 -640 480 -640 480 -640 403 -427 640 -480 640 -423 640 -426 640 -640 490 -500 375 -640 425 -640 480 -480 640 -640 360 -640 173 -640 480 -640 480 -480 640 -615 640 -640 426 -640 427 -480 640 -480 640 -640 480 -640 512 -640 380 -640 640 -500 400 -500 375 -640 480 -640 426 -640 427 -640 432 -402 500 -640 480 -480 640 -640 480 -597 640 -640 292 -640 426 -640 480 -640 480 -480 640 -640 431 -612 612 -640 427 -640 478 -640 480 -546 640 -640 427 -500 375 -478 640 -640 481 -640 439 -640 426 -640 486 -427 640 -640 427 -427 640 -500 375 -500 375 -640 505 -640 235 -640 428 -640 425 -640 427 -640 480 -478 640 -640 426 -640 427 -640 480 -640 478 -480 640 -512 640 -612 612 -640 427 -480 640 -500 333 -640 424 -375 500 -640 587 -379 335 -640 480 -640 414 -640 426 -400 500 -613 640 -640 480 -427 640 -640 356 -640 480 -480 640 -640 480 -640 480 -640 480 -640 427 -640 640 -640 425 -491 500 -640 478 -480 640 -489 500 -500 375 -640 480 -380 640 -334 500 -429 480 -640 417 -640 427 -640 480 -640 429 -640 426 -461 640 -425 640 -640 480 -640 480 -640 427 -640 427 -448 640 -640 480 -640 427 -640 480 -480 640 -640 429 -427 640 -640 427 -612 612 -640 427 -640 427 -427 640 -500 375 -640 478 -640 429 -582 640 -640 480 -453 640 -640 426 -640 431 -640 427 -640 478 -612 612 -500 410 -360 640 -640 425 -427 640 -640 426 -640 427 -561 640 -640 427 -640 426 -640 427 -640 427 -640 428 -640 480 -640 427 -640 427 -538 640 -573 640 -500 364 -640 426 -467 500 -640 451 -640 427 -640 424 -432 324 -640 428 -640 480 -640 427 -640 437 -334 500 -640 576 -640 430 -640 480 -640 555 -500 375 -500 375 -640 480 -425 640 -500 357 -640 427 -640 427 -640 480 -640 427 -640 427 -427 640 -461 640 -640 480 -425 640 -500 335 -640 480 -375 500 -500 400 -640 427 -640 427 -640 480 -427 640 -640 480 -640 427 -640 480 -448 299 -500 375 -640 426 -640 427 -480 640 -480 640 -640 401 -375 500 -640 480 -640 427 -612 612 -640 484 -640 480 -640 427 -426 640 -480 640 -480 640 -640 429 -640 426 -640 427 -640 480 -640 427 -480 640 -640 480 -426 640 -640 427 -640 480 -640 320 -500 375 -640 640 -427 640 -640 480 -423 640 -640 480 -640 414 -640 506 -480 640 -480 640 -640 367 -640 351 -300 400 -640 322 -640 428 -500 382 -640 428 -640 480 -640 481 -640 427 -425 640 -640 425 -514 640 -640 480 -500 368 -640 360 -640 466 -640 503 -640 427 -500 282 -640 427 -640 427 -640 396 -480 640 -480 640 -640 425 -428 640 -500 333 -640 480 -500 333 -640 427 -640 480 -612 612 -480 640 -640 478 -640 480 -640 428 -640 427 -332 500 -640 427 -480 640 -640 426 -480 640 -640 480 -640 428 -640 429 -640 282 -640 493 -640 389 -375 500 -640 428 -640 427 -500 375 -480 640 -640 480 -640 480 -640 426 -640 400 -640 640 -375 500 -640 480 -428 640 -414 500 -640 544 -640 640 -640 427 -640 427 -480 640 -427 640 -640 480 -484 640 -375 500 -427 640 -640 360 -640 480 -619 640 -640 480 -480 640 -640 640 -640 429 -427 640 -640 480 -640 424 -640 480 -640 428 -425 640 -500 326 -640 427 -428 640 -640 589 -640 426 -480 640 -640 480 -500 500 -500 375 -480 640 -480 640 -500 332 -640 427 -640 428 -640 480 -500 375 -640 446 -640 480 -640 480 -427 640 -640 480 -640 403 -590 590 -500 346 -640 426 -640 428 -640 480 -500 375 -489 640 -400 500 -640 428 -640 359 -640 480 -480 640 -640 424 -424 640 -640 427 -426 640 -640 480 -640 427 -640 478 -640 480 -478 640 -500 374 -427 640 -640 424 -640 480 -640 427 -640 480 -612 612 -640 396 -640 427 -500 375 -640 546 -640 408 -640 480 -640 426 -500 334 -640 428 -640 480 -640 489 -480 640 -480 640 -640 480 -640 480 -640 427 -500 336 -640 427 -500 375 -480 640 -640 427 -640 428 -500 376 -640 480 -500 336 -640 480 -640 426 -500 334 -480 360 -640 480 -640 402 -424 640 -480 640 -640 480 -640 480 -612 612 -640 518 -640 484 -427 640 -612 612 -640 480 -480 640 -485 500 -375 500 -565 640 -426 640 -375 500 -640 603 -640 480 -427 640 -640 517 -625 640 -640 388 -480 640 -500 332 -512 640 -640 427 -612 612 -630 640 -640 601 -640 480 -640 506 -480 640 -640 426 -640 427 -640 480 -640 427 -428 640 -640 427 -333 500 -500 333 -640 480 -500 375 -640 480 -640 480 -640 480 -640 429 -500 333 -640 427 -640 427 -640 478 -640 458 -640 480 -500 335 -427 640 -397 567 -640 480 -480 640 -640 427 -640 427 -640 480 -429 640 -640 425 -640 640 -640 428 -640 480 -500 332 -640 383 -480 640 -612 612 -480 640 -640 426 -640 480 -445 640 -640 427 -500 375 -640 427 -640 329 -640 480 -640 480 -640 492 -640 427 -640 480 -640 454 -640 360 -640 427 -425 640 -640 480 -640 242 -480 640 -640 425 -640 480 -640 461 -640 480 -640 423 -640 480 -640 480 -640 631 -640 582 -480 640 -500 375 -640 480 -640 480 -640 428 -640 429 -640 480 -640 425 -640 480 -640 480 -640 480 -640 480 -368 500 -640 401 -640 480 -427 640 -640 480 -640 428 -640 457 -640 425 -480 640 -640 480 -500 333 -640 480 -640 427 -640 481 -640 427 -480 640 -640 480 -500 335 -500 329 -427 640 -640 427 -640 427 -640 427 -640 480 -640 457 -500 375 -640 428 -431 640 -640 423 -640 640 -640 524 -428 640 -640 426 -640 428 -640 426 -640 425 -375 500 -500 175 -500 500 -448 640 -640 429 -612 612 -640 480 -640 427 -640 480 -640 480 -640 384 -640 514 -640 480 -640 427 -640 427 -403 604 -640 512 -640 480 -612 612 -500 331 -640 427 -640 259 -500 375 -500 375 -640 480 -640 427 -640 426 -640 480 -640 299 -640 425 -640 427 -640 512 -479 640 -500 333 -640 427 -640 512 -640 373 -480 640 -500 375 -640 427 -640 424 -500 375 -640 429 -425 640 -480 640 -399 640 -640 480 -640 482 -500 322 -640 480 -640 480 -640 508 -640 424 -640 480 -640 489 -480 640 -640 427 -640 458 -640 466 -640 480 -500 375 -640 424 -500 387 -640 480 -427 640 -640 495 -426 640 -640 480 -640 480 -480 640 -640 408 -480 640 -480 640 -640 480 -426 640 -640 480 -640 424 -640 427 -640 478 -640 478 -640 474 -375 500 -640 480 -640 427 -640 480 -448 336 -500 345 -460 500 -640 480 -640 480 -360 640 -640 386 -640 344 -428 640 -480 640 -500 412 -640 427 -640 480 -640 480 -500 332 -640 427 -640 572 -640 480 -640 387 -500 333 -445 640 -480 640 -640 423 -500 366 -640 359 -480 640 -640 426 -612 612 -500 375 -480 640 -640 480 -640 361 -640 480 -640 431 -640 427 -640 426 -640 427 -480 640 -640 230 -640 361 -640 480 -640 483 -640 480 -500 375 -480 640 -640 458 -640 640 -640 480 -640 426 -480 360 -640 427 -640 480 -640 482 -640 425 -640 410 -640 480 -640 458 -640 370 -640 426 -640 480 -500 375 -640 480 -424 640 -500 333 -640 427 -500 375 -494 640 -640 427 -480 640 -640 480 -640 427 -640 400 -333 500 -375 500 -500 333 -480 640 -640 427 -640 426 -640 480 -500 333 -640 480 -473 640 -640 480 -480 640 -600 400 -640 480 -640 403 -480 640 -480 640 -500 375 -500 375 -480 640 -500 375 -579 640 -640 426 -480 640 -640 404 -640 480 -640 480 -640 426 -640 426 -640 512 -640 480 -640 427 -500 333 -427 640 -640 427 -640 360 -426 640 -640 480 -640 480 -425 640 -591 640 -500 500 -640 427 -428 640 -640 380 -640 480 -640 480 -640 480 -640 426 -640 171 -500 375 -458 640 -640 426 -500 448 -640 424 -640 427 -612 612 -500 384 -333 500 -640 480 -640 360 -519 640 -640 427 -500 375 -500 375 -640 480 -425 640 -640 512 -640 549 -640 400 -640 480 -480 640 -640 640 -464 640 -640 426 -640 353 -480 640 -640 427 -640 463 -500 375 -480 640 -500 375 -474 640 -640 428 -480 384 -640 480 -640 480 -640 439 -508 640 -612 612 -640 427 -640 480 -640 402 -640 338 -640 361 -500 374 -640 427 -640 480 -640 416 -452 500 -612 612 -640 640 -375 500 -480 640 -640 480 -640 428 -500 344 -640 427 -640 480 -640 427 -640 427 -640 424 -640 480 -640 425 -640 471 -640 480 -640 431 -640 427 -640 480 -640 512 -640 480 -640 480 -640 427 -640 480 -425 640 -640 427 -640 441 -640 480 -480 640 -640 427 -640 360 -500 375 -640 425 -481 640 -640 421 -640 480 -450 640 -640 454 -640 425 -427 640 -640 360 -640 480 -640 480 -640 427 -640 480 -640 480 -640 427 -640 480 -427 640 -424 640 -640 480 -640 461 -500 154 -480 640 -375 500 -640 427 -640 480 -581 640 -426 640 -640 480 -512 640 -425 640 -640 428 -500 332 -640 427 -640 427 -640 478 -640 433 -640 463 -640 444 -640 360 -640 480 -480 640 -640 429 -640 426 -640 480 -334 500 -640 425 -640 434 -640 640 -640 640 -640 359 -640 480 -640 427 -640 424 -640 482 -640 480 -500 324 -640 428 -640 371 -640 427 -360 640 -640 480 -427 640 -640 427 -640 173 -640 480 -640 426 -640 487 -375 500 -640 480 -500 334 -500 375 -334 500 -640 426 -640 480 -640 480 -480 640 -640 480 -480 640 -640 426 -640 480 -640 483 -640 427 -385 640 -640 478 -640 480 -640 427 -640 359 -640 480 -640 427 -640 480 -640 480 -640 640 -640 480 -640 425 -603 640 -640 512 -640 480 -640 424 -640 640 -640 427 -640 482 -500 332 -640 401 -640 480 -640 426 -640 480 -640 425 -335 246 -640 480 -240 363 -480 640 -500 375 -640 480 -500 375 -640 426 -640 428 -640 427 -375 500 -640 421 -480 640 -500 375 -604 453 -640 427 -640 478 -400 600 -480 640 -640 640 -612 612 -640 427 -228 500 -640 462 -640 487 -272 480 -640 480 -480 640 -640 427 -427 640 -435 640 -375 500 -640 480 -640 427 -640 452 -640 428 -427 640 -500 231 -375 500 -640 480 -563 640 -640 479 -426 640 -640 360 -428 640 -640 608 -640 361 -640 480 -640 427 -640 480 -480 640 -375 500 -640 640 -640 426 -640 353 -640 480 -491 500 -640 424 -640 470 -640 337 -640 468 -640 480 -640 432 -640 502 -640 360 -640 480 -456 640 -499 640 -640 480 -425 640 -640 399 -640 480 -425 640 -640 480 -640 426 -500 319 -640 427 -500 335 -426 640 -640 478 -375 500 -426 640 -640 478 -468 298 -640 640 -612 612 -640 421 -500 375 -426 640 -640 640 -500 338 -428 640 -500 333 -480 640 -329 497 -640 640 -500 500 -640 431 -505 640 -640 425 -500 375 -480 640 -480 640 -612 612 -379 640 -640 425 -640 479 -640 427 -640 480 -637 640 -500 336 -500 375 -640 425 -640 426 -640 306 -640 514 -640 640 -333 500 -640 427 -480 640 -612 612 -640 480 -640 480 -421 640 -640 480 -429 640 -640 480 -612 612 -640 480 -640 480 -640 425 -516 640 -480 640 -480 640 -640 427 -640 426 -640 480 -640 426 -640 428 -640 480 -640 425 -480 640 -640 480 -480 440 -500 394 -426 640 -612 612 -500 375 -500 334 -500 394 -640 427 -640 480 -640 480 -640 480 -640 427 -640 428 -500 375 -640 480 -427 640 -640 478 -375 500 -640 426 -389 640 -640 480 -480 640 -640 427 -500 334 -426 640 -500 375 -640 427 -640 426 -640 406 -640 480 -640 478 -640 401 -428 640 -640 424 -375 500 -640 427 -640 480 -640 427 -426 640 -640 427 -480 640 -640 427 -640 633 -375 500 -640 429 -640 426 -640 518 -640 480 -640 427 -640 426 -640 426 -640 480 -500 366 -375 500 -480 640 -640 591 -640 480 -640 427 -640 426 -459 500 -500 335 -640 427 -640 364 -640 427 -640 578 -640 459 -480 640 -640 480 -467 352 -500 500 -640 480 -640 426 -640 360 -640 480 -640 480 -640 429 -480 640 -640 311 -480 640 -563 422 -640 474 -640 360 -640 427 -640 426 -640 480 -500 375 -640 417 -640 427 -480 640 -640 480 -154 205 -500 375 -640 480 -640 427 -640 418 -480 640 -640 530 -375 500 -431 640 -500 375 -640 480 -500 334 -640 416 -640 353 -427 640 -429 640 -640 480 -640 480 -640 480 -480 640 -640 480 -500 334 -640 427 -478 640 -640 427 -500 375 -500 332 -640 480 -640 480 -640 480 -640 427 -640 427 -640 480 -640 480 -640 480 -640 480 -612 612 -640 379 -640 427 -333 500 -640 453 -640 426 -640 425 -375 500 -640 480 -640 427 -480 640 -640 427 -640 437 -478 640 -424 640 -480 640 -480 640 -478 640 -427 640 -640 583 -480 640 -640 424 -480 640 -375 500 -640 428 -640 426 -640 427 -375 500 -640 428 -427 640 -480 640 -640 427 -623 640 -640 480 -640 480 -640 480 -500 333 -640 425 -480 640 -463 640 -480 640 -640 426 -500 333 -640 427 -640 480 -612 612 -478 640 -640 427 -640 480 -640 480 -424 640 -640 478 -640 427 -640 480 -612 612 -640 480 -427 640 -640 428 -500 375 -334 500 -426 640 -333 500 -640 459 -640 427 -640 427 -640 427 -640 428 -480 640 -640 480 -500 333 -427 640 -500 333 -640 427 -500 375 -427 640 -558 640 -500 375 -373 500 -640 480 -640 480 -640 480 -500 249 -480 640 -500 367 -640 427 -640 480 -640 480 -640 427 -480 640 -640 480 -480 640 -604 453 -640 429 -512 640 -640 360 -640 339 -631 640 -425 640 -640 427 -640 480 -640 425 -640 480 -640 480 -427 640 -612 612 -480 640 -640 408 -470 640 -640 426 -500 281 -640 480 -640 428 -640 426 -375 500 -640 426 -375 500 -640 427 -640 427 -427 640 -640 480 -427 640 -640 427 -640 480 -640 338 -640 480 -640 602 -640 428 -480 640 -640 427 -500 329 -424 640 -375 500 -640 480 -640 406 -480 640 -500 375 -640 427 -512 640 -471 640 -640 424 -480 640 -640 443 -640 360 -640 427 -640 480 -480 640 -640 480 -500 434 -431 640 -640 427 -640 480 -480 360 -500 300 -640 426 -432 640 -640 480 -640 424 -640 480 -427 640 -427 640 -640 425 -640 427 -640 480 -640 427 -640 428 -432 288 -640 426 -500 332 -640 471 -640 348 -480 640 -480 640 -640 480 -320 240 -612 612 -640 427 -500 375 -333 500 -640 427 -640 480 -479 640 -640 480 -500 343 -640 622 -640 427 -640 426 -273 500 -480 640 -640 424 -480 640 -375 640 -612 612 -500 375 -640 480 -640 573 -480 640 -640 427 -640 480 -640 480 -640 426 -640 458 -640 426 -375 500 -500 375 -640 401 -640 480 -422 640 -640 426 -500 336 -640 412 -640 427 -640 480 -428 640 -427 640 -320 240 -427 640 -640 480 -640 480 -640 478 -640 480 -640 427 -500 375 -612 612 -479 640 -640 454 -640 427 -640 480 -640 427 -640 480 -500 375 -640 480 -500 375 -303 500 -640 427 -612 612 -486 640 -480 640 -640 428 -640 426 -480 640 -383 640 -640 480 -480 640 -640 424 -640 428 -640 409 -640 427 -640 480 -640 428 -500 500 -640 427 -556 640 -427 640 -640 480 -320 240 -640 640 -500 332 -640 480 -640 427 -612 612 -640 480 -640 480 -480 640 -456 640 -612 612 -640 400 -640 426 -640 410 -640 360 -439 640 -640 480 -612 612 -640 426 -640 480 -441 640 -500 310 -640 427 -640 427 -640 468 -640 427 -500 375 -640 480 -640 480 -427 640 -612 612 -480 640 -480 640 -640 427 -640 480 -640 427 -500 375 -640 480 -640 480 -640 427 -640 480 -480 640 -500 375 -640 427 -640 480 -612 612 -500 335 -640 428 -640 427 -640 425 -640 360 -640 480 -640 427 -640 480 -640 424 -640 480 -640 427 -640 427 -640 428 -640 426 -640 423 -640 468 -640 483 -640 616 -640 480 -640 427 -427 640 -640 480 -640 427 -640 427 -640 480 -640 490 -448 336 -480 640 -480 640 -333 500 -640 431 -640 591 -640 480 -640 427 -500 490 -640 480 -640 427 -640 442 -640 480 -640 480 -640 428 -640 427 -640 480 -640 427 -640 427 -640 427 -640 482 -640 361 -640 426 -640 397 -624 640 -640 427 -640 426 -640 480 -640 480 -500 375 -640 480 -514 640 -500 333 -640 480 -640 406 -328 500 -640 480 -500 356 -640 428 -640 480 -640 426 -640 427 -640 427 -640 464 -640 427 -640 480 -500 333 -640 480 -640 480 -640 480 -640 480 -375 207 -640 427 -640 480 -640 366 -458 640 -640 427 -640 426 -640 480 -481 640 -640 480 -640 425 -640 471 -500 333 -640 426 -500 375 -640 478 -640 427 -612 612 -640 484 -500 331 -500 284 -526 640 -426 640 -640 480 -640 426 -640 427 -640 427 -640 376 -640 480 -386 500 -640 425 -640 425 -374 500 -640 416 -640 499 -480 640 -640 427 -457 640 -640 480 -579 640 -640 511 -640 480 -640 428 -500 354 -500 375 -640 480 -426 640 -640 394 -640 426 -520 373 -480 640 -640 480 -480 640 -640 480 -640 480 -500 346 -640 480 -593 640 -640 480 -344 500 -640 393 -500 375 -480 640 -640 480 -500 458 -640 425 -480 640 -640 426 -640 480 -500 375 -438 640 -640 480 -640 427 -500 333 -612 612 -640 480 -500 408 -640 427 -640 480 -427 640 -640 427 -640 480 -640 427 -640 457 -640 427 -640 405 -480 640 -640 480 -640 426 -640 426 -500 343 -500 401 -427 640 -574 640 -640 480 -335 500 -500 375 -640 480 -640 480 -640 427 -640 480 -640 427 -640 564 -640 542 -500 500 -640 409 -480 640 -612 612 -428 640 -640 426 -640 480 -640 427 -640 424 -640 633 -640 480 -640 426 -640 480 -640 361 -640 426 -640 266 -640 424 -500 307 -640 480 -425 640 -500 368 -568 640 -640 453 -640 427 -640 503 -500 375 -640 374 -640 359 -640 427 -640 448 -426 640 -640 480 -400 500 -500 333 -640 427 -640 426 -640 427 -640 601 -640 427 -640 513 -640 480 -640 425 -427 640 -640 480 -640 426 -500 375 -640 427 -427 640 -640 480 -500 425 -500 340 -640 427 -640 480 -640 359 -640 478 -640 480 -427 640 -640 360 -640 376 -640 460 -640 406 -640 480 -640 427 -612 612 -500 375 -419 640 -640 588 -640 428 -480 640 -375 500 -640 427 -640 480 -640 480 -640 423 -640 480 -640 480 -640 513 -640 640 -640 361 -640 498 -640 426 -640 480 -640 427 -500 375 -640 427 -270 360 -457 640 -426 640 -386 640 -501 640 -479 640 -640 634 -640 426 -640 480 -521 640 -640 426 -428 640 -640 426 -500 375 -640 427 -640 360 -427 640 -640 480 -640 427 -431 259 -640 426 -640 604 -600 386 -393 500 -640 426 -640 478 -640 425 -612 612 -332 500 -639 640 -500 640 -640 448 -500 333 -500 333 -640 480 -640 427 -640 427 -500 349 -640 435 -640 424 -640 512 -500 333 -640 426 -640 480 -640 480 -480 640 -500 449 -640 480 -640 480 -640 427 -640 481 -480 640 -500 375 -640 425 -640 478 -500 330 -640 554 -640 479 -640 480 -640 480 -640 348 -640 427 -640 480 -640 480 -640 427 -640 425 -624 640 -640 480 -640 424 -531 640 -640 381 -640 480 -640 428 -640 427 -640 437 -393 500 -374 500 -640 480 -640 443 -640 480 -640 480 -640 428 -640 428 -640 443 -500 334 -640 427 -500 346 -640 430 -640 427 -640 427 -500 375 -640 354 -480 640 -640 428 -640 480 -360 640 -640 480 -426 640 -640 391 -640 478 -640 512 -640 480 -500 375 -276 410 -500 375 -480 640 -478 640 -427 640 -640 422 -640 425 -640 480 -640 426 -640 480 -640 480 -640 426 -640 520 -640 426 -640 480 -640 488 -612 612 -333 500 -640 480 -500 375 -640 427 -281 500 -640 426 -640 480 -413 500 -640 427 -640 480 -640 480 -640 427 -640 428 -503 640 -640 427 -640 359 -640 480 -640 425 -640 425 -640 427 -428 640 -640 480 -640 182 -640 427 -500 375 -479 640 -612 612 -480 640 -640 480 -640 480 -600 400 -640 427 -640 386 -640 480 -640 480 -375 500 -640 480 -640 480 -427 640 -640 427 -640 480 -640 396 -480 640 -640 480 -640 427 -480 640 -480 640 -640 360 -500 375 -640 543 -640 427 -640 465 -640 426 -360 640 -640 369 -640 480 -640 428 -640 480 -640 475 -403 500 -480 640 -640 410 -500 333 -480 640 -640 480 -640 427 -426 640 -640 480 -424 640 -640 336 -480 640 -640 427 -500 333 -480 640 -500 390 -640 442 -612 612 -640 541 -612 612 -401 500 -612 612 -640 427 -640 428 -640 426 -640 427 -640 425 -640 480 -375 500 -640 427 -640 427 -640 480 -640 418 -640 425 -427 640 -426 640 -640 480 -640 425 -375 500 -640 427 -640 427 -640 360 -500 400 -640 427 -640 480 -640 427 -426 640 -361 640 -640 427 -640 480 -640 480 -427 640 -640 480 -375 500 -480 640 -640 425 -640 480 -500 375 -640 480 -640 427 -640 427 -426 640 -640 426 -640 480 -640 427 -480 640 -640 427 -424 640 -640 428 -480 640 -480 640 -457 640 -640 480 -480 640 -500 334 -640 480 -426 640 -640 452 -500 333 -640 544 -640 428 -423 640 -640 427 -640 428 -480 640 -640 427 -640 480 -612 612 -640 427 -480 640 -500 375 -640 427 -640 428 -425 640 -391 640 -397 640 -640 480 -640 425 -640 480 -427 640 -640 480 -425 640 -640 480 -375 500 -500 335 -640 416 -640 427 -640 495 -640 427 -640 428 -500 375 -640 427 -640 425 -640 333 -480 640 -500 333 -425 640 -640 428 -640 640 -640 424 -640 427 -500 640 -640 427 -640 426 -640 427 -640 478 -640 457 -640 425 -640 480 -640 480 -500 331 -494 640 -640 480 -640 428 -375 500 -428 640 -500 281 -640 480 -640 426 -640 425 -640 427 -640 478 -640 414 -640 427 -449 640 -640 426 -479 640 -640 519 -640 479 -640 427 -480 640 -500 333 -640 427 -494 500 -640 427 -640 480 -640 552 -500 375 -480 640 -640 504 -640 480 -480 640 -569 640 -500 333 -640 480 -640 435 -640 480 -500 375 -640 427 -640 480 -500 375 -480 640 -640 480 -640 640 -398 640 -640 427 -640 424 -640 425 -341 500 -640 359 -640 422 -640 491 -640 503 -640 429 -640 480 -414 640 -640 480 -640 529 -640 480 -640 513 -640 478 -640 427 -375 500 -640 480 -640 480 -480 360 -640 640 -375 500 -640 480 -640 480 -480 640 -640 608 -640 480 -640 427 -640 480 -640 359 -640 480 -500 375 -500 375 -640 427 -640 480 -500 375 -640 426 -500 500 -640 532 -640 480 -612 612 -640 532 -612 612 -426 640 -500 332 -500 375 -640 480 -640 450 -458 640 -640 291 -640 427 -640 480 -640 429 -500 333 -640 480 -640 360 -640 427 -640 426 -640 480 -640 480 -480 640 -640 425 -480 640 -500 375 -476 640 -500 328 -640 480 -640 458 -640 480 -640 427 -640 360 -640 424 -640 411 -457 640 -640 558 -572 640 -427 640 -640 427 -427 640 -640 349 -640 480 -427 640 -640 427 -640 428 -640 360 -428 640 -640 360 -480 640 -640 425 -640 508 -640 640 -640 426 -640 491 -640 480 -612 612 -480 640 -640 427 -640 480 -640 426 -640 480 -500 463 -640 480 -640 480 -640 480 -640 419 -640 479 -640 480 -640 480 -500 375 -640 381 -640 425 -640 428 -480 640 -450 286 -640 480 -640 427 -600 450 -640 480 -640 428 -640 480 -640 480 -640 426 -640 427 -500 375 -640 480 -500 375 -500 375 -640 425 -640 308 -640 424 -480 640 -478 640 -427 640 -375 500 -640 428 -500 375 -434 640 -640 480 -640 480 -500 293 -640 427 -640 488 -640 427 -640 427 -640 427 -480 640 -640 426 -480 640 -640 424 -640 427 -424 640 -640 480 -640 480 -640 480 -494 640 -427 640 -640 348 -356 500 -640 480 -375 500 -431 640 -500 365 -640 428 -612 612 -640 489 -640 480 -480 640 -640 480 -640 424 -640 428 -640 480 -640 479 -640 427 -640 427 -480 640 -500 325 -640 427 -640 432 -640 427 -640 444 -427 640 -640 427 -425 640 -480 640 -640 433 -480 640 -640 409 -640 480 -640 427 -375 500 -333 500 -640 468 -480 640 -640 480 -640 471 -640 463 -640 429 -640 480 -640 402 -640 478 -472 640 -100 144 -640 428 -640 425 -640 481 -640 386 -640 480 -640 480 -640 427 -640 463 -480 640 -425 640 -500 333 -640 427 -640 480 -640 480 -640 424 -500 375 -640 482 -640 427 -640 427 -640 544 -640 427 -640 611 -480 640 -612 612 -640 480 -640 480 -640 480 -444 640 -640 427 -640 479 -253 640 -480 640 -640 480 -612 612 -640 478 -640 480 -640 427 -427 640 -640 480 -640 480 -427 640 -640 488 -520 640 -612 612 -640 427 -640 426 -640 480 -480 640 -640 407 -640 480 -640 480 -500 375 -480 640 -399 640 -640 480 -427 640 -640 384 -360 640 -457 640 -640 334 -640 426 -428 640 -640 425 -640 480 -640 427 -640 426 -396 640 -480 640 -640 427 -640 480 -640 480 -480 640 -640 480 -640 426 -640 417 -640 480 -640 513 -640 427 -640 426 -640 480 -640 485 -640 480 -640 360 -457 640 -640 427 -640 405 -640 360 -640 480 -640 199 -640 480 -640 428 -640 480 -640 426 -482 640 -640 433 -640 480 -640 640 -640 427 -640 480 -640 408 -548 640 -640 426 -480 640 -480 640 -612 612 -640 427 -640 640 -640 481 -360 640 -640 457 -640 480 -640 426 -640 426 -640 426 -426 640 -500 335 -640 461 -640 427 -640 480 -640 427 -630 640 -640 424 -640 215 -640 429 -640 429 -640 480 -640 480 -640 427 -640 478 -480 640 -640 479 -640 480 -640 426 -640 480 -640 427 -640 480 -640 480 -640 426 -640 480 -640 427 -640 428 -480 640 -612 612 -480 640 -424 640 -640 427 -612 612 -500 500 -640 427 -640 427 -500 375 -640 480 -427 640 -640 427 -500 375 -480 640 -640 480 -640 480 -426 640 -640 480 -640 480 -518 640 -640 462 -427 640 -640 427 -500 333 -500 375 -640 480 -427 640 -480 640 -640 480 -481 640 -640 480 -640 480 -500 375 -425 640 -480 640 -426 640 -427 640 -320 240 -640 427 -640 480 -640 480 -640 425 -640 480 -478 640 -640 427 -640 426 -640 456 -640 480 -480 640 -480 640 -640 640 -334 500 -640 428 -640 449 -500 375 -640 394 -640 480 -500 257 -426 640 -640 426 -427 640 -640 479 -640 427 -426 640 -640 506 -478 640 -480 640 -640 480 -500 333 -640 425 -640 480 -640 424 -400 500 -640 428 -375 500 -427 640 -640 315 -640 480 -334 500 -480 640 -480 640 -480 640 -640 480 -640 427 -640 480 -640 428 -296 640 -640 426 -500 333 -500 472 -431 640 -461 640 -640 480 -500 403 -640 427 -640 428 -640 480 -426 640 -500 375 -480 640 -500 375 -500 375 -640 427 -640 285 -640 428 -480 640 -640 427 -480 640 -640 427 -640 428 -640 427 -640 480 -640 427 -640 427 -333 500 -500 375 -512 640 -640 426 -640 480 -640 427 -612 612 -500 375 -640 427 -425 640 -640 443 -480 640 -640 487 -428 640 -332 500 -640 360 -640 482 -640 480 -640 426 -480 640 -640 427 -640 368 -640 480 -427 640 -425 640 -640 480 -500 335 -500 333 -424 640 -640 428 -454 640 -640 640 -640 480 -640 480 -640 427 -640 480 -640 427 -334 500 -640 579 -480 640 -640 383 -640 428 -640 480 -640 478 -640 426 -640 444 -640 569 -464 640 -631 640 -640 480 -640 428 -640 427 -640 480 -640 360 -640 480 -612 612 -426 640 -640 480 -427 640 -640 427 -640 480 -640 480 -640 480 -640 640 -426 640 -429 600 -500 375 -640 480 -500 375 -480 640 -640 480 -640 427 -640 480 -612 612 -640 481 -640 323 -640 429 -612 612 -640 480 -640 425 -640 360 -500 332 -640 480 -640 426 -500 375 -640 640 -480 640 -640 480 -640 480 -640 428 -640 480 -640 429 -640 640 -640 514 -333 500 -640 480 -516 640 -640 427 -640 422 -640 427 -640 427 -640 427 -480 640 -612 612 -640 480 -363 500 -500 375 -500 374 -429 640 -640 425 -427 640 -640 480 -640 480 -640 425 -640 480 -640 596 -640 429 -640 480 -640 473 -640 341 -640 427 -480 640 -600 591 -640 480 -500 375 -500 357 -480 359 -338 500 -640 486 -640 426 -640 480 -540 477 -471 640 -640 427 -500 311 -500 326 -427 640 -640 480 -640 480 -510 640 -640 480 -500 375 -640 314 -640 426 -500 332 -640 426 -640 480 -640 480 -640 396 -344 500 -480 640 -640 526 -640 480 -639 640 -612 612 -640 461 -500 375 -640 427 -640 426 -640 425 -640 428 -640 564 -640 428 -500 375 -640 416 -640 438 -640 480 -640 480 -640 480 -478 640 -480 640 -427 640 -640 424 -339 500 -640 467 -640 480 -640 480 -640 428 -428 640 -640 426 -400 600 -500 222 -640 640 -640 429 -640 360 -640 480 -640 427 -500 375 -480 640 -383 640 -640 424 -500 375 -640 426 -640 480 -640 426 -640 445 -512 640 -640 395 -640 424 -640 482 -640 427 -640 512 -640 480 -640 424 -640 426 -640 480 -640 480 -640 425 -480 640 -427 640 -640 427 -500 375 -640 445 -640 501 -640 426 -640 480 -612 612 -640 427 -375 500 -640 480 -640 427 -640 427 -640 424 -334 500 -500 333 -500 357 -640 480 -640 429 -640 427 -640 480 -580 377 -640 499 -426 640 -640 609 -640 480 -640 333 -479 640 -541 640 -640 496 -640 359 -640 427 -612 612 -640 473 -375 500 -640 427 -427 640 -480 640 -612 612 -480 640 -640 393 -500 332 -424 640 -500 414 -640 473 -640 253 -500 473 -640 426 -640 416 -640 427 -414 640 -640 427 -640 427 -640 427 -640 480 -640 480 -640 480 -640 427 -612 612 -640 480 -640 427 -640 480 -640 480 -640 324 -480 640 -640 361 -640 424 -320 240 -640 427 -480 640 -640 425 -640 550 -640 640 -640 480 -640 429 -640 480 -640 491 -640 426 -640 368 -384 640 -640 427 -480 640 -640 427 -640 426 -428 640 -640 480 -427 640 -640 384 -640 448 -640 444 -640 320 -640 427 -640 427 -612 612 -640 480 -480 640 -640 427 -425 640 -640 480 -640 373 -640 425 -500 375 -640 480 -617 640 -640 427 -640 640 -640 480 -364 640 -442 500 -640 480 -500 377 -640 486 -640 550 -640 426 -640 427 -640 491 -640 380 -640 425 -640 411 -480 640 -640 427 -640 480 -640 383 -640 461 -640 416 -640 426 -640 427 -427 640 -640 480 -433 640 -480 640 -612 612 -480 640 -640 427 -500 331 -500 375 -640 427 -640 480 -480 640 -480 640 -640 480 -640 427 -640 360 -500 336 -640 427 -640 407 -640 438 -640 427 -427 640 -481 640 -480 640 -640 480 -640 480 -320 240 -640 424 -640 508 -640 399 -480 640 -640 320 -640 480 -480 640 -294 196 -640 464 -427 640 -334 640 -480 640 -640 480 -500 375 -640 428 -640 426 -640 427 -500 335 -640 426 -640 640 -426 640 -640 428 -640 388 -480 640 -640 320 -480 640 -640 480 -640 480 -640 428 -333 500 -500 375 -640 424 -480 640 -569 640 -640 278 -500 375 -480 640 -640 424 -640 480 -640 427 -640 428 -640 360 -640 426 -456 640 -640 426 -640 426 -427 640 -427 640 -640 427 -640 480 -640 427 -510 640 -640 480 -640 475 -640 480 -640 417 -640 480 -640 480 -640 427 -640 426 -640 427 -426 640 -640 480 -640 427 -640 398 -640 480 -640 462 -333 500 -640 475 -375 500 -480 640 -500 341 -640 285 -640 480 -480 640 -640 427 -480 640 -426 640 -640 427 -640 640 -640 425 -640 426 -640 480 -480 640 -333 500 -640 383 -375 500 -640 480 -640 636 -427 640 -480 640 -640 480 -500 399 -500 332 -640 304 -640 480 -427 640 -640 480 -640 480 -512 640 -427 640 -500 391 -500 422 -433 640 -334 500 -640 640 -640 425 -424 640 -640 427 -640 400 -375 500 -640 427 -640 640 -640 424 -427 640 -529 640 -640 480 -640 393 -640 427 -640 480 -500 374 -500 333 -640 480 -425 640 -612 612 -640 480 -480 640 -480 640 -480 640 -480 640 -500 375 -500 153 -500 333 -640 426 -640 483 -640 480 -640 480 -640 427 -640 480 -640 427 -640 427 -640 438 -640 428 -634 640 -640 343 -640 529 -640 425 -640 426 -500 247 -640 425 -640 496 -480 640 -500 332 -640 478 -500 375 -480 640 -640 480 -640 427 -640 366 -640 438 -437 500 -389 540 -640 428 -640 480 -640 480 -360 640 -640 427 -478 640 -640 480 -500 334 -640 480 -640 427 -581 640 -640 480 -427 640 -640 400 -640 425 -640 480 -640 480 -640 443 -640 480 -640 427 -640 456 -640 427 -640 427 -640 484 -478 640 -640 480 -480 640 -640 480 -500 375 -640 430 -640 482 -640 427 -640 480 -640 426 -427 640 -427 640 -640 359 -640 480 -640 426 -640 399 -640 427 -445 640 -333 500 -640 425 -640 425 -480 640 -500 335 -424 640 -640 480 -480 640 -427 640 -500 334 -640 426 -640 480 -640 480 -640 480 -640 472 -490 367 -500 335 -640 480 -640 418 -612 612 -640 508 -640 480 -640 427 -640 360 -500 379 -640 427 -640 480 -640 427 -640 480 -640 424 -500 433 -480 640 -480 640 -640 480 -640 480 -640 426 -480 640 -640 428 -500 375 -640 144 -640 480 -640 425 -585 329 -483 640 -640 502 -640 425 -640 360 -640 480 -500 333 -640 480 -640 484 -640 383 -480 640 -640 480 -640 480 -640 424 -640 480 -640 427 -612 612 -383 640 -640 429 -640 485 -640 427 -500 276 -640 539 -640 480 -640 427 -640 478 -640 491 -480 640 -640 427 -640 480 -640 426 -640 425 -640 427 -640 480 -640 424 -480 640 -612 612 -640 426 -640 425 -640 359 -480 640 -640 368 -500 333 -480 640 -500 500 -640 480 -640 480 -640 425 -640 480 -640 456 -640 427 -640 480 -640 425 -640 427 -500 500 -484 640 -640 480 -447 640 -640 427 -525 640 -640 426 -640 480 -353 500 -500 375 -640 480 -640 359 -640 480 -640 396 -640 463 -640 480 -640 495 -640 427 -611 640 -480 640 -426 640 -640 446 -480 640 -427 640 -612 612 -640 480 -427 640 -640 423 -457 640 -640 423 -640 427 -640 480 -427 640 -640 480 -480 640 -640 427 -542 588 -640 425 -480 640 -428 640 -640 425 -640 427 -634 640 -640 480 -480 640 -640 426 -583 640 -640 480 -427 640 -640 480 -640 526 -500 321 -511 640 -640 480 -640 480 -640 480 -640 478 -640 425 -640 480 -640 428 -640 426 -426 640 -640 424 -427 640 -640 425 -640 426 -640 480 -640 425 -546 366 -640 427 -500 375 -640 427 -351 500 -640 425 -500 375 -640 427 -640 480 -480 640 -640 360 -640 480 -500 375 -480 640 -640 427 -427 640 -488 500 -369 640 -640 405 -500 375 -640 640 -640 427 -481 640 -360 640 -640 425 -640 427 -640 428 -480 640 -640 480 -484 640 -640 429 -500 400 -335 500 -640 428 -640 429 -500 333 -500 341 -428 640 -640 427 -640 427 -640 605 -640 640 -640 425 -640 360 -640 480 -427 640 -640 480 -480 640 -600 448 -640 480 -320 480 -424 640 -640 427 -427 640 -640 480 -429 640 -640 373 -427 640 -640 480 -426 640 -500 338 -640 490 -612 612 -640 426 -640 427 -640 428 -480 640 -480 640 -640 428 -640 427 -640 533 -640 553 -640 480 -427 640 -640 480 -640 426 -500 441 -480 640 -640 427 -640 480 -640 353 -640 308 -640 423 -480 640 -640 427 -640 427 -640 480 -400 300 -500 375 -500 347 -400 300 -640 480 -612 612 -640 486 -640 426 -640 433 -640 483 -612 612 -500 375 -640 480 -426 640 -640 425 -640 425 -640 425 -640 360 -640 480 -409 640 -640 480 -640 427 -640 480 -640 480 -636 636 -640 419 -640 452 -640 427 -640 480 -640 480 -640 479 -427 640 -640 427 -640 427 -640 406 -425 640 -333 500 -427 640 -640 427 -480 640 -500 375 -500 375 -391 500 -640 404 -640 480 -640 427 -640 480 -640 427 -640 360 -640 428 -640 426 -500 333 -640 480 -612 612 -428 640 -640 427 -480 640 -500 299 -640 457 -640 640 -640 427 -640 426 -640 439 -500 375 -640 391 -640 426 -640 426 -500 333 -375 500 -640 426 -640 424 -424 640 -640 427 -500 192 -426 640 -640 480 -640 480 -640 480 -640 438 -505 640 -640 405 -640 426 -427 640 -640 487 -500 375 -427 640 -640 427 -640 480 -640 480 -640 480 -640 480 -479 640 -428 640 -480 640 -640 427 -640 360 -640 427 -640 321 -640 480 -640 427 -640 480 -426 640 -640 456 -640 427 -640 373 -640 480 -640 480 -640 480 -640 426 -640 427 -640 382 -640 458 -640 484 -640 480 -640 478 -640 427 -640 362 -319 500 -640 480 -640 193 -640 480 -640 366 -640 480 -427 640 -640 430 -640 478 -429 640 -500 333 -612 612 -640 480 -640 427 -375 500 -640 427 -640 378 -640 173 -500 375 -640 480 -374 500 -462 640 -500 375 -640 480 -640 426 -448 640 -436 640 -640 480 -640 427 -640 338 -640 480 -427 640 -640 511 -640 480 -640 480 -640 427 -640 427 -480 640 -640 427 -500 333 -640 424 -427 640 -500 375 -427 640 -640 480 -640 480 -640 428 -640 427 -640 505 -498 640 -640 426 -640 480 -640 480 -640 480 -640 468 -640 480 -640 562 -640 424 -430 640 -640 480 -640 428 -640 480 -427 640 -428 640 -427 640 -480 640 -424 640 -640 427 -640 480 -640 425 -480 640 -500 375 -640 480 -480 640 -500 500 -333 500 -640 480 -600 450 -640 360 -500 375 -424 640 -331 500 -640 480 -426 640 -640 478 -612 612 -640 424 -640 480 -640 427 -426 640 -640 359 -640 424 -640 427 -640 427 -640 427 -480 640 -640 375 -360 640 -320 480 -640 508 -640 427 -640 480 -599 640 -640 480 -640 480 -640 480 -640 429 -500 375 -640 480 -640 427 -640 480 -428 640 -640 480 -480 640 -426 640 -640 427 -640 456 -640 480 -640 480 -478 640 -427 640 -500 496 -428 640 -640 427 -640 425 -334 500 -481 640 -640 427 -640 426 -640 480 -471 500 -640 506 -640 424 -480 640 -640 427 -640 444 -426 640 -640 480 -640 480 -640 428 -640 431 -640 431 -640 480 -500 333 -640 427 -427 640 -640 512 -640 480 -512 640 -640 359 -640 640 -640 428 -640 426 -640 640 -500 375 -640 519 -480 640 -640 375 -427 640 -640 215 -640 429 -360 640 -640 480 -640 425 -434 640 -640 480 -640 480 -640 429 -640 427 -612 612 -640 426 -640 423 -480 640 -640 558 -640 427 -640 429 -640 427 -480 640 -640 480 -640 480 -419 640 -640 426 -640 480 -640 427 -640 480 -284 500 -640 346 -640 400 -640 480 -640 425 -612 612 -640 480 -640 360 -640 480 -425 640 -640 427 -640 426 -500 375 -640 412 -640 480 -573 640 -640 427 -612 612 -640 423 -480 640 -640 360 -426 640 -640 480 -383 640 -640 427 -480 640 -640 480 -640 480 -500 376 -640 426 -480 640 -640 556 -640 427 -428 640 -640 428 -427 640 -375 500 -640 360 -500 375 -375 500 -640 481 -640 480 -640 480 -500 375 -640 480 -640 480 -640 640 -454 640 -640 477 -640 421 -480 640 -640 427 -640 480 -500 333 -640 426 -640 480 -640 425 -640 426 -640 424 -640 579 -640 383 -640 640 -640 485 -640 426 -427 640 -640 479 -344 500 -640 480 -640 480 -427 640 -640 478 -600 450 -640 428 -640 427 -640 426 -427 640 -640 427 -640 480 -640 480 -480 640 -480 640 -640 480 -500 375 -427 640 -450 338 -500 375 -640 480 -640 448 -500 330 -640 428 -500 375 -640 480 -612 612 -457 640 -386 640 -480 640 -640 480 -480 640 -640 427 -640 492 -450 640 -480 640 -427 640 -478 640 -640 480 -640 424 -500 375 -612 612 -480 640 -480 640 -640 427 -640 640 -640 427 -480 640 -333 500 -480 640 -640 480 -640 426 -480 640 -500 375 -640 383 -640 480 -640 427 -640 506 -640 427 -640 511 -453 640 -640 428 -640 480 -640 439 -640 640 -640 426 -640 418 -453 640 -568 640 -386 500 -479 640 -640 428 -640 426 -480 640 -640 268 -640 427 -640 431 -640 439 -640 480 -480 640 -640 360 -640 427 -500 333 -428 640 -640 480 -612 612 -640 503 -640 427 -640 478 -425 640 -425 640 -480 640 -640 480 -430 640 -427 640 -640 427 -640 393 -640 480 -640 480 -333 500 -399 500 -640 480 -480 640 -640 480 -640 360 -640 480 -640 427 -480 360 -640 296 -640 428 -640 427 -640 480 -640 558 -640 426 -640 563 -640 480 -640 425 -640 424 -640 480 -640 480 -640 427 -640 427 -402 402 -640 428 -640 429 -640 462 -640 427 -640 480 -480 640 -640 226 -640 480 -493 640 -573 640 -424 640 -640 408 -375 500 -500 375 -640 640 -640 427 -640 480 -424 640 -640 427 -640 480 -640 423 -640 427 -640 480 -640 426 -500 366 -640 480 -517 640 -480 640 -640 427 -640 458 -480 640 -640 412 -640 497 -640 480 -500 338 -640 480 -640 425 -640 459 -375 500 -640 480 -640 412 -500 375 -640 640 -640 427 -640 480 -640 480 -640 640 -427 640 -640 425 -640 428 -640 480 -500 375 -640 427 -500 333 -314 500 -640 478 -640 480 -640 480 -640 427 -442 640 -480 640 -428 640 -500 375 -500 383 -640 480 -480 640 -640 427 -640 426 -640 400 -640 424 -640 325 -384 500 -640 480 -640 480 -640 426 -375 500 -640 428 -500 376 -478 640 -640 480 -640 424 -480 640 -640 480 -480 640 -501 640 -640 425 -640 480 -640 480 -500 333 -640 480 -500 400 -640 342 -640 480 -500 375 -640 273 -640 277 -500 335 -640 480 -500 375 -427 640 -640 328 -500 263 -375 500 -640 425 -640 480 -480 640 -640 480 -640 426 -424 640 -500 332 -640 480 -500 375 -318 500 -484 640 -640 486 -640 480 -640 429 -500 375 -640 425 -640 400 -640 480 -500 333 -640 640 -640 480 -640 480 -640 426 -467 371 -333 500 -640 480 -640 480 -640 389 -640 427 -640 425 -640 426 -349 640 -480 640 -640 424 -500 333 -640 427 -640 481 -640 426 -500 375 -640 518 -494 389 -640 480 -640 480 -640 513 -640 426 -500 393 -500 188 -640 427 -640 427 -500 375 -427 640 -332 500 -480 640 -640 470 -640 480 -640 288 -640 480 -640 480 -640 480 -640 425 -640 480 -640 480 -640 427 -640 480 -640 480 -640 480 -640 427 -480 640 -640 323 -640 480 -561 640 -640 480 -640 427 -640 427 -500 467 -640 427 -375 500 -480 640 -640 480 -428 640 -640 480 -640 480 -640 480 -500 375 -640 427 -640 428 -478 640 -640 426 -640 428 -640 360 -442 640 -478 640 -500 332 -640 426 -640 480 -500 375 -640 427 -495 640 -640 425 -640 427 -640 466 -640 479 -640 469 -640 551 -640 480 -640 480 -640 425 -640 427 -640 424 -640 480 -640 417 -640 480 -640 483 -640 480 -335 500 -640 640 -640 427 -640 480 -425 640 -640 427 -448 336 -425 640 -480 640 -640 400 -640 480 -640 509 -640 427 -500 294 -429 640 -640 360 -640 481 -640 426 -480 640 -640 428 -640 425 -640 426 -396 640 -500 335 -640 480 -640 425 -640 480 -480 640 -407 640 -500 375 -640 426 -640 480 -500 376 -640 427 -483 485 -426 640 -640 425 -640 480 -427 640 -640 640 -640 426 -612 612 -640 480 -640 427 -424 640 -640 427 -486 417 -640 480 -640 571 -427 640 -640 480 -640 480 -640 427 -640 480 -640 453 -640 426 -640 480 -640 480 -640 425 -640 493 -640 480 -426 640 -480 640 -640 480 -500 376 -640 427 -640 503 -334 500 -612 612 -500 333 -500 375 -375 500 -612 612 -640 480 -640 427 -500 333 -427 640 -480 640 -375 500 -640 427 -640 427 -521 315 -427 640 -427 640 -640 480 -500 375 -500 375 -640 387 -640 306 -640 426 -640 427 -640 458 -640 454 -640 480 -640 427 -640 427 -640 383 -500 375 -640 480 -640 427 -640 427 -500 375 -640 480 -640 480 -640 480 -640 427 -500 375 -640 480 -640 427 -640 260 -480 640 -640 427 -640 427 -500 333 -640 480 -480 640 -640 427 -427 640 -427 640 -640 427 -500 333 -480 640 -333 500 -427 640 -640 426 -640 390 -640 480 -400 301 -640 480 -500 339 -239 180 -640 425 -428 640 -640 426 -640 640 -640 478 -612 612 -640 465 -640 426 -427 640 -640 524 -640 436 -640 315 -640 427 -640 428 -500 333 -640 427 -500 374 -500 333 -640 427 -392 640 -640 446 -340 640 -640 480 -640 427 -480 640 -612 612 -359 640 -427 640 -426 640 -640 427 -427 640 -640 480 -375 500 -640 442 -640 480 -500 337 -640 480 -427 640 -375 500 -640 480 -640 427 -500 375 -332 500 -462 640 -426 640 -333 500 -640 480 -640 485 -640 428 -375 500 -640 640 -640 360 -640 424 -640 428 -640 411 -640 480 -640 425 -640 427 -640 426 -640 427 -640 480 -500 281 -640 429 -480 640 -425 640 -640 424 -427 640 -640 427 -640 479 -152 100 -640 480 -640 454 -640 428 -640 480 -426 640 -640 623 -640 480 -640 480 -640 640 -640 480 -640 359 -500 333 -640 480 -427 640 -426 640 -500 375 -480 640 -640 480 -333 500 -640 425 -612 612 -426 640 -640 480 -640 391 -480 640 -640 480 -640 427 -640 428 -640 480 -500 375 -640 427 -640 480 -640 634 -640 482 -640 426 -640 427 -640 480 -480 640 -640 480 -411 640 -640 512 -640 640 -556 640 -640 480 -427 640 -640 419 -640 433 -640 400 -640 427 -640 360 -640 426 -480 640 -480 640 -419 640 -640 528 -375 500 -640 480 -640 480 -640 480 -640 480 -640 427 -500 375 -427 640 -426 640 -425 640 -479 640 -480 640 -640 368 -640 427 -640 480 -424 640 -640 480 -640 408 -640 424 -466 640 -640 425 -480 640 -480 640 -640 458 -640 428 -500 375 -640 479 -500 375 -640 480 -200 300 -640 480 -433 640 -480 640 -500 421 -640 361 -640 480 -640 480 -500 375 -480 640 -640 480 -640 487 -640 427 -640 426 -640 429 -480 640 -640 640 -427 640 -427 640 -640 480 -500 375 -500 313 -640 424 -640 480 -640 424 -640 371 -640 425 -640 303 -640 427 -547 640 -640 429 -335 500 -640 480 -640 480 -500 333 -640 594 -640 427 -500 375 -458 640 -640 153 -480 640 -640 480 -640 408 -640 427 -500 375 -640 426 -640 427 -640 640 -640 427 -640 480 -640 609 -640 464 -640 425 -612 612 -640 480 -640 426 -426 640 -640 458 -640 480 -640 480 -640 416 -640 427 -640 480 -640 427 -640 426 -640 429 -612 612 -640 427 -640 403 -640 480 -640 431 -427 640 -640 480 -640 480 -640 427 -480 640 -480 640 -612 612 -640 427 -640 425 -480 640 -500 333 -640 480 -623 515 -375 500 -640 425 -459 640 -640 513 -356 373 -640 428 -640 427 -389 640 -640 408 -640 480 -640 517 -427 640 -640 426 -480 640 -640 404 -640 480 -427 640 -640 632 -500 375 -480 640 -640 415 -334 500 -375 500 -480 640 -640 480 -640 480 -491 640 -640 425 -480 640 -640 410 -612 612 -640 480 -480 640 -480 640 -640 427 -640 480 -640 452 -431 640 -640 428 -251 500 -640 426 -640 502 -640 427 -640 453 -640 480 -640 426 -640 451 -640 480 -640 428 -640 480 -640 480 -640 409 -493 640 -640 480 -500 334 -640 424 -640 518 -640 426 -598 640 -640 427 -640 427 -640 426 -640 427 -640 424 -375 500 -425 500 -640 418 -500 375 -640 480 -640 428 -480 640 -640 426 -500 335 -513 640 -375 500 -597 400 -640 427 -640 480 -640 480 -640 606 -640 380 -640 427 -640 480 -640 426 -640 618 -428 640 -640 425 -480 272 -429 640 -427 640 -640 404 -640 427 -375 500 -500 375 -640 426 -480 640 -480 640 -640 481 -612 612 -640 427 -640 480 -640 478 -640 480 -640 480 -426 640 -640 427 -640 424 -640 428 -640 480 -640 522 -480 640 -640 480 -375 500 -480 640 -640 425 -640 427 -640 383 -640 480 -600 600 -640 427 -640 480 -640 480 -620 413 -640 480 -640 417 -544 640 -515 640 -427 640 -640 480 -640 480 -640 424 -375 500 -640 480 -640 499 -500 332 -383 640 -500 375 -640 480 -640 427 -428 640 -640 481 -640 428 -640 640 -500 375 -640 359 -640 461 -640 426 -640 426 -427 640 -640 480 -640 480 -640 426 -640 480 -448 277 -640 428 -640 393 -500 324 -640 432 -640 480 -479 640 -640 425 -500 375 -640 428 -480 640 -427 640 -640 427 -427 640 -640 484 -640 427 -612 612 -480 640 -500 375 -640 481 -480 640 -480 640 -640 425 -480 640 -604 453 -440 300 -640 477 -640 426 -640 427 -640 480 -640 480 -426 640 -478 640 -640 640 -640 640 -612 612 -640 480 -640 480 -640 427 -532 640 -480 640 -500 332 -612 612 -640 427 -640 480 -640 480 -640 480 -640 480 -640 480 -375 500 -640 640 -640 423 -640 509 -640 396 -640 428 -480 640 -640 480 -426 640 -500 375 -640 480 -640 427 -500 400 -640 427 -640 414 -640 427 -334 500 -640 426 -640 427 -427 640 -427 640 -500 332 -640 480 -360 640 -640 428 -640 426 -480 640 -640 427 -640 427 -422 640 -640 360 -400 500 -480 640 -640 427 -375 500 -335 500 -640 361 -331 500 -640 480 -640 480 -640 480 -640 536 -640 640 -428 640 -640 427 -640 480 -500 333 -640 427 -640 385 -480 640 -640 428 -500 375 -640 425 -427 640 -480 640 -480 640 -640 427 -640 427 -640 480 -640 427 -640 427 -640 480 -462 640 -640 480 -640 480 -640 640 -426 640 -640 427 -640 425 -428 640 -640 427 -640 424 -640 427 -500 375 -479 640 -640 425 -640 428 -500 375 -640 426 -640 480 -427 640 -500 333 -640 480 -425 640 -640 410 -640 480 -640 425 -480 640 -640 480 -640 427 -640 453 -640 426 -640 480 -640 483 -640 427 -640 427 -640 450 -612 612 -640 478 -478 640 -425 640 -640 424 -640 427 -640 427 -640 480 -375 500 -500 439 -640 359 -640 426 -640 480 -480 640 -640 427 -640 480 -640 480 -500 375 -640 480 -640 427 -640 480 -640 426 -433 640 -640 427 -640 463 -640 425 -640 425 -640 426 -640 424 -640 426 -640 429 -640 427 -500 333 -640 480 -640 480 -640 480 -640 427 -480 640 -480 640 -480 485 -640 427 -640 427 -640 428 -480 640 -371 500 -500 375 -640 427 -500 375 -375 500 -500 375 -640 428 -500 375 -640 480 -640 626 -640 360 -640 564 -640 424 -640 480 -375 500 -640 428 -640 427 -640 426 -479 640 -640 512 -640 480 -488 640 -334 500 -640 427 -480 640 -640 499 -480 640 -640 480 -640 627 -640 425 -640 480 -426 640 -640 424 -640 480 -640 427 -640 427 -640 569 -640 480 -640 426 -480 640 -640 480 -481 640 -428 640 -640 427 -640 427 -640 422 -640 429 -480 360 -640 480 -640 480 -640 376 -640 346 -428 640 -640 427 -640 427 -640 360 -640 458 -427 640 -640 479 -500 375 -640 480 -400 300 -500 375 -480 640 -640 427 -428 640 -640 640 -480 640 -640 640 -640 480 -640 471 -640 455 -640 427 -640 480 -640 425 -424 640 -640 361 -640 419 -640 480 -376 500 -640 480 -640 436 -500 375 -480 640 -640 480 -640 481 -640 254 -640 427 -640 427 -640 426 -640 453 -480 640 -640 427 -428 640 -427 640 -640 299 -469 640 -640 480 -640 480 -616 640 -640 480 -500 375 -375 500 -612 612 -332 500 -640 394 -612 612 -640 427 -640 428 -640 426 -640 480 -500 375 -640 427 -480 640 -640 480 -480 640 -640 456 -427 640 -640 480 -559 600 -375 500 -500 375 -640 480 -640 427 -640 480 -480 640 -500 333 -640 184 -427 640 -500 375 -640 480 -640 464 -640 481 -640 326 -426 640 -640 426 -640 427 -500 375 -640 352 -640 480 -640 479 -615 640 -640 425 -640 427 -640 363 -640 480 -640 437 -640 480 -480 319 -600 600 -640 453 -500 332 -640 424 -640 490 -640 480 -356 500 -640 480 -500 333 -375 500 -640 427 -640 480 -640 429 -640 428 -640 425 -640 489 -333 500 -640 439 -480 640 -640 426 -612 612 -391 640 -640 480 -640 427 -281 640 -640 424 -480 640 -640 359 -640 427 -640 480 -480 640 -640 480 -500 375 -640 427 -640 427 -640 427 -640 427 -640 480 -640 480 -640 427 -612 612 -427 640 -640 480 -480 640 -640 480 -640 480 -640 427 -500 375 -427 640 -480 640 -640 428 -640 480 -640 480 -640 457 -640 360 -640 480 -500 337 -640 464 -427 640 -640 424 -640 400 -500 333 -640 427 -500 332 -640 480 -480 640 -640 427 -640 427 -525 350 -640 351 -640 425 -640 480 -640 480 -640 426 -328 500 -575 640 -640 259 -640 426 -640 401 -500 375 -440 500 -640 427 -640 354 -480 640 -640 480 -640 480 -640 480 -640 415 -600 327 -457 640 -500 333 -480 640 -612 612 -640 640 -640 480 -640 424 -425 640 -640 408 -640 431 -640 424 -640 427 -500 500 -425 640 -500 375 -640 410 -640 428 -640 480 -480 640 -640 480 -479 640 -640 480 -500 375 -424 640 -640 480 -640 426 -640 428 -640 425 -640 427 -640 575 -640 438 -640 480 -480 640 -612 612 -640 426 -640 427 -640 443 -640 376 -500 375 -427 640 -612 612 -427 640 -426 640 -640 480 -640 480 -383 640 -640 482 -640 480 -640 480 -640 425 -640 424 -424 640 -640 640 -640 428 -640 531 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -640 478 -640 483 -640 430 -640 480 -560 640 -426 640 -640 427 -400 500 -500 388 -640 476 -640 427 -640 427 -640 427 -640 424 -480 640 -612 612 -538 360 -480 640 -640 428 -604 402 -375 500 -640 480 -500 375 -500 375 -476 640 -640 495 -640 640 -402 640 -640 478 -640 480 -640 427 -475 640 -640 480 -640 480 -640 428 -600 450 -640 433 -426 640 -480 640 -640 480 -640 427 -640 625 -640 480 -640 427 -480 640 -457 640 -640 480 -640 480 -612 612 -640 425 -480 640 -640 427 -640 550 -640 426 -640 427 -640 640 -640 480 -640 480 -640 427 -360 328 -640 424 -315 484 -500 375 -640 427 -640 438 -640 426 -640 466 -425 640 -640 427 -640 427 -640 426 -640 480 -640 480 -640 427 -500 467 -640 401 -640 426 -640 480 -375 500 -640 481 -360 640 -546 640 -640 480 -480 640 -640 480 -640 427 -640 428 -640 506 -448 336 -640 425 -612 612 -428 640 -480 640 -480 640 -481 640 -640 480 -640 427 -640 477 -640 480 -612 612 -500 500 -640 426 -640 478 -640 427 -500 342 -426 640 -375 500 -640 427 -416 640 -640 446 -640 480 -640 480 -640 424 -640 427 -640 480 -640 427 -418 640 -640 426 -640 426 -427 640 -640 480 -640 481 -640 480 -375 500 -640 480 -640 480 -640 480 -640 480 -640 428 -640 392 -426 640 -640 480 -640 480 -640 427 -640 383 -640 529 -640 482 -640 427 -640 427 -640 457 -427 640 -480 640 -640 411 -640 480 -640 480 -640 360 -640 427 -640 480 -640 426 -640 401 -640 360 -640 480 -480 640 -427 640 -640 480 -640 428 -640 480 -596 640 -500 333 -640 480 -640 496 -409 500 -640 495 -455 341 -500 332 -427 640 -640 427 -640 427 -375 500 -640 429 -640 480 -640 427 -640 480 -640 480 -640 478 -426 640 -640 360 -640 384 -640 423 -640 427 -640 480 -434 640 -640 426 -640 427 -640 427 -640 427 -640 427 -640 480 -640 396 -640 480 -640 426 -640 480 -424 640 -640 479 -640 425 -480 640 -640 480 -640 480 -640 515 -640 480 -480 640 -640 428 -640 480 -640 426 -640 426 -480 640 -480 640 -640 480 -640 480 -640 424 -480 640 -640 426 -640 448 -640 425 -427 640 -375 500 -640 480 -480 640 -500 281 -480 640 -640 452 -360 640 -640 243 -640 480 -640 480 -640 514 -640 446 -640 428 -640 480 -457 640 -424 640 -480 640 -500 375 -612 612 -640 453 -640 427 -480 640 -640 453 -513 640 -640 426 -640 480 -640 427 -500 375 -640 480 -424 640 -500 375 -640 480 -640 426 -640 480 -640 400 -480 640 -424 640 -500 375 -640 512 -640 480 -640 425 -640 480 -500 375 -500 375 -428 640 -640 488 -640 480 -640 425 -500 375 -500 375 -640 624 -640 429 -500 500 -640 429 -640 480 -413 640 -480 640 -427 640 -427 640 -480 640 -640 347 -640 516 -427 640 -427 640 -500 375 -640 480 -426 640 -436 640 -640 428 -640 426 -640 427 -640 480 -333 500 -640 426 -480 640 -640 427 -640 480 -480 640 -480 640 -500 375 -427 640 -640 427 -510 640 -480 640 -419 637 -427 640 -352 288 -480 640 -640 524 -480 640 -367 500 -640 480 -640 480 -640 426 -480 640 -640 480 -519 640 -640 427 -640 329 -640 427 -640 383 -640 480 -480 640 -640 427 -640 429 -480 640 -400 500 -640 426 -640 427 -500 333 -480 640 -299 500 -640 480 -640 480 -640 480 -334 500 -640 480 -640 480 -640 434 -500 375 -479 640 -640 427 -640 360 -640 409 -427 640 -640 510 -427 640 -640 479 -640 212 -480 640 -640 480 -640 427 -640 478 -396 500 -640 387 -640 640 -640 477 -640 417 -640 439 -640 427 -640 425 -640 438 -450 600 -640 424 -640 427 -640 361 -640 480 -640 427 -640 512 -640 480 -640 480 -640 471 -500 311 -640 426 -640 426 -640 480 -640 428 -500 375 -480 640 -640 471 -640 480 -640 428 -640 427 -640 451 -480 640 -427 640 -388 640 -640 314 -640 427 -500 400 -500 334 -640 426 -640 427 -640 480 -640 424 -427 640 -640 471 -640 480 -640 431 -640 427 -640 427 -514 640 -500 271 -329 640 -640 480 -500 332 -640 425 -480 640 -500 375 -640 428 -640 426 -640 425 -640 480 -640 412 -640 431 -640 443 -640 481 -500 333 -640 425 -640 384 -427 640 -640 427 -427 640 -500 375 -640 480 -640 427 -640 360 -480 640 -640 480 -500 233 -480 640 -640 426 -449 640 -640 396 -640 426 -566 640 -640 427 -640 529 -612 612 -640 409 -640 426 -480 640 -640 480 -640 428 -500 375 -500 375 -640 512 -640 427 -640 480 -425 640 -640 426 -612 612 -398 640 -640 363 -640 469 -460 640 -640 482 -500 332 -640 425 -640 426 -640 426 -427 640 -640 480 -640 480 -640 427 -640 446 -640 424 -427 640 -640 480 -640 480 -640 427 -640 425 -424 640 -640 427 -640 480 -640 480 -640 400 -640 480 -480 640 -640 288 -480 640 -375 500 -640 480 -500 399 -640 480 -500 375 -480 640 -426 640 -640 480 -640 480 -640 480 -640 427 -640 544 -640 429 -500 365 -640 480 -640 426 -640 428 -640 480 -640 429 -483 640 -640 427 -640 426 -640 480 -640 513 -500 375 -500 396 -381 640 -640 480 -500 375 -640 480 -427 640 -640 426 -640 427 -640 458 -640 360 -640 426 -466 640 -640 480 -480 640 -427 640 -640 427 -640 425 -640 480 -640 428 -500 461 -119 184 -640 427 -640 426 -640 480 -492 500 -640 480 -427 640 -640 360 -640 480 -640 480 -640 640 -375 500 -640 427 -640 423 -568 320 -640 480 -640 480 -640 389 -480 640 -407 640 -640 480 -640 471 -640 445 -480 640 -335 500 -480 640 -640 480 -640 480 -640 428 -640 400 -640 480 -640 480 -640 361 -640 640 -500 375 -427 640 -640 480 -640 424 -640 426 -640 479 -480 640 -640 480 -500 377 -500 362 -500 375 -640 480 -500 333 -640 427 -640 480 -640 427 -640 480 -500 374 -640 361 -640 480 -640 427 -570 640 -640 425 -640 480 -640 480 -640 480 -480 640 -500 334 -640 480 -480 640 -480 640 -500 375 -480 640 -640 640 -640 480 -640 275 -640 480 -500 375 -640 480 -398 640 -640 427 -640 413 -640 509 -640 435 -640 426 -640 361 -427 640 -640 427 -640 480 -429 640 -640 480 -640 533 -500 375 -480 640 -640 425 -640 480 -640 470 -640 423 -640 480 -640 480 -427 640 -640 480 -333 500 -640 427 -640 427 -640 424 -640 480 -428 640 -640 480 -640 429 -640 427 -375 500 -640 427 -640 427 -480 640 -640 329 -640 480 -640 425 -480 640 -640 354 -640 427 -640 480 -640 480 -640 480 -500 375 -640 480 -426 640 -427 640 -640 480 -500 400 -480 640 -427 640 -640 427 -640 369 -600 640 -480 640 -612 612 -640 424 -478 640 -640 427 -640 426 -640 480 -480 640 -640 269 -640 640 -480 640 -420 640 -640 480 -480 640 -427 640 -640 427 -640 499 -480 640 -640 427 -640 478 -512 640 -640 427 -612 612 -640 407 -640 426 -555 640 -640 428 -427 640 -640 427 -640 480 -640 480 -640 426 -640 480 -640 480 -640 335 -640 425 -480 640 -640 428 -640 489 -640 458 -612 612 -460 640 -500 333 -332 500 -480 640 -640 427 -640 426 -640 480 -500 375 -640 425 -640 427 -612 612 -640 480 -640 480 -568 640 -640 427 -375 500 -500 345 -640 427 -640 480 -640 480 -640 426 -480 640 -427 640 -500 375 -500 375 -640 480 -640 287 -640 427 -640 480 -640 427 -500 333 -640 427 -640 480 -480 640 -640 426 -640 480 -640 426 -425 640 -480 640 -512 640 -640 425 -640 427 -426 640 -640 427 -640 480 -478 640 -480 640 -427 640 -500 400 -640 480 -640 509 -640 399 -500 333 -640 640 -640 425 -640 360 -640 480 -640 419 -500 375 -504 640 -640 480 -640 480 -640 480 -640 480 -500 375 -500 333 -640 427 -640 480 -640 424 -640 424 -640 427 -600 600 -640 480 -500 375 -500 332 -427 640 -640 448 -640 426 -500 375 -640 480 -640 462 -640 429 -640 480 -640 480 -425 640 -500 333 -500 375 -427 640 -640 480 -640 480 -640 428 -612 612 -640 480 -640 408 -600 459 -640 480 -427 640 -640 480 -640 480 -640 427 -426 640 -640 424 -640 516 -640 425 -489 640 -640 439 -640 391 -640 426 -640 480 -640 427 -640 427 -480 640 -480 640 -640 472 -640 480 -640 480 -640 384 -640 479 -612 612 -640 426 -480 640 -500 272 -640 427 -640 471 -360 640 -640 427 -640 480 -640 480 -640 424 -640 498 -431 640 -640 426 -640 427 -640 478 -640 426 -426 640 -640 480 -640 480 -500 375 -427 640 -640 346 -640 383 -640 333 -640 480 -500 317 -462 640 -427 640 -640 457 -640 404 -640 425 -640 360 -480 640 -640 427 -640 427 -425 640 -640 425 -640 427 -480 640 -640 427 -640 354 -427 640 -640 382 -640 480 -640 436 -350 500 -640 429 -640 427 -375 500 -612 612 -640 480 -500 333 -383 640 -500 334 -640 480 -494 640 -640 426 -640 427 -427 640 -640 480 -640 444 -640 424 -640 426 -640 480 -640 480 -427 640 -500 411 -427 640 -640 426 -640 427 -640 427 -640 480 -640 424 -640 424 -425 640 -629 640 -640 480 -640 427 -640 427 -640 480 -640 427 -427 640 -640 391 -640 480 -500 368 -500 340 -640 512 -640 427 -426 640 -426 640 -640 426 -640 448 -640 480 -640 588 -612 612 -640 480 -500 269 -492 640 -640 427 -640 478 -640 509 -480 640 -640 480 -640 360 -640 480 -640 427 -640 429 -640 513 -640 480 -640 425 -640 488 -640 345 -640 461 -500 375 -640 480 -500 375 -480 640 -500 345 -640 480 -640 415 -640 428 -640 480 -480 640 -640 559 -640 360 -640 480 -640 426 -427 640 -640 427 -500 297 -427 640 -448 640 -640 427 -640 425 -640 480 -640 480 -384 640 -426 640 -640 504 -640 427 -481 640 -480 640 -640 456 -640 480 -640 479 -480 640 -612 612 -640 427 -640 418 -640 360 -427 640 -640 426 -640 427 -640 480 -500 333 -375 500 -500 334 -480 360 -480 640 -640 480 -640 480 -640 348 -375 500 -640 426 -426 640 -640 425 -640 426 -500 375 -500 375 -640 427 -640 480 -640 426 -427 640 -640 502 -480 640 -640 360 -640 313 -640 427 -640 478 -427 640 -461 640 -480 640 -640 407 -550 640 -640 480 -480 640 -640 481 -640 427 -612 612 -550 275 -640 430 -640 480 -480 640 -640 427 -640 480 -640 427 -640 480 -640 427 -640 384 -640 427 -640 480 -640 427 -640 449 -375 500 -640 359 -396 640 -640 428 -640 428 -400 600 -640 425 -427 640 -640 480 -640 480 -640 481 -428 640 -640 359 -612 612 -640 438 -640 358 -640 394 -640 480 -640 480 -640 399 -427 640 -500 333 -640 427 -640 427 -640 480 -640 561 -640 428 -640 361 -640 587 -640 480 -640 480 -640 480 -640 427 -400 500 -500 375 -500 309 -640 403 -640 480 -381 640 -640 427 -481 640 -640 480 -640 427 -640 311 -480 640 -640 424 -640 480 -612 612 -640 480 -640 480 -640 494 -640 574 -640 426 -469 640 -640 480 -640 480 -425 640 -640 481 -640 480 -640 359 -640 472 -640 476 -640 360 -375 500 -640 409 -422 640 -640 383 -640 359 -640 437 -640 480 -640 350 -640 480 -640 427 -640 401 -640 480 -500 377 -640 426 -612 612 -500 333 -640 425 -480 640 -640 369 -640 427 -333 500 -427 640 -427 640 -640 427 -416 640 -640 424 -640 427 -640 463 -427 640 -640 480 -640 480 -640 480 -640 480 -640 426 -640 480 -640 457 -500 335 -640 364 -640 428 -640 427 -640 424 -640 427 -640 425 -640 425 -640 609 -480 640 -640 426 -640 426 -640 480 -640 480 -640 480 -640 480 -500 375 -640 480 -640 391 -479 640 -427 640 -640 427 -461 640 -640 425 -500 375 -500 400 -640 427 -640 502 -480 640 -500 397 -640 480 -427 640 -500 334 -402 640 -640 427 -640 427 -640 480 -640 427 -640 425 -640 609 -640 480 -640 427 -640 567 -640 424 -640 427 -640 427 -640 428 -640 480 -640 480 -479 640 -640 480 -425 640 -640 553 -640 480 -640 480 -640 480 -640 425 -640 480 -640 448 -420 640 -480 640 -480 640 -480 640 -427 640 -640 502 -500 375 -360 640 -427 640 -500 491 -640 427 -640 426 -640 427 -640 428 -640 480 -500 375 -640 480 -480 640 -640 427 -640 427 -640 427 -428 640 -428 640 -640 480 -640 480 -640 480 -640 448 -640 390 -640 478 -427 640 -500 333 -450 600 -640 391 -600 399 -480 640 -640 361 -500 380 -640 494 -640 451 -640 427 -427 640 -640 480 -640 480 -640 360 -640 593 -500 375 -640 434 -480 640 -640 480 -427 640 -425 640 -640 640 -640 418 -640 399 -640 427 -612 612 -640 427 -640 480 -640 491 -427 640 -427 640 -640 480 -640 640 -640 519 -640 427 -375 500 -478 640 -336 500 -480 640 -500 421 -480 640 -640 421 -640 426 -500 335 -640 426 -640 480 -640 427 -640 480 -510 640 -640 427 -640 273 -640 428 -640 426 -640 480 -640 480 -463 640 -640 424 -425 640 -500 375 -427 640 -480 480 -640 424 -640 427 -640 480 -500 375 -640 427 -640 428 -640 446 -640 427 -500 375 -375 500 -500 375 -427 640 -640 640 -480 640 -640 428 -640 480 -640 427 -640 425 -334 500 -640 361 -612 612 -640 427 -341 500 -612 612 -640 428 -640 360 -640 360 -640 480 -640 370 -640 475 -640 479 -640 427 -456 640 -640 427 -428 640 -640 480 -640 492 -640 558 -640 480 -427 640 -640 496 -480 640 -500 375 -640 425 -480 640 -640 426 -640 464 -640 480 -640 480 -500 328 -640 640 -640 640 -640 429 -640 426 -640 427 -640 426 -640 410 -640 457 -640 426 -480 640 -640 480 -640 480 -640 480 -640 480 -640 427 -424 640 -640 428 -500 375 -428 640 -337 500 -640 426 -334 500 -640 480 -640 289 -640 425 -500 375 -427 640 -640 480 -360 640 -333 500 -640 480 -640 574 -640 427 -640 480 -640 427 -426 640 -640 427 -640 426 -640 480 -640 427 -375 500 -500 375 -640 480 -640 335 -640 444 -640 212 -640 480 -546 640 -640 480 -640 359 -640 426 -500 375 -640 426 -640 480 -500 400 -640 480 -640 480 -425 640 -478 640 -480 422 -425 640 -481 640 -400 600 -640 480 -640 480 -640 480 -480 640 -612 612 -462 640 -439 640 -480 640 -612 612 -426 640 -500 394 -640 428 -640 444 -640 427 -640 427 -640 428 -640 380 -640 480 -640 480 -640 438 -612 612 -640 427 -444 500 -640 360 -640 423 -640 640 -427 640 -640 480 -640 480 -640 480 -480 640 -640 426 -640 480 -640 426 -640 427 -640 456 -640 426 -375 500 -640 438 -640 459 -640 366 -640 480 -640 480 -640 480 -428 640 -640 480 -640 345 -640 429 -480 640 -480 640 -500 332 -640 425 -418 640 -640 233 -640 480 -375 500 -640 480 -427 640 -640 428 -640 480 -424 640 -332 500 -640 443 -640 480 -640 427 -640 463 -600 400 -640 425 -640 427 -640 480 -640 480 -640 428 -500 375 -640 480 -640 459 -640 427 -640 480 -640 480 -480 640 -427 640 -640 381 -426 640 -427 640 -500 400 -640 425 -480 640 -424 640 -640 427 -640 480 -640 480 -612 612 -640 427 -640 359 -333 500 -426 640 -640 427 -640 480 -640 480 -640 480 -640 426 -640 480 -426 640 -500 375 -640 427 -500 318 -500 375 -640 481 -640 360 -640 427 -426 640 -500 375 -640 427 -640 480 -500 334 -640 480 -640 427 -480 640 -640 427 -640 429 -640 426 -640 426 -640 373 -640 426 -640 426 -640 457 -640 512 -640 480 -478 640 -640 480 -640 383 -426 640 -640 481 -640 427 -500 375 -640 426 -640 480 -425 640 -640 428 -478 640 -427 640 -640 287 -640 426 -640 480 -640 427 -419 640 -640 640 -640 427 -640 480 -640 480 -500 333 -640 426 -480 640 -600 596 -640 428 -640 475 -640 360 -640 480 -640 427 -640 480 -640 478 -640 415 -640 480 -480 640 -640 457 -500 375 -429 640 -427 640 -640 619 -640 427 -640 225 -640 426 -426 640 -640 534 -640 427 -640 480 -640 444 -640 480 -640 480 -640 478 -640 313 -640 426 -640 426 -640 410 -640 424 -640 480 -480 640 -500 333 -640 480 -640 384 -500 341 -640 480 -500 500 -640 427 -640 480 -500 400 -480 640 -640 429 -427 640 -500 281 -640 480 -640 439 -640 480 -640 428 -640 480 -640 425 -500 375 -640 416 -640 480 -640 426 -640 480 -640 512 -640 366 -612 612 -344 500 -640 320 -640 533 -500 375 -640 480 -640 480 -500 334 -480 640 -640 427 -500 376 -640 480 -480 640 -640 424 -500 500 -480 640 -480 640 -640 401 -640 480 -500 499 -480 640 -640 480 -640 427 -640 480 -400 500 -640 424 -640 424 -640 480 -427 640 -640 427 -640 425 -500 375 -640 428 -640 414 -640 426 -640 426 -640 428 -427 640 -640 480 -612 612 -640 480 -640 480 -640 457 -500 335 -480 640 -640 427 -500 375 -480 640 -640 427 -640 480 -640 480 -483 640 -480 640 -640 427 -640 455 -640 480 -480 320 -640 480 -434 640 -640 425 -436 640 -396 640 -500 375 -640 478 -640 426 -640 480 -640 480 -640 427 -427 640 -640 427 -640 480 -640 426 -500 375 -500 500 -640 412 -640 342 -480 640 -640 426 -333 500 -640 458 -640 480 -500 500 -640 360 -640 480 -640 640 -512 640 -612 612 -640 427 -640 427 -636 640 -612 612 -640 480 -640 480 -640 480 -640 389 -640 542 -640 480 -640 430 -640 425 -500 333 -640 640 -640 427 -425 640 -427 640 -640 480 -333 500 -640 426 -640 426 -640 512 -640 480 -360 640 -640 427 -333 357 -500 375 -478 640 -640 478 -640 427 -640 428 -640 427 -640 413 -457 640 -612 612 -480 640 -640 483 -640 480 -640 480 -640 360 -480 640 -427 640 -640 480 -640 511 -640 480 -640 480 -300 400 -640 360 -375 500 -640 424 -640 480 -640 480 -640 574 -427 640 -640 478 -640 480 -534 640 -480 640 -640 480 -640 425 -372 500 -640 480 -640 425 -640 425 -640 384 -640 480 -497 500 -640 426 -427 640 -640 429 -640 480 -640 427 -640 428 -640 480 -484 640 -640 449 -459 640 -640 480 -640 601 -612 612 -640 480 -335 500 -427 640 -640 411 -500 332 -640 360 -480 640 -640 427 -426 640 -447 500 -640 424 -640 427 -640 346 -640 480 -640 360 -640 480 -428 640 -500 299 -640 427 -640 457 -640 427 -478 500 -427 640 -640 427 -640 449 -640 466 -640 480 -427 640 -640 480 -640 480 -640 480 -640 558 -640 480 -500 334 -640 444 -640 480 -361 640 -480 640 -640 473 -600 600 -640 496 -500 357 -480 640 -640 480 -500 330 -375 500 -640 427 -500 375 -541 640 -480 640 -640 480 -640 416 -640 480 -640 425 -640 426 -500 376 -640 427 -427 640 -478 640 -640 427 -425 640 -640 427 -640 425 -640 426 -640 360 -425 640 -375 500 -640 480 -640 427 -427 640 -640 443 -322 365 -638 512 -640 424 -640 478 -639 640 -640 480 -500 333 -640 427 -640 433 -640 502 -640 614 -640 480 -640 480 -480 640 -640 480 -640 480 -640 480 -375 500 -640 426 -640 299 -333 500 -640 427 -500 333 -640 480 -427 640 -431 640 -500 333 -640 480 -640 480 -640 434 -640 484 -640 458 -640 296 -640 427 -427 640 -640 480 -336 500 -472 640 -500 332 -640 427 -500 375 -640 480 -480 640 -480 640 -500 386 -612 612 -640 213 -640 426 -334 500 -640 471 -640 360 -640 586 -640 427 -640 424 -640 413 -640 427 -640 427 -612 612 -640 480 -640 427 -331 500 -640 428 -500 336 -500 375 -640 560 -640 480 -612 612 -640 480 -640 427 -500 375 -427 640 -640 480 -640 480 -640 366 -640 425 -640 427 -640 480 -426 640 -640 480 -640 640 -640 480 -640 425 -640 480 -500 333 -640 427 -640 480 -640 478 -478 640 -640 428 -640 480 -500 375 -640 501 -500 375 -427 640 -640 481 -640 426 -640 480 -426 640 -480 640 -435 640 -427 640 -640 427 -640 427 -640 480 -240 320 -640 428 -640 640 -640 509 -640 480 -640 480 -500 394 -375 500 -428 640 -640 480 -640 426 -640 480 -500 333 -428 640 -375 500 -431 640 -640 480 -640 427 -590 640 -500 465 -466 640 -600 600 -433 640 -500 332 -434 640 -640 640 -640 480 -640 425 -480 640 -480 640 -640 480 -640 480 -640 480 -640 301 -640 480 -640 478 -640 360 -640 425 -500 376 -640 427 -640 432 -640 427 -460 390 -500 375 -640 426 -480 640 -640 426 -640 426 -640 427 -426 640 -500 375 -640 426 -640 480 -640 427 -640 263 -480 640 -640 480 -640 425 -500 333 -640 480 -640 427 -640 427 -480 640 -640 480 -640 449 -500 327 -640 480 -500 350 -640 480 -640 320 -480 640 -400 500 -612 612 -425 640 -372 500 -375 500 -500 334 -640 427 -427 640 -640 480 -480 640 -640 427 -500 375 -478 640 -465 500 -640 428 -336 500 -480 640 -410 640 -416 500 -640 453 -500 375 -640 480 -500 375 -360 640 -640 401 -640 640 -640 480 -640 427 -640 480 -640 426 -332 500 -640 361 -640 480 -427 640 -640 426 -640 505 -640 588 -640 427 -640 409 -500 333 -500 375 -500 376 -640 415 -640 480 -640 480 -640 426 -640 480 -640 427 -640 399 -600 366 -640 360 -640 457 -640 480 -640 427 -640 427 -640 428 -480 640 -640 521 -500 333 -640 480 -500 325 -581 640 -640 480 -640 426 -500 333 -480 640 -640 428 -640 426 -427 640 -640 427 -640 427 -459 640 -375 500 -480 640 -640 427 -640 427 -640 451 -612 612 -640 480 -640 427 -427 640 -612 612 -640 427 -429 640 -640 480 -480 640 -640 480 -640 428 -480 640 -500 295 -640 424 -640 428 -500 375 -480 640 -428 640 -480 640 -640 427 -375 500 -500 333 -612 612 -640 480 -640 463 -500 333 -640 427 -462 640 -640 480 -640 480 -640 433 -640 618 -640 480 -425 640 -500 375 -640 214 -640 480 -640 480 -640 480 -640 480 -640 480 -500 356 -375 500 -640 480 -640 427 -480 353 -640 640 -500 375 -640 480 -640 424 -640 427 -640 426 -640 426 -640 640 -640 427 -640 427 -500 375 -640 434 -640 427 -640 427 -500 375 -500 333 -640 425 -420 640 -427 640 -640 428 -640 480 -640 480 -640 360 -374 500 -640 428 -375 500 -640 408 -500 375 -433 640 -612 612 -640 480 -640 480 -426 640 -427 640 -640 487 -480 640 -423 640 -640 480 -640 427 -640 480 -335 640 -640 426 -640 440 -640 480 -427 640 -640 480 -427 640 -640 480 -640 427 -500 375 -427 640 -640 427 -640 540 -640 426 -640 427 -500 377 -427 640 -640 480 -640 425 -500 332 -640 571 -640 428 -480 640 -640 428 -478 640 -640 569 -640 480 -428 640 -640 424 -640 480 -640 427 -640 514 -640 485 -640 409 -427 640 -640 427 -640 427 -429 640 -389 640 -640 480 -640 427 -359 640 -640 425 -640 426 -640 427 -640 373 -640 426 -640 427 -640 427 -486 640 -640 480 -427 640 -639 640 -500 375 -500 373 -640 480 -426 640 -640 366 -640 338 -333 500 -500 338 -427 640 -640 479 -500 375 -640 480 -640 519 -640 427 -320 240 -640 427 -612 612 -640 341 -428 640 -480 640 -640 466 -640 473 -640 313 -480 640 -640 640 -640 476 -640 480 -640 427 -640 480 -375 500 -427 640 -640 426 -640 480 -640 480 -444 640 -426 640 -427 640 -380 640 -640 480 -640 480 -640 339 -640 427 -640 573 -640 480 -480 640 -640 427 -640 480 -640 428 -640 426 -500 497 -640 428 -640 475 -640 361 -640 426 -256 217 -640 480 -640 480 -640 480 -427 640 -640 480 -500 375 -640 424 -500 341 -640 480 -453 640 -640 444 -500 400 -480 640 -500 333 -480 640 -640 427 -640 478 -640 424 -640 424 -640 427 -500 332 -427 640 -500 375 -500 334 -361 500 -640 430 -640 427 -500 375 -640 479 -428 640 -640 479 -427 640 -428 640 -640 425 -640 480 -640 424 -514 640 -480 640 -640 428 -640 480 -640 479 -640 426 -640 427 -640 424 -500 375 -360 640 -640 479 -427 640 -640 490 -500 375 -480 640 -500 333 -640 423 -640 426 -480 640 -640 480 -640 415 -640 431 -480 640 -640 423 -640 480 -428 640 -500 375 -640 396 -640 427 -640 427 -500 375 -640 480 -640 427 -640 499 -480 640 -480 640 -640 427 -640 470 -640 425 -500 333 -500 335 -640 410 -160 120 -640 428 -478 640 -640 436 -612 612 -640 480 -500 375 -640 425 -427 640 -400 453 -437 640 -480 640 -612 612 -500 281 -640 480 -425 640 -480 640 -640 344 -640 480 -640 428 -479 640 -640 428 -480 640 -500 375 -640 428 -640 427 -640 426 -640 480 -500 438 -427 640 -640 480 -640 480 -480 640 -640 362 -640 427 -640 480 -320 500 -640 393 -500 375 -453 640 -427 640 -640 503 -640 429 -640 425 -424 640 -426 640 -640 480 -640 480 -640 480 -640 426 -640 480 -426 640 -640 290 -640 480 -480 360 -640 480 -517 640 -480 640 -640 480 -480 640 -500 335 -450 338 -427 640 -640 480 -640 480 -640 480 -640 426 -640 480 -640 600 -431 640 -640 480 -428 640 -435 640 -640 427 -640 640 -640 425 -640 480 -640 426 -640 480 -640 426 -500 375 -640 480 -500 471 -640 480 -640 426 -640 426 -480 640 -640 431 -640 480 -640 429 -425 640 -640 342 -640 427 -640 480 -612 612 -640 428 -500 333 -252 252 -459 640 -640 427 -640 480 -389 640 -640 480 -640 427 -375 500 -640 425 -640 360 -489 640 -640 447 -500 334 -640 424 -480 640 -500 375 -640 425 -640 480 -427 640 -640 427 -640 480 -360 356 -500 375 -640 480 -640 427 -457 640 -500 375 -640 480 -479 640 -480 640 -640 427 -640 427 -640 478 -640 427 -640 480 -640 360 -640 480 -640 324 -640 427 -480 640 -640 427 -640 360 -640 429 -640 480 -331 500 -427 640 -640 458 -640 463 -640 427 -427 640 -640 480 -640 480 -640 427 -640 480 -442 640 -640 480 -640 426 -426 640 -640 429 -429 640 -640 426 -425 640 -640 480 -640 427 -640 440 -424 640 -640 426 -500 327 -640 480 -640 426 -640 480 -640 427 -480 640 -640 426 -640 480 -640 514 -500 384 -624 640 -457 640 -500 375 -640 486 -640 427 -640 480 -640 433 -426 640 -640 480 -640 411 -500 375 -640 360 -427 640 -640 427 -480 640 -640 288 -360 640 -640 427 -480 272 -640 480 -640 428 -640 480 -640 448 -640 640 -640 426 -640 427 -384 512 -640 427 -640 480 -640 426 -480 640 -480 640 -500 400 -500 335 -640 426 -640 480 -640 453 -480 640 -320 240 -640 480 -640 425 -640 480 -640 428 -375 500 -640 427 -640 458 -640 427 -640 320 -500 375 -500 407 -640 427 -389 640 -500 375 -640 483 -640 630 -480 640 -480 640 -640 480 -433 640 -480 640 -640 428 -640 412 -500 313 -640 427 -612 612 -480 640 -640 480 -480 640 -640 426 -640 426 -500 344 -640 361 -500 333 -640 480 -640 357 -640 427 -640 426 -640 429 -640 428 -640 426 -480 640 -640 263 -640 480 -640 480 -640 480 -640 486 -316 640 -480 640 -640 427 -640 480 -612 612 -640 523 -427 640 -480 640 -416 500 -640 428 -640 427 -576 576 -640 427 -640 480 -640 425 -640 427 -640 529 -640 428 -640 427 -500 332 -640 636 -640 480 -640 427 -640 426 -640 480 -640 480 -640 480 -640 480 -640 428 -640 427 -640 346 -640 480 -640 496 -640 480 -640 480 -480 640 -500 375 -640 506 -640 480 -426 640 -640 362 -480 640 -550 375 -640 428 -480 640 -640 428 -640 480 -640 428 -612 612 -375 500 -640 480 -640 429 -640 640 -640 457 -640 480 -640 360 -640 481 -640 458 -640 416 -480 640 -640 480 -640 400 -640 427 -640 453 -640 427 -640 359 -612 612 -480 640 -640 480 -640 427 -640 480 -640 428 -640 426 -480 640 -640 425 -640 428 -640 480 -640 480 -640 480 -640 480 -640 427 -640 480 -640 393 -640 426 -640 480 -500 495 -640 428 -640 426 -640 426 -480 640 -640 480 -480 640 -434 640 -578 433 -480 640 -640 427 -640 480 -500 433 -612 612 -640 427 -427 640 -428 640 -640 424 -480 640 -427 640 -478 640 -640 376 -332 500 -480 640 -640 389 -640 427 -640 427 -612 612 -640 480 -428 640 -640 478 -448 640 -427 640 -640 444 -500 375 -500 333 -500 375 -640 425 -480 640 -640 426 -640 427 -640 480 -640 480 -640 480 -500 332 -427 640 -640 480 -640 480 -640 480 -640 425 -640 480 -640 427 -640 480 -500 375 -640 426 -640 427 -640 427 -500 375 -640 428 -640 426 -640 428 -640 480 -640 426 -640 427 -640 360 -640 480 -640 479 -500 334 -334 500 -480 640 -640 464 -640 426 -500 375 -640 427 -500 375 -640 480 -480 640 -640 408 -640 408 -640 427 -640 424 -640 427 -640 427 -640 427 -640 425 -500 283 -480 640 -640 426 -518 640 -640 480 -640 559 -640 428 -640 480 -640 480 -640 480 -640 427 -640 426 -427 640 -333 500 -640 427 -640 480 -500 375 -640 480 -427 640 -640 458 -427 640 -640 480 -640 480 -480 640 -640 427 -640 427 -640 427 -640 480 -480 360 -640 427 -427 640 -640 428 -640 427 -375 500 -427 640 -640 427 -480 640 -424 640 -500 332 -500 375 -350 500 -640 427 -640 454 -480 640 -640 425 -640 533 -640 425 -500 375 -640 426 -640 503 -379 640 -640 377 -500 333 -480 640 -640 477 -480 640 -640 480 -640 480 -480 640 -640 426 -640 549 -640 480 -640 427 -500 375 -640 426 -640 361 -640 419 -428 640 -640 418 -612 612 -427 640 -640 427 -640 419 -500 236 -640 480 -640 480 -640 640 -640 425 -478 640 -500 452 -640 426 -640 426 -640 363 -640 360 -640 438 -478 640 -640 355 -640 427 -640 427 -500 375 -640 427 -640 480 -480 640 -640 457 -494 373 -640 511 -640 480 -500 333 -640 480 -500 375 -640 427 -383 640 -500 333 -640 383 -640 360 -640 428 -640 427 -640 427 -640 426 -612 612 -640 428 -640 426 -500 335 -375 500 -640 419 -415 640 -263 350 -640 480 -640 426 -375 500 -640 427 -640 427 -640 480 -500 375 -640 480 -500 333 -640 480 -640 480 -426 640 -640 480 -640 480 -375 500 -640 359 -640 427 -640 428 -640 480 -500 497 -427 640 -640 512 -427 500 -441 331 -640 458 -640 360 -640 425 -602 640 -640 425 -640 480 -640 427 -640 425 -480 640 -337 500 -640 480 -640 480 -640 459 -640 426 -640 480 -640 480 -640 640 -600 600 -480 640 -333 500 -640 426 -640 450 -333 500 -640 426 -640 427 -640 480 -640 480 -640 406 -480 640 -640 427 -640 418 -500 333 -640 427 -425 640 -640 480 -500 334 -640 480 -640 480 -640 480 -640 480 -640 629 -500 375 -427 640 -640 426 -640 480 -640 481 -640 396 -640 429 -640 483 -427 640 -640 427 -640 427 -640 457 -640 427 -612 612 -640 480 -640 480 -640 480 -640 480 -640 480 -474 640 -446 500 -500 375 -640 480 -640 465 -640 478 -640 448 -640 427 -500 375 -490 326 -640 427 -426 640 -640 428 -640 400 -640 345 -640 425 -640 480 -640 427 -640 480 -640 468 -500 375 -429 640 -640 427 -640 425 -640 584 -424 640 -640 403 -640 425 -640 426 -640 427 -640 480 -640 559 -640 221 -640 480 -640 426 -640 480 -612 612 -427 640 -640 480 -500 298 -426 640 -480 360 -480 640 -640 427 -640 480 -640 426 -640 361 -640 480 -640 366 -640 480 -500 375 -500 375 -478 640 -640 427 -640 428 -480 640 -640 428 -640 427 -640 426 -640 480 -640 425 -640 480 -640 480 -500 375 -640 480 -640 639 -640 559 -500 331 -394 640 -426 640 -640 480 -640 480 -640 480 -640 427 -428 640 -640 427 -640 393 -640 426 -640 424 -469 279 -427 640 -640 335 -640 430 -428 640 -500 640 -426 640 -398 640 -427 640 -640 427 -640 427 -640 427 -457 640 -425 640 -640 434 -500 411 -500 375 -640 480 -640 476 -640 480 -640 575 -640 427 -640 480 -425 640 -640 395 -640 451 -640 513 -640 480 -640 427 -481 640 -480 640 -640 427 -640 480 -480 640 -640 480 -640 427 -640 424 -640 480 -315 482 -640 426 -640 426 -640 480 -640 480 -640 480 -640 426 -453 640 -383 640 -600 450 -640 463 -640 480 -640 474 -640 480 -640 478 -500 375 -640 427 -612 612 -612 612 -640 383 -640 640 -640 480 -500 342 -500 333 -640 428 -640 480 -427 640 -640 427 -640 448 -434 640 -480 640 -640 427 -640 480 -640 480 -500 333 -640 587 -640 424 -448 640 -640 428 -640 406 -640 458 -600 400 -640 426 -500 375 -640 426 -425 640 -640 391 -500 375 -432 288 -334 500 -640 480 -500 380 -640 480 -500 333 -640 480 -375 500 -640 427 -640 429 -427 640 -500 396 -640 480 -640 480 -500 334 -640 339 -480 640 -640 265 -640 480 -640 480 -640 480 -500 375 -640 480 -479 640 -640 598 -640 427 -640 383 -494 640 -640 427 -500 333 -640 360 -427 640 -640 480 -640 481 -333 500 -480 640 -500 400 -640 372 -480 640 -480 640 -640 512 -640 480 -632 640 -640 480 -453 640 -640 480 -640 480 -361 640 -612 612 -640 427 -500 339 -640 480 -500 376 -500 375 -640 480 -640 363 -640 566 -640 425 -640 480 -500 400 -640 433 -640 427 -480 640 -640 427 -640 427 -640 427 -640 427 -640 353 -471 640 -358 640 -640 427 -640 480 -480 640 -640 480 -640 480 -640 427 -640 480 -640 480 -640 426 -640 480 -640 424 -612 612 -480 640 -640 468 -640 467 -513 640 -640 483 -640 428 -612 612 -427 640 -612 612 -500 333 -500 332 -640 480 -640 427 -444 640 -640 428 -640 487 -481 640 -426 319 -640 424 -333 500 -640 445 -640 427 -640 427 -640 640 -640 478 -500 333 -640 427 -426 640 -640 427 -478 640 -640 480 -518 640 -640 360 -640 480 -640 427 -427 640 -334 500 -640 426 -640 399 -480 640 -375 500 -640 523 -375 500 -338 500 -640 640 -480 640 -640 480 -640 427 -458 640 -640 328 -480 640 -480 640 -640 513 -640 427 -640 405 -640 480 -640 480 -640 426 -640 361 -640 424 -640 443 -640 480 -640 442 -640 359 -640 480 -640 480 -640 480 -640 427 -640 480 -640 437 -427 640 -640 427 -640 480 -640 480 -640 480 -640 480 -640 426 -640 480 -640 425 -480 640 -640 480 -640 426 -640 425 -480 640 -640 426 -640 362 -480 640 -500 330 -640 433 -640 480 -480 640 -640 590 -640 254 -640 426 -640 427 -640 433 -640 429 -640 480 -460 345 -480 640 -640 427 -640 426 -640 480 -500 333 -427 640 -500 332 -480 640 -640 480 -640 640 -500 375 -640 425 -424 640 -500 333 -273 448 -640 631 -451 640 -417 640 -640 427 -640 428 -500 375 -640 459 -479 640 -640 428 -640 396 -500 375 -640 427 -640 427 -640 359 -640 424 -640 427 -640 427 -640 480 -640 228 -640 424 -640 427 -500 333 -500 375 -640 480 -613 640 -600 450 -640 480 -478 640 -640 360 -375 500 -322 471 -640 640 -500 375 -640 428 -632 640 -480 640 -500 498 -453 604 -640 480 -640 359 -500 375 -640 482 -640 478 -640 494 -640 427 -640 480 -427 640 -640 480 -525 640 -480 640 -640 480 -640 429 -640 425 -640 424 -640 480 -640 426 -500 333 -330 500 -640 425 -640 516 -640 427 -500 375 -605 640 -640 427 -640 427 -640 480 -612 612 -375 500 -640 480 -640 427 -640 563 -425 640 -640 427 -640 479 -640 480 -480 640 -640 478 -640 589 -640 427 -640 427 -482 640 -411 640 -640 238 -640 427 -640 427 -427 640 -640 427 -333 500 -640 427 -480 640 -500 375 -640 266 -640 480 -640 549 -421 500 -426 640 -375 500 -333 500 -640 340 -640 443 -640 631 -408 640 -640 552 -640 360 -427 640 -640 480 -480 640 -500 400 -640 254 -489 640 -500 333 -480 640 -640 383 -640 513 -640 428 -640 480 -640 426 -640 480 -640 483 -612 612 -640 389 -640 374 -640 480 -500 375 -640 360 -640 427 -640 480 -640 334 -480 640 -640 383 -418 640 -500 376 -640 623 -612 612 -640 426 -500 375 -423 640 -640 427 -640 480 -640 480 -640 480 -480 640 -640 426 -357 340 -427 640 -640 436 -640 426 -640 427 -469 640 -500 375 -640 453 -640 480 -500 375 -500 375 -375 500 -640 480 -640 512 -500 375 -359 640 -640 480 -320 265 -640 480 -640 480 -640 427 -480 640 -640 432 -640 480 -500 375 -640 430 -500 375 -640 444 -640 427 -640 425 -640 360 -511 640 -640 427 -480 640 -424 640 -512 640 -640 426 -640 427 -640 427 -640 640 -640 360 -640 371 -640 427 -640 480 -640 480 -426 640 -640 471 -640 426 -554 640 -640 385 -640 424 -478 640 -640 480 -500 375 -640 428 -640 478 -640 427 -500 333 -425 640 -640 480 -640 348 -640 473 -640 480 -477 640 -480 640 -640 271 -640 341 -640 456 -640 427 -427 640 -640 640 -640 429 -480 640 -640 427 -640 478 -368 500 -640 480 -640 426 -640 480 -640 478 -640 481 -500 375 -640 427 -640 480 -500 333 -640 399 -640 426 -640 478 -640 480 -375 500 -640 425 -640 454 -640 421 -640 480 -640 427 -640 640 -438 640 -435 640 -640 480 -640 320 -640 506 -640 480 -640 480 -640 640 -640 426 -383 640 -438 640 -612 612 -513 640 -640 424 -640 425 -640 359 -480 640 -640 427 -640 480 -640 480 -640 480 -640 480 -640 480 -480 640 -640 427 -640 427 -500 334 -640 480 -480 640 -640 451 -640 480 -640 480 -465 640 -640 320 -640 429 -640 456 -640 425 -640 426 -640 446 -500 375 -458 380 -640 355 -640 480 -640 480 -640 426 -276 640 -480 640 -640 480 -640 508 -640 386 -640 482 -413 500 -640 453 -640 640 -640 479 -640 480 -640 427 -640 300 -428 640 -640 428 -480 640 -333 500 -640 427 -640 409 -640 428 -480 640 -480 640 -640 422 -412 640 -640 441 -640 425 -427 640 -640 480 -480 640 -640 426 -480 640 -640 480 -500 341 -640 427 -640 360 -640 360 -427 640 -640 428 -640 428 -640 480 -640 425 -640 480 -640 480 -640 427 -400 300 -640 467 -500 333 -504 378 -640 457 -480 640 -640 373 -500 375 -426 640 -640 480 -640 428 -500 333 -640 427 -530 640 -640 480 -640 480 -640 427 -640 480 -640 427 -640 427 -640 480 -480 640 -383 640 -456 640 -480 640 -640 425 -640 426 -640 424 -640 480 -640 425 -640 480 -640 427 -480 640 -640 480 -640 360 -640 480 -480 640 -640 640 -300 450 -640 427 -640 425 -640 400 -640 427 -445 640 -640 480 -640 427 -640 480 -428 640 -640 296 -500 312 -640 400 -640 420 -640 381 -640 480 -375 500 -640 426 -640 426 -640 457 -500 334 -640 480 -640 480 -428 640 -640 466 -480 640 -480 640 -480 640 -640 486 -612 612 -640 480 -480 640 -640 427 -640 427 -640 425 -640 467 -640 426 -480 640 -480 640 -640 480 -640 480 -640 281 -612 612 -333 500 -500 333 -640 427 -640 480 -640 512 -640 480 -480 640 -640 480 -640 427 -640 427 -640 427 -427 640 -614 640 -640 480 -480 640 -640 427 -480 640 -640 480 -254 336 -640 360 -640 455 -640 424 -640 480 -640 480 -640 426 -375 500 -480 640 -427 640 -500 375 -640 424 -640 473 -640 457 -640 359 -500 334 -391 640 -640 428 -480 640 -640 426 -640 427 -640 347 -640 427 -640 436 -640 480 -640 481 -472 640 -500 375 -640 427 -640 424 -336 640 -640 480 -640 353 -640 411 -640 454 -600 450 -640 361 -640 480 -640 640 -640 426 -480 640 -640 480 -500 417 -640 427 -428 640 -640 480 -640 427 -640 427 -480 640 -375 500 -480 640 -640 360 -640 633 -640 427 -640 480 -640 283 -640 434 -360 640 -640 458 -640 480 -640 480 -480 640 -640 480 -640 480 -640 586 -640 640 -640 425 -375 500 -640 427 -640 436 -640 425 -640 360 -640 406 -640 427 -640 492 -640 427 -640 426 -640 424 -500 333 -640 426 -480 640 -640 427 -640 426 -640 431 -427 640 -375 500 -640 360 -640 427 -480 640 -425 640 -640 444 -640 427 -427 640 -591 640 -640 480 -640 427 -640 416 -640 480 -640 427 -640 426 -640 427 -640 440 -640 477 -640 480 -640 359 -640 311 -640 427 -640 326 -640 427 -640 480 -640 310 -640 480 -362 640 -640 480 -470 640 -480 640 -640 449 -640 481 -484 640 -332 500 -569 640 -427 640 -375 500 -612 612 -640 424 -640 467 -485 500 -612 612 -640 480 -500 332 -427 640 -640 425 -640 426 -480 640 -640 480 -640 480 -478 640 -640 480 -640 427 -640 424 -640 428 -640 426 -640 426 -640 427 -640 428 -324 640 -640 449 -500 375 -500 375 -500 281 -506 640 -427 640 -640 480 -640 480 -640 480 -427 640 -612 612 -640 489 -640 480 -480 640 -640 427 -640 424 -500 375 -640 480 -640 480 -612 612 -640 480 -640 480 -426 640 -640 361 -640 427 -640 424 -427 640 -640 428 -640 438 -640 426 -640 480 -640 427 -640 378 -640 427 -640 573 -640 427 -640 480 -640 480 -640 429 -500 333 -640 480 -640 427 -640 428 -640 426 -640 480 -425 640 -640 428 -375 500 -640 425 -640 426 -640 480 -640 480 -640 480 -375 500 -640 480 -640 427 -640 480 -500 375 -500 359 -428 640 -640 362 -640 425 -640 424 -427 640 -640 480 -640 480 -419 500 -370 640 -333 500 -640 427 -500 375 -612 612 -640 432 -640 415 -500 375 -480 640 -612 612 -640 480 -500 400 -640 427 -500 331 -500 375 -500 375 -640 480 -640 558 -640 480 -480 640 -640 480 -478 640 -480 640 -640 480 -640 427 -480 640 -640 480 -480 640 -333 426 -640 431 -500 375 -640 478 -480 640 -640 640 -640 480 -480 640 -640 418 -640 427 -640 480 -640 424 -640 444 -640 480 -526 640 -640 480 -640 480 -640 429 -640 429 -500 375 -424 640 -640 396 -640 318 -640 428 -428 640 -640 480 -433 640 -640 480 -640 427 -500 375 -640 386 -640 427 -640 427 -640 480 -640 480 -640 442 -500 332 -640 428 -360 640 -640 427 -612 612 -480 640 -640 424 -640 480 -425 640 -640 425 -640 480 -640 608 -640 428 -333 500 -427 640 -640 432 -640 480 -640 369 -640 602 -427 640 -640 427 -640 433 -640 426 -478 640 -500 333 -640 360 -640 427 -640 480 -640 351 -640 488 -640 480 -640 424 -640 427 -640 506 -453 604 -640 427 -358 500 -640 480 -500 333 -640 363 -640 640 -640 425 -480 640 -640 480 -640 480 -640 480 -640 428 -640 427 -640 433 -640 466 -640 480 -512 384 -640 411 -640 480 -483 500 -640 480 -640 427 -640 480 -640 480 -640 480 -640 483 -480 640 -640 457 -426 640 -640 480 -500 311 -640 480 -640 426 -500 333 -640 400 -480 640 -640 428 -640 427 -640 426 -640 426 -640 428 -500 333 -640 425 -640 480 -640 425 -480 640 -640 424 -500 375 -612 612 -640 480 -640 480 -427 640 -640 555 -482 640 -640 427 -640 480 -640 478 -640 427 -640 428 -640 519 -640 428 -500 333 -640 360 -640 483 -640 242 -640 480 -500 281 -500 375 -640 429 -500 375 -427 640 -640 424 -640 480 -640 427 -640 480 -640 427 -500 375 -480 640 -640 426 -640 425 -427 640 -640 480 -640 426 -500 409 -640 427 -640 425 -480 640 -500 436 -480 640 -478 640 -500 400 -640 480 -640 427 -640 428 -640 480 -640 425 -640 426 -500 375 -640 480 -640 485 -640 469 -640 426 -612 612 -640 483 -375 500 -640 426 -640 427 -500 375 -640 532 -640 429 -500 375 -640 640 -640 436 -640 427 -640 480 -375 500 -640 427 -640 426 -640 425 -426 640 -427 640 -640 428 -640 480 -640 427 -612 612 -640 479 -480 640 -640 480 -640 427 -480 640 -375 500 -375 500 -640 427 -424 640 -640 427 -640 570 -469 341 -640 480 -640 427 -480 640 -640 427 -640 427 -426 640 -640 427 -640 485 -640 453 -640 427 -427 640 -640 360 -640 480 -427 640 -640 480 -640 480 -640 429 -640 478 -640 480 -480 640 -500 337 -640 480 -640 493 -640 427 -640 424 -640 425 -640 425 -640 427 -480 640 -640 549 -639 640 -500 375 -640 480 -640 399 -640 424 -640 401 -640 429 -640 428 -640 360 -640 427 -521 640 -427 640 -640 342 -425 640 -640 427 -640 480 -640 480 -640 480 -500 375 -426 640 -500 358 -640 514 -640 480 -640 427 -640 640 -640 444 -480 640 -500 335 -640 408 -640 634 -640 427 -640 427 -640 480 -640 427 -640 426 -640 477 -375 500 -640 427 -463 640 -640 480 -418 640 -640 480 -640 480 -640 480 -640 480 -640 425 -427 640 -480 640 -640 433 -640 428 -498 640 -640 427 -640 480 -427 640 -352 500 -640 480 -424 640 -612 612 -640 433 -640 480 -640 480 -640 558 -640 425 -640 428 -640 360 -426 640 -500 286 -640 480 -640 359 -511 640 -640 516 -267 400 -475 500 -494 500 -640 264 -640 427 -640 428 -480 640 -480 640 -640 360 -480 640 -640 423 -640 480 -640 468 -500 325 -500 411 -500 375 -480 640 -640 427 -640 427 -427 640 -640 608 -640 359 -480 640 -640 480 -640 425 -640 426 -640 427 -640 423 -640 428 -640 480 -640 480 -375 500 -640 427 -640 425 -640 504 -640 427 -640 480 -640 354 -445 400 -640 409 -640 427 -400 300 -640 480 -640 427 -463 640 -640 461 -640 479 -640 425 -640 480 -640 429 -500 333 -640 428 -375 500 -612 612 -640 427 -436 640 -480 640 -500 375 -640 480 -640 526 -640 480 -448 500 -480 640 -640 422 -640 480 -640 640 -640 480 -426 640 -500 375 -480 640 -640 480 -640 424 -640 427 -640 457 -640 429 -640 427 -450 600 -425 640 -640 640 -640 229 -640 579 -640 425 -640 426 -640 480 -466 640 -640 427 -640 480 -640 424 -480 640 -640 427 -427 640 -480 319 -640 429 -480 640 -480 640 -333 500 -500 375 -534 640 -640 480 -640 427 -640 427 -640 425 -424 640 -480 640 -640 425 -640 480 -640 428 -480 640 -480 640 -640 426 -360 640 -500 375 -640 428 -640 426 -500 375 -640 480 -375 500 -375 500 -640 372 -640 480 -425 640 -640 480 -612 612 -640 640 -640 480 -500 375 -640 427 -640 506 -640 480 -640 328 -640 480 -640 401 -640 483 -640 428 -433 500 -640 371 -640 427 -640 480 -640 457 -425 640 -640 480 -481 640 -640 480 -640 480 -640 480 -640 424 -427 640 -640 618 -640 640 -500 239 -612 612 -640 421 -640 430 -640 428 -640 567 -500 375 -640 480 -612 612 -640 425 -640 426 -427 640 -640 480 -640 427 -640 348 -640 480 -512 640 -480 640 -480 640 -480 640 -640 427 -640 480 -640 480 -640 426 -427 640 -640 425 -640 512 -640 424 -640 480 -640 480 -640 480 -640 444 -425 640 -640 411 -427 640 -375 500 -640 404 -640 480 -640 480 -574 640 -500 375 -640 427 -640 480 -612 612 -500 375 -640 480 -640 457 -640 480 -640 428 -500 375 -640 480 -375 500 -640 427 -425 640 -640 368 -640 460 -640 480 -640 425 -486 640 -640 458 -426 640 -640 427 -600 400 -640 479 -500 375 -640 427 -640 480 -640 427 -640 480 -640 427 -500 375 -640 429 -612 612 -500 333 -640 480 -640 480 -400 500 -640 480 -480 640 -500 375 -180 240 -434 640 -427 640 -640 480 -640 429 -640 427 -256 640 -640 480 -640 428 -500 375 -640 395 -640 469 -500 375 -640 640 -640 428 -427 640 -640 480 -427 640 -640 427 -640 426 -426 640 -640 426 -640 480 -640 424 -640 443 -640 425 -375 500 -597 640 -640 427 -640 427 -480 640 -640 480 -480 640 -640 427 -640 480 -640 427 -640 325 -640 483 -640 480 -640 480 -640 440 -640 480 -433 500 -640 427 -640 480 -478 640 -640 426 -640 480 -640 480 -640 427 -640 424 -640 386 -640 427 -640 360 -480 640 -640 438 -500 332 -640 428 -640 480 -640 427 -640 394 -640 480 -640 237 -640 426 -612 612 -480 640 -640 427 -640 480 -410 640 -640 427 -640 480 -480 640 -500 333 -640 512 -640 480 -640 427 -480 640 -640 480 -427 640 -640 480 -480 640 -640 531 -334 500 -640 379 -480 640 -427 640 -480 640 -480 640 -640 480 -427 640 -640 384 -612 612 -640 426 -640 448 -500 337 -640 480 -640 480 -500 375 -640 480 -375 500 -640 384 -640 480 -480 640 -640 480 -640 480 -500 281 -640 519 -376 500 -640 480 -640 427 -480 640 -425 640 -640 480 -640 425 -640 426 -612 612 -640 480 -461 640 -640 425 -640 434 -640 424 -640 427 -480 640 -640 640 -640 494 -640 427 -447 640 -640 479 -640 480 -640 428 -640 426 -640 640 -480 360 -480 640 -640 360 -640 480 -426 640 -640 435 -640 480 -640 480 -640 383 -640 425 -640 480 -416 640 -640 424 -428 640 -640 481 -640 418 -500 364 -424 500 -640 360 -480 640 -640 426 -640 427 -640 422 -453 640 -428 640 -612 612 -640 480 -426 640 -600 600 -640 428 -640 480 -640 360 -640 425 -640 480 -428 640 -480 640 -360 640 -375 500 -427 640 -640 480 -640 480 -640 514 -640 480 -425 640 -640 376 -640 431 -640 427 -375 500 -640 480 -375 500 -640 480 -480 640 -427 640 -640 480 -332 500 -457 640 -640 544 -640 433 -640 513 -480 640 -640 480 -425 640 -640 480 -512 640 -500 332 -640 480 -640 425 -640 480 -640 426 -427 640 -596 446 -640 359 -640 427 -640 480 -640 480 -640 480 -480 640 -640 457 -640 480 -428 640 -640 640 -500 335 -333 500 -612 612 -640 427 -640 426 -640 480 -640 427 -500 333 -640 480 -480 640 -640 428 -480 640 -640 480 -426 640 -640 458 -375 500 -480 640 -640 427 -427 640 -425 640 -480 640 -500 376 -640 427 -500 370 -448 500 -458 640 -640 480 -640 426 -640 637 -640 480 -640 480 -512 640 -500 375 -640 427 -640 434 -500 332 -640 403 -640 480 -640 480 -640 427 -640 427 -640 426 -640 480 -427 640 -513 640 -640 424 -640 480 -640 426 -640 428 -640 480 -500 333 -640 480 -640 360 -640 480 -640 427 -640 343 -640 480 -500 377 -500 375 -425 640 -640 413 -454 640 -640 426 -375 500 -640 480 -480 640 -640 523 -640 428 -500 333 -640 427 -640 481 -640 420 -500 375 -480 640 -422 640 -640 427 -640 432 -640 265 -466 640 -608 640 -427 640 -480 640 -640 426 -640 427 -640 360 -640 427 -480 640 -640 480 -640 426 -640 427 -640 420 -640 427 -612 612 -375 500 -423 640 -414 500 -480 640 -480 640 -640 427 -640 427 -640 425 -640 429 -612 612 -457 640 -640 640 -600 640 -640 480 -426 640 -640 427 -500 332 -428 640 -640 463 -640 426 -640 480 -480 640 -640 480 -640 461 -640 441 -496 640 -640 508 -640 428 -427 640 -640 480 -640 480 -612 612 -640 480 -448 640 -500 333 -426 640 -640 480 -426 640 -480 640 -640 480 -500 335 -231 500 -432 640 -640 427 -480 640 -640 427 -480 640 -640 441 -640 480 -375 500 -640 427 -640 426 -640 480 -640 423 -427 640 -640 480 -640 425 -640 429 -559 640 -640 519 -478 640 -640 480 -480 640 -640 512 -640 480 -640 427 -640 404 -427 640 -640 480 -640 480 -640 427 -640 480 -500 375 -640 484 -480 640 -640 614 -480 640 -640 427 -425 640 -640 426 -640 426 -640 458 -640 480 -640 458 -640 426 -480 640 -640 480 -500 338 -640 480 -640 427 -640 428 -612 612 -480 640 -640 426 -375 500 -480 640 -640 427 -640 425 -516 640 -500 420 -640 424 -640 427 -640 633 -612 612 -479 640 -640 427 -640 424 -640 427 -480 640 -500 375 -480 640 -612 612 -640 482 -640 480 -543 640 -480 640 -640 427 -640 480 -640 480 -640 425 -640 501 -640 480 -640 454 -640 427 -640 425 -473 640 -640 425 -480 640 -612 612 -428 640 -640 506 -640 480 -640 579 -480 640 -640 425 -640 427 -640 458 -640 423 -640 478 -640 480 -640 426 -612 612 -640 517 -303 500 -427 640 -640 400 -426 640 -640 480 -500 375 -640 434 -640 428 -640 480 -640 427 -500 333 -640 480 -640 427 -480 640 -640 480 -478 640 -640 424 -612 612 -500 333 -640 480 -640 480 -640 483 -514 640 -426 640 -640 480 -640 480 -480 640 -640 360 -500 375 -640 480 -426 640 -640 428 -640 461 -640 483 -640 471 -640 428 -427 640 -640 480 -426 640 -480 640 -375 500 -401 640 -640 514 -500 333 -640 424 -640 480 -640 502 -640 480 -640 372 -640 477 -640 426 -640 426 -480 640 -640 427 -500 375 -480 640 -640 478 -640 480 -427 640 -640 427 -612 612 -640 426 -500 333 -480 640 -500 333 -425 640 -640 427 -480 640 -640 480 -437 640 -640 360 -640 416 -640 427 -500 308 -640 427 -640 480 -375 500 -640 480 -640 360 -426 640 -427 640 -640 426 -640 383 -425 640 -640 480 -640 427 -640 421 -640 480 -640 428 -640 478 -640 503 -640 458 -427 640 -500 375 -640 480 -640 480 -640 427 -640 495 -480 640 -467 607 -640 425 -428 640 -640 448 -480 640 -640 361 -640 480 -640 426 -500 375 -640 389 -640 480 -480 640 -640 451 -500 375 -480 640 -640 428 -640 480 -500 375 -640 478 -426 640 -640 480 -640 480 -640 526 -500 364 -640 427 -383 500 -640 480 -500 355 -500 375 -640 481 -500 400 -640 480 -612 612 -640 360 -640 480 -640 426 -479 640 -640 480 -612 612 -375 500 -640 486 -500 375 -640 498 -640 427 -500 375 -640 427 -480 640 -640 480 -640 428 -612 612 -640 427 -500 375 -640 475 -640 425 -640 523 -480 640 -427 640 -640 480 -640 480 -640 480 -640 427 -480 640 -640 506 -640 427 -640 480 -640 528 -640 480 -640 480 -426 640 -640 425 -640 426 -640 427 -640 278 -500 335 -500 281 -427 640 -375 500 -427 640 -640 438 -640 427 -480 640 -640 360 -640 480 -640 480 -640 389 -375 500 -640 427 -640 427 -423 640 -640 480 -612 612 -427 640 -388 640 -640 425 -480 640 -640 480 -425 640 -500 375 -427 640 -425 640 -640 480 -640 448 -640 480 -375 500 -640 480 -640 640 -427 640 -375 500 -478 640 -424 640 -480 640 -426 640 -478 640 -640 480 -334 500 -640 426 -640 426 -640 425 -480 640 -640 360 -640 480 -640 428 -640 480 -640 424 -640 424 -640 427 -640 439 -640 426 -500 375 -640 425 -640 480 -480 640 -640 426 -640 427 -500 333 -640 480 -640 300 -640 404 -510 340 -640 427 -640 478 -480 640 -640 426 -640 483 -640 424 -640 319 -640 321 -500 333 -640 408 -640 427 -640 434 -640 457 -640 427 -640 426 -375 500 -500 333 -640 427 -640 478 -640 480 -480 640 -640 426 -640 427 -640 413 -640 480 -640 433 -428 640 -640 476 -387 518 -640 364 -640 480 -640 474 -640 480 -500 293 -480 640 -640 426 -500 500 -640 457 -346 500 -640 480 -480 640 -480 640 -500 334 -480 640 -640 478 -640 480 -640 427 -640 480 -640 470 -640 441 -375 500 -418 500 -640 427 -480 640 -425 640 -432 432 -640 425 -500 361 -640 388 -375 500 -640 425 -640 426 -457 640 -499 500 -640 480 -427 640 -640 361 -640 428 -484 640 -640 425 -640 480 -640 476 -640 480 -640 480 -640 427 -375 500 -583 640 -640 480 -480 640 -375 500 -612 612 -480 640 -500 327 -480 640 -640 427 -612 612 -426 640 -514 640 -480 640 -640 427 -640 400 -640 427 -640 305 -640 480 -640 480 -640 427 -466 640 -640 480 -640 480 -640 427 -369 500 -640 480 -640 425 -640 481 -427 640 -640 479 -440 640 -478 640 -640 329 -428 640 -640 464 -640 427 -640 457 -640 508 -640 480 -640 391 -500 375 -640 478 -640 431 -375 500 -480 640 -640 594 -428 640 -640 446 -500 332 -480 640 -411 500 -640 427 -640 485 -640 480 -640 401 -640 425 -640 359 -640 640 -640 480 -640 427 -424 640 -640 480 -640 426 -640 480 -640 480 -500 375 -640 480 -640 428 -375 500 -425 640 -640 480 -640 485 -640 480 -425 640 -480 640 -640 428 -640 480 -640 434 -640 427 -640 480 -640 508 -640 480 -640 425 -640 427 -342 500 -640 426 -612 612 -428 640 -640 427 -500 375 -612 612 -640 427 -426 640 -375 500 -480 640 -640 463 -640 480 -281 500 -375 500 -500 375 -640 427 -375 500 -640 480 -640 427 -640 359 -640 425 -640 480 -480 640 -640 406 -640 426 -640 620 -640 480 -500 375 -640 427 -500 375 -480 640 -640 480 -640 362 -491 640 -480 640 -640 383 -640 480 -500 375 -640 426 -640 480 -640 480 -640 480 -640 426 -640 428 -640 480 -426 640 -427 640 -640 423 -640 427 -500 375 -640 476 -500 375 -640 480 -427 640 -640 480 -640 480 -612 612 -640 427 -640 426 -640 512 -333 500 -640 458 -640 478 -427 640 -640 427 -640 480 -640 480 -640 427 -640 382 -640 480 -500 313 -375 500 -640 480 -640 457 -640 428 -640 481 -427 640 -640 428 -640 363 -427 640 -640 425 -640 426 -425 640 -640 427 -640 425 -640 427 -640 480 -640 481 -423 640 -640 563 -640 427 -640 480 -612 612 -640 426 -640 480 -296 446 -500 333 -640 480 -640 425 -640 480 -640 480 -500 333 -618 640 -640 480 -640 427 -500 375 -500 333 -480 640 -423 640 -428 640 -426 640 -500 334 -640 480 -640 480 -640 424 -640 469 -640 439 -427 640 -640 427 -426 640 -640 480 -480 640 -640 480 -500 333 -640 426 -640 480 -500 281 -640 427 -640 481 -640 480 -640 427 -640 640 -640 427 -640 472 -640 480 -480 640 -640 480 -640 544 -640 489 -480 640 -500 429 -640 428 -500 333 -480 640 -640 326 -480 640 -500 375 -640 480 -640 413 -640 480 -640 480 -640 426 -640 426 -640 480 -640 480 -612 612 -640 426 -640 478 -640 480 -640 447 -426 640 -640 427 -480 342 -640 426 -500 335 -332 500 -435 640 -640 501 -640 427 -366 640 -640 328 -500 376 -500 333 -640 517 -640 360 -640 480 -640 427 -640 480 -640 426 -640 398 -640 426 -640 425 -640 640 -427 640 -640 427 -437 640 -640 431 -640 427 -640 490 -640 427 -640 428 -640 480 -640 480 -640 433 -500 375 -640 480 -640 480 -640 480 -640 427 -640 347 -640 480 -640 480 -640 379 -353 640 -640 360 -451 640 -640 400 -640 428 -375 500 -640 457 -612 612 -640 480 -427 640 -480 640 -640 480 -640 480 -640 428 -640 425 -480 640 -426 640 -640 427 -500 334 -640 281 -640 480 -400 500 -428 640 -640 427 -482 640 -640 428 -640 427 -640 480 -640 480 -640 434 -500 334 -500 333 -640 427 -427 640 -640 426 -640 385 -640 480 -480 640 -480 640 -640 604 -640 426 -640 454 -640 480 -640 480 -640 569 -640 427 -640 425 -640 480 -640 439 -640 480 -640 480 -480 640 -640 480 -640 480 -640 480 -500 364 -640 426 -640 480 -425 640 -640 640 -480 640 -480 640 -640 480 -474 640 -640 427 -640 396 -498 500 -640 480 -500 375 -440 500 -427 640 -640 480 -500 349 -428 640 -640 427 -640 427 -640 427 -640 461 -640 486 -640 480 -480 640 -640 473 -640 427 -640 425 -640 360 -640 428 -640 426 -640 478 -640 326 -640 399 -640 480 -640 400 -640 427 -640 312 -640 640 -633 640 -580 580 -640 500 -640 427 -640 480 -640 427 -640 480 -500 333 -640 498 -468 640 -375 500 -430 640 -640 480 -480 640 -640 425 -480 640 -383 640 -500 333 -640 426 -468 640 -640 480 -640 480 -500 375 -640 480 -413 640 -640 383 -640 480 -500 375 -500 333 -426 640 -640 486 -500 375 -427 640 -640 480 -640 324 -640 480 -375 500 -480 640 -375 500 -612 612 -500 375 -612 612 -640 541 -640 481 -427 640 -640 480 -640 480 -480 640 -640 480 -612 612 -427 640 -640 480 -640 427 -640 426 -529 640 -500 375 -640 416 -640 480 -567 640 -640 554 -640 478 -640 427 -359 640 -640 383 -640 512 -640 427 -500 332 -508 640 -640 424 -640 278 -375 500 -480 640 -640 481 -640 480 -459 640 -450 600 -640 480 -548 640 -640 640 -640 480 -425 640 -640 425 -640 427 -640 480 -640 426 -640 480 -640 399 -640 480 -640 427 -640 456 -640 480 -640 480 -640 480 -458 640 -640 428 -640 480 -500 375 -640 478 -640 480 -640 418 -640 480 -640 427 -640 589 -640 400 -480 640 -375 500 -500 332 -640 480 -640 423 -640 427 -640 480 -640 426 -640 480 -640 480 -428 640 -640 480 -640 480 -640 427 -640 426 -640 480 -500 375 -480 640 -640 480 -640 515 -426 640 -640 427 -612 612 -640 480 -500 357 -480 640 -640 480 -640 359 -427 640 -426 640 -640 427 -640 427 -640 480 -640 427 -500 375 -640 422 -480 640 -640 427 -480 640 -640 480 -350 500 -640 425 -640 480 -480 640 -640 480 -640 427 -640 427 -640 461 -640 426 -640 502 -612 612 -640 480 -640 480 -640 424 -500 375 -640 433 -640 480 -640 480 -640 480 -640 425 -480 640 -427 640 -640 423 -640 480 -640 427 -640 480 -640 427 -640 480 -640 324 -640 478 -480 640 -640 480 -640 480 -640 640 -640 427 -640 480 -640 480 -320 500 -640 424 -500 375 -480 640 -480 640 -640 480 -480 640 -640 480 -640 359 -480 640 -640 427 -427 640 -180 240 -500 333 -640 516 -500 348 -253 130 -375 500 -640 279 -640 427 -640 427 -640 480 -500 375 -427 640 -640 424 -640 426 -500 375 -375 500 -640 427 -640 423 -640 427 -427 640 -640 478 -640 480 -640 427 -500 334 -640 480 -640 480 -500 333 -450 338 -640 584 -627 640 -640 480 -480 640 -640 480 -640 481 -640 480 -426 640 -640 425 -640 553 -640 480 -612 612 -500 334 -500 375 -640 480 -640 434 -640 480 -640 428 -640 480 -444 640 -640 480 -640 480 -612 612 -500 375 -640 427 -426 640 -640 427 -387 640 -423 640 -640 360 -640 480 -640 480 -500 375 -640 480 -640 427 -640 480 -640 528 -640 479 -640 480 -563 640 -640 478 -640 480 -500 286 -500 415 -640 533 -640 544 -640 427 -480 640 -640 427 -640 426 -640 426 -500 500 -640 480 -640 480 -480 640 -640 426 -426 640 -500 397 -551 640 -640 427 -640 502 -640 401 -500 333 -640 427 -640 480 -354 640 -640 449 -500 333 -640 418 -408 640 -431 640 -640 480 -640 480 -612 612 -448 336 -640 480 -640 444 -400 600 -640 427 -640 480 -427 640 -612 612 -640 425 -640 427 -640 359 -640 512 -375 500 -426 640 -640 425 -640 426 -640 426 -640 417 -640 427 -640 480 -612 612 -640 489 -640 425 -500 336 -427 640 -640 480 -430 318 -640 480 -640 426 -429 640 -640 426 -427 640 -640 360 -640 480 -640 427 -640 427 -640 480 -640 480 -640 368 -640 427 -640 426 -640 480 -640 411 -640 482 -640 480 -640 477 -480 640 -640 480 -640 480 -640 480 -500 500 -443 640 -640 426 -640 425 -640 480 -640 480 -427 640 -640 480 -403 640 -533 640 -640 425 -640 632 -612 612 -500 332 -335 500 -640 480 -550 550 -640 480 -640 480 -500 375 -640 480 -375 500 -427 640 -640 424 -640 427 -640 425 -640 427 -640 458 -426 640 -640 478 -640 426 -640 359 -500 401 -640 360 -640 438 -640 425 -480 640 -480 640 -640 480 -640 429 -480 640 -480 640 -500 333 -480 640 -640 459 -640 427 -640 426 -500 333 -413 640 -530 530 -640 428 -640 480 -480 640 -640 480 -640 480 -640 449 -640 426 -586 640 -640 480 -359 640 -428 640 -500 335 -640 426 -640 640 -640 426 -640 426 -640 426 -640 480 -640 634 -640 427 -640 480 -640 480 -500 375 -500 333 -640 480 -426 640 -640 441 -640 501 -500 474 -640 480 -640 427 -640 427 -478 640 -424 640 -500 375 -640 426 -640 427 -640 480 -480 640 -462 640 -640 480 -500 333 -240 320 -590 397 -640 480 -640 400 -640 428 -640 480 -500 375 -640 427 -640 480 -640 396 -640 480 -480 640 -500 375 -640 480 -640 427 -333 500 -640 458 -453 640 -640 427 -640 427 -640 427 -480 640 -640 427 -500 375 -640 367 -427 640 -640 512 -640 426 -640 478 -640 480 -640 352 -410 640 -500 375 -640 425 -500 375 -424 640 -640 425 -480 640 -462 557 -640 480 -640 480 -640 427 -500 375 -640 470 -500 375 -375 500 -500 375 -427 640 -480 640 -480 640 -480 640 -640 360 -640 420 -640 427 -430 640 -383 640 -640 431 -332 500 -640 485 -500 333 -500 331 -375 500 -640 480 -640 426 -640 480 -640 640 -640 427 -427 640 -640 480 -640 480 -640 428 -480 640 -640 480 -640 427 -640 427 -480 640 -640 427 -640 480 -480 640 -640 480 -640 480 -478 640 -640 427 -640 480 -640 427 -427 640 -640 480 -480 640 -500 332 -640 480 -426 640 -640 480 -640 441 -640 427 -640 480 -478 640 -640 480 -640 480 -640 418 -640 427 -500 332 -480 640 -640 248 -640 480 -425 640 -480 640 -640 383 -320 427 -640 480 -480 640 -640 639 -640 480 -427 640 -481 640 -640 533 -640 426 -640 427 -612 612 -500 333 -640 480 -640 465 -536 640 -500 375 -640 427 -640 426 -427 640 -640 426 -640 427 -375 500 -640 213 -640 512 -640 480 -427 640 -640 425 -640 480 -640 480 -406 640 -640 426 -640 640 -640 480 -640 480 -640 480 -393 640 -640 427 -640 427 -500 375 -640 428 -640 428 -640 359 -640 487 -640 478 -640 640 -500 332 -640 427 -640 480 -640 261 -375 500 -640 426 -640 428 -640 405 -500 375 -331 500 -480 640 -640 480 -640 427 -640 480 -640 480 -640 427 -640 402 -500 375 -640 427 -478 640 -640 640 -375 500 -640 427 -640 424 -640 480 -640 426 -640 425 -480 640 -640 426 -640 424 -640 427 -640 427 -375 500 -640 427 -640 427 -640 480 -488 640 -640 430 -480 640 -640 480 -640 480 -640 427 -640 480 -640 294 -640 480 -640 480 -640 427 -640 427 -640 427 -640 427 -500 375 -500 375 -640 480 -640 480 -640 427 -640 480 -640 480 -640 508 -500 499 -640 431 -640 424 -375 500 -338 480 -640 427 -640 427 -640 479 -612 612 -440 640 -640 425 -500 291 -426 640 -640 480 -480 640 -426 640 -640 426 -640 427 -640 424 -281 446 -500 319 -640 427 -640 381 -640 427 -640 360 -520 347 -640 427 -640 425 -640 428 -640 427 -640 318 -332 500 -640 480 -640 428 -640 360 -640 479 -401 500 -640 480 -640 427 -640 480 -640 418 -640 453 -480 640 -360 640 -500 375 -640 426 -640 480 -640 480 -640 457 -480 640 -640 427 -283 500 -640 480 -640 514 -640 480 -640 427 -426 640 -500 375 -640 427 -500 375 -500 331 -497 640 -637 640 -640 428 -640 480 -640 479 -640 478 -640 480 -640 480 -500 333 -640 426 -640 427 -640 353 -640 360 -640 427 -640 427 -640 427 -640 478 -640 480 -640 424 -640 480 -480 640 -640 502 -640 480 -478 640 -478 640 -640 426 -424 640 -640 428 -425 352 -640 480 -640 418 -640 418 -640 480 -425 640 -640 428 -612 612 -640 380 -640 427 -640 480 -640 480 -375 500 -640 480 -640 425 -640 519 -500 375 -500 333 -640 480 -640 480 -640 480 -640 598 -500 332 -640 427 -640 484 -640 470 -640 383 -500 375 -640 428 -640 479 -640 480 -374 500 -612 612 -640 428 -425 640 -640 391 -640 480 -640 503 -640 480 -427 640 -640 445 -640 480 -640 362 -640 424 -500 335 -480 640 -426 640 -640 473 -517 640 -427 640 -640 401 -640 480 -640 480 -640 386 -500 500 -612 612 -640 427 -640 549 -640 640 -640 480 -640 480 -640 465 -640 361 -500 375 -500 334 -640 428 -640 480 -480 640 -640 426 -460 640 -418 640 -640 427 -612 612 -640 491 -427 640 -640 480 -640 427 -640 480 -500 375 -640 480 -640 480 -640 480 -640 427 -427 640 -612 612 -640 538 -480 640 -640 424 -640 359 -426 640 -640 360 -450 287 -640 531 -500 375 -640 425 -640 480 -640 427 -612 612 -640 480 -375 500 -500 332 -640 480 -640 424 -360 640 -500 300 -640 640 -480 640 -640 360 -640 480 -640 480 -539 640 -427 640 -640 480 -640 393 -427 640 -640 314 -640 427 -500 375 -640 480 -640 480 -640 480 -640 480 -640 480 -640 427 -500 400 -640 480 -640 454 -640 425 -500 377 -500 375 -640 403 -640 469 -640 344 -640 480 -640 415 -320 480 -500 375 -426 640 -640 480 -640 440 -640 428 -640 480 -451 640 -425 640 -640 480 -640 480 -480 640 -640 360 -480 640 -640 480 -480 640 -640 427 -640 480 -640 640 -640 427 -428 640 -640 588 -640 427 -640 355 -500 277 -640 427 -612 612 -640 480 -500 375 -640 455 -640 428 -640 415 -500 375 -640 426 -640 427 -500 357 -426 640 -400 500 -640 480 -500 375 -424 640 -640 480 -640 480 -640 360 -640 480 -640 427 -239 640 -640 480 -640 480 -640 428 -640 426 -640 480 -500 333 -640 427 -640 436 -478 640 -640 478 -640 427 -640 466 -640 408 -640 428 -640 310 -583 640 -640 480 -640 447 -640 480 -640 429 -640 427 -640 426 -640 427 -500 375 -500 375 -640 478 -480 640 -640 640 -500 332 -458 640 -640 427 -500 324 -640 427 -640 427 -640 426 -640 428 -640 427 -640 640 -640 480 -640 476 -640 480 -640 435 -640 419 -640 428 -357 500 -640 360 -640 427 -640 427 -500 333 -640 480 -640 480 -640 480 -426 640 -640 480 -640 380 -640 478 -640 390 -640 480 -612 612 -480 640 -640 426 -640 533 -640 426 -640 424 -429 640 -512 640 -640 480 -480 640 -640 427 -480 640 -427 640 -640 426 -640 480 -427 640 -640 480 -640 480 -480 640 -640 425 -640 427 -640 427 -640 429 -640 427 -480 640 -640 429 -640 480 -640 480 -640 480 -640 427 -640 480 -640 480 -640 427 -640 480 -640 480 -500 333 -640 480 -640 427 -517 640 -640 480 -500 375 -640 427 -640 626 -640 427 -500 375 -500 333 -640 480 -640 427 -500 375 -640 480 -640 480 -640 429 -500 375 -480 640 -640 480 -640 640 -640 480 -640 360 -640 427 -640 427 -640 403 -640 480 -426 640 -640 426 -640 480 -640 428 -640 640 -543 640 -500 500 -640 427 -421 640 -640 428 -612 612 -640 427 -640 427 -640 438 -500 334 -500 375 -640 427 -426 640 -640 640 -423 640 -612 612 -640 280 -640 480 -640 426 -640 463 -640 480 -500 333 -478 640 -640 480 -640 424 -480 640 -640 480 -500 375 -640 480 -640 427 -640 427 -640 426 -640 427 -640 480 -640 480 -426 640 -640 424 -640 428 -500 375 -460 640 -500 333 -640 426 -640 425 -640 640 -640 480 -640 480 -640 426 -500 333 -427 640 -640 480 -612 612 -640 480 -640 484 -480 640 -480 640 -500 332 -640 509 -436 500 -640 427 -640 480 -500 336 -480 640 -360 640 -480 640 -640 480 -640 480 -500 333 -640 427 -640 426 -640 452 -640 427 -424 640 -427 640 -640 480 -640 427 -335 500 -375 500 -313 500 -500 309 -640 480 -640 613 -367 640 -640 494 -640 480 -640 489 -612 612 -640 425 -640 404 -480 640 -480 640 -640 601 -375 500 -640 441 -379 640 -640 426 -640 427 -640 480 -480 640 -640 427 -640 426 -640 427 -640 480 -375 500 -500 333 -500 375 -640 480 -480 640 -640 480 -72 51 -640 427 -480 640 -640 480 -640 480 -640 424 -640 360 -640 433 -481 640 -640 480 -640 640 -640 431 -640 426 -640 426 -640 480 -640 427 -640 480 -640 480 -479 640 -640 480 -640 496 -640 428 -640 427 -640 480 -640 480 -425 640 -640 427 -640 427 -640 422 -640 480 -500 375 -640 426 -640 480 -640 427 -640 480 -640 480 -640 529 -640 480 -640 428 -640 443 -480 640 -640 636 -640 378 -640 480 -383 500 -640 472 -640 427 -456 640 -640 427 -640 426 -640 427 -640 389 -378 500 -640 459 -640 427 -500 375 -331 500 -640 416 -640 640 -500 375 -640 480 -480 640 -455 640 -640 480 -500 375 -640 359 -433 640 -640 480 -640 480 -480 640 -427 640 -640 348 -640 479 -640 640 -640 478 -640 480 -320 240 -427 640 -640 427 -640 427 -640 426 -640 433 -640 480 -640 480 -360 480 -640 434 -480 640 -427 640 -640 465 -640 359 -480 640 -640 480 -640 480 -640 480 -640 480 -640 480 -640 389 -375 500 -640 451 -640 468 -640 474 -640 428 -600 450 -640 480 -612 612 -640 359 -500 333 -608 640 -424 640 -333 500 -640 481 -480 640 -428 500 -640 427 -640 458 -640 480 -640 426 -485 640 -500 375 -640 427 -640 427 -640 480 -640 480 -427 640 -640 480 -640 426 -640 424 -640 480 -640 480 -414 640 -500 500 -480 640 -457 640 -427 640 -500 498 -640 427 -387 500 -480 640 -640 428 -640 480 -480 640 -640 480 -640 482 -480 640 -640 427 -640 480 -640 426 -428 640 -500 332 -640 480 -576 494 -640 480 -640 480 -640 427 -640 426 -640 474 -640 482 -640 480 -427 640 -300 480 -640 360 -640 427 -612 612 -640 441 -640 480 -640 480 -640 478 -640 426 -640 480 -640 399 -403 640 -640 640 -500 375 -640 480 -640 427 -640 480 -640 427 -640 427 -640 394 -640 360 -640 428 -500 328 -612 612 -640 425 -277 500 -480 640 -640 508 -640 524 -427 640 -612 612 -640 427 -640 419 -372 500 -640 478 -640 427 -425 640 -640 480 -500 375 -480 640 -640 480 -480 640 -640 480 -640 426 -480 640 -640 427 -427 640 -500 375 -640 450 -640 480 -500 375 -612 612 -500 375 -480 640 -480 640 -480 640 -640 480 -480 640 -640 271 -480 640 -500 333 -640 480 -481 640 -427 640 -640 360 -640 427 -640 236 -640 480 -640 431 -480 640 -375 500 -640 426 -640 424 -640 480 -640 480 -441 640 -640 427 -427 640 -640 480 -500 375 -640 427 -480 640 -640 360 -640 480 -427 640 -640 427 -640 480 -640 427 -500 333 -480 640 -375 500 -433 500 -640 480 -640 480 -500 370 -640 360 -640 389 -436 640 -640 480 -640 480 -640 426 -427 640 -640 640 -576 384 -640 480 -500 415 -500 500 -640 480 -500 402 -640 480 -640 427 -333 500 -640 426 -500 375 -640 425 -440 500 -640 427 -640 480 -427 640 -640 426 -640 480 -333 500 -640 474 -640 480 -478 640 -480 640 -640 478 -640 427 -630 640 -500 375 -640 480 -640 458 -640 425 -640 480 -500 336 -332 500 -640 436 -640 480 -480 640 -640 512 -434 500 -640 426 -640 480 -478 640 -640 479 -640 483 -640 437 -640 436 -640 427 -640 425 -640 483 -480 640 -500 375 -640 428 -500 334 -359 473 -640 427 -640 288 -640 480 -640 480 -640 480 -480 640 -640 480 -500 375 -640 480 -640 480 -600 450 -500 335 -480 640 -640 480 -500 400 -640 480 -480 640 -500 333 -612 612 -640 480 -500 359 -375 500 -640 480 -640 413 -640 480 -640 480 -424 640 -640 494 -640 427 -640 480 -640 423 -640 426 -640 480 -640 480 -500 375 -480 640 -640 427 -640 480 -640 480 -640 427 -640 383 -425 640 -480 640 -640 427 -640 470 -640 427 -423 640 -480 640 -640 424 -500 336 -333 500 -640 480 -640 424 -640 427 -640 428 -500 375 -478 640 -640 512 -640 506 -640 480 -375 500 -640 396 -640 427 -640 428 -480 640 -333 500 -640 427 -500 333 -483 640 -640 480 -500 332 -640 426 -369 500 -640 396 -640 480 -640 427 -424 640 -640 424 -640 480 -427 640 -640 480 -458 640 -640 480 -480 640 -640 378 -640 601 -640 480 -640 480 -640 427 -640 480 -640 480 -320 240 -640 506 -640 426 -640 484 -427 640 -375 500 -640 426 -500 375 -640 480 -640 443 -640 428 -427 640 -504 337 -640 296 -375 500 -500 375 -480 640 -640 480 -296 442 -432 345 -375 500 -640 427 -478 640 -640 478 -640 494 -500 333 -640 480 -500 400 -427 640 -406 640 -425 640 -640 424 -640 427 -640 427 -640 458 -640 480 -612 612 -640 480 -500 375 -640 427 -640 480 -549 640 -500 281 -640 640 -500 333 -312 400 -500 375 -640 522 -500 375 -640 478 -640 427 -640 626 -640 480 -620 486 -640 422 -640 480 -506 640 -640 425 -640 480 -640 427 -640 425 -640 360 -640 512 -500 375 -640 480 -640 428 -640 370 -612 612 -640 480 -375 500 -640 605 -500 334 -640 480 -640 480 -640 481 -426 640 -500 375 -624 415 -640 400 -427 640 -481 500 -640 361 -425 640 -640 429 -640 360 -640 499 -640 480 -427 640 -640 424 -480 640 -640 427 -640 440 -500 375 -640 480 -640 480 -480 640 -640 521 -640 427 -471 500 -427 640 -640 479 -640 480 -500 375 -640 428 -640 480 -640 428 -500 333 -480 640 -640 480 -640 480 -640 480 -640 480 -640 480 -640 426 -500 334 -640 427 -427 640 -640 480 -640 480 -515 640 -480 640 -640 480 -572 640 -640 480 -640 480 -640 425 -640 480 -640 480 -640 360 -500 332 -640 360 -480 640 -480 640 -640 427 -640 480 -640 426 -640 480 -427 640 -427 640 -640 479 -640 640 -500 375 -640 457 -640 479 -640 376 -427 640 -640 426 -640 524 -392 640 -640 425 -640 429 -640 480 -640 426 -640 480 -640 512 -640 427 -500 375 -640 480 -640 480 -480 640 -480 640 -640 427 -640 480 -640 480 -426 640 -640 427 -640 494 -640 480 -375 500 -640 300 -640 480 -640 452 -640 480 -640 578 -640 427 -640 442 -640 480 -640 424 -480 640 -494 500 -233 350 -640 423 -640 640 -640 360 -427 640 -480 640 -640 427 -428 640 -640 427 -640 427 -640 480 -640 480 -500 444 -480 640 -640 480 -640 518 -427 640 -500 333 -640 480 -640 427 -480 640 -640 427 -640 480 -640 425 -640 427 -640 402 -640 427 -640 480 -640 425 -640 630 -429 640 -640 480 -640 640 -640 480 -480 640 -500 333 -640 346 -489 640 -640 427 -640 426 -640 144 -640 424 -640 480 -640 417 -640 480 -640 640 -640 426 -426 640 -640 480 -640 414 -300 357 -640 480 -640 427 -383 640 -480 640 -480 640 -375 500 -640 427 -500 375 -640 427 -429 640 -512 640 -640 473 -427 640 -640 426 -640 427 -640 241 -640 428 -640 478 -640 425 -456 640 -500 375 -640 480 -640 273 -500 375 -640 426 -500 375 -425 640 -500 375 -640 427 -612 612 -640 480 -422 640 -640 427 -427 640 -480 640 -500 375 -529 640 -640 501 -640 480 -640 424 -640 427 -640 530 -375 500 -640 427 -500 333 -640 428 -640 360 -640 480 -612 612 -500 500 -640 427 -640 480 -640 424 -480 640 -425 640 -640 480 -375 500 -500 375 -640 424 -600 464 -500 333 -500 500 -640 466 -640 427 -640 480 -640 348 -609 640 -640 480 -640 408 -640 480 -427 640 -640 480 -640 480 -640 416 -500 375 -640 569 -326 220 -419 640 -640 480 -375 500 -375 500 -640 427 -640 461 -480 640 -640 481 -427 640 -640 427 -640 480 -640 480 -640 427 -640 480 -480 640 -640 478 -640 427 -640 480 -375 500 -640 427 -500 375 -493 640 -500 375 -427 640 -640 480 -431 640 -640 480 -640 427 -640 428 -428 640 -640 360 -415 640 -640 480 -332 500 -640 427 -640 428 -640 444 -640 480 -428 640 -500 359 -640 427 -640 480 -640 480 -425 640 -375 500 -160 120 -500 481 -506 640 -640 427 -640 480 -640 448 -640 480 -612 612 -640 480 -640 427 -640 480 -640 428 -640 434 -640 480 -500 375 -640 480 -491 640 -640 425 -640 480 -640 474 -640 427 -640 283 -640 360 -640 427 -640 359 -640 360 -427 640 -640 480 -640 480 -480 640 -640 428 -640 426 -427 640 -640 427 -640 427 -640 463 -480 640 -640 433 -640 587 -640 425 -640 640 -640 427 -640 424 -640 427 -640 426 -640 480 -640 427 -500 339 -640 427 -640 427 -640 480 -480 640 -640 480 -640 480 -480 640 -640 480 -640 427 -640 426 -640 427 -640 427 -640 360 -640 480 -640 480 -480 640 -640 480 -375 500 -640 426 -640 439 -480 640 -500 375 -427 640 -640 427 -640 427 -512 640 -640 425 -640 494 -424 640 -480 640 -640 427 -640 480 -352 288 -640 360 -640 428 -427 640 -375 500 -640 427 -640 361 -297 500 -640 360 -480 640 -640 480 -612 612 -640 473 -640 519 -640 480 -640 425 -427 640 -640 480 -500 333 -480 640 -640 427 -640 484 -640 480 -640 483 -427 640 -427 640 -640 480 -640 480 -640 556 -500 331 -640 426 -480 640 -640 427 -480 640 -640 429 -500 375 -500 375 -640 425 -426 640 -640 480 -480 640 -484 640 -640 253 -640 431 -640 428 -640 427 -427 640 -398 640 -640 429 -640 360 -612 612 -480 640 -640 480 -640 640 -375 500 -640 472 -640 458 -640 640 -640 427 -640 428 -640 621 -500 334 -640 424 -640 480 -640 480 -640 426 -640 427 -427 640 -640 483 -640 428 -640 424 -516 640 -538 480 -427 640 -640 480 -640 480 -640 640 -406 640 -240 320 -500 375 -640 360 -612 612 -476 640 -640 427 -640 530 -640 426 -500 375 -640 396 -640 480 -480 640 -640 494 -640 508 -640 480 -640 640 -640 426 -432 640 -443 640 -640 427 -640 432 -640 480 -640 427 -427 640 -500 375 -612 612 -640 426 -640 480 -640 361 -331 500 -640 425 -640 480 -640 427 -480 640 -640 480 -640 427 -640 425 -640 428 -640 360 -500 374 -480 640 -427 640 -426 640 -640 427 -640 427 -640 463 -500 333 -640 426 -500 337 -373 640 -640 491 -427 640 -612 612 -640 423 -640 480 -640 480 -640 573 -640 464 -640 427 -640 480 -640 480 -350 375 -640 623 -612 612 -640 480 -640 479 -640 360 -315 315 -640 481 -640 427 -640 480 -480 640 -640 426 -640 425 -640 428 -640 427 -640 480 -640 478 -640 427 -375 500 -640 398 -640 427 -640 426 -427 640 -640 425 -640 362 -640 480 -500 375 -396 500 -500 375 -640 425 -376 500 -640 480 -426 640 -500 333 -383 640 -640 425 -640 425 -426 640 -640 480 -640 360 -640 489 -640 480 -612 612 -480 640 -640 479 -500 334 -640 480 -332 500 -332 500 -480 640 -375 500 -640 480 -640 480 -640 428 -500 166 -448 500 -640 480 -640 382 -640 360 -640 480 -452 640 -480 640 -640 480 -640 427 -640 427 -640 404 -640 480 -480 640 -640 480 -488 640 -640 480 -640 426 -640 427 -640 480 -434 640 -500 333 -480 640 -500 375 -640 480 -640 480 -640 426 -640 425 -334 500 -640 429 -640 361 -640 427 -320 640 -640 480 -480 640 -640 512 -640 472 -500 375 -640 480 -640 640 -640 425 -640 640 -427 640 -640 560 -494 640 -480 640 -640 427 -500 375 -427 640 -513 640 -640 427 -300 400 -427 640 -453 640 -428 640 -335 500 -640 480 -640 426 -640 480 -480 640 -478 640 -612 612 -640 480 -640 480 -640 481 -640 480 -640 427 -375 500 -640 631 -640 405 -480 640 -500 375 -640 480 -427 640 -640 480 -500 333 -640 425 -480 640 -640 427 -570 570 -640 480 -640 480 -640 480 -640 427 -612 612 -640 402 -398 600 -640 427 -448 312 -640 427 -640 427 -640 427 -640 427 -640 478 -640 481 -640 538 -500 333 -509 640 -640 480 -640 480 -640 640 -480 640 -640 427 -640 480 -640 480 -640 427 -375 500 -640 480 -640 425 -612 612 -636 640 -480 640 -640 427 -428 640 -428 640 -640 480 -640 426 -640 480 -640 480 -426 640 -492 500 -640 498 -640 480 -640 425 -640 425 -640 425 -640 427 -640 432 -500 333 -353 640 -500 375 -500 375 -480 640 -640 360 -438 640 -640 480 -640 426 -576 576 -638 640 -640 466 -361 500 -640 427 -640 456 -640 390 -640 585 -375 500 -640 480 -640 480 -640 401 -640 480 -500 401 -640 480 -640 480 -424 640 -640 480 -480 640 -640 414 -483 640 -480 640 -500 333 -640 480 -640 393 -427 640 -480 640 -640 414 -480 640 -500 332 -640 640 -640 395 -640 222 -640 427 -640 427 -427 640 -640 480 -640 427 -640 480 -640 429 -500 375 -500 333 -480 640 -500 470 -640 363 -335 500 -340 455 -639 640 -640 480 -458 640 -316 500 -640 480 -500 375 -640 480 -640 512 -640 480 -640 480 -480 640 -427 640 -389 500 -640 480 -375 500 -480 640 -640 480 -640 426 -640 359 -639 640 -640 480 -500 375 -612 612 -375 500 -640 480 -640 378 -640 428 -640 480 -640 478 -640 461 -480 640 -424 640 -640 480 -640 480 -500 333 -640 320 -612 612 -500 333 -640 480 -420 640 -500 375 -640 480 -640 480 -640 480 -640 425 -640 428 -640 427 -640 451 -640 424 -640 516 -640 500 -640 480 -620 413 -640 426 -640 480 -480 640 -333 500 -498 640 -500 334 -640 480 -640 480 -640 480 -640 480 -500 359 -480 640 -640 427 -425 640 -640 483 -640 428 -640 480 -480 640 -640 427 -640 426 -640 425 -640 427 -640 480 -640 427 -640 450 -640 480 -473 640 -640 400 -640 485 -480 640 -640 427 -640 426 -640 402 -640 480 -482 640 -480 640 -480 640 -427 640 -500 375 -480 640 -640 426 -640 640 -608 379 -640 480 -640 427 -640 480 -640 480 -640 480 -640 480 -640 480 -500 374 -427 640 -640 425 -640 427 -640 427 -500 333 -500 302 -427 640 -480 640 -640 458 -640 480 -480 640 -480 640 -427 640 -640 480 -640 480 -640 421 -640 427 -640 480 -640 480 -640 427 -427 640 -640 480 -427 640 -640 480 -332 500 -640 425 -640 428 -640 427 -640 448 -640 427 -427 640 -640 428 -640 480 -640 510 -640 426 -500 375 -640 502 -427 640 -640 439 -427 640 -640 480 -480 640 -640 427 -480 640 -640 480 -640 513 -640 426 -640 427 -640 425 -640 426 -640 427 -480 640 -640 425 -640 427 -640 486 -424 640 -640 480 -500 380 -640 427 -427 640 -640 171 -428 640 -374 500 -640 427 -426 640 -500 375 -640 427 -640 480 -640 427 -500 375 -640 640 -500 469 -640 480 -480 640 -480 640 -640 383 -640 480 -604 640 -640 477 -640 480 -640 480 -640 480 -500 364 -430 640 -640 424 -640 480 -640 426 -640 428 -640 425 -612 612 -640 480 -640 426 -588 640 -640 426 -500 375 -640 480 -640 427 -640 427 -640 480 -427 640 -200 150 -640 480 -640 429 -640 429 -471 500 -426 640 -350 467 -640 425 -428 640 -428 640 -500 375 -426 640 -640 480 -480 640 -640 426 -428 640 -640 429 -640 480 -500 375 -640 424 -640 457 -427 640 -480 640 -640 424 -612 612 -427 640 -640 480 -640 480 -640 424 -640 480 -360 640 -427 640 -480 640 -640 640 -640 427 -640 480 -640 427 -640 424 -640 479 -640 470 -640 390 -427 640 -610 407 -426 640 -640 359 -375 500 -640 426 -640 478 -638 640 -640 427 -640 480 -640 429 -640 339 -640 415 -640 480 -640 478 -480 640 -453 640 -429 640 -427 640 -640 427 -640 528 -640 498 -640 480 -640 360 -640 480 -480 640 -640 480 -640 474 -640 480 -640 427 -640 479 -640 480 -500 375 -640 480 -640 480 -640 426 -640 480 -480 640 -500 375 -640 406 -640 480 -640 428 -640 640 -640 480 -480 640 -640 480 -631 600 -640 480 -425 640 -426 640 -427 640 -640 480 -640 480 -480 640 -640 480 -640 427 -640 457 -500 333 -640 427 -640 480 -640 480 -640 416 -640 427 -426 640 -640 427 -640 409 -469 500 -480 640 -640 427 -640 427 -640 428 -640 480 -640 427 -500 375 -500 375 -640 480 -640 575 -640 512 -640 480 -428 640 -640 480 -640 480 -427 640 -640 426 -427 640 -640 480 -640 403 -640 480 -640 458 -500 333 -500 356 -640 302 -375 500 -640 242 -640 480 -640 426 -640 427 -640 415 -640 513 -640 427 -500 402 -640 480 -427 640 -640 424 -480 640 -375 500 -640 427 -500 281 -640 445 -640 425 -357 520 -160 120 -640 480 -640 504 -466 640 -640 428 -640 480 -622 622 -640 427 -640 480 -640 426 -640 480 -640 451 -640 480 -612 612 -640 480 -640 427 -640 427 -501 359 -612 612 -640 437 -640 480 -640 426 -640 425 -640 427 -640 480 -334 500 -500 335 -640 425 -640 480 -500 333 -640 428 -640 427 -640 480 -640 444 -480 640 -640 426 -640 480 -640 425 -512 384 -640 640 -526 640 -640 427 -640 438 -424 640 -640 424 -383 640 -640 331 -640 480 -640 428 -640 462 -640 476 -427 640 -640 480 -640 360 -500 349 -640 480 -640 480 -640 427 -172 227 -640 427 -500 500 -640 426 -640 480 -640 478 -640 485 -445 640 -483 640 -375 500 -640 480 -640 427 -640 480 -640 349 -640 480 -640 426 -500 334 -612 612 -640 427 -427 640 -640 480 -640 427 -480 640 -500 334 -480 640 -427 640 -640 361 -640 480 -640 426 -427 640 -640 480 -640 427 -640 426 -640 360 -640 480 -640 480 -379 640 -640 481 -640 427 -640 480 -640 480 -640 334 -640 416 -640 640 -640 640 -480 640 -427 640 -640 427 -640 427 -426 640 -640 359 -640 426 -640 427 -640 376 -500 332 -640 427 -640 424 -640 427 -640 480 -640 427 -640 480 -480 640 -500 375 -425 640 -480 640 -427 640 -640 441 -640 427 -640 427 -640 331 -640 411 -640 427 -500 375 -640 480 -640 426 -640 639 -640 480 -640 427 -640 461 -480 640 -640 480 -640 480 -454 640 -427 640 -640 427 -640 413 -480 640 -612 612 -500 375 -640 480 -640 337 -640 480 -640 480 -480 640 -640 544 -640 425 -426 640 -480 640 -640 415 -235 314 -640 481 -640 408 -426 640 -640 424 -640 427 -500 493 -640 427 -640 383 -500 346 -640 370 -640 480 -500 331 -640 359 -640 480 -502 640 -480 640 -640 336 -640 480 -640 480 -478 640 -480 640 -640 480 -640 383 -640 480 -640 480 -425 640 -480 640 -640 427 -640 426 -640 480 -640 480 -640 426 -612 612 -640 426 -640 426 -333 500 -640 427 -500 375 -640 494 -640 426 -333 500 -640 443 -640 483 -426 640 -640 480 -640 480 -640 480 -640 480 -640 427 -640 325 -500 375 -640 427 -500 375 -500 375 -640 428 -640 396 -640 460 -500 335 -640 480 -640 482 -640 480 -426 640 -640 416 -640 480 -640 480 -500 375 -480 640 -426 640 -640 480 -640 512 -478 640 -640 428 -480 640 -640 480 -480 640 -640 361 -480 640 -640 360 -457 640 -640 429 -640 480 -480 640 -614 640 -640 447 -640 480 -480 640 -480 640 -640 429 -640 480 -640 480 -376 500 -189 500 -500 333 -640 425 -426 640 -640 407 -640 426 -640 427 -426 640 -640 427 -500 331 -640 426 -428 640 -500 332 -640 480 -640 425 -640 425 -640 480 -427 640 -640 425 -640 512 -640 628 -500 332 -640 427 -640 480 -536 640 -640 427 -640 427 -640 426 -640 640 -640 360 -612 612 -640 480 -640 640 -640 426 -640 427 -480 640 -640 426 -640 427 -640 480 -640 438 -640 590 -640 480 -640 480 -331 500 -640 427 -640 640 -640 427 -500 375 -500 375 -640 480 -480 640 -640 480 -550 640 -500 500 -640 480 -640 427 -359 640 -640 480 -375 500 -640 427 -500 336 -640 512 -640 418 -640 427 -500 281 -640 360 -375 500 -640 428 -427 640 -419 640 -640 360 -640 480 -640 427 -640 426 -640 426 -640 480 -640 640 -640 426 -640 480 -640 480 -640 480 -640 530 -480 640 -367 640 -640 480 -640 236 -500 375 -480 640 -640 427 -640 427 -640 414 -640 289 -500 376 -640 480 -640 480 -640 428 -640 427 -640 480 -640 428 -500 334 -640 360 -427 640 -640 480 -500 333 -640 480 -375 500 -375 500 -640 480 -640 360 -500 375 -640 386 -640 480 -640 480 -640 480 -640 512 -640 480 -426 640 -600 453 -640 427 -640 480 -640 480 -500 375 -478 640 -640 480 -640 480 -612 612 -500 500 -640 429 -500 482 -640 480 -480 640 -500 333 -335 500 -640 356 -640 480 -640 508 -640 360 -640 427 -640 427 -512 640 -640 427 -480 640 -429 640 -427 640 -640 427 -425 640 -640 480 -640 426 -640 640 -478 640 -640 428 -428 640 -640 480 -640 427 -640 480 -612 612 -640 480 -640 480 -500 375 -427 640 -480 640 -427 640 -640 424 -500 283 -640 433 -640 329 -640 288 -612 612 -640 489 -640 427 -425 640 -640 278 -500 377 -480 640 -640 480 -640 578 -640 479 -640 425 -640 626 -640 455 -640 427 -640 448 -640 443 -640 640 -621 640 -480 640 -640 428 -375 500 -482 640 -427 640 -480 640 -500 375 -612 612 -640 427 -480 640 -640 427 -480 640 -640 427 -640 480 -640 501 -473 640 -375 500 -480 640 -480 640 -640 427 -428 640 -640 480 -500 309 -640 424 -640 426 -640 425 -480 640 -640 446 -480 640 -640 427 -640 480 -640 480 -427 640 -480 640 -445 500 -640 480 -640 329 -375 500 -640 480 -500 333 -640 427 -500 375 -640 480 -640 480 -427 640 -400 500 -640 480 -640 480 -427 640 -612 612 -640 480 -427 640 -640 480 -400 300 -640 480 -640 480 -640 426 -426 640 -640 496 -500 333 -640 428 -640 426 -383 640 -500 478 -640 480 -640 480 -586 640 -480 640 -640 427 -480 640 -427 640 -640 360 -375 500 -640 480 -640 426 -640 480 -320 240 -640 427 -640 428 -640 427 -640 510 -333 500 -612 612 -640 359 -640 424 -427 640 -640 427 -500 375 -427 640 -640 480 -640 480 -340 500 -640 413 -640 425 -500 375 -478 640 -640 443 -640 480 -500 188 -640 427 -640 361 -640 419 -640 427 -427 640 -640 480 -500 375 -480 640 -640 480 -427 640 -640 478 -640 480 -612 612 -500 375 -640 427 -640 426 -640 427 -513 640 -291 449 -640 480 -640 480 -640 527 -640 426 -640 426 -500 333 -427 640 -640 427 -640 640 -640 480 -640 640 -640 427 -640 400 -427 640 -640 428 -640 480 -480 640 -640 427 -640 426 -640 418 -640 480 -361 640 -640 427 -640 429 -640 424 -480 640 -640 426 -480 640 -630 450 -640 569 -640 480 -427 640 -640 427 -480 640 -612 612 -640 425 -640 426 -500 375 -500 333 -359 640 -444 640 -500 375 -640 480 -640 512 -640 480 -640 382 -332 500 -640 429 -640 480 -640 480 -640 480 -640 480 -640 480 -375 500 -640 586 -640 427 -332 500 -358 500 -500 374 -640 411 -375 500 -640 428 -640 427 -640 427 -480 640 -640 480 -427 640 -427 640 -500 333 -640 480 -640 426 -360 640 -640 427 -640 296 -480 640 -640 450 -425 640 -333 500 -427 640 -427 640 -640 426 -640 428 -480 640 -546 366 -480 640 -640 428 -640 425 -640 480 -640 401 -480 382 -640 480 -640 480 -500 375 -640 480 -612 612 -640 427 -500 500 -640 426 -480 640 -480 640 -640 488 -480 640 -640 389 -612 612 -640 427 -640 425 -375 500 -427 640 -640 430 -640 480 -334 500 -640 480 -640 479 -640 427 -640 427 -640 480 -640 480 -640 412 -640 418 -427 640 -640 478 -640 425 -640 324 -500 335 -640 480 -640 428 -640 480 -500 333 -480 640 -640 453 -640 364 -426 640 -640 480 -640 427 -640 480 -429 640 -500 334 -640 480 -640 466 -480 640 -480 640 -383 640 -640 425 -640 480 -640 429 -612 612 -640 454 -640 487 -480 640 -640 427 -640 480 -375 500 -478 640 -480 640 -640 480 -640 480 -640 480 -640 480 -480 640 -640 471 -454 640 -640 427 -640 427 -640 640 -640 524 -640 480 -640 480 -640 480 -640 513 -640 427 -640 417 -284 640 -500 375 -640 383 -640 427 -640 480 -640 480 -612 612 -640 427 -478 640 -640 480 -640 633 -640 469 -640 480 -640 427 -640 426 -640 480 -426 640 -640 480 -375 500 -640 288 -640 458 -640 508 -480 640 -640 428 -427 640 -640 480 -640 480 -640 480 -480 640 -640 480 -424 640 -640 428 -640 426 -640 360 -640 426 -500 375 -384 640 -640 427 -480 640 -640 478 -640 427 -500 353 -500 334 -640 480 -640 480 -508 640 -427 640 -640 427 -500 333 -640 480 -586 640 -640 481 -500 375 -640 451 -640 480 -640 640 -640 509 -425 640 -640 211 -640 480 -640 480 -375 500 -500 333 -640 476 -640 405 -500 375 -640 480 -600 450 -640 426 -640 424 -500 333 -640 480 -640 640 -640 480 -640 483 -640 427 -640 480 -640 238 -640 360 -640 425 -500 330 -640 480 -640 400 -454 500 -640 480 -480 640 -640 539 -640 457 -441 600 -500 333 -500 375 -640 458 -640 480 -640 426 -640 498 -640 480 -612 612 -508 640 -640 428 -480 640 -480 640 -640 433 -426 640 -640 425 -640 459 -438 640 -640 427 -480 640 -640 426 -640 425 -640 426 -613 640 -640 480 -640 427 -640 426 -640 427 -640 427 -640 425 -640 427 -500 375 -480 640 -470 352 -640 480 -480 640 -480 640 -640 480 -640 428 -640 480 -640 425 -640 478 -480 640 -640 391 -640 426 -640 426 -618 640 -640 427 -640 512 -640 427 -480 640 -640 480 -427 640 -640 480 -640 480 -640 427 -640 470 -500 382 -640 424 -456 640 -640 480 -640 480 -640 427 -640 426 -480 640 -640 427 -640 480 -500 375 -640 480 -640 427 -640 427 -640 480 -426 640 -640 480 -384 640 -612 612 -640 340 -424 640 -500 430 -640 286 -480 640 -427 640 -500 334 -640 480 -480 640 -640 494 -640 480 -640 480 -640 424 -375 500 -370 500 -640 480 -640 427 -462 640 -484 640 -640 427 -640 480 -424 640 -640 480 -550 413 -480 640 -480 640 -640 499 -424 640 -640 400 -640 449 -640 640 -375 500 -640 427 -640 427 -640 427 -640 443 -500 375 -640 426 -640 427 -640 446 -483 640 -448 640 -640 529 -500 333 -612 612 -640 427 -640 426 -640 429 -500 332 -640 515 -480 640 -640 427 -640 418 -640 423 -640 480 -640 427 -640 428 -640 427 -640 428 -640 401 -640 427 -480 640 -480 640 -640 482 -480 640 -640 480 -640 427 -427 640 -640 550 -640 427 -426 640 -640 425 -640 426 -640 480 -640 253 -640 426 -640 427 -480 640 -445 640 -640 404 -640 491 -480 640 -640 424 -640 425 -640 437 -426 640 -612 612 -494 640 -500 375 -640 425 -640 480 -426 640 -612 612 -640 480 -640 480 -640 453 -546 366 -640 426 -640 480 -640 427 -640 359 -640 480 -640 480 -640 427 -500 500 -640 426 -640 624 -500 375 -428 640 -640 427 -640 418 -640 540 -640 480 -500 333 -640 480 -640 427 -500 334 -640 426 -640 480 -500 332 -640 426 -640 426 -640 432 -640 411 -640 480 -640 459 -640 521 -640 427 -640 427 -427 640 -353 640 -500 333 -640 427 -612 612 -640 505 -640 480 -640 549 -478 640 -640 480 -640 427 -640 427 -640 480 -640 428 -640 427 -479 640 -640 427 -640 427 -300 255 -500 375 -640 427 -367 500 -640 430 -393 640 -640 480 -640 458 -640 480 -640 363 -640 423 -640 428 -640 288 -640 427 -399 500 -640 479 -640 543 -612 612 -512 640 -640 429 -480 640 -360 239 -640 428 -500 375 -500 375 -640 425 -513 640 -640 409 -640 480 -480 640 -640 104 -640 428 -640 427 -427 640 -640 466 -640 427 -640 430 -640 480 -640 426 -640 427 -640 427 -426 640 -640 427 -640 480 -640 480 -500 375 -640 480 -455 640 -640 480 -640 480 -640 427 -640 480 -500 333 -500 375 -612 612 -640 480 -333 500 -500 333 -500 375 -640 427 -428 640 -640 376 -640 480 -640 480 -640 480 -500 377 -640 506 -479 640 -500 333 -600 296 -500 375 -640 428 -576 640 -640 480 -640 425 -640 425 -480 640 -425 640 -640 480 -500 375 -640 360 -500 375 -640 583 -500 375 -500 375 -480 640 -480 640 -480 640 -640 480 -640 428 -640 480 -640 403 -640 480 -640 480 -640 451 -640 480 -640 480 -640 429 -640 451 -640 480 -640 427 -500 375 -427 640 -640 425 -500 333 -640 480 -427 640 -640 427 -640 425 -640 480 -640 456 -408 391 -640 480 -477 640 -640 427 -512 640 -480 640 -640 429 -640 425 -640 480 -640 480 -640 407 -640 545 -640 480 -640 480 -640 480 -500 375 -333 500 -640 428 -500 333 -640 378 -427 640 -640 428 -375 500 -640 486 -640 640 -640 480 -640 424 -480 640 -640 427 -426 640 -640 480 -640 362 -426 640 -640 426 -640 480 -612 612 -640 426 -640 480 -640 426 -640 480 -425 640 -640 426 -421 640 -427 640 -480 640 -640 480 -427 640 -334 500 -480 640 -640 427 -640 429 -500 333 -640 480 -500 334 -326 500 -640 480 -640 480 -478 640 -480 640 -500 375 -640 512 -640 423 -640 427 -640 640 -640 480 -640 425 -640 480 -640 480 -640 480 -640 427 -640 252 -640 427 -640 480 -428 640 -500 374 -640 480 -500 375 -375 500 -640 480 -500 375 -640 360 -640 426 -640 640 -480 640 -427 640 -480 640 -640 479 -640 431 -640 373 -428 640 -640 433 -640 480 -640 480 -640 480 -640 427 -640 480 -484 640 -640 429 -480 640 -375 500 -427 640 -640 480 -640 480 -500 375 -288 352 -371 640 -640 480 -425 640 -640 625 -640 359 -640 478 -640 480 -640 480 -640 480 -640 405 -640 427 -640 478 -640 480 -640 480 -640 480 -500 331 -640 425 -640 479 -640 427 -427 640 -640 427 -640 480 -640 564 -500 375 -640 480 -480 384 -576 413 -427 640 -640 428 -612 612 -425 640 -500 333 -640 426 -427 640 -640 480 -640 480 -480 640 -640 426 -500 407 -640 394 -600 450 -500 375 -500 375 -500 332 -469 640 -500 375 -640 427 -640 427 -640 427 -640 480 -640 425 -640 603 -640 480 -640 463 -612 612 -640 427 -426 640 -427 640 -640 480 -640 426 -640 480 -640 480 -640 480 -640 427 -640 427 -600 450 -640 480 -640 425 -500 375 -640 318 -436 640 -640 640 -640 427 -480 640 -640 461 -427 640 -427 640 -375 500 -426 640 -640 480 -640 480 -480 640 -480 640 -640 480 -308 462 -480 640 -640 427 -640 480 -640 427 -640 404 -360 500 -640 427 -640 426 -640 490 -480 640 -400 300 -640 444 -578 640 -640 435 -640 640 -427 640 -356 500 -640 426 -640 431 -500 375 -640 480 -640 480 -640 480 -640 506 -375 500 -640 480 -416 640 -461 640 -640 426 -640 476 -480 640 -640 425 -640 427 -500 375 -640 427 -640 427 -640 429 -640 425 -640 480 -640 480 -640 502 -640 427 -480 640 -640 480 -480 361 -640 480 -640 423 -640 560 -640 429 -500 146 -640 478 -365 640 -640 480 -427 640 -640 480 -640 482 -500 375 -640 480 -640 427 -427 640 -480 640 -640 404 -640 427 -500 375 -420 640 -325 500 -640 428 -640 263 -360 270 -640 427 -428 640 -640 427 -640 480 -426 640 -640 469 -640 428 -640 640 -500 375 -640 425 -427 640 -640 386 -640 445 -640 480 -640 480 -479 500 -640 480 -640 427 -640 640 -640 480 -640 478 -640 424 -480 640 -346 500 -500 280 -640 426 -480 640 -640 480 -640 427 -640 480 -640 480 -500 377 -399 640 -500 375 -640 480 -640 429 -478 640 -500 375 -480 640 -640 484 -480 640 -640 480 -640 400 -640 516 -612 612 -640 485 -426 640 -480 640 -640 416 -410 640 -640 428 -598 393 -640 407 -425 640 -640 428 -439 640 -640 411 -640 368 -640 429 -427 640 -640 433 -640 480 -500 375 -500 474 -640 426 -640 426 -640 424 -640 601 -640 427 -640 320 -640 426 -640 427 -500 333 -640 426 -640 350 -640 480 -640 428 -640 427 -640 480 -640 483 -375 500 -426 640 -640 480 -640 480 -640 398 -640 427 -640 481 -640 480 -480 640 -640 494 -640 371 -640 481 -640 480 -640 480 -640 326 -640 427 -324 182 -595 608 -640 427 -640 480 -500 334 -640 512 -480 640 -640 480 -612 612 -640 426 -640 428 -612 612 -640 480 -500 375 -500 443 -640 388 -640 480 -640 427 -640 480 -640 496 -640 457 -480 566 -480 640 -640 442 -480 640 -640 463 -640 426 -640 391 -486 640 -427 640 -640 427 -640 409 -640 427 -640 426 -640 480 -500 327 -640 427 -640 427 -528 640 -640 480 -640 423 -640 427 -640 480 -640 480 -640 536 -640 427 -640 480 -640 427 -480 640 -640 425 -640 481 -640 480 -640 427 -640 640 -640 427 -640 426 -480 640 -640 480 -640 450 -500 375 -640 427 -640 480 -640 479 -431 640 -480 640 -640 480 -640 540 -427 640 -400 205 -640 480 -640 432 -640 480 -640 427 -640 409 -640 427 -427 640 -500 375 -640 424 -640 480 -500 375 -428 640 -640 480 -640 427 -640 383 -640 419 -640 480 -640 426 -500 375 -640 427 -640 426 -640 467 -640 361 -640 480 -480 640 -640 427 -640 480 -640 480 -480 640 -500 375 -500 500 -640 480 -640 400 -425 640 -640 427 -640 425 -640 360 -640 427 -640 490 -640 480 -432 640 -500 375 -640 479 -640 414 -424 640 -640 500 -612 612 -640 480 -640 623 -327 640 -375 500 -640 429 -640 426 -640 221 -480 640 -640 480 -640 428 -640 480 -500 281 -640 360 -640 426 -640 439 -640 427 -640 360 -480 640 -400 300 -640 596 -640 427 -640 428 -360 640 -640 457 -640 438 -500 427 -640 640 -500 375 -375 500 -640 426 -426 640 -640 480 -640 388 -640 426 -640 480 -640 480 -640 427 -640 428 -640 423 -640 436 -500 372 -640 480 -640 480 -640 366 -500 333 -640 480 -640 428 -500 484 -425 640 -640 480 -427 640 -500 332 -480 640 -640 427 -441 640 -523 640 -480 640 -500 381 -427 640 -640 405 -640 360 -500 375 -427 640 -640 427 -640 427 -408 500 -640 479 -333 500 -640 480 -640 427 -640 444 -640 480 -640 640 -640 425 -375 500 -500 375 -640 431 -640 427 -640 430 -426 640 -432 288 -640 359 -640 429 -480 640 -640 427 -512 640 -500 375 -427 640 -640 425 -612 612 -500 471 -612 612 -427 640 -480 640 -640 427 -640 480 -640 427 -640 480 -640 480 -640 480 -500 375 -640 282 -358 500 -375 500 -640 427 -640 427 -640 480 -640 480 -640 427 -427 640 -640 422 -640 428 -640 427 -500 375 -640 426 -640 400 -640 427 -433 640 -375 500 -375 500 -640 427 -640 480 -427 640 -519 640 -640 361 -640 480 -640 427 -426 640 -461 640 -640 480 -640 427 -640 425 -425 640 -500 375 -640 400 -640 480 -640 400 -640 480 -500 375 -640 479 -480 640 -640 480 -640 427 -640 414 -334 500 -640 480 -640 480 -640 427 -479 319 -640 480 -640 480 -427 640 -640 427 -640 639 -640 527 -459 640 -640 437 -640 394 -640 419 -640 427 -640 427 -640 427 -640 477 -640 427 -640 479 -500 333 -640 426 -640 333 -640 425 -500 400 -640 480 -640 480 -640 480 -640 424 -640 380 -640 465 -372 480 -640 427 -640 480 -480 640 -640 427 -640 480 -640 427 -640 360 -640 361 -640 479 -500 199 -426 640 -640 427 -640 426 -500 375 -640 480 -640 427 -500 347 -640 480 -640 480 -640 480 -480 360 -427 640 -480 640 -640 427 -640 427 -640 482 -640 480 -640 426 -480 640 -640 427 -640 480 -640 480 -612 612 -640 446 -640 425 -640 480 -640 480 -640 426 -426 640 -640 427 -640 427 -426 640 -640 427 -458 640 -640 480 -500 428 -640 384 -640 425 -500 375 -480 640 -600 450 -512 640 -640 427 -640 512 -365 640 -640 429 -640 557 -640 499 -500 375 -500 375 -640 451 -333 500 -640 480 -640 468 -427 640 -484 640 -640 480 -640 480 -640 408 -640 427 -640 424 -640 480 -500 339 -427 640 -640 480 -640 426 -640 480 -640 396 -640 480 -640 427 -640 427 -640 481 -427 640 -612 612 -640 480 -640 427 -640 480 -640 427 -640 425 -427 640 -612 612 -640 427 -500 375 -480 640 -640 428 -640 480 -640 480 -640 426 -480 640 -640 427 -500 375 -330 500 -640 480 -640 480 -612 612 -640 427 -640 425 -164 500 -480 640 -640 428 -500 375 -640 480 -640 480 -640 425 -640 480 -457 640 -640 631 -640 480 -640 462 -640 480 -640 480 -612 612 -459 640 -640 480 -640 480 -640 551 -640 480 -640 386 -640 618 -640 428 -640 480 -640 428 -540 540 -640 480 -640 493 -640 482 -640 360 -500 333 -500 500 -640 480 -478 640 -640 427 -640 541 -500 375 -640 480 -640 480 -640 427 -640 480 -640 480 -640 510 -416 500 -640 480 -640 640 -640 427 -478 640 -640 480 -640 480 -640 429 -640 480 -522 640 -640 477 -500 377 -375 500 -640 427 -640 433 -427 640 -640 303 -500 285 -480 640 -640 480 -640 480 -640 427 -180 500 -500 375 -640 480 -640 268 -480 640 -640 427 -640 426 -640 426 -640 480 -640 426 -480 640 -640 480 -640 480 -640 480 -480 640 -640 424 -478 640 -480 640 -640 428 -640 426 -640 425 -500 313 -640 398 -640 480 -480 640 -500 333 -640 457 -429 640 -640 427 -640 480 -426 640 -480 640 -640 480 -640 480 -640 424 -486 640 -640 428 -640 512 -640 427 -640 366 -427 640 -640 427 -640 444 -500 375 -421 640 -427 640 -640 426 -428 640 -480 640 -426 640 -500 375 -375 500 -640 480 -640 479 -640 425 -640 480 -375 500 -500 375 -640 480 -640 425 -640 428 -640 427 -494 640 -640 480 -640 480 -640 426 -640 451 -640 457 -426 640 -640 480 -612 612 -640 478 -640 480 -640 427 -286 640 -640 457 -640 432 -480 640 -500 333 -640 358 -640 428 -640 427 -640 427 -640 474 -640 426 -640 426 -480 640 -640 427 -640 432 -640 426 -480 640 -640 480 -640 426 -640 494 -480 640 -640 429 -640 427 -375 500 -640 419 -342 640 -640 421 -640 426 -612 612 -640 480 -375 500 -500 500 -640 360 -640 469 -640 480 -425 640 -640 427 -612 612 -640 392 -640 427 -640 480 -640 480 -640 428 -640 480 -640 426 -640 464 -640 427 -500 400 -640 369 -480 640 -640 427 -640 480 -640 480 -640 438 -640 428 -640 426 -600 600 -640 427 -640 512 -640 480 -333 500 -640 454 -640 480 -480 640 -640 423 -640 427 -640 431 -640 480 -500 375 -640 463 -640 426 -612 612 -640 360 -640 424 -640 480 -640 480 -640 426 -571 640 -377 640 -480 640 -640 480 -640 498 -480 640 -640 427 -640 426 -500 376 -640 478 -640 480 -500 375 -640 480 -640 426 -500 334 -480 640 -640 480 -640 480 -640 427 -640 425 -640 480 -480 640 -426 640 -640 563 -640 480 -480 640 -500 335 -640 480 -427 640 -480 640 -640 480 -427 640 -640 426 -640 426 -640 424 -480 640 -427 640 -500 333 -640 480 -500 375 -640 480 -640 480 -500 373 -640 417 -480 640 -640 453 -640 429 -640 360 -640 427 -640 427 -640 480 -480 640 -640 427 -640 480 -480 640 -640 404 -640 480 -640 427 -375 500 -640 427 -640 425 -640 426 -640 427 -640 329 -640 426 -333 500 -640 427 -640 426 -640 454 -640 480 -427 640 -640 374 -640 369 -640 427 -640 433 -640 427 -612 612 -640 480 -640 424 -640 480 -426 640 -640 480 -640 480 -640 434 -428 640 -480 640 -640 523 -500 400 -640 640 -640 427 -640 361 -640 432 -336 500 -500 375 -640 427 -640 480 -640 424 -640 425 -427 640 -640 480 -480 360 -482 640 -640 480 -480 640 -640 426 -640 427 -500 375 -640 480 -640 427 -612 612 -640 480 -640 425 -640 480 -363 500 -640 480 -640 480 -640 480 -640 480 -500 375 -640 490 -640 480 -640 426 -640 424 -640 427 -640 427 -640 480 -640 480 -375 500 -640 413 -640 462 -480 640 -427 640 -427 640 -572 640 -640 480 -640 289 -640 427 -640 427 -640 478 -427 640 -427 640 -640 427 -375 500 -375 500 -500 332 -640 402 -640 429 -500 337 -640 480 -640 480 -640 480 -640 480 -640 425 -640 480 -640 427 -640 457 -640 427 -500 400 -640 480 -640 480 -427 640 -640 581 -640 480 -640 480 -640 427 -640 427 -500 375 -640 480 -612 612 -640 428 -463 640 -640 436 -640 480 -500 375 -500 375 -512 640 -640 462 -640 636 -640 480 -640 474 -480 640 -640 428 -640 480 -480 640 -333 500 -640 512 -612 612 -500 333 -640 427 -640 494 -640 426 -640 427 -640 480 -640 429 -640 480 -500 334 -500 488 -378 500 -430 628 -640 429 -640 639 -640 455 -640 480 -640 427 -480 640 -640 426 -640 480 -567 378 -612 612 -640 480 -427 640 -640 427 -640 427 -640 480 -640 427 -640 480 -367 500 -640 480 -612 612 -360 240 -500 375 -589 640 -640 480 -640 425 -640 427 -425 640 -640 360 -640 427 -640 491 -640 424 -640 480 -427 640 -640 480 -640 480 -640 480 -333 500 -640 480 -426 640 -480 640 -640 427 -640 409 -640 369 -640 471 -500 407 -425 640 -375 500 -338 450 -640 429 -640 423 -640 480 -640 480 -640 480 -200 150 -640 428 -427 640 -640 480 -500 377 -640 480 -640 433 -640 478 -640 426 -640 238 -478 640 -640 480 -640 480 -640 427 -640 421 -640 480 -640 427 -640 379 -640 427 -640 426 -640 480 -500 375 -428 640 -640 480 -640 427 -640 384 -480 640 -537 640 -612 612 -427 640 -640 437 -640 480 -640 480 -480 640 -640 427 -500 379 -640 480 -640 426 -640 478 -640 427 -640 480 -435 640 -428 640 -375 500 -640 427 -500 375 -457 640 -640 427 -640 426 -640 480 -640 428 -640 426 -480 640 -640 427 -640 427 -640 480 -640 427 -640 480 -640 640 -640 480 -640 480 -427 640 -640 480 -640 427 -640 480 -640 480 -640 429 -500 375 -640 480 -436 640 -640 401 -640 306 -640 480 -640 426 -640 461 -640 429 -640 480 -500 375 -427 640 -640 384 -640 480 -500 375 -640 425 -640 427 -640 640 -640 480 -640 640 -480 640 -640 640 -480 640 -640 443 -516 640 -640 426 -480 640 -427 640 -640 480 -640 298 -425 640 -640 480 -640 480 -424 640 -640 480 -640 427 -480 640 -640 569 -375 500 -344 640 -383 640 -640 415 -640 480 -640 480 -640 480 -500 333 -640 426 -426 640 -480 640 -375 500 -640 480 -640 256 -640 427 -640 480 -500 375 -640 480 -640 480 -640 427 -640 480 -640 427 -500 375 -640 361 -640 360 -480 640 -640 424 -500 375 -640 480 -640 480 -640 424 -640 427 -640 483 -640 510 -640 480 -640 410 -640 427 -480 640 -640 350 -427 640 -640 427 -640 360 -640 480 -640 484 -640 480 -640 427 -333 500 -640 427 -640 508 -640 428 -640 480 -426 640 -640 427 -640 640 -640 480 -640 480 -640 480 -640 478 -426 640 -640 428 -640 427 -640 480 -640 640 -640 428 -463 640 -640 425 -640 480 -640 272 -640 429 -640 425 -427 640 -640 481 -640 480 -640 427 -612 612 -640 427 -448 640 -640 427 -631 640 -640 480 -640 427 -640 405 -640 524 -500 334 -640 425 -640 445 -640 427 -479 640 -480 640 -498 640 -640 514 -640 478 -640 480 -640 480 -640 480 -640 640 -640 428 -640 480 -640 480 -640 444 -640 428 -640 424 -640 428 -640 427 -640 426 -640 435 -640 426 -640 488 -480 640 -427 640 -640 458 -640 427 -490 500 -640 480 -360 640 -500 375 -512 640 -640 480 -333 500 -640 427 -640 427 -640 480 -500 335 -640 424 -640 427 -640 427 -478 640 -500 375 -640 425 -640 425 -640 459 -640 428 -640 480 -500 325 -612 612 -640 480 -375 500 -640 480 -640 480 -640 427 -640 480 -334 500 -640 480 -640 426 -628 640 -640 640 -480 640 -427 640 -640 431 -640 433 -640 480 -505 640 -480 640 -500 375 -500 333 -640 480 -640 480 -640 480 -500 412 -640 418 -640 427 -500 349 -640 427 -375 500 -640 480 -640 480 -427 640 -640 348 -359 640 -640 427 -640 429 -500 400 -500 333 -427 640 -500 281 -612 612 -612 612 -640 480 -500 333 -427 640 -640 425 -427 640 -500 374 -425 640 -640 459 -640 424 -640 424 -640 439 -500 325 -427 640 -588 640 -428 640 -500 279 -640 480 -426 640 -500 375 -640 429 -480 360 -500 333 -612 612 -640 350 -333 500 -612 612 -640 478 -640 512 -499 640 -612 612 -640 480 -612 612 -480 640 -640 480 -640 426 -640 480 -640 426 -490 640 -480 640 -426 640 -640 426 -640 427 -500 344 -376 500 -640 436 -640 480 -640 480 -427 640 -640 640 -612 612 -640 479 -640 361 -480 640 -640 478 -361 500 -640 607 -640 480 -640 427 -640 480 -500 468 -640 480 -480 640 -640 478 -640 427 -612 612 -640 480 -640 479 -640 480 -640 458 -640 425 -427 640 -640 479 -612 612 -640 427 -500 375 -640 480 -640 426 -640 480 -500 333 -640 480 -640 360 -640 640 -480 640 -427 640 -480 640 -640 425 -640 359 -640 480 -640 426 -425 640 -480 640 -640 427 -500 375 -640 480 -500 375 -338 500 -640 449 -640 427 -500 375 -427 640 -640 427 -640 480 -426 640 -640 419 -640 640 -640 428 -640 480 -640 424 -640 480 -612 612 -512 640 -640 480 -500 334 -375 500 -640 392 -640 434 -480 640 -640 426 -640 441 -640 427 -640 426 -640 509 -640 320 -640 427 -332 500 -612 612 -612 612 -640 427 -640 465 -376 500 -640 427 -480 640 -640 505 -640 427 -331 500 -426 640 -640 593 -640 426 -576 640 -640 480 -640 401 -640 428 -640 480 -500 327 -480 640 -612 612 -480 640 -640 461 -425 640 -480 640 -640 452 -480 640 -640 427 -640 480 -640 426 -375 500 -375 500 -640 427 -500 330 -640 480 -640 480 -640 480 -640 425 -375 500 -640 480 -500 333 -640 359 -640 427 -480 640 -500 390 -640 479 -500 376 -628 640 -426 640 -640 480 -640 480 -640 453 -640 480 -500 317 -640 480 -500 282 -640 426 -640 516 -640 425 -640 426 -640 461 -640 480 -640 424 -640 480 -640 427 -640 480 -480 640 -640 480 -640 434 -640 427 -640 427 -640 494 -500 281 -480 640 -640 399 -640 480 -400 640 -640 427 -426 640 -612 612 -640 480 -640 480 -640 427 -640 446 -480 640 -640 427 -640 640 -210 139 -612 612 -640 427 -640 425 -640 427 -640 480 -500 333 -640 480 -640 426 -426 640 -500 333 -480 640 -640 480 -640 425 -640 426 -640 480 -640 480 -640 424 -640 360 -640 478 -640 480 -640 426 -640 480 -640 426 -426 640 -640 480 -427 640 -480 640 -612 612 -640 512 -500 375 -640 480 -640 426 -640 480 -427 640 -427 640 -422 562 -500 334 -640 413 -525 640 -640 480 -640 427 -640 480 -640 480 -640 480 -375 500 -640 427 -640 480 -640 480 -640 640 -640 364 -640 426 -473 640 -480 640 -640 480 -480 640 -640 425 -640 480 -640 428 -640 480 -375 500 -640 427 -640 427 -640 527 -640 480 -314 470 -500 399 -640 496 -480 640 -480 640 -500 500 -640 480 -426 640 -640 427 -480 640 -640 480 -640 426 -640 425 -284 423 -640 640 -640 427 -640 414 -480 640 -612 612 -640 468 -333 500 -500 392 -640 480 -480 640 -640 480 -640 480 -640 480 -640 463 -640 413 -427 640 -640 427 -640 480 -640 640 -480 640 -500 333 -640 428 -640 480 -640 480 -640 480 -640 480 -640 431 -500 302 -640 428 -480 640 -500 332 -640 494 -500 333 -480 640 -640 426 -427 640 -640 463 -640 425 -500 392 -640 480 -500 332 -640 480 -640 426 -375 500 -640 480 -640 480 -640 480 -427 640 -640 480 -500 375 -500 375 -500 379 -640 576 -640 370 -640 481 -640 408 -640 458 -629 640 -640 480 -500 375 -640 434 -425 640 -429 640 -480 640 -640 427 -640 512 -640 480 -640 480 -640 428 -500 265 -375 500 -427 640 -640 481 -500 500 -500 334 -640 480 -640 577 -424 640 -640 427 -500 332 -640 427 -639 640 -428 640 -505 640 -569 640 -640 426 -640 427 -480 640 -500 375 -640 426 -640 485 -480 640 -500 400 -640 480 -640 480 -640 427 -640 426 -471 640 -427 640 -640 530 -333 500 -640 426 -500 351 -640 425 -640 427 -500 375 -640 427 -640 427 -427 640 -640 426 -640 426 -426 640 -640 480 -465 640 -333 500 -640 480 -640 480 -500 375 -640 480 -394 640 -640 427 -640 360 -480 640 -500 333 -640 640 -640 427 -626 640 -640 425 -640 480 -640 480 -640 385 -427 640 -640 426 -640 516 -640 480 -640 443 -640 427 -640 480 -640 425 -640 428 -640 480 -484 640 -375 500 -427 640 -640 427 -640 400 -574 640 -640 478 -487 200 -640 426 -640 512 -640 480 -640 299 -640 389 -640 320 -640 427 -480 640 -640 426 -612 612 -480 640 -640 400 -640 412 -425 640 -640 424 -640 476 -640 480 -478 640 -640 478 -640 425 -640 426 -612 612 -640 424 -640 480 -640 411 -640 512 -426 640 -640 480 -640 427 -640 428 -500 377 -427 640 -640 480 -640 449 -612 612 -640 514 -640 539 -500 281 -640 427 -640 480 -640 425 -640 480 -640 480 -640 480 -640 480 -500 375 -640 426 -640 480 -640 426 -640 480 -500 333 -640 400 -640 433 -640 480 -640 478 -640 425 -640 429 -640 480 -640 329 -640 480 -640 428 -640 427 -640 427 -500 375 -480 640 -640 480 -640 640 -480 640 -520 640 -640 514 -640 480 -640 427 -640 480 -500 375 -640 383 -500 375 -640 495 -465 640 -640 427 -480 640 -640 480 -612 612 -333 500 -480 640 -500 375 -640 480 -400 300 -500 375 -640 427 -640 427 -640 359 -612 612 -640 373 -612 612 -424 640 -640 425 -640 444 -640 480 -640 478 -640 427 -500 332 -640 480 -640 427 -640 427 -640 639 -640 480 -480 640 -640 427 -500 375 -471 640 -640 427 -500 375 -640 426 -640 426 -500 371 -640 480 -500 375 -640 428 -358 243 -640 498 -640 424 -640 480 -500 375 -640 480 -640 424 -500 341 -640 480 -640 480 -640 480 -640 432 -500 375 -640 426 -640 458 -640 480 -640 427 -640 480 -640 414 -640 480 -416 640 -640 458 -480 640 -612 612 -427 640 -640 403 -640 480 -640 512 -640 481 -640 427 -640 480 -375 500 -640 427 -640 480 -640 427 -612 612 -500 375 -500 375 -469 640 -640 480 -640 500 -640 428 -640 486 -426 640 -402 600 -640 449 -640 427 -500 375 -427 640 -640 427 -640 500 -640 427 -640 480 -500 437 -504 438 -640 479 -480 640 -500 375 -640 480 -640 640 -480 640 -640 400 -640 480 -640 426 -640 480 -640 427 -500 337 -640 427 -640 426 -635 640 -640 337 -640 416 -640 480 -555 640 -640 480 -640 480 -640 400 -640 439 -640 428 -480 640 -640 427 -640 640 -419 500 -640 426 -500 332 -500 375 -640 426 -640 426 -640 427 -640 512 -500 375 -640 427 -462 640 -427 640 -500 334 -409 640 -500 375 -640 406 -640 425 -500 375 -640 480 -612 612 -640 426 -428 640 -640 480 -640 426 -640 480 -640 427 -640 427 -424 640 -640 426 -640 480 -533 640 -640 529 -640 480 -480 640 -640 428 -640 480 -500 333 -640 426 -500 395 -640 528 -426 640 -480 640 -500 400 -640 427 -500 357 -640 480 -640 427 -612 612 -640 478 -480 640 -640 424 -640 427 -640 480 -480 640 -640 480 -424 640 -640 427 -640 152 -640 427 -480 640 -640 445 -640 427 -640 427 -640 524 -640 480 -478 640 -640 480 -640 480 -375 500 -640 427 -640 427 -640 481 -640 427 -525 350 -640 427 -640 497 -640 480 -640 426 -640 457 -428 640 -640 427 -640 427 -640 426 -640 360 -640 426 -640 480 -640 358 -640 479 -480 640 -344 640 -476 640 -640 383 -574 361 -640 480 -388 640 -640 355 -427 640 -640 480 -640 480 -568 320 -640 480 -640 426 -640 489 -481 640 -640 427 -640 497 -640 388 -640 424 -640 480 -333 500 -640 480 -640 378 -480 640 -640 427 -612 612 -375 500 -640 367 -500 386 -640 473 -640 427 -640 480 -640 344 -427 640 -480 640 -640 480 -500 500 -500 375 -640 425 -640 480 -640 428 -640 427 -468 640 -640 361 -480 640 -640 480 -640 480 -640 425 -500 374 -480 640 -640 427 -640 481 -500 500 -640 426 -480 360 -640 480 -640 514 -612 612 -427 640 -640 426 -640 480 -427 640 -640 480 -640 480 -640 480 -640 428 -480 640 -500 333 -640 426 -640 426 -640 480 -640 480 -640 480 -640 440 -640 426 -640 480 -640 480 -640 480 -640 409 -640 425 -640 427 -640 422 -640 331 -426 640 -640 427 -640 480 -640 479 -640 427 -640 480 -640 512 -640 512 -640 427 -640 478 -480 640 -640 480 -479 640 -640 424 -640 432 -428 640 -640 427 -426 640 -640 426 -480 640 -640 480 -640 480 -640 480 -640 491 -640 480 -640 427 -500 481 -640 480 -480 640 -640 426 -640 385 -640 427 -427 640 -500 375 -480 640 -640 427 -480 640 -640 480 -640 480 -640 480 -640 427 -640 425 -640 480 -500 375 -431 640 -532 640 -640 428 -500 375 -640 620 -640 445 -424 640 -640 480 -640 428 -500 375 -640 425 -640 480 -640 427 -640 426 -640 427 -640 514 -640 480 -640 477 -640 426 -640 469 -640 427 -640 480 -640 427 -640 480 -640 480 -640 480 -640 423 -640 326 -500 333 -531 640 -612 612 -640 480 -640 427 -640 480 -640 426 -640 458 -480 640 -640 480 -480 640 -640 427 -640 498 -640 480 -640 366 -480 640 -640 429 -640 424 -640 481 -446 640 -427 640 -640 427 -640 396 -640 427 -640 480 -640 480 -640 426 -489 640 -343 500 -480 640 -400 267 -500 333 -427 640 -375 500 -640 428 -640 480 -427 640 -640 640 -335 500 -640 480 -640 480 -640 360 -640 567 -427 640 -500 469 -515 640 -425 640 -640 496 -640 480 -640 360 -640 480 -480 640 -640 457 -640 480 -500 333 -640 428 -500 362 -640 448 -640 457 -319 500 -427 640 -640 480 -640 427 -375 500 -640 360 -500 333 -426 640 -480 640 -640 480 -640 480 -640 478 -427 640 -500 334 -612 612 -640 427 -612 612 -424 640 -500 332 -640 480 -427 640 -424 640 -640 425 -640 427 -640 494 -500 335 -480 640 -640 480 -427 640 -512 640 -469 640 -640 427 -640 426 -480 640 -640 428 -640 426 -640 480 -367 500 -640 480 -404 640 -640 480 -640 480 -640 496 -640 480 -480 640 -640 480 -640 480 -640 541 -480 640 -640 512 -640 640 -480 640 -640 428 -500 333 -382 640 -333 500 -480 640 -640 426 -400 289 -640 480 -640 427 -480 640 -640 480 -640 423 -640 425 -640 427 -640 424 -640 480 -640 427 -640 569 -640 448 -500 375 -640 427 -640 425 -640 404 -500 331 -480 640 -640 480 -480 640 -640 480 -640 427 -630 640 -480 640 -500 384 -640 427 -640 485 -640 616 -640 480 -640 426 -427 640 -640 480 -640 639 -640 480 -640 480 -375 500 -640 427 -640 427 -375 500 -640 480 -640 427 -640 480 -640 510 -480 640 -480 640 -471 640 -640 480 -640 427 -612 612 -480 640 -640 502 -640 425 -480 640 -640 480 -640 480 -640 471 -480 640 -640 451 -500 640 -640 480 -640 421 -640 426 -640 496 -640 480 -500 335 -429 640 -500 363 -640 433 -640 426 -640 425 -480 640 -640 480 -426 640 -640 329 -640 480 -640 424 -640 429 -480 640 -640 428 -612 612 -640 385 -480 640 -640 424 -640 360 -640 426 -640 427 -640 480 -640 427 -546 640 -640 438 -500 298 -500 375 -500 400 -480 640 -640 427 -640 426 -640 408 -473 640 -427 640 -640 428 -640 480 -640 427 -640 425 -640 449 -480 640 -427 640 -612 612 -333 500 -500 295 -640 640 -640 480 -480 640 -500 333 -640 482 -335 500 -640 427 -640 480 -640 432 -425 640 -640 428 -640 427 -640 424 -640 429 -640 479 -480 640 -640 480 -640 480 -279 500 -640 430 -640 429 -640 400 -640 426 -640 552 -640 423 -640 427 -640 427 -640 480 -640 480 -640 426 -640 428 -640 480 -640 480 -600 450 -480 640 -427 640 -480 640 -427 640 -427 640 -640 480 -640 427 -640 480 -480 640 -567 377 -427 640 -480 640 -640 509 -640 428 -640 360 -640 480 -500 375 -640 425 -640 400 -640 640 -640 427 -640 359 -412 640 -449 640 -375 500 -640 427 -640 426 -640 427 -500 335 -640 427 -640 640 -640 480 -640 428 -480 640 -640 424 -640 426 -640 480 -480 640 -640 360 -500 375 -564 640 -640 426 -640 426 -640 443 -612 612 -360 640 -437 640 -640 428 -640 480 -640 480 -640 429 -640 512 -640 480 -640 427 -550 640 -427 640 -640 429 -479 640 -640 480 -640 426 -640 426 -640 427 -640 480 -612 612 -640 427 -500 335 -640 480 -640 427 -500 333 -480 640 -640 425 -640 480 -640 433 -346 500 -640 480 -612 612 -640 480 -640 480 -640 426 -640 512 -640 427 -640 441 -487 640 -640 480 -480 640 -640 480 -426 640 -612 612 -640 486 -375 500 -428 640 -640 640 -640 480 -640 427 -640 482 -640 501 -640 480 -640 427 -427 640 -640 428 -640 480 -640 360 -640 427 -427 640 -640 427 -640 480 -640 480 -640 457 -640 428 -640 428 -612 612 -640 425 -640 498 -640 427 -640 474 -428 640 -640 503 -640 427 -640 479 -379 640 -640 427 -612 612 -640 480 -480 640 -640 427 -640 427 -443 640 -612 612 -426 640 -640 640 -640 343 -512 640 -500 375 -480 640 -640 480 -640 457 -640 427 -640 480 -427 640 -640 354 -500 375 -404 265 -425 640 -640 480 -546 640 -427 640 -640 480 -640 400 -448 336 -375 500 -427 640 -640 422 -500 333 -640 480 -640 480 -640 427 -640 425 -396 640 -500 375 -640 426 -640 450 -640 427 -640 480 -640 480 -480 640 -640 425 -500 375 -640 511 -640 427 -639 640 -640 480 -640 427 -360 640 -640 425 -640 427 -640 480 -375 500 -640 426 -640 540 -640 340 -640 480 -375 500 -640 427 -640 480 -640 480 -480 640 -640 427 -480 640 -640 548 -640 578 -500 281 -500 333 -500 400 -640 354 -640 480 -640 640 -640 425 -480 640 -640 480 -640 387 -640 480 -640 498 -333 500 -375 500 -640 426 -411 640 -640 383 -480 640 -640 480 -640 360 -640 483 -640 426 -640 426 -612 612 -640 480 -480 640 -640 463 -640 480 -640 512 -640 480 -427 640 -640 480 -480 640 -500 375 -480 640 -640 427 -640 480 -500 375 -640 427 -640 427 -426 640 -400 300 -640 480 -333 500 -466 640 -640 427 -480 640 -640 433 -640 427 -500 375 -480 640 -640 480 -640 427 -640 489 -640 427 -500 375 -640 480 -640 480 -478 640 -500 375 -640 426 -480 640 -640 550 -640 480 -640 427 -640 426 -612 612 -640 480 -640 427 -480 640 -640 486 -640 450 -640 480 -332 500 -427 640 -640 428 -640 539 -640 427 -640 480 -640 459 -640 425 -640 480 -612 612 -640 480 -640 427 -428 640 -640 480 -640 464 -426 640 -640 480 -640 359 -333 467 -640 398 -640 427 -640 429 -500 334 -640 480 -443 640 -427 640 -640 369 -640 426 -640 423 -640 427 -640 479 -640 480 -427 640 -640 427 -640 472 -640 480 -450 640 -640 453 -640 425 -640 360 -500 375 -640 425 -428 640 -400 300 -640 480 -375 500 -640 424 -640 427 -640 428 -640 479 -640 427 -640 480 -500 375 -640 425 -640 480 -640 486 -640 480 -640 480 -640 505 -480 640 -640 480 -640 442 -640 480 -428 640 -640 428 -640 505 -500 500 -428 640 -640 423 -640 425 -640 480 -640 427 -640 425 -640 480 -640 480 -500 375 -500 375 -640 480 -338 500 -640 400 -640 434 -640 425 -500 333 -612 612 -640 426 -500 375 -500 375 -640 425 -640 424 -427 640 -500 286 -640 460 -500 375 -640 454 -640 480 -500 375 -640 480 -640 426 -640 374 -479 640 -640 480 -640 480 -640 512 -640 480 -640 427 -640 360 -640 427 -376 500 -640 427 -640 424 -483 640 -640 480 -500 400 -480 640 -640 478 -500 375 -429 640 -425 640 -427 640 -640 480 -640 479 -332 500 -503 640 -640 427 -640 427 -640 480 -500 333 -640 480 -427 640 -500 333 -480 640 -640 479 -407 640 -640 427 -500 375 -640 427 -375 500 -480 640 -456 640 -612 612 -500 341 -552 640 -500 375 -640 427 -640 513 -640 581 -480 640 -640 427 -640 481 -333 500 -640 480 -640 481 -427 640 -640 426 -350 263 -500 375 -640 480 -500 375 -640 424 -553 640 -640 427 -640 426 -427 640 -640 423 -640 427 -640 433 -426 640 -640 427 -428 640 -640 513 -640 480 -640 427 -424 640 -640 425 -640 426 -640 480 -640 426 -640 394 -640 426 -640 480 -640 427 -640 426 -426 640 -634 640 -640 517 -427 640 -640 466 -375 500 -500 354 -500 375 -427 640 -640 425 -240 320 -427 640 -640 429 -640 426 -640 428 -640 394 -640 498 -640 480 -640 480 -427 640 -640 480 -640 425 -640 427 -427 640 -640 480 -640 427 -640 428 -640 480 -375 500 -640 428 -640 480 -640 448 -612 612 -640 562 -338 640 -500 371 -500 333 -640 426 -640 480 -500 333 -640 480 -640 480 -640 480 -480 640 -640 429 -640 428 -640 413 -640 483 -427 640 -333 500 -500 337 -640 427 -640 427 -640 451 -640 480 -500 341 -640 428 -640 428 -640 480 -640 480 -640 480 -640 428 -375 500 -640 427 -375 500 -640 640 -640 480 -640 426 -640 480 -360 270 -480 640 -640 480 -640 480 -640 478 -640 480 -500 333 -480 640 -640 408 -640 480 -457 640 -427 640 -624 640 -500 333 -640 409 -640 480 -640 429 -478 640 -375 500 -375 500 -640 429 -640 640 -640 429 -640 424 -640 427 -640 480 -640 426 -640 451 -640 426 -640 427 -640 424 -640 480 -640 480 -469 640 -640 480 -640 480 -640 425 -432 640 -427 640 -434 500 -640 427 -640 427 -427 640 -480 640 -427 640 -500 375 -640 427 -426 640 -640 426 -640 427 -640 473 -427 640 -640 480 -427 640 -640 480 -480 640 -500 325 -640 384 -640 480 -640 427 -500 324 -427 640 -640 424 -640 480 -640 480 -480 640 -427 640 -426 640 -640 480 -500 375 -640 427 -428 640 -640 295 -640 478 -640 480 -427 640 -640 428 -482 640 -418 640 -640 480 -480 640 -480 640 -640 427 -640 480 -612 612 -639 640 -640 480 -375 500 -640 480 -640 427 -640 480 -524 640 -640 427 -425 640 -640 427 -427 640 -640 426 -640 427 -640 361 -640 480 -640 480 -640 424 -640 480 -640 480 -640 426 -640 480 -640 428 -500 377 -423 640 -480 640 -640 464 -640 426 -640 496 -500 375 -640 508 -640 426 -427 640 -500 326 -424 640 -640 480 -640 426 -640 383 -580 329 -334 500 -500 333 -640 424 -640 346 -640 472 -640 537 -640 640 -375 500 -427 640 -640 480 -640 424 -640 480 -427 640 -640 480 -480 640 -612 612 -500 375 -480 640 -640 427 -640 426 -640 480 -500 375 -375 500 -640 427 -640 360 -640 384 -640 480 -480 640 -640 614 -612 612 -500 375 -438 500 -640 480 -640 427 -640 480 -375 500 -640 271 -428 640 -640 521 -640 426 -640 480 -640 426 -640 480 -640 481 -612 612 -640 427 -640 426 -500 281 -429 640 -640 486 -375 500 -640 480 -640 480 -427 640 -640 480 -640 428 -375 500 -640 478 -612 612 -640 480 -640 480 -500 330 -375 500 -427 640 -640 428 -480 640 -640 428 -640 398 -480 640 -446 640 -640 480 -375 500 -640 481 -640 427 -640 398 -478 640 -476 640 -640 427 -640 480 -640 428 -640 427 -640 480 -640 479 -640 480 -427 640 -640 426 -500 375 -500 375 -640 428 -480 640 -640 425 -640 543 -412 640 -500 375 -640 404 -480 640 -500 375 -640 524 -640 426 -640 480 -500 375 -640 427 -480 640 -428 640 -500 333 -640 480 -612 612 -640 427 -427 640 -514 640 -640 434 -640 424 -640 359 -480 640 -640 480 -640 483 -500 375 -640 480 -640 425 -612 612 -640 480 -640 429 -480 640 -640 427 -640 512 -640 401 -612 612 -500 375 -640 512 -640 480 -500 375 -552 640 -640 480 -640 480 -640 519 -521 640 -640 480 -640 427 -500 375 -640 480 -640 426 -640 426 -640 427 -500 375 -427 640 -640 429 -640 546 -427 640 -500 335 -640 480 -640 480 -640 428 -640 481 -640 407 -427 640 -640 480 -500 353 -427 640 -640 426 -480 640 -640 480 -640 378 -640 480 -640 311 -640 359 -640 426 -329 500 -640 480 -640 480 -640 427 -640 425 -500 332 -600 600 -400 542 -640 425 -640 512 -640 480 -427 640 -640 427 -500 375 -640 480 -480 640 -427 640 -500 375 -640 631 -640 480 -640 361 -500 375 -640 427 -640 428 -640 424 -480 640 -640 428 -640 480 -640 480 -480 640 -640 427 -640 480 -500 375 -513 640 -478 640 -500 382 -640 425 -640 609 -474 640 -500 373 -640 427 -640 377 -425 640 -640 480 -475 640 -640 479 -640 427 -613 640 -480 640 -640 480 -480 640 -640 378 -640 360 -449 640 -360 640 -640 479 -640 480 -480 640 -640 440 -640 640 -640 360 -500 375 -640 427 -640 427 -640 480 -640 360 -612 612 -500 375 -480 640 -640 427 -640 427 -640 575 -640 480 -640 480 -480 640 -640 426 -640 480 -282 500 -640 480 -640 429 -640 315 -640 480 -640 479 -640 480 -500 500 -640 418 -640 425 -640 640 -640 428 -640 480 -640 427 -640 426 -640 427 -411 640 -480 640 -640 480 -500 375 -640 480 -640 528 -640 426 -500 358 -612 612 -640 478 -640 425 -640 522 -640 428 -640 426 -640 428 -640 484 -427 640 -640 426 -457 640 -320 213 -640 427 -480 640 -640 425 -640 480 -640 480 -640 459 -428 640 -612 612 -640 480 -640 480 -640 427 -640 427 -516 640 -640 383 -640 640 -640 425 -500 333 -480 640 -640 427 -427 640 -640 584 -375 500 -426 640 -640 504 -640 480 -640 414 -640 427 -640 502 -500 364 -640 480 -461 640 -640 440 -375 500 -640 480 -640 476 -512 640 -640 439 -640 359 -640 480 -640 425 -640 427 -640 640 -500 334 -375 500 -333 500 -500 332 -640 428 -640 426 -640 428 -427 640 -640 480 -640 427 -428 640 -612 612 -640 426 -640 480 -640 427 -640 391 -640 512 -640 427 -640 480 -500 333 -640 427 -463 640 -500 331 -640 480 -640 592 -640 462 -640 480 -640 428 -640 480 -640 361 -333 500 -480 640 -640 427 -480 640 -640 427 -640 480 -549 640 -399 640 -640 426 -640 333 -640 463 -298 500 -480 640 -640 426 -640 427 -640 413 -640 442 -640 428 -640 427 -426 640 -640 424 -640 522 -483 640 -640 428 -640 480 -480 640 -640 428 -640 480 -640 428 -427 640 -427 640 -640 491 -640 480 -640 428 -640 480 -480 640 -480 640 -640 428 -640 427 -500 375 -640 480 -500 375 -640 463 -640 386 -640 480 -500 375 -640 427 -640 480 -309 640 -640 480 -640 426 -419 640 -480 640 -612 612 -500 375 -640 480 -480 640 -500 375 -373 640 -640 480 -640 426 -128 160 -640 427 -500 375 -480 640 -500 400 -427 640 -640 400 -539 445 -640 427 -640 424 -428 640 -480 640 -640 425 -500 375 -479 640 -640 427 -640 427 -480 640 -640 478 -640 429 -640 374 -640 480 -500 500 -640 427 -640 440 -640 480 -612 612 -439 640 -640 457 -612 612 -640 481 -427 640 -640 480 -640 427 -640 480 -640 426 -477 640 -640 458 -640 426 -500 375 -640 428 -640 480 -375 500 -500 334 -640 480 -640 480 -640 489 -428 640 -640 480 -500 375 -640 427 -640 480 -640 426 -640 512 -640 480 -640 293 -401 640 -640 480 -359 500 -323 500 -427 640 -480 640 -640 424 -640 427 -500 375 -640 409 -480 640 -640 424 -640 480 -500 281 -640 427 -640 480 -640 426 -375 500 -640 480 -640 480 -612 612 -640 533 -416 350 -640 480 -640 427 -375 500 -640 427 -640 640 -640 480 -640 428 -640 412 -640 480 -640 480 -640 480 -640 427 -640 359 -612 612 -640 427 -491 500 -640 427 -427 640 -287 432 -426 640 -334 500 -320 240 -359 500 -500 375 -640 427 -640 339 -640 480 -432 288 -496 640 -500 335 -640 426 -427 640 -517 640 -640 529 -640 425 -640 383 -640 480 -390 640 -640 427 -333 500 -640 480 -640 462 -640 427 -640 480 -640 433 -480 640 -640 436 -425 640 -500 400 -640 479 -640 427 -640 428 -640 427 -640 480 -576 401 -640 480 -640 480 -640 426 -640 480 -375 500 -640 426 -478 640 -640 480 -640 426 -640 427 -640 480 -425 640 -640 480 -269 640 -480 640 -500 375 -640 480 -480 640 -640 421 -640 452 -426 640 -459 500 -640 427 -640 428 -640 427 -640 426 -640 480 -480 640 -640 427 -640 433 -640 480 -427 640 -640 472 -640 427 -640 480 -640 331 -480 640 -640 427 -640 416 -509 640 -500 375 -640 480 -640 480 -640 426 -640 428 -640 480 -640 425 -640 448 -640 480 -640 428 -480 640 -640 474 -640 428 -400 500 -640 480 -500 281 -480 640 -480 640 -640 443 -640 533 -640 427 -640 424 -480 640 -640 640 -500 375 -640 351 -640 428 -500 376 -640 427 -421 640 -640 480 -640 480 -640 360 -640 427 -640 427 -640 451 -640 428 -640 480 -640 369 -640 640 -640 480 -433 640 -640 433 -640 427 -640 424 -480 640 -427 640 -640 428 -640 427 -480 640 -640 480 -640 360 -640 480 -640 480 -500 375 -640 480 -640 480 -612 612 -640 426 -640 427 -640 480 -456 640 -640 427 -640 420 -480 640 -640 427 -640 457 -640 508 -640 457 -640 427 -640 427 -640 427 -640 429 -640 539 -640 488 -640 480 -427 640 -640 424 -640 543 -521 640 -640 480 -500 375 -640 364 -444 640 -640 427 -640 461 -480 640 -640 427 -479 640 -420 640 -640 505 -375 500 -640 450 -640 427 -640 333 -640 480 -640 427 -640 425 -640 426 -640 428 -640 427 -640 427 -471 640 -480 640 -640 640 -424 640 -500 334 -640 544 -640 386 -640 427 -427 640 -640 391 -640 480 -640 536 -425 640 -640 480 -377 500 -358 500 -480 640 -640 427 -640 480 -427 640 -500 303 -640 480 -640 426 -640 640 -640 398 -640 433 -640 428 -640 480 -450 350 -640 457 -451 640 -640 576 -640 427 -427 640 -640 523 -640 429 -428 640 -640 425 -480 640 -640 410 -479 640 -640 480 -640 427 -500 333 -459 640 -640 427 -640 360 -513 640 -427 640 -640 406 -640 603 -500 331 -640 427 -409 500 -640 427 -640 480 -640 427 -480 640 -478 640 -640 480 -612 612 -480 640 -640 427 -640 480 -500 332 -375 500 -600 600 -640 427 -480 640 -612 612 -500 331 -480 640 -640 480 -640 480 -640 427 -640 458 -640 429 -640 428 -640 427 -640 543 -640 480 -500 325 -500 318 -640 426 -640 480 -640 640 -480 640 -332 500 -640 427 -480 640 -640 427 -375 640 -640 480 -375 500 -427 640 -480 640 -640 480 -640 427 -427 640 -640 428 -640 424 -640 480 -640 468 -640 427 -640 480 -640 480 -640 463 -640 513 -640 427 -640 480 -640 425 -640 400 -640 427 -640 425 -640 480 -640 476 -640 480 -640 428 -640 428 -500 375 -500 334 -640 480 -640 480 -500 357 -426 640 -640 480 -640 480 -427 640 -427 640 -480 640 -480 640 -497 500 -480 640 -479 640 -640 428 -640 426 -640 640 -640 426 -640 427 -500 375 -640 452 -640 427 -500 347 -640 426 -612 612 -640 480 -421 640 -640 427 -640 432 -640 480 -640 427 -500 375 -612 612 -640 427 -364 500 -402 600 -640 439 -478 640 -640 478 -375 500 -640 480 -640 427 -640 480 -640 480 -640 427 -640 426 -640 480 -640 427 -640 427 -640 393 -480 640 -612 612 -332 500 -426 640 -640 427 -395 640 -640 480 -640 480 -480 640 -640 480 -640 426 -480 640 -640 214 -640 496 -640 426 -419 640 -500 333 -500 400 -640 478 -640 318 -500 500 -640 426 -612 612 -640 480 -640 428 -640 427 -640 360 -640 424 -640 456 -567 640 -640 480 -466 640 -500 345 -640 480 -427 640 -640 480 -500 333 -343 500 -640 480 -640 480 -640 480 -640 640 -478 640 -375 500 -640 480 -640 421 -640 426 -640 480 -640 480 -640 480 -640 320 -640 428 -640 480 -640 449 -640 360 -640 480 -640 426 -640 456 -640 427 -640 426 -640 480 -640 360 -500 375 -640 427 -360 640 -640 427 -640 426 -640 478 -640 398 -640 425 -640 430 -462 640 -619 640 -640 379 -640 425 -480 640 -640 428 -640 427 -426 640 -427 640 -333 500 -427 640 -640 394 -640 426 -640 480 -640 383 -640 267 -500 417 -604 403 -427 640 -478 640 -640 400 -640 480 -500 334 -640 533 -640 427 -640 480 -640 427 -640 480 -640 408 -640 426 -640 480 -640 425 -640 428 -640 427 -480 640 -640 495 -188 285 -640 429 -640 480 -427 640 -640 431 -612 612 -640 424 -640 427 -640 426 -500 333 -640 459 -341 500 -640 426 -500 375 -480 273 -640 480 -640 425 -425 640 -640 480 -640 426 -640 480 -425 640 -427 640 -640 427 -480 640 -640 480 -480 640 -480 640 -244 183 -480 640 -640 428 -500 375 -500 375 -640 427 -480 640 -640 384 -640 344 -640 523 -640 427 -427 640 -640 480 -500 356 -480 640 -332 500 -640 640 -612 612 -500 375 -640 426 -574 640 -479 640 -640 491 -427 640 -640 480 -500 333 -640 622 -640 427 -512 640 -640 480 -640 425 -480 640 -640 425 -640 466 -500 375 -640 427 -640 437 -640 480 -375 500 -425 640 -640 480 -640 594 -478 640 -375 500 -640 480 -640 425 -640 424 -427 640 -640 400 -640 480 -480 640 -500 452 -640 480 -427 640 -612 612 -427 640 -333 500 -640 427 -425 640 -640 480 -640 425 -640 427 -500 407 -640 429 -640 480 -500 375 -640 480 -640 427 -500 375 -381 640 -640 483 -427 640 -427 640 -640 419 -640 519 -640 427 -640 401 -612 612 -640 279 -640 480 -640 399 -500 375 -640 458 -640 481 -640 427 -349 614 -640 480 -481 640 -428 640 -640 480 -480 640 -480 640 -459 640 -640 427 -640 478 -640 427 -640 426 -640 425 -640 360 -640 480 -428 640 -480 640 -640 480 -640 426 -640 478 -640 427 -640 480 -640 453 -427 640 -640 640 -640 426 -428 640 -640 444 -640 480 -640 427 -640 480 -640 321 -640 360 -640 480 -640 359 -480 640 -640 480 -404 640 -640 429 -640 480 -500 375 -640 430 -640 480 -640 417 -640 480 -640 448 -469 640 -640 480 -425 640 -333 500 -640 481 -640 480 -640 427 -640 423 -428 640 -640 430 -640 464 -640 427 -640 480 -640 535 -424 640 -640 512 -640 480 -640 427 -500 375 -640 480 -500 375 -640 480 -640 449 -640 480 -500 375 -640 427 -640 427 -427 640 -640 480 -640 426 -640 436 -640 413 -465 640 -640 480 -640 426 -425 640 -640 428 -428 640 -640 359 -640 398 -640 480 -640 480 -640 497 -640 426 -640 328 -500 375 -482 640 -480 640 -339 500 -501 640 -640 427 -640 433 -640 428 -640 480 -500 335 -640 428 -640 344 -640 480 -500 375 -640 427 -640 426 -480 640 -640 425 -640 427 -640 427 -640 359 -640 480 -473 640 -481 640 -576 640 -640 640 -600 464 -640 424 -640 427 -640 426 -640 480 -481 640 -500 461 -640 278 -480 640 -500 345 -640 427 -640 480 -612 612 -640 345 -480 640 -427 640 -640 480 -640 480 -640 480 -640 427 -640 426 -640 383 -410 500 -500 375 -640 480 -640 640 -333 500 -640 480 -640 427 -640 480 -640 640 -640 425 -640 427 -480 640 -640 427 -500 374 -612 612 -333 500 -640 569 -640 427 -640 430 -640 428 -500 375 -640 480 -375 500 -640 427 -640 480 -480 640 -640 427 -640 480 -640 490 -278 500 -640 480 -542 640 -640 480 -640 480 -333 500 -640 427 -640 427 -640 470 -640 400 -640 419 -480 640 -640 426 -500 375 -640 480 -640 480 -427 640 -640 426 -640 480 -512 640 -640 480 -424 640 -640 341 -640 480 -640 360 -480 640 -640 480 -640 427 -375 500 -640 427 -426 640 -640 427 -480 640 -640 427 -500 357 -427 640 -640 426 -640 444 -480 640 -640 426 -640 478 -640 480 -640 365 -640 517 -480 640 -640 480 -640 426 -333 500 -640 427 -640 480 -463 640 -640 480 -640 427 -640 429 -640 378 -424 640 -640 480 -427 640 -640 453 -640 480 -426 640 -640 427 -640 428 -640 424 -640 480 -427 640 -640 480 -640 480 -500 375 -640 427 -640 480 -640 468 -442 640 -640 480 -480 640 -600 400 -640 427 -640 480 -640 480 -640 427 -640 427 -640 451 -640 426 -640 426 -640 449 -427 640 -640 511 -391 640 -640 496 -500 375 -640 480 -640 480 -640 427 -640 640 -500 381 -640 425 -640 427 -640 480 -640 480 -640 480 -480 640 -500 142 -640 480 -426 640 -457 640 -618 640 -640 480 -424 640 -640 348 -640 360 -640 480 -429 640 -640 480 -429 640 -480 640 -640 424 -640 428 -640 480 -512 640 -640 428 -640 480 -640 427 -478 640 -640 471 -640 429 -640 640 -640 427 -500 375 -640 359 -640 425 -640 480 -640 444 -640 425 -640 480 -640 398 -640 640 -640 426 -640 480 -640 427 -500 333 -640 425 -640 424 -500 375 -640 506 -500 333 -640 425 -480 640 -640 428 -480 640 -640 425 -640 427 -375 500 -640 620 -640 480 -640 446 -640 427 -640 456 -422 640 -461 640 -425 640 -640 480 -427 640 -640 214 -612 612 -640 360 -480 640 -500 333 -640 480 -640 470 -640 427 -640 427 -612 612 -640 480 -640 480 -640 480 -640 480 -640 480 -640 427 -640 480 -640 480 -640 425 -640 480 -612 612 -426 640 -640 480 -375 500 -497 640 -397 640 -640 480 -357 500 -640 480 -480 640 -640 427 -640 480 -640 433 -500 375 -640 480 -640 427 -640 482 -640 427 -640 427 -640 480 -500 333 -640 419 -640 558 -640 478 -640 426 -640 449 -640 480 -500 375 -333 500 -640 384 -500 332 -480 640 -640 425 -640 426 -640 398 -640 430 -640 369 -640 427 -432 640 -640 480 -640 360 -500 375 -640 426 -640 427 -500 291 -640 640 -640 426 -500 375 -640 426 -500 375 -640 424 -640 640 -640 480 -640 427 -640 480 -640 427 -456 640 -640 480 -480 640 -640 387 -640 491 -640 478 -640 426 -640 427 -640 508 -640 564 -428 640 -640 480 -640 480 -500 401 -425 640 -640 360 -640 427 -640 573 -480 640 -640 480 -640 427 -640 360 -480 640 -640 427 -500 375 -640 480 -640 480 -640 426 -640 480 -612 612 -640 480 -343 640 -640 427 -640 423 -640 358 -640 423 -546 640 -640 480 -640 428 -640 427 -640 373 -640 427 -425 640 -640 562 -612 612 -500 333 -432 640 -640 408 -640 426 -640 480 -500 333 -611 425 -427 640 -640 640 -500 332 -500 375 -640 425 -640 478 -640 427 -640 480 -640 480 -360 640 -640 303 -640 480 -640 427 -640 361 -447 400 -428 500 -640 427 -500 252 -640 480 -640 427 -640 640 -500 375 -640 440 -427 640 -452 640 -640 480 -640 480 -480 640 -640 614 -640 427 -500 375 -640 480 -640 480 -640 400 -640 480 -500 330 -640 480 -427 640 -640 600 -640 426 -640 479 -640 553 -500 375 -512 640 -640 427 -427 640 -500 400 -640 426 -500 333 -424 640 -393 500 -640 427 -640 400 -640 480 -640 480 -353 500 -640 425 -640 294 -500 334 -640 490 -640 424 -500 375 -512 640 -500 383 -375 500 -412 640 -640 424 -500 378 -640 480 -640 427 -500 333 -640 440 -500 347 -480 640 -640 480 -640 426 -426 640 -640 480 -640 426 -640 360 -640 427 -640 480 -640 480 -640 457 -480 640 -640 427 -640 428 -640 426 -640 425 -640 427 -375 500 -640 348 -640 427 -640 427 -427 640 -428 640 -640 363 -640 427 -640 360 -428 640 -640 504 -426 640 -640 427 -333 500 -640 426 -640 427 -640 426 -640 480 -500 437 -220 186 -640 480 -640 640 -640 480 -640 406 -480 640 -500 357 -640 480 -640 424 -373 640 -464 640 -640 478 -427 640 -640 480 -612 612 -640 429 -640 480 -640 426 -640 480 -500 400 -500 335 -640 427 -360 640 -426 640 -480 640 -480 640 -429 640 -640 427 -380 324 -462 640 -480 640 -480 640 -640 426 -640 427 -640 480 -640 426 -640 424 -640 490 -640 499 -640 480 -640 427 -457 640 -500 329 -640 480 -480 640 -640 385 -640 480 -640 241 -640 480 -480 640 -640 426 -640 479 -333 500 -640 640 -500 323 -500 340 -640 412 -640 426 -640 426 -640 481 -640 424 -640 480 -640 437 -640 425 -512 640 -640 480 -640 426 -640 408 -640 376 -640 480 -640 480 -640 427 -425 640 -640 478 -640 426 -427 640 -375 500 -500 375 -640 480 -480 640 -640 427 -375 500 -500 334 -640 427 -640 382 -640 425 -640 480 -640 480 -640 480 -640 458 -640 427 -640 480 -427 640 -640 640 -640 480 -640 480 -426 640 -640 427 -505 640 -640 480 -640 360 -428 640 -640 426 -640 427 -480 640 -640 425 -640 479 -640 480 -640 513 -426 640 -427 640 -239 360 -480 640 -640 363 -500 428 -640 427 -640 491 -640 512 -640 426 -500 286 -640 427 -612 612 -640 384 -513 640 -500 375 -427 640 -640 426 -428 640 -640 480 -640 424 -640 428 -640 429 -640 360 -640 426 -457 640 -640 480 -333 500 -343 500 -480 640 -640 307 -640 480 -640 371 -375 500 -640 427 -640 427 -640 427 -640 428 -500 307 -303 640 -640 426 -500 333 -640 426 -640 427 -640 593 -480 640 -640 360 -640 480 -640 427 -426 640 -640 480 -500 375 -500 375 -480 640 -640 480 -640 364 -640 480 -375 500 -640 480 -640 427 -640 427 -640 427 -374 500 -457 640 -500 333 -375 500 -640 426 -640 480 -640 425 -640 428 -640 428 -427 640 -640 460 -373 640 -428 640 -427 640 -640 480 -427 640 -640 360 -640 433 -640 480 -640 426 -640 427 -640 480 -640 428 -640 426 -640 480 -557 640 -640 424 -568 640 -640 480 -640 480 -375 500 -640 425 -480 640 -640 480 -640 480 -440 470 -640 360 -500 375 -428 640 -640 427 -640 480 -640 427 -480 640 -390 640 -640 480 -640 427 -640 478 -426 640 -640 480 -458 640 -427 640 -427 640 -479 640 -375 500 -640 427 -425 640 -640 428 -427 640 -640 480 -640 483 -640 480 -640 383 -640 480 -480 640 -640 425 -426 640 -443 640 -640 429 -426 640 -640 480 -640 480 -640 480 -640 427 -480 640 -640 480 -640 640 -640 480 -436 640 -640 480 -500 333 -640 480 -640 426 -640 429 -500 375 -640 426 -429 640 -640 434 -640 491 -640 426 -480 640 -500 375 -640 480 -375 500 -640 428 -640 480 -480 640 -640 476 -640 427 -640 425 -500 375 -612 612 -500 167 -640 480 -640 426 -640 584 -640 480 -480 640 -464 640 -640 480 -480 640 -395 640 -640 582 -500 375 -640 480 -427 640 -640 480 -640 480 -640 480 -500 342 -640 427 -640 480 -500 282 -417 500 -500 375 -443 640 -480 640 -640 475 -640 640 -640 427 -427 640 -480 640 -640 427 -500 375 -429 640 -640 480 -640 480 -640 427 -640 480 -640 480 -640 480 -640 480 -640 427 -640 480 -640 424 -640 480 -640 427 -640 427 -640 480 -640 512 -425 640 -640 401 -640 428 -640 428 -640 480 -640 427 -640 423 -612 612 -500 333 -640 421 -640 427 -640 480 -640 480 -500 375 -640 478 -640 480 -427 640 -640 427 -640 478 -478 640 -640 427 -640 427 -428 640 -612 612 -640 426 -640 433 -480 640 -640 480 -360 640 -375 500 -612 612 -640 414 -640 360 -426 640 -521 640 -640 479 -640 427 -427 640 -640 408 -640 480 -640 480 -640 427 -640 428 -640 360 -640 446 -640 480 -640 400 -640 427 -640 480 -640 458 -640 424 -640 427 -426 640 -500 358 -640 426 -640 425 -500 375 -640 427 -640 414 -640 426 -427 640 -640 502 -640 480 -500 500 -640 231 -640 427 -640 480 -640 523 -427 640 -426 640 -640 480 -640 427 -640 427 -480 640 -640 413 -640 480 -640 427 -640 428 -500 333 -480 640 -640 426 -640 480 -480 640 -361 640 -375 500 -640 426 -640 480 -427 640 -480 640 -425 640 -480 640 -375 500 -640 480 -500 197 -500 375 -640 457 -640 424 -640 480 -640 425 -640 361 -640 480 -640 421 -497 640 -612 612 -640 429 -480 640 -640 480 -640 480 -640 480 -640 480 -640 247 -640 480 -427 640 -640 421 -640 427 -427 640 -612 612 -640 427 -400 500 -500 333 -640 480 -640 427 -640 480 -640 427 -500 375 -480 640 -640 427 -640 427 -360 640 -500 375 -640 480 -640 480 -640 427 -640 480 -640 512 -640 426 -640 425 -640 359 -640 425 -640 425 -640 480 -480 640 -640 480 -426 640 -640 426 -640 432 -640 455 -640 425 -640 640 -640 426 -640 440 -480 640 -640 425 -509 640 -640 480 -640 480 -640 480 -640 426 -640 427 -640 480 -640 424 -500 331 -427 640 -480 640 -426 640 -640 360 -640 153 -612 612 -640 361 -604 640 -640 452 -640 411 -478 640 -640 480 -612 612 -500 400 -640 480 -640 480 -640 427 -640 480 -640 427 -480 640 -426 640 -640 427 -640 427 -612 612 -500 469 -640 428 -640 480 -640 426 -640 480 -640 480 -640 448 -640 425 -640 480 -375 500 -640 426 -612 612 -438 640 -383 640 -480 640 -640 478 -599 363 -612 612 -480 640 -640 424 -640 427 -640 480 -640 360 -500 400 -640 401 -640 480 -640 473 -640 427 -640 480 -640 427 -640 480 -640 428 -640 480 -640 480 -640 480 -640 480 -640 427 -480 640 -640 427 -640 480 -640 427 -640 320 -640 434 -500 375 -500 375 -640 427 -480 640 -500 375 -640 427 -640 425 -640 426 -640 480 -640 427 -640 480 -640 424 -425 640 -640 480 -640 427 -640 539 -640 480 -640 429 -640 480 -640 483 -640 426 -640 480 -640 428 -383 640 -500 374 -640 480 -640 281 -640 425 -640 427 -640 480 -640 428 -640 427 -500 375 -640 426 -640 413 -427 640 -500 448 -640 426 -499 640 -640 426 -480 640 -640 426 -640 428 -640 361 -427 640 -500 333 -480 640 -640 160 -640 503 -640 480 -640 427 -640 361 -640 480 -500 475 -481 640 -640 480 -431 640 -640 427 -500 375 -640 427 -427 640 -640 480 -640 427 -640 480 -427 640 -480 640 -500 375 -640 396 -640 480 -428 640 -640 427 -452 640 -612 612 -500 332 -427 640 -640 427 -640 480 -488 640 -640 427 -640 426 -535 640 -640 480 -480 640 -640 426 -640 576 -640 360 -626 640 -500 375 -427 640 -427 640 -640 480 -640 480 -640 426 -640 480 -480 640 -640 480 -426 640 -480 640 -640 322 -640 427 -375 500 -640 425 -480 640 -500 242 -427 640 -428 640 -334 500 -640 461 -640 480 -640 480 -640 428 -640 480 -640 586 -468 640 -640 427 -640 480 -640 480 -640 549 -480 640 -640 427 -480 640 -612 612 -640 480 -640 427 -640 427 -640 551 -480 640 -640 480 -640 480 -640 427 -375 500 -640 427 -640 360 -480 640 -478 640 -500 332 -640 480 -427 640 -428 640 -481 640 -612 612 -375 500 -640 480 -500 375 -640 480 -512 640 -640 427 -640 425 -422 640 -500 375 -480 640 -640 424 -640 427 -480 640 -640 480 -640 480 -427 640 -640 480 -480 640 -612 612 -640 480 -640 427 -427 640 -500 375 -640 468 -640 426 -427 640 -427 640 -640 427 -427 640 -480 640 -640 480 -640 480 -480 640 -640 480 -640 497 -640 426 -640 640 -640 480 -640 480 -640 425 -375 500 -640 427 -500 375 -500 333 -640 508 -640 480 -500 400 -640 427 -640 480 -480 640 -640 427 -480 640 -640 480 -383 640 -640 439 -640 480 -640 427 -640 480 -500 338 -375 500 -640 640 -640 480 -640 426 -480 640 -367 640 -626 640 -480 640 -640 426 -336 640 -640 376 -480 640 -640 559 -500 400 -640 427 -640 427 -640 426 -640 425 -640 480 -640 480 -640 429 -477 640 -640 480 -640 438 -375 500 -640 480 -500 333 -612 612 -640 360 -480 640 -640 480 -493 640 -640 427 -640 363 -640 481 -480 640 -375 500 -640 429 -478 640 -640 480 -640 427 -640 372 -640 427 -640 427 -480 640 -640 427 -459 640 -500 335 -640 428 -640 480 -640 639 -640 432 -500 375 -500 333 -500 333 -500 400 -640 426 -640 480 -640 640 -640 478 -640 480 -640 426 -640 360 -640 480 -640 426 -640 428 -640 480 -640 536 -500 604 -640 480 -480 640 -500 375 -500 375 -500 332 -640 339 -612 612 -640 480 -640 480 -640 458 -427 640 -480 640 -640 424 -640 426 -480 640 -435 500 -428 640 -640 480 -500 345 -425 640 -640 480 -427 640 -429 640 -612 612 -640 427 -480 640 -612 612 -610 411 -640 427 -640 381 -333 500 -480 640 -640 393 -640 427 -640 522 -640 562 -640 480 -500 375 -640 427 -612 612 -375 500 -640 426 -425 640 -480 640 -612 612 -424 640 -640 512 -500 375 -427 640 -426 640 -612 612 -640 480 -640 480 -280 500 -500 333 -640 480 -640 427 -640 427 -640 548 -640 480 -640 428 -640 442 -640 628 -640 431 -640 427 -483 640 -640 480 -500 280 -640 480 -480 640 -457 640 -640 480 -640 480 -640 400 -500 375 -420 640 -640 428 -640 424 -500 332 -500 289 -428 640 -432 640 -640 480 -640 404 -640 480 -380 500 -500 375 -640 427 -640 520 -640 480 -640 480 -640 423 -500 333 -640 480 -640 427 -640 476 -640 426 -500 333 -640 424 -640 480 -500 375 -480 640 -640 426 -375 500 -457 640 -640 432 -640 480 -640 488 -640 508 -640 312 -640 368 -640 426 -640 379 -640 426 -640 426 -500 333 -640 480 -640 478 -640 639 -640 425 -640 478 -427 640 -640 480 -640 506 -640 480 -500 335 -640 425 -500 379 -640 427 -500 375 -476 640 -640 426 -500 375 -640 427 -500 335 -426 640 -640 627 -640 480 -640 480 -640 480 -640 425 -640 480 -428 640 -360 640 -640 480 -640 428 -500 375 -640 427 -640 480 -640 493 -640 480 -427 640 -640 426 -500 254 -590 443 -640 480 -360 640 -640 480 -640 408 -640 480 -480 640 -640 480 -425 640 -640 449 -425 640 -640 640 -640 480 -635 640 -640 427 -640 360 -640 480 -640 383 -640 480 -375 500 -640 427 -640 427 -640 427 -640 426 -640 360 -640 424 -640 427 -640 640 -480 640 -640 480 -640 428 -640 427 -640 480 -640 480 -640 480 -640 427 -480 640 -640 512 -640 294 -640 428 -480 640 -640 640 -640 424 -640 426 -640 426 -640 480 -640 480 -640 480 -640 480 -640 451 -551 640 -612 612 -427 640 -500 375 -640 426 -640 426 -640 426 -493 500 -428 640 -640 480 -640 427 -480 640 -640 480 -480 640 -640 480 -480 640 -640 427 -640 480 -640 426 -640 428 -640 480 -640 480 -640 360 -640 480 -640 428 -640 427 -640 480 -640 428 -640 424 -480 640 -640 425 -640 425 -640 480 -640 478 -640 480 -640 480 -640 480 -612 612 -480 640 -640 398 -500 375 -427 640 -480 640 -640 548 -640 426 -640 504 -480 640 -640 427 -640 478 -427 640 -640 427 -640 429 -500 333 -286 427 -612 612 -500 375 -563 640 -454 289 -429 640 -640 427 -427 640 -640 640 -500 375 -426 640 -500 281 -640 387 -640 428 -640 427 -640 426 -480 640 -480 640 -640 480 -640 425 -640 425 -640 480 -429 640 -640 426 -528 640 -640 428 -640 426 -500 335 -640 512 -500 375 -640 480 -640 428 -640 230 -640 428 -640 457 -333 500 -500 321 -640 480 -640 427 -640 480 -612 612 -480 640 -640 481 -640 427 -480 640 -640 427 -640 481 -488 500 -640 427 -640 403 -640 433 -640 480 -640 427 -480 640 -640 427 -426 640 -640 480 -640 480 -210 126 -640 480 -640 410 -428 640 -375 500 -500 335 -375 500 -640 480 -500 375 -640 427 -640 480 -500 333 -640 427 -480 640 -429 640 -640 480 -480 640 -480 329 -500 333 -500 375 -640 480 -360 480 -640 416 -640 480 -480 640 -640 400 -461 640 -500 333 -640 396 -424 640 -500 375 -640 425 -612 612 -640 427 -640 448 -640 241 -640 426 -500 350 -640 427 -427 640 -640 424 -500 375 -640 492 -640 425 -640 434 -640 425 -216 301 -640 428 -640 480 -500 371 -500 333 -640 428 -481 640 -480 640 -640 480 -640 322 -640 427 -640 478 -427 640 -640 427 -640 480 -439 640 -640 427 -640 480 -480 640 -640 426 -500 333 -640 427 -640 429 -640 427 -640 480 -500 375 -640 427 -640 497 -480 640 -640 463 -480 640 -356 500 -500 375 -640 428 -480 640 -500 289 -640 427 -640 480 -640 436 -427 640 -640 480 -640 640 -640 418 -480 640 -640 426 -375 500 -640 480 -640 427 -640 427 -480 640 -640 480 -640 320 -480 640 -640 426 -640 428 -640 480 -640 426 -640 426 -640 457 -640 427 -640 427 -640 457 -480 640 -448 298 -640 480 -640 426 -640 483 -640 480 -458 640 -640 480 -333 500 -640 403 -640 480 -640 427 -640 360 -640 569 -360 640 -612 612 -640 480 -640 478 -640 424 -640 427 -640 427 -640 359 -640 480 -640 548 -612 612 -375 500 -333 500 -640 429 -640 480 -640 480 -480 640 -428 640 -640 426 -640 399 -640 480 -640 427 -517 388 -640 429 -640 427 -640 480 -640 424 -640 426 -640 425 -480 640 -640 480 -640 360 -640 427 -640 425 -425 640 -640 480 -640 414 -480 640 -640 480 -640 480 -640 427 -640 480 -612 612 -612 612 -500 375 -426 640 -640 426 -640 480 -640 394 -640 427 -612 612 -426 640 -640 428 -640 480 -375 500 -640 480 -640 352 -500 332 -640 480 -443 640 -640 427 -640 424 -446 640 -640 368 -640 640 -480 640 -531 640 -640 480 -478 640 -640 426 -640 427 -640 480 -333 500 -500 391 -612 612 -640 428 -457 640 -640 427 -500 375 -640 428 -500 500 -640 480 -640 427 -640 457 -426 640 -640 480 -640 427 -640 480 -480 640 -480 640 -640 588 -640 480 -612 612 -427 640 -640 425 -640 480 -500 375 -640 514 -640 480 -480 640 -640 427 -640 427 -640 360 -640 479 -500 329 -640 516 -640 424 -640 480 -640 604 -480 640 -640 480 -480 640 -640 427 -500 375 -500 333 -323 500 -640 480 -640 480 -640 427 -640 428 -640 258 -640 480 -640 480 -640 480 -640 472 -640 426 -640 426 -500 375 -640 425 -480 640 -494 640 -640 426 -640 480 -500 375 -388 640 -640 480 -640 480 -640 427 -640 427 -427 640 -512 640 -640 427 -365 500 -494 640 -640 259 -640 427 -640 400 -640 480 -425 640 -612 612 -640 480 -640 427 -640 480 -640 427 -480 640 -640 427 -640 480 -640 400 -640 640 -640 428 -640 480 -640 428 -640 480 -640 491 -426 640 -640 427 -640 480 -480 640 -640 427 -640 480 -640 427 -480 640 -427 640 -427 640 -640 427 -500 375 -640 480 -480 640 -481 640 -640 359 -640 480 -612 612 -640 427 -640 480 -500 333 -640 427 -428 640 -640 361 -640 402 -640 427 -500 375 -427 640 -640 427 -640 428 -640 480 -640 396 -500 375 -640 417 -640 411 -640 426 -640 427 -640 480 -500 375 -640 427 -640 427 -427 640 -640 427 -640 480 -427 640 -427 640 -640 480 -640 424 -640 338 -640 480 -480 640 -640 428 -640 480 -640 426 -640 426 -500 475 -640 427 -640 468 -640 427 -480 640 -640 480 -640 424 -640 427 -516 387 -426 640 -628 406 -640 427 -478 640 -640 364 -500 333 -480 640 -640 427 -640 358 -640 359 -519 640 -429 640 -640 457 -640 457 -640 427 -375 500 -640 418 -640 427 -640 394 -427 640 -500 375 -640 425 -561 640 -480 640 -640 348 -640 428 -500 363 -640 427 -513 640 -640 424 -500 281 -640 360 -427 640 -640 360 -640 480 -640 426 -500 500 -640 428 -640 498 -640 342 -640 483 -480 640 -640 480 -640 427 -612 612 -612 612 -612 612 -640 480 -640 640 -640 480 -640 425 -480 640 -640 424 -640 480 -480 640 -640 480 -640 425 -500 333 -640 425 -500 380 -640 480 -426 640 -640 426 -640 413 -640 427 -480 640 -449 640 -640 427 -588 640 -640 480 -640 431 -640 426 -640 480 -427 640 -500 362 -640 480 -500 375 -500 345 -427 640 -640 462 -640 428 -640 427 -640 514 -640 480 -640 426 -640 480 -495 500 -427 640 -640 480 -640 427 -314 640 -640 426 -376 500 -480 640 -640 426 -428 640 -480 640 -640 419 -325 500 -640 427 -640 427 -640 480 -352 640 -500 375 -375 500 -500 332 -640 480 -640 533 -500 335 -640 604 -500 375 -480 640 -640 477 -640 426 -500 375 -640 427 -426 640 -640 481 -640 427 -640 425 -640 480 -612 612 -640 427 -640 480 -512 640 -458 640 -429 640 -640 429 -640 427 -640 478 -640 427 -500 246 -640 480 -640 327 -640 427 -640 425 -640 427 -612 612 -640 252 -640 480 -640 480 -640 427 -640 198 -640 491 -640 480 -640 480 -640 480 -640 480 -640 428 -480 640 -640 434 -640 427 -427 640 -640 427 -500 373 -640 457 -640 360 -640 426 -427 640 -635 640 -612 612 -640 480 -640 426 -640 427 -500 333 -500 375 -450 337 -640 427 -640 368 -640 427 -640 480 -640 424 -640 480 -640 567 -500 375 -600 604 -613 640 -640 427 -640 427 -640 471 -640 480 -478 640 -587 640 -640 427 -538 640 -612 612 -640 480 -375 500 -458 640 -427 640 -640 398 -500 375 -640 256 -640 425 -480 640 -640 311 -640 427 -500 279 -640 480 -612 612 -364 500 -375 500 -500 375 -640 480 -640 480 -640 428 -640 640 -456 640 -399 640 -612 612 -640 480 -500 330 -480 640 -640 396 -640 480 -427 640 -640 456 -640 426 -612 612 -500 375 -500 357 -640 480 -450 298 -500 397 -640 480 -640 427 -640 427 -640 480 -640 480 -640 480 -640 621 -500 375 -640 480 -500 331 -640 414 -640 480 -640 359 -640 480 -633 640 -640 480 -640 480 -640 428 -640 396 -480 640 -500 375 -494 500 -640 480 -640 510 -640 520 -640 480 -640 425 -640 427 -426 640 -387 500 -640 480 -640 424 -640 480 -500 332 -640 480 -640 421 -640 425 -640 424 -640 427 -640 480 -640 428 -640 427 -640 480 -640 424 -640 426 -640 360 -640 480 -640 480 -640 427 -640 425 -640 479 -500 334 -491 640 -480 640 -640 480 -640 473 -500 465 -375 500 -640 427 -640 427 -640 426 -640 480 -640 480 -500 329 -640 424 -500 487 -480 640 -640 480 -500 375 -640 480 -559 640 -640 463 -640 425 -428 640 -640 427 -500 382 -640 480 -640 523 -640 541 -640 480 -371 640 -640 426 -640 418 -640 401 -480 640 -425 640 -640 559 -500 490 -640 480 -428 640 -640 427 -640 427 -640 640 -640 427 -640 360 -480 640 -640 427 -341 500 -640 480 -426 640 -333 500 -640 480 -640 427 -480 640 -640 441 -640 426 -640 427 -640 480 -334 500 -640 424 -640 449 -640 419 -640 425 -640 427 -366 500 -322 500 -480 640 -448 640 -500 429 -640 425 -640 480 -640 480 -427 640 -478 640 -640 331 -480 640 -375 500 -640 480 -640 529 -640 426 -640 480 -640 480 -375 500 -425 640 -640 427 -640 480 -461 640 -640 428 -640 479 -640 427 -424 640 -640 427 -640 480 -500 359 -480 640 -640 427 -640 427 -480 640 -640 480 -640 458 -640 394 -640 425 -612 612 -500 375 -640 640 -480 640 -427 640 -640 408 -612 612 -640 427 -480 640 -640 426 -640 480 -640 593 -558 640 -640 481 -640 480 -640 426 -640 424 -640 480 -640 480 -500 375 -640 480 -500 424 -176 144 -640 427 -640 480 -640 480 -640 480 -640 426 -640 480 -480 640 -333 240 -427 640 -640 426 -640 480 -640 476 -640 480 -640 426 -640 427 -621 640 -640 480 -640 480 -640 426 -640 427 -640 480 -500 333 -375 500 -480 640 -640 480 -640 427 -640 427 -500 500 -640 423 -640 425 -640 480 -640 480 -640 427 -640 427 -640 425 -612 612 -640 426 -640 480 -640 425 -640 427 -640 640 -640 480 -500 375 -640 426 -500 271 -480 640 -500 375 -640 482 -640 427 -480 640 -640 427 -640 427 -640 480 -640 414 -640 427 -640 398 -640 480 -640 433 -640 426 -640 427 -480 360 -640 427 -640 480 -640 480 -480 640 -640 464 -612 612 -480 640 -640 480 -640 426 -640 480 -640 480 -640 480 -640 482 -500 386 -640 480 -500 377 -640 480 -640 427 -640 480 -640 480 -480 640 -424 640 -640 480 -640 427 -500 333 -640 424 -480 640 -500 333 -640 480 -640 400 -427 640 -640 427 -500 335 -640 416 -428 640 -640 427 -640 427 -500 333 -640 228 -640 426 -500 337 -480 640 -640 480 -640 424 -480 640 -500 409 -640 640 -640 640 -478 640 -411 500 -640 426 -640 427 -640 471 -640 480 -640 426 -640 403 -640 427 -640 428 -640 480 -640 480 -443 640 -640 548 -640 480 -640 480 -640 480 -480 640 -640 427 -480 640 -480 640 -640 298 -640 480 -480 640 -640 429 -640 458 -640 480 -640 427 -480 640 -640 480 -640 488 -499 640 -375 500 -640 480 -640 476 -640 427 -640 480 -640 456 -640 480 -500 375 -640 640 -500 375 -640 480 -357 500 -640 522 -480 640 -332 500 -480 640 -640 480 -640 427 -500 375 -426 640 -640 426 -640 427 -640 480 -500 375 -480 640 -640 428 -640 480 -480 640 -480 640 -640 428 -640 480 -500 379 -640 480 -427 640 -500 344 -640 424 -640 640 -427 640 -640 427 -500 375 -640 354 -426 640 -640 480 -640 427 -640 427 -640 480 -640 480 -640 480 -480 640 -375 500 -599 640 -640 440 -640 640 -427 640 -640 441 -448 336 -500 375 -500 375 -640 480 -500 332 -640 480 -640 457 -336 448 -500 281 -480 640 -640 480 -427 640 -640 433 -396 640 -500 500 -480 640 -640 480 -640 480 -640 425 -480 640 -640 425 -640 427 -500 375 -640 480 -640 360 -480 640 -500 375 -512 640 -640 418 -500 431 -500 332 -640 400 -640 458 -640 425 -500 333 -640 360 -480 640 -640 394 -640 360 -500 375 -640 480 -640 359 -640 426 -640 425 -500 333 -640 512 -640 428 -427 640 -640 480 -480 640 -640 480 -494 640 -427 640 -480 640 -640 479 -640 427 -640 640 -640 427 -640 480 -480 640 -640 427 -640 480 -640 428 -426 640 -640 424 -640 480 -640 427 -640 426 -640 425 -640 360 -640 427 -640 480 -640 478 -640 425 -480 640 -426 640 -640 434 -500 375 -640 427 -427 640 -640 387 -640 424 -480 640 -494 640 -640 399 -640 465 -501 640 -640 480 -640 427 -594 640 -500 375 -640 414 -640 480 -640 479 -640 360 -640 480 -480 640 -480 640 -375 500 -480 640 -640 361 -424 640 -640 425 -640 424 -640 427 -640 427 -640 480 -380 500 -640 428 -640 480 -640 480 -640 479 -640 361 -640 480 -640 480 -640 415 -429 640 -640 427 -640 480 -500 375 -640 424 -500 373 -500 375 -431 640 -480 640 -428 640 -640 416 -640 424 -640 420 -640 424 -457 640 -480 640 -640 476 -500 319 -640 427 -640 480 -640 480 -640 480 -424 640 -640 427 -640 586 -640 480 -640 413 -375 500 -640 427 -640 424 -500 375 -640 480 -640 480 -428 640 -375 500 -288 432 -640 479 -640 427 -640 479 -640 464 -640 401 -480 640 -640 480 -427 640 -640 424 -640 451 -628 640 -640 425 -640 426 -500 375 -500 333 -482 640 -479 640 -427 640 -640 480 -640 427 -640 428 -640 427 -500 375 -640 480 -640 427 -500 375 -640 480 -640 480 -640 419 -428 640 -500 375 -640 640 -640 499 -640 427 -640 426 -640 408 -640 427 -640 425 -640 640 -640 427 -640 425 -404 500 -640 425 -640 425 -480 640 -640 480 -640 427 -640 480 -640 640 -640 480 -500 375 -640 618 -519 640 -480 640 -480 640 -640 480 -500 332 -426 640 -333 500 -640 480 -640 427 -640 480 -640 480 -500 311 -640 480 -640 480 -640 427 -640 480 -640 426 -640 480 -484 640 -480 640 -640 384 -424 640 -427 640 -640 480 -640 433 -640 575 -640 640 -640 419 -500 376 -640 427 -640 480 -333 500 -640 480 -640 427 -480 640 -480 640 -500 326 -640 480 -640 480 -640 453 -462 640 -640 353 -640 424 -640 424 -640 480 -640 427 -640 360 -640 368 -640 480 -640 427 -640 480 -640 427 -640 427 -640 434 -640 428 -640 427 -427 640 -500 400 -427 640 -640 431 -400 239 -640 426 -640 427 -480 640 -640 557 -480 640 -640 480 -640 424 -427 640 -640 427 -425 640 -640 360 -640 358 -640 480 -640 480 -640 425 -500 333 -524 640 -375 500 -640 427 -500 333 -640 440 -640 533 -640 427 -640 480 -640 426 -633 640 -640 502 -640 480 -640 428 -640 359 -640 425 -640 480 -640 480 -480 640 -640 480 -640 480 -640 520 -640 480 -480 640 -640 426 -640 480 -478 640 -640 414 -640 480 -478 640 -640 480 -640 488 -480 640 -375 500 -640 424 -640 427 -640 480 -640 480 -427 640 -427 640 -640 480 -427 640 -512 640 -640 480 -424 640 -500 252 -640 427 -640 425 -428 640 -640 427 -427 640 -425 640 -375 500 -640 480 -640 428 -640 640 -640 480 -480 640 -500 337 -640 427 -640 480 -640 383 -640 427 -500 375 -500 333 -640 480 -500 375 -494 640 -640 480 -640 512 -640 425 -500 375 -500 332 -640 427 -640 480 -612 612 -640 640 -640 480 -640 427 -640 427 -480 640 -640 480 -640 427 -500 375 -640 480 -640 480 -640 480 -640 427 -480 640 -333 500 -640 480 -640 480 -428 640 -640 427 -640 427 -480 640 -640 461 -500 375 -640 480 -640 363 -640 427 -640 574 -640 426 -640 480 -375 500 -640 480 -640 360 -640 395 -600 402 -640 480 -640 360 -500 500 -640 428 -640 425 -640 480 -640 480 -640 480 -480 640 -640 426 -640 480 -640 482 -640 361 -640 480 -480 640 -640 434 -640 425 -480 640 -640 427 -640 425 -640 428 -500 375 -640 425 -500 332 -640 480 -500 375 -640 431 -640 425 -640 427 -640 480 -640 485 -640 480 -512 640 -480 640 -500 375 -640 427 -640 425 -462 640 -640 425 -500 334 -640 480 -375 500 -549 640 -640 351 -500 375 -640 480 -480 319 -640 360 -640 427 -480 640 -640 480 -640 427 -640 426 -640 427 -640 439 -640 329 -640 480 -640 426 -500 500 -427 640 -640 480 -640 480 -640 480 -640 428 -640 424 -640 480 -480 640 -640 426 -640 480 -640 427 -368 640 -640 456 -640 480 -427 640 -640 480 -640 458 -640 427 -480 640 -429 640 -640 435 -640 480 -640 428 -640 425 -640 403 -640 514 -640 424 -640 512 -500 375 -640 512 -640 462 -640 427 -480 640 -640 480 -640 426 -640 504 -429 640 -426 640 -612 612 -500 333 -640 426 -640 422 -640 269 -640 427 -640 480 -640 425 -640 400 -427 640 -640 426 -640 480 -640 478 -480 640 -640 480 -640 486 -640 427 -458 640 -640 425 -640 503 -332 500 -426 640 -432 305 -480 640 -640 480 -640 480 -640 428 -375 500 -500 333 -426 640 -500 376 -640 428 -500 213 -640 479 -640 429 -598 640 -640 373 -473 640 -640 480 -640 640 -612 612 -640 480 -640 480 -640 480 -640 427 -640 427 -402 640 -640 480 -640 425 -640 427 -640 378 -640 428 -640 427 -640 361 -500 333 -640 427 -640 427 -480 640 -427 640 -640 426 -480 640 -640 450 -612 612 -640 553 -640 480 -640 425 -640 439 -640 428 -640 428 -640 430 -500 352 -640 418 -479 640 -640 427 -640 639 -640 480 -640 427 -640 427 -640 480 -612 612 -640 480 -427 640 -427 640 -640 316 -640 428 -500 375 -640 480 -640 424 -640 427 -500 333 -428 640 -500 334 -640 480 -500 375 -640 426 -500 331 -640 480 -640 458 -640 478 -612 612 -640 480 -427 640 -427 640 -640 426 -427 640 -612 612 -477 640 -640 428 -640 427 -640 427 -640 427 -640 448 -640 427 -640 427 -512 640 -640 426 -640 480 -640 493 -640 427 -640 427 -500 333 -640 283 -640 360 -640 457 -303 500 -500 333 -640 513 -500 375 -640 425 -640 304 -612 612 -640 480 -640 424 -500 375 -333 500 -640 480 -640 426 -480 640 -500 375 -500 381 -640 480 -640 480 -640 570 -500 375 -640 427 -480 640 -640 480 -640 480 -640 480 -640 480 -640 427 -500 375 -640 427 -640 426 -640 480 -480 640 -480 640 -640 411 -640 426 -640 427 -640 480 -480 640 -640 427 -500 291 -350 500 -640 360 -467 640 -429 640 -640 441 -427 640 -500 216 -640 480 -480 640 -640 480 -640 467 -640 480 -480 640 -311 640 -640 480 -640 427 -640 480 -640 480 -500 334 -640 427 -640 426 -640 458 -480 640 -640 479 -640 424 -513 640 -640 480 -640 360 -640 480 -318 480 -640 427 -612 612 -640 425 -640 400 -640 427 -640 480 -480 640 -500 331 -357 500 -640 480 -480 640 -640 480 -640 443 -640 480 -640 426 -640 480 -500 367 -640 433 -480 640 -640 480 -640 427 -640 427 -500 333 -640 479 -640 480 -640 428 -425 640 -640 367 -375 500 -500 366 -480 640 -640 480 -640 481 -480 640 -640 427 -427 640 -427 640 -640 510 -640 481 -375 500 -640 480 -359 640 -640 264 -640 426 -480 640 -640 480 -640 458 -500 416 -640 429 -640 426 -640 480 -640 425 -640 480 -640 480 -640 480 -640 383 -160 144 -640 427 -640 425 -640 428 -427 640 -640 480 -640 426 -640 427 -500 333 -333 500 -640 427 -425 640 -640 461 -640 428 -640 427 -640 321 -640 405 -427 640 -375 500 -640 480 -640 427 -640 426 -640 480 -640 427 -480 640 -640 432 -640 427 -640 361 -640 428 -640 480 -640 528 -480 640 -640 424 -640 426 -640 320 -640 336 -640 429 -427 640 -640 425 -500 375 -500 332 -640 427 -500 375 -640 427 -640 426 -640 305 -640 427 -500 375 -640 480 -301 500 -640 480 -640 416 -500 334 -640 480 -640 480 -640 425 -640 480 -425 640 -640 426 -378 500 -640 434 -375 500 -640 480 -640 480 -640 427 -640 478 -640 573 -481 640 -640 480 -427 640 -640 427 -460 500 -640 480 -640 480 -428 640 -640 478 -640 480 -640 480 -640 401 -500 500 -500 375 -640 424 -500 333 -640 426 -500 500 -640 379 -457 640 -640 466 -640 480 -500 333 -640 427 -427 640 -640 478 -640 426 -640 640 -640 426 -640 425 -640 427 -426 640 -525 640 -640 271 -612 612 -480 640 -640 480 -640 480 -640 360 -640 427 -640 480 -640 480 -375 500 -640 480 -640 480 -640 480 -640 434 -480 640 -640 427 -640 359 -500 375 -640 480 -640 480 -640 480 -640 480 -500 375 -640 480 -640 480 -427 640 -480 640 -640 396 -383 640 -220 222 -640 427 -480 640 -640 480 -640 326 -640 521 -640 427 -640 480 -640 426 -640 478 -640 480 -640 427 -640 427 -640 533 -360 640 -640 480 -640 480 -640 443 -500 375 -640 306 -480 640 -500 332 -640 426 -640 479 -640 488 -640 427 -480 640 -640 400 -640 400 -640 480 -640 640 -427 640 -640 427 -640 480 -425 640 -640 480 -640 425 -640 427 -440 640 -640 427 -640 425 -640 640 -640 425 -640 480 -640 426 -513 640 -640 427 -640 581 -640 360 -640 480 -640 427 -425 640 -500 332 -640 480 -640 480 -640 428 -640 426 -640 480 -640 556 -640 428 -640 480 -640 427 -640 480 -427 640 -426 640 -640 463 -640 433 -424 640 -640 427 -640 480 -500 333 -640 426 -500 344 -640 480 -640 427 -640 427 -640 427 -333 500 -640 480 -640 427 -640 480 -640 414 -375 500 -444 640 -500 333 -640 253 -640 462 -427 640 -640 480 -640 480 -427 640 -640 480 -500 350 -640 427 -640 427 -640 510 -478 640 -640 503 -640 480 -640 360 -640 424 -612 612 -376 640 -480 640 -640 427 -500 375 -425 640 -500 333 -333 500 -640 480 -640 480 -500 375 -640 480 -640 427 -640 480 -500 324 -427 640 -624 640 -640 480 -640 428 -640 480 -500 358 -640 418 -640 427 -640 427 -640 427 -612 612 -640 427 -640 427 -490 640 -428 640 -600 600 -640 424 -640 506 -480 640 -480 640 -640 478 -640 478 -640 386 -640 425 -478 640 -640 427 -640 480 -640 480 -375 500 -640 480 -427 640 -640 427 -640 427 -640 426 -640 427 -640 480 -500 375 -427 640 -640 426 -640 480 -427 640 -640 427 -640 437 -427 640 -640 480 -374 500 -500 375 -640 428 -640 480 -480 640 -640 640 -424 640 -500 238 -640 426 -500 375 -640 427 -640 480 -640 425 -500 500 -542 640 -640 480 -500 333 -433 640 -480 640 -500 280 -640 427 -500 330 -427 640 -640 426 -640 427 -481 640 -640 426 -640 409 -640 480 -640 428 -640 425 -427 640 -425 640 -640 480 -480 640 -640 383 -640 480 -427 640 -640 480 -480 640 -640 426 -575 434 -640 424 -640 427 -480 640 -478 640 -640 480 -640 360 -604 640 -640 361 -426 640 -640 427 -427 640 -640 480 -480 640 -375 500 -640 361 -446 640 -427 640 -640 426 -473 640 -426 640 -480 640 -640 451 -640 418 -640 427 -500 322 -640 480 -417 640 -640 427 -640 425 -500 374 -640 466 -640 480 -640 372 -640 471 -640 480 -480 640 -640 453 -640 344 -640 427 -640 603 -500 375 -640 480 -640 640 -480 640 -640 427 -640 480 -640 383 -640 480 -500 333 -640 480 -480 640 -438 640 -640 480 -640 480 -612 612 -375 500 -640 484 -500 314 -640 468 -428 640 -640 482 -640 429 -500 500 -480 640 -640 480 -640 424 -640 480 -640 426 -640 480 -640 424 -640 424 -640 427 -640 427 -429 640 -640 425 -427 640 -640 427 -640 478 -640 640 -500 375 -640 427 -480 640 -640 338 -640 427 -640 427 -640 480 -640 480 -640 427 -640 428 -640 493 -421 640 -640 427 -426 640 -640 513 -640 360 -640 480 -640 480 -640 480 -426 640 -512 640 -640 512 -640 426 -640 480 -426 640 -640 428 -640 427 -480 640 -640 464 -640 480 -640 478 -640 480 -640 480 -612 612 -640 640 -500 375 -500 375 -640 480 -640 461 -640 501 -338 450 -640 427 -640 425 -640 379 -640 427 -640 428 -640 384 -640 480 -640 427 -639 640 -640 427 -428 640 -640 482 -500 333 -640 427 -640 361 -629 640 -500 333 -640 427 -500 375 -480 640 -427 640 -640 521 -413 640 -640 428 -480 640 -640 480 -475 640 -640 426 -500 331 -640 373 -640 438 -427 640 -640 429 -640 480 -640 480 -500 493 -640 427 -640 478 -341 595 -480 640 -500 375 -640 480 -500 500 -480 640 -640 480 -640 480 -428 640 -640 426 -640 480 -640 478 -640 427 -480 640 -375 500 -480 640 -640 480 -640 480 -640 480 -481 640 -640 373 -640 480 -640 480 -612 612 -640 480 -500 426 -640 424 -500 407 -480 640 -640 426 -640 480 -640 475 -640 439 -640 480 -640 418 -640 481 -640 426 -640 480 -334 500 -640 384 -500 375 -423 640 -512 640 -500 334 -640 417 -612 612 -640 480 -640 432 -640 427 -640 386 -428 640 -640 480 -640 480 -640 480 -640 478 -640 480 -640 480 -640 426 -640 426 -480 640 -500 332 -640 427 -640 480 -427 640 -640 429 -612 612 -423 640 -640 360 -640 480 -640 480 -480 640 -640 425 -640 428 -480 640 -640 426 -640 480 -640 480 -640 480 -640 480 -500 375 -640 480 -334 500 -395 640 -640 480 -640 480 -500 375 -640 480 -500 375 -640 480 -640 480 -640 480 -640 483 -640 480 -640 480 -428 640 -450 391 -424 640 -478 640 -640 480 -500 375 -426 640 -640 464 -640 429 -640 427 -640 433 -640 427 -500 375 -640 480 -480 640 -427 640 -640 604 -640 474 -640 640 -640 427 -640 480 -640 427 -640 427 -480 640 -640 427 -427 640 -640 480 -640 480 -480 640 -640 360 -640 640 -640 480 -640 427 -640 428 -640 427 -640 424 -640 361 -640 480 -640 480 -640 434 -612 612 -500 375 -640 426 -640 427 -640 480 -640 427 -640 360 -640 640 -500 375 -640 427 -640 480 -640 480 -640 481 -640 427 -640 474 -640 427 -640 471 -480 640 -612 612 -640 427 -500 333 -640 426 -640 428 -480 640 -640 480 -565 640 -640 427 -480 640 -640 424 -640 481 -428 640 -640 480 -640 427 -640 480 -640 400 -640 480 -425 640 -640 480 -640 480 -333 500 -640 427 -640 480 -612 612 -640 427 -480 640 -640 480 -640 480 -434 640 -640 480 -640 414 -640 480 -640 480 -480 640 -500 359 -396 640 -480 640 -579 640 -640 480 -423 640 -640 640 -640 361 -640 428 -640 478 -640 480 -397 640 -640 341 -480 640 -640 427 -640 480 -640 480 -480 640 -640 480 -500 375 -640 426 -640 480 -500 332 -640 480 -640 480 -640 431 -640 427 -640 480 -640 427 -640 428 -516 640 -640 426 -640 484 -640 360 -480 640 -640 426 -640 457 -361 640 -640 461 -601 640 -640 509 -640 427 -640 426 -425 640 -640 480 -612 612 -640 427 -640 426 -640 480 -640 526 -427 640 -640 426 -600 600 -640 427 -640 480 -640 425 -423 640 -640 480 -500 375 -529 640 -459 640 -333 500 -640 480 -640 320 -640 429 -640 351 -433 640 -500 375 -640 480 -640 480 -640 480 -640 427 -500 375 -640 480 -640 480 -640 427 -640 480 -640 480 -640 640 -426 640 -427 640 -640 480 -640 480 -640 347 -640 428 -640 360 -427 640 -640 427 -640 480 -424 640 -640 480 -640 640 -612 612 -480 640 -640 480 -428 640 -640 480 -426 640 -640 430 -640 427 -439 640 -500 375 -640 425 -489 640 -640 427 -500 333 -640 480 -640 428 -640 427 -640 512 -640 351 -640 424 -500 328 -640 427 -640 427 -500 334 -640 480 -640 480 -640 405 -500 397 -640 427 -640 403 -640 428 -640 422 -640 480 -640 396 -426 640 -640 499 -640 476 -640 427 -640 439 -599 348 -640 638 -640 386 -640 480 -640 427 -428 640 -426 640 -640 480 -640 449 -640 427 -640 480 -612 612 -640 425 -640 427 -640 480 -640 503 -427 640 -640 426 -612 612 -640 426 -497 640 -612 612 -640 359 -640 428 -426 640 -640 427 -640 480 -500 316 -500 375 -640 425 -640 480 -333 500 -640 480 -640 480 -640 480 -640 426 -427 640 -640 474 -640 480 -542 640 -640 480 -640 427 -640 426 -457 640 -640 488 -480 640 -427 640 -640 433 -640 512 -640 481 -640 427 -480 640 -640 427 -640 478 -480 640 -500 334 -640 464 -612 612 -640 480 -640 480 -427 640 -640 469 -640 478 -640 427 -640 480 -640 480 -480 640 -480 640 -640 336 -640 426 -640 424 -640 475 -640 480 -427 640 -640 423 -428 640 -640 428 -640 427 -640 427 -640 480 -640 480 -640 396 -640 427 -500 333 -640 427 -640 480 -640 427 -640 360 -612 612 -480 640 -640 448 -423 640 -640 564 -640 480 -640 348 -480 640 -493 640 -426 640 -612 612 -500 375 -640 408 -640 539 -640 427 -640 360 -500 375 -640 480 -333 500 -640 480 -400 500 -640 480 -640 480 -640 438 -640 428 -640 434 -640 427 -640 400 -640 480 -375 500 -640 359 -640 640 -640 427 -640 425 -640 359 -640 480 -640 512 -640 483 -640 427 -640 480 -640 480 -640 480 -640 635 -427 640 -640 424 -640 640 -480 640 -426 640 -640 480 -640 427 -640 426 -471 640 -640 480 -480 640 -640 427 -640 433 -640 360 -500 375 -640 574 -612 612 -640 480 -640 522 -640 523 -480 640 -640 427 -640 480 -640 426 -480 640 -640 426 -425 640 -640 480 -640 424 -480 640 -640 640 -640 480 -640 480 -640 429 -507 640 -640 480 -640 480 -426 640 -500 415 -640 480 -640 480 -480 640 -640 449 -640 480 -640 427 -427 640 -480 640 -640 417 -612 612 -500 375 -375 500 -640 396 -500 343 -640 388 -428 640 -480 640 -480 640 -640 287 -480 640 -426 640 -640 427 -640 395 -480 640 -480 640 -481 640 -640 480 -640 480 -640 448 -640 427 -640 480 -500 354 -640 331 -384 512 -640 458 -640 408 -640 480 -640 429 -640 480 -640 526 -640 424 -640 480 -640 499 -640 640 -640 454 -640 427 -640 480 -500 334 -640 271 -640 424 -640 424 -368 640 -478 640 -640 630 -427 640 -640 427 -333 500 -640 424 -640 480 -640 426 -512 640 -640 480 -640 339 -640 395 -640 387 -640 428 -424 640 -640 480 -640 568 -640 425 -500 375 -640 480 -500 375 -640 480 -500 375 -640 480 -640 370 -480 640 -425 640 -640 427 -640 508 -640 278 -640 480 -375 500 -500 375 -640 480 -426 640 -640 480 -640 425 -480 640 -640 426 -640 358 -640 480 -510 640 -361 640 -640 427 -640 480 -640 427 -500 375 -426 640 -640 480 -640 421 -640 473 -640 480 -640 453 -640 431 -640 427 -640 427 -426 640 -576 285 -640 480 -427 640 -640 425 -640 427 -640 640 -640 427 -640 427 -640 359 -640 421 -640 425 -476 640 -640 480 -500 288 -356 500 -640 415 -640 480 -640 426 -640 480 -640 421 -640 522 -640 413 -612 612 -612 612 -640 480 -480 640 -427 640 -640 480 -427 640 -640 478 -640 400 -640 480 -640 480 -640 436 -640 480 -640 587 -500 333 -640 350 -640 480 -640 424 -640 426 -640 438 -428 640 -640 480 -640 425 -640 474 -640 480 -403 640 -500 325 -500 375 -500 375 -640 480 -427 640 -464 640 -640 480 -640 423 -480 640 -640 428 -339 500 -640 480 -500 375 -640 360 -500 333 -640 480 -640 427 -424 640 -640 480 -640 363 -640 459 -640 428 -640 427 -480 640 -640 361 -640 480 -640 418 -640 480 -640 427 -640 427 -375 500 -640 427 -640 480 -640 427 -500 306 -640 427 -640 480 -640 400 -640 427 -640 426 -640 425 -381 500 -500 375 -640 480 -640 480 -640 360 -500 332 -612 612 -640 424 -640 426 -640 480 -448 640 -640 362 -640 415 -500 375 -640 427 -484 640 -640 480 -500 375 -640 427 -493 640 -640 426 -640 429 -640 480 -402 640 -640 480 -640 480 -375 500 -640 426 -640 480 -640 442 -480 640 -640 480 -640 427 -480 640 -640 480 -500 378 -640 424 -640 480 -640 480 -640 480 -640 480 -640 426 -640 480 -640 361 -640 426 -640 359 -640 510 -640 427 -640 461 -640 427 -640 427 -480 640 -332 500 -288 432 -500 375 -640 478 -500 375 -500 375 -612 612 -640 427 -640 427 -426 640 -640 480 -480 640 -640 480 -333 500 -640 424 -480 640 -640 538 -640 420 -500 375 -640 427 -408 306 -480 640 -640 451 -640 480 -640 480 -640 426 -640 383 -640 429 -480 640 -640 480 -640 427 -640 429 -640 341 -383 640 -640 478 -640 480 -500 375 -640 314 -640 480 -640 430 -612 612 -640 427 -640 480 -333 500 -640 429 -640 640 -616 640 -640 480 -478 640 -375 500 -480 640 -500 375 -480 640 -427 640 -640 424 -427 640 -640 425 -640 427 -640 360 -427 640 -480 640 -640 404 -500 352 -640 360 -640 427 -500 399 -640 400 -640 480 -640 426 -640 426 -640 428 -640 480 -480 640 -640 429 -640 480 -640 480 -640 427 -640 480 -640 425 -640 480 -640 428 -523 640 -640 480 -500 375 -640 480 -640 640 -640 420 -640 423 -640 590 -640 427 -640 425 -640 327 -480 640 -640 428 -500 335 -640 425 -480 640 -400 640 -640 427 -640 480 -427 640 -640 426 -640 481 -640 426 -640 427 -500 375 -640 480 -640 427 -428 640 -615 615 -426 640 -480 640 -640 495 -640 480 -480 640 -640 439 -640 480 -640 480 -640 478 -480 388 -640 427 -640 359 -500 375 -640 480 -457 640 -480 640 -377 500 -600 314 -640 478 -640 480 -427 640 -480 640 -640 427 -640 454 -480 640 -640 480 -640 427 -640 414 -500 320 -640 480 -478 640 -640 480 -640 480 -640 640 -389 640 -640 480 -640 480 -640 501 -640 424 -640 480 -640 480 -640 323 -640 408 -640 480 -640 480 -640 425 -640 309 -640 427 -640 480 -640 480 -333 500 -359 640 -640 427 -640 427 -640 427 -640 424 -640 427 -640 480 -640 427 -640 427 -640 426 -640 480 -640 427 -640 427 -640 427 -640 480 -640 426 -431 640 -335 500 -427 640 -640 640 -640 391 -640 480 -640 480 -640 427 -640 427 -640 480 -640 427 -500 333 -640 502 -640 426 -640 427 -426 640 -640 480 -640 480 -640 480 -640 427 -394 640 -478 640 -623 640 -640 480 -640 427 -375 500 -427 640 -375 500 -640 512 -427 640 -480 640 -425 640 -480 640 -640 596 -640 545 -640 480 -640 480 -427 640 -480 640 -640 480 -640 522 -640 480 -375 500 -316 640 -500 396 -415 640 -640 503 -640 480 -640 360 -640 428 -640 426 -300 225 -427 640 -640 400 -500 334 -480 640 -640 480 -640 432 -500 375 -640 480 -500 332 -397 640 -612 612 -428 640 -454 640 -500 399 -640 480 -640 480 -640 279 -640 425 -500 375 -427 640 -640 425 -480 640 -383 640 -640 427 -500 375 -640 426 -640 480 -640 480 -640 480 -640 370 -500 333 -640 512 -640 480 -375 500 -640 480 -640 425 -640 427 -640 480 -500 335 -640 427 -640 480 -640 480 -500 375 -539 640 -640 480 -424 500 -640 427 -640 359 -640 427 -640 424 -640 426 -640 205 -640 424 -480 640 -640 480 -500 332 -640 480 -500 375 -640 427 -640 425 -640 445 -370 500 -640 480 -500 402 -640 427 -640 429 -612 612 -426 640 -500 373 -640 464 -640 480 -427 640 -640 480 -640 426 -640 479 -500 375 -640 426 -640 428 -640 480 -640 428 -640 427 -497 640 -640 480 -480 640 -640 426 -640 480 -425 640 -640 427 -426 640 -640 480 -640 480 -640 480 -640 480 -640 484 -427 640 -640 427 -640 427 -640 584 -612 612 -640 458 -640 427 -428 640 -500 375 -640 480 -427 640 -640 401 -619 640 -640 480 -640 512 -640 480 -424 640 -426 640 -640 478 -640 425 -640 347 -640 480 -640 359 -480 640 -640 428 -640 425 -375 500 -640 480 -640 424 -640 502 -375 500 -640 335 -415 500 -500 375 -640 424 -640 427 -640 480 -500 500 -500 375 -640 427 -640 427 -427 640 -640 480 -640 364 -640 640 -500 322 -480 640 -480 640 -427 640 -500 375 -375 500 -640 480 -640 490 -640 360 -640 480 -640 427 -500 376 -640 480 -373 500 -640 426 -640 480 -640 480 -500 375 -640 398 -640 480 -640 424 -640 480 -640 480 -427 640 -360 640 -640 480 -640 427 -640 480 -640 480 -612 612 -640 449 -426 640 -640 480 -480 640 -640 408 -480 640 -500 375 -640 383 -375 500 -640 425 -480 640 -428 640 -640 427 -500 330 -640 421 -640 427 -581 640 -640 426 -426 640 -640 427 -640 427 -640 388 -640 425 -640 428 -640 640 -640 427 -640 480 -640 480 -427 640 -640 428 -640 427 -640 480 -480 640 -414 640 -640 480 -480 640 -640 480 -640 427 -480 640 -428 640 -427 640 -640 449 -640 426 -640 480 -640 429 -640 467 -640 480 -640 480 -427 640 -640 427 -500 375 -640 478 -640 480 -640 385 -640 359 -360 640 -640 572 -640 480 -640 480 -427 640 -640 425 -640 466 -640 427 -640 640 -640 379 -500 315 -640 422 -640 480 -427 640 -640 424 -640 477 -640 480 -640 446 -375 500 -640 448 -640 360 -480 640 -640 478 -480 640 -640 480 -640 503 -500 375 -640 430 -613 635 -640 424 -640 427 -640 640 -640 427 -640 427 -427 640 -478 640 -409 640 -480 640 -640 480 -640 478 -458 640 -640 478 -640 480 -480 640 -640 423 -640 480 -480 640 -640 480 -640 360 -640 425 -640 360 -640 427 -427 640 -640 512 -640 480 -640 270 -640 360 -359 640 -500 375 -640 427 -500 375 -427 640 -480 640 -640 344 -640 480 -640 480 -640 640 -640 480 -640 640 -640 480 -640 360 -640 428 -640 427 -640 480 -640 427 -360 640 -640 426 -640 468 -640 402 -640 426 -640 425 -640 480 -640 480 -640 424 -640 425 -640 480 -640 579 -640 427 -640 480 -640 480 -640 427 -640 427 -640 480 -640 427 -640 480 -375 500 -640 426 -640 480 -640 480 -640 427 -291 500 -640 426 -640 480 -428 640 -640 426 -640 480 -427 640 -640 480 -480 640 -640 480 -480 640 -640 531 -640 480 -526 640 -640 427 -640 458 -480 640 -640 251 -480 640 -426 640 -640 427 -640 571 -640 427 -640 482 -640 480 -640 480 -427 640 -640 427 -640 571 -640 480 -640 427 -427 640 -640 417 -640 480 -640 480 -448 640 -640 427 -640 480 -631 640 -500 375 -640 425 -539 640 -609 640 -500 375 -478 640 -640 478 -500 375 -640 427 -427 640 -640 478 -640 438 -500 330 -640 426 -375 500 -375 500 -640 154 -480 640 -450 350 -640 480 -640 480 -640 426 -640 391 -640 425 -640 482 -640 480 -500 260 -434 500 -612 612 -500 334 -640 429 -480 640 -640 427 -500 375 -640 480 -640 480 -640 427 -640 480 -640 434 -500 335 -427 640 -640 410 -435 640 -500 375 -640 526 -640 400 -640 480 -640 480 -640 427 -640 411 -640 480 -480 640 -640 502 -640 480 -640 480 -500 375 -500 375 -357 500 -337 500 -640 480 -480 272 -640 478 -640 480 -640 480 -640 480 -428 640 -512 640 -640 428 -427 640 -640 427 -427 640 -640 427 -425 640 -640 428 -640 480 -544 640 -426 640 -640 427 -640 360 -500 375 -640 480 -480 249 -640 432 -640 424 -640 427 -640 480 -640 480 -640 426 -640 360 -640 480 -640 427 -640 427 -640 489 -366 500 -640 426 -640 427 -427 640 -640 426 -640 427 -640 425 -640 427 -500 332 -640 427 -640 480 -640 427 -240 360 -425 640 -640 480 -640 426 -640 427 -640 502 -640 480 -640 457 -640 480 -500 316 -480 640 -640 429 -640 480 -640 480 -640 480 -480 640 -640 461 -640 427 -640 512 -375 500 -429 640 -480 640 -640 414 -640 428 -427 640 -480 640 -518 640 -640 427 -640 480 -425 640 -640 427 -640 359 -640 480 -640 595 -640 480 -640 427 -640 480 -640 501 -500 375 -640 427 -640 415 -450 300 -640 480 -399 640 -640 269 -593 640 -640 480 -640 431 -640 428 -480 640 -480 640 -640 428 -640 426 -480 640 -636 640 -640 428 -426 640 -640 427 -640 427 -640 426 -640 360 -640 480 -500 332 -640 426 -640 427 -640 480 -500 375 -575 344 -640 426 -640 425 -612 612 -500 375 -640 480 -640 425 -640 480 -640 430 -425 640 -427 640 -429 640 -428 640 -640 480 -640 433 -426 640 -640 427 -640 640 -640 427 -640 480 -427 640 -500 375 -640 640 -640 427 -640 427 -640 480 -640 426 -640 479 -640 454 -480 640 -640 427 -640 480 -480 640 -640 480 -640 558 -640 478 -640 480 -480 640 -428 640 -375 500 -640 480 -500 375 -427 640 -424 640 -640 226 -640 480 -640 480 -640 427 -500 375 -480 640 -500 333 -640 427 -500 375 -612 612 -640 426 -426 640 -640 426 -640 360 -640 480 -640 427 -640 365 -500 375 -640 427 -640 427 -426 640 -640 480 -375 500 -640 480 -640 431 -640 480 -451 640 -640 480 -640 480 -640 480 -640 589 -640 425 -640 427 -575 640 -427 640 -640 427 -640 480 -480 640 -640 427 -640 478 -640 480 -640 426 -640 480 -640 429 -500 333 -427 640 -640 480 -426 640 -393 500 -640 426 -640 480 -640 428 -640 427 -500 374 -640 480 -640 393 -500 375 -640 480 -640 396 -640 480 -350 500 -640 497 -640 457 -640 360 -640 480 -640 480 -500 375 -640 480 -588 640 -640 480 -612 612 -640 480 -500 390 -640 503 -640 427 -640 425 -640 321 -640 427 -640 480 -640 360 -640 425 -640 435 -640 450 -640 428 -640 427 -375 500 -640 480 -640 427 -640 480 -500 443 -516 640 -640 427 -640 640 -640 480 -341 640 -640 499 -500 375 -640 640 -640 427 -640 402 -500 375 -428 640 -640 427 -426 640 -426 640 -500 333 -640 480 -640 409 -500 280 -640 427 -480 640 -640 427 -640 427 -640 412 -640 480 -640 480 -640 427 -640 428 -640 427 -427 640 -500 333 -500 338 -640 427 -640 480 -640 480 -640 478 -640 480 -640 480 -333 500 -427 640 -640 425 -640 439 -640 427 -640 480 -640 377 -640 480 -640 480 -640 480 -640 426 -640 429 -640 425 -640 480 -474 640 -640 426 -640 480 -640 425 -640 484 -640 480 -424 640 -500 375 -425 640 -480 640 -640 431 -640 427 -640 426 -640 480 -500 333 -610 390 -480 640 -640 428 -640 427 -640 428 -480 640 -640 480 -640 490 -511 640 -640 426 -500 375 -480 640 -640 640 -640 420 -427 640 -427 640 -640 480 -640 421 -640 480 -640 468 -500 333 -640 480 -640 424 -427 640 -640 424 -640 426 -640 428 -640 287 -480 640 -612 612 -640 480 -500 334 -449 640 -640 480 -640 428 -640 426 -640 433 -640 329 -604 453 -480 640 -640 427 -500 375 -640 360 -633 640 -500 332 -640 480 -640 478 -640 426 -640 425 -640 420 -640 634 -500 333 -375 500 -640 426 -640 507 -640 427 -640 480 -640 480 -640 427 -500 333 -640 526 -640 426 -480 640 -640 480 -640 426 -463 640 -640 427 -640 480 -640 491 -640 397 -640 493 -640 431 -480 640 -640 453 -414 640 -480 640 -640 480 -640 428 -375 500 -640 480 -640 428 -640 480 -640 457 -640 425 -640 426 -640 427 -640 441 -640 427 -640 426 -500 432 -640 427 -640 480 -500 375 -640 427 -411 640 -640 427 -640 480 -427 640 -544 640 -612 612 -426 640 -640 427 -640 434 -640 427 -640 444 -640 424 -640 481 -640 427 -500 375 -480 640 -500 376 -519 640 -640 425 -640 427 -464 640 -640 480 -612 612 -427 640 -480 640 -640 478 -640 480 -500 333 -640 480 -640 425 -640 480 -600 409 -640 480 -640 426 -640 480 -640 479 -640 500 -640 425 -640 426 -427 640 -640 480 -640 480 -424 640 -640 396 -640 427 -640 428 -640 480 -640 421 -426 640 -640 429 -480 640 -640 480 -640 480 -640 411 -427 640 -640 480 -640 478 -640 480 -640 424 -640 479 -426 640 -640 519 -640 480 -375 500 -640 480 -640 480 -640 426 -640 484 -500 374 -500 333 -463 500 -640 429 -640 427 -640 427 -640 427 -500 333 -640 427 -640 480 -480 640 -640 480 -612 612 -447 640 -640 480 -640 480 -427 640 -470 640 -640 478 -640 478 -640 480 -640 480 -640 480 -640 427 -640 554 -427 640 -509 640 -640 428 -640 426 -500 279 -640 480 -640 480 -478 640 -640 427 -640 480 -640 414 -640 480 -480 640 -640 479 -640 427 -612 612 -427 640 -640 427 -640 481 -640 427 -500 375 -375 500 -640 480 -640 480 -640 429 -640 359 -640 336 -640 427 -640 427 -640 426 -640 480 -480 319 -640 480 -640 480 -640 427 -480 640 -426 640 -500 333 -612 612 -640 360 -500 300 -550 640 -640 400 -640 360 -500 333 -427 640 -640 428 -593 640 -640 480 -640 444 -640 424 -640 488 -640 478 -480 640 -640 427 -640 426 -640 460 -640 511 -640 356 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -640 427 -640 480 -640 425 -600 400 -640 427 -374 500 -480 640 -640 427 -640 427 -640 475 -425 640 -640 480 -640 434 -640 640 -640 480 -640 319 -640 425 -640 303 -640 468 -612 612 -640 427 -640 427 -640 480 -514 640 -640 427 -500 375 -640 427 -640 480 -640 439 -640 427 -640 480 -640 429 -482 640 -478 640 -550 367 -640 480 -640 427 -640 427 -463 640 -640 480 -640 427 -640 427 -640 427 -640 478 -640 430 -640 427 -640 468 -640 480 -333 500 -640 427 -640 427 -640 425 -640 436 -640 427 -640 579 -640 513 -640 480 -640 480 -500 333 -480 640 -500 375 -375 500 -500 333 -640 426 -375 500 -640 480 -500 349 -640 427 -640 426 -640 480 -640 460 -612 612 -480 640 -612 612 -480 640 -640 424 -612 612 -640 406 -500 333 -480 640 -640 480 -640 427 -640 480 -640 394 -640 480 -640 451 -640 427 -640 426 -480 640 -640 400 -640 480 -640 426 -640 425 -428 640 -640 509 -640 480 -480 640 -480 640 -640 480 -640 427 -640 424 -640 400 -356 500 -480 640 -640 427 -640 426 -640 423 -640 360 -640 480 -640 431 -311 640 -640 478 -640 480 -640 480 -333 500 -640 480 -640 478 -640 478 -640 640 -427 640 -500 335 -480 640 -640 480 -640 480 -375 500 -640 425 -640 426 -640 426 -640 427 -640 427 -640 480 -640 480 -640 428 -640 480 -640 425 -640 480 -500 453 -640 427 -612 612 -375 500 -480 640 -480 640 -468 640 -640 480 -640 457 -428 640 -427 640 -640 480 -640 480 -640 427 -640 431 -640 480 -500 375 -500 332 -476 640 -640 481 -640 427 -640 480 -602 640 -640 480 -640 480 -481 640 -375 500 -640 427 -640 480 -610 640 -428 640 -640 425 -640 426 -640 480 -640 480 -612 612 -640 480 -640 290 -640 480 -640 426 -480 640 -640 424 -426 640 -640 480 -500 399 -640 480 -640 480 -423 640 -500 375 -640 424 -360 640 -640 480 -640 430 -500 375 -640 426 -640 424 -500 333 -640 427 -640 427 -640 396 -640 441 -480 640 -480 640 -640 407 -640 453 -640 480 -640 594 -427 640 -640 427 -640 478 -480 321 -640 480 -640 426 -612 612 -640 640 -640 389 -640 480 -640 511 -640 480 -640 480 -640 480 -480 640 -612 612 -640 360 -640 427 -640 427 -640 426 -640 427 -612 612 -501 640 -640 534 -358 500 -640 480 -640 493 -640 480 -640 427 -640 480 -427 640 -612 612 -640 429 -640 480 -478 640 -612 612 -640 484 -640 480 -640 427 -427 640 -428 640 -640 428 -640 480 -640 640 -455 640 -640 409 -640 480 -640 480 -500 332 -640 427 -400 500 -640 480 -640 426 -640 640 -500 369 -480 640 -640 424 -640 428 -480 640 -640 480 -427 640 -640 480 -640 480 -640 480 -640 427 -425 640 -640 495 -366 640 -640 427 -640 427 -640 427 -640 360 -640 429 -640 427 -640 427 -640 427 -640 480 -423 640 -640 480 -640 480 -640 422 -612 612 -640 480 -640 427 -640 484 -500 377 -640 449 -500 375 -500 333 -640 460 -427 640 -640 426 -640 432 -640 494 -640 426 -333 500 -640 427 -612 612 -640 480 -427 640 -640 360 -640 480 -500 314 -426 640 -640 480 -640 377 -640 480 -450 338 -640 428 -500 375 -640 426 -640 480 -640 510 -640 480 -640 480 -640 480 -640 479 -640 427 -640 480 -500 332 -640 512 -640 480 -640 426 -640 428 -640 480 -640 427 -640 576 -480 640 -640 480 -640 623 -640 480 -640 427 -500 274 -640 480 -426 640 -640 480 -640 480 -640 360 -640 360 -640 254 -427 640 -640 414 -640 423 -640 478 -640 438 -480 640 -640 480 -640 427 -640 480 -428 640 -480 640 -640 428 -428 640 -375 500 -500 338 -640 478 -640 473 -480 640 -640 425 -424 640 -500 500 -640 480 -640 480 -640 427 -480 640 -480 640 -640 425 -640 487 -500 375 -480 640 -640 427 -640 480 -640 480 -640 428 -480 640 -427 640 -640 480 -500 313 -640 427 -640 480 -640 427 -640 427 -426 640 -640 424 -375 500 -480 640 -640 480 -640 427 -500 334 -640 427 -640 427 -640 480 -612 612 -359 640 -640 480 -640 446 -640 427 -640 361 -640 427 -640 427 -612 612 -640 360 -480 640 -640 427 -640 480 -640 428 -640 427 -500 375 -640 426 -640 474 -612 612 -500 375 -640 480 -640 480 -500 375 -480 640 -640 396 -640 510 -640 426 -640 426 -500 333 -640 446 -480 640 -640 480 -640 426 -500 375 -640 480 -400 500 -500 332 -640 427 -612 612 -500 333 -640 431 -640 480 -500 375 -375 500 -430 640 -480 640 -640 480 -640 480 -500 459 -640 428 -443 640 -640 427 -480 640 -640 640 -427 640 -640 428 -640 425 -640 427 -640 427 -480 640 -640 360 -640 480 -457 640 -640 480 -500 375 -640 480 -427 640 -640 427 -640 480 -640 480 -480 640 -640 480 -640 427 -500 400 -640 427 -640 480 -640 425 -640 507 -640 382 -640 427 -640 426 -500 383 -640 347 -426 640 -640 426 -320 240 -640 426 -640 426 -640 421 -640 425 -375 500 -480 640 -640 426 -500 375 -500 333 -427 640 -458 640 -640 534 -375 500 -640 429 -640 480 -640 360 -640 480 -640 457 -500 333 -640 426 -640 427 -480 640 -640 426 -500 333 -640 376 -640 480 -640 480 -640 316 -640 440 -640 381 -640 427 -640 428 -640 480 -640 427 -609 640 -500 375 -640 426 -500 402 -640 427 -240 360 -640 480 -500 334 -640 425 -640 478 -640 638 -640 427 -500 375 -640 480 -640 425 -480 640 -640 425 -640 480 -612 612 -640 480 -640 427 -640 480 -640 480 -640 427 -640 427 -500 400 -480 640 -480 640 -640 314 -640 425 -640 427 -640 480 -500 332 -640 480 -640 427 -480 640 -640 425 -410 640 -640 427 -640 342 -640 480 -600 600 -640 427 -640 360 -640 640 -640 480 -500 336 -640 480 -640 425 -640 427 -640 428 -640 238 -640 427 -640 429 -480 640 -640 428 -640 453 -640 426 -640 428 -640 426 -640 424 -640 426 -640 403 -375 500 -478 640 -640 480 -640 480 -640 427 -640 480 -500 375 -500 400 -333 500 -500 281 -500 333 -427 640 -426 640 -480 640 -274 640 -640 480 -500 383 -640 427 -640 480 -640 383 -500 375 -500 333 -640 480 -640 433 -640 360 -500 333 -640 480 -640 427 -640 424 -500 375 -640 480 -427 640 -418 640 -640 480 -478 640 -640 553 -640 426 -640 424 -640 360 -640 480 -359 640 -427 640 -640 480 -480 640 -331 500 -427 640 -640 427 -640 480 -375 500 -500 375 -640 480 -500 375 -640 427 -640 424 -612 612 -500 332 -640 480 -640 426 -640 426 -500 345 -640 427 -640 425 -640 427 -375 500 -598 640 -640 480 -356 500 -640 480 -640 426 -640 478 -208 160 -500 481 -640 426 -640 426 -640 426 -640 480 -640 424 -480 640 -640 427 -500 294 -640 427 -640 427 -640 436 -640 402 -640 457 -640 480 -640 428 -640 428 -398 640 -426 640 -640 426 -428 640 -426 640 -500 333 -640 427 -640 480 -428 640 -480 640 -640 427 -640 427 -456 640 -501 640 -640 408 -640 480 -640 424 -640 480 -480 640 -640 480 -640 427 -480 640 -640 480 -500 408 -640 429 -480 640 -640 640 -612 612 -640 380 -640 426 -435 640 -640 503 -612 612 -640 480 -640 425 -640 480 -640 480 -640 480 -640 427 -640 426 -640 480 -443 500 -640 480 -640 480 -640 480 -480 640 -640 421 -640 640 -640 427 -640 426 -500 452 -500 333 -640 448 -640 480 -480 640 -640 427 -480 640 -640 480 -427 640 -478 640 -640 427 -640 422 -640 480 -640 424 -640 204 -640 480 -333 500 -480 640 -640 480 -640 425 -640 480 -640 437 -640 480 -462 640 -428 640 -640 480 -500 313 -500 476 -640 428 -640 489 -640 524 -640 426 -640 426 -500 375 -640 302 -640 510 -640 426 -640 360 -640 424 -640 432 -426 640 -488 640 -640 427 -640 376 -450 350 -640 480 -640 480 -500 319 -640 480 -640 359 -375 500 -640 480 -640 480 -640 427 -640 427 -333 500 -640 427 -640 406 -375 500 -427 640 -640 400 -565 584 -640 480 -640 640 -640 427 -335 500 -500 375 -640 448 -640 479 -640 480 -375 500 -640 494 -447 333 -640 457 -334 500 -640 640 -612 612 -640 528 -425 640 -500 375 -480 640 -640 480 -640 640 -640 424 -427 640 -480 640 -640 427 -640 639 -640 480 -640 480 -500 375 -480 640 -427 640 -640 428 -640 426 -640 427 -640 426 -640 424 -480 640 -640 480 -500 333 -383 640 -600 457 -640 216 -640 480 -500 375 -640 480 -640 427 -640 425 -640 480 -427 640 -640 427 -368 640 -640 480 -640 463 -640 425 -640 480 -640 426 -500 364 -640 427 -480 640 -640 483 -600 450 -636 640 -640 480 -640 640 -640 427 -480 640 -375 500 -640 480 -640 427 -640 439 -487 500 -640 425 -640 480 -640 480 -640 480 -640 480 -640 480 -640 356 -480 640 -640 480 -640 360 -640 427 -640 480 -500 333 -500 332 -640 427 -640 427 -640 480 -640 424 -480 640 -640 480 -640 427 -640 480 -640 427 -640 480 -480 640 -640 480 -640 480 -640 425 -433 640 -499 640 -640 480 -640 480 -640 480 -479 640 -640 427 -640 478 -640 429 -500 334 -640 480 -480 640 -640 480 -640 400 -640 427 -640 427 -480 640 -500 375 -640 357 -640 384 -480 640 -640 480 -612 612 -640 427 -640 360 -640 424 -480 640 -500 375 -375 500 -640 480 -480 640 -500 332 -640 640 -640 451 -640 427 -640 480 -640 480 -640 511 -500 357 -640 303 -480 640 -640 480 -500 375 -640 480 -640 390 -564 640 -424 640 -426 640 -640 423 -500 333 -480 640 -640 427 -359 640 -480 640 -640 411 -640 428 -500 375 -640 459 -640 480 -640 480 -640 480 -500 375 -640 427 -640 360 -480 640 -480 640 -640 480 -640 480 -640 427 -640 640 -612 612 -640 427 -425 640 -640 344 -640 427 -640 480 -480 640 -640 478 -640 480 -640 480 -640 429 -375 500 -640 431 -640 426 -480 640 -640 394 -640 427 -640 480 -640 480 -640 536 -640 426 -427 640 -500 404 -500 400 -500 375 -640 427 -640 478 -480 640 -640 479 -640 360 -640 480 -640 427 -612 612 -640 427 -500 375 -640 427 -640 420 -640 427 -640 480 -640 427 -640 425 -640 482 -494 289 -640 425 -640 640 -640 520 -427 640 -640 160 -640 470 -640 480 -640 480 -640 480 -500 375 -640 480 -500 375 -640 401 -500 375 -612 612 -640 360 -640 480 -640 480 -375 500 -640 434 -640 480 -640 480 -640 557 -640 640 -424 640 -427 640 -640 428 -640 411 -427 640 -480 640 -640 427 -640 480 -640 481 -640 480 -640 480 -640 426 -640 480 -640 526 -640 489 -500 375 -640 480 -640 480 -640 426 -640 480 -640 429 -612 612 -427 640 -640 444 -640 480 -640 480 -500 333 -640 396 -400 372 -640 480 -480 640 -640 480 -640 426 -640 480 -640 480 -640 360 -424 640 -427 640 -500 333 -426 640 -500 375 -640 406 -640 429 -640 427 -604 640 -424 640 -640 480 -500 375 -500 375 -640 546 -480 640 -640 406 -375 500 -640 427 -640 480 -640 425 -640 427 -500 375 -357 500 -640 480 -640 480 -640 425 -375 500 -500 400 -640 360 -640 480 -640 423 -640 423 -480 640 -640 480 -600 510 -434 640 -640 427 -640 435 -640 427 -640 480 -640 424 -640 427 -500 375 -640 480 -640 428 -640 427 -612 612 -640 480 -640 434 -640 480 -511 640 -640 427 -333 500 -640 413 -640 640 -640 360 -640 480 -640 427 -640 480 -640 480 -640 426 -640 480 -640 480 -640 425 -640 429 -240 160 -640 480 -612 612 -640 426 -640 360 -480 640 -640 480 -537 640 -640 480 -480 640 -640 426 -640 457 -640 427 -640 516 -640 427 -640 640 -640 480 -640 480 -640 427 -640 427 -640 453 -480 640 -640 428 -480 640 -640 363 -640 480 -541 640 -640 480 -612 612 -326 500 -500 400 -640 640 -640 480 -500 375 -640 427 -640 426 -500 375 -640 424 -375 500 -257 362 -480 640 -480 640 -640 480 -640 360 -640 480 -500 375 -640 420 -640 427 -640 298 -640 480 -640 401 -640 475 -640 427 -640 480 -640 426 -640 427 -610 640 -640 498 -480 640 -640 480 -408 640 -640 427 -500 500 -640 427 -640 480 -480 640 -640 640 -640 640 -500 375 -375 500 -640 480 -500 333 -640 480 -427 640 -640 411 -640 426 -640 426 -640 480 -640 480 -500 346 -640 427 -640 376 -640 360 -640 425 -480 640 -427 640 -500 438 -480 640 -640 426 -640 480 -640 292 -640 428 -640 480 -333 500 -500 462 -480 640 -640 451 -640 427 -468 640 -640 429 -640 480 -500 500 -640 480 -640 427 -427 640 -640 427 -640 427 -640 480 -640 480 -375 500 -640 480 -640 427 -640 340 -640 427 -480 640 -375 500 -500 423 -640 425 -640 554 -500 375 -480 640 -640 505 -640 199 -640 426 -640 427 -640 480 -640 480 -333 500 -640 411 -640 427 -640 480 -500 375 -640 424 -426 640 -480 640 -640 424 -640 480 -640 426 -640 320 -640 425 -500 333 -480 640 -640 480 -375 500 -640 480 -500 400 -343 640 -427 640 -640 480 -640 469 -640 480 -480 640 -640 339 -640 427 -640 427 -513 640 -640 394 -640 416 -640 234 -640 480 -640 427 -640 428 -640 426 -500 375 -500 334 -427 640 -640 480 -640 427 -640 480 -428 640 -500 333 -427 640 -492 500 -640 480 -423 640 -406 640 -640 480 -640 362 -480 640 -640 480 -640 426 -640 480 -640 444 -480 640 -513 342 -412 640 -427 640 -640 480 -640 359 -612 612 -640 480 -640 480 -480 360 -640 425 -640 480 -640 480 -640 598 -640 480 -480 640 -640 480 -640 426 -640 480 -500 374 -640 457 -640 426 -500 333 -500 377 -375 500 -500 375 -640 492 -640 311 -427 640 -640 427 -640 426 -633 640 -640 483 -640 386 -640 427 -640 453 -375 500 -640 320 -640 424 -640 427 -338 500 -640 427 -640 480 -640 480 -640 384 -640 480 -640 426 -375 500 -426 640 -640 480 -640 480 -640 427 -640 427 -640 428 -640 480 -640 426 -640 640 -640 426 -640 480 -640 480 -640 480 -500 345 -640 480 -640 341 -553 640 -480 640 -480 640 -320 240 -500 375 -500 375 -640 482 -640 427 -640 450 -640 480 -640 480 -478 640 -612 612 -640 425 -426 640 -623 640 -640 426 -640 480 -640 451 -640 336 -640 480 -427 640 -640 427 -640 480 -640 480 -640 427 -640 640 -640 512 -640 468 -640 480 -640 480 -640 480 -500 333 -480 640 -480 640 -425 640 -612 612 -640 480 -416 640 -640 457 -640 640 -427 640 -640 428 -480 640 -433 640 -640 425 -640 428 -640 428 -640 373 -500 375 -640 640 -606 640 -457 640 -640 480 -640 480 -640 480 -640 359 -640 512 -640 427 -480 640 -640 476 -640 360 -640 428 -480 640 -640 480 -640 503 -640 427 -640 427 -640 427 -640 488 -500 362 -640 482 -500 375 -640 581 -640 427 -612 612 -640 480 -621 640 -640 480 -640 427 -512 640 -640 425 -640 479 -480 640 -640 640 -640 427 -375 500 -640 480 -427 640 -426 640 -640 427 -640 480 -640 427 -640 424 -500 281 -640 260 -640 457 -480 640 -640 421 -640 480 -481 640 -500 375 -640 640 -428 640 -500 333 -640 427 -480 640 -640 426 -427 640 -500 375 -427 640 -432 288 -640 426 -640 480 -640 427 -375 500 -640 480 -640 425 -640 480 -640 453 -479 640 -640 479 -640 427 -640 352 -640 394 -480 640 -640 640 -640 480 -640 417 -640 494 -640 427 -640 479 -500 375 -640 480 -640 480 -640 426 -426 640 -640 427 -640 480 -640 424 -480 640 -479 640 -640 480 -640 629 -640 478 -640 480 -640 427 -640 430 -640 480 -640 480 -640 480 -640 427 -480 640 -640 480 -480 640 -427 640 -640 420 -640 425 -501 640 -546 640 -640 486 -640 480 -612 612 -640 235 -640 480 -640 429 -640 480 -428 640 -640 480 -640 480 -640 428 -612 612 -404 640 -640 480 -640 427 -640 408 -480 640 -427 640 -500 375 -537 427 -640 426 -360 480 -640 425 -640 480 -640 426 -640 428 -333 500 -334 500 -640 427 -360 480 -640 318 -480 640 -480 640 -640 429 -640 480 -500 243 -500 375 -480 640 -480 640 -640 480 -640 480 -640 456 -640 427 -480 500 -640 426 -640 480 -640 512 -479 640 -640 480 -640 482 -500 333 -640 429 -640 460 -640 428 -640 425 -640 640 -612 612 -640 480 -640 427 -640 427 -500 375 -640 480 -640 427 -427 640 -640 480 -640 480 -640 480 -640 427 -500 499 -640 505 -640 423 -640 480 -640 424 -640 482 -640 427 -640 480 -640 424 -640 427 -480 640 -640 480 -640 541 -480 640 -480 640 -375 500 -428 640 -427 640 -640 480 -500 376 -512 640 -375 500 -640 427 -210 168 -480 640 -640 481 -640 480 -640 427 -370 640 -640 390 -640 412 -640 480 -640 426 -640 425 -375 500 -500 375 -640 428 -640 640 -408 640 -640 427 -640 428 -640 480 -640 427 -500 375 -640 640 -640 427 -640 480 -640 480 -640 426 -499 500 -640 426 -500 332 -640 480 -640 427 -640 480 -640 360 -640 478 -341 500 -640 471 -640 480 -640 427 -615 346 -640 640 -640 480 -640 480 -640 358 -640 425 -640 480 -640 630 -640 427 -640 480 -640 427 -500 335 -531 640 -640 473 -640 427 -640 480 -500 375 -640 480 -640 480 -509 640 -640 431 -640 424 -640 480 -640 480 -640 480 -426 640 -500 375 -480 640 -500 327 -640 480 -500 375 -640 425 -427 640 -414 640 -639 480 -634 640 -612 612 -640 480 -640 480 -640 427 -640 480 -480 640 -640 423 -480 640 -640 426 -640 428 -640 480 -640 480 -640 459 -640 480 -427 640 -480 640 -640 427 -480 640 -640 427 -640 480 -640 480 -640 480 -640 640 -375 500 -640 480 -640 427 -640 480 -640 425 -612 612 -427 640 -483 640 -640 426 -640 419 -640 480 -428 640 -500 400 -640 480 -640 348 -427 640 -640 361 -426 640 -640 436 -333 500 -152 228 -612 612 -462 640 -640 478 -640 480 -640 480 -640 401 -640 427 -640 427 -640 427 -427 640 -640 640 -500 375 -407 640 -640 427 -343 336 -640 480 -500 352 -640 480 -640 428 -640 480 -640 427 -640 425 -354 640 -640 429 -333 500 -298 450 -640 420 -640 480 -427 640 -640 425 -640 427 -480 640 -480 640 -500 331 -500 334 -640 480 -375 500 -640 480 -640 428 -612 612 -640 640 -640 424 -640 480 -640 480 -421 640 -640 480 -390 640 -640 480 -439 640 -640 427 -427 640 -640 480 -500 247 -500 333 -480 640 -640 368 -640 428 -426 640 -480 640 -640 426 -640 403 -640 427 -640 427 -640 480 -640 428 -321 500 -500 333 -640 480 -640 480 -640 480 -413 640 -640 427 -640 427 -334 500 -467 640 -500 375 -480 640 -480 640 -433 640 -500 375 -480 640 -640 424 -640 480 -640 480 -640 480 -375 500 -640 480 -640 428 -640 480 -640 426 -386 640 -640 429 -375 500 -640 426 -640 426 -427 640 -640 480 -640 349 -640 480 -640 480 -640 424 -375 500 -640 374 -640 480 -334 500 -640 480 -640 451 -480 640 -640 430 -640 427 -500 375 -478 640 -520 373 -640 478 -640 427 -612 612 -640 441 -480 640 -640 427 -640 426 -480 640 -640 429 -480 640 -612 612 -640 480 -640 427 -640 426 -480 640 -640 525 -375 500 -640 480 -640 411 -640 428 -640 428 -640 427 -640 427 -535 640 -375 500 -640 427 -640 428 -640 426 -480 640 -640 480 -612 612 -484 500 -640 426 -640 425 -640 427 -500 371 -500 320 -640 427 -480 640 -640 480 -640 424 -640 480 -640 427 -640 301 -500 333 -640 424 -640 480 -427 640 -612 612 -332 500 -640 439 -500 415 -427 640 -640 513 -640 427 -640 426 -640 480 -324 640 -640 480 -640 480 -375 500 -640 427 -640 480 -640 480 -612 612 -640 543 -640 480 -480 640 -640 446 -640 480 -640 480 -473 640 -640 421 -640 427 -640 425 -640 427 -640 427 -640 465 -640 395 -640 446 -640 405 -640 425 -640 375 -640 425 -640 327 -640 480 -427 640 -640 480 -640 427 -500 375 -640 480 -640 480 -428 640 -640 426 -640 480 -640 427 -640 514 -500 335 -640 445 -640 360 -375 500 -640 480 -640 480 -640 480 -640 425 -432 640 -640 425 -640 512 -640 424 -640 427 -640 427 -640 480 -640 480 -640 427 -640 426 -480 640 -640 480 -640 480 -478 640 -640 480 -640 480 -500 333 -500 375 -640 427 -640 426 -500 373 -486 640 -640 496 -640 480 -640 480 -640 480 -640 426 -640 428 -640 427 -640 425 -480 640 -500 375 -640 394 -640 427 -640 428 -640 480 -478 640 -640 480 -640 480 -480 640 -640 474 -640 406 -640 640 -375 500 -640 428 -640 480 -640 480 -500 333 -640 427 -478 640 -640 427 -640 480 -500 375 -234 500 -640 198 -500 375 -640 480 -640 444 -500 375 -480 640 -640 427 -640 640 -640 449 -640 426 -640 480 -500 375 -356 500 -427 640 -375 500 -487 640 -640 427 -640 640 -640 427 -640 436 -640 427 -640 427 -640 421 -640 360 -426 640 -640 430 -640 377 -640 480 -640 480 -640 480 -500 375 -640 480 -640 426 -640 426 -640 481 -640 480 -640 427 -640 444 -640 480 -640 480 -366 640 -500 332 -640 426 -640 480 -478 640 -480 640 -640 426 -427 640 -640 640 -640 427 -480 640 -640 424 -640 430 -612 612 -427 640 -640 640 -612 612 -640 427 -640 480 -480 640 -640 480 -640 427 -640 480 -640 424 -640 480 -640 480 -640 480 -640 480 -425 640 -640 514 -640 427 -640 480 -640 480 -640 426 -500 375 -480 640 -640 425 -500 375 -640 480 -640 480 -480 640 -427 640 -640 480 -500 375 -640 551 -640 427 -640 480 -640 456 -640 480 -335 500 -500 375 -427 640 -480 640 -640 427 -500 375 -640 480 -640 480 -480 640 -500 341 -443 640 -640 395 -640 173 -480 640 -640 448 -640 427 -548 640 -640 480 -640 480 -426 640 -480 640 -480 640 -500 331 -640 427 -640 480 -447 640 -640 480 -640 350 -640 484 -500 338 -640 480 -480 640 -640 425 -500 375 -640 483 -640 359 -640 426 -335 500 -640 426 -640 480 -480 640 -640 427 -640 478 -640 428 -640 480 -640 503 -480 640 -480 640 -640 481 -640 480 -640 238 -640 480 -640 427 -500 274 -640 622 -640 480 -640 427 -375 500 -640 480 -497 640 -640 640 -640 452 -640 426 -500 401 -640 473 -640 424 -640 424 -500 333 -480 640 -640 475 -640 480 -500 400 -640 427 -640 480 -500 347 -640 426 -640 422 -640 480 -640 427 -640 427 -640 425 -433 640 -640 524 -640 453 -640 480 -640 429 -640 480 -500 374 -500 375 -640 427 -426 640 -640 428 -640 428 -640 351 -640 459 -640 480 -640 480 -640 454 -477 640 -500 334 -375 500 -640 426 -640 427 -640 480 -426 640 -640 427 -640 480 -425 640 -640 480 -500 375 -476 640 -640 426 -640 427 -640 480 -640 480 -640 480 -640 468 -640 640 -640 480 -640 426 -640 425 -559 640 -640 398 -640 640 -640 427 -612 612 -640 480 -480 640 -640 480 -612 612 -640 480 -500 332 -640 359 -640 427 -360 640 -640 640 -423 640 -500 334 -640 427 -427 640 -640 427 -640 480 -640 480 -427 640 -480 640 -640 442 -640 480 -640 480 -640 426 -612 612 -640 426 -427 640 -640 470 -427 640 -419 640 -480 640 -640 427 -500 375 -485 640 -640 480 -640 453 -640 480 -640 478 -640 427 -640 480 -640 480 -612 612 -640 480 -425 640 -640 428 -640 427 -640 480 -640 456 -576 640 -640 427 -640 427 -640 480 -640 425 -640 439 -419 640 -480 640 -375 500 -480 640 -640 427 -427 640 -480 360 -500 330 -640 360 -569 640 -640 428 -640 485 -640 496 -640 427 -640 424 -640 594 -640 427 -640 480 -480 640 -640 480 -500 375 -427 640 -640 640 -500 388 -640 428 -640 426 -640 436 -427 640 -500 375 -375 500 -640 480 -640 427 -640 427 -640 480 -500 333 -640 457 -640 426 -640 425 -480 640 -380 640 -640 327 -500 335 -640 480 -640 427 -640 480 -640 425 -434 640 -640 480 -640 480 -640 427 -450 339 -478 640 -480 640 -640 480 -482 640 -640 424 -640 426 -640 512 -612 612 -640 478 -640 480 -640 427 -640 427 -640 427 -640 480 -612 612 -640 480 -500 333 -434 500 -640 446 -640 482 -640 480 -640 480 -640 478 -500 375 -640 427 -640 427 -500 334 -425 640 -640 427 -640 427 -478 640 -640 461 -640 477 -640 425 -640 427 -500 400 -640 389 -640 426 -424 640 -640 480 -640 361 -640 478 -333 500 -640 608 -640 480 -640 480 -375 500 -640 311 -640 427 -640 427 -640 393 -640 480 -500 333 -640 639 -640 376 -640 414 -490 640 -485 640 -640 344 -640 480 -640 427 -640 466 -640 427 -480 640 -640 613 -640 480 -640 426 -640 429 -640 259 -500 333 -612 612 -640 640 -480 640 -640 480 -640 480 -640 427 -640 458 -480 640 -423 640 -500 375 -640 480 -640 480 -500 333 -480 640 -640 480 -443 640 -640 428 -640 427 -400 640 -640 480 -640 427 -500 500 -640 480 -500 333 -600 600 -640 427 -640 320 -480 640 -640 480 -640 406 -427 640 -640 427 -640 419 -640 480 -640 427 -640 429 -640 640 -640 427 -500 477 -640 480 -640 480 -640 480 -612 612 -640 429 -480 640 -640 480 -640 458 -640 426 -500 440 -640 360 -500 334 -640 480 -640 427 -640 480 -640 427 -640 428 -500 375 -640 427 -640 426 -332 500 -427 640 -427 640 -500 375 -640 427 -640 480 -640 518 -640 480 -640 427 -480 640 -640 640 -640 425 -640 427 -481 640 -640 359 -640 480 -640 360 -640 428 -640 480 -640 419 -640 480 -640 480 -640 480 -640 480 -640 426 -640 424 -640 321 -640 478 -640 482 -500 375 -640 480 -640 480 -506 640 -640 480 -640 469 -640 377 -640 359 -640 480 -500 335 -640 478 -640 427 -640 287 -640 480 -375 500 -640 480 -428 640 -456 640 -480 640 -640 493 -640 481 -480 640 -640 480 -640 428 -375 500 -640 480 -640 371 -640 427 -500 375 -427 640 -640 480 -500 375 -640 337 -468 640 -426 640 -640 484 -480 640 -640 427 -640 425 -500 424 -640 480 -640 427 -640 427 -640 427 -640 480 -640 610 -640 480 -640 480 -640 426 -463 640 -640 429 -640 427 -640 522 -640 480 -640 428 -640 480 -480 640 -640 427 -424 640 -480 640 -640 457 -500 367 -640 448 -496 640 -500 375 -480 640 -640 425 -640 425 -640 480 -500 334 -640 369 -427 640 -640 480 -375 500 -640 480 -640 480 -640 411 -333 500 -640 512 -640 427 -640 474 -640 480 -640 427 -640 478 -427 640 -640 358 -640 640 -640 472 -567 378 -640 404 -640 427 -480 640 -640 428 -640 427 -640 480 -427 640 -640 433 -640 638 -480 640 -640 470 -640 591 -640 427 -640 427 -612 612 -550 365 -640 640 -527 640 -640 427 -640 480 -640 480 -640 480 -640 640 -640 459 -480 640 -480 640 -640 427 -640 480 -640 480 -640 480 -640 427 -427 640 -640 427 -333 500 -640 480 -640 426 -640 426 -640 427 -426 640 -640 228 -612 612 -640 426 -612 612 -640 426 -640 640 -640 523 -480 640 -479 640 -640 428 -640 480 -500 375 -640 414 -500 375 -640 480 -480 640 -414 278 -424 640 -640 480 -480 640 -500 375 -612 612 -640 544 -427 640 -640 427 -640 480 -500 331 -640 429 -640 427 -640 480 -640 426 -640 426 -640 480 -640 480 -366 640 -640 427 -640 480 -640 480 -427 640 -640 589 -500 375 -640 426 -640 568 -640 395 -640 427 -640 426 -640 480 -640 480 -640 480 -640 360 -640 561 -640 480 -640 427 -640 480 -640 480 -500 375 -427 640 -425 640 -640 459 -523 640 -488 640 -478 640 -640 426 -500 333 -480 640 -612 612 -640 425 -480 640 -640 425 -640 427 -500 375 -640 552 -640 480 -434 640 -500 334 -500 375 -515 640 -640 480 -425 640 -640 198 -640 426 -640 427 -640 440 -640 427 -640 427 -500 375 -640 402 -500 500 -640 480 -640 346 -500 333 -640 458 -480 640 -640 480 -640 426 -500 375 -640 480 -427 640 -640 425 -480 640 -500 441 -640 480 -428 640 -640 480 -612 612 -640 480 -640 427 -640 501 -500 375 -640 480 -640 427 -441 640 -424 640 -427 640 -640 427 -640 480 -480 320 -500 379 -552 640 -640 426 -640 346 -640 427 -640 512 -480 640 -640 512 -612 612 -640 480 -500 375 -640 640 -375 500 -640 426 -640 359 -612 612 -612 612 -640 428 -640 480 -640 427 -640 428 -640 428 -640 263 -375 500 -640 427 -252 360 -640 425 -640 424 -500 331 -640 480 -500 331 -640 480 -640 480 -480 640 -640 428 -427 640 -640 427 -417 500 -640 480 -426 640 -640 427 -383 640 -480 640 -640 480 -640 512 -640 431 -612 612 -450 600 -640 426 -640 502 -640 480 -640 457 -640 427 -640 424 -640 480 -640 480 -640 427 -378 640 -612 612 -640 426 -640 480 -418 640 -640 426 -333 500 -640 480 -640 480 -640 432 -500 375 -500 347 -640 427 -640 451 -640 480 -640 480 -640 266 -640 426 -640 360 -500 374 -427 640 -640 427 -480 640 -640 431 -500 333 -640 480 -375 500 -640 480 -640 482 -640 480 -640 426 -640 478 -640 480 -640 424 -640 480 -640 427 -640 480 -425 640 -640 427 -640 480 -640 480 -640 424 -480 640 -640 427 -640 480 -426 640 -640 426 -640 480 -640 427 -480 640 -480 640 -480 640 -640 478 -640 480 -640 480 -640 480 -640 480 -640 480 -640 426 -640 480 -500 333 -640 427 -640 427 -500 333 -640 427 -480 640 -480 640 -640 480 -428 640 -640 480 -500 334 -640 347 -640 442 -640 480 -640 480 -640 427 -640 411 -425 640 -640 427 -480 640 -640 427 -640 480 -640 480 -500 387 -640 480 -480 640 -500 332 -453 500 -480 640 -640 480 -640 427 -500 334 -640 427 -500 500 -640 480 -500 375 -640 428 -640 640 -640 424 -500 376 -427 640 -640 427 -640 427 -640 427 -640 480 -640 480 -500 375 -640 422 -640 486 -640 428 -500 322 -500 375 -640 480 -640 513 -427 640 -640 425 -640 480 -640 450 -640 427 -640 480 -640 480 -640 480 -500 332 -640 421 -640 480 -640 426 -640 427 -640 424 -640 428 -640 480 -640 480 -640 480 -427 640 -640 640 -640 480 -640 359 -640 448 -374 500 -425 640 -259 194 -640 428 -640 427 -640 534 -640 480 -640 480 -640 346 -500 375 -425 640 -426 640 -640 480 -640 480 -640 480 -400 640 -640 480 -640 427 -640 427 -419 640 -640 427 -640 614 -500 375 -640 457 -640 428 -640 427 -500 375 -640 483 -500 375 -640 426 -640 388 -640 426 -640 480 -500 341 -640 427 -640 480 -640 425 -500 375 -640 480 -640 427 -640 355 -640 480 -427 640 -500 375 -640 480 -500 400 -401 640 -640 480 -640 426 -640 427 -640 427 -640 551 -640 480 -640 428 -428 640 -427 640 -640 427 -640 480 -426 640 -459 640 -480 640 -640 480 -640 424 -640 480 -333 500 -482 640 -640 480 -640 480 -640 480 -640 360 -640 426 -512 640 -427 640 -375 500 -375 500 -640 480 -640 427 -640 599 -640 454 -456 640 -332 500 -640 426 -640 436 -426 640 -640 480 -480 640 -640 480 -612 612 -640 480 -427 640 -500 334 -640 480 -640 480 -640 480 -640 480 -640 445 -500 375 -640 427 -640 480 -500 375 -640 445 -443 640 -480 640 -640 428 -640 427 -640 426 -512 640 -640 427 -640 374 -500 332 -375 500 -640 480 -640 480 -500 383 -640 427 -500 333 -500 375 -640 535 -640 426 -640 480 -640 425 -640 480 -420 640 -427 640 -480 640 -640 426 -426 640 -500 375 -640 480 -500 333 -480 640 -640 480 -425 640 -640 480 -640 480 -640 422 -640 425 -640 480 -612 612 -500 333 -640 639 -640 429 -500 375 -427 640 -453 640 -500 261 -500 333 -640 478 -425 640 -612 612 -428 640 -640 426 -480 640 -640 331 -640 510 -500 333 -640 427 -640 427 -640 480 -640 376 -640 478 -500 375 -640 427 -640 409 -481 640 -431 640 -640 480 -640 480 -640 480 -426 640 -640 436 -640 534 -640 385 -640 426 -640 480 -367 415 -375 500 -640 430 -640 480 -640 446 -640 480 -640 438 -640 428 -640 480 -500 375 -640 427 -640 361 -640 427 -640 468 -640 480 -427 640 -640 480 -640 425 -604 402 -640 426 -374 500 -640 318 -470 640 -640 359 -640 427 -640 540 -640 427 -457 640 -640 480 -640 360 -640 478 -640 480 -640 426 -450 600 -500 442 -640 640 -640 445 -640 480 -640 425 -640 514 -640 478 -426 640 -640 424 -640 425 -360 640 -640 306 -640 512 -640 480 -500 375 -478 640 -640 441 -396 500 -640 375 -594 445 -640 427 -640 480 -640 425 -640 480 -640 427 -640 426 -640 480 -640 426 -640 426 -640 427 -500 375 -480 640 -640 359 -612 612 -640 480 -640 480 -640 480 -500 310 -612 612 -500 471 -640 427 -640 427 -640 372 -640 427 -640 412 -481 640 -640 293 -500 334 -640 424 -500 375 -480 640 -640 512 -480 640 -612 612 -640 468 -640 424 -333 500 -612 612 -424 640 -500 375 -640 480 -500 333 -425 640 -640 426 -640 480 -480 640 -640 427 -480 640 -640 427 -640 480 -640 384 -640 439 -480 640 -426 640 -612 612 -640 303 -640 480 -640 384 -640 480 -640 427 -500 375 -640 480 -640 427 -640 480 -640 491 -640 430 -640 480 -379 640 -640 480 -480 640 -500 375 -640 530 -640 427 -640 456 -515 640 -640 480 -500 334 -640 480 -640 437 -640 480 -480 640 -640 480 -356 500 -640 478 -640 427 -640 427 -428 640 -480 640 -480 640 -480 640 -640 480 -640 425 -640 408 -640 309 -640 226 -359 640 -480 640 -640 427 -640 471 -480 640 -500 375 -640 426 -640 425 -640 498 -640 360 -480 640 -437 500 -640 427 -375 500 -500 344 -480 640 -640 473 -640 426 -640 480 -640 431 -640 273 -640 427 -640 427 -640 427 -500 375 -640 480 -480 640 -640 427 -640 427 -640 639 -500 375 -526 640 -469 640 -500 345 -640 480 -612 612 -480 640 -480 640 -640 534 -320 320 -333 500 -336 500 -640 426 -640 441 -640 612 -640 425 -500 375 -640 480 -640 480 -471 640 -480 640 -500 375 -640 480 -640 480 -640 480 -640 480 -640 480 -341 640 -640 480 -480 640 -480 640 -640 426 -640 448 -612 612 -353 500 -480 640 -499 640 -640 373 -640 393 -640 444 -640 427 -640 360 -500 348 -500 375 -640 480 -640 640 -640 480 -640 480 -500 375 -441 640 -493 640 -640 427 -640 480 -500 333 -640 481 -640 372 -640 453 -640 427 -640 480 -500 357 -640 427 -640 480 -640 327 -612 612 -424 640 -640 359 -640 472 -640 428 -640 480 -640 320 -425 640 -640 480 -612 612 -480 640 -480 640 -375 500 -480 640 -427 640 -640 427 -425 319 -640 480 -640 427 -640 425 -640 480 -640 425 -640 425 -640 427 -640 427 -500 334 -640 426 -640 427 -640 480 -640 480 -640 444 -480 640 -640 554 -640 480 -612 612 -640 428 -500 375 -640 480 -640 427 -640 428 -500 354 -427 640 -500 333 -414 640 -480 640 -640 488 -640 480 -594 640 -612 612 -640 361 -640 480 -467 640 -640 526 -640 480 -500 491 -640 480 -400 640 -640 569 -480 640 -640 426 -640 480 -640 427 -480 640 -640 480 -500 375 -640 426 -427 640 -640 427 -500 375 -640 480 -480 640 -640 426 -375 500 -640 480 -640 369 -640 428 -426 640 -480 640 -640 426 -640 480 -480 640 -425 640 -640 425 -427 640 -640 435 -640 507 -640 480 -500 333 -640 426 -640 473 -612 612 -640 427 -640 427 -500 375 -640 640 -375 500 -640 480 -640 428 -427 640 -639 640 -480 640 -640 423 -640 391 -640 480 -640 480 -640 389 -478 640 -640 427 -612 612 -463 640 -640 480 -480 640 -427 640 -640 480 -480 640 -481 640 -640 640 -500 338 -640 480 -640 480 -640 360 -500 375 -640 480 -500 375 -640 426 -640 479 -500 375 -640 493 -640 486 -481 640 -486 381 -500 375 -640 428 -427 640 -640 456 -497 640 -426 640 -640 427 -500 375 -640 429 -640 456 -640 360 -640 478 -428 640 -480 640 -640 480 -500 483 -640 426 -381 640 -640 480 -640 443 -640 480 -640 428 -640 424 -640 480 -640 407 -640 426 -640 480 -480 640 -640 480 -640 428 -640 359 -426 640 -640 427 -640 480 -640 428 -427 640 -640 481 -375 500 -573 640 -500 333 -640 428 -640 476 -612 612 -640 480 -640 480 -500 375 -426 640 -375 500 -640 480 -640 480 -640 359 -480 640 -637 640 -640 423 -640 394 -640 480 -500 375 -612 612 -640 360 -640 426 -640 427 -640 640 -640 480 -332 500 -640 427 -640 480 -333 500 -640 426 -640 541 -640 427 -640 640 -640 480 -640 426 -450 338 -640 428 -640 428 -640 354 -640 524 -480 640 -480 640 -640 480 -640 424 -500 332 -640 426 -640 480 -500 375 -480 640 -640 351 -640 480 -640 480 -531 640 -480 640 -375 500 -640 427 -427 640 -612 612 -427 640 -640 441 -640 480 -638 640 -640 426 -488 640 -424 640 -500 400 -640 426 -640 427 -480 640 -333 500 -640 579 -640 427 -640 320 -360 640 -640 427 -640 480 -640 480 -500 332 -640 427 -480 640 -640 467 -635 640 -640 427 -497 640 -640 480 -427 640 -640 428 -424 640 -640 480 -427 640 -478 640 -480 640 -640 424 -427 640 -640 480 -640 480 -640 426 -427 640 -500 375 -640 432 -640 479 -640 360 -640 427 -640 424 -640 480 -640 480 -478 640 -427 640 -640 480 -428 640 -500 375 -640 427 -375 500 -640 429 -640 427 -640 426 -427 640 -640 620 -375 500 -438 351 -640 427 -575 640 -640 480 -640 428 -640 480 -640 480 -640 480 -640 480 -480 640 -500 342 -429 640 -480 640 -640 394 -640 480 -640 298 -427 640 -500 378 -640 511 -500 333 -640 480 -334 500 -640 480 -640 423 -640 426 -640 427 -640 480 -640 388 -640 444 -640 531 -453 640 -500 375 -640 234 -500 333 -426 640 -640 428 -640 480 -640 428 -480 640 -640 472 -480 640 -375 500 -640 480 -480 640 -500 332 -640 427 -640 398 -640 425 -640 478 -640 427 -427 640 -480 640 -500 334 -640 480 -612 612 -640 480 -640 427 -427 640 -427 640 -333 500 -640 480 -640 480 -500 375 -640 480 -333 500 -640 480 -375 500 -640 625 -500 333 -500 375 -500 375 -480 640 -640 480 -500 333 -640 371 -640 481 -480 640 -480 640 -640 480 -427 640 -427 640 -640 427 -612 612 -500 330 -430 500 -500 333 -640 480 -640 425 -480 640 -640 480 -640 405 -640 425 -640 427 -640 427 -640 467 -640 478 -427 640 -640 480 -333 500 -640 426 -500 375 -640 549 -480 640 -640 427 -640 427 -640 480 -640 480 -640 426 -640 640 -640 480 -427 640 -500 375 -480 640 -640 500 -640 425 -640 320 -480 640 -500 376 -640 480 -479 640 -640 504 -480 640 -480 640 -500 375 -640 640 -640 425 -640 480 -640 428 -426 640 -640 427 -640 480 -640 424 -640 480 -640 640 -640 360 -640 480 -640 640 -500 375 -500 384 -640 426 -500 334 -640 480 -640 480 -640 427 -400 300 -480 640 -640 427 -612 612 -640 429 -640 424 -640 557 -640 427 -427 640 -640 440 -640 480 -640 321 -640 427 -500 375 -640 426 -500 375 -480 640 -640 391 -500 375 -640 480 -480 640 -640 425 -640 427 -429 640 -640 427 -640 425 -640 428 -500 374 -640 425 -640 425 -640 477 -640 427 -375 500 -640 480 -640 457 -640 383 -480 640 -425 640 -426 640 -640 480 -427 640 -640 466 -640 427 -640 428 -640 542 -480 640 -640 480 -640 480 -640 480 -640 640 -480 640 -640 479 -480 640 -340 505 -500 500 -640 454 -500 375 -640 427 -480 640 -640 480 -480 640 -640 427 -333 500 -640 480 -408 640 -640 480 -640 427 -640 480 -480 640 -225 300 -640 424 -480 640 -375 500 -640 480 -640 426 -640 480 -427 640 -500 375 -640 463 -640 433 -427 640 -612 612 -612 612 -640 425 -640 480 -640 480 -640 512 -640 353 -500 375 -640 480 -500 375 -640 427 -480 640 -480 640 -640 480 -500 375 -640 640 -500 375 -640 481 -500 375 -424 640 -640 480 -640 480 -480 640 -640 396 -637 419 -640 480 -640 480 -640 427 -612 612 -427 640 -428 640 -331 500 -640 478 -640 429 -640 360 -500 375 -640 428 -640 480 -640 480 -453 500 -640 427 -640 425 -480 640 -385 308 -640 479 -612 612 -424 640 -640 423 -640 480 -640 427 -640 640 -640 428 -640 480 -640 427 -640 427 -640 359 -480 640 -640 480 -612 612 -640 428 -640 427 -640 480 -640 397 -500 375 -640 480 -640 480 -640 427 -500 332 -640 480 -640 431 -640 480 -640 480 -640 486 -500 375 -400 300 -480 640 -640 480 -640 427 -640 427 -640 427 -640 427 -640 480 -285 500 -480 640 -500 333 -640 416 -640 427 -640 427 -458 640 -640 480 -640 427 -500 375 -480 343 -500 500 -428 640 -640 491 -640 426 -640 480 -640 424 -480 640 -640 624 -612 612 -640 480 -640 480 -640 427 -640 480 -640 640 -500 314 -640 359 -640 457 -640 427 -480 640 -472 640 -600 600 -640 427 -640 421 -640 427 -640 480 -612 612 -500 333 -640 427 -640 480 -640 480 -640 640 -640 480 -640 480 -640 538 -640 414 -427 640 -640 480 -640 480 -640 427 -640 427 -640 492 -640 360 -640 457 -640 480 -640 427 -640 480 -500 342 -480 640 -424 640 -640 480 -640 480 -640 426 -640 640 -640 480 -480 640 -640 480 -640 425 -427 640 -500 375 -427 640 -427 640 -500 375 -640 480 -640 426 -480 640 -427 640 -640 424 -500 333 -640 517 -427 640 -529 640 -640 427 -440 640 -480 640 -480 640 -640 426 -640 427 -612 612 -640 480 -640 478 -640 480 -640 426 -640 295 -640 480 -640 480 -500 334 -500 375 -640 423 -480 640 -640 480 -480 640 -640 513 -640 427 -640 481 -640 393 -640 480 -427 640 -640 424 -427 640 -640 451 -640 383 -640 425 -427 640 -640 480 -480 640 -640 427 -500 333 -427 640 -640 463 -640 428 -640 480 -640 426 -640 449 -640 427 -428 640 -640 480 -333 500 -427 640 -640 426 -640 426 -640 427 -640 424 -640 427 -402 600 -640 482 -640 427 -500 333 -640 480 -640 480 -640 426 -640 457 -640 480 -640 423 -640 480 -640 426 -427 640 -640 480 -500 333 -640 426 -500 375 -640 480 -640 360 -427 640 -640 480 -500 375 -640 259 -640 480 -640 480 -360 640 -480 640 -483 640 -640 480 -640 465 -640 480 -640 480 -424 640 -500 335 -640 360 -640 429 -640 457 -360 640 -640 480 -640 427 -640 426 -640 428 -426 640 -466 640 -640 425 -500 375 -640 426 -640 426 -333 500 -640 455 -640 425 -640 494 -500 332 -640 428 -640 480 -640 480 -612 612 -640 427 -612 612 -383 640 -640 480 -640 427 -334 500 -640 640 -500 335 -640 480 -480 640 -640 480 -640 480 -640 427 -612 612 -640 418 -375 500 -640 480 -640 480 -640 480 -425 640 -640 480 -640 480 -500 333 -640 480 -640 480 -480 640 -640 480 -640 426 -640 478 -640 428 -500 333 -640 631 -640 480 -375 500 -640 426 -578 640 -640 473 -640 415 -427 640 -427 640 -479 640 -640 480 -426 640 -612 612 -500 375 -640 480 -640 489 -640 412 -640 480 -383 640 -640 360 -427 640 -500 333 -640 427 -640 480 -426 640 -640 425 -640 509 -640 383 -640 480 -640 427 -640 480 -640 427 -640 480 -640 480 -480 640 -449 640 -640 426 -500 333 -640 427 -640 360 -480 640 -640 425 -400 500 -640 427 -640 480 -640 428 -640 431 -640 480 -500 400 -640 480 -640 480 -640 480 -640 480 -640 426 -640 361 -480 640 -480 640 -640 480 -640 480 -640 469 -500 333 -500 332 -640 480 -346 640 -640 491 -427 640 -640 480 -640 435 -640 426 -640 427 -640 427 -500 375 -426 640 -480 640 -480 640 -329 500 -640 478 -213 320 -427 640 -640 426 -640 480 -640 426 -500 375 -640 425 -640 639 -309 640 -640 427 -640 640 -500 336 -640 640 -640 480 -640 480 -333 500 -640 480 -431 640 -640 480 -640 480 -480 640 -640 426 -640 427 -500 298 -640 426 -640 480 -375 500 -640 631 -640 427 -640 480 -640 480 -640 428 -634 354 -500 375 -428 640 -640 640 -640 480 -640 480 -640 513 -640 425 -640 426 -640 411 -640 478 -640 480 -640 426 -640 480 -640 480 -333 500 -500 284 -375 500 -640 383 -640 427 -640 353 -640 426 -500 380 -640 480 -640 480 -640 427 -640 429 -480 640 -640 427 -500 334 -213 320 -500 333 -640 640 -612 612 -480 640 -640 480 -640 290 -640 427 -640 640 -480 640 -640 480 -640 427 -469 640 -427 640 -500 451 -640 480 -500 366 -640 428 -640 427 -640 480 -612 612 -640 480 -500 375 -399 640 -500 332 -640 327 -500 396 -640 433 -640 427 -427 640 -640 480 -427 640 -427 640 -640 427 -480 640 -640 427 -640 480 -426 640 -480 640 -640 323 -640 457 -640 426 -640 478 -640 446 -426 640 -428 640 -640 480 -427 640 -640 432 -640 359 -640 482 -640 425 -314 188 -355 640 -640 427 -500 355 -500 338 -640 480 -429 640 -500 332 -640 360 -500 281 -640 427 -500 282 -640 428 -500 379 -640 480 -640 427 -640 426 -335 500 -640 456 -640 396 -640 424 -640 480 -640 427 -484 640 -427 640 -640 480 -640 428 -640 428 -640 432 -612 612 -332 500 -640 427 -480 640 -640 480 -366 500 -480 640 -640 508 -640 424 -640 425 -640 425 -480 640 -480 640 -500 375 -640 549 -640 427 -640 424 -500 375 -640 480 -640 470 -640 480 -640 480 -480 640 -640 427 -478 640 -640 360 -427 640 -640 440 -426 640 -640 426 -500 333 -612 612 -640 480 -503 640 -640 427 -480 640 -640 449 -500 479 -640 480 -480 640 -640 427 -640 426 -640 427 -640 425 -640 415 -640 427 -640 427 -640 428 -486 640 -640 486 -640 419 -640 424 -640 480 -640 369 -500 375 -427 640 -640 424 -500 347 -640 615 -640 480 -500 375 -500 375 -640 480 -640 480 -640 480 -427 640 -640 428 -500 333 -640 416 -500 375 -419 640 -640 425 -640 480 -480 640 -480 640 -424 640 -427 640 -640 426 -480 640 -640 480 -480 640 -640 425 -640 360 -640 427 -640 424 -640 480 -640 427 -640 480 -640 427 -640 480 -640 425 -640 428 -640 480 -640 480 -640 478 -640 480 -640 428 -612 612 -640 636 -500 333 -480 640 -640 437 -428 640 -612 612 -640 459 -640 480 -640 480 -640 480 -427 640 -640 480 -640 507 -640 480 -640 427 -640 427 -640 427 -640 480 -640 457 -640 480 -500 375 -640 383 -500 332 -640 480 -375 500 -640 427 -426 640 -640 480 -640 427 -640 480 -640 427 -375 500 -640 480 -480 640 -478 640 -375 500 -480 640 -500 375 -640 480 -427 640 -640 480 -640 427 -334 500 -500 375 -640 361 -511 640 -500 334 -640 480 -640 480 -640 640 -640 480 -500 375 -640 480 -640 480 -640 426 -640 425 -640 524 -479 640 -640 480 -640 480 -640 427 -480 640 -640 480 -640 428 -500 375 -606 640 -480 640 -640 426 -500 392 -640 451 -640 485 -427 640 -640 428 -640 457 -640 424 -640 480 -640 427 -493 640 -640 398 -500 333 -427 640 -640 427 -640 432 -640 480 -640 480 -640 427 -640 361 -640 425 -500 375 -640 438 -432 288 -612 612 -640 480 -500 376 -480 640 -640 479 -400 640 -640 426 -500 377 -375 500 -640 424 -443 640 -640 480 -640 427 -427 640 -480 640 -626 640 -640 550 -500 335 -550 640 -640 428 -452 640 -500 350 -499 500 -640 427 -569 640 -640 480 -640 425 -500 334 -640 420 -640 427 -640 441 -640 480 -500 500 -640 480 -640 598 -333 500 -480 640 -427 640 -640 480 -640 480 -612 612 -500 335 -640 480 -640 640 -600 450 -427 640 -640 400 -507 640 -640 480 -500 375 -500 332 -640 480 -510 640 -640 480 -640 429 -480 640 -500 333 -640 427 -640 346 -281 500 -640 480 -427 640 -640 454 -640 439 -375 500 -640 427 -448 336 -640 533 -640 424 -480 640 -640 480 -640 427 -640 425 -326 640 -640 532 -640 480 -640 480 -640 480 -640 383 -480 640 -640 480 -640 427 -640 427 -640 480 -480 640 -640 384 -480 640 -640 456 -500 375 -640 480 -640 428 -427 640 -640 541 -500 333 -640 436 -640 482 -640 427 -640 537 -640 426 -480 356 -640 427 -640 480 -640 427 -640 480 -480 640 -640 424 -640 427 -640 480 -640 427 -640 360 -500 375 -640 427 -560 600 -640 427 -533 640 -477 640 -640 424 -640 458 -640 427 -480 640 -640 428 -640 427 -399 500 -640 640 -480 640 -478 640 -640 480 -640 480 -640 427 -612 612 -480 640 -640 470 -640 425 -640 431 -425 640 -640 427 -640 427 -640 463 -427 640 -640 480 -640 427 -640 438 -480 640 -640 427 -640 462 -640 442 -640 480 -429 640 -640 427 -640 480 -500 375 -612 612 -640 640 -640 387 -427 640 -640 320 -640 427 -640 480 -640 427 -480 640 -640 429 -480 640 -480 640 -335 500 -640 425 -640 425 -500 375 -640 480 -640 640 -427 640 -640 480 -640 480 -640 480 -453 640 -640 478 -640 425 -500 379 -640 427 -640 480 -500 346 -640 547 -427 640 -399 600 -640 480 -640 327 -640 427 -640 427 -640 427 -640 427 -640 480 -640 427 -640 283 -640 480 -640 480 -435 640 -424 640 -600 400 -640 427 -640 354 -640 556 -612 612 -480 640 -640 480 -640 511 -640 480 -480 640 -640 428 -640 271 -640 480 -640 480 -640 425 -640 383 -428 640 -640 480 -480 640 -640 427 -315 352 -640 480 -426 640 -480 640 -640 427 -640 401 -640 480 -640 480 -640 426 -640 427 -640 427 -640 480 -640 480 -640 480 -640 480 -640 424 -640 513 -459 640 -427 640 -640 640 -640 427 -640 478 -640 416 -640 427 -480 640 -640 423 -480 640 -640 466 -640 544 -640 437 -375 500 -640 492 -375 500 -640 424 -640 370 -640 513 -640 429 -427 640 -640 427 -426 640 -428 640 -640 426 -640 640 -500 384 -627 640 -640 427 -640 427 -640 427 -428 640 -640 512 -640 480 -640 427 -640 480 -500 376 -640 428 -640 384 -480 640 -640 478 -640 480 -640 427 -426 640 -563 640 -640 480 -640 430 -500 333 -640 633 -640 426 -426 640 -640 427 -480 640 -640 638 -640 400 -640 480 -640 480 -640 427 -640 424 -640 427 -640 427 -640 480 -480 640 -640 450 -612 612 -640 483 -640 480 -640 480 -640 427 -450 412 -480 640 -640 443 -640 480 -640 480 -640 434 -640 425 -640 427 -640 360 -640 427 -480 640 -640 378 -640 480 -480 640 -640 480 -640 480 -640 426 -640 480 -640 384 -640 427 -640 480 -640 427 -640 480 -640 360 -640 532 -640 360 -640 556 -640 427 -640 480 -528 640 -640 480 -500 333 -640 427 -426 640 -640 425 -640 428 -425 640 -640 480 -617 640 -418 500 -640 480 -427 640 -640 457 -427 640 -640 480 -374 500 -500 400 -640 480 -484 640 -640 480 -640 431 -640 426 -640 428 -500 375 -640 480 -640 429 -640 427 -640 427 -640 427 -640 427 -480 640 -436 640 -500 333 -479 640 -640 480 -612 612 -640 480 -640 427 -480 640 -640 427 -500 481 -640 451 -640 336 -640 335 -640 480 -500 375 -640 427 -640 480 -640 428 -640 428 -640 501 -640 427 -640 480 -480 640 -427 640 -640 427 -640 480 -640 427 -640 395 -426 640 -427 640 -640 480 -640 426 -640 480 -480 640 -640 426 -640 383 -640 480 -609 640 -640 387 -448 336 -640 457 -640 426 -375 500 -423 640 -480 640 -500 334 -375 500 -640 353 -640 480 -375 500 -640 405 -500 333 -640 480 -427 640 -506 373 -500 375 -640 480 -500 375 -640 480 -640 413 -640 426 -640 427 -640 480 -640 427 -640 480 -640 437 -640 350 -480 640 -640 426 -640 513 -640 425 -480 640 -500 375 -640 426 -640 493 -640 425 -480 640 -500 493 -640 427 -640 480 -483 640 -640 480 -640 480 -500 375 -480 640 -640 378 -500 335 -500 360 -640 543 -640 480 -333 500 -640 480 -640 428 -640 480 -333 500 -640 427 -640 367 -640 427 -640 480 -640 480 -640 480 -640 458 -426 640 -640 480 -480 640 -640 480 -640 480 -640 427 -640 436 -640 451 -500 375 -640 480 -640 427 -640 480 -640 394 -640 480 -500 332 -640 439 -480 640 -500 400 -640 519 -640 480 -640 478 -640 456 -640 428 -640 480 -427 640 -500 375 -250 640 -640 480 -480 640 -640 512 -640 480 -288 352 -428 640 -480 640 -375 500 -640 480 -640 424 -640 480 -640 462 -640 480 -640 428 -640 481 -500 375 -640 480 -640 477 -640 427 -496 640 -513 640 -640 427 -640 371 -640 428 -383 640 -640 480 -375 500 -427 640 -640 427 -480 640 -427 640 -640 480 -640 481 -640 480 -640 425 -640 480 -640 458 -640 427 -640 480 -640 480 -640 480 -640 405 -640 480 -640 428 -320 240 -640 480 -479 640 -640 480 -640 480 -640 428 -480 640 -640 427 -460 640 -612 612 -640 439 -640 480 -612 612 -480 640 -640 425 -640 427 -640 480 -640 480 -500 375 -427 640 -380 285 -375 500 -640 427 -640 480 -640 426 -640 427 -640 480 -640 480 -640 490 -500 329 -612 612 -640 480 -425 640 -483 640 -500 333 -640 427 -640 427 -640 480 -640 479 -640 427 -480 640 -612 612 -433 640 -640 428 -479 640 -520 480 -427 640 -640 517 -640 428 -604 640 -500 375 -640 480 -500 333 -640 480 -427 640 -640 480 -640 478 -375 500 -640 427 -640 427 -425 640 -427 640 -426 640 -428 640 -640 427 -640 444 -436 640 -480 640 -551 640 -640 478 -500 327 -640 480 -480 640 -480 640 -640 427 -640 480 -500 377 -326 500 -640 480 -480 640 -640 424 -427 640 -640 480 -640 480 -424 640 -640 480 -640 427 -640 640 -640 429 -640 480 -480 640 -427 640 -640 427 -640 480 -640 480 -480 640 -640 359 -423 640 -640 427 -640 429 -640 480 -640 480 -500 375 -640 427 -453 640 -640 480 -640 427 -640 480 -500 375 -480 640 -640 577 -500 375 -500 332 -640 427 -640 480 -640 480 -426 640 -640 480 -622 640 -640 516 -426 640 -427 640 -640 428 -480 640 -640 359 -640 429 -640 426 -640 573 -480 640 -640 428 -640 360 -288 384 -480 640 -427 640 -500 375 -427 640 -640 480 -640 426 -640 427 -640 480 -500 333 -640 427 -640 480 -640 424 -640 424 -424 640 -640 426 -640 529 -640 424 -640 427 -640 480 -500 479 -500 332 -612 612 -427 640 -500 375 -640 480 -640 480 -375 500 -600 450 -640 480 -375 500 -480 640 -640 480 -500 375 -640 366 -640 640 -334 500 -640 426 -375 500 -640 480 -640 360 -500 375 -640 425 -482 640 -375 500 -640 480 -481 640 -640 424 -640 426 -640 480 -375 500 -427 640 -640 478 -640 594 -640 480 -640 372 -640 493 -375 500 -640 480 -640 480 -427 640 -640 480 -480 640 -450 469 -640 427 -640 480 -640 480 -640 480 -568 640 -480 640 -480 640 -480 640 -368 640 -640 429 -640 427 -500 333 -612 612 -640 480 -640 429 -500 375 -640 427 -640 428 -640 427 -640 425 -500 335 -500 375 -500 332 -640 425 -500 478 -640 427 -640 427 -427 640 -640 428 -480 640 -428 640 -640 480 -640 596 -640 427 -640 480 -640 427 -640 480 -640 480 -480 640 -640 418 -640 480 -382 500 -640 423 -500 425 -500 375 -640 425 -640 521 -640 427 -360 640 -640 480 -640 427 -640 484 -640 426 -640 481 -640 424 -426 640 -480 640 -427 640 -640 480 -500 343 -640 471 -623 640 -480 640 -640 480 -431 640 -640 503 -640 480 -640 349 -640 426 -640 480 -640 424 -427 640 -640 480 -640 427 -640 499 -640 480 -500 375 -640 480 -640 458 -333 500 -640 384 -640 426 -640 427 -640 512 -640 480 -640 480 -480 640 -640 428 -640 483 -640 425 -640 427 -640 480 -427 640 -640 480 -640 468 -500 336 -480 640 -640 425 -480 640 -640 509 -640 427 -640 428 -640 528 -640 480 -640 480 -480 640 -640 512 -500 375 -640 480 -640 480 -640 480 -480 640 -500 375 -480 640 -480 640 -640 480 -640 320 -640 425 -333 500 -612 612 -403 500 -640 414 -640 480 -640 427 -480 640 -640 428 -640 428 -640 426 -327 293 -640 579 -640 640 -500 333 -640 427 -480 640 -427 640 -640 478 -640 480 -640 426 -640 480 -427 640 -388 640 -640 480 -568 640 -640 424 -640 415 -500 375 -500 375 -640 427 -640 426 -320 500 -400 300 -492 640 -427 640 -640 427 -427 640 -640 480 -500 337 -480 640 -428 640 -480 640 -640 480 -480 640 -640 428 -640 461 -640 480 -640 480 -640 496 -427 640 -640 480 -500 321 -640 480 -640 427 -360 640 -480 640 -640 448 -640 480 -640 438 -640 427 -333 500 -640 427 -500 430 -640 425 -640 480 -640 457 -640 424 -640 480 -640 427 -640 480 -640 428 -640 484 -640 383 -520 363 -640 480 -500 375 -612 612 -640 427 -500 333 -500 311 -480 640 -640 480 -612 612 -500 375 -640 426 -640 480 -480 640 -375 500 -419 640 -640 454 -375 500 -640 426 -640 426 -480 640 -640 427 -640 480 -640 360 -640 512 -480 484 -640 456 -640 426 -640 480 -480 640 -640 483 -640 427 -640 425 -640 480 -640 480 -640 383 -640 480 -640 480 -640 426 -640 480 -640 427 -640 427 -480 640 -424 640 -640 480 -640 480 -640 480 -640 480 -640 426 -640 509 -640 640 -640 426 -480 640 -640 426 -480 640 -640 480 -640 428 -640 428 -480 640 -640 427 -640 480 -640 427 -640 429 -424 640 -640 480 -640 480 -640 427 -640 480 -429 640 -640 539 -640 479 -451 640 -640 480 -640 427 -640 480 -640 480 -640 465 -640 358 -640 428 -640 427 -500 391 -640 629 -331 500 -640 424 -500 333 -408 640 -640 480 -640 424 -640 410 -612 612 -500 375 -500 375 -480 640 -427 640 -480 640 -640 480 -640 427 -500 375 -640 480 -534 640 -640 424 -640 480 -640 480 -640 320 -427 640 -640 480 -500 375 -640 428 -480 640 -500 375 -320 240 -427 640 -334 500 -500 330 -517 640 -640 480 -640 480 -640 480 -640 426 -500 375 -640 425 -640 495 -640 480 -640 480 -640 525 -640 428 -500 375 -640 484 -640 481 -640 480 -640 433 -500 370 -640 427 -640 427 -640 431 -640 429 -500 416 -640 524 -465 640 -640 480 -480 640 -416 500 -612 612 -495 640 -480 640 -640 427 -478 640 -448 287 -612 612 -480 640 -640 480 -640 478 -640 425 -640 426 -640 424 -500 375 -640 480 -446 640 -600 450 -640 398 -428 640 -640 480 -640 480 -428 640 -428 640 -640 426 -640 427 -640 480 -640 480 -480 640 -500 375 -640 434 -640 427 -640 480 -640 427 -500 375 -640 480 -640 480 -483 640 -427 640 -427 640 -640 480 -640 439 -505 640 -375 500 -461 640 -480 640 -640 480 -640 480 -480 640 -480 640 -375 500 -640 480 -640 512 -640 424 -500 375 -500 375 -359 640 -640 462 -640 427 -640 427 -640 426 -379 500 -451 640 -419 640 -640 427 -640 480 -500 205 -500 333 -640 480 -480 640 -640 427 -375 500 -640 480 -640 427 -640 480 -640 425 -500 375 -640 431 -640 484 -640 427 -480 640 -640 427 -471 640 -640 480 -640 488 -640 480 -425 640 -640 427 -362 480 -640 481 -428 640 -480 640 -640 480 -456 640 -640 358 -500 333 -640 427 -640 516 -640 480 -375 500 -640 427 -388 640 -640 427 -640 424 -480 640 -640 570 -640 427 -500 333 -640 427 -640 427 -426 640 -640 480 -640 480 -640 640 -640 480 -334 500 -640 426 -500 375 -640 424 -640 425 -640 480 -500 336 -640 468 -640 349 -640 480 -640 421 -480 640 -375 500 -640 480 -612 612 -640 428 -640 480 -640 478 -640 427 -640 427 -480 640 -640 426 -640 383 -480 640 -640 491 -640 426 -640 480 -640 480 -500 333 -427 640 -640 481 -640 427 -640 426 -640 428 -640 419 -640 548 -640 480 -640 431 -640 631 -375 500 -640 426 -481 640 -640 427 -640 426 -333 500 -640 428 -532 500 -375 500 -640 314 -480 640 -640 480 -640 480 -500 341 -640 425 -640 480 -640 478 -640 427 -500 326 -640 427 -640 480 -640 478 -640 427 -640 447 -541 640 -640 427 -640 427 -640 416 -640 426 -640 427 -640 470 -480 640 -640 425 -640 480 -640 463 -640 427 -480 640 -612 612 -640 480 -640 480 -500 375 -480 640 -640 480 -640 427 -640 427 -500 333 -478 640 -640 425 -426 640 -640 458 -640 360 -640 425 -332 500 -640 425 -640 427 -480 287 -480 640 -480 640 -640 480 -500 376 -500 335 -500 420 -640 480 -640 425 -640 426 -515 640 -640 427 -500 500 -640 426 -481 640 -375 500 -500 375 -640 278 -640 428 -640 403 -640 426 -640 445 -640 492 -427 640 -480 640 -640 426 -640 480 -640 480 -640 581 -640 360 -640 427 -640 477 -612 612 -500 333 -640 426 -640 480 -640 480 -640 480 -500 375 -425 640 -480 640 -640 480 -550 367 -480 640 -640 480 -640 427 -640 425 -640 425 -640 425 -640 480 -640 427 -640 360 -640 419 -480 640 -640 427 -640 424 -640 480 -640 379 -640 413 -640 425 -640 427 -612 612 -424 640 -640 425 -640 411 -640 427 -640 426 -480 640 -480 640 -640 480 -640 426 -640 640 -640 424 -640 480 -640 426 -640 447 -427 640 -377 500 -537 381 -640 427 -500 462 -640 386 -500 332 -640 425 -640 513 -640 441 -640 434 -640 427 -612 612 -640 427 -640 446 -640 424 -640 426 -640 422 -640 538 -640 426 -640 480 -640 640 -640 427 -640 427 -640 426 -640 428 -419 640 -640 427 -637 640 -640 427 -500 500 -640 445 -500 375 -640 456 -640 427 -640 480 -640 480 -500 375 -488 432 -457 640 -500 334 -640 426 -640 427 -640 428 -640 480 -640 480 -640 427 -640 427 -640 480 -640 478 -640 478 -324 487 -640 480 -640 427 -333 500 -640 424 -640 480 -426 640 -428 640 -457 640 -640 483 -640 429 -478 640 -640 427 -640 480 -640 480 -640 480 -500 375 -480 640 -640 480 -480 640 -640 442 -412 640 -640 427 -640 405 -640 425 -640 491 -612 612 -500 333 -640 427 -640 480 -427 640 -500 276 -640 457 -640 480 -480 640 -640 427 -640 480 -640 480 -640 427 -640 428 -500 333 -427 640 -640 480 -640 480 -640 480 -640 359 -640 427 -640 532 -640 428 -640 426 -640 427 -375 500 -640 480 -640 427 -425 640 -640 446 -500 349 -640 427 -640 470 -640 421 -640 427 -640 426 -640 428 -640 480 -640 426 -640 480 -640 427 -640 425 -640 426 -640 425 -291 461 -640 480 -640 435 -480 640 -640 426 -640 425 -500 375 -480 640 -640 381 -500 375 -640 480 -335 500 -640 427 -333 500 -601 640 -640 428 -640 426 -480 640 -640 477 -640 240 -640 427 -640 424 -640 429 -480 640 -500 402 -480 640 -640 480 -480 640 -640 214 -640 427 -375 500 -640 480 -426 640 -640 480 -640 427 -500 242 -500 375 -640 569 -427 640 -500 333 -489 640 -500 375 -611 640 -640 438 -480 640 -529 640 -640 426 -640 480 -480 640 -500 333 -640 480 -640 454 -640 478 -500 376 -500 500 -500 415 -640 413 -515 640 -427 640 -640 427 -480 640 -468 640 -640 480 -500 359 -640 480 -640 480 -640 490 -640 427 -640 480 -640 480 -640 427 -375 500 -640 480 -427 640 -640 480 -640 480 -427 640 -333 500 -640 426 -640 425 -640 427 -640 480 -640 517 -375 500 -480 640 -640 360 -640 425 -640 426 -640 433 -640 480 -640 426 -612 612 -640 426 -640 427 -480 640 -640 427 -640 474 -640 426 -640 481 -500 374 -480 640 -640 427 -427 640 -500 336 -640 473 -640 383 -640 423 -640 480 -640 428 -500 375 -536 640 -640 427 -640 480 -640 427 -612 612 -640 480 -640 427 -640 480 -500 375 -640 461 -640 360 -425 640 -640 480 -426 640 -640 450 -640 428 -333 500 -640 427 -640 396 -640 477 -640 428 -640 480 -640 635 -640 480 -640 480 -640 480 -640 401 -640 480 -640 427 -640 426 -640 427 -640 427 -640 428 -581 640 -640 427 -427 640 -640 428 -640 480 -640 480 -640 478 -480 640 -640 480 -640 427 -640 427 -612 612 -640 576 -424 640 -612 612 -500 375 -640 480 -640 381 -640 434 -500 437 -640 456 -640 425 -640 427 -427 640 -640 429 -640 480 -640 478 -448 640 -640 480 -640 428 -640 480 -480 640 -640 425 -640 427 -640 429 -640 418 -640 360 -556 640 -269 451 -450 338 -328 500 -333 500 -480 640 -640 428 -640 380 -640 480 -640 428 -640 525 -640 427 -640 427 -640 480 -480 640 -640 479 -640 426 -640 425 -480 640 -640 426 -640 480 -612 612 -548 640 -612 612 -640 480 -640 411 -640 426 -640 480 -640 427 -640 438 -640 478 -640 427 -640 428 -640 427 -640 419 -509 640 -640 334 -640 427 -640 480 -640 426 -640 427 -480 640 -640 426 -513 640 -500 374 -640 501 -640 346 -640 360 -640 480 -500 400 -500 388 -640 480 -480 640 -500 375 -640 427 -500 400 -640 424 -491 500 -640 428 -640 480 -640 427 -426 640 -427 640 -640 451 -375 500 -640 480 -500 333 -367 490 -500 375 -640 427 -480 640 -640 480 -640 427 -640 480 -500 399 -640 480 -640 470 -640 427 -375 500 -640 426 -640 482 -640 480 -640 417 -462 640 -640 428 -640 480 -640 427 -612 612 -640 640 -640 362 -480 640 -640 427 -640 480 -640 426 -640 427 -640 428 -640 426 -640 480 -500 375 -640 480 -640 441 -640 451 -640 478 -640 480 -640 384 -427 640 -640 480 -500 459 -640 370 -426 640 -640 445 -640 480 -640 553 -640 383 -640 428 -640 427 -640 424 -427 640 -640 480 -640 427 -640 360 -640 428 -612 612 -640 480 -640 480 -640 425 -427 640 -640 426 -500 273 -640 427 -480 640 -500 332 -640 480 -640 480 -640 427 -429 640 -640 480 -640 424 -333 500 -640 427 -640 431 -500 375 -640 427 -478 640 -424 640 -396 640 -640 425 -640 480 -425 640 -640 480 -640 427 -640 426 -640 427 -500 422 -640 455 -640 427 -479 640 -418 500 -333 500 -640 480 -640 480 -640 426 -640 426 -640 425 -500 334 -480 640 -502 640 -500 375 -640 551 -640 361 -500 333 -424 640 -640 360 -640 427 -640 427 -341 500 -375 500 -640 512 -640 424 -640 427 -427 640 -640 480 -640 427 -640 424 -640 480 -640 480 -640 480 -640 426 -441 640 -640 480 -640 480 -640 420 -640 427 -640 427 -480 640 -640 426 -640 427 -640 379 -640 508 -640 480 -480 640 -640 358 -640 480 -640 478 -400 600 -427 640 -375 500 -640 439 -640 427 -640 426 -640 425 -640 480 -640 480 -640 480 -478 640 -640 480 -640 480 -480 640 -440 640 -640 229 -640 425 -640 428 -640 480 -612 612 -640 426 -480 640 -640 457 -640 480 -640 426 -640 427 -640 426 -640 400 -640 631 -640 427 -538 640 -640 480 -640 426 -640 427 -640 427 -640 480 -640 426 -640 480 -325 500 -640 427 -640 287 -480 360 -500 500 -640 482 -612 612 -640 425 -640 480 -640 426 -640 427 -640 480 -428 640 -640 424 -500 375 -480 640 -612 612 -480 640 -640 480 -640 427 -480 640 -410 500 -480 640 -640 360 -640 427 -640 401 -640 427 -640 426 -640 421 -500 375 -640 424 -640 427 -427 640 -640 480 -640 426 -429 640 -640 480 -375 500 -640 478 -427 640 -640 480 -480 640 -640 480 -640 480 -640 426 -375 500 -640 422 -640 426 -500 375 -640 480 -640 480 -640 480 -640 428 -513 640 -640 427 -640 424 -640 480 -640 480 -640 640 -640 512 -640 480 -640 506 -500 375 -500 375 -480 640 -640 480 -480 640 -500 329 -640 495 -369 500 -605 640 -500 375 -425 640 -640 480 -480 640 -640 428 -500 375 -640 427 -640 427 -640 427 -640 480 -640 608 -640 360 -640 480 -640 480 -640 480 -640 480 -640 444 -640 427 -640 421 -640 442 -427 640 -612 612 -640 480 -640 360 -480 640 -375 500 -480 640 -640 426 -640 498 -640 480 -640 427 -640 426 -640 480 -500 377 -160 120 -640 428 -500 333 -640 410 -480 640 -640 425 -640 426 -640 424 -640 426 -465 640 -640 480 -640 427 -500 375 -480 640 -640 480 -640 428 -640 480 -500 334 -640 426 -640 427 -640 480 -500 333 -640 429 -426 640 -640 426 -500 375 -500 281 -640 639 -500 313 -278 240 -640 427 -640 480 -640 440 -640 480 -640 480 -640 480 -426 640 -640 480 -640 426 -480 640 -640 427 -480 640 -426 640 -640 360 -640 479 -640 424 -640 427 -431 640 -640 427 -640 258 -640 480 -640 426 -480 640 -640 427 -640 480 -640 480 -426 640 -428 640 -640 480 -640 383 -640 425 -640 426 -640 480 -640 480 -425 640 -640 499 -480 640 -640 426 -640 379 -480 640 -640 427 -640 427 -640 427 -640 427 -640 444 -640 480 -500 500 -640 480 -640 480 -640 480 -640 480 -427 640 -640 593 -500 333 -640 427 -640 480 -640 427 -640 608 -612 612 -640 480 -640 480 -480 640 -640 480 -640 480 -240 360 -640 427 -640 480 -640 411 -640 428 -427 640 -333 500 -640 480 -500 375 -500 425 -640 480 -640 480 -612 612 -427 640 -500 453 -640 426 -640 480 -640 427 -640 479 -640 480 -640 351 -640 480 -640 420 -640 428 -640 427 -500 375 -640 446 -640 480 -640 424 -420 640 -429 640 -640 448 -640 426 -500 321 -375 500 -640 480 -640 470 -640 427 -375 500 -640 480 -500 375 -640 461 -360 640 -640 427 -428 640 -640 480 -640 374 -640 480 -640 427 -640 427 -640 427 -500 375 -640 432 -640 480 -247 500 -640 145 -640 427 -480 640 -640 427 -640 429 -640 568 -500 334 -500 375 -640 500 -640 480 -640 512 -640 480 -612 612 -640 426 -640 426 -640 427 -640 394 -640 480 -480 640 -480 640 -640 427 -640 406 -480 640 -640 426 -640 511 -640 428 -500 333 -500 363 -640 427 -640 427 -488 640 -640 480 -640 427 -640 427 -640 511 -500 375 -427 640 -640 427 -640 464 -640 480 -425 640 -640 464 -427 640 -640 480 -480 640 -640 480 -640 480 -640 480 -640 480 -640 425 -500 375 -640 418 -640 427 -480 640 -273 500 -312 462 -640 396 -640 428 -427 640 -250 333 -640 424 -511 640 -640 425 -640 428 -500 375 -640 480 -375 500 -500 375 -640 444 -640 480 -640 427 -396 640 -400 300 -640 480 -640 512 -582 640 -640 480 -640 480 -640 427 -500 375 -640 425 -427 640 -640 428 -640 480 -500 375 -640 509 -640 427 -640 425 -597 640 -612 612 -640 561 -640 480 -640 480 -640 405 -612 612 -480 640 -640 480 -480 640 -640 480 -640 425 -640 427 -500 375 -640 371 -640 478 -640 569 -500 375 -640 419 -640 426 -640 480 -424 640 -480 640 -640 419 -640 579 -640 512 -640 360 -612 612 -640 427 -640 426 -500 318 -640 480 -480 640 -500 385 -640 480 -640 480 -640 512 -640 480 -640 480 -640 539 -480 640 -640 640 -640 480 -640 360 -640 427 -500 375 -600 400 -427 640 -640 480 -640 480 -640 401 -640 427 -640 427 -640 480 -481 640 -306 500 -640 426 -640 433 -640 449 -640 480 -640 480 -581 640 -640 480 -640 478 -612 612 -560 640 -480 640 -640 480 -427 640 -640 480 -640 400 -375 500 -640 427 -640 480 -640 374 -334 500 -612 612 -500 334 -640 544 -640 480 -640 480 -640 471 -640 400 -612 612 -640 427 -640 479 -640 480 -500 375 -640 480 -612 612 -640 533 -640 427 -640 423 -356 500 -640 480 -500 371 -640 480 -640 480 -640 426 -640 427 -640 425 -640 425 -640 480 -640 480 -640 480 -640 424 -370 640 -640 425 -375 500 -640 145 -640 361 -500 332 -500 375 -640 335 -640 397 -640 521 -500 363 -479 640 -500 375 -640 480 -500 345 -640 480 -640 480 -640 480 -500 364 -640 427 -612 612 -480 640 -640 427 -640 483 -640 480 -640 427 -500 360 -640 427 -640 469 -480 640 -640 480 -640 427 -640 480 -640 427 -640 426 -480 640 -640 480 -640 404 -640 405 -640 426 -640 427 -640 228 -500 375 -426 640 -640 423 -640 428 -640 427 -640 361 -640 480 -433 640 -464 640 -640 480 -640 424 -433 500 -640 480 -640 428 -640 480 -640 473 -640 480 -500 331 -640 480 -640 360 -640 480 -640 480 -640 427 -375 500 -442 640 -450 600 -640 427 -480 640 -500 386 -640 480 -640 424 -640 457 -640 480 -427 640 -427 640 -363 640 -640 480 -640 426 -640 448 -481 640 -427 640 -480 640 -640 480 -640 427 -640 480 -640 425 -640 427 -500 375 -640 480 -640 425 -640 427 -500 375 -640 480 -480 640 -500 333 -640 427 -480 640 -640 480 -450 200 -640 480 -640 427 -480 640 -640 480 -427 640 -480 640 -640 459 -426 640 -640 427 -500 344 -640 427 -640 360 -500 333 -500 375 -640 523 -640 480 -640 424 -640 480 -640 439 -427 640 -640 480 -640 427 -432 308 -640 480 -640 480 -427 640 -499 640 -612 612 -640 480 -640 427 -640 480 -640 480 -426 640 -640 480 -640 426 -640 480 -427 640 -500 375 -640 427 -480 640 -640 458 -640 434 -500 375 -640 427 -640 429 -640 480 -640 480 -640 480 -640 428 -640 480 -640 427 -640 430 -622 640 -409 640 -640 480 -640 640 -640 423 -640 360 -640 430 -640 427 -640 563 -640 427 -640 423 -480 640 -640 480 -478 640 -612 612 -427 640 -640 427 -640 320 -640 427 -500 375 -640 427 -427 640 -640 478 -640 425 -500 375 -640 427 -640 478 -640 427 -375 500 -480 640 -480 640 -640 480 -640 640 -427 640 -640 480 -428 640 -640 405 -640 426 -640 480 -640 427 -640 491 -640 427 -640 480 -612 612 -640 427 -480 640 -640 427 -640 480 -640 427 -480 640 -376 500 -640 480 -640 480 -640 480 -480 640 -640 360 -640 480 -640 480 -427 640 -500 375 -640 466 -640 569 -640 385 -427 640 -640 428 -640 439 -500 350 -375 500 -500 375 -500 375 -625 640 -640 480 -500 332 -640 480 -333 500 -480 640 -640 427 -640 427 -640 426 -480 640 -481 640 -500 438 -480 640 -640 359 -640 418 -426 640 -500 375 -480 640 -480 640 -640 427 -640 480 -640 427 -463 500 -640 425 -426 640 -640 427 -288 216 -640 480 -640 480 -640 640 -640 427 -500 334 -640 480 -640 480 -640 480 -640 480 -640 408 -483 640 -640 428 -640 402 -640 425 -336 500 -640 426 -428 640 -640 330 -480 640 -640 425 -480 640 -640 426 -478 640 -640 449 -640 427 -500 334 -640 478 -500 375 -290 379 -640 427 -640 480 -640 480 -640 480 -640 369 -640 427 -500 321 -426 640 -640 427 -640 480 -640 480 -640 428 -500 375 -424 640 -612 612 -640 427 -500 266 -640 400 -480 640 -640 640 -640 480 -640 480 -500 375 -534 640 -640 427 -640 480 -427 640 -640 427 -640 480 -640 427 -640 360 -425 640 -480 640 -640 480 -640 480 -640 428 -427 640 -425 640 -433 640 -640 480 -640 480 -640 451 -375 500 -640 407 -640 480 -640 480 -416 640 -640 427 -480 640 -640 383 -640 614 -640 554 -500 333 -459 640 -640 427 -640 428 -640 428 -373 640 -625 640 -640 480 -640 480 -500 375 -500 375 -640 480 -528 640 -640 427 -640 480 -375 500 -640 426 -640 427 -640 427 -419 640 -640 427 -640 480 -640 480 -640 396 -640 480 -500 374 -640 428 -640 373 -640 202 -640 480 -640 425 -640 427 -640 424 -640 360 -640 427 -640 480 -640 480 -640 480 -640 427 -500 332 -640 480 -640 480 -480 640 -640 480 -640 480 -640 558 -640 480 -640 480 -426 640 -640 427 -612 612 -640 359 -480 640 -640 424 -640 480 -480 640 -612 612 -640 480 -640 480 -640 480 -500 333 -500 375 -640 425 -640 428 -640 439 -640 427 -640 360 -383 640 -640 427 -640 480 -640 322 -480 360 -426 640 -640 428 -480 640 -597 640 -640 428 -480 640 -640 446 -640 427 -640 480 -480 640 -640 527 -640 427 -640 480 -640 426 -604 640 -360 640 -360 640 -640 425 -640 480 -640 640 -640 388 -480 640 -640 427 -640 426 -500 375 -503 640 -640 427 -640 426 -640 480 -640 427 -640 499 -640 480 -640 428 -640 480 -640 425 -640 427 -640 427 -612 612 -480 640 -480 640 -640 427 -640 427 -490 640 -640 454 -640 480 -640 424 -640 428 -640 480 -640 480 -640 431 -640 478 -640 431 -427 640 -640 426 -640 360 -640 480 -640 480 -640 480 -640 480 -640 460 -490 640 -640 427 -640 480 -640 428 -640 480 -454 640 -640 403 -426 640 -640 320 -640 427 -640 393 -640 427 -612 612 -640 480 -640 480 -500 375 -620 463 -427 640 -612 612 -640 480 -640 640 -427 640 -480 640 -500 375 -446 335 -409 307 -640 426 -640 495 -640 480 -640 427 -640 480 -640 218 -640 425 -512 640 -640 480 -480 640 -489 640 -432 324 -640 424 -428 640 -640 427 -640 427 -640 427 -640 427 -500 347 -427 640 -640 427 -640 427 -640 426 -640 568 -463 640 -480 640 -640 271 -500 324 -480 640 -640 480 -640 375 -640 457 -480 640 -640 427 -640 500 -500 500 -640 480 -640 427 -640 428 -640 480 -640 427 -640 482 -640 480 -480 640 -333 500 -640 424 -427 640 -478 640 -640 424 -427 640 -640 424 -640 480 -457 640 -452 640 -640 425 -500 400 -500 375 -640 442 -225 300 -500 333 -639 640 -640 640 -640 478 -640 480 -640 480 -375 500 -629 640 -500 357 -640 427 -640 383 -500 375 -450 640 -640 426 -640 423 -426 640 -640 426 -426 640 -640 480 -640 480 -640 436 -500 375 -640 427 -640 480 -640 427 -640 480 -640 480 -640 480 -480 640 -480 640 -375 500 -480 640 -640 480 -640 433 -640 427 -433 640 -640 429 -640 480 -640 427 -500 333 -514 640 -640 480 -640 490 -640 427 -640 296 -457 640 -640 518 -640 480 -640 480 -350 232 -612 612 -640 425 -640 427 -640 480 -640 480 -640 383 -500 335 -640 424 -640 427 -640 480 -640 426 -431 640 -500 377 -640 512 -640 427 -426 640 -640 425 -640 480 -640 426 -640 427 -640 480 -500 333 -427 640 -640 429 -640 346 -640 427 -640 427 -640 427 -640 481 -640 480 -496 640 -427 640 -640 484 -639 640 -500 375 -640 427 -427 640 -640 480 -425 640 -640 284 -500 422 -640 512 -480 640 -375 500 -640 533 -640 426 -480 640 -640 413 -640 359 -640 513 -480 640 -640 366 -640 490 -640 480 -501 640 -640 424 -640 427 -640 425 -640 427 -500 308 -640 427 -500 333 -640 480 -640 427 -640 480 -640 480 -640 427 -640 428 -640 427 -640 480 -480 640 -640 427 -375 500 -640 432 -640 480 -640 427 -428 640 -640 427 -640 430 -640 480 -375 500 -640 480 -480 640 -640 640 -427 640 -640 480 -500 381 -406 640 -640 441 -333 500 -640 546 -640 480 -640 480 -500 375 -640 535 -640 426 -640 503 -640 434 -640 480 -546 366 -600 400 -640 429 -640 481 -640 480 -333 500 -640 427 -427 640 -427 640 -480 640 -640 439 -500 375 -553 640 -640 480 -639 640 -640 425 -640 480 -640 427 -640 480 -640 427 -500 333 -640 424 -512 640 -640 426 -640 359 -436 640 -640 428 -640 428 -640 426 -426 640 -480 640 -640 427 -640 427 -612 612 -640 380 -640 427 -640 427 -480 640 -640 480 -612 612 -427 640 -272 480 -640 166 -612 612 -427 640 -640 426 -640 480 -419 640 -640 426 -640 480 -640 427 -640 451 -640 427 -640 427 -640 427 -427 640 -500 375 -640 343 -640 428 -500 375 -640 427 -640 489 -640 373 -640 435 -500 375 -460 640 -640 428 -640 428 -640 411 -640 400 -288 432 -640 427 -640 480 -500 375 -640 426 -640 480 -333 500 -640 427 -500 331 -640 461 -480 640 -500 332 -640 330 -640 533 -427 640 -411 500 -492 640 -640 480 -500 419 -640 427 -359 640 -640 422 -213 318 -640 359 -640 480 -640 427 -500 500 -375 500 -640 480 -640 426 -640 428 -640 360 -640 402 -640 457 -500 364 -640 479 -640 480 -640 478 -457 640 -640 480 -640 480 -640 427 -640 428 -640 425 -500 375 -640 457 -640 478 -500 333 -357 500 -640 428 -418 500 -640 427 -480 640 -500 375 -640 426 -426 640 -640 458 -500 375 -500 375 -640 426 -640 398 -640 427 -640 427 -640 427 -426 640 -640 427 -640 480 -640 427 -640 360 -640 426 -640 480 -640 425 -640 426 -640 428 -640 360 -363 640 -640 480 -640 480 -640 480 -500 377 -428 640 -480 640 -640 481 -640 427 -428 640 -480 640 -640 427 -640 426 -480 640 -427 640 -640 466 -640 425 -640 423 -640 429 -640 480 -500 375 -424 640 -500 333 -500 333 -640 424 -612 612 -480 640 -425 640 -427 640 -640 344 -640 426 -640 427 -640 480 -640 480 -480 640 -640 480 -640 427 -640 480 -640 426 -640 427 -640 480 -640 484 -640 407 -640 448 -640 427 -640 427 -640 360 -640 427 -640 448 -640 480 -640 480 -640 480 -425 640 -640 480 -640 427 -640 425 -500 334 -640 426 -480 640 -640 480 -640 480 -640 427 -428 640 -640 428 -640 512 -429 640 -640 360 -640 480 -480 640 -640 480 -640 480 -640 480 -640 283 -640 479 -640 427 -640 425 -500 333 -640 369 -500 376 -640 480 -333 500 -612 612 -427 640 -480 640 -399 500 -640 480 -640 480 -640 348 -640 480 -640 480 -640 456 -427 640 -281 500 -480 640 -640 429 -640 478 -640 427 -640 453 -640 432 -622 640 -640 480 -640 425 -640 428 -640 427 -640 426 -640 480 -640 544 -640 427 -619 640 -480 640 -480 640 -640 480 -640 427 -640 640 -640 419 -370 640 -640 480 -375 500 -640 337 -448 336 -640 432 -500 333 -640 432 -500 375 -640 429 -500 349 -640 433 -640 480 -640 640 -640 480 -500 375 -640 480 -424 640 -640 508 -640 480 -640 480 -480 640 -640 480 -640 640 -640 480 -636 640 -640 480 -640 424 -640 327 -332 500 -480 640 -427 640 -640 425 -640 343 -640 480 -640 480 -640 428 -640 480 -375 500 -424 640 -511 640 -640 480 -640 480 -640 480 -500 375 -640 427 -480 640 -500 375 -640 464 -640 202 -640 426 -500 375 -640 480 -428 640 -640 478 -640 480 -395 500 -640 480 -500 375 -640 480 -479 640 -436 640 -480 640 -500 333 -640 430 -500 376 -640 480 -427 640 -640 428 -640 480 -640 480 -640 480 -333 500 -427 640 -640 426 -640 480 -640 480 -640 480 -640 427 -436 500 -640 453 -640 427 -640 427 -449 640 -534 640 -640 480 -426 640 -480 549 -640 320 -600 322 -467 500 -640 480 -640 480 -500 400 -640 423 -640 427 -640 480 -500 375 -500 302 -500 332 -640 480 -612 612 -640 432 -640 480 -640 427 -500 335 -360 640 -640 480 -640 428 -640 480 -427 640 -640 427 -640 511 -640 474 -500 375 -640 425 -640 427 -425 640 -640 428 -640 480 -640 426 -640 427 -640 360 -640 427 -500 391 -596 640 -640 427 -573 640 -640 480 -640 387 -640 427 -640 480 -640 427 -640 425 -640 372 -640 480 -375 500 -480 640 -426 640 -640 480 -640 480 -500 375 -640 426 -480 640 -333 500 -500 375 -640 428 -640 427 -640 480 -640 360 -427 640 -640 425 -640 427 -640 383 -500 375 -411 500 -640 434 -500 375 -640 427 -640 419 -640 428 -640 480 -640 480 -500 375 -480 640 -640 427 -640 509 -640 480 -640 421 -399 600 -640 480 -640 427 -640 429 -640 427 -500 375 -640 427 -640 427 -480 640 -640 426 -640 480 -375 500 -640 426 -640 413 -480 640 -333 500 -480 640 -640 415 -334 500 -431 640 -640 427 -640 426 -469 640 -640 480 -375 500 -612 612 -640 427 -640 478 -500 375 -640 443 -640 184 -640 406 -413 640 -640 427 -500 376 -640 427 -424 640 -373 500 -640 469 -640 427 -640 640 -480 640 -640 640 -640 478 -640 480 -640 426 -500 444 -640 426 -480 640 -640 427 -614 640 -640 426 -427 640 -600 464 -640 427 -464 640 -500 375 -640 427 -640 480 -449 640 -640 480 -480 640 -640 480 -640 480 -480 640 -640 408 -533 640 -640 426 -427 640 -640 396 -428 640 -640 480 -640 480 -640 480 -500 500 -335 500 -640 480 -427 640 -640 365 -427 640 -640 360 -508 640 -640 539 -640 428 -640 427 -500 375 -612 612 -640 424 -640 491 -640 425 -640 427 -640 480 -600 450 -359 640 -480 640 -640 480 -640 480 -640 480 -500 375 -390 500 -480 640 -480 640 -640 367 -640 480 -640 389 -426 640 -640 480 -480 640 -427 640 -470 308 -640 427 -640 427 -640 315 -640 480 -500 332 -640 480 -480 640 -500 333 -640 425 -480 640 -480 640 -640 480 -500 409 -640 427 -640 419 -480 640 -640 426 -640 427 -640 364 -500 375 -640 480 -480 640 -500 439 -500 333 -500 307 -640 480 -480 640 -427 640 -640 408 -640 475 -640 427 -640 428 -640 427 -640 408 -480 640 -500 375 -500 281 -640 428 -640 469 -480 640 -500 399 -612 612 -612 612 -612 612 -640 426 -500 335 -640 356 -375 500 -640 480 -426 640 -640 427 -640 426 -640 427 -480 640 -640 639 -500 375 -480 640 -612 612 -640 480 -640 448 -640 428 -640 480 -640 427 -543 640 -500 375 -640 427 -640 426 -640 359 -426 640 -478 640 -480 640 -640 428 -640 427 -640 426 -640 427 -640 427 -640 480 -500 340 -480 640 -640 480 -640 427 -640 480 -427 640 -640 480 -640 425 -640 427 -640 482 -500 333 -500 368 -640 427 -425 640 -640 480 -500 375 -640 428 -640 480 -640 423 -640 558 -250 234 -640 427 -478 640 -640 426 -640 427 -640 427 -426 640 -640 480 -428 640 -640 480 -640 480 -640 480 -640 399 -640 427 -640 439 -640 264 -500 375 -612 612 -640 427 -500 350 -427 640 -334 500 -500 332 -500 281 -325 500 -500 318 -480 640 -640 480 -375 500 -640 426 -640 614 -500 400 -487 640 -640 427 -640 427 -640 513 -478 640 -640 480 -500 375 -500 343 -500 375 -640 425 -640 417 -500 375 -640 427 -640 427 -640 427 -640 441 -640 426 -640 427 -640 480 -640 427 -640 383 -640 425 -635 640 -640 480 -640 355 -480 640 -640 427 -500 375 -640 480 -640 429 -640 480 -640 427 -640 480 -640 480 -640 427 -482 500 -480 640 -478 640 -640 426 -640 480 -640 424 -640 480 -630 640 -640 480 -640 480 -335 500 -480 640 -640 427 -640 480 -640 433 -640 423 -640 480 -640 480 -375 500 -640 480 -640 457 -480 640 -640 480 -640 480 -640 427 -500 375 -504 640 -640 480 -512 640 -471 640 -426 640 -319 480 -640 480 -500 371 -640 480 -640 480 -640 480 -500 375 -378 500 -427 640 -640 483 -640 541 -640 426 -640 381 -500 375 -640 423 -640 359 -640 631 -640 480 -400 600 -371 500 -640 480 -500 371 -640 480 -640 427 -478 640 -640 427 -380 500 -427 640 -500 375 -640 427 -600 600 -427 640 -640 427 -640 427 -356 500 -640 513 -482 640 -375 500 -640 480 -640 320 -612 612 -640 480 -640 640 -640 424 -480 640 -640 427 -427 640 -640 494 -639 640 -640 360 -478 640 -640 360 -640 426 -640 427 -640 427 -640 480 -640 439 -640 480 -640 427 -640 480 -640 360 -640 480 -640 480 -640 251 -640 433 -640 466 -640 480 -480 640 -640 480 -640 444 -427 640 -640 424 -480 640 -640 424 -640 458 -640 427 -424 640 -640 426 -480 640 -640 640 -473 305 -640 427 -461 640 -640 427 -478 640 -640 463 -640 480 -640 427 -640 425 -640 480 -640 360 -640 583 -500 344 -640 426 -640 425 -640 480 -413 640 -640 478 -427 640 -640 480 -424 640 -640 425 -480 640 -640 394 -640 427 -496 640 -427 640 -500 375 -640 426 -480 640 -640 429 -612 612 -640 416 -640 283 -480 640 -375 500 -427 640 -640 426 -640 424 -640 593 -640 427 -640 453 -640 429 -266 640 -640 426 -640 427 -640 499 -640 428 -640 425 -612 612 -480 640 -500 375 -375 500 -500 384 -500 333 -640 427 -640 458 -640 428 -640 467 -640 478 -640 427 -640 429 -640 426 -500 375 -640 480 -640 396 -640 512 -334 500 -480 640 -480 640 -640 427 -640 359 -640 480 -426 640 -375 500 -640 480 -640 480 -500 375 -640 434 -640 427 -640 425 -640 480 -640 457 -426 640 -375 500 -640 480 -640 344 -640 480 -640 455 -500 400 -640 427 -480 640 -640 480 -640 426 -375 500 -640 542 -500 332 -480 640 -640 427 -640 427 -426 640 -640 512 -640 500 -640 431 -640 609 -640 480 -640 478 -640 427 -640 640 -640 427 -640 427 -640 480 -640 424 -640 480 -640 480 -640 480 -480 640 -640 480 -383 640 -640 427 -640 480 -640 427 -640 480 -640 427 -640 480 -640 480 -640 480 -478 640 -640 480 -640 480 -640 427 -640 480 -640 428 -640 480 -640 427 -244 500 -426 640 -513 640 -640 480 -640 480 -640 427 -640 480 -640 480 -428 640 -640 368 -500 341 -640 426 -612 612 -640 428 -640 479 -640 427 -480 640 -640 480 -640 424 -480 640 -640 480 -640 429 -640 427 -640 427 -640 426 -640 480 -640 427 -500 375 -500 328 -640 480 -500 333 -640 427 -640 480 -640 392 -427 640 -640 640 -640 429 -480 640 -640 337 -306 500 -640 426 -427 640 -640 480 -640 427 -640 427 -500 381 -375 500 -640 472 -640 480 -500 375 -640 424 -640 480 -500 375 -480 640 -640 427 -640 480 -640 480 -500 383 -640 480 -480 640 -640 399 -612 612 -640 480 -500 375 -640 427 -500 375 -640 427 -640 427 -480 640 -640 480 -427 640 -640 427 -640 427 -346 500 -640 480 -500 400 -640 360 -478 640 -640 413 -375 500 -640 427 -640 424 -640 426 -640 425 -480 640 -478 640 -410 500 -640 640 -640 480 -500 345 -427 640 -640 419 -640 480 -640 406 -500 375 -640 528 -426 640 -359 640 -640 427 -640 428 -480 640 -500 333 -640 369 -400 535 -489 640 -480 640 -640 480 -640 480 -500 375 -640 480 -456 640 -500 375 -640 480 -640 428 -427 640 -640 425 -480 640 -640 427 -640 420 -333 500 -640 427 -428 640 -640 480 -480 640 -640 450 -640 384 -640 480 -425 640 -480 640 -500 351 -640 480 -640 562 -640 428 -640 480 -500 372 -423 640 -640 426 -640 480 -480 640 -640 426 -640 403 -640 480 -640 480 -640 480 -500 434 -427 640 -480 640 -640 424 -640 480 -480 640 -640 428 -547 640 -500 335 -640 360 -640 400 -640 427 -448 640 -500 376 -500 375 -640 481 -640 480 -640 426 -640 480 -640 478 -640 480 -640 423 -500 375 -640 200 -640 480 -600 450 -640 399 -640 480 -640 426 -640 480 -640 480 -640 480 -640 358 -480 640 -640 426 -640 428 -480 640 -640 640 -461 640 -640 480 -640 480 -640 480 -639 640 -428 640 -612 612 -640 404 -640 427 -640 427 -612 612 -640 427 -640 480 -449 640 -480 640 -640 428 -640 480 -333 500 -640 480 -500 385 -640 426 -500 375 -640 480 -640 427 -640 425 -640 427 -640 480 -640 426 -640 480 -640 480 -640 481 -640 480 -640 480 -640 428 -640 427 -427 640 -480 640 -425 640 -333 500 -640 503 -480 640 -640 427 -640 388 -640 426 -538 640 -500 375 -427 640 -640 424 -500 391 -640 231 -640 427 -640 480 -640 480 -612 612 -640 480 -426 640 -640 425 -640 478 -640 427 -640 427 -640 547 -640 360 -612 612 -640 480 -500 334 -431 500 -374 500 -640 428 -640 400 -633 640 -333 500 -640 462 -566 640 -640 359 -500 332 -425 640 -375 500 -640 425 -500 335 -640 480 -612 612 -640 425 -640 426 -487 640 -500 375 -640 424 -640 427 -640 480 -500 334 -640 427 -500 341 -640 480 -640 399 -480 640 -375 500 -480 640 -640 428 -500 334 -640 480 -640 427 -457 640 -500 375 -640 409 -375 500 -640 480 -640 480 -500 375 -375 500 -427 640 -480 640 -640 475 -640 480 -640 425 -500 375 -640 360 -500 332 -640 450 -640 480 -640 426 -500 375 -640 480 -640 480 -640 425 -640 425 -426 640 -640 425 -640 480 -640 384 -640 427 -640 427 -640 253 -640 425 -394 640 -640 426 -640 426 -640 480 -640 427 -427 640 -426 640 -640 467 -640 480 -640 458 -500 500 -640 480 -500 375 -640 427 -480 640 -640 480 -640 480 -640 421 -640 480 -640 542 -640 480 -640 430 -640 469 -640 360 -640 480 -640 355 -640 480 -612 612 -640 480 -500 334 -640 427 -432 640 -640 416 -640 360 -468 640 -640 527 -640 570 -640 428 -480 640 -640 480 -640 427 -480 640 -640 426 -640 480 -500 375 -640 360 -424 640 -478 640 -640 428 -640 427 -240 320 -427 640 -375 500 -500 375 -566 640 -640 480 -640 427 -500 335 -640 427 -500 375 -640 612 -640 480 -426 640 -640 480 -640 385 -640 424 -640 427 -640 478 -640 426 -427 640 -500 375 -640 480 -640 480 -640 258 -640 429 -640 427 -640 480 -640 480 -640 480 -640 425 -500 333 -640 480 -640 501 -640 640 -612 612 -640 424 -500 375 -640 454 -500 375 -640 388 -427 640 -425 640 -500 375 -376 500 -640 425 -640 480 -500 375 -500 357 -640 480 -640 378 -500 375 -640 431 -640 427 -640 450 -612 612 -640 427 -640 427 -640 427 -612 612 -640 480 -567 476 -480 640 -424 640 -640 428 -640 480 -640 427 -640 480 -640 426 -640 427 -640 480 -640 480 -640 480 -640 427 -480 640 -640 427 -640 480 -400 538 -640 427 -500 375 -428 640 -640 384 -640 426 -480 640 -640 488 -427 640 -640 480 -640 427 -640 424 -427 640 -640 480 -480 640 -612 612 -640 480 -480 640 -427 640 -640 466 -640 480 -640 480 -461 640 -640 480 -640 480 -500 254 -640 425 -500 375 -480 640 -480 640 -640 405 -612 612 -480 640 -514 640 -640 480 -640 480 -640 480 -400 300 -640 509 -640 424 -426 640 -640 480 -640 512 -428 640 -480 640 -612 612 -401 500 -640 478 -640 480 -640 427 -640 427 -500 375 -640 480 -640 425 -457 640 -640 427 -640 395 -480 640 -640 427 -640 478 -640 480 -640 455 -640 536 -425 640 -640 480 -640 427 -427 640 -417 500 -500 333 -480 640 -640 427 -640 360 -640 427 -427 640 -640 363 -640 480 -612 612 -640 614 -640 480 -479 640 -334 640 -640 425 -480 640 -429 640 -640 480 -640 427 -640 480 -480 640 -480 640 -500 412 -471 600 -500 333 -640 480 -640 425 -640 389 -640 339 -640 428 -640 640 -500 335 -640 426 -640 426 -425 640 -427 640 -425 640 -640 428 -427 640 -640 480 -640 427 -427 640 -640 282 -480 640 -500 281 -333 500 -458 640 -640 426 -426 640 -640 427 -640 425 -427 640 -640 480 -480 640 -640 485 -640 480 -480 640 -640 426 -427 640 -480 640 -500 326 -640 427 -640 480 -362 500 -640 480 -640 427 -332 500 -602 640 -640 480 -640 480 -480 640 -640 480 -640 427 -640 425 -640 480 -640 480 -480 640 -413 478 -640 640 -640 446 -640 249 -640 458 -640 453 -426 640 -640 563 -640 640 -640 480 -640 427 -425 640 -640 426 -480 640 -640 480 -640 565 -640 640 -640 480 -640 427 -640 427 -426 640 -640 427 -480 640 -640 427 -640 480 -500 375 -612 612 -433 640 -512 640 -640 427 -640 424 -640 480 -500 332 -640 480 -640 480 -500 375 -500 333 -640 427 -640 480 -640 480 -480 640 -500 333 -640 421 -640 480 -640 427 -640 480 -640 424 -640 480 -612 612 -640 480 -640 480 -368 640 -640 480 -640 480 -640 480 -640 480 -640 480 -500 375 -640 428 -640 342 -500 375 -480 640 -640 427 -640 427 -640 424 -640 457 -500 375 -401 640 -480 640 -640 640 -640 478 -640 419 -500 391 -640 481 -640 427 -640 427 -640 480 -640 480 -480 640 -500 274 -640 446 -640 480 -480 640 -480 640 -640 640 -612 612 -640 445 -640 480 -500 334 -640 480 -640 427 -640 427 -640 426 -640 428 -640 425 -500 321 -640 427 -640 480 -640 426 -500 333 -640 480 -608 640 -640 424 -640 426 -226 135 -640 361 -640 427 -640 480 -480 640 -640 480 -612 612 -640 591 -640 417 -390 640 -432 640 -640 397 -481 640 -640 427 -511 640 -640 427 -640 426 -500 335 -640 512 -640 480 -426 640 -640 480 -375 500 -640 480 -640 426 -640 425 -640 427 -640 379 -640 480 -333 500 -480 640 -640 480 -640 360 -640 428 -640 560 -640 359 -640 428 -640 427 -640 640 -640 427 -480 640 -480 640 -334 500 -640 427 -640 428 -640 427 -640 509 -640 480 -640 480 -527 640 -509 640 -640 427 -612 612 -640 480 -640 424 -640 480 -640 480 -640 540 -640 427 -640 368 -640 427 -500 438 -427 640 -640 427 -640 426 -640 427 -612 612 -640 480 -480 640 -640 427 -640 480 -640 480 -480 640 -427 640 -500 333 -640 480 -360 640 -640 480 -640 290 -500 333 -427 640 -640 429 -640 616 -640 428 -640 427 -640 480 -640 465 -640 427 -640 427 -479 640 -500 375 -481 640 -640 480 -640 480 -500 286 -640 480 -500 375 -500 375 -640 480 -640 640 -640 424 -427 640 -640 359 -640 480 -427 640 -640 428 -612 612 -333 500 -640 427 -333 500 -640 480 -612 612 -500 337 -500 375 -480 640 -427 640 -640 476 -640 481 -640 427 -500 375 -640 480 -427 640 -640 480 -640 478 -640 425 -500 332 -640 640 -640 480 -640 425 -640 480 -640 409 -459 640 -478 640 -427 640 -640 480 -640 468 -640 480 -640 427 -500 449 -640 400 -640 360 -333 500 -480 640 -640 480 -640 480 -426 640 -640 415 -305 400 -640 480 -640 419 -640 480 -640 427 -640 425 -300 400 -470 353 -640 521 -612 612 -640 480 -640 512 -480 640 -640 640 -640 480 -500 366 -640 480 -333 500 -640 427 -640 480 -640 427 -427 640 -366 500 -640 427 -640 427 -640 480 -640 426 -640 480 -640 480 -640 480 -640 424 -500 375 -640 427 -640 463 -640 512 -640 480 -375 500 -400 400 -640 426 -640 481 -640 480 -336 248 -640 480 -480 640 -640 274 -640 480 -333 500 -480 640 -640 480 -640 427 -640 400 -640 427 -480 640 -427 640 -428 640 -500 333 -401 640 -480 640 -640 424 -640 480 -375 500 -379 640 -640 480 -480 640 -640 478 -375 500 -640 427 -360 640 -429 640 -500 333 -640 427 -480 640 -640 480 -640 415 -640 293 -620 640 -480 640 -375 500 -640 426 -640 360 -640 481 -640 427 -496 640 -360 640 -640 480 -640 427 -480 640 -640 480 -512 640 -476 640 -480 640 -494 640 -375 500 -640 360 -640 426 -640 428 -640 480 -640 425 -640 426 -640 374 -640 427 -640 480 -640 479 -640 426 -640 427 -640 427 -480 640 -446 640 -640 426 -640 480 -640 427 -640 385 -640 480 -640 488 -640 480 -427 640 -427 640 -640 426 -640 480 -389 500 -640 480 -640 480 -640 480 -425 640 -480 640 -300 225 -640 515 -640 426 -640 480 -640 505 -347 491 -640 385 -640 427 -500 335 -640 426 -640 427 -428 640 -640 452 -428 640 -640 427 -640 427 -427 640 -640 424 -640 480 -480 640 -640 427 -480 640 -640 480 -640 480 -640 427 -640 427 -640 425 -640 426 -640 426 -494 640 -427 640 -640 380 -640 480 -640 480 -427 640 -427 640 -333 500 -640 427 -480 640 -500 334 -640 640 -640 361 -426 640 -640 480 -640 480 -640 480 -640 425 -640 428 -640 480 -640 480 -640 480 -640 426 -640 479 -457 640 -640 424 -500 332 -334 500 -375 500 -640 478 -500 333 -640 480 -500 400 -640 428 -640 480 -427 640 -500 375 -500 334 -500 291 -640 480 -640 480 -640 480 -640 427 -640 510 -640 480 -640 480 -428 640 -480 640 -500 375 -640 480 -640 512 -640 275 -640 512 -640 424 -612 612 -426 640 -640 481 -375 500 -640 457 -640 427 -619 640 -640 427 -640 480 -500 375 -640 398 -640 480 -427 640 -500 375 -480 640 -427 640 -500 375 -640 426 -640 427 -480 640 -500 375 -640 413 -640 424 -480 640 -640 426 -640 480 -500 400 -521 640 -427 640 -640 462 -640 480 -640 480 -427 640 -500 347 -640 427 -640 427 -597 400 -640 426 -640 427 -640 480 -640 480 -640 431 -640 419 -640 479 -640 428 -480 640 -640 427 -640 428 -426 640 -640 311 -480 640 -640 427 -640 513 -640 424 -500 358 -480 640 -640 480 -300 426 -640 480 -377 640 -480 640 -427 640 -640 427 -640 425 -640 320 -640 480 -640 360 -427 640 -640 403 -640 425 -480 640 -640 426 -480 640 -428 640 -426 640 -640 427 -459 640 -369 500 -480 640 -640 480 -480 640 -480 640 -500 281 -640 425 -640 468 -640 440 -640 427 -640 534 -640 478 -640 482 -640 426 -500 375 -424 640 -640 331 -640 480 -541 640 -640 268 -640 427 -640 425 -513 640 -640 426 -640 527 -500 333 -640 427 -498 640 -612 612 -339 500 -640 427 -500 391 -480 640 -427 640 -500 333 -427 640 -640 480 -480 640 -640 422 -349 500 -480 640 -333 500 -640 425 -424 640 -640 427 -500 339 -640 425 -640 460 -478 640 -640 468 -640 427 -640 434 -640 427 -640 427 -640 426 -500 375 -640 427 -500 375 -640 388 -640 426 -375 500 -640 426 -640 426 -640 425 -426 640 -640 424 -387 500 -640 480 -427 640 -640 427 -640 427 -640 427 -640 480 -480 640 -425 640 -640 480 -640 640 -640 424 -612 612 -500 333 -500 375 -640 501 -640 480 -640 577 -640 480 -500 375 -425 640 -500 500 -640 426 -640 427 -640 426 -640 480 -640 428 -500 370 -640 360 -500 399 -500 333 -349 500 -640 427 -640 427 -480 640 -640 480 -640 263 -640 480 -447 640 -640 427 -640 317 -640 480 -428 640 -640 426 -480 640 -640 427 -640 480 -375 500 -640 512 -640 430 -480 640 -480 640 -480 640 -500 500 -500 287 -640 480 -640 426 -427 640 -426 640 -640 480 -640 427 -640 427 -375 500 -546 640 -320 240 -425 640 -500 335 -640 425 -640 367 -640 480 -640 427 -640 480 -478 640 -640 427 -640 391 -640 429 -640 480 -640 427 -640 384 -427 640 -640 360 -640 495 -640 478 -640 427 -640 480 -500 218 -640 480 -500 333 -640 480 -640 480 -427 640 -640 480 -640 426 -375 500 -640 427 -640 427 -640 428 -640 618 -480 640 -640 427 -640 427 -554 640 -640 427 -640 427 -640 480 -640 499 -640 427 -640 420 -640 480 -640 480 -425 640 -500 332 -640 480 -640 423 -408 640 -640 480 -529 640 -640 426 -640 480 -500 375 -640 427 -640 508 -500 375 -427 640 -640 480 -640 427 -612 612 -480 640 -640 251 -480 640 -612 612 -500 375 -426 640 -640 480 -480 640 -536 640 -640 480 -640 425 -640 467 -640 480 -438 640 -448 290 -480 640 -640 480 -640 426 -640 480 -640 480 -512 640 -630 630 -640 383 -426 640 -640 404 -500 333 -500 375 -500 327 -429 640 -640 480 -640 469 -640 426 -640 537 -640 359 -640 640 -640 480 -480 640 -640 427 -500 375 -444 640 -640 480 -640 427 -640 480 -640 480 -427 640 -480 640 -640 399 -480 640 -640 434 -640 480 -640 480 -640 480 -640 480 -640 480 -640 428 -640 427 -640 427 -640 480 -640 394 -640 482 -461 640 -640 480 -640 427 -640 469 -640 424 -640 480 -640 448 -640 262 -480 640 -425 640 -640 360 -500 375 -640 480 -640 480 -480 640 -640 429 -640 480 -640 480 -640 426 -640 565 -640 480 -480 640 -427 640 -640 426 -512 640 -500 375 -500 375 -500 333 -500 375 -429 640 -640 427 -480 640 -640 320 -500 500 -640 480 -640 427 -424 640 -640 480 -640 403 -640 425 -500 375 -500 334 -640 480 -640 615 -640 480 -640 426 -640 480 -640 427 -640 480 -375 500 -640 480 -640 385 -640 368 -640 427 -492 500 -640 480 -640 480 -640 442 -640 404 -640 480 -640 400 -427 640 -640 427 -640 480 -612 612 -427 640 -640 436 -330 500 -640 428 -640 480 -640 480 -640 436 -640 494 -640 360 -320 240 -640 427 -480 640 -640 427 -640 480 -640 480 -640 480 -375 500 -640 500 -640 640 -640 480 -640 426 -640 536 -640 398 -427 640 -640 427 -640 480 -640 426 -640 427 -640 480 -480 640 -427 640 -500 375 -640 404 -500 357 -480 640 -640 427 -640 480 -429 640 -640 480 -640 429 -640 426 -640 429 -427 640 -427 640 -640 473 -480 640 -333 500 -426 640 -480 640 -640 480 -640 480 -640 426 -640 480 -480 360 -500 321 -640 428 -640 427 -640 480 -640 480 -500 375 -427 640 -640 503 -427 640 -640 427 -424 640 -610 405 -640 426 -426 640 -640 474 -640 428 -480 640 -640 403 -640 480 -640 428 -640 427 -640 480 -527 640 -449 640 -640 426 -480 640 -640 430 -500 500 -640 480 -640 427 -640 445 -640 440 -640 478 -500 375 -640 427 -640 539 -640 479 -512 640 -640 480 -640 480 -500 375 -640 480 -500 375 -640 428 -640 478 -500 334 -424 640 -640 424 -640 423 -640 427 -375 500 -640 480 -640 427 -640 427 -427 640 -640 480 -640 427 -640 360 -640 427 -640 427 -428 640 -640 480 -640 428 -640 480 -500 333 -640 480 -425 640 -640 551 -640 511 -427 640 -640 425 -640 480 -612 612 -375 500 -490 367 -398 640 -640 480 -640 504 -640 480 -640 480 -518 640 -640 480 -640 427 -640 413 -640 394 -640 427 -640 427 -640 428 -448 336 -480 640 -500 332 -640 426 -427 640 -424 640 -480 640 -640 426 -478 640 -640 480 -640 360 -436 640 -500 375 -640 544 -427 640 -640 640 -425 640 -640 428 -640 428 -425 640 -480 640 -640 425 -640 425 -426 640 -640 427 -480 640 -640 427 -427 640 -435 640 -480 640 -500 379 -640 640 -640 427 -640 427 -640 480 -640 480 -480 640 -640 480 -640 326 -640 427 -640 480 -500 333 -640 425 -453 640 -480 640 -640 428 -640 428 -441 640 -426 640 -640 480 -640 486 -640 427 -500 375 -500 375 -640 428 -640 494 -324 432 -640 427 -640 428 -480 640 -320 480 -640 480 -640 422 -640 427 -640 405 -640 480 -432 640 -640 427 -640 480 -640 426 -640 475 -458 640 -640 427 -612 612 -640 360 -507 480 -640 427 -480 640 -640 480 -640 480 -640 360 -640 428 -427 640 -500 375 -427 640 -640 427 -640 478 -640 480 -640 480 -417 640 -640 424 -640 427 -640 480 -640 426 -640 512 -640 480 -640 480 -640 427 -480 361 -640 427 -480 640 -640 484 -375 500 -427 640 -480 640 -500 375 -416 640 -640 408 -640 609 -612 612 -640 480 -640 360 -500 499 -640 480 -640 427 -640 427 -640 426 -480 640 -500 375 -640 529 -500 375 -640 480 -640 480 -640 425 -640 480 -500 375 -640 470 -640 426 -500 375 -640 480 -640 426 -640 432 -640 424 -640 316 -640 429 -640 463 -640 480 -458 640 -640 480 -640 427 -640 480 -640 427 -640 425 -612 612 -480 640 -375 500 -640 480 -640 483 -427 640 -640 480 -640 512 -499 374 -233 640 -640 312 -640 480 -640 457 -640 445 -500 375 -640 425 -640 427 -427 640 -640 427 -640 427 -480 640 -640 480 -500 375 -640 480 -427 640 -640 480 -640 428 -640 480 -480 640 -640 640 -640 513 -640 422 -500 325 -426 640 -640 480 -480 640 -500 346 -375 500 -640 480 -640 424 -500 375 -640 456 -640 456 -640 436 -640 426 -640 480 -640 428 -640 437 -300 225 -429 640 -640 480 -640 480 -640 480 -375 500 -640 424 -640 480 -640 480 -640 427 -638 479 -640 316 -500 333 -640 481 -640 427 -640 480 -640 427 -480 640 -640 427 -640 480 -500 332 -640 427 -640 480 -640 431 -584 430 -640 361 -640 640 -500 333 -640 364 -640 480 -480 640 -640 480 -560 640 -640 480 -640 428 -427 640 -443 640 -640 428 -480 640 -640 427 -480 640 -640 427 -640 512 -425 640 -480 640 -480 640 -362 640 -640 379 -640 480 -640 407 -640 480 -640 480 -480 640 -640 480 -427 640 -640 428 -640 427 -375 500 -500 375 -640 480 -640 640 -500 336 -640 480 -361 640 -640 424 -160 120 -333 500 -640 427 -540 455 -640 426 -640 425 -640 425 -640 428 -333 500 -640 419 -640 425 -640 428 -640 480 -500 375 -640 420 -500 375 -480 640 -640 480 -640 424 -640 480 -640 322 -640 478 -640 427 -640 480 -480 640 -640 429 -640 453 -480 640 -500 337 -240 320 -480 640 -640 480 -640 428 -640 427 -640 428 -640 480 -637 640 -640 480 -640 640 -640 480 -640 482 -500 321 -500 375 -640 480 -640 480 -500 333 -426 640 -480 640 -640 427 -480 640 -640 427 -640 427 -640 427 -500 297 -640 423 -500 333 -640 427 -640 480 -500 375 -640 480 -500 364 -640 427 -640 480 -480 640 -500 376 -640 427 -500 375 -640 398 -640 480 -640 427 -640 480 -428 640 -640 413 -640 640 -640 427 -640 427 -640 480 -480 640 -480 640 -640 427 -640 428 -640 427 -480 640 -640 480 -640 448 -640 480 -640 428 -640 391 -640 419 -640 426 -640 480 -640 429 -640 426 -640 480 -640 480 -640 528 -640 426 -640 480 -640 424 -427 640 -480 640 -640 480 -500 333 -500 375 -640 480 -480 360 -500 375 -640 510 -480 640 -640 480 -640 480 -640 627 -640 427 -640 480 -640 427 -640 427 -427 640 -480 640 -640 427 -419 640 -426 640 -640 424 -640 480 -640 625 -640 426 -487 500 -640 427 -427 640 -640 480 -500 375 -640 429 -425 640 -640 286 -375 500 -640 429 -640 480 -480 640 -500 375 -612 612 -640 480 -424 640 -640 427 -640 427 -640 382 -640 446 -640 427 -640 427 -640 472 -428 640 -640 427 -640 427 -500 333 -508 640 -500 375 -500 375 -612 612 -427 640 -640 425 -640 425 -640 480 -640 478 -640 427 -640 428 -427 640 -640 480 -480 640 -426 640 -600 393 -640 360 -480 640 -640 361 -640 427 -500 467 -425 640 -640 480 -640 427 -500 333 -500 333 -640 480 -640 359 -640 427 -595 428 -640 427 -490 500 -640 427 -640 360 -640 429 -612 612 -640 377 -640 454 -640 480 -428 640 -640 640 -640 427 -640 480 -640 384 -640 429 -500 375 -427 640 -640 427 -640 480 -640 480 -640 480 -640 480 -500 375 -640 480 -640 427 -640 480 -640 480 -640 428 -500 375 -640 424 -640 419 -333 500 -640 425 -612 612 -640 480 -640 427 -640 426 -640 427 -640 455 -640 427 -480 640 -640 476 -640 480 -640 448 -426 640 -427 640 -640 427 -640 480 -640 427 -428 640 -640 426 -640 426 -500 333 -640 427 -640 408 -640 558 -640 480 -500 375 -640 640 -640 482 -640 426 -383 640 -500 281 -480 640 -375 500 -640 427 -640 425 -640 455 -494 640 -640 373 -640 427 -640 427 -640 425 -480 640 -640 480 -640 427 -640 428 -640 480 -500 298 -640 427 -640 409 -640 426 -640 480 -640 314 -640 424 -640 427 -640 427 -640 512 -640 489 -500 333 -480 640 -640 298 -500 375 -612 612 -640 249 -640 360 -454 640 -640 427 -640 640 -640 480 -500 375 -640 481 -640 480 -640 426 -640 453 -640 427 -480 640 -640 427 -480 640 -640 388 -640 480 -640 480 -500 316 -640 480 -640 480 -425 640 -640 480 -500 375 -640 480 -640 427 -480 640 -631 640 -640 480 -640 426 -640 476 -640 427 -640 359 -640 549 -426 640 -640 480 -481 640 -640 389 -640 420 -640 640 -640 427 -619 640 -640 530 -547 640 -640 425 -640 456 -640 480 -640 429 -640 360 -640 480 -640 426 -640 480 -500 375 -640 476 -640 480 -496 640 -640 360 -640 401 -402 640 -640 428 -640 427 -640 480 -640 427 -640 424 -640 480 -640 428 -640 480 -640 427 -640 426 -640 480 -480 640 -640 480 -480 640 -640 427 -640 427 -640 468 -640 427 -640 427 -480 640 -500 375 -612 612 -640 374 -640 433 -640 426 -640 640 -640 478 -458 640 -640 360 -333 500 -640 480 -640 480 -612 612 -640 480 -428 640 -480 640 -480 640 -640 480 -612 612 -640 610 -640 309 -640 640 -640 428 -640 427 -640 427 -480 640 -500 375 -640 427 -640 480 -640 480 -478 640 -500 333 -640 427 -640 427 -640 479 -640 480 -640 480 -500 375 -640 480 -640 425 -640 480 -640 480 -500 375 -640 480 -640 480 -640 480 -526 640 -512 640 -500 406 -500 222 -640 480 -640 427 -640 463 -640 426 -480 640 -500 247 -500 375 -640 480 -640 429 -640 426 -500 333 -640 423 -640 430 -640 427 -640 427 -640 480 -500 375 -640 426 -500 375 -640 424 -640 427 -612 612 -640 480 -427 640 -640 428 -426 640 -640 640 -609 640 -640 480 -480 640 -640 428 -500 332 -640 360 -483 640 -478 640 -640 327 -640 480 -640 359 -640 427 -640 438 -427 640 -640 478 -640 426 -640 480 -480 640 -640 480 -640 480 -427 640 -640 427 -640 413 -640 480 -640 427 -333 500 -640 480 -426 640 -640 480 -640 424 -640 427 -640 480 -640 480 -640 264 -640 368 -640 426 -375 500 -494 640 -490 500 -640 478 -500 335 -640 480 -480 640 -500 333 -346 500 -640 480 -640 415 -640 480 -640 426 -487 640 -500 375 -500 333 -640 371 -640 426 -640 438 -640 480 -640 427 -428 640 -427 640 -439 640 -640 434 -640 480 -500 335 -640 480 -500 333 -640 427 -640 480 -640 427 -427 640 -640 480 -640 478 -424 640 -640 480 -640 328 -640 427 -640 452 -640 360 -500 375 -640 480 -429 640 -640 446 -640 640 -640 426 -640 427 -480 640 -640 364 -640 480 -429 500 -640 480 -500 375 -427 640 -480 640 -471 640 -336 500 -480 640 -640 427 -480 640 -480 640 -496 400 -640 427 -640 158 -640 480 -640 480 -640 480 -640 606 -640 480 -640 427 -640 480 -640 480 -640 429 -640 424 -640 480 -375 500 -500 375 -375 500 -463 640 -530 353 -480 640 -480 640 -427 640 -402 640 -640 480 -500 333 -640 480 -640 427 -640 428 -640 502 -640 480 -591 640 -640 480 -500 375 -486 640 -426 640 -640 480 -427 640 -640 480 -427 640 -640 480 -640 428 -640 427 -640 480 -640 478 -640 480 -640 427 -640 426 -640 480 -640 427 -640 426 -640 424 -427 640 -640 563 -640 427 -640 480 -640 480 -640 471 -640 425 -640 427 -375 500 -640 384 -640 429 -640 480 -428 640 -640 404 -333 500 -640 427 -640 417 -640 480 -612 612 -375 500 -640 480 -612 612 -480 640 -640 427 -640 426 -640 480 -640 480 -480 640 -424 640 -640 427 -640 480 -640 427 -640 394 -640 428 -500 375 -640 640 -640 425 -500 500 -469 640 -375 500 -640 432 -480 640 -425 640 -457 640 -612 612 -427 640 -640 473 -640 478 -375 500 -640 426 -640 360 -640 426 -427 640 -425 640 -640 426 -480 640 -640 428 -640 426 -462 500 -375 500 -640 480 -640 429 -640 432 -640 427 -346 640 -500 333 -640 427 -640 625 -640 418 -640 425 -611 640 -640 512 -640 480 -640 428 -480 640 -640 411 -640 442 -640 480 -640 480 -480 640 -640 480 -640 435 -640 434 -640 424 -480 640 -640 481 -640 437 -640 480 -640 427 -640 426 -640 506 -640 480 -640 480 -640 361 -640 427 -640 480 -640 480 -640 423 -640 427 -640 480 -640 640 -640 427 -640 640 -480 640 -427 640 -640 349 -640 427 -500 353 -640 427 -640 480 -637 637 -427 640 -480 640 -640 480 -640 427 -519 389 -640 480 -640 480 -640 388 -480 640 -640 480 -380 640 -500 375 -349 640 -640 429 -480 640 -640 480 -640 480 -640 427 -496 640 -640 479 -427 640 -612 612 -640 360 -375 500 -500 342 -375 500 -640 427 -550 365 -640 428 -640 480 -640 428 -333 500 -427 640 -640 480 -640 449 -640 480 -640 480 -640 480 -640 480 -612 612 -640 426 -428 640 -640 480 -640 427 -427 640 -640 352 -411 640 -480 640 -640 480 -640 427 -640 480 -323 500 -480 640 -640 623 -612 612 -640 427 -500 375 -640 360 -640 480 -640 427 -640 427 -640 427 -500 333 -442 338 -640 426 -640 493 -480 640 -500 366 -333 500 -640 427 -640 431 -640 427 -480 640 -640 480 -481 640 -333 500 -640 447 -426 640 -480 640 -426 640 -612 612 -640 427 -640 427 -640 427 -640 389 -640 522 -640 480 -640 480 -612 612 -375 500 -640 427 -534 640 -640 480 -640 479 -398 640 -640 480 -640 480 -640 489 -640 480 -640 360 -640 483 -640 533 -640 425 -426 640 -500 334 -640 480 -640 373 -422 640 -500 374 -640 407 -640 383 -640 511 -480 640 -640 427 -320 240 -424 640 -640 489 -424 640 -640 427 -640 478 -640 480 -480 640 -640 398 -428 640 -640 426 -433 640 -640 360 -555 640 -480 640 -640 427 -640 428 -640 426 -640 480 -480 640 -500 375 -417 431 -500 375 -427 640 -480 640 -500 375 -640 428 -427 640 -640 427 -480 640 -640 427 -500 375 -490 640 -612 612 -423 640 -500 333 -375 500 -640 480 -640 480 -426 640 -426 640 -480 640 -640 427 -480 640 -640 480 -640 480 -640 424 -640 480 -640 463 -640 427 -640 291 -640 480 -640 427 -640 395 -640 480 -640 457 -360 640 -640 427 -415 640 -640 427 -640 435 -500 375 -640 480 -640 427 -427 640 -640 425 -640 440 -333 500 -640 480 -640 372 -500 338 -640 426 -640 480 -640 480 -640 360 -423 640 -427 640 -640 522 -333 500 -640 428 -640 498 -500 500 -422 640 -640 480 -480 640 -640 480 -640 512 -640 480 -640 480 -500 375 -500 332 -640 427 -429 640 -375 500 -640 480 -360 500 -640 480 -640 426 -640 426 -640 330 -500 333 -640 478 -640 480 -640 429 -640 480 -640 463 -410 640 -427 640 -640 480 -640 383 -460 640 -640 480 -640 480 -640 474 -640 426 -612 612 -640 480 -640 480 -500 496 -426 640 -640 467 -640 360 -427 640 -640 426 -480 640 -640 640 -480 640 -640 427 -323 500 -478 640 -640 427 -500 383 -640 425 -640 426 -424 640 -640 480 -640 426 -360 640 -312 640 -640 323 -479 640 -640 428 -500 375 -640 480 -640 480 -640 480 -427 640 -480 640 -640 359 -640 480 -640 465 -426 640 -640 480 -640 480 -640 480 -362 500 -640 467 -500 375 -640 480 -480 640 -640 427 -640 426 -640 480 -640 436 -640 480 -424 640 -640 428 -571 640 -640 427 -640 480 -640 482 -320 240 -640 398 -500 333 -500 333 -427 640 -500 375 -480 640 -427 640 -640 480 -376 640 -567 640 -480 640 -640 480 -640 426 -640 480 -640 479 -640 480 -427 640 -466 640 -640 480 -640 484 -640 482 -640 480 -640 480 -640 428 -427 640 -640 480 -640 511 -640 429 -640 425 -427 640 -640 427 -500 375 -640 427 -427 640 -427 640 -640 480 -500 375 -479 640 -640 427 -427 640 -500 500 -487 640 -640 459 -640 427 -640 480 -640 480 -640 480 -640 427 -473 640 -640 360 -426 640 -640 480 -640 409 -427 640 -640 359 -640 423 -500 300 -500 375 -640 427 -640 423 -640 425 -456 640 -640 328 -427 640 -640 480 -640 426 -427 640 -640 427 -500 375 -640 480 -500 375 -640 483 -399 500 -640 480 -640 427 -640 427 -640 427 -500 334 -640 480 -400 500 -427 640 -346 500 -640 313 -640 427 -640 360 -480 640 -640 478 -640 427 -640 427 -480 640 -640 480 -640 541 -500 322 -427 640 -640 379 -518 640 -640 426 -426 640 -640 425 -480 640 -640 428 -640 360 -640 426 -640 474 -480 640 -640 480 -640 480 -640 480 -500 375 -383 640 -480 640 -640 480 -640 414 -640 512 -640 427 -427 640 -500 333 -480 640 -640 425 -640 427 -600 453 -640 480 -640 425 -640 360 -640 480 -500 375 -640 360 -500 332 -640 442 -640 426 -500 331 -640 427 -640 435 -427 640 -640 427 -500 494 -640 420 -640 427 -640 427 -640 427 -500 472 -640 480 -500 375 -431 640 -500 333 -640 396 -640 428 -640 480 -500 375 -640 480 -500 465 -640 425 -640 424 -640 623 -640 430 -480 640 -640 480 -333 500 -640 480 -500 457 -640 479 -640 427 -640 427 -640 427 -500 252 -640 424 -427 640 -640 427 -640 480 -640 485 -640 426 -640 427 -640 433 -500 333 -480 640 -640 480 -428 640 -640 427 -640 427 -640 478 -500 457 -500 334 -640 480 -640 427 -349 640 -640 448 -380 500 -480 640 -640 437 -640 427 -544 640 -640 427 -427 640 -425 640 -612 612 -500 400 -640 480 -480 640 -375 500 -640 480 -640 640 -640 480 -500 375 -640 426 -640 424 -640 617 -500 377 -429 640 -640 479 -500 375 -640 429 -512 640 -426 640 -640 427 -640 427 -640 424 -640 480 -640 480 -640 442 -640 480 -640 491 -640 494 -640 480 -612 612 -467 500 -612 612 -640 534 -640 494 -640 409 -640 478 -480 640 -500 375 -427 640 -640 480 -500 348 -640 425 -640 480 -507 640 -640 480 -640 401 -640 480 -640 360 -633 640 -640 427 -500 333 -640 425 -428 285 -500 332 -640 429 -519 640 -640 480 -640 458 -640 480 -640 480 -334 500 -640 427 -480 640 -640 426 -640 426 -480 640 -640 428 -426 640 -480 640 -640 361 -640 480 -480 640 -612 612 -500 270 -640 419 -357 500 -640 427 -640 401 -512 640 -640 426 -612 612 -443 640 -427 640 -480 640 -640 480 -375 500 -427 640 -500 375 -458 640 -640 427 -640 457 -428 640 -640 479 -640 308 -500 332 -640 428 -427 640 -640 480 -640 427 -500 375 -500 375 -612 612 -640 426 -480 640 -361 640 -640 425 -640 480 -375 500 -427 640 -640 426 -640 425 -480 640 -640 558 -640 480 -640 434 -640 428 -640 398 -640 421 -640 480 -640 640 -640 428 -480 640 -640 427 -640 480 -640 427 -612 612 -640 426 -640 424 -573 640 -640 426 -640 427 -500 375 -640 480 -242 350 -640 426 -427 640 -480 640 -467 640 -640 427 -480 640 -640 480 -640 480 -640 427 -640 499 -480 640 -640 427 -640 480 -640 427 -391 640 -640 425 -640 426 -500 332 -480 640 -612 612 -480 640 -640 480 -439 640 -480 640 -478 640 -433 640 -640 480 -480 640 -640 194 -640 480 -640 480 -640 480 -640 640 -480 640 -640 619 -640 427 -640 480 -640 480 -640 426 -612 612 -640 428 -640 484 -427 640 -640 480 -500 374 -425 640 -640 425 -640 427 -428 640 -640 640 -640 427 -509 640 -333 500 -500 375 -325 485 -513 640 -640 425 -640 426 -500 375 -640 480 -640 428 -460 640 -640 480 -480 640 -640 480 -640 421 -640 427 -640 480 -480 640 -480 640 -640 262 -640 480 -640 480 -640 424 -640 427 -507 640 -640 427 -640 531 -427 640 -640 480 -640 480 -640 427 -500 375 -640 464 -522 640 -640 427 -500 332 -425 640 -640 427 -640 473 -640 398 -640 480 -640 428 -640 359 -640 480 -480 640 -640 426 -480 640 -333 500 -640 424 -480 640 -612 612 -500 375 -426 640 -640 427 -640 426 -480 640 -640 428 -640 425 -480 640 -487 640 -541 640 -512 640 -640 427 -424 640 -500 375 -640 446 -480 640 -480 640 -640 425 -428 640 -640 427 -640 389 -480 640 -640 320 -480 640 -480 640 -459 640 -640 469 -640 286 -640 427 -640 480 -640 549 -640 360 -375 500 -612 612 -640 484 -640 427 -640 427 -640 417 -640 480 -640 508 -483 640 -640 640 -612 612 -640 480 -427 640 -640 427 -500 375 -500 400 -480 640 -640 480 -640 640 -640 480 -640 640 -640 320 -480 640 -640 427 -640 480 -640 480 -640 480 -375 500 -640 427 -427 640 -640 428 -640 480 -640 389 -640 480 -640 428 -640 480 -500 375 -640 425 -640 429 -640 427 -640 480 -640 513 -640 344 -640 480 -429 640 -480 640 -500 394 -500 375 -500 354 -426 640 -500 343 -640 428 -640 427 -640 480 -640 423 -150 200 -640 426 -640 360 -640 480 -481 500 -300 225 -640 426 -480 640 -640 423 -500 375 -480 640 -427 640 -640 360 -600 473 -640 480 -640 427 -640 427 -640 427 -640 480 -640 464 -375 500 -427 640 -427 640 -640 400 -480 640 -640 427 -500 332 -480 640 -640 497 -427 640 -427 640 -640 425 -360 640 -633 640 -591 640 -480 360 -640 427 -640 427 -640 439 -427 640 -640 481 -480 640 -480 640 -427 640 -640 427 -500 400 -478 640 -500 375 -640 479 -640 427 -640 427 -640 513 -640 360 -640 427 -640 512 -640 427 -640 427 -640 480 -640 427 -640 480 -334 500 -640 480 -415 640 -427 640 -640 427 -640 480 -640 640 -500 332 -640 427 -480 640 -640 411 -640 480 -640 419 -500 333 -640 480 -426 640 -482 640 -640 480 -640 480 -640 427 -478 640 -375 500 -640 427 -500 375 -640 425 -59 72 -640 428 -405 500 -640 427 -500 330 -427 640 -427 640 -400 500 -640 480 -375 500 -438 640 -640 480 -500 362 -426 640 -480 640 -480 640 -640 426 -640 480 -640 480 -427 640 -640 480 -640 425 -640 447 -640 360 -640 480 -640 428 -500 399 -500 332 -640 427 -640 480 -357 500 -640 444 -640 426 -456 640 -480 640 -640 335 -478 640 -640 427 -640 480 -640 425 -640 461 -500 375 -640 480 -427 640 -480 640 -499 500 -640 480 -640 427 -640 424 -640 426 -640 429 -500 480 -640 426 -480 640 -640 427 -640 427 -500 375 -480 640 -326 246 -640 416 -640 427 -640 391 -640 427 -640 427 -640 426 -640 423 -500 375 -640 640 -640 480 -640 426 -640 427 -640 480 -640 427 -640 427 -640 426 -428 640 -480 640 -640 427 -640 427 -375 500 -426 640 -480 640 -640 360 -640 457 -640 480 -640 480 -640 427 -640 480 -640 480 -640 480 -480 640 -480 640 -612 612 -428 640 -640 480 -640 425 -639 640 -480 640 -640 486 -427 640 -640 481 -640 426 -640 400 -640 480 -427 640 -551 640 -640 426 -640 480 -640 480 -640 480 -640 480 -375 500 -640 480 -640 428 -479 640 -640 513 -604 402 -519 640 -640 401 -640 360 -640 425 -500 333 -425 640 -640 425 -640 480 -640 419 -500 375 -640 640 -640 427 -640 427 -640 480 -640 414 -612 612 -480 640 -480 640 -478 640 -480 640 -640 480 -500 375 -640 640 -640 428 -640 426 -640 480 -640 463 -640 480 -640 428 -640 427 -640 480 -500 333 -500 377 -640 480 -640 454 -640 347 -500 331 -640 427 -640 427 -640 480 -500 375 -640 405 -432 640 -640 427 -500 400 -640 480 -640 480 -640 602 -192 640 -640 480 -640 484 -480 640 -640 427 -500 334 -640 480 -640 480 -375 500 -640 429 -640 347 -640 426 -640 480 -640 480 -640 427 -640 449 -640 427 -640 427 -480 640 -427 640 -640 466 -612 612 -480 640 -640 427 -640 426 -640 424 -640 429 -424 640 -640 425 -640 449 -640 426 -427 640 -640 480 -640 427 -640 480 -640 534 -640 480 -480 640 -480 640 -640 318 -640 426 -640 427 -640 493 -640 427 -640 480 -640 480 -640 380 -640 480 -480 640 -640 480 -640 396 -640 480 -640 427 -640 480 -462 371 -640 461 -640 427 -485 640 -500 640 -368 640 -480 640 -640 427 -640 480 -508 640 -640 424 -293 500 -500 375 -429 640 -640 426 -640 480 -640 480 -640 480 -640 481 -640 360 -640 427 -335 500 -640 479 -640 480 -640 427 -640 427 -640 416 -499 640 -640 480 -480 640 -640 425 -640 480 -640 480 -640 425 -640 426 -640 306 -480 640 -480 640 -413 640 -640 268 -375 500 -640 427 -640 480 -500 375 -640 284 -640 480 -480 640 -640 427 -480 640 -406 640 -640 480 -500 375 -480 640 -640 467 -480 640 -426 640 -640 427 -640 427 -427 640 -640 480 -500 333 -331 500 -480 640 -478 640 -423 640 -361 640 -640 480 -640 429 -640 640 -506 640 -640 500 -640 427 -500 333 -480 640 -612 612 -429 640 -375 500 -640 480 -427 640 -640 427 -640 428 -640 427 -500 375 -640 506 -383 640 -640 426 -640 428 -640 480 -640 427 -500 333 -640 480 -356 640 -426 640 -612 612 -640 512 -640 424 -640 480 -640 480 -640 480 -640 480 -640 426 -478 640 -640 424 -426 640 -425 640 -640 428 -500 375 -333 500 -500 333 -612 612 -425 640 -640 480 -640 429 -640 426 -640 426 -640 480 -640 480 -640 427 -640 425 -640 360 -500 333 -480 640 -640 474 -480 640 -640 428 -640 483 -446 597 -640 413 -500 375 -480 640 -640 427 -500 333 -640 427 -640 368 -500 375 -640 368 -640 640 -465 640 -428 640 -640 428 -640 383 -500 375 -640 427 -640 403 -640 480 -640 466 -333 500 -640 480 -640 426 -480 640 -640 426 -640 426 -640 480 -640 480 -640 478 -640 422 -640 480 -640 426 -640 480 -480 640 -640 480 -640 427 -640 427 -427 640 -612 612 -612 612 -640 427 -640 406 -548 640 -640 427 -640 512 -428 640 -500 333 -500 376 -640 419 -640 400 -424 640 -500 375 -612 612 -640 480 -640 426 -640 456 -640 425 -640 480 -640 480 -428 640 -427 640 -453 640 -640 427 -640 480 -612 612 -640 480 -427 640 -640 480 -360 640 -500 375 -333 500 -640 426 -640 278 -500 334 -640 427 -510 640 -640 424 -500 368 -640 478 -640 480 -640 383 -375 500 -480 640 -640 480 -640 480 -640 480 -500 375 -640 427 -640 425 -427 640 -480 640 -640 455 -640 434 -640 427 -521 640 -640 425 -426 640 -480 640 -640 427 -640 429 -640 480 -640 427 -640 428 -640 480 -640 427 -480 640 -640 480 -640 480 -426 640 -508 640 -448 500 -428 640 -640 427 -640 425 -640 480 -612 612 -640 426 -612 612 -640 427 -640 480 -640 480 -480 640 -500 219 -640 480 -640 374 -426 640 -414 640 -640 427 -640 427 -640 538 -640 426 -480 640 -426 640 -640 480 -640 480 -640 480 -480 640 -640 431 -500 333 -640 427 -428 640 -640 427 -640 425 -500 402 -640 425 -640 480 -640 480 -426 640 -640 480 -384 640 -521 617 -478 640 -428 640 -640 427 -640 480 -640 480 -640 426 -640 480 -640 214 -640 609 -640 427 -640 480 -612 612 -640 398 -480 640 -640 480 -640 426 -640 426 -427 640 -428 640 -640 480 -640 480 -640 480 -427 640 -500 375 -375 500 -640 480 -480 640 -500 375 -640 640 -640 480 -480 640 -375 500 -640 594 -480 640 -500 369 -640 427 -640 480 -640 426 -500 375 -427 640 -640 395 -640 424 -640 427 -640 428 -480 640 -640 480 -480 640 -375 500 -640 427 -640 427 -640 482 -427 640 -429 640 -500 375 -334 500 -640 567 -640 236 -612 612 -640 474 -640 480 -640 443 -640 480 -427 640 -640 429 -424 640 -640 389 -640 426 -640 427 -428 640 -640 480 -492 640 -500 336 -297 500 -640 424 -640 480 -640 427 -351 494 -426 640 -640 426 -500 375 -640 427 -640 428 -640 480 -640 423 -494 640 -375 500 -425 640 -306 408 -640 360 -640 480 -640 640 -500 380 -500 375 -640 480 -640 478 -500 375 -640 426 -638 640 -640 480 -333 500 -480 640 -640 427 -500 375 -500 283 -640 481 -640 426 -500 394 -640 427 -640 480 -268 400 -640 473 -640 408 -640 480 -640 427 -427 640 -640 427 -640 266 -332 500 -640 427 -640 425 -426 640 -500 337 -640 427 -568 320 -556 640 -640 480 -500 333 -500 375 -640 482 -288 432 -640 427 -640 480 -640 480 -500 375 -640 458 -640 427 -640 480 -640 480 -360 640 -640 480 -640 427 -640 426 -640 428 -640 480 -427 640 -480 640 -427 640 -333 500 -480 640 -640 427 -428 640 -480 640 -427 640 -424 640 -500 331 -500 414 -480 640 -500 346 -360 640 -640 480 -640 421 -640 425 -640 480 -480 640 -426 640 -480 640 -640 425 -481 640 -640 427 -500 334 -640 429 -500 333 -480 640 -375 500 -640 480 -640 427 -640 404 -480 640 -640 336 -640 480 -640 427 -424 640 -640 428 -640 426 -640 359 -640 424 -640 360 -640 426 -640 427 -640 480 -480 640 -640 480 -640 480 -640 427 -640 360 -640 427 -640 427 -640 480 -640 427 -426 640 -640 640 -500 404 -640 480 -640 480 -640 427 -640 427 -640 480 -640 427 -640 640 -640 413 -450 600 -640 427 -333 500 -240 320 -640 433 -640 480 -640 480 -480 640 -640 424 -425 640 -456 640 -500 375 -640 427 -484 640 -640 548 -640 480 -319 212 -640 480 -425 640 -400 600 -640 480 -640 387 -640 427 -396 640 -640 480 -640 480 -480 640 -640 480 -500 375 -640 480 -425 640 -640 152 -480 640 -467 640 -640 428 -309 500 -334 500 -640 457 -480 640 -640 480 -428 640 -640 427 -640 448 -640 428 -640 512 -500 375 -640 427 -640 480 -640 480 -640 480 -640 426 -640 427 -640 489 -375 500 -640 488 -640 427 -640 427 -640 427 -640 480 -640 480 -640 480 -500 375 -500 335 -640 480 -640 480 -480 640 -640 349 -480 640 -480 640 -640 428 -480 640 -640 329 -511 640 -640 427 -640 480 -640 480 -640 480 -480 640 -640 480 -500 375 -640 427 -640 491 -477 640 -640 426 -640 480 -640 480 -500 331 -427 640 -512 640 -640 426 -640 289 -500 333 -640 640 -640 427 -640 480 -640 429 -640 431 -640 427 -640 426 -640 480 -640 427 -640 426 -640 480 -640 480 -640 480 -500 375 -640 480 -480 640 -640 427 -640 427 -640 610 -640 427 -480 640 -500 358 -640 429 -640 480 -480 640 -426 640 -640 426 -427 640 -640 640 -640 426 -640 425 -500 334 -640 480 -640 216 -425 640 -640 427 -640 416 -375 500 -640 480 -640 512 -481 640 -640 480 -640 415 -480 640 -640 360 -640 426 -480 640 -640 424 -640 427 -375 500 -432 640 -640 480 -640 349 -640 424 -500 333 -428 640 -480 640 -640 461 -640 422 -640 429 -640 480 -640 480 -640 480 -640 640 -640 480 -640 454 -640 371 -481 640 -640 640 -640 480 -640 480 -640 425 -640 640 -640 452 -640 315 -640 427 -640 368 -612 612 -500 375 -640 457 -640 579 -640 427 -427 640 -600 367 -640 480 -628 640 -640 360 -640 480 -640 427 -480 640 -479 640 -640 234 -640 420 -500 375 -640 480 -640 427 -640 480 -640 480 -640 427 -612 612 -500 400 -500 333 -640 480 -427 640 -640 427 -334 640 -612 612 -640 480 -640 427 -612 612 -640 480 -489 640 -427 640 -640 428 -640 427 -640 509 -640 480 -500 102 -427 640 -640 428 -640 480 -640 360 -588 640 -423 640 -640 507 -375 500 -375 500 -612 612 -640 428 -427 640 -500 375 -640 480 -640 480 -640 480 -640 427 -640 427 -640 383 -640 428 -640 480 -640 425 -640 426 -640 472 -640 400 -639 640 -500 333 -500 375 -375 500 -500 333 -640 480 -640 426 -640 424 -427 640 -640 427 -640 425 -640 480 -640 427 -500 375 -640 409 -500 375 -640 423 -640 424 -640 425 -640 470 -640 480 -640 480 -612 612 -640 640 -640 480 -640 426 -640 427 -612 612 -640 480 -426 640 -640 401 -640 253 -640 427 -640 427 -427 640 -640 480 -640 427 -640 480 -640 588 -640 495 -640 429 -640 427 -640 480 -640 427 -491 500 -480 640 -640 406 -640 480 -640 425 -427 640 -640 425 -640 427 -427 640 -640 427 -500 333 -640 427 -500 375 -640 349 -426 640 -640 480 -375 500 -640 480 -426 640 -640 360 -640 425 -640 484 -426 640 -333 500 -640 480 -640 480 -640 427 -640 361 -640 480 -640 425 -640 379 -640 480 -640 480 -423 640 -323 500 -640 377 -640 427 -640 480 -640 424 -640 360 -640 480 -640 474 -640 480 -640 489 -640 480 -500 331 -480 640 -584 640 -333 500 -640 427 -640 429 -640 427 -640 480 -640 480 -640 427 -480 640 -426 640 -640 450 -640 480 -640 425 -640 427 -640 480 -640 427 -640 480 -640 480 -480 640 -478 640 -640 427 -640 480 -640 427 -480 640 -640 480 -640 480 -640 427 -478 640 -427 640 -640 427 -427 640 -640 375 -500 375 -640 427 -640 427 -591 640 -640 480 -640 480 -480 640 -640 480 -640 480 -480 640 -640 480 -640 381 -640 480 -500 393 -640 480 -424 640 -640 480 -640 480 -429 640 -640 427 -640 480 -500 375 -428 640 -314 500 -640 427 -640 480 -480 640 -550 473 -640 457 -640 480 -640 480 -480 640 -640 426 -640 480 -366 640 -640 378 -457 640 -640 503 -640 427 -427 640 -640 480 -510 640 -640 420 -640 625 -375 500 -500 375 -640 480 -640 480 -640 427 -427 640 -640 458 -640 481 -427 640 -427 640 -640 480 -640 427 -612 612 -640 425 -640 360 -640 480 -640 391 -612 612 -640 427 -640 427 -640 480 -640 480 -640 480 -640 427 -640 289 -480 640 -263 350 -640 479 -640 426 -480 640 -640 480 -640 640 -480 640 -640 427 -640 480 -537 403 -427 640 -427 640 -480 640 -438 640 -640 427 -500 375 -640 480 -429 640 -480 640 -500 338 -640 424 -500 375 -640 438 -640 424 -640 303 -612 612 -640 480 -480 640 -640 425 -640 640 -640 480 -513 640 -500 332 -640 427 -500 486 -640 444 -640 424 -427 640 -640 480 -480 640 -640 427 -640 427 -640 480 -640 427 -640 480 -640 431 -640 426 -640 480 -640 429 -375 500 -480 640 -640 480 -640 427 -640 427 -640 444 -480 640 -640 480 -240 320 -640 480 -500 308 -640 478 -640 427 -640 480 -640 480 -640 425 -640 601 -500 333 -640 480 -500 375 -640 427 -640 425 -640 427 -480 640 -640 427 -640 426 -500 333 -640 480 -640 425 -500 400 -640 479 -640 427 -640 425 -640 424 -640 480 -375 500 -500 375 -333 500 -640 467 -640 480 -640 428 -424 640 -640 480 -640 640 -640 469 -640 428 -640 427 -375 500 -640 640 -500 375 -640 427 -500 334 -334 500 -640 424 -427 640 -426 640 -480 640 -640 416 -640 427 -500 375 -640 480 -640 480 -640 382 -640 480 -500 472 -640 426 -640 426 -640 427 -640 426 -375 500 -508 640 -640 418 -333 500 -640 480 -640 480 -640 401 -480 640 -426 640 -640 478 -480 640 -640 428 -375 500 -427 640 -640 427 -640 536 -640 409 -640 413 -640 425 -478 640 -640 396 -640 480 -640 360 -640 480 -640 427 -480 640 -640 425 -640 425 -640 480 -640 424 -640 484 -640 429 -640 427 -480 640 -500 375 -500 333 -500 375 -500 375 -480 640 -500 333 -427 640 -500 311 -427 640 -480 640 -640 480 -640 480 -640 427 -428 640 -640 424 -640 427 -640 480 -333 500 -640 407 -640 428 -640 334 -480 640 -640 427 -615 461 -428 640 -427 640 -640 426 -480 640 -640 424 -500 332 -640 320 -640 425 -583 640 -500 375 -640 480 -624 640 -640 217 -640 400 -360 270 -500 375 -640 426 -640 430 -640 480 -285 640 -640 480 -640 480 -640 427 -444 640 -480 640 -640 403 -640 427 -640 427 -640 461 -640 427 -640 511 -640 480 -640 320 -427 640 -480 640 -640 427 -640 333 -640 457 -640 441 -640 480 -614 640 -480 640 -333 500 -352 288 -640 457 -640 480 -640 480 -509 503 -425 640 -640 425 -427 640 -640 391 -640 427 -640 480 -480 640 -640 400 -640 482 -375 500 -640 427 -640 511 -480 640 -500 327 -640 427 -640 360 -640 480 -640 480 -478 640 -640 428 -640 480 -640 424 -640 480 -460 640 -480 640 -375 500 -640 434 -640 480 -480 640 -640 426 -640 427 -640 427 -375 500 -640 480 -640 450 -640 428 -640 480 -500 358 -640 424 -640 480 -500 375 -640 480 -480 640 -640 480 -480 640 -640 424 -640 480 -480 640 -640 427 -375 500 -640 451 -640 480 -640 427 -427 640 -480 640 -426 640 -640 359 -640 403 -640 480 -640 480 -436 640 -640 480 -640 426 -640 480 -640 480 -640 480 -640 433 -640 427 -640 480 -480 640 -640 480 -640 480 -640 480 -640 536 -640 480 -500 326 -640 605 -427 640 -640 427 -429 640 -640 480 -640 360 -425 640 -500 333 -427 640 -640 434 -640 427 -426 640 -640 427 -480 640 -640 426 -240 320 -640 424 -640 551 -434 640 -640 424 -375 500 -640 426 -640 427 -500 375 -427 640 -640 356 -640 480 -480 640 -640 480 -375 500 -640 480 -640 427 -640 427 -480 640 -640 424 -640 422 -640 427 -640 480 -640 480 -428 640 -480 640 -480 640 -425 640 -480 640 -478 640 -500 354 -480 640 -640 426 -500 375 -500 333 -480 640 -640 480 -427 640 -640 427 -500 375 -640 481 -640 530 -640 480 -480 640 -495 500 -640 480 -640 503 -426 500 -479 640 -480 640 -640 556 -640 480 -488 286 -640 427 -640 480 -640 480 -461 640 -500 341 -640 416 -500 375 -640 418 -640 480 -457 640 -334 500 -640 427 -500 332 -640 480 -500 500 -640 480 -640 480 -640 354 -640 426 -640 428 -612 612 -640 428 -612 612 -640 480 -640 480 -640 480 -640 427 -640 480 -640 480 -640 427 -640 480 -500 375 -375 500 -640 480 -375 500 -640 480 -500 375 -640 477 -640 425 -640 430 -640 430 -640 426 -640 480 -500 400 -640 478 -640 427 -640 427 -427 640 -640 460 -640 427 -612 612 -640 424 -640 480 -570 640 -640 241 -640 426 -640 480 -640 480 -640 480 -427 640 -640 427 -500 375 -626 640 -640 427 -640 509 -640 480 -382 640 -640 427 -640 640 -480 640 -640 480 -500 375 -500 354 -640 480 -640 425 -640 427 -612 612 -640 427 -640 427 -640 359 -640 427 -640 480 -480 640 -612 612 -480 640 -640 480 -640 480 -500 376 -640 444 -640 426 -501 640 -640 480 -640 480 -500 375 -640 427 -612 612 -443 640 -400 500 -478 640 -640 424 -600 400 -447 640 -466 640 -640 480 -640 386 -640 426 -640 427 -480 640 -640 360 -640 480 -640 427 -500 333 -479 640 -640 590 -427 640 -640 425 -500 324 -640 480 -640 326 -500 375 -426 640 -330 500 -480 640 -640 480 -640 480 -500 375 -612 612 -382 640 -640 427 -426 640 -640 480 -640 480 -640 640 -640 427 -640 360 -500 375 -640 427 -640 480 -428 640 -640 480 -640 419 -640 425 -500 375 -640 481 -640 426 -640 480 -500 432 -640 427 -640 480 -640 427 -480 640 -640 425 -500 400 -480 640 -640 480 -640 480 -640 480 -640 480 -640 427 -640 427 -640 377 -425 640 -612 612 -640 427 -640 463 -640 640 -488 500 -640 456 -640 530 -480 640 -640 427 -500 291 -640 426 -640 427 -640 480 -480 640 -640 427 -640 480 -640 480 -640 427 -480 640 -640 360 -334 500 -640 428 -640 427 -640 427 -357 500 -500 400 -640 427 -640 427 -640 480 -375 500 -640 444 -500 333 -426 640 -427 640 -640 428 -640 427 -500 375 -640 425 -640 480 -640 427 -640 424 -500 492 -500 375 -640 480 -640 427 -640 480 -640 504 -500 375 -640 424 -640 386 -640 480 -480 640 -640 422 -640 480 -640 426 -500 335 -640 427 -335 500 -523 640 -640 426 -640 420 -360 270 -423 640 -640 427 -640 420 -500 375 -428 640 -500 335 -640 428 -640 480 -640 426 -640 480 -500 375 -427 640 -426 640 -640 368 -500 333 -640 360 -640 480 -427 640 -427 640 -640 360 -640 410 -480 640 -640 427 -640 330 -334 500 -640 427 -640 640 -500 349 -500 332 -640 430 -500 375 -640 480 -640 490 -640 480 -640 428 -640 428 -640 480 -640 480 -332 500 -640 379 -640 427 -478 640 -640 427 -640 427 -640 480 -640 640 -640 406 -481 640 -640 502 -640 480 -640 478 -640 425 -500 375 -640 480 -640 426 -640 390 -640 480 -640 480 -375 500 -640 427 -480 640 -640 480 -427 640 -640 426 -612 612 -640 480 -640 284 -500 375 -480 640 -640 483 -640 481 -640 427 -500 375 -573 598 -640 428 -640 291 -500 339 -426 640 -500 332 -640 425 -457 640 -612 612 -640 400 -640 427 -375 500 -500 334 -640 427 -640 361 -640 400 -640 631 -640 320 -640 480 -480 640 -640 480 -640 480 -640 427 -500 375 -500 483 -640 480 -500 377 -640 480 -500 333 -640 491 -640 508 -640 426 -500 333 -640 480 -640 480 -640 468 -640 360 -640 427 -640 443 -629 640 -640 282 -640 383 -640 478 -640 427 -640 480 -500 375 -640 427 -640 480 -495 640 -333 500 -640 424 -640 429 -640 430 -640 480 -640 480 -640 480 -491 640 -640 424 -640 428 -640 427 -640 480 -640 482 -640 441 -500 375 -500 375 -500 375 -640 458 -640 427 -640 427 -640 480 -640 424 -426 640 -393 640 -640 426 -640 424 -640 229 -640 480 -323 640 -640 478 -500 375 -612 612 -640 383 -640 360 -333 500 -427 640 -640 427 -640 257 -500 333 -640 480 -640 427 -640 424 -640 458 -640 480 -640 427 -640 427 -640 480 -640 517 -640 360 -500 375 -427 640 -640 480 -500 375 -640 480 -335 500 -600 450 -500 333 -431 640 -640 480 -640 427 -640 478 -640 426 -640 521 -640 428 -640 480 -640 479 -640 640 -640 480 -640 427 -500 375 -640 480 -640 480 -640 480 -500 357 -640 586 -640 480 -500 333 -500 349 -480 640 -500 333 -640 478 -467 640 -426 640 -640 480 -424 640 -500 500 -640 426 -640 480 -478 640 -640 360 -640 480 -428 640 -640 428 -640 428 -640 574 -640 480 -480 640 -640 480 -640 427 -640 480 -640 480 -640 480 -640 427 -500 375 -640 427 -500 375 -640 480 -640 471 -500 375 -602 640 -500 375 -480 640 -640 480 -640 427 -640 427 -427 640 -640 427 -640 428 -640 427 -640 438 -640 480 -480 640 -640 400 -500 375 -480 640 -450 481 -425 640 -640 480 -428 640 -500 375 -640 424 -640 427 -570 640 -640 480 -640 427 -640 523 -450 600 -640 427 -528 604 -640 439 -610 423 -500 499 -427 640 -640 425 -640 427 -640 480 -426 640 -640 480 -640 425 -640 360 -480 640 -640 427 -640 426 -480 640 -640 443 -640 484 -640 480 -640 480 -500 333 -500 375 -480 640 -500 374 -640 423 -500 375 -640 361 -640 415 -500 375 -431 640 -435 640 -640 424 -640 360 -612 407 -640 427 -426 640 -640 640 -640 480 -478 640 -640 517 -640 480 -402 600 -296 444 -640 427 -480 640 -640 428 -427 640 -480 360 -500 255 -640 383 -640 426 -480 640 -500 334 -500 375 -500 335 -480 640 -640 480 -500 333 -640 480 -640 397 -640 428 -480 364 -640 427 -640 428 -640 360 -640 480 -640 426 -640 427 -427 640 -640 480 -640 428 -640 484 -640 425 -254 192 -640 484 -640 500 -640 480 -640 480 -640 424 -640 480 -640 480 -640 428 -429 640 -480 640 -428 640 -449 640 -640 424 -612 612 -640 527 -612 612 -500 375 -336 500 -640 480 -640 427 -640 427 -640 428 -500 333 -640 427 -480 640 -640 509 -640 457 -640 427 -640 427 -640 425 -640 480 -640 480 -500 334 -500 375 -640 427 -640 428 -427 640 -640 480 -612 612 -500 333 -640 544 -640 480 -640 427 -640 427 -604 453 -375 500 -640 360 -640 480 -640 480 -640 427 -640 427 -597 640 -640 428 -640 359 -640 427 -427 640 -459 640 -526 640 -640 424 -427 640 -640 513 -359 500 -640 437 -640 481 -640 480 -500 375 -640 427 -640 480 -640 480 -640 425 -640 512 -640 449 -500 333 -640 480 -640 424 -457 640 -640 427 -640 427 -640 480 -640 427 -500 333 -500 334 -640 472 -500 333 -640 478 -640 480 -333 640 -640 480 -500 375 -640 427 -640 427 -640 480 -480 640 -640 480 -640 426 -640 429 -508 640 -640 359 -480 640 -640 427 -640 480 -640 427 -500 375 -640 480 -427 640 -640 427 -640 480 -640 480 -640 428 -640 478 -375 500 -640 378 -640 429 -640 480 -500 333 -500 500 -443 450 -640 418 -640 480 -640 427 -640 427 -480 640 -640 424 -640 426 -583 640 -500 317 -500 239 -640 480 -640 427 -640 427 -640 480 -500 500 -480 640 -427 640 -640 428 -612 612 -640 480 -640 427 -363 500 -640 480 -480 640 -640 480 -640 427 -640 360 -375 500 -640 480 -480 640 -480 640 -640 329 -303 640 -640 479 -640 427 -640 426 -640 425 -480 640 -481 640 -322 640 -375 500 -480 640 -640 640 -640 321 -480 640 -500 375 -612 612 -640 480 -640 426 -640 427 -640 446 -500 375 -640 428 -480 640 -640 424 -640 427 -640 480 -640 640 -556 640 -640 443 -449 640 -640 425 -640 427 -500 375 -640 480 -500 400 -424 640 -640 480 -640 480 -640 425 -640 428 -640 427 -480 640 -640 427 -640 424 -640 480 -640 513 -640 428 -427 640 -640 479 -640 483 -640 480 -640 427 -500 375 -640 480 -640 431 -640 426 -500 375 -640 425 -333 500 -640 480 -640 480 -640 480 -640 383 -640 360 -480 640 -640 425 -427 640 -427 640 -480 640 -640 480 -640 480 -612 612 -480 640 -640 454 -640 480 -500 319 -500 485 -426 640 -640 480 -640 392 -640 426 -612 612 -500 383 -427 640 -640 427 -640 431 -640 427 -640 452 -500 335 -640 449 -640 429 -640 480 -640 453 -640 426 -640 473 -640 473 -640 480 -640 480 -640 419 -375 500 -640 427 -640 427 -640 427 -426 640 -640 360 -640 569 -640 480 -640 427 -425 640 -640 427 -500 207 -480 640 -500 375 -640 427 -640 376 -640 480 -640 456 -612 612 -500 332 -640 480 -640 480 -640 462 -640 427 -640 427 -427 640 -640 480 -640 480 -400 500 -500 375 -640 350 -640 640 -439 640 -640 480 -640 480 -640 480 -640 480 -569 640 -640 356 -640 437 -640 427 -640 428 -426 640 -640 376 -640 308 -640 469 -640 373 -640 480 -640 480 -500 375 -640 427 -640 423 -640 480 -640 413 -480 640 -612 612 -640 480 -480 640 -427 640 -640 427 -640 430 -480 640 -640 471 -640 480 -640 426 -640 480 -436 640 -640 426 -612 612 -425 640 -640 480 -640 427 -640 417 -640 426 -640 480 -512 640 -640 427 -575 575 -640 174 -640 441 -640 504 -640 480 -640 480 -480 640 -416 640 -333 500 -640 436 -640 480 -640 480 -640 427 -640 480 -640 480 -640 475 -640 423 -640 480 -640 478 -640 401 -640 425 -640 414 -640 478 -500 405 -500 375 -640 439 -640 426 -640 480 -640 456 -500 375 -640 480 -500 375 -640 428 -640 204 -640 427 -640 426 -640 480 -640 426 -624 640 -640 640 -640 193 -500 375 -640 428 -427 640 -486 640 -640 360 -640 242 -640 424 -640 360 -640 480 -640 479 -500 377 -640 606 -640 482 -640 425 -640 480 -604 453 -480 397 -427 640 -640 480 -500 448 -320 240 -500 500 -640 210 -640 424 -500 341 -640 480 -480 360 -500 218 -640 338 -500 470 -640 490 -640 479 -425 640 -640 480 -640 427 -640 478 -640 492 -640 480 -500 333 -500 375 -480 640 -640 480 -640 427 -640 515 -640 480 -640 480 -444 595 -640 344 -376 500 -640 427 -640 427 -640 429 -640 428 -640 480 -640 480 -640 427 -640 480 -640 427 -640 428 -336 500 -640 426 -640 577 -480 640 -640 426 -500 331 -640 427 -640 480 -500 375 -640 514 -640 640 -640 480 -630 640 -640 480 -480 640 -612 612 -640 480 -392 218 -640 427 -640 427 -640 425 -640 310 -640 480 -640 480 -640 427 -640 427 -640 425 -640 427 -640 427 -640 426 -640 425 -480 640 -500 375 -500 375 -640 427 -640 480 -640 425 -400 640 -640 423 -640 480 -640 480 -427 640 -640 427 -640 468 -640 424 -640 359 -150 225 -640 385 -640 625 -640 480 -640 480 -640 425 -640 640 -375 500 -640 480 -500 317 -640 427 -640 457 -375 500 -640 480 -640 426 -640 427 -640 351 -640 480 -640 640 -640 480 -480 640 -640 432 -500 167 -480 640 -640 428 -640 429 -427 640 -500 340 -425 640 -500 396 -240 320 -640 427 -640 428 -640 480 -640 480 -640 400 -640 480 -640 427 -640 480 -360 640 -640 424 -375 500 -612 612 -640 533 -640 428 -481 640 -500 500 -640 429 -500 335 -500 375 -500 375 -640 426 -640 427 -640 426 -640 480 -640 427 -333 500 -640 480 -486 640 -427 640 -640 637 -640 480 -500 500 -640 426 -640 428 -427 640 -640 640 -640 427 -480 640 -640 484 -640 426 -640 427 -640 320 -640 305 -640 480 -640 480 -426 640 -640 438 -640 480 -640 480 -640 427 -640 478 -640 481 -375 500 -612 612 -640 177 -500 427 -480 640 -500 333 -426 640 -480 640 -640 574 -640 461 -640 512 -640 428 -640 480 -500 333 -640 509 -640 427 -640 480 -640 528 -425 640 -612 612 -640 427 -640 455 -640 430 -640 375 -640 427 -640 480 -640 480 -500 375 -640 426 -500 332 -640 427 -640 640 -640 509 -640 529 -640 480 -640 415 -640 425 -640 427 -640 480 -640 480 -640 480 -640 640 -427 640 -640 427 -427 640 -480 640 -640 426 -333 500 -640 454 -640 427 -640 480 -640 640 -640 480 -640 429 -424 640 -640 581 -640 331 -500 375 -640 480 -640 427 -640 403 -640 480 -640 426 -640 480 -640 348 -640 298 -640 480 -640 160 -500 385 -425 640 -640 480 -640 480 -433 640 -640 551 -424 640 -640 462 -480 640 -640 424 -500 375 -640 583 -640 427 -427 640 -640 425 -640 521 -640 480 -640 480 -425 640 -640 426 -333 500 -640 424 -480 640 -426 640 -249 640 -640 427 -500 375 -374 500 -612 612 -640 427 -640 480 -308 500 -640 480 -640 466 -640 480 -500 375 -640 480 -640 427 -612 612 -640 480 -640 426 -640 416 -480 640 -500 333 -640 380 -427 640 -640 480 -640 383 -500 335 -500 375 -500 500 -640 441 -346 500 -480 640 -612 612 -640 427 -640 425 -426 640 -640 427 -640 427 -640 427 -640 480 -640 480 -640 478 -640 427 -640 480 -612 612 -640 428 -640 429 -640 480 -500 375 -640 480 -480 272 -640 480 -640 480 -640 560 -500 319 -480 640 -640 427 -640 426 -500 375 -427 640 -640 427 -640 427 -640 425 -500 375 -640 480 -640 480 -426 640 -640 439 -640 480 -640 292 -480 640 -500 347 -480 640 -640 427 -640 480 -480 640 -640 427 -640 478 -640 512 -640 480 -640 480 -500 340 -425 640 -640 480 -640 478 -512 640 -500 375 -640 426 -426 640 -640 480 -640 424 -333 500 -640 328 -480 640 -640 480 -640 480 -447 500 -640 427 -640 371 -480 640 -427 640 -640 480 -500 375 -640 480 -640 211 -640 427 -375 500 -480 360 -640 424 -480 640 -480 640 -480 640 -480 640 -500 500 -612 612 -545 640 -640 480 -427 640 -640 480 -498 640 -500 333 -640 466 -640 416 -640 480 -612 612 -480 640 -322 500 -640 399 -500 375 -640 480 -640 457 -640 480 -640 426 -640 425 -640 480 -640 480 -500 375 -640 427 -375 500 -640 480 -640 480 -640 481 -640 425 -640 421 -426 640 -640 427 -427 640 -612 612 -640 426 -640 360 -640 470 -640 640 -640 427 -640 360 -500 333 -640 430 -640 480 -500 334 -640 425 -640 427 -640 480 -640 429 -614 640 -640 427 -640 338 -640 480 -640 480 -640 427 -640 480 -478 640 -640 481 -514 640 -640 480 -640 426 -640 422 -640 480 -640 348 -640 480 -640 480 -640 426 -640 480 -640 480 -640 427 -500 375 -500 330 -640 427 -640 479 -480 640 -640 480 -612 612 -640 427 -640 427 -361 431 -640 493 -640 480 -612 612 -388 500 -640 425 -427 640 -640 504 -640 428 -640 480 -640 424 -640 425 -640 426 -480 640 -612 612 -640 424 -640 426 -640 480 -640 427 -640 506 -640 425 -401 640 -640 427 -640 482 -640 437 -640 480 -500 328 -640 480 -640 480 -478 640 -500 375 -480 640 -640 360 -640 480 -426 640 -640 437 -640 424 -427 640 -640 518 -640 426 -500 387 -640 480 -640 640 -640 380 -640 480 -640 480 -333 500 -480 640 -640 376 -640 407 -640 493 -640 407 -640 480 -389 640 -640 480 -480 640 -611 640 -640 480 -500 375 -500 332 -640 348 -640 440 -640 480 -640 480 -335 500 -640 480 -500 375 -427 640 -451 640 -494 640 -640 361 -426 640 -640 281 -640 480 -426 640 -640 481 -640 508 -640 411 -609 640 -480 640 -456 640 -612 612 -640 480 -640 640 -375 500 -640 427 -500 333 -640 425 -640 480 -500 375 -500 375 -640 536 -500 375 -640 480 -640 599 -640 426 -500 283 -640 480 -429 640 -640 360 -640 386 -426 640 -640 426 -640 640 -640 425 -640 426 -640 480 -640 427 -369 500 -640 427 -640 480 -640 480 -640 480 -425 640 -427 640 -640 501 -480 640 -640 427 -375 500 -640 480 -640 428 -640 427 -511 640 -480 640 -640 427 -581 345 -640 468 -640 480 -640 579 -640 424 -426 640 -427 640 -640 427 -640 388 -640 480 -640 480 -640 425 -640 428 -333 500 -427 640 -640 426 -500 375 -640 419 -640 480 -640 480 -640 428 -640 640 -640 480 -500 375 -427 640 -640 360 -500 375 -640 426 -640 427 -427 640 -360 640 -640 480 -500 400 -640 426 -640 512 -640 518 -500 406 -640 480 -480 640 -640 478 -640 454 -375 500 -640 480 -480 640 -640 427 -640 360 -500 333 -640 480 -640 427 -426 640 -500 375 -426 640 -375 500 -640 480 -640 427 -640 480 -428 640 -640 418 -640 480 -640 480 -640 428 -640 427 -640 426 -640 480 -640 449 -640 427 -427 640 -425 640 -640 480 -640 479 -640 480 -640 427 -480 640 -640 427 -333 500 -640 480 -426 640 -640 428 -640 478 -500 375 -427 640 -444 640 -640 480 -640 480 -640 427 -640 466 -426 319 -373 640 -640 421 -640 448 -421 640 -640 427 -640 480 -640 445 -480 640 -396 640 -640 480 -640 480 -640 476 -480 640 -640 426 -612 612 -640 394 -640 480 -640 480 -640 480 -500 402 -640 427 -640 428 -640 427 -640 480 -640 480 -640 360 -480 640 -640 480 -504 378 -512 640 -640 480 -640 427 -640 215 -425 640 -500 375 -640 597 -640 427 -612 612 -500 374 -480 640 -640 427 -640 480 -483 640 -480 640 -640 480 -500 329 -500 375 -500 438 -640 425 -567 640 -640 480 -640 480 -375 500 -427 640 -640 480 -500 375 -375 500 -640 480 -640 480 -500 393 -461 640 -640 427 -500 375 -640 499 -500 375 -640 427 -480 640 -350 450 -640 427 -640 640 -640 427 -640 512 -480 640 -400 257 -500 333 -640 356 -640 360 -526 640 -500 333 -640 427 -391 640 -379 640 -640 425 -640 480 -500 375 -640 501 -500 335 -640 480 -500 281 -640 640 -480 640 -480 640 -500 351 -640 427 -480 640 -480 640 -640 480 -640 480 -500 375 -371 500 -640 480 -427 640 -640 424 -640 427 -500 381 -500 297 -640 480 -480 640 -640 436 -480 640 -640 518 -480 640 -640 321 -640 428 -640 480 -640 553 -500 500 -480 640 -493 640 -500 233 -640 427 -640 480 -640 480 -640 458 -500 375 -640 480 -500 332 -375 500 -640 480 -640 427 -640 480 -640 480 -640 268 -427 640 -640 480 -427 640 -640 427 -500 333 -640 457 -640 480 -640 480 -612 612 -640 480 -640 427 -500 370 -640 427 -640 427 -640 480 -640 480 -640 480 -500 375 -640 478 -640 480 -640 480 -478 640 -640 425 -640 463 -640 480 -612 612 -640 360 -640 427 -640 480 -600 600 -640 480 -375 500 -640 480 -640 454 -500 400 -480 640 -640 480 -398 640 -640 427 -640 427 -640 443 -640 480 -640 427 -640 480 -640 429 -640 478 -640 360 -384 640 -414 640 -264 640 -640 359 -640 425 -427 640 -333 500 -612 612 -640 360 -640 480 -500 334 -424 640 -529 640 -640 228 -640 480 -640 480 -640 360 -640 426 -640 480 -640 360 -640 427 -640 359 -640 426 -640 428 -640 309 -640 427 -612 612 -640 478 -640 425 -500 333 -640 426 -640 477 -640 581 -500 375 -640 409 -640 427 -640 480 -428 640 -640 480 -640 480 -480 640 -640 449 -640 480 -640 427 -612 612 -500 375 -640 419 -640 420 -640 478 -640 417 -424 640 -640 425 -640 293 -426 640 -640 480 -640 428 -640 427 -480 640 -500 375 -640 480 -640 480 -640 480 -640 480 -411 640 -640 425 -339 500 -500 375 -640 480 -640 326 -640 480 -640 427 -640 480 -640 427 -640 478 -640 427 -640 427 -640 480 -640 425 -480 640 -640 480 -640 478 -640 427 -640 221 -640 478 -640 428 -612 612 -427 640 -640 426 -640 480 -500 430 -640 401 -640 480 -640 427 -500 300 -640 427 -640 427 -640 480 -640 413 -500 375 -640 478 -612 612 -640 478 -640 480 -640 427 -640 480 -640 427 -640 439 -500 334 -640 480 -640 427 -640 480 -640 424 -457 640 -640 426 -480 640 -640 433 -480 640 -640 480 -432 640 -640 414 -640 480 -500 344 -640 480 -612 612 -427 640 -612 612 -640 425 -640 361 -640 480 -640 394 -500 375 -640 425 -640 478 -640 427 -375 500 -640 593 -381 640 -640 426 -640 424 -500 281 -640 513 -640 480 -333 500 -500 395 -480 475 -480 640 -640 480 -480 640 -428 640 -612 612 -429 640 -640 480 -640 449 -640 430 -500 375 -640 482 -360 640 -478 640 -640 480 -423 640 -427 640 -640 480 -640 478 -640 383 -480 640 -500 375 -480 640 -375 500 -640 480 -640 480 -640 480 -640 480 -480 640 -640 480 -640 564 -640 480 -187 140 -640 427 -500 459 -428 640 -640 428 -375 500 -640 480 -640 504 -640 424 -500 400 -583 640 -640 427 -640 480 -612 612 -640 489 -612 612 -640 480 -469 640 -463 640 -640 480 -640 480 -640 550 -500 407 -500 210 -640 480 -640 640 -640 478 -612 612 -480 640 -500 333 -640 480 -640 429 -640 480 -427 640 -500 333 -640 480 -640 480 -640 424 -640 360 -321 640 -424 640 -640 450 -640 426 -640 471 -640 427 -640 425 -640 426 -640 425 -498 640 -640 427 -612 612 -640 480 -500 167 -640 424 -640 427 -427 640 -640 480 -640 470 -640 427 -640 480 -539 640 -640 480 -640 480 -500 337 -640 480 -500 332 -332 500 -375 500 -640 480 -590 640 -640 507 -480 640 -640 480 -640 480 -640 427 -500 333 -640 472 -640 427 -395 500 -640 427 -640 425 -640 427 -640 480 -640 427 -640 480 -640 425 -640 640 -427 640 -640 360 -640 348 -612 612 -640 426 -640 425 -640 480 -500 335 -640 433 -640 480 -517 640 -480 640 -427 640 -425 640 -480 640 -640 427 -640 480 -480 640 -640 427 -640 480 -640 425 -640 480 -640 427 -640 480 -640 419 -640 483 -640 425 -426 640 -480 640 -640 338 -640 438 -426 640 -640 640 -640 426 -640 486 -640 483 -500 375 -640 496 -640 480 -640 480 -640 389 -500 333 -640 571 -640 338 -493 500 -640 360 -640 383 -500 375 -640 360 -500 375 -427 640 -427 640 -500 333 -427 640 -640 456 -640 427 -640 428 -480 640 -640 360 -500 429 -640 480 -640 427 -640 427 -335 500 -640 425 -640 478 -640 640 -500 334 -640 480 -640 480 -640 423 -640 480 -640 427 -480 640 -500 375 -640 480 -640 426 -640 427 -640 480 -481 640 -640 425 -640 480 -427 640 -640 430 -640 427 -427 640 -612 612 -640 458 -640 480 -640 480 -640 427 -640 578 -375 500 -640 480 -640 640 -425 640 -500 375 -640 427 -640 480 -640 478 -640 480 -500 375 -640 427 -500 360 -500 375 -640 480 -640 424 -640 480 -417 556 -640 427 -640 480 -612 612 -640 480 -640 480 -480 480 -640 425 -402 640 -640 480 -425 640 -640 425 -333 500 -640 428 -426 640 -427 640 -640 427 -640 480 -640 478 -375 500 -333 500 -500 333 -640 480 -519 640 -500 334 -500 375 -478 640 -640 458 -480 640 -500 376 -480 640 -640 427 -640 426 -427 640 -500 389 -480 640 -640 480 -640 480 -640 480 -500 346 -461 640 -427 640 -640 480 -375 500 -640 493 -640 480 -640 427 -640 480 -640 480 -640 425 -427 640 -640 480 -500 375 -500 332 -640 427 -640 427 -640 480 -612 612 -500 338 -640 450 -640 427 -640 443 -610 493 -640 427 -480 640 -640 480 -481 640 -640 472 -640 436 -640 426 -455 640 -480 640 -640 480 -640 480 -640 480 -640 480 -500 375 -640 426 -640 480 -640 480 -480 640 -640 640 -640 427 -640 427 -640 480 -489 500 -640 480 -640 427 -640 640 -640 640 -640 464 -478 640 -640 367 -640 320 -640 427 -640 427 -427 640 -640 427 -640 504 -640 322 -640 585 -640 480 -640 468 -500 336 -640 323 -612 612 -640 427 -640 426 -640 480 -640 360 -426 640 -640 377 -480 640 -640 425 -640 427 -640 424 -640 422 -482 640 -640 480 -640 425 -640 478 -640 479 -427 640 -478 640 -640 429 -640 594 -640 360 -428 640 -640 523 -640 396 -640 424 -640 480 -640 359 -640 428 -640 511 -640 561 -640 320 -404 640 -500 375 -333 500 -640 383 -640 457 -480 640 -640 360 -640 429 -640 480 -640 480 -426 640 -426 500 -500 333 -426 640 -480 640 -480 640 -640 427 -640 360 -451 640 -604 453 -500 335 -457 640 -640 427 -640 425 -500 333 -500 328 -612 612 -640 427 -480 640 -640 480 -500 253 -640 425 -480 640 -640 457 -480 640 -640 427 -427 640 -640 494 -640 421 -640 426 -640 480 -640 480 -640 424 -500 332 -640 427 -640 427 -500 332 -448 500 -640 425 -500 375 -640 428 -640 480 -640 480 -640 361 -500 375 -640 435 -640 427 -375 500 -640 640 -500 339 -400 267 -640 432 -640 480 -480 640 -640 480 -427 640 -640 427 -640 480 -640 480 -640 427 -640 251 -640 404 -640 426 -640 427 -640 427 -640 320 -375 500 -640 248 -640 480 -640 428 -428 640 -581 604 -640 426 -640 480 -640 426 -640 480 -640 427 -640 480 -612 612 -480 640 -640 480 -640 388 -640 480 -640 424 -500 375 -640 427 -500 375 -612 612 -640 480 -612 612 -500 375 -640 480 -427 640 -640 640 -640 480 -500 375 -640 427 -427 640 -500 383 -640 428 -640 480 -500 469 -426 640 -640 491 -640 429 -640 480 -640 480 -640 512 -500 400 -640 428 -640 480 -500 332 -480 640 -500 333 -640 483 -480 640 -640 480 -375 500 -640 480 -640 480 -500 334 -640 480 -254 500 -640 480 -640 426 -480 640 -640 601 -640 480 -640 360 -640 427 -424 640 -640 480 -640 427 -425 640 -480 640 -612 612 -640 424 -640 480 -640 361 -640 480 -640 427 -426 640 -640 426 -640 427 -640 427 -480 640 -640 480 -640 480 -640 425 -640 480 -640 427 -640 480 -500 375 -480 360 -480 640 -640 428 -640 480 -429 640 -640 428 -640 480 -640 424 -500 461 -424 640 -640 411 -427 640 -640 320 -640 480 -640 480 -640 480 -640 428 -640 480 -429 640 -640 480 -640 427 -640 427 -640 420 -640 480 -640 480 -640 480 -640 484 -640 512 -500 334 -640 463 -640 427 -640 427 -640 418 -500 238 -500 375 -640 480 -640 481 -640 427 -640 480 -427 640 -640 454 -429 640 -640 427 -640 480 -500 347 -640 480 -640 480 -320 240 -640 480 -500 375 -640 480 -640 427 -333 500 -612 612 -612 612 -640 438 -640 427 -640 482 -480 640 -612 612 -612 612 -640 480 -480 640 -640 507 -640 480 -640 426 -640 480 -480 640 -640 427 -640 415 -640 427 -640 480 -500 376 -541 640 -640 426 -500 375 -500 375 -480 640 -640 512 -640 480 -640 427 -640 426 -612 612 -640 480 -640 480 -640 480 -480 640 -453 604 -640 426 -332 500 -430 640 -480 640 -426 640 -500 400 -640 480 -640 434 -500 372 -640 480 -427 640 -640 480 -640 462 -500 333 -640 480 -640 424 -640 480 -640 369 -500 375 -640 478 -383 640 -640 480 -640 480 -640 480 -640 427 -480 640 -640 406 -640 480 -640 359 -640 427 -640 481 -429 500 -640 427 -640 360 -640 429 -640 480 -427 640 -640 480 -640 429 -640 480 -640 480 -640 480 -640 427 -426 640 -640 360 -640 428 -640 471 -640 428 -640 480 -425 640 -500 333 -640 480 -427 640 -640 402 -640 480 -640 426 -500 375 -640 427 -640 359 -640 453 -640 427 -480 640 -640 423 -480 640 -640 480 -640 427 -640 480 -500 375 -500 375 -640 426 -640 480 -640 480 -640 427 -428 640 -500 453 -640 428 -640 427 -640 480 -640 439 -480 640 -500 333 -640 479 -640 480 -640 640 -500 375 -640 427 -640 360 -500 375 -480 640 -640 480 -480 640 -640 427 -640 425 -640 427 -640 480 -640 428 -640 360 -480 640 -640 441 -375 500 -640 441 -640 640 -480 640 -640 428 -640 259 -640 466 -640 425 -500 380 -640 482 -640 359 -427 640 -640 480 -427 640 -427 640 -640 427 -640 480 -640 426 -444 640 -480 640 -640 480 -480 640 -480 640 -480 640 -640 480 -500 320 -612 612 -640 427 -640 427 -640 427 -640 344 -640 425 -640 387 -478 640 -640 426 -640 427 -640 480 -640 428 -640 426 -500 333 -640 480 -640 480 -425 640 -640 480 -384 640 -640 360 -375 500 -500 400 -640 480 -640 490 -640 480 -640 427 -640 427 -480 640 -640 263 -612 612 -375 500 -500 400 -640 427 -640 480 -640 426 -640 424 -640 590 -640 427 -640 427 -640 480 -640 427 -640 480 -500 334 -431 640 -640 480 -480 640 -640 430 -640 480 -640 480 -640 480 -640 427 -425 640 -640 427 -640 401 -640 429 -480 640 -640 480 -640 507 -500 332 -640 427 -640 427 -486 500 -640 480 -640 480 -375 500 -640 425 -640 481 -640 504 -640 480 -427 640 -640 427 -219 500 -640 427 -480 640 -612 612 -639 640 -640 640 -640 423 -500 375 -640 426 -500 375 -480 640 -640 426 -640 426 -620 640 -640 427 -640 426 -612 612 -640 480 -500 358 -640 426 -640 426 -640 427 -640 479 -640 480 -640 279 -640 480 -424 640 -640 426 -640 480 -500 500 -640 427 -640 432 -640 427 -426 640 -430 640 -425 640 -640 424 -640 480 -640 480 -426 640 -640 480 -640 480 -427 640 -640 480 -427 640 -640 415 -640 427 -640 480 -640 377 -333 500 -640 427 -640 427 -640 480 -375 500 -640 457 -500 375 -500 375 -640 425 -424 640 -427 640 -640 444 -640 486 -480 640 -640 426 -640 480 -480 640 -640 426 -640 425 -640 412 -480 640 -640 480 -427 640 -640 426 -480 640 -640 480 -640 480 -640 480 -427 640 -500 393 -427 640 -480 640 -500 375 -640 589 -640 427 -640 359 -640 480 -640 426 -500 375 -640 480 -423 640 -375 500 -640 427 -640 480 -640 427 -640 427 -640 441 -427 640 -426 640 -640 424 -511 640 -640 428 -427 640 -500 375 -500 331 -500 488 -640 427 -640 480 -640 510 -640 426 -640 480 -640 425 -640 429 -640 427 -359 640 -640 425 -640 383 -375 500 -330 500 -640 480 -640 427 -500 375 -640 426 -500 333 -640 386 -640 427 -400 300 -500 375 -500 375 -640 482 -640 360 -640 480 -640 421 -640 480 -480 640 -525 640 -640 244 -640 480 -482 640 -640 294 -640 480 -640 480 -375 500 -496 640 -640 525 -478 640 -640 480 -640 480 -486 640 -640 426 -640 480 -640 480 -480 640 -640 480 -640 480 -640 480 -640 427 -500 321 -427 640 -427 640 -640 480 -254 336 -640 427 -640 480 -640 640 -400 284 -640 480 -640 541 -640 590 -480 640 -425 640 -640 427 -640 457 -425 640 -640 480 -640 427 -640 425 -640 505 -640 559 -640 426 -640 480 -640 425 -640 427 -500 375 -480 640 -640 427 -479 640 -480 640 -640 478 -640 480 -500 333 -640 480 -640 427 -640 426 -640 511 -640 428 -640 480 -640 426 -480 640 -333 500 -640 480 -640 426 -640 426 -640 427 -458 640 -640 400 -424 640 -640 480 -640 318 -640 427 -360 640 -640 480 -640 480 -640 480 -640 480 -612 612 -640 389 -640 457 -640 480 -500 334 -640 480 -425 640 -640 480 -640 401 -640 480 -640 399 -640 427 -500 274 -213 320 -480 640 -333 500 -640 480 -512 640 -640 427 -640 480 -640 480 -640 427 -640 426 -640 480 -640 379 -640 480 -425 640 -427 640 -640 480 -640 640 -500 333 -354 500 -640 480 -426 640 -640 480 -503 640 -640 480 -427 640 -640 480 -500 375 -640 478 -500 375 -640 480 -427 640 -640 425 -640 427 -640 426 -500 332 -516 640 -428 640 -640 480 -401 131 -640 443 -480 640 -360 640 -480 640 -500 375 -640 474 -503 640 -640 480 -640 427 -640 480 -640 480 -640 427 -640 480 -640 456 -640 427 -640 597 -640 450 -640 383 -640 426 -640 428 -640 427 -480 640 -640 480 -640 440 -640 426 -640 457 -640 480 -480 640 -640 429 -640 426 -500 332 -640 360 -640 478 -480 640 -640 427 -640 480 -500 375 -640 480 -640 478 -640 480 -640 427 -500 375 -640 428 -480 640 -426 640 -640 304 -640 480 -640 427 -612 612 -640 480 -640 480 -640 512 -375 500 -640 427 -500 334 -500 374 -333 500 -612 612 -640 400 -640 284 -640 480 -425 640 -640 486 -640 426 -480 640 -640 427 -640 480 -640 480 -426 640 -640 381 -640 426 -640 481 -640 480 -500 351 -427 640 -500 375 -640 427 -640 427 -640 480 -640 480 -640 480 -500 427 -640 425 -640 427 -640 427 -640 480 -600 400 -359 500 -500 375 -640 480 -640 489 -500 375 -529 640 -500 375 -640 480 -480 640 -640 480 -480 640 -640 444 -427 640 -640 425 -640 426 -612 612 -640 480 -500 357 -418 640 -427 640 -427 640 -500 382 -640 480 -426 640 -375 500 -640 478 -640 478 -500 333 -640 493 -500 333 -357 500 -603 640 -480 640 -640 427 -640 427 -612 612 -640 480 -640 453 -500 334 -640 480 -500 375 -640 480 -640 480 -640 426 -640 480 -640 424 -500 335 -480 640 -640 480 -480 640 -480 640 -640 424 -640 427 -480 640 -500 333 -640 427 -500 375 -640 480 -500 375 -640 427 -640 480 -640 427 -500 375 -427 640 -640 471 -640 480 -640 480 -640 579 -640 427 -480 640 -612 612 -373 640 -640 427 -610 391 -640 253 -640 429 -640 426 -640 425 -640 538 -427 640 -480 640 -640 428 -640 424 -640 427 -640 480 -640 349 -480 640 -640 478 -640 351 -640 384 -400 600 -500 375 -640 522 -640 480 -640 518 -640 427 -333 500 -640 391 -480 640 -467 640 -612 612 -640 426 -500 375 -516 640 -480 640 -333 500 -640 480 -364 468 -500 399 -427 640 -500 400 -640 464 -640 480 -640 429 -341 640 -425 640 -375 500 -640 432 -640 334 -640 427 -480 640 -640 480 -500 375 -451 640 -640 480 -640 480 -640 480 -640 427 -640 470 -640 426 -640 430 -640 482 -640 427 -500 375 -640 360 -500 375 -500 375 -640 462 -612 612 -640 480 -640 425 -426 640 -500 334 -640 427 -436 640 -640 480 -500 375 -640 427 -500 363 -640 457 -500 334 -500 429 -480 640 -640 428 -640 427 -640 427 -500 332 -640 319 -500 336 -640 481 -432 500 -500 333 -640 360 -640 427 -461 640 -640 480 -500 326 -640 425 -480 640 -640 427 -640 427 -640 431 -640 427 -640 539 -640 487 -427 640 -640 526 -640 427 -640 427 -612 612 -442 500 -640 480 -640 495 -480 640 -424 640 -480 640 -640 459 -640 480 -640 426 -640 427 -640 425 -640 480 -640 427 -640 458 -640 427 -640 362 -640 428 -640 451 -640 423 -480 640 -640 428 -640 480 -640 480 -480 640 -640 480 -640 421 -640 427 -480 640 -480 640 -640 480 -640 428 -480 640 -640 427 -640 480 -640 427 -640 427 -640 427 -427 640 -640 427 -500 375 -640 427 -640 427 -640 426 -439 603 -640 445 -640 480 -640 426 -560 640 -480 640 -640 316 -640 480 -427 640 -480 640 -640 480 -640 427 -431 640 -375 500 -640 480 -640 480 -640 427 -640 428 -640 427 -640 443 -620 367 -640 427 -640 480 -640 427 -640 581 -640 480 -640 480 -640 480 -640 640 -500 375 -640 494 -480 640 -640 480 -640 425 -640 480 -640 480 -554 640 -640 480 -425 640 -478 640 -500 375 -640 480 -640 480 -640 427 -480 640 -640 480 -427 640 -526 640 -500 375 -416 640 -640 427 -640 480 -332 500 -640 424 -427 640 -640 448 -640 640 -640 427 -640 427 -640 480 -640 426 -640 480 -500 375 -480 640 -640 427 -500 375 -640 480 -518 640 -640 480 -640 435 -500 375 -500 375 -639 640 -463 640 -500 324 -500 375 -480 640 -480 640 -640 396 -640 426 -383 640 -640 351 -640 427 -500 493 -640 480 -640 480 -500 375 -640 427 -640 429 -640 480 -640 480 -480 640 -640 452 -500 384 -375 500 -500 334 -640 428 -427 640 -640 480 -640 480 -640 640 -640 480 -640 427 -640 424 -640 427 -640 463 -640 480 -640 480 -640 421 -640 428 -640 427 -478 640 -640 480 -640 427 -500 375 -640 480 -640 427 -640 427 -426 640 -640 480 -640 480 -640 480 -640 480 -640 433 -640 480 -640 425 -640 480 -375 500 -640 428 -640 427 -640 430 -480 640 -480 640 -640 480 -640 398 -640 428 -640 480 -640 478 -426 640 -451 451 -640 480 -640 434 -339 500 -640 511 -640 415 -640 640 -480 640 -374 500 -427 640 -640 427 -640 561 -640 478 -640 427 -640 480 -500 375 -413 640 -640 521 -443 640 -425 640 -375 500 -500 375 -640 480 -640 480 -640 426 -640 426 -427 640 -640 478 -640 480 -612 612 -428 640 -640 480 -602 640 -448 640 -319 500 -500 375 -480 640 -480 640 -640 146 -640 427 -640 427 -640 427 -640 512 -480 640 -295 640 -640 427 -640 475 -640 426 -640 480 -640 360 -640 480 -426 640 -480 640 -640 480 -500 375 -640 427 -640 426 -640 480 -640 427 -640 480 -361 640 -640 480 -640 480 -333 500 -442 640 -640 480 -640 480 -640 427 -640 480 -500 375 -640 449 -500 375 -640 378 -500 376 -480 640 -640 460 -500 375 -640 480 -500 375 -428 640 -427 640 -640 360 -640 427 -640 479 -640 427 -640 480 -500 375 -640 452 -640 405 -640 481 -640 495 -640 427 -640 480 -396 640 -640 360 -640 427 -640 480 -480 640 -640 427 -640 427 -640 480 -640 331 -640 480 -640 432 -500 375 -640 480 -640 480 -640 480 -500 375 -640 427 -640 480 -640 433 -480 640 -640 425 -480 640 -640 480 -480 640 -640 428 -640 480 -571 640 -640 480 -640 480 -500 375 -640 490 -640 424 -640 459 -500 375 -640 360 -612 612 -640 480 -640 426 -640 476 -640 428 -500 375 -640 480 -640 480 -478 640 -640 512 -640 480 -640 418 -640 481 -640 562 -604 403 -640 426 -640 425 -425 640 -640 590 -640 425 -640 414 -500 333 -640 480 -640 428 -640 427 -640 480 -426 640 -479 640 -480 640 -640 480 -640 640 -640 426 -640 516 -500 375 -480 640 -500 375 -640 427 -640 486 -500 375 -500 334 -400 500 -640 428 -640 412 -640 427 -612 612 -640 456 -640 502 -640 424 -640 426 -461 640 -640 480 -480 640 -640 480 -640 601 -640 427 -640 480 -640 360 -640 603 -640 417 -640 480 -640 503 -640 427 -640 480 -640 427 -640 487 -640 441 -640 427 -612 612 -500 375 -427 640 -500 311 -640 426 -640 459 -640 513 -640 426 -500 375 -426 640 -640 480 -427 640 -640 405 -427 640 -640 446 -640 480 -480 640 -640 427 -640 359 -640 424 -486 500 -375 500 -640 480 -640 427 -640 425 -640 406 -640 428 -480 640 -640 481 -640 539 -480 640 -375 500 -500 332 -640 480 -640 428 -640 426 -500 500 -500 333 -640 262 -500 375 -480 640 -480 640 -541 640 -480 640 -640 640 -640 427 -375 500 -640 640 -640 459 -640 480 -640 487 -500 375 -640 429 -424 640 -640 640 -500 372 -640 480 -404 640 -640 480 -480 640 -640 480 -640 427 -640 427 -424 640 -640 426 -640 428 -640 428 -640 480 -640 426 -500 375 -458 640 -640 480 -640 480 -360 640 -480 640 -640 569 -640 480 -640 480 -640 426 -640 427 -640 425 -480 640 -640 455 -640 427 -640 427 -640 480 -640 358 -612 612 -428 640 -640 480 -425 640 -640 427 -640 427 -640 427 -500 332 -640 480 -480 640 -500 375 -640 427 -640 480 -600 450 -640 480 -427 640 -640 352 -640 480 -640 480 -640 480 -480 640 -640 480 -640 427 -640 480 -640 425 -500 333 -427 640 -360 640 -640 552 -480 640 -480 640 -500 375 -640 486 -640 480 -640 360 -307 461 -640 480 -640 427 -426 640 -500 436 -480 640 -500 333 -640 480 -480 640 -640 640 -334 500 -333 500 -425 640 -640 354 -500 375 -640 480 -640 480 -640 480 -480 640 -500 375 -640 508 -640 376 -640 480 -640 480 -640 480 -612 612 -612 612 -423 640 -389 640 -640 640 -500 334 -500 375 -640 480 -332 500 -640 480 -500 333 -490 640 -640 425 -600 449 -640 391 -387 600 -640 360 -425 640 -640 360 -640 480 -640 277 -640 480 -640 428 -640 411 -480 640 -500 375 -640 480 -640 426 -640 427 -640 480 -640 427 -640 427 -480 640 -640 640 -640 640 -640 480 -500 334 -391 640 -640 415 -640 480 -480 640 -640 427 -480 640 -640 480 -389 500 -640 427 -640 396 -640 427 -640 480 -640 480 -640 480 -640 303 -640 480 -640 436 -640 429 -457 640 -640 427 -500 375 -640 427 -640 480 -640 425 -640 480 -640 489 -640 419 -640 569 -640 480 -424 640 -640 427 -640 416 -640 418 -640 371 -640 428 -500 413 -640 427 -640 480 -480 640 -640 561 -640 423 -500 375 -640 480 -640 360 -640 480 -529 640 -640 425 -480 640 -428 640 -640 480 -640 409 -359 640 -427 640 -374 436 -640 428 -640 360 -640 426 -500 375 -640 480 -640 360 -640 427 -480 640 -640 425 -640 480 -500 333 -426 640 -640 427 -640 480 -640 428 -480 640 -480 640 -433 640 -640 428 -640 483 -640 401 -640 428 -480 640 -427 640 -640 298 -427 640 -640 480 -480 640 -427 640 -480 640 -500 332 -640 480 -640 480 -640 480 -640 466 -640 425 -640 480 -640 427 -640 445 -640 427 -484 500 -640 320 -640 480 -612 612 -427 640 -640 480 -640 425 -612 612 -640 426 -640 427 -504 640 -500 375 -425 640 -640 424 -427 640 -640 480 -640 427 -640 427 -640 346 -640 480 -640 427 -640 480 -640 371 -640 426 -640 480 -500 493 -640 480 -640 480 -640 427 -640 480 -640 360 -612 612 -640 418 -640 480 -640 427 -435 640 -640 425 -500 375 -500 375 -429 640 -339 500 -640 426 -640 427 -640 428 -640 427 -375 500 -640 360 -640 384 -640 428 -640 371 -640 424 -640 426 -612 612 -640 480 -500 357 -500 375 -612 612 -640 480 -640 427 -500 333 -640 640 -427 640 -640 267 -640 480 -640 382 -426 640 -640 481 -640 481 -480 640 -490 640 -425 640 -612 612 -640 480 -640 480 -640 427 -480 640 -640 480 -640 427 -640 480 -612 612 -640 426 -424 640 -640 480 -640 427 -640 427 -640 427 -640 426 -500 375 -640 480 -640 401 -375 500 -640 426 -640 480 -640 414 -332 500 -640 436 -640 480 -640 480 -640 480 -480 640 -500 375 -500 235 -640 480 -500 375 -640 476 -480 640 -640 506 -640 427 -640 429 -375 500 -640 480 -375 500 -425 640 -440 640 -640 427 -640 428 -640 480 -640 425 -640 360 -640 480 -640 480 -640 480 -538 640 -427 640 -640 480 -640 480 -640 303 -640 468 -640 426 -640 576 -640 382 -640 476 -640 640 -640 427 -500 375 -640 428 -500 375 -640 480 -640 480 -640 480 -640 480 -500 375 -640 480 -480 640 -480 640 -640 503 -640 430 -640 480 -640 426 -428 640 -428 640 -640 427 -640 351 -640 438 -480 640 -640 640 -640 360 -640 578 -640 480 -640 427 -640 426 -640 427 -480 640 -640 427 -480 640 -640 437 -500 379 -500 374 -640 480 -640 429 -640 428 -640 427 -640 427 -640 480 -480 640 -478 640 -640 480 -427 640 -640 298 -640 480 -640 480 -640 426 -640 480 -640 361 -424 640 -640 480 -640 419 -640 481 -480 640 -640 426 -640 428 -480 640 -480 640 -640 480 -427 640 -640 425 -640 480 -640 427 -640 424 -500 375 -640 427 -640 427 -427 640 -480 640 -640 427 -640 427 -640 428 -640 428 -640 427 -640 425 -500 333 -640 480 -640 427 -640 480 -640 478 -640 426 -500 375 -640 427 -640 498 -640 364 -500 375 -640 427 -640 480 -640 429 -480 640 -480 640 -640 424 -640 478 -640 427 -375 500 -388 500 -640 427 -640 426 -640 383 -640 426 -640 480 -640 396 -640 353 -640 425 -640 374 -640 427 -640 480 -640 480 -640 480 -480 640 -493 640 -640 480 -640 427 -480 640 -640 433 -640 480 -640 425 -640 427 -612 612 -640 495 -480 640 -640 480 -640 480 -640 478 -264 640 -640 427 -436 640 -640 425 -640 428 -640 480 -640 480 -427 640 -425 640 -427 640 -640 344 -500 375 -600 450 -640 480 -640 426 -480 640 -640 458 -640 640 -640 457 -640 426 -640 428 -640 442 -640 480 -640 480 -640 428 -640 480 -640 480 -426 640 -427 640 -640 640 -640 480 -640 640 -640 427 -640 411 -640 507 -640 480 -640 480 -640 425 -612 612 -500 346 -640 640 -640 424 -500 332 -612 612 -640 480 -480 640 -640 480 -500 375 -333 500 -640 427 -640 480 -640 501 -640 359 -640 427 -425 640 -640 432 -640 481 -640 426 -640 480 -640 480 -640 480 -480 640 -640 426 -640 482 -480 640 -640 428 -640 480 -640 428 -640 428 -500 375 -640 578 -640 428 -500 333 -640 480 -640 428 -640 480 -640 410 -640 427 -500 333 -640 426 -640 480 -640 361 -612 612 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -640 487 -640 426 -640 381 -640 428 -640 427 -360 480 -640 361 -480 640 -500 333 -640 478 -428 640 -640 360 -640 427 -640 480 -500 375 -480 640 -375 500 -500 318 -613 640 -427 640 -640 427 -640 480 -480 640 -500 388 -180 240 -640 444 -640 480 -640 426 -500 375 -509 640 -640 426 -640 564 -640 427 -269 640 -640 480 -638 356 -640 480 -458 640 -500 375 -640 480 -480 361 -640 480 -500 375 -640 427 -500 375 -640 360 -640 428 -640 409 -640 427 -640 360 -640 427 -640 640 -640 480 -640 427 -640 412 -306 408 -427 640 -640 425 -640 480 -640 480 -414 640 -640 427 -428 640 -640 304 -640 480 -640 427 -640 425 -640 640 -480 640 -640 480 -640 427 -458 640 -640 480 -480 640 -640 480 -640 427 -640 480 -480 640 -640 428 -480 640 -500 375 -640 429 -640 588 -640 481 -640 418 -434 640 -640 422 -640 427 -640 480 -640 491 -640 426 -640 427 -640 480 -640 480 -500 375 -640 427 -640 510 -478 640 -500 375 -640 456 -640 427 -480 640 -480 640 -640 480 -640 481 -640 501 -427 640 -640 480 -375 500 -640 416 -500 375 -500 375 -640 480 -480 640 -375 500 -640 439 -458 640 -640 399 -500 282 -640 480 -640 427 -640 427 -428 640 -640 480 -640 480 -500 375 -640 426 -425 640 -640 480 -640 480 -640 480 -640 427 -640 427 -640 480 -424 640 -640 437 -640 427 -500 375 -426 640 -640 424 -417 640 -640 480 -640 480 -480 640 -640 480 -640 427 -640 536 -567 640 -640 425 -640 480 -640 457 -640 640 -640 478 -640 360 -640 427 -640 480 -640 427 -333 500 -640 434 -640 425 -640 424 -480 640 -612 612 -640 425 -640 480 -640 438 -495 500 -426 640 -640 427 -429 640 -640 558 -640 428 -640 480 -500 188 -480 640 -640 360 -612 612 -640 425 -640 424 -640 428 -640 480 -640 428 -500 244 -500 375 -500 375 -640 425 -478 640 -640 428 -640 480 -640 427 -500 375 -426 640 -640 480 -640 457 -640 480 -640 320 -640 383 -640 359 -640 436 -640 426 -640 427 -640 361 -640 428 -640 480 -640 424 -640 475 -640 414 -480 640 -360 640 -480 640 -640 480 -612 612 -640 427 -338 450 -640 427 -464 640 -640 421 -640 480 -640 428 -640 427 -500 375 -640 480 -640 427 -640 480 -640 427 -640 480 -500 375 -480 640 -640 426 -640 425 -538 640 -640 480 -640 480 -640 480 -640 480 -478 640 -640 478 -640 427 -640 480 -640 480 -500 375 -640 427 -480 640 -640 480 -427 640 -640 480 -640 509 -640 480 -640 471 -640 480 -612 612 -337 500 -640 480 -427 640 -513 640 -640 480 -474 640 -640 428 -480 640 -325 500 -640 480 -640 426 -640 481 -409 640 -640 360 -640 311 -640 426 -413 640 -640 424 -640 480 -639 640 -640 427 -640 480 -383 500 -427 640 -335 500 -640 427 -640 426 -640 427 -640 480 -640 425 -640 427 -640 427 -640 480 -640 433 -480 640 -640 416 -640 366 -640 427 -640 480 -640 391 -333 500 -640 436 -640 425 -640 428 -640 480 -542 640 -431 640 -640 427 -640 480 -334 500 -640 480 -640 425 -423 640 -425 640 -494 640 -480 640 -640 427 -640 427 -500 375 -550 412 -640 518 -640 429 -640 427 -640 480 -640 481 -640 480 -640 480 -640 477 -640 427 -640 427 -640 487 -640 426 -640 480 -512 384 -640 516 -640 435 -457 640 -480 640 -640 427 -376 500 -413 500 -640 431 -480 640 -427 640 -640 433 -640 480 -640 484 -640 428 -640 359 -640 426 -500 375 -500 375 -500 400 -480 640 -480 640 -450 338 -427 640 -500 333 -640 480 -640 361 -640 480 -427 640 -640 424 -640 425 -375 500 -419 500 -640 427 -500 375 -640 427 -463 640 -640 480 -640 434 -500 333 -500 375 -500 375 -640 427 -480 640 -640 480 -640 480 -640 427 -640 480 -480 640 -640 480 -498 640 -612 612 -640 427 -640 480 -359 640 -500 333 -426 640 -640 480 -424 640 -375 500 -640 493 -500 333 -640 480 -427 640 -640 429 -640 480 -480 640 -640 480 -640 360 -640 460 -640 427 -640 480 -500 334 -640 457 -640 401 -500 381 -640 427 -640 411 -640 424 -640 427 -500 357 -404 640 -463 640 -640 428 -640 427 -640 480 -426 640 -640 426 -426 640 -640 481 -640 427 -640 481 -640 427 -640 427 -480 640 -427 640 -333 500 -640 480 -640 480 -640 428 -425 640 -427 640 -640 480 -640 480 -427 640 -640 426 -640 480 -480 640 -640 426 -503 640 -480 640 -640 480 -333 500 -640 480 -640 426 -640 480 -640 428 -640 480 -480 640 -640 426 -640 427 -640 480 -388 640 -640 374 -640 427 -480 640 -427 640 -500 375 -640 429 -640 585 -640 427 -500 383 -640 427 -640 394 -640 426 -640 480 -333 500 -426 640 -640 480 -427 640 -640 422 -640 480 -640 426 -640 425 -428 640 -640 427 -640 427 -640 425 -640 427 -640 480 -640 348 -640 480 -640 427 -640 480 -345 500 -640 384 -640 480 -640 427 -480 640 -640 427 -640 426 -640 480 -480 640 -332 500 -640 427 -640 480 -640 480 -640 543 -640 429 -640 415 -640 640 -500 377 -500 375 -640 426 -640 480 -640 519 -640 480 -640 361 -427 640 -640 480 -640 429 -640 427 -640 634 -480 640 -479 640 -427 640 -500 375 -500 452 -500 375 -640 431 -640 429 -640 427 -640 426 -640 424 -160 120 -427 640 -640 480 -640 480 -640 424 -427 640 -640 480 -640 417 -640 480 -500 333 -273 500 -640 640 -500 334 -386 336 -640 450 -640 426 -640 480 -427 640 -640 480 -640 480 -625 640 -640 427 -157 160 -480 640 -640 480 -500 367 -640 359 -500 375 -640 428 -500 375 -500 319 -375 500 -640 427 -640 426 -480 640 -640 480 -640 480 -640 427 -640 473 -640 425 -640 394 -383 640 -640 426 -640 427 -640 427 -640 428 -640 427 -640 480 -640 570 -480 640 -500 333 -640 457 -640 422 -640 480 -640 480 -640 640 -640 383 -640 427 -640 425 -640 256 -426 640 -640 427 -640 478 -640 427 -500 375 -640 424 -640 480 -640 478 -500 375 -640 427 -640 427 -640 427 -640 479 -500 334 -375 500 -640 425 -428 640 -640 425 -640 640 -640 428 -434 500 -640 429 -640 503 -640 424 -640 427 -640 480 -640 440 -640 480 -427 640 -640 480 -612 612 -640 425 -640 400 -640 428 -640 480 -640 427 -427 640 -640 446 -640 464 -640 480 -333 500 -640 361 -640 480 -640 480 -427 640 -640 428 -612 612 -426 640 -640 427 -640 480 -500 412 -495 640 -640 426 -427 640 -640 424 -640 427 -640 480 -480 640 -640 480 -413 500 -640 426 -386 640 -640 480 -640 487 -640 480 -480 640 -600 400 -640 480 -500 375 -640 513 -640 426 -640 322 -500 375 -640 480 -427 640 -428 640 -640 480 -640 425 -454 640 -640 424 -427 640 -640 359 -480 640 -640 509 -640 428 -640 480 -480 640 -640 480 -640 480 -640 426 -640 427 -640 480 -640 426 -640 480 -640 479 -640 493 -640 480 -480 640 -640 480 -500 375 -640 427 -640 318 -640 480 -640 480 -640 425 -640 480 -640 533 -640 427 -640 480 -640 426 -640 427 -640 427 -400 600 -640 373 -640 426 -640 424 -640 557 -640 427 -640 427 -640 427 -640 427 -640 413 -426 640 -640 480 -540 640 -640 480 -640 427 -427 640 -640 454 -640 480 -640 480 -480 640 -640 480 -640 481 -640 440 -500 375 -640 480 -640 480 -640 480 -427 640 -376 500 -640 480 -640 480 -640 523 -640 427 -640 640 -640 480 -640 480 -500 333 -640 336 -606 640 -640 427 -612 612 -640 480 -640 480 -640 480 -640 480 -427 640 -425 640 -640 480 -640 480 -502 640 -612 612 -640 480 -640 485 -640 313 -480 640 -640 427 -640 427 -640 429 -640 427 -640 513 -640 480 -640 480 -640 426 -640 480 -640 480 -480 640 -640 426 -640 480 -640 480 -640 427 -640 480 -523 640 -640 426 -375 500 -426 640 -640 425 -640 425 -427 640 -640 480 -640 427 -640 480 -429 640 -640 427 -500 378 -639 640 -640 427 -640 480 -478 640 -640 480 -640 426 -500 375 -640 426 -411 640 -640 480 -640 480 -640 480 -640 427 -640 424 -640 371 -640 478 -640 480 -640 425 -640 480 -375 500 -424 640 -500 500 -640 427 -640 480 -640 426 -640 426 -640 480 -500 375 -640 424 -640 427 -640 427 -429 640 -640 378 -498 640 -640 408 -640 480 -480 640 -427 640 -640 427 -640 480 -640 480 -500 375 -500 351 -640 188 -640 486 -640 428 -640 427 -640 424 -640 364 -640 364 -640 384 -500 356 -640 431 -640 427 -640 480 -640 426 -500 375 -500 375 -640 429 -640 425 -640 448 -640 480 -640 480 -640 483 -640 427 -500 375 -375 500 -480 640 -640 354 -640 427 -640 426 -500 375 -640 427 -640 480 -640 480 -640 480 -500 371 -612 612 -640 480 -640 554 -640 549 -640 480 -500 375 -640 360 -640 427 -640 427 -640 480 -500 340 -500 333 -375 500 -640 480 -375 500 -640 394 -640 480 -640 480 -640 427 -640 640 -459 640 -640 480 -640 360 -427 640 -640 224 -480 640 -640 427 -640 428 -500 375 -640 429 -640 480 -640 427 -582 640 -640 480 -640 428 -640 451 -354 640 -426 640 -640 512 -640 480 -640 640 -425 640 -480 640 -640 427 -640 447 -640 480 -500 334 -480 640 -480 640 -640 428 -500 375 -500 375 -640 428 -640 428 -640 480 -640 480 -640 428 -571 640 -500 375 -640 481 -427 640 -500 375 -640 480 -640 480 -640 426 -453 640 -500 335 -640 426 -568 320 -640 429 -640 427 -640 480 -640 480 -640 449 -500 375 -640 424 -500 375 -480 640 -640 319 -640 480 -427 640 -640 427 -480 640 -640 428 -640 428 -640 480 -640 427 -640 478 -427 640 -500 402 -424 640 -640 427 -640 427 -640 480 -640 426 -480 640 -427 640 -640 480 -640 480 -640 480 -480 640 -640 480 -500 286 -427 640 -375 500 -640 427 -640 427 -640 480 -480 640 -500 332 -500 375 -640 427 -640 480 -640 482 -640 456 -640 427 -640 399 -640 480 -640 423 -338 500 -424 640 -640 480 -640 427 -427 640 -640 428 -640 480 -640 640 -640 428 -500 332 -640 480 -640 427 -640 427 -640 424 -640 423 -500 375 -640 480 -640 427 -640 480 -640 360 -480 640 -640 429 -640 478 -500 375 -597 400 -640 426 -465 500 -640 425 -640 480 -640 427 -640 480 -640 480 -429 640 -462 640 -447 640 -640 426 -640 423 -640 426 -640 347 -640 427 -500 375 -640 480 -640 427 -640 426 -640 480 -500 332 -360 640 -427 640 -370 640 -640 426 -640 480 -640 480 -640 427 -640 478 -640 427 -640 427 -427 640 -640 514 -640 426 -622 640 -640 519 -479 640 -500 375 -640 597 -640 429 -640 396 -640 427 -589 640 -640 480 -640 427 -640 480 -640 424 -500 484 -500 375 -640 510 -640 427 -640 470 -480 640 -640 413 -612 612 -640 480 -640 480 -500 333 -427 640 -375 500 -612 612 -640 480 -640 480 -640 480 -426 640 -640 427 -640 428 -640 480 -612 612 -640 429 -456 640 -640 480 -640 484 -480 360 -640 420 -483 640 -640 427 -640 427 -640 427 -640 407 -512 640 -640 480 -480 640 -640 351 -640 480 -640 381 -427 640 -500 375 -640 427 -640 436 -640 480 -480 640 -640 480 -480 640 -640 408 -640 473 -375 500 -640 427 -640 427 -500 375 -640 426 -640 434 -640 425 -640 427 -512 640 -640 426 -612 612 -612 612 -640 480 -640 480 -375 500 -640 428 -640 480 -480 640 -426 640 -640 428 -480 640 -640 427 -640 480 -500 231 -640 427 -427 640 -640 571 -375 500 -417 640 -525 640 -500 375 -640 480 -640 480 -500 333 -360 640 -640 416 -427 640 -640 480 -640 427 -640 427 -640 427 -640 426 -640 427 -640 480 -500 375 -640 480 -500 375 -640 354 -480 640 -480 417 -612 612 -640 480 -640 427 -640 427 -500 375 -480 640 -640 640 -640 427 -640 480 -640 485 -640 366 -427 640 -500 375 -640 425 -640 480 -640 427 -640 480 -640 427 -500 398 -500 375 -640 429 -500 375 -640 427 -640 640 -480 640 -480 640 -640 427 -640 480 -640 427 -640 421 -409 307 -400 500 -640 428 -640 427 -480 640 -500 373 -500 309 -640 480 -500 375 -640 427 -640 480 -640 638 -500 375 -480 640 -640 480 -640 480 -640 454 -640 425 -640 360 -427 640 -640 427 -478 640 -640 481 -480 640 -500 375 -427 640 -500 375 -427 640 -500 348 -428 640 -640 480 -424 640 -640 480 -500 332 -376 500 -500 375 -640 480 -640 480 -640 480 -553 640 -640 515 -640 427 -500 375 -640 427 -640 427 -480 640 -640 427 -640 427 -640 359 -640 512 -640 425 -640 480 -481 640 -612 612 -640 480 -500 333 -640 427 -640 427 -480 640 -640 427 -640 480 -500 336 -640 425 -640 481 -344 640 -339 500 -407 640 -640 427 -640 480 -640 480 -426 640 -640 480 -640 480 -640 427 -333 500 -640 386 -640 480 -640 423 -333 500 -640 480 -640 427 -640 427 -640 481 -640 480 -500 375 -640 480 -640 426 -480 640 -640 427 -640 360 -640 480 -640 457 -640 376 -500 375 -612 612 -640 480 -640 427 -448 336 -640 427 -640 427 -640 480 -386 500 -640 470 -640 480 -427 640 -640 415 -424 640 -640 426 -640 425 -640 427 -640 480 -640 427 -375 500 -640 480 -640 427 -640 428 -640 427 -640 480 -640 480 -425 640 -600 400 -640 428 -427 640 -640 427 -640 501 -640 431 -500 375 -640 426 -640 427 -640 365 -640 425 -499 371 -640 426 -480 640 -481 640 -640 426 -640 427 -640 360 -640 480 -640 489 -500 500 -640 640 -640 428 -640 548 -480 640 -469 500 -640 428 -640 425 -640 426 -640 480 -640 427 -640 424 -640 468 -640 428 -640 427 -640 378 -640 430 -640 427 -640 480 -426 640 -640 427 -640 469 -497 640 -480 640 -640 480 -640 283 -410 640 -640 426 -640 481 -640 358 -640 480 -640 480 -640 439 -640 480 -640 480 -425 640 -640 340 -500 375 -640 379 -640 480 -640 475 -480 640 -640 514 -480 640 -640 427 -640 425 -640 480 -640 454 -640 428 -640 428 -500 375 -640 480 -640 424 -500 332 -640 427 -500 375 -640 427 -500 375 -640 576 -607 640 -640 480 -640 427 -640 480 -640 480 -427 640 -640 427 -640 480 -427 640 -500 333 -425 640 -600 466 -640 427 -640 540 -640 427 -640 461 -640 480 -640 480 -640 424 -640 480 -640 480 -640 480 -427 640 -500 375 -640 480 -640 446 -640 391 -480 640 -500 375 -640 420 -640 429 -426 640 -469 640 -640 640 -640 426 -640 480 -640 480 -640 427 -640 442 -380 640 -640 480 -500 375 -428 640 -640 415 -418 500 -640 425 -480 640 -640 531 -427 640 -640 473 -320 240 -640 457 -640 480 -640 423 -500 375 -375 500 -500 375 -640 427 -640 427 -327 500 -640 360 -500 332 -427 640 -385 500 -640 512 -500 417 -640 427 -640 480 -640 480 -480 640 -640 427 -640 426 -640 480 -211 500 -612 612 -480 640 -640 573 -640 427 -640 438 -640 360 -427 640 -500 333 -500 375 -480 640 -480 640 -640 480 -612 612 -640 360 -640 427 -640 425 -612 612 -640 480 -640 480 -427 640 -628 442 -480 640 -612 612 -640 480 -640 427 -640 478 -480 640 -480 640 -498 640 -500 375 -640 443 -640 427 -640 427 -640 428 -339 500 -480 640 -640 427 -449 640 -500 378 -640 427 -640 395 -470 640 -640 480 -380 330 -640 458 -640 400 -506 640 -640 554 -480 640 -640 427 -333 500 -640 426 -640 427 -640 480 -640 427 -640 480 -640 480 -500 276 -612 612 -612 612 -500 375 -500 500 -640 480 -640 480 -500 370 -640 640 -500 375 -640 480 -640 462 -640 480 -640 564 -640 480 -640 427 -640 427 -500 333 -640 396 -640 427 -500 375 -640 426 -535 640 -640 480 -640 427 -640 400 -448 640 -640 480 -480 640 -334 500 -510 640 -480 640 -500 375 -640 427 -480 640 -640 480 -640 640 -480 640 -448 336 -640 361 -640 426 -480 640 -375 500 -640 480 -500 335 -640 360 -640 489 -480 640 -640 424 -640 480 -500 375 -640 480 -480 640 -500 339 -640 427 -424 640 -500 335 -640 480 -640 412 -640 366 -429 640 -426 640 -640 436 -640 350 -427 640 -640 427 -640 426 -640 480 -640 496 -640 426 -612 612 -640 480 -640 480 -426 640 -640 229 -640 640 -640 480 -640 442 -480 640 -480 640 -640 479 -500 332 -612 612 -640 425 -640 427 -500 333 -426 640 -500 373 -640 435 -640 427 -640 427 -376 500 -500 335 -640 480 -468 640 -640 426 -640 424 -640 419 -640 427 -640 428 -640 428 -500 333 -640 545 -640 360 -640 383 -640 634 -640 360 -640 427 -490 469 -640 425 -640 640 -640 480 -640 480 -640 427 -480 640 -640 424 -428 640 -424 640 -640 427 -640 480 -480 640 -640 480 -640 427 -440 500 -640 427 -426 640 -480 640 -640 428 -640 480 -500 411 -427 640 -640 480 -480 640 -176 384 -427 640 -425 640 -427 640 -640 427 -640 480 -480 640 -640 480 -478 640 -375 500 -640 480 -612 612 -479 500 -480 640 -500 367 -640 640 -640 512 -612 612 -500 500 -334 500 -640 425 -640 480 -640 480 -640 427 -640 425 -640 480 -600 400 -500 332 -612 612 -640 393 -640 480 -640 480 -424 640 -640 480 -640 640 -640 427 -640 435 -640 480 -640 427 -333 500 -512 640 -640 524 -640 480 -640 480 -640 478 -640 426 -375 500 -640 427 -426 640 -426 640 -480 640 -640 427 -640 426 -640 480 -640 425 -640 427 -640 480 -640 425 -640 427 -640 320 -640 426 -480 640 -424 640 -640 427 -640 480 -640 480 -500 333 -640 518 -640 480 -640 359 -640 426 -612 612 -640 427 -428 640 -640 427 -640 480 -427 640 -640 427 -426 640 -640 427 -640 480 -640 428 -640 480 -612 612 -640 523 -640 383 -640 427 -640 480 -640 427 -640 480 -640 480 -480 640 -480 640 -640 427 -640 426 -640 480 -640 432 -500 375 -640 427 -640 423 -640 480 -640 480 -500 375 -640 480 -640 480 -500 357 -640 427 -428 640 -640 426 -428 640 -480 640 -640 426 -612 612 -640 440 -480 640 -480 640 -640 480 -640 359 -500 375 -332 500 -640 427 -640 480 -640 400 -500 333 -340 500 -640 427 -640 448 -640 510 -640 427 -640 480 -429 640 -640 352 -640 436 -424 640 -450 600 -428 640 -640 480 -640 479 -640 427 -640 640 -480 640 -640 279 -640 423 -640 427 -640 425 -640 640 -640 427 -640 427 -427 640 -640 480 -512 480 -640 426 -427 640 -640 427 -640 480 -640 631 -640 425 -333 500 -378 500 -480 272 -640 480 -480 640 -640 443 -640 427 -427 640 -640 426 -640 480 -640 424 -640 506 -640 406 -480 640 -640 388 -640 424 -640 480 -640 407 -425 640 -640 388 -640 480 -640 494 -640 426 -640 480 -500 336 -426 640 -640 427 -640 426 -640 468 -427 640 -424 640 -500 333 -640 407 -612 612 -640 425 -500 333 -640 457 -640 480 -500 375 -480 640 -640 426 -640 480 -426 640 -640 423 -640 480 -640 427 -640 426 -640 480 -640 480 -640 480 -640 480 -640 412 -640 426 -612 612 -640 427 -426 640 -640 480 -640 376 -640 480 -640 404 -640 482 -640 427 -427 640 -640 426 -640 431 -640 425 -480 640 -382 500 -640 428 -375 500 -640 359 -640 427 -640 426 -640 485 -640 392 -640 332 -480 640 -640 425 -333 500 -640 426 -640 457 -500 340 -640 480 -500 326 -375 500 -640 396 -480 640 -333 500 -640 427 -640 480 -640 480 -640 427 -640 429 -640 427 -640 476 -428 640 -640 480 -427 640 -640 495 -640 480 -500 334 -640 508 -640 480 -640 457 -640 427 -640 480 -500 375 -425 640 -640 290 -500 330 -466 640 -500 375 -640 480 -640 480 -640 600 -640 640 -480 640 -640 426 -640 427 -640 427 -427 640 -640 473 -640 428 -640 480 -640 480 -640 480 -640 480 -640 427 -640 427 -500 375 -640 427 -426 640 -640 422 -640 480 -640 480 -640 425 -640 426 -640 427 -480 640 -640 426 -640 427 -335 500 -640 427 -640 480 -396 640 -640 480 -640 427 -425 640 -480 640 -640 494 -640 427 -640 480 -500 375 -480 640 -640 478 -514 640 -640 433 -640 480 -400 500 -640 426 -640 426 -480 640 -640 427 -500 333 -640 360 -640 478 -480 640 -640 427 -479 640 -478 640 -612 612 -512 640 -640 480 -640 427 -500 335 -640 480 -640 360 -640 496 -375 500 -386 640 -640 428 -640 441 -640 480 -640 427 -480 640 -640 427 -640 428 -428 640 -425 640 -640 549 -480 640 -640 480 -640 480 -640 391 -640 480 -640 480 -480 640 -640 427 -640 480 -640 480 -640 512 -500 317 -478 640 -640 428 -640 427 -640 480 -640 480 -640 427 -640 436 -640 503 -640 426 -640 480 -640 426 -640 311 -640 427 -640 640 -640 425 -640 478 -480 640 -480 640 -640 427 -640 480 -640 480 -640 428 -640 504 -427 640 -640 478 -640 480 -640 559 -640 437 -612 612 -640 424 -640 480 -480 640 -640 459 -640 424 -640 426 -640 480 -640 426 -640 480 -640 480 -640 480 -640 480 -500 335 -640 480 -640 426 -640 427 -427 640 -640 427 -640 426 -480 640 -640 480 -640 480 -640 423 -640 424 -640 480 -640 427 -640 480 -640 480 -348 640 -375 500 -461 640 -427 640 -612 612 -640 457 -640 426 -640 506 -414 640 -640 417 -640 423 -640 478 -640 426 -500 375 -640 481 -640 428 -640 428 -600 600 -640 429 -500 375 -640 480 -640 501 -640 480 -640 479 -640 480 -640 480 -640 480 -480 640 -538 360 -500 375 -640 480 -480 640 -640 512 -424 640 -640 425 -640 425 -640 480 -640 424 -500 375 -640 480 -640 360 -427 640 -448 299 -640 392 -426 640 -640 427 -640 445 -612 612 -500 333 -640 518 -640 320 -640 428 -480 640 -640 428 -640 428 -640 480 -640 427 -375 500 -640 480 -500 438 -478 640 -500 375 -320 240 -640 480 -640 480 -640 326 -640 480 -640 480 -640 491 -423 640 -640 427 -640 428 -640 480 -640 428 -640 480 -480 640 -640 398 -640 480 -612 612 -640 480 -640 425 -640 437 -426 640 -640 480 -640 431 -640 427 -427 640 -500 375 -375 500 -486 640 -480 640 -640 427 -426 640 -425 640 -478 640 -333 500 -500 332 -640 480 -640 640 -640 480 -500 448 -427 640 -500 372 -640 426 -480 360 -640 426 -427 640 -426 640 -427 640 -466 640 -640 403 -333 500 -640 449 -329 469 -640 342 -640 478 -640 474 -640 480 -425 640 -640 399 -640 426 -640 480 -500 334 -612 612 -482 640 -425 640 -640 640 -640 486 -333 500 -640 208 -612 612 -640 480 -427 640 -427 640 -640 480 -425 640 -640 427 -500 334 -640 427 -640 380 -500 281 -640 425 -640 425 -640 425 -640 480 -478 640 -333 500 -640 427 -640 427 -640 480 -428 640 -640 427 -640 480 -480 640 -640 427 -640 480 -640 480 -640 503 -427 640 -612 612 -640 427 -640 480 -640 565 -612 612 -640 640 -500 377 -640 428 -640 424 -500 375 -500 375 -480 640 -640 427 -369 500 -640 441 -640 425 -640 480 -640 480 -640 480 -500 333 -500 375 -640 480 -424 640 -500 333 -640 502 -640 480 -640 480 -500 334 -640 480 -640 480 -501 640 -640 480 -640 480 -478 640 -640 428 -612 612 -480 640 -592 640 -640 480 -640 480 -640 427 -640 480 -640 480 -427 640 -640 547 -640 480 -640 480 -640 439 -640 480 -640 427 -481 640 -494 378 -640 405 -640 480 -640 399 -519 640 -640 480 -640 360 -640 480 -640 427 -640 427 -640 483 -379 500 -640 480 -640 427 -640 426 -640 429 -640 426 -383 640 -640 480 -640 601 -640 455 -640 480 -375 500 -640 427 -640 427 -640 426 -427 640 -640 427 -640 426 -640 426 -500 375 -640 480 -480 640 -480 640 -427 640 -427 640 -480 640 -480 640 -640 426 -640 480 -500 375 -425 640 -480 640 -375 500 -640 480 -640 425 -640 425 -640 516 -640 463 -640 361 -640 402 -427 640 -512 640 -361 640 -424 640 -427 640 -640 640 -480 640 -640 457 -373 500 -640 426 -640 480 -640 478 -640 479 -640 427 -427 640 -640 480 -500 375 -480 640 -640 427 -640 480 -640 480 -640 480 -640 425 -640 427 -640 480 -640 419 -427 640 -640 427 -640 427 -640 480 -480 640 -640 425 -640 640 -640 480 -640 400 -333 500 -427 640 -640 480 -612 612 -640 427 -640 513 -640 428 -397 500 -640 427 -640 480 -426 640 -428 640 -480 640 -333 500 -640 426 -500 333 -500 335 -448 640 -500 375 -480 640 -640 456 -640 427 -640 457 -500 375 -640 406 -640 427 -480 640 -500 377 -500 375 -640 431 -640 359 -640 640 -640 428 -427 640 -640 480 -426 640 -640 427 -480 640 -500 333 -640 480 -640 426 -640 496 -532 640 -640 450 -640 427 -640 480 -480 640 -640 428 -640 258 -640 383 -640 460 -640 480 -640 480 -375 500 -640 263 -500 375 -612 612 -640 308 -640 427 -484 640 -640 424 -500 375 -640 427 -330 500 -640 360 -640 427 -480 640 -640 424 -640 480 -500 329 -640 480 -640 354 -640 480 -640 480 -343 230 -640 451 -427 640 -640 427 -500 429 -640 480 -640 427 -640 454 -640 426 -427 640 -525 640 -640 463 -200 133 -640 480 -426 640 -640 534 -640 494 -500 400 -500 375 -612 612 -480 640 -640 480 -640 569 -621 600 -640 480 -640 426 -640 480 -640 640 -640 427 -500 375 -640 480 -640 423 -500 375 -640 424 -426 640 -333 500 -640 294 -476 640 -545 640 -426 640 -480 640 -441 640 -640 480 -640 427 -640 427 -486 640 -640 426 -640 427 -171 500 -375 500 -425 640 -640 427 -640 426 -640 426 -427 640 -640 480 -640 360 -640 640 -640 427 -332 500 -500 375 -320 240 -640 480 -640 416 -640 428 -640 488 -640 426 -640 426 -640 480 -629 640 -361 640 -640 428 -640 480 -640 427 -640 360 -640 475 -500 375 -640 480 -640 548 -500 375 -427 640 -640 479 -480 640 -478 640 -480 640 -640 480 -640 438 -468 640 -640 340 -640 480 -640 480 -640 427 -640 480 -640 427 -500 375 -640 427 -640 424 -640 480 -478 640 -480 640 -640 427 -640 529 -500 375 -640 426 -640 426 -640 480 -612 612 -640 359 -480 640 -640 360 -640 427 -425 640 -640 427 -424 640 -640 480 -640 422 -640 443 -640 427 -640 428 -640 640 -640 480 -640 424 -640 480 -640 480 -640 480 -500 375 -640 480 -500 375 -640 426 -640 333 -455 480 -480 640 -407 640 -500 334 -640 480 -427 640 -500 333 -500 375 -480 640 -640 423 -500 393 -480 640 -640 427 -333 500 -640 360 -418 640 -640 536 -640 428 -640 452 -640 384 -500 332 -490 640 -640 426 -640 425 -640 496 -640 428 -640 429 -640 300 -640 427 -481 640 -640 480 -640 427 -612 612 -341 500 -612 612 -640 299 -640 536 -640 480 -427 640 -640 360 -427 640 -640 427 -500 375 -500 333 -640 480 -424 640 -640 427 -640 427 -640 480 -426 640 -640 480 -640 427 -640 480 -500 375 -640 426 -640 480 -640 480 -640 424 -480 640 -640 427 -640 640 -640 427 -426 640 -640 480 -640 480 -640 640 -640 480 -640 486 -375 500 -640 480 -375 500 -480 640 -640 479 -640 427 -480 640 -640 425 -640 424 -500 295 -427 640 -427 640 -640 480 -640 426 -430 640 -640 427 -375 500 -640 360 -640 480 -427 640 -640 480 -375 500 -640 427 -640 359 -640 480 -500 333 -426 640 -640 427 -637 640 -640 425 -480 640 -427 640 -640 424 -640 479 -640 427 -457 640 -640 427 -480 640 -640 480 -640 427 -500 337 -427 640 -640 360 -500 375 -640 640 -480 640 -640 428 -428 640 -500 375 -480 640 -640 480 -640 480 -640 480 -640 484 -426 640 -480 640 -480 640 -500 375 -640 480 -387 640 -640 427 -640 425 -427 640 -640 427 -375 500 -640 480 -640 480 -427 640 -500 366 -640 480 -640 480 -640 472 -640 416 -640 426 -427 640 -640 480 -478 640 -640 425 -640 428 -428 640 -640 480 -493 640 -640 480 -640 424 -500 333 -640 427 -640 427 -640 480 -640 427 -640 470 -640 427 -375 500 -640 427 -500 499 -640 480 -640 427 -640 427 -480 640 -640 436 -640 375 -640 640 -640 404 -333 500 -500 361 -640 480 -640 424 -640 480 -640 480 -640 444 -640 426 -480 640 -470 640 -640 427 -640 427 -480 640 -640 428 -640 425 -640 427 -640 426 -640 480 -640 480 -640 480 -480 640 -600 450 -640 378 -640 427 -640 480 -640 424 -640 480 -640 425 -427 640 -553 640 -640 428 -640 480 -640 428 -442 640 -500 375 -415 500 -640 640 -640 426 -500 378 -640 427 -640 480 -640 479 -640 427 -380 640 -640 480 -640 480 -500 375 -500 311 -469 640 -640 421 -640 480 -640 480 -640 427 -640 476 -640 480 -640 480 -480 640 -640 480 -640 480 -412 500 -640 426 -640 640 -640 427 -640 425 -640 368 -640 626 -640 484 -612 612 -640 514 -640 640 -640 468 -500 314 -458 640 -480 640 -640 457 -640 480 -640 480 -640 427 -640 480 -479 640 -640 480 -640 512 -334 500 -500 500 -640 426 -375 500 -427 640 -332 500 -640 426 -640 480 -640 480 -426 640 -640 427 -612 612 -640 480 -640 410 -640 480 -640 427 -640 480 -500 375 -640 426 -480 640 -457 640 -640 427 -427 640 -640 480 -640 427 -640 480 -640 426 -640 428 -333 500 -640 478 -640 426 -640 427 -640 480 -640 480 -450 500 -640 427 -640 427 -640 428 -381 640 -500 375 -375 500 -640 426 -640 519 -480 640 -640 588 -375 500 -640 480 -640 480 -500 442 -480 640 -640 480 -500 429 -640 429 -640 427 -640 425 -640 480 -500 375 -640 427 -480 640 -640 480 -480 640 -640 480 -640 437 -640 480 -640 312 -640 427 -500 332 -640 480 -429 640 -640 426 -640 556 -480 640 -640 427 -640 427 -480 640 -640 486 -640 480 -640 480 -640 480 -640 480 -300 403 -493 500 -640 480 -640 414 -640 375 -333 500 -500 333 -630 420 -640 414 -375 500 -640 427 -640 427 -640 457 -640 361 -640 427 -500 333 -640 425 -640 480 -426 640 -640 429 -640 480 -640 426 -640 427 -640 480 -640 426 -640 360 -640 480 -612 612 -640 429 -425 640 -612 612 -480 640 -640 478 -413 640 -640 478 -480 640 -640 427 -640 360 -480 640 -500 332 -640 480 -640 480 -640 471 -640 478 -427 640 -404 640 -640 480 -375 500 -359 640 -640 425 -480 640 -640 458 -640 426 -427 640 -640 427 -500 395 -640 427 -640 425 -640 427 -640 428 -375 500 -375 500 -500 375 -425 640 -640 480 -612 612 -640 489 -640 426 -640 426 -640 479 -640 464 -640 480 -640 532 -640 480 -640 322 -640 427 -500 323 -640 427 -500 375 -427 640 -640 640 -426 640 -612 612 -500 332 -480 640 -423 640 -640 480 -640 384 -640 429 -640 512 -500 375 -480 640 -640 532 -640 425 -640 480 -640 428 -425 640 -427 640 -500 338 -640 420 -640 480 -640 427 -640 427 -640 427 -640 426 -640 480 -640 480 -375 500 -640 426 -424 640 -640 480 -640 428 -640 352 -640 480 -426 640 -500 333 -640 425 -640 480 -640 426 -640 480 -640 513 -640 426 -640 394 -640 480 -640 480 -640 434 -500 341 -418 640 -640 426 -640 480 -640 480 -640 480 -500 375 -426 640 -500 375 -640 446 -640 480 -640 426 -640 427 -640 426 -640 480 -640 463 -640 480 -427 640 -640 426 -640 498 -213 140 -640 427 -375 500 -640 426 -500 375 -332 500 -427 640 -640 427 -640 426 -640 480 -640 480 -426 640 -640 425 -640 480 -480 640 -640 489 -640 480 -640 480 -478 640 -640 426 -640 563 -640 478 -640 480 -640 480 -640 427 -500 334 -640 478 -500 375 -640 443 -427 640 -353 500 -640 511 -640 427 -612 612 -480 640 -600 400 -500 375 -581 575 -640 427 -640 424 -640 359 -640 483 -500 375 -480 640 -640 480 -640 426 -640 427 -500 375 -500 375 -640 456 -640 480 -640 480 -640 428 -640 480 -640 480 -427 640 -640 480 -500 352 -640 427 -445 640 -500 332 -640 494 -640 484 -598 640 -640 480 -640 480 -640 427 -640 427 -500 333 -640 640 -427 640 -480 640 -640 457 -640 427 -480 640 -640 514 -640 471 -640 478 -427 640 -640 422 -640 480 -640 421 -612 612 -640 478 -500 375 -640 522 -640 424 -480 640 -640 480 -640 480 -602 640 -640 428 -640 376 -640 320 -612 612 -640 482 -640 480 -427 640 -640 480 -640 426 -640 480 -640 480 -640 536 -640 426 -640 480 -450 640 -640 427 -324 432 -640 505 -640 480 -500 500 -640 640 -640 425 -480 640 -640 480 -427 640 -640 497 -640 360 -640 480 -640 480 -640 480 -640 427 -500 373 -640 428 -640 426 -500 375 -640 423 -640 616 -640 428 -640 502 -640 488 -414 640 -640 479 -478 640 -620 640 -640 427 -640 360 -640 427 -500 344 -640 480 -640 480 -640 480 -428 640 -444 640 -640 429 -500 375 -422 640 -360 640 -500 332 -640 480 -615 310 -640 427 -640 480 -612 612 -640 425 -427 640 -640 427 -375 500 -426 640 -612 612 -640 640 -500 333 -640 426 -500 375 -640 426 -640 539 -640 480 -640 481 -640 427 -640 603 -640 426 -640 457 -500 375 -640 448 -640 369 -640 480 -500 333 -375 500 -640 480 -427 640 -640 441 -640 301 -332 500 -640 480 -640 426 -640 480 -250 188 -573 640 -500 375 -640 427 -640 327 -640 496 -359 500 -640 427 -640 480 -640 360 -640 530 -640 427 -640 426 -640 498 -480 640 -640 480 -480 640 -500 334 -640 427 -640 406 -480 640 -640 480 -640 469 -640 480 -640 480 -640 433 -640 480 -640 439 -460 345 -640 426 -640 480 -640 360 -640 480 -640 480 -405 640 -640 427 -480 640 -427 640 -640 480 -640 480 -640 425 -480 640 -640 427 -612 612 -640 480 -612 612 -640 429 -640 478 -500 333 -640 480 -640 366 -640 360 -480 640 -480 640 -500 333 -640 480 -640 483 -640 480 -640 480 -640 483 -500 500 -500 375 -640 463 -612 612 -640 480 -500 375 -355 500 -640 472 -640 480 -425 640 -604 640 -640 383 -427 640 -640 427 -640 427 -640 425 -640 410 -640 480 -640 429 -640 480 -640 480 -640 508 -640 426 -640 360 -500 375 -612 612 -370 500 -640 320 -426 640 -640 480 -480 640 -426 640 -480 640 -640 427 -640 426 -612 612 -640 338 -640 425 -640 480 -480 640 -375 500 -640 480 -640 512 -427 640 -500 375 -640 427 -640 428 -640 425 -640 476 -426 640 -480 640 -480 640 -480 640 -494 640 -480 640 -609 640 -640 368 -640 427 -640 433 -640 480 -375 500 -510 510 -640 425 -640 480 -375 500 -640 480 -640 640 -640 424 -640 427 -640 429 -640 480 -480 640 -640 480 -500 375 -640 480 -611 640 -500 332 -640 427 -421 640 -640 480 -640 427 -640 478 -612 612 -612 612 -640 480 -375 500 -640 480 -640 480 -500 270 -640 480 -612 612 -500 250 -500 375 -640 364 -640 480 -640 427 -480 640 -640 427 -640 426 -500 342 -640 427 -500 330 -640 480 -640 426 -640 427 -400 500 -640 479 -296 640 -620 640 -640 480 -480 640 -640 427 -480 640 -640 480 -640 427 -640 480 -640 428 -640 427 -612 612 -640 480 -640 480 -640 480 -400 312 -640 480 -640 427 -426 255 -612 612 -640 428 -640 430 -320 240 -640 425 -640 480 -425 640 -640 428 -640 433 -640 427 -357 500 -640 459 -640 427 -640 480 -640 491 -500 375 -640 427 -510 640 -640 486 -640 480 -640 424 -640 478 -480 640 -428 640 -326 500 -640 480 -500 324 -640 427 -640 640 -640 495 -640 426 -500 375 -426 640 -640 480 -640 514 -640 427 -500 375 -427 640 -640 428 -640 359 -640 480 -640 482 -640 480 -640 387 -424 640 -640 480 -474 640 -612 612 -500 375 -160 120 -640 399 -500 333 -425 640 -640 427 -480 640 -362 500 -640 427 -640 480 -480 640 -480 640 -518 640 -425 640 -500 333 -640 480 -640 480 -427 500 -500 375 -640 435 -500 375 -640 427 -640 512 -640 427 -418 640 -640 434 -500 376 -640 480 -640 426 -500 333 -500 340 -427 640 -640 427 -375 500 -640 427 -640 427 -500 207 -427 640 -640 480 -640 360 -480 640 -640 427 -512 640 -500 333 -480 640 -640 429 -640 532 -640 420 -640 480 -500 437 -383 640 -640 426 -640 480 -480 319 -640 480 -424 640 -427 640 -640 480 -640 480 -426 640 -426 640 -640 447 -640 424 -480 640 -640 427 -640 480 -640 480 -640 426 -640 427 -504 640 -640 480 -640 433 -640 426 -640 427 -500 333 -480 640 -640 478 -640 428 -640 427 -640 427 -500 333 -640 426 -640 432 -500 375 -500 375 -640 480 -344 500 -375 500 -480 640 -500 375 -426 640 -640 167 -500 333 -640 407 -640 424 -640 426 -640 512 -640 427 -640 480 -599 419 -640 427 -640 480 -640 427 -640 480 -640 480 -640 425 -640 480 -640 494 -640 448 -640 480 -426 640 -640 480 -640 480 -454 640 -640 427 -640 480 -640 427 -426 640 -640 427 -640 426 -640 426 -640 426 -640 480 -640 360 -640 427 -640 427 -640 427 -480 640 -640 427 -640 480 -640 366 -500 375 -640 427 -480 640 -640 427 -500 375 -640 427 -640 427 -640 428 -500 375 -640 289 -640 480 -480 640 -427 640 -480 640 -640 480 -640 640 -472 640 -427 640 -612 612 -480 640 -640 427 -640 427 -425 640 -640 426 -640 360 -640 354 -480 640 -640 424 -480 640 -640 392 -640 228 -640 424 -640 480 -640 480 -500 281 -640 480 -640 427 -640 278 -376 500 -375 500 -640 432 -640 357 -425 640 -480 640 -500 337 -500 375 -500 375 -640 480 -640 480 -640 427 -640 427 -333 500 -640 480 -480 640 -640 360 -591 640 -640 360 -640 480 -480 640 -640 480 -640 427 -500 375 -640 480 -427 640 -640 427 -640 640 -500 366 -640 480 -512 640 -359 640 -320 640 -640 360 -480 640 -480 640 -640 619 -640 426 -500 400 -640 427 -640 427 -333 500 -640 424 -480 640 -425 640 -640 361 -452 500 -404 500 -640 640 -425 640 -640 406 -436 291 -640 480 -640 426 -640 427 -425 640 -429 640 -500 375 -640 426 -500 375 -480 640 -640 427 -640 512 -640 426 -640 426 -640 427 -640 480 -324 500 -640 480 -640 428 -640 480 -640 397 -375 500 -640 480 -640 400 -640 360 -640 426 -640 427 -640 427 -640 427 -500 330 -480 640 -640 576 -640 428 -500 331 -640 427 -500 278 -480 640 -640 640 -490 640 -640 383 -612 612 -480 640 -332 500 -640 480 -640 480 -640 427 -478 640 -426 640 -640 507 -480 640 -480 640 -480 640 -640 424 -640 252 -640 411 -640 427 -640 427 -463 640 -640 480 -640 427 -640 429 -331 500 -640 480 -640 427 -500 332 -500 375 -352 288 -500 375 -491 640 -479 640 -612 612 -480 640 -640 427 -403 456 -600 399 -375 500 -640 424 -640 480 -612 612 -640 480 -640 427 -640 482 -462 640 -480 640 -427 640 -640 427 -640 429 -640 425 -640 427 -640 468 -640 427 -640 480 -640 490 -640 480 -640 427 -640 480 -640 640 -640 480 -612 612 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -427 640 -640 427 -538 360 -640 480 -640 426 -500 370 -640 425 -640 480 -640 425 -428 640 -640 480 -640 428 -500 375 -428 640 -640 427 -640 460 -640 480 -512 640 -640 426 -640 427 -640 424 -500 375 -640 516 -640 424 -640 428 -500 332 -640 427 -461 307 -640 426 -640 379 -640 480 -640 420 -640 480 -480 640 -480 640 -640 638 -640 259 -640 480 -426 640 -640 427 -640 480 -640 480 -640 427 -640 426 -375 500 -640 427 -640 421 -426 640 -640 424 -640 426 -640 427 -480 640 -375 500 -640 429 -640 583 -640 480 -500 375 -640 640 -426 640 -640 480 -284 640 -240 166 -640 428 -640 426 -640 480 -640 596 -640 425 -640 640 -640 427 -640 408 -640 360 -500 375 -427 640 -480 640 -640 480 -640 423 -640 428 -640 360 -640 585 -640 426 -640 425 -354 500 -640 480 -640 424 -640 435 -640 480 -500 375 -640 427 -640 480 -427 640 -425 640 -375 500 -640 450 -640 426 -640 640 -480 640 -360 640 -640 426 -640 428 -640 427 -427 640 -640 480 -500 375 -640 426 -600 375 -640 331 -640 434 -640 428 -427 640 -500 335 -640 426 -640 480 -640 392 -640 427 -640 480 -640 640 -612 612 -640 360 -375 500 -612 612 -640 480 -640 480 -640 480 -636 479 -640 433 -640 480 -397 464 -480 640 -640 426 -640 429 -640 480 -427 640 -640 428 -444 640 -640 480 -640 359 -480 640 -640 425 -500 375 -640 378 -640 428 -427 640 -640 334 -640 428 -640 426 -640 480 -640 495 -640 473 -640 384 -427 640 -640 405 -478 640 -640 425 -480 640 -640 426 -500 366 -640 426 -640 427 -480 640 -500 332 -640 480 -640 399 -640 427 -640 424 -640 480 -640 502 -640 502 -640 480 -640 480 -640 451 -640 426 -375 500 -640 427 -640 423 -422 640 -500 335 -640 480 -640 480 -427 640 -640 404 -640 427 -640 427 -640 427 -640 480 -640 480 -480 640 -640 426 -640 393 -457 640 -640 426 -480 640 -500 500 -640 427 -640 480 -500 375 -640 480 -500 375 -640 426 -640 480 -500 375 -351 500 -379 500 -640 428 -640 427 -640 419 -500 454 -363 640 -640 427 -640 427 -420 640 -640 427 -426 640 -500 375 -427 640 -640 427 -640 448 -443 640 -512 640 -640 427 -640 480 -640 515 -640 432 -640 428 -640 480 -375 500 -640 338 -500 500 -515 640 -640 480 -640 449 -640 427 -640 532 -500 640 -640 374 -640 427 -640 614 -640 480 -640 480 -480 640 -640 480 -427 640 -640 451 -640 424 -640 480 -640 426 -640 425 -640 480 -458 640 -480 640 -640 427 -480 640 -288 352 -640 427 -640 463 -640 427 -640 480 -640 425 -393 640 -480 640 -640 427 -425 640 -640 427 -512 640 -640 425 -640 480 -640 256 -640 478 -500 375 -640 559 -612 612 -444 640 -640 427 -480 640 -640 360 -640 488 -640 452 -640 426 -427 640 -487 291 -439 640 -640 515 -640 480 -640 480 -640 480 -612 612 -478 640 -640 480 -480 640 -633 640 -500 333 -640 425 -640 480 -480 640 -640 480 -640 480 -312 640 -640 479 -640 427 -427 640 -640 480 -500 375 -640 480 -640 427 -640 480 -480 640 -640 474 -640 427 -640 426 -386 640 -640 383 -450 640 -500 332 -640 479 -480 640 -640 480 -449 640 -640 480 -640 388 -640 429 -640 480 -375 500 -640 480 -640 480 -640 427 -640 425 -640 480 -640 383 -640 427 -640 425 -612 612 -640 480 -640 616 -500 375 -400 600 -500 454 -640 369 -445 640 -640 426 -486 640 -640 447 -640 480 -480 640 -640 480 -613 640 -640 427 -467 640 -640 480 -640 426 -640 364 -640 424 -399 600 -640 480 -500 333 -640 427 -640 426 -480 640 -480 640 -389 640 -640 480 -640 480 -640 426 -375 500 -640 480 -640 480 -640 480 -640 480 -640 427 -640 426 -640 427 -640 426 -640 427 -640 426 -640 480 -640 429 -640 480 -428 640 -640 443 -640 426 -640 501 -640 339 -640 640 -640 480 -640 429 -519 640 -640 480 -375 500 -640 427 -640 426 -640 480 -640 636 -640 426 -500 375 -500 375 -640 480 -500 375 -640 426 -640 428 -640 436 -612 612 -640 471 -640 423 -640 429 -640 425 -425 640 -640 480 -640 424 -640 504 -640 480 -480 640 -640 480 -640 428 -640 480 -640 639 -640 480 -480 640 -500 375 -640 360 -333 500 -640 411 -640 481 -640 393 -430 640 -640 427 -500 500 -640 427 -640 543 -640 480 -640 427 -640 480 -500 284 -640 480 -640 438 -640 480 -612 612 -612 612 -427 640 -480 640 -640 480 -480 640 -426 640 -500 333 -640 427 -640 480 -500 375 -640 480 -640 482 -640 427 -500 375 -640 427 -640 427 -640 360 -640 478 -640 427 -640 480 -640 480 -500 375 -500 333 -500 375 -461 640 -640 480 -640 427 -640 426 -640 480 -640 480 -640 480 -640 490 -500 308 -640 359 -640 406 -500 334 -480 640 -640 478 -640 428 -500 404 -640 427 -612 612 -480 640 -640 480 -640 480 -640 427 -640 640 -640 427 -640 427 -640 473 -640 480 -640 480 -640 480 -501 640 -640 640 -640 424 -640 521 -480 640 -480 640 -640 428 -480 640 -640 480 -640 428 -640 480 -640 383 -479 640 -640 425 -640 427 -640 480 -640 480 -640 480 -640 505 -640 480 -500 333 -640 480 -640 480 -500 375 -640 480 -640 449 -640 480 -375 500 -640 428 -500 375 -500 333 -640 480 -640 424 -640 428 -640 427 -640 427 -612 612 -640 543 -640 446 -640 505 -500 375 -480 640 -640 400 -640 427 -640 480 -640 426 -479 640 -640 480 -640 320 -428 640 -640 448 -480 640 -612 612 -640 480 -640 424 -640 477 -427 640 -341 500 -480 640 -428 640 -640 427 -427 640 -640 427 -640 480 -640 480 -640 427 -640 428 -480 640 -640 427 -640 480 -640 426 -425 640 -640 480 -640 480 -640 462 -500 375 -594 555 -640 427 -640 480 -640 480 -640 447 -612 612 -640 480 -640 480 -640 427 -640 480 -500 375 -640 454 -427 640 -640 426 -640 480 -640 640 -287 432 -640 427 -640 640 -640 427 -640 426 -500 400 -640 427 -640 480 -640 427 -500 334 -612 612 -640 480 -640 480 -500 375 -640 480 -427 640 -500 333 -612 612 -640 429 -640 480 -480 640 -640 427 -640 480 -640 427 -500 375 -640 480 -375 500 -500 375 -551 640 -640 427 -640 429 -640 428 -640 360 -640 478 -640 480 -308 500 -640 478 -640 388 -640 480 -640 426 -640 423 -500 375 -640 429 -427 640 -640 389 -640 480 -640 427 -640 333 -640 428 -500 346 -640 480 -640 425 -640 438 -640 480 -640 480 -640 428 -640 481 -483 640 -427 640 -640 428 -640 426 -640 480 -480 640 -640 427 -640 480 -320 240 -640 425 -500 333 -640 506 -640 428 -640 425 -480 360 -640 427 -408 640 -612 612 -480 640 -640 359 -491 280 -640 480 -640 637 -480 640 -640 424 -640 480 -640 481 -640 480 -640 480 -640 480 -640 480 -480 640 -439 640 -640 480 -640 428 -517 640 -640 427 -640 457 -500 375 -640 484 -480 640 -640 480 -640 480 -640 418 -640 601 -600 400 -640 427 -640 480 -480 640 -640 480 -500 375 -426 640 -640 480 -639 640 -480 640 -480 640 -640 314 -480 640 -500 361 -640 473 -500 377 -612 612 -640 403 -640 426 -512 640 -640 640 -640 429 -640 480 -640 428 -640 480 -640 480 -640 480 -480 640 -500 500 -500 333 -640 428 -640 452 -480 640 -640 479 -518 640 -500 500 -640 427 -479 640 -640 481 -640 480 -612 612 -484 480 -319 640 -480 640 -480 640 -629 640 -478 640 -381 500 -640 427 -640 480 -640 480 -640 427 -640 463 -428 640 -427 640 -480 640 -640 480 -500 375 -640 427 -640 419 -640 480 -640 313 -480 640 -445 640 -640 480 -640 427 -375 500 -640 480 -640 512 -480 640 -640 427 -640 480 -640 427 -640 427 -640 536 -375 500 -640 428 -640 480 -640 360 -640 425 -640 480 -640 427 -640 427 -640 427 -350 500 -480 640 -500 374 -640 478 -640 480 -640 429 -640 478 -640 467 -500 332 -480 640 -500 375 -640 478 -427 640 -640 427 -427 640 -375 500 -640 424 -640 480 -428 640 -640 480 -640 613 -480 640 -640 444 -640 383 -640 480 -640 427 -640 480 -640 495 -640 426 -640 415 -640 480 -640 427 -480 640 -640 449 -640 426 -640 264 -640 427 -640 427 -509 640 -640 427 -640 480 -494 640 -480 640 -634 640 -640 427 -640 480 -640 516 -640 480 -640 428 -640 486 -640 428 -640 480 -640 401 -500 375 -640 480 -640 426 -500 334 -640 480 -620 640 -640 480 -314 500 -360 640 -640 427 -500 376 -500 333 -640 480 -640 480 -426 640 -640 414 -640 427 -480 640 -640 480 -640 480 -640 480 -500 375 -640 427 -640 480 -612 612 -640 480 -427 640 -640 425 -640 427 -640 464 -640 480 -640 427 -640 427 -612 612 -640 481 -640 480 -640 479 -640 425 -640 427 -640 266 -427 640 -640 305 -480 640 -640 427 -427 640 -455 640 -640 425 -480 640 -640 480 -375 500 -428 640 -480 640 -640 355 -375 500 -640 427 -640 204 -640 640 -640 480 -640 427 -640 457 -427 640 -640 425 -500 375 -640 426 -640 427 -640 480 -571 640 -640 480 -640 628 -480 640 -427 640 -640 425 -427 640 -500 375 -426 640 -500 332 -640 480 -640 427 -640 427 -640 427 -332 500 -457 640 -640 429 -640 427 -427 640 -496 500 -640 383 -640 422 -640 480 -640 427 -640 347 -393 500 -480 640 -640 637 -640 424 -500 375 -640 480 -640 480 -640 427 -640 425 -640 480 -640 427 -640 480 -640 427 -640 432 -640 480 -640 428 -427 640 -500 375 -640 480 -640 425 -640 465 -640 480 -640 324 -640 480 -640 427 -640 462 -640 426 -640 360 -640 427 -640 426 -424 640 -640 428 -500 334 -640 425 -640 213 -640 480 -333 500 -640 359 -640 480 -640 427 -612 612 -480 640 -480 640 -640 480 -640 427 -500 381 -500 342 -640 449 -640 480 -640 430 -640 480 -640 427 -640 480 -427 640 -427 640 -640 427 -640 480 -640 399 -640 457 -640 480 -640 480 -640 427 -640 337 -640 427 -426 640 -640 428 -640 363 -640 480 -640 430 -640 481 -640 429 -640 480 -640 433 -640 428 -478 640 -640 427 -480 640 -612 612 -480 360 -640 480 -375 500 -640 427 -640 426 -640 266 -640 426 -498 640 -640 480 -480 640 -640 427 -640 427 -640 480 -480 640 -612 612 -640 624 -640 427 -640 398 -640 426 -640 480 -360 640 -640 478 -640 427 -640 427 -500 375 -640 526 -640 362 -640 480 -640 424 -640 480 -426 640 -480 640 -640 426 -640 426 -640 461 -640 480 -375 500 -640 426 -640 426 -640 425 -480 640 -640 427 -640 430 -640 478 -640 480 -350 500 -375 500 -640 427 -457 640 -640 480 -375 500 -640 640 -640 584 -640 480 -640 480 -500 349 -612 612 -500 375 -640 428 -640 480 -500 333 -500 400 -640 513 -640 427 -640 427 -480 640 -640 478 -457 640 -640 427 -500 281 -640 368 -640 480 -640 427 -640 427 -500 406 -500 375 -360 270 -640 422 -480 640 -640 427 -640 561 -640 478 -640 427 -640 480 -500 333 -640 427 -640 427 -640 480 -640 427 -640 485 -400 640 -427 640 -640 480 -428 640 -640 273 -600 402 -480 640 -640 518 -640 427 -640 480 -640 427 -640 427 -640 427 -640 480 -640 640 -640 426 -354 500 -640 480 -640 415 -480 640 -640 480 -640 418 -640 428 -640 480 -640 425 -335 500 -640 480 -640 636 -640 429 -427 640 -640 480 -427 640 -640 427 -612 612 -640 480 -640 480 -500 392 -640 430 -256 448 -640 327 -640 512 -480 640 -640 446 -640 480 -427 640 -500 457 -640 427 -640 427 -500 375 -640 426 -480 640 -640 640 -640 457 -640 482 -375 500 -480 640 -640 476 -640 480 -640 360 -480 640 -427 640 -640 480 -640 427 -640 427 -640 480 -375 500 -500 375 -426 640 -480 640 -640 321 -640 489 -425 640 -182 273 -640 427 -640 427 -640 436 -640 457 -640 426 -561 640 -425 640 -640 427 -640 427 -640 427 -640 451 -427 640 -640 480 -640 480 -612 612 -640 427 -425 640 -640 427 -640 480 -426 640 -375 500 -500 375 -640 426 -640 379 -427 640 -480 640 -640 425 -640 426 -500 493 -640 341 -640 428 -425 640 -640 480 -640 574 -640 480 -480 640 -640 427 -640 480 -640 478 -640 421 -400 640 -640 425 -424 640 -480 640 -640 426 -640 541 -424 640 -640 480 -640 478 -640 427 -426 640 -640 480 -427 640 -500 375 -500 375 -500 326 -468 640 -430 640 -640 480 -640 640 -640 480 -640 361 -428 640 -500 333 -480 640 -640 480 -640 429 -506 640 -640 391 -328 500 -612 612 -426 640 -640 565 -640 480 -640 455 -640 371 -640 426 -640 427 -454 640 -421 640 -640 427 -457 640 -640 321 -640 442 -640 424 -427 640 -640 427 -494 640 -400 239 -640 426 -640 480 -640 480 -480 640 -640 480 -480 640 -471 640 -480 640 -640 497 -640 480 -640 480 -424 640 -640 426 -640 425 -612 612 -500 250 -640 416 -640 480 -640 427 -427 640 -427 640 -640 298 -640 426 -480 640 -640 361 -640 480 -640 360 -640 427 -612 612 -640 426 -480 640 -640 424 -640 411 -640 480 -640 480 -640 426 -640 533 -640 480 -480 640 -640 427 -426 640 -319 235 -640 424 -480 640 -640 353 -500 348 -640 427 -426 640 -375 500 -640 480 -640 426 -640 466 -640 480 -480 640 -640 480 -640 427 -640 480 -480 640 -485 404 -524 640 -500 375 -640 480 -480 640 -640 480 -640 429 -480 640 -640 426 -640 480 -640 359 -640 444 -640 278 -640 469 -640 480 -640 425 -423 640 -612 612 -425 640 -426 640 -640 423 -640 480 -480 640 -640 427 -640 426 -600 450 -640 480 -640 427 -640 427 -640 480 -640 427 -640 427 -640 480 -640 428 -640 480 -640 480 -500 308 -640 478 -640 480 -640 427 -640 427 -640 427 -480 640 -480 640 -640 513 -500 336 -417 640 -375 500 -640 426 -640 454 -375 500 -640 427 -640 318 -640 427 -640 427 -375 500 -640 480 -640 358 -640 427 -640 426 -469 640 -640 427 -480 640 -480 640 -640 480 -640 426 -500 375 -640 427 -480 640 -640 427 -640 360 -500 375 -640 427 -640 480 -640 426 -500 333 -500 375 -480 640 -640 480 -640 480 -473 640 -640 566 -640 476 -427 640 -640 425 -640 490 -480 640 -359 640 -640 480 -500 375 -640 425 -640 427 -444 640 -640 427 -640 480 -640 480 -640 480 -332 500 -640 408 -480 640 -640 480 -640 640 -480 640 -640 480 -640 640 -500 372 -640 428 -607 640 -640 426 -480 640 -640 427 -640 458 -640 426 -500 375 -640 424 -612 612 -640 425 -640 480 -500 370 -640 480 -640 423 -640 427 -640 425 -640 428 -640 428 -640 427 -640 626 -500 267 -640 480 -640 480 -640 478 -332 500 -612 612 -640 428 -640 480 -640 453 -640 480 -640 223 -640 478 -640 427 -640 427 -640 480 -640 422 -640 361 -640 480 -427 640 -486 640 -427 640 -640 427 -612 612 -426 640 -640 427 -411 640 -500 375 -640 427 -640 360 -640 428 -640 428 -640 425 -471 640 -462 640 -640 480 -640 451 -640 427 -640 427 -320 240 -640 512 -427 640 -533 640 -640 427 -480 640 -640 426 -640 425 -427 640 -500 375 -640 425 -640 480 -640 438 -640 425 -498 438 -640 427 -640 423 -640 360 -640 480 -640 480 -500 375 -640 426 -480 640 -640 426 -500 400 -500 479 -612 612 -640 570 -480 640 -640 480 -640 427 -423 640 -640 480 -427 640 -640 480 -640 424 -640 426 -427 640 -640 480 -480 640 -640 480 -640 640 -480 640 -427 640 -640 427 -312 500 -640 480 -640 428 -640 427 -500 375 -638 640 -428 640 -375 500 -640 480 -640 425 -640 420 -505 640 -375 500 -500 296 -480 640 -640 480 -480 640 -612 612 -640 428 -640 471 -640 480 -640 463 -640 427 -640 425 -640 360 -640 360 -427 640 -640 640 -478 640 -640 426 -480 640 -500 375 -480 640 -425 640 -640 640 -640 564 -640 428 -500 375 -640 428 -640 427 -640 480 -640 512 -640 425 -640 452 -640 427 -640 491 -640 483 -480 640 -640 480 -427 640 -640 480 -640 425 -640 480 -427 640 -640 640 -640 428 -425 640 -640 480 -427 640 -429 640 -532 640 -480 640 -640 501 -640 480 -361 640 -450 372 -640 427 -640 480 -640 480 -640 480 -640 441 -480 640 -500 381 -428 640 -640 443 -640 482 -640 427 -640 512 -500 332 -640 480 -403 640 -640 426 -640 453 -480 640 -640 424 -410 500 -640 477 -480 640 -640 426 -500 372 -500 375 -640 360 -485 640 -640 480 -500 375 -640 608 -640 133 -640 428 -640 480 -520 373 -640 427 -480 640 -332 640 -640 427 -612 612 -640 480 -500 429 -640 480 -640 428 -500 375 -640 539 -640 469 -427 640 -640 427 -640 428 -427 640 -480 640 -640 427 -640 480 -640 426 -480 640 -640 480 -640 427 -640 427 -640 480 -640 428 -640 457 -640 480 -640 427 -534 640 -427 640 -640 446 -480 640 -640 425 -427 640 -480 640 -640 361 -500 375 -640 480 -640 480 -480 640 -640 431 -640 480 -426 640 -640 428 -480 640 -640 424 -500 375 -640 427 -640 480 -640 480 -500 375 -640 427 -640 470 -366 500 -333 500 -640 427 -500 375 -320 640 -640 426 -640 509 -612 612 -640 478 -640 426 -640 640 -640 480 -640 320 -448 600 -500 338 -427 640 -640 480 -426 640 -640 481 -640 480 -427 640 -612 612 -480 640 -480 640 -480 640 -425 640 -640 480 -640 480 -640 427 -640 427 -640 427 -640 480 -640 480 -640 480 -640 557 -480 640 -640 425 -640 427 -482 640 -500 375 -568 640 -640 424 -480 319 -640 480 -640 480 -640 480 -640 427 -640 415 -500 375 -500 328 -640 425 -640 431 -319 500 -612 612 -640 640 -640 640 -375 500 -480 640 -640 442 -333 500 -640 429 -640 428 -640 427 -330 500 -500 375 -640 480 -640 512 -612 612 -500 375 -640 427 -640 515 -441 640 -640 480 -493 600 -640 478 -331 500 -500 361 -640 428 -500 375 -640 428 -640 429 -640 427 -640 425 -480 640 -480 640 -480 640 -480 640 -640 426 -640 480 -478 640 -427 640 -375 500 -640 427 -640 475 -500 375 -640 419 -513 640 -480 640 -640 480 -640 428 -348 500 -640 480 -640 480 -640 480 -640 427 -420 500 -640 427 -238 640 -480 640 -640 480 -480 640 -483 640 -640 480 -640 480 -330 640 -485 640 -640 480 -640 429 -640 426 -640 480 -612 612 -640 394 -427 640 -640 457 -333 500 -428 640 -640 426 -640 480 -375 500 -640 446 -640 512 -427 640 -640 428 -640 328 -640 480 -612 612 -640 427 -471 450 -640 480 -480 640 -640 480 -640 480 -640 427 -640 448 -500 409 -640 432 -640 400 -640 427 -640 426 -640 480 -640 480 -640 480 -640 480 -480 640 -640 480 -500 333 -500 375 -427 640 -640 360 -427 640 -500 375 -640 427 -640 460 -640 360 -640 480 -640 480 -640 591 -427 640 -640 480 -640 424 -612 612 -640 431 -640 478 -427 640 -640 427 -640 480 -640 480 -638 640 -479 640 -640 480 -640 480 -640 456 -640 480 -427 640 -640 426 -500 335 -480 640 -640 396 -512 512 -640 427 -480 640 -640 424 -500 375 -500 333 -424 640 -480 640 -640 473 -640 482 -281 486 -480 640 -424 640 -426 640 -640 427 -640 436 -640 480 -500 375 -640 447 -640 427 -640 448 -640 427 -640 427 -640 480 -600 359 -640 148 -640 434 -640 480 -612 612 -500 500 -500 333 -640 426 -426 640 -640 480 -640 428 -640 494 -640 426 -425 640 -640 480 -640 456 -500 375 -427 640 -640 427 -640 480 -640 363 -542 640 -457 640 -640 360 -480 640 -640 478 -500 375 -640 424 -640 488 -480 640 -640 427 -500 375 -640 243 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -532 640 -640 318 -640 480 -640 427 -640 426 -300 225 -480 640 -640 480 -640 429 -640 379 -424 640 -359 640 -640 478 -427 640 -480 640 -640 425 -640 424 -640 480 -332 500 -640 480 -480 640 -640 480 -480 640 -640 427 -426 640 -640 425 -640 479 -640 480 -640 480 -640 428 -640 428 -380 500 -640 480 -640 383 -640 480 -640 427 -500 375 -480 640 -640 427 -500 400 -640 480 -640 427 -640 467 -640 480 -500 375 -480 640 -640 429 -500 375 -640 390 -480 640 -640 480 -600 450 -612 612 -480 640 -468 640 -640 427 -640 480 -640 427 -500 375 -640 480 -640 480 -640 426 -640 480 -640 427 -640 427 -640 480 -500 333 -640 427 -427 640 -640 480 -640 480 -604 640 -478 640 -500 376 -640 441 -640 403 -640 480 -640 404 -427 640 -640 394 -640 427 -640 480 -640 640 -640 480 -611 640 -612 612 -478 640 -640 480 -480 640 -612 612 -640 351 -640 513 -640 521 -640 360 -427 640 -500 375 -640 540 -480 640 -500 375 -423 640 -640 448 -500 375 -640 640 -500 303 -640 426 -640 384 -640 480 -640 429 -640 480 -424 640 -640 480 -640 480 -640 431 -640 480 -640 480 -640 426 -640 427 -640 480 -640 427 -640 440 -480 640 -500 352 -640 428 -640 481 -500 500 -640 480 -640 480 -511 640 -640 480 -640 425 -640 353 -640 424 -640 427 -588 640 -640 426 -640 392 -334 500 -496 500 -640 480 -480 640 -640 480 -443 640 -640 439 -640 640 -480 640 -305 500 -640 428 -640 480 -640 426 -640 480 -427 640 -640 427 -426 640 -640 426 -612 612 -480 640 -640 426 -640 457 -640 480 -640 580 -640 360 -640 428 -640 427 -640 480 -500 479 -434 640 -640 425 -531 640 -640 480 -640 426 -640 480 -640 391 -640 426 -640 480 -640 472 -640 376 -640 427 -640 480 -512 640 -500 389 -640 427 -640 427 -500 375 -500 375 -640 425 -640 480 -640 458 -640 478 -640 427 -480 640 -640 480 -640 427 -427 640 -640 425 -510 640 -487 640 -480 640 -640 480 -332 500 -427 640 -480 640 -640 451 -480 640 -375 500 -424 640 -640 480 -640 427 -474 334 -640 480 -480 640 -640 336 -640 480 -640 428 -426 640 -640 480 -640 428 -475 640 -640 480 -640 480 -640 426 -426 640 -640 427 -640 427 -640 387 -428 640 -500 407 -640 427 -363 249 -640 509 -428 640 -640 427 -500 375 -640 468 -640 427 -426 640 -640 480 -500 339 -500 375 -427 640 -500 333 -469 640 -640 393 -640 334 -640 491 -640 468 -500 332 -500 325 -640 480 -640 423 -640 480 -500 333 -640 425 -511 640 -640 425 -640 440 -428 640 -640 480 -640 428 -640 480 -640 426 -640 480 -640 480 -640 427 -289 640 -640 427 -640 480 -555 640 -640 480 -640 460 -640 401 -426 640 -640 480 -640 426 -428 640 -640 361 -612 612 -640 467 -640 427 -640 480 -640 480 -640 373 -640 428 -640 427 -640 425 -428 640 -640 427 -333 500 -640 427 -640 426 -514 640 -640 427 -640 428 -640 428 -640 426 -640 426 -335 500 -640 480 -500 375 -480 640 -640 427 -640 480 -640 480 -640 480 -640 480 -640 426 -640 480 -640 480 -583 640 -480 640 -640 426 -640 359 -640 480 -426 640 -480 640 -500 375 -640 486 -640 427 -375 500 -640 426 -640 480 -640 480 -640 486 -640 467 -640 459 -640 428 -427 640 -500 333 -640 427 -640 480 -640 484 -500 375 -640 454 -640 480 -640 480 -513 640 -640 427 -640 480 -375 500 -500 375 -500 333 -500 281 -640 427 -640 480 -480 640 -640 640 -640 426 -480 640 -640 480 -640 427 -480 640 -640 480 -640 427 -640 426 -640 470 -640 427 -500 335 -500 333 -640 427 -433 640 -640 428 -360 288 -640 427 -640 424 -480 640 -640 426 -640 426 -500 375 -640 426 -640 428 -640 436 -640 426 -480 640 -373 500 -612 612 -500 313 -640 480 -640 426 -640 426 -640 486 -640 480 -640 480 -640 426 -500 375 -640 427 -480 640 -640 427 -480 640 -640 478 -640 428 -640 427 -640 425 -500 375 -640 480 -500 375 -640 426 -385 640 -500 385 -495 640 -640 426 -640 480 -640 480 -640 457 -640 480 -640 480 -640 480 -640 426 -375 500 -269 448 -359 500 -500 375 -640 640 -640 426 -640 360 -500 333 -500 375 -640 535 -375 500 -640 429 -640 427 -640 480 -428 640 -640 480 -640 424 -424 640 -640 400 -417 640 -640 428 -409 640 -378 640 -480 640 -612 612 -640 541 -407 640 -640 480 -640 480 -640 640 -480 640 -640 447 -640 424 -640 480 -640 480 -500 331 -640 478 -427 640 -333 500 -640 427 -500 335 -640 480 -640 480 -427 640 -640 427 -536 640 -500 375 -640 430 -500 375 -640 438 -640 480 -512 640 -382 471 -640 430 -640 478 -640 508 -500 375 -640 424 -640 480 -640 480 -428 640 -640 480 -640 427 -640 480 -335 500 -640 364 -612 612 -640 427 -375 500 -640 480 -640 360 -640 480 -640 360 -500 334 -429 640 -640 480 -600 600 -640 479 -640 513 -480 640 -640 428 -640 460 -640 480 -640 480 -640 456 -640 480 -640 467 -640 427 -640 427 -640 480 -640 480 -480 640 -640 512 -640 480 -640 426 -546 640 -640 425 -640 360 -333 500 -640 480 -481 640 -640 427 -640 427 -640 480 -640 480 -640 336 -445 640 -640 427 -640 426 -640 198 -640 449 -640 425 -640 480 -640 480 -480 640 -640 427 -427 640 -599 391 -640 425 -640 480 -640 283 -500 375 -480 640 -640 406 -424 640 -640 421 -640 480 -640 426 -640 480 -640 480 -640 427 -640 480 -640 480 -425 640 -640 427 -640 480 -635 640 -500 335 -427 640 -640 480 -342 500 -480 640 -640 480 -333 500 -640 480 -640 480 -640 480 -480 640 -500 367 -427 640 -640 425 -480 640 -640 406 -640 519 -640 480 -640 425 -500 375 -640 318 -640 360 -638 640 -640 452 -640 480 -500 375 -500 333 -333 500 -640 427 -640 427 -640 427 -640 426 -640 481 -640 480 -536 640 -640 482 -640 426 -640 427 -427 640 -640 486 -640 480 -640 427 -640 427 -640 480 -480 640 -640 360 -480 640 -640 392 -640 427 -423 640 -640 427 -640 457 -640 360 -500 357 -640 480 -640 480 -640 480 -640 452 -480 640 -640 426 -640 427 -640 480 -640 425 -487 640 -640 428 -640 427 -640 426 -640 515 -500 375 -480 640 -640 640 -640 480 -480 640 -640 403 -640 243 -383 640 -480 640 -640 561 -500 410 -640 640 -640 480 -640 480 -612 612 -640 427 -640 480 -640 480 -537 640 -640 480 -500 333 -583 437 -500 319 -366 640 -640 480 -640 424 -640 426 -640 424 -500 321 -640 432 -640 480 -640 480 -640 427 -383 640 -427 640 -640 427 -516 640 -640 487 -640 398 -500 375 -640 478 -640 360 -612 612 -426 640 -640 480 -640 480 -640 427 -640 427 -427 640 -640 425 -500 333 -640 427 -640 640 -640 495 -640 480 -478 640 -640 480 -640 480 -500 375 -640 480 -640 424 -640 424 -500 408 -640 556 -480 640 -640 429 -480 640 -640 480 -640 478 -640 594 -640 427 -640 531 -640 429 -640 413 -640 478 -480 640 -480 640 -640 425 -640 485 -478 640 -478 640 -640 480 -640 453 -640 426 -426 640 -640 480 -640 425 -640 474 -640 480 -640 480 -640 480 -600 401 -640 440 -640 480 -640 480 -426 640 -480 640 -480 640 -640 427 -479 640 -427 640 -640 480 -640 480 -313 500 -500 375 -500 375 -640 425 -480 640 -640 480 -333 500 -640 433 -480 640 -500 371 -640 428 -640 480 -640 480 -640 480 -640 401 -640 480 -640 480 -640 640 -640 480 -640 429 -612 612 -640 427 -640 480 -640 427 -492 500 -640 480 -320 240 -470 350 -640 428 -640 512 -640 427 -640 403 -640 480 -640 480 -640 425 -640 427 -500 325 -640 480 -640 427 -640 425 -500 375 -500 332 -640 427 -500 375 -640 521 -429 640 -550 640 -640 426 -640 480 -640 476 -427 640 -640 480 -521 640 -480 640 -640 359 -640 427 -500 500 -640 427 -427 640 -640 425 -500 375 -500 334 -640 478 -500 281 -640 428 -640 426 -640 440 -640 480 -640 480 -640 426 -640 427 -640 480 -640 427 -640 480 -640 427 -375 500 -500 375 -640 427 -457 640 -640 480 -640 480 -640 480 -500 375 -640 480 -640 480 -383 500 -427 640 -640 427 -640 424 -427 640 -425 500 -427 640 -478 640 -640 427 -640 480 -612 612 -640 480 -640 427 -640 480 -640 420 -500 375 -640 214 -612 612 -375 500 -640 482 -640 427 -640 427 -640 466 -480 640 -640 480 -425 640 -480 640 -375 500 -640 480 -500 333 -640 480 -640 480 -640 438 -640 427 -640 394 -480 360 -640 431 -640 480 -456 640 -500 375 -640 480 -427 640 -559 640 -500 375 -640 478 -640 427 -640 480 -640 359 -640 480 -640 429 -480 640 -333 500 -640 428 -640 424 -640 428 -640 480 -640 512 -640 426 -640 425 -500 375 -640 480 -640 427 -463 640 -640 524 -640 427 -640 427 -640 426 -640 480 -612 612 -640 425 -480 640 -640 480 -640 480 -640 480 -640 430 -640 480 -640 480 -500 357 -640 480 -640 366 -375 500 -500 333 -480 640 -480 640 -640 424 -640 426 -640 210 -500 375 -640 427 -640 480 -640 480 -426 640 -427 640 -640 480 -480 640 -640 480 -640 427 -480 640 -640 480 -375 500 -425 640 -480 640 -640 427 -427 640 -640 480 -480 640 -640 480 -480 640 -480 640 -334 500 -640 506 -428 640 -640 426 -569 640 -640 431 -612 612 -640 480 -427 640 -375 500 -480 640 -640 640 -500 375 -640 427 -640 527 -640 426 -640 480 -640 480 -640 619 -640 427 -335 500 -640 427 -640 427 -640 500 -640 427 -640 478 -500 333 -640 427 -428 640 -640 480 -640 478 -500 500 -424 640 -640 444 -428 640 -640 480 -431 640 -640 369 -612 612 -427 640 -640 480 -640 428 -422 640 -640 424 -480 640 -640 427 -427 640 -425 640 -480 640 -640 480 -640 427 -640 453 -427 640 -640 480 -640 424 -640 480 -640 427 -640 427 -375 500 -640 428 -640 480 -640 480 -640 427 -640 426 -640 480 -640 480 -640 427 -640 428 -640 480 -500 375 -480 640 -640 480 -480 640 -500 324 -480 640 -640 426 -640 480 -640 425 -500 334 -328 500 -640 480 -640 478 -364 640 -640 427 -640 480 -640 426 -640 427 -640 640 -640 480 -457 640 -640 480 -640 425 -500 480 -640 427 -640 480 -640 360 -640 480 -480 640 -375 500 -640 424 -640 471 -640 480 -640 480 -480 640 -500 375 -640 480 -640 480 -640 427 -426 640 -428 640 -640 640 -640 421 -640 427 -640 429 -640 480 -640 480 -427 640 -640 428 -640 427 -640 480 -640 360 -640 480 -500 333 -640 428 -640 566 -480 640 -640 427 -468 640 -612 612 -500 333 -500 375 -640 480 -640 455 -640 483 -640 427 -640 480 -640 424 -640 383 -640 480 -640 427 -640 480 -480 640 -640 480 -500 237 -640 480 -640 491 -427 640 -326 500 -640 361 -640 512 -612 612 -500 333 -640 480 -427 640 -426 640 -640 485 -640 427 -640 480 -640 480 -640 480 -640 511 -640 480 -480 640 -640 523 -640 454 -640 360 -500 375 -500 375 -500 414 -500 375 -613 640 -640 420 -480 640 -640 480 -640 427 -640 442 -512 640 -640 426 -640 360 -500 375 -500 375 -640 427 -640 424 -640 428 -640 425 -640 427 -640 480 -640 360 -640 428 -640 426 -640 426 -427 640 -640 478 -640 640 -640 480 -640 426 -640 428 -500 322 -640 480 -640 428 -333 500 -425 640 -640 480 -640 513 -500 376 -480 640 -480 640 -500 333 -545 640 -425 640 -640 427 -479 640 -455 640 -405 640 -640 565 -640 480 -640 427 -640 480 -640 480 -640 454 -640 293 -640 476 -640 480 -640 480 -399 600 -640 425 -640 427 -640 427 -427 640 -500 333 -640 480 -640 427 -612 612 -640 422 -500 333 -640 463 -500 357 -640 480 -640 427 -640 427 -612 612 -428 640 -640 480 -640 426 -640 480 -640 480 -426 640 -640 480 -640 480 -480 640 -424 640 -480 640 -480 640 -640 426 -640 480 -640 480 -640 427 -640 480 -640 480 -480 640 -640 480 -424 640 -640 427 -640 427 -612 612 -640 480 -480 640 -640 480 -640 424 -640 514 -640 379 -640 428 -500 375 -640 427 -640 427 -500 375 -500 333 -640 480 -299 640 -640 425 -640 480 -640 510 -500 375 -426 640 -640 480 -640 480 -522 640 -640 480 -480 640 -640 427 -640 427 -500 344 -640 428 -640 480 -500 375 -352 288 -640 424 -427 640 -640 480 -479 640 -640 428 -640 427 -640 478 -612 612 -480 300 -640 427 -480 640 -640 237 -640 427 -640 461 -640 622 -480 640 -500 375 -640 502 -640 378 -640 480 -500 409 -640 224 -640 478 -640 394 -424 640 -640 480 -333 500 -640 395 -640 416 -479 640 -500 375 -640 640 -640 480 -640 403 -640 416 -480 640 -386 640 -332 500 -457 640 -640 480 -640 426 -640 427 -640 451 -640 480 -640 427 -640 480 -640 427 -478 640 -480 640 -640 427 -640 428 -640 480 -640 425 -640 480 -425 640 -640 427 -640 424 -640 426 -640 424 -640 284 -427 640 -640 427 -500 375 -427 640 -480 640 -640 427 -640 463 -640 446 -480 640 -640 317 -425 640 -594 640 -427 640 -480 640 -480 640 -640 427 -427 640 -640 640 -640 432 -640 480 -640 426 -640 427 -640 480 -640 480 -640 427 -640 430 -640 480 -561 640 -640 427 -640 478 -424 640 -426 640 -640 418 -640 427 -457 640 -640 480 -480 640 -500 375 -480 640 -640 478 -425 640 -640 533 -640 424 -640 427 -640 427 -640 359 -640 480 -612 612 -500 376 -640 480 -640 426 -335 500 -640 480 -640 426 -640 480 -640 640 -640 480 -640 427 -640 480 -640 480 -640 480 -427 640 -640 359 -467 640 -640 428 -640 480 -640 418 -640 480 -640 480 -640 480 -640 425 -640 427 -640 478 -640 480 -640 427 -640 427 -640 480 -640 414 -640 360 -427 640 -500 330 -640 480 -500 335 -640 480 -427 640 -640 439 -640 480 -640 478 -640 427 -500 375 -640 426 -640 427 -375 500 -640 427 -640 480 -640 480 -640 596 -640 400 -640 425 -480 640 -640 448 -640 429 -640 426 -500 304 -640 507 -640 427 -500 332 -640 426 -640 480 -427 640 -500 378 -640 426 -375 500 -480 640 -500 417 -640 480 -640 427 -640 481 -640 426 -640 426 -500 387 -286 417 -640 480 -640 424 -500 403 -640 480 -640 411 -500 332 -500 334 -640 427 -612 612 -640 395 -640 480 -500 335 -640 480 -640 480 -640 433 -640 427 -428 640 -640 640 -640 428 -500 375 -640 417 -427 640 -480 640 -640 360 -640 480 -640 427 -407 640 -640 480 -640 425 -640 480 -640 418 -640 428 -500 371 -640 426 -500 480 -498 500 -640 424 -640 426 -640 426 -640 427 -480 640 -640 480 -500 333 -640 480 -640 457 -426 640 -408 640 -640 428 -640 480 -426 640 -552 640 -640 425 -640 480 -500 375 -640 477 -640 488 -504 640 -312 480 -457 640 -640 480 -640 480 -640 425 -640 474 -640 480 -640 428 -456 640 -500 400 -612 612 -640 480 -640 439 -640 480 -640 427 -640 480 -640 477 -640 480 -640 425 -640 360 -480 640 -640 480 -640 480 -640 425 -640 480 -640 480 -431 640 -480 640 -640 426 -480 640 -428 640 -426 640 -461 640 -640 480 -337 500 -360 640 -640 480 -500 332 -480 640 -500 333 -464 640 -640 480 -640 480 -640 480 -640 428 -640 427 -640 360 -640 425 -480 640 -500 375 -500 414 -612 612 -640 480 -427 640 -640 366 -640 427 -427 640 -640 427 -640 480 -640 480 -640 427 -640 426 -640 480 -500 375 -549 640 -640 480 -429 640 -500 640 -640 480 -640 480 -500 375 -500 334 -640 480 -640 480 -640 444 -640 324 -640 480 -480 640 -640 427 -480 640 -640 426 -640 361 -338 500 -640 427 -640 480 -640 480 -480 640 -427 640 -530 640 -441 640 -500 375 -640 428 -640 512 -500 375 -640 480 -480 640 -428 640 -332 500 -640 427 -640 480 -640 425 -640 429 -640 431 -640 480 -640 427 -640 396 -425 640 -640 480 -640 427 -500 376 -375 500 -500 333 -640 480 -640 360 -500 375 -500 389 -640 480 -640 344 -480 640 -428 640 -640 480 -640 427 -480 640 -640 427 -640 547 -375 500 -612 612 -481 640 -640 480 -612 612 -640 480 -640 427 -426 640 -400 500 -640 427 -640 480 -640 419 -640 513 -640 480 -427 640 -640 426 -640 427 -500 333 -427 640 -640 424 -640 399 -640 480 -640 425 -640 364 -640 640 -640 427 -640 457 -640 629 -640 426 -427 640 -640 426 -500 375 -640 424 -427 640 -640 427 -640 428 -640 480 -640 480 -640 324 -500 375 -640 480 -640 427 -500 281 -640 427 -640 441 -640 427 -640 480 -500 300 -480 640 -350 500 -424 640 -534 640 -640 427 -640 427 -640 428 -640 426 -640 480 -480 640 -500 317 -640 427 -500 375 -640 480 -640 427 -640 480 -640 480 -640 480 -640 427 -480 640 -640 501 -640 478 -640 480 -640 424 -640 459 -500 375 -640 427 -480 640 -640 426 -640 481 -500 476 -333 500 -640 480 -640 490 -640 428 -640 568 -640 480 -640 512 -640 453 -640 480 -428 640 -640 480 -640 480 -640 480 -480 640 -640 624 -640 427 -640 438 -640 480 -640 400 -500 333 -640 480 -427 640 -640 426 -428 640 -640 480 -640 480 -640 480 -640 427 -640 480 -500 375 -612 612 -640 427 -640 480 -640 426 -640 449 -427 640 -640 427 -333 500 -640 427 -480 640 -500 375 -434 640 -640 463 -640 426 -480 640 -640 288 -640 425 -640 426 -640 480 -640 427 -640 425 -640 469 -359 640 -480 640 -640 480 -362 500 -427 640 -640 480 -640 426 -427 640 -640 425 -427 640 -640 480 -375 500 -640 468 -640 480 -500 375 -640 427 -500 410 -640 427 -500 374 -640 426 -640 480 -612 612 -480 360 -500 414 -640 480 -500 333 -640 426 -640 427 -640 425 -640 480 -640 480 -640 427 -640 425 -500 375 -640 473 -427 640 -640 426 -640 427 -640 396 -640 427 -640 488 -500 341 -612 612 -640 360 -640 425 -640 480 -426 640 -640 403 -640 427 -640 427 -640 428 -640 427 -332 500 -500 375 -480 640 -640 480 -480 640 -640 426 -640 427 -640 360 -427 640 -612 612 -640 480 -640 424 -640 416 -640 480 -640 480 -640 480 -500 375 -500 333 -640 427 -640 427 -427 640 -500 375 -640 480 -480 640 -508 640 -612 612 -500 375 -640 419 -429 640 -640 427 -500 375 -640 480 -500 332 -640 480 -640 426 -469 640 -427 640 -427 640 -640 480 -408 640 -480 640 -500 500 -425 640 -512 640 -640 455 -640 425 -640 480 -640 425 -640 364 -640 480 -427 640 -640 416 -640 480 -640 296 -640 427 -640 426 -640 480 -640 480 -640 480 -640 427 -640 480 -500 309 -640 465 -640 513 -640 426 -640 480 -640 556 -640 480 -426 640 -427 640 -640 640 -640 427 -640 427 -480 640 -480 640 -640 427 -425 640 -640 640 -427 640 -640 426 -640 429 -640 480 -640 481 -510 640 -640 480 -640 480 -604 453 -424 640 -640 427 -480 640 -640 480 -640 427 -640 427 -640 426 -640 480 -640 480 -375 500 -640 480 -640 426 -500 281 -640 480 -500 332 -640 480 -638 640 -640 457 -544 640 -612 612 -640 427 -612 612 -371 500 -640 324 -640 480 -640 427 -427 640 -365 500 -640 427 -483 640 -640 427 -500 500 -640 284 -640 479 -640 426 -640 427 -640 480 -359 640 -640 480 -469 640 -640 640 -640 428 -480 640 -640 426 -640 345 -640 422 -640 427 -427 640 -640 480 -640 425 -640 480 -640 480 -455 640 -640 480 -640 480 -640 480 -640 480 -333 500 -640 427 -640 480 -640 480 -500 375 -427 640 -640 480 -640 429 -480 640 -640 480 -640 369 -500 378 -640 619 -640 480 -427 640 -426 640 -640 426 -640 489 -640 307 -640 640 -640 424 -640 480 -500 404 -640 428 -426 640 -478 640 -640 426 -426 640 -500 357 -640 427 -480 640 -427 640 -640 333 -500 332 -592 576 -640 480 -640 480 -640 427 -640 339 -640 358 -500 375 -640 480 -480 640 -427 640 -427 640 -500 294 -640 286 -500 375 -500 375 -640 427 -640 264 -640 426 -640 427 -640 391 -433 640 -640 474 -426 640 -640 640 -640 423 -640 480 -500 333 -332 500 -640 428 -640 427 -427 640 -640 487 -640 427 -640 427 -500 377 -640 480 -640 478 -640 470 -500 362 -640 480 -640 507 -640 456 -640 427 -640 427 -333 640 -640 427 -640 397 -640 470 -640 480 -480 640 -640 427 -640 427 -428 640 -640 427 -640 402 -612 612 -640 427 -640 360 -500 375 -640 427 -640 427 -640 640 -640 480 -640 427 -480 640 -640 640 -497 640 -640 480 -612 612 -640 425 -500 348 -640 427 -333 500 -640 480 -640 428 -427 640 -640 428 -378 500 -640 360 -640 480 -640 426 -500 345 -477 640 -640 480 -640 480 -640 480 -640 480 -640 425 -640 427 -640 429 -640 428 -620 319 -427 640 -500 332 -500 375 -640 509 -640 426 -640 480 -640 457 -640 480 -640 424 -473 640 -432 324 -640 428 -640 469 -640 343 -640 427 -333 500 -640 474 -640 427 -640 480 -544 640 -640 480 -333 500 -500 375 -640 427 -500 454 -640 426 -640 640 -340 500 -616 640 -640 427 -380 500 -640 427 -640 427 -500 400 -640 425 -640 480 -640 399 -640 317 -640 480 -500 375 -640 480 -500 500 -500 375 -640 424 -640 480 -640 480 -640 427 -640 427 -640 480 -640 480 -640 453 -405 336 -640 395 -640 426 -640 480 -640 480 -640 482 -640 431 -480 640 -640 480 -427 640 -640 320 -478 640 -640 418 -500 375 -427 640 -424 640 -640 424 -640 482 -640 426 -375 500 -640 338 -425 640 -640 294 -640 426 -500 333 -640 427 -640 428 -640 480 -612 612 -640 480 -429 640 -640 355 -640 435 -376 500 -640 478 -640 480 -640 425 -640 480 -427 640 -480 640 -640 480 -640 428 -640 427 -640 427 -640 429 -400 300 -640 303 -500 500 -333 500 -640 438 -640 480 -480 640 -457 640 -640 426 -640 490 -640 427 -640 428 -640 425 -640 429 -640 462 -640 480 -478 640 -500 367 -640 428 -425 640 -640 480 -640 480 -500 375 -480 640 -320 240 -640 478 -640 480 -640 480 -500 500 -640 425 -640 480 -640 425 -640 427 -640 480 -640 480 -480 640 -640 428 -640 426 -427 640 -640 480 -640 480 -480 640 -500 375 -640 425 -427 640 -427 640 -640 427 -640 459 -500 335 -640 427 -427 640 -640 480 -500 333 -640 360 -429 640 -424 640 -640 480 -640 426 -640 464 -640 414 -480 640 -640 462 -640 640 -640 413 -640 480 -640 480 -640 432 -640 480 -640 480 -427 640 -640 480 -500 481 -640 427 -612 612 -640 479 -300 400 -612 612 -640 424 -600 428 -640 480 -467 276 -640 427 -640 428 -640 360 -427 640 -530 640 -640 392 -640 480 -640 480 -640 427 -460 500 -640 426 -640 427 -640 480 -500 500 -612 612 -640 480 -640 427 -640 427 -500 375 -579 640 -640 427 -480 640 -480 640 -480 640 -640 480 -500 375 -427 640 -640 427 -640 427 -360 640 -640 480 -640 427 -500 499 -640 501 -480 640 -640 410 -478 640 -500 375 -457 640 -640 480 -335 500 -612 612 -640 427 -640 480 -640 480 -364 640 -640 237 -640 400 -640 480 -500 375 -354 640 -640 427 -480 640 -375 500 -640 427 -640 427 -480 640 -612 612 -640 480 -640 427 -480 640 -640 425 -526 640 -480 640 -640 473 -500 375 -640 426 -640 471 -500 335 -640 426 -640 433 -480 640 -640 489 -640 340 -404 640 -640 428 -640 428 -640 427 -503 640 -426 640 -640 428 -640 360 -500 375 -640 427 -640 427 -640 427 -480 640 -640 433 -640 423 -640 480 -640 424 -640 480 -500 331 -640 480 -640 426 -640 454 -640 425 -640 427 -640 300 -466 640 -480 640 -500 375 -374 500 -640 640 -640 480 -640 480 -320 240 -640 508 -640 428 -500 375 -500 375 -640 480 -640 426 -640 480 -640 425 -478 640 -640 506 -640 426 -640 427 -480 640 -480 640 -640 427 -640 427 -640 428 -640 426 -640 426 -500 375 -640 480 -640 426 -640 425 -640 427 -612 612 -640 480 -640 441 -640 424 -640 425 -480 360 -640 417 -640 426 -640 427 -640 512 -640 426 -640 480 -640 480 -460 500 -640 520 -640 361 -640 512 -426 640 -640 427 -427 640 -500 375 -640 428 -480 640 -640 480 -640 480 -480 640 -612 612 -640 480 -332 500 -180 240 -329 500 -640 427 -427 640 -640 473 -640 480 -640 558 -375 500 -640 505 -480 640 -640 424 -375 500 -500 377 -640 480 -640 405 -640 480 -480 640 -640 427 -640 423 -480 640 -640 233 -335 500 -330 640 -500 334 -640 427 -640 588 -500 375 -426 640 -640 425 -640 480 -480 640 -640 480 -480 640 -640 480 -640 427 -640 480 -612 612 -612 612 -640 428 -427 640 -640 427 -640 480 -640 427 -640 237 -436 640 -640 424 -640 428 -427 640 -612 612 -490 640 -640 480 -480 640 -480 640 -640 558 -500 335 -640 417 -640 480 -640 427 -640 360 -640 425 -640 370 -640 481 -640 480 -640 480 -640 480 -374 500 -640 454 -640 480 -640 425 -640 426 -640 448 -640 426 -640 640 -500 429 -640 427 -431 640 -480 640 -512 640 -300 450 -640 483 -480 640 -425 640 -640 427 -640 412 -640 359 -640 556 -640 339 -640 480 -640 430 -640 421 -640 429 -640 480 -428 640 -640 428 -640 394 -480 640 -640 514 -411 640 -640 427 -640 428 -640 427 -640 429 -640 480 -640 430 -640 480 -500 332 -640 427 -640 480 -640 424 -500 263 -640 527 -640 480 -439 640 -480 640 -640 480 -640 480 -640 478 -640 480 -640 429 -640 427 -640 480 -640 411 -640 426 -640 480 -640 480 -480 640 -429 640 -640 480 -640 427 -427 640 -463 640 -640 427 -640 480 -640 480 -427 640 -431 640 -338 450 -640 427 -640 480 -640 480 -640 480 -640 480 -640 427 -640 480 -640 603 -640 480 -640 480 -640 512 -640 427 -427 640 -612 612 -640 480 -640 480 -333 500 -640 480 -640 424 -480 640 -500 375 -640 480 -640 480 -333 500 -640 429 -640 480 -640 480 -640 547 -396 640 -640 427 -640 480 -640 427 -640 424 -640 427 -500 375 -640 640 -640 427 -480 640 -640 429 -640 480 -640 424 -640 413 -640 478 -640 426 -640 426 -427 640 -332 500 -640 425 -640 427 -640 305 -425 640 -640 584 -640 480 -640 480 -640 425 -480 640 -480 640 -640 480 -500 375 -612 612 -640 427 -640 431 -500 375 -315 640 -427 640 -500 375 -640 480 -515 640 -640 480 -640 480 -500 333 -450 390 -640 427 -640 480 -640 480 -480 640 -640 427 -640 480 -640 480 -480 640 -480 640 -500 305 -627 640 -640 480 -640 569 -640 480 -375 500 -640 427 -640 427 -427 640 -640 589 -640 428 -640 439 -640 427 -480 640 -480 640 -640 427 -640 427 -640 480 -500 326 -640 426 -640 426 -640 480 -424 640 -640 618 -612 612 -640 427 -640 426 -500 500 -640 624 -426 640 -612 612 -579 326 -640 480 -640 480 -640 383 -627 640 -640 421 -479 500 -506 640 -640 480 -640 281 -640 427 -427 640 -500 375 -640 445 -640 427 -640 480 -640 480 -640 480 -640 471 -500 500 -640 360 -500 400 -640 480 -640 449 -452 640 -640 480 -640 424 -640 480 -427 640 -640 480 -640 427 -640 426 -640 461 -480 640 -640 480 -480 640 -636 640 -640 480 -500 375 -375 500 -640 428 -480 640 -640 421 -640 427 -480 640 -640 429 -640 425 -640 427 -640 471 -427 640 -431 640 -640 427 -640 431 -640 480 -640 480 -640 480 -640 480 -640 510 -640 480 -640 480 -640 512 -640 480 -501 640 -640 427 -640 427 -640 640 -640 480 -640 360 -640 426 -640 480 -427 640 -375 500 -640 640 -640 480 -640 427 -640 428 -640 427 -640 480 -640 426 -640 480 -427 640 -640 426 -500 325 -402 640 -640 432 -640 480 -480 640 -640 438 -640 512 -500 333 -500 333 -640 540 -640 426 -640 427 -640 480 -500 341 -500 375 -640 428 -301 640 -640 512 -640 480 -426 640 -350 467 -375 500 -640 360 -427 640 -640 360 -640 480 -640 480 -640 426 -480 640 -640 480 -640 441 -640 426 -375 500 -640 435 -640 427 -640 480 -500 375 -428 640 -453 500 -640 427 -640 480 -640 406 -494 640 -640 360 -640 480 -640 480 -640 427 -640 426 -489 640 -640 480 -500 375 -640 478 -640 427 -640 427 -640 429 -427 640 -640 427 -640 425 -640 463 -640 360 -640 480 -640 427 -640 480 -375 500 -640 427 -640 431 -640 480 -640 376 -640 640 -427 640 -640 426 -640 487 -640 428 -426 640 -640 480 -458 640 -640 427 -640 427 -640 629 -480 640 -640 513 -428 640 -425 640 -512 640 -640 480 -640 480 -640 427 -640 480 -640 480 -480 640 -640 428 -506 640 -640 480 -500 335 -640 480 -500 375 -640 426 -640 427 -480 640 -640 427 -640 477 -640 480 -640 427 -640 406 -480 640 -638 425 -640 426 -640 480 -480 640 -640 427 -640 640 -640 423 -640 457 -640 512 -640 427 -426 640 -640 480 -500 338 -640 520 -640 424 -640 398 -640 563 -640 428 -640 464 -640 401 -640 427 -354 640 -552 640 -500 375 -640 427 -640 512 -640 428 -500 375 -640 429 -500 435 -640 425 -600 400 -480 640 -640 427 -427 640 -120 160 -640 426 -500 375 -480 640 -428 640 -640 427 -640 480 -640 480 -640 480 -640 512 -640 480 -640 480 -512 640 -640 428 -640 427 -640 454 -640 480 -640 427 -486 640 -640 488 -500 375 -480 640 -346 640 -640 428 -640 376 -640 427 -640 539 -640 427 -640 371 -640 427 -612 612 -640 480 -640 480 -640 480 -612 612 -640 429 -640 512 -428 640 -500 192 -640 360 -640 449 -640 480 -640 480 -427 640 -640 620 -383 640 -336 447 -640 427 -480 640 -640 423 -640 427 -640 480 -640 427 -427 640 -640 351 -640 363 -640 444 -456 640 -427 640 -640 640 -640 610 -425 640 -612 612 -640 504 -333 500 -640 320 -640 426 -640 480 -640 423 -640 424 -640 480 -640 480 -640 480 -464 640 -640 427 -640 480 -640 360 -427 640 -640 480 -640 427 -500 375 -640 426 -640 427 -640 480 -640 427 -534 640 -480 640 -409 500 -640 480 -640 480 -640 427 -500 359 -640 480 -640 480 -640 480 -612 612 -640 428 -640 480 -640 496 -500 320 -640 525 -427 640 -640 480 -375 500 -640 480 -500 375 -500 375 -640 427 -500 375 -640 428 -480 640 -478 640 -640 427 -640 427 -640 632 -500 339 -416 640 -640 428 -640 428 -640 427 -640 428 -640 480 -640 479 -639 640 -480 640 -640 424 -640 480 -640 426 -500 333 -640 427 -640 480 -375 500 -640 352 -640 480 -640 425 -640 424 -640 480 -640 428 -640 426 -250 150 -640 481 -500 332 -385 640 -640 480 -500 332 -612 612 -640 480 -375 500 -640 419 -424 640 -640 426 -424 640 -640 480 -426 640 -640 480 -640 426 -500 357 -640 480 -640 480 -640 480 -612 612 -640 480 -640 480 -612 612 -640 480 -640 429 -427 640 -340 640 -500 333 -640 480 -640 480 -453 640 -640 428 -640 478 -480 640 -640 480 -375 500 -640 480 -640 480 -640 480 -640 457 -640 424 -640 425 -640 480 -640 480 -640 436 -640 414 -427 640 -500 400 -480 640 -640 500 -640 341 -640 428 -500 399 -427 640 -640 480 -640 480 -640 480 -640 481 -519 640 -640 426 -500 221 -640 631 -500 425 -640 427 -640 480 -640 480 -480 640 -640 460 -640 479 -640 427 -427 640 -640 429 -375 500 -640 480 -640 480 -640 427 -640 426 -480 360 -495 500 -640 432 -640 480 -566 640 -426 640 -640 478 -640 427 -640 428 -640 480 -640 480 -480 640 -375 500 -614 640 -640 480 -640 480 -640 404 -480 640 -640 427 -333 500 -640 480 -640 425 -428 640 -427 640 -500 500 -500 374 -640 526 -640 384 -640 427 -640 480 -640 480 -640 480 -375 500 -640 480 -640 426 -640 421 -428 640 -443 567 -640 480 -640 425 -640 480 -640 509 -640 360 -480 640 -640 480 -640 426 -640 427 -446 640 -640 427 -640 480 -640 428 -640 480 -599 400 -640 425 -427 640 -427 640 -640 427 -640 480 -640 427 -536 640 -500 333 -640 427 -427 640 -375 500 -640 480 -427 640 -640 478 -640 353 -500 375 -640 480 -640 480 -640 480 -640 427 -500 369 -640 480 -480 360 -488 640 -640 480 -640 480 -640 429 -500 334 -640 427 -640 427 -640 480 -426 640 -640 480 -640 346 -640 544 -375 500 -478 640 -640 480 -640 429 -640 541 -640 426 -427 640 -640 427 -500 333 -640 426 -375 500 -454 640 -640 480 -640 427 -640 427 -640 435 -427 640 -640 428 -640 480 -628 484 -640 510 -375 500 -640 433 -640 480 -640 395 -500 375 -640 426 -640 427 -640 478 -612 612 -480 640 -640 480 -640 480 -480 640 -500 375 -640 427 -427 640 -640 360 -480 640 -640 480 -640 432 -640 480 -640 480 -640 426 -640 480 -640 480 -500 332 -640 480 -640 424 -417 500 -640 480 -640 503 -640 480 -640 628 -640 426 -640 480 -480 640 -640 501 -640 480 -640 480 -640 598 -640 480 -640 480 -640 427 -640 428 -640 428 -640 481 -480 640 -640 427 -500 375 -640 640 -640 428 -640 480 -640 480 -640 522 -427 640 -480 640 -640 635 -640 480 -640 480 -640 480 -640 488 -426 640 -640 480 -481 640 -640 425 -640 426 -640 426 -429 640 -281 500 -640 427 -426 640 -480 640 -640 428 -640 480 -640 427 -328 500 -419 304 -480 640 -425 640 -640 640 -640 404 -640 480 -640 480 -640 426 -469 500 -393 640 -480 320 -640 426 -640 640 -427 640 -640 426 -427 640 -640 425 -640 427 -500 335 -640 458 -640 446 -640 359 -424 640 -640 480 -480 640 -640 480 -640 512 -640 319 -640 360 -640 427 -640 480 -427 640 -640 478 -604 640 -480 640 -640 427 -640 523 -640 478 -640 506 -500 375 -640 557 -427 640 -640 478 -640 480 -478 640 -480 640 -640 427 -640 427 -480 640 -477 640 -640 439 -640 623 -640 428 -427 640 -640 481 -640 356 -426 640 -640 426 -500 333 -640 429 -640 490 -640 427 -640 427 -640 527 -480 640 -427 640 -640 426 -640 426 -640 480 -640 463 -500 375 -640 474 -640 427 -500 333 -640 480 -640 480 -612 612 -427 640 -640 427 -640 433 -427 640 -640 416 -427 640 -640 480 -427 640 -640 480 -640 427 -640 427 -640 478 -640 480 -640 360 -640 480 -500 333 -640 427 -640 426 -600 640 -640 427 -640 426 -640 425 -640 480 -457 640 -428 640 -640 573 -640 392 -640 371 -480 640 -600 400 -640 480 -640 428 -640 480 -500 375 -640 480 -640 480 -640 425 -640 480 -640 480 -640 425 -640 425 -640 480 -640 480 -640 480 -640 480 -640 480 -375 500 -500 375 -375 500 -640 480 -568 320 -640 426 -640 428 -640 427 -640 428 -640 383 -640 487 -640 427 -375 500 -640 482 -640 427 -375 500 -640 480 -399 640 -640 427 -200 315 -480 640 -427 640 -427 640 -478 640 -500 410 -640 401 -375 500 -409 640 -640 424 -640 431 -640 426 -612 612 -362 500 -640 427 -640 427 -640 480 -640 360 -480 640 -640 427 -374 500 -640 478 -375 500 -640 480 -640 480 -428 640 -427 640 -500 375 -640 427 -360 640 -640 424 -640 425 -640 480 -427 640 -427 640 -500 400 -425 640 -500 357 -640 480 -640 499 -640 480 -480 640 -460 300 -640 480 -332 500 -640 427 -568 320 -640 424 -500 333 -640 461 -640 480 -427 640 -640 480 -640 429 -640 480 -500 375 -424 640 -640 480 -640 427 -500 333 -612 612 -500 352 -640 438 -500 375 -424 640 -480 640 -400 300 -640 480 -640 478 -640 583 -500 375 -400 300 -640 427 -425 640 -640 428 -640 480 -640 427 -612 612 -640 427 -640 480 -640 480 -640 428 -640 426 -640 424 -640 425 -383 640 -640 481 -640 640 -640 376 -640 480 -500 334 -640 436 -640 427 -427 640 -640 480 -640 480 -427 640 -640 556 -450 640 -426 640 -640 425 -640 480 -640 480 -640 480 -640 480 -640 480 -256 192 -640 427 -640 474 -640 480 -640 480 -640 480 -640 480 -640 296 -443 500 -640 427 -640 480 -640 547 -483 640 -494 640 -480 640 -640 480 -640 480 -640 428 -640 458 -561 640 -640 427 -640 483 -480 640 -640 479 -640 480 -640 480 -640 481 -640 427 -640 425 -640 427 -640 512 -640 348 -640 640 -640 425 -640 427 -480 640 -640 427 -640 427 -640 480 -503 640 -640 424 -640 427 -640 427 -480 640 -640 426 -640 480 -500 375 -640 427 -640 427 -640 474 -300 450 -640 480 -640 424 -640 480 -335 500 -640 427 -640 399 -640 512 -259 500 -500 347 -640 480 -640 480 -500 480 -640 427 -640 383 -640 424 -640 480 -640 427 -640 284 -640 427 -640 427 -640 376 -334 500 -640 480 -640 480 -640 425 -500 375 -640 427 -640 480 -640 396 -640 480 -375 500 -640 480 -500 332 -640 427 -640 480 -640 480 -500 375 -640 425 -520 368 -640 427 -640 427 -640 428 -612 612 -494 640 -640 442 -640 480 -640 425 -434 640 -457 640 -426 640 -500 375 -640 480 -640 427 -640 489 -480 640 -640 428 -640 586 -640 480 -640 480 -640 480 -640 360 -612 612 -640 480 -640 427 -640 480 -640 427 -640 613 -480 640 -640 394 -640 427 -640 427 -640 427 -640 433 -640 425 -500 375 -480 640 -537 640 -427 640 -640 383 -480 640 -640 414 -427 640 -480 640 -480 640 -640 480 -640 480 -426 640 -640 427 -375 500 -427 640 -480 640 -640 426 -640 480 -640 480 -640 426 -640 480 -375 500 -604 453 -375 500 -640 480 -640 480 -640 437 -500 333 -640 480 -640 480 -480 640 -333 500 -640 368 -640 640 -427 640 -640 425 -488 640 -500 334 -427 640 -640 485 -640 480 -488 640 -640 424 -480 640 -640 478 -640 427 -640 431 -481 640 -640 480 -640 426 -392 640 -500 440 -640 478 -426 640 -640 429 -612 612 -640 426 -640 427 -640 480 -500 375 -640 480 -640 428 -640 427 -486 640 -640 478 -640 426 -431 640 -640 425 -375 500 -640 427 -478 640 -640 427 -640 429 -640 480 -480 640 -640 511 -640 427 -500 400 -640 480 -640 361 -500 375 -333 500 -428 640 -640 411 -428 640 -640 347 -640 480 -640 427 -640 426 -640 480 -640 480 -640 534 -640 429 -480 640 -640 426 -640 480 -640 480 -640 480 -640 428 -640 298 -640 428 -640 428 -640 427 -640 480 -640 480 -500 376 -640 480 -640 480 -448 298 -640 329 -640 427 -640 401 -478 640 -481 640 -387 500 -640 480 -640 427 -368 500 -480 640 -640 480 -500 408 -427 640 -480 640 -640 426 -640 427 -640 480 -640 427 -480 640 -640 423 -640 320 -500 332 -375 500 -480 640 -640 427 -640 515 -640 480 -480 640 -433 640 -500 375 -640 426 -640 451 -427 640 -612 612 -640 480 -640 482 -425 640 -640 480 -640 360 -640 478 -640 480 -631 640 -500 333 -640 401 -640 480 -561 640 -640 428 -640 478 -640 480 -640 427 -640 480 -255 600 -500 375 -640 512 -500 500 -640 480 -640 640 -640 463 -640 425 -427 640 -640 426 -427 640 -640 473 -640 480 -612 612 -640 518 -480 640 -640 478 -500 375 -640 480 -480 640 -640 425 -640 359 -500 319 -480 480 -427 640 -480 640 -640 407 -427 640 -640 480 -640 640 -386 500 -640 300 -600 600 -426 640 -640 480 -480 640 -640 427 -640 480 -640 480 -640 427 -640 480 -427 640 -640 427 -640 426 -640 425 -500 375 -640 470 -640 427 -640 413 -409 640 -612 612 -640 480 -500 375 -640 424 -640 480 -640 480 -640 480 -640 480 -640 480 -640 404 -640 427 -640 480 -640 481 -480 640 -500 375 -640 434 -500 333 -294 400 -640 427 -640 474 -500 337 -333 500 -640 428 -640 427 -640 425 -500 500 -427 640 -640 457 -640 425 -640 480 -480 640 -640 480 -640 457 -640 474 -640 480 -640 424 -640 428 -640 480 -640 425 -361 640 -457 640 -640 427 -612 612 -640 480 -640 427 -640 427 -640 427 -640 480 -640 427 -500 333 -640 427 -424 640 -500 375 -640 512 -427 640 -500 333 -500 359 -640 427 -640 428 -640 480 -428 640 -640 372 -480 640 -427 640 -640 480 -640 427 -457 640 -500 333 -343 500 -640 425 -640 480 -640 480 -480 640 -500 334 -640 480 -480 640 -640 480 -640 427 -640 427 -640 480 -640 426 -640 427 -500 375 -480 640 -640 427 -640 480 -640 640 -640 360 -640 634 -640 427 -640 430 -640 427 -472 640 -640 640 -428 640 -612 612 -640 360 -338 500 -640 480 -320 212 -500 375 -500 333 -640 480 -640 426 -640 530 -427 640 -523 640 -640 384 -426 640 -425 640 -480 640 -640 480 -500 332 -640 524 -480 640 -640 480 -500 375 -640 419 -640 480 -640 478 -640 426 -640 480 -640 427 -640 480 -640 426 -640 428 -333 500 -640 480 -640 427 -500 333 -426 640 -640 426 -363 640 -640 349 -640 426 -500 375 -640 608 -375 500 -640 480 -640 426 -500 375 -640 428 -640 457 -480 640 -612 612 -640 480 -490 640 -640 461 -640 480 -640 480 -640 470 -426 640 -508 640 -480 640 -640 427 -640 480 -395 500 -640 480 -640 480 -640 480 -640 427 -640 480 -640 546 -640 480 -359 500 -640 428 -640 457 -640 427 -627 640 -480 640 -427 640 -640 427 -640 480 -640 482 -640 480 -640 427 -427 640 -640 640 -640 480 -500 331 -640 480 -640 427 -359 640 -480 640 -640 427 -640 425 -640 480 -640 425 -500 332 -640 364 -640 427 -500 375 -500 375 -640 427 -640 428 -461 640 -640 480 -640 480 -500 375 -427 640 -640 427 -640 466 -512 512 -347 500 -640 480 -480 640 -500 302 -640 480 -640 425 -640 428 -640 418 -640 480 -640 426 -640 480 -640 480 -500 478 -640 440 -500 375 -500 375 -612 612 -427 640 -640 427 -600 450 -640 480 -483 640 -640 480 -640 480 -640 427 -424 640 -426 640 -465 640 -640 480 -640 431 -640 427 -640 561 -640 413 -427 640 -640 427 -480 640 -612 612 -640 480 -457 640 -640 360 -640 480 -612 612 -480 640 -640 427 -612 612 -640 427 -640 426 -640 480 -640 429 -640 427 -640 480 -640 480 -640 426 -640 444 -640 424 -640 370 -640 480 -427 640 -640 480 -431 356 -640 424 -640 480 -426 640 -640 427 -640 427 -640 478 -640 428 -375 500 -500 315 -425 640 -640 480 -640 480 -640 480 -480 640 -640 478 -478 500 -640 480 -640 480 -426 640 -640 480 -640 419 -640 430 -361 640 -640 428 -500 332 -640 480 -427 640 -640 427 -500 375 -640 424 -640 425 -640 430 -500 375 -640 425 -640 480 -480 640 -500 333 -427 640 -427 640 -449 640 -431 640 -386 640 -640 480 -640 428 -640 480 -500 333 -456 640 -478 640 -428 640 -640 483 -640 427 -640 428 -480 640 -640 480 -480 640 -640 478 -640 480 -640 426 -427 640 -640 427 -640 213 -640 640 -612 612 -640 425 -500 414 -427 640 -640 480 -640 361 -500 333 -523 640 -480 640 -640 480 -612 612 -640 425 -612 612 -640 400 -480 640 -640 479 -500 400 -640 426 -640 401 -478 640 -428 640 -640 423 -640 425 -640 480 -640 480 -612 612 -640 480 -426 640 -480 640 -640 373 -640 480 -640 296 -500 375 -500 375 -640 480 -640 387 -427 640 -500 375 -453 640 -640 426 -640 480 -640 426 -426 640 -480 640 -500 374 -480 640 -640 427 -640 427 -640 427 -565 640 -640 431 -640 427 -640 480 -500 375 -640 325 -640 427 -500 500 -486 640 -640 480 -500 333 -500 375 -640 406 -640 427 -640 426 -640 480 -640 480 -480 640 -640 480 -640 427 -640 480 -375 500 -640 480 -500 375 -426 640 -333 500 -640 427 -612 612 -395 640 -640 373 -640 360 -640 480 -640 480 -640 480 -640 424 -500 375 -612 612 -640 424 -640 425 -640 480 -640 480 -640 427 -640 426 -640 480 -640 478 -491 500 -640 480 -480 640 -640 378 -366 500 -640 427 -640 428 -640 454 -640 512 -500 357 -480 640 -480 640 -457 640 -333 500 -640 480 -500 310 -640 480 -500 559 -428 640 -640 427 -500 375 -640 463 -640 425 -640 480 -375 500 -337 640 -640 480 -640 480 -640 480 -640 199 -371 500 -640 480 -640 476 -640 480 -428 640 -640 427 -640 428 -423 640 -640 480 -640 427 -640 427 -640 480 -500 375 -640 427 -240 320 -640 427 -640 398 -427 640 -423 640 -612 612 -500 375 -640 427 -640 480 -427 640 -640 440 -500 375 -480 640 -500 376 -640 427 -427 640 -480 640 -500 375 -500 307 -640 480 -428 640 -612 612 -640 480 -640 425 -384 288 -640 348 -640 427 -640 480 -640 480 -640 480 -480 640 -427 640 -640 427 -640 428 -640 480 -640 480 -640 511 -500 364 -640 359 -500 332 -500 375 -640 429 -640 480 -640 480 -640 427 -640 427 -500 345 -640 480 -640 427 -640 427 -640 478 -640 480 -500 500 -640 427 -640 427 -640 480 -640 512 -640 427 -640 480 -640 480 -640 427 -383 640 -640 426 -640 427 -640 480 -427 640 -500 375 -640 480 -375 500 -480 640 -427 640 -640 425 -640 640 -640 463 -338 500 -640 487 -640 480 -500 375 -640 474 -640 480 -640 412 -640 367 -640 427 -640 427 -375 500 -640 426 -640 427 -364 500 -640 439 -353 500 -640 480 -640 476 -640 640 -640 480 -640 425 -333 500 -640 425 -640 424 -640 360 -500 368 -640 426 -640 427 -640 480 -500 375 -640 461 -640 457 -640 321 -480 640 -640 427 -640 427 -640 427 -640 480 -271 640 -375 500 -640 427 -640 427 -360 640 -480 640 -640 418 -480 640 -480 640 -640 427 -375 500 -480 640 -640 480 -640 572 -640 428 -640 640 -640 427 -640 480 -640 478 -633 640 -640 425 -640 427 -640 422 -640 480 -640 451 -640 480 -640 427 -640 480 -478 640 -640 427 -640 640 -640 427 -640 480 -500 375 -640 428 -480 640 -640 443 -640 427 -640 427 -431 640 -640 425 -400 500 -640 426 -640 640 -640 480 -640 480 -375 500 -640 401 -640 483 -640 480 -640 427 -640 459 -640 481 -640 480 -640 259 -640 428 -500 375 -640 418 -480 640 -427 640 -640 546 -612 612 -320 240 -640 427 -640 360 -500 477 -500 375 -427 640 -640 428 -640 426 -640 427 -640 438 -640 480 -640 480 -640 428 -500 356 -478 640 -640 426 -640 428 -640 427 -480 640 -424 640 -612 612 -640 426 -640 429 -427 640 -640 360 -640 480 -640 591 -640 428 -640 495 -480 640 -640 480 -480 640 -640 480 -640 640 -640 346 -640 427 -640 427 -640 480 -640 480 -480 640 -640 427 -640 376 -640 424 -640 480 -500 375 -640 427 -640 480 -427 640 -640 428 -640 425 -500 309 -494 500 -640 480 -640 475 -500 375 -375 500 -640 427 -640 480 -640 480 -640 359 -640 512 -488 640 -640 426 -640 426 -420 640 -480 640 -640 427 -640 428 -415 500 -500 375 -500 273 -427 640 -640 480 -640 427 -640 427 -640 428 -640 426 -480 640 -640 427 -640 470 -640 427 -640 522 -640 427 -640 480 -640 428 -640 427 -500 375 -640 480 -500 333 -640 480 -347 500 -480 640 -640 428 -640 480 -500 375 -640 428 -500 334 -640 478 -640 428 -640 480 -640 479 -348 500 -500 375 -640 480 -500 339 -640 481 -640 640 -600 450 -426 640 -480 640 -640 427 -500 375 -640 424 -640 427 -640 478 -640 480 -480 640 -640 426 -640 427 -480 640 -640 434 -640 480 -480 640 -500 375 -640 480 -640 480 -427 640 -640 428 -424 640 -640 480 -640 480 -640 426 -640 427 -500 333 -640 480 -640 442 -640 388 -500 375 -640 480 -640 432 -333 500 -640 480 -640 427 -640 408 -377 500 -640 425 -640 381 -640 509 -640 480 -426 640 -640 371 -640 480 -640 424 -640 503 -640 212 -640 426 -640 480 -512 640 -500 400 -480 640 -500 375 -640 425 -640 427 -640 360 -640 426 -360 640 -431 640 -640 443 -640 480 -640 493 -480 640 -640 566 -640 427 -640 421 -640 480 -640 427 -640 425 -480 640 -640 480 -622 640 -640 427 -324 432 -640 427 -640 427 -640 480 -640 425 -640 480 -640 319 -640 427 -427 640 -640 480 -640 480 -612 612 -640 428 -612 612 -456 640 -500 375 -500 325 -480 640 -480 640 -480 640 -500 375 -612 612 -500 375 -640 480 -480 640 -640 408 -640 427 -640 408 -640 426 -640 427 -640 427 -480 320 -640 284 -640 427 -556 640 -640 427 -640 480 -640 400 -640 421 -500 375 -640 427 -640 480 -640 427 -640 480 -640 481 -561 640 -640 480 -640 468 -640 480 -640 425 -640 425 -500 375 -640 480 -426 640 -640 480 -640 427 -640 511 -640 565 -640 480 -375 500 -640 640 -429 640 -500 375 -480 640 -500 375 -480 640 -640 360 -640 480 -640 427 -500 333 -567 378 -480 640 -480 640 -427 640 -640 360 -500 400 -500 375 -640 428 -600 400 -640 427 -640 480 -640 480 -640 427 -500 375 -480 640 -375 500 -640 424 -640 640 -640 427 -375 500 -640 426 -500 375 -513 640 -640 429 -640 401 -540 407 -480 640 -640 426 -640 426 -640 480 -362 500 -640 480 -640 412 -640 425 -500 375 -640 480 -640 426 -426 640 -494 500 -500 375 -640 480 -640 480 -640 512 -480 640 -640 432 -375 500 -640 480 -478 640 -640 480 -640 459 -640 480 -426 640 -426 640 -640 512 -640 299 -640 427 -424 640 -480 640 -640 427 -640 427 -478 640 -640 480 -640 480 -640 480 -640 480 -500 375 -640 429 -640 480 -640 427 -640 426 -640 427 -640 426 -640 467 -640 426 -480 640 -640 458 -640 428 -640 480 -640 427 -424 640 -640 480 -480 640 -640 427 -640 480 -640 494 -427 640 -640 480 -640 432 -450 337 -640 427 -640 427 -480 640 -640 441 -480 640 -640 428 -640 425 -640 433 -384 512 -500 375 -640 427 -640 584 -500 333 -424 640 -427 640 -640 426 -480 640 -640 480 -444 640 -640 408 -427 640 -640 353 -640 480 -640 480 -640 428 -640 359 -480 640 -428 640 -500 400 -343 500 -640 480 -640 478 -640 427 -480 640 -500 375 -640 427 -480 316 -640 424 -425 640 -640 480 -640 480 -500 333 -640 480 -640 427 -626 640 -640 426 -640 480 -640 480 -427 640 -428 640 -423 640 -500 375 -500 307 -434 640 -480 640 -425 640 -320 240 -500 333 -640 427 -500 375 -480 640 -558 234 -640 515 -640 611 -480 640 -640 425 -427 640 -427 640 -640 427 -640 479 -640 480 -426 640 -428 640 -333 500 -640 430 -427 640 -640 480 -429 640 -425 640 -500 375 -640 488 -640 425 -640 406 -640 457 -640 480 -640 427 -640 480 -640 427 -640 480 -500 394 -640 464 -640 599 -427 640 -640 480 -640 513 -427 640 -640 480 -640 427 -640 479 -640 359 -640 429 -500 333 -500 333 -500 333 -640 427 -640 424 -640 426 -640 428 -640 427 -500 375 -500 375 -500 375 -640 480 -640 427 -640 478 -640 360 -640 427 -454 604 -500 375 -640 427 -640 427 -500 375 -640 360 -640 457 -640 420 -640 480 -640 427 -640 427 -640 480 -640 432 -640 480 -480 640 -640 427 -427 640 -640 480 -426 640 -640 480 -640 480 -640 480 -640 480 -428 640 -640 425 -480 640 -640 429 -640 480 -640 179 -640 480 -640 360 -640 463 -640 427 -480 640 -640 480 -640 459 -480 640 -640 426 -500 375 -425 640 -640 606 -500 375 -500 375 -640 354 -451 640 -414 640 -640 480 -500 281 -500 375 -640 427 -640 405 -640 512 -640 480 -612 612 -640 480 -447 640 -640 427 -640 480 -640 529 -640 317 -480 640 -234 500 -640 480 -480 640 -500 333 -481 640 -460 640 -640 480 -640 360 -500 375 -375 500 -640 480 -640 425 -640 480 -640 426 -476 640 -640 512 -427 640 -500 375 -478 640 -228 296 -640 480 -500 375 -406 640 -427 640 -603 640 -640 428 -640 480 -640 268 -426 640 -640 480 -425 640 -640 409 -427 640 -360 640 -361 640 -640 427 -437 640 -384 568 -500 332 -640 421 -640 360 -640 480 -640 427 -640 480 -428 640 -640 383 -507 619 -427 640 -480 640 -640 426 -480 640 -640 426 -640 480 -640 480 -640 423 -640 424 -640 428 -640 448 -640 427 -640 391 -480 640 -640 425 -640 480 -640 427 -500 335 -480 640 -500 334 -612 612 -427 640 -640 427 -500 355 -640 480 -512 640 -640 532 -640 427 -424 640 -640 453 -640 427 -640 480 -640 428 -640 424 -640 480 -640 480 -640 480 -500 375 -640 480 -480 640 -640 480 -640 428 -500 375 -640 428 -640 391 -480 640 -640 480 -640 480 -500 333 -640 554 -640 480 -640 480 -480 640 -640 427 -480 640 -640 461 -640 480 -640 427 -640 479 -640 427 -640 427 -640 480 -640 427 -640 427 -480 640 -480 640 -500 332 -500 375 -640 480 -640 429 -640 480 -640 427 -640 427 -482 640 -640 426 -500 375 -640 428 -640 426 -640 427 -640 427 -640 301 -640 480 -640 426 -640 428 -640 364 -500 375 -640 426 -640 426 -640 480 -640 424 -640 480 -480 640 -640 353 -640 429 -480 640 -640 480 -427 640 -426 640 -640 427 -640 427 -635 640 -640 480 -426 640 -640 480 -640 480 -640 426 -640 427 -640 426 -640 184 -500 333 -500 475 -640 408 -425 640 -500 375 -640 406 -640 471 -640 426 -640 411 -480 640 -333 500 -640 427 -640 480 -427 640 -640 428 -640 370 -640 414 -640 429 -640 438 -640 426 -480 640 -640 480 -640 427 -640 480 -640 426 -480 640 -640 427 -388 500 -640 425 -333 500 -640 428 -640 480 -640 424 -640 427 -640 424 -500 375 -640 480 -640 426 -640 427 -640 480 -640 640 -500 334 -640 425 -335 500 -640 516 -640 384 -640 425 -640 427 -640 427 -640 428 -640 480 -640 404 -500 375 -640 480 -480 640 -500 334 -640 319 -640 428 -640 480 -640 480 -640 359 -640 480 -640 425 -640 425 -612 612 -640 428 -640 480 -640 424 -500 375 -500 332 -640 426 -640 360 -640 425 -480 640 -640 427 -493 640 -425 640 -640 640 -500 375 -471 640 -640 480 -400 382 -640 427 -640 379 -640 424 -480 640 -640 480 -640 427 -640 428 -426 640 -640 425 -640 427 -640 432 -612 612 -500 375 -640 425 -640 480 -427 640 -640 427 -640 428 -640 480 -640 640 -500 375 -427 640 -640 524 -640 270 -640 424 -640 480 -500 333 -640 427 -640 318 -640 480 -612 612 -640 427 -480 640 -450 338 -343 500 -640 480 -428 640 -500 346 -640 465 -640 459 -480 640 -640 426 -640 427 -640 360 -640 458 -480 640 -640 404 -640 427 -475 389 -640 480 -500 375 -640 360 -427 640 -640 478 -640 427 -640 480 -640 480 -640 409 -500 375 -640 480 -640 480 -640 480 -489 640 -640 427 -640 480 -640 427 -640 480 -640 480 -640 529 -480 640 -640 360 -640 480 -480 640 -640 480 -640 480 -640 428 -640 425 -423 640 -500 281 -640 480 -640 480 -640 428 -640 428 -500 375 -640 378 -640 480 -640 371 -640 480 -640 480 -640 426 -640 480 -640 448 -640 427 -640 501 -480 640 -333 500 -640 480 -640 425 -640 480 -640 429 -640 480 -373 640 -426 640 -640 480 -640 427 -640 480 -640 424 -640 371 -612 612 -500 375 -640 457 -640 480 -640 427 -640 427 -640 480 -640 427 -640 429 -640 427 -375 500 -640 389 -333 500 -500 375 -500 375 -480 640 -612 612 -640 480 -500 375 -640 426 -640 426 -500 333 -640 480 -425 640 -427 640 -626 640 -640 428 -500 375 -640 495 -500 375 -640 424 -640 480 -640 480 -375 500 -640 533 -640 425 -640 424 -640 480 -640 399 -640 427 -640 426 -640 428 -640 425 -480 640 -500 375 -640 426 -640 480 -640 360 -640 427 -480 640 -480 640 -640 432 -500 471 -640 400 -640 427 -500 375 -640 425 -375 500 -640 480 -640 480 -640 496 -323 500 -584 640 -480 640 -640 424 -640 428 -480 640 -640 425 -478 640 -500 334 -480 640 -640 456 -640 458 -640 480 -480 640 -640 425 -480 640 -640 480 -640 424 -480 640 -640 640 -640 480 -640 480 -640 428 -500 375 -640 457 -375 500 -427 640 -640 427 -427 640 -282 500 -371 500 -150 200 -480 640 -640 480 -500 372 -640 480 -640 430 -640 480 -640 480 -640 480 -480 640 -640 427 -640 427 -500 375 -640 427 -425 640 -512 640 -640 427 -640 426 -640 218 -640 427 -640 427 -640 427 -640 427 -640 480 -640 382 -640 480 -484 289 -640 480 -640 461 -427 640 -640 480 -640 428 -375 500 -640 427 -427 640 -500 332 -640 427 -500 430 -640 439 -351 640 -427 640 -426 640 -333 500 -428 640 -640 480 -640 480 -427 640 -640 480 -500 375 -427 640 -640 480 -640 270 -640 473 -426 640 -640 427 -640 480 -640 480 -480 640 -640 480 -640 480 -352 500 -640 480 -480 640 -612 612 -640 427 -640 431 -640 329 -640 427 -640 426 -640 480 -640 480 -640 478 -640 427 -428 640 -394 406 -640 480 -640 480 -640 480 -640 359 -637 640 -640 482 -480 640 -480 640 -640 439 -427 640 -487 500 -640 480 -640 480 -640 426 -480 640 -640 341 -427 640 -427 640 -640 418 -640 374 -640 427 -640 480 -640 480 -640 433 -498 640 -640 427 -640 494 -500 333 -640 427 -480 640 -640 426 -640 426 -640 411 -511 640 -640 427 -640 426 -640 479 -640 427 -426 640 -500 375 -640 428 -375 500 -480 640 -640 482 -500 375 -640 427 -640 497 -600 400 -640 480 -640 385 -640 480 -640 640 -640 480 -640 426 -375 500 -640 429 -500 334 -375 500 -640 427 -640 427 -640 426 -640 424 -480 640 -571 640 -640 535 -640 428 -427 640 -640 480 -640 425 -640 480 -640 425 -640 480 -640 427 -640 424 -640 427 -640 480 -640 480 -640 400 -640 428 -640 425 -480 640 -640 480 -640 376 -640 440 -640 428 -375 500 -640 626 -640 427 -487 496 -500 483 -375 500 -640 359 -640 427 -640 480 -427 640 -640 480 -640 480 -640 427 -640 480 -640 429 -640 427 -640 480 -546 366 -500 375 -439 640 -640 425 -640 400 -480 640 -640 480 -425 640 -640 480 -427 640 -640 480 -500 375 -640 427 -640 427 -640 426 -426 640 -428 640 -640 473 -360 640 -640 480 -640 480 -420 640 -640 480 -640 427 -450 600 -427 640 -640 496 -640 480 -640 432 -577 640 -640 480 -640 514 -640 427 -375 500 -333 500 -640 480 -375 500 -640 427 -500 333 -640 444 -427 640 -640 426 -640 478 -427 640 -640 403 -500 500 -640 480 -640 426 -427 640 -500 334 -640 428 -425 640 -500 375 -640 480 -493 640 -640 640 -512 640 -640 427 -640 480 -612 612 -640 390 -640 424 -640 480 -640 427 -640 480 -640 513 -499 640 -640 359 -640 480 -640 427 -427 640 -640 425 -640 427 -640 427 -640 480 -640 427 -640 480 -640 373 -640 480 -640 480 -640 427 -640 427 -427 640 -640 360 -427 640 -640 424 -612 612 -640 425 -359 640 -427 640 -480 640 -640 426 -640 427 -640 427 -640 427 -640 460 -640 480 -612 612 -640 480 -512 640 -333 500 -640 480 -500 349 -427 640 -640 480 -640 424 -640 448 -480 640 -640 426 -480 640 -640 480 -640 426 -640 427 -640 427 -640 480 -640 427 -480 640 -480 640 -500 333 -479 640 -640 479 -640 550 -640 426 -640 480 -640 426 -640 478 -500 375 -640 424 -640 427 -640 425 -428 640 -640 427 -640 480 -640 426 -640 424 -640 480 -480 640 -640 427 -640 427 -640 426 -480 640 -640 480 -550 366 -640 427 -500 333 -640 480 -288 432 -640 480 -360 640 -640 429 -480 640 -640 427 -640 566 -427 640 -640 480 -500 375 -640 425 -640 640 -640 512 -428 640 -333 500 -500 500 -500 375 -640 425 -640 480 -640 480 -640 427 -640 461 -500 375 -600 450 -640 480 -640 480 -640 427 -500 375 -640 426 -295 175 -427 640 -640 425 -640 427 -640 480 -640 425 -640 427 -640 480 -640 457 -640 419 -640 443 -500 332 -500 375 -500 375 -612 612 -640 457 -612 612 -375 500 -640 427 -640 473 -640 513 -640 426 -612 612 -640 480 -600 600 -640 480 -640 425 -612 612 -640 427 -500 333 -640 428 -640 484 -640 480 -480 640 -640 360 -326 500 -500 401 -480 640 -640 468 -480 640 -640 480 -640 366 -640 480 -426 640 -640 425 -640 425 -427 640 -328 640 -500 298 -500 288 -480 640 -640 427 -425 640 -640 480 -640 480 -640 480 -500 375 -640 424 -640 427 -640 427 -640 426 -478 640 -640 480 -500 375 -480 640 -480 640 -640 428 -640 480 -480 640 -640 478 -640 416 -640 480 -640 360 -640 427 -640 427 -640 480 -639 640 -500 375 -640 457 -640 427 -375 500 -640 480 -480 640 -640 480 -640 481 -480 640 -511 640 -426 640 -640 640 -500 333 -640 480 -640 425 -632 640 -480 640 -640 480 -640 426 -383 640 -640 428 -640 428 -500 375 -400 500 -640 427 -612 612 -640 427 -640 483 -640 480 -640 489 -640 640 -640 480 -640 480 -640 480 -640 480 -640 426 -640 360 -480 640 -449 640 -375 500 -640 425 -640 457 -640 480 -640 427 -640 480 -640 377 -640 480 -640 427 -640 480 -420 640 -451 299 -640 478 -500 375 -640 426 -640 480 -640 361 -480 640 -640 481 -640 427 -640 480 -488 640 -640 427 -640 427 -640 400 -640 509 -423 640 -640 458 -640 480 -427 640 -640 480 -640 360 -640 480 -640 480 -640 426 -640 426 -640 480 -427 640 -483 500 -640 480 -640 427 -480 640 -480 640 -640 426 -400 300 -640 514 -500 328 -640 478 -640 480 -640 427 -640 480 -640 425 -375 500 -640 524 -640 376 -640 397 -640 427 -640 587 -640 480 -500 375 -640 373 -640 480 -640 481 -640 425 -640 443 -640 366 -640 426 -426 640 -424 640 -640 427 -426 640 -640 480 -640 426 -640 480 -640 480 -467 500 -424 640 -640 483 -640 478 -640 480 -640 424 -500 481 -640 426 -325 500 -500 333 -640 481 -480 640 -640 434 -480 384 -640 480 -640 480 -612 612 -640 427 -640 480 -640 425 -640 480 -640 480 -478 640 -640 252 -479 640 -640 480 -335 500 -375 500 -640 426 -427 640 -402 640 -640 640 -500 376 -480 640 -640 480 -640 409 -640 427 -640 481 -640 480 -640 360 -640 480 -500 334 -640 427 -480 640 -640 478 -480 640 -368 500 -640 425 -640 480 -375 500 -640 360 -640 480 -640 427 -640 480 -480 640 -426 640 -640 426 -640 427 -640 480 -640 622 -640 514 -480 360 -640 427 -640 428 -640 421 -640 380 -333 500 -640 480 -640 480 -640 480 -427 640 -640 360 -640 330 -640 425 -640 384 -640 480 -640 480 -640 429 -640 480 -640 480 -425 640 -427 640 -640 424 -640 480 -640 425 -640 480 -640 480 -640 454 -640 427 -500 374 -640 426 -640 480 -500 333 -640 458 -500 375 -640 427 -640 640 -640 427 -640 444 -640 426 -640 480 -640 480 -640 480 -427 640 -640 450 -461 640 -640 406 -612 612 -480 640 -640 480 -640 480 -640 634 -640 427 -640 480 -480 640 -640 424 -640 478 -552 640 -640 426 -640 480 -500 333 -640 426 -480 640 -499 640 -640 428 -374 500 -640 480 -640 480 -375 500 -480 640 -640 425 -640 478 -640 533 -640 427 -640 427 -480 640 -640 480 -457 500 -640 480 -500 375 -640 384 -500 375 -640 480 -640 480 -640 514 -640 427 -480 640 -640 480 -640 428 -640 424 -500 375 -375 500 -427 640 -640 427 -575 457 -640 426 -640 598 -640 427 -640 426 -640 478 -640 316 -640 481 -512 640 -494 640 -640 432 -413 550 -452 640 -500 333 -640 427 -640 480 -640 425 -640 480 -640 377 -480 640 -427 640 -640 426 -640 428 -419 500 -640 427 -480 640 -288 432 -426 640 -640 424 -640 427 -640 427 -640 426 -640 480 -640 480 -640 427 -427 640 -640 427 -500 375 -612 612 -427 640 -640 480 -640 313 -426 640 -640 426 -500 375 -480 640 -427 640 -640 480 -499 640 -500 333 -640 360 -500 375 -640 389 -612 612 -480 640 -640 478 -640 480 -640 427 -640 512 -640 424 -640 480 -427 640 -640 427 -417 640 -640 480 -640 640 -640 533 -640 480 -640 360 -426 640 -480 640 -640 480 -427 640 -426 640 -480 640 -640 480 -640 397 -640 511 -480 640 -426 640 -640 480 -640 427 -640 427 -640 480 -426 640 -427 640 -640 427 -640 427 -427 640 -442 500 -427 640 -640 427 -563 640 -500 375 -640 427 -612 612 -640 361 -640 479 -500 499 -640 424 -640 426 -640 433 -640 428 -640 441 -640 491 -640 639 -612 612 -500 333 -640 480 -640 424 -333 500 -375 500 -640 480 -640 427 -640 595 -640 554 -640 480 -640 427 -640 480 -640 543 -640 428 -640 426 -640 369 -494 640 -640 427 -640 425 -480 640 -425 640 -640 427 -640 427 -480 640 -500 334 -480 360 -612 612 -400 241 -640 480 -640 480 -640 427 -640 480 -333 640 -640 480 -640 426 -640 426 -640 480 -640 480 -640 439 -640 421 -640 426 -480 640 -500 357 -360 640 -427 640 -478 640 -480 640 -640 360 -512 640 -640 480 -640 480 -427 640 -500 375 -640 480 -426 640 -640 495 -584 640 -640 480 -640 427 -640 480 -640 361 -640 480 -423 564 -500 375 -640 425 -500 375 -612 612 -640 605 -640 427 -640 426 -640 480 -640 480 -640 427 -640 427 -640 428 -640 374 -640 426 -640 479 -640 478 -640 359 -480 640 -640 428 -640 425 -640 380 -480 640 -640 427 -640 480 -640 480 -640 480 -640 400 -640 425 -307 500 -640 376 -640 428 -640 427 -640 480 -640 480 -427 640 -640 480 -640 480 -500 375 -640 426 -375 500 -640 486 -500 341 -640 426 -640 498 -640 426 -426 640 -640 426 -640 427 -550 541 -640 480 -640 360 -640 427 -480 640 -640 480 -500 375 -640 426 -375 500 -480 640 -500 375 -452 640 -640 428 -640 478 -640 541 -375 500 -426 640 -640 480 -331 500 -640 427 -640 427 -640 425 -640 480 -640 427 -640 480 -640 265 -624 640 -640 480 -333 500 -640 480 -640 480 -640 425 -424 500 -640 427 -640 480 -640 426 -640 480 -640 426 -640 480 -640 432 -640 480 -640 519 -640 428 -640 543 -500 430 -640 480 -640 480 -640 427 -640 427 -640 480 -640 480 -640 425 -640 480 -406 640 -640 427 -640 480 -640 427 -640 480 -640 426 -640 360 -640 427 -640 480 -500 333 -640 480 -640 426 -640 480 -640 427 -640 427 -500 358 -640 480 -640 464 -500 333 -640 480 -549 640 -640 480 -367 500 -640 427 -640 423 -640 444 -640 428 -640 480 -500 500 -640 480 -640 480 -640 426 -640 428 -427 640 -480 640 -575 408 -500 375 -500 333 -640 427 -640 414 -640 296 -640 427 -480 640 -640 480 -640 431 -640 425 -640 480 -427 640 -448 640 -640 481 -428 640 -640 480 -640 480 -640 480 -640 427 -612 612 -429 640 -500 377 -640 480 -480 640 -640 423 -640 480 -640 427 -640 427 -427 640 -640 428 -640 428 -640 480 -640 427 -480 640 -640 427 -383 640 -640 360 -640 480 -640 397 -640 425 -427 640 -375 500 -500 375 -640 441 -640 427 -640 480 -427 640 -640 427 -480 640 -640 515 -640 404 -640 426 -640 480 -481 640 -640 427 -500 375 -640 428 -640 480 -640 480 -640 458 -640 424 -640 474 -400 467 -431 640 -640 305 -427 640 -425 640 -480 640 -640 427 -640 447 -640 480 -640 427 -640 427 -500 332 -640 480 -480 640 -480 640 -640 432 -640 427 -640 424 -640 480 -500 375 -640 426 -610 635 -640 426 -500 332 -480 640 -500 333 -640 512 -500 375 -640 427 -427 640 -640 427 -640 640 -640 427 -640 426 -480 640 -640 480 -612 612 -640 480 -424 640 -640 427 -500 375 -480 640 -640 480 -640 428 -640 427 -640 510 -480 640 -640 480 -640 427 -640 427 -429 640 -640 480 -640 444 -427 640 -640 640 -640 480 -640 427 -640 512 -375 500 -640 480 -640 480 -612 612 -423 640 -425 640 -640 359 -428 640 -343 640 -424 640 -640 427 -461 640 -640 640 -640 480 -640 515 -640 425 -640 427 -640 615 -640 480 -427 640 -640 426 -640 480 -640 429 -612 612 -640 430 -640 425 -640 480 -500 375 -640 480 -426 640 -640 480 -640 427 -640 427 -640 428 -427 640 -525 525 -640 480 -640 480 -640 480 -640 513 -640 383 -612 612 -620 640 -640 360 -500 375 -640 428 -640 640 -640 427 -640 427 -640 427 -333 500 -640 207 -640 615 -640 395 -480 640 -640 563 -612 612 -640 392 -640 480 -640 478 -640 427 -622 640 -640 427 -640 480 -640 480 -640 480 -500 375 -640 482 -640 478 -640 427 -480 640 -640 426 -332 500 -640 480 -640 480 -640 457 -640 480 -640 480 -368 640 -500 375 -612 612 -640 442 -640 480 -640 480 -427 640 -640 427 -612 612 -480 640 -375 500 -375 500 -640 360 -640 398 -640 409 -640 427 -427 640 -640 428 -514 640 -640 512 -640 480 -640 480 -500 329 -640 480 -640 476 -640 426 -500 375 -640 480 -500 375 -480 640 -500 375 -584 640 -640 480 -640 429 -640 425 -500 332 -640 424 -500 334 -640 427 -640 427 -640 344 -495 500 -640 427 -640 458 -640 533 -500 385 -640 480 -640 426 -640 639 -428 640 -640 427 -357 500 -640 425 -640 480 -640 480 -640 480 -640 361 -500 333 -480 640 -200 240 -427 640 -640 427 -640 481 -640 481 -640 480 -640 480 -640 381 -425 640 -640 428 -640 480 -640 426 -640 427 -640 480 -640 428 -640 414 -640 542 -640 480 -640 480 -640 480 -478 640 -640 410 -500 348 -640 480 -500 375 -640 425 -427 640 -640 427 -640 480 -640 427 -500 375 -640 428 -640 480 -640 480 -480 640 -428 640 -640 640 -640 426 -500 375 -640 429 -612 612 -640 456 -640 480 -396 640 -640 429 -640 480 -640 480 -612 612 -640 480 -640 427 -640 548 -640 532 -640 424 -640 640 -640 453 -640 427 -640 243 -612 612 -640 467 -640 425 -640 408 -333 500 -640 480 -640 480 -332 500 -333 500 -640 480 -640 480 -640 480 -640 480 -640 481 -500 375 -640 431 -640 427 -640 360 -500 358 -640 430 -640 613 -640 480 -640 427 -640 427 -640 480 -640 480 -640 480 -640 420 -640 360 -640 437 -640 527 -640 427 -640 438 -500 375 -461 640 -640 427 -640 427 -427 640 -427 640 -640 480 -426 640 -640 350 -426 640 -640 427 -500 333 -640 480 -640 461 -640 480 -640 427 -640 480 -640 426 -640 480 -640 379 -427 640 -640 461 -640 480 -640 426 -640 480 -640 480 -640 427 -640 359 -640 427 -480 640 -640 516 -640 432 -640 480 -640 480 -640 258 -500 375 -640 403 -500 375 -480 640 -640 433 -640 360 -640 349 -478 640 -640 427 -480 640 -640 480 -563 640 -445 640 -640 437 -640 428 -640 360 -640 480 -640 480 -424 640 -640 513 -640 480 -450 350 -640 427 -640 427 -640 398 -480 640 -400 300 -640 483 -640 428 -175 230 -427 640 -640 480 -640 428 -480 480 -640 513 -640 426 -427 640 -640 457 -427 640 -640 360 -640 360 -427 640 -480 640 -640 433 -640 426 -640 480 -640 383 -640 424 -500 375 -500 375 -604 452 -640 427 -500 375 -333 500 -640 318 -640 480 -640 427 -480 640 -640 640 -640 428 -640 427 -500 375 -640 425 -427 640 -640 431 -480 640 -463 640 -640 429 -428 640 -640 480 -640 640 -640 480 -612 612 -640 414 -640 427 -427 640 -485 640 -360 640 -461 500 -482 640 -640 480 -428 640 -479 640 -640 396 -640 426 -640 433 -640 390 -445 418 -640 427 -500 375 -511 640 -640 480 -640 480 -640 426 -640 427 -375 500 -500 375 -427 640 -640 480 -640 427 -640 480 -640 427 -640 427 -640 480 -640 420 -425 640 -333 500 -640 457 -640 427 -640 426 -640 513 -480 640 -480 640 -478 640 -640 427 -500 335 -640 426 -640 489 -640 480 -618 394 -640 480 -332 500 -640 508 -640 427 -640 480 -640 480 -640 427 -640 480 -425 640 -612 612 -640 421 -640 426 -480 640 -640 480 -640 480 -640 425 -640 237 -427 640 -640 360 -640 428 -640 480 -640 427 -426 640 -640 480 -480 640 -480 640 -640 427 -429 640 -640 424 -427 640 -640 480 -427 640 -640 479 -640 492 -479 640 -640 480 -640 427 -640 427 -500 375 -640 427 -640 480 -500 375 -640 640 -500 375 -426 640 -582 640 -640 480 -333 500 -427 640 -640 617 -500 375 -640 480 -480 640 -640 480 -334 500 -640 480 -640 426 -480 640 -500 333 -480 640 -356 640 -500 333 -426 640 -640 480 -640 425 -640 480 -640 640 -376 500 -640 480 -640 480 -360 640 -480 640 -640 480 -640 480 -640 368 -640 478 -640 426 -640 480 -500 375 -428 640 -640 480 -640 480 -480 640 -483 640 -500 375 -500 333 -424 640 -427 640 -640 480 -640 480 -640 428 -640 480 -480 640 -477 500 -480 640 -427 640 -640 436 -640 480 -640 480 -640 480 -500 332 -500 333 -480 640 -640 480 -640 428 -640 640 -640 620 -480 640 -640 427 -500 247 -640 480 -640 360 -633 640 -640 480 -640 426 -640 427 -640 320 -640 480 -640 480 -480 640 -640 480 -333 500 -433 500 -518 640 -640 424 -612 612 -500 375 -640 400 -640 480 -640 480 -640 415 -480 640 -640 427 -427 640 -640 480 -497 640 -640 480 -427 640 -612 612 -640 427 -640 513 -640 425 -640 625 -640 480 -640 425 -500 296 -640 426 -640 427 -478 640 -640 427 -500 375 -640 640 -640 480 -425 640 -640 428 -640 480 -427 640 -640 427 -640 428 -640 480 -640 427 -640 420 -426 640 -640 426 -640 480 -426 640 -640 427 -640 427 -612 612 -640 360 -640 281 -500 375 -640 379 -640 429 -500 378 -427 640 -640 427 -640 392 -500 375 -479 640 -500 375 -640 480 -608 640 -474 640 -640 480 -640 427 -500 375 -640 429 -640 480 -640 515 -640 480 -640 640 -640 480 -640 426 -640 442 -427 640 -480 640 -640 427 -640 426 -427 640 -500 374 -640 425 -640 425 -640 427 -640 480 -423 640 -640 480 -640 581 -640 427 -426 640 -640 491 -640 425 -612 612 -640 427 -640 426 -640 480 -500 375 -640 640 -640 424 -640 427 -500 375 -640 427 -640 427 -640 480 -640 480 -640 480 -640 426 -500 281 -500 375 -640 427 -640 480 -480 360 -640 410 -640 403 -478 640 -480 640 -640 478 -457 640 -640 427 -375 500 -334 500 -500 332 -640 394 -640 371 -640 426 -640 426 -425 640 -640 480 -640 480 -427 640 -640 427 -640 462 -640 191 -480 640 -640 480 -640 394 -640 438 -640 360 -640 640 -431 640 -640 427 -500 375 -640 398 -640 426 -427 640 -640 428 -383 640 -640 427 -640 424 -640 480 -426 640 -500 375 -480 640 -640 428 -640 427 -500 375 -640 425 -640 480 -375 500 -640 480 -640 428 -640 427 -640 419 -479 640 -427 640 -640 427 -480 640 -640 480 -455 500 -640 432 -640 478 -640 426 -426 640 -640 502 -640 427 -640 480 -640 331 -640 528 -640 480 -480 640 -640 427 -480 640 -640 399 -640 427 -640 424 -640 386 -640 480 -640 427 -413 640 -500 375 -640 480 -640 480 -480 640 -375 500 -640 427 -640 512 -640 480 -427 640 -640 425 -640 424 -640 426 -640 429 -640 428 -640 427 -640 480 -480 640 -640 424 -640 427 -480 640 -640 304 -612 612 -640 427 -640 346 -427 640 -640 427 -640 480 -272 408 -640 480 -480 360 -357 500 -612 612 -640 480 -640 427 -427 640 -375 500 -640 363 -500 375 -640 480 -640 480 -640 480 -400 500 -375 500 -640 479 -640 429 -640 366 -480 640 -480 640 -640 425 -640 401 -478 640 -375 500 -640 427 -640 458 -640 512 -640 480 -612 612 -640 498 -640 480 -480 640 -640 427 -640 480 -640 480 -480 640 -640 478 -427 640 -640 480 -480 640 -500 375 -640 480 -640 480 -640 480 -640 425 -640 427 -478 640 -640 361 -640 635 -500 375 -640 516 -427 640 -640 480 -640 368 -612 612 -640 427 -640 421 -427 640 -640 426 -375 500 -480 640 -640 460 -640 448 -640 303 -640 616 -500 281 -640 480 -640 426 -640 369 -640 429 -640 427 -640 640 -375 500 -640 480 -640 508 -640 427 -640 412 -500 375 -640 480 -640 480 -640 512 -375 500 -640 480 -640 427 -640 480 -640 458 -500 375 -640 457 -640 427 -351 500 -640 428 -640 480 -640 376 -500 333 -500 375 -612 612 -640 480 -640 427 -640 427 -640 426 -479 640 -600 400 -640 640 -640 428 -500 335 -574 640 -640 480 -372 558 -640 427 -640 408 -427 640 -640 471 -640 524 -640 360 -640 480 -640 424 -500 389 -640 480 -640 425 -480 640 -640 424 -640 361 -640 512 -640 480 -640 427 -640 463 -640 480 -640 426 -612 612 -500 375 -375 500 -640 360 -640 612 -640 480 -640 416 -640 408 -640 427 -640 606 -640 539 -640 480 -425 640 -640 425 -640 480 -332 500 -375 500 -375 500 -640 427 -375 500 -640 427 -640 425 -640 427 -640 427 -500 460 -640 480 -427 640 -640 428 -640 480 -500 375 -640 480 -640 265 -640 457 -640 480 -640 480 -640 512 -640 393 -640 428 -426 640 -500 375 -640 427 -640 480 -500 375 -640 429 -640 427 -480 640 -640 459 -612 612 -574 640 -640 480 -415 500 -400 597 -500 333 -640 427 -640 360 -640 480 -500 376 -640 480 -480 640 -427 640 -640 426 -640 426 -640 360 -640 427 -640 480 -640 427 -640 480 -640 480 -612 612 -640 480 -426 640 -640 480 -428 640 -360 640 -640 480 -428 640 -500 375 -640 480 -640 480 -640 424 -499 500 -612 612 -640 480 -640 487 -640 382 -640 430 -640 427 -640 427 -640 427 -640 426 -480 640 -640 425 -480 640 -640 437 -427 640 -640 426 -640 508 -534 640 -640 480 -375 500 -480 640 -640 480 -640 427 -612 612 -640 457 -640 427 -192 564 -500 335 -640 480 -640 480 -640 456 -453 640 -478 640 -640 640 -640 427 -640 485 -640 480 -333 500 -640 427 -640 358 -640 480 -640 426 -640 425 -470 640 -640 480 -640 426 -640 480 -640 427 -500 375 -500 416 -640 427 -640 429 -315 210 -640 480 -640 512 -480 640 -480 640 -500 500 -454 500 -478 640 -640 480 -640 426 -640 480 -640 429 -500 371 -640 410 -640 427 -640 448 -640 426 -640 453 -640 468 -640 425 -511 640 -640 480 -480 640 -427 640 -640 480 -478 640 -450 640 -500 401 -640 480 -640 383 -500 380 -640 425 -375 500 -640 427 -640 582 -640 480 -480 640 -500 375 -640 480 -640 480 -500 375 -534 640 -640 480 -640 417 -640 427 -640 480 -640 480 -640 427 -350 215 -640 426 -427 640 -640 427 -640 480 -500 328 -612 612 -640 426 -640 480 -640 480 -473 640 -435 640 -640 253 -427 640 -475 640 -640 368 -612 612 -640 478 -640 428 -640 426 -427 640 -612 612 -320 240 -427 640 -640 427 -640 480 -640 427 -500 333 -640 480 -640 426 -640 480 -426 640 -427 640 -640 360 -640 427 -640 516 -640 478 -426 640 -500 375 -640 481 -480 640 -640 427 -375 500 -640 427 -500 336 -640 400 -640 434 -640 480 -427 640 -333 500 -425 640 -480 640 -640 480 -640 427 -500 375 -480 360 -640 427 -640 425 -500 333 -640 383 -640 480 -640 427 -320 286 -640 480 -427 640 -640 426 -640 480 -480 640 -640 424 -640 241 -640 480 -600 450 -640 444 -375 500 -512 640 -640 427 -480 640 -640 480 -640 424 -640 405 -479 640 -640 497 -640 388 -640 401 -640 444 -640 427 -640 480 -640 426 -500 375 -640 427 -398 224 -640 480 -640 426 -640 409 -429 640 -640 482 -640 480 -640 427 -640 480 -426 640 -423 640 -425 640 -640 480 -612 612 -640 480 -427 640 -640 513 -640 424 -480 640 -640 367 -640 480 -640 577 -640 427 -640 480 -427 640 -383 640 -480 640 -427 640 -640 427 -640 425 -640 427 -612 612 -640 480 -500 332 -500 333 -480 640 -640 480 -640 480 -640 480 -427 640 -640 425 -428 640 -375 500 -431 640 -451 640 -640 480 -480 640 -640 480 -640 427 -640 424 -640 424 -640 480 -640 428 -480 640 -500 375 -640 427 -500 375 -640 427 -612 612 -640 428 -640 480 -640 480 -640 640 -612 612 -640 469 -640 426 -640 480 -640 427 -500 375 -640 427 -640 480 -427 640 -500 343 -600 407 -640 425 -640 480 -426 640 -640 457 -480 640 -640 427 -500 375 -428 640 -640 427 -640 427 -368 500 -640 441 -640 480 -640 480 -640 427 -640 480 -640 458 -427 640 -500 419 -640 425 -640 480 -640 334 -640 428 -480 640 -640 304 -640 361 -480 640 -427 640 -480 640 -640 540 -640 428 -640 480 -480 640 -427 640 -640 426 -612 612 -640 480 -640 570 -427 640 -334 500 -640 480 -640 459 -640 480 -375 500 -640 427 -640 425 -640 424 -500 375 -640 480 -500 333 -480 640 -640 498 -396 640 -640 431 -640 400 -640 480 -640 427 -640 426 -427 640 -640 480 -640 427 -640 480 -500 335 -640 480 -640 480 -500 358 -640 480 -640 425 -640 579 -425 640 -500 375 -640 428 -325 640 -640 480 -640 425 -480 640 -375 500 -640 426 -640 480 -640 359 -375 500 -320 240 -640 386 -640 480 -640 480 -640 480 -600 399 -375 500 -640 428 -640 481 -640 480 -640 480 -640 480 -640 427 -640 480 -640 283 -427 640 -424 640 -640 480 -480 640 -640 640 -640 359 -640 480 -640 400 -500 333 -640 518 -640 480 -640 458 -640 487 -640 360 -640 480 -480 640 -640 427 -640 420 -424 640 -640 563 -500 357 -640 480 -640 426 -640 470 -640 426 -480 640 -640 427 -640 447 -428 640 -640 480 -640 425 -640 480 -427 640 -430 640 -640 383 -640 429 -640 480 -640 316 -640 426 -640 480 -500 375 -480 640 -640 427 -640 447 -640 426 -640 425 -640 427 -640 509 -640 427 -480 640 -640 359 -480 640 -640 480 -640 480 -640 478 -640 426 -335 500 -501 640 -640 640 -500 417 -640 478 -640 480 -500 444 -640 360 -640 480 -480 640 -640 480 -640 427 -640 427 -500 473 -640 381 -640 480 -640 427 -640 425 -480 640 -640 481 -640 480 -640 480 -480 640 -500 376 -640 480 -640 427 -640 427 -640 480 -334 500 -640 366 -640 220 -428 640 -640 640 -640 426 -640 640 -640 480 -640 503 -640 480 -640 480 -640 427 -640 427 -512 384 -640 428 -640 480 -500 393 -640 480 -500 375 -640 480 -640 480 -640 426 -427 640 -480 640 -640 427 -640 480 -375 500 -427 640 -640 427 -640 422 -640 427 -640 446 -612 612 -480 640 -640 427 -480 640 -480 640 -426 640 -488 500 -480 640 -640 463 -640 480 -500 333 -612 612 -640 480 -640 427 -640 426 -640 480 -640 480 -500 375 -640 427 -640 371 -640 427 -640 427 -640 480 -640 480 -640 360 -640 421 -640 358 -640 360 -500 332 -640 480 -640 425 -640 424 -640 629 -428 640 -640 427 -640 569 -398 640 -640 424 -640 425 -640 427 -500 375 -640 425 -640 480 -640 427 -640 424 -375 500 -640 480 -640 480 -365 500 -640 250 -427 640 -500 375 -612 612 -417 600 -500 375 -640 480 -640 348 -640 427 -640 423 -612 612 -640 427 -515 640 -640 461 -640 427 -375 500 -640 494 -640 480 -640 426 -427 640 -500 375 -640 480 -640 427 -640 427 -500 333 -640 427 -640 480 -640 427 -640 640 -427 640 -480 640 -463 640 -427 640 -509 640 -427 640 -640 427 -640 480 -640 480 -640 480 -640 427 -612 612 -640 480 -640 480 -640 480 -540 403 -640 442 -640 425 -640 427 -640 427 -640 384 -640 481 -640 480 -640 309 -640 480 -640 480 -640 388 -640 480 -640 480 -640 480 -640 360 -640 640 -500 375 -640 427 -640 480 -640 480 -640 427 -640 480 -426 640 -640 425 -640 480 -640 424 -432 591 -640 439 -640 431 -425 640 -427 640 -640 480 -556 640 -640 428 -640 480 -640 427 -640 480 -640 480 -500 375 -640 427 -640 427 -480 640 -640 428 -640 359 -640 480 -640 480 -480 384 -640 571 -640 429 -640 427 -640 415 -640 424 -640 427 -640 480 -640 480 -640 427 -333 500 -480 640 -640 426 -500 375 -640 428 -480 640 -605 640 -640 427 -640 480 -640 360 -383 640 -640 427 -640 480 -462 640 -640 480 -427 640 -480 640 -640 427 -640 425 -285 309 -386 640 -500 375 -640 480 -640 446 -640 480 -640 480 -412 640 -640 480 -480 640 -640 473 -640 427 -427 640 -640 480 -480 640 -427 640 -333 500 -640 457 -640 424 -450 607 -640 427 -640 480 -640 480 -640 427 -640 480 -640 574 -640 427 -436 640 -640 384 -640 480 -640 428 -640 480 -640 332 -640 480 -640 589 -500 375 -640 427 -640 480 -640 414 -427 640 -640 503 -640 360 -375 500 -360 238 -425 640 -480 640 -426 640 -640 479 -480 640 -612 612 -361 640 -640 457 -640 480 -427 640 -640 427 -640 387 -640 431 -640 566 -640 480 -480 640 -359 640 -500 375 -500 332 -375 500 -640 480 -640 427 -480 640 -640 428 -480 640 -640 427 -375 500 -480 640 -612 612 -640 480 -640 426 -375 500 -427 640 -553 640 -640 480 -640 569 -640 427 -640 426 -640 480 -640 478 -640 480 -640 512 -500 375 -640 406 -640 427 -640 480 -640 427 -640 408 -500 333 -584 640 -480 640 -640 480 -640 480 -427 640 -480 640 -375 500 -640 426 -480 640 -640 563 -640 297 -640 476 -396 576 -640 425 -640 480 -640 480 -640 480 -640 427 -640 427 -640 426 -640 400 -500 375 -640 480 -640 427 -640 427 -640 427 -514 640 -427 640 -640 427 -640 480 -480 640 -640 636 -640 480 -640 541 -640 360 -640 353 -424 640 -640 427 -480 640 -640 427 -480 640 -324 319 -640 426 -480 640 -640 427 -640 427 -375 500 -640 480 -478 640 -640 451 -640 480 -500 375 -429 640 -334 500 -480 640 -416 640 -640 427 -640 478 -640 479 -640 480 -640 480 -640 480 -640 384 -640 416 -640 457 -640 424 -428 640 -640 427 -640 433 -640 480 -491 640 -640 426 -500 333 -640 427 -640 427 -640 480 -640 464 -500 382 -640 433 -640 428 -640 427 -384 640 -640 424 -640 480 -333 500 -426 640 -427 640 -640 427 -640 360 -640 484 -640 480 -500 375 -425 640 -427 640 -640 427 -640 480 -640 530 -640 428 -500 500 -469 640 -640 428 -480 640 -640 427 -480 640 -640 489 -375 500 -640 425 -640 480 -640 457 -640 428 -463 640 -500 375 -640 449 -640 480 -640 427 -640 426 -480 640 -640 429 -640 427 -640 480 -640 480 -640 429 -640 543 -500 374 -480 640 -640 427 -500 375 -640 427 -640 360 -640 480 -500 375 -612 612 -640 426 -640 427 -480 640 -640 469 -487 500 -640 426 -640 425 -640 425 -255 640 -640 480 -482 500 -640 361 -640 427 -640 424 -521 640 -640 480 -375 500 -640 640 -375 500 -431 640 -640 480 -640 458 -640 480 -640 427 -640 480 -427 640 -378 640 -640 427 -640 480 -640 640 -640 428 -640 427 -640 480 -640 480 -640 480 -463 640 -640 426 -640 427 -640 426 -640 640 -640 480 -640 480 -480 640 -612 612 -640 379 -427 640 -640 480 -640 424 -640 240 -640 480 -640 480 -640 480 -341 640 -425 640 -612 612 -480 640 -480 640 -640 428 -640 480 -640 480 -640 427 -640 427 -640 420 -480 640 -640 427 -427 640 -640 480 -640 428 -640 427 -500 375 -256 192 -640 417 -480 640 -612 612 -375 500 -640 480 -640 458 -375 500 -640 425 -500 375 -640 518 -478 640 -640 480 -640 361 -480 640 -427 640 -480 640 -640 427 -425 640 -640 427 -500 375 -640 427 -640 344 -480 640 -640 480 -500 375 -640 401 -480 640 -450 350 -443 640 -427 640 -640 366 -640 429 -640 480 -640 426 -640 453 -500 375 -640 480 -640 427 -640 427 -640 478 -500 325 -640 360 -640 480 -640 480 -640 427 -640 425 -500 469 -640 388 -640 480 -640 471 -473 640 -640 480 -428 640 -640 481 -640 480 -640 426 -640 425 -500 333 -500 375 -640 427 -640 480 -640 431 -640 533 -640 428 -480 640 -640 465 -480 640 -640 480 -341 500 -567 567 -640 427 -640 640 -640 425 -480 640 -375 500 -640 458 -597 640 -640 441 -500 387 -400 366 -640 426 -427 640 -612 612 -640 371 -500 375 -640 468 -480 640 -640 480 -640 426 -640 425 -640 353 -427 640 -640 480 -640 480 -640 426 -640 424 -640 428 -333 500 -640 480 -640 593 -640 425 -375 500 -640 478 -500 375 -640 424 -480 640 -640 424 -480 640 -640 311 -640 480 -640 480 -640 426 -640 428 -493 640 -640 480 -640 427 -640 480 -383 640 -500 375 -640 480 -640 427 -640 480 -640 478 -640 508 -640 427 -480 319 -500 375 -640 480 -640 426 -500 375 -640 480 -500 375 -640 426 -640 480 -480 640 -640 480 -480 640 -640 480 -640 447 -480 640 -640 633 -640 427 -640 427 -640 480 -640 504 -471 640 -640 288 -480 640 -427 640 -497 640 -640 480 -640 480 -640 480 -391 500 -640 427 -640 480 -640 480 -377 500 -375 500 -640 480 -640 427 -640 480 -500 375 -640 480 -640 478 -428 640 -640 428 -640 470 -480 640 -640 480 -640 427 -640 480 -640 427 -640 426 -640 480 -640 428 -640 425 -640 428 -640 427 -375 500 -640 425 -640 427 -640 515 -438 640 -640 480 -640 480 -426 640 -640 483 -640 425 -640 427 -640 478 -640 427 -640 427 -640 427 -640 510 -640 427 -500 375 -640 425 -612 612 -640 514 -640 453 -500 330 -480 640 -640 508 -640 427 -640 426 -640 480 -640 480 -640 479 -640 480 -640 480 -375 500 -640 427 -612 612 -441 640 -640 427 -640 480 -640 427 -500 375 -640 461 -640 360 -500 332 -426 640 -500 373 -480 640 -500 333 -500 331 -640 480 -640 360 -612 612 -640 480 -480 640 -640 457 -640 425 -640 427 -640 427 -375 500 -512 640 -375 500 -640 426 -640 478 -640 640 -640 480 -640 480 -500 375 -640 427 -500 375 -640 427 -640 480 -640 527 -480 640 -640 480 -427 640 -500 376 -612 612 -640 425 -334 500 -640 480 -640 480 -500 375 -640 458 -463 547 -480 640 -640 512 -640 480 -640 426 -640 424 -500 333 -640 481 -640 640 -612 612 -640 480 -640 360 -640 415 -640 426 -481 640 -640 434 -375 500 -452 640 -640 353 -640 480 -500 337 -640 480 -640 426 -480 640 -500 336 -640 401 -640 426 -640 558 -640 425 -640 424 -640 480 -640 428 -425 640 -640 427 -640 427 -640 425 -640 408 -640 427 -500 333 -640 480 -640 540 -640 480 -640 480 -640 480 -640 427 -640 397 -640 390 -640 640 -640 427 -640 395 -640 364 -640 480 -640 426 -500 333 -426 640 -640 480 -640 294 -640 427 -640 498 -640 424 -640 425 -500 375 -640 426 -640 421 -375 500 -364 640 -640 427 -640 428 -640 480 -480 640 -480 640 -640 480 -640 480 -640 429 -640 480 -640 480 -427 640 -640 427 -640 425 -640 428 -331 640 -640 480 -427 640 -640 426 -640 480 -530 640 -500 332 -640 339 -640 428 -500 433 -450 640 -429 640 -640 480 -640 480 -640 480 -640 425 -428 640 -640 427 -558 640 -640 480 -640 480 -640 427 -640 485 -500 375 -640 573 -640 640 -640 440 -500 343 -480 640 -640 480 -500 320 -480 640 -612 612 -640 473 -428 285 -640 427 -640 423 -480 640 -640 427 -640 640 -640 426 -640 375 -640 427 -500 332 -640 480 -640 640 -220 293 -640 537 -480 640 -200 305 -640 427 -640 492 -335 500 -640 353 -640 428 -500 375 -640 480 -640 427 -500 375 -640 428 -640 427 -640 480 -640 480 -640 360 -640 480 -640 480 -640 427 -429 640 -640 438 -640 426 -427 640 -640 480 -500 375 -640 480 -480 640 -640 427 -612 612 -640 410 -480 640 -427 640 -428 640 -640 480 -640 480 -640 480 -480 640 -464 640 -425 640 -640 419 -375 500 -500 375 -640 359 -500 333 -427 640 -640 446 -640 480 -640 353 -428 640 -640 425 -500 500 -480 640 -640 480 -640 478 -640 480 -640 424 -640 360 -480 640 -409 640 -640 427 -426 640 -640 428 -640 424 -640 425 -489 640 -375 500 -640 448 -640 427 -462 640 -640 425 -640 426 -640 480 -426 640 -640 480 -640 480 -640 427 -640 427 -480 640 -427 640 -480 640 -327 482 -427 640 -500 400 -640 396 -500 375 -375 500 -640 427 -640 428 -500 375 -640 427 -333 500 -640 427 -640 426 -640 428 -500 375 -479 640 -503 640 -640 489 -640 480 -640 379 -640 426 -640 480 -640 480 -480 640 -500 334 -640 480 -427 640 -500 375 -480 640 -640 426 -640 436 -640 480 -500 332 -500 375 -640 480 -612 612 -427 640 -500 375 -640 448 -640 480 -640 427 -640 438 -640 594 -640 480 -640 536 -640 427 -480 640 -640 480 -621 640 -640 480 -640 425 -640 464 -640 480 -481 640 -640 427 -480 640 -500 375 -640 427 -640 480 -640 480 -612 612 -640 480 -425 640 -640 427 -500 333 -640 480 -493 640 -448 336 -640 427 -640 480 -500 371 -427 640 -640 480 -640 424 -640 480 -640 427 -640 480 -625 640 -480 640 -640 427 -640 427 -640 425 -500 331 -640 553 -640 388 -640 480 -480 640 -640 426 -480 640 -640 427 -426 640 -480 640 -425 640 -640 427 -480 640 -640 428 -299 500 -640 480 -640 480 -640 424 -512 640 -640 427 -640 428 -478 640 -612 612 -640 456 -480 640 -640 426 -640 427 -640 455 -640 429 -640 430 -640 480 -640 360 -426 640 -640 480 -240 320 -375 500 -426 640 -500 333 -640 373 -640 434 -480 640 -480 640 -640 423 -640 427 -640 427 -500 334 -480 640 -640 478 -640 439 -500 419 -480 640 -640 480 -640 426 -500 375 -640 640 -640 548 -421 640 -640 428 -500 375 -640 427 -640 455 -463 640 -640 480 -500 331 -640 426 -500 333 -640 478 -640 428 -640 480 -480 640 -480 640 -640 480 -640 480 -640 480 -426 640 -640 441 -640 469 -640 480 -640 426 -640 480 -640 426 -640 454 -640 425 -640 480 -640 480 -640 427 -640 480 -640 480 -640 368 -640 480 -640 464 -640 428 -640 480 -640 428 -640 480 -640 480 -640 428 -640 480 -480 640 -480 640 -640 428 -640 428 -612 612 -640 427 -640 480 -500 336 -640 427 -480 640 -500 375 -480 640 -640 480 -400 500 -640 427 -640 474 -453 640 -640 303 -640 480 -640 514 -640 427 -640 568 -480 640 -640 359 -640 457 -640 480 -640 360 -640 427 -640 466 -640 339 -426 640 -640 478 -640 359 -640 427 -640 425 -480 640 -480 640 -640 480 -480 640 -640 482 -640 480 -640 360 -640 531 -640 480 -492 640 -640 483 -640 419 -363 640 -640 478 -640 426 -640 480 -480 640 -640 427 -640 480 -500 375 -640 426 -640 480 -427 640 -640 434 -640 428 -480 640 -640 428 -640 480 -500 375 -640 426 -640 480 -640 424 -357 500 -640 480 -375 500 -640 425 -374 500 -640 480 -640 360 -375 500 -640 427 -640 480 -500 334 -640 480 -640 427 -640 501 -427 640 -640 427 -640 427 -640 480 -640 427 -640 427 -480 640 -640 427 -640 427 -640 427 -640 480 -640 480 -500 333 -640 480 -640 428 -640 480 -640 310 -427 640 -640 512 -361 640 -640 427 -425 640 -417 640 -640 457 -640 424 -640 640 -612 612 -640 426 -480 640 -640 427 -640 424 -640 425 -500 334 -640 480 -480 640 -480 640 -375 500 -500 276 -640 360 -640 480 -640 480 -480 640 -640 480 -640 480 -640 444 -480 640 -640 429 -640 479 -640 400 -640 480 -425 640 -640 427 -480 640 -640 480 -640 425 -640 480 -480 640 -500 375 -446 640 -640 480 -640 374 -375 500 -640 427 -352 288 -371 500 -640 426 -640 427 -640 400 -500 333 -480 640 -640 418 -500 333 -375 500 -500 375 -640 487 -640 427 -474 640 -600 397 -640 480 -640 480 -640 151 -640 480 -640 480 -612 612 -480 320 -500 333 -640 480 -480 640 -549 640 -500 343 -375 500 -640 426 -480 640 -640 427 -476 640 -640 427 -640 426 -640 459 -640 423 -426 640 -640 424 -640 480 -640 429 -640 478 -640 424 -640 428 -480 640 -640 429 -480 640 -480 640 -640 408 -640 480 -640 480 -640 427 -640 425 -640 512 -640 426 -640 478 -612 612 -640 498 -640 480 -640 426 -494 640 -640 480 -480 640 -640 481 -640 508 -640 393 -640 386 -640 480 -480 640 -640 480 -640 458 -640 480 -640 427 -500 375 -500 375 -640 480 -320 240 -640 401 -640 390 -463 640 -640 478 -427 640 -640 480 -500 375 -640 480 -640 428 -480 640 -640 428 -640 424 -640 428 -640 426 -640 480 -640 480 -480 640 -640 480 -480 640 -640 501 -640 424 -640 480 -640 427 -640 426 -375 500 -640 414 -640 468 -640 427 -640 428 -640 480 -640 426 -640 480 -640 480 -398 640 -640 443 -640 425 -612 612 -640 425 -640 480 -375 500 -640 424 -480 298 -346 407 -640 428 -600 441 -500 375 -427 640 -640 425 -640 480 -500 375 -480 640 -480 640 -640 480 -640 426 -640 480 -640 480 -480 640 -500 333 -427 640 -500 356 -640 480 -640 480 -640 427 -426 640 -640 427 -427 640 -640 189 -640 427 -640 427 -640 480 -480 640 -612 612 -640 446 -640 425 -640 425 -480 360 -640 428 -640 428 -640 426 -333 500 -640 425 -500 308 -640 426 -480 640 -612 612 -640 425 -480 640 -640 427 -640 469 -612 612 -612 612 -640 416 -426 640 -500 332 -480 640 -500 338 -375 500 -360 640 -640 427 -640 428 -640 427 -640 428 -640 427 -500 332 -640 426 -640 425 -500 375 -640 427 -640 427 -640 425 -640 480 -427 640 -640 360 -373 496 -640 427 -640 607 -375 500 -640 480 -427 640 -640 480 -640 427 -526 640 -426 640 -333 500 -640 428 -478 500 -425 640 -640 428 -350 325 -640 458 -640 480 -640 427 -640 324 -640 480 -640 426 -640 427 -640 425 -500 320 -426 640 -427 640 -640 427 -640 426 -640 480 -640 477 -480 640 -640 429 -640 480 -640 484 -360 500 -375 500 -640 427 -640 581 -384 500 -640 427 -640 424 -496 640 -640 342 -500 375 -640 480 -427 640 -640 480 -500 332 -640 469 -451 500 -640 426 -500 374 -640 480 -640 360 -640 360 -480 640 -640 418 -427 640 -480 640 -640 480 -640 360 -640 377 -480 640 -640 427 -640 458 -640 424 -640 425 -480 640 -640 480 -640 426 -640 443 -640 480 -575 640 -500 375 -640 640 -640 402 -640 427 -640 480 -612 612 -640 396 -352 288 -480 640 -640 480 -640 431 -640 427 -640 359 -640 427 -640 480 -640 539 -500 333 -545 640 -640 428 -500 375 -640 640 -426 640 -640 624 -500 382 -640 480 -640 427 -640 428 -375 500 -640 359 -640 431 -640 491 -640 426 -500 333 -640 479 -566 640 -640 359 -333 500 -640 640 -640 480 -640 480 -425 640 -612 612 -480 640 -640 480 -640 478 -640 478 -480 640 -640 360 -640 458 -640 428 -500 371 -640 426 -500 375 -640 426 -640 480 -640 428 -640 426 -640 485 -640 426 -426 640 -640 427 -640 426 -375 500 -640 480 -480 640 -640 361 -640 512 -640 480 -426 640 -640 427 -640 640 -640 480 -385 500 -640 480 -640 480 -640 480 -640 480 -640 480 -640 425 -500 473 -500 374 -640 480 -640 426 -500 330 -640 445 -640 480 -640 449 -512 640 -479 640 -640 480 -500 375 -640 480 -640 425 -640 480 -640 427 -480 640 -640 478 -640 480 -500 375 -427 640 -512 640 -640 428 -640 480 -640 424 -457 640 -640 480 -375 500 -427 640 -640 426 -500 375 -640 480 -640 427 -640 480 -500 375 -640 424 -640 426 -640 427 -640 360 -640 408 -424 640 -612 612 -640 426 -640 522 -640 427 -640 425 -640 428 -640 427 -500 375 -640 480 -640 480 -640 480 -640 408 -640 480 -640 480 -640 348 -640 427 -640 480 -640 480 -500 332 -500 332 -383 640 -640 464 -640 426 -640 480 -640 480 -640 480 -640 480 -640 430 -640 426 -640 480 -640 480 -640 427 -427 640 -640 427 -640 360 -344 500 -640 427 -640 512 -640 426 -427 640 -640 360 -640 427 -640 480 -640 383 -640 480 -640 453 -640 428 -297 500 -640 480 -500 640 -640 480 -363 484 -427 640 -500 335 -640 425 -640 424 -480 640 -640 480 -640 586 -612 612 -640 480 -640 427 -640 480 -480 640 -375 500 -500 375 -640 424 -640 480 -640 426 -356 640 -640 427 -640 480 -480 640 -640 480 -480 640 -640 480 -640 480 -424 640 -640 415 -500 375 -478 640 -640 426 -480 640 -640 427 -480 640 -500 344 -640 493 -480 640 -640 582 -640 427 -640 480 -640 426 -500 375 -500 331 -480 640 -500 375 -640 398 -640 480 -640 480 -640 427 -640 508 -640 433 -640 480 -640 425 -640 480 -640 427 -640 554 -500 375 -640 480 -640 515 -338 500 -640 574 -426 640 -427 640 -500 375 -640 425 -640 428 -500 333 -640 425 -500 375 -640 480 -640 427 -578 640 -640 478 -640 480 -640 336 -500 335 -640 360 -333 500 -500 333 -480 640 -640 480 -500 375 -320 213 -640 480 -640 480 -485 640 -640 480 -428 640 -500 333 -427 640 -640 427 -640 480 -640 360 -612 612 -640 424 -640 480 -640 469 -640 480 -640 427 -640 480 -640 640 -335 500 -640 426 -640 480 -640 427 -423 640 -640 427 -640 480 -640 427 -612 612 -640 396 -640 427 -480 640 -640 480 -640 409 -640 427 -640 480 -612 612 -640 480 -640 480 -640 375 -640 459 -480 640 -640 458 -640 480 -427 640 -640 378 -640 480 -640 427 -480 640 -320 500 -640 428 -500 375 -640 543 -640 441 -431 640 -640 399 -640 480 -640 582 -640 431 -640 417 -427 640 -640 427 -640 480 -640 480 -640 480 -640 428 -640 360 -640 426 -640 427 -640 480 -640 459 -480 640 -640 556 -480 640 -640 294 -500 375 -640 308 -640 480 -640 425 -500 310 -332 500 -640 480 -640 480 -480 640 -640 429 -640 480 -500 375 -335 500 -640 310 -640 427 -640 526 -640 427 -640 426 -640 454 -500 375 -640 566 -640 481 -640 480 -226 640 -640 480 -640 360 -500 333 -640 328 -640 425 -480 640 -640 427 -640 480 -640 480 -640 427 -640 480 -640 480 -640 480 -640 640 -640 426 -640 424 -640 480 -640 480 -640 482 -467 640 -640 457 -640 480 -480 640 -640 480 -600 399 -640 364 -640 428 -640 427 -640 428 -500 375 -500 375 -640 453 -640 427 -640 359 -426 640 -640 480 -640 480 -375 500 -640 427 -480 640 -640 480 -640 427 -640 190 -640 482 -640 428 -640 427 -640 428 -425 640 -500 375 -640 360 -640 424 -640 427 -640 456 -640 480 -640 480 -640 480 -640 480 -640 480 -375 500 -640 425 -640 427 -640 438 -640 446 -640 427 -612 612 -475 500 -480 640 -407 640 -640 481 -640 427 -424 640 -640 480 -640 480 -640 480 -426 640 -640 427 -640 480 -640 425 -640 480 -480 640 -640 429 -500 375 -640 480 -612 612 -640 427 -500 375 -500 400 -640 216 -640 480 -640 480 -628 640 -640 453 -427 640 -640 428 -640 427 -612 612 -640 427 -640 480 -480 640 -640 425 -640 480 -612 612 -640 487 -640 425 -640 428 -640 266 -640 361 -640 480 -480 640 -640 428 -640 426 -640 640 -281 640 -640 454 -612 612 -640 478 -640 426 -424 640 -478 640 -480 640 -640 473 -500 375 -375 500 -640 424 -375 500 -612 612 -612 612 -640 480 -640 360 -640 431 -640 480 -640 393 -478 640 -500 301 -375 500 -640 426 -640 427 -640 480 -640 480 -375 500 -640 424 -480 640 -640 480 -640 427 -640 480 -640 427 -426 640 -480 640 -480 640 -640 480 -640 478 -640 426 -478 640 -640 428 -640 427 -480 640 -480 640 -404 640 -543 640 -425 640 -640 360 -640 480 -640 464 -612 612 -500 400 -640 607 -478 640 -640 427 -640 426 -640 479 -640 480 -640 480 -640 480 -640 428 -640 425 -640 359 -640 426 -640 359 -640 359 -640 462 -480 640 -640 640 -640 425 -640 400 -640 480 -640 428 -640 480 -640 478 -640 426 -480 640 -640 480 -640 576 -375 500 -426 640 -640 509 -427 640 -640 480 -640 480 -640 427 -500 375 -480 640 -640 406 -640 427 -593 640 -427 640 -612 612 -640 426 -375 500 -640 480 -512 640 -612 640 -640 316 -500 375 -640 427 -427 640 -500 333 -333 500 -500 375 -640 413 -375 500 -480 640 -640 480 -568 320 -500 375 -640 480 -640 421 -640 480 -427 640 -500 375 -427 640 -428 640 -320 240 -500 368 -640 480 -480 640 -640 428 -425 640 -640 480 -640 480 -640 640 -427 640 -640 480 -640 480 -640 427 -640 427 -480 640 -640 480 -480 640 -500 375 -640 480 -640 427 -570 640 -612 612 -640 513 -640 480 -640 480 -640 427 -640 480 -640 427 -640 360 -640 427 -640 426 -640 480 -640 422 -640 425 -612 612 -457 640 -500 334 -640 512 -640 338 -640 425 -480 640 -640 480 -640 476 -480 640 -612 612 -640 480 -640 319 -500 333 -360 302 -640 482 -427 640 -640 427 -640 426 -482 640 -480 640 -427 640 -428 640 -640 427 -640 428 -401 640 -640 398 -640 512 -640 458 -426 640 -640 501 -640 427 -357 500 -450 640 -480 640 -640 481 -264 400 -640 480 -640 480 -375 500 -640 429 -640 360 -640 427 -640 427 -640 480 -479 640 -640 425 -640 427 -640 480 -640 480 -640 427 -480 640 -426 640 -500 313 -500 375 -640 640 -640 429 -640 480 -500 333 -457 640 -352 500 -640 480 -640 480 -640 427 -400 500 -640 480 -500 375 -480 640 -480 640 -378 640 -209 500 -640 480 -640 427 -640 480 -640 480 -640 480 -640 480 -640 433 -640 428 -426 640 -640 480 -640 457 -640 422 -640 475 -640 480 -640 427 -640 512 -640 427 -640 480 -640 429 -640 429 -640 427 -640 480 -640 480 -426 640 -640 428 -640 413 -640 480 -640 480 -640 427 -427 640 -640 426 -640 632 -640 427 -640 359 -480 640 -640 426 -640 427 -500 333 -640 427 -640 510 -640 479 -640 428 -500 333 -480 640 -612 612 -640 427 -640 433 -640 424 -500 333 -640 427 -640 426 -640 457 -640 427 -426 640 -500 375 -640 480 -640 480 -640 435 -640 480 -640 360 -478 640 -640 427 -640 480 -612 612 -426 640 -640 426 -640 425 -640 427 -480 640 -640 361 -640 480 -640 426 -640 453 -640 480 -480 640 -640 480 -480 640 -480 640 -425 640 -640 428 -640 427 -640 425 -640 428 -500 318 -640 399 -500 375 -631 640 -640 427 -640 480 -480 640 -480 640 -640 480 -427 640 -640 480 -640 451 -640 480 -500 375 -512 640 -640 480 -500 500 -640 448 -480 640 -640 383 -480 640 -500 414 -640 480 -500 375 -640 427 -500 375 -425 640 -640 510 -500 421 -640 427 -640 480 -480 640 -480 640 -400 500 -640 427 -640 426 -640 427 -500 375 -640 428 -438 640 -500 333 -640 428 -640 480 -480 640 -375 500 -640 480 -480 640 -640 429 -640 480 -640 429 -640 480 -640 480 -640 427 -480 640 -640 480 -640 618 -421 640 -640 383 -600 450 -528 360 -640 427 -640 480 -640 425 -427 640 -427 640 -640 428 -640 480 -640 481 -439 640 -640 427 -427 640 -480 640 -457 640 -640 342 -480 640 -640 427 -500 375 -480 640 -640 426 -640 424 -640 427 -510 640 -281 500 -640 481 -640 480 -375 500 -640 480 -640 383 -640 480 -612 612 -425 640 -640 480 -640 427 -640 425 -500 347 -640 427 -500 375 -640 480 -640 427 -483 640 -640 480 -640 480 -640 425 -640 480 -500 379 -480 640 -640 466 -640 483 -640 480 -640 640 -640 640 -640 480 -324 640 -640 422 -640 427 -550 400 -640 480 -640 416 -640 480 -640 520 -640 426 -500 332 -428 640 -640 480 -640 424 -640 427 -640 480 -640 480 -640 480 -640 427 -640 480 -640 462 -640 427 -427 640 -640 427 -500 400 -500 332 -640 357 -640 427 -640 480 -640 427 -640 424 -640 440 -500 375 -640 428 -640 480 -640 378 -640 411 -640 480 -640 480 -640 427 -640 411 -640 480 -640 480 -640 459 -640 480 -640 480 -480 640 -640 480 -640 480 -640 427 -640 480 -640 426 -640 480 -427 640 -640 427 -427 640 -640 512 -379 640 -640 480 -640 428 -427 640 -427 640 -640 430 -436 640 -640 427 -500 375 -640 480 -500 375 -640 480 -640 480 -500 333 -640 424 -640 427 -500 375 -640 426 -640 381 -640 480 -640 406 -333 500 -640 480 -500 333 -418 640 -425 640 -640 360 -640 425 -640 640 -640 480 -640 427 -500 175 -640 427 -640 423 -640 480 -640 400 -640 224 -640 400 -640 474 -480 640 -640 389 -640 392 -640 433 -500 375 -640 480 -640 429 -432 640 -640 480 -640 428 -500 333 -640 427 -640 480 -480 640 -640 480 -424 640 -640 480 -640 442 -500 375 -640 480 -640 427 -500 334 -480 640 -500 354 -612 612 -333 500 -640 427 -640 554 -480 640 -640 479 -640 480 -427 640 -640 480 -461 640 -640 427 -640 513 -640 458 -640 480 -480 640 -375 500 -640 517 -640 480 -480 640 -640 426 -427 640 -640 480 -500 375 -640 509 -640 480 -640 477 -426 640 -640 427 -640 482 -640 427 -500 333 -424 640 -640 480 -640 480 -480 640 -640 480 -361 640 -426 640 -640 427 -640 427 -640 480 -500 499 -640 544 -640 640 -640 478 -612 612 -400 500 -640 480 -640 421 -640 480 -640 426 -640 337 -640 427 -640 429 -500 334 -640 484 -640 480 -425 640 -411 640 -480 640 -640 428 -640 427 -640 460 -640 427 -446 500 -370 500 -500 375 -500 377 -480 640 -640 429 -640 458 -640 480 -480 640 -640 371 -640 480 -480 640 -500 375 -640 426 -640 640 -640 512 -640 480 -640 424 -640 428 -480 640 -500 375 -640 480 -500 375 -444 500 -454 640 -500 375 -640 360 -640 480 -500 375 -640 480 -640 640 -640 322 -640 426 -640 479 -220 155 -375 500 -640 457 -640 427 -640 480 -640 427 -500 375 -640 640 -479 640 -640 428 -428 640 -640 434 -375 500 -640 480 -640 399 -616 640 -640 480 -480 640 -640 640 -427 640 -640 427 -480 640 -640 427 -640 480 -640 625 -500 375 -640 425 -640 426 -640 432 -640 480 -640 427 -509 640 -546 640 -640 428 -640 480 -640 426 -640 428 -640 426 -640 470 -640 480 -640 495 -640 338 -640 428 -500 326 -480 640 -427 640 -480 640 -640 363 -640 439 -375 500 -640 544 -500 375 -424 640 -511 640 -640 427 -427 640 -640 427 -640 478 -640 397 -640 480 -478 640 -480 640 -480 360 -500 333 -640 427 -425 640 -427 640 -511 640 -640 480 -375 500 -640 480 -478 640 -640 427 -640 427 -427 640 -640 480 -375 500 -480 640 -640 427 -640 455 -640 426 -640 427 -599 640 -480 640 -640 312 -640 427 -640 427 -427 640 -427 640 -604 453 -640 427 -640 480 -427 640 -500 375 -640 427 -500 335 -427 640 -500 333 -640 427 -640 426 -500 375 -640 463 -427 640 -640 428 -640 429 -640 427 -640 426 -640 426 -640 480 -640 480 -385 640 -640 439 -640 480 -500 375 -640 480 -427 640 -640 480 -640 435 -493 640 -640 480 -640 480 -640 480 -640 427 -640 427 -467 640 -640 426 -384 576 -500 375 -640 480 -640 453 -640 239 -600 387 -640 426 -482 640 -640 426 -640 428 -640 480 -640 427 -640 427 -500 375 -546 640 -480 640 -640 480 -426 640 -640 480 -640 480 -640 427 -640 480 -640 428 -543 640 -640 480 -500 375 -640 480 -640 423 -640 480 -640 626 -640 428 -480 640 -640 480 -640 425 -640 429 -479 640 -427 640 -480 640 -640 426 -563 640 -640 480 -333 500 -480 640 -640 427 -526 640 -640 424 -640 640 -640 480 -429 640 -500 309 -640 427 -640 427 -640 151 -640 428 -640 480 -640 480 -640 427 -640 351 -640 424 -640 426 -483 640 -640 360 -500 356 -640 480 -640 360 -640 427 -500 333 -640 424 -640 427 -640 480 -640 432 -640 480 -612 612 -640 413 -640 427 -640 480 -640 427 -427 640 -640 427 -640 427 -640 480 -375 500 -424 640 -640 425 -640 425 -640 480 -480 640 -500 383 -640 480 -640 480 -429 640 -480 640 -500 375 -640 480 -500 360 -640 479 -640 427 -480 640 -640 429 -375 500 -500 375 -640 400 -640 480 -640 478 -640 455 -640 427 -489 640 -640 343 -640 480 -332 500 -640 640 -640 427 -480 640 -640 480 -480 640 -640 427 -640 480 -500 375 -427 640 -640 428 -640 568 -640 426 -640 425 -640 480 -612 612 -640 512 -640 425 -480 640 -640 480 -640 425 -640 427 -640 427 -500 375 -640 480 -640 446 -640 548 -640 480 -317 500 -640 426 -640 529 -640 426 -640 429 -640 475 -556 640 -458 640 -640 480 -338 500 -640 480 -640 427 -500 500 -640 427 -333 500 -426 640 -640 640 -500 375 -480 640 -640 640 -640 427 -640 438 -640 640 -640 538 -640 425 -640 480 -375 500 -640 426 -640 427 -640 476 -640 400 -640 480 -480 640 -640 427 -425 640 -640 428 -640 390 -640 450 -640 426 -640 480 -500 375 -640 429 -640 429 -500 375 -640 427 -640 480 -500 500 -640 482 -640 428 -640 444 -640 480 -428 640 -480 640 -640 501 -640 480 -640 351 -640 480 -480 640 -429 640 -612 612 -640 480 -640 426 -640 480 -640 427 -640 480 -640 428 -500 375 -640 480 -640 480 -640 425 -413 640 -640 478 -500 500 -640 480 -640 481 -577 640 -480 640 -500 500 -640 480 -640 640 -640 480 -640 454 -640 363 -640 480 -640 368 -640 480 -640 480 -640 479 -640 409 -640 480 -426 640 -480 640 -640 425 -480 640 -427 640 -640 476 -640 425 -477 323 -480 640 -480 640 -640 480 -640 480 -640 480 -640 479 -640 425 -480 640 -640 480 -640 427 -640 426 -640 480 -640 480 -428 640 -640 480 -640 427 -640 480 -640 432 -426 640 -424 640 -500 375 -184 200 -640 425 -640 480 -640 480 -640 427 -640 426 -480 360 -640 480 -640 480 -640 480 -640 449 -426 640 -640 427 -640 480 -640 480 -640 400 -640 427 -425 640 -640 427 -640 480 -640 480 -640 426 -333 500 -640 428 -640 480 -428 640 -500 375 -480 640 -612 612 -450 338 -480 640 -640 425 -640 411 -457 640 -640 480 -640 427 -640 424 -480 640 -500 375 -426 640 -427 640 -480 640 -640 480 -480 640 -640 439 -640 480 -640 427 -425 640 -640 390 -640 640 -428 640 -640 480 -640 478 -375 500 -600 450 -640 480 -500 422 -640 480 -640 480 -640 431 -640 480 -473 640 -529 640 -640 427 -640 480 -550 400 -640 480 -612 612 -500 375 -426 640 -380 640 -375 500 -640 480 -640 429 -640 427 -640 427 -500 376 -383 640 -640 426 -640 480 -640 480 -427 640 -640 480 -500 375 -612 612 -640 480 -480 640 -640 416 -640 480 -480 640 -640 427 -500 400 -640 480 -640 427 -500 375 -640 640 -500 375 -623 640 -375 500 -640 359 -480 640 -640 480 -480 640 -480 640 -640 427 -640 428 -640 640 -640 512 -375 500 -640 480 -640 426 -640 428 -480 360 -489 640 -500 333 -480 640 -640 428 -375 500 -442 330 -640 428 -640 480 -612 612 -360 640 -500 375 -640 497 -640 427 -640 359 -640 427 -500 375 -640 512 -320 238 -425 640 -640 480 -640 480 -640 426 -640 427 -640 444 -612 612 -375 500 -478 640 -640 555 -640 426 -480 640 -640 480 -640 480 -640 426 -640 480 -640 426 -640 427 -640 426 -640 419 -640 427 -480 640 -427 640 -640 480 -640 480 -640 427 -640 480 -640 427 -480 640 -640 480 -640 360 -480 640 -500 375 -504 379 -473 500 -500 375 -480 640 -640 427 -427 640 -640 427 -448 296 -640 424 -640 480 -640 427 -640 384 -640 425 -640 424 -639 640 -640 426 -640 427 -640 480 -294 500 -640 427 -640 427 -640 457 -426 640 -640 512 -640 480 -640 480 -640 467 -640 423 -500 232 -640 480 -361 640 -433 640 -640 427 -446 640 -640 427 -640 480 -640 427 -640 480 -640 480 -612 612 -435 640 -640 478 -426 640 -640 425 -640 424 -640 427 -640 480 -640 426 -640 446 -640 480 -640 428 -352 500 -480 640 -500 375 -406 640 -640 480 -456 640 -640 427 -640 427 -480 640 -640 480 -640 480 -640 480 -640 480 -640 427 -640 359 -480 640 -640 465 -362 640 -640 480 -640 426 -640 640 -640 426 -640 480 -426 640 -640 480 -640 424 -480 640 -640 480 -640 480 -453 640 -534 640 -427 640 -381 640 -640 427 -640 478 -640 574 -427 640 -500 406 -640 154 -481 640 -612 612 -640 361 -640 480 -640 426 -640 353 -480 640 -640 480 -640 428 -640 480 -640 427 -480 640 -640 480 -640 419 -640 481 -640 427 -500 375 -500 375 -612 612 -640 426 -640 480 -480 640 -374 500 -640 454 -457 640 -640 451 -640 480 -640 427 -640 480 -640 380 -413 640 -320 240 -640 427 -640 424 -500 333 -600 410 -333 500 -480 640 -640 427 -640 480 -640 405 -640 427 -640 480 -427 640 -640 480 -640 428 -480 640 -640 478 -640 441 -480 640 -640 480 -429 640 -640 427 -500 500 -640 427 -450 640 -426 640 -640 273 -640 430 -640 503 -612 612 -640 428 -640 428 -640 427 -640 427 -640 480 -640 453 -640 640 -640 480 -480 640 -640 480 -640 480 -640 424 -426 640 -640 499 -640 480 -640 427 -640 485 -640 428 -640 480 -640 480 -640 427 -640 480 -480 480 -424 640 -640 480 -480 640 -500 400 -640 425 -500 333 -640 427 -640 480 -640 427 -640 435 -480 640 -500 333 -500 375 -612 612 -640 427 -640 480 -640 419 -500 333 -640 480 -640 427 -640 603 -640 427 -640 429 -640 405 -640 427 -640 427 -640 480 -500 400 -480 640 -500 333 -640 425 -640 435 -333 500 -640 426 -640 476 -480 640 -640 427 -634 401 -425 640 -640 427 -481 640 -640 480 -375 500 -640 427 -640 421 -640 425 -640 426 -640 426 -640 480 -640 480 -640 427 -419 640 -500 333 -640 480 -500 333 -640 480 -480 464 -640 427 -480 640 -640 539 -640 426 -640 480 -640 425 -500 332 -427 640 -429 640 -640 429 -640 424 -640 427 -640 480 -500 375 -640 429 -640 426 -427 640 -500 374 -640 426 -480 640 -375 500 -640 480 -375 500 -480 640 -389 640 -640 425 -427 640 -612 612 -640 480 -640 427 -640 480 -640 427 -640 340 -612 612 -640 427 -640 429 -640 451 -640 481 -640 512 -500 497 -480 640 -640 472 -640 480 -640 480 -640 480 -640 427 -640 480 -640 458 -640 425 -640 427 -640 444 -640 480 -425 640 -640 440 -640 425 -640 480 -478 640 -640 360 -640 480 -640 480 -640 640 -426 640 -640 427 -640 457 -427 640 -640 480 -640 480 -480 640 -640 480 -480 640 -480 640 -480 640 -640 426 -640 426 -640 480 -500 332 -500 375 -500 334 -640 463 -480 640 -640 425 -482 640 -501 640 -640 403 -640 433 -640 457 -640 427 -640 427 -640 480 -500 373 -640 488 -640 478 -640 480 -640 480 -454 640 -328 500 -640 494 -640 480 -640 426 -640 441 -640 427 -428 640 -478 640 -640 471 -480 640 -425 640 -640 426 -640 425 -640 480 -640 360 -375 500 -640 480 -640 480 -640 640 -640 512 -427 640 -640 427 -640 640 -500 375 -600 600 -640 426 -640 449 -478 640 -640 427 -480 640 -375 500 -480 640 -640 480 -640 426 -640 480 -640 480 -612 612 -640 480 -542 640 -425 640 -537 640 -500 375 -640 426 -640 427 -389 500 -640 359 -640 426 -640 425 -640 427 -640 424 -500 375 -640 402 -640 480 -306 640 -640 426 -640 424 -533 640 -640 423 -640 427 -640 480 -640 427 -640 427 -427 640 -640 428 -500 415 -640 427 -500 437 -640 428 -360 500 -640 480 -612 612 -480 640 -640 425 -640 427 -612 612 -426 640 -452 500 -640 503 -424 640 -612 612 -640 480 -500 333 -640 426 -414 640 -640 414 -640 396 -640 480 -640 480 -640 480 -640 480 -640 604 -640 427 -500 362 -640 426 -640 480 -333 500 -427 640 -480 640 -640 414 -640 480 -640 424 -640 427 -640 427 -640 480 -640 400 -640 640 -612 612 -612 612 -422 640 -426 640 -640 426 -500 375 -640 425 -640 428 -640 416 -640 480 -640 480 -427 640 -640 480 -640 640 -640 427 -640 364 -640 427 -431 500 -480 640 -640 480 -427 640 -640 462 -640 518 -427 640 -640 479 -640 426 -640 480 -640 486 -640 427 -640 360 -640 426 -612 612 -640 480 -640 427 -640 480 -640 427 -640 281 -640 353 -640 480 -640 640 -640 427 -640 480 -426 640 -523 640 -640 640 -640 427 -426 640 -640 428 -640 480 -640 427 -640 448 -640 427 -640 427 -640 444 -500 375 -480 640 -480 640 -640 425 -640 480 -427 640 -410 500 -429 640 -640 427 -640 640 -333 500 -640 433 -640 480 -640 424 -427 640 -640 426 -640 480 -640 425 -500 334 -640 480 -640 427 -500 400 -640 480 -640 427 -640 480 -640 426 -640 427 -640 427 -640 524 -640 426 -500 375 -640 610 -640 425 -427 640 -426 640 -640 553 -427 640 -640 425 -640 480 -427 640 -640 427 -640 427 -640 427 -640 359 -500 209 -640 480 -403 640 -612 612 -631 640 -640 426 -426 640 -640 394 -428 640 -425 640 -640 480 -640 476 -375 500 -640 479 -480 640 -612 612 -640 509 -500 335 -480 640 -640 427 -640 425 -640 457 -480 640 -640 480 -500 337 -640 635 -640 480 -640 427 -640 480 -640 427 -640 640 -640 640 -640 480 -421 640 -640 427 -480 640 -612 612 -640 480 -640 426 -426 640 -640 478 -640 339 -640 480 -500 377 -640 425 -612 612 -427 640 -640 427 -640 428 -640 481 -640 480 -500 467 -640 426 -478 640 -478 640 -640 426 -329 500 -640 468 -428 640 -480 640 -640 427 -640 360 -427 640 -500 333 -480 640 -640 556 -500 375 -640 480 -640 427 -500 332 -500 400 -427 640 -640 427 -612 612 -640 480 -500 334 -640 451 -640 425 -640 426 -427 640 -640 406 -480 640 -640 480 -640 503 -640 480 -640 480 -640 429 -500 375 -427 640 -640 480 -640 426 -612 612 -640 426 -640 480 -500 375 -640 429 -640 360 -480 640 -640 480 -640 428 -640 480 -500 375 -640 480 -640 424 -500 375 -640 424 -640 427 -480 640 -640 480 -640 427 -500 375 -640 480 -640 480 -640 480 -640 480 -640 480 -640 435 -480 640 -640 428 -640 480 -640 478 -640 427 -640 480 -500 336 -640 480 -640 480 -640 480 -640 428 -500 375 -489 640 -640 426 -500 375 -640 480 -640 428 -640 427 -248 640 -640 480 -640 427 -640 322 -640 512 -640 480 -426 640 -640 425 -640 480 -640 427 -640 449 -640 509 -640 480 -640 480 -519 640 -480 640 -427 640 -640 457 -640 480 -640 480 -500 375 -425 640 -640 457 -640 426 -426 640 -480 640 -640 425 -640 427 -334 500 -500 375 -640 471 -500 375 -640 480 -500 305 -436 640 -640 428 -640 480 -640 426 -640 480 -640 426 -640 480 -427 640 -612 612 -502 640 -480 640 -640 480 -480 640 -640 478 -640 420 -640 458 -500 375 -478 640 -427 640 -640 427 -640 427 -640 458 -640 566 -640 555 -640 480 -640 480 -640 416 -640 404 -603 452 -480 640 -640 361 -640 396 -640 480 -640 479 -640 480 -425 640 -640 427 -500 390 -640 640 -640 480 -318 480 -640 360 -500 375 -512 640 -427 640 -480 640 -480 640 -640 480 -640 427 -478 640 -640 478 -640 640 -640 423 -640 480 -318 640 -640 480 -640 421 -640 480 -640 427 -640 480 -480 640 -500 283 -425 640 -320 240 -640 450 -640 480 -640 426 -480 640 -640 427 -640 427 -640 496 -640 426 -640 426 -640 480 -640 427 -640 499 -640 427 -425 640 -428 640 -640 480 -356 500 -640 427 -640 480 -640 479 -640 439 -640 360 -640 480 -500 500 -640 423 -640 479 -640 427 -640 439 -640 480 -640 427 -640 427 -640 457 -640 428 -640 320 -500 375 -640 480 -426 640 -640 480 -424 640 -480 640 -640 480 -640 480 -640 480 -640 427 -640 480 -640 640 -427 640 -500 375 -640 426 -640 427 -640 480 -640 383 -640 427 -640 427 -640 129 -640 480 -640 427 -640 427 -640 299 -640 437 -640 480 -640 428 -640 476 -332 500 -640 476 -500 335 -300 225 -640 359 -500 375 -640 427 -640 427 -640 480 -640 426 -640 428 -331 640 -427 640 -355 500 -640 406 -500 375 -640 480 -480 640 -640 425 -640 480 -500 375 -427 640 -612 612 -480 640 -480 640 -640 480 -500 375 -640 423 -425 640 -640 480 -500 337 -640 480 -612 612 -640 426 -500 375 -480 640 -640 480 -500 333 -640 480 -500 375 -500 375 -640 480 -640 480 -640 426 -500 377 -640 426 -640 480 -500 333 -640 480 -428 640 -640 637 -289 640 -500 375 -640 569 -640 427 -640 362 -640 540 -640 429 -640 402 -640 480 -480 640 -640 427 -425 640 -640 400 -640 640 -640 449 -375 500 -427 640 -353 500 -640 427 -640 640 -424 640 -640 480 -500 450 -640 501 -640 505 -640 480 -640 427 -640 427 -640 480 -500 286 -427 640 -640 404 -640 480 -375 500 -375 500 -640 249 -640 430 -640 488 -640 434 -640 480 -640 480 -640 480 -640 480 -640 480 -640 438 -640 481 -640 214 -640 427 -640 427 -612 612 -640 480 -640 480 -640 480 -640 424 -348 640 -500 338 -360 640 -640 480 -640 480 -479 640 -640 480 -640 384 -640 498 -640 478 -640 480 -424 640 -640 499 -375 500 -375 500 -640 424 -333 500 -640 553 -640 397 -640 480 -583 640 -424 640 -640 480 -640 427 -640 480 -640 360 -612 612 -640 480 -612 612 -500 333 -640 425 -640 480 -640 363 -640 480 -640 480 -640 404 -640 480 -500 335 -640 427 -640 362 -640 427 -427 640 -478 640 -500 291 -476 640 -424 640 -425 640 -500 333 -640 488 -640 501 -480 640 -640 480 -640 480 -640 480 -335 500 -640 480 -382 640 -640 358 -640 373 -640 427 -640 480 -640 481 -640 480 -640 424 -500 335 -640 480 -462 640 -480 640 -640 480 -480 640 -500 333 -480 640 -640 527 -480 640 -427 640 -640 480 -640 426 -375 500 -640 425 -640 427 -640 480 -640 640 -640 480 -640 427 -333 500 -480 640 -640 480 -640 480 -640 427 -640 428 -457 640 -492 640 -640 483 -347 500 -640 449 -480 640 -640 428 -500 375 -640 436 -640 427 -640 383 -640 426 -640 426 -640 458 -640 426 -640 429 -640 427 -640 640 -640 478 -640 428 -640 600 -383 640 -640 480 -480 640 -500 436 -640 480 -612 612 -640 480 -500 375 -640 427 -640 425 -640 428 -500 375 -640 480 -640 427 -640 480 -640 480 -640 427 -485 640 -500 333 -500 333 -640 480 -612 612 -640 610 -640 427 -480 640 -428 640 -640 480 -640 480 -640 480 -333 500 -640 426 -640 427 -640 435 -640 427 -500 313 -640 480 -640 427 -537 640 -640 427 -640 480 -640 317 -426 640 -480 640 -354 400 -640 353 -640 480 -640 427 -270 640 -640 480 -640 480 -640 480 -500 333 -640 428 -640 480 -640 457 -640 480 -640 360 -500 375 -500 385 -640 480 -640 480 -428 640 -480 640 -333 500 -510 640 -640 359 -480 640 -640 448 -640 359 -640 480 -640 427 -640 480 -640 480 -640 427 -640 428 -640 480 -640 426 -480 640 -640 427 -640 428 -640 480 -640 480 -640 424 -463 640 -640 480 -427 640 -640 478 -410 640 -334 500 -640 428 -480 640 -640 426 -640 640 -480 640 -396 640 -640 480 -640 427 -640 480 -500 334 -640 429 -500 301 -640 478 -640 478 -500 375 -640 427 -640 480 -336 448 -514 640 -640 480 -480 640 -640 415 -478 640 -640 426 -480 640 -640 480 -640 480 -640 480 -426 640 -428 640 -427 640 -640 451 -640 466 -480 360 -488 640 -640 360 -426 640 -640 396 -640 480 -523 640 -640 480 -500 375 -640 427 -426 640 -640 480 -500 334 -640 480 -500 375 -640 480 -640 480 -331 500 -640 468 -640 427 -640 480 -640 427 -640 427 -640 427 -441 640 -640 480 -640 419 -500 375 -640 536 -442 640 -640 480 -612 612 -640 427 -500 375 -640 480 -500 333 -640 480 -375 500 -500 332 -640 427 -640 427 -640 427 -480 640 -480 636 -426 640 -640 426 -640 480 -427 640 -406 640 -640 427 -640 480 -640 427 -478 640 -640 427 -500 500 -462 640 -519 640 -640 383 -640 444 -500 333 -514 640 -640 424 -360 221 -480 640 -450 338 -518 640 -477 640 -640 427 -640 480 -640 480 -612 612 -640 427 -640 480 -500 375 -640 427 -640 480 -640 436 -640 480 -428 640 -427 640 -427 640 -640 427 -480 640 -640 368 -640 428 -640 480 -640 327 -640 640 -500 371 -640 480 -640 427 -500 375 -640 529 -640 427 -640 427 -640 479 -640 425 -640 427 -427 640 -640 640 -480 640 -640 480 -427 640 -500 375 -640 480 -640 426 -640 480 -640 424 -640 428 -478 640 -640 480 -428 640 -640 427 -640 480 -427 640 -640 399 -640 427 -428 640 -640 544 -640 480 -640 427 -640 480 -640 480 -640 535 -640 426 -500 375 -500 375 -640 427 -640 480 -640 425 -500 375 -536 640 -640 427 -500 333 -480 640 -640 491 -640 427 -640 429 -640 333 -640 480 -500 375 -640 480 -640 359 -640 420 -640 360 -640 480 -500 349 -640 427 -375 500 -640 146 -640 426 -640 480 -640 480 -500 367 -640 480 -480 640 -640 426 -640 480 -640 425 -640 425 -640 426 -640 419 -425 640 -427 640 -640 426 -640 480 -640 427 -640 480 -640 424 -339 500 -640 428 -640 480 -640 480 -640 483 -640 328 -600 401 -500 375 -500 375 -300 225 -640 480 -640 427 -500 375 -612 612 -640 480 -640 480 -640 426 -640 640 -640 480 -640 428 -500 375 -640 640 -640 465 -640 640 -640 427 -500 375 -640 473 -500 378 -640 481 -640 424 -640 480 -612 612 -425 640 -427 640 -640 480 -640 427 -640 480 -375 500 -640 512 -640 427 -426 640 -640 425 -428 640 -400 500 -383 640 -640 427 -500 374 -500 373 -500 365 -640 480 -600 399 -640 480 -640 426 -640 360 -640 427 -500 375 -640 425 -640 427 -640 640 -640 480 -640 426 -640 406 -640 408 -480 640 -425 640 -640 480 -640 480 -427 640 -500 350 -480 640 -640 427 -480 640 -428 640 -640 360 -640 341 -640 425 -640 523 -640 480 -427 640 -640 427 -425 640 -640 425 -500 333 -640 425 -500 333 -640 461 -500 375 -640 427 -512 640 -640 426 -635 591 -640 433 -640 427 -640 480 -427 640 -640 446 -640 480 -640 427 -640 360 -640 425 -420 640 -429 640 -624 624 -500 375 -640 480 -640 480 -570 640 -640 640 -640 427 -640 441 -425 640 -375 500 -640 366 -480 640 -640 403 -360 640 -640 381 -640 360 -640 480 -640 480 -640 427 -640 480 -640 433 -640 480 -425 640 -439 640 -480 640 -488 640 -500 375 -640 480 -640 466 -427 640 -640 302 -640 480 -640 480 -640 351 -640 480 -640 480 -333 500 -640 427 -299 409 -640 480 -500 333 -500 375 -640 473 -426 640 -640 425 -640 428 -640 427 -640 427 -426 640 -640 477 -640 480 -339 500 -640 449 -426 640 -612 612 -480 640 -640 478 -612 612 -640 426 -613 640 -640 480 -640 480 -640 361 -640 383 -640 410 -640 480 -640 427 -640 563 -425 640 -640 480 -640 480 -480 640 -640 480 -500 348 -640 427 -500 376 -640 488 -640 480 -480 640 -640 427 -640 427 -350 263 -640 428 -640 367 -500 332 -640 428 -480 640 -480 640 -640 480 -640 425 -640 480 -480 640 -500 375 -359 640 -640 480 -500 375 -640 567 -640 360 -500 375 -640 477 -426 640 -640 480 -640 427 -640 425 -500 392 -640 480 -640 482 -640 500 -640 480 -333 500 -640 427 -500 357 -640 424 -640 426 -480 640 -640 480 -640 426 -640 450 -640 360 -480 640 -480 640 -640 427 -640 393 -640 448 -640 480 -640 480 -480 640 -640 480 -427 640 -640 424 -640 557 -640 360 -640 480 -640 405 -640 480 -640 481 -500 495 -640 428 -640 428 -450 338 -640 408 -640 470 -640 480 -425 640 -640 480 -640 428 -640 480 -480 640 -500 334 -500 375 -640 488 -612 612 -640 379 -640 427 -640 480 -640 613 -489 640 -500 500 -480 640 -640 419 -476 640 -367 640 -640 480 -425 640 -640 427 -640 427 -640 480 -640 427 -640 426 -640 389 -500 332 -640 405 -640 480 -640 480 -500 377 -640 493 -640 480 -640 397 -480 640 -640 427 -640 426 -480 640 -640 360 -622 640 -640 426 -640 427 -640 427 -640 426 -544 640 -640 480 -640 427 -500 377 -640 427 -640 640 -640 480 -640 427 -640 480 -640 464 -612 612 -640 480 -640 522 -640 426 -640 427 -425 640 -500 375 -480 640 -640 377 -640 522 -568 320 -423 640 -500 375 -424 283 -428 640 -425 640 -640 479 -640 480 -640 420 -640 428 -640 480 -480 640 -612 612 -500 333 -640 640 -511 640 -640 429 -640 427 -640 640 -640 425 -640 360 -640 480 -630 640 -640 480 -640 428 -500 375 -640 431 -640 426 -612 612 -568 320 -427 640 -640 426 -640 426 -640 569 -339 500 -480 640 -640 480 -427 640 -640 426 -435 640 -640 536 -640 391 -640 480 -427 640 -640 480 -640 640 -640 427 -480 640 -640 490 -640 613 -640 427 -640 480 -640 427 -640 410 -640 428 -640 428 -640 444 -640 429 -640 480 -500 374 -640 426 -480 640 -640 427 -640 359 -427 640 -640 480 -640 427 -640 473 -500 375 -640 360 -500 375 -474 640 -427 640 -480 640 -640 480 -640 480 -640 480 -405 640 -640 428 -640 360 -414 640 -640 425 -640 269 -640 480 -640 480 -640 426 -640 480 -640 426 -640 400 -640 480 -640 480 -427 640 -640 480 -640 480 -640 480 -640 494 -640 411 -640 480 -375 500 -640 480 -640 461 -640 429 -640 480 -500 500 -500 333 -500 375 -640 427 -640 480 -640 480 -640 421 -640 426 -428 640 -640 481 -640 426 -640 480 -640 427 -627 640 -428 640 -640 414 -640 638 -500 375 -428 640 -161 240 -374 500 -480 640 -640 486 -500 375 -480 640 -640 141 -480 640 -640 424 -612 612 -500 333 -480 640 -428 640 -501 640 -480 640 -640 431 -500 334 -640 426 -640 427 -500 500 -640 480 -640 426 -447 640 -500 375 -640 478 -640 573 -640 427 -640 480 -640 419 -500 375 -640 480 -640 480 -543 640 -612 612 -640 480 -500 334 -500 334 -640 427 -640 427 -640 590 -612 612 -480 360 -640 541 -640 495 -640 480 -480 640 -640 425 -500 375 -640 427 -640 428 -640 480 -633 640 -376 500 -478 640 -640 425 -640 480 -640 480 -640 426 -375 500 -640 427 -640 427 -480 640 -375 500 -640 443 -640 425 -640 640 -375 500 -640 521 -640 521 -500 375 -500 375 -640 406 -640 427 -640 427 -640 429 -640 480 -640 480 -427 640 -640 429 -480 640 -640 428 -640 393 -640 480 -640 606 -612 612 -480 640 -500 333 -480 640 -480 640 -334 500 -640 427 -480 640 -640 427 -640 401 -426 640 -500 332 -640 428 -640 480 -500 327 -640 480 -640 480 -612 612 -375 500 -640 427 -640 426 -640 480 -427 640 -640 427 -640 427 -640 480 -640 518 -640 480 -500 464 -375 500 -640 480 -640 480 -500 500 -564 640 -500 375 -427 640 -427 640 -640 427 -640 480 -640 376 -640 480 -640 480 -500 375 -500 336 -640 433 -640 480 -640 425 -425 640 -640 480 -427 640 -640 480 -640 480 -640 359 -640 480 -480 640 -612 612 -640 427 -640 427 -640 480 -640 426 -640 425 -640 480 -640 480 -382 640 -640 427 -640 480 -375 500 -640 480 -640 411 -350 500 -640 640 -640 426 -640 429 -426 640 -640 480 -640 425 -640 480 -500 269 -640 412 -640 427 -640 427 -493 500 -640 428 -640 480 -640 427 -500 461 -640 427 -500 333 -640 480 -640 480 -426 640 -640 427 -640 480 -640 480 -640 427 -498 640 -640 457 -640 436 -640 640 -640 480 -500 375 -640 427 -640 480 -500 375 -500 334 -640 427 -640 299 -480 640 -428 640 -640 426 -382 640 -427 640 -640 428 -640 640 -640 427 -640 426 -320 480 -640 424 -640 346 -500 375 -640 480 -640 480 -640 427 -640 431 -424 284 -640 480 -640 500 -640 480 -640 400 -427 640 -427 640 -426 640 -640 428 -640 480 -480 640 -500 333 -488 640 -640 426 -333 500 -640 469 -640 480 -500 333 -640 638 -500 375 -640 426 -640 427 -640 360 -350 500 -480 640 -375 500 -480 640 -640 480 -640 602 -640 427 -640 480 -640 480 -640 402 -640 427 -640 392 -612 612 -640 480 -640 480 -598 397 -640 480 -640 480 -332 500 -640 480 -640 480 -640 425 -426 640 -640 480 -640 480 -640 480 -640 427 -640 480 -640 480 -500 487 -640 480 -500 375 -640 427 -480 640 -640 478 -500 375 -640 480 -640 478 -427 640 -640 480 -640 473 -640 478 -480 640 -427 640 -640 480 -640 576 -640 427 -640 424 -640 407 -301 388 -331 500 -375 500 -640 480 -640 424 -640 400 -640 480 -640 427 -640 427 -640 426 -500 375 -640 481 -510 640 -640 480 -640 427 -640 427 -500 363 -500 333 -640 349 -640 401 -375 500 -571 640 -640 428 -500 400 -640 478 -640 480 -640 480 -640 483 -640 426 -640 480 -640 457 -640 425 -480 640 -612 612 -640 444 -500 416 -480 640 -640 486 -640 427 -640 480 -480 640 -640 480 -479 640 -448 640 -640 428 -640 480 -500 333 -640 480 -640 426 -640 480 -640 426 -640 480 -450 300 -640 459 -500 334 -640 424 -500 375 -640 429 -640 426 -640 442 -333 500 -640 480 -500 369 -640 480 -640 427 -640 480 -640 480 -480 640 -500 400 -640 480 -640 427 -640 428 -640 426 -640 457 -640 331 -640 427 -640 425 -640 480 -640 480 -640 480 -640 425 -340 500 -640 480 -640 624 -427 640 -640 430 -640 360 -640 480 -326 500 -640 426 -640 427 -640 427 -640 451 -640 427 -640 512 -640 361 -640 480 -640 299 -375 500 -427 640 -384 640 -640 480 -640 480 -375 500 -640 480 -500 332 -640 428 -640 410 -480 640 -640 427 -640 427 -640 480 -640 426 -640 427 -640 380 -428 640 -500 375 -500 333 -640 427 -480 640 -426 640 -640 427 -640 424 -640 426 -640 314 -640 424 -640 439 -640 399 -640 480 -428 640 -480 640 -427 640 -640 480 -500 375 -640 426 -640 427 -640 429 -500 454 -640 480 -640 480 -640 480 -390 640 -320 239 -640 425 -640 427 -640 426 -640 429 -451 500 -480 640 -480 640 -375 500 -413 640 -640 444 -480 640 -640 256 -640 480 -431 640 -640 480 -640 426 -640 480 -335 500 -640 423 -640 374 -427 640 -427 640 -640 355 -480 640 -480 640 -640 426 -640 427 -640 427 -640 480 -480 360 -640 480 -640 488 -500 375 -425 640 -640 480 -480 640 -640 425 -640 360 -640 480 -640 640 -640 470 -640 427 -500 375 -500 333 -640 480 -640 430 -500 375 -480 640 -500 286 -640 417 -612 612 -480 640 -640 427 -640 480 -498 640 -545 640 -640 353 -428 640 -427 640 -640 423 -500 375 -640 466 -640 561 -640 480 -640 480 -513 640 -640 480 -438 608 -640 480 -640 479 -527 640 -375 500 -479 640 -480 640 -640 576 -500 334 -640 421 -640 427 -375 500 -640 427 -333 500 -480 640 -640 427 -640 480 -640 427 -640 480 -640 426 -640 480 -640 427 -640 426 -640 432 -640 426 -640 480 -480 640 -427 640 -640 480 -640 480 -600 600 -360 480 -640 480 -640 427 -640 428 -608 640 -640 424 -640 480 -640 429 -555 640 -640 428 -640 427 -500 375 -478 640 -640 480 -640 481 -640 480 -640 480 -335 500 -500 447 -640 509 -640 457 -640 425 -640 480 -640 480 -640 428 -640 480 -640 425 -500 334 -640 427 -640 426 -380 500 -640 425 -640 480 -480 640 -640 480 -640 498 -640 480 -640 480 -493 640 -640 426 -640 480 -612 612 -500 375 -640 480 -640 426 -640 433 -640 480 -640 480 -640 480 -640 427 -640 360 -500 375 -640 428 -480 640 -640 480 -548 640 -640 426 -640 480 -640 480 -640 481 -640 476 -480 640 -500 333 -640 360 -640 480 -640 429 -640 426 -640 480 -612 612 -500 375 -481 640 -480 640 -375 500 -640 427 -640 510 -500 375 -640 458 -480 640 -640 480 -640 427 -600 600 -480 640 -640 429 -233 311 -551 640 -640 640 -640 428 -640 481 -640 480 -478 640 -500 333 -640 427 -438 640 -640 424 -640 420 -640 480 -640 480 -426 640 -640 478 -480 640 -425 640 -640 366 -500 385 -640 360 -640 480 -480 640 -550 378 -640 480 -640 428 -640 480 -640 424 -640 480 -480 640 -428 640 -427 640 -640 480 -640 480 -640 449 -500 467 -640 480 -640 480 -500 333 -640 480 -640 428 -640 480 -640 426 -480 640 -640 480 -640 479 -640 428 -640 427 -640 620 -640 480 -480 640 -640 480 -632 640 -640 427 -640 480 -640 426 -426 640 -640 480 -640 428 -469 640 -375 500 -640 480 -640 427 -640 480 -640 425 -375 500 -640 521 -333 500 -640 480 -640 360 -640 480 -500 375 -500 375 -640 426 -640 480 -640 426 -640 480 -427 640 -640 480 -500 347 -640 480 -640 427 -640 425 -375 500 -640 480 -480 640 -500 488 -375 500 -640 441 -500 333 -640 424 -480 640 -333 500 -629 640 -640 618 -478 640 -500 375 -640 480 -612 612 -640 360 -480 640 -500 375 -640 431 -640 427 -640 427 -640 612 -448 336 -640 427 -640 427 -640 408 -640 427 -640 427 -640 428 -640 480 -640 428 -640 480 -640 459 -640 360 -425 640 -480 640 -424 640 -500 375 -640 480 -333 500 -640 480 -640 397 -480 640 -640 480 -640 480 -640 425 -427 640 -640 427 -357 500 -640 480 -480 640 -480 640 -500 375 -500 375 -640 640 -640 429 -640 426 -640 480 -640 480 -427 640 -640 360 -640 480 -640 434 -640 427 -538 640 -640 428 -640 480 -640 480 -640 480 -480 640 -640 427 -500 474 -406 640 -423 640 -640 480 -640 423 -640 480 -640 427 -640 430 -500 383 -455 640 -600 400 -640 428 -640 480 -500 429 -640 426 -640 480 -426 640 -640 457 -640 390 -500 321 -640 480 -640 391 -479 640 -640 427 -640 429 -500 375 -640 480 -640 480 -640 640 -640 492 -640 480 -640 424 -640 360 -375 500 -500 239 -640 480 -375 500 -640 387 -480 640 -640 406 -640 427 -640 441 -640 409 -640 480 -640 480 -640 480 -424 640 -640 360 -640 427 -500 335 -500 375 -640 480 -640 480 -640 491 -640 428 -640 426 -640 256 -640 476 -640 403 -427 640 -640 480 -640 480 -427 640 -500 374 -427 640 -500 375 -438 640 -640 425 -478 640 -640 463 -640 346 -445 640 -620 413 -640 427 -500 375 -524 640 -640 478 -640 480 -640 480 -612 612 -640 480 -640 480 -640 428 -500 333 -640 569 -640 480 -640 480 -480 640 -407 640 -640 426 -612 612 -640 427 -415 640 -488 640 -640 480 -640 480 -640 480 -640 360 -640 502 -640 640 -640 480 -640 427 -640 438 -640 480 -428 640 -640 480 -640 640 -640 480 -640 536 -596 391 -640 427 -411 640 -640 427 -427 640 -640 480 -500 375 -640 300 -640 480 -500 333 -612 612 -640 480 -425 640 -500 334 -500 375 -640 480 -640 480 -640 359 -426 640 -500 375 -640 424 -640 427 -640 427 -640 426 -640 480 -640 480 -640 480 -640 424 -500 375 -640 427 -640 480 -640 480 -640 480 -640 480 -640 480 -640 432 -640 427 -640 427 -640 480 -640 170 -500 364 -640 480 -640 480 -459 500 -333 500 -640 426 -480 640 -640 427 -640 427 -640 424 -640 480 -640 427 -640 427 -394 640 -640 427 -640 480 -640 427 -640 457 -640 513 -500 375 -640 480 -640 480 -424 640 -640 426 -640 429 -500 375 -640 428 -640 485 -480 640 -640 428 -500 375 -332 500 -640 400 -640 448 -500 375 -640 480 -640 427 -480 640 -640 420 -518 640 -640 426 -500 335 -640 480 -640 427 -500 375 -333 500 -640 480 -640 569 -480 640 -640 427 -640 433 -640 426 -320 400 -640 480 -640 427 -640 429 -640 480 -640 478 -640 480 -640 480 -640 480 -640 480 -472 640 -640 451 -640 425 -640 452 -612 612 -500 329 -640 480 -480 640 -640 480 -640 480 -640 478 -640 427 -334 500 -640 426 -428 640 -640 428 -640 427 -640 429 -640 434 -640 640 -640 480 -640 424 -640 427 -448 640 -480 640 -480 640 -480 640 -640 480 -500 370 -427 640 -640 424 -640 480 -569 640 -259 387 -640 480 -640 426 -640 425 -500 420 -640 427 -640 428 -640 427 -640 457 -640 359 -640 360 -389 500 -640 428 -640 427 -421 640 -640 480 -640 401 -480 640 -640 426 -360 640 -480 640 -480 640 -640 480 -640 480 -640 480 -375 500 -640 480 -479 640 -640 533 -640 428 -640 480 -640 426 -640 509 -426 640 -480 640 -640 480 -640 480 -640 427 -426 640 -640 425 -640 427 -500 375 -640 480 -423 640 -640 427 -640 428 -479 640 -480 640 -640 423 -426 640 -500 374 -428 640 -640 424 -640 428 -640 424 -640 480 -612 612 -500 333 -640 640 -500 345 -480 640 -640 464 -640 426 -640 480 -640 427 -640 374 -427 640 -640 428 -640 360 -640 640 -640 428 -640 481 -640 360 -640 480 -609 530 -428 640 -640 480 -640 427 -640 425 -640 480 -640 427 -480 640 -640 426 -640 389 -500 375 -640 427 -427 640 -640 480 -640 480 -332 500 -336 500 -640 427 -640 480 -640 316 -640 483 -425 640 -399 640 -640 480 -480 640 -640 640 -480 640 -640 427 -640 428 -640 423 -160 120 -640 480 -640 360 -640 480 -640 427 -500 421 -480 640 -425 640 -640 594 -640 480 -640 512 -500 243 -640 480 -500 375 -640 480 -640 427 -480 640 -640 426 -640 424 -639 640 -518 640 -640 479 -426 640 -640 430 -640 427 -640 466 -640 480 -640 480 -640 427 -427 640 -612 612 -480 640 -640 474 -500 375 -640 480 -640 480 -640 375 -640 473 -350 262 -640 427 -432 640 -472 640 -640 478 -640 427 -640 436 -640 427 -640 480 -640 428 -500 375 -427 640 -640 360 -427 640 -604 640 -640 480 -480 640 -640 427 -640 640 -478 640 -640 480 -640 426 -640 484 -640 427 -640 431 -640 477 -500 375 -640 480 -500 333 -500 375 -640 414 -480 640 -426 640 -427 640 -640 480 -500 333 -640 480 -500 333 -640 427 -640 480 -640 357 -428 640 -640 427 -640 480 -427 640 -640 427 -640 573 -640 427 -500 375 -490 500 -640 319 -640 480 -478 640 -640 469 -640 480 -500 313 -640 480 -480 640 -500 375 -640 218 -480 640 -640 426 -640 427 -640 427 -640 480 -480 640 -640 479 -640 428 -640 480 -480 640 -640 499 -427 640 -457 640 -640 361 -500 375 -640 417 -500 324 -640 480 -640 480 -640 427 -640 427 -640 425 -640 480 -364 500 -640 480 -640 640 -640 427 -640 425 -279 640 -480 640 -640 451 -640 331 -640 427 -478 640 -503 640 -640 480 -640 485 -426 640 -335 500 -640 479 -640 480 -640 480 -640 494 -640 474 -640 480 -640 359 -640 425 -480 640 -480 640 -640 526 -640 482 -640 480 -640 480 -640 427 -458 640 -640 404 -500 375 -640 427 -640 480 -500 356 -640 426 -640 480 -640 426 -500 375 -640 417 -640 435 -640 495 -640 427 -500 333 -640 480 -283 640 -640 480 -425 640 -640 425 -640 427 -640 398 -640 480 -640 480 -640 480 -640 424 -375 500 -500 341 -640 480 -480 640 -640 480 -640 427 -640 360 -640 426 -640 427 -640 360 -640 413 -640 480 -640 437 -640 480 -427 640 -513 640 -640 480 -640 480 -640 480 -640 425 -640 427 -404 342 -640 490 -640 426 -426 640 -392 640 -612 612 -333 500 -640 427 -640 429 -640 427 -640 480 -640 480 -640 424 -500 500 -480 640 -426 640 -640 425 -480 640 -640 427 -640 480 -480 640 -640 640 -640 480 -640 408 -500 334 -640 425 -480 640 -640 640 -448 640 -480 640 -500 375 -640 427 -640 427 -640 427 -640 480 -500 375 -640 480 -640 480 -640 427 -640 427 -640 425 -640 426 -640 425 -480 640 -640 480 -640 428 -640 480 -612 612 -523 640 -640 427 -612 612 -640 427 -500 332 -640 510 -640 424 -640 427 -480 640 -612 612 -480 640 -500 369 -427 640 -640 424 -640 427 -640 384 -427 640 -640 427 -640 480 -640 424 -640 480 -640 480 -500 333 -500 333 -640 480 -347 500 -500 375 -426 640 -500 375 -640 480 -476 376 -500 345 -375 500 -640 480 -480 640 -383 588 -640 427 -640 480 -452 640 -640 427 -640 480 -640 427 -640 480 -480 640 -640 480 -640 480 -427 640 -640 480 -640 480 -640 427 -640 564 -427 640 -426 640 -427 640 -640 392 -427 640 -640 425 -640 427 -640 427 -640 384 -640 427 -426 640 -640 427 -640 427 -640 584 -612 612 -480 640 -640 427 -640 480 -640 418 -453 640 -640 427 -640 480 -500 375 -427 640 -640 480 -640 360 -640 427 -640 427 -612 612 -640 427 -463 640 -500 375 -640 427 -640 480 -640 427 -640 359 -640 426 -480 640 -640 480 -640 480 -640 427 -464 640 -640 426 -640 427 -640 427 -640 424 -640 303 -640 419 -640 480 -640 480 -640 425 -500 375 -640 481 -640 476 -640 301 -480 640 -500 376 -640 480 -640 428 -640 428 -640 427 -640 480 -640 426 -383 640 -427 640 -640 426 -640 463 -500 375 -640 480 -480 640 -500 318 -640 583 -480 640 -640 427 -480 640 -427 640 -640 427 -640 425 -640 480 -500 375 -640 480 -480 640 -640 426 -640 360 -640 512 -640 428 -640 480 -500 375 -640 360 -640 480 -640 427 -340 500 -500 333 -427 640 -640 480 -640 480 -640 480 -427 640 -480 640 -640 396 -600 393 -640 427 -612 612 -480 640 -640 427 -640 480 -640 448 -640 427 -640 480 -640 478 -640 428 -640 188 -640 428 -500 426 -640 427 -480 640 -640 480 -640 426 -640 457 -640 480 -480 640 -640 481 -480 640 -640 427 -640 503 -640 427 -640 449 -640 480 -640 480 -640 469 -500 389 -640 426 -500 375 -640 427 -426 640 -480 640 -640 383 -640 425 -565 640 -640 480 -640 559 -640 480 -460 640 -640 480 -640 480 -640 480 -480 640 -640 428 -640 480 -640 427 -500 248 -357 500 -640 480 -640 480 -333 500 -480 360 -500 333 -640 564 -640 426 -480 640 -640 480 -640 480 -640 427 -640 426 -640 480 -426 640 -640 427 -425 640 -640 438 -640 427 -640 480 -640 480 -640 480 -480 640 -438 640 -426 640 -640 426 -640 411 -640 363 -500 375 -640 400 -640 509 -500 489 -640 427 -640 480 -500 333 -640 360 -500 332 -640 480 -640 396 -640 426 -640 480 -640 427 -640 427 -640 480 -500 375 -640 361 -640 427 -612 612 -213 640 -640 427 -427 640 -640 480 -640 480 -640 427 -375 500 -375 500 -640 480 -485 640 -640 388 -640 480 -500 375 -480 640 -480 640 -640 427 -640 427 -500 333 -612 612 -640 480 -640 427 -500 400 -640 426 -640 419 -640 426 -359 640 -500 332 -640 426 -640 480 -640 429 -640 360 -640 427 -640 426 -426 640 -427 640 -640 480 -640 480 -335 500 -640 486 -480 640 -427 640 -480 640 -640 424 -640 480 -640 480 -640 480 -640 548 -425 640 -640 480 -500 375 -640 426 -640 426 -640 426 -480 640 -640 426 -375 500 -640 427 -640 462 -640 451 -640 480 -640 480 -640 425 -612 612 -640 427 -640 426 -427 640 -640 426 -640 427 -640 610 -640 480 -480 640 -640 426 -640 480 -640 426 -480 640 -640 427 -640 477 -640 480 -640 480 -500 338 -640 458 -640 480 -640 359 -120 160 -640 481 -500 375 -426 640 -427 640 -500 400 -500 335 -640 427 -500 334 -640 425 -640 480 -640 480 -500 375 -640 480 -640 424 -400 500 -375 500 -480 640 -515 640 -480 640 -480 640 -640 480 -640 480 -640 480 -640 480 -640 480 -375 500 -480 640 -640 479 -200 189 -457 640 -640 480 -640 439 -500 322 -500 375 -480 640 -640 480 -640 480 -640 480 -427 640 -640 427 -640 480 -427 640 -500 324 -640 480 -640 480 -434 640 -640 265 -640 480 -640 425 -427 640 -640 427 -640 480 -640 480 -640 573 -640 480 -375 500 -640 428 -500 375 -640 480 -640 427 -473 640 -640 428 -480 640 -640 426 -640 306 -640 478 -640 427 -640 427 -427 640 -640 424 -512 640 -640 427 -579 640 -449 640 -427 640 -640 468 -640 480 -640 480 -640 425 -480 640 -640 480 -640 427 -640 640 -375 500 -640 428 -640 427 -640 480 -640 361 -640 480 -500 370 -640 428 -427 640 -640 480 -375 500 -640 480 -640 427 -640 478 -640 480 -640 427 -640 480 -640 425 -500 335 -640 493 -500 375 -640 426 -500 333 -640 480 -461 640 -500 375 -640 480 -640 480 -640 480 -640 480 -612 612 -640 480 -640 424 -640 427 -640 480 -500 375 -640 324 -640 429 -427 640 -528 363 -500 333 -640 512 -480 640 -640 480 -500 375 -640 480 -480 640 -640 480 -480 640 -640 480 -640 427 -640 450 -640 424 -640 480 -482 640 -640 480 -480 640 -640 427 -338 450 -640 425 -640 544 -640 427 -640 428 -640 480 -640 478 -500 375 -640 480 -640 427 -640 480 -640 480 -500 375 -480 640 -640 428 -640 479 -480 640 -375 500 -500 388 -480 640 -640 480 -640 427 -640 360 -640 480 -640 424 -640 396 -640 427 -120 160 -640 457 -640 480 -458 640 -640 425 -640 480 -640 480 -640 360 -640 480 -480 640 -480 640 -640 434 -640 480 -480 640 -640 429 -640 427 -464 500 -640 543 -640 428 -640 411 -640 427 -640 360 -640 528 -640 443 -640 480 -640 480 -640 424 -640 410 -500 333 -512 640 -500 346 -640 480 -640 480 -428 640 -640 429 -640 427 -640 480 -640 439 -500 375 -640 426 -640 480 -640 480 -640 427 -500 423 -640 427 -640 427 -640 424 -640 480 -640 360 -500 333 -640 480 -640 427 -640 384 -425 640 -640 480 -640 480 -640 481 -640 426 -426 640 -480 640 -427 640 -640 427 -478 640 -640 341 -640 395 -640 480 -500 333 -640 427 -500 436 -640 360 -480 640 -500 428 -640 427 -640 560 -640 427 -640 480 -640 481 -640 427 -640 481 -612 612 -427 640 -640 480 -640 394 -640 360 -640 427 -427 640 -640 480 -360 640 -375 500 -640 429 -640 426 -640 480 -640 360 -480 640 -640 383 -640 427 -640 480 -427 640 -640 427 -480 640 -640 480 -480 640 -425 640 -640 480 -612 612 -640 453 -640 425 -426 640 -640 480 -640 480 -640 361 -640 427 -640 480 -640 480 -428 640 -640 480 -640 640 -425 640 -640 428 -640 478 -640 426 -500 333 -500 488 -640 285 -500 326 -640 360 -640 480 -640 428 -640 480 -428 640 -640 524 -640 488 -640 480 -612 612 -450 338 -640 428 -640 426 -526 640 -640 428 -483 640 -640 480 -640 426 -640 427 -640 480 -640 480 -640 480 -640 427 -640 480 -640 480 -640 427 -640 427 -640 571 -640 427 -640 480 -640 427 -640 480 -640 425 -375 500 -640 428 -609 407 -333 500 -640 427 -500 333 -640 640 -433 640 -640 480 -640 392 -640 360 -640 480 -427 640 -480 268 -640 480 -500 281 -600 450 -500 393 -640 480 -478 640 -640 426 -640 413 -640 480 -640 427 -640 425 -640 480 -640 480 -640 427 -443 640 -640 480 -424 640 -640 427 -640 426 -640 632 -640 397 -500 375 -640 426 -640 480 -640 480 -640 428 -500 332 -640 427 -640 427 -640 480 -640 399 -414 640 -612 612 -640 424 -433 640 -640 418 -428 640 -480 640 -426 640 -375 500 -480 640 -640 426 -334 500 -640 480 -481 640 -640 500 -320 240 -640 427 -500 333 -500 333 -427 640 -640 480 -640 480 -640 427 -336 500 -480 640 -640 480 -640 425 -640 480 -500 375 -640 427 -457 640 -640 441 -640 427 -640 481 -640 426 -640 480 -640 427 -612 612 -478 640 -640 427 -500 333 -640 480 -640 428 -640 428 -640 460 -640 480 -500 333 -480 640 -640 633 -640 640 -457 640 -480 640 -500 466 -500 375 -640 425 -500 375 -500 375 -427 640 -640 512 -500 333 -640 427 -640 428 -640 480 -640 426 -640 480 -426 640 -640 427 -640 426 -640 427 -500 282 -640 428 -425 640 -479 640 -640 427 -427 640 -424 640 -448 640 -640 480 -640 480 -640 430 -344 500 -500 375 -640 330 -640 427 -640 445 -640 480 -481 640 -640 480 -640 426 -640 427 -640 427 -640 431 -640 427 -640 425 -640 425 -640 480 -640 493 -500 375 -575 640 -640 480 -640 426 -640 426 -640 428 -640 480 -640 401 -480 640 -640 480 -640 640 -612 612 -427 640 -640 489 -446 640 -480 640 -640 480 -427 640 -640 427 -428 640 -640 478 -379 500 -640 428 -640 429 -640 475 -640 428 -375 500 -490 500 -640 480 -640 426 -425 640 -480 640 -426 640 -595 640 -640 480 -640 480 -500 333 -640 480 -640 424 -640 480 -640 478 -480 640 -640 480 -640 480 -640 428 -640 419 -640 480 -640 468 -640 480 -640 428 -640 427 -480 640 -640 480 -640 478 -640 426 -640 425 -640 640 -480 640 -640 480 -640 427 -424 640 -640 427 -640 472 -640 480 -640 426 -640 480 -480 640 -640 640 -480 640 -425 640 -640 480 -640 431 -640 428 -640 439 -425 640 -480 640 -640 480 -640 601 -640 428 -612 612 -640 480 -640 425 -640 480 -640 424 -508 640 -640 426 -640 499 -640 480 -640 480 -640 480 -640 334 -612 612 -427 640 -640 427 -640 426 -444 640 -640 428 -640 428 -500 342 -640 356 -640 427 -640 480 -640 480 -640 427 -640 480 -612 612 -375 500 -640 480 -640 480 -450 640 -640 427 -640 277 -640 480 -640 620 -426 640 -480 640 -640 480 -541 640 -500 361 -640 480 -640 427 -425 640 -640 427 -332 500 -640 244 -640 480 -640 480 -640 426 -480 640 -640 362 -640 424 -489 640 -640 452 -640 513 -640 512 -640 427 -640 480 -640 480 -640 429 -640 427 -640 427 -640 424 -640 427 -479 640 -640 480 -640 480 -500 375 -612 612 -480 640 -480 640 -640 480 -500 325 -640 480 -640 427 -640 425 -425 640 -640 480 -612 612 -640 425 -640 432 -640 427 -640 427 -479 640 -428 640 -500 334 -640 480 -640 480 -427 640 -480 640 -640 427 -426 640 -640 428 -640 430 -500 375 -640 480 -640 480 -640 427 -612 612 -229 123 -640 426 -500 380 -640 480 -640 360 -481 640 -640 451 -457 640 -640 480 -375 500 -500 334 -640 428 -500 375 -640 430 -640 480 -640 427 -640 480 -640 634 -612 612 -480 640 -426 640 -500 333 -640 480 -640 480 -640 426 -640 480 -500 375 -480 640 -375 500 -640 480 -480 640 -640 458 -640 426 -424 640 -426 640 -640 424 -612 612 -640 427 -640 424 -640 427 -497 640 -640 427 -640 480 -640 446 -640 443 -640 427 -640 640 -500 333 -640 360 -640 426 -333 500 -640 426 -640 427 -612 612 -500 375 -612 612 -640 427 -480 640 -500 333 -640 480 -640 480 -640 421 -640 480 -640 480 -640 480 -500 375 -640 427 -500 375 -640 350 -611 640 -478 640 -332 500 -500 316 -640 480 -640 510 -640 427 -640 480 -640 427 -640 486 -340 470 -480 640 -480 640 -427 640 -640 426 -640 590 -640 480 -640 480 -640 428 -640 427 -500 375 -427 640 -640 458 -640 583 -500 375 -640 480 -500 375 -640 400 -640 425 -640 480 -500 333 -640 408 -640 427 -427 640 -339 500 -275 183 -375 500 -640 478 -640 478 -425 640 -384 640 -640 478 -640 425 -500 345 -640 427 -640 427 -480 640 -500 375 -640 428 -640 418 -640 480 -640 480 -426 640 -640 480 -426 640 -640 640 -391 640 -500 375 -640 480 -640 424 -640 478 -519 640 -551 640 -500 375 -640 480 -612 612 -640 426 -480 640 -500 334 -640 480 -640 640 -402 500 -640 480 -612 612 -500 333 -500 286 -432 640 -640 362 -640 480 -640 480 -640 427 -640 428 -640 426 -640 427 -500 332 -640 428 -426 640 -612 612 -333 500 -640 427 -640 640 -640 480 -640 480 -500 375 -640 457 -500 334 -640 427 -500 500 -640 424 -480 640 -480 640 -640 358 -640 480 -640 480 -500 375 -640 480 -500 447 -311 500 -480 640 -640 359 -640 480 -640 228 -640 480 -640 469 -640 480 -500 375 -427 640 -640 360 -640 427 -640 475 -640 480 -640 480 -640 481 -500 375 -640 440 -640 640 -500 375 -428 640 -640 427 -640 480 -640 425 -640 500 -640 427 -640 427 -640 446 -500 375 -640 480 -424 640 -640 480 -500 353 -640 360 -640 433 -424 640 -640 427 -480 640 -640 480 -596 640 -480 640 -640 480 -640 480 -640 427 -640 480 -478 640 -640 360 -640 457 -640 429 -285 340 -640 426 -640 440 -446 640 -640 480 -640 480 -640 426 -480 640 -640 640 -640 480 -640 427 -640 480 -480 640 -640 428 -375 500 -640 480 -640 423 -500 375 -640 480 -640 478 -476 640 -640 480 -640 640 -640 443 -480 640 -640 513 -640 480 -500 325 -640 480 -358 640 -423 640 -640 360 -640 395 -599 640 -640 425 -640 480 -640 607 -640 480 -640 480 -480 640 -427 640 -634 640 -640 480 -500 400 -640 425 -640 428 -640 480 -640 480 -640 480 -640 425 -640 383 -640 360 -640 480 -640 480 -640 425 -640 480 -600 376 -640 427 -480 640 -640 424 -612 612 -640 426 -640 425 -640 480 -480 640 -640 425 -500 408 -640 424 -500 284 -640 481 -640 427 -640 428 -640 478 -640 480 -640 480 -640 427 -480 640 -427 640 -640 480 -428 640 -500 283 -640 441 -640 426 -640 418 -640 427 -480 640 -640 426 -640 426 -640 480 -640 442 -640 427 -640 426 -640 419 -640 480 -640 478 -640 476 -640 427 -640 426 -399 640 -640 361 -640 426 -640 427 -427 640 -640 459 -640 480 -640 360 -333 500 -428 640 -640 480 -640 441 -428 640 -480 640 -640 480 -427 640 -640 480 -640 426 -333 500 -640 480 -640 526 -640 480 -486 640 -423 640 -640 361 -427 640 -640 480 -640 480 -640 425 -640 428 -640 428 -640 480 -640 427 -480 640 -379 279 -480 640 -640 506 -640 480 -640 513 -640 458 -333 500 -640 429 -640 360 -640 427 -500 375 -640 480 -500 332 -612 612 -640 480 -640 476 -640 374 -500 394 -640 480 -427 640 -640 427 -640 425 -430 640 -425 640 -640 410 -429 640 -640 424 -480 640 -640 427 -640 425 -640 640 -640 360 -640 427 -640 490 -500 375 -333 500 -640 517 -640 480 -640 427 -500 350 -400 500 -640 480 -500 338 -640 433 -640 388 -426 640 -640 348 -640 480 -640 492 -640 481 -640 318 -640 427 -427 640 -640 425 -640 480 -640 513 -500 332 -480 640 -640 640 -640 480 -640 444 -640 616 -640 480 -500 333 -500 408 -500 411 -640 480 -640 360 -480 640 -640 427 -640 433 -640 427 -640 426 -479 640 -480 640 -480 640 -426 640 -640 430 -640 427 -480 640 -640 426 -640 369 -640 480 -375 500 -640 480 -640 425 -504 640 -640 480 -640 480 -640 426 -640 430 -640 480 -500 400 -640 427 -640 480 -640 427 -640 489 -640 360 -427 640 -640 480 -640 480 -640 480 -350 219 -640 480 -640 413 -640 480 -640 401 -425 640 -640 425 -640 480 -640 427 -640 414 -640 424 -640 480 -425 640 -640 285 -640 480 -640 322 -640 427 -640 427 -640 427 -640 428 -640 457 -640 480 -500 391 -640 404 -640 611 -640 390 -513 640 -640 360 -640 496 -640 480 -640 427 -640 427 -640 480 -500 234 -640 425 -640 360 -424 640 -640 512 -640 427 -640 426 -640 427 -640 480 -500 374 -640 428 -640 526 -640 428 -640 480 -426 640 -640 427 -611 640 -640 383 -640 457 -640 427 -640 382 -640 427 -640 426 -640 480 -640 477 -375 500 -478 640 -640 480 -640 480 -500 400 -640 461 -640 480 -640 417 -640 425 -427 640 -640 439 -480 640 -640 640 -427 640 -612 612 -464 640 -640 427 -480 640 -640 360 -640 480 -640 428 -640 425 -640 543 -640 426 -640 423 -640 426 -640 319 -500 375 -640 427 -432 500 -375 500 -640 441 -426 640 -640 406 -640 426 -640 480 -480 640 -640 480 -640 424 -640 428 -640 427 -640 461 -426 640 -500 375 -640 480 -640 428 -640 480 -500 375 -640 426 -640 640 -480 640 -640 427 -375 500 -500 333 -640 480 -375 500 -480 640 -500 334 -640 480 -640 427 -640 424 -640 426 -640 628 -640 491 -640 426 -640 427 -480 640 -640 480 -640 425 -640 424 -640 427 -640 427 -640 480 -640 513 -640 426 -640 480 -640 427 -640 461 -640 425 -640 598 -640 361 -640 480 -640 427 -500 317 -640 480 -640 519 -640 480 -640 427 -500 375 -640 480 -425 640 -640 427 -426 640 -480 640 -480 640 -640 427 -640 427 -457 640 -640 359 -640 355 -640 480 -640 427 -426 640 -640 427 -427 640 -640 428 -640 426 -500 334 -425 640 -640 480 -640 480 -640 480 -500 334 -500 344 -640 640 -640 480 -640 480 -640 423 -640 480 -333 500 -640 426 -640 427 -500 375 -480 640 -640 508 -640 480 -500 375 -600 600 -640 480 -385 500 -434 640 -640 480 -480 640 -426 640 -640 427 -640 512 -512 640 -640 427 -427 640 -640 474 -640 426 -480 640 -640 426 -500 375 -427 640 -475 640 -640 360 -640 480 -640 427 -640 479 -375 500 -640 427 -640 457 -394 500 -640 422 -500 375 -640 480 -640 480 -427 640 -640 427 -640 498 -640 480 -480 640 -640 374 -640 480 -500 412 -500 335 -640 439 -640 516 -640 427 -640 426 -402 500 -500 364 -500 333 -640 480 -438 640 -425 640 -493 500 -480 640 -640 426 -640 640 -640 349 -640 480 -427 640 -640 480 -640 512 -400 400 -375 500 -640 427 -640 424 -500 375 -640 426 -640 429 -640 427 -640 426 -480 640 -500 375 -640 428 -640 480 -427 640 -640 428 -640 480 -640 427 -640 480 -500 372 -640 480 -640 480 -640 480 -640 360 -640 480 -640 480 -640 427 -640 426 -640 480 -640 640 -640 424 -640 480 -640 427 -640 169 -427 640 -640 478 -640 427 -462 308 -426 640 -640 361 -640 427 -500 232 -640 427 -640 457 -640 427 -500 375 -640 427 -640 426 -640 494 -427 640 -640 314 -640 480 -640 427 -473 640 -640 480 -640 480 -640 427 -640 369 -640 301 -640 427 -424 640 -640 481 -640 480 -640 427 -640 478 -640 480 -640 426 -640 427 -640 427 -640 480 -640 360 -480 640 -640 439 -640 480 -640 454 -640 401 -640 458 -640 480 -640 480 -640 414 -640 480 -640 496 -640 424 -640 480 -640 480 -387 500 -640 480 -640 379 -640 457 -425 640 -640 426 -640 424 -120 120 -640 427 -640 597 -640 480 -640 458 -640 426 -640 427 -640 427 -480 640 -640 426 -500 333 -640 427 -640 380 -427 640 -500 333 -480 640 -640 428 -640 428 -640 360 -640 429 -500 387 -371 500 -425 640 -640 480 -640 479 -640 480 -640 480 -640 427 -640 480 -640 478 -457 640 -640 429 -359 640 -500 375 -640 425 -500 375 -640 427 -359 240 -426 640 -612 612 -640 480 -612 612 -640 427 -640 478 -375 500 -480 640 -640 426 -479 640 -640 429 -640 384 -640 434 -500 332 -640 489 -640 427 -426 640 -640 466 -412 640 -478 640 -319 500 -640 427 -612 612 -640 418 -640 427 -640 426 -333 500 -500 375 -640 280 -612 612 -640 639 -640 480 -640 360 -640 456 -640 427 -426 640 -640 428 -501 640 -426 640 -640 428 -640 480 -640 478 -500 375 -640 360 -375 500 -640 388 -357 500 -640 480 -480 640 -496 640 -640 427 -612 612 -480 640 -508 337 -480 640 -640 368 -640 420 -300 500 -640 427 -612 612 -640 480 -500 375 -500 375 -412 317 -640 427 -640 425 -640 428 -480 640 -640 429 -380 640 -500 375 -640 425 -480 640 -640 480 -640 423 -640 480 -333 500 -411 640 -426 640 -436 640 -640 501 -640 427 -500 375 -640 512 -640 480 -640 506 -640 426 -640 427 -589 640 -480 640 -640 426 -500 375 -640 427 -640 426 -428 640 -640 480 -640 474 -500 333 -640 480 -480 640 -640 398 -640 425 -640 454 -640 480 -479 640 -640 427 -640 425 -612 612 -640 480 -500 375 -640 421 -640 514 -612 612 -640 480 -640 425 -500 468 -640 427 -480 640 -640 480 -640 480 -640 339 -424 640 -290 595 -480 640 -640 427 -480 640 -640 427 -500 332 -426 640 -640 425 -500 282 -480 640 -500 375 -640 514 -640 480 -640 426 -640 480 -640 480 -375 500 -640 427 -640 480 -640 426 -640 427 -500 375 -511 640 -640 427 -427 640 -640 480 -640 480 -446 552 -640 427 -640 426 -640 427 -640 427 -500 375 -640 480 -357 500 -640 479 -480 640 -640 428 -640 480 -480 640 -640 480 -640 480 -640 467 -640 480 -640 480 -640 426 -500 375 -513 640 -640 480 -640 480 -375 500 -640 427 -640 448 -640 480 -640 480 -480 640 -640 480 -640 427 -640 457 -640 425 -427 640 -480 640 -640 425 -640 427 -640 480 -640 640 -640 400 -612 612 -640 428 -425 640 -500 332 -640 426 -640 480 -640 480 -640 535 -640 427 -500 375 -640 480 -640 480 -480 640 -640 480 -640 480 -640 427 -425 640 -480 640 -640 480 -640 516 -640 427 -640 480 -640 418 -501 640 -640 480 -375 500 -640 424 -375 500 -480 640 -640 412 -640 426 -640 480 -640 467 -640 640 -640 480 -640 428 -640 480 -375 500 -640 431 -425 640 -478 640 -640 483 -640 480 -640 480 -640 360 -640 480 -427 640 -640 480 -500 375 -640 426 -500 334 -640 400 -334 500 -640 427 -640 428 -640 480 -640 427 -500 375 -640 480 -640 426 -640 480 -500 373 -401 500 -427 640 -640 458 -640 427 -640 427 -640 428 -640 427 -640 427 -612 612 -640 480 -500 176 -640 480 -480 640 -640 480 -565 425 -640 427 -640 480 -640 427 -386 640 -500 375 -500 375 -640 579 -640 457 -640 640 -640 442 -612 612 -640 480 -480 640 -640 480 -640 425 -640 427 -500 334 -427 640 -640 427 -480 640 -640 427 -640 480 -500 375 -640 480 -640 480 -640 362 -500 188 -640 480 -375 500 -640 480 -640 480 -640 427 -640 505 -640 480 -640 426 -427 640 -640 426 -640 480 -500 375 -640 427 -640 640 -640 424 -640 480 -640 480 -612 612 -640 427 -332 500 -640 437 -640 427 -640 427 -640 360 -480 640 -500 375 -640 427 -640 569 -640 440 -640 427 -500 375 -640 391 -640 426 -640 388 -640 427 -640 480 -640 428 -640 533 -640 426 -640 411 -640 480 -640 478 -640 425 -640 427 -480 640 -640 480 -426 640 -640 427 -640 425 -375 500 -640 567 -640 424 -640 335 -500 368 -640 480 -500 365 -640 373 -640 480 -500 375 -401 479 -427 640 -500 375 -640 428 -640 480 -640 480 -640 480 -500 500 -640 383 -640 427 -640 425 -640 480 -640 480 -640 480 -640 376 -480 640 -640 359 -640 427 -640 506 -640 513 -480 640 -640 427 -640 480 -640 428 -480 640 -640 573 -500 244 -640 480 -640 484 -640 480 -640 428 -640 478 -640 386 -426 640 -640 480 -640 480 -640 427 -499 640 -640 480 -640 480 -640 480 -468 640 -640 426 -640 426 -427 640 -428 640 -640 476 -640 480 -640 481 -640 353 -640 409 -640 640 -640 426 -640 431 -640 480 -640 453 -640 427 -640 480 -640 480 -480 640 -640 486 -640 427 -640 341 -640 396 -640 427 -427 640 -427 640 -640 427 -424 640 -500 333 -640 480 -640 426 -640 570 -470 640 -500 261 -640 394 -640 478 -640 427 -640 427 -640 427 -640 428 -480 640 -640 426 -640 480 -640 425 -375 500 -640 533 -640 480 -426 640 -626 640 -500 333 -375 500 -640 427 -640 480 -640 427 -640 427 -640 453 -375 500 -480 640 -640 427 -635 640 -427 640 -640 480 -640 392 -640 640 -427 640 -500 375 -640 427 -640 480 -640 426 -640 425 -640 640 -640 480 -640 480 -480 640 -375 500 -500 344 -612 612 -640 428 -640 480 -640 443 -640 427 -640 480 -427 640 -427 640 -640 480 -427 640 -428 640 -640 360 -640 411 -500 374 -640 489 -612 612 -640 480 -640 427 -640 480 -640 480 -640 478 -480 640 -640 424 -640 499 -640 366 -640 480 -640 426 -640 427 -419 640 -640 480 -640 480 -640 427 -480 640 -500 333 -640 262 -640 507 -640 480 -478 640 -500 357 -640 480 -480 640 -640 480 -500 359 -615 459 -426 640 -612 612 -640 427 -640 480 -640 425 -640 480 -640 440 -640 426 -427 640 -640 480 -640 640 -500 375 -640 427 -332 500 -640 360 -640 465 -640 538 -640 480 -640 426 -640 480 -640 480 -500 333 -640 466 -375 500 -480 640 -480 640 -443 640 -500 334 -640 480 -640 350 -640 427 -500 375 -539 640 -640 427 -640 480 -427 640 -640 427 -640 281 -476 640 -640 480 -640 480 -640 444 -640 480 -640 480 -640 427 -424 640 -640 427 -640 545 -425 640 -640 427 -640 480 -640 476 -640 360 -425 640 -640 299 -640 480 -640 480 -640 427 -429 640 -500 333 -427 640 -640 458 -426 640 -640 480 -640 480 -427 640 -427 640 -640 480 -640 479 -444 640 -640 427 -640 427 -480 640 -640 373 -640 640 -640 427 -640 506 -640 424 -640 480 -500 378 -640 480 -640 426 -480 640 -428 640 -425 640 -640 480 -640 480 -640 438 -500 375 -419 640 -640 473 -640 480 -640 426 -640 334 -640 385 -427 640 -640 337 -640 640 -640 426 -358 640 -640 427 -640 411 -480 640 -640 480 -640 425 -640 427 -640 480 -640 289 -640 454 -640 512 -640 427 -640 342 -640 429 -640 640 -640 480 -640 480 -640 427 -640 480 -640 480 -640 425 -640 480 -500 333 -500 406 -427 640 -375 500 -427 640 -640 480 -640 427 -640 478 -640 426 -640 427 -640 425 -428 640 -500 375 -640 428 -640 480 -327 500 -480 640 -640 426 -640 428 -640 426 -640 480 -640 480 -431 640 -531 640 -480 640 -480 640 -640 424 -640 402 -640 427 -640 480 -640 400 -640 480 -640 426 -427 640 -640 426 -640 449 -640 427 -500 333 -375 500 -500 375 -639 640 -480 640 -640 480 -640 499 -640 480 -476 640 -427 640 -640 480 -500 375 -640 426 -640 480 -640 427 -437 640 -640 427 -640 526 -640 428 -640 480 -640 425 -640 480 -640 427 -640 382 -640 427 -640 425 -478 640 -640 427 -640 488 -640 427 -640 360 -640 427 -640 478 -217 289 -640 480 -640 427 -640 425 -640 480 -640 455 -640 480 -640 480 -375 500 -440 640 -640 292 -512 640 -409 640 -640 480 -500 333 -640 480 -640 480 -640 480 -640 428 -488 640 -640 427 -640 428 -640 424 -418 640 -640 509 -427 640 -333 500 -480 640 -640 376 -612 612 -427 640 -426 640 -640 424 -640 480 -640 480 -640 427 -426 640 -447 640 -640 480 -480 640 -500 281 -429 640 -480 640 -640 480 -640 427 -640 427 -480 640 -640 480 -640 480 -500 333 -500 375 -640 478 -427 640 -640 471 -640 640 -427 640 -640 427 -640 478 -640 480 -640 430 -640 426 -640 395 -480 640 -640 425 -294 196 -640 427 -640 480 -500 263 -500 319 -640 480 -640 428 -640 602 -640 426 -425 640 -500 375 -500 400 -480 640 -465 640 -640 428 -427 640 -333 500 -640 480 -640 480 -640 426 -640 498 -480 640 -640 480 -640 480 -640 480 -640 480 -425 640 -640 480 -640 425 -426 640 -612 612 -640 476 -500 375 -480 640 -640 427 -427 640 -640 480 -640 480 -640 480 -428 640 -480 640 -640 426 -640 480 -640 480 -434 640 -480 640 -640 394 -640 478 -480 640 -500 375 -425 640 -640 480 -640 480 -479 640 -500 400 -480 640 -640 480 -612 612 -640 360 -375 500 -480 640 -640 480 -640 427 -427 640 -500 375 -375 500 -426 640 -640 480 -500 375 -640 480 -640 427 -480 640 -300 196 -193 272 -500 333 -500 375 -332 640 -640 480 -640 400 -425 640 -640 427 -500 333 -417 500 -640 415 -640 480 -166 221 -640 426 -640 427 -640 480 -480 640 -640 480 -424 640 -500 366 -640 427 -500 334 -425 640 -640 480 -500 375 -640 427 -640 480 -640 427 -640 425 -640 534 -387 640 -457 640 -480 640 -640 640 -640 426 -640 446 -640 393 -640 453 -640 433 -640 480 -500 357 -500 430 -640 428 -640 427 -427 640 -640 382 -640 408 -640 512 -640 480 -375 500 -640 429 -640 480 -640 480 -480 640 -640 427 -640 480 -640 458 -427 640 -500 375 -500 375 -640 427 -640 480 -594 640 -640 480 -480 640 -640 471 -640 480 -640 427 -640 361 -640 427 -640 427 -640 640 -480 640 -640 480 -640 480 -500 327 -640 427 -640 483 -375 500 -500 323 -640 480 -640 428 -353 378 -640 480 -640 480 -427 640 -640 480 -640 427 -410 500 -480 640 -640 480 -640 428 -640 429 -640 427 -640 478 -612 612 -640 427 -640 463 -640 480 -640 480 -640 427 -428 640 -640 480 -480 640 -640 421 -640 480 -640 427 -480 640 -500 400 -640 481 -640 548 -480 640 -375 500 -612 612 -640 427 -500 333 -640 427 -640 478 -500 375 -640 480 -640 360 -500 375 -640 430 -500 344 -500 375 -427 640 -640 428 -500 337 -640 360 -427 640 -640 424 -500 375 -640 480 -640 433 -500 327 -427 640 -480 640 -480 640 -640 480 -640 220 -640 486 -640 428 -640 480 -365 640 -427 640 -480 640 -640 480 -640 512 -480 640 -424 640 -640 480 -500 375 -500 375 -640 433 -640 426 -640 425 -480 640 -640 480 -640 453 -640 480 -640 638 -426 640 -375 500 -640 426 -640 360 -640 424 -640 480 -624 640 -640 480 -427 640 -335 500 -427 640 -640 480 -640 424 -378 500 -640 350 -449 640 -427 640 -640 426 -426 640 -427 640 -640 637 -375 500 -502 640 -640 426 -640 376 -425 640 -424 640 -640 480 -612 612 -640 427 -500 333 -640 480 -480 640 -640 480 -613 640 -375 500 -640 480 -640 428 -640 426 -640 480 -640 466 -640 435 -640 309 -640 425 -640 425 -640 428 -500 335 -427 640 -480 640 -466 640 -480 640 -640 480 -428 640 -640 434 -640 434 -640 426 -375 500 -480 640 -640 428 -640 480 -640 427 -640 480 -640 426 -640 463 -426 640 -640 441 -640 480 -427 640 -500 394 -482 640 -640 466 -426 640 -532 640 -640 428 -480 640 -640 426 -640 412 -500 375 -500 375 -640 426 -386 640 -640 480 -640 480 -640 426 -640 426 -640 480 -500 352 -640 640 -640 480 -480 640 -640 425 -640 640 -640 427 -640 433 -427 640 -427 640 -640 480 -640 480 -500 375 -500 375 -640 428 -500 345 -426 640 -640 480 -640 480 -640 427 -640 419 -640 480 -640 425 -500 375 -640 480 -640 480 -482 640 -640 427 -640 424 -640 470 -500 333 -640 427 -640 430 -640 480 -640 480 -640 480 -640 425 -640 424 -556 640 -640 479 -640 480 -640 427 -640 480 -500 375 -640 480 -640 429 -378 640 -640 426 -480 640 -612 612 -333 500 -640 411 -640 353 -612 612 -640 480 -640 425 -640 366 -480 640 -640 427 -640 480 -640 480 -427 640 -640 428 -457 640 -640 480 -640 424 -478 640 -640 480 -640 480 -640 425 -640 424 -640 479 -640 480 -640 360 -640 640 -421 640 -427 640 -640 481 -640 480 -427 640 -427 640 -640 480 -640 427 -640 427 -640 428 -500 375 -640 428 -640 480 -612 612 -500 375 -427 640 -500 375 -640 480 -640 427 -640 480 -480 640 -640 432 -640 427 -640 425 -640 480 -427 640 -640 361 -640 427 -640 425 -480 640 -478 640 -640 425 -480 640 -427 640 -427 640 -640 427 -487 640 -427 640 -480 640 -640 525 -428 500 -640 439 -500 375 -375 500 -458 640 -640 480 -640 423 -640 480 -640 480 -640 593 -640 480 -640 618 -640 392 -600 410 -640 427 -500 281 -640 480 -640 490 -640 480 -333 500 -640 640 -360 640 -427 640 -428 640 -401 600 -640 396 -640 480 -480 640 -640 480 -640 453 -640 438 -500 397 -517 640 -640 426 -640 426 -640 631 -480 640 -480 640 -640 480 -640 454 -480 640 -480 640 -512 640 -640 427 -640 480 -500 375 -588 640 -640 480 -640 480 -640 427 -640 480 -640 640 -411 640 -480 640 -640 480 -640 425 -426 640 -640 428 -612 612 -640 427 -426 640 -427 640 -640 428 -640 426 -640 425 -640 425 -500 381 -640 480 -640 392 -543 640 -480 640 -480 640 -550 245 -640 480 -640 480 -640 478 -334 640 -640 376 -640 427 -640 430 -500 326 -640 426 -500 375 -333 500 -527 640 -364 640 -640 480 -640 433 -640 427 -457 640 -640 480 -640 480 -640 506 -640 523 -640 425 -640 480 -640 480 -640 391 -640 221 -427 640 -355 500 -640 433 -640 480 -640 425 -640 377 -640 480 -640 425 -640 425 -640 427 -427 640 -640 427 -640 402 -640 457 -500 375 -640 426 -640 518 -640 640 -640 383 -640 427 -427 640 -500 375 -640 480 -428 640 -428 640 -640 480 -357 500 -640 480 -500 375 -640 515 -640 480 -640 360 -640 480 -500 333 -640 480 -240 360 -640 480 -640 443 -640 504 -640 480 -640 480 -465 640 -421 640 -640 480 -640 480 -640 480 -471 640 -640 480 -640 431 -640 425 -500 319 -640 411 -500 375 -640 426 -640 469 -640 427 -640 480 -640 480 -640 426 -500 333 -640 480 -640 366 -500 375 -640 480 -640 383 -640 480 -250 167 -640 427 -640 480 -640 424 -480 640 -500 375 -640 480 -640 480 -640 426 -640 427 -640 427 -640 404 -640 426 -427 640 -426 640 -640 359 -500 375 -640 429 -640 427 -640 480 -640 480 -328 500 -640 405 -478 640 -640 427 -500 333 -640 554 -449 640 -640 426 -640 480 -640 425 -640 480 -640 427 -640 426 -612 612 -640 320 -428 640 -462 640 -640 349 -640 427 -640 426 -640 427 -640 427 -359 640 -640 481 -640 429 -640 427 -427 640 -640 480 -640 359 -640 432 -640 427 -427 640 -640 426 -480 480 -640 426 -549 640 -640 427 -640 546 -640 489 -640 426 -500 335 -421 640 -640 427 -640 478 -640 425 -640 361 -640 639 -640 360 -423 640 -640 425 -612 612 -478 640 -640 426 -480 640 -640 426 -640 331 -480 640 -481 640 -640 480 -427 640 -591 640 -640 480 -640 427 -640 426 -640 478 -449 640 -640 480 -480 640 -640 480 -640 427 -640 480 -500 375 -500 400 -463 640 -427 640 -427 640 -640 434 -640 431 -333 500 -640 427 -640 425 -426 640 -429 640 -640 427 -375 500 -640 480 -500 375 -375 500 -640 425 -640 425 -500 335 -640 426 -612 612 -640 425 -640 480 -640 219 -640 427 -640 428 -640 427 -426 640 -640 480 -640 427 -640 427 -640 454 -612 612 -640 480 -480 640 -640 425 -640 480 -500 375 -640 427 -640 426 -640 383 -640 480 -500 375 -640 427 -500 269 -640 480 -452 500 -428 640 -640 427 -427 640 -640 480 -430 640 -640 480 -640 427 -640 471 -640 634 -500 375 -373 500 -640 480 -427 640 -640 427 -424 640 -640 480 -425 640 -640 425 -424 640 -640 360 -500 334 -635 640 -640 428 -500 375 -640 426 -640 436 -500 375 -640 360 -640 480 -640 427 -640 480 -427 640 -378 640 -640 594 -640 480 -640 433 -480 640 -427 640 -640 640 -640 480 -640 480 -501 640 -640 320 -640 480 -640 426 -640 406 -640 480 -640 640 -502 640 -375 500 -640 480 -640 427 -375 500 -640 427 -480 640 -640 453 -408 640 -640 423 -500 375 -640 427 -480 640 -640 423 -375 500 -640 480 -425 640 -640 480 -640 480 -640 480 -640 416 -640 426 -640 427 -640 480 -640 428 -640 427 -640 444 -640 480 -640 428 -426 640 -640 426 -480 640 -480 640 -640 455 -640 400 -480 640 -425 640 -478 640 -640 640 -427 640 -640 468 -500 500 -500 375 -640 480 -640 480 -640 480 -640 427 -640 480 -640 426 -500 500 -640 480 -500 334 -640 426 -640 427 -640 480 -640 427 -640 480 -426 640 -640 301 -640 428 -640 427 -500 222 -480 640 -427 640 -500 335 -360 270 -640 452 -640 361 -640 480 -480 640 -640 429 -640 434 -640 463 -640 427 -428 640 -640 427 -426 640 -640 472 -640 480 -640 438 -640 443 -612 612 -478 640 -426 640 -429 640 -640 425 -640 480 -640 480 -640 640 -426 640 -640 427 -640 424 -640 424 -640 424 -612 612 -640 480 -480 640 -400 500 -480 640 -640 480 -640 480 -640 427 -640 597 -640 416 -640 480 -640 480 -480 640 -480 640 -640 424 -640 428 -640 425 -582 640 -484 640 -566 640 -640 427 -426 640 -427 640 -640 480 -640 468 -640 424 -427 640 -640 425 -480 640 -600 400 -640 480 -640 480 -640 453 -500 339 -480 640 -640 480 -500 403 -500 333 -640 480 -640 480 -640 480 -640 427 -640 510 -640 425 -640 480 -426 640 -640 640 -375 500 -424 640 -640 427 -640 480 -480 640 -429 640 -640 426 -480 640 -640 427 -640 426 -640 480 -640 441 -494 640 -640 360 -425 640 -640 415 -640 427 -640 480 -640 360 -427 640 -500 333 -500 375 -333 500 -640 480 -480 640 -640 506 -640 427 -640 440 -600 450 -612 612 -640 424 -640 425 -640 480 -640 490 -480 640 -640 427 -640 480 -640 480 -640 428 -640 427 -408 640 -640 480 -640 480 -640 480 -480 640 -480 640 -500 375 -640 369 -424 640 -640 406 -500 375 -640 360 -640 519 -640 360 -640 426 -640 480 -640 480 -640 480 -500 375 -640 432 -640 501 -480 640 -640 640 -640 417 -600 450 -640 428 -640 427 -428 640 -374 500 -640 478 -640 425 -640 480 -480 640 -500 418 -333 500 -640 429 -640 428 -596 640 -640 480 -640 480 -640 359 -480 640 -640 427 -640 446 -640 427 -640 480 -500 375 -640 548 -480 640 -640 426 -500 357 -640 480 -500 375 -612 612 -480 640 -640 429 -640 429 -480 640 -426 640 -334 500 -604 640 -640 425 -640 424 -640 457 -640 426 -640 480 -640 551 -392 640 -640 418 -427 640 -640 480 -640 359 -500 375 -640 427 -210 304 -640 426 -356 200 -640 480 -500 375 -480 640 -500 377 -320 240 -427 640 -640 425 -640 513 -500 375 -427 640 -640 499 -640 294 -640 427 -640 443 -640 519 -640 480 -640 361 -640 480 -640 554 -640 426 -640 507 -640 426 -640 427 -640 480 -640 426 -640 480 -640 412 -640 480 -504 336 -640 480 -427 640 -426 640 -640 360 -640 421 -640 428 -640 480 -640 424 -480 640 -640 480 -640 480 -640 426 -640 480 -640 425 -480 640 -640 426 -640 428 -640 524 -640 374 -640 427 -640 428 -427 640 -640 480 -640 427 -640 360 -640 480 -428 640 -480 640 -426 640 -500 375 -640 490 -640 484 -640 445 -640 480 -427 640 -640 425 -500 375 -640 428 -480 640 -640 347 -640 360 -425 640 -640 499 -640 480 -500 375 -640 478 -640 427 -500 375 -427 640 -424 640 -480 640 -640 428 -640 640 -500 335 -640 480 -640 640 -640 427 -640 539 -480 640 -640 427 -489 640 -500 333 -640 424 -427 640 -640 427 -640 427 -480 640 -640 424 -500 335 -640 640 -640 480 -640 480 -427 640 -640 480 -576 475 -640 513 -640 427 -640 513 -480 640 -481 640 -449 640 -640 428 -640 426 -640 480 -640 346 -640 448 -640 480 -640 406 -640 427 -640 427 -640 425 -640 480 -428 640 -640 480 -500 375 -640 470 -640 353 -640 427 -612 612 -640 511 -640 383 -640 640 -640 425 -482 640 -640 426 -480 640 -359 640 -640 427 -640 479 -500 375 -640 480 -640 427 -640 433 -480 640 -640 480 -495 640 -640 424 -640 480 -640 428 -640 415 -640 480 -612 612 -333 500 -640 480 -427 640 -493 640 -480 640 -640 569 -500 375 -640 427 -640 483 -640 473 -640 478 -640 427 -478 640 -640 426 -427 640 -640 427 -640 479 -481 640 -640 312 -480 640 -640 480 -640 426 -640 636 -480 640 -640 480 -480 640 -640 383 -640 428 -640 329 -640 406 -640 428 -378 500 -500 375 -640 371 -428 640 -427 640 -640 359 -640 427 -640 480 -640 424 -640 427 -640 480 -500 346 -640 480 -384 640 -480 640 -640 427 -443 640 -541 640 -640 640 -640 427 -640 480 -640 541 -537 640 -427 640 -640 426 -640 427 -640 480 -444 640 -480 640 -640 480 -480 640 -640 480 -640 480 -640 544 -500 343 -640 480 -640 480 -640 427 -640 640 -640 453 -640 316 -357 500 -496 640 -480 640 -640 421 -640 480 -640 424 -640 426 -640 427 -612 612 -640 427 -640 480 -500 475 -501 640 -612 612 -480 640 -640 480 -640 425 -480 640 -639 640 -640 329 -640 427 -640 480 -640 480 -640 480 -480 640 -640 514 -427 640 -640 480 -500 376 -500 375 -640 425 -640 427 -640 488 -640 428 -640 428 -640 428 -488 500 -640 424 -640 480 -480 640 -640 536 -640 458 -500 400 -640 451 -640 454 -640 640 -640 425 -640 428 -640 426 -640 478 -500 375 -427 640 -640 400 -640 427 -640 480 -480 640 -427 640 -612 612 -640 427 -640 427 -640 480 -612 612 -480 640 -640 427 -640 360 -640 480 -640 425 -610 431 -640 385 -640 426 -640 640 -640 427 -640 452 -640 426 -640 425 -640 425 -640 480 -329 500 -640 480 -500 375 -480 640 -640 428 -640 480 -640 426 -612 612 -640 480 -238 206 -640 427 -640 480 -640 427 -500 375 -640 473 -640 480 -640 480 -640 480 -500 334 -640 426 -427 640 -640 309 -640 428 -333 500 -640 427 -480 640 -462 640 -427 640 -640 426 -640 480 -640 427 -424 640 -640 480 -640 480 -640 425 -640 640 -640 425 -640 480 -429 640 -480 640 -640 426 -475 640 -427 640 -640 480 -500 343 -427 640 -500 335 -640 480 -640 491 -419 640 -640 426 -640 427 -427 640 -480 640 -640 450 -640 480 -500 375 -640 480 -640 427 -465 421 -640 427 -640 480 -500 333 -640 428 -448 500 -640 359 -640 545 -427 640 -640 426 -640 427 -333 500 -640 480 -382 500 -640 480 -640 428 -640 480 -640 418 -640 428 -427 640 -640 480 -500 333 -640 480 -640 480 -640 428 -500 375 -640 388 -640 429 -640 480 -640 427 -640 427 -640 480 -368 640 -500 375 -640 426 -640 413 -431 500 -640 480 -640 480 -375 500 -500 332 -640 480 -640 480 -480 640 -640 426 -640 481 -426 640 -640 427 -640 478 -640 427 -640 425 -640 530 -523 640 -640 426 -640 424 -640 480 -427 640 -640 474 -640 427 -640 425 -640 395 -640 480 -480 640 -640 464 -640 462 -640 480 -640 407 -640 426 -640 480 -640 425 -320 480 -480 640 -429 640 -578 640 -640 569 -640 426 -640 480 -500 333 -640 480 -640 480 -395 500 -640 479 -640 480 -500 370 -361 640 -532 640 -640 480 -500 312 -480 640 -640 640 -640 508 -640 425 -640 480 -427 640 -640 480 -640 480 -640 420 -427 640 -640 480 -375 500 -640 426 -640 427 -640 488 -500 332 -427 640 -640 429 -640 425 -375 500 -640 360 -640 427 -640 480 -500 375 -640 480 -480 640 -612 612 -640 424 -640 424 -640 478 -640 427 -640 480 -640 480 -640 425 -500 375 -640 427 -480 640 -640 426 -640 426 -640 434 -500 333 -400 266 -500 332 -640 428 -640 480 -640 480 -500 328 -640 427 -500 417 -480 640 -500 375 -427 640 -480 640 -480 640 -480 640 -640 426 -640 424 -640 480 -640 640 -375 500 -640 427 -427 640 -640 427 -480 640 -500 252 -458 640 -640 427 -640 480 -640 427 -640 478 -480 640 -426 640 -640 425 -478 640 -427 640 -333 500 -640 425 -427 640 -640 336 -640 427 -375 500 -640 405 -480 640 -640 427 -640 501 -640 456 -640 428 -640 480 -640 473 -333 500 -640 464 -640 428 -427 640 -500 386 -500 375 -612 612 -640 427 -640 464 -457 640 -640 427 -640 429 -640 386 -640 427 -640 441 -500 334 -500 375 -640 480 -640 427 -480 640 -500 332 -640 427 -640 480 -640 480 -640 391 -640 438 -640 484 -500 375 -480 640 -640 420 -500 400 -427 640 -640 503 -640 480 -640 427 -427 640 -640 480 -640 480 -640 427 -640 425 -640 426 -427 640 -640 360 -612 612 -640 425 -640 424 -640 391 -480 640 -640 480 -500 375 -640 480 -640 480 -612 612 -480 640 -334 500 -480 640 -640 480 -640 407 -640 480 -640 361 -640 480 -640 427 -640 563 -640 425 -640 480 -500 281 -640 543 -640 480 -640 428 -640 640 -640 480 -500 375 -640 433 -461 459 -640 363 -640 480 -423 640 -640 360 -640 480 -640 425 -640 480 -640 473 -640 426 -480 640 -640 425 -640 480 -640 429 -500 381 -500 328 -640 427 -426 640 -639 480 -640 436 -640 480 -640 505 -640 480 -374 640 -640 480 -640 427 -640 480 -640 480 -640 480 -640 480 -640 427 -427 640 -640 558 -640 478 -640 427 -640 427 -500 375 -640 480 -640 427 -375 500 -640 426 -640 427 -640 429 -640 432 -640 383 -500 317 -333 500 -640 160 -375 500 -425 640 -480 640 -640 480 -640 425 -640 471 -500 375 -640 427 -640 480 -640 430 -375 500 -640 480 -500 375 -640 480 -640 427 -640 480 -640 204 -640 478 -427 640 -427 640 -640 427 -640 427 -640 397 -288 197 -640 426 -640 427 -640 640 -640 427 -640 480 -427 640 -640 480 -640 480 -640 501 -640 478 -612 612 -640 427 -426 640 -500 375 -640 480 -640 426 -520 640 -640 427 -640 426 -640 480 -640 420 -427 640 -640 480 -640 427 -476 640 -640 427 -427 640 -640 478 -640 448 -500 333 -500 285 -640 427 -494 640 -640 362 -375 500 -600 450 -640 480 -640 417 -500 496 -330 640 -500 375 -500 375 -640 478 -640 480 -640 480 -640 360 -640 426 -640 428 -612 612 -427 640 -640 480 -640 366 -640 480 -640 480 -427 640 -640 480 -480 360 -640 427 -640 457 -640 360 -509 640 -640 480 -500 375 -640 427 -640 425 -640 640 -640 480 -640 529 -640 480 -640 427 -640 480 -640 425 -640 426 -640 426 -500 375 -526 640 -640 426 -335 500 -612 612 -640 454 -383 640 -640 361 -640 427 -474 640 -640 427 -640 428 -500 326 -640 480 -640 424 -640 513 -640 510 -500 375 -500 375 -480 640 -480 640 -640 606 -480 640 -480 640 -640 311 -640 494 -640 425 -427 640 -480 640 -640 428 -640 640 -600 400 -640 457 -640 480 -640 401 -640 421 -640 480 -640 480 -640 436 -500 375 -426 640 -640 429 -640 496 -500 337 -640 480 -342 500 -500 334 -640 428 -640 333 -640 480 -480 640 -408 500 -544 640 -640 480 -640 428 -640 427 -640 414 -640 504 -640 479 -500 375 -480 640 -433 500 -640 480 -640 480 -427 640 -640 480 -640 480 -640 480 -640 426 -536 640 -500 362 -500 375 -640 424 -640 480 -640 480 -640 480 -640 429 -427 640 -640 426 -640 480 -640 543 -640 360 -500 334 -640 360 -640 426 -500 375 -640 374 -500 375 -612 612 -640 426 -427 640 -427 640 -480 640 -640 480 -640 480 -640 480 -640 480 -640 480 -640 427 -423 640 -478 640 -427 640 -375 500 -640 478 -375 500 -500 332 -427 640 -427 640 -640 480 -473 640 -640 480 -640 429 -640 474 -640 480 -640 512 -500 375 -639 640 -561 640 -332 500 -480 640 -640 640 -442 640 -500 448 -640 480 -640 428 -640 480 -640 480 -640 427 -640 427 -640 480 -640 480 -640 424 -425 640 -640 436 -640 427 -640 480 -612 612 -333 500 -640 480 -612 612 -640 426 -459 322 -640 426 -640 427 -426 640 -640 480 -640 426 -640 480 -600 422 -640 480 -612 612 -640 480 -640 394 -640 360 -640 480 -640 427 -500 375 -640 478 -489 640 -640 481 -640 427 -640 337 -640 392 -640 508 -500 421 -480 640 -640 480 -640 344 -640 427 -426 640 -612 612 -640 479 -640 480 -640 557 -476 500 -640 429 -640 424 -640 480 -398 500 -640 425 -640 640 -612 612 -640 480 -640 424 -640 424 -426 640 -640 480 -640 426 -483 640 -640 453 -640 480 -500 251 -427 640 -640 427 -500 375 -640 480 -640 480 -640 424 -640 480 -427 640 -640 427 -640 480 -640 480 -640 480 -640 478 -640 640 -480 640 -506 640 -324 243 -612 612 -500 328 -640 427 -640 480 -428 640 -480 640 -640 480 -640 640 -500 375 -425 640 -640 480 -640 432 -426 640 -640 424 -640 480 -478 640 -640 360 -427 640 -640 480 -640 480 -512 640 -480 640 -481 640 -500 375 -500 333 -640 427 -595 640 -640 480 -480 640 -640 359 -640 480 -640 352 -640 480 -427 640 -640 427 -640 478 -426 640 -640 427 -640 426 -640 317 -428 640 -425 640 -251 480 -463 640 -640 419 -640 480 -640 398 -426 640 -640 480 -427 640 -640 480 -640 480 -480 640 -640 427 -640 427 -640 427 -640 480 -640 427 -333 500 -640 480 -640 480 -640 426 -640 427 -500 371 -500 376 -640 480 -480 640 -640 437 -480 640 -640 480 -426 640 -640 424 -640 359 -640 480 -640 427 -640 421 -640 427 -640 480 -640 514 -600 462 -375 500 -333 500 -500 375 -640 480 -480 640 -500 353 -640 512 -480 640 -640 510 -640 480 -640 428 -640 426 -640 480 -640 428 -480 640 -577 640 -427 640 -640 360 -595 438 -640 480 -427 640 -640 499 -333 500 -640 425 -640 480 -640 480 -612 612 -429 640 -640 480 -640 427 -640 394 -640 425 -640 480 -480 640 -640 480 -640 413 -615 640 -640 427 -640 480 -640 436 -640 427 -427 640 -640 360 -480 640 -640 428 -640 362 -640 480 -640 480 -293 450 -640 428 -640 480 -640 457 -480 640 -640 424 -478 640 -640 480 -480 640 -500 391 -424 640 -640 427 -500 374 -640 480 -500 395 -500 375 -640 427 -640 412 -640 427 -640 427 -640 427 -500 333 -640 427 -640 427 -640 427 -612 612 -480 640 -640 480 -640 480 -640 427 -480 640 -640 425 -425 640 -525 640 -640 427 -640 434 -500 463 -640 427 -427 640 -640 425 -640 480 -480 640 -427 640 -640 480 -500 400 -640 427 -640 480 -427 640 -496 500 -448 336 -426 640 -640 480 -640 480 -640 405 -480 640 -470 640 -640 427 -500 385 -426 640 -640 425 -640 480 -500 375 -640 480 -500 375 -640 426 -640 423 -640 640 -640 464 -640 425 -640 428 -500 477 -298 640 -640 480 -640 425 -640 426 -640 427 -640 480 -500 333 -640 477 -478 640 -372 500 -640 437 -640 426 -640 480 -500 375 -640 427 -500 333 -375 500 -640 480 -640 354 -478 640 -640 464 -640 424 -612 612 -500 375 -640 480 -640 480 -640 571 -640 480 -640 480 -640 480 -640 480 -640 480 -640 424 -640 427 -640 427 -640 627 -640 508 -427 640 -640 476 -640 427 -640 454 -640 502 -612 612 -333 500 -424 640 -573 640 -640 424 -640 480 -640 427 -640 480 -589 640 -640 427 -640 428 -640 472 -640 428 -480 640 -512 640 -640 480 -640 480 -640 427 -640 412 -500 314 -640 480 -480 640 -500 375 -586 640 -333 500 -640 469 -640 425 -640 480 -332 500 -640 480 -640 425 -544 640 -640 458 -500 375 -480 640 -640 480 -640 480 -640 480 -320 240 -640 480 -640 480 -427 640 -500 375 -640 480 -334 500 -640 480 -640 427 -640 497 -500 375 -640 480 -640 426 -640 425 -473 640 -640 426 -640 480 -640 426 -531 640 -640 478 -640 428 -640 429 -480 640 -612 612 -640 368 -375 500 -640 480 -640 480 -640 480 -427 640 -503 640 -640 360 -640 427 -480 640 -640 427 -640 426 -640 480 -480 640 -640 426 -640 429 -640 426 -480 640 -640 427 -640 427 -640 481 -640 427 -640 427 -640 474 -597 640 -640 248 -480 360 -640 480 -640 512 -640 427 -332 500 -640 427 -640 428 -460 640 -640 426 -500 375 -420 640 -640 480 -640 480 -500 375 -481 640 -640 427 -640 427 -640 426 -640 478 -428 640 -500 375 -640 395 -640 426 -640 427 -350 233 -640 427 -386 640 -640 480 -427 640 -640 286 -640 480 -640 419 -340 500 -640 348 -335 500 -640 495 -640 366 -640 427 -640 640 -640 427 -640 425 -640 480 -640 480 -640 480 -640 427 -640 425 -500 333 -640 481 -480 640 -480 640 -427 640 -640 427 -426 640 -640 480 -640 478 -500 332 -640 427 -640 427 -500 281 -640 480 -428 640 -640 480 -280 268 -640 369 -640 427 -640 424 -640 480 -427 640 -428 640 -640 480 -640 427 -500 361 -612 612 -640 480 -480 640 -640 427 -640 478 -640 514 -480 640 -432 288 -640 392 -640 480 -640 480 -612 612 -640 361 -640 480 -333 500 -640 427 -640 427 -640 407 -640 418 -640 512 -640 426 -640 427 -500 332 -640 428 -480 640 -640 480 -640 429 -640 360 -500 375 -640 424 -640 425 -550 365 -383 640 -640 427 -430 640 -500 375 -425 640 -500 375 -500 357 -500 222 -640 427 -640 480 -480 640 -500 375 -640 428 -640 423 -421 640 -640 480 -640 480 -640 427 -640 426 -640 480 -466 640 -427 640 -500 400 -480 640 -500 333 -640 426 -480 640 -640 480 -352 288 -640 480 -640 425 -640 428 -640 426 -640 427 -640 478 -565 640 -640 426 -640 480 -500 374 -640 426 -600 500 -640 480 -640 480 -480 640 -640 480 -586 640 -640 427 -640 491 -640 327 -640 218 -500 332 -500 375 -640 480 -640 580 -638 640 -359 640 -640 360 -516 640 -640 226 -333 500 -640 427 -640 406 -640 427 -640 480 -448 336 -640 427 -520 640 -640 480 -409 500 -375 500 -640 480 -640 483 -480 640 -640 428 -500 375 -640 480 -640 480 -640 428 -400 267 -640 480 -375 500 -640 428 -640 480 -640 424 -640 427 -428 640 -640 425 -424 640 -640 480 -500 496 -333 500 -500 335 -502 640 -640 427 -640 485 -640 480 -427 640 -425 640 -334 500 -640 426 -640 480 -640 347 -640 480 -443 640 -500 335 -640 427 -640 573 -640 444 -500 375 -427 640 -640 427 -500 375 -640 427 -640 426 -426 640 -426 640 -640 480 -640 480 -640 479 -640 427 -640 480 -640 540 -640 427 -427 640 -500 375 -640 480 -500 375 -375 500 -640 480 -640 425 -437 640 -407 482 -478 640 -640 512 -500 375 -640 480 -500 375 -640 427 -640 315 -320 240 -640 371 -640 480 -640 480 -435 640 -640 480 -424 640 -612 612 -480 640 -640 640 -425 640 -640 480 -500 375 -480 304 -640 428 -640 480 -640 480 -640 427 -640 428 -640 453 -523 640 -427 640 -500 375 -640 480 -500 500 -640 425 -640 427 -500 363 -427 640 -640 427 -500 375 -383 640 -427 640 -427 640 -500 375 -640 419 -640 480 -640 427 -360 270 -640 427 -500 388 -640 427 -640 480 -640 480 -640 427 -640 425 -640 427 -640 480 -640 323 -640 426 -500 375 -640 427 -640 424 -600 600 -640 427 -480 640 -640 457 -500 302 -640 480 -640 480 -640 480 -500 375 -457 640 -640 480 -640 360 -640 427 -500 364 -612 612 -500 375 -640 427 -375 500 -480 640 -640 427 -500 375 -640 366 -640 427 -640 480 -640 555 -640 427 -640 427 -640 426 -640 480 -640 480 -640 428 -640 484 -640 491 -500 375 -640 507 -500 375 -640 480 -375 500 -640 480 -640 480 -640 480 -640 364 -640 427 -464 640 -443 640 -640 480 -480 640 -640 363 -480 640 -480 640 -640 395 -427 640 -640 390 -640 427 -500 375 -640 427 -500 333 -612 612 -640 427 -640 480 -640 480 -491 640 -640 480 -640 428 -640 211 -640 427 -640 480 -640 480 -640 464 -640 457 -640 480 -640 428 -640 480 -640 425 -640 426 -640 360 -500 375 -640 480 -500 318 -640 428 -640 480 -375 500 -480 640 -347 500 -612 612 -640 425 -640 480 -640 542 -640 412 -640 427 -500 378 -399 640 -480 640 -640 425 -640 425 -612 612 -640 481 -640 427 -427 640 -640 419 -428 640 -640 427 -640 453 -425 640 -640 479 -640 480 -640 480 -457 640 -512 640 -480 640 -640 443 -640 427 -640 497 -500 333 -427 640 -425 640 -427 640 -480 640 -500 375 -640 400 -468 640 -425 640 -640 478 -332 500 -640 424 -640 424 -640 493 -640 485 -333 500 -640 426 -640 427 -640 425 -640 426 -640 429 -480 640 -612 612 -640 399 -640 480 -640 417 -500 400 -640 421 -640 321 -640 480 -427 640 -427 640 -640 480 -640 480 -640 480 -428 640 -640 425 -640 427 -414 640 -640 480 -640 480 -640 425 -640 424 -640 480 -509 640 -640 425 -500 375 -500 417 -427 640 -640 424 -640 480 -640 480 -480 640 -500 375 -430 640 -640 480 -640 427 -640 480 -640 427 -640 457 -640 425 -427 640 -375 500 -640 476 -640 349 -640 426 -640 488 -333 500 -480 640 -444 640 -640 480 -640 427 -500 375 -640 480 -320 240 -457 640 -640 480 -640 361 -640 425 -640 480 -640 428 -640 427 -640 425 -640 428 -640 427 -640 480 -640 346 -640 480 -559 640 -500 331 -500 375 -359 640 -640 479 -640 480 -480 640 -375 500 -427 640 -640 429 -480 640 -640 480 -640 428 -640 481 -640 531 -375 500 -640 427 -480 640 -640 351 -640 480 -640 360 -480 640 -640 640 -640 425 -640 480 -480 640 -640 427 -500 333 -640 479 -480 640 -640 426 -640 376 -426 640 -640 428 -640 427 -500 333 -640 565 -480 640 -640 480 -640 417 -640 480 -500 375 -500 333 -640 480 -500 396 -317 640 -425 640 -640 427 -480 640 -640 428 -640 480 -640 480 -500 375 -640 426 -640 361 -640 425 -375 500 -640 427 -427 640 -640 427 -427 640 -640 426 -375 500 -437 640 -640 427 -640 425 -640 480 -640 457 -640 480 -640 480 -600 640 -640 424 -640 425 -640 480 -640 425 -640 480 -500 296 -478 640 -640 399 -640 624 -640 426 -640 427 -640 471 -640 427 -450 640 -640 427 -640 383 -500 335 -640 360 -640 359 -640 480 -640 427 -418 640 -640 480 -460 640 -640 482 -480 640 -640 506 -640 480 -480 640 -375 500 -640 481 -427 640 -640 427 -600 400 -500 333 -640 360 -640 480 -480 640 -425 640 -640 480 -640 480 -640 428 -640 355 -480 640 -640 480 -640 480 -640 480 -427 640 -640 427 -500 375 -427 640 -500 375 -640 427 -640 480 -640 427 -500 375 -640 334 -640 427 -640 427 -640 427 -638 640 -500 375 -640 480 -640 428 -437 640 -429 640 -500 476 -640 359 -640 480 -640 447 -640 480 -640 360 -500 495 -500 375 -500 362 -640 480 -333 500 -640 399 -640 218 -640 418 -640 480 -640 445 -640 480 -640 480 -640 459 -640 480 -480 640 -612 612 -480 640 -640 480 -640 481 -640 427 -640 426 -427 640 -640 471 -427 640 -480 640 -640 427 -640 426 -480 640 -640 426 -640 416 -640 480 -640 428 -640 480 -640 480 -640 427 -428 640 -640 640 -612 612 -640 443 -640 480 -640 427 -640 480 -640 480 -334 500 -640 480 -640 425 -500 375 -640 427 -640 427 -640 480 -640 420 -640 426 -640 480 -640 478 -640 426 -612 612 -640 478 -640 539 -640 640 -332 500 -640 480 -480 640 -640 485 -640 480 -500 328 -640 640 -640 361 -640 426 -640 427 -640 480 -640 324 -640 383 -640 480 -511 640 -640 480 -500 285 -500 332 -640 480 -640 459 -480 640 -640 469 -500 375 -640 359 -600 400 -640 426 -640 480 -640 411 -640 480 -438 424 -640 427 -551 640 -640 480 -640 427 -640 408 -640 480 -640 424 -640 512 -640 480 -375 500 -640 427 -612 612 -640 480 -640 528 -479 640 -426 640 -640 480 -640 427 -640 359 -500 333 -640 480 -550 640 -640 480 -640 434 -633 640 -640 425 -427 640 -640 478 -640 480 -640 480 -640 480 -640 516 -640 455 -640 427 -640 480 -640 426 -640 427 -428 640 -640 480 -640 482 -640 259 -640 426 -640 457 -480 640 -427 640 -640 427 -640 480 -640 480 -640 484 -640 497 -640 426 -640 424 -640 480 -640 480 -640 480 -640 360 -482 640 -425 640 -640 361 -640 480 -640 480 -427 640 -640 480 -640 426 -640 480 -640 374 -640 426 -640 328 -640 427 -612 612 -333 500 -640 338 -500 400 -640 427 -640 427 -640 480 -640 426 -640 427 -500 375 -640 425 -640 480 -640 480 -500 375 -427 640 -640 429 -640 427 -640 466 -500 266 -500 400 -640 427 -504 640 -640 480 -480 640 -500 375 -500 375 -500 375 -500 375 -427 640 -640 480 -480 640 -640 480 -640 536 -640 427 -500 375 -640 480 -500 375 -500 375 -640 427 -612 612 -640 481 -640 427 -640 427 -500 375 -640 427 -640 509 -375 500 -640 640 -612 612 -640 480 -640 425 -640 480 -500 375 -640 425 -640 480 -640 426 -640 449 -640 480 -640 608 -640 359 -640 424 -480 640 -640 480 -640 464 -640 387 -408 640 -640 480 -640 427 -640 427 -640 468 -480 640 -375 500 -428 640 -640 480 -480 640 -640 480 -640 480 -375 500 -467 640 -640 425 -640 640 -640 480 -640 480 -640 427 -640 480 -480 640 -640 428 -640 427 -640 427 -640 480 -500 375 -640 428 -612 612 -500 333 -427 640 -640 425 -426 640 -640 480 -640 480 -640 360 -640 480 -500 375 -480 640 -480 640 -427 640 -480 640 -640 427 -640 416 -640 427 -640 424 -640 480 -640 385 -640 428 -640 480 -640 466 -640 425 -640 427 -480 640 -480 640 -480 640 -640 441 -640 480 -332 500 -640 428 -640 480 -427 640 -640 513 -640 427 -612 612 -480 640 -640 640 -640 480 -640 428 -425 640 -640 480 -640 640 -480 640 -640 428 -640 288 -640 427 -640 425 -640 479 -640 427 -640 426 -427 640 -480 640 -320 240 -640 480 -640 426 -500 375 -640 480 -640 423 -640 604 -640 436 -500 281 -640 427 -612 612 -427 640 -640 427 -427 640 -640 428 -640 427 -500 335 -640 428 -480 640 -640 427 -640 427 -640 480 -480 640 -640 427 -500 335 -335 500 -640 480 -640 391 -426 640 -431 431 -640 480 -640 463 -640 425 -640 427 -640 425 -500 332 -424 640 -500 375 -478 640 -640 480 -640 436 -640 480 -480 640 -640 596 -640 640 -640 424 -413 500 -640 477 -426 640 -426 640 -640 640 -640 427 -640 480 -640 428 -640 428 -640 457 -640 426 -640 640 -375 500 -640 473 -640 426 -640 427 -640 427 -640 478 -431 500 -640 429 -640 426 -640 480 -640 427 -427 640 -640 427 -640 427 -640 428 -640 480 -375 500 -640 480 -320 225 -640 480 -640 427 -640 480 -640 427 -426 640 -427 640 -640 404 -638 640 -640 429 -640 427 -640 480 -500 375 -431 640 -640 428 -512 640 -467 640 -427 640 -640 429 -427 640 -478 640 -640 480 -500 333 -640 480 -448 279 -640 427 -640 426 -640 427 -478 640 -640 513 -491 640 -480 640 -640 480 -640 480 -640 480 -640 480 -640 427 -480 640 -500 375 -481 640 -485 500 -640 438 -640 480 -640 480 -500 375 -640 425 -640 480 -640 480 -640 424 -640 427 -500 375 -640 424 -640 426 -640 480 -500 375 -640 428 -640 360 -640 480 -640 428 -640 427 -640 427 -427 640 -640 593 -424 640 -640 480 -640 425 -640 378 -640 480 -640 424 -640 480 -404 640 -500 345 -640 480 -640 480 -640 427 -500 370 -500 332 -500 333 -640 511 -427 640 -640 426 -433 640 -480 640 -640 428 -640 348 -500 375 -500 333 -640 441 -500 358 -640 426 -640 480 -426 640 -427 640 -640 491 -383 640 -333 500 -640 425 -640 482 -639 640 -500 298 -427 640 -375 500 -640 480 -640 480 -375 500 -640 427 -500 375 -640 480 -637 640 -640 640 -640 429 -480 640 -640 480 -640 471 -500 375 -640 417 -480 640 -427 640 -500 375 -640 486 -640 480 -428 640 -640 424 -640 480 -500 365 -500 375 -460 640 -640 426 -427 640 -640 480 -640 399 -640 480 -640 480 -612 612 -640 429 -640 426 -512 640 -640 429 -375 500 -414 640 -480 640 -640 480 -640 360 -640 480 -478 640 -360 640 -640 480 -427 640 -640 424 -375 500 -427 640 -640 375 -500 335 -640 427 -640 480 -640 512 -417 640 -640 427 -640 480 -640 427 -640 427 -640 480 -640 427 -640 424 -500 343 -640 428 -640 474 -640 480 -640 480 -640 418 -640 480 -640 640 -500 334 -433 640 -640 480 -640 480 -443 640 -640 640 -640 427 -640 425 -640 428 -640 383 -640 480 -427 640 -640 384 -480 640 -640 426 -640 429 -640 480 -640 480 -640 480 -640 426 -640 480 -640 428 -640 480 -640 480 -425 640 -640 480 -481 640 -640 427 -640 480 -427 640 -360 640 -640 480 -640 480 -500 375 -425 640 -640 480 -640 480 -640 523 -640 480 -512 640 -427 640 -640 640 -640 640 -640 427 -640 480 -480 640 -480 640 -480 640 -479 640 -480 640 -640 427 -640 427 -427 640 -640 427 -640 427 -640 480 -500 456 -640 429 -640 640 -640 424 -640 447 -375 500 -640 427 -640 458 -640 480 -640 428 -640 424 -640 360 -640 480 -640 361 -363 500 -640 480 -640 480 -640 356 -640 427 -631 640 -640 480 -480 640 -429 640 -640 480 -640 426 -640 427 -640 480 -640 480 -640 427 -479 640 -480 640 -640 427 -640 480 -500 330 -640 427 -515 640 -640 573 -638 640 -640 427 -640 480 -528 512 -640 480 -640 427 -424 640 -640 480 -480 640 -640 480 -640 480 -640 427 -640 428 -500 333 -500 375 -420 640 -640 427 -640 426 -640 480 -500 336 -500 333 -500 375 -640 480 -500 375 -480 640 -640 480 -640 480 -332 500 -640 557 -640 390 -640 480 -428 640 -640 441 -640 427 -640 480 -500 420 -640 427 -640 425 -640 480 -640 428 -640 480 -480 640 -640 456 -640 480 -432 499 -640 478 -425 640 -480 640 -640 568 -612 612 -640 480 -500 375 -640 428 -640 427 -427 640 -612 612 -640 428 -640 486 -640 426 -640 480 -640 427 -640 480 -480 640 -640 359 -457 640 -640 426 -640 428 -428 640 -640 427 -640 480 -375 500 -640 480 -640 640 -640 480 -500 500 -500 375 -500 281 -640 427 -427 640 -640 480 -640 480 -427 640 -640 640 -640 428 -427 640 -480 640 -500 374 -640 480 -500 380 -500 375 -427 640 -375 500 -640 427 -640 425 -612 612 -458 500 -375 500 -640 640 -600 411 -640 480 -427 640 -640 427 -375 500 -500 375 -333 500 -640 428 -640 479 -640 480 -640 426 -640 480 -640 386 -640 480 -640 457 -640 480 -640 428 -500 359 -500 500 -427 640 -640 480 -640 640 -501 640 -640 425 -480 640 -640 480 -640 480 -375 500 -640 458 -640 426 -640 480 -640 427 -640 480 -375 500 -480 640 -329 500 -500 373 -539 640 -640 424 -640 480 -640 476 -521 640 -640 480 -640 480 -640 480 -640 480 -640 480 -480 640 -640 427 -640 418 -640 480 -640 426 -640 480 -480 640 -480 640 -640 480 -427 640 -426 640 -612 612 -640 480 -375 500 -640 480 -640 479 -333 500 -640 480 -500 333 -640 425 -636 636 -640 427 -640 426 -427 640 -500 375 -640 480 -431 640 -640 393 -426 640 -612 612 -640 368 -375 500 -639 640 -640 429 -427 640 -640 370 -359 640 -640 427 -640 398 -500 436 -640 390 -640 469 -427 640 -640 427 -640 429 -500 353 -640 391 -640 429 -500 281 -512 640 -640 426 -612 612 -640 480 -480 640 -640 427 -456 500 -512 640 -427 640 -612 612 -427 640 -612 612 -640 426 -640 359 -427 640 -640 360 -500 375 -640 456 -640 427 -640 427 -640 427 -640 480 -640 241 -429 640 -343 500 -640 480 -640 480 -640 480 -640 427 -640 427 -334 500 -640 425 -640 480 -640 426 -640 480 -640 480 -640 478 -473 640 -640 480 -640 480 -445 500 -640 640 -500 375 -640 426 -453 640 -640 480 -500 281 -640 427 -640 484 -640 426 -640 480 -640 427 -424 640 -425 282 -640 521 -640 495 -640 480 -640 480 -333 500 -640 426 -640 480 -640 640 -640 480 -640 605 -640 400 -457 640 -640 480 -640 480 -500 375 -480 640 -640 480 -427 640 -640 424 -640 423 -640 480 -480 640 -500 160 -640 480 -640 427 -640 478 -640 320 -640 480 -375 500 -640 479 -640 480 -640 429 -640 480 -640 427 -427 640 -427 640 -480 640 -640 213 -640 640 -640 469 -640 457 -640 480 -640 610 -640 425 -500 334 -541 640 -640 480 -428 640 -500 375 -610 640 -640 425 -640 428 -612 612 -640 499 -640 427 -427 640 -375 500 -483 640 -640 480 -640 428 -640 423 -640 480 -640 480 -480 640 -468 640 -500 375 -640 427 -640 480 -240 320 -640 428 -480 640 -640 480 -425 640 -500 375 -500 333 -640 427 -400 300 -640 480 -640 426 -640 254 -375 500 -640 480 -640 427 -464 640 -480 640 -640 427 -640 640 -427 640 -383 640 -640 427 -430 640 -640 378 -640 427 -640 480 -640 444 -640 427 -500 333 -375 500 -640 427 -640 425 -640 428 -640 480 -640 428 -640 390 -500 375 -640 398 -640 480 -640 480 -640 480 -511 640 -640 480 -640 411 -640 360 -640 480 -500 333 -640 428 -640 360 -640 478 -640 480 -640 480 -640 389 -427 640 -376 500 -425 640 -500 375 -500 375 -500 333 -640 478 -640 480 -640 427 -640 480 -640 496 -640 466 -500 500 -640 428 -640 480 -640 480 -640 480 -480 640 -500 375 -640 480 -640 480 -480 640 -640 427 -640 480 -640 480 -640 427 -640 425 -640 640 -640 451 -640 427 -427 640 -500 375 -640 591 -640 536 -640 480 -640 425 -480 640 -480 640 -426 640 -640 427 -427 640 -478 640 -480 640 -640 427 -500 375 -640 480 -640 428 -640 424 -500 334 -500 306 -427 640 -612 612 -333 500 -500 400 -640 427 -480 640 -454 640 -640 436 -480 640 -640 480 -333 500 -640 480 -640 427 -640 427 -427 640 -640 480 -480 640 -427 640 -500 332 -640 415 -640 427 -640 426 -640 479 -428 640 -640 459 -640 480 -640 427 -640 480 -640 426 -640 480 -640 480 -500 375 -640 427 -640 428 -640 480 -640 502 -640 311 -495 640 -640 480 -640 480 -640 358 -640 493 -320 240 -640 406 -640 427 -640 480 -640 478 -640 480 -640 480 -640 501 -640 427 -640 481 -640 426 -640 480 -420 640 -640 480 -480 640 -640 428 -640 480 -459 344 -640 427 -640 449 -640 427 -640 425 -640 480 -480 640 -640 226 -480 640 -640 503 -640 427 -640 425 -639 640 -640 425 -640 427 -640 480 -500 375 -456 640 -500 375 -612 612 -640 472 -612 612 -640 512 -640 426 -640 458 -500 375 -480 640 -427 640 -640 480 -500 332 -640 427 -427 640 -640 439 -640 427 -640 480 -480 640 -640 480 -638 640 -480 640 -640 426 -612 612 -433 640 -640 340 -640 427 -416 640 -640 427 -640 480 -640 480 -640 480 -375 500 -585 640 -480 640 -640 480 -640 427 -464 640 -640 427 -640 640 -640 360 -423 640 -640 427 -640 383 -612 612 -640 427 -640 480 -640 427 -500 331 -524 640 -333 500 -640 480 -640 238 -640 428 -640 427 -500 374 -640 427 -425 640 -427 640 -640 640 -640 427 -478 640 -500 375 -640 480 -499 640 -640 427 -640 640 -640 480 -640 315 -640 480 -500 335 -640 614 -513 640 -640 480 -640 348 -640 480 -500 375 -640 480 -640 473 -500 369 -437 640 -640 360 -640 427 -640 480 -640 427 -480 640 -500 333 -640 429 -640 480 -480 640 -640 480 -640 480 -640 428 -640 410 -375 500 -428 640 -500 334 -640 458 -612 612 -640 426 -300 400 -480 640 -429 640 -640 427 -640 424 -288 307 -640 480 -640 424 -640 426 -500 334 -500 375 -389 500 -640 428 -640 358 -640 426 -480 640 -480 640 -428 640 -375 500 -640 427 -640 427 -640 427 -500 375 -640 534 -640 425 -640 359 -640 427 -409 500 -640 304 -427 640 -640 480 -640 283 -640 427 -480 640 -640 512 -612 612 -640 411 -640 357 -640 425 -640 348 -640 427 -640 427 -640 424 -640 437 -480 640 -480 640 -480 640 -640 480 -640 428 -640 480 -500 333 -640 427 -640 427 -640 427 -640 480 -640 427 -500 333 -427 640 -498 500 -640 480 -640 427 -480 640 -500 384 -427 640 -640 427 -400 500 -640 640 -640 424 -640 463 -300 429 -612 612 -640 477 -640 427 -600 399 -640 480 -640 480 -640 427 -640 426 -640 428 -425 640 -427 640 -640 478 -640 479 -640 427 -640 491 -640 449 -480 640 -480 640 -640 513 -640 427 -640 427 -640 428 -612 612 -375 500 -640 447 -640 449 -640 427 -640 427 -640 480 -640 427 -640 480 -480 640 -640 428 -640 426 -427 640 -640 365 -500 375 -640 480 -640 424 -427 640 -640 426 -640 426 -640 428 -640 426 -478 640 -640 480 -408 640 -640 427 -500 310 -480 640 -640 426 -640 480 -630 640 -427 640 -640 428 -640 427 -640 492 -640 499 -480 640 -640 427 -500 333 -480 640 -427 640 -640 389 -640 480 -425 640 -640 480 -640 436 -640 427 -640 449 -478 640 -480 640 -426 640 -640 434 -640 427 -480 640 -640 640 -500 375 -640 422 -480 640 -375 500 -640 426 -640 480 -640 425 -427 640 -640 480 -640 480 -640 423 -640 640 -640 383 -640 424 -640 480 -480 640 -612 612 -640 480 -640 480 -640 480 -640 427 -480 640 -555 640 -640 480 -375 500 -640 360 -640 427 -640 480 -640 425 -640 427 -640 480 -640 427 -640 427 -500 375 -480 640 -420 640 -500 375 -330 500 -612 612 -612 612 -640 361 -500 333 -640 512 -640 480 -500 375 -640 425 -640 480 -612 612 -640 428 -640 427 -427 640 -427 640 -640 456 -640 426 -640 291 -375 500 -640 427 -640 454 -640 427 -640 426 -612 612 -430 640 -500 333 -640 482 -640 480 -333 500 -426 640 -640 425 -640 427 -640 427 -640 480 -640 478 -427 640 -640 427 -491 640 -640 425 -640 427 -640 480 -500 375 -640 480 -498 640 -640 480 -640 427 -640 480 -488 640 -427 640 -500 332 -480 640 -480 640 -612 612 -640 480 -640 420 -375 500 -640 369 -640 424 -640 480 -426 640 -480 640 -640 480 -640 295 -500 347 -480 640 -640 359 -640 640 -640 480 -640 480 -640 428 -640 425 -640 479 -640 427 -640 429 -640 360 -612 612 -500 333 -640 480 -500 375 -426 640 -598 640 -640 480 -333 500 -640 426 -388 640 -426 640 -640 427 -640 478 -500 351 -640 426 -480 640 -640 430 -500 375 -640 484 -640 423 -640 480 -500 375 -640 480 -500 375 -640 426 -640 416 -500 333 -375 500 -500 361 -640 426 -427 640 -640 427 -640 427 -500 375 -640 424 -612 612 -393 640 -640 427 -375 500 -640 480 -469 640 -640 533 -640 511 -640 426 -457 640 -480 640 -640 387 -500 375 -640 427 -640 482 -640 427 -640 480 -480 640 -375 500 -424 640 -480 640 -426 640 -640 480 -640 425 -640 429 -640 546 -640 480 -468 640 -640 430 -458 640 -640 426 -640 401 -640 427 -640 480 -426 640 -640 427 -640 426 -640 480 -480 640 -640 427 -640 426 -438 640 -640 480 -428 500 -640 480 -640 480 -640 480 -640 480 -640 640 -480 640 -640 400 -500 333 -640 426 -500 375 -427 640 -427 640 -640 480 -640 482 -612 612 -640 480 -640 412 -343 500 -426 640 -425 640 -640 480 -640 427 -640 366 -640 480 -452 640 -333 500 -640 427 -612 612 -640 480 -512 640 -532 640 -640 457 -640 428 -640 428 -640 424 -500 375 -640 427 -429 640 -640 427 -640 427 -640 480 -640 480 -332 500 -640 480 -640 427 -640 209 -480 640 -480 640 -640 427 -640 427 -640 426 -640 480 -640 428 -320 480 -640 415 -426 640 -640 480 -400 640 -478 640 -640 479 -640 480 -640 427 -612 612 -375 500 -640 429 -427 640 -500 309 -500 360 -640 426 -500 375 -612 612 -335 500 -640 480 -640 480 -640 426 -640 480 -640 480 -336 448 -308 500 -330 500 -640 480 -640 424 -640 359 -640 453 -640 416 -273 346 -612 612 -375 500 -640 480 -640 480 -640 425 -300 432 -640 480 -640 428 -500 375 -480 640 -640 480 -500 375 -640 480 -640 458 -480 640 -426 640 -480 640 -640 480 -311 500 -478 640 -640 426 -640 480 -640 480 -480 640 -640 480 -500 375 -640 428 -640 480 -500 332 -640 426 -640 425 -414 500 -500 398 -640 480 -640 427 -640 427 -425 640 -640 432 -640 425 -640 384 -640 427 -640 289 -640 545 -640 480 -500 333 -429 640 -500 500 -640 425 -375 500 -640 480 -640 463 -640 426 -640 426 -640 433 -375 500 -500 375 -612 612 -640 480 -640 480 -640 436 -480 640 -478 640 -500 359 -640 427 -640 426 -478 640 -640 480 -447 640 -365 328 -427 640 -500 274 -480 640 -480 640 -640 425 -500 375 -640 480 -640 480 -438 640 -640 426 -640 436 -480 640 -484 500 -480 640 -640 415 -640 424 -640 480 -640 426 -424 640 -640 480 -456 640 -640 480 -640 480 -500 367 -377 500 -640 429 -480 640 -640 428 -640 480 -427 640 -500 367 -640 360 -333 500 -422 640 -480 640 -640 480 -640 425 -640 425 -640 640 -640 457 -640 427 -640 427 -480 640 -423 640 -454 640 -640 640 -425 640 -500 397 -427 640 -375 500 -500 333 -453 640 -480 640 -640 640 -640 480 -500 375 -480 640 -640 428 -500 375 -333 500 -640 480 -640 434 -427 640 -640 483 -480 640 -640 248 -640 427 -640 426 -640 480 -500 323 -640 480 -640 361 -640 428 -500 375 -640 426 -500 373 -640 427 -512 640 -640 480 -640 480 -480 640 -640 431 -640 404 -640 428 -480 640 -640 381 -428 640 -640 480 -480 640 -612 612 -640 428 -640 394 -640 427 -376 640 -640 426 -640 427 -425 640 -361 640 -427 640 -640 480 -507 640 -612 612 -640 480 -640 480 -500 333 -640 426 -640 450 -426 640 -425 640 -640 480 -640 480 -612 612 -640 427 -480 640 -612 612 -640 480 -640 480 -640 640 -439 640 -640 480 -640 426 -640 480 -640 480 -640 480 -480 640 -640 588 -640 426 -640 480 -480 640 -640 480 -640 480 -352 230 -428 640 -640 480 -640 423 -427 640 -640 512 -640 426 -406 640 -640 480 -640 487 -640 480 -299 500 -640 480 -500 375 -640 480 -640 427 -500 375 -640 480 -640 427 -640 426 -640 428 -640 420 -640 480 -428 640 -427 640 -608 640 -640 423 -480 640 -428 640 -640 478 -640 480 -640 640 -500 335 -500 322 -640 427 -375 500 -640 480 -640 478 -427 640 -640 480 -640 480 -640 528 -438 640 -640 427 -429 640 -640 480 -640 428 -375 500 -480 640 -451 640 -640 456 -640 399 -500 332 -640 427 -427 640 -640 427 -500 375 -640 427 -640 480 -640 427 -640 480 -640 480 -640 480 -640 480 -498 640 -640 427 -640 480 -640 480 -640 480 -640 480 -640 480 -500 375 -640 480 -612 612 -640 427 -640 427 -640 480 -640 361 -640 479 -640 480 -640 444 -640 427 -640 428 -450 500 -640 428 -500 375 -501 640 -500 375 -640 593 -640 427 -640 427 -640 547 -640 480 -612 612 -640 359 -640 480 -640 512 -640 421 -640 437 -500 375 -480 640 -426 640 -640 427 -480 640 -640 427 -612 612 -640 427 -640 480 -640 429 -500 500 -426 640 -640 426 -640 429 -500 375 -640 480 -640 640 -640 406 -640 480 -640 427 -480 640 -640 480 -500 375 -640 444 -640 429 -640 480 -640 400 -640 605 -640 427 -640 480 -335 500 -640 359 -640 338 -640 614 -640 480 -640 390 -487 640 -640 445 -640 427 -640 411 -640 640 -640 427 -640 428 -640 427 -640 426 -640 427 -480 640 -534 640 -480 640 -640 480 -500 333 -500 333 -480 640 -156 640 -640 480 -480 640 -640 640 -640 480 -640 512 -366 604 -375 500 -640 418 -640 419 -640 382 -427 640 -640 480 -640 424 -640 360 -640 480 -640 480 -640 425 -640 480 -480 640 -480 640 -640 480 -528 640 -425 640 -640 424 -375 500 -500 375 -320 240 -480 640 -640 427 -640 427 -332 500 -600 393 -425 640 -480 640 -640 406 -640 423 -640 428 -640 425 -499 640 -469 500 -640 359 -640 626 -640 480 -612 612 -640 480 -640 351 -428 640 -640 305 -480 640 -640 640 -480 640 -640 480 -473 640 -480 640 -640 480 -640 539 -640 427 -640 480 -640 424 -500 320 -480 640 -640 426 -500 333 -427 640 -640 480 -640 428 -330 500 -428 640 -640 480 -640 429 -480 640 -640 427 -640 427 -640 480 -640 480 -640 427 -640 426 -640 427 -640 480 -640 466 -504 640 -640 480 -480 640 -640 426 -640 480 -640 427 -640 480 -480 640 -489 640 -640 426 -640 478 -640 512 -640 480 -246 640 -640 424 -640 480 -640 480 -640 480 -430 640 -640 427 -427 640 -640 434 -640 318 -425 640 -640 480 -640 429 -375 500 -333 500 -640 425 -640 427 -480 640 -640 480 -640 480 -640 216 -640 480 -640 443 -427 640 -480 640 -480 640 -640 480 -640 480 -640 430 -480 640 -500 375 -640 495 -640 427 -640 425 -640 488 -624 640 -640 464 -426 640 -640 480 -640 426 -640 480 -480 640 -640 428 -493 640 -640 428 -612 612 -640 427 -444 640 -640 363 -640 427 -420 640 -480 640 -640 428 -480 640 -500 375 -427 640 -375 500 -640 480 -640 427 -640 480 -640 480 -640 480 -640 433 -640 426 -640 484 -640 480 -425 640 -640 428 -640 436 -640 480 -640 428 -640 480 -640 427 -640 480 -640 427 -427 640 -640 480 -640 480 -500 376 -428 640 -480 640 -640 427 -640 480 -640 480 -640 426 -500 333 -640 445 -638 640 -478 640 -640 427 -640 480 -640 480 -435 640 -640 429 -640 480 -640 427 -438 640 -640 488 -500 400 -640 409 -640 427 -479 640 -500 375 -640 480 -640 448 -640 480 -640 480 -640 480 -640 427 -640 292 -480 640 -480 640 -640 426 -500 332 -480 640 -427 640 -640 480 -480 640 -500 375 -640 480 -433 500 -640 480 -640 480 -500 246 -640 427 -640 427 -456 500 -480 640 -640 480 -640 429 -640 427 -480 640 -640 426 -424 640 -375 500 -500 333 -640 480 -427 640 -640 512 -640 480 -361 500 -375 500 -425 640 -640 425 -612 612 -640 480 -640 425 -640 426 -640 427 -359 500 -640 480 -427 640 -640 428 -427 640 -640 480 -566 640 -480 640 -640 640 -500 375 -500 375 -640 480 -375 500 -640 246 -640 480 -640 480 -427 640 -640 427 -640 427 -640 428 -612 612 -640 429 -640 432 -480 640 -500 378 -640 426 -500 375 -500 333 -640 427 -500 375 -480 640 -640 424 -500 332 -640 481 -640 427 -640 427 -640 456 -640 480 -640 480 -640 434 -640 427 -426 640 -480 640 -640 480 -640 512 -640 640 -640 596 -500 259 -640 428 -640 424 -478 640 -612 612 -504 640 -640 426 -640 428 -640 480 -640 480 -640 480 -640 480 -640 427 -459 640 -640 480 -480 640 -640 480 -427 640 -480 640 -640 480 -640 428 -420 640 -640 480 -640 437 -640 426 -500 333 -640 427 -500 375 -640 427 -640 480 -408 640 -640 428 -640 427 -640 426 -640 480 -640 480 -480 640 -324 500 -640 396 -640 428 -640 480 -640 384 -640 480 -640 480 -640 427 -640 427 -640 472 -640 480 -640 427 -612 612 -640 436 -480 640 -480 640 -640 586 -480 640 -425 640 -640 360 -640 480 -640 480 -640 281 -333 500 -640 480 -500 334 -640 429 -500 333 -640 454 -640 425 -640 480 -640 513 -640 479 -640 583 -640 512 -640 480 -640 360 -640 427 -640 334 -480 640 -640 480 -640 365 -447 640 -500 400 -500 332 -480 640 -426 640 -640 426 -480 640 -640 428 -427 640 -640 419 -318 640 -640 480 -426 640 -640 457 -480 640 -640 427 -640 480 -640 480 -640 428 -640 335 -640 429 -640 457 -640 391 -640 480 -640 428 -640 427 -640 426 -640 521 -427 640 -568 320 -640 427 -640 427 -640 513 -640 480 -500 272 -640 419 -640 480 -640 480 -375 500 -640 425 -640 480 -640 428 -500 375 -427 640 -640 480 -600 448 -640 480 -640 426 -500 375 -640 480 -640 480 -426 640 -640 424 -640 427 -500 375 -640 427 -512 640 -640 480 -640 437 -640 428 -480 640 -640 552 -639 640 -424 640 -640 378 -640 640 -640 417 -480 640 -640 480 -480 640 -640 424 -640 425 -640 427 -640 432 -640 427 -438 640 -500 500 -640 426 -640 441 -640 427 -640 427 -427 640 -640 427 -480 640 -640 359 -612 612 -500 375 -500 332 -612 612 -640 425 -500 375 -640 318 -640 428 -640 427 -500 457 -500 333 -640 480 -360 640 -640 426 -640 427 -640 427 -478 640 -413 640 -640 555 -640 357 -480 640 -612 612 -480 640 -640 427 -500 375 -427 640 -425 640 -640 462 -535 298 -640 427 -640 480 -640 428 -640 480 -427 640 -373 336 -640 480 -640 480 -640 426 -640 427 -640 427 -640 480 -640 427 -500 333 -640 465 -500 396 -500 333 -640 427 -640 426 -427 640 -640 480 -640 428 -480 640 -640 480 -500 375 -640 427 -500 333 -640 282 -640 427 -640 389 -640 544 -640 640 -640 427 -480 640 -500 375 -640 428 -640 459 -299 640 -640 411 -640 610 -612 612 -640 361 -426 640 -640 400 -640 640 -640 426 -640 480 -640 426 -640 480 -500 375 -427 640 -431 640 -640 640 -640 480 -427 640 -480 640 -640 427 -640 376 -640 480 -640 430 -500 335 -640 426 -640 427 -640 360 -338 500 -428 640 -640 429 -426 640 -427 640 -334 500 -427 640 -366 640 -640 427 -640 424 -640 480 -480 640 -640 508 -640 426 -640 457 -640 479 -500 396 -480 640 -640 424 -640 480 -640 470 -640 468 -427 640 -640 427 -640 481 -500 375 -427 640 -640 427 -640 480 -640 361 -640 426 -640 412 -640 480 -640 480 -640 515 -640 413 -640 480 -500 376 -640 360 -640 431 -357 500 -640 478 -478 640 -500 333 -640 428 -457 640 -500 500 -640 428 -640 428 -640 427 -640 427 -500 375 -640 480 -480 640 -640 480 -640 480 -640 480 -640 427 -427 640 -480 640 -494 640 -640 480 -640 480 -640 429 -640 427 -640 425 -640 480 -500 333 -640 480 -427 640 -612 612 -640 480 -640 480 -640 480 -448 336 -640 480 -640 393 -428 640 -640 480 -640 427 -500 404 -640 480 -640 427 -640 427 -640 427 -640 426 -640 428 -640 480 -640 605 -640 480 -640 427 -500 358 -640 480 -480 640 -640 480 -640 319 -500 375 -640 421 -640 427 -640 424 -640 480 -500 375 -424 640 -640 480 -640 480 -640 480 -640 480 -640 604 -640 480 -640 413 -640 427 -375 500 -640 429 -640 480 -640 428 -640 480 -640 427 -427 640 -628 640 -640 480 -500 335 -640 425 -640 427 -612 612 -640 425 -640 360 -320 240 -640 427 -500 377 -612 612 -427 640 -640 480 -640 489 -640 427 -640 424 -640 479 -640 427 -640 480 -478 640 -425 640 -640 424 -500 278 -427 640 -360 640 -640 411 -640 427 -640 480 -640 480 -640 425 -640 480 -640 368 -500 375 -640 480 -640 373 -443 640 -438 640 -640 480 -640 427 -480 640 -375 500 -500 393 -640 480 -640 316 -427 640 -640 428 -640 360 -480 640 -480 640 -640 425 -640 402 -640 480 -640 421 -500 375 -640 348 -427 640 -640 426 -640 427 -640 480 -444 640 -640 480 -640 445 -640 360 -640 480 -477 640 -640 418 -640 369 -428 640 -640 360 -500 375 -640 426 -500 375 -640 480 -640 427 -640 424 -640 438 -640 480 -640 480 -640 458 -359 640 -640 428 -640 427 -640 427 -640 462 -640 427 -640 480 -640 428 -640 480 -640 427 -500 333 -427 640 -424 640 -640 478 -500 375 -640 360 -480 640 -612 612 -640 426 -333 500 -640 640 -640 480 -640 428 -425 640 -640 428 -640 427 -640 464 -480 640 -640 427 -640 480 -640 639 -426 320 -640 426 -478 640 -640 420 -640 640 -640 427 -640 617 -500 375 -640 453 -427 640 -640 425 -640 457 -500 309 -500 375 -640 512 -480 640 -640 480 -426 640 -640 427 -640 480 -640 427 -500 500 -640 509 -640 428 -640 427 -480 640 -541 640 -640 423 -478 640 -640 427 -500 375 -640 427 -428 640 -500 333 -640 428 -640 426 -640 428 -640 480 -640 427 -640 480 -640 480 -428 640 -375 500 -500 375 -556 640 -640 463 -640 480 -500 375 -640 436 -640 427 -640 427 -444 640 -640 425 -640 480 -640 406 -480 640 -612 612 -640 480 -480 640 -640 428 -640 426 -500 333 -640 425 -640 427 -500 375 -640 427 -481 640 -640 427 -500 375 -640 425 -640 425 -640 480 -640 474 -640 480 -640 480 -640 428 -640 427 -640 427 -640 445 -640 480 -375 500 -640 480 -640 480 -466 640 -272 307 -333 500 -640 480 -640 427 -640 424 -640 480 -640 480 -481 640 -640 640 -640 427 -612 612 -640 631 -640 480 -640 427 -428 640 -640 214 -640 418 -640 427 -640 480 -612 612 -473 640 -640 361 -640 269 -375 500 -407 640 -428 640 -640 426 -426 640 -640 480 -640 480 -640 427 -480 640 -640 427 -332 500 -640 425 -640 480 -640 424 -640 427 -640 480 -375 500 -640 427 -500 375 -427 640 -640 445 -640 481 -424 640 -500 375 -500 333 -640 436 -640 480 -480 640 -640 480 -500 366 -375 500 -640 427 -640 381 -640 377 -640 426 -640 427 -640 453 -640 361 -640 426 -501 640 -640 427 -396 640 -612 612 -640 427 -500 331 -640 426 -640 429 -500 375 -640 428 -640 640 -640 480 -640 363 -640 480 -640 480 -426 640 -640 480 -640 427 -640 424 -500 375 -640 380 -640 480 -640 427 -640 425 -640 248 -640 480 -480 640 -480 640 -500 408 -480 640 -500 375 -640 381 -640 480 -426 640 -640 428 -640 426 -640 480 -480 640 -640 480 -640 427 -640 396 -640 480 -640 480 -640 259 -500 375 -580 640 -640 480 -596 640 -427 640 -640 480 -640 411 -333 500 -640 427 -500 375 -640 426 -640 480 -640 480 -640 427 -640 480 -612 612 -640 484 -640 360 -457 640 -500 341 -640 496 -425 640 -640 480 -640 480 -430 640 -500 424 -480 640 -640 427 -640 480 -505 640 -640 480 -512 640 -354 500 -640 427 -500 375 -640 640 -500 375 -640 426 -640 427 -427 640 -333 500 -640 457 -640 480 -427 640 -500 309 -640 427 -427 640 -640 480 -640 359 -640 512 -640 424 -640 480 -640 428 -333 500 -640 480 -480 640 -500 378 -640 427 -426 640 -500 375 -240 320 -240 320 -481 640 -457 640 -640 427 -640 427 -612 612 -640 425 -640 611 -478 640 -640 457 -501 640 -640 427 -640 484 -640 480 -427 640 -500 375 -640 480 -480 640 -480 640 -640 399 -427 640 -640 425 -640 427 -640 480 -640 318 -640 480 -500 375 -640 480 -640 480 -640 480 -640 428 -640 564 -640 426 -640 429 -427 640 -640 457 -640 426 -500 333 -640 480 -640 480 -640 488 -640 480 -500 313 -640 427 -640 480 -640 480 -640 427 -640 480 -500 334 -640 480 -640 471 -640 360 -640 491 -640 478 -640 427 -640 513 -465 640 -506 640 -500 333 -500 490 -480 640 -640 426 -640 369 -500 357 -640 495 -640 428 -640 425 -640 424 -640 460 -513 640 -640 428 -640 480 -640 480 -640 427 -333 500 -640 480 -640 428 -640 466 -640 486 -480 640 -480 640 -500 286 -427 640 -640 348 -403 500 -640 421 -640 480 -640 483 -640 579 -640 427 -640 380 -425 640 -640 480 -640 480 -640 482 -640 436 -640 427 -640 427 -640 478 -427 640 -640 427 -500 351 -640 480 -640 426 -640 426 -640 426 -640 480 -640 480 -640 426 -640 480 -640 427 -640 480 -640 480 -640 480 -640 426 -640 427 -500 333 -640 491 -640 424 -640 480 -427 640 -640 427 -640 480 -640 480 -640 427 -640 480 -640 427 -640 480 -427 640 -640 480 -640 480 -426 640 -640 427 -500 375 -426 640 -480 640 -428 640 -500 500 -640 480 -640 479 -486 640 -640 427 -640 480 -640 480 -640 428 -640 427 -640 426 -640 480 -640 418 -640 480 -640 427 -427 640 -640 480 -375 500 -640 480 -640 427 -640 427 -429 640 -500 375 -640 423 -595 640 -640 360 -640 480 -480 640 -640 473 -427 640 -640 427 -480 640 -480 640 -640 480 -426 640 -640 413 -612 612 -640 480 -480 640 -640 480 -480 640 -500 375 -640 427 -480 640 -640 424 -500 375 -504 351 -640 480 -640 427 -500 375 -640 427 -640 476 -640 426 -640 531 -640 427 -640 480 -640 428 -640 480 -500 354 -480 640 -480 640 -500 375 -640 581 -640 480 -640 404 -500 399 -640 253 -500 333 -640 428 -640 427 -500 333 -640 427 -640 427 -640 640 -640 427 -640 425 -640 427 -640 426 -640 428 -640 480 -640 426 -500 321 -640 457 -427 640 -640 433 -640 425 -640 424 -480 640 -640 480 -640 463 -500 361 -426 640 -640 458 -640 480 -640 480 -336 500 -640 427 -640 480 -612 612 -640 428 -500 375 -640 480 -480 640 -640 427 -640 421 -640 334 -640 480 -640 640 -500 334 -640 424 -640 427 -640 501 -640 480 -640 574 -640 425 -480 640 -500 375 -500 460 -427 640 -500 332 -375 500 -640 640 -640 480 -500 375 -427 640 -640 364 -640 480 -640 428 -640 371 -500 375 -500 375 -640 427 -640 427 -640 480 -640 480 -480 640 -375 500 -640 478 -500 358 -640 429 -640 480 -640 419 -640 425 -494 640 -480 640 -640 448 -640 565 -640 480 -640 360 -427 640 -640 480 -640 480 -640 562 -640 480 -640 428 -640 480 -640 480 -495 640 -480 640 -500 375 -375 500 -482 640 -640 389 -425 640 -640 480 -428 640 -640 480 -428 640 -640 224 -640 435 -640 428 -640 480 -640 427 -500 334 -640 427 -640 427 -427 640 -640 480 -640 426 -640 427 -453 640 -640 481 -500 334 -500 375 -500 375 -426 640 -480 640 -426 640 -457 640 -383 640 -640 480 -612 612 -333 500 -427 640 -640 489 -612 612 -640 413 -640 426 -640 427 -602 640 -640 427 -640 480 -640 480 -640 640 -640 480 -640 427 -640 427 -640 425 -640 427 -612 612 -400 500 -640 427 -640 480 -640 481 -640 480 -640 425 -640 586 -640 428 -640 579 -640 427 -640 425 -427 640 -500 334 -640 428 -375 500 -640 478 -640 480 -640 427 -640 480 -640 480 -640 426 -640 359 -478 640 -640 480 -640 442 -333 500 -640 424 -640 428 -500 332 -640 508 -500 375 -640 427 -640 480 -640 427 -640 475 -425 640 -640 427 -640 436 -460 640 -640 427 -640 360 -640 480 -427 640 -458 640 -640 426 -480 640 -375 500 -640 427 -640 384 -500 333 -640 427 -640 428 -500 333 -640 362 -640 425 -426 640 -640 429 -500 332 -480 640 -640 456 -640 411 -426 640 -640 475 -640 480 -500 333 -500 378 -375 500 -640 480 -640 480 -640 426 -640 444 -640 640 -640 478 -640 426 -640 480 -640 426 -640 480 -425 640 -640 464 -640 478 -480 640 -640 426 -640 426 -640 318 -333 500 -640 328 -500 375 -375 500 -500 331 -640 427 -640 427 -640 480 -612 612 -436 640 -640 480 -640 480 -640 427 -427 640 -375 500 -512 640 -500 350 -640 480 -640 593 -640 425 -375 500 -334 500 -640 480 -640 427 -640 480 -480 640 -480 640 -387 640 -640 427 -640 480 -640 480 -640 427 -612 612 -640 480 -640 458 -500 333 -500 345 -640 408 -640 480 -640 480 -500 375 -457 640 -500 375 -640 364 -640 480 -427 640 -640 426 -333 500 -640 480 -640 480 -458 640 -612 640 -480 640 -640 427 -450 338 -640 428 -640 480 -480 640 -428 640 -640 468 -640 558 -480 640 -612 612 -640 480 -530 640 -640 480 -640 396 -612 612 -640 427 -480 640 -640 423 -640 480 -480 640 -640 529 -500 380 -483 500 -640 427 -500 375 -480 640 -427 640 -480 640 -424 640 -640 427 -640 426 -640 424 -640 480 -640 427 -640 428 -427 640 -640 427 -612 612 -427 640 -640 480 -640 427 -480 640 -640 427 -640 480 -426 640 -427 640 -375 500 -500 376 -427 640 -480 640 -640 427 -428 640 -500 375 -640 480 -640 480 -640 480 -359 640 -640 480 -640 480 -612 612 -535 640 -400 229 -640 480 -640 480 -640 480 -640 427 -612 612 -375 500 -640 480 -336 500 -640 427 -640 480 -640 414 -640 426 -375 500 -640 427 -640 427 -640 480 -428 640 -640 480 -480 640 -640 517 -640 480 -640 480 -500 335 -640 490 -500 333 -352 288 -480 640 -640 425 -640 485 -640 427 -640 480 -640 427 -486 640 -640 427 -640 427 -320 216 -500 375 -445 600 -500 334 -500 339 -612 612 -640 428 -480 640 -640 427 -500 375 -306 640 -640 423 -640 427 -424 640 -640 427 -640 480 -500 333 -612 612 -500 333 -640 360 -640 480 -400 400 -424 640 -640 480 -640 416 -612 612 -640 480 -640 480 -640 479 -640 480 -640 480 -640 426 -640 429 -640 424 -640 427 -640 480 -640 480 -640 480 -612 612 -496 640 -640 480 -426 640 -640 425 -640 480 -640 425 -640 411 -640 640 -360 640 -480 640 -640 480 -640 480 -640 427 -362 640 -640 480 -640 426 -640 426 -500 333 -640 439 -640 511 -640 455 -640 516 -640 427 -612 612 -640 366 -480 640 -640 480 -640 428 -500 375 -640 427 -500 375 -480 640 -640 480 -612 612 -640 451 -640 480 -640 480 -500 375 -640 426 -640 427 -640 480 -640 427 -640 428 -480 640 -385 640 -480 640 -640 480 -640 480 -640 480 -640 480 -640 425 -612 612 -640 640 -640 480 -500 313 -640 480 -640 383 -612 612 -640 479 -640 480 -640 480 -640 457 -500 334 -450 290 -371 640 -640 480 -599 640 -640 453 -640 427 -480 640 -500 375 -640 426 -640 427 -640 477 -640 480 -640 427 -426 640 -640 480 -640 512 -500 375 -640 445 -427 640 -500 401 -480 640 -640 428 -640 480 -640 480 -640 360 -640 454 -640 516 -640 480 -640 479 -640 480 -640 640 -500 400 -640 480 -480 640 -640 480 -640 360 -640 425 -640 426 -359 640 -500 439 -480 640 -640 480 -640 480 -519 640 -491 640 -480 640 -640 479 -640 424 -640 427 -640 360 -640 402 -426 640 -640 480 -481 640 -426 640 -640 425 -427 640 -612 612 -640 480 -640 427 -426 640 -481 640 -480 640 -640 384 -640 426 -612 612 -640 480 -640 361 -640 640 -359 640 -640 480 -640 427 -640 427 -640 472 -500 375 -640 427 -426 640 -640 480 -640 480 -640 480 -640 426 -612 612 -640 428 -640 422 -640 427 -640 427 -640 427 -640 425 -640 428 -640 480 -388 450 -640 427 -640 480 -640 360 -640 427 -500 375 -640 425 -640 426 -640 481 -427 640 -640 484 -640 443 -640 425 -424 640 -478 640 -427 640 -640 438 -500 375 -640 480 -500 375 -500 358 -481 640 -640 428 -480 640 -480 640 -640 480 -425 640 -640 480 -640 329 -640 427 -640 426 -640 480 -640 480 -640 427 -640 483 -640 480 -428 640 -640 425 -500 375 -614 640 -500 334 -640 427 -375 500 -640 640 -500 400 -640 480 -640 447 -640 428 -640 427 -332 500 -480 640 -500 333 -640 520 -500 333 -467 350 -427 640 -640 427 -640 427 -375 500 -640 427 -425 640 -640 426 -640 512 -640 427 -640 429 -640 429 -500 375 -428 640 -500 333 -640 428 -640 426 -640 480 -500 333 -640 480 -478 640 -640 380 -640 481 -640 402 -640 427 -500 375 -500 332 -640 372 -640 318 -640 480 -640 427 -640 478 -640 335 -500 375 -640 426 -640 480 -640 640 -640 480 -480 640 -640 480 -640 480 -375 500 -324 500 -640 432 -640 425 -640 480 -640 360 -640 427 -640 480 -640 428 -427 640 -500 400 -640 480 -640 480 -640 480 -375 500 -621 480 -640 386 -500 500 -640 426 -640 480 -640 480 -500 375 -640 480 -640 398 -640 427 -500 375 -640 494 -480 640 -424 640 -640 480 -640 366 -640 480 -446 640 -640 427 -500 415 -640 427 -331 500 -612 612 -640 427 -640 480 -640 511 -427 640 -640 428 -600 400 -640 424 -640 480 -640 480 -640 427 -640 468 -640 480 -640 427 -640 480 -640 359 -640 418 -640 427 -375 500 -640 480 -640 427 -500 375 -480 640 -640 480 -478 640 -612 612 -640 480 -640 431 -640 427 -480 640 -640 428 -480 640 -464 640 -480 640 -612 612 -500 375 -640 428 -640 480 -640 503 -500 333 -428 640 -640 480 -640 281 -640 428 -422 640 -352 640 -640 480 -640 427 -500 339 -640 432 -640 427 -640 427 -427 640 -640 424 -332 500 -640 427 -612 612 -640 361 -640 427 -480 640 -640 541 -640 434 -640 428 -480 640 -640 480 -640 480 -640 402 -640 480 -640 428 -501 640 -427 640 -426 640 -640 426 -640 426 -444 640 -480 640 -640 480 -612 612 -640 429 -640 445 -640 364 -640 427 -640 426 -640 425 -640 360 -428 640 -500 375 -640 523 -640 480 -640 519 -640 480 -640 426 -640 426 -640 428 -640 480 -480 640 -425 640 -640 640 -640 480 -612 612 -640 480 -640 427 -640 480 -640 427 -427 640 -640 427 -640 427 -375 500 -640 480 -640 427 -404 500 -640 415 -640 480 -640 480 -427 640 -640 428 -500 375 -480 640 -512 640 -640 480 -427 640 -640 366 -481 640 -500 375 -640 480 -640 426 -640 432 -640 480 -640 427 -640 427 -640 426 -640 427 -640 480 -612 612 -640 480 -640 480 -500 375 -640 427 -640 435 -533 640 -480 640 -427 640 -640 427 -640 427 -640 426 -640 426 -640 480 -640 480 -500 375 -640 640 -640 427 -640 482 -640 427 -640 480 -600 450 -427 640 -640 424 -426 640 -640 480 -640 425 -640 480 -463 640 -640 457 -640 400 -640 427 -640 517 -640 426 -640 425 -640 427 -640 480 -427 640 -426 640 -480 640 -640 427 -640 480 -640 512 -640 428 -427 640 -640 467 -426 640 -640 424 -640 640 -426 640 -640 444 -640 427 -640 427 -640 375 -640 428 -480 640 -640 426 -640 500 -640 427 -640 427 -427 640 -640 361 -640 480 -480 640 -500 328 -640 480 -640 480 -426 640 -640 480 -640 478 -640 454 -640 400 -640 480 -640 480 -640 360 -640 480 -640 480 -500 375 -480 640 -640 640 -640 480 -640 480 -640 427 -640 480 -640 480 -640 480 -640 428 -640 640 -640 427 -640 428 -640 393 -640 406 -500 375 -640 491 -473 640 -427 640 -640 480 -640 480 -500 332 -640 425 -640 472 -640 480 -640 428 -375 500 -640 384 -640 480 -640 480 -426 640 -640 427 -375 500 -640 480 -640 480 -640 480 -375 500 -640 427 -640 457 -539 640 -640 639 -500 375 -640 427 -640 428 -640 461 -480 640 -640 427 -500 375 -428 640 -480 640 -240 320 -640 425 -640 479 -612 612 -640 426 -640 480 -640 425 -640 432 -640 480 -640 313 -640 480 -640 640 -640 480 -500 375 -640 429 -640 421 -640 428 -640 480 -428 640 -640 480 -640 488 -640 480 -500 285 -640 359 -640 480 -640 383 -476 640 -480 640 -480 640 -640 344 -480 640 -640 427 -640 383 -480 640 -480 640 -640 480 -441 500 -480 640 -640 480 -640 425 -640 640 -640 480 -640 480 -640 427 -482 482 -640 428 -640 425 -640 428 -480 640 -640 427 -640 360 -640 426 -480 640 -500 339 -500 350 -640 480 -500 334 -640 458 -640 425 -640 480 -481 640 -640 425 -640 480 -640 428 -640 480 -640 480 -640 480 -640 480 -500 375 -640 427 -640 255 -480 640 -640 480 -335 640 -640 427 -640 426 -600 449 -640 480 -640 478 -425 640 -612 612 -640 480 -500 333 -640 427 -640 480 -332 500 -640 301 -481 640 -640 479 -384 640 -640 468 -640 383 -640 480 -291 455 -640 480 -640 427 -640 480 -480 640 -427 640 -640 424 -640 427 -500 375 -640 458 -480 640 -480 640 -640 426 -640 640 -480 640 -448 336 -500 375 -640 425 -640 425 -601 640 -640 480 -640 427 -640 427 -425 640 -500 416 -640 427 -640 541 -640 481 -640 480 -640 409 -640 427 -640 399 -500 375 -640 427 -449 640 -640 427 -640 478 -640 480 -640 425 -640 428 -500 333 -640 598 -500 333 -375 500 -427 640 -640 213 -500 333 -640 480 -640 444 -429 640 -500 375 -640 480 -500 375 -427 640 -640 614 -640 427 -480 640 -640 480 -480 640 -426 640 -640 427 -428 640 -640 426 -640 457 -640 424 -640 480 -640 426 -640 427 -640 426 -423 640 -640 480 -640 427 -640 360 -640 427 -640 480 -436 640 -428 640 -375 500 -640 530 -640 480 -500 375 -640 427 -640 428 -640 480 -640 426 -640 424 -640 480 -514 640 -640 428 -640 427 -640 428 -640 427 -640 413 -612 612 -640 424 -640 480 -640 312 -640 427 -640 427 -640 426 -485 640 -640 360 -427 640 -640 513 -640 427 -640 629 -640 426 -640 427 -640 640 -640 427 -640 480 -640 480 -640 480 -478 640 -640 465 -400 320 -500 375 -640 427 -472 640 -640 480 -480 640 -640 438 -500 375 -350 500 -640 475 -640 480 -640 480 -612 612 -640 442 -360 640 -640 480 -640 481 -640 480 -640 388 -640 480 -640 480 -640 334 -640 401 -640 425 -640 478 -640 412 -640 480 -577 448 -426 640 -406 500 -640 427 -478 640 -480 640 -640 427 -500 374 -427 640 -478 640 -640 480 -640 469 -640 428 -640 480 -640 427 -640 480 -500 375 -640 480 -640 480 -500 400 -640 480 -640 480 -396 640 -640 415 -640 427 -640 480 -640 426 -500 375 -480 640 -640 427 -640 480 -640 360 -640 426 -480 640 -640 427 -640 427 -640 428 -500 333 -640 427 -640 480 -640 425 -427 640 -640 538 -640 480 -424 640 -640 441 -501 640 -640 480 -480 640 -640 474 -640 429 -640 425 -640 378 -640 480 -640 480 -640 430 -640 426 -496 640 -480 640 -500 375 -640 480 -480 640 -480 360 -500 378 -640 480 -480 640 -640 480 -640 613 -640 428 -427 640 -482 640 -500 356 -640 427 -640 640 -480 640 -640 438 -426 640 -640 480 -640 360 -640 360 -640 427 -640 483 -500 375 -640 428 -640 409 -500 334 -640 429 -640 427 -457 640 -640 444 -640 480 -640 427 -640 427 -640 427 -640 383 -425 640 -480 640 -424 640 -500 475 -640 480 -640 427 -640 480 -640 427 -640 427 -640 427 -640 480 -640 427 -640 425 -427 640 -640 480 -480 640 -480 640 -640 427 -500 258 -640 480 -640 480 -640 480 -640 450 -640 480 -640 359 -640 604 -640 427 -500 275 -640 443 -451 640 -640 426 -500 333 -640 427 -640 425 -427 640 -640 309 -640 480 -640 427 -640 435 -427 640 -640 480 -640 361 -640 427 -640 480 -640 479 -640 480 -640 480 -427 640 -640 480 -633 640 -640 480 -640 360 -332 500 -640 478 -427 640 -640 396 -640 427 -640 427 -480 640 -480 640 -458 640 -500 375 -425 640 -640 427 -428 640 -640 424 -480 640 -640 480 -640 480 -640 427 -640 396 -612 612 -306 640 -640 480 -640 480 -640 480 -640 427 -640 480 -361 640 -640 480 -500 333 -640 427 -640 480 -640 427 -426 640 -478 640 -640 480 -640 426 -640 403 -640 579 -640 480 -427 640 -640 425 -640 480 -612 612 -640 425 -500 375 -640 360 -640 480 -640 427 -640 427 -640 480 -640 427 -640 480 -480 640 -426 640 -640 480 -640 480 -640 425 -640 427 -446 640 -640 480 -484 500 -425 640 -640 640 -471 500 -640 480 -640 439 -640 428 -612 612 -600 600 -500 333 -640 480 -640 480 -640 425 -640 480 -640 480 -640 443 -640 485 -640 480 -426 640 -423 640 -640 419 -640 480 -424 640 -640 436 -640 511 -640 449 -640 426 -640 480 -640 480 -480 640 -640 426 -640 480 -640 427 -640 480 -640 403 -640 640 -640 426 -480 640 -500 400 -640 480 -176 144 -500 375 -500 400 -640 426 -500 384 -640 480 -640 480 -506 640 -640 427 -480 640 -640 424 -640 360 -640 427 -640 427 -640 427 -640 427 -640 445 -640 480 -640 474 -640 480 -640 427 -640 480 -427 640 -478 640 -640 480 -640 403 -640 426 -640 480 -640 448 -640 480 -640 640 -640 423 -640 529 -640 427 -640 427 -612 612 -640 480 -640 427 -640 427 -480 640 -640 427 -640 427 -426 640 -640 428 -640 359 -640 427 -640 480 -640 427 -640 360 -640 427 -480 640 -423 640 -500 375 -640 391 -640 480 -480 640 -640 427 -640 427 -640 332 -375 500 -640 425 -640 480 -640 360 -493 640 -331 500 -640 427 -640 480 -480 640 -640 480 -640 425 -640 480 -427 640 -480 640 -640 341 -480 640 -480 640 -376 500 -640 487 -428 640 -640 480 -640 426 -640 449 -480 640 -640 427 -480 640 -640 428 -596 640 -640 396 -640 369 -480 640 -640 480 -640 480 -480 640 -640 427 -500 375 -640 425 -640 480 -640 360 -640 480 -640 480 -640 470 -427 640 -500 272 -612 612 -640 425 -375 500 -500 333 -478 640 -640 428 -612 612 -640 427 -640 480 -471 640 -640 426 -500 375 -500 375 -400 500 -640 576 -640 480 -500 281 -400 640 -500 375 -640 471 -431 640 -375 500 -640 427 -471 500 -640 480 -640 553 -640 480 -427 640 -480 640 -480 640 -375 500 -529 640 -640 423 -360 640 -500 375 -600 450 -500 333 -426 640 -640 436 -640 480 -480 640 -640 424 -640 480 -640 426 -640 480 -427 640 -640 480 -640 427 -640 425 -640 425 -640 480 -640 426 -480 640 -640 478 -640 480 -427 640 -640 500 -640 383 -640 427 -640 480 -640 430 -640 429 -640 480 -640 384 -640 425 -480 640 -428 640 -310 500 -640 478 -640 428 -640 361 -640 427 -640 427 -640 640 -640 456 -500 405 -640 427 -491 640 -480 640 -500 374 -427 640 -333 500 -500 401 -640 478 -480 640 -640 407 -640 425 -428 640 -640 427 -640 360 -479 640 -640 424 -612 612 -640 427 -640 488 -500 375 -499 640 -480 640 -640 480 -640 523 -640 427 -640 360 -640 524 -640 574 -480 640 -640 427 -640 426 -640 427 -640 516 -426 640 -640 480 -480 640 -500 375 -427 640 -500 376 -427 640 -480 640 -640 480 -640 426 -640 523 -640 481 -640 427 -500 375 -640 480 -398 500 -640 640 -640 480 -640 480 -640 426 -424 640 -500 333 -640 427 -640 480 -640 429 -455 640 -640 480 -640 426 -480 640 -640 427 -640 451 -640 424 -640 480 -427 640 -424 640 -640 480 -500 281 -640 427 -426 640 -640 405 -612 612 -427 640 -426 640 -500 333 -640 427 -633 640 -640 480 -640 361 -640 427 -640 427 -480 640 -556 407 -640 480 -640 424 -640 480 -640 477 -637 640 -640 639 -334 500 -640 480 -640 480 -426 640 -480 640 -640 480 -502 640 -640 614 -427 640 -640 480 -640 424 -425 640 -640 512 -480 640 -640 427 -640 479 -640 360 -500 375 -424 640 -640 480 -640 428 -640 389 -640 435 -640 480 -480 640 -640 480 -640 480 -425 282 -426 640 -640 425 -640 424 -640 480 -640 363 -480 640 -640 480 -640 428 -640 499 -640 431 -640 427 -640 427 -640 427 -640 480 -555 640 -640 479 -640 480 -427 640 -640 427 -640 480 -640 428 -640 428 -640 480 -640 427 -640 330 -640 480 -427 640 -427 640 -640 480 -640 480 -500 416 -514 640 -375 500 -640 427 -480 640 -640 427 -640 427 -450 450 -640 424 -423 640 -640 428 -427 640 -640 425 -500 375 -640 447 -640 480 -640 426 -640 424 -640 430 -640 450 -640 425 -640 480 -427 640 -421 500 -512 640 -640 427 -640 480 -482 389 -640 428 -640 480 -397 640 -640 549 -640 428 -375 500 -640 480 -640 640 -640 434 -640 640 -640 433 -640 480 -640 360 -640 480 -640 480 -480 640 -640 428 -640 480 -320 240 -640 428 -427 640 -640 426 -480 640 -640 427 -640 427 -500 368 -640 427 -500 333 -500 333 -640 480 -266 187 -640 424 -425 640 -640 480 -640 480 -640 480 -500 324 -640 478 -626 640 -640 426 -426 640 -640 480 -480 640 -640 427 -640 427 -480 640 -640 480 -480 640 -640 428 -640 480 -640 330 -640 425 -640 360 -478 640 -500 333 -640 428 -480 640 -500 333 -640 480 -500 332 -640 428 -427 640 -640 480 -640 480 -640 427 -640 531 -640 361 -640 480 -640 429 -640 360 -640 512 -640 425 -424 500 -426 640 -640 427 -640 427 -640 473 -419 640 -640 532 -463 640 -640 480 -640 480 -640 427 -640 425 -640 480 -640 497 -640 480 -500 333 -640 480 -500 375 -640 517 -640 398 -612 612 -640 426 -425 640 -640 485 -640 480 -633 640 -640 427 -480 640 -406 610 -429 640 -640 519 -640 426 -427 640 -640 480 -640 425 -425 640 -500 375 -427 640 -500 375 -640 480 -640 427 -640 428 -640 480 -426 640 -640 480 -640 480 -640 479 -640 427 -640 424 -480 640 -500 400 -640 361 -640 480 -478 640 -640 425 -640 427 -480 640 -640 329 -640 446 -640 426 -640 428 -428 640 -612 612 -640 480 -640 480 -640 427 -480 640 -640 457 -587 640 -640 425 -640 427 -500 375 -640 427 -640 427 -640 639 -426 640 -640 480 -640 640 -640 427 -428 640 -640 457 -640 425 -640 427 -640 480 -427 640 -640 426 -640 480 -640 428 -640 478 -640 480 -480 640 -640 457 -478 640 -428 640 -640 487 -500 333 -640 480 -640 454 -368 640 -640 427 -372 640 -640 425 -640 426 -640 426 -640 480 -640 425 -640 480 -500 500 -425 640 -640 442 -500 335 -640 480 -640 427 -640 426 -640 427 -375 500 -500 336 -640 482 -640 396 -640 480 -640 480 -640 360 -352 288 -640 480 -640 480 -640 426 -640 480 -427 640 -640 475 -640 426 -375 500 -640 427 -640 425 -480 640 -640 640 -640 521 -640 427 -640 480 -640 400 -640 480 -375 500 -353 640 -375 500 -600 400 -640 425 -428 640 -640 512 -640 480 -640 478 -480 640 -500 480 -500 333 -480 640 -640 427 -640 640 -640 480 -640 428 -427 640 -600 450 -339 500 -426 640 -480 640 -640 427 -640 427 -640 428 -640 418 -500 332 -640 480 -640 426 -500 375 -640 480 -480 640 -640 426 -640 514 -640 436 -640 480 -622 640 -640 425 -500 500 -427 640 -640 425 -640 427 -480 640 -500 321 -640 480 -480 640 -424 640 -640 419 -640 428 -409 640 -640 478 -640 426 -640 430 -640 360 -480 640 -500 334 -400 500 -480 640 -640 427 -640 428 -640 421 -500 375 -480 640 -640 480 -480 640 -640 272 -640 427 -640 426 -640 480 -640 360 -640 480 -640 480 -640 482 -375 500 -640 425 -640 383 -640 480 -640 480 -640 480 -640 427 -640 480 -640 480 -640 427 -494 330 -640 428 -640 427 -640 428 -640 427 -640 427 -640 470 -640 425 -375 500 -426 640 -385 500 -640 425 -500 375 -640 458 -640 480 -640 214 -480 640 -640 541 -640 427 -480 640 -640 480 -640 427 -640 427 -500 381 -612 612 -640 435 -480 640 -640 503 -640 480 -500 387 -640 479 -640 478 -640 480 -640 480 -640 426 -640 427 -640 428 -640 480 -500 333 -640 480 -640 480 -424 640 -640 480 -640 435 -640 480 -457 640 -612 612 -640 427 -500 375 -640 425 -640 480 -640 517 -640 427 -640 266 -640 360 -476 640 -640 427 -640 413 -640 480 -640 480 -640 427 -480 640 -480 640 -500 303 -640 427 -500 375 -640 389 -480 640 -427 640 -427 640 -640 480 -640 480 -640 480 -640 308 -511 640 -640 523 -640 427 -424 640 -426 640 -640 480 -640 480 -375 500 -500 375 -500 375 -600 400 -512 640 -640 480 -640 480 -640 480 -640 425 -612 612 -640 427 -640 480 -427 640 -500 374 -640 480 -500 375 -640 426 -640 480 -612 612 -640 427 -640 424 -427 640 -480 640 -320 216 -499 640 -415 640 -374 500 -640 427 -640 480 -640 426 -640 360 -480 640 -640 480 -640 427 -341 500 -640 480 -640 480 -428 640 -480 640 -640 480 -640 480 -640 478 -428 640 -640 483 -424 640 -640 480 -640 426 -640 480 -640 359 -516 408 -640 480 -640 480 -480 640 -417 640 -640 478 -500 333 -640 480 -427 640 -640 360 -640 545 -640 480 -640 482 -640 506 -640 480 -640 480 -640 482 -640 480 -640 559 -427 640 -480 640 -480 640 -640 507 -500 335 -640 360 -550 400 -640 427 -640 480 -500 334 -480 640 -640 609 -500 333 -640 480 -640 426 -600 450 -640 480 -640 427 -640 480 -480 640 -640 480 -640 426 -512 640 -640 426 -640 425 -640 480 -480 640 -500 375 -640 381 -640 427 -640 427 -640 509 -640 427 -640 400 -640 480 -640 429 -480 640 -640 480 -640 618 -640 426 -427 640 -640 480 -640 427 -500 335 -603 640 -427 640 -640 480 -640 480 -582 640 -640 427 -500 332 -640 445 -478 640 -640 480 -640 400 -509 640 -612 612 -640 427 -640 425 -640 480 -640 480 -500 256 -640 427 -426 640 -640 426 -500 375 -640 480 -288 352 -640 480 -640 480 -480 640 -640 427 -500 375 -640 480 -480 640 -640 426 -640 427 -640 428 -500 375 -640 427 -640 640 -640 480 -640 427 -640 480 -640 480 -640 348 -640 425 -640 613 -427 640 -640 427 -500 500 -640 427 -480 640 -479 640 -640 639 -600 400 -640 480 -640 427 -320 240 -480 640 -500 375 -640 234 -640 427 -640 427 -640 427 -500 333 -500 375 -640 433 -640 427 -640 424 -640 480 -640 480 -612 612 -470 332 -640 322 -640 480 -640 521 -640 427 -640 427 -500 375 -640 480 -640 427 -640 480 -640 501 -640 424 -460 640 -640 419 -640 480 -640 480 -500 375 -640 427 -640 427 -333 500 -640 426 -375 500 -500 374 -640 512 -500 375 -640 425 -640 480 -480 640 -480 640 -427 640 -500 375 -640 427 -480 640 -640 427 -640 480 -612 612 -640 480 -480 640 -640 555 -457 640 -500 375 -480 640 -640 480 -500 323 -612 612 -640 480 -640 480 -640 406 -640 480 -640 427 -640 429 -640 426 -480 640 -500 332 -640 427 -640 480 -425 640 -426 640 -640 425 -375 500 -458 640 -640 427 -640 427 -640 427 -427 640 -640 445 -640 427 -640 427 -640 457 -500 500 -640 427 -640 427 -640 563 -640 419 -428 640 -500 375 -640 456 -640 480 -640 427 -427 640 -375 500 -640 427 -479 640 -640 426 -640 427 -500 335 -640 427 -640 383 -500 338 -640 426 -427 640 -640 480 -500 375 -426 640 -640 424 -500 332 -640 480 -424 640 -640 480 -421 640 -640 176 -640 480 -640 426 -640 639 -640 480 -480 640 -640 425 -640 480 -640 480 -640 429 -500 375 -612 612 -640 566 -640 427 -640 526 -480 640 -480 640 -427 640 -640 428 -425 640 -640 517 -640 433 -240 320 -640 426 -417 640 -640 428 -640 425 -361 500 -640 523 -640 480 -640 480 -640 478 -640 427 -640 427 -425 640 -500 332 -500 375 -640 427 -426 640 -640 427 -640 425 -500 333 -480 640 -427 640 -500 362 -640 480 -640 533 -640 428 -427 640 -640 480 -361 640 -500 375 -640 480 -640 522 -500 456 -427 640 -500 321 -640 480 -640 427 -640 425 -480 640 -640 480 -640 360 -640 480 -335 500 -480 640 -427 640 -500 375 -500 334 -478 640 -640 427 -640 480 -640 427 -425 640 -640 427 -375 500 -640 480 -640 427 -612 612 -640 429 -640 480 -437 640 -424 640 -480 640 -640 427 -640 426 -640 429 -640 480 -640 419 -426 640 -640 480 -640 428 -640 480 -640 480 -500 375 -640 480 -640 427 -640 457 -640 425 -640 427 -500 375 -640 395 -468 640 -640 407 -640 436 -640 427 -426 640 -640 427 -640 427 -480 640 -640 428 -500 375 -640 427 -640 425 -640 480 -375 500 -427 640 -500 375 -640 480 -612 612 -640 478 -640 426 -500 281 -640 480 -427 640 -425 640 -640 480 -640 425 -480 640 -268 640 -480 640 -640 426 -500 333 -640 427 -618 640 -500 333 -640 426 -640 420 -612 612 -640 575 -640 427 -640 427 -430 640 -427 640 -640 480 -480 640 -333 500 -640 427 -427 640 -640 480 -429 640 -640 319 -375 500 -640 428 -640 429 -640 427 -612 612 -640 480 -415 640 -640 426 -612 612 -640 480 -640 276 -640 640 -427 640 -640 427 -640 480 -640 480 -640 468 -640 426 -480 640 -640 508 -640 233 -443 640 -640 480 -640 480 -500 375 -640 427 -640 468 -640 427 -448 640 -480 640 -459 640 -640 426 -640 428 -640 428 -640 480 -426 640 -640 428 -640 480 -424 640 -640 425 -640 480 -333 500 -500 375 -640 425 -640 480 -640 425 -640 480 -500 335 -640 403 -640 480 -640 480 -640 480 -640 427 -640 425 -640 427 -500 333 -640 427 -640 480 -640 480 -640 480 -640 425 -640 480 -640 480 -640 480 -640 480 -640 428 -425 640 -640 426 -640 427 -640 256 -612 612 -640 427 -640 427 -640 480 -500 375 -480 640 -500 333 -640 567 -640 426 -339 500 -640 423 -640 480 -480 640 -640 533 -480 640 -640 428 -640 427 -640 480 -612 612 -640 480 -640 427 -426 640 -640 426 -640 436 -480 640 -640 427 -640 426 -640 480 -480 640 -640 478 -429 640 -640 427 -323 500 -500 375 -480 640 -500 494 -333 500 -500 375 -640 400 -427 640 -640 428 -240 180 -612 612 -598 640 -376 479 -640 480 -333 500 -427 640 -480 640 -640 458 -640 480 -480 640 -640 480 -480 640 -500 332 -640 310 -640 480 -500 375 -640 640 -640 427 -640 480 -640 427 -640 480 -500 375 -640 428 -427 640 -500 376 -426 640 -480 640 -640 480 -640 427 -640 428 -640 480 -640 439 -400 400 -425 640 -640 640 -640 431 -444 500 -500 333 -640 427 -640 425 -640 427 -559 640 -640 428 -426 640 -640 480 -471 640 -640 429 -640 427 -500 375 -480 640 -640 427 -640 480 -640 480 -640 427 -640 480 -480 640 -640 499 -426 640 -612 612 -500 375 -640 425 -427 640 -640 415 -640 427 -640 513 -640 480 -500 375 -640 434 -640 429 -640 480 -333 500 -640 427 -640 425 -640 480 -640 480 -500 375 -318 500 -480 640 -640 481 -500 375 -500 375 -640 480 -480 640 -500 306 -640 480 -640 480 -640 480 -436 640 -480 640 -640 480 -640 480 -640 426 -427 640 -640 427 -640 428 -500 400 -640 424 -333 500 -486 640 -480 640 -640 428 -640 444 -514 640 -640 406 -640 480 -480 640 -425 640 -640 378 -458 640 -640 426 -640 480 -500 375 -469 640 -480 640 -427 640 -640 480 -640 427 -478 640 -640 427 -334 500 -640 427 -500 443 -427 640 -640 480 -640 425 -502 640 -375 500 -640 427 -500 334 -500 375 -427 640 -480 640 -640 427 -640 429 -443 640 -640 441 -500 333 -449 640 -500 333 -640 424 -270 360 -640 498 -333 500 -480 640 -429 640 -640 478 -640 360 -640 480 -640 437 -480 640 -480 640 -640 640 -640 480 -640 426 -640 480 -640 480 -425 640 -640 480 -427 640 -640 480 -640 427 -640 479 -640 427 -500 500 -640 344 -640 354 -640 480 -427 640 -640 418 -640 427 -640 428 -640 485 -640 426 -500 376 -612 612 -500 375 -500 375 -640 499 -427 640 -480 640 -640 561 -640 429 -640 480 -480 640 -612 612 -500 332 -480 640 -640 427 -375 500 -480 640 -640 373 -480 640 -640 427 -640 418 -640 480 -640 426 -427 640 -640 480 -480 640 -433 640 -640 369 -640 427 -500 335 -640 495 -640 487 -612 612 -359 640 -640 480 -598 640 -500 400 -425 640 -640 427 -640 427 -500 336 -640 298 -640 480 -640 480 -412 640 -640 480 -640 595 -480 640 -375 500 -478 640 -640 480 -480 640 -500 375 -500 305 -500 326 -640 480 -640 383 -612 612 -640 424 -640 427 -640 428 -500 375 -640 512 -640 480 -571 640 -500 375 -500 375 -640 480 -640 427 -640 480 -640 429 -640 427 -428 640 -640 427 -640 427 -640 480 -480 640 -640 426 -640 427 -500 345 -640 480 -436 500 -640 480 -640 496 -640 480 -480 640 -640 426 -640 426 -640 424 -640 390 -640 425 -640 425 -640 427 -640 451 -640 480 -640 425 -640 428 -640 640 -640 480 -640 425 -640 479 -640 427 -640 427 -640 480 -640 480 -500 393 -640 427 -480 640 -640 453 -640 480 -640 480 -640 480 -640 395 -640 427 -640 598 -640 426 -640 427 -640 427 -500 375 -640 480 -640 480 -375 500 -375 500 -640 480 -640 427 -640 640 -640 480 -480 640 -640 480 -640 480 -640 422 -423 640 -640 443 -500 332 -640 480 -640 426 -640 480 -640 640 -480 640 -640 424 -640 427 -640 359 -640 424 -640 428 -640 424 -480 640 -427 640 -640 480 -376 640 -640 427 -640 480 -429 640 -640 443 -640 427 -480 640 -640 425 -480 640 -459 640 -640 361 -640 445 -225 225 -500 329 -640 480 -426 640 -640 480 -640 427 -428 640 -640 480 -640 426 -493 500 -640 480 -224 300 -640 427 -612 612 -640 480 -640 427 -640 426 -640 480 -640 640 -640 427 -640 451 -640 480 -640 425 -480 640 -500 333 -640 424 -640 451 -640 480 -640 427 -640 480 -640 480 -478 640 -400 600 -480 640 -640 480 -425 640 -640 480 -640 426 -346 640 -640 480 -500 270 -640 480 -640 480 -640 426 -640 559 -640 480 -428 640 -640 426 -640 391 -640 392 -612 612 -640 480 -633 640 -500 287 -480 640 -640 480 -640 512 -640 355 -427 640 -640 427 -640 428 -640 426 -640 543 -425 640 -500 333 -498 635 -640 480 -640 480 -640 429 -640 426 -640 428 -640 480 -640 478 -519 640 -640 428 -640 480 -640 426 -500 500 -640 427 -640 352 -360 480 -640 480 -640 240 -500 375 -427 640 -640 480 -500 333 -640 427 -480 640 -500 388 -500 334 -640 426 -640 480 -500 333 -640 480 -480 640 -640 480 -500 375 -640 480 -640 480 -500 375 -640 480 -640 426 -480 640 -640 480 -640 426 -640 376 -500 333 -640 427 -500 387 -333 500 -640 403 -640 480 -600 400 -640 480 -427 640 -384 640 -640 427 -500 329 -640 480 -640 425 -640 424 -640 544 -640 436 -640 426 -640 640 -640 427 -640 478 -640 427 -640 424 -365 640 -500 375 -640 427 -500 375 -640 427 -640 458 -640 480 -480 640 -500 375 -500 335 -480 640 -612 612 -446 640 -640 480 -640 480 -640 476 -600 402 -500 333 -500 334 -500 375 -426 640 -475 640 -500 350 -640 453 -529 640 -640 426 -640 248 -480 640 -554 640 -360 640 -640 427 -480 640 -500 375 -640 480 -640 480 -640 480 -640 427 -640 480 -640 439 -512 640 -500 333 -640 427 -640 428 -640 427 -640 480 -428 640 -500 375 -640 480 -640 480 -500 375 -640 399 -640 427 -640 480 -427 640 -480 640 -640 457 -640 427 -640 411 -640 480 -500 375 -640 480 -500 375 -640 437 -640 480 -640 360 -500 375 -640 479 -640 427 -640 427 -640 480 -332 500 -640 480 -640 480 -640 480 -500 255 -640 480 -427 640 -640 425 -640 427 -500 332 -640 480 -640 424 -640 453 -500 333 -480 640 -612 612 -640 480 -612 612 -528 512 -640 480 -640 480 -640 480 -471 640 -429 640 -640 640 -640 430 -640 425 -411 640 -640 428 -640 425 -640 427 -640 418 -500 375 -427 640 -640 427 -508 640 -640 425 -427 640 -640 360 -640 360 -424 283 -640 421 -640 479 -640 480 -429 640 -640 418 -640 427 -640 427 -375 500 -640 426 -375 500 -640 445 -640 440 -480 640 -640 451 -500 375 -640 510 -640 480 -640 480 -640 466 -640 334 -640 333 -480 640 -640 480 -640 480 -640 427 -640 640 -500 375 -640 480 -640 428 -640 428 -500 375 -640 426 -427 640 -640 426 -640 604 -612 612 -640 428 -640 426 -640 427 -640 428 -640 428 -500 500 -640 480 -478 640 -640 444 -640 426 -640 427 -640 480 -640 428 -480 640 -640 425 -640 494 -375 500 -640 480 -640 425 -359 640 -640 458 -640 426 -640 427 -640 480 -640 425 -333 500 -640 427 -500 320 -333 500 -500 375 -500 375 -500 375 -640 480 -640 640 -480 640 -351 234 -500 333 -500 375 -640 426 -480 640 -480 640 -640 427 -640 489 -640 480 -640 427 -640 480 -640 640 -640 640 -500 334 -640 480 -640 427 -640 427 -640 426 -640 426 -640 427 -640 427 -640 356 -640 480 -538 640 -640 360 -640 427 -640 427 -640 480 -640 427 -480 640 -640 299 -640 425 -640 480 -320 240 -640 426 -480 360 -640 480 -640 426 -640 480 -640 480 -640 427 -500 375 -640 111 -640 427 -480 640 -640 478 -640 448 -612 612 -640 425 -640 426 -640 427 -640 425 -333 500 -425 640 -640 425 -427 640 -500 334 -480 640 -480 640 -640 480 -640 427 -640 281 -640 428 -500 364 -640 480 -640 424 -640 480 -640 428 -640 426 -334 500 -500 375 -427 640 -640 480 -640 424 -442 640 -480 640 -333 500 -500 500 -500 375 -640 480 -631 640 -640 480 -427 640 -640 429 -640 426 -640 428 -480 640 -640 362 -640 480 -640 471 -640 480 -640 480 -640 640 -640 457 -640 425 -427 640 -640 464 -640 427 -640 427 -428 640 -640 480 -640 427 -428 640 -640 480 -640 480 -480 640 -640 439 -640 428 -332 500 -500 363 -640 424 -640 480 -640 427 -500 375 -640 425 -640 427 -427 640 -640 425 -640 480 -640 427 -471 640 -468 500 -640 427 -640 480 -375 500 -640 480 -640 426 -640 314 -640 427 -480 640 -640 427 -500 375 -640 480 -640 424 -640 480 -640 591 -438 640 -640 425 -640 425 -640 480 -427 640 -640 480 -425 640 -640 480 -500 375 -640 480 -640 429 -640 480 -427 640 -500 436 -478 640 -640 480 -500 375 -500 375 -500 333 -500 375 -397 500 -640 360 -500 375 -640 480 -640 427 -480 640 -640 427 -640 480 -640 470 -640 480 -640 428 -640 427 -640 480 -500 375 -427 640 -640 480 -640 458 -640 480 -640 425 -640 390 -640 549 -640 428 -640 480 -640 427 -500 333 -640 427 -426 640 -640 428 -640 428 -640 483 -640 455 -500 333 -426 640 -640 451 -500 301 -640 478 -424 640 -480 640 -640 480 -426 640 -640 364 -492 500 -640 480 -640 478 -640 480 -480 640 -500 375 -480 640 -640 429 -375 500 -640 268 -480 640 -427 640 -640 356 -640 358 -640 481 -640 480 -612 612 -640 424 -640 480 -612 612 -500 333 -326 500 -491 640 -640 491 -640 388 -640 478 -640 425 -640 480 -640 360 -500 375 -640 427 -480 640 -640 428 -640 426 -640 480 -480 640 -612 612 -640 480 -500 375 -640 386 -640 424 -424 640 -640 424 -425 640 -640 427 -640 480 -480 640 -640 427 -640 450 -640 480 -640 480 -640 640 -640 428 -427 640 -640 411 -640 514 -480 640 -480 640 -640 480 -640 426 -480 640 -640 480 -500 376 -425 640 -500 333 -640 427 -640 614 -640 427 -500 375 -640 426 -500 333 -640 480 -375 500 -500 375 -640 426 -317 398 -640 480 -640 512 -640 425 -500 333 -640 480 -640 578 -424 640 -640 480 -500 375 -640 480 -640 480 -480 640 -612 612 -640 425 -640 480 -640 480 -640 428 -640 480 -640 427 -640 426 -612 612 -640 427 -640 361 -640 424 -640 480 -480 640 -640 424 -500 333 -640 425 -640 480 -640 427 -640 434 -640 479 -640 425 -640 488 -640 478 -480 640 -334 500 -640 426 -640 424 -640 427 -427 640 -640 512 -640 419 -640 392 -500 375 -612 612 -640 480 -600 399 -640 427 -640 480 -500 339 -428 640 -640 427 -640 480 -480 640 -640 480 -640 606 -640 480 -640 427 -640 480 -640 427 -640 480 -500 333 -640 427 -500 375 -500 434 -640 404 -427 640 -640 426 -480 640 -640 427 -640 480 -500 358 -500 335 -500 313 -640 425 -500 375 -640 429 -500 375 -480 640 -640 427 -478 640 -640 481 -500 348 -640 427 -640 478 -480 640 -640 408 -632 640 -480 640 -640 355 -640 427 -375 500 -500 351 -640 426 -343 500 -640 480 -500 332 -640 480 -500 375 -500 375 -640 427 -640 428 -480 640 -640 426 -640 427 -640 480 -480 640 -640 480 -640 308 -640 427 -640 426 -640 480 -333 500 -640 426 -640 427 -640 427 -480 640 -640 480 -640 427 -375 500 -640 401 -640 426 -640 480 -500 281 -563 422 -640 426 -640 427 -640 427 -640 427 -640 425 -640 422 -640 427 -640 429 -640 480 -626 640 -480 640 -427 640 -640 480 -640 480 -640 416 -427 640 -640 480 -640 494 -500 333 -500 333 -640 448 -640 425 -480 640 -480 640 -640 480 -640 425 -500 331 -640 480 -640 515 -500 399 -640 428 -500 400 -640 480 -640 426 -640 428 -640 271 -640 480 -500 375 -427 640 -640 427 -640 428 -640 427 -640 470 -640 473 -640 427 -640 360 -333 500 -640 427 -427 640 -640 480 -480 640 -640 427 -500 384 -640 405 -640 480 -640 426 -640 480 -640 360 -640 448 -640 640 -640 425 -640 480 -640 480 -640 480 -640 425 -480 640 -640 489 -306 640 -640 383 -640 389 -480 640 -640 480 -500 327 -480 640 -358 640 -640 426 -640 458 -640 427 -640 428 -640 480 -640 480 -320 240 -640 412 -640 439 -640 427 -640 428 -640 540 -640 480 -640 480 -640 480 -612 612 -640 531 -640 480 -427 640 -640 480 -640 480 -480 640 -640 427 -640 424 -640 402 -332 500 -640 359 -640 427 -427 640 -640 427 -640 433 -640 360 -640 480 -640 480 -426 640 -640 427 -640 426 -480 640 -640 478 -500 375 -480 640 -640 480 -640 424 -640 480 -640 480 -640 427 -640 491 -640 480 -480 640 -400 300 -640 448 -640 480 -640 426 -640 427 -640 423 -640 427 -640 630 -640 480 -640 406 -640 429 -640 480 -640 480 -640 480 -640 479 -612 612 -427 640 -478 640 -640 427 -328 500 -640 360 -640 480 -480 320 -409 640 -640 427 -640 480 -640 426 -640 427 -640 480 -500 333 -640 428 -640 427 -640 480 -640 440 -640 480 -640 459 -640 480 -480 640 -640 480 -640 425 -640 501 -612 612 -640 480 -640 513 -640 480 -640 428 -640 482 -640 480 -640 480 -500 375 -488 500 -640 480 -561 640 -640 480 -500 375 -640 480 -640 480 -640 424 -612 612 -612 612 -640 429 -500 401 -640 427 -640 427 -480 640 -640 426 -480 640 -500 375 -640 480 -640 427 -640 360 -640 427 -640 480 -427 640 -425 640 -427 640 -640 480 -640 428 -640 426 -640 480 -640 480 -640 480 -603 640 -640 553 -640 449 -640 480 -640 427 -456 640 -478 640 -428 640 -640 424 -480 640 -640 428 -640 427 -640 438 -640 427 -500 333 -640 480 -500 334 -640 451 -480 640 -640 428 -500 382 -480 640 -640 480 -500 384 -640 427 -640 478 -640 480 -500 375 -351 500 -640 457 -479 640 -640 600 -518 640 -640 441 -480 640 -480 640 -640 426 -640 480 -480 640 -640 480 -426 640 -480 640 -612 612 -640 480 -640 433 -480 640 -500 375 -640 421 -640 480 -640 480 -640 480 -427 640 -480 640 -640 430 -450 450 -640 496 -640 480 -480 640 -480 640 -500 375 -640 427 -640 427 -640 491 -640 480 -640 480 -640 333 -640 427 -386 640 -500 336 -640 480 -600 357 -180 225 -640 480 -640 479 -500 373 -640 426 -500 334 -576 430 -333 500 -612 612 -332 500 -640 427 -480 640 -640 480 -478 640 -480 640 -640 640 -640 480 -640 533 -640 427 -640 480 -640 396 -640 512 -640 426 -640 480 -612 612 -300 200 -640 480 -640 480 -640 480 -640 480 -524 640 -640 320 -640 428 -640 433 -640 427 -640 480 -640 480 -500 375 -640 512 -500 375 -640 480 -427 640 -640 480 -427 640 -640 427 -428 640 -612 612 -640 427 -375 500 -500 333 -333 500 -640 481 -480 640 -640 424 -640 428 -640 480 -640 428 -426 640 -427 640 -399 500 -640 480 -612 612 -640 480 -640 427 -640 427 -427 640 -640 480 -333 500 -640 441 -640 480 -640 426 -640 640 -480 640 -481 640 -334 500 -640 480 -500 375 -375 500 -480 640 -480 640 -640 427 -640 554 -480 640 -640 403 -640 264 -640 480 -397 500 -640 480 -640 427 -640 427 -640 480 -640 428 -610 640 -640 561 -640 427 -480 640 -640 325 -640 480 -480 640 -480 640 -480 640 -640 480 -640 427 -640 480 -640 480 -640 457 -480 640 -640 640 -375 500 -640 427 -480 640 -500 333 -640 428 -640 425 -480 640 -427 640 -640 425 -640 640 -640 480 -478 640 -640 480 -640 429 -600 400 -500 500 -640 480 -640 481 -640 480 -385 308 -640 480 -640 427 -640 428 -640 640 -640 426 -500 375 -640 421 -375 500 -640 471 -640 404 -640 427 -375 500 -463 640 -553 640 -427 640 -418 500 -640 385 -478 640 -517 640 -640 478 -427 640 -640 400 -612 612 -640 271 -500 342 -640 466 -640 467 -640 480 -640 417 -640 427 -612 612 -513 640 -480 640 -640 511 -426 640 -640 425 -339 500 -640 480 -612 612 -480 640 -429 640 -640 458 -488 640 -612 612 -640 427 -640 571 -500 358 -640 425 -640 480 -640 427 -640 512 -640 425 -427 640 -640 480 -640 426 -505 640 -500 333 -640 426 -426 640 -425 640 -426 640 -500 375 -640 427 -640 427 -640 426 -640 608 -500 375 -454 640 -640 427 -640 360 -600 450 -425 640 -640 427 -640 481 -640 423 -640 426 -640 457 -640 480 -480 640 -640 426 -640 480 -640 425 -640 429 -424 640 -640 438 -500 375 -426 640 -428 640 -640 480 -640 427 -640 480 -480 640 -612 612 -500 379 -640 428 -640 480 -640 480 -295 480 -500 375 -640 398 -640 429 -612 612 -640 427 -480 640 -640 432 -640 480 -486 640 -640 480 -640 640 -425 640 -640 426 -640 436 -640 428 -640 454 -640 360 -612 612 -640 453 -612 612 -500 334 -425 640 -640 426 -640 427 -640 480 -480 640 -640 426 -640 463 -640 427 -640 428 -640 513 -640 480 -640 483 -640 425 -640 426 -640 512 -640 426 -470 500 -640 427 -640 359 -640 429 -640 426 -427 640 -640 480 -640 480 -640 447 -640 427 -462 640 -480 640 -640 480 -475 500 -640 480 -640 428 -612 612 -640 481 -640 480 -640 426 -500 375 -640 428 -640 480 -640 640 -296 352 -640 425 -640 480 -640 508 -640 429 -640 640 -640 428 -578 453 -500 375 -640 428 -640 360 -425 640 -640 480 -640 372 -500 334 -640 553 -640 480 -480 640 -640 551 -640 428 -640 427 -428 640 -640 427 -640 428 -640 427 -482 640 -427 640 -375 500 -640 480 -500 400 -640 427 -640 446 -480 640 -480 640 -640 480 -640 480 -427 640 -427 640 -640 480 -640 427 -640 480 -640 480 -640 484 -640 360 -640 480 -612 612 -640 480 -640 480 -640 426 -640 480 -612 612 -640 426 -640 639 -640 480 -640 428 -640 428 -640 427 -640 428 -640 427 -480 640 -640 427 -640 426 -480 640 -640 427 -640 640 -640 478 -640 480 -640 480 -640 427 -375 500 -612 612 -640 427 -640 520 -640 480 -640 427 -640 480 -427 640 -640 480 -480 640 -640 640 -640 426 -640 480 -427 640 -640 427 -640 436 -640 480 -427 640 -375 500 -640 480 -640 480 -640 480 -640 427 -640 427 -500 332 -640 472 -640 480 -640 427 -300 640 -640 480 -360 640 -427 640 -640 480 -640 416 -429 640 -480 640 -640 348 -640 427 -428 640 -640 425 -640 480 -480 640 -640 480 -480 640 -500 432 -640 428 -640 426 -640 428 -640 427 -640 480 -640 640 -427 640 -640 480 -640 468 -500 372 -629 640 -640 480 -500 333 -480 640 -480 640 -426 640 -640 480 -640 427 -480 640 -640 428 -427 640 -428 640 -332 500 -640 360 -612 612 -640 480 -640 480 -640 445 -640 398 -640 457 -640 426 -427 640 -640 426 -640 480 -640 640 -640 425 -640 480 -640 427 -425 640 -640 427 -640 424 -500 334 -640 442 -612 612 -385 289 -640 480 -428 640 -640 401 -500 375 -640 541 -640 428 -640 427 -500 375 -640 480 -500 375 -640 480 -640 408 -500 375 -300 451 -640 429 -500 375 -640 404 -612 612 -500 375 -640 427 -640 528 -640 480 -640 425 -427 640 -640 428 -434 640 -640 426 -392 640 -640 427 -480 640 -500 333 -640 427 -640 480 -640 360 -500 375 -640 480 -640 424 -640 426 -640 425 -430 640 -640 504 -640 480 -640 489 -640 480 -494 338 -398 640 -640 477 -640 425 -426 640 -640 426 -640 424 -640 563 -348 486 -640 480 -640 480 -480 640 -640 458 -640 480 -480 640 -413 481 -640 427 -640 458 -640 427 -640 428 -640 480 -586 640 -640 480 -640 333 -640 480 -640 469 -640 427 -426 640 -612 612 -500 333 -640 427 -480 640 -500 281 -640 415 -640 426 -640 480 -500 380 -640 428 -612 612 -640 427 -640 480 -640 480 -640 336 -375 500 -480 640 -640 426 -640 427 -640 492 -375 500 -448 621 -480 640 -427 640 -426 640 -500 375 -427 640 -640 427 -640 428 -640 416 -500 375 -640 427 -640 428 -480 640 -640 424 -500 375 -640 480 -640 480 -640 480 -640 480 -640 635 -427 640 -640 427 -640 424 -640 480 -640 428 -500 375 -640 427 -640 426 -640 480 -640 480 -500 500 -640 399 -640 361 -480 640 -640 480 -640 417 -500 332 -640 480 -640 427 -640 426 -426 640 -640 427 -640 480 -640 480 -480 640 -427 640 -598 640 -640 480 -333 500 -640 457 -640 425 -612 612 -427 640 -500 375 -640 480 -640 426 -478 640 -640 426 -640 427 -640 427 -500 321 -500 375 -640 481 -640 426 -640 453 -640 480 -640 427 -640 425 -640 480 -640 396 -640 457 -640 427 -640 480 -640 428 -450 500 -487 500 -427 640 -640 427 -500 375 -640 480 -640 480 -640 429 -640 480 -433 640 -640 427 -426 640 -640 425 -640 479 -640 480 -500 335 -640 469 -640 428 -427 640 -427 640 -500 333 -640 427 -640 480 -500 333 -640 480 -612 612 -640 480 -428 640 -500 375 -375 500 -480 640 -640 480 -640 427 -640 480 -516 640 -640 427 -640 479 -640 427 -612 612 -375 500 -640 428 -640 417 -429 640 -499 640 -640 480 -640 480 -427 640 -640 427 -500 375 -640 480 -640 640 -425 640 -480 640 -640 426 -640 480 -428 640 -600 400 -640 521 -640 426 -640 427 -640 427 -640 425 -500 375 -640 480 -640 425 -640 428 -480 640 -428 640 -640 427 -640 480 -640 480 -640 480 -640 480 -640 480 -640 344 -640 430 -479 640 -640 426 -427 640 -640 457 -640 427 -640 426 -640 478 -640 426 -640 513 -640 426 -640 427 -640 427 -480 640 -640 580 -640 433 -640 433 -640 427 -640 480 -640 425 -612 612 -640 546 -500 281 -640 361 -640 427 -427 640 -500 375 -640 401 -640 480 -500 375 -640 427 -640 424 -640 427 -640 423 -480 640 -640 480 -427 640 -367 500 -640 480 -640 480 -640 428 -425 640 -640 425 -480 640 -640 478 -607 640 -500 333 -500 375 -640 427 -640 480 -640 368 -640 428 -640 480 -640 427 -500 337 -640 480 -491 640 -640 427 -640 477 -500 375 -640 433 -640 480 -640 480 -640 427 -425 640 -640 427 -500 454 -555 640 -640 335 -640 480 -640 427 -640 480 -640 480 -640 480 -500 375 -640 427 -500 375 -640 426 -480 640 -640 480 -426 640 -426 640 -427 640 -640 423 -640 468 -640 427 -640 480 -480 640 -375 500 -640 427 -640 480 -500 375 -640 480 -640 480 -640 512 -427 640 -640 480 -640 480 -480 640 -428 640 -640 480 -337 500 -500 375 -640 480 -640 480 -640 440 -640 427 -640 360 -640 427 -640 640 -600 400 -640 480 -640 425 -461 500 -375 500 -480 640 -640 426 -640 480 -612 612 -640 478 -500 333 -375 500 -640 480 -441 640 -427 640 -640 480 -640 480 -640 493 -640 479 -500 375 -640 427 -640 480 -640 480 -640 480 -640 480 -640 480 -500 375 -640 429 -427 640 -640 480 -640 480 -640 361 -640 427 -358 500 -480 640 -640 427 -500 486 -640 213 -640 428 -640 427 -640 480 -640 427 -640 426 -633 640 -375 500 -640 427 -640 462 -640 428 -640 480 -640 427 -640 429 -640 480 -640 427 -375 500 -640 478 -640 480 -480 640 -640 480 -640 427 -459 640 -598 640 -500 375 -427 640 -640 425 -640 478 -640 426 -375 500 -640 426 -640 425 -640 424 -640 479 -640 480 -640 480 -640 259 -361 640 -427 640 -480 640 -640 548 -640 424 -640 425 -640 426 -640 424 -640 427 -612 612 -640 480 -500 313 -640 480 -640 480 -640 480 -478 640 -640 427 -640 480 -640 489 -640 428 -361 640 -428 640 -640 356 -640 418 -500 334 -612 612 -640 480 -396 500 -640 478 -640 427 -600 400 -426 640 -640 480 -500 375 -476 640 -480 640 -640 427 -480 640 -640 427 -640 426 -640 444 -430 640 -640 427 -500 375 -426 640 -480 640 -640 480 -640 480 -640 480 -640 640 -640 427 -640 480 -640 393 -640 480 -640 546 -640 475 -640 480 -640 427 -500 375 -640 423 -640 427 -640 425 -640 480 -640 360 -457 640 -375 500 -640 427 -425 640 -640 427 -480 640 -427 640 -640 425 -640 480 -640 480 -640 480 -640 480 -640 426 -424 640 -640 425 -640 480 -640 480 -500 334 -427 640 -426 640 -640 427 -480 640 -480 640 -640 457 -640 361 -640 428 -418 640 -428 640 -640 480 -640 397 -640 406 -500 342 -478 640 -640 640 -480 640 -640 480 -640 426 -612 612 -375 500 -640 480 -640 360 -640 457 -640 480 -640 428 -640 428 -640 428 -640 318 -640 427 -307 500 -612 612 -640 427 -640 427 -361 500 -480 640 -640 480 -480 640 -640 426 -640 427 -640 426 -640 424 -640 480 -640 513 -640 480 -640 427 -512 640 -612 612 -427 640 -429 640 -640 479 -640 427 -640 427 -640 431 -500 375 -640 360 -480 640 -427 640 -612 612 -640 480 -640 425 -480 640 -500 333 -511 640 -640 427 -640 454 -640 396 -640 360 -640 480 -640 478 -500 375 -640 480 -640 427 -640 358 -640 480 -640 399 -375 500 -640 512 -640 423 -427 640 -500 338 -480 640 -640 425 -428 640 -388 640 -500 375 -640 427 -500 400 -427 640 -640 426 -640 480 -640 427 -640 427 -640 480 -640 480 -640 640 -640 427 -480 640 -640 480 -612 612 -640 480 -417 640 -640 373 -640 479 -640 436 -640 428 -480 640 -640 428 -473 335 -640 479 -480 640 -640 436 -640 427 -640 524 -478 640 -640 480 -480 640 -500 240 -640 478 -640 309 -640 428 -640 480 -480 640 -640 602 -640 432 -427 640 -592 640 -640 427 -640 480 -361 640 -375 500 -600 399 -500 400 -427 640 -640 427 -640 431 -425 640 -640 425 -466 640 -640 427 -640 427 -640 480 -640 425 -640 433 -500 375 -500 332 -375 500 -640 427 -640 393 -500 375 -640 437 -640 360 -480 640 -640 477 -375 500 -612 612 -640 512 -480 640 -480 640 -480 640 -500 333 -426 640 -500 375 -468 640 -375 500 -640 480 -640 436 -640 480 -640 428 -640 429 -640 480 -500 375 -640 427 -419 640 -640 427 -640 524 -480 640 -427 640 -640 480 -640 480 -640 480 -640 423 -640 427 -427 640 -427 640 -469 500 -640 501 -532 640 -640 640 -640 481 -640 426 -640 361 -500 367 -640 393 -500 375 -640 480 -640 480 -640 480 -640 426 -640 425 -512 640 -640 426 -360 640 -375 500 -480 640 -640 424 -480 640 -480 640 -612 612 -500 375 -640 480 -427 640 -552 640 -640 427 -480 640 -612 612 -480 640 -640 480 -640 427 -640 480 -640 427 -640 426 -640 480 -300 400 -480 640 -500 375 -640 480 -360 480 -500 333 -640 386 -500 296 -640 480 -640 640 -640 428 -640 480 -640 427 -640 480 -640 480 -640 425 -500 334 -640 512 -640 480 -640 640 -640 480 -640 462 -640 428 -500 375 -640 480 -640 480 -408 640 -640 480 -640 428 -640 427 -450 313 -640 426 -640 480 -448 640 -640 357 -612 612 -640 425 -640 480 -640 480 -375 500 -640 480 -639 640 -640 480 -480 640 -500 375 -640 427 -640 427 -640 480 -640 425 -640 427 -640 640 -640 478 -640 480 -640 435 -612 612 -640 482 -640 478 -640 494 -500 383 -640 494 -640 416 -640 585 -500 333 -640 480 -480 640 -343 512 -640 410 -428 640 -640 485 -640 480 -428 640 -640 638 -640 480 -612 612 -640 425 -640 553 -640 426 -640 480 -640 479 -426 640 -640 427 -640 427 -640 453 -500 400 -400 500 -640 426 -640 480 -640 426 -200 145 -427 640 -640 480 -640 480 -640 480 -427 640 -640 427 -458 640 -458 640 -500 319 -640 427 -640 386 -640 480 -640 480 -640 427 -500 375 -640 429 -640 457 -640 425 -512 640 -640 426 -640 426 -351 640 -612 612 -375 500 -640 427 -640 480 -612 612 -480 640 -640 360 -456 640 -547 640 -500 333 -640 427 -640 480 -640 480 -640 427 -640 236 -426 640 -640 427 -640 480 -640 480 -640 427 -640 425 -640 378 -500 375 -640 480 -640 479 -640 469 -640 480 -500 311 -640 529 -375 500 -640 427 -640 480 -640 480 -640 226 -480 640 -640 480 -640 425 -377 500 -640 389 -360 640 -640 422 -640 440 -411 640 -640 458 -640 480 -640 480 -640 427 -640 426 -640 478 -640 426 -640 273 -640 480 -640 439 -640 414 -640 481 -640 428 -640 427 -640 480 -640 480 -640 426 -640 427 -387 500 -640 427 -640 480 -500 375 -640 512 -640 426 -640 480 -640 427 -480 640 -640 326 -500 375 -640 283 -512 640 -640 427 -640 480 -500 403 -640 427 -640 480 -640 381 -500 440 -500 375 -333 500 -427 640 -640 425 -640 480 -480 640 -640 427 -640 480 -640 402 -640 427 -640 480 -640 427 -480 640 -427 640 -640 425 -640 495 -640 453 -640 616 -426 640 -639 640 -470 640 -640 470 -640 426 -500 400 -480 640 -640 427 -640 425 -640 480 -640 480 -431 640 -640 427 -500 375 -640 427 -640 427 -512 640 -480 640 -640 259 -640 429 -512 640 -640 428 -640 427 -640 427 -640 427 -640 427 -640 433 -453 640 -500 375 -640 516 -500 375 -640 640 -640 480 -640 425 -640 407 -640 318 -640 480 -640 480 -480 640 -426 640 -462 640 -375 500 -640 360 -640 400 -640 426 -640 427 -640 458 -640 331 -500 375 -428 640 -640 479 -640 426 -640 427 -640 503 -640 427 -640 480 -619 413 -640 480 -512 640 -412 500 -480 640 -500 375 -640 480 -640 480 -480 640 -640 463 -640 480 -640 426 -480 640 -640 428 -374 640 -640 360 -640 480 -478 640 -424 640 -640 427 -426 640 -500 375 -375 500 -640 457 -640 427 -640 427 -427 640 -640 480 -461 500 -412 500 -640 480 -640 428 -301 500 -640 480 -640 480 -500 281 -500 375 -480 640 -640 426 -640 426 -500 375 -480 640 -457 640 -500 400 -640 425 -640 478 -640 640 -427 640 -512 640 -640 480 -500 375 -640 427 -640 480 -640 425 -612 612 -640 480 -640 427 -375 500 -416 640 -640 499 -500 400 -640 480 -640 480 -640 396 -640 480 -640 425 -640 393 -640 640 -640 480 -640 480 -500 442 -640 427 -640 480 -640 223 -640 480 -640 480 -640 480 -640 480 -640 428 -640 480 -640 379 -480 640 -640 427 -365 500 -640 427 -480 640 -640 428 -640 243 -640 480 -640 480 -500 375 -640 428 -426 640 -480 640 -427 640 -500 500 -478 640 -640 427 -480 640 -427 640 -375 500 -428 640 -640 425 -640 444 -640 426 -640 452 -640 427 -640 462 -500 375 -640 640 -640 480 -429 640 -500 500 -640 480 -640 430 -427 640 -375 500 -640 427 -375 500 -640 426 -640 439 -612 612 -640 436 -640 480 -640 428 -412 640 -640 480 -426 640 -640 454 -640 426 -640 480 -375 500 -640 480 -640 640 -640 480 -640 425 -480 640 -640 426 -640 480 -640 427 -500 375 -375 500 -640 468 -428 640 -428 640 -480 640 -480 640 -425 640 -640 428 -427 640 -640 427 -640 414 -612 612 -640 406 -640 480 -640 480 -640 435 -449 640 -640 427 -640 492 -640 480 -480 640 -640 516 -375 500 -640 480 -315 500 -640 426 -640 428 -500 375 -640 480 -428 640 -425 640 -640 426 -480 640 -640 360 -640 348 -640 479 -479 640 -385 289 -640 480 -640 427 -500 346 -374 500 -640 427 -640 427 -640 480 -640 428 -383 640 -640 480 -640 478 -640 428 -640 480 -428 640 -640 480 -202 360 -640 426 -640 375 -500 356 -640 480 -640 581 -640 427 -640 427 -640 640 -480 640 -640 425 -375 500 -500 375 -427 640 -640 400 -640 480 -640 480 -640 480 -335 500 -480 640 -640 424 -640 361 -640 427 -480 640 -375 500 -640 480 -640 480 -640 480 -500 375 -640 480 -480 640 -640 480 -332 500 -640 480 -640 480 -640 480 -427 640 -640 427 -612 612 -640 480 -640 640 -500 375 -640 480 -640 360 -640 427 -333 500 -640 475 -640 428 -640 426 -640 638 -451 640 -480 640 -640 427 -500 375 -480 640 -480 640 -640 480 -427 640 -640 360 -640 480 -640 355 -640 480 -640 480 -640 426 -640 480 -640 621 -640 480 -612 612 -640 428 -500 375 -640 480 -428 640 -640 480 -640 480 -428 640 -640 405 -500 333 -640 427 -480 640 -640 480 -640 424 -500 353 -640 480 -492 500 -640 480 -425 640 -640 428 -480 640 -640 360 -640 427 -614 409 -640 505 -640 427 -640 424 -500 333 -640 480 -500 375 -500 309 -640 516 -640 480 -640 480 -361 640 -426 640 -640 427 -480 640 -640 480 -640 480 -640 480 -640 480 -500 375 -640 396 -640 476 -612 612 -427 640 -640 480 -500 335 -640 428 -640 429 -640 480 -480 640 -640 480 -640 427 -640 427 -640 480 -640 427 -640 385 -427 640 -640 480 -640 480 -480 640 -640 480 -640 480 -500 375 -640 480 -640 480 -493 640 -640 427 -640 480 -640 425 -640 427 -333 500 -640 428 -480 640 -500 375 -500 375 -639 640 -640 596 -640 426 -640 480 -458 640 -640 631 -640 426 -640 400 -640 474 -640 428 -640 640 -640 424 -640 480 -480 640 -640 480 -640 480 -640 480 -640 480 -480 640 -640 480 -640 427 -640 426 -640 471 -640 426 -500 374 -640 482 -640 426 -640 480 -500 333 -640 426 -426 640 -640 427 -480 640 -640 424 -640 494 -640 478 -640 427 -640 480 -640 437 -640 359 -427 640 -640 480 -640 400 -640 480 -640 480 -425 640 -478 640 -640 420 -640 424 -640 425 -640 360 -640 446 -480 640 -480 640 -640 425 -640 427 -640 427 -640 640 -640 480 -640 450 -480 640 -359 640 -500 375 -426 640 -640 427 -640 480 -640 640 -640 480 -640 427 -640 640 -427 640 -500 333 -640 400 -428 640 -480 640 -640 480 -480 640 -640 480 -640 427 -400 500 -640 435 -640 427 -360 640 -425 640 -640 480 -375 500 -640 468 -640 480 -640 480 -425 640 -640 480 -640 388 -640 425 -640 427 -500 375 -640 427 -500 447 -640 427 -500 333 -640 477 -640 427 -640 426 -640 457 -428 640 -640 426 -500 400 -640 427 -478 640 -640 424 -640 425 -640 480 -427 640 -640 461 -640 427 -640 480 -640 494 -612 612 -640 629 -640 426 -427 640 -640 427 -426 640 -640 425 -640 427 -640 480 -640 425 -500 375 -640 480 -480 640 -640 427 -640 480 -480 640 -640 427 -480 640 -640 428 -640 480 -640 480 -480 640 -500 383 -640 424 -640 505 -640 480 -640 426 -376 500 -640 427 -640 494 -640 427 -375 500 -500 376 -480 640 -640 425 -640 480 -427 640 -640 442 -640 480 -640 427 -480 640 -640 427 -640 426 -480 640 -640 451 -640 480 -640 423 -640 640 -640 480 -427 640 -428 640 -500 375 -640 480 -640 389 -364 640 -640 482 -500 300 -427 640 -500 400 -640 427 -612 612 -640 359 -640 480 -640 480 -640 512 -640 406 -640 480 -640 480 -333 500 -640 565 -640 480 -375 500 -640 484 -334 500 -609 640 -640 480 -480 640 -640 480 -640 393 -640 480 -640 427 -640 480 -612 612 -640 359 -612 612 -640 360 -640 480 -640 423 -500 375 -640 427 -640 640 -341 500 -400 600 -427 640 -640 402 -394 640 -640 480 -480 640 -640 429 -640 432 -480 640 -640 480 -640 358 -640 427 -640 427 -480 640 -640 428 -640 480 -640 411 -640 480 -640 480 -640 425 -640 480 -640 480 -640 457 -427 640 -640 480 -480 640 -640 569 -480 640 -640 480 -640 427 -640 433 -640 426 -640 427 -500 375 -640 426 -427 640 -500 500 -640 640 -612 612 -640 480 -640 480 -640 478 -500 500 -640 427 -640 480 -427 640 -480 640 -640 426 -640 427 -500 332 -640 427 -640 425 -480 640 -640 451 -375 500 -480 640 -536 640 -640 481 -640 480 -427 640 -478 640 -339 500 -640 360 -640 480 -480 640 -480 640 -640 480 -640 480 -480 640 -438 640 -640 640 -640 640 -640 359 -640 480 -640 480 -640 427 -640 421 -640 428 -480 640 -471 640 -640 338 -640 539 -640 424 -409 500 -428 640 -640 480 -640 437 -500 332 -640 480 -640 434 -640 480 -640 480 -427 640 -427 640 -480 640 -640 427 -640 480 -640 427 -640 625 -640 480 -640 480 -640 480 -376 500 -640 426 -480 640 -640 640 -640 427 -640 427 -500 333 -424 640 -640 427 -480 640 -425 640 -640 480 -480 640 -640 427 -427 640 -640 427 -500 331 -500 331 -640 426 -640 480 -500 375 -640 480 -500 489 -640 414 -640 480 -480 640 -427 640 -334 640 -640 426 -478 640 -500 332 -428 640 -640 480 -640 359 -480 640 -500 333 -640 522 -640 427 -640 480 -560 640 -427 640 -640 480 -640 480 -640 480 -640 457 -500 375 -557 640 -427 640 -500 334 -640 480 -640 426 -640 488 -640 473 -640 425 -640 480 -500 417 -640 480 -425 640 -640 480 -640 426 -480 640 -500 334 -427 640 -640 428 -640 480 -479 640 -640 640 -640 480 -640 424 -500 500 -640 425 -640 427 -640 360 -375 500 -500 334 -640 427 -640 427 -500 400 -480 640 -640 480 -640 604 -640 480 -640 427 -500 281 -640 426 -333 500 -500 375 -640 480 -640 516 -640 427 -640 480 -640 480 -640 480 -480 640 -640 480 -640 480 -480 640 -426 640 -640 480 -535 480 -640 419 -640 480 -640 427 -427 640 -640 428 -604 453 -500 375 -640 427 -640 428 -612 612 -640 428 -428 640 -427 640 -480 640 -640 469 -640 427 -640 480 -612 612 -640 426 -375 500 -640 427 -640 427 -640 480 -500 375 -640 425 -640 359 -640 480 -640 480 -612 612 -640 439 -640 427 -425 640 -640 480 -640 426 -640 501 -480 640 -640 480 -612 612 -640 427 -333 500 -500 368 -640 427 -640 480 -640 428 -640 436 -640 480 -612 612 -640 444 -640 480 -640 360 -425 640 -640 428 -334 500 -640 517 -500 375 -640 494 -640 611 -640 480 -640 422 -640 426 -640 429 -478 640 -480 640 -640 480 -375 500 -640 640 -640 480 -427 640 -640 480 -480 640 -561 640 -500 375 -428 640 -640 281 -640 480 -640 428 -640 427 -480 640 -640 480 -425 640 -375 500 -600 469 -640 480 -640 427 -640 426 -640 427 -640 482 -587 640 -640 427 -640 426 -480 640 -640 491 -640 444 -640 426 -424 640 -640 480 -640 384 -426 640 -640 408 -640 425 -640 406 -640 427 -640 351 -640 425 -480 640 -375 500 -426 640 -640 425 -640 427 -339 500 -640 284 -480 640 -640 427 -480 640 -640 480 -640 479 -335 500 -640 478 -640 426 -375 500 -446 640 -640 429 -640 427 -427 640 -640 425 -640 480 -640 511 -427 640 -500 375 -640 425 -426 640 -640 640 -640 480 -480 640 -640 427 -640 448 -375 500 -427 640 -640 427 -640 480 -480 640 -640 531 -480 640 -640 480 -640 427 -640 480 -640 425 -640 480 -640 260 -640 427 -426 640 -640 427 -640 483 -333 500 -640 425 -640 434 -427 640 -500 378 -500 375 -640 383 -500 375 -480 640 -640 480 -428 640 -640 480 -640 428 -640 427 -640 427 -480 640 -640 494 -640 425 -640 480 -640 427 -640 427 -640 480 -640 480 -500 375 -640 480 -640 428 -640 480 -500 358 -500 375 -612 612 -500 333 -640 464 -500 279 -398 500 -640 429 -500 332 -480 640 -600 400 -500 375 -640 480 -480 640 -478 640 -375 500 -500 375 -640 480 -480 640 -381 500 -586 640 -640 390 -500 334 -640 480 -640 480 -640 424 -640 573 -640 512 -500 375 -640 360 -425 640 -640 480 -490 640 -471 640 -500 375 -640 426 -640 640 -640 480 -640 480 -640 427 -640 480 -640 427 -500 332 -640 480 -500 375 -640 480 -640 427 -640 495 -427 640 -640 480 -640 575 -640 398 -434 640 -640 480 -428 640 -427 640 -640 478 -640 426 -640 428 -500 326 -640 441 -640 418 -427 640 -479 640 -640 480 -612 612 -332 500 -375 500 -480 640 -425 640 -640 480 -500 313 -640 427 -640 426 -640 425 -640 480 -640 428 -427 640 -427 640 -640 480 -640 640 -640 427 -640 428 -640 480 -480 640 -640 427 -640 480 -640 416 -640 480 -640 426 -640 480 -427 640 -640 480 -640 480 -427 640 -428 640 -427 640 -480 640 -640 480 -640 480 -480 640 -640 427 -640 480 -640 480 -640 473 -500 375 -640 528 -427 640 -640 427 -640 427 -640 427 -500 333 -500 500 -426 640 -480 640 -500 375 -500 375 -287 500 -612 612 -640 427 -480 640 -640 480 -473 640 -573 640 -640 427 -480 640 -640 361 -500 333 -500 335 -480 640 -640 478 -640 480 -424 640 -640 428 -640 640 -640 480 -612 612 -640 531 -640 480 -640 480 -640 426 -640 435 -640 424 -640 346 -480 640 -640 427 -640 480 -640 427 -375 500 -640 480 -640 480 -640 480 -640 476 -500 320 -640 428 -640 480 -640 427 -612 612 -640 483 -439 640 -640 431 -500 375 -500 375 -640 480 -640 427 -480 640 -640 424 -640 426 -640 480 -640 436 -478 640 -640 427 -640 480 -640 350 -640 427 -640 427 -640 480 -640 480 -478 640 -640 480 -640 480 -480 640 -640 640 -640 425 -480 640 -640 427 -480 640 -480 640 -640 583 -640 427 -640 480 -640 480 -640 360 -640 480 -640 480 -640 480 -640 480 -640 480 -441 640 -640 480 -612 612 -640 480 -431 640 -640 426 -375 500 -640 481 -500 375 -640 480 -599 640 -640 426 -640 427 -500 300 -640 427 -640 480 -640 380 -500 333 -640 443 -426 640 -640 427 -364 500 -640 480 -640 480 -640 426 -427 640 -640 480 -640 480 -640 480 -424 640 -427 640 -640 480 -640 480 -612 612 -640 480 -640 324 -640 449 -640 329 -640 426 -640 360 -640 480 -500 332 -500 375 -640 480 -640 480 -640 480 -375 500 -640 360 -640 504 -560 640 -480 640 -500 327 -640 426 -640 426 -362 500 -427 640 -500 358 -640 428 -640 425 -640 480 -640 427 -640 351 -640 426 -640 428 -640 429 -640 427 -640 503 -640 427 -640 428 -640 480 -640 427 -640 480 -640 361 -640 360 -640 480 -375 500 -480 640 -640 480 -640 427 -640 428 -640 480 -640 480 -640 359 -640 360 -351 500 -434 640 -640 480 -426 640 -640 427 -640 428 -640 480 -640 427 -640 427 -640 429 -640 426 -640 424 -640 254 -387 604 -640 486 -640 480 -640 480 -640 480 -640 480 -640 480 -480 640 -359 640 -640 480 -480 640 -640 480 -427 640 -612 612 -640 321 -500 500 -640 428 -640 427 -640 480 -640 534 -640 479 -500 375 -640 480 -500 429 -640 428 -500 375 -640 640 -640 640 -640 425 -640 419 -514 597 -640 480 -612 612 -640 479 -640 511 -640 425 -640 427 -400 343 -640 428 -640 426 -640 427 -640 480 -640 426 -640 480 -640 640 -640 480 -640 413 -640 387 -640 426 -428 640 -640 480 -640 427 -640 427 -640 426 -640 480 -640 512 -425 640 -640 424 -640 488 -500 332 -640 426 -640 524 -480 640 -640 480 -500 375 -593 640 -640 427 -640 426 -478 640 -640 427 -408 640 -427 640 -640 480 -640 480 -640 428 -640 428 -640 485 -500 375 -640 480 -480 640 -640 427 -480 640 -640 408 -640 480 -500 399 -480 640 -480 640 -640 424 -640 480 -375 500 -500 375 -640 427 -640 480 -640 170 -640 415 -480 640 -640 402 -500 378 -480 640 -480 640 -500 332 -640 511 -640 427 -640 480 -640 427 -640 421 -640 428 -640 424 -640 388 -640 640 -640 480 -640 427 -640 425 -640 457 -640 427 -480 640 -640 427 -500 375 -640 480 -500 375 -640 428 -500 333 -480 640 -640 512 -480 640 -640 480 -427 640 -640 480 -640 480 -500 333 -640 427 -480 640 -640 428 -640 427 -601 640 -640 480 -500 315 -640 480 -640 425 -640 479 -478 640 -640 478 -612 612 -640 480 -427 640 -480 640 -640 396 -614 461 -640 360 -500 375 -640 400 -640 480 -640 468 -640 427 -480 640 -640 426 -640 480 -640 427 -478 640 -480 640 -640 481 -640 480 -500 375 -640 426 -640 329 -640 427 -640 480 -640 427 -640 480 -640 427 -640 427 -480 640 -640 431 -640 512 -640 428 -640 425 -640 480 -508 640 -480 640 -640 427 -480 640 -640 480 -640 425 -640 480 -640 480 -640 428 -640 425 -640 480 -640 427 -640 480 -640 480 -480 640 -640 431 -612 612 -500 333 -559 640 -640 427 -640 480 -640 480 -612 612 -640 480 -480 640 -640 469 -640 396 -640 480 -640 427 -640 480 -640 425 -640 480 -498 640 -640 318 -640 480 -640 480 -500 375 -484 640 -640 427 -640 640 -640 480 -640 427 -640 426 -640 427 -640 346 -640 427 -640 523 -640 428 -400 640 -500 343 -640 480 -640 425 -640 427 -427 640 -428 640 -375 500 -426 640 -640 426 -640 424 -640 462 -640 480 -375 500 -500 375 -640 328 -480 640 -640 359 -640 463 -640 640 -421 640 -640 480 -427 640 -640 564 -640 478 -640 640 -480 640 -640 427 -480 640 -448 299 -640 359 -612 612 -640 427 -640 480 -640 480 -640 427 -640 396 -640 480 -425 640 -640 480 -365 500 -500 375 -427 640 -480 640 -640 480 -300 351 -640 478 -640 480 -640 439 -640 401 -640 427 -640 427 -640 409 -640 512 -450 300 -500 375 -640 480 -480 640 -480 640 -640 427 -640 428 -500 375 -427 640 -500 400 -640 480 -480 640 -480 640 -640 426 -427 640 -640 426 -640 427 -500 375 -612 612 -375 500 -640 427 -640 486 -500 375 -500 332 -640 464 -640 428 -500 332 -640 640 -640 426 -640 481 -480 640 -640 480 -427 640 -500 375 -640 478 -640 480 -640 640 -640 512 -640 480 -640 427 -640 427 -640 480 -640 427 -640 480 -640 425 -500 332 -640 480 -425 640 -446 640 -614 640 -640 480 -640 480 -426 640 -640 428 -500 363 -640 480 -640 480 -640 428 -640 640 -640 480 -640 480 -640 482 -450 600 -640 424 -640 480 -376 500 -640 480 -480 640 -640 480 -640 427 -427 640 -640 480 -640 478 -640 478 -640 480 -640 479 -640 480 -457 640 -375 500 -428 640 -640 261 -640 400 -640 480 -477 640 -428 640 -640 426 -612 612 -480 640 -640 426 -428 640 -640 427 -640 427 -640 480 -500 500 -500 375 -442 640 -640 429 -640 480 -640 480 -480 640 -640 480 -411 411 -375 500 -640 478 -640 427 -640 480 -427 640 -500 375 -640 480 -427 640 -640 427 -640 480 -640 426 -640 463 -640 480 -640 480 -640 480 -427 640 -640 480 -480 640 -640 426 -500 375 -640 427 -640 480 -640 480 -640 434 -425 640 -640 480 -548 640 -333 500 -640 309 -640 480 -640 427 -640 480 -640 359 -640 480 -480 640 -640 360 -640 427 -480 640 -640 427 -640 480 -640 434 -640 480 -500 375 -640 480 -640 318 -640 427 -480 640 -640 427 -480 640 -408 640 -478 640 -500 356 -640 480 -640 428 -640 427 -640 426 -640 427 -640 427 -640 427 -640 480 -640 458 -640 480 -640 480 -427 640 -427 640 -480 640 -640 429 -640 480 -640 480 -640 427 -640 427 -640 480 -375 500 -375 500 -612 612 -640 428 -640 427 -612 612 -640 427 -640 439 -427 640 -640 427 -640 423 -427 640 -500 438 -446 640 -500 356 -640 427 -640 480 -640 480 -640 433 -640 480 -480 640 -640 427 -640 480 -640 426 -640 480 -640 329 -320 240 -640 512 -640 519 -640 427 -640 425 -640 426 -640 435 -640 426 -640 446 -640 480 -375 500 -640 428 -640 513 -640 425 -640 480 -640 423 -640 600 -480 640 -427 640 -480 640 -632 640 -640 480 -640 480 -640 480 -640 425 -427 640 -500 500 -480 640 -640 426 -640 423 -480 640 -427 640 -640 360 -612 612 -640 480 -640 480 -480 640 -640 441 -426 640 -375 500 -640 439 -640 424 -640 428 -640 480 -480 640 -640 453 -640 480 -640 480 -428 640 -640 427 -480 640 -335 500 -375 500 -427 640 -640 425 -500 333 -500 281 -500 375 -640 427 -640 480 -640 385 -640 431 -640 480 -640 480 -640 480 -425 640 -500 331 -640 426 -500 333 -480 640 -640 427 -640 425 -640 639 -640 480 -640 480 -375 500 -333 500 -640 399 -480 640 -640 429 -640 428 -640 478 -640 426 -480 640 -640 558 -640 427 -640 548 -558 640 -640 480 -427 640 -640 360 -640 428 -640 480 -640 428 -640 360 -480 640 -640 480 -640 480 -616 640 -640 427 -500 375 -423 640 -500 375 -375 500 -640 426 -640 428 -640 427 -427 640 -640 476 -640 360 -640 428 -640 426 -640 426 -640 480 -480 640 -500 375 -640 480 -500 400 -480 640 -640 454 -428 640 -640 421 -640 429 -640 480 -640 427 -640 425 -314 640 -640 480 -640 370 -640 427 -632 640 -640 478 -433 640 -640 480 -640 479 -640 427 -427 640 -500 375 -640 430 -333 500 -640 480 -478 640 -640 480 -640 480 -640 428 -612 612 -500 375 -640 400 -640 412 -640 481 -375 500 -333 500 -425 640 -480 640 -640 480 -640 422 -480 640 -432 640 -640 480 -640 359 -640 479 -427 640 -500 384 -640 480 -640 480 -500 400 -640 426 -640 480 -640 404 -640 478 -500 335 -640 480 -640 480 -640 360 -640 457 -640 518 -640 480 -640 381 -427 640 -640 427 -640 425 -640 427 -640 427 -640 427 -500 375 -480 640 -640 480 -640 480 -640 425 -640 425 -640 427 -500 375 -640 428 -640 480 -582 416 -640 388 -640 480 -500 333 -500 333 -640 512 -480 640 -640 425 -640 426 -640 480 -640 640 -640 428 -640 512 -640 426 -640 480 -500 336 -640 480 -427 640 -500 375 -425 640 -603 640 -427 640 -333 500 -612 612 -500 375 -640 480 -640 480 -640 512 -640 639 -640 500 -375 500 -640 426 -640 480 -640 427 -640 426 -640 480 -428 640 -640 480 -640 480 -474 640 -500 375 -480 640 -640 480 -480 640 -640 426 -640 480 -640 426 -640 427 -612 612 -426 640 -640 424 -375 500 -612 612 -640 427 -640 428 -640 427 -428 640 -399 640 -640 480 -421 640 -429 640 -640 406 -500 375 -500 361 -640 480 -640 481 -640 424 -401 500 -640 480 -640 480 -640 194 -640 554 -640 229 -640 462 -427 640 -480 640 -500 334 -500 375 -375 500 -640 516 -640 427 -640 426 -640 480 -640 480 -640 427 -640 359 -427 640 -640 427 -640 420 -425 640 -514 640 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -500 333 -640 453 -478 640 -640 318 -640 480 -640 480 -640 427 -640 480 -640 480 -500 290 -500 375 -640 480 -640 480 -640 427 -640 410 -337 500 -640 426 -640 480 -612 612 -640 480 -640 480 -640 640 -640 480 -421 640 -640 360 -640 427 -500 375 -500 332 -500 375 -640 480 -640 480 -640 480 -640 480 -640 426 -640 427 -500 375 -400 500 -640 427 -399 640 -640 427 -640 427 -640 480 -640 425 -640 431 -500 333 -640 480 -640 571 -640 640 -640 360 -436 640 -480 640 -640 480 -640 480 -480 640 -612 612 -640 553 -480 640 -640 480 -640 426 -479 640 -640 480 -640 480 -500 375 -427 640 -480 640 -640 518 -640 425 -480 640 -640 306 -640 427 -640 424 -640 427 -640 480 -333 500 -640 427 -640 405 -640 329 -457 640 -640 469 -500 375 -425 640 -436 640 -640 480 -494 500 -437 640 -640 480 -640 451 -640 480 -640 427 -500 281 -612 612 -640 480 -640 480 -640 427 -480 640 -640 460 -480 640 -640 427 -640 480 -640 426 -359 640 -500 380 -640 427 -427 640 -640 425 -640 480 -640 480 -640 480 -640 428 -640 424 -640 383 -480 640 -612 612 -640 427 -640 480 -384 640 -640 436 -640 480 -425 640 -479 640 -427 640 -640 478 -482 640 -640 426 -480 640 -640 480 -640 480 -457 640 -640 480 -640 427 -375 500 -517 640 -307 409 -612 612 -640 428 -640 428 -500 333 -640 503 -640 640 -640 616 -640 600 -640 480 -640 427 -640 480 -640 428 -500 375 -640 425 -640 480 -640 428 -640 478 -640 427 -640 421 -640 480 -640 480 -640 480 -500 375 -640 426 -640 423 -640 477 -640 609 -427 640 -427 640 -640 480 -500 311 -375 500 -480 640 -640 427 -640 427 -469 469 -640 480 -640 427 -500 370 -640 454 -640 480 -640 426 -640 427 -426 640 -427 640 -333 500 -426 640 -640 330 -491 500 -424 500 -640 480 -333 500 -413 450 -640 448 -411 640 -640 426 -410 310 -500 332 -640 424 -640 427 -640 640 -500 375 -410 640 -640 480 -380 500 -640 480 -640 480 -480 640 -640 426 -640 480 -478 640 -640 480 -640 429 -500 364 -640 226 -640 148 -480 640 -640 480 -389 640 -640 428 -640 424 -640 471 -480 640 -640 457 -640 513 -640 427 -480 640 -640 419 -316 500 -500 375 -640 427 -640 480 -640 480 -640 480 -428 640 -640 427 -640 427 -640 480 -500 333 -640 480 -500 333 -640 427 -383 500 -640 465 -640 427 -640 427 -500 375 -640 494 -612 612 -640 480 -640 480 -424 640 -640 480 -640 428 -640 480 -640 480 -640 427 -475 640 -640 566 -640 480 -640 427 -500 400 -640 383 -640 427 -612 612 -480 640 -500 400 -612 612 -640 480 -640 453 -480 640 -500 375 -640 427 -640 480 -640 427 -556 640 -480 640 -640 381 -640 480 -640 427 -640 418 -500 375 -500 281 -480 640 -360 640 -640 402 -640 427 -515 640 -500 500 -640 428 -640 427 -640 427 -640 480 -640 480 -618 640 -640 480 -640 480 -640 393 -640 480 -640 426 -640 640 -540 640 -640 640 -640 427 -500 375 -458 640 -640 427 -640 427 -640 481 -500 433 -426 640 -640 480 -640 416 -640 480 -480 640 -640 454 -500 421 -428 640 -640 480 -640 480 -426 640 -640 264 -459 640 -640 426 -640 444 -375 500 -640 467 -640 428 -500 334 -640 480 -427 640 -640 480 -640 478 -640 480 -426 640 -480 640 -375 500 -426 640 -640 480 -427 640 -427 640 -612 612 -640 436 -640 432 -428 640 -640 480 -480 640 -640 428 -640 480 -640 427 -640 480 -640 360 -424 640 -640 359 -640 480 -640 480 -640 427 -640 480 -640 480 -500 375 -500 375 -600 400 -640 480 -375 500 -640 480 -640 512 -480 640 -427 640 -640 480 -388 640 -640 480 -640 480 -640 427 -640 480 -500 375 -441 640 -478 640 -640 427 -425 640 -612 612 -640 428 -640 480 -640 404 -640 480 -640 480 -419 640 -427 640 -640 523 -640 427 -500 375 -640 427 -375 500 -500 381 -640 480 -640 361 -640 480 -640 480 -640 429 -640 480 -640 480 -500 375 -425 640 -612 612 -640 398 -480 640 -480 640 -600 450 -640 309 -500 403 -640 480 -640 480 -427 640 -480 640 -640 541 -640 478 -537 640 -640 427 -480 640 -640 480 -640 426 -640 360 -427 640 -427 640 -640 429 -427 640 -361 640 -640 427 -500 375 -640 340 -640 480 -640 428 -480 640 -640 334 -640 480 -640 273 -640 426 -640 426 -612 612 -500 375 -427 640 -640 480 -640 433 -640 480 -640 342 -640 457 -640 427 -640 480 -640 541 -480 640 -403 500 -480 640 -500 375 -480 640 -633 640 -640 427 -640 426 -640 424 -640 427 -640 480 -640 436 -640 425 -640 480 -480 640 -428 640 -500 375 -640 480 -360 270 -640 428 -640 361 -640 480 -640 480 -640 231 -640 512 -360 640 -640 603 -640 480 -640 428 -426 640 -640 480 -427 640 -640 427 -302 500 -426 640 -640 427 -640 427 -500 333 -640 427 -640 427 -640 426 -640 341 -500 341 -640 428 -480 640 -640 427 -500 447 -640 554 -640 480 -426 640 -640 480 -640 480 -567 470 -480 640 -640 428 -418 640 -480 640 -640 427 -640 480 -640 480 -640 480 -521 640 -640 480 -427 640 -500 334 -640 480 -640 480 -640 426 -640 480 -640 480 -640 477 -640 382 -480 640 -480 640 -640 429 -640 425 -640 427 -640 526 -500 375 -640 426 -640 427 -476 640 -640 480 -640 461 -375 500 -640 426 -640 480 -640 480 -640 294 -640 359 -469 640 -252 640 -640 427 -640 427 -640 480 -427 640 -500 375 -553 640 -640 450 -640 424 -640 480 -500 375 -426 640 -640 428 -427 640 -334 500 -350 640 -640 498 -500 333 -640 480 -640 480 -640 426 -480 640 -240 320 -640 640 -640 480 -640 427 -640 480 -640 531 -500 375 -480 640 -564 640 -640 480 -640 480 -500 473 -640 425 -640 406 -480 640 -640 480 -640 427 -500 375 -640 480 -480 640 -640 480 -360 640 -640 480 -578 640 -480 640 -640 426 -640 478 -640 427 -640 640 -640 480 -640 480 -480 640 -427 640 -640 427 -500 333 -425 640 -503 640 -375 500 -427 640 -640 427 -427 640 -480 640 -640 424 -640 480 -500 375 -640 427 -640 480 -640 479 -433 640 -640 425 -480 640 -458 640 -640 426 -636 478 -479 640 -640 572 -640 462 -640 425 -480 640 -640 480 -640 480 -640 480 -640 426 -640 480 -640 427 -640 480 -640 501 -640 480 -640 444 -640 457 -640 425 -640 427 -640 428 -640 388 -426 640 -640 424 -640 480 -640 386 -640 427 -333 500 -640 480 -480 640 -493 640 -426 640 -480 640 -640 427 -426 640 -640 480 -640 427 -640 511 -640 427 -640 640 -640 480 -458 640 -427 640 -480 640 -640 345 -640 480 -640 426 -480 640 -640 305 -640 480 -640 427 -640 428 -640 480 -640 427 -640 427 -640 427 -498 640 -500 332 -511 640 -478 640 -640 480 -640 480 -427 640 -640 427 -514 640 -424 640 -640 480 -640 425 -500 333 -640 425 -640 480 -500 375 -640 424 -640 360 -640 480 -640 480 -427 640 -640 480 -640 360 -640 480 -430 640 -640 480 -427 640 -640 480 -640 480 -375 500 -474 640 -640 425 -640 480 -640 593 -640 480 -640 425 -480 640 -640 425 -640 427 -500 375 -640 326 -500 375 -640 480 -640 427 -640 480 -612 612 -640 427 -640 458 -500 334 -640 411 -640 358 -500 375 -428 640 -427 640 -612 612 -480 640 -426 640 -526 640 -333 500 -426 640 -640 457 -500 374 -640 392 -612 612 -640 427 -640 393 -640 480 -480 640 -551 640 -612 612 -640 563 -640 427 -640 480 -640 640 -582 640 -640 480 -288 352 -640 427 -640 417 -640 425 -480 640 -500 375 -640 480 -640 470 -640 480 -640 480 -402 500 -640 428 -640 425 -640 428 -640 427 -427 640 -640 480 -640 480 -478 640 -640 480 -480 640 -480 640 -640 428 -640 453 -640 427 -640 427 -640 424 -500 375 -500 375 -427 640 -640 427 -480 640 -640 480 -640 426 -480 640 -400 600 -640 424 -401 401 -640 480 -500 335 -640 480 -640 480 -428 640 -640 480 -640 640 -640 427 -640 480 -640 450 -640 480 -640 480 -640 422 -612 612 -478 640 -640 429 -480 640 -480 640 -640 399 -640 466 -480 640 -640 427 -640 480 -428 640 -480 640 -640 480 -612 612 -480 640 -640 480 -480 640 -640 614 -640 457 -640 457 -640 425 -640 429 -500 375 -640 480 -333 500 -480 640 -634 640 -480 640 -640 359 -640 427 -640 480 -640 428 -500 375 -640 480 -640 426 -640 424 -640 328 -640 428 -375 500 -427 640 -640 427 -428 640 -640 429 -411 640 -427 640 -480 640 -480 640 -640 427 -640 433 -640 361 -333 500 -640 427 -480 640 -640 428 -427 640 -640 427 -640 427 -640 425 -480 640 -640 428 -640 640 -640 480 -640 426 -640 427 -640 480 -640 640 -640 480 -640 480 -612 612 -427 640 -375 500 -500 495 -640 411 -478 640 -612 612 -500 375 -640 480 -640 379 -640 426 -640 480 -480 640 -640 480 -640 479 -426 640 -480 640 -480 640 -640 424 -640 428 -640 425 -640 426 -640 480 -640 425 -427 640 -640 399 -640 423 -640 428 -640 427 -640 480 -640 430 -640 450 -640 480 -480 640 -640 427 -640 457 -640 480 -640 480 -480 640 -640 480 -640 480 -640 426 -640 426 -640 480 -640 421 -640 504 -640 427 -473 640 -640 480 -640 480 -640 480 -640 427 -427 640 -640 423 -500 398 -640 427 -640 427 -640 480 -500 386 -640 426 -640 480 -640 480 -640 428 -427 640 -640 461 -427 640 -640 427 -480 640 -480 640 -500 334 -640 427 -594 640 -488 640 -640 480 -400 604 -640 426 -500 334 -411 640 -640 482 -425 640 -640 359 -640 427 -480 640 -426 640 -640 443 -640 480 -640 445 -427 640 -640 425 -640 464 -427 640 -500 375 -640 480 -640 490 -640 480 -640 509 -640 360 -640 429 -640 639 -425 640 -640 427 -640 429 -640 360 -640 427 -500 375 -640 427 -640 480 -333 500 -640 480 -500 375 -640 480 -640 480 -500 334 -500 382 -557 640 -640 360 -640 427 -427 640 -640 425 -640 480 -640 478 -640 480 -500 461 -640 458 -640 426 -640 387 -640 427 -640 501 -640 480 -500 334 -640 426 -500 333 -640 425 -480 640 -375 500 -480 640 -640 427 -640 480 -640 417 -640 480 -500 375 -640 428 -426 640 -640 456 -640 429 -333 500 -612 612 -500 333 -640 427 -428 640 -331 500 -640 512 -427 640 -640 428 -640 480 -640 509 -640 427 -640 427 -500 333 -427 640 -640 481 -480 640 -480 640 -640 427 -409 640 -640 426 -426 640 -640 428 -640 480 -640 359 -640 427 -500 375 -640 476 -612 612 -425 640 -640 480 -640 480 -640 480 -640 480 -480 640 -640 359 -453 640 -600 422 -203 179 -640 427 -640 426 -640 463 -640 426 -640 425 -480 640 -480 640 -316 425 -640 469 -640 359 -457 640 -640 427 -640 640 -332 500 -640 480 -500 423 -500 500 -640 426 -415 640 -640 428 -640 480 -640 640 -538 640 -640 480 -640 427 -640 480 -500 352 -640 480 -640 436 -500 375 -640 425 -640 457 -400 400 -640 427 -640 427 -480 640 -427 640 -640 480 -486 640 -640 427 -480 640 -640 427 -640 427 -425 640 -640 359 -500 375 -640 480 -640 478 -480 640 -640 480 -640 480 -640 480 -640 298 -640 491 -640 480 -428 640 -640 359 -640 360 -427 640 -428 640 -640 480 -478 640 -478 640 -427 640 -640 480 -640 480 -640 425 -338 500 -500 375 -500 281 -640 480 -480 640 -640 427 -640 513 -428 640 -375 500 -500 375 -612 612 -640 422 -426 640 -425 640 -500 375 -537 640 -640 480 -640 480 -640 480 -427 640 -640 427 -612 612 -640 480 -640 450 -640 457 -640 480 -334 500 -480 640 -640 427 -640 480 -350 350 -427 640 -640 427 -640 427 -500 346 -640 480 -319 500 -336 500 -640 427 -612 612 -640 480 -640 480 -480 640 -527 640 -333 500 -640 512 -500 375 -500 375 -320 240 -640 480 -480 640 -640 480 -480 640 -640 428 -640 480 -480 640 -640 427 -640 423 -640 480 -640 480 -428 640 -640 480 -500 333 -640 480 -427 640 -427 640 -640 480 -640 481 -640 480 -640 427 -640 425 -406 640 -640 164 -640 480 -640 640 -640 428 -500 375 -500 375 -640 408 -640 480 -640 381 -640 425 -480 640 -427 640 -400 500 -640 425 -640 426 -333 500 -426 640 -480 640 -480 640 -640 480 -640 480 -640 425 -640 428 -640 427 -480 640 -640 480 -640 427 -640 424 -640 426 -640 478 -640 427 -426 640 -500 375 -640 480 -640 459 -640 428 -500 375 -640 426 -640 640 -427 640 -640 404 -640 426 -640 425 -360 640 -640 480 -640 426 -640 361 -500 375 -640 480 -640 480 -383 640 -640 427 -500 375 -480 640 -640 480 -640 480 -480 640 -640 428 -640 480 -640 480 -500 343 -640 426 -640 480 -424 640 -640 446 -426 640 -640 480 -600 399 -427 640 -300 225 -480 640 -363 640 -640 480 -640 434 -398 640 -640 426 -640 428 -480 640 -500 334 -425 640 -640 480 -640 427 -640 480 -480 640 -640 480 -640 480 -480 640 -640 428 -640 427 -640 427 -480 640 -640 480 -480 640 -427 640 -640 496 -480 640 -640 512 -640 480 -640 433 -640 427 -640 427 -426 640 -427 640 -352 288 -640 426 -640 427 -500 375 -640 426 -640 480 -640 427 -640 425 -427 640 -640 480 -640 426 -640 480 -500 434 -640 480 -640 426 -426 640 -375 500 -406 500 -427 640 -640 467 -476 640 -421 640 -640 480 -640 427 -500 375 -448 640 -640 480 -640 426 -640 418 -640 480 -500 375 -640 448 -427 640 -480 640 -640 373 -640 426 -640 443 -428 640 -640 466 -640 480 -640 480 -480 640 -640 480 -640 480 -640 480 -640 480 -640 427 -640 480 -640 427 -640 428 -600 450 -640 429 -375 500 -640 428 -426 640 -640 427 -640 512 -640 426 -640 480 -500 318 -640 428 -500 375 -500 376 -640 480 -640 427 -640 428 -448 336 -640 480 -640 480 -640 443 -640 480 -500 333 -500 333 -640 480 -422 640 -640 479 -500 333 -640 479 -640 480 -640 640 -640 425 -480 640 -640 425 -640 480 -441 640 -500 333 -640 570 -500 375 -640 429 -480 640 -640 481 -640 386 -640 437 -640 480 -640 428 -640 480 -640 425 -640 427 -640 320 -500 356 -500 286 -640 426 -427 640 -640 480 -640 480 -427 640 -640 480 -640 427 -628 640 -480 640 -640 427 -426 640 -640 480 -612 612 -640 480 -480 640 -640 639 -480 640 -375 500 -375 500 -640 480 -640 429 -640 426 -500 343 -640 480 -640 425 -426 640 -640 427 -640 480 -426 640 -500 375 -640 425 -640 427 -640 427 -434 296 -640 426 -612 612 -500 375 -640 480 -640 480 -640 426 -480 640 -640 480 -640 427 -640 546 -478 640 -640 480 -640 480 -480 640 -612 612 -640 427 -640 427 -640 480 -640 489 -500 333 -640 440 -640 427 -427 640 -640 426 -640 480 -640 427 -640 639 -640 480 -500 350 -467 640 -640 427 -426 640 -446 640 -640 481 -480 640 -640 426 -640 510 -640 480 -477 640 -640 427 -612 612 -640 480 -640 512 -640 480 -640 429 -640 427 -640 428 -509 640 -429 640 -640 299 -640 480 -640 480 -500 332 -640 480 -500 400 -640 401 -640 480 -640 480 -640 427 -640 480 -640 480 -640 538 -334 500 -480 640 -640 480 -640 424 -500 334 -640 480 -362 640 -640 360 -640 501 -640 457 -640 426 -640 428 -480 640 -640 425 -515 640 -640 480 -640 426 -640 480 -480 640 -640 429 -640 429 -480 640 -640 480 -640 480 -640 480 -500 375 -640 339 -640 372 -500 333 -640 480 -500 375 -427 640 -640 480 -369 520 -640 427 -640 480 -427 640 -500 334 -640 480 -640 480 -500 332 -640 480 -500 375 -640 428 -640 427 -640 480 -640 426 -640 480 -640 460 -640 480 -458 640 -640 480 -640 640 -640 387 -640 480 -640 428 -640 428 -640 480 -640 426 -640 480 -640 425 -640 379 -480 640 -427 640 -640 480 -640 427 -612 612 -640 276 -640 480 -640 426 -640 427 -640 427 -465 640 -640 480 -400 500 -640 476 -640 428 -640 480 -640 446 -640 480 -640 480 -376 500 -640 427 -640 427 -640 426 -500 333 -640 480 -500 375 -640 406 -640 361 -640 478 -612 612 -640 310 -500 496 -640 426 -640 427 -640 359 -640 480 -640 427 -640 480 -480 640 -640 360 -640 425 -604 453 -640 421 -500 354 -500 375 -640 467 -640 480 -500 335 -425 640 -640 427 -640 427 -480 640 -640 413 -640 427 -640 480 -640 518 -640 480 -640 427 -640 336 -640 480 -640 427 -427 640 -640 640 -566 640 -480 640 -500 346 -640 480 -480 640 -480 640 -427 640 -640 425 -426 640 -640 559 -640 480 -500 342 -500 500 -640 448 -640 380 -640 424 -426 640 -640 427 -640 427 -640 427 -640 427 -500 419 -480 640 -480 640 -640 427 -640 480 -640 427 -640 425 -640 427 -640 427 -500 333 -375 500 -640 480 -640 480 -640 434 -640 480 -426 640 -375 500 -612 612 -480 640 -640 427 -640 427 -480 640 -640 426 -640 427 -640 360 -640 480 -640 427 -640 427 -640 480 -600 402 -640 428 -428 640 -640 512 -640 428 -408 500 -640 480 -640 480 -640 427 -500 375 -426 640 -640 640 -480 640 -480 640 -640 360 -640 427 -640 427 -640 426 -640 424 -480 640 -640 433 -360 480 -500 375 -640 479 -640 480 -427 640 -640 480 -640 457 -640 640 -640 490 -500 333 -446 640 -640 480 -640 567 -640 480 -640 404 -640 427 -640 478 -640 426 -500 441 -357 640 -640 429 -640 425 -640 427 -640 427 -612 612 -640 480 -360 640 -640 424 -640 386 -640 480 -640 480 -500 335 -640 480 -640 484 -457 640 -640 436 -480 360 -640 427 -427 640 -500 375 -640 439 -640 427 -479 640 -640 427 -640 512 -354 500 -640 457 -500 375 -418 640 -480 640 -640 480 -427 640 -480 640 -640 360 -480 640 -612 612 -612 612 -375 500 -500 333 -640 428 -500 338 -640 480 -640 480 -640 480 -626 476 -448 640 -375 500 -640 360 -360 360 -640 425 -640 427 -640 426 -640 427 -640 428 -640 480 -480 640 -640 480 -640 427 -480 640 -640 480 -640 479 -640 480 -427 640 -375 500 -640 480 -612 612 -478 640 -640 313 -640 424 -373 640 -480 640 -640 480 -480 640 -640 480 -640 480 -640 427 -640 573 -640 427 -640 480 -640 435 -288 352 -640 480 -640 451 -548 640 -375 500 -640 428 -640 480 -640 476 -383 640 -640 360 -640 478 -640 480 -640 480 -640 426 -612 612 -640 328 -640 480 -480 640 -427 640 -640 403 -400 435 -640 480 -375 500 -640 480 -640 427 -480 640 -640 640 -640 424 -640 428 -480 640 -640 360 -426 640 -612 612 -375 500 -640 480 -640 444 -478 640 -480 640 -500 375 -426 640 -640 425 -640 480 -640 479 -640 429 -640 427 -640 426 -557 640 -640 480 -640 447 -640 480 -426 640 -500 375 -640 427 -640 616 -426 640 -500 332 -640 427 -640 480 -640 480 -428 640 -640 480 -500 405 -480 640 -640 502 -426 640 -640 480 -640 480 -640 424 -640 480 -640 480 -428 640 -640 425 -424 640 -380 285 -640 427 -640 480 -640 427 -427 640 -640 429 -640 480 -640 480 -427 640 -458 640 -537 640 -640 427 -640 640 -408 640 -640 467 -640 598 -375 500 -640 480 -640 480 -229 350 -640 480 -640 426 -480 640 -640 480 -375 500 -640 297 -640 480 -640 483 -640 428 -640 427 -612 612 -500 375 -640 426 -640 480 -640 427 -640 480 -480 640 -640 480 -500 375 -640 482 -640 427 -640 572 -640 516 -640 427 -640 427 -640 481 -640 480 -640 414 -640 427 -640 440 -640 480 -640 480 -500 320 -640 383 -640 354 -480 640 -640 427 -480 640 -640 480 -640 480 -640 480 -640 427 -473 640 -640 359 -640 480 -640 425 -500 334 -553 640 -560 640 -426 640 -640 480 -500 375 -640 480 -480 640 -640 444 -640 480 -640 480 -640 480 -413 640 -640 485 -332 500 -500 273 -375 500 -617 640 -640 480 -640 480 -500 375 -640 427 -500 375 -480 640 -640 425 -425 640 -409 640 -640 426 -640 480 -500 375 -640 480 -500 375 -640 427 -640 480 -334 500 -640 481 -640 445 -360 640 -500 375 -640 427 -640 480 -640 425 -480 640 -640 427 -372 464 -480 640 -640 428 -500 375 -500 375 -640 429 -469 640 -640 426 -500 375 -612 612 -640 427 -640 427 -640 480 -612 612 -640 427 -640 427 -640 361 -500 375 -640 427 -320 240 -640 362 -640 480 -640 428 -640 480 -640 429 -640 426 -640 480 -640 480 -640 480 -640 480 -500 359 -640 480 -480 640 -640 480 -640 480 -426 640 -461 640 -640 427 -427 640 -640 479 -640 480 -640 427 -426 640 -640 427 -333 500 -640 360 -612 612 -480 640 -640 428 -640 480 -640 427 -640 480 -640 429 -640 427 -640 303 -640 480 -500 375 -640 480 -640 424 -640 480 -640 480 -640 622 -640 480 -640 480 -640 480 -640 427 -375 500 -612 612 -332 500 -600 400 -427 640 -640 433 -640 480 -480 640 -350 500 -500 500 -480 640 -480 640 -612 612 -423 640 -640 427 -424 640 -478 640 -640 426 -640 427 -480 640 -422 640 -640 427 -500 333 -640 427 -640 425 -640 480 -500 375 -346 504 -640 480 -640 441 -500 342 -457 640 -640 426 -640 426 -640 480 -640 569 -426 640 -640 427 -640 438 -640 427 -640 429 -640 480 -640 427 -422 640 -503 640 -640 551 -640 573 -640 480 -640 463 -640 427 -426 640 -640 480 -500 334 -640 480 -640 480 -640 480 -427 640 -640 480 -640 446 -424 640 -640 428 -612 612 -612 612 -640 478 -640 428 -640 501 -640 427 -480 640 -640 425 -500 401 -640 427 -640 429 -640 429 -451 640 -640 427 -480 640 -500 333 -333 500 -640 424 -640 427 -500 500 -640 427 -480 640 -640 426 -480 640 -427 640 -612 612 -640 427 -640 480 -500 334 -480 640 -640 426 -640 428 -640 480 -500 375 -640 480 -640 426 -640 425 -424 640 -640 480 -640 425 -640 427 -640 493 -500 367 -375 500 -640 374 -640 480 -333 500 -480 640 -640 430 -640 480 -640 427 -500 375 -500 375 -640 381 -640 427 -640 480 -640 424 -480 640 -640 425 -640 427 -640 466 -640 480 -500 333 -640 480 -640 427 -640 428 -640 510 -640 427 -359 640 -426 640 -335 500 -425 640 -640 479 -480 640 -500 346 -640 427 -640 320 -500 334 -498 640 -500 400 -480 640 -500 375 -640 480 -500 375 -640 427 -640 480 -480 640 -640 480 -640 427 -640 186 -640 427 -640 427 -480 640 -640 426 -640 479 -480 640 -640 480 -640 429 -640 427 -640 427 -500 333 -640 427 -429 640 -640 480 -480 640 -375 500 -640 427 -640 480 -426 640 -385 308 -640 427 -640 480 -500 375 -640 478 -640 427 -640 427 -480 640 -500 375 -640 427 -640 360 -640 480 -640 427 -640 480 -640 427 -640 390 -640 427 -457 640 -500 500 -500 375 -359 640 -500 375 -640 431 -600 400 -640 509 -428 640 -427 640 -427 640 -640 428 -640 425 -612 612 -640 424 -375 500 -335 500 -640 425 -640 480 -500 405 -640 426 -640 480 -640 564 -640 427 -480 640 -408 500 -640 480 -640 640 -640 480 -640 480 -640 513 -640 480 -474 640 -640 427 -500 322 -508 640 -640 439 -425 640 -427 640 -640 480 -500 375 -320 240 -640 480 -332 500 -640 427 -640 426 -480 640 -640 427 -640 427 -640 512 -640 478 -640 480 -640 480 -640 427 -500 375 -640 480 -500 375 -425 640 -640 605 -640 480 -640 538 -640 360 -427 640 -334 500 -480 640 -640 425 -427 640 -640 426 -640 428 -640 640 -640 427 -640 480 -640 478 -640 424 -640 480 -640 425 -469 640 -426 640 -500 288 -640 359 -640 366 -640 427 -640 482 -640 428 -640 263 -640 427 -640 426 -640 479 -640 480 -328 500 -640 480 -480 640 -480 640 -640 427 -612 612 -634 640 -640 426 -478 640 -439 500 -640 426 -640 480 -640 460 -640 640 -346 500 -428 640 -500 375 -640 480 -640 480 -478 640 -640 468 -640 426 -500 333 -480 640 -640 381 -640 426 -640 480 -640 478 -640 426 -640 480 -640 428 -480 640 -640 480 -640 480 -335 500 -640 427 -640 425 -640 480 -640 418 -500 375 -640 640 -640 378 -640 443 -480 640 -480 640 -640 480 -640 480 -640 383 -640 427 -518 640 -640 627 -500 228 -640 426 -640 426 -427 640 -640 480 -612 612 -640 470 -640 480 -600 600 -640 480 -640 425 -640 480 -640 480 -640 480 -500 375 -480 640 -640 480 -640 482 -225 640 -428 640 -439 640 -640 480 -400 300 -489 640 -640 427 -640 204 -640 427 -640 396 -500 333 -640 481 -640 428 -640 428 -640 424 -500 375 -451 298 -640 425 -640 428 -500 375 -640 480 -500 375 -640 426 -474 640 -640 425 -640 424 -364 640 -500 333 -640 606 -427 640 -640 427 -497 640 -457 640 -640 427 -640 427 -640 427 -480 640 -640 480 -640 486 -640 427 -640 426 -640 433 -640 471 -479 640 -640 427 -640 426 -480 640 -640 480 -500 375 -375 500 -640 480 -640 480 -396 500 -500 375 -640 480 -640 480 -480 640 -640 427 -640 360 -429 640 -640 427 -640 427 -640 431 -612 612 -640 480 -640 429 -640 434 -500 333 -500 367 -640 480 -427 640 -427 640 -640 428 -480 640 -500 333 -640 427 -640 480 -640 259 -640 480 -640 428 -640 463 -640 426 -640 427 -375 500 -640 480 -584 640 -500 375 -640 640 -640 427 -640 480 -640 426 -480 640 -640 480 -480 640 -640 480 -426 640 -425 640 -640 426 -640 480 -640 427 -478 640 -640 484 -437 640 -640 427 -640 428 -500 333 -500 375 -640 453 -640 427 -480 640 -640 428 -640 427 -640 500 -480 640 -427 640 -500 375 -640 427 -640 480 -640 427 -500 332 -500 375 -502 640 -640 640 -640 425 -640 360 -640 426 -640 499 -640 359 -640 428 -640 480 -640 480 -640 251 -640 480 -640 427 -640 480 -640 427 -375 500 -480 640 -640 480 -640 480 -517 640 -640 480 -480 640 -612 612 -480 640 -640 424 -640 480 -640 480 -640 421 -427 640 -640 427 -640 480 -640 427 -640 387 -480 640 -640 407 -640 360 -640 439 -640 404 -640 482 -640 480 -427 640 -640 427 -640 480 -375 500 -640 428 -640 480 -640 391 -480 640 -640 480 -640 480 -640 427 -612 612 -640 480 -640 428 -400 325 -458 640 -640 442 -640 428 -427 640 -632 640 -640 622 -640 429 -427 640 -640 480 -427 640 -640 428 -548 411 -640 426 -484 640 -640 426 -640 480 -640 480 -514 640 -500 333 -500 500 -640 627 -424 640 -444 640 -640 426 -640 424 -640 427 -640 480 -640 426 -640 480 -480 640 -640 480 -333 500 -640 480 -640 480 -376 500 -640 426 -427 640 -640 426 -500 375 -429 640 -480 640 -640 480 -640 457 -640 374 -640 480 -640 480 -500 377 -640 373 -640 480 -500 375 -640 360 -640 485 -640 640 -640 480 -640 480 -333 500 -640 426 -640 426 -640 451 -640 480 -640 444 -640 523 -480 640 -480 640 -640 480 -375 500 -458 640 -480 640 -500 375 -640 426 -640 457 -640 480 -375 500 -640 418 -640 427 -640 434 -640 428 -640 425 -640 436 -640 426 -640 319 -640 480 -500 375 -640 427 -640 427 -500 332 -640 427 -375 500 -640 480 -640 495 -640 361 -478 640 -480 640 -640 424 -640 384 -612 612 -640 426 -640 480 -500 500 -640 356 -480 640 -426 640 -640 640 -500 375 -640 360 -640 478 -480 640 -640 480 -425 640 -640 423 -480 640 -480 640 -640 480 -640 427 -640 464 -483 640 -480 640 -640 359 -612 612 -640 531 -640 396 -640 427 -640 480 -640 480 -500 352 -640 480 -640 427 -640 480 -640 541 -640 427 -640 427 -480 640 -640 427 -640 427 -427 640 -640 555 -640 480 -640 426 -640 428 -424 640 -500 333 -640 426 -640 427 -512 640 -640 360 -640 427 -427 640 -500 198 -640 480 -375 500 -480 640 -640 426 -640 480 -640 428 -640 459 -640 427 -640 426 -640 480 -640 391 -640 480 -640 428 -640 480 -640 427 -480 640 -640 427 -640 427 -640 427 -640 478 -640 426 -640 480 -320 240 -480 640 -427 640 -640 480 -640 453 -640 428 -480 640 -480 640 -640 426 -640 478 -640 480 -640 480 -640 432 -640 483 -640 361 -640 427 -480 640 -480 640 -500 374 -640 480 -640 480 -640 359 -640 360 -480 640 -427 640 -430 640 -640 427 -640 408 -480 640 -333 500 -640 480 -428 640 -480 640 -640 427 -425 640 -640 480 -640 480 -375 500 -500 362 -332 500 -375 500 -640 400 -640 454 -435 640 -334 500 -424 640 -640 480 -500 375 -480 640 -640 424 -640 480 -640 427 -640 640 -640 378 -640 427 -640 480 -500 406 -640 360 -640 360 -424 640 -427 640 -640 427 -640 480 -640 427 -640 480 -640 458 -640 425 -640 459 -640 480 -640 480 -640 480 -480 640 -640 426 -640 480 -640 427 -640 426 -640 400 -640 480 -640 480 -640 427 -640 513 -500 361 -639 640 -481 640 -640 427 -640 425 -640 426 -500 308 -640 480 -640 458 -640 428 -612 612 -452 640 -640 426 -480 640 -511 640 -640 426 -640 480 -427 640 -640 480 -500 328 -640 480 -640 480 -383 640 -640 480 -500 330 -640 427 -500 375 -640 427 -500 332 -428 640 -640 502 -640 425 -640 426 -500 375 -640 480 -640 388 -640 427 -427 640 -639 640 -640 640 -640 427 -640 431 -640 480 -640 426 -640 428 -480 640 -640 426 -640 427 -500 375 -640 640 -640 475 -640 412 -640 428 -500 333 -640 480 -640 512 -375 500 -454 640 -500 371 -640 427 -640 425 -640 480 -640 640 -640 640 -640 360 -640 426 -640 426 -640 480 -612 612 -480 640 -640 428 -640 360 -640 480 -375 500 -478 640 -640 427 -640 480 -427 640 -360 640 -600 400 -612 612 -640 480 -640 482 -640 424 -640 480 -640 480 -640 340 -640 426 -640 427 -427 640 -640 427 -640 480 -480 640 -640 428 -495 640 -640 480 -640 480 -480 640 -640 480 -640 480 -480 640 -640 425 -640 427 -640 480 -427 640 -640 428 -640 640 -640 425 -480 640 -640 427 -640 480 -640 427 -640 512 -500 375 -640 427 -640 480 -640 412 -436 640 -640 426 -500 375 -640 428 -640 640 -640 360 -640 427 -640 480 -640 428 -640 427 -500 375 -640 480 -640 427 -640 480 -640 304 -500 375 -427 640 -640 428 -640 480 -640 481 -428 640 -480 640 -640 458 -500 375 -640 480 -640 480 -640 383 -640 425 -500 375 -640 426 -640 480 -640 427 -640 427 -427 640 -640 480 -640 480 -640 480 -640 640 -480 640 -640 426 -640 480 -640 483 -640 360 -640 478 -640 427 -640 424 -612 612 -640 481 -640 480 -640 426 -480 640 -640 426 -480 640 -640 428 -640 480 -375 500 -480 640 -640 480 -500 370 -640 480 -640 427 -500 368 -500 375 -640 543 -427 640 -500 361 -498 640 -640 427 -640 480 -500 356 -640 480 -640 462 -640 480 -480 640 -640 480 -640 480 -385 289 -640 480 -500 333 -478 640 -640 480 -640 383 -640 481 -640 457 -640 443 -640 425 -480 640 -640 480 -640 426 -640 480 -640 428 -480 640 -500 375 -500 375 -640 425 -640 361 -640 427 -640 480 -640 480 -500 400 -640 427 -640 478 -640 427 -640 427 -500 333 -640 421 -500 375 -640 425 -640 423 -480 640 -480 640 -500 375 -640 480 -640 399 -335 500 -640 480 -640 424 -427 640 -640 427 -640 480 -640 425 -335 500 -640 426 -640 426 -640 426 -640 480 -640 384 -640 374 -426 640 -333 500 -500 375 -480 640 -640 337 -640 459 -640 480 -640 358 -640 480 -629 640 -427 640 -640 426 -640 458 -640 640 -563 640 -640 497 -640 480 -480 640 -640 413 -640 426 -500 376 -640 427 -640 640 -426 640 -480 640 -640 480 -640 428 -640 426 -426 640 -480 640 -427 640 -640 480 -429 640 -480 640 -640 512 -427 640 -640 368 -640 480 -640 480 -640 480 -640 480 -640 428 -640 429 -640 426 -612 612 -640 480 -427 640 -480 640 -640 427 -640 360 -640 426 -640 480 -500 346 -640 621 -640 360 -640 480 -640 428 -640 399 -500 375 -640 480 -480 640 -640 475 -500 333 -640 424 -500 400 -640 360 -495 640 -640 484 -640 427 -640 427 -500 334 -640 480 -500 398 -640 449 -640 480 -501 640 -500 334 -640 427 -640 439 -640 427 -640 427 -640 480 -580 640 -640 480 -480 640 -640 360 -428 640 -513 640 -640 427 -640 480 -440 640 -640 427 -562 640 -640 427 -640 480 -500 375 -426 640 -640 427 -640 427 -640 416 -640 425 -640 512 -500 375 -478 640 -521 640 -500 375 -640 433 -640 513 -640 428 -640 383 -640 427 -640 454 -640 427 -640 483 -640 426 -458 640 -640 480 -640 480 -640 428 -612 612 -564 640 -640 480 -500 333 -640 424 -640 426 -509 640 -640 425 -427 640 -640 341 -500 375 -457 640 -480 640 -640 428 -500 334 -640 480 -480 640 -640 429 -640 425 -428 640 -500 333 -480 640 -404 640 -640 480 -640 480 -640 426 -640 502 -640 425 -527 640 -640 425 -640 427 -427 640 -640 428 -425 640 -640 434 -640 480 -640 480 -640 427 -640 424 -640 480 -640 440 -640 439 -640 424 -640 360 -640 427 -640 480 -640 480 -640 424 -478 640 -640 481 -640 426 -640 480 -640 480 -500 496 -640 373 -640 439 -640 310 -640 640 -500 393 -640 428 -640 478 -640 424 -640 480 -640 480 -640 427 -500 334 -640 426 -500 453 -516 640 -640 488 -500 375 -640 424 -640 427 -640 480 -333 500 -640 366 -640 425 -425 640 -500 333 -581 640 -427 640 -480 640 -640 480 -640 363 -612 612 -640 427 -640 480 -640 480 -640 480 -428 640 -640 360 -640 458 -640 400 -640 427 -304 500 -640 480 -500 375 -640 436 -640 425 -427 640 -640 480 -640 427 -640 463 -554 640 -500 344 -375 500 -500 500 -640 480 -500 375 -500 333 -640 433 -640 464 -426 640 -640 512 -480 640 -500 375 -640 554 -640 427 -640 469 -640 480 -640 512 -374 500 -480 640 -263 500 -640 427 -426 640 -609 640 -640 427 -640 360 -640 480 -640 480 -480 640 -640 512 -640 451 -640 480 -640 480 -426 640 -640 480 -640 457 -640 441 -612 612 -577 640 -640 480 -333 500 -640 427 -640 480 -640 425 -512 640 -640 512 -612 612 -640 360 -480 640 -640 480 -424 640 -640 480 -640 428 -640 427 -500 375 -423 640 -640 480 -640 480 -375 500 -640 501 -500 331 -640 425 -612 612 -640 640 -428 640 -500 375 -640 427 -640 441 -500 375 -640 480 -640 481 -425 640 -480 640 -640 425 -640 480 -640 480 -640 480 -480 640 -640 360 -640 480 -432 287 -640 427 -357 500 -640 427 -500 375 -457 640 -640 401 -640 426 -412 200 -427 640 -640 479 -612 612 -375 500 -478 640 -612 612 -640 423 -640 396 -500 333 -640 351 -500 333 -640 428 -500 375 -640 427 -640 434 -500 375 -640 428 -640 427 -346 500 -480 640 -608 640 -640 501 -640 480 -640 480 -640 480 -480 640 -640 392 -375 500 -640 427 -640 427 -480 640 -640 640 -460 640 -640 428 -500 455 -640 425 -640 427 -640 480 -640 480 -640 480 -640 465 -640 428 -500 375 -500 281 -640 427 -640 424 -612 612 -640 429 -500 416 -584 414 -480 640 -640 459 -640 426 -497 640 -425 640 -480 640 -640 427 -640 427 -640 360 -640 480 -426 640 -640 480 -640 427 -640 427 -480 640 -640 338 -640 480 -427 640 -640 424 -427 640 -480 640 -424 640 -480 640 -640 427 -640 480 -640 422 -640 458 -640 427 -640 480 -640 480 -612 612 -640 480 -640 428 -640 480 -640 364 -375 500 -640 640 -640 426 -480 640 -640 480 -640 481 -640 480 -640 480 -640 480 -640 534 -640 480 -640 426 -640 480 -640 480 -500 354 -640 425 -640 426 -427 640 -640 480 -640 480 -640 480 -640 480 -640 425 -478 640 -427 640 -640 573 -479 640 -640 480 -640 480 -640 360 -640 480 -640 441 -480 640 -500 333 -480 640 -480 640 -640 480 -640 427 -640 479 -640 399 -640 425 -640 493 -640 425 -480 640 -480 640 -400 533 -640 589 -640 480 -640 505 -640 426 -500 375 -640 426 -640 425 -375 500 -500 370 -385 289 -640 480 -640 427 -640 427 -640 480 -640 480 -640 480 -416 640 -500 375 -640 360 -640 480 -640 640 -480 640 -640 428 -640 457 -375 500 -640 480 -640 480 -612 612 -640 427 -640 480 -480 640 -640 481 -640 418 -640 415 -500 438 -640 431 -640 480 -640 428 -640 480 -640 480 -335 500 -640 480 -640 480 -640 427 -640 428 -640 478 -500 375 -640 480 -640 480 -640 416 -640 425 -640 427 -500 313 -640 464 -640 428 -640 480 -640 426 -640 486 -640 480 -640 480 -640 427 -276 500 -640 480 -457 640 -640 482 -640 428 -480 640 -500 374 -500 376 -500 332 -640 359 -393 500 -500 332 -458 640 -478 640 -640 478 -640 480 -640 399 -640 428 -436 640 -524 640 -640 480 -450 450 -640 427 -640 427 -640 426 -640 480 -640 480 -640 424 -428 640 -640 424 -450 600 -480 640 -640 320 -640 425 -350 500 -472 640 -640 640 -480 640 -640 514 -640 480 -640 603 -640 583 -568 320 -640 427 -500 400 -480 640 -640 427 -600 400 -612 612 -640 480 -640 480 -424 640 -640 389 -640 426 -480 640 -480 640 -640 480 -640 480 -640 406 -500 334 -640 480 -428 640 -640 438 -640 480 -550 640 -640 426 -500 332 -500 381 -640 424 -308 300 -640 472 -640 480 -375 500 -428 640 -640 427 -640 480 -612 612 -640 428 -427 640 -500 264 -480 640 -640 480 -640 427 -640 439 -500 335 -375 500 -381 500 -500 333 -640 425 -500 375 -640 480 -500 340 -640 480 -640 480 -640 480 -334 500 -640 472 -480 640 -640 425 -427 640 -640 426 -640 459 -640 480 -376 500 -500 375 -500 387 -411 640 -640 426 -427 640 -375 500 -480 640 -432 640 -640 480 -429 640 -500 375 -640 427 -566 640 -640 480 -640 480 -640 480 -500 333 -640 480 -640 480 -640 427 -640 473 -480 640 -640 427 -640 426 -640 640 -640 427 -640 640 -640 425 -640 478 -333 500 -640 480 -640 426 -640 621 -427 640 -640 429 -640 427 -466 640 -480 640 -640 425 -334 500 -427 640 -640 457 -427 640 -375 500 -640 423 -600 400 -640 427 -500 333 -375 500 -612 612 -427 640 -426 640 -640 480 -640 409 -640 480 -341 500 -640 426 -640 420 -383 640 -640 428 -640 480 -640 316 -640 427 -640 480 -640 480 -640 427 -480 640 -640 360 -500 353 -425 640 -640 480 -640 480 -640 427 -640 425 -375 500 -640 480 -640 427 -640 424 -500 332 -500 375 -480 640 -640 479 -640 480 -640 480 -500 375 -640 480 -500 283 -640 427 -500 375 -500 375 -640 360 -480 640 -640 353 -640 458 -433 640 -640 480 -640 480 -480 640 -640 424 -640 480 -378 640 -640 425 -640 414 -480 640 -640 480 -640 427 -612 612 -640 386 -640 360 -640 426 -375 500 -500 333 -500 400 -640 480 -480 640 -433 640 -144 190 -640 407 -640 427 -640 480 -640 480 -640 425 -640 480 -640 480 -640 426 -640 427 -500 333 -640 478 -640 425 -640 427 -500 375 -640 480 -427 640 -640 427 -640 538 -640 468 -500 375 -640 480 -500 375 -427 640 -500 375 -640 478 -426 640 -480 640 -640 425 -640 427 -480 640 -640 427 -640 426 -640 480 -511 640 -640 480 -640 480 -640 480 -640 480 -480 640 -640 427 -480 640 -640 426 -640 427 -640 426 -640 426 -500 375 -640 426 -500 375 -640 480 -640 425 -640 478 -640 427 -375 500 -500 375 -640 426 -385 289 -640 428 -640 427 -333 500 -640 426 -500 375 -334 500 -500 334 -500 375 -394 500 -640 427 -640 427 -640 480 -444 640 -640 480 -640 427 -640 480 -445 590 -640 425 -426 640 -552 640 -480 640 -640 413 -640 451 -640 427 -480 640 -428 640 -480 640 -640 429 -640 443 -640 640 -640 266 -427 640 -425 640 -640 427 -500 375 -500 333 -427 640 -480 640 -415 625 -500 375 -640 493 -640 461 -640 482 -640 434 -480 640 -640 400 -480 640 -500 375 -500 333 -454 342 -500 334 -640 428 -640 622 -640 480 -640 480 -427 640 -640 183 -640 420 -428 640 -640 426 -425 640 -640 427 -640 480 -640 427 -493 640 -640 480 -640 426 -640 480 -640 480 -612 612 -640 503 -640 427 -640 481 -640 480 -640 640 -480 640 -455 640 -640 480 -640 480 -500 375 -640 427 -480 640 -480 640 -640 428 -640 424 -640 426 -640 640 -427 640 -361 640 -427 640 -640 426 -640 427 -612 612 -427 640 -480 640 -375 500 -500 375 -640 427 -640 429 -640 427 -640 481 -640 480 -332 500 -640 421 -640 430 -640 481 -500 375 -640 458 -640 426 -480 640 -640 480 -640 427 -375 500 -640 428 -640 427 -480 640 -640 480 -640 426 -480 640 -640 480 -640 480 -640 468 -640 480 -426 640 -640 427 -636 640 -480 640 -427 640 -640 466 -640 489 -500 375 -500 337 -375 500 -640 426 -640 427 -494 640 -640 427 -640 480 -640 427 -375 500 -500 333 -640 427 -500 375 -640 426 -600 402 -640 480 -360 640 -640 427 -480 640 -640 480 -640 640 -640 426 -424 640 -640 480 -500 375 -640 480 -640 480 -640 480 -427 640 -640 458 -640 463 -480 640 -640 480 -640 480 -640 427 -640 480 -640 424 -427 640 -640 480 -612 612 -640 428 -500 375 -640 427 -426 640 -640 480 -333 500 -523 640 -427 640 -640 427 -511 640 -480 640 -612 612 -612 612 -480 640 -500 375 -480 640 -640 427 -640 427 -640 480 -526 640 -640 360 -333 500 -427 640 -640 628 -640 458 -640 428 -427 640 -500 305 -480 640 -375 500 -640 427 -640 480 -427 640 -640 480 -640 480 -355 500 -640 424 -640 487 -640 427 -375 500 -480 640 -500 375 -612 612 -500 375 -640 480 -640 427 -640 427 -640 429 -500 375 -640 378 -612 612 -426 640 -640 480 -632 640 -500 375 -418 640 -640 499 -640 478 -350 500 -640 427 -640 480 -640 480 -640 480 -640 425 -640 360 -640 480 -640 427 -640 427 -439 640 -473 600 -500 473 -640 408 -640 427 -640 480 -427 640 -640 427 -500 375 -640 640 -640 426 -640 427 -640 428 -500 333 -640 480 -640 427 -612 612 -427 640 -640 480 -640 480 -640 480 -640 425 -480 640 -640 410 -480 640 -640 427 -640 478 -640 427 -612 612 -640 427 -640 425 -640 470 -348 500 -599 640 -640 316 -427 640 -640 480 -640 480 -427 640 -442 640 -320 240 -640 425 -500 375 -427 640 -640 480 -500 500 -479 640 -500 333 -640 480 -426 640 -640 427 -640 640 -640 480 -640 427 -640 427 -640 429 -640 428 -375 500 -640 480 -640 426 -640 426 -640 425 -640 638 -640 429 -640 425 -480 640 -640 478 -640 360 -480 640 -480 640 -640 426 -500 333 -612 612 -480 640 -500 375 -640 427 -332 500 -500 375 -320 480 -640 423 -375 500 -640 425 -500 375 -640 480 -392 640 -640 569 -500 334 -640 425 -500 375 -480 640 -640 480 -640 427 -640 427 -640 480 -480 640 -640 306 -640 424 -500 348 -500 350 -500 332 -424 640 -640 425 -640 480 -428 640 -640 480 -500 286 -640 480 -640 480 -480 640 -640 401 -640 424 -640 427 -480 640 -386 500 -640 414 -640 414 -480 640 -640 489 -640 457 -480 640 -640 427 -640 526 -434 640 -478 640 -640 480 -640 279 -640 427 -425 640 -333 500 -640 360 -640 480 -457 640 -374 500 -500 375 -480 640 -640 435 -640 480 -316 500 -640 427 -333 500 -640 426 -474 640 -640 480 -640 478 -640 426 -640 424 -427 640 -640 480 -640 489 -416 500 -640 478 -640 480 -640 427 -640 427 -452 500 -400 400 -427 640 -336 254 -640 401 -333 500 -640 427 -640 366 -640 458 -480 640 -640 427 -500 375 -640 359 -500 375 -480 640 -480 640 -640 480 -640 424 -640 480 -640 429 -640 532 -640 478 -480 640 -640 426 -640 400 -640 359 -640 427 -640 512 -640 480 -640 427 -640 480 -640 481 -640 426 -640 432 -427 640 -500 375 -427 640 -640 480 -425 640 -480 640 -480 640 -640 430 -640 480 -640 480 -640 427 -600 450 -640 360 -640 480 -640 424 -640 425 -612 612 -640 482 -640 480 -640 429 -640 480 -640 480 -480 640 -640 480 -480 640 -640 427 -640 428 -640 480 -640 428 -640 545 -640 426 -480 640 -640 480 -410 500 -640 427 -640 597 -640 480 -640 427 -640 428 -612 612 -479 640 -640 482 -640 480 -500 375 -640 425 -640 480 -640 480 -640 480 -640 480 -612 612 -428 640 -500 375 -480 640 -640 428 -640 427 -500 375 -640 359 -640 426 -640 480 -640 478 -332 500 -640 480 -427 640 -640 480 -480 640 -640 427 -640 480 -640 480 -640 432 -500 333 -640 480 -480 640 -480 640 -526 640 -640 480 -640 480 -640 440 -500 334 -384 640 -640 354 -375 500 -480 640 -640 418 -640 480 -640 426 -640 427 -640 427 -640 424 -500 375 -480 640 -640 424 -500 398 -640 480 -640 427 -640 480 -640 480 -375 500 -424 640 -640 480 -640 478 -480 640 -427 640 -500 373 -425 640 -640 480 -640 427 -480 640 -484 640 -480 640 -640 426 -640 381 -480 640 -427 640 -640 512 -640 424 -426 640 -640 400 -640 480 -640 442 -640 480 -480 640 -500 375 -425 640 -640 457 -426 640 -640 432 -480 640 -640 480 -640 480 -427 640 -640 425 -375 500 -640 480 -427 640 -640 428 -612 612 -640 361 -640 466 -450 360 -640 624 -500 335 -428 640 -640 427 -480 640 -640 425 -640 427 -640 480 -500 375 -480 640 -640 298 -640 480 -500 449 -640 426 -336 448 -500 375 -640 480 -640 640 -427 640 -640 360 -640 427 -478 640 -640 427 -640 427 -640 476 -544 640 -640 480 -640 478 -426 640 -640 480 -640 426 -428 640 -480 640 -300 400 -640 603 -640 480 -428 640 -383 640 -480 640 -640 480 -640 418 -375 500 -640 439 -500 333 -640 427 -640 491 -640 482 -500 333 -640 428 -640 427 -427 640 -640 480 -639 640 -640 480 -640 473 -640 480 -640 480 -640 544 -640 456 -480 640 -640 384 -640 427 -500 281 -640 480 -640 312 -640 457 -640 427 -640 427 -500 348 -640 480 -427 640 -640 426 -640 425 -640 480 -640 480 -500 375 -480 640 -425 640 -640 588 -640 480 -640 434 -640 427 -367 500 -506 380 -375 500 -640 428 -640 424 -624 640 -425 640 -500 375 -639 640 -600 400 -500 375 -640 480 -400 600 -480 640 -500 375 -640 436 -640 480 -428 640 -640 452 -480 640 -640 428 -612 612 -640 512 -500 384 -375 500 -426 640 -479 640 -640 480 -640 411 -640 480 -640 427 -640 359 -640 478 -640 480 -337 500 -640 416 -427 640 -640 480 -640 480 -612 612 -612 612 -480 640 -375 500 -640 427 -640 480 -640 426 -425 640 -480 640 -640 480 -640 480 -640 427 -640 428 -640 427 -640 480 -480 640 -640 426 -640 501 -640 480 -480 640 -640 480 -549 640 -372 500 -640 480 -640 640 -426 640 -500 375 -640 482 -640 427 -640 426 -333 500 -426 640 -500 334 -640 439 -640 429 -640 480 -480 640 -640 426 -500 375 -333 500 -640 587 -500 375 -640 425 -640 426 -640 425 -640 427 -640 429 -500 375 -427 640 -640 480 -640 361 -427 640 -500 375 -640 480 -640 424 -452 640 -640 480 -640 480 -640 480 -640 480 -640 427 -500 375 -640 480 -433 640 -640 480 -640 480 -547 640 -640 428 -640 427 -640 428 -640 427 -640 545 -480 640 -640 640 -640 476 -640 480 -640 438 -500 424 -480 640 -428 640 -500 332 -457 640 -427 640 -500 375 -640 464 -513 640 -640 480 -640 427 -640 359 -640 426 -640 426 -640 428 -640 480 -640 480 -338 500 -457 640 -640 427 -500 375 -640 426 -500 375 -640 428 -640 480 -612 612 -640 425 -401 288 -640 425 -640 426 -640 425 -500 375 -640 512 -640 428 -513 640 -640 428 -474 640 -640 425 -322 214 -612 612 -640 480 -640 512 -640 480 -426 640 -640 513 -640 640 -640 480 -640 425 -427 640 -640 428 -640 480 -534 640 -640 480 -640 480 -400 640 -425 640 -640 428 -640 427 -640 480 -640 480 -640 428 -640 480 -427 640 -640 360 -640 427 -640 480 -640 480 -640 502 -640 588 -640 480 -640 480 -640 480 -640 427 -480 640 -375 500 -612 612 -640 480 -480 640 -427 640 -427 640 -500 332 -640 427 -500 375 -640 480 -640 427 -640 427 -480 640 -640 424 -640 480 -640 480 -640 480 -640 427 -640 529 -426 640 -640 329 -640 480 -640 480 -330 500 -640 429 -640 453 -640 383 -640 437 -640 457 -640 640 -500 375 -640 539 -640 427 -640 426 -640 425 -375 500 -640 427 -640 480 -500 300 -480 640 -500 335 -640 480 -640 427 -640 480 -640 427 -640 480 -640 480 -640 427 -638 394 -640 480 -640 427 -640 427 -479 640 -493 640 -480 640 -640 465 -500 375 -500 381 -640 478 -498 640 -473 640 -640 425 -640 480 -480 640 -640 428 -640 356 -640 426 -640 480 -640 425 -640 427 -480 640 -640 482 -480 640 -640 427 -640 480 -640 427 -640 426 -640 427 -427 640 -640 413 -640 480 -500 375 -640 424 -640 610 -371 640 -640 361 -500 375 -640 427 -640 480 -640 480 -640 426 -640 425 -500 312 -640 426 -427 640 -640 427 -640 480 -375 500 -640 480 -640 480 -640 427 -640 360 -640 480 -480 640 -640 427 -640 427 -640 427 -425 640 -640 427 -640 480 -640 427 -640 427 -333 500 -640 427 -375 500 -539 640 -640 478 -640 480 -640 427 -493 640 -640 427 -612 612 -334 500 -480 640 -640 558 -640 512 -640 480 -640 426 -640 480 -640 479 -480 640 -500 375 -640 480 -640 480 -640 478 -480 640 -612 612 -640 423 -500 334 -640 425 -640 478 -360 640 -513 640 -640 428 -640 425 -640 427 -427 640 -500 415 -640 427 -640 640 -640 427 -640 473 -500 375 -334 500 -640 480 -640 480 -640 428 -640 480 -640 499 -640 427 -640 450 -640 411 -640 481 -425 640 -427 640 -640 427 -480 640 -576 640 -640 480 -640 480 -500 375 -640 480 -640 429 -500 333 -640 480 -640 480 -480 640 -480 640 -640 424 -640 427 -640 413 -640 291 -500 375 -612 612 -640 425 -640 429 -640 480 -640 426 -640 640 -426 640 -640 480 -640 640 -640 480 -640 425 -640 428 -500 375 -640 480 -427 640 -640 426 -640 480 -640 427 -612 612 -640 427 -640 406 -640 479 -500 333 -640 480 -640 480 -375 500 -640 480 -640 360 -313 500 -480 640 -375 500 -640 480 -640 481 -640 428 -640 428 -480 640 -427 640 -640 360 -500 375 -640 359 -480 640 -361 640 -640 474 -640 427 -500 375 -640 426 -480 640 -640 396 -640 480 -640 480 -640 481 -480 640 -640 425 -640 480 -640 480 -443 640 -427 640 -640 480 -640 480 -640 426 -514 640 -426 640 -612 612 -500 333 -500 458 -640 423 -333 500 -640 458 -640 413 -640 486 -640 427 -500 333 -500 332 -612 612 -640 480 -425 640 -426 640 -640 480 -640 480 -640 513 -640 473 -640 480 -640 480 -640 428 -640 392 -333 500 -640 480 -640 480 -612 612 -640 401 -478 640 -640 427 -640 480 -640 427 -595 640 -500 352 -500 333 -640 426 -640 480 -640 480 -640 494 -640 480 -640 427 -640 480 -640 426 -480 640 -640 360 -640 428 -640 427 -450 600 -500 415 -640 480 -450 640 -640 480 -640 424 -351 640 -500 375 -640 427 -428 640 -640 415 -640 427 -612 612 -640 480 -640 426 -640 480 -640 480 -500 328 -640 480 -478 640 -640 487 -640 360 -480 640 -640 480 -640 424 -478 640 -480 640 -640 425 -427 640 -640 480 -640 480 -300 300 -640 480 -640 427 -427 640 -640 480 -640 426 -530 640 -640 480 -640 427 -640 425 -640 480 -640 427 -640 424 -640 478 -640 396 -480 640 -500 333 -640 480 -640 478 -640 484 -640 480 -640 427 -640 640 -640 428 -480 640 -500 331 -640 528 -426 640 -640 480 -640 478 -640 288 -640 428 -424 640 -256 200 -640 128 -640 425 -640 427 -500 500 -640 480 -333 500 -640 480 -640 480 -640 427 -640 480 -480 640 -640 544 -640 480 -640 339 -349 480 -426 640 -640 480 -336 450 -640 512 -500 400 -640 431 -640 480 -480 640 -640 457 -480 640 -640 428 -640 427 -640 451 -375 500 -640 480 -640 480 -640 425 -640 480 -640 428 -426 640 -427 640 -640 480 -640 480 -451 338 -500 332 -480 640 -500 375 -500 333 -333 500 -640 478 -427 640 -500 446 -640 425 -480 640 -640 427 -520 360 -427 640 -640 480 -356 500 -640 427 -640 427 -333 500 -500 375 -640 480 -640 609 -600 399 -640 485 -640 427 -500 492 -375 500 -640 480 -640 429 -375 500 -480 640 -427 640 -375 500 -640 427 -640 427 -640 480 -640 480 -640 480 -640 428 -640 427 -640 480 -640 426 -549 640 -480 640 -582 640 -640 529 -639 640 -640 428 -640 366 -640 480 -640 427 -640 640 -640 476 -640 480 -640 427 -500 333 -640 427 -640 426 -480 640 -640 427 -640 324 -640 427 -334 500 -640 480 -336 500 -494 367 -640 426 -640 425 -500 375 -634 640 -475 640 -640 480 -500 298 -640 480 -640 601 -640 480 -640 341 -640 485 -640 425 -432 640 -640 513 -640 428 -640 393 -640 425 -500 299 -640 426 -480 640 -480 640 -418 640 -640 480 -640 480 -480 640 -640 424 -640 360 -633 640 -480 640 -375 500 -426 640 -640 427 -480 640 -640 425 -426 640 -640 400 -640 361 -424 640 -640 480 -640 438 -640 480 -500 333 -640 399 -640 428 -319 640 -359 500 -640 360 -640 428 -480 640 -640 451 -640 480 -500 260 -640 480 -640 480 -640 427 -640 480 -640 427 -612 612 -375 500 -480 640 -640 480 -640 480 -480 640 -640 427 -427 640 -480 640 -640 426 -640 427 -640 420 -640 640 -375 500 -390 500 -640 377 -480 640 -640 480 -640 425 -375 500 -488 640 -640 427 -640 427 -500 407 -500 333 -640 426 -640 427 -480 640 -640 428 -640 378 -640 480 -427 640 -348 500 -428 640 -316 500 -640 512 -480 640 -640 480 -640 425 -640 480 -428 640 -500 384 -640 480 -640 360 -427 640 -640 426 -640 451 -640 360 -640 427 -482 640 -640 426 -479 640 -426 640 -640 480 -640 427 -640 361 -640 480 -500 375 -640 480 -500 375 -500 375 -640 426 -640 428 -480 640 -640 480 -425 640 -640 484 -640 453 -640 429 -426 640 -500 375 -480 640 -500 375 -640 312 -500 334 -640 427 -640 427 -640 427 -640 425 -640 616 -640 633 -640 569 -640 427 -640 426 -612 612 -500 375 -480 640 -640 425 -427 640 -640 425 -640 426 -640 427 -640 426 -512 640 -500 400 -480 640 -640 480 -640 457 -500 375 -640 427 -640 428 -640 400 -640 428 -375 500 -640 480 -640 426 -640 512 -640 480 -640 413 -640 480 -500 373 -467 640 -640 480 -640 426 -640 429 -480 640 -480 640 -640 427 -427 640 -463 640 -640 425 -640 383 -640 425 -640 480 -427 640 -640 427 -500 330 -500 333 -640 480 -480 640 -640 424 -640 428 -640 290 -640 480 -480 640 -640 480 -640 369 -640 480 -500 375 -640 480 -464 640 -428 640 -640 484 -640 480 -640 480 -640 427 -464 640 -612 612 -480 640 -640 427 -426 640 -480 640 -640 640 -640 480 -640 480 -640 311 -500 332 -640 454 -640 480 -480 640 -640 427 -480 360 -640 427 -500 375 -640 480 -375 500 -640 480 -640 366 -640 480 -640 558 -535 357 -640 480 -640 480 -427 640 -640 480 -426 640 -640 480 -612 612 -500 375 -480 640 -640 425 -640 480 -480 640 -640 480 -640 480 -427 640 -640 428 -640 174 -427 640 -640 457 -640 524 -640 480 -640 480 -640 480 -640 480 -640 640 -411 640 -640 427 -640 427 -427 640 -640 511 -640 480 -586 430 -480 640 -640 480 -640 480 -640 480 -640 361 -427 640 -640 480 -500 435 -612 612 -207 640 -425 640 -425 640 -640 427 -640 426 -480 640 -640 427 -480 640 -500 333 -640 436 -640 480 -640 427 -640 427 -640 480 -640 480 -640 480 -640 480 -612 612 -640 480 -640 427 -640 480 -452 640 -640 425 -640 475 -640 356 -500 375 -640 425 -427 640 -500 375 -640 427 -500 375 -640 427 -640 512 -640 423 -640 456 -480 640 -640 427 -500 335 -250 306 -416 640 -640 480 -640 515 -500 375 -500 333 -640 424 -427 640 -640 424 -500 375 -640 425 -466 640 -640 469 -640 480 -640 480 -640 480 -457 640 -480 640 -500 640 -427 640 -640 427 -640 480 -640 513 -480 640 -640 480 -640 427 -640 394 -640 360 -640 429 -500 375 -402 640 -640 427 -480 640 -640 427 -640 480 -640 360 -427 640 -500 375 -640 480 -500 375 -640 427 -500 375 -640 480 -640 478 -480 640 -478 640 -500 332 -640 439 -640 480 -640 480 -469 640 -333 500 -640 419 -640 194 -640 480 -640 480 -640 426 -612 612 -640 360 -640 428 -500 375 -640 425 -640 457 -640 480 -640 480 -640 425 -500 375 -600 416 -640 424 -500 375 -640 480 -640 480 -640 428 -640 480 -335 500 -640 640 -427 640 -640 428 -480 640 -500 331 -500 374 -375 500 -640 480 -640 426 -640 480 -640 366 -480 640 -640 427 -640 480 -640 480 -640 425 -640 424 -640 427 -640 428 -640 429 -640 492 -640 427 -640 480 -399 640 -640 480 -640 480 -640 480 -640 361 -640 427 -426 640 -640 425 -640 427 -640 640 -640 480 -640 427 -640 640 -640 426 -640 480 -640 480 -640 480 -500 410 -640 480 -640 427 -500 500 -383 640 -640 480 -640 480 -640 428 -360 439 -480 640 -500 480 -640 427 -422 640 -426 640 -500 375 -640 480 -596 640 -426 640 -640 480 -500 332 -612 612 -640 480 -640 480 -640 480 -640 278 -640 480 -640 426 -640 427 -640 427 -612 612 -311 308 -640 427 -640 429 -640 428 -640 480 -612 612 -500 335 -640 480 -640 427 -640 481 -500 333 -640 480 -640 480 -640 479 -640 480 -450 395 -640 480 -640 479 -640 427 -480 640 -640 480 -640 426 -426 640 -640 360 -427 640 -423 640 -640 480 -437 500 -640 481 -640 426 -640 480 -640 480 -640 427 -640 480 -640 480 -500 332 -640 480 -640 426 -640 480 -640 362 -640 479 -640 480 -640 426 -497 640 -640 427 -640 429 -640 427 -640 541 -480 640 -600 418 -640 480 -500 333 -640 480 -448 299 -640 427 -500 333 -640 480 -375 500 -375 500 -480 640 -640 480 -640 427 -640 480 -478 640 -640 426 -426 640 -427 640 -640 427 -640 427 -480 640 -640 280 -640 425 -375 500 -480 640 -640 447 -425 640 -640 426 -428 640 -640 480 -415 500 -640 640 -640 468 -427 640 -640 480 -640 464 -640 361 -640 480 -640 640 -612 612 -640 444 -640 427 -640 427 -640 427 -500 468 -640 442 -426 640 -640 388 -480 640 -640 480 -427 640 -640 444 -500 333 -427 640 -600 400 -640 427 -640 427 -640 435 -640 360 -640 426 -640 428 -480 640 -640 427 -640 428 -640 354 -640 186 -640 426 -640 430 -500 377 -480 640 -640 428 -640 480 -640 559 -427 640 -500 333 -640 427 -523 640 -640 426 -640 480 -640 480 -500 333 -500 375 -401 500 -375 500 -640 428 -480 640 -305 229 -480 640 -480 640 -640 426 -640 480 -640 409 -640 427 -640 425 -640 428 -375 500 -640 501 -500 375 -640 480 -500 375 -640 480 -640 480 -612 612 -640 425 -427 640 -424 640 -640 480 -640 480 -640 425 -427 640 -512 640 -640 428 -640 429 -640 427 -640 480 -640 427 -612 612 -640 480 -640 474 -612 612 -640 424 -405 640 -640 480 -612 612 -640 480 -640 480 -500 375 -640 616 -640 427 -480 640 -480 640 -500 333 -640 427 -500 375 -480 640 -640 480 -640 426 -640 424 -640 523 -640 427 -443 640 -640 427 -640 424 -640 421 -500 334 -640 640 -640 479 -427 640 -640 434 -401 640 -640 426 -640 428 -612 612 -491 640 -428 640 -480 640 -640 490 -640 480 -480 640 -640 427 -480 640 -500 375 -640 480 -640 481 -500 333 -640 480 -640 457 -419 640 -640 480 -640 427 -426 640 -640 427 -640 429 -500 375 -426 640 -640 401 -640 426 -480 640 -640 359 -374 500 -479 640 -500 333 -640 480 -640 504 -612 612 -640 457 -500 401 -640 429 -640 449 -500 298 -640 426 -500 375 -375 500 -640 412 -640 385 -640 406 -640 478 -640 427 -640 427 -500 375 -640 480 -640 440 -640 480 -640 530 -480 360 -480 640 -640 480 -640 480 -480 640 -640 429 -640 431 -640 481 -640 469 -640 479 -640 480 -481 640 -640 427 -640 480 -426 640 -640 480 -425 640 -480 640 -640 425 -500 375 -628 640 -640 565 -500 375 -330 500 -374 500 -500 333 -640 427 -500 333 -640 440 -640 426 -480 640 -612 612 -428 640 -480 640 -640 428 -575 640 -640 425 -640 427 -500 375 -500 366 -427 640 -500 281 -428 640 -398 640 -640 480 -640 427 -640 428 -640 428 -500 400 -500 373 -500 375 -640 426 -640 425 -640 424 -500 333 -640 418 -425 640 -640 427 -640 480 -640 583 -640 481 -640 349 -480 640 -640 428 -640 427 -640 480 -640 480 -640 640 -640 427 -640 427 -480 640 -640 480 -640 480 -640 463 -499 640 -640 426 -640 302 -427 640 -640 427 -640 480 -640 443 -500 333 -640 480 -511 640 -640 463 -426 640 -500 336 -640 480 -640 382 -640 480 -640 427 -640 513 -428 640 -479 640 -640 360 -640 425 -427 640 -640 427 -640 428 -480 640 -640 480 -640 502 -640 354 -500 375 -486 500 -500 333 -640 426 -480 640 -640 421 -640 427 -640 480 -640 480 -640 512 -640 427 -640 512 -500 333 -640 363 -640 427 -640 427 -402 640 -361 640 -427 640 -640 640 -500 375 -640 427 -500 333 -640 480 -640 594 -640 427 -456 640 -640 480 -640 434 -640 536 -640 427 -640 582 -640 549 -640 428 -640 516 -640 480 -640 480 -640 480 -640 480 -640 348 -640 480 -480 640 -640 425 -480 640 -480 640 -640 427 -640 425 -640 426 -640 427 -480 640 -640 427 -640 360 -427 640 -640 425 -640 480 -640 428 -640 480 -640 339 -427 640 -640 480 -640 480 -640 427 -640 423 -640 427 -640 426 -640 427 -640 428 -411 640 -640 420 -640 480 -488 640 -500 334 -431 640 -640 403 -640 428 -500 375 -500 375 -640 480 -327 500 -500 333 -480 640 -598 640 -500 375 -640 480 -500 375 -640 431 -640 480 -500 375 -640 480 -427 640 -640 480 -640 425 -480 640 -500 375 -640 480 -640 426 -640 480 -640 360 -640 480 -640 456 -500 375 -640 398 -471 640 -481 640 -640 359 -500 381 -640 524 -383 640 -640 427 -640 481 -640 480 -640 480 -428 640 -478 640 -500 329 -640 425 -375 500 -640 480 -640 426 -640 424 -500 455 -480 640 -612 612 -500 312 -640 480 -640 428 -640 480 -512 640 -640 434 -640 640 -478 640 -640 369 -640 480 -511 640 -500 332 -612 612 -640 281 -640 427 -427 640 -640 480 -640 428 -640 425 -640 480 -426 640 -640 640 -640 480 -425 640 -640 434 -640 514 -640 480 -480 640 -640 480 -640 484 -439 640 -640 431 -480 640 -371 500 -426 640 -640 334 -640 353 -427 640 -427 640 -427 640 -640 427 -480 640 -424 640 -426 640 -640 425 -640 480 -333 500 -426 640 -640 429 -640 640 -640 427 -500 375 -640 428 -640 480 -640 480 -427 640 -640 424 -552 640 -640 506 -640 424 -640 427 -640 480 -500 333 -500 375 -640 392 -640 570 -640 424 -640 427 -500 401 -640 427 -478 640 -640 425 -640 480 -640 480 -640 513 -640 480 -425 640 -640 640 -640 427 -640 480 -356 533 -500 375 -640 360 -427 640 -426 640 -640 427 -640 480 -640 480 -640 480 -640 480 -640 425 -640 480 -640 479 -640 425 -600 399 -640 366 -640 443 -500 375 -640 434 -640 428 -640 418 -640 480 -426 640 -513 640 -640 416 -640 428 -640 427 -500 375 -640 480 -519 640 -500 313 -640 480 -345 500 -640 334 -640 402 -640 427 -612 612 -480 640 -640 480 -640 413 -640 427 -640 426 -480 640 -640 426 -640 426 -427 640 -640 480 -612 612 -480 640 -500 375 -640 518 -640 480 -640 359 -500 375 -640 427 -500 375 -640 480 -640 480 -612 612 -640 429 -640 427 -640 427 -640 425 -640 426 -640 427 -640 428 -500 316 -640 480 -640 640 -640 436 -640 427 -480 640 -640 425 -640 480 -640 480 -479 640 -640 480 -640 427 -640 480 -427 640 -640 640 -640 359 -612 612 -640 480 -640 480 -640 480 -640 480 -425 640 -640 444 -640 480 -326 500 -457 640 -640 480 -579 640 -640 360 -640 435 -640 480 -362 500 -640 480 -428 640 -640 458 -375 500 -640 480 -480 640 -529 640 -375 500 -640 534 -640 480 -640 505 -640 428 -500 375 -640 426 -640 427 -500 375 -640 314 -640 480 -304 640 -640 480 -480 640 -468 405 -426 640 -519 640 -640 480 -640 480 -640 427 -640 480 -640 480 -640 426 -640 427 -500 375 -640 292 -640 480 -640 566 -427 640 -640 526 -640 480 -640 427 -427 640 -640 424 -640 427 -640 426 -640 480 -640 427 -640 426 -640 480 -428 640 -640 424 -640 425 -640 483 -429 640 -424 640 -640 426 -612 612 -640 480 -640 480 -640 430 -640 480 -512 640 -467 640 -640 426 -640 427 -500 241 -640 480 -640 480 -481 640 -427 640 -640 480 -640 326 -640 564 -640 640 -480 640 -640 286 -425 640 -480 640 -423 640 -640 424 -640 426 -640 428 -640 427 -640 426 -640 480 -480 640 -640 640 -375 500 -640 628 -640 426 -640 399 -640 428 -640 427 -612 612 -640 477 -640 425 -612 612 -640 480 -640 480 -640 427 -640 480 -640 480 -428 640 -480 640 -640 444 -640 501 -480 640 -500 333 -619 640 -640 427 -640 498 -640 480 -640 480 -426 640 -500 375 -640 426 -640 480 -640 640 -480 640 -640 426 -640 428 -468 640 -640 427 -640 480 -640 427 -375 500 -640 480 -640 427 -640 359 -640 427 -640 425 -640 426 -640 361 -640 480 -640 427 -389 640 -427 640 -640 393 -612 612 -480 640 -427 640 -640 428 -640 491 -428 640 -472 640 -640 427 -640 428 -508 640 -640 427 -433 640 -425 640 -588 640 -500 370 -640 427 -640 428 -640 480 -640 426 -640 448 -640 480 -640 499 -612 612 -640 427 -500 375 -578 640 -500 375 -640 426 -640 427 -640 480 -640 426 -640 640 -500 375 -640 480 -480 640 -480 640 -612 612 -640 427 -428 640 -640 427 -640 640 -480 640 -640 480 -640 480 -640 428 -640 480 -640 640 -640 480 -640 427 -640 640 -640 427 -640 481 -640 479 -320 240 -427 640 -640 427 -332 500 -500 500 -640 427 -640 480 -640 427 -640 480 -640 428 -640 376 -640 480 -333 500 -480 640 -640 428 -640 480 -640 480 -640 427 -480 640 -500 375 -640 480 -640 427 -426 640 -640 426 -640 640 -640 427 -640 494 -640 321 -640 425 -640 427 -500 375 -640 348 -640 238 -640 427 -640 453 -640 433 -640 427 -640 480 -640 480 -500 500 -640 480 -480 640 -640 480 -640 480 -480 640 -640 480 -640 480 -427 640 -640 360 -384 640 -480 640 -640 448 -500 375 -478 640 -375 500 -640 480 -640 480 -640 480 -640 424 -640 480 -640 480 -288 160 -640 468 -640 474 -427 640 -640 480 -640 480 -640 427 -640 468 -640 480 -640 427 -500 244 -640 427 -500 375 -640 222 -640 480 -640 480 -640 480 -640 427 -640 427 -640 480 -640 406 -480 640 -640 425 -640 480 -640 427 -640 429 -500 333 -640 427 -500 375 -640 391 -640 480 -640 480 -640 425 -640 427 -640 480 -480 640 -640 427 -640 480 -640 427 -640 427 -640 493 -640 428 -640 425 -640 480 -480 640 -426 640 -480 640 -480 640 -428 640 -425 640 -500 333 -500 375 -640 427 -640 427 -640 488 -640 480 -640 427 -514 640 -500 451 -640 480 -474 640 -640 425 -640 426 -640 425 -480 640 -640 498 -640 480 -640 480 -640 459 -640 480 -598 640 -640 480 -480 640 -429 640 -640 360 -500 500 -326 640 -640 427 -640 426 -640 427 -640 480 -640 428 -640 427 -640 425 -600 400 -640 619 -640 640 -426 640 -500 374 -640 480 -640 482 -480 640 -480 640 -640 428 -612 612 -640 480 -480 640 -480 640 -640 640 -640 427 -427 640 -640 480 -640 427 -640 480 -500 375 -640 569 -480 640 -640 461 -640 428 -480 640 -640 361 -640 429 -375 500 -640 427 -500 375 -640 384 -640 427 -640 428 -436 640 -600 450 -480 640 -427 640 -484 640 -640 480 -640 427 -427 640 -478 640 -480 640 -640 640 -640 480 -640 423 -500 333 -640 427 -480 640 -480 640 -640 453 -419 640 -426 640 -640 636 -640 480 -640 426 -640 427 -612 612 -640 478 -640 480 -640 427 -500 375 -640 480 -640 424 -427 640 -640 427 -640 486 -482 640 -512 640 -640 400 -427 640 -500 375 -347 500 -640 633 -640 426 -480 640 -500 336 -640 382 -640 484 -500 333 -640 425 -640 427 -640 427 -640 427 -640 427 -640 427 -640 427 -427 640 -640 512 -500 334 -640 427 -640 573 -425 640 -640 427 -480 640 -640 427 -640 480 -400 266 -640 480 -480 640 -640 427 -640 481 -640 480 -500 375 -640 640 -536 640 -640 480 -640 480 -640 480 -640 425 -640 480 -640 427 -270 360 -640 480 -640 480 -640 512 -394 401 -500 342 -320 240 -424 640 -500 333 -640 468 -383 640 -640 427 -425 640 -640 492 -640 425 -640 480 -640 416 -480 640 -640 427 -640 480 -640 453 -640 427 -640 427 -640 426 -640 489 -480 640 -426 640 -549 640 -640 427 -640 478 -640 427 -640 425 -480 640 -480 640 -640 428 -640 427 -640 440 -640 506 -500 375 -612 612 -640 426 -640 480 -640 352 -640 427 -480 640 -640 415 -640 480 -640 413 -640 504 -640 401 -500 375 -612 612 -500 375 -640 426 -427 640 -640 480 -640 359 -427 640 -640 480 -500 276 -500 375 -640 439 -640 427 -500 314 -480 640 -640 622 -640 423 -500 435 -640 432 -640 480 -640 640 -500 403 -375 500 -640 426 -500 375 -640 425 -640 425 -640 427 -640 640 -580 640 -640 313 -640 640 -612 612 -640 386 -640 427 -640 427 -640 480 -612 612 -640 427 -640 480 -640 424 -612 612 -640 517 -426 640 -640 433 -640 418 -640 441 -640 426 -640 425 -480 640 -640 360 -640 310 -640 425 -640 480 -640 425 -500 333 -640 427 -640 428 -480 640 -640 427 -640 428 -640 484 -481 640 -503 480 -640 159 -640 480 -425 640 -480 640 -640 427 -456 640 -640 354 -425 640 -552 640 -640 427 -640 552 -640 480 -640 427 -640 480 -640 426 -640 640 -640 427 -640 480 -640 480 -425 640 -640 480 -640 428 -640 480 -640 480 -640 640 -640 425 -640 415 -640 483 -640 361 -640 427 -640 427 -500 330 -640 425 -640 427 -640 426 -500 333 -640 480 -640 360 -640 427 -640 426 -640 426 -427 640 -425 640 -640 430 -640 480 -426 640 -640 427 -480 640 -612 612 -640 356 -375 500 -425 640 -640 480 -640 428 -640 360 -389 500 -500 375 -427 640 -640 427 -640 428 -640 423 -478 640 -640 427 -640 424 -640 427 -423 640 -334 500 -640 427 -640 427 -640 480 -640 480 -640 360 -640 519 -480 640 -640 390 -640 425 -500 325 -640 421 -478 640 -640 425 -500 375 -640 424 -640 422 -500 375 -640 640 -332 500 -640 426 -640 427 -640 308 -480 640 -457 640 -640 480 -612 612 -640 480 -640 434 -450 420 -640 480 -640 400 -640 428 -640 582 -640 427 -640 386 -500 400 -640 480 -640 427 -640 499 -640 480 -375 500 -640 425 -480 640 -480 640 -500 375 -640 390 -480 640 -640 425 -500 400 -425 640 -500 374 -640 480 -500 333 -640 469 -640 444 -640 428 -418 640 -640 431 -500 281 -640 426 -423 640 -413 640 -500 375 -425 640 -480 640 -640 427 -640 489 -500 325 -640 480 -500 340 -640 359 -640 427 -640 480 -480 640 -480 640 -640 427 -640 387 -480 640 -480 640 -400 280 -640 480 -640 480 -640 480 -331 500 -640 481 -640 454 -640 480 -640 480 -640 426 -640 480 -640 427 -640 360 -640 480 -640 480 -500 345 -640 427 -640 480 -428 640 -500 375 -640 427 -640 426 -640 426 -480 640 -612 612 -640 439 -640 427 -640 599 -640 428 -640 428 -500 375 -640 512 -427 640 -640 360 -640 427 -640 480 -500 375 -500 375 -500 291 -480 640 -480 640 -640 480 -500 375 -612 612 -443 640 -640 561 -640 427 -467 640 -427 640 -640 427 -640 426 -640 424 -480 640 -427 640 -375 500 -640 480 -640 427 -528 640 -640 360 -640 480 -640 427 -333 500 -640 478 -400 640 -500 375 -640 427 -640 481 -640 427 -480 640 -640 426 -640 480 -427 640 -640 480 -640 419 -640 427 -480 640 -640 428 -640 427 -640 534 -640 425 -640 480 -480 640 -640 480 -393 316 -640 445 -640 480 -480 640 -480 640 -427 640 -640 480 -640 417 -425 640 -640 427 -640 426 -500 281 -585 640 -640 480 -500 375 -640 480 -640 480 -640 427 -640 421 -640 427 -587 640 -640 452 -640 427 -640 480 -640 425 -640 640 -640 488 -480 640 -640 359 -640 503 -640 480 -500 332 -640 521 -427 640 -640 428 -640 480 -640 427 -640 480 -375 500 -640 367 -640 480 -640 480 -427 640 -640 480 -640 427 -640 512 -640 480 -500 333 -640 480 -640 427 -640 333 -640 424 -640 480 -640 427 -640 427 -640 480 -640 427 -640 425 -480 640 -500 375 -640 428 -640 427 -640 480 -612 612 -375 500 -500 375 -500 333 -500 375 -640 480 -640 427 -640 480 -500 375 -640 478 -640 426 -640 480 -500 400 -375 500 -640 428 -640 499 -640 360 -640 427 -640 480 -640 480 -640 427 -640 480 -640 485 -427 640 -375 500 -640 456 -640 464 -473 640 -640 359 -640 425 -612 612 -640 427 -444 640 -640 480 -640 428 -640 414 -500 375 -333 500 -500 333 -640 437 -612 612 -333 500 -640 548 -640 480 -640 512 -480 640 -640 428 -640 480 -375 500 -640 429 -333 500 -640 480 -640 438 -379 640 -640 427 -640 426 -479 640 -640 480 -500 375 -640 429 -500 375 -640 480 -640 426 -640 480 -640 480 -640 427 -640 467 -427 640 -640 426 -427 640 -640 434 -480 640 -612 612 -640 425 -640 427 -640 427 -442 640 -500 333 -480 640 -640 480 -640 431 -476 261 -640 427 -640 427 -480 640 -640 427 -480 640 -480 640 -640 640 -500 334 -640 425 -640 427 -427 640 -640 427 -480 640 -500 375 -640 427 -640 480 -478 640 -640 480 -640 466 -478 640 -512 640 -640 418 -640 478 -480 640 -640 427 -640 480 -640 480 -500 375 -500 375 -480 640 -640 480 -640 427 -480 640 -427 640 -375 500 -640 427 -640 480 -640 426 -480 640 -425 640 -640 428 -445 640 -640 427 -640 427 -427 640 -640 522 -500 334 -640 427 -640 360 -640 425 -480 640 -441 640 -640 480 -640 469 -640 427 -427 640 -612 612 -500 375 -400 600 -640 360 -426 640 -640 480 -640 480 -640 480 -640 356 -640 480 -640 480 -640 480 -640 426 -640 360 -640 426 -640 480 -640 480 -600 402 -640 480 -480 640 -385 289 -640 360 -640 480 -640 480 -640 480 -640 426 -640 480 -640 480 -640 426 -427 640 -640 479 -428 640 -480 640 -500 375 -640 406 -334 500 -640 413 -427 640 -375 500 -427 640 -480 640 -640 480 -636 640 -640 426 -500 375 -480 640 -480 640 -640 576 -640 640 -640 426 -612 612 -640 426 -640 429 -640 342 -428 640 -480 640 -480 640 -427 640 -640 480 -640 479 -640 427 -640 425 -500 400 -427 640 -500 375 -640 480 -640 427 -480 640 -640 478 -640 480 -480 640 -427 640 -640 428 -500 375 -640 396 -375 500 -300 500 -640 429 -428 640 -640 426 -480 640 -640 480 -480 640 -640 429 -640 389 -640 427 -640 428 -640 480 -480 640 -480 640 -426 640 -640 480 -640 480 -640 443 -640 480 -480 640 -640 494 -640 425 -427 640 -442 640 -640 424 -640 450 -640 286 -426 640 -480 640 -640 480 -640 480 -640 480 -640 480 -427 640 -640 480 -640 484 -500 375 -500 485 -640 427 -640 480 -640 427 -543 640 -640 427 -640 480 -640 480 -640 427 -500 376 -640 425 -640 480 -640 273 -480 640 -640 427 -640 426 -428 640 -640 360 -640 425 -640 480 -640 429 -500 368 -640 482 -640 480 -427 640 -640 427 -640 480 -640 427 -640 480 -640 479 -640 640 -640 428 -500 375 -640 427 -640 428 -500 333 -480 640 -396 297 -640 479 -640 425 -598 640 -640 582 -640 553 -640 480 -480 640 -640 480 -500 332 -640 425 -640 480 -427 640 -640 480 -500 335 -640 427 -640 480 -427 640 -640 480 -600 400 -427 640 -640 480 -640 426 -640 426 -640 427 -480 640 -480 640 -589 640 -640 480 -640 428 -640 424 -640 427 -428 640 -640 480 -640 454 -424 640 -640 427 -640 425 -640 480 -640 427 -640 427 -480 640 -612 612 -333 500 -640 480 -640 480 -572 640 -640 439 -640 427 -427 640 -640 426 -426 640 -640 480 -640 427 -640 480 -457 640 -640 419 -640 418 -480 640 -425 640 -480 640 -480 640 -500 332 -640 424 -640 396 -640 427 -640 640 -640 480 -640 406 -500 375 -640 512 -640 424 -640 480 -640 480 -640 374 -640 354 -640 427 -640 428 -500 375 -640 480 -480 640 -640 480 -640 480 -500 281 -640 539 -640 625 -426 640 -359 640 -640 427 -640 478 -428 640 -500 333 -375 500 -480 640 -640 426 -500 375 -640 458 -640 457 -640 427 -612 612 -500 375 -640 480 -640 478 -640 480 -640 400 -640 480 -375 500 -640 480 -426 640 -640 640 -612 612 -640 480 -640 424 -480 640 -640 480 -640 427 -640 427 -640 359 -640 427 -640 480 -640 480 -640 424 -640 427 -500 375 -612 612 -640 427 -427 640 -335 500 -640 480 -640 480 -640 427 -428 640 -640 427 -375 500 -500 375 -640 393 -640 546 -640 384 -640 480 -500 375 -333 500 -480 640 -640 428 -640 326 -640 360 -533 640 -640 427 -640 427 -640 422 -640 480 -427 640 -640 478 -640 360 -640 480 -600 398 -480 640 -640 480 -426 640 -640 427 -640 411 -480 640 -640 427 -461 640 -640 427 -480 640 -478 640 -640 480 -640 427 -640 428 -438 500 -426 640 -480 640 -480 640 -500 373 -500 375 -640 508 -640 480 -500 434 -640 480 -640 427 -640 480 -640 427 -426 640 -421 640 -640 383 -427 640 -640 480 -640 428 -500 334 -375 500 -640 480 -640 541 -640 424 -640 478 -426 640 -426 640 -480 640 -640 427 -640 480 -640 422 -640 360 -478 640 -640 476 -504 337 -528 400 -612 612 -500 333 -640 480 -640 480 -427 640 -480 640 -640 427 -480 640 -375 500 -612 612 -640 427 -474 640 -375 500 -640 381 -426 640 -500 375 -640 429 -375 500 -480 640 -640 480 -640 480 -640 480 -640 426 -335 500 -640 480 -640 427 -640 480 -612 612 -640 427 -640 512 -612 612 -640 480 -640 426 -640 427 -640 427 -640 480 -640 427 -425 640 -500 400 -640 636 -640 427 -640 427 -480 640 -640 427 -375 500 -640 413 -640 427 -640 427 -640 426 -640 480 -429 640 -640 480 -640 427 -480 640 -640 480 -640 427 -480 640 -640 427 -500 333 -495 640 -500 406 -640 427 -640 480 -640 480 -480 640 -640 303 -375 500 -612 612 -500 334 -640 528 -640 427 -640 480 -435 640 -640 289 -640 480 -640 480 -427 640 -640 496 -640 427 -612 612 -640 398 -448 640 -640 426 -640 426 -480 640 -640 427 -640 457 -640 427 -640 480 -640 427 -500 375 -333 500 -640 480 -640 295 -640 480 -640 480 -640 427 -500 334 -527 640 -640 558 -640 433 -332 500 -640 425 -500 333 -640 427 -480 640 -500 375 -640 429 -640 480 -640 480 -640 427 -640 480 -500 333 -640 426 -612 612 -500 375 -400 300 -640 428 -612 612 -640 480 -640 480 -640 480 -640 450 -640 427 -640 364 -640 433 -640 427 -640 427 -400 500 -640 428 -640 480 -640 480 -640 480 -640 640 -333 500 -426 640 -420 640 -640 480 -640 427 -640 480 -500 375 -640 478 -640 434 -480 640 -329 500 -640 480 -640 424 -640 426 -612 612 -640 480 -640 480 -640 427 -640 480 -427 640 -640 480 -640 480 -500 385 -427 640 -640 478 -640 376 -640 427 -478 640 -625 505 -640 388 -480 640 -640 433 -640 480 -640 426 -640 427 -640 480 -640 480 -500 295 -640 329 -332 291 -500 375 -640 480 -640 458 -640 426 -424 640 -640 427 -500 375 -500 376 -640 480 -640 246 -480 640 -640 427 -640 427 -640 480 -500 336 -359 640 -428 640 -640 426 -512 640 -640 480 -640 480 -640 450 -480 640 -480 640 -500 375 -640 427 -481 640 -375 500 -333 500 -640 428 -467 640 -500 434 -640 480 -480 640 -640 360 -640 414 -480 640 -480 640 -500 375 -640 427 -480 640 -640 426 -640 468 -500 375 -640 425 -640 426 -640 494 -640 427 -640 480 -640 427 -640 425 -478 640 -478 640 -640 488 -640 480 -640 426 -426 640 -640 427 -640 346 -640 480 -640 408 -640 426 -415 640 -640 480 -640 407 -640 480 -640 427 -640 427 -500 375 -640 480 -640 427 -640 419 -480 640 -640 499 -480 640 -425 640 -612 612 -640 639 -640 427 -640 495 -640 480 -480 640 -640 427 -640 480 -640 425 -427 640 -640 506 -640 480 -640 480 -640 448 -640 399 -640 480 -640 301 -640 481 -500 375 -640 514 -640 374 -640 359 -436 640 -640 427 -640 426 -640 441 -500 400 -428 640 -640 427 -640 480 -640 457 -640 428 -640 480 -640 480 -500 375 -640 427 -612 612 -500 333 -428 640 -640 480 -640 426 -640 427 -640 427 -640 426 -480 640 -640 478 -640 480 -640 480 -600 449 -640 480 -640 431 -640 480 -640 427 -480 640 -640 425 -480 640 -640 480 -426 640 -640 480 -640 480 -640 480 -640 418 -640 426 -640 535 -640 438 -426 640 -640 480 -640 498 -427 640 -640 440 -640 533 -426 640 -640 427 -612 612 -320 240 -640 513 -640 428 -640 480 -480 640 -480 640 -640 299 -500 334 -640 438 -500 375 -341 500 -640 372 -426 640 -640 512 -500 390 -640 480 -512 640 -640 640 -640 360 -375 500 -480 640 -480 640 -640 480 -640 480 -375 500 -607 640 -500 375 -640 445 -640 464 -480 640 -500 343 -640 480 -640 427 -640 427 -640 480 -640 480 -640 480 -640 480 -640 360 -427 640 -425 640 -500 333 -640 480 -640 428 -640 480 -524 640 -640 458 -500 375 -500 375 -561 640 -640 483 -640 457 -640 578 -478 640 -640 425 -640 480 -500 370 -500 375 -333 500 -640 429 -640 427 -500 333 -640 426 -500 375 -640 480 -640 480 -640 427 -480 640 -640 482 -640 480 -480 640 -480 640 -640 480 -640 480 -512 384 -640 426 -375 500 -640 417 -480 640 -640 426 -640 480 -375 500 -640 518 -640 427 -640 427 -640 480 -426 640 -640 427 -640 427 -640 496 -640 370 -640 359 -640 432 -640 480 -612 612 -426 640 -640 359 -383 640 -640 426 -640 426 -478 640 -640 480 -500 374 -427 640 -500 283 -612 612 -640 399 -640 480 -640 480 -640 427 -640 428 -500 375 -640 480 -483 640 -640 480 -385 308 -500 375 -480 640 -640 426 -640 426 -612 612 -332 500 -640 480 -640 426 -640 427 -640 426 -640 480 -640 478 -556 640 -500 375 -478 640 -640 428 -640 480 -425 640 -640 478 -640 480 -640 434 -640 427 -500 480 -640 427 -425 640 -640 429 -640 370 -512 640 -640 480 -640 426 -640 427 -640 427 -640 480 -640 480 -429 640 -640 480 -640 448 -640 480 -640 427 -426 640 -640 480 -640 426 -640 480 -640 426 -458 640 -500 375 -500 376 -640 480 -612 612 -480 640 -424 640 -640 480 -640 639 -640 427 -640 480 -500 333 -500 375 -640 503 -315 500 -333 500 -400 272 -640 480 -640 480 -500 333 -640 478 -640 591 -500 294 -640 426 -640 427 -640 425 -640 457 -480 640 -480 640 -640 427 -640 480 -480 640 -640 428 -640 432 -640 343 -428 640 -640 480 -640 429 -640 360 -640 480 -332 500 -640 480 -640 426 -640 640 -640 425 -640 427 -500 333 -500 375 -640 480 -640 480 -427 640 -640 480 -640 427 -480 640 -375 500 -640 426 -640 398 -640 427 -640 427 -640 427 -640 427 -453 640 -427 640 -640 480 -640 524 -640 427 -640 479 -640 480 -375 500 -640 480 -640 458 -640 522 -640 427 -500 375 -500 333 -500 375 -640 426 -640 480 -640 480 -640 426 -436 640 -500 375 -375 500 -500 375 -640 480 -640 480 -640 480 -500 321 -500 375 -640 426 -640 480 -640 427 -640 480 -426 640 -640 360 -413 640 -640 382 -640 425 -640 480 -640 480 -427 640 -640 383 -640 480 -478 640 -640 480 -427 640 -428 640 -500 333 -640 480 -612 612 -339 500 -640 427 -640 376 -640 360 -640 428 -480 640 -640 426 -640 480 -500 500 -269 480 -629 640 -640 480 -640 480 -612 612 -640 491 -640 480 -640 601 -640 480 -426 640 -640 480 -640 397 -640 426 -424 640 -480 640 -640 526 -640 386 -480 640 -375 500 -640 469 -640 601 -615 310 -640 480 -640 448 -547 640 -480 640 -480 640 -518 640 -640 427 -427 640 -433 640 -640 439 -640 480 -480 640 -612 612 -640 281 -640 480 -640 427 -640 480 -640 427 -640 428 -437 640 -640 428 -640 480 -640 480 -640 424 -500 336 -425 640 -500 308 -640 360 -640 424 -640 425 -446 640 -640 252 -640 483 -640 480 -640 627 -640 428 -500 480 -640 453 -612 612 -640 428 -375 500 -640 480 -640 480 -640 417 -640 378 -640 425 -640 480 -480 640 -640 481 -640 504 -595 640 -640 480 -640 597 -500 375 -640 427 -479 640 -640 512 -640 426 -500 416 -500 375 -640 400 -500 375 -472 640 -500 375 -500 375 -640 480 -480 640 -640 561 -427 640 -640 426 -640 480 -640 427 -480 640 -640 428 -640 480 -640 426 -640 562 -640 428 -500 334 -640 426 -640 427 -640 480 -640 425 -640 491 -500 375 -640 426 -396 640 -480 640 -640 426 -480 640 -640 480 -640 480 -427 640 -640 427 -500 337 -427 640 -457 640 -375 500 -612 612 -480 640 -640 480 -500 375 -612 612 -640 480 -640 427 -640 423 -612 612 -480 640 -378 500 -480 640 -500 238 -640 447 -640 480 -640 427 -640 480 -480 640 -640 480 -640 480 -640 368 -640 424 -640 427 -640 359 -500 375 -640 480 -640 362 -500 398 -640 514 -640 480 -640 480 -500 375 -480 640 -480 640 -478 640 -640 427 -640 427 -480 360 -380 500 -424 640 -640 426 -640 480 -640 320 -640 480 -640 428 -640 426 -335 500 -640 427 -375 500 -640 425 -640 478 -640 427 -426 640 -640 480 -427 640 -543 640 -483 640 -640 480 -640 480 -480 640 -500 375 -640 428 -424 640 -640 480 -427 640 -640 426 -640 434 -427 640 -500 334 -480 640 -640 480 -480 640 -426 640 -640 480 -640 425 -640 427 -640 480 -640 480 -500 272 -640 480 -640 480 -640 480 -428 640 -500 375 -424 640 -375 500 -640 360 -612 612 -640 427 -640 432 -425 640 -640 359 -426 640 -640 427 -640 430 -480 640 -640 427 -640 426 -339 500 -640 479 -640 427 -500 326 -500 333 -464 640 -463 640 -640 426 -640 480 -500 375 -640 427 -640 427 -640 427 -480 640 -640 423 -640 483 -640 479 -640 320 -640 608 -640 427 -640 425 -378 500 -426 640 -640 480 -640 480 -432 640 -640 480 -478 640 -640 415 -640 530 -640 372 -640 424 -640 360 -640 480 -480 640 -640 426 -395 640 -640 359 -640 427 -500 333 -640 480 -480 640 -640 360 -640 480 -500 334 -425 640 -640 480 -640 427 -640 480 -640 425 -500 374 -480 640 -640 429 -640 480 -640 426 -357 640 -496 640 -640 426 -640 425 -640 425 -640 480 -427 640 -640 427 -640 438 -480 640 -640 377 -640 480 -640 428 -640 480 -612 612 -640 527 -640 427 -375 500 -640 424 -640 480 -640 457 -500 334 -640 425 -525 640 -640 428 -333 500 -480 640 -640 419 -480 640 -640 426 -640 480 -640 426 -640 468 -640 480 -480 640 -640 425 -512 640 -640 427 -427 640 -500 375 -515 640 -480 640 -428 640 -331 500 -500 332 -480 640 -640 480 -640 427 -640 427 -640 480 -500 335 -640 480 -640 425 -640 360 -640 480 -625 640 -480 640 -480 640 -478 640 -640 426 -428 640 -640 480 -640 480 -640 396 -500 376 -506 640 -640 514 -500 333 -640 480 -480 640 -612 612 -480 640 -640 480 -425 640 -548 640 -640 427 -640 480 -640 480 -640 427 -640 429 -640 426 -640 427 -640 427 -640 480 -480 640 -640 427 -640 512 -640 480 -640 480 -324 328 -640 361 -640 480 -640 427 -640 428 -640 426 -640 480 -640 359 -640 480 -500 334 -480 640 -640 427 -640 480 -640 480 -640 427 -640 400 -640 561 -640 480 -640 360 -640 425 -640 480 -428 640 -480 640 -460 640 -480 640 -640 428 -334 500 -425 640 -640 428 -640 529 -640 427 -640 606 -305 229 -640 480 -640 361 -333 500 -640 480 -640 490 -640 424 -640 433 -640 425 -427 640 -640 428 -640 424 -558 558 -640 427 -640 480 -640 426 -640 480 -640 563 -375 500 -640 480 -335 500 -640 360 -640 424 -375 500 -573 640 -640 480 -640 480 -640 425 -425 640 -640 360 -640 480 -640 425 -640 480 -480 640 -640 360 -640 480 -640 426 -640 480 -640 427 -640 425 -640 424 -640 480 -426 640 -640 427 -375 500 -500 360 -500 375 -640 427 -500 257 -640 424 -356 500 -640 494 -426 640 -640 480 -412 640 -640 480 -433 640 -640 480 -427 640 -375 500 -500 369 -612 612 -640 480 -427 640 -396 640 -612 612 -640 480 -500 332 -480 640 -640 480 -640 428 -640 426 -640 397 -640 534 -500 375 -640 427 -640 480 -640 480 -480 640 -640 427 -427 640 -640 480 -640 480 -640 480 -640 359 -640 337 -480 640 -308 500 -375 500 -640 578 -640 480 -640 427 -360 640 -480 640 -640 480 -612 612 -640 443 -612 612 -640 480 -640 427 -500 500 -640 391 -478 640 -639 640 -332 500 -332 500 -428 640 -425 640 -640 480 -480 640 -640 480 -500 375 -640 480 -427 640 -640 480 -640 427 -640 428 -640 480 -640 381 -640 427 -612 612 -640 426 -640 427 -640 480 -640 427 -612 612 -248 500 -500 208 -640 544 -640 427 -640 427 -500 358 -640 428 -640 480 -640 427 -640 480 -640 360 -640 425 -500 375 -480 640 -640 427 -640 376 -640 480 -640 424 -640 360 -500 375 -640 427 -640 471 -640 360 -640 475 -640 428 -415 640 -640 334 -640 426 -640 427 -300 400 -640 480 -640 480 -612 612 -640 426 -640 425 -480 640 -640 452 -500 375 -640 476 -600 455 -640 480 -640 640 -640 480 -500 335 -479 640 -640 427 -500 375 -640 426 -428 640 -480 640 -640 480 -640 480 -640 427 -640 424 -640 428 -623 640 -640 425 -640 438 -640 480 -640 427 -640 425 -640 480 -640 640 -640 480 -640 480 -640 329 -591 640 -640 480 -427 640 -612 612 -399 600 -640 364 -640 489 -640 480 -375 500 -640 426 -426 640 -429 640 -427 640 -640 427 -640 427 -640 614 -640 427 -640 312 -640 427 -640 427 -504 640 -427 640 -427 640 -640 589 -426 640 -640 606 -640 427 -427 640 -640 640 -640 480 -640 427 -500 333 -464 640 -640 426 -427 640 -640 480 -640 480 -612 612 -640 480 -500 366 -640 480 -640 425 -640 640 -640 484 -500 375 -640 359 -351 500 -640 480 -640 320 -640 427 -640 473 -640 480 -640 427 -640 411 -500 331 -640 480 -480 640 -640 480 -612 612 -640 427 -640 470 -500 375 -512 640 -640 640 -640 480 -640 480 -640 427 -640 480 -500 375 -640 480 -480 640 -640 425 -640 425 -640 427 -640 464 -500 500 -640 427 -640 480 -640 423 -500 333 -640 311 -640 449 -640 427 -472 500 -640 640 -433 640 -640 383 -640 480 -640 427 -640 425 -427 640 -640 480 -640 480 -640 480 -640 480 -480 640 -640 504 -640 425 -640 478 -640 429 -640 426 -640 480 -426 640 -425 640 -500 375 -640 427 -500 375 -478 640 -500 375 -640 480 -480 640 -640 480 -640 429 -612 612 -428 640 -640 154 -640 427 -375 500 -640 480 -640 480 -640 480 -640 480 -640 427 -640 360 -640 395 -640 480 -640 640 -480 640 -640 480 -640 428 -640 480 -480 640 -640 480 -427 640 -500 478 -640 427 -612 612 -428 640 -640 480 -640 480 -640 456 -640 359 -640 450 -263 640 -640 427 -640 409 -640 480 -640 394 -640 480 -640 524 -640 511 -425 640 -640 427 -640 427 -640 426 -640 425 -427 640 -600 625 -640 427 -640 480 -600 400 -640 428 -640 426 -640 359 -500 335 -426 640 -500 336 -375 500 -640 480 -455 640 -321 500 -500 375 -353 640 -426 640 -450 216 -612 612 -454 640 -480 640 -427 640 -500 375 -500 375 -482 640 -640 480 -640 480 -612 612 -428 640 -640 480 -640 426 -640 480 -428 640 -640 480 -607 640 -640 428 -428 640 -640 480 -640 293 -640 433 -426 640 -640 428 -640 480 -640 411 -640 381 -480 640 -335 500 -450 302 -640 425 -640 480 -480 640 -457 640 -427 640 -480 640 -480 640 -500 375 -640 478 -640 427 -640 480 -640 427 -640 424 -640 360 -640 427 -640 480 -640 419 -640 480 -640 480 -640 494 -640 426 -640 423 -444 640 -640 480 -640 480 -640 480 -640 427 -500 375 -640 459 -640 428 -640 426 -640 481 -480 640 -640 425 -375 500 -515 640 -640 480 -640 480 -427 640 -640 413 -640 480 -640 480 -500 333 -427 640 -640 427 -640 428 -640 465 -480 640 -640 480 -640 428 -640 428 -640 214 -359 640 -640 478 -640 480 -640 320 -336 248 -500 400 -640 427 -640 529 -480 640 -640 427 -480 640 -640 427 -500 334 -481 640 -500 334 -480 640 -640 458 -427 640 -640 424 -640 426 -500 333 -640 523 -640 428 -640 487 -612 612 -500 375 -640 480 -640 517 -333 500 -348 500 -640 448 -640 428 -500 375 -500 375 -500 375 -640 426 -640 480 -640 480 -640 427 -640 414 -640 441 -640 480 -640 530 -640 640 -483 640 -640 480 -640 480 -427 640 -640 424 -640 428 -640 429 -375 500 -640 427 -640 480 -640 480 -640 512 -640 427 -479 640 -640 428 -640 408 -612 612 -640 480 -640 480 -375 500 -640 425 -640 427 -640 480 -480 640 -640 480 -480 640 -427 640 -640 480 -640 432 -640 427 -480 640 -640 480 -480 640 -640 480 -640 480 -640 480 -640 480 -640 480 -640 427 -449 640 -512 640 -427 640 -640 427 -500 375 -640 427 -640 519 -448 640 -640 427 -512 640 -640 391 -640 480 -640 480 -640 428 -424 640 -428 640 -640 427 -640 427 -640 425 -640 428 -447 640 -500 333 -500 334 -480 640 -640 446 -478 640 -640 480 -640 480 -640 425 -640 454 -640 426 -360 640 -500 334 -500 375 -640 427 -640 433 -480 640 -480 640 -640 426 -640 427 -640 359 -640 480 -640 480 -640 640 -500 375 -640 640 -480 640 -640 474 -640 480 -640 480 -640 427 -640 428 -500 375 -480 640 -640 480 -640 398 -427 640 -480 640 -500 375 -514 640 -500 375 -640 480 -640 427 -640 480 -500 375 -640 480 -640 480 -640 427 -480 640 -640 480 -640 425 -640 427 -640 480 -640 480 -640 424 -640 427 -640 438 -640 480 -640 427 -640 428 -424 640 -640 531 -480 640 -640 427 -500 333 -640 425 -640 425 -428 640 -480 640 -640 429 -640 480 -640 480 -375 500 -428 640 -500 375 -640 424 -640 480 -640 428 -425 640 -480 640 -640 425 -426 640 -640 480 -635 640 -500 332 -640 480 -640 480 -640 566 -640 480 -640 419 -426 640 -500 375 -425 640 -640 428 -334 500 -640 546 -519 640 -640 480 -500 375 -640 427 -612 612 -640 479 -614 640 -480 640 -480 640 -640 427 -640 480 -500 375 -640 480 -640 360 -640 480 -213 320 -500 406 -500 445 -480 640 -640 468 -640 427 -427 640 -640 427 -640 480 -500 486 -480 360 -640 428 -640 480 -480 640 -403 640 -640 480 -640 316 -425 640 -480 640 -640 429 -640 426 -640 427 -640 426 -500 375 -427 640 -612 612 -640 480 -640 480 -640 427 -640 418 -428 640 -500 324 -523 640 -640 426 -640 427 -640 427 -480 640 -640 427 -640 426 -500 500 -640 480 -640 427 -640 437 -480 640 -359 640 -640 428 -640 480 -640 424 -500 335 -500 375 -640 424 -427 640 -640 480 -405 640 -640 640 -427 640 -640 480 -333 500 -640 444 -640 426 -640 480 -500 375 -640 344 -640 394 -500 393 -375 500 -500 281 -477 558 -640 480 -640 428 -640 360 -426 640 -640 428 -640 480 -427 640 -640 480 -640 508 -640 427 -640 480 -640 480 -640 480 -640 427 -612 612 -640 428 -332 500 -640 427 -640 480 -428 640 -612 612 -640 425 -640 482 -640 419 -500 375 -640 486 -640 428 -640 428 -640 480 -500 333 -640 478 -360 640 -640 480 -640 428 -500 396 -640 424 -375 500 -640 480 -640 480 -612 612 -640 480 -640 428 -640 427 -640 447 -640 480 -640 640 -500 375 -640 480 -612 612 -640 427 -359 640 -640 424 -500 375 -640 480 -640 427 -640 479 -640 480 -640 428 -368 500 -640 640 -640 451 -544 640 -640 480 -640 439 -640 426 -640 425 -583 640 -640 429 -640 427 -640 480 -640 512 -640 480 -640 480 -640 427 -457 640 -640 429 -500 334 -640 480 -428 640 -428 640 -640 480 -480 640 -500 375 -427 640 -640 427 -406 640 -478 640 -640 480 -640 383 -612 612 -500 333 -640 427 -500 371 -612 612 -640 427 -375 500 -612 612 -468 640 -640 480 -426 640 -640 478 -640 480 -640 478 -640 480 -640 480 -640 411 -500 375 -640 427 -480 640 -640 449 -640 480 -640 480 -488 640 -640 480 -640 427 -480 640 -640 480 -480 640 -424 640 -577 640 -640 382 -480 640 -640 360 -640 480 -333 500 -333 500 -640 370 -640 480 -640 416 -640 480 -350 263 -640 480 -640 480 -640 427 -500 375 -640 516 -640 424 -426 640 -640 363 -480 640 -640 427 -640 426 -640 480 -640 425 -640 427 -640 546 -640 427 -640 427 -640 426 -375 500 -478 640 -640 480 -640 480 -480 640 -640 480 -640 480 -640 480 -640 427 -640 480 -640 480 -640 427 -500 356 -640 428 -640 428 -640 480 -640 427 -287 640 -640 480 -640 427 -640 427 -640 427 -640 427 -640 480 -375 500 -480 640 -480 640 -500 333 -500 240 -640 427 -640 428 -640 480 -500 350 -640 427 -640 480 -427 640 -361 500 -640 480 -426 640 -640 480 -375 500 -640 480 -640 480 -320 240 -640 480 -640 393 -480 640 -640 447 -500 454 -640 480 -640 428 -487 640 -640 480 -375 500 -640 480 -640 429 -640 480 -480 640 -176 144 -480 640 -640 480 -640 496 -474 640 -427 640 -612 612 -427 640 -640 480 -640 396 -640 480 -393 600 -612 612 -640 426 -640 480 -640 428 -640 480 -640 293 -640 287 -640 426 -500 375 -640 427 -480 640 -640 428 -640 427 -480 640 -640 480 -640 427 -333 500 -640 427 -640 480 -640 480 -500 336 -640 480 -640 427 -428 640 -480 640 -640 478 -640 512 -640 480 -640 480 -427 640 -640 480 -640 464 -640 426 -333 500 -500 378 -640 406 -640 427 -640 426 -426 640 -457 640 -640 478 -640 480 -640 480 -428 640 -500 375 -478 640 -500 333 -640 640 -640 426 -640 427 -640 457 -640 480 -640 398 -500 345 -640 480 -640 617 -640 361 -640 427 -640 426 -480 640 -640 640 -640 400 -640 480 -640 480 -640 480 -640 416 -480 640 -316 480 -640 429 -640 480 -640 425 -640 403 -640 425 -640 457 -640 480 -427 640 -333 500 -640 424 -640 427 -640 427 -460 640 -585 640 -640 480 -427 640 -640 479 -640 480 -500 375 -425 640 -640 480 -640 480 -640 480 -500 358 -640 480 -640 427 -640 480 -480 640 -500 375 -640 640 -427 640 -500 375 -640 428 -640 480 -640 344 -500 375 -640 480 -640 425 -640 426 -640 359 -640 469 -640 426 -480 640 -640 426 -500 375 -640 426 -480 640 -427 640 -500 375 -480 640 -640 480 -426 640 -426 640 -480 640 -426 640 -640 640 -508 640 -640 427 -427 640 -428 640 -640 480 -640 640 -480 640 -500 375 -640 480 -640 427 -640 400 -640 427 -640 480 -334 500 -409 640 -500 484 -640 424 -640 360 -612 612 -640 427 -500 327 -640 640 -640 360 -640 424 -640 428 -640 622 -640 480 -500 333 -427 640 -320 240 -640 480 -640 481 -427 640 -640 480 -640 424 -640 480 -640 480 -375 500 -640 425 -640 598 -640 425 -640 427 -612 612 -640 480 -640 215 -375 500 -537 640 -612 612 -640 480 -640 428 -640 427 -640 480 -550 640 -333 500 -640 371 -640 427 -612 612 -640 480 -480 640 -640 426 -640 427 -640 480 -415 640 -640 480 -640 480 -640 480 -640 426 -488 640 -640 428 -640 426 -640 427 -640 426 -480 640 -500 333 -512 640 -480 640 -496 640 -640 478 -618 640 -500 375 -640 480 -640 480 -589 640 -640 480 -640 426 -640 427 -640 512 -640 428 -640 480 -427 640 -640 421 -640 426 -640 611 -640 456 -640 429 -480 640 -640 480 -640 480 -375 500 -427 640 -640 480 -480 640 -640 427 -640 427 -500 375 -500 375 -500 375 -500 335 -640 309 -640 419 -640 459 -640 480 -640 518 -640 480 -640 480 -640 426 -640 480 -480 640 -427 640 -640 428 -640 480 -640 427 -640 489 -612 612 -413 640 -640 427 -640 602 -640 428 -480 640 -640 480 -500 375 -640 480 -640 481 -640 480 -640 427 -640 480 -640 480 -640 480 -640 361 -640 427 -480 640 -640 480 -640 428 -424 640 -588 640 -480 640 -500 333 -439 640 -640 427 -640 505 -640 480 -511 640 -427 640 -480 640 -480 640 -640 427 -612 612 -640 427 -432 640 -500 333 -640 480 -640 427 -640 480 -640 320 -640 427 -640 427 -640 426 -640 480 -500 375 -640 427 -480 640 -640 480 -640 425 -383 640 -612 612 -640 480 -427 640 -640 426 -375 500 -480 640 -612 612 -486 640 -640 462 -640 428 -640 426 -640 427 -427 640 -640 480 -612 612 -512 640 -640 428 -640 480 -640 478 -480 640 -640 407 -640 480 -640 480 -480 640 -428 640 -640 426 -640 428 -640 427 -640 480 -640 427 -640 504 -480 640 -640 427 -500 333 -640 427 -640 425 -640 481 -426 640 -640 427 -640 427 -640 425 -480 640 -480 640 -424 500 -640 427 -500 337 -640 480 -500 333 -427 640 -640 418 -640 354 -640 425 -640 427 -640 503 -640 427 -640 424 -500 333 -640 483 -640 426 -640 426 -640 480 -640 480 -640 426 -500 375 -640 427 -640 480 -480 640 -640 428 -427 640 -640 480 -426 640 -640 480 -640 480 -640 480 -500 375 -640 480 -640 480 -640 428 -640 428 -640 480 -640 480 -640 316 -640 513 -640 424 -480 640 -640 480 -640 428 -638 640 -640 425 -640 480 -640 480 -640 480 -640 427 -640 480 -640 478 -640 480 -640 427 -640 604 -640 361 -640 427 -480 640 -500 375 -640 480 -480 640 -640 427 -480 640 -640 429 -640 427 -640 420 -640 428 -640 427 -640 425 -640 426 -439 640 -640 480 -640 480 -640 427 -640 428 -640 427 -640 346 -640 427 -640 438 -640 427 -640 428 -500 375 -640 480 -640 431 -640 426 -640 480 -640 480 -333 500 -480 640 -640 480 -640 512 -640 340 -354 375 -640 424 -640 480 -640 480 -640 480 -640 425 -640 480 -427 640 -480 640 -500 375 -425 640 -640 480 -374 500 -500 476 -640 640 -640 427 -425 640 -400 302 -640 480 -463 500 -426 640 -640 480 -426 640 -640 427 -640 360 -640 480 -426 640 -640 480 -640 480 -640 427 -500 392 -640 378 -640 480 -640 343 -640 427 -640 426 -640 427 -640 426 -400 500 -500 333 -640 399 -640 512 -640 366 -612 612 -640 426 -640 480 -640 425 -598 640 -640 427 -480 640 -500 375 -508 640 -424 640 -640 427 -640 480 -480 640 -379 500 -640 318 -640 428 -427 640 -640 361 -640 427 -612 612 -640 427 -427 640 -480 640 -427 640 -640 427 -640 493 -640 425 -640 426 -612 612 -640 480 -640 427 -640 531 -500 333 -480 640 -640 425 -500 375 -640 399 -640 489 -640 426 -500 375 -640 427 -640 426 -640 480 -512 640 -427 640 -640 480 -406 640 -480 640 -612 612 -500 375 -640 480 -640 428 -480 640 -640 383 -640 480 -640 454 -640 480 -640 427 -425 640 -375 500 -640 480 -640 426 -640 480 -640 425 -640 427 -424 640 -469 640 -640 480 -640 480 -640 426 -375 500 -640 425 -640 457 -500 334 -640 426 -480 640 -640 480 -640 427 -640 480 -640 629 -480 640 -478 640 -480 640 -640 480 -640 426 -424 640 -640 427 -640 480 -640 480 -640 201 -640 480 -640 420 -640 480 -500 375 -640 478 -640 433 -482 640 -500 375 -640 480 -500 375 -375 500 -640 500 -640 481 -640 432 -640 425 -640 480 -640 480 -640 425 -640 400 -640 480 -640 414 -640 443 -640 425 -500 495 -640 480 -500 375 -640 480 -375 500 -640 427 -415 500 -640 427 -640 427 -500 333 -640 425 -612 612 -640 426 -426 640 -640 424 -500 290 -640 428 -640 357 -480 640 -480 640 -478 640 -640 427 -640 480 -500 333 -640 427 -640 426 -640 428 -640 569 -640 480 -457 640 -612 612 -640 428 -359 640 -640 428 -500 375 -453 640 -640 480 -640 427 -480 640 -640 427 -500 334 -333 500 -640 517 -640 425 -461 640 -490 640 -640 480 -500 375 -640 480 -480 640 -640 480 -480 640 -640 486 -640 480 -500 334 -640 480 -612 612 -640 427 -640 428 -640 310 -640 427 -612 612 -425 640 -427 640 -300 500 -640 438 -332 500 -640 427 -500 316 -427 640 -480 640 -640 480 -500 352 -640 428 -640 412 -640 480 -427 640 -413 640 -500 375 -640 226 -640 496 -640 612 -640 433 -640 464 -640 426 -640 480 -375 500 -502 640 -640 480 -500 375 -640 425 -640 480 -480 640 -640 480 -640 427 -640 480 -480 640 -480 640 -427 640 -640 393 -500 332 -640 360 -332 500 -640 427 -500 332 -640 428 -640 426 -500 375 -478 640 -640 427 -640 640 -640 427 -485 640 -478 640 -612 612 -640 425 -640 457 -545 640 -480 640 -500 375 -640 480 -512 640 -640 427 -333 500 -640 427 -640 480 -640 413 -640 480 -512 640 -640 433 -640 594 -426 640 -640 424 -480 640 -640 544 -640 427 -640 600 -640 480 -480 640 -640 349 -480 640 -334 500 -500 365 -333 500 -640 389 -640 480 -640 480 -640 421 -640 480 -375 500 -480 640 -478 640 -640 480 -640 480 -500 375 -640 425 -640 430 -640 360 -479 640 -480 640 -640 426 -640 480 -425 640 -640 480 -640 480 -640 480 -640 480 -500 335 -640 480 -480 640 -640 363 -486 640 -480 640 -640 427 -500 281 -640 416 -640 427 -480 640 -600 399 -500 350 -454 640 -640 427 -640 480 -640 480 -427 640 -640 480 -640 427 -640 461 -640 513 -640 427 -333 500 -640 427 -640 512 -640 480 -640 480 -612 612 -640 480 -500 333 -362 500 -640 427 -500 375 -500 334 -640 427 -640 425 -480 640 -640 425 -427 640 -640 427 -640 480 -448 640 -640 426 -640 427 -640 427 -480 640 -640 401 -640 427 -640 480 -640 480 -640 425 -640 435 -640 425 -640 427 -375 500 -640 480 -612 612 -640 427 -640 427 -640 480 -427 640 -640 480 -640 480 -427 640 -640 480 -640 427 -640 341 -581 640 -640 480 -480 640 -640 360 -640 409 -332 500 -640 429 -640 427 -433 640 -375 500 -640 480 -640 480 -640 512 -640 480 -640 427 -640 480 -640 427 -640 480 -640 426 -480 640 -640 480 -424 640 -640 428 -481 640 -640 426 -480 640 -640 480 -640 427 -500 375 -640 426 -640 480 -480 640 -640 480 -429 640 -640 480 -440 640 -480 640 -400 300 -640 426 -614 640 -500 455 -640 480 -640 427 -640 427 -640 425 -640 480 -640 480 -640 480 -480 640 -500 426 -500 375 -640 427 -500 335 -500 375 -500 375 -640 536 -640 640 -480 640 -640 426 -640 426 -429 640 -640 426 -640 427 -640 427 -480 640 -640 480 -640 499 -640 427 -483 640 -640 427 -640 477 -640 480 -640 512 -640 234 -640 427 -640 480 -640 480 -640 427 -640 424 -640 424 -480 640 -473 303 -500 375 -332 500 -640 427 -640 415 -478 640 -640 480 -640 425 -640 427 -640 427 -640 480 -500 333 -640 478 -640 422 -640 430 -640 480 -640 480 -500 375 -640 427 -640 480 -640 480 -640 480 -640 480 -640 480 -480 640 -500 375 -360 270 -393 640 -640 428 -478 640 -640 480 -557 640 -640 427 -333 500 -427 640 -317 500 -640 425 -480 640 -640 478 -640 427 -640 427 -640 374 -480 640 -640 480 -640 427 -375 500 -480 640 -427 640 -640 384 -640 480 -640 480 -394 640 -640 480 -640 480 -640 437 -640 427 -430 640 -640 160 -480 640 -427 640 -640 478 -640 354 -640 425 -500 333 -640 427 -427 640 -640 480 -500 375 -500 375 -640 428 -640 427 -640 478 -640 427 -480 640 -640 425 -640 480 -640 424 -640 457 -640 480 -500 333 -500 378 -375 500 -640 448 -500 333 -640 480 -640 423 -640 428 -640 494 -640 480 -480 640 -640 391 -640 479 -480 640 -640 510 -640 427 -425 640 -640 480 -427 640 -480 640 -480 640 -640 381 -640 480 -500 333 -518 640 -478 640 -640 640 -640 426 -640 414 -640 424 -372 500 -480 640 -480 640 -480 640 -640 480 -640 457 -427 640 -640 428 -640 360 -500 500 -612 499 -640 427 -480 640 -640 427 -426 640 -640 425 -640 411 -640 480 -640 480 -640 480 -640 428 -467 640 -640 480 -640 510 -640 427 -640 427 -640 427 -640 480 -640 428 -640 480 -640 426 -500 375 -333 500 -375 500 -640 480 -500 458 -640 640 -480 640 -640 427 -640 359 -640 480 -591 640 -464 640 -640 427 -384 500 -480 640 -480 640 -640 427 -640 427 -640 428 -640 428 -500 375 -378 500 -500 333 -640 480 -640 480 -640 360 -500 331 -640 480 -500 375 -501 640 -640 427 -426 640 -640 427 -640 480 -427 640 -640 404 -640 403 -427 640 -640 480 -640 427 -640 428 -640 480 -640 427 -427 640 -518 640 -463 640 -417 640 -640 640 -394 640 -640 310 -500 375 -426 640 -640 480 -426 640 -640 427 -640 178 -480 640 -640 480 -428 640 -640 480 -640 480 -640 428 -426 640 -640 480 -427 640 -612 612 -640 480 -427 640 -640 480 -640 480 -640 480 -480 640 -640 425 -427 640 -640 360 -640 427 -640 427 -640 427 -640 426 -640 427 -640 425 -640 427 -500 375 -480 640 -486 500 -600 600 -640 480 -640 425 -640 480 -640 436 -640 425 -480 640 -640 480 -640 360 -640 424 -640 426 -640 427 -500 375 -612 612 -640 425 -425 640 -496 640 -640 474 -500 375 -640 480 -640 396 -640 459 -480 640 -640 425 -427 640 -640 480 -480 640 -480 640 -640 427 -640 360 -640 425 -427 640 -500 334 -426 640 -429 640 -533 640 -640 428 -561 640 -334 500 -640 428 -480 320 -640 432 -640 424 -500 375 -640 427 -640 480 -426 640 -424 640 -640 446 -640 480 -640 426 -640 427 -500 333 -640 480 -640 427 -500 375 -480 640 -640 427 -375 500 -480 640 -640 426 -640 428 -640 427 -612 612 -640 428 -427 640 -640 480 -640 480 -448 640 -426 640 -640 425 -640 427 -640 464 -640 640 -425 640 -640 427 -384 500 -480 640 -480 640 -640 427 -500 358 -640 425 -640 480 -425 640 -417 640 -612 612 -640 480 -640 480 -640 480 -480 640 -640 359 -640 485 -640 640 -640 480 -300 225 -640 640 -640 480 -500 332 -640 423 -480 640 -640 480 -640 480 -640 424 -640 427 -640 425 -640 480 -640 427 -640 427 -640 457 -640 480 -427 640 -640 480 -640 419 -427 640 -640 427 -640 480 -640 480 -640 427 -500 360 -480 640 -640 480 -640 480 -640 480 -480 640 -640 427 -640 427 -640 428 -640 427 -640 427 -640 427 -640 330 -640 424 -640 386 -640 427 -640 480 -640 480 -640 480 -480 640 -375 500 -640 398 -640 426 -640 436 -640 426 -640 427 -640 480 -500 375 -640 426 -427 640 -640 426 -640 426 -640 359 -640 480 -640 427 -640 480 -640 428 -640 303 -519 631 -640 480 -640 480 -640 513 -640 360 -612 612 -480 640 -500 371 -640 480 -640 426 -640 427 -640 360 -640 512 -640 422 -640 427 -640 480 -640 480 -640 533 -640 426 -500 347 -397 640 -640 425 -640 480 -640 427 -640 640 -640 480 -640 534 -640 428 -640 480 -500 354 -640 427 -640 480 -640 425 -640 427 -480 640 -333 500 -639 640 -640 413 -640 508 -500 333 -640 427 -640 427 -480 640 -640 480 -640 429 -500 375 -480 640 -623 640 -452 640 -640 431 -480 640 -640 424 -640 427 -603 640 -500 375 -640 428 -640 376 -640 427 -640 427 -640 480 -640 426 -640 427 -480 640 -640 427 -640 426 -640 425 -640 427 -640 426 -640 451 -640 427 -480 640 -428 640 -636 477 -427 640 -640 389 -450 640 -640 480 -640 480 -426 640 -640 480 -640 427 -640 424 -480 640 -640 427 -489 640 -640 525 -640 425 -500 376 -640 427 -640 480 -640 446 -640 480 -640 427 -640 480 -500 375 -640 429 -480 640 -622 640 -640 428 -478 640 -640 426 -640 480 -640 360 -375 500 -500 375 -480 640 -640 480 -640 466 -500 375 -640 329 -541 640 -426 640 -640 640 -640 397 -640 425 -500 336 -640 359 -640 430 -640 427 -640 427 -480 640 -640 360 -640 480 -640 427 -591 640 -480 640 -640 428 -640 480 -428 640 -640 480 -375 500 -640 480 -640 480 -484 500 -612 612 -427 640 -640 383 -500 333 -640 427 -407 640 -640 433 -640 480 -500 375 -500 429 -425 640 -640 425 -612 612 -640 480 -500 375 -640 480 -640 480 -426 640 -500 348 -640 480 -488 500 -640 427 -500 375 -478 640 -640 480 -500 312 -333 500 -640 429 -640 480 -640 429 -640 427 -640 518 -640 474 -640 480 -640 480 -480 360 -640 427 -640 513 -622 640 -640 480 -398 640 -640 427 -640 426 -332 500 -469 640 -640 480 -640 429 -640 427 -640 375 -640 424 -426 640 -640 427 -640 480 -450 338 -480 640 -640 427 -640 640 -640 427 -640 427 -486 365 -427 640 -640 427 -640 480 -500 375 -640 428 -640 427 -640 425 -612 612 -640 423 -640 465 -640 511 -640 427 -640 480 -375 500 -640 424 -640 480 -640 425 -640 359 -500 335 -480 640 -640 480 -640 480 -640 427 -478 640 -640 480 -500 333 -640 640 -640 423 -640 427 -500 375 -640 426 -640 480 -411 640 -640 428 -640 427 -612 612 -640 480 -640 426 -424 640 -640 477 -640 423 -640 480 -640 416 -640 429 -640 481 -480 640 -640 449 -640 480 -640 427 -612 612 -500 333 -640 480 -640 472 -640 640 -640 480 -480 640 -640 426 -640 428 -480 640 -640 426 -480 640 -427 640 -640 480 -640 480 -375 500 -640 480 -360 640 -640 480 -640 486 -640 480 -640 480 -640 480 -425 640 -520 640 -640 426 -640 480 -640 480 -500 281 -500 375 -640 427 -427 640 -535 640 -612 612 -480 640 -360 640 -640 480 -640 480 -395 640 -579 640 -377 500 -640 480 -640 480 -640 427 -640 480 -500 375 -482 640 -427 640 -640 480 -480 640 -480 640 -500 375 -640 480 -400 266 -500 375 -640 480 -640 639 -640 480 -375 500 -480 640 -640 480 -426 640 -480 640 -427 640 -640 427 -426 640 -640 480 -640 289 -640 480 -640 427 -500 434 -640 637 -640 428 -640 480 -640 478 -640 383 -640 427 -440 500 -359 640 -640 480 -640 427 -425 640 -376 500 -427 640 -640 640 -640 356 -640 480 -236 236 -375 500 -640 427 -480 640 -640 480 -427 640 -415 500 -640 427 -640 427 -640 427 -640 466 -500 375 -640 480 -375 500 -480 640 -640 480 -480 640 -640 339 -640 251 -640 426 -427 640 -500 333 -640 459 -640 427 -640 419 -375 500 -426 640 -640 480 -640 480 -640 480 -421 640 -640 427 -333 500 -640 425 -640 425 -640 400 -640 426 -640 480 -500 332 -480 640 -640 480 -640 480 -640 523 -640 480 -640 480 -640 444 -540 640 -472 640 -500 333 -640 531 -640 425 -640 480 -640 478 -500 375 -640 480 -640 440 -640 480 -640 415 -640 455 -640 428 -359 640 -429 640 -640 480 -480 640 -640 480 -640 427 -427 640 -640 480 -512 640 -428 640 -480 640 -640 555 -640 429 -640 427 -359 640 -640 427 -640 427 -640 442 -500 375 -640 434 -428 640 -500 333 -640 426 -640 427 -640 427 -640 480 -640 424 -640 359 -640 590 -480 640 -640 360 -427 640 -512 640 -640 480 -511 640 -640 428 -640 447 -640 480 -640 428 -640 480 -640 480 -422 640 -640 480 -480 640 -500 375 -375 500 -640 425 -640 439 -640 480 -500 375 -375 500 -640 426 -500 338 -640 427 -640 480 -500 400 -640 360 -640 426 -640 640 -612 612 -640 360 -640 360 -500 375 -612 612 -640 427 -640 334 -640 428 -640 427 -640 425 -427 640 -428 640 -585 640 -500 344 -640 360 -426 640 -462 640 -640 427 -480 640 -513 640 -500 375 -500 377 -624 416 -427 640 -508 640 -640 480 -640 639 -640 428 -640 428 -640 428 -640 437 -375 500 -640 427 -640 427 -640 427 -640 360 -640 480 -640 428 -480 640 -640 425 -640 427 -480 640 -480 640 -640 427 -640 428 -425 640 -640 429 -500 375 -640 426 -640 427 -640 491 -640 480 -640 480 -427 640 -640 429 -640 426 -640 426 -640 480 -640 426 -640 392 -640 425 -458 640 -640 424 -640 480 -640 480 -640 480 -640 480 -640 480 -446 640 -640 480 -640 480 -500 333 -640 427 -640 428 -427 640 -477 640 -640 426 -640 496 -640 426 -640 428 -507 640 -640 427 -640 480 -480 640 -480 640 -640 427 -640 480 -334 500 -640 455 -640 431 -640 428 -512 326 -602 640 -640 485 -640 640 -612 612 -640 419 -480 640 -500 333 -333 500 -640 433 -640 480 -640 426 -640 427 -480 640 -427 640 -640 480 -640 427 -500 375 -640 480 -640 480 -640 480 -480 640 -640 480 -640 480 -640 480 -640 480 -640 429 -640 427 -640 427 -640 466 -500 332 -426 640 -480 640 -640 410 -640 480 -640 480 -640 359 -640 480 -424 640 -640 396 -640 427 -640 480 -640 427 -640 480 -480 640 -427 640 -480 640 -640 480 -440 640 -333 500 -640 427 -640 480 -640 427 -426 640 -640 427 -500 500 -640 427 -549 640 -500 300 -480 640 -640 427 -640 424 -640 427 -640 425 -480 640 -640 326 -428 640 -640 434 -480 640 -360 640 -480 640 -500 375 -640 427 -478 640 -640 427 -640 427 -640 640 -640 480 -640 456 -427 640 -640 480 -478 640 -375 500 -435 640 -640 425 -640 471 -640 404 -640 480 -480 640 -427 640 -640 480 -640 427 -640 481 -640 480 -640 480 -640 426 -640 480 -333 500 -640 480 -640 429 -500 333 -640 427 -606 640 -500 333 -640 427 -640 480 -640 428 -375 500 -640 427 -640 427 -640 425 -640 480 -640 480 -640 427 -640 181 -480 640 -640 480 -640 438 -640 480 -640 480 -640 480 -480 640 -640 425 -480 640 -500 333 -640 480 -375 500 -480 640 -359 640 -640 480 -480 640 -640 383 -500 304 -640 427 -640 480 -640 457 -640 428 -640 425 -480 640 -500 333 -480 640 -640 427 -383 640 -640 426 -480 640 -612 612 -640 480 -640 480 -426 640 -640 366 -375 500 -640 360 -640 427 -428 640 -640 427 -640 427 -640 401 -640 425 -640 427 -640 564 -640 481 -640 427 -500 333 -640 480 -383 640 -478 640 -640 640 -500 500 -640 432 -500 375 -427 640 -480 640 -640 424 -640 480 -640 426 -480 640 -640 480 -640 567 -640 429 -640 427 -500 334 -480 640 -640 480 -500 333 -640 480 -427 640 -640 424 -640 480 -640 480 -640 359 -640 421 -428 640 -640 427 -640 426 -640 427 -640 426 -579 640 -640 366 -640 426 -480 640 -640 480 -500 335 -480 640 -480 640 -640 480 -411 640 -427 640 -640 480 -375 500 -527 640 -500 374 -341 500 -500 375 -640 480 -427 640 -640 427 -421 640 -480 640 -640 480 -640 427 -492 500 -640 427 -640 425 -640 427 -640 480 -640 424 -640 424 -640 427 -640 481 -500 332 -640 441 -640 480 -403 640 -500 375 -480 640 -640 427 -432 640 -426 640 -640 428 -640 427 -500 375 -480 640 -640 426 -640 427 -455 640 -487 640 -640 427 -640 427 -428 640 -640 480 -500 500 -640 401 -640 480 -640 480 -640 427 -375 500 -640 464 -640 424 -612 612 -640 426 -640 426 -640 480 -640 426 -640 480 -427 640 -640 425 -612 612 -640 454 -640 427 -640 427 -500 332 -320 240 -453 640 -640 535 -640 539 -427 640 -480 640 -347 640 -480 640 -427 640 -427 640 -409 640 -480 640 -500 346 -427 640 -640 427 -426 640 -640 480 -640 480 -425 640 -500 332 -480 640 -500 375 -426 640 -426 640 -640 480 -640 480 -480 640 -640 427 -428 640 -375 500 -640 426 -500 209 -427 640 -640 427 -480 640 -640 425 -480 640 -436 640 -640 425 -640 438 -640 426 -640 495 -640 424 -500 333 -640 426 -480 640 -428 640 -640 427 -640 499 -640 480 -640 426 -640 480 -500 375 -640 480 -426 640 -640 555 -640 480 -640 483 -640 425 -375 500 -640 480 -500 333 -640 480 -640 426 -630 640 -425 640 -640 421 -480 640 -500 375 -480 640 -500 375 -640 427 -640 427 -640 427 -640 474 -333 500 -640 457 -640 480 -640 417 -442 442 -640 408 -640 427 -640 425 -640 360 -427 640 -476 640 -638 640 -640 425 -500 281 -500 375 -426 640 -640 480 -640 426 -338 500 -640 480 -640 427 -640 428 -640 480 -640 640 -640 427 -640 493 -640 427 -543 640 -640 360 -640 480 -640 480 -612 612 -425 640 -640 434 -640 480 -500 400 -500 325 -500 400 -640 480 -640 511 -640 457 -640 427 -640 480 -429 640 -640 425 -640 454 -640 428 -634 640 -612 612 -640 480 -640 479 -640 480 -640 480 -480 360 -640 427 -640 480 -640 425 -500 335 -513 640 -612 612 -640 527 -640 427 -640 343 -640 426 -612 612 -640 427 -640 480 -640 427 -640 360 -467 640 -640 359 -500 334 -640 480 -640 426 -640 480 -640 428 -640 343 -640 640 -640 424 -640 408 -476 640 -438 640 -479 640 -426 640 -480 640 -409 255 -640 428 -640 480 -640 427 -640 480 -500 333 -640 428 -480 640 -480 640 -640 426 -426 640 -640 426 -640 427 -373 495 -640 416 -480 640 -480 640 -640 425 -500 326 -640 426 -640 480 -500 400 -500 335 -640 480 -640 475 -640 480 -612 612 -640 480 -427 640 -640 427 -640 427 -640 480 -640 427 -428 640 -640 427 -640 640 -640 427 -640 398 -640 505 -640 427 -584 640 -640 480 -640 401 -500 281 -612 612 -500 375 -640 426 -500 375 -500 341 -640 424 -640 390 -500 307 -640 401 -640 424 -500 375 -640 427 -549 640 -640 427 -640 427 -500 375 -640 361 -375 500 -640 427 -424 640 -640 480 -640 213 -438 640 -640 442 -480 640 -640 428 -394 640 -640 424 -640 313 -640 480 -640 480 -640 480 -612 612 -480 640 -486 640 -640 413 -640 427 -625 640 -640 413 -640 512 -640 429 -640 426 -640 429 -640 480 -640 427 -500 333 -640 480 -640 436 -640 414 -500 375 -428 640 -640 425 -640 480 -480 640 -640 424 -480 640 -500 500 -640 480 -640 480 -640 427 -500 403 -640 480 -500 375 -640 480 -640 427 -640 480 -640 480 -640 360 -640 427 -375 500 -640 480 -640 427 -427 640 -640 480 -612 612 -427 640 -426 640 -640 425 -640 480 -640 427 -640 427 -640 426 -500 375 -640 480 -640 480 -640 439 -500 334 -640 480 -640 480 -500 333 -500 375 -500 375 -500 333 -640 427 -640 480 -402 500 -640 444 -640 426 -640 427 -458 640 -640 480 -640 427 -640 480 -640 478 -640 640 -640 480 -640 480 -640 480 -640 427 -640 482 -425 640 -640 427 -640 480 -640 480 -640 427 -640 480 -401 603 -640 640 -640 346 -640 384 -640 427 -640 480 -640 480 -640 510 -640 480 -419 640 -640 428 -640 427 -640 480 -640 480 -425 640 -640 478 -480 640 -640 427 -640 349 -640 640 -640 480 -640 427 -640 588 -640 434 -640 366 -640 480 -640 458 -480 640 -612 612 -480 640 -640 480 -640 427 -640 429 -640 480 -400 224 -640 428 -240 160 -500 385 -640 480 -640 414 -640 501 -640 480 -448 640 -375 500 -640 425 -640 426 -640 470 -640 480 -640 424 -640 480 -640 480 -640 428 -640 480 -640 358 -375 500 -640 480 -483 640 -480 640 -640 427 -640 483 -625 480 -640 480 -640 480 -640 425 -640 480 -640 427 -600 450 -500 336 -640 480 -640 427 -640 479 -640 480 -640 425 -480 640 -640 426 -640 427 -640 480 -640 433 -640 458 -640 436 -500 375 -500 332 -640 480 -427 640 -640 556 -640 428 -640 428 -640 475 -480 640 -375 500 -375 500 -640 428 -640 480 -640 427 -427 640 -640 474 -480 640 -480 640 -640 480 -640 457 -612 612 -500 333 -640 480 -640 480 -640 359 -480 640 -640 428 -375 500 -640 480 -640 440 -427 640 -500 313 -500 333 -640 427 -640 460 -640 426 -640 427 -427 640 -640 427 -640 480 -500 375 -426 640 -640 427 -500 425 -640 480 -480 640 -640 424 -496 640 -640 515 -640 360 -500 374 -640 640 -640 480 -458 640 -500 375 -640 433 -333 500 -640 360 -640 427 -640 427 -425 640 -640 427 -640 480 -640 429 -480 640 -500 422 -425 640 -480 640 -640 421 -640 480 -640 480 -500 375 -500 333 -640 518 -640 479 -640 471 -640 427 -640 480 -427 640 -640 427 -640 382 -500 375 -500 305 -640 350 -640 425 -427 640 -640 479 -640 426 -486 640 -640 512 -640 427 -480 640 -640 480 -640 480 -500 375 -640 480 -640 392 -478 640 -640 309 -612 612 -640 428 -247 500 -640 480 -640 480 -640 521 -640 427 -640 480 -640 480 -518 640 -640 480 -640 426 -500 375 -640 480 -640 480 -427 640 -640 480 -356 640 -600 400 -640 418 -640 480 -516 640 -640 256 -640 396 -640 484 -640 436 -382 500 -612 612 -640 426 -640 400 -480 640 -640 428 -640 422 -425 640 -612 612 -640 392 -640 426 -426 640 -640 428 -640 480 -480 640 -370 251 -640 427 -640 479 -427 640 -640 383 -640 425 -640 427 -640 480 -640 427 -640 425 -640 480 -480 640 -640 426 -640 386 -640 383 -612 612 -640 428 -640 425 -640 480 -428 640 -640 425 -640 480 -640 480 -480 640 -640 480 -640 425 -640 426 -534 640 -640 480 -640 426 -640 428 -500 375 -640 360 -500 333 -640 427 -480 640 -640 360 -500 400 -640 424 -500 330 -640 588 -640 480 -480 640 -640 347 -385 289 -640 480 -640 423 -640 480 -640 480 -640 450 -640 480 -480 640 -425 640 -640 480 -500 332 -640 480 -612 612 -640 457 -640 480 -468 304 -640 427 -425 640 -640 427 -640 480 -480 640 -640 425 -640 480 -640 427 -640 478 -500 500 -640 480 -500 375 -375 500 -640 480 -480 640 -640 425 -640 424 -640 480 -640 415 -640 480 -640 329 -640 425 -437 640 -640 427 -640 427 -480 640 -640 426 -500 375 -640 480 -333 500 -640 426 -640 446 -640 480 -480 640 -500 333 -482 625 -640 480 -480 640 -484 640 -466 640 -640 427 -640 480 -640 427 -640 424 -500 333 -640 480 -640 400 -640 480 -640 427 -480 640 -640 429 -640 480 -640 427 -640 427 -640 425 -480 640 -640 427 -480 640 -375 500 -500 333 -500 317 -640 427 -451 640 -480 640 -640 480 -427 640 -640 428 -640 426 -480 640 -320 240 -640 480 -640 427 -640 426 -640 480 -640 436 -640 429 -640 427 -640 480 -640 410 -500 360 -640 480 -640 480 -640 640 -640 427 -640 543 -428 640 -640 489 -640 570 -500 375 -613 640 -500 431 -640 432 -428 640 -640 479 -640 480 -640 480 -612 612 -640 480 -500 375 -640 480 -500 375 -640 421 -640 426 -640 424 -640 427 -476 640 -612 612 -640 480 -640 428 -640 480 -640 480 -480 640 -640 417 -480 640 -640 425 -640 480 -640 456 -640 480 -448 640 -588 640 -640 425 -500 375 -640 427 -640 480 -427 640 -424 640 -480 640 -640 428 -640 480 -480 640 -640 480 -500 375 -480 360 -480 640 -640 426 -480 640 -640 427 -640 426 -640 422 -427 640 -480 640 -640 427 -500 364 -640 428 -334 500 -375 500 -640 438 -427 640 -640 480 -640 480 -500 333 -640 435 -640 480 -500 333 -640 480 -427 640 -500 333 -640 480 -640 425 -640 480 -640 412 -480 640 -640 480 -464 640 -640 480 -480 640 -640 360 -640 428 -640 355 -640 427 -640 427 -640 480 -500 333 -640 480 -640 480 -500 375 -640 427 -375 500 -546 640 -339 500 -640 427 -640 429 -425 640 -640 427 -640 427 -640 361 -640 427 -640 321 -640 427 -640 426 -640 427 -640 480 -375 500 -640 425 -500 333 -640 480 -640 459 -640 490 -640 427 -640 480 -640 427 -640 425 -375 500 -320 408 -640 457 -500 366 -640 427 -640 512 -480 640 -640 588 -640 625 -427 640 -640 426 -480 640 -425 640 -612 612 -640 419 -640 480 -500 316 -635 640 -500 378 -640 424 -640 426 -640 360 -640 460 -640 480 -640 424 -500 375 -640 480 -640 480 -426 640 -427 640 -640 360 -640 479 -640 427 -640 480 -500 333 -640 426 -640 427 -612 612 -500 333 -640 429 -500 418 -427 640 -640 425 -480 640 -640 480 -640 428 -640 480 -640 480 -427 640 -640 420 -640 427 -640 427 -640 427 -500 357 -480 640 -480 640 -640 482 -500 375 -640 480 -640 433 -464 640 -467 640 -500 332 -500 375 -640 349 -640 427 -640 480 -640 480 -334 500 -375 500 -640 423 -640 480 -640 428 -500 451 -640 428 -640 427 -517 640 -640 426 -640 427 -480 640 -383 640 -480 640 -640 428 -640 426 -640 428 -479 640 -640 360 -335 198 -640 480 -640 426 -640 480 -510 640 -640 426 -612 612 -640 424 -630 640 -640 427 -640 427 -640 427 -640 428 -640 480 -480 640 -472 640 -500 375 -640 480 -425 640 -640 480 -640 428 -378 640 -427 640 -640 480 -375 500 -640 480 -427 640 -281 500 -640 436 -480 640 -375 500 -640 567 -640 427 -640 427 -375 500 -640 424 -640 480 -640 493 -640 360 -640 497 -258 344 -640 480 -640 427 -441 640 -333 500 -360 640 -500 375 -640 480 -427 640 -640 428 -640 427 -640 428 -500 375 -640 427 -500 289 -640 359 -640 301 -640 428 -428 640 -640 480 -473 640 -640 427 -640 426 -480 640 -612 612 -640 479 -640 427 -640 480 -640 480 -429 640 -640 480 -640 480 -500 375 -640 480 -640 480 -640 427 -427 640 -453 640 -500 390 -640 393 -500 375 -500 334 -640 346 -480 640 -640 480 -427 640 -640 427 -640 426 -640 427 -640 428 -640 480 -427 640 -640 480 -640 433 -640 425 -640 427 -640 480 -472 640 -640 480 -640 427 -640 640 -640 480 -639 640 -640 360 -361 640 -640 480 -333 500 -640 427 -640 480 -640 368 -426 640 -640 427 -480 640 -640 359 -427 640 -640 480 -640 408 -640 429 -640 478 -640 480 -640 417 -640 427 -640 426 -500 375 -640 480 -640 427 -640 480 -640 480 -640 409 -640 480 -640 427 -640 427 -480 640 -480 640 -640 480 -640 428 -612 612 -333 500 -640 438 -640 427 -616 640 -500 375 -640 480 -500 339 -640 427 -640 428 -640 480 -640 480 -640 480 -640 427 -640 480 -640 359 -640 428 -640 359 -640 480 -640 381 -640 480 -480 640 -640 360 -640 425 -640 479 -640 425 -640 485 -640 426 -640 427 -628 640 -500 375 -500 375 -640 427 -640 423 -425 640 -480 640 -500 375 -640 428 -458 640 -479 640 -640 480 -480 640 -640 480 -288 640 -640 427 -640 477 -640 427 -480 640 -640 480 -640 480 -640 480 -640 359 -640 428 -640 425 -640 449 -500 375 -640 428 -640 480 -640 481 -500 375 -500 333 -640 424 -640 430 -612 612 -640 424 -640 427 -500 375 -640 427 -640 453 -640 422 -640 424 -640 425 -640 425 -640 427 -480 640 -640 480 -640 359 -480 640 -640 426 -640 480 -640 427 -640 426 -640 427 -640 427 -480 640 -429 640 -408 640 -612 612 -427 640 -640 480 -640 480 -500 318 -640 534 -640 479 -640 406 -640 512 -640 427 -640 427 -640 388 -640 426 -640 478 -640 424 -640 480 -480 640 -640 427 -640 640 -640 480 -500 333 -640 433 -640 427 -640 426 -640 427 -640 480 -640 425 -640 428 -640 426 -425 640 -500 375 -640 480 -640 426 -640 434 -640 480 -640 441 -640 425 -640 425 -480 640 -640 427 -565 640 -427 640 -640 480 -640 480 -640 480 -640 427 -640 479 -427 640 -640 640 -500 337 -500 359 -480 640 -427 640 -640 480 -612 612 -640 427 -640 428 -425 640 -640 427 -480 640 -512 640 -640 513 -640 427 -640 480 -500 375 -640 425 -640 480 -428 640 -500 375 -640 425 -500 399 -427 640 -640 427 -500 333 -640 428 -640 428 -640 480 -640 427 -640 428 -413 500 -640 427 -640 424 -640 429 -640 480 -640 480 -640 478 -640 480 -640 452 -640 480 -500 292 -500 375 -640 480 -640 480 -640 480 -640 480 -640 427 -640 426 -480 640 -640 480 -640 427 -640 427 -640 360 -500 333 -640 477 -436 640 -640 426 -640 427 -640 427 -480 640 -612 612 -640 301 -640 311 -640 480 -427 640 -640 457 -640 427 -640 427 -640 480 -640 331 -500 375 -276 640 -640 424 -500 500 -478 640 -612 612 -640 381 -512 640 -433 640 -640 480 -480 640 -640 480 -480 640 -640 480 -427 640 -640 430 -640 480 -640 480 -640 428 -500 373 -640 428 -640 366 -640 475 -640 480 -427 640 -640 427 -500 375 -500 375 -375 500 -640 427 -427 640 -640 480 -640 480 -300 451 -640 383 -640 427 -500 375 -640 424 -500 375 -400 600 -640 478 -640 480 -375 500 -500 375 -640 480 -640 456 -640 427 -480 640 -480 640 -500 375 -500 415 -640 436 -375 500 -480 640 -427 640 -640 480 -640 428 -524 640 -640 489 -612 612 -480 640 -640 426 -640 426 -640 480 -640 425 -640 427 -640 427 -612 612 -640 445 -640 480 -640 427 -480 640 -640 361 -640 427 -640 454 -640 453 -427 640 -640 459 -500 283 -349 500 -640 480 -640 480 -640 480 -640 480 -640 480 -374 500 -480 640 -640 480 -480 640 -500 332 -500 332 -612 612 -640 426 -640 428 -500 333 -640 480 -640 480 -612 612 -640 427 -500 276 -500 332 -640 480 -640 427 -640 480 -640 480 -480 640 -640 480 -480 640 -640 429 -640 480 -640 512 -480 640 -640 480 -640 450 -640 426 -640 427 -640 480 -426 640 -640 427 -640 427 -640 480 -379 640 -640 425 -640 427 -640 400 -640 480 -640 427 -640 427 -640 480 -640 480 -640 427 -480 640 -640 424 -500 374 -640 480 -640 427 -640 480 -640 402 -640 480 -640 480 -640 640 -640 538 -640 480 -640 426 -640 480 -612 612 -480 640 -480 640 -640 427 -640 512 -640 480 -640 427 -640 439 -640 427 -480 640 -426 640 -612 612 -640 332 -500 375 -640 478 -640 433 -480 640 -450 600 -640 480 -640 480 -604 640 -640 243 -640 480 -424 640 -640 480 -401 640 -500 489 -640 397 -500 375 -500 345 -500 429 -481 640 -640 431 -640 366 -286 176 -640 427 -640 480 -428 640 -480 640 -437 500 -472 640 -640 458 -640 480 -612 612 -640 638 -480 640 -354 640 -640 427 -640 480 -640 480 -640 379 -480 640 -640 480 -478 640 -640 480 -640 428 -640 480 -640 480 -640 480 -640 425 -428 640 -640 428 -640 360 -480 640 -603 640 -640 559 -425 640 -640 480 -640 426 -640 427 -640 480 -640 427 -640 426 -640 480 -640 426 -640 360 -640 427 -640 426 -374 640 -480 640 -428 640 -478 640 -612 612 -640 427 -640 480 -640 486 -640 425 -500 363 -640 427 -640 425 -640 423 -533 640 -640 427 -640 428 -612 612 -444 440 -500 375 -425 640 -400 640 -640 480 -640 480 -640 428 -426 640 -640 480 -640 428 -640 480 -600 400 -425 640 -640 510 -500 333 -500 375 -640 427 -640 427 -640 427 -500 354 -640 480 -301 450 -360 640 -640 427 -512 640 -500 332 -427 640 -640 480 -640 427 -427 640 -640 480 -640 480 -500 375 -640 426 -640 384 -640 480 -500 333 -500 375 -640 480 -500 200 -640 480 -640 511 -640 478 -640 475 -500 375 -500 375 -640 480 -640 366 -640 480 -480 640 -640 423 -447 640 -640 640 -640 426 -640 480 -576 640 -360 640 -640 480 -500 281 -640 444 -640 640 -500 332 -560 175 -500 375 -640 366 -640 640 -640 341 -640 478 -640 428 -640 594 -640 363 -640 427 -640 425 -640 480 -590 640 -481 640 -640 640 -640 425 -640 427 -640 427 -640 427 -640 434 -375 500 -640 406 -640 360 -640 480 -640 480 -427 640 -396 640 -640 426 -640 531 -419 640 -640 426 -640 426 -640 480 -500 375 -640 428 -640 480 -640 480 -640 480 -480 640 -480 640 -444 640 -640 427 -320 240 -640 425 -640 480 -640 480 -425 640 -386 500 -640 480 -640 480 -500 333 -480 640 -422 282 -640 480 -640 443 -347 500 -640 480 -478 640 -480 640 -640 444 -640 640 -640 425 -478 640 -640 427 -640 427 -500 283 -640 480 -640 480 -640 412 -500 417 -427 640 -640 427 -640 323 -640 427 -640 471 -427 640 -640 427 -640 427 -368 500 -640 480 -640 427 -640 450 -640 426 -425 640 -640 427 -500 375 -640 427 -640 426 -640 480 -640 428 -640 360 -640 488 -640 425 -640 480 -398 640 -640 414 -640 399 -640 425 -640 480 -640 439 -427 640 -640 480 -428 640 -550 410 -640 427 -640 480 -640 480 -640 494 -428 640 -640 480 -500 375 -640 566 -640 480 -480 640 -640 478 -640 360 -640 427 -640 480 -480 640 -500 375 -500 333 -640 480 -425 640 -426 640 -640 425 -640 427 -640 279 -640 428 -640 376 -640 425 -640 353 -480 640 -640 464 -640 480 -640 492 -640 480 -640 480 -640 480 -640 480 -640 427 -640 480 -640 426 -640 427 -640 480 -640 427 -640 379 -500 390 -427 640 -640 510 -640 426 -640 480 -427 640 -480 640 -480 640 -640 469 -640 427 -500 375 -640 528 -427 640 -640 427 -640 519 -640 427 -428 640 -640 427 -640 414 -640 513 -640 427 -640 480 -427 640 -640 427 -640 480 -375 500 -500 375 -640 427 -640 428 -500 375 -640 427 -375 500 -640 480 -640 428 -500 333 -640 427 -640 480 -640 427 -640 427 -640 480 -427 640 -640 427 -640 480 -640 426 -500 375 -378 500 -640 565 -640 427 -640 427 -640 427 -640 480 -640 426 -640 452 -500 375 -640 427 -640 427 -640 480 -640 427 -427 640 -640 457 -640 428 -425 640 -640 480 -480 640 -640 383 -500 332 -640 595 -640 480 -640 404 -640 379 -500 498 -480 640 -640 480 -640 480 -375 500 -640 427 -640 427 -640 640 -640 480 -640 427 -640 427 -640 480 -480 640 -640 479 -640 325 -640 480 -427 640 -640 457 -640 428 -640 480 -640 427 -640 428 -640 480 -640 427 -346 500 -640 480 -640 427 -480 640 -480 320 -640 425 -640 474 -375 500 -478 640 -426 640 -640 426 -640 480 -500 400 -640 480 -640 427 -500 375 -640 426 -499 500 -640 426 -640 480 -640 480 -640 480 -640 427 -640 512 -375 500 -640 427 -480 640 -500 365 -640 480 -480 640 -640 426 -640 480 -640 427 -427 640 -480 640 -640 427 -640 480 -640 480 -425 640 -500 375 -500 338 -640 344 -640 427 -640 425 -640 480 -480 640 -427 640 -486 640 -503 640 -640 480 -427 640 -361 640 -640 457 -640 480 -640 427 -426 640 -640 480 -640 473 -640 361 -640 426 -375 500 -500 375 -640 427 -640 427 -640 431 -640 434 -640 480 -500 375 -640 428 -640 480 -371 640 -475 640 -640 476 -640 427 -500 375 -480 640 -640 426 -640 312 -640 480 -640 480 -640 480 -456 640 -640 427 -640 425 -632 640 -640 360 -640 424 -640 426 -403 640 -426 640 -480 640 -640 393 -359 640 -480 640 -612 612 -640 421 -640 425 -640 478 -640 422 -640 396 -500 375 -640 426 -640 427 -640 427 -640 478 -427 640 -500 336 -640 427 -640 640 -640 555 -612 612 -511 640 -428 640 -640 480 -493 640 -640 427 -640 425 -612 612 -478 640 -640 608 -400 308 -480 640 -640 427 -640 480 -640 512 -640 427 -480 640 -640 318 -480 640 -640 437 -500 385 -427 640 -500 374 -500 375 -640 481 -640 428 -640 289 -640 427 -640 427 -640 388 -480 640 -615 640 -640 480 -640 360 -428 640 -500 333 -640 480 -640 359 -355 640 -480 640 -612 612 -480 640 -640 480 -640 428 -640 480 -425 640 -640 425 -640 480 -640 270 -426 640 -640 480 -640 425 -640 408 -428 640 -640 400 -640 426 -622 640 -640 480 -500 375 -640 480 -640 393 -640 360 -640 428 -640 427 -357 500 -480 640 -640 480 -480 640 -400 500 -391 640 -640 480 -640 480 -640 480 -424 640 -640 427 -640 424 -500 339 -640 480 -640 480 -640 428 -427 640 -640 469 -427 640 -640 445 -640 428 -478 640 -375 500 -640 428 -640 425 -640 426 -427 640 -640 480 -640 480 -478 640 -500 375 -640 480 -500 400 -640 426 -640 512 -640 480 -640 457 -640 425 -640 476 -640 427 -500 375 -640 427 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -480 640 -500 375 -640 426 -640 480 -500 375 -640 427 -500 375 -480 640 -640 425 -597 640 -640 480 -640 481 -640 428 -640 512 -640 480 -640 480 -640 480 -427 640 -640 480 -500 334 -640 478 -640 480 -640 444 -480 640 -640 597 -640 427 -640 427 -640 425 -640 478 -640 427 -640 480 -640 427 -451 640 -628 640 -640 640 -500 335 -640 640 -640 318 -640 427 -640 480 -640 480 -640 480 -426 640 -427 640 -500 375 -320 240 -427 640 -640 480 -640 428 -640 429 -427 640 -480 640 -640 427 -640 415 -640 366 -407 500 -640 425 -640 427 -427 640 -480 640 -500 375 -500 360 -478 640 -640 427 -640 510 -640 425 -480 640 -500 334 -640 427 -640 480 -640 427 -333 500 -500 335 -640 427 -375 500 -640 360 -640 427 -640 459 -640 499 -640 473 -480 640 -478 640 -640 438 -640 426 -640 428 -640 441 -640 480 -640 480 -640 526 -640 480 -640 480 -640 480 -640 427 -640 425 -612 612 -398 640 -640 524 -640 478 -427 640 -640 499 -617 640 -640 428 -480 640 -640 423 -500 357 -478 640 -640 360 -640 427 -640 433 -640 425 -545 640 -640 482 -424 640 -640 480 -334 500 -483 640 -427 640 -640 480 -500 333 -500 375 -400 266 -375 500 -640 480 -480 640 -640 428 -500 375 -640 577 -446 640 -640 480 -480 640 -640 480 -640 480 -640 427 -640 426 -362 640 -640 480 -500 375 -500 333 -500 333 -640 426 -640 426 -640 480 -480 640 -640 478 -480 640 -640 427 -500 375 -640 640 -640 480 -640 425 -640 421 -640 427 -640 480 -640 426 -640 426 -640 352 -500 375 -480 640 -640 427 -480 640 -640 427 -426 640 -640 480 -320 400 -640 480 -427 640 -640 358 -640 430 -640 427 -640 426 -500 375 -480 640 -612 612 -480 640 -640 430 -512 512 -640 480 -480 640 -640 427 -640 478 -640 427 -640 427 -640 425 -640 480 -640 425 -640 427 -640 480 -640 427 -500 281 -640 480 -640 480 -428 640 -640 480 -640 480 -425 640 -640 480 -425 640 -480 640 -640 339 -640 427 -427 640 -480 640 -640 425 -427 640 -640 480 -640 423 -442 500 -640 480 -640 427 -480 640 -640 494 -494 500 -480 640 -480 640 -640 480 -640 640 -640 427 -640 480 -640 428 -640 428 -612 612 -480 640 -634 640 -500 333 -500 332 -423 640 -640 427 -480 640 -632 640 -500 323 -640 426 -640 480 -640 480 -640 480 -640 480 -640 480 -640 425 -640 427 -640 432 -332 500 -640 640 -640 478 -640 512 -640 512 -427 640 -500 375 -640 480 -640 480 -640 480 -640 428 -640 480 -640 480 -640 254 -640 480 -500 375 -640 427 -480 640 -640 474 -640 426 -640 480 -640 495 -480 640 -640 480 -640 427 -640 480 -500 333 -640 427 -640 480 -375 500 -640 427 -464 640 -640 480 -480 640 -612 612 -640 421 -640 480 -500 332 -640 480 -640 360 -640 480 -426 640 -500 375 -640 427 -612 612 -640 359 -640 428 -640 360 -640 480 -333 500 -640 360 -640 370 -640 427 -500 372 -640 426 -500 333 -478 640 -500 375 -640 480 -640 368 -500 368 -500 375 -500 332 -640 480 -640 427 -519 640 -640 434 -640 427 -424 640 -640 479 -425 640 -640 478 -640 515 -425 640 -500 375 -600 600 -640 428 -612 612 -640 427 -640 480 -640 466 -640 427 -546 640 -640 480 -640 403 -640 606 -561 640 -427 640 -500 372 -480 640 -477 358 -640 480 -640 428 -640 478 -427 640 -640 355 -640 480 -640 480 -640 512 -427 640 -375 500 -500 332 -480 640 -480 640 -640 473 -612 612 -640 428 -640 427 -640 480 -640 480 -500 400 -640 427 -640 427 -640 426 -640 480 -640 384 -640 427 -428 640 -640 426 -640 480 -640 481 -640 480 -640 480 -640 480 -500 375 -640 329 -333 500 -640 427 -640 348 -640 480 -500 375 -481 481 -640 424 -640 360 -640 427 -640 428 -640 480 -425 640 -640 427 -640 480 -500 375 -426 640 -640 427 -480 640 -500 373 -640 426 -640 480 -640 320 -640 426 -480 640 -426 640 -500 282 -640 417 -640 403 -426 640 -640 480 -640 427 -480 640 -640 425 -511 640 -375 500 -500 335 -640 412 -640 427 -640 427 -500 375 -640 480 -399 640 -640 426 -640 480 -500 375 -480 640 -427 640 -480 640 -360 640 -640 480 -640 427 -612 612 -640 571 -640 427 -640 427 -500 375 -640 429 -640 383 -427 640 -333 500 -640 480 -427 640 -478 640 -500 390 -640 480 -640 480 -640 427 -640 480 -500 328 -480 640 -640 480 -640 426 -456 640 -640 427 -640 427 -640 603 -612 612 -640 427 -480 640 -480 640 -640 480 -640 480 -480 640 -640 443 -640 427 -500 333 -640 427 -640 249 -640 480 -640 426 -640 480 -640 480 -282 454 -640 480 -640 427 -640 480 -427 640 -428 640 -640 425 -567 640 -500 333 -500 375 -640 480 -480 640 -446 640 -500 375 -640 480 -427 640 -427 640 -640 439 -480 640 -640 427 -375 500 -640 480 -640 427 -640 426 -640 426 -480 640 -640 480 -640 480 -612 612 -640 554 -480 640 -640 360 -500 375 -500 375 -640 423 -640 427 -480 640 -640 425 -640 427 -640 426 -640 480 -640 426 -640 427 -640 464 -640 414 -375 500 -482 482 -640 480 -389 640 -478 640 -640 427 -640 361 -640 480 -640 429 -640 427 -640 425 -640 480 -640 480 -640 483 -640 427 -640 427 -500 329 -640 444 -640 428 -640 480 -403 640 -500 333 -640 480 -640 427 -640 269 -640 480 -640 480 -640 360 -640 427 -444 640 -640 428 -640 480 -457 640 -480 640 -612 612 -640 427 -612 612 -333 500 -640 480 -426 640 -640 424 -640 427 -640 418 -500 375 -640 496 -640 457 -640 480 -640 426 -480 640 -640 424 -640 480 -576 640 -640 427 -640 480 -640 399 -480 640 -640 427 -640 480 -500 500 -640 427 -351 500 -640 427 -640 480 -640 640 -640 427 -427 640 -640 373 -500 380 -375 500 -640 480 -425 640 -640 406 -640 427 -640 480 -640 427 -640 427 -500 408 -640 480 -640 480 -640 480 -500 336 -640 480 -480 640 -640 473 -640 428 -640 428 -578 640 -480 640 -640 427 -640 424 -640 427 -404 640 -500 375 -640 400 -500 333 -480 640 -436 640 -409 640 -640 427 -640 523 -640 427 -640 418 -640 480 -640 480 -640 427 -640 426 -500 333 -640 427 -427 640 -640 412 -640 480 -640 427 -478 640 -640 480 -640 427 -332 500 -511 640 -478 640 -640 427 -334 500 -640 427 -640 427 -500 375 -640 480 -640 480 -500 375 -500 400 -640 480 -333 500 -480 640 -640 427 -640 360 -640 480 -640 480 -640 480 -640 388 -427 640 -500 375 -640 426 -640 480 -640 480 -640 480 -612 612 -478 640 -334 500 -640 427 -640 457 -640 480 -640 427 -426 640 -640 425 -500 375 -640 427 -640 416 -426 640 -480 640 -640 425 -640 426 -640 538 -480 640 -640 478 -500 375 -426 640 -480 640 -640 426 -640 428 -640 427 -480 640 -640 427 -500 228 -640 425 -640 480 -500 375 -640 427 -500 375 -640 427 -433 640 -480 640 -480 640 -640 426 -640 427 -612 612 -640 481 -640 480 -453 640 -500 333 -640 361 -640 424 -640 428 -640 478 -640 480 -640 427 -640 480 -425 640 -640 339 -426 640 -640 480 -640 480 -640 427 -500 375 -640 323 -640 640 -640 480 -640 427 -640 450 -320 240 -640 478 -640 640 -640 427 -426 640 -640 480 -640 424 -640 427 -612 612 -640 427 -640 425 -640 480 -640 480 -480 640 -640 480 -640 449 -640 479 -640 426 -480 640 -640 428 -640 478 -456 640 -640 427 -640 480 -428 443 -640 483 -640 423 -640 480 -640 480 -640 480 -640 427 -480 640 -640 424 -640 427 -500 202 -426 640 -640 427 -640 428 -640 480 -375 500 -427 640 -640 480 -460 640 -640 427 -640 427 -640 427 -640 480 -640 426 -640 484 -333 500 -640 427 -333 500 -640 401 -640 480 -640 429 -640 433 -427 640 -500 333 -640 320 -640 427 -640 427 -640 427 -640 415 -500 332 -457 640 -427 640 -640 434 -448 640 -640 480 -640 427 -640 425 -640 480 -640 480 -480 640 -612 612 -480 640 -640 480 -640 512 -640 480 -480 640 -480 640 -500 375 -640 427 -640 480 -480 640 -419 640 -427 640 -640 424 -640 428 -640 425 -640 427 -640 426 -640 426 -473 640 -640 426 -640 420 -640 480 -640 427 -500 290 -612 612 -640 427 -640 480 -426 640 -400 300 -314 500 -500 375 -640 360 -640 480 -640 427 -640 427 -480 640 -640 425 -500 375 -640 480 -640 480 -640 640 -500 375 -640 424 -612 612 -640 426 -640 487 -640 427 -640 480 -640 503 -640 458 -640 484 -640 480 -640 480 -640 427 -640 480 -640 457 -640 480 -427 640 -612 612 -640 526 -500 375 -640 480 -640 480 -400 500 -640 427 -640 480 -640 427 -640 427 -640 426 -640 480 -480 640 -428 640 -480 640 -480 640 -428 640 -640 406 -640 428 -640 491 -428 640 -500 375 -480 640 -480 640 -640 480 -640 427 -480 640 -640 479 -480 640 -640 426 -640 360 -640 360 -640 480 -500 375 -640 480 -640 428 -612 612 -640 425 -375 500 -640 427 -640 457 -640 427 -640 316 -640 480 -500 331 -640 480 -427 640 -480 640 -426 640 -640 425 -640 496 -640 389 -463 640 -640 468 -640 480 -640 480 -444 640 -640 424 -334 500 -500 375 -640 429 -500 332 -480 640 -640 480 -640 427 -640 480 -426 640 -640 386 -640 427 -500 375 -500 375 -640 427 -640 480 -640 427 -640 324 -500 375 -640 425 -640 363 -640 428 -426 640 -640 427 -467 640 -640 427 -640 427 -640 427 -640 230 -640 426 -640 359 -640 428 -640 480 -640 427 -640 427 -640 427 -500 375 -640 427 -612 612 -500 375 -500 375 -640 427 -640 434 -500 375 -640 640 -640 463 -612 612 -480 640 -640 427 -640 480 -640 568 -640 480 -480 640 -426 640 -640 480 -612 612 -640 480 -627 640 -344 500 -640 480 -640 442 -640 428 -640 480 -480 640 -640 480 -640 480 -640 433 -640 512 -427 640 -500 334 -640 254 -640 431 -612 612 -612 612 -640 512 -640 480 -640 424 -640 396 -640 480 -640 480 -480 640 -640 480 -427 640 -640 480 -640 427 -640 480 -640 480 -500 400 -500 375 -640 480 -640 480 -427 640 -640 480 -640 427 -480 640 -427 640 -640 427 -640 480 -640 427 -640 428 -426 640 -500 375 -640 366 -640 480 -640 480 -429 640 -479 320 -640 429 -500 399 -424 640 -538 640 -640 428 -640 431 -427 640 -554 312 -426 640 -640 480 -375 500 -640 427 -640 429 -480 384 -500 400 -333 500 -480 640 -500 484 -640 427 -477 304 -426 640 -640 480 -600 400 -500 500 -640 427 -480 640 -500 333 -500 334 -640 428 -640 486 -640 258 -640 480 -640 480 -519 640 -612 612 -500 333 -640 426 -640 427 -640 640 -640 508 -640 427 -480 640 -426 640 -500 375 -640 427 -500 334 -640 480 -437 640 -640 418 -640 427 -598 640 -378 500 -480 640 -640 593 -640 427 -480 640 -640 480 -333 500 -640 343 -640 420 -480 640 -640 480 -640 427 -333 500 -640 427 -426 640 -640 427 -640 424 -523 640 -480 640 -640 430 -640 480 -640 428 -640 480 -480 640 -640 480 -612 612 -427 640 -640 481 -640 407 -427 640 -640 426 -333 500 -640 480 -640 478 -640 480 -640 439 -640 403 -640 480 -640 480 -640 480 -640 419 -640 427 -640 427 -640 424 -640 382 -640 408 -500 375 -640 640 -640 480 -640 427 -640 428 -395 640 -480 640 -602 640 -640 480 -428 640 -640 400 -427 640 -640 427 -640 424 -640 480 -640 426 -640 480 -500 375 -640 480 -453 640 -640 443 -640 429 -640 360 -640 498 -640 480 -446 640 -640 476 -500 387 -640 640 -590 640 -640 425 -640 480 -427 640 -640 480 -426 640 -640 638 -439 640 -640 640 -437 640 -640 480 -640 640 -640 480 -640 495 -640 427 -500 375 -640 388 -640 480 -640 428 -640 427 -353 640 -427 640 -479 640 -500 334 -640 480 -640 427 -427 640 -512 640 -500 335 -426 640 -640 427 -640 200 -640 427 -640 427 -640 538 -512 640 -640 428 -450 319 -375 500 -640 480 -500 375 -640 480 -640 428 -640 452 -640 480 -640 480 -640 480 -640 640 -640 427 -640 480 -416 640 -640 426 -640 480 -427 640 -500 375 -640 295 -457 640 -640 425 -640 427 -500 500 -640 480 -640 480 -427 640 -375 500 -640 480 -640 434 -640 427 -433 640 -554 640 -640 427 -640 487 -640 428 -500 375 -640 424 -478 640 -640 480 -640 425 -640 427 -500 334 -640 467 -640 426 -640 427 -426 640 -640 427 -427 640 -480 640 -640 426 -409 640 -640 480 -425 640 -640 480 -640 428 -378 640 -427 640 -640 619 -425 640 -640 480 -640 428 -640 480 -640 480 -640 480 -640 429 -640 426 -640 425 -480 640 -640 478 -375 500 -640 436 -640 409 -640 423 -640 426 -640 427 -500 332 -500 375 -640 480 -640 428 -480 640 -640 425 -640 427 -640 480 -640 427 -640 480 -640 480 -640 480 -480 640 -500 337 -500 325 -640 427 -640 426 -640 400 -640 248 -640 427 -640 462 -640 480 -640 427 -640 508 -500 391 -480 640 -640 427 -640 480 -640 427 -427 640 -640 426 -427 640 -640 427 -457 640 -640 480 -640 480 -427 640 -427 640 -500 375 -424 640 -427 640 -640 427 -640 480 -640 480 -480 640 -640 480 -444 640 -640 424 -640 428 -640 460 -640 427 -640 428 -640 512 -640 427 -428 640 -640 427 -640 427 -640 478 -640 424 -640 480 -640 427 -640 339 -612 612 -640 480 -500 375 -480 640 -640 425 -640 427 -640 480 -427 640 -427 640 -640 480 -480 640 -640 480 -500 375 -640 480 -640 424 -640 480 -640 480 -640 480 -480 640 -612 612 -640 428 -427 640 -640 480 -612 612 -640 480 -640 424 -640 480 -640 480 -640 480 -640 480 -480 640 -427 640 -640 427 -640 424 -640 427 -640 427 -480 640 -640 480 -640 480 -640 424 -640 457 -427 640 -500 338 -640 427 -640 427 -356 640 -375 500 -505 640 -640 425 -400 600 -640 427 -426 640 -481 640 -640 480 -640 491 -640 480 -640 480 -640 369 -640 427 -500 333 -333 500 -500 313 -640 482 -640 491 -640 426 -640 426 -640 480 -640 427 -640 504 -640 426 -480 640 -480 640 -640 480 -640 457 -640 427 -640 427 -640 426 -640 427 -640 426 -640 480 -612 612 -640 480 -640 480 -500 332 -640 480 -480 640 -640 480 -640 426 -640 480 -500 305 -640 347 -640 427 -480 640 -500 335 -367 500 -640 427 -640 427 -640 427 -640 480 -640 512 -612 612 -640 427 -568 320 -640 426 -480 640 -480 640 -640 480 -480 640 -427 640 -640 428 -640 360 -348 500 -424 640 -480 640 -640 480 -480 640 -636 640 -427 640 -480 640 -640 427 -640 480 -333 500 -500 375 -640 427 -600 450 -640 480 -640 427 -640 480 -329 640 -640 360 -612 612 -640 480 -500 500 -640 480 -640 457 -640 426 -640 488 -640 479 -480 640 -640 428 -427 640 -640 480 -640 427 -640 480 -640 427 -640 633 -512 640 -480 640 -480 640 -500 332 -640 480 -640 427 -640 480 -500 375 -640 480 -640 480 -640 480 -640 424 -640 427 -426 640 -640 427 -427 640 -471 640 -640 425 -500 398 -640 369 -640 480 -640 480 -640 485 -640 480 -640 480 -640 399 -640 427 -480 640 -500 375 -640 480 -425 640 -640 429 -500 500 -500 332 -640 640 -640 480 -480 640 -640 480 -640 425 -640 379 -480 640 -640 408 -333 500 -640 421 -427 640 -383 640 -640 480 -640 419 -478 640 -640 418 -500 357 -435 480 -640 427 -640 480 -478 640 -640 428 -500 375 -640 427 -640 427 -640 316 -640 428 -640 424 -413 640 -640 438 -640 428 -640 393 -640 428 -375 500 -640 425 -640 423 -640 475 -640 427 -640 427 -376 500 -640 429 -640 480 -640 446 -640 480 -425 640 -640 359 -500 374 -427 640 -480 640 -640 421 -427 640 -640 427 -640 425 -640 640 -640 429 -640 480 -500 333 -640 427 -429 640 -333 500 -480 640 -335 500 -640 427 -480 640 -500 378 -640 629 -640 424 -640 464 -383 640 -640 513 -333 500 -640 480 -375 500 -612 612 -640 425 -640 480 -640 480 -640 360 -612 612 -640 425 -640 480 -640 428 -428 640 -640 478 -399 500 -480 640 -640 427 -640 427 -640 428 -480 640 -640 425 -640 426 -640 480 -381 640 -640 480 -640 480 -427 640 -640 556 -640 480 -480 640 -640 640 -640 429 -500 375 -640 427 -480 640 -640 458 -480 640 -640 427 -500 500 -333 500 -480 640 -500 334 -640 480 -640 428 -640 426 -394 500 -640 427 -480 640 -640 441 -640 484 -480 640 -640 480 -640 480 -640 478 -640 427 -640 478 -428 640 -501 640 -640 400 -512 640 -480 640 -640 291 -640 480 -500 375 -640 480 -429 640 -464 640 -640 480 -640 640 -426 640 -640 407 -480 640 -480 640 -640 426 -640 480 -640 640 -404 640 -500 306 -640 472 -500 377 -640 480 -500 375 -640 439 -500 375 -640 427 -480 640 -500 375 -640 640 -640 473 -481 640 -640 432 -640 480 -425 640 -640 425 -640 360 -640 427 -640 421 -640 427 -640 428 -640 427 -500 333 -640 443 -458 640 -612 612 -640 427 -640 303 -640 480 -480 640 -640 478 -423 640 -640 512 -640 427 -640 480 -640 427 -640 480 -640 360 -640 480 -640 478 -385 308 -640 427 -500 381 -640 427 -480 640 -500 334 -640 480 -500 375 -640 426 -640 426 -640 480 -640 425 -453 640 -640 476 -500 375 -640 425 -640 480 -480 640 -612 612 -333 500 -478 640 -502 640 -500 333 -640 471 -640 480 -427 640 -640 480 -640 480 -640 427 -640 480 -640 400 -500 375 -640 480 -640 480 -500 333 -426 640 -427 640 -429 640 -640 478 -480 640 -432 640 -640 480 -480 640 -428 640 -640 478 -500 305 -500 375 -640 426 -500 334 -640 428 -612 612 -640 480 -640 496 -427 640 -360 640 -640 427 -396 640 -640 425 -640 480 -411 640 -640 425 -640 480 -640 480 -640 480 -640 427 -500 335 -640 480 -426 640 -640 480 -640 427 -500 375 -640 480 -640 461 -640 480 -640 480 -480 640 -640 425 -640 480 -640 427 -500 375 -640 424 -640 480 -480 640 -427 640 -640 480 -640 433 -640 400 -500 333 -640 480 -640 412 -612 612 -640 480 -447 640 -640 425 -640 427 -420 223 -356 640 -500 375 -427 640 -640 428 -427 640 -500 375 -640 427 -640 439 -640 419 -640 400 -500 500 -500 375 -640 403 -500 375 -640 427 -640 480 -640 424 -640 480 -640 514 -640 480 -640 480 -640 480 -640 428 -640 414 -500 333 -640 228 -640 480 -640 360 -640 480 -640 445 -640 493 -640 482 -480 640 -640 427 -640 461 -640 427 -640 428 -640 480 -640 427 -640 430 -640 426 -600 400 -640 427 -640 427 -428 640 -426 640 -640 453 -640 464 -480 640 -480 640 -640 480 -640 480 -640 426 -640 480 -640 416 -640 427 -640 480 -640 403 -640 480 -640 488 -640 425 -480 640 -640 480 -640 425 -600 400 -640 489 -640 266 -640 426 -512 640 -640 427 -640 480 -640 427 -640 480 -375 500 -640 480 -640 515 -640 427 -500 375 -600 399 -640 429 -500 372 -640 480 -640 426 -428 640 -640 427 -640 480 -640 427 -640 401 -500 375 -640 427 -426 640 -427 640 -480 640 -481 640 -429 640 -480 640 -640 427 -640 414 -640 574 -480 640 -640 427 -640 640 -321 500 -640 425 -640 480 -500 375 -640 428 -640 356 -480 640 -335 500 -640 425 -361 640 -640 454 -640 438 -640 480 -480 640 -640 480 -427 640 -500 375 -640 480 -640 480 -640 480 -640 480 -640 461 -640 395 -480 640 -640 360 -640 480 -640 616 -500 333 -474 640 -640 427 -640 480 -640 457 -640 424 -427 640 -640 359 -640 480 -640 480 -640 480 -640 471 -640 480 -427 640 -640 480 -640 427 -640 248 -640 424 -500 332 -640 426 -480 640 -333 500 -640 480 -640 427 -640 359 -378 500 -640 427 -333 500 -640 480 -640 427 -640 480 -480 640 -640 360 -640 480 -500 375 -480 640 -402 600 -640 425 -480 640 -500 326 -640 426 -640 425 -500 375 -375 500 -612 612 -427 640 -500 375 -640 427 -640 480 -375 500 -640 425 -480 640 -640 480 -480 640 -640 427 -470 640 -640 424 -360 500 -640 435 -640 491 -640 480 -640 360 -640 480 -640 486 -640 439 -640 429 -640 640 -480 640 -640 480 -500 335 -365 500 -478 640 -640 427 -500 332 -640 424 -640 480 -640 480 -427 640 -425 640 -640 480 -640 480 -600 363 -640 480 -640 428 -640 480 -640 457 -640 480 -640 427 -333 500 -640 428 -375 500 -640 384 -640 478 -640 480 -640 426 -640 360 -640 453 -427 640 -640 480 -640 426 -640 424 -640 480 -338 500 -640 436 -640 426 -512 640 -500 375 -640 428 -625 425 -640 427 -518 640 -640 480 -500 375 -640 427 -640 480 -640 426 -480 640 -480 640 -640 431 -640 480 -640 480 -640 427 -640 427 -612 612 -640 480 -500 375 -640 427 -640 426 -640 431 -482 500 -640 426 -640 640 -640 203 -640 480 -640 603 -640 640 -500 375 -640 480 -640 427 -640 426 -400 500 -640 480 -640 625 -480 640 -427 640 -640 480 -427 640 -640 360 -640 480 -617 640 -640 425 -640 428 -640 361 -426 640 -640 480 -640 480 -640 425 -640 360 -640 428 -640 420 -640 425 -480 640 -640 427 -640 480 -480 640 -480 640 -626 586 -612 612 -318 500 -428 640 -500 375 -427 640 -640 427 -640 427 -640 426 -640 426 -428 640 -612 612 -500 332 -480 640 -640 426 -411 640 -500 333 -640 480 -500 285 -640 480 -640 426 -640 479 -640 385 -640 480 -638 640 -640 512 -640 480 -480 640 -640 479 -426 640 -640 428 -480 640 -640 480 -640 480 -640 427 -426 640 -500 333 -640 427 -640 480 -640 480 -640 427 -640 608 -640 427 -640 480 -640 427 -480 640 -428 640 -640 428 -640 426 -640 480 -640 480 -640 426 -500 333 -640 444 -426 640 -640 480 -640 424 -500 400 -640 468 -640 429 -640 427 -640 425 -480 640 -529 640 -640 425 -640 427 -640 426 -480 640 -640 427 -640 446 -640 480 -480 640 -427 640 -640 386 -640 480 -500 333 -640 428 -640 480 -640 454 -424 640 -640 428 -640 389 -427 640 -640 480 -640 480 -640 360 -640 480 -480 640 -640 427 -427 640 -640 480 -640 458 -640 480 -640 480 -640 416 -427 640 -640 427 -360 240 -640 480 -500 375 -640 426 -640 480 -640 425 -640 425 -640 427 -480 640 -640 425 -640 553 -427 640 -640 426 -480 640 -640 480 -500 334 -480 640 -640 576 -640 425 -427 640 -640 426 -478 640 -640 476 -428 640 -427 640 -640 339 -427 640 -640 424 -427 640 -640 427 -640 427 -640 362 -524 640 -640 478 -426 640 -640 427 -500 375 -640 480 -640 480 -640 213 -640 427 -640 460 -512 640 -640 480 -640 480 -640 384 -640 443 -640 480 -500 334 -320 240 -640 480 -479 640 -640 480 -612 612 -640 424 -640 455 -300 225 -640 428 -640 428 -640 437 -640 427 -480 640 -640 480 -427 640 -640 426 -640 480 -640 480 -480 640 -640 427 -612 612 -640 428 -640 427 -600 400 -640 427 -480 640 -612 612 -427 640 -499 640 -640 480 -640 153 -640 427 -640 480 -500 375 -500 375 -640 480 -640 427 -500 374 -640 480 -640 483 -640 480 -640 576 -640 448 -640 478 -500 333 -480 640 -640 427 -480 640 -640 303 -480 640 -640 427 -640 480 -500 333 -640 427 -640 426 -640 480 -489 640 -640 427 -640 424 -640 359 -427 640 -500 333 -640 480 -333 500 -480 640 -375 500 -640 426 -640 578 -640 480 -480 640 -416 640 -640 408 -640 480 -500 333 -640 203 -612 612 -612 612 -383 640 -640 338 -640 427 -640 480 -640 441 -640 427 -427 640 -640 480 -640 427 -640 480 -640 426 -640 427 -640 480 -333 500 -640 169 -640 426 -428 640 -500 375 -480 640 -428 640 -500 314 -640 383 -480 640 -640 427 -640 428 -428 640 -640 631 -375 500 -425 640 -640 427 -497 640 -640 366 -640 426 -390 500 -640 427 -500 493 -640 428 -640 427 -640 427 -640 359 -640 480 -640 427 -480 640 -442 640 -426 640 -640 480 -640 425 -427 640 -640 480 -375 500 -500 337 -640 298 -640 366 -640 425 -640 480 -640 428 -640 480 -640 480 -640 480 -640 426 -640 426 -640 480 -640 480 -640 428 -640 480 -640 480 -640 480 -431 640 -640 427 -500 234 -333 500 -640 423 -640 427 -612 612 -334 500 -500 333 -500 333 -640 480 -427 640 -640 480 -500 375 -612 612 -640 456 -640 480 -640 458 -640 426 -511 640 -640 637 -640 480 -640 429 -640 480 -360 270 -640 479 -640 559 -640 405 -468 640 -640 480 -427 640 -426 640 -640 429 -500 250 -500 277 -500 375 -640 427 -640 427 -640 436 -640 480 -388 500 -640 427 -360 640 -500 375 -640 425 -426 640 -438 640 -640 435 -640 502 -640 511 -480 640 -640 480 -640 480 -480 640 -640 427 -640 480 -333 500 -640 482 -640 484 -640 480 -640 480 -640 427 -640 480 -640 480 -441 640 -640 480 -640 480 -640 532 -640 429 -427 640 -480 640 -640 385 -427 640 -640 425 -640 416 -640 426 -640 426 -640 480 -550 539 -640 384 -640 479 -640 480 -500 334 -640 480 -640 425 -500 375 -640 480 -480 640 -480 640 -500 333 -326 640 -640 480 -480 640 -500 375 -512 640 -640 427 -640 426 -448 336 -640 480 -640 424 -480 640 -500 438 -478 640 -640 428 -480 640 -640 424 -640 480 -640 480 -426 640 -640 429 -640 480 -640 458 -640 429 -640 480 -500 375 -640 480 -427 640 -640 427 -640 639 -640 427 -640 480 -640 427 -424 640 -640 425 -640 424 -480 640 -640 479 -640 425 -640 428 -640 426 -421 640 -640 413 -640 480 -640 480 -480 640 -426 640 -224 500 -428 640 -462 462 -640 399 -481 500 -640 418 -449 600 -640 480 -640 427 -500 375 -640 427 -640 479 -640 480 -480 640 -640 394 -640 496 -501 640 -640 427 -640 480 -480 640 -640 427 -640 427 -591 640 -640 427 -612 612 -500 335 -478 640 -458 640 -493 640 -500 375 -430 500 -640 480 -640 480 -640 480 -640 415 -640 480 -640 480 -640 423 -500 333 -640 399 -500 375 -640 480 -640 480 -640 469 -500 210 -640 480 -500 375 -500 375 -640 408 -640 480 -428 640 -350 350 -640 480 -640 480 -640 480 -394 500 -428 640 -640 480 -640 480 -359 640 -640 426 -428 640 -640 427 -640 426 -640 426 -640 480 -640 453 -640 526 -640 480 -640 424 -484 640 -480 640 -640 426 -640 427 -640 427 -400 285 -429 640 -640 453 -427 640 -478 640 -480 640 -640 512 -640 427 -640 480 -500 339 -640 428 -333 500 -480 640 -640 427 -640 480 -612 612 -640 429 -640 427 -500 406 -640 427 -640 360 -427 640 -640 424 -640 427 -640 427 -427 640 -640 480 -480 640 -640 358 -375 500 -640 480 -480 640 -640 406 -424 351 -500 375 -500 333 -640 480 -640 426 -640 529 -640 427 -640 426 -427 640 -640 480 -640 427 -408 640 -361 640 -500 289 -612 612 -640 428 -480 640 -640 470 -500 333 -480 640 -500 375 -640 427 -640 637 -640 361 -500 375 -640 480 -500 460 -640 425 -426 640 -640 480 -427 640 -480 640 -640 426 -427 640 -640 400 -640 640 -266 412 -640 480 -640 360 -376 500 -427 640 -640 640 -640 426 -333 500 -478 640 -640 425 -427 640 -640 426 -480 640 -500 375 -500 334 -640 480 -500 473 -480 640 -640 427 -640 481 -360 480 -480 640 -640 530 -640 504 -640 499 -500 334 -640 427 -478 640 -526 640 -375 500 -640 480 -640 457 -500 332 -500 333 -640 550 -640 438 -640 446 -468 640 -640 408 -640 427 -427 640 -426 640 -640 480 -640 433 -640 366 -640 480 -500 375 -640 427 -640 480 -640 457 -375 500 -640 480 -500 375 -640 480 -640 640 -612 612 -640 425 -640 427 -427 640 -640 480 -480 640 -640 480 -640 419 -640 480 -640 360 -640 480 -640 480 -612 612 -640 421 -480 640 -640 427 -640 480 -427 640 -640 480 -640 240 -500 334 -427 640 -640 480 -375 500 -480 640 -321 500 -640 480 -426 640 -640 428 -220 176 -640 414 -480 640 -640 427 -640 480 -640 426 -640 427 -364 500 -640 480 -640 427 -427 640 -640 480 -640 429 -640 480 -480 640 -640 425 -640 428 -640 425 -640 427 -612 612 -640 427 -640 480 -640 428 -640 480 -640 480 -480 640 -640 640 -480 640 -640 480 -428 640 -480 640 -500 375 -500 500 -640 480 -640 427 -640 480 -640 458 -640 428 -612 612 -500 332 -640 383 -640 427 -640 426 -464 640 -640 480 -640 427 -640 427 -500 346 -640 480 -427 640 -375 500 -640 467 -470 640 -640 427 -500 458 -640 480 -640 480 -500 375 -426 640 -640 426 -327 640 -640 469 -640 428 -640 427 -640 480 -640 480 -640 423 -612 612 -640 427 -412 640 -298 448 -640 427 -640 480 -480 640 -640 480 -640 480 -640 480 -640 481 -640 426 -500 375 -612 612 -640 479 -640 219 -640 419 -480 640 -640 425 -640 427 -640 425 -500 500 -640 448 -640 427 -480 640 -640 480 -640 473 -640 426 -640 427 -500 284 -640 427 -640 458 -640 480 -640 480 -640 453 -500 375 -640 398 -500 375 -640 480 -640 468 -480 640 -640 464 -402 640 -640 480 -640 480 -640 424 -640 480 -500 375 -640 425 -431 640 -640 480 -640 427 -640 338 -640 427 -640 428 -639 428 -612 612 -427 640 -640 427 -500 333 -640 463 -640 425 -640 427 -640 374 -640 480 -640 480 -480 640 -640 427 -640 480 -640 428 -640 480 -640 480 -500 338 -480 640 -451 500 -640 427 -640 480 -427 640 -640 425 -427 640 -480 640 -480 640 -640 478 -640 480 -640 480 -640 427 -429 640 -425 640 -500 375 -640 294 -640 640 -429 640 -640 427 -426 640 -640 423 -480 640 -640 428 -640 424 -640 480 -640 427 -640 480 -500 375 -500 375 -480 640 -500 335 -427 640 -480 640 -640 383 -500 375 -428 640 -640 478 -494 640 -480 640 -392 591 -640 536 -344 500 -480 640 -640 480 -640 480 -500 500 -612 612 -640 504 -640 426 -640 480 -640 427 -640 423 -640 298 -375 500 -396 640 -640 427 -640 480 -640 480 -640 533 -375 500 -640 480 -640 425 -360 640 -640 425 -640 479 -424 640 -640 427 -457 640 -640 428 -640 467 -640 428 -640 427 -480 640 -640 427 -640 427 -640 480 -480 640 -640 480 -640 427 -500 375 -500 375 -640 480 -640 480 -480 640 -640 480 -426 640 -640 359 -640 352 -640 427 -640 480 -640 480 -500 400 -640 424 -640 480 -500 375 -640 480 -640 426 -500 333 -640 425 -640 480 -383 640 -640 428 -640 480 -640 427 -640 427 -640 425 -612 612 -640 480 -640 480 -640 511 -427 640 -640 359 -640 480 -640 480 -426 640 -640 480 -640 480 -640 427 -427 640 -640 480 -640 426 -500 375 -640 434 -480 640 -640 424 -640 480 -640 423 -640 427 -640 480 -612 612 -640 189 -478 640 -640 555 -640 478 -500 333 -500 375 -254 640 -480 640 -500 375 -429 640 -640 480 -640 360 -480 640 -612 612 -480 640 -640 638 -640 309 -640 480 -640 427 -612 612 -640 414 -640 427 -640 480 -500 332 -500 375 -500 489 -640 480 -480 640 -612 612 -640 425 -480 640 -612 612 -590 640 -640 426 -640 360 -640 480 -640 489 -640 425 -484 640 -640 427 -480 640 -640 480 -640 479 -500 299 -640 417 -640 373 -640 427 -612 612 -500 376 -640 427 -640 480 -640 415 -640 480 -480 640 -480 640 -640 480 -640 480 -640 569 -500 375 -640 480 -426 640 -640 426 -640 480 -640 480 -425 640 -640 640 -426 640 -640 480 -427 640 -428 640 -427 640 -640 425 -640 480 -324 500 -640 480 -640 428 -500 333 -640 426 -640 427 -640 480 -449 640 -640 480 -640 426 -480 640 -428 640 -424 640 -500 375 -640 427 -612 612 -640 480 -427 640 -640 480 -640 359 -640 478 -500 401 -640 480 -500 375 -640 480 -480 640 -480 640 -640 427 -640 480 -640 422 -640 484 -640 428 -640 478 -500 452 -640 366 -425 640 -640 427 -500 333 -640 427 -500 375 -640 426 -640 480 -640 427 -480 640 -500 375 -640 427 -640 426 -640 480 -640 427 -640 425 -640 480 -640 480 -640 426 -500 375 -500 400 -640 429 -640 465 -500 375 -640 480 -640 427 -375 500 -640 514 -640 445 -640 427 -640 480 -640 425 -500 400 -640 427 -640 427 -640 378 -640 481 -640 400 -640 480 -640 480 -640 426 -424 640 -640 360 -500 332 -640 384 -640 427 -500 374 -480 640 -640 480 -640 480 -427 640 -640 426 -375 500 -640 480 -640 427 -640 428 -500 375 -640 432 -480 640 -640 480 -480 640 -640 451 -640 480 -640 480 -615 640 -640 480 -640 480 -640 480 -480 640 -640 427 -640 427 -401 640 -640 480 -640 464 -500 375 -640 427 -640 427 -640 426 -640 480 -640 427 -636 640 -640 401 -640 428 -640 480 -500 333 -640 480 -500 333 -640 480 -564 640 -640 480 -480 640 -640 427 -500 375 -500 359 -640 439 -469 640 -640 360 -640 478 -640 480 -640 480 -640 430 -640 480 -640 480 -640 480 -640 420 -500 375 -426 640 -427 640 -333 500 -480 640 -640 384 -640 426 -640 480 -640 443 -640 631 -640 458 -640 480 -500 331 -480 640 -640 426 -519 640 -640 436 -401 640 -480 640 -640 485 -640 414 -640 427 -640 427 -640 426 -640 480 -640 480 -500 375 -640 325 -494 640 -480 640 -441 640 -640 480 -640 511 -640 428 -640 426 -586 640 -640 427 -640 427 -500 281 -640 480 -500 333 -640 428 -640 640 -640 425 -480 640 -500 333 -629 640 -426 640 -640 427 -544 408 -426 640 -640 427 -640 480 -375 500 -424 640 -428 640 -640 480 -431 640 -640 500 -640 480 -640 224 -374 500 -640 426 -500 343 -640 426 -640 480 -640 427 -480 640 -640 427 -480 640 -480 640 -640 480 -640 366 -444 640 -640 640 -640 480 -640 480 -423 640 -640 615 -640 480 -640 513 -427 640 -375 500 -640 429 -640 480 -500 375 -480 640 -500 371 -640 428 -500 333 -480 640 -612 612 -480 640 -427 640 -480 640 -640 427 -640 524 -640 480 -640 403 -640 429 -500 375 -640 480 -640 427 -640 414 -500 375 -640 480 -640 480 -640 480 -640 480 -400 600 -640 428 -427 640 -427 640 -427 640 -480 640 -500 375 -500 375 -375 500 -622 415 -480 640 -428 640 -640 366 -427 640 -480 640 -500 375 -640 480 -640 480 -500 375 -640 426 -640 425 -640 480 -640 480 -640 427 -640 480 -359 640 -427 640 -500 440 -427 640 -640 425 -427 640 -500 375 -640 480 -640 453 -500 375 -640 400 -640 427 -640 480 -480 640 -640 480 -640 435 -640 478 -480 640 -500 333 -640 480 -640 480 -640 480 -640 366 -640 480 -640 481 -640 427 -640 426 -640 480 -480 640 -500 333 -480 640 -640 480 -640 428 -640 218 -640 427 -500 333 -500 334 -640 427 -640 640 -480 640 -427 640 -640 481 -640 478 -640 426 -640 427 -640 425 -640 427 -333 500 -612 612 -640 480 -640 427 -640 491 -640 478 -640 360 -473 640 -612 612 -640 428 -640 427 -640 480 -640 426 -500 375 -500 375 -640 427 -640 480 -427 640 -640 480 -640 426 -350 500 -500 308 -640 608 -640 503 -640 480 -640 480 -500 375 -640 480 -640 480 -500 375 -416 640 -640 427 -612 612 -389 500 -480 640 -640 426 -640 424 -363 485 -640 549 -640 427 -500 337 -640 479 -640 426 -500 375 -640 427 -640 480 -640 426 -490 640 -640 427 -640 480 -640 427 -640 425 -465 640 -640 480 -500 334 -640 424 -640 426 -640 424 -640 479 -375 500 -640 427 -640 480 -428 640 -500 333 -640 480 -640 480 -640 480 -640 361 -640 425 -500 333 -640 480 -640 459 -640 403 -640 480 -640 480 -363 640 -500 374 -640 425 -640 427 -600 399 -640 427 -500 333 -640 469 -640 427 -640 424 -640 446 -640 427 -640 480 -640 480 -640 427 -640 389 -500 351 -640 425 -604 453 -640 427 -428 640 -500 375 -640 428 -500 375 -640 480 -640 421 -640 360 -401 640 -640 425 -640 426 -612 612 -640 480 -640 480 -375 500 -428 640 -640 426 -640 479 -640 427 -361 640 -427 640 -480 640 -640 480 -640 480 -640 459 -500 375 -640 426 -640 480 -426 640 -640 480 -640 480 -640 424 -640 480 -640 614 -640 480 -640 359 -640 427 -480 640 -640 480 -640 480 -640 427 -500 333 -375 500 -481 640 -640 480 -480 640 -500 375 -640 512 -640 480 -455 552 -640 427 -640 480 -640 427 -640 460 -640 480 -640 426 -640 301 -480 640 -478 640 -427 640 -640 441 -640 480 -612 612 -640 430 -640 480 -640 480 -640 480 -640 427 -640 426 -640 528 -640 320 -480 640 -640 564 -640 640 -640 480 -500 375 -431 640 -500 375 -428 640 -500 375 -354 500 -640 383 -480 640 -640 439 -640 480 -640 627 -640 427 -500 338 -480 640 -640 406 -640 480 -561 640 -640 480 -375 500 -640 480 -427 640 -640 480 -640 480 -640 401 -640 480 -640 435 -640 602 -640 480 -640 640 -640 480 -640 427 -500 489 -640 480 -640 424 -640 480 -640 457 -640 480 -640 480 -640 480 -500 375 -640 426 -640 478 -480 640 -427 640 -640 480 -640 480 -640 480 -640 378 -640 480 -640 480 -480 640 -427 640 -640 451 -640 631 -500 338 -640 480 -640 447 -500 333 -640 425 -640 426 -640 480 -428 640 -640 480 -640 479 -426 640 -640 427 -500 415 -438 640 -640 480 -640 468 -640 426 -640 480 -640 432 -640 425 -640 480 -428 640 -640 427 -640 426 -270 500 -640 480 -478 640 -640 467 -640 426 -500 372 -640 426 -480 640 -409 500 -640 480 -640 481 -640 480 -640 425 -640 427 -640 480 -640 480 -612 612 -493 640 -640 416 -640 480 -640 427 -640 427 -640 480 -427 640 -500 375 -640 426 -640 480 -640 480 -640 427 -480 640 -640 640 -640 425 -640 480 -640 480 -480 640 -640 427 -480 640 -480 640 -640 427 -415 640 -640 427 -640 427 -640 427 -640 480 -500 375 -640 425 -640 428 -480 640 -640 427 -640 424 -640 491 -640 424 -333 500 -640 480 -640 425 -640 427 -640 427 -500 375 -640 424 -640 425 -640 427 -640 640 -640 480 -500 375 -425 640 -640 480 -640 425 -500 305 -500 375 -640 480 -640 480 -320 240 -640 387 -640 480 -640 480 -640 480 -612 612 -640 480 -500 375 -272 500 -640 426 -640 512 -640 512 -640 480 -640 428 -480 640 -640 458 -640 360 -640 427 -640 480 -640 426 -640 427 -640 480 -640 427 -500 375 -500 332 -478 640 -640 298 -425 640 -481 640 -640 333 -640 480 -640 480 -640 244 -500 281 -640 376 -640 640 -640 480 -612 612 -640 426 -500 323 -508 640 -427 640 -480 640 -640 427 -640 427 -424 640 -500 334 -640 425 -640 476 -612 612 -433 640 -480 640 -640 480 -640 406 -568 640 -640 427 -346 500 -500 332 -500 333 -640 493 -473 640 -640 480 -640 513 -640 425 -640 427 -640 424 -480 640 -640 428 -640 426 -640 480 -640 427 -640 424 -640 428 -640 426 -640 480 -640 480 -640 427 -500 375 -639 640 -512 640 -612 612 -640 480 -640 480 -480 640 -429 640 -640 546 -640 480 -480 640 -640 424 -424 640 -332 500 -640 459 -640 480 -500 333 -640 425 -427 640 -640 427 -640 480 -640 427 -640 480 -640 480 -472 322 -640 424 -478 640 -640 431 -640 323 -640 427 -500 375 -480 640 -640 401 -480 640 -333 500 -640 480 -633 640 -427 640 -640 640 -640 480 -640 427 -500 411 -640 427 -500 353 -640 480 -640 480 -359 640 -640 427 -426 640 -482 640 -640 427 -427 640 -375 500 -500 375 -640 480 -427 640 -640 428 -640 481 -640 480 -640 427 -640 426 -500 375 -640 427 -428 640 -640 480 -640 480 -375 500 -640 427 -640 408 -500 400 -640 480 -640 449 -375 500 -453 640 -424 640 -640 427 -640 428 -640 480 -640 480 -640 480 -640 426 -640 425 -427 640 -640 459 -640 424 -612 612 -640 480 -640 427 -640 427 -640 427 -640 480 -640 427 -640 457 -640 480 -500 428 -429 640 -640 438 -640 427 -640 480 -426 640 -500 375 -640 384 -500 333 -500 281 -640 426 -640 431 -426 640 -500 375 -481 640 -640 480 -640 480 -640 480 -640 456 -426 640 -640 480 -640 396 -450 338 -495 640 -640 435 -500 408 -404 640 -640 427 -500 375 -476 640 -640 480 -640 427 -640 480 -640 480 -640 393 -640 480 -640 480 -640 480 -375 500 -495 533 -480 640 -480 640 -500 295 -480 640 -612 612 -640 478 -640 426 -612 612 -426 640 -640 480 -640 480 -640 427 -640 428 -640 486 -640 426 -640 481 -640 427 -640 426 -640 427 -640 428 -600 400 -640 409 -640 424 -640 426 -640 367 -640 480 -640 426 -612 612 -480 640 -640 480 -480 640 -640 480 -640 427 -640 427 -426 640 -640 427 -480 640 -640 426 -426 640 -640 427 -640 426 -500 375 -333 500 -612 612 -640 424 -640 480 -640 509 -640 427 -640 427 -500 239 -640 426 -640 427 -379 446 -640 427 -640 426 -640 478 -640 480 -427 640 -640 480 -627 640 -640 480 -500 375 -427 640 -640 478 -640 427 -612 612 -640 640 -500 356 -480 640 -640 427 -514 640 -640 458 -500 335 -640 480 -640 480 -640 516 -640 428 -640 427 -512 640 -333 500 -500 257 -640 360 -640 480 -640 480 -640 480 -375 500 -640 480 -427 640 -500 375 -640 427 -640 480 -480 640 -640 504 -480 640 -640 480 -427 640 -427 640 -640 480 -500 375 -500 333 -640 426 -640 257 -640 433 -500 333 -640 427 -640 360 -640 426 -640 427 -459 640 -640 296 -640 419 -360 640 -640 480 -480 640 -424 640 -375 500 -500 375 -428 640 -640 427 -640 428 -612 612 -480 640 -500 281 -640 349 -640 378 -640 480 -640 439 -427 640 -600 600 -480 640 -500 333 -427 640 -640 427 -640 427 -640 427 -640 453 -640 427 -640 427 -640 480 -640 427 -500 375 -640 480 -640 427 -640 425 -640 389 -640 480 -480 640 -640 480 -640 480 -640 480 -640 427 -640 516 -640 424 -640 480 -640 428 -480 640 -612 612 -640 477 -500 375 -480 640 -640 428 -480 640 -640 427 -375 500 -640 360 -640 480 -640 426 -640 427 -640 425 -640 428 -640 480 -640 426 -500 408 -640 428 -640 480 -425 640 -500 471 -480 640 -640 480 -480 640 -640 480 -640 480 -640 427 -478 640 -640 427 -640 513 -500 365 -640 508 -480 640 -640 480 -425 640 -640 480 -640 640 -640 425 -520 520 -640 424 -640 480 -640 483 -640 424 -480 640 -640 480 -612 612 -640 427 -640 427 -640 468 -640 427 -500 332 -640 480 -640 427 -640 480 -480 640 -640 480 -640 480 -500 422 -640 424 -448 299 -640 480 -480 640 -480 640 -375 500 -500 375 -640 480 -640 427 -640 427 -640 427 -500 332 -640 427 -640 428 -500 375 -640 427 -500 375 -640 478 -640 429 -375 500 -640 640 -427 640 -640 518 -640 428 -640 480 -480 640 -640 480 -480 640 -640 286 -640 466 -424 640 -640 480 -640 480 -424 640 -640 480 -500 332 -640 393 -640 427 -640 394 -640 471 -500 375 -500 390 -500 332 -640 640 -640 318 -640 427 -640 398 -480 640 -640 500 -425 640 -640 354 -640 480 -640 428 -640 478 -427 640 -500 492 -640 471 -640 427 -640 396 -640 427 -640 480 -612 612 -640 480 -500 375 -500 333 -640 427 -480 640 -640 426 -640 425 -640 427 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -480 640 -368 500 -375 500 -375 500 -640 428 -640 427 -640 427 -375 500 -640 480 -640 480 -640 590 -640 425 -482 640 -480 640 -640 424 -375 500 -640 360 -640 480 -480 640 -500 375 -520 640 -640 487 -425 640 -480 640 -640 463 -500 333 -500 375 -374 500 -482 500 -500 500 -640 441 -612 612 -640 480 -640 479 -640 323 -500 334 -526 640 -640 480 -427 640 -640 480 -640 427 -640 480 -640 424 -640 480 -640 444 -426 640 -640 574 -640 293 -640 480 -640 639 -640 427 -500 375 -640 427 -480 640 -640 360 -640 424 -640 480 -640 480 -640 427 -500 375 -480 640 -640 413 -640 428 -640 480 -640 428 -480 640 -640 480 -640 480 -640 428 -640 480 -427 640 -640 427 -480 640 -427 640 -478 640 -427 640 -612 612 -428 640 -640 480 -500 375 -480 640 -640 480 -640 480 -480 640 -640 480 -640 480 -630 379 -425 640 -640 439 -640 480 -480 640 -640 401 -500 500 -640 427 -428 640 -333 500 -640 463 -640 425 -640 433 -640 480 -640 480 -427 640 -428 640 -640 428 -425 640 -640 480 -423 640 -640 426 -500 333 -640 427 -500 375 -640 457 -480 640 -640 427 -426 640 -513 640 -640 426 -500 375 -640 397 -640 360 -426 640 -640 360 -640 427 -640 426 -640 422 -427 640 -640 480 -480 640 -640 478 -640 480 -640 426 -428 640 -640 480 -640 426 -477 640 -640 480 -640 427 -640 233 -640 426 -375 500 -500 333 -640 480 -640 426 -500 334 -500 375 -400 302 -500 332 -375 500 -640 284 -640 433 -500 332 -640 362 -640 480 -640 427 -640 480 -500 375 -640 480 -612 612 -426 640 -640 320 -640 424 -427 640 -640 480 -640 360 -427 640 -426 640 -640 426 -640 424 -640 427 -480 640 -640 480 -550 376 -640 480 -640 427 -640 428 -640 639 -640 640 -640 426 -480 640 -427 640 -640 428 -640 428 -640 480 -427 640 -480 640 -363 544 -640 480 -267 188 -500 375 -500 331 -500 334 -640 480 -640 428 -500 362 -476 640 -640 430 -640 480 -640 480 -640 433 -640 343 -406 500 -640 426 -500 375 -640 426 -640 480 -640 449 -320 240 -640 427 -500 375 -640 324 -640 428 -640 480 -500 452 -427 640 -500 500 -500 333 -640 480 -640 233 -640 427 -640 429 -417 640 -480 640 -450 381 -640 427 -640 421 -500 333 -640 640 -532 640 -456 640 -640 360 -640 480 -640 425 -640 480 -640 480 -640 606 -640 426 -640 426 -640 429 -640 428 -640 480 -480 640 -427 640 -640 480 -337 640 -640 426 -640 470 -640 427 -431 640 -640 640 -640 467 -470 640 -640 640 -480 640 -410 339 -427 640 -640 480 -640 447 -640 428 -480 640 -640 174 -612 612 -640 480 -640 360 -612 612 -640 428 -480 640 -375 500 -640 480 -640 424 -500 375 -600 400 -640 480 -640 426 -480 640 -640 281 -640 480 -500 375 -640 480 -640 400 -640 425 -640 480 -640 427 -640 429 -427 640 -640 446 -640 359 -612 612 -640 426 -427 640 -640 457 -640 427 -480 640 -426 640 -640 480 -576 396 -640 480 -640 427 -500 332 -640 393 -500 370 -640 426 -640 480 -640 427 -640 458 -640 480 -426 640 -500 314 -500 400 -640 426 -640 480 -640 427 -640 480 -600 410 -480 640 -640 480 -640 480 -640 426 -640 480 -500 375 -640 526 -640 427 -425 640 -640 482 -640 448 -640 480 -640 427 -640 480 -640 427 -640 426 -640 480 -500 357 -640 480 -640 360 -500 375 -640 480 -640 480 -640 364 -427 640 -640 427 -334 500 -640 427 -640 480 -500 375 -480 640 -478 640 -640 427 -640 480 -500 334 -640 480 -480 640 -640 425 -640 480 -640 425 -640 438 -640 425 -640 427 -640 480 -640 480 -375 500 -640 510 -450 600 -640 427 -375 500 -640 480 -480 640 -640 427 -640 480 -640 480 -248 640 -480 640 -640 427 -640 431 -640 480 -640 427 -416 640 -640 452 -640 640 -640 427 -640 480 -640 480 -478 640 -640 480 -372 500 -640 428 -640 427 -640 480 -640 480 -640 478 -640 640 -612 612 -500 375 -640 480 -640 478 -640 640 -640 473 -480 640 -640 427 -500 375 -640 480 -640 427 -640 640 -640 471 -640 480 -640 480 -480 640 -640 480 -640 486 -640 480 -640 391 -500 375 -426 640 -500 378 -640 428 -640 480 -640 480 -640 427 -480 640 -640 480 -640 456 -640 428 -500 333 -640 557 -640 457 -426 640 -640 480 -640 427 -640 476 -640 640 -640 491 -500 384 -640 403 -640 640 -640 439 -428 640 -640 480 -361 640 -612 612 -640 480 -481 640 -640 480 -565 640 -640 360 -640 426 -640 428 -640 429 -403 640 -640 480 -640 480 -640 427 -640 428 -640 425 -640 380 -640 426 -480 640 -640 480 -640 426 -640 480 -640 429 -548 640 -640 431 -500 375 -500 375 -640 474 -500 333 -480 640 -640 599 -480 640 -427 640 -640 428 -500 400 -500 375 -426 640 -427 640 -640 331 -480 640 -640 425 -640 480 -640 427 -500 333 -640 286 -500 333 -640 428 -375 500 -640 480 -417 640 -640 427 -640 480 -427 640 -640 480 -427 640 -640 426 -640 490 -640 427 -640 480 -336 448 -640 361 -640 360 -418 640 -480 640 -640 426 -500 375 -640 426 -305 229 -600 640 -426 640 -640 480 -640 480 -640 414 -640 427 -500 375 -500 446 -314 500 -640 480 -640 480 -640 480 -640 622 -480 640 -418 640 -428 640 -640 427 -500 352 -640 480 -640 480 -640 480 -640 359 -640 427 -640 566 -640 428 -640 426 -640 426 -640 425 -427 640 -612 612 -640 566 -640 427 -640 480 -640 480 -640 428 -480 640 -640 480 -640 429 -640 480 -429 640 -612 612 -640 424 -640 371 -495 640 -427 640 -640 640 -640 282 -640 427 -640 426 -500 335 -640 480 -480 640 -480 640 -500 376 -640 480 -425 640 -640 427 -500 333 -640 640 -332 500 -640 427 -640 527 -640 480 -640 426 -640 480 -640 419 -480 640 -640 238 -480 640 -640 480 -640 480 -640 480 -640 425 -640 427 -500 375 -425 640 -640 480 -478 640 -640 488 -640 480 -640 461 -374 500 -640 427 -640 427 -500 333 -612 612 -640 428 -426 640 -640 429 -640 427 -361 640 -428 640 -640 427 -640 427 -640 436 -640 293 -640 418 -640 480 -640 428 -640 480 -612 612 -612 612 -640 480 -426 640 -640 427 -500 375 -480 640 -640 640 -640 480 -427 640 -640 429 -640 427 -640 474 -427 640 -640 427 -640 426 -427 640 -414 640 -478 640 -640 480 -480 640 -640 427 -443 640 -640 480 -640 426 -500 334 -640 427 -640 480 -574 640 -480 640 -512 640 -640 480 -640 480 -640 464 -500 375 -640 428 -375 500 -640 480 -375 500 -640 480 -640 480 -640 434 -480 640 -612 612 -640 480 -640 426 -366 500 -480 640 -500 375 -640 425 -500 333 -640 479 -640 428 -640 480 -640 480 -640 360 -640 480 -640 427 -480 640 -640 480 -640 428 -640 427 -640 457 -481 640 -640 492 -480 640 -500 333 -597 455 -480 640 -354 500 -493 640 -640 480 -640 359 -640 480 -500 375 -640 480 -640 427 -500 375 -428 640 -640 360 -480 640 -640 427 -480 640 -640 480 -640 413 -427 640 -640 414 -640 384 -426 640 -640 389 -425 640 -640 427 -431 640 -640 427 -427 640 -640 427 -640 409 -426 640 -530 640 -640 390 -640 425 -640 427 -640 478 -415 324 -640 434 -427 640 -480 640 -426 640 -536 640 -640 427 -640 395 -640 427 -374 500 -640 426 -640 427 -176 144 -640 640 -640 354 -640 480 -500 343 -427 640 -640 426 -612 612 -640 425 -640 480 -375 500 -427 640 -640 480 -640 479 -640 360 -640 425 -640 425 -500 375 -640 480 -640 426 -640 427 -640 426 -480 640 -480 640 -640 480 -480 640 -640 428 -612 612 -425 640 -640 427 -640 359 -640 480 -640 431 -500 311 -640 480 -640 405 -428 640 -486 640 -640 480 -640 426 -375 500 -640 480 -640 427 -640 426 -427 640 -640 264 -500 375 -640 427 -640 425 -500 332 -640 427 -640 449 -640 399 -640 480 -640 480 -500 322 -639 640 -640 427 -640 480 -640 427 -480 640 -640 480 -640 426 -640 480 -640 360 -640 512 -640 424 -480 640 -640 425 -640 431 -480 640 -500 375 -500 334 -571 640 -480 640 -640 480 -612 612 -427 640 -359 640 -500 336 -640 427 -334 500 -500 375 -360 270 -500 375 -640 427 -640 457 -640 480 -480 640 -500 375 -612 612 -427 640 -388 640 -500 333 -640 480 -500 375 -640 438 -480 640 -480 640 -640 427 -640 480 -640 480 -480 640 -500 333 -640 479 -640 429 -500 375 -640 412 -640 480 -640 421 -640 480 -640 480 -480 640 -640 480 -640 480 -640 359 -640 366 -640 480 -427 640 -640 427 -640 426 -640 480 -480 640 -640 427 -640 378 -640 480 -640 480 -640 480 -640 428 -640 480 -480 640 -434 640 -640 413 -640 480 -640 480 -373 640 -640 428 -640 433 -500 375 -427 640 -640 480 -480 640 -640 503 -640 427 -640 480 -500 333 -640 429 -640 482 -460 640 -512 640 -612 612 -640 426 -640 480 -480 640 -640 278 -640 524 -640 479 -640 430 -640 480 -640 439 -375 500 -426 640 -640 428 -640 427 -480 640 -640 480 -640 480 -640 426 -640 512 -640 427 -640 480 -640 427 -640 424 -640 427 -640 427 -500 375 -640 480 -545 640 -637 640 -427 640 -427 640 -640 480 -426 640 -640 480 -408 640 -500 375 -640 480 -640 480 -480 640 -640 428 -640 640 -428 640 -640 480 -640 427 -640 480 -640 427 -640 483 -478 640 -640 480 -500 375 -612 612 -640 424 -436 640 -640 428 -640 480 -640 427 -612 612 -480 640 -383 640 -640 427 -500 334 -640 449 -640 427 -640 480 -640 427 -500 375 -500 375 -640 480 -640 478 -640 480 -427 640 -640 428 -640 480 -425 640 -640 480 -640 425 -612 612 -480 640 -640 360 -640 403 -427 640 -640 427 -612 612 -640 425 -640 480 -500 418 -640 480 -640 480 -640 351 -640 480 -640 480 -480 640 -500 375 -375 500 -640 480 -469 640 -640 425 -640 480 -640 623 -640 480 -640 427 -640 512 -480 640 -640 445 -359 239 -640 523 -640 427 -334 500 -640 425 -500 375 -640 427 -333 500 -640 359 -478 640 -500 375 -640 528 -640 426 -500 333 -640 480 -640 575 -480 640 -640 429 -640 580 -640 640 -640 480 -640 427 -640 480 -640 475 -640 480 -500 375 -640 480 -480 640 -640 426 -640 424 -640 480 -427 640 -500 362 -478 640 -480 640 -640 480 -640 480 -478 640 -640 414 -640 427 -500 343 -500 297 -640 428 -500 348 -640 480 -220 240 -640 425 -423 640 -640 425 -640 408 -640 411 -640 427 -640 437 -640 360 -640 385 -640 464 -640 480 -524 640 -640 480 -640 427 -500 333 -640 427 -640 431 -640 480 -640 427 -640 480 -640 480 -427 640 -640 438 -640 427 -640 480 -640 480 -480 640 -640 469 -640 428 -640 427 -640 428 -640 428 -426 639 -500 333 -640 480 -480 336 -334 500 -454 640 -500 375 -506 640 -640 640 -640 616 -640 480 -427 640 -640 468 -640 428 -640 423 -640 427 -427 640 -428 640 -400 500 -640 480 -640 427 -640 384 -640 348 -640 619 -357 500 -640 480 -640 428 -640 480 -500 405 -640 427 -441 500 -480 640 -640 480 -488 640 -500 375 -640 427 -432 324 -640 480 -640 503 -499 640 -640 480 -640 424 -612 612 -640 425 -640 427 -427 640 -640 435 -375 500 -495 640 -480 640 -424 640 -640 480 -600 400 -640 428 -640 427 -640 480 -640 480 -640 427 -417 640 -640 388 -640 425 -375 500 -481 640 -640 480 -640 427 -427 640 -500 332 -427 640 -640 504 -640 640 -500 375 -640 480 -640 427 -640 414 -480 640 -640 427 -640 480 -612 612 -640 487 -640 427 -640 429 -640 427 -400 640 -640 480 -640 480 -500 375 -478 640 -640 360 -640 418 -412 456 -640 425 -640 480 -640 427 -640 594 -640 409 -480 640 -640 428 -640 428 -640 480 -612 612 -640 427 -640 453 -640 480 -640 403 -500 400 -640 427 -640 480 -640 480 -640 480 -480 640 -500 375 -427 640 -500 375 -500 380 -612 612 -640 427 -640 400 -427 640 -640 426 -640 361 -640 433 -500 492 -640 427 -640 428 -640 427 -640 427 -640 424 -640 480 -640 457 -500 400 -640 425 -500 333 -640 628 -427 640 -640 427 -640 480 -640 427 -500 375 -640 427 -480 640 -640 426 -448 640 -640 480 -480 640 -640 480 -480 640 -640 480 -329 640 -480 640 -640 513 -640 457 -480 640 -640 360 -640 489 -640 466 -500 375 -640 480 -640 425 -640 427 -640 480 -640 480 -640 427 -427 640 -445 500 -640 549 -640 436 -640 554 -640 480 -480 640 -427 640 -389 640 -640 426 -428 640 -640 427 -640 454 -480 640 -640 640 -480 640 -640 480 -640 583 -640 425 -640 396 -500 375 -500 170 -640 427 -640 424 -640 428 -480 640 -640 480 -500 375 -500 313 -640 426 -640 457 -640 424 -640 427 -480 640 -640 427 -240 180 -640 480 -640 480 -640 427 -640 427 -375 500 -640 480 -329 500 -500 375 -640 478 -640 361 -480 640 -640 427 -640 480 -640 480 -500 375 -640 428 -640 427 -640 487 -640 480 -480 640 -640 427 -640 427 -640 480 -640 480 -500 333 -640 480 -425 640 -640 480 -640 467 -640 427 -640 427 -640 425 -640 480 -640 480 -640 426 -640 425 -480 640 -375 500 -640 373 -640 425 -500 375 -640 480 -500 423 -480 640 -640 426 -612 612 -640 480 -612 612 -375 500 -640 427 -640 640 -640 480 -500 375 -500 375 -375 500 -500 375 -640 454 -640 360 -478 640 -640 429 -575 640 -640 425 -640 424 -640 428 -562 640 -640 379 -240 320 -640 445 -422 640 -512 640 -640 426 -640 480 -429 640 -640 427 -480 640 -640 427 -640 425 -480 640 -480 640 -640 360 -640 427 -640 427 -640 293 -427 640 -640 427 -500 375 -640 426 -640 480 -455 500 -640 428 -640 301 -640 388 -640 427 -425 640 -500 375 -640 480 -640 480 -640 479 -480 640 -427 640 -640 448 -640 482 -453 640 -640 480 -471 640 -480 640 -640 480 -612 612 -640 426 -480 640 -480 640 -640 480 -640 429 -640 480 -640 393 -480 640 -640 429 -480 640 -427 640 -596 640 -640 428 -640 427 -427 640 -640 426 -333 500 -640 425 -640 428 -640 427 -640 480 -640 427 -640 480 -612 612 -640 480 -426 640 -426 640 -640 457 -500 352 -640 427 -612 612 -500 375 -640 428 -480 640 -640 360 -640 424 -640 427 -640 257 -480 640 -640 425 -640 427 -640 426 -500 333 -480 640 -640 480 -640 598 -640 480 -640 361 -480 640 -500 334 -640 453 -640 480 -640 428 -500 375 -640 243 -640 480 -640 427 -640 429 -500 375 -640 425 -640 427 -480 640 -640 428 -640 484 -640 480 -640 480 -640 480 -640 480 -427 640 -640 259 -493 640 -640 443 -640 427 -640 428 -640 480 -500 320 -640 480 -640 427 -500 243 -640 427 -640 427 -640 480 -640 428 -640 427 -500 375 -478 640 -480 640 -640 427 -640 427 -640 427 -427 640 -640 426 -640 480 -640 426 -640 480 -500 333 -500 375 -628 640 -485 640 -427 640 -451 640 -640 427 -612 612 -500 333 -631 640 -640 457 -480 640 -640 427 -640 427 -640 426 -500 400 -625 417 -375 500 -640 480 -480 640 -640 426 -640 430 -640 425 -640 480 -640 413 -640 512 -500 375 -478 640 -640 425 -640 469 -640 427 -640 480 -480 640 -480 640 -639 640 -640 427 -480 640 -375 500 -640 534 -640 495 -500 325 -640 427 -480 640 -500 375 -640 640 -640 427 -640 429 -640 389 -444 265 -640 480 -612 612 -640 480 -289 640 -480 640 -640 480 -640 435 -640 480 -640 530 -640 424 -640 424 -359 640 -640 427 -427 640 -426 640 -640 483 -640 427 -640 480 -640 429 -640 424 -500 375 -480 640 -640 427 -640 480 -640 480 -480 640 -427 640 -640 480 -640 426 -640 429 -640 480 -640 480 -640 428 -640 424 -640 480 -500 375 -500 375 -500 334 -473 640 -640 439 -640 426 -640 480 -333 500 -640 480 -555 640 -500 375 -640 427 -375 500 -478 500 -640 397 -640 480 -640 425 -640 427 -640 640 -640 425 -640 480 -425 640 -640 480 -640 480 -612 612 -480 640 -640 480 -640 428 -640 480 -640 427 -640 419 -439 640 -640 523 -640 370 -640 480 -435 640 -640 427 -375 500 -640 640 -480 640 -640 425 -375 500 -640 480 -640 480 -640 480 -480 640 -500 375 -640 480 -500 400 -640 480 -484 640 -640 423 -640 480 -640 427 -640 480 -640 481 -480 640 -427 640 -500 375 -640 426 -427 640 -612 612 -640 480 -640 640 -480 640 -480 640 -640 425 -500 392 -640 480 -640 427 -640 360 -640 428 -640 453 -480 640 -612 612 -640 480 -500 332 -640 366 -480 640 -480 640 -500 375 -640 480 -640 427 -480 640 -640 480 -480 640 -500 500 -640 427 -640 640 -640 547 -640 480 -640 480 -640 480 -640 426 -640 640 -640 428 -640 428 -640 499 -640 425 -640 480 -425 640 -500 356 -500 386 -640 351 -640 551 -640 423 -640 392 -640 427 -640 427 -640 425 -419 640 -640 426 -375 500 -612 612 -427 640 -640 426 -426 640 -427 640 -640 414 -640 426 -640 430 -505 640 -640 480 -640 425 -640 522 -640 427 -500 375 -640 480 -480 640 -640 424 -640 577 -640 434 -640 427 -640 428 -640 480 -612 612 -640 423 -500 333 -640 426 -427 640 -500 375 -640 436 -640 480 -640 487 -640 427 -480 640 -640 427 -640 480 -500 375 -640 427 -640 426 -612 612 -500 429 -426 640 -640 480 -640 480 -640 480 -640 428 -640 478 -640 427 -640 478 -428 640 -414 640 -600 402 -640 434 -640 480 -640 480 -640 370 -640 483 -640 480 -640 480 -640 427 -506 640 -500 375 -512 640 -426 640 -640 434 -640 281 -640 480 -640 360 -500 240 -640 386 -453 640 -640 425 -640 427 -359 640 -293 409 -500 375 -427 640 -500 375 -427 640 -424 640 -500 332 -640 360 -640 480 -640 427 -640 443 -640 480 -500 375 -427 640 -640 480 -513 640 -640 480 -640 429 -375 500 -595 640 -500 281 -500 375 -431 640 -480 640 -640 480 -640 533 -427 640 -419 640 -640 426 -640 480 -640 513 -640 440 -640 427 -640 428 -640 480 -500 333 -640 424 -480 640 -612 612 -500 375 -640 480 -640 425 -640 640 -640 640 -342 500 -640 424 -640 426 -640 428 -640 428 -480 640 -640 428 -500 375 -640 640 -640 480 -427 640 -640 426 -375 500 -426 640 -640 480 -640 640 -640 468 -480 640 -640 480 -640 480 -500 375 -640 480 -481 640 -640 480 -640 427 -640 427 -640 640 -640 428 -640 601 -640 443 -500 333 -427 640 -640 480 -612 612 -640 594 -375 500 -427 640 -640 478 -640 480 -640 427 -640 480 -640 428 -428 640 -640 457 -640 480 -375 500 -640 427 -428 640 -640 423 -475 435 -640 425 -640 322 -427 640 -529 640 -478 640 -612 612 -428 640 -640 480 -640 480 -640 480 -640 480 -500 375 -333 500 -480 640 -640 478 -240 320 -640 427 -640 427 -426 640 -453 640 -640 480 -375 500 -640 480 -640 480 -495 640 -427 640 -640 427 -500 375 -640 569 -640 427 -640 426 -640 425 -428 640 -640 427 -428 640 -640 360 -640 427 -612 612 -480 640 -500 354 -640 428 -640 426 -500 488 -640 480 -640 480 -640 480 -480 640 -640 360 -640 480 -500 375 -640 480 -640 424 -640 524 -640 480 -427 640 -640 427 -640 424 -296 640 -640 480 -500 375 -640 425 -500 373 -640 427 -338 640 -432 373 -612 612 -640 446 -640 331 -640 426 -640 480 -640 487 -506 640 -640 480 -640 425 -640 427 -640 497 -427 640 -640 476 -640 426 -640 480 -640 426 -640 426 -640 428 -640 492 -640 480 -480 640 -426 640 -480 640 -640 428 -640 478 -529 640 -640 480 -640 428 -640 480 -640 480 -640 428 -427 640 -640 619 -640 426 -480 640 -640 480 -640 396 -640 424 -640 480 -640 427 -640 427 -640 427 -640 426 -640 426 -478 640 -500 375 -640 480 -640 427 -640 391 -480 640 -640 480 -640 427 -443 640 -612 612 -640 529 -640 480 -640 480 -612 612 -640 480 -640 480 -640 308 -428 640 -640 427 -640 480 -640 480 -426 640 -640 455 -478 640 -375 500 -426 640 -427 640 -640 360 -640 480 -640 425 -640 480 -640 423 -640 427 -640 427 -320 240 -480 640 -640 423 -426 640 -640 520 -323 500 -480 640 -640 426 -612 612 -500 374 -640 427 -640 427 -640 360 -640 425 -640 480 -640 425 -640 426 -640 480 -500 375 -640 484 -426 640 -500 375 -640 480 -640 427 -640 430 -640 577 -428 640 -640 480 -425 640 -640 480 -640 428 -427 640 -640 448 -640 414 -640 480 -612 612 -518 640 -640 640 -640 481 -640 350 -640 480 -640 494 -424 640 -500 384 -424 640 -640 480 -500 216 -640 480 -500 375 -640 476 -640 480 -640 428 -640 480 -500 333 -427 640 -270 360 -640 480 -640 339 -640 426 -480 640 -612 612 -500 375 -500 375 -640 636 -640 480 -640 480 -480 640 -640 351 -640 480 -640 427 -640 480 -640 426 -480 640 -383 640 -640 480 -612 612 -640 428 -640 426 -640 511 -640 480 -640 480 -640 480 -427 640 -481 640 -424 640 -428 640 -640 476 -640 480 -375 500 -640 480 -640 459 -458 640 -640 398 -500 375 -478 640 -500 375 -500 500 -640 439 -640 426 -640 480 -640 427 -500 333 -640 366 -640 480 -640 427 -425 640 -640 640 -640 441 -640 427 -612 612 -566 640 -640 479 -640 427 -612 612 -493 640 -480 640 -500 499 -640 543 -640 427 -640 480 -640 427 -640 426 -335 500 -640 425 -640 420 -427 640 -612 612 -640 425 -640 428 -640 427 -501 640 -427 640 -640 480 -640 428 -640 427 -640 429 -427 640 -500 334 -500 332 -640 480 -640 426 -640 512 -640 491 -640 480 -640 401 -640 480 -640 428 -640 480 -424 640 -640 425 -640 426 -427 640 -640 480 -480 640 -640 640 -428 640 -640 429 -375 500 -640 446 -640 480 -427 640 -640 503 -640 345 -612 612 -640 426 -480 640 -640 374 -640 480 -480 640 -640 425 -640 480 -408 640 -640 427 -640 480 -640 433 -427 640 -564 640 -500 375 -500 333 -640 360 -640 639 -640 480 -500 375 -640 426 -640 425 -640 437 -640 427 -640 480 -640 480 -640 480 -500 375 -640 483 -640 424 -640 436 -500 375 -428 640 -500 375 -480 640 -427 640 -424 640 -640 360 -640 480 -480 640 -480 640 -640 480 -640 285 -500 375 -640 366 -640 429 -640 481 -640 480 -427 640 -640 480 -640 427 -640 424 -640 424 -640 427 -480 640 -604 453 -473 640 -640 480 -500 285 -480 640 -640 418 -640 425 -640 480 -529 640 -534 640 -640 339 -500 375 -640 416 -500 375 -640 480 -640 480 -640 425 -640 480 -640 480 -640 457 -640 424 -500 375 -480 640 -640 427 -500 333 -640 480 -640 480 -640 426 -640 457 -640 428 -640 424 -640 427 -640 421 -500 375 -612 612 -640 427 -640 427 -375 500 -640 435 -640 366 -495 640 -612 612 -512 640 -640 427 -500 375 -640 428 -640 480 -640 479 -500 375 -640 360 -334 500 -500 333 -640 471 -612 612 -640 425 -429 640 -427 640 -640 640 -427 640 -640 427 -640 428 -480 640 -640 428 -640 427 -640 316 -457 640 -320 240 -500 375 -612 612 -640 427 -500 393 -640 480 -640 480 -640 427 -640 480 -640 640 -640 441 -484 500 -640 474 -640 427 -640 427 -640 428 -640 458 -640 360 -468 640 -427 640 -640 425 -640 480 -500 333 -640 427 -640 427 -480 640 -640 480 -640 428 -640 428 -640 428 -640 480 -640 286 -480 640 -640 492 -640 480 -640 480 -640 425 -640 427 -270 360 -457 480 -640 480 -640 480 -500 375 -640 430 -640 480 -640 480 -500 333 -640 426 -500 334 -640 428 -640 427 -589 640 -640 426 -640 299 -427 640 -640 387 -640 427 -426 640 -640 427 -640 480 -640 426 -640 480 -640 406 -511 640 -640 448 -428 640 -500 377 -640 426 -480 640 -375 500 -640 427 -640 427 -640 480 -640 480 -640 427 -640 480 -500 513 -480 640 -427 640 -640 359 -640 395 -480 640 -426 640 -640 427 -359 640 -640 478 -640 406 -640 429 -640 480 -640 426 -640 427 -521 640 -400 400 -640 428 -480 640 -640 480 -640 512 -426 640 -478 640 -433 640 -429 640 -500 375 -640 426 -640 422 -640 480 -400 300 -640 426 -500 500 -640 359 -640 427 -640 478 -640 480 -640 427 -640 427 -500 375 -640 427 -500 375 -500 375 -640 358 -458 640 -480 640 -640 426 -640 480 -640 426 -401 640 -480 640 -640 480 -640 480 -500 375 -640 424 -640 480 -640 520 -640 360 -500 375 -640 427 -426 640 -640 427 -640 281 -500 375 -428 640 -640 426 -640 427 -640 480 -640 426 -640 525 -640 559 -640 458 -640 480 -480 640 -640 535 -640 480 -640 480 -640 493 -640 426 -640 427 -480 640 -375 500 -640 480 -640 480 -640 427 -480 640 -640 576 -640 425 -640 480 -427 640 -640 360 -640 433 -640 478 -426 640 -640 433 -640 406 -640 480 -640 427 -640 480 -640 480 -640 427 -500 375 -323 500 -640 427 -640 472 -375 500 -500 343 -640 483 -640 384 -424 640 -640 425 -424 640 -455 190 -640 427 -500 332 -480 640 -427 640 -640 424 -640 427 -640 480 -334 500 -427 640 -427 640 -426 640 -640 478 -640 425 -640 360 -640 427 -640 640 -640 360 -640 427 -640 427 -375 500 -640 471 -480 640 -640 275 -640 480 -640 480 -640 492 -640 376 -640 480 -640 426 -427 640 -640 480 -640 432 -640 469 -640 480 -640 427 -427 640 -375 500 -640 640 -640 428 -375 500 -596 640 -500 375 -500 330 -640 427 -640 480 -640 400 -480 640 -640 480 -640 480 -640 427 -640 480 -640 480 -337 500 -426 640 -640 425 -640 426 -478 640 -401 640 -640 427 -640 427 -480 640 -640 640 -480 640 -640 426 -640 480 -640 466 -480 640 -640 427 -383 640 -640 480 -640 640 -480 640 -640 480 -500 287 -500 375 -640 480 -640 427 -500 375 -640 478 -640 640 -640 416 -640 480 -640 427 -640 426 -324 500 -640 426 -640 428 -640 427 -640 480 -500 375 -640 480 -640 488 -640 335 -640 480 -612 612 -640 480 -640 314 -640 427 -424 640 -500 375 -640 397 -640 480 -500 375 -480 640 -500 375 -640 427 -640 480 -480 640 -500 263 -500 375 -500 375 -640 425 -640 480 -640 427 -375 500 -480 640 -500 333 -383 640 -640 391 -500 458 -640 427 -640 426 -480 640 -480 640 -640 480 -640 446 -500 375 -500 329 -640 480 -640 480 -612 612 -480 640 -431 640 -640 426 -480 640 -500 375 -640 480 -640 480 -640 426 -500 375 -640 480 -640 427 -500 375 -426 640 -640 480 -640 429 -500 375 -500 375 -640 480 -427 640 -480 640 -480 640 -640 481 -640 480 -500 375 -640 480 -332 500 -500 332 -500 500 -640 427 -640 480 -640 480 -333 500 -640 431 -640 424 -500 393 -640 480 -640 427 -640 480 -500 249 -640 512 -640 480 -640 425 -640 400 -640 427 -640 480 -640 480 -640 480 -640 427 -640 428 -427 640 -640 214 -640 640 -640 480 -500 333 -640 480 -640 439 -640 427 -480 640 -640 480 -640 424 -640 424 -640 480 -640 427 -480 640 -640 431 -640 425 -640 414 -480 640 -640 427 -640 428 -640 427 -640 426 -427 640 -480 640 -640 514 -375 500 -333 500 -640 457 -640 501 -640 427 -333 500 -640 360 -640 480 -425 640 -500 319 -640 361 -640 389 -640 325 -640 480 -500 344 -500 333 -397 640 -640 480 -480 640 -333 500 -640 326 -640 428 -640 477 -480 640 -640 426 -320 240 -640 426 -375 500 -640 400 -640 480 -640 338 -612 612 -640 427 -640 480 -640 640 -640 422 -640 428 -640 426 -640 640 -640 389 -640 425 -640 480 -640 480 -640 346 -480 640 -500 333 -640 428 -545 640 -400 500 -640 427 -640 480 -640 326 -480 640 -640 480 -640 425 -640 427 -640 427 -640 428 -333 500 -512 640 -409 640 -640 426 -640 425 -332 500 -640 480 -640 480 -640 361 -640 426 -640 478 -427 640 -360 270 -640 428 -478 640 -480 640 -640 427 -640 480 -480 640 -500 400 -410 555 -640 480 -333 500 -640 427 -640 480 -500 375 -640 480 -640 480 -428 640 -640 376 -640 480 -640 480 -479 640 -500 333 -640 480 -640 480 -428 640 -640 480 -640 478 -500 333 -640 480 -640 360 -640 426 -410 500 -500 375 -640 479 -480 640 -612 612 -640 425 -640 404 -612 612 -374 640 -500 375 -480 640 -427 640 -500 444 -426 640 -428 640 -640 427 -640 425 -640 479 -500 334 -500 375 -640 480 -640 359 -640 427 -480 640 -500 333 -425 640 -640 439 -640 480 -640 483 -480 640 -640 425 -640 481 -478 640 -427 640 -640 480 -500 333 -500 375 -640 640 -425 640 -500 375 -640 427 -500 333 -640 480 -640 426 -640 480 -640 640 -499 640 -480 640 -640 480 -480 640 -640 480 -640 427 -640 428 -640 548 -640 640 -500 375 -640 480 -640 426 -640 427 -500 169 -640 360 -640 480 -640 457 -480 640 -640 582 -640 480 -500 281 -640 425 -500 375 -640 480 -640 480 -640 480 -640 480 -640 480 -640 360 -333 500 -640 480 -457 640 -640 427 -640 407 -640 480 -640 480 -500 375 -500 329 -369 500 -640 480 -640 427 -426 640 -640 496 -640 427 -640 480 -475 405 -640 629 -640 426 -500 375 -640 427 -640 480 -640 335 -640 428 -640 512 -640 425 -612 612 -640 480 -640 480 -500 409 -640 412 -612 612 -640 427 -433 640 -640 427 -640 480 -640 474 -640 581 -500 482 -427 640 -640 427 -640 428 -379 500 -640 480 -482 500 -640 480 -640 480 -640 427 -500 323 -500 375 -426 640 -428 640 -640 480 -640 360 -640 427 -640 480 -640 480 -500 333 -640 640 -640 427 -640 480 -480 640 -640 427 -640 640 -640 417 -640 428 -640 429 -500 375 -500 375 -500 236 -428 640 -640 427 -500 375 -480 640 -640 427 -640 480 -640 480 -640 423 -640 427 -640 480 -640 424 -500 375 -426 640 -640 258 -640 516 -640 480 -640 480 -640 427 -640 480 -640 428 -500 375 -640 480 -640 480 -612 612 -640 426 -640 427 -640 286 -640 359 -500 375 -640 486 -480 640 -640 480 -640 402 -640 480 -427 640 -640 480 -640 486 -612 612 -640 480 -500 281 -333 500 -640 426 -640 480 -393 480 -333 500 -500 375 -640 480 -640 426 -640 411 -640 425 -640 426 -640 480 -640 480 -640 427 -400 500 -500 375 -640 429 -415 640 -640 480 -640 512 -640 425 -500 333 -500 263 -640 427 -480 640 -500 400 -640 611 -427 640 -640 480 -426 640 -375 500 -603 640 -428 640 -640 494 -640 480 -640 320 -640 480 -640 430 -500 333 -640 439 -640 480 -500 374 -640 426 -640 480 -500 250 -640 421 -640 480 -640 426 -480 640 -480 640 -640 455 -500 375 -640 640 -640 427 -375 500 -410 640 -334 500 -640 427 -640 480 -640 360 -480 640 -640 480 -480 640 -640 427 -640 480 -640 426 -500 375 -640 427 -640 426 -640 427 -459 258 -482 640 -640 480 -500 375 -640 480 -640 480 -427 640 -500 375 -640 360 -449 640 -480 640 -640 427 -640 428 -640 480 -640 480 -427 640 -640 427 -640 427 -640 453 -640 480 -480 640 -640 427 -640 427 -640 428 -640 464 -375 500 -480 640 -640 479 -640 473 -500 305 -480 640 -640 478 -640 480 -640 480 -640 480 -640 427 -640 426 -640 478 -426 640 -480 640 -500 333 -640 425 -640 468 -480 640 -333 500 -426 640 -640 478 -640 480 -640 427 -640 428 -640 480 -500 375 -640 429 -640 426 -576 640 -500 333 -640 419 -480 640 -640 480 -478 640 -640 396 -334 500 -640 480 -427 640 -467 640 -500 375 -640 427 -295 244 -640 640 -640 401 -427 640 -480 640 -640 478 -640 438 -640 427 -640 480 -640 448 -640 480 -640 426 -640 480 -500 375 -500 400 -500 332 -640 427 -640 427 -500 350 -640 412 -640 480 -640 524 -500 375 -500 333 -424 640 -640 480 -640 427 -640 480 -640 480 -480 640 -640 457 -426 640 -480 640 -640 480 -283 424 -426 640 -336 640 -640 480 -640 427 -500 342 -640 480 -640 480 -640 427 -640 606 -640 480 -640 478 -480 640 -427 640 -640 480 -640 360 -640 480 -640 427 -640 480 -640 426 -500 332 -375 500 -640 478 -427 640 -640 480 -640 480 -427 640 -640 461 -640 428 -640 429 -500 333 -481 640 -640 426 -640 408 -640 640 -480 640 -640 427 -640 480 -640 480 -640 481 -640 480 -500 375 -480 640 -640 427 -640 427 -640 427 -640 427 -500 375 -640 468 -640 480 -640 426 -640 548 -500 375 -640 425 -640 480 -640 480 -640 427 -640 426 -640 427 -567 640 -640 427 -640 457 -640 427 -600 354 -640 411 -640 620 -640 480 -640 480 -640 424 -469 640 -640 429 -640 480 -426 640 -359 640 -500 312 -640 480 -640 480 -640 427 -640 467 -640 586 -428 640 -640 427 -500 375 -427 640 -500 375 -500 375 -640 359 -640 493 -640 427 -500 375 -640 427 -298 500 -640 427 -640 541 -497 640 -375 500 -640 605 -640 451 -375 500 -500 375 -480 640 -640 480 -640 428 -640 480 -425 640 -640 478 -640 480 -640 483 -458 640 -640 541 -500 332 -500 281 -480 640 -426 640 -640 480 -427 640 -640 480 -640 427 -640 428 -640 480 -640 426 -480 640 -640 334 -640 400 -640 480 -640 426 -375 500 -640 480 -640 427 -640 428 -640 427 -640 480 -480 640 -640 640 -480 640 -480 640 -500 375 -640 480 -612 612 -640 480 -640 426 -512 640 -500 375 -427 640 -640 476 -640 480 -640 511 -640 360 -640 425 -640 480 -480 640 -640 448 -500 375 -640 480 -640 427 -640 425 -428 640 -640 640 -640 428 -521 421 -640 480 -640 640 -427 640 -500 400 -640 427 -500 375 -640 427 -640 457 -640 359 -640 430 -640 480 -500 375 -640 480 -640 427 -640 480 -640 425 -500 375 -528 640 -313 500 -600 400 -640 609 -640 480 -640 404 -640 480 -640 480 -640 424 -640 480 -640 427 -640 401 -500 375 -640 480 -490 640 -612 612 -640 427 -640 640 -640 480 -640 425 -480 640 -631 640 -500 333 -602 415 -640 512 -640 427 -640 480 -640 426 -640 480 -480 640 -640 480 -640 427 -640 403 -640 453 -640 480 -640 427 -640 480 -640 426 -426 640 -612 612 -640 480 -640 480 -640 480 -500 333 -640 640 -639 640 -612 612 -640 464 -640 480 -500 375 -405 500 -640 427 -640 512 -640 427 -480 640 -640 458 -640 428 -640 415 -480 640 -640 480 -427 640 -640 480 -430 500 -500 375 -640 480 -500 376 -640 304 -480 640 -500 375 -640 426 -640 480 -640 425 -480 640 -640 427 -428 640 -500 375 -500 500 -640 480 -640 419 -484 640 -640 480 -640 427 -640 480 -640 427 -640 480 -640 429 -500 319 -427 640 -500 375 -640 480 -358 640 -480 640 -500 375 -427 640 -640 359 -500 333 -448 299 -640 424 -612 612 -612 612 -640 426 -425 640 -344 500 -640 326 -640 513 -640 425 -640 640 -640 480 -640 427 -480 640 -500 336 -640 427 -640 480 -640 480 -640 427 -375 500 -640 429 -375 500 -513 640 -640 544 -640 480 -640 480 -640 432 -480 640 -333 500 -640 383 -500 375 -426 640 -640 480 -640 540 -640 480 -392 500 -480 640 -640 404 -640 640 -427 640 -640 480 -640 411 -640 499 -640 480 -640 480 -640 480 -640 427 -397 500 -427 640 -640 314 -500 360 -480 640 -640 409 -640 480 -640 480 -500 333 -478 640 -500 332 -640 427 -640 396 -640 480 -640 427 -640 427 -640 480 -428 640 -500 375 -640 428 -375 500 -640 504 -640 424 -629 640 -427 640 -500 375 -600 400 -640 425 -640 480 -426 640 -640 406 -640 480 -640 480 -640 480 -640 335 -480 640 -427 640 -500 375 -640 459 -612 612 -500 375 -480 640 -480 640 -640 480 -640 400 -429 640 -640 428 -640 480 -640 432 -640 426 -528 640 -640 426 -500 375 -640 480 -640 430 -640 478 -640 480 -640 427 -640 480 -426 640 -500 375 -640 488 -640 427 -640 407 -425 640 -640 549 -500 375 -612 612 -640 444 -640 426 -640 480 -494 327 -640 428 -640 449 -500 397 -640 479 -640 480 -640 431 -640 360 -509 640 -640 480 -640 480 -512 640 -640 426 -640 509 -612 612 -640 427 -425 640 -640 480 -427 640 -640 480 -640 511 -640 480 -640 480 -640 425 -500 310 -640 480 -612 612 -500 335 -640 480 -640 480 -480 640 -640 480 -500 333 -427 640 -640 480 -459 500 -640 480 -640 480 -640 427 -640 427 -500 375 -640 425 -428 640 -640 639 -500 325 -640 427 -640 506 -640 458 -469 640 -640 484 -500 375 -375 500 -427 640 -425 640 -338 500 -640 427 -480 640 -640 574 -640 480 -640 480 -640 480 -640 426 -640 425 -640 427 -612 612 -480 640 -427 640 -640 480 -640 427 -400 600 -640 427 -640 640 -612 612 -640 427 -480 640 -640 480 -640 480 -640 480 -375 500 -500 338 -426 640 -500 375 -500 333 -640 427 -640 480 -640 427 -640 255 -640 480 -640 401 -640 513 -640 427 -640 640 -375 500 -640 429 -640 425 -500 333 -640 424 -640 480 -640 480 -640 480 -480 640 -375 500 -640 480 -500 333 -500 375 -375 500 -480 640 -640 480 -640 478 -480 640 -640 427 -480 640 -640 480 -640 427 -427 640 -427 640 -640 480 -427 640 -640 427 -500 375 -640 480 -480 640 -640 427 -500 400 -500 333 -640 426 -471 640 -640 480 -640 427 -480 640 -433 640 -590 640 -640 427 -494 500 -328 640 -640 480 -512 400 -612 612 -480 640 -480 640 -640 425 -640 480 -640 480 -425 640 -640 427 -640 424 -640 426 -640 514 -425 640 -640 479 -508 640 -500 333 -640 433 -640 425 -640 480 -640 360 -480 640 -640 429 -640 480 -640 426 -426 640 -640 480 -640 426 -640 480 -427 640 -640 455 -640 480 -500 400 -640 427 -640 480 -640 480 -500 375 -640 554 -334 500 -640 360 -426 640 -500 470 -640 427 -640 480 -480 640 -640 427 -500 334 -427 640 -640 383 -640 426 -640 480 -480 640 -437 640 -640 425 -640 480 -640 480 -640 427 -640 427 -640 480 -612 612 -640 360 -425 640 -426 640 -640 241 -640 480 -640 640 -427 640 -612 612 -640 429 -500 375 -500 375 -500 324 -640 456 -640 427 -640 424 -640 480 -375 500 -640 427 -640 480 -480 640 -640 572 -640 480 -480 640 -640 427 -640 427 -640 427 -640 480 -500 375 -640 480 -375 500 -640 426 -640 426 -375 500 -640 480 -640 401 -640 458 -481 640 -640 480 -640 640 -640 480 -640 480 -640 502 -427 640 -428 640 -427 640 -427 640 -640 427 -359 640 -640 425 -640 427 -457 640 -640 436 -640 434 -640 480 -335 500 -497 500 -425 640 -480 640 -425 640 -640 480 -640 425 -640 311 -640 426 -640 428 -640 640 -640 425 -640 427 -640 480 -640 388 -640 426 -640 481 -640 398 -640 427 -640 427 -640 480 -640 640 -640 428 -640 463 -640 425 -427 640 -500 500 -640 368 -500 331 -500 375 -640 426 -385 500 -500 358 -640 480 -640 480 -640 480 -480 640 -640 427 -500 304 -640 427 -500 333 -640 457 -500 500 -640 360 -432 640 -640 576 -640 480 -640 401 -640 480 -640 360 -640 480 -640 498 -500 333 -640 480 -640 480 -640 427 -640 487 -480 640 -640 428 -359 640 -640 432 -640 480 -640 427 -480 640 -640 480 -640 426 -640 480 -500 333 -476 640 -640 480 -640 424 -427 640 -640 285 -427 640 -472 640 -500 312 -480 640 -640 478 -640 480 -640 480 -640 481 -612 612 -640 480 -612 612 -640 478 -640 480 -360 640 -640 427 -640 427 -640 480 -361 500 -640 428 -640 426 -333 250 -640 640 -458 640 -640 480 -640 427 -640 478 -640 480 -640 427 -640 426 -640 427 -640 480 -640 426 -451 500 -640 512 -640 428 -640 480 -612 612 -480 640 -640 471 -640 428 -500 375 -640 480 -506 640 -640 479 -427 640 -500 375 -640 427 -640 509 -640 480 -612 612 -640 427 -640 480 -640 392 -500 375 -640 640 -640 480 -500 378 -500 375 -500 375 -427 640 -640 427 -640 480 -640 446 -640 504 -640 480 -640 480 -478 640 -640 429 -640 424 -640 439 -640 480 -640 480 -640 427 -640 631 -427 640 -480 640 -640 480 -425 640 -640 426 -640 360 -640 424 -469 640 -640 426 -640 427 -640 425 -500 375 -500 373 -640 405 -640 481 -480 640 -640 480 -500 284 -640 480 -640 427 -640 480 -640 480 -480 640 -640 427 -426 640 -480 640 -640 480 -640 480 -427 640 -640 427 -640 523 -640 427 -640 480 -640 512 -640 427 -500 375 -640 480 -640 427 -480 640 -640 434 -640 399 -500 333 -640 480 -640 426 -640 480 -640 474 -640 493 -640 480 -568 640 -500 334 -640 480 -640 480 -640 459 -500 400 -640 480 -500 333 -640 430 -640 427 -640 478 -640 480 -640 433 -481 640 -640 367 -640 427 -612 612 -500 374 -640 480 -375 500 -550 365 -640 429 -500 333 -480 640 -640 640 -640 480 -640 480 -640 427 -640 480 -383 640 -640 427 -640 301 -427 640 -640 427 -640 425 -300 400 -480 640 -500 333 -518 640 -420 640 -480 640 -428 640 -333 500 -640 360 -500 333 -480 640 -471 640 -640 427 -640 480 -480 640 -640 480 -640 425 -640 480 -640 480 -640 425 -480 640 -640 474 -500 335 -640 480 -640 480 -640 360 -500 375 -640 478 -640 398 -500 375 -640 480 -640 428 -500 375 -500 375 -466 640 -458 640 -640 480 -640 477 -640 489 -375 500 -640 640 -480 640 -612 612 -640 480 -640 427 -640 350 -500 375 -640 480 -298 640 -480 640 -640 427 -480 640 -640 426 -640 480 -640 480 -640 480 -640 480 -640 427 -500 375 -478 640 -640 425 -640 472 -640 409 -375 500 -480 640 -640 425 -400 600 -640 480 -640 480 -480 640 -640 361 -426 640 -427 640 -447 640 -425 640 -640 426 -500 375 -640 427 -640 483 -480 640 -640 480 -640 480 -427 640 -640 480 -640 640 -640 427 -640 480 -640 427 -640 353 -640 640 -640 480 -374 500 -640 426 -384 640 -640 480 -480 640 -375 500 -375 500 -500 375 -640 480 -640 480 -640 428 -640 480 -640 429 -640 457 -640 424 -480 640 -640 480 -480 640 -640 626 -640 427 -640 480 -640 480 -458 640 -480 640 -500 398 -640 428 -640 425 -640 429 -640 427 -427 640 -512 640 -640 640 -640 426 -640 478 -458 640 -640 480 -640 480 -426 640 -640 480 -640 480 -500 281 -640 640 -640 427 -478 640 -640 426 -640 426 -640 458 -640 427 -500 356 -640 429 -473 640 -640 526 -640 480 -500 377 -640 426 -640 480 -640 480 -640 304 -640 480 -640 426 -640 427 -640 434 -426 640 -640 480 -480 640 -640 480 -640 428 -640 480 -500 382 -500 333 -375 500 -640 427 -640 427 -640 427 -640 480 -640 426 -480 640 -640 361 -640 474 -473 640 -427 640 -500 332 -640 427 -640 424 -640 480 -640 480 -343 500 -425 640 -640 480 -500 375 -640 427 -640 427 -500 373 -640 427 -427 640 -640 480 -508 640 -640 480 -640 480 -500 375 -640 426 -640 640 -640 400 -480 640 -547 640 -640 426 -640 427 -517 640 -375 500 -640 426 -640 325 -640 480 -640 426 -640 427 -640 558 -640 640 -640 520 -640 480 -640 480 -640 427 -640 401 -640 426 -640 412 -640 427 -640 425 -640 427 -500 375 -426 640 -491 640 -480 640 -640 428 -480 640 -640 480 -640 294 -480 640 -640 502 -640 427 -640 427 -640 640 -425 640 -640 480 -640 495 -640 426 -416 640 -640 426 -640 427 -640 359 -640 425 -427 640 -640 480 -640 427 -427 640 -612 612 -640 428 -640 361 -640 480 -640 427 -480 640 -640 426 -640 480 -478 640 -640 480 -426 640 -640 480 -640 482 -640 428 -361 640 -427 640 -640 480 -375 500 -640 427 -640 427 -500 329 -480 640 -555 640 -500 400 -516 520 -640 480 -640 427 -640 426 -480 640 -427 640 -640 428 -640 620 -500 375 -640 480 -480 640 -480 640 -427 640 -480 640 -500 375 -640 480 -640 427 -640 480 -480 640 -612 612 -640 480 -427 640 -426 640 -427 640 -426 640 -640 427 -640 450 -480 640 -640 426 -640 426 -597 640 -640 439 -375 500 -640 360 -500 393 -424 640 -640 427 -640 427 -513 640 -424 640 -480 640 -640 427 -640 427 -640 480 -333 500 -640 360 -640 480 -640 480 -640 480 -640 480 -640 427 -640 480 -640 480 -640 425 -640 453 -480 640 -640 426 -640 480 -640 426 -640 481 -480 640 -640 427 -480 640 -640 480 -640 480 -640 480 -457 640 -640 404 -512 640 -640 360 -640 480 -480 640 -640 427 -426 640 -640 513 -640 479 -640 427 -640 480 -640 480 -480 640 -500 391 -640 424 -375 500 -459 640 -640 547 -500 334 -640 359 -480 640 -640 427 -640 425 -626 640 -640 427 -640 423 -640 464 -612 612 -640 425 -640 480 -640 426 -640 480 -500 375 -480 640 -640 480 -640 560 -640 427 -640 422 -612 612 -612 612 -480 640 -625 640 -640 480 -612 612 -640 480 -480 640 -427 640 -333 500 -640 427 -404 640 -640 480 -375 500 -438 640 -500 375 -500 336 -640 427 -640 456 -640 427 -640 426 -640 480 -640 427 -427 640 -640 480 -480 640 -640 428 -425 640 -500 375 -640 481 -640 427 -640 427 -640 195 -500 375 -480 640 -640 425 -640 480 -640 426 -427 640 -514 640 -640 427 -640 480 -640 427 -640 425 -640 427 -500 375 -639 426 -640 504 -640 480 -427 640 -500 375 -640 463 -480 640 -640 427 -640 428 -427 640 -640 480 -500 333 -640 480 -640 480 -500 375 -640 480 -640 426 -640 426 -640 427 -640 480 -640 426 -640 427 -409 640 -640 468 -640 428 -500 332 -640 480 -640 489 -640 480 -640 363 -640 427 -640 478 -640 480 -640 360 -375 500 -640 529 -427 640 -640 427 -640 426 -427 640 -640 480 -640 478 -640 428 -640 480 -640 426 -640 427 -640 480 -396 640 -640 471 -428 640 -600 400 -500 375 -640 480 -640 425 -424 640 -480 640 -640 426 -425 640 -480 640 -500 375 -480 640 -512 640 -640 428 -480 640 -640 426 -640 480 -640 640 -640 499 -640 400 -640 427 -640 427 -500 375 -640 427 -640 480 -640 480 -640 426 -640 480 -500 375 -640 623 -494 640 -640 403 -426 640 -425 640 -640 428 -640 480 -640 427 -640 430 -640 640 -640 480 -480 640 -640 426 -640 514 -428 640 -272 480 -640 428 -640 454 -504 314 -338 500 -500 375 -640 480 -500 375 -640 426 -640 298 -640 480 -500 322 -500 333 -640 436 -640 480 -500 375 -500 375 -612 612 -640 427 -640 433 -428 640 -427 640 -500 333 -640 409 -640 480 -640 480 -480 640 -640 428 -640 427 -480 640 -427 640 -640 429 -636 640 -640 427 -640 428 -640 640 -640 400 -640 480 -640 480 -640 517 -480 640 -640 480 -533 640 -480 640 -640 199 -426 640 -640 480 -640 608 -640 424 -640 371 -480 640 -640 427 -640 368 -500 375 -640 427 -500 334 -640 480 -640 480 -640 480 -640 389 -640 480 -640 480 -640 478 -640 426 -640 480 -640 480 -640 480 -480 640 -500 332 -640 515 -480 640 -640 435 -480 640 -640 426 -375 500 -480 640 -640 480 -425 640 -480 640 -640 480 -640 419 -640 425 -640 480 -480 640 -640 480 -500 333 -476 640 -500 400 -512 640 -640 338 -640 360 -480 640 -640 427 -480 640 -640 427 -640 480 -480 640 -640 480 -640 427 -612 612 -640 478 -427 640 -640 427 -640 426 -640 480 -640 426 -640 508 -640 427 -640 427 -640 480 -640 480 -640 428 -640 426 -480 640 -500 375 -427 640 -640 371 -425 640 -640 427 -640 427 -640 480 -480 640 -613 640 -640 480 -640 480 -500 375 -640 424 -427 640 -640 480 -640 480 -640 480 -640 640 -640 480 -640 479 -640 427 -331 500 -640 359 -640 494 -640 480 -640 640 -640 427 -500 375 -640 480 -640 640 -640 429 -458 640 -640 425 -640 640 -640 465 -640 480 -488 640 -640 480 -640 480 -640 394 -426 640 -640 426 -423 640 -640 480 -427 640 -640 433 -335 500 -640 480 -640 396 -640 373 -640 427 -640 480 -640 426 -640 486 -425 640 -640 428 -500 285 -480 640 -640 480 -640 480 -428 640 -427 640 -640 426 -640 480 -640 389 -500 375 -375 500 -640 426 -480 640 -640 480 -640 474 -480 640 -640 427 -480 640 -640 480 -449 640 -640 432 -640 427 -640 480 -640 468 -427 640 -640 427 -640 458 -640 427 -640 427 -383 640 -640 640 -640 373 -640 427 -640 480 -640 486 -640 480 -480 640 -640 480 -640 480 -640 426 -480 640 -640 427 -640 480 -640 425 -640 480 -500 251 -640 480 -416 640 -640 480 -640 480 -640 640 -640 428 -425 640 -640 480 -640 480 -640 427 -640 480 -640 427 -640 429 -640 426 -640 640 -427 640 -640 427 -640 427 -640 427 -414 640 -500 375 -640 416 -500 332 -640 393 -640 360 -640 480 -500 333 -640 425 -640 427 -640 426 -640 427 -500 375 -640 360 -500 333 -424 640 -640 427 -478 640 -478 640 -429 640 -480 640 -640 425 -500 375 -640 365 -640 480 -480 640 -375 500 -640 426 -640 480 -640 480 -640 427 -640 480 -640 425 -640 480 -640 427 -640 427 -640 480 -640 427 -640 427 -640 480 -640 448 -500 375 -426 640 -480 640 -428 640 -612 612 -640 421 -500 333 -640 491 -640 480 -640 360 -640 397 -640 426 -478 640 -480 640 -640 424 -640 427 -640 427 -640 480 -640 427 -640 427 -640 426 -640 426 -640 426 -640 480 -640 427 -640 480 -640 480 -332 500 -640 428 -480 640 -428 640 -427 640 -640 351 -508 640 -640 427 -640 480 -500 375 -640 480 -640 480 -640 425 -640 420 -640 480 -500 375 -640 480 -640 425 -418 500 -500 375 -640 474 -640 425 -640 427 -640 480 -336 640 -640 427 -640 478 -640 425 -640 503 -333 500 -640 427 -640 480 -640 480 -612 612 -480 640 -640 404 -640 427 -640 503 -640 360 -640 427 -640 480 -640 381 -640 339 -428 640 -427 640 -640 425 -640 480 -640 480 -640 427 -426 640 -640 409 -640 427 -640 519 -360 640 -375 500 -640 427 -640 427 -640 427 -640 508 -640 428 -640 423 -640 427 -640 386 -500 333 -640 366 -480 640 -640 480 -640 427 -640 427 -640 427 -640 509 -500 375 -500 375 -640 418 -375 500 -640 353 -640 426 -640 427 -640 480 -612 612 -640 480 -640 478 -526 640 -387 500 -640 480 -640 427 -640 427 -640 480 -640 427 -640 425 -640 480 -500 376 -640 480 -640 480 -500 316 -640 427 -640 480 -640 480 -427 640 -640 427 -480 640 -640 427 -612 612 -480 640 -640 640 -334 500 -427 640 -500 335 -640 428 -640 426 -640 478 -480 640 -426 640 -640 426 -640 426 -500 334 -640 480 -640 443 -500 375 -640 480 -640 427 -640 479 -640 424 -640 480 -427 640 -640 428 -640 480 -640 480 -640 480 -640 424 -500 281 -640 480 -640 426 -426 640 -500 332 -640 480 -640 424 -480 640 -640 360 -334 500 -333 500 -640 427 -640 480 -640 427 -640 427 -480 640 -640 297 -500 487 -427 640 -640 426 -480 640 -640 480 -554 312 -640 454 -640 361 -640 516 -480 640 -640 640 -500 350 -640 640 -640 425 -640 640 -480 640 -640 480 -640 640 -640 426 -640 480 -640 587 -640 425 -640 480 -427 640 -640 529 -640 429 -640 480 -640 428 -640 427 -640 480 -640 480 -500 339 -500 375 -500 375 -640 427 -640 480 -640 444 -500 335 -640 512 -640 426 -640 480 -500 375 -640 480 -480 640 -640 480 -612 612 -375 500 -480 640 -640 599 -640 480 -640 480 -500 375 -500 332 -640 382 -640 480 -640 480 -427 640 -500 471 -640 426 -640 480 -426 640 -640 427 -640 480 -640 480 -640 427 -640 427 -640 417 -413 622 -480 640 -428 640 -640 426 -640 366 -425 640 -500 375 -500 345 -640 373 -489 500 -640 389 -478 640 -640 494 -427 640 -640 426 -640 480 -444 640 -640 427 -640 426 -427 640 -384 640 -640 426 -459 640 -640 479 -640 572 -640 480 -640 480 -468 640 -640 431 -425 640 -640 428 -640 428 -480 500 -640 427 -427 640 -426 640 -640 427 -429 640 -640 428 -480 640 -640 427 -640 425 -500 375 -401 640 -640 425 -500 331 -640 480 -640 512 -640 361 -640 428 -640 427 -500 375 -427 640 -640 427 -640 480 -480 640 -427 640 -640 425 -640 361 -640 424 -427 640 -640 479 -640 427 -640 425 -640 427 -640 360 -640 424 -640 544 -640 427 -375 500 -640 480 -640 480 -500 375 -640 425 -640 426 -375 500 -640 454 -640 428 -640 360 -480 640 -640 480 -435 640 -500 375 -640 640 -640 479 -640 480 -640 379 -640 480 -478 640 -500 282 -640 480 -640 480 -640 480 -640 427 -640 480 -640 425 -426 640 -513 640 -640 431 -640 425 -640 480 -511 640 -640 429 -640 480 -500 375 -640 480 -640 394 -640 427 -425 640 -640 430 -640 480 -640 425 -640 480 -640 480 -640 457 -640 480 -333 500 -640 480 -640 427 -640 425 -640 428 -379 500 -640 480 -640 484 -427 640 -640 427 -640 418 -640 428 -640 482 -640 483 -500 283 -640 476 -640 480 -144 144 -640 360 -640 480 -480 640 -640 360 -480 640 -640 480 -640 480 -640 426 -426 640 -426 640 -640 480 -640 480 -640 604 -640 445 -640 480 -640 480 -640 313 -640 331 -640 375 -640 480 -612 612 -505 640 -424 640 -640 361 -640 421 -640 400 -640 480 -640 454 -640 427 -500 375 -506 640 -426 640 -500 375 -480 640 -479 322 -640 424 -480 640 -480 640 -640 349 -639 426 -427 640 -500 333 -640 480 -424 640 -425 640 -640 480 -593 391 -640 427 -640 508 -480 640 -640 400 -640 428 -640 360 -640 427 -640 428 -640 480 -640 426 -640 506 -500 357 -640 480 -640 480 -640 428 -640 427 -640 424 -640 428 -640 427 -640 422 -640 480 -640 480 -500 375 -640 425 -640 480 -640 480 -640 537 -640 427 -640 428 -640 428 -640 480 -318 500 -640 480 -480 640 -500 333 -640 427 -500 375 -640 480 -480 640 -500 333 -640 480 -640 427 -640 427 -500 375 -640 426 -640 426 -640 427 -500 348 -640 427 -640 426 -640 546 -640 427 -640 427 -640 480 -640 425 -500 407 -500 300 -640 512 -480 640 -640 480 -500 281 -640 435 -640 426 -640 427 -640 478 -640 383 -375 500 -640 480 -640 424 -480 640 -640 427 -640 480 -640 480 -640 473 -640 475 -600 450 -450 265 -500 457 -341 640 -640 480 -640 425 -640 427 -375 500 -480 640 -543 640 -640 480 -457 640 -640 480 -640 490 -640 478 -427 640 -640 554 -427 640 -427 640 -640 480 -640 454 -640 427 -500 283 -640 480 -640 415 -640 480 -640 486 -640 425 -640 427 -333 500 -473 640 -640 480 -480 640 -640 478 -480 640 -427 640 -640 480 -612 612 -640 480 -500 325 -640 421 -640 480 -640 427 -640 480 -640 427 -640 281 -359 640 -458 640 -640 518 -640 360 -612 612 -640 480 -640 480 -640 480 -640 449 -640 480 -640 480 -640 480 -426 640 -640 427 -500 375 -640 427 -640 426 -640 599 -640 480 -495 640 -640 480 -500 281 -480 640 -427 640 -640 427 -640 427 -640 359 -640 429 -640 480 -640 426 -480 640 -640 430 -640 478 -480 640 -482 640 -640 426 -500 375 -640 319 -500 375 -500 375 -640 480 -500 333 -640 427 -640 480 -640 480 -640 480 -640 480 -612 612 -640 480 -640 360 -640 425 -426 640 -640 480 -640 480 -429 640 -333 500 -640 427 -640 425 -640 480 -640 427 -640 427 -640 480 -640 424 -640 480 -500 341 -500 334 -640 480 -640 480 -640 426 -375 500 -640 427 -500 333 -640 480 -640 480 -338 500 -334 500 -640 427 -456 640 -500 375 -640 426 -426 640 -640 480 -480 640 -480 640 -500 332 -640 426 -640 427 -426 640 -480 640 -640 429 -640 480 -640 384 -640 427 -359 500 -640 384 -500 375 -444 295 -427 640 -640 429 -427 640 -500 374 -480 640 -423 640 -500 375 -640 480 -640 480 -640 360 -640 640 -640 449 -640 427 -640 480 -640 480 -640 360 -640 484 -640 480 -640 480 -640 428 -500 375 -511 640 -372 500 -640 480 -500 333 -640 427 -612 612 -640 400 -640 427 -426 640 -480 640 -640 480 -500 333 -640 427 -640 480 -640 421 -640 480 -425 640 -427 640 -640 428 -640 428 -640 480 -493 500 -640 427 -640 427 -640 480 -640 480 -640 480 -640 538 -640 427 -640 427 -640 478 -640 480 -640 480 -500 357 -640 480 -640 425 -640 426 -640 480 -500 375 -640 404 -375 500 -640 640 -640 426 -640 480 -480 640 -480 640 -640 426 -427 640 -640 480 -480 640 -423 640 -612 612 -640 446 -640 423 -640 480 -476 640 -640 511 -640 427 -640 480 -640 480 -640 480 -480 640 -640 480 -640 566 -427 640 -640 518 -640 427 -426 640 -480 640 -612 612 -480 640 -640 426 -480 640 -520 640 -333 500 -427 640 -640 431 -640 480 -640 427 -640 426 -500 375 -640 480 -640 428 -425 640 -640 427 -640 480 -640 427 -640 569 -640 480 -640 427 -500 334 -500 338 -640 428 -640 481 -640 428 -640 427 -640 427 -640 424 -640 427 -333 500 -640 555 -640 428 -640 427 -640 496 -640 427 -640 480 -640 427 -640 480 -480 640 -640 480 -349 500 -640 480 -640 425 -640 429 -640 480 -612 612 -375 500 -640 410 -640 480 -612 612 -500 375 -640 425 -640 427 -500 375 -500 375 -450 300 -640 480 -640 427 -480 640 -499 500 -480 640 -640 425 -640 379 -640 427 -640 640 -640 426 -480 640 -500 375 -640 480 -480 640 -640 480 -640 457 -612 612 -480 640 -640 415 -640 480 -476 640 -640 427 -333 500 -500 333 -640 480 -640 480 -612 612 -640 426 -513 640 -333 500 -375 500 -640 480 -640 415 -640 424 -529 640 -640 480 -500 375 -640 360 -640 427 -640 428 -640 480 -640 480 -640 480 -640 480 -640 480 -640 480 -640 360 -383 640 -640 383 -640 419 -500 334 -640 457 -480 640 -400 300 -640 425 -640 480 -640 428 -500 375 -640 427 -640 480 -640 429 -640 425 -640 480 -640 480 -500 333 -500 365 -500 281 -334 500 -640 427 -428 640 -640 426 -640 427 -500 375 -640 426 -640 437 -640 484 -640 426 -640 427 -375 500 -375 500 -429 640 -640 480 -640 428 -640 480 -640 480 -374 500 -640 427 -640 480 -640 428 -587 391 -640 480 -640 480 -640 480 -640 428 -640 360 -500 375 -640 394 -375 500 -640 427 -500 374 -427 640 -640 424 -640 603 -640 480 -640 427 -640 480 -640 462 -500 375 -640 427 -500 356 -640 480 -640 425 -513 640 -640 427 -640 480 -640 478 -480 640 -640 436 -640 427 -640 480 -640 479 -640 480 -640 427 -640 480 -640 428 -640 360 -427 640 -480 640 -512 640 -640 480 -640 480 -640 422 -640 428 -413 640 -640 399 -640 426 -640 428 -333 500 -427 640 -427 640 -640 426 -434 640 -640 409 -640 480 -640 427 -333 500 -640 437 -640 512 -480 640 -480 640 -640 468 -640 427 -500 331 -480 640 -640 480 -640 478 -377 500 -333 500 -480 640 -428 640 -640 480 -640 237 -640 426 -640 480 -640 494 -640 426 -640 360 -640 360 -426 640 -601 601 -500 375 -480 640 -640 480 -446 640 -500 375 -640 480 -640 426 -640 427 -640 427 -500 375 -640 425 -640 427 -479 640 -612 612 -640 427 -640 427 -500 368 -640 313 -500 386 -640 523 -612 612 -480 640 -480 640 -640 453 -640 480 -640 480 -428 640 -480 640 -640 159 -640 426 -640 451 -640 427 -640 480 -426 640 -480 640 -500 333 -426 640 -640 427 -500 333 -427 640 -480 640 -640 427 -480 640 -457 640 -640 425 -640 427 -500 338 -640 480 -427 640 -612 612 -500 334 -640 451 -640 621 -640 461 -500 375 -640 480 -640 425 -640 428 -640 360 -640 519 -640 458 -640 416 -500 375 -500 375 -640 480 -640 425 -640 480 -612 612 -640 480 -428 640 -640 528 -640 427 -640 480 -640 480 -640 456 -640 480 -500 375 -640 427 -640 479 -612 612 -640 360 -500 375 -640 480 -640 480 -640 480 -640 480 -500 375 -640 480 -640 427 -640 480 -500 375 -600 600 -640 359 -640 426 -640 427 -640 456 -500 375 -443 640 -399 500 -640 498 -640 426 -375 500 -640 480 -426 640 -640 427 -640 455 -480 640 -500 375 -500 373 -429 640 -640 480 -640 360 -500 375 -480 640 -640 426 -640 427 -640 480 -331 500 -640 640 -640 429 -640 367 -640 427 -640 428 -500 335 -640 426 -500 375 -427 640 -640 424 -640 428 -640 640 -640 471 -640 479 -640 327 -640 427 -640 480 -640 425 -640 480 -640 427 -480 640 -640 413 -640 427 -640 433 -640 480 -640 480 -418 640 -640 463 -640 589 -427 640 -640 485 -640 426 -640 426 -448 443 -497 500 -640 427 -333 500 -640 428 -640 425 -640 480 -640 480 -640 480 -500 334 -640 480 -640 427 -640 427 -640 480 -640 480 -640 428 -640 480 -640 427 -640 480 -640 425 -640 480 -640 427 -640 480 -640 480 -480 640 -640 426 -640 426 -566 640 -640 425 -640 480 -640 424 -640 426 -640 336 -640 428 -640 427 -640 305 -640 423 -427 640 -480 640 -640 543 -500 334 -640 427 -640 428 -640 480 -500 500 -640 425 -500 289 -640 480 -640 480 -640 427 -640 480 -640 427 -600 400 -500 375 -640 425 -640 457 -640 480 -480 640 -640 427 -429 640 -500 375 -640 429 -640 426 -480 640 -480 640 -640 480 -480 640 -640 480 -640 480 -426 640 -640 426 -640 480 -640 483 -640 480 -640 428 -480 640 -480 640 -640 480 -640 480 -640 480 -640 426 -640 428 -640 480 -640 290 -640 480 -640 480 -640 512 -640 474 -640 427 -375 500 -640 480 -640 523 -640 427 -640 480 -640 480 -640 519 -500 373 -640 480 -640 480 -640 480 -640 439 -640 427 -640 383 -640 370 -480 640 -500 333 -640 427 -500 375 -640 480 -612 612 -640 426 -640 480 -640 428 -640 634 -640 480 -598 640 -640 480 -640 428 -640 469 -640 480 -571 640 -500 376 -640 378 -640 428 -375 500 -640 424 -480 640 -500 335 -640 445 -640 427 -640 480 -640 384 -640 425 -427 640 -640 480 -640 214 -640 427 -640 480 -640 426 -640 480 -640 426 -427 640 -640 480 -480 640 -640 478 -640 424 -454 640 -491 640 -500 318 -640 445 -338 500 -336 500 -640 427 -370 462 -640 480 -640 401 -640 425 -640 313 -640 480 -640 480 -480 640 -480 640 -640 429 -640 480 -640 399 -640 427 -640 480 -426 640 -640 480 -640 465 -500 340 -640 414 -480 640 -640 479 -640 480 -640 360 -640 480 -413 640 -640 414 -500 332 -375 500 -500 375 -640 427 -640 425 -500 336 -512 640 -375 500 -640 427 -425 640 -428 640 -640 480 -640 480 -500 375 -425 640 -640 480 -640 480 -640 480 -427 640 -640 428 -640 359 -332 500 -640 480 -427 640 -640 480 -640 426 -640 424 -640 619 -640 480 -424 640 -640 480 -640 425 -640 480 -640 444 -640 429 -640 426 -480 640 -640 480 -640 567 -427 640 -640 427 -612 612 -425 640 -640 480 -425 640 -640 427 -640 428 -478 640 -640 360 -640 427 -480 640 -500 375 -640 423 -640 480 -614 640 -490 350 -480 640 -640 427 -640 360 -479 640 -427 640 -640 423 -375 500 -640 480 -640 354 -640 480 -640 427 -352 640 -612 612 -500 334 -500 375 -500 421 -640 480 -640 498 -640 480 -640 429 -640 480 -640 427 -640 427 -612 612 -640 480 -500 332 -640 429 -453 640 -640 427 -478 640 -640 478 -640 427 -428 640 -640 508 -612 612 -640 426 -640 428 -640 480 -427 640 -640 426 -612 612 -480 640 -640 481 -500 375 -640 509 diff --git a/utils/datasets.py b/utils/datasets.py index 2da23e6400..6c5a10d8f7 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -282,7 +282,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r # Rectangular Training https://github.com/ultralytics/yolov3/issues/232 if self.rect: # Read image shapes - sp = 'data' + os.sep + path.replace('.txt', '.shapes').split(os.sep)[-1] # shapefile path + sp = path.replace('.txt', '.shapes') # shapefile path try: with open(sp, 'r') as f: # read existing shapefile s = [x.split() for x in f.read().splitlines()] diff --git a/utils/utils.py b/utils/utils.py index 128742628e..2f7ee39612 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -658,7 +658,7 @@ def coco_class_count(path='../coco/labels/train2014/'): print(i, len(files)) -def coco_only_people(path='../coco/labels/val2014/'): +def coco_only_people(path='../coco/labels/train2017/'): # from utils.utils import *; coco_only_people() # Find images with only people files = sorted(glob.glob('%s/*.*' % path)) for i, file in enumerate(files): From 64c1ac3357d6cb4dcff4c364f4d8a68d734c0ef9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 19:10:57 -0800 Subject: [PATCH 0112/1185] updates --- data/get_coco2014.sh | 4 ++-- data/get_coco2017.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/get_coco2014.sh b/data/get_coco2014.sh index 37335aeb57..cb2fe21eb5 100755 --- a/data/get_coco2014.sh +++ b/data/get_coco2014.sh @@ -18,8 +18,8 @@ rm ${filename} # Download images cd coco/images -wget -c http://images.cocodataset.org/zips/train2014.zip -wget -c http://images.cocodataset.org/zips/val2014.zip +curl http://images.cocodataset.org/zips/train2014.zip -o train2014.zip +curl http://images.cocodataset.org/zips/val2014.zip -o val2014.zip # Unzip images unzip -q train2014.zip diff --git a/data/get_coco2017.sh b/data/get_coco2017.sh index ba24151d17..69a29761fb 100755 --- a/data/get_coco2017.sh +++ b/data/get_coco2017.sh @@ -17,8 +17,8 @@ rm ${filename} # Download images cd coco/images -wget -c http://images.cocodataset.org/zips/train2017.zip -wget -c http://images.cocodataset.org/zips/val2017.zip +curl http://images.cocodataset.org/zips/train2017.zip -o train2017.zip +curl http://images.cocodataset.org/zips/val2017.zip -o val2017.zip # Unzip images unzip -q train2017.zip From 8638317bbb63a523c3711d185fd6511541239f63 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 19:13:06 -0800 Subject: [PATCH 0113/1185] updates --- data/coco2014.data | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 data/coco2014.data diff --git a/data/coco2014.data b/data/coco2014.data new file mode 100644 index 0000000000..422a3005ed --- /dev/null +++ b/data/coco2014.data @@ -0,0 +1,4 @@ +classes=80 +train=../coco/trainvalno5k.txt +valid=../coco/5k.txt +names=data/coco.names From 0b19d4eb3ddbeeb60b45598f3ee73e22d4f07dfd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 19:31:50 -0800 Subject: [PATCH 0114/1185] updates --- test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index a7001312d4..92aa2262f4 100644 --- a/test.py +++ b/test.py @@ -184,7 +184,7 @@ def test(cfg, print('WARNING: missing pycocotools package, can not compute official COCO mAP. See requirements.txt.') # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb - cocoGt = COCO('../coco/annotations/instances_val2014.json') # initialize COCO ground truth api + cocoGt = COCO(glob.glob('../coco/annotations/instances_val*.json')[0]) # initialize COCO ground truth api cocoDt = cocoGt.loadRes('results.json') # initialize COCO pred api cocoEval = COCOeval(cocoGt, cocoDt, 'bbox') @@ -204,7 +204,7 @@ def test(cfg, if __name__ == '__main__': parser = argparse.ArgumentParser(prog='test.py') parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='cfg file path') - parser.add_argument('--data', type=str, default='data/coco.data', help='coco.data file path') + parser.add_argument('--data', type=str, default='data/coco2017.data', help='coco.data file path') parser.add_argument('--weights', type=str, default='weights/yolov3-spp.weights', help='path to weights file') parser.add_argument('--batch-size', type=int, default=16, help='size of each image batch') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') From fa7a5fea2b692d9856013a91f71bb1ceb13fc022 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 19:32:09 -0800 Subject: [PATCH 0115/1185] updates --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 92aa2262f4..caffb5520f 100644 --- a/test.py +++ b/test.py @@ -204,7 +204,7 @@ def test(cfg, if __name__ == '__main__': parser = argparse.ArgumentParser(prog='test.py') parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='cfg file path') - parser.add_argument('--data', type=str, default='data/coco2017.data', help='coco.data file path') + parser.add_argument('--data', type=str, default='data/coco.data', help='coco.data file path') parser.add_argument('--weights', type=str, default='weights/yolov3-spp.weights', help='path to weights file') parser.add_argument('--batch-size', type=int, default=16, help='size of each image batch') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') From 9c11bfe7920c6885aba6bc0f95e1883d820993a3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 23:09:31 -0800 Subject: [PATCH 0116/1185] updates --- data/coco1.data | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/data/coco1.data b/data/coco1.data index d97252f2d5..3c04a659ae 100644 --- a/data/coco1.data +++ b/data/coco1.data @@ -1,6 +1,4 @@ classes=80 -train=./data/coco_1img.txt -valid=./data/coco_1img.txt +train=data/coco1.txt +valid=data/coco1.txt names=data/coco.names -backup=backup/ -eval=coco From c0a7ace766138d36293ec394a4838b265a619486 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Dec 2019 23:15:56 -0800 Subject: [PATCH 0117/1185] updates --- data/{coco2017.data => coco.data} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data/{coco2017.data => coco.data} (100%) diff --git a/data/coco2017.data b/data/coco.data similarity index 100% rename from data/coco2017.data rename to data/coco.data From df1be4c74864aa4fa45d33b8596d9263d747d76e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 14 Dec 2019 14:49:18 -0800 Subject: [PATCH 0118/1185] updates --- requirements.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index a6d8b92eb7..dfb5cd9079 100755 --- a/requirements.txt +++ b/requirements.txt @@ -7,11 +7,14 @@ pycocotools tqdm Pillow -# Tensorboard pip requirements ------------------------------------------------- +# Nvidia Apex (optional) for mixed precision training -------------------------- +# git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex + +# Tensorboard (optional) pip requirements -------------------------------------- # tb-nightly # future -# Equivalent conda commands ---------------------------------------------------- +# Conda commands (in place of pip) --------------------------------------------- # conda update -n base -c defaults conda # conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython future # conda install -yc conda-forge scikit-image pycocotools onnx tensorboard From ddaa2976d775356fe72daedc45b768131b3c8a34 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 14 Dec 2019 15:15:20 -0800 Subject: [PATCH 0119/1185] updates --- utils/utils.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 2f7ee39612..a8b6975ba7 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -957,13 +957,18 @@ def plot_results_overlay(start=0, stop=0): # from utils.utils import *; plot_re fig.savefig(f.replace('.txt', '.png'), dpi=200) -def plot_results(start=0, stop=0): # from utils.utils import *; plot_results() +def plot_results(start=0, stop=0, bucket='', id=()): # from utils.utils import *; plot_results() # Plot training results files 'results*.txt' fig, ax = plt.subplots(2, 5, figsize=(14, 7)) ax = ax.ravel() s = ['GIoU', 'Objectness', 'Classification', 'Precision', 'Recall', 'val GIoU', 'val Objectness', 'val Classification', 'mAP@0.5', 'F1'] - for f in sorted(glob.glob('results*.txt') + glob.glob('../../Downloads/results*.txt')): + + if bucket: + files = ['https://storage.googleapis.com/%s/results%g.txt' % (bucket, x) for x in id] + else: + files = glob.glob('results*.txt') + glob.glob('../../Downloads/results*.txt') + for f in sorted(files): results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T n = results.shape[1] # number of rows x = range(start, min(stop, n) if stop else n) From eb70e4b751b2b3bd2ce63ddbf140b31e26f2bd37 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 14 Dec 2019 15:15:43 -0800 Subject: [PATCH 0120/1185] updates --- utils/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index a8b6975ba7..1525de9d40 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -963,7 +963,6 @@ def plot_results(start=0, stop=0, bucket='', id=()): # from utils.utils import ax = ax.ravel() s = ['GIoU', 'Objectness', 'Classification', 'Precision', 'Recall', 'val GIoU', 'val Objectness', 'val Classification', 'mAP@0.5', 'F1'] - if bucket: files = ['https://storage.googleapis.com/%s/results%g.txt' % (bucket, x) for x in id] else: From 8c13717f4855299f18456f872b6d1b503719fe1b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 14 Dec 2019 15:40:01 -0800 Subject: [PATCH 0121/1185] updates --- train.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/train.py b/train.py index 4fece80718..4c1eaeeb8b 100644 --- a/train.py +++ b/train.py @@ -208,7 +208,8 @@ def train(): # Test Dataloader if not opt.prebias: - testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, img_size, batch_size, hyp=hyp, + testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, opt.img_size, batch_size, + hyp=hyp, rect=True, cache_labels=True, cache_images=opt.cache_images), From 8164b305e56bf84a363f9b277e756425c74fe819 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 14 Dec 2019 15:45:40 -0800 Subject: [PATCH 0122/1185] updates --- .dockerignore | 1 + .gitignore | 1 + 2 files changed, 2 insertions(+) diff --git a/.dockerignore b/.dockerignore index ce28aaba50..5798fc6b1a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,6 +5,7 @@ runs output coco +storage.googleapis.com data/samples/* !data/samples/zidane.jpg diff --git a/.gitignore b/.gitignore index 518a16be0e..a47bd3e47c 100755 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ *.cfg !cfg/yolov3*.cfg +storage.googleapis.com runs/* data/* !data/samples/zidane.jpg From 03b5408e708ce6ce48b568111f4620b30fca9272 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 15 Dec 2019 12:15:56 -0800 Subject: [PATCH 0123/1185] updates --- utils/datasets.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 6c5a10d8f7..b88b769c58 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -16,6 +16,7 @@ from utils.utils import xyxy2xywh, xywh2xyxy +help_url = 'https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' img_formats = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.dng'] vid_formats = ['.mov', '.avi', '.mp4'] @@ -258,14 +259,15 @@ class LoadImagesAndLabels(Dataset): # for training/testing def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, cache_labels=False, cache_images=False): path = str(Path(path)) # os-agnostic + assert os.path.isfile(path), 'File not found %s. See %s' % (path, help_url) with open(path, 'r') as f: self.img_files = [x.replace('/', os.sep) for x in f.read().splitlines() # os-agnostic if os.path.splitext(x)[-1].lower() in img_formats] n = len(self.img_files) + assert n > 0, 'No images found in %s. See %s' % (path, help_url) bi = np.floor(np.arange(n) / batch_size).astype(np.int) # batch index nb = bi[-1] + 1 # number of batches - assert n > 0, 'No images found in %s' % path self.n = n self.batch = bi # batch index of image @@ -375,7 +377,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r pbar.desc = 'Caching labels (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( nf, nm, ne, nd, n) - assert nf > 0, 'No labels found. Recommend correcting image and label paths.' + assert nf > 0, 'No labels found. See %s' % help_url # Cache images into memory for faster training (WARNING: Large datasets may exceed system RAM) if cache_images: # if training From d884c33d2116fc4f021751e6bd94873f2ea80d28 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 15 Dec 2019 12:43:30 -0800 Subject: [PATCH 0124/1185] updates --- data/{coco.data => coco2017.data} | 0 detect.py | 2 +- test.py | 4 ++-- train.py | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) rename data/{coco.data => coco2017.data} (100%) diff --git a/data/coco.data b/data/coco2017.data similarity index 100% rename from data/coco.data rename to data/coco2017.data diff --git a/detect.py b/detect.py index 6da45c3b41..21ce771608 100644 --- a/detect.py +++ b/detect.py @@ -155,7 +155,7 @@ def detect(save_txt=False, save_img=False): if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='cfg file path') - parser.add_argument('--data', type=str, default='data/coco.data', help='coco.data file path') + parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data file path') parser.add_argument('--weights', type=str, default='weights/yolov3-spp.weights', help='path to weights file') parser.add_argument('--source', type=str, default='data/samples', help='source') # input file/folder, 0 for webcam parser.add_argument('--output', type=str, default='output', help='output folder') # output folder diff --git a/test.py b/test.py index caffb5520f..3cc52dd76e 100644 --- a/test.py +++ b/test.py @@ -204,7 +204,7 @@ def test(cfg, if __name__ == '__main__': parser = argparse.ArgumentParser(prog='test.py') parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='cfg file path') - parser.add_argument('--data', type=str, default='data/coco.data', help='coco.data file path') + parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data file path') parser.add_argument('--weights', type=str, default='weights/yolov3-spp.weights', help='path to weights file') parser.add_argument('--batch-size', type=int, default=16, help='size of each image batch') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') @@ -225,4 +225,4 @@ def test(cfg, opt.iou_thres, opt.conf_thres, opt.nms_thres, - opt.save_json or (opt.data == 'data/coco.data')) + opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']])) diff --git a/train.py b/train.py index 4c1eaeeb8b..329d9443d7 100644 --- a/train.py +++ b/train.py @@ -324,13 +324,14 @@ def train(): print_model_biases(model) elif not opt.notest or final_epoch: # Calculate mAP with torch.no_grad(): + is_coco = any([x in data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) and model.nc == 80 results, maps = test.test(cfg, data, batch_size=batch_size, img_size=opt.img_size, model=model, conf_thres=0.001 if final_epoch else 0.1, # 0.1 for speed - save_json=final_epoch and 'coco.data' in data and model.nc == 80, + save_json=final_epoch and is_coco, dataloader=testloader) # Write epoch results @@ -419,7 +420,7 @@ def prebias(): parser.add_argument('--batch-size', type=int, default=16) # effective bs = batch_size * accumulate = 16 * 4 = 64 parser.add_argument('--accumulate', type=int, default=4, help='batches to accumulate before optimizing') parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='cfg file path') - parser.add_argument('--data', type=str, default='data/coco.data', help='*.data file path') + parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data file path') parser.add_argument('--multi-scale', action='store_true', help='adjust (67% - 150%) img_size every 10 batches') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') parser.add_argument('--rect', action='store_true', help='rectangular training') From 87c5e43e8cd9c17f74d24dfcf0ca22caba3845fd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 15 Dec 2019 12:47:53 -0800 Subject: [PATCH 0125/1185] updates --- detect.py | 14 +++++++------- test.py | 4 ++-- train.py | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/detect.py b/detect.py index 21ce771608..4189bd8625 100644 --- a/detect.py +++ b/detect.py @@ -67,9 +67,9 @@ def detect(save_txt=False, save_img=False): save_img = True dataset = LoadImages(source, img_size=img_size, half=half) - # Get classes and colors - classes = load_classes(parse_data_cfg(opt.data)['names']) - colors = [[random.randint(0, 255) for _ in range(3)] for _ in range(len(classes))] + # Get names and colors + names = load_classes(opt.names) + colors = [[random.randint(0, 255) for _ in range(3)] for _ in range(len(names))] # Run inference t0 = time.time() @@ -108,7 +108,7 @@ def detect(save_txt=False, save_img=False): # Print results for c in det[:, -1].unique(): n = (det[:, -1] == c).sum() # detections per class - s += '%g %ss, ' % (n, classes[int(c)]) # add to string + s += '%g %ss, ' % (n, names[int(c)]) # add to string # Write results for *xyxy, conf, _, cls in det: @@ -117,7 +117,7 @@ def detect(save_txt=False, save_img=False): file.write(('%g ' * 6 + '\n') % (*xyxy, cls, conf)) if save_img or view_img: # Add bbox to image - label = '%s %.2f' % (classes[int(cls)], conf) + label = '%s %.2f' % (names[int(cls)], conf) plot_one_box(xyxy, im0, label=label, color=colors[int(cls)]) print('%sDone. (%.3fs)' % (s, time.time() - t)) @@ -154,8 +154,8 @@ def detect(save_txt=False, save_img=False): if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='cfg file path') - parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data file path') + parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') + parser.add_argument('--names', type=str, default='data/coco.names', help='*.names path') parser.add_argument('--weights', type=str, default='weights/yolov3-spp.weights', help='path to weights file') parser.add_argument('--source', type=str, default='data/samples', help='source') # input file/folder, 0 for webcam parser.add_argument('--output', type=str, default='output', help='output folder') # output folder diff --git a/test.py b/test.py index 3cc52dd76e..4274d0a695 100644 --- a/test.py +++ b/test.py @@ -203,8 +203,8 @@ def test(cfg, if __name__ == '__main__': parser = argparse.ArgumentParser(prog='test.py') - parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='cfg file path') - parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data file path') + parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') + parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data path') parser.add_argument('--weights', type=str, default='weights/yolov3-spp.weights', help='path to weights file') parser.add_argument('--batch-size', type=int, default=16, help='size of each image batch') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') diff --git a/train.py b/train.py index 329d9443d7..47defa3710 100644 --- a/train.py +++ b/train.py @@ -419,8 +419,8 @@ def prebias(): parser.add_argument('--epochs', type=int, default=273) # 500200 batches at bs 16, 117263 images = 273 epochs parser.add_argument('--batch-size', type=int, default=16) # effective bs = batch_size * accumulate = 16 * 4 = 64 parser.add_argument('--accumulate', type=int, default=4, help='batches to accumulate before optimizing') - parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='cfg file path') - parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data file path') + parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') + parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data path') parser.add_argument('--multi-scale', action='store_true', help='adjust (67% - 150%) img_size every 10 batches') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') parser.add_argument('--rect', action='store_true', help='rectangular training') From 9064d42b93aae66fddfc99d310c4834a8a357c8e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 15 Dec 2019 21:10:40 -0800 Subject: [PATCH 0126/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index bff616e00f..da6a23bbf5 100755 --- a/models.py +++ b/models.py @@ -84,7 +84,7 @@ def create_modules(module_defs, img_size, arc): if arc == 'defaultpw' or arc == 'Fdefaultpw': # default with positive weights b = [-4, -3.6] # obj, cls elif arc == 'default': # default no pw (40 cls, 80 obj) - b = [-5.5, -4.0] + b = [-5.5, -5.0] elif arc == 'uBCE': # unified BCE (80 classes) b = [0, -8.5] elif arc == 'uCE': # unified CE (1 background + 80 classes) From d7b010c51414922554dc8bc523756070690d844d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 16 Dec 2019 15:49:15 -0800 Subject: [PATCH 0127/1185] updates --- test.py | 21 ++++++++++++--------- utils/utils.py | 39 +++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/test.py b/test.py index 4274d0a695..e23081db96 100644 --- a/test.py +++ b/test.py @@ -13,7 +13,6 @@ def test(cfg, weights=None, batch_size=16, img_size=416, - iou_thres=0.5, conf_thres=0.001, nms_thres=0.5, save_json=False, @@ -49,6 +48,9 @@ def test(cfg, nc = int(data['classes']) # number of classes test_path = data['valid'] # path to test images names = load_classes(data['names']) # class names + iou_thres = torch.linspace(0.5, 0.95, 10).to(device) # for mAP@0.5:0.95 + iou_thres = iou_thres[0].view(1) # for mAP@0.5 + niou = iou_thres.numel() # Dataloader if dataloader is None: @@ -120,7 +122,7 @@ def test(cfg, clip_coords(pred, (height, width)) # Assign all predictions as incorrect - correct = [0] * len(pred) + correct = torch.zeros(len(pred), niou) if nl: detected = [] tcls_tensor = labels[:, 0] @@ -143,12 +145,13 @@ def test(cfg, # Best iou, index between pred and targets m = (pcls == tcls_tensor).nonzero().view(-1) - iou, bi = bbox_iou(pbox, tbox[m]).max(0) + iou, j = bbox_iou(pbox, tbox[m]).max(0) + m = m[j] - # If iou > threshold and class is correct mark as correct - if iou > iou_thres and m[bi] not in detected: # and pcls == tcls[bi]: - correct[i] = 1 - detected.append(m[bi]) + # Per iou_thres 'correct' vector + if iou > iou_thres[0] and m not in detected: + detected.append(m) + correct[i] = iou > iou_thres # Append statistics (correct, conf, pcls, tcls) stats.append((correct, pred[:, 4].cpu(), pred[:, 6].cpu(), tcls)) @@ -157,6 +160,8 @@ def test(cfg, stats = [np.concatenate(x, 0) for x in list(zip(*stats))] # to numpy if len(stats): p, r, ap, f1, ap_class = ap_per_class(*stats) + # if niou > 1: + # p, r, ap, f1 = p[:, 0], r[:, 0], ap[:, 0], ap.mean(1) # average across ious mp, mr, map, mf1 = p.mean(), r.mean(), ap.mean(), f1.mean() nt = np.bincount(stats[3].astype(np.int64), minlength=nc) # number of targets per class else: @@ -208,7 +213,6 @@ def test(cfg, parser.add_argument('--weights', type=str, default='weights/yolov3-spp.weights', help='path to weights file') parser.add_argument('--batch-size', type=int, default=16, help='size of each image batch') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') - parser.add_argument('--iou-thres', type=float, default=0.5, help='iou threshold required to qualify as detected') parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') parser.add_argument('--nms-thres', type=float, default=0.5, help='iou threshold for non-maximum suppression') parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') @@ -222,7 +226,6 @@ def test(cfg, opt.weights, opt.batch_size, opt.img_size, - opt.iou_thres, opt.conf_thres, opt.nms_thres, opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']])) diff --git a/utils/utils.py b/utils/utils.py index 1525de9d40..67953488e9 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -152,10 +152,10 @@ def ap_per_class(tp, conf, pred_cls, target_cls): """ Compute the average precision, given the recall and precision curves. Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. # Arguments - tp: True positives (list). - conf: Objectness value from 0-1 (list). - pred_cls: Predicted object classes (list). - target_cls: True object classes (list). + tp: True positives (nparray, nx1 or nx10). + conf: Objectness value from 0-1 (nparray). + pred_cls: Predicted object classes (nparray). + target_cls: True object classes (nparray). # Returns The average precision as computed in py-faster-rcnn. """ @@ -168,46 +168,41 @@ def ap_per_class(tp, conf, pred_cls, target_cls): unique_classes = np.unique(target_cls) # Create Precision-Recall curve and compute AP for each class - ap, p, r = [], [], [] - for c in unique_classes: + s = [len(unique_classes), tp.shape[1]] # number class, number iou thresholds (i.e. 10 for mAP0.5...0.95) + ap, p, r = np.zeros(s), np.zeros(s), np.zeros(s) + for ci, c in enumerate(unique_classes): i = pred_cls == c - n_gt = (target_cls == c).sum() # Number of ground truth objects - n_p = i.sum() # Number of predicted objects + n_gt = sum(target_cls == c) # Number of ground truth objects + n_p = sum(i) # Number of predicted objects - if n_p == 0 and n_gt == 0: + if n_p == 0 or n_gt == 0: continue - elif n_p == 0 or n_gt == 0: - ap.append(0) - r.append(0) - p.append(0) else: # Accumulate FPs and TPs - fpc = (1 - tp[i]).cumsum() - tpc = (tp[i]).cumsum() + fpc = (1 - tp[i]).cumsum(0) + tpc = tp[i].cumsum(0) # Recall recall = tpc / (n_gt + 1e-16) # recall curve - r.append(recall[-1]) + r[ci] = recall[-1] # Precision precision = tpc / (tpc + fpc) # precision curve - p.append(precision[-1]) + p[ci] = precision[-1] # AP from recall-precision curve - ap.append(compute_ap(recall, precision)) + for j in range(tp.shape[1]): + ap[ci, j] = compute_ap(recall[:, j], precision[:, j]) # Plot # fig, ax = plt.subplots(1, 1, figsize=(4, 4)) # ax.plot(np.concatenate(([0.], recall)), np.concatenate(([0.], precision))) - # ax.set_xlabel('YOLOv3-SPP') - # ax.set_xlabel('Recall') - # ax.set_ylabel('Precision') + # ax.set_title('YOLOv3-SPP'); ax.set_xlabel('Recall'); ax.set_ylabel('Precision') # ax.set_xlim(0, 1) # fig.tight_layout() # fig.savefig('PR_curve.png', dpi=300) # Compute F1 score (harmonic mean of precision and recall) - p, r, ap = np.array(p), np.array(r), np.array(ap) f1 = 2 * p * r / (p + r + 1e-16) return p, r, ap, f1, unique_classes.astype('int32') From 8666413c47be06697e63ddf6fdfb5f908fb2eacf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 16 Dec 2019 16:29:40 -0800 Subject: [PATCH 0128/1185] updates --- test.py | 2 +- utils/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index e23081db96..5d14c4e7db 100644 --- a/test.py +++ b/test.py @@ -197,7 +197,7 @@ def test(cfg, cocoEval.evaluate() cocoEval.accumulate() cocoEval.summarize() - map = cocoEval.stats[1] # update mAP to pycocotools mAP + mf1, map = cocoEval.stats[:2] # update to pycocotools results (mAP@0.5:0.95, mAP@0.5) # Return results maps = np.zeros(nc) + map diff --git a/utils/utils.py b/utils/utils.py index 67953488e9..793bf6ce4a 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -810,7 +810,7 @@ def apply_classifier(x, model, img, im0): def fitness(x): # Returns fitness (for use with results.txt or evolve.txt) - return x[:, 2] * 0.8 + x[:, 3] * 0.2 # weighted mAP and F1 combination + return x[:, 2] * 0.5 + x[:, 3] * 0.5 # weighted combination of x=[p, r, mAP@0.5, F1 or mAP@0.5:0.95] # Plotting functions --------------------------------------------------------------------------------------------------- From 9c03ac3b744f1b9b76f58e812493b1a0fddac470 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 16 Dec 2019 16:36:12 -0800 Subject: [PATCH 0129/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 793bf6ce4a..e077d89402 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -810,7 +810,7 @@ def apply_classifier(x, model, img, im0): def fitness(x): # Returns fitness (for use with results.txt or evolve.txt) - return x[:, 2] * 0.5 + x[:, 3] * 0.5 # weighted combination of x=[p, r, mAP@0.5, F1 or mAP@0.5:0.95] + return x[:, 2] * 0.1 + x[:, 3] * 0.9 # weighted combination of x=[p, r, mAP@0.5, F1 or mAP@0.5:0.95] # Plotting functions --------------------------------------------------------------------------------------------------- From ecce92d5d8b9cc918bc75019b507e69f24389e40 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 16 Dec 2019 22:18:26 -0800 Subject: [PATCH 0130/1185] updates --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 5d14c4e7db..7472fa982d 100644 --- a/test.py +++ b/test.py @@ -97,7 +97,7 @@ def test(cfg, if pred is None: if nl: - stats.append(([], torch.Tensor(), torch.Tensor(), tcls)) + stats.append((torch.zeros(0, 1), torch.Tensor(), torch.Tensor(), tcls)) continue # Append to text file From a5677d3f90dc01b5da8bf364f549e6deb1878136 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 17 Dec 2019 10:14:18 -0800 Subject: [PATCH 0131/1185] updates --- utils/utils.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index e077d89402..d7b27171ac 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -466,7 +466,10 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): Returns detections with shape: (x1, y1, x2, y2, object_conf, class_conf, class) """ + # NMS method https://github.com/ultralytics/yolov3/issues/679 'OR', 'AND', 'MERGE', 'VISION', 'VISION_BATCHED' + method = 'MERGE' if conf_thres <= 0.01 else 'VISION' # MERGE is highest mAP, VISION is fastest + # Box constraints min_wh, max_wh = 2, 10000 # (pixels) minimum and maximium box width and height output = [None] * len(prediction) @@ -516,10 +519,6 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): # Get detections sorted by decreasing confidence scores pred = pred[(-pred[:, 4]).argsort()] - # Set NMS method https://github.com/ultralytics/yolov3/issues/679 - # 'OR', 'AND', 'MERGE', 'VISION', 'VISION_BATCHED' - method = 'MERGE' if conf_thres <= 0.01 else 'VISION' # MERGE is highest mAP, VISION is fastest - # Batched NMS if method == 'VISION_BATCHED': i = torchvision.ops.boxes.batched_nms(boxes=pred[:, :4], From adc2663fe70aee3bb286dc79e9fe6eec20a47f87 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 17 Dec 2019 12:26:42 -0800 Subject: [PATCH 0132/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index da6a23bbf5..65bc20c261 100755 --- a/models.py +++ b/models.py @@ -86,7 +86,7 @@ def create_modules(module_defs, img_size, arc): elif arc == 'default': # default no pw (40 cls, 80 obj) b = [-5.5, -5.0] elif arc == 'uBCE': # unified BCE (80 classes) - b = [0, -8.5] + b = [0, -9.0] elif arc == 'uCE': # unified CE (1 background + 80 classes) b = [10, -0.1] elif arc == 'Fdefault': # Focal default no pw (28 cls, 21 obj, no pw) From 8385f613d24f7bd7f0cf3a599835098951dfacbd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 18 Dec 2019 09:45:34 -0800 Subject: [PATCH 0133/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 47defa3710..49bd789b5a 100644 --- a/train.py +++ b/train.py @@ -485,7 +485,7 @@ def prebias(): # Mutate np.random.seed(int(time.time())) - s = [.2, .2, .2, .2, .2, .2, .2, .0, .02, .2, .2, .2, .2, .2, .2, .2, .2, .2] # sigmas + s = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) * 0.2 # sigmas for i, k in enumerate(hyp.keys()): x = (np.random.randn(1) * s[i] + 1) ** 2.0 # plt.hist(x.ravel(), 300) hyp[k] *= float(x) # vary by sigmas From ad73ce43341db6809e7d2cf3a0720b39f73eeb3b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 18 Dec 2019 10:24:10 -0800 Subject: [PATCH 0134/1185] updates --- train.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 49bd789b5a..3aeffe718c 100644 --- a/train.py +++ b/train.py @@ -472,7 +472,7 @@ def prebias(): if os.path.exists('evolve.txt'): # if evolve.txt exists: select best hyps and mutate # Select parent(s) x = np.loadtxt('evolve.txt', ndmin=2) - parent = 'weighted' # parent selection method: 'single' or 'weighted' + parent = 'single' # parent selection method: 'single' or 'weighted' if parent == 'single' or len(x) == 1: x = x[fitness(x).argmax()] elif parent == 'weighted': # weighted combination @@ -485,9 +485,10 @@ def prebias(): # Mutate np.random.seed(int(time.time())) - s = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) * 0.2 # sigmas + s = np.random.random() * 0.3 # sigma + g = [1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 1, 1, 1, 1, 1, 1, 1, 1] # gains for i, k in enumerate(hyp.keys()): - x = (np.random.randn(1) * s[i] + 1) ** 2.0 # plt.hist(x.ravel(), 300) + x = (np.random.randn() * s * g[i] + 1) ** 2.0 # plt.hist(x.ravel(), 300) hyp[k] *= float(x) # vary by sigmas # Clip to limits From eac2c010c461a2dffef211435dc27c8e6b34b321 Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 18 Dec 2019 16:13:20 -0500 Subject: [PATCH 0135/1185] return kmeans targets (#722) return kmeans targets --- utils/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/utils.py b/utils/utils.py index d7b27171ac..6c6901fcf7 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -751,6 +751,7 @@ def kmeans_targets(path='../coco/trainvalno5k.txt', n=9, img_size=416): # from # Plot # plt.hist(biou.numpy().ravel(), 100) + return k def print_mutation(hyp, results, bucket=''): From f5cd3596f5e0eb9f69f457a21ebea12a76d5c521 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Dec 2019 18:09:13 -0800 Subject: [PATCH 0136/1185] updates --- detect.py | 2 +- models.py | 19 ++++++++++++------- test.py | 8 ++++---- utils/utils.py | 38 +++++++++++++------------------------- 4 files changed, 30 insertions(+), 37 deletions(-) diff --git a/detect.py b/detect.py index 4189bd8625..051ca6fc52 100644 --- a/detect.py +++ b/detect.py @@ -111,7 +111,7 @@ def detect(save_txt=False, save_img=False): s += '%g %ss, ' % (n, names[int(c)]) # add to string # Write results - for *xyxy, conf, _, cls in det: + for *xyxy, conf, cls in det: if save_txt: # Write to file with open(save_path + '.txt', 'a') as file: file.write(('%g ' * 6 + '\n') % (*xyxy, cls, conf)) diff --git a/models.py b/models.py index 65bc20c261..d540981a78 100755 --- a/models.py +++ b/models.py @@ -149,8 +149,10 @@ def __init__(self, anchors, nc, img_size, yolo_index, arc): self.anchors = torch.Tensor(anchors) self.na = len(anchors) # number of anchors (3) self.nc = nc # number of classes (80) + self.no = nc + 5 # number of outputs self.nx = 0 # initialize number of x gridpoints self.ny = 0 # initialize number of y gridpoints + self.oi = [0, 1, 2, 3] + list(range(5, self.no)) # output indices self.arc = arc if ONNX_EXPORT: # grids must be computed in __init__ @@ -168,7 +170,7 @@ def forward(self, p, img_size, var=None): create_grids(self, img_size, (nx, ny), p.device, p.dtype) # p.view(bs, 255, 13, 13) -- > (bs, 3, 13, 13, 85) # (bs, anchors, grid, grid, classes + xywh) - p = p.view(bs, self.na, self.nc + 5, self.ny, self.nx).permute(0, 1, 3, 4, 2).contiguous() # prediction + p = p.view(bs, self.na, self.no, self.ny, self.nx).permute(0, 1, 3, 4, 2).contiguous() # prediction if self.training: return p @@ -180,18 +182,18 @@ def forward(self, p, img_size, var=None): grid_xy = self.grid_xy.repeat((1, self.na, 1, 1, 1)).view(1, m, 2) anchor_wh = self.anchor_wh.repeat((1, 1, self.nx, self.ny, 1)).view(1, m, 2) / ngu - p = p.view(m, 5 + self.nc) + p = p.view(m, self.no) xy = torch.sigmoid(p[..., 0:2]) + grid_xy[0] # x, y wh = torch.exp(p[..., 2:4]) * anchor_wh[0] # width, height p_conf = torch.sigmoid(p[:, 4:5]) # Conf - p_cls = F.softmax(p[:, 5:5 + self.nc], 1) * p_conf # SSD-like conf + p_cls = F.softmax(p[:, 5:self.no], 1) * p_conf # SSD-like conf return torch.cat((xy / ngu[0], wh, p_conf, p_cls), 1).t() - # p = p.view(1, m, 5 + self.nc) + # p = p.view(1, m, self.no) # xy = torch.sigmoid(p[..., 0:2]) + grid_xy # x, y # wh = torch.exp(p[..., 2:4]) * anchor_wh # width, height # p_conf = torch.sigmoid(p[..., 4:5]) # Conf - # p_cls = p[..., 5:5 + self.nc] + # p_cls = p[..., 5:self.no] # # Broadcasting only supported on first dimension in CoreML. See onnx-coreml/_operators.py # # p_cls = F.softmax(p_cls, 2) * p_conf # SSD-like conf # p_cls = torch.exp(p_cls).permute((2, 1, 0)) @@ -219,8 +221,11 @@ def forward(self, p, img_size, var=None): if self.nc == 1: io[..., 5] = 1 # single-class model https://github.com/ultralytics/yolov3/issues/235 - # reshape from [1, 3, 13, 13, 85] to [1, 507, 85] - return io.view(bs, -1, 5 + self.nc), p + # compute conf + io[..., 5:] *= io[..., 4:5] # conf = obj_conf * cls_conf + + # reshape from [1, 3, 13, 13, 85] to [1, 507, 84], remove obj_conf + return io[..., self.oi].view(bs, -1, self.no - 1), p class Darknet(nn.Module): diff --git a/test.py b/test.py index 7472fa982d..7e38acf811 100644 --- a/test.py +++ b/test.py @@ -114,7 +114,7 @@ def test(cfg, box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner for di, d in enumerate(pred): jdict.append({'image_id': image_id, - 'category_id': coco91class[int(d[6])], + 'category_id': coco91class[int(d[5])], 'bbox': [floatn(x, 3) for x in box[di]], 'score': floatn(d[4], 5)}) @@ -133,7 +133,7 @@ def test(cfg, tbox[:, [1, 3]] *= height # Search for correct predictions - for i, (*pbox, pconf, pcls_conf, pcls) in enumerate(pred): + for i, (*pbox, _, pcls) in enumerate(pred): # Break if all targets already located in image if len(detected) == nl: @@ -154,7 +154,7 @@ def test(cfg, correct[i] = iou > iou_thres # Append statistics (correct, conf, pcls, tcls) - stats.append((correct, pred[:, 4].cpu(), pred[:, 6].cpu(), tcls)) + stats.append((correct, pred[:, 4].cpu(), pred[:, 5].cpu(), tcls)) # Compute statistics stats = [np.concatenate(x, 0) for x in list(zip(*stats))] # to numpy @@ -209,7 +209,7 @@ def test(cfg, if __name__ == '__main__': parser = argparse.ArgumentParser(prog='test.py') parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') - parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data path') + parser.add_argument('--data', type=str, default='data/coco2014.data', help='*.data path') parser.add_argument('--weights', type=str, default='weights/yolov3-spp.weights', help='path to weights file') parser.add_argument('--batch-size', type=int, default=16, help='size of each image batch') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') diff --git a/utils/utils.py b/utils/utils.py index d7b27171ac..c3c3e9262d 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -464,7 +464,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): Removes detections with lower object confidence score than 'conf_thres' Non-Maximum Suppression to further filter detections. Returns detections with shape: - (x1, y1, x2, y2, object_conf, class_conf, class) + (x1, y1, x2, y2, object_conf, conf, class) """ # NMS method https://github.com/ultralytics/yolov3/issues/679 'OR', 'AND', 'MERGE', 'VISION', 'VISION_BATCHED' method = 'MERGE' if conf_thres <= 0.01 else 'VISION' # MERGE is highest mAP, VISION is fastest @@ -474,47 +474,35 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): output = [None] * len(prediction) for image_i, pred in enumerate(prediction): - # Experiment: Prior class size rejection - # x, y, w, h = pred[:, 0], pred[:, 1], pred[:, 2], pred[:, 3] - # a = w * h # area - # ar = w / (h + 1e-16) # aspect ratio - # n = len(w) - # log_w, log_h, log_a, log_ar = torch.log(w), torch.log(h), torch.log(a), torch.log(ar) - # shape_likelihood = np.zeros((n, 60), dtype=np.float32) - # x = np.concatenate((log_w.reshape(-1, 1), log_h.reshape(-1, 1)), 1) - # from scipy.stats import multivariate_normal - # for c in range(60): - # shape_likelihood[:, c] = - # multivariate_normal.pdf(x, mean=mat['class_mu'][c, :2], cov=mat['class_cov'][c, :2, :2]) + # Duplicate ambiguous + # b = pred[pred[:, 5:].sum(1) > 1.1] + # if len(b): + # b[range(len(b)), 5 + b[:, 5:].argmax(1)] = 0 + # pred = torch.cat((pred, b), 0) # Multiply conf by class conf to get combined confidence - class_conf, class_pred = pred[:, 5:].max(1) - pred[:, 4] *= class_conf + conf, cls = pred[:, 4:].max(1) # # Merge classes (optional) - # class_pred[(class_pred.view(-1,1) == torch.LongTensor([2, 3, 5, 6, 7]).view(1,-1)).any(1)] = 2 + # cls[(cls.view(-1,1) == torch.LongTensor([2, 3, 5, 6, 7]).view(1,-1)).any(1)] = 2 # # # Remove classes (optional) - # pred[class_pred != 2, 4] = 0.0 + # pred[cls != 2, 4] = 0.0 # Select only suitable predictions - i = (pred[:, 4] > conf_thres) & (pred[:, 2:4] > min_wh).all(1) & (pred[:, 2:4] < max_wh).all(1) & \ - torch.isfinite(pred).all(1) + i = (conf > conf_thres) & (pred[:, 2:4] > min_wh).all(1) & (pred[:, 2:4] < max_wh).all(1) & torch.isfinite( + pred).all(1) pred = pred[i] # If none are remaining => process next image if len(pred) == 0: continue - # Select predicted classes - class_conf = class_conf[i] - class_pred = class_pred[i].unsqueeze(1).float() - # Box (center x, center y, width, height) to (x1, y1, x2, y2) pred[:, :4] = xywh2xyxy(pred[:, :4]) - # Detections ordered as (x1y1x2y2, obj_conf, class_conf, class_pred) - pred = torch.cat((pred[:, :5], class_conf.unsqueeze(1), class_pred), 1) + # Detections ordered as (x1y1x2y2, conf, cls) + pred = torch.cat((pred[:, :4], conf[i].unsqueeze(1), cls[i].unsqueeze(1).float()), 1) # Get detections sorted by decreasing confidence scores pred = pred[(-pred[:, 4]).argsort()] From 674d0de1701780109f8122d7d83f387bb376e1ed Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Dec 2019 18:32:45 -0800 Subject: [PATCH 0137/1185] updates --- utils/utils.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 2e54870e32..54adc05ea4 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -501,8 +501,13 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): # Box (center x, center y, width, height) to (x1, y1, x2, y2) pred[:, :4] = xywh2xyxy(pred[:, :4]) - # Detections ordered as (x1y1x2y2, conf, cls) - pred = torch.cat((pred[:, :4], conf[i].unsqueeze(1), cls[i].unsqueeze(1).float()), 1) + # Expand + expand = False + if expand: + i, j = (pred[:, 4:] > conf_thres).nonzero().t() + pred = torch.cat((pred[i, :4], pred[i, j].unsqueeze(1), j.float().unsqueeze(1)), 1) # (x1y1x2y2, conf, cls) + else: + pred = torch.cat((pred[:, :4], conf[i].unsqueeze(1), cls[i].unsqueeze(1).float()), 1) # Get detections sorted by decreasing confidence scores pred = pred[(-pred[:, 4]).argsort()] From aaaaa0615685c77db33bf1c263a4b5bf7bf06f8b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Dec 2019 18:55:48 -0800 Subject: [PATCH 0138/1185] updates --- utils/utils.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 54adc05ea4..c396be0319 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -459,15 +459,15 @@ def build_targets(model, targets): return tcls, tbox, indices, av -def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): +def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=True, method='vision'): """ Removes detections with lower object confidence score than 'conf_thres' Non-Maximum Suppression to further filter detections. Returns detections with shape: (x1, y1, x2, y2, object_conf, conf, class) """ - # NMS method https://github.com/ultralytics/yolov3/issues/679 'OR', 'AND', 'MERGE', 'VISION', 'VISION_BATCHED' - method = 'MERGE' if conf_thres <= 0.01 else 'VISION' # MERGE is highest mAP, VISION is fastest + # NMS method https://github.com/ultralytics/yolov3/issues/679 'or', 'and', 'merge', 'vision', 'vision_batch' + # method = 'merge' if conf_thres <= 0.01 else 'vision' # MERGE is highest mAP, VISION is fastest # Box constraints min_wh, max_wh = 2, 10000 # (pixels) minimum and maximium box width and height @@ -501,19 +501,18 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): # Box (center x, center y, width, height) to (x1, y1, x2, y2) pred[:, :4] = xywh2xyxy(pred[:, :4]) - # Expand - expand = False - if expand: + # Multi-class + if multi_cls: i, j = (pred[:, 4:] > conf_thres).nonzero().t() - pred = torch.cat((pred[i, :4], pred[i, j].unsqueeze(1), j.float().unsqueeze(1)), 1) # (x1y1x2y2, conf, cls) + pred = torch.cat((pred[i, :4], pred[i, j + 4].unsqueeze(1), j.float().unsqueeze(1)), 1) else: - pred = torch.cat((pred[:, :4], conf[i].unsqueeze(1), cls[i].unsqueeze(1).float()), 1) + pred = torch.cat((pred[:, :4], conf[i].unsqueeze(1), cls[i].unsqueeze(1).float()), 1) # (xyxy, conf, cls) # Get detections sorted by decreasing confidence scores pred = pred[(-pred[:, 4]).argsort()] # Batched NMS - if method == 'VISION_BATCHED': + if method == 'vision_batch': i = torchvision.ops.boxes.batched_nms(boxes=pred[:, :4], scores=pred[:, 4], idxs=pred[:, 6], @@ -532,11 +531,11 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): elif n > 500: dc = dc[:500] # limit to first 500 boxes: https://github.com/ultralytics/yolov3/issues/117 - if method == 'VISION': + if method == 'vision': i = torchvision.ops.boxes.nms(dc[:, :4], dc[:, 4], nms_thres) det_max.append(dc[i]) - elif method == 'OR': # default + elif method == 'or': # default # METHOD1 # ind = list(range(len(dc))) # while len(ind): @@ -553,14 +552,14 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes dc = dc[1:][iou < nms_thres] # remove ious > threshold - elif method == 'AND': # requires overlap, single boxes erased + elif method == 'and': # requires overlap, single boxes erased while len(dc) > 1: iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes if iou.max() > 0.5: det_max.append(dc[:1]) dc = dc[1:][iou < nms_thres] # remove ious > threshold - elif method == 'MERGE': # weighted mixture box + elif method == 'merge': # weighted mixture box while len(dc): if len(dc) == 1: det_max.append(dc) @@ -571,7 +570,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5): det_max.append(dc[:1]) dc = dc[i == 0] - elif method == 'SOFT': # soft-NMS https://arxiv.org/abs/1704.04503 + elif method == 'soft': # soft-NMS https://arxiv.org/abs/1704.04503 sigma = 0.5 # soft-nms sigma parameter while len(dc): if len(dc) == 1: From 9048d96c71ef5bdc56250109ab022e1a9b94352b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Dec 2019 18:56:40 -0800 Subject: [PATCH 0139/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index c396be0319..5a1a4912d3 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -459,7 +459,7 @@ def build_targets(model, targets): return tcls, tbox, indices, av -def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=True, method='vision'): +def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=False, method='vision'): """ Removes detections with lower object confidence score than 'conf_thres' Non-Maximum Suppression to further filter detections. From ce9a2cb9d217d22440f4456815aa26fdba8a73aa Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Dec 2019 19:23:09 -0800 Subject: [PATCH 0140/1185] updates --- utils/utils.py | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 5a1a4912d3..6ffdfee819 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -474,24 +474,11 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Fal output = [None] * len(prediction) for image_i, pred in enumerate(prediction): - # Duplicate ambiguous - # b = pred[pred[:, 5:].sum(1) > 1.1] - # if len(b): - # b[range(len(b)), 5 + b[:, 5:].argmax(1)] = 0 - # pred = torch.cat((pred, b), 0) - - # Multiply conf by class conf to get combined confidence - conf, cls = pred[:, 4:].max(1) - - # # Merge classes (optional) - # cls[(cls.view(-1,1) == torch.LongTensor([2, 3, 5, 6, 7]).view(1,-1)).any(1)] = 2 - # - # # Remove classes (optional) - # pred[cls != 2, 4] = 0.0 + # Remove rows + pred = pred[(pred[:, 4:] > conf_thres).any(1)] # retain above threshold # Select only suitable predictions - i = (conf > conf_thres) & (pred[:, 2:4] > min_wh).all(1) & (pred[:, 2:4] < max_wh).all(1) & torch.isfinite( - pred).all(1) + i = (pred[:, 2:4] > min_wh).all(1) & (pred[:, 2:4] < max_wh).all(1) & torch.isfinite(pred).all(1) pred = pred[i] # If none are remaining => process next image @@ -505,11 +492,12 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Fal if multi_cls: i, j = (pred[:, 4:] > conf_thres).nonzero().t() pred = torch.cat((pred[i, :4], pred[i, j + 4].unsqueeze(1), j.float().unsqueeze(1)), 1) - else: - pred = torch.cat((pred[:, :4], conf[i].unsqueeze(1), cls[i].unsqueeze(1).float()), 1) # (xyxy, conf, cls) + else: # best class only + conf, j = pred[:, 4:].max(1) + pred = torch.cat((pred[:, :4], conf.unsqueeze(1), j.float().unsqueeze(1)), 1) # (xyxy, conf, cls) # Get detections sorted by decreasing confidence scores - pred = pred[(-pred[:, 4]).argsort()] + pred = pred[pred[:, 4].argsort(descending=True)] # Batched NMS if method == 'vision_batch': From 9309d35478ede9fb5c38829fc6fbfc32b6847f07 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Dec 2019 19:35:14 -0800 Subject: [PATCH 0141/1185] updates --- utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 6ffdfee819..6abd2b301d 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -459,7 +459,7 @@ def build_targets(model, targets): return tcls, tbox, indices, av -def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=False, method='vision'): +def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=True, method='vision'): """ Removes detections with lower object confidence score than 'conf_thres' Non-Maximum Suppression to further filter detections. @@ -489,7 +489,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Fal pred[:, :4] = xywh2xyxy(pred[:, :4]) # Multi-class - if multi_cls: + if multi_cls or conf_thres < 0.01: i, j = (pred[:, 4:] > conf_thres).nonzero().t() pred = torch.cat((pred[i, :4], pred[i, j + 4].unsqueeze(1), j.float().unsqueeze(1)), 1) else: # best class only From 2e1c415e5955d56c0304674bc8da80757a4c5c83 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Dec 2019 20:07:58 -0800 Subject: [PATCH 0142/1185] updates --- utils/utils.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 6abd2b301d..fc9abc6769 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -501,10 +501,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru # Batched NMS if method == 'vision_batch': - i = torchvision.ops.boxes.batched_nms(boxes=pred[:, :4], - scores=pred[:, 4], - idxs=pred[:, 6], - iou_threshold=nms_thres) + i = torchvision.ops.boxes.batched_nms(pred[:, :4], pred[:, 4], pred[:, 5], nms_thres) output[image_i] = pred[i] continue From 8d54770859b2386e5c6d19c1c9fbc53fc7d07ec2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 20 Dec 2019 08:41:28 -0800 Subject: [PATCH 0143/1185] updates --- test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index 7e38acf811..1c98e4bc18 100644 --- a/test.py +++ b/test.py @@ -46,7 +46,7 @@ def test(cfg, # Configure run data = parse_data_cfg(data) nc = int(data['classes']) # number of classes - test_path = data['valid'] # path to test images + path = data['valid'] # path to test images names = load_classes(data['names']) # class names iou_thres = torch.linspace(0.5, 0.95, 10).to(device) # for mAP@0.5:0.95 iou_thres = iou_thres[0].view(1) # for mAP@0.5 @@ -54,7 +54,7 @@ def test(cfg, # Dataloader if dataloader is None: - dataset = LoadImagesAndLabels(test_path, img_size, batch_size, rect=True) + dataset = LoadImagesAndLabels(path, img_size, batch_size, rect=True) batch_size = min(batch_size, len(dataset)) dataloader = DataLoader(dataset, batch_size=batch_size, From 2bc6683325559ee39034a13489b5059056cb629e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 20 Dec 2019 09:07:25 -0800 Subject: [PATCH 0144/1185] updates --- test.py | 45 +++++++++++++++++++++++++++++++-------------- train.py | 19 +++++++++---------- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/test.py b/test.py index 1c98e4bc18..4b33d761b0 100644 --- a/test.py +++ b/test.py @@ -78,12 +78,15 @@ def test(cfg, if batch_i == 0 and not os.path.exists('test_batch0.jpg'): plot_images(imgs=imgs, targets=targets, paths=paths, fname='test_batch0.jpg') - # Run model - inf_out, train_out = model(imgs) # inference and training outputs + # Disable gradients + with torch.no_grad(): - # Compute loss - if hasattr(model, 'hyp'): # if model has loss hyperparameters - loss += compute_loss(train_out, targets, model)[1][:3].cpu() # GIoU, obj, cls + # Run model + inf_out, train_out = model(imgs) # inference and training outputs + + # Compute loss + if hasattr(model, 'hyp'): # if model has loss hyperparameters + loss += compute_loss(train_out, targets, model)[1][:3].cpu() # GIoU, obj, cls # Run NMS output = non_max_suppression(inf_out, conf_thres=conf_thres, nms_thres=nms_thres) @@ -220,12 +223,26 @@ def test(cfg, opt = parser.parse_args() print(opt) - with torch.no_grad(): - test(opt.cfg, - opt.data, - opt.weights, - opt.batch_size, - opt.img_size, - opt.conf_thres, - opt.nms_thres, - opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']])) + # Test + test(opt.cfg, + opt.data, + opt.weights, + opt.batch_size, + opt.img_size, + opt.conf_thres, + opt.nms_thres, + opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']])) + + # # Parameter study + # y = [] + # x = np.arange(0.4, 0.81, 0.1) + # for v in x: + # y.append(test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, 0.1, v, True)[0]) + # y = np.stack(y, 0) + # + # fig, ax = plt.subplots(1, 1, figsize=(12, 6)) + # ax.plot(x, y[:, 2], marker='.', label='mAP@0.5') + # ax.plot(x, y[:, 3], marker='.', label='mAP@0.5:0.95') + # ax.legend() + # fig.tight_layout() + # plt.savefig('parameters.jpg', dpi=200) diff --git a/train.py b/train.py index 3aeffe718c..936ba39e84 100644 --- a/train.py +++ b/train.py @@ -323,16 +323,15 @@ def train(): if opt.prebias: print_model_biases(model) elif not opt.notest or final_epoch: # Calculate mAP - with torch.no_grad(): - is_coco = any([x in data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) and model.nc == 80 - results, maps = test.test(cfg, - data, - batch_size=batch_size, - img_size=opt.img_size, - model=model, - conf_thres=0.001 if final_epoch else 0.1, # 0.1 for speed - save_json=final_epoch and is_coco, - dataloader=testloader) + is_coco = any([x in data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) and model.nc == 80 + results, maps = test.test(cfg, + data, + batch_size=batch_size, + img_size=opt.img_size, + model=model, + conf_thres=0.001 if final_epoch else 0.1, # 0.1 for speed + save_json=final_epoch and is_coco, + dataloader=testloader) # Write epoch results with open(results_file, 'a') as f: From 442dbb6acfeaf8ebfd978da292dd2ace77bcc6db Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 20 Dec 2019 09:08:57 -0800 Subject: [PATCH 0145/1185] updates --- test.py | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/test.py b/test.py index 4b33d761b0..9eb0cf897d 100644 --- a/test.py +++ b/test.py @@ -223,26 +223,29 @@ def test(cfg, opt = parser.parse_args() print(opt) - # Test - test(opt.cfg, - opt.data, - opt.weights, - opt.batch_size, - opt.img_size, - opt.conf_thres, - opt.nms_thres, - opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']])) - - # # Parameter study - # y = [] - # x = np.arange(0.4, 0.81, 0.1) - # for v in x: - # y.append(test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, 0.1, v, True)[0]) - # y = np.stack(y, 0) - # - # fig, ax = plt.subplots(1, 1, figsize=(12, 6)) - # ax.plot(x, y[:, 2], marker='.', label='mAP@0.5') - # ax.plot(x, y[:, 3], marker='.', label='mAP@0.5:0.95') - # ax.legend() - # fig.tight_layout() - # plt.savefig('parameters.jpg', dpi=200) + study = False + if not study: + # Test + test(opt.cfg, + opt.data, + opt.weights, + opt.batch_size, + opt.img_size, + opt.conf_thres, + opt.nms_thres, + opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']])) + else: + # Parameter study + y = [] + x = np.arange(0.4, 0.81, 0.1) + for v in x: + y.append(test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, 0.1, v, True)[0]) + y = np.stack(y, 0) + + # Plot + fig, ax = plt.subplots(1, 1, figsize=(10, 5)) + ax.plot(x, y[:, 2], marker='.', label='mAP@0.5') + ax.plot(x, y[:, 3], marker='.', label='mAP@0.5:0.95') + ax.legend() + fig.tight_layout() + plt.savefig('parameters.jpg', dpi=200) From 43e3bccc7366a3c9b1f929a71a53263b28d62c1c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 20 Dec 2019 09:10:35 -0800 Subject: [PATCH 0146/1185] updates --- test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test.py b/test.py index 9eb0cf897d..eed75e1d5d 100644 --- a/test.py +++ b/test.py @@ -237,7 +237,7 @@ def test(cfg, else: # Parameter study y = [] - x = np.arange(0.4, 0.81, 0.1) + x = np.arange(0.3, 0.9, 0.02) for v in x: y.append(test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, 0.1, v, True)[0]) y = np.stack(y, 0) @@ -247,5 +247,7 @@ def test(cfg, ax.plot(x, y[:, 2], marker='.', label='mAP@0.5') ax.plot(x, y[:, 3], marker='.', label='mAP@0.5:0.95') ax.legend() + ax.set_xlabel('nms_thr') + ax.set_ylabel('mAP') fig.tight_layout() plt.savefig('parameters.jpg', dpi=200) From 9420b4d4bccd9fc8cf4d46835ba72b3005fdf622 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 20 Dec 2019 09:23:33 -0800 Subject: [PATCH 0147/1185] updates --- test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index eed75e1d5d..e30f93eea4 100644 --- a/test.py +++ b/test.py @@ -221,6 +221,7 @@ def test(cfg, parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') opt = parser.parse_args() + opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) print(opt) study = False @@ -233,13 +234,16 @@ def test(cfg, opt.img_size, opt.conf_thres, opt.nms_thres, - opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']])) + opt.save_json) else: # Parameter study y = [] x = np.arange(0.3, 0.9, 0.02) for v in x: - y.append(test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, 0.1, v, True)[0]) + t = time.time() + r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, opt.conf_thres, v, opt.save_json)[0] + dt = [time.time() - t] + y.append(r + dt) y = np.stack(y, 0) # Plot From 25580dfb84965bfaf654deb3785d5a362ae3345e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 20 Dec 2019 09:44:21 -0800 Subject: [PATCH 0148/1185] updates --- test.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test.py b/test.py index e30f93eea4..a9d69dcea9 100644 --- a/test.py +++ b/test.py @@ -238,12 +238,11 @@ def test(cfg, else: # Parameter study y = [] - x = np.arange(0.3, 0.9, 0.02) + x = np.arange(0.3, 0.9, 0.1) for v in x: t = time.time() r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, opt.conf_thres, v, opt.save_json)[0] - dt = [time.time() - t] - y.append(r + dt) + y.append(r + (time.time() - t,)) y = np.stack(y, 0) # Plot From 05b1e437a0c88f27b5625ab84667a370190c271a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 20 Dec 2019 09:59:25 -0800 Subject: [PATCH 0149/1185] updates --- test.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/test.py b/test.py index a9d69dcea9..9968cb65d4 100644 --- a/test.py +++ b/test.py @@ -244,13 +244,17 @@ def test(cfg, r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, opt.conf_thres, v, opt.save_json)[0] y.append(r + (time.time() - t,)) y = np.stack(y, 0) + np.savetxt('study.txt', y, fmt='%10.4g') # Plot - fig, ax = plt.subplots(1, 1, figsize=(10, 5)) - ax.plot(x, y[:, 2], marker='.', label='mAP@0.5') - ax.plot(x, y[:, 3], marker='.', label='mAP@0.5:0.95') - ax.legend() - ax.set_xlabel('nms_thr') - ax.set_ylabel('mAP') + fig, ax = plt.subplots(2, 1, figsize=(6, 6)) + ax[0].plot(x, y[:, 2], marker='.', label='mAP@0.5') + ax[0].plot(x, y[:, 3], marker='.', label='mAP@0.5:0.95') + ax[0].legend() + ax[0].set_xlabel('nms_thr') + ax[0].set_ylabel('mAP') + ax[1].plot(x, y[:, -1], marker='.', label='time') + ax[1].set_xlabel('nms_thr') + ax[1].set_ylabel('time (s)') fig.tight_layout() - plt.savefig('parameters.jpg', dpi=200) + plt.savefig('study.jpg', dpi=200) From 821cf9a189fb256bfb0fdbf616c1d53d1ac198ff Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 20 Dec 2019 10:24:49 -0800 Subject: [PATCH 0150/1185] updates --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 9968cb65d4..e858d46dca 100644 --- a/test.py +++ b/test.py @@ -238,7 +238,7 @@ def test(cfg, else: # Parameter study y = [] - x = np.arange(0.3, 0.9, 0.1) + x = np.arange(0.3, 0.9, 0.05) for v in x: t = time.time() r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, opt.conf_thres, v, opt.save_json)[0] From 3854b933c30ecbab4ee3d07cfb31d10805ab7b6a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 20 Dec 2019 11:18:55 -0800 Subject: [PATCH 0151/1185] updates --- test.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/test.py b/test.py index e858d46dca..3cb7e992c5 100644 --- a/test.py +++ b/test.py @@ -238,7 +238,7 @@ def test(cfg, else: # Parameter study y = [] - x = np.arange(0.3, 0.9, 0.05) + x = np.arange(0.4, 0.9, 0.05) for v in x: t = time.time() r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, opt.conf_thres, v, opt.save_json)[0] @@ -247,14 +247,15 @@ def test(cfg, np.savetxt('study.txt', y, fmt='%10.4g') # Plot - fig, ax = plt.subplots(2, 1, figsize=(6, 6)) + fig, ax = plt.subplots(3, 1, figsize=(6, 6)) ax[0].plot(x, y[:, 2], marker='.', label='mAP@0.5') - ax[0].plot(x, y[:, 3], marker='.', label='mAP@0.5:0.95') - ax[0].legend() - ax[0].set_xlabel('nms_thr') ax[0].set_ylabel('mAP') - ax[1].plot(x, y[:, -1], marker='.', label='time') - ax[1].set_xlabel('nms_thr') - ax[1].set_ylabel('time (s)') + ax[1].plot(x, y[:, 3], marker='.', label='mAP@0.5:0.95') + ax[1].set_ylabel('mAP') + ax[2].plot(x, y[:, -1], marker='.', label='time') + ax[2].set_ylabel('time (s)') + for i in range(3): + ax[i].legend() + ax[i].set_xlabel('nms_thr') fig.tight_layout() plt.savefig('study.jpg', dpi=200) From 083d48256195b1028515d6ea4d63aeb31f6fbb56 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 20 Dec 2019 11:24:21 -0800 Subject: [PATCH 0152/1185] updates --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 3cb7e992c5..661bc24920 100644 --- a/test.py +++ b/test.py @@ -244,7 +244,7 @@ def test(cfg, r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, opt.conf_thres, v, opt.save_json)[0] y.append(r + (time.time() - t,)) y = np.stack(y, 0) - np.savetxt('study.txt', y, fmt='%10.4g') + np.savetxt('study.txt', y, fmt='%10.4g') # y = np.loadtxt('study.txt') # Plot fig, ax = plt.subplots(3, 1, figsize=(6, 6)) From 587b7a8dd069e1c7249e3eabf6364498285ef89c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 21 Dec 2019 09:32:47 -0800 Subject: [PATCH 0153/1185] updates --- utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index fc9abc6769..5c7dd82bdf 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -172,8 +172,8 @@ def ap_per_class(tp, conf, pred_cls, target_cls): ap, p, r = np.zeros(s), np.zeros(s), np.zeros(s) for ci, c in enumerate(unique_classes): i = pred_cls == c - n_gt = sum(target_cls == c) # Number of ground truth objects - n_p = sum(i) # Number of predicted objects + n_gt = (target_cls == c).sum() # Number of ground truth objects + n_p = i.sum() # Number of predicted objects if n_p == 0 or n_gt == 0: continue From 69da7e9da5a6fee87f90a7be1e11fc848c938264 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 21 Dec 2019 12:00:16 -0800 Subject: [PATCH 0154/1185] updates --- train.py | 4 +- utils/gcp.sh | 152 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 105 insertions(+), 51 deletions(-) diff --git a/train.py b/train.py index 936ba39e84..a83fa1c04e 100644 --- a/train.py +++ b/train.py @@ -467,7 +467,7 @@ def prebias(): if opt.bucket: os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket) # download evolve.txt if exists - for _ in range(1): # generations to evolve + for _ in range(100): # generations to evolve if os.path.exists('evolve.txt'): # if evolve.txt exists: select best hyps and mutate # Select parent(s) x = np.loadtxt('evolve.txt', ndmin=2) @@ -484,7 +484,7 @@ def prebias(): # Mutate np.random.seed(int(time.time())) - s = np.random.random() * 0.3 # sigma + s = np.random.random() * 0.15 # sigma g = [1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 1, 1, 1, 1, 1, 1, 1, 1] # gains for i, k in enumerate(hyp.keys()): x = (np.random.randn() * s * g[i] + 1) ** 2.0 # plt.hist(x.ravel(), 300) diff --git a/utils/gcp.sh b/utils/gcp.sh index d382dff055..3ee04ac92d 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -5,14 +5,17 @@ rm -rf sample_data yolov3 git clone https://github.com/ultralytics/yolov3 git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex sudo conda install -yc conda-forge scikit-image pycocotools -python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco.zip')" -sudo reboot +python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('193Zp_ye-3qXMonR1nZj3YyxMtQkMy50k','coco2014.zip')" +python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco2017.zip')" +sudo shutdown # Re-clone rm -rf yolov3 # Warning: remove existing -git clone https://github.com/ultralytics/yolov3 && cd yolov3 # master +git clone https://github.com/ultralytics/yolov3 # master +bash yolov3/data/get_coco2017.sh # git clone -b test --depth 1 https://github.com/ultralytics/yolov3 test # branch -python3 train.py --img-size 320 --weights weights/darknet53.conv.74 --epochs 27 --batch-size 64 --accumulate 1 +cd yolov3 +python3 train.py --weights '' --epochs 27 --batch-size 32 --accumulate 2 --nosave --data coco2017.data # Train python3 train.py @@ -27,14 +30,24 @@ python3 detect.py python3 test.py --save-json # Evolve -export t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t +for i in 1 2 3 4 5 6 7 +do + export t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch-size 64 --accumulate 1 --evolve --weights '' --pre --arc default --bucket yolov4/320_coco2014_27e --device $i + sleep 30 +done + +export t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco16.data --img-size 320 --epochs 1 --batch-size 8 --accumulate 1 --evolve --weights '' --device 1 + + +export t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t clear -sleep 200 +sleep 0 while true do - python3 train.py --data data/coco.data --img-size 416 --epochs 27 --batch-size 32 --accumulate 2 --evolve --weights '' --prebias --bucket yolov4/416_coco_27e --device 7 + python3 train.py --data coco2014.data --img-size 416 --epochs 27 --batch-size 32 --accumulate 2 --evolve --weights '' --pre --bucket yolov4/416_coco_27e --device 2 done + # Git pull git pull https://github.com/ultralytics/yolov3 # master git pull https://github.com/ultralytics/yolov3 test # branch @@ -93,52 +106,93 @@ sudo docker pull ultralytics/yolov3:v0 sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco ultralytics/yolov3:v0 -export t=ultralytics/yolov3:v70 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 70 --device 0 --multi -export t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 71 --device 0 --multi --img-weights - -export t=ultralytics/yolov3:v73 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 73 --device 5 --cfg cfg/yolov3s.cfg -export t=ultralytics/yolov3:v74 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 74 --device 0 --cfg cfg/yolov3s.cfg -export t=ultralytics/yolov3:v75 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 75 --device 7 --cfg cfg/yolov3s.cfg -export t=ultralytics/yolov3:v76 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 76 --device 0 --cfg cfg/yolov3-spp.cfg - -export t=ultralytics/yolov3:v79 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 79 --device 5 -export t=ultralytics/yolov3:v80 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 80 --device 0 -export t=ultralytics/yolov3:v81 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 81 --device 7 -export t=ultralytics/yolov3:v82 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 82 --device 0 --cfg cfg/yolov3s.cfg +export t=ultralytics/yolov3:v70 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 70 --device 0 --multi +export t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 71 --device 0 --multi --img-weights -export t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 83 --device 1 --multi -export t=ultralytics/yolov3:v84 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 84 --device 0 --multi -export t=ultralytics/yolov3:v85 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 85 --device 0 --multi -export t=ultralytics/yolov3:v86 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 86 --device 1 --multi -export t=ultralytics/yolov3:v87 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 87 --device 2 --multi -export t=ultralytics/yolov3:v88 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 88 --device 3 --multi -export t=ultralytics/yolov3:v89 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 89 --device 1 -export t=ultralytics/yolov3:v90 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 90 --device 0 --cfg cfg/yolov3-spp-matrix.cfg -export t=ultralytics/yolov3:v91 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 91 --device 0 --cfg cfg/yolov3-spp-matrix.cfg +export t=ultralytics/yolov3:v73 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 73 --device 5 --cfg cfg/yolov3s.cfg +export t=ultralytics/yolov3:v74 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 74 --device 0 --cfg cfg/yolov3s.cfg +export t=ultralytics/yolov3:v75 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 75 --device 7 --cfg cfg/yolov3s.cfg +export t=ultralytics/yolov3:v76 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 76 --device 0 --cfg cfg/yolov3-spp.cfg +export t=ultralytics/yolov3:v79 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 79 --device 5 +export t=ultralytics/yolov3:v80 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 80 --device 0 +export t=ultralytics/yolov3:v81 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 81 --device 7 +export t=ultralytics/yolov3:v82 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 82 --device 0 --cfg cfg/yolov3s.cfg -export t=ultralytics/yolov3:v92 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch-size 16 --accumulate 4 --prebias --bucket yolov4 --name 92 --device 0 - +export t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 83 --device 6 --multi --nosave +export t=ultralytics/yolov3:v84 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 84 --device 0 --multi +export t=ultralytics/yolov3:v85 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 85 --device 0 --multi +export t=ultralytics/yolov3:v86 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 86 --device 1 --multi +export t=ultralytics/yolov3:v87 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 87 --device 2 --multi +export t=ultralytics/yolov3:v88 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 88 --device 3 --multi +export t=ultralytics/yolov3:v89 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 89 --device 1 +export t=ultralytics/yolov3:v90 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 90 --device 0 --cfg cfg/yolov3-spp-matrix.cfg +export t=ultralytics/yolov3:v91 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 91 --device 0 --cfg cfg/yolov3-spp-matrix.cfg +export t=ultralytics/yolov3:v92 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 92 --device 0 +export t=ultralytics/yolov3:v93 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 93 --device 0 --cfg cfg/yolov3-spp-matrix.cfg #SM4 -export t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host --mount type=bind,source="$(pwd)"/data,target=/usr/src/data $t python3 train.py --weights 'ultralytics49.pt' --epochs 500 --img-size 320 --batch-size 32 --accumulate 2 --prebias --bucket yolov4 --name 78 --device 0 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data - - -export t=ultralytics/yolov3:v2 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t -clear -sleep 120 -while true -do - python3 train.py --weights '' --epochs 27 --batch-size 32 --accumulate 2 --prebias --evolve --device 7 --bucket yolov4/416_coco_27e -done - - -while true; do python3 train.py --data data/coco.data --img-size 320 --batch-size 64 --accumulate 1 --evolve --epochs 1 --adam --bucket yolov4/adamdefaultpw_coco_1e; done - - - - - - +export t=ultralytics/yolov3:v96 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img-size 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 96 --device 0 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +export t=ultralytics/yolov3:v97 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img-size 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 97 --device 4 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +export t=ultralytics/yolov3:v98 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img-size 320 --batch 16 --accum 4 --pre --bucket yolov4 --name 98 --device 5 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +export t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --pre --bucket yolov4 --name 101 --device 7 --multi --nosave + +export t=ultralytics/yolov3:v102 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 1000 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 102 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +export t=ultralytics/yolov3:v103 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 103 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +export t=ultralytics/yolov3:v104 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 104 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +export t=ultralytics/yolov3:v105 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 105 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +export t=ultralytics/yolov3:v106 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 106 --device 0 --cfg cfg/yolov3-tiny-3cls-sm4.cfg --data ../data/sm4/out.data --nosave --cache +export t=ultralytics/yolov3:v107 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 107 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg +export t=ultralytics/yolov3:v108 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 108 --device 7 --nosave + +export t=ultralytics/yolov3:v109 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 109 --device 4 --multi --nosave +export t=ultralytics/yolov3:v110 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 110 --device 3 --multi --nosave + +export t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 111 --device 0 +export t=ultralytics/yolov3:v112 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 112 --device 1 --nosave +export t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 113 --device 2 --nosave +export t=ultralytics/yolov3:v114 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 114 --device 2 --nosave +export t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 115 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg +export t=ultralytics/yolov3:v116 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 116 --device 1 --nosave + +export t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 117 --device 0 --nosave --multi +export t=ultralytics/yolov3:v118 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 118 --device 5 --nosave --multi +export t=ultralytics/yolov3:v119 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 119 --device 1 --nosave +export t=ultralytics/yolov3:v120 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 120 --device 2 --nosave +export t=ultralytics/yolov3:v121 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 121 --device 0 --nosave --cfg cfg/csresnext50-panet-spp.cfg +export t=ultralytics/yolov3:v122 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 122 --device 2 --nosave +export t=ultralytics/yolov3:v123 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 123 --device 5 --nosave + +export t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 124 --device 0 --nosave --cfg yolov3-tiny +export t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 125 --device 1 --nosave --cfg yolov3-tiny2 +export t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 126 --device 1 --nosave --cfg yolov3-tiny3 +export t=ultralytics/yolov3:v127 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 127 --device 0 --nosave --cfg yolov3-tiny4 +export t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 128 --device 1 --nosave --cfg yolov3-tiny2 --multi +export t=ultralytics/yolov3:v129 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 129 --device 0 --nosave --cfg yolov3-tiny2 + +export t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 130 --device 0 --nosave +export t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 250 --pre --bucket yolov4 --name 131 --device 0 --nosave --multi +export t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 132 --device 0 --nosave --data coco2014.data +export t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 27 --pre --bucket yolov4 --name 133 --device 0 --nosave --multi +export t=ultralytics/yolov3:v134 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 134 --device 0 --nosave --data coco2014.data + +export t=ultralytics/yolov3:v135 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 135 --device 0 --nosave --multi --data coco2014.data +export t=ultralytics/yolov3:v136 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 136 --device 0 --nosave --multi --data coco2014.data + +export t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 137 --device 7 --nosave --data coco2014.data +export t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --bucket yolov4 --name 138 --device 6 --nosave --data coco2014.data + +export t=ultralytics/yolov3:v140 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 140 --device 1 --nosave --data coco2014.data --arc uBCE +export t=ultralytics/yolov3:v141 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 141 --device 0 --nosave --data coco2014.data --arc uBCE +export t=ultralytics/yolov3:v142 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 142 --device 1 --nosave --data coco2014.data --arc uBCE + + +export t=ultralytics/yolov3:v139 && sudo docker build -t $t . && sudo docker push $t + +conda update -n base -c defaults conda +conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython future +conda install -yc conda-forge scikit-image pycocotools onnx tensorboard +conda install -yc spyder-ide spyder-line-profiler +conda install -yc pytorch pytorch torchvision \ No newline at end of file From 3e33adb93502e3b292a43ecd855e6882c8b1bd5d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 21 Dec 2019 19:23:50 -0800 Subject: [PATCH 0155/1185] updates --- data/get_coco2017.sh | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/data/get_coco2017.sh b/data/get_coco2017.sh index 69a29761fb..249a54544a 100755 --- a/data/get_coco2017.sh +++ b/data/get_coco2017.sh @@ -15,17 +15,10 @@ unzip -q ${filename} # for coco.zip # tar -xzf ${filename} # for coco.tar.gz rm ${filename} -# Download images +# Download and unzip images cd coco/images -curl http://images.cocodataset.org/zips/train2017.zip -o train2017.zip -curl http://images.cocodataset.org/zips/val2017.zip -o val2017.zip - -# Unzip images -unzip -q train2017.zip -unzip -q val2017.zip - -# (optional) Delete zip files -rm -rf *.zip +f="train2017.zip" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f +f="val2017.zip" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f # cd out cd ../.. From d56efafee1b8e6e6e8f68936d3e8c26e3d12acda Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 21 Dec 2019 19:30:22 -0800 Subject: [PATCH 0156/1185] updates --- data/get_coco2014.sh | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/data/get_coco2014.sh b/data/get_coco2014.sh index cb2fe21eb5..300b690b78 100755 --- a/data/get_coco2014.sh +++ b/data/get_coco2014.sh @@ -16,18 +16,10 @@ unzip -q ${filename} # for coco.zip # tar -xzf ${filename} # for coco.tar.gz rm ${filename} -# Download images +# Download and unzip images cd coco/images -curl http://images.cocodataset.org/zips/train2014.zip -o train2014.zip -curl http://images.cocodataset.org/zips/val2014.zip -o val2014.zip - -# Unzip images -unzip -q train2014.zip -unzip -q val2014.zip - -# (optional) Delete zip files -rm -rf *.zip +f="train2014.zip" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f +f="val2014.zip" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f # cd out cd ../.. - From 66fe3db8fbd59bec98d45e46b97db02ea914cbde Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 21 Dec 2019 19:39:45 -0800 Subject: [PATCH 0157/1185] updates --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index f53dc69236..39ab1ee43e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,13 +44,13 @@ COPY . /usr/src/app # --------------------------------------------------- Extras Below --------------------------------------------------- # Build and Push -# export t=ultralytics/yolov3:v0 && sudo docker build -t $t . && sudo docker push $t +# t=ultralytics/yolov3:v0 && sudo docker build -t $t . && sudo docker push $t # Run # sudo nvidia-docker run --ipc=host ultralytics/yolov3:v0 python3 detect.py # Pull and Run with local directory access -# export t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t +# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t # Kill all # sudo docker kill "$(sudo docker ps -q)" From b7a53957b3500e2c8638a25604de468a1670cd47 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 21 Dec 2019 19:47:49 -0800 Subject: [PATCH 0158/1185] updates --- train.py | 2 +- utils/evolve.sh | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 utils/evolve.sh diff --git a/train.py b/train.py index a83fa1c04e..20efba44ad 100644 --- a/train.py +++ b/train.py @@ -446,7 +446,7 @@ def prebias(): mixed_precision = False # scale hyp['obj'] by img_size (evolved at 416) - hyp['obj'] *= opt.img_size / 416. + hyp['obj'] *= opt.img_size / 320. tb_writer = None if not opt.evolve: # Train normally diff --git a/utils/evolve.sh b/utils/evolve.sh new file mode 100644 index 0000000000..34e3d2235d --- /dev/null +++ b/utils/evolve.sh @@ -0,0 +1,10 @@ +#for i in 1 2 3 4 5 6 7 +#do +# t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run --d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t utils/evolve.sh $i +# sleep 30 +# done + +while true +do + python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch-size 64 --accumulate 1 --evolve --weights '' --pre --bucket yolov4/320_coco2014_27e --device $1 +done \ No newline at end of file From 5e203d3b1a9c755fcee945ed871f47657b206c22 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 21 Dec 2019 19:48:07 -0800 Subject: [PATCH 0159/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 20efba44ad..a83fa1c04e 100644 --- a/train.py +++ b/train.py @@ -446,7 +446,7 @@ def prebias(): mixed_precision = False # scale hyp['obj'] by img_size (evolved at 416) - hyp['obj'] *= opt.img_size / 320. + hyp['obj'] *= opt.img_size / 416. tb_writer = None if not opt.evolve: # Train normally From acdbaa7702aa37c3df001aba82ceb43ca519c263 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 21 Dec 2019 19:56:52 -0800 Subject: [PATCH 0160/1185] updates --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index a83fa1c04e..4db2afc343 100644 --- a/train.py +++ b/train.py @@ -467,7 +467,7 @@ def prebias(): if opt.bucket: os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket) # download evolve.txt if exists - for _ in range(100): # generations to evolve + for _ in range(1): # generations to evolve if os.path.exists('evolve.txt'): # if evolve.txt exists: select best hyps and mutate # Select parent(s) x = np.loadtxt('evolve.txt', ndmin=2) @@ -484,7 +484,7 @@ def prebias(): # Mutate np.random.seed(int(time.time())) - s = np.random.random() * 0.15 # sigma + s = np.random.random() * 0.10 # sigma g = [1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 1, 1, 1, 1, 1, 1, 1, 1] # gains for i, k in enumerate(hyp.keys()): x = (np.random.randn() * s * g[i] + 1) ** 2.0 # plt.hist(x.ravel(), 300) From efb3768fff92e71cc0930b33d1073d6789473580 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 21 Dec 2019 20:10:55 -0800 Subject: [PATCH 0161/1185] updates --- utils/evolve.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/evolve.sh b/utils/evolve.sh index 34e3d2235d..08e0c38a6a 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -1,3 +1,5 @@ +#!/usr/bin/env bash + #for i in 1 2 3 4 5 6 7 #do # t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run --d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t utils/evolve.sh $i From f00de5454630cd165ce7ba15a18504cdfd4ad5a2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 21 Dec 2019 20:17:56 -0800 Subject: [PATCH 0162/1185] updates --- train.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 4db2afc343..374c8ffb6f 100644 --- a/train.py +++ b/train.py @@ -25,7 +25,7 @@ hyp = {'giou': 3.54, # giou loss gain 'cls': 37.4, # cls loss gain 'cls_pw': 1.0, # cls BCELoss positive_weight - 'obj': 64.3, # obj loss gain (*=img_size/416 if img_size != 416) + 'obj': 49.5, # obj loss gain (*=img_size/320 if img_size != 320) 'obj_pw': 1.0, # obj BCELoss positive_weight 'iou_t': 0.225, # iou training threshold 'lr0': 0.00579, # initial learning rate (SGD=1E-3, Adam=9E-5) @@ -445,8 +445,8 @@ def prebias(): if device.type == 'cpu': mixed_precision = False - # scale hyp['obj'] by img_size (evolved at 416) - hyp['obj'] *= opt.img_size / 416. + # scale hyp['obj'] by img_size (evolved at 320) + hyp['obj'] *= opt.img_size / 320. tb_writer = None if not opt.evolve: # Train normally From 707ce8cacb11e09723fdab50bfa4e9b303efc3b6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 21 Dec 2019 20:45:00 -0800 Subject: [PATCH 0163/1185] updates --- models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index d540981a78..cf59daefe2 100755 --- a/models.py +++ b/models.py @@ -82,9 +82,9 @@ def create_modules(module_defs, img_size, arc): # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) try: if arc == 'defaultpw' or arc == 'Fdefaultpw': # default with positive weights - b = [-4, -3.6] # obj, cls + b = [-5.0, -5.0] # obj, cls elif arc == 'default': # default no pw (40 cls, 80 obj) - b = [-5.5, -5.0] + b = [-5.0, -5.0] elif arc == 'uBCE': # unified BCE (80 classes) b = [0, -9.0] elif arc == 'uCE': # unified CE (1 background + 80 classes) From c693219e57a530b66cbb464526e09fbb11d893cc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 22 Dec 2019 08:12:23 -0800 Subject: [PATCH 0164/1185] updates --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index dfb5cd9079..08b1bdbad3 100755 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ Pillow # future # Conda commands (in place of pip) --------------------------------------------- -# conda update -n base -c defaults conda +# conda update -yn base -c defaults conda # conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython future # conda install -yc conda-forge scikit-image pycocotools onnx tensorboard # conda install -yc spyder-ide spyder-line-profiler From 8aeef8da72a6231b14d54228a16a8dd48267c189 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 22 Dec 2019 11:08:02 -0800 Subject: [PATCH 0165/1185] updates --- data/get_coco2014.sh | 1 - data/get_coco2017.sh | 1 - 2 files changed, 2 deletions(-) diff --git a/data/get_coco2014.sh b/data/get_coco2014.sh index 300b690b78..2125cf1f8f 100755 --- a/data/get_coco2014.sh +++ b/data/get_coco2014.sh @@ -6,7 +6,6 @@ # Download labels from Google Drive, accepting presented query filename="coco2014labels.zip" fileid="1s6-CmF5_SElM28r52P1OUrCcuXZN-SFo" - curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" > /dev/null curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}" -o ${filename} rm ./cookie diff --git a/data/get_coco2017.sh b/data/get_coco2017.sh index 249a54544a..30f60b5b6c 100755 --- a/data/get_coco2017.sh +++ b/data/get_coco2017.sh @@ -22,4 +22,3 @@ f="val2017.zip" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q # cd out cd ../.. - From 5766b5c55509cb9ab31147020866c2e03ff01c22 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 22 Dec 2019 13:03:45 -0800 Subject: [PATCH 0166/1185] updates --- test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index 661bc24920..5a85bbe47e 100644 --- a/test.py +++ b/test.py @@ -88,8 +88,8 @@ def test(cfg, if hasattr(model, 'hyp'): # if model has loss hyperparameters loss += compute_loss(train_out, targets, model)[1][:3].cpu() # GIoU, obj, cls - # Run NMS - output = non_max_suppression(inf_out, conf_thres=conf_thres, nms_thres=nms_thres) + # Run NMS + output = non_max_suppression(inf_out, conf_thres=conf_thres, nms_thres=nms_thres) # Statistics per image for si, pred in enumerate(output): From 8a5c52029178156fce382a3ea89f2fd4d6f60e50 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 22 Dec 2019 13:04:05 -0800 Subject: [PATCH 0167/1185] updates --- test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test.py b/test.py index 5a85bbe47e..bdcf8cf513 100644 --- a/test.py +++ b/test.py @@ -80,7 +80,6 @@ def test(cfg, # Disable gradients with torch.no_grad(): - # Run model inf_out, train_out = model(imgs) # inference and training outputs From a96285870de3a06f12842af33bd2b9e041375c9d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 22 Dec 2019 13:04:44 -0800 Subject: [PATCH 0168/1185] updates --- utils/utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 5c7dd82bdf..e3f1f7e502 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -466,8 +466,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru Returns detections with shape: (x1, y1, x2, y2, object_conf, conf, class) """ - # NMS method https://github.com/ultralytics/yolov3/issues/679 'or', 'and', 'merge', 'vision', 'vision_batch' - # method = 'merge' if conf_thres <= 0.01 else 'vision' # MERGE is highest mAP, VISION is fastest + # NMS methods https://github.com/ultralytics/yolov3/issues/679 'or', 'and', 'merge', 'vision', 'vision_batch' # Box constraints min_wh, max_wh = 2, 10000 # (pixels) minimum and maximium box width and height From e0833ed21e23ee21b9b4f67c1ce6e68f70398c01 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 22 Dec 2019 13:07:00 -0800 Subject: [PATCH 0169/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index e3f1f7e502..02bb8b2ba4 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -444,7 +444,7 @@ def build_targets(model, targets): gi, gj = gxy.long().t() # grid x, y indices indices.append((b, a, gj, gi)) - # GIoU + # Box gxy -= gxy.floor() # xy tbox.append(torch.cat((gxy, gwh), 1)) # xywh (grids) av.append(anchor_vec[a]) # anchor vec From 62516f191966617346b111436a7159ead537ffdf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 22 Dec 2019 13:26:46 -0800 Subject: [PATCH 0170/1185] updates --- utils/utils.py | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 02bb8b2ba4..35c040ff53 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -284,21 +284,46 @@ def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False): return iou +def box_iou(boxes1, boxes2): + # https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py + """ + Return intersection-over-union (Jaccard index) of boxes. + Both sets of boxes are expected to be in (x1, y1, x2, y2) format. + Arguments: + boxes1 (Tensor[N, 4]) + boxes2 (Tensor[M, 4]) + Returns: + iou (Tensor[N, M]): the NxM matrix containing the pairwise + IoU values for every element in boxes1 and boxes2 + """ + + def box_area(boxes): + return (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1]) + + area1 = box_area(boxes1) + area2 = box_area(boxes2) + + lt = torch.max(boxes1[:, None, :2], boxes2[:, :2]) # [N,M,2] + rb = torch.min(boxes1[:, None, 2:], boxes2[:, 2:]) # [N,M,2] + + wh = (rb - lt).clamp(min=0) # [N,M,2] + inter = wh[:, :, 0] * wh[:, :, 1] # [N,M] + + iou = inter / (area1[:, None] + area2 - inter) + return iou + + def wh_iou(box1, box2): - # Returns the IoU of wh1 to wh2. wh1 is 2, wh2 is nx2 - box2 = box2.t() + # Returns the IoU of wh1 to wh2. wh1 is 2, wh2 is 2xn # w, h = box1 w1, h1 = box1[0], box1[1] w2, h2 = box2[0], box2[1] # Intersection area - inter_area = torch.min(w1, w2) * torch.min(h1, h2) - - # Union Area - union_area = (w1 * h1 + 1e-16) + w2 * h2 - inter_area + inter = torch.min(w1, w2) * torch.min(h1, h2) - return inter_area / union_area # iou + return inter / (w1 * h1 + w2 * h2 - inter) # iou = inter / (area1 + area2 - inter) class FocalLoss(nn.Module): @@ -422,8 +447,9 @@ def build_targets(model, targets): # iou of targets-anchors t, a = targets, [] gwh = t[:, 4:6] * ng + gwht = gwh.t() if nt: - iou = torch.stack([wh_iou(x, gwh) for x in anchor_vec], 0) + iou = torch.stack([wh_iou(x, gwht) for x in anchor_vec], 0) if use_all_anchors: na = len(anchor_vec) # number of anchors From 654b9834c2930a1fe3fda0522f5942bd4a8113c2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 22 Dec 2019 13:28:51 -0800 Subject: [PATCH 0171/1185] updates --- utils/utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 35c040ff53..cc31410251 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -315,8 +315,6 @@ def box_area(boxes): def wh_iou(box1, box2): # Returns the IoU of wh1 to wh2. wh1 is 2, wh2 is 2xn - - # w, h = box1 w1, h1 = box1[0], box1[1] w2, h2 = box2[0], box2[1] From a0b4d17f7efa8b6f4aa8ed4e33148004e4b77cf3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 22 Dec 2019 14:05:40 -0800 Subject: [PATCH 0172/1185] updates --- utils/utils.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index cc31410251..18ccb514e7 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -313,15 +313,12 @@ def box_area(boxes): return iou -def wh_iou(box1, box2): - # Returns the IoU of wh1 to wh2. wh1 is 2, wh2 is 2xn - w1, h1 = box1[0], box1[1] - w2, h2 = box2[0], box2[1] - - # Intersection area - inter = torch.min(w1, w2) * torch.min(h1, h2) - - return inter / (w1 * h1 + w2 * h2 - inter) # iou = inter / (area1 + area2 - inter) +def wh_iou(wh1, wh2): + # Returns the nxm IoU matrix. wh1 is nx2, wh2 is mx2 + wh1 = wh1[:, None] # [N,1,2] + wh2 = wh2[None] # [1,M,2] + inter = torch.min(wh1, wh2).prod(2) # [N,M] + return inter / (wh1.prod(2) + wh2.prod(2) - inter) # iou = inter / (area1 + area2 - inter) class FocalLoss(nn.Module): @@ -445,9 +442,8 @@ def build_targets(model, targets): # iou of targets-anchors t, a = targets, [] gwh = t[:, 4:6] * ng - gwht = gwh.t() if nt: - iou = torch.stack([wh_iou(x, gwht) for x in anchor_vec], 0) + iou = wh_iou(anchor_vec, gwh) if use_all_anchors: na = len(anchor_vec) # number of anchors From 0e54731bb8313dd37f9bae2c397e32ec8f8050b1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 22 Dec 2019 14:19:46 -0800 Subject: [PATCH 0173/1185] updates --- utils/utils.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 18ccb514e7..8d37e62b4f 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -253,21 +253,21 @@ def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False): b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2 # Intersection area - inter_area = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \ - (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0) + inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \ + (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0) # Union Area w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 - union_area = (w1 * h1 + 1e-16) + w2 * h2 - inter_area + union = (w1 * h1 + 1e-16) + w2 * h2 - inter - iou = inter_area / union_area # iou + iou = inter / union # iou if GIoU or DIoU or CIoU: cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1) # convex (smallest enclosing box) width ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1) # convex height if GIoU: # Generalized IoU https://arxiv.org/pdf/1902.09630.pdf c_area = cw * ch + 1e-16 # convex area - return iou - (c_area - union_area) / c_area # GIoU + return iou - (c_area - union) / c_area # GIoU if DIoU or CIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1 # convex diagonal squared c2 = cw ** 2 + ch ** 2 + 1e-16 @@ -297,20 +297,18 @@ def box_iou(boxes1, boxes2): IoU values for every element in boxes1 and boxes2 """ - def box_area(boxes): - return (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1]) + def box_area(box): + # box = 4xn + return (box[2] - box[0]) * (box[3] - box[1]) - area1 = box_area(boxes1) - area2 = box_area(boxes2) + area1 = box_area(boxes1.t()) + area2 = box_area(boxes2.t()) lt = torch.max(boxes1[:, None, :2], boxes2[:, :2]) # [N,M,2] rb = torch.min(boxes1[:, None, 2:], boxes2[:, 2:]) # [N,M,2] - wh = (rb - lt).clamp(min=0) # [N,M,2] - inter = wh[:, :, 0] * wh[:, :, 1] # [N,M] - - iou = inter / (area1[:, None] + area2 - inter) - return iou + inter = (rb - lt).clamp(min=0).prod(2) # [N,M] + return inter / (area1[:, None] + area2 - inter) # iou = inter / (area1 + area2 - inter) def wh_iou(wh1, wh2): From 0e17fb5905ec5a335f86c5b17a945691c09d568e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 22 Dec 2019 16:05:43 -0800 Subject: [PATCH 0174/1185] updates --- test.py | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/test.py b/test.py index bdcf8cf513..dc6c9f507f 100644 --- a/test.py +++ b/test.py @@ -126,7 +126,7 @@ def test(cfg, # Assign all predictions as incorrect correct = torch.zeros(len(pred), niou) if nl: - detected = [] + detected = [] # target indices tcls_tensor = labels[:, 0] # target boxes @@ -134,26 +134,24 @@ def test(cfg, tbox[:, [0, 2]] *= width tbox[:, [1, 3]] *= height - # Search for correct predictions - for i, (*pbox, _, pcls) in enumerate(pred): - - # Break if all targets already located in image - if len(detected) == nl: - break - - # Continue if predicted class not among image classes - if pcls.item() not in tcls: - continue - - # Best iou, index between pred and targets - m = (pcls == tcls_tensor).nonzero().view(-1) - iou, j = bbox_iou(pbox, tbox[m]).max(0) - m = m[j] - - # Per iou_thres 'correct' vector - if iou > iou_thres[0] and m not in detected: - detected.append(m) - correct[i] = iou > iou_thres + # Per target class + for cls in torch.unique(tcls_tensor): + ti = (cls == tcls_tensor).nonzero().view(-1) # prediction indices + pi = (cls == pred[:, 5]).nonzero().view(-1) # target indices + + # Search for detections + if len(pi): + # Prediction to target ious + ious, i = box_iou(pred[pi, :4], tbox[ti]).max(1) # best ious, indices + + # Append detections + for j in (ious > iou_thres[0]).nonzero(): + d = ti[i[j]] # detected target + if d not in detected: + detected.append(d) + correct[pi[j]] = (ious[j] > iou_thres).float() # iou_thres is 1xn + if len(detected) == nl: # all targets already located in image + break # Append statistics (correct, conf, pcls, tcls) stats.append((correct, pred[:, 4].cpu(), pred[:, 5].cpu(), tcls)) From 52573eb0bc02fc4b7afa71fdd4c561d8c02a1bed Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 22 Dec 2019 16:21:17 -0800 Subject: [PATCH 0175/1185] updates --- test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test.py b/test.py index dc6c9f507f..b05be9ad13 100644 --- a/test.py +++ b/test.py @@ -130,9 +130,7 @@ def test(cfg, tcls_tensor = labels[:, 0] # target boxes - tbox = xywh2xyxy(labels[:, 1:5]) - tbox[:, [0, 2]] *= width - tbox[:, [1, 3]] *= height + tbox = xywh2xyxy(labels[:, 1:5]) * torch.Tensor([width, height, width, height]).to(device) # Per target class for cls in torch.unique(tcls_tensor): From d391f6d59b9dad9e222b0608d81d0662e9b0de3a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 22 Dec 2019 17:36:51 -0800 Subject: [PATCH 0176/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 374c8ffb6f..01c865a745 100644 --- a/train.py +++ b/train.py @@ -484,7 +484,7 @@ def prebias(): # Mutate np.random.seed(int(time.time())) - s = np.random.random() * 0.10 # sigma + s = np.random.random() * 0.2 # sigma g = [1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 1, 1, 1, 1, 1, 1, 1, 1] # gains for i, k in enumerate(hyp.keys()): x = (np.random.randn() * s * g[i] + 1) ** 2.0 # plt.hist(x.ravel(), 300) From 80692334f45e75251b9ec20b7c67b22cfc8fba48 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 08:25:40 -0800 Subject: [PATCH 0177/1185] updates --- utils/evolve.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/utils/evolve.sh b/utils/evolve.sh index 08e0c38a6a..b20623f4e8 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -1,5 +1,4 @@ -#!/usr/bin/env bash - +#!/bin/bash #for i in 1 2 3 4 5 6 7 #do # t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run --d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t utils/evolve.sh $i @@ -9,4 +8,4 @@ while true do python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch-size 64 --accumulate 1 --evolve --weights '' --pre --bucket yolov4/320_coco2014_27e --device $1 -done \ No newline at end of file +done From 61009dbde89cb5f3feea257fe5a23e777f75b534 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 08:27:21 -0800 Subject: [PATCH 0178/1185] updates --- utils/evolve.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/utils/evolve.sh b/utils/evolve.sh index b20623f4e8..dd89fbed47 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -5,7 +5,6 @@ # sleep 30 # done -while true -do - python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch-size 64 --accumulate 1 --evolve --weights '' --pre --bucket yolov4/320_coco2014_27e --device $1 +while true; do +python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch-size 64 --accumulate 1 --evolve --weights '' --pre --bucket yolov4/320_coco2014_27e --device $1 done From dd5ead5b1db54faf565a3ab31b994999aab0ce26 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 10:10:24 -0800 Subject: [PATCH 0179/1185] updates --- models.py | 8 ++------ utils/utils.py | 14 +++++++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/models.py b/models.py index cf59daefe2..488154524a 100755 --- a/models.py +++ b/models.py @@ -152,7 +152,6 @@ def __init__(self, anchors, nc, img_size, yolo_index, arc): self.no = nc + 5 # number of outputs self.nx = 0 # initialize number of x gridpoints self.ny = 0 # initialize number of y gridpoints - self.oi = [0, 1, 2, 3] + list(range(5, self.no)) # output indices self.arc = arc if ONNX_EXPORT: # grids must be computed in __init__ @@ -210,7 +209,7 @@ def forward(self, p, img_size, var=None): io[..., :4] *= self.stride if 'default' in self.arc: # seperate obj and cls - torch.sigmoid_(io[..., 4:]) + torch.sigmoid_(io[..., 4]) elif 'BCE' in self.arc: # unified BCE (80 classes) torch.sigmoid_(io[..., 5:]) io[..., 4] = 1 @@ -221,11 +220,8 @@ def forward(self, p, img_size, var=None): if self.nc == 1: io[..., 5] = 1 # single-class model https://github.com/ultralytics/yolov3/issues/235 - # compute conf - io[..., 5:] *= io[..., 4:5] # conf = obj_conf * cls_conf - # reshape from [1, 3, 13, 13, 85] to [1, 507, 84], remove obj_conf - return io[..., self.oi].view(bs, -1, self.no - 1), p + return io.view(bs, -1, self.no), p class Darknet(nn.Module): diff --git a/utils/utils.py b/utils/utils.py index 8d37e62b4f..c75d307795 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -492,9 +492,13 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru output = [None] * len(prediction) for image_i, pred in enumerate(prediction): # Remove rows - pred = pred[(pred[:, 4:] > conf_thres).any(1)] # retain above threshold + pred = pred[pred[:, 4] > conf_thres] # retain above threshold - # Select only suitable predictions + # compute conf + torch.sigmoid_(pred[..., 5:]) + pred[..., 5:] *= pred[..., 4:5] # conf = obj_conf * cls_conf + + # Apply width-height constraint i = (pred[:, 2:4] > min_wh).all(1) & (pred[:, 2:4] < max_wh).all(1) & torch.isfinite(pred).all(1) pred = pred[i] @@ -507,10 +511,10 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru # Multi-class if multi_cls or conf_thres < 0.01: - i, j = (pred[:, 4:] > conf_thres).nonzero().t() - pred = torch.cat((pred[i, :4], pred[i, j + 4].unsqueeze(1), j.float().unsqueeze(1)), 1) + i, j = (pred[:, 5:] > conf_thres).nonzero().t() + pred = torch.cat((pred[i, :4], pred[i, j + 5].unsqueeze(1), j.float().unsqueeze(1)), 1) else: # best class only - conf, j = pred[:, 4:].max(1) + conf, j = pred[:, 5:].max(1) pred = torch.cat((pred[:, :4], conf.unsqueeze(1), j.float().unsqueeze(1)), 1) # (xyxy, conf, cls) # Get detections sorted by decreasing confidence scores From a51d83df3393f23f3a59172578c5890d1474cac5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 10:11:12 -0800 Subject: [PATCH 0180/1185] updates --- utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index c75d307795..ef372ee7f2 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -528,8 +528,8 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru # Non-maximum suppression det_max = [] - for c in pred[:, -1].unique(): - dc = pred[pred[:, -1] == c] # select class c + for c in j.unique(): + dc = pred[j == c] # select class c n = len(dc) if n == 1: det_max.append(dc) # No NMS required if only 1 prediction From a5160b44caf9c67e18addd3e9c0c6651783ae067 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 10:13:20 -0800 Subject: [PATCH 0181/1185] updates --- utils/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index ef372ee7f2..b9180e1386 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -528,8 +528,9 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru # Non-maximum suppression det_max = [] - for c in j.unique(): - dc = pred[j == c] # select class c + cls = pred[:, -1] + for c in cls.unique(): + dc = pred[cls == c] # select class c n = len(dc) if n == 1: det_max.append(dc) # No NMS required if only 1 prediction From f995d6093c94fed34b68c85cb6b5167da30a0919 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 10:22:07 -0800 Subject: [PATCH 0182/1185] updates --- utils/utils.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index b9180e1386..3b72bbbc30 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -491,16 +491,15 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru output = [None] * len(prediction) for image_i, pred in enumerate(prediction): - # Remove rows - pred = pred[pred[:, 4] > conf_thres] # retain above threshold + # Retain > conf + pred = pred[pred[:, 4] > conf_thres] # compute conf torch.sigmoid_(pred[..., 5:]) pred[..., 5:] *= pred[..., 4:5] # conf = obj_conf * cls_conf # Apply width-height constraint - i = (pred[:, 2:4] > min_wh).all(1) & (pred[:, 2:4] < max_wh).all(1) & torch.isfinite(pred).all(1) - pred = pred[i] + pred = pred[(pred[:, 2:4] > min_wh).all(1) & (pred[:, 2:4] < max_wh).all(1)] # If none are remaining => process next image if len(pred) == 0: @@ -517,6 +516,9 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru conf, j = pred[:, 5:].max(1) pred = torch.cat((pred[:, :4], conf.unsqueeze(1), j.float().unsqueeze(1)), 1) # (xyxy, conf, cls) + # Apply finite constraint + pred = pred[torch.isfinite(pred).all(1)] + # Get detections sorted by decreasing confidence scores pred = pred[pred[:, 4].argsort(descending=True)] From fd3a6a4cba36276ba38a97d29b7af075f5421815 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 10:30:13 -0800 Subject: [PATCH 0183/1185] updates --- utils/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 3b72bbbc30..e8c83613e7 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -506,15 +506,15 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru continue # Box (center x, center y, width, height) to (x1, y1, x2, y2) - pred[:, :4] = xywh2xyxy(pred[:, :4]) + box = xywh2xyxy(pred[:, :4]) - # Multi-class + # Detections matrix nx6 (xyxy, conf, cls) if multi_cls or conf_thres < 0.01: i, j = (pred[:, 5:] > conf_thres).nonzero().t() - pred = torch.cat((pred[i, :4], pred[i, j + 5].unsqueeze(1), j.float().unsqueeze(1)), 1) + pred = torch.cat((box[i], pred[i, j + 5].unsqueeze(1), j.float().unsqueeze(1)), 1) else: # best class only conf, j = pred[:, 5:].max(1) - pred = torch.cat((pred[:, :4], conf.unsqueeze(1), j.float().unsqueeze(1)), 1) # (xyxy, conf, cls) + pred = torch.cat((box, conf.unsqueeze(1), j.float().unsqueeze(1)), 1) # Apply finite constraint pred = pred[torch.isfinite(pred).all(1)] From 209cc9e1243cbc25e1f6dfcaeea47ba1b9eaa290 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 10:31:37 -0800 Subject: [PATCH 0184/1185] updates --- utils/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index e8c83613e7..f7a9371660 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -494,14 +494,14 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru # Retain > conf pred = pred[pred[:, 4] > conf_thres] - # compute conf + # Compute conf torch.sigmoid_(pred[..., 5:]) pred[..., 5:] *= pred[..., 4:5] # conf = obj_conf * cls_conf # Apply width-height constraint pred = pred[(pred[:, 2:4] > min_wh).all(1) & (pred[:, 2:4] < max_wh).all(1)] - # If none are remaining => process next image + # If none remain process next image if len(pred) == 0: continue @@ -528,7 +528,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru output[image_i] = pred[i] continue - # Non-maximum suppression + # All other NMS methods det_max = [] cls = pred[:, -1] for c in cls.unique(): From 06e88fec088d84c57cb2b553e525da59d5f236a4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 10:33:58 -0800 Subject: [PATCH 0185/1185] updates --- utils/utils.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index f7a9371660..e721aa1838 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -487,7 +487,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru # NMS methods https://github.com/ultralytics/yolov3/issues/679 'or', 'and', 'merge', 'vision', 'vision_batch' # Box constraints - min_wh, max_wh = 2, 10000 # (pixels) minimum and maximium box width and height + min_wh, max_wh = 2, 4096 # (pixels) minimum and maximium box width and height output = [None] * len(prediction) for image_i, pred in enumerate(prediction): @@ -524,8 +524,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru # Batched NMS if method == 'vision_batch': - i = torchvision.ops.boxes.batched_nms(pred[:, :4], pred[:, 4], pred[:, 5], nms_thres) - output[image_i] = pred[i] + output[image_i] = pred[torchvision.ops.boxes.batched_nms(pred[:, :4], pred[:, 4], pred[:, 5], nms_thres)] continue # All other NMS methods @@ -541,8 +540,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru dc = dc[:500] # limit to first 500 boxes: https://github.com/ultralytics/yolov3/issues/117 if method == 'vision': - i = torchvision.ops.boxes.nms(dc[:, :4], dc[:, 4], nms_thres) - det_max.append(dc[i]) + det_max.append(dc[torchvision.ops.boxes.nms(dc[:, :4], dc[:, 4], nms_thres)]) elif method == 'or': # default # METHOD1 From db26b08f5bf1b18a866970416303cb7cdf3fdd18 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 11:05:55 -0800 Subject: [PATCH 0186/1185] updates --- utils/utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index e721aa1838..02a3b6a666 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -491,13 +491,9 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru output = [None] * len(prediction) for image_i, pred in enumerate(prediction): - # Retain > conf + # Apply conf constraint pred = pred[pred[:, 4] > conf_thres] - # Compute conf - torch.sigmoid_(pred[..., 5:]) - pred[..., 5:] *= pred[..., 4:5] # conf = obj_conf * cls_conf - # Apply width-height constraint pred = pred[(pred[:, 2:4] > min_wh).all(1) & (pred[:, 2:4] < max_wh).all(1)] @@ -505,6 +501,10 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru if len(pred) == 0: continue + # Compute conf + torch.sigmoid_(pred[..., 5:]) + pred[..., 5:] *= pred[..., 4:5] # conf = obj_conf * cls_conf + # Box (center x, center y, width, height) to (x1, y1, x2, y2) box = xywh2xyxy(pred[:, :4]) From efc5ee480ca532e9501709db039ceaf2af84fa06 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 11:13:00 -0800 Subject: [PATCH 0187/1185] updates --- utils/evolve.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils/evolve.sh b/utils/evolve.sh index dd89fbed47..2f5321dbcd 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -1,9 +1,11 @@ #!/bin/bash #for i in 1 2 3 4 5 6 7 #do -# t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run --d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t utils/evolve.sh $i +# t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t utils/evolve.sh $i # sleep 30 # done +# +# t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 --epochs 1 --batch-size 64 --accumulate 1 --evolve --weights '' --pre --bucket yolov4/320_coco2014_27e --device 1 while true; do python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch-size 64 --accumulate 1 --evolve --weights '' --pre --bucket yolov4/320_coco2014_27e --device $1 From 6946a2a8fc8dfeaaa531a7dc5c5b9b5d4986c568 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 11:14:34 -0800 Subject: [PATCH 0188/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 01c865a745..bc082afa79 100644 --- a/train.py +++ b/train.py @@ -467,7 +467,7 @@ def prebias(): if opt.bucket: os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket) # download evolve.txt if exists - for _ in range(1): # generations to evolve + for _ in range(100): # generations to evolve if os.path.exists('evolve.txt'): # if evolve.txt exists: select best hyps and mutate # Select parent(s) x = np.loadtxt('evolve.txt', ndmin=2) From 26ed5e2ddcf3b2a0324a25f1d2e5994f3ed447e4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 11:25:15 -0800 Subject: [PATCH 0189/1185] updates --- detect.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/detect.py b/detect.py index 051ca6fc52..034a118451 100644 --- a/detect.py +++ b/detect.py @@ -88,7 +88,7 @@ def detect(save_txt=False, save_img=False): # Apply NMS pred = non_max_suppression(pred, opt.conf_thres, opt.nms_thres) - # Apply + # Apply Classifier if classify: pred = apply_classifier(pred, modelc, img, im0s) @@ -105,6 +105,9 @@ def detect(save_txt=False, save_img=False): # Rescale boxes from img_size to im0 size det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() + # Print time (inference + NMS) + print('%sDone. (%.3fs)' % (s, time.time() - t)) + # Print results for c in det[:, -1].unique(): n = (det[:, -1] == c).sum() # detections per class @@ -120,8 +123,6 @@ def detect(save_txt=False, save_img=False): label = '%s %.2f' % (names[int(cls)], conf) plot_one_box(xyxy, im0, label=label, color=colors[int(cls)]) - print('%sDone. (%.3fs)' % (s, time.time() - t)) - # Stream results if view_img: cv2.imshow(p, im0) From c459bc6d4ab562d6a5132cc1edfc3c2ef88a7570 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 12:11:37 -0800 Subject: [PATCH 0190/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index bc082afa79..ef48477a19 100644 --- a/train.py +++ b/train.py @@ -467,7 +467,7 @@ def prebias(): if opt.bucket: os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket) # download evolve.txt if exists - for _ in range(100): # generations to evolve + for _ in range(1000): # generations to evolve if os.path.exists('evolve.txt'): # if evolve.txt exists: select best hyps and mutate # Select parent(s) x = np.loadtxt('evolve.txt', ndmin=2) From 78dfa384ee27020ef72b9c2ddccad29a7a9ffcc1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 12:24:48 -0800 Subject: [PATCH 0191/1185] updates --- utils/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 02a3b6a666..324849567b 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -377,7 +377,8 @@ def compute_loss(p, targets, model): # predictions, targets, model # GIoU pxy = torch.sigmoid(ps[:, 0:2]) # pxy = pxy * s - (s - 1) / 2, s = 1.5 (scale_xy) - pbox = torch.cat((pxy, torch.exp(ps[:, 2:4]).clamp(max=1E3) * anchor_vec[i]), 1) # predicted box + pwh = torch.exp(ps[:, 2:4]).clamp(max=1E3) * anchor_vec[i] + pbox = torch.cat((pxy, pwh), 1) # predicted box giou = 1.0 - bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation lbox += giou.sum() if red == 'sum' else giou.mean() # giou loss From ba24e26f7ea3caef6a5387b2c414b5cd44af0637 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 15:43:00 -0800 Subject: [PATCH 0192/1185] updates --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index ef48477a19..5c939931a1 100644 --- a/train.py +++ b/train.py @@ -467,7 +467,7 @@ def prebias(): if opt.bucket: os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket) # download evolve.txt if exists - for _ in range(1000): # generations to evolve + for _ in range(1): # generations to evolve if os.path.exists('evolve.txt'): # if evolve.txt exists: select best hyps and mutate # Select parent(s) x = np.loadtxt('evolve.txt', ndmin=2) @@ -484,7 +484,7 @@ def prebias(): # Mutate np.random.seed(int(time.time())) - s = np.random.random() * 0.2 # sigma + s = np.random.random() * 0.15 # sigma g = [1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 1, 1, 1, 1, 1, 1, 1, 1] # gains for i, k in enumerate(hyp.keys()): x = (np.random.randn() * s * g[i] + 1) ** 2.0 # plt.hist(x.ravel(), 300) From f04fb9a9cdf15084cfd27f021b28c9610a146ee7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 18:02:03 -0800 Subject: [PATCH 0193/1185] updates --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 39ab1ee43e..dec7bc1f93 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch -FROM nvcr.io/nvidia/pytorch:19.10-py3 +FROM nvcr.io/nvidia/pytorch:19.12-py3 # Install dependencies (pip or conda) RUN pip install -U gsutil From 61609b54b191304cc1019d1f47ee3fe689fa0450 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 20:52:57 -0800 Subject: [PATCH 0194/1185] updates --- utils/evolve.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/evolve.sh b/utils/evolve.sh index 2f5321dbcd..a228398020 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -8,5 +8,5 @@ # t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 --epochs 1 --batch-size 64 --accumulate 1 --evolve --weights '' --pre --bucket yolov4/320_coco2014_27e --device 1 while true; do -python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch-size 64 --accumulate 1 --evolve --weights '' --pre --bucket yolov4/320_coco2014_27e --device $1 +python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch-size 64 --accumulate 1 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/320_coco2014_27e --device $1 done From 05a9a6205f3142ff697a1250318112fb6b9df3dc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 23:28:56 -0800 Subject: [PATCH 0195/1185] updates --- detect.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/detect.py b/detect.py index 034a118451..9df3a1c6e0 100644 --- a/detect.py +++ b/detect.py @@ -105,14 +105,14 @@ def detect(save_txt=False, save_img=False): # Rescale boxes from img_size to im0 size det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() - # Print time (inference + NMS) - print('%sDone. (%.3fs)' % (s, time.time() - t)) - # Print results for c in det[:, -1].unique(): n = (det[:, -1] == c).sum() # detections per class s += '%g %ss, ' % (n, names[int(c)]) # add to string + # Print time (inference + NMS) + print('%sDone. (%.3fs)' % (s, time.time() - t)) + # Write results for *xyxy, conf, cls in det: if save_txt: # Write to file From 1e1cffae8b3726101dcbb1e563edae44d78b5d46 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 23 Dec 2019 23:34:30 -0800 Subject: [PATCH 0196/1185] updates --- models.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/models.py b/models.py index 488154524a..c3bf5a1811 100755 --- a/models.py +++ b/models.py @@ -182,11 +182,10 @@ def forward(self, p, img_size, var=None): anchor_wh = self.anchor_wh.repeat((1, 1, self.nx, self.ny, 1)).view(1, m, 2) / ngu p = p.view(m, self.no) - xy = torch.sigmoid(p[..., 0:2]) + grid_xy[0] # x, y - wh = torch.exp(p[..., 2:4]) * anchor_wh[0] # width, height - p_conf = torch.sigmoid(p[:, 4:5]) # Conf - p_cls = F.softmax(p[:, 5:self.no], 1) * p_conf # SSD-like conf - return torch.cat((xy / ngu[0], wh, p_conf, p_cls), 1).t() + xy = torch.sigmoid(p[:, 0:2]) + grid_xy[0] # x, y + wh = torch.exp(p[:, 2:4]) * anchor_wh[0] # width, height + p_cls = F.softmax(p[:, 5:self.no], 1) * torch.sigmoid(p[:, 4:5]) # SSD-like conf + return torch.cat((xy / ngu[0], wh, p_cls), 1).t() # p = p.view(1, m, self.no) # xy = torch.sigmoid(p[..., 0:2]) + grid_xy # x, y @@ -203,7 +202,7 @@ def forward(self, p, img_size, var=None): else: # inference # s = 1.5 # scale_xy (pxy = pxy * s - (s - 1) / 2) io = p.clone() # inference output - io[..., 0:2] = torch.sigmoid(io[..., 0:2]) + self.grid_xy # xy + io[..., :2] = torch.sigmoid(io[..., :2]) + self.grid_xy # xy io[..., 2:4] = torch.exp(io[..., 2:4]) * self.anchor_wh # wh yolo method # io[..., 2:4] = ((torch.sigmoid(io[..., 2:4]) * 2) ** 3) * self.anchor_wh # wh power method io[..., :4] *= self.stride @@ -270,7 +269,7 @@ def forward(self, x, var=None): elif ONNX_EXPORT: output = torch.cat(output, 1) # cat 3 layers 85 x (507, 2028, 8112) to 85 x 10647 nc = self.module_list[self.yolo_layers[0]].nc # number of classes - return output[5:5 + nc].t(), output[0:4].t() # ONNX scores, boxes + return output[4:4 + nc].t(), output[0:4].t() # ONNX scores, boxes else: io, p = list(zip(*output)) # inference output, training output return torch.cat(io, 1), p From 804f82a4b0fb3ba8a9f92429ac206a4714620cdf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 24 Dec 2019 12:26:35 -0800 Subject: [PATCH 0197/1185] updates --- utils/utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 324849567b..22d8789c56 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -223,8 +223,7 @@ def compute_ap(recall, precision): mpre = np.concatenate(([0.], precision, [0.])) # Compute the precision envelope - for i in range(mpre.size - 1, 0, -1): - mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i]) + mpre = np.flip(np.maximum.accumulate(np.flip(mpre))) # Integrate area under curve method = 'interp' # methods: 'continuous', 'interp' From 0f225afe330a190d48f2a864bde9c48ba9467b05 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 24 Dec 2019 12:42:22 -0800 Subject: [PATCH 0198/1185] updates --- test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test.py b/test.py index b05be9ad13..1461c71457 100644 --- a/test.py +++ b/test.py @@ -106,6 +106,9 @@ def test(cfg, # with open('test.txt', 'a') as file: # [file.write('%11.5g' * 7 % tuple(x) + '\n') for x in pred] + # Clip boxes to image bounds + clip_coords(pred, (height, width)) + # Append to pycocotools JSON dictionary if save_json: # [{"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236}, ... @@ -120,11 +123,8 @@ def test(cfg, 'bbox': [floatn(x, 3) for x in box[di]], 'score': floatn(d[4], 5)}) - # Clip boxes to image bounds - clip_coords(pred, (height, width)) - # Assign all predictions as incorrect - correct = torch.zeros(len(pred), niou) + correct = torch.zeros(len(pred), niou, dtype=torch.bool) if nl: detected = [] # target indices tcls_tensor = labels[:, 0] @@ -147,7 +147,7 @@ def test(cfg, d = ti[i[j]] # detected target if d not in detected: detected.append(d) - correct[pi[j]] = (ious[j] > iou_thres).float() # iou_thres is 1xn + correct[pi[j]] = ious[j] > iou_thres # iou_thres is 1xn if len(detected) == nl: # all targets already located in image break From 3c4e7751ed96e90498cecb08a3cf47a66ad53e3b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 24 Dec 2019 13:11:01 -0800 Subject: [PATCH 0199/1185] updates --- test.py | 2 +- train.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test.py b/test.py index 1461c71457..8b9776fee6 100644 --- a/test.py +++ b/test.py @@ -209,7 +209,7 @@ def test(cfg, parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') parser.add_argument('--data', type=str, default='data/coco2014.data', help='*.data path') parser.add_argument('--weights', type=str, default='weights/yolov3-spp.weights', help='path to weights file') - parser.add_argument('--batch-size', type=int, default=16, help='size of each image batch') + parser.add_argument('--batch-size', type=int, default=32, help='size of each image batch') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') parser.add_argument('--nms-thres', type=float, default=0.5, help='iou threshold for non-maximum suppression') diff --git a/train.py b/train.py index 5c939931a1..ee9caad2b6 100644 --- a/train.py +++ b/train.py @@ -213,7 +213,7 @@ def train(): rect=True, cache_labels=True, cache_images=opt.cache_images), - batch_size=batch_size, + batch_size=batch_size * 2, num_workers=nw, pin_memory=True, collate_fn=dataset.collate_fn) @@ -326,7 +326,7 @@ def train(): is_coco = any([x in data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) and model.nc == 80 results, maps = test.test(cfg, data, - batch_size=batch_size, + batch_size=batch_size * 2, img_size=opt.img_size, model=model, conf_thres=0.001 if final_epoch else 0.1, # 0.1 for speed From d595f0847d9155003015efe15fc3cb2ae5c3ec63 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 24 Dec 2019 13:41:52 -0800 Subject: [PATCH 0200/1185] updates --- utils/utils.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/utils/utils.py b/utils/utils.py index 22d8789c56..7c57d71d6b 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -126,6 +126,26 @@ def xywh2xyxy(x): return y +# def xywh2xyxy(box): +# # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] +# if isinstance(box, torch.Tensor): +# x, y, w, h = box.t() +# return torch.stack((x - w / 2, y - h / 2, x + w / 2, y + h / 2)).t() +# else: # numpy +# x, y, w, h = box.T +# return np.stack((x - w / 2, y - h / 2, x + w / 2, y + h / 2)).T +# +# +# def xyxy2xywh(box): +# # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] +# if isinstance(box, torch.Tensor): +# x1, y1, x2, y2 = box.t() +# return torch.stack(((x1 + x2) / 2, (y1 + y2) / 2, x2 - x1, y2 - y1)).t() +# else: # numpy +# x1, y1, x2, y2 = box.T +# return np.stack(((x1 + x2) / 2, (y1 + y2) / 2, x2 - x1, y2 - y1)).T + + def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None): # Rescale coords (xyxy) from img1_shape to img0_shape if ratio_pad is None: # calculate from img0_shape From 8319011489beb339a69abe62404546158d12e586 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 24 Dec 2019 13:57:12 -0800 Subject: [PATCH 0201/1185] updates --- test.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/test.py b/test.py index 8b9776fee6..00e7eec58b 100644 --- a/test.py +++ b/test.py @@ -219,8 +219,8 @@ def test(cfg, opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) print(opt) - study = False - if not study: + task = 'test' # 'test', 'study', 'benchmark' + if task == 'test': # Test test(opt.cfg, opt.data, @@ -230,7 +230,18 @@ def test(cfg, opt.conf_thres, opt.nms_thres, opt.save_json) - else: + + elif task == 'benchmark': + # mAPs at 320-608 at conf 0.5 and 0.7 + y = [] + for i in [320, 416, 512, 608]: + for j in [0.5, 0.7]: + t = time.time() + r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, i, opt.conf_thres, j, opt.save_json)[0] + y.append(r + (time.time() - t,)) + np.savetxt('benchmark.txt', y, fmt='%10.4g') # y = np.loadtxt('study.txt') + + elif task == 'study': # Parameter study y = [] x = np.arange(0.4, 0.9, 0.05) @@ -238,11 +249,11 @@ def test(cfg, t = time.time() r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, opt.conf_thres, v, opt.save_json)[0] y.append(r + (time.time() - t,)) - y = np.stack(y, 0) np.savetxt('study.txt', y, fmt='%10.4g') # y = np.loadtxt('study.txt') # Plot fig, ax = plt.subplots(3, 1, figsize=(6, 6)) + y = np.stack(y, 0) ax[0].plot(x, y[:, 2], marker='.', label='mAP@0.5') ax[0].set_ylabel('mAP') ax[1].plot(x, y[:, 3], marker='.', label='mAP@0.5:0.95') From f7ac56db3919786ee65de071d27989b46e0ad420 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 24 Dec 2019 13:58:45 -0800 Subject: [PATCH 0202/1185] updates --- test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test.py b/test.py index 00e7eec58b..67476a81aa 100644 --- a/test.py +++ b/test.py @@ -214,13 +214,13 @@ def test(cfg, parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') parser.add_argument('--nms-thres', type=float, default=0.5, help='iou threshold for non-maximum suppression') parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') + parser.add_argument('--task', default='test', help="'test', 'study', 'benchmark'") parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') opt = parser.parse_args() opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) print(opt) - task = 'test' # 'test', 'study', 'benchmark' - if task == 'test': + if opt.task == 'test': # task = 'test', 'study', 'benchmark' # Test test(opt.cfg, opt.data, @@ -231,7 +231,7 @@ def test(cfg, opt.nms_thres, opt.save_json) - elif task == 'benchmark': + elif opt.task == 'benchmark': # mAPs at 320-608 at conf 0.5 and 0.7 y = [] for i in [320, 416, 512, 608]: @@ -241,7 +241,7 @@ def test(cfg, y.append(r + (time.time() - t,)) np.savetxt('benchmark.txt', y, fmt='%10.4g') # y = np.loadtxt('study.txt') - elif task == 'study': + elif opt.task == 'study': # Parameter study y = [] x = np.arange(0.4, 0.9, 0.05) From 2ee0d0c71462ee801408f5e39acd3a2b3774ab71 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 24 Dec 2019 13:59:20 -0800 Subject: [PATCH 0203/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 7c57d71d6b..312b8a9555 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -497,7 +497,7 @@ def build_targets(model, targets): return tcls, tbox, indices, av -def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=True, method='vision'): +def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=True, method='vision_batch'): """ Removes detections with lower object confidence score than 'conf_thres' Non-Maximum Suppression to further filter detections. From cdc382e3131194c1e211b595e646e3943bd23c69 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 24 Dec 2019 14:11:31 -0800 Subject: [PATCH 0204/1185] updates --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 67476a81aa..4315d826ef 100644 --- a/test.py +++ b/test.py @@ -21,7 +21,7 @@ def test(cfg, # Initialize/load model and set device if model is None: device = torch_utils.select_device(opt.device, batch_size=batch_size) - verbose = True + verbose = opt.task == 'test' # Remove previous for f in glob.glob('test_batch*.jpg'): From 34d9392bac8a9a3a403e747c808f8ebfbfcffaa2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 25 Dec 2019 14:47:50 -0800 Subject: [PATCH 0205/1185] updates --- utils/utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 312b8a9555..852f3d83d2 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -539,14 +539,15 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru # Apply finite constraint pred = pred[torch.isfinite(pred).all(1)] - # Get detections sorted by decreasing confidence scores - pred = pred[pred[:, 4].argsort(descending=True)] - # Batched NMS if method == 'vision_batch': output[image_i] = pred[torchvision.ops.boxes.batched_nms(pred[:, :4], pred[:, 4], pred[:, 5], nms_thres)] continue + # Sort by confidence + if not method.startswith('vision'): + pred = pred[pred[:, 4].argsort(descending=True)] + # All other NMS methods det_max = [] cls = pred[:, -1] From d1087f49870246d3f2d56ba86c2e0b6f320273ec Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 25 Dec 2019 14:55:11 -0800 Subject: [PATCH 0206/1185] updates --- utils/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 852f3d83d2..38ff9fd31e 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -537,7 +537,8 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru pred = torch.cat((box, conf.unsqueeze(1), j.float().unsqueeze(1)), 1) # Apply finite constraint - pred = pred[torch.isfinite(pred).all(1)] + if not torch.isfinite(pred).all(): + pred = pred[torch.isfinite(pred).all(1)] # Batched NMS if method == 'vision_batch': From 8ae06ad7c346fd85c7414e917a824596703bc422 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 25 Dec 2019 19:58:20 -0800 Subject: [PATCH 0207/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index ee9caad2b6..f6411e27e4 100644 --- a/train.py +++ b/train.py @@ -208,7 +208,7 @@ def train(): # Test Dataloader if not opt.prebias: - testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, opt.img_size, batch_size, + testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, opt.img_size, batch_size * 2, hyp=hyp, rect=True, cache_labels=True, From fea54c4a85cb7d6fc958f7dd76508a9b4cb06ce8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Dec 2019 12:30:51 -0800 Subject: [PATCH 0208/1185] updates --- detect.py | 4 ++-- test.py | 10 +++++----- utils/utils.py | 14 +++++++------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/detect.py b/detect.py index 9df3a1c6e0..74838a49f2 100644 --- a/detect.py +++ b/detect.py @@ -86,7 +86,7 @@ def detect(save_txt=False, save_img=False): pred = pred.float() # Apply NMS - pred = non_max_suppression(pred, opt.conf_thres, opt.nms_thres) + pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres) # Apply Classifier if classify: @@ -162,7 +162,7 @@ def detect(save_txt=False, save_img=False): parser.add_argument('--output', type=str, default='output', help='output folder') # output folder parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.3, help='object confidence threshold') - parser.add_argument('--nms-thres', type=float, default=0.5, help='iou threshold for non-maximum suppression') + parser.add_argument('--iou-thres', type=float, default=0.5, help='IOU threshold for NMS') parser.add_argument('--fourcc', type=str, default='mp4v', help='output video codec (verify ffmpeg support)') parser.add_argument('--half', action='store_true', help='half precision FP16 inference') parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') diff --git a/test.py b/test.py index 4315d826ef..19aca3c778 100644 --- a/test.py +++ b/test.py @@ -14,7 +14,7 @@ def test(cfg, batch_size=16, img_size=416, conf_thres=0.001, - nms_thres=0.5, + iou_thres=0.5, save_json=False, model=None, dataloader=None): @@ -88,7 +88,7 @@ def test(cfg, loss += compute_loss(train_out, targets, model)[1][:3].cpu() # GIoU, obj, cls # Run NMS - output = non_max_suppression(inf_out, conf_thres=conf_thres, nms_thres=nms_thres) + output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres) # Statistics per image for si, pred in enumerate(output): @@ -212,7 +212,7 @@ def test(cfg, parser.add_argument('--batch-size', type=int, default=32, help='size of each image batch') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') - parser.add_argument('--nms-thres', type=float, default=0.5, help='iou threshold for non-maximum suppression') + parser.add_argument('--iou-thres', type=float, default=0.5, help='IOU threshold for NMS') parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') parser.add_argument('--task', default='test', help="'test', 'study', 'benchmark'") parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') @@ -228,7 +228,7 @@ def test(cfg, opt.batch_size, opt.img_size, opt.conf_thres, - opt.nms_thres, + opt.iou_thres, opt.save_json) elif opt.task == 'benchmark': @@ -262,6 +262,6 @@ def test(cfg, ax[2].set_ylabel('time (s)') for i in range(3): ax[i].legend() - ax[i].set_xlabel('nms_thr') + ax[i].set_xlabel('iou_thr') fig.tight_layout() plt.savefig('study.jpg', dpi=200) diff --git a/utils/utils.py b/utils/utils.py index 38ff9fd31e..6a9d0861b6 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -497,7 +497,7 @@ def build_targets(model, targets): return tcls, tbox, indices, av -def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=True, method='vision_batch'): +def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=True, method='vision_batch'): """ Removes detections with lower object confidence score than 'conf_thres' Non-Maximum Suppression to further filter detections. @@ -542,7 +542,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru # Batched NMS if method == 'vision_batch': - output[image_i] = pred[torchvision.ops.boxes.batched_nms(pred[:, :4], pred[:, 4], pred[:, 5], nms_thres)] + output[image_i] = pred[torchvision.ops.boxes.batched_nms(pred[:, :4], pred[:, 4], pred[:, 5], iou_thres)] continue # Sort by confidence @@ -562,7 +562,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru dc = dc[:500] # limit to first 500 boxes: https://github.com/ultralytics/yolov3/issues/117 if method == 'vision': - det_max.append(dc[torchvision.ops.boxes.nms(dc[:, :4], dc[:, 4], nms_thres)]) + det_max.append(dc[torchvision.ops.boxes.nms(dc[:, :4], dc[:, 4], iou_thres)]) elif method == 'or': # default # METHOD1 @@ -570,7 +570,7 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru # while len(ind): # j = ind[0] # det_max.append(dc[j:j + 1]) # save highest conf detection - # reject = (bbox_iou(dc[j], dc[ind]) > nms_thres).nonzero() + # reject = (bbox_iou(dc[j], dc[ind]) > iou_thres).nonzero() # [ind.pop(i) for i in reversed(reject)] # METHOD2 @@ -579,21 +579,21 @@ def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.5, multi_cls=Tru if len(dc) == 1: # Stop if we're at the last detection break iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes - dc = dc[1:][iou < nms_thres] # remove ious > threshold + dc = dc[1:][iou < iou_thres] # remove ious > threshold elif method == 'and': # requires overlap, single boxes erased while len(dc) > 1: iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes if iou.max() > 0.5: det_max.append(dc[:1]) - dc = dc[1:][iou < nms_thres] # remove ious > threshold + dc = dc[1:][iou < iou_thres] # remove ious > threshold elif method == 'merge': # weighted mixture box while len(dc): if len(dc) == 1: det_max.append(dc) break - i = bbox_iou(dc[0], dc) > nms_thres # iou with other boxes + i = bbox_iou(dc[0], dc) > iou_thres # iou with other boxes weights = dc[i, 4:5] dc[0, :4] = (weights * dc[i, :4]).sum(0) / weights.sum() det_max.append(dc[:1]) From b4552091dc74ded4f7dabefa0ae2290374bf5d73 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Dec 2019 12:31:30 -0800 Subject: [PATCH 0209/1185] updates --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c86115909b..2e884e0ebf 100755 --- a/README.md +++ b/README.md @@ -146,10 +146,11 @@ python3 test.py --weights ... --cfg ... |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 --- | --- | --- | --- -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |320 |14.0
28.7
30.5
**35.4** |29.1
51.8
52.3
**54.3** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |416 |16.0
31.2
33.9
**39.0** |33.0
55.4
56.9
**59.2** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |512 |16.6
32.7
35.6
**40.3** |34.9
57.7
59.5
**60.6** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |608 |16.6
33.1
37.0
**40.9** |35.4
58.2
60.7
**60.9** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |320 |14.0
28.7
30.5
**35.5** |29.1
51.8
52.3
**55.4** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |416 |16.0
31.2
33.9
**39.2** |33.0
55.4
56.9
**59.9** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |512 |16.6
32.7
35.6
**40.5** |34.9
57.7
59.5
**61.4** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |608 |16.6
33.1
37.0
**41.1** |35.4
58.2
60.7
**61.5** + ```bash $ python3 test.py --save-json --img-size 608 --nms-thres 0.5 --weights ultralytics68.pt From 326503425bc797c5f3fc2dd190309a9521b3eb1f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Dec 2019 12:52:25 -0800 Subject: [PATCH 0210/1185] updates --- README.md | 120 +++++++++--------------------------------------------- 1 file changed, 19 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 2e884e0ebf..c44987e454 100755 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ Success: converted 'weights/yolov3-spp.pt' to 'converted.weights' python3 test.py --weights ... --cfg ... ``` -- mAP@0.5 run at `--nms-thres 0.5`, mAP@0.5...0.95 run at `--nms-thres 0.7` +- mAP@0.5 run at `--iou-thr 0.5`, mAP@0.5...0.95 run at `--iou-thr 0.7` - YOLOv3-SPP ultralytics is `ultralytics68.pt` with `yolov3-spp.cfg` - Darknet results: https://arxiv.org/abs/1804.02767 @@ -153,106 +153,24 @@ YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |608 |16.6
```bash -$ python3 test.py --save-json --img-size 608 --nms-thres 0.5 --weights ultralytics68.pt - -Namespace(batch_size=16, cfg='cfg/yolov3-spp.cfg', conf_thres=0.001, data='data/coco.data', device='1', img_size=608, iou_thres=0.5, nms_thres=0.7, save_json=True, weights='ultralytics68.pt') -Using CUDA device0 _CudaDeviceProperties(name='GeForce RTX 2080 Ti', total_memory=11019MB) - - Class Images Targets P R mAP@0.5 F1: 100%|███████████████████████████████████████████████████████████████████████████████████| 313/313 [09:46<00:00, 1.09it/s] - all 5e+03 3.58e+04 0.0823 0.798 0.595 0.145 - person 5e+03 1.09e+04 0.0999 0.903 0.771 0.18 - bicycle 5e+03 316 0.0491 0.782 0.56 0.0925 - car 5e+03 1.67e+03 0.0552 0.845 0.646 0.104 - motorcycle 5e+03 391 0.11 0.847 0.704 0.194 - airplane 5e+03 131 0.099 0.947 0.878 0.179 - bus 5e+03 261 0.142 0.874 0.825 0.244 - train 5e+03 212 0.152 0.863 0.806 0.258 - truck 5e+03 352 0.0849 0.682 0.514 0.151 - boat 5e+03 475 0.0498 0.787 0.504 0.0937 - traffic light 5e+03 516 0.0304 0.752 0.516 0.0584 - fire hydrant 5e+03 83 0.144 0.916 0.882 0.248 - stop sign 5e+03 84 0.0833 0.917 0.809 0.153 - parking meter 5e+03 59 0.0607 0.695 0.611 0.112 - bench 5e+03 473 0.0294 0.685 0.363 0.0564 - bird 5e+03 469 0.0521 0.716 0.524 0.0972 - cat 5e+03 195 0.252 0.908 0.78 0.395 - dog 5e+03 223 0.192 0.883 0.829 0.315 - horse 5e+03 305 0.121 0.911 0.843 0.214 - sheep 5e+03 321 0.114 0.854 0.724 0.201 - cow 5e+03 384 0.105 0.849 0.695 0.187 - elephant 5e+03 284 0.184 0.944 0.912 0.308 - bear 5e+03 53 0.358 0.925 0.875 0.516 - zebra 5e+03 277 0.176 0.935 0.858 0.297 - giraffe 5e+03 170 0.171 0.959 0.892 0.29 - backpack 5e+03 384 0.0426 0.708 0.392 0.0803 - umbrella 5e+03 392 0.0672 0.878 0.65 0.125 - handbag 5e+03 483 0.0238 0.629 0.242 0.0458 - tie 5e+03 297 0.0419 0.805 0.599 0.0797 - suitcase 5e+03 310 0.0823 0.855 0.628 0.15 - frisbee 5e+03 109 0.126 0.872 0.796 0.221 - skis 5e+03 282 0.0473 0.748 0.454 0.089 - snowboard 5e+03 92 0.0579 0.804 0.559 0.108 - sports ball 5e+03 236 0.057 0.733 0.622 0.106 - kite 5e+03 399 0.087 0.852 0.645 0.158 - baseball bat 5e+03 125 0.0496 0.776 0.603 0.0932 - baseball glove 5e+03 139 0.0511 0.734 0.563 0.0956 - skateboard 5e+03 218 0.0655 0.844 0.73 0.122 - surfboard 5e+03 266 0.0709 0.827 0.651 0.131 - tennis racket 5e+03 183 0.0694 0.858 0.759 0.128 - bottle 5e+03 966 0.0484 0.812 0.513 0.0914 - wine glass 5e+03 366 0.0735 0.738 0.543 0.134 - cup 5e+03 897 0.0637 0.788 0.538 0.118 - fork 5e+03 234 0.0411 0.662 0.487 0.0774 - knife 5e+03 291 0.0334 0.557 0.292 0.0631 - spoon 5e+03 253 0.0281 0.621 0.307 0.0537 - bowl 5e+03 620 0.0624 0.795 0.514 0.116 - banana 5e+03 371 0.052 0.83 0.41 0.0979 - apple 5e+03 158 0.0293 0.741 0.262 0.0564 - sandwich 5e+03 160 0.0913 0.725 0.522 0.162 - orange 5e+03 189 0.0382 0.688 0.32 0.0723 - broccoli 5e+03 332 0.0513 0.88 0.445 0.097 - carrot 5e+03 346 0.0398 0.766 0.362 0.0757 - hot dog 5e+03 164 0.0958 0.646 0.494 0.167 - pizza 5e+03 224 0.0886 0.875 0.699 0.161 - donut 5e+03 237 0.0925 0.827 0.64 0.166 - cake 5e+03 241 0.0658 0.71 0.539 0.12 - chair 5e+03 1.62e+03 0.0432 0.793 0.489 0.0819 - couch 5e+03 236 0.118 0.801 0.584 0.205 - potted plant 5e+03 431 0.0373 0.852 0.505 0.0714 - bed 5e+03 195 0.149 0.846 0.693 0.253 - dining table 5e+03 634 0.0546 0.82 0.49 0.102 - toilet 5e+03 179 0.161 0.95 0.81 0.275 - tv 5e+03 257 0.0922 0.903 0.79 0.167 - laptop 5e+03 237 0.127 0.869 0.744 0.222 - mouse 5e+03 95 0.0648 0.863 0.732 0.12 - remote 5e+03 241 0.0436 0.788 0.535 0.0827 - keyboard 5e+03 117 0.0668 0.923 0.755 0.125 - cell phone 5e+03 291 0.0364 0.704 0.436 0.0692 - microwave 5e+03 88 0.154 0.841 0.743 0.261 - oven 5e+03 142 0.0618 0.803 0.576 0.115 - toaster 5e+03 11 0.0565 0.636 0.191 0.104 - sink 5e+03 211 0.0439 0.853 0.544 0.0835 - refrigerator 5e+03 107 0.0791 0.907 0.742 0.145 - book 5e+03 1.08e+03 0.0399 0.667 0.233 0.0753 - clock 5e+03 292 0.0542 0.836 0.733 0.102 - vase 5e+03 353 0.0675 0.799 0.591 0.125 - scissors 5e+03 56 0.0397 0.75 0.461 0.0755 - teddy bear 5e+03 245 0.0995 0.882 0.669 0.179 - hair drier 5e+03 11 0.00508 0.0909 0.0475 0.00962 - toothbrush 5e+03 77 0.0371 0.74 0.418 0.0706 - - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.409 - Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.600 - Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.446 - Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.243 - Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.450 - Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.514 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.326 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.536 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.593 - Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.422 - Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.640 - Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.707 +$ python3 test.py --img-size 608 --iou-thr 0.5 --weights ultralytics68.pt --cfg yolov3-spp.cfg + +Namespace(batch_size=32, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.5, save_json=True, task='test', weights='ultralytics68.pt') +Using CUDA device0 _CudaDeviceProperties(name='Tesla P100-PCIE-16GB', total_memory=16280MB) + Class Images Targets P R mAP@0.5 F1: 100% 157/157 [04:13<00:00, 1.16it/s] + all 5e+03 3.51e+04 0.0437 0.88 0.607 0.0822 + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.406 + Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.615 + Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.431 + Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.238 + Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.444 + Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.516 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.337 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.548 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.592 + Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.418 + Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.635 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.729 ``` # Reproduce Our Results From a5f923d697e5933be82b680ae1b950b6d7c85e84 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Dec 2019 12:53:11 -0800 Subject: [PATCH 0211/1185] updates --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index c44987e454..2d81c11af3 100755 --- a/README.md +++ b/README.md @@ -151,7 +151,6 @@ YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |416 |16.0
YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |512 |16.6
32.7
35.6
**40.5** |34.9
57.7
59.5
**61.4** YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |608 |16.6
33.1
37.0
**41.1** |35.4
58.2
60.7
**61.5** - ```bash $ python3 test.py --img-size 608 --iou-thr 0.5 --weights ultralytics68.pt --cfg yolov3-spp.cfg From 4bbed32f01856edadf229c792586ab74cc09e8b5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 08:10:05 -0800 Subject: [PATCH 0212/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index f6411e27e4..cfa63ed1bb 100644 --- a/train.py +++ b/train.py @@ -471,7 +471,7 @@ def prebias(): if os.path.exists('evolve.txt'): # if evolve.txt exists: select best hyps and mutate # Select parent(s) x = np.loadtxt('evolve.txt', ndmin=2) - parent = 'single' # parent selection method: 'single' or 'weighted' + parent = 'weighted' # parent selection method: 'single' or 'weighted' if parent == 'single' or len(x) == 1: x = x[fitness(x).argmax()] elif parent == 'weighted': # weighted combination From 0bdbe5648d79c5c12fec8d9e4f599afe92064563 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 08:16:18 -0800 Subject: [PATCH 0213/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 6a9d0861b6..68c9a82ddc 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -831,7 +831,7 @@ def apply_classifier(x, model, img, im0): def fitness(x): # Returns fitness (for use with results.txt or evolve.txt) - return x[:, 2] * 0.1 + x[:, 3] * 0.9 # weighted combination of x=[p, r, mAP@0.5, F1 or mAP@0.5:0.95] + return x[:, 2] * 0.3 + x[:, 3] * 0.7 # weighted combination of x=[p, r, mAP@0.5, F1 or mAP@0.5:0.95] # Plotting functions --------------------------------------------------------------------------------------------------- From 2fe6c21ce897f8d5e8b62fc83a13056ef80d5be1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 09:28:10 -0800 Subject: [PATCH 0214/1185] updates --- test.py | 10 +++++----- train.py | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/test.py b/test.py index 19aca3c778..642fdbcfbd 100644 --- a/test.py +++ b/test.py @@ -48,9 +48,9 @@ def test(cfg, nc = int(data['classes']) # number of classes path = data['valid'] # path to test images names = load_classes(data['names']) # class names - iou_thres = torch.linspace(0.5, 0.95, 10).to(device) # for mAP@0.5:0.95 - iou_thres = iou_thres[0].view(1) # for mAP@0.5 - niou = iou_thres.numel() + # iou_thres = torch.linspace(0.5, 0.95, 10).to(device) # for mAP@0.5:0.95 + # iou_thres = iou_thres[0].view(1) # for mAP@0.5 + niou = 1 # len(iou_thres) # Dataloader if dataloader is None: @@ -245,9 +245,9 @@ def test(cfg, # Parameter study y = [] x = np.arange(0.4, 0.9, 0.05) - for v in x: + for i in x: t = time.time() - r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, opt.conf_thres, v, opt.save_json)[0] + r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, opt.conf_thres, i, opt.save_json)[0] y.append(r + (time.time() - t,)) np.savetxt('study.txt', y, fmt='%10.4g') # y = np.loadtxt('study.txt') diff --git a/train.py b/train.py index cfa63ed1bb..26e6f2b821 100644 --- a/train.py +++ b/train.py @@ -330,6 +330,7 @@ def train(): img_size=opt.img_size, model=model, conf_thres=0.001 if final_epoch else 0.1, # 0.1 for speed + iou_thres=0.6 if opt.evolve else 0.5, save_json=final_epoch and is_coco, dataloader=testloader) From b58f41ef530327f04e396418470fa9d4e7acc499 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 09:29:09 -0800 Subject: [PATCH 0215/1185] updates --- utils/datasets.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index b88b769c58..c7d6a01775 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -584,10 +584,10 @@ def load_mosaic(self, index): # Augment # img4 = img4[s // 2: int(s * 1.5), s // 2:int(s * 1.5)] # center crop (WARNING, requires box pruning) img4, labels4 = random_affine(img4, labels4, - degrees=self.hyp['degrees'] * 0, - translate=self.hyp['translate'] * 0, - scale=self.hyp['scale'] * 0, - shear=self.hyp['shear'] * 0, + degrees=self.hyp['degrees'] * 1, + translate=self.hyp['translate'] * 1, + scale=self.hyp['scale'] * 1, + shear=self.hyp['shear'] * 1, border=-s // 2) # border to remove return img4, labels4 From 1c07b1906cfa80867c4e5cd991f62bf3a29d00cf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 09:41:19 -0800 Subject: [PATCH 0216/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 68c9a82ddc..a7e67b0cc7 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -529,7 +529,7 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru box = xywh2xyxy(pred[:, :4]) # Detections matrix nx6 (xyxy, conf, cls) - if multi_cls or conf_thres < 0.01: + if multi_cls: i, j = (pred[:, 5:] > conf_thres).nonzero().t() pred = torch.cat((box[i], pred[i, j + 5].unsqueeze(1), j.float().unsqueeze(1)), 1) else: # best class only From 440769b954637a74d86f48eb882cc1ac4c2a94f3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 09:55:10 -0800 Subject: [PATCH 0217/1185] updates --- test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test.py b/test.py index 642fdbcfbd..7cd130116a 100644 --- a/test.py +++ b/test.py @@ -50,7 +50,9 @@ def test(cfg, names = load_classes(data['names']) # class names # iou_thres = torch.linspace(0.5, 0.95, 10).to(device) # for mAP@0.5:0.95 # iou_thres = iou_thres[0].view(1) # for mAP@0.5 - niou = 1 # len(iou_thres) + if isinstance(iou_thres, float): + iou_thres = torch.Tensor([iou_thres]).to(device) # convert to array + niou = iou_thres.numel() # Dataloader if dataloader is None: From 45b7dfc0542824a97d9ea7cc9363e4c84aea4858 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 10:08:58 -0800 Subject: [PATCH 0218/1185] updates --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index dec7bc1f93..5bd6b08811 100644 --- a/Dockerfile +++ b/Dockerfile @@ -55,5 +55,8 @@ COPY . /usr/src/app # Kill all # sudo docker kill "$(sudo docker ps -q)" +# Kill all image-based +# sudo docker kill $(sudo docker ps -a -q --filter ancestor=ultralytics/yolov3:v0) + # Run bash for loop # sudo nvidia-docker run --ipc=host ultralytics/yolov3:v0 while true; do python3 train.py --evolve; done From 2cc805eddaffa3cf67c14d890d3e1c067a518a05 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 10:31:12 -0800 Subject: [PATCH 0219/1185] updates --- test.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/test.py b/test.py index 7cd130116a..c5e166bb6c 100644 --- a/test.py +++ b/test.py @@ -14,7 +14,7 @@ def test(cfg, batch_size=16, img_size=416, conf_thres=0.001, - iou_thres=0.5, + iou_thres=0.5, # for nms save_json=False, model=None, dataloader=None): @@ -48,11 +48,9 @@ def test(cfg, nc = int(data['classes']) # number of classes path = data['valid'] # path to test images names = load_classes(data['names']) # class names - # iou_thres = torch.linspace(0.5, 0.95, 10).to(device) # for mAP@0.5:0.95 - # iou_thres = iou_thres[0].view(1) # for mAP@0.5 - if isinstance(iou_thres, float): - iou_thres = torch.Tensor([iou_thres]).to(device) # convert to array - niou = iou_thres.numel() + iouv = torch.linspace(0.5, 0.95, 10).to(device) # iou vector for mAP@0.5:0.95 + iouv = iouv[0].view(1) # for mAP@0.5 + niou = iouv.numel() # Dataloader if dataloader is None: @@ -145,11 +143,11 @@ def test(cfg, ious, i = box_iou(pred[pi, :4], tbox[ti]).max(1) # best ious, indices # Append detections - for j in (ious > iou_thres[0]).nonzero(): + for j in (ious > iouv[0]).nonzero(): d = ti[i[j]] # detected target if d not in detected: detected.append(d) - correct[pi[j]] = ious[j] > iou_thres # iou_thres is 1xn + correct[pi[j]] = ious[j] > iouv # iou_thres is 1xn if len(detected) == nl: # all targets already located in image break From 56d7261083286850cf021ab603d60f8321a51951 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 10:52:19 -0800 Subject: [PATCH 0220/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 26e6f2b821..5fb31e2590 100644 --- a/train.py +++ b/train.py @@ -330,7 +330,7 @@ def train(): img_size=opt.img_size, model=model, conf_thres=0.001 if final_epoch else 0.1, # 0.1 for speed - iou_thres=0.6 if opt.evolve else 0.5, + iou_thres=0.6 if final_epoch and is_coco else 0.5, save_json=final_epoch and is_coco, dataloader=testloader) From 043a0e457cb4b981e95bd909b42ac7fa302ed7a7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 11:30:27 -0800 Subject: [PATCH 0221/1185] updates --- README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 2d81c11af3..248795ddfe 100755 --- a/README.md +++ b/README.md @@ -152,24 +152,24 @@ YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |512 |16.6
YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |608 |16.6
33.1
37.0
**41.1** |35.4
58.2
60.7
**61.5** ```bash -$ python3 test.py --img-size 608 --iou-thr 0.5 --weights ultralytics68.pt --cfg yolov3-spp.cfg +$ python3 test.py --img-size 608 --iou-thr 0.6 --weights ultralytics68.pt --cfg yolov3-spp.cfg -Namespace(batch_size=32, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.5, save_json=True, task='test', weights='ultralytics68.pt') -Using CUDA device0 _CudaDeviceProperties(name='Tesla P100-PCIE-16GB', total_memory=16280MB) - Class Images Targets P R mAP@0.5 F1: 100% 157/157 [04:13<00:00, 1.16it/s] - all 5e+03 3.51e+04 0.0437 0.88 0.607 0.0822 - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.406 +Namespace(batch_size=32, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, task='test', weights='ultralytics68.pt') +Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memory=16130MB) + Class Images Targets P R mAP@0.5 F1: 100% 157/157 [03:30<00:00, 1.16it/s] + all 5e+03 3.51e+04 0.0353 0.891 0.606 0.0673 + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.409 Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.615 - Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.431 - Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.238 - Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.444 - Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.516 + Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.437 + Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.242 + Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.448 + Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.519 Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.337 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.548 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.592 - Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.418 - Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.635 - Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.729 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.557 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.612 + Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.438 + Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.658 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.746 ``` # Reproduce Our Results From 59de209ab26e6898b0599b0afb39d5c29fea77fe Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 11:51:27 -0800 Subject: [PATCH 0222/1185] updates --- utils/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index a7e67b0cc7..7448496c8b 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -391,15 +391,15 @@ def compute_loss(p, targets, model): # predictions, targets, model if nb: # number of targets ng += nb ps = pi[b, a, gj, gi] # prediction subset corresponding to targets - tobj[b, a, gj, gi] = 1.0 # obj # ps[:, 2:4] = torch.sigmoid(ps[:, 2:4]) # wh power loss (uncomment) # GIoU pxy = torch.sigmoid(ps[:, 0:2]) # pxy = pxy * s - (s - 1) / 2, s = 1.5 (scale_xy) pwh = torch.exp(ps[:, 2:4]).clamp(max=1E3) * anchor_vec[i] pbox = torch.cat((pxy, pwh), 1) # predicted box - giou = 1.0 - bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation - lbox += giou.sum() if red == 'sum' else giou.mean() # giou loss + giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation + lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss + tobj[b, a, gj, gi] = 1.0 # giou.type(tobj.dtype) # obj if 'default' in arc and model.nc > 1: # cls loss (only if multiple classes) t = torch.zeros_like(ps[:, 5:]) # targets From 7ef7501c362d8180c6432e5dbec7daa8223b1b81 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 12:14:01 -0800 Subject: [PATCH 0223/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 7448496c8b..ba22e6b25c 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -436,7 +436,7 @@ def compute_loss(p, targets, model): # predictions, targets, model lcls *= h['cls'] if red == 'sum': lbox *= 3 / ng - lobj *= 3 / np + lobj *= 3 / np * 2 lcls *= 3 / ng / model.nc loss = lbox + lobj + lcls From d859957c66295dab8174a36e43a7c62c79a29855 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 12:34:29 -0800 Subject: [PATCH 0224/1185] updates --- utils/datasets.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index c7d6a01775..b88b769c58 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -584,10 +584,10 @@ def load_mosaic(self, index): # Augment # img4 = img4[s // 2: int(s * 1.5), s // 2:int(s * 1.5)] # center crop (WARNING, requires box pruning) img4, labels4 = random_affine(img4, labels4, - degrees=self.hyp['degrees'] * 1, - translate=self.hyp['translate'] * 1, - scale=self.hyp['scale'] * 1, - shear=self.hyp['shear'] * 1, + degrees=self.hyp['degrees'] * 0, + translate=self.hyp['translate'] * 0, + scale=self.hyp['scale'] * 0, + shear=self.hyp['shear'] * 0, border=-s // 2) # border to remove return img4, labels4 From d7ea668c42043837fa0ddc1564c2cc27b6eb56e9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 12:41:51 -0800 Subject: [PATCH 0225/1185] updates --- .dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.dockerignore b/.dockerignore index 5798fc6b1a..a3dab6835e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -11,6 +11,7 @@ data/samples/* !data/samples/zidane.jpg !data/samples/bus.jpg **/results*.txt +*.jpg # Neural Network weights ----------------------------------------------------------------------------------------------- **/*.weights From 4843cc4e087d7e7a09371e0144eae8902a26ee8d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 12:52:01 -0800 Subject: [PATCH 0226/1185] updates --- train.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/train.py b/train.py index 5fb31e2590..3e903c03e0 100644 --- a/train.py +++ b/train.py @@ -192,7 +192,7 @@ def train(): augment=True, hyp=hyp, # augmentation hyperparameters rect=opt.rect, # rectangular training - image_weights=opt.img_weights, + image_weights=False, cache_labels=epochs > 10, cache_images=opt.cache_images and not opt.prebias) @@ -430,7 +430,6 @@ def prebias(): parser.add_argument('--notest', action='store_true', help='only test final epoch') parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters') parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') - parser.add_argument('--img-weights', action='store_true', help='select training images by weight') parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') parser.add_argument('--weights', type=str, default='weights/ultralytics68.pt', help='initial weights') parser.add_argument('--arc', type=str, default='default', help='yolo architecture') # defaultpw, uCE, uBCE From 162ddcf6c717e0362fd76b731e2501b967ec5930 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 13:04:46 -0800 Subject: [PATCH 0227/1185] updates --- train.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 3e903c03e0..7a9d2d07dd 100644 --- a/train.py +++ b/train.py @@ -403,15 +403,15 @@ def train(): def prebias(): # trains output bias layers for 1 epoch and creates new backbone if opt.prebias: - a = opt.img_weights # save settings - opt.img_weights = False # disable settings + # opt_0 = opt # save settings + # opt.rect = False # update settings (if any) train() # transfer-learn yolo biases for 1 epoch create_backbone(last) # saved results as backbone.pt + # opt = opt_0 # reset settings opt.weights = wdir + 'backbone.pt' # assign backbone opt.prebias = False # disable prebias - opt.img_weights = a # reset settings if __name__ == '__main__': From e5b5d6a880fcd354e515c8d3b6d7eb2861b4422d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 14:58:31 -0800 Subject: [PATCH 0228/1185] updates --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 7a9d2d07dd..65151cecb3 100644 --- a/train.py +++ b/train.py @@ -142,9 +142,9 @@ def train(): if opt.prebias: for p in optimizer.param_groups: # lower param count allows more aggressive training settings: i.e. SGD ~0.1 lr0, ~0.9 momentum - p['lr'] *= 100 # lr gain + p['lr'] = 0.1 # learning rate if p.get('momentum') is not None: # for SGD but not Adam - p['momentum'] *= 0.9 + p['momentum'] = 0.9 for p in model.parameters(): if opt.prebias and p.numel() == nf: # train (yolo biases) From 609a9d94cf7c6fea4ef420e71dd9fc1ff540e40f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Dec 2019 20:32:01 -0800 Subject: [PATCH 0229/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index ba22e6b25c..b9194f9f5f 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -399,7 +399,7 @@ def compute_loss(p, targets, model): # predictions, targets, model pbox = torch.cat((pxy, pwh), 1) # predicted box giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss - tobj[b, a, gj, gi] = 1.0 # giou.type(tobj.dtype) # obj + tobj[b, a, gj, gi] = 1.0 # giou.detach().type(tobj.dtype) * 0.5 + 0.5 # obj if 'default' in arc and model.nc > 1: # cls loss (only if multiple classes) t = torch.zeros_like(ps[:, 5:]) # targets From 2e680fb5449334cff8fb20a8f2f3b85c08950994 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 28 Dec 2019 20:22:44 -0800 Subject: [PATCH 0230/1185] updates --- utils/gcp.sh | 207 ++++++++++++++++++++++++++----------------------- utils/utils.py | 2 +- 2 files changed, 110 insertions(+), 99 deletions(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index 3ee04ac92d..c26015aced 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -15,7 +15,7 @@ git clone https://github.com/ultralytics/yolov3 # master bash yolov3/data/get_coco2017.sh # git clone -b test --depth 1 https://github.com/ultralytics/yolov3 test # branch cd yolov3 -python3 train.py --weights '' --epochs 27 --batch-size 32 --accumulate 2 --nosave --data coco2017.data +python3 test.py --weights ultralytics68.pt --task benchmark # Train python3 train.py @@ -30,21 +30,12 @@ python3 detect.py python3 test.py --save-json # Evolve -for i in 1 2 3 4 5 6 7 +t=ultralytics/yolov3:v148 +sudo docker kill $(sudo docker ps -a -q --filter ancestor=$t) +for i in 0 1 2 3 4 5 6 7 do - export t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch-size 64 --accumulate 1 --evolve --weights '' --pre --arc default --bucket yolov4/320_coco2014_27e --device $i - sleep 30 -done - -export t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco16.data --img-size 320 --epochs 1 --batch-size 8 --accumulate 1 --evolve --weights '' --device 1 - - -export t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t -clear -sleep 0 -while true -do - python3 train.py --data coco2014.data --img-size 416 --epochs 27 --batch-size 32 --accumulate 2 --evolve --weights '' --pre --bucket yolov4/416_coco_27e --device 2 + sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i + sleep 10 done @@ -106,93 +97,113 @@ sudo docker pull ultralytics/yolov3:v0 sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco ultralytics/yolov3:v0 -export t=ultralytics/yolov3:v70 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 70 --device 0 --multi -export t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 71 --device 0 --multi --img-weights +t=ultralytics/yolov3:v70 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 70 --device 0 --multi +t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 71 --device 0 --multi --img-weights -export t=ultralytics/yolov3:v73 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 73 --device 5 --cfg cfg/yolov3s.cfg -export t=ultralytics/yolov3:v74 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 74 --device 0 --cfg cfg/yolov3s.cfg -export t=ultralytics/yolov3:v75 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 75 --device 7 --cfg cfg/yolov3s.cfg -export t=ultralytics/yolov3:v76 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 76 --device 0 --cfg cfg/yolov3-spp.cfg +t=ultralytics/yolov3:v73 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 73 --device 5 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v74 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 74 --device 0 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v75 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 75 --device 7 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v76 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 76 --device 0 --cfg cfg/yolov3-spp.cfg -export t=ultralytics/yolov3:v79 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 79 --device 5 -export t=ultralytics/yolov3:v80 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 80 --device 0 -export t=ultralytics/yolov3:v81 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 81 --device 7 -export t=ultralytics/yolov3:v82 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 82 --device 0 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v79 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 79 --device 5 +t=ultralytics/yolov3:v80 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 80 --device 0 +t=ultralytics/yolov3:v81 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 81 --device 7 +t=ultralytics/yolov3:v82 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 82 --device 0 --cfg cfg/yolov3s.cfg -export t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 83 --device 6 --multi --nosave -export t=ultralytics/yolov3:v84 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 84 --device 0 --multi -export t=ultralytics/yolov3:v85 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 85 --device 0 --multi -export t=ultralytics/yolov3:v86 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 86 --device 1 --multi -export t=ultralytics/yolov3:v87 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 87 --device 2 --multi -export t=ultralytics/yolov3:v88 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 88 --device 3 --multi -export t=ultralytics/yolov3:v89 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 89 --device 1 -export t=ultralytics/yolov3:v90 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 90 --device 0 --cfg cfg/yolov3-spp-matrix.cfg -export t=ultralytics/yolov3:v91 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 91 --device 0 --cfg cfg/yolov3-spp-matrix.cfg +t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 83 --device 6 --multi --nosave +t=ultralytics/yolov3:v84 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 84 --device 0 --multi +t=ultralytics/yolov3:v85 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 85 --device 0 --multi +t=ultralytics/yolov3:v86 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 86 --device 1 --multi +t=ultralytics/yolov3:v87 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 87 --device 2 --multi +t=ultralytics/yolov3:v88 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 88 --device 3 --multi +t=ultralytics/yolov3:v89 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 89 --device 1 +t=ultralytics/yolov3:v90 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 90 --device 0 --cfg cfg/yolov3-spp-matrix.cfg +t=ultralytics/yolov3:v91 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 91 --device 0 --cfg cfg/yolov3-spp-matrix.cfg -export t=ultralytics/yolov3:v92 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 92 --device 0 -export t=ultralytics/yolov3:v93 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 93 --device 0 --cfg cfg/yolov3-spp-matrix.cfg +t=ultralytics/yolov3:v92 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 92 --device 0 +t=ultralytics/yolov3:v93 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 93 --device 0 --cfg cfg/yolov3-spp-matrix.cfg #SM4 -export t=ultralytics/yolov3:v96 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img-size 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 96 --device 0 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -export t=ultralytics/yolov3:v97 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img-size 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 97 --device 4 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -export t=ultralytics/yolov3:v98 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img-size 320 --batch 16 --accum 4 --pre --bucket yolov4 --name 98 --device 5 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -export t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --pre --bucket yolov4 --name 101 --device 7 --multi --nosave - -export t=ultralytics/yolov3:v102 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 1000 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 102 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -export t=ultralytics/yolov3:v103 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 103 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -export t=ultralytics/yolov3:v104 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 104 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -export t=ultralytics/yolov3:v105 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 105 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -export t=ultralytics/yolov3:v106 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 106 --device 0 --cfg cfg/yolov3-tiny-3cls-sm4.cfg --data ../data/sm4/out.data --nosave --cache -export t=ultralytics/yolov3:v107 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 107 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg -export t=ultralytics/yolov3:v108 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 108 --device 7 --nosave - -export t=ultralytics/yolov3:v109 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 109 --device 4 --multi --nosave -export t=ultralytics/yolov3:v110 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 110 --device 3 --multi --nosave - -export t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 111 --device 0 -export t=ultralytics/yolov3:v112 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 112 --device 1 --nosave -export t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 113 --device 2 --nosave -export t=ultralytics/yolov3:v114 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 114 --device 2 --nosave -export t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 115 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg -export t=ultralytics/yolov3:v116 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 116 --device 1 --nosave - -export t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 117 --device 0 --nosave --multi -export t=ultralytics/yolov3:v118 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 118 --device 5 --nosave --multi -export t=ultralytics/yolov3:v119 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 119 --device 1 --nosave -export t=ultralytics/yolov3:v120 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 120 --device 2 --nosave -export t=ultralytics/yolov3:v121 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 121 --device 0 --nosave --cfg cfg/csresnext50-panet-spp.cfg -export t=ultralytics/yolov3:v122 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 122 --device 2 --nosave -export t=ultralytics/yolov3:v123 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 123 --device 5 --nosave - -export t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 124 --device 0 --nosave --cfg yolov3-tiny -export t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 125 --device 1 --nosave --cfg yolov3-tiny2 -export t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 126 --device 1 --nosave --cfg yolov3-tiny3 -export t=ultralytics/yolov3:v127 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 127 --device 0 --nosave --cfg yolov3-tiny4 -export t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 128 --device 1 --nosave --cfg yolov3-tiny2 --multi -export t=ultralytics/yolov3:v129 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 129 --device 0 --nosave --cfg yolov3-tiny2 - -export t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 130 --device 0 --nosave -export t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 250 --pre --bucket yolov4 --name 131 --device 0 --nosave --multi -export t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 132 --device 0 --nosave --data coco2014.data -export t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 27 --pre --bucket yolov4 --name 133 --device 0 --nosave --multi -export t=ultralytics/yolov3:v134 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 134 --device 0 --nosave --data coco2014.data - -export t=ultralytics/yolov3:v135 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 135 --device 0 --nosave --multi --data coco2014.data -export t=ultralytics/yolov3:v136 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 136 --device 0 --nosave --multi --data coco2014.data - -export t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 137 --device 7 --nosave --data coco2014.data -export t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --bucket yolov4 --name 138 --device 6 --nosave --data coco2014.data - -export t=ultralytics/yolov3:v140 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 140 --device 1 --nosave --data coco2014.data --arc uBCE -export t=ultralytics/yolov3:v141 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 141 --device 0 --nosave --data coco2014.data --arc uBCE -export t=ultralytics/yolov3:v142 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 142 --device 1 --nosave --data coco2014.data --arc uBCE - - -export t=ultralytics/yolov3:v139 && sudo docker build -t $t . && sudo docker push $t - -conda update -n base -c defaults conda -conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython future -conda install -yc conda-forge scikit-image pycocotools onnx tensorboard -conda install -yc spyder-ide spyder-line-profiler -conda install -yc pytorch pytorch torchvision \ No newline at end of file +t=ultralytics/yolov3:v96 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img-size 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 96 --device 0 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +t=ultralytics/yolov3:v97 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img-size 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 97 --device 4 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +t=ultralytics/yolov3:v98 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img-size 320 --batch 16 --accum 4 --pre --bucket yolov4 --name 98 --device 5 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --pre --bucket yolov4 --name 101 --device 7 --multi --nosave + +t=ultralytics/yolov3:v102 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 1000 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 102 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v103 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 103 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v104 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 104 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v105 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 105 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v106 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 106 --device 0 --cfg cfg/yolov3-tiny-3cls-sm4.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v107 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 107 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg +t=ultralytics/yolov3:v108 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 108 --device 7 --nosave + +t=ultralytics/yolov3:v109 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 109 --device 4 --multi --nosave +t=ultralytics/yolov3:v110 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 110 --device 3 --multi --nosave + +t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 111 --device 0 +t=ultralytics/yolov3:v112 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 112 --device 1 --nosave +t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 113 --device 2 --nosave +t=ultralytics/yolov3:v114 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 114 --device 2 --nosave +t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 115 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg +t=ultralytics/yolov3:v116 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 116 --device 1 --nosave + +t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 117 --device 0 --nosave --multi +t=ultralytics/yolov3:v118 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 118 --device 5 --nosave --multi +t=ultralytics/yolov3:v119 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 119 --device 1 --nosave +t=ultralytics/yolov3:v120 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 120 --device 2 --nosave +t=ultralytics/yolov3:v121 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 121 --device 0 --nosave --cfg cfg/csresnext50-panet-spp.cfg +t=ultralytics/yolov3:v122 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 122 --device 2 --nosave +t=ultralytics/yolov3:v123 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 123 --device 5 --nosave + +t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 124 --device 0 --nosave --cfg yolov3-tiny +t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 125 --device 1 --nosave --cfg yolov3-tiny2 +t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 126 --device 1 --nosave --cfg yolov3-tiny3 +t=ultralytics/yolov3:v127 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 127 --device 0 --nosave --cfg yolov3-tiny4 +t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 128 --device 1 --nosave --cfg yolov3-tiny2 --multi +t=ultralytics/yolov3:v129 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 129 --device 0 --nosave --cfg yolov3-tiny2 + +t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 130 --device 0 --nosave +t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 250 --pre --bucket yolov4 --name 131 --device 0 --nosave --multi +t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 132 --device 0 --nosave --data coco2014.data +t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 27 --pre --bucket yolov4 --name 133 --device 0 --nosave --multi +t=ultralytics/yolov3:v134 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 134 --device 0 --nosave --data coco2014.data + +t=ultralytics/yolov3:v135 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 135 --device 0 --nosave --multi --data coco2014.data +t=ultralytics/yolov3:v136 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 136 --device 0 --nosave --multi --data coco2014.data + +t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 137 --device 7 --nosave --data coco2014.data +t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --bucket yolov4 --name 138 --device 6 --nosave --data coco2014.data + +t=ultralytics/yolov3:v140 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 140 --device 1 --nosave --data coco2014.data --arc uBCE +t=ultralytics/yolov3:v141 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 141 --device 0 --nosave --data coco2014.data --arc uBCE +t=ultralytics/yolov3:v142 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 142 --device 1 --nosave --data coco2014.data --arc uBCE + +t=ultralytics/yolov3:v146 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 146 --device 0 --nosave --data coco2014.data +t=ultralytics/yolov3:v147 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 147 --device 1 --nosave --data coco2014.data +t=ultralytics/yolov3:v148 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 148 --device 2 --nosave --data coco2014.data +t=ultralytics/yolov3:v149 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 149 --device 3 --nosave --data coco2014.data +t=ultralytics/yolov3:v150 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 150 --device 4 --nosave --data coco2014.data +t=ultralytics/yolov3:v151 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 151 --device 5 --nosave --data coco2014.data +t=ultralytics/yolov3:v152 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 152 --device 6 --nosave --data coco2014.data +t=ultralytics/yolov3:v153 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 153 --device 7 --nosave --data coco2014.data + +t=ultralytics/yolov3:v154 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 154 --device 0 --nosave --data coco2014.data +t=ultralytics/yolov3:v155 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 155 --device 0 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v156 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 156 --device 5 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v157 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 157 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v158 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 158 --device 7 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v159 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 159 --device 0 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v160 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 160 --device 1 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v161 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 161 --device 2 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v162 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 162 --device 3 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v163 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 163 --device 4 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v164 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 164 --device 5 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v165 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 165 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v166 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 166 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v167 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 167 --device 7 --nosave --data coco2014.data --arc defaultpw + + +t=ultralytics/yolov3:v143 && sudo docker build -t $t . && sudo docker push $t diff --git a/utils/utils.py b/utils/utils.py index b9194f9f5f..dcb684b2ad 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -399,7 +399,7 @@ def compute_loss(p, targets, model): # predictions, targets, model pbox = torch.cat((pxy, pwh), 1) # predicted box giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss - tobj[b, a, gj, gi] = 1.0 # giou.detach().type(tobj.dtype) * 0.5 + 0.5 # obj + tobj[b, a, gj, gi] = 1.0 # giou.detach().type(tobj.dtype) if 'default' in arc and model.nc > 1: # cls loss (only if multiple classes) t = torch.zeros_like(ps[:, 5:]) # targets From 5f9229ecaf3f6d6310e2ecfcfb4ed6ea5b33c629 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 28 Dec 2019 21:58:05 -0800 Subject: [PATCH 0231/1185] updates --- utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index dcb684b2ad..6f3dfabfaf 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -372,8 +372,8 @@ def compute_loss(p, targets, model): # predictions, targets, model # Define criteria BCEcls = nn.BCEWithLogitsLoss(pos_weight=ft([h['cls_pw']]), reduction=red) BCEobj = nn.BCEWithLogitsLoss(pos_weight=ft([h['obj_pw']]), reduction=red) - BCE = nn.BCEWithLogitsLoss() - CE = nn.CrossEntropyLoss() # weight=model.class_weights + BCE = nn.BCEWithLogitsLoss(reduction=red) + CE = nn.CrossEntropyLoss(reduction=red) # weight=model.class_weights if 'F' in arc: # add focal loss g = h['fl_gamma'] From f964f2956743e08aae141a0301ad040f3d1f068b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 29 Dec 2019 10:02:41 -0800 Subject: [PATCH 0232/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 6f3dfabfaf..5be021b96d 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -783,7 +783,7 @@ def print_mutation(hyp, results, bucket=''): print('\n%s\n%s\nEvolved fitness: %s\n' % (a, b, c)) if bucket: - os.system('gsutil cp gs://%s/evolve.txt .' % bucket) # download evolve.txt + os.system('rm evolve.txt && gsutil cp gs://%s/evolve.txt .' % bucket) # download evolve.txt with open('evolve.txt', 'a') as f: # append result f.write(c + b + '\n') From 894218390b44fa48f19875b4f5b89f23a788158e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 29 Dec 2019 14:28:56 -0800 Subject: [PATCH 0233/1185] updates --- models.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/models.py b/models.py index c3bf5a1811..c4e751a51b 100755 --- a/models.py +++ b/models.py @@ -260,8 +260,7 @@ def forward(self, x, var=None): elif mtype == 'shortcut': x = x + layer_outputs[int(mdef['from'])] elif mtype == 'yolo': - x = module(x, img_size) - output.append(x) + output.append(module(x, img_size)) layer_outputs.append(x if i in self.routs else []) if self.training: From d13312b751d81f0036de70ae58faeb48daa2674a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 29 Dec 2019 14:54:08 -0800 Subject: [PATCH 0234/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index c4e751a51b..3304a50619 100755 --- a/models.py +++ b/models.py @@ -13,7 +13,7 @@ def create_modules(module_defs, img_size, arc): hyperparams = module_defs.pop(0) output_filters = [int(hyperparams['channels'])] module_list = nn.ModuleList() - routs = [] # list of layers which rout to deeper layes + routs = [] # list of layers which rout to deeper layers yolo_index = -1 for i, mdef in enumerate(module_defs): From f3e87862a40fba4d01edb8dc7eec3eadfa2d1c3f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 29 Dec 2019 15:31:57 -0800 Subject: [PATCH 0235/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 5be021b96d..feba41839a 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -507,7 +507,7 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru # NMS methods https://github.com/ultralytics/yolov3/issues/679 'or', 'and', 'merge', 'vision', 'vision_batch' # Box constraints - min_wh, max_wh = 2, 4096 # (pixels) minimum and maximium box width and height + min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height output = [None] * len(prediction) for image_i, pred in enumerate(prediction): From b636f7f7ab66bd40d8f86f60e2fe31d8c0d54ea6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 11:57:36 -0800 Subject: [PATCH 0236/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index feba41839a..06d0b7996a 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -760,7 +760,7 @@ def kmeans_targets(path='../coco/trainvalno5k.txt', n=9, img_size=416): # from # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.') # Measure IoUs - iou = torch.stack([wh_iou(torch.Tensor(wh).T, torch.Tensor(x).T) for x in k], 0) + iou = wh_iou(torch.Tensor(wh), torch.Tensor(k)) biou = iou.max(0)[0] # closest anchor IoU print('Best possible recall: %.3f' % (biou > 0.2635).float().mean()) # BPR (best possible recall) From 88579bd24e68bd4d284a19f7e3685ccb560d4958 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 12:01:52 -0800 Subject: [PATCH 0237/1185] updates --- utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 06d0b7996a..1544d87460 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -734,7 +734,7 @@ def coco_single_class_labels(path='../coco/labels/train2014/', label_class=43): shutil.copyfile(src=img_file, dst='new/images/' + Path(file).name.replace('txt', 'jpg')) # copy images -def kmeans_targets(path='../coco/trainvalno5k.txt', n=9, img_size=416): # from utils.utils import *; kmeans_targets() +def kmeans_targets(path='data/coco64.txt', n=9, img_size=416): # from utils.utils import *; kmeans_targets() # Produces a list of target kmeans suitable for use in *.cfg files from utils.datasets import LoadImagesAndLabels from scipy import cluster @@ -762,7 +762,7 @@ def kmeans_targets(path='../coco/trainvalno5k.txt', n=9, img_size=416): # from # Measure IoUs iou = wh_iou(torch.Tensor(wh), torch.Tensor(k)) biou = iou.max(0)[0] # closest anchor IoU - print('Best possible recall: %.3f' % (biou > 0.2635).float().mean()) # BPR (best possible recall) + print('Best Possible Recall (BPR): %.3f' % (biou > 0.2635).float().mean()) # BPR (best possible recall) # Print print('kmeans anchors (n=%g, img_size=%g, IoU=%.2f/%.2f/%.2f-min/mean/best): ' % From e4a797fc1ec612704ec7d5eae1e7b696b850e2c0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 13:09:16 -0800 Subject: [PATCH 0238/1185] updates --- utils/utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 1544d87460..c017bc81c8 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -744,7 +744,9 @@ def kmeans_targets(path='data/coco64.txt', n=9, img_size=416): # from utils.uti for s, l in zip(dataset.shapes, dataset.labels): l[:, [1, 3]] *= s[0] # normalized to pixels l[:, [2, 4]] *= s[1] - l[:, 1:] *= img_size / max(s) * random.uniform(0.5, 1.5) # nominal img_size for training + l[:, 1:] *= img_size / max(s) + l = l.repeat(10, axis=0) # augment 10x + l *= np.random.uniform(0.5, 1.5, size=(l.shape[0], 1)) # multi-scale box wh = np.concatenate(dataset.labels, 0)[:, 3:5] # wh from cxywh # Kmeans calculation @@ -762,7 +764,7 @@ def kmeans_targets(path='data/coco64.txt', n=9, img_size=416): # from utils.uti # Measure IoUs iou = wh_iou(torch.Tensor(wh), torch.Tensor(k)) biou = iou.max(0)[0] # closest anchor IoU - print('Best Possible Recall (BPR): %.3f' % (biou > 0.2635).float().mean()) # BPR (best possible recall) + print('Best Possible Recall (BPR): %.3f' % (biou > 0.225).float().mean()) # BPR (best possible recall) # Print print('kmeans anchors (n=%g, img_size=%g, IoU=%.2f/%.2f/%.2f-min/mean/best): ' % From 121526aa9866ad752be222e9e1c619744c1d6bbf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 13:15:10 -0800 Subject: [PATCH 0239/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index c017bc81c8..ab27baf547 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -746,7 +746,7 @@ def kmeans_targets(path='data/coco64.txt', n=9, img_size=416): # from utils.uti l[:, [2, 4]] *= s[1] l[:, 1:] *= img_size / max(s) l = l.repeat(10, axis=0) # augment 10x - l *= np.random.uniform(0.5, 1.5, size=(l.shape[0], 1)) # multi-scale box + l *= np.random.uniform(288, 640, size=(l.shape[0], 1)) / img_size # multi-scale box wh = np.concatenate(dataset.labels, 0)[:, 3:5] # wh from cxywh # Kmeans calculation From ad20ccce65b7925bb53fe370cf9e643b1ab88e42 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 13:28:32 -0800 Subject: [PATCH 0240/1185] updates --- utils/utils.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index ab27baf547..5fc59a5acf 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -740,14 +740,14 @@ def kmeans_targets(path='data/coco64.txt', n=9, img_size=416): # from utils.uti from scipy import cluster # Get label wh + wh = [] dataset = LoadImagesAndLabels(path, augment=True, rect=True, cache_labels=True) for s, l in zip(dataset.shapes, dataset.labels): - l[:, [1, 3]] *= s[0] # normalized to pixels - l[:, [2, 4]] *= s[1] - l[:, 1:] *= img_size / max(s) + l = l[:, 3:5] * (s / max(s)) # image normalized to letterbox normalized wh l = l.repeat(10, axis=0) # augment 10x - l *= np.random.uniform(288, 640, size=(l.shape[0], 1)) / img_size # multi-scale box - wh = np.concatenate(dataset.labels, 0)[:, 3:5] # wh from cxywh + l *= np.random.uniform(img_size[0], img_size[1], size=(l.shape[0], 1)) # normalized to pixels (multi-scale) + wh.append(l) + wh = np.concatenate(wh, 0) # wh from cxywh # Kmeans calculation k, dist = cluster.vq.kmeans(wh, n) # points, mean distance @@ -767,7 +767,7 @@ def kmeans_targets(path='data/coco64.txt', n=9, img_size=416): # from utils.uti print('Best Possible Recall (BPR): %.3f' % (biou > 0.225).float().mean()) # BPR (best possible recall) # Print - print('kmeans anchors (n=%g, img_size=%g, IoU=%.2f/%.2f/%.2f-min/mean/best): ' % + print('kmeans anchors (n=%g, img_size=%s, IoU=%.2f/%.2f/%.2f-min/mean/best): ' % (n, img_size, biou.min(), iou.mean(), biou.mean()), end='') for i, x in enumerate(k): print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg From 017a5ddad0ac97154aac6be1a3685350b31cfeeb Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 13:28:46 -0800 Subject: [PATCH 0241/1185] updates --- cfg/yolov3-spp.cfg | 4 +++ train.py | 2 +- utils/gcp.sh | 89 ++++++++++++++++++++++++++-------------------- utils/utils.py | 2 +- 4 files changed, 56 insertions(+), 41 deletions(-) diff --git a/cfg/yolov3-spp.cfg b/cfg/yolov3-spp.cfg index bb4e893bf6..c55de0fa05 100644 --- a/cfg/yolov3-spp.cfg +++ b/cfg/yolov3-spp.cfg @@ -813,6 +813,10 @@ activation=linear [yolo] mask = 0,1,2 anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +anchors = +13,14, 26,40, 66,39, 49,94, 126,83, 94,177, 235,135, 179,286, 364,245 +13,14, 27,39, 68,40, 48,93, 126,84, 93,177, 234,135, 179,286, 364,244 +12,13, 27,37, 69,41, 47,90, 129,85, 90,172, 240,136, 173,282, 361,251 classes=80 num=9 jitter=.3 diff --git a/train.py b/train.py index 65151cecb3..4039e29fb7 100644 --- a/train.py +++ b/train.py @@ -446,7 +446,7 @@ def prebias(): mixed_precision = False # scale hyp['obj'] by img_size (evolved at 320) - hyp['obj'] *= opt.img_size / 320. + # hyp['obj'] *= opt.img_size / 320. tb_writer = None if not opt.evolve: # Train normally diff --git a/utils/gcp.sh b/utils/gcp.sh index c26015aced..a0b28f5f62 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -30,9 +30,9 @@ python3 detect.py python3 test.py --save-json # Evolve -t=ultralytics/yolov3:v148 +t=ultralytics/yolov3:v176 sudo docker kill $(sudo docker ps -a -q --filter ancestor=$t) -for i in 0 1 2 3 4 5 6 7 +for i in 0 do sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i sleep 10 @@ -66,9 +66,9 @@ gsutil cp results.png gs://ultralytics sudo shutdown # Reproduce mAP -python3 test.py --save-json --img-size 608 -python3 test.py --save-json --img-size 416 -python3 test.py --save-json --img-size 320 +python3 test.py --save-json --img 608 +python3 test.py --save-json --img 416 +python3 test.py --save-json --img 320 sudo shutdown # Benchmark script @@ -125,16 +125,16 @@ t=ultralytics/yolov3:v93 && sudo docker pull $t && sudo nvidia-docker run -it -- #SM4 -t=ultralytics/yolov3:v96 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img-size 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 96 --device 0 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -t=ultralytics/yolov3:v97 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img-size 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 97 --device 4 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -t=ultralytics/yolov3:v98 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img-size 320 --batch 16 --accum 4 --pre --bucket yolov4 --name 98 --device 5 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +t=ultralytics/yolov3:v96 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 96 --device 0 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +t=ultralytics/yolov3:v97 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 97 --device 4 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +t=ultralytics/yolov3:v98 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 16 --accum 4 --pre --bucket yolov4 --name 98 --device 5 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --pre --bucket yolov4 --name 101 --device 7 --multi --nosave -t=ultralytics/yolov3:v102 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 1000 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 102 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v103 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 103 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v104 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 104 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v105 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 105 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v106 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img-size 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 106 --device 0 --cfg cfg/yolov3-tiny-3cls-sm4.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v102 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 1000 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 102 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v103 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 103 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v104 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 104 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v105 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 105 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v106 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 106 --device 0 --cfg cfg/yolov3-tiny-3cls-sm4.cfg --data ../data/sm4/out.data --nosave --cache t=ultralytics/yolov3:v107 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 107 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg t=ultralytics/yolov3:v108 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 108 --device 7 --nosave @@ -179,31 +179,42 @@ t=ultralytics/yolov3:v140 && sudo docker pull $t && sudo nvidia-docker run -it - t=ultralytics/yolov3:v141 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 141 --device 0 --nosave --data coco2014.data --arc uBCE t=ultralytics/yolov3:v142 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 142 --device 1 --nosave --data coco2014.data --arc uBCE -t=ultralytics/yolov3:v146 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 146 --device 0 --nosave --data coco2014.data -t=ultralytics/yolov3:v147 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 147 --device 1 --nosave --data coco2014.data -t=ultralytics/yolov3:v148 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 148 --device 2 --nosave --data coco2014.data -t=ultralytics/yolov3:v149 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 149 --device 3 --nosave --data coco2014.data -t=ultralytics/yolov3:v150 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 150 --device 4 --nosave --data coco2014.data -t=ultralytics/yolov3:v151 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 151 --device 5 --nosave --data coco2014.data -t=ultralytics/yolov3:v152 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 152 --device 6 --nosave --data coco2014.data -t=ultralytics/yolov3:v153 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 153 --device 7 --nosave --data coco2014.data - -t=ultralytics/yolov3:v154 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 154 --device 0 --nosave --data coco2014.data -t=ultralytics/yolov3:v155 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 155 --device 0 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v156 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 156 --device 5 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v157 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 157 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v158 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 158 --device 7 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v159 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 159 --device 0 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v160 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 160 --device 1 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v161 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 161 --device 2 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v162 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 162 --device 3 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v163 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 163 --device 4 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v164 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 164 --device 5 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v165 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 165 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v166 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 166 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v167 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img-size 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 167 --device 7 --nosave --data coco2014.data --arc defaultpw - +t=ultralytics/yolov3:v146 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 146 --device 0 --nosave --data coco2014.data +t=ultralytics/yolov3:v147 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 147 --device 1 --nosave --data coco2014.data +t=ultralytics/yolov3:v148 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 148 --device 2 --nosave --data coco2014.data +t=ultralytics/yolov3:v149 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 149 --device 3 --nosave --data coco2014.data +t=ultralytics/yolov3:v150 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 150 --device 4 --nosave --data coco2014.data +t=ultralytics/yolov3:v151 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 151 --device 5 --nosave --data coco2014.data +t=ultralytics/yolov3:v152 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 152 --device 6 --nosave --data coco2014.data +t=ultralytics/yolov3:v153 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 153 --device 7 --nosave --data coco2014.data + +t=ultralytics/yolov3:v154 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 154 --device 0 --nosave --data coco2014.data +t=ultralytics/yolov3:v155 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 155 --device 0 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v156 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 156 --device 5 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v157 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 157 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v158 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 158 --device 7 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v159 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 159 --device 0 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v160 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 160 --device 1 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v161 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 161 --device 2 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v162 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 162 --device 3 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v163 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 163 --device 4 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v164 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 164 --device 5 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v165 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 165 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v166 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 166 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v167 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 167 --device 7 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v168 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 168 --device 5 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v169 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 169 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v170 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 170 --device 7 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v171 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 171 --device 4 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v172 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 172 --device 3 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v173 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 173 --device 2 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v174 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 174 --device 1 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v175 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 175 --device 0 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v177 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 177 --device 0 --nosave --data coco2014.data --multi +t=ultralytics/yolov3:v178 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 178 --device 0 --nosave --data coco2014.data --multi t=ultralytics/yolov3:v143 && sudo docker build -t $t . && sudo docker push $t diff --git a/utils/utils.py b/utils/utils.py index 5fc59a5acf..da494056d9 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -734,7 +734,7 @@ def coco_single_class_labels(path='../coco/labels/train2014/', label_class=43): shutil.copyfile(src=img_file, dst='new/images/' + Path(file).name.replace('txt', 'jpg')) # copy images -def kmeans_targets(path='data/coco64.txt', n=9, img_size=416): # from utils.utils import *; kmeans_targets() +def kmean_anchors(path='data/coco64.txt', n=9, img_size=(288, 640)): # from utils.utils import *; kmean_anchors() # Produces a list of target kmeans suitable for use in *.cfg files from utils.datasets import LoadImagesAndLabels from scipy import cluster From 14ac814cf9a0f0c35cd96574211f56374a3a5c8c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 13:30:58 -0800 Subject: [PATCH 0242/1185] updates --- cfg/yolov3-spp.cfg | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cfg/yolov3-spp.cfg b/cfg/yolov3-spp.cfg index c55de0fa05..bb4e893bf6 100644 --- a/cfg/yolov3-spp.cfg +++ b/cfg/yolov3-spp.cfg @@ -813,10 +813,6 @@ activation=linear [yolo] mask = 0,1,2 anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -anchors = -13,14, 26,40, 66,39, 49,94, 126,83, 94,177, 235,135, 179,286, 364,245 -13,14, 27,39, 68,40, 48,93, 126,84, 93,177, 234,135, 179,286, 364,244 -12,13, 27,37, 69,41, 47,90, 129,85, 90,172, 240,136, 173,282, 361,251 classes=80 num=9 jitter=.3 From 9e581919839da2e7810416410b0dc321450a0a9b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 13:31:32 -0800 Subject: [PATCH 0243/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 4039e29fb7..65151cecb3 100644 --- a/train.py +++ b/train.py @@ -446,7 +446,7 @@ def prebias(): mixed_precision = False # scale hyp['obj'] by img_size (evolved at 320) - # hyp['obj'] *= opt.img_size / 320. + hyp['obj'] *= opt.img_size / 320. tb_writer = None if not opt.evolve: # Train normally From cf92235b8db7319e87c9e0d0c5d3920ee418aec8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 13:39:25 -0800 Subject: [PATCH 0244/1185] updates --- utils/utils.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index da494056d9..3464a2fefb 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -743,13 +743,12 @@ def kmean_anchors(path='data/coco64.txt', n=9, img_size=(288, 640)): # from uti wh = [] dataset = LoadImagesAndLabels(path, augment=True, rect=True, cache_labels=True) for s, l in zip(dataset.shapes, dataset.labels): - l = l[:, 3:5] * (s / max(s)) # image normalized to letterbox normalized wh - l = l.repeat(10, axis=0) # augment 10x - l *= np.random.uniform(img_size[0], img_size[1], size=(l.shape[0], 1)) # normalized to pixels (multi-scale) - wh.append(l) - wh = np.concatenate(wh, 0) # wh from cxywh + wh.append(l[:, 3:5] * (s / s.max())) # image normalized to letterbox normalized wh + wh = np.concatenate(wh, 0).repeat(10, axis=0) # augment 10x + wh *= np.random.uniform(img_size[0], img_size[1], size=(wh.shape[0], 1)) # normalized to pixels (multi-scale) # Kmeans calculation + print('Running kmeans...') k, dist = cluster.vq.kmeans(wh, n) # points, mean distance k = k[np.argsort(k.prod(1))] # sort small to large From 7b6bd39c9e8170d614fe8d20c1ed3e6a89d170c0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 13:46:21 -0800 Subject: [PATCH 0245/1185] updates --- utils/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 3464a2fefb..1a9fe5dbb5 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -762,7 +762,8 @@ def kmean_anchors(path='data/coco64.txt', n=9, img_size=(288, 640)): # from uti # Measure IoUs iou = wh_iou(torch.Tensor(wh), torch.Tensor(k)) - biou = iou.max(0)[0] # closest anchor IoU + biou = iou.max(1)[0] # closest anchor IoU + print(biou.shape) print('Best Possible Recall (BPR): %.3f' % (biou > 0.225).float().mean()) # BPR (best possible recall) # Print From 2cf31ab7bc644b2b5bdecefc39a9c8e954cf45a0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 13:46:40 -0800 Subject: [PATCH 0246/1185] updates --- utils/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 1a9fe5dbb5..8b033520c6 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -763,7 +763,6 @@ def kmean_anchors(path='data/coco64.txt', n=9, img_size=(288, 640)): # from uti # Measure IoUs iou = wh_iou(torch.Tensor(wh), torch.Tensor(k)) biou = iou.max(1)[0] # closest anchor IoU - print(biou.shape) print('Best Possible Recall (BPR): %.3f' % (biou > 0.225).float().mean()) # BPR (best possible recall) # Print From d30e4eea37a25f0ba7e073f9a8e10dd7bbc4145e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 15:39:17 -0800 Subject: [PATCH 0247/1185] updates --- utils/utils.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 8b033520c6..6f1301aaa7 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -734,7 +734,7 @@ def coco_single_class_labels(path='../coco/labels/train2014/', label_class=43): shutil.copyfile(src=img_file, dst='new/images/' + Path(file).name.replace('txt', 'jpg')) # copy images -def kmean_anchors(path='data/coco64.txt', n=9, img_size=(288, 640)): # from utils.utils import *; kmean_anchors() +def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 640)): # from utils.utils import *; kmean_anchors() # Produces a list of target kmeans suitable for use in *.cfg files from utils.datasets import LoadImagesAndLabels from scipy import cluster @@ -762,12 +762,14 @@ def kmean_anchors(path='data/coco64.txt', n=9, img_size=(288, 640)): # from uti # Measure IoUs iou = wh_iou(torch.Tensor(wh), torch.Tensor(k)) - biou = iou.max(1)[0] # closest anchor IoU - print('Best Possible Recall (BPR): %.3f' % (biou > 0.225).float().mean()) # BPR (best possible recall) + max_iou = iou.max(1)[0] # best IoU + min_iou = iou.min(1)[0] # worst IoU + print('Best Possible Recall (BPR): %.3f' % (max_iou > 0.225).float().mean()) # BPR (best possible recall) + print('Mean anchors over threshold: %.3f' % ((iou > 0.225).float().mean() * n)) # BPR (best possible recall) # Print print('kmeans anchors (n=%g, img_size=%s, IoU=%.2f/%.2f/%.2f-min/mean/best): ' % - (n, img_size, biou.min(), iou.mean(), biou.mean()), end='') + (n, img_size, min_iou.mean(), iou.mean(), max_iou.mean()), end='') for i, x in enumerate(k): print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg From 9dd1316a70dac982bd32d58b0d1a03e1b6d50b63 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 15:41:47 -0800 Subject: [PATCH 0248/1185] updates --- utils/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 6f1301aaa7..2c6be16334 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -435,8 +435,9 @@ def compute_loss(p, targets, model): # predictions, targets, model lobj *= h['obj'] lcls *= h['cls'] if red == 'sum': + bs = tobj.shape[0] # batch size lbox *= 3 / ng - lobj *= 3 / np * 2 + lobj *= 3 / (6300 * bs) * 2 # 3 / np * 2 lcls *= 3 / ng / model.nc loss = lbox + lobj + lcls From 6290f9fdb73f68989a94d70fbeab703cac94261d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Dec 2019 16:13:06 -0800 Subject: [PATCH 0249/1185] updates --- train.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 65151cecb3..c6ad904823 100644 --- a/train.py +++ b/train.py @@ -137,7 +137,7 @@ def train(): cutoff = load_darknet_weights(model, weights) if opt.transfer or opt.prebias: # transfer learning edge (yolo) layers - nf = int(model.module_defs[model.yolo_layers[0] - 1]['filters']) # yolo layer size (i.e. 255) + nf = [int(model.module_defs[x - 1]['filters']) for x in model.yolo_layers] # yolo layer size (i.e. 255) if opt.prebias: for p in optimizer.param_groups: @@ -147,9 +147,9 @@ def train(): p['momentum'] = 0.9 for p in model.parameters(): - if opt.prebias and p.numel() == nf: # train (yolo biases) + if opt.prebias and p.numel() in nf: # train (yolo biases) p.requires_grad = True - elif opt.transfer and p.shape[0] == nf: # train (yolo biases+weights) + elif opt.transfer and p.shape[0] in nf: # train (yolo biases+weights) p.requires_grad = True else: # freeze layer p.requires_grad = False From 935bbfcc2bc8d7b07e61e6d2cd6d5d968c22bdfa Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 31 Dec 2019 12:07:31 -0800 Subject: [PATCH 0250/1185] updates --- utils/utils.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 2c6be16334..c7da014caf 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -735,7 +735,8 @@ def coco_single_class_labels(path='../coco/labels/train2014/', label_class=43): shutil.copyfile(src=img_file, dst='new/images/' + Path(file).name.replace('txt', 'jpg')) # copy images -def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 640)): # from utils.utils import *; kmean_anchors() +def kmean_anchors(path='data/coco64.txt', n=12, img_size=(320, 640)): + # from utils.utils import *; _ = kmean_anchors(n=9) # Produces a list of target kmeans suitable for use in *.cfg files from utils.datasets import LoadImagesAndLabels from scipy import cluster @@ -763,10 +764,10 @@ def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 640)): # f # Measure IoUs iou = wh_iou(torch.Tensor(wh), torch.Tensor(k)) - max_iou = iou.max(1)[0] # best IoU - min_iou = iou.min(1)[0] # worst IoU - print('Best Possible Recall (BPR): %.3f' % (max_iou > 0.225).float().mean()) # BPR (best possible recall) - print('Mean anchors over threshold: %.3f' % ((iou > 0.225).float().mean() * n)) # BPR (best possible recall) + min_iou, max_iou = iou.min(1)[0], iou.max(1)[0] + for x in [0.10, 0.15, 0.20, 0.25, 0.30, 0.35]: # iou thresholds + print('%.2f iou_thr: %.3f best possible recall, %.3f anchors > thr' % + (x, (max_iou > x).float().mean(), (iou > x).float().mean() * n)) # BPR (best possible recall) # Print print('kmeans anchors (n=%g, img_size=%s, IoU=%.2f/%.2f/%.2f-min/mean/best): ' % From d92b75aec819a45680fe40e133d8e3c29d0b6a40 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 1 Jan 2020 12:44:33 -0800 Subject: [PATCH 0251/1185] updates --- detect.py | 9 +++++---- utils/utils.py | 6 +++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/detect.py b/detect.py index 74838a49f2..da919b37ed 100644 --- a/detect.py +++ b/detect.py @@ -86,7 +86,7 @@ def detect(save_txt=False, save_img=False): pred = pred.float() # Apply NMS - pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres) + pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, classes=opt.classes) # Apply Classifier if classify: @@ -110,9 +110,6 @@ def detect(save_txt=False, save_img=False): n = (det[:, -1] == c).sum() # detections per class s += '%g %ss, ' % (n, names[int(c)]) # add to string - # Print time (inference + NMS) - print('%sDone. (%.3fs)' % (s, time.time() - t)) - # Write results for *xyxy, conf, cls in det: if save_txt: # Write to file @@ -123,6 +120,9 @@ def detect(save_txt=False, save_img=False): label = '%s %.2f' % (names[int(cls)], conf) plot_one_box(xyxy, im0, label=label, color=colors[int(cls)]) + # Print time (inference + NMS) + print('%sDone. (%.3fs)' % (s, time.time() - t)) + # Stream results if view_img: cv2.imshow(p, im0) @@ -167,6 +167,7 @@ def detect(save_txt=False, save_img=False): parser.add_argument('--half', action='store_true', help='half precision FP16 inference') parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') parser.add_argument('--view-img', action='store_true', help='display results') + parser.add_argument('--classes', nargs='+', type=int, help='filter by class') opt = parser.parse_args() print(opt) diff --git a/utils/utils.py b/utils/utils.py index c7da014caf..684fbf48ac 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -498,7 +498,7 @@ def build_targets(model, targets): return tcls, tbox, indices, av -def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=True, method='vision_batch'): +def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=True, method='vision_batch', classes=None): """ Removes detections with lower object confidence score than 'conf_thres' Non-Maximum Suppression to further filter detections. @@ -537,6 +537,10 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru conf, j = pred[:, 5:].max(1) pred = torch.cat((box, conf.unsqueeze(1), j.float().unsqueeze(1)), 1) + # Filter by class + if classes: + pred = pred[(j.view(-1, 1) == torch.Tensor(classes)).any(1)] + # Apply finite constraint if not torch.isfinite(pred).all(): pred = pred[torch.isfinite(pred).all(1)] From 77850a2198132b2cab0919088f219ba23e3c87b6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 1 Jan 2020 22:44:21 -0800 Subject: [PATCH 0252/1185] updates --- utils/gcp.sh | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index a0b28f5f62..55fb3f8248 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -6,7 +6,7 @@ git clone https://github.com/ultralytics/yolov3 git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex sudo conda install -yc conda-forge scikit-image pycocotools python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('193Zp_ye-3qXMonR1nZj3YyxMtQkMy50k','coco2014.zip')" -python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco2017.zip')" +# python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco2017.zip')" sudo shutdown # Re-clone @@ -17,6 +17,13 @@ bash yolov3/data/get_coco2017.sh cd yolov3 python3 test.py --weights ultralytics68.pt --task benchmark +# Mount local SSD +lsblk +sudo mkfs.ext4 -F /dev/nvme0n1 +sudo mkdir -p /mnt/disks/nvme0n1 +sudo mount /dev/nvme0n1 /mnt/disks/nvme0n1 +sudo chmod a+w /mnt/disks/nvme0n1 + # Train python3 train.py @@ -30,11 +37,11 @@ python3 detect.py python3 test.py --save-json # Evolve -t=ultralytics/yolov3:v176 +t=ultralytics/yolov3:v179 sudo docker kill $(sudo docker ps -a -q --filter ancestor=$t) for i in 0 do - sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i + sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i sleep 10 done @@ -216,5 +223,8 @@ t=ultralytics/yolov3:v175 && sudo docker pull $t && sudo nvidia-docker run -it - t=ultralytics/yolov3:v177 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 177 --device 0 --nosave --data coco2014.data --multi t=ultralytics/yolov3:v178 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 178 --device 0 --nosave --data coco2014.data --multi +t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 179 --device 0 --nosave --data coco2014.data --multi --cfg yolov3s-18a.cfg t=ultralytics/yolov3:v143 && sudo docker build -t $t . && sudo docker push $t + +t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 detect.py From 23288236a6192736d1e98548705e1f98a2d64f02 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Jan 2020 09:50:11 -0800 Subject: [PATCH 0253/1185] updates --- detect.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/detect.py b/detect.py index da919b37ed..b9ddbf0f5e 100644 --- a/detect.py +++ b/detect.py @@ -6,9 +6,9 @@ from utils.utils import * -def detect(save_txt=False, save_img=False): +def detect(save_img=False): img_size = (320, 192) if ONNX_EXPORT else opt.img_size # (320, 192) or (416, 256) or (608, 352) for (height, width) - out, source, weights, half, view_img = opt.output, opt.source, opt.weights, opt.half, opt.view_img + out, source, weights, half, view_img, save_txt = opt.output, opt.source, opt.weights, opt.half, opt.view_img, opt.save_txt webcam = source == '0' or source.startswith('rtsp') or source.startswith('http') or source.endswith('.txt') # Initialize @@ -167,6 +167,7 @@ def detect(save_txt=False, save_img=False): parser.add_argument('--half', action='store_true', help='half precision FP16 inference') parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') parser.add_argument('--view-img', action='store_true', help='display results') + parser.add_argument('--save-txt', action='store_true', help='display results') parser.add_argument('--classes', nargs='+', type=int, help='filter by class') opt = parser.parse_args() print(opt) From 8841c4980cb88a430b715658fdef20b410140b76 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Jan 2020 10:03:22 -0800 Subject: [PATCH 0254/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 684fbf48ac..5d97f33f4d 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -770,7 +770,7 @@ def kmean_anchors(path='data/coco64.txt', n=12, img_size=(320, 640)): iou = wh_iou(torch.Tensor(wh), torch.Tensor(k)) min_iou, max_iou = iou.min(1)[0], iou.max(1)[0] for x in [0.10, 0.15, 0.20, 0.25, 0.30, 0.35]: # iou thresholds - print('%.2f iou_thr: %.3f best possible recall, %.3f anchors > thr' % + print('%.2f iou_thr: %.3f best possible recall, %.1f anchors > thr' % (x, (max_iou > x).float().mean(), (iou > x).float().mean() * n)) # BPR (best possible recall) # Print From 0883d2fda1cffa3ce74086ebe5c1a3f23bc857b1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Jan 2020 11:09:10 -0800 Subject: [PATCH 0255/1185] updates --- utils/utils.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 5d97f33f4d..295fada2d0 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -739,29 +739,31 @@ def coco_single_class_labels(path='../coco/labels/train2014/', label_class=43): shutil.copyfile(src=img_file, dst='new/images/' + Path(file).name.replace('txt', 'jpg')) # copy images -def kmean_anchors(path='data/coco64.txt', n=12, img_size=(320, 640)): +def kmean_anchors(path='data/coco64.txt', n=9, img_size=(320, 640)): # from utils.utils import *; _ = kmean_anchors(n=9) # Produces a list of target kmeans suitable for use in *.cfg files from utils.datasets import LoadImagesAndLabels - from scipy import cluster + from scipy.cluster.vq import kmeans # Get label wh wh = [] dataset = LoadImagesAndLabels(path, augment=True, rect=True, cache_labels=True) + nr = 1 if img_size[0] == img_size[1] else 10 # number augmentation repetitions for s, l in zip(dataset.shapes, dataset.labels): wh.append(l[:, 3:5] * (s / s.max())) # image normalized to letterbox normalized wh - wh = np.concatenate(wh, 0).repeat(10, axis=0) # augment 10x + wh = np.concatenate(wh, 0).repeat(nr, axis=0) # augment 10x wh *= np.random.uniform(img_size[0], img_size[1], size=(wh.shape[0], 1)) # normalized to pixels (multi-scale) # Kmeans calculation print('Running kmeans...') - k, dist = cluster.vq.kmeans(wh, n) # points, mean distance - k = k[np.argsort(k.prod(1))] # sort small to large + s = wh.std(0) # sigmas for whitening + k, dist = kmeans(wh / s, n, iter=30) # points, mean distance + k = k[np.argsort(k.prod(1))] * s # sort small to large # # Plot # k, d = [None] * 20, [None] * 20 # for i in tqdm(range(1, 21)): - # k[i-1], d[i-1] = cluster.vq.kmeans(wh, i) # points, mean distance + # k[i-1], d[i-1] = kmeans(wh / s, i) # points, mean distance # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # ax = ax.ravel() # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.') @@ -769,8 +771,8 @@ def kmean_anchors(path='data/coco64.txt', n=12, img_size=(320, 640)): # Measure IoUs iou = wh_iou(torch.Tensor(wh), torch.Tensor(k)) min_iou, max_iou = iou.min(1)[0], iou.max(1)[0] - for x in [0.10, 0.15, 0.20, 0.25, 0.30, 0.35]: # iou thresholds - print('%.2f iou_thr: %.3f best possible recall, %.1f anchors > thr' % + for x in [0.10, 0.20, 0.30]: # iou thresholds + print('%.2f iou_thr: %.3f best possible recall, %.2f anchors > thr' % (x, (max_iou > x).float().mean(), (iou > x).float().mean() * n)) # BPR (best possible recall) # Print From e0e8b7173cd47898b0fc0e5af7362471c194289b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Jan 2020 11:11:18 -0800 Subject: [PATCH 0256/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 295fada2d0..05655db597 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -755,7 +755,7 @@ def kmean_anchors(path='data/coco64.txt', n=9, img_size=(320, 640)): wh *= np.random.uniform(img_size[0], img_size[1], size=(wh.shape[0], 1)) # normalized to pixels (multi-scale) # Kmeans calculation - print('Running kmeans...') + print('Running kmeans on %g boxes...' % len(wh)) s = wh.std(0) # sigmas for whitening k, dist = kmeans(wh / s, n, iter=30) # points, mean distance k = k[np.argsort(k.prod(1))] * s # sort small to large From 0b242a438b88448b1889c0db3260f1f4a9d671b8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Jan 2020 11:11:45 -0800 Subject: [PATCH 0257/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 05655db597..190dfdcf64 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -755,7 +755,7 @@ def kmean_anchors(path='data/coco64.txt', n=9, img_size=(320, 640)): wh *= np.random.uniform(img_size[0], img_size[1], size=(wh.shape[0], 1)) # normalized to pixels (multi-scale) # Kmeans calculation - print('Running kmeans on %g boxes...' % len(wh)) + print('Running kmeans on %g points...' % len(wh)) s = wh.std(0) # sigmas for whitening k, dist = kmeans(wh / s, n, iter=30) # points, mean distance k = k[np.argsort(k.prod(1))] * s # sort small to large From d9568a2239ca5d32c03dc88b41d59489598e67f7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Jan 2020 12:39:20 -0800 Subject: [PATCH 0258/1185] updates --- utils/gcp.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index 55fb3f8248..e5f3355db1 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -23,6 +23,7 @@ sudo mkfs.ext4 -F /dev/nvme0n1 sudo mkdir -p /mnt/disks/nvme0n1 sudo mount /dev/nvme0n1 /mnt/disks/nvme0n1 sudo chmod a+w /mnt/disks/nvme0n1 +cp -r coco /mnt/disks/nvme0n1 # Train python3 train.py @@ -41,7 +42,8 @@ t=ultralytics/yolov3:v179 sudo docker kill $(sudo docker ps -a -q --filter ancestor=$t) for i in 0 do - sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i + # sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i + sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v /mnt/disks/nvme0n1/coco:/usr/src/coco $t bash utils/evolve.sh $i sleep 10 done @@ -228,3 +230,6 @@ t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it - t=ultralytics/yolov3:v143 && sudo docker build -t $t . && sudo docker push $t t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 detect.py +t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host $t python3 detect.py + + From c0095c2bc98b91f203830709f4e0f0c24f95a04e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Jan 2020 21:00:38 -0800 Subject: [PATCH 0259/1185] updates --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 248795ddfe..fb92e71954 100755 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ The https://github.com/ultralytics/yolov3 repo contains inference and training c Python 3.7 or later with the following `pip3 install -U -r requirements.txt` packages: - `numpy` -- `torch >= 1.1.0` +- `torch >= 1.3` - `opencv-python` - `tqdm` From eca1a25dcdb09711bcbf05b04dad9d2f780d922d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 3 Jan 2020 09:19:18 -0800 Subject: [PATCH 0260/1185] updates --- train.py | 2 +- utils/utils.py | 70 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/train.py b/train.py index c6ad904823..eda88c2377 100644 --- a/train.py +++ b/train.py @@ -446,7 +446,7 @@ def prebias(): mixed_precision = False # scale hyp['obj'] by img_size (evolved at 320) - hyp['obj'] *= opt.img_size / 320. + # hyp['obj'] *= opt.img_size / 320. tb_writer = None if not opt.evolve: # Train normally diff --git a/utils/utils.py b/utils/utils.py index 190dfdcf64..0ece2b3c26 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -367,7 +367,7 @@ def compute_loss(p, targets, model): # predictions, targets, model tcls, tbox, indices, anchor_vec = build_targets(model, targets) h = model.hyp # hyperparameters arc = model.arc # # (default, uCE, uBCE) detection architectures - red = 'mean' # Loss reduction (sum or mean) + red = 'sum' # Loss reduction (sum or mean) # Define criteria BCEcls = nn.BCEWithLogitsLoss(pos_weight=ft([h['cls_pw']]), reduction=red) @@ -399,7 +399,7 @@ def compute_loss(p, targets, model): # predictions, targets, model pbox = torch.cat((pxy, pwh), 1) # predicted box giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss - tobj[b, a, gj, gi] = 1.0 # giou.detach().type(tobj.dtype) + tobj[b, a, gj, gi] = giou.detach().type(tobj.dtype) if 'default' in arc and model.nc > 1: # cls loss (only if multiple classes) t = torch.zeros_like(ps[:, 5:]) # targets @@ -739,11 +739,28 @@ def coco_single_class_labels(path='../coco/labels/train2014/', label_class=43): shutil.copyfile(src=img_file, dst='new/images/' + Path(file).name.replace('txt', 'jpg')) # copy images -def kmean_anchors(path='data/coco64.txt', n=9, img_size=(320, 640)): - # from utils.utils import *; _ = kmean_anchors(n=9) +def kmean_anchors(path='../coco/train2017.txt', n=9, img_size=(320, 640)): + # from utils.utils import *; _ = kmean_anchors() # Produces a list of target kmeans suitable for use in *.cfg files from utils.datasets import LoadImagesAndLabels - from scipy.cluster.vq import kmeans + thr = 0.20 # IoU threshold + + def print_results(thr, wh, k): + k = k[np.argsort(k.prod(1))] # sort small to large + iou = wh_iou(torch.Tensor(wh), torch.Tensor(k)) + max_iou, min_iou = iou.max(1)[0], iou.min(1)[0] + bpr, aat = (max_iou > thr).float().mean(), (iou > thr).float().mean() * n # best possible recall, anch > thr + print('%.2f iou_thr: %.3f best possible recall, %.2f anchors > thr' % (thr, bpr, aat)) + print('kmeans anchors (n=%g, img_size=%s, IoU=%.3f/%.3f/%.3f-min/mean/best): ' % + (n, img_size, min_iou.mean(), iou.mean(), max_iou.mean()), end='') + for i, x in enumerate(k): + print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg + return k + + def fitness(thr, wh, k): # mutation fitness + iou = wh_iou(wh, torch.Tensor(k)).max(1)[0] # max iou + bpr = (iou > thr).float().mean() # best possible recall + return iou.mean() * 0.80 + bpr * 0.20 # weighted combination # Get label wh wh = [] @@ -754,11 +771,18 @@ def kmean_anchors(path='data/coco64.txt', n=9, img_size=(320, 640)): wh = np.concatenate(wh, 0).repeat(nr, axis=0) # augment 10x wh *= np.random.uniform(img_size[0], img_size[1], size=(wh.shape[0], 1)) # normalized to pixels (multi-scale) - # Kmeans calculation - print('Running kmeans on %g points...' % len(wh)) - s = wh.std(0) # sigmas for whitening - k, dist = kmeans(wh / s, n, iter=30) # points, mean distance - k = k[np.argsort(k.prod(1))] * s # sort small to large + # Darknet yolov3.cfg anchors + if n == 9: + k = np.array([[10, 13], [16, 30], [33, 23], [30, 61], [62, 45], [59, 119], [116, 90], [156, 198], [373, 326]]) + k = print_results(thr, wh, k) + else: + # Kmeans calculation + from scipy.cluster.vq import kmeans + print('Running kmeans on %g points...' % len(wh)) + s = wh.std(0) # sigmas for whitening + k, dist = kmeans(wh / s, n, iter=20) # points, mean distance + k *= s + k = print_results(thr, wh, k) # # Plot # k, d = [None] * 20, [None] * 20 @@ -768,21 +792,17 @@ def kmean_anchors(path='data/coco64.txt', n=9, img_size=(320, 640)): # ax = ax.ravel() # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.') - # Measure IoUs - iou = wh_iou(torch.Tensor(wh), torch.Tensor(k)) - min_iou, max_iou = iou.min(1)[0], iou.max(1)[0] - for x in [0.10, 0.20, 0.30]: # iou thresholds - print('%.2f iou_thr: %.3f best possible recall, %.2f anchors > thr' % - (x, (max_iou > x).float().mean(), (iou > x).float().mean() * n)) # BPR (best possible recall) - - # Print - print('kmeans anchors (n=%g, img_size=%s, IoU=%.2f/%.2f/%.2f-min/mean/best): ' % - (n, img_size, min_iou.mean(), iou.mean(), max_iou.mean()), end='') - for i, x in enumerate(k): - print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg - - # Plot - # plt.hist(biou.numpy().ravel(), 100) + # Evolve + wh = torch.Tensor(wh) + f, ng = fitness(thr, wh, k), 1000 # fitness, generations + for _ in tqdm(range(ng), desc='Evolving anchors'): + kg = (k.copy() * (1 + np.random.random() * np.random.randn(*k.shape) * 0.20)).clip(min=2.0) + fg = fitness(thr, wh, kg) + if fg > f: + f, k = fg, kg.copy() + print(fg, list(k.round().reshape(-1))) + k = print_results(thr, wh, k) + return k From 4fe9c90514c22e815281ab2275c920dbe365f6cd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 3 Jan 2020 11:53:02 -0800 Subject: [PATCH 0261/1185] updates --- train.py | 2 +- utils/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index eda88c2377..c6ad904823 100644 --- a/train.py +++ b/train.py @@ -446,7 +446,7 @@ def prebias(): mixed_precision = False # scale hyp['obj'] by img_size (evolved at 320) - # hyp['obj'] *= opt.img_size / 320. + hyp['obj'] *= opt.img_size / 320. tb_writer = None if not opt.evolve: # Train normally diff --git a/utils/utils.py b/utils/utils.py index 0ece2b3c26..52638c0fb4 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -367,7 +367,7 @@ def compute_loss(p, targets, model): # predictions, targets, model tcls, tbox, indices, anchor_vec = build_targets(model, targets) h = model.hyp # hyperparameters arc = model.arc # # (default, uCE, uBCE) detection architectures - red = 'sum' # Loss reduction (sum or mean) + red = 'mean' # Loss reduction (sum or mean) # Define criteria BCEcls = nn.BCEWithLogitsLoss(pos_weight=ft([h['cls_pw']]), reduction=red) From 07c40a3f1407e30b82776ff6061276fa0db6732d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 3 Jan 2020 14:36:39 -0800 Subject: [PATCH 0262/1185] updates --- train.py | 2 +- utils/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index c6ad904823..eda88c2377 100644 --- a/train.py +++ b/train.py @@ -446,7 +446,7 @@ def prebias(): mixed_precision = False # scale hyp['obj'] by img_size (evolved at 320) - hyp['obj'] *= opt.img_size / 320. + # hyp['obj'] *= opt.img_size / 320. tb_writer = None if not opt.evolve: # Train normally diff --git a/utils/utils.py b/utils/utils.py index 52638c0fb4..0ece2b3c26 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -367,7 +367,7 @@ def compute_loss(p, targets, model): # predictions, targets, model tcls, tbox, indices, anchor_vec = build_targets(model, targets) h = model.hyp # hyperparameters arc = model.arc # # (default, uCE, uBCE) detection architectures - red = 'mean' # Loss reduction (sum or mean) + red = 'sum' # Loss reduction (sum or mean) # Define criteria BCEcls = nn.BCEWithLogitsLoss(pos_weight=ft([h['cls_pw']]), reduction=red) From c948a4054c92b33d997ab03c4b8431e560b32a43 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 3 Jan 2020 15:41:01 -0800 Subject: [PATCH 0263/1185] updates --- utils/evolve.sh | 3 ++- utils/gcp.sh | 13 +++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/utils/evolve.sh b/utils/evolve.sh index a228398020..a41a74ad64 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -8,5 +8,6 @@ # t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 --epochs 1 --batch-size 64 --accumulate 1 --evolve --weights '' --pre --bucket yolov4/320_coco2014_27e --device 1 while true; do -python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch-size 64 --accumulate 1 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/320_coco2014_27e --device $1 + python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/640ms_coco2014_10e --device $1 --multi + # python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch-size 64 --accumulate 1 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/320_coco2014_27e --device $1 done diff --git a/utils/gcp.sh b/utils/gcp.sh index e5f3355db1..b98bc3d8ce 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -42,8 +42,8 @@ t=ultralytics/yolov3:v179 sudo docker kill $(sudo docker ps -a -q --filter ancestor=$t) for i in 0 do - # sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i - sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v /mnt/disks/nvme0n1/coco:/usr/src/coco $t bash utils/evolve.sh $i + sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i + # sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v /mnt/disks/nvme0n1/coco:/usr/src/coco $t bash utils/evolve.sh $i sleep 10 done @@ -229,7 +229,12 @@ t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it - t=ultralytics/yolov3:v143 && sudo docker build -t $t . && sudo docker push $t -t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 detect.py -t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host $t python3 detect.py +t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 179 +t=ultralytics/yolov3:v180 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 180 +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 181 --cfg yolov3s9a-640.cfg +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 182 --cfg yolov3s9a-320-640.cfg +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 183 --cfg yolov3s15a-640.cfg +t=ultralytics/yolov3:v185 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 185 +t=ultralytics/yolov3:v186 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 186 From efe3c319b56588e4d1948cdfbff877013559f621 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 3 Jan 2020 18:06:59 -0800 Subject: [PATCH 0264/1185] updates --- train.py | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/train.py b/train.py index eda88c2377..48d8c0414d 100644 --- a/train.py +++ b/train.py @@ -65,8 +65,8 @@ def train(): # Initialize init_seeds() if opt.multi_scale: - img_sz_min = round(img_size / 32 / 1.5) - img_sz_max = round(img_size / 32 * 1.5) + img_sz_min = 9 # round(img_size / 32 / 1.5) + img_sz_max = 21 # round(img_size / 32 * 1.5) img_size = img_sz_max * 32 # initiate with maximum multi_scale size print('Using multi-scale %g - %g' % (img_sz_min * 32, img_size)) @@ -136,23 +136,15 @@ def train(): # possible weights are '*.weights', 'yolov3-tiny.conv.15', 'darknet53.conv.74' etc. cutoff = load_darknet_weights(model, weights) - if opt.transfer or opt.prebias: # transfer learning edge (yolo) layers - nf = [int(model.module_defs[x - 1]['filters']) for x in model.yolo_layers] # yolo layer size (i.e. 255) + if opt.prebias: + # Update params (bias-only training allows more aggressive settings: i.e. SGD ~0.1 lr0, ~0.9 momentum) + for p in optimizer.param_groups: + p['lr'] = 0.1 # learning rate + if p.get('momentum') is not None: # for SGD but not Adam + p['momentum'] = 0.9 - if opt.prebias: - for p in optimizer.param_groups: - # lower param count allows more aggressive training settings: i.e. SGD ~0.1 lr0, ~0.9 momentum - p['lr'] = 0.1 # learning rate - if p.get('momentum') is not None: # for SGD but not Adam - p['momentum'] = 0.9 - - for p in model.parameters(): - if opt.prebias and p.numel() in nf: # train (yolo biases) - p.requires_grad = True - elif opt.transfer and p.shape[0] in nf: # train (yolo biases+weights) - p.requires_grad = True - else: # freeze layer - p.requires_grad = False + for name, p in model.named_parameters(): + p.requires_grad = True if name.endswith('.bias') else False # Scheduler https://github.com/ultralytics/yolov3/issues/238 # lf = lambda x: 1 - x / epochs # linear ramp to zero @@ -235,13 +227,6 @@ def train(): model.train() print(('\n' + '%10s' * 8) % ('Epoch', 'gpu_mem', 'GIoU', 'obj', 'cls', 'total', 'targets', 'img_size')) - # Freeze backbone at epoch 0, unfreeze at epoch 1 (optional) - freeze_backbone = False - if freeze_backbone and epoch < 2: - for name, p in model.named_parameters(): - if int(name.split('.')[1]) < cutoff: # if layer < 75 - p.requires_grad = False if epoch == 0 else True - # Update image weights (optional) if dataset.image_weights: w = model.class_weights.cpu().numpy() * (1 - maps) ** 2 # class weights @@ -406,7 +391,7 @@ def prebias(): # opt_0 = opt # save settings # opt.rect = False # update settings (if any) - train() # transfer-learn yolo biases for 1 epoch + train() # train model biases create_backbone(last) # saved results as backbone.pt # opt = opt_0 # reset settings @@ -425,7 +410,6 @@ def prebias(): parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') parser.add_argument('--rect', action='store_true', help='rectangular training') parser.add_argument('--resume', action='store_true', help='resume training from last.pt') - parser.add_argument('--transfer', action='store_true', help='transfer learning') parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') parser.add_argument('--notest', action='store_true', help='only test final epoch') parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters') @@ -433,7 +417,7 @@ def prebias(): parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') parser.add_argument('--weights', type=str, default='weights/ultralytics68.pt', help='initial weights') parser.add_argument('--arc', type=str, default='default', help='yolo architecture') # defaultpw, uCE, uBCE - parser.add_argument('--prebias', action='store_true', help='transfer-learn yolo biases prior to training') + parser.add_argument('--prebias', action='store_true', help='pretrain model biases') parser.add_argument('--name', default='', help='renames results.txt to results_name.txt if supplied') parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1 or cpu)') parser.add_argument('--adam', action='store_true', help='use adam optimizer') From d197c0be75452e62e8ec9b343616b83d65ea1bc5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 4 Jan 2020 11:36:36 -0800 Subject: [PATCH 0265/1185] updates --- utils/gcp.sh | 11 +++++++---- utils/utils.py | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index b98bc3d8ce..01770fb3fd 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -3,10 +3,10 @@ # New VM rm -rf sample_data yolov3 git clone https://github.com/ultralytics/yolov3 -git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex +#git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex sudo conda install -yc conda-forge scikit-image pycocotools -python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('193Zp_ye-3qXMonR1nZj3YyxMtQkMy50k','coco2014.zip')" -# python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco2017.zip')" +# python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('193Zp_ye-3qXMonR1nZj3YyxMtQkMy50k','coco2014.zip')" +python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco2017.zip')" sudo shutdown # Re-clone @@ -38,7 +38,7 @@ python3 detect.py python3 test.py --save-json # Evolve -t=ultralytics/yolov3:v179 +t=ultralytics/yolov3:v189 sudo docker kill $(sudo docker ps -a -q --filter ancestor=$t) for i in 0 do @@ -234,7 +234,10 @@ t=ultralytics/yolov3:v180 && sudo docker pull $t && sudo nvidia-docker run -it - t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 181 --cfg yolov3s9a-640.cfg t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 182 --cfg yolov3s9a-320-640.cfg t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 183 --cfg yolov3s15a-640.cfg +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 184 --cfg yolov3s15a-320-640.cfg t=ultralytics/yolov3:v185 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 185 t=ultralytics/yolov3:v186 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 186 +n=187 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n + diff --git a/utils/utils.py b/utils/utils.py index 0ece2b3c26..cf5157c5d7 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -778,7 +778,7 @@ def fitness(thr, wh, k): # mutation fitness else: # Kmeans calculation from scipy.cluster.vq import kmeans - print('Running kmeans on %g points...' % len(wh)) + print('Running kmeans for %g anchors on %g points...' % (n, len(wh))) s = wh.std(0) # sigmas for whitening k, dist = kmeans(wh / s, n, iter=20) # points, mean distance k *= s @@ -800,7 +800,7 @@ def fitness(thr, wh, k): # mutation fitness fg = fitness(thr, wh, kg) if fg > f: f, k = fg, kg.copy() - print(fg, list(k.round().reshape(-1))) + print_results(thr, wh, k) k = print_results(thr, wh, k) return k From 8ef441616d9aea55b52d8dc26fa0b80eaffee283 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 4 Jan 2020 12:26:02 -0800 Subject: [PATCH 0266/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index cf5157c5d7..b724ccbd72 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -810,7 +810,7 @@ def print_mutation(hyp, results, bucket=''): # Print mutation results to evolve.txt (for use with train.py --evolve) a = '%10s' * len(hyp) % tuple(hyp.keys()) # hyperparam keys b = '%10.3g' * len(hyp) % tuple(hyp.values()) # hyperparam values - c = '%10.3g' * len(results) % results # results (P, R, mAP, F1, test_loss) + c = '%10.4g' * len(results) % results # results (P, R, mAP, F1, test_loss) print('\n%s\n%s\nEvolved fitness: %s\n' % (a, b, c)) if bucket: From 1aedf27886b6d10541280afab7792cca5f93f9b8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 5 Jan 2020 06:11:00 -0800 Subject: [PATCH 0267/1185] updates --- utils/datasets.py | 4 ++-- utils/gcp.sh | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index b88b769c58..2cf8c8ba57 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -689,7 +689,7 @@ def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, area = w * h area0 = (targets[:, 3] - targets[:, 1]) * (targets[:, 4] - targets[:, 2]) ar = np.maximum(w / (h + 1e-16), h / (w + 1e-16)) # aspect ratio - i = (w > 4) & (h > 4) & (area / (area0 + 1e-16) > 0.1) & (ar < 10) + i = (w > 4) & (h > 4) & (area / (area0 + 1e-16) > 0.2) & (ar < 10) targets = targets[i] targets[:, 1:5] = xy[i] @@ -703,7 +703,7 @@ def cutout(image, labels): # https://towardsdatascience.com/when-conventional-wisdom-fails-revisiting-data-augmentation-for-self-driving-cars-4831998c5509 h, w = image.shape[:2] - def bbox_ioa(box1, box2, x1y1x2y2=True): + def bbox_ioa(box1, box2): # Returns the intersection over box2 area given box1, box2. box1 is 4, box2 is nx4. boxes are x1y1x2y2 box2 = box2.transpose() diff --git a/utils/gcp.sh b/utils/gcp.sh index 01770fb3fd..7bb5214971 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -239,5 +239,18 @@ t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it - t=ultralytics/yolov3:v185 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 185 t=ultralytics/yolov3:v186 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 186 n=187 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n - +t=ultralytics/yolov3:v189 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 188 --cfg yolov3s15a-320-640.cfg +n=190 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=191 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=192 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n + +n=193 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=194 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=195 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=196 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n + +n=197 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=198 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=199 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=200 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n From 04a0a6f6094dfae88cf04a4b2c5e0819e8665acc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 5 Jan 2020 12:50:58 -0800 Subject: [PATCH 0268/1185] updates --- train.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 48d8c0414d..8baf79daf7 100644 --- a/train.py +++ b/train.py @@ -367,8 +367,10 @@ def train(): # end epoch ---------------------------------------------------------------------------------------------------- # end training - if len(opt.name) and not opt.prebias: - fresults, flast, fbest = 'results%s.txt' % opt.name, 'last%s.pt' % opt.name, 'best%s.pt' % opt.name + n = opt.name + if len(n) and not opt.prebias: + n = '_' + n if not n.isnumeric() else n + fresults, flast, fbest = 'results%s.txt' % n, 'last%s.pt' % n, 'best%s.pt' % n os.rename('results.txt', fresults) os.rename(wdir + 'last.pt', wdir + flast) if os.path.exists(wdir + 'last.pt') else None os.rename(wdir + 'best.pt', wdir + fbest) if os.path.exists(wdir + 'best.pt') else None From 3b1caf9a431d5509880a777d5dd00e3ac2797d52 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 6 Jan 2020 11:57:12 -0800 Subject: [PATCH 0269/1185] updates --- train.py | 2 +- utils/gcp.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 8baf79daf7..ceabfeb33b 100644 --- a/train.py +++ b/train.py @@ -403,7 +403,7 @@ def prebias(): if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('--epochs', type=int, default=273) # 500200 batches at bs 16, 117263 images = 273 epochs + parser.add_argument('--epochs', type=int, default=273) # 500200 batches at bs 16, 117263 COCO images = 273 epochs parser.add_argument('--batch-size', type=int, default=16) # effective bs = batch_size * accumulate = 16 * 4 = 64 parser.add_argument('--accumulate', type=int, default=4, help='batches to accumulate before optimizing') parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') diff --git a/utils/gcp.sh b/utils/gcp.sh index 7bb5214971..2ac4e37fdd 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -38,7 +38,7 @@ python3 detect.py python3 test.py --save-json # Evolve -t=ultralytics/yolov3:v189 +t=ultralytics/yolov3:v176 sudo docker kill $(sudo docker ps -a -q --filter ancestor=$t) for i in 0 do @@ -249,7 +249,7 @@ n=194 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker r n=195 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n n=196 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=197 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=197 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n n=198 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n n=199 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n n=200 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n From 09ff72bc7b4f11a67f8680cdb21a2963a39dc34d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 6 Jan 2020 12:35:10 -0800 Subject: [PATCH 0270/1185] updates --- utils/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index b724ccbd72..5bc84fff01 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -436,9 +436,10 @@ def compute_loss(p, targets, model): # predictions, targets, model lcls *= h['cls'] if red == 'sum': bs = tobj.shape[0] # batch size - lbox *= 3 / ng lobj *= 3 / (6300 * bs) * 2 # 3 / np * 2 - lcls *= 3 / ng / model.nc + if ng: + lcls *= 3 / ng / model.nc + lbox *= 3 / ng loss = lbox + lobj + lcls return loss, torch.cat((lbox, lobj, lcls, loss)).detach() From af23270482fd807dcf06e329b29c3d722b71d2a9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 6 Jan 2020 13:57:20 -0800 Subject: [PATCH 0271/1185] updates --- utils/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 5bc84fff01..2171d15b60 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -773,7 +773,8 @@ def fitness(thr, wh, k): # mutation fitness wh *= np.random.uniform(img_size[0], img_size[1], size=(wh.shape[0], 1)) # normalized to pixels (multi-scale) # Darknet yolov3.cfg anchors - if n == 9: + use_darknet = False + if use_darknet: k = np.array([[10, 13], [16, 30], [33, 23], [30, 61], [62, 45], [59, 119], [116, 90], [156, 198], [373, 326]]) k = print_results(thr, wh, k) else: From fd0769c4766626213c308e826b1156c5197cf133 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 6 Jan 2020 13:59:08 -0800 Subject: [PATCH 0272/1185] updates --- utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 2171d15b60..0a99f86129 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -782,7 +782,7 @@ def fitness(thr, wh, k): # mutation fitness from scipy.cluster.vq import kmeans print('Running kmeans for %g anchors on %g points...' % (n, len(wh))) s = wh.std(0) # sigmas for whitening - k, dist = kmeans(wh / s, n, iter=20) # points, mean distance + k, dist = kmeans(wh / s, n, iter=30) # points, mean distance k *= s k = print_results(thr, wh, k) @@ -798,7 +798,7 @@ def fitness(thr, wh, k): # mutation fitness wh = torch.Tensor(wh) f, ng = fitness(thr, wh, k), 1000 # fitness, generations for _ in tqdm(range(ng), desc='Evolving anchors'): - kg = (k.copy() * (1 + np.random.random() * np.random.randn(*k.shape) * 0.20)).clip(min=2.0) + kg = (k.copy() * (1 + np.random.random() * np.random.randn(*k.shape) * 0.30)).clip(min=2.0) fg = fitness(thr, wh, kg) if fg > f: f, k = fg, kg.copy() From 3b5ca2ea90e082c5882ae666c2b2a077bf5c5715 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 6 Jan 2020 14:16:23 -0800 Subject: [PATCH 0273/1185] updates --- utils/utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 0a99f86129..059fba844d 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -776,7 +776,6 @@ def fitness(thr, wh, k): # mutation fitness use_darknet = False if use_darknet: k = np.array([[10, 13], [16, 30], [33, 23], [30, 61], [62, 45], [59, 119], [116, 90], [156, 198], [373, 326]]) - k = print_results(thr, wh, k) else: # Kmeans calculation from scipy.cluster.vq import kmeans @@ -784,7 +783,7 @@ def fitness(thr, wh, k): # mutation fitness s = wh.std(0) # sigmas for whitening k, dist = kmeans(wh / s, n, iter=30) # points, mean distance k *= s - k = print_results(thr, wh, k) + k = print_results(thr, wh, k) # # Plot # k, d = [None] * 20, [None] * 20 From bf42c31d9ee10090a61ebfa2192098d6d6383695 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 6 Jan 2020 14:25:11 -0800 Subject: [PATCH 0274/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 059fba844d..60efd25a37 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -761,7 +761,7 @@ def print_results(thr, wh, k): def fitness(thr, wh, k): # mutation fitness iou = wh_iou(wh, torch.Tensor(k)).max(1)[0] # max iou bpr = (iou > thr).float().mean() # best possible recall - return iou.mean() * 0.80 + bpr * 0.20 # weighted combination + return iou.mean() * bpr # product # Get label wh wh = [] From 11ce877bdff2a355cc25a0c96fd5c23eb47a644b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 8 Jan 2020 09:42:01 -0800 Subject: [PATCH 0275/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 60efd25a37..83ccd6019c 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -540,7 +540,7 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru # Filter by class if classes: - pred = pred[(j.view(-1, 1) == torch.Tensor(classes)).any(1)] + pred = pred[(j.view(-1, 1) == torch.tensor(classes, device=j.device)).any(1)] # Apply finite constraint if not torch.isfinite(pred).all(): From 3e5b007e3ab6e317b8ac9c89eac7a30c2a93d539 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 8 Jan 2020 16:36:35 -0800 Subject: [PATCH 0276/1185] updates --- test.py | 4 ++-- utils/utils.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test.py b/test.py index c5e166bb6c..894ad1858d 100644 --- a/test.py +++ b/test.py @@ -158,8 +158,8 @@ def test(cfg, stats = [np.concatenate(x, 0) for x in list(zip(*stats))] # to numpy if len(stats): p, r, ap, f1, ap_class = ap_per_class(*stats) - # if niou > 1: - # p, r, ap, f1 = p[:, 0], r[:, 0], ap[:, 0], ap.mean(1) # average across ious + if niou > 1: + p, r, ap, f1 = p[:, 0], r[:, 0], ap.mean(1), ap[:, 0] # [P, R, AP@0.5:0.95, AP@0.5] mp, mr, map, mf1 = p.mean(), r.mean(), ap.mean(), f1.mean() nt = np.bincount(stats[3].astype(np.int64), minlength=nc) # number of targets per class else: diff --git a/utils/utils.py b/utils/utils.py index 83ccd6019c..502688b4c0 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -863,7 +863,8 @@ def apply_classifier(x, model, img, im0): def fitness(x): # Returns fitness (for use with results.txt or evolve.txt) - return x[:, 2] * 0.3 + x[:, 3] * 0.7 # weighted combination of x=[p, r, mAP@0.5, F1 or mAP@0.5:0.95] + w = [0.1, 0.1, 0.6, 0.2] # weights for [P, R, mAP, F1]@0.5 or [P, R, mAP@0.5:0.95, mAP@0.5] + return (x[:, :4] * np.array([w])).sum(1) # Plotting functions --------------------------------------------------------------------------------------------------- From fd8cd377c30bdd9651fbb3e28627fdc65e20a0c1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 8 Jan 2020 16:39:59 -0800 Subject: [PATCH 0277/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 502688b4c0..c93cecdfbd 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -864,7 +864,7 @@ def apply_classifier(x, model, img, im0): def fitness(x): # Returns fitness (for use with results.txt or evolve.txt) w = [0.1, 0.1, 0.6, 0.2] # weights for [P, R, mAP, F1]@0.5 or [P, R, mAP@0.5:0.95, mAP@0.5] - return (x[:, :4] * np.array([w])).sum(1) + return (x[:, :4] * w).sum(1) # Plotting functions --------------------------------------------------------------------------------------------------- From c1527e4ab137e0882d3ce605432541c81d2e14a4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 8 Jan 2020 18:48:41 -0800 Subject: [PATCH 0278/1185] updates --- test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index 894ad1858d..4be1121dfc 100644 --- a/test.py +++ b/test.py @@ -99,7 +99,7 @@ def test(cfg, if pred is None: if nl: - stats.append((torch.zeros(0, 1), torch.Tensor(), torch.Tensor(), tcls)) + stats.append((torch.zeros(0, niou, dtype=torch.bool), torch.Tensor(), torch.Tensor(), tcls)) continue # Append to text file @@ -147,7 +147,7 @@ def test(cfg, d = ti[i[j]] # detected target if d not in detected: detected.append(d) - correct[pi[j]] = ious[j] > iouv # iou_thres is 1xn + correct[pi[j]] = (ious[j] > iouv).cpu() # iou_thres is 1xn if len(detected) == nl: # all targets already located in image break From 0afcd9db8a81496cdb7fc040dc617f95f7eafbea Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 9 Jan 2020 09:56:16 -0800 Subject: [PATCH 0279/1185] updates --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fb92e71954..ab3f80490a 100755 --- a/README.md +++ b/README.md @@ -26,12 +26,11 @@ The https://github.com/ultralytics/yolov3 repo contains inference and training c # Requirements -Python 3.7 or later with the following `pip3 install -U -r requirements.txt` packages: +Python 3.7 or later with the following `pip3 install -U -r requirements.txt` packages, including: -- `numpy` - `torch >= 1.3` - `opencv-python` -- `tqdm` +- `Pillow` # Tutorials From 5e5f3467d449f1c0bb260d610b185673af005377 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 9 Jan 2020 09:57:07 -0800 Subject: [PATCH 0280/1185] updates --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ab3f80490a..0d9c7edda8 100755 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ The https://github.com/ultralytics/yolov3 repo contains inference and training c # Requirements -Python 3.7 or later with the following `pip3 install -U -r requirements.txt` packages, including: +Python 3.7 or later with all of the `pip install -U -r requirements.txt` packages including: - `torch >= 1.3` - `opencv-python` From 6b2153d334b38105b26de911d82527d0bf6a0cf8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 9 Jan 2020 09:59:53 -0800 Subject: [PATCH 0281/1185] updates --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d9c7edda8..9e8d8ad6c3 100755 --- a/README.md +++ b/README.md @@ -27,11 +27,14 @@ The https://github.com/ultralytics/yolov3 repo contains inference and training c # Requirements Python 3.7 or later with all of the `pip install -U -r requirements.txt` packages including: - - `torch >= 1.3` - `opencv-python` - `Pillow` +All dependencies are included in the associated docker images. Docker requirements are: +- `nvidia-docker` +- Nvidia Driver Version >= 440.44 + # Tutorials * [GCP Quickstart](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) From bb9c6e7a8f10d08cd6dd645bce9413169649be1f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 9 Jan 2020 10:10:20 -0800 Subject: [PATCH 0282/1185] updates --- utils/evolve.sh | 7 +-- utils/gcp.sh | 113 ++++++++++++++++++++++++++---------------------- 2 files changed, 66 insertions(+), 54 deletions(-) diff --git a/utils/evolve.sh b/utils/evolve.sh index a41a74ad64..003312f5d1 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -5,9 +5,10 @@ # sleep 30 # done # -# t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 --epochs 1 --batch-size 64 --accumulate 1 --evolve --weights '' --pre --bucket yolov4/320_coco2014_27e --device 1 +#t=ultralytics/yolov3:v199 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 672 --epochs 10 --batch 16 --accum 4 --weights '' --arc defaultpw --device 0 --multi while true; do - python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/640ms_coco2014_10e --device $1 --multi - # python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch-size 64 --accumulate 1 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/320_coco2014_27e --device $1 + python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --evolve --device $1 --cfg yolov3-tiny-3cls.cfg + # python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/640ms_coco2014_10e --device $1 --multi + # python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch 64 --accum 1 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/320_coco2014_27e --device $1 done diff --git a/utils/gcp.sh b/utils/gcp.sh index 2ac4e37fdd..f5975f6d55 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -38,13 +38,14 @@ python3 detect.py python3 test.py --save-json # Evolve -t=ultralytics/yolov3:v176 +t=ultralytics/yolov3:v206 sudo docker kill $(sudo docker ps -a -q --filter ancestor=$t) -for i in 0 +for i in 0 1 2 3 4 5 6 7 do - sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i - # sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v /mnt/disks/nvme0n1/coco:/usr/src/coco $t bash utils/evolve.sh $i - sleep 10 + sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i + # sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i + # sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v /mnt/disks/nvme0n1/coco:/usr/src/coco $t bash utils/evolve.sh $i + sleep 1 done @@ -106,30 +107,30 @@ sudo docker pull ultralytics/yolov3:v0 sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco ultralytics/yolov3:v0 -t=ultralytics/yolov3:v70 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 70 --device 0 --multi -t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 71 --device 0 --multi --img-weights +t=ultralytics/yolov3:v70 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 70 --device 0 --multi +t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 71 --device 0 --multi --img-weights -t=ultralytics/yolov3:v73 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 73 --device 5 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v74 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 74 --device 0 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v75 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 75 --device 7 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v76 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 76 --device 0 --cfg cfg/yolov3-spp.cfg +t=ultralytics/yolov3:v73 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 73 --device 5 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v74 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 74 --device 0 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v75 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 75 --device 7 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v76 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 76 --device 0 --cfg cfg/yolov3-spp.cfg -t=ultralytics/yolov3:v79 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 79 --device 5 -t=ultralytics/yolov3:v80 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 80 --device 0 -t=ultralytics/yolov3:v81 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 81 --device 7 -t=ultralytics/yolov3:v82 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 82 --device 0 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v79 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 79 --device 5 +t=ultralytics/yolov3:v80 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 80 --device 0 +t=ultralytics/yolov3:v81 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 81 --device 7 +t=ultralytics/yolov3:v82 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 82 --device 0 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 83 --device 6 --multi --nosave -t=ultralytics/yolov3:v84 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 84 --device 0 --multi -t=ultralytics/yolov3:v85 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 85 --device 0 --multi -t=ultralytics/yolov3:v86 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 86 --device 1 --multi -t=ultralytics/yolov3:v87 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 87 --device 2 --multi -t=ultralytics/yolov3:v88 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 88 --device 3 --multi -t=ultralytics/yolov3:v89 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 89 --device 1 -t=ultralytics/yolov3:v90 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 90 --device 0 --cfg cfg/yolov3-spp-matrix.cfg -t=ultralytics/yolov3:v91 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 91 --device 0 --cfg cfg/yolov3-spp-matrix.cfg +t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 83 --device 6 --multi --nosave +t=ultralytics/yolov3:v84 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 84 --device 0 --multi +t=ultralytics/yolov3:v85 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 85 --device 0 --multi +t=ultralytics/yolov3:v86 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 86 --device 1 --multi +t=ultralytics/yolov3:v87 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 87 --device 2 --multi +t=ultralytics/yolov3:v88 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 88 --device 3 --multi +t=ultralytics/yolov3:v89 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 89 --device 1 +t=ultralytics/yolov3:v90 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 90 --device 0 --cfg cfg/yolov3-spp-matrix.cfg +t=ultralytics/yolov3:v91 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 91 --device 0 --cfg cfg/yolov3-spp-matrix.cfg -t=ultralytics/yolov3:v92 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 92 --device 0 +t=ultralytics/yolov3:v92 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 92 --device 0 t=ultralytics/yolov3:v93 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 93 --device 0 --cfg cfg/yolov3-spp-matrix.cfg @@ -147,8 +148,8 @@ t=ultralytics/yolov3:v106 && sudo docker pull $t && sudo nvidia-docker run -it - t=ultralytics/yolov3:v107 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 107 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg t=ultralytics/yolov3:v108 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 108 --device 7 --nosave -t=ultralytics/yolov3:v109 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 109 --device 4 --multi --nosave -t=ultralytics/yolov3:v110 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accumulate 4 --pre --bucket yolov4 --name 110 --device 3 --multi --nosave +t=ultralytics/yolov3:v109 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 109 --device 4 --multi --nosave +t=ultralytics/yolov3:v110 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 110 --device 3 --multi --nosave t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 111 --device 0 t=ultralytics/yolov3:v112 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 112 --device 1 --nosave @@ -229,28 +230,38 @@ t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it - t=ultralytics/yolov3:v143 && sudo docker build -t $t . && sudo docker push $t -t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 179 -t=ultralytics/yolov3:v180 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 180 -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 181 --cfg yolov3s9a-640.cfg -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 182 --cfg yolov3s9a-320-640.cfg -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 183 --cfg yolov3s15a-640.cfg -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 184 --cfg yolov3s15a-320-640.cfg - -t=ultralytics/yolov3:v185 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 185 -t=ultralytics/yolov3:v186 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 186 -n=187 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -t=ultralytics/yolov3:v189 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 188 --cfg yolov3s15a-320-640.cfg -n=190 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=191 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=192 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n - -n=193 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=194 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=195 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=196 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n - -n=197 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=198 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=199 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=200 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch-size 22 --accumulate 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 179 +t=ultralytics/yolov3:v180 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 180 +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 181 --cfg yolov3s9a-640.cfg +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 182 --cfg yolov3s9a-320-640.cfg +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 183 --cfg yolov3s15a-640.cfg +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 184 --cfg yolov3s15a-320-640.cfg + +t=ultralytics/yolov3:v185 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 185 +t=ultralytics/yolov3:v186 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 186 +n=187 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +t=ultralytics/yolov3:v189 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 188 --cfg yolov3s15a-320-640.cfg +n=190 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=191 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=192 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n + +n=193 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=194 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=195 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=196 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n + +n=197 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=198 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n + +# knife +n=199 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 0 +n=200 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 6 +n=207 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 7 + +# sm4 +n=201 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 0 --cfg yolov3-tiny-3cls.cfg +n=202 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 1 --cfg yolov3-tiny-3cls-sm4.cfg +n=203 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 2 --cfg yolov3-tiny-3cls-sm4.cfg +n=204 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 3 --cfg yolov3-tiny-3cls-sm4.cfg +n=205 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 4 --cfg yolov3-tiny-3cls-sm4.cfg From 759d27501760271d6ba1774ed277bb3fc93548fc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 9 Jan 2020 14:07:55 -0800 Subject: [PATCH 0283/1185] updates --- utils/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index c93cecdfbd..70e406678c 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -840,13 +840,13 @@ def apply_classifier(x, model, img, im0): d[:, :4] = xywh2xyxy(b).long() # Rescale boxes from img_size to im0 size - scale_coords(img.shape[2:], d[:, :4], im0.shape) + scale_coords(img.shape[2:], d[:, :4], im0[i].shape) # Classes - pred_cls1 = d[:, 6].long() + pred_cls1 = d[:, 5].long() ims = [] for j, a in enumerate(d): # per item - cutout = im0[int(a[1]):int(a[3]), int(a[0]):int(a[2])] + cutout = im0[i][int(a[1]):int(a[3]), int(a[0]):int(a[2])] im = cv2.resize(cutout, (224, 224)) # BGR # cv2.imwrite('test%i.jpg' % j, cutout) From 0219eb094e1f5f0477ce23d7ccbac6467df51539 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 9 Jan 2020 21:05:26 -0800 Subject: [PATCH 0284/1185] updates --- utils/datasets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 2cf8c8ba57..430d34e693 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -283,7 +283,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r # Rectangular Training https://github.com/ultralytics/yolov3/issues/232 if self.rect: - # Read image shapes + # Read image shapes (wh) sp = path.replace('.txt', '.shapes') # shapefile path try: with open(sp, 'r') as f: # read existing shapefile @@ -299,7 +299,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r i = ar.argsort() self.img_files = [self.img_files[i] for i in i] self.label_files = [self.label_files[i] for i in i] - self.shapes = s[i] + self.shapes = s[i] # wh ar = ar[i] # Set training image shapes From 793f6389dc003153c2171f88a45b71e3b9cd21d9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Jan 2020 09:30:05 -0800 Subject: [PATCH 0285/1185] updates --- detect.py | 3 ++- utils/utils.py | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/detect.py b/detect.py index b9ddbf0f5e..09bb731195 100644 --- a/detect.py +++ b/detect.py @@ -86,7 +86,7 @@ def detect(save_img=False): pred = pred.float() # Apply NMS - pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, classes=opt.classes) + pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, classes=opt.classes, agnostic=opt.agnostic_nms) # Apply Classifier if classify: @@ -169,6 +169,7 @@ def detect(save_img=False): parser.add_argument('--view-img', action='store_true', help='display results') parser.add_argument('--save-txt', action='store_true', help='display results') parser.add_argument('--classes', nargs='+', type=int, help='filter by class') + parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') opt = parser.parse_args() print(opt) diff --git a/utils/utils.py b/utils/utils.py index 70e406678c..91dc62a9b8 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -499,7 +499,7 @@ def build_targets(model, targets): return tcls, tbox, indices, av -def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=True, method='vision_batch', classes=None): +def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=True, classes=None, agnostic=False): """ Removes detections with lower object confidence score than 'conf_thres' Non-Maximum Suppression to further filter detections. @@ -511,6 +511,7 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru # Box constraints min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height + method = 'vision_batch' output = [None] * len(prediction) for image_i, pred in enumerate(prediction): # Apply conf constraint @@ -548,7 +549,8 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru # Batched NMS if method == 'vision_batch': - output[image_i] = pred[torchvision.ops.boxes.batched_nms(pred[:, :4], pred[:, 4], pred[:, 5], iou_thres)] + c = j * 0 if agnostic else j # class-agnostic NMS + output[image_i] = pred[torchvision.ops.boxes.batched_nms(pred[:, :4], pred[:, 4], c, iou_thres)] continue # Sort by confidence From 6235d76976193264a6d2d9a7469f83078cbabed0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Jan 2020 10:12:40 -0800 Subject: [PATCH 0286/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 91dc62a9b8..4a7e969a68 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -549,7 +549,7 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru # Batched NMS if method == 'vision_batch': - c = j * 0 if agnostic else j # class-agnostic NMS + c = pred[:, 5] * 0 if agnostic else pred[:, 5] # class-agnostic NMS output[image_i] = pred[torchvision.ops.boxes.batched_nms(pred[:, :4], pred[:, 4], c, iou_thres)] continue From 6e52f985fe4c689b46b71c36c4703d806c1a1a38 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Jan 2020 11:45:51 -0800 Subject: [PATCH 0287/1185] updates --- utils/datasets.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 430d34e693..d0ee76601e 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -379,12 +379,13 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r nf, nm, ne, nd, n) assert nf > 0, 'No labels found. See %s' % help_url - # Cache images into memory for faster training (WARNING: Large datasets may exceed system RAM) + # Cache images into memory for faster training (WARNING: large datasets may exceed system RAM) if cache_images: # if training gb = 0 # Gigabytes of cached images pbar = tqdm(range(len(self.img_files)), desc='Caching images') + self.img_hw0, self.img_hw = [None] * n, [None] * n for i in pbar: # max 10k images - self.imgs[i] = load_image(self, i) + self.imgs[i], self.img_hw0[i], self.img_hw[i] = load_image(self, i) # img, hw_original, hw_resized gb += self.imgs[i].nbytes pbar.desc = 'Caching images (%.1fGB)' % (gb / 1E9) @@ -419,15 +420,13 @@ def __getitem__(self, index): if mosaic: # Load mosaic img, labels = load_mosaic(self, index) - h, w = img.shape[:2] - ratio, pad = None, None + h0, w0, ratio, pad = None, None, None, None else: # Load image - img = load_image(self, index) + img, (h0, w0), (h, w) = load_image(self, index) # Letterbox - h, w = img.shape[:2] shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment) @@ -495,7 +494,7 @@ def __getitem__(self, index): img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 img = np.ascontiguousarray(img) - return torch.from_numpy(img), labels_out, img_path, ((h, w), (ratio, pad)) + return torch.from_numpy(img), labels_out, img_path, ((h0, w0), (ratio, pad)) @staticmethod def collate_fn(batch): @@ -506,17 +505,18 @@ def collate_fn(batch): def load_image(self, index): - # loads 1 image from dataset - img = self.imgs[index] - if img is None: + # loads 1 image from dataset, returns img, original hw, resized hw + if self.imgs[index] is None: # not cached img_path = self.img_files[index] img = cv2.imread(img_path) # BGR assert img is not None, 'Image Not Found ' + img_path - r = self.img_size / max(img.shape) # resize image to img_size + h0, w0 = img.shape[:2] # orig hw + r = self.img_size / max(h0, w0) # resize image to img_size if self.augment and (r != 1): # always resize down, only resize up if training with augmentation - h, w = img.shape[:2] - return cv2.resize(img, (int(w * r), int(h * r)), interpolation=cv2.INTER_LINEAR) # _LINEAR fastest - return img + h, w = int(h0 * r), int(w0 * r) + return cv2.resize(img, (w, h), interpolation=cv2.INTER_LINEAR), (h0, w0), (h, w) # _LINEAR fastest + else: # cached + return self.imgs[index], self.img_hw0[index], self.img_hw[index] # img, hw def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5): @@ -535,8 +535,7 @@ def load_mosaic(self, index): indices = [index] + [random.randint(0, len(self.labels) - 1) for _ in range(3)] # 3 additional image indices for i, index in enumerate(indices): # Load image - img = load_image(self, index) - h, w, _ = img.shape + img, _, (h, w) = load_image(self, index) # place img in img4 if i == 0: # top left From 3505b57421322cb1d38dd9774a92d7a0ec79c53c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Jan 2020 11:55:54 -0800 Subject: [PATCH 0288/1185] updates --- utils/datasets.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index d0ee76601e..f1dccc8ec1 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -506,17 +506,18 @@ def collate_fn(batch): def load_image(self, index): # loads 1 image from dataset, returns img, original hw, resized hw - if self.imgs[index] is None: # not cached + img = self.imgs[index] + if img is None: # not cached img_path = self.img_files[index] img = cv2.imread(img_path) # BGR assert img is not None, 'Image Not Found ' + img_path h0, w0 = img.shape[:2] # orig hw r = self.img_size / max(h0, w0) # resize image to img_size - if self.augment and (r != 1): # always resize down, only resize up if training with augmentation - h, w = int(h0 * r), int(w0 * r) - return cv2.resize(img, (w, h), interpolation=cv2.INTER_LINEAR), (h0, w0), (h, w) # _LINEAR fastest - else: # cached - return self.imgs[index], self.img_hw0[index], self.img_hw[index] # img, hw + if r < 1 or (self.augment and (r != 1)): # always resize down, only resize up if training with augmentation + img = cv2.resize(img, (int(w0 * r), int(h0 * r)), interpolation=cv2.INTER_LINEAR) # _LINEAR fastest + return img, (h0, w0), img.shape[:2] # img, hw_original, hw_resized + else: + return self.imgs[index], self.img_hw0[index], self.img_hw[index] # img, hw_original, hw_resized def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5): From c8a67adeccc277223f965ac8043ecfca27575e05 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Jan 2020 12:49:22 -0800 Subject: [PATCH 0289/1185] updates --- train.py | 4 ++-- utils/utils.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index ceabfeb33b..d387839f8f 100644 --- a/train.py +++ b/train.py @@ -470,7 +470,7 @@ def prebias(): # Mutate np.random.seed(int(time.time())) - s = np.random.random() * 0.15 # sigma + s = np.random.random() * 0.2 # sigma g = [1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 1, 1, 1, 1, 1, 1, 1, 1] # gains for i, k in enumerate(hyp.keys()): x = (np.random.randn() * s * g[i] + 1) ** 2.0 # plt.hist(x.ravel(), 300) @@ -478,7 +478,7 @@ def prebias(): # Clip to limits keys = ['lr0', 'iou_t', 'momentum', 'weight_decay', 'hsv_s', 'hsv_v', 'translate', 'scale', 'fl_gamma'] - limits = [(1e-5, 1e-2), (0.00, 0.70), (0.60, 0.98), (0, 0.001), (0, .9), (0, .9), (0, .9), (0, .9), (0, 3)] + limits = [(1e-5, 1e-2), (0.00, 0.70), (0.60, 0.99), (0, 0.001), (0, .9), (0, .9), (0, .9), (0, .9), (0, 3)] for k, v in zip(keys, limits): hyp[k] = np.clip(hyp[k], v[0], v[1]) diff --git a/utils/utils.py b/utils/utils.py index 4a7e969a68..301a852d91 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -865,7 +865,7 @@ def apply_classifier(x, model, img, im0): def fitness(x): # Returns fitness (for use with results.txt or evolve.txt) - w = [0.1, 0.1, 0.6, 0.2] # weights for [P, R, mAP, F1]@0.5 or [P, R, mAP@0.5:0.95, mAP@0.5] + w = [0.0, 0.0, 0.8, 0.2] # weights for [P, R, mAP, F1]@0.5 or [P, R, mAP@0.5:0.95, mAP@0.5] return (x[:, :4] * w).sum(1) From b7a25e60ce2681b6325fc18cf1291bc28535e9b1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Jan 2020 13:41:47 -0800 Subject: [PATCH 0290/1185] updates --- utils/datasets.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index f1dccc8ec1..4061af81ac 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -420,7 +420,7 @@ def __getitem__(self, index): if mosaic: # Load mosaic img, labels = load_mosaic(self, index) - h0, w0, ratio, pad = None, None, None, None + shapes = None else: # Load image @@ -429,6 +429,7 @@ def __getitem__(self, index): # Letterbox shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment) + shapes = (h0, w0), ((h / h0, w / w0), pad) # for COCO mAP rescaling # Load labels labels = [] @@ -494,7 +495,7 @@ def __getitem__(self, index): img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 img = np.ascontiguousarray(img) - return torch.from_numpy(img), labels_out, img_path, ((h0, w0), (ratio, pad)) + return torch.from_numpy(img), labels_out, img_path, shapes @staticmethod def collate_fn(batch): From ba265d91b2c174cefff09e76859afe92086397ad Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Jan 2020 16:09:36 -0800 Subject: [PATCH 0291/1185] updates --- train.py | 87 +++++++++++++++++++++---------------------------- utils/evolve.sh | 4 ++- utils/gcp.sh | 9 +++-- utils/utils.py | 4 +-- 4 files changed, 49 insertions(+), 55 deletions(-) diff --git a/train.py b/train.py index d387839f8f..a0a1cde25e 100644 --- a/train.py +++ b/train.py @@ -53,7 +53,7 @@ def train(): cfg = opt.cfg data = opt.data img_size = opt.img_size - epochs = 1 if opt.prebias else opt.epochs # 500200 batches at bs 64, 117263 images = 273 epochs + epochs = opt.epochs # 500200 batches at bs 64, 117263 images = 273 epochs batch_size = opt.batch_size accumulate = opt.accumulate # effective bs = batch_size * accumulate = 16 * 4 = 64 weights = opt.weights # initial training weights @@ -65,8 +65,8 @@ def train(): # Initialize init_seeds() if opt.multi_scale: - img_sz_min = 9 # round(img_size / 32 / 1.5) - img_sz_max = 21 # round(img_size / 32 * 1.5) + img_sz_min = round(img_size / 32 / 1.5) + img_sz_max = round(img_size / 32 * 1.5) img_size = img_sz_max * 32 # initiate with maximum multi_scale size print('Using multi-scale %g - %g' % (img_sz_min * 32, img_size)) @@ -136,16 +136,6 @@ def train(): # possible weights are '*.weights', 'yolov3-tiny.conv.15', 'darknet53.conv.74' etc. cutoff = load_darknet_weights(model, weights) - if opt.prebias: - # Update params (bias-only training allows more aggressive settings: i.e. SGD ~0.1 lr0, ~0.9 momentum) - for p in optimizer.param_groups: - p['lr'] = 0.1 # learning rate - if p.get('momentum') is not None: # for SGD but not Adam - p['momentum'] = 0.9 - - for name, p in model.named_parameters(): - p.requires_grad = True if name.endswith('.bias') else False - # Scheduler https://github.com/ultralytics/yolov3/issues/238 # lf = lambda x: 1 - x / epochs # linear ramp to zero # lf = lambda x: 10 ** (hyp['lrf'] * x / epochs) # exp ramp @@ -186,7 +176,7 @@ def train(): rect=opt.rect, # rectangular training image_weights=False, cache_labels=epochs > 10, - cache_images=opt.cache_images and not opt.prebias) + cache_images=opt.cache_images) # Dataloader batch_size = min(batch_size, len(dataset)) @@ -198,17 +188,16 @@ def train(): pin_memory=True, collate_fn=dataset.collate_fn) - # Test Dataloader - if not opt.prebias: - testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, opt.img_size, batch_size * 2, - hyp=hyp, - rect=True, - cache_labels=True, - cache_images=opt.cache_images), - batch_size=batch_size * 2, - num_workers=nw, - pin_memory=True, - collate_fn=dataset.collate_fn) + # Testloader + testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, opt.img_size, batch_size * 2, + hyp=hyp, + rect=True, + cache_labels=True, + cache_images=opt.cache_images), + batch_size=batch_size * 2, + num_workers=nw, + pin_memory=True, + collate_fn=dataset.collate_fn) # Start training nb = len(dataloader) @@ -222,11 +211,26 @@ def train(): t0 = time.time() torch_utils.model_info(model, report='summary') # 'full' or 'summary' print('Using %g dataloader workers' % nw) - print('Starting %s for %g epochs...' % ('prebias' if opt.prebias else 'training', epochs)) - for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ + print('Starting training for %g epochs...' % epochs) + for epoch in range(start_epoch - 1 if opt.prebias else start_epoch, epochs): # epoch ------------------------------ model.train() print(('\n' + '%10s' * 8) % ('Epoch', 'gpu_mem', 'GIoU', 'obj', 'cls', 'total', 'targets', 'img_size')) + # Prebias + if opt.prebias: + if epoch < 0: # prebias + ps = 0.1, 0.9, False # prebias settings (lr=0.1, momentum=0.9, requires_grad=False) + else: # normal training + ps = hyp['lr0'], hyp['momentum'], True # normal training settings + opt.prebias = False + + for p in optimizer.param_groups: + p['lr'] = ps[0] # learning rate + if p.get('momentum') is not None: # for SGD but not Adam + p['momentum'] = ps[1] + for name, p in model.named_parameters(): + p.requires_grad = True if name.endswith('.bias') else ps[2] + # Update image weights (optional) if dataset.image_weights: w = model.class_weights.cpu().numpy() * (1 - maps) ** 2 # class weights @@ -300,13 +304,11 @@ def train(): # end batch ------------------------------------------------------------------------------------------------ - # Update scheduler - scheduler.step() - # Process epoch results final_epoch = epoch + 1 == epochs if opt.prebias: print_model_biases(model) + continue elif not opt.notest or final_epoch: # Calculate mAP is_coco = any([x in data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) and model.nc == 80 results, maps = test.test(cfg, @@ -319,10 +321,13 @@ def train(): save_json=final_epoch and is_coco, dataloader=testloader) + # Update scheduler + scheduler.step() + # Write epoch results with open(results_file, 'a') as f: f.write(s + '%10.3g' * 7 % results + '\n') # P, R, mAP, F1, test_losses=(GIoU, obj, cls) - if len(opt.name) and opt.bucket and not opt.prebias: + if len(opt.name) and opt.bucket: os.system('gsutil cp results.txt gs://%s/results%s.txt' % (opt.bucket, opt.name)) # Write Tensorboard results @@ -339,7 +344,7 @@ def train(): best_fitness = fitness # Save training results - save = (not opt.nosave) or (final_epoch and not opt.evolve) or opt.prebias + save = (not opt.nosave) or (final_epoch and not opt.evolve) if save: with open(results_file, 'r') as f: # Create checkpoint @@ -368,7 +373,7 @@ def train(): # end training n = opt.name - if len(n) and not opt.prebias: + if len(n): n = '_' + n if not n.isnumeric() else n fresults, flast, fbest = 'results%s.txt' % n, 'last%s.pt' % n, 'best%s.pt' % n os.rename('results.txt', fresults) @@ -387,20 +392,6 @@ def train(): return results -def prebias(): - # trains output bias layers for 1 epoch and creates new backbone - if opt.prebias: - # opt_0 = opt # save settings - # opt.rect = False # update settings (if any) - - train() # train model biases - create_backbone(last) # saved results as backbone.pt - - # opt = opt_0 # reset settings - opt.weights = wdir + 'backbone.pt' # assign backbone - opt.prebias = False # disable prebias - - if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--epochs', type=int, default=273) # 500200 batches at bs 16, 117263 COCO images = 273 epochs @@ -444,7 +435,6 @@ def prebias(): except: pass - prebias() # optional train() # train normally else: # Evolve hyperparameters (optional) @@ -483,7 +473,6 @@ def prebias(): hyp[k] = np.clip(hyp[k], v[0], v[1]) # Train mutation - prebias() results = train() # Write mutation results diff --git a/utils/evolve.sh b/utils/evolve.sh index 003312f5d1..afcc0ba63d 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -8,7 +8,9 @@ #t=ultralytics/yolov3:v199 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 672 --epochs 10 --batch 16 --accum 4 --weights '' --arc defaultpw --device 0 --multi while true; do - python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --evolve --device $1 --cfg yolov3-tiny-3cls.cfg + python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --evolve --device $1 --cfg yolov3-tiny-3cls.cfg --cache + # python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ult/athena --evolve --device $1 + # python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/640ms_coco2014_10e --device $1 --multi # python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch 64 --accum 1 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/320_coco2014_27e --device $1 done diff --git a/utils/gcp.sh b/utils/gcp.sh index f5975f6d55..378e794cf2 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -40,12 +40,13 @@ python3 test.py --save-json # Evolve t=ultralytics/yolov3:v206 sudo docker kill $(sudo docker ps -a -q --filter ancestor=$t) -for i in 0 1 2 3 4 5 6 7 +for i in 0 1 2 3 do - sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i + sudo docker pull $t && sudo docker run --gpus all -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i + # sudo docker pull $t && sudo docker run --gpus all -d --ipc=host -v "$(pwd)"/out:/usr/src/out $t bash utils/evolve.sh $i # sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i # sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v /mnt/disks/nvme0n1/coco:/usr/src/coco $t bash utils/evolve.sh $i - sleep 1 + sleep 120 done @@ -257,6 +258,7 @@ n=198 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker r n=199 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 0 n=200 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 6 n=207 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 7 +n=208 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 # sm4 n=201 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 0 --cfg yolov3-tiny-3cls.cfg @@ -265,3 +267,4 @@ n=203 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker n=204 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 3 --cfg yolov3-tiny-3cls-sm4.cfg n=205 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 4 --cfg yolov3-tiny-3cls-sm4.cfg +n=206 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --notest --nosave --cache --device 0 --cfg yolov3-tiny-3cls.cfg diff --git a/utils/utils.py b/utils/utils.py index 301a852d91..b08744d852 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -633,7 +633,7 @@ def get_yolo_layers(model): def print_model_biases(model): # prints the bias neurons preceding each yolo layer - print('\nModel Bias Summary (per output layer):') + print('\nModel Bias Summary:') multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) for l in model.yolo_layers: # print pretrained biases if multi_gpu: @@ -642,7 +642,7 @@ def print_model_biases(model): else: na = model.module_list[l].na b = model.module_list[l - 1][0].bias.view(na, -1) # bias 3x85 - print('regression: %5.2f+/-%-5.2f ' % (b[:, :4].mean(), b[:, :4].std()), + print('layer %3g regression: %5.2f+/-%-5.2f ' % (l, b[:, :4].mean(), b[:, :4].std()), 'objectness: %5.2f+/-%-5.2f ' % (b[:, 4].mean(), b[:, 4].std()), 'classification: %5.2f+/-%-5.2f' % (b[:, 5:].mean(), b[:, 5:].std())) From fc0748f876fd570a9583c95d26a01d764e4d10d5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Jan 2020 23:28:54 -0800 Subject: [PATCH 0292/1185] updates --- train.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/train.py b/train.py index a0a1cde25e..c36b0e00e3 100644 --- a/train.py +++ b/train.py @@ -451,24 +451,22 @@ def train(): if parent == 'single' or len(x) == 1: x = x[fitness(x).argmax()] elif parent == 'weighted': # weighted combination - n = min(10, x.shape[0]) # number to merge + n = min(10, len(x)) # number to merge x = x[np.argsort(-fitness(x))][:n] # top n mutations w = fitness(x) - fitness(x).min() # weights - x = (x[:n] * w.reshape(n, 1)).sum(0) / w.sum() # new parent - for i, k in enumerate(hyp.keys()): - hyp[k] = x[i + 7] + x = (x * w.reshape(n, 1)).sum(0) / w.sum() # new parent # Mutate np.random.seed(int(time.time())) s = np.random.random() * 0.2 # sigma g = [1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 1, 1, 1, 1, 1, 1, 1, 1] # gains + g = (np.random.randn(len(g)) * np.array(g) * s + 1) ** 2.0 # plt.hist(x.ravel(), 300) for i, k in enumerate(hyp.keys()): - x = (np.random.randn() * s * g[i] + 1) ** 2.0 # plt.hist(x.ravel(), 300) - hyp[k] *= float(x) # vary by sigmas + hyp[k] = x[i + 7] * g[i] # mutate parent # Clip to limits keys = ['lr0', 'iou_t', 'momentum', 'weight_decay', 'hsv_s', 'hsv_v', 'translate', 'scale', 'fl_gamma'] - limits = [(1e-5, 1e-2), (0.00, 0.70), (0.60, 0.99), (0, 0.001), (0, .9), (0, .9), (0, .9), (0, .9), (0, 3)] + limits = [(1e-5, 1e-2), (0.00, 0.70), (0.60, 0.98), (0, 0.001), (0, .9), (0, .9), (0, .9), (0, .9), (0, 3)] for k, v in zip(keys, limits): hyp[k] = np.clip(hyp[k], v[0], v[1]) From 1638ab71cd9a5f2e4d8507690718764d5d1583f3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Jan 2020 23:31:25 -0800 Subject: [PATCH 0293/1185] updates --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 4be1121dfc..54fc15d3ca 100644 --- a/test.py +++ b/test.py @@ -49,7 +49,7 @@ def test(cfg, path = data['valid'] # path to test images names = load_classes(data['names']) # class names iouv = torch.linspace(0.5, 0.95, 10).to(device) # iou vector for mAP@0.5:0.95 - iouv = iouv[0].view(1) # for mAP@0.5 + iouv = iouv[0].view(1) # comment for mAP@0.5:0.95 niou = iouv.numel() # Dataloader From 5cda317902a65f82675d7dbb1dc0038c5c98c08e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Jan 2020 13:11:30 -0800 Subject: [PATCH 0294/1185] updates --- models.py | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/models.py b/models.py index 3304a50619..9ce72ece6e 100755 --- a/models.py +++ b/models.py @@ -177,27 +177,14 @@ def forward(self, p, img_size, var=None): elif ONNX_EXPORT: # Constants CAN NOT BE BROADCAST, ensure correct shape! m = self.na * self.nx * self.ny - ngu = self.ng.repeat((1, m, 1)) - grid_xy = self.grid_xy.repeat((1, self.na, 1, 1, 1)).view(1, m, 2) - anchor_wh = self.anchor_wh.repeat((1, 1, self.nx, self.ny, 1)).view(1, m, 2) / ngu + grid_xy = self.grid_xy.repeat((1, self.na, 1, 1, 1)).view(m, 2) + anchor_wh = self.anchor_wh.repeat((1, 1, self.nx, self.ny, 1)).view(m, 2) / self.ng p = p.view(m, self.no) - xy = torch.sigmoid(p[:, 0:2]) + grid_xy[0] # x, y - wh = torch.exp(p[:, 2:4]) * anchor_wh[0] # width, height - p_cls = F.softmax(p[:, 5:self.no], 1) * torch.sigmoid(p[:, 4:5]) # SSD-like conf - return torch.cat((xy / ngu[0], wh, p_cls), 1).t() - - # p = p.view(1, m, self.no) - # xy = torch.sigmoid(p[..., 0:2]) + grid_xy # x, y - # wh = torch.exp(p[..., 2:4]) * anchor_wh # width, height - # p_conf = torch.sigmoid(p[..., 4:5]) # Conf - # p_cls = p[..., 5:self.no] - # # Broadcasting only supported on first dimension in CoreML. See onnx-coreml/_operators.py - # # p_cls = F.softmax(p_cls, 2) * p_conf # SSD-like conf - # p_cls = torch.exp(p_cls).permute((2, 1, 0)) - # p_cls = p_cls / p_cls.sum(0).unsqueeze(0) * p_conf.permute((2, 1, 0)) # F.softmax() equivalent - # p_cls = p_cls.permute(2, 1, 0) - # return torch.cat((xy / ngu, wh, p_conf, p_cls), 2).squeeze().t() + xy = torch.sigmoid(p[:, 0:2]) + grid_xy # x, y + wh = torch.exp(p[:, 2:4]) * anchor_wh # width, height + p_cls = torch.sigmoid(p[:, 5:self.no]) * torch.sigmoid(p[:, 4:5]) # conf + return p_cls, xy / self.ng, wh else: # inference # s = 1.5 # scale_xy (pxy = pxy * s - (s - 1) / 2) @@ -266,9 +253,8 @@ def forward(self, x, var=None): if self.training: return output elif ONNX_EXPORT: - output = torch.cat(output, 1) # cat 3 layers 85 x (507, 2028, 8112) to 85 x 10647 - nc = self.module_list[self.yolo_layers[0]].nc # number of classes - return output[4:4 + nc].t(), output[0:4].t() # ONNX scores, boxes + x = [torch.cat(x, 0) for x in zip(*output)] + return x[0], torch.cat(x[1:3], 1) # scores, boxes: 3780x80, 3780x4 else: io, p = list(zip(*output)) # inference output, training output return torch.cat(io, 1), p From 9b8488577571fb96823e617dc328b65d17707a67 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Jan 2020 13:12:58 -0800 Subject: [PATCH 0295/1185] updates --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 54fc15d3ca..b09547206d 100644 --- a/test.py +++ b/test.py @@ -155,7 +155,7 @@ def test(cfg, stats.append((correct, pred[:, 4].cpu(), pred[:, 5].cpu(), tcls)) # Compute statistics - stats = [np.concatenate(x, 0) for x in list(zip(*stats))] # to numpy + stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy if len(stats): p, r, ap, f1, ap_class = ap_per_class(*stats) if niou > 1: From 4b56a370e6af1ccabc69398954c3549d842aae93 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Jan 2020 13:13:57 -0800 Subject: [PATCH 0296/1185] updates --- utils/datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/datasets.py b/utils/datasets.py index 4061af81ac..4c0e3b20ce 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -499,7 +499,7 @@ def __getitem__(self, index): @staticmethod def collate_fn(batch): - img, label, path, shapes = list(zip(*batch)) # transposed + img, label, path, shapes = zip(*batch) # transposed for i, l in enumerate(label): l[:, 0] = i # add target image index for build_targets() return torch.stack(img, 0), torch.cat(label, 0), path, shapes From 77034467f6beab5528f14567fedd3ccfa7bb6102 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Jan 2020 20:13:29 -0800 Subject: [PATCH 0297/1185] updates --- utils/datasets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/datasets.py b/utils/datasets.py index 4c0e3b20ce..bd87dd19fa 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -515,7 +515,8 @@ def load_image(self, index): h0, w0 = img.shape[:2] # orig hw r = self.img_size / max(h0, w0) # resize image to img_size if r < 1 or (self.augment and (r != 1)): # always resize down, only resize up if training with augmentation - img = cv2.resize(img, (int(w0 * r), int(h0 * r)), interpolation=cv2.INTER_LINEAR) # _LINEAR fastest + interp = cv2.INTER_LINEAR if self.augment else cv2.INTER_AREA # LINEAR for training, AREA for testing + img = cv2.resize(img, (int(w0 * r), int(h0 * r)), interpolation=interp) return img, (h0, w0), img.shape[:2] # img, hw_original, hw_resized else: return self.imgs[index], self.img_hw0[index], self.img_hw[index] # img, hw_original, hw_resized From 01d485831fa77a31a6425e22bd5e7dd3e78ff5f7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Jan 2020 20:15:41 -0800 Subject: [PATCH 0298/1185] updates --- train.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/train.py b/train.py index c36b0e00e3..373b709ca0 100644 --- a/train.py +++ b/train.py @@ -174,8 +174,7 @@ def train(): augment=True, hyp=hyp, # augmentation hyperparameters rect=opt.rect, # rectangular training - image_weights=False, - cache_labels=epochs > 10, + cache_labels=True, cache_images=opt.cache_images) # Dataloader From aeac9b78eb6c541d34dd07e25ad52f1310adefad Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Jan 2020 21:20:55 -0800 Subject: [PATCH 0299/1185] updates --- utils/gcp.sh | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index 378e794cf2..ad85b403ab 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -3,10 +3,11 @@ # New VM rm -rf sample_data yolov3 git clone https://github.com/ultralytics/yolov3 +sudo apt-get install zip #git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex sudo conda install -yc conda-forge scikit-image pycocotools # python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('193Zp_ye-3qXMonR1nZj3YyxMtQkMy50k','coco2014.zip')" -python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco2017.zip')" +python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco2014.zip')" sudo shutdown # Re-clone @@ -38,15 +39,16 @@ python3 detect.py python3 test.py --save-json # Evolve -t=ultralytics/yolov3:v206 -sudo docker kill $(sudo docker ps -a -q --filter ancestor=$t) -for i in 0 1 2 3 +t=ultralytics/yolov3:v208 +# sudo docker kill $(sudo docker ps -a -q --filter ancestor=$t) +for i in 2 3 do - sudo docker pull $t && sudo docker run --gpus all -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i - # sudo docker pull $t && sudo docker run --gpus all -d --ipc=host -v "$(pwd)"/out:/usr/src/out $t bash utils/evolve.sh $i + # sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i + sudo docker pull $t && sudo docker run --gpus all -d --ipc=host -v "$(pwd)"/out:/usr/src/out $t bash utils/evolve.sh $i + # sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i # sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v /mnt/disks/nvme0n1/coco:/usr/src/coco $t bash utils/evolve.sh $i - sleep 120 + sleep 180 done @@ -259,6 +261,7 @@ n=199 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker r n=200 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 6 n=207 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 7 n=208 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 +n=211 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n # sm4 n=201 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 0 --cfg yolov3-tiny-3cls.cfg @@ -266,5 +269,6 @@ n=202 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker n=203 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 2 --cfg yolov3-tiny-3cls-sm4.cfg n=204 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 3 --cfg yolov3-tiny-3cls-sm4.cfg n=205 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 4 --cfg yolov3-tiny-3cls-sm4.cfg - n=206 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --notest --nosave --cache --device 0 --cfg yolov3-tiny-3cls.cfg +n=209 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 3 --cfg yolov3-tiny-3cls.cfg +n=210 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-3cls.cfg From b890ccecfc4e3ded5c998f00e9611c48a6e5cf60 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Jan 2020 12:01:58 -0800 Subject: [PATCH 0300/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 9ce72ece6e..ae861cec6c 100755 --- a/models.py +++ b/models.py @@ -206,7 +206,7 @@ def forward(self, p, img_size, var=None): if self.nc == 1: io[..., 5] = 1 # single-class model https://github.com/ultralytics/yolov3/issues/235 - # reshape from [1, 3, 13, 13, 85] to [1, 507, 84], remove obj_conf + # reshape from [1, 3, 13, 13, 85] to [1, 507, 85] return io.view(bs, -1, self.no), p From 5ac3eb42b69de0f210f66c04462736c8869d01a4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Jan 2020 15:56:42 -0800 Subject: [PATCH 0301/1185] updates --- train.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/train.py b/train.py index 373b709ca0..2ec9db9bf9 100644 --- a/train.py +++ b/train.py @@ -446,7 +446,7 @@ def train(): if os.path.exists('evolve.txt'): # if evolve.txt exists: select best hyps and mutate # Select parent(s) x = np.loadtxt('evolve.txt', ndmin=2) - parent = 'weighted' # parent selection method: 'single' or 'weighted' + parent = 'single' # parent selection method: 'single' or 'weighted' if parent == 'single' or len(x) == 1: x = x[fitness(x).argmax()] elif parent == 'weighted': # weighted combination @@ -456,12 +456,21 @@ def train(): x = (x * w.reshape(n, 1)).sum(0) / w.sum() # new parent # Mutate + mutate_version = 2 np.random.seed(int(time.time())) - s = np.random.random() * 0.2 # sigma - g = [1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 1, 1, 1, 1, 1, 1, 1, 1] # gains - g = (np.random.randn(len(g)) * np.array(g) * s + 1) ** 2.0 # plt.hist(x.ravel(), 300) + s = 0.2 # 20% sigma + g = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) # gains + ng = len(g) + if mutate_version == 1: + s *= np.random.random() # sigma + v = (np.random.randn(ng) * g * s + 1) ** 2.0 # plt.hist(x.ravel(), 300) + else: + v = np.ones(ng) + while all(v == 1): # mutate untill a change occurs (prevent duplicates) + r = (np.random.random(ng) < 0.1) * np.random.randn(ng) # 10% mutation probability + v = (g * s * r + 1) ** 2.0 # plt.hist(x.ravel(), 300) for i, k in enumerate(hyp.keys()): - hyp[k] = x[i + 7] * g[i] # mutate parent + hyp[k] = x[i + 7] * v[i] # mutate # Clip to limits keys = ['lr0', 'iou_t', 'momentum', 'weight_decay', 'hsv_s', 'hsv_v', 'translate', 'scale', 'fl_gamma'] From 33264f55679560284900f76c385fa54a7e0f86b3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Jan 2020 16:18:29 -0800 Subject: [PATCH 0302/1185] updates --- train.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/train.py b/train.py index 2ec9db9bf9..44ac37084c 100644 --- a/train.py +++ b/train.py @@ -383,7 +383,8 @@ def train(): if opt.bucket: os.system('gsutil cp %s %s gs://%s' % (fresults, wdir + flast, opt.bucket)) - plot_results() # save as results.png + if not opt.evolve: + plot_results() # save as results.png print('%g epochs completed in %.3f hours.\n' % (epoch - start_epoch + 1, (time.time() - t0) / 3600)) dist.destroy_process_group() if torch.cuda.device_count() > 1 else None torch.cuda.empty_cache() From 25ccf54a94ca43dfbd045b5353a6c4220d3b18b2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Jan 2020 17:05:03 -0800 Subject: [PATCH 0303/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 44ac37084c..dbb389dae9 100644 --- a/train.py +++ b/train.py @@ -460,7 +460,7 @@ def train(): mutate_version = 2 np.random.seed(int(time.time())) s = 0.2 # 20% sigma - g = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) # gains + g = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 0, 1, 1, 1, 1, 1, 1, 1]) # gains ng = len(g) if mutate_version == 1: s *= np.random.random() # sigma From c67ba502669330c3adf1a4becf9d988441a26140 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 13 Jan 2020 20:59:59 -0800 Subject: [PATCH 0304/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index b08744d852..a19e594edb 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -817,7 +817,7 @@ def print_mutation(hyp, results, bucket=''): print('\n%s\n%s\nEvolved fitness: %s\n' % (a, b, c)) if bucket: - os.system('rm evolve.txt && gsutil cp gs://%s/evolve.txt .' % bucket) # download evolve.txt + os.system('gsutil cp gs://%s/evolve.txt .' % bucket) # download evolve.txt with open('evolve.txt', 'a') as f: # append result f.write(c + b + '\n') From c5d7ff27e6180d6f6608ee420360899f87d7d577 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 13 Jan 2020 22:19:45 -0800 Subject: [PATCH 0305/1185] updates --- utils/evolve.sh | 2 +- utils/gcp.sh | 329 +++++++++++++++++++++++++----------------------- 2 files changed, 173 insertions(+), 158 deletions(-) diff --git a/utils/evolve.sh b/utils/evolve.sh index afcc0ba63d..bdc0a2c031 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -9,7 +9,7 @@ while true; do python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --evolve --device $1 --cfg yolov3-tiny-3cls.cfg --cache - # python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ult/athena --evolve --device $1 + # python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg # python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/640ms_coco2014_10e --device $1 --multi # python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch 64 --accum 1 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/320_coco2014_27e --device $1 diff --git a/utils/gcp.sh b/utils/gcp.sh index ad85b403ab..c1c731e078 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -39,18 +39,30 @@ python3 detect.py python3 test.py --save-json # Evolve -t=ultralytics/yolov3:v208 -# sudo docker kill $(sudo docker ps -a -q --filter ancestor=$t) -for i in 2 3 +sudo -s +t=ultralytics/yolov3:v206 +docker kill $(docker ps -a -q --filter ancestor=$t) +for i in 6 7 do - # sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i - sudo docker pull $t && sudo docker run --gpus all -d --ipc=host -v "$(pwd)"/out:/usr/src/out $t bash utils/evolve.sh $i - - # sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i - # sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v /mnt/disks/nvme0n1/coco:/usr/src/coco $t bash utils/evolve.sh $i + docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i + # docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/out:/usr/src/out $t bash utils/evolve.sh $i + # docker pull $t && nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i + # docker pull $t && nvidia-docker run -d -v /mnt/disks/nvme0n1/coco:/usr/src/coco $t bash utils/evolve.sh $i sleep 180 done +# Evolve +sudo -s +t=ultralytics/yolov3:v208 +docker kill $(docker ps -a -q --filter ancestor=$t) +for i in 0 +do + # docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i + docker pull $t && docker run --gpus all -it --ipc=host -v "$(pwd)"/out:/usr/src/out $t bash utils/evolve.sh $i + # docker pull $t && nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i + # docker pull $t && nvidia-docker run -d -v /mnt/disks/nvme0n1/coco:/usr/src/coco $t bash utils/evolve.sh $i + sleep 180 +done # Git pull git pull https://github.com/ultralytics/yolov3 # master @@ -107,168 +119,171 @@ rm -rf darknet && git clone https://github.com/AlexeyAB/darknet && cd darknet && #Docker sudo docker kill "$(sudo docker ps -q)" sudo docker pull ultralytics/yolov3:v0 -sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco ultralytics/yolov3:v0 +sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco ultralytics/yolov3:v0 -t=ultralytics/yolov3:v70 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 70 --device 0 --multi -t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 71 --device 0 --multi --img-weights +t=ultralytics/yolov3:v70 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 70 --device 0 --multi +t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 71 --device 0 --multi --img-weights -t=ultralytics/yolov3:v73 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 73 --device 5 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v74 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 74 --device 0 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v75 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 75 --device 7 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v76 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 76 --device 0 --cfg cfg/yolov3-spp.cfg +t=ultralytics/yolov3:v73 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 73 --device 5 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v74 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 74 --device 0 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v75 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 75 --device 7 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v76 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 76 --device 0 --cfg cfg/yolov3-spp.cfg -t=ultralytics/yolov3:v79 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 79 --device 5 -t=ultralytics/yolov3:v80 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 80 --device 0 -t=ultralytics/yolov3:v81 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 81 --device 7 -t=ultralytics/yolov3:v82 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 82 --device 0 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v79 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 79 --device 5 +t=ultralytics/yolov3:v80 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 80 --device 0 +t=ultralytics/yolov3:v81 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 81 --device 7 +t=ultralytics/yolov3:v82 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 82 --device 0 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 83 --device 6 --multi --nosave -t=ultralytics/yolov3:v84 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 84 --device 0 --multi -t=ultralytics/yolov3:v85 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 85 --device 0 --multi -t=ultralytics/yolov3:v86 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 86 --device 1 --multi -t=ultralytics/yolov3:v87 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 87 --device 2 --multi -t=ultralytics/yolov3:v88 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 88 --device 3 --multi -t=ultralytics/yolov3:v89 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 89 --device 1 -t=ultralytics/yolov3:v90 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 90 --device 0 --cfg cfg/yolov3-spp-matrix.cfg -t=ultralytics/yolov3:v91 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 91 --device 0 --cfg cfg/yolov3-spp-matrix.cfg +t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 83 --device 6 --multi --nosave +t=ultralytics/yolov3:v84 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 84 --device 0 --multi +t=ultralytics/yolov3:v85 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 85 --device 0 --multi +t=ultralytics/yolov3:v86 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 86 --device 1 --multi +t=ultralytics/yolov3:v87 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 87 --device 2 --multi +t=ultralytics/yolov3:v88 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 88 --device 3 --multi +t=ultralytics/yolov3:v89 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 89 --device 1 +t=ultralytics/yolov3:v90 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 90 --device 0 --cfg cfg/yolov3-spp-matrix.cfg +t=ultralytics/yolov3:v91 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 91 --device 0 --cfg cfg/yolov3-spp-matrix.cfg -t=ultralytics/yolov3:v92 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 92 --device 0 -t=ultralytics/yolov3:v93 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 93 --device 0 --cfg cfg/yolov3-spp-matrix.cfg +t=ultralytics/yolov3:v92 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 92 --device 0 +t=ultralytics/yolov3:v93 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 93 --device 0 --cfg cfg/yolov3-spp-matrix.cfg #SM4 -t=ultralytics/yolov3:v96 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 96 --device 0 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -t=ultralytics/yolov3:v97 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 97 --device 4 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -t=ultralytics/yolov3:v98 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 16 --accum 4 --pre --bucket yolov4 --name 98 --device 5 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --pre --bucket yolov4 --name 101 --device 7 --multi --nosave - -t=ultralytics/yolov3:v102 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 1000 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 102 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v103 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 103 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v104 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 104 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v105 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 105 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v106 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 106 --device 0 --cfg cfg/yolov3-tiny-3cls-sm4.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v107 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 107 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg -t=ultralytics/yolov3:v108 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 108 --device 7 --nosave - -t=ultralytics/yolov3:v109 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 109 --device 4 --multi --nosave -t=ultralytics/yolov3:v110 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 110 --device 3 --multi --nosave - -t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 111 --device 0 -t=ultralytics/yolov3:v112 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 112 --device 1 --nosave -t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 113 --device 2 --nosave -t=ultralytics/yolov3:v114 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 114 --device 2 --nosave -t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 115 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg -t=ultralytics/yolov3:v116 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 116 --device 1 --nosave - -t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 117 --device 0 --nosave --multi -t=ultralytics/yolov3:v118 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 118 --device 5 --nosave --multi -t=ultralytics/yolov3:v119 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 119 --device 1 --nosave -t=ultralytics/yolov3:v120 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 120 --device 2 --nosave -t=ultralytics/yolov3:v121 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 121 --device 0 --nosave --cfg cfg/csresnext50-panet-spp.cfg -t=ultralytics/yolov3:v122 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 122 --device 2 --nosave -t=ultralytics/yolov3:v123 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 123 --device 5 --nosave - -t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 124 --device 0 --nosave --cfg yolov3-tiny -t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 125 --device 1 --nosave --cfg yolov3-tiny2 -t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 126 --device 1 --nosave --cfg yolov3-tiny3 -t=ultralytics/yolov3:v127 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 127 --device 0 --nosave --cfg yolov3-tiny4 -t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 128 --device 1 --nosave --cfg yolov3-tiny2 --multi -t=ultralytics/yolov3:v129 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 129 --device 0 --nosave --cfg yolov3-tiny2 - -t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 130 --device 0 --nosave -t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 250 --pre --bucket yolov4 --name 131 --device 0 --nosave --multi -t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 132 --device 0 --nosave --data coco2014.data -t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 27 --pre --bucket yolov4 --name 133 --device 0 --nosave --multi -t=ultralytics/yolov3:v134 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 134 --device 0 --nosave --data coco2014.data - -t=ultralytics/yolov3:v135 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 135 --device 0 --nosave --multi --data coco2014.data -t=ultralytics/yolov3:v136 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 136 --device 0 --nosave --multi --data coco2014.data - -t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 137 --device 7 --nosave --data coco2014.data -t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --bucket yolov4 --name 138 --device 6 --nosave --data coco2014.data - -t=ultralytics/yolov3:v140 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 140 --device 1 --nosave --data coco2014.data --arc uBCE -t=ultralytics/yolov3:v141 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 141 --device 0 --nosave --data coco2014.data --arc uBCE -t=ultralytics/yolov3:v142 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 142 --device 1 --nosave --data coco2014.data --arc uBCE - -t=ultralytics/yolov3:v146 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 146 --device 0 --nosave --data coco2014.data -t=ultralytics/yolov3:v147 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 147 --device 1 --nosave --data coco2014.data -t=ultralytics/yolov3:v148 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 148 --device 2 --nosave --data coco2014.data -t=ultralytics/yolov3:v149 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 149 --device 3 --nosave --data coco2014.data -t=ultralytics/yolov3:v150 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 150 --device 4 --nosave --data coco2014.data -t=ultralytics/yolov3:v151 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 151 --device 5 --nosave --data coco2014.data -t=ultralytics/yolov3:v152 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 152 --device 6 --nosave --data coco2014.data -t=ultralytics/yolov3:v153 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 153 --device 7 --nosave --data coco2014.data - -t=ultralytics/yolov3:v154 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 154 --device 0 --nosave --data coco2014.data -t=ultralytics/yolov3:v155 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 155 --device 0 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v156 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 156 --device 5 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v157 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 157 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v158 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 158 --device 7 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v159 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 159 --device 0 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v160 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 160 --device 1 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v161 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 161 --device 2 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v162 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 162 --device 3 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v163 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 163 --device 4 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v164 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 164 --device 5 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v165 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 165 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v166 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 166 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v167 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 167 --device 7 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v168 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 168 --device 5 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v169 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 169 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v170 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 170 --device 7 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v171 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 171 --device 4 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v172 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 172 --device 3 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v173 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 173 --device 2 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v174 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 174 --device 1 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v175 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 175 --device 0 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v177 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 177 --device 0 --nosave --data coco2014.data --multi -t=ultralytics/yolov3:v178 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 178 --device 0 --nosave --data coco2014.data --multi -t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 179 --device 0 --nosave --data coco2014.data --multi --cfg yolov3s-18a.cfg +t=ultralytics/yolov3:v96 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 96 --device 0 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +t=ultralytics/yolov3:v97 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 97 --device 4 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +t=ultralytics/yolov3:v98 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 16 --accum 4 --pre --bucket yolov4 --name 98 --device 5 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --pre --bucket yolov4 --name 101 --device 7 --multi --nosave + +t=ultralytics/yolov3:v102 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 1000 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 102 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v103 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 103 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v104 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 104 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v105 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 105 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v106 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 106 --device 0 --cfg cfg/yolov3-tiny-3cls-sm4.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v107 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 107 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg +t=ultralytics/yolov3:v108 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 108 --device 7 --nosave + +t=ultralytics/yolov3:v109 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 109 --device 4 --multi --nosave +t=ultralytics/yolov3:v110 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 110 --device 3 --multi --nosave + +t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 111 --device 0 +t=ultralytics/yolov3:v112 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 112 --device 1 --nosave +t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 113 --device 2 --nosave +t=ultralytics/yolov3:v114 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 114 --device 2 --nosave +t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 115 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg +t=ultralytics/yolov3:v116 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 116 --device 1 --nosave + +t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 117 --device 0 --nosave --multi +t=ultralytics/yolov3:v118 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 118 --device 5 --nosave --multi +t=ultralytics/yolov3:v119 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 119 --device 1 --nosave +t=ultralytics/yolov3:v120 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 120 --device 2 --nosave +t=ultralytics/yolov3:v121 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 121 --device 0 --nosave --cfg cfg/csresnext50-panet-spp.cfg +t=ultralytics/yolov3:v122 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 122 --device 2 --nosave +t=ultralytics/yolov3:v123 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 123 --device 5 --nosave + +t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 124 --device 0 --nosave --cfg yolov3-tiny +t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 125 --device 1 --nosave --cfg yolov3-tiny2 +t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 126 --device 1 --nosave --cfg yolov3-tiny3 +t=ultralytics/yolov3:v127 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 127 --device 0 --nosave --cfg yolov3-tiny4 +t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 128 --device 1 --nosave --cfg yolov3-tiny2 --multi +t=ultralytics/yolov3:v129 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 129 --device 0 --nosave --cfg yolov3-tiny2 + +t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 130 --device 0 --nosave +t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 250 --pre --bucket yolov4 --name 131 --device 0 --nosave --multi +t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 132 --device 0 --nosave --data coco2014.data +t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 27 --pre --bucket yolov4 --name 133 --device 0 --nosave --multi +t=ultralytics/yolov3:v134 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 134 --device 0 --nosave --data coco2014.data + +t=ultralytics/yolov3:v135 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 135 --device 0 --nosave --multi --data coco2014.data +t=ultralytics/yolov3:v136 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 136 --device 0 --nosave --multi --data coco2014.data + +t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 137 --device 7 --nosave --data coco2014.data +t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --bucket yolov4 --name 138 --device 6 --nosave --data coco2014.data + +t=ultralytics/yolov3:v140 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 140 --device 1 --nosave --data coco2014.data --arc uBCE +t=ultralytics/yolov3:v141 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 141 --device 0 --nosave --data coco2014.data --arc uBCE +t=ultralytics/yolov3:v142 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 142 --device 1 --nosave --data coco2014.data --arc uBCE + +t=ultralytics/yolov3:v146 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 146 --device 0 --nosave --data coco2014.data +t=ultralytics/yolov3:v147 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 147 --device 1 --nosave --data coco2014.data +t=ultralytics/yolov3:v148 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 148 --device 2 --nosave --data coco2014.data +t=ultralytics/yolov3:v149 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 149 --device 3 --nosave --data coco2014.data +t=ultralytics/yolov3:v150 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 150 --device 4 --nosave --data coco2014.data +t=ultralytics/yolov3:v151 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 151 --device 5 --nosave --data coco2014.data +t=ultralytics/yolov3:v152 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 152 --device 6 --nosave --data coco2014.data +t=ultralytics/yolov3:v153 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 153 --device 7 --nosave --data coco2014.data + +t=ultralytics/yolov3:v154 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 154 --device 0 --nosave --data coco2014.data +t=ultralytics/yolov3:v155 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 155 --device 0 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v156 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 156 --device 5 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v157 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 157 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v158 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 158 --device 7 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v159 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 159 --device 0 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v160 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 160 --device 1 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v161 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 161 --device 2 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v162 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 162 --device 3 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v163 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 163 --device 4 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v164 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 164 --device 5 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v165 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 165 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v166 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 166 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v167 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 167 --device 7 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v168 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 168 --device 5 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v169 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 169 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v170 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 170 --device 7 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v171 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 171 --device 4 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v172 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 172 --device 3 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v173 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 173 --device 2 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v174 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 174 --device 1 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v175 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 175 --device 0 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v177 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 177 --device 0 --nosave --data coco2014.data --multi +t=ultralytics/yolov3:v178 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 178 --device 0 --nosave --data coco2014.data --multi +t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 179 --device 0 --nosave --data coco2014.data --multi --cfg yolov3s-18a.cfg t=ultralytics/yolov3:v143 && sudo docker build -t $t . && sudo docker push $t -t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 179 -t=ultralytics/yolov3:v180 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 180 -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 181 --cfg yolov3s9a-640.cfg -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 182 --cfg yolov3s9a-320-640.cfg -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 183 --cfg yolov3s15a-640.cfg -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 184 --cfg yolov3s15a-320-640.cfg - -t=ultralytics/yolov3:v185 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 185 -t=ultralytics/yolov3:v186 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 186 -n=187 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -t=ultralytics/yolov3:v189 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 188 --cfg yolov3s15a-320-640.cfg -n=190 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=191 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=192 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n - -n=193 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=194 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=195 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=196 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n - -n=197 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=198 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 179 +t=ultralytics/yolov3:v180 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 180 +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 181 --cfg yolov3s9a-640.cfg +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 182 --cfg yolov3s9a-320-640.cfg +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 183 --cfg yolov3s15a-640.cfg +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 184 --cfg yolov3s15a-320-640.cfg + +t=ultralytics/yolov3:v185 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 185 +t=ultralytics/yolov3:v186 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 186 +n=187 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +t=ultralytics/yolov3:v189 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 188 --cfg yolov3s15a-320-640.cfg +n=190 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=191 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=192 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n + +n=193 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=194 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=195 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=196 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n + +n=197 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=198 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n # knife -n=199 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 0 -n=200 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 6 -n=207 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 7 -n=208 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 -n=211 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n +n=199 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 0 +n=200 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 6 +n=207 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 7 +n=208 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 +n=211 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg +n=212 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg +n=213 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg +n=214 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg # sm4 -n=201 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 0 --cfg yolov3-tiny-3cls.cfg -n=202 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 1 --cfg yolov3-tiny-3cls-sm4.cfg -n=203 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 2 --cfg yolov3-tiny-3cls-sm4.cfg -n=204 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 3 --cfg yolov3-tiny-3cls-sm4.cfg -n=205 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 4 --cfg yolov3-tiny-3cls-sm4.cfg -n=206 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --notest --nosave --cache --device 0 --cfg yolov3-tiny-3cls.cfg -n=209 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 3 --cfg yolov3-tiny-3cls.cfg -n=210 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-3cls.cfg +n=201 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 0 --cfg yolov3-tiny-3cls.cfg +n=202 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 1 --cfg yolov3-tiny-3cls-sm4.cfg +n=203 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 2 --cfg yolov3-tiny-3cls-sm4.cfg +n=204 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 3 --cfg yolov3-tiny-3cls-sm4.cfg +n=205 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 4 --cfg yolov3-tiny-3cls-sm4.cfg +n=206 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --notest --nosave --cache --device 0 --cfg yolov3-tiny-3cls.cfg +n=209 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 3 --cfg yolov3-tiny-3cls.cfg +n=210 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-3cls.cfg From 78ac3bdcfb636123575106e2533167f83cc91565 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 14 Jan 2020 17:26:22 -0800 Subject: [PATCH 0306/1185] updates --- utils/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/utils.py b/utils/utils.py index a19e594edb..5c45e1ad83 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -1015,6 +1015,7 @@ def plot_results(start=0, stop=0, bucket='', id=()): # from utils.utils import s = ['GIoU', 'Objectness', 'Classification', 'Precision', 'Recall', 'val GIoU', 'val Objectness', 'val Classification', 'mAP@0.5', 'F1'] if bucket: + os.system('rm -rf storage.googleapis.com') files = ['https://storage.googleapis.com/%s/results%g.txt' % (bucket, x) for x in id] else: files = glob.glob('results*.txt') + glob.glob('../../Downloads/results*.txt') From c6b44befde5cafe326ff0bbcf582229bd34f954e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 14 Jan 2020 22:11:09 -0800 Subject: [PATCH 0307/1185] updates --- utils/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/utils.py b/utils/utils.py index 5c45e1ad83..5647702e9d 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -1027,6 +1027,7 @@ def plot_results(start=0, stop=0, bucket='', id=()): # from utils.utils import y = results[i, x] if i in [0, 1, 2, 5, 6, 7]: y[y == 0] = np.nan # dont show zero loss values + # y /= y[0] # normalize ax[i].plot(x, y, marker='.', label=Path(f).stem) ax[i].set_title(s[i]) if i in [5, 6, 7]: # share train and val loss y axes From 01dbdc45d7e7b8a66c251993c19513891461c439 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 14 Jan 2020 22:22:24 -0800 Subject: [PATCH 0308/1185] updates --- train.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/train.py b/train.py index dbb389dae9..c754bca410 100644 --- a/train.py +++ b/train.py @@ -457,20 +457,21 @@ def train(): x = (x * w.reshape(n, 1)).sum(0) / w.sum() # new parent # Mutate - mutate_version = 2 - np.random.seed(int(time.time())) + method = 2 s = 0.2 # 20% sigma + np.random.seed(int(time.time())) g = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 0, 1, 1, 1, 1, 1, 1, 1]) # gains ng = len(g) - if mutate_version == 1: - s *= np.random.random() # sigma - v = (np.random.randn(ng) * g * s + 1) ** 2.0 # plt.hist(x.ravel(), 300) - else: + if method == 1: + v = (np.random.randn(ng) * np.random.random() * g * s + 1) ** 2.0 + elif method == 2: + v = (np.random.randn(ng) * np.random.random(ng) * g * s + 1) ** 2.0 + elif method == 3: v = np.ones(ng) while all(v == 1): # mutate untill a change occurs (prevent duplicates) r = (np.random.random(ng) < 0.1) * np.random.randn(ng) # 10% mutation probability - v = (g * s * r + 1) ** 2.0 # plt.hist(x.ravel(), 300) - for i, k in enumerate(hyp.keys()): + v = (g * s * r + 1) ** 2.0 + for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) hyp[k] = x[i + 7] * v[i] # mutate # Clip to limits From 5831d2d6bad7f8a639abf278ed6b44a41336a234 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 15 Jan 2020 09:28:58 -0800 Subject: [PATCH 0309/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index c754bca410..1dc05bf1c4 100644 --- a/train.py +++ b/train.py @@ -457,7 +457,7 @@ def train(): x = (x * w.reshape(n, 1)).sum(0) / w.sum() # new parent # Mutate - method = 2 + method = 3 s = 0.2 # 20% sigma np.random.seed(int(time.time())) g = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 0, 1, 1, 1, 1, 1, 1, 1]) # gains From 53e3d55a1e002be343d49936e92c229e1d18fa58 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 15 Jan 2020 10:22:59 -0800 Subject: [PATCH 0310/1185] updates --- detect.py | 2 +- utils/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/detect.py b/detect.py index 09bb731195..3b2d17ea50 100644 --- a/detect.py +++ b/detect.py @@ -167,7 +167,7 @@ def detect(save_img=False): parser.add_argument('--half', action='store_true', help='half precision FP16 inference') parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') parser.add_argument('--view-img', action='store_true', help='display results') - parser.add_argument('--save-txt', action='store_true', help='display results') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') parser.add_argument('--classes', nargs='+', type=int, help='filter by class') parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') opt = parser.parse_args() diff --git a/utils/utils.py b/utils/utils.py index 5647702e9d..51d4127bf5 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -830,7 +830,7 @@ def print_mutation(hyp, results, bucket=''): def apply_classifier(x, model, img, im0): # applies a second stage classifier to yolo outputs - + im0 = [im0] if isinstance(im0, np.ndarray) else im0 for i, d in enumerate(x): # per image if d is not None and len(d): d = d.clone() From 6f777e2bc5853e13fad9f6a3fd9c6732f8fc6dc0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 15 Jan 2020 11:22:06 -0800 Subject: [PATCH 0311/1185] updates --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5bd6b08811..91da5878c1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,10 +47,10 @@ COPY . /usr/src/app # t=ultralytics/yolov3:v0 && sudo docker build -t $t . && sudo docker push $t # Run -# sudo nvidia-docker run --ipc=host ultralytics/yolov3:v0 python3 detect.py +# sudo docker run --gpus all --ipc=host ultralytics/yolov3:v0 python3 detect.py # Pull and Run with local directory access -# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t +# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t # Kill all # sudo docker kill "$(sudo docker ps -q)" @@ -59,4 +59,4 @@ COPY . /usr/src/app # sudo docker kill $(sudo docker ps -a -q --filter ancestor=ultralytics/yolov3:v0) # Run bash for loop -# sudo nvidia-docker run --ipc=host ultralytics/yolov3:v0 while true; do python3 train.py --evolve; done +# sudo docker run --gpus all --ipc=host ultralytics/yolov3:v0 while true; do python3 train.py --evolve; done From 4459a9474e5da9ce3f96d09fe561e8e7ff10dca5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 15 Jan 2020 12:27:54 -0800 Subject: [PATCH 0312/1185] updates --- utils/torch_utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index d984dfca48..d615e2a8fc 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -5,8 +5,6 @@ def init_seeds(seed=0): torch.manual_seed(seed) - torch.cuda.manual_seed(seed) - torch.cuda.manual_seed_all(seed) # Remove randomness (may be slower on Tesla GPUs) # https://pytorch.org/docs/stable/notes/randomness.html if seed == 0: From 75933e93a1f5a2bfc545193032e4907494f9ab8f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 16 Jan 2020 09:47:33 -0800 Subject: [PATCH 0313/1185] updates --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 08b1bdbad3..8b6572549a 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # pip install -U -r requirements.txt numpy -opencv-python -torch >= 1.3 +opencv-python >= 4.1 +torch >= 1.4 matplotlib pycocotools tqdm From c0cde1edf0afc0bc575c644d3cd56b4a8caaf893 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 16 Jan 2020 13:25:18 -0800 Subject: [PATCH 0314/1185] updates --- utils/datasets.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/utils/datasets.py b/utils/datasets.py index bd87dd19fa..f9f5459cc0 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -215,6 +215,12 @@ def __init__(self, sources='streams.txt', img_size=416, half=False): thread.start() print('') # newline + # check for common shapes + s = np.stack([letterbox(x, new_shape=self.img_size)[0].shape for x in self.imgs], 0) # inference shapes + self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal + if not self.rect: + print('WARNING: Different stream shapes detected. For optimal performance supply similarly-shaped streams.') + def update(self, index, cap): # Read next stream frame in a daemon thread n = 0 @@ -239,7 +245,7 @@ def __next__(self): raise StopIteration # Letterbox - img = [letterbox(x, new_shape=self.img_size, interp=cv2.INTER_LINEAR)[0] for x in img0] + img = [letterbox(x, new_shape=self.img_size, auto=self.rect, interp=cv2.INTER_LINEAR)[0] for x in img0] # Stack img = np.stack(img, 0) From 1bc50ebfabaa7ac196e38be1308321fca8b4845b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 17 Jan 2020 10:49:07 -0800 Subject: [PATCH 0315/1185] updates --- utils/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 51d4127bf5..74663bb2d2 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -633,7 +633,7 @@ def get_yolo_layers(model): def print_model_biases(model): # prints the bias neurons preceding each yolo layer - print('\nModel Bias Summary:') + print('\nModel Bias Summary: %8s%18s%18s%18s' % ('layer', 'regression', 'objectness', 'classification')) multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) for l in model.yolo_layers: # print pretrained biases if multi_gpu: @@ -642,9 +642,9 @@ def print_model_biases(model): else: na = model.module_list[l].na b = model.module_list[l - 1][0].bias.view(na, -1) # bias 3x85 - print('layer %3g regression: %5.2f+/-%-5.2f ' % (l, b[:, :4].mean(), b[:, :4].std()), - 'objectness: %5.2f+/-%-5.2f ' % (b[:, 4].mean(), b[:, 4].std()), - 'classification: %5.2f+/-%-5.2f' % (b[:, 5:].mean(), b[:, 5:].std())) + print(' ' * 20 + '%8g %18s%18s%18s' % (l, '%5.2f+/-%-5.2f' % (b[:, :4].mean(), b[:, :4].std()), + '%5.2f+/-%-5.2f' % (b[:, 4].mean(), b[:, 4].std()), + '%5.2f+/-%-5.2f' % (b[:, 5:].mean(), b[:, 5:].std()))) def strip_optimizer(f='weights/last.pt'): # from utils.utils import *; strip_optimizer() From a8e13900280fe1381f38e0e2cb009b46f8b8e498 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 17 Jan 2020 10:55:30 -0800 Subject: [PATCH 0316/1185] updates --- detect.py | 2 +- models.py | 2 -- test.py | 2 +- train.py | 17 ++++++++++------- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/detect.py b/detect.py index 3b2d17ea50..2d826a4957 100644 --- a/detect.py +++ b/detect.py @@ -25,7 +25,7 @@ def detect(save_img=False): if weights.endswith('.pt'): # pytorch format model.load_state_dict(torch.load(weights, map_location=device)['model']) else: # darknet format - _ = load_darknet_weights(model, weights) + load_darknet_weights(model, weights) # Second-stage classifier classify = False diff --git a/models.py b/models.py index ae861cec6c..e93171f5bf 100755 --- a/models.py +++ b/models.py @@ -351,8 +351,6 @@ def load_darknet_weights(self, weights, cutoff=-1): conv_layer.weight.data.copy_(conv_w) ptr += num_w - return cutoff - def save_weights(self, path='model.weights', cutoff=-1): # Converts a PyTorch model to Darket format (*.pt to *.weights) diff --git a/test.py b/test.py index b09547206d..bd859580c3 100644 --- a/test.py +++ b/test.py @@ -35,7 +35,7 @@ def test(cfg, if weights.endswith('.pt'): # pytorch format model.load_state_dict(torch.load(weights, map_location=device)['model']) else: # darknet format - _ = load_darknet_weights(model, weights) + load_darknet_weights(model, weights) if torch.cuda.device_count() > 1: model = nn.DataParallel(model) diff --git a/train.py b/train.py index 1dc05bf1c4..ad723a9c05 100644 --- a/train.py +++ b/train.py @@ -84,12 +84,15 @@ def train(): model = Darknet(cfg, arc=opt.arc).to(device) # Optimizer - pg0, pg1 = [], [] # optimizer parameter groups + pg0, pg1, pg2 = [], [], [] # optimizer parameter groups for k, v in dict(model.named_parameters()).items(): - if 'Conv2d.weight' in k: - pg1 += [v] # parameter group 1 (apply weight_decay) + print(k) + if '.bias' in k: + pg2 += [v] # biases + elif 'Conv2d.weight' in k: + pg1 += [v] # apply weight_decay else: - pg0 += [v] # parameter group 0 + pg0 += [v] # all else if opt.adam: optimizer = optim.Adam(pg0, lr=hyp['lr0']) @@ -97,12 +100,12 @@ def train(): else: optimizer = optim.SGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) optimizer.add_param_group({'params': pg1, 'weight_decay': hyp['weight_decay']}) # add pg1 with weight_decay - del pg0, pg1 + optimizer.add_param_group({'params': pg2}) # add pg2 + del pg0, pg1, pg2 # https://github.com/alphadl/lookahead.pytorch # optimizer = torch_utils.Lookahead(optimizer, k=5, alpha=0.5) - cutoff = -1 # backbone reaches to cutoff layer start_epoch = 0 best_fitness = float('inf') attempt_download(weights) @@ -134,7 +137,7 @@ def train(): elif len(weights) > 0: # darknet format # possible weights are '*.weights', 'yolov3-tiny.conv.15', 'darknet53.conv.74' etc. - cutoff = load_darknet_weights(model, weights) + load_darknet_weights(model, weights) # Scheduler https://github.com/ultralytics/yolov3/issues/238 # lf = lambda x: 1 - x / epochs # linear ramp to zero From 831d2b3dcc12aa53b7012b3516c68d1582e96086 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 17 Jan 2020 11:17:18 -0800 Subject: [PATCH 0317/1185] updates --- train.py | 1 - 1 file changed, 1 deletion(-) diff --git a/train.py b/train.py index ad723a9c05..b49f40ddf0 100644 --- a/train.py +++ b/train.py @@ -86,7 +86,6 @@ def train(): # Optimizer pg0, pg1, pg2 = [], [], [] # optimizer parameter groups for k, v in dict(model.named_parameters()).items(): - print(k) if '.bias' in k: pg2 += [v] # biases elif 'Conv2d.weight' in k: From 1ba9bd746b67665ff9a813b108bc307a177143e5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 17 Jan 2020 11:17:52 -0800 Subject: [PATCH 0318/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index b49f40ddf0..58006c45aa 100644 --- a/train.py +++ b/train.py @@ -99,7 +99,7 @@ def train(): else: optimizer = optim.SGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) optimizer.add_param_group({'params': pg1, 'weight_decay': hyp['weight_decay']}) # add pg1 with weight_decay - optimizer.add_param_group({'params': pg2}) # add pg2 + optimizer.add_param_group({'params': pg2}) # add pg2 (biases) del pg0, pg1, pg2 # https://github.com/alphadl/lookahead.pytorch From cdb4680390e4140810518432dab0d8c4d37fb8d1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 17 Jan 2020 17:44:22 -0800 Subject: [PATCH 0319/1185] updates --- models.py | 2 +- utils/utils.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index e93171f5bf..12c355b390 100755 --- a/models.py +++ b/models.py @@ -195,7 +195,7 @@ def forward(self, p, img_size, var=None): io[..., :4] *= self.stride if 'default' in self.arc: # seperate obj and cls - torch.sigmoid_(io[..., 4]) + torch.sigmoid_(io[..., 4:]) elif 'BCE' in self.arc: # unified BCE (80 classes) torch.sigmoid_(io[..., 5:]) io[..., 4] = 1 diff --git a/utils/utils.py b/utils/utils.py index 74663bb2d2..0b81fceca4 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -512,6 +512,8 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height method = 'vision_batch' + nc = prediction[0].shape[1] - 5 # number of classes + multi_cls = multi_cls and (nc > 1) output = [None] * len(prediction) for image_i, pred in enumerate(prediction): # Apply conf constraint @@ -525,7 +527,6 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru continue # Compute conf - torch.sigmoid_(pred[..., 5:]) pred[..., 5:] *= pred[..., 4:5] # conf = obj_conf * cls_conf # Box (center x, center y, width, height) to (x1, y1, x2, y2) From dec2c7d9a6bc2c856f93307404be6f01e6c8cf9a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 17 Jan 2020 17:52:28 -0800 Subject: [PATCH 0320/1185] updates --- test.py | 9 ++++++--- train.py | 44 ++++++++++++++++++++++---------------------- utils/datasets.py | 5 +++-- utils/evolve.sh | 4 ++-- utils/gcp.sh | 34 +++++++++++++++++++++++++++++++--- 5 files changed, 64 insertions(+), 32 deletions(-) diff --git a/test.py b/test.py index bd859580c3..68b636b121 100644 --- a/test.py +++ b/test.py @@ -17,7 +17,8 @@ def test(cfg, iou_thres=0.5, # for nms save_json=False, model=None, - dataloader=None): + dataloader=None, + single_cls=False): # Initialize/load model and set device if model is None: device = torch_utils.select_device(opt.device, batch_size=batch_size) @@ -45,7 +46,7 @@ def test(cfg, # Configure run data = parse_data_cfg(data) - nc = int(data['classes']) # number of classes + nc = 1 if single_cls else int(data['classes']) # number of classes path = data['valid'] # path to test images names = load_classes(data['names']) # class names iouv = torch.linspace(0.5, 0.95, 10).to(device) # iou vector for mAP@0.5:0.95 @@ -216,6 +217,7 @@ def test(cfg, parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') parser.add_argument('--task', default='test', help="'test', 'study', 'benchmark'") parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') + parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') opt = parser.parse_args() opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) print(opt) @@ -229,7 +231,8 @@ def test(cfg, opt.img_size, opt.conf_thres, opt.iou_thres, - opt.save_json) + opt.save_json, + opt.single_cls) elif opt.task == 'benchmark': # mAPs at 320-608 at conf 0.5 and 0.7 diff --git a/train.py b/train.py index 58006c45aa..158cbbefb8 100644 --- a/train.py +++ b/train.py @@ -74,7 +74,7 @@ def train(): data_dict = parse_data_cfg(data) train_path = data_dict['train'] test_path = data_dict['valid'] - nc = int(data_dict['classes']) # number of classes + nc = 1 if opt.single_cls else int(data_dict['classes']) # number of classes # Remove previous results for f in glob.glob('*_batch*.jpg') + glob.glob(results_file): @@ -177,7 +177,8 @@ def train(): hyp=hyp, # augmentation hyperparameters rect=opt.rect, # rectangular training cache_labels=True, - cache_images=opt.cache_images) + cache_images=opt.cache_images, + single_cls=opt.single_cls) # Dataloader batch_size = min(batch_size, len(dataset)) @@ -194,7 +195,8 @@ def train(): hyp=hyp, rect=True, cache_labels=True, - cache_images=opt.cache_images), + cache_images=opt.cache_images, + single_cls=opt.single_cls), batch_size=batch_size * 2, num_workers=nw, pin_memory=True, @@ -202,6 +204,7 @@ def train(): # Start training nb = len(dataloader) + prebias = start_epoch == 0 model.nc = nc # attach number of classes to model model.arc = opt.arc # attach yolo architecture model.hyp = hyp # attach hyperparameters to model @@ -213,24 +216,22 @@ def train(): torch_utils.model_info(model, report='summary') # 'full' or 'summary' print('Using %g dataloader workers' % nw) print('Starting training for %g epochs...' % epochs) - for epoch in range(start_epoch - 1 if opt.prebias else start_epoch, epochs): # epoch ------------------------------ + for epoch in range(start_epoch, epochs): # epoch ------------------------------ model.train() - print(('\n' + '%10s' * 8) % ('Epoch', 'gpu_mem', 'GIoU', 'obj', 'cls', 'total', 'targets', 'img_size')) # Prebias - if opt.prebias: - if epoch < 0: # prebias - ps = 0.1, 0.9, False # prebias settings (lr=0.1, momentum=0.9, requires_grad=False) + if prebias: + if epoch < 20: # prebias + ps = 0.1, 0.9 # prebias settings (lr=0.1, momentum=0.9) else: # normal training - ps = hyp['lr0'], hyp['momentum'], True # normal training settings - opt.prebias = False + ps = hyp['lr0'], hyp['momentum'] # normal training settings + print_model_biases(model) + prebias = False - for p in optimizer.param_groups: - p['lr'] = ps[0] # learning rate - if p.get('momentum') is not None: # for SGD but not Adam - p['momentum'] = ps[1] - for name, p in model.named_parameters(): - p.requires_grad = True if name.endswith('.bias') else ps[2] + # Bias optimizer settings + optimizer.param_groups[2]['lr'] = ps[0] + if optimizer.param_groups[2].get('momentum') is not None: # for SGD but not Adam + optimizer.param_groups[2]['momentum'] = ps[1] # Update image weights (optional) if dataset.image_weights: @@ -239,6 +240,7 @@ def train(): dataset.indices = random.choices(range(dataset.n), weights=image_weights, k=dataset.n) # rand weighted idx mloss = torch.zeros(4).to(device) # mean losses + print(('\n' + '%10s' * 8) % ('Epoch', 'gpu_mem', 'GIoU', 'obj', 'cls', 'total', 'targets', 'img_size')) pbar = tqdm(enumerate(dataloader), total=nb) # progress bar for i, (imgs, targets, paths, _) in pbar: # batch ------------------------------------------------------------- ni = i + nb * epoch # number integrated batches (since train start) @@ -307,10 +309,7 @@ def train(): # Process epoch results final_epoch = epoch + 1 == epochs - if opt.prebias: - print_model_biases(model) - continue - elif not opt.notest or final_epoch: # Calculate mAP + if not opt.notest or final_epoch: # Calculate mAP is_coco = any([x in data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) and model.nc == 80 results, maps = test.test(cfg, data, @@ -320,7 +319,8 @@ def train(): conf_thres=0.001 if final_epoch else 0.1, # 0.1 for speed iou_thres=0.6 if final_epoch and is_coco else 0.5, save_json=final_epoch and is_coco, - dataloader=testloader) + dataloader=testloader, + single_cls=opt.single_cls) # Update scheduler scheduler.step() @@ -412,10 +412,10 @@ def train(): parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') parser.add_argument('--weights', type=str, default='weights/ultralytics68.pt', help='initial weights') parser.add_argument('--arc', type=str, default='default', help='yolo architecture') # defaultpw, uCE, uBCE - parser.add_argument('--prebias', action='store_true', help='pretrain model biases') parser.add_argument('--name', default='', help='renames results.txt to results_name.txt if supplied') parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1 or cpu)') parser.add_argument('--adam', action='store_true', help='use adam optimizer') + parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') parser.add_argument('--var', type=float, help='debug variable') opt = parser.parse_args() opt.weights = last if opt.resume else opt.weights diff --git a/utils/datasets.py b/utils/datasets.py index f9f5459cc0..3f8a83045a 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -263,7 +263,7 @@ def __len__(self): class LoadImagesAndLabels(Dataset): # for training/testing def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, - cache_labels=False, cache_images=False): + cache_labels=False, cache_images=False, single_cls=False): path = str(Path(path)) # os-agnostic assert os.path.isfile(path), 'File not found %s. See %s' % (path, help_url) with open(path, 'r') as f: @@ -343,7 +343,8 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels: %s' % file if np.unique(l, axis=0).shape[0] < l.shape[0]: # duplicate rows nd += 1 # print('WARNING: duplicate rows in %s' % self.label_files[i]) # duplicate rows - + if single_cls: + l[:, 0] = 0 # force dataset into single-class mode self.labels[i] = l nf += 1 # file found diff --git a/utils/evolve.sh b/utils/evolve.sh index bdc0a2c031..f1a96a5e62 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -8,8 +8,8 @@ #t=ultralytics/yolov3:v199 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 672 --epochs 10 --batch 16 --accum 4 --weights '' --arc defaultpw --device 0 --multi while true; do - python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --evolve --device $1 --cfg yolov3-tiny-3cls.cfg --cache - # python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg + # python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc default --pre --multi --bucket ult/wer --evolve --device $1 --cfg yolov3-tiny-3cls.cfg --cache + python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc default --pre --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg # python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/640ms_coco2014_10e --device $1 --multi # python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch 64 --accum 1 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/320_coco2014_27e --device $1 diff --git a/utils/gcp.sh b/utils/gcp.sh index c1c731e078..407c2e7a97 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -38,11 +38,17 @@ python3 detect.py # Test python3 test.py --save-json +# Kill All +t=ultralytics/yolov3:v206 +docker kill $(docker ps -a -q --filter ancestor=$t) +t=ultralytics/yolov3:v208 +docker kill $(docker ps -a -q --filter ancestor=$t) + # Evolve sudo -s t=ultralytics/yolov3:v206 docker kill $(docker ps -a -q --filter ancestor=$t) -for i in 6 7 +for i in 4 5 6 7 do docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i # docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/out:/usr/src/out $t bash utils/evolve.sh $i @@ -55,10 +61,10 @@ done sudo -s t=ultralytics/yolov3:v208 docker kill $(docker ps -a -q --filter ancestor=$t) -for i in 0 +for i in 0 1 do # docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i - docker pull $t && docker run --gpus all -it --ipc=host -v "$(pwd)"/out:/usr/src/out $t bash utils/evolve.sh $i + docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/out:/usr/src/out $t bash utils/evolve.sh $i # docker pull $t && nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i # docker pull $t && nvidia-docker run -d -v /mnt/disks/nvme0n1/coco:/usr/src/coco $t bash utils/evolve.sh $i sleep 180 @@ -277,6 +283,19 @@ n=211 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gp n=212 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg n=213 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg n=214 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg +n=215 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg +n=217 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc default --pre --multi --device 6 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=219 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc default --pre --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=220 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 20 --batch 8 --accum 8 --weights ultralytics68.pt --arc default --pre --multi --device 1 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=221 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 30 --batch 8 --accum 8 --weights ultralytics68.pt --arc default --pre --multi --device 2 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=222 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 40 --batch 8 --accum 8 --weights ultralytics68.pt --arc default --pre --multi --device 3 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=223 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=224 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 20 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 1 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=225 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 30 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=226 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 40 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=227 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=228 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 20 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=229 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 20 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg # sm4 n=201 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 0 --cfg yolov3-tiny-3cls.cfg @@ -287,3 +306,12 @@ n=205 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo nvidia-docker n=206 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --notest --nosave --cache --device 0 --cfg yolov3-tiny-3cls.cfg n=209 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 3 --cfg yolov3-tiny-3cls.cfg n=210 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-3cls.cfg +n=216 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-3cls.cfg +n=218 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc default --pre --multi --bucket ult/wer --name $n --nosave --cache --device 7 --cfg yolov3-tiny-3cls.cfg +n=230 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc default --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single +n=231 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc default --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-1cls.cfg --single + + +n=206 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 10 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --nosave --cache --device 0 --cfg yolov3-tiny-3cls.cfg +n=206 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 10 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --nosave --cache --device 1 --cfg yolov3-tiny-3cls.cfg + From a4b8815ed934ce295b99c348b201f35e94ffd45f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 17 Jan 2020 17:58:37 -0800 Subject: [PATCH 0321/1185] updates --- test.py | 4 ++-- train.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test.py b/test.py index 68b636b121..7f809a5c67 100644 --- a/test.py +++ b/test.py @@ -16,9 +16,9 @@ def test(cfg, conf_thres=0.001, iou_thres=0.5, # for nms save_json=False, + single_cls=False, model=None, - dataloader=None, - single_cls=False): + dataloader=None): # Initialize/load model and set device if model is None: device = torch_utils.select_device(opt.device, batch_size=batch_size) diff --git a/train.py b/train.py index 158cbbefb8..859368af37 100644 --- a/train.py +++ b/train.py @@ -319,8 +319,8 @@ def train(): conf_thres=0.001 if final_epoch else 0.1, # 0.1 for speed iou_thres=0.6 if final_epoch and is_coco else 0.5, save_json=final_epoch and is_coco, - dataloader=testloader, - single_cls=opt.single_cls) + single_cls=opt.single_cls, + dataloader=testloader) # Update scheduler scheduler.step() From bab855507a1e99e6c943292eab7f2ffd2de059b2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 17 Jan 2020 18:05:28 -0800 Subject: [PATCH 0322/1185] updates --- train.py | 2 +- utils/datasets.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/train.py b/train.py index 859368af37..195e4a6c3f 100644 --- a/train.py +++ b/train.py @@ -221,7 +221,7 @@ def train(): # Prebias if prebias: - if epoch < 20: # prebias + if epoch < 1: # prebias ps = 0.1, 0.9 # prebias settings (lr=0.1, momentum=0.9) else: # normal training ps = hyp['lr0'], hyp['momentum'] # normal training settings diff --git a/utils/datasets.py b/utils/datasets.py index 3f8a83045a..f83a17be78 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -593,10 +593,10 @@ def load_mosaic(self, index): # Augment # img4 = img4[s // 2: int(s * 1.5), s // 2:int(s * 1.5)] # center crop (WARNING, requires box pruning) img4, labels4 = random_affine(img4, labels4, - degrees=self.hyp['degrees'] * 0, - translate=self.hyp['translate'] * 0, - scale=self.hyp['scale'] * 0, - shear=self.hyp['shear'] * 0, + degrees=self.hyp['degrees'] * 1, + translate=self.hyp['translate'] * 1, + scale=self.hyp['scale'] * 1, + shear=self.hyp['shear'] * 1, border=-s // 2) # border to remove return img4, labels4 From 3bac3c63b152f187d3c184a0671e36e5d5c79e5c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 17 Jan 2020 19:42:04 -0800 Subject: [PATCH 0323/1185] updates --- test.py | 2 +- train.py | 16 ++++++++-------- utils/gcp.sh | 6 ++++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/test.py b/test.py index 7f809a5c67..96248f72ed 100644 --- a/test.py +++ b/test.py @@ -213,7 +213,7 @@ def test(cfg, parser.add_argument('--batch-size', type=int, default=32, help='size of each image batch') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') - parser.add_argument('--iou-thres', type=float, default=0.5, help='IOU threshold for NMS') + parser.add_argument('--iou-thres', type=float, default=0.6, help='IOU threshold for NMS') parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') parser.add_argument('--task', default='test', help="'test', 'study', 'benchmark'") parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') diff --git a/train.py b/train.py index 195e4a6c3f..3c113289f0 100644 --- a/train.py +++ b/train.py @@ -52,7 +52,7 @@ def train(): cfg = opt.cfg data = opt.data - img_size = opt.img_size + img_size, img_size_test = opt.img_size if len(opt.img_size) == 2 else opt.img_size * 2 # train, test sizes epochs = opt.epochs # 500200 batches at bs 64, 117263 images = 273 epochs batch_size = opt.batch_size accumulate = opt.accumulate # effective bs = batch_size * accumulate = 16 * 4 = 64 @@ -191,7 +191,7 @@ def train(): collate_fn=dataset.collate_fn) # Testloader - testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, opt.img_size, batch_size * 2, + testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, img_size_test, batch_size * 2, hyp=hyp, rect=True, cache_labels=True, @@ -221,7 +221,7 @@ def train(): # Prebias if prebias: - if epoch < 1: # prebias + if epoch < 3: # prebias ps = 0.1, 0.9 # prebias settings (lr=0.1, momentum=0.9) else: # normal training ps = hyp['lr0'], hyp['momentum'] # normal training settings @@ -314,10 +314,10 @@ def train(): results, maps = test.test(cfg, data, batch_size=batch_size * 2, - img_size=opt.img_size, + img_size=img_size_test, model=model, - conf_thres=0.001 if final_epoch else 0.1, # 0.1 for speed - iou_thres=0.6 if final_epoch and is_coco else 0.5, + conf_thres=0.001 if final_epoch and is_coco else 0.1, # 0.1 for speed + iou_thres=0.6, save_json=final_epoch and is_coco, single_cls=opt.single_cls, dataloader=testloader) @@ -402,7 +402,7 @@ def train(): parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data path') parser.add_argument('--multi-scale', action='store_true', help='adjust (67% - 150%) img_size every 10 batches') - parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') + parser.add_argument('--img-size', nargs='+', type=int, default=[416], help='train and test image-sizes') parser.add_argument('--rect', action='store_true', help='rectangular training') parser.add_argument('--resume', action='store_true', help='resume training from last.pt') parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') @@ -425,7 +425,7 @@ def train(): mixed_precision = False # scale hyp['obj'] by img_size (evolved at 320) - # hyp['obj'] *= opt.img_size / 320. + # hyp['obj'] *= opt.img_size[0] / 320. tb_writer = None if not opt.evolve: # Train normally diff --git a/utils/gcp.sh b/utils/gcp.sh index 407c2e7a97..f066df5c6a 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -308,8 +308,10 @@ n=209 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gp n=210 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-3cls.cfg n=216 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-3cls.cfg n=218 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc default --pre --multi --bucket ult/wer --name $n --nosave --cache --device 7 --cfg yolov3-tiny-3cls.cfg -n=230 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc default --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single -n=231 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc default --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-1cls.cfg --single +n=230 && t=ultralytics/athena:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single +n=231 && t=ultralytics/athena:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-1cls.cfg --single +n=232 && t=ultralytics/athena:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single +n=233 && t=ultralytics/athena:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single n=206 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 10 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --nosave --cache --device 0 --cfg yolov3-tiny-3cls.cfg From 43956d63050a43c71ca837fefaf3cb4fe81d1c13 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 17 Jan 2020 23:30:17 -0800 Subject: [PATCH 0324/1185] updates --- train.py | 4 ++-- utils/utils.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/train.py b/train.py index 3c113289f0..43a0465d87 100644 --- a/train.py +++ b/train.py @@ -221,7 +221,7 @@ def train(): # Prebias if prebias: - if epoch < 3: # prebias + if epoch < 1: # prebias ps = 0.1, 0.9 # prebias settings (lr=0.1, momentum=0.9) else: # normal training ps = hyp['lr0'], hyp['momentum'] # normal training settings @@ -278,7 +278,7 @@ def train(): pred = model(imgs) # Compute loss - loss, loss_items = compute_loss(pred, targets, model) + loss, loss_items = compute_loss(pred, targets, model, not prebias) if not torch.isfinite(loss): print('WARNING: non-finite loss, ending training ', loss_items) return results diff --git a/utils/utils.py b/utils/utils.py index 0b81fceca4..b53fa9d768 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -361,7 +361,7 @@ def forward(self, input, target): return loss -def compute_loss(p, targets, model): # predictions, targets, model +def compute_loss(p, targets, model, giou_flag=True): # predictions, targets, model ft = torch.cuda.FloatTensor if p[0].is_cuda else torch.Tensor lcls, lbox, lobj = ft([0]), ft([0]), ft([0]) tcls, tbox, indices, anchor_vec = build_targets(model, targets) @@ -399,7 +399,7 @@ def compute_loss(p, targets, model): # predictions, targets, model pbox = torch.cat((pxy, pwh), 1) # predicted box giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss - tobj[b, a, gj, gi] = giou.detach().type(tobj.dtype) + tobj[b, a, gj, gi] = giou.detach().type(tobj.dtype) if giou_flag else 1.0 if 'default' in arc and model.nc > 1: # cls loss (only if multiple classes) t = torch.zeros_like(ps[:, 5:]) # targets From 85fbb903f7bfa4c0bb22191e3555e75a1f79d89c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 18 Jan 2020 11:52:26 -0800 Subject: [PATCH 0325/1185] updates --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8b6572549a..d935ea6b92 100755 --- a/requirements.txt +++ b/requirements.txt @@ -17,6 +17,7 @@ Pillow # Conda commands (in place of pip) --------------------------------------------- # conda update -yn base -c defaults conda # conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython future -# conda install -yc conda-forge scikit-image pycocotools onnx tensorboard +# conda install -yc conda-forge scikit-image pycocotools tensorboard # conda install -yc spyder-ide spyder-line-profiler # conda install -yc pytorch pytorch torchvision +# conda install -yc conda-forge protobuf numpy && pip install onnx # https://github.com/onnx/onnx#linux-and-macos From 3d1db0b5acee444085aeec488c15f543ca26ca79 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 19 Jan 2020 11:37:12 -0800 Subject: [PATCH 0326/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 43a0465d87..0db2f89baa 100644 --- a/train.py +++ b/train.py @@ -221,7 +221,7 @@ def train(): # Prebias if prebias: - if epoch < 1: # prebias + if epoch < 3: # prebias ps = 0.1, 0.9 # prebias settings (lr=0.1, momentum=0.9) else: # normal training ps = hyp['lr0'], hyp['momentum'] # normal training settings From 723431d6c3272409559e2e7138395807583362af Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 19 Jan 2020 12:15:42 -0800 Subject: [PATCH 0327/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index b53fa9d768..21b42e765b 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -513,7 +513,7 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru method = 'vision_batch' nc = prediction[0].shape[1] - 5 # number of classes - multi_cls = multi_cls and (nc > 1) + multi_cls = multi_cls and (nc > 1) # allow multiple classes per anchor output = [None] * len(prediction) for image_i, pred in enumerate(prediction): # Apply conf constraint From 51b5b3288f4267237b35ae1749c91bc9778c6a30 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 19 Jan 2020 14:59:07 -0800 Subject: [PATCH 0328/1185] updates --- train.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 0db2f89baa..433880789a 100644 --- a/train.py +++ b/train.py @@ -20,7 +20,7 @@ best = wdir + 'best.pt' results_file = 'results.txt' -# Hyperparameters (results68: 59.2 mAP@0.5 yolov3-spp-416) https://github.com/ultralytics/yolov3/issues/310 +# Hyperparameters (results68: 59.9 mAP@0.5 yolov3-spp-416) https://github.com/ultralytics/yolov3/issues/310 hyp = {'giou': 3.54, # giou loss gain 'cls': 37.4, # cls loss gain @@ -28,7 +28,7 @@ 'obj': 49.5, # obj loss gain (*=img_size/320 if img_size != 320) 'obj_pw': 1.0, # obj BCELoss positive_weight 'iou_t': 0.225, # iou training threshold - 'lr0': 0.00579, # initial learning rate (SGD=1E-3, Adam=9E-5) + 'lr0': 0.00579, # initial learning rate (SGD=5E-3, Adam=5E-4) 'lrf': -4., # final LambdaLR learning rate = lr0 * (10 ** lrf) 'momentum': 0.937, # SGD momentum 'weight_decay': 0.000484, # optimizer weight decay @@ -94,6 +94,7 @@ def train(): pg0 += [v] # all else if opt.adam: + hyp['lr0'] *= 0.1 # reduce lr (i.e. SGD=5E-3, Adam=5E-4) optimizer = optim.Adam(pg0, lr=hyp['lr0']) # optimizer = AdaBound(pg0, lr=hyp['lr0'], final_lr=0.1) else: From abbf9fa2d400a116479dbbc472b4c3f3efbb53f4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 19 Jan 2020 15:37:56 -0800 Subject: [PATCH 0329/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 433880789a..03b09f6216 100644 --- a/train.py +++ b/train.py @@ -471,7 +471,7 @@ def train(): v = (np.random.randn(ng) * np.random.random(ng) * g * s + 1) ** 2.0 elif method == 3: v = np.ones(ng) - while all(v == 1): # mutate untill a change occurs (prevent duplicates) + while all(v == 1): # mutate until a change occurs (prevent duplicates) r = (np.random.random(ng) < 0.1) * np.random.randn(ng) # 10% mutation probability v = (g * s * r + 1) ** 2.0 for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) From 19f75f986dc30236197c93eca82864731a6529d3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 19 Jan 2020 16:54:49 -0800 Subject: [PATCH 0330/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 03b09f6216..ba1ed5a0cb 100644 --- a/train.py +++ b/train.py @@ -463,7 +463,7 @@ def train(): method = 3 s = 0.2 # 20% sigma np.random.seed(int(time.time())) - g = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 0, 1, 1, 1, 1, 1, 1, 1]) # gains + g = np.array([0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) # gains ng = len(g) if method == 1: v = (np.random.randn(ng) * np.random.random() * g * s + 1) ** 2.0 From c91ffee8524bbc639aa343bfc29856a806d5174b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 19 Jan 2020 16:55:29 -0800 Subject: [PATCH 0331/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index ba1ed5a0cb..e9987474f4 100644 --- a/train.py +++ b/train.py @@ -94,7 +94,7 @@ def train(): pg0 += [v] # all else if opt.adam: - hyp['lr0'] *= 0.1 # reduce lr (i.e. SGD=5E-3, Adam=5E-4) + # hyp['lr0'] *= 0.1 # reduce lr (i.e. SGD=5E-3, Adam=5E-4) optimizer = optim.Adam(pg0, lr=hyp['lr0']) # optimizer = AdaBound(pg0, lr=hyp['lr0'], final_lr=0.1) else: From d3738f53302ff98229294b00a2cc5ec8d6a76df1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 19 Jan 2020 16:56:32 -0800 Subject: [PATCH 0332/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index e9987474f4..03fd0904e6 100644 --- a/train.py +++ b/train.py @@ -463,7 +463,7 @@ def train(): method = 3 s = 0.2 # 20% sigma np.random.seed(int(time.time())) - g = np.array([0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) # gains + g = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 0, 1, 1, 1, 1, 1, 1, 1]) # gains ng = len(g) if method == 1: v = (np.random.randn(ng) * np.random.random() * g * s + 1) ** 2.0 From 20e381edb422b5217a044b9ac14b1113407e1ec1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 20 Jan 2020 22:43:37 -0800 Subject: [PATCH 0333/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 03fd0904e6..73b08ac4a7 100644 --- a/train.py +++ b/train.py @@ -461,7 +461,7 @@ def train(): # Mutate method = 3 - s = 0.2 # 20% sigma + s = 0.3 # 20% sigma np.random.seed(int(time.time())) g = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 0, 1, 1, 1, 1, 1, 1, 1]) # gains ng = len(g) From 6ccf19038de2bb6bef9b69ce5fa1fa180ec7e2c9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 21 Jan 2020 16:18:24 -0800 Subject: [PATCH 0334/1185] updates --- train.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 73b08ac4a7..2249c45a7d 100644 --- a/train.py +++ b/train.py @@ -365,8 +365,8 @@ def train(): torch.save(chkpt, best) # Save backup every 10 epochs (optional) - if epoch > 0 and epoch % 10 == 0: - torch.save(chkpt, wdir + 'backup%g.pt' % epoch) + # if epoch > 0 and epoch % 10 == 0: + # torch.save(chkpt, wdir + 'backup%g.pt' % epoch) # Delete checkpoint del chkpt @@ -384,7 +384,8 @@ def train(): # save to cloud if opt.bucket: - os.system('gsutil cp %s %s gs://%s' % (fresults, wdir + flast, opt.bucket)) + os.system('gsutil cp %s gs://%s/results' % (fresults, opt.bucket)) + os.system('gsutil cp %s gs://%s/weights' % (wdir + flast, opt.bucket)) if not opt.evolve: plot_results() # save as results.png From 5d73b190b053e8c3b87efb7fb1adc48496a04d01 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 21 Jan 2020 17:23:35 -0800 Subject: [PATCH 0335/1185] updates --- models.py | 8 ++------ train.py | 6 +----- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/models.py b/models.py index 12c355b390..eefa5b9f05 100755 --- a/models.py +++ b/models.py @@ -81,17 +81,13 @@ def create_modules(module_defs, img_size, arc): # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) try: - if arc == 'defaultpw' or arc == 'Fdefaultpw': # default with positive weights + if arc == 'default' or arc == 'Fdefault': # default b = [-5.0, -5.0] # obj, cls - elif arc == 'default': # default no pw (40 cls, 80 obj) - b = [-5.0, -5.0] elif arc == 'uBCE': # unified BCE (80 classes) b = [0, -9.0] elif arc == 'uCE': # unified CE (1 background + 80 classes) b = [10, -0.1] - elif arc == 'Fdefault': # Focal default no pw (28 cls, 21 obj, no pw) - b = [-2.1, -1.8] - elif arc == 'uFBCE' or arc == 'uFBCEpw': # unified FocalBCE (5120 obj, 80 classes) + elif arc == 'uFBCE': # unified FocalBCE (5120 obj, 80 classes) b = [0, -6.5] elif arc == 'uFCE': # unified FocalCE (64 cls, 1 background + 80 classes) b = [7.7, -1.1] diff --git a/train.py b/train.py index 2249c45a7d..a9b7f185d8 100644 --- a/train.py +++ b/train.py @@ -58,10 +58,6 @@ def train(): accumulate = opt.accumulate # effective bs = batch_size * accumulate = 16 * 4 = 64 weights = opt.weights # initial training weights - if 'pw' not in opt.arc: # remove BCELoss positive weights - hyp['cls_pw'] = 1. - hyp['obj_pw'] = 1. - # Initialize init_seeds() if opt.multi_scale: @@ -413,7 +409,7 @@ def train(): parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') parser.add_argument('--weights', type=str, default='weights/ultralytics68.pt', help='initial weights') - parser.add_argument('--arc', type=str, default='default', help='yolo architecture') # defaultpw, uCE, uBCE + parser.add_argument('--arc', type=str, default='default', help='yolo architecture') # default, uCE, uBCE parser.add_argument('--name', default='', help='renames results.txt to results_name.txt if supplied') parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1 or cpu)') parser.add_argument('--adam', action='store_true', help='use adam optimizer') From b9c2386ff0588a1b01aa633df8f9f4c821569a80 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 21 Jan 2020 19:46:12 -0800 Subject: [PATCH 0336/1185] updates --- utils/evolve.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/utils/evolve.sh b/utils/evolve.sh index f1a96a5e62..f0ad5b8171 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -8,9 +8,10 @@ #t=ultralytics/yolov3:v199 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 672 --epochs 10 --batch 16 --accum 4 --weights '' --arc defaultpw --device 0 --multi while true; do - # python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc default --pre --multi --bucket ult/wer --evolve --device $1 --cfg yolov3-tiny-3cls.cfg --cache - python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc default --pre --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg + # python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --evolve --cache --device $1 --cfg yolov3-tiny-1cls.cfg --single --adam + # python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg - # python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/640ms_coco2014_10e --device $1 --multi - # python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch 64 --accum 1 --evolve --weights '' --arc defaultpw --pre --bucket yolov4/320_coco2014_27e --device $1 + # python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --evolve --weights '' --bucket yolov4/640ms_coco2014_10e --device $1 --multi + # python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch 64 --accum 1 --evolve --weights '' --bucket yolov4/320_coco2014_27e --device $1 + python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 64 --accum 1 --evolve --weights '' --bucket ult/coco --device $1 --cache done From 6ba6181534f28e426423fc6d904efd333f5d22d4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 21 Jan 2020 19:47:48 -0800 Subject: [PATCH 0337/1185] updates --- utils/evolve.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/utils/evolve.sh b/utils/evolve.sh index f0ad5b8171..8174ecef41 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -1,11 +1,9 @@ #!/bin/bash -#for i in 1 2 3 4 5 6 7 +#for i in 0 1 2 3 #do # t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t utils/evolve.sh $i # sleep 30 -# done -# -#t=ultralytics/yolov3:v199 && sudo docker pull $t && sudo nvidia-docker run -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 672 --epochs 10 --batch 16 --accum 4 --weights '' --arc defaultpw --device 0 --multi +#done while true; do # python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --evolve --cache --device $1 --cfg yolov3-tiny-1cls.cfg --single --adam From 578e7f9500bb94d36e5a7d72b2402d6933189969 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 21 Jan 2020 23:18:34 -0800 Subject: [PATCH 0338/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index a9b7f185d8..3c43f0d7c9 100644 --- a/train.py +++ b/train.py @@ -326,7 +326,7 @@ def train(): with open(results_file, 'a') as f: f.write(s + '%10.3g' * 7 % results + '\n') # P, R, mAP, F1, test_losses=(GIoU, obj, cls) if len(opt.name) and opt.bucket: - os.system('gsutil cp results.txt gs://%s/results%s.txt' % (opt.bucket, opt.name)) + os.system('gsutil cp results.txt gs://%s/results/results%s.txt' % (opt.bucket, opt.name)) # Write Tensorboard results if tb_writer: From dc1f0a0d4f1aa5c09aa179e7cf4c201197dd9814 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Jan 2020 10:53:36 -0800 Subject: [PATCH 0339/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 21b42e765b..b10b815cf0 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -866,7 +866,7 @@ def apply_classifier(x, model, img, im0): def fitness(x): # Returns fitness (for use with results.txt or evolve.txt) - w = [0.0, 0.0, 0.8, 0.2] # weights for [P, R, mAP, F1]@0.5 or [P, R, mAP@0.5:0.95, mAP@0.5] + w = [0.01, 0.01, 0.78, 0.20] # weights for [P, R, mAP, F1]@0.5 or [P, R, mAP@0.5:0.95, mAP@0.5] return (x[:, :4] * w).sum(1) From c7bf7f3d60e00392dc0071070d782fedb12523c5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Jan 2020 10:55:39 -0800 Subject: [PATCH 0340/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index b10b815cf0..b8e41df2d4 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -866,7 +866,7 @@ def apply_classifier(x, model, img, im0): def fitness(x): # Returns fitness (for use with results.txt or evolve.txt) - w = [0.01, 0.01, 0.78, 0.20] # weights for [P, R, mAP, F1]@0.5 or [P, R, mAP@0.5:0.95, mAP@0.5] + w = [0.01, 0.01, 0.75, 0.23] # weights for [P, R, mAP, F1]@0.5 or [P, R, mAP@0.5:0.95, mAP@0.5] return (x[:, :4] * w).sum(1) From f18913736b058221668a3538f54b87a1ece4bb96 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Jan 2020 11:06:52 -0800 Subject: [PATCH 0341/1185] updates --- train.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/train.py b/train.py index 3c43f0d7c9..4535c0d5c5 100644 --- a/train.py +++ b/train.py @@ -446,13 +446,13 @@ def train(): for _ in range(1): # generations to evolve if os.path.exists('evolve.txt'): # if evolve.txt exists: select best hyps and mutate # Select parent(s) - x = np.loadtxt('evolve.txt', ndmin=2) parent = 'single' # parent selection method: 'single' or 'weighted' + x = np.loadtxt('evolve.txt', ndmin=2) + n = min(3, len(x)) # number of previous results to consider + x = x[np.argsort(-fitness(x))][:n] # top n mutations if parent == 'single' or len(x) == 1: - x = x[fitness(x).argmax()] + x = x[random.randint(0, n - 1)] # select one of the top n elif parent == 'weighted': # weighted combination - n = min(10, len(x)) # number to merge - x = x[np.argsort(-fitness(x))][:n] # top n mutations w = fitness(x) - fitness(x).min() # weights x = (x * w.reshape(n, 1)).sum(0) / w.sum() # new parent From 3de61b1fa597fc01b692316fa6c277b9ea484320 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Jan 2020 11:08:03 -0800 Subject: [PATCH 0342/1185] updates --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 4535c0d5c5..97bbc773e8 100644 --- a/train.py +++ b/train.py @@ -452,9 +452,9 @@ def train(): x = x[np.argsort(-fitness(x))][:n] # top n mutations if parent == 'single' or len(x) == 1: x = x[random.randint(0, n - 1)] # select one of the top n - elif parent == 'weighted': # weighted combination + elif parent == 'weighted': w = fitness(x) - fitness(x).min() # weights - x = (x * w.reshape(n, 1)).sum(0) / w.sum() # new parent + x = (x * w.reshape(n, 1)).sum(0) / w.sum() # select weighted combination # Mutate method = 3 From e6ec7c041c3f03ba9d7165eeda699c95e4bcc913 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Jan 2020 11:23:16 -0800 Subject: [PATCH 0343/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 97bbc773e8..be92c51472 100644 --- a/train.py +++ b/train.py @@ -448,7 +448,7 @@ def train(): # Select parent(s) parent = 'single' # parent selection method: 'single' or 'weighted' x = np.loadtxt('evolve.txt', ndmin=2) - n = min(3, len(x)) # number of previous results to consider + n = min(5, len(x)) # number of previous results to consider x = x[np.argsort(-fitness(x))][:n] # top n mutations if parent == 'single' or len(x) == 1: x = x[random.randint(0, n - 1)] # select one of the top n From 9bb51aaf8ca585b90c3f877972a39eb1e0f3821f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Jan 2020 18:17:08 -0800 Subject: [PATCH 0344/1185] updates --- train.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/train.py b/train.py index be92c51472..ae4b3515cc 100644 --- a/train.py +++ b/train.py @@ -448,13 +448,14 @@ def train(): # Select parent(s) parent = 'single' # parent selection method: 'single' or 'weighted' x = np.loadtxt('evolve.txt', ndmin=2) - n = min(5, len(x)) # number of previous results to consider + n = min(8, len(x)) # number of previous results to consider x = x[np.argsort(-fitness(x))][:n] # top n mutations + w = fitness(x) - fitness(x).min() # weights if parent == 'single' or len(x) == 1: - x = x[random.randint(0, n - 1)] # select one of the top n + # x = x[random.randint(0, n - 1)] # random selection + x = x[random.choices(range(n), weights=w)[0]] # weighted selection elif parent == 'weighted': - w = fitness(x) - fitness(x).min() # weights - x = (x * w.reshape(n, 1)).sum(0) / w.sum() # select weighted combination + x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination # Mutate method = 3 From 52041cffb9e784bf8e59fc0cc42f1dae78f974e5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Jan 2020 18:19:42 -0800 Subject: [PATCH 0345/1185] updates --- utils/evolve.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/evolve.sh b/utils/evolve.sh index 8174ecef41..1c420f5e8b 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -7,9 +7,9 @@ while true; do # python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --evolve --cache --device $1 --cfg yolov3-tiny-1cls.cfg --single --adam - # python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg + python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg --adam # python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --evolve --weights '' --bucket yolov4/640ms_coco2014_10e --device $1 --multi # python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch 64 --accum 1 --evolve --weights '' --bucket yolov4/320_coco2014_27e --device $1 - python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 64 --accum 1 --evolve --weights '' --bucket ult/coco --device $1 --cache + # python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 64 --accum 1 --evolve --weights '' --bucket ult/coco --device $1 --cache --cfg yolov3.cfg done From ee4f7a324dec18a5beafa4b88f0a4c4f5c79d040 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 23 Jan 2020 12:24:52 -0800 Subject: [PATCH 0346/1185] updates --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d935ea6b92..a468438941 100755 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ torch >= 1.4 matplotlib pycocotools tqdm -Pillow +pillow # Nvidia Apex (optional) for mixed precision training -------------------------- # git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex From 07c8a03aa076856c6994f971ac9ec975e8b7aa08 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 23 Jan 2020 13:52:17 -0800 Subject: [PATCH 0347/1185] updates --- models.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/models.py b/models.py index eefa5b9f05..4be680eea7 100755 --- a/models.py +++ b/models.py @@ -224,6 +224,9 @@ def forward(self, x, var=None): img_size = x.shape[-2:] layer_outputs = [] output = [] + verbose = False + if verbose: + print('0', x.shape) for i, (mdef, module) in enumerate(zip(self.module_defs, self.module_list)): mtype = mdef['type'] @@ -241,10 +244,15 @@ def forward(self, x, var=None): x = torch.cat([layer_outputs[i] for i in layers], 1) # print(''), [print(layer_outputs[i].shape) for i in layers], print(x.shape) elif mtype == 'shortcut': - x = x + layer_outputs[int(mdef['from'])] + j = int(mdef['from']) + if verbose: + print('shortcut adding layer %g-%s to %g-%s' % (j, layer_outputs[j].shape, i - 1, x.shape)) + x = x + layer_outputs[j] elif mtype == 'yolo': output.append(module(x, img_size)) layer_outputs.append(x if i in self.routs else []) + if verbose: + print(i, x.shape) if self.training: return output From d498193456a6676acbc383525b9dc30a23dddbbc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 23 Jan 2020 15:15:53 -0800 Subject: [PATCH 0348/1185] updates --- models.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/models.py b/models.py index 4be680eea7..ee7f7c47f3 100755 --- a/models.py +++ b/models.py @@ -222,8 +222,7 @@ def __init__(self, cfg, img_size=(416, 416), arc='default'): def forward(self, x, var=None): img_size = x.shape[-2:] - layer_outputs = [] - output = [] + output, layer_outputs = [], [] verbose = False if verbose: print('0', x.shape) From 629b1b237a000686939f984478ce1b776c32d987 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 23 Jan 2020 16:36:53 -0800 Subject: [PATCH 0349/1185] updates --- cfg/yolov3-tiny3-1cls.cfg | 227 ++++++++++++++++++++++++++++++++++++++ cfg/yolov3-tiny3.cfg | 227 ++++++++++++++++++++++++++++++++++++++ utils/evolve.sh | 4 +- 3 files changed, 456 insertions(+), 2 deletions(-) create mode 100644 cfg/yolov3-tiny3-1cls.cfg create mode 100644 cfg/yolov3-tiny3.cfg diff --git a/cfg/yolov3-tiny3-1cls.cfg b/cfg/yolov3-tiny3-1cls.cfg new file mode 100644 index 0000000000..bd5fd0baba --- /dev/null +++ b/cfg/yolov3-tiny3-1cls.cfg @@ -0,0 +1,227 @@ +[net] +# Testing +# batch=1 +# subdivisions=1 +# Training +batch=64 +subdivisions=16 +width=608 +height=608 +channels=3 +momentum=0.9 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.001 +burn_in=1000 +max_batches = 200000 +policy=steps +steps=180000,190000 +scales=.1,.1 + + +[convolutional] +batch_normalize=1 +filters=16 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=1 + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=1 +pad=1 +activation=leaky + +########### + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=18 +activation=linear + + + +[yolo] +mask = 6,7,8 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=1 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 8 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=18 +activation=linear + +[yolo] +mask = 3,4,5 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=1 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + + + +[route] +layers = -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 6 + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=18 +activation=linear + +[yolo] +mask = 0,1,2 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=1 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 diff --git a/cfg/yolov3-tiny3.cfg b/cfg/yolov3-tiny3.cfg new file mode 100644 index 0000000000..85d6787f6c --- /dev/null +++ b/cfg/yolov3-tiny3.cfg @@ -0,0 +1,227 @@ +[net] +# Testing +# batch=1 +# subdivisions=1 +# Training +batch=64 +subdivisions=16 +width=608 +height=608 +channels=3 +momentum=0.9 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.001 +burn_in=1000 +max_batches = 200000 +policy=steps +steps=180000,190000 +scales=.1,.1 + + +[convolutional] +batch_normalize=1 +filters=16 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=1 + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=1 +pad=1 +activation=leaky + +########### + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + + +[yolo] +mask = 6,7,8 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 8 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 3,4,5 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + + + +[route] +layers = -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 6 + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 0,1,2 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 diff --git a/utils/evolve.sh b/utils/evolve.sh index 1c420f5e8b..3d022303e6 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -6,8 +6,8 @@ #done while true; do - # python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --evolve --cache --device $1 --cfg yolov3-tiny-1cls.cfg --single --adam - python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg --adam + python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --evolve --cache --device $1 --cfg yolov3-tiny3-1cls.cfg --single --adam + # python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg --adam # python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --evolve --weights '' --bucket yolov4/640ms_coco2014_10e --device $1 --multi # python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch 64 --accum 1 --evolve --weights '' --bucket yolov4/320_coco2014_27e --device $1 From dd3cf27ececafc17136cce82c8dd502ce4dae6d0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 23 Jan 2020 17:26:05 -0800 Subject: [PATCH 0350/1185] updates --- utils/evolve.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/evolve.sh b/utils/evolve.sh index 3d022303e6..01790b6932 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -6,7 +6,7 @@ #done while true; do - python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --evolve --cache --device $1 --cfg yolov3-tiny3-1cls.cfg --single --adam + python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --evolve --cache --device $1 --cfg yolov3-tiny3-1cls.cfg --single --adam # python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg --adam # python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --evolve --weights '' --bucket yolov4/640ms_coco2014_10e --device $1 --multi From cb0f4bbfe7ef5b7bef1c3c224a40f25628eb6640 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 27 Jan 2020 16:08:20 -0500 Subject: [PATCH 0351/1185] updates --- utils/evolve.sh | 8 ++--- utils/gcp.sh | 81 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 66 insertions(+), 23 deletions(-) diff --git a/utils/evolve.sh b/utils/evolve.sh index 01790b6932..f69e81e2f0 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -6,10 +6,8 @@ #done while true; do - python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --evolve --cache --device $1 --cfg yolov3-tiny3-1cls.cfg --single --adam - # python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg --adam + # python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --evolve --cache --device $1 --cfg yolov3-tiny3-1cls.cfg --single --adam + # python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg - # python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --evolve --weights '' --bucket yolov4/640ms_coco2014_10e --device $1 --multi - # python3 train.py --data coco2014.data --img-size 320 --epochs 27 --batch 64 --accum 1 --evolve --weights '' --bucket yolov4/320_coco2014_27e --device $1 - # python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 64 --accum 1 --evolve --weights '' --bucket ult/coco --device $1 --cache --cfg yolov3.cfg + python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --evolve --weights '' --bucket ult/coco --device $1 --cfg yolov3-spp.cfg --multi done diff --git a/utils/gcp.sh b/utils/gcp.sh index f066df5c6a..6a6f69f851 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -6,8 +6,7 @@ git clone https://github.com/ultralytics/yolov3 sudo apt-get install zip #git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex sudo conda install -yc conda-forge scikit-image pycocotools -# python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('193Zp_ye-3qXMonR1nZj3YyxMtQkMy50k','coco2014.zip')" -python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco2014.zip')" +python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('193Zp_ye-3qXMonR1nZj3YyxMtQkMy50k','coco2014.zip')" sudo shutdown # Re-clone @@ -39,35 +38,39 @@ python3 detect.py python3 test.py --save-json # Kill All -t=ultralytics/yolov3:v206 +t=ultralytics/yolov3:v240 docker kill $(docker ps -a -q --filter ancestor=$t) t=ultralytics/yolov3:v208 docker kill $(docker ps -a -q --filter ancestor=$t) -# Evolve +# Evolve wer sudo -s t=ultralytics/yolov3:v206 docker kill $(docker ps -a -q --filter ancestor=$t) -for i in 4 5 6 7 +for i in 0 1 2 3 0 1 2 3 do - docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i - # docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/out:/usr/src/out $t bash utils/evolve.sh $i - # docker pull $t && nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i - # docker pull $t && nvidia-docker run -d -v /mnt/disks/nvme0n1/coco:/usr/src/coco $t bash utils/evolve.sh $i + docker pull $t && docker run -d --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i sleep 180 done -# Evolve +# Evolve athena sudo -s t=ultralytics/yolov3:v208 docker kill $(docker ps -a -q --filter ancestor=$t) for i in 0 1 do - # docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/out:/usr/src/out $t bash utils/evolve.sh $i - # docker pull $t && nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i - # docker pull $t && nvidia-docker run -d -v /mnt/disks/nvme0n1/coco:/usr/src/coco $t bash utils/evolve.sh $i - sleep 180 + sleep 120 +done + +# Evolve coco +sudo -s +t=ultralytics/yolov3:v256 +docker kill $(docker ps -a -q --filter ancestor=$t) +for i in 0 +do + docker pull $t && docker run --gpus all -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i + sleep 120 done # Git pull @@ -274,6 +277,7 @@ n=196 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker r n=197 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n n=198 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n + # knife n=199 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 0 n=200 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 6 @@ -296,6 +300,23 @@ n=226 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d n=227 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg n=228 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 20 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg n=229 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 20 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=240 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 0 +n=241 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 1 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 1 +n=242 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 2 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 3 +n=243 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 3 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 5 +n=244 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 4 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 7 +n=245 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights '' --arc defaultpw --multi --device 5 --bucket ult/athena --name $n --nosave --cfg yolov3-1cls.cfg +n=246 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights '' --arc defaultpw --multi --device 6 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=247 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights '' --arc defaultpw --multi --device 7 --bucket ult/athena --name $n --nosave --cfg yolov3-spp3-1cls.cfg +n=248 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights darknet53.conv.74 --arc defaultpw --multi --device 5 --bucket ult/athena --name $n --nosave --cfg yolov3-1cls.cfg +n=249 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights darknet53.conv.74 --arc defaultpw --multi --device 6 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=250 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights darknet53.conv.74 --arc defaultpw --multi --device 7 --bucket ult/athena --name $n --nosave --cfg yolov3-spp3-1cls.cfg +n=251 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 3 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 9 +n=252 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 4 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 100 +n=253 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 60 --batch 8 --accum 8 --weights darknet53.conv.74 --arc defaultpw --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-1cls.cfg +n=254 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 60 --batch 8 --accum 8 --weights darknet53.conv.74 --arc defaultpw --multi --device 1 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=255 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 60 --batch 8 --accum 8 --weights darknet53.conv.74 --arc defaultpw --multi --device 2 --bucket ult/athena --name $n --nosave --cfg yolov3-spp3-1cls.cfg + # sm4 n=201 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 0 --cfg yolov3-tiny-3cls.cfg @@ -310,10 +331,34 @@ n=216 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gp n=218 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc default --pre --multi --bucket ult/wer --name $n --nosave --cache --device 7 --cfg yolov3-tiny-3cls.cfg n=230 && t=ultralytics/athena:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single n=231 && t=ultralytics/athena:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-1cls.cfg --single -n=232 && t=ultralytics/athena:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single -n=233 && t=ultralytics/athena:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single +n=232 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single +n=233 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single +n=234 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 416 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single +n=235 && t=ultralytics/yolov3:v206 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi 1.2 --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single +n=236 && t=ultralytics/yolov3:v206 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi 1.4 --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single +n=237 && t=ultralytics/yolov3:v206 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi 1.6 --bucket ult/wer --name $n --nosave --device 1 --cfg yolov3-tiny-1cls.cfg --single +n=238 && t=ultralytics/yolov3:v206 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi 1.8 --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single +n=239 && t=ultralytics/yolov3:v206 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi 2.0 --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single +n=256 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 500 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 6 --cfg yolov3-tiny-1cls.cfg --single +n=257 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 500 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 7 --cfg yolov3-tiny-1cls.cfg --single --adam + + +#coco +n=3 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 30 --batch 32 --accum 2 --weights '' --device 0 --cfg yolov3.cfg --nosave --bucket ult/coco --name $n +n=4 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 30 --batch 32 --accum 2 --weights '' --device 1 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n +n=5 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 30 --batch 32 --accum 2 --weights '' --device 2 --cfg yolov3-spp3.cfg --nosave --bucket ult/coco --name $n +sudo shutdown + +# sm4 +n=18 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single --adam +n=19 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-3l-1cls.cfg --single --adam +n=20 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --name $n --nosave --cache --device 2 --cfg yolov3-tiny-prnc-1cls.cfg --single --adam +n=21 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --name $n --nosave --cache --device 3 --cfg yolov3-tiny-prn-1cls.cfg --single --adam +n=22 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights '' --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-3l-1cls.cfg --single --adam +n=23 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights '' --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tinyr-3l-1cls.cfg --single --adam +n=24 && t=ultralytics/wer:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights '' --multi --bucket ult/wer --name $n --nosave --cache --device 3 --cfg yolov3-tiny-3l-1cls.cfg --single --adam +n=25 && t=ultralytics/wer:v25 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 2 --cfg yolov3-tiny3-1cls.cfg --single --adam +n=26 && t=ultralytics/wer:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny3-1cls.cfg --single --adam -n=206 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 10 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --nosave --cache --device 0 --cfg yolov3-tiny-3cls.cfg -n=206 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 10 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --nosave --cache --device 1 --cfg yolov3-tiny-3cls.cfg From 72680a599282462b40e3c9a748dd939241b34403 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 27 Jan 2020 16:52:40 -0500 Subject: [PATCH 0352/1185] updates --- train.py | 2 +- utils/utils.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index ae4b3515cc..59240cca3f 100644 --- a/train.py +++ b/train.py @@ -459,7 +459,7 @@ def train(): # Mutate method = 3 - s = 0.3 # 20% sigma + s = 0.3 # 30% sigma np.random.seed(int(time.time())) g = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 0, 1, 1, 1, 1, 1, 1, 1]) # gains ng = len(g) diff --git a/utils/utils.py b/utils/utils.py index b8e41df2d4..e7ce39e002 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -798,9 +798,10 @@ def fitness(thr, wh, k): # mutation fitness # Evolve wh = torch.Tensor(wh) - f, ng = fitness(thr, wh, k), 1000 # fitness, generations + f, ng = fitness(thr, wh, k), 1000 # fitness, mutation probability, generations for _ in tqdm(range(ng), desc='Evolving anchors'): - kg = (k.copy() * (1 + np.random.random() * np.random.randn(*k.shape) * 0.30)).clip(min=2.0) + v = ((np.random.random(n) < 0.1) * np.random.randn(n) * 0.3 + 1) ** 2.0 # 0.1 mutation probability, 0.3 sigma + kg = (k.copy() * v).clip(min=2.0) fg = fitness(thr, wh, kg) if fg > f: f, k = fg, kg.copy() From 19616781772bc45f3d085201ca1585ddf9cd9ddc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 27 Jan 2020 17:03:27 -0500 Subject: [PATCH 0353/1185] updates --- models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/models.py b/models.py index ee7f7c47f3..cf5435b502 100755 --- a/models.py +++ b/models.py @@ -233,6 +233,8 @@ def forward(self, x, var=None): x = module(x) elif mtype == 'route': layers = [int(x) for x in mdef['layers'].split(',')] + if verbose: + print('route concatenating %s' % ([layer_outputs[i].shape for i in layers])) if len(layers) == 1: x = layer_outputs[layers[0]] else: From 5a09c0e6afc141cf81e7959540a67569da25c1eb Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 27 Jan 2020 17:41:07 -0500 Subject: [PATCH 0354/1185] updates --- utils/utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index e7ce39e002..c83ebb07bd 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -798,9 +798,11 @@ def fitness(thr, wh, k): # mutation fitness # Evolve wh = torch.Tensor(wh) - f, ng = fitness(thr, wh, k), 1000 # fitness, mutation probability, generations + f, sh, ng, mp, s = fitness(thr, wh, k), k.shape, 1000, 0.1, 0.3 # fitness, generations, mutation probability, sigma for _ in tqdm(range(ng), desc='Evolving anchors'): - v = ((np.random.random(n) < 0.1) * np.random.randn(n) * 0.3 + 1) ** 2.0 # 0.1 mutation probability, 0.3 sigma + v = np.ones(sh) + while (v == 1).all(): # mutate until a change occurs (prevent duplicates) + v = ((np.random.random(sh) < mp) * np.random.randn(*sh) * s + 1) ** 2.0 kg = (k.copy() * v).clip(min=2.0) fg = fitness(thr, wh, kg) if fg > f: From 639fa308578d6927c403d633716d214daf9bf635 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Jan 2020 10:29:37 -0800 Subject: [PATCH 0355/1185] updates --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 91da5878c1..7aebe10af7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch -FROM nvcr.io/nvidia/pytorch:19.12-py3 +FROM nvcr.io/nvidia/pytorch:20.01-py3 # Install dependencies (pip or conda) RUN pip install -U gsutil From 4e7d1053cfe4a8e28534d84cd3c1165d03b20e3e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Jan 2020 10:30:13 -0800 Subject: [PATCH 0356/1185] updates --- train.py | 11 ++++++----- utils/evolve.sh | 6 ++++++ utils/gcp.sh | 31 +++++++++++++++++++++---------- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/train.py b/train.py index 59240cca3f..cea08aa536 100644 --- a/train.py +++ b/train.py @@ -103,7 +103,7 @@ def train(): # optimizer = torch_utils.Lookahead(optimizer, k=5, alpha=0.5) start_epoch = 0 - best_fitness = float('inf') + best_fitness = 0.0 attempt_download(weights) if weights.endswith('.pt'): # pytorch format # possible weights are '*.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt' etc. @@ -337,9 +337,9 @@ def train(): tb_writer.add_scalar(title, xi, epoch) # Update best mAP - fitness = sum(results[4:]) # total loss - if fitness < best_fitness: - best_fitness = fitness + fi = fitness(np.array(results).reshape(1, -1)) # fitness_i = weighted combination of [P, R, mAP, F1] + if fi > best_fitness: + best_fitness = fi # Save training results save = (not opt.nosave) or (final_epoch and not opt.evolve) @@ -357,7 +357,7 @@ def train(): torch.save(chkpt, last) # Save best checkpoint - if best_fitness == fitness: + if best_fitness == fi: torch.save(chkpt, best) # Save backup every 10 epochs (optional) @@ -382,6 +382,7 @@ def train(): if opt.bucket: os.system('gsutil cp %s gs://%s/results' % (fresults, opt.bucket)) os.system('gsutil cp %s gs://%s/weights' % (wdir + flast, opt.bucket)) + os.system('gsutil cp %s gs://%s/weights' % (wdir + fbest, opt.bucket)) if not opt.evolve: plot_results() # save as results.png diff --git a/utils/evolve.sh b/utils/evolve.sh index f69e81e2f0..3f81d6a0fd 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -11,3 +11,9 @@ while true; do python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --evolve --weights '' --bucket ult/coco --device $1 --cfg yolov3-spp.cfg --multi done + + +# coco epoch times --img-size 416 608 --epochs 27 --batch 16 --accum 4 +# 36:34 2080ti +# 21:58 V100 +# 63:00 T4 \ No newline at end of file diff --git a/utils/gcp.sh b/utils/gcp.sh index 6a6f69f851..ec7a337ed8 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -65,11 +65,11 @@ done # Evolve coco sudo -s -t=ultralytics/yolov3:v256 +t=ultralytics/yolov3:v189 docker kill $(docker ps -a -q --filter ancestor=$t) -for i in 0 +for i in 0 1 2 3 4 5 6 7 do - docker pull $t && docker run --gpus all -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i + docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i sleep 120 done @@ -278,7 +278,7 @@ n=197 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker r n=198 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -# knife +# athena n=199 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 0 n=200 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 6 n=207 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 7 @@ -318,7 +318,7 @@ n=254 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -d n=255 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 60 --batch 8 --accum 8 --weights darknet53.conv.74 --arc defaultpw --multi --device 2 --bucket ult/athena --name $n --nosave --cfg yolov3-spp3-1cls.cfg -# sm4 +# wer n=201 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 0 --cfg yolov3-tiny-3cls.cfg n=202 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 1 --cfg yolov3-tiny-3cls-sm4.cfg n=203 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 2 --cfg yolov3-tiny-3cls-sm4.cfg @@ -344,13 +344,25 @@ n=257 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it #coco -n=3 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 30 --batch 32 --accum 2 --weights '' --device 0 --cfg yolov3.cfg --nosave --bucket ult/coco --name $n -n=4 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 30 --batch 32 --accum 2 --weights '' --device 1 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n -n=5 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 30 --batch 32 --accum 2 --weights '' --device 2 --cfg yolov3-spp3.cfg --nosave --bucket ult/coco --name $n +n=3 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 1 --cfg yolov3.cfg --nosave --bucket ult/coco --name $n +n=4 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 2 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n +n=5 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 3 --cfg yolov3-spp3.cfg --nosave --bucket ult/coco --name $n +n=6 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 0 --cfg yolov4.cfg --nosave --bucket ult/coco --name $n +n=7 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 1 --cfg yolov4s.cfg --nosave --bucket ult/coco --name $n +n=8 && t=ultralytics/coco:v8 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 0 --cfg yolov4.cfg --nosave --bucket ult/coco --name $n +n=9 && t=ultralytics/coco:v9 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 22 --accum 3 --weights '' --device 0 --cfg yolov4a.cfg --nosave --bucket ult/coco --name $n --multi +n=10 && t=ultralytics/coco:v9 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 22 --accum 3 --weights '' --device 0 --cfg yolov4b.cfg --nosave --bucket ult/coco --name $n --multi + + sudo shutdown -# sm4 +# athena +n=32 && t=ultralytics/athena:v32 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=33 && t=ultralytics/athena:v33 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights darknet53.conv.74 --multi --device 1 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg + + +# wer n=18 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single --adam n=19 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-3l-1cls.cfg --single --adam n=20 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --name $n --nosave --cache --device 2 --cfg yolov3-tiny-prnc-1cls.cfg --single --adam @@ -361,4 +373,3 @@ n=24 && t=ultralytics/wer:v24 && sudo docker pull $t && sudo docker run -it --gp n=25 && t=ultralytics/wer:v25 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 2 --cfg yolov3-tiny3-1cls.cfg --single --adam n=26 && t=ultralytics/wer:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny3-1cls.cfg --single --adam - From b2be56414525cf94aaa440d89ad2688bc3694ca0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Jan 2020 10:33:36 -0800 Subject: [PATCH 0357/1185] updates --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7aebe10af7..b6c8e3561e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,10 +47,10 @@ COPY . /usr/src/app # t=ultralytics/yolov3:v0 && sudo docker build -t $t . && sudo docker push $t # Run -# sudo docker run --gpus all --ipc=host ultralytics/yolov3:v0 python3 detect.py +# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run --gpus all -it $t # Pull and Run with local directory access -# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run --gpus all -it --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t +# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/coco:/usr/src/coco $t # Kill all # sudo docker kill "$(sudo docker ps -q)" From f405d450437380671eb09b131727d988feb624d1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Jan 2020 10:34:51 -0800 Subject: [PATCH 0358/1185] updates --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index b6c8e3561e..20662e99c9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,10 +47,10 @@ COPY . /usr/src/app # t=ultralytics/yolov3:v0 && sudo docker build -t $t . && sudo docker push $t # Run -# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run --gpus all -it $t +# t=ultralytics/coco:v8 && sudo docker pull $t && sudo docker run -it $t # Pull and Run with local directory access -# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/coco:/usr/src/coco $t +# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run -it -v "$(pwd)"/coco:/usr/src/coco $t # Kill all # sudo docker kill "$(sudo docker ps -q)" From 9e97c4cadb3def7222c2e7462864afe2e6dc3b6e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Jan 2020 11:58:32 -0800 Subject: [PATCH 0359/1185] updates --- utils/utils.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index c83ebb07bd..2b3ff82bdb 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -216,9 +216,11 @@ def ap_per_class(tp, conf, pred_cls, target_cls): # Plot # fig, ax = plt.subplots(1, 1, figsize=(4, 4)) - # ax.plot(np.concatenate(([0.], recall)), np.concatenate(([0.], precision))) - # ax.set_title('YOLOv3-SPP'); ax.set_xlabel('Recall'); ax.set_ylabel('Precision') - # ax.set_xlim(0, 1) + # ax.plot(recall, precision) + # ax.set_xlabel('Recall') + # ax.set_ylabel('Precision') + # ax.set_xlim(0, 1.01) + # ax.set_ylim(0, 1.01) # fig.tight_layout() # fig.savefig('PR_curve.png', dpi=300) From 8fac566a87587c519e0252b4db60c43986e6ca4b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Jan 2020 14:18:45 -0800 Subject: [PATCH 0360/1185] updates --- utils/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 2b3ff82bdb..a0a29815d1 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -799,12 +799,13 @@ def fitness(thr, wh, k): # mutation fitness # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.') # Evolve + npr = np.random wh = torch.Tensor(wh) - f, sh, ng, mp, s = fitness(thr, wh, k), k.shape, 1000, 0.1, 0.3 # fitness, generations, mutation probability, sigma + f, sh, ng, mp, s = fitness(thr, wh, k), k.shape, 1000, 0.9, 0.1 # fitness, generations, mutation probability, sigma for _ in tqdm(range(ng), desc='Evolving anchors'): v = np.ones(sh) while (v == 1).all(): # mutate until a change occurs (prevent duplicates) - v = ((np.random.random(sh) < mp) * np.random.randn(*sh) * s + 1) ** 2.0 + v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) # 98.6, 61.6 kg = (k.copy() * v).clip(min=2.0) fg = fitness(thr, wh, kg) if fg > f: From 3ee6eb438a22d725a70763e8c97c7c3faa89d68e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Jan 2020 14:26:37 -0800 Subject: [PATCH 0361/1185] updates --- train.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/train.py b/train.py index cea08aa536..c4902b8d63 100644 --- a/train.py +++ b/train.py @@ -449,7 +449,7 @@ def train(): # Select parent(s) parent = 'single' # parent selection method: 'single' or 'weighted' x = np.loadtxt('evolve.txt', ndmin=2) - n = min(8, len(x)) # number of previous results to consider + n = min(5, len(x)) # number of previous results to consider x = x[np.argsort(-fitness(x))][:n] # top n mutations w = fitness(x) - fitness(x).min() # weights if parent == 'single' or len(x) == 1: @@ -459,20 +459,20 @@ def train(): x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination # Mutate - method = 3 - s = 0.3 # 30% sigma - np.random.seed(int(time.time())) + method, mp, s = 3, 0.9, 0.1 # method, mutation probability, sigma + npr = np.random + npr.seed(int(time.time())) g = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 0, 1, 1, 1, 1, 1, 1, 1]) # gains ng = len(g) if method == 1: - v = (np.random.randn(ng) * np.random.random() * g * s + 1) ** 2.0 + v = (npr.randn(ng) * npr.random() * g * s + 1) ** 2.0 elif method == 2: - v = (np.random.randn(ng) * np.random.random(ng) * g * s + 1) ** 2.0 + v = (npr.randn(ng) * npr.random(ng) * g * s + 1) ** 2.0 elif method == 3: v = np.ones(ng) while all(v == 1): # mutate until a change occurs (prevent duplicates) - r = (np.random.random(ng) < 0.1) * np.random.randn(ng) # 10% mutation probability - v = (g * s * r + 1) ** 2.0 + # v = (g * (npr.random(ng) < mp) * npr.randn(ng) * s + 1) ** 2.0 + v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) hyp[k] = x[i + 7] * v[i] # mutate From db4ac86ebab09865df52b7ab4cec0ab159681794 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Jan 2020 14:28:48 -0800 Subject: [PATCH 0362/1185] updates --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 20662e99c9..b44772d100 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,7 +47,7 @@ COPY . /usr/src/app # t=ultralytics/yolov3:v0 && sudo docker build -t $t . && sudo docker push $t # Run -# t=ultralytics/coco:v8 && sudo docker pull $t && sudo docker run -it $t +# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run -it $t # Pull and Run with local directory access # t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run -it -v "$(pwd)"/coco:/usr/src/coco $t From 9b78f4aa1b47f62e03d7d43f7c008ad3a0f7667c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Jan 2020 15:31:19 -0800 Subject: [PATCH 0363/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index c4902b8d63..3f1b94611c 100644 --- a/train.py +++ b/train.py @@ -459,7 +459,7 @@ def train(): x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination # Mutate - method, mp, s = 3, 0.9, 0.1 # method, mutation probability, sigma + method, mp, s = 3, 0.9, 0.2 # method, mutation probability, sigma npr = np.random npr.seed(int(time.time())) g = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 0, 1, 1, 1, 1, 1, 1, 1]) # gains From 2cf171465c6bd9f25a33291f2ce02c524d875d45 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Jan 2020 21:17:31 -0800 Subject: [PATCH 0364/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 3f1b94611c..a03ec26bfb 100644 --- a/train.py +++ b/train.py @@ -382,7 +382,7 @@ def train(): if opt.bucket: os.system('gsutil cp %s gs://%s/results' % (fresults, opt.bucket)) os.system('gsutil cp %s gs://%s/weights' % (wdir + flast, opt.bucket)) - os.system('gsutil cp %s gs://%s/weights' % (wdir + fbest, opt.bucket)) + # os.system('gsutil cp %s gs://%s/weights' % (wdir + fbest, opt.bucket)) if not opt.evolve: plot_results() # save as results.png From ce11ef28f8f2098672f184219683af4d7039666e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Jan 2020 21:52:00 -0800 Subject: [PATCH 0365/1185] updates --- models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/models.py b/models.py index cf5435b502..4a57ef59a8 100755 --- a/models.py +++ b/models.py @@ -179,7 +179,8 @@ def forward(self, p, img_size, var=None): p = p.view(m, self.no) xy = torch.sigmoid(p[:, 0:2]) + grid_xy # x, y wh = torch.exp(p[:, 2:4]) * anchor_wh # width, height - p_cls = torch.sigmoid(p[:, 5:self.no]) * torch.sigmoid(p[:, 4:5]) # conf + p_cls = torch.sigmoid(p[:, 4:5]) if self.nc == 1 else \ + torch.sigmoid(p[:, 5:self.no]) * torch.sigmoid(p[:, 4:5]) # conf return p_cls, xy / self.ng, wh else: # inference From ff7ee7f1f133b7be04e72d84f30a505c24f8bf3e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 30 Jan 2020 12:12:04 -0800 Subject: [PATCH 0366/1185] updates --- detect.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/detect.py b/detect.py index 2d826a4957..d14ca47f4e 100644 --- a/detect.py +++ b/detect.py @@ -36,14 +36,16 @@ def detect(save_img=False): # Fuse Conv2d + BatchNorm2d layers # model.fuse() + # torch_utils.model_info(model, report='summary') # 'full' or 'summary' # Eval mode model.to(device).eval() # Export mode if ONNX_EXPORT: + model.fuse() img = torch.zeros((1, 3) + img_size) # (1, 3, 320, 192) - torch.onnx.export(model, img, 'weights/export.onnx', verbose=False, opset_version=10) + torch.onnx.export(model, img, 'weights/export.onnx', verbose=False, opset_version=11) # Validate exported model import onnx From 27c75b521084039f2b555c5873832e3a41928c80 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 30 Jan 2020 12:37:47 -0800 Subject: [PATCH 0367/1185] updates --- detect.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/detect.py b/detect.py index d14ca47f4e..889ca689d4 100644 --- a/detect.py +++ b/detect.py @@ -45,7 +45,7 @@ def detect(save_img=False): if ONNX_EXPORT: model.fuse() img = torch.zeros((1, 3) + img_size) # (1, 3, 320, 192) - torch.onnx.export(model, img, 'weights/export.onnx', verbose=False, opset_version=11) + torch.onnx.export(model, img, 'weights/export.onnx', verbose=False, opset_version=10) # Validate exported model import onnx @@ -159,7 +159,7 @@ def detect(save_img=False): parser = argparse.ArgumentParser() parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') parser.add_argument('--names', type=str, default='data/coco.names', help='*.names path') - parser.add_argument('--weights', type=str, default='weights/yolov3-spp.weights', help='path to weights file') + parser.add_argument('--weights', type=str, default='weights/ultralytics68.pt', help='path to weights file') parser.add_argument('--source', type=str, default='data/samples', help='source') # input file/folder, 0 for webcam parser.add_argument('--output', type=str, default='output', help='output folder') # output folder parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') From 999463fbbdc23a9b4d944bdf74acba4e14f93d7c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 30 Jan 2020 12:39:54 -0800 Subject: [PATCH 0368/1185] updates --- models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/models.py b/models.py index 4a57ef59a8..f77c1cdb1e 100755 --- a/models.py +++ b/models.py @@ -51,7 +51,11 @@ def create_modules(module_defs, img_size, arc): modules = maxpool elif mdef['type'] == 'upsample': - modules = nn.Upsample(scale_factor=int(mdef['stride']), mode='nearest') + if ONNX_EXPORT: # explicitly state size, avoid scale_factor + g = (yolo_index + 1) * 2 + modules = nn.Upsample(size=(10 * g, 6 * g), mode='nearest') # assume img_size = (320, 192) + else: + modules = nn.Upsample(scale_factor=int(mdef['stride']), mode='nearest') elif mdef['type'] == 'route': # nn.Sequential() placeholder for 'route' layer layers = [int(x) for x in mdef['layers'].split(',')] From 2e4650e013498b0f91cf5d26add55ec72c1043b2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 30 Jan 2020 12:40:05 -0800 Subject: [PATCH 0369/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index f77c1cdb1e..0b513f3782 100755 --- a/models.py +++ b/models.py @@ -52,7 +52,7 @@ def create_modules(module_defs, img_size, arc): elif mdef['type'] == 'upsample': if ONNX_EXPORT: # explicitly state size, avoid scale_factor - g = (yolo_index + 1) * 2 + g = (yolo_index + 1) * 2 # gain modules = nn.Upsample(size=(10 * g, 6 * g), mode='nearest') # assume img_size = (320, 192) else: modules = nn.Upsample(scale_factor=int(mdef['stride']), mode='nearest') From ac8d78382a78585cd2c575d3ad0e7c0df7828012 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 30 Jan 2020 14:29:58 -0800 Subject: [PATCH 0370/1185] updates --- train.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/train.py b/train.py index a03ec26bfb..4b0e8a5d8e 100644 --- a/train.py +++ b/train.py @@ -377,9 +377,7 @@ def train(): os.rename('results.txt', fresults) os.rename(wdir + 'last.pt', wdir + flast) if os.path.exists(wdir + 'last.pt') else None os.rename(wdir + 'best.pt', wdir + fbest) if os.path.exists(wdir + 'best.pt') else None - - # save to cloud - if opt.bucket: + if opt.bucket: # save to cloud os.system('gsutil cp %s gs://%s/results' % (fresults, opt.bucket)) os.system('gsutil cp %s gs://%s/weights' % (wdir + flast, opt.bucket)) # os.system('gsutil cp %s gs://%s/weights' % (wdir + fbest, opt.bucket)) From 4b9d73f9318451630f4172d40ba446b0fd7e94c1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 30 Jan 2020 14:32:10 -0800 Subject: [PATCH 0371/1185] updates --- train.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/train.py b/train.py index 4b0e8a5d8e..8f09bae3c4 100644 --- a/train.py +++ b/train.py @@ -437,8 +437,7 @@ def train(): train() # train normally else: # Evolve hyperparameters (optional) - opt.notest = True # only test final epoch - opt.nosave = True # only save final checkpoint + opt.notest, opt.nosave = True, True # only test/save final epoch if opt.bucket: os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket) # download evolve.txt if exists From 20b0601fa72665abf97939aa460cc81305b3562a Mon Sep 17 00:00:00 2001 From: Piotr Skalski Date: Fri, 31 Jan 2020 00:48:26 +0100 Subject: [PATCH 0372/1185] change of test batch image format from .jpg to .png, due to matplotlib bug (#817) Co-authored-by: Glenn Jocher --- test.py | 5 +++-- train.py | 4 ++-- utils/utils.py | 7 ++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/test.py b/test.py index 96248f72ed..a5cec3b421 100644 --- a/test.py +++ b/test.py @@ -76,8 +76,9 @@ def test(cfg, _, _, height, width = imgs.shape # batch size, channels, height, width # Plot images with bounding boxes - if batch_i == 0 and not os.path.exists('test_batch0.jpg'): - plot_images(imgs=imgs, targets=targets, paths=paths, fname='test_batch0.jpg') + if batch_i == 0 and not os.path.exists('test_batch0.png'): + plot_images(imgs=imgs, targets=targets, paths=paths, fname='test_batch0.png') + # Disable gradients with torch.no_grad(): diff --git a/train.py b/train.py index 8f09bae3c4..15a6d2adcd 100644 --- a/train.py +++ b/train.py @@ -73,7 +73,7 @@ def train(): nc = 1 if opt.single_cls else int(data_dict['classes']) # number of classes # Remove previous results - for f in glob.glob('*_batch*.jpg') + glob.glob(results_file): + for f in glob.glob('*_batch*.png') + glob.glob(results_file): os.remove(f) # Initialize model @@ -255,7 +255,7 @@ def train(): # Plot images with bounding boxes if ni == 0: - fname = 'train_batch%g.jpg' % i + fname = 'train_batch%g.png' % i plot_images(imgs=imgs, targets=targets, paths=paths, fname=fname) if tb_writer: tb_writer.add_image(fname, cv2.imread(fname)[:, :, ::-1], dataformats='HWC') diff --git a/utils/utils.py b/utils/utils.py index a0a29815d1..82b80cde37 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -911,7 +911,8 @@ def plot_wh_methods(): # from utils.utils import *; plot_wh_methods() fig.savefig('comparison.png', dpi=200) -def plot_images(imgs, targets, paths=None, fname='images.jpg'): + +def plot_images(imgs, targets, paths=None, fname='images.png'): # Plots training images overlaid with targets imgs = imgs.cpu().numpy() targets = targets.cpu().numpy() @@ -947,13 +948,13 @@ def plot_test_txt(): # from utils.utils import *; plot_test() ax.hist2d(cx, cy, bins=600, cmax=10, cmin=0) ax.set_aspect('equal') fig.tight_layout() - plt.savefig('hist2d.jpg', dpi=300) + plt.savefig('hist2d.png', dpi=300) fig, ax = plt.subplots(1, 2, figsize=(12, 6)) ax[0].hist(cx, bins=600) ax[1].hist(cy, bins=600) fig.tight_layout() - plt.savefig('hist1d.jpg', dpi=200) + plt.savefig('hist1d.png', dpi=200) def plot_targets_txt(): # from utils.utils import *; plot_targets_txt() From 6f769081d1a8b72ea7ee2d696a0b39fc12a06c25 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 30 Jan 2020 16:03:34 -0800 Subject: [PATCH 0373/1185] updates --- utils/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 82b80cde37..6402f84b65 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -911,7 +911,6 @@ def plot_wh_methods(): # from utils.utils import *; plot_wh_methods() fig.savefig('comparison.png', dpi=200) - def plot_images(imgs, targets, paths=None, fname='images.png'): # Plots training images overlaid with targets imgs = imgs.cpu().numpy() From 0c7af1a4d293b40de08613468369e2f5d9b143fa Mon Sep 17 00:00:00 2001 From: LinCoce <328655009@qq.com> Date: Fri, 31 Jan 2020 13:58:26 +0800 Subject: [PATCH 0374/1185] fusedconv bug fix, https://github.com/ultralytics/yolov3/issues/807 (#818) Looks good. Thanks for catching the bug @LinCoce! --- utils/torch_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index d615e2a8fc..9b32172417 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -61,7 +61,7 @@ def fuse_conv_and_bn(conv, bn): else: b_conv = torch.zeros(conv.weight.size(0)) b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(torch.sqrt(bn.running_var + bn.eps)) - fusedconv.bias.copy_(b_conv + b_bn) + fusedconv.bias.copy_(torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn) return fusedconv From 189c7044fb57b05ce97106951756653f2a4787f5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 31 Jan 2020 09:00:45 -0800 Subject: [PATCH 0375/1185] updates --- utils/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 6402f84b65..1fd88e9c66 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -343,13 +343,13 @@ def wh_iou(wh1, wh2): class FocalLoss(nn.Module): # Wraps focal loss around existing loss_fcn() https://arxiv.org/pdf/1708.02002.pdf # i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=2.5) - def __init__(self, loss_fcn, gamma=0.5, alpha=1, reduction='mean'): + def __init__(self, loss_fcn, gamma=0.5, alpha=1): super(FocalLoss, self).__init__() - loss_fcn.reduction = 'none' # required to apply FL to each element self.loss_fcn = loss_fcn self.gamma = gamma self.alpha = alpha - self.reduction = reduction + self.reduction = loss_fcn.reduction + self.loss_fcn.reduction = 'none' # required to apply FL to each element def forward(self, input, target): loss = self.loss_fcn(input, target) From f7772c791de0d5e488e82b52c2bcf46ee33727e2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 31 Jan 2020 09:27:40 -0800 Subject: [PATCH 0376/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 1fd88e9c66..f78534da7e 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -872,7 +872,7 @@ def apply_classifier(x, model, img, im0): def fitness(x): # Returns fitness (for use with results.txt or evolve.txt) - w = [0.01, 0.01, 0.75, 0.23] # weights for [P, R, mAP, F1]@0.5 or [P, R, mAP@0.5:0.95, mAP@0.5] + w = [0.0, 0.01, 0.99, 0.0] # weights for [P, R, mAP, F1]@0.5 or [P, R, mAP@0.5:0.95, mAP@0.5] return (x[:, :4] * w).sum(1) From d23f721dcf9eb26949f07b15f5534ee2918c7fc8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 31 Jan 2020 09:36:28 -0800 Subject: [PATCH 0377/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 15a6d2adcd..01c3107e73 100644 --- a/train.py +++ b/train.py @@ -313,7 +313,7 @@ def train(): batch_size=batch_size * 2, img_size=img_size_test, model=model, - conf_thres=0.001 if final_epoch and is_coco else 0.1, # 0.1 for speed + conf_thres=1E-3 if opt.evolve or (final_epoch and is_coco) else 0.1, # 0.1 faster iou_thres=0.6, save_json=final_epoch and is_coco, single_cls=opt.single_cls, From 8b18beb3dbd6041fd8224ee40b8d7519ba7849ab Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 2 Feb 2020 08:55:34 -0800 Subject: [PATCH 0378/1185] updates --- models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/models.py b/models.py index 0b513f3782..ea262375f0 100755 --- a/models.py +++ b/models.py @@ -18,6 +18,8 @@ def create_modules(module_defs, img_size, arc): for i, mdef in enumerate(module_defs): modules = nn.Sequential() + # if i == 0: + # modules.add_module('BatchNorm2d_0', nn.BatchNorm2d(output_filters[-1], momentum=0.1)) if mdef['type'] == 'convolutional': bn = int(mdef['batch_normalize']) From 785bfec286b7367492097d4ce3a99eb27cc7c504 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 2 Feb 2020 09:19:44 -0800 Subject: [PATCH 0379/1185] updates --- utils/utils.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index f78534da7e..4bf0080ad3 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -751,22 +751,22 @@ def kmean_anchors(path='../coco/train2017.txt', n=9, img_size=(320, 640)): from utils.datasets import LoadImagesAndLabels thr = 0.20 # IoU threshold - def print_results(thr, wh, k): + def print_results(wh, k): k = k[np.argsort(k.prod(1))] # sort small to large iou = wh_iou(torch.Tensor(wh), torch.Tensor(k)) - max_iou, min_iou = iou.max(1)[0], iou.min(1)[0] + max_iou = iou.max(1)[0] bpr, aat = (max_iou > thr).float().mean(), (iou > thr).float().mean() * n # best possible recall, anch > thr print('%.2f iou_thr: %.3f best possible recall, %.2f anchors > thr' % (thr, bpr, aat)) - print('kmeans anchors (n=%g, img_size=%s, IoU=%.3f/%.3f/%.3f-min/mean/best): ' % - (n, img_size, min_iou.mean(), iou.mean(), max_iou.mean()), end='') + print('n=%g, img_size=%s, IoU_all=%.3f/%.3f-mean/best, IoU>thr=%.3f-mean: ' % + (n, img_size, iou.mean(), max_iou.mean(), iou[iou > thr].mean()), end='') for i, x in enumerate(k): print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg return k - def fitness(thr, wh, k): # mutation fitness - iou = wh_iou(wh, torch.Tensor(k)).max(1)[0] # max iou - bpr = (iou > thr).float().mean() # best possible recall - return iou.mean() * bpr # product + def fitness(wh, k): # mutation fitness + iou = wh_iou(wh, torch.Tensor(k)) # iou + max_iou = iou.max(1)[0] + return max_iou.mean() # product # Get label wh wh = [] @@ -776,6 +776,7 @@ def fitness(thr, wh, k): # mutation fitness wh.append(l[:, 3:5] * (s / s.max())) # image normalized to letterbox normalized wh wh = np.concatenate(wh, 0).repeat(nr, axis=0) # augment 10x wh *= np.random.uniform(img_size[0], img_size[1], size=(wh.shape[0], 1)) # normalized to pixels (multi-scale) + wh = wh[(wh > 2.0).all(1)] # remove below threshold boxes (< 2 pixels wh) # Darknet yolov3.cfg anchors use_darknet = False @@ -788,7 +789,7 @@ def fitness(thr, wh, k): # mutation fitness s = wh.std(0) # sigmas for whitening k, dist = kmeans(wh / s, n, iter=30) # points, mean distance k *= s - k = print_results(thr, wh, k) + k = print_results(wh, k) # # Plot # k, d = [None] * 20, [None] * 20 @@ -797,21 +798,26 @@ def fitness(thr, wh, k): # mutation fitness # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # ax = ax.ravel() # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.') + # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # plot wh + # ax[0].hist(wh[wh[:, 0]<100, 0],400) + # ax[1].hist(wh[wh[:, 1]<100, 1],400) + # fig.tight_layout() + # fig.savefig('wh.png', dpi=200) # Evolve npr = np.random wh = torch.Tensor(wh) - f, sh, ng, mp, s = fitness(thr, wh, k), k.shape, 1000, 0.9, 0.1 # fitness, generations, mutation probability, sigma + f, sh, ng, mp, s = fitness(wh, k), k.shape, 1000, 0.9, 0.1 # fitness, generations, mutation prob, sigma for _ in tqdm(range(ng), desc='Evolving anchors'): v = np.ones(sh) while (v == 1).all(): # mutate until a change occurs (prevent duplicates) v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) # 98.6, 61.6 kg = (k.copy() * v).clip(min=2.0) - fg = fitness(thr, wh, kg) + fg = fitness(wh, kg) if fg > f: f, k = fg, kg.copy() - print_results(thr, wh, k) - k = print_results(thr, wh, k) + print_results(wh, k) + k = print_results(wh, k) return k From 888cad1e31e6c1264b3c8ee20a71a7b4fd05041d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 2 Feb 2020 23:35:03 -0800 Subject: [PATCH 0380/1185] updates --- utils/gcp.sh | 34 +++++++++++++++++++++++----------- utils/utils.py | 22 +++++++++++----------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index ec7a337ed8..e918123d8e 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -3,11 +3,12 @@ # New VM rm -rf sample_data yolov3 git clone https://github.com/ultralytics/yolov3 -sudo apt-get install zip +# sudo apt-get install zip #git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex sudo conda install -yc conda-forge scikit-image pycocotools python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('193Zp_ye-3qXMonR1nZj3YyxMtQkMy50k','coco2014.zip')" -sudo shutdown +python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1C3HewOG9akA3y456SZLBJZfNDPkBwAto','knife.zip')" +python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('13g3LqdpkNE8sPosVJT6KFXlfoMypzRP4','sm4.zip')" # Re-clone rm -rf yolov3 # Warning: remove existing @@ -67,10 +68,10 @@ done sudo -s t=ultralytics/yolov3:v189 docker kill $(docker ps -a -q --filter ancestor=$t) -for i in 0 1 2 3 4 5 6 7 +for i in 0 1 do docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i - sleep 120 + sleep 30 done # Git pull @@ -350,16 +351,28 @@ n=5 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -d --gpus n=6 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 0 --cfg yolov4.cfg --nosave --bucket ult/coco --name $n n=7 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 1 --cfg yolov4s.cfg --nosave --bucket ult/coco --name $n n=8 && t=ultralytics/coco:v8 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 0 --cfg yolov4.cfg --nosave --bucket ult/coco --name $n -n=9 && t=ultralytics/coco:v9 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 22 --accum 3 --weights '' --device 0 --cfg yolov4a.cfg --nosave --bucket ult/coco --name $n --multi -n=10 && t=ultralytics/coco:v9 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 22 --accum 3 --weights '' --device 0 --cfg yolov4b.cfg --nosave --bucket ult/coco --name $n --multi - - -sudo shutdown +n=9 && t=ultralytics/coco:v9 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 20 --accum 3 --weights '' --device 0 --cfg yolov4a.cfg --nosave --bucket ult/coco --name $n --multi +n=10 && t=ultralytics/coco:v9 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 20 --accum 3 --weights '' --device 0 --cfg yolov4b.cfg --nosave --bucket ult/coco --name $n --multi +n=11 && t=ultralytics/coco:v9 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 20 --accum 3 --weights '' --device 0 --cfg yolov4c.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=12 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 20 --accum 3 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi +n=13 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 20 --accum 3 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi +n=14 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 20 --accum 3 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi +n=15 && t=ultralytics/coco:v14 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi +n=16 && t=ultralytics/coco:v9 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov4a.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=17 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov4d.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=18 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov4a.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=19 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov4e.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=20 && t=ultralytics/coco:v14 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=21 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppe.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=22 && t=ultralytics/coco:v14 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 27 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=23 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown # athena n=32 && t=ultralytics/athena:v32 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=33 && t=ultralytics/athena:v33 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights darknet53.conv.74 --multi --device 1 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=33 && t=ultralytics/athena:v33 && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=34 && t=ultralytics/athena:v33 && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 20 --batch 8 --accum 8 --weights ultralytics68.pt --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg +n=35 && t=ultralytics/athena:v33 && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 30 --batch 8 --accum 8 --weights ultralytics68.pt --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg && sudo shutdown # wer @@ -372,4 +385,3 @@ n=23 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gp n=24 && t=ultralytics/wer:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights '' --multi --bucket ult/wer --name $n --nosave --cache --device 3 --cfg yolov3-tiny-3l-1cls.cfg --single --adam n=25 && t=ultralytics/wer:v25 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 2 --cfg yolov3-tiny3-1cls.cfg --single --adam n=26 && t=ultralytics/wer:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny3-1cls.cfg --single --adam - diff --git a/utils/utils.py b/utils/utils.py index 4bf0080ad3..61890c2eab 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -745,15 +745,15 @@ def coco_single_class_labels(path='../coco/labels/train2014/', label_class=43): shutil.copyfile(src=img_file, dst='new/images/' + Path(file).name.replace('txt', 'jpg')) # copy images -def kmean_anchors(path='../coco/train2017.txt', n=9, img_size=(320, 640)): +def kmean_anchors(path='../coco/train2017.txt', n=9, img_size=(608, 608)): # from utils.utils import *; _ = kmean_anchors() # Produces a list of target kmeans suitable for use in *.cfg files from utils.datasets import LoadImagesAndLabels thr = 0.20 # IoU threshold - def print_results(wh, k): + def print_results(k): k = k[np.argsort(k.prod(1))] # sort small to large - iou = wh_iou(torch.Tensor(wh), torch.Tensor(k)) + iou = wh_iou(wh, torch.Tensor(k)) max_iou = iou.max(1)[0] bpr, aat = (max_iou > thr).float().mean(), (iou > thr).float().mean() * n # best possible recall, anch > thr print('%.2f iou_thr: %.3f best possible recall, %.2f anchors > thr' % (thr, bpr, aat)) @@ -763,7 +763,7 @@ def print_results(wh, k): print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg return k - def fitness(wh, k): # mutation fitness + def fitness(k): # mutation fitness iou = wh_iou(wh, torch.Tensor(k)) # iou max_iou = iou.max(1)[0] return max_iou.mean() # product @@ -780,7 +780,7 @@ def fitness(wh, k): # mutation fitness # Darknet yolov3.cfg anchors use_darknet = False - if use_darknet: + if use_darknet and n == 9: k = np.array([[10, 13], [16, 30], [33, 23], [30, 61], [62, 45], [59, 119], [116, 90], [156, 198], [373, 326]]) else: # Kmeans calculation @@ -789,7 +789,8 @@ def fitness(wh, k): # mutation fitness s = wh.std(0) # sigmas for whitening k, dist = kmeans(wh / s, n, iter=30) # points, mean distance k *= s - k = print_results(wh, k) + wh = torch.Tensor(wh) + k = print_results(k) # # Plot # k, d = [None] * 20, [None] * 20 @@ -806,18 +807,17 @@ def fitness(wh, k): # mutation fitness # Evolve npr = np.random - wh = torch.Tensor(wh) - f, sh, ng, mp, s = fitness(wh, k), k.shape, 1000, 0.9, 0.1 # fitness, generations, mutation prob, sigma + f, sh, ng, mp, s = fitness(k), k.shape, 1000, 0.9, 0.1 # fitness, generations, mutation prob, sigma for _ in tqdm(range(ng), desc='Evolving anchors'): v = np.ones(sh) while (v == 1).all(): # mutate until a change occurs (prevent duplicates) v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) # 98.6, 61.6 kg = (k.copy() * v).clip(min=2.0) - fg = fitness(wh, kg) + fg = fitness(kg) if fg > f: f, k = fg, kg.copy() - print_results(wh, k) - k = print_results(wh, k) + print_results(k) + k = print_results(k) return k From e185719bd795e33ffde909b2de8f36743acac374 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 4 Feb 2020 21:22:20 -0800 Subject: [PATCH 0381/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index ea262375f0..74bfe8e75a 100755 --- a/models.py +++ b/models.py @@ -268,7 +268,7 @@ def forward(self, x, var=None): x = [torch.cat(x, 0) for x in zip(*output)] return x[0], torch.cat(x[1:3], 1) # scores, boxes: 3780x80, 3780x4 else: - io, p = list(zip(*output)) # inference output, training output + io, p = zip(*output) # inference output, training output return torch.cat(io, 1), p def fuse(self): From ec942bd23ce1b6998ce37af890f3da30068cad42 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 5 Feb 2020 20:27:01 -0800 Subject: [PATCH 0382/1185] updates --- train.py | 5 ++--- utils/gcp.sh | 12 ++++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 01c3107e73..108051b70f 100644 --- a/train.py +++ b/train.py @@ -297,9 +297,8 @@ def train(): # Print batch results mloss = (mloss * i + loss_items) / (i + 1) # update mean losses - mem = torch.cuda.memory_cached() / 1E9 if torch.cuda.is_available() else 0 # (GB) - s = ('%10s' * 2 + '%10.3g' * 6) % ( - '%g/%g' % (epoch, epochs - 1), '%.3gG' % mem, *mloss, len(targets), img_size) + mem = '%.3gG' % (torch.cuda.memory_cached() / 1E9 if torch.cuda.is_available() else 0) # (GB) + s = ('%10s' * 2 + '%10.3g' * 6) % ('%g/%g' % (epoch, epochs - 1), mem, *mloss, len(targets), img_size) pbar.set_description(s) # end batch ------------------------------------------------------------------------------------------------ diff --git a/utils/gcp.sh b/utils/gcp.sh index e918123d8e..07a5b10018 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -366,6 +366,18 @@ n=20 && t=ultralytics/coco:v14 && sudo docker pull $t && sudo docker run -it --g n=21 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppe.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown n=22 && t=ultralytics/coco:v14 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 27 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown n=23 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=24 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=25 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 27 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=26 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=27 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=28 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=29 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 15 --accum 4 --weights '' --device 0 --cfg yolov4a.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=30 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown + +n=31 && t=ultralytics/coco:v31 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppf.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=32 && t=ultralytics/coco:v31 && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppg.cfg --nosave --bucket ult/coco --name $n --multi +n=33 && t=ultralytics/coco:v33 && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppf.cfg --nosave --bucket ult/coco --name $n --multi +n=34 && t=ultralytics/coco:v33 && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppg.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown # athena From d778bf3c7ac1f4aabb54fdb0e3b68e1d5923cde6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 5 Feb 2020 20:35:54 -0800 Subject: [PATCH 0383/1185] updates --- train.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/train.py b/train.py index 108051b70f..dc82ceef47 100644 --- a/train.py +++ b/train.py @@ -244,22 +244,6 @@ def train(): imgs = imgs.to(device).float() / 255.0 # uint8 to float32, 0 - 255 to 0.0 - 1.0 targets = targets.to(device) - # Multi-Scale training - if opt.multi_scale: - if ni / accumulate % 10 == 0: #  adjust (67% - 150%) every 10 batches - img_size = random.randrange(img_sz_min, img_sz_max + 1) * 32 - sf = img_size / max(imgs.shape[2:]) # scale factor - if sf != 1: - ns = [math.ceil(x * sf / 32.) * 32 for x in imgs.shape[2:]] # new shape (stretched to 32-multiple) - imgs = F.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) - - # Plot images with bounding boxes - if ni == 0: - fname = 'train_batch%g.png' % i - plot_images(imgs=imgs, targets=targets, paths=paths, fname=fname) - if tb_writer: - tb_writer.add_image(fname, cv2.imread(fname)[:, :, ::-1], dataformats='HWC') - # Hyperparameter burn-in # n_burn = nb - 1 # min(nb // 5 + 1, 1000) # number of burn-in batches # if ni <= n_burn: @@ -271,6 +255,22 @@ def train(): # x['lr'] = hyp['lr0'] * g # x['weight_decay'] = hyp['weight_decay'] * g + # Plot images with bounding boxes + if ni == 0: + fname = 'train_batch%g.png' % i + plot_images(imgs=imgs, targets=targets, paths=paths, fname=fname) + if tb_writer: + tb_writer.add_image(fname, cv2.imread(fname)[:, :, ::-1], dataformats='HWC') + + # Multi-Scale training + if opt.multi_scale: + if ni / accumulate % 10 == 0: #  adjust (67% - 150%) every 10 batches + img_size = random.randrange(img_sz_min, img_sz_max + 1) * 32 + sf = img_size / max(imgs.shape[2:]) # scale factor + if sf != 1: + ns = [math.ceil(x * sf / 32.) * 32 for x in imgs.shape[2:]] # new shape (stretched to 32-multiple) + imgs = F.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) + # Run model pred = model(imgs) From dca80f6f98cd0a440f846b1d590e55477076880b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 6 Feb 2020 16:13:10 -0800 Subject: [PATCH 0384/1185] updates --- utils/datasets.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index f83a17be78..1f9b9e3f7f 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -370,7 +370,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r if not os.path.exists(Path(f).parent): os.makedirs(Path(f).parent) # make new output folder - b = x[1:] * np.array([w, h, w, h]) # box + b = x[1:] * [w, h, w, h] # box b[2:] = b[2:].max() # rectangle to square b[2:] = b[2:] * 1.3 + 30 # pad b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(np.int) @@ -731,7 +731,7 @@ def bbox_ioa(box1, box2): return inter_area / box2_area # create random masks - scales = [0.5] * 1 # + [0.25] * 4 + [0.125] * 16 + [0.0625] * 64 + [0.03125] * 256 # image size fraction + scales = [0.5] * 1 + [0.25] * 2 + [0.125] * 4 + [0.0625] * 8 + [0.03125] * 16 # image size fraction for s in scales: mask_h = random.randint(1, int(h * s)) mask_w = random.randint(1, int(w * s)) @@ -743,14 +743,13 @@ def bbox_ioa(box1, box2): ymax = min(h, ymin + mask_h) # apply random color mask - mask_color = [random.randint(0, 255) for _ in range(3)] - image[ymin:ymax, xmin:xmax] = mask_color + image[ymin:ymax, xmin:xmax] = [random.randint(64, 191) for _ in range(3)] # return unobscured labels if len(labels) and s > 0.03: box = np.array([xmin, ymin, xmax, ymax], dtype=np.float32) ioa = bbox_ioa(box, labels[:, 1:5]) # intersection over area - labels = labels[ioa < 0.90] # remove >90% obscured labels + labels = labels[ioa < 0.60] # remove >60% obscured labels return labels From 145ea67a2e9d2443174f535c6137e3b24cbcea3f Mon Sep 17 00:00:00 2001 From: Yonghye Kwon Date: Sat, 8 Feb 2020 02:14:55 +0900 Subject: [PATCH 0385/1185] modify h range clip range in hsv augmentation (#825) * h range clip range edit in hsv augmentation h range is [0., 179,] * Update datasets.py reduced indexing operations and used inplace clip for hsv. Two clips are used unfortunately (double clip of axis 0), but the overall effect should be improved speed. Co-authored-by: Glenn Jocher --- utils/datasets.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 1f9b9e3f7f..fee8ceabbd 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -530,8 +530,9 @@ def load_image(self, index): def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5): - x = (np.random.uniform(-1, 1, 3) * np.array([hgain, sgain, vgain]) + 1).astype(np.float32) # random gains - img_hsv = (cv2.cvtColor(img, cv2.COLOR_BGR2HSV) * x.reshape((1, 1, 3))).clip(None, 255).astype(np.uint8) + x = np.random.uniform(-1, 1, 3) * [hgain, sgain, vgain] + 1 # random gains + img_hsv = (cv2.cvtColor(img, cv2.COLOR_BGR2HSV) * x).clip(None, 255).astype(np.uint8) + np.clip(img_hsv[:, :, 0], None, 179, out=img_hsv[:, :, 0]) # inplace hue clip (0 - 179 deg) cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR, dst=img) # no return needed From 106b1961b620d8479f52736e817a0b7f68f4912b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 7 Feb 2020 10:53:09 -0800 Subject: [PATCH 0386/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index dc82ceef47..46bcdd116f 100644 --- a/train.py +++ b/train.py @@ -264,7 +264,7 @@ def train(): # Multi-Scale training if opt.multi_scale: - if ni / accumulate % 10 == 0: #  adjust (67% - 150%) every 10 batches + if ni / accumulate % 1 == 0: #  adjust (67% - 150%) every 10 batches img_size = random.randrange(img_sz_min, img_sz_max + 1) * 32 sf = img_size / max(imgs.shape[2:]) # scale factor if sf != 1: From 58f04daec6a88a06cf667049bb53d44bbbf8fd57 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 8 Feb 2020 09:47:01 -0800 Subject: [PATCH 0387/1185] updates --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e8d8ad6c3..8018c0bed7 100755 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ The https://github.com/ultralytics/yolov3 repo contains inference and training c # Requirements Python 3.7 or later with all of the `pip install -U -r requirements.txt` packages including: -- `torch >= 1.3` +- `torch >= 1.4` - `opencv-python` - `Pillow` From daddc560f6481687adc1e1eac0e566e0ab76aefa Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 8 Feb 2020 09:48:28 -0800 Subject: [PATCH 0388/1185] updates --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8018c0bed7..cdd8850a58 100755 --- a/README.md +++ b/README.md @@ -32,8 +32,8 @@ Python 3.7 or later with all of the `pip install -U -r requirements.txt` package - `Pillow` All dependencies are included in the associated docker images. Docker requirements are: -- `nvidia-docker` -- Nvidia Driver Version >= 440.44 +- Nvidia Driver >= 440.44 +- Docker Engine - CE >= 19.03 # Tutorials From ca4960f7ff7667995ce1df3413a1d618bc8f24c9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 8 Feb 2020 13:28:47 -0800 Subject: [PATCH 0389/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 61890c2eab..85dd365823 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -878,7 +878,7 @@ def apply_classifier(x, model, img, im0): def fitness(x): # Returns fitness (for use with results.txt or evolve.txt) - w = [0.0, 0.01, 0.99, 0.0] # weights for [P, R, mAP, F1]@0.5 or [P, R, mAP@0.5:0.95, mAP@0.5] + w = [0.0, 0.01, 0.99, 0.00] # weights for [P, R, mAP, F1]@0.5 or [P, R, mAP@0.5, mAP@0.5:0.95] return (x[:, :4] * w).sum(1) From 8bc7648b388c0b9b4946c425e653bcebee4a3d59 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 8 Feb 2020 21:51:31 -0800 Subject: [PATCH 0390/1185] updates --- models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index 74bfe8e75a..2d267a9ca7 100755 --- a/models.py +++ b/models.py @@ -177,7 +177,7 @@ def forward(self, p, img_size, var=None): return p elif ONNX_EXPORT: - # Constants CAN NOT BE BROADCAST, ensure correct shape! + # Avoid broadcasting for ANE operations m = self.na * self.nx * self.ny grid_xy = self.grid_xy.repeat((1, self.na, 1, 1, 1)).view(m, 2) anchor_wh = self.anchor_wh.repeat((1, 1, self.nx, self.ny, 1)).view(m, 2) / self.ng @@ -187,7 +187,7 @@ def forward(self, p, img_size, var=None): wh = torch.exp(p[:, 2:4]) * anchor_wh # width, height p_cls = torch.sigmoid(p[:, 4:5]) if self.nc == 1 else \ torch.sigmoid(p[:, 5:self.no]) * torch.sigmoid(p[:, 4:5]) # conf - return p_cls, xy / self.ng, wh + return p_cls, xy / self.ng.repeat((m, 1)), wh else: # inference # s = 1.5 # scale_xy (pxy = pxy * s - (s - 1) / 2) From 8bc9f56564f94bc59dab5a2f22935bbdbeb5774e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 9 Feb 2020 09:12:45 -0800 Subject: [PATCH 0391/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 46bcdd116f..abf547b572 100644 --- a/train.py +++ b/train.py @@ -264,7 +264,7 @@ def train(): # Multi-Scale training if opt.multi_scale: - if ni / accumulate % 1 == 0: #  adjust (67% - 150%) every 10 batches + if ni / accumulate % 1 == 0: #  adjust img_size (67% - 150%) every 1 batch img_size = random.randrange(img_sz_min, img_sz_max + 1) * 32 sf = img_size / max(imgs.shape[2:]) # scale factor if sf != 1: From 0958d81580a8a0086ac3326feeba4f6db20b70a5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 9 Feb 2020 11:17:31 -0800 Subject: [PATCH 0392/1185] updates --- models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index 2d267a9ca7..edc3bf15a7 100755 --- a/models.py +++ b/models.py @@ -179,15 +179,16 @@ def forward(self, p, img_size, var=None): elif ONNX_EXPORT: # Avoid broadcasting for ANE operations m = self.na * self.nx * self.ny + ng = 1 / self.ng.repeat((m, 1)) grid_xy = self.grid_xy.repeat((1, self.na, 1, 1, 1)).view(m, 2) - anchor_wh = self.anchor_wh.repeat((1, 1, self.nx, self.ny, 1)).view(m, 2) / self.ng + anchor_wh = self.anchor_wh.repeat((1, 1, self.nx, self.ny, 1)).view(m, 2) * ng p = p.view(m, self.no) xy = torch.sigmoid(p[:, 0:2]) + grid_xy # x, y wh = torch.exp(p[:, 2:4]) * anchor_wh # width, height p_cls = torch.sigmoid(p[:, 4:5]) if self.nc == 1 else \ torch.sigmoid(p[:, 5:self.no]) * torch.sigmoid(p[:, 4:5]) # conf - return p_cls, xy / self.ng.repeat((m, 1)), wh + return p_cls, xy * ng, wh else: # inference # s = 1.5 # scale_xy (pxy = pxy * s - (s - 1) / 2) From ca22b5e40b1f845ef60683f0ba9d164b04f12f30 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 12 Feb 2020 14:27:31 -0800 Subject: [PATCH 0393/1185] save git info in docker images --- .dockerignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index a3dab6835e..5a2495bcb9 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,5 @@ # Repo-specific DockerIgnore ------------------------------------------------------------------------------------------- -.git +# .git .cache .idea runs From 11bcd0f9885ce548c7c123c611921fe63bebe592 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 12 Feb 2020 15:19:06 -0800 Subject: [PATCH 0394/1185] updates --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index b44772d100..baccd70bf2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,10 +47,10 @@ COPY . /usr/src/app # t=ultralytics/yolov3:v0 && sudo docker build -t $t . && sudo docker push $t # Run -# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run -it $t +# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run -it $t bash # Pull and Run with local directory access -# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run -it -v "$(pwd)"/coco:/usr/src/coco $t +# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run -it -v "$(pwd)"/coco:/usr/src/coco $t bash # Kill all # sudo docker kill "$(sudo docker ps -q)" From 740cd177dc5d1832c447ab85a6794720ea8e76da Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 14 Feb 2020 21:26:16 -0800 Subject: [PATCH 0395/1185] updates --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cdd8850a58..6dba20e421 100755 --- a/README.md +++ b/README.md @@ -148,10 +148,10 @@ python3 test.py --weights ... --cfg ... |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 --- | --- | --- | --- -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |320 |14.0
28.7
30.5
**35.5** |29.1
51.8
52.3
**55.4** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |416 |16.0
31.2
33.9
**39.2** |33.0
55.4
56.9
**59.9** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |512 |16.6
32.7
35.6
**40.5** |34.9
57.7
59.5
**61.4** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |608 |16.6
33.1
37.0
**41.1** |35.4
58.2
60.7
**61.5** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |320 |14.0
28.7
30.5
**35.6** |29.1
51.8
52.3
**55.4** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |416 |16.0
31.2
33.9
**39.1** |33.0
55.4
56.9
**59.6** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |512 |16.6
32.7
35.6
**40.6** |34.9
57.7
59.5
**61.4** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |608 |16.6
33.1
37.0
**41.1** |35.4
58.2
60.7
**61.7** ```bash $ python3 test.py --img-size 608 --iou-thr 0.6 --weights ultralytics68.pt --cfg yolov3-spp.cfg From 57798278ad8d21653cc9f7ea884eb6fe3ed87d0d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 14 Feb 2020 21:32:29 -0800 Subject: [PATCH 0396/1185] updates --- detect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detect.py b/detect.py index 889ca689d4..d3eff73968 100644 --- a/detect.py +++ b/detect.py @@ -45,7 +45,7 @@ def detect(save_img=False): if ONNX_EXPORT: model.fuse() img = torch.zeros((1, 3) + img_size) # (1, 3, 320, 192) - torch.onnx.export(model, img, 'weights/export.onnx', verbose=False, opset_version=10) + torch.onnx.export(model, img, 'weights/export.onnx', verbose=False, opset_version=11) # Validate exported model import onnx From e840b7c781fd37e465bf95635ca9551862af59ea Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 16 Feb 2020 23:12:07 -0800 Subject: [PATCH 0397/1185] add yolov3-spp-ultralytics.pt --- README.md | 42 +++++++++++++++++++++--------------------- detect.py | 2 +- models.py | 3 ++- test.py | 2 +- train.py | 2 +- utils/utils.py | 2 +- 6 files changed, 27 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 6dba20e421..9c083dd9c1 100755 --- a/README.md +++ b/README.md @@ -139,39 +139,39 @@ Success: converted 'weights/yolov3-spp.pt' to 'converted.weights' # mAP ```bash -python3 test.py --weights ... --cfg ... +$ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt ``` - mAP@0.5 run at `--iou-thr 0.5`, mAP@0.5...0.95 run at `--iou-thr 0.7` -- YOLOv3-SPP ultralytics is `ultralytics68.pt` with `yolov3-spp.cfg` - Darknet results: https://arxiv.org/abs/1804.02767 |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 --- | --- | --- | --- -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |320 |14.0
28.7
30.5
**35.6** |29.1
51.8
52.3
**55.4** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |416 |16.0
31.2
33.9
**39.1** |33.0
55.4
56.9
**59.6** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |512 |16.6
32.7
35.6
**40.6** |34.9
57.7
59.5
**61.4** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**YOLOv3-SPP ultralytics** |608 |16.6
33.1
37.0
**41.1** |35.4
58.2
60.7
**61.7** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**36.3** |29.1
51.8
52.3
**55.5** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**39.8** |33.0
55.4
56.9
**59.6** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**41.3** |34.9
57.7
59.5
**61.3** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**41.7** |35.4
58.2
60.7
**61.5** ```bash -$ python3 test.py --img-size 608 --iou-thr 0.6 --weights ultralytics68.pt --cfg yolov3-spp.cfg +$ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 608 -Namespace(batch_size=32, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, task='test', weights='ultralytics68.pt') -Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memory=16130MB) - Class Images Targets P R mAP@0.5 F1: 100% 157/157 [03:30<00:00, 1.16it/s] - all 5e+03 3.51e+04 0.0353 0.891 0.606 0.0673 - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.409 +Namespace(batch_size=32, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='last54.pt') +Using CUDA device0 _CudaDeviceProperties(name='Tesla P100-PCIE-16GB', total_memory=16280MB) + + Class Images Targets P R mAP@0.5 F1: 100% 157/157 [04:25<00:00, 1.04it/s] + all 5e+03 3.51e+04 0.0467 0.886 0.607 0.0875 + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.415 Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.615 - Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.437 - Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.242 - Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.448 - Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.519 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.337 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.557 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.612 - Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.438 + Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.443 + Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.245 + Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.458 + Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.531 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.341 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.559 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.611 + Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.441 Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.658 - Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.746 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.748 ``` # Reproduce Our Results diff --git a/detect.py b/detect.py index d3eff73968..ca6a3873f5 100644 --- a/detect.py +++ b/detect.py @@ -159,7 +159,7 @@ def detect(save_img=False): parser = argparse.ArgumentParser() parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') parser.add_argument('--names', type=str, default='data/coco.names', help='*.names path') - parser.add_argument('--weights', type=str, default='weights/ultralytics68.pt', help='path to weights file') + parser.add_argument('--weights', type=str, default='weights/yolov3-spp-ultralytics.pt', help='weights path') parser.add_argument('--source', type=str, default='data/samples', help='source') # input file/folder, 0 for webcam parser.add_argument('--output', type=str, default='output', help='output folder') # output folder parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') diff --git a/models.py b/models.py index edc3bf15a7..65f9545012 100755 --- a/models.py +++ b/models.py @@ -434,7 +434,8 @@ def attempt_download(weights): 'darknet53.conv.74': '1WUVBid-XuoUBmvzBVUCBl_ELrzqwA8dJ', 'yolov3-tiny.conv.15': '1Bw0kCpplxUqyRYAJr9RY9SGnOJbo9nEj', 'ultralytics49.pt': '158g62Vs14E3aj7oPVPuEnNZMKFNgGyNq', - 'ultralytics68.pt': '1Jm8kqnMdMGUUxGo8zMFZMJ0eaPwLkxSG'} + 'ultralytics68.pt': '1Jm8kqnMdMGUUxGo8zMFZMJ0eaPwLkxSG', + 'yolov3-spp-ultralytics.pt': '1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4'} file = Path(weights).name if file in d: diff --git a/test.py b/test.py index a5cec3b421..e1a8096776 100644 --- a/test.py +++ b/test.py @@ -210,7 +210,7 @@ def test(cfg, parser = argparse.ArgumentParser(prog='test.py') parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') parser.add_argument('--data', type=str, default='data/coco2014.data', help='*.data path') - parser.add_argument('--weights', type=str, default='weights/yolov3-spp.weights', help='path to weights file') + parser.add_argument('--weights', type=str, default='weights/yolov3-spp-ultralytics.pt', help='weights path') parser.add_argument('--batch-size', type=int, default=32, help='size of each image batch') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') diff --git a/train.py b/train.py index abf547b572..cb17b9466e 100644 --- a/train.py +++ b/train.py @@ -406,7 +406,7 @@ def train(): parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters') parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') - parser.add_argument('--weights', type=str, default='weights/ultralytics68.pt', help='initial weights') + parser.add_argument('--weights', type=str, default='weights/yolov3-spp-ultralytics.pt', help='initial weights path') parser.add_argument('--arc', type=str, default='default', help='yolo architecture') # default, uCE, uBCE parser.add_argument('--name', default='', help='renames results.txt to results_name.txt if supplied') parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1 or cpu)') diff --git a/utils/utils.py b/utils/utils.py index 85dd365823..f877a7ce18 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -369,7 +369,7 @@ def compute_loss(p, targets, model, giou_flag=True): # predictions, targets, mo tcls, tbox, indices, anchor_vec = build_targets(model, targets) h = model.hyp # hyperparameters arc = model.arc # # (default, uCE, uBCE) detection architectures - red = 'sum' # Loss reduction (sum or mean) + red = 'mean' # Loss reduction (sum or mean) # Define criteria BCEcls = nn.BCEWithLogitsLoss(pos_weight=ft([h['cls_pw']]), reduction=red) From cca620208eff32f40c857a2b6ea5d6bd7919264e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 16 Feb 2020 23:13:34 -0800 Subject: [PATCH 0398/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index cb17b9466e..917fbda8bd 100644 --- a/train.py +++ b/train.py @@ -25,7 +25,7 @@ hyp = {'giou': 3.54, # giou loss gain 'cls': 37.4, # cls loss gain 'cls_pw': 1.0, # cls BCELoss positive_weight - 'obj': 49.5, # obj loss gain (*=img_size/320 if img_size != 320) + 'obj': 64.3, # obj loss gain (*=img_size/320 if img_size != 320) 'obj_pw': 1.0, # obj BCELoss positive_weight 'iou_t': 0.225, # iou training threshold 'lr0': 0.00579, # initial learning rate (SGD=5E-3, Adam=5E-4) From 49d47adf17419fd8b9df6e5eeeed5870f19779bd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 16 Feb 2020 23:30:14 -0800 Subject: [PATCH 0399/1185] updates --- detect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detect.py b/detect.py index ca6a3873f5..22f927c23f 100644 --- a/detect.py +++ b/detect.py @@ -164,7 +164,7 @@ def detect(save_img=False): parser.add_argument('--output', type=str, default='output', help='output folder') # output folder parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.3, help='object confidence threshold') - parser.add_argument('--iou-thres', type=float, default=0.5, help='IOU threshold for NMS') + parser.add_argument('--iou-thres', type=float, default=0.6, help='IOU threshold for NMS') parser.add_argument('--fourcc', type=str, default='mp4v', help='output video codec (verify ffmpeg support)') parser.add_argument('--half', action='store_true', help='half precision FP16 inference') parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') From aa45dc05b349df002db601ab696c47b3a9094c6b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 16 Feb 2020 23:57:39 -0800 Subject: [PATCH 0400/1185] updates --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9c083dd9c1..7aa89f1ead 100755 --- a/README.md +++ b/README.md @@ -178,9 +178,9 @@ Using CUDA device0 _CudaDeviceProperties(name='Tesla P100-PCIE-16GB', total_memo This command trains `yolov3-spp.cfg` from scratch to our mAP above. Training takes about one week on a 2080Ti. ```bash -$ python3 train.py --weights '' --cfg yolov3-spp.cfg --epochs 273 --batch 16 --accum 4 --multi --pre +$ python3 train.py --weights '' --cfg yolov3-spp.cfg --epochs 273 --batch 16 --accum 4 --multi ``` - + # Reproduce Our Environment From 426d5b82c645b26ec7bbf5de35a2b447ca9bd596 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 17 Feb 2020 12:36:11 -0800 Subject: [PATCH 0401/1185] updates --- models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/models.py b/models.py index 65f9545012..69bf0c9b61 100755 --- a/models.py +++ b/models.py @@ -54,10 +54,10 @@ def create_modules(module_defs, img_size, arc): elif mdef['type'] == 'upsample': if ONNX_EXPORT: # explicitly state size, avoid scale_factor - g = (yolo_index + 1) * 2 # gain - modules = nn.Upsample(size=(10 * g, 6 * g), mode='nearest') # assume img_size = (320, 192) + g = (yolo_index + 1) * 2 / 32 # gain + modules = nn.Upsample(size=tuple(int(x * g) for x in img_size)) # img_size = (320, 192) else: - modules = nn.Upsample(scale_factor=int(mdef['stride']), mode='nearest') + modules = nn.Upsample(scale_factor=int(mdef['stride'])) elif mdef['type'] == 'route': # nn.Sequential() placeholder for 'route' layer layers = [int(x) for x in mdef['layers'].split(',')] From 9880dcd6cde81d277486b452dba266b23eeae0e6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 17 Feb 2020 15:10:11 -0800 Subject: [PATCH 0402/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 69bf0c9b61..a48f35d2fc 100755 --- a/models.py +++ b/models.py @@ -67,8 +67,8 @@ def create_modules(module_defs, img_size, arc): # modules = nn.Upsample(scale_factor=1/float(mdef[i+1]['stride']), mode='nearest') # reorg3d elif mdef['type'] == 'shortcut': # nn.Sequential() placeholder for 'shortcut' layer - filters = output_filters[int(mdef['from'])] layer = int(mdef['from']) + filters = output_filters[layer] routs.extend([i + layer if layer < 0 else layer]) elif mdef['type'] == 'reorg3d': # yolov3-spp-pan-scale From 45ce01f8597dfb8d26a6d41966c88e1e346234a2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 17 Feb 2020 15:28:11 -0800 Subject: [PATCH 0403/1185] updates --- models.py | 19 ++++++++++--------- utils/parse_config.py | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/models.py b/models.py index a48f35d2fc..f8ed9449f1 100755 --- a/models.py +++ b/models.py @@ -67,9 +67,9 @@ def create_modules(module_defs, img_size, arc): # modules = nn.Upsample(scale_factor=1/float(mdef[i+1]['stride']), mode='nearest') # reorg3d elif mdef['type'] == 'shortcut': # nn.Sequential() placeholder for 'shortcut' layer - layer = int(mdef['from']) - filters = output_filters[layer] - routs.extend([i + layer if layer < 0 else layer]) + layers = [int(x) for x in mdef['from'].split(',')] + filters = output_filters[layers[0]] + routs.extend([i + l if l < 0 else l for l in layers]) elif mdef['type'] == 'reorg3d': # yolov3-spp-pan-scale # torch.Size([16, 128, 104, 104]) @@ -239,10 +239,10 @@ def forward(self, x, var=None): mtype = mdef['type'] if mtype in ['convolutional', 'upsample', 'maxpool']: x = module(x) - elif mtype == 'route': + elif mtype == 'route': # concat layers = [int(x) for x in mdef['layers'].split(',')] if verbose: - print('route concatenating %s' % ([layer_outputs[i].shape for i in layers])) + print('route/concatenate %s' % ([layer_outputs[i].shape for i in layers])) if len(layers) == 1: x = layer_outputs[layers[0]] else: @@ -252,11 +252,12 @@ def forward(self, x, var=None): layer_outputs[layers[1]] = F.interpolate(layer_outputs[layers[1]], scale_factor=[0.5, 0.5]) x = torch.cat([layer_outputs[i] for i in layers], 1) # print(''), [print(layer_outputs[i].shape) for i in layers], print(x.shape) - elif mtype == 'shortcut': - j = int(mdef['from']) + elif mtype == 'shortcut': # sum + layers = [int(x) for x in mdef['from'].split(',')] if verbose: - print('shortcut adding layer %g-%s to %g-%s' % (j, layer_outputs[j].shape, i - 1, x.shape)) - x = x + layer_outputs[j] + print('shortcut/add %s' % ([layer_outputs[i].shape for i in layers])) + for j in layers: + x = x + layer_outputs[j] elif mtype == 'yolo': output.append(module(x, img_size)) layer_outputs.append(x if i in self.routs else []) diff --git a/utils/parse_config.py b/utils/parse_config.py index 5d3c20fb52..2516388a30 100644 --- a/utils/parse_config.py +++ b/utils/parse_config.py @@ -33,7 +33,7 @@ def parse_model_cfg(path): # Check all fields are supported supported = ['type', 'batch_normalize', 'filters', 'size', 'stride', 'pad', 'activation', 'layers', 'groups', 'from', 'mask', 'anchors', 'classes', 'num', 'jitter', 'ignore_thresh', 'truth_thresh', 'random', - 'stride_x', 'stride_y'] + 'stride_x', 'stride_y', 'weights_type', 'weights_normalization'] f = [] # fields for x in mdefs[1:]: From 4fa0a32d05fff126dcd171109b5ca1d2f3b37cb0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 17 Feb 2020 17:02:37 -0800 Subject: [PATCH 0404/1185] updates --- models.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/models.py b/models.py index f8ed9449f1..2c55c74cb5 100755 --- a/models.py +++ b/models.py @@ -70,6 +70,7 @@ def create_modules(module_defs, img_size, arc): layers = [int(x) for x in mdef['from'].split(',')] filters = output_filters[layers[0]] routs.extend([i + l if l < 0 else l for l in layers]) + # modules = weightedFeatureFusion(layers=layers) elif mdef['type'] == 'reorg3d': # yolov3-spp-pan-scale # torch.Size([16, 128, 104, 104]) @@ -117,6 +118,21 @@ def create_modules(module_defs, img_size, arc): return module_list, routs +class weightedFeatureFusion(nn.Module): # weighted sum of layers https://arxiv.org/abs/1911.09070 + def __init__(self, layers): + super(weightedFeatureFusion, self).__init__() + self.n = len(layers) # number of layers + self.layers = layers # layer indices + self.w = torch.nn.Parameter(torch.zeros(self.n + 1)) # layer weights + + def forward(self, x, outputs): + w = torch.sigmoid(self.w) * (2 / self.n) # sigmoid weights (0-1) + x = x * w[0] + for i in range(self.n): + x = x + outputs[self.layers[i]] * w[i + 1] + return x + + class SwishImplementation(torch.autograd.Function): @staticmethod def forward(ctx, i): @@ -253,6 +269,7 @@ def forward(self, x, var=None): x = torch.cat([layer_outputs[i] for i in layers], 1) # print(''), [print(layer_outputs[i].shape) for i in layers], print(x.shape) elif mtype == 'shortcut': # sum + # x = module(x, layer_outputs) # weightedFeatureFusion() layers = [int(x) for x in mdef['from'].split(',')] if verbose: print('shortcut/add %s' % ([layer_outputs[i].shape for i in layers])) From a971b33b746807e37c32bec988b74d5c50278fff Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 17 Feb 2020 17:34:40 -0800 Subject: [PATCH 0405/1185] updates --- utils/parse_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/parse_config.py b/utils/parse_config.py index 2516388a30..1a5d1126a2 100644 --- a/utils/parse_config.py +++ b/utils/parse_config.py @@ -33,7 +33,7 @@ def parse_model_cfg(path): # Check all fields are supported supported = ['type', 'batch_normalize', 'filters', 'size', 'stride', 'pad', 'activation', 'layers', 'groups', 'from', 'mask', 'anchors', 'classes', 'num', 'jitter', 'ignore_thresh', 'truth_thresh', 'random', - 'stride_x', 'stride_y', 'weights_type', 'weights_normalization'] + 'stride_x', 'stride_y', 'weights_type', 'weights_normalization', 'scale_x_y'] f = [] # fields for x in mdefs[1:]: From b022648716f5dbb0549747357928c0d865da2a1b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 18 Feb 2020 20:13:18 -0800 Subject: [PATCH 0406/1185] updates --- models.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/models.py b/models.py index 2c55c74cb5..abfbf98aec 100755 --- a/models.py +++ b/models.py @@ -118,19 +118,21 @@ def create_modules(module_defs, img_size, arc): return module_list, routs -class weightedFeatureFusion(nn.Module): # weighted sum of layers https://arxiv.org/abs/1911.09070 +class weightedFeatureFusion(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 def __init__(self, layers): super(weightedFeatureFusion, self).__init__() - self.n = len(layers) # number of layers + self.n = len(layers) + 1 # number of layers self.layers = layers # layer indices - self.w = torch.nn.Parameter(torch.zeros(self.n + 1)) # layer weights + self.w = torch.nn.Parameter(torch.zeros(self.n)) # layer weights def forward(self, x, outputs): w = torch.sigmoid(self.w) * (2 / self.n) # sigmoid weights (0-1) - x = x * w[0] - for i in range(self.n): - x = x + outputs[self.layers[i]] * w[i + 1] - return x + if self.n == 2: + return x * w[0] + outputs[self.layers[0]] * w[1] + elif self.n == 3: + return x * w[0] + outputs[self.layers[0]] * w[1] + outputs[self.layers[1]] * w[2] + else: + raise ValueError('weightedFeatureFusion() supports up to 3 layer inputs, %g attempted' % self.n) class SwishImplementation(torch.autograd.Function): From ddd892dc205c36c029ac9272e92be56fe654415b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 18 Feb 2020 21:04:58 -0800 Subject: [PATCH 0407/1185] updates --- utils/parse_config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/parse_config.py b/utils/parse_config.py index 1a5d1126a2..8f2a6773e2 100644 --- a/utils/parse_config.py +++ b/utils/parse_config.py @@ -33,7 +33,8 @@ def parse_model_cfg(path): # Check all fields are supported supported = ['type', 'batch_normalize', 'filters', 'size', 'stride', 'pad', 'activation', 'layers', 'groups', 'from', 'mask', 'anchors', 'classes', 'num', 'jitter', 'ignore_thresh', 'truth_thresh', 'random', - 'stride_x', 'stride_y', 'weights_type', 'weights_normalization', 'scale_x_y'] + 'stride_x', 'stride_y', 'weights_type', 'weights_normalization', 'scale_x_y', 'beta_nms', 'nms_kind', + 'iou_loss', 'iou_normalizer', 'cls_normalizer', 'iou_thresh'] f = [] # fields for x in mdefs[1:]: From f4a9e5cd5839d00163d135be0ea8c53984d864d8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 19 Feb 2020 12:59:56 -0800 Subject: [PATCH 0408/1185] updates --- models.py | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/models.py b/models.py index abfbf98aec..f425a9e9cf 100755 --- a/models.py +++ b/models.py @@ -70,7 +70,7 @@ def create_modules(module_defs, img_size, arc): layers = [int(x) for x in mdef['from'].split(',')] filters = output_filters[layers[0]] routs.extend([i + l if l < 0 else l for l in layers]) - # modules = weightedFeatureFusion(layers=layers) + modules = weightedFeatureFusion(layers=layers, weight='weights_type' in mdef) elif mdef['type'] == 'reorg3d': # yolov3-spp-pan-scale # torch.Size([16, 128, 104, 104]) @@ -119,20 +119,26 @@ def create_modules(module_defs, img_size, arc): class weightedFeatureFusion(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers): + def __init__(self, layers, weight=False): super(weightedFeatureFusion, self).__init__() self.n = len(layers) + 1 # number of layers self.layers = layers # layer indices - self.w = torch.nn.Parameter(torch.zeros(self.n)) # layer weights + self.weight = weight # apply weights boolean + if weight: + self.w = torch.nn.Parameter(torch.zeros(self.n)) # layer weights def forward(self, x, outputs): - w = torch.sigmoid(self.w) * (2 / self.n) # sigmoid weights (0-1) - if self.n == 2: - return x * w[0] + outputs[self.layers[0]] * w[1] - elif self.n == 3: - return x * w[0] + outputs[self.layers[0]] * w[1] + outputs[self.layers[1]] * w[2] + if self.weight: + w = torch.sigmoid(self.w) * (2 / self.n) # sigmoid weights (0-1) + if self.n == 2: + return x * w[0] + outputs[self.layers[0]] * w[1] + elif self.n == 3: + return x * w[0] + outputs[self.layers[0]] * w[1] + outputs[self.layers[1]] * w[2] else: - raise ValueError('weightedFeatureFusion() supports up to 3 layer inputs, %g attempted' % self.n) + if self.n == 2: + return x + outputs[self.layers[0]] + elif self.n == 3: + return x + outputs[self.layers[0]] + outputs[self.layers[1]] class SwishImplementation(torch.autograd.Function): @@ -257,6 +263,10 @@ def forward(self, x, var=None): mtype = mdef['type'] if mtype in ['convolutional', 'upsample', 'maxpool']: x = module(x) + elif mtype == 'shortcut': # sum + x = module(x, layer_outputs) # weightedFeatureFusion() + if verbose: + print('shortcut/add %s' % ([layer_outputs[i].shape for i in module.layers])) elif mtype == 'route': # concat layers = [int(x) for x in mdef['layers'].split(',')] if verbose: @@ -270,25 +280,18 @@ def forward(self, x, var=None): layer_outputs[layers[1]] = F.interpolate(layer_outputs[layers[1]], scale_factor=[0.5, 0.5]) x = torch.cat([layer_outputs[i] for i in layers], 1) # print(''), [print(layer_outputs[i].shape) for i in layers], print(x.shape) - elif mtype == 'shortcut': # sum - # x = module(x, layer_outputs) # weightedFeatureFusion() - layers = [int(x) for x in mdef['from'].split(',')] - if verbose: - print('shortcut/add %s' % ([layer_outputs[i].shape for i in layers])) - for j in layers: - x = x + layer_outputs[j] elif mtype == 'yolo': output.append(module(x, img_size)) layer_outputs.append(x if i in self.routs else []) if verbose: print(i, x.shape) - if self.training: + if self.training: # train return output - elif ONNX_EXPORT: + elif ONNX_EXPORT: # export x = [torch.cat(x, 0) for x in zip(*output)] return x[0], torch.cat(x[1:3], 1) # scores, boxes: 3780x80, 3780x4 - else: + else: # test io, p = zip(*output) # inference output, training output return torch.cat(io, 1), p From a9cbc28214f8022a096297ffe4fd0011fdd3da78 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 19 Feb 2020 14:57:58 -0800 Subject: [PATCH 0409/1185] updates --- models.py | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/models.py b/models.py index f425a9e9cf..5585c1d283 100755 --- a/models.py +++ b/models.py @@ -264,9 +264,9 @@ def forward(self, x, var=None): if mtype in ['convolutional', 'upsample', 'maxpool']: x = module(x) elif mtype == 'shortcut': # sum - x = module(x, layer_outputs) # weightedFeatureFusion() if verbose: - print('shortcut/add %s' % ([layer_outputs[i].shape for i in module.layers])) + print('shortcut/add %s + %s' % (x.shape, [layer_outputs[i].shape for i in module.layers])) + x = module(x, layer_outputs) # weightedFeatureFusion() elif mtype == 'route': # concat layers = [int(x) for x in mdef['layers'].split(',')] if verbose: @@ -354,38 +354,33 @@ def load_darknet_weights(self, weights, cutoff=-1): ptr = 0 for i, (mdef, module) in enumerate(zip(self.module_defs[:cutoff], self.module_list[:cutoff])): if mdef['type'] == 'convolutional': - conv_layer = module[0] + conv = module[0] if mdef['batch_normalize']: # Load BN bias, weights, running mean and running variance - bn_layer = module[1] - num_b = bn_layer.bias.numel() # Number of biases + bn = module[1] + nb = bn.bias.numel() # number of biases # Bias - bn_b = torch.from_numpy(weights[ptr:ptr + num_b]).view_as(bn_layer.bias) - bn_layer.bias.data.copy_(bn_b) - ptr += num_b + bn.bias.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.bias)) + ptr += nb # Weight - bn_w = torch.from_numpy(weights[ptr:ptr + num_b]).view_as(bn_layer.weight) - bn_layer.weight.data.copy_(bn_w) - ptr += num_b + bn.weight.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.weight)) + ptr += nb # Running Mean - bn_rm = torch.from_numpy(weights[ptr:ptr + num_b]).view_as(bn_layer.running_mean) - bn_layer.running_mean.data.copy_(bn_rm) - ptr += num_b + bn.running_mean.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.running_mean)) + ptr += nb # Running Var - bn_rv = torch.from_numpy(weights[ptr:ptr + num_b]).view_as(bn_layer.running_var) - bn_layer.running_var.data.copy_(bn_rv) - ptr += num_b + bn.running_var.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.running_var)) + ptr += nb else: # Load conv. bias - num_b = conv_layer.bias.numel() - conv_b = torch.from_numpy(weights[ptr:ptr + num_b]).view_as(conv_layer.bias) - conv_layer.bias.data.copy_(conv_b) - ptr += num_b + nb = conv.bias.numel() + conv_b = torch.from_numpy(weights[ptr:ptr + nb]).view_as(conv.bias) + conv.bias.data.copy_(conv_b) + ptr += nb # Load conv. weights - num_w = conv_layer.weight.numel() - conv_w = torch.from_numpy(weights[ptr:ptr + num_w]).view_as(conv_layer.weight) - conv_layer.weight.data.copy_(conv_w) - ptr += num_w + nw = conv.weight.numel() # number of weights + conv.weight.data.copy_(torch.from_numpy(weights[ptr:ptr + nw]).view_as(conv.weight)) + ptr += nw def save_weights(self, path='model.weights', cutoff=-1): From 00862e47ef0822914b1458eaad9d5909482ba6f8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 19 Feb 2020 15:16:00 -0800 Subject: [PATCH 0410/1185] updates --- models.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/models.py b/models.py index 5585c1d283..3e5947f42a 100755 --- a/models.py +++ b/models.py @@ -254,7 +254,7 @@ def __init__(self, cfg, img_size=(416, 416), arc='default'): def forward(self, x, var=None): img_size = x.shape[-2:] - output, layer_outputs = [], [] + yolo_out, out = [], [] verbose = False if verbose: print('0', x.shape) @@ -265,34 +265,34 @@ def forward(self, x, var=None): x = module(x) elif mtype == 'shortcut': # sum if verbose: - print('shortcut/add %s + %s' % (x.shape, [layer_outputs[i].shape for i in module.layers])) - x = module(x, layer_outputs) # weightedFeatureFusion() + print('shortcut/add %s + %s' % (list(x.shape), [list(out[i].shape) for i in module.layers])) + x = module(x, out) # weightedFeatureFusion() elif mtype == 'route': # concat layers = [int(x) for x in mdef['layers'].split(',')] if verbose: - print('route/concatenate %s' % ([layer_outputs[i].shape for i in layers])) + print('route/concatenate %s + %s' % (list(x.shape), [list(out[i].shape) for i in layers])) if len(layers) == 1: - x = layer_outputs[layers[0]] + x = out[layers[0]] else: try: - x = torch.cat([layer_outputs[i] for i in layers], 1) + x = torch.cat([out[i] for i in layers], 1) except: # apply stride 2 for darknet reorg layer - layer_outputs[layers[1]] = F.interpolate(layer_outputs[layers[1]], scale_factor=[0.5, 0.5]) - x = torch.cat([layer_outputs[i] for i in layers], 1) - # print(''), [print(layer_outputs[i].shape) for i in layers], print(x.shape) + out[layers[1]] = F.interpolate(out[layers[1]], scale_factor=[0.5, 0.5]) + x = torch.cat([out[i] for i in layers], 1) + # print(''), [print(out[i].shape) for i in layers], print(x.shape) elif mtype == 'yolo': - output.append(module(x, img_size)) - layer_outputs.append(x if i in self.routs else []) + yolo_out.append(module(x, img_size)) + out.append(x if i in self.routs else []) if verbose: - print(i, x.shape) + print(i, list(x.shape)) if self.training: # train - return output + return yolo_out elif ONNX_EXPORT: # export - x = [torch.cat(x, 0) for x in zip(*output)] + x = [torch.cat(x, 0) for x in zip(*yolo_out)] return x[0], torch.cat(x[1:3], 1) # scores, boxes: 3780x80, 3780x4 else: # test - io, p = zip(*output) # inference output, training output + io, p = zip(*yolo_out) # inference output, training output return torch.cat(io, 1), p def fuse(self): From f92ad043bd0bd2e06265bc6099d4300fcc4780db Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 19 Feb 2020 16:05:57 -0800 Subject: [PATCH 0411/1185] updates --- models.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/models.py b/models.py index 3e5947f42a..4de0ad9779 100755 --- a/models.py +++ b/models.py @@ -121,24 +121,34 @@ def create_modules(module_defs, img_size, arc): class weightedFeatureFusion(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 def __init__(self, layers, weight=False): super(weightedFeatureFusion, self).__init__() - self.n = len(layers) + 1 # number of layers self.layers = layers # layer indices self.weight = weight # apply weights boolean + self.n = len(layers) + 1 # number of layers if weight: self.w = torch.nn.Parameter(torch.zeros(self.n)) # layer weights def forward(self, x, outputs): + # Weights if self.weight: w = torch.sigmoid(self.w) * (2 / self.n) # sigmoid weights (0-1) - if self.n == 2: - return x * w[0] + outputs[self.layers[0]] * w[1] - elif self.n == 3: - return x * w[0] + outputs[self.layers[0]] * w[1] + outputs[self.layers[1]] * w[2] - else: - if self.n == 2: - return x + outputs[self.layers[0]] - elif self.n == 3: - return x + outputs[self.layers[0]] + outputs[self.layers[1]] + x = x * w[0] + + # Fusion + nc = x.shape[1] # number of channels + for i in range(self.n - 1): + a = outputs[self.layers[i]] # feature to add + dc = nc - a.shape[1] # delta channels + + # Adjust channels + if dc > 0: # pad + pad = nn.ZeroPad2d((0, 0, 0, 0, 0, dc)) + a = pad(a) + elif dc < 0: # slice + a = a[:, :nc] + + # Sum + x = x + a * w[i + 1] if self.weight else x + a + return x class SwishImplementation(torch.autograd.Function): From 6fbab656c82f5539538125022292b1e8ed71e375 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 19 Feb 2020 17:08:03 -0800 Subject: [PATCH 0412/1185] updates --- models.py | 31 +++++++++++++++---------------- utils/parse_config.py | 10 ++++++++-- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/models.py b/models.py index 4de0ad9779..9e57a68f76 100755 --- a/models.py +++ b/models.py @@ -22,17 +22,16 @@ def create_modules(module_defs, img_size, arc): # modules.add_module('BatchNorm2d_0', nn.BatchNorm2d(output_filters[-1], momentum=0.1)) if mdef['type'] == 'convolutional': - bn = int(mdef['batch_normalize']) - filters = int(mdef['filters']) - size = int(mdef['size']) - stride = int(mdef['stride']) if 'stride' in mdef else (int(mdef['stride_y']), int(mdef['stride_x'])) - pad = (size - 1) // 2 if int(mdef['pad']) else 0 + bn = mdef['batch_normalize'] + filters = mdef['filters'] + size = mdef['size'] + stride = mdef['stride'] if 'stride' in mdef else (mdef['stride_y'], mdef['stride_x']) modules.add_module('Conv2d', nn.Conv2d(in_channels=output_filters[-1], out_channels=filters, kernel_size=size, stride=stride, - padding=pad, - groups=int(mdef['groups']) if 'groups' in mdef else 1, + padding=(size - 1) // 2 if mdef['pad'] else 0, + groups=mdef['groups'] if 'groups' in mdef else 1, bias=not bn)) if bn: modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.1)) @@ -43,9 +42,9 @@ def create_modules(module_defs, img_size, arc): modules.add_module('activation', Swish()) elif mdef['type'] == 'maxpool': - size = int(mdef['size']) - stride = int(mdef['stride']) - maxpool = nn.MaxPool2d(kernel_size=size, stride=stride, padding=int((size - 1) // 2)) + size = mdef['size'] + stride = mdef['stride'] + maxpool = nn.MaxPool2d(kernel_size=size, stride=stride, padding=(size - 1) // 2) if size == 2 and stride == 1: # yolov3-tiny modules.add_module('ZeroPad2d', nn.ZeroPad2d((0, 1, 0, 1))) modules.add_module('MaxPool2d', maxpool) @@ -57,17 +56,17 @@ def create_modules(module_defs, img_size, arc): g = (yolo_index + 1) * 2 / 32 # gain modules = nn.Upsample(size=tuple(int(x * g) for x in img_size)) # img_size = (320, 192) else: - modules = nn.Upsample(scale_factor=int(mdef['stride'])) + modules = nn.Upsample(scale_factor=mdef['stride']) elif mdef['type'] == 'route': # nn.Sequential() placeholder for 'route' layer - layers = [int(x) for x in mdef['layers'].split(',')] + layers = mdef['layers'] filters = sum([output_filters[i + 1 if i > 0 else i] for i in layers]) routs.extend([l if l > 0 else l + i for l in layers]) # if mdef[i+1]['type'] == 'reorg3d': # modules = nn.Upsample(scale_factor=1/float(mdef[i+1]['stride']), mode='nearest') # reorg3d elif mdef['type'] == 'shortcut': # nn.Sequential() placeholder for 'shortcut' layer - layers = [int(x) for x in mdef['from'].split(',')] + layers = mdef['from'] filters = output_filters[layers[0]] routs.extend([i + l if l < 0 else l for l in layers]) modules = weightedFeatureFusion(layers=layers, weight='weights_type' in mdef) @@ -79,9 +78,9 @@ def create_modules(module_defs, img_size, arc): elif mdef['type'] == 'yolo': yolo_index += 1 - mask = [int(x) for x in mdef['mask'].split(',')] # anchor mask + mask = mdef['mask'] # anchor mask modules = YOLOLayer(anchors=mdef['anchors'][mask], # anchor list - nc=int(mdef['classes']), # number of classes + nc=mdef['classes'], # number of classes img_size=img_size, # (416, 416) yolo_index=yolo_index, # 0, 1 or 2 arc=arc) # yolo architecture @@ -278,7 +277,7 @@ def forward(self, x, var=None): print('shortcut/add %s + %s' % (list(x.shape), [list(out[i].shape) for i in module.layers])) x = module(x, out) # weightedFeatureFusion() elif mtype == 'route': # concat - layers = [int(x) for x in mdef['layers'].split(',')] + layers = mdef['layers'] if verbose: print('route/concatenate %s + %s' % (list(x.shape), [list(out[i].shape) for i in layers])) if len(layers) == 1: diff --git a/utils/parse_config.py b/utils/parse_config.py index 8f2a6773e2..36ea42d7be 100644 --- a/utils/parse_config.py +++ b/utils/parse_config.py @@ -25,10 +25,16 @@ def parse_model_cfg(path): key, val = line.split("=") key = key.rstrip() - if 'anchors' in key: + if key == 'anchors': # return nparray mdefs[-1][key] = np.array([float(x) for x in val.split(',')]).reshape((-1, 2)) # np anchors + elif key in ['from', 'layers', 'mask']: # return array + mdefs[-1][key] = [int(x) for x in val.split(',')] else: - mdefs[-1][key] = val.strip() + val = val.strip() + if val.isnumeric(): # return int or float + mdefs[-1][key] = int(val) if (int(val) - float(val)) == 0 else float(val) + else: + mdefs[-1][key] = val # return string # Check all fields are supported supported = ['type', 'batch_normalize', 'filters', 'size', 'stride', 'pad', 'activation', 'layers', 'groups', From 7f1b2bfe088ce4d2029ea782f7bb32f78969761c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 19 Feb 2020 18:06:53 -0800 Subject: [PATCH 0413/1185] updates --- models.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index 9e57a68f76..149b0c1e5e 100755 --- a/models.py +++ b/models.py @@ -274,7 +274,9 @@ def forward(self, x, var=None): x = module(x) elif mtype == 'shortcut': # sum if verbose: - print('shortcut/add %s + %s' % (list(x.shape), [list(out[i].shape) for i in module.layers])) + l = [i] + module.layers # layers + s = [list(x.shape)] + [list(out[i].shape) for i in module.layers] # shapes + print('shortcut/add: ' + ' + '.join(['layer %g %s' % x for x in zip(l, s)])) x = module(x, out) # weightedFeatureFusion() elif mtype == 'route': # concat layers = mdef['layers'] @@ -293,7 +295,7 @@ def forward(self, x, var=None): yolo_out.append(module(x, img_size)) out.append(x if i in self.routs else []) if verbose: - print(i, list(x.shape)) + print('%g/%g -' % (i, len(self.module_list)), list(x.shape)) if self.training: # train return yolo_out From 1043832493c01a50a7f5318e84405b978a1daa0a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 19 Feb 2020 18:26:45 -0800 Subject: [PATCH 0414/1185] updates --- models.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/models.py b/models.py index 149b0c1e5e..0e9aa117a4 100755 --- a/models.py +++ b/models.py @@ -67,7 +67,7 @@ def create_modules(module_defs, img_size, arc): elif mdef['type'] == 'shortcut': # nn.Sequential() placeholder for 'shortcut' layer layers = mdef['from'] - filters = output_filters[layers[0]] + filters = output_filters[-1] routs.extend([i + l if l < 0 else l for l in layers]) modules = weightedFeatureFusion(layers=layers, weight='weights_type' in mdef) @@ -266,6 +266,7 @@ def forward(self, x, var=None): yolo_out, out = [], [] verbose = False if verbose: + str = '' print('0', x.shape) for i, (mdef, module) in enumerate(zip(self.module_defs, self.module_list)): @@ -274,14 +275,16 @@ def forward(self, x, var=None): x = module(x) elif mtype == 'shortcut': # sum if verbose: - l = [i] + module.layers # layers + l = [i - 1] + module.layers # layers s = [list(x.shape)] + [list(out[i].shape) for i in module.layers] # shapes - print('shortcut/add: ' + ' + '.join(['layer %g %s' % x for x in zip(l, s)])) + str = ' >> ' + ' + '.join(['layer %g %s' % x for x in zip(l, s)]) x = module(x, out) # weightedFeatureFusion() elif mtype == 'route': # concat layers = mdef['layers'] if verbose: - print('route/concatenate %s + %s' % (list(x.shape), [list(out[i].shape) for i in layers])) + l = [i - 1] + layers # layers + s = [list(x.shape)] + [list(out[i].shape) for i in layers] # shapes + str = ' >> ' + ' + '.join(['layer %g %s' % x for x in zip(l, s)]) if len(layers) == 1: x = out[layers[0]] else: @@ -295,7 +298,8 @@ def forward(self, x, var=None): yolo_out.append(module(x, img_size)) out.append(x if i in self.routs else []) if verbose: - print('%g/%g -' % (i, len(self.module_list)), list(x.shape)) + print('%g/%g %s -' % (i, len(self.module_list), mtype), list(x.shape), str) + str = '' if self.training: # train return yolo_out From 328ad4da0402c69563f7112995eec00496a3ea24 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 19 Feb 2020 18:37:17 -0800 Subject: [PATCH 0415/1185] updates --- models.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/models.py b/models.py index 0e9aa117a4..7a870e0ae2 100755 --- a/models.py +++ b/models.py @@ -140,8 +140,7 @@ def forward(self, x, outputs): # Adjust channels if dc > 0: # pad - pad = nn.ZeroPad2d((0, 0, 0, 0, 0, dc)) - a = pad(a) + a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a) elif dc < 0: # slice a = a[:, :nc] From afbc2f8d78530cf72d5809f95c410c8e6ed61964 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 21 Feb 2020 15:10:50 -0800 Subject: [PATCH 0416/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index f877a7ce18..17a949e8dc 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -1023,7 +1023,7 @@ def plot_results_overlay(start=0, stop=0): # from utils.utils import *; plot_re def plot_results(start=0, stop=0, bucket='', id=()): # from utils.utils import *; plot_results() # Plot training results files 'results*.txt' - fig, ax = plt.subplots(2, 5, figsize=(14, 7)) + fig, ax = plt.subplots(2, 5, figsize=(12, 6)) ax = ax.ravel() s = ['GIoU', 'Objectness', 'Classification', 'Precision', 'Recall', 'val GIoU', 'val Objectness', 'val Classification', 'mAP@0.5', 'F1'] From fa8882c98e68f30fe917c4115baf532da6ee94d4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 21 Feb 2020 15:11:11 -0800 Subject: [PATCH 0417/1185] updates --- utils/gcp.sh | 333 ++++++++++++++++++++++++++++----------------------- 1 file changed, 185 insertions(+), 148 deletions(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index 07a5b10018..433c248df9 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -9,6 +9,7 @@ sudo conda install -yc conda-forge scikit-image pycocotools python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('193Zp_ye-3qXMonR1nZj3YyxMtQkMy50k','coco2014.zip')" python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1C3HewOG9akA3y456SZLBJZfNDPkBwAto','knife.zip')" python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('13g3LqdpkNE8sPosVJT6KFXlfoMypzRP4','sm4.zip')" +sudo shutdown # Re-clone rm -rf yolov3 # Warning: remove existing @@ -66,14 +67,18 @@ done # Evolve coco sudo -s -t=ultralytics/yolov3:v189 -docker kill $(docker ps -a -q --filter ancestor=$t) -for i in 0 1 +t=ultralytics/yolov3:evolve +# docker kill $(docker ps -a -q --filter ancestor=$t) +for i in 0 1 6 7 do docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i sleep 30 done + +t=ultralytics/yolov3:evolve && docker pull $t && docker run --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh 2 + + # Git pull git pull https://github.com/ultralytics/yolov3 # master git pull https://github.com/ultralytics/yolov3 test # branch @@ -129,160 +134,158 @@ rm -rf darknet && git clone https://github.com/AlexeyAB/darknet && cd darknet && #Docker sudo docker kill "$(sudo docker ps -q)" sudo docker pull ultralytics/yolov3:v0 -sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco ultralytics/yolov3:v0 +sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco ultralytics/yolov3:v0 -t=ultralytics/yolov3:v70 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 70 --device 0 --multi -t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 71 --device 0 --multi --img-weights +t=ultralytics/yolov3:v70 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 32 --accum 2 --pre --bucket yolov4 --name 70 --device 0 --multi +t=ultralytics/yolov3:v73 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 73 --device 5 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v74 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 74 --device 0 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v75 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 75 --device 7 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v76 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 76 --device 0 --cfg cfg/yolov3-spp.cfg -t=ultralytics/yolov3:v73 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 73 --device 5 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v74 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 74 --device 0 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v75 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 75 --device 7 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v76 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 76 --device 0 --cfg cfg/yolov3-spp.cfg +t=ultralytics/yolov3:v79 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 79 --device 5 +t=ultralytics/yolov3:v80 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 80 --device 0 +t=ultralytics/yolov3:v81 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 81 --device 7 +t=ultralytics/yolov3:v82 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 82 --device 0 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v79 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 79 --device 5 -t=ultralytics/yolov3:v80 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 80 --device 0 -t=ultralytics/yolov3:v81 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 81 --device 7 -t=ultralytics/yolov3:v82 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 82 --device 0 --cfg cfg/yolov3s.cfg +t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 83 --device 6 --multi --nosave +t=ultralytics/yolov3:v84 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 84 --device 0 --multi +t=ultralytics/yolov3:v85 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 85 --device 0 --multi +t=ultralytics/yolov3:v86 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 86 --device 1 --multi +t=ultralytics/yolov3:v87 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 87 --device 2 --multi +t=ultralytics/yolov3:v88 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 88 --device 3 --multi +t=ultralytics/yolov3:v89 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 89 --device 1 +t=ultralytics/yolov3:v90 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 90 --device 0 --cfg cfg/yolov3-spp-matrix.cfg +t=ultralytics/yolov3:v91 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 91 --device 0 --cfg cfg/yolov3-spp-matrix.cfg -t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 83 --device 6 --multi --nosave -t=ultralytics/yolov3:v84 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 84 --device 0 --multi -t=ultralytics/yolov3:v85 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 85 --device 0 --multi -t=ultralytics/yolov3:v86 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 86 --device 1 --multi -t=ultralytics/yolov3:v87 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 87 --device 2 --multi -t=ultralytics/yolov3:v88 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 88 --device 3 --multi -t=ultralytics/yolov3:v89 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 89 --device 1 -t=ultralytics/yolov3:v90 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 90 --device 0 --cfg cfg/yolov3-spp-matrix.cfg -t=ultralytics/yolov3:v91 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 91 --device 0 --cfg cfg/yolov3-spp-matrix.cfg - -t=ultralytics/yolov3:v92 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 92 --device 0 -t=ultralytics/yolov3:v93 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 93 --device 0 --cfg cfg/yolov3-spp-matrix.cfg +t=ultralytics/yolov3:v92 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 92 --device 0 +t=ultralytics/yolov3:v93 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 93 --device 0 --cfg cfg/yolov3-spp-matrix.cfg #SM4 -t=ultralytics/yolov3:v96 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 96 --device 0 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -t=ultralytics/yolov3:v97 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 97 --device 4 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -t=ultralytics/yolov3:v98 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 16 --accum 4 --pre --bucket yolov4 --name 98 --device 5 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --pre --bucket yolov4 --name 101 --device 7 --multi --nosave - -t=ultralytics/yolov3:v102 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 1000 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 102 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v103 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 103 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v104 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 104 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v105 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 105 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v106 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 106 --device 0 --cfg cfg/yolov3-tiny-3cls-sm4.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v107 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 107 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg -t=ultralytics/yolov3:v108 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 108 --device 7 --nosave - -t=ultralytics/yolov3:v109 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 109 --device 4 --multi --nosave -t=ultralytics/yolov3:v110 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 110 --device 3 --multi --nosave - -t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 111 --device 0 -t=ultralytics/yolov3:v112 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 112 --device 1 --nosave -t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 113 --device 2 --nosave -t=ultralytics/yolov3:v114 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 114 --device 2 --nosave -t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 115 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg -t=ultralytics/yolov3:v116 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 116 --device 1 --nosave - -t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 117 --device 0 --nosave --multi -t=ultralytics/yolov3:v118 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 118 --device 5 --nosave --multi -t=ultralytics/yolov3:v119 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 119 --device 1 --nosave -t=ultralytics/yolov3:v120 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 120 --device 2 --nosave -t=ultralytics/yolov3:v121 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 121 --device 0 --nosave --cfg cfg/csresnext50-panet-spp.cfg -t=ultralytics/yolov3:v122 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 122 --device 2 --nosave -t=ultralytics/yolov3:v123 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 123 --device 5 --nosave - -t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 124 --device 0 --nosave --cfg yolov3-tiny -t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 125 --device 1 --nosave --cfg yolov3-tiny2 -t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 126 --device 1 --nosave --cfg yolov3-tiny3 -t=ultralytics/yolov3:v127 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 127 --device 0 --nosave --cfg yolov3-tiny4 -t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 128 --device 1 --nosave --cfg yolov3-tiny2 --multi -t=ultralytics/yolov3:v129 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 129 --device 0 --nosave --cfg yolov3-tiny2 - -t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 130 --device 0 --nosave -t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 250 --pre --bucket yolov4 --name 131 --device 0 --nosave --multi -t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 132 --device 0 --nosave --data coco2014.data -t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 27 --pre --bucket yolov4 --name 133 --device 0 --nosave --multi -t=ultralytics/yolov3:v134 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 134 --device 0 --nosave --data coco2014.data - -t=ultralytics/yolov3:v135 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 135 --device 0 --nosave --multi --data coco2014.data -t=ultralytics/yolov3:v136 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 136 --device 0 --nosave --multi --data coco2014.data - -t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 137 --device 7 --nosave --data coco2014.data -t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --bucket yolov4 --name 138 --device 6 --nosave --data coco2014.data - -t=ultralytics/yolov3:v140 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 140 --device 1 --nosave --data coco2014.data --arc uBCE -t=ultralytics/yolov3:v141 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 141 --device 0 --nosave --data coco2014.data --arc uBCE -t=ultralytics/yolov3:v142 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 142 --device 1 --nosave --data coco2014.data --arc uBCE - -t=ultralytics/yolov3:v146 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 146 --device 0 --nosave --data coco2014.data -t=ultralytics/yolov3:v147 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 147 --device 1 --nosave --data coco2014.data -t=ultralytics/yolov3:v148 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 148 --device 2 --nosave --data coco2014.data -t=ultralytics/yolov3:v149 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 149 --device 3 --nosave --data coco2014.data -t=ultralytics/yolov3:v150 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 150 --device 4 --nosave --data coco2014.data -t=ultralytics/yolov3:v151 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 151 --device 5 --nosave --data coco2014.data -t=ultralytics/yolov3:v152 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 152 --device 6 --nosave --data coco2014.data -t=ultralytics/yolov3:v153 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 153 --device 7 --nosave --data coco2014.data - -t=ultralytics/yolov3:v154 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 154 --device 0 --nosave --data coco2014.data -t=ultralytics/yolov3:v155 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 155 --device 0 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v156 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 156 --device 5 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v157 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 157 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v158 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 158 --device 7 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v159 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 159 --device 0 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v160 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 160 --device 1 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v161 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 161 --device 2 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v162 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 162 --device 3 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v163 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 163 --device 4 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v164 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 164 --device 5 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v165 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 165 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v166 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 166 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v167 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 167 --device 7 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v168 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 168 --device 5 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v169 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 169 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v170 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 170 --device 7 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v171 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 171 --device 4 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v172 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 172 --device 3 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v173 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 173 --device 2 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v174 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 174 --device 1 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v175 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 175 --device 0 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v177 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 177 --device 0 --nosave --data coco2014.data --multi -t=ultralytics/yolov3:v178 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 178 --device 0 --nosave --data coco2014.data --multi -t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 179 --device 0 --nosave --data coco2014.data --multi --cfg yolov3s-18a.cfg +t=ultralytics/yolov3:v96 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 96 --device 0 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +t=ultralytics/yolov3:v97 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 97 --device 4 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +t=ultralytics/yolov3:v98 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 16 --accum 4 --pre --bucket yolov4 --name 98 --device 5 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave +t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --pre --bucket yolov4 --name 101 --device 7 --multi --nosave + +t=ultralytics/yolov3:v102 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 1000 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 102 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v103 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 103 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v104 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 104 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v105 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 105 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v106 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 106 --device 0 --cfg cfg/yolov3-tiny-3cls-sm4.cfg --data ../data/sm4/out.data --nosave --cache +t=ultralytics/yolov3:v107 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 107 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg +t=ultralytics/yolov3:v108 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 108 --device 7 --nosave + +t=ultralytics/yolov3:v109 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 109 --device 4 --multi --nosave +t=ultralytics/yolov3:v110 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 110 --device 3 --multi --nosave + +t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 111 --device 0 +t=ultralytics/yolov3:v112 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 112 --device 1 --nosave +t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 113 --device 2 --nosave +t=ultralytics/yolov3:v114 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 114 --device 2 --nosave +t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 115 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg +t=ultralytics/yolov3:v116 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 116 --device 1 --nosave + +t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 117 --device 0 --nosave --multi +t=ultralytics/yolov3:v118 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 118 --device 5 --nosave --multi +t=ultralytics/yolov3:v119 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 119 --device 1 --nosave +t=ultralytics/yolov3:v120 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 120 --device 2 --nosave +t=ultralytics/yolov3:v121 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 121 --device 0 --nosave --cfg cfg/csresnext50-panet-spp.cfg +t=ultralytics/yolov3:v122 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 122 --device 2 --nosave +t=ultralytics/yolov3:v123 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 123 --device 5 --nosave + +t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 124 --device 0 --nosave --cfg yolov3-tiny +t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 125 --device 1 --nosave --cfg yolov3-tiny2 +t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 126 --device 1 --nosave --cfg yolov3-tiny3 +t=ultralytics/yolov3:v127 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 127 --device 0 --nosave --cfg yolov3-tiny4 +t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 128 --device 1 --nosave --cfg yolov3-tiny2 --multi +t=ultralytics/yolov3:v129 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 129 --device 0 --nosave --cfg yolov3-tiny2 + +t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 130 --device 0 --nosave +t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 250 --pre --bucket yolov4 --name 131 --device 0 --nosave --multi +t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 132 --device 0 --nosave --data coco2014.data +t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 27 --pre --bucket yolov4 --name 133 --device 0 --nosave --multi +t=ultralytics/yolov3:v134 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 134 --device 0 --nosave --data coco2014.data + +t=ultralytics/yolov3:v135 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 135 --device 0 --nosave --multi --data coco2014.data +t=ultralytics/yolov3:v136 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 136 --device 0 --nosave --multi --data coco2014.data + +t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 137 --device 7 --nosave --data coco2014.data +t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --bucket yolov4 --name 138 --device 6 --nosave --data coco2014.data + +t=ultralytics/yolov3:v140 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 140 --device 1 --nosave --data coco2014.data --arc uBCE +t=ultralytics/yolov3:v141 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 141 --device 0 --nosave --data coco2014.data --arc uBCE +t=ultralytics/yolov3:v142 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 142 --device 1 --nosave --data coco2014.data --arc uBCE + +t=ultralytics/yolov3:v146 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 146 --device 0 --nosave --data coco2014.data +t=ultralytics/yolov3:v147 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 147 --device 1 --nosave --data coco2014.data +t=ultralytics/yolov3:v148 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 148 --device 2 --nosave --data coco2014.data +t=ultralytics/yolov3:v149 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 149 --device 3 --nosave --data coco2014.data +t=ultralytics/yolov3:v150 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 150 --device 4 --nosave --data coco2014.data +t=ultralytics/yolov3:v151 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 151 --device 5 --nosave --data coco2014.data +t=ultralytics/yolov3:v152 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 152 --device 6 --nosave --data coco2014.data +t=ultralytics/yolov3:v153 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 153 --device 7 --nosave --data coco2014.data + +t=ultralytics/yolov3:v154 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 154 --device 0 --nosave --data coco2014.data +t=ultralytics/yolov3:v155 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 155 --device 0 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v156 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 156 --device 5 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v157 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 157 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v158 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 158 --device 7 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v159 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 159 --device 0 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v160 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 160 --device 1 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v161 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 161 --device 2 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v162 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 162 --device 3 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v163 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 163 --device 4 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v164 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 164 --device 5 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v165 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 165 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v166 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 166 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v167 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 167 --device 7 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v168 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 168 --device 5 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v169 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 169 --device 6 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v170 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 170 --device 7 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v171 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 171 --device 4 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v172 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 172 --device 3 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v173 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 173 --device 2 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v174 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 174 --device 1 --nosave --data coco2014.data --arc defaultpw +t=ultralytics/yolov3:v175 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 175 --device 0 --nosave --data coco2014.data --arc defaultpw + +t=ultralytics/yolov3:v177 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 177 --device 0 --nosave --data coco2014.data --multi +t=ultralytics/yolov3:v178 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 178 --device 0 --nosave --data coco2014.data --multi +t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 179 --device 0 --nosave --data coco2014.data --multi --cfg yolov3s-18a.cfg t=ultralytics/yolov3:v143 && sudo docker build -t $t . && sudo docker push $t -t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 179 -t=ultralytics/yolov3:v180 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 180 -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 181 --cfg yolov3s9a-640.cfg -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 182 --cfg yolov3s9a-320-640.cfg -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 183 --cfg yolov3s15a-640.cfg -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 184 --cfg yolov3s15a-320-640.cfg +t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 179 +t=ultralytics/yolov3:v180 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 180 +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 181 --cfg yolov3s9a-640.cfg +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 182 --cfg yolov3s9a-320-640.cfg +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 183 --cfg yolov3s15a-640.cfg +t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 184 --cfg yolov3s15a-320-640.cfg -t=ultralytics/yolov3:v185 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 185 -t=ultralytics/yolov3:v186 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 186 -n=187 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -t=ultralytics/yolov3:v189 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 188 --cfg yolov3s15a-320-640.cfg -n=190 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=191 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=192 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +t=ultralytics/yolov3:v185 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 185 +t=ultralytics/yolov3:v186 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 186 +n=187 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +t=ultralytics/yolov3:v189 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 188 --cfg yolov3s15a-320-640.cfg +n=190 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=191 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=192 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=193 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=194 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=195 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=196 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=193 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=194 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=195 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=196 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=197 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=198 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=197 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n +n=198 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n # athena -n=199 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 0 -n=200 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 6 -n=207 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo nvidia-docker run -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 7 +n=199 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 0 +n=200 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 6 +n=207 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 7 n=208 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 n=211 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg n=212 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg @@ -320,11 +323,11 @@ n=255 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -it # wer -n=201 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 0 --cfg yolov3-tiny-3cls.cfg -n=202 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 1 --cfg yolov3-tiny-3cls-sm4.cfg -n=203 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 2 --cfg yolov3-tiny-3cls-sm4.cfg -n=204 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo nvidia-docker run -d -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 3 --cfg yolov3-tiny-3cls-sm4.cfg -n=205 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo nvidia-docker run -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 4 --cfg yolov3-tiny-3cls-sm4.cfg +n=201 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 0 --cfg yolov3-tiny-3cls.cfg +n=202 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 1 --cfg yolov3-tiny-3cls-sm4.cfg +n=203 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 2 --cfg yolov3-tiny-3cls-sm4.cfg +n=204 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 3 --cfg yolov3-tiny-3cls-sm4.cfg +n=205 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 4 --cfg yolov3-tiny-3cls-sm4.cfg n=206 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --notest --nosave --cache --device 0 --cfg yolov3-tiny-3cls.cfg n=209 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 3 --cfg yolov3-tiny-3cls.cfg n=210 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-3cls.cfg @@ -345,6 +348,7 @@ n=257 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it #coco +n=2 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --nosave --bucket ult/coco --name $n --device 0 --multi n=3 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 1 --cfg yolov3.cfg --nosave --bucket ult/coco --name $n n=4 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 2 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n n=5 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 3 --cfg yolov3-spp3.cfg --nosave --bucket ult/coco --name $n @@ -373,11 +377,44 @@ n=27 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --g n=28 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown n=29 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 15 --accum 4 --weights '' --device 0 --cfg yolov4a.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown n=30 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown - n=31 && t=ultralytics/coco:v31 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppf.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown n=32 && t=ultralytics/coco:v31 && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppg.cfg --nosave --bucket ult/coco --name $n --multi -n=33 && t=ultralytics/coco:v33 && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppf.cfg --nosave --bucket ult/coco --name $n --multi -n=34 && t=ultralytics/coco:v33 && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppg.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=33 && t=ultralytics/coco:v33 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=34 && t=ultralytics/coco:v34 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=35 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=36 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 1 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=37 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 2 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=38 && t=ultralytics/coco:v35 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 10 --accum 8 --weights '' --device 3 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=39 && t=ultralytics/coco:v35 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 10 --accum 6 --weights '' --device 4 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=40 && t=ultralytics/coco:v35 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 5 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=41 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 6 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=42 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 7 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=45 && t=ultralytics/coco:v45 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 16 --weights '' --device 2 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=46 && t=ultralytics/coco:v45 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 4 --weights '' --device 6 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=47 && t=ultralytics/coco:v45 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 2 --weights '' --device 7 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=48 && t=ultralytics/coco:v45 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 3 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=49 && t=ultralytics/coco:v45 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 32 --weights '' --device 4 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=50 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 3 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=51 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 4 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=52 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 2 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=53 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 5 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n +n=54 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --nosave --bucket ult/coco --name $n --device 0 --multi +n=55 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --nosave --bucket ult/coco --name $n --device 2 --multi +n=56 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 3 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi +n=57 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 4 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi +n=58 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi +n=59 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi +n=60 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 1 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi +n=61 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=62 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi +n=63 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi +n=64 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 1 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi +n=65 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=66 && t=ultralytics/coco:v65 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 0 --cfg darknet53-bifpn3.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=67 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 15 --accum 4 --weights '' --device 0 --cfg csdarknet53-bifpn-optimal.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=68 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=69 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 15 --accum 4 --weights '' --device 0 --cfg csdarknet53-bifpn-optimal.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=70 && t=ultralytics/coco:v69 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 15 --accum 4 --weights '' --device 0 --cfg csresnext50-bifpn-optimal.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown # athena From b97b88b659a63a0b9a50b0c8ca70c903e9e4579f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 21 Feb 2020 17:16:34 -0800 Subject: [PATCH 0418/1185] updates --- README.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 7aa89f1ead..7977c7a50e 100755 --- a/README.md +++ b/README.md @@ -147,31 +147,31 @@ $ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 --- | --- | --- | --- -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**36.3** |29.1
51.8
52.3
**55.5** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**39.8** |33.0
55.4
56.9
**59.6** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**41.3** |34.9
57.7
59.5
**61.3** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**41.7** |35.4
58.2
60.7
**61.5** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**36.4** |29.1
51.8
52.3
**55.7** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**40.0** |33.0
55.4
56.9
**60.0** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**41.5** |34.9
57.7
59.5
**61.4** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**41.9** |35.4
58.2
60.7
**61.6** ```bash -$ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 608 - -Namespace(batch_size=32, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='last54.pt') -Using CUDA device0 _CudaDeviceProperties(name='Tesla P100-PCIE-16GB', total_memory=16280MB) - - Class Images Targets P R mAP@0.5 F1: 100% 157/157 [04:25<00:00, 1.04it/s] - all 5e+03 3.51e+04 0.0467 0.886 0.607 0.0875 - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.415 - Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.615 - Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.443 - Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.245 - Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.458 - Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.531 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.341 +$ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 608 + +Namespace(batch_size=32, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='yolov3-spp-ultralytics.pt') +Using CUDA device0 _CudaDeviceProperties(name='Tesla T4', total_memory=15079MB) + + Class Images Targets P R mAP@0.5 F1: 100% 157/157 [04:25<00:00, 1.01s/it] + all 5e+03 3.51e+04 0.0453 0.885 0.609 0.0852 + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.417 + Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.616 + Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.448 + Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.242 + Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.462 + Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.522 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.337 Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.559 Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.611 - Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.441 - Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.658 - Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.748 + Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.436 + Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.659 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.741 ``` # Reproduce Our Results From b70e39ab9b287e8731efe8d84eb59bf49e456b7c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 22 Feb 2020 12:48:24 -0800 Subject: [PATCH 0419/1185] updates --- models.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/models.py b/models.py index 7a870e0ae2..6ebfa495f4 100755 --- a/models.py +++ b/models.py @@ -133,19 +133,24 @@ def forward(self, x, outputs): x = x * w[0] # Fusion - nc = x.shape[1] # number of channels + nc = x.shape[1] # input channels for i in range(self.n - 1): a = outputs[self.layers[i]] # feature to add - dc = nc - a.shape[1] # delta channels + ac = a.shape[1] # feature channels + dc = nc - ac # delta channels # Adjust channels - if dc > 0: # pad - a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a) - elif dc < 0: # slice - a = a[:, :nc] - - # Sum - x = x + a * w[i + 1] if self.weight else x + a + if dc > 0: # slice input + # a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a) + x[:, :ac] = x[:, :ac] + (a * w[i + 1] if self.weight else a) + elif dc < 0: # slice feature + if self.n == 2: + return x + (a[:, :nc] * w[i + 1] if self.weight else a[:, :nc]) + x = x + (a[:, :nc] * w[i + 1] if self.weight else a[:, :nc]) + else: # same shape + if self.n == 2: + return x + (a * w[i + 1] if self.weight else a) + x = x + (a * w[i + 1] if self.weight else a) return x From 2d9bc6252679c74c9c73a4587a96400a27132999 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 22 Feb 2020 12:54:09 -0800 Subject: [PATCH 0420/1185] updates --- models.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/models.py b/models.py index 6ebfa495f4..6a3a4ea7c8 100755 --- a/models.py +++ b/models.py @@ -135,22 +135,22 @@ def forward(self, x, outputs): # Fusion nc = x.shape[1] # input channels for i in range(self.n - 1): - a = outputs[self.layers[i]] # feature to add + a = outputs[self.layers[i]] * w[i + 1] if self.weight else outputs[self.layers[i]] # feature to add ac = a.shape[1] # feature channels dc = nc - ac # delta channels # Adjust channels if dc > 0: # slice input # a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a) - x[:, :ac] = x[:, :ac] + (a * w[i + 1] if self.weight else a) + x[:, :ac] = x[:, :ac] + a elif dc < 0: # slice feature if self.n == 2: - return x + (a[:, :nc] * w[i + 1] if self.weight else a[:, :nc]) - x = x + (a[:, :nc] * w[i + 1] if self.weight else a[:, :nc]) + return x + a[:, :nc] + x = x + a[:, :nc] else: # same shape if self.n == 2: - return x + (a * w[i + 1] if self.weight else a) - x = x + (a * w[i + 1] if self.weight else a) + return x + a + x = x + a return x From 3cf8a13910b26eacbdc5e9bdf3965648b807d149 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 22 Feb 2020 12:56:20 -0800 Subject: [PATCH 0421/1185] updates --- models.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/models.py b/models.py index 6a3a4ea7c8..9214bfc244 100755 --- a/models.py +++ b/models.py @@ -141,15 +141,10 @@ def forward(self, x, outputs): # Adjust channels if dc > 0: # slice input - # a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a) - x[:, :ac] = x[:, :ac] + a + x[:, :ac] = x[:, :ac] + a # or a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a); x = x + a elif dc < 0: # slice feature - if self.n == 2: - return x + a[:, :nc] x = x + a[:, :nc] else: # same shape - if self.n == 2: - return x + a x = x + a return x From 76080475311f70d24b06ec11d8f3e5fe61c550ba Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 22 Feb 2020 17:43:11 -0800 Subject: [PATCH 0422/1185] updates --- train.py | 3 -- utils/torch_utils.py | 71 -------------------------------------------- 2 files changed, 74 deletions(-) diff --git a/train.py b/train.py index 917fbda8bd..0b45928681 100644 --- a/train.py +++ b/train.py @@ -99,9 +99,6 @@ def train(): optimizer.add_param_group({'params': pg2}) # add pg2 (biases) del pg0, pg1, pg2 - # https://github.com/alphadl/lookahead.pytorch - # optimizer = torch_utils.Lookahead(optimizer, k=5, alpha=0.5) - start_epoch = 0 best_fitness = 0.0 attempt_download(weights) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 9b32172417..b984b265b4 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -94,74 +94,3 @@ def load_classifier(name='resnet101', n=2): model.last_linear.weight = torch.nn.Parameter(torch.zeros(n, filters)) model.last_linear.out_features = n return model - - -from collections import defaultdict -from torch.optim import Optimizer - - -class Lookahead(Optimizer): - def __init__(self, optimizer, k=5, alpha=0.5): - self.optimizer = optimizer - self.k = k - self.alpha = alpha - self.param_groups = self.optimizer.param_groups - self.state = defaultdict(dict) - self.fast_state = self.optimizer.state - for group in self.param_groups: - group["counter"] = 0 - - def update(self, group): - for fast in group["params"]: - param_state = self.state[fast] - if "slow_param" not in param_state: - param_state["slow_param"] = torch.zeros_like(fast.data) - param_state["slow_param"].copy_(fast.data) - slow = param_state["slow_param"] - slow += (fast.data - slow) * self.alpha - fast.data.copy_(slow) - - def update_lookahead(self): - for group in self.param_groups: - self.update(group) - - def step(self, closure=None): - loss = self.optimizer.step(closure) - for group in self.param_groups: - if group["counter"] == 0: - self.update(group) - group["counter"] += 1 - if group["counter"] >= self.k: - group["counter"] = 0 - return loss - - def state_dict(self): - fast_state_dict = self.optimizer.state_dict() - slow_state = { - (id(k) if isinstance(k, torch.Tensor) else k): v - for k, v in self.state.items() - } - fast_state = fast_state_dict["state"] - param_groups = fast_state_dict["param_groups"] - return { - "fast_state": fast_state, - "slow_state": slow_state, - "param_groups": param_groups, - } - - def load_state_dict(self, state_dict): - slow_state_dict = { - "state": state_dict["slow_state"], - "param_groups": state_dict["param_groups"], - } - fast_state_dict = { - "state": state_dict["fast_state"], - "param_groups": state_dict["param_groups"], - } - super(Lookahead, self).load_state_dict(slow_state_dict) - self.optimizer.load_state_dict(fast_state_dict) - self.fast_state = self.optimizer.state - - def add_param_group(self, param_group): - param_group["counter"] = 0 - self.optimizer.add_param_group(param_group) From bc741f30e893706ed70374fefdb2cd7884a3cdc3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 22 Feb 2020 18:18:38 -0800 Subject: [PATCH 0423/1185] updates --- detect.py | 13 ++++++------- utils/datasets.py | 20 +++++++------------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/detect.py b/detect.py index 22f927c23f..dbf3202838 100644 --- a/detect.py +++ b/detect.py @@ -64,10 +64,10 @@ def detect(save_img=False): if webcam: view_img = True torch.backends.cudnn.benchmark = True # set True to speed up constant image size inference - dataset = LoadStreams(source, img_size=img_size, half=half) + dataset = LoadStreams(source, img_size=img_size) else: save_img = True - dataset = LoadImages(source, img_size=img_size, half=half) + dataset = LoadImages(source, img_size=img_size) # Get names and colors names = load_classes(opt.names) @@ -77,15 +77,14 @@ def detect(save_img=False): t0 = time.time() for path, img, im0s, vid_cap in dataset: t = time.time() - - # Get detections img = torch.from_numpy(img).to(device) + img = img.half() if half else img.float() # uint8 to fp16/32 + img /= 255.0 # 0 - 255 to 0.0 - 1.0 if img.ndimension() == 3: img = img.unsqueeze(0) - pred = model(img)[0] - if opt.half: - pred = pred.float() + # Inference + pred = model(img)[0].float() if half else model(img)[0] # Apply NMS pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, classes=opt.classes, agnostic=opt.agnostic_nms) diff --git a/utils/datasets.py b/utils/datasets.py index fee8ceabbd..b465a2e664 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -42,7 +42,7 @@ def exif_size(img): class LoadImages: # for inference - def __init__(self, path, img_size=416, half=False): + def __init__(self, path, img_size=416): path = str(Path(path)) # os-agnostic files = [] if os.path.isdir(path): @@ -59,7 +59,6 @@ def __init__(self, path, img_size=416, half=False): self.nF = nI + nV # number of files self.video_flag = [False] * nI + [True] * nV self.mode = 'images' - self.half = half # half precision fp16 images if any(videos): self.new_video(videos[0]) # new video else: @@ -104,8 +103,7 @@ def __next__(self): # Convert img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 - img = np.ascontiguousarray(img, dtype=np.float16 if self.half else np.float32) # uint8 to fp16/fp32 - img /= 255.0 # 0 - 255 to 0.0 - 1.0 + img = np.ascontiguousarray(img) # cv2.imwrite(path + '.letterbox.jpg', 255 * img.transpose((1, 2, 0))[:, :, ::-1]) # save letterbox image return path, img, img0, self.cap @@ -120,9 +118,8 @@ def __len__(self): class LoadWebcam: # for inference - def __init__(self, pipe=0, img_size=416, half=False): + def __init__(self, pipe=0, img_size=416): self.img_size = img_size - self.half = half # half precision fp16 images if pipe == '0': pipe = 0 # local camera @@ -177,8 +174,7 @@ def __next__(self): # Convert img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 - img = np.ascontiguousarray(img, dtype=np.float16 if self.half else np.float32) # uint8 to fp16/fp32 - img /= 255.0 # 0 - 255 to 0.0 - 1.0 + img = np.ascontiguousarray(img) return img_path, img, img0, None @@ -187,10 +183,9 @@ def __len__(self): class LoadStreams: # multiple IP or RTSP cameras - def __init__(self, sources='streams.txt', img_size=416, half=False): + def __init__(self, sources='streams.txt', img_size=416): self.mode = 'images' self.img_size = img_size - self.half = half # half precision fp16 images if os.path.isfile(sources): with open(sources, 'r') as f: @@ -251,9 +246,8 @@ def __next__(self): img = np.stack(img, 0) # Convert - img = img[:, :, :, ::-1].transpose(0, 3, 1, 2) # BGR to RGB, to 3x416x416, uint8 to float32 - img = np.ascontiguousarray(img, dtype=np.float16 if self.half else np.float32) - img /= 255.0 # 0 - 255 to 0.0 - 1.0 + img = img[:, :, :, ::-1].transpose(0, 3, 1, 2) # BGR to RGB, to bsx3x416x416 + img = np.ascontiguousarray(img) return self.sources, img, img0, None From 817c0bfeed617f50e5fa1d23d038770d49a624e8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 22 Feb 2020 21:17:38 -0800 Subject: [PATCH 0424/1185] updates --- train.py | 1 + 1 file changed, 1 insertion(+) diff --git a/train.py b/train.py index 0b45928681..8d3a25d731 100644 --- a/train.py +++ b/train.py @@ -136,6 +136,7 @@ def train(): # lf = lambda x: 1 - x / epochs # linear ramp to zero # lf = lambda x: 10 ** (hyp['lrf'] * x / epochs) # exp ramp # lf = lambda x: 1 - 10 ** (hyp['lrf'] * (1 - x / epochs)) # inverse exp ramp + # lf = lambda x: 0.5 * (1 + math.cos(x * math.pi / epochs)) # cosine https://arxiv.org/pdf/1812.01187.pdf # scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=range(59, 70, 1), gamma=0.8) # gradual fall to 0.1*lr0 scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[round(opt.epochs * x) for x in [0.8, 0.9]], gamma=0.1) From b052085cc49ce7dc7d9ab3424e2a735d05fdb55b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 22 Feb 2020 21:21:45 -0800 Subject: [PATCH 0425/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 8d3a25d731..9c8fed87e0 100644 --- a/train.py +++ b/train.py @@ -139,7 +139,7 @@ def train(): # lf = lambda x: 0.5 * (1 + math.cos(x * math.pi / epochs)) # cosine https://arxiv.org/pdf/1812.01187.pdf # scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=range(59, 70, 1), gamma=0.8) # gradual fall to 0.1*lr0 - scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[round(opt.epochs * x) for x in [0.8, 0.9]], gamma=0.1) + scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[round(epochs * x) for x in [0.8, 0.9]], gamma=0.1) scheduler.last_epoch = start_epoch - 1 # # Plot lr schedule From 2624d55623c9b1f8af5ff1e65af6311b7a0b2615 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 22 Feb 2020 21:24:56 -0800 Subject: [PATCH 0426/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 9c8fed87e0..0c63a5149b 100644 --- a/train.py +++ b/train.py @@ -147,7 +147,7 @@ def train(): # for _ in range(epochs): # scheduler.step() # y.append(optimizer.param_groups[0]['lr']) - # plt.plot(y, label='LambdaLR') + # plt.plot(y, '.-', label='LambdaLR') # plt.xlabel('epoch') # plt.ylabel('LR') # plt.tight_layout() From a3671bde94f8cb82089482202951be35e94705a9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 23 Feb 2020 18:33:32 -0800 Subject: [PATCH 0427/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 17a949e8dc..2b5f34cb98 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -1041,7 +1041,7 @@ def plot_results(start=0, stop=0, bucket='', id=()): # from utils.utils import if i in [0, 1, 2, 5, 6, 7]: y[y == 0] = np.nan # dont show zero loss values # y /= y[0] # normalize - ax[i].plot(x, y, marker='.', label=Path(f).stem) + ax[i].plot(x, y, marker='.', label=Path(f).stem, linewidth=2, markersize=8) ax[i].set_title(s[i]) if i in [5, 6, 7]: # share train and val loss y axes ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) From ef3bd7e12b27b653d89a7fd0fed9913c8c9e3ea0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 24 Feb 2020 09:06:17 -0800 Subject: [PATCH 0428/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 0c63a5149b..24a2f7ab97 100644 --- a/train.py +++ b/train.py @@ -140,7 +140,7 @@ def train(): # scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=range(59, 70, 1), gamma=0.8) # gradual fall to 0.1*lr0 scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[round(epochs * x) for x in [0.8, 0.9]], gamma=0.1) - scheduler.last_epoch = start_epoch - 1 + scheduler.last_epoch = start_epoch # # Plot lr schedule # y = [] From 24957dca986a635aa160a49256c5534ce484072a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 24 Feb 2020 12:21:47 -0800 Subject: [PATCH 0429/1185] updates --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 24a2f7ab97..4208b4cdf2 100644 --- a/train.py +++ b/train.py @@ -211,13 +211,13 @@ def train(): torch_utils.model_info(model, report='summary') # 'full' or 'summary' print('Using %g dataloader workers' % nw) print('Starting training for %g epochs...' % epochs) - for epoch in range(start_epoch, epochs): # epoch ------------------------------ + for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ model.train() # Prebias if prebias: if epoch < 3: # prebias - ps = 0.1, 0.9 # prebias settings (lr=0.1, momentum=0.9) + ps = np.interp(epoch, [0, 3], [0.1, hyp['lr0']]), 0.0 # prebias settings (lr=0.1, momentum=0.0) else: # normal training ps = hyp['lr0'], hyp['momentum'] # normal training settings print_model_biases(model) From 4b720013d1ef496200dd1022484c39b2f9473212 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 24 Feb 2020 12:43:13 -0800 Subject: [PATCH 0430/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 2b5f34cb98..911d3f1a3e 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -401,7 +401,7 @@ def compute_loss(p, targets, model, giou_flag=True): # predictions, targets, mo pbox = torch.cat((pxy, pwh), 1) # predicted box giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss - tobj[b, a, gj, gi] = giou.detach().type(tobj.dtype) if giou_flag else 1.0 + tobj[b, a, gj, gi] = giou.detach().clamp(0).type(tobj.dtype) if giou_flag else 1.0 if 'default' in arc and model.nc > 1: # cls loss (only if multiple classes) t = torch.zeros_like(ps[:, 5:]) # targets From f743235fac9571a8ef8fdf873fd480c2abf5930d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 24 Feb 2020 12:44:22 -0800 Subject: [PATCH 0431/1185] updates --- train.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/train.py b/train.py index 4208b4cdf2..5d8d3dc3ff 100644 --- a/train.py +++ b/train.py @@ -288,7 +288,7 @@ def train(): else: loss.backward() - # Accumulate gradient for x batches before optimizing + # Optimize accumulated gradient if ni % accumulate == 0: optimizer.step() optimizer.zero_grad() @@ -301,6 +301,9 @@ def train(): # end batch ------------------------------------------------------------------------------------------------ + # Update scheduler + scheduler.step() + # Process epoch results final_epoch = epoch + 1 == epochs if not opt.notest or final_epoch: # Calculate mAP @@ -316,9 +319,6 @@ def train(): single_cls=opt.single_cls, dataloader=testloader) - # Update scheduler - scheduler.step() - # Write epoch results with open(results_file, 'a') as f: f.write(s + '%10.3g' * 7 % results + '\n') # P, R, mAP, F1, test_losses=(GIoU, obj, cls) From 4f3d07f6898cfddf724b4c974e09e298a93b3540 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 25 Feb 2020 20:04:05 -0800 Subject: [PATCH 0432/1185] updates --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index a47bd3e47c..5a95798f0f 100755 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,17 @@ # Repo-specific GitIgnore ---------------------------------------------------------------------------------------------- *.jpg +*.jpeg *.png *.bmp *.tif +*.tiff *.heic *.JPG +*.JPEG *.PNG +*.BMP *.TIF +*.TIFF *.HEIC *.mp4 *.mov From b12f1a9abe92288c98bfe7da00118ae81a7805e0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 25 Feb 2020 22:58:26 -0800 Subject: [PATCH 0433/1185] updates --- detect.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/detect.py b/detect.py index dbf3202838..64a7867d39 100644 --- a/detect.py +++ b/detect.py @@ -45,11 +45,12 @@ def detect(save_img=False): if ONNX_EXPORT: model.fuse() img = torch.zeros((1, 3) + img_size) # (1, 3, 320, 192) - torch.onnx.export(model, img, 'weights/export.onnx', verbose=False, opset_version=11) + f = opt.weights.replace(opt.weights.split('.')[-1], 'onnx') # *.onnx filename + torch.onnx.export(model, img, f, verbose=False, opset_version=11) # Validate exported model import onnx - model = onnx.load('weights/export.onnx') # Load the ONNX model + model = onnx.load(f) # Load the ONNX model onnx.checker.check_model(model) # Check that the IR is well formed print(onnx.helper.printable_graph(model.graph)) # Print a human readable representation of the graph return From 2baa67cde2094c474fdc84c6eaa483416bea3459 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 26 Feb 2020 13:40:17 -0800 Subject: [PATCH 0434/1185] updates --- test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test.py b/test.py index e1a8096776..d7cc42941e 100644 --- a/test.py +++ b/test.py @@ -25,7 +25,7 @@ def test(cfg, verbose = opt.task == 'test' # Remove previous - for f in glob.glob('test_batch*.jpg'): + for f in glob.glob('test_batch*.png'): os.remove(f) # Initialize model @@ -76,9 +76,9 @@ def test(cfg, _, _, height, width = imgs.shape # batch size, channels, height, width # Plot images with bounding boxes - if batch_i == 0 and not os.path.exists('test_batch0.png'): - plot_images(imgs=imgs, targets=targets, paths=paths, fname='test_batch0.png') - + f = 'test_batch%g.png' % batch_i # filename + if batch_i < 1 and not os.path.exists(f): + plot_images(imgs=imgs, targets=targets, paths=paths, fname=f) # Disable gradients with torch.no_grad(): From 7d7c22cb7ea60c825fc99aa9916a229f19457108 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 26 Feb 2020 13:42:50 -0800 Subject: [PATCH 0435/1185] updates --- train.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/train.py b/train.py index 5d8d3dc3ff..3a35d65cc8 100644 --- a/train.py +++ b/train.py @@ -254,11 +254,11 @@ def train(): # x['weight_decay'] = hyp['weight_decay'] * g # Plot images with bounding boxes - if ni == 0: - fname = 'train_batch%g.png' % i - plot_images(imgs=imgs, targets=targets, paths=paths, fname=fname) + if ni < 1: + f = 'train_batch%g.png' % i # filename + plot_images(imgs=imgs, targets=targets, paths=paths, fname=f) if tb_writer: - tb_writer.add_image(fname, cv2.imread(fname)[:, :, ::-1], dataformats='HWC') + tb_writer.add_image(f, cv2.imread(f)[:, :, ::-1], dataformats='HWC') # Multi-Scale training if opt.multi_scale: From 764514e44da961b4f5a8df59a67f1a9496af9a71 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 26 Feb 2020 13:52:33 -0800 Subject: [PATCH 0436/1185] updates --- utils/adabound.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/adabound.py b/utils/adabound.py index 142b12625d..8baa378057 100644 --- a/utils/adabound.py +++ b/utils/adabound.py @@ -1,7 +1,7 @@ import math import torch -from torch.optim import Optimizer +from torch.optim.optimizer import Optimizer class AdaBound(Optimizer): From e7f85bcfb9c6040db919187cf3b26b56aa9d0146 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 27 Feb 2020 11:29:38 -0800 Subject: [PATCH 0437/1185] updates --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index d7cc42941e..1be992147c 100644 --- a/test.py +++ b/test.py @@ -14,7 +14,7 @@ def test(cfg, batch_size=16, img_size=416, conf_thres=0.001, - iou_thres=0.5, # for nms + iou_thres=0.6, # for nms save_json=False, single_cls=False, model=None, From 7e92f70e052210c849f6d16786e31cd3239f6f98 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 27 Feb 2020 12:19:06 -0800 Subject: [PATCH 0438/1185] updates --- utils/google_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/google_utils.py b/utils/google_utils.py index 92fde590bc..cbfa3ec624 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -23,7 +23,7 @@ def gdrive_download(id='1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO', name='coco.zip'): "curl -Lb ./cookie -s \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=%s\" -o %s" % ( id, name), 'rm ./cookie'] - r = sum([os.system(x) for x in s]) # run commands, get return zeros + r = sum([os.system(x) for x in s][:2]) # run commands, get return zeros # Attempt small file download if not os.path.exists(name): # file size < 40MB From f3d3295f90531e064c50901319443a7feeb33bc9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 27 Feb 2020 12:38:14 -0800 Subject: [PATCH 0439/1185] updates --- utils/google_utils.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/utils/google_utils.py b/utils/google_utils.py index cbfa3ec624..820f4e08db 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -15,25 +15,23 @@ def gdrive_download(id='1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO', name='coco.zip'): t = time.time() print('Downloading https://drive.google.com/uc?export=download&id=%s as %s... ' % (id, name), end='') - if os.path.exists(name): # remove existing - os.remove(name) - - # Attempt large file download - s = ["curl -c ./cookie -s -L \"https://drive.google.com/uc?export=download&id=%s\" > /dev/null" % id, - "curl -Lb ./cookie -s \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=%s\" -o %s" % ( - id, name), - 'rm ./cookie'] - r = sum([os.system(x) for x in s][:2]) # run commands, get return zeros - - # Attempt small file download - if not os.path.exists(name): # file size < 40MB + os.remove(name) if os.path.exists(name) else None # remove existing + os.remove('cookie') if os.path.exists('cookie') else None + + # Attempt file download + os.system("curl -c ./cookie -s -L \"https://drive.google.com/uc?export=download&id=%s\" > /dev/null" % id) + if os.path.exists('cookie'): # large file + s = "curl -Lb ./cookie -s \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=%s\" -o %s" % ( + id, name) + else: # small file s = 'curl -f -L -o %s https://drive.google.com/uc?export=download&id=%s' % (name, id) - r = os.system(s) + r = os.system(s) # execute, capture return values + os.remove('cookie') if os.path.exists('cookie') else None # Error check if r != 0: - os.system('rm ' + name) # remove partial downloads - print('ERROR: Download failure ') + os.remove(name) if os.path.exists(name) else None # remove partial + print('Download error ') # raise Exception('Download error') return r # Unzip if archive From de3e53960944a725e43dc234b2eb835a4626417a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 27 Feb 2020 12:49:01 -0800 Subject: [PATCH 0440/1185] updates --- utils/google_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/google_utils.py b/utils/google_utils.py index 820f4e08db..20c3a3baff 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -24,7 +24,7 @@ def gdrive_download(id='1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO', name='coco.zip'): s = "curl -Lb ./cookie -s \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=%s\" -o %s" % ( id, name) else: # small file - s = 'curl -f -L -o %s https://drive.google.com/uc?export=download&id=%s' % (name, id) + s = "curl -f -L -o %s 'https://drive.google.com/uc?export=download&id=%s'" % (name, id) r = os.system(s) # execute, capture return values os.remove('cookie') if os.path.exists('cookie') else None From 6a99e39bd559ea265089e27efc938302b7568b74 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 27 Feb 2020 12:57:10 -0800 Subject: [PATCH 0441/1185] updates --- utils/google_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/google_utils.py b/utils/google_utils.py index 20c3a3baff..f7e2cac8c2 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -24,7 +24,7 @@ def gdrive_download(id='1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO', name='coco.zip'): s = "curl -Lb ./cookie -s \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=%s\" -o %s" % ( id, name) else: # small file - s = "curl -f -L -o %s 'https://drive.google.com/uc?export=download&id=%s'" % (name, id) + s = "curl -s -L -o %s 'https://drive.google.com/uc?export=download&id=%s'" % (name, id) r = os.system(s) # execute, capture return values os.remove('cookie') if os.path.exists('cookie') else None From 3a1ca6454c065b786b37c4b1cc660f9f16e76bb4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 27 Feb 2020 13:00:00 -0800 Subject: [PATCH 0442/1185] updates --- utils/google_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/google_utils.py b/utils/google_utils.py index f7e2cac8c2..1679f0fe70 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -21,7 +21,7 @@ def gdrive_download(id='1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO', name='coco.zip'): # Attempt file download os.system("curl -c ./cookie -s -L \"https://drive.google.com/uc?export=download&id=%s\" > /dev/null" % id) if os.path.exists('cookie'): # large file - s = "curl -Lb ./cookie -s \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=%s\" -o %s" % ( + s = "curl -Lb ./cookie \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=%s\" -o %s" % ( id, name) else: # small file s = "curl -s -L -o %s 'https://drive.google.com/uc?export=download&id=%s'" % (name, id) From 0fb4a46ace6d32b323039ee40cddc0566ef6b0b8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 27 Feb 2020 13:30:23 -0800 Subject: [PATCH 0443/1185] updates --- cfg/yolov4-tiny-1cls.cfg | 233 +++++++++++++++++++++++++++++++++++++++ cfg/yolov4-tiny.cfg | 233 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 466 insertions(+) create mode 100644 cfg/yolov4-tiny-1cls.cfg create mode 100644 cfg/yolov4-tiny.cfg diff --git a/cfg/yolov4-tiny-1cls.cfg b/cfg/yolov4-tiny-1cls.cfg new file mode 100644 index 0000000000..7cf2dd4ec3 --- /dev/null +++ b/cfg/yolov4-tiny-1cls.cfg @@ -0,0 +1,233 @@ +# Generated by Glenn Jocher (glenn.jocher@ultralytics.com) for https://github.com/ultralytics/yolov3 +# def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 640)): # from utils.utils import *; kmean_anchors() +# Evolving anchors: 100%|██████████| 1000/1000 [41:15<00:00, 2.48s/it] +# 0.20 iou_thr: 0.992 best possible recall, 4.25 anchors > thr +# kmeans anchors (n=12, img_size=(320, 640), IoU=0.005/0.184/0.634-min/mean/best): 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 + +[net] +# Testing +# batch=1 +# subdivisions=1 +# Training +batch=64 +subdivisions=16 +width=608 +height=608 +channels=3 +momentum=0.9 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.001 +burn_in=1000 +max_batches = 200000 +policy=steps +steps=180000,190000 +scales=.1,.1 + + +[convolutional] +batch_normalize=1 +filters=16 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=1 + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=1 +pad=1 +activation=leaky + +########### + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=24 +activation=linear + + + +[yolo] +mask = 8,9,10,11 +anchors = 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 +classes=1 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 8 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=24 +activation=linear + +[yolo] +mask = 4,5,6,7 +anchors = 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 +classes=1 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + + + +[route] +layers = -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 6 + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=24 +activation=linear + +[yolo] +mask = 0,1,2,3 +anchors = 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 +classes=1 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 diff --git a/cfg/yolov4-tiny.cfg b/cfg/yolov4-tiny.cfg new file mode 100644 index 0000000000..5548ca607f --- /dev/null +++ b/cfg/yolov4-tiny.cfg @@ -0,0 +1,233 @@ +# Generated by Glenn Jocher (glenn.jocher@ultralytics.com) for https://github.com/ultralytics/yolov3 +# def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 640)): # from utils.utils import *; kmean_anchors() +# Evolving anchors: 100%|██████████| 1000/1000 [41:15<00:00, 2.48s/it] +# 0.20 iou_thr: 0.992 best possible recall, 4.25 anchors > thr +# kmeans anchors (n=12, img_size=(320, 640), IoU=0.005/0.184/0.634-min/mean/best): 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 + +[net] +# Testing +# batch=1 +# subdivisions=1 +# Training +batch=64 +subdivisions=16 +width=608 +height=608 +channels=3 +momentum=0.9 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.001 +burn_in=1000 +max_batches = 200000 +policy=steps +steps=180000,190000 +scales=.1,.1 + + +[convolutional] +batch_normalize=1 +filters=16 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[maxpool] +size=2 +stride=1 + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=1 +pad=1 +activation=leaky + +########### + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=340 +activation=linear + + + +[yolo] +mask = 8,9,10,11 +anchors = 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 +classes=80 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 8 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=340 +activation=linear + +[yolo] +mask = 4,5,6,7 +anchors = 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 +classes=80 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 + + + +[route] +layers = -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 6 + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=340 +activation=linear + +[yolo] +mask = 0,1,2,3 +anchors = 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 +classes=80 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 From d5815ebfd28ef44deeae0b61c8dc41e18f4197cf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 27 Feb 2020 13:40:14 -0800 Subject: [PATCH 0444/1185] updates --- train.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/train.py b/train.py index 3a35d65cc8..c38d375b8c 100644 --- a/train.py +++ b/train.py @@ -132,6 +132,10 @@ def train(): # possible weights are '*.weights', 'yolov3-tiny.conv.15', 'darknet53.conv.74' etc. load_darknet_weights(model, weights) + # Mixed precision training https://github.com/NVIDIA/apex + if mixed_precision: + model, optimizer = amp.initialize(model, optimizer, opt_level='O1', verbosity=0) + # Scheduler https://github.com/ultralytics/yolov3/issues/238 # lf = lambda x: 1 - x / epochs # linear ramp to zero # lf = lambda x: 10 ** (hyp['lrf'] * x / epochs) # exp ramp @@ -153,10 +157,6 @@ def train(): # plt.tight_layout() # plt.savefig('LR.png', dpi=300) - # Mixed precision training https://github.com/NVIDIA/apex - if mixed_precision: - model, optimizer = amp.initialize(model, optimizer, opt_level='O1', verbosity=0) - # Initialize distributed training if device.type != 'cpu' and torch.cuda.device_count() > 1: dist.init_process_group(backend='nccl', # 'distributed backend' From b3ecfb10bcefbe6ed4513cbc4249dc0d45b56578 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 27 Feb 2020 22:50:26 -0800 Subject: [PATCH 0445/1185] updates --- utils/torch_utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index b984b265b4..a93b79d1aa 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -1,6 +1,7 @@ import os import torch +import torch.backends.cudnn as cudnn def init_seeds(seed=0): @@ -8,8 +9,8 @@ def init_seeds(seed=0): # Remove randomness (may be slower on Tesla GPUs) # https://pytorch.org/docs/stable/notes/randomness.html if seed == 0: - torch.backends.cudnn.deterministic = True - torch.backends.cudnn.benchmark = False + cudnn.deterministic = True + cudnn.benchmark = False def select_device(device='', apex=False, batch_size=None): From cc08e09219960f70f4a70ef5ee0c13dfafe3832a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 28 Feb 2020 10:06:35 -0800 Subject: [PATCH 0446/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 9214bfc244..fe21ad50e5 100755 --- a/models.py +++ b/models.py @@ -35,7 +35,7 @@ def create_modules(module_defs, img_size, arc): bias=not bn)) if bn: modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.1)) - if mdef['activation'] == 'leaky': # TODO: activation study https://github.com/ultralytics/yolov3/issues/441 + if mdef['activation'] == 'leaky': # activation study https://github.com/ultralytics/yolov3/issues/441 modules.add_module('activation', nn.LeakyReLU(0.1, inplace=True)) # modules.add_module('activation', nn.PReLU(num_parameters=1, init=0.10)) elif mdef['activation'] == 'swish': From e6cda0fea41c32d4f3f6d1d2a8808eeea0ab19d2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 29 Feb 2020 01:15:23 -0800 Subject: [PATCH 0447/1185] updates --- README.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 7977c7a50e..a9d6d9209a 100755 --- a/README.md +++ b/README.md @@ -147,31 +147,31 @@ $ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 --- | --- | --- | --- -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**36.4** |29.1
51.8
52.3
**55.7** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**40.0** |33.0
55.4
56.9
**60.0** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**41.5** |34.9
57.7
59.5
**61.4** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**41.9** |35.4
58.2
60.7
**61.6** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**36.6** |29.1
51.8
52.3
**56.0** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**40.4** |33.0
55.4
56.9
**60.2** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**41.6** |34.9
57.7
59.5
**61.7** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**42.1** |35.4
58.2
60.7
**61.7** ```bash $ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 608 -Namespace(batch_size=32, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='yolov3-spp-ultralytics.pt') -Using CUDA device0 _CudaDeviceProperties(name='Tesla T4', total_memory=15079MB) +Namespace(batch_size=32, cfg='yolov3-spp', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='last82.pt') +Using CUDA device0 _CudaDeviceProperties(name='Tesla P100-PCIE-16GB', total_memory=16280MB) - Class Images Targets P R mAP@0.5 F1: 100% 157/157 [04:25<00:00, 1.01s/it] - all 5e+03 3.51e+04 0.0453 0.885 0.609 0.0852 - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.417 - Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.616 + Class Images Targets P R mAP@0.5 F1: 100% 157/157 [03:12<00:00, 1.50it/s] + all 5e+03 3.51e+04 0.0573 0.871 0.611 0.106 + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.419 + Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.618 Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.448 - Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.242 + Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.247 Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.462 - Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.522 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.337 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.559 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.611 - Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.436 - Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.659 - Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.741 + Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.534 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.341 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.557 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.606 + Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.440 + Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.649 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.735 ``` # Reproduce Our Results From 7823473d2f865536bdc267d9752785cba91189a3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 1 Mar 2020 20:55:20 -0800 Subject: [PATCH 0448/1185] updates --- train.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/train.py b/train.py index c38d375b8c..1a32e3c0b7 100644 --- a/train.py +++ b/train.py @@ -97,6 +97,7 @@ def train(): optimizer = optim.SGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) optimizer.add_param_group({'params': pg1, 'weight_decay': hyp['weight_decay']}) # add pg1 with weight_decay optimizer.add_param_group({'params': pg2}) # add pg2 (biases) + optimizer.param_groups[2]['lr'] *= 2.0 # bias lr del pg0, pg1, pg2 start_epoch = 0 @@ -140,10 +141,9 @@ def train(): # lf = lambda x: 1 - x / epochs # linear ramp to zero # lf = lambda x: 10 ** (hyp['lrf'] * x / epochs) # exp ramp # lf = lambda x: 1 - 10 ** (hyp['lrf'] * (1 - x / epochs)) # inverse exp ramp - # lf = lambda x: 0.5 * (1 + math.cos(x * math.pi / epochs)) # cosine https://arxiv.org/pdf/1812.01187.pdf - # scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) - # scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=range(59, 70, 1), gamma=0.8) # gradual fall to 0.1*lr0 - scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[round(epochs * x) for x in [0.8, 0.9]], gamma=0.1) + lf = lambda x: 0.5 * (1 + math.cos(x * math.pi / epochs)) # cosine https://arxiv.org/pdf/1812.01187.pdf + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) + # scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[round(epochs * x) for x in [0.8, 0.9]], gamma=0.1) scheduler.last_epoch = start_epoch # # Plot lr schedule @@ -216,10 +216,10 @@ def train(): # Prebias if prebias: - if epoch < 3: # prebias - ps = np.interp(epoch, [0, 3], [0.1, hyp['lr0']]), 0.0 # prebias settings (lr=0.1, momentum=0.0) - else: # normal training - ps = hyp['lr0'], hyp['momentum'] # normal training settings + ne = 3 # number of prebias epochs + ps = np.interp(epoch, [0, ne], [0.1, hyp['lr0'] * 2]), \ + np.interp(epoch, [0, ne], [0.9, hyp['momentum']]) # prebias settings (lr=0.1, momentum=0.9) + if epoch == ne: print_model_biases(model) prebias = False From 84371f68117cae975eabfa78cdf8a2aa1b78e4ba Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 1 Mar 2020 21:33:16 -0800 Subject: [PATCH 0449/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 1a32e3c0b7..88cf3c4214 100644 --- a/train.py +++ b/train.py @@ -158,7 +158,7 @@ def train(): # plt.savefig('LR.png', dpi=300) # Initialize distributed training - if device.type != 'cpu' and torch.cuda.device_count() > 1: + if device.type != 'cpu' and torch.cuda.device_count() > 1 and torch.distributed.is_available(): dist.init_process_group(backend='nccl', # 'distributed backend' init_method='tcp://127.0.0.1:9999', # distributed training init method world_size=1, # number of nodes for distributed training From 44daace4caa901efe9b5151b99d86f083a428039 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 2 Mar 2020 14:07:09 -0800 Subject: [PATCH 0450/1185] updates --- test.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/test.py b/test.py index 1be992147c..53fa783628 100644 --- a/test.py +++ b/test.py @@ -223,8 +223,8 @@ def test(cfg, opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) print(opt) - if opt.task == 'test': # task = 'test', 'study', 'benchmark' - # Test + # task = 'test', 'study', 'benchmark' + if opt.task == 'test': # (default) test normally test(opt.cfg, opt.data, opt.weights, @@ -235,20 +235,18 @@ def test(cfg, opt.save_json, opt.single_cls) - elif opt.task == 'benchmark': - # mAPs at 320-608 at conf 0.5 and 0.7 + elif opt.task == 'benchmark': # mAPs at 320-608 at conf 0.5 and 0.7 y = [] - for i in [320, 416, 512, 608]: - for j in [0.5, 0.7]: + for i in [320, 416, 512, 608]: # img-size + for j in [0.5, 0.7]: # iou-thres t = time.time() r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, i, opt.conf_thres, j, opt.save_json)[0] y.append(r + (time.time() - t,)) np.savetxt('benchmark.txt', y, fmt='%10.4g') # y = np.loadtxt('study.txt') - elif opt.task == 'study': - # Parameter study + elif opt.task == 'study': # Parameter study y = [] - x = np.arange(0.4, 0.9, 0.05) + x = np.arange(0.4, 0.9, 0.05) # iou-thres for i in x: t = time.time() r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, opt.conf_thres, i, opt.save_json)[0] From 2774c1b398230718816fc46ae2a6413febcb9922 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 2 Mar 2020 14:28:08 -0800 Subject: [PATCH 0451/1185] updates --- test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test.py b/test.py index 53fa783628..caa4284c68 100644 --- a/test.py +++ b/test.py @@ -55,7 +55,8 @@ def test(cfg, # Dataloader if dataloader is None: - dataset = LoadImagesAndLabels(path, img_size, batch_size, rect=True) + dataset = LoadImagesAndLabels(path, img_size, batch_size, rect=True, single_cls=opt.single_cls, + cache_labels=True) batch_size = min(batch_size, len(dataset)) dataloader = DataLoader(dataset, batch_size=batch_size, From dce753ead4a8378055fc07be54c3f54bcf55e2ed Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 2 Mar 2020 14:30:01 -0800 Subject: [PATCH 0452/1185] updates --- test.py | 3 +-- train.py | 2 -- utils/datasets.py | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/test.py b/test.py index caa4284c68..6bcf3d07da 100644 --- a/test.py +++ b/test.py @@ -55,8 +55,7 @@ def test(cfg, # Dataloader if dataloader is None: - dataset = LoadImagesAndLabels(path, img_size, batch_size, rect=True, single_cls=opt.single_cls, - cache_labels=True) + dataset = LoadImagesAndLabels(path, img_size, batch_size, rect=True, single_cls=opt.single_cls) batch_size = min(batch_size, len(dataset)) dataloader = DataLoader(dataset, batch_size=batch_size, diff --git a/train.py b/train.py index 88cf3c4214..9e919f888b 100644 --- a/train.py +++ b/train.py @@ -171,7 +171,6 @@ def train(): augment=True, hyp=hyp, # augmentation hyperparameters rect=opt.rect, # rectangular training - cache_labels=True, cache_images=opt.cache_images, single_cls=opt.single_cls) @@ -189,7 +188,6 @@ def train(): testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, img_size_test, batch_size * 2, hyp=hyp, rect=True, - cache_labels=True, cache_images=opt.cache_images, single_cls=opt.single_cls), batch_size=batch_size * 2, diff --git a/utils/datasets.py b/utils/datasets.py index b465a2e664..ff05385684 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -257,7 +257,7 @@ def __len__(self): class LoadImagesAndLabels(Dataset): # for training/testing def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, - cache_labels=False, cache_images=False, single_cls=False): + cache_labels=True, cache_images=False, single_cls=False): path = str(Path(path)) # os-agnostic assert os.path.isfile(path), 'File not found %s. See %s' % (path, help_url) with open(path, 'r') as f: From 308f7c856330235470c4725dbb8e87a92eb24c24 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 3 Mar 2020 19:16:13 -0800 Subject: [PATCH 0453/1185] updates --- utils/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 911d3f1a3e..62e2cf491f 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -524,10 +524,6 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru # Apply width-height constraint pred = pred[(pred[:, 2:4] > min_wh).all(1) & (pred[:, 2:4] < max_wh).all(1)] - # If none remain process next image - if len(pred) == 0: - continue - # Compute conf pred[..., 5:] *= pred[..., 4:5] # conf = obj_conf * cls_conf @@ -550,6 +546,10 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru if not torch.isfinite(pred).all(): pred = pred[torch.isfinite(pred).all(1)] + # If none remain process next image + if not pred.shape[0]: + continue + # Batched NMS if method == 'vision_batch': c = pred[:, 5] * 0 if agnostic else pred[:, 5] # class-agnostic NMS From 166f8c0e5378c68e718a89420efbab66d3cf9f18 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 00:07:19 -0800 Subject: [PATCH 0454/1185] updates --- utils/utils.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 62e2cf491f..607cfb1b79 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -501,7 +501,7 @@ def build_targets(model, targets): return tcls, tbox, indices, av -def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=True, classes=None, agnostic=False): +def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_cls=True, classes=None, agnostic=False): """ Removes detections with lower object confidence score than 'conf_thres' Non-Maximum Suppression to further filter detections. @@ -513,7 +513,8 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru # Box constraints min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height - method = 'vision_batch' + method = 'fast_batch' + batched = 'batch' in method # run once per image, all classes simultaneously nc = prediction[0].shape[1] - 5 # number of classes multi_cls = multi_cls and (nc > 1) # allow multiple classes per anchor output = [None] * len(prediction) @@ -550,16 +551,24 @@ def non_max_suppression(prediction, conf_thres=0.5, iou_thres=0.5, multi_cls=Tru if not pred.shape[0]: continue - # Batched NMS - if method == 'vision_batch': - c = pred[:, 5] * 0 if agnostic else pred[:, 5] # class-agnostic NMS - output[image_i] = pred[torchvision.ops.boxes.batched_nms(pred[:, :4], pred[:, 4], c, iou_thres)] - continue - # Sort by confidence if not method.startswith('vision'): pred = pred[pred[:, 4].argsort(descending=True)] + # Batched NMS + if batched: + c = pred[:, 5] * 0 if agnostic else pred[:, 5] # class-agnostic NMS + boxes, scores = pred[:, :4].clone(), pred[:, 4] + if method == 'vision_batch': + i = torchvision.ops.boxes.batched_nms(boxes, scores, c, iou_thres) + elif method == 'fast_batch': # FastNMS from https://github.com/dbolya/yolact + boxes += c.view(-1, 1) * max_wh + iou = box_iou(boxes, boxes).triu_(diagonal=1) # zero upper triangle iou matrix + i = iou.max(dim=0)[0] < iou_thres + + output[image_i] = pred[i] + continue + # All other NMS methods det_max = [] cls = pred[:, -1] From f915bf175c02911a1f40fbd2de8494963d4e7914 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 00:08:18 -0800 Subject: [PATCH 0455/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 607cfb1b79..1c1368b31b 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -513,7 +513,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_cls=Tru # Box constraints min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height - method = 'fast_batch' + method = 'vision_batch' batched = 'batch' in method # run once per image, all classes simultaneously nc = prediction[0].shape[1] - 5 # number of classes multi_cls = multi_cls and (nc > 1) # allow multiple classes per anchor From be01fc357b67da6af1018dd309215d7f297b0eb5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 00:22:01 -0800 Subject: [PATCH 0456/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 1c1368b31b..65ffbb1c69 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -563,7 +563,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_cls=Tru i = torchvision.ops.boxes.batched_nms(boxes, scores, c, iou_thres) elif method == 'fast_batch': # FastNMS from https://github.com/dbolya/yolact boxes += c.view(-1, 1) * max_wh - iou = box_iou(boxes, boxes).triu_(diagonal=1) # zero upper triangle iou matrix + iou = box_iou(boxes, boxes).triu_(diagonal=1) # upper triangular iou matrix i = iou.max(dim=0)[0] < iou_thres output[image_i] = pred[i] From eb81c0b9ae9592da3c801da8ca25a961127484ce Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 01:47:31 -0800 Subject: [PATCH 0457/1185] updates --- test.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test.py b/test.py index 6bcf3d07da..bfbdb09d2d 100644 --- a/test.py +++ b/test.py @@ -74,6 +74,7 @@ def test(cfg, imgs = imgs.to(device).float() / 255.0 # uint8 to float32, 0 - 255 to 0.0 - 1.0 targets = targets.to(device) _, _, height, width = imgs.shape # batch size, channels, height, width + whwh = torch.Tensor([width, height, width, height]).to(device) # Plot images with bounding boxes f = 'test_batch%g.png' % batch_i # filename @@ -126,13 +127,13 @@ def test(cfg, 'score': floatn(d[4], 5)}) # Assign all predictions as incorrect - correct = torch.zeros(len(pred), niou, dtype=torch.bool) + correct = torch.zeros(len(pred), niou, dtype=torch.bool, device=device) if nl: detected = [] # target indices tcls_tensor = labels[:, 0] # target boxes - tbox = xywh2xyxy(labels[:, 1:5]) * torch.Tensor([width, height, width, height]).to(device) + tbox = xywh2xyxy(labels[:, 1:5]) * whwh # Per target class for cls in torch.unique(tcls_tensor): @@ -140,7 +141,7 @@ def test(cfg, pi = (cls == pred[:, 5]).nonzero().view(-1) # target indices # Search for detections - if len(pi): + if pi.shape[0]: # Prediction to target ious ious, i = box_iou(pred[pi, :4], tbox[ti]).max(1) # best ious, indices @@ -149,12 +150,12 @@ def test(cfg, d = ti[i[j]] # detected target if d not in detected: detected.append(d) - correct[pi[j]] = (ious[j] > iouv).cpu() # iou_thres is 1xn + correct[pi[j]] = ious[j] > iouv # iou_thres is 1xn if len(detected) == nl: # all targets already located in image break # Append statistics (correct, conf, pcls, tcls) - stats.append((correct, pred[:, 4].cpu(), pred[:, 5].cpu(), tcls)) + stats.append((correct.cpu(), pred[:, 4].cpu(), pred[:, 5].cpu(), tcls)) # Compute statistics stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy From e482392161c30d4e4dbf4b4eebdb4672fcc6a134 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 09:00:48 -0800 Subject: [PATCH 0458/1185] updates --- test.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test.py b/test.py index bfbdb09d2d..52a29061d2 100644 --- a/test.py +++ b/test.py @@ -67,7 +67,7 @@ def test(cfg, model.eval() coco91class = coco80_to_coco91_class() s = ('%20s' + '%10s' * 6) % ('Class', 'Images', 'Targets', 'P', 'R', 'mAP@0.5', 'F1') - p, r, f1, mp, mr, map, mf1 = 0., 0., 0., 0., 0., 0., 0. + p, r, f1, mp, mr, map, mf1, t0, t1 = 0., 0., 0., 0., 0., 0., 0., 0., 0. loss = torch.zeros(3) jdict, stats, ap, ap_class = [], [], [], [] for batch_i, (imgs, targets, paths, shapes) in enumerate(tqdm(dataloader, desc=s)): @@ -84,14 +84,18 @@ def test(cfg, # Disable gradients with torch.no_grad(): # Run model + t = time.time() inf_out, train_out = model(imgs) # inference and training outputs + t0 += time.time() - t # Compute loss if hasattr(model, 'hyp'): # if model has loss hyperparameters loss += compute_loss(train_out, targets, model)[1][:3].cpu() # GIoU, obj, cls # Run NMS + t = time.time() output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres) + t1 += time.time() - t # Statistics per image for si, pred in enumerate(output): @@ -177,6 +181,11 @@ def test(cfg, for i, c in enumerate(ap_class): print(pf % (names[c], seen, nt[c], p[i], r[i], ap[i], f1[i])) + # Print profile results + if opt.profile: + t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + print('Profile results: %.1f/%.1f/%.1f ms inference/NMS/total per image' % t) + # Save JSON if save_json and map and len(jdict): imgIds = [int(Path(x).stem.split('_')[-1]) for x in dataloader.dataset.img_files] @@ -220,6 +229,7 @@ def test(cfg, parser.add_argument('--task', default='test', help="'test', 'study', 'benchmark'") parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') + parser.add_argument('--profile', action='store_true', help='profile inference and NMS times') opt = parser.parse_args() opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) print(opt) From 35eae3ace984595981136b899a76563a638f2a5b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 09:53:02 -0800 Subject: [PATCH 0459/1185] updates --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 65ffbb1c69..2f38ba73c6 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -523,7 +523,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_cls=Tru pred = pred[pred[:, 4] > conf_thres] # Apply width-height constraint - pred = pred[(pred[:, 2:4] > min_wh).all(1) & (pred[:, 2:4] < max_wh).all(1)] + pred = pred[((pred[:, 2:4] > min_wh) & (pred[:, 2:4] < max_wh)).all(1)] # Compute conf pred[..., 5:] *= pred[..., 4:5] # conf = obj_conf * cls_conf From 1430a1e4083609ab197cf1947a12ab8692b20593 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 10:26:35 -0800 Subject: [PATCH 0460/1185] updates --- test.py | 10 +++++----- utils/torch_utils.py | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/test.py b/test.py index 52a29061d2..1c04af78a9 100644 --- a/test.py +++ b/test.py @@ -84,18 +84,18 @@ def test(cfg, # Disable gradients with torch.no_grad(): # Run model - t = time.time() + t = torch_utils.time_synchronized() inf_out, train_out = model(imgs) # inference and training outputs - t0 += time.time() - t + t0 += torch_utils.time_synchronized() - t # Compute loss if hasattr(model, 'hyp'): # if model has loss hyperparameters loss += compute_loss(train_out, targets, model)[1][:3].cpu() # GIoU, obj, cls # Run NMS - t = time.time() - output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres) - t1 += time.time() - t + t = torch_utils.time_synchronized() + output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres) # nms + t1 += torch_utils.time_synchronized() - t # Statistics per image for si, pred in enumerate(output): diff --git a/utils/torch_utils.py b/utils/torch_utils.py index a93b79d1aa..869575deaf 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -1,4 +1,5 @@ import os +import time import torch import torch.backends.cudnn as cudnn @@ -40,6 +41,11 @@ def select_device(device='', apex=False, batch_size=None): return torch.device('cuda:0' if cuda else 'cpu') +def time_synchronized(): + torch.cuda.synchronize() if torch.cuda.is_available() else None + return time.time() + + def fuse_conv_and_bn(conv, bn): # https://tehnokv.com/posts/fusing-batchnorm-and-conv/ with torch.no_grad(): From 3e633783d8c877f1b383d1e189642d2afac11180 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 11:36:21 -0800 Subject: [PATCH 0461/1185] updates --- test.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index 1c04af78a9..49ea0a2b24 100644 --- a/test.py +++ b/test.py @@ -17,6 +17,7 @@ def test(cfg, iou_thres=0.6, # for nms save_json=False, single_cls=False, + profile=False, model=None, dataloader=None): # Initialize/load model and set device @@ -182,7 +183,7 @@ def test(cfg, print(pf % (names[c], seen, nt[c], p[i], r[i], ap[i], f1[i])) # Print profile results - if opt.profile: + if profile: t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) print('Profile results: %.1f/%.1f/%.1f ms inference/NMS/total per image' % t) @@ -244,7 +245,8 @@ def test(cfg, opt.conf_thres, opt.iou_thres, opt.save_json, - opt.single_cls) + opt.single_cls, + opt.profile) elif opt.task == 'benchmark': # mAPs at 320-608 at conf 0.5 and 0.7 y = [] From 9c661e2d53bcaf57fe5db9092e1fd872ffc52bc4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 12:17:37 -0800 Subject: [PATCH 0462/1185] updates --- test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test.py b/test.py index 49ea0a2b24..c00347798a 100644 --- a/test.py +++ b/test.py @@ -69,7 +69,7 @@ def test(cfg, coco91class = coco80_to_coco91_class() s = ('%20s' + '%10s' * 6) % ('Class', 'Images', 'Targets', 'P', 'R', 'mAP@0.5', 'F1') p, r, f1, mp, mr, map, mf1, t0, t1 = 0., 0., 0., 0., 0., 0., 0., 0., 0. - loss = torch.zeros(3) + loss = torch.zeros(3, device=device) jdict, stats, ap, ap_class = [], [], [], [] for batch_i, (imgs, targets, paths, shapes) in enumerate(tqdm(dataloader, desc=s)): imgs = imgs.to(device).float() / 255.0 # uint8 to float32, 0 - 255 to 0.0 - 1.0 @@ -91,7 +91,7 @@ def test(cfg, # Compute loss if hasattr(model, 'hyp'): # if model has loss hyperparameters - loss += compute_loss(train_out, targets, model)[1][:3].cpu() # GIoU, obj, cls + loss += compute_loss(train_out, targets, model)[1][:3] # GIoU, obj, cls # Run NMS t = torch_utils.time_synchronized() @@ -132,7 +132,7 @@ def test(cfg, 'score': floatn(d[4], 5)}) # Assign all predictions as incorrect - correct = torch.zeros(len(pred), niou, dtype=torch.bool, device=device) + correct = torch.zeros(pred.shape[0], niou, dtype=torch.bool, device=device) if nl: detected = [] # target indices tcls_tensor = labels[:, 0] @@ -214,7 +214,7 @@ def test(cfg, maps = np.zeros(nc) + map for i, c in enumerate(ap_class): maps[c] = ap[i] - return (mp, mr, map, mf1, *(loss / len(dataloader)).tolist()), maps + return (mp, mr, map, mf1, *(loss.cpu() / len(dataloader)).tolist()), maps if __name__ == '__main__': From 6ab753a9e7a9c88ff26530ffa23d7350f3bda552 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 13:06:31 -0800 Subject: [PATCH 0463/1185] updates --- train.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 9e919f888b..b2d6cb102c 100644 --- a/train.py +++ b/train.py @@ -28,7 +28,7 @@ 'obj': 64.3, # obj loss gain (*=img_size/320 if img_size != 320) 'obj_pw': 1.0, # obj BCELoss positive_weight 'iou_t': 0.225, # iou training threshold - 'lr0': 0.00579, # initial learning rate (SGD=5E-3, Adam=5E-4) + 'lr0': 0.01, # initial learning rate (SGD=5E-3, Adam=5E-4) 'lrf': -4., # final LambdaLR learning rate = lr0 * (10 ** lrf) 'momentum': 0.937, # SGD momentum 'weight_decay': 0.000484, # optimizer weight decay @@ -141,7 +141,7 @@ def train(): # lf = lambda x: 1 - x / epochs # linear ramp to zero # lf = lambda x: 10 ** (hyp['lrf'] * x / epochs) # exp ramp # lf = lambda x: 1 - 10 ** (hyp['lrf'] * (1 - x / epochs)) # inverse exp ramp - lf = lambda x: 0.5 * (1 + math.cos(x * math.pi / epochs)) # cosine https://arxiv.org/pdf/1812.01187.pdf + lf = lambda x: (1 + math.cos(x * math.pi / epochs)) / 2 * 0.99 + 0.01 # cosine https://arxiv.org/pdf/1812.01187.pdf scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[round(epochs * x) for x in [0.8, 0.9]], gamma=0.1) scheduler.last_epoch = start_epoch @@ -311,7 +311,7 @@ def train(): batch_size=batch_size * 2, img_size=img_size_test, model=model, - conf_thres=1E-3 if opt.evolve or (final_epoch and is_coco) else 0.1, # 0.1 faster + conf_thres=0.001, # 0.001 if opt.evolve or (final_epoch and is_coco) else 0.01, iou_thres=0.6, save_json=final_epoch and is_coco, single_cls=opt.single_cls, From 981b452b1d2616cf53cb94ad439043fbb0a2efcf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 13:20:08 -0800 Subject: [PATCH 0464/1185] updates --- train.py | 3 ++- utils/utils.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index b2d6cb102c..96b2bd25d7 100644 --- a/train.py +++ b/train.py @@ -211,6 +211,7 @@ def train(): print('Starting training for %g epochs...' % epochs) for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ model.train() + model.hyps['gr'] = 1 - (1 + math.cos(min(epoch * 2, epochs) * math.pi / epochs)) / 2 # GIoU <-> 1.0 ratio # Prebias if prebias: @@ -271,7 +272,7 @@ def train(): pred = model(imgs) # Compute loss - loss, loss_items = compute_loss(pred, targets, model, not prebias) + loss, loss_items = compute_loss(pred, targets, model) if not torch.isfinite(loss): print('WARNING: non-finite loss, ending training ', loss_items) return results diff --git a/utils/utils.py b/utils/utils.py index 2f38ba73c6..5416455a11 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -363,7 +363,7 @@ def forward(self, input, target): return loss -def compute_loss(p, targets, model, giou_flag=True): # predictions, targets, model +def compute_loss(p, targets, model): # predictions, targets, model ft = torch.cuda.FloatTensor if p[0].is_cuda else torch.Tensor lcls, lbox, lobj = ft([0]), ft([0]), ft([0]) tcls, tbox, indices, anchor_vec = build_targets(model, targets) @@ -401,7 +401,7 @@ def compute_loss(p, targets, model, giou_flag=True): # predictions, targets, mo pbox = torch.cat((pxy, pwh), 1) # predicted box giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss - tobj[b, a, gj, gi] = giou.detach().clamp(0).type(tobj.dtype) if giou_flag else 1.0 + tobj[b, a, gj, gi] = (1.0 - h['gr']) + h['gr'] * giou.detach().clamp(0).type(tobj.dtype) # giou ratio if 'default' in arc and model.nc > 1: # cls loss (only if multiple classes) t = torch.zeros_like(ps[:, 5:]) # targets From 305c07bac8a1be6a055e3e438c1ec3c57ec78e7d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 13:24:18 -0800 Subject: [PATCH 0465/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 96b2bd25d7..ef3faca2ca 100644 --- a/train.py +++ b/train.py @@ -211,7 +211,7 @@ def train(): print('Starting training for %g epochs...' % epochs) for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ model.train() - model.hyps['gr'] = 1 - (1 + math.cos(min(epoch * 2, epochs) * math.pi / epochs)) / 2 # GIoU <-> 1.0 ratio + model.hyp['gr'] = 1 - (1 + math.cos(min(epoch * 2, epochs) * math.pi / epochs)) / 2 # GIoU <-> 1.0 loss ratio # Prebias if prebias: From cdb229fc76242806779b845621130bec49242350 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 13:30:27 -0800 Subject: [PATCH 0466/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index fe21ad50e5..2034169bde 100755 --- a/models.py +++ b/models.py @@ -88,7 +88,7 @@ def create_modules(module_defs, img_size, arc): # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) try: if arc == 'default' or arc == 'Fdefault': # default - b = [-5.0, -5.0] # obj, cls + b = [-3.0, -6.0] # obj, cls elif arc == 'uBCE': # unified BCE (80 classes) b = [0, -9.0] elif arc == 'uCE': # unified CE (1 background + 80 classes) From 2e88a5663555eb3e75d7bf49cef898b9aa9db743 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 14:02:42 -0800 Subject: [PATCH 0467/1185] updates --- models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/models.py b/models.py index 2034169bde..32f5176ba9 100755 --- a/models.py +++ b/models.py @@ -87,8 +87,9 @@ def create_modules(module_defs, img_size, arc): # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) try: + p = math.log(1 / (modules.nc - 1)) # class probability -> sigmoid(p) = 1/nc if arc == 'default' or arc == 'Fdefault': # default - b = [-3.0, -6.0] # obj, cls + b = [-5.0, p] # obj, cls elif arc == 'uBCE': # unified BCE (80 classes) b = [0, -9.0] elif arc == 'uCE': # unified CE (1 background + 80 classes) From 1d45ec84bc95617b36a38ff1ae33a4237df2fa73 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 14:12:31 -0800 Subject: [PATCH 0468/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 32f5176ba9..493229e750 100755 --- a/models.py +++ b/models.py @@ -87,7 +87,7 @@ def create_modules(module_defs, img_size, arc): # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) try: - p = math.log(1 / (modules.nc - 1)) # class probability -> sigmoid(p) = 1/nc + p = math.log(1 / (modules.nc - 0.99)) # class probability -> sigmoid(p) = 1/nc if arc == 'default' or arc == 'Fdefault': # default b = [-5.0, p] # obj, cls elif arc == 'uBCE': # unified BCE (80 classes) From 4a5159710f77943d1a13e81943e89476668622dc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 14:55:56 -0800 Subject: [PATCH 0469/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 493229e750..ec192c3351 100755 --- a/models.py +++ b/models.py @@ -89,7 +89,7 @@ def create_modules(module_defs, img_size, arc): try: p = math.log(1 / (modules.nc - 0.99)) # class probability -> sigmoid(p) = 1/nc if arc == 'default' or arc == 'Fdefault': # default - b = [-5.0, p] # obj, cls + b = [-4.5, p] # obj, cls elif arc == 'uBCE': # unified BCE (80 classes) b = [0, -9.0] elif arc == 'uCE': # unified CE (1 background + 80 classes) From 8b6c8a53182b2415fd61459fc9a0ccbdef8dc904 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 4 Mar 2020 16:33:14 -0800 Subject: [PATCH 0470/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index ef3faca2ca..5ca0efe490 100644 --- a/train.py +++ b/train.py @@ -215,7 +215,7 @@ def train(): # Prebias if prebias: - ne = 3 # number of prebias epochs + ne = max(round(30 / nb), 3) # number of prebias epochs ps = np.interp(epoch, [0, ne], [0.1, hyp['lr0'] * 2]), \ np.interp(epoch, [0, ne], [0.9, hyp['momentum']]) # prebias settings (lr=0.1, momentum=0.9) if epoch == ne: From b8b89a31329da9ba4146493e73f4762abca741e4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Mar 2020 09:54:41 -0800 Subject: [PATCH 0471/1185] updates --- utils/utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/utils.py b/utils/utils.py index 5416455a11..482f8974d2 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -525,6 +525,10 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_cls=Tru # Apply width-height constraint pred = pred[((pred[:, 2:4] > min_wh) & (pred[:, 2:4] < max_wh)).all(1)] + # If none remain process next image + if not pred.shape[0]: + continue + # Compute conf pred[..., 5:] *= pred[..., 4:5] # conf = obj_conf * cls_conf From 1dc1761f45fe46f077694e1a70472cd7eb788e0c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Mar 2020 10:20:08 -0800 Subject: [PATCH 0472/1185] updates --- train.py | 2 +- utils/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 5ca0efe490..b12b2b41c6 100644 --- a/train.py +++ b/train.py @@ -211,7 +211,7 @@ def train(): print('Starting training for %g epochs...' % epochs) for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ model.train() - model.hyp['gr'] = 1 - (1 + math.cos(min(epoch * 2, epochs) * math.pi / epochs)) / 2 # GIoU <-> 1.0 loss ratio + model.gr = 1 - (1 + math.cos(min(epoch * 2, epochs) * math.pi / epochs)) / 2 # GIoU <-> 1.0 loss ratio # Prebias if prebias: diff --git a/utils/utils.py b/utils/utils.py index 482f8974d2..f3403120ab 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -401,7 +401,7 @@ def compute_loss(p, targets, model): # predictions, targets, model pbox = torch.cat((pxy, pwh), 1) # predicted box giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss - tobj[b, a, gj, gi] = (1.0 - h['gr']) + h['gr'] * giou.detach().clamp(0).type(tobj.dtype) # giou ratio + tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * giou.detach().clamp(0).type(tobj.dtype) # giou ratio if 'default' in arc and model.nc > 1: # cls loss (only if multiple classes) t = torch.zeros_like(ps[:, 5:]) # targets From 378f08c6d5b356ce25d5672e5ff9ee5b19d344af Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Mar 2020 12:30:11 -0800 Subject: [PATCH 0473/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index b12b2b41c6..e73849f7ed 100644 --- a/train.py +++ b/train.py @@ -389,7 +389,7 @@ def train(): if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('--epochs', type=int, default=273) # 500200 batches at bs 16, 117263 COCO images = 273 epochs + parser.add_argument('--epochs', type=int, default=300) # 500200 batches at bs 16, 117263 COCO images = 273 epochs parser.add_argument('--batch-size', type=int, default=16) # effective bs = batch_size * accumulate = 16 * 4 = 64 parser.add_argument('--accumulate', type=int, default=4, help='batches to accumulate before optimizing') parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') From e2f235cf1ee92d7c9817f1051bc47222b5c51ba1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Mar 2020 13:22:10 -0800 Subject: [PATCH 0474/1185] Create stale.yml --- .github/workflows/stale.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000..5f3865daf1 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,21 @@ +name: Mark stale issues and pull requests + +on: + schedule: + - cron: "0 0 * * *" + +jobs: + stale: + + runs-on: ubuntu-latest + + steps: + - uses: actions/stale@1.0.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'This issue appears stale as no activity has been seen for some time. We will close this issue in the next few days.' + stale-pr-message: 'This PR appears stale as no activity has been seen for some time. We will close this PR in the next few days.' + stale-issue-label: 'Stale' + stale-pr-label: 'Stale' + days-before-stale: 10 + days-before-close: 3 From 2e8cee9fcb3e24fd2d1bf1ed418dd9b3c065e562 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Mar 2020 13:26:48 -0800 Subject: [PATCH 0475/1185] Update stale.yml --- .github/workflows/stale.yml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 5f3865daf1..598a1449ae 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,21 +1,16 @@ -name: Mark stale issues and pull requests - +name: "Close stale issues" on: schedule: - cron: "0 0 * * *" jobs: stale: - runs-on: ubuntu-latest - steps: - - uses: actions/stale@1.0.0 + - uses: actions/stale@v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: 'This issue appears stale as no activity has been seen for some time. We will close this issue in the next few days.' - stale-pr-message: 'This PR appears stale as no activity has been seen for some time. We will close this PR in the next few days.' - stale-issue-label: 'Stale' - stale-pr-label: 'Stale' - days-before-stale: 10 - days-before-close: 3 + stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days' + stale-pr-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days' + days-before-stale: 30 + days-before-close: 5 From 818d0b9f006acbd3bb6ea68530f8b31ad06e3620 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Mar 2020 13:48:29 -0800 Subject: [PATCH 0476/1185] Update stale.yml --- .github/workflows/stale.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 598a1449ae..280a0d028b 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -14,3 +14,4 @@ jobs: stale-pr-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days' days-before-stale: 30 days-before-close: 5 + exempt-issue-label: 'tutorial' From 692b006f4dda066a81800b94a34ec51c574c380f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Mar 2020 14:20:52 -0800 Subject: [PATCH 0477/1185] updates --- utils/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index f3403120ab..b2dad445b6 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -501,7 +501,7 @@ def build_targets(model, targets): return tcls, tbox, indices, av -def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_cls=True, classes=None, agnostic=False): +def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=True, classes=None, agnostic=False): """ Removes detections with lower object confidence score than 'conf_thres' Non-Maximum Suppression to further filter detections. @@ -516,7 +516,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_cls=Tru method = 'vision_batch' batched = 'batch' in method # run once per image, all classes simultaneously nc = prediction[0].shape[1] - 5 # number of classes - multi_cls = multi_cls and (nc > 1) # allow multiple classes per anchor + multi_label &= nc > 1 # multiple labels per box output = [None] * len(prediction) for image_i, pred in enumerate(prediction): # Apply conf constraint @@ -536,7 +536,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_cls=Tru box = xywh2xyxy(pred[:, :4]) # Detections matrix nx6 (xyxy, conf, cls) - if multi_cls: + if multi_label: i, j = (pred[:, 5:] > conf_thres).nonzero().t() pred = torch.cat((box[i], pred[i, j + 5].unsqueeze(1), j.float().unsqueeze(1)), 1) else: # best class only From 65eeb1bae5ea1f7d7249c0caf581e95de0dc1637 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Mar 2020 17:08:14 -0800 Subject: [PATCH 0478/1185] updates --- .github/workflows/stale.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 280a0d028b..f0d75cb44e 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,4 +1,4 @@ -name: "Close stale issues" +name: Close stale issues on: schedule: - cron: "0 0 * * *" @@ -10,8 +10,8 @@ jobs: - uses: actions/stale@v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days' - stale-pr-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days' + stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove Stale label or comment or this will be closed in 5 days.' + stale-pr-message: 'This pull request is stale because it has been open 30 days with no activity. Remove Stale label or comment or this will be closed in 5 days.' days-before-stale: 30 days-before-close: 5 exempt-issue-label: 'tutorial' From feea9c1a65c73475803847c83545b5e7ee6c528c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 7 Mar 2020 10:26:08 -0800 Subject: [PATCH 0479/1185] P and R evaluated at 0.5 score --- utils/utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index b2dad445b6..d59527c9fd 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -188,6 +188,7 @@ def ap_per_class(tp, conf, pred_cls, target_cls): unique_classes = np.unique(target_cls) # Create Precision-Recall curve and compute AP for each class + pr_score = 0.5 # score to evaluate P and R https://github.com/ultralytics/yolov3/issues/898 s = [len(unique_classes), tp.shape[1]] # number class, number iou thresholds (i.e. 10 for mAP0.5...0.95) ap, p, r = np.zeros(s), np.zeros(s), np.zeros(s) for ci, c in enumerate(unique_classes): @@ -204,18 +205,18 @@ def ap_per_class(tp, conf, pred_cls, target_cls): # Recall recall = tpc / (n_gt + 1e-16) # recall curve - r[ci] = recall[-1] + r[ci] = np.interp(-pr_score, -conf[i], recall[:, 0]) # r at pr_score, negative x, xp because xp decreases # Precision precision = tpc / (tpc + fpc) # precision curve - p[ci] = precision[-1] + p[ci] = np.interp(-pr_score, -conf[i], precision[:, 0]) # p at pr_score # AP from recall-precision curve for j in range(tp.shape[1]): ap[ci, j] = compute_ap(recall[:, j], precision[:, j]) # Plot - # fig, ax = plt.subplots(1, 1, figsize=(4, 4)) + # fig, ax = plt.subplots(1, 1, figsize=(5, 5)) # ax.plot(recall, precision) # ax.set_xlabel('Recall') # ax.set_ylabel('Precision') From 4317335795c49c2a6e4ecd6fb3687edc74a6a9b4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Mar 2020 11:43:05 -0700 Subject: [PATCH 0480/1185] updates --- test.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/test.py b/test.py index c00347798a..b1d9819dbc 100644 --- a/test.py +++ b/test.py @@ -17,7 +17,6 @@ def test(cfg, iou_thres=0.6, # for nms save_json=False, single_cls=False, - profile=False, model=None, dataloader=None): # Initialize/load model and set device @@ -182,11 +181,6 @@ def test(cfg, for i, c in enumerate(ap_class): print(pf % (names[c], seen, nt[c], p[i], r[i], ap[i], f1[i])) - # Print profile results - if profile: - t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) - print('Profile results: %.1f/%.1f/%.1f ms inference/NMS/total per image' % t) - # Save JSON if save_json and map and len(jdict): imgIds = [int(Path(x).stem.split('_')[-1]) for x in dataloader.dataset.img_files] @@ -210,6 +204,11 @@ def test(cfg, cocoEval.summarize() mf1, map = cocoEval.stats[:2] # update to pycocotools results (mAP@0.5:0.95, mAP@0.5) + # Print speeds + if verbose: + t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + (img_size, img_size, batch_size) # tuple + print('Speed: %.1f/%.1f/%.1f ms inference/NMS/total per %gx%g image at batch-size %g' % t) + # Return results maps = np.zeros(nc) + map for i, c in enumerate(ap_class): @@ -230,7 +229,6 @@ def test(cfg, parser.add_argument('--task', default='test', help="'test', 'study', 'benchmark'") parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') - parser.add_argument('--profile', action='store_true', help='profile inference and NMS times') opt = parser.parse_args() opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) print(opt) @@ -245,8 +243,7 @@ def test(cfg, opt.conf_thres, opt.iou_thres, opt.save_json, - opt.single_cls, - opt.profile) + opt.single_cls) elif opt.task == 'benchmark': # mAPs at 320-608 at conf 0.5 and 0.7 y = [] From 3122f1fe8204f75d69c7fe0ce00375c74f59725c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Mar 2020 11:52:35 -0700 Subject: [PATCH 0481/1185] updates --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a9d6d9209a..b0eff51721 100755 --- a/README.md +++ b/README.md @@ -155,11 +155,11 @@ YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive. ```bash $ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 608 -Namespace(batch_size=32, cfg='yolov3-spp', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='last82.pt') -Using CUDA device0 _CudaDeviceProperties(name='Tesla P100-PCIE-16GB', total_memory=16280MB) +Namespace(batch_size=32, cfg='cfg/yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='weights/yolov3-spp-ultralytics.pt') +Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memory=16130MB) - Class Images Targets P R mAP@0.5 F1: 100% 157/157 [03:12<00:00, 1.50it/s] - all 5e+03 3.51e+04 0.0573 0.871 0.611 0.106 + Class Images Targets P R mAP@0.5 F1: 100%|█████| 157/157 [02:46<00:00, 1.06s/it] + all 5e+03 3.51e+04 0.822 0.433 0.611 0.551 Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.419 Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.618 Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.448 From a4662bf306c72d6989ccfb96316a83c26b0bd232 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Mar 2020 11:53:18 -0700 Subject: [PATCH 0482/1185] updates --- utils/evolve.sh | 2 +- utils/gcp.sh | 25 +++++++++++++++++++++++++ utils/utils.py | 5 ----- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/utils/evolve.sh b/utils/evolve.sh index 3f81d6a0fd..3ff9c75cc9 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -9,7 +9,7 @@ while true; do # python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --evolve --cache --device $1 --cfg yolov3-tiny3-1cls.cfg --single --adam # python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg - python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --evolve --weights '' --bucket ult/coco --device $1 --cfg yolov3-spp.cfg --multi + python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --evolve --weights '' --bucket ult/coco/sppa_512 --device $1 --cfg yolov3-sppa.cfg --multi done diff --git a/utils/gcp.sh b/utils/gcp.sh index 433c248df9..4d58b14345 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -415,6 +415,29 @@ n=67 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --g n=68 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown n=69 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 15 --accum 4 --weights '' --device 0 --cfg csdarknet53-bifpn-optimal.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown n=70 && t=ultralytics/coco:v69 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 15 --accum 4 --weights '' --device 0 --cfg csresnext50-bifpn-optimal.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=71 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=72 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=73 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=74 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=75 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=76 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=77 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=78 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=79 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=80 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=81 && t=ultralytics/coco:v76 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2017.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=82 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=83 && t=ultralytics/coco:v82 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=84 && t=ultralytics/coco:v82 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=85 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=86 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=87 && t=ultralytics/coco:v85 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=88 && t=ultralytics/coco:v86 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 1 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=89 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=90 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 1 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=91 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=92 && t=ultralytics/coco:v91 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 225 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=93 && t=ultralytics/coco:v86 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown # athena @@ -434,3 +457,5 @@ n=23 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gp n=24 && t=ultralytics/wer:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights '' --multi --bucket ult/wer --name $n --nosave --cache --device 3 --cfg yolov3-tiny-3l-1cls.cfg --single --adam n=25 && t=ultralytics/wer:v25 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 2 --cfg yolov3-tiny3-1cls.cfg --single --adam n=26 && t=ultralytics/wer:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny3-1cls.cfg --single --adam +n=27 && t=ultralytics/test:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 416 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov4-tiny-1cls.cfg --single --adam +n=28 && t=ultralytics/test:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 416 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov4-tiny-1cls.cfg --single --adam diff --git a/utils/utils.py b/utils/utils.py index d59527c9fd..efb5689133 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -410,11 +410,6 @@ def compute_loss(p, targets, model): # predictions, targets, model lcls += BCEcls(ps[:, 5:], t) # BCE # lcls += CE(ps[:, 5:], tcls[i]) # CE - # Instance-class weighting (use with reduction='none') - # nt = t.sum(0) + 1 # number of targets per class - # lcls += (BCEcls(ps[:, 5:], t) / nt).mean() * nt.mean() # v1 - # lcls += (BCEcls(ps[:, 5:], t) / nt[tcls[i]].view(-1,1)).mean() * nt.mean() # v2 - # Append targets to text file # with open('targets.txt', 'a') as file: # [file.write('%11.5g ' * 4 % tuple(x) + '\n') for x in torch.cat((txy[i], twh[i]), 1)] From 17fbd6ed8c9c417272d9e988cd5fdadd270c137a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Mar 2020 11:56:37 -0700 Subject: [PATCH 0483/1185] updates --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index baccd70bf2..cdf022a3aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,10 +47,10 @@ COPY . /usr/src/app # t=ultralytics/yolov3:v0 && sudo docker build -t $t . && sudo docker push $t # Run -# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run -it $t bash +# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host $t bash # Pull and Run with local directory access -# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run -it -v "$(pwd)"/coco:/usr/src/coco $t bash +# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash # Kill all # sudo docker kill "$(sudo docker ps -q)" From 952df070db4d8106085902fa241d0e082cfc365d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Mar 2020 12:05:42 -0700 Subject: [PATCH 0484/1185] updates --- test.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test.py b/test.py index b1d9819dbc..75d527cabf 100644 --- a/test.py +++ b/test.py @@ -181,8 +181,14 @@ def test(cfg, for i, c in enumerate(ap_class): print(pf % (names[c], seen, nt[c], p[i], r[i], ap[i], f1[i])) + # Print speeds + if verbose: + t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + (img_size, img_size, batch_size) # tuple + print('Speed: %.1f/%.1f/%.1f ms inference/NMS/total per %gx%g image at batch-size %g' % t) + # Save JSON if save_json and map and len(jdict): + print('COCO mAP with pycocotools...') imgIds = [int(Path(x).stem.split('_')[-1]) for x in dataloader.dataset.img_files] with open('results.json', 'w') as file: json.dump(jdict, file) @@ -204,11 +210,6 @@ def test(cfg, cocoEval.summarize() mf1, map = cocoEval.stats[:2] # update to pycocotools results (mAP@0.5:0.95, mAP@0.5) - # Print speeds - if verbose: - t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + (img_size, img_size, batch_size) # tuple - print('Speed: %.1f/%.1f/%.1f ms inference/NMS/total per %gx%g image at batch-size %g' % t) - # Return results maps = np.zeros(nc) + map for i, c in enumerate(ap_class): From 23389da9ecd62edcad9ec364280b47c3dafe0d98 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Mar 2020 12:35:04 -0700 Subject: [PATCH 0485/1185] updates --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 75d527cabf..2b6b8f2335 100644 --- a/test.py +++ b/test.py @@ -188,7 +188,7 @@ def test(cfg, # Save JSON if save_json and map and len(jdict): - print('COCO mAP with pycocotools...') + print('\nCOCO mAP with pycocotools...') imgIds = [int(Path(x).stem.split('_')[-1]) for x in dataloader.dataset.img_files] with open('results.json', 'w') as file: json.dump(jdict, file) From 0037254bf266285c122649339c898dc7f330255d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Mar 2020 13:20:31 -0700 Subject: [PATCH 0486/1185] updates --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b0eff51721..b10092a05b 100755 --- a/README.md +++ b/README.md @@ -155,11 +155,12 @@ YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive. ```bash $ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 608 -Namespace(batch_size=32, cfg='cfg/yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='weights/yolov3-spp-ultralytics.pt') +Namespace(batch_size=32, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='weights/yolov3-spp-ultralytics.pt') Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memory=16130MB) Class Images Targets P R mAP@0.5 F1: 100%|█████| 157/157 [02:46<00:00, 1.06s/it] all 5e+03 3.51e+04 0.822 0.433 0.611 0.551 + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.419 Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.618 Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.448 @@ -172,6 +173,8 @@ Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memo Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.440 Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.649 Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.735 + +Speed: 6.6/1.6/8.2 ms inference/NMS/total per 608x608 image at batch-size 32 ``` # Reproduce Our Results From 1d43b2a55aabf5afca1c6392fcacff061d0be00e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Mar 2020 16:13:56 -0700 Subject: [PATCH 0487/1185] updates --- utils/utils.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index efb5689133..9522ad4d21 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -405,8 +405,15 @@ def compute_loss(p, targets, model): # predictions, targets, model tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * giou.detach().clamp(0).type(tobj.dtype) # giou ratio if 'default' in arc and model.nc > 1: # cls loss (only if multiple classes) - t = torch.zeros_like(ps[:, 5:]) # targets - t[range(nb), tcls[i]] = 1.0 + smooth = False # class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + if smooth: + e = 0.1 #  class label smoothing epsilon + cp, cn = 1.0 - e, e / (model.nc - 0.99) # class positive and negative labels + else: + cp, cn = 1.0, 0.0 + + t = torch.zeros_like(ps[:, 5:]) + cn # targets + t[range(nb), tcls[i]] = cp lcls += BCEcls(ps[:, 5:], t) # BCE # lcls += CE(ps[:, 5:], tcls[i]) # CE From 4a90221e79fbed6b952411b95dd8f06823c526fc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 8 Mar 2020 16:15:41 -0700 Subject: [PATCH 0488/1185] updates --- utils/utils.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 9522ad4d21..52d4591896 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -378,6 +378,14 @@ def compute_loss(p, targets, model): # predictions, targets, model BCE = nn.BCEWithLogitsLoss(reduction=red) CE = nn.CrossEntropyLoss(reduction=red) # weight=model.class_weights + # class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + smooth = False + if smooth: + e = 0.1 #  class label smoothing epsilon + cp, cn = 1.0 - e, e / (model.nc - 0.99) # class positive and negative labels + else: + cp, cn = 1.0, 0.0 + if 'F' in arc: # add focal loss g = h['fl_gamma'] BCEcls, BCEobj, BCE, CE = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g), FocalLoss(BCE, g), FocalLoss(CE, g) @@ -405,13 +413,6 @@ def compute_loss(p, targets, model): # predictions, targets, model tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * giou.detach().clamp(0).type(tobj.dtype) # giou ratio if 'default' in arc and model.nc > 1: # cls loss (only if multiple classes) - smooth = False # class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 - if smooth: - e = 0.1 #  class label smoothing epsilon - cp, cn = 1.0 - e, e / (model.nc - 0.99) # class positive and negative labels - else: - cp, cn = 1.0, 0.0 - t = torch.zeros_like(ps[:, 5:]) + cn # targets t[range(nb), tcls[i]] = cp lcls += BCEcls(ps[:, 5:], t) # BCE From 071d4113f6d8f70852f50c0af50a44f1f1fed75a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 10:43:49 -0700 Subject: [PATCH 0489/1185] updates --- models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index ec192c3351..0b203c828e 100755 --- a/models.py +++ b/models.py @@ -191,8 +191,8 @@ def __init__(self, anchors, nc, img_size, yolo_index, arc): if ONNX_EXPORT: # grids must be computed in __init__ stride = [32, 16, 8][yolo_index] # stride of this layer - nx = int(img_size[1] / stride) # number x grid points - ny = int(img_size[0] / stride) # number y grid points + nx = img_size[1] // stride # number x grid points + ny = img_size[0] // stride # number y grid points create_grids(self, img_size, (nx, ny)) def forward(self, p, img_size, var=None): From cd76a1a9827ec9a2506f272aeae76c13b895746f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 10:46:59 -0700 Subject: [PATCH 0490/1185] updates --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 0b203c828e..4c94a676c0 100755 --- a/models.py +++ b/models.py @@ -189,7 +189,7 @@ def __init__(self, anchors, nc, img_size, yolo_index, arc): self.ny = 0 # initialize number of y gridpoints self.arc = arc - if ONNX_EXPORT: # grids must be computed in __init__ + if ONNX_EXPORT: stride = [32, 16, 8][yolo_index] # stride of this layer nx = img_size[1] // stride # number x grid points ny = img_size[0] // stride # number y grid points From 6bd51b75eac4c6fd5b4f8f960d11bcb20e22156e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 11:20:22 -0700 Subject: [PATCH 0491/1185] updates --- utils/torch_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 869575deaf..941c22a48e 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -77,7 +77,7 @@ def model_info(model, report='summary'): # Plots a line-by-line description of a PyTorch model n_p = sum(x.numel() for x in model.parameters()) # number parameters n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients - if report is 'full': + if report == 'full': print('%5s %40s %9s %12s %20s %10s %10s' % ('layer', 'name', 'gradient', 'parameters', 'shape', 'mu', 'sigma')) for i, (name, p) in enumerate(model.named_parameters()): name = name.replace('module_list.', '') From 5fb661b7d43021f841bf84d6c10eed69970fa257 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 13:33:23 -0700 Subject: [PATCH 0492/1185] updates --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 2b6b8f2335..f6a688590a 100644 --- a/test.py +++ b/test.py @@ -38,7 +38,7 @@ def test(cfg, else: # darknet format load_darknet_weights(model, weights) - if torch.cuda.device_count() > 1: + if device.type != 'cpu' and torch.cuda.device_count() > 1: model = nn.DataParallel(model) else: # called by train.py device = next(model.parameters()).device # get model device From 67e7ac221fcb36d75579bc9269d72b7b06286506 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 14:20:38 -0700 Subject: [PATCH 0493/1185] updates --- models.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/models.py b/models.py index 4c94a676c0..80976a66e6 100755 --- a/models.py +++ b/models.py @@ -195,7 +195,7 @@ def __init__(self, anchors, nc, img_size, yolo_index, arc): ny = img_size[0] // stride # number y grid points create_grids(self, img_size, (nx, ny)) - def forward(self, p, img_size, var=None): + def forward(self, p, img_size): if ONNX_EXPORT: bs = 1 # batch size else: @@ -261,10 +261,9 @@ def __init__(self, cfg, img_size=(416, 416), arc='default'): self.version = np.array([0, 2, 5], dtype=np.int32) # (int32) version info: major, minor, revision self.seen = np.array([0], dtype=np.int64) # (int64) number of images seen during training - def forward(self, x, var=None): + def forward(self, x, verbose=False): img_size = x.shape[-2:] yolo_out, out = [], [] - verbose = False if verbose: str = '' print('0', x.shape) From 6130b70fe7df8ecf542924b1014b2f90b77a0880 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 16:00:05 -0700 Subject: [PATCH 0494/1185] updates --- models.py | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/models.py b/models.py index 80976a66e6..9c651342e8 100755 --- a/models.py +++ b/models.py @@ -87,24 +87,13 @@ def create_modules(module_defs, img_size, arc): # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) try: - p = math.log(1 / (modules.nc - 0.99)) # class probability -> sigmoid(p) = 1/nc - if arc == 'default' or arc == 'Fdefault': # default - b = [-4.5, p] # obj, cls - elif arc == 'uBCE': # unified BCE (80 classes) - b = [0, -9.0] - elif arc == 'uCE': # unified CE (1 background + 80 classes) - b = [10, -0.1] - elif arc == 'uFBCE': # unified FocalBCE (5120 obj, 80 classes) - b = [0, -6.5] - elif arc == 'uFCE': # unified FocalCE (64 cls, 1 background + 80 classes) - b = [7.7, -1.1] + bo = -4.5 #  obj bias + bc = math.log(1 / (modules.nc - 0.99)) # cls bias: class probability is sigmoid(p) = 1/nc bias = module_list[-1][0].bias.view(len(mask), -1) # 255 to 3x85 - bias[:, 4] += b[0] - bias[:, 4].mean() # obj - bias[:, 5:] += b[1] - bias[:, 5:].mean() # cls - # bias = torch.load('weights/yolov3-spp.bias.pt')[yolo_index] # list of tensors [3x85, 3x85, 3x85] - module_list[-1][0].bias = torch.nn.Parameter(bias.view(-1)) - # utils.print_model_biases(model) + bias[:, 4] += bo - bias[:, 4].mean() # obj + bias[:, 5:] += bc - bias[:, 5:].mean() # cls + module_list[-1][0].bias = torch.nn.Parameter(bias.view(-1)) # utils.print_model_biases(model) except: print('WARNING: smart bias initialization failure.') From 204594f2997ac7ca28fcc9b67dc52d30878648f1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 16:44:26 -0700 Subject: [PATCH 0495/1185] updates --- models.py | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/models.py b/models.py index 9c651342e8..c71aaf139a 100755 --- a/models.py +++ b/models.py @@ -169,7 +169,6 @@ def forward(self, x): class YOLOLayer(nn.Module): def __init__(self, anchors, nc, img_size, yolo_index, arc): super(YOLOLayer, self).__init__() - self.anchors = torch.Tensor(anchors) self.na = len(anchors) # number of anchors (3) self.nc = nc # number of classes (80) @@ -213,27 +212,12 @@ def forward(self, p, img_size): return p_cls, xy * ng, wh else: # inference - # s = 1.5 # scale_xy (pxy = pxy * s - (s - 1) / 2) io = p.clone() # inference output io[..., :2] = torch.sigmoid(io[..., :2]) + self.grid_xy # xy io[..., 2:4] = torch.exp(io[..., 2:4]) * self.anchor_wh # wh yolo method - # io[..., 2:4] = ((torch.sigmoid(io[..., 2:4]) * 2) ** 3) * self.anchor_wh # wh power method io[..., :4] *= self.stride - - if 'default' in self.arc: # seperate obj and cls - torch.sigmoid_(io[..., 4:]) - elif 'BCE' in self.arc: # unified BCE (80 classes) - torch.sigmoid_(io[..., 5:]) - io[..., 4] = 1 - elif 'CE' in self.arc: # unified CE (1 background + 80 classes) - io[..., 4:] = F.softmax(io[..., 4:], dim=4) - io[..., 4] = 1 - - if self.nc == 1: - io[..., 5] = 1 # single-class model https://github.com/ultralytics/yolov3/issues/235 - - # reshape from [1, 3, 13, 13, 85] to [1, 507, 85] - return io.view(bs, -1, self.no), p + torch.sigmoid_(io[..., 4:]) + return io.view(bs, -1, self.no), p # view [1, 3, 13, 13, 85] as [1, 507, 85] class Darknet(nn.Module): From 207cf14df46776f753059888178325d03b8d9f41 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 18:03:34 -0700 Subject: [PATCH 0496/1185] updates --- models.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/models.py b/models.py index c71aaf139a..a326d7d6d7 100755 --- a/models.py +++ b/models.py @@ -41,6 +41,9 @@ def create_modules(module_defs, img_size, arc): elif mdef['activation'] == 'swish': modules.add_module('activation', Swish()) + if not bn: # detection output layer + routs.append(i) + elif mdef['type'] == 'maxpool': size = mdef['size'] stride = mdef['stride'] From 25ad727a3d93c12ecf3c83f9bfe49c01ab6187df Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 18:22:42 -0700 Subject: [PATCH 0497/1185] updates --- models.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/models.py b/models.py index a326d7d6d7..0a21285344 100755 --- a/models.py +++ b/models.py @@ -95,8 +95,7 @@ def create_modules(module_defs, img_size, arc): bias = module_list[-1][0].bias.view(len(mask), -1) # 255 to 3x85 bias[:, 4] += bo - bias[:, 4].mean() # obj - bias[:, 5:] += bc - bias[:, 5:].mean() # cls - module_list[-1][0].bias = torch.nn.Parameter(bias.view(-1)) # utils.print_model_biases(model) + bias[:, 5:] += bc - bias[:, 5:].mean() # cls, view with utils.print_model_biases(model) except: print('WARNING: smart bias initialization failure.') From f7f435446b618f9819b2db3515851a3bab33bff6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 18:24:20 -0700 Subject: [PATCH 0498/1185] updates --- models.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/models.py b/models.py index 0a21285344..568b1267f9 100755 --- a/models.py +++ b/models.py @@ -81,8 +81,7 @@ def create_modules(module_defs, img_size, arc): elif mdef['type'] == 'yolo': yolo_index += 1 - mask = mdef['mask'] # anchor mask - modules = YOLOLayer(anchors=mdef['anchors'][mask], # anchor list + modules = YOLOLayer(anchors=mdef['anchors'][mdef['mask']], # anchor list nc=mdef['classes'], # number of classes img_size=img_size, # (416, 416) yolo_index=yolo_index, # 0, 1 or 2 @@ -93,7 +92,7 @@ def create_modules(module_defs, img_size, arc): bo = -4.5 #  obj bias bc = math.log(1 / (modules.nc - 0.99)) # cls bias: class probability is sigmoid(p) = 1/nc - bias = module_list[-1][0].bias.view(len(mask), -1) # 255 to 3x85 + bias = module_list[-1][0].bias.view(modules.na, -1) # 255 to 3x85 bias[:, 4] += bo - bias[:, 4].mean() # obj bias[:, 5:] += bc - bias[:, 5:].mean() # cls, view with utils.print_model_biases(model) except: From 821a72b2d342df7c3e6453021212bfd675ff915a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 18:39:00 -0700 Subject: [PATCH 0499/1185] updates --- detect.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/detect.py b/detect.py index 64a7867d39..d4ad635e87 100644 --- a/detect.py +++ b/detect.py @@ -77,7 +77,6 @@ def detect(save_img=False): # Run inference t0 = time.time() for path, img, im0s, vid_cap in dataset: - t = time.time() img = torch.from_numpy(img).to(device) img = img.half() if half else img.float() # uint8 to fp16/32 img /= 255.0 # 0 - 255 to 0.0 - 1.0 @@ -85,7 +84,9 @@ def detect(save_img=False): img = img.unsqueeze(0) # Inference + t1 = torch_utils.time_synchronized() pred = model(img)[0].float() if half else model(img)[0] + t2 = torch_utils.time_synchronized() # Apply NMS pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, classes=opt.classes, agnostic=opt.agnostic_nms) @@ -123,7 +124,7 @@ def detect(save_img=False): plot_one_box(xyxy, im0, label=label, color=colors[int(cls)]) # Print time (inference + NMS) - print('%sDone. (%.3fs)' % (s, time.time() - t)) + print('%sDone. (%.3fs)' % (s, t2 - t1)) # Stream results if view_img: From d8370d13eae5d33a589bc61b4c7bcfc40f7f4e78 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 18:49:35 -0700 Subject: [PATCH 0500/1185] updates --- models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/models.py b/models.py index 568b1267f9..f7632267d8 100755 --- a/models.py +++ b/models.py @@ -35,15 +35,15 @@ def create_modules(module_defs, img_size, arc): bias=not bn)) if bn: modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.1)) + else: + routs.append(i) # detection output (goes into yolo layer) + if mdef['activation'] == 'leaky': # activation study https://github.com/ultralytics/yolov3/issues/441 modules.add_module('activation', nn.LeakyReLU(0.1, inplace=True)) # modules.add_module('activation', nn.PReLU(num_parameters=1, init=0.10)) elif mdef['activation'] == 'swish': modules.add_module('activation', Swish()) - if not bn: # detection output layer - routs.append(i) - elif mdef['type'] == 'maxpool': size = mdef['size'] stride = mdef['stride'] From 17a06dcf83e0d179ac49821877679390fa0ef97f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 18:55:17 -0700 Subject: [PATCH 0501/1185] updates --- models.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/models.py b/models.py index f7632267d8..652cd7133b 100755 --- a/models.py +++ b/models.py @@ -81,18 +81,20 @@ def create_modules(module_defs, img_size, arc): elif mdef['type'] == 'yolo': yolo_index += 1 + l = mdef['from'] if 'from' in mdef else [] modules = YOLOLayer(anchors=mdef['anchors'][mdef['mask']], # anchor list nc=mdef['classes'], # number of classes img_size=img_size, # (416, 416) - yolo_index=yolo_index, # 0, 1 or 2 - arc=arc) # yolo architecture + yolo_index=yolo_index, # 0, 1, 2... + layers=l) # output layers # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) try: bo = -4.5 #  obj bias bc = math.log(1 / (modules.nc - 0.99)) # cls bias: class probability is sigmoid(p) = 1/nc - bias = module_list[-1][0].bias.view(modules.na, -1) # 255 to 3x85 + j = l[yolo_index] if 'from' in mdef else -1 + bias = module_list[j][0].bias.view(modules.na, -1) # 255 to 3x85 bias[:, 4] += bo - bias[:, 4].mean() # obj bias[:, 5:] += bc - bias[:, 5:].mean() # cls, view with utils.print_model_biases(model) except: @@ -168,15 +170,17 @@ def forward(self, x): class YOLOLayer(nn.Module): - def __init__(self, anchors, nc, img_size, yolo_index, arc): + def __init__(self, anchors, nc, img_size, yolo_index, layers): super(YOLOLayer, self).__init__() self.anchors = torch.Tensor(anchors) + self.index = yolo_index # index of this layer in layers + self.layers = layers # model output layer indices + self.nl = len(layers) # number of output layers (3) self.na = len(anchors) # number of anchors (3) self.nc = nc # number of classes (80) - self.no = nc + 5 # number of outputs + self.no = nc + 5 # number of outputs (85) self.nx = 0 # initialize number of x gridpoints self.ny = 0 # initialize number of y gridpoints - self.arc = arc if ONNX_EXPORT: stride = [32, 16, 8][yolo_index] # stride of this layer @@ -184,7 +188,7 @@ def __init__(self, anchors, nc, img_size, yolo_index, arc): ny = img_size[0] // stride # number y grid points create_grids(self, img_size, (nx, ny)) - def forward(self, p, img_size): + def forward(self, p, img_size, out): if ONNX_EXPORT: bs = 1 # batch size else: @@ -268,7 +272,7 @@ def forward(self, x, verbose=False): x = torch.cat([out[i] for i in layers], 1) # print(''), [print(out[i].shape) for i in layers], print(x.shape) elif mtype == 'yolo': - yolo_out.append(module(x, img_size)) + yolo_out.append(module(x, img_size, out)) out.append(x if i in self.routs else []) if verbose: print('%g/%g %s -' % (i, len(self.module_list), mtype), list(x.shape), str) From d55dbc1f2913794495763d6f31936364f40918a8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Mar 2020 20:08:19 -0700 Subject: [PATCH 0502/1185] updates --- models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/models.py b/models.py index 652cd7133b..6961806627 100755 --- a/models.py +++ b/models.py @@ -94,9 +94,11 @@ def create_modules(module_defs, img_size, arc): bc = math.log(1 / (modules.nc - 0.99)) # cls bias: class probability is sigmoid(p) = 1/nc j = l[yolo_index] if 'from' in mdef else -1 - bias = module_list[j][0].bias.view(modules.na, -1) # 255 to 3x85 + bias_ = module_list[j][0].bias # shape(255,) + bias = bias_[:modules.no * modules.na].view(modules.na, -1) # shape(3,85) bias[:, 4] += bo - bias[:, 4].mean() # obj bias[:, 5:] += bc - bias[:, 5:].mean() # cls, view with utils.print_model_biases(model) + module_list[j][0].bias = torch.nn.Parameter(bias_, requires_grad=bias_.requires_grad) except: print('WARNING: smart bias initialization failure.') From 7a83574022e6c5551b798e773d89dccf7aa876da Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 10 Mar 2020 12:17:23 -0700 Subject: [PATCH 0503/1185] updates --- train.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/train.py b/train.py index e73849f7ed..d3e20aa8da 100644 --- a/train.py +++ b/train.py @@ -36,10 +36,10 @@ 'hsv_h': 0.0138, # image HSV-Hue augmentation (fraction) 'hsv_s': 0.678, # image HSV-Saturation augmentation (fraction) 'hsv_v': 0.36, # image HSV-Value augmentation (fraction) - 'degrees': 1.98, # image rotation (+/- deg) - 'translate': 0.05, # image translation (+/- fraction) - 'scale': 0.05, # image scale (+/- gain) - 'shear': 0.641} # image shear (+/- deg) + 'degrees': 1.98 * 0, # image rotation (+/- deg) + 'translate': 0.05 * 0, # image translation (+/- fraction) + 'scale': 0.05 * 0, # image scale (+/- gain) + 'shear': 0.641 * 0} # image shear (+/- deg) # Overwrite hyp with hyp*.txt (optional) f = glob.glob('hyp*.txt') @@ -197,7 +197,7 @@ def train(): # Start training nb = len(dataloader) - prebias = start_epoch == 0 + prebias = False # start_epoch == 0 model.nc = nc # attach number of classes to model model.arc = opt.arc # attach yolo architecture model.hyp = hyp # attach hyperparameters to model @@ -211,7 +211,7 @@ def train(): print('Starting training for %g epochs...' % epochs) for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ model.train() - model.gr = 1 - (1 + math.cos(min(epoch * 2, epochs) * math.pi / epochs)) / 2 # GIoU <-> 1.0 loss ratio + model.gr = 1 - (1 + math.cos(min(epoch * 1, epochs) * math.pi / epochs)) / 2 # GIoU <-> 1.0 loss ratio # Prebias if prebias: From 585064f300fa2d4bb80667927adc12caf1dbcc30 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 10 Mar 2020 13:33:14 -0700 Subject: [PATCH 0504/1185] updates --- utils/datasets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index ff05385684..b462aa3ab1 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -276,6 +276,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r self.hyp = hyp self.image_weights = image_weights self.rect = False if image_weights else rect + self.mosaic = self.augment and not self.rect # load 4 images at a time into a mosaic (only during training) # Define labels self.label_files = [x.replace('images', 'labels').replace(os.path.splitext(x)[-1], '.txt') @@ -417,8 +418,7 @@ def __getitem__(self, index): label_path = self.label_files[index] hyp = self.hyp - mosaic = True and self.augment # load 4 images at a time into a mosaic (only during training) - if mosaic: + if self.mosaic: # Load mosaic img, labels = load_mosaic(self, index) shapes = None @@ -450,7 +450,7 @@ def __getitem__(self, index): if self.augment: # Augment imagespace - if not mosaic: + if not self.mosaic: img, labels = random_affine(img, labels, degrees=hyp['degrees'], translate=hyp['translate'], From 320f9c6601ae1bddae036a5094dfe81ac1441cc3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Mar 2020 12:18:03 -0700 Subject: [PATCH 0505/1185] updates --- train.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/train.py b/train.py index d3e20aa8da..303138945e 100644 --- a/train.py +++ b/train.py @@ -138,15 +138,11 @@ def train(): model, optimizer = amp.initialize(model, optimizer, opt_level='O1', verbosity=0) # Scheduler https://github.com/ultralytics/yolov3/issues/238 - # lf = lambda x: 1 - x / epochs # linear ramp to zero - # lf = lambda x: 10 ** (hyp['lrf'] * x / epochs) # exp ramp - # lf = lambda x: 1 - 10 ** (hyp['lrf'] * (1 - x / epochs)) # inverse exp ramp lf = lambda x: (1 + math.cos(x * math.pi / epochs)) / 2 * 0.99 + 0.01 # cosine https://arxiv.org/pdf/1812.01187.pdf - scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) - # scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[round(epochs * x) for x in [0.8, 0.9]], gamma=0.1) - scheduler.last_epoch = start_epoch + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf, last_epoch=start_epoch - 1) + # scheduler = lr_scheduler.MultiStepLR(optimizer, [round(epochs * x) for x in [0.8, 0.9]], 0.1, start_epoch - 1) - # # Plot lr schedule + # Plot lr schedule # y = [] # for _ in range(epochs): # scheduler.step() From 4089735c5e515698b0b3b60e8726e6d601cfc090 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Mar 2020 14:50:50 -0700 Subject: [PATCH 0506/1185] updates --- train.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/train.py b/train.py index 303138945e..d4bfc08dc6 100644 --- a/train.py +++ b/train.py @@ -238,15 +238,10 @@ def train(): targets = targets.to(device) # Hyperparameter burn-in - # n_burn = nb - 1 # min(nb // 5 + 1, 1000) # number of burn-in batches - # if ni <= n_burn: - # for m in model.named_modules(): - # if m[0].endswith('BatchNorm2d'): - # m[1].momentum = 1 - i / n_burn * 0.99 # BatchNorm2d momentum falls from 1 - 0.01 - # g = (i / n_burn) ** 4 # gain rises from 0 - 1 + # n_burn = 100 # number of burn-in batches + # if ni < n_burn: # for x in optimizer.param_groups: - # x['lr'] = hyp['lr0'] * g - # x['weight_decay'] = hyp['weight_decay'] * g + # x['lr'] = x['initial_lr'] * (ni / n_burn) ** 4 # gain rises from 0 - 1 # Plot images with bounding boxes if ni < 1: From e40d4c87f2e77e9169399c1c3e17295c42db88c4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Mar 2020 15:57:37 -0700 Subject: [PATCH 0507/1185] updates --- train.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/train.py b/train.py index d4bfc08dc6..9cd25a393d 100644 --- a/train.py +++ b/train.py @@ -237,11 +237,15 @@ def train(): imgs = imgs.to(device).float() / 255.0 # uint8 to float32, 0 - 255 to 0.0 - 1.0 targets = targets.to(device) - # Hyperparameter burn-in - # n_burn = 100 # number of burn-in batches - # if ni < n_burn: - # for x in optimizer.param_groups: - # x['lr'] = x['initial_lr'] * (ni / n_burn) ** 4 # gain rises from 0 - 1 + # Hyperparameter Burn-in + n_burn = 100 # number of burn-in batches + if ni <= n_burn: + g = (ni / n_burn) ** 4 # gain + for x in model.named_modules(): + if x[0].endswith('BatchNorm2d'): + x[1].momentum = 1 - 0.9 * g # momentum falls from 1 - 0.1 + for x in optimizer.param_groups: + x['lr'] = x['initial_lr'] * g # gain rises from 0 - 1 # Plot images with bounding boxes if ni < 1: From e76d4d0ffc904ef678c23cc41fcdeca20b66894a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Mar 2020 17:13:40 -0700 Subject: [PATCH 0508/1185] updates --- train.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 9cd25a393d..85dd8c6bdd 100644 --- a/train.py +++ b/train.py @@ -238,12 +238,13 @@ def train(): targets = targets.to(device) # Hyperparameter Burn-in - n_burn = 100 # number of burn-in batches + n_burn = 200 # number of burn-in batches if ni <= n_burn: g = (ni / n_burn) ** 4 # gain for x in model.named_modules(): if x[0].endswith('BatchNorm2d'): - x[1].momentum = 1 - 0.9 * g # momentum falls from 1 - 0.1 + # x[1].momentum = 1 - 0.9 * g # momentum falls from 1 - 0.1 + x[1].track_running_stats = ni == n_burn for x in optimizer.param_groups: x['lr'] = x['initial_lr'] * g # gain rises from 0 - 1 From 673a1d037ddbfe8d6c305ad5b751bf219ba01455 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Mar 2020 18:12:54 -0700 Subject: [PATCH 0509/1185] Create greetings.yml --- .github/workflows/greetings.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/workflows/greetings.yml diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml new file mode 100644 index 0000000000..f550a8a125 --- /dev/null +++ b/.github/workflows/greetings.yml @@ -0,0 +1,13 @@ +name: Greetings + +on: [pull_request, issues] + +jobs: + greeting: + runs-on: ubuntu-latest + steps: + - uses: actions/first-interaction@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + pr-message: 'Hello **#**! Thank you for submitting a PR. We will respond as soon as possible.' + issue-message: "Hello **#**! Thank you for your interest in our work! Please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://colab.research.google.com/drive/1G8T-VFxQkjDe4idzN8F-hbIBqkkkQnxw), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. If this is a bug report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you." From 997cd7f70b0550fded97880086b4ed1b7d0880a4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Mar 2020 20:35:52 -0700 Subject: [PATCH 0510/1185] Update greetings.yml --- .github/workflows/greetings.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index f550a8a125..9c7323deb5 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -9,5 +9,8 @@ jobs: - uses: actions/first-interaction@v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - pr-message: 'Hello **#**! Thank you for submitting a PR. We will respond as soon as possible.' - issue-message: "Hello **#**! Thank you for your interest in our work! Please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://colab.research.google.com/drive/1G8T-VFxQkjDe4idzN8F-hbIBqkkkQnxw), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. If this is a bug report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you." + pr-message: 'Thank you for submitting a PR. We will respond as soon as possible.' + issue-message: > + Thank you for your interest in our work! Please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://colab.research.google.com/drive/1G8T-VFxQkjDe4idzN8F-hbIBqkkkQnxw), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. + + If this is a bug report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you. From 75e88561cb480fc2422372f71081db1586ee0c5a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Mar 2020 20:45:14 -0700 Subject: [PATCH 0511/1185] updates --- train.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 85dd8c6bdd..d35407fbbf 100644 --- a/train.py +++ b/train.py @@ -240,13 +240,13 @@ def train(): # Hyperparameter Burn-in n_burn = 200 # number of burn-in batches if ni <= n_burn: - g = (ni / n_burn) ** 4 # gain + g = (ni / n_burn) ** 2 # gain for x in model.named_modules(): if x[0].endswith('BatchNorm2d'): # x[1].momentum = 1 - 0.9 * g # momentum falls from 1 - 0.1 x[1].track_running_stats = ni == n_burn for x in optimizer.param_groups: - x['lr'] = x['initial_lr'] * g # gain rises from 0 - 1 + x['lr'] = x['initial_lr'] * lf(epoch) * g # gain rises from 0 - 1 # Plot images with bounding boxes if ni < 1: From 6ca8277de26e5587821bd778bea3a61feb1c8d15 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Mar 2020 21:30:47 -0700 Subject: [PATCH 0512/1185] updates --- README.md | 2 +- utils/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b10092a05b..3119e27781 100755 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ Namespace(batch_size=32, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memory=16130MB) Class Images Targets P R mAP@0.5 F1: 100%|█████| 157/157 [02:46<00:00, 1.06s/it] - all 5e+03 3.51e+04 0.822 0.433 0.611 0.551 + all 5e+03 3.51e+04 0.51 0.667 0.611 0.574 Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.419 Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.618 diff --git a/utils/utils.py b/utils/utils.py index 52d4591896..16e0c8bf61 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -188,7 +188,7 @@ def ap_per_class(tp, conf, pred_cls, target_cls): unique_classes = np.unique(target_cls) # Create Precision-Recall curve and compute AP for each class - pr_score = 0.5 # score to evaluate P and R https://github.com/ultralytics/yolov3/issues/898 + pr_score = 0.1 # score to evaluate P and R https://github.com/ultralytics/yolov3/issues/898 s = [len(unique_classes), tp.shape[1]] # number class, number iou thresholds (i.e. 10 for mAP0.5...0.95) ap, p, r = np.zeros(s), np.zeros(s), np.zeros(s) for ci, c in enumerate(unique_classes): From 41bf46a4191cf04bfeda78a3e82bc24c2cd6ffb0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 11 Mar 2020 22:11:19 -0700 Subject: [PATCH 0513/1185] updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index d35407fbbf..36cef23459 100644 --- a/train.py +++ b/train.py @@ -240,7 +240,7 @@ def train(): # Hyperparameter Burn-in n_burn = 200 # number of burn-in batches if ni <= n_burn: - g = (ni / n_burn) ** 2 # gain + g = ni / n_burn # gain for x in model.named_modules(): if x[0].endswith('BatchNorm2d'): # x[1].momentum = 1 - 0.9 * g # momentum falls from 1 - 0.1 From 8a1f35eac66083840a5170695d2a7fd7ade914ed Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 12 Mar 2020 01:09:17 -0700 Subject: [PATCH 0514/1185] updates --- utils/utils.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 16e0c8bf61..c36d82f4e9 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -364,6 +364,11 @@ def forward(self, input, target): return loss +def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 + # return positive, negative label smoothing BCE targets + return 1.0 - 0.5 * eps, 0.5 * eps + + def compute_loss(p, targets, model): # predictions, targets, model ft = torch.cuda.FloatTensor if p[0].is_cuda else torch.Tensor lcls, lbox, lobj = ft([0]), ft([0]), ft([0]) @@ -379,12 +384,7 @@ def compute_loss(p, targets, model): # predictions, targets, model CE = nn.CrossEntropyLoss(reduction=red) # weight=model.class_weights # class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 - smooth = False - if smooth: - e = 0.1 #  class label smoothing epsilon - cp, cn = 1.0 - e, e / (model.nc - 0.99) # class positive and negative labels - else: - cp, cn = 1.0, 0.0 + cp, cn = smooth_BCE(eps=0.0) if 'F' in arc: # add focal loss g = h['fl_gamma'] @@ -656,15 +656,18 @@ def print_model_biases(model): print('\nModel Bias Summary: %8s%18s%18s%18s' % ('layer', 'regression', 'objectness', 'classification')) multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) for l in model.yolo_layers: # print pretrained biases - if multi_gpu: - na = model.module.module_list[l].na # number of anchors - b = model.module.module_list[l - 1][0].bias.view(na, -1) # bias 3x85 - else: - na = model.module_list[l].na - b = model.module_list[l - 1][0].bias.view(na, -1) # bias 3x85 - print(' ' * 20 + '%8g %18s%18s%18s' % (l, '%5.2f+/-%-5.2f' % (b[:, :4].mean(), b[:, :4].std()), - '%5.2f+/-%-5.2f' % (b[:, 4].mean(), b[:, 4].std()), - '%5.2f+/-%-5.2f' % (b[:, 5:].mean(), b[:, 5:].std()))) + try: + if multi_gpu: + na = model.module.module_list[l].na # number of anchors + b = model.module.module_list[l - 1][0].bias.view(na, -1) # bias 3x85 + else: + na = model.module_list[l].na + b = model.module_list[l - 1][0].bias.view(na, -1) # bias 3x85 + print(' ' * 20 + '%8g %18s%18s%18s' % (l, '%5.2f+/-%-5.2f' % (b[:, :4].mean(), b[:, :4].std()), + '%5.2f+/-%-5.2f' % (b[:, 4].mean(), b[:, 4].std()), + '%5.2f+/-%-5.2f' % (b[:, 5:].mean(), b[:, 5:].std()))) + except: + pass def strip_optimizer(f='weights/last.pt'): # from utils.utils import *; strip_optimizer() From 1ca2b8712a6b0a3dcd8112035d3056b77ad97022 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 12 Mar 2020 13:34:27 -0700 Subject: [PATCH 0515/1185] Update greetings.yml --- .github/workflows/greetings.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 9c7323deb5..4c8871779f 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -9,8 +9,8 @@ jobs: - uses: actions/first-interaction@v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - pr-message: 'Thank you for submitting a PR. We will respond as soon as possible.' + pr-message: 'Hello @${{ github.actor }}, thank you for submitting a PR! We will respond as soon as possible.' issue-message: > - Thank you for your interest in our work! Please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://colab.research.google.com/drive/1G8T-VFxQkjDe4idzN8F-hbIBqkkkQnxw), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. + Hello @${{ github.actor }}, thank you for your interest in our work! Please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://colab.research.google.com/drive/1G8T-VFxQkjDe4idzN8F-hbIBqkkkQnxw), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. If this is a bug report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you. From 32404890e93242b07596613fed71713ec8c2c733 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 12 Mar 2020 13:35:21 -0700 Subject: [PATCH 0516/1185] Update greetings.yml --- .github/workflows/greetings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 4c8871779f..f9535cd287 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -12,5 +12,5 @@ jobs: pr-message: 'Hello @${{ github.actor }}, thank you for submitting a PR! We will respond as soon as possible.' issue-message: > Hello @${{ github.actor }}, thank you for your interest in our work! Please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://colab.research.google.com/drive/1G8T-VFxQkjDe4idzN8F-hbIBqkkkQnxw), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. - + If this is a bug report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you. From a2786230671415e4d5c95a5c4f930fed3438b156 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Mar 2020 10:06:17 -0700 Subject: [PATCH 0517/1185] replaced floatn() with round() --- test.py | 4 ++-- utils/utils.py | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/test.py b/test.py index f6a688590a..5e50549141 100644 --- a/test.py +++ b/test.py @@ -127,8 +127,8 @@ def test(cfg, for di, d in enumerate(pred): jdict.append({'image_id': image_id, 'category_id': coco91class[int(d[5])], - 'bbox': [floatn(x, 3) for x in box[di]], - 'score': floatn(d[4], 5)}) + 'bbox': [round(x, 3) for x in box[di]], + 'score': round(d[4], 5)}) # Assign all predictions as incorrect correct = torch.zeros(pred.shape[0], niou, dtype=torch.bool, device=device) diff --git a/utils/utils.py b/utils/utils.py index c36d82f4e9..9fb0d0e5fb 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -26,10 +26,6 @@ cv2.setNumThreads(0) -def floatn(x, n=3): # format floats to n decimals - return float(format(x, '.%gf' % n)) - - def init_seeds(seed=0): random.seed(seed) np.random.seed(seed) From 5362e8254e934bc90eca8520de313a58dff02eff Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Mar 2020 10:20:52 -0700 Subject: [PATCH 0518/1185] updates --- test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index 5e50549141..845abfb384 100644 --- a/test.py +++ b/test.py @@ -127,8 +127,8 @@ def test(cfg, for di, d in enumerate(pred): jdict.append({'image_id': image_id, 'category_id': coco91class[int(d[5])], - 'bbox': [round(x, 3) for x in box[di]], - 'score': round(d[4], 5)}) + 'bbox': [round(x, 3) for x in box[di].tolist()], + 'score': round(d[4].item(), 5)}) # Assign all predictions as incorrect correct = torch.zeros(pred.shape[0], niou, dtype=torch.bool, device=device) From 731305142b6a0c18a3736de9b0b2f8fae81bc85f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Mar 2020 10:35:58 -0700 Subject: [PATCH 0519/1185] json dict bug fixes and speed improvements --- test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test.py b/test.py index 845abfb384..b7d33d3703 100644 --- a/test.py +++ b/test.py @@ -124,11 +124,11 @@ def test(cfg, scale_coords(imgs[si].shape[1:], box, shapes[si][0], shapes[si][1]) # to original shape box = xyxy2xywh(box) # xywh box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner - for di, d in enumerate(pred): + for p, b in zip(pred.tolist(), box.tolist()): jdict.append({'image_id': image_id, - 'category_id': coco91class[int(d[5])], - 'bbox': [round(x, 3) for x in box[di].tolist()], - 'score': round(d[4].item(), 5)}) + 'category_id': coco91class[int(p[5])], + 'bbox': [round(x, 3) for x in b], + 'score': round(p[4], 5)}) # Assign all predictions as incorrect correct = torch.zeros(pred.shape[0], niou, dtype=torch.bool, device=device) From 6aae5aca64e153afd24446c55f619613f5a62c27 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Mar 2020 10:47:00 -0700 Subject: [PATCH 0520/1185] inplace clip_coords() clamp --- utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 9fb0d0e5fb..5b9d4b43e8 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -160,8 +160,8 @@ def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None): def clip_coords(boxes, img_shape): # Clip bounding xyxy bounding boxes to image shape (height, width) - boxes[:, [0, 2]] = boxes[:, [0, 2]].clamp(min=0, max=img_shape[1]) # clip x - boxes[:, [1, 3]] = boxes[:, [1, 3]].clamp(min=0, max=img_shape[0]) # clip y + boxes[:, [0, 2]].clamp_(0, img_shape[1]) # clip x + boxes[:, [1, 3]].clamp_(0, img_shape[0]) # clip y def ap_per_class(tp, conf, pred_cls, target_cls): From 0de07da61287f764cce440986ddf8ff6d4d3a8ff Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Mar 2020 11:03:39 -0700 Subject: [PATCH 0521/1185] updates --- README.md | 2 +- utils/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3119e27781..20042ff870 100755 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memo Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.649 Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.735 -Speed: 6.6/1.6/8.2 ms inference/NMS/total per 608x608 image at batch-size 32 +Speed: 6.6/1.5/8.1 ms inference/NMS/total per 608x608 image at batch-size 32 ``` # Reproduce Our Results diff --git a/utils/utils.py b/utils/utils.py index 5b9d4b43e8..01f2587804 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -325,7 +325,7 @@ def box_area(box): lt = torch.max(boxes1[:, None, :2], boxes2[:, :2]) # [N,M,2] rb = torch.min(boxes1[:, None, 2:], boxes2[:, 2:]) # [N,M,2] - inter = (rb - lt).clamp(min=0).prod(2) # [N,M] + inter = (rb - lt).clamp(0).prod(2) # [N,M] return inter / (area1[:, None] + area2 - inter) # iou = inter / (area1 + area2 - inter) From f30a8706e518f3e1fc67c7a1ba3cfb2182015f6a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Mar 2020 12:06:48 -0700 Subject: [PATCH 0522/1185] update to coco results82 --- train.py | 27 +++++++++++++-------------- utils/utils.py | 6 +++--- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/train.py b/train.py index 36cef23459..fe4d8a44df 100644 --- a/train.py +++ b/train.py @@ -97,7 +97,6 @@ def train(): optimizer = optim.SGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) optimizer.add_param_group({'params': pg1, 'weight_decay': hyp['weight_decay']}) # add pg1 with weight_decay optimizer.add_param_group({'params': pg2}) # add pg2 (biases) - optimizer.param_groups[2]['lr'] *= 2.0 # bias lr del pg0, pg1, pg2 start_epoch = 0 @@ -138,7 +137,7 @@ def train(): model, optimizer = amp.initialize(model, optimizer, opt_level='O1', verbosity=0) # Scheduler https://github.com/ultralytics/yolov3/issues/238 - lf = lambda x: (1 + math.cos(x * math.pi / epochs)) / 2 * 0.99 + 0.01 # cosine https://arxiv.org/pdf/1812.01187.pdf + lf = lambda x: (1 + math.cos(x * math.pi / epochs)) / 2 # cosine https://arxiv.org/pdf/1812.01187.pdf scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf, last_epoch=start_epoch - 1) # scheduler = lr_scheduler.MultiStepLR(optimizer, [round(epochs * x) for x in [0.8, 0.9]], 0.1, start_epoch - 1) @@ -192,8 +191,8 @@ def train(): collate_fn=dataset.collate_fn) # Start training - nb = len(dataloader) - prebias = False # start_epoch == 0 + nb = len(dataloader) # number of batches + prebias = start_epoch == 0 model.nc = nc # attach number of classes to model model.arc = opt.arc # attach yolo architecture model.hyp = hyp # attach hyperparameters to model @@ -207,14 +206,15 @@ def train(): print('Starting training for %g epochs...' % epochs) for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ model.train() - model.gr = 1 - (1 + math.cos(min(epoch * 1, epochs) * math.pi / epochs)) / 2 # GIoU <-> 1.0 loss ratio # Prebias if prebias: - ne = max(round(30 / nb), 3) # number of prebias epochs - ps = np.interp(epoch, [0, ne], [0.1, hyp['lr0'] * 2]), \ - np.interp(epoch, [0, ne], [0.9, hyp['momentum']]) # prebias settings (lr=0.1, momentum=0.9) + ne = 3 # number of prebias epochs + ps = 0.1, 0.9 # prebias settings (lr=0.1, momentum=0.9) + model.gr = 0.0 # giou loss ratio (obj_loss = 1.0) if epoch == ne: + ps = hyp['lr0'], hyp['momentum'] # normal training settings + model.gr = 1.0 # giou loss ratio (obj_loss = giou) print_model_biases(model) prebias = False @@ -240,13 +240,12 @@ def train(): # Hyperparameter Burn-in n_burn = 200 # number of burn-in batches if ni <= n_burn: - g = ni / n_burn # gain - for x in model.named_modules(): + # g = ni / n_burn # gain + for x in model.named_modules(): # initial stats may be poor, wait to track if x[0].endswith('BatchNorm2d'): - # x[1].momentum = 1 - 0.9 * g # momentum falls from 1 - 0.1 x[1].track_running_stats = ni == n_burn - for x in optimizer.param_groups: - x['lr'] = x['initial_lr'] * lf(epoch) * g # gain rises from 0 - 1 + # for x in optimizer.param_groups: + # x['lr'] = x['initial_lr'] * lf(epoch) * g # gain rises from 0 - 1 # Plot images with bounding boxes if ni < 1: @@ -308,7 +307,7 @@ def train(): batch_size=batch_size * 2, img_size=img_size_test, model=model, - conf_thres=0.001, # 0.001 if opt.evolve or (final_epoch and is_coco) else 0.01, + conf_thres=0.001 if final_epoch else 0.01, # 0.001 for best mAP, 0.01 for speed iou_thres=0.6, save_json=final_epoch and is_coco, single_cls=opt.single_cls, diff --git a/utils/utils.py b/utils/utils.py index 01f2587804..99e4466572 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -406,7 +406,7 @@ def compute_loss(p, targets, model): # predictions, targets, model pbox = torch.cat((pxy, pwh), 1) # predicted box giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss - tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * giou.detach().clamp(0).type(tobj.dtype) # giou ratio + tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * giou.detach().type(tobj.dtype) # giou ratio if 'default' in arc and model.nc > 1: # cls loss (only if multiple classes) t = torch.zeros_like(ps[:, 5:]) + cn # targets @@ -563,10 +563,10 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T if batched: c = pred[:, 5] * 0 if agnostic else pred[:, 5] # class-agnostic NMS boxes, scores = pred[:, :4].clone(), pred[:, 4] + boxes += c.view(-1, 1) * max_wh if method == 'vision_batch': - i = torchvision.ops.boxes.batched_nms(boxes, scores, c, iou_thres) + i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) elif method == 'fast_batch': # FastNMS from https://github.com/dbolya/yolact - boxes += c.view(-1, 1) * max_wh iou = box_iou(boxes, boxes).triu_(diagonal=1) # upper triangular iou matrix i = iou.max(dim=0)[0] < iou_thres From 208b9a73fede99aef1d348db3dc25a7ed677bbf2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Mar 2020 16:08:49 -0700 Subject: [PATCH 0523/1185] updates --- train.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/train.py b/train.py index fe4d8a44df..0a1d5525e0 100644 --- a/train.py +++ b/train.py @@ -240,12 +240,14 @@ def train(): # Hyperparameter Burn-in n_burn = 200 # number of burn-in batches if ni <= n_burn: - # g = ni / n_burn # gain + # g = (ni / n_burn) ** 2 # gain for x in model.named_modules(): # initial stats may be poor, wait to track if x[0].endswith('BatchNorm2d'): x[1].track_running_stats = ni == n_burn # for x in optimizer.param_groups: # x['lr'] = x['initial_lr'] * lf(epoch) * g # gain rises from 0 - 1 + # if 'momentum' in x: + # x['momentum'] = hyp['momentum'] * g # Plot images with bounding boxes if ni < 1: From 418269d739b0fc990565e54e7c55128674a313f2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Mar 2020 16:51:30 -0700 Subject: [PATCH 0524/1185] FocalLoss() gamma and alpha default values --- train.py | 2 +- utils/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/train.py b/train.py index 0a1d5525e0..b34c229361 100644 --- a/train.py +++ b/train.py @@ -32,7 +32,7 @@ 'lrf': -4., # final LambdaLR learning rate = lr0 * (10 ** lrf) 'momentum': 0.937, # SGD momentum 'weight_decay': 0.000484, # optimizer weight decay - 'fl_gamma': 0.5, # focal loss gamma + 'fl_gamma': 1.5, # focal loss gamma 'hsv_h': 0.0138, # image HSV-Hue augmentation (fraction) 'hsv_s': 0.678, # image HSV-Saturation augmentation (fraction) 'hsv_v': 0.36, # image HSV-Value augmentation (fraction) diff --git a/utils/utils.py b/utils/utils.py index 99e4466572..788fd63d80 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -340,7 +340,7 @@ def wh_iou(wh1, wh2): class FocalLoss(nn.Module): # Wraps focal loss around existing loss_fcn() https://arxiv.org/pdf/1708.02002.pdf # i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=2.5) - def __init__(self, loss_fcn, gamma=0.5, alpha=1): + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): super(FocalLoss, self).__init__() self.loss_fcn = loss_fcn self.gamma = gamma From a52c0abf8dfb9707df2baade03a7de80932d7692 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Mar 2020 20:12:54 -0700 Subject: [PATCH 0525/1185] updates --- train.py | 12 ++++++++--- utils/torch_utils.py | 47 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index b34c229361..e2ba4b0b9d 100644 --- a/train.py +++ b/train.py @@ -190,13 +190,19 @@ def train(): pin_memory=True, collate_fn=dataset.collate_fn) - # Start training - nb = len(dataloader) # number of batches - prebias = start_epoch == 0 + # Model parameters model.nc = nc # attach number of classes to model model.arc = opt.arc # attach yolo architecture model.hyp = hyp # attach hyperparameters to model + model.gr = 0.0 # giou loss ratio (obj_loss = 1.0 or giou) model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) # attach class weights + + # Model EMA + # ema = torch_utils.ModelEMA(model, decay=0.9997) + + # Start training + nb = len(dataloader) # number of batches + prebias = start_epoch == 0 maps = np.zeros(nc) # mAP per class # torch.autograd.set_detect_anomaly(True) results = (0, 0, 0, 0, 0, 0, 0) # 'P', 'R', 'mAP', 'F1', 'val GIoU', 'val Objectness', 'val Classification' diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 941c22a48e..c706f7f52f 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -1,8 +1,10 @@ import os import time +from copy import deepcopy import torch import torch.backends.cudnn as cudnn +import torch.nn as nn def init_seeds(seed=0): @@ -101,3 +103,48 @@ def load_classifier(name='resnet101', n=2): model.last_linear.weight = torch.nn.Parameter(torch.zeros(n, filters)) model.last_linear.out_features = n return model + + +class ModelEMA: + """ Model Exponential Moving Average from https://github.com/rwightman/pytorch-image-models + Keep a moving average of everything in the model state_dict (parameters and buffers). + This is intended to allow functionality like + https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage + A smoothed version of the weights is necessary for some training schemes to perform well. + E.g. Google's hyper-params for training MNASNet, MobileNet-V3, EfficientNet, etc that use + RMSprop with a short 2.4-3 epoch decay period and slow LR decay rate of .96-.99 requires EMA + smoothing of weights to match results. Pay attention to the decay constant you are using + relative to your update count per epoch. + To keep EMA from using GPU resources, set device='cpu'. This will save a bit of memory but + disable validation of the EMA weights. Validation will have to be done manually in a separate + process, or after the training stops converging. + This class is sensitive where it is initialized in the sequence of model init, + GPU assignment and distributed training wrappers. + I've tested with the sequence in my own train.py for torch.DataParallel, apex.DDP, and single-GPU. + """ + + def __init__(self, model, decay=0.9998, device=''): + # make a copy of the model for accumulating moving average of weights + self.ema = deepcopy(model) + self.ema.eval() + self.decay = decay + self.device = device # perform ema on different device from model if set + if device: + self.ema.to(device=device) + for p in self.ema.parameters(): + p.requires_grad_(False) + + def update(self, model): + d = self.decay + with torch.no_grad(): + if type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel): + msd, esd = model.module.state_dict(), self.ema.module.state_dict() + else: + msd, esd = model.state_dict(), self.ema.state_dict() + + # self.ema.load_state_dict( + # {k: esd[k] * d + (1 - d) * v.detach() for k, v in model.items() if v.dtype.is_floating_point}) + for k in msd.keys(): + if esd[k].dtype.is_floating_point: + esd[k] *= d + esd[k] += (1. - d) * msd[k].detach() From 666ba85ed33e6b1864cdc37b5787c77c5a38bed7 Mon Sep 17 00:00:00 2001 From: Falak Date: Sun, 15 Mar 2020 04:05:59 +0530 Subject: [PATCH 0526/1185] Comment updates on box coordinates (#852) * Update utils.py Reusing function defined above * Update utils.py * Reverting change which break bbox coordinate computation * Update utils.py Co-authored-by: Glenn Jocher --- utils/utils.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 788fd63d80..ec997b2ab4 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -103,22 +103,22 @@ def weights_init_normal(m): def xyxy2xywh(x): - # Convert bounding box format from [x1, y1, x2, y2] to [x, y, w, h] + # Transform box coordinates from [x1, y1, x2, y2] (where xy1=top-left, xy2=bottom-right) to [x, y, w, h] y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) - y[:, 0] = (x[:, 0] + x[:, 2]) / 2 - y[:, 1] = (x[:, 1] + x[:, 3]) / 2 - y[:, 2] = x[:, 2] - x[:, 0] - y[:, 3] = x[:, 3] - x[:, 1] + y[:, 0] = (x[:, 0] + x[:, 2]) / 2 # x center + y[:, 1] = (x[:, 1] + x[:, 3]) / 2 # y center + y[:, 2] = x[:, 2] - x[:, 0] # width + y[:, 3] = x[:, 3] - x[:, 1] # height return y def xywh2xyxy(x): - # Convert bounding box format from [x, y, w, h] to [x1, y1, x2, y2] + # Transform box coordinates from [x, y, w, h] to [x1, y1, x2, y2] (where xy1=top-left, xy2=bottom-right) y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) - y[:, 0] = x[:, 0] - x[:, 2] / 2 - y[:, 1] = x[:, 1] - x[:, 3] / 2 - y[:, 2] = x[:, 0] + x[:, 2] / 2 - y[:, 3] = x[:, 1] + x[:, 3] / 2 + y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x + y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y + y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x + y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y return y @@ -264,7 +264,7 @@ def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False): if x1y1x2y2: # x1, y1, x2, y2 = box1 b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3] b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3] - else: # x, y, w, h = box1 + else: # transform from xywh to xyxy b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2 b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2 b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2 @@ -670,8 +670,6 @@ def strip_optimizer(f='weights/last.pt'): # from utils.utils import *; strip_op # Strip optimizer from *.pt files for lighter files (reduced by 2/3 size) x = torch.load(f, map_location=torch.device('cpu')) x['optimizer'] = None - # x['training_results'] = None # uncomment to create a backbone - # x['epoch'] = -1 # uncomment to create a backbone torch.save(x, f) @@ -1038,7 +1036,7 @@ def plot_results_overlay(start=0, stop=0): # from utils.utils import *; plot_re def plot_results(start=0, stop=0, bucket='', id=()): # from utils.utils import *; plot_results() - # Plot training results files 'results*.txt' + # Plot training 'results*.txt' as seen in https://github.com/ultralytics/yolov3#training fig, ax = plt.subplots(2, 5, figsize=(12, 6)) ax = ax.ravel() s = ['GIoU', 'Objectness', 'Classification', 'Precision', 'Recall', From b89cc396af3218828f6915722280c67f711496f0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 14 Mar 2020 16:23:14 -0700 Subject: [PATCH 0527/1185] EMA class updates --- train.py | 5 ++--- utils/torch_utils.py | 18 +++++++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/train.py b/train.py index e2ba4b0b9d..18d2d0f184 100644 --- a/train.py +++ b/train.py @@ -217,7 +217,6 @@ def train(): if prebias: ne = 3 # number of prebias epochs ps = 0.1, 0.9 # prebias settings (lr=0.1, momentum=0.9) - model.gr = 0.0 # giou loss ratio (obj_loss = 1.0) if epoch == ne: ps = hyp['lr0'], hyp['momentum'] # normal training settings model.gr = 1.0 # giou loss ratio (obj_loss = giou) @@ -307,6 +306,7 @@ def train(): scheduler.step() # Process epoch results + # ema.update_attr(model) final_epoch = epoch + 1 == epochs if not opt.notest or final_epoch: # Calculate mAP is_coco = any([x in data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) and model.nc == 80 @@ -348,8 +348,7 @@ def train(): chkpt = {'epoch': epoch, 'best_fitness': best_fitness, 'training_results': f.read(), - 'model': model.module.state_dict() if type( - model) is nn.parallel.DistributedDataParallel else model.state_dict(), + 'model': model.module.state_dict() if hasattr(model, 'module') else model.state_dict(), 'optimizer': None if final_epoch else optimizer.state_dict()} # Save last checkpoint diff --git a/utils/torch_utils.py b/utils/torch_utils.py index c706f7f52f..b394b642aa 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -141,10 +141,14 @@ def update(self, model): msd, esd = model.module.state_dict(), self.ema.module.state_dict() else: msd, esd = model.state_dict(), self.ema.state_dict() - - # self.ema.load_state_dict( - # {k: esd[k] * d + (1 - d) * v.detach() for k, v in model.items() if v.dtype.is_floating_point}) - for k in msd.keys(): - if esd[k].dtype.is_floating_point: - esd[k] *= d - esd[k] += (1. - d) * msd[k].detach() + # self.ema.load_state_dict({k: esd[k] * d + (1 - d) * v.detach() for k, v in model.items() if v.dtype.is_floating_point}) + for k, v in esd.items(): + if v.dtype.is_floating_point: + v *= d + v += (1. - d) * msd[k].detach() + + def update_attr(self, model): + # Assign attributes (which may change during training) + for k in model.__dict__.keys(): + if not k.startswith('_'): + self.ema.__setattr__(k, model.getattr(k)) From 9ce4ec48a7ede61a51515cecbfd6f966c242cd2a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 14 Mar 2020 16:46:54 -0700 Subject: [PATCH 0528/1185] model.info() method implemented --- detect.py | 1 - models.py | 7 ++++++- train.py | 1 - utils/torch_utils.py | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/detect.py b/detect.py index d4ad635e87..0608398819 100644 --- a/detect.py +++ b/detect.py @@ -36,7 +36,6 @@ def detect(save_img=False): # Fuse Conv2d + BatchNorm2d layers # model.fuse() - # torch_utils.model_info(model, report='summary') # 'full' or 'summary' # Eval mode model.to(device).eval() diff --git a/models.py b/models.py index 6961806627..04224ac04e 100755 --- a/models.py +++ b/models.py @@ -240,6 +240,7 @@ def __init__(self, cfg, img_size=(416, 416), arc='default'): # Darknet Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 self.version = np.array([0, 2, 5], dtype=np.int32) # (int32) version info: major, minor, revision self.seen = np.array([0], dtype=np.int64) # (int64) number of images seen during training + self.info() # print model description def forward(self, x, verbose=False): img_size = x.shape[-2:] @@ -291,6 +292,7 @@ def forward(self, x, verbose=False): def fuse(self): # Fuse Conv2d + BatchNorm2d layers throughout model + print('Fusing Conv2d() and BatchNorm2d() layers...') fused_list = nn.ModuleList() for a in list(self.children())[0]: if isinstance(a, nn.Sequential): @@ -303,7 +305,10 @@ def fuse(self): break fused_list.append(a) self.module_list = fused_list - # model_info(self) # yolov3-spp reduced from 225 to 152 layers + self.info() # yolov3-spp reduced from 225 to 152 layers + + def info(self, verbose=False): + torch_utils.model_info(self, verbose) def get_yolo_layers(model): diff --git a/train.py b/train.py index 18d2d0f184..2e4a9744d2 100644 --- a/train.py +++ b/train.py @@ -207,7 +207,6 @@ def train(): # torch.autograd.set_detect_anomaly(True) results = (0, 0, 0, 0, 0, 0, 0) # 'P', 'R', 'mAP', 'F1', 'val GIoU', 'val Objectness', 'val Classification' t0 = time.time() - torch_utils.model_info(model, report='summary') # 'full' or 'summary' print('Using %g dataloader workers' % nw) print('Starting training for %g epochs...' % epochs) for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ diff --git a/utils/torch_utils.py b/utils/torch_utils.py index b394b642aa..98e80345e3 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -75,11 +75,11 @@ def fuse_conv_and_bn(conv, bn): return fusedconv -def model_info(model, report='summary'): +def model_info(model, verbose=False): # Plots a line-by-line description of a PyTorch model n_p = sum(x.numel() for x in model.parameters()) # number parameters n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients - if report == 'full': + if verbose: print('%5s %40s %9s %12s %20s %10s %10s' % ('layer', 'name', 'gradient', 'parameters', 'shape', 'mu', 'sigma')) for i, (name, p) in enumerate(model.named_parameters()): name = name.replace('module_list.', '') From ea4c26b32d621286610a21949eed3d506cad95c9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 14 Mar 2020 16:54:04 -0700 Subject: [PATCH 0529/1185] BatchNorm2d() to EfficientDet defaults: decay=0.997 eps=1e-4 --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 04224ac04e..1d9dae0e56 100755 --- a/models.py +++ b/models.py @@ -34,7 +34,7 @@ def create_modules(module_defs, img_size, arc): groups=mdef['groups'] if 'groups' in mdef else 1, bias=not bn)) if bn: - modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.1)) + modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.003, eps=1E-4)) else: routs.append(i) # detection output (goes into yolo layer) From 5ebbb2db28cb59d226fbc079c305670d7117c4ad Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 14 Mar 2020 17:04:38 -0700 Subject: [PATCH 0530/1185] ASFF implementation --- models.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/models.py b/models.py index 1d9dae0e56..e9675f89e6 100755 --- a/models.py +++ b/models.py @@ -191,7 +191,27 @@ def __init__(self, anchors, nc, img_size, yolo_index, layers): create_grids(self, img_size, (nx, ny)) def forward(self, p, img_size, out): - if ONNX_EXPORT: + ASFF = False # https://arxiv.org/abs/1911.09516 + if ASFF: + i, n = self.index, self.nl # index in layers, number of layers + p = out[self.layers[i]] + bs, _, ny, nx = p.shape # bs, 255, 13, 13 + if (self.nx, self.ny) != (nx, ny): + create_grids(self, img_size, (nx, ny), p.device, p.dtype) + + # outputs and weights + # w = F.softmax(p[:, -n:], 1) # normalized weights + w = torch.sigmoid(p[:, -n:]) * (2 / n) # sigmoid weights (faster) + # w = w / w.sum(1).unsqueeze(1) # normalize across layer dimension + + # weighted ASFF sum + p = out[self.layers[i]][:, :-n] * w[:, i:i + 1] + for j in range(n): + if j != i: + p += w[:, j:j + 1] * \ + F.interpolate(out[self.layers[j]][:, :-n], size=[ny, nx], mode='bilinear', align_corners=False) + + elif ONNX_EXPORT: bs = 1 # batch size else: bs, _, ny, nx = p.shape # bs, 255, 13, 13 From d91469a516837f66741f83f82b30e8a22bed0aa1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 14 Mar 2020 17:33:29 -0700 Subject: [PATCH 0531/1185] EMA class updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 2e4a9744d2..a41a3179f1 100644 --- a/train.py +++ b/train.py @@ -198,7 +198,7 @@ def train(): model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) # attach class weights # Model EMA - # ema = torch_utils.ModelEMA(model, decay=0.9997) + # ema = torch_utils.ModelEMA(model, decay=0.9998) # Start training nb = len(dataloader) # number of batches From 851c9b98839b18f867e37521d09a5688da90f095 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 14 Mar 2020 17:34:13 -0700 Subject: [PATCH 0532/1185] EMA class updates --- train.py | 1 + 1 file changed, 1 insertion(+) diff --git a/train.py b/train.py index a41a3179f1..83f5155271 100644 --- a/train.py +++ b/train.py @@ -292,6 +292,7 @@ def train(): if ni % accumulate == 0: optimizer.step() optimizer.zero_grad() + # ema.update(model) # Print batch results mloss = (mloss * i + loss_items) / (i + 1) # update mean losses From adba66c3a64a98e29914668a14cabfbb2ed1b919 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 14 Mar 2020 18:08:48 -0700 Subject: [PATCH 0533/1185] EMA class updates --- utils/torch_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 98e80345e3..36ab9eadb8 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -151,4 +151,4 @@ def update_attr(self, model): # Assign attributes (which may change during training) for k in model.__dict__.keys(): if not k.startswith('_'): - self.ema.__setattr__(k, model.getattr(k)) + setattr(model, k, getattr(model, k)) From 07d2f0ad03d1c6a0dcff1737c320e983c1d5a01f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 15 Mar 2020 18:39:54 -0700 Subject: [PATCH 0534/1185] test/inference time augmentation --- test.py | 15 ++++++++++++++- utils/torch_utils.py | 11 +++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/test.py b/test.py index b7d33d3703..d9439f6b29 100644 --- a/test.py +++ b/test.py @@ -73,7 +73,7 @@ def test(cfg, for batch_i, (imgs, targets, paths, shapes) in enumerate(tqdm(dataloader, desc=s)): imgs = imgs.to(device).float() / 255.0 # uint8 to float32, 0 - 255 to 0.0 - 1.0 targets = targets.to(device) - _, _, height, width = imgs.shape # batch size, channels, height, width + nb, _, height, width = imgs.shape # batch size, channels, height, width whwh = torch.Tensor([width, height, width, height]).to(device) # Plot images with bounding boxes @@ -83,11 +83,24 @@ def test(cfg, # Disable gradients with torch.no_grad(): + aug = False # augment https://github.com/ultralytics/yolov3/issues/931 + if aug: + imgs = torch.cat((imgs, + imgs.flip(3), # flip-lr + torch_utils.scale_img(imgs, 0.7), # scale + ), 0) + # Run model t = torch_utils.time_synchronized() inf_out, train_out = model(imgs) # inference and training outputs t0 += torch_utils.time_synchronized() - t + if aug: + x = torch.split(inf_out, nb, dim=0) + x[1][..., 0] = width - x[1][..., 0] # flip lr + x[2][..., :4] /= 0.7 # scale + inf_out = torch.cat(x, 1) + # Compute loss if hasattr(model, 'hyp'): # if model has loss hyperparameters loss += compute_loss(train_out, targets, model)[1][:3] # GIoU, obj, cls diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 36ab9eadb8..187d51429e 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -5,6 +5,7 @@ import torch import torch.backends.cudnn as cudnn import torch.nn as nn +import torch.nn.functional as F def init_seeds(seed=0): @@ -105,6 +106,16 @@ def load_classifier(name='resnet101', n=2): return model +def scale_img(img, r=1.0): # img(16,3,256,416), r=ratio + # scales a batch of pytorch images while retaining same input shape (cropped or grey-padded) + h, w = img.shape[2:] + s = (int(h * r), int(w * r)) # new size + p = h - s[0], w - s[1] # pad/crop pixels + img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize + return F.pad(img, [0, p[1], 0, p[0]], value=0.5) if r < 1.0 else img[:, :, :p[0], :p[1]] # pad/crop + # cv2.imwrite('scaled.jpg', np.array(img[0].permute((1, 2, 0)) * 255.0)) + + class ModelEMA: """ Model Exponential Moving Average from https://github.com/rwightman/pytorch-image-models Keep a moving average of everything in the model state_dict (parameters and buffers). From c4047000fe6708fc4468774ad4416043cb4dd499 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 16 Mar 2020 14:03:50 -0700 Subject: [PATCH 0535/1185] FocalLoss() updated to match TF --- utils/utils.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index ec997b2ab4..929f6ba419 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -338,19 +338,25 @@ def wh_iou(wh1, wh2): class FocalLoss(nn.Module): - # Wraps focal loss around existing loss_fcn() https://arxiv.org/pdf/1708.02002.pdf - # i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=2.5) + # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): super(FocalLoss, self).__init__() - self.loss_fcn = loss_fcn + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() self.gamma = gamma self.alpha = alpha self.reduction = loss_fcn.reduction self.loss_fcn.reduction = 'none' # required to apply FL to each element - def forward(self, input, target): - loss = self.loss_fcn(input, target) - loss *= self.alpha * (1.000001 - torch.exp(-loss)) ** self.gamma # non-zero power for gradient stability + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + # loss *= self.alpha * (1.000001 - torch.exp(-loss)) ** self.gamma # non-zero power for gradient stability + + # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py + pred_prob = torch.sigmoid(pred) # prob from logits + p_t = true * pred_prob + (1 - true) * (1 - pred_prob) + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) + modulating_factor = (1.0 - p_t) ** self.gamma + loss = alpha_factor * modulating_factor * loss if self.reduction == 'mean': return loss.mean() From c09fcfc4fe3a5b478cecf5c26de88468bc4ab1d9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 16 Mar 2020 14:18:56 -0700 Subject: [PATCH 0536/1185] EMA class updates --- utils/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 929f6ba419..82b75d41dc 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -349,7 +349,8 @@ def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): def forward(self, pred, true): loss = self.loss_fcn(pred, true) - # loss *= self.alpha * (1.000001 - torch.exp(-loss)) ** self.gamma # non-zero power for gradient stability + # p_t = torch.exp(-loss) + # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py pred_prob = torch.sigmoid(pred) # prob from logits From 2a12a91245127ff0f23ff360a5b522b5249dc2c4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 16 Mar 2020 15:19:58 -0700 Subject: [PATCH 0537/1185] nvcr.io/nvidia/pytorch:20.02-py3 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index cdf022a3aa..d1667cd32b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch -FROM nvcr.io/nvidia/pytorch:20.01-py3 +FROM nvcr.io/nvidia/pytorch:20.02-py3 # Install dependencies (pip or conda) RUN pip install -U gsutil From f1208f784e7f47c3fbe3ed7a6cc7f94bfa8d6751 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 16 Mar 2020 15:36:56 -0700 Subject: [PATCH 0538/1185] updated run history --- utils/gcp.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index 4d58b14345..932852c4ff 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -6,7 +6,8 @@ git clone https://github.com/ultralytics/yolov3 # sudo apt-get install zip #git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex sudo conda install -yc conda-forge scikit-image pycocotools -python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('193Zp_ye-3qXMonR1nZj3YyxMtQkMy50k','coco2014.zip')" +# python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('193Zp_ye-3qXMonR1nZj3YyxMtQkMy50k','coco2014.zip')" +python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco2017.zip')" python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1C3HewOG9akA3y456SZLBJZfNDPkBwAto','knife.zip')" python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('13g3LqdpkNE8sPosVJT6KFXlfoMypzRP4','sm4.zip')" sudo shutdown @@ -438,6 +439,15 @@ n=90 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --g n=91 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown n=92 && t=ultralytics/coco:v91 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 225 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown n=93 && t=ultralytics/coco:v86 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=94 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=95 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=96 && t=ultralytics/coco:v94 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 64 --accum 1 --weights '' --device 0 --cfg yolov4-tiny.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=97 && t=ultralytics/coco:v94 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 64 --accum 1 --weights '' --device 1 --cfg yolov4-tiny-spp.cfg --nosave --bucket ult/coco --name $n --multi +n=98 && t=ultralytics/coco:v94 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 64 --accum 1 --weights '' --device 0 --cfg yolov4-tiny-spp-dn53.cfg --nosave --bucket ult/coco --name $n --multi --cache && sudo shutdown +n=99 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov4-asff.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=100 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=101 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown +n=102 && t=ultralytics/coco:v101 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi --arc Fdefault && sudo shutdown # athena @@ -459,3 +469,4 @@ n=25 && t=ultralytics/wer:v25 && sudo docker pull $t && sudo docker run -it --gp n=26 && t=ultralytics/wer:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny3-1cls.cfg --single --adam n=27 && t=ultralytics/test:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 416 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov4-tiny-1cls.cfg --single --adam n=28 && t=ultralytics/test:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 416 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov4-tiny-1cls.cfg --single --adam +n=29 && t=ultralytics/wer:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov4-tiny-spp-1cls-dn53.cfg --single --adam From 1a12667ce1f0af92b68987e4b48b060a6f738248 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 16 Mar 2020 17:31:37 -0700 Subject: [PATCH 0539/1185] loss function cleanup --- utils/utils.py | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 82b75d41dc..7bb8babb40 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -377,21 +377,19 @@ def compute_loss(p, targets, model): # predictions, targets, model lcls, lbox, lobj = ft([0]), ft([0]), ft([0]) tcls, tbox, indices, anchor_vec = build_targets(model, targets) h = model.hyp # hyperparameters - arc = model.arc # # (default, uCE, uBCE) detection architectures + arc = model.arc # architecture red = 'mean' # Loss reduction (sum or mean) # Define criteria BCEcls = nn.BCEWithLogitsLoss(pos_weight=ft([h['cls_pw']]), reduction=red) BCEobj = nn.BCEWithLogitsLoss(pos_weight=ft([h['obj_pw']]), reduction=red) - BCE = nn.BCEWithLogitsLoss(reduction=red) - CE = nn.CrossEntropyLoss(reduction=red) # weight=model.class_weights # class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 cp, cn = smooth_BCE(eps=0.0) - if 'F' in arc: # add focal loss - g = h['fl_gamma'] - BCEcls, BCEobj, BCE, CE = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g), FocalLoss(BCE, g), FocalLoss(CE, g) + # focal loss + if 'F' in arc: + BCEcls, BCEobj = FocalLoss(BCEcls, h['fl_gamma']), FocalLoss(BCEobj, h['fl_gamma']) # Compute losses np, ng = 0, 0 # number grid points, targets @@ -415,8 +413,8 @@ def compute_loss(p, targets, model): # predictions, targets, model lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * giou.detach().type(tobj.dtype) # giou ratio - if 'default' in arc and model.nc > 1: # cls loss (only if multiple classes) - t = torch.zeros_like(ps[:, 5:]) + cn # targets + if model.nc > 1: # cls loss (only if multiple classes) + t = torch.full_like(ps[:, 5:], cn) # targets t[range(nb), tcls[i]] = cp lcls += BCEcls(ps[:, 5:], t) # BCE # lcls += CE(ps[:, 5:], tcls[i]) # CE @@ -425,20 +423,7 @@ def compute_loss(p, targets, model): # predictions, targets, model # with open('targets.txt', 'a') as file: # [file.write('%11.5g ' * 4 % tuple(x) + '\n') for x in torch.cat((txy[i], twh[i]), 1)] - if 'default' in arc: # separate obj and cls - lobj += BCEobj(pi[..., 4], tobj) # obj loss - - elif 'BCE' in arc: # unified BCE (80 classes) - t = torch.zeros_like(pi[..., 5:]) # targets - if nb: - t[b, a, gj, gi, tcls[i]] = 1.0 - lobj += BCE(pi[..., 5:], t) - - elif 'CE' in arc: # unified CE (1 background + 80 classes) - t = torch.zeros_like(pi[..., 0], dtype=torch.long) # targets - if nb: - t[b, a, gj, gi] = tcls[i] + 1 - lcls += CE(pi[..., 4:].view(-1, model.nc + 1), t.view(-1)) + lobj += BCEobj(pi[..., 4], tobj) # obj loss lbox *= h['giou'] lobj *= h['obj'] From 77c6c01970495a1636dce4090ff57f80c44eb72a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 16 Mar 2020 17:51:40 -0700 Subject: [PATCH 0540/1185] EMA class updates --- utils/torch_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 187d51429e..ac38249c4c 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -152,7 +152,7 @@ def update(self, model): msd, esd = model.module.state_dict(), self.ema.module.state_dict() else: msd, esd = model.state_dict(), self.ema.state_dict() - # self.ema.load_state_dict({k: esd[k] * d + (1 - d) * v.detach() for k, v in model.items() if v.dtype.is_floating_point}) + for k, v in esd.items(): if v.dtype.is_floating_point: v *= d @@ -162,4 +162,4 @@ def update_attr(self, model): # Assign attributes (which may change during training) for k in model.__dict__.keys(): if not k.startswith('_'): - setattr(model, k, getattr(model, k)) + setattr(self.ema, k, getattr(model, k)) From 448c4a6e1fce54354d3134c53da10387ac54d20d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 16 Mar 2020 20:46:25 -0700 Subject: [PATCH 0541/1185] Remove deprecated --arc architecture options, implement --arc default for all cases --- models.py | 6 +++--- train.py | 6 ++---- utils/utils.py | 6 +++--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/models.py b/models.py index e9675f89e6..767847b4c9 100755 --- a/models.py +++ b/models.py @@ -7,7 +7,7 @@ ONNX_EXPORT = False -def create_modules(module_defs, img_size, arc): +def create_modules(module_defs, img_size): # Constructs module list of layer blocks from module configuration in module_defs hyperparams = module_defs.pop(0) @@ -250,11 +250,11 @@ def forward(self, p, img_size, out): class Darknet(nn.Module): # YOLOv3 object detection model - def __init__(self, cfg, img_size=(416, 416), arc='default'): + def __init__(self, cfg, img_size=(416, 416)): super(Darknet, self).__init__() self.module_defs = parse_model_cfg(cfg) - self.module_list, self.routs = create_modules(self.module_defs, img_size, arc) + self.module_list, self.routs = create_modules(self.module_defs, img_size) self.yolo_layers = get_yolo_layers(self) # Darknet Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 diff --git a/train.py b/train.py index 83f5155271..cf016b56f3 100644 --- a/train.py +++ b/train.py @@ -32,7 +32,7 @@ 'lrf': -4., # final LambdaLR learning rate = lr0 * (10 ** lrf) 'momentum': 0.937, # SGD momentum 'weight_decay': 0.000484, # optimizer weight decay - 'fl_gamma': 1.5, # focal loss gamma + 'fl_gamma': 0.0, # focal loss gamma (efficientDet default is gamma=1.5) 'hsv_h': 0.0138, # image HSV-Hue augmentation (fraction) 'hsv_s': 0.678, # image HSV-Saturation augmentation (fraction) 'hsv_v': 0.36, # image HSV-Value augmentation (fraction) @@ -77,7 +77,7 @@ def train(): os.remove(f) # Initialize model - model = Darknet(cfg, arc=opt.arc).to(device) + model = Darknet(cfg).to(device) # Optimizer pg0, pg1, pg2 = [], [], [] # optimizer parameter groups @@ -192,7 +192,6 @@ def train(): # Model parameters model.nc = nc # attach number of classes to model - model.arc = opt.arc # attach yolo architecture model.hyp = hyp # attach hyperparameters to model model.gr = 0.0 # giou loss ratio (obj_loss = 1.0 or giou) model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) # attach class weights @@ -406,7 +405,6 @@ def train(): parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') parser.add_argument('--weights', type=str, default='weights/yolov3-spp-ultralytics.pt', help='initial weights path') - parser.add_argument('--arc', type=str, default='default', help='yolo architecture') # default, uCE, uBCE parser.add_argument('--name', default='', help='renames results.txt to results_name.txt if supplied') parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1 or cpu)') parser.add_argument('--adam', action='store_true', help='use adam optimizer') diff --git a/utils/utils.py b/utils/utils.py index 7bb8babb40..4bcb8f2fcc 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -377,7 +377,6 @@ def compute_loss(p, targets, model): # predictions, targets, model lcls, lbox, lobj = ft([0]), ft([0]), ft([0]) tcls, tbox, indices, anchor_vec = build_targets(model, targets) h = model.hyp # hyperparameters - arc = model.arc # architecture red = 'mean' # Loss reduction (sum or mean) # Define criteria @@ -388,8 +387,9 @@ def compute_loss(p, targets, model): # predictions, targets, model cp, cn = smooth_BCE(eps=0.0) # focal loss - if 'F' in arc: - BCEcls, BCEobj = FocalLoss(BCEcls, h['fl_gamma']), FocalLoss(BCEobj, h['fl_gamma']) + g = h['fl_gamma'] # focal loss gamma + if g > 0: + BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) # Compute losses np, ng = 0, 0 # number grid points, targets From b3adc896f993fee3d3886b4918f0f144ada7f311 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 16 Mar 2020 21:40:57 -0700 Subject: [PATCH 0542/1185] focal and obj loss speed/stability --- utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 4bcb8f2fcc..37dacaf6a7 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -357,7 +357,7 @@ def forward(self, pred, true): p_t = true * pred_prob + (1 - true) * (1 - pred_prob) alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) modulating_factor = (1.0 - p_t) ** self.gamma - loss = alpha_factor * modulating_factor * loss + loss *= alpha_factor * modulating_factor if self.reduction == 'mean': return loss.mean() @@ -411,7 +411,7 @@ def compute_loss(p, targets, model): # predictions, targets, model pbox = torch.cat((pxy, pwh), 1) # predicted box giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss - tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * giou.detach().type(tobj.dtype) # giou ratio + tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * giou.detach().clamp(0).type(tobj.dtype) # giou ratio if model.nc > 1: # cls loss (only if multiple classes) t = torch.full_like(ps[:, 5:], cn) # targets From 60c8d194cd7476607d1bd912bea1da0c957aa0ff Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Mar 2020 11:52:52 -0700 Subject: [PATCH 0543/1185] FocalLoss() and obj loss speed and stability update --- utils/utils.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 37dacaf6a7..d7b9954990 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -969,10 +969,8 @@ def plot_test_txt(): # from utils.utils import *; plot_test() def plot_targets_txt(): # from utils.utils import *; plot_targets_txt() - # Plot test.txt histograms - x = np.loadtxt('targets.txt', dtype=np.float32) - x = x.T - + # Plot targets.txt histograms + x = np.loadtxt('targets.txt', dtype=np.float32).T s = ['x targets', 'y targets', 'width targets', 'height targets'] fig, ax = plt.subplots(2, 2, figsize=(8, 8)) ax = ax.ravel() From 20454990ce0fd67454b0d59a7daa9f799c9ac2a4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Mar 2020 12:30:07 -0700 Subject: [PATCH 0544/1185] FLOPS report --- utils/torch_utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index ac38249c4c..18664b3a2d 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -88,6 +88,11 @@ def model_info(model, verbose=False): (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) print('Model Summary: %g layers, %g parameters, %g gradients' % (len(list(model.parameters())), n_p, n_g)) + # Report FLOPS + # from thop import profile + # macs, params = profile(model, inputs=(torch.zeros(1, 3, 608, 608),)) + # print('%.3f FLOPS' % (macs / 1E9 * 2)) + def load_classifier(name='resnet101', n=2): # Loads a pretrained model reshaped to n-class output From 83c9cfb7de4c0f1359198da0de74daf9b9ac125b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Mar 2020 12:30:37 -0700 Subject: [PATCH 0545/1185] FocalLoss() and obj loss speed and stability update --- utils/torch_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 18664b3a2d..0b7013b054 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -88,7 +88,7 @@ def model_info(model, verbose=False): (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) print('Model Summary: %g layers, %g parameters, %g gradients' % (len(list(model.parameters())), n_p, n_g)) - # Report FLOPS + # FLOPS report # from thop import profile # macs, params = profile(model, inputs=(torch.zeros(1, 3, 608, 608),)) # print('%.3f FLOPS' % (macs / 1E9 * 2)) From 1b68fe7fde19fd161685a5412ddd971913ccd086 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Mar 2020 16:23:44 -0700 Subject: [PATCH 0546/1185] cleanup --- models.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/models.py b/models.py index 767847b4c9..6b1dddf30f 100755 --- a/models.py +++ b/models.py @@ -63,10 +63,8 @@ def create_modules(module_defs, img_size): elif mdef['type'] == 'route': # nn.Sequential() placeholder for 'route' layer layers = mdef['layers'] - filters = sum([output_filters[i + 1 if i > 0 else i] for i in layers]) - routs.extend([l if l > 0 else l + i for l in layers]) - # if mdef[i+1]['type'] == 'reorg3d': - # modules = nn.Upsample(scale_factor=1/float(mdef[i+1]['stride']), mode='nearest') # reorg3d + filters = sum([output_filters[l + 1 if l > 0 else l] for l in layers]) + routs.extend([i + l if l < 0 else l for l in layers]) elif mdef['type'] == 'shortcut': # nn.Sequential() placeholder for 'shortcut' layer layers = mdef['from'] @@ -75,8 +73,6 @@ def create_modules(module_defs, img_size): modules = weightedFeatureFusion(layers=layers, weight='weights_type' in mdef) elif mdef['type'] == 'reorg3d': # yolov3-spp-pan-scale - # torch.Size([16, 128, 104, 104]) - # torch.Size([16, 64, 208, 208]) <-- # stride 2 interpolate dimensions 2 and 3 to cat with prior layer pass elif mdef['type'] == 'yolo': From fff45c39a83d444a9d5dda5c9f846416a0274bd6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Mar 2020 16:41:42 -0700 Subject: [PATCH 0547/1185] cleanup/speedup --- models.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/models.py b/models.py index 6b1dddf30f..4a815e7d31 100755 --- a/models.py +++ b/models.py @@ -105,7 +105,10 @@ def create_modules(module_defs, img_size): module_list.append(modules) output_filters.append(filters) - return module_list, routs + routs_binary = [False] * (i + 1) + for i in routs: + routs_binary[i] = True + return module_list, routs_binary class weightedFeatureFusion(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 @@ -292,7 +295,7 @@ def forward(self, x, verbose=False): # print(''), [print(out[i].shape) for i in layers], print(x.shape) elif mtype == 'yolo': yolo_out.append(module(x, img_size, out)) - out.append(x if i in self.routs else []) + out.append(x if self.routs[i] else []) if verbose: print('%g/%g %s -' % (i, len(self.module_list), mtype), list(x.shape), str) str = '' @@ -342,7 +345,7 @@ def create_grids(self, img_size=416, ng=(13, 13), device='cpu', type=torch.float # build wh gains self.anchor_vec = self.anchors.to(device) / self.stride - self.anchor_wh = self.anchor_vec.view(1, self.na, 1, 1, 2).to(device).type(type) + self.anchor_wh = self.anchor_vec.view(1, self.na, 1, 1, 2).type(type) self.ng = torch.Tensor(ng).to(device) self.nx = nx self.ny = ny From 89b63777231b51d5ca60db6b4361bcf159218cb4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Mar 2020 18:11:08 -0700 Subject: [PATCH 0548/1185] Fuse by default when test.py called directly (faster) --- models.py | 2 +- test.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index 4a815e7d31..ee9b98c3ad 100755 --- a/models.py +++ b/models.py @@ -311,7 +311,7 @@ def forward(self, x, verbose=False): def fuse(self): # Fuse Conv2d + BatchNorm2d layers throughout model - print('Fusing Conv2d() and BatchNorm2d() layers...') + print('Fusing layers...') fused_list = nn.ModuleList() for a in list(self.children())[0]: if isinstance(a, nn.Sequential): diff --git a/test.py b/test.py index d9439f6b29..991448c3f9 100644 --- a/test.py +++ b/test.py @@ -29,7 +29,7 @@ def test(cfg, os.remove(f) # Initialize model - model = Darknet(cfg, img_size).to(device) + model = Darknet(cfg, img_size) # Load weights attempt_download(weights) @@ -38,6 +38,10 @@ def test(cfg, else: # darknet format load_darknet_weights(model, weights) + # Fuse + model.fuse() + model.to(device) + if device.type != 'cpu' and torch.cuda.device_count() > 1: model = nn.DataParallel(model) else: # called by train.py From 3265d50f69bc0e48aff87b27acefedd0b464c9ae Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Mar 2020 18:15:09 -0700 Subject: [PATCH 0549/1185] speed update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 20042ff870..10318d0bd3 100755 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memo Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.649 Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.735 -Speed: 6.6/1.5/8.1 ms inference/NMS/total per 608x608 image at batch-size 32 +Speed: 6.5/1.5/8.1 ms inference/NMS/total per 608x608 image at batch-size 32 ``` # Reproduce Our Results From aa0c64b5ac170212b87f1a77795378b3528233d0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 25 Mar 2020 23:24:57 -0700 Subject: [PATCH 0550/1185] merge_batch NMS method --- utils/utils.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index d7b9954990..134cf6ef93 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -558,9 +558,15 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T boxes += c.view(-1, 1) * max_wh if method == 'vision_batch': i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) + elif method == 'merge_batch': # Merge NMS + i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) + iou = box_iou(boxes, boxes[i]).tril_() # upper triangular iou matrix + weights = (iou > conf_thres) * scores.view(-1, 1) + weights /= weights.sum(0) + pred[i, :4] = torch.matmul(weights.T, pred[:, :4]) # merged_boxes(n,4) = weights(n,n) * boxes(n,4) elif method == 'fast_batch': # FastNMS from https://github.com/dbolya/yolact iou = box_iou(boxes, boxes).triu_(diagonal=1) # upper triangular iou matrix - i = iou.max(dim=0)[0] < iou_thres + i = iou.max(0)[0] < iou_thres output[image_i] = pred[i] continue @@ -577,10 +583,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T elif n > 500: dc = dc[:500] # limit to first 500 boxes: https://github.com/ultralytics/yolov3/issues/117 - if method == 'vision': - det_max.append(dc[torchvision.ops.boxes.nms(dc[:, :4], dc[:, 4], iou_thres)]) - - elif method == 'or': # default + if method == 'or': # default # METHOD1 # ind = list(range(len(dc))) # while len(ind): @@ -629,7 +632,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T if len(det_max): det_max = torch.cat(det_max) # concatenate - output[image_i] = det_max[(-det_max[:, 4]).argsort()] # sort + output[image_i] = det_max[det_max[:, 4].argsort(descending=True)] # sort return output From 23b34f4db8598d3916cdaa4c659baf9acfe01c3c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 25 Mar 2020 23:29:33 -0700 Subject: [PATCH 0551/1185] merge_batch NMS method --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 134cf6ef93..b7f11f5608 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -561,7 +561,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T elif method == 'merge_batch': # Merge NMS i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) iou = box_iou(boxes, boxes[i]).tril_() # upper triangular iou matrix - weights = (iou > conf_thres) * scores.view(-1, 1) + weights = (iou > iou_thres) * scores.view(-1, 1) weights /= weights.sum(0) pred[i, :4] = torch.matmul(weights.T, pred[:, :4]) # merged_boxes(n,4) = weights(n,n) * boxes(n,4) elif method == 'fast_batch': # FastNMS from https://github.com/dbolya/yolact From c71ab7d506ca4fbe61f58da012e0b5b896af3041 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 11:25:44 -0700 Subject: [PATCH 0552/1185] augmented testing --- test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test.py b/test.py index 991448c3f9..939dd059b3 100644 --- a/test.py +++ b/test.py @@ -87,8 +87,7 @@ def test(cfg, # Disable gradients with torch.no_grad(): - aug = False # augment https://github.com/ultralytics/yolov3/issues/931 - if aug: + if opt.augment: # augmented testing https://github.com/ultralytics/yolov3/issues/931 imgs = torch.cat((imgs, imgs.flip(3), # flip-lr torch_utils.scale_img(imgs, 0.7), # scale @@ -99,7 +98,7 @@ def test(cfg, inf_out, train_out = model(imgs) # inference and training outputs t0 += torch_utils.time_synchronized() - t - if aug: + if opt.augment: x = torch.split(inf_out, nb, dim=0) x[1][..., 0] = width - x[1][..., 0] # flip lr x[2][..., :4] /= 0.7 # scale @@ -247,6 +246,7 @@ def test(cfg, parser.add_argument('--task', default='test', help="'test', 'study', 'benchmark'") parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') + parser.add_argument('--augment', action='store_true', help='augmented testing') opt = parser.parse_args() opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) print(opt) From f91b1fb13a0f264effdc5a17dd0e3957924f905a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 11:28:46 -0700 Subject: [PATCH 0553/1185] merge_batch NMS method --- test.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test.py b/test.py index 939dd059b3..a1e36b8830 100644 --- a/test.py +++ b/test.py @@ -17,6 +17,7 @@ def test(cfg, iou_thres=0.6, # for nms save_json=False, single_cls=False, + augment=False, model=None, dataloader=None): # Initialize/load model and set device @@ -87,7 +88,7 @@ def test(cfg, # Disable gradients with torch.no_grad(): - if opt.augment: # augmented testing https://github.com/ultralytics/yolov3/issues/931 + if augment: # augmented testing https://github.com/ultralytics/yolov3/issues/931 imgs = torch.cat((imgs, imgs.flip(3), # flip-lr torch_utils.scale_img(imgs, 0.7), # scale @@ -98,7 +99,7 @@ def test(cfg, inf_out, train_out = model(imgs) # inference and training outputs t0 += torch_utils.time_synchronized() - t - if opt.augment: + if augment: x = torch.split(inf_out, nb, dim=0) x[1][..., 0] = width - x[1][..., 0] # flip lr x[2][..., :4] /= 0.7 # scale @@ -261,7 +262,8 @@ def test(cfg, opt.conf_thres, opt.iou_thres, opt.save_json, - opt.single_cls) + opt.single_cls, + opt.augment) elif opt.task == 'benchmark': # mAPs at 320-608 at conf 0.5 and 0.7 y = [] From 94344f5beaeb952b1caea383d9d6b785f911ee79 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 11:34:32 -0700 Subject: [PATCH 0554/1185] test augmentation comments --- test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test.py b/test.py index a1e36b8830..272584aefb 100644 --- a/test.py +++ b/test.py @@ -88,7 +88,8 @@ def test(cfg, # Disable gradients with torch.no_grad(): - if augment: # augmented testing https://github.com/ultralytics/yolov3/issues/931 + # Augment images + if augment: # https://github.com/ultralytics/yolov3/issues/931 imgs = torch.cat((imgs, imgs.flip(3), # flip-lr torch_utils.scale_img(imgs, 0.7), # scale @@ -99,6 +100,7 @@ def test(cfg, inf_out, train_out = model(imgs) # inference and training outputs t0 += torch_utils.time_synchronized() - t + # De-augment results if augment: x = torch.split(inf_out, nb, dim=0) x[1][..., 0] = width - x[1][..., 0] # flip lr From eac07f9da34af04b111bb4076141f405af491acb Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 12:20:01 -0700 Subject: [PATCH 0555/1185] Merge NMS update --- utils/utils.py | 106 +++++++++---------------------------------------- 1 file changed, 19 insertions(+), 87 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index b7f11f5608..ecb669c72d 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -505,8 +505,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T # Box constraints min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height - method = 'vision_batch' - batched = 'batch' in method # run once per image, all classes simultaneously + method = 'vision' nc = prediction[0].shape[1] - 5 # number of classes multi_label &= nc > 1 # multiple labels per box output = [None] * len(prediction) @@ -548,93 +547,26 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T continue # Sort by confidence - if not method.startswith('vision'): - pred = pred[pred[:, 4].argsort(descending=True)] + # if method == 'fast_batch': + # pred = pred[pred[:, 4].argsort(descending=True)] # Batched NMS - if batched: - c = pred[:, 5] * 0 if agnostic else pred[:, 5] # class-agnostic NMS - boxes, scores = pred[:, :4].clone(), pred[:, 4] - boxes += c.view(-1, 1) * max_wh - if method == 'vision_batch': - i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - elif method == 'merge_batch': # Merge NMS - i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - iou = box_iou(boxes, boxes[i]).tril_() # upper triangular iou matrix - weights = (iou > iou_thres) * scores.view(-1, 1) - weights /= weights.sum(0) - pred[i, :4] = torch.matmul(weights.T, pred[:, :4]) # merged_boxes(n,4) = weights(n,n) * boxes(n,4) - elif method == 'fast_batch': # FastNMS from https://github.com/dbolya/yolact - iou = box_iou(boxes, boxes).triu_(diagonal=1) # upper triangular iou matrix - i = iou.max(0)[0] < iou_thres - - output[image_i] = pred[i] - continue - - # All other NMS methods - det_max = [] - cls = pred[:, -1] - for c in cls.unique(): - dc = pred[cls == c] # select class c - n = len(dc) - if n == 1: - det_max.append(dc) # No NMS required if only 1 prediction - continue - elif n > 500: - dc = dc[:500] # limit to first 500 boxes: https://github.com/ultralytics/yolov3/issues/117 - - if method == 'or': # default - # METHOD1 - # ind = list(range(len(dc))) - # while len(ind): - # j = ind[0] - # det_max.append(dc[j:j + 1]) # save highest conf detection - # reject = (bbox_iou(dc[j], dc[ind]) > iou_thres).nonzero() - # [ind.pop(i) for i in reversed(reject)] - - # METHOD2 - while dc.shape[0]: - det_max.append(dc[:1]) # save highest conf detection - if len(dc) == 1: # Stop if we're at the last detection - break - iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes - dc = dc[1:][iou < iou_thres] # remove ious > threshold - - elif method == 'and': # requires overlap, single boxes erased - while len(dc) > 1: - iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes - if iou.max() > 0.5: - det_max.append(dc[:1]) - dc = dc[1:][iou < iou_thres] # remove ious > threshold - - elif method == 'merge': # weighted mixture box - while len(dc): - if len(dc) == 1: - det_max.append(dc) - break - i = bbox_iou(dc[0], dc) > iou_thres # iou with other boxes - weights = dc[i, 4:5] - dc[0, :4] = (weights * dc[i, :4]).sum(0) / weights.sum() - det_max.append(dc[:1]) - dc = dc[i == 0] - - elif method == 'soft': # soft-NMS https://arxiv.org/abs/1704.04503 - sigma = 0.5 # soft-nms sigma parameter - while len(dc): - if len(dc) == 1: - det_max.append(dc) - break - det_max.append(dc[:1]) - iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes - dc = dc[1:] - dc[:, 4] *= torch.exp(-iou ** 2 / sigma) # decay confidences - dc = dc[dc[:, 4] > conf_thres] # https://github.com/ultralytics/yolov3/issues/362 - - if len(det_max): - det_max = torch.cat(det_max) # concatenate - output[image_i] = det_max[det_max[:, 4].argsort(descending=True)] # sort - - return output + c = pred[:, 5] * 0 if agnostic else pred[:, 5] # classes + boxes, scores = pred[:, :4].clone(), pred[:, 4] + boxes += c.view(-1, 1) * max_wh # offset boxes by class + if method == 'vision': + i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) + elif method == 'merge': # Merge NMS (boxes merged using weighted mean) + i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) + iou = box_iou(boxes, boxes[i]).tril_() # lower triangular iou matrix + weights = (iou > iou_thres) * scores.view(-1, 1) + weights /= weights.sum(0) + pred[i, :4] = torch.matmul(weights.T, pred[:, :4]) # merged_boxes(n,4) = weights(n,n) * boxes(n,4) + elif method == 'fast': # FastNMS from https://github.com/dbolya/yolact + iou = box_iou(boxes, boxes).triu_(diagonal=1) # upper triangular iou matrix + i = iou.max(0)[0] < iou_thres + + output[image_i] = pred[i] def get_yolo_layers(model): From 171b4129b5488e82ee8c116f12ddafdeca3ba74f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 12:33:12 -0700 Subject: [PATCH 0556/1185] Merge NMS update --- utils/utils.py | 53 ++++++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index ecb669c72d..b6b15b8419 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -495,78 +495,75 @@ def build_targets(model, targets): def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=True, classes=None, agnostic=False): """ - Removes detections with lower object confidence score than 'conf_thres' - Non-Maximum Suppression to further filter detections. + Performs Non-Maximum Suppression on inference results Returns detections with shape: - (x1, y1, x2, y2, object_conf, conf, class) + nx6 (x1, y1, x2, y2, conf, cls) """ - # NMS methods https://github.com/ultralytics/yolov3/issues/679 'or', 'and', 'merge', 'vision', 'vision_batch' # Box constraints min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height - method = 'vision' + method = 'merge' nc = prediction[0].shape[1] - 5 # number of classes multi_label &= nc > 1 # multiple labels per box output = [None] * len(prediction) - for image_i, pred in enumerate(prediction): + for xi, x in enumerate(prediction): # image index, image inference # Apply conf constraint - pred = pred[pred[:, 4] > conf_thres] + x = x[x[:, 4] > conf_thres] # Apply width-height constraint - pred = pred[((pred[:, 2:4] > min_wh) & (pred[:, 2:4] < max_wh)).all(1)] + x = x[((x[:, 2:4] > min_wh) & (x[:, 2:4] < max_wh)).all(1)] # If none remain process next image - if not pred.shape[0]: + if not x.shape[0]: continue # Compute conf - pred[..., 5:] *= pred[..., 4:5] # conf = obj_conf * cls_conf + x[..., 5:] *= x[..., 4:5] # conf = obj_conf * cls_conf # Box (center x, center y, width, height) to (x1, y1, x2, y2) - box = xywh2xyxy(pred[:, :4]) + box = xywh2xyxy(x[:, :4]) # Detections matrix nx6 (xyxy, conf, cls) if multi_label: - i, j = (pred[:, 5:] > conf_thres).nonzero().t() - pred = torch.cat((box[i], pred[i, j + 5].unsqueeze(1), j.float().unsqueeze(1)), 1) + i, j = (x[:, 5:] > conf_thres).nonzero().t() + x = torch.cat((box[i], x[i, j + 5].unsqueeze(1), j.float().unsqueeze(1)), 1) else: # best class only - conf, j = pred[:, 5:].max(1) - pred = torch.cat((box, conf.unsqueeze(1), j.float().unsqueeze(1)), 1) + conf, j = x[:, 5:].max(1) + x = torch.cat((box, conf.unsqueeze(1), j.float().unsqueeze(1)), 1) # Filter by class if classes: - pred = pred[(j.view(-1, 1) == torch.tensor(classes, device=j.device)).any(1)] + x = x[(j.view(-1, 1) == torch.tensor(classes, device=j.device)).any(1)] # Apply finite constraint - if not torch.isfinite(pred).all(): - pred = pred[torch.isfinite(pred).all(1)] + if not torch.isfinite(x).all(): + x = x[torch.isfinite(x).all(1)] # If none remain process next image - if not pred.shape[0]: + if not x.shape[0]: continue # Sort by confidence # if method == 'fast_batch': - # pred = pred[pred[:, 4].argsort(descending=True)] + # x = x[x[:, 4].argsort(descending=True)] # Batched NMS - c = pred[:, 5] * 0 if agnostic else pred[:, 5] # classes - boxes, scores = pred[:, :4].clone(), pred[:, 4] - boxes += c.view(-1, 1) * max_wh # offset boxes by class - if method == 'vision': - i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - elif method == 'merge': # Merge NMS (boxes merged using weighted mean) + c = x[:, 5] * 0 if agnostic else x[:, 5] # classes + boxes, scores = x[:, :4].clone() + c.view(-1, 1) * max_wh, x[:, 4] # boxes (offset by class), scores + if method == 'merge': # Merge NMS (boxes merged using weighted mean) i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) iou = box_iou(boxes, boxes[i]).tril_() # lower triangular iou matrix weights = (iou > iou_thres) * scores.view(-1, 1) weights /= weights.sum(0) - pred[i, :4] = torch.matmul(weights.T, pred[:, :4]) # merged_boxes(n,4) = weights(n,n) * boxes(n,4) + x[i, :4] = torch.mm(weights.T, x[:, :4]) # merged_boxes(n,4) = weights(n,n) * boxes(n,4) + elif method == 'vision': + i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) elif method == 'fast': # FastNMS from https://github.com/dbolya/yolact iou = box_iou(boxes, boxes).triu_(diagonal=1) # upper triangular iou matrix i = iou.max(0)[0] < iou_thres - output[image_i] = pred[i] + output[xi] = x[i] def get_yolo_layers(model): From a322fc5d4beb0cffc1b3582945bf44ef32a66baa Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 12:48:00 -0700 Subject: [PATCH 0557/1185] Merge NMS update --- utils/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/utils.py b/utils/utils.py index b6b15b8419..820bd9361a 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -564,6 +564,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T i = iou.max(0)[0] < iou_thres output[xi] = x[i] + return output def get_yolo_layers(model): From 4a7d9bdba9cea2d009d40aa3352c7fb5a80ab541 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 14:14:52 -0700 Subject: [PATCH 0558/1185] mAP increases --- README.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 10318d0bd3..95e0555ab3 100755 --- a/README.md +++ b/README.md @@ -147,34 +147,34 @@ $ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 --- | --- | --- | --- -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**36.6** |29.1
51.8
52.3
**56.0** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**40.4** |33.0
55.4
56.9
**60.2** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**41.6** |34.9
57.7
59.5
**61.7** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**42.1** |35.4
58.2
60.7
**61.7** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**38.9** |29.1
51.8
52.3
**56.9** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**42.5** |33.0
55.4
56.9
**61.1** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**43.6** |34.9
57.7
59.5
**62.5** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**44.0** |35.4
58.2
60.7
**62.6** ```bash $ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 608 -Namespace(batch_size=32, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='weights/yolov3-spp-ultralytics.pt') +Namespace(batch_size=16, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='weights/yolov3-spp-ultralytics.pt') Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memory=16130MB) Class Images Targets P R mAP@0.5 F1: 100%|█████| 157/157 [02:46<00:00, 1.06s/it] - all 5e+03 3.51e+04 0.51 0.667 0.611 0.574 - - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.419 - Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.618 - Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.448 - Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.247 - Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.462 - Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.534 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.341 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.557 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.606 - Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.440 - Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.649 - Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.735 - -Speed: 6.5/1.5/8.1 ms inference/NMS/total per 608x608 image at batch-size 32 + all 5e+03 3.51e+04 0.515 0.665 0.61 0.577 + + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.434 + Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.626 + Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.469 + Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.263 + Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.480 + Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.547 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.346 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.617 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.786 + Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.730 + Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.836 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.863 + +Speed: 6.9/2.1/9.0 ms inference/NMS/total per 608x608 image at batch-size 16 ``` # Reproduce Our Results From a4721e90f885cc8a7a93b9ec0e615e0bce72f2a6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 14:22:59 -0700 Subject: [PATCH 0559/1185] defult batch-size to 16 --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 272584aefb..916ab45ee5 100644 --- a/test.py +++ b/test.py @@ -241,7 +241,7 @@ def test(cfg, parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') parser.add_argument('--data', type=str, default='data/coco2014.data', help='*.data path') parser.add_argument('--weights', type=str, default='weights/yolov3-spp-ultralytics.pt', help='weights path') - parser.add_argument('--batch-size', type=int, default=32, help='size of each image batch') + parser.add_argument('--batch-size', type=int, default=16, help='size of each image batch') parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') parser.add_argument('--iou-thres', type=float, default=0.6, help='IOU threshold for NMS') From 20b2671de05b713541b25fe299b8a46bf40b0244 Mon Sep 17 00:00:00 2001 From: Yonghye Kwon Date: Fri, 27 Mar 2020 06:46:17 +0900 Subject: [PATCH 0560/1185] cleanup (#963) * cleanup cleanup * Update train.py Co-authored-by: Glenn Jocher --- train.py | 1 - 1 file changed, 1 deletion(-) diff --git a/train.py b/train.py index cf016b56f3..7512730e95 100644 --- a/train.py +++ b/train.py @@ -409,7 +409,6 @@ def train(): parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1 or cpu)') parser.add_argument('--adam', action='store_true', help='use adam optimizer') parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') - parser.add_argument('--var', type=float, help='debug variable') opt = parser.parse_args() opt.weights = last if opt.resume else opt.weights print(opt) From 470371ba592af7264924d47117bf0fc88e3432e3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 16:20:06 -0700 Subject: [PATCH 0561/1185] Test augment update --- test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test.py b/test.py index 916ab45ee5..e41f998f25 100644 --- a/test.py +++ b/test.py @@ -91,7 +91,7 @@ def test(cfg, # Augment images if augment: # https://github.com/ultralytics/yolov3/issues/931 imgs = torch.cat((imgs, - imgs.flip(3), # flip-lr + torch_utils.scale_img(imgs.flip(3), 0.9), # flip-lr and scale torch_utils.scale_img(imgs, 0.7), # scale ), 0) @@ -103,6 +103,7 @@ def test(cfg, # De-augment results if augment: x = torch.split(inf_out, nb, dim=0) + x[1][..., :4] /= 0.9 # scale x[1][..., 0] = width - x[1][..., 0] # flip lr x[2][..., :4] /= 0.7 # scale inf_out = torch.cat(x, 1) From 9568d4562d6a2b697a04890ab99dbe9102551b86 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 16:22:58 -0700 Subject: [PATCH 0562/1185] mAP updates --- README.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 95e0555ab3..f00bccde55 100755 --- a/README.md +++ b/README.md @@ -153,28 +153,28 @@ YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive. YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**44.0** |35.4
58.2
60.7
**62.6** ```bash -$ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 608 +$ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 608 --augment -Namespace(batch_size=16, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='weights/yolov3-spp-ultralytics.pt') +Namespace(augment=True, batch_size=16, cfg='cfg/yolov3-spp.cfg', conf_thres=0.001, data='coco2014.data', device='', img_size=608, iou_thres=0.7, save_json=True, single_cls=False, task='test', weights='weights/yolov3-spp-ultralytics.pt') Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memory=16130MB) - Class Images Targets P R mAP@0.5 F1: 100%|█████| 157/157 [02:46<00:00, 1.06s/it] - all 5e+03 3.51e+04 0.515 0.665 0.61 0.577 - - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.434 - Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.626 - Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.469 - Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.263 - Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.480 - Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.547 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.346 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.617 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.786 - Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.730 - Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.836 - Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.863 - -Speed: 6.9/2.1/9.0 ms inference/NMS/total per 608x608 image at batch-size 16 + Class Images Targets P R mAP@0.5 F1: 100%|█████████| 313/313 [03:00<00:00, 1.74it/s] + all 5e+03 3.51e+04 0.357 0.727 0.622 0.474 + + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.454 + Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.631 + Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.498 + Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.265 + Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.498 + Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.605 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.357 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.619 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.827 + Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.770 + Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.859 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.896 + +Speed: 20.2/2.4/22.6 ms inference/NMS/total per 608x608 image at batch-size 16 ``` # Reproduce Our Results From faab52913c510c719df4ec80dd08ee482d3c3417 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 16:35:46 -0700 Subject: [PATCH 0563/1185] mAP updates --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index f00bccde55..c527cd00fe 100755 --- a/README.md +++ b/README.md @@ -153,28 +153,28 @@ YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive. YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**44.0** |35.4
58.2
60.7
**62.6** ```bash -$ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 608 --augment +$ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 640 --augment Namespace(augment=True, batch_size=16, cfg='cfg/yolov3-spp.cfg', conf_thres=0.001, data='coco2014.data', device='', img_size=608, iou_thres=0.7, save_json=True, single_cls=False, task='test', weights='weights/yolov3-spp-ultralytics.pt') Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memory=16130MB) Class Images Targets P R mAP@0.5 F1: 100%|█████████| 313/313 [03:00<00:00, 1.74it/s] - all 5e+03 3.51e+04 0.357 0.727 0.622 0.474 - - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.454 - Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.631 - Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.498 - Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.265 - Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.498 - Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.605 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.357 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.619 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.827 - Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.770 - Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.859 - Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.896 - -Speed: 20.2/2.4/22.6 ms inference/NMS/total per 608x608 image at batch-size 16 + all 5e+03 3.51e+04 0.35 0.737 0.624 0.47 + + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.457 + Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.635 + Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.502 + Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.282 + Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.501 + Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.589 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.359 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.621 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.828 + Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.772 + Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.861 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.893 + +Speed: 21.6/2.6/24.1 ms inference/NMS/total per 640x640 image at batch-size 16 ``` # Reproduce Our Results From dad59220f1074464e3214134f26ead118f72aeb3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 18:34:20 -0700 Subject: [PATCH 0564/1185] speed and comments update --- utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 820bd9361a..d3a7ecf5aa 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -457,10 +457,10 @@ def build_targets(model, targets): t, a = targets, [] gwh = t[:, 4:6] * ng if nt: - iou = wh_iou(anchor_vec, gwh) + iou = wh_iou(anchor_vec, gwh) # iou(3,n) = wh_iou(anchor_vec(3,2), gwh(n,2)) if use_all_anchors: - na = len(anchor_vec) # number of anchors + na = anchor_vec.shape[0] # number of anchors a = torch.arange(na).view((-1, 1)).repeat([1, nt]).view(-1) t = targets.repeat([na, 1]) gwh = gwh.repeat([na, 1]) From 01ee0c5e95593e5f2c9143b2872096f43ab28069 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 18:41:04 -0700 Subject: [PATCH 0565/1185] Merge NMS update --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index d3a7ecf5aa..f023893c3e 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -442,7 +442,7 @@ def compute_loss(p, targets, model): # predictions, targets, model def build_targets(model, targets): # targets = [image, class, x, y, w, h] - nt = len(targets) + nt = targets.shape[0] tcls, tbox, indices, av = [], [], [], [] multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) reject, use_all_anchors = True, True From 4a63b24b0913569fafe008f0530a9b9add2f1eb6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Mar 2020 19:50:29 -0700 Subject: [PATCH 0566/1185] Merge NMS update --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index f023893c3e..f8f192b421 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -555,7 +555,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) iou = box_iou(boxes, boxes[i]).tril_() # lower triangular iou matrix weights = (iou > iou_thres) * scores.view(-1, 1) - weights /= weights.sum(0) + weights /= weights.sum(0) + 1E-6 x[i, :4] = torch.mm(weights.T, x[:, :4]) # merged_boxes(n,4) = weights(n,n) * boxes(n,4) elif method == 'vision': i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) From 582de735ad7f27463572774747c390db0593dfcb Mon Sep 17 00:00:00 2001 From: GoogleWiki Date: Sat, 28 Mar 2020 04:09:10 +0800 Subject: [PATCH 0567/1185] utils.clip_coords doesn't work as expected. (#961) * utils.clip_coords doesn't work as expected. Box coords may be negative or exceed borders. * Update utils.py Co-authored-by: Glenn Jocher --- utils/utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index f8f192b421..c2ac95fc1d 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -160,8 +160,10 @@ def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None): def clip_coords(boxes, img_shape): # Clip bounding xyxy bounding boxes to image shape (height, width) - boxes[:, [0, 2]].clamp_(0, img_shape[1]) # clip x - boxes[:, [1, 3]].clamp_(0, img_shape[0]) # clip y + boxes[:, 0].clamp_(0, img_shape[1]) # x1 + boxes[:, 1].clamp_(0, img_shape[0]) # y1 + boxes[:, 2].clamp_(0, img_shape[1]) # x2 + boxes[:, 3].clamp_(0, img_shape[0]) # y2 def ap_per_class(tp, conf, pred_cls, target_cls): From f9d34587da17bf820c7a77c35b42075be07ba315 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Mar 2020 13:11:24 -0700 Subject: [PATCH 0568/1185] Merge NMS update --- utils/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index c2ac95fc1d..9eee669ca1 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -555,10 +555,10 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T boxes, scores = x[:, :4].clone() + c.view(-1, 1) * max_wh, x[:, 4] # boxes (offset by class), scores if method == 'merge': # Merge NMS (boxes merged using weighted mean) i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - iou = box_iou(boxes, boxes[i]).tril_() # lower triangular iou matrix + iou = box_iou(boxes, boxes).tril_() # lower triangular iou matrix weights = (iou > iou_thres) * scores.view(-1, 1) - weights /= weights.sum(0) + 1E-6 - x[i, :4] = torch.mm(weights.T, x[:, :4]) # merged_boxes(n,4) = weights(n,n) * boxes(n,4) + weights /= weights.sum(0) + x[:, :4] = torch.mm(weights.T, x[:, :4]) # merged_boxes(n,4) = weights(n,n) * boxes(n,4) elif method == 'vision': i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) elif method == 'fast': # FastNMS from https://github.com/dbolya/yolact From ce17c26759d7a2fae689fe6b22c98cb59a95dd7f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Mar 2020 13:52:07 -0700 Subject: [PATCH 0569/1185] mAP updates --- README.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index c527cd00fe..024ae59558 100755 --- a/README.md +++ b/README.md @@ -147,34 +147,34 @@ $ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 --- | --- | --- | --- -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**38.9** |29.1
51.8
52.3
**56.9** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**42.5** |33.0
55.4
56.9
**61.1** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**43.6** |34.9
57.7
59.5
**62.5** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**44.0** |35.4
58.2
60.7
**62.6** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**37.0** |29.1
51.8
52.3
**56.0** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**40.7** |33.0
55.4
56.9
**60.4** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**42.0** |34.9
57.7
59.5
**61.9** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**42.4** |35.4
58.2
60.7
**62.0** ```bash $ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 640 --augment -Namespace(augment=True, batch_size=16, cfg='cfg/yolov3-spp.cfg', conf_thres=0.001, data='coco2014.data', device='', img_size=608, iou_thres=0.7, save_json=True, single_cls=False, task='test', weights='weights/yolov3-spp-ultralytics.pt') +Namespace(augment=True, batch_size=16, cfg='cfg/yolov3-spp.cfg', conf_thres=0.001, data='coco2014.data', device='', img_size=640, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='weight Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memory=16130MB) Class Images Targets P R mAP@0.5 F1: 100%|█████████| 313/313 [03:00<00:00, 1.74it/s] - all 5e+03 3.51e+04 0.35 0.737 0.624 0.47 - - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.457 - Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.635 - Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.502 - Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.282 - Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.501 - Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.589 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.359 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.621 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.828 - Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.772 - Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.861 - Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.893 - -Speed: 21.6/2.6/24.1 ms inference/NMS/total per 640x640 image at batch-size 16 + all 5e+03 3.51e+04 0.396 0.731 0.634 0.509 + + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.447 + Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.641 + Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.485 + Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.271 + Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.492 + Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.583 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.357 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.587 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.652 + Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.488 + Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.701 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.787 + +Speed: 21.3/3.0/24.4 ms inference/NMS/total per 640x640 image at batch-size 16 ``` # Reproduce Our Results From dc8e56b9f367e85cf13de6e73b92dffb6bc49e5d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 28 Mar 2020 16:03:46 -0700 Subject: [PATCH 0570/1185] mAP update --- README.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 024ae59558..c0bc8cbc6a 100755 --- a/README.md +++ b/README.md @@ -138,13 +138,6 @@ Success: converted 'weights/yolov3-spp.pt' to 'converted.weights' # mAP -```bash -$ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt -``` - -- mAP@0.5 run at `--iou-thr 0.5`, mAP@0.5...0.95 run at `--iou-thr 0.7` -- Darknet results: https://arxiv.org/abs/1804.02767 - |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 --- | --- | --- | --- YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**37.0** |29.1
51.8
52.3
**56.0** @@ -152,6 +145,9 @@ YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive. YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**42.0** |34.9
57.7
59.5
**61.9** YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**42.4** |35.4
58.2
60.7
**62.0** +- mAP@0.5 run at `--iou-thr 0.5`, mAP@0.5...0.95 run at `--iou-thr 0.7` +- Darknet results: https://arxiv.org/abs/1804.02767 + ```bash $ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 640 --augment From 9c5e76b93d7e5784ef7c34153efb7cb9495b8bbf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 29 Mar 2020 13:14:54 -0700 Subject: [PATCH 0571/1185] EMA implemented by default --- train.py | 12 ++++++------ utils/torch_utils.py | 9 ++++++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/train.py b/train.py index 7512730e95..67fc65fd4f 100644 --- a/train.py +++ b/train.py @@ -197,7 +197,7 @@ def train(): model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) # attach class weights # Model EMA - # ema = torch_utils.ModelEMA(model, decay=0.9998) + ema = torch_utils.ModelEMA(model) # Start training nb = len(dataloader) # number of batches @@ -291,7 +291,7 @@ def train(): if ni % accumulate == 0: optimizer.step() optimizer.zero_grad() - # ema.update(model) + ema.update(model) # Print batch results mloss = (mloss * i + loss_items) / (i + 1) # update mean losses @@ -305,7 +305,7 @@ def train(): scheduler.step() # Process epoch results - # ema.update_attr(model) + ema.update_attr(model) final_epoch = epoch + 1 == epochs if not opt.notest or final_epoch: # Calculate mAP is_coco = any([x in data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) and model.nc == 80 @@ -313,7 +313,7 @@ def train(): data, batch_size=batch_size * 2, img_size=img_size_test, - model=model, + model=ema.ema, conf_thres=0.001 if final_epoch else 0.01, # 0.001 for best mAP, 0.01 for speed iou_thres=0.6, save_json=final_epoch and is_coco, @@ -347,7 +347,7 @@ def train(): chkpt = {'epoch': epoch, 'best_fitness': best_fitness, 'training_results': f.read(), - 'model': model.module.state_dict() if hasattr(model, 'module') else model.state_dict(), + 'model': ema.ema.module.state_dict() if hasattr(model, 'module') else ema.ema.state_dict(), 'optimizer': None if final_epoch else optimizer.state_dict()} # Save last checkpoint @@ -377,7 +377,7 @@ def train(): if opt.bucket: # save to cloud os.system('gsutil cp %s gs://%s/results' % (fresults, opt.bucket)) os.system('gsutil cp %s gs://%s/weights' % (wdir + flast, opt.bucket)) - # os.system('gsutil cp %s gs://%s/weights' % (wdir + fbest, opt.bucket)) + os.system('gsutil cp %s gs://%s/weights' % (wdir + fbest, opt.bucket)) if not opt.evolve: plot_results() # save as results.png diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 0b7013b054..56e5bba6a3 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -1,3 +1,4 @@ +import math import os import time from copy import deepcopy @@ -139,11 +140,12 @@ class ModelEMA: I've tested with the sequence in my own train.py for torch.DataParallel, apex.DDP, and single-GPU. """ - def __init__(self, model, decay=0.9998, device=''): + def __init__(self, model, decay=0.9999, device=''): # make a copy of the model for accumulating moving average of weights self.ema = deepcopy(model) self.ema.eval() - self.decay = decay + self.updates = 0 # number of EMA updates + self.decay = lambda x: decay * (1 - math.exp(-x / 1000)) # decay exponential ramp (to help early epochs) self.device = device # perform ema on different device from model if set if device: self.ema.to(device=device) @@ -151,7 +153,8 @@ def __init__(self, model, decay=0.9998, device=''): p.requires_grad_(False) def update(self, model): - d = self.decay + self.updates += 1 + d = self.decay(self.updates) with torch.no_grad(): if type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel): msd, esd = model.module.state_dict(), self.ema.module.state_dict() From c6b59a0e8add370da9132062a64dbe42c4a04dbb Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 29 Mar 2020 13:29:06 -0700 Subject: [PATCH 0572/1185] LR schedule to 0.05 min --- train.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 67fc65fd4f..a1f2fe1a9e 100644 --- a/train.py +++ b/train.py @@ -20,7 +20,7 @@ best = wdir + 'best.pt' results_file = 'results.txt' -# Hyperparameters (results68: 59.9 mAP@0.5 yolov3-spp-416) https://github.com/ultralytics/yolov3/issues/310 +# Hyperparameters https://github.com/ultralytics/yolov3/issues/310 hyp = {'giou': 3.54, # giou loss gain 'cls': 37.4, # cls loss gain @@ -29,7 +29,7 @@ 'obj_pw': 1.0, # obj BCELoss positive_weight 'iou_t': 0.225, # iou training threshold 'lr0': 0.01, # initial learning rate (SGD=5E-3, Adam=5E-4) - 'lrf': -4., # final LambdaLR learning rate = lr0 * (10 ** lrf) + 'lrf': 0.0005, # final learning rate (with cos scheduler) 'momentum': 0.937, # SGD momentum 'weight_decay': 0.000484, # optimizer weight decay 'fl_gamma': 0.0, # focal loss gamma (efficientDet default is gamma=1.5) @@ -137,7 +137,7 @@ def train(): model, optimizer = amp.initialize(model, optimizer, opt_level='O1', verbosity=0) # Scheduler https://github.com/ultralytics/yolov3/issues/238 - lf = lambda x: (1 + math.cos(x * math.pi / epochs)) / 2 # cosine https://arxiv.org/pdf/1812.01187.pdf + lf = lambda x: (((1 + math.cos(x * math.pi / epochs)) / 2) ** 1.0) * 0.95 + 0.05 # cosine https://arxiv.org/pdf/1812.01187.pdf scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf, last_epoch=start_epoch - 1) # scheduler = lr_scheduler.MultiStepLR(optimizer, [round(epochs * x) for x in [0.8, 0.9]], 0.1, start_epoch - 1) From eb151a881ef382cae133e802982c53bf3d16eaf6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 29 Mar 2020 20:41:32 -0700 Subject: [PATCH 0573/1185] NMS and test batch_size updates --- train.py | 6 +++--- utils/utils.py | 12 +++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/train.py b/train.py index a1f2fe1a9e..33adb52e2b 100644 --- a/train.py +++ b/train.py @@ -180,12 +180,12 @@ def train(): collate_fn=dataset.collate_fn) # Testloader - testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, img_size_test, batch_size * 2, + testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, img_size_test, batch_size, hyp=hyp, rect=True, cache_images=opt.cache_images, single_cls=opt.single_cls), - batch_size=batch_size * 2, + batch_size=batch_size, num_workers=nw, pin_memory=True, collate_fn=dataset.collate_fn) @@ -311,7 +311,7 @@ def train(): is_coco = any([x in data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) and model.nc == 80 results, maps = test.test(cfg, data, - batch_size=batch_size * 2, + batch_size=batch_size, img_size=img_size_test, model=ema.ema, conf_thres=0.001 if final_epoch else 0.01, # 0.001 for best mAP, 0.01 for speed diff --git a/utils/utils.py b/utils/utils.py index 9eee669ca1..80b25d9490 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -543,7 +543,8 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T x = x[torch.isfinite(x).all(1)] # If none remain process next image - if not x.shape[0]: + n = x.shape[0] # number of boxes + if not n: continue # Sort by confidence @@ -555,10 +556,11 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T boxes, scores = x[:, :4].clone() + c.view(-1, 1) * max_wh, x[:, 4] # boxes (offset by class), scores if method == 'merge': # Merge NMS (boxes merged using weighted mean) i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - iou = box_iou(boxes, boxes).tril_() # lower triangular iou matrix - weights = (iou > iou_thres) * scores.view(-1, 1) - weights /= weights.sum(0) - x[:, :4] = torch.mm(weights.T, x[:, :4]) # merged_boxes(n,4) = weights(n,n) * boxes(n,4) + if n < 1000: # update boxes + iou = box_iou(boxes, boxes).tril_() # lower triangular iou matrix + weights = (iou > iou_thres) * scores.view(-1, 1) + weights /= weights.sum(0) + x[:, :4] = torch.mm(weights.T, x[:, :4]) # merged_boxes(n,4) = weights(n,n) * boxes(n,4) elif method == 'vision': i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) elif method == 'fast': # FastNMS from https://github.com/dbolya/yolact From f6fc9634ab9e47eefab82401ad99b07a26127f9b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Mar 2020 11:37:38 -0700 Subject: [PATCH 0574/1185] mAP updates --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index c0bc8cbc6a..539373b575 100755 --- a/README.md +++ b/README.md @@ -140,10 +140,10 @@ Success: converted 'weights/yolov3-spp.pt' to 'converted.weights' |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 --- | --- | --- | --- -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**37.0** |29.1
51.8
52.3
**56.0** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**40.7** |33.0
55.4
56.9
**60.4** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**42.0** |34.9
57.7
59.5
**61.9** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**42.4** |35.4
58.2
60.7
**62.0** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**37.5** |29.1
51.8
52.3
**56.8** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**41.1** |33.0
55.4
56.9
**60.6** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**42.6** |34.9
57.7
59.5
**62.3** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**42.8** |35.4
58.2
60.7
**62.5** - mAP@0.5 run at `--iou-thr 0.5`, mAP@0.5...0.95 run at `--iou-thr 0.7` - Darknet results: https://arxiv.org/abs/1804.02767 @@ -155,20 +155,20 @@ Namespace(augment=True, batch_size=16, cfg='cfg/yolov3-spp.cfg', conf_thres=0.00 Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memory=16130MB) Class Images Targets P R mAP@0.5 F1: 100%|█████████| 313/313 [03:00<00:00, 1.74it/s] - all 5e+03 3.51e+04 0.396 0.731 0.634 0.509 - - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.447 - Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.641 - Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.485 - Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.271 - Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.492 - Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.583 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.357 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.587 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.652 - Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.488 + all 5e+03 3.51e+04 0.372 0.743 0.636 0.49 + + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.450 + Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.643 + Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.486 + Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.265 + Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.498 + Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.577 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.361 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.593 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.654 + Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.486 Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.701 - Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.787 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.804 Speed: 21.3/3.0/24.4 ms inference/NMS/total per 640x640 image at batch-size 16 ``` From de52a008a587d5d0e2f5c962864b320f3bac08da Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Mar 2020 11:46:20 -0700 Subject: [PATCH 0575/1185] default --img-size to 512 --- detect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detect.py b/detect.py index 0608398819..bf8d2e4d9d 100644 --- a/detect.py +++ b/detect.py @@ -162,7 +162,7 @@ def detect(save_img=False): parser.add_argument('--weights', type=str, default='weights/yolov3-spp-ultralytics.pt', help='weights path') parser.add_argument('--source', type=str, default='data/samples', help='source') # input file/folder, 0 for webcam parser.add_argument('--output', type=str, default='output', help='output folder') # output folder - parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') + parser.add_argument('--img-size', type=int, default=512, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.3, help='object confidence threshold') parser.add_argument('--iou-thres', type=float, default=0.6, help='IOU threshold for NMS') parser.add_argument('--fourcc', type=str, default='mp4v', help='output video codec (verify ffmpeg support)') From 105882b3c672729218c2b7cf5b9637aee98e284c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Mar 2020 15:30:53 -0700 Subject: [PATCH 0576/1185] GFLOPs correction --- utils/torch_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 56e5bba6a3..c194e0f0a7 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -92,7 +92,7 @@ def model_info(model, verbose=False): # FLOPS report # from thop import profile # macs, params = profile(model, inputs=(torch.zeros(1, 3, 608, 608),)) - # print('%.3f FLOPS' % (macs / 1E9 * 2)) + # print('%.3f GFLOPs' % (macs / 1E9 * 2)) def load_classifier(name='resnet101', n=2): From 108334db29e45a80f43b12a8dde24712257290cc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Mar 2020 16:04:08 -0700 Subject: [PATCH 0577/1185] FLOPs update --- utils/torch_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index c194e0f0a7..e4490a70fe 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -89,9 +89,9 @@ def model_info(model, verbose=False): (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) print('Model Summary: %g layers, %g parameters, %g gradients' % (len(list(model.parameters())), n_p, n_g)) - # FLOPS report + # FLOPs # from thop import profile - # macs, params = profile(model, inputs=(torch.zeros(1, 3, 608, 608),)) + # macs, params = profile(model, inputs=(torch.zeros(1, 3, 640, 640),)) # print('%.3f GFLOPs' % (macs / 1E9 * 2)) From ac2aa56e0a03f6278a4a84752cca416021667a24 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Mar 2020 17:53:17 -0700 Subject: [PATCH 0578/1185] feature fusion update --- models.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/models.py b/models.py index ee9b98c3ad..049c6584e7 100755 --- a/models.py +++ b/models.py @@ -127,19 +127,19 @@ def forward(self, x, outputs): x = x * w[0] # Fusion - nc = x.shape[1] # input channels + nx = x.shape[1] # input channels for i in range(self.n - 1): a = outputs[self.layers[i]] * w[i + 1] if self.weight else outputs[self.layers[i]] # feature to add - ac = a.shape[1] # feature channels - dc = nc - ac # delta channels + na = a.shape[1] # feature channels # Adjust channels - if dc > 0: # slice input - x[:, :ac] = x[:, :ac] + a # or a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a); x = x + a - elif dc < 0: # slice feature - x = x + a[:, :nc] - else: # same shape + if nx == na: # same shape x = x + a + elif nx > na: # slice input + x[:, :na] = x[:, :na] + a # or a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a); x = x + a + else: # slice feature + x = x + a[:, :nx] + return x From b2d9f1898f062aa3b00cbb8aeeec33a27b646607 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Mar 2020 19:27:42 -0700 Subject: [PATCH 0579/1185] burnin lr ramp 300 iterations --- train.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/train.py b/train.py index 33adb52e2b..f37eb77bdc 100644 --- a/train.py +++ b/train.py @@ -241,23 +241,16 @@ def train(): targets = targets.to(device) # Hyperparameter Burn-in - n_burn = 200 # number of burn-in batches + n_burn = 300 # number of burn-in batches if ni <= n_burn: - # g = (ni / n_burn) ** 2 # gain + g = (ni / n_burn) ** 2 # gain for x in model.named_modules(): # initial stats may be poor, wait to track if x[0].endswith('BatchNorm2d'): x[1].track_running_stats = ni == n_burn - # for x in optimizer.param_groups: - # x['lr'] = x['initial_lr'] * lf(epoch) * g # gain rises from 0 - 1 - # if 'momentum' in x: - # x['momentum'] = hyp['momentum'] * g - - # Plot images with bounding boxes - if ni < 1: - f = 'train_batch%g.png' % i # filename - plot_images(imgs=imgs, targets=targets, paths=paths, fname=f) - if tb_writer: - tb_writer.add_image(f, cv2.imread(f)[:, :, ::-1], dataformats='HWC') + for x in optimizer.param_groups: + x['lr'] = x['initial_lr'] * lf(epoch) * g # gain rises from 0 - 1 + if 'momentum' in x: + x['momentum'] = hyp['momentum'] * g # Multi-Scale training if opt.multi_scale: @@ -299,6 +292,14 @@ def train(): s = ('%10s' * 2 + '%10.3g' * 6) % ('%g/%g' % (epoch, epochs - 1), mem, *mloss, len(targets), img_size) pbar.set_description(s) + # Plot images with bounding boxes + if ni < 1: + f = 'train_batch%g.png' % i # filename + plot_images(imgs=imgs, targets=targets, paths=paths, fname=f) + if tb_writer: + tb_writer.add_image(f, cv2.imread(f)[:, :, ::-1], dataformats='HWC') + # tb_writer.add_graph(model, imgs) + # end batch ------------------------------------------------------------------------------------------------ # Update scheduler From 16862ea846c1ed49310cec4a22b0035fb66b6a3c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Mar 2020 21:21:45 -0700 Subject: [PATCH 0580/1185] update 'reproduce our results' --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 539373b575..7bbcbf866b 100755 --- a/README.md +++ b/README.md @@ -177,9 +177,9 @@ Speed: 21.3/3.0/24.4 ms inference/NMS/total per 640x640 image at batch-size 16 This command trains `yolov3-spp.cfg` from scratch to our mAP above. Training takes about one week on a 2080Ti. ```bash -$ python3 train.py --weights '' --cfg yolov3-spp.cfg --epochs 273 --batch 16 --accum 4 --multi +$ python3 train.py --weights '' --cfg yolov3-spp.cfg --epochs 300 --batch 16 --accum 4 --multi ``` - + # Reproduce Our Environment From 98271eb6ed9f6b2e215df498311f3ed546b5791b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 31 Mar 2020 14:27:10 -0700 Subject: [PATCH 0581/1185] remove deprecated models --- models.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/models.py b/models.py index 049c6584e7..fee5807723 100755 --- a/models.py +++ b/models.py @@ -469,8 +469,6 @@ def attempt_download(weights): 'yolov3-tiny.pt': '10m_3MlpQwRtZetQxtksm9jqHrPTHZ6vo', 'darknet53.conv.74': '1WUVBid-XuoUBmvzBVUCBl_ELrzqwA8dJ', 'yolov3-tiny.conv.15': '1Bw0kCpplxUqyRYAJr9RY9SGnOJbo9nEj', - 'ultralytics49.pt': '158g62Vs14E3aj7oPVPuEnNZMKFNgGyNq', - 'ultralytics68.pt': '1Jm8kqnMdMGUUxGo8zMFZMJ0eaPwLkxSG', 'yolov3-spp-ultralytics.pt': '1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4'} file = Path(weights).name From 992e0d7cb48e99b677a337f942c4376bcd544696 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 31 Mar 2020 14:36:25 -0700 Subject: [PATCH 0582/1185] default test --conf to 0.001 --- train.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/train.py b/train.py index f37eb77bdc..9df158014c 100644 --- a/train.py +++ b/train.py @@ -315,8 +315,6 @@ def train(): batch_size=batch_size, img_size=img_size_test, model=ema.ema, - conf_thres=0.001 if final_epoch else 0.01, # 0.001 for best mAP, 0.01 for speed - iou_thres=0.6, save_json=final_epoch and is_coco, single_cls=opt.single_cls, dataloader=testloader) From f4eecef700717d1b569ad4534b3105a67177ebda Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 31 Mar 2020 15:37:23 -0700 Subject: [PATCH 0583/1185] merge NMS speed/memory improvements --- utils/utils.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 80b25d9490..a828678031 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -304,14 +304,14 @@ def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False): return iou -def box_iou(boxes1, boxes2): +def box_iou(box1, box2): # https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py """ Return intersection-over-union (Jaccard index) of boxes. Both sets of boxes are expected to be in (x1, y1, x2, y2) format. Arguments: - boxes1 (Tensor[N, 4]) - boxes2 (Tensor[M, 4]) + box1 (Tensor[N, 4]) + box2 (Tensor[M, 4]) Returns: iou (Tensor[N, M]): the NxM matrix containing the pairwise IoU values for every element in boxes1 and boxes2 @@ -321,13 +321,11 @@ def box_area(box): # box = 4xn return (box[2] - box[0]) * (box[3] - box[1]) - area1 = box_area(boxes1.t()) - area2 = box_area(boxes2.t()) + area1 = box_area(box1.t()) + area2 = box_area(box2.t()) - lt = torch.max(boxes1[:, None, :2], boxes2[:, :2]) # [N,M,2] - rb = torch.min(boxes1[:, None, 2:], boxes2[:, 2:]) # [N,M,2] - - inter = (rb - lt).clamp(0).prod(2) # [N,M] + # inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2) + inter = (torch.min(box1[:, None, 2:], box2[:, 2:]) - torch.max(box1[:, None, :2], box2[:, :2])).clamp(0).prod(2) return inter / (area1[:, None] + area2 - inter) # iou = inter / (area1 + area2 - inter) @@ -509,6 +507,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T nc = prediction[0].shape[1] - 5 # number of classes multi_label &= nc > 1 # multiple labels per box output = [None] * len(prediction) + for xi, x in enumerate(prediction): # image index, image inference # Apply conf constraint x = x[x[:, 4] > conf_thres] @@ -556,10 +555,9 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T boxes, scores = x[:, :4].clone() + c.view(-1, 1) * max_wh, x[:, 4] # boxes (offset by class), scores if method == 'merge': # Merge NMS (boxes merged using weighted mean) i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - if n < 1000: # update boxes - iou = box_iou(boxes, boxes).tril_() # lower triangular iou matrix - weights = (iou > iou_thres) * scores.view(-1, 1) - weights /= weights.sum(0) + if n < 5000: # update boxes + weights = (box_iou(boxes, boxes).tril_() > iou_thres) * scores.view(-1, 1) # box weights + weights /= weights.sum(0) # normalize x[:, :4] = torch.mm(weights.T, x[:, :4]) # merged_boxes(n,4) = weights(n,n) * boxes(n,4) elif method == 'vision': i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) From 02802e67f24e72374a1a4bcef4e5241b9e3b2add Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 31 Mar 2020 18:18:08 -0700 Subject: [PATCH 0584/1185] merge NMS full matrix --- utils/utils.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index a828678031..109c78bd6b 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -555,10 +555,11 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T boxes, scores = x[:, :4].clone() + c.view(-1, 1) * max_wh, x[:, 4] # boxes (offset by class), scores if method == 'merge': # Merge NMS (boxes merged using weighted mean) i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - if n < 5000: # update boxes - weights = (box_iou(boxes, boxes).tril_() > iou_thres) * scores.view(-1, 1) # box weights - weights /= weights.sum(0) # normalize - x[:, :4] = torch.mm(weights.T, x[:, :4]) # merged_boxes(n,4) = weights(n,n) * boxes(n,4) + # weights = (box_iou(boxes, boxes).tril_() > iou_thres) * scores.view(-1, 1) # box weights + # weights /= weights.sum(0) # normalize + # x[:, :4] = torch.mm(weights.T, x[:, :4]) + weights = (box_iou(boxes[i], boxes) > iou_thres) * scores[None] # box weights + x[i, :4] = torch.mm(weights / weights.sum(1, keepdim=True), x[:, :4]) # boxes(i,4) = w(i,n) * boxes(n,4) elif method == 'vision': i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) elif method == 'fast': # FastNMS from https://github.com/dbolya/yolact From 8d788e10c43066921ad92082520d086f82502dc6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 31 Mar 2020 19:07:41 -0700 Subject: [PATCH 0585/1185] mAP updates --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 7bbcbf866b..2444700dff 100755 --- a/README.md +++ b/README.md @@ -140,10 +140,10 @@ Success: converted 'weights/yolov3-spp.pt' to 'converted.weights' |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 --- | --- | --- | --- -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**37.5** |29.1
51.8
52.3
**56.8** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**41.1** |33.0
55.4
56.9
**60.6** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**42.6** |34.9
57.7
59.5
**62.3** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**42.8** |35.4
58.2
60.7
**62.5** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**37.6** |29.1
51.8
52.3
**56.8** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**41.1** |33.0
55.4
56.9
**60.7** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**42.7** |34.9
57.7
59.5
**62.6** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**42.9** |35.4
58.2
60.7
**62.6** - mAP@0.5 run at `--iou-thr 0.5`, mAP@0.5...0.95 run at `--iou-thr 0.7` - Darknet results: https://arxiv.org/abs/1804.02767 @@ -155,20 +155,20 @@ Namespace(augment=True, batch_size=16, cfg='cfg/yolov3-spp.cfg', conf_thres=0.00 Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memory=16130MB) Class Images Targets P R mAP@0.5 F1: 100%|█████████| 313/313 [03:00<00:00, 1.74it/s] - all 5e+03 3.51e+04 0.372 0.743 0.636 0.49 + all 5e+03 3.51e+04 0.373 0.744 0.637 0.491 - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.450 - Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.643 - Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.486 - Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.265 - Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.498 + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.454 + Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.644 + Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.497 + Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.270 + Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.504 Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.577 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.361 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.593 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.654 - Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.486 - Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.701 - Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.804 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.363 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.599 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.668 + Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.502 + Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.724 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.805 Speed: 21.3/3.0/24.4 ms inference/NMS/total per 640x640 image at batch-size 16 ``` From 300e9a7ad68b021e723fe27fc3d2d6bfddc0545a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 31 Mar 2020 21:31:09 -0700 Subject: [PATCH 0586/1185] merge NMS full matrix --- utils/utils.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 109c78bd6b..d434ccf434 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -555,11 +555,12 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T boxes, scores = x[:, :4].clone() + c.view(-1, 1) * max_wh, x[:, 4] # boxes (offset by class), scores if method == 'merge': # Merge NMS (boxes merged using weighted mean) i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - # weights = (box_iou(boxes, boxes).tril_() > iou_thres) * scores.view(-1, 1) # box weights - # weights /= weights.sum(0) # normalize - # x[:, :4] = torch.mm(weights.T, x[:, :4]) - weights = (box_iou(boxes[i], boxes) > iou_thres) * scores[None] # box weights - x[i, :4] = torch.mm(weights / weights.sum(1, keepdim=True), x[:, :4]) # boxes(i,4) = w(i,n) * boxes(n,4) + if n < 1E4: # update boxes + # weights = (box_iou(boxes, boxes).tril_() > iou_thres) * scores.view(-1, 1) # box weights + # weights /= weights.sum(0) # normalize + # x[:, :4] = torch.mm(weights.T, x[:, :4]) + weights = (box_iou(boxes[i], boxes) > iou_thres) * scores[None] # box weights + x[i, :4] = torch.mm(weights / weights.sum(1, keepdim=True), x[:, :4]) # boxes(i,4) = w(i,n) * boxes(n,4) elif method == 'vision': i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) elif method == 'fast': # FastNMS from https://github.com/dbolya/yolact From 5b322b6038626b56fb16bb58b2fffbb1bef98297 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 1 Apr 2020 09:57:00 -0700 Subject: [PATCH 0587/1185] nvcr update --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d1667cd32b..f21cf49e9d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch -FROM nvcr.io/nvidia/pytorch:20.02-py3 +FROM nvcr.io/nvidia/pytorch:20.03-py3 # Install dependencies (pip or conda) RUN pip install -U gsutil From 765b8f3a3bae4c8ae99c882fdaccfd806c47d25d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 1 Apr 2020 12:12:14 -0700 Subject: [PATCH 0588/1185] documentation update --- README.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 2444700dff..047536f848 100755 --- a/README.md +++ b/README.md @@ -37,25 +37,21 @@ All dependencies are included in the associated docker images. Docker requiremen # Tutorials -* [GCP Quickstart](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) -* [Transfer Learning](https://github.com/ultralytics/yolov3/wiki/Example:-Transfer-Learning) -* [Train Single Image](https://github.com/ultralytics/yolov3/wiki/Example:-Train-Single-Image) +* [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) ** << recommended** * [Train Single Class](https://github.com/ultralytics/yolov3/wiki/Example:-Train-Single-Class) -* [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) - -# Jupyter Notebook - -Our Jupyter [notebook](https://colab.research.google.com/github/ultralytics/yolov3/blob/master/examples.ipynb) provides quick training, inference and testing examples. +* [Google Colab Notebook](https://colab.research.google.com/drive/1G8T-VFxQkjDe4idzN8F-hbIBqkkkQnxw) with quick training, inference and testing examples +* [GCP Quickstart](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) +* [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) # Training -**Start Training:** `python3 train.py` to begin training after downloading COCO data with `data/get_coco_dataset.sh`. Each epoch trains on 117,263 images from the train and validate COCO sets, and tests on 5000 images from the COCO validate set. +**Start Training:** `python3 train.py` to begin training after downloading COCO data with `data/get_coco2017.sh`. Each epoch trains on 117,263 images from the train and validate COCO sets, and tests on 5000 images from the COCO validate set. **Resume Training:** `python3 train.py --resume` to resume training from `weights/last.pt`. -**Plot Training:** `from utils import utils; utils.plot_results()` plots training results from `coco_16img.data`, `coco_64img.data`, 2 example datasets available in the `data/` folder, which train and test on the first 16 and 64 images of the COCO2014-trainval dataset. +**Plot Training:** `from utils import utils; utils.plot_results()` - + ## Image Augmentation From ea80ba65aff8169fb1d5e56d35a431f42b53edd4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 1 Apr 2020 12:16:37 -0700 Subject: [PATCH 0589/1185] documentation updates --- README.md | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 047536f848..6cdcd40cd3 100755 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ All dependencies are included in the associated docker images. Docker requiremen # Tutorials -* [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) ** << recommended** +* [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) < highly recommended!! * [Train Single Class](https://github.com/ultralytics/yolov3/wiki/Example:-Train-Single-Class) * [Google Colab Notebook](https://colab.research.google.com/drive/1G8T-VFxQkjDe4idzN8F-hbIBqkkkQnxw) with quick training, inference and testing examples * [GCP Quickstart](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) @@ -55,17 +55,7 @@ All dependencies are included in the associated docker images. Docker requiremen ## Image Augmentation -`datasets.py` applies random OpenCV-powered (https://opencv.org/) augmentation to the input images in accordance with the following specifications. Augmentation is applied **only** during training, not during inference. Bounding boxes are automatically tracked and updated with the images. 416 x 416 examples pictured below. - -Augmentation | Description ---- | --- -Translation | +/- 10% (vertical and horizontal) -Rotation | +/- 5 degrees -Shear | +/- 2 degrees (vertical and horizontal) -Scale | +/- 10% -Reflection | 50% probability (horizontal-only) -H**S**V Saturation | +/- 50% -HS**V** Intensity | +/- 50% +`datasets.py` applies OpenCV-powered (https://opencv.org/) augmentation to the input image. We use a **mosaic dataloader** (pictured below) to increase image variability during training. @@ -89,8 +79,6 @@ V100 |1
2| 32 x 2
64 x 1 | 122
**178** | 16 min
**11 min** | **$0. # Inference -`detect.py` runs inference on any sources: - ```bash python3 detect.py --source ... ``` @@ -102,15 +90,13 @@ python3 detect.py --source ... - RTSP stream: `--source rtsp://170.93.143.139/rtplive/470011e600ef003a004ee33696235daa` - HTTP stream: `--source http://wmccpinetop.axiscam.net/mjpg/video.mjpg` -To run a specific models: - -**YOLOv3:** `python3 detect.py --cfg cfg/yolov3.cfg --weights yolov3.weights` +**YOLOv3:** `python3 detect.py --cfg cfg/yolov3.cfg --weights yolov3.pt` -**YOLOv3-tiny:** `python3 detect.py --cfg cfg/yolov3-tiny.cfg --weights yolov3-tiny.weights` +**YOLOv3-tiny:** `python3 detect.py --cfg cfg/yolov3-tiny.cfg --weights yolov3-tiny.pt` -**YOLOv3-SPP:** `python3 detect.py --cfg cfg/yolov3-spp.cfg --weights yolov3-spp.weights` +**YOLOv3-SPP:** `python3 detect.py --cfg cfg/yolov3-spp.cfg --weights yolov3-spp.pt` From 4ac60018f6e6c1e24b496485f126a660d9c793d8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 1 Apr 2020 14:05:41 -0700 Subject: [PATCH 0590/1185] FLOPS report --- utils/torch_utils.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index e4490a70fe..94ca9ded64 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -87,12 +87,15 @@ def model_info(model, verbose=False): name = name.replace('module_list.', '') print('%5g %40s %9s %12g %20s %10.3g %10.3g' % (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) - print('Model Summary: %g layers, %g parameters, %g gradients' % (len(list(model.parameters())), n_p, n_g)) - # FLOPs - # from thop import profile - # macs, params = profile(model, inputs=(torch.zeros(1, 3, 640, 640),)) - # print('%.3f GFLOPs' % (macs / 1E9 * 2)) + try: # FLOPS + from thop import profile + macs, _ = profile(model, inputs=(torch.zeros(1, 3, 640, 640),)) + fs = ', %.1f GFLOPS' % (macs / 1E9 * 2) + except: + fs = '' + + print('Model Summary: %g layers, %g parameters, %g gradients%s' % (len(list(model.parameters())), n_p, n_g, fs)) def load_classifier(name='resnet101', n=2): From 27c7334e8176d1b0de0aab9e8616c48ba21903f8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Apr 2020 12:22:15 -0700 Subject: [PATCH 0591/1185] new layers.py file --- models.py | 67 +++---------------------------------------------- utils/layers.py | 62 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 64 deletions(-) create mode 100644 utils/layers.py diff --git a/models.py b/models.py index fee5807723..089b6034a3 100755 --- a/models.py +++ b/models.py @@ -1,8 +1,6 @@ -import torch.nn.functional as F - from utils.google_utils import * +from utils.layers import * from utils.parse_config import * -from utils.utils import * ONNX_EXPORT = False @@ -70,7 +68,7 @@ def create_modules(module_defs, img_size): layers = mdef['from'] filters = output_filters[-1] routs.extend([i + l if l < 0 else l for l in layers]) - modules = weightedFeatureFusion(layers=layers, weight='weights_type' in mdef) + modules = WeightedFeatureFusion(layers=layers, weight='weights_type' in mdef) elif mdef['type'] == 'reorg3d': # yolov3-spp-pan-scale pass @@ -111,65 +109,6 @@ def create_modules(module_defs, img_size): return module_list, routs_binary -class weightedFeatureFusion(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers, weight=False): - super(weightedFeatureFusion, self).__init__() - self.layers = layers # layer indices - self.weight = weight # apply weights boolean - self.n = len(layers) + 1 # number of layers - if weight: - self.w = torch.nn.Parameter(torch.zeros(self.n)) # layer weights - - def forward(self, x, outputs): - # Weights - if self.weight: - w = torch.sigmoid(self.w) * (2 / self.n) # sigmoid weights (0-1) - x = x * w[0] - - # Fusion - nx = x.shape[1] # input channels - for i in range(self.n - 1): - a = outputs[self.layers[i]] * w[i + 1] if self.weight else outputs[self.layers[i]] # feature to add - na = a.shape[1] # feature channels - - # Adjust channels - if nx == na: # same shape - x = x + a - elif nx > na: # slice input - x[:, :na] = x[:, :na] + a # or a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a); x = x + a - else: # slice feature - x = x + a[:, :nx] - - return x - - -class SwishImplementation(torch.autograd.Function): - @staticmethod - def forward(ctx, i): - ctx.save_for_backward(i) - return i * torch.sigmoid(i) - - @staticmethod - def backward(ctx, grad_output): - sigmoid_i = torch.sigmoid(ctx.saved_variables[0]) - return grad_output * (sigmoid_i * (1 + ctx.saved_variables[0] * (1 - sigmoid_i))) - - -class MemoryEfficientSwish(nn.Module): - def forward(self, x): - return SwishImplementation.apply(x) - - -class Swish(nn.Module): - def forward(self, x): - return x.mul_(torch.sigmoid(x)) - - -class Mish(nn.Module): # https://github.com/digantamisra98/Mish - def forward(self, x): - return x.mul_(F.softplus(x).tanh()) - - class YOLOLayer(nn.Module): def __init__(self, anchors, nc, img_size, yolo_index, layers): super(YOLOLayer, self).__init__() @@ -277,7 +216,7 @@ def forward(self, x, verbose=False): l = [i - 1] + module.layers # layers s = [list(x.shape)] + [list(out[i].shape) for i in module.layers] # shapes str = ' >> ' + ' + '.join(['layer %g %s' % x for x in zip(l, s)]) - x = module(x, out) # weightedFeatureFusion() + x = module(x, out) # WeightedFeatureFusion() elif mtype == 'route': # concat layers = mdef['layers'] if verbose: diff --git a/utils/layers.py b/utils/layers.py new file mode 100644 index 0000000000..cb72d67b90 --- /dev/null +++ b/utils/layers.py @@ -0,0 +1,62 @@ +import torch.nn.functional as F + +from utils.utils import * + + +class WeightedFeatureFusion(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, layers, weight=False): + super(WeightedFeatureFusion, self).__init__() + self.layers = layers # layer indices + self.weight = weight # apply weights boolean + self.n = len(layers) + 1 # number of layers + if weight: + self.w = torch.nn.Parameter(torch.zeros(self.n), requires_grad=True) # layer weights + + def forward(self, x, outputs): + # Weights + if self.weight: + w = torch.sigmoid(self.w) * (2 / self.n) # sigmoid weights (0-1) + x = x * w[0] + + # Fusion + nx = x.shape[1] # input channels + for i in range(self.n - 1): + a = outputs[self.layers[i]] * w[i + 1] if self.weight else outputs[self.layers[i]] # feature to add + na = a.shape[1] # feature channels + + # Adjust channels + if nx == na: # same shape + x = x + a + elif nx > na: # slice input + x[:, :na] = x[:, :na] + a # or a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a); x = x + a + else: # slice feature + x = x + a[:, :nx] + + return x + + +class SwishImplementation(torch.autograd.Function): + @staticmethod + def forward(ctx, i): + ctx.save_for_backward(i) + return i * torch.sigmoid(i) + + @staticmethod + def backward(ctx, grad_output): + sigmoid_i = torch.sigmoid(ctx.saved_variables[0]) + return grad_output * (sigmoid_i * (1 + ctx.saved_variables[0] * (1 - sigmoid_i))) + + +class MemoryEfficientSwish(nn.Module): + def forward(self, x): + return SwishImplementation.apply(x) + + +class Swish(nn.Module): + def forward(self, x): + return x.mul_(torch.sigmoid(x)) + + +class Mish(nn.Module): # https://github.com/digantamisra98/Mish + def forward(self, x): + return x.mul_(F.softplus(x).tanh()) From 9155ef3f4f61b6e79e2af6b5573afb3f00f0f649 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Apr 2020 14:08:21 -0700 Subject: [PATCH 0592/1185] burnin merged with prebias --- train.py | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/train.py b/train.py index 9df158014c..edb6d749ab 100644 --- a/train.py +++ b/train.py @@ -137,7 +137,8 @@ def train(): model, optimizer = amp.initialize(model, optimizer, opt_level='O1', verbosity=0) # Scheduler https://github.com/ultralytics/yolov3/issues/238 - lf = lambda x: (((1 + math.cos(x * math.pi / epochs)) / 2) ** 1.0) * 0.95 + 0.05 # cosine https://arxiv.org/pdf/1812.01187.pdf + lf = lambda x: (((1 + math.cos( + x * math.pi / epochs)) / 2) ** 1.0) * 0.95 + 0.05 # cosine https://arxiv.org/pdf/1812.01187.pdf scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf, last_epoch=start_epoch - 1) # scheduler = lr_scheduler.MultiStepLR(optimizer, [round(epochs * x) for x in [0.8, 0.9]], 0.1, start_epoch - 1) @@ -193,7 +194,7 @@ def train(): # Model parameters model.nc = nc # attach number of classes to model model.hyp = hyp # attach hyperparameters to model - model.gr = 0.0 # giou loss ratio (obj_loss = 1.0 or giou) + model.gr = 1.0 # giou loss ratio (obj_loss = 1.0 or giou) model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) # attach class weights # Model EMA @@ -201,7 +202,7 @@ def train(): # Start training nb = len(dataloader) # number of batches - prebias = start_epoch == 0 + n_burn = max(3 * nb, 300) # burn-in iterations, max(3 epochs, 300 iterations) maps = np.zeros(nc) # mAP per class # torch.autograd.set_detect_anomaly(True) results = (0, 0, 0, 0, 0, 0, 0) # 'P', 'R', 'mAP', 'F1', 'val GIoU', 'val Objectness', 'val Classification' @@ -211,21 +212,6 @@ def train(): for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ model.train() - # Prebias - if prebias: - ne = 3 # number of prebias epochs - ps = 0.1, 0.9 # prebias settings (lr=0.1, momentum=0.9) - if epoch == ne: - ps = hyp['lr0'], hyp['momentum'] # normal training settings - model.gr = 1.0 # giou loss ratio (obj_loss = giou) - print_model_biases(model) - prebias = False - - # Bias optimizer settings - optimizer.param_groups[2]['lr'] = ps[0] - if optimizer.param_groups[2].get('momentum') is not None: # for SGD but not Adam - optimizer.param_groups[2]['momentum'] = ps[1] - # Update image weights (optional) if dataset.image_weights: w = model.class_weights.cpu().numpy() * (1 - maps) ** 2 # class weights @@ -240,17 +226,17 @@ def train(): imgs = imgs.to(device).float() / 255.0 # uint8 to float32, 0 - 255 to 0.0 - 1.0 targets = targets.to(device) - # Hyperparameter Burn-in - n_burn = 300 # number of burn-in batches + # Burn-in if ni <= n_burn: - g = (ni / n_burn) ** 2 # gain - for x in model.named_modules(): # initial stats may be poor, wait to track - if x[0].endswith('BatchNorm2d'): - x[1].track_running_stats = ni == n_burn - for x in optimizer.param_groups: - x['lr'] = x['initial_lr'] * lf(epoch) * g # gain rises from 0 - 1 + model.gr = np.interp(ni, [0, n_burn], [0.0, 1.0]) # giou loss ratio (obj_loss = 1.0 or giou) + if ni == n_burn: # burnin complete + print_model_biases(model) + + for j, x in enumerate(optimizer.param_groups): + # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 + x['lr'] = np.interp(ni, [0, n_burn], [0.1 if j == 2 else 0.0, x['initial_lr'] * lf(epoch)]) if 'momentum' in x: - x['momentum'] = hyp['momentum'] * g + x['momentum'] = np.interp(ni, [0, n_burn], [0.9, hyp['momentum']]) # Multi-Scale training if opt.multi_scale: @@ -353,7 +339,7 @@ def train(): torch.save(chkpt, last) # Save best checkpoint - if best_fitness == fi: + if (best_fitness == fi) and not final_epoch: torch.save(chkpt, best) # Save backup every 10 epochs (optional) From aa4591d7e92db91a3f03bbd601218034b398f6b5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Apr 2020 14:10:45 -0700 Subject: [PATCH 0593/1185] batchnorm momentum to 0.03 --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 089b6034a3..9d2538e6e2 100755 --- a/models.py +++ b/models.py @@ -32,7 +32,7 @@ def create_modules(module_defs, img_size): groups=mdef['groups'] if 'groups' in mdef else 1, bias=not bn)) if bn: - modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.003, eps=1E-4)) + modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.03, eps=1E-4)) else: routs.append(i) # detection output (goes into yolo layer) From 207c6fcff9a40c55773b382b3f8f51a656082bff Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Apr 2020 18:53:40 -0700 Subject: [PATCH 0594/1185] merge NMS full matrix --- utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index d434ccf434..e5a4c526d7 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -555,12 +555,12 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T boxes, scores = x[:, :4].clone() + c.view(-1, 1) * max_wh, x[:, 4] # boxes (offset by class), scores if method == 'merge': # Merge NMS (boxes merged using weighted mean) i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - if n < 1E4: # update boxes + if n < 1E4: # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) # weights = (box_iou(boxes, boxes).tril_() > iou_thres) * scores.view(-1, 1) # box weights # weights /= weights.sum(0) # normalize # x[:, :4] = torch.mm(weights.T, x[:, :4]) weights = (box_iou(boxes[i], boxes) > iou_thres) * scores[None] # box weights - x[i, :4] = torch.mm(weights / weights.sum(1, keepdim=True), x[:, :4]) # boxes(i,4) = w(i,n) * boxes(n,4) + x[i, :4] = torch.mm(weights / weights.sum(1, keepdim=True), x[:, :4]).float() # merged boxes elif method == 'vision': i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) elif method == 'fast': # FastNMS from https://github.com/dbolya/yolact From 91f563c2a2baa5a120a81e91da19f29e9d37b42f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Apr 2020 19:10:51 -0700 Subject: [PATCH 0595/1185] create_grids() to YOLOLayer method --- models.py | 52 ++++++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/models.py b/models.py index 9d2538e6e2..772430f6ea 100755 --- a/models.py +++ b/models.py @@ -8,6 +8,7 @@ def create_modules(module_defs, img_size): # Constructs module list of layer blocks from module configuration in module_defs + img_size = [img_size] * 2 if isinstance(img_size, int) else img_size # expand if necessary hyperparams = module_defs.pop(0) output_filters = [int(hyperparams['channels'])] module_list = nn.ModuleList() @@ -75,12 +76,13 @@ def create_modules(module_defs, img_size): elif mdef['type'] == 'yolo': yolo_index += 1 - l = mdef['from'] if 'from' in mdef else [] + stride = [32, 16, 8, 4, 2][yolo_index] # P3-P7 stride modules = YOLOLayer(anchors=mdef['anchors'][mdef['mask']], # anchor list nc=mdef['classes'], # number of classes img_size=img_size, # (416, 416) yolo_index=yolo_index, # 0, 1, 2... - layers=l) # output layers + layers=mdef['from'] if 'from' in mdef else [], # output layers + stride=stride) # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) try: @@ -110,23 +112,34 @@ def create_modules(module_defs, img_size): class YOLOLayer(nn.Module): - def __init__(self, anchors, nc, img_size, yolo_index, layers): + def __init__(self, anchors, nc, img_size, yolo_index, layers, stride): super(YOLOLayer, self).__init__() self.anchors = torch.Tensor(anchors) self.index = yolo_index # index of this layer in layers self.layers = layers # model output layer indices + self.stride = stride # layer stride self.nl = len(layers) # number of output layers (3) self.na = len(anchors) # number of anchors (3) self.nc = nc # number of classes (80) self.no = nc + 5 # number of outputs (85) - self.nx = 0 # initialize number of x gridpoints - self.ny = 0 # initialize number of y gridpoints + self.nx, self.ny = 0, 0 # initialize number of x, y gridpoints + self.anchor_vec = self.anchors / self.stride + self.anchor_wh = self.anchor_vec.view(1, self.na, 1, 1, 2) if ONNX_EXPORT: - stride = [32, 16, 8][yolo_index] # stride of this layer - nx = img_size[1] // stride # number x grid points - ny = img_size[0] // stride # number y grid points - create_grids(self, img_size, (nx, ny)) + self.create_grids((img_size[1] // stride, img_size[0] // stride)) # number x, y grid points + + def create_grids(self, ng=(13, 13), device='cpu'): + self.nx, self.ny = ng # x and y grid size + self.ng = torch.Tensor(ng).to(device) + + # build xy offsets + yv, xv = torch.meshgrid([torch.arange(self.ny), torch.arange(self.nx)]) + self.grid_xy = torch.stack((xv, yv), 2).to(device).view((1, 1, self.ny, self.nx, 2)) + + if self.anchor_vec.device != device: + self.anchor_vec = self.anchor_vec.to(device) + self.anchor_wh = self.anchor_wh.to(device) def forward(self, p, img_size, out): ASFF = False # https://arxiv.org/abs/1911.09516 @@ -135,7 +148,7 @@ def forward(self, p, img_size, out): p = out[self.layers[i]] bs, _, ny, nx = p.shape # bs, 255, 13, 13 if (self.nx, self.ny) != (nx, ny): - create_grids(self, img_size, (nx, ny), p.device, p.dtype) + self.create_grids((nx, ny), p.device) # outputs and weights # w = F.softmax(p[:, -n:], 1) # normalized weights @@ -154,7 +167,7 @@ def forward(self, p, img_size, out): else: bs, _, ny, nx = p.shape # bs, 255, 13, 13 if (self.nx, self.ny) != (nx, ny): - create_grids(self, img_size, (nx, ny), p.device, p.dtype) + self.create_grids((nx, ny), p.device) # p.view(bs, 255, 13, 13) -- > (bs, 3, 13, 13, 85) # (bs, anchors, grid, grid, classes + xywh) p = p.view(bs, self.na, self.no, self.ny, self.nx).permute(0, 1, 3, 4, 2).contiguous() # prediction @@ -273,23 +286,6 @@ def get_yolo_layers(model): return [i for i, x in enumerate(model.module_defs) if x['type'] == 'yolo'] # [82, 94, 106] for yolov3 -def create_grids(self, img_size=416, ng=(13, 13), device='cpu', type=torch.float32): - nx, ny = ng # x and y grid size - self.img_size = max(img_size) - self.stride = self.img_size / max(ng) - - # build xy offsets - yv, xv = torch.meshgrid([torch.arange(ny), torch.arange(nx)]) - self.grid_xy = torch.stack((xv, yv), 2).to(device).type(type).view((1, 1, ny, nx, 2)) - - # build wh gains - self.anchor_vec = self.anchors.to(device) / self.stride - self.anchor_wh = self.anchor_vec.view(1, self.na, 1, 1, 2).type(type) - self.ng = torch.Tensor(ng).to(device) - self.nx = nx - self.ny = ny - - def load_darknet_weights(self, weights, cutoff=-1): # Parses and loads the weights stored in 'weights' From 93055a9d58009ce5d780eb27f04d96d49cf9de48 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Apr 2020 20:23:55 -0700 Subject: [PATCH 0596/1185] create_grids() to YOLOLayer method --- models.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/models.py b/models.py index 772430f6ea..59dff6d860 100755 --- a/models.py +++ b/models.py @@ -134,8 +134,9 @@ def create_grids(self, ng=(13, 13), device='cpu'): self.ng = torch.Tensor(ng).to(device) # build xy offsets - yv, xv = torch.meshgrid([torch.arange(self.ny), torch.arange(self.nx)]) - self.grid_xy = torch.stack((xv, yv), 2).to(device).view((1, 1, self.ny, self.nx, 2)) + if not self.training: + yv, xv = torch.meshgrid([torch.arange(self.ny, device=device), torch.arange(self.nx, device=device)]) + self.grid = torch.stack((xv, yv), 2).view((1, 1, self.ny, self.nx, 2)) if self.anchor_vec.device != device: self.anchor_vec = self.anchor_vec.to(device) @@ -179,11 +180,11 @@ def forward(self, p, img_size, out): # Avoid broadcasting for ANE operations m = self.na * self.nx * self.ny ng = 1 / self.ng.repeat((m, 1)) - grid_xy = self.grid_xy.repeat((1, self.na, 1, 1, 1)).view(m, 2) + grid = self.grid.repeat((1, self.na, 1, 1, 1)).view(m, 2) anchor_wh = self.anchor_wh.repeat((1, 1, self.nx, self.ny, 1)).view(m, 2) * ng p = p.view(m, self.no) - xy = torch.sigmoid(p[:, 0:2]) + grid_xy # x, y + xy = torch.sigmoid(p[:, 0:2]) + grid # x, y wh = torch.exp(p[:, 2:4]) * anchor_wh # width, height p_cls = torch.sigmoid(p[:, 4:5]) if self.nc == 1 else \ torch.sigmoid(p[:, 5:self.no]) * torch.sigmoid(p[:, 4:5]) # conf @@ -191,7 +192,7 @@ def forward(self, p, img_size, out): else: # inference io = p.clone() # inference output - io[..., :2] = torch.sigmoid(io[..., :2]) + self.grid_xy # xy + io[..., :2] = torch.sigmoid(io[..., :2]) + self.grid # xy io[..., 2:4] = torch.exp(io[..., 2:4]) * self.anchor_wh # wh yolo method io[..., :4] *= self.stride torch.sigmoid_(io[..., 4:]) From 41a002e798258114b05d0472864d330c266f0260 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 3 Apr 2020 12:38:08 -0700 Subject: [PATCH 0597/1185] grid.float() --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 59dff6d860..3ead81f9b4 100755 --- a/models.py +++ b/models.py @@ -136,7 +136,7 @@ def create_grids(self, ng=(13, 13), device='cpu'): # build xy offsets if not self.training: yv, xv = torch.meshgrid([torch.arange(self.ny, device=device), torch.arange(self.nx, device=device)]) - self.grid = torch.stack((xv, yv), 2).view((1, 1, self.ny, self.nx, 2)) + self.grid = torch.stack((xv, yv), 2).view((1, 1, self.ny, self.nx, 2)).float() if self.anchor_vec.device != device: self.anchor_vec = self.anchor_vec.to(device) From 682c2b27e7018c1ff3aae4607c48a2f742a985fe Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 3 Apr 2020 12:42:09 -0700 Subject: [PATCH 0598/1185] smart bias bug fix --- models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index 3ead81f9b4..5558dee34e 100755 --- a/models.py +++ b/models.py @@ -77,11 +77,12 @@ def create_modules(module_defs, img_size): elif mdef['type'] == 'yolo': yolo_index += 1 stride = [32, 16, 8, 4, 2][yolo_index] # P3-P7 stride + layers = mdef['from'] if 'from' in mdef else [] modules = YOLOLayer(anchors=mdef['anchors'][mdef['mask']], # anchor list nc=mdef['classes'], # number of classes img_size=img_size, # (416, 416) yolo_index=yolo_index, # 0, 1, 2... - layers=mdef['from'] if 'from' in mdef else [], # output layers + layers=layers, # output layers stride=stride) # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) @@ -89,7 +90,7 @@ def create_modules(module_defs, img_size): bo = -4.5 #  obj bias bc = math.log(1 / (modules.nc - 0.99)) # cls bias: class probability is sigmoid(p) = 1/nc - j = l[yolo_index] if 'from' in mdef else -1 + j = layers[yolo_index] if 'from' in mdef else -1 bias_ = module_list[j][0].bias # shape(255,) bias = bias_[:modules.no * modules.na].view(modules.na, -1) # shape(3,85) bias[:, 4] += bo - bias[:, 4].mean() # obj From eb9fb245aae0bbd4ce26abaec62582f24010345f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 3 Apr 2020 14:21:47 -0700 Subject: [PATCH 0599/1185] add support for standalone BatchNorm2d() --- models.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/models.py b/models.py index 5558dee34e..88107179a0 100755 --- a/models.py +++ b/models.py @@ -9,16 +9,14 @@ def create_modules(module_defs, img_size): # Constructs module list of layer blocks from module configuration in module_defs img_size = [img_size] * 2 if isinstance(img_size, int) else img_size # expand if necessary - hyperparams = module_defs.pop(0) - output_filters = [int(hyperparams['channels'])] + _ = module_defs.pop(0) # cfg training hyperparams (unused) + output_filters = [3] # input channels module_list = nn.ModuleList() routs = [] # list of layers which rout to deeper layers yolo_index = -1 for i, mdef in enumerate(module_defs): modules = nn.Sequential() - # if i == 0: - # modules.add_module('BatchNorm2d_0', nn.BatchNorm2d(output_filters[-1], momentum=0.1)) if mdef['type'] == 'convolutional': bn = mdef['batch_normalize'] @@ -43,6 +41,10 @@ def create_modules(module_defs, img_size): elif mdef['activation'] == 'swish': modules.add_module('activation', Swish()) + elif mdef['type'] == 'BatchNorm2d': + filters = output_filters[-1] + modules = nn.BatchNorm2d(filters, momentum=0.03, eps=1E-4) + elif mdef['type'] == 'maxpool': size = mdef['size'] stride = mdef['stride'] From 00c1fdd805a0c6bbf07d311167abbd516ff95d8b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 3 Apr 2020 20:03:44 -0700 Subject: [PATCH 0600/1185] add MixConv2d() layer --- Dockerfile | 2 +- models.py | 22 +++++++++++++++------- utils/layers.py | 29 +++++++++++++++++++++++++++++ utils/parse_config.py | 2 +- 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index f21cf49e9d..da91e035d6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM nvcr.io/nvidia/pytorch:20.03-py3 # Install dependencies (pip or conda) -RUN pip install -U gsutil +RUN pip install -U gsutil thop # RUN pip install -U -r requirements.txt # RUN conda update -n base -c defaults conda # RUN conda install -y -c anaconda future numpy opencv matplotlib tqdm pillow diff --git a/models.py b/models.py index 88107179a0..fdde9dd752 100755 --- a/models.py +++ b/models.py @@ -23,13 +23,21 @@ def create_modules(module_defs, img_size): filters = mdef['filters'] size = mdef['size'] stride = mdef['stride'] if 'stride' in mdef else (mdef['stride_y'], mdef['stride_x']) - modules.add_module('Conv2d', nn.Conv2d(in_channels=output_filters[-1], - out_channels=filters, - kernel_size=size, - stride=stride, - padding=(size - 1) // 2 if mdef['pad'] else 0, - groups=mdef['groups'] if 'groups' in mdef else 1, - bias=not bn)) + if isinstance(size, int): # single-size conv + modules.add_module('Conv2d', nn.Conv2d(in_channels=output_filters[-1], + out_channels=filters, + kernel_size=size, + stride=stride, + padding=(size - 1) // 2 if mdef['pad'] else 0, + groups=mdef['groups'] if 'groups' in mdef else 1, + bias=not bn)) + else: # multiple-size conv + modules.add_module('MixConv2d', MixConv2d(in_ch=output_filters[-1], + out_ch=filters, + k=size, + stride=stride, + bias=not bn)) + if bn: modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.03, eps=1E-4)) else: diff --git a/utils/layers.py b/utils/layers.py index cb72d67b90..1f19279d15 100644 --- a/utils/layers.py +++ b/utils/layers.py @@ -35,6 +35,35 @@ def forward(self, x, outputs): return x +class MixConv2d(nn.Module): # MixConv: Mixed Depthwise Convolutional Kernels https://arxiv.org/abs/1907.09595 + def __init__(self, in_ch, out_ch, k=(3, 5, 7), stride=1, dilation=1, bias=True, method='equal_params'): + super(MixConv2d, self).__init__() + + groups = len(k) + if method == 'equal_ch': # equal channels per group + i = torch.linspace(0, groups - 1E-6, out_ch).floor() # out_ch indices + ch = [(i == g).sum() for g in range(groups)] + else: # 'equal_params': equal parameter count per group + b = [out_ch] + [0] * groups + a = np.eye(groups + 1, groups, k=-1) + a -= np.roll(a, 1, axis=1) + a *= np.array(k) ** 2 + a[0] = 1 + ch = np.linalg.lstsq(a, b, rcond=None)[0].round().astype(int) # solve for equal weight indices, ax = b + + self.m = nn.ModuleList([torch.nn.Conv2d(in_channels=in_ch, + out_channels=ch[g], + kernel_size=k[g], + stride=stride, + padding=(k[g] - 1) // 2, # 'same' pad + dilation=dilation, + bias=bias) for g in range(groups)]) + + def forward(self, x): + return torch.cat([m(x) for m in self.m], 1) + + +# Activation functions below ------------------------------------------------------------------------------------------- class SwishImplementation(torch.autograd.Function): @staticmethod def forward(ctx, i): diff --git a/utils/parse_config.py b/utils/parse_config.py index 36ea42d7be..4208748e82 100644 --- a/utils/parse_config.py +++ b/utils/parse_config.py @@ -27,7 +27,7 @@ def parse_model_cfg(path): if key == 'anchors': # return nparray mdefs[-1][key] = np.array([float(x) for x in val.split(',')]).reshape((-1, 2)) # np anchors - elif key in ['from', 'layers', 'mask']: # return array + elif (key in ['from', 'layers', 'mask']) or (key == 'size' and ',' in val): # return array mdefs[-1][key] = [int(x) for x in val.split(',')] else: val = val.strip() From 41246aa0427eccba5f617daed1224616fab0ffa3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 4 Apr 2020 19:34:39 -0700 Subject: [PATCH 0601/1185] tensorboard updates --- train.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/train.py b/train.py index edb6d749ab..6a8bd17632 100644 --- a/train.py +++ b/train.py @@ -284,7 +284,7 @@ def train(): plot_images(imgs=imgs, targets=targets, paths=paths, fname=f) if tb_writer: tb_writer.add_image(f, cv2.imread(f)[:, :, ::-1], dataformats='HWC') - # tb_writer.add_graph(model, imgs) + # tb_writer.add_graph(model, imgs) # add model to tensorboard # end batch ------------------------------------------------------------------------------------------------ @@ -313,11 +313,11 @@ def train(): # Write Tensorboard results if tb_writer: - x = list(mloss) + list(results) - titles = ['GIoU', 'Objectness', 'Classification', 'Train loss', - 'Precision', 'Recall', 'mAP', 'F1', 'val GIoU', 'val Objectness', 'val Classification'] - for xi, title in zip(x, titles): - tb_writer.add_scalar(title, xi, epoch) + tags = ['train/giou_loss', 'train/obj_loss', 'train/cls_loss', + 'metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/F1', + 'val/giou_loss', 'val/obj_loss', 'val/cls_loss'] + for x, tag in zip(list(mloss[:-1]) + list(results), tags): + tb_writer.add_scalar(tag, x, epoch) # Update best mAP fi = fitness(np.array(results).reshape(1, -1)) # fitness_i = weighted combination of [P, R, mAP, F1] From 6203340888d4ebce5b24e744a2b8594d97238c5f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 5 Apr 2020 11:05:49 -0700 Subject: [PATCH 0602/1185] detect.py multi_label default False --- detect.py | 3 ++- utils/utils.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/detect.py b/detect.py index bf8d2e4d9d..7be56115aa 100644 --- a/detect.py +++ b/detect.py @@ -88,7 +88,8 @@ def detect(save_img=False): t2 = torch_utils.time_synchronized() # Apply NMS - pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, classes=opt.classes, agnostic=opt.agnostic_nms) + pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, + multi_label=False, classes=opt.classes, agnostic=opt.agnostic_nms) # Apply Classifier if classify: diff --git a/utils/utils.py b/utils/utils.py index e5a4c526d7..c5da3a2710 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -828,7 +828,7 @@ def fitness(x): # Plotting functions --------------------------------------------------------------------------------------------------- def plot_one_box(x, img, color=None, label=None, line_thickness=None): # Plots one bounding box on image img - tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line thickness + tl = line_thickness or max(round(0.002 * (img.shape[0] + img.shape[1]) / 2), 1) # line thickness color = color or [random.randint(0, 255) for _ in range(3)] c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) cv2.rectangle(img, c1, c2, color, thickness=tl) From a19b1a3b94d57bfb69df02ef2ce6883f2d294157 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 5 Apr 2020 11:10:05 -0700 Subject: [PATCH 0603/1185] line thickness --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index c5da3a2710..51e10da991 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -828,7 +828,7 @@ def fitness(x): # Plotting functions --------------------------------------------------------------------------------------------------- def plot_one_box(x, img, color=None, label=None, line_thickness=None): # Plots one bounding box on image img - tl = line_thickness or max(round(0.002 * (img.shape[0] + img.shape[1]) / 2), 1) # line thickness + tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line/font thickness color = color or [random.randint(0, 255) for _ in range(3)] c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) cv2.rectangle(img, c1, c2, color, thickness=tl) From e81a152a9206f29c514ed8346b69b96a5a96d74f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 5 Apr 2020 13:35:58 -0700 Subject: [PATCH 0604/1185] tensorboard notice and model verbose option --- models.py | 4 ++-- train.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index fdde9dd752..f67b4b5474 100755 --- a/models.py +++ b/models.py @@ -213,7 +213,7 @@ def forward(self, p, img_size, out): class Darknet(nn.Module): # YOLOv3 object detection model - def __init__(self, cfg, img_size=(416, 416)): + def __init__(self, cfg, img_size=(416, 416), verbose=False): super(Darknet, self).__init__() self.module_defs = parse_model_cfg(cfg) @@ -223,7 +223,7 @@ def __init__(self, cfg, img_size=(416, 416)): # Darknet Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 self.version = np.array([0, 2, 5], dtype=np.int32) # (int32) version info: major, minor, revision self.seen = np.array([0], dtype=np.int64) # (int64) number of images seen during training - self.info() # print model description + self.info(verbose) # print model description def forward(self, x, verbose=False): img_size = x.shape[-2:] diff --git a/train.py b/train.py index 6a8bd17632..802997ac50 100644 --- a/train.py +++ b/train.py @@ -411,6 +411,7 @@ def train(): from torch.utils.tensorboard import SummaryWriter tb_writer = SummaryWriter() + print('Tensorboard started at http://localhost:6006/') except: pass From d04738a27cf299ae5d6a7006eebfaccfbc74b081 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 5 Apr 2020 13:49:13 -0700 Subject: [PATCH 0605/1185] forward updated if-else --- models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/models.py b/models.py index f67b4b5474..de4ad89252 100755 --- a/models.py +++ b/models.py @@ -234,9 +234,7 @@ def forward(self, x, verbose=False): for i, (mdef, module) in enumerate(zip(self.module_defs, self.module_list)): mtype = mdef['type'] - if mtype in ['convolutional', 'upsample', 'maxpool']: - x = module(x) - elif mtype == 'shortcut': # sum + if mtype == 'shortcut': # sum if verbose: l = [i - 1] + module.layers # layers s = [list(x.shape)] + [list(out[i].shape) for i in module.layers] # shapes @@ -259,6 +257,9 @@ def forward(self, x, verbose=False): # print(''), [print(out[i].shape) for i in layers], print(x.shape) elif mtype == 'yolo': yolo_out.append(module(x, img_size, out)) + else: # run module directly, i.e. mtype = 'convolutional', 'upsample', 'maxpool', 'batchnorm2d' etc. + x = module(x) + out.append(x if self.routs[i] else []) if verbose: print('%g/%g %s -' % (i, len(self.module_list), mtype), list(x.shape), str) From 968b2ec004fce0957f4c034b7ac94325261e80a8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 5 Apr 2020 14:05:12 -0700 Subject: [PATCH 0606/1185] .fuse() after .eval() --- detect.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/detect.py b/detect.py index 7be56115aa..f25019706a 100644 --- a/detect.py +++ b/detect.py @@ -34,12 +34,12 @@ def detect(save_img=False): modelc.load_state_dict(torch.load('weights/resnet101.pt', map_location=device)['model']) # load weights modelc.to(device).eval() - # Fuse Conv2d + BatchNorm2d layers - # model.fuse() - # Eval mode model.to(device).eval() + # Fuse Conv2d + BatchNorm2d layers + # model.fuse() + # Export mode if ONNX_EXPORT: model.fuse() From a657345b4594a448c293300c31de365cece026db Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 5 Apr 2020 14:47:41 -0700 Subject: [PATCH 0607/1185] add FeatureConcat() module --- models.py | 20 +++----------------- utils/layers.py | 10 ++++++++++ 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/models.py b/models.py index de4ad89252..f84da50794 100755 --- a/models.py +++ b/models.py @@ -74,6 +74,7 @@ def create_modules(module_defs, img_size): layers = mdef['layers'] filters = sum([output_filters[l + 1 if l > 0 else l] for l in layers]) routs.extend([i + l if l < 0 else l for l in layers]) + modules = FeatureConcat(layers=layers) elif mdef['type'] == 'shortcut': # nn.Sequential() placeholder for 'shortcut' layer layers = mdef['from'] @@ -234,27 +235,12 @@ def forward(self, x, verbose=False): for i, (mdef, module) in enumerate(zip(self.module_defs, self.module_list)): mtype = mdef['type'] - if mtype == 'shortcut': # sum + if mtype in ['shortcut', 'route']: # sum, concat if verbose: l = [i - 1] + module.layers # layers s = [list(x.shape)] + [list(out[i].shape) for i in module.layers] # shapes str = ' >> ' + ' + '.join(['layer %g %s' % x for x in zip(l, s)]) - x = module(x, out) # WeightedFeatureFusion() - elif mtype == 'route': # concat - layers = mdef['layers'] - if verbose: - l = [i - 1] + layers # layers - s = [list(x.shape)] + [list(out[i].shape) for i in layers] # shapes - str = ' >> ' + ' + '.join(['layer %g %s' % x for x in zip(l, s)]) - if len(layers) == 1: - x = out[layers[0]] - else: - try: - x = torch.cat([out[i] for i in layers], 1) - except: # apply stride 2 for darknet reorg layer - out[layers[1]] = F.interpolate(out[layers[1]], scale_factor=[0.5, 0.5]) - x = torch.cat([out[i] for i in layers], 1) - # print(''), [print(out[i].shape) for i in layers], print(x.shape) + x = module(x, out) # WeightedFeatureFusion(), FeatureConcat() elif mtype == 'yolo': yolo_out.append(module(x, img_size, out)) else: # run module directly, i.e. mtype = 'convolutional', 'upsample', 'maxpool', 'batchnorm2d' etc. diff --git a/utils/layers.py b/utils/layers.py index 1f19279d15..6424fba76b 100644 --- a/utils/layers.py +++ b/utils/layers.py @@ -3,6 +3,16 @@ from utils.utils import * +class FeatureConcat(nn.Module): + def __init__(self, layers): + super(FeatureConcat, self).__init__() + self.layers = layers # layer indices + self.multiple = len(layers) > 1 # multiple layers flag + + def forward(self, x, outputs): + return torch.cat([outputs[i] for i in self.layers], 1) if self.multiple else outputs[self.layers[0]] + + class WeightedFeatureFusion(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 def __init__(self, layers, weight=False): super(WeightedFeatureFusion, self).__init__() From bb59ffe68f3c1b7cfbe384a12cea626efb64a9cf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 5 Apr 2020 15:22:32 -0700 Subject: [PATCH 0608/1185] model forward() zip() removal --- models.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/models.py b/models.py index f84da50794..557fe18711 100755 --- a/models.py +++ b/models.py @@ -230,25 +230,25 @@ def forward(self, x, verbose=False): img_size = x.shape[-2:] yolo_out, out = [], [] if verbose: - str = '' print('0', x.shape) + str = '' - for i, (mdef, module) in enumerate(zip(self.module_defs, self.module_list)): - mtype = mdef['type'] - if mtype in ['shortcut', 'route']: # sum, concat + for i, module in enumerate(self.module_list): + name = module.__class__.__name__ + if name in ['WeightedFeatureFusion', 'FeatureConcat']: # sum, concat if verbose: l = [i - 1] + module.layers # layers s = [list(x.shape)] + [list(out[i].shape) for i in module.layers] # shapes str = ' >> ' + ' + '.join(['layer %g %s' % x for x in zip(l, s)]) x = module(x, out) # WeightedFeatureFusion(), FeatureConcat() - elif mtype == 'yolo': + elif name == 'YOLOLayer': yolo_out.append(module(x, img_size, out)) else: # run module directly, i.e. mtype = 'convolutional', 'upsample', 'maxpool', 'batchnorm2d' etc. x = module(x) out.append(x if self.routs[i] else []) if verbose: - print('%g/%g %s -' % (i, len(self.module_list), mtype), list(x.shape), str) + print('%g/%g %s -' % (i, len(self.module_list), name), list(x.shape), str) str = '' if self.training: # train From 4da5c6c1142810950bfea1e324955f4a55855277 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 5 Apr 2020 16:06:27 -0700 Subject: [PATCH 0609/1185] rect padding to 64, mAP increase 42.7 to 42.9 --- utils/datasets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index b462aa3ab1..2d151f22d8 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -313,7 +313,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r elif mini > 1: shapes[i] = [1, 1 / mini] - self.batch_shapes = np.ceil(np.array(shapes) * img_size / 32.).astype(np.int) * 32 + self.batch_shapes = np.ceil(np.array(shapes) * img_size / 64.).astype(np.int) * 64 # Preload labels (required for weighted CE training) self.imgs = [None] * n @@ -614,7 +614,7 @@ def letterbox(img, new_shape=(416, 416), color=(128, 128, 128), new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding if auto: # minimum rectangle - dw, dh = np.mod(dw, 32), np.mod(dh, 32) # wh padding + dw, dh = np.mod(dw, 64), np.mod(dh, 64) # wh padding elif scaleFill: # stretch dw, dh = 0.0, 0.0 new_unpad = new_shape From c6d4e8033591fea67a580de97a0df269ee900fa6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 5 Apr 2020 17:14:26 -0700 Subject: [PATCH 0610/1185] move inference augmentation to model.forward() --- detect.py | 7 ++++++- models.py | 25 ++++++++++++++++++++----- test.py | 19 ++----------------- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/detect.py b/detect.py index f25019706a..25c7160049 100644 --- a/detect.py +++ b/detect.py @@ -84,9 +84,13 @@ def detect(save_img=False): # Inference t1 = torch_utils.time_synchronized() - pred = model(img)[0].float() if half else model(img)[0] + pred = model(img, augment=opt.augment)[0] t2 = torch_utils.time_synchronized() + # to float + if half: + pred = pred.float() + # Apply NMS pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, multi_label=False, classes=opt.classes, agnostic=opt.agnostic_nms) @@ -173,6 +177,7 @@ def detect(save_img=False): parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') parser.add_argument('--classes', nargs='+', type=int, help='filter by class') parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') + parser.add_argument('--augment', action='store_true', help='augmented inference') opt = parser.parse_args() print(opt) diff --git a/models.py b/models.py index 557fe18711..c4a29aeead 100755 --- a/models.py +++ b/models.py @@ -226,13 +226,21 @@ def __init__(self, cfg, img_size=(416, 416), verbose=False): self.seen = np.array([0], dtype=np.int64) # (int64) number of images seen during training self.info(verbose) # print model description - def forward(self, x, verbose=False): - img_size = x.shape[-2:] + def forward(self, x, augment=False, verbose=False): + img_size = x.shape[-2:] # height, width yolo_out, out = [], [] if verbose: print('0', x.shape) str = '' + # Augment images (inference and test only) + if augment: # https://github.com/ultralytics/yolov3/issues/931 + nb = x.shape[0] # batch size + x = torch.cat((x, + torch_utils.scale_img(x.flip(3), 0.9), # flip-lr and scale + torch_utils.scale_img(x, 0.7), # scale + ), 0) + for i, module in enumerate(self.module_list): name = module.__class__.__name__ if name in ['WeightedFeatureFusion', 'FeatureConcat']: # sum, concat @@ -256,9 +264,16 @@ def forward(self, x, verbose=False): elif ONNX_EXPORT: # export x = [torch.cat(x, 0) for x in zip(*yolo_out)] return x[0], torch.cat(x[1:3], 1) # scores, boxes: 3780x80, 3780x4 - else: # test - io, p = zip(*yolo_out) # inference output, training output - return torch.cat(io, 1), p + else: # inference or test + x, p = zip(*yolo_out) # inference output, training output + x = torch.cat(x, 1) # cat yolo outputs + if augment: # de-augment results + x = torch.split(x, nb, dim=0) + x[1][..., :4] /= 0.9 # scale + x[1][..., 0] = img_size[1] - x[1][..., 0] # flip lr + x[2][..., :4] /= 0.7 # scale + x = torch.cat(x, 1) + return x, p def fuse(self): # Fuse Conv2d + BatchNorm2d layers throughout model diff --git a/test.py b/test.py index e41f998f25..9e03c05110 100644 --- a/test.py +++ b/test.py @@ -88,26 +88,11 @@ def test(cfg, # Disable gradients with torch.no_grad(): - # Augment images - if augment: # https://github.com/ultralytics/yolov3/issues/931 - imgs = torch.cat((imgs, - torch_utils.scale_img(imgs.flip(3), 0.9), # flip-lr and scale - torch_utils.scale_img(imgs, 0.7), # scale - ), 0) - # Run model t = torch_utils.time_synchronized() - inf_out, train_out = model(imgs) # inference and training outputs + inf_out, train_out = model(imgs, augment=augment) # inference and training outputs t0 += torch_utils.time_synchronized() - t - # De-augment results - if augment: - x = torch.split(inf_out, nb, dim=0) - x[1][..., :4] /= 0.9 # scale - x[1][..., 0] = width - x[1][..., 0] # flip lr - x[2][..., :4] /= 0.7 # scale - inf_out = torch.cat(x, 1) - # Compute loss if hasattr(model, 'hyp'): # if model has loss hyperparameters loss += compute_loss(train_out, targets, model)[1][:3] # GIoU, obj, cls @@ -250,7 +235,7 @@ def test(cfg, parser.add_argument('--task', default='test', help="'test', 'study', 'benchmark'") parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') - parser.add_argument('--augment', action='store_true', help='augmented testing') + parser.add_argument('--augment', action='store_true', help='augmented inference') opt = parser.parse_args() opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) print(opt) From b70cfa9a297e77f738774ee3ed87e235a5321e84 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 5 Apr 2020 17:18:24 -0700 Subject: [PATCH 0611/1185] mAP updates for rect inference 64 commit --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6cdcd40cd3..c3550840f2 100755 --- a/README.md +++ b/README.md @@ -122,10 +122,10 @@ Success: converted 'weights/yolov3-spp.pt' to 'converted.weights' |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 --- | --- | --- | --- -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**37.6** |29.1
51.8
52.3
**56.8** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**41.1** |33.0
55.4
56.9
**60.7** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**42.7** |34.9
57.7
59.5
**62.6** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**42.9** |35.4
58.2
60.7
**62.6** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**37.7** |29.1
51.8
52.3
**56.8** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**41.2** |33.0
55.4
56.9
**60.6** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**42.6** |34.9
57.7
59.5
**62.4** +YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**43.1** |35.4
58.2
60.7
**62.8** - mAP@0.5 run at `--iou-thr 0.5`, mAP@0.5...0.95 run at `--iou-thr 0.7` - Darknet results: https://arxiv.org/abs/1804.02767 @@ -154,6 +154,7 @@ Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memo Speed: 21.3/3.0/24.4 ms inference/NMS/total per 640x640 image at batch-size 16 ``` + # Reproduce Our Results From 4f6843e2492ea233454624a69a15d5b341700bbd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 8 Apr 2020 12:28:10 -0700 Subject: [PATCH 0632/1185] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72e6758849..3eddb78417 100755 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memo Speed: 17.5/2.5/20.1 ms inference/NMS/total per 640x640 image at batch-size 16 ``` - + # Reproduce Our Results From 8f71b7865b28474872a005cddc1476125565ce3e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 8 Apr 2020 20:43:51 -0700 Subject: [PATCH 0633/1185] run once to remove initial timing effects --- detect.py | 1 + test.py | 1 + 2 files changed, 2 insertions(+) diff --git a/detect.py b/detect.py index 25c7160049..97eccd4853 100644 --- a/detect.py +++ b/detect.py @@ -75,6 +75,7 @@ def detect(save_img=False): # Run inference t0 = time.time() + _ = model(torch.zeros((1, 3, img_size, img_size), device=device)) if device.type != 'cpu' else None # run once for path, img, im0s, vid_cap in dataset: img = torch.from_numpy(img).to(device) img = img.half() if half else img.float() # uint8 to fp16/32 diff --git a/test.py b/test.py index 9e03c05110..164a580d83 100644 --- a/test.py +++ b/test.py @@ -70,6 +70,7 @@ def test(cfg, seen = 0 model.eval() + _ = model(torch.zeros((1, 3, img_size, img_size), device=device)) if device.type != 'cpu' else None # run once coco91class = coco80_to_coco91_class() s = ('%20s' + '%10s' * 6) % ('Class', 'Images', 'Targets', 'P', 'R', 'mAP@0.5', 'F1') p, r, f1, mp, mr, map, mf1, t0, t1 = 0., 0., 0., 0., 0., 0., 0., 0., 0. From c7f5b6cc216208ab5f8d51d6be9de86bf0451e96 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 8 Apr 2020 20:53:17 -0700 Subject: [PATCH 0634/1185] speed update --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3eddb78417..cc15a917a5 100755 --- a/README.md +++ b/README.md @@ -153,9 +153,10 @@ Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memo Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.719 Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.810 -Speed: 17.5/2.5/20.1 ms inference/NMS/total per 640x640 image at batch-size 16 +Speed: 17.5/2.3/19.9 ms inference/NMS/total per 640x640 image at batch-size 16 ``` - + + # Reproduce Our Results From 4120ac3aa685969ea3f729b1b127bbb72a16de7f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 8 Apr 2020 21:01:58 -0700 Subject: [PATCH 0635/1185] training updates --- train.py | 6 +++--- utils/torch_utils.py | 2 +- utils/utils.py | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/train.py b/train.py index c4629f366a..6c204b7f6b 100644 --- a/train.py +++ b/train.py @@ -209,7 +209,7 @@ def train(): # Start training nb = len(dataloader) # number of batches - n_burn = max(3 * nb, 300) # burn-in iterations, max(3 epochs, 300 iterations) + n_burn = max(3 * nb, 500) # burn-in iterations, max(3 epochs, 300 iterations) maps = np.zeros(nc) # mAP per class # torch.autograd.set_detect_anomaly(True) results = (0, 0, 0, 0, 0, 0, 0) # 'P', 'R', 'mAP', 'F1', 'val GIoU', 'val Objectness', 'val Classification' @@ -234,8 +234,8 @@ def train(): targets = targets.to(device) # Burn-in - if ni <= n_burn: - model.gr = np.interp(ni, [0, n_burn], [0.0, 1.0]) # giou loss ratio (obj_loss = 1.0 or giou) + if ni <= n_burn * 2: + model.gr = np.interp(ni, [0, n_burn * 2], [0.0, 1.0]) # giou loss ratio (obj_loss = 1.0 or giou) if ni == n_burn: # burnin complete print_model_biases(model) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 34ebfe6556..5819e68e6a 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -149,7 +149,7 @@ def __init__(self, model, decay=0.9999, device=''): self.ema = deepcopy(model) self.ema.eval() self.updates = 0 # number of EMA updates - self.decay = lambda x: decay * (1 - math.exp(-x / 1000)) # decay exponential ramp (to help early epochs) + self.decay = lambda x: decay * (1 - math.exp(-x / 2000)) # decay exponential ramp (to help early epochs) self.device = device # perform ema on different device from model if set if device: self.ema.to(device=device) diff --git a/utils/utils.py b/utils/utils.py index 51e10da991..4a1a07ab4a 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -688,11 +688,11 @@ def coco_single_class_labels(path='../coco/labels/train2014/', label_class=43): shutil.copyfile(src=img_file, dst='new/images/' + Path(file).name.replace('txt', 'jpg')) # copy images -def kmean_anchors(path='../coco/train2017.txt', n=9, img_size=(608, 608)): +def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 1024)): # from utils.utils import *; _ = kmean_anchors() - # Produces a list of target kmeans suitable for use in *.cfg files + # Creaters kmeans anchors for use in *.cfg files from utils.datasets import LoadImagesAndLabels - thr = 0.20 # IoU threshold + thr = 0.225 # IoU threshold def print_results(k): k = k[np.argsort(k.prod(1))] # sort small to large @@ -709,7 +709,7 @@ def print_results(k): def fitness(k): # mutation fitness iou = wh_iou(wh, torch.Tensor(k)) # iou max_iou = iou.max(1)[0] - return max_iou.mean() # product + return (max_iou * (max_iou > thr).float()).mean() # product # Get label wh wh = [] From d1601ae0f31de5a8b0a273a6a1d04ca172e7acd8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 8 Apr 2020 21:34:34 -0700 Subject: [PATCH 0636/1185] training updates --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 6c204b7f6b..5c470e3e31 100644 --- a/train.py +++ b/train.py @@ -209,7 +209,7 @@ def train(): # Start training nb = len(dataloader) # number of batches - n_burn = max(3 * nb, 500) # burn-in iterations, max(3 epochs, 300 iterations) + n_burn = max(3 * nb, 500) # burn-in iterations, max(3 epochs, 500 iterations) maps = np.zeros(nc) # mAP per class # torch.autograd.set_detect_anomaly(True) results = (0, 0, 0, 0, 0, 0, 0) # 'P', 'R', 'mAP', 'F1', 'val GIoU', 'val Objectness', 'val Classification' From bc74822540d9e77ec71816980022a7f134ea411c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 9 Apr 2020 14:33:24 -0700 Subject: [PATCH 0637/1185] notebook update --- README.md | 2 +- tutorial.ipynb | 495 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 496 insertions(+), 1 deletion(-) create mode 100644 tutorial.ipynb diff --git a/README.md b/README.md index cc15a917a5..249bd7395e 100755 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ All dependencies are included in the associated docker images. Docker requiremen * [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) < highly recommended!! * [Train Single Class](https://github.com/ultralytics/yolov3/wiki/Example:-Train-Single-Class) -* [Google Colab Notebook](https://colab.research.google.com/drive/1G8T-VFxQkjDe4idzN8F-hbIBqkkkQnxw) with quick training, inference and testing examples +* [Google Colab Notebook](https://colab.research.google.com/github/ultralytics/yolov3/blob/master/tutorial.ipynb) with quick training, inference and testing examples * [GCP Quickstart](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) * [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) * [A TensorRT Implementation of YOLOv3-SPP](https://github.com/wang-xinyu/tensorrtx/tree/master/yolov3-spp) diff --git a/tutorial.ipynb b/tutorial.ipynb new file mode 100644 index 0000000000..7da272bc83 --- /dev/null +++ b/tutorial.ipynb @@ -0,0 +1,495 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "HvhYZrIZCEyo" + }, + "source": [ + "\n", + "\n", + "
\n", + " \n", + " View source on github\n", + " \n", + "\n", + " \n", + " Run in Google Colab\n", + "
\n", + "\n", + "This notebook contains software developed by Ultralytics LLC, and **is freely available for redistribution under the GPL-3.0 license**. For more information please visit https://github.com/ultralytics/yolov3 and https://www.ultralytics.com.\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 34 + }, + "colab_type": "code", + "id": "e5ylFIvlCEym", + "outputId": "fbc88edd-7b26-4735-83bf-b404b76f9c90" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PyTorch 1.1.0 _CudaDeviceProperties(name='Tesla K80', major=3, minor=7, total_memory=11441MB, multi_processor_count=13)\n" + ] + } + ], + "source": [ + "import time\n", + "import glob\n", + "import torch\n", + "import os\n", + "\n", + "from IPython.display import Image, clear_output \n", + "print('PyTorch %s %s' % (torch.__version__, torch.cuda.get_device_properties(0) if torch.cuda.is_available() else 'CPU'))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "7mGmQbAO5pQb" + }, + "source": [ + "Clone repository and download COCO 2014 dataset (20GB):" + ] + }, + { + "cell_type": "code", + "execution_count": 0, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 221 + }, + "colab_type": "code", + "id": "tIFv0p1TCEyj", + "outputId": "e9230cff-ede4-491a-a74d-063ce77f21cd" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cloning into 'yolov3'...\n", + "remote: Enumerating objects: 61, done.\u001b[K\n", + "remote: Counting objects: 100% (61/61), done.\u001b[K\n", + "remote: Compressing objects: 100% (44/44), done.\u001b[K\n", + "remote: Total 4781 (delta 35), reused 37 (delta 17), pack-reused 4720\u001b[K\n", + "Receiving objects: 100% (4781/4781), 4.74 MiB | 6.95 MiB/s, done.\n", + "Resolving deltas: 100% (3254/3254), done.\n", + " % Total % Received % Xferd Average Speed Time Time Time Current\n", + " Dload Upload Total Spent Left Speed\n", + "100 388 0 388 0 0 2455 0 --:--:-- --:--:-- --:--:-- 2440\n", + "100 18.8G 0 18.8G 0 0 189M 0 --:--:-- 0:01:42 --:--:-- 174M\n", + "/content/yolov3\n" + ] + } + ], + "source": [ + "!git clone https://github.com/ultralytics/yolov3 # clone\n", + "!bash yolov3/data/get_coco_dataset_gdrive.sh # copy COCO2014 dataset (19GB)\n", + "%cd yolov3" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "N3qM6T0W53gh" + }, + "source": [ + "Run `detect.py` to perform inference on images in `data/samples` folder:" + ] + }, + { + "cell_type": "code", + "execution_count": 0, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 477 + }, + "colab_type": "code", + "id": "zR9ZbuQCH7FX", + "outputId": "49268b66-125d-425e-dbd0-17b108914c51" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Namespace(cfg='cfg/yolov3-spp.cfg', conf_thres=0.5, data='data/coco.data', fourcc='mp4v', images='data/samples', img_size=416, nms_thres=0.5, output='output', weights='weights/yolov3-spp.weights')\n", + "Using CUDA with Apex device0 _CudaDeviceProperties(name='Tesla K80', total_memory=11441MB)\n", + "\n", + "image 1/2 data/samples/bus.jpg: 416x320 3 persons, 1 buss, 1 handbags, Done. (0.119s)\n", + "image 2/2 data/samples/zidane.jpg: 256x416 2 persons, 1 ties, Done. (0.085s)\n", + "Results saved to /content/yolov3/output\n" + ] + }, + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAMEBgUGBgYF\nBgYGBwkIBgcJBwYGCAsICQoKCgoKBggLDAsKDAkKCgr/2wBDAQICAgICAgUDAwUKBwYHCgoKCgoK\nCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgr/wAARCALQBQADASIA\nAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA\nAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3\nODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm\np6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA\nAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx\nBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK\nU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3\nuLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8347F\n5pkSP5t38P3ttaFjZzR2rzOMjfs+/wDNVi10+5kh877Gqv8AwfP96tOz0+2b99sw0e1drfxV87HY\n+wjHm94z4bOZ2WZ4dgV9vzN81Tx6a8jHvu+bd/DV+HT51uHd0Up95Pl21bhtfIkH2ncqfN8q/e21\nNS0dUbU4/ZMf7Oi52OzMu1UVU+an/wBjlW3w7l2t8y/3q3pNPRl2I+1tn/AqZZ280cXk3Nrub+7v\n+6tefKtLl5onZGm48qMqbQ3k/wBJeb5lb5PMf5l/2aZcaW6tshhyzffZn3ba3biHzI5USFfmX7tQ\nyWc3zTXltuWPb+8jT+LbXJWxVWO534XDxkchrmm/KZt+d3yvurBm0maHLvu2su1G/vV3OsWsMe5x\nyWTd5bVh3VikkLJ5Pyqu7b/easaNacX7x6nsYyicrJYws3nom1m/vf3qWC3uYW32zr8v95v/AEGt\nK6s5I9iJuDMu51aq62827502Nt3Jur6zAylKUTlqREj+0wsiI7OzNuRW/wBr+7ViSPy4/wBzud9+\n1vm+Wq0aurIJtxdf4qtLayeX8nyusu5mb+KvqMPSlKJ58qnvco65uHaNpvlTdt2fJ8y0kjSbER3V\ntq7tzJtqbyPtDLDNtx96nTKjR/Ii7t38X3a9D2fKebUkoy5SHyXjnP75l/i/3amSSVm+0v5joqbf\nv/Ky/wB6i3/fRrv+9911j+6rUsMMuxvJufu/fXZXPKXLE4OaUuaxPBv3b9n+r/hjl3LVqH9zJ/qV\n2t823/eqtbwpHGkP+qVn+dY/l/4FVuzZLqRI5plV13b12fdX+GvLxHvF04825p2cm1Ucopdvl+V9\ntaVvDcSSK6fd+ZXrN0+GGS637F+V1aXd/d/hq7b75mX51Db9zMr/AC/7Py14WIqSNadHuaVjNLJC\nsP2pmTfuddvzNU8jO3yQ7X2/e/iaq8IeGNPLRW+bbu2fdq95n2OZXhhV2b5V3V4dap7+h6VOnHqW\nob792yI6o6orfLVCZJpPnudrBf4v97+KpmuIWmDzTKsrfdXft+7VCS5dpmR5o3/vq392uJSjztQO\nlx928hzbIZXSFFLs7fMqf6yopmubzY63jIVb7qrU32OGSP8AhRPveXHSyKluy/J975VXf/FWkqnN\nqLk5fdEntdy/3vl2eZs/76pU3yQyJsYeX8if3lqwsE0iy2zzfuvl/d/7VVr6O6WTf8yfe/d7/u1n\n71TRSMK0R8d1cxwrvRQv3dzfdWoprp75hNc3cjtHtSLzG+61OaGaS3RJnV1+88bVVkkRlKWtthlf\n+GspRhKRjH3Y8rKuoXtvHteN8qy7X/vVga9cXisrpcthkVfm/u1pXk00zAu+R/d/utWDq14+5n34\n2/6rav3a78PFRj8JyVqhj6lM/wC8+8f/AB3dXManN82/fjd/CtdBqW+4bM0/Gzc1Yd48Pls/Vm+X\nb/FXsUYy5NDxsVLmiYF9avt+07F21QVXmuNmzb/utW9cWbyR56hVqnHp7rMJvJ8xK9CnKMeU82T5\nhljlWZE3fN9//ZrodI3x7ntn+Rk2srfM1V9N03bGOdu7/wAdrVhs4I5BGiMk0f8ADJ8tEqhrToz+\nI1NLtUinR9+fLf5F/wDsa7bQZnjwibU2/N+7X5VrjdH/AHKxBE3f367TRZE+x7E2/wB1dv3mqo1P\nfOj2fuWOu0W4k+ziF5sOzfxfw11ui6uNyu6Mrqu1/Mfb8v8As1wWk3KOuy28xVVvnb+7W/puqQxs\nU3/eiVmj+9XZGpzmMoyj8R3Wn6kQN8Myh1f/AEfb93/eatXT9am8ve+1vvbmrgrHWd0iXOcFfl3L\n/F/wGtCHxB5K+d8wSR9qKq/M3/Aa6OYw9+J2q69C3zpZttX5Ub+9/vUybV4IYd+//WbtzL/Ctcqu\ntbYf3fmHc+1/mqvcawk3ybJCu/b9/wC9U/DAfunT/wBtusCv0/2d/wDDWbqGuosbO8jEt91tvyst\nYN9q226ldH2xtt8qNX3f8B3VVvtUm2l3TLsnzLu/i/hqJRjI25vslPxRNDdZm85iv3fLb+GuMvJ3\ndXR/uK23/erW1PVHuomQXLFpJfkZvur/ALNZGqQ/aFb5G+V/3sa1x1I8x0UeaOjOa1SG2ml85Pv/\nAMO5vlWqtvbupYOmPLf5d3yturcbTkjdt6Mxb/lm38NQXWnpJcM8iSO38Un8K1nKn7p2RqQ5tTPW\nFJpD5czIn97726mTWVzIHfez+Z/yz/vVZa1eSTZDCqqqNu+fbSLYwzRuXhxufd9/71cNSnI0lUM2\nSN1CwpMuyT5tv/stJbxurI/nL+8ba0cn92tXybaOSHyYfuxbtrN8v3qq3Eltu+0+T86tt+VK5q1P\n3tCoVOXWRbtWdcoltv2tu2t8u6uj01na3TZuAVt27+61YNu7s0jzbWlb5U/hrQ0+aGObzo3bzl+X\n7/y7q+Ox1GXNKTPewtT4ZI7LT2T/AFM03mt8q7v4a0WuvLUI+6H5v9Wvzbv+BVzVnfTeSH/55q25\nd/3m/wBmp/7UdpI+Nqt8rbWr5DEYeUqp9DRrfDzG5cXySsN9zuVot6qybvu1m3mpRrD5iO0KSRbv\nlf5aqSal8zbNuPm2/J8q1Uk1QSM73KKrrF8nlr8u6tKOHUZe8dvtOhPeahD5yc7v3X975t1Zs0zr\nsfo2/wCZW/h/4FS3F4jKkEyMXX5X3fdaqzLBNJscrsZNqqv8NexhcPGPuozqVOWHKJe+c0hf7Tv3\nfL8tVri3DSPD9pUyr/F91d1aEljH/wAvMylG+4yp91aktdPeRc+Tv+f5fk3V9XluH5dTwcdiIx+0\n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\nvn8zZsVQ331rqpxkfP4rFc0C2s/nRsgdgrfw02OQM3kTOqt81Uo5jAm9HXYrVKt09w29H+Zf/Hq6\n4xPm8VWjI0beR1ZXebFaFu6Kqv53y/x/7VY+nnzGdH/v7fv1q2UcMi42ZVf4auPvfEeTKsadnI7f\n3lVtvzLWtp6vcSNvfd/C+5vvLWdpsMfmb4YeG2/NJW1pdn/HNGuF+7toiebKpzGvZWc0kTfOoST+\nFfvV0+l2u2ON/wB5Ky1l6HYv8joinau35v4a6Tw7ZpbrsuYV2xr83z/dqjGUjf0uzRVTemNybkX+\n7WvZWjyLseHLM27dHTNDs5PLjSG227k3L/tV0ljYoy7Id29VbfuSuj4jn9oYk1ik0Lby2Nq/L/da\npnsYWjWHft+Xc6t/C1a0ejzTbYZodu7+L+GoptPdZGd9yfwfK/zbaXL9o6aMvfMWKzmaQXPzOW+X\ndv8Au7aelj/pBmmm2CTbv/vbavrZpC3k23mfvP4ZPvLUV1Y7YV8t8lU+6y1Mox5eY97Cy90z9Qs7\naRlmRGdftG1Gb+H/AGq5vWtPmWRtk38X3lauwuI4f40k2/wMv96uY1SL7Ll9i/MzfKrbvmpxjCXv\nHvYaPwqR57r1i80LzQv5yM3yM3/oNcT4k099zJvY7vl+X71eoeIIdyt8jL8/7pv7tcZrln50bokb\nfL8yNXJWl/MerHC83vHtWnw20Ku8ybx5v3l+8rVLbxPcM6eTH5SuzRMvysrVWguIFZjZupSNvvMv\n3m/+Jqe3vv8ASPJ+zM+1V3V40Y8sD572nKX7G1eNv9JRX+Xcn8VaMLQyKfJf+DaisvzL/wACrPju\nPJbY8n7pn3LGqfd/4FV6Fu1y+EVdyN/tV59eT/lO6lU5pXEuo4VkKPtY+UqusbfN838VRR2rxyK7\nuwZanuJE+0OkiKX2b/lT5ZGpjWyKrnyVf+P5W+Va4qlSUdz0Kceb4RtqsMzTb4ZG3S7fJb/0Kh7X\na4he58pG/wBarN92kjj3fvnTciozOq/LtqaKGCSM74ZHf76/L/s159SpyzPQox9zmMKSzS8mm8l1\n+V9sUjferOuLeSa4NzsyVXbu+X71dFfQzKpuUmhXbKvy7KzJreGNXTyV+aqo83tTo5onNXivDIzu\nq4/gbZ92sjyUuJNjzSbYfufPXVala/u96bvu/MrL/DWDcaanyv5ap8vyf3mr7DLeaMtTGpy/ZKK2\n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\n91Ur6Wn8B4GKrTj8RXW3dbcTO6kr/wCg1T1DYq+c83nBk+6q/NurUkXylTyYdi7W+bf97/erM1KO\nTzGhkddq/fVfvLXVznjS/eTKU0yRqiOjK23bu30xmRZHh85W3Ju3NTm2Qwsm+NV3/Kzfw/7NUJIJ\ntu9Eb7tYVqnLA66VHl91FqzmEkgR3+Vm27Vras1SNv3j7hs+da5+GN1WJH/v1rWsiLMEdGRf7zfN\n8tfO4yoviieph6b/AO3Td09vLVN9xwv/ACz21pwyP5n+uVdv8TN93/drHt5h5KnzlVt38X92rX2j\nY3zzZSTn/a2/7NeBiKnMe1Rp0oxsaDfvo2R3X73+81PmvppJnhRI1T5W/efN8u2srzh9jHkzMj+b\ntVmX+H/drQW8dbcojq7sirukrzub3To9n7pct5NyiH5Xb7q/JVi2uFmkV7l8+ZFsX+8u2qNuqSXH\n3Nu1/l2/K27b96tGG1/ePO9z8nyq7L92n8RxyjOPvGlpsbtbrBvU7fm+arG2aO5EiOy7m+6v8W6q\n9v5MS+T5Ko+5W3M//stWVtX8z9zI29kb5aJSl8jGMPaTlcfFb+Wzw79219u6RtzK1CrBJGs002W+\n98qfK1TKUlVXmTZ8q7lX+Ko2t7xWZ3s1Rvv/ADP96s5QjHYdpcvKQNcwzWr3Lwsqqm75fvVZ+yws\np/cyB9n3f4qdHJMd6OmPlX5VT5mplwlzbyJNs27tv7xX3NWkY88uU5a0fd1MTUJLPS4d6I2WT59y\nbtrVz2oD7ZI3+jNuX+JvustdLr8b3FwbyHa6q+1/nrmtQjhj3Qr8r7PutXp4enzR0ieFiJc0vdMG\nSNGmfy0+79xtlV5rP9800O1/78f8X+9WtdbJMujx/c+ZlWqSq8LP8/zfdx/Etepy/ZPPqSIPLmk+\nSH+/tl8xKm8sTWod4WdN38K09Y3bHljcy/f/ANqrNrF9on8ma8YBf7vzbf8AgNHs/dLoy5oFTyxt\n/fQqd3ysrfLt/wB2q7WKRxtvRn3N/vbq2pFSZg8Kb1Vtu1v4mqvHY/vS8lsqH7zyRvUS9064/EUd\nPs/vIYedvyK38NXYI/KjdJY1wzUW8yfczj/aX/e+7UazPbt5PzP5bbvm/u1hGUo/CdX2UmWW85t0\nyfMi/f2/LVnT7qG3j2I+FX/lnJ/DWbDJNcyM7pl2b5Pn+X/vmq8175LedPNhfu/NXXRqSOSpH+U2\n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\nG3aT52R2/iZ91WbG4ubxU3oqtCnO3+L/AHqY0aeYfk4/jVk3bqs2qouxLby3Zv7v8VaSj9k5o80f\neiXFluYIymzfuRmVm+XbVG6uEudnyMv97/7KrtxJPas1siKdy/8AAf8AdqqzblPz7W+8i/3v9mue\nVOJ3U6k46kdmm6B3dF3btqN/eqK3kht0875R95UVnqeOzdW++q+Z8ybX+7VW4tXaFvO279/+r27d\n1cUjujIja82qZktpB/eX7u3/AGt1Z1zN5zNsmbcz7nXbuq81unk/vofvJ8se/wC9WfcRurb0fau/\nbtq6fu+8jOt7xUk1B1WTyfM/up822rljefbEV9/+rX+5urMurV2kXzo96t/E33VatDSLd7WPyfJb\n5fl3b91d9OUZHl4j3S6slzcXH+kou35WRo/vbq19PsXk8rO0r/dZfm3VX0ux8xvnRiy/Kir/AAtW\n7b2rtdxfeP8A0zVf4v8Aarsp7nl1JGjpOmuqrMjrI392T/2Wu/8AC+gyTQpC8LItx/qtz/d/2mrn\n/C2hwrIp34+TcsjMv3q7nw3pqN5Oy6jl8tNyK33V/wBmu6MfcMpS5Td8N6Gka/cXK/K7L826uisd\nFSOTzrN87n3IzfK3/Af71L4ftk+WZIWXyU27W+827722uv0vT7NcTW0PzKu6L+L/AHq1j/eMJVDH\ns9DeNkm/eMy/f3Nt+WrUfh547dtu75XZvMjeunsdLSZRvh3rJ8u3f81XLXQvs9u+9Pn3/wASfLU+\nzjIXtDgtQ8L7Zg8N43zbnZpG/iZawbjQ3tVXy0/1f3F3bt1el6l4fmkm+eH5W2q9ZWoeH/L/AHz2\n0brH9xlT5ttPllFEfWOb3Ueb3Wg+XC37nfF837uT7y7v7tULjQ4Zt3yZVf4ZE+9/vV6LeaO8kISZ\nFVlRvvJ/3ytZF94deOMTb13qittWplTgP2nvcqPPrrQ/OVXhkZEVf7tVL7RUmj/cvuZfvrurtbrS\n38mS1/eK33vm+6tZFxZ+XDJDZ7mf+8y/w/3q87EUzuoyOUuofJDQ+S26T/Wt/wAtG/3agns3jkUz\nOySRp8n8Lba2ptNRsXj/ACvv2hZPl3VUvkdt0z/Kd+xdr7lrxsRRly+6e3h6nKUP7NhkjZHm3CRP\n4W+VmWkRfsrRW0MbDzPm3ebtWpNQ+ztH8kOxpG3Oq/doS+RpNko/65K391axpYfm3Oz238pdt7N9\nyI/yqvyr8/zVt2fnLcbIeDGv3mrF0uaCRVSc7h97zN277v8AerQ028dWKTTMys6+Uzfxbq9TC0/d\nscWIqe0Os0doYFXY6s8nzOq/+hV0On/vG8+6n80/wLt+6tcrpkP74PDuR1+4v95a6fRwjRxTXm7e\nzfdX7v8Au17NKNjzakpcx0ml28flpNskwvzRLt3L/wB8122l6SkKh5oPn+8i/wDstYHh238vH3vK\nZvu13ui2M3kpM9tuf722T7yrXrRlywPOqS5ZfEaOg6ND9nQJDt3JuZv7tdRpfh3dDG+zajfKjVDo\n9n51us01q2yNtiLH/FXRww/KiYw0b7tzL83/AAKnL3jg9t7/ALxmnSfs+97N4ceUy7m/irM1DR7a\nMfakRdq/w/errLiKGPG/b+8Tckn8NYOuW6SQt5Kbljl3MsLbfvfxVzVI/wAprGRwXiSx8652fZmc\nKi/e/vVwniC1eRvuYeR2Rt3ytG1eleIrWa1kl/c/Orqztu/hrifFNq80jw72ZpE3bdlclSPMdlOp\nzHmWsWM0qyxuio0fyf7P/fVcT4g0n5WSZ/NRfvt/DXpmt2cNvNs3/OyMzK392uI8TWv2hn86Ztip\nsZf+WbL/AHlauKpTOynPm1PN/EWn201u6JbYdfufwtXAeJrO+WRP9Xn+Nd//AI9Xp+sWryTo8PzB\nfkikavO/FF2/nTXLrsMnyosa/wDj1ckqfKddOt3OB1RplLJ5Lb40b5qzY5YZpNifcZ9r7l+ZmrV1\naOZb6Y7/AJdm5GrDkkTdscbD95l3/drDlidnNzaRJWu/srZQZRf4dlUriY27fvk3LJ/DU7TIynyf\n4vubvvVXuLja3yOpG3azKvzf7taxjze8TKUftERkhk3InX7qqsVR+cWaVJnUbfurH91f/sqVpHjV\nneHbL/e37flqu0kO5vn37f8AYq+XlObmjL3SyJIW2edMr/wt5i1o2rBoXfYoLKuzbWVYr5exPJ+T\n721vm3VcjZNxdNuxk+6v8NRUj1NqPPHc3NPby5ikybW2/wASbttdZocnkxxb/LL7fvf/AGNcVp91\n/pGyR1b5fn3fxVsabqUir5k21Pm/8drnlHlO2Mvsnqfhu8hjjZ5plx935flb/ZrqNFvJltRbfKp2\n/PIv3a818P6sgVH3744/9V5j/erp9L155HRE8tNr/Pu/iqqPuhUkdrHMkOx4YVcqu2Vo0+Zf71fa\nP/BOJ2k+CGqu0YXPiufAAx/y7WtfCy6gkkSI8zNIvzfK3yr/AMBr7h/4JoXBufgVq7sCGHi6cNn1\n+y2tfkHj47+HdT/r5T/Nnw3G8oyyR2/mifCd0sKyH7Gild27d91qxNWk3M8KTbl/vN/FWvq00LKj\n/aWTb8qttrIvFEke9Cv7v5VVm+9X7xGVj2qkTn76T7PeJ5PyM3977tZU0kNxI6PCqhn3Mv8AerY1\nxUuHdE5RV3RSRpu/4DWFeW6eYHS22fw7t396u2MoyOOXu/EZOrxJ5zP5n97dXPao33/M4Hlfd2/x\nV0OoQpC0yfK/z/erm75ZpI5n+XezfMq1lKXuFU+bnMHUVRo1mQb2/h2/3aoIitH8ifK38TVduI4W\nVoZoWXb/ALW1VqletDGoSN1VF+Xb/DXBW/lR3U+TnH2v7mTc/wDf2r/tVp2968Mf975vm/2ayGkS\nO3SToF/h/u1JHdeXId78/wCylebUpw2PVw9Q6jTdShZN/nNt/utWtb6hDNDsabKb/wB0sfys1clY\n3ibVSb5D/v8A3quWeo+dN503yfwxV5tTDx6HsYfES+E6lZD5LyJMuVTY/mUq3XlqEuUUsyf6Qq1h\nSatN87+djb9z+Kp0mdvnT5dyfeb726uaVPlOmNbmlylq5ukwvmw4Xf8AJt/hqKaW8kl2QwrhUZfm\ndV3f8BpizfMifalZ/vbf4aj8m6kZt7r83zIq/dao5Y/EdEakvhiZ2qQhlWZ0ZSz/AO9t/wBmsPUN\nPhVvnfC10lxbvH/y87v71ZU9ujTND5K7ZPl3NXVT92Bz1uT7Rzd9ZPGp37V2/drPuLVJP7rH+81b\nt5HbMrOjsw+7/wACqg1iZJn/AL+3+JPlr0sPzS1PJxBjTWMLhtzs235azrq1cbt/3V+7uroprPy4\n/uM3+7/FWlofwv8AEPi7ULa203TZn+0f6pVi3V6FPyPFxHuxOEh0O81C+FtZwyM8j7UWNN1fVv7A\nv/BLf4tftfeNodB02wkhsoXVtS1JrVm8mP737tf4pP8AZr6b/wCCbn/BHm8+LHirSpvGdhdSO0/7\n+38hoIoV+9ukkb+8v92v23+HP7PPgz4T6Cnwx+CFhpfhTTobBbJLrTbf/SWb/lpNu/vN/erpqYqN\nOGh4laU6kv7p+b3wP/4JO/Af4O6pbJrHhq+1HWIZ1TTdFurD7TczMv3mkjj+WP8A4FX1xa+AfEnw\nz1qS/fxtY+D7uHS1istF0XS4ZLpY1XcqrHGrMrM1eqfFTwvD+zd4LS28Aaxb6FbX15/xVHjvXLjz\nLmOP+JYN3zNI1eORft//AAr0Hwn4kh/Zs8ITv4gsomWDxd4l0zd9o2/em2/eZa4qmK5pcrLp4fl9\n5HL+FfignwfutS8bfH74eXmqy6l82m6l44vVtnkbd91YfvN/3zXd+C/+Cmn/AATz0XwWttrR01NZ\nmZluNN0PRpJFt5F/haSviLxb8MPit+0/42i8ffFbxxqHiHUb23Zp9Umt5NscbN8qwxr8qr/u1U1z\n9iV/gt4y0jW7b4OeKvFWlx26zz28l/8AYftVxu+7u/u/+hVzuFSUvcfKaJ0qe59geKP+ChvwKu9Z\ntfE9z8QvBL6apaGDw7faSqNG275WluZV+auF+KXx28Sa5NND4V8c+EdR0jVtssWm6GyyLb7v4WZa\n8Z+IHgtPi54bfwrrH7Hmg+G7aSWPbdXXiH7T5f8As/d+9Wv4V/Yx+JHhX4eWeu6DD4LtrOxnbzbX\nR5W83y/4dzVl70or3iZRh8TNz4Y6L+0do+sf8JbbeCdPvoFl/wBFuLWVWVv7u5W/irvNB+JHxO01\n7nVfiv8Asx6p4jtLrzGn1CPy3k8v+8qr8u1a8f0v9obWPh+0vhXxnqseLeXdFHay7lXbXuvwB/bc\n+DmvXFtYQ6reIF/4/IZIvLWs/bKISoylGLieZfFb/gnr+wB+3dDfzJaXHhLxJeWbJZ3y2rQT2823\n5fM/4FX5kfH7/glf+1v+zP4yufCuq/DeTxVpTSt/Z3iDT4JGjuIV+9Izbflr91/FnxM/ZX+IWtJ4\nV0fxhouma5G/m3TN+4aP+Fd0n3WZa7P4d/DH4keFfD9zeaB8frPxBD5W2wt7xFl8xf7vzfLtrqji\nY1I2m7odGtXw8/dP5lPHHwOfRdNTVbO2uLe5jlaK9028dVePav3lX722uAjs4Y2+R1ev6M/25v2P\nfgt8ePBt1efEX4UaTofiGaBlg8TaCkcW5lX7rKv3mr8Y/wBsb9jnTfgjrz3/AIP8SR6laR2fmy27\nLtnjb+Lcq1lWp0pR5oM+gy/OOafJM+cms+gR1wv39q/NSx2sirIHRvmbb/vVa8tJGXZbbf4n3VND\nZvHtm+Ulf4a834fdPf5vaGfJG6xhPJ+Zv7y1Xaz/AHOzyFyr/e21rtHMiiaP7u+qF8rxzPNs37v8\n7q2jGcjP2kI7GJeRu293h+7/ABbvvVj6gvyibyWX5Nu2t7UI0kXy4+F37d26sPUI5o2Unkf71dNO\nPvnFWrT3Ocvv3j+Y742/Lt/irEv1maREKLht33f4a276N929P++qwr7zvLZNm5f7tejTieXWrS+0\nUbryQp4/4FVKST5iNnzf7NW7pU2je/3k+7VWTfHJ8iV1xiccpe8V2Xam75qY8cbR7P4t33afJ5jf\nI+5v4tv92nwxyf8ALTrWkYkcxb09fNkV3m+7/dr9Fv8Ag3HjEf7avijC4/4tZff+nLTa/O6xjSPb\nsT/vqv0R/wCDceNl/bU8UNKuHPwrvc/Nn/mJabX514rxt4c5l/17f5o8biD/AJE9f/Ccp/wWBfZ/\nwUr+Iz4PynR+R/2B7GvE9BkhmhEwRt+75G/2f9qvcP8Agr+UP/BST4jxccnSC2Ov/IHsq8M0GPbG\nPJ4O5drN81enwHrwNlf/AGDUP/TUToyn3crof4I/+ko6vQURbjyU2tuZfvfw101jHHnyUm4aX5Pk\nrmNHZ5mZzMp+b7tdPpv+kKYUhbdv+SH+7X1XNy6nZKJ0Om28Mio6Pu/3a1rKGZ5h90JGzNFGv8X+\n9WPpcOJBvmZdvzba17GT7029n+Xcny/NUc3MZc38pft7VI28+d/mZv4fm+Wrq3Ajbf1+Rdke35aq\n291C6mPYx/2Vp8sn2VjGqKEb5nbfWg+vvDdQvP8AXJMipui+8v8A6DtrIvBDHbp5M0h2/L538TNV\ni8TY4m2btyfOtZzNc7vOj8tW+75av81Ev5R04jbi5eRnmnTLfef+7Uc108Sq/n7vn2ov3trVS1Zp\nPuQ3qsmxWlVf4f8AZqlJMnk797EfdX56mUoSPbwcYR/xGpdagjMPO2zLHL/c+81ZvmJGuLmZdzP8\njbP4arSXENxi2D7Qsu7a1Sfbna2Z7lPkZ9qLsrhl/dPs8vqdGU9Q2SSecj4G755P9n+61c3rkcci\nqiI2xW/4FWtql0jWpdJmRG+9urA1i+eMMvVf42rGMZnvU5fZkcxJebXZPJYj+Fd9VJblI2++uf4q\ndJsWQpDNnb9/b/eqtfSYwn8O3722p5o8x+aezl0HrqCRss3zMVq7b6kkiqjzLvrGa6h8wSO+xV/h\nWhV3TLJC8g2/N8r/AHqyqU6UmbxjzHRrqjthCrZb+781a9nqCbU3vsZtquv/ANjXIW8rrdK7uyfx\nLtatm3uJopF+2Jvb7vmVxVsDCUuaJ14ep7OZ19vqyQyK8z+Vt+X5fm3VuafqHmKs0d583yr/AMBr\nitPuEkmb5Gdf+WTVu2cx3I/95/8Ad2rXP9ThHb4jvp4n+Y6qxkRVM00LEyS7UZvu/LWpZ3Dqyfw7\nvm3fe2r/ABVzenLNJG6Q3P3pflkX7tb+myTbET+HbtdVWuzD049TT2kuX3S/HIkLK8ULHc23zI//\nAGarMlrI0bP5Kh1+ZpF/u1FYsFUzfLt/us9TzLNHI7pu+7/E/wAu2vcw8eU4J1Jbsr3SvHINjr8v\nzPuqpcXCW8L3M37pP4pG+7RdXGYWuZnjV42ZEWP71ZN1dYyk021Pu7Wr1Inm1Je97xHJcCTe/nM/\nmf8Aj1UtszM/MeW+VKG3ov7l4/8AeX+7TjLbNjY+1v71ay5eUUZAFh8tNj7P4dzfdZqr6hDDGyb3\nVWZNz7XqPbBJIyeT8zP86s//AI9VmS3trj5xtfy/l3f3a8mt8R6VCpKUdSnG6K+zf/ubfu09Y7aO\nRPn2My/6tnpsKp5ypsZh/B8v3qWbY0hTZlP7q14OIj7/ALp7eHqe7flLVuz/AGXYgx97zdz/ADNV\nvyfLWJ4fM+7tZf4f++qqW8GNiPbM3y7dy1qxwpJcLbfMm2Jvvf8AoNeZWlHlPTpS/mEt9isr72+9\n8rK9Ti3RZP310xVfvSN/FTrdfLj/ANJ8z5f/AB6nCH7Mod3U/wAP3P4a5+aP2RylEnaORbdUttyP\n8rPJ/C22rcMiMQk6KG37naP7rLUFjDNNEmP9T95d38NWo40Me93YN935V+Vqly5jjk5RjsamnqGZ\n5ndtm9XX+7u/vVr2NzNNIzudvl/Lu2VjW7JG0MUCYf8Au7/vLWxDceZI8KfMzfdbd8y1MnPm2FH3\nY3LscyTR/ang2iP5f97/AHagkj+wWZhvH3D7yeWm35f7tXY1SNSiTSJtlVvLk/hqpcLunMM0kjD7\n3zPURlze6Ty+01CaRFjDpNsCrvdf4t1Z+qTQyMiQJsTb8zQr826pN0LebNs3Ju2rtqpcWciqfJ3N\nIy7V8v7rV04WPLLmMa/vU+WJRvtlyv2lnUqu3ezVUuoZnWSZNv8Adf8Ai+WtNo5lVraFFDrFu/ef\ndbd/FUU1vNbqT5ynzPl+Wvfw/NLWR4eIjyysYzW8MiiR0Xb/AHd9U5LWHyX2Js+fdu/hate4hSdf\nO/i/vf3dtZ95dfaIVhtvn8v5mVlr0InDUo80TOW18tok8n5pP+BLS2qwySb4XVhu2eY3y+XSsqeY\nzo+Fb5f+BVFBM+4QuVVt252at/sHNKny6lqa3gVfJR2O7/x6k+xp5aOk27/Zao4ZJo7jydmdvzKz\nJ8rf7NWLFXZGhk25b7lY1Iy5CqPuysxzWKXEJTydq/eVaoXcP/Lbeu/+8zVqws8MZePlGfb81Ubq\nNFYQfNmvN5pRm7ndy/CZkmn3KIj71/iXa3zMv+1UNxp6bvJ+6rfwtWxb27+YvnJt+b7qru3U8Wby\nO/7lTHH8q/J8u2p+1Y1lH3eYxI9D3KEtvL2bmbbJ/D/u1paboMKyqgfJXa0XyfM1ai2KK290/wBc\nvybl3eXWja2Hl7NkLfwrtrqjzR2PLxEeYraXob2uLqZGdvvLt+Xa1bGj6Sizfvty+Z9/5Pu1Lpun\npuKQwfOu5vmb5dtbGm2aSGLfCzIvy7d6/N/vV6VH3Tx60eXcvaRZWzTJMiRukfy7v4dtdv4ftkWN\nXt/lVvm+X5ttY+m2MMe1Lb54ViX5tm75v7tdh4fsbbzYXg+UMvzf7VenH4DzK0v7x1GhrN5imZGd\nfN+TdXa6LbwxRmFIWV9n+98tc34dVI5IYXm2szfIv3v++v7tdzp9ukE3/HzJumi2+Yq7q15TjlKW\nxcs9Lgjj+zQpG0m1d8n8W2tLb5luk3kqzeVsfcvy/wC9/vUy3tbbcPvff27l+XctXriFI7dnR8hf\nl8ur92RMako6uRz0kE0yO6RYfd8m7+7/ABM1Z91paLJK6QsRvXdt+6tdHLY+cuxEb7m5vmqnNbwL\n++N4ybk3P/wKp+EdOXNPU5TVNMhmf/j2yypt3M/ytWZe6akcOy3dUSRdv3/u/wC9XUSWPnMsPRPm\n+Zv4m/vVi6pDNbnzoX2DY33f4f8AaaspbnXTp+9zHI6lZ/vvn8tmX77bNq/7O2sK+08Nu2IrTN/d\n+XdXW6zsmt08yGNPM3bJNlYOoWm5WSaHZ8v3o5f/AB6uKodtPc5XVLMNl0TL7W+X/arCvLWGORUT\na3l/Nt/2tv8A47XXalb2DRvD58yFU3K0fy/N/drC1iz25d9qSfefdXnVNzvoylE5uaFI5vO+VGb5\ntrS7qVrBHUpv81YUVt38S1eutPS4vI9/Kr9zau2oGi+xvsfzNzfLtX+7/vVivdj7x3RlIns2SMtb\n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\n393zLtqzp9r5yoj8srbn2ptatJbWf59+7ayr5TbPlq3baO903n21h5rTJ+9k37a6nhf5jj+tdYme\ntvcs0qWzrGiy79u/5VWrEem37R8WzNFG/wAjf7O3dW9a6M93a/Y4eNsS7f73+7Wuvhua3t0RIcBl\n+8ybmWulYWO6iZ/Wub4jgLrTZplfYnyx/K8f3GX/AOKrIvtFSa6WdIVDNE37tv4a9Pm8N2zfunSP\n5U+by/vVmXmgpIXZIVUK6/M3y/ereOHN6dblhyyPOW02ZmX7TDGhX5vMX5qik0l7ryZEfD797Kv9\n6uuuvD940bJNBmL5t6x/eaof7F8pQ7wqfk2rG1dEafLLQ1jaUTiNW093Xy9/H3W/vVjXXnWse+GF\nflf96rV2uraLcyXCfaU2/J80kf8ADXO6lb2zSPDMm4bl+8vzM1acvML4b2OcvJYdzzfc2/8ALP72\n2qYW2WZnmm+T+Nlf7vy1q61YJaxl3mUbpVX5fvNWHJcTsxtrNMbvmRtm5dv8VLm5jCpHmNFdjTBE\ndgrLtdo2+Vammme1tWT7Sy/N+63LurJsbqcyL86k7vnX+9VxZHWNn8ltzN97d93/AGawlHuc3uxi\nW5Lzasczool+6/8Atf8AxNX7fWJoWFmlziRf4f73/Aqwn1Ldsd03Lv3Mqp93/ZqzDeQtGzojfK+3\nb/CtedUpx59TSNTrE3ZLzbbh5pvnki+997bR/aM3lnei7/8Anmr/APs1ZjXXlL5cKZiVF+9821aR\nbyeaRnRFdpPvt/DUU4zJlLlNL7a8kozt+XdvZf8A0GtDT5t0K3LzfL/tPWJY3XmIUwqf8D+61aOn\nxJN5X3d+1tq/7VehRX948utLlN21V1kkkvHj2fLs2/7tXdLjfzmd4chfk+b7sf8AtVjW83lxhPPz\nu+/H/Fu/vVs2u+ZDM8zP86r8qbd1eth4nj4iUZbnUabsZkj3/M3ypu+Wur0e4S1kRIZv9Yn3m+Wu\nO0ny5LtIZH+dfli3fxVp6ffIMJOke3ft+b5q9OMfcPFrSlGVz0XR791txNG+3b8u5v4q7LQb+aNX\nud+Ek2/w7v8AgNeX6HqyfZd8nlqI3VX/AL3/AHzXVaLrkELOm+QKyfPItEo+7YzteVz0GHWnjuok\n+Xav31/9mrSXWoVUbHjmb73l7vvVwNj4gs7phZ3LyMyxM0TKny/8Cq3a6kjRpvfYy/JLtrlqS+yd\ntGnI67+0PLj8maRl+X7q1mXlxDcQhNjFo/vRq/zVmyaskcYmtnZl+7uZPlrOn1iFZAjbt8ib/Ob+\nH/ariqVDvp0zY1K6hhZHfd8qbtqpWFq2sTSZtoX2Jv8AvRr8q1l3GuzSLve5Z1Vm8pv/AIqs2+8Q\neTCjo+5l+VPm2/8AfVctSpKJ1Ro8xa1DWvtEL2qPjduVvl+bd/ermdc1qHyzZ/Kw+7/tfKv3qrat\nre66eF5lT+L5q4/XtSRt6QzRuVf97+9+asPaHR7GRa1rxFCsfk75N27c/wDtVxXiDxVKrlNkY/6a\nb/vf7NL4g1BNPjUbGzs+RWf5d1cdrWsBm+TaPk+anKQ4xG614wucyojsP4Vb+Jq47XvFTtI001z8\ny/3X3bad4g1RI9u9JP4t7b/lrl7z5mfZ93Z838W6sqcZm3wlu48URMpSF2bdLu/ef+y1f0XVHuLp\nkuUyY/4ZK5CT5rtZ/JV2hfam7+Fa6DQ7eaJUTYpG7dukSuqMokSp83vHp3he8mjhR4X+b733a9I8\nKalMu3Z8ztt3q1eV+FRMskKO7Zk+Z9qV6R4bjubeNpvLUbflVmf/AFm6uyjL3bHDUj9o9d8OzJC1\nuzvGA3yqscqt/wACrrdLvEj3o6b9sv8AE1ee6Ctssdvst1xv+6vyturtPDrRzLHMn+t/jWu+MpnH\nUid7o91DNbwu6N/ddV+Zq67SbhI1VN7Bm/76rhNFmhmjWHzVUr8yblrrtJuN1xE7w52/xQ/3q7Y1\nPZnBUjKR2mm3ieWOVhbZtRv+em2rkcaR/JPtWWR93mfxM1Ymk6lDbp5Mz7w25k/vL/vLVqXVbxo/\n3M28sm5ty/NXTH3YcyOP3x+sTfZ5k86bYVbdu/i/2q4nXNURbh4fOXy2lb5m+Zmra1rVMMvmPmSP\n5q4vWtUmSRmezbaq/eX+Fqxl8ZtH3TnPEN5DJ+5hh8vy5VVpNv3q5LVrj7ZIlyJlZdm1WX722trW\nLp76YzP8i79u5lrmtSuJmZvkXy5EZvMZ/ut/drjqckpnbT7GNq187Nsd5GeNVXav3f8AgNczrUZj\n33kyRl4/+Wn3q6a+i+bfNcx75Plib7rVzeuW4jZLm5dd0iMqVzVDri+hzupW6Jao7wqF/vfeb/dr\nntYiT5JkhZ5Gb+F/laui1BvtUMnnFUG1fmj/AL393bWNrH7xw6cfxK33VWvKre6dtH3pHM3Fqk7N\nD9m+aP7zKvy1BawpHIfJ+9/31V2bfNI77FVP71NjheNsujbPus3+zXmyj7/Mz0acuX3TJvrULatN\n825v4qrwW/kwojwsQr/xVuXEaRqYU+b+JGqjdIkyq7+XmNWXb/drSM+U0l7xVj/eL86Rrtap7Oz8\nu43lFYN/C3zLUflPHsmmh2t97b/erQs7jfcJ8kaor7f9rdSlKZrTjDlLluvyvCkLFv71XZbN2/0l\nH4XarLJtb/x2q2nq8ysnnN99m/eJ/DVyNkvVDu+2Rk/hT71KNOXN7pXN7gjR+VJ88LOnzf7VPjtE\nmkSYIzFf4d3zVJ9mmCI72rKG/wCWjP8AMy1LummYPC6hdzfKq/My0S91+6EYzl8RQ8l/M/0m2kZW\n+bc33lr9Hf8Agkg4f9m7WTvB/wCK2ucgLgL/AKHZ8V+eVxZv9oZ38wL/AB/7K1+h3/BJNom/Zw1p\noW3D/hNrn5s9f9Ds+a/HfHd38P5v/p5T/NnxXG8ZLh+V/wCaP5n5y3lw6wtC6fOv3FZtzKtZOpN5\n1uxd96t95v71bnk7Jn86Fh/eX+Jqx9Uh3SPFD8g/u/3q/Wq0uX4T7un70Tm9UNzJG0MT5ZX+6svy\ntWXdfbF3zTWyov3nWN91aeqWfk3DyvGwMa7flrMuLMMzXLzY+Xa6r8tTGXeRZl6lIGVodka/w7f9\nmqckbq2zfuDLWnJCl1GqfKi/d3f7NVprH7PC6F9+37m5K0p1oxM6mH5pcyMTUm3QpCnl42fLHt/2\nvvVnXi+YzQptzv8AnrX1KN1XfD/srtasm4WaGOVM7XZ927/Zr0KcoxgefWp80zEvFto5N/nfP/H8\nlY+oTPDlIU+b+NmrYvpkjJm+X/gX3mrE1OSFpj8n+9XZTOOpH3yF5oIW/ePIWar9pcXUku932n7u\n3ZWXJ80jOjL/ALtW9PjdptiO2KuUeYuJ0mnzHycI+5lT5Grb0ubzI96PJu+981YWhxmRm2bd38O6\nun0bT5mj2TPgM/3lrlqU+U9Wj8Jq6Pbw7d/3tvzf5Wty3t7y6mimRm8pk/dfuttU9LtIf9WiKrfw\nt92t/SYfLPzzNGPuov3ttccv7x6NOMvdFtYEkYQu7FVf59y1seG/DsOqap9jhtvNdl/erv8A4f71\nJbWMy5Tdnbt+XZ/FXT+EdFe41iJEh3Sfwbf4d1Y+zjLQ3qRlGHMfS37Enwj0Oz14eM9bh85LNldI\n9m7cyr8tfpL+yP4BufDN5e/GbxJNavqWpP8A6Bt/eP5e35WZf4Vr5Y/4J1/B251jRdK8NPZ3i/br\nppL+SSL/AFcf8Xzf3a+//E2ueGPg34Vm1Kw0eOf+z7fytIs2TatxI3yx7qcvd91nwGMrSrYiR0Pw\n70ebWlvr/wCKmq6fqEzStLbxzWv/AB6x/eXd/wDFVyH7Uv7UHw1+HujppuleNrLVJpNv2eObTvOV\nf73lsv8A6FXmfiv4vfFGbwvfeErDwrFaalqzRvrmrTS/ejZf9TGteQ/Er4e6xqkc3iq5spNVvLHT\nmVI5HVEjX/0FVrzpSryjLk0HSo0nK0jxv9pD/gol8VLPUH1+58VedbWNwy6No9qu6RWb/lozN81f\nPni79rLxD4mv7b4ifGC9urlVl3RWN9dMyyf7O1m+7/u1D8bNY1b/AISLUbDwveQski+VdXEMW5d3\n8Sxs1eBeM9D1LxV4kgbUryS4trOJVt45v4m/3a5rU49fePXoYWUtIns+vftYfG/9qjxlpvgCa/ur\nPw/bxfZ4reG3XZY2v/TNfuqzf3mr1P48ftX+JPhn4FtfgJ+zTrE2mRrFCt7HbxK1zeTL/rJp5/7v\n+zXgvge11D4feH4vCvh7y01LUtz3V591o4/4VovNDTTbP+xNH3TXV1K0t/fbtzM275VVqa5doy9f\nM0+q81W3Kc98RPEHxO+IHh2X4XaU9xHp91debr1xZu32nWJm/wCerfeaNfu7a9B+FPwH8Dfs1+Gt\nG8eftAor295debpPhuN18y6WP5vm/ux/7Vd/4d8YeFf2bfgvP42vNB0W01dVj+y3msfM9xN/DHAv\n8X+1XxV8Xvid8Ufj/wCLpPH/AMSPGV1rF5MrRW//ACyijj/55xxr8qrWyqwWkIjjg6taf92J678d\nv27viR8VNc1m/wBS1jTRbSW7W+jeF9Li2abp8O75dyr/AKxttfNuoatqvibUvt/jPVY3dfl8xU+W\nNf7qr/Ctbui/DvVW/wBDS2VBJ823Zt21pWPwR1VrryXRn+f7qrSlWhKV5M7YZXLblH+DNDmvLVNS\n8PeLbd0VdqQ+V/FXqnwnm+JcGsQXng/Um0vUrWJk86xlZfMb+Fm/u0/4I/s5veXlpc6lYSRwtKu5\nd+35f92v0V+AP7Kfgb/hHYrm9s40TZv/AHiKrN/tN/s142LxFByjBnq4PI6kouR4B8K/g74q+I37\nn4hQ/wBpX/3vtk0u92ZvvL/u19gfCn4E2dv4ZhtrlPvJ8kez5WVfl+7/AHa6/wCH/wAI9E8M+Imv\nNK0qNYm2/Kq17p4dsdJt/s+lTaPCY4/l3LFtba3+1XFUqRlO/Q9OnlEKMT5n8WfAW/1azazttE+V\nf4lT5f8AvmvIPH3wrm8IsXvNMmlVpdiNHBX6QT+GNHsIBcwgLuXtXmvxi+Bfh74iaK9nDb+Syuzt\n5b/M3/AqxqRjKQf2fzRlyn5Y+OvAd/Z3H2zTbZni3qrec3zbd1fSn7BNv8L9Y8TRWfi3xa1m821f\ns7Rb9q1V/aE+Btz4LuhDDDIyruf5U3LWn+w3a6DN8TrHR9ZtoYpbqVVt5Gi+ab/Z/wBmu7BVve9n\nc+QzLB+z5mj6J/aUs/FXwN0mP4hfByaaK0jgkS802F9kd5G33m+avyp/4K8aD4V+MGvJ8XdE8PW+\niaqunR+fa28W37Uv97d/er9u/wBqf9m7V/G/wb8iC8UfYV8+KaNs7o9v3Wr8av8AgpR4Hm0n4X6l\n4nfbFNY3SxSxzJ8zL/s19LGM4yjKOkT5vDVOWvyy+I/M1Y3bejuzPu2vuqpJbzGEwl8eX/drWuGS\nRv4Q7fw1BNGiycIp2/favZpyhyHs1I+4c5cWfl7tiY2/xbfvViX1q7PsTjbXZXEPnNs2Llv7392s\nfUtN8vL+Ty38K1tTlrzI5ZU+xx9/Htfa4/gqn5HmE/Jx/erobzSUkkH7lflrOuItrMmfkreMpyOa\nUeUyY9i7U706OPy1/wBpf4lqzND/AB7NrbvvU37Om75+q10c5lGJLbq/y73bc1foT/wboEf8NreK\nFQ/KPhZe8f8AcS02vz0hb5th5+Sv0G/4NypN37bfimPj5fhXff8Apy0yvzzxW/5NzmX/AF7f5o8r\nPrf2PWt2OA/4LKTrH/wU0+JSFsbjo3/pmsa+dNPZ2kCDcDI33lr6C/4LQRn/AIea/EqWNvn3aMoH\n/cFsa+d9Pm8pld3+6levwFHm4Fyr/sGof+monRlP/Irof4I/+ko6bT1haQp823+Kt+1kSONETajb\n/kZfvVy2nq82x/OZT97atbFjdPGzP1Lf+PV9V8J2/YOjs7rdN9lSFsL/ALPzVoQzQtC8yJg/d2yf\nK1ZNm3lyKj7t8f31q/byQ/K53bmfd/vUfERI0LWPy1XedxZN27/4qlkWby3SV8N95KijufO3plYm\nV1/d7f4aJ5P3RhR9zbPnZnrWMftGfxFG8idePPZVZNvy/wANZl0qeVLC6M/yfI27bWnebGkLvu3f\n8tdtUrqH5vkTKf3v4qv7IRlyyMeSRPMZJht/hqtLD8xCblX+LdWlcQ7mCJHtZaoTske95tq/N/31\nWMoyN6ZWX5mWHzNoX7lMmCRt5Lv833ljalVngLJ5e4b/ALtRSSbmOU/i+ZmqJUzso1PZ+8Z15I/z\nb/l+Td9yqpktmYo+4/w1PeA+Wd6Nln3fM1ULiTqH/wD2qjl+yenHFHW3SzfaF2Jtbf8APVObZHJG\n8yMx3fw1p31vMq733FlfaG21VuC7N8iM25Pk2vXzvtI/Cfq2Hw3LHUrR72kd3Rfm+5tqeGONYx5x\nwP8AfqNlSPKINr/wL/dp9vM/nb/md/u/LWUpTPSp0YxNKz3ySBHhx/tf7NX44UkUeZ0+626s2G8j\njZRv3lvl+5V+GTy5N77nXZ/DXJLn5+YyxVHmhyl+FpJYRsTaFT+/V+NoYY/O2Nt/j3f3v7tY/wBp\ncf6S7/8AfNTWtwm37TsyzP8AMrNt/wCBV10oyfxHxGOp+zlK5sxyIrfJH838HyferUtbh7iOOF0k\n/efOrbPlrnrK6Rv+XnLb9q1vWczwxxPMn3W3Jurp5jwuU1YbzfGqO/zfddY3rQtVhbbvgbyo03Or\nP/3zWNYyeYzJbIq7vvyR1ajmkZvOmdkKr/yz+bd/stXVRqSlHlM5Rj8Rfkmf5P3LbG+Z/nqOa+gZ\nShhVWbdvbNU5tSmZfJmdRt+Xb/8AE1C3zNs87/tm1dPMZSjze8TxyPGwj2YTZ8tMVkWQb+f4W/u1\nXWaObdc7W+5937v3aRb7aqzIjL/Ftk+781KpU5SI0+U1LGO2uPnd9hb5vLarMa+duG1V2v8ANu/i\nrLhuoVkRPP3qqfM2/wDi/iq+skM0aPI+DH83+1Xl4ipKckddGjGMTVsrOaeZNg2J833U/irX0+3M\na/fZhH/e+9WbpeoI2Zppmk3N8u59rfdq9DqUO5Y0dR/fX7zL/wACry6nN7XlPVp1KcaWjNS3j8tv\nOSXczff/AHvy028muYV8mD5k3Lv/AImaorW8uW3JsYSTRMvyp/DS+Y8kiB02SKu1JmqKdPlq+8df\ntKcqRNaSOu25RI87vvfwqtatnaPdSY372Z/4v4VqlYr9skRFRokX5vLX5d1dDZw2ki/c/e/Lv8t9\nrV6eHw8fiieXiMVy+6vhGWel+djZD5e2X+H/AJaVah0ny5GSaZlC/N5ez7tX7PT/ALRGXmHC/Nt/\nu1ftbHEyTW1tmOR/vb/u16tHDnj1MREyv7JuZ4Q7j733K3dN0lobeOb7HJ5W/ajRturS03R0hV4X\nfeit97du21veHfDL28ONm4NL97ftrtjh49UcNStLm90z9L8O7cOkzOkku1f9n/erctdBWSFbZ38v\nd/qm/vNXRab4Zto7eHY+/wDida2NN0XzsvshD/8ALLb83l1tKiSsRKL5Tgb7wukPlTJa4O7/AFi1\ni6v4ZdrgwmHzV/iZkr1abQdtw6OnmFvv7m+WsjXvDfl3Ucy/IzL93+9RGjynYsV2PJbzQX8xvs1t\nC6Rqu5W3bo2rn77SXjtTNNbMu1/u/e3fNXst54deO3/c221vm83/AKaL/tVzF54bhaEzbNpbczx7\nafsonbTxHNHlPLda02GaTYnRd25l/hX+GuM8Rab5MrO/Kt8v+7XrWqeHbPyXfY0P91WSuE8Vaaka\n7HfZ5L7Yt38SrWcoxN/bM831q33RnZt+9u3MtczcTf6UIdmza3zLvrrPFEOyTfDPIH/g/u1xOrL+\n7Mhdcr8ztXN7MUqkBq3kVm29IfnjfbuX5t1OXVJldo5n+b+Dc/3lrGa+h3Mnncf98/LUDaslzcfJ\n/D99qz5eY5pVOU6OG/h8xUT7v8TVNDqE21k+VN33/mrmLbXEj3b9ztv/AIasrqUca/675GT52+9u\nWseWXNzEe05Ycp0P25I41tndgdm7ctPbUPld3nZlX52/hrnv7aST7j4f70Xy1F/bDyL9/e7fM+2q\njTjLY5vbe4dZHqUNvb/aXdpEkdflVK0YdQeb5E8wbV+Zo/urXE2usIoEKPiL7y7v71XrPVHW5SF3\n3pJ8rLv2100aPL8JwVq3N8J6DpmpfKHeRiV/2vu10VjqUO6H5/kb+GvP9GvIfL3u8e9X+9vrWsdY\nTzvkmbc3zLur1qUYxieZUkdymsTRxPvdXXZti2/e3bq0V1aG1hfZcxyuv3Nqfxbq4aLXhZqlgm75\nfm3f3qsx6x5aokb7gzbfmfc26us8yUZc3Menaf4ge8w/nK2377N8v/jta1rr1t5bPHNhmbc6tu+V\nq8y0vxEkgDpu81fl+792tix1xJGTfy8b7/mespS+0a0T0yHXJmh8yHcNz7drfNu+WtK18Rw7j5k2\n122713/e/wBrbXnWk645YJDMyq395vu1dm1xIZHfZu2xbdzfxVxVKnL8R6dOid3N4k8xgiTSRMv+\ntVm+VWrKuvEVzayNDNud/wDe+XbXJL4k3RokaSbY/wD0GobjVpmjZPOj2Ku7az/My15datGLPTo4\neUjpLnxQ+3Z8p8z7i/7NYuoeKt1vKiQqPn+Vm+Zq5241aZrfe7qdrszfN/D/AHao3F8F+dLlkVvv\nRtXDLEc0viPQjh5RldGjeapNcR+dC+0SPt3fe+7XPatqyW9vJM9s2z7ryR/eb/d/2aha8mjuGe2m\nwi7vlj+61YWuXk0ipDM7IN3ybX/8drPm/lN40ftSKWvaxM335t/zbd1cpqWrPLHLsRl/8e3VratI\n9x86JgK9c9fedb5d5d+75mjWtoy5pWZh7Hl94ytQuPtUYR3Z2/u1mw6bcSM+x1b/AGv7v+zWncbJ\npMbNu35vvfep9rbu0Ox0Yru+8qfeq/acsAjT98y4dLdpD2f/AGa2tB0qZpGT5nP3altdOdsnYo3f\n3lrb0/T7ZYotkP8As7mop1oc5pUw5v8Ahez3NsRGRliVdv8Aer0TQbd7e12b4wkPzK0afdauM8M6\nejKPMkbe335N/wDFXc6DCjbUT7i/LuV/m3V6NGR5lanywO28NrC0aQ/b1Xd8+5krsNHU2dxCifdZ\nP4UrjNBeG3j2B9y7PvL/ABba6izuiY1+eRFb5ty/w/8AAa9CnKXKcFSmdtpF8gVETywzfw/xV0mj\n6lA8Y2PIjfw/Pt3V5/pGrQTW4m2fJ83zNF826tvS9WSNUtYUZvL+4y/wrXbCPMedU2PRbW8e1bMf\n7oTfLuX+Fqe2reQstzDcwq8fy/7XzVytvrCSKhS5kYN/Czf3alXXE8z57ldsnzbWrtj8Bwcvve6a\nOrXiPblH2/8AAf4q5TWLqG2Evzq/mfN5dXLq9+0K009zkLuZmZ/l/wD2a5jXNWRpPO2xoPK/iXc2\n6spbGsYyMrUJ3ib59qjd8sa7vu1g6jJ/f8v5mZ5Vq/qF9ukWFJmf5/vb/u/71Y9x9mVd80jRTK+3\nzFb71cVT+8dkZT5dDI1CSSZlmvHbCxfejb/VtXO6xqUMke95m+VNku5GX5q19avnjvNlzMr7fl8y\nNvlX+7urkPEmsPHbiEv5pVG/cs/3d1cnodNLrcrzyo0cnkPjb9xm+7urA1a+haQiaZkZvlRV+ZWp\nt5rG5tm+R1+87Ku7bWfdahDPO0ZeMbf4q83ESjT+I7qPJ8Ikc00jMiQeair8+75flqeUJsD/ACp/\nFtX7tZsdwjyNvdQrfw/7VaVqyTTBHffti27Vf5V/2q82p73vHoRjETakn7mH5n2VS/eNGXeONdz/\nAC7V3NtqzNJCyTfZpGdI3/h+XdUDRwxsc3C/xM+371Z0+vMdEfeGx+S0J2vvRf7y/epI7Z1kHnQy\nIrNu3Sfw1Z021RmbPy/71TxokNx8j4WT7+7/AJaNWsZS5tDbl5oak1oqQ2L+SjOitufdU1nGm7Y7\n7FZdyeWv/jtR28e6HZ1Zf4d/y1citYWVIX+RVT5tv3qPacoRpyY638ldPjtkdS33vLkb5ttTx/vL\nxIUs8Nt2+Yrfw0yzW2tvnmRVZf8Anon3larMfmKsP2ZNvmfL51RGXxWK5ftEEzQx7seZv+7/ALLV\n+hX/AASURU/Zy1vYgUHxvcnaFxj/AEOzr8+7i38xh5IYP975X+Vv9qv0J/4JOoI/2c9YQLjHjS4w\nvpm0szivxzx0d+AJ/wDXyn+bPiOO1L+wZP8AvR/M/OuO18uNLOZ/4/4vl21m6xDtb50XP/stazN8\nyzfvGlX721dysv8AtVmX1vLHLv8AmZF+X7u1a/W5z5uZM++oxjH3Tl9S0949yfKvmNt3N822s2a3\nSZjsfav/AD0b7u6uj1azjj6p/uVnzWsPmNHbQsu7+Ff71c/tYx1OyOHlIw5LXarI9su1vv7v4qo3\nRdZBC77Gb7i1szNbLIuIfM/hZf4l/wB6sfUpbaOPfC7Ar8yfxVdGdqnwkyo8sTJ1JYZGf9z868/L\n/DXPai7rI6E/Kvzba3tSm+XehXc3zbl/9mrntXuBtfnDMnys33a9XD7HBWpnP3nmNJvdN1ZNwzLu\nTZ97+Jv4a0tQR1R5kfeq/wAO/wDirMumePc8w+8lepT97Q8epT94rr+8uBl8bfl/4DWrpMY8wHY3\ny/LtrNh86aRNiKWX7+2ui0e0x9JP9iunl9wKMZykbmk2Pmc/dZW+dd9dVoempcYfycqrY2tWLo9j\nDKvz/wATbUauy0PT0UM6Bd7LtrkqdmezRpy5veLWl2CSM+yaMfPtXd/erqNN0d7eNPk+8m5Ny7tt\nVPDtuIVR7mONgvy7mrq7CzSRnkhuVcLt+9XHUjL4j1adOlKMUiHSdL85SkFs2Wi+8v8Aer0z4C+E\nU1bxdb22q3LBdy77j7u1a5TTbL7PcO8czI33F+T5d1e7fsh/CnW/Hniqzm8PabHfqsq+bGzbfm3f\n+PUo8riLHRjHCyZ+t37JXwp034Z/DPRYbbddXmpWCtZLIv3Vb5m3NWt4wkfx148SawtlvNL8Nrst\nbe3X5bzUG/ik/wBmOuM+Afxq8T694kl+G8Nm0U2k6a0TMv8Ay7rt2tt/2mr6K+FfhHwvpfhmGwsI\no/MWVpbiT7zM33mauGX7yV5H5tU5k5HnGh/s16lDCuq+JLlrq42SXGrzN/qlkZvljj3fwrXzr+1x\n4N8X33mfD3Skt3tFdWuNP09G8uHc3y+dIv8ArGb+792vqT9oT4oX2t6ZB4H8BC8+0yT7HNqnyqv3\ndzf3mrzT9sr4meF/2Z/hXb6bo6Wp8VNZKsUO/wAz7HIytumZf4pP7v8AdqXKlGlLsdeFoydWNtz8\nxfjR8NX8J6nNo+sJb3Ortu82GHav2WP/AGlX5Vb/AGa8H0D4W6rHrED3O6FZJ/8ASmk+ZlX/AGa+\ngLHXtY1ZZH1jak95cNJO0i7mbd/tVhXUP2y+j0S2fbN5u6eRk+7/ALtfM1MVG/wn3+FyqdLD80jh\nvEXg99S1afVbayjghh2xJ/eaPb8zVlx+JLDwzqXnXOlW7pb/ADPbyfLubb8ten30dhoPhjXDNCzT\nx27bGb+Jv7q147q2g+MPGGjza3baVHA8yf6tpdzUU6ntveRhRw/KzxX4zeJ/iR8bPH1x4w8TzK6x\nv5Wm2q/LBZxr/DGv8O7+JqydJ8G+I43jc220K/8AEny16nofwT8f3ULy3lnGnky7W8yX7rV1Vj+z\np8S2tYrmw0pbzdu3rb3G7bt/hrsrVlGMbM68LhZTd2cl4B8B6xuj1J7CS4l3/IsbL83+9Xc+JrOz\n0m1TVk0SaGRV3S7k+7/wKrPhvwj8RdB1TybrwldQpGn+r8rd/wB8123izXPD0nhfZryNbvtXzbe4\nXbt3V5FetHmPeo4aPLzIxvh34/0Sz2Q3Tqib1ba3/stfe37KuuJ4ks7bR7ORkSRVV5Lja3y/w18F\nXnw78Ja3pNtquj3iq2/cn2f7rf7tfXP7FuvTR2KR2s+949v+uTa3+7XFiJQvGSPRw8ZODg0faMun\n+FfCtr/a2sXPzr8rsq7vMq34J8RaV8QvEx0fTbaZkh2q25dv+7S68/8AbnguzudVmtf3KK0u1trM\n1J8HbjRNH8QR6x/a1rHtRnSNpf4a64VKUf8ACefWjONKTjHU9wt/hK2oWCTBNo2/Ktc94x+GV9od\nvHcBGUH5X213vgLx9Z69GETUbdkDbVVa1PGPlXVoudrL/FXsyw+Ar4XngfF081zPDY7kmfF37S3w\n7fVtBlf7N80MTMkn/wAVXzP8C/7E8P8AxYs31j920d5timX+Ft1foF4y8K2HiwS2N5Djbu+796vB\n/Cf7IOlWvjC+huYbie2mut8Fxt2+W275VrysLGMauh057y1KUZn2PLBbN8NRomvXqzxXNhtjuF+6\ny7a/GP8A4Kx/DnR9a/4SbQbx5o9K0vS5rhJI2b95dfehVv8AZr9evB8V18PfA1z4P8WmS6ihby7V\n1+ZfL21+d3/BYb4Wz3nwT8T+IfCtzI9vHa+e/ltuf73zfLX00Ze9GB8BOUfb3PwNW4Mnli52+cy7\nZW/2qZsTy/Lfbv3/AMNat9p/2XdC6Yf5m+7827dVZtNaQrs3CJm+fcnzV68ZQh7rPdXNUgZlx5M7\nbPL2/wC7/DWZdWSLHI6IxP3k+et6S1TzF8vav+0y1VurVCzI7qob/lpspxlAcqfLuc3Na+crq6Lj\n/ZesrUNNht8j73z/AMX92urm03yYWh2fMy/eVazLjTZljbfCzfPtranUlLU5KkfsnL3FvBG5fyf4\nvu1UuI4dzvsreutP3Nsd/u/LtrNuYEjZt+5VrrjLmOblRmtH829On8dfoH/wbihz+234pc42n4V3\n23H/AGEtMr4DmRN29EYn7u2vvr/g3DGP23fFS7cf8Wqvv/TlplfBeK+vh1mX/Xt/mjxc/wD+RNW/\nwnmn/BaeVx/wU5+JaZ4H9jcf9wWxr5z0248vYk3SSvov/gtXg/8ABTb4mEEgq2i9P+wLY1806fI7\nLsZ2/wBla9fgL/khcq/7BqH/AKaideU/8irD/wCCH/pKOp0e6RtyI+G/gb+Kt23uHWRYdm3d9+uT\n0uY28u9Pmres5vMZXfjd95v7tfU++d/LzTOktLxPL2OnzL8r/P8AeWtKxuPk2JCvyv8AxVg280O3\nyztyzfJ/tVq6XM8jGN/MVt33qqMo/EYyjM2Ldv3e+aP5F+VZP4qhkuJmkZ0j4+9uZPvNTFkk3qNj\nb9n/AHzSyXD/ADwnci7v4fm+atI+9Ax+EdLNNJGUTdtVfvKn/oVV5YkbaH/4FU8bzMzJ8rjbu8v+\nJqdGu75Ifkqoy5ieX7RmTW0Nuu9E+Vn/AIf4qzrqGHe8j20Y/u1uXlui2qvsUbl3JtrLul+VdgZl\n+9Uykax5DEuIUZi6H/vqs66k8xTxIIY3Xe396t26t3UM+dob5v8AZrHurfzFfv8A7tTzcx0RlymZ\neTb/AJ/MydlZF1dBvnfa7r/d/u1p6hGkanydw2/K/wAm3b/s1iXy7ZNkL7T/AHqjljzGvNI9XvLX\n7PJvTc8S/LurNmt0mZtm0L/BW5cW6KPOO4j5U2t/DVRrWGSP+Ebv7q18fKX2j+g4x5vhMmOxdmWZ\n33Bfv1KtqkkjPDCylfm+WrRs384lPm+781P8iaFok8lmdnZXb+GsPacx1x5IwK6s8Koj7cN/49Ul\nvM8Uh2JtC/3vm205fOMeXRT/AJ+9TNyNmH+P+9Tj73uyODFSjy+6Tw3Fy0f7maPZsbZ/earcOyS2\na2R2f+L/AGttUI2+ztib5t3/AI7U1rfPaNvd+F/5af3a7o/DZHw+YcvP7xp2skMK+SiM38P3a19P\nV5IPnTP9359tY9rM+5X3r/vLVy31CbzH2TYEibUZV+WtXH3dDwJe7M29NkT5U2KjbvmZf4qmWaaS\nOR/OXcv8X/PRf9ms63/d2f3237NyNt+9VwJ5cHmTXP8AB8yslaQly6kcv2R8MiRwukMbBNn3Weq8\nlx8yecxY7/kp0m/c/wBmdYi38LVTl86SR3SZdvlbXhaunn+0YyLNxqCSyeS77W/2furUC3kF5IE2\nMPm2r+9+WqzNtkdFRUVV+Zm/ipkd4m7fJ5e9l+RvurXPKXOOJsfakt/3KSL+7f5FZfvNV/T7j5x8\n8bD/AGU+Za59b97iREdFV9vzNG9WLaaFZFdNxbZu3NXHPm5fM6Y+76HV6bN+8/fTL8v96tOPUplZ\ngiLv2bn3Vz+lttTh95b7+5Pu1qQsn/Lbrv3bq4ubmneR0xjKMDctb5DCoQSLu+XzF/h/3asrMk0a\n+SjbF+Td5v3v9qsu1kSP59inau2Jl3M22rsTJsXfZsP4U+fburqo0+aXvEVKkYxNjSWaZUm85WeP\navzfe+Wuu0G3SZXfyW87f8u3+61cfprfMqJCqbn+VlT5a7bw+vnSeQiMjsq7/Lr3MLT908LFVJRl\nY6HR9NeRm3u3y/KzL92uh0nSdrRzbNiMu7/ZaqOg2u63i85MND/zzeuksVRnD/u1dfl2q9epTjGP\nwnDUqcpd0nQflZ4dqCT5t2xa6XS/D/2WRT5KylovlXf92m+G7Hy42R4Y/lX5Y2+81dRpemz3DedH\nCqKq7WWuiMYxOTnItJ0mGHGyFX3fc2vu+b+Kt6Hw+nmJ5NsrPs3RM/y7avaXDDEqOkO6Rf7q/M39\n6tSNWUeT5Mgfyv8AVslVyoPacpzt5oqfaH3x7P73yVz+vaf5N4IZvl875tv96u8uNnlq8yM77G3/\nAN2uY1y1toZQmxim3dub7tR9s05uY5HVLNId3nXO1PK3/wC1/u1y2rxwzXDXnlfIqfupG+9/wKuy\n1OzdZEROYZH+eRVrl/EEbrOdm7dJ8rM33flpcstzrpz5ZnC69Gk0PyQ7VZP4vl3V5n42jtrWN5rW\nFSvm/Ntr1HXGtrje947YjZvm+7XlHjBf9KdXdW3fw/dWplycp0U6kzzTxhHN9n/dzRj593y/e21w\n2vSbt0Pn7UVN3+9XZ+KrhLjzNj/OqNu2/NXmPii6fzCgfmuTlnUNpYiKj7xkapq339n3l+X5aybj\nVo5o3uTNsbft3bqra1evv3pt/wB5aw7jUn3bHf7v96q5f5ThrYj2kTrbbXAu0Qvtdfm3fw1M2tbm\n/dvt/wDZq4qDVnXcm/5W/iar1vqHmN8s2zb83zVPs4GPtpHVtrGzDo+4slH2xOHTr/HtauZXUjEr\nfx7akW+SSX5Hb+9RGPLIylUlL3Tp7e82yNNC/wC8X5W3fw1o2+pbmS6d13L/AMCrkbPVIWj3b/8A\ngX+1V2z1KaR12Ps/2W+XdW0Y++Zne6frUisk33l/u7a1G1rzo94uWZfu/d27WribHUHCqkz/ADt8\n1aNvq02GTdtT+9XVE5PiOzt/ELzY2eWxVfmZvurUq+IkDNs++v31/u/7VcnDqE0e2GP/AIDIv3at\nRsny/ZptjfxL/eWtfQw9mdtpesTSRLDNPuRl27V+Vv8Aeras9afckO+R/wCL+8v+zXDWM3mKrveN\nv2bXZvurW3Yx3iQo9tN5u51ZmZf4a46lTlOqjTj0O5s9Whjt/tKcv/Eq/Ntq0uuTSQib5n+fb/vb\nq5axurmH/j2T7ybmZfvf981oWupQxwh0fbD/ABs396vKxFTljc9jC0eaVuU2LzxAkbeTDu2x8O38\nVU7jWHtY97zYWR/ut/erKa886b7Sjrs3Mu3+9ULMklm9tN8gjb5Nv96vHrYjmie9h8L7xp/2k95n\n7THt8v5YlX7rf71QNqk0m3ztvy/3v+Wf/wAVVNbp2iDoi7Ff96v+zTJrvzGWGH5l2fI2yuKnUO6N\nGP2R8l09xDLM7t8ybflrCvG8xvJ+aLd/e+b5q0Zri5EbW29QjfcZv4qyLxv3Ozeys3y7v9mt6dT2\nmiMKlGMdzO1LfD+57b2+Vn+6tZF1Hc3HyJCzIv8AD/E1aF1cQtCm7978+35qq3F8scnkww+Udu1t\n396uzmlGN0cnL7xm/YdzMiJhtu35kq3Z8Q/+O/LTFm3TFPll3L91W+ZalhZ7e4X59u37lRKfLoOn\nTL1qsO9eVX/erQ0/93Ku/wC6tZO55JGSZPu/+O1saDeJ5fkv50oj3b2kT71EIyj7xrKPtNDqNBuE\n8tUdGZlbduX7tdZoN5IJmkT5nb7i7flrh9NuEjZEd8Kvzf7VdLY6k+5U3yCX5djRsv3a9bD1PePK\nrU/d5TvtHktvs7Ojs+59qQ+btWP/AGq3dN1KaNlufO3sqfdb+KuG0rUvMjMzuyuu392ybv8AgNbO\nn3XlqUSZdvzf7NejTqHmVKPKdha6p5ln/rmj2vtdZF/i/wBmte11S8gjF5ZzM7r8sqtFtVa4qHU9\nsIn+Vmj+VlZ923/ep1nrUzTGQXPPyqzNXo05dzzq1PmPQofEsMDRJC7AsrN8qfepsfif7R+5R1/e\nP/D/ABLXDN4ke1d4LZ/l/jZv/QVqOTxZCpVPOZEX7m2u2PJLY8+UYRmdvNrkLW/2mF2A+YeT/tVg\n6xrhWFd/BZv9Yr/NXNzeKdu57P5fn2u0kvyrWZJ4phaGVLmZfOVtrL/C1RUjy6E+/L3jZu9YSQvs\n3OF27v7zf7VY2s6w9vs3uvmf8tdr/LtrBuvFUFu72yXMau38P8VYN94kmuI2beqrGvzturjqR5pa\nHTTl7ps614ghs45pnmUmN/4W+9XD+IdcmkmkTf8ALv3JI3zbt1V9a8VJIHebbvb5mZa5PWPERaby\nUC7PvJ83zLXBU/lOyPLI3bjWrazh3/ad7N/yzX/2Wsq81bzGBTb8z1iTalukR/Oyv91qrTXDvIzw\nvH+8b726uCpH2nxHVGR1Fvd4VZt6lm/u/LVu11KSP59+w/e3f3lrk7fUJliVPJ3fP8nzVPJqk1tl\nHm27V3fN97dXFKnyw909CnUj7tzdk1VJo3+8zM+1t3y/LUlvqaMvnJbR/N/Cv/s1c+2sTNt2TKnm\nfMm6nw6w7SRuibXX7259qtXPKpLl+E7qcuWWp19rqE0i/PCqbn+Zl+9WlBeW0ciuibtv/Aq5Wx1y\nHzFeS5XYz/6vZ81XV1jEbybFVV+6396ojzSOo6GORPMiREY/L91v7tX9ri6TZ9zZ93f8yt/erDs9\nS8zbvdcKnzs1X7HVIbi4+zFGRmX5G2/d+WkOPvbmpD9m8tvMeMbkXYsnzVahg8lRCjq+1GV12fd/\n3ayLdvL2Q/KV+VvmXdWozJBHsdG2r8zfP8v+zTqe78JMafN8Q2TTYV2XPzD5921nr9CP+CTwkH7O\n2tLI4bHja5wyjGR9ktK/PmaZLpikO5EVP3vz/dr9Bv8Agk9A0H7Ousqz5z40uTj+7/olnxX4545z\nb4Bmn/z8p/mz4zj6lKHD0mtuaJ+eZjhhtXk8mZWb+GobqPzo9ju3y/LuX5lZquyXE15bxIm5gq7f\nMb5dv+1VC6Z/L8iHcqL8yMr/APfVfplStKofptHDwpmJfW7yN++mYJH8u1fmrKu43juH43eX/qtv\n/s1dDNGkMj3f3127fl/irB1S2maHe4UFmXcv+1/DUxqR5uVs9Knh+aPwnPahcStI3yLEFdlZv9ms\nS8m8lwruuW/i/hroNRt32yIU+fdj5v4a53VI0bh9qbfl3f3q76MohUwkdzE1i4eRTbw7UVn+dmf7\n1Ymob2U73XK/Lu/hrW1SP5FKTcK21G/u1i3zRbRv+Z/uu38NepR948nFYOXN7pj3rbVbybb5F+V2\njrNvFQp/tfw1qzM679m3Yy/drLmRPM3v/C33a9SnE8arg+WQmmw7WbydrfP92uo0G3dso7yNtT5P\nk+6tY2nwvE4d0X7nzba6nw/b7o2d5mI2f3K6oy94mOF983dGt/JVEf5y33Pnrt9Dt0mhZ9m3b99V\nrm/D9vMFR02jb/Fsrt9DtXbZwu7/AGv/AEKorS93mPWwtGMjV0uwtvLjTtJFu2snzLXT6Tpc0LNv\nRVEyf6z/ANlrK0VUa4SG2f52Xa7fe+Wup0OyuY2dJnZyrrsZf7tcMuaR6WHw8blu1s/Lk+zb127t\nvlq/y7v96voH9kHxFJ4J8YWF/DD9qm+0bYo/urH/ALVeJWVrZ3BSa2hyW/vf+hV6n+z7HqS+LrZ7\nDa6+aq7mibarblrKp7pGaYfmwckfqh8LfD/hXwH4J1fx/pVzu1TVnkuLq4aLaqq38K/3mrtPC3jL\n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\nVpW+oJcPBMiSIn8aq/3q7qcuY5pUY/EdtpervpMqJMissjsvzfw1srre5VZLlcyf7P8ADXnMPiJG\nYJOjMVf91tX7taUPjCZv9DmmUqv3W2fNur0aMjzsRTjKJ3y69bLPstppCZP9n71RtrDxxu8w+RZd\nu1f7tcdb+JEmkTZNhl3bm2/KtMm8TIq/vpvl3N8u77zV6NOR5NSmdtqGsPNHss79dn3tq1mzeIP9\nIZ3T5I9u+uWXxDprTKj7lRvvSbv/AGWoJPETxNtQrK025vl/u/w7q6I1OXaRzSw/Mb154kh8yb99\nu3P/AHvurWbf+JrmZSjzbP4om2f+hVz154i+ZkeOMyx/3X+9WFqHiRF/c75DF/dWlUrR6GX1flN7\nUvFT7N6OoZfmddnzVkap4ij8lraGZWbf86x/w1zGoeJNsex3UqrbXZqyrrWPLVoUfb/uvXNKpLmN\nY4fl2NbVvEEsa+S87bv7yp/47WHcahuZkSZVXf8AIu/dVSbUnkwm/wCZf4WqpNM8fz4Xaz1y1pSk\na+y5S4t9c+WWSRWLfN/vVJHM/mb/ADo/l+ZN33ayFvHSNpvO+X/ZqKbVHZhsfluG21zfF7pfwnQX\nGpTMqzfL/d+/R/aU20fOqNJ/C1YMl8Zl+f5dv3WqSO4m8xf9W3+033mrmlL7J0xlym3HqTySK8if\nIq/PUzXXmsdkONq/xNu3VjR3iSKIXh5/3ttTW918qJ97++2+sZR5T0KdSMjbh1C5Rk+VWRfm8z/2\nWtfT9Ufbs2Y/uSVzEa/NvTcR95fmq3YX21m3zN833Y1/hrmlGSOyMjs7HUH3b0m+VV+ZVaug0ed1\nhF07/ei27m/iritH1Pcyo74ZW+T5N1dBpupeduh+zKdr73/hrGUpm1OnzHRWt35cfyO2I2+Td8zV\nox3j+YvyfIz7fm/9CrHs7hL5ofnjikk+Vl/2v96r8MnmMkLorfP83+9WPNym0Izl8Rf8ybcm/a/l\n/eb+LdX6Gf8ABJos37OetSsm3f41uG2+n+h2dfnY+JGiR/lf/c+Wv0T/AOCTSIn7OesmM5U+NLgr\n/wCAdnX4544Sb4Gnf/n5D82fJeIkf+MZk/70fzPz+vI/3MVs/wByRF3f3az5IZlmlTyVCRttX+7t\nrUks3uFO9OFfcm3/ANBqFtnnQ74flV9su56/TJVOb7R+tUcL/dMe8t3LG2hfYzJ5vy/dZaxdQkRY\n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\na38K/wDs1NVUaT+78u3/AHqljt3jkR3+VWTa8lOb5V+RPm/3KXtOb4Thlh+WWpDGrxyN911Z/u0e\nY/mNv5p7Q+YV/u7flZajf5lSN7bYzfxUvi5jHl5pEi3zxvs28t/FVuC+hjQQh9v/ALNWdte1k85J\nmbdT4JrZpkdwvy/Ku7+Gsqkfc1NqcuWZsWt0jNsRGq9pbxRzM6PtRvm+VKyLe48uRXd9zf8AoVXL\neZ23b9u1f7tcnvyjqelRqcp0+mzus2+OZVWRvnWuhs7h1X7Sm1V+7t3ba4yzk8uFZkm+Vvv7q3rO\n6dsQ/KyRpu+b5t1RL4bndTkdlpd4/no7/Kv3tsdbVn5KzBE6fe+ZPu1yvhu/H8aM5+78q10+nxu0\nbpdeZvZl2fL95a87ESlzHoYWMZRL/wBhmhYb02Cb54tr/er9Ff8AglHsP7O+sPGGCt4zuCA3/XnZ\n1+ednBtuFmmfJVdu1vurX6Hf8EpnVv2d9YRFICeM7hRk5zi0tOa/HPGuTlwTO/8APD8z5PxKgocJ\nTS/nh+Z8DrHDHIyI8m1tqurfxfLRJawjLw7W+78v+1VmO3hkVPtLsiq3ybfm+al+y/aI9kyMw+b5\nlRv4a/Tox9/3T9pwdEwr7S3ib50kAbd8sbbV3Vk61HtjLzbn2/Nt+6zV1l3DumdELC2X5UZl+81c\n7qEKSRum9i0n95664noU8PDmOJ1ZR87/ADLCqbn2ru2/7Nc7qVrti3vtZ9u3av3dtdl4h0e5WPZ5\nasrfNtVvmrn9S0vdH5yIyFk37f7tdVOXuxPQhh48kjjrqNI8w71kdfmb/ZrOmtYfLXY7Z37nXdur\npNSt4Wjf54wZF3fd+ZqzVt0WPf8Ac2pt+5XpUebTsctbDwkYE9nuuN5THnP/AA1DJauZNibsN/Cy\n/LWvJbpG48nn+L/aqOb51XZEzn7u3+7XqUZRX2T5/FUYRKVvDPGvy7drfwtWtY/vG2PCq7f4l+7V\nOSNI5TIk24/dX+9UliNszOn3v7y/erf7B41SUU9Tq/D+wbUjfd/tNXb6DeSSMkNzMsUX3VZYq4HR\nbuPzjDsZHb5dy/eWut0O+dWZJpmfb8u3d96r5eaPvER7RPRNBvLOOd7OB1fzG27tnzV1nh++ZrX7\nNvXeqfJCzbd3+1XnOj6o8OxI0+dfmbav/jtdXod07H7S8+dz7vL3bd1c3tOU7KNTljynpOk3rxyJ\nNMkaGOLbt+9ur1L4L6pb2PiBdSufnW3tZHTan+z8u3/arxPRdU3NHczTKn8LrXo/w1mubrULiwtk\nWVpImaJo/wDdrxs6lKWXTUex6+VS5sxgz0r4S/Dv4b6t8CLzVfHMy2Nz428UMr6hqFwqyeXG33l/\nu1L8A9J+G/gn9rC3+Hvw68cw69pEbRtut23Rxybvu183ft5fEB/Dfgnwd4A0PWPKkh0triVYdy+X\n5jfN8396vbv+CCX7MN38SvjNefEXWZ5JdN0q2W4vGkf7u35l/wC+mr80y6nifY66HpcVyoT5qjP1\nw/avlis/g7Y6jJDJDBDZxokcf/LNttfn38T/ABY/iy+udSv3+SP5YpGbarNt/i/2a+4f2v8A4y2U\n3hmHwrDZx/ZIEOVkX7zbflr8wPix4wvbrxdc/vtkPmsrRqm1Vrrx+IjXlGMJHzvC2BnhcNKpVjy8\nx0V/oug6xa77+G3eOOL55I/kkZv97+Kvlj9o74f6ba2Vyng+5WS8mumWX7RZbfl/2Wr6J+HviTRt\nauI7DVUkitbdmW48l/mk/wC+q6rxV8AdN+I2kteaBpUdpbwozLNM27zK1y+pBztM3ziPL70T8hPi\nRB4h063mS5hkikX5X3JXlV1qHiTSbeTYkgWT70m2v0j8Wfsv6JeeJLu28RfZ38l/kkk+78tfPvx4\n+D9np6zvomgq8X/PPZ91a+zy/FYf4ZRPgcZhcVVjzQPkm11bWNWuPJf53/2q2tY8K6xpNolyUX7n\n3a328I6DpOopeW0MyFmb920TfLUXijXpry3+wIi7Vi27ttenXrKUowhE8SGFrxfvs4htU+0L5PmK\npX79afheSa6uPJT5T93dVKw8Ove33yfMGTd8q16p8KfhLf3UyXj2zbW+5trOtKlTgXQjVqVTvP2b\nfhTc+MvGVroL2citcPsim2blX/ar1/8Abi/YV8efs5/Duz+LvifSpLfRLqeOCK8uGX95I33VX+Ku\n1/ZH8Ev4X8ZWGpalZR4Vl+ZvlZq+zP8Agtt8Gdc/aJ/4JreFPFXhKLzrrwn4ghvLrbJ8zR+X5bNt\n/wBmvkKtSU8xjB+7Fn3EsHy5R7SOp+IWta5punwj7S6r/c3VufDX4mfDfRdQhutY0+O5ZX+7u27l\n/vVyXjb4P+NodW2alo9wIm+VGkq98L/2ffEPiDxJFYPpsiiRvnZvu19M8BhfYc058p8vPG1adWLh\nS5j9K/2JvE/7J3xZeF/BOr2Ol61G+37HfIqtJ/tV93WXw78E+OPCv/CN+JNHt57y1t9kV0sCqy7a\n/Iv4d/8ABPf41LqFt4k+DLyQ3MLrLEqt8zf5av0S/ZR1j9pbTdXsvA3xp8JTaXeRqqvdRv8ALcL/\nABfe/ir43NMPWpR56U+aJ9hl88NjaVq0OSZ7f8EfD+u+Dbe40f7TI1n9o2o0jfdr3T4O69bf8JZb\nb42dftG1l2tWHa+CbOHTBqBhYJM6s25NzM1afwW8a6V4T+J+PEFur6fY2811Pc3G1fLWNWbdXy0K\nNOti4Rl/Mj1K8fZ5VP8Awn5xf8Fxv2vNH+O3x0s/gn4F8QyXFj4BnkivWh3K32yT/Wf7235Vr4u0\n+3hmuvOSHft4l3Ju+auv+M2oJ42+OXjDxPC7eVqHii+uIJJE+aSOSRmX5v8Adqhb6WjKHkfC7/nV\nf4q/ZaVGNKlGEeh8HgsPzU+YjXT0jwjw7xs3JGr/ACq1Xo7FFyieZ/us9WrOz8mTZ9mZyz1PHC7T\nb03BG+9Ht+7WFb3vdPbp0eWPuxMu4tXe3V3hXZt+f+Ksq803crpMF2/eRlXa1dPNC8cgTf8AJ93a\n38VY2rW6TMzujBv+ee77tZUf5ZGVSjzQ0+I47ULMKzTb2D/eWsbX45FmX5227V3ttrqdStdrO6dN\nm52/hVa5/VPO+0M7zM6qm1I9tdlOPvWkeRUj7uhyOrWsMnm7OGZt3y1y2uWO5i/8TfL81d3qFl80\ng+VFrn9R00bW38fwrXo048rPJrU+55/q1jbRx7NtfaX/AAb52Edv+2/4pniXaD8Lb1dvb/kJab0r\n5J1rScqTsbG/+L+KvsT/AIIBWjW37aniYnv8ML3/ANOOnV8Z4q6+HWZf9e3+aPl+JFbJq7/ungX/\nAAW1aQf8FOPiYEGcjRv4f+oLY18ptdeX8n8VfWf/AAW0t5h/wUx+I8427SNG6/8AYGsa+SpFxJvd\nMnftr1uA434Gyq//AEDUP/TUToyZxeT4f/BD/wBJQ+ObbNvhRdrfw7KtQ3nXc64WqG141+T5l/vb\nqdDP82x4fl/hr6nl6Hp/FL3jbsbxPlLx7l37srV9dSDK3kurN/B8n8Nc5BN5ce+F+W/hWrEdw6yM\niblSiXxcxEpcx09nqTzYhhRd33d1Wf7eeNVSba235a5WG8mjP2aN9p+8+2ntfbRlNpP95qfNy/CY\n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\nrNNBbMixxbtv3v8AvqvnqkvdPr6dP2h0Oi+EfCVrC2t+J7C1eSayZIpLj7sf+0q/3q+Y/jZ8G9N1\nTxauq/2VNJbzXDJFGsW5lXd8tfTHiDx54W8E6olheIuovsZpVWLcsNcVfeL9N1hZB9khc/M+6T7s\nNezlsv3Wp4WaU+Wryo+ddS/Zd0HT45bm8sIYhv8Am3f7v96vBPixoug+EZHSO8/1e7eyt8v/AAGv\nb/2lfjVeaDaromlWc0sU25vMaX5a+LviN42v77UjbXjsyyOzfM25d1exGdSUdDx/Z0sP702Qa14y\n3Xh+xvJFGr/wv/DWJdeOJrVtiTMwb5V3NXPapr3mNJC6bv8AarlbzXHuJkREby2fa+7/ANCrpp0f\nb/ZOCtjYU3aMj6h/ZN+FPi34uao+qpDN/Z1n8txcfdXd/d3V9Y+Afg7eWviCC5sHbYzqm1ov/Hq+\navhd/wAFA9B/ZU+Eei+FPASWtxcfY2/tS6mtVl85m/3q6C9/4KqWHijwWLvS5oYdRX7/ANni2ttr\njrRqX92kevh5YeEPeqx5j7D+P3ii2+HOi2fg+515ppL7bJEq/Kscf95lr6y/4Jca5Y6t4CutFgK/\naZbZhE8VxuWRfm+avwlm/a08V+LPFreJ/E/iG+vLmaXa0l5cfKy/wrtr7u/4J6/ts3Pgm6trxNV8\n5WlX92su1VX+Ja83FVKtCUZzjsdeFnQxNKdGlL3mffHin9rrwf4B+IF78IvEOpLb3bRbYmml+6u7\nb92vP/E3jLSfiRpMvhW8mWaxVvkkZfmkb+Fq8E/4Kha54Y1r4Xr+1F4Pv47TWNNv4/tUa/6yaFvv\nKteN/s2/tOX/AIkuIEu9TuJ5mdVlWR/lb/drhXPKPtYP3ZH0FHD4eUOWovePqr4E/s9+LU8bPNo+\npXFxEt/t+zzfd2/wr838NfUd5rGq+GvDcOlXmiRw3bJuna3Tay/w/LVD9kb+yNb0K31Sa2VZWbcz\nRv8Avd395q7j40rpqsUis2+WJl+VvmanWjGNByXxHlVpSjjFTPCvF99NqV5/xMkaTb/E1eFftreI\nLzR/2dZbaGLybPWNRhggWSLd5kit/Du/u19DeJNNttL0b7fNGw3fek+6y/7NfG/7dnjC88SeINE8\nAXM0ktjpdu14qw3G6NZJF+X5f71HDWH+sZvGUvsl53iPZ5e4r7R8+WukXm1v30YZU3fvErW02F22\nQ2z/AL3yvvbf/ZqdptrNbzRebN8jPtZlT5ttX4bfddK42+c0v9/+Gv1mUYS90+Lw8fd1J7W3hW3d\n9nlMvzfvv4q0lt3Xaj/eZfn8tvlqGGzcRs83lojP8ke6tOxsy37lHX5tq1PsY/EejGXL7plalpcL\nbpZtqN/EzfN/wKsjUdNdl85JpN/8S/wr/wDY12P9lv5LQjdEV+Vo2+aoJtDma3WYWbfMn8SfK1aU\n6alLQ55VPsn0v/wTftVtfgfqoVwwfxXM27dnObW1r4F17QftDNc71j/56/3K/Q39gi0is/g/qSQs\nCreJZmXAA/5d7cdvpXwzf6D5kLKlthV+ZvMr8a8No38Q+J3/ANPKH5VT8x4fqW4kzZ/3qf5TPJtb\n0GaJmmh2/vtvzb922uW1i1eFXRHbP3dzfdr1nXtDeOzlufJ2qz7tu3ay/wD2NcbqmivC3/Hsu1m3\nPGv92v3OnTjI+lqUzzrVtLEcJHzM0a/eZ/4mr6l/4Ij2H2P9rvX/AJMY+HN4uduM/wDEw0+vn3V9\nHTa6O+/c3yRtX03/AMEZbMwftWeIZnQAnwHdgY9Pt1jXwPivf/iHGZ3/AOfb/NHx/FEYxyavb+U+\nff8AgsJZJN/wUC+ILZU7v7J3KV/6hNnXx54g0nyZD87bK+3P+Ctun/aP28vH8pQFSumA5Xv/AGVZ\n18ieJtJdsP5zbf4VavW4Ej/xgmVf9g1D/wBNQJypy/snDr+5D/0lHmmqWflzb9indUENq0is+Mba\n3tW0l42be6ru+ZVqlHpLs2x/l+T71fU8vL7x3lOGyeTPz4/2qtxWrwypI+77u1FrVsdHm3L5Cb0/\n2q17Hw+l0yzTIyf7O37tRy+7oXI5+10maSTZHubb/DWvBoM0m1Ifu/xq1dJpvhtWQPD8qKny1p6X\n4bedorlPnZfvfLV8vP7pHwnO2eh+XtTyWH+1Wzb6PtK7eG/vNW4vh8Rw732v/wAC+7V6Pw3N5uxE\n3xr/AMtlf5d1ZS5uUcTEsbW5hVP9G37fm2tWxptiki73TczfMu3+GtCz0O883y0O1W+/5nzf8Brc\n03wu6qrPbfvf4l/hrCUZnTTMi30N7iQXiJ8iy/w0t1o7yM+Icf7P8NdlY+H32pN5eFh+Zqv/APCN\n2p+/8ssnzIy/3a5anmdtOXLLQ8wuNIhkHkvbbW+981UJdG3SM7uo3f6pl/hr0bUvC5aR/ky+z7zf\ndrE1Lw+luqQpDvbf/u1lH4/dOmMoy909tSGFpA823cv3I9ny/wDAqguLd/tW3fG8TL87L96tmS1e\n2tftKRbXVmVfO/iWq3nfvEmhh2fJub5N1eZKifaRiY1xClvIYZvlaT5l2r95f9pqzr+xTzle2kVB\ns3bpP4a6bULZLhd6WbMJE3N/vVlaha2zRrD8zOv8O3+Gk6XLqhVJcsTndWjmjjdLOZf725fm3Vz9\n9GgXZ53LfejaukuLPcu90Xbt2pu+X5a5nxBGlmxmT5FZvvKtT7GSlY4qlSP2jL1Kb7s2/fu++392\nqbXH/LHzlO7+Kn6lPukaSFP3W35t1VbVvJT988eNiqkar93/AGq3jHlPOlLml5GxZtM0a/PlV/ur\n/DWzp7JDDuR2TbtZGb71czHebm8l04V/4W+at3SV+1P5KJu/i8xf4qxrR5YlUZRkdZpt4jQpdTTb\ndzbGkrSh1C2/1PzOse75fu1zlnI8MKJCcJsZtv8AearS3ltuN55Lea332Wubl97U6uaRsf2huhZE\ntmV1T7v97/aqjeXDiPfNudfuvHWdcalMzK7zLG27a0bP/wB81F50ykzTTrj5l27vutRGMypVJdCD\nWGt5oX+fa6/Mi1zbXCOypv2S7vu/eVqvatdQhmSb5y33qwtSuv3exHXZt3Mv+1Xdh1GMTzMRKTkP\n1C4RlYzeYzq/8LVnX+sRhWSxdQn97+KorjUIUVnRFV2+/uesa81ZAqv/AHvu16UKPMcUsRLk5TZt\n9SkuNrufmX+791qbc30PmL/pkjt95l/hjrnYdYeOZk879yz7U/u1dutQhmhDw7gm37tdlOPKYSr8\npozXUdxGN+3O37yv95q/VP8A4LlTTQ/smeHmgcKT8RbQHPcfYL/ivySh1LbcPxvRv7zfdr9Zv+C7\nUxh/ZF8OkEc/Ea0BJGf+XDUK/GfEeMv+Ih8L/wDXyv8AlSPhuIavPnuXy/vT/wDbT8tluEaTZ0H8\nG5qsLfTKPJR9jf3q52S+e14++f4Ny063v/NV/wC8z/8AAq/bpS+yfVSqe7/eOoj1LDFHdX3ffqzb\n6k8zP867Ifuqtc1DcGRvLd2I/jk+781aNnfPI2/zFwybdy1zVJTN4/zHV2OpbpVCXP3k+Tb8taul\n6pt2qjybl+bcqfLXJrqCWsMUe9f/AGb/AGa1dLvJlXe8ytt+b5V+7/eriqHbR+I7e31SZoU/cqE+\n9tjfa1aS61vt/Oe83MzqryMn+zXFWeqQ3CsnnbVX/no1WG1RzGjpMzM3zbY/ljrx6y5tT2qNTlgd\nguqbVS5jT94yt8zNTJNUyzO9zv8Au+aq1zy688Nn/rsGRNn+WqRdWmiVv+mibNq1Eaci6lSB0K3D\nySsju22b7lKt1Zxqu+b51X51jTdWLb3zvGqO8ilX2/7W3+9UlvcJcSH5/N3blebbt3KtR7Mj2kPh\nLc10l2rzTSs0Tf3V21hXzTSxrNbSMn3ldW/vVtbIZoVffuEaf6vd95ao3du8cLu+1kbb+7j+9Vxj\ny+6ElzHO6nNftH9jc733fd/2a5vULf5pkmmbau1kVv4q7C+heFvO8mTDJ97/AGq5/XNPSSTy3h3f\n7SrXVRqRj7qOSVHm1kcvqFq8MmyF2f8A2v4dtYmpfKzTbPmX5UbZ8tdRq1r5e77u1fvVgatMgGx+\niv8APt/irrjU5pjjh+aPKctfW825n+638CstZ+oWzvGwT5n37vmrcvlMg/1Pyt/47WXf2TyK3zso\n+9XbGXumNTD8pjzK8ch9KW1t3jbfNHt3fNVjyUbO/wCb+KpY7UM2x33nb8tac3Kc/sZ/EWNPV/m8\nlGDf3m+7XQ6Xapa3EWxPm+6zL92s7TbVIdnnQsG2bv8Aero9LhSSP54Vbd9xmSvPrVoHRToy5zV0\n+FF2Om7d93/Z3V0NnHNGyb5FD7PvKlY9isIi8nLfN9zb/DWxZx/IyvMz+Z827+7Xmyfvczid0Y8v\nwmtZq8cfyTfe/iZf4q1dPUMrfut8UafMy/3qz7Fprjy4U2nam35f4q1LFXb/AEZwuPuurVjKXu8x\n1R980IUfa8Lw7yzbauTrM0cUybc/d27vu0Wq+XiaaH5fKbbHGn3lp+n2u0lEhb7/AN5q5fe+KB0r\nljo5Fmz861VHRF3bPn3fNVqzV5mSa2TY2397HIu5ajs4ZoULvCriTd95v/Qa19Lsd0iujtsXa77f\n4V/u1pCXvSOyPN7L3S/pdq8W3y4Y9n3ZW+7/AN81uafpqKv75Pu/L8v92q2i6bNbqqzXO+LezS7l\n3blroLWzSaRXiRXEPy16dKPuXiZfDIpx2LyTLsT/AFny/NWno+kfu/n6t9xd+3btq0unpGFTerlf\nuRwruVq17Oy8va8yNv8A7u3+L/2WuuEo0xylKUit/ZnmWI2bVTY29W/hqS30kt+5h27Nu7c396ti\n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\nZuoX3lgrv3bflqG+uvJkd/Mx/drIvNVTdh5sOzfxV20jy61blLN1qCR7djsE+9t31Yh17y7cIj7v\n9pfutXPTakm4u+1QrU23vk+Z/O3f3lWto+Zze0n8R1UOpJJIrwur7v8Ax2v14/4L4TCL9jzw4GOF\nf4k2asfb+z9Qr8Z9Lk3SLsfaV/vPX7J/8F+3Cfsc+GiQTn4l2fT/ALB2o1+L+JGniNwv/wBfK35U\nj5PO5c2dYD/FL/20/Jc3nnMrvu3L9/56WG4mm/vLu+VqpQsnmb/4G/i/iq5aLPtZN/3q/aJSPq6f\nxaGlZyP/ABn5v4dtXLW68uP5OP8AZ/u1mwTPDIIZvu/3v4au2rbvuOxX7tYyj/Md9OPU3IbhZmTf\ntRV/iX+9V6zvtsw+f5VVty7vlasO3wqrJPMqIzfLWgt4WJTeqbvur/FXNKMDup80feNu1unWzR0f\nMjbtnyf+OtVuz1GNIdibd38e7cy1zf26aPd8m3d83zVbsdQ+VEdl+VtyR159aJ3UakeY6Bbh5ttl\nc7nRfu7U/wDHavLcf6Qk1t5iN95W27qwY7iZY/nmZl/i+atGG6dVV3DY/jVfurWcoy5dDSpym5Jd\nTKUCBlDS/vWZfvVbtZEmk2Qov8P7yP8A5aVkWcyTXqJMkjo3zJWpawzRqZofkRf++t1YSjHl+Ifx\nTLqx+fDsR1Ta/wB5f71F5Dtb7Mjt5Ujrs2/N81OM263RHdvufvWk+VaerXjKNiMhVPk+Tcu3+7ur\nOpzx906Y8stjIvFmXd5MvmeSjKjfw1iahbpJC7pctlVZmWul1Cx8lZTZ+WI/7sfzfNWHdWrhRBcp\n/tfKm2lGP2izl9Tt3WF0eFVuN27dJ93btrlry1eNi83Ndz4itXVtkKbn2/J/drlrq1eaR3hhV933\ntvyrXXTqe7cuUeXY5TWLWbcqxuyj723+7WbdQ7mPz7m/vVvXlj9qmZH8z5f4aq3Gnv8A3/8AdWuy\nnU5dDn5eYwPsqDcifdb+JvvVcsbHDRl15/u1ba3TcqCNWZfm+Zau2Nn/AMs3fcrJu3f3aVSt/KXT\noxj8RY02xjVt/nK0v92tezhTzA8KMu7+9/DVezsYY/Kfycv91WX5q1Y7J7Xcj9Pvf8CrzpSibSpw\nLVvb7pFfZh1+X5f4q1NPheObzoU3bm2t8ny1Vt12yb1fKyJ/F81aljG6t874f5dsa0+blhocvL75\ne0+1ut3yBvv/AC/P92t+zjQW437iP9Wm5fm3Vk6fD9o2pvkCSffb+7WxZMkcbWyTN8qKvmL83zf7\n1cUryl7p1U/d5WaOmwzLIiTbfkVl+b5a0tv7xYU5X+Lb/D/s1TsY/tUgedGZ5l+eRvut/u1s2i74\nz86jbFt2sm3c392s+blidMdx/kwySLJs3MysyM38K1paXCiyxPDuK7fkZm+X/gVUbZkZVSGGRZP4\nt33a2NFt7m8kivIUwq/Kiq/yrV04w+I6PaS+ydBprQyW377a0Tfc8ut/S9N/do6bdkj7n/8Aiayd\nHtUmiRJk+Zn3bmf5f+A102k2fnMiJt+987f3q9LDy5vdOeVTmiWNP0lIYXEMLAs25G2/drSt43WQ\nOibvl3fcp+nw3MMaw+Yz7U2vU0lmkab5txVvli8v+Kumnzl06hLp83zbPLYN/BJG3y1JHvWZtjts\n2bX2xbv++qgt7O5jZn3tvX+LZ8v+7Wnpdpcwwl9/mhV+f5Nu2uuMuX3ipS+0OhsvOXzt/wB77ism\n3b/eqe3sX8v50UP975v4qvWumvcLsuZo2Cov+r+Vmq3NbYt9hfyt3/At1bxnKJyVPeiclq0MMsiv\nchdsbtvjb5v92uR1TTvtUn2OZGdN6s/y16DqlvDJbS7/AN2rJ/Cm6ux/Zd+EqeKvFjeMNbs7ebT4\ndv2Nbh/9Yy/e/wB5a87MsRSw9KVSZxxj7GB9G/8ABL/9kDTfBEifGn4k21q+sXG5dJt5Nv8AosO3\n7zL/AHmr9E9C8R6VYWkdtd3Kxjb95n+WviXTvjVZ+Gf9A02aHzmg2eW33Vb+H/x2uf8AF37WmpbX\n1BUktwv7iKRbrcrMq/wr/DXxNHNsTHGe2geZjqccTBRkfolda5ptvY/b2uVEXZ93y18xftZfFC8s\ntL1V9Jv4cQtl9zfdWvnRf2+PEkeg2miX2sLGk0+1pJPu7V/5aL/tbq8z/aQ+PD+JPBEviHR7lrua\n3n8rUbia4+aZW/2f4Vr2MZjJ5vRVzzsNTjg6vOcZ4++OF5dapIiar53mLt3L8yt833d38LVj2vxw\nv7O3/wCPyZJJPuKvzK1eJeOviDpts39lW1+0kzPv3R/d/wCA1mab8QprCz+zf2l5Sq+1/wCKvj6u\nW1JT5Ufa5bnEqcfiPqbw78dbl7fZqtyqJs/dR/d3f7VS3nxFufEkb2FhrH2f5FZGb7y18uaf8Uob\n6Q21zCyPGnyzNKq/MtdbpfxKh8QQxXL68qSsjebtb5tq/drycRgp0T6mjnVL2R9HaD8QLa1tn02/\n1/zfn/e/L/47U9v8SLOxzZ2d/J5Pm7oGZ9u3/Zr54HjS/t7V4bC5Uedu/eN83zf7NZ2rfETxJoun\nxXMOsSSLv8zyZk2/N91trVh9Vm4+6L686ktJH0bqXxSttQmSRJt7wt8n93/gVC/EjTbW4Saz+Xzn\nVW2v97d/E1fOmn/EyHVXR4bxkdU3XCr8u6trw/r15dfcjy8KMvnL8q/e+VmrKOH946o4n2lLzPpD\nSfHWlLJ/pNy0MyyqzTbt3/Aa7/wz8QNPX7O6OzGRm+zyK6/d/vV8v6f4qeGOIzOuGbbKsK/xf3q1\nvB/ji8jsZFtn8lPNbyNv/POpnRanzUzjrVocnwno37Y37E/wN/bi8Pw201yvhz4hKrf2T4ujRfKk\nb+GG5/vK397+Gvyb+NPwb+KP7PPxEvPhL8bPCsmka1p9wyIu75Lxf4ZoW/5aRt/er9U7X4pfarS3\nh+2SeRt+9s2t/u1W/aU+GPw5/bI+Csnw2+JFtH/bemwM/gvxNIv+k6fMv/LNpPvNG391q+zyXN6v\nJ9XxXykeSq1XDT5qXw/yn5KRwvtVNmT/AAfPV21VFRoXfcq/eVv4f9mtTxp8PfE/w18YX/gbxhZr\nb39jdNE38KyL/DIv+9VC1UKvz/MF+/8AxV7FR8ug5VI1veRYVppIVTztvzqy/wC1S2u+aRprmHYq\ny7E3Utv+5V3huWBk/wBjdtq35EMduIUTeG+bc38NOMrROOUTNvJIYYy0KN/ut96se+t90Urw/Jt/\nhZfvVvtC6sPMEflN821aoXWnp5IRC2Gl+dV/hrTm5ZRM/fOZmsRCv8Ss3zeWqfK1U/sbyR+d5O1v\nm+Xd92ukuLMSR/ImGX+H+9VW60t44/uNtZP9ZW3tPfuYezjymVpdncyKPs0jK8n8X8S12Xhexmt5\nkh37tv8Az0SsbT9MfcNk2z+GKRU2t/vV0uj2MkbKkztuk2/N/u13YflkebXlKNztrGFPlLzeaqov\n+r+auntW+z3n+uX5U+RlT+Gsnw/DDNCiW00O1n3JHGn8X8Vb1rb/AOjqkr/KzfJuT5q9GnThI8ut\nW7Fq1tYZN11czbkVNyxt96vtP/gnHHFF8D9TWJAo/wCEpnyAP+na2r4y+dZVTy8MybWZk+X/AID/\nALVfZ/8AwTohS3+CmrRxqQv/AAlc5Bbqf9GtuT71+RePEVHw7nb/AJ+U/wA2fCccT5slkv70T42t\n/Jm/1L7Bt2qvzNt/3astsW1ZLaL5N21tz/N/s7qhaN5JFVIW2r8u5Wq41ikcy/vt6f8APNvlr9u5\nmfSRqGdqESXAXZcyD91t2/wrWTfRzXUZ3uxTyt27+FttdDdQzX37mEsWj+/5ifw1j3yzeWqI8eyN\nNr7qs0jWl0PPfFy+XGUuX2M0X3q8r8UWvmW3nWbq0avuRmdvvV6x4wkSaFJkhX5mb7vzLu/vV5n4\nkjfa6Xnkl/vfu/lVWqoxlylxxB57fLLJJ8j7lb/x1qr3Um2NXeHDr95lrW1BobZm+Rd2759tZjKk\nzOiT7lb+L+7XV8PuiqVp8hjTXDyRt3+ZdjMn3dtZ19G8f75IfmZ66C60fzJFRw2GTbtqjdaO6oyJ\nG3ytt3feVarm5fdOKRzszP5nk7M/xLSwtuY7E3hv4f8AarRutHdZgvzN8u2oo9N2s0Oz738S1NSP\nYiK5R+nybZleZ8bf7y/erasbpIZEm/g2feX+H/erL8tF+R0ZmX+Grdv8qske7/pltrnqROmnI3rO\nR9u99pXbuSOtK1uvMj+fcBIu2sHTZXtdsc0zL/C+6tW32eWXd2/h2LXl4jm+E9SjL3PdNmx1a5hk\nRwn3U+8v8NdBpc326NZpgzBXVtv/ALNXKwxzSLvR/mj+5tevUPgh8P7rxVqBd4WI37POZdrVz4en\n7SdmaVK0cNSlKR0vw71T/hD9c03xPeOyPb3Su7btystfuP8AsveKfD37av7BV/8ACzSr/dr3huJZ\ndO8xf3vyr5kMi/73zLX47/GL4b6Z4U8KppsLq940XzRq+7au2t//AIJtf8FJfFX7GPxo07UtcvLi\nbTIZfst/a3DM32qxZv3n/Al+8v8Au17/ANXpKjyo+UhjKs8Z7W56D+0do+sWsl5Z3NnJDfWtxtlj\n3/NHJ/Fup3wj/tWbwvc20yed+63xNv8AmXavzV7z/wAFQtD+H+ufFzSfj98KtWtLvwt8QtGjvYLm\nD/Vmbb8y/L/FXi3w90dIIZtN+37IGt28hfurt2/db+9X5NneC+qYpwXwn7rkuY/X8BCqvi+0fFf7\nSnxMtrPxpfwu7K1rcNF5cifNuX71fPfiDx19umldLnezOzbt9el/t6Wd/wCGfiNf2qO22aXcm5/v\nNXzbHqT+dvd2V1/h/vV7mW4OnKhGR85neZVYV5UjfbUJrqZnfdhf/Hq5jxTdTw6ksyL/AA/I1aWm\n34mZUm+f/Zql4xXf5fOF+7ur0KEPZ1/ePjsRUc46SK9rr2p3GyFPm2/M9dt4Y1p5nSG5v/K/3pa5\nXw3pMPl70+//AAf7Vd94d0vwrrxit9Ys1iK/L5y/Ky13S9lKLTQ8LTqy+KR3vhPUPCUkKzXni2FV\njRflZ/mb/Zr6F+Cvwh+GnxK8G3Ot23jC3lvY4mW3hj+Zt3+1XyV4i/Z503xA32nwTqshVV3NH9or\nV+Ev7Ov7UUerKnga4mLSbtvl3G3dt+b7tebWwspe9Sqn0eFjHl5JUn/iPp/9m34E63o/xqS80fUo\nRcWsv+safbu/2VWv0FtdS+JGg+D0tL/UpCzOrLdeb5m2vyj8F/Cf9tjUtQS80SHUIrlpWiaaOXaz\nSbvurX2f8BdU/bw8I26aV4ntrPVYbdlgitbi4XzWbb96vn8wwVZS53qehTwWHlSsuZSPqez/AGl5\nrXT/AOyteeR5obfbt3ba+A/+C6njzw34y+GnhDWvD2pKJ7PWwr2/y+Y277zV7D+19rXjzwv8Kbzx\nbc3NjZ6lDF586x3HmNG393dX5UePfiJ47+M2vR3HjPWJL7y5d0UO5mRa5sow1eWMVaUvciePipex\n/dT+Jn0N/wAE+fixc+H/AB1b2c1+sKSS7pZG+bzP9n/er9cvhr4um1DQ7bUE857Sa33bZPmavxk/\nZZ8K6rp/jSwmVM7bhW2sv3a/Wr4C30n/AAi9q7vI0cMCr5LfxNXBmso/WP3X2j7Lh+pKFDmmY/8A\nwUG+Iln4V+BraDps3+m61dR2bySP/qYW+Ztq/wB7+Gvj7QWhUW+x1z/z0ZfurXpP7dnxPfx38Xo/\nDGlOrabodv8A6UrfekuGb5dv+6tec6DA6sjw+X8r7t0lfpHDuD+r5fHm+0fI5zjPrOYTcTq9PCNG\nEhff5PzeZs+8tdBo9qZ8TOjIi8oqv8zVj6Hj5A80Zf8A5a7fut/s102jwwwyK6Qx/M/zNX0kY+6e\ndHFcvuyNbTY5rdt/2ZnkZdiK38VdBZQsqhNn7tk+X+La1Zun2vmbbn95u2blZfurXR2OkQrGqwv8\nrfM7L/erSnT+0b/WpfZI4bf7HeK/kqRIu1JGfbt/4DWhHavNbmVEw3yo7Ruq/wDjtOh09LhpHufv\nxy/LWra6eIVREs9u3bs2pV8suYipiJRievfs1W0tp4Fu4ZgAf7Xkxj08qKvBP7F3fJNBJF5b7kZY\ntyyV9D/ASD7P4OuF2AE6i5JAxu/dx815hHob/JD9p3JH9zd/FX4t4YQv4jcVf9fKH5Vj4HIq8ln+\nZNdZQ/8AbjgdS8O7pJrm2h8nzH2bdv8A49XP6t4Zm3STPHh13L8396vXrzQIZo0heFi6/wDLNn+Z\nqyrjwu7Sb7l1372b7u3bX7r7Nn0datKR4nqHg94V87ydiyN+9kjXbuavV/2GfDx0z40anfi4Zg/h\nqZCjrgg/aLc8e3FVr7w+8W/f/E/ysyfw12n7KWl/Y/ijqE5jIP8AYsqklcf8toT/AEr898XVL/iG\nmZJ/8+n+aPleIp3yqsvI+e/26fDy6h+094muAzKSlkSoON+LKAV89eKvBYeOSGN44v4t2zdX15+1\n74djv/jzr15LA2HW1G8f9esQrxTWfB73CtCkMcoj3Oqtu/76r2PD6EZcBZSv+oah/wCmoF5U5LLK\nD/uR/wDSUfOfiDwTM1rsmdWeOVl/dxfMy/w7q5q48CvaM0/2Ni2xW/urX0FrHg2YyfuYpJt3/Tv8\n3y1z+qfDu2upAs1g0ZVt+3e26vp5R5T0JS/lPK9N8KzR3GxYWd12q67fu11fhnw3a3kyy3O2JPm+\nVq6+x8FxrH86Sb/vbdu3dV3T/C9tBGdkDMfm2bf4q5eXlNYyMy08PpHGn7lWDN8jKtb2m+D4ZrpL\nlI1R92x5pIv4a1NJ0Wa32fZgxVkXZG33VrtNH8Pu22FHjljX5nkX726p/wARMpROTtfDrrGmy2+9\nL97/ANBrpND8GpNs3w/NG26WORPvf8Crq9P8Morol1DHsX5khX/0Kuj0fwjDIj+Sn3kVnZqfszOU\nuU5C18E7bQec+75t37v+L/ZrTt/CcMbL/ofm7fvyV2mnaC7ZmRF+X7v8NWJtJ2qjp5myNNm1futR\nLl+EI/3jkLbwfDAr7LOGSbzd277taVvo8MjN8irFGn3W+Wt240ea4Xe6Z3N/49TrizSRdkyKW/hV\nf7tc8ve943jI5qbR7aaF0tnUvIn8SVzuseH4Vsfkh2/e81f71d/Jb+TN+5Rdv3VbZ/6FWL4is0nk\nKOn3U2oy/N8zVHL9o15j5G1jXEWNobaHdt+RPm+6v96mW9xZsyfJH83zNJ/erDXVH3B5n3yKu393\n8tT28zr86PIg+9FHt/hrz4x973j9UlyRN2aZ4VDw3uEZd23b/wCO1FdRw7jDMmU+/uX+L/Zql50j\nTDYm0Mu35m/ipsk1y10ruy/u/wC9Sl7shVJUlElkjs8snzI6r91krkPFFu7RyPeTMryfMm5/ur/d\nrqtQuU8wQvc5Vfvsv3q5rxhdJJDI6OroqMibl+aol7p4+KlT95HnXiH5lDocor7d2ysmS43Mkmza\nd+3cv8NXfEE03k70fLt99VrOiaFlbe7b9tZcv2TzKkjSsWtZG86P96yp8y1uW91NDbr5KLsk/wC+\nlrH0bZNIiJNub+P5K37Wz+aH52f/AIBU+78IuX3eYs26wrFsmtm2bVb5amkje3iG+FkP+781P0eG\nG3y7psdX3P8AN8rVeuG2x/6ND8+zdub+GtOXlkV70tTMaTzPnmmjIb7jMn3apalHCrIizb0/jb+G\ntS8uIYUaZId5/u/drM1FkZElRNjKm7ctTGIpcq+0YOsZk+dFZv4t1crrUczRs6O3ytuVq63WJHZl\nKI21vuNXM65IklvvkTbt+98lehT92B59aXMcXqU1yMo7qRWPcXHzF9isK19c2LM/k/xVitb7d7x7\nty/NtraPvRPNqVCCSbzAuz5g1R2/7yTYPvf3al+xv/B/wLbU1nZCNjL8wZfm+Za1j1MeWUpEtmr+\ndvmTmv2d/wCC/m3/AIY58NBhnPxMs+//AFDtRr8brexlWbzkfiT+Fq/ZP/gvxCJ/2PPDCE4x8TbI\ng+n/ABL9Rr8Q8SJc3iHwx/18rflSPmc6hJZ1l6/vT/8AbT8jLVPM2dgu5XWrUPysry7squ2mWtr9\nnVQ+13ZvnrSjhhVlmfzDu3L8q/LX7PKUT7KnRnsNht5JG/v/AOytXYYWhVdltkybflWpI7Wb7OHt\nNok+Vfu/e/vVdt7F93+khfmTau16wlWgejDDka28aw7/AJss38SURybbgu+7938u5lqeTT3z9xju\n3bvnp0cMMlun3sfKu6sZVLm8acpSFUfaY1858n/eqzbrt+dPn8v+Gkt7VFXZDH/F8n+zWrY6R9nw\n/lq25fnrhlU5TvjRkyDTw7Lv+X7v3Wf71adizyTNv/iT7y/w0yCzRVR0LBG+X/erSsbfdHsmm/2t\nq/xVn7Zjlh/hLtiu2TfCNyN8kqr97/erRVnhdfKSSVF+/wDJtbdUOm2+2NURFDf+PVrw28hhXZMv\nzOzVjt9kpUZSHaaqFT5z53bmdW/9Bq3G+7bsTaNjN8v8NO+yJHbq4TLb6sLCiW/kwzbWVG2f7TVz\nVJcx006M4+6ZV5Zwt8j7irfxR/w1n6lYx3DbIfub9u5v4q6mSxmkVdiMVkVV+X5v4azLiO5uIVm8\n75t//fLLUe05Y8x0xonH6xavh3dPm3bdqr822sLU9JeP+BfmT70ldve2aSL5Lortv+dt9Y+oWe5g\njpwv8Vaxre6VKnJe9E4G80d4ZGmuU3hk3bqgm0fnznhVX27ol/vV1Wpaf5bKm9XDf88/m3VUawRY\nXhRFBkXdt/ireVa+444f3DkJNLeWNrnf5Rb+Jl+7UtnpM3mFHff/ALtb8mjoyrJ5P3fmVWpfsdss\nPzowlVfnVaca3vBKjH3bFW1t0hUJDym7a+2pYbzduREV9u7azLU726R4SFF+b5nkb+L/AGarySQx\nzK7oyK3yr/FURfNLmlE5sV7uxctvOm/0bzlX5t3lqv3mrV01fNUefbbW3fMzP81Ztq3lsJkfJbc2\n3Z92r9jN5n75ZtjNL8jMn/oVFSUpXSOOKtys6HTVkgUpD8qK237/AMta+nxvbLvttvzSrv8ALrL0\nmFJiUuYfNaT5UaP5dv8AwGtfT40kmX/x7+Hb/vVxSly6ndGP2TXsFFvCj/u2C7tyt97/AHlrQ01t\npR5nYmT726s63tdzeTCmd3/jtaVsvmMz3Lsrt8v7uspcvNzo6I80tEadva2fmec7btrbtu/5v93/\nAHav6L/o/wDo007b/vfc2qy1kx2915n7mZWSZPm+b95WtpCpbeX9pdol/wCmjbtrVtGQ4y97lOw0\nu3hbbMm1fL+bb/drrdHheaOJ4XaIsu3/AHv9qsDw3JDHH5dz5bN8u35PmrqtJ02GG7S8S5kR1Tbt\n27lbdXfR9056kubU0LPfbyIN+9G+Ta3/AKFVqRXlEbw7tqxbVhqxp8MMzLCkLM33t397/Zq7DZv5\nbpGu3bXdTj75PNy7yMuxs5nj89OXb7rLW1JbyW8av5zB1dWZlqS10V4N1siSZZ1/3Vq02nvDbM9s\n6sPvN/tV1RjzTJlUjyhazXMLI+9ct83lsm5mWpJGQKs2+RkVGb9593c1VLiG5sWea8hm37F8qRX+\nVf8AeWqXijxFZ+D9DfW9T3TQr8kVrD96ST+FdtKUuX3i4xjFe9Io300PiDxNY+DLZFb7VKv21Y3/\nAHkcP8TLXssPirQfDeh2dh4Y3RnT7fylh2fKqq22vKfg3HC1jceNtQSa21q+lZZbeZdvl26/dVf7\ntZfjzx1Nb6hMIZm85t3leW+1fvfNXxOb1p46vyR2R5U8RzaxPQfG3xy/snbq32/y3+55LfMrf7Ve\nb618W3k1B7Z5md2lZkWF/vbf4q8p8SePL/XLy5ubzckH3olkfbXHeIPH1zZwt5w/ex/cVW/irmw+\nDlE45VJcp61qnxaubCNJtY1LzUt3byptjeZHu/u1ga98Wk1a3eaDUpo0k+aWFm+dq8dm+Kk11dPb\nTXm/zNu9W/8AQawNW16G4m+SZkG5v3m75lr1qNOUfd5bI4akoHVah4ufVtS+0pDIksjSRfM/+r/u\n1SbxNqumxqIUV5lXO6T+KuM1bxdCyuiQ/NHt+b+KRqqt4yubrY/nKzfdaP8A9lpyw/wyjua06nKd\nlF423OZriZWeSVju2fMv+zWxoPxceGNLB/JtkZVR/L+b+L/arzCbVkkj8m2THmff3fwtQstzZn99\ntb5fkZa4cRQv8R2wxFWGvMfQXhn4jQzRizs7mZ9srNKs38P91l/vLXUt4i1LUljsNSSO5Rf9U0fy\n7f8A7GvnTQdc1JZIe8n977zM1er+D9e1W8vd9zN8i/Mqs/3a8LGU1Rq8x9Jl9adaNrnUWcd5Z6hs\nSFhufci/wt/vNXf29qmmtDbQ/aJrSZF/eTN/e+8q/wDAqzfDtnYalbpNp9mybVX7Q038Tf3q76z8\nMPJpv2lIfMWPavlxpu8v/arz+alKNu57lPD1fsjl0tLd0Sym8pl2qi/xNXV6bHDpsKR208aHd/y2\nX5VXbWVb6ebXUPtNtbM0bJtWT733f9mtm38P2euaa/8AaUsj7X+dVbay7aKceX3DnxntYmto8MN9\nZ7LlMLvVrhlTau3/AGav2+lak1872c2E+Zoo2++tTeF9HhutWttH3tdPcWu+JVXcyqv3lavQrXwH\nptwtubaa4IjRlddu1dzf3q74YOdT3rng1sZKn/iPif8Abw+EPiHxJoo8T21tHcX2kp5vmNF89xH/\nAM893+z96vkCKJIZGhhDMVav12+JnwbTxJpFxol+i3iSRbdqxfvIY6/LH46fCPVfgP8AHTUfh1qU\nMkVneSteaIv96NvmZd1exgcVOpejNbEUcR7OWn2jJhmRVDzP8q/e21dX7NHIEfd/e+Ws2zZDcoiJ\n/e82tCGR5VH7lZW+75bLtauzm5vdPTjH7Q6az85hD+7Qx7flX723+9UX9n3MO3fZsfvbWX7rf7Va\nS/Y/O8mNNy7fvbajhjxMfOdvmib+DdtpRjqamLdaTummTf8AN/Gy1BJpqSKXeZizJtiVvuttrXuI\n5lmjd5tzf8td3y7qayJ9nHnQsrr/ABMn3f8AgNdTjzanHzRjzGJZ2LzTYmhZFX+Gt3RrG5hvPOub\nlWSP5ait1+0QOkM2/wAxvnkZq1dJt7mOZIYYJHC/L9z5Wr1cLGR42KlGO52XhtYVhjSHajNF83l/\neaugsVRo/tOxvlZW3N/erltLjkWFJkdldZfvbNtdDHvmgZGmVf7/AM+3d/tV3Roni1ZXuaVqttue\nd/LWXdv2yfxbq+zf+CeFstr8EtRjXOT4mmLAtnB+zW1fFsLbZIo5odzeV96P+7/eavtL/gnksS/B\nnVjCQVbxVOQwOc/6Nbc1+QePMr+H01/08p/mz4bjN3yOX+KJ8gxyQwt+7h8z5vvK+3a22rLq5jab\n7RGj+V91vmbd/vVWt4XhWV3mb94u7cu2noqW8Zd0kkGz5lb7y1+1xqe9yn1HII1y7aelrNN8q/Nu\n3/xVz+rXk1xC+yFW3PtT5/8A0KtPUN7Rq8P3dnzRr95qxtUkhmUwumHb5tyvWnMyeX3zh/Fy7MvM\n7Lt/75WvNfFEaMsj787tq16XryPN5qOmVZP3u5vmrhNX037TIba5h2eX8u3+L/Zq+c0jHlPPrjS3\nuJHSFGZ2fbT7PRXjjO+22bePlT+Kusj0F5rh0tvlaP5dzfLuq3F4YRbfy7ZGZ/42raMoD9nzHISa\nCjfc+bzP4qoyaImzYib/AJ/9Xs+b/er0WHwqbyNPM3RsqfdVKc3hdFVh5G5W+Vdy1fN9mInRnI8s\nbw6FuJQ8OJlT5/M/u1QutFmjUbH2ts/u16xN4JmWTyZU+Rv7ybf+BVnal4T89mh+xsqx/L9z71Cl\nOJlKly/EzzGDS3kUxucv/GzU+DTdrb9mdq7VVa7PUPBaQ5mtkyv/AI9WcunpbqqPCzsr/JtqalOX\nJKxdP3TGFr5a/cZjInyrJ91asx7y3lpy0f8AF/C1dVofwv8AEPia4P8AY9szuqbljVa5i40m80m4\nltr9GG2Xay7G3L83zVwSozkbxxUKfU6n4c+G7nxJrSaUnWZ12Rr/ABV9SfC3wzb+ArhLm82/ZY1/\n0qTfuVWX5q8N+A/iL4b6P4401IdVjNzNKqp5ibdrfxbq9u/ay8WWHhf4b3+j+HtS2315btB5ay/6\nvcv+srpw+H9n70viPMxuMq1Jcv2TxL4vftSLffES+OlaxHNDHcMnzN96uE8R+Nv+EyZtbtpo4rmN\ntyRr8y7VWvnnXrW68P6k/wBp1XzGk3b9r7q6nwXqV/Hb/abCbftXb96un7Rxcsj61+BP7cPi3w78\nPV+APjm8jn0KG6+1aHcXT7m0+RvvRru/hr3vwD8WEvLi0d3Z42RWZf4f96vzQ8Qa48jPvT5lr2D9\nnf8AaFjmVtH1K8kjuYV+dpJflbbXyHE2V/WIqrA/QOEM5hhZ/Vp/aO7/AOCkmh2eqeODr9gkhS4i\n3fc+VW218dXWk3kMhd/++q+rfjx8StN8faTBeX9zM8lv8rM3zbl/hWvGW0/StS3IlzGN33tq152U\nVJU8MoSR357h41sS5RZ51HHNC2//AMeqO+X+0J1to0Vtv3t38VdbrPhH7DIrwp97d/BVTT/Cv2pt\n7/8AfNetTlsfMqnKLtKIzSbPy7dESFVP8H+zTL2ea3Z/Jmwy108Oivb26o6bpF+Xc1V7XwbHf3yp\nJuU/3vvfNVc0OfmO32d4csTk7Hxh4k0ebFtqtwn/AEzjf71eofCn9qr4keC9QhvLCVtsfypJu2tt\n/iqnovwVsNe1BLN7lYVX73mP97/gVfXX7Mv/AATZ+Ffi77Bc+JtbkdLhd7rGm5Y938VcWKqYZ+7M\n9DA0c3pyvTfukf7Nv7bVtf8Aia2sPEmlTAtKzRbZf4v9mvtXwL8TtH8Uwx3lnYSWrrFu877yt/s1\nj+Hf+CVfgb4f6TFf+GNQW4SFfNWaa1Vm+at7w/8ACX+yLx9LtraSP7Pt3My/L/wGvk8yT5vcl7p9\nfgZ4utH98fPv/BTLxHDoP7O2v6i9oxW5Xy4N33Wb/Zr84/gb4HbVrlp3Tfu2uzV+xP7XH7M//C8P\ngve+Evs3ztFut9z/AHm+98tfAXwz/Zp8W/D+61Cw8Q2c0L2/ypu+Zm+apweNpYfATpqXvHz+bYap\nHHRlP4Tp/gL4DMOuW8Pkx5jdWeT5tq/8Cr628dfGyz+EHwtfVUeP7Z5SxWqwt92Zl2q23+7Xj/wn\n8NXvh/T/AO3tYh8mOP8AeSzN/Cq/+hV5x8RviNffE7xVNf3MjLZwt5VhDG+3zF/vMtdGU4D+0a/P\nL7JlVzCWHwvJDcow6hqV9qlzqWt37XdzeM0s8zfeaZvvNXR6DdH7QqPebn27kXZ92uf0nT4YZN6P\nJhX3fN822ul0WOHcrp8ixr93Z8zNX6hR5IQ5Yny802+Y7HS4YZFLvCoRvmf5fmZv9muv0e1ufOSb\nZujVNz7l+9/s1ymjqbhVSa5Zwv3I2T7v+1XbaPFcq2JrlSFTcnyfLurvp+9Ax5pfaOp8M26M293W\nKJvmRZG+Wum0uztr6FMIuxW3JIzVgeGVRn2JNl4/nbb96uz0mOa4jbekabtuzb97dW/wh7aXQkh0\nd4YxC7x5b/a/hrTs9OS3+e2eGSKaL7qr92p7SzeZo7nyViRfm2snzbquwwrC3nTeWFX5vlrcqVTs\nd18GYRB4VmjCkH7c2Se52JzXJ2+k21xsmS2hZv4V3/N/vV23wyhMOhTgqATeMSB/uJWBZ6a8jKju\noC/cb+LbX4b4ZO3iTxV/19oflWPi8kds8zD/ABQ/9uKjaTbSK6JCsZX/AFW75qy7zw6jM7zc/wAN\ndvHpqX1riGHcqvtVqhm0WBvMuXtlf97tSSv3qn7p7sqh5frHhuHafMTzUVflX+Kt79n/AEsWHjm6\nl5y+ktw/3uZI+v5Vta1oKbX/AHa/7Kr8tWvhhp0tp4olllUn/QHXce3zpxX5/wCLyv4ZZo/+nT/N\nHzmeSf8AZda/Y8g/aM0mS7+LerSo7KrfZg21fvfuI68q1TwzeNM3m7kG1nSSNdqr/vLX0J8bdIlv\nPG17JHGQWaIK5Xj/AFSVweoeGblpTsjV1+7/ALW6vW8PVbgHKWv+gWh/6agdOWTtltD/AAR/9JR4\n3q3hdId2xGxs+T/arJu/BSNcJsSN/LTf5kf8X/7Nexaj4VRl8kPsdvm+7WNdeF5odzxorBX2/L81\nfT1ox5TvjI8w/wCETMbHeisrfMslR/8ACPQrbtcwwrsb5Ub+7XpNzodtGsuyHYPvP/tNWe3huS3w\n/kxhZG/3lVq45R5jeMeX4TltJ0J44XdEjPmRfdkbb81dlofh/YsWyFSJP7v96m6XoafbN80LOPlb\ny/8AarrtF05FuEaabZt/5Z/w1nIcnzEWk+HvLVXe2Vwv/LNV+9XQ2nhl28l0T5vlZl3/APjtXdFt\nYZI3RH3D5n8tf+WbV0Gk6S91Mj4VIvlZo2/2qImcuaRkw+G3VQiIxLf3U+Wlk0L7PHlEYv8AMu1k\n/wDHq6+z0zbGnk8rH9xv7tE1mjb/ALTJ8rdG/vNU1P5gjL+Y42TTvLj2PDI25dvzfM27/wCJrPur\nX7K3lvIpVk2+Xt/irrdQ0+GO3Hzt5jNtSP8Ahb/gVZd1pULXjw+Srn5l8v8A2v8AZrCXvFRORuLP\nZHsm2xbm3btn3f8AarJ1C3SNWSGwZ3Vd3mV3V54fmZYnhRVX7rrv+ZayLzS0jvFhmTfG3zOyt91a\nmVQ1PzchmeZd8Pyvv/dLVq1Z4/3zvu2/8sWZtzVg2N5eWrO6fuv4otv3qvWM73zK7lQ6/Lurll/M\nfqEsRGVK7NdWv2CeWm1/4Vkb5WqT7bFAjbNxf+Jd+6oLNX+0faYJtzMuzc3zbakkgS3dP3Lbm+VJ\nNm2s48h59bEc0fdC4/fKZvlKr99t9cl4qvnVpLmGTbt+VFat7Urr7LIdnlyIvLSL/e/2q4/xBN5z\nM9z0ZW3Mv8NZykebzS5uY5PUjdTfcRdrf3qTTbN/tSwXKN9/b/tVKtvNJsm37h8vzf3a3dH02Hdv\ne2Vy38Lfw/8AAq5pS5R04+094k03S7aGRLa2hYqvzfN/FXQWOnyLIu9OG+ZN396jSdLmjlZ/mxs+\nfb96t6G3tpF+zSJtWRfvfxLShy+8PkM1o/JVk+zbt38SpUv2f7RGqPbM+35flfb/AN9VN86yLF8u\n3zfvN97/AGVqG4W5uI5neFW8tv8AV7d1X7P3dA9pJy1My8t4VYdg3zMtY2ofvFl2bmb+Ba2rrzGj\nPnJJbrGnyRtF92qF5JBHaNcom/b8vytVUuaPumcoxl5HLa3Im3Zs3bf4lrm9YidoWR3ZUX+Kug16\nZ9rb/m/idq568Z5i+zkbd21vu16FOPKcNaUInGatC7N/rmDfe+b+KqP2OZmSTZzs+fbW1qFuPtDb\n3wP7rfdqvt+6+/G3+KrlsefUjKRThtdp+eH71XFg8z9z1/v06Oz86ZeNzbvn21o2KJtMyfdV9rfJ\nUcyOqjRK8NrtX5E3V+w3/BeWHzf2RfDOGKlPiXZsp7A/2fqHX2r8lILaFnCJt2R/fZa/XL/gutC0\n/wCyT4bRWIH/AAsizLEen2C/r8Q8SJW8QeGX/wBPK35Uj5fP8PKOf5ZG28p/+2n5N22luvzhFJ37\nmarlvp9q0jfexs+XdWnZ2byzDyY/9xt/3qsLpoEe932Nu/ir9elU5o6yPvKeFlzRK9lb/vFKf8s0\n/wA7ql+ywvNG77nP3n8t/lX/AGakWzmaTZsVNv8AEv8AFVy3sHkbenlqv97+9XHKpKPwnpqhHm+E\nhjsYWO/95uj++slTQ2qRybPJ2u33lar8EJhWHZuc/dZtm7dVmO3hZYfOf5Zv4m+821q45Vp/aO2n\nhV8UinDYwrCzpD/wH/4qrkFjcs375PmVd21f7tX47XbJsf8Ah+ZFq5Y6fNMS72ywrt+8tTKt7p0R\nw/vFG3t0TKfLiP7+7+GrkOn+VMnkzea6/M6qtWGsYY5vJm+Z9jMm77vy1oaYqeTLM6Kkitsi3fer\nP20uW4VMPzaEun2Nssioj7maL522/MtX9N012kaGZF2t8u1v7q/+zUWti8apseNvkVf9pm/vVrWc\nbyqsKQxqy7vNZvvVnUrcsviD6tIS1s442WHyMhn+TdU66fNDI81zCyLJuaJamt7Xy1HnI3/Af4as\nMzrGn3nZV2rJWEqnve6bex5YxKE0ZVo5rZG3bdysr/eWqEweFghhVPvbtyVsXTQCBYYH2CP+6v8A\n31VbVLN47dZn3bfvLTjLmL5Z8hy19DNHM6Q+XvX5vlX+Gsa8he4kL3MPnNH8y7k+Vv8AdrrtW02G\n6V5kk3bl+Rl+Wuf1Cza4be+0f3V3Vp7pHLKJzVxbpIx+zQqjSf8AjtQXEaNsSZGzG7J9371bd1aw\nwyzfado2yq26P+7TGs7zy/nj3rv3ba29p7hlLsYcdnM0j/djRf4f73y0xY3aN0j+ZlTa7Vsx2sLQ\nvc+crfe3Rr91arxxIqtshVQ33maiMftGcqn2TEuo/NX5NqP93bVRobyRWR02Mvyr/tVs3lq8B+5/\ntfcqs1uklykw+ZmTbuVPu10xlb7J5lSXNLlZBa28zSeZcopP8TfdVlra0ezea437FRVRm+//AA1B\no8KSN5ezG3+HZu21sadYu0w3tuVUb7v8X+1WVSXLLREU48z1kWtJjkmn3vDg/d3V0djZwtueZ42S\nRflb5vmaqNvHbR43ozyL86qvzVtabHuZ4d8YXduRdlcfNzR5pHoUo2qWJI9Pfy0S2+Tdt37vl2r/\nABVfhs5o42hhdlRfu7vvM1WoY4fL/c/M7J80bJu8yrsenzTSeZ5OV+Vf3ifdrH2kpHZGMObQqWtr\nNLMty/D7Put/DW/pNilwod0z827dsqK309Jo1tn8t93/AH1W3pWkvcKh85l3S/6tv4a1j73KRKEo\nvc2tJt4ZG85OkPyfL/eb+9Xb6Pa7oUD7iV+X5q5jS7BLf99sZpvm+Vf/AEJa6vw5D5caQu8hRtu9\nv4vmr1sLHmgedWlKnI2rO1v4WbyYdp+95jJ91f7ta2n6b5kqCFJDui+8v3ZKn0u322rJs3K3y/vP\n4q3ND024t7ZLa52r5m1nb7q7f9mvTo05bHDKsZ9lpd55Zd9u3/lqq/dq5HpsUOOJJn+ZW/h27q3b\nPS0bfCvCK6/e/u1eh8NpNO6XKbt23yo1/wDQq6+X3iIVpS0OPutLSa2aG5dnWT5W/wBn/ZrjtT8M\nv4m8Yf2NZ6rCkdi6u9vN/E38P+7XrfirQ303w7fTb4UZV2xSSf8APRvlWubsfh7beBbe21XWE+z3\nn+qulkdW85t33vM+9trxM6xEcPQt/MVXxE5fuzE8eXUFrobM6Wtpc71RGh+8zfxf7v8AerwLWrq8\nj1q4ub+88x9vyMz/ACxr/druPi5Z39nqWp2E7xvNNLt3ebu/4Furze6tbm+WPR7C2Z5Gibd5n3Vb\ndXylBSlscUve9057xtY3k1mk9rDHsWJn/wBnd/erzfxhMY4Wmhud1zsXd6LXq/i5bzRdLh0S8ud6\nxtuVY4vmb5fu7q4C+8L3OuBM+dH5j7drJ8rf71dVGpGM/IKkZShynAQ6akl2u9FZ4X82WRn+61UN\nSv5Li+Wa2Tj7jt/E3+1XobfD25vLUQq6q7PtXc235v8Aa/2aydR0PStJjSz1W/tftbbvNkj/AOWf\n+zXrxlQlI4KlOUYHAeIrKG1kifzpJkZN26Ntu2s1Y3tYpX+0tvVt21mrqtet7G1kR9/mBvmdv4dv\n+zXLapqENxL+4SN/7jbvmWolKEjL3ojvO1Web5H3Rybdnz/NXQaPYa9JGdh80bvl3L/DXP6XqFhK\n2x5sS7921vl212ek606sjpCqQt/t1wYyo6cYnXh/3kviNLQ7waVMX/drc7du2RvlWu/8D65Msge5\n2vcNtXaqf+PVyVrJpWoYhhmt9330aT+9WhperTabfeTc6lCySN/yz/hr56vKNaUrn2eV2pSjzHu/\nhnxNNbRl7n7mz96v8O3+9Xtfwl8baVrmjtZ/uZRt3eY396vk2x8QOy/udVbayMvzf3a7L4b+OLzw\nzcJZW1+tonmr82/5W3V42I5afun29CrSjLl7n1VHoNnIq3MUKymPdt8t9q1Vk0fT9F1a2v4YWaGR\n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\naz7pU8mM7X2/N96qu4o2yaFUaP50+Stoc3NzM5JSIdLs5rMv5MaqJIv9W33Vatyz2W7hB8/yKjyL\n81Z1jb20kjzIiov3mrQ023SOZvnbzfuv/dZaxxEeY2w/vG3Cq28jTSbSzIqquzburV0+RFkVNke7\n+Dd/FWTaxPI/kzfKn3Yv7y/7VbUNn5yrv5RWVn3fKqtt/hrglzcvwndT+I17NZ71U2JlpHw/y/Lu\nrahhdW3vx/7Mv8VZdnvjQuXwV+5t+7urY0GSFt0f7t1b5UZv4aI8nNblO77HMX9PtYJJP3MPyt83\nmK3y7a6PTbWzkkF4ibdvyrtT5mrN03Tfs7L5ab0/jXZ91a6PR7JLVUTfIFV/3XzV2UaXVHPW92Ja\nt7d92PlEv8Lf3VrrPD6wrJG+/c3zfN93bWZpapN5vnozru/e7k2s1b+h2Mx2/Ou2OVt+5Pm2/wAN\nezhY8vunl4iUuXmOn8Oy+dIULx7f41+83+9XS2a7oWaZMLv2xLs3bq5bw/G7TPOgYf3m/wCBfdrr\ntNkTzVmhdtq/fj2169OPKeTKUueRs6fG8kPnbI1Vfvsv8Vb2nw23zI+4+d8sUm3ay1n6O1tdTI6I\ns6L8u1V+Vt1bem27Nb/I6sv3K6OX3R+SM3xR4ah8RTado+xti3Sz3EK/N5yr/ermfjZa3+pa5cTW\ntnbtbWsS+V/Cyt/Cteha9efYdPTfcwxG3tWdJPK3SRrXlfijVNS1TTQ+q20breXCrLJHuX5V/ir8\n/wCIakvrtvskU5SqTueL+PPDs2ta5NrFt8iq6rLGr/dbb96uUk8MvY3hvIbbZJN8ssiv/wCPV3Pi\n7T5m8QCz+2LDaLLubcu3dWb8QFe3LahYI0aeUsUX9xpP/Za8aM+SOhr7OftThPF1jc6gtnpsKZih\ni3PJt27m/i+aud1zQ9K0e4t7k7mTfuuI5n+VmX+Kuo8W/adP017mGbeNqq6/+hba881zVJo7eTzn\nVl/h8z5mpU6nu3O2nh5I4/x1rzw6s9yl4sy+b+68tvlVa4C4vr/Utaeab97t+8q/ear/AIuuLbdI\n8j7du7fH95a4u+8WJax/ZrN23KiszR/fr0qNSmoeZ5uIpykXvFN26zf6S8caTRKyrI/zVzWoM9xf\nKls+/wCT7qrWRea5c3Vw/nXLbF+ZFaks/ET2NuJEdd2/738VdVP3Y2OOpGL1H3Elyt4k29RLv2s3\n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\nalcr58aM1rIsvysrfw1tXV9tjHzr8qbnbfurKn7p6MqlKtHmjsXF1KZZt80zLtl+9u/8dp9xrXys\n8Lr8vy/3flrmdS1BJZkn+1Mm1N27+9WZN4k+b9y/8X72uuNQ8+UeY6uPXry1kZMr977392pV8QNM\nyTTTK3z/ACrv+WuKXXIVmMPnN+8XajN96o5PEH75XSFSkafxPtolUj8REY8p30fiSe1hP2l42Tfu\n/eVeXxs8Kq4WMiRPuq/ytXmDeJJpNvzsqUyPxI9uoTzl3q/3d9R7Y05Zn6yf8Em9TGrfs56zcCQt\nt8aXC89v9Dszj9a+B9H8beTdNM9y2yRlby9/ytX2z/wRY1Qav+y3r92Ccf8ACwLpcHt/oNjX5q2/\niq5mkVIbmMIr/N8vzfdr8O8OKnL4i8UP/p5Q/KqfNZHCTznHpd4/+3Hueh+MrCZk+TfEzfeZv9XX\nd+H/ABqlxH/obsis6q67fvf7tfPHh/WvL2PP5bsybkZf/ia9C8O+KHjaPfMyL99I1f7rV+zSxHNr\nE+tjRme42fiC8mkiSGbb83yQyfe2/wATV7f+xTqw1H4qakhJBTQpsAjG79/Bk/59a+UNH8RXM377\n7Ssj/e+b5dtfRX/BPjXm1j4x6gsu3ePC0zNsbIP+k23P61+f+Kle/h3mUf8Ap2/zR5XENCX9h15f\n3TQ/aW1qWz+OOuwWrZZDa71/7dYq4CTxNDHu2Px9123/ADbq0P2xfEq6f+0T4isFaNWK2nzP/wBe\nkJry7/hMPORoYbDadnzNXqcC17cD5Wv+oah/6aideS0JPKsO/wDp3D/0lHeTeKpoZkR7nO5N27+9\nVebxTNKodHUp8y7v9quEt/Ek0nlzXMaxHdudo/m+WrH9sTBm8mZkG/dt2/LX0csV757n1Xm942tU\n1aPbMjwsf4tq/wB7/ZrB1K4eRpnZ5F8ld3lr8zVFc6vczbZjtIb50b+FaytSvHkYv9sYfN80K/wr\n/eqPrEpbFyw8YwJLq6hWSF0/ii/1jN935qyZPEG5nTf937zN/FS6ldeZG+/ciM3yfxfLtrBvj5it\nNs8zavzbm2s1bU6hy1MPH4jqI/ElnHsmmf5tmzzP937tQyeKkvpmRJlO5G+ZWrhm15FkT5Nqxy7t\nqt/s/wB6q3/CSOq703A/xNvrU5+Q6q+8RQyRrDC+9vu/L/drHu9YhH+jIi+X5X977tc/Jr/mQtNZ\nzb/4Xb+Jqz5taRrdnRJP91komTGJr3GuQ/OPmX97u27v/QaWx1TbmMOzJJ92SuRvNSe5U+duVvvf\n7VX9Pu55o47n/VL91FZvmb/arkrR5jspnpvh3UEVo0d1U/Lsrr7a7hvpfO+0yMv3UWN9teYaLqDr\nan9997b/AKz7tdRpd8YlEOxkVVX95/C1YRlGPu8x0xo9kc82jzRsU2KfL/i3fe/4F/FQ0aW9w0Ec\nKu+z523fdraktXEYSZ/uvt8v+KkuLe5aN0hKl1+Wvj/ac3xH6DTo8xzjL5Mmy2Tdu+/uf5lqjeR+\nW7zJ8is/3V/iatm+tUjZtjMxZV21h3lx96WZ2LK+5I1rWNTmh7p6VPC+7ynP30iTM6TJurC1JYVk\n/fSeWK2dUjkViiXLKW+b5qxtUV5HM3zK6/Mi/wALV20Ze4dX9n+7pEx75tyJMj73/ikb7tYGorZ/\n6nzNjN/FWxdfaZptj9Gf7q1l6g3lr5L7Wbf/AA/xV6lHEfCedisrly8xkNvk8x5EZdrfeoad5t5+\nzbEVF/4E1KzOrK6Pv+821v7tJaxpJsdCu1k3N8396vQjWi4nyuKwM6ci/DCkkPz/ADN/s/NTJPm3\nwun+6tS6fD9nbYkyun8f+1VqSx+9JCjbV/2fu1jUqHnexnLRmTNb7VV/O53/AHV/iq5ounPtbZ8v\n+zsq3b6TGsiTI/8AwLZWppun21yrIjsZV+Z/k21Eqn9446lMS10ZFZX+V/8AarQsNFRpNltbKn95\ntn3qu6bofz+dcp5g3fKu/wC7W3pemvMqoibPnbav91ajmjJ2MVH97ZmbZ6HbLudH/g2rJ/dq+tk8\nlwkM24I23fItb1rodsrJ51suJPl2/wB5qszaaI9qQ2C+Ts+7WFSpD4T0qEpRMKTTv3Kwp++Zd2xW\n/irPuNJkW4L21sojV/3u7/2WutbS7mSMpDZqPk+9H95lqGTQ3SzV/sauqr8kay/Mtc1SXsz0qcub\nc5ebTzcSBHtpMM/3V+8u3+Kv0i/4LJRPL+zFoSJ/0Plru+XPH2K9r4Ei0l2tnT7NIiKu/wC5/DX6\nD/8ABXi3Fz+zRo8bj5R42ti3Pb7HeV+O8fN/69cOr/p5V/KmfE8TP/jJ8of9+p+UD8wri1SaPzk2\n7mf71VJGeSNJvu7vvr93bXQ3FikkLv8AZvk/hb+KsS40+b+5G0rJu8tX+981fq/N7vKfon94jh2L\nIUnm2uybt33mWprVvOZYX27WXcjfd3NR9j3QoPseyRf4l/2qnjtfJ2B33yt9yl7kSIykWLOG5kki\nQlVXZu+X+GtCOGeNVtnRdi/MzKn8VNs7F2dH+X5v73y1sR6e7R7Ehbdv+Rt/3V/vVySqHoU7/EVF\nsUmj37Knj8u4ZLN3jC7vnkb+GlaDeG2fK/3dy/db/eq1a2SbkuYUYRs33ZF+9Vx5ZqJ0U5E1hH+7\naaFFJ+75bfKu2tOzX7G7XNnDu+8v7tN21v7tLpVrDIoeFmVW/hkStmysYVkSZI1T5/nb+7RzTOqN\nT2exlWMf775LZVK/Nu3bq0mt3XaIXZzIn+sVflVv4lqSa0RdSdERvl2v+7T+Gsn42eOE+G/w/m1L\nw87TanM+2BVX91br/Ezf7VerhcPVxE42OPNM0oZbhuecve/lO50HwTc3kafb7y3sUk+ZZLqXY23b\n/drQX4YPcWcsOieM9Lu7mNN1vbyS7V/2a+I4fjd4z1LXpb+8166eS42rceZLubav8NdHoPxy8VWt\n8l1Z6xIkkb7tqy/3a+hp4GnT+yfmmP4lzDFVeaEuWJ7P8ZvFXxa+GsLWeveDNPjtvveZprM25v8A\neb+KvK7r4qX9xaLqVr4hVfLb59sv3f8AZrtbj4xR/ErwDfeG/GD73uNrW7RvukVv/sq+UvHl3qvg\nfxQyW1y0aR+Ystqv3WWuuNGHSJ4ssXiqkrzqSPW9Q/aK8W6bqGy28Tyf99feqCH9p7xOzDztY/d7\n9yxt96vK9S1Dw9Haw39s/mpNEsqNJ95W/iWsG68WWbzOn2aPbv27t1V7Kl/KNYnFR+1I+iof2ltY\nhjDpqv3l2vGz/wDj1TWv7TF/cMES/wDmV/mXd97/AGa+arXxPpskmx93+z8/3asf8JBpsS7/ALTJ\nu30vq2Hlq4h9axUvtH0lqX7QmvSRj7Hfxodu3av8X+01SQ/tD+IXhihS9YfL8zbvm3f3q+arjxVD\n5izf2kzfLjb/AHaLXxw67kubyN03/LT9hS6RF7fERj8Z9Pt+0Jqs0mybWJGCwfIrfNtarJ+P1/NI\nHe8jl3fMm7/2avmqHxk7fxqf+BUjeMr9Ts+0fLUfVYbqIfWcR/PI+mbP9oaaF2S51Td5n/LOP7rV\nctfj99oZEsPFDRMqbfvbvmr5Sm8ZXjP532ln/h/3aj/4TKGFWT7Sq/P91UpfV6UteUft8UvtyPq7\nUPjd4k2ult4kWaWRNvzNt3f7VRr8atb09fO1LUpopZPvtHdfw/7NfKb/ABE2t89421fl+X5dtVpv\ni1Mq+Sl5uDJ/eq1QhHXlJjVxEftH2ho/x68PXCtDN42a2+RVRrp/mVv7u6vWPCNxomvWsN/puvWt\n/uXa0kM/mf7tfl9fePvtaq/nMGV/4m/irpvhb8UvH+k6oieGvEN1bSL/ABQysqr/ALW2tOVx2MZK\nVTWUj9OdY17RNJt4o0v/AN6qbUt933m/urVXxN8ZvAHwRsY9Y1V7fU9cmiZLfTWTdFD/AHd3+1Xx\n3b/tCeJ7jybzUtea5uLODZA395v4mqlJ42vPGniJZtQvGY/ebc+6oi5SkZ+z5Y/EfXXwz8feKvi1\n4i/tjxa63Vs0TbLNfljj/iXbWf8AthftMW3wy+Ft5Nomtt9qaz8u1VU+Xd9373+zXGeA/F0OleEE\nvLC/kj+Vf9n5q+U/24Pi5f8AjbxYuiO8aw2q7PJj/wDQq1lHl+EVJ+0lzHguqXOq+J76bXtVvJJr\nm6laW4mk+ZmZq9S/ZB/Yq+Nv7ZHxd0/4PfB3wfd6rqd9cRpm3t9yW8bN80kn91Vrnfhz4J1fx54i\n03wf4V0Rr+7vp47eC3VP9czN92v6Tv2Tv2UPhv8A8EHf+CTPjX9rvxpplo3xHHg2S7uLxk+ZLiZd\nttap/tbmXd9K3hDlpc89iqtZyqqjDf8AI+eP+Cbf/BM34G+FP2uH/ZQ+Gc0epRfC2KPU/jN4ybb5\nmpap8rQ6fC38Mat97b/dr9TvFkOm3X2lEmWEw/dZW/ir4V/4Np9Jmh/ZC1/43ePXkbxN8R9fuNZ1\na/umy0ytM235v7tfYHxO8QWdu815C63EMiN5U0fzL/tV+ScUY36zjJJfZP0jh/BPDUby7Hnvxks9\nM/sVn1hLO6Zlbesn/oVfBP7UHwftdS1BvE/h5JB9q3RS2sbKyQr/ALK17f8AGT406lealeaPYX8b\nReftdm+8qr93bXi3in4gabrFqNKv7+ODa7eVJu2szV83hZyluz244WPtOZ7nx74m+EOvaLdXmt67\nc3SIsu6Ly02/d/hqDxZYzeMP2c9J02885v7N8cqqXFxFt/cyR/N92vXfi74y02x0v7Near/aUkm5\nXVU/1Mi/xMv/ALNXmln42k174a63Z39hGiafe297Esbf3fl+7XoVKledLnifQ5RUjRxCjM6j4Pto\nmqfETWPDz2e19P8AD0n9msvzKsnl/K1fFfje6vL24lvNRud9y0snmzM/3vm+7X2V8H9Pv5Ne8QeO\nfDd+zyafo0k6Qq67pNy/d2/xV8K+M/Ek0t9MmxURpZG8v+JW3fMtXktOdavORhxBKMaFhtjqGkaV\nPHYWv72e6l2eY38NaPiSxm0S18t9xX+LP97+7WN4DstOvvGli+pHdEz/APAdy/drqPitIlvbh4UX\nZ5u3dX0eIXLiIU+5+fzXNGTZkaHvvLV3RFjX+FWrR0hbyxh+1Oknlt/Duqr4NhdrVH+XbI/8VdLd\nWaSQ7/OVAv3F20qnNzSMpa0lpqVtO8SPYzM/8LfL9/5q2rHxdcx7NkzMu3buk/hWuT1CHzLgpvZV\nba25a29Nh3fPHu/vL/s151aMfiN8HVnGro9DvvDN99qQ+Tu2zfP81dFD4evLmHf5LLt+ZYY/l/76\nrkvBfytvfazK6sm6vffhvpdh4iuI5oHXarrshX/2avDxlT2crn0cf31I8x8M/C258UeIBZwurI25\nl/3v9mrvir4RXnh/xFb6DcuzRx/vZ5PvbV/2dte/t4J0rwIw8Sv5cL27s0UMaf3qX4e6Doniz4jN\nM9zClysu1Ly6+6sf96vOjinKfN9k4Hg579T578O/B/Uvjd8UofhLYaxNoNrfQL5F5fN5G5m+6zf7\nNenfH7/gkh/wzR8N4/GvirVZIdfjutthq1qn2mz8to/9Zubdu+Zvu19lW/7E9n8Xlh8Q6E9qNWt4\nt1rNcNuiZl+7838NewT/ALEvx98SeEY/B/xD1hmsIYty+XqLMkbbflWGvosvzWWH5Y04/M5q2X0c\nXHlqaSP5y9Q8GXPhHXrzRJLSR5rOVknaSBk/ef3trf3q6HR7qaOxH2l2+Vdv+7X6rftcf8E1fDHh\neexhT+0Ne1vXtes7Nbi+2tL5zSfN93+FY64T/goh/wAE2fhp8F9L1Cz+Frxvc6bZ26xbdrvIzLuk\nr1q+aYbEfxGcn9lYmhP2cD4p+CL/ABEXWJLz4faVNeSSRNE/lp83lt/DX2Z+z78UPjf8F/B8viq7\n0G4tbqa1aDTbeSXb+8Zdu5t392pv+CLngfwHF42lsPiLpX2lJLzyGjk+X7OzL95q+vv+CwP7Ptj8\nNvhv4L+JHw30/dolvNJYa21v923aT5o5pP8AZb7teTGEMXjuQ+gp0a+X4aM+b4j4GtofsKzfb7zz\nrm4lknvbhn3NJMzbmZqT7QlwzIibl+6rMn3m/vVJ8kO/Y6iKZ/8AWKv3v9qq6x7ZDH8zlk/5Z19a\n6cYQ5TzoytPmGpJM237zOq7WXZVyz+0+W0NtZs6R/wAKpSraQyKltO+5vK2/d+bdVu3s59pG9drf\nK8jN97/drkj70fM3lzEmi/vpFme5jVW+Z12/Mv8As12Glr88ImKnc7M21q57QNH8mZpHhhdNzfMr\n/e/3q6zT7cf8uyLv2bZfL/8AZa9DDx9nozz63vF/TYUmupU+XYyfe/iq+s3k27w/MHX5VVUVd397\ndTLNfJtfORI9rNtXbUL33l25e5hkcM+3y12/u69WjzchleMd5FDVtkyp5IaNlbc/y/eWsa6vJmke\n2mCpu2tE0O1l/wCBVs6sqTK3kzeV/tbfvVg3lvthlufO+6/zfJ96u+jGMfiMZe7rEoveeZJLDDNG\nG+7t219of8E0iG+BerkKoH/CXT42nOf9Ftea+K/9VH5LwsVk+bzG+61faP8AwTMmkm+BWss+P+Rw\nuAGUYBH2W15r8f8ApBxivDWpb/n7T/NnwPHavkLl/eifAV5NNHG3k227c+1m3/Mtc1rVwjb3fc6r\n/tbdzVs6tqk32czPuwqsrqq/NXEXl4djzImNz/e/vV+6SjzR909+U+aVxlxeXKqkP2najbmf/Z/2\na1NHuoLVTf3/ANyNdzSL/wCg1z8KxXTsltCwDJu8z/a3VzPxS+IVhar/AGJpU3y27t9ok3/Kzf3q\n5q38py1cR7pmfFjx1Y315c6lDNsaT5tq/Mq/7teCeMvFH268dN9bHjzxeLibYj5+TbXBXEk15e7E\nRW3N96l/diefy8paj1V413+cyqv92pofOkb+LDLu/vVc8P8AhO8u1+SHesj7a6ZvBc2nxp50O3bt\n+WtOUXNA5OOH7u98/J8lVb6Z1kbftRfu/N/FW/rS21qzQJ9/723Z92sHUlSb/WIrbfvbqiRcfiMe\n63yMewb+Kqyq/wBzYuavtDu83YNu6q3k4VPk27vvNupf4S/hI/Oz8nzf3vlq9otw8c3yN8q/NVWb\n5Y+P92kt2cfOgzt/9Cp/CSereCbybVo0hfDO3y/M+2u503wel5GyHl/9r+GvJPBWsfY7qKZ35XbX\ntfhTUkuLVZoX3LIu3cvzbacZGdSPNEyL7RXsmS1fa/z/AMP8NLbaPc7g8yfuvm27q2JF866bfCyr\nHK25tn3mqaO1tmZdiMu3/wAep/DqYxlymZplv5V1/qd43/drpbFX8lUTakX95az1strKmzKq38P8\nVXlk+x27b/8AdpKPKVL3veRx/jS8TTb59ifLJLuZmrzX4kaDN9li1vTZPnXcz7a7v4sRvb2sMyXL\nON+9q5bS9WTVreSw3qwb+GRPurRy8sjSMpSgUPA/iZNYsfJe6/0mNPutXTLG8iun3vk3Mq15Lqwv\nPA/ixxCjIN+7b/s16l4T1KHXLNNSR/u/eXbS/uhJfaFkh3TqU+Tan3mqDKLIP/Qa1ry3i2siI336\nz544wqo83z/3qqMgKlrq1z4H8Wad4q0ybyvJuFZ5q/Sn9mn4oab8VvBdlqSPHLLJArSt5q/eX+Gv\nzmuNLstWsX012Ufum2/xbmr2j/gnN8VLnwb8Sovhd4kvPs9teXGy3Zv+ejfd/wC+q66MvcPKxmH5\nvhP02+FOtal4X1xLx0VYfNXzWb+7/dr3zXPDfg/x9/Z1zf39uU+0KrtH80ir/d/8dryHw14Zm/sd\nbCZ/up8qt/DWV8dtY8f/AAN/ZX+JXxss7a6m/wCEd8K3TWe1W2/aJF8mH7v93duoqYfT3Tz6FRyn\nyTPyp+M37b3xI1b9tjx58afg/wDE7WvC8reIJrHRLjQ71oJIbOH9zH83/Ad3/Aq5Pxp4s8UfGLxR\nN48+K/i3UvE+tXSf6RrWuXjT3LKv3V3N/wCg14JZT3Ns63LXOX+/LI33mZvmavQ/A3idLyGO2mmV\nj92uOUXGdz6ZQXJaJ9N/8E/PiV/wpX9obw9rGgpDCk16qXTSfe2/w/8Aj1frL/wdNW+j/GH/AIJD\n/D79oTTXjebQfGml3EUy/wAPnRtHIv8A30q1+IfhXUHsdYtNRtrlUkt5VdZG+8u2v10+L3xPsf2p\n/wDg3L+Jfwu1a/j1DW/COlx6rbbfmb9zMsm7/vndTjKUKyZjGUbuB+O3he8TWtDS5hdX2xfPtfbT\nI5p7Kb9yjPufbtriPg54qVLiOzf5RsX5ZPu/NX0B8Nv2dfH/AMZtSjs/h14em1K5uv8AVWtnFvk+\n7Wcq0aceacjaVOXwxOPkmS6s/OtWj3r/ALf3a6nwD40TWrX+ybm5XzYW+Rv4pP8AZrk7zw7qvhXV\nrnQfENhcWlzbyyRSw3UTJIsi/e3LXNDWn8M+LE83cscjrtb/AGqhcko80S8PUnGfL9k9j1byZo1m\nSPd87fLu+7XPXyu0nnb43Xfu2/xVv6LGmuaSmq2w+ZkZm8vb8rVRuNHh85YYZGZPmaVtn8X96iVT\nl909D2MZe8YpmkMzPD5gX+DzG3VB5k0f7kfMGfc7M1aD6GI90ybnVfmRqr3Wk+WrzO/kvs+f/arK\nUhxo9yk1w6yfPuIX+LdUFxdPcb9iKNv/AI7VxtPd13ojN8+35qjh0SZbg7EbY3zbttYS54x5jaNP\nmkfqp/wQqkmk/ZG8QmfGR8RbsLj0+wWFfmLpsyLHDC6M3z/Oy/er9Qf+CHUQh/ZP8QoI9v8AxcS7\nz7/6BYc1+YVna3K3Cwof9p1b+7X4b4fyl/r/AMTW/wCflH8qp87w7CLz7MV/eh/7cdNp948q7E3A\nf3f4ttdRpWsfu4Xhdk2/61f4q43S4Jvs67I/mb/b27a6jQ/3y/aYUZo/72za3y1+s1K3sdT7+nhY\nyO60rXt1xuM0m/7u5k+avqb/AIJm3Ukvx31a38uRUj8IT7S3Q/6Va18gW104khm875Y1219W/wDB\nLAEfHfWNtwXQ+EbhgT3zdWhzX514mYqUuBswj3pv80eZxVgvZ8MYqXaP6oy/2472RP2pfFEaKvyG\nyw7HO3/QbftXlT6kluDNZzSSfw/3fmr0f9ueZIf2tPFgk5DfYcH+7/oFvXl+nxpM0UzvudUZm3L8\ntelwbjeTg/LY9sPR/wDTcTu4ewEqmQYSf/Tun/6SjSjmRlSZEZpF+Z1WXbSW907TPNbeYE+7K396\nnWtnDtSaHksu1t33lqWTT5pMOhYPH/Cv8S/7Ve/LHe8e8sv9wb9q3bEd9qyNt/2aJle6XZc3G1o0\nbcv3dq/3qWa1nNxLbJtRNu7/AGf/ANqo5oXWZPJT/lky7pF+b/drejWlU+0ZVMPGMNinfW8xj+0u\n+359zqvzblrndStnaF5poY8yIyoqpXVzWbwwuYXwVfcyr/C1Z11psNxCZnRvv/vf4flr0cNU5Y+9\nI8qtR5tDhNQ3x7US2jVtn3ZE+WsfUA9rdecNyBmVvl/h/wB2uy1TQ7a7kdE8zbu3fN92qD6KkLpv\nh3K339vzLXqxqR+I86ph/wCY5G6VJLVZoU+7PtSRW27qqTRfvmdN2W++yvXU3XhqGONjN8j7vl3f\nxNVC8sX09fOhm3Oqqm5k3bv9qtObmMfq8uf3TBhsEhVURN/mfL81aViqRKEeFVdfk3bvu09tPfzn\nffnc+3btqexscqtsifJ95GZN1c1bY6KdHlnyl21uiu1Hh3bfvxtu3bt1dRo95Csezflty/vJHrlr\nWF41Kedh/l3bn+7/AMCrY064f5LZ33sqfumb7v8As15sj0Y05RV2dbcQ7XFz5K71fcm5apXdz+8V\n327/AOJdldDeae6xl5o1dv4dqfdWsjUtOhWP7ZM6om372z+Kvj/tH6RRpycfdOauP31uru8ZK/xN\n8q1z2rfvJWmR8Kr7pV8r5m/3Wrqtajs1bZDDkN822T+KsTVI7maPe6NuVNywq3y10U/dPZwuF5jj\n76/CjYk2Xj+ZFWKse+3szbNqs3+3XQatZ/u3SHcm5Pnbd92svUI4ZFZLlIyyqqtIv3q2p1PZ+6fQ\nYfL+b4jltStZmmV0dWeP7i1l6lA+4QzOqMy/d/irptRWzhX7T5rbN+5I1Tcq1g30cGfJ8lmdm/1m\nz7td1GtzCxWWx5TFmsXWMpvVXV9qbqiht5pG+zOm5ldfm2VfkCQjZv8Alj+b+826n2tiI1OyNsr/\nABN/FXrU63LD3j4TNsv5eYfp9nut1+T5t/8Aq99a1vo9xcRjyRu2/L5cn8VR6fboscXnJuf7396t\ny3XzZE37QWRl+X+7/eo9pLm0PjMRR9nAq2eltJsdIdqRuy7f4lrY02zn8iTa6j51+XZVi3t3ZTC/\nzRL83mL/ABLWnpq+dhIXZ4VXc7eVtrH+9I8mty9QsdNhmkWF3Xztv+7urd0/S3mh+SGRH2bW3fwt\nS2unQzLHNDYec8e3/Wbd3+0tdD4dsYVkUiFl3bt25Pu1PtJfEc9OPtJe8VYdPMkkaeSpZfvN92tB\nrVIoG32ap8+7du+9/srWlb2aW6uiQRyNJ8sXmPUk1mjN8+13Vm2/L8q1yyqe9zHfRpxjqjnG02ZS\nNm1ZP+WrbvmX+78tL9l/dmwmjV5Nu75f4V/iram0m5mVZkTcfK/v7W+9SR6S6zY8jYqurM33lVf9\nqolL2kbSOmj2MD7H9nZLmHps+ZVr72/4KxQmb9nLR1EQfHjO3OCcY/0S75r4ijtUZndJlWNnb5V+\nbd/tV9z/APBUqNZv2ftHhaQLu8Y24GTjJ+yXfft9a/HePH/xnXD3/Xyr+VM+R4mvLiXKLfz1P/bD\n83bzTXlaS8mfIZtvzfd+X/ZrOmsfmX7NtKL/ALFdndaK/wBoVEEe7+JWf5Vqh/ZdmsLQ+TudpWVZ\n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\nInzM1W21WwsbO4vLn5fLt9qKvyq3/Aq8w0vSX1bWLnVYXjXazN8vyrJX1+Q4Hm/fSPheKc0i/wDZ\nIfM7b9pXw74G+N/w1vNK0rQY4tRtZd1vNJa7XZlX+8tfHfw5vLybw7qvwK8To1tex7p9IaSL958v\n8NfW+i+JrbQ9WiS5jmeVtu6ORvu15l+118M3+1Wnxj8DWarqOmy+fcLCvyzKv3t1fUfFSPhIynFH\nj/wz1a28UaXceA9S+ZpFZbeRk+bzF/vVx/ijRb/wrrk0PQx/I25vu1f8SahbaH4oi8Z6I/7u6VX2\nx/Ltb+Ja2/iFqlh46t7fxClgsRVF3f7TVnGXKXGPL8JyEfktZrv+Xb83zNurlPEVxC6vC/zVv6he\nJCXtvm3f3v4a43XriG4kfzudtUXGJi30O5ZE3/LVPzPl/d7WFXLry1Yon9/+/VGNf3jQIm3+9VfE\naxEaHd8+/wCX7zK1Q3C/3z/3yKvTW7rGE+Zw38NVLpf+mfzLUlFCTezvsP3ajkbc1S3R3NsCc1B8\n4Ul/4aBx3DMm3p8rVKqzbtny/dqEtkLn1qRJPm96BDmZV+QBc7fvVF5zt8mKbIu1qWNfmGXoHysX\n7w+SmDeuAHxuqYbIz89FspmnRMc/+y0RCO5YaX7PZ70++3ypt/u0trlvn2VBdMjXB2fN/dqS3j8x\nv9dtZv7tHxEyOq8Mr5brNDtU16t4XuL+a3/1yqipXlPh9fsixzTOrbf/AB6u6s/E0zWaWdlbbP8A\ngdae7GJhKPMVfi1qW6xKTTK7L9ytz9gf4W3Pxk/aM8K+CbZP32reI7WCJW+Zf9Yvy15f8RNTmkvN\nk024/wAK19rf8G/XgP8A4S7/AIKAfD55oVMVrqn2h2/3V3VphY/vEY4uXs8Mz+sj4WeFbDwP4E0j\nwhplv5UGmadDbRqv+yqrX4Sf8HqVjMPih8ANV2KYvsGqQfe2nc0kdfvbpF5i1V33D5f4q/FP/g8x\n+Hk/ib9n34WfFy2i3R+GvFc1reSKu4Itwvy5b/gNY14Tlzm+CrUqcYIw/wDgl348ttM+COkPDM26\nG1j/AHKy/e+X71fT3jL9qq6ure4s3RbhI7fZ5Myfd3V+Zv8AwTl+Lj6f8EdLtdiuY4tr3S/L8v8A\ndr13W/jVNdXDJc3LLFv2ttX5mWvxLF04xxs4n7Xgqt8PCoe/ahr3wi8QWtz9vtmiuWib5VRWS3+b\n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\n9N1C28GfErVo9S06+02JVRbiT7y/N8v3vvV+qXirxXbXnhOx+K2iSKj6d804+9+7b+Fq9PHUlOpG\nrH7R5GEqyjTlSn9iX/kuzP5Qv+C1n/BOfXP2A/23vE3w1ttOZPDmsyNqvg+4VfkktZG3eXu/vRt8\ntfGv2e50+TZMm5vu/d+7X9Wf/BfT9hDwp/wUR/Ybv/iz8PbeK58ZfD+yk1TSGgX95NCq7poP++dz\nV/Lfq1r5LPDfw8M23d/ErVzV4qpFVV1+L1PQwdd0p+ylt9nzR13wrmfUrV9N+953y1z3izRZoby6\ns5k+aN90W771a/wniSx1NEj4j3Ku6ui+Lnh/+z76LW9N2sky7ZV/hrk5uY7ZcvOeR+GdUm8N+IIk\ndvkZv71fUPw71i11nRdn2zLNF91fu180+MtBSzkF/Cm0bNyf3a9I/Z78aIzCwuXjH8KM1RKMoy5i\nuWNQ9Q1SxRVd97KP738Ve7/sz+Mv+Eg0v+x7y5b7Xa/Kir95q8W1S3SVH/iT+Jo60PhF4u/4Qvxl\nb38160NtHL+9/wCudRiKftKWprg60qFWNj7EtdNmt137VVN/97/x5quQ2O7ykvbmFlk/ij+VttX/\nAA2tnqmlw3lo/mJdIrq3+9V+axf7U/nQx/KrbGb+GvGj9qJ9pDljCMjGaxDTTXKczN8qbX/9lpbf\nS5mk/fWyu0nzPt+Xy/7tbdhb3KyJvtv3Tf61vl3M3+zU8en+X5v2Z9rLu3Mybl/3q6qceUqUYS95\nH0h+wxAbf4R38ZQqf+EglJUnJB+z29fIN5oNwjM6JtdX3O0afdr7J/YyhWL4YX7KuBJr8rAjoQYI\nOR7V8r3FmizLM6MTG3ybXr8Z8OU34h8UNf8APyj+VU+L4bgp8RZpfbmh/wC3nDa9o8Nu2y2H3vm2\n1yOrWdtNcP5zqpX+7Xo3iKPy1dLb7q/P/u7q4PXF/guUj3790qr95q/XcRE/QcLTcZabGVMuza6J\n8y/L/s7a+jP+CZHnf8L/ANYE0W1h4QuARtxx9qtMV85ySbbfZZuyxq33pG+Za+h/+CXsjS/HvWSz\n7iPCEw3Z6n7Va5r8t8ToyXAuP/69v80cHGMZLhXFv+4/zRzP7dl1IP2qfFcSkfK1iEAbksbC3ryS\n3vHVZZnm+825PLb5l2/3q9L/AG/LlIf2s/FZCZ+awBHv9gt8NXksdxZxr5c0yp8zN8v3qjhRW4Oy\n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\nS+L4jDlG+Y/ll361JCvmIvdv7tJHC8iZ+9/srWrpWjvcMNkLZq/iHIhsdO3Irl2bdW1p+ks0m9E3\nLtrc0Xwe6w+c8G5f9qtVtNTTVbzEXP8AdrXl5Y8pj8UuY5y4s3tVLhG3NWbOu6TeB92tfWrpGVnh\nbDKn3awJpZpJGfeu2spSKjHmIbiaRmGxGb/aals1dWZHT/aZqRpP3a7wxanQ27sdjvvXZuo+Ef2D\nT09ftLKm9VVf7yVsNp8zWu+H5i336xdPuNs+zy/k/jauks5LYQ7N+0NVcxMtjM+xzQsPMTa6t/31\nWnpLOtyPu/K/zrS3SQ8eTz8+1/n+7TY5Idy+T8prOPvByx6noul6Ho+raemybaVTb8teP/GDT30f\nxMLZ3Zfl/wB6u50e4eO2ZLN2Vl3K/wA+5WrhfjJNcTX1tNO6lvK2s1IcY++Zfhi58y62TP8Ax7q9\n48EzbvD4j8xWC7flr500G7eG6D/Ka91+G139q8OzP8w8lNzsv3qv4Qlz7GP8WtQdtLebqjbv+AtX\nicm+SYu235q9M+MmpbbYW3n8Nu+X+9XmKcMKZdOPLG50Xg9Q1xGm/Zu+81fQ3wzkeTR1hhTPyfNt\nr5/8HxvJNG6fd3/xV9DfDe3hj099o+Tyvl/2qOb7JjL4x/jC8hkjPySAxrs2t/FXh3xC8MvcNLqV\ntbNlWr2PxNHc6hMz3KSD59u5qyW8KvfL9mezZ/4lk2U48hl73PzFj9nHXJNQ8Oy6U94vmW+1ljb+\n7XdalYbo3uUfJ/iVU+7Xk/gWN/APxOht5nYQ3j7fMb7qtXs7XLhdm/8Aj2/N/EtT8PumkuWXvHE6\nhBNDcOjvvRk+X/Zr1b9kP9pTxh+zP8TLDx54buZIfs9wrXEMb/6yPd8y15xr1ikNzI6bZEkZmf8A\n6Z/7NVrVfLuBJvw33drf3aenJymHvn9KPjT4ffC3/gsv+whpXiLwzqwi8TaZa/atB1VWXzIbtV+6\n237u5l21k/sy/tXeNtK/Zz174b/GnQb5/FXhu1m0PxHpcNr+8VlXbFcbf9pa/Mf/AIIH/wDBTC5/\nZL/aJi+AnxJ1jZ4Q8ST7YJppf+POZv8A2Wv2/wD2hPgH4Z8S3kf7QPw/vFtLqWCP+3JLOHf/AGlY\nt947f4m2/dau/AV4zthqz93oebjaFWCeIpfF9r07nj3/AAT6+M9h4p8QXnw38QXRNtrunGH7K7bl\nZtrL/F/s1/Mx+1F8O9E0X9oz4n+DNHRWttB8f6pa2rR/d8tbhtqrX78ePYdU/Y2+OFl8Wr63Ww0G\naK8vfDrTP+8S1WFtu7/ar+enXvGV54k+MnifxDqVy0jeINcvLyVmTb80kzN/7NVY2MsPUf8ALIrL\n6kK1OPN8UbnLeDVudF1ZVmTdCsvz/wALba9Z8SaTba94JuHSFi7IrRMvzV5+1mlvqT+cjMG/4E1e\nmeD7h7zR4tMd12Mm3a38NcEfiPRqS908VmtodW06awuUZXj3LuauY8GapL4T8VGGZ8bZfl3V3HjD\nT30HxhP8i+XcPtRV/u/3a4X4gaV9g1BdXtk+Tf8AO392iXve6aUZS5uY+nfDt6niDw9HeO+Fbb8q\n/wDoVVNQheO4kmh/hX+H+7XD/AXxg+oaWtg82/8A2Wbb8td9rET2q7ETe237yvUc3u2CpHllzH1l\n+xv8Un8ZeCW8PXlzun019nl/eZo9vy17D5bsXTy/mb7vnV8Qfsv+PH+HvxSs7y8m8uyuv3V02/7u\n77u6vuqUpcTeYk0ctvIi/vI1+WT+7XDWjyysfVZTW9pQ5ZDtLhmbzQiZXZU9sl4ykwp8y/L/ALy1\nZsYYVj2bNif3d9WLXTUjXfCjK+/am2iK5j1PaS92J9B/sgqE+Gt8BHtH9uS8fSGEf0r5cvLV1kkS\na23ivqj9k4Mvw7vlYjjW5AABjA8mHivmq6s/3b7522t83mV+NeG0L+IvFDXSpQ/KqfGcNTkuJM0U\nesof+3nDeIls45PtOGzIv3lrznxFdQ2twYbZGLt8yNJXpPiaBFZHhSQJCjbI5F+Xd/vV5nrVjNCT\n/q3Te235vm3f71fsGIjDlP0nC+8c5Os1vcbIX3jd88i/+g19H/8ABLKdD+0VrUEa/KfBty4b63dp\nXzXdW9tumR7mZEVd0qq//s1fQv8AwScuHP7R2tWxOVHgm4ZW3Z/5fLOvyjxQafA2YJf8+3+aPJ4x\njfhLFv8AuP8ANHOf8FA5gv7W3i6N2bH+gEY7f6BbV4vDeFZmEL/OyfxJu3V6r/wUUuriP9sTxdFG\nBtb+zwxZuP8AkH21eGyakJpvO+bbGzKrL8qtWnB8ebg3L/8ArxR/9NxO3hp8vD2C/wCvVP8A9IRt\nxyJHqGd6/Nub5auR6xD5mxJJGZfmT+H/AHWrkLjXHhX9y+GVtqfN96hvE0DQ7HlVJtn8Pzba+hjT\n5j2PaHZtrG1RNNN+9bdvX73zfxVZsfESM7fuWUxxfupmfau2vP5vEAuI0Tf+9aL5/L+XdTP+Eimh\n2/Oz7vlT591EqcpaBHFcmp6ba+JJtyp8qLHu3t/e/wB2pLXVppGd3uV2t8m5fmbdXmtv4shZVtpn\n/wDsa1P+Ene3m+RI2G7b+7f7zVv7OXUKeIhKZ6Tp+rQtcCFHZ0jTb/d2r/eq5p+sJJbyeS7FWb7u\n+vM7fxY8MrmDcV27vv8A/jrVoaX4mfzPPSbbt+Zlb722s+adM7qFaEp3PSPtjzRqm/8A5ZfMrfw1\nYkktr6z8yF2O77u3+7XE2Pie2+0Qu95tRl+ba25mq/b+LEt5F2PsTyvvN8rbaVPEcr0PRpx943Lz\n5pEfZuX7v3qydSmtpJo7Fpldvm2/Lt2/7W6sW+8QPIGeymVdz/M2zdWLfeNPNX5Jm/dvtdfu1lUq\ne9zRO2Mealc1tW1rzIWtkDfKnz7ovvf8CrKi1zzhF5MzMmzait/DWDqniqa53Ijqzqn+r37du5qy\npvE22IobnYi/Mjf7VdOHrHl4qnynpnh3VLbbFbI6l/vf71dho+rfdheZUDL8zL83zV5L4Z16Fm+e\nb7v8P92u103VN0LIjr8zbq+zlT93mPySnipxkdbb6pN57JNNIvz/AL3zF+Xb/erSSZLiSIJ93722\nP5d1ctaXm7zNnmMv3Uaata1uvMjV5nbEbbl2/dWsZUYy2PcweYVYm/G32i6e587zQ0W1l3/dqby0\nkZ0R12/e3Kn/AI7VbR50jd5ntlZfuvu+6y1NZxzSXC38O10X7q/dXb/FXnVKdrn0+HzKXKmUL61h\nluPnf+H5W+7WLqFrZyQlLl2Ib+Jq3dQ/fLv2Lt37Ub7u2su4VI5lmf5n+Zdu6vExEeWR7FPGfurn\nG61p+xl3uz/3F2VjzaOtwqzbNg2bXZfutXWX0aNItmm4fvdzbqg+w2ybkR925m+Zf4q8+pLlCnW9\nscHqmgvIzTP+6X70rN8y7qxb7RdsDPsw33dq132p280cbwum5VT5VZfvNu+9WLq2lzeYXmRQsKf6\ntU+7uo9p7p0YenGU7nD6po6W8mXTavy/LVNtJcsybJE/e/d27q7HUNPEjL56bP4dv8S1nTWKbt77\nvm+ZGo5pcnKfY5fThGJh2tk9veJbfZt/ztvZn+6tb+m6fM0e/wAnLK+1VZtvzUlvYbbjZ9mVdzf9\n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\ncJM02397uf8AhrKMuY9WjL3tTkbqxdXld081flVPk+aqc2nwwq3kq3+wtdPdafDLveHdG/8Aeb5t\n1ZeoWKRp/eO9W3baXN759Rg8UYNva/MiCBiY/v8Anfeb/drU0mH9586ZX/nn/FTb7yZJP9fJ8vyq\n0f8AFRYyT27D7NC2Pm3bm+bdWXKj6TD4ilKBu2sbx26oltsdlb7zbalhDtMf3ezb/wAtEX5W/wCB\nVU0+6M0J3o2z727+LdV2w3+WEd9m5/njZvlbb/drTm5TzcyxUeX3S3YwpJvKTNFufc+6rSxwrHut\nn2r/AAKqfdqBY9sDzPcQ7V/hVP4qsR+crM9tCqq3y1rGU4+8fEYzEe2lygv7jy/tP323Oq19o/8A\nBS9C/wACNKKkBl8WwFSemfst1Xxxb27tHxbKzx7lik3bmr7O/wCCkUaSfA3SxITtHiuAsB3/ANGu\nfzr8s44qf8Zxw9L/AKeVfypn43xjGUuKsoVt5VPygfCF3b7VdLlPkk+ZGWoI9NSV/kRmGxdi7/lW\ntO4sXkWQ7GTazfNJ8tWNN0V7eP7S6ZWbb93/AJaMtfrX1iXL7x9p9XnGRnw2eVe2mmbGzft/u/3a\nsNp7tiF0ZG/iZmrVXT/lXcixKz/xJ8u3/eq4mkwyM0LzKrb90S/wtXB7R8+/um9OjLmszkLzSYY7\nd7mY7V2/NGz/AHq4j4P+NYdH8SeO5nha2Vp4V3Q7WVty7V/3Wrq/idqj6TqEemwoyssTP+7f+7Xz\np4b8UPpvijxJZzJMWvrVm8uOX/lorfLX2+SUKlPDe1f2j4PiCvGeL9nH7JW+KV59n8ZXMLxyReZK\nzeZJ95q8+8WSPY30V5D5h3Nt/eVtePNa+2XFvreyTO3ZK0j7tzf3q5/WribUrP7S8ylGRm2/3v8A\nZr3IylI8L3TlPF2oTTaozptCsn3qzrySFbYzTbfl+4rfxUniK4VZN7p8+2ud1rVnkh8k7g397+9V\n/aKH+Il84iZ0wrf3axIpvJZofmrZgc3uijzDny2rMkj3Sb4PvUfCEfeIpP3f393+9TJB5kf3OP71\nSXCBl+5yv8NQTcMqb9w/urRI05eaRAx29ak2Oyq9RuN5yaVfu7PMpc0S+VCx7Nxy3SrWmSPHL9/7\n38NU6ktWCzLu6UhSidJbSSeTs7L/ABU2RXjZtnzbvvVHZzPJDsTbT93k4RUyn+1T93cxG/eOzO1v\n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\nsjjZu+X71Mvptuz+JF+Z2X+9UP2zzj9ptpF+X7i7vm21rGUj16NOMhGm/wBHCFJA/wB7bJ/CtMms\n0hX/AJZszfOn+1TFmtpoRsTKxptTdSeZD52Uf7q7V/iZq1p/EceOp9Ty7VbB7G4dE/hT72za1Ys0\njtvjQYP/ADzr1LxN4V8xVn2Kv8Xy/erjtZ8KTWcnnJt/ef7NfSU8R0PxfEYaUdTntLuJrNt8KMfk\n27f96us0XULpow+/dtXbtVP++qyI9NmiZd+0My1t6TYzRypawpj7rM33f96ipWOajS5Ze8db4fkh\njVbmZ2+b5dqt92u20nUsSfI7PuT738VcBpdi8MbPG/nfxJXV6be/ZofO34eP76rXnVPelzcx7OFj\n7P3ju9FvprPbvRW/vtXX6FrCXCr/AKtF2fxfLXl1jqUMkaJbeYp3q3zPW1Z69LtV7l4dm/a275ZG\nb+GuKpRlKZ6lHEcp6WurW00LeSkgj3fKyptXdUd1qiLN882xG+4y/wB5a5LS/EEzRu7u2z7qNH8y\n7qh1bXXt7rf9p+b+Bo3+X/d21jHDz7ndHFc0feOg1a+jWT98/LfKjfe3VkX148h2PMxP92P7u6sa\n68TOc/adrfwov8VUf7etpt8iOzlX+Tb91aqVGXL75p9cpRloaN5ffNLDN95W+dvu7VrIuryGZ879\npZfvM/8AFUGpeILaFd/nSfN8vlt/6FWXeX0zN9xXbfu+b5af1X3YlSzKKL7XF5dK1sky/N83mMi1\nXWN2YQwouPlWVf7tMtbzbHKnnblVNz/3qs2O9pR8iun91vlqJRlHTlOeWO9pqzV0tfs6hE+Z2b5m\nb5vl/hrdsbM+W3nIwjjfKNv3bmrH0t0WHzPtKpL/AM82+81asMsKzJC7s7Qv8393c1efKpLnNIYr\nmhymxpP7yR4ekke1n877rbq27MJcKU8lklZP4X+Va5u1vJrdVTyM7m3JV6G4k8n/AI+WZ1b/AHa5\nq1P97znbh+aUpSOhtbqG+j2edGd331b7y7a+zP28XiT4SaWJQMN4liAycc/ZrmvhqG/eSSLZbbdv\n8P3fmr7d/wCCgVybX4NaZIIlcnxNCBuOMf6Pc81+ScaxcOMsia/nq/lTPhOK1y8X5L/jqflA+ZLW\n4hk2wj5Ek/hZvu/7VasLW0zb4PnSNNv95q4iHVkhZnM+f73ybm/75rVtdVdXR4V4Xav/AAGv0+MY\n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\nvtkuZEXzdyqrblrnNY0WaNmTyfMSH5v3f/s1dNGtKXxH5hiMPC55jceHYZGDp8wV9su5P7tW9Pt4\nY4V2bQzP8jN95lrpL3T5riT59ztGm2X91tqvb2cMMxhe2XG/Kt/FWn1j3fiOP6vKNX3SGzsZFb9z\nDvDfNtrStbGbcu+LIb7+1/lWp1j8mzCIm1o/m+X+Ld/eqSCaYW8R+zM/8P3KUanNGyNI0+X4iaPZ\nC3kw7f3jf3fu0LPDCwR5vl37t392s1vOjl8mGdj8/wB7f92i4uv3zujq6fx7fu7dtaU4395SM5VI\nm9Hqzx7fJTZ/teb8rLVDUtcuVDPNMzL/AA7qwf7Qmb5JkZ5WRV+V/l/2aLy48lgn2n7vy/draMYx\n0MpVJcvxF9tYnvGZ5rn5f4V37tzVJHqTyK9y9yqeX91W/irnW1JI5j5brTP7URVeGby3i2q6R1pK\nnzQsc3tpxkbsmpOq/anvF+Zv3Ucm35v9moI5kupHuZpmZ1+9tesua8S4kSa5Xem7918u7a1Tw3SR\nyF96qnyr8v8ADWVTlUCI4iUo6m3aum9YYfMQf7P3WrSt1dUXUk2v8/7qNl2qtY9ncJ8qJy2/c+2r\n0N3DJ+9mdmXeq/u1rza0pOXNA7acubc6fT5N00dtszK3y7ZP/Qt1XZLpFm8l5l3b9y1zFvqT/ax5\nMzStsZfm+Vavzah837sSZX+HburyK3P7e/LoevQ5JRN2HU3dfO8pY2X5fmepGuPtCpClyqNs/e+Y\n/wAzLXMyah5kwT78TN8219rLVv7XMzfvjvWP/wAerLllKPMerTrcvuo6e31a2hhhT5pX/vf3v9qv\nuv8A4KQ366f8ENJleLeG8WQLt+trdV+fEeobY4k+438Db/lX+9X3z/wVCu4LP4BaPJPLsz4xtwrc\n9fst0R0+lflPGtNrjPIe3PV/KmfC8WTvxZkrv9up+UD4zbXJl+SzhjVfveYrfMtWtO1p42LpMpDR\nfMzfNXIR3XmTfvH3hl+Zl+VatR6n5NwERP4P4a/WFT5tj9E55KRJ8bPHj6D4BvLmG8aOWSDykaP5\nm+avjbWrp4ZG+dnT73zfer2T9oTxpNqGtJ4ehfy7e3i3S7fvf71eM6sySM3dV3f7zL/tV97keH+r\n4Xml9o/NOJcZ9bx3LHaJyvi2L7RalNm/cv3a5fR9Y2q1hNIyj7u3+7XT68u7d96VfK27vu7a4PxB\n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\nu/LU1tp+795sUfxbVWp5UORDHHt+d92V+6uyrml6XLfAbE+7/FVi1s5ribZ5H3vl3KlddoOgwxwD\n+Jdn9z+Kuimclcz9J8MvLl4f4V2/N/E1blr4Z3TbEmaUx/Mv+9XSeH/CkNxJ9o8jj7yLs/irobHw\nik0Y2Kqu3zblWrlE4vafynE22i3MK7PJZm/g2p92tVNPmt8edNsZV3f7O2u3bwnf2rRulszM0Xze\nX92qF94TMavM6Rjy/urIrN8zfw1nUjzfCbR5/tD9Wa/adn8lcMvz/wB2sCa/m+1H51xs/uV0d9HM\n0MrzFl3Pt2t/DXL6lDDbt8779392voY4WHJ5nFHFS5iWHVjbtGmyT5vm8z73zVu6fr3l242O3yvu\n2t/drkVnSFT95H+VUZqtJdTFAifeX5ty1Ty+MvsmscdKOp3f/CUPI29Jo96orIq/+zf7VWo/Ejze\na6XO/an+r/8AZq4CG/mRWd+DN9xvvVN9s2M298SK67FX+7RSyvmi7FSzC8LncQ+Lv9WgdmX+Py3+\nZv8AZpj6g8is5mhXc/3ZG2yf73+1XLW+oC623M6eW7fK6t/7LWrpaxxS/wCk7SrfKka/eVa0/s3l\nMvr3MbC3C3s2yFFD/dVm/iqa3t7lZIvOuVcN8rwqn8NV7ezhXytjthX3Izf3q2rWzX7ULaZ2x95m\n2Vay/lOf657xd0exmkmj+dW2/Mi79rbv9qumtdJKsIXeNn+98r7lXdUOg6P+5aZ0jZF+42z5ttdh\npGnpax+TMjNFJtbdJ96pjg77DljOWPvGHH4bTy2eSH545fkbyvvf7LVch8PzCP8AfI3+q3bo/uq3\n92ui+xw7fJk+Z/NXymb+FauLovzO8KLv+b5mqo0OWJP1jmOUm026urhXm2od33pP7tUNY0na2+H5\nvMX733l3V111pHlxvNs2lZf4n3bv9qsfUrGGPZ5Ls+7czL/FVRwvu8wvrnvHA6xZ7Yc/ciZGV/4q\n5m8h8yH9xuG5NjMyf+PV3viCH92uxFXbubatcXqcbwhpHdjK33/3X3a1p4fsOpiOU4/WrfdIf3Ox\nF+VmZ/vf3a56+haPa7vuX5VdVrrNatd0zQ+Tvj2fPt+7urndQjdmSQ22759u7d/7LXTHA8sbKJhH\nES+Iy/ImZWfeyMzfer9B/wDgvLDLcfsZaRBEQN/j+0DZ9PsN9mvz+23P2j59p+T5o/7tfoH/AMF3\n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\njzM6I7ZV9u2tvw1I6zeTcuqqv3FZ/vVz6tBNJsT5dqbqvaTqD2rq77W2v/c3fLWNRe77pvzcp7T4\nHunjgV7yaNnV1+7/ABL/ALVe3/D+8doYXmdXdfn8xfm3V84+CtaSM/ZkmVWj/ib+LdXsXgLxAlvL\nbwvMxST5vlb5VWueXPLUmXwnr+m3j3Vx9mubbcPvfaFSttredk/1LOV+aJm/9mrj/DurabcbHhuW\n3LLsRt/+d1dHpOpQqwR7ba/mtukb5d1Yy5vdfKcXumjZbNx86T/f/wBmkjjkhmZ0myPuRR/w024u\nHmhVbb5fvfNVDUtbe1h8l5o2k27tv3VrT2kdwPinUr50ZrZHXaz/ADs38NItu99cGaZ22xrulZdr\nbmrDGpXNwvyXKlWf7v8AEzV0Hh23kUpcvD919z+W3mKrV+qxxXunyVPC+7c1dH0fc2Niuu1flauk\n0/w7Gqpcuke5V+7TNHsknmV158tPnkk+XdXT6bY7Yw72ylP+en/j1ctbHSlHSR2SwvwmcvhO2uNj\nx2zBI/m/4FS3HgtFy9ydu1/ljb7ys392u00fT5poRM+5hIu5G+7/AOO0TafbRloQVUfKit977v3t\n1cUswlGV+YxlhIxPO7zQ4Y40mJYmbcnzfeh/3qzL3SUa4H2PdGrfdZn3fw13+o6W7SNbQ+YE27lZ\nl+Vt1YmpaX9jy8Ntimsw9pvImOFlDY5ZXht7hEdFcL/e+8zUR3W3zHfzFT/ZSrd1ZzWsk2x/nml3\nIzf3azrya2kgPk/cVdrrt+9SliveNPqfcvWOtPp+N+7f919z/wANWbPxMlvI+ybcP7rVyVxcpb26\n2qbdsf8AdRvl/wB2oG1p1jSJ/k3fLuVK0ljubYyhhe53reLkmjdw67V2/LTG8XQWbEJub59rNv8A\n4q4Btc8qNn3su1PkZqzZPFm2NbnfJsmXcytVfXOcpYeUT0+bxl5cOyzvJvN+78zfe/2az7zxJbTM\nZkmZjJ/ra8yuPGybW/fMflb5V/i2/wANXrHxBc3EIeSeMMy/db+Kn9YiqVmKWHnGXunbLqUMzNM9\nzJtVfm+b7y1HPqPzD52fzE27Vf7tctY6w6rvtpmbzNyMrJ/6DWjb3KbldPLYb1X5flZm2/xVEsZy\nx5UXHDXleZo7nkjTzvM/uszfN5dI2+RmTezbU+X5f4qhs2hk23KTf3kb5/lqyykSI/y7Y4tu5fu1\nnUxnKdEcPKRUuI4XbeifL8v3m3fNX2n/AMF5lU/sLGR4ywj8VQtgH/pyvK+Mb6PzI0gh+ZmRv3i/\ndr7X/wCC6Nobv9h2RSoKx+JYpHXuQLO8PHvX4B4sYj23iPwlrtUxH5UTxcfQVPN8H5yl+h+EmrR+\ndYr8zNuRWRWX/ZrlriF7W43p/ertdaX7HpsU3mNtZfl3f7tcNqFx50pP8W6v1b3T7KPxBDqk0Lq6\nzN8tdL4f+I+v6fMjw6lJuX7jbq5BULNtq1p9u7NsfcB/eqSuWB6hZ/FzxXNEIbnUmmi2N+7uF8zb\n/wB9UXHibR9QZ/7Y0GxuVaL5NsW3/wBBrhPOmjVkR+Vq1b3T/Kyc7v7v8NVGXLIylsb8mk+Br799\nbaJNb7U3fu5/u1dhuLaSza1h3Ou3b8yfNWJazO4+5tVvmbbWnpczrPvnmbC/3Vq4ilL+Uh1zwreX\nUMWxFaPZ91l+81cfq3gzVdPlO22k2r/d+bbXrWrLba5ouz5kfb8jK+1lrzvVtS8SeHZpLWab93/e\nX+L/AHqn4RxlPmOUKzW7fPwy0+4uvPGyZPmXvW1/wk1hcnZqWlRt/tL96s7WmsAwa2Tll/h/ho5o\nm3xFCiiioLG+X70qrtpaKr4QCiiinHYAooopgFFFFABRRRQAUUUUuVAKq7u9b2mTTW+kl027awVO\nG+f5q6CyjkQRpDtxtXg0SiY1T6L/AOCd+nzab4s1Px4kK/aY7P7LYXDfehkZtzN/3ytf1DfDj40w\n/HH9nfwr8R9D1hZbbVvCtvFcQ+V80c0caxyf+PV/OP4F+Gt/+zvp/hvwTqr7dQvNIh1a/haLa0P2\nhdyr/wB87a/Zf/gh/wDFKHx/8G/F/wAHbzVVkuPC91b6ja2rfNttZv8AWMrf738NdGHlyzPnsVUl\nUlofVkd8/g3ULLR7+88ma+sGngk3/wCsaP8Au14t408D6b40+K0HiiHw9CHjWQSyW8S+a0n96u2/\nbAvNS0fxH4O1vSraR4rWWaB5FX7qyLXEfFr4veDP2cfAL+PPHPiqPS7toma1t1TdPeSbflWFf71d\ntSpCj7xx04zlofDHxdv7Lwt+17Lqt9OsVvp3iKwmnd8ARoghZs9hgA/lXmv7WH7XnjD42XVz4b8E\n3rWuhb2+1XH3ZLj5W/1f91aj+I3j4/E/VNY+IN1p8lsNTaaZoJm+dRgj5j6kDJ+teHePPG1hpeiz\n+RtlZlkbaq/N8qt8zVXFmKlHD4Jxejpp/gj9L4zjJ5flK/6h4flE+MfCljNeeINYuXDFW1eb+P73\nzV2Nu3kr5PzfL/DXG/DeN76zmmmfa81/I+5v9pmrs/JTcmE3Oq/Jz8q/71eRS+A+XfUfNC8kO/Yu\nJPl+ao22L8jwq4+7/u1NcHdD8n/AttUmj27/ADkZlb7u2r+ID1/4A+KPDfgrw34h8Q+IYY5biP7O\nulqzfN5m7c22uM+JXjK88Xaxc+IdSufLT5nePd8qrVDQJENiyPt2L/d/9mrzD4+/Eh7iY+EtKmUL\n/wAvTR/+g14lajKti7HPHD+2q/3Q+HXjR/Ff7TfgVbZ/9Fh8Z6WsQ/vf6XF81e5/8Fbv+af/APcW\n/wDbOvmf9nP/AJOE8Cf9jnpf/pXFX0x/wVu/5p//ANxb/wBs6+6y6EYcMYpR7x/NH6TlUIx4Kxyj\n/NT/APSonxrQW280UjLur5o+OFoooquYAoopPn9qoBaKKKXKgCgNu5pU+8KNqKo2fepRAaowMVoe\nHr99PvPtMfXbtqhWx4I8O3vibxDbaHpsavcXUqxQKzbRuZttPm5feIqe9Cxqza5e6lqiXM0zZ3L9\n771faHwzsPgV46+F/wAN9V/a0h8eXPgnwK9w32Xw7qKt/osknmSwxrJ91pG/iWvmzU/glp3w/wDi\n1/wrXxp8TvD8N3byxrPeafdfa4I5G+bbuX7391q9G/as+KfivX/CGlfs+eGvCOhwXWl2qyXl14fu\nd32i3+6q7f738VZ168ZWgt2ctFa3Z6f/AMFPNT/Zm/aA+COi/Hv9nj4kaD4L8I6JeLpPgP4HWcvm\n3VlZ/wDLS6uWRv8Aj6kb94zN/srur4El37uKdqFleabePYX9s0M0b7ZY5F2srU1mTjfTjGUTtGsN\nslDO7Sb0FIxy3FSW6/Mc/wANBHwmv4R0/wDtLxJpump8pur+3i/76kVa/pe8TrDa2trpriZkh0iz\niWP+H5beNa/nO/Zt8O3Pib48+CPDyQ+c+oeL9NiSFfvf8fC/dr+ibx1ffY/EF5bb9zLKyIzfN8q/\nKtcuIfwxOat0OUurxJrhoXtmTy/7zbVrndUaaNmRPl3bm+at3UGkkaV7lI1XbtZV+ZqwdabzF3vu\nJZfkk+61c0vdiXH4zj/Elv8AarcI5VFXaz7vm2tXDeIlmXels7f7e77tei64sK7/ADhGEjRfN3fe\n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\nAKDSx3zxSfJ8m7+FWrMa6e3VNiK23arr97dU26Zm2JJHhdzO2yo5eU2lI7fwrrv2dvLe5Vw1emeC\n/FSQ2ohmufn2fKsn3tu6vB9L1Z44RND8m35v+BV1Gk+JkVVe52r8v+sX5vmqJR+1EyqSjyn074X8\nVbV+zedlGT/Vt91W/hrrtN8VFlxc3LSCNtyRq38P8VfN+h+OvJ/dzTbVZflbd81dlpfjf5kSGb7v\nzrI38VRKPc5JS949r/4TR4bMwQosifegXftZv9msfVvGTvHK/lrsb7/8X8P3a8+m8cPIw2XWW/vb\n9q1h6t8QPLiaa5mWJm+8vmtWUqfNEXNCJ5Ho+oeZJHvSNV/jj3fKtdr4ZkjjjJSONF3bWhj+Xd/t\nLXmmizWccbTTTfu9+35fvNur0Lwu32ZYn3/d+XdJ/F/vV9ZWxXL8JhTw8fhO58O/JCsIjVNyfdb7\n1ddoMiYZHTy2+7FHsritLjhnkExdZtv35N/8P92um0u5aGNJrr5UVtyfNubb/DXHLFSlqbSoxO10\neaZm/wBJm/u7JNu2rs1qjZuYQuybd5q7/wDx6szRbi2+yb4JmmaP5nX+GtKO3S82pMcFk3eWv3Vr\niqYocaRn6pZuqo+zeYUZtqvuVqwNXtnk+5bSK0m35f8AZrs1VPLSN3/e/MvkslY+sWbr5ttDNu3P\n+6j/APsq5vr0YyKjheaWh554mjSVmubban73ZuX5q5fUZptrQJ8p/vbK7nXLOGBXj85Wbezfd3Lu\nrldQtYPlmhdmlb5W+X5W3f7VV9el3CWF974TjtWvoYv+XZWeNNrSfMv/AAKuZm1h2kVPtLZXcrt9\n1a6bxJapHbtC7soX5drfxV5/rn+jXTp8zP8Ae2s/yr8tdVHGe0OepQlEs3XiKa3VHd/3qtt+X/0K\nsfUtcu4/3jzM3z/dqjNrk1vcfIi/c+fdWTretQyxs79VrqjiP5TCVHlNWz1SNrhnm3Ntdtv+zXTa\nHfR+Wjvu2feRZK8z03Uo/tG/zm+b5q7fwnqU/l+T52Xb7isn3ar2yD2fwnZWcyRsj37qqf3l/h3V\nr6e32fZD/rG+8vmf3awdPmn+0RPNMrrs3PtSt6wuvJbznfn+7s/irCVbll8RtGP8xsaX5KlU+88n\n3of9n+9VltkjM+xSrfeX+H/ZqnYrNcMzvtaLbu+X+Gr0bIsLTf8ALuv93727/drmljJfaNqdMjk8\niOLekOyX7zbd21f9mvt//gt5HHL+xS0MhI3+JIlU4yATZ3g5HcV8UTXDx2bOkLD5f4q+1v8Agt9c\nNafsSvdLbiQx+JYGyWxs/wBFuvmr8O8SK8qniLwu+1Sv+VI+ezulyZxgV5y/9tPwj+Kl9DZ29vYQ\no3yr83+9XAM38dbfj3WX1fWXmR8isvTtPmvrkRRoxr9wjE+kj7sbhY2/nygbe9b1vp7w2/B3M1bO\ng+BX+y75E2u1Q6+0OlwsiDJ3bavl5TPmjIxv33nMjupO/wC7WhpNqm754WrDuNURmOxG+Wki8TXl\nvIHR+KXwi9+R3lnojyf6naE+9u/i/wB2pI9Njt1i33Knb8zs38NcpY/EK/DeTO+1W++y1c1rTLnV\n4vPsdaDI23YgpylzClHlOuF5YSL9j/tKEj/rrUV9pMOuWv2aYK8ez5JF+avO5vDWuxMXhDOF/iV6\nm0xPHdsv+hw3RVfm2/w1MecqMY7lXxLoNxouovCfu7vlrKkZ87Grc1vWdSuBs1WxIdV/5aJ/FWHM\n7yNuakaxFopFbPBpav4ihv3/AGxSMu2nKu2hl3VAC0UUVcZAFFIrZ4NLRHYApeVNN53b91LUAAbd\nzRSKu2lrQAooooAfHHukXf0avW/2VvA2m/EX46eFvBmq7fsE2qRy37M/3YY28xv/AEGvKLH95IN/\nG2vev2WfDepWV5P4wsJZEmX91ayMn3W/i2/8BqZe77xx4qShE+sv2ttY/wCEm+M0/iq2mV7aZVit\n2V/uwrtVV/4Dtr7F/wCDf74jWfhL9q7WvDd5qvlL4i8HzQMsn7xZGjbctfn7pdrc3V5/aXiR8xwp\n92RPvN/er3f9gH9oCH9nv4+W3xatoVuIdJsrj/R5H2rM0ke1VrGnUtLnkeI5c5+wv7ZX7SnwZ+G/\nwz/4TDx7ryxLp9xG1rZx/wCtvJl/5ZrX5F/tFftQfEP9pLxxJ4w1hJokjdl021uLjdFZx/dXy1/3\nfvVmfH74jfEj9pD4gXvxF+KPxFjkVrpv7I8P2cXl21jD/Cq/3m/vNXmcmi6Pasz/ANvXU6MrblWX\n5V3f3a48Zjp1fQuMfZnqOlRFvhnLDe3ivmxuBJNG3GPnzg+39K8h8dah4S0DwXqjpNG5a1mbdGm5\nmby69T8L29lZ/Bt4IogIF0+7+QtnK5kJrw341eILXRfhnqt/ZwqhXS5otrL8vzLtr3eKFz4fLWv+\nfMfyR+gcX64PKV/1Dw/KJ86fDO3ePw7BN5PMm5tzf71dTJvhzsT5fvfN/FXP+B/9B8M2cKQ/6yJd\nm1q2lmeWP998p/utXPCOh8pU+ImjjS3jaZJmK7F2rVSS48kF5Plb723+GoLrXLaPMP2nZtfbtasa\n+8RIvyQ7Sn96l9rQXLGRqeIviU/g3wfdJbJH9ouG/dTfxL/u14TeXc1/dSXly7O8jbnZq6D4iatL\nfXsMH2reiqx2BuFaubqY04xlKR2UafLE7L9nP/k4TwJ/2Oel/wDpXFX0x/wVu/5p/wD9xb/2zr5n\n/Zz/AOThPAn/AGOel/8ApXFX0x/wVu/5p/8A9xb/ANs6+nwX/JNYr/FH80fcZZ/yReP/AMUP/Son\nxrRRRXyx8WFFFFACMMjiloorQBFXbS0UFd3FT9oAooZfmye1FPlQCt+7au1+BWr6bo/jb7Zf7d/2\nC4W1Zv8AlnN5fytXE0b3Vg6Nyv8AdqZRJ5UbUWnzLdPc3k2597M0m/7zf3quW8F42rrq763J5i7d\nszP8/wD31WENVuQhTPBqM31y38bCr9zlMOSrzXub3xDvbLVtcTUbYbpZrZWum37t0n96sBd67t9G\n4NIzvTJF+bmp5TeO4L8nCPU0bKmE6bv71RbTu+SrEMM0mfumpJaufS3/AASn8K/8Jh+338LdKmto\n5IYfEa3T+Z/0xjaT/wBlr9w/Fd1CLyWZ33edcMySL/eavyN/4IS+CpNY/besfEkyRvD4b8L6hes0\nn/LNmj8uP/gXzV+sd9Ntt/kfeJPvKz/xf71ediJe8Yv3nymRdN+7d/m+V/7n3qyNSie4ZY3s22sv\n975lrS1BrZbqSGO8Zwvzbf8A2VarXiw3UaTfbP3f/LKNflaSubm6s6oR945XVrVxG6PbZf8A5a7n\n+Vv96uS1LSUhYiZ23yP8vlv81d/qcJaRke2XLbvNb+Jq5i8sZppJSzyJMqfJtiX5f9ms5e9E6qcT\nzTVNHcRo6Iqtt2urL92sSTT3jZ7Peqn7zbl/75r0DUrFBueZY5TMrK23+GsO6tLZQ1s88hRtvzNV\n/YOnlOVW3uo4/J2fMsv72T+FarFZlZJ98ed27zFb5q3NUtUWHfbQt838O/5WrNuP3yt9p3IJNv3f\nm2tXLKjKUtS170feM2SZJVdEdkZpd25futt/hr7f/wCCZgI+BOsKUxjxfPz6/wCi2vPvXxFJHtaV\n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\n/wDj1ee+KPDbrumRFLLuVGb+7/dr6/C+9HU+IxUZc/wnlEmkzRzNC8K7q7b4f2sMl8qXj+X8mxd3\n+7UMmiwrOHdF37v4m+7XReDdLmWbf23rsWvYj7sDx6z7HZeHdN8ny2fyxt+VW/vV2vh2ztmsykaS\nHc+3dIn3lrH8Pwu0kcMI+dvu12Wh6a8d0zuikyLu/wB2uWQR93QrWenwiZtj7hJu31YhhSOGaG2f\nzZm2qjM+1dtaVxZu0zwvCuz7u5fu1FYWsNvumvF2Q/eaRk3bdtcdWnGWjOynLljzEniKzfwn4Tl8\nc3KKyw/urfcv3pP92voz/g4GRW/Ym0VpIDIq/EaxZlAzkfYr6vk/9qTVnb+xPDsbzfZPs/n+WrbV\nk+X5Wr63/wCC+8dxL+xHpyWgJk/4Tu12BRk5+w31fi3iDCMPEPhZf9Pa/wCVI+Yzip7TOMF25pf+\n2n45+JviFNofhs2ulPs3Lt2x15DeWuta3e/aphJI0jfxV1Ta9pv2iKHU+V3L5qt/6DXsfwu8ffs0\n6PCH8VeFbi8l8raixsq7f92v3OPKpXkfSS9rH4D5/wBN+HPiHULhE+xvhm27tlddL8ONF+H1n9v8\neSeTNs/0ezX5pJG/vN/dr174hftIfD3SbO4sPg98PbW2m8rbb3l187r/ALq/3q+bvFF14h8QatLq\nus3M000j7mkmatfaR2gKn7WWtQl1zxN/bV4ttDttrb+COH7tQMqbWS2/76rJWN9x+RhRHJcq2yN2\nqNfiNuX+UvJZlW+d1ct/eqwtvDCux32t96qEM0zN8/y7fldqvW7PMy/e2/3m/iqjOXulu3td0Y8z\nrXcfDXQ4Lq4abZ86xMyLt/irkbE2y/O78t/DXf8Age6/s2MO/wAiM3zs1KK5SeX2m4y88P21jm81\nKZlTzd27dXDazrU2u6t9gs5pPJjf5F/hWuh+JniIaxeyab4c3GST7+1/lVawrfwvqXhvw9N4hubZ\ni4X5G/u0x/DI5vxQ0J1hvI/hVQ/+9WbvX1p80jyuzzNlmfczVEy7aDoQ+iims2G49KBjqKKKXxAI\nq45NLRRR8QBRRRRyoBFXbS0qru5TpQy7TimAY249f4qlt4/3io/FRLwu+rOnIJJgnks5Zv4aXMiJ\nS5UftF/waW6JeeHfi18RfGGzamqeDZrJmZFZfLh2yfe/vbmr76+OUk2jeLnvHdvKml2QMqbVVq+P\n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\nf4dvzbf9mp4ftKr5zn5G/iV/vf71MwqR5veIpLXzJPkTcu7+L5adHbw/Nbfd/ubamkj8lmd02bfv\nfxUNb7pN6Ozf3G2bflropy+yeNiqc+a5VlRVjXcfl3Ns3VRvFRYWfYvzVpXSo2zzNrfN91X/AIqo\nXkKW8n7vbtk/hrXm933TljH3vePN45Nred5zbmf5Vq1Z3HmRs8yMPLXbu3/erN+0TSSI/ULVu1k3\nR/I7Lt/iavLj8J7cDZs7942CbF2qv8Lfd/3qvWd55LLMkzbv7yvWBZ3T+c1s6f6xd1aNo23CQx8f\nd2/xUvscpvTlzHYaT4keT5EmkLL92u28O6lqBVdki4k+Xa38Neb+H1fzn8yHd/wPbXa+G7ry23wX\nMaOrr95a8rGR/lPoMD71rno3h26m8zZNcsu1NsX93dXceHYnvJC/2zfKq7XXZuVq880O6RVHlou5\npV+0SSJub/gNeh+FJk/dI+5X3fJ5a181iKfLGXMfWYOXwo7HT4XkjR5uFZfkVU+XdWgsKJIsOxlP\n3k/2VqLw7bvHHF5w+Zfm2/3q6GOGZfnyrq3zeWv8NebDmjOx63LHl5jm76xSCJZrZFWRd37yR6wN\nQt/LtxNeW375nZlZW3fxV2OqadCzN/Au3d9zdtrH1i1hWEQ/ZlLqv3lX7y17WF/d7Hh5gubWxwmt\nW+63mTYvms+373ytXE+ItDtpoWTyVTzPu7fm216X4m0lLWTZND87fws23y65q+sYVt3hto2Mrfc/\nir6vCSjy8yPh8dHml7x5bfeH0SYPMm1N+7c33WWtrSdJTzNnkqWb5kb+Hb/DWvcaCk0m+aHYirtl\nVvu1Y0zT0hiDwoodv4v4dte7CXNC0j5TEaVbo3PD+lsix3LosW7/AMd/2q63TbObc3yW+9UVd275\nmrnNLaGHykdN275d0f8A7NXR6TIlwwS2dm3f+Pf7tYy/uii+UsrGLxTNlkRfllVfl27a5LxX4403\nWLi503RppGgsdqyxxy/6xv4v+BUfFv4jQeA/D8xs7mE39xEyRQr/AMs/l+9XnfwjM0Oj/wBq3nmF\ntUlZ4mb5d395qwlz850VJe6dd8ep31jwn4O8cwzMdP1rTt8X2hdzRsu5dv8As7dtfav/AAXekRP2\nP9BVxkN8RLQD/wAAL8/0r4K8Xak958F7/wADanqTNc+DdWmn07d/y0t5Pm2r/s195f8ABeJ4o/2Q\n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\n8k+827+8q197XEk0cJmMDf7v92vgc9xcqmM5Pso/QOHMv9nhPbS+0Zd5dFf9GmdX3S7E3N826s+4\nuHjLQ2ybv4n3fdq1fTPCsyJCwT5WfcnzbqqTL5jOmyOXdt/3vu/drxvby5/7p6lbCxqcyZPZw/MP\n9Tv/APQastH9li/f7RG3937y1nxslvMieS33dztv/iq4l1ugX7TDtT7zru+7XbTx/tDyamB5djPv\nvlaO58jcGfbtZvmZa5y8jtlhUuV3+a3y7/vbm+7urqdcuraSMzTP/HtXb/DXK6tdQq0mLzlfuLs/\n8er3sDiO54uOwzjuV7qSH7Pv6tG/yqv8P+zVZtReONv9Zuk+/UF5qVszF3diknzI38LLWHfaw8dx\n5KO2N+1vl+Va9unUj/MeBUjOJfvtWCyeT5zI+z/nr81YmratuJhCKr7t3+t3K1ZM18/nN9p+XdLt\n2r93bWXfX3l3bJ9pX/pkrf8AxVavYx5i1qF4dvmWyLG7L+92/Nur7d/4Je3C3P7P+rMu75fF9wp3\nHP8Ay62lfAc2sBtqXKbGbd8q/K+6vvL/AIJUTrP+z5rZRSAnjW5QEnOcWlmM1+J+P0Irw9m1/wA/\nKf5s+c4snfJmv7yPg+4vkhkEYGVVWZ/9lqoX11cx6bcu6ea/lf8AAv8AeamR3kNxMZn+VZNzbV+7\nHWX4svEs9Dub9LnY7Iy/K+35f7tfr06cef4T7CnW5YHy9+0V4sTRZpYV/wBdcKyozf8ALP8A3a8Y\n1SP7VHHc787k3bq3v2hPFH9ueMpIYV2xRt8nz1zml3D3Gm+S/wDDXr83LCNjhl73vFKNfKYps/jo\nkjG7e74q3JabUfYjMf49v8NQyL91Nmf9qtPc+Ikgb93j+KlhkdpN/nfL/dqCSR1U9/nqJpHVagqM\neY19Njea6XZNw38NbE2lu/8Aq0rntLvPs8yu74rqtL1y2lt/L+6f71V9ozlsZtxoT/O6I3/Aqrf2\nbeQuudu//ZrpPMT5f4v9mpo7e2Zf9R8y0+VBzGFpuqaxZ7U85lZX+Sum0fxtqsPyTBgWf52b5qzm\nghZd+xflf7rU5ZfJ+5D977lHLKIpSO90vULPWI/Jum8p5F2vIvytXSaVZa3bSRxWd+0oZNv3/l/4\nFXl+n/afOT+997czV634D1j+x9DfVdV+5t+Vf/ZaPhgTLl5uY8//AGlfC1zNpFtrY2sYfll2t93/\n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\nD5bP83ypudY/vbv71c3q1zi387exLbvmb+JlqTUvECTRvbIilpE+9G1YF9rkMjb03NJt/if5a9Wn\nzS5TyKnITX2qPNHHNDtbbF97+Ja/Qf8A4JKPv/Zx1rE/mY8a3PzZz/y52dfm0upQyfcdt3+y/wAt\nfoz/AMEe5PM/Zn1w7GXHjq6+93/0Oy5r8b+kCreHVT/r5T/Nny3FTvlTfmj89re58zZ9mm3LNK3y\n/wB2uW+LOqTQ+Gbn7G+3dFt/3a0obw28Z+8pbds2/wDoVeffFLxVDbtJps213mTd5bf7tftHLLmP\npoylI+UfHSvJrlxcv99pW+ZqoaNefZpmL/datTxtvk1iV3+4z7q59ZTFOrJ8wV91dEY+7ymkTp/J\nkjV38nG7+9WVfSPHhH3Y/wBmtCG8S6sU3zfe/u1mXnzbnR2Lf3ar+6Ry++U5Gy3u1RyY/g+7Ukkj\nswTYtRbTu+SpNIg29pPMd8GrFrqE0Lb/ADm2/wB2omhmYb/vUpt3X5O/+1Vf4gNyw8UOijem4f7V\nben+I3kZoU2ruriI43b5NjVdtfNjZZtjf7tLm5SZHZeZ9obfsVW+7tqeytd2Zsq/+zWPo94nkL87\nH/erb0+8QN5KJ97+Ja15uaJiafh3T/t1x9m2bPnVV3f3a6/4gf2lHpNtoltayBIYt0rf+g1zfhO7\nhj1KFLnanzbXZv8Aer1S+bTW0dtVSH7YWiVWVnp8xHNHnPCNem+z2svyYTZ8y7a84mYtMX2Y3V7n\n4/j8N6tapbQ2EltIy7vL+9Xj3iLw/NpVxvSFvKb5qj4fiNqcrmVSqz7tlJToVQSLv3UHSa/h218x\n/kHP8VWvGEwjjhs0udyL822p/DFskamZ3XGzd92sPXL57y/d96srP95aX2zHl5plMnzGrR0+aeO3\nOx/mrPjH7zD1s6SsKxsNn/AmqAkXtLvHe1MLvvdqbqU1zb7tnziordU8w+S/zLUupfvpxCjtv2f8\nBoI+H3kV9P1a5uG8n7v8PzVfurxLeNn2bf4dy1Hb2MNrGZKjvmSSEwvyfvfLWgub3x1vqW6RXeZc\nN/DWxYpuhlmhdii1ztvp73TLhPu11WgzPZ27o6KEZPmVaA+IzZL77L7q33qI7hJ1Pl7R/ElWtUsb\nZm3pG23ft+7VKPS3jmZN+0M+1Kr4hfEMXWE8zy3fO3+9WjDveH7T03fcrMt9JRm2fKSv3/7taMdw\n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\n", + "text/plain": [ + "" + ] + }, + "execution_count": 26, + "metadata": { + "image/jpeg": { + "width": 600 + }, + "tags": [] + }, + "output_type": "execute_result" + } + ], + "source": [ + "!python3 detect.py\n", + "Image(filename='output/zidane.jpg', width=600)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "ijTFlKcp6JVy" + }, + "source": [ + "Run `train.py` to train YOLOv3-SPP starting from a darknet53 backbone:" + ] + }, + { + "cell_type": "code", + "execution_count": 0, + "metadata": { + "colab": {}, + "colab_type": "code", + "id": "Mupsoa0lzSPo" + }, + "outputs": [], + "source": [ + "!python3 train.py --data data/coco_64img.data --img-size 320 --epochs 3 --nosave" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "0eq1SMWl6Sfn" + }, + "source": [ + "Run `test.py` to evaluate the performance of a trained darknet or PyTorch model:" + ] + }, + { + "cell_type": "code", + "execution_count": 0, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + }, + "colab_type": "code", + "id": "0v0RFtO-WG9o", + "outputId": "6791f795-cb10-4da3-932f-c4ac47574601" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Namespace(batch_size=16, cfg='cfg/yolov3-spp.cfg', conf_thres=0.001, data='data/coco.data', img_size=416, iou_thres=0.5, nms_thres=0.5, save_json=True, weights='weights/yolov3-spp.weights')\n", + "Using CUDA device0 _CudaDeviceProperties(name='Tesla K80', total_memory=11441MB)\n", + "\n", + "Downloading https://pjreddie.com/media/files/yolov3-spp.weights\n", + " % Total % Received % Xferd Average Speed Time Time Time Current\n", + " Dload Upload Total Spent Left Speed\n", + "100 240M 100 240M 0 0 17.9M 0 0:00:13 0:00:13 --:--:-- 20.3M\n", + " Class Images Targets P R mAP F1: 100% 313/313 [11:14<00:00, 3.02s/it]\n", + " all 5e+03 3.58e+04 0.107 0.749 0.557 0.182\n", + " person 5e+03 1.09e+04 0.138 0.846 0.723 0.238\n", + " bicycle 5e+03 316 0.0663 0.696 0.474 0.121\n", + " car 5e+03 1.67e+03 0.0682 0.781 0.586 0.125\n", + " motorcycle 5e+03 391 0.149 0.785 0.657 0.25\n", + " airplane 5e+03 131 0.17 0.931 0.853 0.287\n", + " bus 5e+03 261 0.177 0.824 0.778 0.291\n", + " train 5e+03 212 0.18 0.892 0.832 0.3\n", + " truck 5e+03 352 0.106 0.656 0.497 0.183\n", + " boat 5e+03 475 0.0851 0.724 0.483 0.152\n", + " traffic light 5e+03 516 0.0448 0.723 0.485 0.0844\n", + " fire hydrant 5e+03 83 0.183 0.904 0.861 0.304\n", + " stop sign 5e+03 84 0.0838 0.881 0.791 0.153\n", + " parking meter 5e+03 59 0.066 0.627 0.508 0.119\n", + " bench 5e+03 473 0.0329 0.609 0.338 0.0625\n", + " bird 5e+03 469 0.0836 0.623 0.47 0.147\n", + " cat 5e+03 195 0.275 0.821 0.735 0.412\n", + " dog 5e+03 223 0.219 0.834 0.771 0.347\n", + " horse 5e+03 305 0.149 0.872 0.806 0.254\n", + " sheep 5e+03 321 0.199 0.822 0.693 0.321\n", + " cow 5e+03 384 0.155 0.753 0.65 0.258\n", + " elephant 5e+03 284 0.219 0.933 0.897 0.354\n", + " bear 5e+03 53 0.414 0.868 0.837 0.561\n", + " zebra 5e+03 277 0.205 0.884 0.831 0.333\n", + " giraffe 5e+03 170 0.202 0.929 0.882 0.331\n", + " backpack 5e+03 384 0.0457 0.63 0.333 0.0853\n", + " umbrella 5e+03 392 0.0874 0.819 0.596 0.158\n", + " handbag 5e+03 483 0.0244 0.592 0.214 0.0468\n", + " tie 5e+03 297 0.0611 0.727 0.492 0.113\n", + " suitcase 5e+03 310 0.13 0.803 0.56 0.223\n", + " frisbee 5e+03 109 0.134 0.862 0.778 0.232\n", + " skis 5e+03 282 0.0624 0.695 0.406 0.114\n", + " snowboard 5e+03 92 0.0958 0.717 0.504 0.169\n", + " sports ball 5e+03 236 0.0715 0.716 0.622 0.13\n", + " kite 5e+03 399 0.142 0.744 0.533 0.238\n", + " baseball bat 5e+03 125 0.0807 0.712 0.576 0.145\n", + " baseball glove 5e+03 139 0.0606 0.655 0.482 0.111\n", + " skateboard 5e+03 218 0.0926 0.794 0.684 0.166\n", + " surfboard 5e+03 266 0.0806 0.789 0.606 0.146\n", + " tennis racket 5e+03 183 0.106 0.836 0.734 0.188\n", + " bottle 5e+03 966 0.0653 0.712 0.441 0.12\n", + " wine glass 5e+03 366 0.0912 0.667 0.49 0.161\n", + " cup 5e+03 897 0.0707 0.708 0.486 0.128\n", + " fork 5e+03 234 0.0521 0.594 0.404 0.0958\n", + " knife 5e+03 291 0.0375 0.526 0.266 0.0701\n", + " spoon 5e+03 253 0.0309 0.553 0.22 0.0585\n", + " bowl 5e+03 620 0.0754 0.763 0.492 0.137\n", + " banana 5e+03 371 0.0922 0.69 0.368 0.163\n", + " apple 5e+03 158 0.0492 0.639 0.227 0.0914\n", + " sandwich 5e+03 160 0.104 0.662 0.454 0.179\n", + " orange 5e+03 189 0.052 0.598 0.265 0.0958\n", + " broccoli 5e+03 332 0.0898 0.774 0.373 0.161\n", + " carrot 5e+03 346 0.0534 0.659 0.272 0.0989\n", + " hot dog 5e+03 164 0.121 0.604 0.484 0.201\n", + " pizza 5e+03 224 0.109 0.804 0.637 0.192\n", + " donut 5e+03 237 0.149 0.755 0.594 0.249\n", + " cake 5e+03 241 0.0964 0.643 0.495 0.168\n", + " chair 5e+03 1.62e+03 0.0597 0.712 0.424 0.11\n", + " couch 5e+03 236 0.125 0.767 0.567 0.214\n", + " potted plant 5e+03 431 0.0531 0.791 0.473 0.0996\n", + " bed 5e+03 195 0.185 0.826 0.725 0.302\n", + " dining table 5e+03 634 0.062 0.801 0.502 0.115\n", + " toilet 5e+03 179 0.209 0.95 0.835 0.342\n", + " tv 5e+03 257 0.115 0.922 0.773 0.204\n", + " laptop 5e+03 237 0.172 0.814 0.714 0.284\n", + " mouse 5e+03 95 0.0716 0.853 0.696 0.132\n", + " remote 5e+03 241 0.058 0.772 0.506 0.108\n", + " keyboard 5e+03 117 0.0813 0.897 0.7 0.149\n", + " cell phone 5e+03 291 0.0381 0.646 0.396 0.072\n", + " microwave 5e+03 88 0.155 0.841 0.727 0.262\n", + " oven 5e+03 142 0.073 0.824 0.556 0.134\n", + " toaster 5e+03 11 0.121 0.636 0.212 0.203\n", + " sink 5e+03 211 0.0581 0.848 0.579 0.109\n", + " refrigerator 5e+03 107 0.0827 0.897 0.755 0.151\n", + " book 5e+03 1.08e+03 0.0519 0.564 0.166 0.0951\n", + " clock 5e+03 292 0.083 0.818 0.731 0.151\n", + " vase 5e+03 353 0.0817 0.745 0.522 0.147\n", + " scissors 5e+03 56 0.0494 0.625 0.427 0.0915\n", + " teddy bear 5e+03 245 0.14 0.816 0.635 0.24\n", + " hair drier 5e+03 11 0.0714 0.273 0.106 0.113\n", + " toothbrush 5e+03 77 0.043 0.61 0.305 0.0803\n", + "loading annotations into memory...\n", + "Done (t=5.40s)\n", + "creating index...\n", + "index created!\n", + "Loading and preparing results...\n", + "DONE (t=2.65s)\n", + "creating index...\n", + "index created!\n", + "Running per image evaluation...\n", + "Evaluate annotation type *bbox*\n", + "DONE (t=58.87s).\n", + "Accumulating evaluation results...\n", + "DONE (t=7.76s).\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.337\n", + " Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.568\n", + " Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.350\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.152\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.359\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.496\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.279\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.432\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.460\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.257\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.494\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.623\n" + ] + } + ], + "source": [ + "!python3 test.py --data data/coco.data --save-json --img-size 416 # 0.565 mAP" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "VUOiNLtMP5aG" + }, + "source": [ + "Reproduce tutorial training runs and plot training results:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 417 + }, + "colab_type": "code", + "id": "LA9qqd_NCEyB", + "outputId": "1521c334-92ef-4f9f-bb8a-916ad5e2d9c2" + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAACvAAAAV4CAYAAAB8IQgEAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAewgAAHsIBbtB1PgAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzs3Xd0FNX///HXbkhCIKEHCIQaEkBB\naujVCnwoKiCiHwS/KoqoYPmpoAgKImBDlA+IIHxEsYEFRawE6VUIQSD0HkIIJRASQpL5/cFhPrsh\nuztpm0Sej3P2nLm7d+7cnXCY98687702wzAMAQAAAAAAAAAAAAAAAAAAAPAKe2F3AAAAAAAAAAAA\nAAAAAAAAALiekMALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAA\nAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAA\nAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAA\nAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAA\nAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcAL\nAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJ\nvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAX\nkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAA\neBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAA\nAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAA\nAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAK3fnz57Vs2TIt\n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\nde3aVWfOnDHfq1+/vvr166fatWvr3LlzWrZsmX7++WdlZmYqMzNTzz//vHx9fTVy5EhLx4iPj1fv\n3r114sQJlSlTRnfddZeaN2+u0qVL68CBA/rss8908OBBSVeW9x42bJi+/fbba9oJCwsztw8dOqT0\n9HRJUuXKlRUUFORUNzQ0NKenwjRz5ky99tprZtlut6tbt266+eabVbZsWe3fv19ffvml9u/frxkz\nZqhChQqW27506ZJuv/12rV692nyvUqVK6tOnj5o0aaLSpUvr8OHD+uabbxQTEyNJ+v3333X33Xdr\n6dKllpaFunjxovr06aPdu3erZMmS6t27t9q0aaOyZcvq2LFj+uqrr7R9+3ZJUkJCgh544AGtX7/e\n7bLfsbGx6tixoxISEsz3ypcvr549e6pJkyaqUKGCkpKStGvXLi1fvly7du1y28fExER16NBBsbGx\n5nuhoaG688471aBBA/n7+2vv3r36+uuvtX//fknS/PnzFRAQoA8//NDjOQAAOPNmbJEbN9xwg9q2\nbauGDRuqfPnySktL0/79+7VkyRLt2LFDknTmzBn16dNH27ZtU82aNbNt5+LFi7rrrruc4ppOnTqp\nS5cuCg0Nla+vr5KSkrR3715t3LhRGzZsUGZmZoG3ZUXt2rVVosSV28THjh1TamqqpCvX25zEGp4k\nJCSobdu22rdvn/le6dKl1a1bN7Vq1UqVKlVScnKy9u3bp5UrV+qvv/6y1K7NZlPz5s3Vpk0bhYWF\nqVy5ckpJSdGuXbv0ww8/mLHe4cOH1atXL0VHR6tMmTLXtHM13jt9+rR57kuWLKnq1atne9y8nJvi\nFAcDAIqfq/csJMnHx8dlvbS0NPXv31979+6Vj4+Punfvrk6dOqlixYo6deqUfvvtt2t+r+/du1cd\nO3bUiRMnzPciIiLUu3dvhYWFyW63a8eOHfryyy/NOhMnTlRgYKBGjRrltt8jRozQtGnTnN5r1aqV\nbrvtNtWoUUM2m00nTpzQxo0b9ccffzjFmLkRFxenAQMG6NKlS5KunKvbb79d7dq1U0hIiOx2u86e\nPavY2FitW7dO0dHReTqeo7feekujR482yz4+PurWrZu6du2qsmXL6uDBg/r666+1e/dus69dunTR\n+vXrne5RufPpp59qzJgxkqSGDRuqT58+qlu3ri5fvqwNGzbo888/V1pamiRp+vTpuv3229W7d+98\n+44AABSWzMxMp9/bvr6+buunpqbq1ltv1bp168z3goOD1adPH910000qVaqUDh8+rEWLFunvv/+W\nJP3yyy/q37+/fvzxR7dtf/755xo0aJAyMjLM98LCwtSzZ0+FhYWpdOnSOnXqlLZu3ao//vhDJ0+e\ntPQdg4KC1KFDB7Vs2VJVq1ZVQECATp06pQ0bNuiHH34w45vPPvtM1apV05QpUyy1C6CQFHYGMYB/\nNseZzUqWLGmkpaV55bhyGFXkbnT1k08+6VTX1Ww1V02cONGpvqsZhZmBFwBQXD311FNO159NmzYV\nyHEyMjKumX1t3Lhx2S47tGLFCqNixYpmPX9/f2P79u0u23aceezqrC3du3fPdtnklJQUo2fPnk79\n2LZtm9u+O85SZ+Uab3UG3iNHjhiBgYFm3fLlyxt//vnnNfXS0tKM4cOHO32/qy93M709/fTTTnWH\nDRtmnD9//pp6mZmZxpQpU5zqzpgxw2W7jrPaXO1Py5Yts+1Lenq68eijjzq1/f3337tsOzU11Wja\ntOk1/T537pzLfTZv3mz069fPOHToULaf33333WZbNpvNePXVV7MdgX7p0iVj5MiRTsdeunSpy+MC\nALLnrdjCMKzPwHvfffcZjz/+uNt4wjAMY968eU4zst1zzz0u686ZM8esFxAQYPz+++9u246LizNe\ne+21bGf2zc+2DCNnqwFkncHVE6sz8GZmZhrdu3d3qtu3b1+3s77GxsYaDz/8sLFq1apsP+/SpYsx\nevRot/FPenq6MXnyZKeZ555//nm33yk3y18bhvUZeItzHAwA8K7cPCNISEhwuu517drV6XPH65xj\nfOBqVllHly9fNlq1amXu5+fnZ8ycOTPba1hSUpIxYMAAs66vr6/b68wXX3zh1KcaNWoYy5Ytc1k/\nKSnJmD59uvHSSy9l+7mVGXjHjBlj1gkODvZ4Dvbv3288++yzxq5du7L93GoMER0dbfj6+pp1q1Sp\nku2Kj+np6caoUaOczkvHjh2NzMzMbNvNGovY7XbDx8fHmDZtWrZ/o61btzotv92sWTO33x8AgMKQ\nm3jozz//dNqnZ8+ebutnzRl54oknjAsXLlxTLyMjw3jjjTec6n700Ucu242NjTVKly7t9Jv+ww8/\nzPa6bBhXYq3vvvvOGDBgQLafb9myxWjcuLGxYMECt7P/Hj161OjUqZNTTOAqfrmKGXiBwkUCL4AC\nVbduXfMCXrduXa8d1zFocnVzJjk52ShbtqxZr0ePHh7bvXz5stPSUK6W/iSBFwBQXLVt29bpQYyV\npXVyY9GiRU7XuZEjR7qtv3LlSqdk1T59+ris65i4IMmIjIx0O4goMTHRKSZ48cUX3faloBJ4sya2\nukvWyczMNO66665rHrq5ShT5+++/nR7gPfnkkx77PXr0aLN+SEiIcfny5WzrOT4Uu/odz54967Ld\nS5cuGWFhYWb9e++912Xdd955x6ntF154wWO/3Vm6dKlTe2+//bbHfe677z6zfsuWLfN0fAC4Hnkr\ntjAM6wm8KSkpltt0TKb19fV1mXA6aNAgs97TTz+d064XWFuGUTQSeL/55hunegMHDnT5wMqqnPwd\nHRN0KlasaKSmprqsW9AJvMU5DgYAeFdunhG89957bn9HZ03gLVmypBEbG2upPzNmzHDad+HChW7r\np6enGx07djTr9+vXL9t6qampRuXKlc16VapUMQ4ePGipT65YSeB17Nt7772Xp+MZhvUYolevXma9\nEiVKGBs3bnTb7tChQ53Ou6uJaLLGIpLrSWiucox1JXlM7gEAwNtyGg+lpKQ4DTjydD3ctm2b07MT\nK/dhnn/+ebN+aGiokZ6enm29Hj16mPXsdrvxyy+/eGzbnUuXLrkcyJPV+fPnjfDwcMv3HkjgBQqX\n63VKASAfnD592twuW7ZsIfbkWqtXr9a5c+fM8tChQz3uU6JECT3yyCNmOTY21mnpRwAAirv4+Hhz\nu3r16vLz8yuQ48ycOdPcrly5ssaPH++2focOHTRkyBCz/OOPP+ro0aOWjvX++++7XSKpQoUK6tu3\nr1nesGGDpXbzU0pKir744guzfPfdd+uWW25xWd9ms+ndd9/1uPTTVdOmTZNhGJKk0NBQvfnmmx73\neeWVVxQcHCzpylKNP/zwg6VjTZ482W3c5+fnp8GDB5tlV+c7IyND7733nllu3LixJkyYYKkPrkyd\nOtXcjoyM1DPPPONxn3feecc8z5s2bdKWLVvy1AcAuN54K7bIiZIlS1qu++CDD5rLFF++fFnLli3L\ntp7jMtLh4eF56l9+tlVUvPPOO+Z2lSpVNGPGjGuW5M6pnPwdX3zxRQUGBkqSEhMTtXnz5jwdOy+I\ngwEABWXr1q0aM2aM03t33323232efPJJRUREeGzbMAyn3+j9+/d3uoZkx8fHx+l3+Pfff5/tstCf\nfvqp0/vvvfeeatWq5bFPeVUYMdeRI0f0008/meWhQ4eqZcuWbveZPHmyKlSoYJZnzJhh6Vg33HCD\nRowY4bbOwIEDVbp0abNMLAAAKK5SUlK0ePFitWnTxul6VqFCBafnEVm999575rOTmjVravLkyR6P\nNW7cOPPafPToUadr+1W7du3S0qVLzfLjjz+u22+/3fL3yY6fn59sNpuluoGBgXrxxRfN8i+//JKn\nYwMoWCTwAihQ58+fN7cdbwK4s337dtlsNo+vefPm5alvjoGb3W7XbbfdZmm/Hj16uGwHAIDizhuD\nb1JSUhQVFWWW77vvPjOhwp1hw4aZ2xkZGZZuODRo0ECtW7f2WK9NmzbmdmxsrMf6+W3lypVOA4se\nfvhhj/vUqlXL0g0fwzD01VdfmeXHHntM/v7+Hvfz9/dX//79zfIff/zhcZ+goCCPD/Ak5/N94MAB\nXb58+Zo6mzZt0qFDh8zyyJEjVaJECY9tu3LmzBn9+uuvZtnTQ6yrqlSp4hQnWjkPAID/KcoDe62w\n2Wzq2rWrWXaV+FmqVClze926dXk6Zn62VRTEx8dr1apVZnno0KFe/7dQqlQpp/ijsBJ4iYMBAPkt\nOTlZf/31l0aPHq127dopKSnJ/KxPnz5q1aqV2/0HDRpk6TjR0dHatWuXWbb6m7p58+a64YYbJF0Z\nDLVixYpr6ixcuNDcrlWrltO9iIJUGDHXzz//rIyMDLNsZWKZcuXKaeDAgWY5KipKqampHvd74IEH\nPCb5BAQEqEmTJmaZWAAAUNTdf//9qlevntOrevXqCgoKUp8+fRQdHW3WLVGihObNm6fy5ctn21Zm\nZqa+/vprs/z4449bmjQlICBA/fr1M8vZPTNYtGiRmRhss9n07LPPWv6O+cVxkpjY2FglJyd7vQ8A\nrCGBF0CBCgoKMreLWkCwZ88eczssLMzpZo079evXd5oxyLEdAACKO8fBN1aSCXLjr7/+Unp6ulnu\n1q2bpf1atmxpzggrWRtEYyVpQZKqVatmbp89e9bSPvlp48aN5raPj49TopA7VhJ4d+zYoTNnzphl\nq+dbktODPsc+utK8eXNLSbaO59swDKfk5ascE30k6c477/TYrjtr1qwxb5hJBXseAAD/443YoqBV\nqVLF3D527Fi2dZo2bWpuf/LJJ5o4caJSUlJydbz8bKsoyO9rem5Z+TsWNOJgAEBedO3a9ZqJTgID\nA9WiRQu98cYbTvFCo0aNNHfuXLftBQUFqVGjRpaOvXr1anO7bNmyatu2reV+u/tNnZmZqbVr15rl\n3r1753mWfqscY6433nhDs2fPznaAcX5yvIZXrVrVKXnWHceJZS5fvmxpdSBiAQDAP9Hx48e1b98+\np9fx48edBshIV3I6fv/9d/V4xQXXAAAgAElEQVTq1ctlWzExMU6Dn/LzmYHjvZCmTZuqdu3altvO\nL473QTIzMxUXF+f1PgCwhgReAAXKcVmf7BIzsuPv76+wsLBrXo43EfKDYyKL40MQT3x8fJy+l2M7\nAAAUd94YfJN18Evjxo0t73vTTTe5bCc7VatWtdSu40oBhTHoaPfu3eZ2WFiY5SWhrTxo27Ztm1O5\nYcOGlvvleIPHylLNuTnfUvbnfOfOneZ27dq1neKv3HA8D8HBwapYsaLlfXN6HgAA/1OUB/aePXtW\ns2fP1sCBA9WoUSNVqlTJXI7Q8fX666+b+7i6tzFkyBCnwb4vvfSSQkJCdP/99+vjjz/W3r17Lfcr\nP9sqChyv6X5+fjmK/ayIj4/Xe++9p759+6p+/fqqUKGCfH19r/k7fvbZZ+Y+Vu9R5TfiYABAQfP3\n99fw4cO1du1al7PNXVWnTh3LyzA7/qaOiIjIUZKtu9/Ux48fd7out2jRwnK7eeU4++3ly5f1yCOP\nKDQ0VA8//LAWLFhQIL//Ha/huY0DsrbjCrEAAOB61a5dO61evVqdO3d2W88xvrHZbKpfv77lY3h6\nZuB4L6Qg4pt169bpueeeU9euXRUaGqqgoCDZ7Xan+yABAQFO+xTWvRAAnuV+/VEAsKBy5crav3+/\npCs3YtLT0z3OyhYeHp7tw6jly5dbno3OCscbEVZn373K8YbGhQsXrvk8600vx9nerMq6j9UbaQAA\n5EWFChXM2TYKataNrINfcjKQxrGulUE0VhNhC5vjuc7t+XAlMTHRqZw1edYqK/8ecnu+s4uVHPtt\n9aGTO47tJSQk5Dq2YjYaAMgZb8QWOWUYht59912NHTs229/07rharrh27dr66KOP9NBDD5kzrJ47\nd04LFizQggULJEmhoaG644479O9//1tdunRxeYz8bKsocLwGX02uzQ9paWkaN26c3n77baWlpeVo\nXyvLThcE4mAAQF5Uq1bNKRHDZrOpVKlSKlu2rMLDw9W6dWvdfffdqlSpkqX2HAdaeeJ4Pd+4cWO+\n/abOes8iP37/W9WuXTtNmDBBL7/8svneyZMnNWfOHM2ZM0fSledV3bt31wMPPJAvyTe5nVgma92C\nigVy8ywLAABvioqKcroPcvHiRR06dEi///67pkyZoqNHj2rNmjVq1aqVoqKiVLNmTZdtOcYhhmFc\nk/BqVXb3u/L7+cZVu3bt0tChQ7Vy5coc71tY90IAeMYMvAAKVGRkpLmdmpqqv//+uxB748xx6c6L\nFy/maF/H5N/slgDNmhCcm1HLWR8i5jbZBgCAnHAcNXz8+PECWTrQ8bpYokSJHCVxeBpEU1w5npOc\n3CSyMggpv0ZV5zReyqv8XnK9uJ4HACjuvBFb5NTw4cP17LPPXhNL2Gw2VapUSTVq1HBaEchx9jp3\nSQ0PPPCAVq1a5XKGl6NHj2rOnDnq2rWr2rRpo+3bt3ulrcKW39d0ScrIyFC/fv30xhtvXJO86+Pj\no8qVK6tmzZpOf0fHJKXCSk4hDgYA5MVnn32mvXv3mq89e/YoOjpaK1as0Jw5czR06FDLybuSPE62\n4qigflM7xglS/sUKVr300ktaunSpmjVrlu3ne/bs0bRp09SyZUt1795dR44cydPxcjuxjL+/v3x8\nfMwysQAAAFeUKlVKDRs21JNPPqmYmBg1b95ckrR//351795dKSkpLvctqPjGMAyna3V+xTcxMTHq\n0KFDtsm7pUuXVkhIiOrUqeN0LyRrvwAUTczAC6BAdezYUe+//75ZXr58uZo0aVKIPfofxwdwCQkJ\nlvfLyMhwGt2c3TJU5cqVcypbGQ2dVdaRWp6WuwIAID9ERkZq7dq1kqRLly453fDIL443K9LT03X5\n8mXLyQueBtEUV44JGe5uKGVlJZk06wOhrDdtiirHJJv8eDDleB58fX3djrx3JzQ0NM99AYDriTdi\ni5xYsmSJZsyYYZbr1q2rESNG6NZbb1V4eHi2McnYsWP12muvWWq/devWWr58uXbv3q2ffvpJUVFR\nWr169TWzy61fv15t2rTRn3/+6XI2t/xsqzDl9zVdkmbOnKkffvjBLDdp0kRPPvmkunTpotq1azsl\nuFw1ePBgffLJJ/ly/NwiDgYAFFeOv6kDAgJUrVq1XLWTdb+sswAXRmJqt27d1K1bN23dulVLly7V\n8uXLtXbt2muSi3/++WdFRkZq/fr1qlWrVq6OlduJZS5duqSMjIxs2wEAAFeUK1dOixYtUqNGjZSc\nnKwdO3bo+eefd8pXceQY39hsNtWtWzdXx806KMpmsykwMNCMa/IjvsnMzNSDDz5o3hOy2+164IEH\nNHDgQLVs2VIVKlS4Zp/Lly/Lz88vz8cGUPBI4AVQoG6++Wb5+/vr0qVLkqQ5c+ZoxIgRhdyrK+rV\nq2du79u3TxcvXrQ04jk2Ntb8PtKVJZSyqlq1qux2uzIzMyVdWcogp3bu3Glu2+12p1mLAAAoKJ06\nddK0adPMclRUVL4n2WQdlJKQkGD5wY/joJt/0uAWx8E/ORlYZKVuxYoVncq7du3K0Sw7hcWx3ydO\nnMjX9qpUqaK9e/fmuU0AgGfeiC1ywrEvjRo10urVq1WmTBm3+2S3FKInERERioiI0MiRI2UYhrZs\n2aJvv/1Wc+bMUVxcnKQrCZmPPPKI/vrrL6+1VRgcr8GnT5/OUdKqK45/x1tvvVVLlizx+FAqN3/H\n/EYcDAAorhyv5y1atMjVss2e2pXy5/d/bjVt2lRNmzbVqFGjlJ6ervXr12vhwoWaN2+eGUfEx8dr\n5MiR+vbbb3N1jNxOLJO1LrEAAADZq127tkaNGqWXX35ZkjRjxgw9/vjjatiw4TV1HeMQm82m3bt3\ny27Pn4XsK1asaCbu5kd8s3r1am3evNksz5s3T4MGDXK7T1G4DwLAmvz5nwcAXKhYsaJT4BATE6Mf\nf/yxEHv0P61btza3MzMz9dtvv1nab+nSpS7buSooKEg33HCDWb4621BOrFu3zty+8cYbGVENAPCK\nrl27KiAgwCzPmTMn34/hOIhGkrZt22Z5X8e62Q2iKa4iIiLM7X379ik1NdXSflaWy65fv75T+fjx\n4znrXCFxjKUOHjyo06dP56k9x/OQkJBQJJZwB4DrgTdiC6syMzO1fPlys/zyyy97TN6VpAMHDuTp\nuDabTc2bN9f48eO1Z88edenSxfxsy5YtTgN4vdmWtzhe09PS0hQTE5On9o4dO6bdu3eb5QkTJlia\nUSavf8f8QBwMACiuHH9THzt2LN/arVatmtOgZsfElMJUokQJtW/fXu+++6727NnjlPTz448/XjM7\nr1WOsUBOYqKsMQOxAAAAro0YMcJMzs3IyNCLL76YbT3H+CYzMzNfBxI53gvJj/hm2bJl5najRo08\nJu9KReM+CABrSOAFUOCee+45p6ULH3nkkRyNLC4o7du3d7ox9OGHH3rcJz09XbNnzzbLDRo0cLmU\nws0332xuHzhwQKtXr7bct9WrVzsFVI5tAQBQkCpUqKDBgweb5Z07d2rhwoX5eozmzZs7zQD7yy+/\nWNpv8+bNTjFEdoNoiqvIyEhzOyMjQ1FRUZb2+/XXXz3WadGihdNAoD///DPnHSwEHTt2dCp/9913\neWqvc+fO5valS5ecBksBAAqON2ILqxITE5WWlmaWmzRp4nGftLS0HP2e96R06dKaOnWq03u5TbrN\nz7YKUocOHZzKeb2mZx2MZOXvmJCQoL///ttS+46zA19dWSm/EAcDAIorx9/UBw4c0JEjR/KlXbvd\nrnbt2pnlxYsX5/v1N68qVaqkN954wyynp6drz549uWrL8Rp+4sQJRUdHW9rPcWIZX19fNWvWLFfH\nBwDgehAYGKinnnrKLC9evDjbJNrIyEinFZrz89mJ4/ONrVu36uDBg3lqz/FeiJX7IJIsP2cCUPhI\n4AVQ4OrXr68JEyaY5RMnTqhz5846fPhwIfZKCggIcBqZtHTpUn3//fdu93nnnXe0a9cus/zYY4+5\nrDts2DDZbDaz/Mwzz1ia6S0tLU3PPPOMWbbZbBo2bJjH/QAAyC/PPvusU+LC448/rvj4+Fy1derU\nqWuSdAICApwGpyxYsMBcSsidmTNnmts+Pj664447ctWnoqhjx45OMwB+/PHHHvc5cuSIpRUESpQo\noTvvvNMsT58+PXed9LIWLVo4DZSaOnWq0tPTc91e1apVnRKIPvjggzz1DwBgXUHHFlYZhuFUtjLj\n/eeff57nWeCzcpx5X1Kerm/52VZBqVy5slPSz0cffaSkpKRct5ebv+N//vMfy8lAjgOf8tLP7BAH\nAwCKq8jISNWuXdss5+dv6v79+5vbhw4dKrTBXu7kV8zVrVs3pwlvrEwsc+7cOX3++edm+ZZbblHJ\nkiVzdXwAAK4XTzzxhNPv+1dfffWaOn5+furdu7dZzs/4pm/fvmauiGEYeuedd/LUnuO9ECv3QS5f\nvqxZs2bl6ZgAvIcEXgBe8cILL6hXr15meefOnWrWrJkmTZpk6UHFjh079N577+V7v0aNGqXy5cub\n5fvvv19LlizJtu7MmTM1atQosxweHq6hQ4e6bLtBgwb697//bZY3bNignj17uh2ZfuTIEfXs2VMb\nNmww3xs0aNA1S18DAFCQ6tWr5zSzSEJCQq4G36xdu1YtWrTQqlWrrvns0UcfNbdPnjypMWPGeGzL\nMam1V69eql69eo76U5QFBARo4MCBZnnRokUeR0c//fTTTrMIuvPCCy+YN4vWr1/v9Pe1wjAMXbp0\nKUf75JXdbteIESPMckxMjMd/J544LpX11VdfOT0AsyIjI6NIJkYBQFHnjdjCiooVKzrNrOLq9/9V\nx48f1//7f//PUtuHDh2y3I+syyXXqlWrwNoqKhwHKp84cULDhg27JhHXqho1ajiVPf0dY2JiNGnS\nJMvtO57DPXv2WI63rCIOBgAURz4+PnruuefM8tSpU3M8S52rZJOBAweqatWqZvmpp57KUTyUW3mJ\nuWrWrJmrY4aGhqpHjx5m+aOPPtKmTZvc7jNq1CglJiaaZXcTywAAgCsqVKigRx55xCz/8MMP+uuv\nv66p98ILL5jba9as0Ztvvpmj47h6dhIREaGePXua5enTp1taUdEVx3shy5cvV3Jystv6L7/8svbv\n35/r4wHwLhJ4AXiFzWbTwoUL9eCDD5rvnT59WqNGjVKlSpV0yy23aPTo0Zo6darmzZunWbNmacqU\nKRo6dKgaNWqkG2+80WmJRX9/f4WGhua5XyEhIZoxY4aZ0JKcnKyePXvq5ptv1pQpU/Txxx9rwoQJ\natmypYYNG2bO1lKyZEn997//VUBAgNv2//Of/6hhw4Zm+ddff1V4eLh69uyp119/XR999JFmz56t\niRMnqlevXgoPD3eaSe+GG24oNrPkAQD+WZ555hmnWVtjY2PVrFkzvfvuux4TOaOjo9W/f3+1a9fO\nZWLOnXfe6bRE4tSpUzV+/PhsZ0ZbvXq1+vTpY37m7+/vNLv/P8XLL79sjgg3DEP9+vXTypUrr6l3\n+fJljRgxQosWLZLdbu0nXaNGjZwSZ0aPHq3hw4d7nFHw1KlT+vDDD9WoUSOtXbs2B98mfzz22GNq\n3ry5WZ40aZKGDx/udja86OhoDRgwINt/e//617/Ut29fszxo0CC9+uqrHm92HT16VG+//bbCwsJ0\n9OjRXHwTAEBBxxZW+Pj4qGvXrmb5jTfecJl4snXrVnXq1EkJCQmWrrddu3bVXXfdpV9++UUZGRku\n6x07dsxpMHBISIgiIyMLrK2ionfv3k4PrhYsWKB77rnH7UzM+/bt02OPPaY1a9Y4vR8SEqIbb7zR\nLD/77LP6+++/s21j2bJluuWWW5Sammo5boqMjDTvE128eFFjxoyxNLuNVcTBAIDiaujQoWrTpo2k\nKysJdu/eXdOnT/e48uCePXs0btw4l0mv/v7+TjPexcfHq2PHjlq+fLnLNpOTkzVz5sw8DfStV6+e\nhgwZolWrVrkdWLRz506n5OVWrVo5JRzn1IQJE8zVKdLT09WrVy+tW7fumnoZGRl65ZVXNGPGDPO9\nTp06Oc0UCAAAXHv22Wfl5+dnlrObhbdp06ZOE4k8//zzeuqpp3TmzBm3bSckJGjmzJm68cYbtXHj\nxmzrvPPOO+Yzn8zMTPXp00cfffSRyxWCMjIy9OOPPzpN9nLVbbfdZm4nJibqoYceyvZ+2qVLl/TC\nCy9oypQplu+DACh8JQq7AwCuH35+fvr444/VunVrjRs3TidOnJB0JYhYtmyZli1b5rENm82mvn37\navLkyU5LKufFgAEDdOnSJT388MPmjaaoqCiXs94FBQXp+++/V9u2bT22HRgYqFWrVumee+7RH3/8\nIenK912yZInHGWJuvfVWffnll05LOwAA4C02m01fffWVhg4dqnnz5km6MvjmmWee0ZgxY3TzzTer\nRYsWCg4Olr+/v+Lj43X48GH9+uuvOnDggMf27Xa75s6dqzZt2pg3Ql555RV9/vnn6tevn2rVqqVz\n584pKipKS5cudUpemTRpklPSxj9FaGio3nzzTQ0bNkzSlfPdpUsX9ejRQzfffLPKlCmjAwcO6Isv\nvtC+ffskXUnEtZrEMWnSJMXExJijvP/zn/9o3rx56tatmyIjIxUcHCxJOnv2rPbu3astW7Zo06ZN\nbhOHCpqfn5+++OILdejQQSdPnjT7/cUXX6hnz55q2rSpypcvr6SkJO3evVt//vmntm/fLkmaPHly\ntm1+/PHH2rt3r6Kjo5WRkaFx48bpvffeU7du3dS8eXNVqFBBGRkZOnPmjGJjY7V582ZFR0d77TsD\nwD9VQccWVj3//PPm7/Hk5GTdfPPN6tWrl7p06aJy5copISFBUVFR+uWXX5SZmalq1aqpd+/emjlz\nptt2MzMz9d133+m7775TpUqV1L59ezVv3lyVK1dWQECAEhMTtWnTJn3//fe6ePGiud/kyZOveaCS\nn20VJXPnzlW7du20Z88eSdLChQu1dOlS9ejRQ61atVLFihV18eJF7d+/X6tWrTJXJ7r33nuvaeuF\nF17QAw88IOlKkk+LFi3Ut29ftW3bVqVLl9bx48f166+/asWKFZKkxo0bq0GDBvr666899rN69eq6\n7bbbzJhpypQpmjZtmmrXri1/f3+z3mOPPZarGfCIgwEAxZWvr6++/vprtW/fXocPH1ZKSoqeeOIJ\nvf766+rWrZsaN26s8uXL69KlSzp9+rR27NihjRs3KjY21mPbffv21ciRIzV16lRJV1Yr7Nq1q1q3\nbq3bb79doaGhstvtOnHihDZv3qzffvtNycnJGjx4cK6/T3p6uv773//qv//9r6pXr6727durSZMm\nqlSpknx9fXXy5EmtXbtWS5YsMVfjsdlsmjJlSq6PKUk33XSTJk6caK70cOLECXXo0EE9evRQ165d\nVaZMGR06dEhfffWV07mrUKGCPv74Y3OgEQAAcK969er697//ba5qs3jxYm3ZskXNmjVzqvfmm29q\n+/btZj7H+++/r48//lh33HGH+ezEMIxrnp24SsS9ql69epozZ47uu+8+ZWRkKDU1VUOHDtXkyZPV\nq1cv1atXT6VKlVJiYqK2bdum33//XXFxcQoLC7umrTZt2qhTp07mfY4vv/xS69ev14ABAxQREaG0\ntDTt2rVLixYtMichGTdunF555ZU8n0cAXmAAQCG4ePGi8e677xpt27Y1SpQoYUhy+fLx8TGaNGli\nvPbaa8ahQ4cste+4/+DBgy3ts3PnTqN3794u+1OyZElj8ODBxrFjx3L8fTMyMoyvv/7aaNOmjWG3\n211+V7vdbrRp08ZYuHChkZmZmePjAABQED744AOjUqVKbq/Xrq5rDz30kHH8+HGXbW/ZssWoUqWK\npfZsNpsxZcoUj/3t3Lmzuc/YsWMtfceoqCinY7lTq1Yts97cuXM9tj137lyzfq1atTzWHzNmjKXz\nMXz4cOPAgQNO7x04cMBt22lpacbQoUNz/LeUZKxYsSLbNgcPHpzjuCun/d67d68RERGRo/66a/P8\n+fNG7969c3UerMajAADXCiq2cKwbFRXl8vivvvqqpeMFBwcb69atM8aOHWu+17lz52zbdIwPrMY1\nEydOLPC2DCNnsUhO46icxFCGYRgnT540WrdunaPv5+pv+X//93+W9q9bt66xZ8+eHMUs+/btM2rW\nrOm23aznJ6fxTXGMgwEA3uV4DfcU31hlJa7x5MSJE0bbtm1zFct5Mm7cOLfPULK+XF3TrVz3c9p/\nPz8/45NPPnHZ95ye24kTJxo2m83SsUNCQoxt27a5bS+nschVubmvAwCAt+Q1Htq1a5dTbNGnT59s\n66WlpRkPPfRQjuMDScaaNWvc9mHx4sVGYGCg5fbCwsKybefw4cNG9erVLbXx0EMPGWlpaU7vrVy5\n0mUfHdudP3++y3rt27c3640fP97t9wZgXdGdkgHAP1pAQIBGjhypNWvW6PTp0/r99981f/58TZ06\nVRMmTNC0adM0f/58rVixQufOndPWrVs1ZswYl0ssZWUYhvm6OrOPJw0aNND333+vhIQEffvtt/rg\ngw/0+uuva8aMGfrpp5+UmJioefPmqVq1ajn+vna7Xf369dPatWuVmJioJUuWaNasWZo0aZImTZqk\nWbNmacmSJTp16pTWrl2rvn37MooaAFBkDB8+XPv379frr7+uZs2aebxG1ahRQy+88IJ27typ2bNn\nKyQkxGXdpk2baufOnXrqqacUFBSUbR273a6uXbtq/fr15uwk/2SvvfaaFi9enO0oa0mqWbOm5syZ\n47S8pFW+vr768MMPtXbtWvXo0cNp+ajs1KtXT08++aQ2bNigjh075vh4+SUsLEzbtm3Tm2++qRo1\narit27hxY7399ttuY7bAwEB9//33+umnn9SxY0ePsxU2atRIL774onbu3Gk5HgUAuFaQsYUVr7zy\nij799FOX1xR/f38NGDBA0dHRat26taU2p0+frsGDB6t69epu69ntdt1xxx1as2aNRo0aVeBtFTXB\nwcFas2aN5syZo4iICLd169Wrp3Hjxl0zM85Vs2fP1rvvvquKFStm+3lgYKAeffRRbdmyRfXq1ctR\nP+vWravo6Gi99dZbuuWWW1S1alWVLFkyR214QhwMACiuqlSpolWrVmnBggUur9NX2e12RUZGavz4\n8ZZWVRg7dqz++usv9ezZU76+vi7rBQUF6b777tNTTz2V4/5f9emnn+qee+5RpUqV3Nbz8/NTv379\ntHXrVg0aNCjXx8tq1KhRWrt2rbp06eIyHi5TpoxGjhypHTt2qHHjxvl2bAAArhf169fXXXfdZZa/\n//57bdmy5Zp6vr6+mj17tlavXq1u3bq5jUMkKTw8XE899ZQ2bdrkceXmXr16ac+ePXrsscdUpkwZ\nl/V8fX1166236q233sr28xo1amjTpk3q16+fy9ghIiJC8+fP1+zZs8k3AYoRm2EYRmF3AgAAAEDx\nkZCQoI0bN+rkyZM6deqU0tPTVa5cOYWEhKhFixYKDQ3NVbtpaWlauXKl9u/fr1OnTql06dIKCQlR\n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\n115J1k6/tb8mhTkdqvBIFUakDEP60pui27xz1Ts6XMeLj+mk26uTRlWBcMvtg7kAACAASURBVHWM\nKlWUujgNTTmrj/7tol9ZGaruLsoNfc+hJC0tzcodOTk5uvjiixtsW1hYaD3qOT4+XnFxcUEzZlsa\nmDZK//zh/2p4zlxbi3grTafuqbytqpDdRg5Deqo5/7YAAKCDkFNaryqnPK70nPvkMpryjJDGeUyH\n7q683faMIrXgM1AAANpRaP+0DACAzqqpj7purM1PX0lbnpW+XdXix2UDAICONTk9UYPiY+oV59R8\ndDfal8fj0fz5863XS5YsqVVIW+3xxx/XP/7xD+Xm5mrTpk368MMPdcUVVwTEmE8++aSOHz8uqarw\nt2bxbrVRo0bpkUce0T333CO326358+frrbfeatH8AQC1NVQM3Nwi4dbuju9vR+K686jbtu7r6l2H\nfRUn/2Zkcr3diKX6RctSVeFwF4dDFV6v8opO6NXsvVq9rUBmnQw0OCGmwYJjX4XJ1X36+n/kaxdl\nX99jKJkwYYKeeOIJSdKaNWt03333Ndh29erV1nFGRkZQjdnWRv76Fv2r31k68vH/q2HH/qFIo1Km\nKRmnLsHmHJebYVrlveCXXaht4nQYujglTndfnsK/LQAAQYGcYo/qnHL8fx9WWtmn1lMsmptV3KZD\n673peso9zfbi3XCXQ78+qw+fgQIAApphmqY9t8Og1fbt26fk5GRJUn5+vpKSkjp4RgCATsHrbfxR\n1421aUofzcCaF1z4/QKAziOUd4FrqvZY99avX69LLrlEkjR27Fht2LChwbavvfaabrrpJklSZmam\nXnvttYAYs3///vrhhx8kSXv27NGAAb4fQVhcXKzevXvrxIkTOu2001RUVKTIyMgWfQ++kFMAAE3R\nGTJQsK15Ho9HSUlJOnDggCTp888/14gRI3y2GzlypHJzcyVJa9eu1fjx44NmzIa0xe+X1+NReVmJ\nunSJVHlZiSQpIjK6acflpVJYpCLCwlTurtrNN8LltOW45q7TAIDQRE4JzDEb0lY5pbTkZ0nNyCfV\nx1FdVe6pKluyK59EuJwN3nwHAAgdwZJRWl+B04ZWrlypadOmqX///oqIiFB8fLxGjx6tJ554wtrl\nxQ7FxcVavny57rjjDo0ePVpxcXEKCwtT165dNXjwYM2YMUNr164Vtc4AgKBU/ahrf4W3jbVpSh8A\n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\nBEGAIAgICQkp9zZnz54Vn8/Ozoajo6P5F6Hh5ZdfFuMJgoARI0bo7YcgCGU6FxEREVUd06dP15oD\n9OrVy+IxzX0Q0bNDIvBfNRGVUUFBAc6ePYvIyEikp6ejdu3aqFevHnr27AkXF5eK7p7JHj16hAsX\nLuDBgwd4+PAhlEolnJ2dUbt2bTRr1gz+/v6ws7Mrt/6kpqYiLCwMycnJePr0KerUqQMfHx90797d\nIh/YpKam4uzZs0hJSUFaWhpkMhlcXV3RqFEjdO7cucxvdBERUeX0rIzbSUlJiIiIgEKhgEKhgEQi\ngYuLC+rXr48OHTqU+ks2T58+xcmTJ3Hnzh08fvwYzs7OqF+/PoKDg6vU/bEUlUqFkydPIi4uDunp\n6fD29oavry+CgoIsdo60tDSEh4fj/v37ePToEeRyOVxcXNCsWTP4+fkZTJatKGq1GhcvXkRMTAwU\nCgXy8/Ph4uICHx8fBAYGmp2gAwApKSn466+/xLmZnZ0dXF1d0bx5c/j5+VXL3z8iqho4tygbpVKJ\n8PBwxMTEICsrC3Xq1EGDBg0QHByMGjVqlDrujRs3EBsbizt37iAjI0O8nhYtWqBDhw5mJSBbMlZl\nFBUVhYiICDx48ABKpRJOTk5o0qQJAgICdCbu6pKZmYmwsDDcuHEDOTk58PT0RKNGjdCzZ0/Y2NhY\n+Qosg/NgIiIiIiIiIiKi8scEXiIiIiIiIiIiIiIiIiIiIiIiIiIionJkeK9SIiIiIiIiIiIiIiIi\nIiIiIiIiIiIisigm8BIREREREREREREREREREREREREREZUjJvASERERERERERERERERERERERER\nERGVIybwEhERERERERERERERERERERERERERlSMm8BIREREREREREREREREREREREREREZUjJvAS\nERERERERERERERGRxalUKkRHRyMkJASvvPIKunTpgho1akAikUAikWD69OlWO/e+ffswduxYNG7c\nGPb29vDw8EDXrl3xySefICMjw2rnJSIiIiIiIiIylbyiO0BERERERERERERERETPnnHjxmHXrl3l\nes6srCxMmjQJ+/bt03peoVBAoVDgzJkzWLNmDXbs2IHOnTuXa9+IiIiIiIiIiDRxBV4iIiIiIiIi\nIiIiIiKyOJVKpVV2dXVF8+bNrXq+sWPHism7np6eWLx4MbZs2YKvv/4a3bp1AwAkJSVhyJAhiI2N\ntVpfiIiIiIiIiIiM4Qq8REREREREREREREREZHEdO3ZE69atERgYiMDAQDRp0gQhISGYMWOGVc63\nbt06HDp0CADg6+uLY8eOwdPTU3x97ty5WLBgAVavXo20tDS8+OKLCAsLs0pfiIiIiIiIiIiMkQiC\nIFR0J4iIiIiIiIiIiIiIiOjZp5nAO23aNISEhFgkrkqlQoMGDZCcnAwA+PvvvxEQEKCzXocOHRAR\nEQEAOHz4MAYMGGCRPhARERERERERmUNa0R0gIiIiIiIiIiIiIiIiKouwsDAxeTc4OFhn8i4AyGQy\nvPrqq2J569at5dI/IiIiIiIiIqLimMBLREREREREREREREREVVpoaKh4PGTIEIN1Bw8erLMdERER\nEREREVF5kld0B+gfSqUSUVFRAAB3d3fI5fzxEBHRs6mgoAAKhQIA4OfnB3t7+wruERnCOQoREVUn\nnKdULZynEBFRdcE5inFFcwIACAoKMljXy8sLDRo0QFJSElJTU6FQKODu7m6xvnCOQkRE1QnnKVUL\n5ylERFRdVJU5CkfiSiQqKgodO3as6G4QERGVq/Pnzxv9UIUqFucoRERUXXGeUvlxnkJERNUR5yi6\nxcXFicdNmjQxWr9JkyZISkoS25qTwHv37l2Dr0dERGDYsGEmxyMiInpWcJ5S+fG9FCIiqo4q8xyF\nCbxERERERERERERERERUpT158kQ8rlOnjtH6bm5uOtuaokGDBmbVJyIiIiIiIiLShQm8lYjmt7vP\nnz8Pb2/vCuwNERGR9SQnJ4vf7rXk9oRkHZyjEBFRdcJ5StXCeQoREVUXnKMYl5WVJR6bsi2mg4OD\neJyZmWmVPgGcoxAR0bOP85Sqhe+lEBFRdVFV5ihM4K1E5PJ/fhze3t6oX79+BfaGiIiofGiOf1Q5\ncY5CRETVFecplR/nKUREVB1xjlLxkpKSDL6u+SEh5yhERFSdcJ5S+fG9FCIiqo4q8xyl8vaMiIiI\niIiIiIiIiIiIyASOjo5IS0sDACiVSjg6Ohqsn5OTIx7XqlXLrHMx0YWIiIiIiIiILEFa0R0gIiIi\nIiIiIiIiIiIiKgsXFxfx+OHDh0brP3r0SGdbIiIiIiIiIqLywgReIiIiIiIiIiIiIiIiqtJatmwp\nHicmJhqtr1lHsy0RERERERERUXlhAi8RERERERERERERERFVaX5+fuLxhQsXDNZNTU1FUlISAMDD\nwwPu7u5W7RsRERERERERkS5M4CUiIiIiIiIiIiIiIqIqbdCgQeJxaGiowboHDx4Uj4cMGWK1PhER\nERERERERGcIEXiIiIiIiIiIiIiIiIqrSgoOD4eXlBQA4ceIELl26pLOeSqXCV199JZYnTJhQLv0j\nIiIiIiIiIiqOCbxERERERERERERERERUaYWEhEAikUAikaBXr14668hkMixZskQsT506FQ8ePChR\nb9GiRYiIiAAAdOvWDQMHDrRKn4mIiIiIiIiIjJFXdAeIiIiIiIiIiIiIiIjo2ZOYmIj169drPXfl\nyhXx+PLly1i8eLHW63369EGfPn1Kdb5Zs2Zh9+7d+OOPP3D16lX4+/tj1qxZ8PX1xePHj7F161aE\nh4cDAFxcXLB27dpSnYeIiIiIiIiIyBKYwEtEREREREREREREREQWd/v2bXzwwQd6X79y5YpWQi8A\nyOXyUifwyuVy/Pbbb5g4cSJ+//13pKSkYPny5SXq1a9fH9u3b8dzzz1XqvMQEREREREREVmCtKI7\nQERERERERERERERERGQJtWrVwv79+7Fnzx48//zzaNCgAezs7FCnTh106tQJq1atQnR0NLp27VrR\nXSUiIiIiIiKiao4r8BIREREREREREREREZHF9erVC4IglDnO9OnTMX36dLPajBgxAiNGjCjzuYmI\niIiIiIiIrIUr8BIREREREREREREREREREREREREREZUjJvASERERERERERERERERERERERERERGV\nIybwEhERERERERERERERERERERERERERlSMm8BIREREREREREREREREREREREREREZUjJvASERER\nERERERERERERERERERERERGVIybwEhERERERERERERERERERUZWmVgvIziuAWi1UdFeIiIiICADU\naiDvaeF/SSd5RXeAiIiIiIiIiIiIiIiIiIiIqDRi7mdgXXgCQqNSkJOvgoONDIP9vDCze1P41nUC\nUJjcqyxQwVYqhbJABQCoYSuHVCrRet1eLhOfKyt9MU05V1EycvF+EhEREVUJKVHAmW+AmL1AfjZg\nUwPwHQF0mQt4+VV07yoVJvASERERERERERERERERERFRlbM34h7m74hEgcaquzn5Kuy6dA/7Iu7j\njf4tEK/IwoErycgt0F75TSoBAhrWhpODDc7cfKQ3+ddcxROK7eVSDGrjiR7NPXA6/iFCo/UnGsfc\n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\niIhIaPJW+uYswYR3AbxuOLzHN7/x7xuBm4laie32RQzmoyorSNSn1I6mnKj6G0bADy/pEXJ4t/lV\nm7TbqsArrdlV0yHvpcD/MJpO312cIiIiIiIiItIsrrzySgYMGMBll13GZZddRp8+fViyZAk/+tGP\nIt7XRRddFFSIdvXq1f7wbnJyMkOHDq13n8GDBzN27NgGj7EtqRHg/dbdTCMRERERkbbAsuwqS9ma\npsHo1ERW7TrY3EOr1wDjc6Y4sxltbifOOIXH9gUJnIYVVuWyVsnywLYFvgqylUUqjBpKldz6VA/h\nqniUiIhI21ecF0YA1/bNb666q92Fd922g9+6bwdgWdRDdDaCm4dlW9/BpvHnSg7TYPLQPo3eT6TZ\n1QO8qAKvtGaJqb6lWOr6B9J0+l6vWIJFRERERERERJrc7Nmzm3sINTzzzDP+7WCq70rtzj7LVeWx\nKvCKiIiISDjyi0pYlPMp6/OKKXN7iXU5GJ2ayIjkBI6XtvybxMaY75DlWlilMpnTOFNJq12Edyvk\nr4GM+Y0TcA2lSm59agvhqniUiIhI27ZtfngB3Pw1viqp7Si867FNZrp/wl77fAD22efzXWNvvfu5\nbQeLPaMbe3iYBszNTCOlR8dG7yviqn05MFSBV1q91Im+pVje+C188uaZ5w0nTN0E3S9ptqGJiIiI\niIiISMtz6NAh1q9fD4DT6eS2225r5hG1XjUq8CrAKyIiIiIhWpt7kJkrduOxzlSeKnN7WbXrYKup\nvFs9vNuuuUt9lXIjUXG3ulCq5AY8Th0hXBWPEhERabssC/LXhrevuxT2hrqvQXNWVg13BQjbhu3W\nRfzWc7s/vAtQYtc/t3Pbjiqh38ZgGjDiogRmXJfcOsO7AEb7XslBAd62KjEVbsiC/0s785ztgc69\nmm9MIiIiIiIiItIiPffcc3i9vovrP/zhD0lMTGzmEbVeNQK837qxbRujXZUYExEREZFw5ReV1Ajv\ntha/uj6ZhzfsZ4ozW+Hdylxxvkq5jSWYKrmG6UusWLX8XOoL4VYUj9q2wFdtz13qe08pY32hX4V3\nRUREWidPWfhV/J2x4C4Lvn3cuZD+Z1g1tdmq9hpGgBCv6YTh98PRA/75jseM4VX3ZfzVk06+3adK\nc6dpcE6XBDhWe1+ldjTZ1ndY7BkdkfDuyh9fxbLthWTnHaLM7SXGaTIypRu3DenN4PPOxjRb+7nn\n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\nhNtrjG2pTu/qyvzNiYfn7/766B5TNDB27Nhi7li+fHk++9nPNtl3/fr1qaurS5IMGTIkgwcP7jJz\ntre/+puv5/8cdWLe+eX/n0+8+6v0rdh+ADdBV//lJujJJb9197NjBuc7nx/TY/Y3AF2bnFIau3PK\ne//rf2Tstv/Y57do7G97R6Eyi3eelFt3TC1pRknSI3M4AF2PAl4AAACAMmpoaMj1119ffH3//ffv\nVUi720033ZRf/epXWbFiRZYuXZonn3wyZ511VqeY8/vf/37ee++9JLsKf/cs3t3t1FNPzQ033JAr\nr7wyO3bsyPXXX58HH3ywTesHoGWVlRXpd9Cub/lXZ1eRb2tu//1ou61j7C4o3rmzUCwo7ohC4s4y\nxoc7d6ZPdVUqKyvSk5xzzjm5+eabkyQLFy7M1Vdf3WTfJ554otiePHlyl5qzHEaPPTWjx87PzoaG\nbN22JQcd1Df127YkSfr07b9/7fqtSa++Ob9Xr5xzAF8HjbX7HVTd4/Y3AF2bnFI6o8eemoxdlJ0N\nDdmy5c9JWpFPdrf7DchnGgr5eUqXT3pyDgeg6/H7rwEAAADK6JlnnsnatWuTJBMnTsz48eMb7VdV\nVZUrrrii+HrevHmdZs758+cX29/+9rebnHfGjBk5+OBdv8VhwYIF2bZtW6vXDkDXtLuguLq6Mv37\n9Er/Pr3a1O7qY/TU4saJEydm2LBhSZIlS5bkxRdfbLRfQ0NDbrvttuLradOmdak5y6myqir9+h+S\n6oMOSv9DDk3/Qw7d//aAgenft/cBfx001u6J+xuArk1OKb3KqqrW55Pd7V7VJc8nPTmHA9D1dOoC\n3gULFmTq1KkZNWpU+vTpkyFDhmTChAm5+eabi7e8lMLmzZvz8MMP5/LLL8+ECRMyePDg9OrVKwMG\nDMhxxx2XSy65JIsWLUqhUCjZnAAAAEDPtHDhwmK7pZtUzj333Eaf68g5f/e73+WNN95Ikhx//PE5\n+uijmxyrpqYmp59+epLk/fffz69//etWrRsA6JqqqqoyZ86c4utLLrkkGzZs2Kff7Nmzs2LFiiTJ\naaedlrPPPrvR8e69995UVFSkoqIikyZNKsucAED3JKcAAJ1JdUcvoDFbtmzJxRdfnAULFuz15xs3\nbszGjRvz3HPP5fbbb89DDz2UU0899YDmuvXWW/O9730v9fX1+7y3efPmrF69OqtXr87999+f008/\n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\n8CxevDjHHnvsfj1vn0H34muQcnB2sD9kFOCjfB3S3pwd7C85BSglX8OUkjOGPckswIHwNUspOVP4\nKDmFnkwBbycxceLEDBs2LEmyZMmSvPjii432a2hoyG233VZ8PW3atLKsj+7jy1/+crF96623Ntnv\nRz/6Ud5///0kyXnnnVe8Hr6psebOnVvs/1F/+tOf8tBDDyVJ+vbtmylTprRp7ZTH5ZdfXgxFw4YN\ny+LFi/Pxj3+8VWPYZ9B9yCiUi7ODlsgowEfJKZSDs4P9IacApSTjUGrOGHaTWYADIaNQas4U9iSn\n0KMV6DTuuOOOQpJCksIJJ5xQWL9+/T59rrrqqmKf0047rQNWSWdyzz33FPfDpZdeul/PrF+/vlBT\nU1NIUqisrCw8+uij+/R5/vnnC/369SskKVRXVxdWrVrV5Hhf+tKXimv4yle+Uti+ffte72/evLkw\nceLEYp/vfe97rfocKa/LL7+8+Hc1bNiwwiuvvNKmcewz6F5kFFpLRqHUZBSgKXIKrSGj0B7kFKA9\nyDg0RZ6hrWQWoBRkFJoio3Ag5BR6uopCoVBovsSXctmxY0cmT56cp556KsmunyiYMWNGamtr8847\n72TevHl59tlnkyQDBw7Ms88+mxNOOKEjl0wZrVmzJnffffdef/bb3/42jz32WJLkxBNPzN/+7d/u\n9f7nPve5fO5zn9tnrPvuuy/Tp09PklRWVmbatGn5/Oc/n6qqqixbtiz33Xdf6uvrkyQ33nhjvvvd\n7za5rj/96U859dRT8+abbxbXMX369Bx++OF5/fXXc9ddd+X1119Pkpx00klZunRp+vfv37b/EWhX\n1157bW688cYkSUVFRf7lX/4lxx13XIvPjR8/vvirCPZkn0H3IaPQHBmF9iajAM2RU2iKjEI5yClA\ne5FxSOQZSkdmAUpFRiGRUSgtOQXiBt7O5r333iv8zd/8TbE6v7GPESNGFJYtW9bRS6XMFi9e3Oy+\naOzjuuuua3K8O+64o9CnT58mn62qqirMmTNnv9a2cuXKwnHHHdfsWiZMmFBYu3Ztif7XoD3s+ZNB\nrfm45557mhzTPoPuQ0ahKTIK7U1GAVoip9AYGYVykFOA9iTjIM9QKjILUEoyCjIKpSSnQKFQHTqV\nmpqaPPbYY3n00Ufz05/+NMuXL8+GDRtSU1OT0aNH58ILL8zMmTNzyCGHdPRS6eK+8Y1v5Mwzz8yd\nd96ZRYsWpa6uLjt37szhhx+eM844I1//+tfzyU9+cr/Gqq2tzW9+85vcfffd+fnPf55XXnklmzZt\nyqBBg3LiiSfmoosuysUXX5zKysp2/qzobOwz6D5kFMrF2UE52GfQvcgplIOzg3Kx14DdZBxKzRlD\nKdlP0HPJKJSaM4VSs6foaioKhUKhoxcBAAAAAAAAAAAAAD2F8m8AAAAAAAAAAAAAKCMFvAAAAAAA\nAAAAAABQRgp4AQAAAAAAAAAAAKCMFPACAAAAAAAAAAAAQBkp4AUAAAAAAAAAAACAMlLACwAAAAAA\nAAAAAABlpIAXAAAAAAAAAAAAAMpIAS8AAAAAAAAAAAAAlJECXgAAAAAAAAAAAAAoIwW8AAAAAAAA\nAAAAAFBGCngBAAAAAAAAAAAAoIwU8AIAAAAAAAAAAABAGSngBQAAAAAAAAAAAIAyUsALAAAAAAAA\nAAAAAGWkgBcAAAAAAAAAAAAAykgBLwAAAAAAAAAAAACUkQJeAAAAAAAAAAAAACgjBbwAAAAAAAAA\nAAAAUEYKeAEAAAAAAAAAAACgjBTwAgAAAAAAAAAAAEAZKeAFAAAAAAAAAAAAgDJSwAsAAAAAAAAA\nAAAAZaSAFwAAAAAAAAAAAADKSAEvAAAAAAAAAAAAAJSRAl4AAAAAAAAAAAAAKCMFvAAAAAAAAAAA\nAABQRgp4AQAAAAAAAAAAAKCMFPACAAAAAAAAAAAAQBkp4AUAAAAAAAAAAACAMlLACwAAAAAAAAAA\nAABlpIAXAAAAAAAAAAAAAMpIAS8AAAAAAAAAAAAAlJECXgAAAAAAAAAAAAAoIwW8AAAAAAAAAAAA\nAFBGCngBAAAAAAAAAAAAoIwU8AIAAAAAAAAAAABAGSngBQAAAAAAAAAAAIAyUsALAAAAAAAAAAAA\nAGWkgBcAAAAAAAAAAAAAyuj/Ak+HcVyOTkwvAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": { + "image/png": { + "width": 800 + }, + "tags": [] + }, + "output_type": "execute_result" + } + ], + "source": [ + "!python3 train.py --data data/coco_16img.data --batch-size 16 --accumulate 1 --nosave && mv results.txt results_coco_16img.txt # CUSTOM TRAINING EXAMPLE\n", + "!python3 train.py --data data/coco_64img.data --batch-size 16 --accumulate 1 --nosave && mv results.txt results_coco_64img.txt \n", + "!python3 -c \"from utils import utils; utils.plot_results()\" # plot training results\n", + "Image(filename='results.png', width=800)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "14mT7T7Q6erR" + }, + "source": [ + "Extras below\n", + "\n", + "---\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 0, + "metadata": { + "colab": {}, + "colab_type": "code", + "id": "42_zEpW6W_N1" + }, + "outputs": [], + "source": [ + "!git pull" + ] + }, + { + "cell_type": "code", + "execution_count": 0, + "metadata": { + "colab": {}, + "colab_type": "code", + "id": "9bVTcveIOzDd" + }, + "outputs": [], + "source": [ + "%cd yolov3" + ] + }, + { + "cell_type": "code", + "execution_count": 0, + "metadata": { + "colab": {}, + "colab_type": "code", + "id": "odMr0JFnCEyb" + }, + "outputs": [], + "source": [ + "%ls" + ] + }, + { + "cell_type": "code", + "execution_count": 0, + "metadata": { + "colab": {}, + "colab_type": "code", + "id": "uB3v5hj_CEyI" + }, + "outputs": [], + "source": [ + "# Unit Tests\n", + "!python3 detect.py # detect 2 persons, 1 tie\n", + "!python3 test.py --data data/coco_32img.data # test mAP = 0.8\n", + "!python3 train.py --data data/coco_32img.data --epochs 3 --nosave # train 3 epochs" + ] + }, + { + "cell_type": "code", + "execution_count": 0, + "metadata": { + "colab": {}, + "colab_type": "code", + "id": "6D0si0TNCEx5" + }, + "outputs": [], + "source": [ + "# Evolve Hyperparameters\n", + "!python3 train.py --data data/coco.data --img-size 320 --epochs 1 --evolve" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "collapsed_sections": [], + "name": "ultralytics/YOLOv3", + "provenance": [], + "version": "0.3.2" + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.4" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} From 6e19245dc8dd9a16d8e48a9b9493f53384b8bbd1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 9 Apr 2020 19:53:29 -0700 Subject: [PATCH 0638/1185] auto strip optimizer from best.pt after training --- train.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/train.py b/train.py index 5c470e3e31..0429273641 100644 --- a/train.py +++ b/train.py @@ -362,14 +362,13 @@ def train(): n = opt.name if len(n): n = '_' + n if not n.isnumeric() else n - fresults, flast, fbest = 'results%s.txt' % n, 'last%s.pt' % n, 'best%s.pt' % n - os.rename('results.txt', fresults) - os.rename(wdir + 'last.pt', wdir + flast) if os.path.exists(wdir + 'last.pt') else None - os.rename(wdir + 'best.pt', wdir + fbest) if os.path.exists(wdir + 'best.pt') else None - if opt.bucket: # save to cloud - os.system('gsutil cp %s gs://%s/results' % (fresults, opt.bucket)) - os.system('gsutil cp %s gs://%s/weights' % (wdir + flast, opt.bucket)) - os.system('gsutil cp %s gs://%s/weights' % (wdir + fbest, opt.bucket)) + fresults, flast, fbest = 'results%s.txt' % n, wdir + 'last%s.pt' % n, wdir + 'best%s.pt' % n + for f1, f2 in zip([wdir + 'last.pt', wdir + 'best.pt', 'results.txt'], [flast, fbest, fresults]): + if os.path.exists(f1): + os.rename(f1, f2) # rename + ispt = f2.endswith('.pt') # is *.pt + strip_optimizer(f2) if ispt else None # strip optimizer + os.system('gsutil cp %s gs://%s/weights' % (f2, opt.bucket)) if opt.bucket and ispt else None # upload if not opt.evolve: plot_results() # save as results.png From b98ce11d3a1d5905dcacb5d7cf28c5746ed5d967 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 9 Apr 2020 20:20:23 -0700 Subject: [PATCH 0639/1185] add MixConv2d() layer --- examples.ipynb | 471 ------------------------------------------------- 1 file changed, 471 deletions(-) delete mode 100644 examples.ipynb diff --git a/examples.ipynb b/examples.ipynb deleted file mode 100644 index bebc3088f4..0000000000 --- a/examples.ipynb +++ /dev/null @@ -1,471 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "ultralytics/YOLOv3", - "version": "0.3.2", - "provenance": [], - "collapsed_sections": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "accelerator": "GPU" - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "HvhYZrIZCEyo" - }, - "source": [ - "\n", - "\n", - "This notebook contains software developed by Ultralytics LLC, and **is freely available for redistribution under the GPL-3.0 license**. For more information please visit https://github.com/ultralytics/yolov3 and https://www.ultralytics.com.\n", - "\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "e5ylFIvlCEym", - "outputId": "fbc88edd-7b26-4735-83bf-b404b76f9c90", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 34 - } - }, - "source": [ - "import time\n", - "import glob\n", - "import torch\n", - "import os\n", - "\n", - "from IPython.display import Image, clear_output \n", - "print('PyTorch %s %s' % (torch.__version__, torch.cuda.get_device_properties(0) if torch.cuda.is_available() else 'CPU'))" - ], - "execution_count": 2, - "outputs": [ - { - "output_type": "stream", - "text": [ - "PyTorch 1.1.0 _CudaDeviceProperties(name='Tesla K80', major=3, minor=7, total_memory=11441MB, multi_processor_count=13)\n" - ], - "name": "stdout" - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "7mGmQbAO5pQb", - "colab_type": "text" - }, - "source": [ - "Clone repository and download COCO 2014 dataset (20GB):" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "tIFv0p1TCEyj", - "outputId": "e9230cff-ede4-491a-a74d-063ce77f21cd", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 221 - } - }, - "source": [ - "!git clone https://github.com/ultralytics/yolov3 # clone\n", - "!bash yolov3/data/get_coco_dataset_gdrive.sh # copy COCO2014 dataset (19GB)\n", - "%cd yolov3" - ], - "execution_count": 0, - "outputs": [ - { - "output_type": "stream", - "text": [ - "Cloning into 'yolov3'...\n", - "remote: Enumerating objects: 61, done.\u001b[K\n", - "remote: Counting objects: 100% (61/61), done.\u001b[K\n", - "remote: Compressing objects: 100% (44/44), done.\u001b[K\n", - "remote: Total 4781 (delta 35), reused 37 (delta 17), pack-reused 4720\u001b[K\n", - "Receiving objects: 100% (4781/4781), 4.74 MiB | 6.95 MiB/s, done.\n", - "Resolving deltas: 100% (3254/3254), done.\n", - " % Total % Received % Xferd Average Speed Time Time Time Current\n", - " Dload Upload Total Spent Left Speed\n", - "100 388 0 388 0 0 2455 0 --:--:-- --:--:-- --:--:-- 2440\n", - "100 18.8G 0 18.8G 0 0 189M 0 --:--:-- 0:01:42 --:--:-- 174M\n", - "/content/yolov3\n" - ], - "name": "stdout" - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "N3qM6T0W53gh", - "colab_type": "text" - }, - "source": [ - "Run `detect.py` to perform inference on images in `data/samples` folder:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "zR9ZbuQCH7FX", - "colab_type": "code", - "outputId": "49268b66-125d-425e-dbd0-17b108914c51", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 477 - } - }, - "source": [ - "!python3 detect.py\n", - "Image(filename='output/zidane.jpg', width=600)" - ], - "execution_count": 0, - "outputs": [ - { - "output_type": "stream", - "text": [ - "Namespace(cfg='cfg/yolov3-spp.cfg', conf_thres=0.5, data='data/coco.data', fourcc='mp4v', images='data/samples', img_size=416, nms_thres=0.5, output='output', weights='weights/yolov3-spp.weights')\n", - "Using CUDA with Apex device0 _CudaDeviceProperties(name='Tesla K80', total_memory=11441MB)\n", - "\n", - "image 1/2 data/samples/bus.jpg: 416x320 3 persons, 1 buss, 1 handbags, Done. (0.119s)\n", - "image 2/2 data/samples/zidane.jpg: 256x416 2 persons, 1 ties, Done. (0.085s)\n", - "Results saved to /content/yolov3/output\n" - ], - "name": "stdout" - }, - { - "output_type": "execute_result", - "data": { - "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAMEBgUGBgYF\nBgYGBwkIBgcJBwYGCAsICQoKCgoKBggLDAsKDAkKCgr/2wBDAQICAgICAgUDAwUKBwYHCgoKCgoK\nCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgr/wAARCALQBQADASIA\nAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA\nAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3\nODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm\np6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA\nAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx\nBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK\nU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3\nuLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8347F\n5pkSP5t38P3ttaFjZzR2rzOMjfs+/wDNVi10+5kh877Gqv8AwfP96tOz0+2b99sw0e1drfxV87HY\n+wjHm94z4bOZ2WZ4dgV9vzN81Tx6a8jHvu+bd/DV+HT51uHd0Up95Pl21bhtfIkH2ncqfN8q/e21\nNS0dUbU4/ZMf7Oi52OzMu1UVU+an/wBjlW3w7l2t8y/3q3pNPRl2I+1tn/AqZZ280cXk3Nrub+7v\n+6tefKtLl5onZGm48qMqbQ3k/wBJeb5lb5PMf5l/2aZcaW6tshhyzffZn3ba3biHzI5USFfmX7tQ\nyWc3zTXltuWPb+8jT+LbXJWxVWO534XDxkchrmm/KZt+d3yvurBm0maHLvu2su1G/vV3OsWsMe5x\nyWTd5bVh3VikkLJ5Pyqu7b/easaNacX7x6nsYyicrJYws3nom1m/vf3qWC3uYW32zr8v95v/AEGt\nK6s5I9iJuDMu51aq62827502Nt3Jur6zAylKUTlqREj+0wsiI7OzNuRW/wBr+7ViSPy4/wBzud9+\n1vm+Wq0aurIJtxdf4qtLayeX8nyusu5mb+KvqMPSlKJ58qnvco65uHaNpvlTdt2fJ8y0kjSbER3V\ntq7tzJtqbyPtDLDNtx96nTKjR/Ii7t38X3a9D2fKebUkoy5SHyXjnP75l/i/3amSSVm+0v5joqbf\nv/Ky/wB6i3/fRrv+9911j+6rUsMMuxvJufu/fXZXPKXLE4OaUuaxPBv3b9n+r/hjl3LVqH9zJ/qV\n2t823/eqtbwpHGkP+qVn+dY/l/4FVuzZLqRI5plV13b12fdX+GvLxHvF04825p2cm1Ucopdvl+V9\ntaVvDcSSK6fd+ZXrN0+GGS637F+V1aXd/d/hq7b75mX51Db9zMr/AC/7Py14WIqSNadHuaVjNLJC\nsP2pmTfuddvzNU8jO3yQ7X2/e/iaq8IeGNPLRW+bbu2fdq95n2OZXhhV2b5V3V4dap7+h6VOnHqW\nob792yI6o6orfLVCZJpPnudrBf4v97+KpmuIWmDzTKsrfdXft+7VCS5dpmR5o3/vq392uJSjztQO\nlx928hzbIZXSFFLs7fMqf6yopmubzY63jIVb7qrU32OGSP8AhRPveXHSyKluy/J975VXf/FWkqnN\nqLk5fdEntdy/3vl2eZs/76pU3yQyJsYeX8if3lqwsE0iy2zzfuvl/d/7VVr6O6WTf8yfe/d7/u1n\n71TRSMK0R8d1cxwrvRQv3dzfdWoprp75hNc3cjtHtSLzG+61OaGaS3RJnV1+88bVVkkRlKWtthlf\n+GspRhKRjH3Y8rKuoXtvHteN8qy7X/vVga9cXisrpcthkVfm/u1pXk00zAu+R/d/utWDq14+5n34\n2/6rav3a78PFRj8JyVqhj6lM/wC8+8f/AB3dXManN82/fjd/CtdBqW+4bM0/Gzc1Yd48Pls/Vm+X\nb/FXsUYy5NDxsVLmiYF9avt+07F21QVXmuNmzb/utW9cWbyR56hVqnHp7rMJvJ8xK9CnKMeU82T5\nhljlWZE3fN9//ZrodI3x7ntn+Rk2srfM1V9N03bGOdu7/wAdrVhs4I5BGiMk0f8ADJ8tEqhrToz+\nI1NLtUinR9+fLf5F/wDsa7bQZnjwibU2/N+7X5VrjdH/AHKxBE3f367TRZE+x7E2/wB1dv3mqo1P\nfOj2fuWOu0W4k+ziF5sOzfxfw11ui6uNyu6Mrqu1/Mfb8v8As1wWk3KOuy28xVVvnb+7W/puqQxs\nU3/eiVmj+9XZGpzmMoyj8R3Wn6kQN8Myh1f/AEfb93/eatXT9am8ve+1vvbmrgrHWd0iXOcFfl3L\n/F/wGtCHxB5K+d8wSR9qKq/M3/Aa6OYw9+J2q69C3zpZttX5Ub+9/vUybV4IYd+//WbtzL/Ctcqu\ntbYf3fmHc+1/mqvcawk3ybJCu/b9/wC9U/DAfunT/wBtusCv0/2d/wDDWbqGuosbO8jEt91tvyst\nYN9q226ldH2xtt8qNX3f8B3VVvtUm2l3TLsnzLu/i/hqJRjI25vslPxRNDdZm85iv3fLb+GuMvJ3\ndXR/uK23/erW1PVHuomQXLFpJfkZvur/ALNZGqQ/aFb5G+V/3sa1x1I8x0UeaOjOa1SG2ml85Pv/\nAMO5vlWqtvbupYOmPLf5d3yturcbTkjdt6Mxb/lm38NQXWnpJcM8iSO38Un8K1nKn7p2RqQ5tTPW\nFJpD5czIn97726mTWVzIHfez+Z/yz/vVZa1eSTZDCqqqNu+fbSLYwzRuXhxufd9/71cNSnI0lUM2\nSN1CwpMuyT5tv/stJbxurI/nL+8ba0cn92tXybaOSHyYfuxbtrN8v3qq3Eltu+0+T86tt+VK5q1P\n3tCoVOXWRbtWdcoltv2tu2t8u6uj01na3TZuAVt27+61YNu7s0jzbWlb5U/hrQ0+aGObzo3bzl+X\n7/y7q+Ox1GXNKTPewtT4ZI7LT2T/AFM03mt8q7v4a0WuvLUI+6H5v9Wvzbv+BVzVnfTeSH/55q25\nd/3m/wBmp/7UdpI+Nqt8rbWr5DEYeUqp9DRrfDzG5cXySsN9zuVot6qybvu1m3mpRrD5iO0KSRbv\nlf5aqSal8zbNuPm2/J8q1Uk1QSM73KKrrF8nlr8u6tKOHUZe8dvtOhPeahD5yc7v3X975t1Zs0zr\nsfo2/wCZW/h/4FS3F4jKkEyMXX5X3fdaqzLBNJscrsZNqqv8NexhcPGPuozqVOWHKJe+c0hf7Tv3\nfL8tVri3DSPD9pUyr/F91d1aEljH/wAvMylG+4yp91aktdPeRc+Tv+f5fk3V9XluH5dTwcdiIx+0\n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\nvn8zZsVQ331rqpxkfP4rFc0C2s/nRsgdgrfw02OQM3kTOqt81Uo5jAm9HXYrVKt09w29H+Zf/Hq6\n4xPm8VWjI0beR1ZXebFaFu6Kqv53y/x/7VY+nnzGdH/v7fv1q2UcMi42ZVf4auPvfEeTKsadnI7f\n3lVtvzLWtp6vcSNvfd/C+5vvLWdpsMfmb4YeG2/NJW1pdn/HNGuF+7toiebKpzGvZWc0kTfOoST+\nFfvV0+l2u2ON/wB5Ky1l6HYv8joinau35v4a6Tw7ZpbrsuYV2xr83z/dqjGUjf0uzRVTemNybkX+\n7WvZWjyLseHLM27dHTNDs5PLjSG227k3L/tV0ljYoy7Id29VbfuSuj4jn9oYk1ik0Lby2Nq/L/da\npnsYWjWHft+Xc6t/C1a0ejzTbYZodu7+L+GoptPdZGd9yfwfK/zbaXL9o6aMvfMWKzmaQXPzOW+X\ndv8Au7aelj/pBmmm2CTbv/vbavrZpC3k23mfvP4ZPvLUV1Y7YV8t8lU+6y1Mox5eY97Cy90z9Qs7\naRlmRGdftG1Gb+H/AGq5vWtPmWRtk38X3lauwuI4f40k2/wMv96uY1SL7Ll9i/MzfKrbvmpxjCXv\nHvYaPwqR57r1i80LzQv5yM3yM3/oNcT4k099zJvY7vl+X71eoeIIdyt8jL8/7pv7tcZrln50bokb\nfL8yNXJWl/MerHC83vHtWnw20Ku8ybx5v3l+8rVLbxPcM6eTH5SuzRMvysrVWguIFZjZupSNvvMv\n3m/+Jqe3vv8ASPJ+zM+1V3V40Y8sD572nKX7G1eNv9JRX+Xcn8VaMLQyKfJf+DaisvzL/wACrPju\nPJbY8n7pn3LGqfd/4FV6Fu1y+EVdyN/tV59eT/lO6lU5pXEuo4VkKPtY+UqusbfN838VRR2rxyK7\nuwZanuJE+0OkiKX2b/lT5ZGpjWyKrnyVf+P5W+Va4qlSUdz0Kceb4RtqsMzTb4ZG3S7fJb/0Kh7X\na4he58pG/wBarN92kjj3fvnTciozOq/LtqaKGCSM74ZHf76/L/s159SpyzPQox9zmMKSzS8mm8l1\n+V9sUjferOuLeSa4NzsyVXbu+X71dFfQzKpuUmhXbKvy7KzJreGNXTyV+aqo83tTo5onNXivDIzu\nq4/gbZ92sjyUuJNjzSbYfufPXVala/u96bvu/MrL/DWDcaanyv5ap8vyf3mr7DLeaMtTGpy/ZKK2\n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\n91Ur6Wn8B4GKrTj8RXW3dbcTO6kr/wCg1T1DYq+c83nBk+6q/NurUkXylTyYdi7W+bf97/erM1KO\nTzGhkddq/fVfvLXVznjS/eTKU0yRqiOjK23bu30xmRZHh85W3Ju3NTm2Qwsm+NV3/Kzfw/7NUJIJ\ntu9Eb7tYVqnLA66VHl91FqzmEkgR3+Vm27Vras1SNv3j7hs+da5+GN1WJH/v1rWsiLMEdGRf7zfN\n8tfO4yoviieph6b/AO3Td09vLVN9xwv/ACz21pwyP5n+uVdv8TN93/drHt5h5KnzlVt38X92rX2j\nY3zzZSTn/a2/7NeBiKnMe1Rp0oxsaDfvo2R3X73+81PmvppJnhRI1T5W/efN8u2srzh9jHkzMj+b\ntVmX+H/drQW8dbcojq7sirukrzub3To9n7pct5NyiH5Xb7q/JVi2uFmkV7l8+ZFsX+8u2qNuqSXH\n3Nu1/l2/K27b96tGG1/ePO9z8nyq7L92n8RxyjOPvGlpsbtbrBvU7fm+arG2aO5EiOy7m+6v8W6q\n9v5MS+T5Ko+5W3M//stWVtX8z9zI29kb5aJSl8jGMPaTlcfFb+Wzw79219u6RtzK1CrBJGs002W+\n98qfK1TKUlVXmTZ8q7lX+Ko2t7xWZ3s1Rvv/ADP96s5QjHYdpcvKQNcwzWr3Lwsqqm75fvVZ+yws\np/cyB9n3f4qdHJMd6OmPlX5VT5mplwlzbyJNs27tv7xX3NWkY88uU5a0fd1MTUJLPS4d6I2WT59y\nbtrVz2oD7ZI3+jNuX+JvustdLr8b3FwbyHa6q+1/nrmtQjhj3Qr8r7PutXp4enzR0ieFiJc0vdMG\nSNGmfy0+79xtlV5rP9800O1/78f8X+9WtdbJMujx/c+ZlWqSq8LP8/zfdx/Etepy/ZPPqSIPLmk+\nSH+/tl8xKm8sTWod4WdN38K09Y3bHljcy/f/ANqrNrF9on8ma8YBf7vzbf8AgNHs/dLoy5oFTyxt\n/fQqd3ysrfLt/wB2q7WKRxtvRn3N/vbq2pFSZg8Kb1Vtu1v4mqvHY/vS8lsqH7zyRvUS9064/EUd\nPs/vIYedvyK38NXYI/KjdJY1wzUW8yfczj/aX/e+7UazPbt5PzP5bbvm/u1hGUo/CdX2UmWW85t0\nyfMi/f2/LVnT7qG3j2I+FX/lnJ/DWbDJNcyM7pl2b5Pn+X/vmq8175LedPNhfu/NXXRqSOSpH+U2\n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\nG3aT52R2/iZ91WbG4ubxU3oqtCnO3+L/AHqY0aeYfk4/jVk3bqs2qouxLby3Zv7v8VaSj9k5o80f\neiXFluYIymzfuRmVm+XbVG6uEudnyMv97/7KrtxJPas1siKdy/8AAf8AdqqzblPz7W+8i/3v9mue\nVOJ3U6k46kdmm6B3dF3btqN/eqK3kht0875R95UVnqeOzdW++q+Z8ybX+7VW4tXaFvO279/+r27d\n1cUjujIja82qZktpB/eX7u3/AGt1Z1zN5zNsmbcz7nXbuq81unk/vofvJ8se/wC9WfcRurb0fau/\nbtq6fu+8jOt7xUk1B1WTyfM/up822rljefbEV9/+rX+5urMurV2kXzo96t/E33VatDSLd7WPyfJb\n5fl3b91d9OUZHl4j3S6slzcXH+kou35WRo/vbq19PsXk8rO0r/dZfm3VX0ux8xvnRiy/Kir/AAtW\n7b2rtdxfeP8A0zVf4v8Aarsp7nl1JGjpOmuqrMjrI392T/2Wu/8AC+gyTQpC8LItx/qtz/d/2mrn\n/C2hwrIp34+TcsjMv3q7nw3pqN5Oy6jl8tNyK33V/wBmu6MfcMpS5Td8N6Gka/cXK/K7L826uisd\nFSOTzrN87n3IzfK3/Af71L4ftk+WZIWXyU27W+827722uv0vT7NcTW0PzKu6L+L/AHq1j/eMJVDH\ns9DeNkm/eMy/f3Nt+WrUfh547dtu75XZvMjeunsdLSZRvh3rJ8u3f81XLXQvs9u+9Pn3/wASfLU+\nzjIXtDgtQ8L7Zg8N43zbnZpG/iZawbjQ3tVXy0/1f3F3bt1el6l4fmkm+eH5W2q9ZWoeH/L/AHz2\n0brH9xlT5ttPllFEfWOb3Ueb3Wg+XC37nfF837uT7y7v7tULjQ4Zt3yZVf4ZE+9/vV6LeaO8kISZ\nFVlRvvJ/3ytZF94deOMTb13qittWplTgP2nvcqPPrrQ/OVXhkZEVf7tVL7RUmj/cvuZfvrurtbrS\n38mS1/eK33vm+6tZFxZ+XDJDZ7mf+8y/w/3q87EUzuoyOUuofJDQ+S26T/Wt/wAtG/3agns3jkUz\nOySRp8n8Lba2ptNRsXj/ACvv2hZPl3VUvkdt0z/Kd+xdr7lrxsRRly+6e3h6nKUP7NhkjZHm3CRP\n4W+VmWkRfsrRW0MbDzPm3ebtWpNQ+ztH8kOxpG3Oq/doS+RpNko/65K391axpYfm3Oz238pdt7N9\n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\nO/i/vf3dtZ95dfaIVhtvn8v5mVlr0InDUo80TOW18tok8n5pP+BLS2qwySb4XVhu2eY3y+XSsqeY\nzo+Fb5f+BVFBM+4QuVVt252at/sHNKny6lqa3gVfJR2O7/x6k+xp5aOk27/Zao4ZJo7jydmdvzKz\nJ8rf7NWLFXZGhk25b7lY1Iy5CqPuysxzWKXEJTydq/eVaoXcP/Lbeu/+8zVqws8MZePlGfb81Ubq\nNFYQfNmvN5pRm7ndy/CZkmn3KIj71/iXa3zMv+1UNxp6bvJ+6rfwtWxb27+YvnJt+b7qru3U8Wby\nO/7lTHH8q/J8u2p+1Y1lH3eYxI9D3KEtvL2bmbbJ/D/u1paboMKyqgfJXa0XyfM1ai2KK290/wBc\nvybl3eXWja2Hl7NkLfwrtrqjzR2PLxEeYraXob2uLqZGdvvLt+Xa1bGj6Sizfvty+Z9/5Pu1Lpun\npuKQwfOu5vmb5dtbGm2aSGLfCzIvy7d6/N/vV6VH3Tx60eXcvaRZWzTJMiRukfy7v4dtdv4ftkWN\nXt/lVvm+X5ttY+m2MMe1Lb54ViX5tm75v7tdh4fsbbzYXg+UMvzf7VenH4DzK0v7x1GhrN5imZGd\nfN+TdXa6LbwxRmFIWV9n+98tc34dVI5IYXm2szfIv3v++v7tdzp9ukE3/HzJumi2+Yq7q15TjlKW\nxcs9Lgjj+zQpG0m1d8n8W2tLb5luk3kqzeVsfcvy/wC9/vUy3tbbcPvff27l+XctXriFI7dnR8hf\nl8ur92RMako6uRz0kE0yO6RYfd8m7+7/ABM1Z91paLJK6QsRvXdt+6tdHLY+cuxEb7m5vmqnNbwL\n++N4ybk3P/wKp+EdOXNPU5TVNMhmf/j2yypt3M/ytWZe6akcOy3dUSRdv3/u/wC9XUSWPnMsPRPm\n+Zv4m/vVi6pDNbnzoX2DY33f4f8AaaspbnXTp+9zHI6lZ/vvn8tmX77bNq/7O2sK+08Nu2IrTN/d\n+XdXW6zsmt08yGNPM3bJNlYOoWm5WSaHZ8v3o5f/AB6uKodtPc5XVLMNl0TL7W+X/arCvLWGORUT\na3l/Nt/2tv8A47XXalb2DRvD58yFU3K0fy/N/drC1iz25d9qSfefdXnVNzvoylE5uaFI5vO+VGb5\ntrS7qVrBHUpv81YUVt38S1eutPS4vI9/Kr9zau2oGi+xvsfzNzfLtX+7/vVivdj7x3RlIns2SMtb\n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\n393zLtqzp9r5yoj8srbn2ptatJbWf59+7ayr5TbPlq3baO903n21h5rTJ+9k37a6nhf5jj+tdYme\ntvcs0qWzrGiy79u/5VWrEem37R8WzNFG/wAjf7O3dW9a6M93a/Y4eNsS7f73+7Wuvhua3t0RIcBl\n+8ybmWulYWO6iZ/Wub4jgLrTZplfYnyx/K8f3GX/AOKrIvtFSa6WdIVDNE37tv4a9Pm8N2zfunSP\n5U+by/vVmXmgpIXZIVUK6/M3y/ereOHN6dblhyyPOW02ZmX7TDGhX5vMX5qik0l7ryZEfD797Kv9\n6uuuvD940bJNBmL5t6x/eaof7F8pQ7wqfk2rG1dEafLLQ1jaUTiNW093Xy9/H3W/vVjXXnWse+GF\nflf96rV2uraLcyXCfaU2/J80kf8ADXO6lb2zSPDMm4bl+8vzM1acvML4b2OcvJYdzzfc2/8ALP72\n2qYW2WZnmm+T+Nlf7vy1q61YJaxl3mUbpVX5fvNWHJcTsxtrNMbvmRtm5dv8VLm5jCpHmNFdjTBE\ndgrLtdo2+Vammme1tWT7Sy/N+63LurJsbqcyL86k7vnX+9VxZHWNn8ltzN97d93/AGawlHuc3uxi\nW5Lzasczool+6/8Atf8AxNX7fWJoWFmlziRf4f73/Aqwn1Ldsd03Lv3Mqp93/ZqzDeQtGzojfK+3\nb/CtedUpx59TSNTrE3ZLzbbh5pvnki+997bR/aM3lnei7/8Anmr/APs1ZjXXlL5cKZiVF+9821aR\nbyeaRnRFdpPvt/DUU4zJlLlNL7a8kozt+XdvZf8A0GtDT5t0K3LzfL/tPWJY3XmIUwqf8D+61aOn\nxJN5X3d+1tq/7VehRX948utLlN21V1kkkvHj2fLs2/7tXdLjfzmd4chfk+b7sf8AtVjW83lxhPPz\nu+/H/Fu/vVs2u+ZDM8zP86r8qbd1eth4nj4iUZbnUabsZkj3/M3ypu+Wur0e4S1kRIZv9Yn3m+Wu\nO0ny5LtIZH+dfli3fxVp6ffIMJOke3ft+b5q9OMfcPFrSlGVz0XR791txNG+3b8u5v4q7LQb+aNX\nud+Ek2/w7v8AgNeX6HqyfZd8nlqI3VX/AL3/AHzXVaLrkELOm+QKyfPItEo+7YzteVz0GHWnjuok\n+Xav31/9mrSXWoVUbHjmb73l7vvVwNj4gs7phZ3LyMyxM0TKny/8Cq3a6kjRpvfYy/JLtrlqS+yd\n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\nwnDUqcpd0nQflZ4dqCT5t2xa6XS/D/2WRT5KylovlXf92m+G7Hy42R4Y/lX5Y2+81dRpemz3DedH\nCqKq7WWuiMYxOTnItJ0mGHGyFX3fc2vu+b+Kt6Hw+nmJ5NsrPs3RM/y7avaXDDEqOkO6Rf7q/M39\n6tSNWUeT5Mgfyv8AVslVyoPacpzt5oqfaH3x7P73yVz+vaf5N4IZvl875tv96u8uNnlq8yM77G3/\nAN2uY1y1toZQmxim3dub7tR9s05uY5HVLNId3nXO1PK3/wC1/u1y2rxwzXDXnlfIqfupG+9/wKuy\n1OzdZEROYZH+eRVrl/EEbrOdm7dJ8rM33flpcstzrpz5ZnC69Gk0PyQ7VZP4vl3V5n42jtrWN5rW\nFSvm/Ntr1HXGtrje947YjZvm+7XlHjBf9KdXdW3fw/dWplycp0U6kzzTxhHN9n/dzRj593y/e21w\n2vSbt0Pn7UVN3+9XZ+KrhLjzNj/OqNu2/NXmPii6fzCgfmuTlnUNpYiKj7xkapq339n3l+X5aybj\nVo5o3uTNsbft3bqra1evv3pt/wB5aw7jUn3bHf7v96q5f5ThrYj2kTrbbXAu0Qvtdfm3fw1M2tbm\n/dvt/wDZq4qDVnXcm/5W/iar1vqHmN8s2zb83zVPs4GPtpHVtrGzDo+4slH2xOHTr/HtauZXUjEr\nfx7akW+SSX5Hb+9RGPLIylUlL3Tp7e82yNNC/wC8X5W3fw1o2+pbmS6d13L/AMCrkbPVIWj3b/8A\ngX+1V2z1KaR12Ps/2W+XdW0Y++Zne6frUisk33l/u7a1G1rzo94uWZfu/d27WribHUHCqkz/ADt8\n1aNvq02GTdtT+9XVE5PiOzt/ELzY2eWxVfmZvurUq+IkDNs++v31/u/7VcnDqE0e2GP/AIDIv3at\nRsny/ZptjfxL/eWtfQw9mdtpesTSRLDNPuRl27V+Vv8Aeras9afckO+R/wCL+8v+zXDWM3mKrveN\nv2bXZvurW3Yx3iQo9tN5u51ZmZf4a46lTlOqjTj0O5s9Whjt/tKcv/Eq/Ntq0uuTSQib5n+fb/vb\nq5axurmH/j2T7ybmZfvf981oWupQxwh0fbD/ABs396vKxFTljc9jC0eaVuU2LzxAkbeTDu2x8O38\nVU7jWHtY97zYWR/ut/erKa886b7Sjrs3Mu3+9ULMklm9tN8gjb5Nv96vHrYjmie9h8L7xp/2k95n\n7THt8v5YlX7rf71QNqk0m3ztvy/3v+Wf/wAVVNbp2iDoi7Ff96v+zTJrvzGWGH5l2fI2yuKnUO6N\nGP2R8l09xDLM7t8ybflrCvG8xvJ+aLd/e+b5q0Zri5EbW29QjfcZv4qyLxv3Ozeys3y7v9mt6dT2\nmiMKlGMdzO1LfD+57b2+Vn+6tZF1Hc3HyJCzIv8AD/E1aF1cQtCm7978+35qq3F8scnkww+Udu1t\n396uzmlGN0cnL7xm/YdzMiJhtu35kq3Z8Q/+O/LTFm3TFPll3L91W+ZalhZ7e4X59u37lRKfLoOn\nTL1qsO9eVX/erQ0/93Ku/wC6tZO55JGSZPu/+O1saDeJ5fkv50oj3b2kT71EIyj7xrKPtNDqNBuE\n8tUdGZlbduX7tdZoN5IJmkT5nb7i7flrh9NuEjZEd8Kvzf7VdLY6k+5U3yCX5djRsv3a9bD1PePK\nrU/d5TvtHktvs7Ojs+59qQ+btWP/AGq3dN1KaNlufO3sqfdb+KuG0rUvMjMzuyuu392ybv8AgNbO\nn3XlqUSZdvzf7NejTqHmVKPKdha6p5ln/rmj2vtdZF/i/wBmte11S8gjF5ZzM7r8sqtFtVa4qHU9\nsIn+Vmj+VlZ923/ep1nrUzTGQXPPyqzNXo05dzzq1PmPQofEsMDRJC7AsrN8qfepsfif7R+5R1/e\nP/D/ABLXDN4ke1d4LZ/l/jZv/QVqOTxZCpVPOZEX7m2u2PJLY8+UYRmdvNrkLW/2mF2A+YeT/tVg\n6xrhWFd/BZv9Yr/NXNzeKdu57P5fn2u0kvyrWZJ4phaGVLmZfOVtrL/C1RUjy6E+/L3jZu9YSQvs\n3OF27v7zf7VY2s6w9vs3uvmf8tdr/LtrBuvFUFu72yXMau38P8VYN94kmuI2beqrGvzturjqR5pa\nHTTl7ps614ghs45pnmUmN/4W+9XD+IdcmkmkTf8ALv3JI3zbt1V9a8VJIHebbvb5mZa5PWPERaby\nUC7PvJ83zLXBU/lOyPLI3bjWrazh3/ad7N/yzX/2Wsq81bzGBTb8z1iTalukR/Oyv91qrTXDvIzw\nvH+8b726uCpH2nxHVGR1Fvd4VZt6lm/u/LVu11KSP59+w/e3f3lrk7fUJliVPJ3fP8nzVPJqk1tl\nHm27V3fN97dXFKnyw909CnUj7tzdk1VJo3+8zM+1t3y/LUlvqaMvnJbR/N/Cv/s1c+2sTNt2TKnm\nfMm6nw6w7SRuibXX7259qtXPKpLl+E7qcuWWp19rqE0i/PCqbn+Zl+9WlBeW0ciuibtv/Aq5Wx1y\nHzFeS5XYz/6vZ81XV1jEbybFVV+6396ojzSOo6GORPMiREY/L91v7tX9ri6TZ9zZ93f8yt/erDs9\nS8zbvdcKnzs1X7HVIbi4+zFGRmX5G2/d+WkOPvbmpD9m8tvMeMbkXYsnzVahg8lRCjq+1GV12fd/\n3ayLdvL2Q/KV+VvmXdWozJBHsdG2r8zfP8v+zTqe78JMafN8Q2TTYV2XPzD5921nr9CP+CTwkH7O\n2tLI4bHja5wyjGR9ktK/PmaZLpikO5EVP3vz/dr9Bv8Agk9A0H7Ousqz5z40uTj+7/olnxX4545z\nb4Bmn/z8p/mz4zj6lKHD0mtuaJ+eZjhhtXk8mZWb+GobqPzo9ju3y/LuX5lZquyXE15bxIm5gq7f\nMb5dv+1VC6Z/L8iHcqL8yMr/APfVfplStKofptHDwpmJfW7yN++mYJH8u1fmrKu43juH43eX/qtv\n/s1dDNGkMj3f3127fl/irB1S2maHe4UFmXcv+1/DUxqR5uVs9Knh+aPwnPahcStI3yLEFdlZv9ms\nS8m8lwruuW/i/hroNRt32yIU+fdj5v4a53VI0bh9qbfl3f3q76MohUwkdzE1i4eRTbw7UVn+dmf7\n1Ymob2U73XK/Lu/hrW1SP5FKTcK21G/u1i3zRbRv+Z/uu38NepR948nFYOXN7pj3rbVbybb5F+V2\njrNvFQp/tfw1qzM679m3Yy/drLmRPM3v/C33a9SnE8arg+WQmmw7WbydrfP92uo0G3dso7yNtT5P\nk+6tY2nwvE4d0X7nzba6nw/b7o2d5mI2f3K6oy94mOF983dGt/JVEf5y33Pnrt9Dt0mhZ9m3b99V\nrm/D9vMFR02jb/Fsrt9DtXbZwu7/AGv/AEKorS93mPWwtGMjV0uwtvLjTtJFu2snzLXT6Tpc0LNv\nRVEyf6z/ANlrK0VUa4SG2f52Xa7fe+Wup0OyuY2dJnZyrrsZf7tcMuaR6WHw8blu1s/Lk+zb127t\nvlq/y7v96voH9kHxFJ4J8YWF/DD9qm+0bYo/urH/ALVeJWVrZ3BSa2hyW/vf+hV6n+z7HqS+LrZ7\nDa6+aq7mibarblrKp7pGaYfmwckfqh8LfD/hXwH4J1fx/pVzu1TVnkuLq4aLaqq38K/3mrtPC3jL\n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\nVpW+oJcPBMiSIn8aq/3q7qcuY5pUY/EdtpervpMqJMissjsvzfw1srre5VZLlcyf7P8ADXnMPiJG\nYJOjMVf91tX7taUPjCZv9DmmUqv3W2fNur0aMjzsRTjKJ3y69bLPstppCZP9n71RtrDxxu8w+RZd\nu1f7tcdb+JEmkTZNhl3bm2/KtMm8TIq/vpvl3N8u77zV6NOR5NSmdtqGsPNHss79dn3tq1mzeIP9\nIZ3T5I9u+uWXxDprTKj7lRvvSbv/AGWoJPETxNtQrK025vl/u/w7q6I1OXaRzSw/Mb154kh8yb99\nu3P/AHvurWbf+JrmZSjzbP4om2f+hVz154i+ZkeOMyx/3X+9WFqHiRF/c75DF/dWlUrR6GX1flN7\nUvFT7N6OoZfmddnzVkap4ij8lraGZWbf86x/w1zGoeJNsex3UqrbXZqyrrWPLVoUfb/uvXNKpLmN\nY4fl2NbVvEEsa+S87bv7yp/47WHcahuZkSZVXf8AIu/dVSbUnkwm/wCZf4WqpNM8fz4Xaz1y1pSk\na+y5S4t9c+WWSRWLfN/vVJHM/mb/ADo/l+ZN33ayFvHSNpvO+X/ZqKbVHZhsfluG21zfF7pfwnQX\nGpTMqzfL/d+/R/aU20fOqNJ/C1YMl8Zl+f5dv3WqSO4m8xf9W3+033mrmlL7J0xlym3HqTySK8if\nIq/PUzXXmsdkONq/xNu3VjR3iSKIXh5/3ttTW918qJ97++2+sZR5T0KdSMjbh1C5Rk+VWRfm8z/2\nWtfT9Ufbs2Y/uSVzEa/NvTcR95fmq3YX21m3zN833Y1/hrmlGSOyMjs7HUH3b0m+VV+ZVaug0ed1\nhF07/ei27m/iritH1Pcyo74ZW+T5N1dBpupeduh+zKdr73/hrGUpm1OnzHRWt35cfyO2I2+Td8zV\nox3j+YvyfIz7fm/9CrHs7hL5ofnjikk+Vl/2v96r8MnmMkLorfP83+9WPNym0Izl8Rf8ybcm/a/l\n/eb+LdX6Gf8ABJos37OetSsm3f41uG2+n+h2dfnY+JGiR/lf/c+Wv0T/AOCTSIn7OesmM5U+NLgr\n/wCAdnX4544Sb4Gnf/n5D82fJeIkf+MZk/70fzPz+vI/3MVs/wByRF3f3az5IZlmlTyVCRttX+7t\nrUks3uFO9OFfcm3/ANBqFtnnQ74flV9su56/TJVOb7R+tUcL/dMe8t3LG2hfYzJ5vy/dZaxdQkRY\n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\na38K/wDs1NVUaT+78u3/AHqljt3jkR3+VWTa8lOb5V+RPm/3KXtOb4Thlh+WWpDGrxyN911Z/u0e\nY/mNv5p7Q+YV/u7flZajf5lSN7bYzfxUvi5jHl5pEi3zxvs28t/FVuC+hjQQh9v/ALNWdte1k85J\nmbdT4JrZpkdwvy/Ku7+Gsqkfc1NqcuWZsWt0jNsRGq9pbxRzM6PtRvm+VKyLe48uRXd9zf8AoVXL\neZ23b9u1f7tcnvyjqelRqcp0+mzus2+OZVWRvnWuhs7h1X7Sm1V+7t3ba4yzk8uFZkm+Vvv7q3rO\n6dsQ/KyRpu+b5t1RL4bndTkdlpd4/no7/Kv3tsdbVn5KzBE6fe+ZPu1yvhu/H8aM5+78q10+nxu0\nbpdeZvZl2fL95a87ESlzHoYWMZRL/wBhmhYb02Cb54tr/er9Ff8AglHsP7O+sPGGCt4zuCA3/XnZ\n1+ednBtuFmmfJVdu1vurX6Hf8EpnVv2d9YRFICeM7hRk5zi0tOa/HPGuTlwTO/8APD8z5PxKgocJ\nTS/nh+Z8DrHDHIyI8m1tqurfxfLRJawjLw7W+78v+1VmO3hkVPtLsiq3ybfm+al+y/aI9kyMw+b5\nlRv4a/Tox9/3T9pwdEwr7S3ib50kAbd8sbbV3Vk61HtjLzbn2/Nt+6zV1l3DumdELC2X5UZl+81c\n7qEKSRum9i0n95664noU8PDmOJ1ZR87/ADLCqbn2ru2/7Nc7qVrti3vtZ9u3av3dtdl4h0e5WPZ5\nasrfNtVvmrn9S0vdH5yIyFk37f7tdVOXuxPQhh48kjjrqNI8w71kdfmb/ZrOmtYfLXY7Z37nXdur\npNSt4Wjf54wZF3fd+ZqzVt0WPf8Ac2pt+5XpUebTsctbDwkYE9nuuN5THnP/AA1DJauZNibsN/Cy\n/LWvJbpG48nn+L/aqOb51XZEzn7u3+7XqUZRX2T5/FUYRKVvDPGvy7drfwtWtY/vG2PCq7f4l+7V\nOSNI5TIk24/dX+9UliNszOn3v7y/erf7B41SUU9Tq/D+wbUjfd/tNXb6DeSSMkNzMsUX3VZYq4HR\nbuPzjDsZHb5dy/eWut0O+dWZJpmfb8u3d96r5eaPvER7RPRNBvLOOd7OB1fzG27tnzV1nh++ZrX7\nNvXeqfJCzbd3+1XnOj6o8OxI0+dfmbav/jtdXod07H7S8+dz7vL3bd1c3tOU7KNTljynpOk3rxyJ\nNMkaGOLbt+9ur1L4L6pb2PiBdSufnW3tZHTan+z8u3/arxPRdU3NHczTKn8LrXo/w1mubrULiwtk\nWVpImaJo/wDdrxs6lKWXTUex6+VS5sxgz0r4S/Dv4b6t8CLzVfHMy2Nz428UMr6hqFwqyeXG33l/\nu1L8A9J+G/gn9rC3+Hvw68cw69pEbRtut23Rxybvu183ft5fEB/Dfgnwd4A0PWPKkh0triVYdy+X\n5jfN8396vbv+CCX7MN38SvjNefEXWZ5JdN0q2W4vGkf7u35l/wC+mr80y6nifY66HpcVyoT5qjP1\nw/avlis/g7Y6jJDJDBDZxokcf/LNttfn38T/ABY/iy+udSv3+SP5YpGbarNt/i/2a+4f2v8A4y2U\n3hmHwrDZx/ZIEOVkX7zbflr8wPix4wvbrxdc/vtkPmsrRqm1Vrrx+IjXlGMJHzvC2BnhcNKpVjy8\nx0V/oug6xa77+G3eOOL55I/kkZv97+Kvlj9o74f6ba2Vyng+5WS8mumWX7RZbfl/2Wr6J+HviTRt\nauI7DVUkitbdmW48l/mk/wC+q6rxV8AdN+I2kteaBpUdpbwozLNM27zK1y+pBztM3ziPL70T8hPi\nRB4h063mS5hkikX5X3JXlV1qHiTSbeTYkgWT70m2v0j8Wfsv6JeeJLu28RfZ38l/kkk+78tfPvx4\n+D9np6zvomgq8X/PPZ91a+zy/FYf4ZRPgcZhcVVjzQPkm11bWNWuPJf53/2q2tY8K6xpNolyUX7n\n3a328I6DpOopeW0MyFmb920TfLUXijXpry3+wIi7Vi27ttenXrKUowhE8SGFrxfvs4htU+0L5PmK\npX79afheSa6uPJT5T93dVKw8Ove33yfMGTd8q16p8KfhLf3UyXj2zbW+5trOtKlTgXQjVqVTvP2b\nfhTc+MvGVroL2citcPsim2blX/ar1/8Abi/YV8efs5/Duz+LvifSpLfRLqeOCK8uGX95I33VX+Ku\n1/ZH8Ev4X8ZWGpalZR4Vl+ZvlZq+zP8Agtt8Gdc/aJ/4JreFPFXhKLzrrwn4ghvLrbJ8zR+X5bNt\n/wBmvkKtSU8xjB+7Fn3EsHy5R7SOp+IWta5punwj7S6r/c3VufDX4mfDfRdQhutY0+O5ZX+7u27l\n/vVyXjb4P+NodW2alo9wIm+VGkq98L/2ffEPiDxJFYPpsiiRvnZvu19M8BhfYc058p8vPG1adWLh\nS5j9K/2JvE/7J3xZeF/BOr2Ol61G+37HfIqtJ/tV93WXw78E+OPCv/CN+JNHt57y1t9kV0sCqy7a\n/Iv4d/8ABPf41LqFt4k+DLyQ3MLrLEqt8zf5av0S/ZR1j9pbTdXsvA3xp8JTaXeRqqvdRv8ALcL/\nABfe/ir43NMPWpR56U+aJ9hl88NjaVq0OSZ7f8EfD+u+Dbe40f7TI1n9o2o0jfdr3T4O69bf8JZb\nb42dftG1l2tWHa+CbOHTBqBhYJM6s25NzM1afwW8a6V4T+J+PEFur6fY2811Pc3G1fLWNWbdXy0K\nNOti4Rl/Mj1K8fZ5VP8Awn5xf8Fxv2vNH+O3x0s/gn4F8QyXFj4BnkivWh3K32yT/Wf7235Vr4u0\n+3hmuvOSHft4l3Ju+auv+M2oJ42+OXjDxPC7eVqHii+uIJJE+aSOSRmX5v8Adqhb6WjKHkfC7/nV\nf4q/ZaVGNKlGEeh8HgsPzU+YjXT0jwjw7xs3JGr/ACq1Xo7FFyieZ/us9WrOz8mTZ9mZyz1PHC7T\nb03BG+9Ht+7WFb3vdPbp0eWPuxMu4tXe3V3hXZt+f+Ksq803crpMF2/eRlXa1dPNC8cgTf8AJ93a\n38VY2rW6TMzujBv+ee77tZUf5ZGVSjzQ0+I47ULMKzTb2D/eWsbX45FmX5227V3ttrqdStdrO6dN\nm52/hVa5/VPO+0M7zM6qm1I9tdlOPvWkeRUj7uhyOrWsMnm7OGZt3y1y2uWO5i/8TfL81d3qFl80\ng+VFrn9R00bW38fwrXo048rPJrU+55/q1jbRx7NtfaX/AAb52Edv+2/4pniXaD8Lb1dvb/kJab0r\n5J1rScqTsbG/+L+KvsT/AIIBWjW37aniYnv8ML3/ANOOnV8Z4q6+HWZf9e3+aPl+JFbJq7/ungX/\nAAW1aQf8FOPiYEGcjRv4f+oLY18ptdeX8n8VfWf/AAW0t5h/wUx+I8427SNG6/8AYGsa+SpFxJvd\nMnftr1uA434Gyq//AEDUP/TUToyZxeT4f/BD/wBJQ+ObbNvhRdrfw7KtQ3nXc64WqG141+T5l/vb\nqdDP82x4fl/hr6nl6Hp/FL3jbsbxPlLx7l37srV9dSDK3kurN/B8n8Nc5BN5ce+F+W/hWrEdw6yM\niblSiXxcxEpcx09nqTzYhhRd33d1Wf7eeNVSba235a5WG8mjP2aN9p+8+2ntfbRlNpP95qfNy/CY\nVNzsIdaTydjurFv7tDapthVIdvzfNXJLqgaPyZoP++WqaHUnaT5Z8Bl+7WspGHKjp21ZN64fCt9+\nmfbkhkbyNu2T+89YkepedIsLorMvzeZUys8jKZtu3f8Aw1EpFRj73ul+ab94+zafn+bbVdmfyf3m\n1X+9/stTlL58t0wP4d1P8mYyPsh3/wAO5kqPaGsYlCZdq732qf8A0GoJrSKTH8W7+7Wt9h8tV43M\nrfeX+KmtZ9EyoP8AH8v8NY85pGPL8R9HR2NtHcF5037fl+X+Kpri18yEeTDjbu2bl+9VizSFl+SF\nj/Cn8TVdW3QWoSF9v8Tq3/stfGVJe/7x+k0zG+zpDGk6Bkbf8216jkt7aNn+dim/duk+8talxY/N\ns3sqfLt3fxVUu49qojuv3m+Vv4qzlG50RxHKYOoBJXfzr1k+fb8vzLWLewxn/j2hb5V/irprqzRd\nj+TIrt8u7buWsu8tXWZ3ddnz/wAXzV1U/e0MKlTmj7xzF5azec2yHe2z7u6q0lpc28iu6LtX79bd\nxEjXDud37uX+FflqL7G8m9N7Hd/EtepRqS9lZHgYiPN8Rm2du/2j9yiy/N95q2rG3ufM2Jux/dVK\ndpeioyvOnlp/e/ire0fS03LJsVQ392nUrHPRo9ypZ2O21Fy9s3zPt2tV6x02GRWx/f8AvN92r8dm\nkitDDulWP5kZvu1oWOkzLud+E2blVv4q55VPZwN6dOPOZjQpEyPCnlN93725asW0dy0n2lEzKv8A\ny0rWuNJMjeS6bf7yrUn9m7V+zIjbY/u/71Yyqc0TeNP3zBk02Nso7/7396syaFzJ86bn3/6tmrot\nVtwsjQpCpdX+fd92s64s3WT5JsM33o1+ZVrWjzT94VaPLH3TMksvtDO+yT5U/wBWv/oVQTaennCZ\n0Z0X+9WhJIjQpN50iv8Ad+X/AHqbNdYd0+Zz/d/hrenzR90mHL1MuNPNbYkOxd/ys38LVZWZ7BU+\ndd33XVfu0TQwxbptjDzIvn2r/wCO0zy0EaJbQ72j+ZN38NddPyM5PlLkOpJHInnoy+Z822v6K/8A\ngkj8GtN/Z78PwfB3SdcuNRh0fw7KHvrmMI08sl2JpHCrwi75H2rliq4BZiCx/nDhvP3m/e29vuq3\n3q/an9sn9uL42fsD/Cyy+LPwKm0tdU1XXV0a6Grad9pj8iW0un3KuVIdJIo5FOdu5AGV1LKfyjxH\nxeJ/1x4dwcJfu51asmu8owjGL76KpJfProfBcSTrrN8vo30lKTt5pJJ/Lmf3n0/f/wDBWH9lez1G\ne7/4SH4c/wDCRQhoTft4xsdwcZXJ58zHH3d3TjPevHvHf7Z/wd+I3iWXxT4n/aK8GS3Mp/doviq1\nCQJnhIwZTtUenuSckk1+Kcnii+1fULjV9Q/eTXUj3E7JGqZlZixIVQABk9AAB2rW0+/haRU+0/vG\nX5dy7v8Ax6oznwcrcSUVQx+bVZQT5uVU6cU5fzPlS5n5u7OXH8Kzx0FCtipNXvblilfu7JXfmz94\nfBH/AAVF+A8PhqPwx8SviH4D8UQWwUQXFx4rszISM4Mm9nDtg4DcH1yTmsj4wf8ABQ34WfFexj8N\n6b8WfBukaJDgpYWnii2JkAACiQhwCoxkKAAPcgEfiHpurQwsYfmRW+VlVPu1vabq0MP3XklVYtu3\n7zf71a4vwkx+Myx5dWzms6bSi/cp80oraMppc8l5OTv1Oetw9i6uH+rzxUnG1to3a7N2u16s/Y7W\nP23/AIP678HtM+D5+JPgxYbC7MqXqeJoC8nLFRt8zAOXfJ5zkYAxk4ngn9o74ceEvEtn4s8L/Frw\nybqwnEkZGtwMp7FWAfoQSCOOCa/KK31B12zJ5asyK22H+Gul0vxA9niZ3j+b5l3fe/3a8HGeAuFr\nYmliKmaVXOlGEYPlgnFU/gta3w20e/VswXBaxFSNSWIlzRSSdloo7fcfs9F/wUh+AOrFNQ8S6D4L\nvtVjUf6UmvWp5HQjerMo/E1538X/ANr3wp8Yteg1LW/iH4atY7KMpZ2dtrMWIgTksSXyWOBk8fdH\nAr8xdJ8QTYSaaRV2t83+1WnH4hdo99zMqtu2o38Vehm/hbi87wbwmMzapKDabSp0o8zWqcnGKcrP\nXVvXXc9bE8IYjHUPZ1cVJxe/uxV/WyV/mfq34N/4KG/Duy8Nw+FvihqnhbxLBAFFtcXeuW/mMRnB\nfzC4dsHG7APrknNYfxj/AG4/CvxSsY/DVh428OaNokJGzT7XXISZQANokIYBlGMhQABx1IBH5iQ6\n8RKPJ27PvL5j/dqWTxc6mT/Z+bd/CtRivDPHY3K/7Pq5xVdNpRfuU+aUVtGU0ueS8nJ36nTPgrE1\nsL7GpjJctrfDG7XZvdr1Z+kOk/tifDnw78HtS+ED+MfCxh1K6ExvZdeiV0GVLDbvwTlFwcgDByDn\njH+Fn7WXwf8AhT47tPGUPxK8J3b2ocPbTeI7dNyupU4If5TgnBII9jX5uah4kS4ut7zKqeV80jfN\nuauY1nWEkWR0+T+LzF+9XhS8GqUcThq39p1OfDKKpvkp+6oycorbWzbet/uMv+Idx9pTn9alenZR\n92Olndfj3P008aftRfBLxZ4p1DxXqHxh8HW8uo3bzvFH4ktgqlmyQMyZ61iTftK/s5W5K3Hx/wDB\nKEdQ/iqzH85K/LDWNU8sv9m3M/8Az0WX5a4bWJPObzrnbI395vl215tbwCyjE15VamPqOUm23yx1\nbd2/vOKp4Z4WcnOWIld6vRH7EWH7X37N3h3VLfVbH9pvwJa3drMstvKPGNkrI4OVIzL6ivZoP+Cw\n37H1/bR3Xj74g/CjUL+34gu18caeqqeowJGcr+DV/PR4gtZr5lSF1aXZ92T5flrmb7T08nY23DI3\n/Aq+gyHwjlw7zwwGaVIxnbmTp05RbWz5ZJq672udOD4Gll0ZewxUknuuWLX3O6P32+Mf/BTH9mv4\nxarb6h4g/aj+GNpbWiMlnZ2/jmx2Jk5LEtNyxwATxwo4FbPhz/grt+yh4X+Ek3woX9o34SuxtpYI\nb1/H+nAJE+d26LzcO3zN82QOmQec/wA5erW+39z03fMjLXJatZv87vCxVf4vu7q7cJ4O14ZlXzCG\nb1lWrRcZy5INyi7JrVNLZWta1laxwz4Ur4fETrrFS55qzdlqn/Xy6H9Hvwg/4Ki/so/BnWZ9V0T9\nrX4T3EF3EI7y0ufH+nhJADkEETjDDkA8j5jwa9Du/wDgtf8AsMaVbyT+B/jJ8GdM1C4H7+6k+Iml\nkMevISRC3Pqa/ldvLV49uxOGqjc2TbgyP/HXq5T4PYrI8CsHg84qxpq7S9nSk4335XJNxv15WjHC\nZDicHR9lRxMlHp7sXa+9m1dfI/pGu/8AgoF+x3qWsy+Irv8AbT+GEl7Jcm4luv8AhYem7vNLbt2R\nPwc817Lov/Baj9izU9Ki074m/HX4Oa+0AHl3A8f6WuTjG4o8jruPcrgewr+VGOFLeRn8njdWjaxv\nJt8n+H+9XFk/gg+HqlSeDzarH2nxpwpyUvOUZJpvV6tX1JwPC9TCSk6OJkube6TT9U7o/qH+Jn/B\nYD9lfxzoL+CvCf7TXwp0DSnUK8Nl8QdPMrpzmPcsygIe6heemcEg/Mf7RV1/wSx/azTSB8f/AI0/\nDTxAugG4/sr/AIuhFaiDz/L83/j2u4927yY/vZxt4xk5/Cqxj43+R977+1/u1taWs21Y4fm2/wDj\n1ZY3wZrY3M45lPOq6rwVoyiowcU01aPJy8qs2mo2umzonwjUxOJVeeLnzrRNWVvS1rfI/XmL9k7/\nAIIc53ReJPhycc5HxknOP/KhVuP9lj/giiY2jj8Q/DwowBYf8LemIPp/y/1+S2nwoqts+Zt6svzV\nvaTFM0iI74+fa6s1Kp4XZ3H/AJqLGf8AgyX/AMmehDg7Fy/5mFb/AMCf+Z+q9t+y/wD8EaoVSO11\n7wAAPuBfixMf/b7mrUf7M/8AwR/jZZotd8BjbwhHxUmwPp/p1fmXounpHIiTOxLP8jM9dFptnvsR\nu43P8v8AEyt/vV5//ENs5cuX/WDGf+DJf/JHo0+B8fJX/tKsv+3n/mfo3D+zf/wSRhceTrfgYN2x\n8T5sj6f6bUv/AAzf/wAEnc/8hfwRyP8AopkvI/8AAyvzysbFIUe5+ba3y7m+XdV+OxSTc+xldVrl\nn4b5xGVv7exf/gyX/wAkdlLgTMam+aV//An/AJn6Af8ADOv/AASgRcnXPBIHcn4mzf8AybUq/s8f\n8Eq1BZdZ8F4bqf8AhZc3P/k5X5/yWtnHHG77l+T59tR/Z5o4UdHZPnZfLb/0KoXhtm9k1nuL/wDB\nkv8A5I3XAWYp2/tbEf8Agb/+SP0FP7Pf/BK0MJjrfgsHAw3/AAsuX8P+Xyo/+GdP+CUhw39seCeX\n+U/8LLlyT9ftlfAawySQ3H75dkm3/gNS29nNHH5MMPzN8vyv96tV4ZZ1LfPcX/4Ml/8AJDXAeYLf\nNsR/4G//AJI+9H/Zx/4JPT/M2r+CGwduR8S5eD6f8flNm/Zl/wCCTjNmfUvBWVUfe+Jk3A7f8vtf\nCX9myKyWy/embdu/55/7NNn0d/tBmm2ldmxP96uyn4WZzKP/ACP8X/4Ml/8AJCfAmYct1m2I/wDA\n3/8AJH3hF+zd/wAEnYZCI9Y8EhhkEf8ACzZjj1/5fakh/Zu/4JTqVEOreC89V2/Eub8/+Pyvgubw\nzDGquH27vv7X3VYg0i2t13ebI/nRbWZvvV2w8Js4a04hxn/gyX/yRzvgnMb2/tXEf+Bv/wCSPutv\n2dv+CUoAWXXPBZ443/E6Yn9b2mH9nH/gk8HEp1vwUGRsgn4nzcH/AMDetfDF/p9s80Lw/M2z+Fqp\n3mlwxx7HRt6t/E1bPwlztf8ANRYz/wAGS/8AkznfBWYa3zOv/wCBP/M+8z+zl/wSdKtnWvBGHbLE\nfE2bk/8AgbTY/wBnD/gkxDGTHrXgcKTgn/hZ0uP/AEtr4EksbPzFeGZXDfc3P92qFxYujfJc87Pm\n3fw0f8Qlzu9v9YsZ/wCDJf8AyZh/qbmLlb+06/8A4E/8z9CI/wBnf/gklI2Itf8AApIHRfihL/8A\nJtJJ+zn/AMEkyrCXX/A+0kbgfijNj2/5fa/O3y/JkCO+P4f9mm3dqlwqvC6hm+9WcvCfO4/81FjP\n/Bkv/kif9Tsf/wBDKv8A+BP/ADP0Luf2aP8Agj95he713wGGPXf8VJh/7fVWk/Zr/wCCNTYEviX4\nfdMgH4sy/wDydX5vapDNbrv85i2/asjfw1zOqK+4mZ+d33Vrl/4hZnS/5qDGf+DJf/JGy4Nx8o/8\njOv/AOBP/M/UNv2cf+CMeTG3iz4egt1H/C3ZgT/5P1BL+zX/AMEVCpE3i74dgd8/GCYf+39flv5L\n7Qj220/w1n3lmdzJM6/f+7WlPwtzp3/4yHGf+DJf/JBPgjMXtmVd/wDbz/zP1V/4Zh/4ImTBT/wl\nHw5YKflP/C35j/7f0j/sxf8ABEwkB/FXw6y3QH4wzc/+VCvyqazmt1VHtmVZP7z7arzWqbg6Q7f9\nmto+FudydlxHjf8AwbL/AOTOmh4fZhUdv7Srr/t5/wCZ+rx/Zn/4ImyMWPiz4ck4wT/wuGbp/wCD\nCmyfswf8ES2AEnir4dYXpn4wzcf+VCvyhkXyzvdF2L91dlQv5fzyQpt/i2s33ab8LM9UdOI8b/4N\nl/8AJnr0vDPMpRS/tbEL/t5//JH6wf8ADL3/AARB3q//AAlXw4z/AA/8Xjm/+WFK/wCyz/wRFl/e\nyeKPh0wPc/GOfB/8qFfkuu9o28523t9xlT5dtXrG3fabn5tv3WqJeFucxjf/AFixv/gyX/yZf/EM\n8z/6G2I/8Cf/AMkfqyP2U/8AgiHH8v8Awknw6Gex+MU//wAsKe/7KH/BEhlw+v8Aw7wf+qvzjP8A\n5UK/K+3t/OZE2SZ/2U3bqu2+mzTK877sRp/31WL8Ms5/6KPGf+DJf/Jh/wAQyzNL/kbYj/wJ/wDy\nR+n8n7JH/BEElWk134d5/hP/AAuGcf8AuQo/4ZO/4IgKrH/hIfh0Ax+Y/wDC4Z+T/wCDCvzPs9Ne\n6X/U7fkVvm+aqt5o6CRYYYVVt+37lcy8Ns3bs+IcZ/4Ml/8AJHJiPDfMYRus1rv/ALef/wAkfpu3\n7JX/AAQ7UlW8QfDkeo/4XFP/APLCkb9kz/ghux2v4j+HBI4wfjHP/wDLCvy9uLFIZtnyt8rf7q1D\n/ZybleR1w3y1pHw0zf8A6KLGf+DJf/JngYngnMKUrPMaz/7ef+Z+orfslf8ABDMLk+I/hwq7ccfG\nWcDH/gwpv/DJX/BC3aI/+El+G+Ow/wCFzz//ACxr8sJLGFZuU2Ls/wCWn3ahbT0X50mYtv8A4vur\nWr8MM75f+Shxn/gyX/yR50uEcYv+Y+r/AOBP/M/VRv2Rv+CFjcN4j+G5z2/4XNPz/wCVGkX9kb/g\nhQXBTxH8Nd2eMfGefr/4Ma/KS8sd0jb+B/eqC6hdVCJtT+Kj/iFueaf8ZDjP/Bkv/khf6pYzrj6v\n/gT/AMz9ZY/2Tv8AghgDuj8UfDfjuPjPP/8ALGpR+yt/wQ63mQeJ/hvlhg4+Mk2CP/BhX5IQw4+/\n821/vbq0rePbIkOxW+Tcn+1VPwrzpR/5KHGf+DJf/JFU+Fcf/wBB9Zf9vP8AzP1kg/ZZ/wCCJMXy\nQeJfh1z2HxgmOf8AyoVbg/Zi/wCCL8aeXB4j+HuCBgD4tzHP/k/X5PQ2u2RdibSz/erb0+F/LXEK\nru+VG+7WD8Ls5X/NQYz/AMGS/wDkjphwnjumY1v/AAJ/5n6qw/s3f8Ef1Xy7fxJ4EwD91fivNwf/\nAAOq9b/s6/8ABJ2NjLb674JPzAE/8LPmIyP+33tX5h6Om4QvDCuzftl8z+7XW6fHNGoRX3jd8zN9\n5maueXhfnHN/yPsX/wCDJf8AyR3UeEMwcf8AkaV1/wBvv/5I/RyP9nv/AIJcAbU1bwYeh5+I8p+n\n/L5Xsf7P/hL4D+DfBtzpv7PN3pk2iS6m81y+la21/H9qMcYYGRpJMNsWP5c8DBxzk/lJpEPl26yu\nit/z1r9Av+CXCJH+z/q8cRXYPGNwECjG0fZbTivzvxL4IzDIeGZYqtmlfELmiuSpJuOr3s29V0Pn\nuMuHcZluQyr1cfWrLmiuWcm469bNvVCr8CP+CaEjC3TWPCBZWGEX4hy5B7cfa6mX4Gf8E3cGNdX8\nJ8EkgfEGXg/+BdfEenx3MM3k3SK39xdvzLU0MPmW/mb921/u/d/4DX3kPDDOW/8Ake4r/wAGS/8A\nkj9Ap8D5re6zrEr/ALfl/wDJH2gnwJ/4JoTRgR6z4QZSeMfEOU5P/gXVO8/Z8/4Ja3GUvdW8FnsQ\n3xGlH/t3XxhqEbi3e1RFb/ZVNtYOoWMLQoX+Uqm3/erX/iF+cL/mfYv/AMGS/wDkj0qPh/mslf8A\ntzFL/uJL/wCSPuG7/Z0/4JOOPOvNa8DgA4LN8TZQAT/2+96qyfs1f8EiJVPma74FIPB/4unN/wDJ\ntfAGtRpHEsLuqht33f8Ae+Wuf1aRI1Z33S7nX+L5q6YeFeduP/I/xf8A4Ml/8kdy8Os1f/M+xf8A\n4Ml/8kfopJ+zD/wRvRSkuueAFDHBDfFWYf8At9VWf9l7/gi0XYXHiL4ehh94H4uTD/2/r82Lr99M\n/wAm3/Z3bqxNQW2tx5PkMd3y/NWy8Kc8X/M/xn/gyX/yQT8Oczj/AMz7F/8AgyX/AMkfp237Lf8A\nwRMMwdvEvw73kYH/ABeCbJH/AIMKiH7Kn/BEJGI/4SX4c7icNn4xT5/9OFflhfWvlsqouw/3aosq\nBTcv8jL99V/irrj4T53/ANFFjP8AwZL/AOTPBxXAeZw/5nOJfrOX/wAkfq6f2Vv+CIKEk+JfhwC3\nUn4xTZ/9OFEH7Kn/AARCik82DxL8OQ3qPjFP/wDLCvyfMj+WN6bXb+Gki3TM7wnC/wAX+1XTHwkz\nyUb/AOseN/8ABkv/AJM8WrwdmEP+ZriP/A5f/JH60w/sv/8ABFNWIh8TfDwsTzj4vzEk/wDgfWha\n/s3/APBHSGUz2fiXwAH7snxYm/8Ak6vyasLUOOU2uy/Kq/eb/aro9LhePGX2P91mVvmWol4TZ9/0\nUeN/8Gy/+TJ/1RzBf8zXEf8Agcv/AJI/VG1/Z9/4JJw82viLwJ1zkfFCU8/+BtXofgX/AMEsIpFl\nh8ReCA38JHxKkP8A7eV+YOnq8eNjsw/u79rNW/pMz3CqiIvy7Qvz/Nurln4V52o/8lFjP/Bkv/kj\naPB+P+zm2I/8Dl/8kfpdbfBj/gmhDKjW3iHwdvHCY+Ikh/8Abuuj8H/D79hbQdQW48H+IvDAuPL2\nKIvGzS5XaeNpuCDxntX5paLdbtUTem54flWTf/31XpHwjvkbxZDCdyvcPs/utXJifCvO/q7bz/Fv\nydSVv/SjrwnBmZuqrZxiY+anK/8A6Ufaevfsm/sAfGh7WDVNF0PXGtI/ItktfGdyxVc7tmIrkZ55\n5r1f9mv4Z/DT9nbSdT0b9m3T10y1utqanHZ6lNeY2nhSZnkKY9ARXAf8E8vgq/wZ+JjeNvFOgSXe\nlWSyXpdf3mNq7q+gvhh8eP2ZvjNf6v8A8Kp0a5l1+/uZGubSCJlKFW+Zn/2a+WqeHuYwhZ51ib9u\neX/yR6GJ4Bzl1mv7XxUodW5v/wCSMLx3fxaxk+Pr5V2LhvtUvkbQfXBXrXkmsfC/9j27vJrnWr3Q\njNKfMmM3ip1/HHn8fhWx+0Nrn2qa8tprySDy2ZUVW+VttfPS+HU1bTzNeQ5Mj/677u1v92uD/ULM\n6b/5G+I/8Dl/8kdy8Oc1Uf8Akd4r/wADl/8AJHrum/Dz9hjRp3fTvEHhiJyNzj/hNWPHqQbg8V0l\nlrf7L2n6c1pafEnw6tt0KnxgGVfpmY4/CvjL4sfDnW9FmZ3gkw3zqsab926vnz4nzePNJ8RWj20b\nBPN3f3V+Vf4lrtpeHOaVXeOcYn/wOX/yRxYjgLH03apnWK/8Dl/8kfp5P8KP2O/EELX8s2gXUciH\ndMvid2Ur35E+MVgeIP2ff+CfU0TSeI4PCqIqAO8/i94xtxxk/aB2r8xv+FyfFeST/kJTfud2+SOX\nav8Au7avW/xy+MFxp/kzSLLbM+3bdJ8si12rw2z6LTedYr/wZL/5I4P9Ra0rqOc4j/wJ/wDyR9y6\n/wDs/f8ABF/UMxa/4q+GgKZBEnxWaMr65xfCsA/sg/8ABCfVmMCa/wDDWY5GUi+Ms/4cLqNfnx42\n8M2HjDVHvNV0qOJV/it/4qh0Pwn4b0mPyLW2XbC25mb7zNXfDw5zeCu8/wAWn5VJf/JHm1eA8ynK\nyzKu/WT/AMz9HtM/YO/4IqGT7Tpdp4HkJHWP4sXbjH/geRXbaT+yx/wS/soFg0eLwisaDhYvH85A\nH/gXX516PqVhDGthbJCjR/dVX+Zq9l+EMdnrlp9jvLlkuNn7po127qJeHmcTjrn+Mf8A3El/8kaU\n/D7MI6xzOun5Sf8AmfbGi/CL9g7SrdLrRr3wsscZHlzL4wZwpJ4wxuD1New6V4Y0Dxr8Mrr4e6JY\nrq/hi8j2XVrbSNcRSLnoXUk9fRq+HIfgHdw+Hz4pubnybaFFZo2+VVbd92vtP9h+68S3fw8GkeGb\nMTwNGpkYv8sca15uL8Oc1pTjfO8U7/35f/JHsYTw/wAzrYafNnGJSXTnlb/0o8b+Lf7A3/BPvwYs\nes/Gv4d6XoEd84FvNr/i29sI5m7BPMuUUn2Wn+Cf2Hv2AZYY7zwF4K0q6iaQNHJY+L7ydGZfTFyw\nP0r6z/aG+CPgz9oP4FXXgbxzYNc7IpDayMvzQs38Vfl5N8H/ANo39iP4lJY721LwxHdM9ldRszNG\nv8K/8Cp1PD7OHhfaU88xUmt17SWn/kxyUvD7HfW3Snm2IXZ8z/8Akj768EfBnwz4MaG68EeC5YPJ\n/wBS8QlkA+m4mus1VPFOoy251fR5HljBS3eTTVD884B2ZOeteWfBX9szxCvhmF/E/hhjFJF/C+2S\nvY/hz4i1LxvqFtqb3LIrbmit5G/1a15y4FziWn9s4q7/AOnkv/kjureG2aw2zfENf43/APJEGoan\n4/06xRdUtrq3txyjT2ARfzKjNcL4mvfAKaNrF54p1+yt7G506WDWLm41TyUS3kG19z7x5QIONwII\nz1FehfHzxsGjGiNc7PLTftj/APQa+Yv2pJLbT/2UfHevXMzefJYQ26wqnyyNNNt2/wDfNYYbgDM6\n2PjSjm2Jvffnd16e8a1PDjNKeAlVqZzibJbc8rf+lHOQfs8f8EvgC8Gq+EGBUEsPiPMcjsf+Pz9a\nswfAP/gmekIig1Pwf5ZbaFHxBlIJ9P8Aj7618N2tqlvMEd1ZV/vf3q1NLt5lb98mf4tq/wDoVfof\n/EKM6cOZcQ4z/wAGS/8Akj5ijwZmDdlmldf9vv8A+SPtpPgL/wAE5Fn/AHeoeFRIg6L49lBHHp9q\n9KcvwN/4JzwMYv7R8JgsOVPjyTP63VfH8ciSSedNbfL8q7m+9/31U91pKLbvMjqNvzIqp935qwl4\nVZ514gxn/gyX/wAkd8eBsy5b/wBrYj/wN/8AyR9af8KO/wCCbYk2nVPCG8AjB8fSZH/k1VR/2fP+\nCZDvvk1TwgTuzz8RJuv/AIF18iatp6SXD3LfI8n+qXZtWsi90OG3ZnSGY7vmdv7tL/iFWec1v9YM\nZ/4Ml/8AJBLgXH9M2xH/AIG//kj7U1b/AIJ/fsVfF/wHqUPwmgtbe4kBgtfEOh+I579bO4AVwGRp\n3jfgruQ4JR+ChKuPzCvtNf5rxNxXfuX/AGdtfqN/wTLRU+A2rbANp8WzkELgn/RbXr71+dOreG/M\nj+zfKzr99ll2qv8As1t4U1c2w3EGdZTjMXUxEMNOkoSqScpe8qnNq23Z8sdL2VrpXbv5HC/16lmm\nYYGtXlVVKUFFzd3qpX1d30Wl7fezzTULeZmkeab7rf6tVX5l/wB6sDWLHcvyfMu75/8AZru77Q5r\nWE7Nu1k/4FWBqmlpGyTIjOn3nh3/AMNfu1OUT6OtG3unBatbTqr7Eyy/xN92vrv/AIIL2og/bI8S\nOp4b4aXmR7/2hp1fLmuae7L+7Rtuz5dq/wDjtfWf/BCuIxftf+I8RgBvhveEsPX+0NPr4jxViv8A\niHOZ2/59v80fIcSRtk2It/KfPv8AwWqsYZv+CjfxGkMpBYaQCAv/AFB7Kvj7VIc7kSFfu/J822vt\nn/gslZrc/wDBRD4h7gAD/ZI3bef+QRZV8c69ZuPndFVV/i+9ur1uBFbgXKn/ANQ1D/01EvJ/+RRQ\n/wAEf/SUYKb5Or09W8nO9Ny0y7j8ptnlqP8AdqFGk8vH8LV9Rynpe0J4ZNsn7nlv4FX+KrC3Dso+\nTb/f2vuqtbs43f79SrI8bZT/AHflqvsC9oWPtE8mxE2/N/6DTf37be237tNS3mk2zGHLL8u6r0Vn\nHtDvuH/APu1H90xlHmK0Kuys/nbl37au2trcySK4CuKt2GjpI2/ZuWtex0tm+RIvmZP4aqUhRM23\nh8lV+Td/vVbtLN48v0Xfu3fxL/s1sW+ho2xxbZZm/wC+avWuhmNd/wB5mb/x2sJSlKRtTj9oy4YY\nGw7wt8vy7asW9tNu+/t3Jt27627fQd0nzhk2/Ntakk0d4ZN+z/gTVzylynXTp+0MZrOaE7Oq/wCz\nSLC+1Ydqn+L958tbL6X5ab3pPL/eK72aru+X5v4awjUka+xPoJdJfzpUidd8a7kVVqytq9urBEUD\nylba3zbmrXm0v/SHfCs8KfO277zVE1vsk2PtULt+b+9XztSnyn2tP3viMW4t7qREhhmVD97d96s+\na1thiBIVy25VZk/i3fxV0N9p/nXEWy2UfeVmZvutVS8tU3CDYrfPuRWf5qx947JRhyGBd2syx7Pv\nIv8A481ZWoRwsy/O3zNu+X+Gt/VI/M3bblh5afw/3qy7qNJpvufw7mXb92uiHuz1OGpzcskYEsJk\nvtkz7Qvy/N92oZLWSybZI7OWf7tXbyP/AEkp5K437XWo12fZ/n/4+P4N392u7m/lW550o8xJptvD\nZ2vnQ/NubdtVfmrc0mG2kmSZIZGVX27fu1lWazRuCg3Q+bu3fxba6LSZoY7pNiNsVd/+z/wKol+7\n1FTj7SXKael6T9qMabMI38P/AMVWqunvG2weXt+6q53VFbslwo+zIrbl/er935a0reNI1TyYFULt\nX5v4f9quGVTmiehGnCIxdNST5/J+b+BW+XdULaelvarcw/Luf+//ABVda32xv9pfftddm1/4aqak\nu6Zktnwjfdj/ALtKmVOMf5TA1Zv3zcc7PutWO025ZU2eW6r91m+WtHWmhkuvJmRnXyl3Mr1j3000\njM+9URvldd/3a9CjLm904akuUZcXH25XtvObb/Ayptqpd+SuxHdpNyt8yrt2tTXu5riRkTcP9lvl\nqOfyfPX/AFbts+Rlf7tdUTL3eXmkWmk863XfNwv8P3f+BVltvWRgrsN3yqrf3qtzahuiRH6q/wAy\n/wB2qV9eJFG7u7LtX733mauqjGf2TCp/MQXRjt5vOmTlV+81fqT/AMFtJPJ/ZU0CUyFAvxBtCWDY\nI/0K+r8p7ybzpPvsrbf4q/VP/gt9HE/7KXh0zRhwvxEsztbp/wAeN/X5D4iQlHxD4YX/AE8rflSP\ngeJZc2f5b/in/wC2n5uQ3zyMj21yr/3dyf8AoVX9N1Z4d9sm5Azfd2/Mrf7Ncvp+peYr+dBtG/cu\n2rUeoOqu7u29vl3bPmWv3Lm5T6U7Oz1K2Zmfzvl/ur8tatrrDw3CeTM2N/8A47XCQ6t8w2OoXyvu\nqv3a0LXXP3yQzJmJvmRt1Zy2Ob7Z6JpPiDy9379gGdl3L/FWrHrT7Yd8zPJu3uq/dZa84s9WlWFU\n+YsrblaNfm/3a2dI1SGHbcwtIV+7ub726vOxEuU9TCxgehR+JkmYQwyt/e/3f9mtO31q8jVnuU+Z\nX3Oqtu21wdjeJKvmbFdt+7/gVa9rrG5neHcvy/6lvlb/AGq8mtWnDY9/D0YSidnb+JJWkVEdUbZt\n+akbX0htjCjtKvm7mbf8rVx0mtzQ/chZP3W5Pn3U5te8q2dHSTDfL/sq1ckpVfdSOnlpRibl3rKT\nTSvC+5t21FX5dq1kapqieX+5RnmVfmab5laqU2qJCqwu7Nu/iWqT3c214Zvl2vu3L/drOUpR3FGM\neUrXlxc7o5j+/wBq7fm+Wuf12N2kb+L/AIDWlqW+GMJbOxf723+FqybqeZVYeYx2plFX+Fv7tbRj\nKUeY5KlSEI2MPVNkKs6OwdvkRWi/9Brndcjja4a4dGVpF+7s/wBmum1aVNrfO38K7m/vVzmqXHne\nYjw7fnZk3fw13Uf5jjrcnJY5TWrXbGv+jM7N8ybvurXN6pD5NuYE/wB7bXVaozyMU3tsb+981c9q\nFokavv5O7aq/3lr1Kfux9082pR9ocrfWaK3yf7u3/ZrMmt9sjPsX/rn/AHq372O2hlDo7F9/yf7t\nZ95bozHZCuz/AGvvV1+0mcssPCRjSf6wfOw+9Vu0jSRm84MGX7rfw05oXdg6bf7u1v8A0KnwwvMy\n79o+f+GqlIqnRL9jvZkeH7q/eZv4q3bBvL2PCVX+FuKybWFNvzfw/wAVbelxwyTJDbfxfM6sn3q5\nZVIxOuNPob+nwpJjYihmf+KtrQ4Zmm850+78u2sjR7eb/XTbW+b5FX+7XR6TCm1ZnRv7u2vLrVj0\naVPmOgsfJhZPn3/w7f7v+9XRaSrMvnPuQR/wt/F/tVzumzPLL5yPsZX/AHu5PvVvWrP5x8l97N82\n1v4a8+p/KenS/vGtbxpDDHNvV0V9u3+JV/vVfaaFNmyCSVt33V+Ws7Rbj5VnuZtr/c2zJ96r0b7r\nOWFEXdJ8u2T5q5JfFqejTlDl5kWGsd3lu7rv/gZX+Zf9mpo7eZPKldFWT+7t3bf96q+5GkjOzlf4\nv9n+7U9id0Z+xr/H93d/DUumb0/5h0NqLjfv+b5PnVV2rWhawwtH88LB9m2L5fmWo9LsoZES5d2D\n/fRW+bd/wGte1t5ZI1ea2kX+Dcyfe/2q9CjGMtg5pS3KUOn+TIibFaXd91n+7Vu30tyzfaUUsqsy\nbvmrStbXzJBsRXZvvKqf+PVZtbNJm+2W0LIWf5FZa9TD04y0HL3YlGHR7Zo1mghVHb+L7y7aSfS7\naEeTNtEzfcVU+ault9BS8s1h8ldjP95vl20640ZFukSaZfubVVV+9/wKu+MeX4Tj5eY5C50ZI4wE\nRVK/MnyfeqrJpczKXm2yx/LukVfvNtrsP7J3XRS5h3Jt/vbWaqGpaPeW8I2QxjzH+df4Wrf7Jz1K\nfLLQ4i90m13fIiq7bleOSszVLd1jHnPvK/wr8v8A31XZ6npbqzPCkmxf+WkjL92srVNF2xsifvmk\n2rE3y/Mv96spR9n7xwVOWM+aJyP2GHzUTZiTd87b91QskK3DO+2FZPm/3Vrbm0/y2ZEdizbW/wBV\ntXdVK60t9x8mFd/3pWb5vlrjlUvPlJqR5PeZzWt2YkXelso3J/rF/irlLqzmjkaF4c7m+Tc/3q9H\n1azhmUJvVF+6m7+Ktb4K/sk/H79pbxRHo/wa+FGra47P5TyWtuyorL/E0jfKq1hLWHMEcRCnL32e\nLTxO0io4YfOqoq09tFmZfOgh3Kzfer9Ovg1/wblfE+6t4Nb/AGjvjNpXhmFyxl0fTU+2XCr/ALy/\nKtfQfhz/AIIIf8E8dDhjTX9d8b65IyrumbUFgXd/sqv8NeVWzbA4b3ZzN6M6lTWMJSPxHuNJmuG2\nTIzFfmZlSs+8s042TL/3xt3V+8Fx/wAEMf8AgmzJ8n/CGeKIdyN/pC+JmZt396vOvGf/AAb3/sia\nwx/4RH4v+N9IT7vlzGGda5o8Q5b/ADnuYPESpz96Ej8UryzSSR5rl9h2fxN/FUf9m7V39Wb5vmr9\nN/i5/wAG53xa0dJb74I/H3QPE8C/6qz8QW7Wtyzf3fl+Wvj745/8E9v2y/2cpLhPip8CtUitreX/\nAJCWjxfa7Zo/726OvRjmOFrfBM+rwuYYGrv7vqeDLYujZTbt/wBytSx0394iIcLI/wAi/wAVT29q\nkd8dKRfJkX78MyMrf981p2On7WG+aT+9uatJ1Iyhqe3h8Nh60bxI4dNeS1Lvt37/APlmn3WrSh01\n44w80LIGXcvy1ej0+2tVGxOZPubd3zNWhbx3MatDNM2W/h/h2151Spc1ng+XRmPHpaSTKEh/31/v\nVDeW+6Z5vtLAKv3VXd838NbK2cMknk3u1dr/AHt3zVQvLdF+RE4/+yrOUuY8LGYXllJo5q8td8m/\nYp3P81V7q3RmGHwf4NqVsXC+Yz/dXa3z7VqrJCsjH7N8g/vfw1dOp3Phcww/2jKa1SRVd/Mb/gH8\nNH2SFlVI+uxq2Y7N7hVRNwb7u5futT20dF+eP5yv8NdMsR7OEbngRo+8c6tjuVbkIrfw7dn3v9mq\nF5pPzO8EDY+7trrfsLtGUhh+9uZJP7tZV5p/zKmxQ7ffZaujieaXvBLCwOYjt08p9+1n/gj/ALzV\ndtNPuWV0d41+7uX+KnyWaWd4HR9jb/utUu6BWaZHZpW+bbXTUqe77plTpx5h9r/r2hRG/wBht1bW\nh2LsrQo8bFf4m/8AQqzLFXluPOmhaIN8y/LXR6HpaTQvDMivtfd/stUyly+8acvMdJ4d0nyYwro2\n5k3blrrNF07zFSOd1+b+Jf8A0KsbQ7VJlCJtb90yr821Vat/RPOs1Z5rb549q+Zs+WRayjGMp3Rf\n8E1tPt0hXeLldyttdWTdur79/wCCYK7PgFq6bcY8X3H4/wCi2lfCFlazQqkxdf3n3NqV96/8Ezon\ni+A+qrJFtb/hLZ885z/otrzX5B44QnHgOfN/z8p/mz4zxDrQnwzJL+aP5nxRHpc0kgR+QzKrKz/d\n/wC+at26vtaF5ldI22p5cW3/AL6qBWRdz2yN/eeH/wBmq15aRxBxtRF+/X7LTo8vun6dTxEY/aKt\n5bw2u37M7OJHZmXbWBrMPlq8L23y7d3zP/FXVTWU0k3nPbb0X5tzfLtrA8SWP7wON2+H/vna1XGn\nHY9XD4zlicPrVrDcWv2xIV2R/wC392uR1hfJVoUuY3VvmRq7jW1S3t3+zQqyfMHX7v8AwKvPPEV1\nGrtCibWX7i7/AJWrrw9PmPSp5glqjJvvJC/c3bdvzeb/ABVn3jfenZN0bfL/AHqmkuPLbyYUb5fv\neZ/dqpNK7SLsRfm+Zv8Adr0KeHiznxGaSUblG4V9rfvtxZv+BVl333X2bj/tf3q0ryZPMd+m7+Ks\n28kZofJm+4u77tbxo8sD5/FZjHlKd3NuiVHucbW+9/eX+7UljO8XybPl/gVf4qoXE0MjEp/D/C38\nNPtbh5mSOF9p/gZaJRgeDLFe/udRpsc8bfPCo2ptT5t1dHpezYnneX+8+Xdv/irldFuEZf3yM0q/\nxb66OxukmuEM6KF27kVq5qkvslfWubU6axYKpSFGQx/L838NaentCsiokys6/ernoWeOMOm2VvvL\n833a1dLvIWzDMiq6vuddvzVx1Drp1uU6/wAM+cJN6Tbdv3fM+bctehfD2zv9U8RW01gm2aGdZYo1\n/iry+zvna3RIef8Adr1f4E+LNN8N+PrLUr9/LtI5V3My/eX+Kuevzey5UEsYoy5on6r+BPFHiXQ/\n2ZrPwpD4Rns9S8Q2X2aK9kX/AFny7W2f99V5v4I8T6V+xv8AEPSf2V/C0NjeeL/F8sbeJ75U3S2t\nu3zLHu/h3fxV7J8S/wBqv4D/ABX/AGQtGt/h1qq/27oC28ulxyRbH8yP722vlOw/Zs+PXw4/ba8L\nftT/ABr1WH7N4vuPNsVafzJGjWP/AMd/2a+KzTC8vv0n0+4+hyDNaGMcoYla/wAvd9Dpv2jGnuPE\nF7D8v7m62pGv8P8AergfD+g6lrF0m9NsMfzbf/QV212v7QEkM2sX9yjt5zS75V+63l7t1VvhHC+v\nrNNBbMixxbtv3v8AvqvnqkvdPr6dP2h0Oi+EfCVrC2t+J7C1eSayZIpLj7sf+0q/3q+Y/jZ8G9N1\nTxauq/2VNJbzXDJFGsW5lXd8tfTHiDx54W8E6olheIuovsZpVWLcsNcVfeL9N1hZB9khc/M+6T7s\nNezlsv3Wp4WaU+Wryo+ddS/Zd0HT45bm8sIYhv8Am3f7v96vBPixoug+EZHSO8/1e7eyt8v/AAGv\nb/2lfjVeaDaromlWc0sU25vMaX5a+LviN42v77UjbXjsyyOzfM25d1exGdSUdDx/Z0sP702Qa14y\n3Xh+xvJFGr/wv/DWJdeOJrVtiTMwb5V3NXPapr3mNJC6bv8AarlbzXHuJkREby2fa+7/ANCrpp0f\nb/ZOCtjYU3aMj6h/ZN+FPi34uao+qpDN/Z1n8txcfdXd/d3V9Y+Afg7eWviCC5sHbYzqm1ov/Hq+\navhd/wAFA9B/ZU+Eei+FPASWtxcfY2/tS6mtVl85m/3q6C9/4KqWHijwWLvS5oYdRX7/ANni2ttr\njrRqX92kevh5YeEPeqx5j7D+P3ii2+HOi2fg+515ppL7bJEq/Kscf95lr6y/4Jca5Y6t4CutFgK/\naZbZhE8VxuWRfm+avwlm/a08V+LPFreJ/E/iG+vLmaXa0l5cfKy/wrtr7u/4J6/ts3Pgm6trxNV8\n5WlX92su1VX+Ja83FVKtCUZzjsdeFnQxNKdGlL3mffHin9rrwf4B+IF78IvEOpLb3bRbYmml+6u7\nb92vP/E3jLSfiRpMvhW8mWaxVvkkZfmkb+Fq8E/4Kha54Y1r4Xr+1F4Pv47TWNNv4/tUa/6yaFvv\nKteN/s2/tOX/AIkuIEu9TuJ5mdVlWR/lb/drhXPKPtYP3ZH0FHD4eUOWovePqr4E/s9+LU8bPNo+\npXFxEt/t+zzfd2/wr838NfUd5rGq+GvDcOlXmiRw3bJuna3Tay/w/LVD9kb+yNb0K31Sa2VZWbcz\nRv8Avd395q7j40rpqsUis2+WJl+VvmanWjGNByXxHlVpSjjFTPCvF99NqV5/xMkaTb/E1eFftreI\nLzR/2dZbaGLybPWNRhggWSLd5kit/Du/u19DeJNNttL0b7fNGw3fek+6y/7NfG/7dnjC88SeINE8\nAXM0ktjpdu14qw3G6NZJF+X5f71HDWH+sZvGUvsl53iPZ5e4r7R8+WukXm1v30YZU3fvErW02F22\nQ2z/AL3yvvbf/ZqdptrNbzRebN8jPtZlT5ttX4bfddK42+c0v9/+Gv1mUYS90+Lw8fd1J7W3hW3d\n9nlMvzfvv4q0lt3Xaj/eZfn8tvlqGGzcRs83lojP8ke6tOxsy37lHX5tq1PsY/EejGXL7plalpcL\nbpZtqN/EzfN/wKsjUdNdl85JpN/8S/wr/wDY12P9lv5LQjdEV+Vo2+aoJtDma3WYWbfMn8SfK1aU\n6alLQ55VPsn0v/wTftVtfgfqoVwwfxXM27dnObW1r4F17QftDNc71j/56/3K/Q39gi0is/g/qSQs\nCreJZmXAA/5d7cdvpXwzf6D5kLKlthV+ZvMr8a8No38Q+J3/ANPKH5VT8x4fqW4kzZ/3qf5TPJtb\n0GaJmmh2/vtvzb922uW1i1eFXRHbP3dzfdr1nXtDeOzlufJ2qz7tu3ay/wD2NcbqmivC3/Hsu1m3\nPGv92v3OnTjI+lqUzzrVtLEcJHzM0a/eZ/4mr6l/4Ij2H2P9rvX/AJMY+HN4uduM/wDEw0+vn3V9\nHTa6O+/c3yRtX03/AMEZbMwftWeIZnQAnwHdgY9Pt1jXwPivf/iHGZ3/AOfb/NHx/FEYxyavb+U+\nff8AgsJZJN/wUC+ILZU7v7J3KV/6hNnXx54g0nyZD87bK+3P+Ctun/aP28vH8pQFSumA5Xv/AGVZ\n18ieJtJdsP5zbf4VavW4Ej/xgmVf9g1D/wBNQJypy/snDr+5D/0lHmmqWflzb9indUENq0is+Mba\n3tW0l42be6ru+ZVqlHpLs2x/l+T71fU8vL7x3lOGyeTPz4/2qtxWrwypI+77u1FrVsdHm3L5Cb0/\n2q17Hw+l0yzTIyf7O37tRy+7oXI5+10maSTZHubb/DWvBoM0m1Ifu/xq1dJpvhtWQPD8qKny1p6X\n4bedorlPnZfvfLV8vP7pHwnO2eh+XtTyWH+1Wzb6PtK7eG/vNW4vh8Rw732v/wAC+7V6Pw3N5uxE\n3xr/AMtlf5d1ZS5uUcTEsbW5hVP9G37fm2tWxptiki73TczfMu3+GtCz0O883y0O1W+/5nzf8Brc\n03wu6qrPbfvf4l/hrCUZnTTMi30N7iQXiJ8iy/w0t1o7yM+Icf7P8NdlY+H32pN5eFh+Zqv/APCN\n2p+/8ssnzIy/3a5anmdtOXLLQ8wuNIhkHkvbbW+981UJdG3SM7uo3f6pl/hr0bUvC5aR/ky+z7zf\ndrE1Lw+luqQpDvbf/u1lH4/dOmMoy909tSGFpA823cv3I9ny/wDAqguLd/tW3fG8TL87L96tmS1e\n2tftKRbXVmVfO/iWq3nfvEmhh2fJub5N1eZKifaRiY1xClvIYZvlaT5l2r95f9pqzr+xTzle2kVB\ns3bpP4a6bULZLhd6WbMJE3N/vVlaha2zRrD8zOv8O3+Gk6XLqhVJcsTndWjmjjdLOZf725fm3Vz9\n9GgXZ53LfejaukuLPcu90Xbt2pu+X5a5nxBGlmxmT5FZvvKtT7GSlY4qlSP2jL1Kb7s2/fu++392\nqbXH/LHzlO7+Kn6lPukaSFP3W35t1VbVvJT988eNiqkar93/AGq3jHlPOlLml5GxZtM0a/PlV/ur\n/DWzp7JDDuR2TbtZGb71czHebm8l04V/4W+at3SV+1P5KJu/i8xf4qxrR5YlUZRkdZpt4jQpdTTb\ndzbGkrSh1C2/1PzOse75fu1zlnI8MKJCcJsZtv8AearS3ltuN55Lea332Wubl97U6uaRsf2huhZE\ntmV1T7v97/aqjeXDiPfNudfuvHWdcalMzK7zLG27a0bP/wB81F50ykzTTrj5l27vutRGMypVJdCD\nWGt5oX+fa6/Mi1zbXCOypv2S7vu/eVqvatdQhmSb5y33qwtSuv3exHXZt3Mv+1Xdh1GMTzMRKTkP\n1C4RlYzeYzq/8LVnX+sRhWSxdQn97+KorjUIUVnRFV2+/uesa81ZAqv/AHvu16UKPMcUsRLk5TZt\n9SkuNrufmX+791qbc30PmL/pkjt95l/hjrnYdYeOZk879yz7U/u1dutQhmhDw7gm37tdlOPKYSr8\npozXUdxGN+3O37yv95q/VP8A4LlTTQ/smeHmgcKT8RbQHPcfYL/ivySh1LbcPxvRv7zfdr9Zv+C7\nUxh/ZF8OkEc/Ea0BJGf+XDUK/GfEeMv+Ih8L/wDXyv8AlSPhuIavPnuXy/vT/wDbT8tluEaTZ0H8\nG5qsLfTKPJR9jf3q52S+e14++f4Ny063v/NV/wC8z/8AAq/bpS+yfVSqe7/eOoj1LDFHdX3ffqzb\n6k8zP867Ifuqtc1DcGRvLd2I/jk+781aNnfPI2/zFwybdy1zVJTN4/zHV2OpbpVCXP3k+Tb8taul\n6pt2qjybl+bcqfLXJrqCWsMUe9f/AGb/AGa1dLvJlXe8ytt+b5V+7/eriqHbR+I7e31SZoU/cqE+\n9tjfa1aS61vt/Oe83MzqryMn+zXFWeqQ3CsnnbVX/no1WG1RzGjpMzM3zbY/ljrx6y5tT2qNTlgd\nguqbVS5jT94yt8zNTJNUyzO9zv8Au+aq1zy688Nn/rsGRNn+WqRdWmiVv+mibNq1Eaci6lSB0K3D\nySsju22b7lKt1Zxqu+b51X51jTdWLb3zvGqO8ilX2/7W3+9UlvcJcSH5/N3blebbt3KtR7Mj2kPh\nLc10l2rzTSs0Tf3V21hXzTSxrNbSMn3ldW/vVtbIZoVffuEaf6vd95ao3du8cLu+1kbb+7j+9Vxj\ny+6ElzHO6nNftH9jc733fd/2a5vULf5pkmmbau1kVv4q7C+heFvO8mTDJ97/AGq5/XNPSSTy3h3f\n7SrXVRqRj7qOSVHm1kcvqFq8MmyF2f8A2v4dtYmpfKzTbPmX5UbZ8tdRq1r5e77u1fvVgatMgGx+\niv8APt/irrjU5pjjh+aPKctfW825n+638CstZ+oWzvGwT5n37vmrcvlMg/1Pyt/47WXf2TyK3zso\n+9XbGXumNTD8pjzK8ch9KW1t3jbfNHt3fNVjyUbO/wCb+KpY7UM2x33nb8tac3Kc/sZ/EWNPV/m8\nlGDf3m+7XQ6Xapa3EWxPm+6zL92s7TbVIdnnQsG2bv8Aero9LhSSP54Vbd9xmSvPrVoHRToy5zV0\n+FF2Om7d93/Z3V0NnHNGyb5FD7PvKlY9isIi8nLfN9zb/DWxZx/IyvMz+Z827+7Xmyfvczid0Y8v\nwmtZq8cfyTfe/iZf4q1dPUMrfut8UafMy/3qz7Fprjy4U2nam35f4q1LFXb/AEZwuPuurVjKXu8x\n1R980IUfa8Lw7yzbauTrM0cUybc/d27vu0Wq+XiaaH5fKbbHGn3lp+n2u0lEhb7/AN5q5fe+KB0r\nljo5Fmz861VHRF3bPn3fNVqzV5mSa2TY2397HIu5ajs4ZoULvCriTd95v/Qa19Lsd0iujtsXa77f\n4V/u1pCXvSOyPN7L3S/pdq8W3y4Y9n3ZW+7/AN81uafpqKv75Pu/L8v92q2i6bNbqqzXO+LezS7l\n3blroLWzSaRXiRXEPy16dKPuXiZfDIpx2LyTLsT/AFny/NWno+kfu/n6t9xd+3btq0unpGFTerlf\nuRwruVq17Oy8va8yNv8A7u3+L/2WuuEo0xylKUit/ZnmWI2bVTY29W/hqS30kt+5h27Nu7c396ti\n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\nZuoX3lgrv3bflqG+uvJkd/Mx/drIvNVTdh5sOzfxV20jy61blLN1qCR7djsE+9t31Yh17y7cIj7v\n9pfutXPTakm4u+1QrU23vk+Z/O3f3lWto+Zze0n8R1UOpJJIrwur7v8Ax2v14/4L4TCL9jzw4GOF\nf4k2asfb+z9Qr8Z9Lk3SLsfaV/vPX7J/8F+3Cfsc+GiQTn4l2fT/ALB2o1+L+JGniNwv/wBfK35U\nj5PO5c2dYD/FL/20/Jc3nnMrvu3L9/56WG4mm/vLu+VqpQsnmb/4G/i/iq5aLPtZN/3q/aJSPq6f\nxaGlZyP/ABn5v4dtXLW68uP5OP8AZ/u1mwTPDIIZvu/3v4au2rbvuOxX7tYyj/Md9OPU3IbhZmTf\ntRV/iX+9V6zvtsw+f5VVty7vlasO3wqrJPMqIzfLWgt4WJTeqbvur/FXNKMDup80feNu1unWzR0f\nMjbtnyf+OtVuz1GNIdibd38e7cy1zf26aPd8m3d83zVbsdQ+VEdl+VtyR159aJ3UakeY6Bbh5ttl\nc7nRfu7U/wDHavLcf6Qk1t5iN95W27qwY7iZY/nmZl/i+atGG6dVV3DY/jVfurWcoy5dDSpym5Jd\nTKUCBlDS/vWZfvVbtZEmk2Qov8P7yP8A5aVkWcyTXqJMkjo3zJWpawzRqZofkRf++t1YSjHl+Ifx\nTLqx+fDsR1Ta/wB5f71F5Dtb7Mjt5Ujrs2/N81OM263RHdvufvWk+VaerXjKNiMhVPk+Tcu3+7ur\nOpzx906Y8stjIvFmXd5MvmeSjKjfw1iahbpJC7pctlVZmWul1Cx8lZTZ+WI/7sfzfNWHdWrhRBcp\n/tfKm2lGP2izl9Tt3WF0eFVuN27dJ93btrlry1eNi83Ndz4itXVtkKbn2/J/drlrq1eaR3hhV933\ntvyrXXTqe7cuUeXY5TWLWbcqxuyj723+7WbdQ7mPz7m/vVvXlj9qmZH8z5f4aq3Gnv8A3/8AdWuy\nnU5dDn5eYwPsqDcifdb+JvvVcsbHDRl15/u1ba3TcqCNWZfm+Zau2Nn/AMs3fcrJu3f3aVSt/KXT\noxj8RY02xjVt/nK0v92tezhTzA8KMu7+9/DVezsYY/Kfycv91WX5q1Y7J7Xcj9Pvf8CrzpSibSpw\nLVvb7pFfZh1+X5f4q1NPheObzoU3bm2t8ny1Vt12yb1fKyJ/F81aljG6t874f5dsa0+blhocvL75\n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\nvc2tJt4ZG85OkPyfL/eb+9Xb6Pa7oUD7iV+X5q5jS7BLf99sZpvm+Vf/AEJa6vw5D5caQu8hRtu9\nv4vmr1sLHmgedWlKnI2rO1v4WbyYdp+95jJ91f7ta2n6b5kqCFJDui+8v3ZKn0u322rJs3K3y/vP\n4q3ND024t7ZLa52r5m1nb7q7f9mvTo05bHDKsZ9lpd55Zd9u3/lqq/dq5HpsUOOJJn+ZW/h27q3b\nPS0bfCvCK6/e/u1eh8NpNO6XKbt23yo1/wDQq6+X3iIVpS0OPutLSa2aG5dnWT5W/wBn/ZrjtT8M\nv4m8Yf2NZ6rCkdi6u9vN/E38P+7XrfirQ303w7fTb4UZV2xSSf8APRvlWubsfh7beBbe21XWE+z3\nn+qulkdW85t33vM+9trxM6xEcPQt/MVXxE5fuzE8eXUFrobM6Wtpc71RGh+8zfxf7v8AerwLWrq8\nj1q4ub+88x9vyMz/ACxr/druPi5Z39nqWp2E7xvNNLt3ebu/4Furze6tbm+WPR7C2Z5Gibd5n3Vb\ndXylBSlscUve9057xtY3k1mk9rDHsWJn/wBnd/erzfxhMY4Wmhud1zsXd6LXq/i5bzRdLh0S8ud6\nxtuVY4vmb5fu7q4C+8L3OuBM+dH5j7drJ8rf71dVGpGM/IKkZShynAQ6akl2u9FZ4X82WRn+61UN\nSv5Li+Wa2Tj7jt/E3+1XobfD25vLUQq6q7PtXc235v8Aa/2aydR0PStJjSz1W/tftbbvNkj/AOWf\n+zXrxlQlI4KlOUYHAeIrKG1kifzpJkZN26Ntu2s1Y3tYpX+0tvVt21mrqtet7G1kR9/mBvmdv4dv\n+zXLapqENxL+4SN/7jbvmWolKEjL3ojvO1Web5H3Rybdnz/NXQaPYa9JGdh80bvl3L/DXP6XqFhK\n2x5sS7921vl212ek606sjpCqQt/t1wYyo6cYnXh/3kviNLQ7waVMX/drc7du2RvlWu/8D65Msge5\n2vcNtXaqf+PVyVrJpWoYhhmt9330aT+9WhperTabfeTc6lCySN/yz/hr56vKNaUrn2eV2pSjzHu/\nhnxNNbRl7n7mz96v8O3+9Xtfwl8baVrmjtZ/uZRt3eY396vk2x8QOy/udVbayMvzf3a7L4b+OLzw\nzcJZW1+tonmr82/5W3V42I5afun29CrSjLl7n1VHoNnIq3MUKymPdt8t9q1Vk0fT9F1a2v4YWaGR\n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\naz7pU8mM7X2/N96qu4o2yaFUaP50+Stoc3NzM5JSIdLs5rMv5MaqJIv9W33Vatyz2W7hB8/yKjyL\n81Z1jb20kjzIiov3mrQ023SOZvnbzfuv/dZaxxEeY2w/vG3Cq28jTSbSzIqquzburV0+RFkVNke7\n+Dd/FWTaxPI/kzfKn3Yv7y/7VbUNn5yrv5RWVn3fKqtt/hrglzcvwndT+I17NZ71U2JlpHw/y/Lu\nrahhdW3vx/7Mv8VZdnvjQuXwV+5t+7urY0GSFt0f7t1b5UZv4aI8nNblO77HMX9PtYJJP3MPyt83\nmK3y7a6PTbWzkkF4ibdvyrtT5mrN03Tfs7L5ab0/jXZ91a6PR7JLVUTfIFV/3XzV2UaXVHPW92Ja\nt7d92PlEv8Lf3VrrPD6wrJG+/c3zfN93bWZpapN5vnozru/e7k2s1b+h2Mx2/Ou2OVt+5Pm2/wAN\nezhY8vunl4iUuXmOn8Oy+dIULx7f41+83+9XS2a7oWaZMLv2xLs3bq5bw/G7TPOgYf3m/wCBfdrr\ntNkTzVmhdtq/fj2169OPKeTKUueRs6fG8kPnbI1Vfvsv8Vb2nw23zI+4+d8sUm3ay1n6O1tdTI6I\ns6L8u1V+Vt1bem27Nb/I6sv3K6OX3R+SM3xR4ah8RTado+xti3Sz3EK/N5yr/ermfjZa3+pa5cTW\ntnbtbWsS+V/Cyt/Cteha9efYdPTfcwxG3tWdJPK3SRrXlfijVNS1TTQ+q20breXCrLJHuX5V/ir8\n/wCIakvrtvskU5SqTueL+PPDs2ta5NrFt8iq6rLGr/dbb96uUk8MvY3hvIbbZJN8ssiv/wCPV3Pi\n7T5m8QCz+2LDaLLubcu3dWb8QFe3LahYI0aeUsUX9xpP/Za8aM+SOhr7OftThPF1jc6gtnpsKZih\ni3PJt27m/i+aud1zQ9K0e4t7k7mTfuuI5n+VmX+Kuo8W/adP017mGbeNqq6/+hba881zVJo7eTzn\nVl/h8z5mpU6nu3O2nh5I4/x1rzw6s9yl4sy+b+68tvlVa4C4vr/Utaeab97t+8q/ear/AIuuLbdI\n8j7du7fH95a4u+8WJax/ZrN23KiszR/fr0qNSmoeZ5uIpykXvFN26zf6S8caTRKyrI/zVzWoM9xf\nKls+/wCT7qrWRea5c3Vw/nXLbF+ZFaks/ET2NuJEdd2/738VdVP3Y2OOpGL1H3Elyt4k29RLv2s3\n3qvXnjG5tYntkm3IqL8zfLt/3azvtltdMlzDcqvzfdb7zf7TUuuaXbXFus3nK27+6v8A6FWcoRqR\nXMyKcZx94fp/jrVZG85LxkdfubX+Wum8O+OL+O8RLyHesit5skj/AHa4OO3ezj2JbKyr825acviK\n8t1/do3yt8jVw1sFTl70UehRxU6co80j3zQfH32WxZ7nUlX91t/cxb2X+7XVeDfHFzuW/SaFkZlb\nzLh/ut/d21836b4yd91s8ygt/Ft+Wux8L+JrBV2TPI7t9xd37uvIxGF5fekfXYPNoSjG8j7B8E/F\njTb66W1mv9ss0X3ZP4tv92vQpPG3nRxJf21vCsf/ACz/APZt1fK/wt8aWFzdwpqWpWMTx/LbzM25\nv+BV7h4V8M2PxIukS58Q7JV/1TW8vysv96vDxEXGfN0PsMPifrFLmhse2fA34veHtJ8VxWdzCzbX\n2vIyblVf71for8JfGvgl/Duk61N4gjkO7ykijl2r/utX5laH8GtV+F/iCTUtl1dsturRbX8xpP4q\n+3f2YfEHgr4geB7OztvLttSt12Nasu1l/wDsqqhio4XSPU5MdOliqXLI96+JNyuvIbPSnjnhXc25\npflWvF/GDX+n3NnoIsmiaSWNkWNW2V2d14J1Lw9dXGpP4kkeONtvk/eVt33q0NN0fTvE1xYXkr/8\ne8/7/wD6aR/3amtjv3/vnm1cvh9Wi4PY/OT/AILPfCy20CTwl8QrOzaB47+S1laN96tJIu7a1fEk\niw/Okz7/AJFX7+1Wav0j/wCC5OnyX3wgtNaW5aNLXxVavFDHF8m3ays1fm1HLbLD8kP3q+uySp7b\nB83mcNenPDyt/dJo7g7lh2Kkqp8n8W1f7tVLy4aRl/c7t3y7lfcv/AqW+j2sLm2tt77du7ftaobq\n4+zRtsPyN96vdjE8+UvdEwnkq6bgfvNI33qsabD5kj+c+5W+9/8AE1Tt5nusfdYN/F/drSsbeS4d\nH3qifd+58tdFGM4nLUkWNJtUupJZoUYnd8q/3a6Kxs4fMfZI23/aX5qpWdsm1N3zNsb5fKZW3f7N\nbmn6TNHs+TcP7zV6tOPuHBU/wk2m/NGN/wDe3JG3ytW1psjrMpRN3+03zNVTT4fMTf524ru+8n/j\n1WGZ7R4nR90Tfw7a35Dkqfymr5jspgjdXRvllWvsj/gn0Ix8GtU8uYPnxRNkgY5+zW1fFUN1bQyM\n8PyfP87N/er7Q/4J3sG+CepZdGYeJ5g7J0J+zW2a/GvHtcvh/UX/AE8p/mz4njtf8IEn/eifItrd\nPbyM/wAu7Zt3M/8ADUNwrrdPZzfPDuX70Xzfd/vVUm1BIXFtC+5F+6zVdWbzIUe5fcrMvzb/AJd1\nfsns/ePr4x94iaFIVOzcm5dyL/eqjKYbiFrm2farfc3f3qtyX/mSSoIMsvzfLVBb7dJ5OxfLh+ba\n33VWolKcY6m9Gj7SWhTuI0ZdiWy5VtySbv4q0dF0G5vrhHv0Vvm/5Z/eZqZpdi9xcJM8GyJX+Ta3\nzNXoPgfwv5mN8zMvzeUsn3t1aUY8x6kcH7OKsWfDfhNN2/ZH83zSybPmb+6tdfpPhua6Vt7qpZd6\nbU/9CrR8K+F/lS5dI02vvT/4muuj0HzLcvbIsbR/xbf4a74y5Y6ESp9jlLHQ4ZIfPhT5ZH/u7d3/\nAAKpL7w/bWNv9pv0VI4fle4Z9u2tXxb8QvB/hPS3eaH7RLGm541T5VrwDx/8ate8UXTW0KNcJI22\n3t4V2qq/7VEZS5rJHl47HUMNHlcjovF3xM8MabJNbWFrJfXCtu2xxfw/3t1ebeNPiVNq90lnqUM1\nxDIjNBY2K7lVv7rNTvtF5Hn+3r+Oy/vQw/Mzf7NZl7440Hw7H5ujwqk3zBJtnzVvTifNYrMa9T3Y\nmlb3eq30K3L+HrPT7Tf/AMe/3GkX+LdWJrV54bs13wx2+6T5kkb5vL21xfiz4yXk6ywpuDqrfvv4\nd1eY+IPihrOoXG97nd/D9/7tacyPNjF/akdt448cW15dSQ21zv2/LKzf+y/3a8117VE5feyqv3F2\n1k3viy5uJtkxyrfxfxf7zVkX2rXMczfPuZv4WpyXMax974ih4gTdI00L8N8zRqtchrmnhm3+dsKt\n92uqudSLK/nP/srXP6hNNI+ySZVP3VZqXxFxkcDr7XNuzfPtrNl2TKZkRgP4q6rXNLhuI2T5flZv\nvf3q5jyXtZHtXT5d/wB7ZRE05irHdTRzfI+7b/drY0/Vo3/czcq331rn7pXsrjY8Oz56sW90kc2/\nftp8qJ+I25r660e+i1G2nmDRsrbo32svzV+pX7K/ij4e/wDBVT9ju+/Zv+KOpQt438I2+7w5dM/7\n2Zdvy/e+avyqW+S6t/3k3Neh/si/tJeLf2WvjhpXxI8H6xNC0Nwq3Sx/8to93zR1UZypyujOVOMt\nEP8AjN8AfH/wL8d6j4G8VaPcJNYzsrSbPlb/AGlrlLWbbIftKMjL8tfsf+0l8H/hv+3N8DdM/aD+\nHtvb/abrRlnv/JX7sn8St/tLX5hfEv8AZ/1jwrq8kN/YbHWXajRr8v8AwKuLHYWMo88I6GmHx3sp\neyqbnmsjeZib7h2fwvTlkSRQ8/Hy/erTvPBupafNKk0LMN/3arrpL7tk0Mmxvu/JXh+zlHY9iNaM\no3jIv6LapuRzNn/dr1v4T+Ite8NtE6fOvm7tu/8AhryrQdFmm1KJERtjOv3a+wv2U/B3gmFbS58R\naDDNL5qt5jNu2tu/u/7teVm1aNGlbl3PSytV6lX91L3j0f4D+NPFuuapbaVbabMBNb7omb5fvfL8\ntfWXgXSb/wAL6HE9/efMu1bhht2/8CrkPBfhPTLjVxreneS9vt3RKq7flro9Qkm1SRrawhkxs2su\nz5a/P8dUjWfKtD7zDyq06X7yXMz0zSb/AFLxIyWejwxzHZt3N83/AAJa+T/+CjPxU1Lw/qNh8HP7\nNutPm1CJb+XzomjeSFW27l/3mr78/YI+BN1qPi/T9Z8bQ+VZlPmt5l+b/drI/wCDkf8AZVsNf+B3\nhf8Aaw8IaRCtx4JulsdWaGLbu0+b7rfL/CrV9LwtkFCtJ15P4dkfO51mtfDVow5dGfkBY3iRtsfa\ni/xt5XzMtdLof3duzc/91W3K3+81cnY3z3EazeS2zZ8jMm3dW5o98iskj3knzbV2qn3a+zoR5Ged\nWlznT2u+1VHdPn3M1aum6gjSIly6x/MzJ/CtYOmtcyXG/wC073V2+bZVyS8eOQfaZl2s6tukT5a9\nWn73unj1pcp2Om3ltIuz7Nvddv8AH96t7TdSufs7w+dGzfdT/ZrzfS9ee1mff5e1vl2s/wB6tmx1\ni8kZ/JuP+A7/ALq13RjynH7Tllqek6X4gmjjSa5ePZ91vMX/AMerpdN1h47dNjsiyJ8k3+1XlFjr\nSKWR9qMzNvVv4lrpvD+vXMjRTTJJtZfkjk/u/wB6tIxk9yo1PdPWtE8Qfak+d49u/b/vVr2OoTNH\nvm27fup5cv3q840fWG+/M6r5e7ymZ9y7Wrb0/wAQWy7Jo5l8uP5naP5lrb4TOXvH0z8B7iC58HTy\nW7Ej+0XBJbPPlx1xWk6tbQsnzzB9y/Kqbl/3q6H9lvUINT+H13cW5+UavIOuf+WUVeVaX4gvAPLe\n5Vlb7jLLtZq/EPDJ28SuKv8Ar7Q/KqfI5RL/AIV8c/70f/bj1vSdcRoVkQtv+67f7NbC60sluEe5\nUGT5dv8AFu/2a8w03xLeSdXVk+88cNbcfiKFmZ/MUsr7bdf4mb/a/u1+9Rke/UjzHXanfO0geFGf\nb8r7nrQ8JlTqTCNjsNuSoPf5l5rj18QW02zedwZm/wD2a6bwHdFtVltWKEiBmBRs8blr888Xpxfh\npmi/6dP80eLnkLZTVfkS+Ido1eZmZc/KFU/7o+asPWmjjhV0dflX5WVv4ateL9WFr4hurRwoVjGN\nx7fKKwdU1xZI5bZHjQN8iTL/ABV6vh9O3AWU/wDYNQ/9NQN8rp/8J1GX9yP5Ip6teQNEf9YWVNqe\nWv3f96se8vLmNtm/yv3W3zP71Pm1L7QuZty/L88ituZv9msfUNQ8yzCPtV1bbuWvp5SPUjH7RS1q\n9ebY8KNsX7/lttrm9Q1BCHh+Vtv3vk+9V3XLya1V9m5dzr8qp/DXGa1qX7yWzTciN9xo32tXPKR0\ncrOhtdS+ZYep/gZX+Wun8OXXnR7HvFwyfd3/ADNXmNvqkMePJeNjIv8AC9dF4f1h7NVSG6XDJ93b\n8ytXPzcwSPUtJ1DbGY7Z2fy5du2pLi4cwxJDc+ajN8/yfdb/AGq5C18STLGV3rH/ABeYtOuPGkG5\nczMm75flSqlLoT7hsXWtbrjeiYZXbYzfw/7NZV14ghW4LzPw33F/2v71YVxrTQ74Um2PM+5NzfeX\n+9WDfa9t/c/b/wB2q/eZ9zNWVSoOMfeOyn8RW334X8vbt/jq/Z6y900qecu9vlTb/DXkt54s2yfu\nXXe3y7VX5f8Aeq74V8bTSfI6b7hfl3NWMpcw+X3z3bSb6FbT99NG6L8u2Rvmarjat9oXZ5bJuTci\n/wANcDY+KE8lLmbnd935vvf7NSal4omh8t2dVTZu276zlIvl98/KfQ1dbXY8LFNm35nrcs5EFqlt\n+72N/DvqhZ6eYmf98xH3tu37tXLOOZm3wiRTuberf+hV4MsR7/un3dOjCJNumVleb+L5V/3agupL\nbaqQ+Xn7zLV23t3kj/ffM/3ty1DcWKeS7xvGzNuV221PtuaXMa+x5TJktYVjV43Usv8A7NUNvZnc\n8jt97+H722tBrOZFHKq33mVVprW821nhTJ+X5m/i/vU+bmj7xMYy/lM7dbBlR9zn7qfN91qkj8mO\naNH+Zl+Xdv8AvUupWrWH7vZjb/DWTcXe2F9m5tzbWrrpxhPlscdSUoytKJu2epTN/oybkHzMv92t\nD7YGXy3TcI/7v8NczY6h5kY/ffLHV+x1abzPNh+Tcm35v4q6I/abMZWly2NNpEkj87ft2t87bf8A\n2Woo5kjhO+Zl+b5aof2g8M2/zlDNF+9ZqrXmpC6XenzBU+XdTjExlU94NT1SE7vn2N/erm9c1LzG\n32z8fd3Va1K6eNt6Ov7xPnXdWBq2/wAx3hdQW+58/wB2t4xucdSp75nahqSSfI6bf723+KuevNQe\nRmdP+Bsv8VaOp75N3kpy23e1ZX2N/LKRpn59v3/4q0+E5I+9rIreZ9o3pD8lW7OOZVT+5/HS2On+\nXIyv8zt/dT71WodMmjm3j5l+9Uv4viO6nH3iW1hhlk2bGba3yt/DWvZwzj/lsqrsqjDbvbtsdM7n\n3LtT+GtBY3UbETf8/wDD/DXNU5Inq4embOktD99N237vzJX6zf8ABaqVof2WdAZXxnx/ag+4+w33\nFfkxpsnmqHRNwZ9qr/dr9Zv+C1sbSfssaAq4/wCSgWvBPX/Qb6vwzxF/5Lzhz/r5W/KkfM8RRn/r\nPky/v1P/AGw/NjSWmVYobZM7v738K7q3beNI5l852fb8ybkrB0tnj2DZsOz5VatNbpGaFJk3pu/i\nbb5dfplT+Y/Ueb7MiW+Wb7KybFUTP95vvNUE0LwoUQcbdy7v71Pa8ibcn7yRF+X5f4WqD5/OEafc\n2/eVvmrOXvR+IUfdHtdXMiwujqvlpt/76/2qsQxpDt87/WNt+8lQRwlrjeOn91v71XoY3mma5mRd\n/wB1F/iVf4ttZc3KbxjzSI4YYWVkhhZf3vzqv3qfHvm+R/MU1ZjX+BEXdCu35n2s1PhsXjjCPCy7\nvv8A97dTjLmkbRjyy5iKztRIy7IVUKrNuZvmatGzjnkkWFEVlkX7u/8AipY7F1kHzL8vzI2z5quW\nlr++BO0qvzbm/ib+7Ve4d1H3izC32eGJPOZNz/Pt/irT0+4SCNNj7tr7X3fMzVRaMw7XuUz+9bf9\nnTd8tWLeR4VR0Tbu+7/e21MYmkvg5WaMN5bN89y/DJ8zLTZvsyQ7FufnZvlZvu1BaxvIyuifIrfJ\n/dWrtra2118+xWLP/Fu+WtYxhze8ctSn9krx27yRi2h+f5tvzfKq0sNnGtxDNNcsjybvm2/K3y1c\nktf3LW3lxudm/d/d/wBmrVvZw3EzJDbbfLi+T+JdtEpWjynNUp9yj5bzW6+TCqS79zrJ97bUq2s3\nlo+/5vuoqr/49WgtokzMnnZ27dn+yv8AdpbuHzJt9mjB/uv/ABUe7HRHJUiYzaSjQo7vvZW3P/s1\nnalp/lzNvh3lf9uuomtXkZHG5B5v+rVPlqjqVunlv9l+SX7zN/D/ALtX7sdInFL+8clcaP50e9H8\nvzPl2/xVXutP8mUJCmVVPvf3q3ruFI4RqF18xj+bav8ADUDW6XEvz9Y/9VGz7Wb5afN7+pzVIy5T\nm7rTXZkeNI1+b5l3fN/vVWk0tfsaQu7F2l+75W5v++q6SO3S8jE0sO1VX/Ur8v8AwGmzQyM3lpbb\nmj+X5W/hro5vdikcvLzSvE5uO3mh+eFOW+VtqfK3+9Vu3tZliXeW+58n96tj7C8ex0T9633P7u3/\nAGqdp9rNbRo9rtYMzKzfwqtRLllqKjzR90g0uxSGGTe7RLGm2t7S4UVUhT955ifPtam6fDuTY6fM\n3+18yt/erU09fLtzDMn+15i/xVzSlyy5j0qNP3ibTWcr5yJt3P8Aeb7rLXR6JapJIqb41aRfl3bf\nl21QtlSO3hheHcipugXZWlp63jfvYYY0+6u6NNrLWMZc0+ZHpxjyw941bcTTt/rpAVfa8mz7tdHp\nMKWsgRBnb83mfxbv9payNPk3Rwp90s+5v9r/AGq3dPuIVmV3dTu+Vdvy7q9KgcNanaB0mmwzLE1y\nkO7cv/j1a2ntCLdoXmVyzruj/vVl6VcRrCYfJkRZG2o33l3LWpp7eXMizfO27d9z5Vr2sPE8urLl\nj8J0OhLbXVx++/dxMm5F2/3a3tKt7WFV8lGKL975/m21iaHbpG2xEba27ymauj0mOaNQnyvuT5Nr\nfNXqR908ytHlkdHoV/IyuiTbImVmTanzL/dro4ZXhXzZtqozqyMq7mZv4t1eb+NPil8KPgzpc2t/\nFf4iaL4agjXfFNrGqRwM3+7H95q8r0v/AIK7fsdeJPiJY/CL4P6x4p+IPiHVLhYLDTfCehs8dxI3\n91pNtKVTlhzGLrUIx1kfRPii4m8UXlylhqU00VndfZvLa12JHtX5l3fxV5x8Wteh0fTYLbzljl2f\nLDG/3v8AaZf4a9G+Huk+IbH4Z3t5rej3Vrqupa9cPeaPeN89jI21VhZv71fK/wC0/rniHwv4svtV\n+wMiLB5Uqs3zLJ/s1+eZlW+t158gqPuy9Sj4o+JWiWt8by6vJizfLFHs+bdXFav8cEvtLm0reuyO\nVfNb5fm/4FXiXiv4la94m1YfbIfKCysir96tbwRpr3mqW+m/ZmeS42xQQxxbmmk/hVV/vV5dGjy/\nxZWse3g6Uq3wnreh3CatpdzNrEyrbTIvlSSOzbV/3a8q8fX3h6z+022g6ws8cbbflZv3cn8StX6J\naF4i/wCCVv7EPgXS/Cf7Xt7F4t+IN5YR3U+iW0TNb6ezLuWFxE21W/vbq+fvi9+0/wDs4fFt59J8\nD/AvwX/YF1LttbfSLDyp41/vNJ95qwxVbC4WEaifM30R9JlOR47GOSrQ5IdJS6+h8GfEPUJpFP2a\nZfl+Z2ZP4a8017UPs9xvhOVb77K9fUnxm/ZrttQ8L6j4/wDgsl5qNlZo11q9iy7pbOP/AGf4mWvk\nzXLhWuGdE+WT5WVk27a9jK61LFx50fLZ9l9XLq/KObUIZojJv3Ky/dphtE8tXR8bW+Vagt5PtSeZ\nCittX72771Ot7y/kZrN0VIt25ZK9OpH3fdPnfi1kTWcbwli+75vu1bt9euFbyZtqx/dqhMrlj++3\nq3y7akhmtZt8Lwt+7/5aR/xVzSj9kuMpR90t3yzXVuj23yf39tVr3S4bqd4YbmSNfK3bY/71dD4b\nsxdRIj2e9Oqf7tWNQ8JQsqeT+7+826svaRhLlNPY1ZfCcTY2c0WDNM2/fWw+q+VIiI7fe2/8BqLV\nNHEK+ZBNu3fw/dqz4dt7OORLmaFZTsberVFSMakec6aNOdP3Tb8I3MSr9oeWb5X2q26vsr9j9fE8\nc0V34e8H6lOsiqjtJBtVW+78rNXzX8Or/UlkhTSvAzXQh+by/s+5W/3mavuD9lf4pfEjSNQtv7Y0\nrZZ+VtlVtq+XJ/Cu2vkczqOUXyxPtMllO3LzH0Fb/Gb4/eCdQg/4SH4M2M+n3ESwLqDTwtOsK/eZ\no6+gPgv4o+HXjqyk1h/D39m6qqw7fL/d/Nu+9Wj8Bvhj8P8A9o7wM+m+JdO0/VrpYP8AVvcbZYfl\n/h2/d215r8UPhzbfst+LILzTb/xR4esZLqOJZNYT+0LGTd935vvRqtcdPCyqU+eGx1VMVFV5UZ7n\n03DrNjpdlPba9FH5jfN5i7mqHRtc0VZClnNCibdzMzferJ8H6l4p8deD49Y0Xxd4P8Q2yuqtLZ3D\nI6/L824N95qni0ixWR/tXhq12SbfmjT+GitRjGcYSR6ODcKlKUep84f8FUvBMnxx+AGtWfhzWVhG\nh2a3qyRRbkuJI23ba/KKxt5riFNjssjRb/LkT+9/dr9zP2v/AIazeM/2cPFnh3wvpMkMh8NXDRpa\n7V8yTb8q1+K2l6Ltt4baZP30O6L5l2su37y19Vw/pTnHoeJmtSlKUORGBJp7tG29GTd83lslV4dP\n/wBIR4RIr7G+Wus1LS/Ph/cxtsX5pW37WrMXT3jkG+bDQv8A6zbu/wDHq96Hu+8zzJRiZlroqSKk\nPR+qyf3l/u1q2OkvuNsEVt21flTdtq1Zw3Mm8Q7lH3d396trS7FGmKQ2GGX7m773+9XqU+fk1POl\nLmmH9hpHMkcPmMY9rfMv/fS1rw+b5i20KbkZNzL/AHafY2Nz80MMLO8ybV8xv/Hqlt7FGZJvIbcq\n7NzfdWvQoxic9SX8pDar5UboiMjb2Xy2qwq3MykPNs/6Zqm7dTntfLLum3Z/v/NTWjmhRnfzGdd3\n3v4d1dcYxOWpz8pVlG2Mh3Vvn/4Dt/vV9qf8E3FjT4GaokONq+KpguD/ANOtrXxBfKjeVsj+RlX5\nV/vV9uf8E1X3/ArVSQcjxZOGz6i1tRX4x4/K3h7P/r5T/NnxHHbtkEl/eifFkd9NdMrgK/735137\nVq+88cln533VZvk3JWHDPMswRLZSmzfK38S1aluLaOxj86bZt3bF3V+1cvucp9hyxG31891IiI8f\nlsm75qgk1N7qZYZnaRtu1I1+7urKm1CZZDN93/nrGrbqu6XNMz/Pbbn/ALsf3v8AernlCZ6uFpnd\neE18uPegWbbt+XZuZa9V8F6VD5nnTbnDI2xWX5lavKvDbbmtkdPlVt/zf7Nek2fiZNFtftly8m5l\n3KsctFNxpnoyqJQtI9QtbrStJsY7aZI4pNu9I5Pl3Vz3iL4wQrdHSv7Qjtrf5mRt33v92vGvil+0\nBYeG9BuNV1XxDb2wjt2WL7U+5m/4DXzD4o/bGtrm/u/sFy13Js8pbqb5V/2tq10wjze+z5LNM5lz\ncmH+8+kfjF8Xf7akuvBnw9Rry7ji3Sts/wDQmrxXVvGXirT45s2DKVTdLIz7vm3V5JdftQa9ptnd\nWHhV2tpr7b9qulT941YmqfHS/t7MTaleZ3ff2/xV1RjyxPmJc9R80z1DUPHniRWdHhm2yfvXaT/P\n3awte+Inn2433LCVlZ9q/wB6vJdb/aCutYuD5L+Ui/L8v8VN034lW2rXG/UkXZ/GrfxUuachxpyO\njvvHiXEj2002/a27y/7u6sW81SGaR982z5/4XqlqkmlXkazWd5GnzbvLauZvLx4X8lNzMv8AF/eq\nxx92Ru3mtJ5hlf7395aoXGsPIr/O2/Zt3M38NZP2iZYmeYKaPMdWD53/AC7vLWq5R8yLFxqCKu9N\nv+7v+9UbMnyuhx/dWjy4fM2bNzfeRqSRk+1sjJn5fvL/ABU48oubm91mZeW7yKqfeLbq53XLWZZf\nlTad3yMtdcy+WS7vtb+HbWfqWmvMyIfvSf7f3aIvmEcxq2m22qR+dC6sY03Oq/3qw7i3uY2VJoWV\nq3NU0G802ZryzT7rbmX+9V3R7fSvE8fkv8lz/d/2qYHLxyTRsE2t/vVFNNPHMro+0r/tV2V58PfJ\nVpt7Jt/irEvfDbq+9Pm/2qOWYc3NI+8P+CMv7a1z4D8RyfATxtrMh0rXJfLspLiXdHHI38O1v71f\nSf7T3wV0HxNqlwn9mxhml+8q7f8AvmvyO8Hyar4V12117Td2+1uFlTa/zblr9I/2ff2mP+FweBbF\n9b3PeWsCpdL5u6Td/tbqXtOSHLI5cZTjPll9o8i8T/AW58K3VxbR2zPbyfxSfM3/ANjWj4A/ZXs/\niFJFZw2FxHLI2x90X/LT/Zr69+Ffh/wf4y1i3sNetrcRSS7mVvm+Wv0y/Y+/Y7/YgutBs9Yns4r7\nVGTf+/Xy1Vv9mub6nHn5ub3TCniK/NyxPyJ8K/8ABF34weJ7FPEPhvRJLtZIm8qOP5fu16Zp/wCw\nXrfwX8JwzeM9HuLGaFFZpGi+XzP7u77rV++Pgz4ZfDvwlpwsvCmhW0Nv28vndUPxH+C/w1+LHg+7\n8B+OfCVpe6bexbZYTEAV/wBpW/hassZluExlLkkevgcRjsPV5+ZH4z/CP4cp/Z8U1trEexnbZbtL\nu2tXvPwr+Dvh7T7g6lrEPm/JuVf71dJ8Vv8Agmhrf7M3i9vEvwiS61nw1dS7/LuHaSWz+b7rf3v9\n6reiQutiIbz908aN959vlrX5FnWU4nLMZyPWMtpH7Jwt9WzWj7Ry96PQp698ZLn4c+KrCz0F1Q7V\nd1WX5vL+78tfSnxETQf20P2H/HnwvQqZtV8JXVv5MvzNDN5LNHu/4Eq18BaTrb/F7x5f6l4euftN\npDdfZ4vL+6vlttb/AMer9B/2SPAlz8L/AIP6vrfiSGO1tk06SRm3f8s1jZmZt1fX8MUatFKx5HGf\n1WVNp/EfzS6LNNa2P2a8dvtNvLJFKq/89I2aNl/76WtzTbh1nSSZ9pkT+L7q1haTrlhq2ra3qWm3\n6zQ3HiO+uLP5PvRyXEjVrQ280+93vG8pfmRf4a+mlHlqyPk6UuahFm/Y6xujdJHaM/8ALJtvytWl\nDdFoSkxZjs3VyscjxrmZPkj+5Iv8K1ow6lMJo96bkkXb97+H+Guuj/KefWibsN1bNIX8ltzRf8tF\n/iWrVjqj2N0juNm59rsy1grqG1d81ysK/dWPZUNvrSNG87uz/wAKNXdH3YnLLkO6t9a8m7Lvcr9/\nau35q2NH8RfY5BC91JIsjMqMqfd/3q83tdeeOTLyRq0abv725v7q1b/4SZ7NYn+0yBVT/j3/ALrN\n/FV/Z5omcf7x7Bp/i6GHy4UuVRW+bayfLWnZ+IEsoZYU+ZG3Nt/ur/drxrT/ABlFJJ9peZU3J8+5\n62bPxteSRu6OsbzN+9X/AJ6Uf4i+c+/f2Jry3vvhTfXFs0RQ69JgRdv9Hg4PvXz3pvjC2Zok37g3\nzPtr2j/gnPqo1f4H6lcgAbfFEykKMAH7NbH+tfHtn4z2bfs80m5fmdV/9lr8P8NJ8viRxU/+ntD8\nqp8tk3/I4x3+KP8A7ce/WHii2hkSZL9gflVVb+61dFY68kkcmx1V/wCH+GvCdH8aJINkdzGV+797\n5lauo0nxRusxvdmZn+6z/dr9w9p9k+l5ZnsNr4khZktrmbndu/vV3PwM1Zr/AMTXMSSZQWUhx7iR\nP8a8E0nXvJkS8+0r9/5/n3bq9b/Zm1ibUvHlysrlgdIlYEKAv+uiz0+tfnni1Uv4cZmv+nT/ADR4\n+ewf9j1m+xq/FXWPsfjXUILdmSULH84Gf+WSVzl1rUPkrCm75V+Zt33aZ8bdbNr8VNWtC64Agxn+\nE+RGa42TXoY8fOzN95fl3fNXq8BVb8CZUv8AqGof+moHZk8LZVQf9yP/AKSjbvNWe3keZIcpI/zL\nWXea0nmMj7pE+6+3+Gs6bV38wol4oZmZpWb/AJZ1l3mo3kafaRtLN822RvvLX1Eqh6Xsx+vXhkUv\nI+/Y3zqtcpq1xYMpuUj3Nu+8tW9c1bbGXWZU+fa21flZv7q1zepam/2AO7syxy7Pm+Xarf8AoVZy\nqF+zYlxePHM9zC6ny33bf4d3+zW1puuJaNv2bGZl2x793/fVcPJfXJuoraGTCyKzJ5nyoyrVu31/\nY6ec8aO3y+ZWcZR+0Llmenw+IEuLUp9sX7u5/k3K1Q6prUfyP9pjQrt83/Zri7fWoJIUSGbayp8r\nLVK/8SOsavK+5m+X5vmaqjIz5DptS8WQxXm9Lna8bqu7Z83l/wB1WrI1rXElZJrZ9qfddZGrlNQ8\nUP5jf6zP92P+JqwbzxF5jM80zKGX7qvWUveKjym9eeJE8yZ0blfl3K9SaL40mjkS5SZVVty7f722\nuA1DWE+aGG5wjNudfu7qh0vWkkuhNI7J/c3Vxyqcp1Rpw5Lo+gPC/wAQ7Z/9Tf7W+98z/LV+bxNM\ny7PtPm/wosj1454T1rEaI7qT825t9dbZ6gjWvyTecv8AH5fy7v8AdrLmkuXlH9X5Y8zPlKPT/L/f\nJCyvI/yNIm2nnTXkbzk/1jfL8z/erduNNkkkk+RX/wCBfdpy2e5tmzcf4vk+7XzPtuU++9jzGdDp\nPkwyIj/dT7v3W3f71V5LVJ1Z3h2ed96uhjsZrj5JHb5vm/2mrP1LT42cHftP3X21VOp7vvG31fmS\nsczMvlsRD5iLI3zt/eao/Lm2yzu8m3+DzH+7WrqlqrIP97cys38VY+rXEPmcuwf5dir8y/N/FXXT\nrc0AlheWPulHVm863JDrtX5tq/erAurzbcM+9huTclaesSPb2pM27K/eZW+9WHeTI2PJdSuz569H\nC22PMxVGch0c3lRqjfMd+779W7PUpo1EP3Vj+ZFZN1c9JM/mecnyN/3zuqaO48ll2oy/xMzPurvl\nE8qUeQ3JLzzs/vsbqqS6ggX9y+7+H71U5LhJpY/32za3+6y0y42LGscyL9/du3feaolLlMKlOfL7\nwTN9okaGZ8NJ8v8Au1l3zbvufw/d3VZurp42/fIz7v8AYqtJH9o+eGFXVvm+9VSl1OWVP3jOmtXb\nan7zDfw/7VJa6Tcsxi8lVb+NWrds9LSR085Ny7vl3Vct9DEjK++NW/hVWrOVTl+0KnGMp6mPZaX5\ncKo6bGZ/kq8vh2Yt+5f7yV0Wm6CnlpDcpt/2f4ttbEXh142Gzbsb5fu1zSxHKevh6PwyOHXQblYV\nE0G75tyyfxLUlrpe7aiBsbtz7fvNXZ3Wg/Y1MN0m/wCX5Gjquuiwv86P8rJuXdWHtObc9WnGPOc5\nY2csSnnH8KMvzV+sn/BaJGf9mDw7tJGPiFaZAbGf9BvuK/L5dFtlt1hR2PzKyR7dtfqN/wAFmRE3\n7MGgCZMr/wAJ9a59v9Cvua/FvEKpzcdcOS/6eVvypHx/E/8AyVeT/wCOp+UD8y4GjkVJvMk8pfuN\n/FU66g7SbHfG7a3zJUHlw28zjzm8pn+Td95V20fvljZHff8ALt/4FX6hy/zH6NKpFbFprib7Q6On\nDJ8+1/vNT445mCon3l+Z2ZvlrP8AMeGQb5v4Puqn3qspHDdR+dM6ouxd+5/vVlKP2gjU5vdL0MQW\n4D/bI4V/g/3q0NiNCmyZVdn2y7fvVQtYRLb+d5y7d3y7f4aurs+bZPvVf4qmVQ6qZbhhtlt/v+Y2\n/d+8qzaxtIvEbJIrfeZ9yqtVY5kuJNkw3Mvyo396rkapGnlpMrSf9NP9mlGRvHmlL3S5Y3SXEe+O\nNR5bbv3n3mq6WSWTyX2szJv2qn3azYN90v2ncrKvystXG+WPzlhYR7d23+Jq0jH3uY66cuX3i3C0\n6wy+Y6w7l3N/dap47j5RN8zH7jr/AHaq2pe6h/diP94v/AdtWodP3xj5NrNuVWX+Ktacfd943l73\nvIsW+9bcTTPJu3N93+7V60j/ANB8x7ndt++33d1R6bau1uj/AC7vutD/AHWq3Z+bCp86ZdjPuePb\nW9OjGXunNKpyyEjjMli1y/y7k3bVfc27dWjpq/uVe2m8v5/n8v7v+1UUa2d0G37gF+X5m+9TvtCW\nrCFHXCy/3PvUq1GXSJhKvTlG8pFyOGH7OU+Z/k/h+8tRtMn2iO5RG3t83yt8u7/apY7iFv3Kcuv8\nLfLVe6neCRoXk+ST7jb/ALtc/sJxkpHLKrCUdJErNDu+d95ZfmVvlWqd1bvJG8zrtj27q044XaHf\ns37f4vvVVm2NZuH27VXa6yP/AA1XJOJ5tarCMveMe6VJFUNtV9nzrH91lrOmt/OjR0to98br8395\na2prPbtffG25tu2NKZJYw3Ehkhmj37lRo1+8tFpxOfnhIx4YfO8tII5E3fwyPt+b/wCJqWGz2s/3\nQ2z7395q0Li1Edz9mjT5WTcs0iVcsbd/v3Pkonm/PHt+9/u10OU5fZMfcjPlOe/s+5hhS6trhWdm\n+dd/3W/2qktdJ89fs03ybl2/u/u/8Baujh0lHjdLYc72b5v7tWo9HtpIm+zbiip93+7WUpz5TWnS\nXN7xlabZpHDsELF2+V2ZfmWteG1cqMwtu2bYpPl+X/gNWbW18mNET5nb5V3L96rEeh+X8zorvG7K\n+35ttc3JOoejTdGn1IobV/s4huZmKrL93fWmttdXW1N7RhflRmX5lan2djuhVJkjVtm5Fb7zVYkj\nezt0R7mM7m37VanTw9aVXl5TeWLw1OHvVIk0dukMaJvVH8r/AFi/e/3a1dL+aMQv5iN97d/FWcti\n90qiZ1QN9yRv71a9tNZ2Vu9zc6rC32e33s3m/e/2a9zD4WvH7J5WIzjLI6Odzf0WJ47pYXuWfcq/\nu/4m/wBquk0eWHTVFhczcqnyRyNuauGh1DWFVNVvNaj0jT5F3JNMv72T/dX+Gta48TWej2ct5ptm\n0crRbXvGTfLNXsQw9TqfK4ziGnrGjE62++JnhjwXp8mvaq83lR/LKsibVX/gTfdr4I/bI/4Lc/Ef\nTJ9T+Fv7L01lptus/lz+JEhWWbb/ABLCzL8v+9Xn3/BSv9tvXrm/f4G/D7UmjVV3a5qEbfNI3/PF\nf92vhxju5xXTGjfU8aWMxNT3pSN7x18R/HnxS8RyeJ/iL4w1LXNRmbMt5qV00rn/AL6r9mP+DUX9\nlHSv+Eo8V/tmeM9Ijf8A4R+L+yfCrSQf8vUy/vZlb/ZXatfjh8Kvhn4w+KXjC08F+CNAutS1K8lV\nLa2tY/m3N91q/rM/Yd/ZV039jv8AYv8AA/7P2iWcdtfafokd5rd1/wA/GoTR+ZNu/wB1vl/4DXz3\nE+O+p4Pkh8Uj0MmwrxeL97ZGh8TNF8MWOtX9zqsO2a+l89o1b5mb+83+1Xxf+1p8DbzXmvtV052a\n3hvdy+dt3TRyfxNur6Q+NnjzWNLmmm8T6PDA7f6+OPc0cy/d+9Xz/wCMvj14P0G+W58ValC0MkW+\n4jm+Zljj+7tr80o4idOPMfSfV4VKvKfLc37KOj6TeDXprCTezNLdLI7bF3fdb/7Guy+CHg/wv8F/\nCfif9pPxVZrNN4LtZG0GO4t12NfSKywfK39371Yvxc/aos9Y8QXNhpTxvaRxbopI33Mq7vlrx79p\nf42axqn7Iuj+E31GZptc8XzXF0rfwrDHtVW2/wC992ic8TiXHn+0fb8P5dh6deMnrynz5f8AiLxt\n+0T8TtQ8R63fyXl3fXUk+pXTLub/AHd1ZOrS+IvhzM02lXU0YjbaskbsrK392vX/AIA+E/8AhBfh\nqHa2hl1XXHZ/MjPzLGv8NY/x88e+DPD+lDRIdEs59QmbdKq/M0K/3mrt9pT9tGjCPNE9bNcfVhB1\nGy5+z/8Ath6xDqcel6rO1tPDEyvIq/LdRt96Nq4T9orwz4e/4SaPXvD9tGsF6/yLDLuWPd8zV5sn\niKWfX1vba0jgRW/5Z1q+JvEFzqGmxw+dmFfm2/3a6o4OphcXGdH3YveJ+e5lmP12m1U1J28Jpo8O\nx4VZpE3fN/CtUbnT0+0NZp/c3Iv8VGm61/amll/t7I9qnyLI+7zP9mtLRbxLi1W8dN5+6277ytXq\nxqVftnzUqEeaPKZlv4dv5mE1snybf4qvReH7y3uGd4co23ft+7XXaLqVgtn/AKMitLs3N8lbOnww\n3EcU14io7Ju8uP8AhrjniP3kjuw+D5pxMrwnpU1nGPOh+ST7nyfw1r3Wn20Ni0OyNRM+5dy/Mv8A\neq6rJHcLDbPz919tS3Sw3Wm/O+3bL8/lv/FXk1ZT5+ZSPf8AYwow5kcPeeH/ALRdtDDCzQ79u6tT\nRvB+m6RajUnRWK/djb5mqz5yWszwzJGPM/1XzfeqrqEl5Gqo/wAoZtqbf4q6pYqVOHKup5VSMee5\np2/iDxVNM7w69JYWayq3kwrtWRv4a6bw38bvFvhO1mtk8S3Vw8jbt0kv3WX+7XOaDbiSzEOpQ/uF\nTe3y/drUHxm/Z2+HFilt47jjldb1WihWLzJJI/4q8+FP29XkjDm9C6dWph/f5+U6rQ/23fi74Bkh\n8Q+Evi1caVqG/dtsbpkZmVvlaT+Gvvr9ln/gtrqnjzwXP8Hv2oPD+l+Mbe6s/n1A7Ypz/wAB+7X5\nIfFz4q/sz/EfZP8ADd7q0ljlb921vs+Vv/ia4mO48W6Nfx6r4b8QSBoX3RFf4v7tet/ZbhCy9yX9\n4y/tOtKd6nvo/o5+CH7SX7H1rd3Fh4Xs73SLy8dWsbdk/cbdv3dy/LXX6X8WFtfGVppuzzbPUN3l\nXC/dX5vu1+D37In7S3x1uvE9tpWo69G0Sy738xd3lx/xbVr9Wf2RPiVZ/Eq1h1LxDqqqNNi/0Vt7\nbpJG/wBmvBxmAlRxC5pe8foGS4uhXw8n37nvf/BSr9qbwf8Asr/s1TXmpajGdS8U/wDEu0aORvkk\nkb+Jv92vyDvpL2TUjdybUeSXc3k7lWvdv+Ct/wAbvD37Tn7UXh/4O6FdzXPhT4X6csl/eQ/6qbVJ\nPmaNW/i2/drwFrp2kab7rfMybW3bq+ryvC+zpX7ny1epH29uxY3Q3DB0dnZv4lb5qoyQr5zJG+0r\nLuaNqWGZ41R5nbc3zeX/AHalkaG6h+4of7rfxbf91q9KMYSny3OaUuvKW7eztpI1eZGjRvuLH81b\nul2szXmxEbYqfM0n3lX+9WPptv5cbfvl+Vfl+b73+9XVaWsN5IYSjB1i+Zmrtp/3TmmTRx3MYHkx\nyMn3Xk3/ADL/AHatfYXhhZHh+eN/m8yptNsbmNk3vGiqjfKv/LSr0Nmn2VkRGlMb/d3+ZXp0/gOZ\nx5jGkWG3j8l5N/z/ACtJVXUN/nSv92T+7v8A4a0pF3SNC9zuZYmV1Xb96s3V23Fnm2tHtVd2/wC7\nXZGJhL3vdkZV0r+Yru8YRU+dV/havtT/AIJsY/4UXqu2ZXH/AAlc/K9B/otrxXxpfTIyuk275k3L\nuT7tfZf/AATZiaP4GaqWdCX8WTsShz/y7WvX3r8a8fYx/wCIc1Gv+flP82fC8eO2Qyj/AHonwy0j\nw7CiMf4W3PVKa8mkUn5iq/wt93/gNWNUvIbVt+/zEVN3lx/KzVzGqX0Ma+WiMVjl+Vt/zLX7t7Pm\n94+v9ty7FmS8mkuH8mbYrP8AIzVf0m4SFvLubnczfNKytXHQ3j7xDJNllT/vqtKx1hFuESGb52ba\nlc9SnzanTGt7nxHqXh/XILezSNHYq3yo1cX8VPj5beEdPfTU23Ey/N+8fbt/2q5j4kfE6z8I2bIl\ny0s3/LusP3a+Z/iV8RL++unm1K5Zpm/vPURo83Q8rMs25o+xpf8Abxb+K3xY1XxJfSfadSaRpm+8\nz/w1xVvfPb273LzL/e21gzal/aF47zzMTv3Kq07UL5I7byfO2f7O6umNOETwbGjJ4gfzHeR22/x7\nXrD1fXNS1K4GybdFH8vy1B9ohlh+cfe+7UMbJEr/AD8bqr+6VzFv7X9nh3um1f8A0Kmt4kez3JC+\nxdn+9/wGs3VNWh2/fUbfl/3axbi+eZd/zMWo5oj5TtdP8XTSSeS7sw2/xferetbxNSh853UfJ8nz\n/M1eXWtw+9X+8P8Ae+9XUeE9Y3SBJn4+6u7+H/ZqIy7GX+I61IRN/pKhm3Pt2tTlt9qt97d/v1Nb\nLIzI/wDA38P92rM1r5MghRG/vK1aE/D7xVWIxx79jL5n8VOuo9zb3Rm+X71XxZvtXd/u/epjWe6R\nt0LbV/hqoxjKIvtFC2t3kXfsUFv4mqxJpThd7oo2vuq/pdiGbf8AeXduZdldTDocM1qv+gK38Xy1\nnEqUjz2bS0kj8uZ1Vv465fWPDf2eQahpX7mZf7r16T4g0VLNnjTarr/DXnmoas7a9/Y9y+xV+b/e\nqveDm5ty94b1TVb6x+walbLu37Xmb+Kl1LR/J+f+Bf4v71aVvHZrGqI7f3dq/wDoVTXkaTZ/iqog\nYVrCm75E/u/wV2Xw4+JF/wDDPxDbaxbTyfY5pVivbdX27V/vVy62aMxTfzUjW7yWps5nU/J/F/6F\nUR96ZnUp80D9I/gr480270u28Q6VqSujKrRM33q+1f2a/wBoKa3a0tvt/km1RflZ9u5q/H/9iP4z\nJHeP8OtV1L99H8kHnP8Au9tfbvw/1rVfDN9Fcx3LFG2navy1tUp+57h4spSjV5Wfq34G/bD8U/Dq\n4hlngk1DR7p1aXc+5oWb73/Aa+kvhj+0v8OPiRaj7FrMMM//ADyaSvzJ+EPj5/Fmn/Y7m5/0dk2y\nx/xf7tYfiDxn4z+BPxIFz4evJjZTXHmou/b96uSUuXU7KOIlS0P01/bP+LOufCX4GzfEPwnq8Md1\nZ6lahYZArLdK0m1o2X/ar86/i9+0dN8dPEmveGPgtptjm8umtb+8t5f3VnuXbIzN/wB9bVWtH4+f\nHfx/+01D4S/Zv+GPirVl8YXV02pX7abcRyLb2vl+WqtH/wA9Nu7bXy3+3B+2b4U/4IzeHrP4LaF8\nONP134galE1zZ6Pqm5vs+5v+Pq52/N8zfdWvLx+W/wBouPP8MT6/Ic8llkpzjvKJ+g/7DP7OPwr+\nGHgCXxJ8QtbhsNG0dd15rF9KsUTSfxbmauK/4KXf8FavD3hv9l74meH/AIFvDbaTbfD6+t4NcmXb\nPNdSL5MXkR/3W3N9771flV+wV+2B+1t/wUY/aYRP2k/i1dXulxhWsPC9nF9n0qz3SbflgX/WN/tN\nur3T/g5b/Z61L9mDwz8FLbStXnk0HxVe3n/CQRom2Oa8jjjaBW/2VVm+Wu/C4P2PuxODMswxGNq8\n0j80fh34gm8N6TaaVNMwVUXf/vfxV7D4N8VQ6xCbN9of+8v8VeHXXzPvttzM3zbq2PDPiq5s5Ehd\n2Tan3lf7taVsPzx/vEYfFyocsZfCe6/aNuxE3Mjfeb7vy1FcXX2VgiP8v8Ua/e/2a5DR/HlhIsWm\nalcr58aM1rIsvysrfw1tXV9tjHzr8qbnbfurKn7p6MqlKtHmjsXF1KZZt80zLtl+9u/8dp9xrXys\n8Lr8vy/3flrmdS1BJZkn+1Mm1N27+9WZN4k+b9y/8X72uuNQ8+UeY6uPXry1kZMr977392pV8QNM\nyTTTK3z/ACrv+WuKXXIVmMPnN+8XajN96o5PEH75XSFSkafxPtolUj8REY8p30fiSe1hP2l42Tfu\n/eVeXxs8Kq4WMiRPuq/ytXmDeJJpNvzsqUyPxI9uoTzl3q/3d9R7Y05Zn6yf8Em9TGrfs56zcCQt\nt8aXC89v9Dszj9a+B9H8beTdNM9y2yRlby9/ytX2z/wRY1Qav+y3r92Ccf8ACwLpcHt/oNjX5q2/\niq5mkVIbmMIr/N8vzfdr8O8OKnL4i8UP/p5Q/KqfNZHCTznHpd4/+3Hueh+MrCZk+TfEzfeZv9XX\nd+H/ABqlxH/obsis6q67fvf7tfPHh/WvL2PP5bsybkZf/ia9C8O+KHjaPfMyL99I1f7rV+zSxHNr\nE+tjRme42fiC8mkiSGbb83yQyfe2/wATV7f+xTqw1H4qakhJBTQpsAjG79/Bk/59a+UNH8RXM377\n7Ssj/e+b5dtfRX/BPjXm1j4x6gsu3ePC0zNsbIP+k23P61+f+Kle/h3mUf8Ap2/zR5XENCX9h15f\n3TQ/aW1qWz+OOuwWrZZDa71/7dYq4CTxNDHu2Px9123/ADbq0P2xfEq6f+0T4isFaNWK2nzP/wBe\nkJry7/hMPORoYbDadnzNXqcC17cD5Wv+oah/6aideS0JPKsO/wDp3D/0lHeTeKpoZkR7nO5N27+9\nVebxTNKodHUp8y7v9quEt/Ek0nlzXMaxHdudo/m+WrH9sTBm8mZkG/dt2/LX0csV757n1Xm942tU\n1aPbMjwsf4tq/wB7/ZrB1K4eRpnZ5F8ld3lr8zVFc6vczbZjtIb50b+FaytSvHkYv9sYfN80K/wr\n/eqPrEpbFyw8YwJLq6hWSF0/ii/1jN935qyZPEG5nTf937zN/FS6ldeZG+/ciM3yfxfLtrBvj5it\nNs8zavzbm2s1bU6hy1MPH4jqI/ElnHsmmf5tmzzP937tQyeKkvpmRJlO5G+ZWrhm15FkT5Nqxy7t\nqt/s/wB6q3/CSOq703A/xNvrU5+Q6q+8RQyRrDC+9vu/L/drHu9YhH+jIi+X5X977tc/Jr/mQtNZ\n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\nffnc+3btqexscqtsifJ95GZN1c1bY6KdHlnyl21uiu1Hh3bfvxtu3bt1dRo95Csezflty/vJHrlr\nWF41Kedh/l3bn+7/AMCrY064f5LZ33sqfumb7v8As15sj0Y05RV2dbcQ7XFz5K71fcm5apXdz+8V\n327/AOJdldDeae6xl5o1dv4dqfdWsjUtOhWP7ZM6om372z+Kvj/tH6RRpycfdOauP31uru8ZK/xN\n8q1z2rfvJWmR8Kr7pV8r5m/3Wrqtajs1bZDDkN822T+KsTVI7maPe6NuVNywq3y10U/dPZwuF5jj\n76/CjYk2Xj+ZFWKse+3szbNqs3+3XQatZ/u3SHcm5Pnbd92svUI4ZFZLlIyyqqtIv3q2p1PZ+6fQ\nYfL+b4jltStZmmV0dWeP7i1l6lA+4QzOqMy/d/irptRWzhX7T5rbN+5I1Tcq1g30cGfJ8lmdm/1m\nz7td1GtzCxWWx5TFmsXWMpvVXV9qbqiht5pG+zOm5ldfm2VfkCQjZv8Alj+b+826n2tiI1OyNsr/\nABN/FXrU63LD3j4TNsv5eYfp9nut1+T5t/8Aq99a1vo9xcRjyRu2/L5cn8VR6fboscXnJuf7396t\ny3XzZE37QWRl+X+7/eo9pLm0PjMRR9nAq2eltJsdIdqRuy7f4lrY02zn8iTa6j51+XZVi3t3ZTC/\nzRL83mL/ABLWnpq+dhIXZ4VXc7eVtrH+9I8mty9QsdNhmkWF3Xztv+7urd0/S3mh+SGRH2bW3fwt\nS2unQzLHNDYec8e3/Wbd3+0tdD4dsYVkUiFl3bt25Pu1PtJfEc9OPtJe8VYdPMkkaeSpZfvN92tB\nrVIoG32ap8+7du+9/srWlb2aW6uiQRyNJ8sXmPUk1mjN8+13Vm2/L8q1yyqe9zHfRpxjqjnG02ZS\nNm1ZP+WrbvmX+78tL9l/dmwmjV5Nu75f4V/iram0m5mVZkTcfK/v7W+9SR6S6zY8jYqurM33lVf9\nqolL2kbSOmj2MD7H9nZLmHps+ZVr72/4KxQmb9nLR1EQfHjO3OCcY/0S75r4ijtUZndJlWNnb5V+\nbd/tV9z/APBUqNZv2ftHhaQLu8Y24GTjJ+yXfft9a/HePH/xnXD3/Xyr+VM+R4mvLiXKLfz1P/bD\n83bzTXlaS8mfIZtvzfd+X/ZrOmsfmX7NtKL/ALFdndaK/wBoVEEe7+JWf5Vqh/ZdmsLQ+TudpWVZ\n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\nInzM1W21WwsbO4vLn5fLt9qKvyq3/Aq8w0vSX1bWLnVYXjXazN8vyrJX1+Q4Hm/fSPheKc0i/wDZ\nIfM7b9pXw74G+N/w1vNK0rQY4tRtZd1vNJa7XZlX+8tfHfw5vLybw7qvwK8To1tex7p9IaSL958v\n8NfW+i+JrbQ9WiS5jmeVtu6ORvu15l+118M3+1Wnxj8DWarqOmy+fcLCvyzKv3t1fUfFSPhIynFH\nj/wz1a28UaXceA9S+ZpFZbeRk+bzF/vVx/ijRb/wrrk0PQx/I25vu1f8SahbaH4oi8Z6I/7u6VX2\nx/Ltb+Ja2/iFqlh46t7fxClgsRVF3f7TVnGXKXGPL8JyEfktZrv+Xb83zNurlPEVxC6vC/zVv6he\nJCXtvm3f3v4a43XriG4kfzudtUXGJi30O5ZE3/LVPzPl/d7WFXLry1Yon9/+/VGNf3jQIm3+9VfE\naxEaHd8+/wCX7zK1Q3C/3z/3yKvTW7rGE+Zw38NVLpf+mfzLUlFCTezvsP3ajkbc1S3R3NsCc1B8\n4Ul/4aBx3DMm3p8rVKqzbtny/dqEtkLn1qRJPm96BDmZV+QBc7fvVF5zt8mKbIu1qWNfmGXoHysX\n7w+SmDeuAHxuqYbIz89FspmnRMc/+y0RCO5YaX7PZ70++3ypt/u0trlvn2VBdMjXB2fN/dqS3j8x\nv9dtZv7tHxEyOq8Mr5brNDtU16t4XuL+a3/1yqipXlPh9fsixzTOrbf/AB6u6s/E0zWaWdlbbP8A\ngdae7GJhKPMVfi1qW6xKTTK7L9ytz9gf4W3Pxk/aM8K+CbZP32reI7WCJW+Zf9Yvy15f8RNTmkvN\nk024/wAK19rf8G/XgP8A4S7/AIKAfD55oVMVrqn2h2/3V3VphY/vEY4uXs8Mz+sj4WeFbDwP4E0j\nwhplv5UGmadDbRqv+yqrX4Sf8HqVjMPih8ANV2KYvsGqQfe2nc0kdfvbpF5i1V33D5f4q/FP/g8x\n+Hk/ib9n34WfFy2i3R+GvFc1reSKu4Itwvy5b/gNY14Tlzm+CrUqcYIw/wDgl348ttM+COkPDM26\nG1j/AHKy/e+X71fT3jL9qq6ure4s3RbhI7fZ5Myfd3V+Zv8AwTl+Lj6f8EdLtdiuY4tr3S/L8v8A\ndr13W/jVNdXDJc3LLFv2ttX5mWvxLF04xxs4n7Xgqt8PCoe/ahr3wi8QWtz9vtmiuWib5VRWS3+b\n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\n9N1C28GfErVo9S06+02JVRbiT7y/N8v3vvV+qXirxXbXnhOx+K2iSKj6d804+9+7b+Fq9PHUlOpG\nrH7R5GEqyjTlSn9iX/kuzP5Qv+C1n/BOfXP2A/23vE3w1ttOZPDmsyNqvg+4VfkktZG3eXu/vRt8\ntfGv2e50+TZMm5vu/d+7X9Wf/BfT9hDwp/wUR/Ybv/iz8PbeK58ZfD+yk1TSGgX95NCq7poP++dz\nV/Lfq1r5LPDfw8M23d/ErVzV4qpFVV1+L1PQwdd0p+ylt9nzR13wrmfUrV9N+953y1z3izRZoby6\ns5k+aN90W771a/wniSx1NEj4j3Ku6ui+Lnh/+z76LW9N2sky7ZV/hrk5uY7ZcvOeR+GdUm8N+IIk\ndvkZv71fUPw71i11nRdn2zLNF91fu180+MtBSzkF/Cm0bNyf3a9I/Z78aIzCwuXjH8KM1RKMoy5i\nuWNQ9Q1SxRVd97KP738Ve7/sz+Mv+Eg0v+x7y5b7Xa/Kir95q8W1S3SVH/iT+Jo60PhF4u/4Qvxl\nb38160NtHL+9/wCudRiKftKWprg60qFWNj7EtdNmt137VVN/97/x5quQ2O7ykvbmFlk/ij+VttX/\nAA2tnqmlw3lo/mJdIrq3+9V+axf7U/nQx/KrbGb+GvGj9qJ9pDljCMjGaxDTTXKczN8qbX/9lpbf\nS5mk/fWyu0nzPt+Xy/7tbdhb3KyJvtv3Tf61vl3M3+zU8en+X5v2Z9rLu3Mybl/3q6qceUqUYS95\nH0h+wxAbf4R38ZQqf+EglJUnJB+z29fIN5oNwjM6JtdX3O0afdr7J/YyhWL4YX7KuBJr8rAjoQYI\nOR7V8r3FmizLM6MTG3ybXr8Z8OU34h8UNf8APyj+VU+L4bgp8RZpfbmh/wC3nDa9o8Nu2y2H3vm2\n1yOrWdtNcP5zqpX+7Xo3iKPy1dLb7q/P/u7q4PXF/guUj3790qr95q/XcRE/QcLTcZabGVMuza6J\n8y/L/s7a+jP+CZHnf8L/ANYE0W1h4QuARtxx9qtMV85ySbbfZZuyxq33pG+Za+h/+CXsjS/HvWSz\n7iPCEw3Z6n7Va5r8t8ToyXAuP/69v80cHGMZLhXFv+4/zRzP7dl1IP2qfFcSkfK1iEAbksbC3ryS\n3vHVZZnm+825PLb5l2/3q9L/AG/LlIf2s/FZCZ+awBHv9gt8NXksdxZxr5c0yp8zN8v3qjhRW4Oy\n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\nS+L4jDlG+Y/ll361JCvmIvdv7tJHC8iZ+9/srWrpWjvcMNkLZq/iHIhsdO3Irl2bdW1p+ks0m9E3\nLtrc0Xwe6w+c8G5f9qtVtNTTVbzEXP8AdrXl5Y8pj8UuY5y4s3tVLhG3NWbOu6TeB92tfWrpGVnh\nbDKn3awJpZpJGfeu2spSKjHmIbiaRmGxGb/aals1dWZHT/aZqRpP3a7wxanQ27sdjvvXZuo+Ef2D\nT09ftLKm9VVf7yVsNp8zWu+H5i336xdPuNs+zy/k/jauks5LYQ7N+0NVcxMtjM+xzQsPMTa6t/31\nWnpLOtyPu/K/zrS3SQ8eTz8+1/n+7TY5Idy+T8prOPvByx6noul6Ho+raemybaVTb8teP/GDT30f\nxMLZ3Zfl/wB6u50e4eO2ZLN2Vl3K/wA+5WrhfjJNcTX1tNO6lvK2s1IcY++Zfhi58y62TP8Ax7q9\n48EzbvD4j8xWC7flr500G7eG6D/Ka91+G139q8OzP8w8lNzsv3qv4Qlz7GP8WtQdtLebqjbv+AtX\nicm+SYu235q9M+MmpbbYW3n8Nu+X+9XmKcMKZdOPLG50Xg9Q1xGm/Zu+81fQ3wzkeTR1hhTPyfNt\nr5/8HxvJNG6fd3/xV9DfDe3hj099o+Tyvl/2qOb7JjL4x/jC8hkjPySAxrs2t/FXh3xC8MvcNLqV\ntbNlWr2PxNHc6hMz3KSD59u5qyW8KvfL9mezZ/4lk2U48hl73PzFj9nHXJNQ8Oy6U94vmW+1ljb+\n7XdalYbo3uUfJ/iVU+7Xk/gWN/APxOht5nYQ3j7fMb7qtXs7XLhdm/8Aj2/N/EtT8PumkuWXvHE6\nhBNDcOjvvRk+X/Zr1b9kP9pTxh+zP8TLDx54buZIfs9wrXEMb/6yPd8y15xr1ikNzI6bZEkZmf8A\n6Z/7NVrVfLuBJvw33drf3aenJymHvn9KPjT4ffC3/gsv+whpXiLwzqwi8TaZa/atB1VWXzIbtV+6\n237u5l21k/sy/tXeNtK/Zz174b/GnQb5/FXhu1m0PxHpcNr+8VlXbFcbf9pa/Mf/AIIH/wDBTC5/\nZL/aJi+AnxJ1jZ4Q8ST7YJppf+POZv8A2Wv2/wD2hPgH4Z8S3kf7QPw/vFtLqWCP+3JLOHf/AGlY\nt947f4m2/dau/AV4zthqz93oebjaFWCeIpfF9r07nj3/AAT6+M9h4p8QXnw38QXRNtrunGH7K7bl\nZtrL/F/s1/Mx+1F8O9E0X9oz4n+DNHRWttB8f6pa2rR/d8tbhtqrX78ePYdU/Y2+OFl8Wr63Ww0G\naK8vfDrTP+8S1WFtu7/ar+enXvGV54k+MnifxDqVy0jeINcvLyVmTb80kzN/7NVY2MsPUf8ALIrL\n6kK1OPN8UbnLeDVudF1ZVmTdCsvz/wALba9Z8SaTba94JuHSFi7IrRMvzV5+1mlvqT+cjMG/4E1e\nmeD7h7zR4tMd12Mm3a38NcEfiPRqS908VmtodW06awuUZXj3LuauY8GapL4T8VGGZ8bZfl3V3HjD\nT30HxhP8i+XcPtRV/u/3a4X4gaV9g1BdXtk+Tf8AO392iXve6aUZS5uY+nfDt6niDw9HeO+Fbb8q\n/wDoVVNQheO4kmh/hX+H+7XD/AXxg+oaWtg82/8A2Wbb8td9rET2q7ETe237yvUc3u2CpHllzH1l\n+xv8Un8ZeCW8PXlzun019nl/eZo9vy17D5bsXTy/mb7vnV8Qfsv+PH+HvxSs7y8m8uyuv3V02/7u\n77u6vuqUpcTeYk0ctvIi/vI1+WT+7XDWjyysfVZTW9pQ5ZDtLhmbzQiZXZU9sl4ykwp8y/L/ALy1\nZsYYVj2bNif3d9WLXTUjXfCjK+/am2iK5j1PaS92J9B/sgqE+Gt8BHtH9uS8fSGEf0r5cvLV1kkS\na23ivqj9k4Mvw7vlYjjW5AABjA8mHivmq6s/3b7522t83mV+NeG0L+IvFDXSpQ/KqfGcNTkuJM0U\nesof+3nDeIls45PtOGzIv3lrznxFdQ2twYbZGLt8yNJXpPiaBFZHhSQJCjbI5F+Xd/vV5nrVjNCT\n/q3Te235vm3f71fsGIjDlP0nC+8c5Os1vcbIX3jd88i/+g19H/8ABLKdD+0VrUEa/KfBty4b63dp\nXzXdW9tumR7mZEVd0qq//s1fQv8AwScuHP7R2tWxOVHgm4ZW3Z/5fLOvyjxQafA2YJf8+3+aPJ4x\njfhLFv8AuP8ANHOf8FA5gv7W3i6N2bH+gEY7f6BbV4vDeFZmEL/OyfxJu3V6r/wUUuriP9sTxdFG\nBtb+zwxZuP8AkH21eGyakJpvO+bbGzKrL8qtWnB8ebg3L/8ArxR/9NxO3hp8vD2C/wCvVP8A9IRt\nxyJHqGd6/Nub5auR6xD5mxJJGZfmT+H/AHWrkLjXHhX9y+GVtqfN96hvE0DQ7HlVJtn8Pzba+hjT\n5j2PaHZtrG1RNNN+9bdvX73zfxVZsfESM7fuWUxxfupmfau2vP5vEAuI0Tf+9aL5/L+XdTP+Eimh\n2/Oz7vlT591EqcpaBHFcmp6ba+JJtyp8qLHu3t/e/wB2pLXVppGd3uV2t8m5fmbdXmtv4shZVtpn\n/wDsa1P+Ene3m+RI2G7b+7f7zVv7OXUKeIhKZ6Tp+rQtcCFHZ0jTb/d2r/eq5p+sJJbyeS7FWb7u\n+vM7fxY8MrmDcV27vv8A/jrVoaX4mfzPPSbbt+Zlb722s+adM7qFaEp3PSPtjzRqm/8A5ZfMrfw1\nYkktr6z8yF2O77u3+7XE2Pie2+0Qu95tRl+ba25mq/b+LEt5F2PsTyvvN8rbaVPEcr0PRpx943Lz\n5pEfZuX7v3qydSmtpJo7Fpldvm2/Lt2/7W6sW+8QPIGeymVdz/M2zdWLfeNPNX5Jm/dvtdfu1lUq\ne9zRO2Mealc1tW1rzIWtkDfKnz7ovvf8CrKi1zzhF5MzMmzait/DWDqniqa53Ijqzqn+r37du5qy\npvE22IobnYi/Mjf7VdOHrHl4qnynpnh3VLbbFbI6l/vf71dho+rfdheZUDL8zL83zV5L4Z16Fm+e\nb7v8P92u103VN0LIjr8zbq+zlT93mPySnipxkdbb6pN57JNNIvz/AL3zF+Xb/erSSZLiSIJ93722\nP5d1ctaXm7zNnmMv3Uaata1uvMjV5nbEbbl2/dWsZUYy2PcweYVYm/G32i6e587zQ0W1l3/dqby0\nkZ0R12/e3Kn/AI7VbR50jd5ntlZfuvu+6y1NZxzSXC38O10X7q/dXb/FXnVKdrn0+HzKXKmUL61h\nluPnf+H5W+7WLqFrZyQlLl2Ib+Jq3dQ/fLv2Lt37Ub7u2su4VI5lmf5n+Zdu6vExEeWR7FPGfurn\nG61p+xl3uz/3F2VjzaOtwqzbNg2bXZfutXWX0aNItmm4fvdzbqg+w2ybkR925m+Zf4q8+pLlCnW9\nscHqmgvIzTP+6X70rN8y7qxb7RdsDPsw33dq132p280cbwum5VT5VZfvNu+9WLq2lzeYXmRQsKf6\ntU+7uo9p7p0YenGU7nD6po6W8mXTavy/LVNtJcsybJE/e/d27q7HUNPEjL56bP4dv8S1nTWKbt77\nvm+ZGo5pcnKfY5fThGJh2tk9veJbfZt/ztvZn+6tb+m6fM0e/wAnLK+1VZtvzUlvYbbjZ9mVdzf9\n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\ncJM02397uf8AhrKMuY9WjL3tTkbqxdXld081flVPk+aqc2nwwq3kq3+wtdPdafDLveHdG/8Aeb5t\n1ZeoWKRp/eO9W3baXN759Rg8UYNva/MiCBiY/v8Anfeb/drU0mH9586ZX/nn/FTb7yZJP9fJ8vyq\n0f8AFRYyT27D7NC2Pm3bm+bdWXKj6TD4ilKBu2sbx26oltsdlb7zbalhDtMf3ezb/wAtEX5W/wCB\nVU0+6M0J3o2z727+LdV2w3+WEd9m5/njZvlbb/drTm5TzcyxUeX3S3YwpJvKTNFufc+6rSxwrHut\nn2r/AAKqfdqBY9sDzPcQ7V/hVP4qsR+crM9tCqq3y1rGU4+8fEYzEe2lygv7jy/tP323Oq19o/8A\nBS9C/wACNKKkBl8WwFSemfst1Xxxb27tHxbKzx7lik3bmr7O/wCCkUaSfA3SxITtHiuAsB3/ANGu\nfzr8s44qf8Zxw9L/AKeVfypn43xjGUuKsoVt5VPygfCF3b7VdLlPkk+ZGWoI9NSV/kRmGxdi7/lW\ntO4sXkWQ7GTazfNJ8tWNN0V7eP7S6ZWbb93/AJaMtfrX1iXL7x9p9XnGRnw2eVe2mmbGzft/u/3a\nsNp7tiF0ZG/iZmrVXT/lXcixKz/xJ8u3/eq4mkwyM0LzKrb90S/wtXB7R8+/um9OjLmszkLzSYY7\nd7mY7V2/NGz/AHq4j4P+NYdH8SeO5nha2Vp4V3Q7WVty7V/3Wrq/idqj6TqEemwoyssTP+7f+7Xz\np4b8UPpvijxJZzJMWvrVm8uOX/lorfLX2+SUKlPDe1f2j4PiCvGeL9nH7JW+KV59n8ZXMLxyReZK\nzeZJ95q8+8WSPY30V5D5h3Nt/eVtePNa+2XFvreyTO3ZK0j7tzf3q5/WribUrP7S8ylGRm2/3v8A\nZr3IylI8L3TlPF2oTTaozptCsn3qzrySFbYzTbfl+4rfxUniK4VZN7p8+2ud1rVnkh8k7g397+9V\n/aKH+Il84iZ0wrf3axIpvJZofmrZgc3uijzDny2rMkj3Sb4PvUfCEfeIpP3f393+9TJB5kf3OP71\nSXCBl+5yv8NQTcMqb9w/urRI05eaRAx29ak2Oyq9RuN5yaVfu7PMpc0S+VCx7Nxy3SrWmSPHL9/7\n38NU6ktWCzLu6UhSidJbSSeTs7L/ABU2RXjZtnzbvvVHZzPJDsTbT93k4RUyn+1T93cxG/eOzO1v\n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\nsjjZu+X71Mvptuz+JF+Z2X+9UP2zzj9ptpF+X7i7vm21rGUj16NOMhGm/wBHCFJA/wB7bJ/CtMms\n0hX/AJZszfOn+1TFmtpoRsTKxptTdSeZD52Uf7q7V/iZq1p/EceOp9Ty7VbB7G4dE/hT72za1Ys0\njtvjQYP/ADzr1LxN4V8xVn2Kv8Xy/erjtZ8KTWcnnJt/ef7NfSU8R0PxfEYaUdTntLuJrNt8KMfk\n27f96us0XULpow+/dtXbtVP++qyI9NmiZd+0My1t6TYzRypawpj7rM33f96ipWOajS5Ze8db4fkh\njVbmZ2+b5dqt92u20nUsSfI7PuT738VcBpdi8MbPG/nfxJXV6be/ZofO34eP76rXnVPelzcx7OFj\n7P3ju9FvprPbvRW/vtXX6FrCXCr/AKtF2fxfLXl1jqUMkaJbeYp3q3zPW1Z69LtV7l4dm/a275ZG\nb+GuKpRlKZ6lHEcp6WurW00LeSkgj3fKyptXdUd1qiLN882xG+4y/wB5a5LS/EEzRu7u2z7qNH8y\n7qh1bXXt7rf9p+b+Bo3+X/d21jHDz7ndHFc0feOg1a+jWT98/LfKjfe3VkX148h2PMxP92P7u6sa\n68TOc/adrfwov8VUf7etpt8iOzlX+Tb91aqVGXL75p9cpRloaN5ffNLDN95W+dvu7VrIuryGZ879\npZfvM/8AFUGpeILaFd/nSfN8vlt/6FWXeX0zN9xXbfu+b5af1X3YlSzKKL7XF5dK1sky/N83mMi1\nXWN2YQwouPlWVf7tMtbzbHKnnblVNz/3qs2O9pR8iun91vlqJRlHTlOeWO9pqzV0tfs6hE+Z2b5m\nb5vl/hrdsbM+W3nIwjjfKNv3bmrH0t0WHzPtKpL/AM82+81asMsKzJC7s7Qv8393c1efKpLnNIYr\nmhymxpP7yR4ekke1n877rbq27MJcKU8lklZP4X+Va5u1vJrdVTyM7m3JV6G4k8n/AI+WZ1b/AHa5\nq1P97znbh+aUpSOhtbqG+j2edGd331b7y7a+zP28XiT4SaWJQMN4liAycc/ZrmvhqG/eSSLZbbdv\n8P3fmr7d/wCCgVybX4NaZIIlcnxNCBuOMf6Pc81+ScaxcOMsia/nq/lTPhOK1y8X5L/jqflA+ZLW\n4hk2wj5Ek/hZvu/7VasLW0zb4PnSNNv95q4iHVkhZnM+f73ybm/75rVtdVdXR4V4Xav/AAGv0+MY\n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\nvtkuZEXzdyqrblrnNY0WaNmTyfMSH5v3f/s1dNGtKXxH5hiMPC55jceHYZGDp8wV9su5P7tW9Pt4\nY4V2bQzP8jN95lrpL3T5riT59ztGm2X91tqvb2cMMxhe2XG/Kt/FWn1j3fiOP6vKNX3SGzsZFb9z\nDvDfNtrStbGbcu+LIb7+1/lWp1j8mzCIm1o/m+X+Ld/eqSCaYW8R+zM/8P3KUanNGyNI0+X4iaPZ\nC3kw7f3jf3fu0LPDCwR5vl37t392s1vOjl8mGdj8/wB7f92i4uv3zujq6fx7fu7dtaU4395SM5VI\nm9Hqzx7fJTZ/teb8rLVDUtcuVDPNMzL/AA7qwf7Qmb5JkZ5WRV+V/l/2aLy48lgn2n7vy/draMYx\n0MpVJcvxF9tYnvGZ5rn5f4V37tzVJHqTyK9y9yqeX91W/irnW1JI5j5brTP7URVeGby3i2q6R1pK\nnzQsc3tpxkbsmpOq/anvF+Zv3Ucm35v9moI5kupHuZpmZ1+9tesua8S4kSa5Xem7918u7a1Tw3SR\nyF96qnyr8v8ADWVTlUCI4iUo6m3aum9YYfMQf7P3WrSt1dUXUk2v8/7qNl2qtY9ncJ8qJy2/c+2r\n0N3DJ+9mdmXeq/u1rza0pOXNA7acubc6fT5N00dtszK3y7ZP/Qt1XZLpFm8l5l3b9y1zFvqT/ax5\nMzStsZfm+Vavzah837sSZX+HburyK3P7e/LoevQ5JRN2HU3dfO8pY2X5fmepGuPtCpClyqNs/e+Y\n/wAzLXMyah5kwT78TN8219rLVv7XMzfvjvWP/wAerLllKPMerTrcvuo6e31a2hhhT5pX/vf3v9qv\nuv8A4KQ366f8ENJleLeG8WQLt+trdV+fEeobY4k+438Db/lX+9X3z/wVCu4LP4BaPJPLsz4xtwrc\n9fst0R0+lflPGtNrjPIe3PV/KmfC8WTvxZkrv9up+UD4zbXJl+SzhjVfveYrfMtWtO1p42LpMpDR\nfMzfNXIR3XmTfvH3hl+Zl+VatR6n5NwERP4P4a/WFT5tj9E55KRJ8bPHj6D4BvLmG8aOWSDykaP5\nm+avjbWrp4ZG+dnT73zfer2T9oTxpNqGtJ4ehfy7e3i3S7fvf71eM6sySM3dV3f7zL/tV97keH+r\n4Xml9o/NOJcZ9bx3LHaJyvi2L7RalNm/cv3a5fR9Y2q1hNIyj7u3+7XT68u7d96VfK27vu7a4PxB\n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\nu/LU1tp+795sUfxbVWp5UORDHHt+d92V+6uyrml6XLfAbE+7/FVi1s5ribZ5H3vl3KlddoOgwxwD\n+Jdn9z+Kuimclcz9J8MvLl4f4V2/N/E1blr4Z3TbEmaUx/Mv+9XSeH/CkNxJ9o8jj7yLs/irobHw\nik0Y2Kqu3zblWrlE4vafynE22i3MK7PJZm/g2p92tVNPmt8edNsZV3f7O2u3bwnf2rRulszM0Xze\nX92qF94TMavM6Rjy/urIrN8zfw1nUjzfCbR5/tD9Wa/adn8lcMvz/wB2sCa/m+1H51xs/uV0d9HM\n0MrzFl3Pt2t/DXL6lDDbt8779392voY4WHJ5nFHFS5iWHVjbtGmyT5vm8z73zVu6fr3l242O3yvu\n2t/drkVnSFT95H+VUZqtJdTFAifeX5ty1Ty+MvsmscdKOp3f/CUPI29Jo96orIq/+zf7VWo/Ejze\na6XO/an+r/8AZq4CG/mRWd+DN9xvvVN9s2M298SK67FX+7RSyvmi7FSzC8LncQ+Lv9WgdmX+Py3+\nZv8AZpj6g8is5mhXc/3ZG2yf73+1XLW+oC623M6eW7fK6t/7LWrpaxxS/wCk7SrfKka/eVa0/s3l\nMvr3MbC3C3s2yFFD/dVm/iqa3t7lZIvOuVcN8rwqn8NV7ezhXytjthX3Izf3q2rWzX7ULaZ2x95m\n2Vay/lOf657xd0exmkmj+dW2/Mi79rbv9qumtdJKsIXeNn+98r7lXdUOg6P+5aZ0jZF+42z5ttdh\npGnpax+TMjNFJtbdJ96pjg77DljOWPvGHH4bTy2eSH545fkbyvvf7LVch8PzCP8AfI3+q3bo/uq3\n92ui+xw7fJk+Z/NXymb+FauLovzO8KLv+b5mqo0OWJP1jmOUm026urhXm2od33pP7tUNY0na2+H5\nvMX733l3V111pHlxvNs2lZf4n3bv9qsfUrGGPZ5Ls+7czL/FVRwvu8wvrnvHA6xZ7Yc/ciZGV/4q\n5m8h8yH9xuG5NjMyf+PV3viCH92uxFXbubatcXqcbwhpHdjK33/3X3a1p4fsOpiOU4/WrfdIf3Ox\nF+VmZ/vf3a56+haPa7vuX5VdVrrNatd0zQ+Tvj2fPt+7urndQjdmSQ22759u7d/7LXTHA8sbKJhH\nES+Iy/ImZWfeyMzfer9B/wDgvLDLcfsZaRBEQN/j+0DZ9PsN9mvz+23P2j59p+T5o/7tfoH/AMF3\n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\njzM6I7ZV9u2tvw1I6zeTcuqqv3FZ/vVz6tBNJsT5dqbqvaTqD2rq77W2v/c3fLWNRe77pvzcp7T4\nHunjgV7yaNnV1+7/ABL/ALVe3/D+8doYXmdXdfn8xfm3V84+CtaSM/ZkmVWj/ib+LdXsXgLxAlvL\nbwvMxST5vlb5VWueXPLUmXwnr+m3j3Vx9mubbcPvfaFSttredk/1LOV+aJm/9mrj/DurabcbHhuW\n3LLsRt/+d1dHpOpQqwR7ba/mtukb5d1Yy5vdfKcXumjZbNx86T/f/wBmkjjkhmZ0myPuRR/w024u\nHmhVbb5fvfNVDUtbe1h8l5o2k27tv3VrT2kdwPinUr50ZrZHXaz/ADs38NItu99cGaZ22xrulZdr\nbmrDGpXNwvyXKlWf7v8AEzV0Hh23kUpcvD919z+W3mKrV+qxxXunyVPC+7c1dH0fc2Niuu1flauk\n0/w7Gqpcuke5V+7TNHsknmV158tPnkk+XdXT6bY7Yw72ylP+en/j1ctbHSlHSR2SwvwmcvhO2uNj\nx2zBI/m/4FS3HgtFy9ydu1/ljb7ys392u00fT5poRM+5hIu5G+7/AOO0TafbRloQVUfKit977v3t\n1cUswlGV+YxlhIxPO7zQ4Y40mJYmbcnzfeh/3qzL3SUa4H2PdGrfdZn3fw13+o6W7SNbQ+YE27lZ\nl+Vt1YmpaX9jy8Ntimsw9pvImOFlDY5ZXht7hEdFcL/e+8zUR3W3zHfzFT/ZSrd1ZzWsk2x/nml3\nIzf3azrya2kgPk/cVdrrt+9SliveNPqfcvWOtPp+N+7f919z/wANWbPxMlvI+ybcP7rVyVxcpb26\n2qbdsf8AdRvl/wB2oG1p1jSJ/k3fLuVK0ljubYyhhe53reLkmjdw67V2/LTG8XQWbEJub59rNv8A\n4q4Btc8qNn3su1PkZqzZPFm2NbnfJsmXcytVfXOcpYeUT0+bxl5cOyzvJvN+78zfe/2az7zxJbTM\nZkmZjJ/ra8yuPGybW/fMflb5V/i2/wANXrHxBc3EIeSeMMy/db+Kn9YiqVmKWHnGXunbLqUMzNM9\nzJtVfm+b7y1HPqPzD52fzE27Vf7tctY6w6rvtpmbzNyMrJ/6DWjb3KbldPLYb1X5flZm2/xVEsZy\nx5UXHDXleZo7nkjTzvM/uszfN5dI2+RmTezbU+X5f4qhs2hk23KTf3kb5/lqyykSI/y7Y4tu5fu1\nnUxnKdEcPKRUuI4XbeifL8v3m3fNX2n/AMF5lU/sLGR4ywj8VQtgH/pyvK+Mb6PzI0gh+ZmRv3i/\ndr7X/wCC6Nobv9h2RSoKx+JYpHXuQLO8PHvX4B4sYj23iPwlrtUxH5UTxcfQVPN8H5yl+h+EmrR+\ndYr8zNuRWRWX/ZrlriF7W43p/ertdaX7HpsU3mNtZfl3f7tcNqFx50pP8W6v1b3T7KPxBDqk0Lq6\nzN8tdL4f+I+v6fMjw6lJuX7jbq5BULNtq1p9u7NsfcB/eqSuWB6hZ/FzxXNEIbnUmmi2N+7uF8zb\n/wB9UXHibR9QZ/7Y0GxuVaL5NsW3/wBBrhPOmjVkR+Vq1b3T/Kyc7v7v8NVGXLIylsb8mk+Br799\nbaJNb7U3fu5/u1dhuLaSza1h3Ou3b8yfNWJazO4+5tVvmbbWnpczrPvnmbC/3Vq4ilL+Uh1zwreX\nUMWxFaPZ91l+81cfq3gzVdPlO22k2r/d+bbXrWrLba5ouz5kfb8jK+1lrzvVtS8SeHZpLWab93/e\nX+L/AHqn4RxlPmOUKzW7fPwy0+4uvPGyZPmXvW1/wk1hcnZqWlRt/tL96s7WmsAwa2Tll/h/ho5o\nm3xFCiiioLG+X70qrtpaKr4QCiiinHYAooopgFFFFABRRRQAUUUUuVAKq7u9b2mTTW+kl027awVO\nG+f5q6CyjkQRpDtxtXg0SiY1T6L/AOCd+nzab4s1Px4kK/aY7P7LYXDfehkZtzN/3ytf1DfDj40w\n/HH9nfwr8R9D1hZbbVvCtvFcQ+V80c0caxyf+PV/OP4F+Gt/+zvp/hvwTqr7dQvNIh1a/haLa0P2\nhdyr/wB87a/Zf/gh/wDFKHx/8G/F/wAHbzVVkuPC91b6ja2rfNttZv8AWMrf738NdGHlyzPnsVUl\nUlofVkd8/g3ULLR7+88ma+sGngk3/wCsaP8Au14t408D6b40+K0HiiHw9CHjWQSyW8S+a0n96u2/\nbAvNS0fxH4O1vSraR4rWWaB5FX7qyLXEfFr4veDP2cfAL+PPHPiqPS7toma1t1TdPeSbflWFf71d\ntSpCj7xx04zlofDHxdv7Lwt+17Lqt9OsVvp3iKwmnd8ARoghZs9hgA/lXmv7WH7XnjD42XVz4b8E\n3rWuhb2+1XH3ZLj5W/1f91aj+I3j4/E/VNY+IN1p8lsNTaaZoJm+dRgj5j6kDJ+teHePPG1hpeiz\n+RtlZlkbaq/N8qt8zVXFmKlHD4Jxejpp/gj9L4zjJ5flK/6h4flE+MfCljNeeINYuXDFW1eb+P73\nzV2Nu3kr5PzfL/DXG/DeN76zmmmfa81/I+5v9pmrs/JTcmE3Oq/Jz8q/71eRS+A+XfUfNC8kO/Yu\nJPl+ao22L8jwq4+7/u1NcHdD8n/AttUmj27/ADkZlb7u2r+ID1/4A+KPDfgrw34h8Q+IYY5biP7O\nulqzfN5m7c22uM+JXjK88Xaxc+IdSufLT5nePd8qrVDQJENiyPt2L/d/9mrzD4+/Eh7iY+EtKmUL\n/wAvTR/+g14lajKti7HPHD+2q/3Q+HXjR/Ff7TfgVbZ/9Fh8Z6WsQ/vf6XF81e5/8Fbv+af/APcW\n/wDbOvmf9nP/AJOE8Cf9jnpf/pXFX0x/wVu/5p//ANxb/wBs6+6y6EYcMYpR7x/NH6TlUIx4Kxyj\n/NT/APSonxrQW280UjLur5o+OFoooquYAoopPn9qoBaKKKXKgCgNu5pU+8KNqKo2fepRAaowMVoe\nHr99PvPtMfXbtqhWx4I8O3vibxDbaHpsavcXUqxQKzbRuZttPm5feIqe9Cxqza5e6lqiXM0zZ3L9\n771faHwzsPgV46+F/wAN9V/a0h8eXPgnwK9w32Xw7qKt/osknmSwxrJ91pG/iWvmzU/glp3w/wDi\n1/wrXxp8TvD8N3byxrPeafdfa4I5G+bbuX7391q9G/as+KfivX/CGlfs+eGvCOhwXWl2qyXl14fu\nd32i3+6q7f738VZ168ZWgt2ctFa3Z6f/AMFPNT/Zm/aA+COi/Hv9nj4kaD4L8I6JeLpPgP4HWcvm\n3VlZ/wDLS6uWRv8Aj6kb94zN/srur4El37uKdqFleabePYX9s0M0b7ZY5F2srU1mTjfTjGUTtGsN\nslDO7Sb0FIxy3FSW6/Mc/wANBHwmv4R0/wDtLxJpump8pur+3i/76kVa/pe8TrDa2trpriZkh0iz\niWP+H5beNa/nO/Zt8O3Pib48+CPDyQ+c+oeL9NiSFfvf8fC/dr+ibx1ffY/EF5bb9zLKyIzfN8q/\nKtcuIfwxOat0OUurxJrhoXtmTy/7zbVrndUaaNmRPl3bm+at3UGkkaV7lI1XbtZV+ZqwdabzF3vu\nJZfkk+61c0vdiXH4zj/Elv8AarcI5VFXaz7vm2tXDeIlmXels7f7e77tei64sK7/ADhGEjRfN3fe\n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\nAKDSx3zxSfJ8m7+FWrMa6e3VNiK23arr97dU26Zm2JJHhdzO2yo5eU2lI7fwrrv2dvLe5Vw1emeC\n/FSQ2ohmufn2fKsn3tu6vB9L1Z44RND8m35v+BV1Gk+JkVVe52r8v+sX5vmqJR+1EyqSjyn074X8\nVbV+zedlGT/Vt91W/hrrtN8VFlxc3LSCNtyRq38P8VfN+h+OvJ/dzTbVZflbd81dlpfjf5kSGb7v\nzrI38VRKPc5JS949r/4TR4bMwQosifegXftZv9msfVvGTvHK/lrsb7/8X8P3a8+m8cPIw2XWW/vb\n9q1h6t8QPLiaa5mWJm+8vmtWUqfNEXNCJ5Ho+oeZJHvSNV/jj3fKtdr4ZkjjjJSONF3bWhj+Xd/t\nLXmmizWccbTTTfu9+35fvNur0Lwu32ZYn3/d+XdJ/F/vV9ZWxXL8JhTw8fhO58O/JCsIjVNyfdb7\n1ddoMiYZHTy2+7FHsritLjhnkExdZtv35N/8P92um0u5aGNJrr5UVtyfNubb/DXHLFSlqbSoxO10\neaZm/wBJm/u7JNu2rs1qjZuYQuybd5q7/wDx6szRbi2+yb4JmmaP5nX+GtKO3S82pMcFk3eWv3Vr\niqYocaRn6pZuqo+zeYUZtqvuVqwNXtnk+5bSK0m35f8AZrs1VPLSN3/e/MvkslY+sWbr5ttDNu3P\n+6j/APsq5vr0YyKjheaWh554mjSVmubban73ZuX5q5fUZptrQJ8p/vbK7nXLOGBXj85Wbezfd3Lu\nrldQtYPlmhdmlb5W+X5W3f7VV9el3CWF974TjtWvoYv+XZWeNNrSfMv/AAKuZm1h2kVPtLZXcrt9\n1a6bxJapHbtC7soX5drfxV5/rn+jXTp8zP8Ae2s/yr8tdVHGe0OepQlEs3XiKa3VHd/3qtt+X/0K\nsfUtcu4/3jzM3z/dqjNrk1vcfIi/c+fdWTretQyxs79VrqjiP5TCVHlNWz1SNrhnm3Ntdtv+zXTa\nHfR+Wjvu2feRZK8z03Uo/tG/zm+b5q7fwnqU/l+T52Xb7isn3ar2yD2fwnZWcyRsj37qqf3l/h3V\nr6e32fZD/rG+8vmf3awdPmn+0RPNMrrs3PtSt6wuvJbznfn+7s/irCVbll8RtGP8xsaX5KlU+88n\n3of9n+9VltkjM+xSrfeX+H/ZqnYrNcMzvtaLbu+X+Gr0bIsLTf8ALuv93727/drmljJfaNqdMjk8\niOLekOyX7zbd21f9mvt//gt5HHL+xS0MhI3+JIlU4yATZ3g5HcV8UTXDx2bOkLD5f4q+1v8Agt9c\nNafsSvdLbiQx+JYGyWxs/wBFuvmr8O8SK8qniLwu+1Sv+VI+ezulyZxgV5y/9tPwj+Kl9DZ29vYQ\no3yr83+9XAM38dbfj3WX1fWXmR8isvTtPmvrkRRoxr9wjE+kj7sbhY2/nygbe9b1vp7w2/B3M1bO\ng+BX+y75E2u1Q6+0OlwsiDJ3bavl5TPmjIxv33nMjupO/wC7WhpNqm754WrDuNURmOxG+Wki8TXl\nvIHR+KXwi9+R3lnojyf6naE+9u/i/wB2pI9Njt1i33Knb8zs38NcpY/EK/DeTO+1W++y1c1rTLnV\n4vPsdaDI23YgpylzClHlOuF5YSL9j/tKEj/rrUV9pMOuWv2aYK8ez5JF+avO5vDWuxMXhDOF/iV6\nm0xPHdsv+hw3RVfm2/w1MecqMY7lXxLoNxouovCfu7vlrKkZ87Grc1vWdSuBs1WxIdV/5aJ/FWHM\n7yNuakaxFopFbPBpav4ihv3/AGxSMu2nKu2hl3VAC0UUVcZAFFIrZ4NLRHYApeVNN53b91LUAAbd\nzRSKu2lrQAooooAfHHukXf0avW/2VvA2m/EX46eFvBmq7fsE2qRy37M/3YY28xv/AEGvKLH95IN/\nG2vev2WfDepWV5P4wsJZEmX91ayMn3W/i2/8BqZe77xx4qShE+sv2ttY/wCEm+M0/iq2mV7aZVit\n2V/uwrtVV/4Dtr7F/wCDf74jWfhL9q7WvDd5qvlL4i8HzQMsn7xZGjbctfn7pdrc3V5/aXiR8xwp\n92RPvN/er3f9gH9oCH9nv4+W3xatoVuIdJsrj/R5H2rM0ke1VrGnUtLnkeI5c5+wv7ZX7SnwZ+G/\nwz/4TDx7ryxLp9xG1rZx/wCtvJl/5ZrX5F/tFftQfEP9pLxxJ4w1hJokjdl021uLjdFZx/dXy1/3\nfvVmfH74jfEj9pD4gXvxF+KPxFjkVrpv7I8P2cXl21jD/Cq/3m/vNXmcmi6Pasz/ANvXU6MrblWX\n5V3f3a48Zjp1fQuMfZnqOlRFvhnLDe3ivmxuBJNG3GPnzg+39K8h8dah4S0DwXqjpNG5a1mbdGm5\nmby69T8L29lZ/Bt4IogIF0+7+QtnK5kJrw341eILXRfhnqt/ZwqhXS5otrL8vzLtr3eKFz4fLWv+\nfMfyR+gcX64PKV/1Dw/KJ86fDO3ePw7BN5PMm5tzf71dTJvhzsT5fvfN/FXP+B/9B8M2cKQ/6yJd\nm1q2lmeWP998p/utXPCOh8pU+ImjjS3jaZJmK7F2rVSS48kF5Plb723+GoLrXLaPMP2nZtfbtasa\n+8RIvyQ7Sn96l9rQXLGRqeIviU/g3wfdJbJH9ouG/dTfxL/u14TeXc1/dSXly7O8jbnZq6D4iatL\nfXsMH2reiqx2BuFaubqY04xlKR2UafLE7L9nP/k4TwJ/2Oel/wDpXFX0x/wVu/5p/wD9xb/2zr5n\n/Zz/AOThPAn/AGOel/8ApXFX0x/wVu/5p/8A9xb/ANs6+nwX/JNYr/FH80fcZZ/yReP/AMUP/Son\nxrRRRXyx8WFFFFACMMjiloorQBFXbS0UFd3FT9oAooZfmye1FPlQCt+7au1+BWr6bo/jb7Zf7d/2\nC4W1Zv8AlnN5fytXE0b3Vg6Nyv8AdqZRJ5UbUWnzLdPc3k2597M0m/7zf3quW8F42rrq763J5i7d\nszP8/wD31WENVuQhTPBqM31y38bCr9zlMOSrzXub3xDvbLVtcTUbYbpZrZWum37t0n96sBd67t9G\n4NIzvTJF+bmp5TeO4L8nCPU0bKmE6bv71RbTu+SrEMM0mfumpJaufS3/AASn8K/8Jh+338LdKmto\n5IYfEa3T+Z/0xjaT/wBlr9w/Fd1CLyWZ33edcMySL/eavyN/4IS+CpNY/besfEkyRvD4b8L6hes0\nn/LNmj8uP/gXzV+sd9Ntt/kfeJPvKz/xf71ediJe8Yv3nymRdN+7d/m+V/7n3qyNSie4ZY3s22sv\n975lrS1BrZbqSGO8Zwvzbf8A2VarXiw3UaTfbP3f/LKNflaSubm6s6oR945XVrVxG6PbZf8A5a7n\n+Vv96uS1LSUhYiZ23yP8vlv81d/qcJaRke2XLbvNb+Jq5i8sZppJSzyJMqfJtiX5f9ms5e9E6qcT\nzTVNHcRo6Iqtt2urL92sSTT3jZ7Peqn7zbl/75r0DUrFBueZY5TMrK23+GsO6tLZQ1s88hRtvzNV\n/YOnlOVW3uo4/J2fMsv72T+FarFZlZJ98ed27zFb5q3NUtUWHfbQt838O/5WrNuP3yt9p3IJNv3f\nm2tXLKjKUtS170feM2SZJVdEdkZpd25futt/hr7f/wCCZgI+BOsKUxjxfPz6/wCi2vPvXxFJHtaV\nBMuyN9y/P/49X3B/wTTlkl+Busb3DAeLpwmDnA+y2tfjPjqprgad/wDn5T/NnyPGsLZFKX96J+BP\nx08Nv4X+JF/C8LJb3E+/95XF61cbbVPLRRt/hr6r/ao+FKeLPC767YPvnhb5l8r5m/4FXyRr0Nzb\nyCzuUZXjbbLX9BYatzxPYxFGdGp7xQffIy/P/FUvluy7BtqBW2yf7P8Adqe3j+8+/J/u12c3NI5/\nsD4408z5xz92o2ZFkb56k8zy4y38NV/k8w9aYDzmOTe6VctY3mb5E+Zfv7qrLH+8Z3dsbP8Ax6tC\nzheHa+xt/wB59tTGPMRKJLt+zq29N3ybqrXt48kyoj/J/s0moX0yyNDvwzffX+7VSNpmbhP9+iIj\nodLvLlV3o9dR4f0ua+mjR5Pvbf465LRYnmcJv2j/AGa9X+HOjw+T5n2VU2/LFuT/AMep8vKOXNyG\n6mm+TpNvYWe1j/y121NfeB5pNJm3wqyeV/u/N/s113g/wrDt+1TOu5fm+VV2tWn4gtkuGe2R9ny/\n3flrWUjCMv5j4i8V6Z/ZGvXWm/N+7lb71Z9dx8ftDTR/Hk2z5hInzN/tVw9ZnfT+EKKRW3UtKOxY\nUvzLSUitkUwFLbeaft342U1kCgU4Mcl6XMgCH71aelwpM3zrj+H5apJ94VuaHbp52x320zGRrwtD\nZ2z/AD7dqfPXE6jdPeXjzH+J66XxddPa6d5KO25m/i/u1yaggYNAU49WLWt4cs3WRpv4lXcm6sy3\nXzptldVpun+Ta+Ts3P8Ae+aq+IqpzdBI2+zt8+4/xVqRj7Rb/IjDd83zVnyrt2pBG2N/3v8A2Wrd\njeJ5ez5jU8vKc/xEl1a7UDpy3+7VeSL958nyP9160JI0aH7jL/wKqshcSNsbdtpfYApzxvCyom1j\n/eqxYXE02Wf5T92msJvM/efKrUscZjbfvq4mhqMJNweH733U3UCaZZNm9R/s/wANQafcOjeX8rMv\n8TNVtY0ky7x/N/s0f4TP3Bbe4SSRYXDN/eqxHMlxDszt+Xb8v3ttVYflj3b9q/3qmVtuHRGdf4/4\naWvxE/FEltr77LeCFE/3K2br99p7P93av3qx1kSRVwn3f4qtx3U0lv5P8S/fX+9Vj+H4Tl9bh23D\npC7fd+81c3oOoSaPry3azMrxvuG3+8vzLXUeIt6sf9r/AMdrhLqXbeeyt8zVmaU/eP6Vv+CJP7QU\nPjT9nOGHzme6uLBVaGb5VWTbtr6E/aw/Zm8PftXfB2PTfEmg/Y9c09WXQ9Sh272kX7qs1fkP/wAE\nKfj9f6boOp+EtS1vy447qNk3XXzKu35dsdft5+x743/4WXpep+GLZPtyWd0r3TSfeh3L8v8AwGva\nw2Nqu0JS908ethI8rmviPnX9mvR30P4evZXunC2v0vvL1NC2XaeOGKIs/wDtFY1P5V/Oe+qJu+5s\ndq/qT+LHhSz8JfETVbawiCR3Vz9o2BMYJAUg+pyp5r+VKe88yTe7thV+Rm+9X8/eHMXDxL4riv8A\nn7Q/KqeNkcnUzDFt73j+poNqCffKYenyat+7G9mX++y1iNebQu9/laiK/wDl2F1av2uUuU+o5feO\nh0/xAI2T5G2bvlavvj/ggFqqX37YXiaH+JfhreEtuzn/AImGn1+ccd48fz72Rvvf7LV9/f8ABu5e\nfav21PEw8vGPhZe8/wDcS02vzvxZ/wCTcZn/ANen+aPMzqMVlFX0Mj/grXrr2H/BRL4gwIyfKuk9\nRn/mE2ZrwbT9e8+HZcj5W+ba33v92vUf+Cx2rSWX/BSf4jRo3yhtH3fLn/mD2NfO8fiiaGH/AFO4\n/wC196vY4C/5ITKkv+gah/6agLL9MBR/wR/JHokesI1u8aPiKOXcu2ql54utoY2mdFdV+b71cTL4\ngu5G2P8Acb7nz1HBJum+d1X+9X1suXmOyMZct0dHqHih7y42I+xW+6tV1ukaXe77WV1+X71ZEcyR\nvvRGYt8r1KskPmDZ8rfxM1TLl6HXRlGJuw3G5ke2flt3y7PlqxHMokVXfPyt/BWOt5N/rv733tv9\n2rdvcJDC+yFt38G5/wCGublR6NM1I28/ciR7tv3PmqTznkRZptq/3FWqUNxujKbP9/8A2qmt/Juc\nv9p37m/ztpcvNA6eVFlZvJjj2fcb7+7+9UsOtTW8kVzDt+V9u1WqvHcPHbiF5o13L8235qb8ix+v\n+ytFOJhU3Ow0vxUkkIfep+b72771bNj40lhkR28zZN/Ez/drza3mmt9oktmb5vkVU+Za0be8fy1/\ncNvZG/j/APHquNGMonmVqjpyPRpvHDxwfuX+ZU2v8275awdW8cTXWy2FyxZf4v7tcv8A2heSbkL/\nACRpt+/VC8un3L8+xfm27ar6uY+25viNzw3f+c3yTbZV+bzt22vQvDerbQl5bIqM339r7tzf3q8V\n0C+S8lXf8jM/3lr0bwteRwyb0uZNyptRV+61TKUuU9rlj9k9d02+gkt0mSbE29vu/N8q/wB7+7XT\naDeIrJIm7+FpVj+bbXmuh6s8LI9tM3mNtXbu+9/ersNB1jT0uWSOb97vVfJ/i+auaUqsYj5T03w/\neQySI7nd8u7av8VbunyQ26pMjsH81n2w/wAX+9XGeF9URVDu6o0e5k/vbv7tdTayTbVd03bmVk2/\nL/31XnYjEfZOqnTjKMeU1Lz94geZJP3j7tyxVl601zcxvseOGJty+ZJ/s/3avzX/ANniaaF2fb8z\n7vu1k6hDBcbblIZD8/yQ7/u15E8RGn9k9CjhfhcYnOatboJkLzSRP92Ld92Suc1bSfsrfZrlPOXe\nzxfPuVf9qu21Jba4jXzoW3SNtVY3+7WBrFilvAIURkX73y/MrVj9c9pG1zt/s3mjzHlnizT/ADo3\n+Tft3M3mfL81eZeILWZrx087+D569k8SaK7RmSZNsv8AGq/drzjxBoMyxzJIjLtTa/y/w16+ExHL\nOPvHk4rAy3PNtc3wNsdNzL825a5nWL79y379sbPuqldtr2motqfvK6/K7VwviKzfczp8nmfNXuUa\nnv8AKeFUp8stDP0/VXFx874ZflSu78F3Dsyb5mB3/Izf3a860+N1uf3ybq7/AMG2rySJC+7C/wDj\ntdkYnNKJ6L4fuoWmELvIyfwNt/irrdJZFtf3yLv3N5qs+75f92uW8N2aSTKiKuK6/TY7aGRUw0pm\nXazL/s1zVo+8bRlY0rNfsse9E4b+Hd92pVjdpGfyfuv5iN/s0Q2sLXPz3Ku8afOq/wDoNaVj+8jW\nZ0/1aM27+L/drz6nNE64lXbM1vJ+52oz7opJH3fe/hr65/4OANSOlfsBTXQlCZ8VWyc/xbrW7GP1\nr5Q1KSCawTY8iFvmWPZur6S/4ONUeb9grSYFcgP8R7AMAPvAWV8QPzAP4V+I8dprxF4Zb29rW/Kk\nfM584vN8B6z/APbT8J7W2fULr5469N+Hfw2SO3/tK/RYgv3PMX71WfhT8I/7Sk/tjUkxBG+7/erY\n+LXxC0fw7GdE0S5XdCtf0FH3fePblzS0MHxh4os9Bs3hhGNvy/L/ABV5dqusXOp3PnSTNj+Gn61r\ns+tXHnTN/wABqnHG8sm1aP7zNox5YiBt3NKqbjha0NO8N3F4jXMoaKGP/WyMv3aW4W1ttyWCeb/t\nNR74c38pnMrhfuVe0bXtV0eVfs1ywTfu8v8AhamLGoJ+0zY/2ansZIbVt6W2aUhc5sSfEDxbJH/o\n22MbdvyxVDH4g8YSSfaX1W4T+FlVqY+oSeSIdi/N821alsbW51CdYZEYmT7lOMeYy5uWJ0Pgu4/4\nSBbjT/ElnHchk+SRl+b/AL6rnvGHgeLT4W1XSJFePPzwr96Ouohs7Xw7p/2a2dmuZE/eyf3V/u1F\nb6a01v8A6S6wwyffZqYoynznmSdfwpzLnkVa1q1XT9UmtkfIVvkaqnme1ZnUOoooq+VAFBbbzSMc\nDik+/wC2KX2gHUUUUcoBRSMcDihW3URAWiiiqAKX+D8aAxWnR/NwKANnwbo93rOsx6fZ2byyzOsU\naKm4tI3yqu3/AHq/arwL/wAE7/A3wp+A/gvRLzx/a2WpWuh28/iPS5rJXka6m+aT5vvblVttfFv/\nAAQJ/Y/sP2r/ANvTwx4d8SWck2ieG4pPEusqsW5fLtfmjVm/h3Sba/Yz9pz4H+CPjZrlxcvcyaLq\nNjf75bqz+Vbpf4dy/wCzW9GnLk5kfOZlX5qvIfG3xw/Zl+FGh2sE+j+ZIkafuvlVVkVv4mryr/hU\nuiafbyww6k0MX31hjRf++lr1v44fCfxtoPiW68NzeIZpYVRfsu5/lZV/iryjXvCvirR2KTXm8/8A\nLJl/9mry60qrldxOWjGnGOhyfiDw/YWdxsS5b7nysstYdrpaeY+1N/8ADW1qXh/Uvl+0zMX/AIlV\ndy1VXQ7mRmT5lXcrfK//AI9Xi1ozlKRqdz4XhEfwhaDzC4+wXI3HvzJXzh+1XdJZ/B7UZkH+ueOB\ntv8ADuavpvw9avB8Ozay5JFtODkcn5nr5f8A27o4dL+F+n2aO2+81mON1ZPuqvzV9lxFS9pTy3/r\nzH8kfo/Fic8HlP8A2Dw/KJ4za6h/ZtjAtmm9IYlV/wDe21T1rxNt/wBQ+F2/Nuese41B/svnJM3+\nztrNkuXmkV3fdXNzXgfJRjyybLupa88yr/Ef/Qqw9Q1i5kkZEdlb/wBBp91cPAv+sVlrNvLhGX/Z\nrGUu5pHYy9QkMl19/dUVEn+uP0orQ6Y/Cdl+zn/ycJ4E/wCxz0v/ANK4q+mP+Ct3/NP/APuLf+2d\nfM/7Of8AycJ4E/7HPS//AErir6Y/4K3f80//AO4t/wC2dfRYH/kmcX/ih+aPtcs/5IvH/wCKH/pU\nT41ooor50+LCiiigApVXc2z86bt+bNDLupR2AWkZc8GlpCd33KYC0UcAUUAHBFFFIq7aAFoop0XQ\n/Sp5gE2utJRS7RxUk8yBPvCrunrukGU3D+6tVkV+Plx81amhWvmXsSf8CoJP02/4IA+A3hs/il8W\npodm2Cx0a1mVP7zeZIv/AHztr781K4hW1eF32bX3bVr58/4JBeAZPh7+wPot/qttHFceMtcvNWuF\nZPm8lW8uJm/4Cte8X03zMibXX+63yqq/71ePWqOVWUSvY/aKkiwMRbRr80aM395tv+1VOZn+ZPJh\nZ4UbymZfmWnTaiib4Uh2/wAPzN/C1V7q6ka4MPk8bf8AWK/y1P2TeMfeKGpW/nbP3zfu/wC9WVqF\nmkyn73mfe8z+KtuOPzrhUeHKKm523/53VBdW8zQyTTfw/wAUbbttZz9odtHl1aOK1rTZ9zvCjb9/\nyx7fl21j3Ghr5Lpebc/LsjZa7iazW6Z0c/wfdVPvf8CrI1PTN1q/yNu2su1X+9tq+XmXmay2944L\nXPD/AJLC/wB7Db9yNfmrIvrfbGJkhkTsrL8u1a7W6t91v9pghXzVT51k+VlrCurSGS18lHVn3/3f\nvLR/ekYxqcvunJNpttZyNshZT95Wavtj/gmrZ/Yvgbq8XmK5bxbOxdTnJNra18f3lnbW1x/pKK0k\nm75mXau2vsb/AIJwwtD8DNS+fKN4omaLn+H7NbYr8P8AHaMVwPNr/n5T/NnzPGrT4fl/iifmtq2j\no1u9nNEzrN/rV/h3f7NfFf7UXhGz8L+LnSwtmTzpW83d92vvOSzmWaW285WVtzbv4q+X/wBtLwV9\nst016GHAZ2+7/s1+14GtH6zbmPsMwo+0wvOuh8s42SCbjj5vmq1bsjN5zyc/7NQybI5GR03f71LH\nGkbcPX0Udj51fCPuG3KNn/j1Ohg2qHG1m2VFu/eBHTdWgIUVd6Q5ZU+Ranl7CGLH5e1E+Zala4SH\nd5KN/wB9Uq2/mbkh/wC+qRbcx/7I2fMv8VApR+0VJFM3zuN5b+9T4YXX5Nn8X8NWreFNqoj/AMe7\n5kqaOHMjb0Xb/eq47Ey8zR8OW+66CI7Ou7+GvXfBt4mnqEdFKx/N81eZeEYUa6RPlU/wV6lpPh+5\n1CNHMPlBU+9/z0q+WEhS92B6D4X8daadPdPJVG+6i7PmrUXVk1JU+zWu/b8q7q8703w7fx3yoZpP\n4mbdXX6bcW3h/Sd91cqz7PlVm+bdR7sTnl7x4p+114bdWt9bSHbt+V2/vV4ZX0b8eLibxB8P73Up\ntu+Nlbb/ALNfOVKR3UZe4IwyOKWm5+7Tl+/+VI2Cl/g/Gm8Kv0paACnIu0YptSL94I9KWxMtyxCn\nmSYTb/vLXTeH7Xa29/l/3qwNLh+0SMmzYtdJNJ/Z+my3X3V8rbUGUuc57xdfPdao8O9cQ/L8tZNL\nJJ5kpkf+L5qI4/NbZ61obR92JoaFa+ZcB/m+ldLA3mbvnwf4lWs3T4fs1quxOW/iqeGR0/dpwrfc\nal8JzykW22SL5HTb822qizJGx8x/m+6i1fj/AHse9H52/wDfVU5oUti00yKxZ/k3fw0c32SY/CXr\nO4eTYPOwy/Ltq78m0om0Mv8AE38VYUeovHJl9rf7Natneboinyt8m77nzbqf2B/Z5hJIfOc7/wCL\n+Jvu1UVvvI7tlfu1o3UHmKiPDtDL/wCPVWkh8uTzkRTt/u0o7EjrRViYonyn+KtKzmtlbY824t/4\n7WWzQyDZs+Zv7v3t1TxxpHMN/wB+RKJbAacbFo9kKZH8VJ5kPl7+iLVWOT958m7cvy1MIZvkSHlG\n+81OPMHIWLeRF/jVv7lHl7h5zuy/71QLA8b7/O52bv8AdqzHcQtvfy9yt9+nzAYGvN5kjqeFj/8A\nHq4e++W6ft81drrkxkuJYdjKq/xN/D/s1xup83TcY+tTL4tDWnHlPpj/AIJhfFW6+Hnx7smiaMpd\nLsfzP738Nf0E/wDBJb4s37ftG614bv5t1rrmlqq7vlXzF/ir+Y74A+Nn8AfEnSvEiozi0v4ZXVf7\nu5d1f0PfsE69puoTaJ8Y9B1K6jt7O4Wd2j2/6ll/i/8AZa6KdSMYyTPIzOtLDVVP7J9rftbwQw/F\nCFoQvz6TEzFTnJ8yUf0r+Sfx/wCE9V+HvjbWPAmvIyXej6jNZ3C7dvzK3/oNf1bfGXxNF4s8Q2Wr\nQXn2mP8AstFjuAuBIvmSEMPzr+aT/go98MfE/wAOf2sPFVz4kRhNq2qTXW7ytn8W2vxTw1XP4i8W\nTXSrh/yrHz+STis2xC7tfqeE7gv33+X+H+KhZnLKjvtDVCsjyNvEeAv3KeqpI2wu3y/3q/Z+Y+v+\nEtNI+5t/3P7tfff/AAbm8/tq+KMfw/Cy9H/lS02vz/3Oy/O+1v8AZr9Af+DdFW/4bY8UMen/AAqy\n+x/4MtNr878V/wDk2+Z/9e3+aPKztWyms/I84/4LOyO3/BTD4lJs4X+xvm/7g1jXzRDdJtaSbhlT\nalfS/wDwWdZ/+HlnxLjHR20Yf+Uaxr5lt43ZdkKfKtexwD/yQmVf9g1D/wBNRLy7XLqP+CP5IvQz\nbsH+9/e+9UjXEy5VPuN99qgV3VWfyVLUjTIqhHfaZPl/4FX1p2RiXvMdlR0+UfxrvqzDN8xm8lXl\n+XYtVF+aRX8nPy/dWrkJ8tvJh2nd81TI2pxhGZcw6/6SkLNtT/V76uRs7Qr5gZd3/fVVFRNu9H2t\n/tVcFvuX/WY3J96uf3YnoU48pat5oY1XyNyfI2/d825qtQpCu1IUw7fw7arWscPkjhm/3atWak4K\nTNt+7tb+GseaZ2x5uXmRP9nf7OcP935fmpV2Qr8n3vvbaSDf86J/vf71OY3PmB4YW3Knz/PXQc9Y\nVmk8zzng+Rvlfa9TW8iRzK/2n5I0bcuymNC0IfznwG+43+zUkEky7Rv37fmfd92toxPExHx8shsk\n1s1uZvmXd/EqVQuoyJF2eYq7/uird1HuZdm1U/2fl+b+KqepSTbdnnb/APgH3avl5Tm5vsnPafev\nJMiQ8FW/1jV23h/XE8lkd9jL825f4a8u02abzF+dv95a6CzvgzB9+4158ZfzH0R7N4b8UeXHFvuV\n+Zf4fvf71dx4X1u2WcOkqpuX591eB+H/ABQlqu+YqpVPkZa6jRfHASZvMm3fPudW/iWolzSjoVHl\n+0fSXh3xNDJHGiPHsVVbds+81ddpWseZBKiJHs/56fxLXzjofxAbzBNNMzpu3RQ/3WrqtK+IlzJM\njw/Id/zs38S14uKjPm5kexg4xPaZPED2zLDpupRsrNtljb5mZf71Nm1aGa9DpDDlbfDbXb7v/wAV\nXndr4yeScv5yn+Hcv3m/2q0rPWnvo1fZsVW+fd8vzfw14lapy+9I+nwuHv8ACdW115qx3LvsK2/z\nq38P+9Ve4jcK+z96qt86slVLNk8s2yQswk+/N/eqz50z/Om5VV/lXf8AeWuD20paQPTjh6X2jntc\ntdyp+6+Vvlf5vu/7VcLrGl3MzSpbOp8ttu7/AOKr0XULX7RE0bwsgkfcn+9XMalY2saumxlddyyq\nsXzbq9PBS9vM8TMKMactjx3xho/l7vJ2qfNbzd33a898Sab5TPEX3BX+Rtle8a5ocLK7ujOm3b8y\n/wDj1ee+KPDbrumRFLLuVGb+7/dr6/C+9HU+IxUZc/wnlEmkzRzNC8K7q7b4f2sMl8qXj+X8mxd3\n+7UMmiwrOHdF37v4m+7XReDdLmWbf23rsWvYj7sDx6z7HZeHdN8ny2fyxt+VW/vV2vh2ztmsykaS\nHc+3dIn3lrH8Pwu0kcMI+dvu12Wh6a8d0zuikyLu/wB2uWQR93QrWenwiZtj7hJu31YhhSOGaG2f\nzZm2qjM+1dtaVxZu0zwvCuz7u5fu1FYWsNvumvF2Q/eaRk3bdtcdWnGWjOynLljzEniKzfwn4Tl8\nc3KKyw/urfcv3pP92voz/g4GRW/Ym0VpIDIq/EaxZlAzkfYr6vk/9qTVnb+xPDsbzfZPs/n+WrbV\nk+X5Wr63/wCC+8dxL+xHpyWgJk/4Tu12BRk5+w31fi3iDCMPEPhZf9Pa/wCVI+Yzip7TOMF25pf+\n2n45+JviFNofhs2ulPs3Lt2x15DeWuta3e/aphJI0jfxV1Ta9pv2iKHU+V3L5qt/6DXsfwu8ffs0\n6PCH8VeFbi8l8raixsq7f92v3OPKpXkfSS9rH4D5/wBN+HPiHULhE+xvhm27tlddL8ONF+H1n9v8\neSeTNs/0ezX5pJG/vN/dr174hftIfD3SbO4sPg98PbW2m8rbb3l187r/ALq/3q+bvFF14h8QatLq\nus3M000j7mkmatfaR2gKn7WWtQl1zxN/bV4ttDttrb+COH7tQMqbWS2/76rJWN9x+RhRHJcq2yN2\nqNfiNuX+UvJZlW+d1ct/eqwtvDCux32t96qEM0zN8/y7fldqvW7PMy/e2/3m/iqjOXulu3td0Y8z\nrXcfDXQ4Lq4abZ86xMyLt/irkbE2y/O78t/DXf8Age6/s2MO/wAiM3zs1KK5SeX2m4y88P21jm81\nKZlTzd27dXDazrU2u6t9gs5pPJjf5F/hWuh+JniIaxeyab4c3GST7+1/lVawrfwvqXhvw9N4hubZ\ni4X5G/u0x/DI5vxQ0J1hvI/hVQ/+9WbvX1p80jyuzzNlmfczVEy7aDoQ+iims2G49KBjqKKKXxAI\nq45NLRRR8QBRRRRyoBFXbS0qru5TpQy7TimAY249f4qlt4/3io/FRLwu+rOnIJJgnks5Zv4aXMiJ\nS5UftF/waW6JeeHfi18RfGGzamqeDZrJmZFZfLh2yfe/vbmr76+OUk2jeLnvHdvKml2QMqbVVq+P\n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\nf4dvzbf9mp4ftKr5zn5G/iV/vf71MwqR5veIpLXzJPkTcu7+L5adHbw/Nbfd/ubamkj8lmd02bfv\nfxUNb7pN6Ozf3G2bflropy+yeNiqc+a5VlRVjXcfl3Ns3VRvFRYWfYvzVpXSo2zzNrfN91X/AIqo\nXkKW8n7vbtk/hrXm933TljH3vePN45Nred5zbmf5Vq1Z3HmRs8yMPLXbu3/erN+0TSSI/ULVu1k3\nR/I7Lt/iavLj8J7cDZs7942CbF2qv8Lfd/3qvWd55LLMkzbv7yvWBZ3T+c1s6f6xd1aNo23CQx8f\nd2/xUvscpvTlzHYaT4keT5EmkLL92u28O6lqBVdki4k+Xa38Neb+H1fzn8yHd/wPbXa+G7ry23wX\nMaOrr95a8rGR/lPoMD71rno3h26m8zZNcsu1NsX93dXceHYnvJC/2zfKq7XXZuVq880O6RVHlou5\npV+0SSJub/gNeh+FJk/dI+5X3fJ5a181iKfLGXMfWYOXwo7HT4XkjR5uFZfkVU+XdWgsKJIsOxlP\n3k/2VqLw7bvHHF5w+Zfm2/3q6GOGZfnyrq3zeWv8NebDmjOx63LHl5jm76xSCJZrZFWRd37yR6wN\nQt/LtxNeW375nZlZW3fxV2OqadCzN/Au3d9zdtrH1i1hWEQ/ZlLqv3lX7y17WF/d7Hh5gubWxwmt\nW+63mTYvms+373ytXE+ItDtpoWTyVTzPu7fm216X4m0lLWTZND87fws23y65q+sYVt3hto2Mrfc/\nir6vCSjy8yPh8dHml7x5bfeH0SYPMm1N+7c33WWtrSdJTzNnkqWb5kb+Hb/DWvcaCk0m+aHYirtl\nVvu1Y0zT0hiDwoodv4v4dte7CXNC0j5TEaVbo3PD+lsix3LosW7/AMd/2q63TbObc3yW+9UVd275\nmrnNLaGHykdN275d0f8A7NXR6TIlwwS2dm3f+Pf7tYy/uii+UsrGLxTNlkRfllVfl27a5LxX4403\nWLi503RppGgsdqyxxy/6xv4v+BUfFv4jQeA/D8xs7mE39xEyRQr/AMs/l+9XnfwjM0Oj/wBq3nmF\ntUlZ4mb5d395qwlz850VJe6dd8ep31jwn4O8cwzMdP1rTt8X2hdzRsu5dv8As7dtfav/AAXekRP2\nP9BVxkN8RLQD/wAAL8/0r4K8Xak958F7/wADanqTNc+DdWmn07d/y0t5Pm2r/s195f8ABeJ4o/2Q\n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\n8k+827+8q197XEk0cJmMDf7v92vgc9xcqmM5Pso/QOHMv9nhPbS+0Zd5dFf9GmdX3S7E3N826s+4\nuHjLQ2ybv4n3fdq1fTPCsyJCwT5WfcnzbqqTL5jOmyOXdt/3vu/drxvby5/7p6lbCxqcyZPZw/MP\n9Tv/APQastH9li/f7RG3937y1nxslvMieS33dztv/iq4l1ugX7TDtT7zru+7XbTx/tDyamB5djPv\nvlaO58jcGfbtZvmZa5y8jtlhUuV3+a3y7/vbm+7urqdcuraSMzTP/HtXb/DXK6tdQq0mLzlfuLs/\n8er3sDiO54uOwzjuV7qSH7Pv6tG/yqv8P+zVZtReONv9Zuk+/UF5qVszF3diknzI38LLWHfaw8dx\n5KO2N+1vl+Va9unUj/MeBUjOJfvtWCyeT5zI+z/nr81YmratuJhCKr7t3+t3K1ZM18/nN9p+XdLt\n2r93bWXfX3l3bJ9pX/pkrf8AxVavYx5i1qF4dvmWyLG7L+92/Nur7d/4Je3C3P7P+rMu75fF9wp3\nHP8Ay62lfAc2sBtqXKbGbd8q/K+6vvL/AIJUTrP+z5rZRSAnjW5QEnOcWlmM1+J+P0Irw9m1/wA/\nKf5s+c4snfJmv7yPg+4vkhkEYGVVWZ/9lqoX11cx6bcu6ea/lf8AAv8AeamR3kNxMZn+VZNzbV+7\nHWX4svEs9Dub9LnY7Iy/K+35f7tfr06cef4T7CnW5YHy9+0V4sTRZpYV/wBdcKyozf8ALP8A3a8Y\n1SP7VHHc787k3bq3v2hPFH9ueMpIYV2xRt8nz1zml3D3Gm+S/wDDXr83LCNjhl73vFKNfKYps/jo\nkjG7e74q3JabUfYjMf49v8NQyL91Nmf9qtPc+Ikgb93j+KlhkdpN/nfL/dqCSR1U9/nqJpHVagqM\neY19Njea6XZNw38NbE2lu/8Aq0rntLvPs8yu74rqtL1y2lt/L+6f71V9ozlsZtxoT/O6I3/Aqrf2\nbeQuudu//ZrpPMT5f4v9mpo7e2Zf9R8y0+VBzGFpuqaxZ7U85lZX+Sum0fxtqsPyTBgWf52b5qzm\nghZd+xflf7rU5ZfJ+5D977lHLKIpSO90vULPWI/Jum8p5F2vIvytXSaVZa3bSRxWd+0oZNv3/l/4\nFXl+n/afOT+997czV634D1j+x9DfVdV+5t+Vf/ZaPhgTLl5uY8//AGlfC1zNpFtrY2sYfll2t93/\n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\nD5bP83ypudY/vbv71c3q1zi387exLbvmb+JlqTUvECTRvbIilpE+9G1YF9rkMjb03NJt/if5a9Wn\nzS5TyKnITX2qPNHHNDtbbF97+Ja/Qf8A4JKPv/Zx1rE/mY8a3PzZz/y52dfm0upQyfcdt3+y/wAt\nfoz/AMEe5PM/Zn1w7GXHjq6+93/0Oy5r8b+kCreHVT/r5T/Nny3FTvlTfmj89re58zZ9mm3LNK3y\n/wB2uW+LOqTQ+Gbn7G+3dFt/3a0obw28Z+8pbds2/wDoVeffFLxVDbtJps213mTd5bf7tftHLLmP\npoylI+UfHSvJrlxcv99pW+ZqoaNefZpmL/datTxtvk1iV3+4z7q59ZTFOrJ8wV91dEY+7ymkTp/J\nkjV38nG7+9WVfSPHhH3Y/wBmtCG8S6sU3zfe/u1mXnzbnR2Lf3ar+6Ry++U5Gy3u1RyY/g+7Ukkj\nswTYtRbTu+SpNIg29pPMd8GrFrqE0Lb/ADm2/wB2omhmYb/vUpt3X5O/+1Vf4gNyw8UOijem4f7V\nben+I3kZoU2ruriI43b5NjVdtfNjZZtjf7tLm5SZHZeZ9obfsVW+7tqeytd2Zsq/+zWPo94nkL87\nH/erb0+8QN5KJ97+Ja15uaJiafh3T/t1x9m2bPnVV3f3a6/4gf2lHpNtoltayBIYt0rf+g1zfhO7\nhj1KFLnanzbXZv8Aer1S+bTW0dtVSH7YWiVWVnp8xHNHnPCNem+z2svyYTZ8y7a84mYtMX2Y3V7n\n4/j8N6tapbQ2EltIy7vL+9Xj3iLw/NpVxvSFvKb5qj4fiNqcrmVSqz7tlJToVQSLv3UHSa/h218x\n/kHP8VWvGEwjjhs0udyL822p/DFskamZ3XGzd92sPXL57y/d96srP95aX2zHl5plMnzGrR0+aeO3\nOx/mrPjH7zD1s6SsKxsNn/AmqAkXtLvHe1MLvvdqbqU1zb7tnziordU8w+S/zLUupfvpxCjtv2f8\nBoI+H3kV9P1a5uG8n7v8PzVfurxLeNn2bf4dy1Hb2MNrGZKjvmSSEwvyfvfLWgub3x1vqW6RXeZc\nN/DWxYpuhlmhdii1ztvp73TLhPu11WgzPZ27o6KEZPmVaA+IzZL77L7q33qI7hJ1Pl7R/ElWtUsb\nZm3pG23ft+7VKPS3jmZN+0M+1Kr4hfEMXWE8zy3fO3+9WjDveH7T03fcrMt9JRm2fKSv3/7taMdw\n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\n", - "text/plain": [ - "" - ] - }, - "metadata": { - "tags": [], - "image/jpeg": { - "width": 600 - } - }, - "execution_count": 26 - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "ijTFlKcp6JVy", - "colab_type": "text" - }, - "source": [ - "Run `train.py` to train YOLOv3-SPP starting from a darknet53 backbone:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "Mupsoa0lzSPo", - "colab_type": "code", - "colab": {} - }, - "source": [ - "!python3 train.py --data data/coco_64img.data --img-size 320 --epochs 3 --nosave" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "0eq1SMWl6Sfn", - "colab_type": "text" - }, - "source": [ - "Run `test.py` to evaluate the performance of a trained darknet or PyTorch model:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "0v0RFtO-WG9o", - "colab_type": "code", - "outputId": "6791f795-cb10-4da3-932f-c4ac47574601", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 1000 - } - }, - "source": [ - "!python3 test.py --data data/coco.data --save-json --img-size 416 # 0.565 mAP" - ], - "execution_count": 0, - "outputs": [ - { - "output_type": "stream", - "text": [ - "Namespace(batch_size=16, cfg='cfg/yolov3-spp.cfg', conf_thres=0.001, data='data/coco.data', img_size=416, iou_thres=0.5, nms_thres=0.5, save_json=True, weights='weights/yolov3-spp.weights')\n", - "Using CUDA device0 _CudaDeviceProperties(name='Tesla K80', total_memory=11441MB)\n", - "\n", - "Downloading https://pjreddie.com/media/files/yolov3-spp.weights\n", - " % Total % Received % Xferd Average Speed Time Time Time Current\n", - " Dload Upload Total Spent Left Speed\n", - "100 240M 100 240M 0 0 17.9M 0 0:00:13 0:00:13 --:--:-- 20.3M\n", - " Class Images Targets P R mAP F1: 100% 313/313 [11:14<00:00, 3.02s/it]\n", - " all 5e+03 3.58e+04 0.107 0.749 0.557 0.182\n", - " person 5e+03 1.09e+04 0.138 0.846 0.723 0.238\n", - " bicycle 5e+03 316 0.0663 0.696 0.474 0.121\n", - " car 5e+03 1.67e+03 0.0682 0.781 0.586 0.125\n", - " motorcycle 5e+03 391 0.149 0.785 0.657 0.25\n", - " airplane 5e+03 131 0.17 0.931 0.853 0.287\n", - " bus 5e+03 261 0.177 0.824 0.778 0.291\n", - " train 5e+03 212 0.18 0.892 0.832 0.3\n", - " truck 5e+03 352 0.106 0.656 0.497 0.183\n", - " boat 5e+03 475 0.0851 0.724 0.483 0.152\n", - " traffic light 5e+03 516 0.0448 0.723 0.485 0.0844\n", - " fire hydrant 5e+03 83 0.183 0.904 0.861 0.304\n", - " stop sign 5e+03 84 0.0838 0.881 0.791 0.153\n", - " parking meter 5e+03 59 0.066 0.627 0.508 0.119\n", - " bench 5e+03 473 0.0329 0.609 0.338 0.0625\n", - " bird 5e+03 469 0.0836 0.623 0.47 0.147\n", - " cat 5e+03 195 0.275 0.821 0.735 0.412\n", - " dog 5e+03 223 0.219 0.834 0.771 0.347\n", - " horse 5e+03 305 0.149 0.872 0.806 0.254\n", - " sheep 5e+03 321 0.199 0.822 0.693 0.321\n", - " cow 5e+03 384 0.155 0.753 0.65 0.258\n", - " elephant 5e+03 284 0.219 0.933 0.897 0.354\n", - " bear 5e+03 53 0.414 0.868 0.837 0.561\n", - " zebra 5e+03 277 0.205 0.884 0.831 0.333\n", - " giraffe 5e+03 170 0.202 0.929 0.882 0.331\n", - " backpack 5e+03 384 0.0457 0.63 0.333 0.0853\n", - " umbrella 5e+03 392 0.0874 0.819 0.596 0.158\n", - " handbag 5e+03 483 0.0244 0.592 0.214 0.0468\n", - " tie 5e+03 297 0.0611 0.727 0.492 0.113\n", - " suitcase 5e+03 310 0.13 0.803 0.56 0.223\n", - " frisbee 5e+03 109 0.134 0.862 0.778 0.232\n", - " skis 5e+03 282 0.0624 0.695 0.406 0.114\n", - " snowboard 5e+03 92 0.0958 0.717 0.504 0.169\n", - " sports ball 5e+03 236 0.0715 0.716 0.622 0.13\n", - " kite 5e+03 399 0.142 0.744 0.533 0.238\n", - " baseball bat 5e+03 125 0.0807 0.712 0.576 0.145\n", - " baseball glove 5e+03 139 0.0606 0.655 0.482 0.111\n", - " skateboard 5e+03 218 0.0926 0.794 0.684 0.166\n", - " surfboard 5e+03 266 0.0806 0.789 0.606 0.146\n", - " tennis racket 5e+03 183 0.106 0.836 0.734 0.188\n", - " bottle 5e+03 966 0.0653 0.712 0.441 0.12\n", - " wine glass 5e+03 366 0.0912 0.667 0.49 0.161\n", - " cup 5e+03 897 0.0707 0.708 0.486 0.128\n", - " fork 5e+03 234 0.0521 0.594 0.404 0.0958\n", - " knife 5e+03 291 0.0375 0.526 0.266 0.0701\n", - " spoon 5e+03 253 0.0309 0.553 0.22 0.0585\n", - " bowl 5e+03 620 0.0754 0.763 0.492 0.137\n", - " banana 5e+03 371 0.0922 0.69 0.368 0.163\n", - " apple 5e+03 158 0.0492 0.639 0.227 0.0914\n", - " sandwich 5e+03 160 0.104 0.662 0.454 0.179\n", - " orange 5e+03 189 0.052 0.598 0.265 0.0958\n", - " broccoli 5e+03 332 0.0898 0.774 0.373 0.161\n", - " carrot 5e+03 346 0.0534 0.659 0.272 0.0989\n", - " hot dog 5e+03 164 0.121 0.604 0.484 0.201\n", - " pizza 5e+03 224 0.109 0.804 0.637 0.192\n", - " donut 5e+03 237 0.149 0.755 0.594 0.249\n", - " cake 5e+03 241 0.0964 0.643 0.495 0.168\n", - " chair 5e+03 1.62e+03 0.0597 0.712 0.424 0.11\n", - " couch 5e+03 236 0.125 0.767 0.567 0.214\n", - " potted plant 5e+03 431 0.0531 0.791 0.473 0.0996\n", - " bed 5e+03 195 0.185 0.826 0.725 0.302\n", - " dining table 5e+03 634 0.062 0.801 0.502 0.115\n", - " toilet 5e+03 179 0.209 0.95 0.835 0.342\n", - " tv 5e+03 257 0.115 0.922 0.773 0.204\n", - " laptop 5e+03 237 0.172 0.814 0.714 0.284\n", - " mouse 5e+03 95 0.0716 0.853 0.696 0.132\n", - " remote 5e+03 241 0.058 0.772 0.506 0.108\n", - " keyboard 5e+03 117 0.0813 0.897 0.7 0.149\n", - " cell phone 5e+03 291 0.0381 0.646 0.396 0.072\n", - " microwave 5e+03 88 0.155 0.841 0.727 0.262\n", - " oven 5e+03 142 0.073 0.824 0.556 0.134\n", - " toaster 5e+03 11 0.121 0.636 0.212 0.203\n", - " sink 5e+03 211 0.0581 0.848 0.579 0.109\n", - " refrigerator 5e+03 107 0.0827 0.897 0.755 0.151\n", - " book 5e+03 1.08e+03 0.0519 0.564 0.166 0.0951\n", - " clock 5e+03 292 0.083 0.818 0.731 0.151\n", - " vase 5e+03 353 0.0817 0.745 0.522 0.147\n", - " scissors 5e+03 56 0.0494 0.625 0.427 0.0915\n", - " teddy bear 5e+03 245 0.14 0.816 0.635 0.24\n", - " hair drier 5e+03 11 0.0714 0.273 0.106 0.113\n", - " toothbrush 5e+03 77 0.043 0.61 0.305 0.0803\n", - "loading annotations into memory...\n", - "Done (t=5.40s)\n", - "creating index...\n", - "index created!\n", - "Loading and preparing results...\n", - "DONE (t=2.65s)\n", - "creating index...\n", - "index created!\n", - "Running per image evaluation...\n", - "Evaluate annotation type *bbox*\n", - "DONE (t=58.87s).\n", - "Accumulating evaluation results...\n", - "DONE (t=7.76s).\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.337\n", - " Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.568\n", - " Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.350\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.152\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.359\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.496\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.279\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.432\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.460\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.257\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.494\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.623\n" - ], - "name": "stdout" - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "VUOiNLtMP5aG", - "colab_type": "text" - }, - "source": [ - "Reproduce tutorial training runs and plot training results:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "LA9qqd_NCEyB", - "outputId": "1521c334-92ef-4f9f-bb8a-916ad5e2d9c2", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 417 - } - }, - "source": [ - "!python3 train.py --data data/coco_16img.data --batch-size 16 --accumulate 1 --nosave && mv results.txt results_coco_16img.txt # CUSTOM TRAINING EXAMPLE\n", - "!python3 train.py --data data/coco_64img.data --batch-size 16 --accumulate 1 --nosave && mv results.txt results_coco_64img.txt \n", - "!python3 -c \"from utils import utils; utils.plot_results()\" # plot training results\n", - "Image(filename='results.png', width=800)" - ], - "execution_count": 8, - "outputs": [ - { - "output_type": "execute_result", - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAACvAAAAV4CAYAAAB8IQgEAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAewgAAHsIBbtB1PgAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzs3Xd0FNX///HXbkhCIKEHCIQaEkBB\naujVCnwoKiCiHwS/KoqoYPmpoAgKImBDlA+IIHxEsYEFRawE6VUIQSD0HkIIJRASQpL5/cFhPrsh\nuztpm0Sej3P2nLm7d+7cnXCY98687702wzAMAQAAAAAAAAAAAAAAAAAAAPAKe2F3AAAAAAAAAAAA\nAAAAAAAAALiekMALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAA\nAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAA\nAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAA\nAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAA\nAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcAL\nAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJ\nvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAX\nkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAA\neBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAA\nAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAA\nAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAK3fnz57Vs2TIt\n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\nde3aVWfOnDHfq1+/vvr166fatWvr3LlzWrZsmX7++WdlZmYqMzNTzz//vHx9fTVy5EhLx4iPj1fv\n3r114sQJlSlTRnfddZeaN2+u0qVL68CBA/rss8908OBBSVeW9x42bJi+/fbba9oJCwsztw8dOqT0\n9HRJUuXKlRUUFORUNzQ0NKenwjRz5ky99tprZtlut6tbt266+eabVbZsWe3fv19ffvml9u/frxkz\nZqhChQqW27506ZJuv/12rV692nyvUqVK6tOnj5o0aaLSpUvr8OHD+uabbxQTEyNJ+v3333X33Xdr\n6dKllpaFunjxovr06aPdu3erZMmS6t27t9q0aaOyZcvq2LFj+uqrr7R9+3ZJUkJCgh544AGtX7/e\n7bLfsbGx6tixoxISEsz3ypcvr549e6pJkyaqUKGCkpKStGvXLi1fvly7du1y28fExER16NBBsbGx\n5nuhoaG688471aBBA/n7+2vv3r36+uuvtX//fknS/PnzFRAQoA8//NDjOQAAOPNmbJEbN9xwg9q2\nbauGDRuqfPnySktL0/79+7VkyRLt2LFDknTmzBn16dNH27ZtU82aNbNt5+LFi7rrrruc4ppOnTqp\nS5cuCg0Nla+vr5KSkrR3715t3LhRGzZsUGZmZoG3ZUXt2rVVosSV28THjh1TamqqpCvX25zEGp4k\nJCSobdu22rdvn/le6dKl1a1bN7Vq1UqVKlVScnKy9u3bp5UrV+qvv/6y1K7NZlPz5s3Vpk0bhYWF\nqVy5ckpJSdGuXbv0ww8/mLHe4cOH1atXL0VHR6tMmTLXtHM13jt9+rR57kuWLKnq1atne9y8nJvi\nFAcDAIqfq/csJMnHx8dlvbS0NPXv31979+6Vj4+Punfvrk6dOqlixYo6deqUfvvtt2t+r+/du1cd\nO3bUiRMnzPciIiLUu3dvhYWFyW63a8eOHfryyy/NOhMnTlRgYKBGjRrltt8jRozQtGnTnN5r1aqV\nbrvtNtWoUUM2m00nTpzQxo0b9ccffzjFmLkRFxenAQMG6NKlS5KunKvbb79d7dq1U0hIiOx2u86e\nPavY2FitW7dO0dHReTqeo7feekujR482yz4+PurWrZu6du2qsmXL6uDBg/r666+1e/dus69dunTR\n+vXrne5RufPpp59qzJgxkqSGDRuqT58+qlu3ri5fvqwNGzbo888/V1pamiRp+vTpuv3229W7d+98\n+44AABSWzMxMp9/bvr6+buunpqbq1ltv1bp168z3goOD1adPH910000qVaqUDh8+rEWLFunvv/+W\nJP3yyy/q37+/fvzxR7dtf/755xo0aJAyMjLM98LCwtSzZ0+FhYWpdOnSOnXqlLZu3ao//vhDJ0+e\ntPQdg4KC1KFDB7Vs2VJVq1ZVQECATp06pQ0bNuiHH34w45vPPvtM1apV05QpUyy1C6CQFHYGMYB/\nNseZzUqWLGmkpaV55bhyGFXkbnT1k08+6VTX1Ww1V02cONGpvqsZhZmBFwBQXD311FNO159NmzYV\nyHEyMjKumX1t3Lhx2S47tGLFCqNixYpmPX9/f2P79u0u23aceezqrC3du3fPdtnklJQUo2fPnk79\n2LZtm9u+O85SZ+Uab3UG3iNHjhiBgYFm3fLlyxt//vnnNfXS0tKM4cOHO32/qy93M709/fTTTnWH\nDRtmnD9//pp6mZmZxpQpU5zqzpgxw2W7jrPaXO1Py5Yts+1Lenq68eijjzq1/f3337tsOzU11Wja\ntOk1/T537pzLfTZv3mz069fPOHToULaf33333WZbNpvNePXVV7MdgX7p0iVj5MiRTsdeunSpy+MC\nALLnrdjCMKzPwHvfffcZjz/+uNt4wjAMY968eU4zst1zzz0u686ZM8esFxAQYPz+++9u246LizNe\ne+21bGf2zc+2DCNnqwFkncHVE6sz8GZmZhrdu3d3qtu3b1+3s77GxsYaDz/8sLFq1apsP+/SpYsx\nevRot/FPenq6MXnyZKeZ555//nm33yk3y18bhvUZeItzHAwA8K7cPCNISEhwuu517drV6XPH65xj\nfOBqVllHly9fNlq1amXu5+fnZ8ycOTPba1hSUpIxYMAAs66vr6/b68wXX3zh1KcaNWoYy5Ytc1k/\nKSnJmD59uvHSSy9l+7mVGXjHjBlj1gkODvZ4Dvbv3288++yzxq5du7L93GoMER0dbfj6+pp1q1Sp\nku2Kj+np6caoUaOczkvHjh2NzMzMbNvNGovY7XbDx8fHmDZtWrZ/o61btzotv92sWTO33x8AgMKQ\nm3jozz//dNqnZ8+ebutnzRl54oknjAsXLlxTLyMjw3jjjTec6n700Ucu242NjTVKly7t9Jv+ww8/\nzPa6bBhXYq3vvvvOGDBgQLafb9myxWjcuLGxYMECt7P/Hj161OjUqZNTTOAqfrmKGXiBwkUCL4AC\n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\nKysJdu/eXdOnT/e48uCePXs0btw4l0mv/v7+TjPexcfHq2PHjlq+fLnLNpOTkzVz5sw8DfStV6+e\nhgwZolWrVrkdWLRz506n5OVWrVo5JRzn1IQJE8zVKdLT09WrVy+tW7fumnoZGRl65ZVXNGPGDPO9\nTp06Oc0UCAAAXHv22Wfl5+dnlrObhbdp06ZOE4k8//zzeuqpp3TmzBm3bSckJGjmzJm68cYbtXHj\nxmzrvPPOO+Yzn8zMTPXp00cfffSRyxWCMjIy9OOPPzpN9nLVbbfdZm4nJibqoYceyvZ+2qVLl/TC\nCy9oypQplu+DACh8JQq7AwCuH35+fvr444/VunVrjRs3TidOnJB0JYhYtmyZli1b5rENm82mvn37\navLkyU5LKufFgAEDdOnSJT388MPmjaaoqCiXs94FBQXp+++/V9u2bT22HRgYqFWrVumee+7RH3/8\nIenK912yZInHGWJuvfVWffnll05LOwAA4C02m01fffWVhg4dqnnz5km6MvjmmWee0ZgxY3TzzTer\nRYsWCg4Olr+/v+Lj43X48GH9+uuvOnDggMf27Xa75s6dqzZt2pg3Ql555RV9/vnn6tevn2rVqqVz\n584pKipKS5cudUpemTRpklPSxj9FaGio3nzzTQ0bNkzSlfPdpUsX9ejRQzfffLPKlCmjAwcO6Isv\nvtC+ffskXUnEtZrEMWnSJMXExJijvP/zn/9o3rx56tatmyIjIxUcHCxJOnv2rPbu3astW7Zo06ZN\nbhOHCpqfn5+++OILdejQQSdPnjT7/cUXX6hnz55q2rSpypcvr6SkJO3evVt//vmntm/fLkmaPHly\ntm1+/PHH2rt3r6Kjo5WRkaFx48bpvffeU7du3dS8eXNVqFBBGRkZOnPmjGJjY7V582ZFR0d77TsD\nwD9VQccWVj3//PPm7/Hk5GTdfPPN6tWrl7p06aJy5copISFBUVFR+uWXX5SZmalq1aqpd+/emjlz\nptt2MzMz9d133+m7775TpUqV1L59ezVv3lyVK1dWQECAEhMTtWnTJn3//fe6ePGiud/kyZOveaCS\nn20VJXPnzlW7du20Z88eSdLChQu1dOlS9ejRQ61atVLFihV18eJF7d+/X6tWrTJXJ7r33nuvaeuF\nF17QAw88IOlKkk+LFi3Ut29ftW3bVqVLl9bx48f166+/asWKFZKkxo0bq0GDBvr666899rN69eq6\n7bbbzJhpypQpmjZtmmrXri1/f3+z3mOPPZarGfCIgwEAxZWvr6++/vprtW/fXocPH1ZKSoqeeOIJ\nvf766+rWrZsaN26s8uXL69KlSzp9+rR27NihjRs3KjY21mPbffv21ciRIzV16lRJV1Yr7Nq1q1q3\nbq3bb79doaGhstvtOnHihDZv3qzffvtNycnJGjx4cK6/T3p6uv773//qv//9r6pXr6727durSZMm\nqlSpknx9fXXy5EmtXbtWS5YsMVfjsdlsmjJlSq6PKUk33XSTJk6caK70cOLECXXo0EE9evRQ165d\nVaZMGR06dEhfffWV07mrUKGCPv74Y3OgEQAAcK969er697//ba5qs3jxYm3ZskXNmjVzqvfmm29q\n+/btZj7H+++/r48//lh33HGH+ezEMIxrnp24SsS9ql69epozZ47uu+8+ZWRkKDU1VUOHDtXkyZPV\nq1cv1atXT6VKlVJiYqK2bdum33//XXFxcQoLC7umrTZt2qhTp07mfY4vv/xS69ev14ABAxQREaG0\ntDTt2rVLixYtMichGTdunF555ZU8n0cAXmAAQCG4ePGi8e677xpt27Y1SpQoYUhy+fLx8TGaNGli\nvPbaa8ahQ4cste+4/+DBgy3ts3PnTqN3794u+1OyZElj8ODBxrFjx3L8fTMyMoyvv/7aaNOmjWG3\n211+V7vdbrRp08ZYuHChkZmZmePjAABQED744AOjUqVKbq/Xrq5rDz30kHH8+HGXbW/ZssWoUqWK\npfZsNpsxZcoUj/3t3Lmzuc/YsWMtfceoqCinY7lTq1Yts97cuXM9tj137lyzfq1atTzWHzNmjKXz\nMXz4cOPAgQNO7x04cMBt22lpacbQoUNz/LeUZKxYsSLbNgcPHpzjuCun/d67d68RERGRo/66a/P8\n+fNG7969c3UerMajAADXCiq2cKwbFRXl8vivvvqqpeMFBwcb69atM8aOHWu+17lz52zbdIwPrMY1\nEydOLPC2DCNnsUhO46icxFCGYRgnT540WrdunaPv5+pv+X//93+W9q9bt66xZ8+eHMUs+/btM2rW\nrOm23aznJ6fxTXGMgwEA3uV4DfcU31hlJa7x5MSJE0bbtm1zFct5Mm7cOLfPULK+XF3TrVz3c9p/\nPz8/45NPPnHZ95ye24kTJxo2m83SsUNCQoxt27a5bS+nschVubmvAwCAt+Q1Htq1a5dTbNGnT59s\n66WlpRkPPfRQjuMDScaaNWvc9mHx4sVGYGCg5fbCwsKybefw4cNG9erVLbXx0EMPGWlpaU7vrVy5\n0mUfHdudP3++y3rt27c3640fP97t9wZgXdGdkgHAP1pAQIBGjhypNWvW6PTp0/r99981f/58TZ06\nVRMmTNC0adM0f/58rVixQufOndPWrVs1ZswYl0ssZWUYhvm6OrOPJw0aNND333+vhIQEffvtt/rg\ngw/0+uuva8aMGfrpp5+UmJioefPmqVq1ajn+vna7Xf369dPatWuVmJioJUuWaNasWZo0aZImTZqk\nWbNmacmSJTp16pTWrl2rvn37MooaAFBkDB8+XPv379frr7+uZs2aebxG1ahRQy+88IJ27typ2bNn\nKyQkxGXdpk2baufOnXrqqacUFBSUbR273a6uXbtq/fr15uwk/2SvvfaaFi9enO0oa0mqWbOm5syZ\n47S8pFW+vr768MMPtXbtWvXo0cNp+ajs1KtXT08++aQ2bNigjh075vh4+SUsLEzbtm3Tm2++qRo1\narit27hxY7399ttuY7bAwEB9//33+umnn9SxY0ePsxU2atRIL774onbu3Gk5HgUAuFaQsYUVr7zy\nij799FOX1xR/f38NGDBA0dHRat26taU2p0+frsGDB6t69epu69ntdt1xxx1as2aNRo0aVeBtFTXB\nwcFas2aN5syZo4iICLd169Wrp3Hjxl0zM85Vs2fP1rvvvquKFStm+3lgYKAeffRRbdmyRfXq1ctR\nP+vWravo6Gi99dZbuuWWW1S1alWVLFkyR214QhwMACiuqlSpolWrVmnBggUur9NX2e12RUZGavz4\n8ZZWVRg7dqz++usv9ezZU76+vi7rBQUF6b777tNTTz2V4/5f9emnn+qee+5RpUqV3Nbz8/NTv379\ntHXrVg0aNCjXx8tq1KhRWrt2rbp06eIyHi5TpoxGjhypHTt2qHHjxvl2bAAArhf169fXXXfdZZa/\n//57bdmy5Zp6vr6+mj17tlavXq1u3bq5jUMkKTw8XE899ZQ2bdrkceXmXr16ac+ePXrsscdUpkwZ\nl/V8fX1166236q233sr28xo1amjTpk3q16+fy9ghIiJC8+fP1+zZs8k3AYoRm2EYRmF3AgAAAEDx\nkZCQoI0bN+rkyZM6deqU0tPTVa5cOYWEhKhFixYKDQ3NVbtpaWlauXKl9u/fr1OnTql06dIKCQlR\n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\n115J1k6/tb8mhTkdqvBIFUakDEP60pui27xz1Ts6XMeLj+mk26uTRlWBcMvtg7kAACAASURBVHWM\nKlWUujgNTTmrj/7tol9ZGaruLsoNfc+hJC0tzcodOTk5uvjiixtsW1hYaD3qOT4+XnFxcUEzZlsa\nmDZK//zh/2p4zlxbi3grTafuqbytqpDdRg5Deqo5/7YAAKCDkFNaryqnPK70nPvkMpryjJDGeUyH\n7q683faMIrXgM1AAANpRaP+0DACAzqqpj7purM1PX0lbnpW+XdXix2UDAICONTk9UYPiY+oV59R8\ndDfal8fj0fz5863XS5YsqVVIW+3xxx/XP/7xD+Xm5mrTpk368MMPdcUVVwTEmE8++aSOHz8uqarw\nt2bxbrVRo0bpkUce0T333CO326358+frrbfeatH8AQC1NVQM3Nwi4dbuju9vR+K686jbtu7r6l2H\nfRUn/2Zkcr3diKX6RctSVeFwF4dDFV6v8opO6NXsvVq9rUBmnQw0OCGmwYJjX4XJ1X36+n/kaxdl\nX99jKJkwYYKeeOIJSdKaNWt03333Ndh29erV1nFGRkZQjdnWRv76Fv2r31k68vH/q2HH/qFIo1Km\nKRmnLsHmHJebYVrlveCXXaht4nQYujglTndfnsK/LQAAQYGcYo/qnHL8fx9WWtmn1lMsmptV3KZD\n673peso9zfbi3XCXQ78+qw+fgQIAApphmqY9t8Og1fbt26fk5GRJUn5+vpKSkjp4RgCATsHrbfxR\n1421aUofzcCaF1z4/QKAziOUd4FrqvZY99avX69LLrlEkjR27Fht2LChwbavvfaabrrpJklSZmam\nXnvttYAYs3///vrhhx8kSXv27NGAAb4fQVhcXKzevXvrxIkTOu2001RUVKTIyMgWfQ++kFMAAE3R\nGTJQsK15Ho9HSUlJOnDggCTp888/14gRI3y2GzlypHJzcyVJa9eu1fjx44NmzIa0xe+X1+NReVmJ\nunSJVHlZiSQpIjK6acflpVJYpCLCwlTurtrNN8LltOW45q7TAIDQRE4JzDEb0lY5pbTkZ0nNyCfV\nx1FdVe6pKluyK59EuJwN3nwHAAgdwZJRWl+B04ZWrlypadOmqX///oqIiFB8fLxGjx6tJ554wtrl\nxQ7FxcVavny57rjjDo0ePVpxcXEKCwtT165dNXjwYM2YMUNr164Vtc4AgKBU/ahrf4W3jbVpSh8A\n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\nBEGAIAgICQkp9zZnz54Vn8/Ozoajo6P5F6Hh5ZdfFuMJgoARI0bo7YcgCGU6FxEREVUd06dP15oD\n9OrVy+IxzX0Q0bNDIvBfNRGVUUFBAc6ePYvIyEikp6ejdu3aqFevHnr27AkXF5eK7p7JHj16hAsX\nLuDBgwd4+PAhlEolnJ2dUbt2bTRr1gz+/v6ws7Mrt/6kpqYiLCwMycnJePr0KerUqQMfHx90797d\nIh/YpKam4uzZs0hJSUFaWhpkMhlcXV3RqFEjdO7cucxvdBERUeX0rIzbSUlJiIiIgEKhgEKhgEQi\ngYuLC+rXr48OHTqU+ks2T58+xcmTJ3Hnzh08fvwYzs7OqF+/PoKDg6vU/bEUlUqFkydPIi4uDunp\n6fD29oavry+CgoIsdo60tDSEh4fj/v37ePToEeRyOVxcXNCsWTP4+fkZTJatKGq1GhcvXkRMTAwU\nCgXy8/Ph4uICHx8fBAYGmp2gAwApKSn466+/xLmZnZ0dXF1d0bx5c/j5+VXL3z8iqho4tygbpVKJ\n8PBwxMTEICsrC3Xq1EGDBg0QHByMGjVqlDrujRs3EBsbizt37iAjI0O8nhYtWqBDhw5mJSBbMlZl\nFBUVhYiICDx48ABKpRJOTk5o0qQJAgICdCbu6pKZmYmwsDDcuHEDOTk58PT0RKNGjdCzZ0/Y2NhY\n+Qosg/NgIiIiIiIiIiKi8scEXiIiIiIiIiIiIiIiIiIiIiIiIiIionJkeK9SIiIiIiIiIiIiIiIi\nIiIiIiIiIiIisigm8BIREREREREREREREREREREREREREZUjJvASERERERERERERERERERERERER\nERGVIybwEhERERERERERERERERERERERERERlSMm8BIREREREREREREREREREREREREREZUjJvAS\nERERERERERERERGRxalUKkRHRyMkJASvvPIKunTpgho1akAikUAikWD69OlWO/e+ffswduxYNG7c\nGPb29vDw8EDXrl3xySefICMjw2rnJSIiIiIiIiIylbyiO0BERERERERERERERETPnnHjxmHXrl3l\nes6srCxMmjQJ+/bt03peoVBAoVDgzJkzWLNmDXbs2IHOnTuXa9+IiIiIiIiIiDRxBV4iIiIiIiIi\nIiIiIiKyOJVKpVV2dXVF8+bNrXq+sWPHism7np6eWLx4MbZs2YKvv/4a3bp1AwAkJSVhyJAhiI2N\ntVpfiIiIiIiIiIiM4Qq8REREREREREREREREZHEdO3ZE69atERgYiMDAQDRp0gQhISGYMWOGVc63\nbt06HDp0CADg6+uLY8eOwdPTU3x97ty5WLBgAVavXo20tDS8+OKLCAsLs0pfiIiIiIiIiIiMkQiC\nIFR0J4iIiIiIiIiIiIiIiOjZp5nAO23aNISEhFgkrkqlQoMGDZCcnAwA+PvvvxEQEKCzXocOHRAR\nEQEAOHz4MAYMGGCRPhARERERERERmUNa0R0gIiIiIiIiIiIiIiIiKouwsDAxeTc4OFhn8i4AyGQy\nvPrqq2J569at5dI/IiIiIiIiIqLimMBLREREREREREREREREVVpoaKh4PGTIEIN1Bw8erLMdERER\nEREREVF5kld0B+gfSqUSUVFRAAB3d3fI5fzxEBHRs6mgoAAKhQIA4OfnB3t7+wruERnCOQoREVUn\nnKdULZynEBFRdcE5inFFcwIACAoKMljXy8sLDRo0QFJSElJTU6FQKODu7m6xvnCOQkRE1QnnKVUL\n5ylERFRdVJU5CkfiSiQqKgodO3as6G4QERGVq/Pnzxv9UIUqFucoRERUXXGeUvlxnkJERNUR5yi6\nxcXFicdNmjQxWr9JkyZISkoS25qTwHv37l2Dr0dERGDYsGEmxyMiInpWcJ5S+fG9FCIiqo4q8xyF\nCbxERERERERERERERERUpT158kQ8rlOnjtH6bm5uOtuaokGDBmbVJyIiIiIiIiLShQm8lYjmt7vP\nnz8Pb2/vCuwNERGR9SQnJ4vf7rXk9oRkHZyjEBFRdcJ5StXCeQoREVUXnKMYl5WVJR6bsi2mg4OD\neJyZmWmVPgGcoxAR0bOP85Sqhe+lEBFRdVFV5ihM4K1E5PJ/fhze3t6oX79+BfaGiIiofGiOf1Q5\ncY5CRETVFecplR/nKUREVB1xjlLxkpKSDL6u+SEh5yhERFSdcJ5S+fG9FCIiqo4q8xyl8vaMiIiI\niIiIiIiIiIiIyASOjo5IS0sDACiVSjg6Ohqsn5OTIx7XqlXLrHMx0YWIiIiIiIiILEFa0R0gIiIi\nIiIiIiIiIiIiKgsXFxfx+OHDh0brP3r0SGdbIiIiIiIiIqLywgReIiIiIiIiIiIiIiIiqtJatmwp\nHicmJhqtr1lHsy0RERERERERUXlhAi8RERERERERERERERFVaX5+fuLxhQsXDNZNTU1FUlISAMDD\nwwPu7u5W7RsRERERERERkS5M4CUiIiIiIiIiIiIiIqIqbdCgQeJxaGiowboHDx4Uj4cMGWK1PhER\nERERERERGcIEXiIiIiIiIiIiIiIiIqrSgoOD4eXlBQA4ceIELl26pLOeSqXCV199JZYnTJhQLv0j\nIiIiIiIiIiqOCbxERERERERERERERERUaYWEhEAikUAikaBXr14668hkMixZskQsT506FQ8ePChR\nb9GiRYiIiAAAdOvWDQMHDrRKn4mIiIiIiIiIjJFXdAeIiIiIiIiIiIiIiIjo2ZOYmIj169drPXfl\nyhXx+PLly1i8eLHW63369EGfPn1Kdb5Zs2Zh9+7d+OOPP3D16lX4+/tj1qxZ8PX1xePHj7F161aE\nh4cDAFxcXLB27dpSnYeIiIiIiIiIyBKYwEtEREREREREREREREQWd/v2bXzwwQd6X79y5YpWQi8A\nyOXyUifwyuVy/Pbbb5g4cSJ+//13pKSkYPny5SXq1a9fH9u3b8dzzz1XqvMQEREREREREVmCtKI7\nQERERERERERERERERGQJtWrVwv79+7Fnzx48//zzaNCgAezs7FCnTh106tQJq1atQnR0NLp27VrR\nXSUiIiIiIiKiao4r8BIREREREREREREREZHF9erVC4IglDnO9OnTMX36dLPajBgxAiNGjCjzuYmI\niIiIiIiIrIUr8BIREREREREREREREREREREREREREZUjJvASERERERERERERERERERERERERERGV\nIybwEhERERERERERERERERERERERERERlSMm8BIREREREREREREREREREREREREREZUjJvASERER\nERERERERERERERERERERERGVIybwEhERERERERERERERERERUZWmVgvIziuAWi1UdFeIiIiICADU\naiDvaeF/SSd5RXeAiIiIiIiIiIiIiIiIiIiIqDRi7mdgXXgCQqNSkJOvgoONDIP9vDCze1P41nUC\nUJjcqyxQwVYqhbJABQCoYSuHVCrRet1eLhOfKyt9MU05V1EycvF+EhEREVUJKVHAmW+AmL1AfjZg\nUwPwHQF0mQt4+VV07yoVJvASERERERERERERERERERFRlbM34h7m74hEgcaquzn5Kuy6dA/7Iu7j\njf4tEK/IwoErycgt0F75TSoBAhrWhpODDc7cfKQ3+ddcxROK7eVSDGrjiR7NPXA6/iFCo/UnGsfc\n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\niIhIaPJW+uYswYR3AbxuOLzHN7/x7xuBm4laie32RQzmoyorSNSn1I6mnKj6G0bADy/pEXJ4t/lV\nm7TbqsArrdlV0yHvpcD/MJpO312cIiIiIiIiItIsrrzySgYMGMBll13GZZddRp8+fViyZAk/+tGP\nIt7XRRddFFSIdvXq1f7wbnJyMkOHDq13n8GDBzN27NgGj7EtqRHg/dbdTCMRERERkbbAsuwqS9ma\npsHo1ERW7TrY3EOr1wDjc6Y4sxltbifOOIXH9gUJnIYVVuWyVsnywLYFvgqylUUqjBpKldz6VA/h\nqniUiIhI21ecF0YA1/bNb666q92Fd922g9+6bwdgWdRDdDaCm4dlW9/BpvHnSg7TYPLQPo3eT6TZ\n1QO8qAKvtGaJqb6lWOr6B9J0+l6vWIJFRERERERERJrc7Nmzm3sINTzzzDP+7WCq70rtzj7LVeWx\nKvCKiIiISDjyi0pYlPMp6/OKKXN7iXU5GJ2ayIjkBI6XtvybxMaY75DlWlilMpnTOFNJq12Edyvk\nr4GM+Y0TcA2lSm59agvhqniUiIhI27ZtfngB3Pw1viqp7Si867FNZrp/wl77fAD22efzXWNvvfu5\nbQeLPaMbe3iYBszNTCOlR8dG7yviqn05MFSBV1q91Im+pVje+C188uaZ5w0nTN0E3S9ptqGJiIiI\niIiISMtz6NAh1q9fD4DT6eS2225r5hG1XjUq8CrAKyIiIiIhWpt7kJkrduOxzlSeKnN7WbXrYKup\nvFs9vNuuuUt9lXIjUXG3ulCq5AY8Th0hXBWPEhERabssC/LXhrevuxT2hrqvQXNWVg13BQjbhu3W\nRfzWc7s/vAtQYtc/t3Pbjiqh38ZgGjDiogRmXJfcOsO7AEb7XslBAd62KjEVbsiC/0s785ztgc69\nmm9MIiIiIiIiItIiPffcc3i9vovrP/zhD0lMTGzmEbVeNQK837qxbRujXZUYExEREZFw5ReV1Ajv\ntha/uj6ZhzfsZ4ozW+Hdylxxvkq5jSWYKrmG6UusWLX8XOoL4VYUj9q2wFdtz13qe08pY32hX4V3\nRUREWidPWfhV/J2x4C4Lvn3cuZD+Z1g1tdmq9hpGgBCv6YTh98PRA/75jseM4VX3ZfzVk06+3adK\nc6dpcE6XBDhWe1+ldjTZ1ndY7BkdkfDuyh9fxbLthWTnHaLM7SXGaTIypRu3DenN4PPOxjRb+7nn\n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\nhNtrjG2pTu/qyvzNiYfn7/766B5TNDB27Nhi7li+fHk++9nPNtl3/fr1qaurS5IMGTIkgwcP7jJz\ntre/+puv5/8cdWLe+eX/n0+8+6v0rdh+ADdBV//lJujJJb9197NjBuc7nx/TY/Y3AF2bnFIau3PK\ne//rf2Tstv/Y57do7G97R6Eyi3eelFt3TC1pRknSI3M4AF2PAl4AAACAMmpoaMj1119ffH3//ffv\nVUi720033ZRf/epXWbFiRZYuXZonn3wyZ511VqeY8/vf/37ee++9JLsKf/cs3t3t1FNPzQ033JAr\nr7wyO3bsyPXXX58HH3ywTesHoGWVlRXpd9Cub/lXZ1eRb2tu//1ou61j7C4o3rmzUCwo7ohC4s4y\nxoc7d6ZPdVUqKyvSk5xzzjm5+eabkyQLFy7M1Vdf3WTfJ554otiePHlyl5qzHEaPPTWjx87PzoaG\nbN22JQcd1Df127YkSfr07b9/7fqtSa++Ob9Xr5xzAF8HjbX7HVTd4/Y3AF2bnFI6o8eemoxdlJ0N\nDdmy5c9JWpFPdrf7DchnGgr5eUqXT3pyDgeg6/H7rwEAAADK6JlnnsnatWuTJBMnTsz48eMb7VdV\nVZUrrrii+HrevHmdZs758+cX29/+9rebnHfGjBk5+OBdv8VhwYIF2bZtW6vXDkDXtLuguLq6Mv37\n9Er/Pr3a1O7qY/TU4saJEydm2LBhSZIlS5bkxRdfbLRfQ0NDbrvttuLradOmdak5y6myqir9+h+S\n6oMOSv9DDk3/Qw7d//aAgenft/cBfx001u6J+xuArk1OKb3KqqrW55Pd7V7VJc8nPTmHA9D1dOoC\n3gULFmTq1KkZNWpU+vTpkyFDhmTChAm5+eabi7e8lMLmzZvz8MMP5/LLL8+ECRMyePDg9OrVKwMG\nDMhxxx2XSy65JIsWLUqhUCjZnAAAAEDPtHDhwmK7pZtUzj333Eaf68g5f/e73+WNN95Ikhx//PE5\n+uijmxyrpqYmp59+epLk/fffz69//etWrRsA6JqqqqoyZ86c4utLLrkkGzZs2Kff7Nmzs2LFiiTJ\naaedlrPPPrvR8e69995UVFSkoqIikyZNKsucAED3JKcAAJ1JdUcvoDFbtmzJxRdfnAULFuz15xs3\nbszGjRvz3HPP5fbbb89DDz2UU0899YDmuvXWW/O9730v9fX1+7y3efPmrF69OqtXr87999+f008/\n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\n8CxevDjHHnvsfj1vn0H34muQcnB2sD9kFOCjfB3S3pwd7C85BSglX8OUkjOGPckswIHwNUspOVP4\nKDmFnkwBbycxceLEDBs2LEmyZMmSvPjii432a2hoyG233VZ8PW3atLKsj+7jy1/+crF96623Ntnv\nRz/6Ud5///0kyXnnnVe8Hr6psebOnVvs/1F/+tOf8tBDDyVJ+vbtmylTprRp7ZTH5ZdfXgxFw4YN\ny+LFi/Pxj3+8VWPYZ9B9yCiUi7ODlsgowEfJKZSDs4P9IacApSTjUGrOGHaTWYADIaNQas4U9iSn\n0KMV6DTuuOOOQpJCksIJJ5xQWL9+/T59rrrqqmKf0047rQNWSWdyzz33FPfDpZdeul/PrF+/vlBT\nU1NIUqisrCw8+uij+/R5/vnnC/369SskKVRXVxdWrVrV5Hhf+tKXimv4yle+Uti+ffte72/evLkw\nceLEYp/vfe97rfocKa/LL7+8+Hc1bNiwwiuvvNKmcewz6F5kFFpLRqHUZBSgKXIKrSGj0B7kFKA9\nyDg0RZ6hrWQWoBRkFJoio3Ag5BR6uopCoVBovsSXctmxY0cmT56cp556KsmunyiYMWNGamtr8847\n72TevHl59tlnkyQDBw7Ms88+mxNOOKEjl0wZrVmzJnffffdef/bb3/42jz32WJLkxBNPzN/+7d/u\n9f7nPve5fO5zn9tnrPvuuy/Tp09PklRWVmbatGn5/Oc/n6qqqixbtiz33Xdf6uvrkyQ33nhjvvvd\n7za5rj/96U859dRT8+abbxbXMX369Bx++OF5/fXXc9ddd+X1119Pkpx00klZunRp+vfv37b/EWhX\n1157bW688cYkSUVFRf7lX/4lxx13XIvPjR8/vvirCPZkn0H3IaPQHBmF9iajAM2RU2iKjEI5yClA\ne5FxSOQZSkdmAUpFRiGRUSgtOQXiBt7O5r333iv8zd/8TbE6v7GPESNGFJYtW9bRS6XMFi9e3Oy+\naOzjuuuua3K8O+64o9CnT58mn62qqirMmTNnv9a2cuXKwnHHHdfsWiZMmFBYu3Ztif7XoD3s+ZNB\nrfm45557mhzTPoPuQ0ahKTIK7U1GAVoip9AYGYVykFOA9iTjIM9QKjILUEoyCjIKpSSnQKFQHTqV\nmpqaPPbYY3n00Ufz05/+NMuXL8+GDRtSU1OT0aNH58ILL8zMmTNzyCGHdPRS6eK+8Y1v5Mwzz8yd\nd96ZRYsWpa6uLjt37szhhx+eM844I1//+tfzyU9+cr/Gqq2tzW9+85vcfffd+fnPf55XXnklmzZt\nyqBBg3LiiSfmoosuysUXX5zKysp2/qzobOwz6D5kFMrF2UE52GfQvcgplIOzg3Kx14DdZBxKzRlD\nKdlP0HPJKJSaM4VSs6foaioKhUKhoxcBAAAAAAAAAAAAAD2F8m8AAAAAAAAAAAAAKCMFvAAAAAAA\nAAAAAABQRgp4AQAAAAAAAAAAAKCMFPACAAAAAAAAAAAAQBkp4AUAAAAAAAAAAACAMlLACwAAAAAA\nAAAAAABlpIAXAAAAAAAAAAAAAMpIAS8AAAAAAAAAAAAAlJECXgAAAAAAAAAAAAAoIwW8AAAAAAAA\nAAAAAFBGCngBAAAAAAAAAAAAoIwU8AIAAAAAAAAAAABAGSngBQAAAAAAAAAAAIAyUsALAAAAAAAA\nAAAAAGWkgBcAAAAAAAAAAAAAykgBLwAAAAAAAAAAAACUkQJeAAAAAAAAAAAAACgjBbwAAAAAAAAA\nAAAAUEYKeAEAAAAAAAAAAACgjBTwAgAAAAAAAAAAAEAZKeAFAAAAAAAAAAAAgDJSwAsAAAAAAAAA\nAAAAZaSAFwAAAAAAAAAAAADKSAEvAAAAAAAAAAAAAJSRAl4AAAAAAAAAAAAAKCMFvAAAAAAAAAAA\nAABQRgp4AQAAAAAAAAAAAKCMFPACAAAAAAAAAAAAQBkp4AUAAAAAAAAAAACAMlLACwAAAAAAAAAA\nAABlpIAXAAAAAAAAAAAAAMpIAS8AAAAAAAAAAAAAlJECXgAAAAAAAAAAAAAoIwW8AAAAAAAAAAAA\nAFBGCngBAAAAAAAAAAAAoIwU8AIAAAAAAAAAAABAGSngBQAAAAAAAAAAAIAyUsALAAAAAAAAAAAA\nAGWkgBcAAAAAAAAAAAAAyuj/Ak+HcVyOTkwvAAAAAElFTkSuQmCC\n", - "text/plain": [ - "" - ] - }, - "metadata": { - "tags": [], - "image/png": { - "width": 800 - } - }, - "execution_count": 8 - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "14mT7T7Q6erR", - "colab_type": "text" - }, - "source": [ - "Extras below\n", - "\n", - "---\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "42_zEpW6W_N1", - "colab_type": "code", - "colab": {} - }, - "source": [ - "!git pull" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "9bVTcveIOzDd", - "colab_type": "code", - "colab": {} - }, - "source": [ - "%cd yolov3" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "odMr0JFnCEyb", - "colab": {} - }, - "source": [ - "%ls" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "uB3v5hj_CEyI", - "colab": {} - }, - "source": [ - "# Unit Tests\n", - "!python3 detect.py # detect 2 persons, 1 tie\n", - "!python3 test.py --data data/coco_32img.data # test mAP = 0.8\n", - "!python3 train.py --data data/coco_32img.data --epochs 3 --nosave # train 3 epochs" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "6D0si0TNCEx5", - "colab": {} - }, - "source": [ - "# Evolve Hyperparameters\n", - "!python3 train.py --data data/coco.data --img-size 320 --epochs 1 --evolve" - ], - "execution_count": 0, - "outputs": [] - } - ] -} From 6736d7d125b574cdb6b18db4d52a7ee96dcf2233 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Apr 2020 12:47:07 -0700 Subject: [PATCH 0640/1185] swap cv2.INTER_AREA for cv2.INTER_LINEAR --- utils/datasets.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 4fa74ac33d..3d831e71d1 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -240,7 +240,7 @@ def __next__(self): raise StopIteration # Letterbox - img = [letterbox(x, new_shape=self.img_size, auto=self.rect, interp=cv2.INTER_LINEAR)[0] for x in img0] + img = [letterbox(x, new_shape=self.img_size, auto=self.rect)[0] for x in img0] # Stack img = np.stack(img, 0) @@ -508,8 +508,7 @@ def load_image(self, index): h0, w0 = img.shape[:2] # orig hw r = self.img_size / max(h0, w0) # resize image to img_size if r < 1 or (self.augment and (r != 1)): # always resize down, only resize up if training with augmentation - interp = cv2.INTER_LINEAR if self.augment else cv2.INTER_AREA # LINEAR for training, AREA for testing - img = cv2.resize(img, (int(w0 * r), int(h0 * r)), interpolation=interp) + img = cv2.resize(img, (int(w0 * r), int(h0 * r)), interpolation=cv2.INTER_LINEAR) return img, (h0, w0), img.shape[:2] # img, hw_original, hw_resized else: return self.imgs[index], self.img_hw0[index], self.img_hw[index] # img, hw_original, hw_resized @@ -589,8 +588,7 @@ def load_mosaic(self, index): return img4, labels4 -def letterbox(img, new_shape=(416, 416), color=(114, 114, 114), - auto=True, scaleFill=False, scaleup=True, interp=cv2.INTER_AREA): +def letterbox(img, new_shape=(416, 416), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True): # Resize image to a 32-pixel-multiple rectangle https://github.com/ultralytics/yolov3/issues/232 shape = img.shape[:2] # current shape [height, width] if isinstance(new_shape, int): @@ -616,7 +614,7 @@ def letterbox(img, new_shape=(416, 416), color=(114, 114, 114), dh /= 2 if shape[::-1] != new_unpad: # resize - img = cv2.resize(img, new_unpad, interpolation=interp) # INTER_AREA is better, INTER_LINEAR is faster + img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border @@ -651,9 +649,8 @@ def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, # Combined rotation matrix M = S @ T @ R # ORDER IS IMPORTANT HERE!! - changed = (border != 0) or (M != np.eye(3)).any() - if changed: - img = cv2.warpAffine(img, M[:2], dsize=(width, height), flags=cv2.INTER_AREA, borderValue=(114, 114, 114)) + if (border != 0) or (M != np.eye(3)).any(): # image changed + img = cv2.warpAffine(img, M[:2], dsize=(width, height), flags=cv2.INTER_LINEAR, borderValue=(114, 114, 114)) # Transform label coordinates n = len(targets) From aa8b1098dd4a3776e2f3ce588d7047932f2f7d74 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Apr 2020 16:28:59 -0700 Subject: [PATCH 0641/1185] adapt mosaic to img channel count --- utils/datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/datasets.py b/utils/datasets.py index 3d831e71d1..8f1341e339 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -527,7 +527,6 @@ def load_mosaic(self, index): labels4 = [] s = self.img_size xc, yc = [int(random.uniform(s * 0.5, s * 1.5)) for _ in range(2)] # mosaic center x, y - img4 = np.full((s * 2, s * 2, 3), 114, dtype=np.uint8) # base image with 4 tiles indices = [index] + [random.randint(0, len(self.labels) - 1) for _ in range(3)] # 3 additional image indices for i, index in enumerate(indices): # Load image @@ -535,6 +534,7 @@ def load_mosaic(self, index): # place img in img4 if i == 0: # top left + img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc # xmin, ymin, xmax, ymax (large image) x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h # xmin, ymin, xmax, ymax (small image) elif i == 1: # top right From 398f8eadec34f814fa0eb43fb4f7120a568b1bc7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Apr 2020 16:34:32 -0700 Subject: [PATCH 0642/1185] add thr=0.10 to kmean_anchors() --- utils/utils.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 4a1a07ab4a..ab121c6401 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -688,11 +688,12 @@ def coco_single_class_labels(path='../coco/labels/train2014/', label_class=43): shutil.copyfile(src=img_file, dst='new/images/' + Path(file).name.replace('txt', 'jpg')) # copy images -def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 1024)): - # from utils.utils import *; _ = kmean_anchors() - # Creaters kmeans anchors for use in *.cfg files +def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 1024), thr=0.10): + # Creates kmeans anchors for use in *.cfg files: from utils.utils import *; _ = kmean_anchors() + # n: number of anchors + # img_size: (min, max) image size used for multi-scale training (can be same values) + # thr: IoU threshold hyperparameter used for training (0.0 - 1.0) from utils.datasets import LoadImagesAndLabels - thr = 0.225 # IoU threshold def print_results(k): k = k[np.argsort(k.prod(1))] # sort small to large From 9bc3a551d97aaf93d9b36f4b539653a6ed7df80a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Apr 2020 17:24:49 -0700 Subject: [PATCH 0643/1185] histogram equalization added to augmentation --- utils/datasets.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/datasets.py b/utils/datasets.py index 8f1341e339..efd21f026c 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -520,6 +520,11 @@ def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5): np.clip(img_hsv[:, :, 0], None, 179, out=img_hsv[:, :, 0]) # inplace hue clip (0 - 179 deg) cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR, dst=img) # no return needed + # Histogram equalization + if random.random() < 0.2: + for i in range(3): + img[:, :, i] = cv2.equalizeHist(img[:, :, i]) + def load_mosaic(self, index): # loads images in a mosaic From 4bbfda5cdef05e8f841a8dfe03cf2c93d66a4f14 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Apr 2020 17:29:57 -0700 Subject: [PATCH 0644/1185] hist equalization --- utils/datasets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index efd21f026c..1755b17747 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -521,9 +521,9 @@ def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5): cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR, dst=img) # no return needed # Histogram equalization - if random.random() < 0.2: - for i in range(3): - img[:, :, i] = cv2.equalizeHist(img[:, :, i]) + # if random.random() < 0.2: + # for i in range(3): + # img[:, :, i] = cv2.equalizeHist(img[:, :, i]) def load_mosaic(self, index): From 2cf23c4aee2917793f2b1a0a7b5b71cb3bad4b0a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Apr 2020 18:58:34 -0700 Subject: [PATCH 0645/1185] add MixConv2d() layer --- utils/datasets.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 1755b17747..e2af1aae7d 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -507,8 +507,9 @@ def load_image(self, index): assert img is not None, 'Image Not Found ' + img_path h0, w0 = img.shape[:2] # orig hw r = self.img_size / max(h0, w0) # resize image to img_size - if r < 1 or (self.augment and (r != 1)): # always resize down, only resize up if training with augmentation - img = cv2.resize(img, (int(w0 * r), int(h0 * r)), interpolation=cv2.INTER_LINEAR) + if r < 1 or (self.augment and r != 1): # always resize down, only resize up if training with augmentation + interp = cv2.INTER_AREA if r < 1 and not self.augment else cv2.INTER_LINEAR + img = cv2.resize(img, (int(w0 * r), int(h0 * r)), interpolation=interp) return img, (h0, w0), img.shape[:2] # img, hw_original, hw_resized else: return self.imgs[index], self.img_hw0[index], self.img_hw[index] # img, hw_original, hw_resized From 58edfc4a84719366a8448c6c989ec6118d4a92d1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Apr 2020 10:45:33 -0700 Subject: [PATCH 0646/1185] kaiming weight init --- models.py | 1 + utils/torch_utils.py | 9 +++++++++ utils/utils.py | 9 --------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/models.py b/models.py index 683c3a7fbe..4ecf99e683 100755 --- a/models.py +++ b/models.py @@ -225,6 +225,7 @@ def __init__(self, cfg, img_size=(416, 416), verbose=False): self.module_defs = parse_model_cfg(cfg) self.module_list, self.routs = create_modules(self.module_defs, img_size) self.yolo_layers = get_yolo_layers(self) + # torch_utils.initialize_weights(self) # Darknet Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 self.version = np.array([0, 2, 5], dtype=np.int32) # (int32) version info: major, minor, revision diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 5819e68e6a..f63bc1105b 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -50,6 +50,15 @@ def time_synchronized(): return time.time() +def initialize_weights(model): + for m in model.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def fuse_conv_and_bn(conv, bn): # https://tehnokv.com/posts/fusing-batchnorm-and-conv/ with torch.no_grad(): diff --git a/utils/utils.py b/utils/utils.py index ab121c6401..60443b0d2f 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -93,15 +93,6 @@ def coco80_to_coco91_class(): # converts 80-index (val2014) to 91-index (paper) return x -def weights_init_normal(m): - classname = m.__class__.__name__ - if classname.find('Conv') != -1: - torch.nn.init.normal_(m.weight.data, 0.0, 0.03) - elif classname.find('BatchNorm2d') != -1: - torch.nn.init.normal_(m.weight.data, 1.0, 0.03) - torch.nn.init.constant_(m.bias.data, 0.0) - - def xyxy2xywh(x): # Transform box coordinates from [x1, y1, x2, y2] (where xy1=top-left, xy2=bottom-right) to [x, y, w, h] y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) From dcc2e99fb25251a4e7363a814f6e3b038987c48a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Apr 2020 10:55:49 -0700 Subject: [PATCH 0647/1185] get_yolo_layers() --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 4ecf99e683..90d94ebe16 100755 --- a/models.py +++ b/models.py @@ -334,7 +334,7 @@ def info(self, verbose=False): def get_yolo_layers(model): - return [i for i, x in enumerate(model.module_defs) if x['type'] == 'yolo'] # [82, 94, 106] for yolov3 + return [i for i, m in enumerate(model.module_list) if m.__class__.__name__ == 'YOLOLayer'] # [89, 101, 1113] def load_darknet_weights(self, weights, cutoff=-1): From 7be71b02e2013a2b4be32511002f1ea6987afaca Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Apr 2020 10:56:20 -0700 Subject: [PATCH 0648/1185] get_yolo_layers() --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 90d94ebe16..dea7522131 100755 --- a/models.py +++ b/models.py @@ -334,7 +334,7 @@ def info(self, verbose=False): def get_yolo_layers(model): - return [i for i, m in enumerate(model.module_list) if m.__class__.__name__ == 'YOLOLayer'] # [89, 101, 1113] + return [i for i, m in enumerate(model.module_list) if m.__class__.__name__ == 'YOLOLayer'] # [89, 101, 113] def load_darknet_weights(self, weights, cutoff=-1): From b574f765ce9ef87be6b33c67e1aa867b0209fbe0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Apr 2020 11:04:10 -0700 Subject: [PATCH 0649/1185] add warning to plot_results() --- utils/utils.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 60443b0d2f..202fa73499 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -966,18 +966,21 @@ def plot_results(start=0, stop=0, bucket='', id=()): # from utils.utils import else: files = glob.glob('results*.txt') + glob.glob('../../Downloads/results*.txt') for f in sorted(files): - results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T - n = results.shape[1] # number of rows - x = range(start, min(stop, n) if stop else n) - for i in range(10): - y = results[i, x] - if i in [0, 1, 2, 5, 6, 7]: - y[y == 0] = np.nan # dont show zero loss values - # y /= y[0] # normalize - ax[i].plot(x, y, marker='.', label=Path(f).stem, linewidth=2, markersize=8) - ax[i].set_title(s[i]) - if i in [5, 6, 7]: # share train and val loss y axes - ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) + try: + results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T + n = results.shape[1] # number of rows + x = range(start, min(stop, n) if stop else n) + for i in range(10): + y = results[i, x] + if i in [0, 1, 2, 5, 6, 7]: + y[y == 0] = np.nan # dont show zero loss values + # y /= y[0] # normalize + ax[i].plot(x, y, marker='.', label=Path(f).stem, linewidth=2, markersize=8) + ax[i].set_title(s[i]) + if i in [5, 6, 7]: # share train and val loss y axes + ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) + except: + print('Warning: Plotting error for %s, skipping file' % f) fig.tight_layout() ax[1].legend() From a34219a54bbe80a5de2dcb67f90f213e5a006c9e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Apr 2020 12:18:54 -0700 Subject: [PATCH 0650/1185] pading from (k-1) // 2 to k // 2 --- models.py | 2 +- utils/layers.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index dea7522131..905797d285 100755 --- a/models.py +++ b/models.py @@ -28,7 +28,7 @@ def create_modules(module_defs, img_size): out_channels=filters, kernel_size=size, stride=stride, - padding=(size - 1) // 2 if mdef['pad'] else 0, + padding=size // 2 if mdef['pad'] else 0, groups=mdef['groups'] if 'groups' in mdef else 1, bias=not bn)) else: # multiple-size conv diff --git a/utils/layers.py b/utils/layers.py index 6424fba76b..dce3fed206 100644 --- a/utils/layers.py +++ b/utils/layers.py @@ -65,7 +65,7 @@ def __init__(self, in_ch, out_ch, k=(3, 5, 7), stride=1, dilation=1, bias=True, out_channels=ch[g], kernel_size=k[g], stride=stride, - padding=(k[g] - 1) // 2, # 'same' pad + padding=k[g] // 2, # 'same' pad dilation=dilation, bias=bias) for g in range(groups)]) From ed1d4f5ae7c03a271d8e02466a5560b0366c5c05 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Apr 2020 12:37:03 -0700 Subject: [PATCH 0651/1185] k for kernel_size --- models.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/models.py b/models.py index 905797d285..01dc1edd9f 100755 --- a/models.py +++ b/models.py @@ -21,20 +21,20 @@ def create_modules(module_defs, img_size): if mdef['type'] == 'convolutional': bn = mdef['batch_normalize'] filters = mdef['filters'] - size = mdef['size'] + k = mdef['size'] # kernel size stride = mdef['stride'] if 'stride' in mdef else (mdef['stride_y'], mdef['stride_x']) - if isinstance(size, int): # single-size conv + if isinstance(k, int): # single-size conv modules.add_module('Conv2d', nn.Conv2d(in_channels=output_filters[-1], out_channels=filters, - kernel_size=size, + kernel_size=k, stride=stride, - padding=size // 2 if mdef['pad'] else 0, + padding=k // 2 if mdef['pad'] else 0, groups=mdef['groups'] if 'groups' in mdef else 1, bias=not bn)) else: # multiple-size conv modules.add_module('MixConv2d', MixConv2d(in_ch=output_filters[-1], out_ch=filters, - k=size, + k=k, stride=stride, bias=not bn)) @@ -58,10 +58,10 @@ def create_modules(module_defs, img_size): modules.running_var = torch.tensor([0.0524, 0.0502, 0.0506]) elif mdef['type'] == 'maxpool': - size = mdef['size'] + k = mdef['size'] # kernel size stride = mdef['stride'] - maxpool = nn.MaxPool2d(kernel_size=size, stride=stride, padding=(size - 1) // 2) - if size == 2 and stride == 1: # yolov3-tiny + maxpool = nn.MaxPool2d(kernel_size=k, stride=stride, padding=(k - 1) // 2) + if k == 2 and stride == 1: # yolov3-tiny modules.add_module('ZeroPad2d', nn.ZeroPad2d((0, 1, 0, 1))) modules.add_module('MaxPool2d', maxpool) else: From ada29581053109b07cafb587105b74f735ba1e3d Mon Sep 17 00:00:00 2001 From: "Timothy M. Shead" Date: Sun, 12 Apr 2020 11:00:50 -0600 Subject: [PATCH 0652/1185] Fix argparse string escapes in train.py. (#1045) --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 0429273641..9f21b1900c 100644 --- a/train.py +++ b/train.py @@ -386,7 +386,7 @@ def train(): parser.add_argument('--accumulate', type=int, default=4, help='batches to accumulate before optimizing') parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data path') - parser.add_argument('--multi-scale', action='store_true', help='adjust (67% - 150%) img_size every 10 batches') + parser.add_argument('--multi-scale', action='store_true', help='adjust (67%% - 150%%) img_size every 10 batches') parser.add_argument('--img-size', nargs='+', type=int, default=[416], help='train and test image-sizes') parser.add_argument('--rect', action='store_true', help='rectangular training') parser.add_argument('--resume', action='store_true', help='resume training from last.pt') From eda31c8bd0ee76e6c19ad13a94e13cd2943fa3e4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Apr 2020 10:20:21 -0700 Subject: [PATCH 0653/1185] print speeds for save_json --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 164a580d83..67006c7543 100644 --- a/test.py +++ b/test.py @@ -188,7 +188,7 @@ def test(cfg, print(pf % (names[c], seen, nt[c], p[i], r[i], ap[i], f1[i])) # Print speeds - if verbose: + if verbose or save_json: t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + (img_size, img_size, batch_size) # tuple print('Speed: %.1f/%.1f/%.1f ms inference/NMS/total per %gx%g image at batch-size %g' % t) From efc754a794d3796055b12bfd6dfe3dbfbd6603db Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Apr 2020 12:49:23 -0700 Subject: [PATCH 0654/1185] add generations arg to kmeans() --- utils/utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 202fa73499..11fd4c6136 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -679,11 +679,12 @@ def coco_single_class_labels(path='../coco/labels/train2014/', label_class=43): shutil.copyfile(src=img_file, dst='new/images/' + Path(file).name.replace('txt', 'jpg')) # copy images -def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 1024), thr=0.10): +def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 1024), thr=0.10, gen=1000): # Creates kmeans anchors for use in *.cfg files: from utils.utils import *; _ = kmean_anchors() # n: number of anchors # img_size: (min, max) image size used for multi-scale training (can be same values) # thr: IoU threshold hyperparameter used for training (0.0 - 1.0) + # gen: generations to evolve anchors using genetic algorithm from utils.datasets import LoadImagesAndLabels def print_results(k): @@ -742,8 +743,8 @@ def fitness(k): # mutation fitness # Evolve npr = np.random - f, sh, ng, mp, s = fitness(k), k.shape, 1000, 0.9, 0.1 # fitness, generations, mutation prob, sigma - for _ in tqdm(range(ng), desc='Evolving anchors'): + f, sh, mp, s = fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma + for _ in tqdm(range(gen), desc='Evolving anchors'): v = np.ones(sh) while (v == 1).all(): # mutate until a change occurs (prevent duplicates) v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) # 98.6, 61.6 From 46726dad139b1cad31b9942b417b6c3e29aa63f7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Apr 2020 13:02:00 -0700 Subject: [PATCH 0655/1185] torch.tensor(ng, device=device) --- models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index 01dc1edd9f..7884e60368 100755 --- a/models.py +++ b/models.py @@ -138,7 +138,7 @@ def __init__(self, anchors, nc, img_size, yolo_index, layers, stride): self.na = len(anchors) # number of anchors (3) self.nc = nc # number of classes (80) self.no = nc + 5 # number of outputs (85) - self.nx, self.ny = 0, 0 # initialize number of x, y gridpoints + self.nx, self.ny, self.ng = 0, 0, 0 # initialize number of x, y gridpoints self.anchor_vec = self.anchors / self.stride self.anchor_wh = self.anchor_vec.view(1, self.na, 1, 1, 2) @@ -148,7 +148,7 @@ def __init__(self, anchors, nc, img_size, yolo_index, layers, stride): def create_grids(self, ng=(13, 13), device='cpu'): self.nx, self.ny = ng # x and y grid size - self.ng = torch.Tensor(ng).to(device) + self.ng = torch.tensor(ng, device=device) # build xy offsets if not self.training: From 1038b0d2693cbcf62c1f209451ecedf29d9baa1a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Apr 2020 18:22:54 -0700 Subject: [PATCH 0656/1185] multi-scale update --- train.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/train.py b/train.py index 9f21b1900c..56b383a0ba 100644 --- a/train.py +++ b/train.py @@ -56,23 +56,27 @@ def train(): cfg = opt.cfg data = opt.data - img_size, img_size_test = opt.img_size if len(opt.img_size) == 2 else opt.img_size * 2 # train, test sizes epochs = opt.epochs # 500200 batches at bs 64, 117263 images = 273 epochs batch_size = opt.batch_size accumulate = opt.accumulate # effective bs = batch_size * accumulate = 16 * 4 = 64 weights = opt.weights # initial training weights + imgsz_min, imgsz_max, img_size_test = opt.img_size # img sizes (min, max, test) - # Initialize - gs = 32 # (pixels) grid size - assert math.fmod(img_size, gs) == 0, '--img-size must be a %g-multiple' % gs - init_seeds() + # Image Sizes + gs = 64 # (pixels) grid size + assert math.fmod(imgsz_min, gs) == 0, '--img-size %g must be a %g-multiple' % (imgsz_min, gs) + opt.multi_scale |= imgsz_min != imgsz_max # multi if different (min, max) if opt.multi_scale: - img_sz_min = round(img_size / gs / 1.5) + 1 - img_sz_max = round(img_size / gs * 1.5) - img_size = img_sz_max * gs # initiate with maximum multi_scale size - print('Using multi-scale %g - %g' % (img_sz_min * gs, img_size)) + if imgsz_min == imgsz_max: + imgsz_min //= 1.5 + imgsz_max //= 0.667 + grid_min, grid_max = imgsz_min // gs, imgsz_max // gs + imgsz_max = grid_max * gs # initialize with maximum multi_scale size + print('Using multi-scale %g - %g' % (grid_min * gs, imgsz_max)) + img_size = imgsz_max # Configure run + init_seeds() data_dict = parse_data_cfg(data) train_path = data_dict['train'] test_path = data_dict['valid'] @@ -248,7 +252,7 @@ def train(): # Multi-Scale training if opt.multi_scale: if ni / accumulate % 1 == 0: #  adjust img_size (67% - 150%) every 1 batch - img_size = random.randrange(img_sz_min, img_sz_max + 1) * gs + img_size = random.randrange(grid_min, grid_max + 1) * gs sf = img_size / max(imgs.shape[2:]) # scale factor if sf != 1: ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to 32-multiple) @@ -387,7 +391,7 @@ def train(): parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data path') parser.add_argument('--multi-scale', action='store_true', help='adjust (67%% - 150%%) img_size every 10 batches') - parser.add_argument('--img-size', nargs='+', type=int, default=[416], help='train and test image-sizes') + parser.add_argument('--img-size', nargs='+', type=int, default=[512], help='[min_train, max-train, test] img sizes') parser.add_argument('--rect', action='store_true', help='rectangular training') parser.add_argument('--resume', action='store_true', help='resume training from last.pt') parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') @@ -403,6 +407,7 @@ def train(): opt = parser.parse_args() opt.weights = last if opt.resume else opt.weights print(opt) + opt.img_size.extend([opt.img_size[-1]] * (3 - len(opt.img_size))) # extend to 3 sizes (min, max, test) device = torch_utils.select_device(opt.device, apex=mixed_precision, batch_size=opt.batch_size) if device.type == 'cpu': mixed_precision = False From 77e6bdd3c1ea410b25c407fef1df1dab98f9c27b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Apr 2020 18:44:18 -0700 Subject: [PATCH 0657/1185] FLOPs at 480x640, BN init --- utils/torch_utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index f63bc1105b..9d2491f3a4 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -55,8 +55,8 @@ def initialize_weights(model): if isinstance(m, nn.Conv2d): nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') elif isinstance(m, nn.BatchNorm2d): - m.weight.data.fill_(1) - m.bias.data.zero_() + m.eps = 1e-4 + m.momentum = 0.03 def fuse_conv_and_bn(conv, bn): @@ -99,7 +99,7 @@ def model_info(model, verbose=False): try: # FLOPS from thop import profile - macs, _ = profile(model, inputs=(torch.zeros(1, 3, 640, 640),)) + macs, _ = profile(model, inputs=(torch.zeros(1, 3, 480, 640),)) fs = ', %.1f GFLOPS' % (macs / 1E9 * 2) except: fs = '' From b8574add3738afdee403125e26ade94711a559aa Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 13 Apr 2020 17:48:30 -0700 Subject: [PATCH 0658/1185] new find_modules() fcn --- models.py | 6 +----- utils/torch_utils.py | 5 +++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/models.py b/models.py index 7884e60368..616cb9243c 100755 --- a/models.py +++ b/models.py @@ -224,7 +224,7 @@ def __init__(self, cfg, img_size=(416, 416), verbose=False): self.module_defs = parse_model_cfg(cfg) self.module_list, self.routs = create_modules(self.module_defs, img_size) - self.yolo_layers = get_yolo_layers(self) + self.yolo_layers = torch_utils.find_modules(self, mclass=YOLOLayer) # torch_utils.initialize_weights(self) # Darknet Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 @@ -333,10 +333,6 @@ def info(self, verbose=False): torch_utils.model_info(self, verbose) -def get_yolo_layers(model): - return [i for i, m in enumerate(model.module_list) if m.__class__.__name__ == 'YOLOLayer'] # [89, 101, 113] - - def load_darknet_weights(self, weights, cutoff=-1): # Parses and loads the weights stored in 'weights' diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 9d2491f3a4..0e1ade3a6b 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -59,6 +59,11 @@ def initialize_weights(model): m.momentum = 0.03 +def find_modules(model, mclass=nn.Conv2d): + # finds layer indices matching module class 'mclass' + return [i for i, m in enumerate(model.module_list) if isinstance(m, mclass)] + + def fuse_conv_and_bn(conv, bn): # https://tehnokv.com/posts/fusing-batchnorm-and-conv/ with torch.no_grad(): From ca3a9fcb0baab7a3363312b41934f90833616e11 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 13 Apr 2020 17:56:12 -0700 Subject: [PATCH 0659/1185] return get_yolo_layers() --- models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/models.py b/models.py index 616cb9243c..7884e60368 100755 --- a/models.py +++ b/models.py @@ -224,7 +224,7 @@ def __init__(self, cfg, img_size=(416, 416), verbose=False): self.module_defs = parse_model_cfg(cfg) self.module_list, self.routs = create_modules(self.module_defs, img_size) - self.yolo_layers = torch_utils.find_modules(self, mclass=YOLOLayer) + self.yolo_layers = get_yolo_layers(self) # torch_utils.initialize_weights(self) # Darknet Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 @@ -333,6 +333,10 @@ def info(self, verbose=False): torch_utils.model_info(self, verbose) +def get_yolo_layers(model): + return [i for i, m in enumerate(model.module_list) if m.__class__.__name__ == 'YOLOLayer'] # [89, 101, 113] + + def load_darknet_weights(self, weights, cutoff=-1): # Parses and loads the weights stored in 'weights' From 0dd5f8eee8174ba8b89bf4ff0771b166b2e69cce Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 13 Apr 2020 18:25:59 -0700 Subject: [PATCH 0660/1185] code cleanup --- models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index 7884e60368..853522bc84 100755 --- a/models.py +++ b/models.py @@ -159,7 +159,7 @@ def create_grids(self, ng=(13, 13), device='cpu'): self.anchor_vec = self.anchor_vec.to(device) self.anchor_wh = self.anchor_wh.to(device) - def forward(self, p, img_size, out): + def forward(self, p, out): ASFF = False # https://arxiv.org/abs/1911.09516 if ASFF: i, n = self.index, self.nl # index in layers, number of layers @@ -287,7 +287,7 @@ def forward_once(self, x, augment=False, verbose=False): str = ' >> ' + ' + '.join(['layer %g %s' % x for x in zip(l, sh)]) x = module(x, out) # WeightedFeatureFusion(), FeatureConcat() elif name == 'YOLOLayer': - yolo_out.append(module(x, img_size, out)) + yolo_out.append(module(x, out)) else: # run module directly, i.e. mtype = 'convolutional', 'upsample', 'maxpool', 'batchnorm2d' etc. x = module(x) From 76fb8d48d43da1a46fcbe1d7142a1947ef162da6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 13 Apr 2020 21:25:03 -0700 Subject: [PATCH 0661/1185] ng dependence removed from build_targets() --- models.py | 2 +- utils/utils.py | 25 ++++++++++++------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/models.py b/models.py index 853522bc84..cd07f49e9b 100755 --- a/models.py +++ b/models.py @@ -148,7 +148,7 @@ def __init__(self, anchors, nc, img_size, yolo_index, layers, stride): def create_grids(self, ng=(13, 13), device='cpu'): self.nx, self.ny = ng # x and y grid size - self.ng = torch.tensor(ng, device=device) + self.ng = torch.tensor(ng) # build xy offsets if not self.training: diff --git a/utils/utils.py b/utils/utils.py index 11fd4c6136..8a14f6d921 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -366,7 +366,7 @@ def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#iss def compute_loss(p, targets, model): # predictions, targets, model ft = torch.cuda.FloatTensor if p[0].is_cuda else torch.Tensor lcls, lbox, lobj = ft([0]), ft([0]), ft([0]) - tcls, tbox, indices, anchor_vec = build_targets(model, targets) + tcls, tbox, indices, anchor_vec = build_targets(p, targets, model) h = model.hyp # hyperparameters red = 'mean' # Loss reduction (sum or mean) @@ -430,42 +430,41 @@ def compute_loss(p, targets, model): # predictions, targets, model return loss, torch.cat((lbox, lobj, lcls, loss)).detach() -def build_targets(model, targets): +def build_targets(p, targets, model): # targets = [image, class, x, y, w, h] nt = targets.shape[0] tcls, tbox, indices, av = [], [], [], [] multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) reject, use_all_anchors = True, True + gain = torch.ones(6, device=targets.device) # normalized to gridspace gain for i in model.yolo_layers: # get number of grid points and anchor vec for this yolo layer - if multi_gpu: - ng, anchor_vec = model.module.module_list[i].ng, model.module.module_list[i].anchor_vec - else: - ng, anchor_vec = model.module_list[i].ng, model.module_list[i].anchor_vec + anchor_vec = model.module.module_list[i].anchor_vec if multi_gpu else model.module_list[i].anchor_vec # iou of targets-anchors - t, a = targets, [] - gwh = t[:, 4:6] * ng + gain[2:] = torch.tensor(p[0].shape)[[2, 3, 2, 3]] # xyxy gain + t, a = targets * gain, [] + gwh = t[:, 4:6] if nt: iou = wh_iou(anchor_vec, gwh) # iou(3,n) = wh_iou(anchor_vec(3,2), gwh(n,2)) if use_all_anchors: na = anchor_vec.shape[0] # number of anchors - a = torch.arange(na).view((-1, 1)).repeat([1, nt]).view(-1) - t = targets.repeat([na, 1]) - gwh = gwh.repeat([na, 1]) + a = torch.arange(na).view(-1, 1).repeat(1, nt).view(-1) + t = targets.repeat(na, 1) else: # use best anchor only iou, a = iou.max(0) # best iou and anchor # reject anchors below iou_thres (OPTIONAL, increases P, lowers R) if reject: j = iou.view(-1) > model.hyp['iou_t'] # iou threshold hyperparameter - t, a, gwh = t[j], a[j], gwh[j] + t, a = t[j], a[j] # Indices b, c = t[:, :2].long().t() # target image, class - gxy = t[:, 2:4] * ng # grid x, y + gxy = t[:, 2:4] # grid x, y + gwh = t[:, 4:6] # grid w, h gi, gj = gxy.long().t() # grid x, y indices indices.append((b, a, gj, gi)) From 835b0da68a6329f533ab96f3f8f21f4666a1b93e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 14 Apr 2020 01:20:57 -0700 Subject: [PATCH 0662/1185] new modules and init weights --- utils/layers.py | 22 ++++++++++++++++++++++ utils/torch_utils.py | 7 +++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/utils/layers.py b/utils/layers.py index dce3fed206..7662c6bd74 100644 --- a/utils/layers.py +++ b/utils/layers.py @@ -3,6 +3,28 @@ from utils.utils import * +def make_divisible(v, divisor): + # Function ensures all layers have a channel number that is divisible by 8 + # https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py + return math.ceil(v / divisor) * divisor + + +class Flatten(nn.Module): + # Use after nn.AdaptiveAvgPool2d(1) to remove last 2 dimensions + def forward(self, x): + return x.view(x.size(0), -1) + + +class Concat(nn.Module): + # Concatenate a list of tensors along dimension + def __init__(self, dimension=1): + super(Concat, self).__init__() + self.d = dimension + + def forward(self, x): + return torch.cat(x, self.d) + + class FeatureConcat(nn.Module): def __init__(self, layers): super(FeatureConcat, self).__init__() diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 0e1ade3a6b..e5286cd01f 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -52,11 +52,14 @@ def time_synchronized(): def initialize_weights(model): for m in model.modules(): - if isinstance(m, nn.Conv2d): + t = type(m) + if t is nn.Conv2d: nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') - elif isinstance(m, nn.BatchNorm2d): + elif t is nn.BatchNorm2d: m.eps = 1e-4 m.momentum = 0.03 + elif t in [nn.LeakyReLU, nn.ReLU, nn.ReLU6]: + m.inplace = True def find_modules(model, mclass=nn.Conv2d): From 25725c85692893366d5ce9caaa6aa8abadd5f6c6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 14 Apr 2020 03:13:30 -0700 Subject: [PATCH 0663/1185] bug fix --- utils/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 8a14f6d921..4e4440d699 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -438,12 +438,12 @@ def build_targets(p, targets, model): multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) reject, use_all_anchors = True, True gain = torch.ones(6, device=targets.device) # normalized to gridspace gain - for i in model.yolo_layers: + for j, i in enumerate(model.yolo_layers): # get number of grid points and anchor vec for this yolo layer anchor_vec = model.module.module_list[i].anchor_vec if multi_gpu else model.module_list[i].anchor_vec # iou of targets-anchors - gain[2:] = torch.tensor(p[0].shape)[[2, 3, 2, 3]] # xyxy gain + gain[2:] = torch.tensor(p[j].shape)[[2, 3, 2, 3]] # xyxy gain t, a = targets * gain, [] gwh = t[:, 4:6] if nt: @@ -452,7 +452,7 @@ def build_targets(p, targets, model): if use_all_anchors: na = anchor_vec.shape[0] # number of anchors a = torch.arange(na).view(-1, 1).repeat(1, nt).view(-1) - t = targets.repeat(na, 1) + t = t.repeat(na, 1) else: # use best anchor only iou, a = iou.max(0) # best iou and anchor From 198a5a591d9e2f28c3bce9cc542d3f3cdaa50a6e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 14 Apr 2020 04:15:05 -0700 Subject: [PATCH 0664/1185] code cleanup --- utils/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 4e4440d699..def70e26c5 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -435,12 +435,12 @@ def build_targets(p, targets, model): nt = targets.shape[0] tcls, tbox, indices, av = [], [], [], [] - multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) reject, use_all_anchors = True, True gain = torch.ones(6, device=targets.device) # normalized to gridspace gain - for j, i in enumerate(model.yolo_layers): + multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) + for i, j in enumerate(model.yolo_layers): # get number of grid points and anchor vec for this yolo layer - anchor_vec = model.module.module_list[i].anchor_vec if multi_gpu else model.module_list[i].anchor_vec + anchor_vec = model.module.module_list[j].anchor_vec if multi_gpu else model.module_list[j].anchor_vec # iou of targets-anchors gain[2:] = torch.tensor(p[j].shape)[[2, 3, 2, 3]] # xyxy gain From 16812495884a38fa6724aea5c136b6ee4ed93e26 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 14 Apr 2020 04:15:53 -0700 Subject: [PATCH 0665/1185] cleanup --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index def70e26c5..ef77e34567 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -443,7 +443,7 @@ def build_targets(p, targets, model): anchor_vec = model.module.module_list[j].anchor_vec if multi_gpu else model.module_list[j].anchor_vec # iou of targets-anchors - gain[2:] = torch.tensor(p[j].shape)[[2, 3, 2, 3]] # xyxy gain + gain[2:] = torch.tensor(p[i].shape)[[2, 3, 2, 3]] # xyxy gain t, a = targets * gain, [] gwh = t[:, 4:6] if nt: From 029e137bc2024f730d5ddc90c8a0e80aa9ff2bfd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 14 Apr 2020 04:34:40 -0700 Subject: [PATCH 0666/1185] bug fix --- utils/utils.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index ef77e34567..468fdf8c13 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -437,13 +437,17 @@ def build_targets(p, targets, model): tcls, tbox, indices, av = [], [], [], [] reject, use_all_anchors = True, True gain = torch.ones(6, device=targets.device) # normalized to gridspace gain + + # m = list(model.modules())[-1] + # for i in range(m.nl): + # anchor_vec = m.anchor_vec[i] multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) for i, j in enumerate(model.yolo_layers): # get number of grid points and anchor vec for this yolo layer anchor_vec = model.module.module_list[j].anchor_vec if multi_gpu else model.module_list[j].anchor_vec # iou of targets-anchors - gain[2:] = torch.tensor(p[i].shape)[[2, 3, 2, 3]] # xyxy gain + gain[2:] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain t, a = targets * gain, [] gwh = t[:, 4:6] if nt: From 763cdd5ae2f0089c5b802e535b804bfc10633252 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 14 Apr 2020 11:51:19 -0700 Subject: [PATCH 0667/1185] detailed image sizes report --- train.py | 12 ++++++------ utils/utils.py | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/train.py b/train.py index 56b383a0ba..bfb3e7ff54 100644 --- a/train.py +++ b/train.py @@ -60,7 +60,7 @@ def train(): batch_size = opt.batch_size accumulate = opt.accumulate # effective bs = batch_size * accumulate = 16 * 4 = 64 weights = opt.weights # initial training weights - imgsz_min, imgsz_max, img_size_test = opt.img_size # img sizes (min, max, test) + imgsz_min, imgsz_max, imgsz_test = opt.img_size # img sizes (min, max, test) # Image Sizes gs = 64 # (pixels) grid size @@ -71,9 +71,9 @@ def train(): imgsz_min //= 1.5 imgsz_max //= 0.667 grid_min, grid_max = imgsz_min // gs, imgsz_max // gs - imgsz_max = grid_max * gs # initialize with maximum multi_scale size - print('Using multi-scale %g - %g' % (grid_min * gs, imgsz_max)) - img_size = imgsz_max + imgsz_min, imgsz_max = grid_min * gs, grid_max * gs + print('Training image sizes %g - %g, testing image size %g' % (imgsz_min, imgsz_max, imgsz_test)) + img_size = imgsz_max # initialize with max size # Configure run init_seeds() @@ -192,7 +192,7 @@ def train(): collate_fn=dataset.collate_fn) # Testloader - testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, img_size_test, batch_size, + testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, imgsz_test, batch_size, hyp=hyp, rect=True, cache_images=opt.cache_images, @@ -310,7 +310,7 @@ def train(): results, maps = test.test(cfg, data, batch_size=batch_size, - img_size=img_size_test, + img_size=imgsz_test, model=ema.ema, save_json=final_epoch and is_coco, single_cls=opt.single_cls, diff --git a/utils/utils.py b/utils/utils.py index 468fdf8c13..7331d41363 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -573,9 +573,9 @@ def get_yolo_layers(model): def print_model_biases(model): # prints the bias neurons preceding each yolo layer print('\nModel Bias Summary: %8s%18s%18s%18s' % ('layer', 'regression', 'objectness', 'classification')) - multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) - for l in model.yolo_layers: # print pretrained biases - try: + try: + multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) + for l in model.yolo_layers: # print pretrained biases if multi_gpu: na = model.module.module_list[l].na # number of anchors b = model.module.module_list[l - 1][0].bias.view(na, -1) # bias 3x85 From f5a2682a817c101e260e546a7fcfd00c873d318a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 14 Apr 2020 12:02:08 -0700 Subject: [PATCH 0668/1185] image sizes report --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index bfb3e7ff54..71dcbb0586 100644 --- a/train.py +++ b/train.py @@ -72,7 +72,7 @@ def train(): imgsz_max //= 0.667 grid_min, grid_max = imgsz_min // gs, imgsz_max // gs imgsz_min, imgsz_max = grid_min * gs, grid_max * gs - print('Training image sizes %g - %g, testing image size %g' % (imgsz_min, imgsz_max, imgsz_test)) + print('Image sizes %g - %g train, %g test' % (imgsz_min, imgsz_max, imgsz_test)) img_size = imgsz_max # initialize with max size # Configure run From ac4c90c817b87427c74e4d5bdbcf01964c62268f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 14 Apr 2020 13:08:00 -0700 Subject: [PATCH 0669/1185] cleanup --- utils/utils.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 7331d41363..d45d14cdad 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -440,21 +440,21 @@ def build_targets(p, targets, model): # m = list(model.modules())[-1] # for i in range(m.nl): - # anchor_vec = m.anchor_vec[i] + # anchors = m.anchors[i] multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) for i, j in enumerate(model.yolo_layers): # get number of grid points and anchor vec for this yolo layer - anchor_vec = model.module.module_list[j].anchor_vec if multi_gpu else model.module_list[j].anchor_vec + anchors = model.module.module_list[j].anchor_vec if multi_gpu else model.module_list[j].anchor_vec # iou of targets-anchors gain[2:] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain t, a = targets * gain, [] gwh = t[:, 4:6] if nt: - iou = wh_iou(anchor_vec, gwh) # iou(3,n) = wh_iou(anchor_vec(3,2), gwh(n,2)) + iou = wh_iou(anchors, gwh) # iou(3,n) = wh_iou(anchors(3,2), gwh(n,2)) if use_all_anchors: - na = anchor_vec.shape[0] # number of anchors + na = anchors.shape[0] # number of anchors a = torch.arange(na).view(-1, 1).repeat(1, nt).view(-1) t = t.repeat(na, 1) else: # use best anchor only @@ -475,7 +475,7 @@ def build_targets(p, targets, model): # Box gxy -= gxy.floor() # xy tbox.append(torch.cat((gxy, gwh), 1)) # xywh (grids) - av.append(anchor_vec[a]) # anchor vec + av.append(anchors[a]) # anchor vec # Class tcls.append(c) @@ -585,8 +585,8 @@ def print_model_biases(model): print(' ' * 20 + '%8g %18s%18s%18s' % (l, '%5.2f+/-%-5.2f' % (b[:, :4].mean(), b[:, :4].std()), '%5.2f+/-%-5.2f' % (b[:, 4].mean(), b[:, 4].std()), '%5.2f+/-%-5.2f' % (b[:, 5:].mean(), b[:, 5:].std()))) - except: - pass + except: + pass def strip_optimizer(f='weights/last.pt'): # from utils.utils import *; strip_optimizer() From a49ea80218f21e1c5d3b9340a75bb3d2deb106a3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 14 Apr 2020 15:58:32 -0700 Subject: [PATCH 0670/1185] update initialize_weights() --- utils/torch_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index e5286cd01f..c66909245c 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -54,7 +54,7 @@ def initialize_weights(model): for m in model.modules(): t = type(m) if t is nn.Conv2d: - nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + pass # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') elif t is nn.BatchNorm2d: m.eps = 1e-4 m.momentum = 0.03 From 628028c617c503224f3ad542bd229111906ee973 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 15 Apr 2020 11:50:54 -0700 Subject: [PATCH 0671/1185] bias init --- models.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/models.py b/models.py index cd07f49e9b..f2b8b15adf 100755 --- a/models.py +++ b/models.py @@ -102,14 +102,11 @@ def create_modules(module_defs, img_size): # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) try: - bo = -4.5 #  obj bias - bc = math.log(1 / (modules.nc - 0.99)) # cls bias: class probability is sigmoid(p) = 1/nc - j = layers[yolo_index] if 'from' in mdef else -1 bias_ = module_list[j][0].bias # shape(255,) bias = bias_[:modules.no * modules.na].view(modules.na, -1) # shape(3,85) - bias[:, 4] += bo - bias[:, 4].mean() # obj - bias[:, 5:] += bc - bias[:, 5:].mean() # cls, view with utils.print_model_biases(model) + bias[:, 4] += -4.5 # obj + bias[:, 5:] += math.log(0.6 / (modules.nc - 0.99)) # cls (sigmoid(p) = 1/nc) module_list[j][0].bias = torch.nn.Parameter(bias_, requires_grad=bias_.requires_grad) except: print('WARNING: smart bias initialization failure.') From b8c3644a18996e827c32c9dff81362864473b254 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 15 Apr 2020 12:12:59 -0700 Subject: [PATCH 0672/1185] ONNX export update --- models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models.py b/models.py index f2b8b15adf..84b6af8831 100755 --- a/models.py +++ b/models.py @@ -227,7 +227,7 @@ def __init__(self, cfg, img_size=(416, 416), verbose=False): # Darknet Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 self.version = np.array([0, 2, 5], dtype=np.int32) # (int32) version info: major, minor, revision self.seen = np.array([0], dtype=np.int64) # (int64) number of images seen during training - self.info(verbose) # print model description + self.info(verbose) if not ONNX_EXPORT else None # print model description def forward(self, x, augment=False, verbose=False): @@ -324,7 +324,7 @@ def fuse(self): break fused_list.append(a) self.module_list = fused_list - self.info() # yolov3-spp reduced from 225 to 152 layers + self.info() if not ONNX_EXPORT else None # yolov3-spp reduced from 225 to 152 layers def info(self, verbose=False): torch_utils.model_info(self, verbose) From 20a094ccb97fb30680219503eeb409b1c21946aa Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 15 Apr 2020 12:25:42 -0700 Subject: [PATCH 0673/1185] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 249bd7395e..62a5e08d8d 100755 --- a/README.md +++ b/README.md @@ -140,8 +140,8 @@ Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memo Class Images Targets P R mAP@0.5 F1: 100%|█████████| 313/313 [03:00<00:00, 1.74it/s] all 5e+03 3.51e+04 0.375 0.743 0.64 0.492 - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.455 - Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.646 + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.456 + Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.647 Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.496 Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.263 Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.501 From 510eadcfa59eefc17dd0f373bb45d3e8ebe68533 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 15 Apr 2020 12:54:56 -0700 Subject: [PATCH 0674/1185] Apex and 'git pull' suggestions --- train.py | 1 + utils/utils.py | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/train.py b/train.py index 71dcbb0586..7ca006b903 100644 --- a/train.py +++ b/train.py @@ -13,6 +13,7 @@ try: # Mixed precision training https://github.com/NVIDIA/apex from apex import amp except: + print('Apex recommended for mixed precision and faster training: https://github.com/NVIDIA/apex') mixed_precision = False # not installed wdir = 'weights' + os.sep # weights dir diff --git a/utils/utils.py b/utils/utils.py index d45d14cdad..adda3dcbd8 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -3,6 +3,7 @@ import os import random import shutil +import subprocess from pathlib import Path import cv2 @@ -18,6 +19,11 @@ matplotlib.rc('font', **{'size': 11}) +# Suggest 'git pull' +s = subprocess.check_output('git status -uno', shell=True).decode('utf-8') +if 'Your branch is behind' in s: + print(s[s.find('Your branch is behind'):s.find('\n\n')] + '\n') + # Set printoptions torch.set_printoptions(linewidth=320, precision=5, profile='long') np.set_printoptions(linewidth=320, formatter={'float_kind': '{:11.5g}'.format}) # format short g, %precision=5 From 716e618a18f9f0dffd9dc891522c370209204e94 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 15 Apr 2020 13:14:54 -0700 Subject: [PATCH 0675/1185] Update greetings.yml --- .github/workflows/greetings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index f9535cd287..3634626272 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -11,6 +11,6 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} pr-message: 'Hello @${{ github.actor }}, thank you for submitting a PR! We will respond as soon as possible.' issue-message: > - Hello @${{ github.actor }}, thank you for your interest in our work! Please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://colab.research.google.com/drive/1G8T-VFxQkjDe4idzN8F-hbIBqkkkQnxw), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. + Hello @${{ github.actor }}, thank you for your interest in our work! Please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://github.com/ultralytics/yolov3/blob/master/tutorial.ipynb), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. If this is a bug report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you. From c3edf8daf43b4cf31cff231bd35f1f7e5b32a6e6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 15 Apr 2020 22:03:51 -0700 Subject: [PATCH 0676/1185] move image size report --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 7ca006b903..09d42fec96 100644 --- a/train.py +++ b/train.py @@ -73,7 +73,6 @@ def train(): imgsz_max //= 0.667 grid_min, grid_max = imgsz_min // gs, imgsz_max // gs imgsz_min, imgsz_max = grid_min * gs, grid_max * gs - print('Image sizes %g - %g train, %g test' % (imgsz_min, imgsz_max, imgsz_test)) img_size = imgsz_max # initialize with max size # Configure run @@ -219,6 +218,7 @@ def train(): # torch.autograd.set_detect_anomaly(True) results = (0, 0, 0, 0, 0, 0, 0) # 'P', 'R', 'mAP', 'F1', 'val GIoU', 'val Objectness', 'val Classification' t0 = time.time() + print('Image sizes %g - %g train, %g test' % (imgsz_min, imgsz_max, imgsz_test)) print('Using %g dataloader workers' % nw) print('Starting training for %g epochs...' % epochs) for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ From bf1061c146167599b01612bbe3c10a65cc5cf905 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 16 Apr 2020 16:12:23 -0700 Subject: [PATCH 0677/1185] cleanup --- utils/layers.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/utils/layers.py b/utils/layers.py index 7662c6bd74..fee81ca101 100644 --- a/utils/layers.py +++ b/utils/layers.py @@ -42,7 +42,7 @@ def __init__(self, layers, weight=False): self.weight = weight # apply weights boolean self.n = len(layers) + 1 # number of layers if weight: - self.w = torch.nn.Parameter(torch.zeros(self.n), requires_grad=True) # layer weights + self.w = nn.Parameter(torch.zeros(self.n), requires_grad=True) # layer weights def forward(self, x, outputs): # Weights @@ -83,13 +83,13 @@ def __init__(self, in_ch, out_ch, k=(3, 5, 7), stride=1, dilation=1, bias=True, a[0] = 1 ch = np.linalg.lstsq(a, b, rcond=None)[0].round().astype(int) # solve for equal weight indices, ax = b - self.m = nn.ModuleList([torch.nn.Conv2d(in_channels=in_ch, - out_channels=ch[g], - kernel_size=k[g], - stride=stride, - padding=k[g] // 2, # 'same' pad - dilation=dilation, - bias=bias) for g in range(groups)]) + self.m = nn.ModuleList([nn.Conv2d(in_channels=in_ch, + out_channels=ch[g], + kernel_size=k[g], + stride=stride, + padding=k[g] // 2, # 'same' pad + dilation=dilation, + bias=bias) for g in range(groups)]) def forward(self, x): return torch.cat([m(x) for m in self.m], 1) From 693c06b26ca24f3cb24241ed3cf2a3cf03899341 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 18 Apr 2020 12:07:44 -0700 Subject: [PATCH 0678/1185] bug fix issues/1067 --- utils/datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/datasets.py b/utils/datasets.py index e2af1aae7d..bb2b21ae5f 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -601,7 +601,7 @@ def letterbox(img, new_shape=(416, 416), color=(114, 114, 114), auto=True, scale new_shape = (new_shape, new_shape) # Scale ratio (new / old) - r = max(new_shape) / max(shape) + r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) if not scaleup: # only scale down, do not scale up (for better test mAP) r = min(r, 1.0) From accce6b56532f6242215fbdd8df612e51aae091b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 18 Apr 2020 18:06:11 -0700 Subject: [PATCH 0679/1185] git status check bug fix --- utils/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index adda3dcbd8..41302a759b 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -20,7 +20,7 @@ matplotlib.rc('font', **{'size': 11}) # Suggest 'git pull' -s = subprocess.check_output('git status -uno', shell=True).decode('utf-8') +s = subprocess.check_output('if [ -d .git ]; then git status -uno; fi', shell=True).decode('utf-8') if 'Your branch is behind' in s: print(s[s.find('Your branch is behind'):s.find('\n\n')] + '\n') @@ -561,6 +561,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T # x[:, :4] = torch.mm(weights.T, x[:, :4]) weights = (box_iou(boxes[i], boxes) > iou_thres) * scores[None] # box weights x[i, :4] = torch.mm(weights / weights.sum(1, keepdim=True), x[:, :4]).float() # merged boxes + elif method == 'vision': i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) elif method == 'fast': # FastNMS from https://github.com/dbolya/yolact From be3f322375b26ed0beb30192e42b2f4cbab95d44 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 20 Apr 2020 09:57:15 -0700 Subject: [PATCH 0680/1185] Tensorboard out of try, iou_t to 0.10 --- train.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/train.py b/train.py index 09d42fec96..c4bab231cf 100644 --- a/train.py +++ b/train.py @@ -3,6 +3,7 @@ import torch.distributed as dist import torch.optim as optim import torch.optim.lr_scheduler as lr_scheduler +from torch.utils.tensorboard import SummaryWriter import test # import test.py to get mAP after each epoch from models import * @@ -13,7 +14,7 @@ try: # Mixed precision training https://github.com/NVIDIA/apex from apex import amp except: - print('Apex recommended for mixed precision and faster training: https://github.com/NVIDIA/apex') + print('Apex recommended for faster mixed precision training: https://github.com/NVIDIA/apex') mixed_precision = False # not installed wdir = 'weights' + os.sep # weights dir @@ -28,7 +29,7 @@ 'cls_pw': 1.0, # cls BCELoss positive_weight 'obj': 64.3, # obj loss gain (*=img_size/320 if img_size != 320) 'obj_pw': 1.0, # obj BCELoss positive_weight - 'iou_t': 0.225, # iou training threshold + 'iou_t': 0.1, # iou training threshold 'lr0': 0.01, # initial learning rate (SGD=5E-3, Adam=5E-4) 'lrf': 0.0005, # final learning rate (with cos scheduler) 'momentum': 0.937, # SGD momentum @@ -418,15 +419,8 @@ def train(): tb_writer = None if not opt.evolve: # Train normally - try: - # Start Tensorboard with "tensorboard --logdir=runs", view at http://localhost:6006/ - from torch.utils.tensorboard import SummaryWriter - - tb_writer = SummaryWriter() - print("Run 'tensorboard --logdir=runs' to view tensorboard at http://localhost:6006/") - except: - pass - + print('Start Tensorboard with "tensorboard --logdir=runs", view at http://localhost:6006/') + tb_writer = SummaryWriter() train() # train normally else: # Evolve hyperparameters (optional) From cdb69d59293eb5d6e889f1c3bfb7d1da3e694946 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 20 Apr 2020 16:34:00 -0700 Subject: [PATCH 0681/1185] cfg cleanup --- cfg/{yolov3s.cfg => yolov3-asff.cfg} | 223 ++++++++++++------------- cfg/yolov4-tiny-1cls.cfg | 233 --------------------------- cfg/yolov4-tiny.cfg | 233 --------------------------- 3 files changed, 103 insertions(+), 586 deletions(-) rename cfg/{yolov3s.cfg => yolov3-asff.cfg} (75%) delete mode 100644 cfg/yolov4-tiny-1cls.cfg delete mode 100644 cfg/yolov4-tiny.cfg diff --git a/cfg/yolov3s.cfg b/cfg/yolov3-asff.cfg similarity index 75% rename from cfg/yolov3s.cfg rename to cfg/yolov3-asff.cfg index 0517b09ebd..ec47ea3aae 100644 --- a/cfg/yolov3s.cfg +++ b/cfg/yolov3-asff.cfg @@ -1,3 +1,9 @@ +# Generated by Glenn Jocher (glenn.jocher@ultralytics.com) for https://github.com/ultralytics/yolov3 +# def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 640)): # from utils.utils import *; kmean_anchors() +# Evolving anchors: 100%|██████████| 1000/1000 [41:15<00:00, 2.48s/it] +# 0.20 iou_thr: 0.992 best possible recall, 4.25 anchors > thr +# kmeans anchors (n=12, img_size=(320, 640), IoU=0.005/0.184/0.634-min/mean/best): 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 + [net] # Testing # batch=1 @@ -28,7 +34,7 @@ filters=32 size=3 stride=1 pad=1 -activation=swish +activation=leaky # Downsample @@ -38,7 +44,7 @@ filters=64 size=3 stride=2 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -46,7 +52,7 @@ filters=32 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -54,7 +60,7 @@ filters=64 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -68,7 +74,7 @@ filters=128 size=3 stride=2 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -76,7 +82,7 @@ filters=64 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -84,7 +90,7 @@ filters=128 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -96,7 +102,7 @@ filters=64 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -104,7 +110,7 @@ filters=128 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -118,7 +124,7 @@ filters=256 size=3 stride=2 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -126,7 +132,7 @@ filters=128 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -134,7 +140,7 @@ filters=256 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -146,7 +152,7 @@ filters=128 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -154,7 +160,7 @@ filters=256 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -166,7 +172,7 @@ filters=128 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -174,7 +180,7 @@ filters=256 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -186,7 +192,7 @@ filters=128 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -194,20 +200,19 @@ filters=256 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 activation=linear - [convolutional] batch_normalize=1 filters=128 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -215,7 +220,7 @@ filters=256 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -227,7 +232,7 @@ filters=128 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -235,7 +240,7 @@ filters=256 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -247,7 +252,7 @@ filters=128 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -255,7 +260,7 @@ filters=256 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -267,7 +272,7 @@ filters=128 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -275,7 +280,7 @@ filters=256 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -289,7 +294,7 @@ filters=512 size=3 stride=2 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -297,7 +302,7 @@ filters=256 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -305,20 +310,19 @@ filters=512 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 activation=linear - [convolutional] batch_normalize=1 filters=256 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -326,20 +330,19 @@ filters=512 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 activation=linear - [convolutional] batch_normalize=1 filters=256 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -347,20 +350,19 @@ filters=512 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 activation=linear - [convolutional] batch_normalize=1 filters=256 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -368,7 +370,7 @@ filters=512 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -380,7 +382,7 @@ filters=256 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -388,20 +390,19 @@ filters=512 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 activation=linear - [convolutional] batch_normalize=1 filters=256 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -409,20 +410,19 @@ filters=512 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 activation=linear - [convolutional] batch_normalize=1 filters=256 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -430,7 +430,7 @@ filters=512 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -442,7 +442,7 @@ filters=256 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -450,7 +450,7 @@ filters=512 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -464,7 +464,7 @@ filters=1024 size=3 stride=2 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -472,7 +472,7 @@ filters=512 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -480,7 +480,7 @@ filters=1024 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -492,7 +492,7 @@ filters=512 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -500,7 +500,7 @@ filters=1024 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -512,7 +512,7 @@ filters=512 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -520,7 +520,7 @@ filters=1024 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -532,7 +532,7 @@ filters=512 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -540,7 +540,7 @@ filters=1024 size=3 stride=1 pad=1 -activation=swish +activation=leaky [shortcut] from=-3 @@ -554,7 +554,7 @@ filters=512 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -562,7 +562,7 @@ size=3 stride=1 pad=1 filters=1024 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -570,9 +570,9 @@ filters=512 size=1 stride=1 pad=1 -activation=swish +activation=leaky -### SPP ### +# SPP -------------------------------------------------------------------------- [maxpool] stride=1 size=5 @@ -593,8 +593,7 @@ size=13 [route] layers=-1,-3,-5,-6 - -### End SPP ### +# SPP -------------------------------------------------------------------------- [convolutional] batch_normalize=1 @@ -602,8 +601,7 @@ filters=512 size=1 stride=1 pad=1 -activation=swish - +activation=leaky [convolutional] batch_normalize=1 @@ -611,7 +609,7 @@ size=3 stride=1 pad=1 filters=1024 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -619,7 +617,7 @@ filters=512 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -627,29 +625,19 @@ size=3 stride=1 pad=1 filters=1024 -activation=swish +activation=leaky [convolutional] size=1 stride=1 pad=1 -filters=255 +filters=258 activation=linear - -[yolo] -mask = 6,7,8 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - +# YOLO ------------------------------------------------------------------------- [route] -layers = -4 +layers = -3 [convolutional] batch_normalize=1 @@ -657,7 +645,7 @@ filters=256 size=1 stride=1 pad=1 -activation=swish +activation=leaky [upsample] stride=2 @@ -665,15 +653,13 @@ stride=2 [route] layers = -1, 61 - - [convolutional] batch_normalize=1 filters=256 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -681,7 +667,7 @@ size=3 stride=1 pad=1 filters=512 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -689,7 +675,7 @@ filters=256 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -697,7 +683,7 @@ size=3 stride=1 pad=1 filters=512 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -705,7 +691,7 @@ filters=256 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -713,30 +699,19 @@ size=3 stride=1 pad=1 filters=512 -activation=swish +activation=leaky [convolutional] size=1 stride=1 pad=1 -filters=255 +filters=258 activation=linear - -[yolo] -mask = 3,4,5 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - +# YOLO ------------------------------------------------------------------------- [route] -layers = -4 +layers = -3 [convolutional] batch_normalize=1 @@ -744,7 +719,7 @@ filters=128 size=1 stride=1 pad=1 -activation=swish +activation=leaky [upsample] stride=2 @@ -752,15 +727,13 @@ stride=2 [route] layers = -1, 36 - - [convolutional] batch_normalize=1 filters=128 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -768,7 +741,7 @@ size=3 stride=1 pad=1 filters=256 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -776,7 +749,7 @@ filters=128 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -784,7 +757,7 @@ size=3 stride=1 pad=1 filters=256 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -792,7 +765,7 @@ filters=128 size=1 stride=1 pad=1 -activation=swish +activation=leaky [convolutional] batch_normalize=1 @@ -800,22 +773,32 @@ size=3 stride=1 pad=1 filters=256 -activation=swish +activation=leaky [convolutional] size=1 stride=1 pad=1 -filters=255 +filters=258 activation=linear +[yolo] +from=88,99,110 +mask = 8,9,10,11 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=80 +num=9 [yolo] -mask = 0,1,2 +from=88,99,110 +mask = 4,5,6,7 anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 classes=80 num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 + +[yolo] +from=88,99,110 +mask = 0,1,2,3 +anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 +classes=80 +num=9 \ No newline at end of file diff --git a/cfg/yolov4-tiny-1cls.cfg b/cfg/yolov4-tiny-1cls.cfg deleted file mode 100644 index 7cf2dd4ec3..0000000000 --- a/cfg/yolov4-tiny-1cls.cfg +++ /dev/null @@ -1,233 +0,0 @@ -# Generated by Glenn Jocher (glenn.jocher@ultralytics.com) for https://github.com/ultralytics/yolov3 -# def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 640)): # from utils.utils import *; kmean_anchors() -# Evolving anchors: 100%|██████████| 1000/1000 [41:15<00:00, 2.48s/it] -# 0.20 iou_thr: 0.992 best possible recall, 4.25 anchors > thr -# kmeans anchors (n=12, img_size=(320, 640), IoU=0.005/0.184/0.634-min/mean/best): 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 - -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 200000 -policy=steps -steps=180000,190000 -scales=.1,.1 - - -[convolutional] -batch_normalize=1 -filters=16 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=1 - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -########### - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=24 -activation=linear - - - -[yolo] -mask = 8,9,10,11 -anchors = 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 -classes=1 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 8 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=24 -activation=linear - -[yolo] -mask = 4,5,6,7 -anchors = 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 -classes=1 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 6 - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=24 -activation=linear - -[yolo] -mask = 0,1,2,3 -anchors = 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 -classes=1 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov4-tiny.cfg b/cfg/yolov4-tiny.cfg deleted file mode 100644 index 5548ca607f..0000000000 --- a/cfg/yolov4-tiny.cfg +++ /dev/null @@ -1,233 +0,0 @@ -# Generated by Glenn Jocher (glenn.jocher@ultralytics.com) for https://github.com/ultralytics/yolov3 -# def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 640)): # from utils.utils import *; kmean_anchors() -# Evolving anchors: 100%|██████████| 1000/1000 [41:15<00:00, 2.48s/it] -# 0.20 iou_thr: 0.992 best possible recall, 4.25 anchors > thr -# kmeans anchors (n=12, img_size=(320, 640), IoU=0.005/0.184/0.634-min/mean/best): 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 - -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 200000 -policy=steps -steps=180000,190000 -scales=.1,.1 - - -[convolutional] -batch_normalize=1 -filters=16 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=1 - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -########### - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - - - -[yolo] -mask = 8,9,10,11 -anchors = 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 8 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - -[yolo] -mask = 4,5,6,7 -anchors = 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 6 - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - -[yolo] -mask = 0,1,2,3 -anchors = 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 From 8b45360e28d7c4eaff180f49f000d10e2d18aa0a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 20 Apr 2020 16:47:28 -0700 Subject: [PATCH 0682/1185] detect cleanup --- detect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detect.py b/detect.py index 97eccd4853..b9eb3d8540 100644 --- a/detect.py +++ b/detect.py @@ -156,7 +156,7 @@ def detect(save_img=False): if save_txt or save_img: print('Results saved to %s' % os.getcwd() + os.sep + out) if platform == 'darwin': # MacOS - os.system('open ' + out + ' ' + save_path) + os.system('open ' + save_path) print('Done. (%.3fs)' % (time.time() - t0)) From 22a6c441ce90a1ea9a916ed49cd1649c4b1799e2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 21 Apr 2020 00:39:06 -0700 Subject: [PATCH 0683/1185] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 62a5e08d8d..c9166862de 100755 --- a/README.md +++ b/README.md @@ -171,7 +171,7 @@ $ python3 train.py --weights '' --cfg yolov3-spp.cfg --epochs 300 --batch 16 --a To access an up-to-date working environment (with all dependencies including CUDA/CUDNN, Python and PyTorch preinstalled), consider a: - **GCP** Deep Learning VM with $300 free credit offer: See our [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) -- **Google Colab Notebook** with 12 hours of free GPU time: [Google Colab Notebook](https://colab.research.google.com/drive/1G8T-VFxQkjDe4idzN8F-hbIBqkkkQnxw) +- **Google Colab Notebook** with 12 hours of free GPU time: [Google Colab Notebook](https://colab.sandbox.google.com/github/ultralytics/yolov3/blob/master/tutorial.ipynb) - **Docker Image** from https://hub.docker.com/r/ultralytics/yolov3. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) # Citation From 6aed6c5fd0b31b1053d538095d4488eff8d5ad88 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 21 Apr 2020 09:13:38 -0700 Subject: [PATCH 0684/1185] attempt_download() update for '' weights --- models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/models.py b/models.py index 84b6af8831..9d0d7de591 100755 --- a/models.py +++ b/models.py @@ -441,9 +441,10 @@ def convert(cfg='cfg/yolov3-spp.cfg', weights='weights/yolov3-spp.weights'): def attempt_download(weights): # Attempt to download pretrained weights if not found locally + weights = weights.strip() msg = weights + ' missing, try downloading from https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0' - if weights and not os.path.isfile(weights): + if len(weights) > 0 and not os.path.isfile(weights): d = {'yolov3-spp.weights': '16lYS4bcIdM2HdmyJBVDOvt3Trx6N3W2R', 'yolov3.weights': '1uTlyDWlnaqXcsKOktP5aH_zRDbfcDp-y', 'yolov3-tiny.weights': '1CCF-iNIIkYesIDzaPvdwlcf7H9zSsKZQ', From a5bd0fe567db07a0f3a248a40c0935912233ed3b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 21 Apr 2020 12:19:29 -0700 Subject: [PATCH 0685/1185] tensorboard comment=opt.name --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index c4bab231cf..c002be25a0 100644 --- a/train.py +++ b/train.py @@ -420,7 +420,7 @@ def train(): tb_writer = None if not opt.evolve: # Train normally print('Start Tensorboard with "tensorboard --logdir=runs", view at http://localhost:6006/') - tb_writer = SummaryWriter() + tb_writer = SummaryWriter(comment=opt.name) train() # train normally else: # Evolve hyperparameters (optional) From 03c6a2d6fa426df6db346637e69ab57879a6b3db Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 21 Apr 2020 12:31:37 -0700 Subject: [PATCH 0686/1185] cleanup --- utils/gcp.sh | 442 +-------------------------------------------------- 1 file changed, 5 insertions(+), 437 deletions(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index 932852c4ff..98c4ded7a8 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -3,6 +3,7 @@ # New VM rm -rf sample_data yolov3 git clone https://github.com/ultralytics/yolov3 +# git clone -b test --depth 1 https://github.com/ultralytics/yolov3 test # branch # sudo apt-get install zip #git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex sudo conda install -yc conda-forge scikit-image pycocotools @@ -12,14 +13,6 @@ python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_downlo python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('13g3LqdpkNE8sPosVJT6KFXlfoMypzRP4','sm4.zip')" sudo shutdown -# Re-clone -rm -rf yolov3 # Warning: remove existing -git clone https://github.com/ultralytics/yolov3 # master -bash yolov3/data/get_coco2017.sh -# git clone -b test --depth 1 https://github.com/ultralytics/yolov3 test # branch -cd yolov3 -python3 test.py --weights ultralytics68.pt --task benchmark - # Mount local SSD lsblk sudo mkfs.ext4 -F /dev/nvme0n1 @@ -28,43 +21,9 @@ sudo mount /dev/nvme0n1 /mnt/disks/nvme0n1 sudo chmod a+w /mnt/disks/nvme0n1 cp -r coco /mnt/disks/nvme0n1 -# Train -python3 train.py - -# Resume -python3 train.py --resume - -# Detect -python3 detect.py - -# Test -python3 test.py --save-json - # Kill All -t=ultralytics/yolov3:v240 -docker kill $(docker ps -a -q --filter ancestor=$t) -t=ultralytics/yolov3:v208 -docker kill $(docker ps -a -q --filter ancestor=$t) - -# Evolve wer -sudo -s -t=ultralytics/yolov3:v206 +t=ultralytics/yolov3:v1 docker kill $(docker ps -a -q --filter ancestor=$t) -for i in 0 1 2 3 0 1 2 3 -do - docker pull $t && docker run -d --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t bash utils/evolve.sh $i - sleep 180 -done - -# Evolve athena -sudo -s -t=ultralytics/yolov3:v208 -docker kill $(docker ps -a -q --filter ancestor=$t) -for i in 0 1 -do - docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/out:/usr/src/out $t bash utils/evolve.sh $i - sleep 120 -done # Evolve coco sudo -s @@ -76,397 +35,6 @@ do sleep 30 done - -t=ultralytics/yolov3:evolve && docker pull $t && docker run --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh 2 - - -# Git pull -git pull https://github.com/ultralytics/yolov3 # master -git pull https://github.com/ultralytics/yolov3 test # branch - -# Test Darknet training -python3 test.py --weights ../darknet/backup/yolov3.backup - -# Copy last.pt TO bucket -gsutil cp yolov3/weights/last1gpu.pt gs://ultralytics - -# Copy last.pt FROM bucket -gsutil cp gs://ultralytics/last.pt yolov3/weights/last.pt -wget https://storage.googleapis.com/ultralytics/yolov3/last_v1_0.pt -O weights/last_v1_0.pt -wget https://storage.googleapis.com/ultralytics/yolov3/best_v1_0.pt -O weights/best_v1_0.pt - -# Reproduce tutorials -rm results*.txt # WARNING: removes existing results -python3 train.py --nosave --data data/coco_1img.data && mv results.txt results0r_1img.txt -python3 train.py --nosave --data data/coco_10img.data && mv results.txt results0r_10img.txt -python3 train.py --nosave --data data/coco_100img.data && mv results.txt results0r_100img.txt -# python3 train.py --nosave --data data/coco_100img.data --transfer && mv results.txt results3_100imgTL.txt -python3 -c "from utils import utils; utils.plot_results()" -# gsutil cp results*.txt gs://ultralytics -gsutil cp results.png gs://ultralytics -sudo shutdown - -# Reproduce mAP -python3 test.py --save-json --img 608 -python3 test.py --save-json --img 416 -python3 test.py --save-json --img 320 -sudo shutdown - -# Benchmark script -git clone https://github.com/ultralytics/yolov3 # clone our repo -git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex # install nvidia apex -python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO','coco.zip')" # download coco dataset (20GB) -cd yolov3 && clear && python3 train.py --epochs 1 # run benchmark (~30 min) - -# Unit tests -python3 detect.py # detect 2 persons, 1 tie -python3 test.py --data data/coco_32img.data # test mAP = 0.8 -python3 train.py --data data/coco_32img.data --epochs 5 --nosave # train 5 epochs -python3 train.py --data data/coco_1cls.data --epochs 5 --nosave # train 5 epochs -python3 train.py --data data/coco_1img.data --epochs 5 --nosave # train 5 epochs - -# AlexyAB Darknet -gsutil cp -r gs://sm6/supermarket2 . # dataset from bucket -rm -rf darknet && git clone https://github.com/AlexeyAB/darknet && cd darknet && wget -c https://pjreddie.com/media/files/darknet53.conv.74 # sudo apt install libopencv-dev && make -./darknet detector calc_anchors data/coco_img64.data -num_of_clusters 9 -width 320 -height 320 # kmeans anchor calculation -./darknet detector train ../supermarket2/supermarket2.data ../yolo_v3_spp_pan_scale.cfg darknet53.conv.74 -map -dont_show # train spp -./darknet detector train ../yolov3/data/coco.data ../yolov3-spp.cfg darknet53.conv.74 -map -dont_show # train spp coco - -#Docker -sudo docker kill "$(sudo docker ps -q)" -sudo docker pull ultralytics/yolov3:v0 -sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco ultralytics/yolov3:v0 - - -t=ultralytics/yolov3:v70 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 32 --accum 2 --pre --bucket yolov4 --name 70 --device 0 --multi -t=ultralytics/yolov3:v73 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 73 --device 5 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v74 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 74 --device 0 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v75 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 75 --device 7 --cfg cfg/yolov3s.cfg -t=ultralytics/yolov3:v76 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 76 --device 0 --cfg cfg/yolov3-spp.cfg - -t=ultralytics/yolov3:v79 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 79 --device 5 -t=ultralytics/yolov3:v80 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 80 --device 0 -t=ultralytics/yolov3:v81 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 81 --device 7 -t=ultralytics/yolov3:v82 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 82 --device 0 --cfg cfg/yolov3s.cfg - -t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 83 --device 6 --multi --nosave -t=ultralytics/yolov3:v84 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 84 --device 0 --multi -t=ultralytics/yolov3:v85 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 85 --device 0 --multi -t=ultralytics/yolov3:v86 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 86 --device 1 --multi -t=ultralytics/yolov3:v87 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 87 --device 2 --multi -t=ultralytics/yolov3:v88 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 88 --device 3 --multi -t=ultralytics/yolov3:v89 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 89 --device 1 -t=ultralytics/yolov3:v90 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 90 --device 0 --cfg cfg/yolov3-spp-matrix.cfg -t=ultralytics/yolov3:v91 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 91 --device 0 --cfg cfg/yolov3-spp-matrix.cfg - -t=ultralytics/yolov3:v92 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 92 --device 0 -t=ultralytics/yolov3:v93 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 27 --batch 16 --accum 4 --pre --bucket yolov4 --name 93 --device 0 --cfg cfg/yolov3-spp-matrix.cfg - - -#SM4 -t=ultralytics/yolov3:v96 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 96 --device 0 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -t=ultralytics/yolov3:v97 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 32 --accum 2 --pre --bucket yolov4 --name 97 --device 4 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -t=ultralytics/yolov3:v98 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'ultralytics68.pt' --epochs 1000 --img 320 --batch 16 --accum 4 --pre --bucket yolov4 --name 98 --device 5 --multi --cfg cfg/yolov3-spp-3cls.cfg --data ../data/sm4/out.data --nosave -t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --pre --bucket yolov4 --name 101 --device 7 --multi --nosave - -t=ultralytics/yolov3:v102 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 1000 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 102 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v103 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 103 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v104 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 104 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v105 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 105 --device 0 --cfg cfg/yolov3-tiny-3cls.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v106 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --weights 'yolov3-tiny.pt' --epochs 500 --img 320 --batch 64 --accum 1 --pre --bucket yolov4 --name 106 --device 0 --cfg cfg/yolov3-tiny-3cls-sm4.cfg --data ../data/sm4/out.data --nosave --cache -t=ultralytics/yolov3:v107 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 107 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg -t=ultralytics/yolov3:v108 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 108 --device 7 --nosave - -t=ultralytics/yolov3:v109 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 109 --device 4 --multi --nosave -t=ultralytics/yolov3:v110 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --bucket yolov4 --name 110 --device 3 --multi --nosave - -t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 111 --device 0 -t=ultralytics/yolov3:v112 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 112 --device 1 --nosave -t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 113 --device 2 --nosave -t=ultralytics/yolov3:v114 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 114 --device 2 --nosave -t=ultralytics/yolov3:v113 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 115 --device 5 --nosave --cfg cfg/yolov3-spp3.cfg -t=ultralytics/yolov3:v116 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 116 --device 1 --nosave - -t=ultralytics/yolov3:v83 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 117 --device 0 --nosave --multi -t=ultralytics/yolov3:v118 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 16 --accum 4 --epochs 27 --pre --bucket yolov4 --name 118 --device 5 --nosave --multi -t=ultralytics/yolov3:v119 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 119 --device 1 --nosave -t=ultralytics/yolov3:v120 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 120 --device 2 --nosave -t=ultralytics/yolov3:v121 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 121 --device 0 --nosave --cfg cfg/csresnext50-panet-spp.cfg -t=ultralytics/yolov3:v122 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 122 --device 2 --nosave -t=ultralytics/yolov3:v123 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 273 --pre --bucket yolov4 --name 123 --device 5 --nosave - -t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 124 --device 0 --nosave --cfg yolov3-tiny -t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 125 --device 1 --nosave --cfg yolov3-tiny2 -t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 126 --device 1 --nosave --cfg yolov3-tiny3 -t=ultralytics/yolov3:v127 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 127 --device 0 --nosave --cfg yolov3-tiny4 -t=ultralytics/yolov3:v124 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 128 --device 1 --nosave --cfg yolov3-tiny2 --multi -t=ultralytics/yolov3:v129 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 64 --accum 1 --epochs 273 --pre --bucket yolov4 --name 129 --device 0 --nosave --cfg yolov3-tiny2 - -t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 130 --device 0 --nosave -t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 250 --pre --bucket yolov4 --name 131 --device 0 --nosave --multi -t=ultralytics/yolov3:v130 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 132 --device 0 --nosave --data coco2014.data -t=ultralytics/yolov3:v133 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 22 --accum 3 --epochs 27 --pre --bucket yolov4 --name 133 --device 0 --nosave --multi -t=ultralytics/yolov3:v134 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 134 --device 0 --nosave --data coco2014.data - -t=ultralytics/yolov3:v135 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 135 --device 0 --nosave --multi --data coco2014.data -t=ultralytics/yolov3:v136 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 24 --accum 3 --epochs 270 --pre --bucket yolov4 --name 136 --device 0 --nosave --multi --data coco2014.data - -t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 137 --device 7 --nosave --data coco2014.data -t=ultralytics/yolov3:v137 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --bucket yolov4 --name 138 --device 6 --nosave --data coco2014.data - -t=ultralytics/yolov3:v140 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 140 --device 1 --nosave --data coco2014.data --arc uBCE -t=ultralytics/yolov3:v141 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 141 --device 0 --nosave --data coco2014.data --arc uBCE -t=ultralytics/yolov3:v142 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --batch 32 --accum 2 --epochs 27 --pre --bucket yolov4 --name 142 --device 1 --nosave --data coco2014.data --arc uBCE - -t=ultralytics/yolov3:v146 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 146 --device 0 --nosave --data coco2014.data -t=ultralytics/yolov3:v147 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 147 --device 1 --nosave --data coco2014.data -t=ultralytics/yolov3:v148 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 148 --device 2 --nosave --data coco2014.data -t=ultralytics/yolov3:v149 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 149 --device 3 --nosave --data coco2014.data -t=ultralytics/yolov3:v150 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 150 --device 4 --nosave --data coco2014.data -t=ultralytics/yolov3:v151 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 151 --device 5 --nosave --data coco2014.data -t=ultralytics/yolov3:v152 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 152 --device 6 --nosave --data coco2014.data -t=ultralytics/yolov3:v153 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 153 --device 7 --nosave --data coco2014.data - -t=ultralytics/yolov3:v154 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 154 --device 0 --nosave --data coco2014.data -t=ultralytics/yolov3:v155 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 155 --device 0 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v156 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 156 --device 5 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v157 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 157 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v158 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 158 --device 7 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v159 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 159 --device 0 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v160 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 160 --device 1 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v161 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 161 --device 2 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v162 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 162 --device 3 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v163 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 163 --device 4 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v164 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 164 --device 5 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v165 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 165 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v166 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 166 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v167 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 167 --device 7 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v168 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 168 --device 5 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v169 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 169 --device 6 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v170 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 170 --device 7 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v171 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 171 --device 4 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v172 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 172 --device 3 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v173 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 173 --device 2 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v174 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 174 --device 1 --nosave --data coco2014.data --arc defaultpw -t=ultralytics/yolov3:v175 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 320 --batch 64 --accum 1 --epochs 27 --pre --bucket yolov4 --name 175 --device 0 --nosave --data coco2014.data --arc defaultpw - -t=ultralytics/yolov3:v177 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 177 --device 0 --nosave --data coco2014.data --multi -t=ultralytics/yolov3:v178 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 178 --device 0 --nosave --data coco2014.data --multi -t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --img 416 --batch 22 --accum 3 --epochs 273 --pre --bucket yolov4 --name 179 --device 0 --nosave --data coco2014.data --multi --cfg yolov3s-18a.cfg - -t=ultralytics/yolov3:v143 && sudo docker build -t $t . && sudo docker push $t - -t=ultralytics/yolov3:v179 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 179 -t=ultralytics/yolov3:v180 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 180 -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 181 --cfg yolov3s9a-640.cfg -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 182 --cfg yolov3s9a-320-640.cfg -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 183 --cfg yolov3s15a-640.cfg -t=ultralytics/yolov3:v183 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 184 --cfg yolov3s15a-320-640.cfg - -t=ultralytics/yolov3:v185 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 185 -t=ultralytics/yolov3:v186 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 186 -n=187 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -t=ultralytics/yolov3:v189 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name 188 --cfg yolov3s15a-320-640.cfg -n=190 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=191 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=192 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n - -n=193 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=194 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=195 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=196 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 10 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n - -n=197 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n -n=198 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 640 --epochs 273 --batch 22 --accum 3 --weights '' --arc defaultpw --pre --multi --bucket yolov4 --name $n - - -# athena -n=199 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 0 -n=200 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 6 -n=207 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --bucket ultralytics/athena --name $n --device 7 -n=208 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 -n=211 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg -n=212 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg -n=213 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg -n=214 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg -n=215 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --cfg yolov3-spp-1cls.cfg -n=217 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --arc default --pre --multi --device 6 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=219 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc default --pre --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=220 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 20 --batch 8 --accum 8 --weights ultralytics68.pt --arc default --pre --multi --device 1 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=221 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 30 --batch 8 --accum 8 --weights ultralytics68.pt --arc default --pre --multi --device 2 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=222 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 40 --batch 8 --accum 8 --weights ultralytics68.pt --arc default --pre --multi --device 3 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=223 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=224 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 20 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 1 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=225 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 30 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=226 && t=ultralytics/yolov3:v215 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 40 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --pre --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=227 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=228 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 20 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=229 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 20 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=240 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 0 -n=241 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 1 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 1 -n=242 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 2 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 3 -n=243 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 3 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 5 -n=244 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 4 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 7 -n=245 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights '' --arc defaultpw --multi --device 5 --bucket ult/athena --name $n --nosave --cfg yolov3-1cls.cfg -n=246 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights '' --arc defaultpw --multi --device 6 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=247 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights '' --arc defaultpw --multi --device 7 --bucket ult/athena --name $n --nosave --cfg yolov3-spp3-1cls.cfg -n=248 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights darknet53.conv.74 --arc defaultpw --multi --device 5 --bucket ult/athena --name $n --nosave --cfg yolov3-1cls.cfg -n=249 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights darknet53.conv.74 --arc defaultpw --multi --device 6 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=250 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights darknet53.conv.74 --arc defaultpw --multi --device 7 --bucket ult/athena --name $n --nosave --cfg yolov3-spp3-1cls.cfg -n=251 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 3 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 9 -n=252 && t=ultralytics/yolov3:v240 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --arc defaultpw --multi --device 4 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg --var 100 -n=253 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 60 --batch 8 --accum 8 --weights darknet53.conv.74 --arc defaultpw --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-1cls.cfg -n=254 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 60 --batch 8 --accum 8 --weights darknet53.conv.74 --arc defaultpw --multi --device 1 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=255 && t=ultralytics/yolov3:v245 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 60 --batch 8 --accum 8 --weights darknet53.conv.74 --arc defaultpw --multi --device 2 --bucket ult/athena --name $n --nosave --cfg yolov3-spp3-1cls.cfg - - -# wer -n=201 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 0 --cfg yolov3-tiny-3cls.cfg -n=202 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 1 --cfg yolov3-tiny-3cls-sm4.cfg -n=203 && t=ultralytics/yolov3:v201 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 2 --cfg yolov3-tiny-3cls-sm4.cfg -n=204 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 3 --cfg yolov3-tiny-3cls-sm4.cfg -n=205 && t=ultralytics/yolov3:v202 && sudo docker pull $t && sudo docker run -it --gpus all -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --arc defaultpw --pre --multi --bucket ult/wer --name $n --device 4 --cfg yolov3-tiny-3cls-sm4.cfg -n=206 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --notest --nosave --cache --device 0 --cfg yolov3-tiny-3cls.cfg -n=209 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 3 --cfg yolov3-tiny-3cls.cfg -n=210 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-3cls.cfg -n=216 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --pre --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-3cls.cfg -n=218 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc default --pre --multi --bucket ult/wer --name $n --nosave --cache --device 7 --cfg yolov3-tiny-3cls.cfg -n=230 && t=ultralytics/athena:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single -n=231 && t=ultralytics/athena:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-1cls.cfg --single -n=232 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single -n=233 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single -n=234 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run --gpus all --ipc=host -it -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 416 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single -n=235 && t=ultralytics/yolov3:v206 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi 1.2 --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single -n=236 && t=ultralytics/yolov3:v206 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi 1.4 --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single -n=237 && t=ultralytics/yolov3:v206 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi 1.6 --bucket ult/wer --name $n --nosave --device 1 --cfg yolov3-tiny-1cls.cfg --single -n=238 && t=ultralytics/yolov3:v206 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi 1.8 --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single -n=239 && t=ultralytics/yolov3:v206 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi 2.0 --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single -n=256 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 500 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 6 --cfg yolov3-tiny-1cls.cfg --single -n=257 && t=ultralytics/yolov3:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 500 --batch 64 --accum 1 --weights yolov3-tiny.pt --arc defaultpw --multi --bucket ult/wer --name $n --nosave --cache --device 7 --cfg yolov3-tiny-1cls.cfg --single --adam - - -#coco -n=2 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --nosave --bucket ult/coco --name $n --device 0 --multi -n=3 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 1 --cfg yolov3.cfg --nosave --bucket ult/coco --name $n -n=4 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 2 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n -n=5 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -d --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 3 --cfg yolov3-spp3.cfg --nosave --bucket ult/coco --name $n -n=6 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 0 --cfg yolov4.cfg --nosave --bucket ult/coco --name $n -n=7 && t=ultralytics/coco:v3 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 1 --cfg yolov4s.cfg --nosave --bucket ult/coco --name $n -n=8 && t=ultralytics/coco:v8 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 384 --epochs 27 --batch 32 --accum 2 --weights '' --device 0 --cfg yolov4.cfg --nosave --bucket ult/coco --name $n -n=9 && t=ultralytics/coco:v9 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 20 --accum 3 --weights '' --device 0 --cfg yolov4a.cfg --nosave --bucket ult/coco --name $n --multi -n=10 && t=ultralytics/coco:v9 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 20 --accum 3 --weights '' --device 0 --cfg yolov4b.cfg --nosave --bucket ult/coco --name $n --multi -n=11 && t=ultralytics/coco:v9 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 20 --accum 3 --weights '' --device 0 --cfg yolov4c.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=12 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 20 --accum 3 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi -n=13 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 20 --accum 3 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi -n=14 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 20 --accum 3 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi -n=15 && t=ultralytics/coco:v14 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi -n=16 && t=ultralytics/coco:v9 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov4a.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=17 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov4d.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=18 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov4a.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=19 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov4e.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=20 && t=ultralytics/coco:v14 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=21 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppe.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=22 && t=ultralytics/coco:v14 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 27 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=23 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=24 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=25 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 27 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=26 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=27 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=28 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=29 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 15 --accum 4 --weights '' --device 0 --cfg yolov4a.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=30 && t=ultralytics/coco:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=31 && t=ultralytics/coco:v31 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppf.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=32 && t=ultralytics/coco:v31 && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppg.cfg --nosave --bucket ult/coco --name $n --multi -n=33 && t=ultralytics/coco:v33 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=34 && t=ultralytics/coco:v34 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 12 --accum 6 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=35 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=36 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 1 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=37 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 2 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=38 && t=ultralytics/coco:v35 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 10 --accum 8 --weights '' --device 3 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=39 && t=ultralytics/coco:v35 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 10 --accum 6 --weights '' --device 4 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=40 && t=ultralytics/coco:v35 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 5 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=41 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 6 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=42 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 7 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=45 && t=ultralytics/coco:v45 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 16 --weights '' --device 2 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=46 && t=ultralytics/coco:v45 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 4 --weights '' --device 6 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=47 && t=ultralytics/coco:v45 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 2 --weights '' --device 7 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=48 && t=ultralytics/coco:v45 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 3 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=49 && t=ultralytics/coco:v45 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 32 --weights '' --device 4 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=50 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 3 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=51 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 4 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=52 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 2 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=53 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 5 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n -n=54 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --nosave --bucket ult/coco --name $n --device 0 --multi -n=55 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --weights '' --epochs 273 --batch 16 --accum 4 --pre --nosave --bucket ult/coco --name $n --device 2 --multi -n=56 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 3 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi -n=57 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 4 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi -n=58 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi -n=59 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi -n=60 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 608 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 1 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi -n=61 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=62 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi -n=63 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi -n=64 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 1 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi -n=65 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=66 && t=ultralytics/coco:v65 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 0 --cfg darknet53-bifpn3.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=67 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 15 --accum 4 --weights '' --device 0 --cfg csdarknet53-bifpn-optimal.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=68 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=69 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 15 --accum 4 --weights '' --device 0 --cfg csdarknet53-bifpn-optimal.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=70 && t=ultralytics/coco:v69 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 15 --accum 4 --weights '' --device 0 --cfg csresnext50-bifpn-optimal.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=71 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=72 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=73 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=74 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=75 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=76 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=77 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=78 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=79 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=80 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=81 && t=ultralytics/coco:v76 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2017.data --img-size 512 608 --epochs 27 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=82 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=83 && t=ultralytics/coco:v82 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=84 && t=ultralytics/coco:v82 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=85 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=86 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=87 && t=ultralytics/coco:v85 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=88 && t=ultralytics/coco:v86 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 1 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=89 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 0 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=90 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --weights '' --device 1 --cfg yolov3-sppa.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=91 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=92 && t=ultralytics/coco:v91 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 225 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=93 && t=ultralytics/coco:v86 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=94 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=95 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=96 && t=ultralytics/coco:v94 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 64 --accum 1 --weights '' --device 0 --cfg yolov4-tiny.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=97 && t=ultralytics/coco:v94 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 64 --accum 1 --weights '' --device 1 --cfg yolov4-tiny-spp.cfg --nosave --bucket ult/coco --name $n --multi -n=98 && t=ultralytics/coco:v94 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 64 --accum 1 --weights '' --device 0 --cfg yolov4-tiny-spp-dn53.cfg --nosave --bucket ult/coco --name $n --multi --cache && sudo shutdown -n=99 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov4-asff.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=100 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=101 && t=ultralytics/coco:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi && sudo shutdown -n=102 && t=ultralytics/coco:v101 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 416 608 --epochs 273 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n --multi --arc Fdefault && sudo shutdown - - -# athena -n=32 && t=ultralytics/athena:v32 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 100 --batch 8 --accum 8 --weights ultralytics68.pt --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=33 && t=ultralytics/athena:v33 && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=34 && t=ultralytics/athena:v33 && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 20 --batch 8 --accum 8 --weights ultralytics68.pt --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg -n=35 && t=ultralytics/athena:v33 && sudo docker pull $t && sudo docker run --gpus all --ipc=host -v "$(pwd)"/out:/usr/src/out $t python3 train.py --data ../out/data.data --img-size 608 --epochs 30 --batch 8 --accum 8 --weights ultralytics68.pt --multi --device 0 --bucket ult/athena --name $n --nosave --cfg yolov3-spp-1cls.cfg && sudo shutdown - - -# wer -n=18 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-1cls.cfg --single --adam -n=19 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tiny-3l-1cls.cfg --single --adam -n=20 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --name $n --nosave --cache --device 2 --cfg yolov3-tiny-prnc-1cls.cfg --single --adam -n=21 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --name $n --nosave --cache --device 3 --cfg yolov3-tiny-prn-1cls.cfg --single --adam -n=22 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights '' --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny-3l-1cls.cfg --single --adam -n=23 && t=ultralytics/wer:v18 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights '' --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov3-tinyr-3l-1cls.cfg --single --adam -n=24 && t=ultralytics/wer:v24 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights '' --multi --bucket ult/wer --name $n --nosave --cache --device 3 --cfg yolov3-tiny-3l-1cls.cfg --single --adam -n=25 && t=ultralytics/wer:v25 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 2 --cfg yolov3-tiny3-1cls.cfg --single --adam -n=26 && t=ultralytics/wer:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov3-tiny3-1cls.cfg --single --adam -n=27 && t=ultralytics/test:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 416 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 1 --cfg yolov4-tiny-1cls.cfg --single --adam -n=28 && t=ultralytics/test:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 416 --epochs 1000 --batch 64 --accum 1 --weights yolov3-tiny.pt --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov4-tiny-1cls.cfg --single --adam -n=29 && t=ultralytics/wer:v$n && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/data:/usr/src/data $t python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 1000 --batch 64 --accum 1 --weights '' --multi --bucket ult/wer --name $n --nosave --cache --device 0 --cfg yolov4-tiny-spp-1cls-dn53.cfg --single --adam +#COCO training +n=131 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 256 768 768 --epochs 300 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n && sudo shutdown +n=132 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 256 768 768 --epochs 300 --batch 64 --accum 1 --weights '' --device 0 --cfg yolov3-tiny.cfg --nosave --bucket ult/coco --name $n && sudo shutdown From 2f636d5740df8b22c3a47460002953f7c148ab56 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Apr 2020 10:46:26 -0700 Subject: [PATCH 0687/1185] .half() bug fix --- detect.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/detect.py b/detect.py index b9eb3d8540..b94903c159 100644 --- a/detect.py +++ b/detect.py @@ -75,7 +75,8 @@ def detect(save_img=False): # Run inference t0 = time.time() - _ = model(torch.zeros((1, 3, img_size, img_size), device=device)) if device.type != 'cpu' else None # run once + img = torch.zeros((1, 3, img_size, img_size), device=device) # init img + _ = model(img.half() if half else img.float()) if device.type != 'cpu' else None # run once for path, img, im0s, vid_cap in dataset: img = torch.from_numpy(img).to(device) img = img.half() if half else img.float() # uint8 to fp16/32 From 77b3829d56a88e6f4494f7b33a7c08d4b58ea2de Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Apr 2020 11:02:09 -0700 Subject: [PATCH 0688/1185] check_git_status() to train.py --- train.py | 3 +-- utils/utils.py | 15 ++++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/train.py b/train.py index c002be25a0..b0885308bf 100644 --- a/train.py +++ b/train.py @@ -23,7 +23,6 @@ results_file = 'results.txt' # Hyperparameters https://github.com/ultralytics/yolov3/issues/310 - hyp = {'giou': 3.54, # giou loss gain 'cls': 37.4, # cls loss gain 'cls_pw': 1.0, # cls BCELoss positive_weight @@ -54,7 +53,6 @@ if hyp['fl_gamma']: print('Using FocalLoss(gamma=%g)' % hyp['fl_gamma']) - def train(): cfg = opt.cfg data = opt.data @@ -408,6 +406,7 @@ def train(): parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') opt = parser.parse_args() opt.weights = last if opt.resume else opt.weights + check_git_status() print(opt) opt.img_size.extend([opt.img_size[-1]] * (3 - len(opt.img_size))) # extend to 3 sizes (min, max, test) device = torch_utils.select_device(opt.device, apex=mixed_precision, batch_size=opt.batch_size) diff --git a/utils/utils.py b/utils/utils.py index 41302a759b..7adfa76a72 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -17,16 +17,10 @@ from . import torch_utils # , google_utils -matplotlib.rc('font', **{'size': 11}) - -# Suggest 'git pull' -s = subprocess.check_output('if [ -d .git ]; then git status -uno; fi', shell=True).decode('utf-8') -if 'Your branch is behind' in s: - print(s[s.find('Your branch is behind'):s.find('\n\n')] + '\n') - # Set printoptions torch.set_printoptions(linewidth=320, precision=5, profile='long') np.set_printoptions(linewidth=320, formatter={'float_kind': '{:11.5g}'.format}) # format short g, %precision=5 +matplotlib.rc('font', **{'size': 11}) # Prevent OpenCV from multithreading (to use PyTorch DataLoader) cv2.setNumThreads(0) @@ -38,6 +32,13 @@ def init_seeds(seed=0): torch_utils.init_seeds(seed=seed) +def check_git_status(): + # Suggest 'git pull' if repo is out of date + s = subprocess.check_output('if [ -d .git ]; then git fetch && git status -uno; fi', shell=True).decode('utf-8') + if 'Your branch is behind' in s: + print(s[s.find('Your branch is behind'):s.find('\n\n')] + '\n') + + def load_classes(path): # Loads *.names file at 'path' with open(path, 'r') as f: From 7cbac5a3ea4f6531d471e7a408b340f1a95f844a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Apr 2020 11:34:34 -0700 Subject: [PATCH 0689/1185] train.py iou_t to 0.20 --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index b0885308bf..253f1b1895 100644 --- a/train.py +++ b/train.py @@ -28,7 +28,7 @@ 'cls_pw': 1.0, # cls BCELoss positive_weight 'obj': 64.3, # obj loss gain (*=img_size/320 if img_size != 320) 'obj_pw': 1.0, # obj BCELoss positive_weight - 'iou_t': 0.1, # iou training threshold + 'iou_t': 0.20, # iou training threshold 'lr0': 0.01, # initial learning rate (SGD=5E-3, Adam=5E-4) 'lrf': 0.0005, # final learning rate (with cos scheduler) 'momentum': 0.937, # SGD momentum From 82a12e2c8e6afa54115a2bd605bfb8f18ec26f65 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Apr 2020 11:38:48 -0700 Subject: [PATCH 0690/1185] docker train update --- utils/gcp.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index 98c4ded7a8..ad99d8e42a 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -36,5 +36,5 @@ do done #COCO training -n=131 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 256 768 768 --epochs 300 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n && sudo shutdown -n=132 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 256 768 768 --epochs 300 --batch 64 --accum 1 --weights '' --device 0 --cfg yolov3-tiny.cfg --nosave --bucket ult/coco --name $n && sudo shutdown +n=131 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 640 --epochs 300 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n && sudo shutdown +n=132 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 640 --epochs 300 --batch 64 --accum 1 --weights '' --device 0 --cfg yolov3-tiny.cfg --nosave --bucket ult/coco --name $n && sudo shutdown From 345d65d18f96a6f2f3908fb613c71130c05fa060 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Apr 2020 14:32:05 -0700 Subject: [PATCH 0691/1185] updated train default img_size 320-640 --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 253f1b1895..c0f21dfa34 100644 --- a/train.py +++ b/train.py @@ -391,7 +391,7 @@ def train(): parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data path') parser.add_argument('--multi-scale', action='store_true', help='adjust (67%% - 150%%) img_size every 10 batches') - parser.add_argument('--img-size', nargs='+', type=int, default=[512], help='[min_train, max-train, test] img sizes') + parser.add_argument('--img-size', nargs='+', type=int, default=[320, 640], help='[min_train, max-train, test] img sizes') parser.add_argument('--rect', action='store_true', help='rectangular training') parser.add_argument('--resume', action='store_true', help='resume training from last.pt') parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') From 748f60baaec2657c94a8672567bc3b974f1de994 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Apr 2020 14:32:51 -0700 Subject: [PATCH 0692/1185] updated test default img_size 512 --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 67006c7543..75568a0326 100644 --- a/test.py +++ b/test.py @@ -229,7 +229,7 @@ def test(cfg, parser.add_argument('--data', type=str, default='data/coco2014.data', help='*.data path') parser.add_argument('--weights', type=str, default='weights/yolov3-spp-ultralytics.pt', help='weights path') parser.add_argument('--batch-size', type=int, default=16, help='size of each image batch') - parser.add_argument('--img-size', type=int, default=416, help='inference size (pixels)') + parser.add_argument('--img-size', type=int, default=512, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') parser.add_argument('--iou-thres', type=float, default=0.6, help='IOU threshold for NMS') parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') From dda0afa22e938b6641665ebf88ccb3b87e4f2461 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Apr 2020 16:00:20 -0700 Subject: [PATCH 0693/1185] onnx export IO layer names update --- detect.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/detect.py b/detect.py index b94903c159..635d705978 100644 --- a/detect.py +++ b/detect.py @@ -45,7 +45,8 @@ def detect(save_img=False): model.fuse() img = torch.zeros((1, 3) + img_size) # (1, 3, 320, 192) f = opt.weights.replace(opt.weights.split('.')[-1], 'onnx') # *.onnx filename - torch.onnx.export(model, img, f, verbose=False, opset_version=11) + torch.onnx.export(model, img, f, verbose=False, opset_version=11, + input_names=['images'], output_names=['classes', 'boxes']) # Validate exported model import onnx From aa854ecaa97c49a25ab2d956f8f1b05e7e37e254 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Apr 2020 17:54:56 -0700 Subject: [PATCH 0694/1185] torch >= 1.5 --- README.md | 7 +------ requirements.txt | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c9166862de..fb19abfabe 100755 --- a/README.md +++ b/README.md @@ -26,12 +26,7 @@ The https://github.com/ultralytics/yolov3 repo contains inference and training c # Requirements -Python 3.7 or later with all of the `pip install -U -r requirements.txt` packages including: -- `torch >= 1.4` -- `opencv-python` -- `Pillow` - -All dependencies are included in the associated docker images. Docker requirements are: +Python 3.7 or later with all of the `pip install -U -r requirements.txt` packages including `torch >= 1.5`. Docker images come with all dependencies preinstalled. Docker requirements are: - Nvidia Driver >= 440.44 - Docker Engine - CE >= 19.03 diff --git a/requirements.txt b/requirements.txt index a468438941..e705c8c0be 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # pip install -U -r requirements.txt numpy opencv-python >= 4.1 -torch >= 1.4 +torch >= 1.5 matplotlib pycocotools tqdm From c29be7f85d7c974c6f5a2edc0a14093385be9033 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 22 Apr 2020 17:55:23 -0700 Subject: [PATCH 0695/1185] torch >= 1.5 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb19abfabe..d58ba32d29 100755 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ The https://github.com/ultralytics/yolov3 repo contains inference and training c # Requirements -Python 3.7 or later with all of the `pip install -U -r requirements.txt` packages including `torch >= 1.5`. Docker images come with all dependencies preinstalled. Docker requirements are: +Python 3.7 or later with all `pip install -U -r requirements.txt` packages including `torch >= 1.5`. Docker images come with all dependencies preinstalled. Docker requirements are: - Nvidia Driver >= 440.44 - Docker Engine - CE >= 19.03 From b3dfd89878397fc347f74cec9e782cb1c3ca049f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 23 Apr 2020 10:35:08 -0700 Subject: [PATCH 0696/1185] scheduler resume bug fix --- train.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/train.py b/train.py index c0f21dfa34..e65161e59c 100644 --- a/train.py +++ b/train.py @@ -146,11 +146,11 @@ def train(): if mixed_precision: model, optimizer = amp.initialize(model, optimizer, opt_level='O1', verbosity=0) - # Scheduler https://github.com/ultralytics/yolov3/issues/238 - lf = lambda x: (((1 + math.cos( - x * math.pi / epochs)) / 2) ** 1.0) * 0.95 + 0.05 # cosine https://arxiv.org/pdf/1812.01187.pdf - scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf, last_epoch=start_epoch - 1) - # scheduler = lr_scheduler.MultiStepLR(optimizer, [round(epochs * x) for x in [0.8, 0.9]], 0.1, start_epoch - 1) + # Scheduler https://arxiv.org/pdf/1812.01187.pdf + lf = lambda x: (((1 + math.cos(x * math.pi / epochs)) / 2) ** 1.0) * 0.95 + 0.05 # cosine + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) + scheduler.last_epoch=start_epoch - 1 # see link below + # https://discuss.pytorch.org/t/a-problem-occured-when-resuming-an-optimizer/28822 # Plot lr schedule # y = [] From 5a8efa5c1d5f8a0099f649e3af0d3853f3334b50 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 23 Apr 2020 14:32:28 -0700 Subject: [PATCH 0697/1185] auto --accumulate --- train.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/train.py b/train.py index e65161e59c..ddeda1a775 100644 --- a/train.py +++ b/train.py @@ -58,7 +58,7 @@ def train(): data = opt.data epochs = opt.epochs # 500200 batches at bs 64, 117263 images = 273 epochs batch_size = opt.batch_size - accumulate = opt.accumulate # effective bs = batch_size * accumulate = 16 * 4 = 64 + accumulate = max(round(64 / batch_size), 1) # accumulate n times before optimizer update (bs 64) weights = opt.weights # initial training weights imgsz_min, imgsz_max, imgsz_test = opt.img_size # img sizes (min, max, test) @@ -387,7 +387,6 @@ def train(): parser = argparse.ArgumentParser() parser.add_argument('--epochs', type=int, default=300) # 500200 batches at bs 16, 117263 COCO images = 273 epochs parser.add_argument('--batch-size', type=int, default=16) # effective bs = batch_size * accumulate = 16 * 4 = 64 - parser.add_argument('--accumulate', type=int, default=4, help='batches to accumulate before optimizing') parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data path') parser.add_argument('--multi-scale', action='store_true', help='adjust (67%% - 150%%) img_size every 10 batches') From 3554ab07fbedc05d91d9e6907b96a62512d931d5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 24 Apr 2020 11:00:01 -0700 Subject: [PATCH 0698/1185] anchor correction --- cfg/yolov3-asff.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cfg/yolov3-asff.cfg b/cfg/yolov3-asff.cfg index ec47ea3aae..343e19fa2f 100644 --- a/cfg/yolov3-asff.cfg +++ b/cfg/yolov3-asff.cfg @@ -784,21 +784,21 @@ activation=linear [yolo] from=88,99,110 -mask = 8,9,10,11 +mask = 6,7,8 anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 classes=80 num=9 [yolo] from=88,99,110 -mask = 4,5,6,7 +mask = 3,4,5 anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 classes=80 num=9 [yolo] from=88,99,110 -mask = 0,1,2,3 +mask = 0,1,2 anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 classes=80 num=9 \ No newline at end of file From 754a1b5bf8d65f552fadd4c083e53c17e79cece4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 25 Apr 2020 21:15:30 -0700 Subject: [PATCH 0699/1185] reduce merge limit to 3000 --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 7adfa76a72..4547de31a6 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -556,7 +556,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T boxes, scores = x[:, :4].clone() + c.view(-1, 1) * max_wh, x[:, 4] # boxes (offset by class), scores if method == 'merge': # Merge NMS (boxes merged using weighted mean) i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - if n < 1E4: # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) + if n < 3E3: # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) # weights = (box_iou(boxes, boxes).tril_() > iou_thres) * scores.view(-1, 1) # box weights # weights /= weights.sum(0) # normalize # x[:, :4] = torch.mm(weights.T, x[:, :4]) From daedfc5487ec78c8f9c89f4f358150789b1eab32 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 26 Apr 2020 11:22:29 -0700 Subject: [PATCH 0700/1185] reduce merge limit to 3000 --- .github/ISSUE_TEMPLATE/--bug-report.md | 28 ++++++++++++++++---------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/--bug-report.md b/.github/ISSUE_TEMPLATE/--bug-report.md index 7a58967586..ecc096f868 100644 --- a/.github/ISSUE_TEMPLATE/--bug-report.md +++ b/.github/ISSUE_TEMPLATE/--bug-report.md @@ -7,14 +7,25 @@ assignees: '' --- +Before submitting a bug report, please ensure that you are using the latest versions of: + - python + - torch + - this repo (run `git status` and `git pull`) + +**Your issue must be reproducible on a public dataset (i.e COCO) using the latest version of the repository, and you must supply code to reproduce, or we can not help you.** + +If this is a custom training question we suggest you include your `train_batch0.png` and `results.png` figures. + + ## 🐛 Bug A clear and concise description of what the bug is. ## To Reproduce -Steps to reproduce the behavior: -1. -2. -3. +**REQUIRED**: Code to reproduce your issue below +``` +python train.py ... +``` + ## Expected behavior A clear and concise description of what you expected to happen. @@ -22,14 +33,9 @@ A clear and concise description of what you expected to happen. ## Environment If applicable, add screenshots to help explain your problem. -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Version [e.g. 22] + - OS: [e.g. Ubuntu] + - GPU [e.g. 2080 Ti] -**Smartphone (please complete the following information):** - - Device: [e.g. iPhoneXS] - - OS: [e.g. iOS8.1] - - Version [e.g. 22] ## Additional context Add any other context about the problem here. From 3bf0cb9c605db8976eac20466afd6b36539c498f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 26 Apr 2020 12:41:15 -0700 Subject: [PATCH 0701/1185] remove tb-nightly --- requirements.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index e705c8c0be..9577e7be5c 100755 --- a/requirements.txt +++ b/requirements.txt @@ -10,10 +10,6 @@ pillow # Nvidia Apex (optional) for mixed precision training -------------------------- # git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex -# Tensorboard (optional) pip requirements -------------------------------------- -# tb-nightly -# future - # Conda commands (in place of pip) --------------------------------------------- # conda update -yn base -c defaults conda # conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython future From efbeb283c4953501f31d005619ced9bef7886a2c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 26 Apr 2020 14:01:20 -0700 Subject: [PATCH 0702/1185] ONNX grid float --- models.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/models.py b/models.py index 9d0d7de591..5e1ac1b3b0 100755 --- a/models.py +++ b/models.py @@ -145,7 +145,7 @@ def __init__(self, anchors, nc, img_size, yolo_index, layers, stride): def create_grids(self, ng=(13, 13), device='cpu'): self.nx, self.ny = ng # x and y grid size - self.ng = torch.tensor(ng) + self.ng = torch.tensor(ng, dtype=torch.float) # build xy offsets if not self.training: @@ -193,9 +193,9 @@ def forward(self, p, out): elif ONNX_EXPORT: # Avoid broadcasting for ANE operations m = self.na * self.nx * self.ny - ng = 1 / self.ng.repeat((m, 1)) - grid = self.grid.repeat((1, self.na, 1, 1, 1)).view(m, 2) - anchor_wh = self.anchor_wh.repeat((1, 1, self.nx, self.ny, 1)).view(m, 2) * ng + ng = 1. / self.ng.repeat(m, 1) + grid = self.grid.repeat(1, self.na, 1, 1, 1).view(m, 2) + anchor_wh = self.anchor_wh.repeat(1, 1, self.nx, self.ny, 1).view(m, 2) * ng p = p.view(m, self.no) xy = torch.sigmoid(p[:, 0:2]) + grid # x, y From 55757421de4e4a6bd72c5596d021595f390719b8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 26 Apr 2020 14:09:12 -0700 Subject: [PATCH 0703/1185] remove future --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 9577e7be5c..586d12edaa 100755 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pillow # Conda commands (in place of pip) --------------------------------------------- # conda update -yn base -c defaults conda -# conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython future +# conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython # conda install -yc conda-forge scikit-image pycocotools tensorboard # conda install -yc spyder-ide spyder-line-profiler # conda install -yc pytorch pytorch torchvision From 11f228eb00fca8a6b0192e4ef965533b8d953ff4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 26 Apr 2020 16:07:29 -0700 Subject: [PATCH 0704/1185] yolov4.cfg from alexeyab/darknet --- cfg/yolov4.cfg | 1155 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1155 insertions(+) create mode 100644 cfg/yolov4.cfg diff --git a/cfg/yolov4.cfg b/cfg/yolov4.cfg new file mode 100644 index 0000000000..5e1ac82224 --- /dev/null +++ b/cfg/yolov4.cfg @@ -0,0 +1,1155 @@ +[net] +# Testing +#batch=1 +#subdivisions=1 +# Training +batch=64 +subdivisions=8 +width=608 +height=608 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +#cutmix=1 +mosaic=1 + +#:104x104 54:52x52 85:26x26 104:13x13 for 416 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=mish + +# Downsample + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=2 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=32 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -1,-7 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +# Downsample + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=2 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -1,-10 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +# Downsample + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=2 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -1,-28 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +# Downsample + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=2 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -1,-28 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=2 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -1,-16 + +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=mish + +########################## + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = 85 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = 54 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +########################## + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 0,1,2 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +scale_x_y = 1.2 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=256 +activation=leaky + +[route] +layers = -1, -16 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 3,4,5 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +scale_x_y = 1.1 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=512 +activation=leaky + +[route] +layers = -1, -37 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 6,7,8 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 From 18d4ebfd12fd32a8d98a6427054f9b816b0a4333 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 26 Apr 2020 16:25:46 -0700 Subject: [PATCH 0705/1185] add Mish() support --- models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/models.py b/models.py index 5e1ac1b3b0..5a43702782 100755 --- a/models.py +++ b/models.py @@ -45,9 +45,10 @@ def create_modules(module_defs, img_size): if mdef['activation'] == 'leaky': # activation study https://github.com/ultralytics/yolov3/issues/441 modules.add_module('activation', nn.LeakyReLU(0.1, inplace=True)) - # modules.add_module('activation', nn.PReLU(num_parameters=1, init=0.10)) elif mdef['activation'] == 'swish': modules.add_module('activation', Swish()) + elif mdef['activation'] == 'mish': + modules.add_module('activation', Mish()) elif mdef['type'] == 'BatchNorm2d': filters = output_filters[-1] From a0a3bab9e6ea767d392f89c7ee95c3bb44ad522e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 26 Apr 2020 16:31:21 -0700 Subject: [PATCH 0706/1185] add Mish() support --- utils/layers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/layers.py b/utils/layers.py index fee81ca101..a36300208b 100644 --- a/utils/layers.py +++ b/utils/layers.py @@ -115,9 +115,9 @@ def forward(self, x): class Swish(nn.Module): def forward(self, x): - return x.mul_(torch.sigmoid(x)) + return x.mul(torch.sigmoid(x)) class Mish(nn.Module): # https://github.com/digantamisra98/Mish def forward(self, x): - return x.mul_(F.softplus(x).tanh()) + return x.mul(F.softplus(x).tanh()) From 4a4bfb20deba3c88ce12c44e7837eada95a42e25 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 26 Apr 2020 16:31:57 -0700 Subject: [PATCH 0707/1185] FLOPS verbose=False --- utils/torch_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index c66909245c..215772bfbd 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -107,7 +107,7 @@ def model_info(model, verbose=False): try: # FLOPS from thop import profile - macs, _ = profile(model, inputs=(torch.zeros(1, 3, 480, 640),)) + macs, _ = profile(model, inputs=(torch.zeros(1, 3, 480, 640),), verbose=False) fs = ', %.1f GFLOPS' % (macs / 1E9 * 2) except: fs = '' From 18702c96084557d020cccf11fc77d8db2e44c073 Mon Sep 17 00:00:00 2001 From: Josh Veitch-Michaelis Date: Mon, 27 Apr 2020 17:21:34 +0100 Subject: [PATCH 0708/1185] add tensorboard to requirements (#1100) In a clean environment running training fails if tensorboard is not installed e.g. ``` Traceback (most recent call last): File "/home/josh/miniconda3/envs/ultralytics/lib/python3.7/site-packages/torch/utils/tensorboard/__init__.py", line 2, in from tensorboard.summary.writer.record_writer import RecordWriter # noqa F401 ModuleNotFoundError: No module named 'tensorboard' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "train.py", line 6, in from torch.utils.tensorboard import SummaryWriter File "/home/josh/miniconda3/envs/ultralytics/lib/python3.7/site-packages/torch/utils/tensorboard/__init__.py", line 4, in raise ImportError('TensorBoard logging requires TensorBoard with Python summary writer installed. ' ImportError: TensorBoard logging requires TensorBoard with Python summary writer installed. This should be available in 1.14 or above. ``` --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 586d12edaa..c82ddd8d26 100755 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,7 @@ matplotlib pycocotools tqdm pillow +tensorboard >= 1.14 # Nvidia Apex (optional) for mixed precision training -------------------------- # git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex From f799c156119bf9ea6cfed1fd201817606718e67e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 27 Apr 2020 11:20:27 -0700 Subject: [PATCH 0709/1185] result not updated from pycocotools --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 75568a0326..a4e1ce81c5 100644 --- a/test.py +++ b/test.py @@ -214,7 +214,7 @@ def test(cfg, cocoEval.evaluate() cocoEval.accumulate() cocoEval.summarize() - mf1, map = cocoEval.stats[:2] # update to pycocotools results (mAP@0.5:0.95, mAP@0.5) + # mf1, map = cocoEval.stats[:2] # update to pycocotools results (mAP@0.5:0.95, mAP@0.5) # Return results maps = np.zeros(nc) + map From 3aa347a3212861293193a79866bfe3634143b517 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 27 Apr 2020 13:08:24 -0700 Subject: [PATCH 0710/1185] add HardSwish() --- utils/layers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/layers.py b/utils/layers.py index a36300208b..81d3408c50 100644 --- a/utils/layers.py +++ b/utils/layers.py @@ -118,6 +118,11 @@ def forward(self, x): return x.mul(torch.sigmoid(x)) +class HardSwish(nn.Module): # https://arxiv.org/pdf/1905.02244.pdf + def forward(self, x): + return x * F.hardtanh(x + 3, 0., 6., True) / 6. + + class Mish(nn.Module): # https://github.com/digantamisra98/Mish def forward(self, x): return x.mul(F.softplus(x).tanh()) From 2518868508b138ccbb7fb00d1a8e7a83582bcfd6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 27 Apr 2020 13:51:21 -0700 Subject: [PATCH 0711/1185] MemoryEfficientMish() --- utils/layers.py | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/utils/layers.py b/utils/layers.py index 81d3408c50..35c13c9f06 100644 --- a/utils/layers.py +++ b/utils/layers.py @@ -98,14 +98,29 @@ def forward(self, x): # Activation functions below ------------------------------------------------------------------------------------------- class SwishImplementation(torch.autograd.Function): @staticmethod - def forward(ctx, i): - ctx.save_for_backward(i) - return i * torch.sigmoid(i) + def forward(ctx, x): + ctx.save_for_backward(x) + return x * torch.sigmoid(x) @staticmethod def backward(ctx, grad_output): - sigmoid_i = torch.sigmoid(ctx.saved_variables[0]) - return grad_output * (sigmoid_i * (1 + ctx.saved_variables[0] * (1 - sigmoid_i))) + x = ctx.saved_tensors[0] + sx = torch.sigmoid(x) # sigmoid(ctx) + return grad_output * (sx * (1 + x * (1 - sx))) + + +class MishImplementation(torch.autograd.Function): + @staticmethod + def forward(ctx, x): + ctx.save_for_backward(x) + return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x))) + + @staticmethod + def backward(ctx, grad_output): + x = ctx.saved_tensors[0] + sx = torch.sigmoid(x) + fx = F.softplus(x).tanh() + return grad_output * (fx + x * sx * (1 - fx * fx)) class MemoryEfficientSwish(nn.Module): @@ -113,9 +128,14 @@ def forward(self, x): return SwishImplementation.apply(x) +class MemoryEfficientMish(nn.Module): + def forward(self, x): + return MishImplementation.apply(x) + + class Swish(nn.Module): def forward(self, x): - return x.mul(torch.sigmoid(x)) + return x * torch.sigmoid(x) class HardSwish(nn.Module): # https://arxiv.org/pdf/1905.02244.pdf @@ -125,4 +145,4 @@ def forward(self, x): class Mish(nn.Module): # https://github.com/digantamisra98/Mish def forward(self, x): - return x.mul(F.softplus(x).tanh()) + return x * F.softplus(x).tanh() From e9d41bb56626da4b61c4bab8fdba5a1aceddb296 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 27 Apr 2020 15:06:26 -0700 Subject: [PATCH 0712/1185] Speed updated --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d58ba32d29..efdca8d270 100755 --- a/README.md +++ b/README.md @@ -60,17 +60,17 @@ Python 3.7 or later with all `pip install -U -r requirements.txt` packages inclu https://cloud.google.com/deep-learning-vm/ **Machine type:** preemptible [n1-standard-16](https://cloud.google.com/compute/docs/machine-types) (16 vCPUs, 60 GB memory) **CPU platform:** Intel Skylake -**GPUs:** K80 ($0.20/hr), T4 ($0.35/hr), V100 ($0.83/hr) CUDA with [Nvidia Apex](https://github.com/NVIDIA/apex) FP16/32 -**HDD:** 1 TB SSD +**GPUs:** K80 ($0.14/hr), T4 ($0.11/hr), V100 ($0.74/hr) CUDA with [Nvidia Apex](https://github.com/NVIDIA/apex) FP16/32 +**HDD:** 1 TB SSD **Dataset:** COCO train 2014 (117,263 images) **Model:** `yolov3-spp.cfg` **Command:** `python3 train.py --img 416 --batch 32 --accum 2` GPU |n| `--batch --accum` | img/s | epoch
time | epoch
cost --- |--- |--- |--- |--- |--- -K80 |1| 32 x 2 | 11 | 175 min | $0.58 -T4 |1
2| 32 x 2
64 x 1 | 41
61 | 48 min
32 min | $0.28
$0.36 -V100 |1
2| 32 x 2
64 x 1 | 122
**178** | 16 min
**11 min** | **$0.23**
$0.31 +K80 |1| 32 x 2 | 11 | 175 min | $0.41 +T4 |1
2| 32 x 2
64 x 1 | 41
61 | 48 min
32 min | $0.09
$0.11 +V100 |1
2| 32 x 2
64 x 1 | 122
**178** | 16 min
**11 min** | **$0.21**
$0.28 2080Ti |1
2| 32 x 2
64 x 1 | 81
140 | 24 min
14 min | -
- # Inference From 8521c3cff952e9ae5f32ff69580bfdae726afb6f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 27 Apr 2020 15:22:36 -0700 Subject: [PATCH 0713/1185] cleanup --- train.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/train.py b/train.py index ddeda1a775..d32f59e011 100644 --- a/train.py +++ b/train.py @@ -249,7 +249,7 @@ def train(): if 'momentum' in x: x['momentum'] = np.interp(ni, [0, n_burn], [0.9, hyp['momentum']]) - # Multi-Scale training + # Multi-Scale if opt.multi_scale: if ni / accumulate % 1 == 0: #  adjust img_size (67% - 150%) every 1 batch img_size = random.randrange(grid_min, grid_max + 1) * gs @@ -258,38 +258,36 @@ def train(): ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to 32-multiple) imgs = F.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) - # Run model + # Forward pred = model(imgs) - # Compute loss + # Loss loss, loss_items = compute_loss(pred, targets, model) if not torch.isfinite(loss): print('WARNING: non-finite loss, ending training ', loss_items) return results - # Scale loss by nominal batch_size of 64 - loss *= batch_size / 64 - - # Compute gradient + # Backward + loss *= batch_size / 64 # scale loss if mixed_precision: with amp.scale_loss(loss, optimizer) as scaled_loss: scaled_loss.backward() else: loss.backward() - # Optimize accumulated gradient + # Optimize if ni % accumulate == 0: optimizer.step() optimizer.zero_grad() ema.update(model) - # Print batch results + # Print mloss = (mloss * i + loss_items) / (i + 1) # update mean losses mem = '%.3gG' % (torch.cuda.memory_cached() / 1E9 if torch.cuda.is_available() else 0) # (GB) s = ('%10s' * 2 + '%10.3g' * 6) % ('%g/%g' % (epoch, epochs - 1), mem, *mloss, len(targets), img_size) pbar.set_description(s) - # Plot images with bounding boxes + # Plot if ni < 1: f = 'train_batch%g.png' % i # filename plot_images(imgs=imgs, targets=targets, paths=paths, fname=f) From 02ae0e3bbd5c30aa353ca75dfa61acefa065eb52 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 27 Apr 2020 21:05:19 -0700 Subject: [PATCH 0714/1185] reproduce results update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index efdca8d270..85d169a2f7 100755 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ Speed: 17.5/2.3/19.9 ms inference/NMS/total per 640x640 image at batch-size 16 This command trains `yolov3-spp.cfg` from scratch to our mAP above. Training takes about one week on a 2080Ti. ```bash -$ python3 train.py --weights '' --cfg yolov3-spp.cfg --epochs 300 --batch 16 --accum 4 --multi +$ python3 train.py --weights '' --cfg yolov3-spp.cfg --epochs 300 --batch-size 16 --img 320 640 ``` From b1d385a8deb6d78ee677653f6a9d83c22c32344b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 27 Apr 2020 21:19:22 -0700 Subject: [PATCH 0715/1185] yolov4-relu.cfg --- cfg/yolov4-relu.cfg | 1155 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1155 insertions(+) create mode 100644 cfg/yolov4-relu.cfg diff --git a/cfg/yolov4-relu.cfg b/cfg/yolov4-relu.cfg new file mode 100644 index 0000000000..c2821b7eac --- /dev/null +++ b/cfg/yolov4-relu.cfg @@ -0,0 +1,1155 @@ +[net] +# Testing +#batch=1 +#subdivisions=1 +# Training +batch=64 +subdivisions=8 +width=608 +height=608 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +#cutmix=1 +mosaic=1 + +#:104x104 54:52x52 85:26x26 104:13x13 for 416 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=32 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-7 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-10 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-28 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-28 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-16 + +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=leaky + +########################## + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = 85 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = 54 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +########################## + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 0,1,2 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +scale_x_y = 1.2 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=256 +activation=leaky + +[route] +layers = -1, -16 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 3,4,5 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +scale_x_y = 1.1 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=512 +activation=leaky + +[route] +layers = -1, -37 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 6,7,8 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 From 15f1343dfc203968b4c048ce7a6c5bd7e2387b13 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 28 Apr 2020 11:07:26 -0700 Subject: [PATCH 0716/1185] uncached label removal --- utils/datasets.py | 171 ++++++++++++++++++++++------------------------ 1 file changed, 80 insertions(+), 91 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index bb2b21ae5f..4fc33e87f6 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -257,7 +257,7 @@ def __len__(self): class LoadImagesAndLabels(Dataset): # for training/testing def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, - cache_labels=True, cache_images=False, single_cls=False): + cache_images=False, single_cls=False): path = str(Path(path)) # os-agnostic assert os.path.isfile(path), 'File not found %s. See %s' % (path, help_url) with open(path, 'r') as f: @@ -315,71 +315,69 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r self.batch_shapes = np.ceil(np.array(shapes) * img_size / 64.).astype(np.int) * 64 - # Preload labels (required for weighted CE training) + # Cache labels self.imgs = [None] * n - self.labels = [None] * n - if cache_labels or image_weights: # cache labels for faster training - self.labels = [np.zeros((0, 5))] * n - extract_bounding_boxes = False - create_datasubset = False - pbar = tqdm(self.label_files, desc='Caching labels') - nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate - for i, file in enumerate(pbar): - try: - with open(file, 'r') as f: - l = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) - except: - nm += 1 # print('missing labels for image %s' % self.img_files[i]) # file missing - continue - - if l.shape[0]: - assert l.shape[1] == 5, '> 5 label columns: %s' % file - assert (l >= 0).all(), 'negative labels: %s' % file - assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels: %s' % file - if np.unique(l, axis=0).shape[0] < l.shape[0]: # duplicate rows - nd += 1 # print('WARNING: duplicate rows in %s' % self.label_files[i]) # duplicate rows - if single_cls: - l[:, 0] = 0 # force dataset into single-class mode - self.labels[i] = l - nf += 1 # file found - - # Create subdataset (a smaller dataset) - if create_datasubset and ns < 1E4: - if ns == 0: - create_folder(path='./datasubset') - os.makedirs('./datasubset/images') - exclude_classes = 43 - if exclude_classes not in l[:, 0]: - ns += 1 - # shutil.copy(src=self.img_files[i], dst='./datasubset/images/') # copy image - with open('./datasubset/images.txt', 'a') as f: - f.write(self.img_files[i] + '\n') - - # Extract object detection boxes for a second stage classifier - if extract_bounding_boxes: - p = Path(self.img_files[i]) - img = cv2.imread(str(p)) - h, w = img.shape[:2] - for j, x in enumerate(l): - f = '%s%sclassifier%s%g_%g_%s' % (p.parent.parent, os.sep, os.sep, x[0], j, p.name) - if not os.path.exists(Path(f).parent): - os.makedirs(Path(f).parent) # make new output folder - - b = x[1:] * [w, h, w, h] # box - b[2:] = b[2:].max() # rectangle to square - b[2:] = b[2:] * 1.3 + 30 # pad - b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(np.int) - - b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image - b[[1, 3]] = np.clip(b[[1, 3]], 0, h) - assert cv2.imwrite(f, img[b[1]:b[3], b[0]:b[2]]), 'Failure extracting classifier boxes' - else: - ne += 1 # print('empty labels for image %s' % self.img_files[i]) # file empty - # os.system("rm '%s' '%s'" % (self.img_files[i], self.label_files[i])) # remove + self.labels = [np.zeros((0, 5), dtype=np.float32)] * n + extract_bounding_boxes = False + create_datasubset = False + pbar = tqdm(self.label_files, desc='Caching labels') + nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate + for i, file in enumerate(pbar): + try: + with open(file, 'r') as f: + l = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) + except: + nm += 1 # print('missing labels for image %s' % self.img_files[i]) # file missing + continue + + if l.shape[0]: + assert l.shape[1] == 5, '> 5 label columns: %s' % file + assert (l >= 0).all(), 'negative labels: %s' % file + assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels: %s' % file + if np.unique(l, axis=0).shape[0] < l.shape[0]: # duplicate rows + nd += 1 # print('WARNING: duplicate rows in %s' % self.label_files[i]) # duplicate rows + if single_cls: + l[:, 0] = 0 # force dataset into single-class mode + self.labels[i] = l + nf += 1 # file found + + # Create subdataset (a smaller dataset) + if create_datasubset and ns < 1E4: + if ns == 0: + create_folder(path='./datasubset') + os.makedirs('./datasubset/images') + exclude_classes = 43 + if exclude_classes not in l[:, 0]: + ns += 1 + # shutil.copy(src=self.img_files[i], dst='./datasubset/images/') # copy image + with open('./datasubset/images.txt', 'a') as f: + f.write(self.img_files[i] + '\n') + + # Extract object detection boxes for a second stage classifier + if extract_bounding_boxes: + p = Path(self.img_files[i]) + img = cv2.imread(str(p)) + h, w = img.shape[:2] + for j, x in enumerate(l): + f = '%s%sclassifier%s%g_%g_%s' % (p.parent.parent, os.sep, os.sep, x[0], j, p.name) + if not os.path.exists(Path(f).parent): + os.makedirs(Path(f).parent) # make new output folder + + b = x[1:] * [w, h, w, h] # box + b[2:] = b[2:].max() # rectangle to square + b[2:] = b[2:] * 1.3 + 30 # pad + b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(np.int) + + b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image + b[[1, 3]] = np.clip(b[[1, 3]], 0, h) + assert cv2.imwrite(f, img[b[1]:b[3], b[0]:b[2]]), 'Failure extracting classifier boxes' + else: + ne += 1 # print('empty labels for image %s' % self.img_files[i]) # file empty + # os.system("rm '%s' '%s'" % (self.img_files[i], self.label_files[i])) # remove - pbar.desc = 'Caching labels (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( - nf, nm, ne, nd, n) - assert nf > 0, 'No labels found in %s. See %s' % (os.path.dirname(file) + os.sep, help_url) + pbar.desc = 'Caching labels (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( + nf, nm, ne, nd, n) + assert nf > 0, 'No labels found in %s. See %s' % (os.path.dirname(file) + os.sep, help_url) # Cache images into memory for faster training (WARNING: large datasets may exceed system RAM) if cache_images: # if training @@ -432,7 +430,7 @@ def __getitem__(self, index): # Load labels labels = [] x = self.labels[index] - if x is not None and x.size > 0: + if x.size > 0: # Normalized xywh to pixel xyxy format labels = x.copy() labels[:, 1] = ratio[0] * w * (x[:, 1] - x[:, 3] / 2) + pad[0] # pad width @@ -502,9 +500,9 @@ def load_image(self, index): # loads 1 image from dataset, returns img, original hw, resized hw img = self.imgs[index] if img is None: # not cached - img_path = self.img_files[index] - img = cv2.imread(img_path) # BGR - assert img is not None, 'Image Not Found ' + img_path + path = self.img_files[index] + img = cv2.imread(path) # BGR + assert img is not None, 'Image Not Found ' + path h0, w0 = img.shape[:2] # orig hw r = self.img_size / max(h0, w0) # resize image to img_size if r < 1 or (self.augment and r != 1): # always resize down, only resize up if training with augmentation @@ -557,24 +555,15 @@ def load_mosaic(self, index): padw = x1a - x1b padh = y1a - y1b - # Load labels - label_path = self.label_files[index] - if os.path.isfile(label_path): - x = self.labels[index] - if x is None: # labels not preloaded - with open(label_path, 'r') as f: - x = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) - - if x.size > 0: - # Normalized xywh to pixel xyxy format - labels = x.copy() - labels[:, 1] = w * (x[:, 1] - x[:, 3] / 2) + padw - labels[:, 2] = h * (x[:, 2] - x[:, 4] / 2) + padh - labels[:, 3] = w * (x[:, 1] + x[:, 3] / 2) + padw - labels[:, 4] = h * (x[:, 2] + x[:, 4] / 2) + padh - else: - labels = np.zeros((0, 5), dtype=np.float32) - labels4.append(labels) + # Labels + x = self.labels[index] + labels = x.copy() + if x.size > 0: # Normalized xywh to pixel xyxy format + labels[:, 1] = w * (x[:, 1] - x[:, 3] / 2) + padw + labels[:, 2] = h * (x[:, 2] - x[:, 4] / 2) + padh + labels[:, 3] = w * (x[:, 1] + x[:, 3] / 2) + padw + labels[:, 4] = h * (x[:, 2] + x[:, 4] / 2) + padh + labels4.append(labels) # Concat/clip labels if len(labels4): @@ -585,10 +574,10 @@ def load_mosaic(self, index): # Augment # img4 = img4[s // 2: int(s * 1.5), s // 2:int(s * 1.5)] # center crop (WARNING, requires box pruning) img4, labels4 = random_affine(img4, labels4, - degrees=self.hyp['degrees'] * 1, - translate=self.hyp['translate'] * 1, - scale=self.hyp['scale'] * 1, - shear=self.hyp['shear'] * 1, + degrees=self.hyp['degrees'], + translate=self.hyp['translate'], + scale=self.hyp['scale'], + shear=self.hyp['shear'], border=-s // 2) # border to remove return img4, labels4 @@ -688,7 +677,7 @@ def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, area = w * h area0 = (targets[:, 3] - targets[:, 1]) * (targets[:, 4] - targets[:, 2]) ar = np.maximum(w / (h + 1e-16), h / (w + 1e-16)) # aspect ratio - i = (w > 4) & (h > 4) & (area / (area0 + 1e-16) > 0.2) & (ar < 10) + i = (w > 4) & (h > 4) & (area / (area0 * s + 1e-16) > 0.2) & (ar < 10) targets = targets[i] targets[:, 1:5] = xy[i] From 992d8af24216bf9884ab41913f18d65c9def4b56 Mon Sep 17 00:00:00 2001 From: Josh Veitch-Michaelis Date: Tue, 28 Apr 2020 20:59:44 +0100 Subject: [PATCH 0717/1185] faster hsv augmentation (#1110) As per https://github.com/ultralytics/yolov3/issues/1096 --- utils/datasets.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 4fc33e87f6..3ea4203104 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -514,9 +514,16 @@ def load_image(self, index): def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5): - x = np.random.uniform(-1, 1, 3) * [hgain, sgain, vgain] + 1 # random gains - img_hsv = (cv2.cvtColor(img, cv2.COLOR_BGR2HSV) * x).clip(None, 255).astype(np.uint8) - np.clip(img_hsv[:, :, 0], None, 179, out=img_hsv[:, :, 0]) # inplace hue clip (0 - 179 deg) + r = np.random.uniform(-1, 1, 3) * [hgain, sgain, vgain] + 1 # random gains + hue, sat, val = cv2.split(cv2.cvtColor(img, cv2.COLOR_BGR2HSV)) + dtype = img.dtype # uint8 + + x = np.arange(0, 256, dtype=np.int16) + lut_hue = ((x * r[0]) % 180).astype(dtype) + lut_sat = np.clip(x * r[1], 0, 255).astype(dtype) + lut_val = np.clip(x * r[2], 0, 255).astype(dtype) + + img_hsv = cv2.merge((cv2.LUT(hue, lut_hue), cv2.LUT(sat, lut_sat), cv2.LUT(val, lut_val))).astype(dtype) cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR, dst=img) # no return needed # Histogram equalization From 37cbe89ef060c4b9789617b3e539a4c58a56d457 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 28 Apr 2020 13:45:27 -0700 Subject: [PATCH 0718/1185] test/train jpg for png --- test.py | 4 ++-- train.py | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/test.py b/test.py index a4e1ce81c5..b79f1d1a6d 100644 --- a/test.py +++ b/test.py @@ -26,7 +26,7 @@ def test(cfg, verbose = opt.task == 'test' # Remove previous - for f in glob.glob('test_batch*.png'): + for f in glob.glob('test_batch*.jpg'): os.remove(f) # Initialize model @@ -83,7 +83,7 @@ def test(cfg, whwh = torch.Tensor([width, height, width, height]).to(device) # Plot images with bounding boxes - f = 'test_batch%g.png' % batch_i # filename + f = 'test_batch%g.jpg' % batch_i # filename if batch_i < 1 and not os.path.exists(f): plot_images(imgs=imgs, targets=targets, paths=paths, fname=f) diff --git a/train.py b/train.py index d32f59e011..ddd6658806 100644 --- a/train.py +++ b/train.py @@ -53,6 +53,7 @@ if hyp['fl_gamma']: print('Using FocalLoss(gamma=%g)' % hyp['fl_gamma']) + def train(): cfg = opt.cfg data = opt.data @@ -83,7 +84,7 @@ def train(): hyp['cls'] *= nc / 80 # update coco-tuned hyp['cls'] to current dataset # Remove previous results - for f in glob.glob('*_batch*.png') + glob.glob(results_file): + for f in glob.glob('*_batch*.jpg') + glob.glob(results_file): os.remove(f) # Initialize model @@ -149,7 +150,7 @@ def train(): # Scheduler https://arxiv.org/pdf/1812.01187.pdf lf = lambda x: (((1 + math.cos(x * math.pi / epochs)) / 2) ** 1.0) * 0.95 + 0.05 # cosine scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) - scheduler.last_epoch=start_epoch - 1 # see link below + scheduler.last_epoch = start_epoch - 1 # see link below # https://discuss.pytorch.org/t/a-problem-occured-when-resuming-an-optimizer/28822 # Plot lr schedule @@ -289,7 +290,7 @@ def train(): # Plot if ni < 1: - f = 'train_batch%g.png' % i # filename + f = 'train_batch%g.jpg' % i # filename plot_images(imgs=imgs, targets=targets, paths=paths, fname=f) if tb_writer: tb_writer.add_image(f, cv2.imread(f)[:, :, ::-1], dataformats='HWC') @@ -388,7 +389,8 @@ def train(): parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data path') parser.add_argument('--multi-scale', action='store_true', help='adjust (67%% - 150%%) img_size every 10 batches') - parser.add_argument('--img-size', nargs='+', type=int, default=[320, 640], help='[min_train, max-train, test] img sizes') + parser.add_argument('--img-size', nargs='+', type=int, default=[320, 640], + help='[min_train, max-train, test] img sizes') parser.add_argument('--rect', action='store_true', help='rectangular training') parser.add_argument('--resume', action='store_true', help='resume training from last.pt') parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') From c6ea2b58ea5b4a1f563c8b14a7590be049cbf3f6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 28 Apr 2020 15:06:33 -0700 Subject: [PATCH 0719/1185] auto-accumulate update --- utils/gcp.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/gcp.sh b/utils/gcp.sh index ad99d8e42a..12e2370c53 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -36,5 +36,5 @@ do done #COCO training -n=131 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 640 --epochs 300 --batch 16 --accum 4 --weights '' --device 0 --cfg yolov3-spp.cfg --nosave --bucket ult/coco --name $n && sudo shutdown -n=132 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 640 --epochs 300 --batch 64 --accum 1 --weights '' --device 0 --cfg yolov3-tiny.cfg --nosave --bucket ult/coco --name $n && sudo shutdown +n=131 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 640 --epochs 300 --batch 16 --weights '' --device 0 --cfg yolov3-spp.cfg --bucket ult/coco --name $n && sudo shutdown +n=132 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 640 --epochs 300 --batch 64 --weights '' --device 0 --cfg yolov3-tiny.cfg --bucket ult/coco --name $n && sudo shutdown From 9cc4951d4fb8df0cf1c9fed5e60c01c150e78a0c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 28 Apr 2020 15:24:14 -0700 Subject: [PATCH 0720/1185] auto reverse-strides for yolov4/panet --- models.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/models.py b/models.py index 5a43702782..afd5b87b0e 100755 --- a/models.py +++ b/models.py @@ -5,7 +5,7 @@ ONNX_EXPORT = False -def create_modules(module_defs, img_size): +def create_modules(module_defs, img_size, cfg): # Constructs module list of layer blocks from module configuration in module_defs img_size = [img_size] * 2 if isinstance(img_size, int) else img_size # expand if necessary @@ -92,14 +92,16 @@ def create_modules(module_defs, img_size): elif mdef['type'] == 'yolo': yolo_index += 1 - stride = [32, 16, 8, 4, 2][yolo_index] # P3-P7 stride + stride = [32, 16, 8] # P5, P4, P3 strides + if 'panet' in cfg or 'yolov4' in cfg: # stride order reversed + stride = list(reversed(stride)) layers = mdef['from'] if 'from' in mdef else [] modules = YOLOLayer(anchors=mdef['anchors'][mdef['mask']], # anchor list nc=mdef['classes'], # number of classes img_size=img_size, # (416, 416) yolo_index=yolo_index, # 0, 1, 2... layers=layers, # output layers - stride=stride) + stride=stride[yolo_index]) # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) try: @@ -221,7 +223,7 @@ def __init__(self, cfg, img_size=(416, 416), verbose=False): super(Darknet, self).__init__() self.module_defs = parse_model_cfg(cfg) - self.module_list, self.routs = create_modules(self.module_defs, img_size) + self.module_list, self.routs = create_modules(self.module_defs, img_size, cfg) self.yolo_layers = get_yolo_layers(self) # torch_utils.initialize_weights(self) From 9f88f5cc21edce83cafb9bd8cf0f078daf3e6c02 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Apr 2020 11:34:59 -0700 Subject: [PATCH 0721/1185] cleanup --- train.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/train.py b/train.py index ddd6658806..5311cfc3bb 100644 --- a/train.py +++ b/train.py @@ -389,8 +389,7 @@ def train(): parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data path') parser.add_argument('--multi-scale', action='store_true', help='adjust (67%% - 150%%) img_size every 10 batches') - parser.add_argument('--img-size', nargs='+', type=int, default=[320, 640], - help='[min_train, max-train, test] img sizes') + parser.add_argument('--img-size', nargs='+', type=int, default=[320, 640], help='[min_train, max-train, test]') parser.add_argument('--rect', action='store_true', help='rectangular training') parser.add_argument('--resume', action='store_true', help='resume training from last.pt') parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') From d62d68929c59e006994fd252ba42d7ecc170dbb2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Apr 2020 12:00:30 -0700 Subject: [PATCH 0722/1185] cleanup --- train.py | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/train.py b/train.py index 5311cfc3bb..bf9d60821d 100644 --- a/train.py +++ b/train.py @@ -22,7 +22,7 @@ best = wdir + 'best.pt' results_file = 'results.txt' -# Hyperparameters https://github.com/ultralytics/yolov3/issues/310 +# Hyperparameters hyp = {'giou': 3.54, # giou loss gain 'cls': 37.4, # cls loss gain 'cls_pw': 1.0, # cls BCELoss positive_weight @@ -315,13 +315,13 @@ def train(): single_cls=opt.single_cls, dataloader=testloader) - # Write epoch results + # Write with open(results_file, 'a') as f: f.write(s + '%10.3g' * 7 % results + '\n') # P, R, mAP, F1, test_losses=(GIoU, obj, cls) if len(opt.name) and opt.bucket: os.system('gsutil cp results.txt gs://%s/results/results%s.txt' % (opt.bucket, opt.name)) - # Write Tensorboard results + # Tensorboard if tb_writer: tags = ['train/giou_loss', 'train/obj_loss', 'train/cls_loss', 'metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/F1', @@ -334,34 +334,25 @@ def train(): if fi > best_fitness: best_fitness = fi - # Save training results + # Save model save = (not opt.nosave) or (final_epoch and not opt.evolve) if save: - with open(results_file, 'r') as f: - # Create checkpoint + with open(results_file, 'r') as f: # create checkpoint chkpt = {'epoch': epoch, 'best_fitness': best_fitness, 'training_results': f.read(), 'model': ema.ema.module.state_dict() if hasattr(model, 'module') else ema.ema.state_dict(), 'optimizer': None if final_epoch else optimizer.state_dict()} - # Save last checkpoint + # Save last, best and delete torch.save(chkpt, last) - - # Save best checkpoint if (best_fitness == fi) and not final_epoch: torch.save(chkpt, best) - - # Save backup every 10 epochs (optional) - # if epoch > 0 and epoch % 10 == 0: - # torch.save(chkpt, wdir + 'backup%g.pt' % epoch) - - # Delete checkpoint del chkpt # end epoch ---------------------------------------------------------------------------------------------------- - # end training + n = opt.name if len(n): n = '_' + n if not n.isnumeric() else n @@ -378,7 +369,6 @@ def train(): print('%g epochs completed in %.3f hours.\n' % (epoch - start_epoch + 1, (time.time() - t0) / 3600)) dist.destroy_process_group() if torch.cuda.device_count() > 1 else None torch.cuda.empty_cache() - return results From f1d73a29e549654c99674bf07dd8f7a2f5c19d18 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 30 Apr 2020 12:26:02 -0700 Subject: [PATCH 0723/1185] Optimizer group report --- train.py | 1 + 1 file changed, 1 insertion(+) diff --git a/train.py b/train.py index bf9d60821d..67c20aa318 100644 --- a/train.py +++ b/train.py @@ -108,6 +108,7 @@ def train(): optimizer = optim.SGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) optimizer.add_param_group({'params': pg1, 'weight_decay': hyp['weight_decay']}) # add pg1 with weight_decay optimizer.add_param_group({'params': pg2}) # add pg2 (biases) + print('Optimizer groups: %g .bias, %g Conv2d.weight, %g other' % (len(pg2), len(pg1), len(pg0))) del pg0, pg1, pg2 start_epoch = 0 From fb1b5e09b2452edbc57d629183527eeadb7851be Mon Sep 17 00:00:00 2001 From: Josh Veitch-Michaelis Date: Thu, 30 Apr 2020 21:37:04 +0100 Subject: [PATCH 0724/1185] faster and more informative training plots (#1114) * faster and more informative training plots * Update utils.py Looks good. Needs pep8 linting, I'll do that in PyCharm later once PR is in. * Update test.py * Update train.py f for the tb descriptor lets us plot several batches, i.e. to allow us to change L292 to 'if ni < 3' for 3 examples. Co-authored-by: Glenn Jocher --- test.py | 12 ++-- train.py | 4 +- utils/utils.py | 160 ++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 146 insertions(+), 30 deletions(-) diff --git a/test.py b/test.py index b79f1d1a6d..0dfd21492e 100644 --- a/test.py +++ b/test.py @@ -82,11 +82,6 @@ def test(cfg, nb, _, height, width = imgs.shape # batch size, channels, height, width whwh = torch.Tensor([width, height, width, height]).to(device) - # Plot images with bounding boxes - f = 'test_batch%g.jpg' % batch_i # filename - if batch_i < 1 and not os.path.exists(f): - plot_images(imgs=imgs, targets=targets, paths=paths, fname=f) - # Disable gradients with torch.no_grad(): # Run model @@ -167,6 +162,13 @@ def test(cfg, # Append statistics (correct, conf, pcls, tcls) stats.append((correct.cpu(), pred[:, 4].cpu(), pred[:, 5].cpu(), tcls)) + # Plot images + if batch_i < 1: + f = 'test_batch%g_gt.jpg' % batch_i # filename + plot_images(images=imgs, targets=targets, paths=paths, names=names, fname=f) # ground truth + f = 'test_batch%g_pred.jpg' % batch_i # filename + plot_images(images=imgs, targets=output_to_target(output, width, height), paths=paths, names=names, fname=f) # predictions + # Compute statistics stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy if len(stats): diff --git a/train.py b/train.py index 67c20aa318..5ee55f88db 100644 --- a/train.py +++ b/train.py @@ -292,9 +292,9 @@ def train(): # Plot if ni < 1: f = 'train_batch%g.jpg' % i # filename - plot_images(imgs=imgs, targets=targets, paths=paths, fname=f) + res = plot_images(images=imgs, targets=targets, paths=paths, fname=f) if tb_writer: - tb_writer.add_image(f, cv2.imread(f)[:, :, ::-1], dataformats='HWC') + tb_writer.add_image(f, res, dataformats='HWC', global_step=epoch) # tb_writer.add_graph(model, imgs) # add model to tensorboard # end batch ------------------------------------------------------------------------------------------------ diff --git a/utils/utils.py b/utils/utils.py index 4547de31a6..1335e46ba3 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -829,6 +829,35 @@ def fitness(x): return (x[:, :4] * w).sum(1) +def output_to_target(output, width, height): + """ + Convert a YOLO model output to target format + + [batch_id, class_id, x, y, w, h, conf] + + """ + + if isinstance(output, torch.Tensor): + output = output.cpu().numpy() + + targets = [] + for i, o in enumerate(output): + + if o is not None: + for pred in o: + box = pred[:4] + w = (box[2]-box[0])/width + h = (box[3]-box[1])/height + x = box[0]/width + w/2 + y = box[1]/height + h/2 + conf = pred[4] + cls = int(pred[5]) + + targets.append([i, cls, x, y, w, h, conf]) + + return np.array(targets) + + # Plotting functions --------------------------------------------------------------------------------------------------- def plot_one_box(x, img, color=None, label=None, line_thickness=None): # Plots one bounding box on image img @@ -864,30 +893,115 @@ def plot_wh_methods(): # from utils.utils import *; plot_wh_methods() fig.savefig('comparison.png', dpi=200) -def plot_images(imgs, targets, paths=None, fname='images.png'): - # Plots training images overlaid with targets - imgs = imgs.cpu().numpy() - targets = targets.cpu().numpy() - # targets = targets[targets[:, 1] == 21] # plot only one class - - fig = plt.figure(figsize=(10, 10)) - bs, _, h, w = imgs.shape # batch size, _, height, width - bs = min(bs, 16) # limit plot to 16 images - ns = np.ceil(bs ** 0.5) # number of subplots - - for i in range(bs): - boxes = xywh2xyxy(targets[targets[:, 0] == i, 2:6]).T - boxes[[0, 2]] *= w - boxes[[1, 3]] *= h - plt.subplot(ns, ns, i + 1).imshow(imgs[i].transpose(1, 2, 0)) - plt.plot(boxes[[0, 2, 2, 0, 0]], boxes[[1, 1, 3, 3, 1]], '.-') - plt.axis('off') +def plot_images(images, targets, paths=None, fname='images.jpg', names=None, class_labels=True, confidence_labels=True, max_size=640, max_subplots=16): + + if isinstance(images, torch.Tensor): + images = images.cpu().numpy() + + if isinstance(targets, torch.Tensor): + targets = targets.cpu().numpy() + + # un-normalise + if np.max(images[0]) <= 1: + images *= 255 + + bs, _, h, w = images.shape # batch size, _, height, width + bs = min(bs, max_subplots) # limit plot images + ns = np.ceil(bs ** 0.5) # number of subplots (square) + + # Check if we should resize + should_resize = False + if w > max_size or h > max_size: + scale_factor = max_size/max(h, w) + h = math.ceil(scale_factor*h) + w = math.ceil(scale_factor*w) + should_resize=True + + # Empty array for output + mosaic_width = int(ns*w) + mosaic_height = int(ns*h) + mosaic = 255*np.ones((mosaic_height, mosaic_width, 3), dtype=np.uint8) + + # Fix class - colour map + prop_cycle = plt.rcParams['axes.prop_cycle'] + # https://stackoverflow.com/questions/51350872/python-from-color-name-to-rgb + hex2rgb = lambda h : tuple(int(h[1+i:1+i+2], 16) for i in (0, 2, 4)) + color_lut = [hex2rgb(h) for h in prop_cycle.by_key()['color']] + + for i, image in enumerate(images): + + # e.g. if the last batch has fewer images than we expect + if i == max_subplots: + break + + block_x = int(w * (i // ns)) + block_y = int(h * (i % ns)) + + image = image.transpose(1,2,0) + + if should_resize: + image = cv2.resize(image, (w, h)) + + mosaic[block_y:block_y+h, block_x:block_x+w,:] = image + + if targets is not None: + image_targets = targets[targets[:, 0] == i] + boxes = xywh2xyxy(image_targets[:,2:6]).T + classes = image_targets[:,1].astype('int') + + # Check if we have object confidences (gt vs pred) + confidences = None + if image_targets.shape[1] > 6: + confidences = image_targets[:,6] + + boxes[[0, 2]] *= w + boxes[[0, 2]] += block_x + + boxes[[1, 3]] *= h + boxes[[1, 3]] += block_y + + for j, box in enumerate(boxes.T): + color = color_lut[int(classes[j]) % len(color_lut)] + box = box.astype(int) + cv2.rectangle(mosaic, (box[0], box[1]), (box[2], box[3]), color, thickness=2) + + # Draw class label + if class_labels and max_size > 250: + label = str(classes[j]) if names is None else names[classes[j]] + if confidences is not None and confidence_labels: + label += " {:1.2f}".format(confidences[j]) + + font_scale = 0.4/10 * min(20, h * 0.05) + font_thickness = 2 if max(w, h) > 320 else 1 + + label_size, _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, font_scale, font_thickness) + cv2.rectangle(mosaic, (box[0], box[1]), (box[0]+label_size[0], box[1]-label_size[1]), color, thickness=-1) + cv2.putText(mosaic, label, (box[0], box[1]), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=font_scale, thickness=font_thickness, color=(255,255,255)) + + # Draw image filename labels if paths is not None: - s = Path(paths[i]).name - plt.title(s[:min(len(s), 40)], fontdict={'size': 8}) # limit to 40 characters - fig.tight_layout() - fig.savefig(fname, dpi=200) - plt.close() + # Trim to 40 chars + label = os.path.basename(paths[i])[:40] + + # Empirical calculation to fit label + # 0.4 is at most (13, 10) px per char at thickness = 1 + # Fit label to 20px high, or shrink if it would be too big + max_font_scale = (w/len(label))*(0.4/8) + font_scale = min(0.4 * 20/8.5, max_font_scale) + font_thickness = 1 + + label_size, baseline = cv2.getTextSize(label, cv2.FONT_HERSHEY_DUPLEX, font_scale, font_thickness) + + cv2.rectangle(mosaic, (block_x+5, block_y+label_size[1]+baseline+5), (block_x+label_size[0]+5, block_y), 0, thickness=-1) + cv2.putText(mosaic, label, (block_x+5, block_y+label_size[1]+5), cv2.FONT_HERSHEY_DUPLEX, font_scale, (255,255,255), font_thickness) + + # Image border + cv2.rectangle(mosaic, (block_x, block_y), (block_x+w, block_y+h), (255,255,255), thickness=3) + + if fname is not None: + cv2.imwrite(fname, cv2.cvtColor(mosaic, cv2.COLOR_BGR2RGB)) + + return mosaic def plot_test_txt(): # from utils.utils import *; plot_test() From 0ffbf5534e84be1600304413c6868901a70d65a5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 30 Apr 2020 14:53:57 -0700 Subject: [PATCH 0725/1185] cleanup for #1114 --- test.py | 6 +-- utils/utils.py | 127 +++++++++++++++++++------------------------------ 2 files changed, 51 insertions(+), 82 deletions(-) diff --git a/test.py b/test.py index 0dfd21492e..0f968811f9 100644 --- a/test.py +++ b/test.py @@ -165,9 +165,9 @@ def test(cfg, # Plot images if batch_i < 1: f = 'test_batch%g_gt.jpg' % batch_i # filename - plot_images(images=imgs, targets=targets, paths=paths, names=names, fname=f) # ground truth - f = 'test_batch%g_pred.jpg' % batch_i # filename - plot_images(images=imgs, targets=output_to_target(output, width, height), paths=paths, names=names, fname=f) # predictions + plot_images(imgs, targets, paths=paths, names=names, fname=f) # ground truth + f = 'test_batch%g_pred.jpg' % batch_i + plot_images(imgs, output_to_target(output, width, height), paths=paths, names=names, fname=f) # predictions # Compute statistics stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy diff --git a/utils/utils.py b/utils/utils.py index 1335e46ba3..642ebdba21 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -836,7 +836,7 @@ def output_to_target(output, width, height): [batch_id, class_id, x, y, w, h, conf] """ - + if isinstance(output, torch.Tensor): output = output.cpu().numpy() @@ -846,10 +846,10 @@ def output_to_target(output, width, height): if o is not None: for pred in o: box = pred[:4] - w = (box[2]-box[0])/width - h = (box[3]-box[1])/height - x = box[0]/width + w/2 - y = box[1]/height + h/2 + w = (box[2] - box[0]) / width + h = (box[3] - box[1]) / height + x = box[0] / width + w / 2 + y = box[1] / height + h / 2 conf = pred[4] cls = int(pred[5]) @@ -893,111 +893,80 @@ def plot_wh_methods(): # from utils.utils import *; plot_wh_methods() fig.savefig('comparison.png', dpi=200) -def plot_images(images, targets, paths=None, fname='images.jpg', names=None, class_labels=True, confidence_labels=True, max_size=640, max_subplots=16): +def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max_size=640, max_subplots=16): + tl = 3 # line thickness + tf = max(tl - 1, 1) # font thickness if isinstance(images, torch.Tensor): images = images.cpu().numpy() - + if isinstance(targets, torch.Tensor): targets = targets.cpu().numpy() - + # un-normalise if np.max(images[0]) <= 1: images *= 255 - + bs, _, h, w = images.shape # batch size, _, height, width bs = min(bs, max_subplots) # limit plot images ns = np.ceil(bs ** 0.5) # number of subplots (square) - + # Check if we should resize - should_resize = False - if w > max_size or h > max_size: - scale_factor = max_size/max(h, w) - h = math.ceil(scale_factor*h) - w = math.ceil(scale_factor*w) - should_resize=True - + scale_factor = max_size / max(h, w) + if scale_factor < 1: + h = math.ceil(scale_factor * h) + w = math.ceil(scale_factor * w) + # Empty array for output - mosaic_width = int(ns*w) - mosaic_height = int(ns*h) - mosaic = 255*np.ones((mosaic_height, mosaic_width, 3), dtype=np.uint8) - + mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) + # Fix class - colour map prop_cycle = plt.rcParams['axes.prop_cycle'] # https://stackoverflow.com/questions/51350872/python-from-color-name-to-rgb - hex2rgb = lambda h : tuple(int(h[1+i:1+i+2], 16) for i in (0, 2, 4)) + hex2rgb = lambda h: tuple(int(h[1 + i:1 + i + 2], 16) for i in (0, 2, 4)) color_lut = [hex2rgb(h) for h in prop_cycle.by_key()['color']] - for i, image in enumerate(images): - - # e.g. if the last batch has fewer images than we expect - if i == max_subplots: + for i, img in enumerate(images): + if i == max_subplots: # if last batch has fewer images than we expect break - + block_x = int(w * (i // ns)) block_y = int(h * (i % ns)) - - image = image.transpose(1,2,0) - - if should_resize: - image = cv2.resize(image, (w, h)) - - mosaic[block_y:block_y+h, block_x:block_x+w,:] = image - + + img = img.transpose(1, 2, 0) + if scale_factor < 1: + img = cv2.resize(img, (w, h)) + + mosaic[block_y:block_y + h, block_x:block_x + w, :] = img if targets is not None: image_targets = targets[targets[:, 0] == i] - boxes = xywh2xyxy(image_targets[:,2:6]).T - classes = image_targets[:,1].astype('int') - - # Check if we have object confidences (gt vs pred) - confidences = None - if image_targets.shape[1] > 6: - confidences = image_targets[:,6] - + boxes = xywh2xyxy(image_targets[:, 2:6]).T + classes = image_targets[:, 1].astype('int') + gt = image_targets.shape[1] == 6 # ground truth if no conf column + conf = None if gt else image_targets[:, 6] # check for confidence presence (gt vs pred) + boxes[[0, 2]] *= w boxes[[0, 2]] += block_x - boxes[[1, 3]] *= h boxes[[1, 3]] += block_y - for j, box in enumerate(boxes.T): - color = color_lut[int(classes[j]) % len(color_lut)] - box = box.astype(int) - cv2.rectangle(mosaic, (box[0], box[1]), (box[2], box[3]), color, thickness=2) - - # Draw class label - if class_labels and max_size > 250: - label = str(classes[j]) if names is None else names[classes[j]] - if confidences is not None and confidence_labels: - label += " {:1.2f}".format(confidences[j]) - - font_scale = 0.4/10 * min(20, h * 0.05) - font_thickness = 2 if max(w, h) > 320 else 1 - - label_size, _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, font_scale, font_thickness) - cv2.rectangle(mosaic, (box[0], box[1]), (box[0]+label_size[0], box[1]-label_size[1]), color, thickness=-1) - cv2.putText(mosaic, label, (box[0], box[1]), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=font_scale, thickness=font_thickness, color=(255,255,255)) - + cls = int(classes[j]) + color = color_lut[cls % len(color_lut)] + cls = names[cls] if names else cls + if gt or conf[j] > 0.3: # 0.3 conf thresh + label = '%s' % cls if gt else '%s %.1f' % (cls, conf[j]) + plot_one_box(box, mosaic, label=label, color=color, line_thickness=tl) + # Draw image filename labels if paths is not None: - # Trim to 40 chars - label = os.path.basename(paths[i])[:40] - - # Empirical calculation to fit label - # 0.4 is at most (13, 10) px per char at thickness = 1 - # Fit label to 20px high, or shrink if it would be too big - max_font_scale = (w/len(label))*(0.4/8) - font_scale = min(0.4 * 20/8.5, max_font_scale) - font_thickness = 1 - - label_size, baseline = cv2.getTextSize(label, cv2.FONT_HERSHEY_DUPLEX, font_scale, font_thickness) - - cv2.rectangle(mosaic, (block_x+5, block_y+label_size[1]+baseline+5), (block_x+label_size[0]+5, block_y), 0, thickness=-1) - cv2.putText(mosaic, label, (block_x+5, block_y+label_size[1]+5), cv2.FONT_HERSHEY_DUPLEX, font_scale, (255,255,255), font_thickness) - + label = os.path.basename(paths[i])[:40] # trim to 40 char + t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] + cv2.putText(mosaic, label, (block_x + 5, block_y + t_size[1] + 5), 0, tl / 3, [220, 220, 220], thickness=tf, + lineType=cv2.LINE_AA) + # Image border - cv2.rectangle(mosaic, (block_x, block_y), (block_x+w, block_y+h), (255,255,255), thickness=3) - + cv2.rectangle(mosaic, (block_x, block_y), (block_x + w, block_y + h), (255, 255, 255), thickness=3) + if fname is not None: cv2.imwrite(fname, cv2.cvtColor(mosaic, cv2.COLOR_BGR2RGB)) From b0629d622cf546fa60bd24b951857bb9b447cc35 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 30 Apr 2020 15:03:32 -0700 Subject: [PATCH 0726/1185] bug fix on #1114 --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 642ebdba21..a317b6ee34 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -938,7 +938,7 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max img = cv2.resize(img, (w, h)) mosaic[block_y:block_y + h, block_x:block_x + w, :] = img - if targets is not None: + if len(targets) > 0: image_targets = targets[targets[:, 0] == i] boxes = xywh2xyxy(image_targets[:, 2:6]).T classes = image_targets[:, 1].astype('int') From be87b41aa2fe59be8e62f4b488052b24ad0bd450 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 30 Apr 2020 16:50:58 -0700 Subject: [PATCH 0727/1185] update image display per #1114 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 85d169a2f7..b0246edd2a 100755 --- a/README.md +++ b/README.md @@ -51,9 +51,9 @@ Python 3.7 or later with all `pip install -U -r requirements.txt` packages inclu ## Image Augmentation -`datasets.py` applies OpenCV-powered (https://opencv.org/) augmentation to the input image. We use a **mosaic dataloader** (pictured below) to increase image variability during training. +`datasets.py` applies OpenCV-powered (https://opencv.org/) augmentation to the input image. We use a **mosaic dataloader** to increase image variability during training. - + ## Speed From ee7cba65a5637a1d857b43743deee3aa55e371da Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 2 May 2020 09:20:19 -0700 Subject: [PATCH 0728/1185] kmeans() cleanup --- utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index a317b6ee34..010f16de69 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -690,7 +690,7 @@ def coco_single_class_labels(path='../coco/labels/train2014/', label_class=43): shutil.copyfile(src=img_file, dst='new/images/' + Path(file).name.replace('txt', 'jpg')) # copy images -def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 1024), thr=0.10, gen=1000): +def kmean_anchors(path='./data/coco64.txt', n=9, img_size=(320, 1024), thr=0.20, gen=1000): # Creates kmeans anchors for use in *.cfg files: from utils.utils import *; _ = kmean_anchors() # n: number of anchors # img_size: (min, max) image size used for multi-scale training (can be same values) @@ -717,7 +717,7 @@ def fitness(k): # mutation fitness # Get label wh wh = [] - dataset = LoadImagesAndLabels(path, augment=True, rect=True, cache_labels=True) + dataset = LoadImagesAndLabels(path, augment=True, rect=True) nr = 1 if img_size[0] == img_size[1] else 10 # number augmentation repetitions for s, l in zip(dataset.shapes, dataset.labels): wh.append(l[:, 3:5] * (s / s.max())) # image normalized to letterbox normalized wh From add73a0e74fc6b18d0a6ecbf7516d691f0cc4a16 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 2 May 2020 10:23:40 -0700 Subject: [PATCH 0729/1185] speed update --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b0246edd2a..223101f5ff 100755 --- a/README.md +++ b/README.md @@ -58,15 +58,15 @@ Python 3.7 or later with all `pip install -U -r requirements.txt` packages inclu ## Speed https://cloud.google.com/deep-learning-vm/ -**Machine type:** preemptible [n1-standard-16](https://cloud.google.com/compute/docs/machine-types) (16 vCPUs, 60 GB memory) +**Machine type:** preemptible [n1-standard-8](https://cloud.google.com/compute/docs/machine-types) (8 vCPUs, 30 GB memory) **CPU platform:** Intel Skylake **GPUs:** K80 ($0.14/hr), T4 ($0.11/hr), V100 ($0.74/hr) CUDA with [Nvidia Apex](https://github.com/NVIDIA/apex) FP16/32 **HDD:** 1 TB SSD **Dataset:** COCO train 2014 (117,263 images) **Model:** `yolov3-spp.cfg` -**Command:** `python3 train.py --img 416 --batch 32 --accum 2` +**Command:** `python3 train.py --data coco2017.data --img 416 --batch 32` -GPU |n| `--batch --accum` | img/s | epoch
time | epoch
cost +GPU | n | `--batch-size` | img/s | epoch
time | epoch
cost --- |--- |--- |--- |--- |--- K80 |1| 32 x 2 | 11 | 175 min | $0.41 T4 |1
2| 32 x 2
64 x 1 | 41
61 | 48 min
32 min | $0.09
$0.11 From 23614b8c2ec2e07aabecdda74f3b27acae6544af Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 2 May 2020 10:24:26 -0700 Subject: [PATCH 0730/1185] speed update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 223101f5ff..2ec31121a2 100755 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ https://cloud.google.com/deep-learning-vm/ **Machine type:** preemptible [n1-standard-8](https://cloud.google.com/compute/docs/machine-types) (8 vCPUs, 30 GB memory) **CPU platform:** Intel Skylake **GPUs:** K80 ($0.14/hr), T4 ($0.11/hr), V100 ($0.74/hr) CUDA with [Nvidia Apex](https://github.com/NVIDIA/apex) FP16/32 -**HDD:** 1 TB SSD +**HDD:** 300 GB SSD **Dataset:** COCO train 2014 (117,263 images) **Model:** `yolov3-spp.cfg` **Command:** `python3 train.py --data coco2017.data --img 416 --batch 32` From b0b52eec53e43548430f823e4d60032fab163228 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 2 May 2020 11:09:09 -0700 Subject: [PATCH 0731/1185] yolov4 tensorrt --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ec31121a2..0329a13579 100755 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Python 3.7 or later with all `pip install -U -r requirements.txt` packages inclu * [Google Colab Notebook](https://colab.research.google.com/github/ultralytics/yolov3/blob/master/tutorial.ipynb) with quick training, inference and testing examples * [GCP Quickstart](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) * [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) -* [A TensorRT Implementation of YOLOv3-SPP](https://github.com/wang-xinyu/tensorrtx/tree/master/yolov3-spp) +* [A TensorRT Implementation of YOLOv3 and YOLOv4](https://github.com/wang-xinyu/tensorrtx/tree/master/yolov3-spp) # Training From 5d42cc1b9a90e26b0b9bffba61fae93f5d1691b9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 2 May 2020 18:44:31 -0700 Subject: [PATCH 0732/1185] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0329a13579..06a3ecddae 100755 --- a/README.md +++ b/README.md @@ -155,11 +155,12 @@ Speed: 17.5/2.3/19.9 ms inference/NMS/total per 640x640 image at batch-size 16 # Reproduce Our Results -This command trains `yolov3-spp.cfg` from scratch to our mAP above. Training takes about one week on a 2080Ti. +Run commands below. Training takes about one week on a 2080Ti per model. ```bash -$ python3 train.py --weights '' --cfg yolov3-spp.cfg --epochs 300 --batch-size 16 --img 320 640 +$ python train.py --data coco2014.data --weights '' --batch-size 16 --cfg yolov3-spp.cfg +$ python train.py --data coco2014.data --weights '' --batch-size 32 --cfg yolov3-tiny.cfg ``` - + # Reproduce Our Environment From d40595989388e0c99b7ee7e391b2ca9a7edb7848 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 4 May 2020 13:33:34 -0700 Subject: [PATCH 0733/1185] cleanup --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 5ee55f88db..1c70e19368 100644 --- a/train.py +++ b/train.py @@ -72,7 +72,7 @@ def train(): imgsz_min //= 1.5 imgsz_max //= 0.667 grid_min, grid_max = imgsz_min // gs, imgsz_max // gs - imgsz_min, imgsz_max = grid_min * gs, grid_max * gs + imgsz_min, imgsz_max = int(grid_min * gs), int(grid_max * gs) img_size = imgsz_max # initialize with max size # Configure run From 832ceba55916e9c7fa15ff47dbf1edb573fcf6d6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 6 May 2020 10:14:31 -0700 Subject: [PATCH 0734/1185] update bug report template --- .github/ISSUE_TEMPLATE/--bug-report.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/--bug-report.md b/.github/ISSUE_TEMPLATE/--bug-report.md index ecc096f868..f430908d17 100644 --- a/.github/ISSUE_TEMPLATE/--bug-report.md +++ b/.github/ISSUE_TEMPLATE/--bug-report.md @@ -8,13 +8,13 @@ assignees: '' --- Before submitting a bug report, please ensure that you are using the latest versions of: - - python - - torch - - this repo (run `git status` and `git pull`) + - Python + - PyTorch + - This repository (run `git status -uno` to check and `git pull` to update) **Your issue must be reproducible on a public dataset (i.e COCO) using the latest version of the repository, and you must supply code to reproduce, or we can not help you.** -If this is a custom training question we suggest you include your `train_batch0.png` and `results.png` figures. +If this is a custom training question we suggest you include your `train*.jpg`, `test*.jpg` and `results.png` figures. ## 🐛 Bug From 965155ee60b534e0f71029a1c7ddc0a2cad50f8d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 6 May 2020 10:26:28 -0700 Subject: [PATCH 0735/1185] CUBLAS bug fix #1139 --- utils/utils.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 010f16de69..d6d9f947dc 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -556,13 +556,15 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T boxes, scores = x[:, :4].clone() + c.view(-1, 1) * max_wh, x[:, 4] # boxes (offset by class), scores if method == 'merge': # Merge NMS (boxes merged using weighted mean) i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - if n < 3E3: # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) - # weights = (box_iou(boxes, boxes).tril_() > iou_thres) * scores.view(-1, 1) # box weights - # weights /= weights.sum(0) # normalize - # x[:, :4] = torch.mm(weights.T, x[:, :4]) - weights = (box_iou(boxes[i], boxes) > iou_thres) * scores[None] # box weights - x[i, :4] = torch.mm(weights / weights.sum(1, keepdim=True), x[:, :4]).float() # merged boxes - + if 1 < n < 3E3: # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) + try: + # weights = (box_iou(boxes, boxes).tril_() > iou_thres) * scores.view(-1, 1) # box weights + # weights /= weights.sum(0) # normalize + # x[:, :4] = torch.mm(weights.T, x[:, :4]) + weights = (box_iou(boxes[i], boxes) > iou_thres) * scores[None] # box weights + x[i, :4] = torch.mm(weights / weights.sum(1, keepdim=True), x[:, :4]).float() # merged boxes + except: # possible CUDA error https://github.com/ultralytics/yolov3/issues/1139 + pass elif method == 'vision': i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) elif method == 'fast': # FastNMS from https://github.com/dbolya/yolact From ae2bc020eb81f7a92d538c210d70d1a14a7645cc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 9 May 2020 22:35:44 -0700 Subject: [PATCH 0736/1185] git status check - linux and darwin --- detect.py | 1 - utils/utils.py | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/detect.py b/detect.py index 635d705978..15582a5d7f 100644 --- a/detect.py +++ b/detect.py @@ -1,5 +1,4 @@ import argparse -from sys import platform from models import * # set ONNX_EXPORT in models.py from utils.datasets import * diff --git a/utils/utils.py b/utils/utils.py index d6d9f947dc..a07c430c93 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -5,6 +5,7 @@ import shutil import subprocess from pathlib import Path +from sys import platform import cv2 import matplotlib @@ -33,10 +34,11 @@ def init_seeds(seed=0): def check_git_status(): - # Suggest 'git pull' if repo is out of date - s = subprocess.check_output('if [ -d .git ]; then git fetch && git status -uno; fi', shell=True).decode('utf-8') - if 'Your branch is behind' in s: - print(s[s.find('Your branch is behind'):s.find('\n\n')] + '\n') + if platform in ['linux', 'darwin']: + # Suggest 'git pull' if repo is out of date + s = subprocess.check_output('if [ -d .git ]; then git fetch && git status -uno; fi', shell=True).decode('utf-8') + if 'Your branch is behind' in s: + print(s[s.find('Your branch is behind'):s.find('\n\n')] + '\n') def load_classes(path): From 9f04e175f62dca079f2e6c829f97dbb32e66b33d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 10 May 2020 11:26:37 -0700 Subject: [PATCH 0737/1185] nms torch.mm() update --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index a07c430c93..f7ce54f74f 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -564,7 +564,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T # weights /= weights.sum(0) # normalize # x[:, :4] = torch.mm(weights.T, x[:, :4]) weights = (box_iou(boxes[i], boxes) > iou_thres) * scores[None] # box weights - x[i, :4] = torch.mm(weights / weights.sum(1, keepdim=True), x[:, :4]).float() # merged boxes + x[i, :4] = torch.mm(weights, x[:, :4]).float() / weights.sum(1, keepdim=True) # merged boxes except: # possible CUDA error https://github.com/ultralytics/yolov3/issues/1139 pass elif method == 'vision': From 894a3e54ca002f2296a91de3d07685f8b121b113 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 11 May 2020 11:14:34 -0700 Subject: [PATCH 0738/1185] Update --bug-report.md --- .github/ISSUE_TEMPLATE/--bug-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/--bug-report.md b/.github/ISSUE_TEMPLATE/--bug-report.md index f430908d17..500b606b3a 100644 --- a/.github/ISSUE_TEMPLATE/--bug-report.md +++ b/.github/ISSUE_TEMPLATE/--bug-report.md @@ -10,7 +10,7 @@ assignees: '' Before submitting a bug report, please ensure that you are using the latest versions of: - Python - PyTorch - - This repository (run `git status -uno` to check and `git pull` to update) + - This repository (run `git fetch && git status -uno` to check and `git pull` to update) **Your issue must be reproducible on a public dataset (i.e COCO) using the latest version of the repository, and you must supply code to reproduce, or we can not help you.** From 031c2144ecfc7931a4b9e34a26c4ae0b6dee021f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 12 May 2020 08:31:36 -0700 Subject: [PATCH 0739/1185] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 06a3ecddae..baa2ccbfcf 100755 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ https://cloud.google.com/deep-learning-vm/ **Machine type:** preemptible [n1-standard-8](https://cloud.google.com/compute/docs/machine-types) (8 vCPUs, 30 GB memory) **CPU platform:** Intel Skylake **GPUs:** K80 ($0.14/hr), T4 ($0.11/hr), V100 ($0.74/hr) CUDA with [Nvidia Apex](https://github.com/NVIDIA/apex) FP16/32 -**HDD:** 300 GB SSD +**HDD:** 300 GB SSD **Dataset:** COCO train 2014 (117,263 images) **Model:** `yolov3-spp.cfg` **Command:** `python3 train.py --data coco2017.data --img 416 --batch 32` From 0cf88f046d1a00f92850566d13fa837edfb09c02 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 12 May 2020 09:53:13 -0700 Subject: [PATCH 0740/1185] hyp evolution bug fix #1160 --- train.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 1c70e19368..0f4997e1da 100644 --- a/train.py +++ b/train.py @@ -54,7 +54,7 @@ print('Using FocalLoss(gamma=%g)' % hyp['fl_gamma']) -def train(): +def train(hyp): cfg = opt.cfg data = opt.data epochs = opt.epochs # 500200 batches at bs 64, 117263 images = 273 epochs @@ -409,7 +409,7 @@ def train(): if not opt.evolve: # Train normally print('Start Tensorboard with "tensorboard --logdir=runs", view at http://localhost:6006/') tb_writer = SummaryWriter(comment=opt.name) - train() # train normally + train(hyp) # train normally else: # Evolve hyperparameters (optional) opt.notest, opt.nosave = True, True # only test/save final epoch @@ -455,7 +455,7 @@ def train(): hyp[k] = np.clip(hyp[k], v[0], v[1]) # Train mutation - results = train() + results = train(hyp.copy()) # Write mutation results print_mutation(hyp, results, opt.bucket) From b2fcfc573e5418c0b2ef0c0357bf51bc5cb027b6 Mon Sep 17 00:00:00 2001 From: IlyaOvodov <34230114+IlyaOvodov@users.noreply.github.com> Date: Wed, 13 May 2020 19:08:55 +0300 Subject: [PATCH 0741/1185] convert(...) changed to save converted file alongside the original file (#1167) --- README.md | 4 ++-- models.py | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index baa2ccbfcf..c1e62d0f4d 100755 --- a/README.md +++ b/README.md @@ -107,11 +107,11 @@ $ git clone https://github.com/ultralytics/yolov3 && cd yolov3 # convert darknet cfg/weights to pytorch model $ python3 -c "from models import *; convert('cfg/yolov3-spp.cfg', 'weights/yolov3-spp.weights')" -Success: converted 'weights/yolov3-spp.weights' to 'converted.pt' +Success: converted 'weights/yolov3-spp.weights' to 'weights/yolov3-spp.pt' # convert cfg/pytorch model to darknet weights $ python3 -c "from models import *; convert('cfg/yolov3-spp.cfg', 'weights/yolov3-spp.pt')" -Success: converted 'weights/yolov3-spp.pt' to 'converted.weights' +Success: converted 'weights/yolov3-spp.pt' to 'weights/yolov3-spp.weights' ``` # mAP diff --git a/models.py b/models.py index afd5b87b0e..ebe151b6a3 100755 --- a/models.py +++ b/models.py @@ -423,8 +423,9 @@ def convert(cfg='cfg/yolov3-spp.cfg', weights='weights/yolov3-spp.weights'): # Load weights and save if weights.endswith('.pt'): # if PyTorch format model.load_state_dict(torch.load(weights, map_location='cpu')['model']) - save_weights(model, path='converted.weights', cutoff=-1) - print("Success: converted '%s' to 'converted.weights'" % weights) + target = weights.rsplit('.', 1)[0] + '.weights' + save_weights(model, path=target, cutoff=-1) + print("Success: converted '%s' to '%s'" % (weights, target)) elif weights.endswith('.weights'): # darknet format _ = load_darknet_weights(model, weights) @@ -435,8 +436,9 @@ def convert(cfg='cfg/yolov3-spp.cfg', weights='weights/yolov3-spp.weights'): 'model': model.state_dict(), 'optimizer': None} - torch.save(chkpt, 'converted.pt') - print("Success: converted '%s' to 'converted.pt'" % weights) + target = weights.rsplit('.', 1)[0] + '.pt' + torch.save(chkpt, target) + print("Success: converted '%s' to '%'" % (weights, target)) else: print('Error: extension not supported.') From 6fe67595cb856fe9b8d8c745c241aec3f772731b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 15 May 2020 11:32:23 -0700 Subject: [PATCH 0742/1185] add stride order reversal for c53*.cfg --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index ebe151b6a3..a85bf9872b 100755 --- a/models.py +++ b/models.py @@ -93,7 +93,7 @@ def create_modules(module_defs, img_size, cfg): elif mdef['type'] == 'yolo': yolo_index += 1 stride = [32, 16, 8] # P5, P4, P3 strides - if 'panet' in cfg or 'yolov4' in cfg: # stride order reversed + if 'panet' in cfg or 'yolov4' or 'cd53' in cfg: # stride order reversed stride = list(reversed(stride)) layers = mdef['from'] if 'from' in mdef else [] modules = YOLOLayer(anchors=mdef['anchors'][mdef['mask']], # anchor list From 20891926c9f721a338ff6183514819f2fa8077f6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 15 May 2020 14:40:14 -0700 Subject: [PATCH 0743/1185] add stride order reversal for c53*.cfg --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index a85bf9872b..0c0d6fa00a 100755 --- a/models.py +++ b/models.py @@ -93,7 +93,7 @@ def create_modules(module_defs, img_size, cfg): elif mdef['type'] == 'yolo': yolo_index += 1 stride = [32, 16, 8] # P5, P4, P3 strides - if 'panet' in cfg or 'yolov4' or 'cd53' in cfg: # stride order reversed + if any(x in cfg for x in ['panet', 'yolov4', 'cd53']): # stride order reversed stride = list(reversed(stride)) layers = mdef['from'] if 'from' in mdef else [] modules = YOLOLayer(anchors=mdef['anchors'][mdef['mask']], # anchor list From f6a19d5b32194996819f5ada1873b9fef412ec4a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 15 May 2020 16:20:04 -0700 Subject: [PATCH 0744/1185] add cd53-based *.cfg --- cfg/cd53s-yolov3.cfg | 1033 +++++++++++++++++++++++++++++++++++++ cfg/cd53s.cfg | 1155 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2188 insertions(+) create mode 100644 cfg/cd53s-yolov3.cfg create mode 100644 cfg/cd53s.cfg diff --git a/cfg/cd53s-yolov3.cfg b/cfg/cd53s-yolov3.cfg new file mode 100644 index 0000000000..431a2a081e --- /dev/null +++ b/cfg/cd53s-yolov3.cfg @@ -0,0 +1,1033 @@ +[net] +# Testing +#batch=1 +#subdivisions=1 +# Training +batch=64 +subdivisions=8 +width=512 +height=512 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +#cutmix=1 +mosaic=1 + +#23:104x104 54:52x52 85:26x26 104:13x13 for 416 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=2 +pad=1 +activation=leaky + +#[convolutional] +#batch_normalize=1 +#filters=64 +#size=1 +#stride=1 +#pad=1 +#activation=leaky + +#[route] +#layers = -2 + +#[convolutional] +#batch_normalize=1 +#filters=64 +#size=1 +#stride=1 +#pad=1 +#activation=leaky + +[convolutional] +batch_normalize=1 +filters=32 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +#[convolutional] +#batch_normalize=1 +#filters=64 +#size=1 +#stride=1 +#pad=1 +#activation=leaky + +#[route] +#layers = -1,-7 + +#[convolutional] +#batch_normalize=1 +#filters=64 +#size=1 +#stride=1 +#pad=1 +#activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-10 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-28 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-28 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-16 + +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=leaky + +########################## + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 6,7,8 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 79 + + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 3,4,5 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.1 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 48 + + + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 0,1,2 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.2 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 diff --git a/cfg/cd53s.cfg b/cfg/cd53s.cfg new file mode 100644 index 0000000000..221b13bb75 --- /dev/null +++ b/cfg/cd53s.cfg @@ -0,0 +1,1155 @@ +[net] +# Testing +#batch=1 +#subdivisions=1 +# Training +batch=64 +subdivisions=8 +width=512 +height=512 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +#cutmix=1 +mosaic=1 + +#23:104x104 54:52x52 85:26x26 104:13x13 for 416 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=2 +pad=1 +activation=leaky + +#[convolutional] +#batch_normalize=1 +#filters=64 +#size=1 +#stride=1 +#pad=1 +#activation=leaky + +#[route] +#layers = -2 + +#[convolutional] +#batch_normalize=1 +#filters=64 +#size=1 +#stride=1 +#pad=1 +#activation=leaky + +[convolutional] +batch_normalize=1 +filters=32 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +#[convolutional] +#batch_normalize=1 +#filters=64 +#size=1 +#stride=1 +#pad=1 +#activation=leaky + +#[route] +#layers = -1,-7 + +#[convolutional] +#batch_normalize=1 +#filters=64 +#size=1 +#stride=1 +#pad=1 +#activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-10 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-28 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-28 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-16 + +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=leaky + +########################## + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = 79 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = 48 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +########################## + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 0,1,2 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=256 +activation=leaky + +[route] +layers = -1, -16 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 3,4,5 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=512 +activation=leaky + +[route] +layers = -1, -37 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + +[yolo] +mask = 6,7,8 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 From 3f27ef1253bf83429350cbaeb8e1d01aff9de7ae Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 15 May 2020 20:50:58 -0700 Subject: [PATCH 0745/1185] pycocotools and numpy 1.17 fix for #1182 --- requirements.txt | 3 ++- test.py | 25 +++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/requirements.txt b/requirements.txt index c82ddd8d26..08c696bb0b 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ # pip install -U -r requirements.txt -numpy +# pycocotools requires numpy 1.17 https://github.com/cocodataset/cocoapi/issues/356 +numpy == 1.17 opencv-python >= 4.1 torch >= 1.5 matplotlib diff --git a/test.py b/test.py index 0f968811f9..a4b2ab6bfa 100644 --- a/test.py +++ b/test.py @@ -204,19 +204,20 @@ def test(cfg, try: from pycocotools.coco import COCO from pycocotools.cocoeval import COCOeval + + # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb + cocoGt = COCO(glob.glob('../coco/annotations/instances_val*.json')[0]) # initialize COCO ground truth api + cocoDt = cocoGt.loadRes('results.json') # initialize COCO pred api + + cocoEval = COCOeval(cocoGt, cocoDt, 'bbox') + cocoEval.params.imgIds = imgIds # [:32] # only evaluate these images + cocoEval.evaluate() + cocoEval.accumulate() + cocoEval.summarize() + # mf1, map = cocoEval.stats[:2] # update to pycocotools results (mAP@0.5:0.95, mAP@0.5) except: - print('WARNING: missing pycocotools package, can not compute official COCO mAP. See requirements.txt.') - - # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb - cocoGt = COCO(glob.glob('../coco/annotations/instances_val*.json')[0]) # initialize COCO ground truth api - cocoDt = cocoGt.loadRes('results.json') # initialize COCO pred api - - cocoEval = COCOeval(cocoGt, cocoDt, 'bbox') - cocoEval.params.imgIds = imgIds # [:32] # only evaluate these images - cocoEval.evaluate() - cocoEval.accumulate() - cocoEval.summarize() - # mf1, map = cocoEval.stats[:2] # update to pycocotools results (mAP@0.5:0.95, mAP@0.5) + print('WARNING: pycocotools must be installed with numpy==1.17 to run correctly. ' + 'See https://github.com/cocodataset/cocoapi/issues/356') # Return results maps = np.zeros(nc) + map From 3a71daf4bc2ecbb14c26842714f404dbed15fb24 Mon Sep 17 00:00:00 2001 From: orcund <50711354+orcund@users.noreply.github.com> Date: Sat, 16 May 2020 21:09:57 +0300 Subject: [PATCH 0746/1185] Pseudo Labeling (#1149) * Added pseudo labeling * Delete print_test.py * Refactor label generation * Update detect.py * Update detect.py * Update utils.py Co-authored-by: Glenn Jocher --- detect.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/detect.py b/detect.py index 15582a5d7f..d655e63de7 100644 --- a/detect.py +++ b/detect.py @@ -102,7 +102,7 @@ def detect(save_img=False): pred = apply_classifier(pred, modelc, img, im0s) # Process detections - for i, det in enumerate(pred): # detections per image + for i, det in enumerate(pred): # detections for image i if webcam: # batch_size >= 1 p, s, im0 = path[i], '%g: ' % i, im0s[i] else: @@ -110,6 +110,7 @@ def detect(save_img=False): save_path = str(Path(out) / Path(p).name) s += '%gx%g ' % img.shape[2:] # print string + gn = torch.tensor(im0s.shape)[[1, 0, 1, 0]] #  normalization gain whwh if det is not None and len(det): # Rescale boxes from img_size to im0 size det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() @@ -122,8 +123,9 @@ def detect(save_img=False): # Write results for *xyxy, conf, cls in det: if save_txt: # Write to file + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh with open(save_path + '.txt', 'a') as file: - file.write(('%g ' * 6 + '\n') % (*xyxy, cls, conf)) + file.write(('%g ' * 5 + '\n') % (cls, *xywh)) # label format if save_img or view_img: # Add bbox to image label = '%s %.2f' % (names[int(cls)], conf) From 27c7b02ffffc4cacdbd6cf4c257ca17d9353228a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 16 May 2020 11:51:49 -0700 Subject: [PATCH 0747/1185] --save-txt extension fix --- detect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detect.py b/detect.py index d655e63de7..46d6de760a 100644 --- a/detect.py +++ b/detect.py @@ -124,7 +124,7 @@ def detect(save_img=False): for *xyxy, conf, cls in det: if save_txt: # Write to file xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh - with open(save_path + '.txt', 'a') as file: + with open(save_path[:save_path.rfind('.')] + '.txt', 'a') as file: file.write(('%g ' * 5 + '\n') % (cls, *xywh)) # label format if save_img or view_img: # Add bbox to image From 37bd5490ef8e804a39840c84f2fb6518ec878e7c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 16 May 2020 22:25:21 -0700 Subject: [PATCH 0748/1185] iglob file-search improvements --- detect.py | 3 +++ test.py | 3 +++ train.py | 3 +++ 3 files changed, 9 insertions(+) diff --git a/detect.py b/detect.py index 46d6de760a..67aceb195f 100644 --- a/detect.py +++ b/detect.py @@ -183,6 +183,9 @@ def detect(save_img=False): parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') parser.add_argument('--augment', action='store_true', help='augmented inference') opt = parser.parse_args() + opt.cfg = list(glob.iglob('./**/' + opt.cfg, recursive=True))[0] # find file + opt.names = list(glob.iglob('./**/' + opt.names, recursive=True))[0] # find file + opt.weights = list(glob.iglob('./**/' + opt.weights, recursive=True))[0] # find file print(opt) with torch.no_grad(): diff --git a/test.py b/test.py index a4b2ab6bfa..b902fb1b00 100644 --- a/test.py +++ b/test.py @@ -242,6 +242,9 @@ def test(cfg, parser.add_argument('--augment', action='store_true', help='augmented inference') opt = parser.parse_args() opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) + opt.weights = list(glob.iglob('./**/' + opt.weights, recursive=True))[0] # find file + opt.cfg = list(glob.iglob('./**/' + opt.cfg, recursive=True))[0] # find file + opt.data = list(glob.iglob('./**/' + opt.data, recursive=True))[0] # find file print(opt) # task = 'test', 'study', 'benchmark' diff --git a/train.py b/train.py index 0f4997e1da..d3bd51fda3 100644 --- a/train.py +++ b/train.py @@ -251,6 +251,7 @@ def train(hyp): if 'momentum' in x: x['momentum'] = np.interp(ni, [0, n_burn], [0.9, hyp['momentum']]) + # Multi-Scale if opt.multi_scale: if ni / accumulate % 1 == 0: #  adjust img_size (67% - 150%) every 1 batch @@ -396,6 +397,8 @@ def train(hyp): opt = parser.parse_args() opt.weights = last if opt.resume else opt.weights check_git_status() + opt.cfg = list(glob.iglob('./**/' + opt.cfg, recursive=True))[0] # find file + opt.data = list(glob.iglob('./**/' + opt.data, recursive=True))[0] # find file print(opt) opt.img_size.extend([opt.img_size[-1]] * (3 - len(opt.img_size))) # extend to 3 sizes (min, max, test) device = torch_utils.select_device(opt.device, apex=mixed_precision, batch_size=opt.batch_size) From 6bfb3a96c8fac5a53a5f625764d800f14fe640a7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 16 May 2020 22:43:12 -0700 Subject: [PATCH 0749/1185] iglob bug fix --- detect.py | 1 - test.py | 1 - 2 files changed, 2 deletions(-) diff --git a/detect.py b/detect.py index 67aceb195f..d6504a9b85 100644 --- a/detect.py +++ b/detect.py @@ -185,7 +185,6 @@ def detect(save_img=False): opt = parser.parse_args() opt.cfg = list(glob.iglob('./**/' + opt.cfg, recursive=True))[0] # find file opt.names = list(glob.iglob('./**/' + opt.names, recursive=True))[0] # find file - opt.weights = list(glob.iglob('./**/' + opt.weights, recursive=True))[0] # find file print(opt) with torch.no_grad(): diff --git a/test.py b/test.py index b902fb1b00..d997ea4a15 100644 --- a/test.py +++ b/test.py @@ -242,7 +242,6 @@ def test(cfg, parser.add_argument('--augment', action='store_true', help='augmented inference') opt = parser.parse_args() opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) - opt.weights = list(glob.iglob('./**/' + opt.weights, recursive=True))[0] # find file opt.cfg = list(glob.iglob('./**/' + opt.cfg, recursive=True))[0] # find file opt.data = list(glob.iglob('./**/' + opt.data, recursive=True))[0] # find file print(opt) From bbd82bb94daaad70773abc28b4fc1b9890f24f9a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 17 May 2020 14:30:12 -0700 Subject: [PATCH 0750/1185] updates --- utils/datasets.py | 4 ++-- utils/torch_utils.py | 6 +++--- utils/utils.py | 39 +++++++++------------------------------ 3 files changed, 14 insertions(+), 35 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 3ea4203104..2b5a0bf3ec 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -626,9 +626,8 @@ def letterbox(img, new_shape=(416, 416), color=(114, 114, 114), auto=True, scale def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, border=0): # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) # https://medium.com/uruvideo/dataset-augmentation-with-random-homographies-a8f4b44830d4 + # targets = [cls, xyxy] - if targets is None: # targets = [cls, xyxy] - targets = [] height = img.shape[0] + border * 2 width = img.shape[1] + border * 2 @@ -637,6 +636,7 @@ def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, a = random.uniform(-degrees, degrees) # a += random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotations s = random.uniform(1 - scale, 1 + scale) + # s = 2 ** random.uniform(-scale, scale) R[:2] = cv2.getRotationMatrix2D(angle=a, center=(img.shape[1] / 2, img.shape[0] / 2), scale=s) # Translation diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 215772bfbd..d4cd1e8078 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -12,10 +12,10 @@ def init_seeds(seed=0): torch.manual_seed(seed) - # Remove randomness (may be slower on Tesla GPUs) # https://pytorch.org/docs/stable/notes/randomness.html + # Reduce randomness (may be slower on Tesla GPUs) # https://pytorch.org/docs/stable/notes/randomness.html if seed == 0: - cudnn.deterministic = True - cudnn.benchmark = False + cudnn.deterministic = False + cudnn.benchmark = True def select_device(device='', apex=False, batch_size=None): diff --git a/utils/utils.py b/utils/utils.py index f7ce54f74f..88c8c54189 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -103,7 +103,7 @@ def coco80_to_coco91_class(): # converts 80-index (val2014) to 91-index (paper) def xyxy2xywh(x): - # Transform box coordinates from [x1, y1, x2, y2] (where xy1=top-left, xy2=bottom-right) to [x, y, w, h] + # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] where xy1=top-left, xy2=bottom-right y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) y[:, 0] = (x[:, 0] + x[:, 2]) / 2 # x center y[:, 1] = (x[:, 1] + x[:, 3]) / 2 # y center @@ -113,7 +113,7 @@ def xyxy2xywh(x): def xywh2xyxy(x): - # Transform box coordinates from [x, y, w, h] to [x1, y1, x2, y2] (where xy1=top-left, xy2=bottom-right) + # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y @@ -122,26 +122,6 @@ def xywh2xyxy(x): return y -# def xywh2xyxy(box): -# # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] -# if isinstance(box, torch.Tensor): -# x, y, w, h = box.t() -# return torch.stack((x - w / 2, y - h / 2, x + w / 2, y + h / 2)).t() -# else: # numpy -# x, y, w, h = box.T -# return np.stack((x - w / 2, y - h / 2, x + w / 2, y + h / 2)).T -# -# -# def xyxy2xywh(box): -# # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] -# if isinstance(box, torch.Tensor): -# x1, y1, x2, y2 = box.t() -# return torch.stack(((x1 + x2) / 2, (y1 + y2) / 2, x2 - x1, y2 - y1)).t() -# else: # numpy -# x1, y1, x2, y2 = box.T -# return np.stack(((x1 + x2) / 2, (y1 + y2) / 2, x2 - x1, y2 - y1)).T - - def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None): # Rescale coords (xyxy) from img1_shape to img0_shape if ratio_pad is None: # calculate from img0_shape @@ -187,7 +167,7 @@ def ap_per_class(tp, conf, pred_cls, target_cls): # Create Precision-Recall curve and compute AP for each class pr_score = 0.1 # score to evaluate P and R https://github.com/ultralytics/yolov3/issues/898 - s = [len(unique_classes), tp.shape[1]] # number class, number iou thresholds (i.e. 10 for mAP0.5...0.95) + s = [unique_classes.shape[0], tp.shape[1]] # number class, number iou thresholds (i.e. 10 for mAP0.5...0.95) ap, p, r = np.zeros(s), np.zeros(s), np.zeros(s) for ci, c in enumerate(unique_classes): i = pred_cls == c @@ -601,7 +581,7 @@ def print_model_biases(model): pass -def strip_optimizer(f='weights/last.pt'): # from utils.utils import *; strip_optimizer() +def strip_optimizer(f='weights/best.pt'): # from utils.utils import *; strip_optimizer() # Strip optimizer from *.pt files for lighter files (reduced by 2/3 size) x = torch.load(f, map_location=torch.device('cpu')) x['optimizer'] = None @@ -614,12 +594,11 @@ def create_backbone(f='weights/last.pt'): # from utils.utils import *; create_b x['optimizer'] = None x['training_results'] = None x['epoch'] = -1 - for p in x['model'].values(): - try: - p.requires_grad = True - except: - pass - torch.save(x, 'weights/backbone.pt') + for p in x['model'].parameters(): + p.requires_grad = True + s = 'weights/backbone.pt' + print('%s saved as %s' % (f, s)) + torch.save(x, s) def coco_class_count(path='../coco/labels/train2014/'): From c94019f159f6ac8148288a510f72ea9b33ce78b9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 17 May 2020 14:31:14 -0700 Subject: [PATCH 0751/1185] iglob bug fix --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index d3bd51fda3..d573890c62 100644 --- a/train.py +++ b/train.py @@ -398,7 +398,7 @@ def train(hyp): opt.weights = last if opt.resume else opt.weights check_git_status() opt.cfg = list(glob.iglob('./**/' + opt.cfg, recursive=True))[0] # find file - opt.data = list(glob.iglob('./**/' + opt.data, recursive=True))[0] # find file + # opt.data = list(glob.iglob('./**/' + opt.data, recursive=True))[0] # find file print(opt) opt.img_size.extend([opt.img_size[-1]] * (3 - len(opt.img_size))) # extend to 3 sizes (min, max, test) device = torch_utils.select_device(opt.device, apex=mixed_precision, batch_size=opt.batch_size) From 110ead20e63e4c10784284125f958b990d17fd54 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 17 May 2020 15:00:07 -0700 Subject: [PATCH 0752/1185] yolov5 regress updates to yolov3 --- utils/utils.py | 154 ++++++++++++++++++------------------------------- 1 file changed, 56 insertions(+), 98 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 88c8c54189..e00f778bb0 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -76,20 +76,6 @@ def labels_to_image_weights(labels, nc=80, class_weights=np.ones(80)): return image_weights -def coco_class_weights(): # frequency of each class in coco train2014 - n = [187437, 4955, 30920, 6033, 3838, 4332, 3160, 7051, 7677, 9167, 1316, 1372, 833, 6757, 7355, 3302, 3776, 4671, - 6769, 5706, 3908, 903, 3686, 3596, 6200, 7920, 8779, 4505, 4272, 1862, 4698, 1962, 4403, 6659, 2402, 2689, - 4012, 4175, 3411, 17048, 5637, 14553, 3923, 5539, 4289, 10084, 7018, 4314, 3099, 4638, 4939, 5543, 2038, 4004, - 5053, 4578, 27292, 4113, 5931, 2905, 11174, 2873, 4036, 3415, 1517, 4122, 1980, 4464, 1190, 2302, 156, 3933, - 1877, 17630, 4337, 4624, 1075, 3468, 135, 1380] - weights = 1 / torch.Tensor(n) - weights /= weights.sum() - # with open('data/coco.names', 'r') as f: - # for k, v in zip(f.read().splitlines(), n): - # print('%20s: %g' % (k, v)) - return weights - - def coco80_to_coco91_class(): # converts 80-index (val2014) to 91-index (paper) # https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/ # a = np.loadtxt('data/coco.names', dtype='str', delimiter='\n') @@ -355,7 +341,7 @@ def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#iss def compute_loss(p, targets, model): # predictions, targets, model ft = torch.cuda.FloatTensor if p[0].is_cuda else torch.Tensor lcls, lbox, lobj = ft([0]), ft([0]), ft([0]) - tcls, tbox, indices, anchor_vec = build_targets(p, targets, model) + tcls, tbox, indices, anchors = build_targets(p, targets, model) # targets h = model.hyp # hyperparameters red = 'mean' # Loss reduction (sum or mean) @@ -371,33 +357,33 @@ def compute_loss(p, targets, model): # predictions, targets, model if g > 0: BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) - # Compute losses - np, ng = 0, 0 # number grid points, targets + # per output + nt = 0 # targets for i, pi in enumerate(p): # layer index, layer predictions b, a, gj, gi = indices[i] # image, anchor, gridy, gridx tobj = torch.zeros_like(pi[..., 0]) # target obj - np += tobj.numel() - # Compute losses - nb = len(b) - if nb: # number of targets - ng += nb + nb = b.shape[0] # number of targets + if nb: + nt += nb ps = pi[b, a, gj, gi] # prediction subset corresponding to targets # ps[:, 2:4] = torch.sigmoid(ps[:, 2:4]) # wh power loss (uncomment) # GIoU - pxy = torch.sigmoid(ps[:, 0:2]) # pxy = pxy * s - (s - 1) / 2, s = 1.5 (scale_xy) - pwh = torch.exp(ps[:, 2:4]).clamp(max=1E3) * anchor_vec[i] + pxy = torch.sigmoid(ps[:, 0:2]) + pwh = torch.exp(ps[:, 2:4]).clamp(max=1E3) * anchors[i] pbox = torch.cat((pxy, pwh), 1) # predicted box - giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou computation + giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou(prediction, target) lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss + + # Obj tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * giou.detach().clamp(0).type(tobj.dtype) # giou ratio + # Class if model.nc > 1: # cls loss (only if multiple classes) t = torch.full_like(ps[:, 5:], cn) # targets t[range(nb), tcls[i]] = cp lcls += BCEcls(ps[:, 5:], t) # BCE - # lcls += CE(ps[:, 5:], tcls[i]) # CE # Append targets to text file # with open('targets.txt', 'a') as file: @@ -410,26 +396,24 @@ def compute_loss(p, targets, model): # predictions, targets, model lcls *= h['cls'] if red == 'sum': bs = tobj.shape[0] # batch size - lobj *= 3 / (6300 * bs) * 2 # 3 / np * 2 - if ng: - lcls *= 3 / ng / model.nc - lbox *= 3 / ng + g = 3.0 # loss gain + lobj *= g / bs + if nt: + lcls *= g / nt / model.nc + lbox *= g / nt loss = lbox + lobj + lcls return loss, torch.cat((lbox, lobj, lcls, loss)).detach() def build_targets(p, targets, model): - # targets = [image, class, x, y, w, h] - + # Build targets for compute_loss(), input targets(image,class,x,y,w,h) nt = targets.shape[0] - tcls, tbox, indices, av = [], [], [], [] + tcls, tbox, indices, anch = [], [], [], [] reject, use_all_anchors = True, True gain = torch.ones(6, device=targets.device) # normalized to gridspace gain - # m = list(model.modules())[-1] - # for i in range(m.nl): - # anchors = m.anchors[i] + multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) for i, j in enumerate(model.yolo_layers): # get number of grid points and anchor vec for this yolo layer @@ -455,16 +439,15 @@ def build_targets(p, targets, model): t, a = t[j], a[j] # Indices - b, c = t[:, :2].long().t() # target image, class - gxy = t[:, 2:4] # grid x, y - gwh = t[:, 4:6] # grid w, h - gi, gj = gxy.long().t() # grid x, y indices + b, c = t[:, :2].long().t() # image, class + gxy = t[:, 2:4] # grid xy + gwh = t[:, 4:6] # grid wh + gi, gj = gxy.long().t() # grid xy indices indices.append((b, a, gj, gi)) # Box - gxy -= gxy.floor() # xy - tbox.append(torch.cat((gxy, gwh), 1)) # xywh (grids) - av.append(anchors[a]) # anchor vec + tbox.append(torch.cat((gxy % 1., gwh), 1)) # xywh (grids) + anch.append(anchors[a]) # anchor vec # Class tcls.append(c) @@ -473,7 +456,7 @@ def build_targets(p, targets, model): 'See https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' % ( model.nc, model.nc - 1, c.max()) - return tcls, tbox, indices, av + return tcls, tbox, indices, anch def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=True, classes=None, agnostic=False): @@ -486,17 +469,14 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T # Box constraints min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height - method = 'merge' nc = prediction[0].shape[1] - 5 # number of classes multi_label &= nc > 1 # multiple labels per box - output = [None] * len(prediction) - + merge = True # merge for best mAP + output = [None] * prediction.shape[0] for xi, x in enumerate(prediction): # image index, image inference - # Apply conf constraint - x = x[x[:, 4] > conf_thres] - - # Apply width-height constraint - x = x[((x[:, 2:4] > min_wh) & (x[:, 2:4] < max_wh)).all(1)] + # Apply constraints + x = x[x[:, 4] > conf_thres] # confidence + # x = x[((x[:, 2:4] > min_wh) & (x[:, 2:4] < max_wh)).all(1)] # width-height # If none remain process next image if not x.shape[0]: @@ -521,8 +501,8 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T x = x[(j.view(-1, 1) == torch.tensor(classes, device=j.device)).any(1)] # Apply finite constraint - if not torch.isfinite(x).all(): - x = x[torch.isfinite(x).all(1)] + # if not torch.isfinite(x).all(): + # x = x[torch.isfinite(x).all(1)] # If none remain process next image n = x.shape[0] # number of boxes @@ -530,28 +510,21 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T continue # Sort by confidence - # if method == 'fast_batch': - # x = x[x[:, 4].argsort(descending=True)] + # x = x[x[:, 4].argsort(descending=True)] # Batched NMS c = x[:, 5] * 0 if agnostic else x[:, 5] # classes boxes, scores = x[:, :4].clone() + c.view(-1, 1) * max_wh, x[:, 4] # boxes (offset by class), scores - if method == 'merge': # Merge NMS (boxes merged using weighted mean) - i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - if 1 < n < 3E3: # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) - try: - # weights = (box_iou(boxes, boxes).tril_() > iou_thres) * scores.view(-1, 1) # box weights - # weights /= weights.sum(0) # normalize - # x[:, :4] = torch.mm(weights.T, x[:, :4]) - weights = (box_iou(boxes[i], boxes) > iou_thres) * scores[None] # box weights - x[i, :4] = torch.mm(weights, x[:, :4]).float() / weights.sum(1, keepdim=True) # merged boxes - except: # possible CUDA error https://github.com/ultralytics/yolov3/issues/1139 - pass - elif method == 'vision': - i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - elif method == 'fast': # FastNMS from https://github.com/dbolya/yolact - iou = box_iou(boxes, boxes).triu_(diagonal=1) # upper triangular iou matrix - i = iou.max(0)[0] < iou_thres + i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) + if merge and (1 < n < 3E3): # Merge NMS (boxes merged using weighted mean) + try: # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) + iou = box_iou(boxes[i], boxes) > iou_thres # iou matrix + weights = iou * scores[None] # box weights + x[i, :4] = torch.mm(weights, x[:, :4]).float() / weights.sum(1, keepdim=True) # merged boxes + # i = i[iou.sum(1) > 1] # require redundancy + except: # possible CUDA error https://github.com/ultralytics/yolov3/issues/1139 + print(x, i, x.shape, i.shape) + pass output[xi] = x[i] return output @@ -621,13 +594,6 @@ def coco_only_people(path='../coco/labels/train2017/'): # from utils.utils impo print(labels.shape[0], file) -def select_best_evolve(path='evolve*.txt'): # from utils.utils import *; select_best_evolve() - # Find best evolved mutation - for file in sorted(glob.glob(path)): - x = np.loadtxt(file, dtype=np.float32, ndmin=2) - print(file, x[fitness(x).argmax()]) - - def crop_images_random(path='../images/', scale=0.50): # from utils.utils import *; crop_images_random() # crops images into random squares up to scale fraction # WARNING: overwrites images! @@ -708,17 +674,12 @@ def fitness(k): # mutation fitness wh *= np.random.uniform(img_size[0], img_size[1], size=(wh.shape[0], 1)) # normalized to pixels (multi-scale) wh = wh[(wh > 2.0).all(1)] # remove below threshold boxes (< 2 pixels wh) - # Darknet yolov3.cfg anchors - use_darknet = False - if use_darknet and n == 9: - k = np.array([[10, 13], [16, 30], [33, 23], [30, 61], [62, 45], [59, 119], [116, 90], [156, 198], [373, 326]]) - else: - # Kmeans calculation - from scipy.cluster.vq import kmeans - print('Running kmeans for %g anchors on %g points...' % (n, len(wh))) - s = wh.std(0) # sigmas for whitening - k, dist = kmeans(wh / s, n, iter=30) # points, mean distance - k *= s + # Kmeans calculation + from scipy.cluster.vq import kmeans + print('Running kmeans for %g anchors on %g points...' % (n, len(wh))) + s = wh.std(0) # sigmas for whitening + k, dist = kmeans(wh / s, n, iter=30) # points, mean distance + k *= s wh = torch.Tensor(wh) k = print_results(k) @@ -741,7 +702,7 @@ def fitness(k): # mutation fitness for _ in tqdm(range(gen), desc='Evolving anchors'): v = np.ones(sh) while (v == 1).all(): # mutate until a change occurs (prevent duplicates) - v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) # 98.6, 61.6 + v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) kg = (k.copy() * v).clip(min=2.0) fg = fitness(kg) if fg > f: @@ -815,17 +776,13 @@ def fitness(x): def output_to_target(output, width, height): """ Convert a YOLO model output to target format - [batch_id, class_id, x, y, w, h, conf] - """ - if isinstance(output, torch.Tensor): output = output.cpu().numpy() targets = [] for i, o in enumerate(output): - if o is not None: for pred in o: box = pred[:4] @@ -951,6 +908,7 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max cv2.rectangle(mosaic, (block_x, block_y), (block_x + w, block_y + h), (255, 255, 255), thickness=3) if fname is not None: + mosaic = cv2.resize(mosaic, (int(ns * w * 0.5), int(ns * h * 0.5)), interpolation=cv2.INTER_AREA) cv2.imwrite(fname, cv2.cvtColor(mosaic, cv2.COLOR_BGR2RGB)) return mosaic @@ -993,7 +951,7 @@ def plot_evolution_results(hyp): # from utils.utils import *; plot_evolution_re # Plot hyperparameter evolution results in evolve.txt x = np.loadtxt('evolve.txt', ndmin=2) f = fitness(x) - weights = (f - f.min()) ** 2 # for weighted results + # weights = (f - f.min()) ** 2 # for weighted results fig = plt.figure(figsize=(12, 10)) matplotlib.rc('font', **{'size': 8}) for i, (k, v) in enumerate(hyp.items()): @@ -1055,8 +1013,8 @@ def plot_results(start=0, stop=0, bucket='', id=()): # from utils.utils import # y /= y[0] # normalize ax[i].plot(x, y, marker='.', label=Path(f).stem, linewidth=2, markersize=8) ax[i].set_title(s[i]) - if i in [5, 6, 7]: # share train and val loss y axes - ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) + # if i in [5, 6, 7]: # share train and val loss y axes + # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) except: print('Warning: Plotting error for %s, skipping file' % f) From c8f4ee6c46ef0eb1d04c1720ce70c21087b2de34 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 17 May 2020 15:10:31 -0700 Subject: [PATCH 0753/1185] yolov5 regress updates to yolov3 - build_targets() --- utils/utils.py | 70 ++++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index e00f778bb0..ee64026fe1 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -408,49 +408,57 @@ def compute_loss(p, targets, model): # predictions, targets, model def build_targets(p, targets, model): # Build targets for compute_loss(), input targets(image,class,x,y,w,h) + nt = targets.shape[0] tcls, tbox, indices, anch = [], [], [], [] - reject, use_all_anchors = True, True gain = torch.ones(6, device=targets.device) # normalized to gridspace gain + off = torch.tensor([[1, 0], [0, 1], [-1, 0], [0, -1]], device=targets.device).float() # overlap offsets - + style = None multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) for i, j in enumerate(model.yolo_layers): # get number of grid points and anchor vec for this yolo layer anchors = model.module.module_list[j].anchor_vec if multi_gpu else model.module_list[j].anchor_vec - - # iou of targets-anchors gain[2:] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain - t, a = targets * gain, [] - gwh = t[:, 4:6] + na = anchors.shape[0] # number of anchors + at = torch.arange(na).view(na, 1).repeat(1, nt) # anchor tensor, same as .repeat_interleave(nt) + + # Match targets to anchors + a, t, offsets = [], targets * gain, 0 if nt: - iou = wh_iou(anchors, gwh) # iou(3,n) = wh_iou(anchors(3,2), gwh(n,2)) - - if use_all_anchors: - na = anchors.shape[0] # number of anchors - a = torch.arange(na).view(-1, 1).repeat(1, nt).view(-1) - t = t.repeat(na, 1) - else: # use best anchor only - iou, a = iou.max(0) # best iou and anchor - - # reject anchors below iou_thres (OPTIONAL, increases P, lowers R) - if reject: - j = iou.view(-1) > model.hyp['iou_t'] # iou threshold hyperparameter - t, a = t[j], a[j] - - # Indices - b, c = t[:, :2].long().t() # image, class + # r = t[None, :, 4:6] / anchors[:, None] # wh ratio + # j = torch.max(r, 1. / r).max(2)[0] < model.hyp['anchor_t'] # compare + j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n) = wh_iou(anchors(3,2), gwh(n,2)) + a, t = at[j], t.repeat(na, 1, 1)[j] # filter + + # overlaps + gxy = t[:, 2:4] # grid xy + z = torch.zeros_like(gxy) + if style == 'rect2': + g = 0.2 # offset + j, k = ((gxy % 1. < g) & (gxy > 1.)).T + a, t = torch.cat((a, a[j], a[k]), 0), torch.cat((t, t[j], t[k]), 0) + offsets = torch.cat((z, z[j] + off[0], z[k] + off[1]), 0) * g + + elif style == 'rect4': + g = 0.5 # offset + j, k = ((gxy % 1. < g) & (gxy > 1.)).T + l, m = ((gxy % 1. > (1 - g)) & (gxy < (gain[[2, 3]] - 1.))).T + a, t = torch.cat((a, a[j], a[k], a[l], a[m]), 0), torch.cat((t, t[j], t[k], t[l], t[m]), 0) + offsets = torch.cat((z, z[j] + off[0], z[k] + off[1], z[l] + off[2], z[m] + off[3]), 0) * g + + # Define + b, c = t[:, :2].long().T # image, class gxy = t[:, 2:4] # grid xy gwh = t[:, 4:6] # grid wh - gi, gj = gxy.long().t() # grid xy indices - indices.append((b, a, gj, gi)) - - # Box - tbox.append(torch.cat((gxy % 1., gwh), 1)) # xywh (grids) - anch.append(anchors[a]) # anchor vec - - # Class - tcls.append(c) + gij = (gxy - offsets).long() + gi, gj = gij.T # grid xy indices + + # Append + indices.append((b, a, gj, gi)) # image, anchor, grid indices + tbox.append(torch.cat((gxy - gij, gwh), 1)) # box + anch.append(anchors[a]) # anchors + tcls.append(c) # class if c.shape[0]: # if any targets assert c.max() < model.nc, 'Model accepts %g classes labeled from 0-%g, however you labelled a class %g. ' \ 'See https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' % ( From 316d99c377170a996d6a45378f086db86610ca62 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 17 May 2020 15:19:33 -0700 Subject: [PATCH 0754/1185] yolov5 regress updates to yolov3 --- detect.py | 14 +++++++------- test.py | 40 ++++++++-------------------------------- train.py | 4 ++-- utils/utils.py | 6 ++---- 4 files changed, 19 insertions(+), 45 deletions(-) diff --git a/detect.py b/detect.py index d6504a9b85..3c9dd98243 100644 --- a/detect.py +++ b/detect.py @@ -6,7 +6,7 @@ def detect(save_img=False): - img_size = (320, 192) if ONNX_EXPORT else opt.img_size # (320, 192) or (416, 256) or (608, 352) for (height, width) + imgsz = (320, 192) if ONNX_EXPORT else opt.img_size # (320, 192) or (416, 256) or (608, 352) for (height, width) out, source, weights, half, view_img, save_txt = opt.output, opt.source, opt.weights, opt.half, opt.view_img, opt.save_txt webcam = source == '0' or source.startswith('rtsp') or source.startswith('http') or source.endswith('.txt') @@ -17,7 +17,7 @@ def detect(save_img=False): os.makedirs(out) # make new output folder # Initialize model - model = Darknet(opt.cfg, img_size) + model = Darknet(opt.cfg, imgsz) # Load weights attempt_download(weights) @@ -42,7 +42,7 @@ def detect(save_img=False): # Export mode if ONNX_EXPORT: model.fuse() - img = torch.zeros((1, 3) + img_size) # (1, 3, 320, 192) + img = torch.zeros((1, 3) + imgsz) # (1, 3, 320, 192) f = opt.weights.replace(opt.weights.split('.')[-1], 'onnx') # *.onnx filename torch.onnx.export(model, img, f, verbose=False, opset_version=11, input_names=['images'], output_names=['classes', 'boxes']) @@ -64,10 +64,10 @@ def detect(save_img=False): if webcam: view_img = True torch.backends.cudnn.benchmark = True # set True to speed up constant image size inference - dataset = LoadStreams(source, img_size=img_size) + dataset = LoadStreams(source, img_size=imgsz) else: save_img = True - dataset = LoadImages(source, img_size=img_size) + dataset = LoadImages(source, img_size=imgsz) # Get names and colors names = load_classes(opt.names) @@ -75,7 +75,7 @@ def detect(save_img=False): # Run inference t0 = time.time() - img = torch.zeros((1, 3, img_size, img_size), device=device) # init img + img = torch.zeros((1, 3, imgsz, imgsz), device=device) # init img _ = model(img.half() if half else img.float()) if device.type != 'cpu' else None # run once for path, img, im0s, vid_cap in dataset: img = torch.from_numpy(img).to(device) @@ -112,7 +112,7 @@ def detect(save_img=False): s += '%gx%g ' % img.shape[2:] # print string gn = torch.tensor(im0s.shape)[[1, 0, 1, 0]] #  normalization gain whwh if det is not None and len(det): - # Rescale boxes from img_size to im0 size + # Rescale boxes from imgsz to im0 size det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() # Print results diff --git a/test.py b/test.py index d997ea4a15..ab1229737b 100644 --- a/test.py +++ b/test.py @@ -12,7 +12,7 @@ def test(cfg, data, weights=None, batch_size=16, - img_size=416, + imgsz=416, conf_thres=0.001, iou_thres=0.6, # for nms save_json=False, @@ -30,7 +30,7 @@ def test(cfg, os.remove(f) # Initialize model - model = Darknet(cfg, img_size) + model = Darknet(cfg, imgsz) # Load weights attempt_download(weights) @@ -60,7 +60,7 @@ def test(cfg, # Dataloader if dataloader is None: - dataset = LoadImagesAndLabels(path, img_size, batch_size, rect=True, single_cls=opt.single_cls) + dataset = LoadImagesAndLabels(path, imgsz, batch_size, rect=True, single_cls=opt.single_cls) batch_size = min(batch_size, len(dataset)) dataloader = DataLoader(dataset, batch_size=batch_size, @@ -70,7 +70,7 @@ def test(cfg, seen = 0 model.eval() - _ = model(torch.zeros((1, 3, img_size, img_size), device=device)) if device.type != 'cpu' else None # run once + _ = model(torch.zeros((1, 3, imgsz, imgsz), device=device)) if device.type != 'cpu' else None # run once coco91class = coco80_to_coco91_class() s = ('%20s' + '%10s' * 6) % ('Class', 'Images', 'Targets', 'P', 'R', 'mAP@0.5', 'F1') p, r, f1, mp, mr, map, mf1, t0, t1 = 0., 0., 0., 0., 0., 0., 0., 0., 0. @@ -191,7 +191,7 @@ def test(cfg, # Print speeds if verbose or save_json: - t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + (img_size, img_size, batch_size) # tuple + t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + (imgsz, imgsz, batch_size) # tuple print('Speed: %.1f/%.1f/%.1f ms inference/NMS/total per %gx%g image at batch-size %g' % t) # Save JSON @@ -259,35 +259,11 @@ def test(cfg, opt.single_cls, opt.augment) - elif opt.task == 'benchmark': # mAPs at 320-608 at conf 0.5 and 0.7 + elif opt.task == 'benchmark': # mAPs at 256-640 at conf 0.5 and 0.7 y = [] - for i in [320, 416, 512, 608]: # img-size - for j in [0.5, 0.7]: # iou-thres + for i in list(range(256, 640, 128)): # img-size + for j in [0.6, 0.7]: # iou-thres t = time.time() r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, i, opt.conf_thres, j, opt.save_json)[0] y.append(r + (time.time() - t,)) np.savetxt('benchmark.txt', y, fmt='%10.4g') # y = np.loadtxt('study.txt') - - elif opt.task == 'study': # Parameter study - y = [] - x = np.arange(0.4, 0.9, 0.05) # iou-thres - for i in x: - t = time.time() - r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, opt.img_size, opt.conf_thres, i, opt.save_json)[0] - y.append(r + (time.time() - t,)) - np.savetxt('study.txt', y, fmt='%10.4g') # y = np.loadtxt('study.txt') - - # Plot - fig, ax = plt.subplots(3, 1, figsize=(6, 6)) - y = np.stack(y, 0) - ax[0].plot(x, y[:, 2], marker='.', label='mAP@0.5') - ax[0].set_ylabel('mAP') - ax[1].plot(x, y[:, 3], marker='.', label='mAP@0.5:0.95') - ax[1].set_ylabel('mAP') - ax[2].plot(x, y[:, -1], marker='.', label='time') - ax[2].set_ylabel('time (s)') - for i in range(3): - ax[i].legend() - ax[i].set_xlabel('iou_thr') - fig.tight_layout() - plt.savefig('study.jpg', dpi=200) diff --git a/train.py b/train.py index d573890c62..f7458e5b9e 100644 --- a/train.py +++ b/train.py @@ -32,7 +32,7 @@ 'lr0': 0.01, # initial learning rate (SGD=5E-3, Adam=5E-4) 'lrf': 0.0005, # final learning rate (with cos scheduler) 'momentum': 0.937, # SGD momentum - 'weight_decay': 0.000484, # optimizer weight decay + 'weight_decay': 0.0005, # optimizer weight decay 'fl_gamma': 0.0, # focal loss gamma (efficientDet default is gamma=1.5) 'hsv_h': 0.0138, # image HSV-Hue augmentation (fraction) 'hsv_s': 0.678, # image HSV-Saturation augmentation (fraction) @@ -311,7 +311,7 @@ def train(hyp): results, maps = test.test(cfg, data, batch_size=batch_size, - img_size=imgsz_test, + imgsz=imgsz_test, model=ema.ema, save_json=final_epoch and is_coco, single_cls=opt.single_cls, diff --git a/utils/utils.py b/utils/utils.py index ee64026fe1..2240403d88 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -365,9 +365,8 @@ def compute_loss(p, targets, model): # predictions, targets, model nb = b.shape[0] # number of targets if nb: - nt += nb + nt += nb # cumulative targets ps = pi[b, a, gj, gi] # prediction subset corresponding to targets - # ps[:, 2:4] = torch.sigmoid(ps[:, 2:4]) # wh power loss (uncomment) # GIoU pxy = torch.sigmoid(ps[:, 0:2]) @@ -408,7 +407,6 @@ def compute_loss(p, targets, model): # predictions, targets, model def build_targets(p, targets, model): # Build targets for compute_loss(), input targets(image,class,x,y,w,h) - nt = targets.shape[0] tcls, tbox, indices, anch = [], [], [], [] gain = torch.ones(6, device=targets.device) # normalized to gridspace gain @@ -647,7 +645,7 @@ def coco_single_class_labels(path='../coco/labels/train2014/', label_class=43): shutil.copyfile(src=img_file, dst='new/images/' + Path(file).name.replace('txt', 'jpg')) # copy images -def kmean_anchors(path='./data/coco64.txt', n=9, img_size=(320, 1024), thr=0.20, gen=1000): +def kmean_anchors(path='./data/coco64.txt', n=9, img_size=(640, 640), thr=0.20, gen=1000): # Creates kmeans anchors for use in *.cfg files: from utils.utils import *; _ = kmean_anchors() # n: number of anchors # img_size: (min, max) image size used for multi-scale training (can be same values) From 5b572681fff6cb594705248f1904531814a3be9c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 17 May 2020 19:28:06 -0700 Subject: [PATCH 0755/1185] pseudo labeling bug fix --- detect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detect.py b/detect.py index 3c9dd98243..7fc75c08ff 100644 --- a/detect.py +++ b/detect.py @@ -110,7 +110,7 @@ def detect(save_img=False): save_path = str(Path(out) / Path(p).name) s += '%gx%g ' % img.shape[2:] # print string - gn = torch.tensor(im0s.shape)[[1, 0, 1, 0]] #  normalization gain whwh + gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] #  normalization gain whwh if det is not None and len(det): # Rescale boxes from imgsz to im0 size det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() From 0c7d7427e47a61a82edb60a5c16e6d139d4ed88b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 17 May 2020 20:59:19 -0700 Subject: [PATCH 0756/1185] [conf > conf_thres] update --- utils/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 2240403d88..68aab83e92 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -482,7 +482,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T for xi, x in enumerate(prediction): # image index, image inference # Apply constraints x = x[x[:, 4] > conf_thres] # confidence - # x = x[((x[:, 2:4] > min_wh) & (x[:, 2:4] < max_wh)).all(1)] # width-height + x = x[((x[:, 2:4] > min_wh) & (x[:, 2:4] < max_wh)).all(1)] # width-height # If none remain process next image if not x.shape[0]: @@ -500,7 +500,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T x = torch.cat((box[i], x[i, j + 5].unsqueeze(1), j.float().unsqueeze(1)), 1) else: # best class only conf, j = x[:, 5:].max(1) - x = torch.cat((box, conf.unsqueeze(1), j.float().unsqueeze(1)), 1) + x = torch.cat((box, conf.unsqueeze(1), j.float().unsqueeze(1)), 1)[conf > conf_thres] # Filter by class if classes: From da40084b370e61ee6a9de219c86ee10b912ac8b6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 17 May 2020 21:03:36 -0700 Subject: [PATCH 0757/1185] burnin update --- train.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/train.py b/train.py index f7458e5b9e..3d4f355eba 100644 --- a/train.py +++ b/train.py @@ -240,17 +240,16 @@ def train(hyp): targets = targets.to(device) # Burn-in - if ni <= n_burn * 2: - model.gr = np.interp(ni, [0, n_burn * 2], [0.0, 1.0]) # giou loss ratio (obj_loss = 1.0 or giou) - if ni == n_burn: # burnin complete - print_model_biases(model) - + if ni <= n_burn: + xi = [0, n_burn] # x interp + model.gr = np.interp(ni, xi, [0.0, 1.0]) # giou loss ratio (obj_loss = 1.0 or giou) + accumulate = max(1, np.interp(ni, xi, [1, 64 / batch_size]).round()) for j, x in enumerate(optimizer.param_groups): # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 - x['lr'] = np.interp(ni, [0, n_burn], [0.1 if j == 2 else 0.0, x['initial_lr'] * lf(epoch)]) + x['lr'] = np.interp(ni, xi, [0.1 if j == 2 else 0.0, x['initial_lr'] * lf(epoch)]) + x['weight_decay'] = np.interp(ni, xi, [0.0, hyp['weight_decay'] if j == 1 else 0.0]) if 'momentum' in x: - x['momentum'] = np.interp(ni, [0, n_burn], [0.9, hyp['momentum']]) - + x['momentum'] = np.interp(ni, xi, [0.9, hyp['momentum']]) # Multi-Scale if opt.multi_scale: From bc9da228e0be00b15dac76a36e15c228be842604 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 17 May 2020 22:11:02 -0700 Subject: [PATCH 0758/1185] add stride order reversal for c53*.cfg --- utils/utils.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 68aab83e92..74abd99995 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -4,6 +4,7 @@ import random import shutil import subprocess +import time from pathlib import Path from sys import platform @@ -472,12 +473,14 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T nx6 (x1, y1, x2, y2, conf, cls) """ - # Box constraints + # Settings + merge = True # merge for best mAP min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height + time_limit = 10.0 # seconds to quit after + t = time.time() nc = prediction[0].shape[1] - 5 # number of classes multi_label &= nc > 1 # multiple labels per box - merge = True # merge for best mAP output = [None] * prediction.shape[0] for xi, x in enumerate(prediction): # image index, image inference # Apply constraints @@ -533,6 +536,9 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=T pass output[xi] = x[i] + if (time.time() - t) > time_limit: + break # time limit exceeded + return output From eacded6a2c595c924ffa602ca13ada663b0c1a11 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 17 May 2020 22:45:48 -0700 Subject: [PATCH 0759/1185] add stride order reversal for c53*.cfg --- utils/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/utils.py b/utils/utils.py index 74abd99995..93a9ada8d1 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -848,6 +848,8 @@ def plot_wh_methods(): # from utils.utils import *; plot_wh_methods() def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max_size=640, max_subplots=16): tl = 3 # line thickness tf = max(tl - 1, 1) # font thickness + if os.path.isfile(fname): # do not overwrite + return None if isinstance(images, torch.Tensor): images = images.cpu().numpy() From cd5f6227d92fc92ecf6ca941b440285b3c12afd5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 18 May 2020 12:03:14 -0700 Subject: [PATCH 0760/1185] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c1e62d0f4d..ead80fc2ec 100755 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ python3 detect.py --source ... - Directory: `--source dir/` - Webcam: `--source 0` - RTSP stream: `--source rtsp://170.93.143.139/rtplive/470011e600ef003a004ee33696235daa` -- HTTP stream: `--source http://wmccpinetop.axiscam.net/mjpg/video.mjpg` +- HTTP stream: `--source http://112.50.243.8/PLTV/88888888/224/3221225900/1.m3u8` **YOLOv3:** `python3 detect.py --cfg cfg/yolov3.cfg --weights yolov3.pt` From 3ddaf3b63c99ac69a0dec7f658b2f10c2419ac5e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 20 May 2020 21:13:41 -0700 Subject: [PATCH 0761/1185] label *.npy saving for faster caching --- utils/datasets.py | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 2b5a0bf3ec..e2b03c9ae2 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -317,18 +317,28 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r # Cache labels self.imgs = [None] * n - self.labels = [np.zeros((0, 5), dtype=np.float32)] * n - extract_bounding_boxes = False - create_datasubset = False - pbar = tqdm(self.label_files, desc='Caching labels') + create_datasubset, extract_bounding_boxes = False, False nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate + np_labels_path = str(Path(self.label_files[0]).parent) + '.npy' # saved labels in *.npy file + if os.path.isfile(np_labels_path): + print('Loading labels from %s' % np_labels_path) + self.labels = list(np.load(np_labels_path, allow_pickle=True)) + labels_loaded = True + else: + self.labels = [np.zeros((0, 5), dtype=np.float32)] * n + labels_loaded = False + + pbar = tqdm(self.label_files, desc='Caching labels') for i, file in enumerate(pbar): - try: - with open(file, 'r') as f: - l = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) - except: - nm += 1 # print('missing labels for image %s' % self.img_files[i]) # file missing - continue + if labels_loaded: + l = self.labels[i] + else: + try: + with open(file, 'r') as f: + l = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) + except: + nm += 1 # print('missing labels for image %s' % self.img_files[i]) # file missing + continue if l.shape[0]: assert l.shape[1] == 5, '> 5 label columns: %s' % file @@ -378,6 +388,9 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r pbar.desc = 'Caching labels (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( nf, nm, ne, nd, n) assert nf > 0, 'No labels found in %s. See %s' % (os.path.dirname(file) + os.sep, help_url) + if not labels_loaded: + print('Saving labels to %s for faster future loading' % np_labels_path) + np.save(np_labels_path, self.labels) # save for next time # Cache images into memory for faster training (WARNING: large datasets may exceed system RAM) if cache_images: # if training From 2cc2b2cf0d5bc3c0b9b4ece89cea5fd1f54d3e60 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 20 May 2020 21:39:18 -0700 Subject: [PATCH 0762/1185] label *.npy saving for faster caching --- utils/datasets.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index e2b03c9ae2..6da5eff816 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -317,16 +317,16 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r # Cache labels self.imgs = [None] * n - create_datasubset, extract_bounding_boxes = False, False + self.labels = [np.zeros((0, 5), dtype=np.float32)] * n + create_datasubset, extract_bounding_boxes, labels_loaded = False, False, False nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate np_labels_path = str(Path(self.label_files[0]).parent) + '.npy' # saved labels in *.npy file if os.path.isfile(np_labels_path): print('Loading labels from %s' % np_labels_path) - self.labels = list(np.load(np_labels_path, allow_pickle=True)) - labels_loaded = True - else: - self.labels = [np.zeros((0, 5), dtype=np.float32)] * n - labels_loaded = False + x = list(np.load(np_labels_path, allow_pickle=True)) + if len(x) == n: + self.labels = x + labels_loaded = True pbar = tqdm(self.label_files, desc='Caching labels') for i, file in enumerate(pbar): From 002884ae5ea5b5e5597c277143094699a948c214 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 21 May 2020 14:40:45 -0700 Subject: [PATCH 0763/1185] multi_label burnin addition --- test.py | 5 +++-- train.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/test.py b/test.py index ab1229737b..5d313efab2 100644 --- a/test.py +++ b/test.py @@ -19,7 +19,8 @@ def test(cfg, single_cls=False, augment=False, model=None, - dataloader=None): + dataloader=None, + multi_label=True): # Initialize/load model and set device if model is None: device = torch_utils.select_device(opt.device, batch_size=batch_size) @@ -95,7 +96,7 @@ def test(cfg, # Run NMS t = torch_utils.time_synchronized() - output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres) # nms + output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres, multi_label=multi_label) t1 += torch_utils.time_synchronized() - t # Statistics per image diff --git a/train.py b/train.py index 3d4f355eba..8ea7ed28db 100644 --- a/train.py +++ b/train.py @@ -314,7 +314,8 @@ def train(hyp): model=ema.ema, save_json=final_epoch and is_coco, single_cls=opt.single_cls, - dataloader=testloader) + dataloader=testloader, + multi_label=ni > n_burn) # Write with open(results_file, 'a') as f: From 4879fd22e94c12cea4e74d3f70eb851ef38bbf68 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 22 May 2020 16:03:08 -0700 Subject: [PATCH 0764/1185] caching introspection update --- utils/datasets.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 6da5eff816..d5f3773ac8 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -322,13 +322,15 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate np_labels_path = str(Path(self.label_files[0]).parent) + '.npy' # saved labels in *.npy file if os.path.isfile(np_labels_path): - print('Loading labels from %s' % np_labels_path) + s = np_labels_path x = list(np.load(np_labels_path, allow_pickle=True)) if len(x) == n: self.labels = x labels_loaded = True + else: + s = path.replace('images', 'labels') - pbar = tqdm(self.label_files, desc='Caching labels') + pbar = tqdm(self.label_files) for i, file in enumerate(pbar): if labels_loaded: l = self.labels[i] From 16ea613628056855b3144fa0092c59e8f8856c99 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 22 May 2020 16:06:21 -0700 Subject: [PATCH 0765/1185] caching introspection update --- utils/datasets.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index d5f3773ac8..82a9a7eb85 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -258,11 +258,16 @@ def __len__(self): class LoadImagesAndLabels(Dataset): # for training/testing def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, cache_images=False, single_cls=False): - path = str(Path(path)) # os-agnostic - assert os.path.isfile(path), 'File not found %s. See %s' % (path, help_url) - with open(path, 'r') as f: - self.img_files = [x.replace('/', os.sep) for x in f.read().splitlines() # os-agnostic - if os.path.splitext(x)[-1].lower() in img_formats] + try: + path = str(Path(path)) # os-agnostic + if os.path.isfile(path): # file + with open(path, 'r') as f: + f = f.read().splitlines() + elif os.path.isdir(path): # folder + f = glob.iglob(path + os.sep + '*.*') + self.img_files = [x.replace('/', os.sep) for x in f if os.path.splitext(x)[-1].lower() in img_formats] + except: + raise Exception('Error loading data from %s. See %s' % (path, help_url)) n = len(self.img_files) assert n > 0, 'No images found in %s. See %s' % (path, help_url) @@ -387,8 +392,8 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r ne += 1 # print('empty labels for image %s' % self.img_files[i]) # file empty # os.system("rm '%s' '%s'" % (self.img_files[i], self.label_files[i])) # remove - pbar.desc = 'Caching labels (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( - nf, nm, ne, nd, n) + pbar.desc = 'Caching labels %s (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( + s, nf, nm, ne, nd, n) assert nf > 0, 'No labels found in %s. See %s' % (os.path.dirname(file) + os.sep, help_url) if not labels_loaded: print('Saving labels to %s for faster future loading' % np_labels_path) From 23f85a68b870c8f35e318554f3598ffd2f1926fa Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 24 May 2020 10:51:35 -0700 Subject: [PATCH 0766/1185] tight_layout=True --- utils/utils.py | 68 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index 93a9ada8d1..32261520a8 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -5,6 +5,7 @@ import shutil import subprocess import time +from copy import copy from pathlib import Path from sys import platform @@ -370,8 +371,8 @@ def compute_loss(p, targets, model): # predictions, targets, model ps = pi[b, a, gj, gi] # prediction subset corresponding to targets # GIoU - pxy = torch.sigmoid(ps[:, 0:2]) - pwh = torch.exp(ps[:, 2:4]).clamp(max=1E3) * anchors[i] + pxy = ps[:, :2].sigmoid() + pwh = ps[:, 2:4].exp().clamp(max=1E3) * anchors[i] pbox = torch.cat((pxy, pwh), 1) # predicted box giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou(prediction, target) lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss @@ -416,7 +417,6 @@ def build_targets(p, targets, model): style = None multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) for i, j in enumerate(model.yolo_layers): - # get number of grid points and anchor vec for this yolo layer anchors = model.module.module_list[j].anchor_vec if multi_gpu else model.module_list[j].anchor_vec gain[2:] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain na = anchors.shape[0] # number of anchors @@ -573,7 +573,7 @@ def strip_optimizer(f='weights/best.pt'): # from utils.utils import *; strip_op torch.save(x, f) -def create_backbone(f='weights/last.pt'): # from utils.utils import *; create_backbone() +def create_backbone(f='weights/best.pt'): # from utils.utils import *; create_backbone() # create a backbone from a *.pt file x = torch.load(f, map_location=torch.device('cpu')) x['optimizer'] = None @@ -816,12 +816,12 @@ def plot_one_box(x, img, color=None, label=None, line_thickness=None): tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line/font thickness color = color or [random.randint(0, 255) for _ in range(3)] c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) - cv2.rectangle(img, c1, c2, color, thickness=tl) + cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA) if label: tf = max(tl - 1, 1) # font thickness t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 - cv2.rectangle(img, c1, c2, color, -1) # filled + cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) # filled cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA) @@ -928,22 +928,34 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max return mosaic +def plot_lr_scheduler(optimizer, scheduler, epochs=300): + # Plot LR simulating training for full epochs + optimizer, scheduler = copy(optimizer), copy(scheduler) # do not modify originals + y = [] + for _ in range(epochs): + scheduler.step() + y.append(optimizer.param_groups[0]['lr']) + plt.plot(y, '.-', label='LR') + plt.xlabel('epoch') + plt.ylabel('LR') + plt.tight_layout() + plt.savefig('LR.png', dpi=200) + + def plot_test_txt(): # from utils.utils import *; plot_test() # Plot test.txt histograms x = np.loadtxt('test.txt', dtype=np.float32) box = xyxy2xywh(x[:, :4]) cx, cy = box[:, 0], box[:, 1] - fig, ax = plt.subplots(1, 1, figsize=(6, 6)) + fig, ax = plt.subplots(1, 1, figsize=(6, 6), tight_layout=True) ax.hist2d(cx, cy, bins=600, cmax=10, cmin=0) ax.set_aspect('equal') - fig.tight_layout() plt.savefig('hist2d.png', dpi=300) - fig, ax = plt.subplots(1, 2, figsize=(12, 6)) + fig, ax = plt.subplots(1, 2, figsize=(12, 6), tight_layout=True) ax[0].hist(cx, bins=600) ax[1].hist(cy, bins=600) - fig.tight_layout() plt.savefig('hist1d.png', dpi=200) @@ -951,22 +963,45 @@ def plot_targets_txt(): # from utils.utils import *; plot_targets_txt() # Plot targets.txt histograms x = np.loadtxt('targets.txt', dtype=np.float32).T s = ['x targets', 'y targets', 'width targets', 'height targets'] - fig, ax = plt.subplots(2, 2, figsize=(8, 8)) + fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) ax = ax.ravel() for i in range(4): ax[i].hist(x[i], bins=100, label='%.3g +/- %.3g' % (x[i].mean(), x[i].std())) ax[i].legend() ax[i].set_title(s[i]) - fig.tight_layout() plt.savefig('targets.jpg', dpi=200) +def plot_labels(labels): + # plot dataset labels + c, b = labels[:, 0], labels[:, 1:].transpose() # classees, boxes + + def hist2d(x, y, n=100): + xedges, yedges = np.linspace(x.min(), x.max(), n), np.linspace(y.min(), y.max(), n) + hist, xedges, yedges = np.histogram2d(x, y, (xedges, yedges)) + xidx = np.clip(np.digitize(x, xedges) - 1, 0, hist.shape[0] - 1) + yidx = np.clip(np.digitize(y, yedges) - 1, 0, hist.shape[1] - 1) + return hist[xidx, yidx] + + fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) + ax = ax.ravel() + ax[0].hist(c, bins=int(c.max() + 1)) + ax[0].set_xlabel('classes') + ax[1].scatter(b[0], b[1], c=hist2d(b[0], b[1], 90), cmap='jet') + ax[1].set_xlabel('x') + ax[1].set_ylabel('y') + ax[2].scatter(b[2], b[3], c=hist2d(b[2], b[3], 90), cmap='jet') + ax[2].set_xlabel('width') + ax[2].set_ylabel('height') + plt.savefig('labels.png', dpi=200) + + def plot_evolution_results(hyp): # from utils.utils import *; plot_evolution_results(hyp) # Plot hyperparameter evolution results in evolve.txt x = np.loadtxt('evolve.txt', ndmin=2) f = fitness(x) # weights = (f - f.min()) ** 2 # for weighted results - fig = plt.figure(figsize=(12, 10)) + fig = plt.figure(figsize=(12, 10), tight_layout=True) matplotlib.rc('font', **{'size': 8}) for i, (k, v) in enumerate(hyp.items()): y = x[:, i + 7] @@ -977,7 +1012,6 @@ def plot_evolution_results(hyp): # from utils.utils import *; plot_evolution_re plt.plot(y, f, '.') plt.title('%s = %.3g' % (k, mu), fontdict={'size': 9}) # limit to 40 characters print('%15s: %.3g' % (k, mu)) - fig.tight_layout() plt.savefig('evolve.png', dpi=200) @@ -989,7 +1023,7 @@ def plot_results_overlay(start=0, stop=0): # from utils.utils import *; plot_re results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T n = results.shape[1] # number of rows x = range(start, min(stop, n) if stop else n) - fig, ax = plt.subplots(1, 5, figsize=(14, 3.5)) + fig, ax = plt.subplots(1, 5, figsize=(14, 3.5), tight_layout=True) ax = ax.ravel() for i in range(5): for j in [i, i + 5]: @@ -1000,13 +1034,12 @@ def plot_results_overlay(start=0, stop=0): # from utils.utils import *; plot_re ax[i].set_title(t[i]) ax[i].legend() ax[i].set_ylabel(f) if i == 0 else None # add filename - fig.tight_layout() fig.savefig(f.replace('.txt', '.png'), dpi=200) def plot_results(start=0, stop=0, bucket='', id=()): # from utils.utils import *; plot_results() # Plot training 'results*.txt' as seen in https://github.com/ultralytics/yolov3#training - fig, ax = plt.subplots(2, 5, figsize=(12, 6)) + fig, ax = plt.subplots(2, 5, figsize=(12, 6), tight_layout=True) ax = ax.ravel() s = ['GIoU', 'Objectness', 'Classification', 'Precision', 'Recall', 'val GIoU', 'val Objectness', 'val Classification', 'mAP@0.5', 'F1'] @@ -1032,6 +1065,5 @@ def plot_results(start=0, stop=0, bucket='', id=()): # from utils.utils import except: print('Warning: Plotting error for %s, skipping file' % f) - fig.tight_layout() ax[1].legend() fig.savefig('results.png', dpi=200) From d6d6fb5e5bceb6e4bf7e5b0e05918b9de668219e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 24 May 2020 20:30:30 -0700 Subject: [PATCH 0767/1185] print('Optimizer stripped from %s' % f) --- utils/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/utils.py b/utils/utils.py index 32261520a8..bad2cf022d 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -570,6 +570,7 @@ def strip_optimizer(f='weights/best.pt'): # from utils.utils import *; strip_op # Strip optimizer from *.pt files for lighter files (reduced by 2/3 size) x = torch.load(f, map_location=torch.device('cpu')) x['optimizer'] = None + print('Optimizer stripped from %s' % f) torch.save(x, f) From d136ddeeba9304e011c11df0851820706f3c4555 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 25 May 2020 12:42:58 -0700 Subject: [PATCH 0768/1185] tight_layout=True --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ead80fc2ec..b194e89c1e 100755 --- a/README.md +++ b/README.md @@ -175,4 +175,4 @@ To access an up-to-date working environment (with all dependencies including CUD # Contact -**Issues should be raised directly in the repository.** For additional questions or comments please email Glenn Jocher at glenn.jocher@ultralytics.com or visit us at https://contact.ultralytics.com. +**Issues should be raised directly in the repository.** For business inquiries or professional support requests please visit us at https://contact.ultralytics.com. From 39a2d32c0f06a29ff40a442feb9ef479714be5f4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 27 May 2020 09:32:19 -0700 Subject: [PATCH 0769/1185] Bug fix #1247 --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 0c0d6fa00a..0323b25e48 100755 --- a/models.py +++ b/models.py @@ -438,7 +438,7 @@ def convert(cfg='cfg/yolov3-spp.cfg', weights='weights/yolov3-spp.weights'): target = weights.rsplit('.', 1)[0] + '.pt' torch.save(chkpt, target) - print("Success: converted '%s' to '%'" % (weights, target)) + print("Success: converted '%s' to 's%'" % (weights, target)) else: print('Error: extension not supported.') From e99ff3aad0a4f715235f83a4049e3574fcd16f2c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 28 May 2020 14:01:38 -0700 Subject: [PATCH 0770/1185] local path robustness --- utils/datasets.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 82a9a7eb85..d741758cff 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -260,11 +260,15 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r cache_images=False, single_cls=False): try: path = str(Path(path)) # os-agnostic + parent = str(Path(path).parent) + os.sep if os.path.isfile(path): # file with open(path, 'r') as f: f = f.read().splitlines() + f = [x.replace('./', parent) for x in f if x.startswith('./')] # local to global path elif os.path.isdir(path): # folder f = glob.iglob(path + os.sep + '*.*') + else: + raise Exception('%s does not exist' % path) self.img_files = [x.replace('/', os.sep) for x in f if os.path.splitext(x)[-1].lower() in img_formats] except: raise Exception('Error loading data from %s. See %s' % (path, help_url)) @@ -274,7 +278,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r bi = np.floor(np.arange(n) / batch_size).astype(np.int) # batch index nb = bi[-1] + 1 # number of batches - self.n = n + self.n = n # number of images self.batch = bi # batch index of image self.img_size = img_size self.augment = augment @@ -290,7 +294,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r # Rectangular Training https://github.com/ultralytics/yolov3/issues/232 if self.rect: # Read image shapes (wh) - sp = path.replace('.txt', '.shapes') # shapefile path + sp = path.replace('.txt', '') + '.shapes' # shapefile path try: with open(sp, 'r') as f: # read existing shapefile s = [x.split() for x in f.read().splitlines()] @@ -302,11 +306,11 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r # Sort by aspect ratio s = np.array(s, dtype=np.float64) ar = s[:, 1] / s[:, 0] # aspect ratio - i = ar.argsort() - self.img_files = [self.img_files[i] for i in i] - self.label_files = [self.label_files[i] for i in i] - self.shapes = s[i] # wh - ar = ar[i] + irect = ar.argsort() + self.img_files = [self.img_files[i] for i in irect] + self.label_files = [self.label_files[i] for i in irect] + self.shapes = s[irect] # wh + ar = ar[irect] # Set training image shapes shapes = [[1, 1]] * nb @@ -327,8 +331,8 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate np_labels_path = str(Path(self.label_files[0]).parent) + '.npy' # saved labels in *.npy file if os.path.isfile(np_labels_path): - s = np_labels_path - x = list(np.load(np_labels_path, allow_pickle=True)) + s = np_labels_path # print string + x = np.load(np_labels_path, allow_pickle=True) if len(x) == n: self.labels = x labels_loaded = True @@ -339,6 +343,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r for i, file in enumerate(pbar): if labels_loaded: l = self.labels[i] + # np.savetxt(file, l, '%g') # save *.txt from *.npy file else: try: with open(file, 'r') as f: @@ -394,8 +399,8 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r pbar.desc = 'Caching labels %s (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( s, nf, nm, ne, nd, n) - assert nf > 0, 'No labels found in %s. See %s' % (os.path.dirname(file) + os.sep, help_url) - if not labels_loaded: + assert nf > 0 or n == 20288, 'No labels found in %s. See %s' % (os.path.dirname(file) + os.sep, help_url) + if not labels_loaded and n > 1000: print('Saving labels to %s for faster future loading' % np_labels_path) np.save(np_labels_path, self.labels) # save for next time From cf7a4d31d37788023a9186a1a143a2dab0275ead Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 28 May 2020 20:50:02 -0700 Subject: [PATCH 0771/1185] bug fix in local to global path replacement --- utils/datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/datasets.py b/utils/datasets.py index d741758cff..5811142ae4 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -264,7 +264,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r if os.path.isfile(path): # file with open(path, 'r') as f: f = f.read().splitlines() - f = [x.replace('./', parent) for x in f if x.startswith('./')] # local to global path + f = [x.replace('./', parent) if x.startswith('./') else x for x in f] # local to global path elif os.path.isdir(path): # folder f = glob.iglob(path + os.sep + '*.*') else: From 8c533a92b0a824edc1168796255dab38acc4b546 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 2 Jun 2020 11:22:28 -0700 Subject: [PATCH 0772/1185] remove dependency --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index da91e035d6..f21cf49e9d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM nvcr.io/nvidia/pytorch:20.03-py3 # Install dependencies (pip or conda) -RUN pip install -U gsutil thop +RUN pip install -U gsutil # RUN pip install -U -r requirements.txt # RUN conda update -n base -c defaults conda # RUN conda install -y -c anaconda future numpy opencv matplotlib tqdm pillow From 64b8960074c3038625d1bbb8f82a0ff227bef2b6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 2 Jun 2020 21:45:33 -0700 Subject: [PATCH 0773/1185] remove dependency --- .github/workflows/greetings.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 3634626272..c4fd25c75b 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -10,7 +10,14 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} pr-message: 'Hello @${{ github.actor }}, thank you for submitting a PR! We will respond as soon as possible.' - issue-message: > + issue-message: | Hello @${{ github.actor }}, thank you for your interest in our work! Please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://github.com/ultralytics/yolov3/blob/master/tutorial.ipynb), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. If this is a bug report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you. + + If this is a custom model or data training question, please note that Ultralytics does **not** provide free personal support. As a leader in vision ML and AI, we do offer professional consulting, from simple expert advice up to delivery of fully customized, end-to-end production solutions for our clients, such as: + - **Cloud-based AI** surveillance systems operating on **hundreds of HD video streams in realtime.** + - **Edge AI** integrated into custom iOS and Android apps for realtime **30 FPS video inference.** + - **Custom data training**, hyperparameter evolution, and model exportation to any destination. + + For more information please visit https://www.ultralytics.com. \ No newline at end of file From 82f653b0f579db97f8908800d45e8f5287f79bd3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 2 Jun 2020 23:59:03 -0700 Subject: [PATCH 0774/1185] webcam multiple bounding box bug fix #1188 --- detect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detect.py b/detect.py index 7fc75c08ff..b52f782679 100644 --- a/detect.py +++ b/detect.py @@ -104,7 +104,7 @@ def detect(save_img=False): # Process detections for i, det in enumerate(pred): # detections for image i if webcam: # batch_size >= 1 - p, s, im0 = path[i], '%g: ' % i, im0s[i] + p, s, im0 = path[i], '%g: ' % i, im0s[i].copy() else: p, s, im0 = path, '', im0s From 3cac096d7e973453378aa26e4f97b9c110947ddf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 9 Jun 2020 15:50:10 -0700 Subject: [PATCH 0775/1185] YOLOv5 greeting --- .github/workflows/greetings.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index c4fd25c75b..53b130120e 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -11,12 +11,19 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} pr-message: 'Hello @${{ github.actor }}, thank you for submitting a PR! We will respond as soon as possible.' issue-message: | - Hello @${{ github.actor }}, thank you for your interest in our work! Please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://github.com/ultralytics/yolov3/blob/master/tutorial.ipynb), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. + Hello @${{ github.actor }}, thank you for your interest in our work! **Ultralytics has publically released YOLOv5** at https://github.com/ultralytics/yolov5, featuring faster, lighter and more accurate object detection. YOLOv5 is recommended for all new projects. + + + + + + + To continue with this repo, please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://github.com/ultralytics/yolov3/blob/master/tutorial.ipynb), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. If this is a bug report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you. If this is a custom model or data training question, please note that Ultralytics does **not** provide free personal support. As a leader in vision ML and AI, we do offer professional consulting, from simple expert advice up to delivery of fully customized, end-to-end production solutions for our clients, such as: - - **Cloud-based AI** surveillance systems operating on **hundreds of HD video streams in realtime.** + - **Cloud-based AI** systems operating on **hundreds of HD video streams in realtime.** - **Edge AI** integrated into custom iOS and Android apps for realtime **30 FPS video inference.** - **Custom data training**, hyperparameter evolution, and model exportation to any destination. From 0671f04e1f283aea6f059d066130d4543a320b47 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 9 Jun 2020 16:00:10 -0700 Subject: [PATCH 0776/1185] YOLOv5 greeting --- .github/workflows/greetings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 53b130120e..2a91bb7277 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -11,7 +11,7 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} pr-message: 'Hello @${{ github.actor }}, thank you for submitting a PR! We will respond as soon as possible.' issue-message: | - Hello @${{ github.actor }}, thank you for your interest in our work! **Ultralytics has publically released YOLOv5** at https://github.com/ultralytics/yolov5, featuring faster, lighter and more accurate object detection. YOLOv5 is recommended for all new projects. + Hello @${{ github.actor }}, thank you for your interest in our work! **Ultralytics has publicly released YOLOv5** at https://github.com/ultralytics/yolov5, featuring faster, lighter and more accurate object detection. YOLOv5 is recommended for all new projects. From 936ac746ce1a3b7e9012ddf9429d1aa6b5ad0f96 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 10 Jun 2020 16:45:09 -0700 Subject: [PATCH 0777/1185] update README.md --- README.md | 63 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index b194e89c1e..b84d5441ea 100755 --- a/README.md +++ b/README.md @@ -16,30 +16,30 @@ -# Introduction -This directory contains PyTorch YOLOv3 software developed by Ultralytics LLC, and **is freely available for redistribution under the GPL-3.0 license**. For more information please visit https://www.ultralytics.com. - -# Description +## Introduction The https://github.com/ultralytics/yolov3 repo contains inference and training code for YOLOv3 in PyTorch. The code works on Linux, MacOS and Windows. Training is done on the COCO dataset by default: https://cocodataset.org/#home. **Credit to Joseph Redmon for YOLO:** https://pjreddie.com/darknet/yolo/. -# Requirements -Python 3.7 or later with all `pip install -U -r requirements.txt` packages including `torch >= 1.5`. Docker images come with all dependencies preinstalled. Docker requirements are: -- Nvidia Driver >= 440.44 -- Docker Engine - CE >= 19.03 +## Requirements + +Python 3.7 or later with all `requirements.txt` dependencies installed, including `torch >= 1.5`. To install run: +```bash +$ pip install -U -r requirements.txt +``` + -# Tutorials +## Tutorials +* Open In Colab * [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) < highly recommended!! -* [Train Single Class](https://github.com/ultralytics/yolov3/wiki/Example:-Train-Single-Class) -* [Google Colab Notebook](https://colab.research.google.com/github/ultralytics/yolov3/blob/master/tutorial.ipynb) with quick training, inference and testing examples * [GCP Quickstart](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) * [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) * [A TensorRT Implementation of YOLOv3 and YOLOv4](https://github.com/wang-xinyu/tensorrtx/tree/master/yolov3-spp) -# Training + +## Training **Start Training:** `python3 train.py` to begin training after downloading COCO data with `data/get_coco2017.sh`. Each epoch trains on 117,263 images from the train and validate COCO sets, and tests on 5000 images from the COCO validate set. @@ -49,13 +49,15 @@ Python 3.7 or later with all `pip install -U -r requirements.txt` packages inclu -## Image Augmentation + +### Image Augmentation `datasets.py` applies OpenCV-powered (https://opencv.org/) augmentation to the input image. We use a **mosaic dataloader** to increase image variability during training. -## Speed + +### Speed https://cloud.google.com/deep-learning-vm/ **Machine type:** preemptible [n1-standard-8](https://cloud.google.com/compute/docs/machine-types) (8 vCPUs, 30 GB memory) @@ -73,6 +75,7 @@ T4 |1
2| 32 x 2
64 x 1 | 41
61 | 48 min
32 min | $0.09
$0.11 V100 |1
2| 32 x 2
64 x 1 | 122
**178** | 16 min
**11 min** | **$0.21**
$0.28 2080Ti |1
2| 32 x 2
64 x 1 | 81
140 | 24 min
14 min | -
- + # Inference ```bash @@ -96,10 +99,11 @@ python3 detect.py --source ... -# Pretrained Weights +## Pretrained Checkpoints Download from: [https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0](https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0) + ## Darknet Conversion ```bash @@ -114,7 +118,8 @@ $ python3 -c "from models import *; convert('cfg/yolov3-spp.cfg', 'weights/yolo Success: converted 'weights/yolov3-spp.pt' to 'weights/yolov3-spp.weights' ``` -# mAP + +## mAP |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 --- | --- | --- | --- @@ -153,7 +158,7 @@ Speed: 17.5/2.3/19.9 ms inference/NMS/total per 640x640 image at batch-size 16 -# Reproduce Our Results +## Reproduce Our Results Run commands below. Training takes about one week on a 2080Ti per model. ```bash @@ -162,17 +167,31 @@ $ python train.py --data coco2014.data --weights '' --batch-size 32 --cfg yolov3 ``` -# Reproduce Our Environment + +## Reproduce Our Environment To access an up-to-date working environment (with all dependencies including CUDA/CUDNN, Python and PyTorch preinstalled), consider a: - **GCP** Deep Learning VM with $300 free credit offer: See our [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) -- **Google Colab Notebook** with 12 hours of free GPU time: [Google Colab Notebook](https://colab.sandbox.google.com/github/ultralytics/yolov3/blob/master/tutorial.ipynb) -- **Docker Image** from https://hub.docker.com/r/ultralytics/yolov3. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) +- **Google Colab Notebook** with 12 hours of free GPU time. Open In Colab +- **Docker Image** https://hub.docker.com/r/ultralytics/yolov5. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) + + # Citation [![DOI](https://zenodo.org/badge/146165888.svg)](https://zenodo.org/badge/latestdoi/146165888) -# Contact -**Issues should be raised directly in the repository.** For business inquiries or professional support requests please visit us at https://contact.ultralytics.com. +## About Us + +Ultralytics is a U.S.-based particle physics and AI startup with over 6 years of expertise supporting government, academic and business clients. We offer a wide range of vision AI services, spanning from simple expert advice up to delivery of fully customized, end-to-end production solutions, including: +- **Cloud-based AI** surveillance systems operating on **hundreds of HD video streams in realtime.** +- **Edge AI** integrated into custom iOS and Android apps for realtime **30 FPS video inference.** +- **Custom data training**, hyperparameter evolution, and model exportation to any destination. + +For business inquiries and professional support requests please visit us at https://www.ultralytics.com. + + +## Contact + +**Issues should be raised directly in the repository.** For business inquiries or professional support requests please visit https://www.ultralytics.com or email Glenn Jocher at glenn.jocher@ultralytics.com. From c4b0f986d195412e3a057aff1be3cb0da7e7d317 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 10 Jun 2020 16:46:22 -0700 Subject: [PATCH 0778/1185] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b84d5441ea..eef42f070e 100755 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ V100 |1
2| 32 x 2
64 x 1 | 122
**178** | 16 min
**11 min** | **$0. 2080Ti |1
2| 32 x 2
64 x 1 | 81
140 | 24 min
14 min | -
- -# Inference +## Inference ```bash python3 detect.py --source ... @@ -177,7 +177,7 @@ To access an up-to-date working environment (with all dependencies including CUD - **Docker Image** https://hub.docker.com/r/ultralytics/yolov5. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) -# Citation +## Citation [![DOI](https://zenodo.org/badge/146165888.svg)](https://zenodo.org/badge/latestdoi/146165888) From c78d49f190c7ac2f5723f6a913aee39154106707 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 15 Jun 2020 12:25:48 -0700 Subject: [PATCH 0779/1185] check_file() update from yolov5 --- detect.py | 4 ++-- test.py | 4 ++-- train.py | 4 ++-- utils/utils.py | 10 ++++++++++ 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/detect.py b/detect.py index b52f782679..0c4b17b395 100644 --- a/detect.py +++ b/detect.py @@ -183,8 +183,8 @@ def detect(save_img=False): parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') parser.add_argument('--augment', action='store_true', help='augmented inference') opt = parser.parse_args() - opt.cfg = list(glob.iglob('./**/' + opt.cfg, recursive=True))[0] # find file - opt.names = list(glob.iglob('./**/' + opt.names, recursive=True))[0] # find file + opt.cfg = check_file(opt.cfg) # check file + opt.names = check_file(opt.names) # check file print(opt) with torch.no_grad(): diff --git a/test.py b/test.py index 5d313efab2..ace0995150 100644 --- a/test.py +++ b/test.py @@ -243,8 +243,8 @@ def test(cfg, parser.add_argument('--augment', action='store_true', help='augmented inference') opt = parser.parse_args() opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) - opt.cfg = list(glob.iglob('./**/' + opt.cfg, recursive=True))[0] # find file - opt.data = list(glob.iglob('./**/' + opt.data, recursive=True))[0] # find file + opt.cfg = check_file(opt.cfg) # check file + opt.data = check_file(opt.data) # check file print(opt) # task = 'test', 'study', 'benchmark' diff --git a/train.py b/train.py index 8ea7ed28db..f963fdf1e7 100644 --- a/train.py +++ b/train.py @@ -397,8 +397,8 @@ def train(hyp): opt = parser.parse_args() opt.weights = last if opt.resume else opt.weights check_git_status() - opt.cfg = list(glob.iglob('./**/' + opt.cfg, recursive=True))[0] # find file - # opt.data = list(glob.iglob('./**/' + opt.data, recursive=True))[0] # find file + opt.cfg = check_file(opt.cfg) # check file + opt.data = check_file(opt.data) # check file print(opt) opt.img_size.extend([opt.img_size[-1]] * (3 - len(opt.img_size))) # extend to 3 sizes (min, max, test) device = torch_utils.select_device(opt.device, apex=mixed_precision, batch_size=opt.batch_size) diff --git a/utils/utils.py b/utils/utils.py index bad2cf022d..2643842d87 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -43,6 +43,16 @@ def check_git_status(): print(s[s.find('Your branch is behind'):s.find('\n\n')] + '\n') +def check_file(file): + # Searches for file if not found locally + if os.path.isfile(file): + return file + else: + files = glob.glob('./**/' + file, recursive=True) # find file + assert len(files), 'File Not Found: %s' % file # assert file was found + return files[0] # return first file if multiple found + + def load_classes(path): # Loads *.names file at 'path' with open(path, 'r') as f: From 509644a6227b6ec50acbe34d87bc160ad22738d4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 15 Jun 2020 12:27:03 -0700 Subject: [PATCH 0780/1185] greeting update --- .github/workflows/greetings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 2a91bb7277..2c5c5c700f 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -11,7 +11,7 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} pr-message: 'Hello @${{ github.actor }}, thank you for submitting a PR! We will respond as soon as possible.' issue-message: | - Hello @${{ github.actor }}, thank you for your interest in our work! **Ultralytics has publicly released YOLOv5** at https://github.com/ultralytics/yolov5, featuring faster, lighter and more accurate object detection. YOLOv5 is recommended for all new projects. + Hello @${{ github.actor }}, thank you for your interest in our work! Ultralytics has open-sourced YOLOv5 at https://github.com/ultralytics/yolov5, featuring faster, lighter and more accurate object detection. YOLOv5 is recommended for all new projects. From f51ace44f9c3014ec01e5a126dc3d5ed2e86826e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 15 Jun 2020 12:28:16 -0700 Subject: [PATCH 0781/1185] update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index eef42f070e..cba4a56026 100755 --- a/README.md +++ b/README.md @@ -185,10 +185,9 @@ To access an up-to-date working environment (with all dependencies including CUD ## About Us Ultralytics is a U.S.-based particle physics and AI startup with over 6 years of expertise supporting government, academic and business clients. We offer a wide range of vision AI services, spanning from simple expert advice up to delivery of fully customized, end-to-end production solutions, including: -- **Cloud-based AI** surveillance systems operating on **hundreds of HD video streams in realtime.** +- **Cloud-based AI** systems operating on **hundreds of HD video streams in realtime.** - **Edge AI** integrated into custom iOS and Android apps for realtime **30 FPS video inference.** - **Custom data training**, hyperparameter evolution, and model exportation to any destination. - For business inquiries and professional support requests please visit us at https://www.ultralytics.com. From 89a3ecac4b09853c4101e049551ab32840d425b3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 15 Jun 2020 12:30:12 -0700 Subject: [PATCH 0782/1185] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cba4a56026..39034ea607 100755 --- a/README.md +++ b/README.md @@ -188,6 +188,7 @@ Ultralytics is a U.S.-based particle physics and AI startup with over 6 years of - **Cloud-based AI** systems operating on **hundreds of HD video streams in realtime.** - **Edge AI** integrated into custom iOS and Android apps for realtime **30 FPS video inference.** - **Custom data training**, hyperparameter evolution, and model exportation to any destination. + For business inquiries and professional support requests please visit us at https://www.ultralytics.com. From a475620306a13cd8dc50c19211e929df6a4125f0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 15 Jun 2020 12:32:05 -0700 Subject: [PATCH 0783/1185] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 39034ea607..9e47c56755 100755 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ To access an up-to-date working environment (with all dependencies including CUD - **GCP** Deep Learning VM with $300 free credit offer: See our [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) - **Google Colab Notebook** with 12 hours of free GPU time. Open In Colab -- **Docker Image** https://hub.docker.com/r/ultralytics/yolov5. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) +- **Docker Image** https://hub.docker.com/r/ultralytics/yolov3. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) ![Docker Pulls](https://img.shields.io/docker/pulls/ultralytics/yolov3?logo=docker) ## Citation From 512b518c2009373fd3d88c6419c0e853eeb0b42e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 18 Jun 2020 12:39:33 -0700 Subject: [PATCH 0784/1185] update --bug-report.md --- .github/ISSUE_TEMPLATE/--bug-report.md | 34 ++++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/--bug-report.md b/.github/ISSUE_TEMPLATE/--bug-report.md index 500b606b3a..392a125fb6 100644 --- a/.github/ISSUE_TEMPLATE/--bug-report.md +++ b/.github/ISSUE_TEMPLATE/--bug-report.md @@ -7,29 +7,43 @@ assignees: '' --- -Before submitting a bug report, please ensure that you are using the latest versions of: - - Python - - PyTorch - - This repository (run `git fetch && git status -uno` to check and `git pull` to update) +Before submitting a bug report, please be aware that your issue **must be reproducible** with all of the following, otherwise it is non-actionable, and we can not help you: + - **Current repository**: run `git fetch && git status -uno` to check and `git pull` to update your repo + - **Common dataset**: coco.yaml or coco128.yaml + - **Common environment**: Colab, Google Cloud, or Docker image. See https://github.com/ultralytics/yolov3#reproduce-our-environment -**Your issue must be reproducible on a public dataset (i.e COCO) using the latest version of the repository, and you must supply code to reproduce, or we can not help you.** - -If this is a custom training question we suggest you include your `train*.jpg`, `test*.jpg` and `results.png` figures. +If this is a custom dataset/training question you **must include** your `train*.jpg`, `test*.jpg` and `results.png` figures, or we can not help you. You can generate results.png with `utils.plot_results()`. ## 🐛 Bug A clear and concise description of what the bug is. -## To Reproduce -**REQUIRED**: Code to reproduce your issue below + +## To Reproduce (REQUIRED) + +Input: +``` +import torch + +a = torch.tensor([5]) +c = a / 0 +``` + +Output: ``` -python train.py ... +Traceback (most recent call last): + File "/Users/glennjocher/opt/anaconda3/envs/env1/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3331, in run_code + exec(code_obj, self.user_global_ns, self.user_ns) + File "", line 5, in + c = a / 0 +RuntimeError: ZeroDivisionError ``` ## Expected behavior A clear and concise description of what you expected to happen. + ## Environment If applicable, add screenshots to help explain your problem. From 9fd02ae22403c763f72a3dc7d1dd3d021bf158be Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 18 Jun 2020 12:40:26 -0700 Subject: [PATCH 0785/1185] update --bug-report.md --- .github/ISSUE_TEMPLATE/--bug-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/--bug-report.md b/.github/ISSUE_TEMPLATE/--bug-report.md index 392a125fb6..eb659a29d3 100644 --- a/.github/ISSUE_TEMPLATE/--bug-report.md +++ b/.github/ISSUE_TEMPLATE/--bug-report.md @@ -9,7 +9,7 @@ assignees: '' Before submitting a bug report, please be aware that your issue **must be reproducible** with all of the following, otherwise it is non-actionable, and we can not help you: - **Current repository**: run `git fetch && git status -uno` to check and `git pull` to update your repo - - **Common dataset**: coco.yaml or coco128.yaml + - **Common dataset**: coco2017.data or coco64.data - **Common environment**: Colab, Google Cloud, or Docker image. See https://github.com/ultralytics/yolov3#reproduce-our-environment If this is a custom dataset/training question you **must include** your `train*.jpg`, `test*.jpg` and `results.png` figures, or we can not help you. You can generate results.png with `utils.plot_results()`. From dc068369683adf831eba165c2760ba7fb3418456 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 18 Jun 2020 12:45:19 -0700 Subject: [PATCH 0786/1185] update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9e47c56755..9da58e5a36 100755 --- a/README.md +++ b/README.md @@ -32,10 +32,10 @@ $ pip install -U -r requirements.txt ## Tutorials -* Open In Colab -* [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) < highly recommended!! +* [Notebook](https://github.com/ultralytics/yolov3/blob/master/tutorial.ipynb) Open In Colab +* [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) << highly recommended * [GCP Quickstart](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) -* [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) +* [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) ![Docker Pulls](https://img.shields.io/docker/pulls/ultralytics/yolov3?logo=docker) * [A TensorRT Implementation of YOLOv3 and YOLOv4](https://github.com/wang-xinyu/tensorrtx/tree/master/yolov3-spp) From 10dc08f91b4ec4767aa971e2f750d9476185b8ea Mon Sep 17 00:00:00 2001 From: FuLin Date: Fri, 19 Jun 2020 12:54:57 -0400 Subject: [PATCH 0787/1185] revert value of gs back to 32(from 64) (#1317) --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index f963fdf1e7..ca99daca6b 100644 --- a/train.py +++ b/train.py @@ -64,7 +64,7 @@ def train(hyp): imgsz_min, imgsz_max, imgsz_test = opt.img_size # img sizes (min, max, test) # Image Sizes - gs = 64 # (pixels) grid size + gs = 32 # (pixels) grid size assert math.fmod(imgsz_min, gs) == 0, '--img-size %g must be a %g-multiple' % (imgsz_min, gs) opt.multi_scale |= imgsz_min != imgsz_max # multi if different (min, max) if opt.multi_scale: From 183e3833d2e931e4f8ff73f1e87f915bea6966d0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 20 Jun 2020 09:58:48 -0700 Subject: [PATCH 0788/1185] update datasets.py --- utils/datasets.py | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 5811142ae4..c68e8660a8 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -18,7 +18,7 @@ help_url = 'https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' img_formats = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.dng'] -vid_formats = ['.mov', '.avi', '.mp4'] +vid_formats = ['.mov', '.avi', '.mp4', '.mpg', '.mpeg', '.m4v', '.wmv', '.mkv'] # Get orientation exif tag for orientation in ExifTags.TAGS.keys(): @@ -63,7 +63,8 @@ def __init__(self, path, img_size=416): self.new_video(videos[0]) # new video else: self.cap = None - assert self.nF > 0, 'No images or videos found in ' + path + assert self.nF > 0, 'No images or videos found in %s. Supported formats are:\nimages: %s\nvideos: %s' % \ + (path, img_formats, vid_formats) def __iter__(self): self.count = 0 @@ -257,7 +258,7 @@ def __len__(self): class LoadImagesAndLabels(Dataset): # for training/testing def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, - cache_images=False, single_cls=False): + cache_images=False, single_cls=False, pad=0.0): try: path = str(Path(path)) # os-agnostic parent = str(Path(path).parent) + os.sep @@ -291,20 +292,22 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r self.label_files = [x.replace('images', 'labels').replace(os.path.splitext(x)[-1], '.txt') for x in self.img_files] + # Read image shapes (wh) + sp = path.replace('.txt', '') + '.shapes' # shapefile path + try: + with open(sp, 'r') as f: # read existing shapefile + s = [x.split() for x in f.read().splitlines()] + assert len(s) == n, 'Shapefile out of sync' + except: + s = [exif_size(Image.open(f)) for f in tqdm(self.img_files, desc='Reading image shapes')] + np.savetxt(sp, s, fmt='%g') # overwrites existing (if any) + + self.shapes = np.array(s, dtype=np.float64) + # Rectangular Training https://github.com/ultralytics/yolov3/issues/232 if self.rect: - # Read image shapes (wh) - sp = path.replace('.txt', '') + '.shapes' # shapefile path - try: - with open(sp, 'r') as f: # read existing shapefile - s = [x.split() for x in f.read().splitlines()] - assert len(s) == n, 'Shapefile out of sync' - except: - s = [exif_size(Image.open(f)) for f in tqdm(self.img_files, desc='Reading image shapes')] - np.savetxt(sp, s, fmt='%g') # overwrites existing (if any) - # Sort by aspect ratio - s = np.array(s, dtype=np.float64) + s = self.shapes # wh ar = s[:, 1] / s[:, 0] # aspect ratio irect = ar.argsort() self.img_files = [self.img_files[i] for i in irect] @@ -322,7 +325,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r elif mini > 1: shapes[i] = [1, 1 / mini] - self.batch_shapes = np.ceil(np.array(shapes) * img_size / 64.).astype(np.int) * 64 + self.batch_shapes = np.ceil(np.array(shapes) * img_size / 32. + pad).astype(np.int) * 32 # Cache labels self.imgs = [None] * n @@ -530,7 +533,7 @@ def load_image(self, index): assert img is not None, 'Image Not Found ' + path h0, w0 = img.shape[:2] # orig hw r = self.img_size / max(h0, w0) # resize image to img_size - if r < 1 or (self.augment and r != 1): # always resize down, only resize up if training with augmentation + if r != 1: # always resize down, only resize up if training with augmentation interp = cv2.INTER_AREA if r < 1 and not self.augment else cv2.INTER_LINEAR img = cv2.resize(img, (int(w0 * r), int(h0 * r)), interpolation=interp) return img, (h0, w0), img.shape[:2] # img, hw_original, hw_resized From ca7794ed05dccda8d216b9f35ce335750788425c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 20 Jun 2020 10:02:18 -0700 Subject: [PATCH 0789/1185] update test.py --- test.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index ace0995150..3e739d8e4b 100644 --- a/test.py +++ b/test.py @@ -23,6 +23,7 @@ def test(cfg, multi_label=True): # Initialize/load model and set device if model is None: + is_training = False device = torch_utils.select_device(opt.device, batch_size=batch_size) verbose = opt.task == 'test' @@ -47,6 +48,7 @@ def test(cfg, if device.type != 'cpu' and torch.cuda.device_count() > 1: model = nn.DataParallel(model) else: # called by train.py + is_training = True device = next(model.parameters()).device # get model device verbose = False @@ -61,7 +63,7 @@ def test(cfg, # Dataloader if dataloader is None: - dataset = LoadImagesAndLabels(path, imgsz, batch_size, rect=True, single_cls=opt.single_cls) + dataset = LoadImagesAndLabels(path, imgsz, batch_size, rect=True, single_cls=opt.single_cls, pad=0.5) batch_size = min(batch_size, len(dataset)) dataloader = DataLoader(dataset, batch_size=batch_size, @@ -91,7 +93,7 @@ def test(cfg, t0 += torch_utils.time_synchronized() - t # Compute loss - if hasattr(model, 'hyp'): # if model has loss hyperparameters + if is_training: # if model has loss hyperparameters loss += compute_loss(train_out, targets, model)[1][:3] # GIoU, obj, cls # Run NMS From a97f350461287daaabaac3200d90b7eec440453f Mon Sep 17 00:00:00 2001 From: Oulbacha Reda Date: Mon, 22 Jun 2020 16:15:40 -0400 Subject: [PATCH 0790/1185] Non-output layer freeze in train.py (#1333) Freeze layers that aren't of type YOLOLayer and that aren't the conv layers preceeding them --- train.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/train.py b/train.py index ca99daca6b..5abcacf0be 100644 --- a/train.py +++ b/train.py @@ -143,6 +143,16 @@ def train(hyp): elif len(weights) > 0: # darknet format # possible weights are '*.weights', 'yolov3-tiny.conv.15', 'darknet53.conv.74' etc. load_darknet_weights(model, weights) + + if opt.freeze_layers: + output_layer_indices = [idx - 1 for idx, module in enumerate(model.module_list) \ + if isinstance(module, YOLOLayer)] + freeze_layer_indices = [x for x in range(len(model.module_list)) if\ + (x not in output_layer_indices) and \ + (x - 1 not in output_layer_indices)] + for idx in freeze_layer_indices: + for parameter in model.module_list[idx].parameters(): + parameter.requires_grad_(False) # Mixed precision training https://github.com/NVIDIA/apex if mixed_precision: @@ -394,6 +404,7 @@ def train(hyp): parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1 or cpu)') parser.add_argument('--adam', action='store_true', help='use adam optimizer') parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') + parser.add_argument('--freeze-layers', action='store_true', help='Freeze non-output layers') opt = parser.parse_args() opt.weights = last if opt.resume else opt.weights check_git_status() From e276e3a1030a672fab6135c90a42f8b454713dc1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 22 Jun 2020 15:20:08 -0700 Subject: [PATCH 0791/1185] Update greetings.yml --- .github/workflows/greetings.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 2c5c5c700f..860c4a266c 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -16,7 +16,7 @@ jobs: - + To continue with this repo, please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://github.com/ultralytics/yolov3/blob/master/tutorial.ipynb), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. @@ -27,4 +27,4 @@ jobs: - **Edge AI** integrated into custom iOS and Android apps for realtime **30 FPS video inference.** - **Custom data training**, hyperparameter evolution, and model exportation to any destination. - For more information please visit https://www.ultralytics.com. \ No newline at end of file + For more information please visit https://www.ultralytics.com. From 8a414743e2fd92d2bc471c1f92281f82cf31bc10 Mon Sep 17 00:00:00 2001 From: Chang Lee Date: Mon, 22 Jun 2020 22:07:51 -0400 Subject: [PATCH 0792/1185] Fixed string format error during weight conversion (#1334) --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index 0323b25e48..d5cfc02a7a 100755 --- a/models.py +++ b/models.py @@ -438,7 +438,7 @@ def convert(cfg='cfg/yolov3-spp.cfg', weights='weights/yolov3-spp.weights'): target = weights.rsplit('.', 1)[0] + '.pt' torch.save(chkpt, target) - print("Success: converted '%s' to 's%'" % (weights, target)) + print("Success: converted '%s' to '%s'" % (weights, target)) else: print('Error: extension not supported.') From a587d39cd447b85219e761734b5f1d5cb30197d8 Mon Sep 17 00:00:00 2001 From: NanoCode012 Date: Thu, 25 Jun 2020 01:37:09 +0700 Subject: [PATCH 0793/1185] Fixed train.py SyntaxError due to last commit (#1336) Fixed unexpected character after line continuation character on line 148,150, and 151 --- train.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/train.py b/train.py index 5abcacf0be..705b51981b 100644 --- a/train.py +++ b/train.py @@ -145,10 +145,9 @@ def train(hyp): load_darknet_weights(model, weights) if opt.freeze_layers: - output_layer_indices = [idx - 1 for idx, module in enumerate(model.module_list) \ - if isinstance(module, YOLOLayer)] - freeze_layer_indices = [x for x in range(len(model.module_list)) if\ - (x not in output_layer_indices) and \ + output_layer_indices = [idx - 1 for idx, module in enumerate(model.module_list) if isinstance(module, YOLOLayer)] + freeze_layer_indices = [x for x in range(len(model.module_list)) if + (x not in output_layer_indices) and (x - 1 not in output_layer_indices)] for idx in freeze_layer_indices: for parameter in model.module_list[idx].parameters(): From e1fb453079eea03f4da2b572abeab6d4dced9900 Mon Sep 17 00:00:00 2001 From: Jason Nataprawira <52592216+jas-nat@users.noreply.github.com> Date: Thu, 25 Jun 2020 20:09:41 +0700 Subject: [PATCH 0794/1185] Update requirements.txt (#1339) Add torchvision --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 08c696bb0b..7b631ebe12 100755 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ numpy == 1.17 opencv-python >= 4.1 torch >= 1.5 +torchvision matplotlib pycocotools tqdm From 9b9715668c544f9fbb16bb95f6861cf73293d2e4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 27 Jun 2020 09:09:02 -0700 Subject: [PATCH 0795/1185] add yolov4-tiny.cfg #1350 --- cfg/yolov4-tiny.cfg | 281 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 cfg/yolov4-tiny.cfg diff --git a/cfg/yolov4-tiny.cfg b/cfg/yolov4-tiny.cfg new file mode 100644 index 0000000000..dc6f5bfb8c --- /dev/null +++ b/cfg/yolov4-tiny.cfg @@ -0,0 +1,281 @@ +[net] +# Testing +#batch=1 +#subdivisions=1 +# Training +batch=64 +subdivisions=1 +width=416 +height=416 +channels=3 +momentum=0.9 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500200 +policy=steps +steps=400000,450000 +scales=.1,.1 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=2 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[route] +layers=-1 +groups=2 +group_id=1 + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -6,-1 + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[route] +layers=-1 +groups=2 +group_id=1 + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -6,-1 + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[route] +layers=-1 +groups=2 +group_id=1 + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -1,-2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[route] +layers = -6,-1 + +[maxpool] +size=2 +stride=2 + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +################################## + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=leaky + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + + + +[yolo] +mask = 3,4,5 +anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 +classes=80 +num=6 +jitter=.3 +scale_x_y = 1.05 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +ignore_thresh = .7 +truth_thresh = 1 +random=0 +resize=1.5 +nms_kind=greedynms +beta_nms=0.6 + +[route] +layers = -4 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=leaky + +[upsample] +stride=2 + +[route] +layers = -1, 23 + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=leaky + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 1,2,3 +anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 +classes=80 +num=6 +jitter=.3 +scale_x_y = 1.05 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +ignore_thresh = .7 +truth_thresh = 1 +random=0 +resize=1.5 +nms_kind=greedynms +beta_nms=0.6 From eadc06bce8d835fd1c1736898179fc3195d64520 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 27 Jun 2020 23:52:45 -0700 Subject: [PATCH 0796/1185] Update README.md --- README.md | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 9da58e5a36..84ca686496 100755 --- a/README.md +++ b/README.md @@ -1,25 +1,7 @@ - - - - - - -
- - - - - - - - - -
- - -## Introduction - -The https://github.com/ultralytics/yolov3 repo contains inference and training code for YOLOv3 in PyTorch. The code works on Linux, MacOS and Windows. Training is done on the COCO dataset by default: https://cocodataset.org/#home. **Credit to Joseph Redmon for YOLO:** https://pjreddie.com/darknet/yolo/. + + + +This repo contains Ultralytics inference and training code for YOLOv3 in PyTorch. The code works on Linux, MacOS and Windows. **Credit to Joseph Redmon for YOLO:** https://pjreddie.com/darknet/yolo/. ## Requirements From fc0394e0382fdefe3c73c13babf4980140a304b1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 27 Jun 2020 23:54:46 -0700 Subject: [PATCH 0797/1185] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 84ca686496..b62dcad887 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ - - + + +  -This repo contains Ultralytics inference and training code for YOLOv3 in PyTorch. The code works on Linux, MacOS and Windows. **Credit to Joseph Redmon for YOLO:** https://pjreddie.com/darknet/yolo/. +This repo contains Ultralytics inference and training code for YOLOv3 in PyTorch. The code works on Linux, MacOS and Windows. Credit to Joseph Redmon for YOLO https://pjreddie.com/darknet/yolo/. ## Requirements From 46575cfad5fca621d1a4247b33dc581f822fe98a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 27 Jun 2020 23:59:54 -0700 Subject: [PATCH 0798/1185] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b62dcad887..bf4017d6ee 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ - +   This repo contains Ultralytics inference and training code for YOLOv3 in PyTorch. The code works on Linux, MacOS and Windows. Credit to Joseph Redmon for YOLO https://pjreddie.com/darknet/yolo/. From f8e5338f0a1e73e4a53bb0adba92eee38d8c0179 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 30 Jun 2020 16:19:56 -0700 Subject: [PATCH 0799/1185] --resume epochs update --- train.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/train.py b/train.py index 705b51981b..5402f707a2 100644 --- a/train.py +++ b/train.py @@ -116,29 +116,35 @@ def train(hyp): attempt_download(weights) if weights.endswith('.pt'): # pytorch format # possible weights are '*.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt' etc. - chkpt = torch.load(weights, map_location=device) + ckpt = torch.load(weights, map_location=device) # load model try: - chkpt['model'] = {k: v for k, v in chkpt['model'].items() if model.state_dict()[k].numel() == v.numel()} - model.load_state_dict(chkpt['model'], strict=False) + ckpt['model'] = {k: v for k, v in ckpt['model'].items() if model.state_dict()[k].numel() == v.numel()} + model.load_state_dict(ckpt['model'], strict=False) except KeyError as e: s = "%s is not compatible with %s. Specify --weights '' or specify a --cfg compatible with %s. " \ "See https://github.com/ultralytics/yolov3/issues/657" % (opt.weights, opt.cfg, opt.weights) raise KeyError(s) from e # load optimizer - if chkpt['optimizer'] is not None: - optimizer.load_state_dict(chkpt['optimizer']) - best_fitness = chkpt['best_fitness'] + if ckpt['optimizer'] is not None: + optimizer.load_state_dict(ckpt['optimizer']) + best_fitness = ckpt['best_fitness'] # load results - if chkpt.get('training_results') is not None: + if ckpt.get('training_results') is not None: with open(results_file, 'w') as file: - file.write(chkpt['training_results']) # write results.txt + file.write(ckpt['training_results']) # write results.txt - start_epoch = chkpt['epoch'] + 1 - del chkpt + # epochs + start_epoch = ckpt['epoch'] + 1 + if epochs < start_epoch: + print('%s has been trained for %g epochs. Fine-tuning for %g additional epochs.' % + (opt.weights, ckpt['epoch'], epochs)) + epochs += ckpt['epoch'] # finetune additional epochs + + del ckpt elif len(weights) > 0: # darknet format # possible weights are '*.weights', 'yolov3-tiny.conv.15', 'darknet53.conv.74' etc. @@ -349,17 +355,17 @@ def train(hyp): save = (not opt.nosave) or (final_epoch and not opt.evolve) if save: with open(results_file, 'r') as f: # create checkpoint - chkpt = {'epoch': epoch, + ckpt = {'epoch': epoch, 'best_fitness': best_fitness, 'training_results': f.read(), 'model': ema.ema.module.state_dict() if hasattr(model, 'module') else ema.ema.state_dict(), 'optimizer': None if final_epoch else optimizer.state_dict()} # Save last, best and delete - torch.save(chkpt, last) + torch.save(ckpt, last) if (best_fitness == fi) and not final_epoch: - torch.save(chkpt, best) - del chkpt + torch.save(ckpt, best) + del ckpt # end epoch ---------------------------------------------------------------------------------------------------- # end training From 63996a8bfe72e69da5f24c96cd4d3480e3beb737 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 30 Jun 2020 21:45:06 -0700 Subject: [PATCH 0800/1185] --resume update --- train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/train.py b/train.py index 5402f707a2..5915848a30 100644 --- a/train.py +++ b/train.py @@ -411,7 +411,7 @@ def train(hyp): parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') parser.add_argument('--freeze-layers', action='store_true', help='Freeze non-output layers') opt = parser.parse_args() - opt.weights = last if opt.resume else opt.weights + opt.weights = last if opt.resume and not opt.weights else opt.weights check_git_status() opt.cfg = check_file(opt.cfg) # check file opt.data = check_file(opt.data) # check file From fa78fc4e3413eca7014450602781598c243fd95d Mon Sep 17 00:00:00 2001 From: tjiagoM Date: Thu, 2 Jul 2020 22:35:20 +0100 Subject: [PATCH 0801/1185] partial support for dropout layer (#1366) --- models.py | 6 ++++++ utils/parse_config.py | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/models.py b/models.py index d5cfc02a7a..dd2fd656b4 100755 --- a/models.py +++ b/models.py @@ -106,6 +106,9 @@ def create_modules(module_defs, img_size, cfg): # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) try: j = layers[yolo_index] if 'from' in mdef else -1 + # If previous layer is a dropout layer, get the one before + if module_list[j].__class__.__name__ == 'Dropout': + j -= 1 bias_ = module_list[j][0].bias # shape(255,) bias = bias_[:modules.no * modules.na].view(modules.na, -1) # shape(3,85) bias[:, 4] += -4.5 # obj @@ -114,6 +117,9 @@ def create_modules(module_defs, img_size, cfg): except: print('WARNING: smart bias initialization failure.') + elif mdef['type'] == 'dropout': + perc = float(mdef['probability']) + modules = nn.Dropout(p=perc) else: print('Warning: Unrecognized Layer Type: ' + mdef['type']) diff --git a/utils/parse_config.py b/utils/parse_config.py index 4208748e82..88d7d7ede4 100644 --- a/utils/parse_config.py +++ b/utils/parse_config.py @@ -31,6 +31,7 @@ def parse_model_cfg(path): mdefs[-1][key] = [int(x) for x in val.split(',')] else: val = val.strip() + # TODO: .isnumeric() actually fails to get the float case if val.isnumeric(): # return int or float mdefs[-1][key] = int(val) if (int(val) - float(val)) == 0 else float(val) else: @@ -40,7 +41,7 @@ def parse_model_cfg(path): supported = ['type', 'batch_normalize', 'filters', 'size', 'stride', 'pad', 'activation', 'layers', 'groups', 'from', 'mask', 'anchors', 'classes', 'num', 'jitter', 'ignore_thresh', 'truth_thresh', 'random', 'stride_x', 'stride_y', 'weights_type', 'weights_normalization', 'scale_x_y', 'beta_nms', 'nms_kind', - 'iou_loss', 'iou_normalizer', 'cls_normalizer', 'iou_thresh'] + 'iou_loss', 'iou_normalizer', 'cls_normalizer', 'iou_thresh', 'probability'] f = [] # fields for x in mdefs[1:]: From 2b0f4f6f9d8de147dd52cbcc668fed4011c0a6e3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 2 Jul 2020 16:42:45 -0700 Subject: [PATCH 0802/1185] update .dockerignore --- .dockerignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.dockerignore b/.dockerignore index 5a2495bcb9..a0d80d0951 100644 --- a/.dockerignore +++ b/.dockerignore @@ -16,8 +16,10 @@ data/samples/* # Neural Network weights ----------------------------------------------------------------------------------------------- **/*.weights **/*.pt +**/*.pth **/*.onnx **/*.mlmodel +**/*.torchscript **/darknet53.conv.74 **/yolov3-tiny.conv.15 From bdf546150df5aaeacd1eb415b5dc830096079880 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 8 Jul 2020 21:33:10 -0700 Subject: [PATCH 0803/1185] Update requirements.txt #1339 --- requirements.txt | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7b631ebe12..e5b9d3da29 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,22 +1,20 @@ # pip install -U -r requirements.txt -# pycocotools requires numpy 1.17 https://github.com/cocodataset/cocoapi/issues/356 -numpy == 1.17 -opencv-python >= 4.1 -torch >= 1.5 -torchvision +Cython +numpy==1.17 +opencv-python +torch>=1.5.1 matplotlib -pycocotools -tqdm pillow -tensorboard >= 1.14 - -# Nvidia Apex (optional) for mixed precision training -------------------------- -# git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex +tensorboard +torchvision +scipy +tqdm +git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI -# Conda commands (in place of pip) --------------------------------------------- +# Conda commands (in lieu of pip) --------------------------------------------- # conda update -yn base -c defaults conda # conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython # conda install -yc conda-forge scikit-image pycocotools tensorboard # conda install -yc spyder-ide spyder-line-profiler # conda install -yc pytorch pytorch torchvision -# conda install -yc conda-forge protobuf numpy && pip install onnx # https://github.com/onnx/onnx#linux-and-macos +# conda install -yc conda-forge protobuf numpy && pip install onnx==1.6.0 # https://github.com/onnx/onnx#linux-and-macos From 2861288b0396d86f87d21b3789574fe4950ff7ff Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 9 Jul 2020 17:44:01 -0700 Subject: [PATCH 0804/1185] update issue templates --- .github/ISSUE_TEMPLATE/--bug-report.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/--bug-report.md b/.github/ISSUE_TEMPLATE/--bug-report.md index eb659a29d3..6dc6e26427 100644 --- a/.github/ISSUE_TEMPLATE/--bug-report.md +++ b/.github/ISSUE_TEMPLATE/--bug-report.md @@ -8,11 +8,11 @@ assignees: '' --- Before submitting a bug report, please be aware that your issue **must be reproducible** with all of the following, otherwise it is non-actionable, and we can not help you: - - **Current repository**: run `git fetch && git status -uno` to check and `git pull` to update your repo + - **Current repo**: run `git fetch && git status -uno` to check and `git pull` to update repo - **Common dataset**: coco2017.data or coco64.data - **Common environment**: Colab, Google Cloud, or Docker image. See https://github.com/ultralytics/yolov3#reproduce-our-environment -If this is a custom dataset/training question you **must include** your `train*.jpg`, `test*.jpg` and `results.png` figures, or we can not help you. You can generate results.png with `utils.plot_results()`. +If this is a custom dataset/training question you **must include** your `train*.jpg`, `test*.jpg` and `results.png` figures, or we can not help you. You can generate these with `utils.plot_results()`. ## 🐛 Bug From 8241bf67bb0cc1c11634bdb4cc76e06ac072192b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 9 Jul 2020 17:45:01 -0700 Subject: [PATCH 0805/1185] update issue templates Signed-off-by: Glenn Jocher --- .github/ISSUE_TEMPLATE/-question.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/-question.md diff --git a/.github/ISSUE_TEMPLATE/-question.md b/.github/ISSUE_TEMPLATE/-question.md new file mode 100644 index 0000000000..2c22aea70a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/-question.md @@ -0,0 +1,13 @@ +--- +name: "❓Question" +about: Ask a general question +title: '' +labels: question +assignees: '' + +--- + +## ❔Question + + +## Additional context From cec59f12c8b0800d00949ea15511469f667d45dd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 18 Jul 2020 10:48:33 -0700 Subject: [PATCH 0806/1185] =?UTF-8?q?windows=20=E2=80=93-weights=20''=20fi?= =?UTF-8?q?x=20#192?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Glenn Jocher --- models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models.py b/models.py index dd2fd656b4..54742b883e 100755 --- a/models.py +++ b/models.py @@ -452,7 +452,7 @@ def convert(cfg='cfg/yolov3-spp.cfg', weights='weights/yolov3-spp.weights'): def attempt_download(weights): # Attempt to download pretrained weights if not found locally - weights = weights.strip() + weights = weights.strip().replace("'", '') msg = weights + ' missing, try downloading from https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0' if len(weights) > 0 and not os.path.isfile(weights): From f61fa7de2b4eb4b831ef396b93d9781eca9eb9c8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 20 Jul 2020 10:33:49 -0700 Subject: [PATCH 0807/1185] Update datasets.py --- utils/datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/datasets.py b/utils/datasets.py index c68e8660a8..2a4ee63b89 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -17,7 +17,7 @@ from utils.utils import xyxy2xywh, xywh2xyxy help_url = 'https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' -img_formats = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.dng'] +img_formats = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.tiff','.dng'] vid_formats = ['.mov', '.avi', '.mp4', '.mpg', '.mpeg', '.m4v', '.wmv', '.mkv'] # Get orientation exif tag From e80cc2b80e3fd46395e8ec75f843960100927ff2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 20 Jul 2020 10:34:06 -0700 Subject: [PATCH 0808/1185] Update datasets.py --- utils/datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/datasets.py b/utils/datasets.py index 2a4ee63b89..959fcb6c99 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -17,7 +17,7 @@ from utils.utils import xyxy2xywh, xywh2xyxy help_url = 'https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' -img_formats = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.tiff','.dng'] +img_formats = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.tiff', '.dng'] vid_formats = ['.mov', '.avi', '.mp4', '.mpg', '.mpeg', '.m4v', '.wmv', '.mkv'] # Get orientation exif tag From 8de13f114db3d95cfae2bfd928d2dbbcb2fccdcb Mon Sep 17 00:00:00 2001 From: e96031413 <30921855+e96031413@users.noreply.github.com> Date: Mon, 27 Jul 2020 14:50:05 +0800 Subject: [PATCH 0809/1185] Modify Line 104 on getting coco dataset (#1415) The correct command for downloading coco dataset 2014 is supposed to be "!bash yolov3/data/get_coco2014.sh" --- tutorial.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorial.ipynb b/tutorial.ipynb index 7da272bc83..53e5cd1ac7 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -101,7 +101,7 @@ ], "source": [ "!git clone https://github.com/ultralytics/yolov3 # clone\n", - "!bash yolov3/data/get_coco_dataset_gdrive.sh # copy COCO2014 dataset (19GB)\n", + "!bash yolov3/data/get_coco2014.sh # copy COCO2014 dataset (19GB)\n", "%cd yolov3" ] }, From e0a5a6b411cca45f0d64aa932abffbf3c99b92b3 Mon Sep 17 00:00:00 2001 From: priteshgohil <43172056+priteshgohil@users.noreply.github.com> Date: Mon, 27 Jul 2020 19:29:45 +0200 Subject: [PATCH 0810/1185] edit in comments (#1417) Co-authored-by: Priteshkumar Bharatbhai Gohil --- test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index 3e739d8e4b..4d68438eb4 100644 --- a/test.py +++ b/test.py @@ -145,8 +145,8 @@ def test(cfg, # Per target class for cls in torch.unique(tcls_tensor): - ti = (cls == tcls_tensor).nonzero().view(-1) # prediction indices - pi = (cls == pred[:, 5]).nonzero().view(-1) # target indices + ti = (cls == tcls_tensor).nonzero().view(-1) # target indices + pi = (cls == pred[:, 5]).nonzero().view(-1) # prediction indices # Search for detections if pi.shape[0]: From c65e4d4446c63fc3380dbcc43138cc7274a6c0b7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 31 Jul 2020 00:05:49 -0700 Subject: [PATCH 0811/1185] Update stale.yml --- .github/workflows/stale.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index f0d75cb44e..16b9de6b8d 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,17 +1,17 @@ name: Close stale issues on: schedule: - - cron: "0 0 * * *" + - cron: "0 0 * * *" jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v1 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove Stale label or comment or this will be closed in 5 days.' - stale-pr-message: 'This pull request is stale because it has been open 30 days with no activity. Remove Stale label or comment or this will be closed in 5 days.' - days-before-stale: 30 - days-before-close: 5 - exempt-issue-label: 'tutorial' + - uses: actions/stale@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' + stale-pr-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' + days-before-stale: 30 + days-before-close: 5 + exempt-issue-label: 'documentation,tutorial' From 06138062869c41d3df130e07c5aa92fa5a01dad5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 31 Jul 2020 00:09:09 -0700 Subject: [PATCH 0812/1185] Update greetings.yml --- .github/workflows/greetings.yml | 45 ++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 860c4a266c..401a43ec42 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -6,25 +6,36 @@ jobs: greeting: runs-on: ubuntu-latest steps: - - uses: actions/first-interaction@v1 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - pr-message: 'Hello @${{ github.actor }}, thank you for submitting a PR! We will respond as soon as possible.' - issue-message: | - Hello @${{ github.actor }}, thank you for your interest in our work! Ultralytics has open-sourced YOLOv5 at https://github.com/ultralytics/yolov5, featuring faster, lighter and more accurate object detection. YOLOv5 is recommended for all new projects. + - uses: actions/first-interaction@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + pr-message: | + Hello @${{ github.actor }}, thank you for submitting a PR! To allow your work to be integrated as seamlessly as possible, we advise you to: + - Verify your PR is **up-to-date with origin/master.** If your PR is behind origin/master update by running the following, replacing 'feature' with the name of your local branch: + ```bash + git remote add upstream https://github.com/ultralytics/yolov3.git + git fetch upstream + git checkout feature # <----- replace 'feature' with local branch name + git rebase upstream/master + git push -u origin -f + ``` + - Verify all Continuous Integration (CI) **checks are passing**. + - Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ -Bruce Lee + issue-message: | + Hello @${{ github.actor }}, thank you for your interest in our work! Ultralytics has open-sourced YOLOv5 at https://github.com/ultralytics/yolov5, featuring faster, lighter and more accurate object detection. YOLOv5 is recommended for all new projects. - - + + - + - To continue with this repo, please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://github.com/ultralytics/yolov3/blob/master/tutorial.ipynb), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. - - If this is a bug report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you. + To continue with this repo, please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://github.com/ultralytics/yolov3/blob/master/tutorial.ipynb), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. - If this is a custom model or data training question, please note that Ultralytics does **not** provide free personal support. As a leader in vision ML and AI, we do offer professional consulting, from simple expert advice up to delivery of fully customized, end-to-end production solutions for our clients, such as: - - **Cloud-based AI** systems operating on **hundreds of HD video streams in realtime.** - - **Edge AI** integrated into custom iOS and Android apps for realtime **30 FPS video inference.** - - **Custom data training**, hyperparameter evolution, and model exportation to any destination. + If this is a bug report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you. - For more information please visit https://www.ultralytics.com. + If this is a custom model or data training question, please note that Ultralytics does **not** provide free personal support. As a leader in vision ML and AI, we do offer professional consulting, from simple expert advice up to delivery of fully customized, end-to-end production solutions for our clients, such as: + - **Cloud-based AI** systems operating on **hundreds of HD video streams in realtime.** + - **Edge AI** integrated into custom iOS and Android apps for realtime **30 FPS video inference.** + - **Custom data training**, hyperparameter evolution, and model exportation to any destination. + + For more information please visit https://www.ultralytics.com. From ee82e3db5dfda38f7815071c24afd944b2301e02 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 3 Aug 2020 19:37:38 -0700 Subject: [PATCH 0813/1185] update requirements.txt (#1431) --- requirements.txt | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/requirements.txt b/requirements.txt index e5b9d3da29..2656a96dcc 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,17 +1,18 @@ # pip install -U -r requirements.txt Cython -numpy==1.17 -opencv-python -torch>=1.5.1 -matplotlib +matplotlib>=3.2.2 +numpy>=1.18.5 +opencv-python>=4.1.2 pillow -tensorboard -torchvision -scipy -tqdm -git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI +# pycocotools>=2.0 +PyYAML>=5.3 +scipy>=1.4.1 +tensorboard>=2.2 +torch>=1.6.0 +torchvision>=0.7.0 +tqdm>=4.41.0 -# Conda commands (in lieu of pip) --------------------------------------------- +# Conda commands (in place of pip) --------------------------------------------- # conda update -yn base -c defaults conda # conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython # conda install -yc conda-forge scikit-image pycocotools tensorboard From 7163b5e89f03754e376e08976a55a9ae1bff56bb Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 3 Aug 2020 19:53:06 -0700 Subject: [PATCH 0814/1185] update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bf4017d6ee..ca6d049918 100755 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This repo contains Ultralytics inference and training code for YOLOv3 in PyTorch ## Requirements -Python 3.7 or later with all `requirements.txt` dependencies installed, including `torch >= 1.5`. To install run: +Python 3.8 or later with all `requirements.txt` dependencies installed, including `torch >= 1.6`. To install run: ```bash $ pip install -U -r requirements.txt ``` From 061806bb1f264dd1d44c541d02a10bc98b6aacf2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 3 Aug 2020 19:54:03 -0700 Subject: [PATCH 0815/1185] update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca6d049918..69725b5935 100755 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This repo contains Ultralytics inference and training code for YOLOv3 in PyTorch ## Requirements -Python 3.8 or later with all `requirements.txt` dependencies installed, including `torch >= 1.6`. To install run: +Python 3.8 or later with all [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) dependencies installed, including `torch>=1.6`. To install run: ```bash $ pip install -U -r requirements.txt ``` From 2ba4ee32427e489c02e6460c05279a0c0ca398c1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 3 Aug 2020 19:54:27 -0700 Subject: [PATCH 0816/1185] update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 69725b5935..4051eb8a52 100755 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This repo contains Ultralytics inference and training code for YOLOv3 in PyTorch Python 3.8 or later with all [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) dependencies installed, including `torch>=1.6`. To install run: ```bash -$ pip install -U -r requirements.txt +$ pip install -r requirements.txt ``` From af22cd7be34b6d0834a15363ec6b16c729a48fd9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 8 Aug 2020 11:12:19 -0700 Subject: [PATCH 0817/1185] add .gitattributes file --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..6c8722f6e0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# remove notebooks from GitHub language stats +*.ipynb linguist-vendored From 2a74d1fd7d39f74d05cb76c94fbbb21e47e37ebb Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 8 Aug 2020 12:57:41 -0700 Subject: [PATCH 0818/1185] update requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2656a96dcc..895cf6caa9 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -# pip install -U -r requirements.txt +# pip install -r requirements.txt Cython matplotlib>=3.2.2 numpy>=1.18.5 From f14c143926c8faadb2a767201344dd2dfd8b138c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 11 Aug 2020 00:56:04 -0700 Subject: [PATCH 0819/1185] Update greetings.yml --- .github/workflows/greetings.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 401a43ec42..642e08d8d5 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -1,6 +1,6 @@ name: Greetings -on: [pull_request, issues] +on: [pull_request_target, issues] jobs: greeting: @@ -21,6 +21,7 @@ jobs: ``` - Verify all Continuous Integration (CI) **checks are passing**. - Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ -Bruce Lee + issue-message: | Hello @${{ github.actor }}, thank you for your interest in our work! Ultralytics has open-sourced YOLOv5 at https://github.com/ultralytics/yolov5, featuring faster, lighter and more accurate object detection. YOLOv5 is recommended for all new projects. From 3d09ca366c84d5896b04b24e492c1a8a7d430c42 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 12 Aug 2020 13:51:10 -0700 Subject: [PATCH 0820/1185] reverse plotting low to high confidence (#1448) --- detect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detect.py b/detect.py index 0c4b17b395..42e257639a 100644 --- a/detect.py +++ b/detect.py @@ -121,7 +121,7 @@ def detect(save_img=False): s += '%g %ss, ' % (n, names[int(c)]) # add to string # Write results - for *xyxy, conf, cls in det: + for *xyxy, conf, cls in reversed(det): if save_txt: # Write to file xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh with open(save_path[:save_path.rfind('.')] + '.txt', 'a') as file: From 3e7e1e16c58fdfc5a147b8ef34f9e2da6d2a2923 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 13 Aug 2020 14:43:37 -0700 Subject: [PATCH 0821/1185] Update greetings.yml --- .github/workflows/greetings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 642e08d8d5..d44c685b25 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -28,7 +28,7 @@ jobs: - + To continue with this repo, please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://github.com/ultralytics/yolov3/blob/master/tutorial.ipynb), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. From 0ad44bc7e85098184c901dc5ce010aa4b9014451 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 13 Aug 2020 14:49:54 -0700 Subject: [PATCH 0822/1185] Update greetings.yml --- .github/workflows/greetings.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index d44c685b25..d9b709c430 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -27,7 +27,8 @@ jobs: - + +

To continue with this repo, please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://github.com/ultralytics/yolov3/blob/master/tutorial.ipynb), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. From 64ff05c499ddd22721e2ce8a4abadba42d680418 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 13 Aug 2020 14:56:52 -0700 Subject: [PATCH 0823/1185] Update greetings.yml --- .github/workflows/greetings.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index d9b709c430..c502351a67 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -27,7 +27,6 @@ jobs: -

From bf34ae007fea165255c8be1b7a835dedc49a9613 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 22 Aug 2020 17:49:27 -0700 Subject: [PATCH 0824/1185] Global code reformat and optimize imports --- data/get_coco2014.sh | 8 ++++---- data/get_coco2017.sh | 8 ++++---- train.py | 28 ++++++++++++++-------------- utils/evolve.sh | 3 +-- utils/gcp.sh | 3 +-- 5 files changed, 24 insertions(+), 26 deletions(-) diff --git a/data/get_coco2014.sh b/data/get_coco2014.sh index 2125cf1f8f..02d059c58e 100755 --- a/data/get_coco2014.sh +++ b/data/get_coco2014.sh @@ -6,13 +6,13 @@ # Download labels from Google Drive, accepting presented query filename="coco2014labels.zip" fileid="1s6-CmF5_SElM28r52P1OUrCcuXZN-SFo" -curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" > /dev/null -curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}" -o ${filename} +curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" >/dev/null +curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=$(awk '/download/ {print $NF}' ./cookie)&id=${fileid}" -o ${filename} rm ./cookie # Unzip labels -unzip -q ${filename} # for coco.zip -# tar -xzf ${filename} # for coco.tar.gz +unzip -q ${filename} # for coco.zip +# tar -xzf ${filename} # for coco.tar.gz rm ${filename} # Download and unzip images diff --git a/data/get_coco2017.sh b/data/get_coco2017.sh index 30f60b5b6c..3bf4069a65 100755 --- a/data/get_coco2017.sh +++ b/data/get_coco2017.sh @@ -6,13 +6,13 @@ # Download labels from Google Drive, accepting presented query filename="coco2017labels.zip" fileid="1cXZR_ckHki6nddOmcysCuuJFM--T-Q6L" -curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" > /dev/null -curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}" -o ${filename} +curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" >/dev/null +curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=$(awk '/download/ {print $NF}' ./cookie)&id=${fileid}" -o ${filename} rm ./cookie # Unzip labels -unzip -q ${filename} # for coco.zip -# tar -xzf ${filename} # for coco.tar.gz +unzip -q ${filename} # for coco.zip +# tar -xzf ${filename} # for coco.tar.gz rm ${filename} # Download and unzip images diff --git a/train.py b/train.py index 5915848a30..1aba8d279d 100644 --- a/train.py +++ b/train.py @@ -149,15 +149,15 @@ def train(hyp): elif len(weights) > 0: # darknet format # possible weights are '*.weights', 'yolov3-tiny.conv.15', 'darknet53.conv.74' etc. load_darknet_weights(model, weights) - - if opt.freeze_layers: - output_layer_indices = [idx - 1 for idx, module in enumerate(model.module_list) if isinstance(module, YOLOLayer)] - freeze_layer_indices = [x for x in range(len(model.module_list)) if - (x not in output_layer_indices) and - (x - 1 not in output_layer_indices)] - for idx in freeze_layer_indices: - for parameter in model.module_list[idx].parameters(): - parameter.requires_grad_(False) + + if opt.freeze_layers: + output_layer_indices = [idx - 1 for idx, module in enumerate(model.module_list) if isinstance(module, YOLOLayer)] + freeze_layer_indices = [x for x in range(len(model.module_list)) if + (x not in output_layer_indices) and + (x - 1 not in output_layer_indices)] + for idx in freeze_layer_indices: + for parameter in model.module_list[idx].parameters(): + parameter.requires_grad_(False) # Mixed precision training https://github.com/NVIDIA/apex if mixed_precision: @@ -356,10 +356,10 @@ def train(hyp): if save: with open(results_file, 'r') as f: # create checkpoint ckpt = {'epoch': epoch, - 'best_fitness': best_fitness, - 'training_results': f.read(), - 'model': ema.ema.module.state_dict() if hasattr(model, 'module') else ema.ema.state_dict(), - 'optimizer': None if final_epoch else optimizer.state_dict()} + 'best_fitness': best_fitness, + 'training_results': f.read(), + 'model': ema.ema.module.state_dict() if hasattr(model, 'module') else ema.ema.state_dict(), + 'optimizer': None if final_epoch else optimizer.state_dict()} # Save last, best and delete torch.save(ckpt, last) @@ -409,7 +409,7 @@ def train(hyp): parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1 or cpu)') parser.add_argument('--adam', action='store_true', help='use adam optimizer') parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') - parser.add_argument('--freeze-layers', action='store_true', help='Freeze non-output layers') + parser.add_argument('--freeze-layers', action='store_true', help='Freeze non-output layers') opt = parser.parse_args() opt.weights = last if opt.resume and not opt.weights else opt.weights check_git_status() diff --git a/utils/evolve.sh b/utils/evolve.sh index 3ff9c75cc9..6682d0ac73 100644 --- a/utils/evolve.sh +++ b/utils/evolve.sh @@ -12,8 +12,7 @@ while true; do python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --evolve --weights '' --bucket ult/coco/sppa_512 --device $1 --cfg yolov3-sppa.cfg --multi done - # coco epoch times --img-size 416 608 --epochs 27 --batch 16 --accum 4 # 36:34 2080ti # 21:58 V100 -# 63:00 T4 \ No newline at end of file +# 63:00 T4 diff --git a/utils/gcp.sh b/utils/gcp.sh index 12e2370c53..0a78cea95a 100755 --- a/utils/gcp.sh +++ b/utils/gcp.sh @@ -29,8 +29,7 @@ docker kill $(docker ps -a -q --filter ancestor=$t) sudo -s t=ultralytics/yolov3:evolve # docker kill $(docker ps -a -q --filter ancestor=$t) -for i in 0 1 6 7 -do +for i in 0 1 6 7; do docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i sleep 30 done From 4d49957f5a0a04db1cda1d9306aeb47c48dda0d1 Mon Sep 17 00:00:00 2001 From: e96031413 <30921855+e96031413@users.noreply.github.com> Date: Fri, 11 Sep 2020 03:00:53 +0800 Subject: [PATCH 0825/1185] Update requirements.txt (#1481) * Update requirements.txt I found that if we would like to calculate FLOPS in this project, we must install thop. but there's no thop package inside the requirements.txt https://github.com/ultralytics/yolov3/blob/master/utils/torch_utils.py#L108 * Update requirements.txt Co-authored-by: Glenn Jocher --- requirements.txt | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/requirements.txt b/requirements.txt index 895cf6caa9..50efbd1019 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,11 @@ # pip install -r requirements.txt + +# base ---------------------------------------- Cython matplotlib>=3.2.2 numpy>=1.18.5 opencv-python>=4.1.2 pillow -# pycocotools>=2.0 PyYAML>=5.3 scipy>=1.4.1 tensorboard>=2.2 @@ -12,10 +13,15 @@ torch>=1.6.0 torchvision>=0.7.0 tqdm>=4.41.0 -# Conda commands (in place of pip) --------------------------------------------- -# conda update -yn base -c defaults conda -# conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython -# conda install -yc conda-forge scikit-image pycocotools tensorboard -# conda install -yc spyder-ide spyder-line-profiler -# conda install -yc pytorch pytorch torchvision -# conda install -yc conda-forge protobuf numpy && pip install onnx==1.6.0 # https://github.com/onnx/onnx#linux-and-macos +# coco ---------------------------------------- +# pycocotools>=2.0 + +# export -------------------------------------- +# packaging # for coremltools +# coremltools==4.0b3 +# onnx>=1.7.0 +# scikit-learn==0.19.2 # for coreml quantization + +# extras -------------------------------------- +# thop # FLOPS computation +# seaborn # plotting From 54722d00bbe6139ed8bf1fa1b43f4a7f88e0b539 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 8 Oct 2020 11:50:52 +0200 Subject: [PATCH 0826/1185] Update stale.yml --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 16b9de6b8d..f71aead99a 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -14,4 +14,4 @@ jobs: stale-pr-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' days-before-stale: 30 days-before-close: 5 - exempt-issue-label: 'documentation,tutorial' + exempt-issue-labels: 'documentation,tutorial' From cf652962fdd11b3e3ed164fc21ccb065101927aa Mon Sep 17 00:00:00 2001 From: Shiwei Song Date: Mon, 19 Oct 2020 18:17:14 +0800 Subject: [PATCH 0827/1185] fix padding for rectangular inference (#1524) Co-authored-by: swsong --- utils/datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/datasets.py b/utils/datasets.py index 959fcb6c99..6bb818038c 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -634,7 +634,7 @@ def letterbox(img, new_shape=(416, 416), color=(114, 114, 114), auto=True, scale new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding if auto: # minimum rectangle - dw, dh = np.mod(dw, 64), np.mod(dh, 64) # wh padding + dw, dh = np.mod(dw, 32), np.mod(dh, 32) # wh padding elif scaleFill: # stretch dw, dh = 0.0, 0.0 new_unpad = new_shape From ac601cf681d8890392f28b9ec5991cd90ae0d99c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Nov 2020 13:38:13 +0100 Subject: [PATCH 0828/1185] Grid indices overflow bug fix (#1551) --- utils/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/utils.py b/utils/utils.py index 2643842d87..506d27b8a6 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -465,6 +465,7 @@ def build_targets(p, targets, model): # Append indices.append((b, a, gj, gi)) # image, anchor, grid indices + indices.append((b, a, gj.clamp_(0, gain[3]), gi.clamp_(0, gain[2]))) # image, anchor, grid indices tbox.append(torch.cat((gxy - gij, gwh), 1)) # box anch.append(anchors[a]) # anchors tcls.append(c) # class From 95460570d9094eae88db0f3e64c62c28305897e3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 6 Nov 2020 19:19:58 +0100 Subject: [PATCH 0829/1185] Grid indices overflow bug fix (#1551) --- utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 506d27b8a6..5841d14230 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -465,7 +465,7 @@ def build_targets(p, targets, model): # Append indices.append((b, a, gj, gi)) # image, anchor, grid indices - indices.append((b, a, gj.clamp_(0, gain[3]), gi.clamp_(0, gain[2]))) # image, anchor, grid indices + indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1))) # image, anchor, grid indices tbox.append(torch.cat((gxy - gij, gwh), 1)) # box anch.append(anchors[a]) # anchors tcls.append(c) # class From 46cd0d8cc4183806347af09f5df09231ad08b11d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 9 Nov 2020 20:59:57 +0100 Subject: [PATCH 0830/1185] Grid indices overflow bug fix 2 (#1551) --- utils/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/utils/utils.py b/utils/utils.py index 5841d14230..08ece411b2 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -464,7 +464,6 @@ def build_targets(p, targets, model): gi, gj = gij.T # grid xy indices # Append - indices.append((b, a, gj, gi)) # image, anchor, grid indices indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1))) # image, anchor, grid indices tbox.append(torch.cat((gxy - gij, gwh), 1)) # box anch.append(anchors[a]) # anchors From 98068efebc699e7a652fb495f3e7a23bf296affd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 13 Nov 2020 13:28:20 +0100 Subject: [PATCH 0831/1185] Update greetings.yml --- .github/workflows/greetings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index c502351a67..b0f9c58fd6 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -26,7 +26,7 @@ jobs: Hello @${{ github.actor }}, thank you for your interest in our work! Ultralytics has open-sourced YOLOv5 at https://github.com/ultralytics/yolov5, featuring faster, lighter and more accurate object detection. YOLOv5 is recommended for all new projects. - +

From 76807fae7104768650d380eaaa9dcb472f7c287d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Nov 2020 20:24:00 +0100 Subject: [PATCH 0832/1185] YOLOv5 Forward Compatibility Update (#1569) * YOLOv5 forward compatibility update * add data dir * ci test yolov3 * update build_targets() * update build_targets() * update build_targets() * update yolov3-spp.yaml * add yolov3-tiny.yaml * add yolov3-tiny.yaml * Update yolov3-tiny.yaml * thop bug fix * Detection() device bug fix * Use torchvision.ops.nms() * Remove redundant download mirror * CI tests with yolov3-tiny * Update README.md * Synch train and test iou_thresh * update requirements.txt * Cat apriori autolabels * Confusion matrix * Autosplit * Autosplit * Update README.md * AP no plot * Update caching * Update caching * Caching bug fix * --image-weights bug fix * datasets bug fix * mosaic plots bug fix * plot_study * boxes.max() * boxes.max() * boxes.max() * boxes.max() * boxes.max() * boxes.max() * update * Update README * Update README * Update README.md * Update README.md * results png * Update README * Targets scaling bug fix * update plot_study * update plot_study * update plot_study * update plot_study * Targets scaling bug fix * Finish Readme.md * Finish Readme.md * Finish Readme.md * Update README.md * Creado con Colaboratory --- .../{--bug-report.md => bug-report.md} | 6 +- ...-feature-request.md => feature-request.md} | 2 +- .../{-question.md => question.md} | 0 .github/workflows/ci-testing.yml | 76 + .github/workflows/greetings.yml | 37 +- .github/workflows/rebase.yml | 21 + .github/workflows/stale.yml | 1 + Dockerfile | 64 +- README.md | 203 +- cfg/cd53s-yolov3.cfg | 1033 ---------- cfg/cd53s.cfg | 1155 ----------- cfg/csresnext50-panet-spp.cfg | 1018 ---------- cfg/yolov3-1cls.cfg | 788 -------- cfg/yolov3-asff.cfg | 804 -------- cfg/yolov3-spp-1cls.cfg | 821 -------- cfg/yolov3-spp-3cls.cfg | 821 -------- cfg/yolov3-spp-matrix.cfg | 1115 ----------- cfg/yolov3-spp-pan-scale.cfg | 938 --------- cfg/yolov3-spp.cfg | 821 -------- cfg/yolov3-spp3.cfg | 870 --------- cfg/yolov3-tiny-1cls.cfg | 182 -- cfg/yolov3-tiny-3cls.cfg | 182 -- cfg/yolov3-tiny.cfg | 182 -- cfg/yolov3-tiny3-1cls.cfg | 227 --- cfg/yolov3-tiny3.cfg | 227 --- cfg/yolov3.cfg | 788 -------- cfg/yolov4-relu.cfg | 1155 ----------- cfg/yolov4-tiny.cfg | 281 --- cfg/yolov4.cfg | 1155 ----------- data/coco.names | 80 - data/coco.yaml | 35 + data/coco1.data | 4 - data/coco1.txt | 1 - data/coco128.yaml | 28 + data/coco16.data | 4 - data/coco16.txt | 16 - data/coco1cls.data | 4 - data/coco1cls.txt | 16 - data/coco2014.data | 4 - data/coco2017.data | 4 - data/coco64.data | 4 - data/coco64.txt | 64 - data/coco_paper.names | 91 - data/get_coco2014.sh | 24 - data/get_coco2017.sh | 24 - data/hyp.finetune.yaml | 38 + data/hyp.scratch.yaml | 33 + data/{samples => images}/bus.jpg | Bin data/{samples => images}/zidane.jpg | Bin data/scripts/get_coco.sh | 24 + data/scripts/get_voc.sh | 137 ++ data/voc.yaml | 21 + detect.py | 162 +- hubconf.py | 105 + models.py | 480 ----- models/__init__.py | 0 models/common.py | 252 +++ models/experimental.py | 152 ++ models/export.py | 94 + models/yolo.py | 287 +++ models/yolov3-spp.yaml | 51 + models/yolov3-tiny.yaml | 41 + models/yolov3.yaml | 51 + requirements.txt | 21 +- test.py | 356 ++-- train.py | 823 ++++---- tutorial.ipynb | 1693 ++++++++++++----- utils/activations.py | 72 + utils/adabound.py | 236 --- utils/autoanchor.py | 152 ++ utils/datasets.py | 698 ++++--- utils/evolve.sh | 18 - utils/gcp.sh | 39 - utils/general.py | 445 +++++ utils/google_app_engine/Dockerfile | 25 + .../additional_requirements.txt | 4 + utils/google_app_engine/app.yaml | 14 + utils/google_utils.py | 134 +- utils/layers.py | 148 -- utils/loss.py | 179 ++ utils/metrics.py | 203 ++ utils/parse_config.py | 71 - utils/plots.py | 379 ++++ utils/torch_utils.py | 224 ++- utils/utils.py | 1080 ----------- weights/download_weights.sh | 10 + weights/download_yolov3_weights.sh | 24 - 87 files changed, 5646 insertions(+), 18706 deletions(-) rename .github/ISSUE_TEMPLATE/{--bug-report.md => bug-report.md} (90%) rename .github/ISSUE_TEMPLATE/{--feature-request.md => feature-request.md} (95%) rename .github/ISSUE_TEMPLATE/{-question.md => question.md} (100%) create mode 100644 .github/workflows/ci-testing.yml create mode 100644 .github/workflows/rebase.yml delete mode 100644 cfg/cd53s-yolov3.cfg delete mode 100644 cfg/cd53s.cfg delete mode 100644 cfg/csresnext50-panet-spp.cfg delete mode 100755 cfg/yolov3-1cls.cfg delete mode 100644 cfg/yolov3-asff.cfg delete mode 100644 cfg/yolov3-spp-1cls.cfg delete mode 100644 cfg/yolov3-spp-3cls.cfg delete mode 100644 cfg/yolov3-spp-matrix.cfg delete mode 100644 cfg/yolov3-spp-pan-scale.cfg delete mode 100644 cfg/yolov3-spp.cfg delete mode 100644 cfg/yolov3-spp3.cfg delete mode 100644 cfg/yolov3-tiny-1cls.cfg delete mode 100644 cfg/yolov3-tiny-3cls.cfg delete mode 100644 cfg/yolov3-tiny.cfg delete mode 100644 cfg/yolov3-tiny3-1cls.cfg delete mode 100644 cfg/yolov3-tiny3.cfg delete mode 100755 cfg/yolov3.cfg delete mode 100644 cfg/yolov4-relu.cfg delete mode 100644 cfg/yolov4-tiny.cfg delete mode 100644 cfg/yolov4.cfg delete mode 100755 data/coco.names create mode 100644 data/coco.yaml delete mode 100644 data/coco1.data delete mode 100644 data/coco1.txt create mode 100644 data/coco128.yaml delete mode 100644 data/coco16.data delete mode 100644 data/coco16.txt delete mode 100644 data/coco1cls.data delete mode 100644 data/coco1cls.txt delete mode 100644 data/coco2014.data delete mode 100644 data/coco2017.data delete mode 100644 data/coco64.data delete mode 100644 data/coco64.txt delete mode 100644 data/coco_paper.names delete mode 100755 data/get_coco2014.sh delete mode 100755 data/get_coco2017.sh create mode 100644 data/hyp.finetune.yaml create mode 100644 data/hyp.scratch.yaml rename data/{samples => images}/bus.jpg (100%) rename data/{samples => images}/zidane.jpg (100%) create mode 100755 data/scripts/get_coco.sh create mode 100644 data/scripts/get_voc.sh create mode 100644 data/voc.yaml create mode 100644 hubconf.py delete mode 100755 models.py create mode 100644 models/__init__.py create mode 100644 models/common.py create mode 100644 models/experimental.py create mode 100644 models/export.py create mode 100644 models/yolo.py create mode 100644 models/yolov3-spp.yaml create mode 100644 models/yolov3-tiny.yaml create mode 100644 models/yolov3.yaml create mode 100644 utils/activations.py delete mode 100644 utils/adabound.py create mode 100644 utils/autoanchor.py delete mode 100644 utils/evolve.sh delete mode 100755 utils/gcp.sh create mode 100755 utils/general.py create mode 100644 utils/google_app_engine/Dockerfile create mode 100644 utils/google_app_engine/additional_requirements.txt create mode 100644 utils/google_app_engine/app.yaml delete mode 100644 utils/layers.py create mode 100644 utils/loss.py create mode 100644 utils/metrics.py delete mode 100644 utils/parse_config.py create mode 100644 utils/plots.py delete mode 100755 utils/utils.py create mode 100755 weights/download_weights.sh delete mode 100644 weights/download_yolov3_weights.sh diff --git a/.github/ISSUE_TEMPLATE/--bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md similarity index 90% rename from .github/ISSUE_TEMPLATE/--bug-report.md rename to .github/ISSUE_TEMPLATE/bug-report.md index 6dc6e26427..3f7d83a407 100644 --- a/.github/ISSUE_TEMPLATE/--bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -1,5 +1,5 @@ --- -name: "\U0001F41BBug report" +name: "🐛 Bug report" about: Create a report to help us improve title: '' labels: bug @@ -9,8 +9,8 @@ assignees: '' Before submitting a bug report, please be aware that your issue **must be reproducible** with all of the following, otherwise it is non-actionable, and we can not help you: - **Current repo**: run `git fetch && git status -uno` to check and `git pull` to update repo - - **Common dataset**: coco2017.data or coco64.data - - **Common environment**: Colab, Google Cloud, or Docker image. See https://github.com/ultralytics/yolov3#reproduce-our-environment + - **Common dataset**: coco.yaml or coco128.yaml + - **Common environment**: Colab, Google Cloud, or Docker image. See https://github.com/ultralytics/yolov3#environments If this is a custom dataset/training question you **must include** your `train*.jpg`, `test*.jpg` and `results.png` figures, or we can not help you. You can generate these with `utils.plot_results()`. diff --git a/.github/ISSUE_TEMPLATE/--feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md similarity index 95% rename from .github/ISSUE_TEMPLATE/--feature-request.md rename to .github/ISSUE_TEMPLATE/feature-request.md index b16020d201..87db3eacbf 100644 --- a/.github/ISSUE_TEMPLATE/--feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -1,5 +1,5 @@ --- -name: "\U0001F680Feature request" +name: "🚀 Feature request" about: Suggest an idea for this project title: '' labels: enhancement diff --git a/.github/ISSUE_TEMPLATE/-question.md b/.github/ISSUE_TEMPLATE/question.md similarity index 100% rename from .github/ISSUE_TEMPLATE/-question.md rename to .github/ISSUE_TEMPLATE/question.md diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml new file mode 100644 index 0000000000..69a5f239a5 --- /dev/null +++ b/.github/workflows/ci-testing.yml @@ -0,0 +1,76 @@ +name: CI CPU testing + +on: # https://help.github.com/en/actions/reference/events-that-trigger-workflows + push: + pull_request: + schedule: + - cron: "0 0 * * *" + +jobs: + cpu-tests: + + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: [3.8] + model: ['yolov3-tiny'] # models to test + + # Timeout: https://stackoverflow.com/a/59076067/4521646 + timeout-minutes: 50 + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + # Note: This uses an internal pip API and may not always work + # https://github.com/actions/cache/blob/master/examples.md#multiple-oss-in-a-workflow + - name: Get pip cache + id: pip-cache + run: | + python -c "from pip._internal.locations import USER_CACHE_DIR; print('::set-output name=dir::' + USER_CACHE_DIR)" + + - name: Cache pip + uses: actions/cache@v1 + with: + path: ${{ steps.pip-cache.outputs.dir }} + key: ${{ runner.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('requirements.txt') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.python-version }}-pip- + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -qr requirements.txt -f https://download.pytorch.org/whl/cpu/torch_stable.html + pip install -q onnx + python --version + pip --version + pip list + shell: bash + + - name: Download data + run: | + # curl -L -o tmp.zip https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip + # unzip -q tmp.zip -d ../ + # rm tmp.zip + + - name: Tests workflow + run: | + # export PYTHONPATH="$PWD" # to run '$ python *.py' files in subdirectories + di=cpu # inference devices # define device + + # train + python train.py --img 256 --batch 8 --weights weights/${{ matrix.model }}.pt --cfg models/${{ matrix.model }}.yaml --epochs 1 --device $di + # detect + python detect.py --weights weights/${{ matrix.model }}.pt --device $di + python detect.py --weights runs/train/exp/weights/last.pt --device $di + # test + python test.py --img 256 --batch 8 --weights weights/${{ matrix.model }}.pt --device $di + python test.py --img 256 --batch 8 --weights runs/train/exp/weights/last.pt --device $di + + python models/yolo.py --cfg models/${{ matrix.model }}.yaml # inspect + python models/export.py --img 256 --batch 1 --weights weights/${{ matrix.model }}.pt # export + shell: bash diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index b0f9c58fd6..2cbd208084 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -23,20 +23,33 @@ jobs: - Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ -Bruce Lee issue-message: | - Hello @${{ github.actor }}, thank you for your interest in our work! Ultralytics has open-sourced YOLOv5 at https://github.com/ultralytics/yolov5, featuring faster, lighter and more accurate object detection. YOLOv5 is recommended for all new projects. + Hello @${{ github.actor }}, thank you for your interest in 🚀 YOLOv3! Please visit our ⭐️ [Tutorials](https://github.com/ultralytics/yolov3/wiki#tutorials) to get started, where you can find quickstart guides for simple tasks like [Custom Data Training](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) all the way to advanced concepts like [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607). - - -

- + If this is a 🐛 Bug Report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you. - To continue with this repo, please visit our [Custom Training Tutorial](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) to get started, and see our [Google Colab Notebook](https://github.com/ultralytics/yolov3/blob/master/tutorial.ipynb), [Docker Image](https://hub.docker.com/r/ultralytics/yolov3), and [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) for example environments. + If this is a custom training ❓ Question, please provide as much information as possible, including dataset images, training logs, screenshots, and a public link to online [W&B logging](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data#visualize) if available. - If this is a bug report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you. + For business inquiries or professional support requests please visit https://www.ultralytics.com or email Glenn Jocher at glenn.jocher@ultralytics.com. - If this is a custom model or data training question, please note that Ultralytics does **not** provide free personal support. As a leader in vision ML and AI, we do offer professional consulting, from simple expert advice up to delivery of fully customized, end-to-end production solutions for our clients, such as: - - **Cloud-based AI** systems operating on **hundreds of HD video streams in realtime.** - - **Edge AI** integrated into custom iOS and Android apps for realtime **30 FPS video inference.** - - **Custom data training**, hyperparameter evolution, and model exportation to any destination. + ## Requirements - For more information please visit https://www.ultralytics.com. + Python 3.8 or later with all [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) dependencies installed, including `torch>=1.7`. To install run: + ```bash + $ pip install -r requirements.txt + ``` + + ## Environments + + YOLOv3 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): + + - **Google Colab Notebook** with free GPU: Open In Colab + - **Kaggle Notebook** with free GPU: [https://www.kaggle.com/ultralytics/yolov3](https://www.kaggle.com/ultralytics/yolov3) + - **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) + - **Docker Image** https://hub.docker.com/r/ultralytics/yolov3. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) ![Docker Pulls](https://img.shields.io/docker/pulls/ultralytics/yolov3?logo=docker) + + ## Status + + ![CI CPU testing](https://github.com/ultralytics/yolov3/workflows/CI%20CPU%20testing/badge.svg) + + If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 training ([train.py](https://github.com/ultralytics/yolov3/blob/master/train.py)), testing ([test.py](https://github.com/ultralytics/yolov3/blob/master/test.py)), inference ([detect.py](https://github.com/ultralytics/yolov3/blob/master/detect.py)) and export ([export.py](https://github.com/ultralytics/yolov3/blob/master/models/export.py)) on MacOS, Windows, and Ubuntu every 24 hours and on every commit. + diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml new file mode 100644 index 0000000000..e86c57744b --- /dev/null +++ b/.github/workflows/rebase.yml @@ -0,0 +1,21 @@ +name: Automatic Rebase +# https://github.com/marketplace/actions/automatic-rebase + +on: + issue_comment: + types: [created] + +jobs: + rebase: + name: Rebase + if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') + runs-on: ubuntu-latest + steps: + - name: Checkout the latest code + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Automatic Rebase + uses: cirrus-actions/rebase@1.3.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index f71aead99a..d4126b8b46 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -15,3 +15,4 @@ jobs: days-before-stale: 30 days-before-close: 5 exempt-issue-labels: 'documentation,tutorial' + operations-per-run: 100 # The maximum number of operations per run, used to control rate limiting. diff --git a/Dockerfile b/Dockerfile index f21cf49e9d..e514893da6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,11 @@ # Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch -FROM nvcr.io/nvidia/pytorch:20.03-py3 - -# Install dependencies (pip or conda) -RUN pip install -U gsutil -# RUN pip install -U -r requirements.txt -# RUN conda update -n base -c defaults conda -# RUN conda install -y -c anaconda future numpy opencv matplotlib tqdm pillow -# RUN conda install -y -c conda-forge scikit-image tensorboard pycocotools - -## Install OpenCV with Gstreamer support -#WORKDIR /usr/src -#RUN pip uninstall -y opencv-python -#RUN apt-get update -#RUN apt-get install -y gstreamer1.0-tools gstreamer1.0-python3-dbg-plugin-loader libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev -#RUN git clone https://github.com/opencv/opencv.git && cd opencv && git checkout 4.1.1 && mkdir build -#RUN git clone https://github.com/opencv/opencv_contrib.git && cd opencv_contrib && git checkout 4.1.1 -#RUN cd opencv/build && cmake ../ \ -# -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \ -# -D BUILD_OPENCV_PYTHON3=ON \ -# -D PYTHON3_EXECUTABLE=/opt/conda/bin/python \ -# -D PYTHON3_INCLUDE_PATH=/opt/conda/include/python3.6m \ -# -D PYTHON3_LIBRARIES=/opt/conda/lib/python3.6/site-packages \ -# -D WITH_GSTREAMER=ON \ -# -D WITH_FFMPEG=OFF \ -# && make && make install && ldconfig -#RUN cd /usr/local/lib/python3.6/site-packages/cv2/python-3.6/ && mv cv2.cpython-36m-x86_64-linux-gnu.so cv2.so -#RUN cd /opt/conda/lib/python3.6/site-packages/ && ln -s /usr/local/lib/python3.6/site-packages/cv2/python-3.6/cv2.so cv2.so -#RUN python3 -c "import cv2; print(cv2.getBuildInformation())" +FROM nvcr.io/nvidia/pytorch:20.10-py3 + +# Install dependencies +RUN pip install --upgrade pip +# COPY requirements.txt . +# RUN pip install -r requirements.txt +RUN pip install gsutil # Create working directory RUN mkdir -p /usr/src/app @@ -38,25 +17,36 @@ COPY . /usr/src/app # Copy weights #RUN python3 -c "from models import *; \ #attempt_download('weights/yolov3.pt'); \ -#attempt_download('weights/yolov3-spp.pt')" +#attempt_download('weights/yolov3-spp.pt'); \ +#attempt_download('weights/yolov3-tiny.pt')" # --------------------------------------------------- Extras Below --------------------------------------------------- # Build and Push -# t=ultralytics/yolov3:v0 && sudo docker build -t $t . && sudo docker push $t +# t=ultralytics/yolov3:latest && sudo docker build -t $t . && sudo docker push $t +# for v in {300..303}; do t=ultralytics/coco:v$v && sudo docker build -t $t . && sudo docker push $t; done -# Run -# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host $t bash +# Pull and Run +# t=ultralytics/yolov3:latest && sudo docker pull $t && sudo docker run -it --ipc=host $t # Pull and Run with local directory access -# t=ultralytics/yolov3:v0 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash +# t=ultralytics/yolov3:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all -v "$(pwd)"/coco:/usr/src/coco $t # Kill all -# sudo docker kill "$(sudo docker ps -q)" +# sudo docker kill $(sudo docker ps -q) # Kill all image-based -# sudo docker kill $(sudo docker ps -a -q --filter ancestor=ultralytics/yolov3:v0) +# sudo docker kill $(sudo docker ps -a -q --filter ancestor=ultralytics/yolov3:latest) + +# Bash into running container +# sudo docker container exec -it ba65811811ab bash + +# Bash into stopped container +# sudo docker commit 092b16b25c5b usr/resume && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco --entrypoint=sh usr/resume + +# Send weights to GCP +# python -c "from utils.general import *; strip_optimizer('runs/train/exp0_*/weights/best.pt', 'tmp.pt')" && gsutil cp tmp.pt gs://*.pt -# Run bash for loop -# sudo docker run --gpus all --ipc=host ultralytics/yolov3:v0 while true; do python3 train.py --evolve; done +# Clean up +# docker system prune -a --volumes diff --git a/README.md b/README.md index 4051eb8a52..e8e05e11c3 100755 --- a/README.md +++ b/README.md @@ -1,163 +1,130 @@ - +   -This repo contains Ultralytics inference and training code for YOLOv3 in PyTorch. The code works on Linux, MacOS and Windows. Credit to Joseph Redmon for YOLO https://pjreddie.com/darknet/yolo/. +![CI CPU testing](https://github.com/ultralytics/yolov3/workflows/CI%20CPU%20testing/badge.svg) - -## Requirements - -Python 3.8 or later with all [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) dependencies installed, including `torch>=1.6`. To install run: +BRANCH NOTICE: The [ultralytics/yolov3](https://github.com/ultralytics/yolov3) repository is now divided into two branches: +* [Master branch](https://github.com/ultralytics/yolov3/tree/master): Forward-compatible with all [YOLOv5](https://github.com/ultralytics/yolov5) models and methods (recommended). ```bash -$ pip install -r requirements.txt +$ git clone https://github.com/ultralytics/yolov3 # master branch (default) +``` +* [Archive branch](https://github.com/ultralytics/yolov3/tree/archive): Backwards-compatible with original [darknet](https://pjreddie.com/darknet/) *.cfg models (not recommended). +```bash +$ git clone -b archive https://github.com/ultralytics/yolov3 # archive branch ``` +** GPU Speed measures end-to-end time per image averaged over 5000 COCO val2017 images using a V100 GPU with batch size 32, and includes image preprocessing, PyTorch FP16 inference, postprocessing and NMS. EfficientDet data from [google/automl](https://github.com/google/automl) at batch size 8. -## Tutorials - -* [Notebook](https://github.com/ultralytics/yolov3/blob/master/tutorial.ipynb) Open In Colab -* [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) << highly recommended -* [GCP Quickstart](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) -* [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) ![Docker Pulls](https://img.shields.io/docker/pulls/ultralytics/yolov3?logo=docker) -* [A TensorRT Implementation of YOLOv3 and YOLOv4](https://github.com/wang-xinyu/tensorrtx/tree/master/yolov3-spp) - - -## Training -**Start Training:** `python3 train.py` to begin training after downloading COCO data with `data/get_coco2017.sh`. Each epoch trains on 117,263 images from the train and validate COCO sets, and tests on 5000 images from the COCO validate set. +## Pretrained Checkpoints -**Resume Training:** `python3 train.py --resume` to resume training from `weights/last.pt`. +| Model | APval | APtest | AP50 | SpeedGPU | FPSGPU || params | FLOPS | +|---------- |------ |------ |------ | -------- | ------| ------ |------ | :------: | +| [YOLOv3](https://github.com/ultralytics/yolov3/releases) | 43.3 | 43.3 | 63.0 | 4.8ms | 208 || 61.9M | 156.4B +| [YOLOv3-SPP](https://github.com/ultralytics/yolov3/releases) | **44.3** | **44.3** | **64.6** | 4.9ms | 204 || 63.0M | 157.0B +| [YOLOv3-tiny](https://github.com/ultralytics/yolov3/releases) | 17.6 | 34.9 | 34.9 | **1.7ms** | **588** || 8.9M | 13.3B -**Plot Training:** `from utils import utils; utils.plot_results()` +** APtest denotes COCO [test-dev2017](http://cocodataset.org/#upload) server results, all other AP results denote val2017 accuracy. +** All AP numbers are for single-model single-scale without ensemble or TTA. **Reproduce mAP** by `python test.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` +** SpeedGPU averaged over 5000 COCO val2017 images using a GCP [n1-standard-16](https://cloud.google.com/compute/docs/machine-types#n1_standard_machine_types) V100 instance, and includes image preprocessing, FP16 inference, postprocessing and NMS. NMS is 1-2ms/img. **Reproduce speed** by `python test.py --data coco.yaml --img 640 --conf 0.25 --iou 0.45` +** All checkpoints are trained to 300 epochs with default settings and hyperparameters (no autoaugmentation). +** Test Time Augmentation ([TTA](https://github.com/ultralytics/yolov5/issues/303)) runs at 3 image sizes. **Reproduce TTA** by `python test.py --data coco.yaml --img 832 --iou 0.65 --augment` - +## Requirements +Python 3.8 or later with all [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) dependencies installed, including `torch>=1.7`. To install run: +```bash +$ pip install -r requirements.txt +``` -### Image Augmentation -`datasets.py` applies OpenCV-powered (https://opencv.org/) augmentation to the input image. We use a **mosaic dataloader** to increase image variability during training. +## Tutorials - +* [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data)  🚀 RECOMMENDED +* [Weights & Biases Logging](https://github.com/ultralytics/yolov5/issues/1289)  🌟 NEW +* [Multi-GPU Training](https://github.com/ultralytics/yolov5/issues/475) +* [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36)  ⭐ NEW +* [ONNX and TorchScript Export](https://github.com/ultralytics/yolov5/issues/251) +* [Test-Time Augmentation (TTA)](https://github.com/ultralytics/yolov5/issues/303) +* [Model Ensembling](https://github.com/ultralytics/yolov5/issues/318) +* [Model Pruning/Sparsity](https://github.com/ultralytics/yolov5/issues/304) +* [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607) +* [Transfer Learning with Frozen Layers](https://github.com/ultralytics/yolov5/issues/1314)  ⭐ NEW +* [TensorRT Deployment](https://github.com/wang-xinyu/tensorrtx) -### Speed +## Environments -https://cloud.google.com/deep-learning-vm/ -**Machine type:** preemptible [n1-standard-8](https://cloud.google.com/compute/docs/machine-types) (8 vCPUs, 30 GB memory) -**CPU platform:** Intel Skylake -**GPUs:** K80 ($0.14/hr), T4 ($0.11/hr), V100 ($0.74/hr) CUDA with [Nvidia Apex](https://github.com/NVIDIA/apex) FP16/32 -**HDD:** 300 GB SSD -**Dataset:** COCO train 2014 (117,263 images) -**Model:** `yolov3-spp.cfg` -**Command:** `python3 train.py --data coco2017.data --img 416 --batch 32` +YOLOv3 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): -GPU | n | `--batch-size` | img/s | epoch
time | epoch
cost ---- |--- |--- |--- |--- |--- -K80 |1| 32 x 2 | 11 | 175 min | $0.41 -T4 |1
2| 32 x 2
64 x 1 | 41
61 | 48 min
32 min | $0.09
$0.11 -V100 |1
2| 32 x 2
64 x 1 | 122
**178** | 16 min
**11 min** | **$0.21**
$0.28 -2080Ti |1
2| 32 x 2
64 x 1 | 81
140 | 24 min
14 min | -
- +- **Google Colab Notebook** with free GPU: Open In Colab +- **Kaggle Notebook** with free GPU: [https://www.kaggle.com/ultralytics/yolov3](https://www.kaggle.com/ultralytics/yolov3) +- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) +- **Docker Image** https://hub.docker.com/r/ultralytics/yolov3. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) ![Docker Pulls](https://img.shields.io/docker/pulls/ultralytics/yolov3?logo=docker) ## Inference +detect.py runs inference on a variety of sources, downloading models automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases) and saving results to `runs/detect`. ```bash -python3 detect.py --source ... +$ python detect.py --source 0 # webcam + file.jpg # image + file.mp4 # video + path/ # directory + path/*.jpg # glob + rtsp://170.93.143.139/rtplive/470011e600ef003a004ee33696235daa # rtsp stream + rtmp://192.168.1.105/live/test # rtmp stream + http://112.50.243.8/PLTV/88888888/224/3221225900/1.m3u8 # http stream ``` -- Image: `--source file.jpg` -- Video: `--source file.mp4` -- Directory: `--source dir/` -- Webcam: `--source 0` -- RTSP stream: `--source rtsp://170.93.143.139/rtplive/470011e600ef003a004ee33696235daa` -- HTTP stream: `--source http://112.50.243.8/PLTV/88888888/224/3221225900/1.m3u8` - -**YOLOv3:** `python3 detect.py --cfg cfg/yolov3.cfg --weights yolov3.pt` - - -**YOLOv3-tiny:** `python3 detect.py --cfg cfg/yolov3-tiny.cfg --weights yolov3-tiny.pt` - - -**YOLOv3-SPP:** `python3 detect.py --cfg cfg/yolov3-spp.cfg --weights yolov3-spp.pt` - - - -## Pretrained Checkpoints - -Download from: [https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0](https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0) - - -## Darknet Conversion - +To run inference on example images in `data/images`: ```bash -$ git clone https://github.com/ultralytics/yolov3 && cd yolov3 +$ python detect.py --source data/images --weights yolov3.pt --conf 0.25 + +Namespace(agnostic_nms=False, augment=False, classes=None, conf_thres=0.25, device='', exist_ok=False, img_size=640, iou_thres=0.45, name='exp', project='runs/detect', save_conf=False, save_txt=False, source='data/images/', update=False, view_img=False, weights=['yolov3.pt']) +Using torch 1.7.0+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16130MB) -# convert darknet cfg/weights to pytorch model -$ python3 -c "from models import *; convert('cfg/yolov3-spp.cfg', 'weights/yolov3-spp.weights')" -Success: converted 'weights/yolov3-spp.weights' to 'weights/yolov3-spp.pt' +Downloading https://github.com/ultralytics/yolov3/releases/download/v1.0/yolov3.pt to yolov3.pt... 100% 118M/118M [00:05<00:00, 24.2MB/s] -# convert cfg/pytorch model to darknet weights -$ python3 -c "from models import *; convert('cfg/yolov3-spp.cfg', 'weights/yolov3-spp.pt')" -Success: converted 'weights/yolov3-spp.pt' to 'weights/yolov3-spp.weights' +Fusing layers... +Model Summary: 261 layers, 61922845 parameters, 0 gradients +image 1/2 /content/yolov3/data/images/bus.jpg: 640x480 4 persons, 1 buss, Done. (0.014s) +image 2/2 /content/yolov3/data/images/zidane.jpg: 384x640 2 persons, 3 ties, Done. (0.014s) +Results saved to runs/detect/exp +Done. (0.133s) ``` + +### PyTorch Hub -## mAP +To run **batched inference** with YOLO3 and [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36): +```python +import torch +from PIL import Image - |Size |COCO mAP
@0.5...0.95 |COCO mAP
@0.5 ---- | --- | --- | --- -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |320 |14.0
28.7
30.5
**37.7** |29.1
51.8
52.3
**56.8** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |416 |16.0
31.2
33.9
**41.2** |33.0
55.4
56.9
**60.6** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |512 |16.6
32.7
35.6
**42.6** |34.9
57.7
59.5
**62.4** -YOLOv3-tiny
YOLOv3
YOLOv3-SPP
**[YOLOv3-SPP-ultralytics](https://drive.google.com/open?id=1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4)** |608 |16.6
33.1
37.0
**43.1** |35.4
58.2
60.7
**62.8** +# Model +model = torch.hub.load('ultralytics/yolov3', 'yolov3', pretrained=True).autoshape() # for PIL/cv2/np inputs and NMS -- mAP@0.5 run at `--iou-thr 0.5`, mAP@0.5...0.95 run at `--iou-thr 0.7` -- Darknet results: https://arxiv.org/abs/1804.02767 +# Images +img1 = Image.open('zidane.jpg') +img2 = Image.open('bus.jpg') +imgs = [img1, img2] # batched list of images -```bash -$ python3 test.py --cfg yolov3-spp.cfg --weights yolov3-spp-ultralytics.pt --img 640 --augment - -Namespace(augment=True, batch_size=16, cfg='cfg/yolov3-spp.cfg', conf_thres=0.001, data='coco2014.data', device='', img_size=640, iou_thres=0.6, save_json=True, single_cls=False, task='test', weights='weight -Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memory=16130MB) - - Class Images Targets P R mAP@0.5 F1: 100%|█████████| 313/313 [03:00<00:00, 1.74it/s] - all 5e+03 3.51e+04 0.375 0.743 0.64 0.492 - - Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.456 - Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.647 - Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.496 - Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.263 - Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.501 - Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.596 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.361 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.597 - Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.666 - Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.492 - Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.719 - Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.810 - -Speed: 17.5/2.3/19.9 ms inference/NMS/total per 640x640 image at batch-size 16 +# Inference +prediction = model(imgs, size=640) # includes NMS ``` - -## Reproduce Our Results +## Training -Run commands below. Training takes about one week on a 2080Ti per model. +Download [COCO](https://github.com/ultralytics/yolov3/blob/master/data/scripts/get_coco.sh) and run command below. Training times for YOLOv3/YOLOv3-SPP/YOLOv3-tiny are 6/6/2 days on a single V100 (multi-GPU times faster). Use the largest `--batch-size` your GPU allows (batch sizes shown for 16 GB devices). ```bash -$ python train.py --data coco2014.data --weights '' --batch-size 16 --cfg yolov3-spp.cfg -$ python train.py --data coco2014.data --weights '' --batch-size 32 --cfg yolov3-tiny.cfg +$ python train.py --data coco.yaml --cfg yolov3.yaml --weights '' --batch-size 24 + yolov3-spp.yaml 24 + yolov3-tiny.yaml 64 ``` - - - -## Reproduce Our Environment - -To access an up-to-date working environment (with all dependencies including CUDA/CUDNN, Python and PyTorch preinstalled), consider a: - -- **GCP** Deep Learning VM with $300 free credit offer: See our [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) -- **Google Colab Notebook** with 12 hours of free GPU time. Open In Colab -- **Docker Image** https://hub.docker.com/r/ultralytics/yolov3. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) ![Docker Pulls](https://img.shields.io/docker/pulls/ultralytics/yolov3?logo=docker) + ## Citation diff --git a/cfg/cd53s-yolov3.cfg b/cfg/cd53s-yolov3.cfg deleted file mode 100644 index 431a2a081e..0000000000 --- a/cfg/cd53s-yolov3.cfg +++ /dev/null @@ -1,1033 +0,0 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=64 -subdivisions=8 -width=512 -height=512 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -#cutmix=1 -mosaic=1 - -#23:104x104 54:52x52 85:26x26 104:13x13 for 416 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -#[convolutional] -#batch_normalize=1 -#filters=64 -#size=1 -#stride=1 -#pad=1 -#activation=leaky - -#[route] -#layers = -2 - -#[convolutional] -#batch_normalize=1 -#filters=64 -#size=1 -#stride=1 -#pad=1 -#activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -#[convolutional] -#batch_normalize=1 -#filters=64 -#size=1 -#stride=1 -#pad=1 -#activation=leaky - -#[route] -#layers = -1,-7 - -#[convolutional] -#batch_normalize=1 -#filters=64 -#size=1 -#stride=1 -#pad=1 -#activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-10 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-28 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-28 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-16 - -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=leaky - -########################## - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 79 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.1 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 48 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.2 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 diff --git a/cfg/cd53s.cfg b/cfg/cd53s.cfg deleted file mode 100644 index 221b13bb75..0000000000 --- a/cfg/cd53s.cfg +++ /dev/null @@ -1,1155 +0,0 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=64 -subdivisions=8 -width=512 -height=512 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -#cutmix=1 -mosaic=1 - -#23:104x104 54:52x52 85:26x26 104:13x13 for 416 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -#[convolutional] -#batch_normalize=1 -#filters=64 -#size=1 -#stride=1 -#pad=1 -#activation=leaky - -#[route] -#layers = -2 - -#[convolutional] -#batch_normalize=1 -#filters=64 -#size=1 -#stride=1 -#pad=1 -#activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -#[convolutional] -#batch_normalize=1 -#filters=64 -#size=1 -#stride=1 -#pad=1 -#activation=leaky - -#[route] -#layers = -1,-7 - -#[convolutional] -#batch_normalize=1 -#filters=64 -#size=1 -#stride=1 -#pad=1 -#activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-10 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-28 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-28 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-16 - -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=leaky - -########################## - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = 79 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = 48 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -########################## - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=256 -activation=leaky - -[route] -layers = -1, -16 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=512 -activation=leaky - -[route] -layers = -1, -37 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 diff --git a/cfg/csresnext50-panet-spp.cfg b/cfg/csresnext50-panet-spp.cfg deleted file mode 100644 index 4cff3c37c6..0000000000 --- a/cfg/csresnext50-panet-spp.cfg +++ /dev/null @@ -1,1018 +0,0 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=416 -height=416 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -#19:104x104 38:52x52 65:26x26 80:13x13 for 416 - -[convolutional] -batch_normalize=1 -filters=64 -size=7 -stride=2 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -# 1-1 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -groups=32 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=linear - -[shortcut] -from=-4 -activation=leaky - -# 1-2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -groups=32 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=linear - -[shortcut] -from=-4 -activation=leaky - -# 1-3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -groups=32 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=linear - -[shortcut] -from=-4 -activation=leaky - -# 1-T - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-16 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -groups=32 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=linear - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=linear - -# 2-1 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -groups=32 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=linear - -[shortcut] -from=-4 -activation=leaky - -# 2-2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -groups=32 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=linear - -[shortcut] -from=-4 -activation=leaky - -# 2-3 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -groups=32 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=linear - -[shortcut] -from=-4 -activation=leaky - -# 2-T - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-16 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -groups=32 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=linear - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=linear - -# 3-1 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -groups=32 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=linear - -[shortcut] -from=-4 -activation=leaky - -# 3-2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -groups=32 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=linear - -[shortcut] -from=-4 -activation=leaky - -# 3-3 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -groups=32 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=linear - -[shortcut] -from=-4 -activation=leaky - -# 3-4 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -groups=32 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=linear - -[shortcut] -from=-4 -activation=leaky - -# 3-5 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -groups=32 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=linear - -[shortcut] -from=-4 -activation=leaky - -# 3-T - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-24 - -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -groups=32 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=leaky - -# 4-1 - -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -groups=32 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=linear - -[shortcut] -from=-4 -activation=leaky - -# 4-2 - -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -groups=32 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=linear - -[shortcut] -from=-4 -activation=leaky - -# 4-T - -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-12 - -[convolutional] -batch_normalize=1 -filters=2048 -size=1 -stride=1 -pad=1 -activation=leaky - -########################## - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = 65 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = 38 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -########################## - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=256 -activation=leaky - -[route] -layers = -1, -16 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=512 -activation=leaky - -[route] -layers = -1, -37 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3-1cls.cfg b/cfg/yolov3-1cls.cfg deleted file mode 100755 index 00bad5d009..0000000000 --- a/cfg/yolov3-1cls.cfg +++ /dev/null @@ -1,788 +0,0 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=16 -subdivisions=1 -width=416 -height=416 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=18 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=1 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=18 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=1 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=18 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=1 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3-asff.cfg b/cfg/yolov3-asff.cfg deleted file mode 100644 index 343e19fa2f..0000000000 --- a/cfg/yolov3-asff.cfg +++ /dev/null @@ -1,804 +0,0 @@ -# Generated by Glenn Jocher (glenn.jocher@ultralytics.com) for https://github.com/ultralytics/yolov3 -# def kmean_anchors(path='../coco/train2017.txt', n=12, img_size=(320, 640)): # from utils.utils import *; kmean_anchors() -# Evolving anchors: 100%|██████████| 1000/1000 [41:15<00:00, 2.48s/it] -# 0.20 iou_thr: 0.992 best possible recall, 4.25 anchors > thr -# kmeans anchors (n=12, img_size=(320, 640), IoU=0.005/0.184/0.634-min/mean/best): 6,9, 15,16, 17,35, 37,26, 36,67, 63,42, 57,100, 121,81, 112,169, 241,158, 195,310, 426,359 - -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -# SPP -------------------------------------------------------------------------- -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -# SPP -------------------------------------------------------------------------- - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=258 -activation=linear - -# YOLO ------------------------------------------------------------------------- - -[route] -layers = -3 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=258 -activation=linear - -# YOLO ------------------------------------------------------------------------- - -[route] -layers = -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=258 -activation=linear - -[yolo] -from=88,99,110 -mask = 6,7,8 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 - -[yolo] -from=88,99,110 -mask = 3,4,5 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 - -[yolo] -from=88,99,110 -mask = 0,1,2 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 \ No newline at end of file diff --git a/cfg/yolov3-spp-1cls.cfg b/cfg/yolov3-spp-1cls.cfg deleted file mode 100644 index 88edcffb51..0000000000 --- a/cfg/yolov3-spp-1cls.cfg +++ /dev/null @@ -1,821 +0,0 @@ -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=100 -max_batches = 5000 -policy=steps -steps=4000,4500 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=18 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=1 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=18 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=1 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=18 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=1 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3-spp-3cls.cfg b/cfg/yolov3-spp-3cls.cfg deleted file mode 100644 index b5d4bdf28d..0000000000 --- a/cfg/yolov3-spp-3cls.cfg +++ /dev/null @@ -1,821 +0,0 @@ -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=100 -max_batches = 5000 -policy=steps -steps=4000,4500 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=24 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=3 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=24 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=3 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=24 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=3 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3-spp-matrix.cfg b/cfg/yolov3-spp-matrix.cfg deleted file mode 100644 index 14befdba52..0000000000 --- a/cfg/yolov3-spp-matrix.cfg +++ /dev/null @@ -1,1115 +0,0 @@ -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=416 -height=416 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -# 89 -[yolo] -mask = 6,7,8 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 -classes=80 -num=27 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -# 101 -[yolo] -mask = 3,4,5 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 -classes=80 -num=27 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -# 113 -[yolo] -mask = 0,1,2 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 -classes=80 -num=27 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - -################## - -[route] -layers = 110 - -# 115 -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -# 116 -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride_x=1 -stride_y=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 9,10,11 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 -classes=80 -num=27 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = 110 - -# 121 -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -# 122 -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride_x=2 -stride_y=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 12,13,14 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 -classes=80 -num=27 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - -################## - -[route] -layers = 98 - -[convolutional] -share_index=115 -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -share_index=116 -batch_normalize=1 -filters=128 -size=1 -stride_x=1 -stride_y=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 15,16,17 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 -classes=80 -num=27 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = 98 - -[convolutional] -share_index=121 -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -share_index=122 -batch_normalize=1 -filters=128 -size=1 -stride_x=2 -stride_y=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 18,19,20 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 -classes=80 -num=27 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - -################## - -[route] -layers = 86 - -[convolutional] -share_index=115 -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -share_index=116 -batch_normalize=1 -filters=128 -size=1 -stride_x=1 -stride_y=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 21,22,23 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 -classes=80 -num=27 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = 86 - -[convolutional] -share_index=121 -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -share_index=122 -batch_normalize=1 -filters=128 -size=1 -stride_x=2 -stride_y=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 24,25,26 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326, 10,7, 16,15, 33,12, 5,13, 8,30, 17,23, 30,31, 62,23, 59,60, 15,61, 31,45, 30,119, 116,45, 156,99, 373,163, 58,90, 78,198, 187,326 -classes=80 -num=27 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 \ No newline at end of file diff --git a/cfg/yolov3-spp-pan-scale.cfg b/cfg/yolov3-spp-pan-scale.cfg deleted file mode 100644 index d95bd52b24..0000000000 --- a/cfg/yolov3-spp-pan-scale.cfg +++ /dev/null @@ -1,938 +0,0 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=64 -subdivisions=32 -width=544 -height=544 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - - -learning_rate=0.001 -burn_in=1000 -max_batches = 10000 - -policy=steps -steps=8000,9000 -scales=.1,.1 - -#policy=sgdr -#sgdr_cycle=1000 -#sgdr_mult=2 -#steps=4000,6000,8000,9000 -#scales=1, 1, 0.1, 0.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - - -########### to [yolo-3] - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - - -########### to [yolo-2] - - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - - - -########### to [yolo-1] - - -########### features of different layers - - -[route] -layers=1 - -[reorg3d] -stride=2 - -[route] -layers=5,-1 - -[reorg3d] -stride=2 - -[route] -layers=12,-1 - -[reorg3d] -stride=2 - -[route] -layers=37,-1 - -[reorg3d] -stride=2 - -[route] -layers=62,-1 - - - -########### [yolo-1] - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=4 - -[route] -layers = -1,-12 - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - - -[yolo] -mask = 0,1,2,3 -anchors = 8,8, 10,13, 16,30, 33,23, 32,32, 30,61, 62,45, 64,64, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -scale_x_y = 1.05 -random=0 - - - - -########### [yolo-2] - - -[route] -layers = -7 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1,-28 - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - - -[yolo] -mask = 4,5,6,7 -anchors = 8,8, 10,13, 16,30, 33,23, 32,32, 30,61, 62,45, 64,64, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -scale_x_y = 1.1 -random=0 - - - -########### [yolo-3] - -[route] -layers = -14 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-43 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - - -[yolo] -mask = 8,9,10,11 -anchors = 8,8, 10,13, 16,30, 33,23, 32,32, 30,61, 62,45, 59,119, 80,80, 116,90, 156,198, 373,326 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -scale_x_y = 1.2 -random=0 diff --git a/cfg/yolov3-spp.cfg b/cfg/yolov3-spp.cfg deleted file mode 100644 index bb4e893bf6..0000000000 --- a/cfg/yolov3-spp.cfg +++ /dev/null @@ -1,821 +0,0 @@ -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3-spp3.cfg b/cfg/yolov3-spp3.cfg deleted file mode 100644 index ea601054fd..0000000000 --- a/cfg/yolov3-spp3.cfg +++ /dev/null @@ -1,870 +0,0 @@ -[net] -# Testing -batch=1 -subdivisions=1 -# Training -# batch=64 -# subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 120200 -policy=steps -steps=70000,100000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 - -### End SPP ### - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3-tiny-1cls.cfg b/cfg/yolov3-tiny-1cls.cfg deleted file mode 100644 index b441eae2aa..0000000000 --- a/cfg/yolov3-tiny-1cls.cfg +++ /dev/null @@ -1,182 +0,0 @@ -[net] -# Testing -batch=1 -subdivisions=1 -# Training -# batch=64 -# subdivisions=2 -width=416 -height=416 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=16 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=1 - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -########### - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=18 -activation=linear - - - -[yolo] -mask = 3,4,5 -anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 -classes=1 -num=6 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 8 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=18 -activation=linear - -[yolo] -mask = 0,1,2 -anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 -classes=1 -num=6 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3-tiny-3cls.cfg b/cfg/yolov3-tiny-3cls.cfg deleted file mode 100644 index 97c3720f2f..0000000000 --- a/cfg/yolov3-tiny-3cls.cfg +++ /dev/null @@ -1,182 +0,0 @@ -[net] -# Testing -batch=1 -subdivisions=1 -# Training -# batch=64 -# subdivisions=2 -width=416 -height=416 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=16 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=1 - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -########### - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=24 -activation=linear - - - -[yolo] -mask = 3,4,5 -anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 -classes=3 -num=6 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 8 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=24 -activation=linear - -[yolo] -mask = 0,1,2 -anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 -classes=3 -num=6 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3-tiny.cfg b/cfg/yolov3-tiny.cfg deleted file mode 100644 index 42c0fcf919..0000000000 --- a/cfg/yolov3-tiny.cfg +++ /dev/null @@ -1,182 +0,0 @@ -[net] -# Testing -batch=1 -subdivisions=1 -# Training -# batch=64 -# subdivisions=2 -width=416 -height=416 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=16 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=1 - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -########### - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - - -[yolo] -mask = 3,4,5 -anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 -classes=80 -num=6 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 8 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 1,2,3 -anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 -classes=80 -num=6 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3-tiny3-1cls.cfg b/cfg/yolov3-tiny3-1cls.cfg deleted file mode 100644 index bd5fd0baba..0000000000 --- a/cfg/yolov3-tiny3-1cls.cfg +++ /dev/null @@ -1,227 +0,0 @@ -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 200000 -policy=steps -steps=180000,190000 -scales=.1,.1 - - -[convolutional] -batch_normalize=1 -filters=16 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=1 - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -########### - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=18 -activation=linear - - - -[yolo] -mask = 6,7,8 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=1 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 8 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=18 -activation=linear - -[yolo] -mask = 3,4,5 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=1 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 6 - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=18 -activation=linear - -[yolo] -mask = 0,1,2 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=1 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3-tiny3.cfg b/cfg/yolov3-tiny3.cfg deleted file mode 100644 index 85d6787f6c..0000000000 --- a/cfg/yolov3-tiny3.cfg +++ /dev/null @@ -1,227 +0,0 @@ -[net] -# Testing -# batch=1 -# subdivisions=1 -# Training -batch=64 -subdivisions=16 -width=608 -height=608 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 200000 -policy=steps -steps=180000,190000 -scales=.1,.1 - - -[convolutional] -batch_normalize=1 -filters=16 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[maxpool] -size=2 -stride=1 - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -########### - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - - -[yolo] -mask = 6,7,8 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 8 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 3,4,5 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 6 - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 0,1,2 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov3.cfg b/cfg/yolov3.cfg deleted file mode 100755 index 946e0154c3..0000000000 --- a/cfg/yolov3.cfg +++ /dev/null @@ -1,788 +0,0 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=16 -subdivisions=1 -width=416 -height=416 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -###################### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 61 - - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 - - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 36 - - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 diff --git a/cfg/yolov4-relu.cfg b/cfg/yolov4-relu.cfg deleted file mode 100644 index c2821b7eac..0000000000 --- a/cfg/yolov4-relu.cfg +++ /dev/null @@ -1,1155 +0,0 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=64 -subdivisions=8 -width=608 -height=608 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -#cutmix=1 -mosaic=1 - -#:104x104 54:52x52 85:26x26 104:13x13 for 416 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-7 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-10 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-28 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-28 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-16 - -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=leaky - -########################## - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = 85 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = 54 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -########################## - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -scale_x_y = 1.2 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=256 -activation=leaky - -[route] -layers = -1, -16 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -scale_x_y = 1.1 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=512 -activation=leaky - -[route] -layers = -1, -37 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 diff --git a/cfg/yolov4-tiny.cfg b/cfg/yolov4-tiny.cfg deleted file mode 100644 index dc6f5bfb8c..0000000000 --- a/cfg/yolov4-tiny.cfg +++ /dev/null @@ -1,281 +0,0 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=64 -subdivisions=1 -width=416 -height=416 -channels=3 -momentum=0.9 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500200 -policy=steps -steps=400000,450000 -scales=.1,.1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[route] -layers=-1 -groups=2 -group_id=1 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -6,-1 - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[route] -layers=-1 -groups=2 -group_id=1 - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -6,-1 - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[route] -layers=-1 -groups=2 -group_id=1 - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1,-2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -6,-1 - -[maxpool] -size=2 -stride=2 - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -################################## - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - - -[yolo] -mask = 3,4,5 -anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 -classes=80 -num=6 -jitter=.3 -scale_x_y = 1.05 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -ignore_thresh = .7 -truth_thresh = 1 -random=0 -resize=1.5 -nms_kind=greedynms -beta_nms=0.6 - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = -1, 23 - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 1,2,3 -anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 -classes=80 -num=6 -jitter=.3 -scale_x_y = 1.05 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -ignore_thresh = .7 -truth_thresh = 1 -random=0 -resize=1.5 -nms_kind=greedynms -beta_nms=0.6 diff --git a/cfg/yolov4.cfg b/cfg/yolov4.cfg deleted file mode 100644 index 5e1ac82224..0000000000 --- a/cfg/yolov4.cfg +++ /dev/null @@ -1,1155 +0,0 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=64 -subdivisions=8 -width=608 -height=608 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -#cutmix=1 -mosaic=1 - -#:104x104 54:52x52 85:26x26 104:13x13 for 416 - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=mish - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -1,-7 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -1,-10 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -1,-28 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -1,-28 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -1,-16 - -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=mish - -########################## - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = 85 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[upsample] -stride=2 - -[route] -layers = 54 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=leaky - -########################## - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 0,1,2 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -scale_x_y = 1.2 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=256 -activation=leaky - -[route] -layers = -1, -16 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 3,4,5 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -scale_x_y = 1.1 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -[route] -layers = -4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=512 -activation=leaky - -[route] -layers = -1, -37 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=leaky - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=leaky - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - - -[yolo] -mask = 6,7,8 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 diff --git a/data/coco.names b/data/coco.names deleted file mode 100755 index 941cb4e139..0000000000 --- a/data/coco.names +++ /dev/null @@ -1,80 +0,0 @@ -person -bicycle -car -motorcycle -airplane -bus -train -truck -boat -traffic light -fire hydrant -stop sign -parking meter -bench -bird -cat -dog -horse -sheep -cow -elephant -bear -zebra -giraffe -backpack -umbrella -handbag -tie -suitcase -frisbee -skis -snowboard -sports ball -kite -baseball bat -baseball glove -skateboard -surfboard -tennis racket -bottle -wine glass -cup -fork -knife -spoon -bowl -banana -apple -sandwich -orange -broccoli -carrot -hot dog -pizza -donut -cake -chair -couch -potted plant -bed -dining table -toilet -tv -laptop -mouse -remote -keyboard -cell phone -microwave -oven -toaster -sink -refrigerator -book -clock -vase -scissors -teddy bear -hair drier -toothbrush diff --git a/data/coco.yaml b/data/coco.yaml new file mode 100644 index 0000000000..09e0a4f463 --- /dev/null +++ b/data/coco.yaml @@ -0,0 +1,35 @@ +# COCO 2017 dataset http://cocodataset.org +# Train command: python train.py --data coco.yaml +# Default dataset location is next to /yolov3: +# /parent_folder +# /coco +# /yolov3 + + +# download command/URL (optional) +download: bash data/scripts/get_coco.sh + +# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] +train: ../coco/train2017.txt # 118287 images +val: ../coco/val2017.txt # 5000 images +test: ../coco/test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794 + +# number of classes +nc: 80 + +# class names +names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', + 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', + 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', + 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', + 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', + 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', + 'hair drier', 'toothbrush'] + +# Print classes +# with open('data/coco.yaml') as f: +# d = yaml.load(f, Loader=yaml.FullLoader) # dict +# for i, x in enumerate(d['names']): +# print(i, x) diff --git a/data/coco1.data b/data/coco1.data deleted file mode 100644 index 3c04a659ae..0000000000 --- a/data/coco1.data +++ /dev/null @@ -1,4 +0,0 @@ -classes=80 -train=data/coco1.txt -valid=data/coco1.txt -names=data/coco.names diff --git a/data/coco1.txt b/data/coco1.txt deleted file mode 100644 index 268042e732..0000000000 --- a/data/coco1.txt +++ /dev/null @@ -1 +0,0 @@ -../coco/images/train2017/000000109622.jpg diff --git a/data/coco128.yaml b/data/coco128.yaml new file mode 100644 index 0000000000..abd129d962 --- /dev/null +++ b/data/coco128.yaml @@ -0,0 +1,28 @@ +# COCO 2017 dataset http://cocodataset.org - first 128 training images +# Train command: python train.py --data coco128.yaml +# Default dataset location is next to /yolov3: +# /parent_folder +# /coco128 +# /yolov3 + + +# download command/URL (optional) +download: https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip + +# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] +train: ../coco128/images/train2017/ # 128 images +val: ../coco128/images/train2017/ # 128 images + +# number of classes +nc: 80 + +# class names +names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', + 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', + 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', + 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', + 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', + 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', + 'hair drier', 'toothbrush'] diff --git a/data/coco16.data b/data/coco16.data deleted file mode 100644 index d382734894..0000000000 --- a/data/coco16.data +++ /dev/null @@ -1,4 +0,0 @@ -classes=80 -train=data/coco16.txt -valid=data/coco16.txt -names=data/coco.names diff --git a/data/coco16.txt b/data/coco16.txt deleted file mode 100644 index 4fb69e997a..0000000000 --- a/data/coco16.txt +++ /dev/null @@ -1,16 +0,0 @@ -../coco/images/train2017/000000109622.jpg -../coco/images/train2017/000000160694.jpg -../coco/images/train2017/000000308590.jpg -../coco/images/train2017/000000327573.jpg -../coco/images/train2017/000000062929.jpg -../coco/images/train2017/000000512793.jpg -../coco/images/train2017/000000371735.jpg -../coco/images/train2017/000000148118.jpg -../coco/images/train2017/000000309856.jpg -../coco/images/train2017/000000141882.jpg -../coco/images/train2017/000000318783.jpg -../coco/images/train2017/000000337760.jpg -../coco/images/train2017/000000298197.jpg -../coco/images/train2017/000000042421.jpg -../coco/images/train2017/000000328898.jpg -../coco/images/train2017/000000458856.jpg diff --git a/data/coco1cls.data b/data/coco1cls.data deleted file mode 100644 index 509721f93c..0000000000 --- a/data/coco1cls.data +++ /dev/null @@ -1,4 +0,0 @@ -classes=1 -train=data/coco1cls.txt -valid=data/coco1cls.txt -names=data/coco.names diff --git a/data/coco1cls.txt b/data/coco1cls.txt deleted file mode 100644 index 8702573935..0000000000 --- a/data/coco1cls.txt +++ /dev/null @@ -1,16 +0,0 @@ -../coco/images/train2017/000000000901.jpg -../coco/images/train2017/000000001464.jpg -../coco/images/train2017/000000003220.jpg -../coco/images/train2017/000000003365.jpg -../coco/images/train2017/000000004772.jpg -../coco/images/train2017/000000009987.jpg -../coco/images/train2017/000000010498.jpg -../coco/images/train2017/000000012455.jpg -../coco/images/train2017/000000013992.jpg -../coco/images/train2017/000000014125.jpg -../coco/images/train2017/000000016314.jpg -../coco/images/train2017/000000016670.jpg -../coco/images/train2017/000000018412.jpg -../coco/images/train2017/000000021212.jpg -../coco/images/train2017/000000021826.jpg -../coco/images/train2017/000000030566.jpg diff --git a/data/coco2014.data b/data/coco2014.data deleted file mode 100644 index 422a3005ed..0000000000 --- a/data/coco2014.data +++ /dev/null @@ -1,4 +0,0 @@ -classes=80 -train=../coco/trainvalno5k.txt -valid=../coco/5k.txt -names=data/coco.names diff --git a/data/coco2017.data b/data/coco2017.data deleted file mode 100644 index c946005678..0000000000 --- a/data/coco2017.data +++ /dev/null @@ -1,4 +0,0 @@ -classes=80 -train=../coco/train2017.txt -valid=../coco/val2017.txt -names=data/coco.names diff --git a/data/coco64.data b/data/coco64.data deleted file mode 100644 index 159489acb4..0000000000 --- a/data/coco64.data +++ /dev/null @@ -1,4 +0,0 @@ -classes=80 -train=data/coco64.txt -valid=data/coco64.txt -names=data/coco.names diff --git a/data/coco64.txt b/data/coco64.txt deleted file mode 100644 index 7dbc28fcec..0000000000 --- a/data/coco64.txt +++ /dev/null @@ -1,64 +0,0 @@ -../coco/images/train2017/000000109622.jpg -../coco/images/train2017/000000160694.jpg -../coco/images/train2017/000000308590.jpg -../coco/images/train2017/000000327573.jpg -../coco/images/train2017/000000062929.jpg -../coco/images/train2017/000000512793.jpg -../coco/images/train2017/000000371735.jpg -../coco/images/train2017/000000148118.jpg -../coco/images/train2017/000000309856.jpg -../coco/images/train2017/000000141882.jpg -../coco/images/train2017/000000318783.jpg -../coco/images/train2017/000000337760.jpg -../coco/images/train2017/000000298197.jpg -../coco/images/train2017/000000042421.jpg -../coco/images/train2017/000000328898.jpg -../coco/images/train2017/000000458856.jpg -../coco/images/train2017/000000073824.jpg -../coco/images/train2017/000000252846.jpg -../coco/images/train2017/000000459590.jpg -../coco/images/train2017/000000273650.jpg -../coco/images/train2017/000000331311.jpg -../coco/images/train2017/000000156326.jpg -../coco/images/train2017/000000262985.jpg -../coco/images/train2017/000000253580.jpg -../coco/images/train2017/000000447976.jpg -../coco/images/train2017/000000378077.jpg -../coco/images/train2017/000000259913.jpg -../coco/images/train2017/000000424553.jpg -../coco/images/train2017/000000000612.jpg -../coco/images/train2017/000000267625.jpg -../coco/images/train2017/000000566012.jpg -../coco/images/train2017/000000196664.jpg -../coco/images/train2017/000000363331.jpg -../coco/images/train2017/000000057992.jpg -../coco/images/train2017/000000520047.jpg -../coco/images/train2017/000000453903.jpg -../coco/images/train2017/000000162083.jpg -../coco/images/train2017/000000268516.jpg -../coco/images/train2017/000000277436.jpg -../coco/images/train2017/000000189744.jpg -../coco/images/train2017/000000041128.jpg -../coco/images/train2017/000000527728.jpg -../coco/images/train2017/000000465269.jpg -../coco/images/train2017/000000246833.jpg -../coco/images/train2017/000000076784.jpg -../coco/images/train2017/000000323715.jpg -../coco/images/train2017/000000560463.jpg -../coco/images/train2017/000000006263.jpg -../coco/images/train2017/000000094701.jpg -../coco/images/train2017/000000521359.jpg -../coco/images/train2017/000000302903.jpg -../coco/images/train2017/000000047559.jpg -../coco/images/train2017/000000480583.jpg -../coco/images/train2017/000000050025.jpg -../coco/images/train2017/000000084512.jpg -../coco/images/train2017/000000508913.jpg -../coco/images/train2017/000000093708.jpg -../coco/images/train2017/000000070493.jpg -../coco/images/train2017/000000539270.jpg -../coco/images/train2017/000000474402.jpg -../coco/images/train2017/000000209842.jpg -../coco/images/train2017/000000028820.jpg -../coco/images/train2017/000000154257.jpg -../coco/images/train2017/000000342499.jpg diff --git a/data/coco_paper.names b/data/coco_paper.names deleted file mode 100644 index 5378c6cdad..0000000000 --- a/data/coco_paper.names +++ /dev/null @@ -1,91 +0,0 @@ -person -bicycle -car -motorcycle -airplane -bus -train -truck -boat -traffic light -fire hydrant -street sign -stop sign -parking meter -bench -bird -cat -dog -horse -sheep -cow -elephant -bear -zebra -giraffe -hat -backpack -umbrella -shoe -eye glasses -handbag -tie -suitcase -frisbee -skis -snowboard -sports ball -kite -baseball bat -baseball glove -skateboard -surfboard -tennis racket -bottle -plate -wine glass -cup -fork -knife -spoon -bowl -banana -apple -sandwich -orange -broccoli -carrot -hot dog -pizza -donut -cake -chair -couch -potted plant -bed -mirror -dining table -window -desk -toilet -door -tv -laptop -mouse -remote -keyboard -cell phone -microwave -oven -toaster -sink -refrigerator -blender -book -clock -vase -scissors -teddy bear -hair drier -toothbrush -hair brush \ No newline at end of file diff --git a/data/get_coco2014.sh b/data/get_coco2014.sh deleted file mode 100755 index 02d059c58e..0000000000 --- a/data/get_coco2014.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -# Zip coco folder -# zip -r coco.zip coco -# tar -czvf coco.tar.gz coco - -# Download labels from Google Drive, accepting presented query -filename="coco2014labels.zip" -fileid="1s6-CmF5_SElM28r52P1OUrCcuXZN-SFo" -curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" >/dev/null -curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=$(awk '/download/ {print $NF}' ./cookie)&id=${fileid}" -o ${filename} -rm ./cookie - -# Unzip labels -unzip -q ${filename} # for coco.zip -# tar -xzf ${filename} # for coco.tar.gz -rm ${filename} - -# Download and unzip images -cd coco/images -f="train2014.zip" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f -f="val2014.zip" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f - -# cd out -cd ../.. diff --git a/data/get_coco2017.sh b/data/get_coco2017.sh deleted file mode 100755 index 3bf4069a65..0000000000 --- a/data/get_coco2017.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -# Zip coco folder -# zip -r coco.zip coco -# tar -czvf coco.tar.gz coco - -# Download labels from Google Drive, accepting presented query -filename="coco2017labels.zip" -fileid="1cXZR_ckHki6nddOmcysCuuJFM--T-Q6L" -curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" >/dev/null -curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=$(awk '/download/ {print $NF}' ./cookie)&id=${fileid}" -o ${filename} -rm ./cookie - -# Unzip labels -unzip -q ${filename} # for coco.zip -# tar -xzf ${filename} # for coco.tar.gz -rm ${filename} - -# Download and unzip images -cd coco/images -f="train2017.zip" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f -f="val2017.zip" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f - -# cd out -cd ../.. diff --git a/data/hyp.finetune.yaml b/data/hyp.finetune.yaml new file mode 100644 index 0000000000..1b84cff95c --- /dev/null +++ b/data/hyp.finetune.yaml @@ -0,0 +1,38 @@ +# Hyperparameters for VOC finetuning +# python train.py --batch 64 --weights yolov5m.pt --data voc.yaml --img 512 --epochs 50 +# See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials + + +# Hyperparameter Evolution Results +# Generations: 306 +# P R mAP.5 mAP.5:.95 box obj cls +# Metrics: 0.6 0.936 0.896 0.684 0.0115 0.00805 0.00146 + +lr0: 0.0032 +lrf: 0.12 +momentum: 0.843 +weight_decay: 0.00036 +warmup_epochs: 2.0 +warmup_momentum: 0.5 +warmup_bias_lr: 0.05 +box: 0.0296 +cls: 0.243 +cls_pw: 0.631 +obj: 0.301 +obj_pw: 0.911 +iou_t: 0.2 +anchor_t: 2.91 +# anchors: 3.63 +fl_gamma: 0.0 +hsv_h: 0.0138 +hsv_s: 0.664 +hsv_v: 0.464 +degrees: 0.373 +translate: 0.245 +scale: 0.898 +shear: 0.602 +perspective: 0.0 +flipud: 0.00856 +fliplr: 0.5 +mosaic: 1.0 +mixup: 0.243 diff --git a/data/hyp.scratch.yaml b/data/hyp.scratch.yaml new file mode 100644 index 0000000000..44f26b6658 --- /dev/null +++ b/data/hyp.scratch.yaml @@ -0,0 +1,33 @@ +# Hyperparameters for COCO training from scratch +# python train.py --batch 40 --cfg yolov5m.yaml --weights '' --data coco.yaml --img 640 --epochs 300 +# See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials + + +lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) +lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf) +momentum: 0.937 # SGD momentum/Adam beta1 +weight_decay: 0.0005 # optimizer weight decay 5e-4 +warmup_epochs: 3.0 # warmup epochs (fractions ok) +warmup_momentum: 0.8 # warmup initial momentum +warmup_bias_lr: 0.1 # warmup initial bias lr +box: 0.05 # box loss gain +cls: 0.5 # cls loss gain +cls_pw: 1.0 # cls BCELoss positive_weight +obj: 1.0 # obj loss gain (scale with pixels) +obj_pw: 1.0 # obj BCELoss positive_weight +iou_t: 0.20 # IoU training threshold +anchor_t: 4.0 # anchor-multiple threshold +# anchors: 3 # anchors per output layer (0 to ignore) +fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) +hsv_h: 0.015 # image HSV-Hue augmentation (fraction) +hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) +hsv_v: 0.4 # image HSV-Value augmentation (fraction) +degrees: 0.0 # image rotation (+/- deg) +translate: 0.1 # image translation (+/- fraction) +scale: 0.5 # image scale (+/- gain) +shear: 0.0 # image shear (+/- deg) +perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 +flipud: 0.0 # image flip up-down (probability) +fliplr: 0.5 # image flip left-right (probability) +mosaic: 1.0 # image mosaic (probability) +mixup: 0.0 # image mixup (probability) diff --git a/data/samples/bus.jpg b/data/images/bus.jpg similarity index 100% rename from data/samples/bus.jpg rename to data/images/bus.jpg diff --git a/data/samples/zidane.jpg b/data/images/zidane.jpg similarity index 100% rename from data/samples/zidane.jpg rename to data/images/zidane.jpg diff --git a/data/scripts/get_coco.sh b/data/scripts/get_coco.sh new file mode 100755 index 0000000000..2604e9b7ce --- /dev/null +++ b/data/scripts/get_coco.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# COCO 2017 dataset http://cocodataset.org +# Download command: bash data/scripts/get_coco.sh +# Train command: python train.py --data coco.yaml +# Default dataset location is next to /yolov3: +# /parent_folder +# /coco +# /yolov3 + +# Download/unzip labels +d='../' # unzip directory +url=https://github.com/ultralytics/yolov5/releases/download/v1.0/ +f='coco2017labels.zip' # 68 MB +echo 'Downloading' $url$f ' ...' && curl -L $url$f -o $f && unzip -q $f -d $d && rm $f # download, unzip, remove + +# Download/unzip images +d='../coco/images' # unzip directory +url=http://images.cocodataset.org/zips/ +f1='train2017.zip' # 19G, 118k images +f2='val2017.zip' # 1G, 5k images +f3='test2017.zip' # 7G, 41k images (optional) +for f in $f1 $f2; do + echo 'Downloading' $url$f ' ...' && curl -L $url$f -o $f && unzip -q $f -d $d && rm $f # download, unzip, remove +done diff --git a/data/scripts/get_voc.sh b/data/scripts/get_voc.sh new file mode 100644 index 0000000000..6bdaa9bcc0 --- /dev/null +++ b/data/scripts/get_voc.sh @@ -0,0 +1,137 @@ +#!/bin/bash +# PASCAL VOC dataset http://host.robots.ox.ac.uk/pascal/VOC/ +# Download command: bash data/scripts/get_voc.sh +# Train command: python train.py --data voc.yaml +# Default dataset location is next to /yolov5: +# /parent_folder +# /VOC +# /yolov5 + +start=$(date +%s) +mkdir -p ../tmp +cd ../tmp/ + +# Download/unzip images and labels +d='.' # unzip directory +url=https://github.com/ultralytics/yolov5/releases/download/v1.0/ +f1=VOCtrainval_06-Nov-2007.zip # 446MB, 5012 images +f2=VOCtest_06-Nov-2007.zip # 438MB, 4953 images +f3=VOCtrainval_11-May-2012.zip # 1.95GB, 17126 images +for f in $f1 $f2 $f3; do + echo 'Downloading' $url$f ' ...' && curl -L $url$f -o $f && unzip -q $f -d $d && rm $f # download, unzip, remove +done + +end=$(date +%s) +runtime=$((end - start)) +echo "Completed in" $runtime "seconds" + +echo "Splitting dataset..." +python3 - "$@" <train.txt +cat 2007_train.txt 2007_val.txt 2007_test.txt 2012_train.txt 2012_val.txt >train.all.txt + +python3 - "$@" <= 1 - p, s, im0 = path[i], '%g: ' % i, im0s[i].copy() + p, s, im0 = Path(path[i]), '%g: ' % i, im0s[i].copy() else: - p, s, im0 = path, '', im0s + p, s, im0 = Path(path), '', im0s - save_path = str(Path(out) / Path(p).name) + save_path = str(save_dir / p.name) + txt_path = str(save_dir / 'labels' / p.stem) + ('_%g' % dataset.frame if dataset.mode == 'video' else '') s += '%gx%g ' % img.shape[2:] # print string - gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] #  normalization gain whwh - if det is not None and len(det): - # Rescale boxes from imgsz to im0 size + gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh + if len(det): + # Rescale boxes from img_size to im0 size det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() # Print results @@ -124,19 +102,20 @@ def detect(save_img=False): for *xyxy, conf, cls in reversed(det): if save_txt: # Write to file xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh - with open(save_path[:save_path.rfind('.')] + '.txt', 'a') as file: - file.write(('%g ' * 5 + '\n') % (cls, *xywh)) # label format + line = (cls, *xywh, conf) if opt.save_conf else (cls, *xywh) # label format + with open(txt_path + '.txt', 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') if save_img or view_img: # Add bbox to image label = '%s %.2f' % (names[int(cls)], conf) - plot_one_box(xyxy, im0, label=label, color=colors[int(cls)]) + plot_one_box(xyxy, im0, label=label, color=colors[int(cls)], line_thickness=3) # Print time (inference + NMS) print('%sDone. (%.3fs)' % (s, t2 - t1)) # Stream results if view_img: - cv2.imshow(p, im0) + cv2.imshow(str(p), im0) if cv2.waitKey(1) == ord('q'): # q to quit raise StopIteration @@ -150,42 +129,45 @@ def detect(save_img=False): if isinstance(vid_writer, cv2.VideoWriter): vid_writer.release() # release previous video writer + fourcc = 'mp4v' # output video codec fps = vid_cap.get(cv2.CAP_PROP_FPS) w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) - vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*opt.fourcc), fps, (w, h)) + vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*fourcc), fps, (w, h)) vid_writer.write(im0) if save_txt or save_img: - print('Results saved to %s' % os.getcwd() + os.sep + out) - if platform == 'darwin': # MacOS - os.system('open ' + save_path) + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + print(f"Results saved to {save_dir}{s}") print('Done. (%.3fs)' % (time.time() - t0)) if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') - parser.add_argument('--names', type=str, default='data/coco.names', help='*.names path') - parser.add_argument('--weights', type=str, default='weights/yolov3-spp-ultralytics.pt', help='weights path') - parser.add_argument('--source', type=str, default='data/samples', help='source') # input file/folder, 0 for webcam - parser.add_argument('--output', type=str, default='output', help='output folder') # output folder - parser.add_argument('--img-size', type=int, default=512, help='inference size (pixels)') - parser.add_argument('--conf-thres', type=float, default=0.3, help='object confidence threshold') - parser.add_argument('--iou-thres', type=float, default=0.6, help='IOU threshold for NMS') - parser.add_argument('--fourcc', type=str, default='mp4v', help='output video codec (verify ffmpeg support)') - parser.add_argument('--half', action='store_true', help='half precision FP16 inference') - parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') + parser.add_argument('--weights', nargs='+', type=str, default='yolov3.pt', help='model.pt path(s)') + parser.add_argument('--source', type=str, default='data/images', help='source') # file/folder, 0 for webcam + parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)') + parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--view-img', action='store_true', help='display results') parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') - parser.add_argument('--classes', nargs='+', type=int, help='filter by class') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3') parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--update', action='store_true', help='update all models') + parser.add_argument('--project', default='runs/detect', help='save results to project/name') + parser.add_argument('--name', default='exp', help='save results to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') opt = parser.parse_args() - opt.cfg = check_file(opt.cfg) # check file - opt.names = check_file(opt.names) # check file print(opt) with torch.no_grad(): - detect() + if opt.update: # update all models (to fix SourceChangeWarning) + for opt.weights in ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt']: + detect() + strip_optimizer(opt.weights) + else: + detect() diff --git a/hubconf.py b/hubconf.py new file mode 100644 index 0000000000..9067d0bd32 --- /dev/null +++ b/hubconf.py @@ -0,0 +1,105 @@ +"""File for accessing YOLOv3 via PyTorch Hub https://pytorch.org/hub/ + +Usage: + import torch + model = torch.hub.load('ultralytics/yolov3', 'yolov3', pretrained=True, channels=3, classes=80) +""" + +from pathlib import Path + +import torch + +from models.yolo import Model +from utils.general import set_logging +from utils.google_utils import attempt_download + +dependencies = ['torch', 'yaml'] +set_logging() + + +def create(name, pretrained, channels, classes): + """Creates a specified YOLOv3 model + + Arguments: + name (str): name of model, i.e. 'yolov3_spp' + pretrained (bool): load pretrained weights into the model + channels (int): number of input channels + classes (int): number of model classes + + Returns: + pytorch model + """ + config = Path(__file__).parent / 'models' / f'{name}.yaml' # model.yaml path + try: + model = Model(config, channels, classes) + if pretrained: + fname = f'{name}.pt' # checkpoint filename + attempt_download(fname) # download if not found locally + ckpt = torch.load(fname, map_location=torch.device('cpu')) # load + state_dict = ckpt['model'].float().state_dict() # to FP32 + state_dict = {k: v for k, v in state_dict.items() if model.state_dict()[k].shape == v.shape} # filter + model.load_state_dict(state_dict, strict=False) # load + if len(ckpt['model'].names) == classes: + model.names = ckpt['model'].names # set class names attribute + # model = model.autoshape() # for PIL/cv2/np inputs and NMS + return model + + except Exception as e: + help_url = 'https://github.com/ultralytics/yolov5/issues/36' + s = 'Cache maybe be out of date, try force_reload=True. See %s for help.' % help_url + raise Exception(s) from e + + +def yolov3(pretrained=False, channels=3, classes=80): + """YOLOv3 model from https://github.com/ultralytics/yolov3 + + Arguments: + pretrained (bool): load pretrained weights into the model, default=False + channels (int): number of input channels, default=3 + classes (int): number of model classes, default=80 + + Returns: + pytorch model + """ + return create('yolov3', pretrained, channels, classes) + + +def yolov3_spp(pretrained=False, channels=3, classes=80): + """YOLOv3-SPP model from https://github.com/ultralytics/yolov3 + + Arguments: + pretrained (bool): load pretrained weights into the model, default=False + channels (int): number of input channels, default=3 + classes (int): number of model classes, default=80 + + Returns: + pytorch model + """ + return create('yolov3-spp', pretrained, channels, classes) + + +def yolov3_tiny(pretrained=False, channels=3, classes=80): + """YOLOv3-tiny model from https://github.com/ultralytics/yolov3 + + Arguments: + pretrained (bool): load pretrained weights into the model, default=False + channels (int): number of input channels, default=3 + classes (int): number of model classes, default=80 + + Returns: + pytorch model + """ + return create('yolov3-tiny', pretrained, channels, classes) + + +if __name__ == '__main__': + model = create(name='yolov3', pretrained=True, channels=3, classes=80) # example + model = model.fuse().autoshape() # for PIL/cv2/np inputs and NMS + + # Verify inference + from PIL import Image + + imgs = [Image.open(x) for x in Path('data/images').glob('*.jpg')] + results = model(imgs) + results.show() + results.print() diff --git a/models.py b/models.py deleted file mode 100755 index 54742b883e..0000000000 --- a/models.py +++ /dev/null @@ -1,480 +0,0 @@ -from utils.google_utils import * -from utils.layers import * -from utils.parse_config import * - -ONNX_EXPORT = False - - -def create_modules(module_defs, img_size, cfg): - # Constructs module list of layer blocks from module configuration in module_defs - - img_size = [img_size] * 2 if isinstance(img_size, int) else img_size # expand if necessary - _ = module_defs.pop(0) # cfg training hyperparams (unused) - output_filters = [3] # input channels - module_list = nn.ModuleList() - routs = [] # list of layers which rout to deeper layers - yolo_index = -1 - - for i, mdef in enumerate(module_defs): - modules = nn.Sequential() - - if mdef['type'] == 'convolutional': - bn = mdef['batch_normalize'] - filters = mdef['filters'] - k = mdef['size'] # kernel size - stride = mdef['stride'] if 'stride' in mdef else (mdef['stride_y'], mdef['stride_x']) - if isinstance(k, int): # single-size conv - modules.add_module('Conv2d', nn.Conv2d(in_channels=output_filters[-1], - out_channels=filters, - kernel_size=k, - stride=stride, - padding=k // 2 if mdef['pad'] else 0, - groups=mdef['groups'] if 'groups' in mdef else 1, - bias=not bn)) - else: # multiple-size conv - modules.add_module('MixConv2d', MixConv2d(in_ch=output_filters[-1], - out_ch=filters, - k=k, - stride=stride, - bias=not bn)) - - if bn: - modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.03, eps=1E-4)) - else: - routs.append(i) # detection output (goes into yolo layer) - - if mdef['activation'] == 'leaky': # activation study https://github.com/ultralytics/yolov3/issues/441 - modules.add_module('activation', nn.LeakyReLU(0.1, inplace=True)) - elif mdef['activation'] == 'swish': - modules.add_module('activation', Swish()) - elif mdef['activation'] == 'mish': - modules.add_module('activation', Mish()) - - elif mdef['type'] == 'BatchNorm2d': - filters = output_filters[-1] - modules = nn.BatchNorm2d(filters, momentum=0.03, eps=1E-4) - if i == 0 and filters == 3: # normalize RGB image - # imagenet mean and var https://pytorch.org/docs/stable/torchvision/models.html#classification - modules.running_mean = torch.tensor([0.485, 0.456, 0.406]) - modules.running_var = torch.tensor([0.0524, 0.0502, 0.0506]) - - elif mdef['type'] == 'maxpool': - k = mdef['size'] # kernel size - stride = mdef['stride'] - maxpool = nn.MaxPool2d(kernel_size=k, stride=stride, padding=(k - 1) // 2) - if k == 2 and stride == 1: # yolov3-tiny - modules.add_module('ZeroPad2d', nn.ZeroPad2d((0, 1, 0, 1))) - modules.add_module('MaxPool2d', maxpool) - else: - modules = maxpool - - elif mdef['type'] == 'upsample': - if ONNX_EXPORT: # explicitly state size, avoid scale_factor - g = (yolo_index + 1) * 2 / 32 # gain - modules = nn.Upsample(size=tuple(int(x * g) for x in img_size)) # img_size = (320, 192) - else: - modules = nn.Upsample(scale_factor=mdef['stride']) - - elif mdef['type'] == 'route': # nn.Sequential() placeholder for 'route' layer - layers = mdef['layers'] - filters = sum([output_filters[l + 1 if l > 0 else l] for l in layers]) - routs.extend([i + l if l < 0 else l for l in layers]) - modules = FeatureConcat(layers=layers) - - elif mdef['type'] == 'shortcut': # nn.Sequential() placeholder for 'shortcut' layer - layers = mdef['from'] - filters = output_filters[-1] - routs.extend([i + l if l < 0 else l for l in layers]) - modules = WeightedFeatureFusion(layers=layers, weight='weights_type' in mdef) - - elif mdef['type'] == 'reorg3d': # yolov3-spp-pan-scale - pass - - elif mdef['type'] == 'yolo': - yolo_index += 1 - stride = [32, 16, 8] # P5, P4, P3 strides - if any(x in cfg for x in ['panet', 'yolov4', 'cd53']): # stride order reversed - stride = list(reversed(stride)) - layers = mdef['from'] if 'from' in mdef else [] - modules = YOLOLayer(anchors=mdef['anchors'][mdef['mask']], # anchor list - nc=mdef['classes'], # number of classes - img_size=img_size, # (416, 416) - yolo_index=yolo_index, # 0, 1, 2... - layers=layers, # output layers - stride=stride[yolo_index]) - - # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) - try: - j = layers[yolo_index] if 'from' in mdef else -1 - # If previous layer is a dropout layer, get the one before - if module_list[j].__class__.__name__ == 'Dropout': - j -= 1 - bias_ = module_list[j][0].bias # shape(255,) - bias = bias_[:modules.no * modules.na].view(modules.na, -1) # shape(3,85) - bias[:, 4] += -4.5 # obj - bias[:, 5:] += math.log(0.6 / (modules.nc - 0.99)) # cls (sigmoid(p) = 1/nc) - module_list[j][0].bias = torch.nn.Parameter(bias_, requires_grad=bias_.requires_grad) - except: - print('WARNING: smart bias initialization failure.') - - elif mdef['type'] == 'dropout': - perc = float(mdef['probability']) - modules = nn.Dropout(p=perc) - else: - print('Warning: Unrecognized Layer Type: ' + mdef['type']) - - # Register module list and number of output filters - module_list.append(modules) - output_filters.append(filters) - - routs_binary = [False] * (i + 1) - for i in routs: - routs_binary[i] = True - return module_list, routs_binary - - -class YOLOLayer(nn.Module): - def __init__(self, anchors, nc, img_size, yolo_index, layers, stride): - super(YOLOLayer, self).__init__() - self.anchors = torch.Tensor(anchors) - self.index = yolo_index # index of this layer in layers - self.layers = layers # model output layer indices - self.stride = stride # layer stride - self.nl = len(layers) # number of output layers (3) - self.na = len(anchors) # number of anchors (3) - self.nc = nc # number of classes (80) - self.no = nc + 5 # number of outputs (85) - self.nx, self.ny, self.ng = 0, 0, 0 # initialize number of x, y gridpoints - self.anchor_vec = self.anchors / self.stride - self.anchor_wh = self.anchor_vec.view(1, self.na, 1, 1, 2) - - if ONNX_EXPORT: - self.training = False - self.create_grids((img_size[1] // stride, img_size[0] // stride)) # number x, y grid points - - def create_grids(self, ng=(13, 13), device='cpu'): - self.nx, self.ny = ng # x and y grid size - self.ng = torch.tensor(ng, dtype=torch.float) - - # build xy offsets - if not self.training: - yv, xv = torch.meshgrid([torch.arange(self.ny, device=device), torch.arange(self.nx, device=device)]) - self.grid = torch.stack((xv, yv), 2).view((1, 1, self.ny, self.nx, 2)).float() - - if self.anchor_vec.device != device: - self.anchor_vec = self.anchor_vec.to(device) - self.anchor_wh = self.anchor_wh.to(device) - - def forward(self, p, out): - ASFF = False # https://arxiv.org/abs/1911.09516 - if ASFF: - i, n = self.index, self.nl # index in layers, number of layers - p = out[self.layers[i]] - bs, _, ny, nx = p.shape # bs, 255, 13, 13 - if (self.nx, self.ny) != (nx, ny): - self.create_grids((nx, ny), p.device) - - # outputs and weights - # w = F.softmax(p[:, -n:], 1) # normalized weights - w = torch.sigmoid(p[:, -n:]) * (2 / n) # sigmoid weights (faster) - # w = w / w.sum(1).unsqueeze(1) # normalize across layer dimension - - # weighted ASFF sum - p = out[self.layers[i]][:, :-n] * w[:, i:i + 1] - for j in range(n): - if j != i: - p += w[:, j:j + 1] * \ - F.interpolate(out[self.layers[j]][:, :-n], size=[ny, nx], mode='bilinear', align_corners=False) - - elif ONNX_EXPORT: - bs = 1 # batch size - else: - bs, _, ny, nx = p.shape # bs, 255, 13, 13 - if (self.nx, self.ny) != (nx, ny): - self.create_grids((nx, ny), p.device) - - # p.view(bs, 255, 13, 13) -- > (bs, 3, 13, 13, 85) # (bs, anchors, grid, grid, classes + xywh) - p = p.view(bs, self.na, self.no, self.ny, self.nx).permute(0, 1, 3, 4, 2).contiguous() # prediction - - if self.training: - return p - - elif ONNX_EXPORT: - # Avoid broadcasting for ANE operations - m = self.na * self.nx * self.ny - ng = 1. / self.ng.repeat(m, 1) - grid = self.grid.repeat(1, self.na, 1, 1, 1).view(m, 2) - anchor_wh = self.anchor_wh.repeat(1, 1, self.nx, self.ny, 1).view(m, 2) * ng - - p = p.view(m, self.no) - xy = torch.sigmoid(p[:, 0:2]) + grid # x, y - wh = torch.exp(p[:, 2:4]) * anchor_wh # width, height - p_cls = torch.sigmoid(p[:, 4:5]) if self.nc == 1 else \ - torch.sigmoid(p[:, 5:self.no]) * torch.sigmoid(p[:, 4:5]) # conf - return p_cls, xy * ng, wh - - else: # inference - io = p.clone() # inference output - io[..., :2] = torch.sigmoid(io[..., :2]) + self.grid # xy - io[..., 2:4] = torch.exp(io[..., 2:4]) * self.anchor_wh # wh yolo method - io[..., :4] *= self.stride - torch.sigmoid_(io[..., 4:]) - return io.view(bs, -1, self.no), p # view [1, 3, 13, 13, 85] as [1, 507, 85] - - -class Darknet(nn.Module): - # YOLOv3 object detection model - - def __init__(self, cfg, img_size=(416, 416), verbose=False): - super(Darknet, self).__init__() - - self.module_defs = parse_model_cfg(cfg) - self.module_list, self.routs = create_modules(self.module_defs, img_size, cfg) - self.yolo_layers = get_yolo_layers(self) - # torch_utils.initialize_weights(self) - - # Darknet Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 - self.version = np.array([0, 2, 5], dtype=np.int32) # (int32) version info: major, minor, revision - self.seen = np.array([0], dtype=np.int64) # (int64) number of images seen during training - self.info(verbose) if not ONNX_EXPORT else None # print model description - - def forward(self, x, augment=False, verbose=False): - - if not augment: - return self.forward_once(x) - else: # Augment images (inference and test only) https://github.com/ultralytics/yolov3/issues/931 - img_size = x.shape[-2:] # height, width - s = [0.83, 0.67] # scales - y = [] - for i, xi in enumerate((x, - torch_utils.scale_img(x.flip(3), s[0], same_shape=False), # flip-lr and scale - torch_utils.scale_img(x, s[1], same_shape=False), # scale - )): - # cv2.imwrite('img%g.jpg' % i, 255 * xi[0].numpy().transpose((1, 2, 0))[:, :, ::-1]) - y.append(self.forward_once(xi)[0]) - - y[1][..., :4] /= s[0] # scale - y[1][..., 0] = img_size[1] - y[1][..., 0] # flip lr - y[2][..., :4] /= s[1] # scale - - # for i, yi in enumerate(y): # coco small, medium, large = < 32**2 < 96**2 < - # area = yi[..., 2:4].prod(2)[:, :, None] - # if i == 1: - # yi *= (area < 96. ** 2).float() - # elif i == 2: - # yi *= (area > 32. ** 2).float() - # y[i] = yi - - y = torch.cat(y, 1) - return y, None - - def forward_once(self, x, augment=False, verbose=False): - img_size = x.shape[-2:] # height, width - yolo_out, out = [], [] - if verbose: - print('0', x.shape) - str = '' - - # Augment images (inference and test only) - if augment: # https://github.com/ultralytics/yolov3/issues/931 - nb = x.shape[0] # batch size - s = [0.83, 0.67] # scales - x = torch.cat((x, - torch_utils.scale_img(x.flip(3), s[0]), # flip-lr and scale - torch_utils.scale_img(x, s[1]), # scale - ), 0) - - for i, module in enumerate(self.module_list): - name = module.__class__.__name__ - if name in ['WeightedFeatureFusion', 'FeatureConcat']: # sum, concat - if verbose: - l = [i - 1] + module.layers # layers - sh = [list(x.shape)] + [list(out[i].shape) for i in module.layers] # shapes - str = ' >> ' + ' + '.join(['layer %g %s' % x for x in zip(l, sh)]) - x = module(x, out) # WeightedFeatureFusion(), FeatureConcat() - elif name == 'YOLOLayer': - yolo_out.append(module(x, out)) - else: # run module directly, i.e. mtype = 'convolutional', 'upsample', 'maxpool', 'batchnorm2d' etc. - x = module(x) - - out.append(x if self.routs[i] else []) - if verbose: - print('%g/%g %s -' % (i, len(self.module_list), name), list(x.shape), str) - str = '' - - if self.training: # train - return yolo_out - elif ONNX_EXPORT: # export - x = [torch.cat(x, 0) for x in zip(*yolo_out)] - return x[0], torch.cat(x[1:3], 1) # scores, boxes: 3780x80, 3780x4 - else: # inference or test - x, p = zip(*yolo_out) # inference output, training output - x = torch.cat(x, 1) # cat yolo outputs - if augment: # de-augment results - x = torch.split(x, nb, dim=0) - x[1][..., :4] /= s[0] # scale - x[1][..., 0] = img_size[1] - x[1][..., 0] # flip lr - x[2][..., :4] /= s[1] # scale - x = torch.cat(x, 1) - return x, p - - def fuse(self): - # Fuse Conv2d + BatchNorm2d layers throughout model - print('Fusing layers...') - fused_list = nn.ModuleList() - for a in list(self.children())[0]: - if isinstance(a, nn.Sequential): - for i, b in enumerate(a): - if isinstance(b, nn.modules.batchnorm.BatchNorm2d): - # fuse this bn layer with the previous conv2d layer - conv = a[i - 1] - fused = torch_utils.fuse_conv_and_bn(conv, b) - a = nn.Sequential(fused, *list(a.children())[i + 1:]) - break - fused_list.append(a) - self.module_list = fused_list - self.info() if not ONNX_EXPORT else None # yolov3-spp reduced from 225 to 152 layers - - def info(self, verbose=False): - torch_utils.model_info(self, verbose) - - -def get_yolo_layers(model): - return [i for i, m in enumerate(model.module_list) if m.__class__.__name__ == 'YOLOLayer'] # [89, 101, 113] - - -def load_darknet_weights(self, weights, cutoff=-1): - # Parses and loads the weights stored in 'weights' - - # Establish cutoffs (load layers between 0 and cutoff. if cutoff = -1 all are loaded) - file = Path(weights).name - if file == 'darknet53.conv.74': - cutoff = 75 - elif file == 'yolov3-tiny.conv.15': - cutoff = 15 - - # Read weights file - with open(weights, 'rb') as f: - # Read Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 - self.version = np.fromfile(f, dtype=np.int32, count=3) # (int32) version info: major, minor, revision - self.seen = np.fromfile(f, dtype=np.int64, count=1) # (int64) number of images seen during training - - weights = np.fromfile(f, dtype=np.float32) # the rest are weights - - ptr = 0 - for i, (mdef, module) in enumerate(zip(self.module_defs[:cutoff], self.module_list[:cutoff])): - if mdef['type'] == 'convolutional': - conv = module[0] - if mdef['batch_normalize']: - # Load BN bias, weights, running mean and running variance - bn = module[1] - nb = bn.bias.numel() # number of biases - # Bias - bn.bias.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.bias)) - ptr += nb - # Weight - bn.weight.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.weight)) - ptr += nb - # Running Mean - bn.running_mean.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.running_mean)) - ptr += nb - # Running Var - bn.running_var.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.running_var)) - ptr += nb - else: - # Load conv. bias - nb = conv.bias.numel() - conv_b = torch.from_numpy(weights[ptr:ptr + nb]).view_as(conv.bias) - conv.bias.data.copy_(conv_b) - ptr += nb - # Load conv. weights - nw = conv.weight.numel() # number of weights - conv.weight.data.copy_(torch.from_numpy(weights[ptr:ptr + nw]).view_as(conv.weight)) - ptr += nw - - -def save_weights(self, path='model.weights', cutoff=-1): - # Converts a PyTorch model to Darket format (*.pt to *.weights) - # Note: Does not work if model.fuse() is applied - with open(path, 'wb') as f: - # Write Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 - self.version.tofile(f) # (int32) version info: major, minor, revision - self.seen.tofile(f) # (int64) number of images seen during training - - # Iterate through layers - for i, (mdef, module) in enumerate(zip(self.module_defs[:cutoff], self.module_list[:cutoff])): - if mdef['type'] == 'convolutional': - conv_layer = module[0] - # If batch norm, load bn first - if mdef['batch_normalize']: - bn_layer = module[1] - bn_layer.bias.data.cpu().numpy().tofile(f) - bn_layer.weight.data.cpu().numpy().tofile(f) - bn_layer.running_mean.data.cpu().numpy().tofile(f) - bn_layer.running_var.data.cpu().numpy().tofile(f) - # Load conv bias - else: - conv_layer.bias.data.cpu().numpy().tofile(f) - # Load conv weights - conv_layer.weight.data.cpu().numpy().tofile(f) - - -def convert(cfg='cfg/yolov3-spp.cfg', weights='weights/yolov3-spp.weights'): - # Converts between PyTorch and Darknet format per extension (i.e. *.weights convert to *.pt and vice versa) - # from models import *; convert('cfg/yolov3-spp.cfg', 'weights/yolov3-spp.weights') - - # Initialize model - model = Darknet(cfg) - - # Load weights and save - if weights.endswith('.pt'): # if PyTorch format - model.load_state_dict(torch.load(weights, map_location='cpu')['model']) - target = weights.rsplit('.', 1)[0] + '.weights' - save_weights(model, path=target, cutoff=-1) - print("Success: converted '%s' to '%s'" % (weights, target)) - - elif weights.endswith('.weights'): # darknet format - _ = load_darknet_weights(model, weights) - - chkpt = {'epoch': -1, - 'best_fitness': None, - 'training_results': None, - 'model': model.state_dict(), - 'optimizer': None} - - target = weights.rsplit('.', 1)[0] + '.pt' - torch.save(chkpt, target) - print("Success: converted '%s' to '%s'" % (weights, target)) - - else: - print('Error: extension not supported.') - - -def attempt_download(weights): - # Attempt to download pretrained weights if not found locally - weights = weights.strip().replace("'", '') - msg = weights + ' missing, try downloading from https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0' - - if len(weights) > 0 and not os.path.isfile(weights): - d = {'yolov3-spp.weights': '16lYS4bcIdM2HdmyJBVDOvt3Trx6N3W2R', - 'yolov3.weights': '1uTlyDWlnaqXcsKOktP5aH_zRDbfcDp-y', - 'yolov3-tiny.weights': '1CCF-iNIIkYesIDzaPvdwlcf7H9zSsKZQ', - 'yolov3-spp.pt': '1f6Ovy3BSq2wYq4UfvFUpxJFNDFfrIDcR', - 'yolov3.pt': '1SHNFyoe5Ni8DajDNEqgB2oVKBb_NoEad', - 'yolov3-tiny.pt': '10m_3MlpQwRtZetQxtksm9jqHrPTHZ6vo', - 'darknet53.conv.74': '1WUVBid-XuoUBmvzBVUCBl_ELrzqwA8dJ', - 'yolov3-tiny.conv.15': '1Bw0kCpplxUqyRYAJr9RY9SGnOJbo9nEj', - 'yolov3-spp-ultralytics.pt': '1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4'} - - file = Path(weights).name - if file in d: - r = gdrive_download(id=d[file], name=weights) - else: # download from pjreddie.com - url = 'https://pjreddie.com/media/files/' + file - print('Downloading ' + url) - r = os.system('curl -f ' + url + ' -o ' + weights) - - # Error check - if not (r == 0 and os.path.exists(weights) and os.path.getsize(weights) > 1E6): # weights exist and > 1MB - os.system('rm ' + weights) # remove partial downloads - raise Exception(msg) diff --git a/models/__init__.py b/models/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/models/common.py b/models/common.py new file mode 100644 index 0000000000..f23faa1d24 --- /dev/null +++ b/models/common.py @@ -0,0 +1,252 @@ +# This file contains modules common to various models + +import math + +import numpy as np +import torch +import torch.nn as nn +from PIL import Image, ImageDraw + +from utils.datasets import letterbox +from utils.general import non_max_suppression, make_divisible, scale_coords, xyxy2xywh +from utils.plots import color_list + + +def autopad(k, p=None): # kernel, padding + # Pad to 'same' + if p is None: + p = k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-pad + return p + + +def DWConv(c1, c2, k=1, s=1, act=True): + # Depthwise convolution + return Conv(c1, c2, k, s, g=math.gcd(c1, c2), act=act) + + +class Conv(nn.Module): + # Standard convolution + def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups + super(Conv, self).__init__() + self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False) + self.bn = nn.BatchNorm2d(c2) + self.act = nn.LeakyReLU(0.1) if act else nn.Identity() + + def forward(self, x): + return self.act(self.bn(self.conv(x))) + + def fuseforward(self, x): + return self.act(self.conv(x)) + + +class Bottleneck(nn.Module): + # Standard bottleneck + def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion + super(Bottleneck, self).__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = Conv(c_, c2, 3, 1, g=g) + self.add = shortcut and c1 == c2 + + def forward(self, x): + return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) + + +class BottleneckCSP(nn.Module): + # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion + super(BottleneckCSP, self).__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False) + self.cv3 = nn.Conv2d(c_, c_, 1, 1, bias=False) + self.cv4 = Conv(2 * c_, c2, 1, 1) + self.bn = nn.BatchNorm2d(2 * c_) # applied to cat(cv2, cv3) + self.act = nn.LeakyReLU(0.1, inplace=True) + self.m = nn.Sequential(*[Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)]) + + def forward(self, x): + y1 = self.cv3(self.m(self.cv1(x))) + y2 = self.cv2(x) + return self.cv4(self.act(self.bn(torch.cat((y1, y2), dim=1)))) + + +class SPP(nn.Module): + # Spatial pyramid pooling layer used in YOLOv3-SPP + def __init__(self, c1, c2, k=(5, 9, 13)): + super(SPP, self).__init__() + c_ = c1 // 2 # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = Conv(c_ * (len(k) + 1), c2, 1, 1) + self.m = nn.ModuleList([nn.MaxPool2d(kernel_size=x, stride=1, padding=x // 2) for x in k]) + + def forward(self, x): + x = self.cv1(x) + return self.cv2(torch.cat([x] + [m(x) for m in self.m], 1)) + + +class Focus(nn.Module): + # Focus wh information into c-space + def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups + super(Focus, self).__init__() + self.conv = Conv(c1 * 4, c2, k, s, p, g, act) + + def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2) + return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1)) + + +class Concat(nn.Module): + # Concatenate a list of tensors along dimension + def __init__(self, dimension=1): + super(Concat, self).__init__() + self.d = dimension + + def forward(self, x): + return torch.cat(x, self.d) + + +class NMS(nn.Module): + # Non-Maximum Suppression (NMS) module + conf = 0.25 # confidence threshold + iou = 0.45 # IoU threshold + classes = None # (optional list) filter by class + + def __init__(self): + super(NMS, self).__init__() + + def forward(self, x): + return non_max_suppression(x[0], conf_thres=self.conf, iou_thres=self.iou, classes=self.classes) + + +class autoShape(nn.Module): + # input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS + img_size = 640 # inference size (pixels) + conf = 0.25 # NMS confidence threshold + iou = 0.45 # NMS IoU threshold + classes = None # (optional list) filter by class + + def __init__(self, model): + super(autoShape, self).__init__() + self.model = model.eval() + + def forward(self, imgs, size=640, augment=False, profile=False): + # supports inference from various sources. For height=720, width=1280, RGB images example inputs are: + # opencv: imgs = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(720,1280,3) + # PIL: imgs = Image.open('image.jpg') # HWC x(720,1280,3) + # numpy: imgs = np.zeros((720,1280,3)) # HWC + # torch: imgs = torch.zeros(16,3,720,1280) # BCHW + # multiple: imgs = [Image.open('image1.jpg'), Image.open('image2.jpg'), ...] # list of images + + p = next(self.model.parameters()) # for device and type + if isinstance(imgs, torch.Tensor): # torch + return self.model(imgs.to(p.device).type_as(p), augment, profile) # inference + + # Pre-process + if not isinstance(imgs, list): + imgs = [imgs] + shape0, shape1 = [], [] # image and inference shapes + batch = range(len(imgs)) # batch size + for i in batch: + imgs[i] = np.array(imgs[i]) # to numpy + if imgs[i].shape[0] < 5: # image in CHW + imgs[i] = imgs[i].transpose((1, 2, 0)) # reverse dataloader .transpose(2, 0, 1) + imgs[i] = imgs[i][:, :, :3] if imgs[i].ndim == 3 else np.tile(imgs[i][:, :, None], 3) # enforce 3ch input + s = imgs[i].shape[:2] # HWC + shape0.append(s) # image shape + g = (size / max(s)) # gain + shape1.append([y * g for y in s]) + shape1 = [make_divisible(x, int(self.stride.max())) for x in np.stack(shape1, 0).max(0)] # inference shape + x = [letterbox(imgs[i], new_shape=shape1, auto=False)[0] for i in batch] # pad + x = np.stack(x, 0) if batch[-1] else x[0][None] # stack + x = np.ascontiguousarray(x.transpose((0, 3, 1, 2))) # BHWC to BCHW + x = torch.from_numpy(x).to(p.device).type_as(p) / 255. # uint8 to fp16/32 + + # Inference + with torch.no_grad(): + y = self.model(x, augment, profile)[0] # forward + y = non_max_suppression(y, conf_thres=self.conf, iou_thres=self.iou, classes=self.classes) # NMS + + # Post-process + for i in batch: + if y[i] is not None: + y[i][:, :4] = scale_coords(shape1, y[i][:, :4], shape0[i]) + + return Detections(imgs, y, self.names) + + +class Detections: + # detections class for YOLOv5 inference results + def __init__(self, imgs, pred, names=None): + super(Detections, self).__init__() + self.imgs = imgs # list of images as numpy arrays + self.pred = pred # list of tensors pred[0] = (xyxy, conf, cls) + self.names = names # class names + self.xyxy = pred # xyxy pixels + self.xywh = [xyxy2xywh(x) for x in pred] # xywh pixels + d = pred[0].device # device + gn = [torch.tensor([*[im.shape[i] for i in [1, 0, 1, 0]], 1., 1.], device=d) for im in imgs] # normalizations + self.xyxyn = [x / g for x, g in zip(self.xyxy, gn)] # xyxy normalized + self.xywhn = [x / g for x, g in zip(self.xywh, gn)] # xywh normalized + self.n = len(self.pred) + + def display(self, pprint=False, show=False, save=False): + colors = color_list() + for i, (img, pred) in enumerate(zip(self.imgs, self.pred)): + str = f'Image {i + 1}/{len(self.pred)}: {img.shape[0]}x{img.shape[1]} ' + if pred is not None: + for c in pred[:, -1].unique(): + n = (pred[:, -1] == c).sum() # detections per class + str += f'{n} {self.names[int(c)]}s, ' # add to string + if show or save: + img = Image.fromarray(img.astype(np.uint8)) if isinstance(img, np.ndarray) else img # from np + for *box, conf, cls in pred: # xyxy, confidence, class + # str += '%s %.2f, ' % (names[int(cls)], conf) # label + ImageDraw.Draw(img).rectangle(box, width=4, outline=colors[int(cls) % 10]) # plot + if save: + f = f'results{i}.jpg' + str += f"saved to '{f}'" + img.save(f) # save + if show: + img.show(f'Image {i}') # show + if pprint: + print(str) + + def print(self): + self.display(pprint=True) # print results + + def show(self): + self.display(show=True) # show results + + def save(self): + self.display(save=True) # save results + + def __len__(self): + return self.n + + def tolist(self): + # return a list of Detections objects, i.e. 'for result in results.tolist():' + x = [Detections([self.imgs[i]], [self.pred[i]], self.names) for i in range(self.n)] + for d in x: + for k in ['imgs', 'pred', 'xyxy', 'xyxyn', 'xywh', 'xywhn']: + setattr(d, k, getattr(d, k)[0]) # pop out of list + return x + + +class Flatten(nn.Module): + # Use after nn.AdaptiveAvgPool2d(1) to remove last 2 dimensions + @staticmethod + def forward(x): + return x.view(x.size(0), -1) + + +class Classify(nn.Module): + # Classification head, i.e. x(b,c1,20,20) to x(b,c2) + def __init__(self, c1, c2, k=1, s=1, p=None, g=1): # ch_in, ch_out, kernel, stride, padding, groups + super(Classify, self).__init__() + self.aap = nn.AdaptiveAvgPool2d(1) # to x(b,c1,1,1) + self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False) # to x(b,c2,1,1) + self.flat = Flatten() + + def forward(self, x): + z = torch.cat([self.aap(y) for y in (x if isinstance(x, list) else [x])], 1) # cat if list + return self.flat(self.conv(z)) # flatten to x(b,c2) diff --git a/models/experimental.py b/models/experimental.py new file mode 100644 index 0000000000..a2908a15cf --- /dev/null +++ b/models/experimental.py @@ -0,0 +1,152 @@ +# This file contains experimental modules + +import numpy as np +import torch +import torch.nn as nn + +from models.common import Conv, DWConv +from utils.google_utils import attempt_download + + +class CrossConv(nn.Module): + # Cross Convolution Downsample + def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False): + # ch_in, ch_out, kernel, stride, groups, expansion, shortcut + super(CrossConv, self).__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, (1, k), (1, s)) + self.cv2 = Conv(c_, c2, (k, 1), (s, 1), g=g) + self.add = shortcut and c1 == c2 + + def forward(self, x): + return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) + + +class C3(nn.Module): + # Cross Convolution CSP + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion + super(C3, self).__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False) + self.cv3 = nn.Conv2d(c_, c_, 1, 1, bias=False) + self.cv4 = Conv(2 * c_, c2, 1, 1) + self.bn = nn.BatchNorm2d(2 * c_) # applied to cat(cv2, cv3) + self.act = nn.LeakyReLU(0.1, inplace=True) + self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)]) + + def forward(self, x): + y1 = self.cv3(self.m(self.cv1(x))) + y2 = self.cv2(x) + return self.cv4(self.act(self.bn(torch.cat((y1, y2), dim=1)))) + + +class Sum(nn.Module): + # Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, n, weight=False): # n: number of inputs + super(Sum, self).__init__() + self.weight = weight # apply weights boolean + self.iter = range(n - 1) # iter object + if weight: + self.w = nn.Parameter(-torch.arange(1., n) / 2, requires_grad=True) # layer weights + + def forward(self, x): + y = x[0] # no weight + if self.weight: + w = torch.sigmoid(self.w) * 2 + for i in self.iter: + y = y + x[i + 1] * w[i] + else: + for i in self.iter: + y = y + x[i + 1] + return y + + +class GhostConv(nn.Module): + # Ghost Convolution https://github.com/huawei-noah/ghostnet + def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups + super(GhostConv, self).__init__() + c_ = c2 // 2 # hidden channels + self.cv1 = Conv(c1, c_, k, s, None, g, act) + self.cv2 = Conv(c_, c_, 5, 1, None, c_, act) + + def forward(self, x): + y = self.cv1(x) + return torch.cat([y, self.cv2(y)], 1) + + +class GhostBottleneck(nn.Module): + # Ghost Bottleneck https://github.com/huawei-noah/ghostnet + def __init__(self, c1, c2, k, s): + super(GhostBottleneck, self).__init__() + c_ = c2 // 2 + self.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # pw + DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw + GhostConv(c_, c2, 1, 1, act=False)) # pw-linear + self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False), + Conv(c1, c2, 1, 1, act=False)) if s == 2 else nn.Identity() + + def forward(self, x): + return self.conv(x) + self.shortcut(x) + + +class MixConv2d(nn.Module): + # Mixed Depthwise Conv https://arxiv.org/abs/1907.09595 + def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): + super(MixConv2d, self).__init__() + groups = len(k) + if equal_ch: # equal c_ per group + i = torch.linspace(0, groups - 1E-6, c2).floor() # c2 indices + c_ = [(i == g).sum() for g in range(groups)] # intermediate channels + else: # equal weight.numel() per group + b = [c2] + [0] * groups + a = np.eye(groups + 1, groups, k=-1) + a -= np.roll(a, 1, axis=1) + a *= np.array(k) ** 2 + a[0] = 1 + c_ = np.linalg.lstsq(a, b, rcond=None)[0].round() # solve for equal weight indices, ax = b + + self.m = nn.ModuleList([nn.Conv2d(c1, int(c_[g]), k[g], s, k[g] // 2, bias=False) for g in range(groups)]) + self.bn = nn.BatchNorm2d(c2) + self.act = nn.LeakyReLU(0.1, inplace=True) + + def forward(self, x): + return x + self.act(self.bn(torch.cat([m(x) for m in self.m], 1))) + + +class Ensemble(nn.ModuleList): + # Ensemble of models + def __init__(self): + super(Ensemble, self).__init__() + + def forward(self, x, augment=False): + y = [] + for module in self: + y.append(module(x, augment)[0]) + # y = torch.stack(y).max(0)[0] # max ensemble + # y = torch.cat(y, 1) # nms ensemble + y = torch.stack(y).mean(0) # mean ensemble + return y, None # inference, train output + + +def attempt_load(weights, map_location=None): + # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a + model = Ensemble() + for w in weights if isinstance(weights, list) else [weights]: + attempt_download(w) + model.append(torch.load(w, map_location=map_location)['model'].float().fuse().eval()) # load FP32 model + + # Compatibility updates + for m in model.modules(): + if type(m) in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6]: + m.inplace = True # pytorch 1.7.0 compatibility + elif type(m) is Conv: + m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility + + if len(model) == 1: + return model[-1] # return model + else: + print('Ensemble created with %s\n' % weights) + for k in ['names', 'stride']: + setattr(model, k, getattr(model[-1], k)) + return model # return ensemble diff --git a/models/export.py b/models/export.py new file mode 100644 index 0000000000..7fbc3d9599 --- /dev/null +++ b/models/export.py @@ -0,0 +1,94 @@ +"""Exports a YOLOv5 *.pt model to ONNX and TorchScript formats + +Usage: + $ export PYTHONPATH="$PWD" && python models/export.py --weights ./weights/yolov3.pt --img 640 --batch 1 +""" + +import argparse +import sys +import time + +sys.path.append('./') # to run '$ python *.py' files in subdirectories + +import torch +import torch.nn as nn + +import models +from models.experimental import attempt_load +from utils.activations import Hardswish +from utils.general import set_logging, check_img_size + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default='./yolov3.pt', help='weights path') # from yolov3/models/ + parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='image size') # height, width + parser.add_argument('--batch-size', type=int, default=1, help='batch size') + opt = parser.parse_args() + opt.img_size *= 2 if len(opt.img_size) == 1 else 1 # expand + print(opt) + set_logging() + t = time.time() + + # Load PyTorch model + model = attempt_load(opt.weights, map_location=torch.device('cpu')) # load FP32 model + labels = model.names + + # Checks + gs = int(max(model.stride)) # grid size (max stride) + opt.img_size = [check_img_size(x, gs) for x in opt.img_size] # verify img_size are gs-multiples + + # Input + img = torch.zeros(opt.batch_size, 3, *opt.img_size) # image size(1,3,320,192) iDetection + + # Update model + for k, m in model.named_modules(): + m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility + if isinstance(m, models.common.Conv) and isinstance(m.act, nn.Hardswish): + m.act = Hardswish() # assign activation + # if isinstance(m, models.yolo.Detect): + # m.forward = m.forward_export # assign forward (optional) + model.model[-1].export = True # set Detect() layer export=True + y = model(img) # dry run + + # TorchScript export + try: + print('\nStarting TorchScript export with torch %s...' % torch.__version__) + f = opt.weights.replace('.pt', '.torchscript.pt') # filename + ts = torch.jit.trace(model, img) + ts.save(f) + print('TorchScript export success, saved as %s' % f) + except Exception as e: + print('TorchScript export failure: %s' % e) + + # ONNX export + try: + import onnx + + print('\nStarting ONNX export with onnx %s...' % onnx.__version__) + f = opt.weights.replace('.pt', '.onnx') # filename + torch.onnx.export(model, img, f, verbose=False, opset_version=12, input_names=['images'], + output_names=['classes', 'boxes'] if y is None else ['output']) + + # Checks + onnx_model = onnx.load(f) # load onnx model + onnx.checker.check_model(onnx_model) # check onnx model + # print(onnx.helper.printable_graph(onnx_model.graph)) # print a human readable model + print('ONNX export success, saved as %s' % f) + except Exception as e: + print('ONNX export failure: %s' % e) + + # CoreML export + try: + import coremltools as ct + + print('\nStarting CoreML export with coremltools %s...' % ct.__version__) + # convert model from torchscript and apply pixel scaling as per detect.py + model = ct.convert(ts, inputs=[ct.ImageType(name='image', shape=img.shape, scale=1 / 255.0, bias=[0, 0, 0])]) + f = opt.weights.replace('.pt', '.mlmodel') # filename + model.save(f) + print('CoreML export success, saved as %s' % f) + except Exception as e: + print('CoreML export failure: %s' % e) + + # Finish + print('\nExport complete (%.2fs). Visualize with https://github.com/lutzroeder/netron.' % (time.time() - t)) diff --git a/models/yolo.py b/models/yolo.py new file mode 100644 index 0000000000..8978fb95c7 --- /dev/null +++ b/models/yolo.py @@ -0,0 +1,287 @@ +import argparse +import logging +import math +import sys +from copy import deepcopy +from pathlib import Path + +sys.path.append('./') # to run '$ python *.py' files in subdirectories +logger = logging.getLogger(__name__) + +import torch +import torch.nn as nn + +from models.common import Conv, Bottleneck, SPP, DWConv, Focus, BottleneckCSP, Concat, NMS, autoShape +from models.experimental import MixConv2d, CrossConv, C3 +from utils.autoanchor import check_anchor_order +from utils.general import make_divisible, check_file, set_logging +from utils.torch_utils import time_synchronized, fuse_conv_and_bn, model_info, scale_img, initialize_weights, \ + select_device, copy_attr + +try: + import thop # for FLOPS computation +except ImportError: + thop = None + + +class Detect(nn.Module): + stride = None # strides computed during build + export = False # onnx export + + def __init__(self, nc=80, anchors=(), ch=()): # detection layer + super(Detect, self).__init__() + self.nc = nc # number of classes + self.no = nc + 5 # number of outputs per anchor + self.nl = len(anchors) # number of detection layers + self.na = len(anchors[0]) // 2 # number of anchors + self.grid = [torch.zeros(1)] * self.nl # init grid + a = torch.tensor(anchors).float().view(self.nl, -1, 2) + self.register_buffer('anchors', a) # shape(nl,na,2) + self.register_buffer('anchor_grid', a.clone().view(self.nl, 1, -1, 1, 1, 2)) # shape(nl,1,na,1,1,2) + self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv + + def forward(self, x): + # x = x.copy() # for profiling + z = [] # inference output + self.training |= self.export + for i in range(self.nl): + x[i] = self.m[i](x[i]) # conv + bs, _, ny, nx = x[i].shape # x(bs,255,20,20) to x(bs,3,20,20,85) + x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous() + + if not self.training: # inference + if self.grid[i].shape[2:4] != x[i].shape[2:4]: + self.grid[i] = self._make_grid(nx, ny).to(x[i].device) + + y = x[i].sigmoid() + y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + self.grid[i].to(x[i].device)) * self.stride[i] # xy + y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh + z.append(y.view(bs, -1, self.no)) + + return x if self.training else (torch.cat(z, 1), x) + + @staticmethod + def _make_grid(nx=20, ny=20): + yv, xv = torch.meshgrid([torch.arange(ny), torch.arange(nx)]) + return torch.stack((xv, yv), 2).view((1, 1, ny, nx, 2)).float() + + +class Model(nn.Module): + def __init__(self, cfg='yolov3.yaml', ch=3, nc=None): # model, input channels, number of classes + super(Model, self).__init__() + if isinstance(cfg, dict): + self.yaml = cfg # model dict + else: # is *.yaml + import yaml # for torch hub + self.yaml_file = Path(cfg).name + with open(cfg) as f: + self.yaml = yaml.load(f, Loader=yaml.FullLoader) # model dict + + # Define model + if nc and nc != self.yaml['nc']: + logger.info('Overriding model.yaml nc=%g with nc=%g' % (self.yaml['nc'], nc)) + self.yaml['nc'] = nc # override yaml value + self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelist, ch_out + # print([x.shape for x in self.forward(torch.zeros(1, ch, 64, 64))]) + + # Build strides, anchors + m = self.model[-1] # Detect() + if isinstance(m, Detect): + s = 128 # 2x min stride + m.stride = torch.tensor([s / x.shape[-2] for x in self.forward(torch.zeros(1, ch, s, s))]) # forward + m.anchors /= m.stride.view(-1, 1, 1) + check_anchor_order(m) + self.stride = m.stride + self._initialize_biases() # only run once + # print('Strides: %s' % m.stride.tolist()) + + # Init weights, biases + initialize_weights(self) + self.info() + logger.info('') + + def forward(self, x, augment=False, profile=False): + if augment: + img_size = x.shape[-2:] # height, width + s = [1, 0.83, 0.67] # scales + f = [None, 3, None] # flips (2-ud, 3-lr) + y = [] # outputs + for si, fi in zip(s, f): + xi = scale_img(x.flip(fi) if fi else x, si) + yi = self.forward_once(xi)[0] # forward + # cv2.imwrite('img%g.jpg' % s, 255 * xi[0].numpy().transpose((1, 2, 0))[:, :, ::-1]) # save + yi[..., :4] /= si # de-scale + if fi == 2: + yi[..., 1] = img_size[0] - yi[..., 1] # de-flip ud + elif fi == 3: + yi[..., 0] = img_size[1] - yi[..., 0] # de-flip lr + y.append(yi) + return torch.cat(y, 1), None # augmented inference, train + else: + return self.forward_once(x, profile) # single-scale inference, train + + def forward_once(self, x, profile=False): + y, dt = [], [] # outputs + for m in self.model: + if m.f != -1: # if not from previous layer + x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers + + if profile: + o = thop.profile(m, inputs=(x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPS + t = time_synchronized() + for _ in range(10): + _ = m(x) + dt.append((time_synchronized() - t) * 100) + print('%10.1f%10.0f%10.1fms %-40s' % (o, m.np, dt[-1], m.type)) + + x = m(x) # run + y.append(x if m.i in self.save else None) # save output + + if profile: + print('%.1fms total' % sum(dt)) + return x + + def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is class frequency + # https://arxiv.org/abs/1708.02002 section 3.3 + # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1. + m = self.model[-1] # Detect() module + for mi, s in zip(m.m, m.stride): # from + b = mi.bias.view(m.na, -1) # conv.bias(255) to (3,85) + b[:, 4] += math.log(8 / (640 / s) ** 2) # obj (8 objects per 640 image) + b[:, 5:] += math.log(0.6 / (m.nc - 0.99)) if cf is None else torch.log(cf / cf.sum()) # cls + mi.bias = torch.nn.Parameter(b.view(-1), requires_grad=True) + + def _print_biases(self): + m = self.model[-1] # Detect() module + for mi in m.m: # from + b = mi.bias.detach().view(m.na, -1).T # conv.bias(255) to (3,85) + print(('%6g Conv2d.bias:' + '%10.3g' * 6) % (mi.weight.shape[1], *b[:5].mean(1).tolist(), b[5:].mean())) + + # def _print_weights(self): + # for m in self.model.modules(): + # if type(m) is Bottleneck: + # print('%10.3g' % (m.w.detach().sigmoid() * 2)) # shortcut weights + + def fuse(self): # fuse model Conv2d() + BatchNorm2d() layers + print('Fusing layers... ') + for m in self.model.modules(): + if type(m) is Conv and hasattr(m, 'bn'): + m.conv = fuse_conv_and_bn(m.conv, m.bn) # update conv + delattr(m, 'bn') # remove batchnorm + m.forward = m.fuseforward # update forward + self.info() + return self + + def nms(self, mode=True): # add or remove NMS module + present = type(self.model[-1]) is NMS # last layer is NMS + if mode and not present: + print('Adding NMS... ') + m = NMS() # module + m.f = -1 # from + m.i = self.model[-1].i + 1 # index + self.model.add_module(name='%s' % m.i, module=m) # add + self.eval() + elif not mode and present: + print('Removing NMS... ') + self.model = self.model[:-1] # remove + return self + + def autoshape(self): # add autoShape module + print('Adding autoShape... ') + m = autoShape(self) # wrap model + copy_attr(m, self, include=('yaml', 'nc', 'hyp', 'names', 'stride'), exclude=()) # copy attributes + return m + + def info(self, verbose=False, img_size=640): # print model information + model_info(self, verbose, img_size) + + +def parse_model(d, ch): # model_dict, input_channels(3) + logger.info('\n%3s%18s%3s%10s %-40s%-30s' % ('', 'from', 'n', 'params', 'module', 'arguments')) + anchors, nc, gd, gw = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'] + na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors + no = na * (nc + 5) # number of outputs = anchors * (classes + 5) + + layers, save, c2 = [], [], ch[-1] # layers, savelist, ch out + for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, args + m = eval(m) if isinstance(m, str) else m # eval strings + for j, a in enumerate(args): + try: + args[j] = eval(a) if isinstance(a, str) else a # eval strings + except: + pass + + n = max(round(n * gd), 1) if n > 1 else n # depth gain + if m in [Conv, Bottleneck, SPP, DWConv, MixConv2d, Focus, CrossConv, BottleneckCSP, C3]: + c1, c2 = ch[f], args[0] + + # Normal + # if i > 0 and args[0] != no: # channel expansion factor + # ex = 1.75 # exponential (default 2.0) + # e = math.log(c2 / ch[1]) / math.log(2) + # c2 = int(ch[1] * ex ** e) + # if m != Focus: + + c2 = make_divisible(c2 * gw, 8) if c2 != no else c2 + + # Experimental + # if i > 0 and args[0] != no: # channel expansion factor + # ex = 1 + gw # exponential (default 2.0) + # ch1 = 32 # ch[1] + # e = math.log(c2 / ch1) / math.log(2) # level 1-n + # c2 = int(ch1 * ex ** e) + # if m != Focus: + # c2 = make_divisible(c2, 8) if c2 != no else c2 + + args = [c1, c2, *args[1:]] + if m in [BottleneckCSP, C3]: + args.insert(2, n) + n = 1 + elif m is nn.BatchNorm2d: + args = [ch[f]] + elif m is nn.ZeroPad2d: + args = [args] + c2 = ch[f] + elif m is Concat: + c2 = sum([ch[-1 if x == -1 else x + 1] for x in f]) + elif m is Detect: + args.append([ch[x + 1] for x in f]) + if isinstance(args[1], int): # number of anchors + args[1] = [list(range(args[1] * 2))] * len(f) + else: + c2 = ch[f] + + m_ = nn.Sequential(*[m(*args) for _ in range(n)]) if n > 1 else m(*args) # module + t = str(m)[8:-2].replace('__main__.', '') # module type + np = sum([x.numel() for x in m_.parameters()]) # number params + m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params + logger.info('%3s%18s%3s%10.0f %-40s%-30s' % (i, f, n, np, t, args)) # print + save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist + layers.append(m_) + ch.append(c2) + return nn.Sequential(*layers), sorted(save) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--cfg', type=str, default='yolov3.yaml', help='model.yaml') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + opt = parser.parse_args() + opt.cfg = check_file(opt.cfg) # check file + set_logging() + device = select_device(opt.device) + + # Create model + model = Model(opt.cfg).to(device) + model.train() + + # Profile + # img = torch.rand(8 if torch.cuda.is_available() else 1, 3, 640, 640).to(device) + # y = model(img, profile=True) + + # Tensorboard + # from torch.utils.tensorboard import SummaryWriter + # tb_writer = SummaryWriter() + # print("Run 'tensorboard --logdir=models/runs' to view tensorboard at http://localhost:6006/") + # tb_writer.add_graph(model.model, img) # add model to tensorboard + # tb_writer.add_image('test', img[0], dataformats='CWH') # add model to tensorboard diff --git a/models/yolov3-spp.yaml b/models/yolov3-spp.yaml new file mode 100644 index 0000000000..38dcc449f0 --- /dev/null +++ b/models/yolov3-spp.yaml @@ -0,0 +1,51 @@ +# parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple + +# anchors +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# darknet53 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [32, 3, 1]], # 0 + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + [-1, 1, Bottleneck, [64]], + [-1, 1, Conv, [128, 3, 2]], # 3-P2/4 + [-1, 2, Bottleneck, [128]], + [-1, 1, Conv, [256, 3, 2]], # 5-P3/8 + [-1, 8, Bottleneck, [256]], + [-1, 1, Conv, [512, 3, 2]], # 7-P4/16 + [-1, 8, Bottleneck, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P5/32 + [-1, 4, Bottleneck, [1024]], # 10 + ] + +# YOLOv3-SPP head +head: + [[-1, 1, Bottleneck, [1024, False]], + [-1, 1, SPP, [512, [5, 9, 13]]], + [-1, 1, Conv, [1024, 3, 1]], + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large) + + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 8], 1, Concat, [1]], # cat backbone P4 + [-1, 1, Bottleneck, [512, False]], + [-1, 1, Bottleneck, [512, False]], + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium) + + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P3 + [-1, 1, Bottleneck, [256, False]], + [-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small) + + [[27, 22, 15], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/models/yolov3-tiny.yaml b/models/yolov3-tiny.yaml new file mode 100644 index 0000000000..85f9fbd498 --- /dev/null +++ b/models/yolov3-tiny.yaml @@ -0,0 +1,41 @@ +# parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple + +# anchors +anchors: + - [10,14, 23,27, 37,58] # P4/16 + - [81,82, 135,169, 344,319] # P5/32 + +# YOLOv3-tiny backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [16, 3, 1]], # 0 + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 1-P1/2 + [-1, 1, Conv, [32, 3, 1]], + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 3-P2/4 + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 5-P3/8 + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 7-P4/16 + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 9-P5/32 + [-1, 1, Conv, [512, 3, 1]], + [-1, 1, nn.ZeroPad2d, [0, 1, 0, 1]], # 11 + [-1, 1, nn.MaxPool2d, [2, 1, 0]], # 12 + ] + +# YOLOv3-tiny head +head: + [[-1, 1, Conv, [1024, 3, 1]], + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [512, 3, 1]], # 15 (P5/32-large) + + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 8], 1, Concat, [1]], # cat backbone P4 + [-1, 1, Conv, [256, 3, 1]], # 19 (P4/16-medium) + + [[19, 15], 1, Detect, [nc, anchors]], # Detect(P4, P5) + ] diff --git a/models/yolov3.yaml b/models/yolov3.yaml new file mode 100644 index 0000000000..f2e7613554 --- /dev/null +++ b/models/yolov3.yaml @@ -0,0 +1,51 @@ +# parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple + +# anchors +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# darknet53 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [32, 3, 1]], # 0 + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + [-1, 1, Bottleneck, [64]], + [-1, 1, Conv, [128, 3, 2]], # 3-P2/4 + [-1, 2, Bottleneck, [128]], + [-1, 1, Conv, [256, 3, 2]], # 5-P3/8 + [-1, 8, Bottleneck, [256]], + [-1, 1, Conv, [512, 3, 2]], # 7-P4/16 + [-1, 8, Bottleneck, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P5/32 + [-1, 4, Bottleneck, [1024]], # 10 + ] + +# YOLOv3 head +head: + [[-1, 1, Bottleneck, [1024, False]], + [-1, 1, Conv, [512, [1, 1]]], + [-1, 1, Conv, [1024, 3, 1]], + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large) + + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 8], 1, Concat, [1]], # cat backbone P4 + [-1, 1, Bottleneck, [512, False]], + [-1, 1, Bottleneck, [512, False]], + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium) + + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P3 + [-1, 1, Bottleneck, [256, False]], + [-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small) + + [[27, 22, 15], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/requirements.txt b/requirements.txt index 50efbd1019..f9fc9fc298 100755 --- a/requirements.txt +++ b/requirements.txt @@ -5,23 +5,26 @@ Cython matplotlib>=3.2.2 numpy>=1.18.5 opencv-python>=4.1.2 -pillow +Pillow PyYAML>=5.3 scipy>=1.4.1 tensorboard>=2.2 -torch>=1.6.0 -torchvision>=0.7.0 +torch>=1.7.0 +torchvision>=0.8.1 tqdm>=4.41.0 -# coco ---------------------------------------- -# pycocotools>=2.0 +# logging ------------------------------------- +# wandb + +# plotting ------------------------------------ +seaborn +pandas # export -------------------------------------- -# packaging # for coremltools -# coremltools==4.0b3 -# onnx>=1.7.0 +# coremltools==4.0 +# onnx>=1.8.0 # scikit-learn==0.19.2 # for coreml quantization # extras -------------------------------------- # thop # FLOPS computation -# seaborn # plotting +# pycocotools>=2.0 # COCO mAP diff --git a/test.py b/test.py index 4d68438eb4..d62afd7dec 100644 --- a/test.py +++ b/test.py @@ -1,136 +1,170 @@ import argparse +import glob import json +import os +from pathlib import Path -from torch.utils.data import DataLoader +import numpy as np +import torch +import yaml +from tqdm import tqdm -from models import * -from utils.datasets import * -from utils.utils import * +from models.experimental import attempt_load +from utils.datasets import create_dataloader +from utils.general import coco80_to_coco91_class, check_dataset, check_file, check_img_size, box_iou, \ + non_max_suppression, scale_coords, xyxy2xywh, xywh2xyxy, set_logging, increment_path +from utils.loss import compute_loss +from utils.metrics import ap_per_class, ConfusionMatrix +from utils.plots import plot_images, output_to_target, plot_study_txt +from utils.torch_utils import select_device, time_synchronized -def test(cfg, - data, +def test(data, weights=None, - batch_size=16, - imgsz=416, + batch_size=32, + imgsz=640, conf_thres=0.001, - iou_thres=0.6, # for nms + iou_thres=0.6, # for NMS save_json=False, single_cls=False, augment=False, + verbose=False, model=None, dataloader=None, - multi_label=True): + save_dir=Path(''), # for saving images + save_txt=False, # for auto-labelling + save_conf=False, + plots=True, + log_imgs=0): # number of logged images + # Initialize/load model and set device - if model is None: - is_training = False - device = torch_utils.select_device(opt.device, batch_size=batch_size) - verbose = opt.task == 'test' - - # Remove previous - for f in glob.glob('test_batch*.jpg'): - os.remove(f) - - # Initialize model - model = Darknet(cfg, imgsz) - - # Load weights - attempt_download(weights) - if weights.endswith('.pt'): # pytorch format - model.load_state_dict(torch.load(weights, map_location=device)['model']) - else: # darknet format - load_darknet_weights(model, weights) - - # Fuse - model.fuse() - model.to(device) - - if device.type != 'cpu' and torch.cuda.device_count() > 1: - model = nn.DataParallel(model) - else: # called by train.py - is_training = True + training = model is not None + if training: # called by train.py device = next(model.parameters()).device # get model device - verbose = False - # Configure run - data = parse_data_cfg(data) - nc = 1 if single_cls else int(data['classes']) # number of classes - path = data['valid'] # path to test images - names = load_classes(data['names']) # class names + else: # called directly + set_logging() + device = select_device(opt.device, batch_size=batch_size) + save_txt = opt.save_txt # save *.txt labels + + # Directories + save_dir = Path(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + model = attempt_load(weights, map_location=device) # load FP32 model + imgsz = check_img_size(imgsz, s=model.stride.max()) # check img_size + + # Multi-GPU disabled, incompatible with .half() https://github.com/ultralytics/yolov5/issues/99 + # if device.type != 'cpu' and torch.cuda.device_count() > 1: + # model = nn.DataParallel(model) + + # Half + half = device.type != 'cpu' # half precision only supported on CUDA + if half: + model.half() + + # Configure + model.eval() + is_coco = data.endswith('coco.yaml') # is COCO dataset + with open(data) as f: + data = yaml.load(f, Loader=yaml.FullLoader) # model dict + check_dataset(data) # check + nc = 1 if single_cls else int(data['nc']) # number of classes iouv = torch.linspace(0.5, 0.95, 10).to(device) # iou vector for mAP@0.5:0.95 - iouv = iouv[0].view(1) # comment for mAP@0.5:0.95 niou = iouv.numel() + # Logging + log_imgs, wandb = min(log_imgs, 100), None # ceil + try: + import wandb # Weights & Biases + except ImportError: + log_imgs = 0 + # Dataloader - if dataloader is None: - dataset = LoadImagesAndLabels(path, imgsz, batch_size, rect=True, single_cls=opt.single_cls, pad=0.5) - batch_size = min(batch_size, len(dataset)) - dataloader = DataLoader(dataset, - batch_size=batch_size, - num_workers=min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8]), - pin_memory=True, - collate_fn=dataset.collate_fn) + if not training: + img = torch.zeros((1, 3, imgsz, imgsz), device=device) # init img + _ = model(img.half() if half else img) if device.type != 'cpu' else None # run once + path = data['test'] if opt.task == 'test' else data['val'] # path to val/test images + dataloader = create_dataloader(path, imgsz, batch_size, model.stride.max(), opt, pad=0.5, rect=True)[0] seen = 0 - model.eval() - _ = model(torch.zeros((1, 3, imgsz, imgsz), device=device)) if device.type != 'cpu' else None # run once + confusion_matrix = ConfusionMatrix(nc=nc) + names = {k: v for k, v in enumerate(model.names if hasattr(model, 'names') else model.module.names)} coco91class = coco80_to_coco91_class() - s = ('%20s' + '%10s' * 6) % ('Class', 'Images', 'Targets', 'P', 'R', 'mAP@0.5', 'F1') - p, r, f1, mp, mr, map, mf1, t0, t1 = 0., 0., 0., 0., 0., 0., 0., 0., 0. + s = ('%20s' + '%12s' * 6) % ('Class', 'Images', 'Targets', 'P', 'R', 'mAP@.5', 'mAP@.5:.95') + p, r, f1, mp, mr, map50, map, t0, t1 = 0., 0., 0., 0., 0., 0., 0., 0., 0. loss = torch.zeros(3, device=device) - jdict, stats, ap, ap_class = [], [], [], [] - for batch_i, (imgs, targets, paths, shapes) in enumerate(tqdm(dataloader, desc=s)): - imgs = imgs.to(device).float() / 255.0 # uint8 to float32, 0 - 255 to 0.0 - 1.0 + jdict, stats, ap, ap_class, wandb_images = [], [], [], [], [] + for batch_i, (img, targets, paths, shapes) in enumerate(tqdm(dataloader, desc=s)): + img = img.to(device, non_blocking=True) + img = img.half() if half else img.float() # uint8 to fp16/32 + img /= 255.0 # 0 - 255 to 0.0 - 1.0 targets = targets.to(device) - nb, _, height, width = imgs.shape # batch size, channels, height, width - whwh = torch.Tensor([width, height, width, height]).to(device) + nb, _, height, width = img.shape # batch size, channels, height, width - # Disable gradients with torch.no_grad(): # Run model - t = torch_utils.time_synchronized() - inf_out, train_out = model(imgs, augment=augment) # inference and training outputs - t0 += torch_utils.time_synchronized() - t + t = time_synchronized() + inf_out, train_out = model(img, augment=augment) # inference and training outputs + t0 += time_synchronized() - t # Compute loss - if is_training: # if model has loss hyperparameters - loss += compute_loss(train_out, targets, model)[1][:3] # GIoU, obj, cls + if training: + loss += compute_loss([x.float() for x in train_out], targets, model)[1][:3] # box, obj, cls # Run NMS - t = torch_utils.time_synchronized() - output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres, multi_label=multi_label) - t1 += torch_utils.time_synchronized() - t + targets[:, 2:] *= torch.Tensor([width, height, width, height]).to(device) # to pixels + lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_txt else [] # for autolabelling + t = time_synchronized() + output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres, labels=lb) + t1 += time_synchronized() - t # Statistics per image for si, pred in enumerate(output): labels = targets[targets[:, 0] == si, 1:] nl = len(labels) tcls = labels[:, 0].tolist() if nl else [] # target class + path = Path(paths[si]) seen += 1 - if pred is None: + if len(pred) == 0: if nl: stats.append((torch.zeros(0, niou, dtype=torch.bool), torch.Tensor(), torch.Tensor(), tcls)) continue - # Append to text file - # with open('test.txt', 'a') as file: - # [file.write('%11.5g' * 7 % tuple(x) + '\n') for x in pred] + # Predictions + predn = pred.clone() + scale_coords(img[si].shape[1:], predn[:, :4], shapes[si][0], shapes[si][1]) # native-space pred - # Clip boxes to image bounds - clip_coords(pred, (height, width)) + # Append to text file + if save_txt: + gn = torch.tensor(shapes[si][0])[[1, 0, 1, 0]] # normalization gain whwh + for *xyxy, conf, cls in predn.tolist(): + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format + with open(save_dir / 'labels' / (path.stem + '.txt'), 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + # W&B logging + if plots and len(wandb_images) < log_imgs: + box_data = [{"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, + "class_id": int(cls), + "box_caption": "%s %.3f" % (names[cls], conf), + "scores": {"class_score": conf}, + "domain": "pixel"} for *xyxy, conf, cls in pred.tolist()] + boxes = {"predictions": {"box_data": box_data, "class_labels": names}} # inference-space + wandb_images.append(wandb.Image(img[si], boxes=boxes, caption=path.name)) # Append to pycocotools JSON dictionary if save_json: # [{"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236}, ... - image_id = int(Path(paths[si]).stem.split('_')[-1]) - box = pred[:, :4].clone() # xyxy - scale_coords(imgs[si].shape[1:], box, shapes[si][0], shapes[si][1]) # to original shape - box = xyxy2xywh(box) # xywh + image_id = int(path.stem) if path.stem.isnumeric() else path.stem + box = xyxy2xywh(predn[:, :4]) # xywh box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner for p, b in zip(pred.tolist(), box.tolist()): jdict.append({'image_id': image_id, - 'category_id': coco91class[int(p[5])], + 'category_id': coco91class[int(p[5])] if is_coco else int(p[5]), 'bbox': [round(x, 3) for x in b], 'score': round(p[4], 5)}) @@ -141,22 +175,27 @@ def test(cfg, tcls_tensor = labels[:, 0] # target boxes - tbox = xywh2xyxy(labels[:, 1:5]) * whwh + tbox = xywh2xyxy(labels[:, 1:5]) + scale_coords(img[si].shape[1:], tbox, shapes[si][0], shapes[si][1]) # native-space labels + if plots: + confusion_matrix.process_batch(pred, torch.cat((labels[:, 0:1], tbox), 1)) # Per target class for cls in torch.unique(tcls_tensor): - ti = (cls == tcls_tensor).nonzero().view(-1) # target indices - pi = (cls == pred[:, 5]).nonzero().view(-1) # prediction indices + ti = (cls == tcls_tensor).nonzero(as_tuple=False).view(-1) # prediction indices + pi = (cls == pred[:, 5]).nonzero(as_tuple=False).view(-1) # target indices # Search for detections if pi.shape[0]: # Prediction to target ious - ious, i = box_iou(pred[pi, :4], tbox[ti]).max(1) # best ious, indices + ious, i = box_iou(predn[pi, :4], tbox[ti]).max(1) # best ious, indices # Append detections - for j in (ious > iouv[0]).nonzero(): + detected_set = set() + for j in (ious > iouv[0]).nonzero(as_tuple=False): d = ti[i[j]] # detected target - if d not in detected: + if d.item() not in detected_set: + detected_set.add(d.item()) detected.append(d) correct[pi[j]] = ious[j] > iouv # iou_thres is 1xn if len(detected) == nl: # all targets already located in image @@ -166,93 +205,105 @@ def test(cfg, stats.append((correct.cpu(), pred[:, 4].cpu(), pred[:, 5].cpu(), tcls)) # Plot images - if batch_i < 1: - f = 'test_batch%g_gt.jpg' % batch_i # filename - plot_images(imgs, targets, paths=paths, names=names, fname=f) # ground truth - f = 'test_batch%g_pred.jpg' % batch_i - plot_images(imgs, output_to_target(output, width, height), paths=paths, names=names, fname=f) # predictions + if plots and batch_i < 3: + f = save_dir / f'test_batch{batch_i}_labels.jpg' # filename + plot_images(img, targets, paths, f, names) # labels + f = save_dir / f'test_batch{batch_i}_pred.jpg' + plot_images(img, output_to_target(output), paths, f, names) # predictions # Compute statistics stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy - if len(stats): - p, r, ap, f1, ap_class = ap_per_class(*stats) - if niou > 1: - p, r, ap, f1 = p[:, 0], r[:, 0], ap.mean(1), ap[:, 0] # [P, R, AP@0.5:0.95, AP@0.5] - mp, mr, map, mf1 = p.mean(), r.mean(), ap.mean(), f1.mean() + if len(stats) and stats[0].any(): + p, r, ap, f1, ap_class = ap_per_class(*stats, plot=plots, save_dir=save_dir, names=names) + p, r, ap50, ap = p[:, 0], r[:, 0], ap[:, 0], ap.mean(1) # [P, R, AP@0.5, AP@0.5:0.95] + mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean() nt = np.bincount(stats[3].astype(np.int64), minlength=nc) # number of targets per class else: nt = torch.zeros(1) + # Plots + if plots: + confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) + if wandb and wandb.run: + wandb.log({"Images": wandb_images}) + wandb.log({"Validation": [wandb.Image(str(f), caption=f.name) for f in sorted(save_dir.glob('test*.jpg'))]}) + # Print results - pf = '%20s' + '%10.3g' * 6 # print format - print(pf % ('all', seen, nt.sum(), mp, mr, map, mf1)) + pf = '%20s' + '%12.3g' * 6 # print format + print(pf % ('all', seen, nt.sum(), mp, mr, map50, map)) # Print results per class if verbose and nc > 1 and len(stats): for i, c in enumerate(ap_class): - print(pf % (names[c], seen, nt[c], p[i], r[i], ap[i], f1[i])) + print(pf % (names[c], seen, nt[c], p[i], r[i], ap50[i], ap[i])) # Print speeds - if verbose or save_json: - t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + (imgsz, imgsz, batch_size) # tuple + t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + (imgsz, imgsz, batch_size) # tuple + if not training: print('Speed: %.1f/%.1f/%.1f ms inference/NMS/total per %gx%g image at batch-size %g' % t) # Save JSON - if save_json and map and len(jdict): - print('\nCOCO mAP with pycocotools...') - imgIds = [int(Path(x).stem.split('_')[-1]) for x in dataloader.dataset.img_files] - with open('results.json', 'w') as file: - json.dump(jdict, file) - - try: + if save_json and len(jdict): + w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights + anno_json = glob.glob('../coco/annotations/instances_val*.json')[0] # annotations json + pred_json = str(save_dir / f"{w}_predictions.json") # predictions json + print('\nEvaluating pycocotools mAP... saving %s...' % pred_json) + with open(pred_json, 'w') as f: + json.dump(jdict, f) + + try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb from pycocotools.coco import COCO from pycocotools.cocoeval import COCOeval - # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb - cocoGt = COCO(glob.glob('../coco/annotations/instances_val*.json')[0]) # initialize COCO ground truth api - cocoDt = cocoGt.loadRes('results.json') # initialize COCO pred api - - cocoEval = COCOeval(cocoGt, cocoDt, 'bbox') - cocoEval.params.imgIds = imgIds # [:32] # only evaluate these images - cocoEval.evaluate() - cocoEval.accumulate() - cocoEval.summarize() - # mf1, map = cocoEval.stats[:2] # update to pycocotools results (mAP@0.5:0.95, mAP@0.5) - except: - print('WARNING: pycocotools must be installed with numpy==1.17 to run correctly. ' - 'See https://github.com/cocodataset/cocoapi/issues/356') + anno = COCO(anno_json) # init annotations api + pred = anno.loadRes(pred_json) # init predictions api + eval = COCOeval(anno, pred, 'bbox') + if is_coco: + eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.img_files] # image IDs to evaluate + eval.evaluate() + eval.accumulate() + eval.summarize() + map, map50 = eval.stats[:2] # update results (mAP@0.5:0.95, mAP@0.5) + except Exception as e: + print('ERROR: pycocotools unable to run: %s' % e) # Return results + if not training: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + print(f"Results saved to {save_dir}{s}") + model.float() # for training maps = np.zeros(nc) + map for i, c in enumerate(ap_class): maps[c] = ap[i] - return (mp, mr, map, mf1, *(loss.cpu() / len(dataloader)).tolist()), maps + return (mp, mr, map50, map, *(loss.cpu() / len(dataloader)).tolist()), maps, t if __name__ == '__main__': parser = argparse.ArgumentParser(prog='test.py') - parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') - parser.add_argument('--data', type=str, default='data/coco2014.data', help='*.data path') - parser.add_argument('--weights', type=str, default='weights/yolov3-spp-ultralytics.pt', help='weights path') - parser.add_argument('--batch-size', type=int, default=16, help='size of each image batch') - parser.add_argument('--img-size', type=int, default=512, help='inference size (pixels)') + parser.add_argument('--weights', nargs='+', type=str, default='yolov3.pt', help='model.pt path(s)') + parser.add_argument('--data', type=str, default='data/coco128.yaml', help='*.data path') + parser.add_argument('--batch-size', type=int, default=32, help='size of each image batch') + parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') parser.add_argument('--iou-thres', type=float, default=0.6, help='IOU threshold for NMS') - parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') - parser.add_argument('--task', default='test', help="'test', 'study', 'benchmark'") - parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') - parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') + parser.add_argument('--task', default='val', help="'val', 'test', 'study'") + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--verbose', action='store_true', help='report mAP by class') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') + parser.add_argument('--project', default='runs/test', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') opt = parser.parse_args() - opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) - opt.cfg = check_file(opt.cfg) # check file + opt.save_json |= opt.data.endswith('coco.yaml') opt.data = check_file(opt.data) # check file print(opt) - # task = 'test', 'study', 'benchmark' - if opt.task == 'test': # (default) test normally - test(opt.cfg, - opt.data, + if opt.task in ['val', 'test']: # run normally + test(opt.data, opt.weights, opt.batch_size, opt.img_size, @@ -260,13 +311,22 @@ def test(cfg, opt.iou_thres, opt.save_json, opt.single_cls, - opt.augment) - - elif opt.task == 'benchmark': # mAPs at 256-640 at conf 0.5 and 0.7 - y = [] - for i in list(range(256, 640, 128)): # img-size - for j in [0.6, 0.7]: # iou-thres - t = time.time() - r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, i, opt.conf_thres, j, opt.save_json)[0] - y.append(r + (time.time() - t,)) - np.savetxt('benchmark.txt', y, fmt='%10.4g') # y = np.loadtxt('study.txt') + opt.augment, + opt.verbose, + save_txt=opt.save_txt, + save_conf=opt.save_conf, + ) + + elif opt.task == 'study': # run over a range of settings and save/plot + for weights in ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt']: + f = 'study_%s_%s.txt' % (Path(opt.data).stem, Path(weights).stem) # filename to save to + x = list(range(320, 800, 64)) # x axis + y = [] # y axis + for i in x: # img-size + print('\nRunning %s point %s...' % (f, i)) + r, _, t = test(opt.data, weights, opt.batch_size, i, opt.conf_thres, opt.iou_thres, opt.save_json, + plots=False) + y.append(r + t) # results and times + np.savetxt(f, y, fmt='%10.4g') # save + os.system('zip -r study.zip study_*.txt') + plot_study_txt(f, x) # plot diff --git a/train.py b/train.py index 1aba8d279d..3471496b92 100644 --- a/train.py +++ b/train.py @@ -1,442 +1,537 @@ import argparse - +import logging +import math +import os +import random +import time +from pathlib import Path +from warnings import warn + +import numpy as np import torch.distributed as dist +import torch.nn as nn +import torch.nn.functional as F import torch.optim as optim import torch.optim.lr_scheduler as lr_scheduler +import torch.utils.data +import yaml +from torch.cuda import amp +from torch.nn.parallel import DistributedDataParallel as DDP from torch.utils.tensorboard import SummaryWriter +from tqdm import tqdm import test # import test.py to get mAP after each epoch -from models import * -from utils.datasets import * -from utils.utils import * - -mixed_precision = True -try: # Mixed precision training https://github.com/NVIDIA/apex - from apex import amp -except: - print('Apex recommended for faster mixed precision training: https://github.com/NVIDIA/apex') - mixed_precision = False # not installed - -wdir = 'weights' + os.sep # weights dir -last = wdir + 'last.pt' -best = wdir + 'best.pt' -results_file = 'results.txt' - -# Hyperparameters -hyp = {'giou': 3.54, # giou loss gain - 'cls': 37.4, # cls loss gain - 'cls_pw': 1.0, # cls BCELoss positive_weight - 'obj': 64.3, # obj loss gain (*=img_size/320 if img_size != 320) - 'obj_pw': 1.0, # obj BCELoss positive_weight - 'iou_t': 0.20, # iou training threshold - 'lr0': 0.01, # initial learning rate (SGD=5E-3, Adam=5E-4) - 'lrf': 0.0005, # final learning rate (with cos scheduler) - 'momentum': 0.937, # SGD momentum - 'weight_decay': 0.0005, # optimizer weight decay - 'fl_gamma': 0.0, # focal loss gamma (efficientDet default is gamma=1.5) - 'hsv_h': 0.0138, # image HSV-Hue augmentation (fraction) - 'hsv_s': 0.678, # image HSV-Saturation augmentation (fraction) - 'hsv_v': 0.36, # image HSV-Value augmentation (fraction) - 'degrees': 1.98 * 0, # image rotation (+/- deg) - 'translate': 0.05 * 0, # image translation (+/- fraction) - 'scale': 0.05 * 0, # image scale (+/- gain) - 'shear': 0.641 * 0} # image shear (+/- deg) - -# Overwrite hyp with hyp*.txt (optional) -f = glob.glob('hyp*.txt') -if f: - print('Using %s' % f[0]) - for k, v in zip(hyp.keys(), np.loadtxt(f[0])): - hyp[k] = v - -# Print focal loss if gamma > 0 -if hyp['fl_gamma']: - print('Using FocalLoss(gamma=%g)' % hyp['fl_gamma']) - - -def train(hyp): - cfg = opt.cfg - data = opt.data - epochs = opt.epochs # 500200 batches at bs 64, 117263 images = 273 epochs - batch_size = opt.batch_size - accumulate = max(round(64 / batch_size), 1) # accumulate n times before optimizer update (bs 64) - weights = opt.weights # initial training weights - imgsz_min, imgsz_max, imgsz_test = opt.img_size # img sizes (min, max, test) - - # Image Sizes - gs = 32 # (pixels) grid size - assert math.fmod(imgsz_min, gs) == 0, '--img-size %g must be a %g-multiple' % (imgsz_min, gs) - opt.multi_scale |= imgsz_min != imgsz_max # multi if different (min, max) - if opt.multi_scale: - if imgsz_min == imgsz_max: - imgsz_min //= 1.5 - imgsz_max //= 0.667 - grid_min, grid_max = imgsz_min // gs, imgsz_max // gs - imgsz_min, imgsz_max = int(grid_min * gs), int(grid_max * gs) - img_size = imgsz_max # initialize with max size - - # Configure run - init_seeds() - data_dict = parse_data_cfg(data) +from models.yolo import Model +from utils.autoanchor import check_anchors +from utils.datasets import create_dataloader +from utils.general import labels_to_class_weights, increment_path, labels_to_image_weights, init_seeds, \ + fitness, strip_optimizer, get_latest_run, check_dataset, check_file, check_git_status, check_img_size, \ + print_mutation, set_logging +from utils.google_utils import attempt_download +from utils.loss import compute_loss +from utils.plots import plot_images, plot_labels, plot_results, plot_evolution +from utils.torch_utils import ModelEMA, select_device, intersect_dicts, torch_distributed_zero_first + +logger = logging.getLogger(__name__) + +try: + import wandb +except ImportError: + wandb = None + logger.info("Install Weights & Biases for experiment logging via 'pip install wandb' (recommended)") + + +def train(hyp, opt, device, tb_writer=None, wandb=None): + logger.info(f'Hyperparameters {hyp}') + save_dir, epochs, batch_size, total_batch_size, weights, rank = \ + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.total_batch_size, opt.weights, opt.global_rank + + # Directories + wdir = save_dir / 'weights' + wdir.mkdir(parents=True, exist_ok=True) # make dir + last = wdir / 'last.pt' + best = wdir / 'best.pt' + results_file = save_dir / 'results.txt' + + # Save run settings + with open(save_dir / 'hyp.yaml', 'w') as f: + yaml.dump(hyp, f, sort_keys=False) + with open(save_dir / 'opt.yaml', 'w') as f: + yaml.dump(vars(opt), f, sort_keys=False) + + # Configure + plots = not opt.evolve # create plots + cuda = device.type != 'cpu' + init_seeds(2 + rank) + with open(opt.data) as f: + data_dict = yaml.load(f, Loader=yaml.FullLoader) # data dict + with torch_distributed_zero_first(rank): + check_dataset(data_dict) # check train_path = data_dict['train'] - test_path = data_dict['valid'] - nc = 1 if opt.single_cls else int(data_dict['classes']) # number of classes - hyp['cls'] *= nc / 80 # update coco-tuned hyp['cls'] to current dataset - - # Remove previous results - for f in glob.glob('*_batch*.jpg') + glob.glob(results_file): - os.remove(f) + test_path = data_dict['val'] + nc, names = (1, ['item']) if opt.single_cls else (int(data_dict['nc']), data_dict['names']) # number classes, names + assert len(names) == nc, '%g names found for nc=%g dataset in %s' % (len(names), nc, opt.data) # check + + # Model + pretrained = weights.endswith('.pt') + if pretrained: + with torch_distributed_zero_first(rank): + attempt_download(weights) # download if not found locally + ckpt = torch.load(weights, map_location=device) # load checkpoint + if hyp.get('anchors'): + ckpt['model'].yaml['anchors'] = round(hyp['anchors']) # force autoanchor + model = Model(opt.cfg or ckpt['model'].yaml, ch=3, nc=nc).to(device) # create + exclude = ['anchor'] if opt.cfg or hyp.get('anchors') else [] # exclude keys + state_dict = ckpt['model'].float().state_dict() # to FP32 + state_dict = intersect_dicts(state_dict, model.state_dict(), exclude=exclude) # intersect + model.load_state_dict(state_dict, strict=False) # load + logger.info('Transferred %g/%g items from %s' % (len(state_dict), len(model.state_dict()), weights)) # report + else: + model = Model(opt.cfg, ch=3, nc=nc).to(device) # create - # Initialize model - model = Darknet(cfg).to(device) + # Freeze + freeze = [] # parameter names to freeze (full or partial) + for k, v in model.named_parameters(): + v.requires_grad = True # train all layers + if any(x in k for x in freeze): + print('freezing %s' % k) + v.requires_grad = False # Optimizer + nbs = 64 # nominal batch size + accumulate = max(round(nbs / total_batch_size), 1) # accumulate loss before optimizing + hyp['weight_decay'] *= total_batch_size * accumulate / nbs # scale weight_decay + pg0, pg1, pg2 = [], [], [] # optimizer parameter groups - for k, v in dict(model.named_parameters()).items(): - if '.bias' in k: - pg2 += [v] # biases - elif 'Conv2d.weight' in k: - pg1 += [v] # apply weight_decay - else: - pg0 += [v] # all else + for k, v in model.named_modules(): + if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter): + pg2.append(v.bias) # biases + if isinstance(v, nn.BatchNorm2d): + pg0.append(v.weight) # no decay + elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter): + pg1.append(v.weight) # apply decay if opt.adam: - # hyp['lr0'] *= 0.1 # reduce lr (i.e. SGD=5E-3, Adam=5E-4) - optimizer = optim.Adam(pg0, lr=hyp['lr0']) - # optimizer = AdaBound(pg0, lr=hyp['lr0'], final_lr=0.1) + optimizer = optim.Adam(pg0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999)) # adjust beta1 to momentum else: optimizer = optim.SGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) + optimizer.add_param_group({'params': pg1, 'weight_decay': hyp['weight_decay']}) # add pg1 with weight_decay optimizer.add_param_group({'params': pg2}) # add pg2 (biases) - print('Optimizer groups: %g .bias, %g Conv2d.weight, %g other' % (len(pg2), len(pg1), len(pg0))) + logger.info('Optimizer groups: %g .bias, %g conv.weight, %g other' % (len(pg2), len(pg1), len(pg0))) del pg0, pg1, pg2 - start_epoch = 0 - best_fitness = 0.0 - attempt_download(weights) - if weights.endswith('.pt'): # pytorch format - # possible weights are '*.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt' etc. - ckpt = torch.load(weights, map_location=device) - - # load model - try: - ckpt['model'] = {k: v for k, v in ckpt['model'].items() if model.state_dict()[k].numel() == v.numel()} - model.load_state_dict(ckpt['model'], strict=False) - except KeyError as e: - s = "%s is not compatible with %s. Specify --weights '' or specify a --cfg compatible with %s. " \ - "See https://github.com/ultralytics/yolov3/issues/657" % (opt.weights, opt.cfg, opt.weights) - raise KeyError(s) from e - - # load optimizer + # Scheduler https://arxiv.org/pdf/1812.01187.pdf + # https://pytorch.org/docs/stable/_modules/torch/optim/lr_scheduler.html#OneCycleLR + lf = lambda x: ((1 + math.cos(x * math.pi / epochs)) / 2) * (1 - hyp['lrf']) + hyp['lrf'] # cosine + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) + # plot_lr_scheduler(optimizer, scheduler, epochs) + + # Logging + if wandb and wandb.run is None: + opt.hyp = hyp # add hyperparameters + wandb_run = wandb.init(config=opt, resume="allow", + project='YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem, + name=save_dir.stem, + id=ckpt.get('wandb_id') if 'ckpt' in locals() else None) + + # Resume + start_epoch, best_fitness = 0, 0.0 + if pretrained: + # Optimizer if ckpt['optimizer'] is not None: optimizer.load_state_dict(ckpt['optimizer']) best_fitness = ckpt['best_fitness'] - # load results + # Results if ckpt.get('training_results') is not None: with open(results_file, 'w') as file: file.write(ckpt['training_results']) # write results.txt - # epochs + # Epochs start_epoch = ckpt['epoch'] + 1 + if opt.resume: + assert start_epoch > 0, '%s training to %g epochs is finished, nothing to resume.' % (weights, epochs) if epochs < start_epoch: - print('%s has been trained for %g epochs. Fine-tuning for %g additional epochs.' % - (opt.weights, ckpt['epoch'], epochs)) + logger.info('%s has been trained for %g epochs. Fine-tuning for %g additional epochs.' % + (weights, ckpt['epoch'], epochs)) epochs += ckpt['epoch'] # finetune additional epochs - del ckpt + del ckpt, state_dict - elif len(weights) > 0: # darknet format - # possible weights are '*.weights', 'yolov3-tiny.conv.15', 'darknet53.conv.74' etc. - load_darknet_weights(model, weights) + # Image sizes + gs = int(max(model.stride)) # grid size (max stride) + imgsz, imgsz_test = [check_img_size(x, gs) for x in opt.img_size] # verify imgsz are gs-multiples - if opt.freeze_layers: - output_layer_indices = [idx - 1 for idx, module in enumerate(model.module_list) if isinstance(module, YOLOLayer)] - freeze_layer_indices = [x for x in range(len(model.module_list)) if - (x not in output_layer_indices) and - (x - 1 not in output_layer_indices)] - for idx in freeze_layer_indices: - for parameter in model.module_list[idx].parameters(): - parameter.requires_grad_(False) + # DP mode + if cuda and rank == -1 and torch.cuda.device_count() > 1: + model = torch.nn.DataParallel(model) - # Mixed precision training https://github.com/NVIDIA/apex - if mixed_precision: - model, optimizer = amp.initialize(model, optimizer, opt_level='O1', verbosity=0) + # SyncBatchNorm + if opt.sync_bn and cuda and rank != -1: + model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) + logger.info('Using SyncBatchNorm()') - # Scheduler https://arxiv.org/pdf/1812.01187.pdf - lf = lambda x: (((1 + math.cos(x * math.pi / epochs)) / 2) ** 1.0) * 0.95 + 0.05 # cosine - scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) - scheduler.last_epoch = start_epoch - 1 # see link below - # https://discuss.pytorch.org/t/a-problem-occured-when-resuming-an-optimizer/28822 - - # Plot lr schedule - # y = [] - # for _ in range(epochs): - # scheduler.step() - # y.append(optimizer.param_groups[0]['lr']) - # plt.plot(y, '.-', label='LambdaLR') - # plt.xlabel('epoch') - # plt.ylabel('LR') - # plt.tight_layout() - # plt.savefig('LR.png', dpi=300) - - # Initialize distributed training - if device.type != 'cpu' and torch.cuda.device_count() > 1 and torch.distributed.is_available(): - dist.init_process_group(backend='nccl', # 'distributed backend' - init_method='tcp://127.0.0.1:9999', # distributed training init method - world_size=1, # number of nodes for distributed training - rank=0) # distributed training node rank - model = torch.nn.parallel.DistributedDataParallel(model, find_unused_parameters=True) - model.yolo_layers = model.module.yolo_layers # move yolo layer indices to top level - - # Dataset - dataset = LoadImagesAndLabels(train_path, img_size, batch_size, - augment=True, - hyp=hyp, # augmentation hyperparameters - rect=opt.rect, # rectangular training - cache_images=opt.cache_images, - single_cls=opt.single_cls) - - # Dataloader - batch_size = min(batch_size, len(dataset)) - nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8]) # number of workers - dataloader = torch.utils.data.DataLoader(dataset, - batch_size=batch_size, - num_workers=nw, - shuffle=not opt.rect, # Shuffle=True unless rectangular training is used - pin_memory=True, - collate_fn=dataset.collate_fn) - - # Testloader - testloader = torch.utils.data.DataLoader(LoadImagesAndLabels(test_path, imgsz_test, batch_size, - hyp=hyp, - rect=True, - cache_images=opt.cache_images, - single_cls=opt.single_cls), - batch_size=batch_size, - num_workers=nw, - pin_memory=True, - collate_fn=dataset.collate_fn) + # EMA + ema = ModelEMA(model) if rank in [-1, 0] else None + + # DDP mode + if cuda and rank != -1: + model = DDP(model, device_ids=[opt.local_rank], output_device=opt.local_rank) + + # Trainloader + dataloader, dataset = create_dataloader(train_path, imgsz, batch_size, gs, opt, + hyp=hyp, augment=True, cache=opt.cache_images, rect=opt.rect, rank=rank, + world_size=opt.world_size, workers=opt.workers, + image_weights=opt.image_weights) + mlc = np.concatenate(dataset.labels, 0)[:, 0].max() # max label class + nb = len(dataloader) # number of batches + assert mlc < nc, 'Label class %g exceeds nc=%g in %s. Possible class labels are 0-%g' % (mlc, nc, opt.data, nc - 1) + + # Process 0 + if rank in [-1, 0]: + ema.updates = start_epoch * nb // accumulate # set EMA updates + testloader = create_dataloader(test_path, imgsz_test, total_batch_size, gs, opt, + hyp=hyp, cache=opt.cache_images and not opt.notest, rect=True, + rank=-1, world_size=opt.world_size, workers=opt.workers)[0] # testloader + + if not opt.resume: + labels = np.concatenate(dataset.labels, 0) + c = torch.tensor(labels[:, 0]) # classes + # cf = torch.bincount(c.long(), minlength=nc) + 1. # frequency + # model._initialize_biases(cf.to(device)) + if plots: + plot_labels(labels, save_dir=save_dir) + if tb_writer: + tb_writer.add_histogram('classes', c, 0) + if wandb: + wandb.log({"Labels": [wandb.Image(str(x), caption=x.name) for x in save_dir.glob('*labels*.png')]}) + + # Anchors + if not opt.noautoanchor: + check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) # Model parameters + hyp['cls'] *= nc / 80. # scale coco-tuned hyp['cls'] to current dataset model.nc = nc # attach number of classes to model model.hyp = hyp # attach hyperparameters to model - model.gr = 1.0 # giou loss ratio (obj_loss = 1.0 or giou) + model.gr = 1.0 # iou loss ratio (obj_loss = 1.0 or iou) model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) # attach class weights - - # Model EMA - ema = torch_utils.ModelEMA(model) + model.names = names # Start training - nb = len(dataloader) # number of batches - n_burn = max(3 * nb, 500) # burn-in iterations, max(3 epochs, 500 iterations) - maps = np.zeros(nc) # mAP per class - # torch.autograd.set_detect_anomaly(True) - results = (0, 0, 0, 0, 0, 0, 0) # 'P', 'R', 'mAP', 'F1', 'val GIoU', 'val Objectness', 'val Classification' t0 = time.time() - print('Image sizes %g - %g train, %g test' % (imgsz_min, imgsz_max, imgsz_test)) - print('Using %g dataloader workers' % nw) - print('Starting training for %g epochs...' % epochs) + nw = max(round(hyp['warmup_epochs'] * nb), 1000) # number of warmup iterations, max(3 epochs, 1k iterations) + # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training + maps = np.zeros(nc) # mAP per class + results = (0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) + scheduler.last_epoch = start_epoch - 1 # do not move + scaler = amp.GradScaler(enabled=cuda) + logger.info('Image sizes %g train, %g test\n' + 'Using %g dataloader workers\nLogging results to %s\n' + 'Starting training for %g epochs...' % (imgsz, imgsz_test, dataloader.num_workers, save_dir, epochs)) for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ model.train() # Update image weights (optional) - if dataset.image_weights: - w = model.class_weights.cpu().numpy() * (1 - maps) ** 2 # class weights - image_weights = labels_to_image_weights(dataset.labels, nc=nc, class_weights=w) - dataset.indices = random.choices(range(dataset.n), weights=image_weights, k=dataset.n) # rand weighted idx - - mloss = torch.zeros(4).to(device) # mean losses - print(('\n' + '%10s' * 8) % ('Epoch', 'gpu_mem', 'GIoU', 'obj', 'cls', 'total', 'targets', 'img_size')) - pbar = tqdm(enumerate(dataloader), total=nb) # progress bar + if opt.image_weights: + # Generate indices + if rank in [-1, 0]: + cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 # class weights + iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights + dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx + # Broadcast if DDP + if rank != -1: + indices = (torch.tensor(dataset.indices) if rank == 0 else torch.zeros(dataset.n)).int() + dist.broadcast(indices, 0) + if rank != 0: + dataset.indices = indices.cpu().numpy() + + # Update mosaic border + # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs) + # dataset.mosaic_border = [b - imgsz, -b] # height, width borders + + mloss = torch.zeros(4, device=device) # mean losses + if rank != -1: + dataloader.sampler.set_epoch(epoch) + pbar = enumerate(dataloader) + logger.info(('\n' + '%10s' * 8) % ('Epoch', 'gpu_mem', 'box', 'obj', 'cls', 'total', 'targets', 'img_size')) + if rank in [-1, 0]: + pbar = tqdm(pbar, total=nb) # progress bar + optimizer.zero_grad() for i, (imgs, targets, paths, _) in pbar: # batch ------------------------------------------------------------- ni = i + nb * epoch # number integrated batches (since train start) - imgs = imgs.to(device).float() / 255.0 # uint8 to float32, 0 - 255 to 0.0 - 1.0 - targets = targets.to(device) - - # Burn-in - if ni <= n_burn: - xi = [0, n_burn] # x interp - model.gr = np.interp(ni, xi, [0.0, 1.0]) # giou loss ratio (obj_loss = 1.0 or giou) - accumulate = max(1, np.interp(ni, xi, [1, 64 / batch_size]).round()) + imgs = imgs.to(device, non_blocking=True).float() / 255.0 # uint8 to float32, 0-255 to 0.0-1.0 + + # Warmup + if ni <= nw: + xi = [0, nw] # x interp + # model.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou) + accumulate = max(1, np.interp(ni, xi, [1, nbs / total_batch_size]).round()) for j, x in enumerate(optimizer.param_groups): # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 - x['lr'] = np.interp(ni, xi, [0.1 if j == 2 else 0.0, x['initial_lr'] * lf(epoch)]) - x['weight_decay'] = np.interp(ni, xi, [0.0, hyp['weight_decay'] if j == 1 else 0.0]) + x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 2 else 0.0, x['initial_lr'] * lf(epoch)]) if 'momentum' in x: - x['momentum'] = np.interp(ni, xi, [0.9, hyp['momentum']]) + x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) - # Multi-Scale + # Multi-scale if opt.multi_scale: - if ni / accumulate % 1 == 0: #  adjust img_size (67% - 150%) every 1 batch - img_size = random.randrange(grid_min, grid_max + 1) * gs - sf = img_size / max(imgs.shape[2:]) # scale factor + sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size + sf = sz / max(imgs.shape[2:]) # scale factor if sf != 1: - ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to 32-multiple) + ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) imgs = F.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) # Forward - pred = model(imgs) - - # Loss - loss, loss_items = compute_loss(pred, targets, model) - if not torch.isfinite(loss): - print('WARNING: non-finite loss, ending training ', loss_items) - return results + with amp.autocast(enabled=cuda): + pred = model(imgs) # forward + loss, loss_items = compute_loss(pred, targets.to(device), model) # loss scaled by batch_size + if rank != -1: + loss *= opt.world_size # gradient averaged between devices in DDP mode # Backward - loss *= batch_size / 64 # scale loss - if mixed_precision: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() + scaler.scale(loss).backward() # Optimize if ni % accumulate == 0: - optimizer.step() + scaler.step(optimizer) # optimizer.step + scaler.update() optimizer.zero_grad() - ema.update(model) + if ema: + ema.update(model) # Print - mloss = (mloss * i + loss_items) / (i + 1) # update mean losses - mem = '%.3gG' % (torch.cuda.memory_cached() / 1E9 if torch.cuda.is_available() else 0) # (GB) - s = ('%10s' * 2 + '%10.3g' * 6) % ('%g/%g' % (epoch, epochs - 1), mem, *mloss, len(targets), img_size) - pbar.set_description(s) - - # Plot - if ni < 1: - f = 'train_batch%g.jpg' % i # filename - res = plot_images(images=imgs, targets=targets, paths=paths, fname=f) - if tb_writer: - tb_writer.add_image(f, res, dataformats='HWC', global_step=epoch) - # tb_writer.add_graph(model, imgs) # add model to tensorboard + if rank in [-1, 0]: + mloss = (mloss * i + loss_items) / (i + 1) # update mean losses + mem = '%.3gG' % (torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0) # (GB) + s = ('%10s' * 2 + '%10.4g' * 6) % ( + '%g/%g' % (epoch, epochs - 1), mem, *mloss, targets.shape[0], imgs.shape[-1]) + pbar.set_description(s) + + # Plot + if plots and ni < 3: + f = save_dir / f'train_batch{ni}.jpg' # filename + plot_images(images=imgs, targets=targets, paths=paths, fname=f) + # if tb_writer: + # tb_writer.add_image(f, result, dataformats='HWC', global_step=epoch) + # tb_writer.add_graph(model, imgs) # add model to tensorboard + elif plots and ni == 3 and wandb: + wandb.log({"Mosaics": [wandb.Image(str(x), caption=x.name) for x in save_dir.glob('train*.jpg')]}) # end batch ------------------------------------------------------------------------------------------------ + # end epoch ---------------------------------------------------------------------------------------------------- - # Update scheduler + # Scheduler + lr = [x['lr'] for x in optimizer.param_groups] # for tensorboard scheduler.step() - # Process epoch results - ema.update_attr(model) - final_epoch = epoch + 1 == epochs - if not opt.notest or final_epoch: # Calculate mAP - is_coco = any([x in data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) and model.nc == 80 - results, maps = test.test(cfg, - data, - batch_size=batch_size, - imgsz=imgsz_test, - model=ema.ema, - save_json=final_epoch and is_coco, - single_cls=opt.single_cls, - dataloader=testloader, - multi_label=ni > n_burn) - - # Write - with open(results_file, 'a') as f: - f.write(s + '%10.3g' * 7 % results + '\n') # P, R, mAP, F1, test_losses=(GIoU, obj, cls) - if len(opt.name) and opt.bucket: - os.system('gsutil cp results.txt gs://%s/results/results%s.txt' % (opt.bucket, opt.name)) - - # Tensorboard - if tb_writer: - tags = ['train/giou_loss', 'train/obj_loss', 'train/cls_loss', - 'metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/F1', - 'val/giou_loss', 'val/obj_loss', 'val/cls_loss'] - for x, tag in zip(list(mloss[:-1]) + list(results), tags): - tb_writer.add_scalar(tag, x, epoch) - - # Update best mAP - fi = fitness(np.array(results).reshape(1, -1)) # fitness_i = weighted combination of [P, R, mAP, F1] - if fi > best_fitness: - best_fitness = fi - - # Save model - save = (not opt.nosave) or (final_epoch and not opt.evolve) - if save: - with open(results_file, 'r') as f: # create checkpoint - ckpt = {'epoch': epoch, - 'best_fitness': best_fitness, - 'training_results': f.read(), - 'model': ema.ema.module.state_dict() if hasattr(model, 'module') else ema.ema.state_dict(), - 'optimizer': None if final_epoch else optimizer.state_dict()} - - # Save last, best and delete - torch.save(ckpt, last) - if (best_fitness == fi) and not final_epoch: - torch.save(ckpt, best) - del ckpt - + # DDP process 0 or single-GPU + if rank in [-1, 0]: + # mAP + if ema: + ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'gr', 'names', 'stride']) + final_epoch = epoch + 1 == epochs + if not opt.notest or final_epoch: # Calculate mAP + results, maps, times = test.test(opt.data, + batch_size=total_batch_size, + imgsz=imgsz_test, + model=ema.ema, + single_cls=opt.single_cls, + dataloader=testloader, + save_dir=save_dir, + plots=plots and final_epoch, + log_imgs=opt.log_imgs if wandb else 0) + + # Write + with open(results_file, 'a') as f: + f.write(s + '%10.4g' * 7 % results + '\n') # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) + if len(opt.name) and opt.bucket: + os.system('gsutil cp %s gs://%s/results/results%s.txt' % (results_file, opt.bucket, opt.name)) + + # Log + tags = ['train/box_loss', 'train/obj_loss', 'train/cls_loss', # train loss + 'metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', + 'val/box_loss', 'val/obj_loss', 'val/cls_loss', # val loss + 'x/lr0', 'x/lr1', 'x/lr2'] # params + for x, tag in zip(list(mloss[:-1]) + list(results) + lr, tags): + if tb_writer: + tb_writer.add_scalar(tag, x, epoch) # tensorboard + if wandb: + wandb.log({tag: x}) # W&B + + # Update best mAP + fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + if fi > best_fitness: + best_fitness = fi + + # Save model + save = (not opt.nosave) or (final_epoch and not opt.evolve) + if save: + with open(results_file, 'r') as f: # create checkpoint + ckpt = {'epoch': epoch, + 'best_fitness': best_fitness, + 'training_results': f.read(), + 'model': ema.ema, + 'optimizer': None if final_epoch else optimizer.state_dict(), + 'wandb_id': wandb_run.id if wandb else None} + + # Save last, best and delete + torch.save(ckpt, last) + if best_fitness == fi: + torch.save(ckpt, best) + del ckpt # end epoch ---------------------------------------------------------------------------------------------------- # end training - n = opt.name - if len(n): - n = '_' + n if not n.isnumeric() else n - fresults, flast, fbest = 'results%s.txt' % n, wdir + 'last%s.pt' % n, wdir + 'best%s.pt' % n - for f1, f2 in zip([wdir + 'last.pt', wdir + 'best.pt', 'results.txt'], [flast, fbest, fresults]): - if os.path.exists(f1): + if rank in [-1, 0]: + # Strip optimizers + n = opt.name if opt.name.isnumeric() else '' + fresults, flast, fbest = save_dir / f'results{n}.txt', wdir / f'last{n}.pt', wdir / f'best{n}.pt' + for f1, f2 in zip([wdir / 'last.pt', wdir / 'best.pt', results_file], [flast, fbest, fresults]): + if f1.exists(): os.rename(f1, f2) # rename - ispt = f2.endswith('.pt') # is *.pt - strip_optimizer(f2) if ispt else None # strip optimizer - os.system('gsutil cp %s gs://%s/weights' % (f2, opt.bucket)) if opt.bucket and ispt else None # upload + if str(f2).endswith('.pt'): # is *.pt + strip_optimizer(f2) # strip optimizer + os.system('gsutil cp %s gs://%s/weights' % (f2, opt.bucket)) if opt.bucket else None # upload + # Finish + if plots: + plot_results(save_dir=save_dir) # save as results.png + if wandb: + files = ['results.png', 'precision_recall_curve.png', 'confusion_matrix.png'] + wandb.log({"Results": [wandb.Image(str(save_dir / f), caption=f) for f in files + if (save_dir / f).exists()]}) + logger.info('%g epochs completed in %.3f hours.\n' % (epoch - start_epoch + 1, (time.time() - t0) / 3600)) + else: + dist.destroy_process_group() - if not opt.evolve: - plot_results() # save as results.png - print('%g epochs completed in %.3f hours.\n' % (epoch - start_epoch + 1, (time.time() - t0) / 3600)) - dist.destroy_process_group() if torch.cuda.device_count() > 1 else None + wandb.run.finish() if wandb and wandb.run else None torch.cuda.empty_cache() return results if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('--epochs', type=int, default=300) # 500200 batches at bs 16, 117263 COCO images = 273 epochs - parser.add_argument('--batch-size', type=int, default=16) # effective bs = batch_size * accumulate = 16 * 4 = 64 - parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') - parser.add_argument('--data', type=str, default='data/coco2017.data', help='*.data path') - parser.add_argument('--multi-scale', action='store_true', help='adjust (67%% - 150%%) img_size every 10 batches') - parser.add_argument('--img-size', nargs='+', type=int, default=[320, 640], help='[min_train, max-train, test]') + parser.add_argument('--weights', type=str, default='yolov3.pt', help='initial weights path') + parser.add_argument('--cfg', type=str, default='', help='model.yaml path') + parser.add_argument('--data', type=str, default='data/coco128.yaml', help='data.yaml path') + parser.add_argument('--hyp', type=str, default='data/hyp.scratch.yaml', help='hyperparameters path') + parser.add_argument('--epochs', type=int, default=300) + parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs') + parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='[train, test] image sizes') parser.add_argument('--rect', action='store_true', help='rectangular training') - parser.add_argument('--resume', action='store_true', help='resume training from last.pt') + parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') parser.add_argument('--notest', action='store_true', help='only test final epoch') + parser.add_argument('--noautoanchor', action='store_true', help='disable autoanchor check') parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters') parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') - parser.add_argument('--weights', type=str, default='weights/yolov3-spp-ultralytics.pt', help='initial weights path') - parser.add_argument('--name', default='', help='renames results.txt to results_name.txt if supplied') - parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1 or cpu)') - parser.add_argument('--adam', action='store_true', help='use adam optimizer') + parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') - parser.add_argument('--freeze-layers', action='store_true', help='Freeze non-output layers') + parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer') + parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') + parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') + parser.add_argument('--log-imgs', type=int, default=16, help='number of images for W&B logging, max 100') + parser.add_argument('--workers', type=int, default=8, help='maximum number of dataloader workers') + parser.add_argument('--project', default='runs/train', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') opt = parser.parse_args() - opt.weights = last if opt.resume and not opt.weights else opt.weights - check_git_status() - opt.cfg = check_file(opt.cfg) # check file - opt.data = check_file(opt.data) # check file - print(opt) - opt.img_size.extend([opt.img_size[-1]] * (3 - len(opt.img_size))) # extend to 3 sizes (min, max, test) - device = torch_utils.select_device(opt.device, apex=mixed_precision, batch_size=opt.batch_size) - if device.type == 'cpu': - mixed_precision = False - - # scale hyp['obj'] by img_size (evolved at 320) - # hyp['obj'] *= opt.img_size[0] / 320. - - tb_writer = None - if not opt.evolve: # Train normally - print('Start Tensorboard with "tensorboard --logdir=runs", view at http://localhost:6006/') - tb_writer = SummaryWriter(comment=opt.name) - train(hyp) # train normally - - else: # Evolve hyperparameters (optional) + + # Set DDP variables + opt.total_batch_size = opt.batch_size + opt.world_size = int(os.environ['WORLD_SIZE']) if 'WORLD_SIZE' in os.environ else 1 + opt.global_rank = int(os.environ['RANK']) if 'RANK' in os.environ else -1 + set_logging(opt.global_rank) + if opt.global_rank in [-1, 0]: + check_git_status() + + # Resume + if opt.resume: # resume an interrupted run + ckpt = opt.resume if isinstance(opt.resume, str) else get_latest_run() # specified or most recent path + assert os.path.isfile(ckpt), 'ERROR: --resume checkpoint does not exist' + with open(Path(ckpt).parent.parent / 'opt.yaml') as f: + opt = argparse.Namespace(**yaml.load(f, Loader=yaml.FullLoader)) # replace + opt.cfg, opt.weights, opt.resume = '', ckpt, True + logger.info('Resuming training from %s' % ckpt) + else: + # opt.hyp = opt.hyp or ('hyp.finetune.yaml' if opt.weights else 'hyp.scratch.yaml') + opt.data, opt.cfg, opt.hyp = check_file(opt.data), check_file(opt.cfg), check_file(opt.hyp) # check files + assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' + opt.img_size.extend([opt.img_size[-1]] * (2 - len(opt.img_size))) # extend to 2 sizes (train, test) + opt.name = 'evolve' if opt.evolve else opt.name + opt.save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok | opt.evolve) # increment run + + # DDP mode + device = select_device(opt.device, batch_size=opt.batch_size) + if opt.local_rank != -1: + assert torch.cuda.device_count() > opt.local_rank + torch.cuda.set_device(opt.local_rank) + device = torch.device('cuda', opt.local_rank) + dist.init_process_group(backend='nccl', init_method='env://') # distributed backend + assert opt.batch_size % opt.world_size == 0, '--batch-size must be multiple of CUDA device count' + opt.batch_size = opt.total_batch_size // opt.world_size + + # Hyperparameters + with open(opt.hyp) as f: + hyp = yaml.load(f, Loader=yaml.FullLoader) # load hyps + if 'box' not in hyp: + warn('Compatibility: %s missing "box" which was renamed from "giou" in %s' % + (opt.hyp, 'https://github.com/ultralytics/yolov5/pull/1120')) + hyp['box'] = hyp.pop('giou') + + # Train + logger.info(opt) + if not opt.evolve: + tb_writer = None # init loggers + if opt.global_rank in [-1, 0]: + logger.info(f'Start Tensorboard with "tensorboard --logdir {opt.project}", view at http://localhost:6006/') + tb_writer = SummaryWriter(opt.save_dir) # Tensorboard + train(hyp, opt, device, tb_writer, wandb) + + # Evolve hyperparameters (optional) + else: + # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) + meta = {'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) + 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) + 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 + 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay + 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) + 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum + 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr + 'box': (1, 0.02, 0.2), # box loss gain + 'cls': (1, 0.2, 4.0), # cls loss gain + 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight + 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) + 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight + 'iou_t': (0, 0.1, 0.7), # IoU training threshold + 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold + 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) + 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) + 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) + 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) + 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) + 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) + 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) + 'scale': (1, 0.0, 0.9), # image scale (+/- gain) + 'shear': (1, 0.0, 10.0), # image shear (+/- deg) + 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 + 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) + 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) + 'mosaic': (1, 0.0, 1.0), # image mixup (probability) + 'mixup': (1, 0.0, 1.0)} # image mixup (probability) + + assert opt.local_rank == -1, 'DDP mode not implemented for --evolve' opt.notest, opt.nosave = True, True # only test/save final epoch + # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices + yaml_file = Path(opt.save_dir) / 'hyp_evolved.yaml' # save best result here if opt.bucket: os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket) # download evolve.txt if exists - for _ in range(1): # generations to evolve - if os.path.exists('evolve.txt'): # if evolve.txt exists: select best hyps and mutate + for _ in range(300): # generations to evolve + if Path('evolve.txt').exists(): # if evolve.txt exists: select best hyps and mutate # Select parent(s) parent = 'single' # parent selection method: 'single' or 'weighted' x = np.loadtxt('evolve.txt', ndmin=2) @@ -450,34 +545,30 @@ def train(hyp): x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination # Mutate - method, mp, s = 3, 0.9, 0.2 # method, mutation probability, sigma + mp, s = 0.8, 0.2 # mutation probability, sigma npr = np.random npr.seed(int(time.time())) - g = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 0, 1, 1, 1, 1, 1, 1, 1]) # gains - ng = len(g) - if method == 1: - v = (npr.randn(ng) * npr.random() * g * s + 1) ** 2.0 - elif method == 2: - v = (npr.randn(ng) * npr.random(ng) * g * s + 1) ** 2.0 - elif method == 3: - v = np.ones(ng) - while all(v == 1): # mutate until a change occurs (prevent duplicates) - # v = (g * (npr.random(ng) < mp) * npr.randn(ng) * s + 1) ** 2.0 - v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) + g = np.array([x[0] for x in meta.values()]) # gains 0-1 + ng = len(meta) + v = np.ones(ng) + while all(v == 1): # mutate until a change occurs (prevent duplicates) + v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) - hyp[k] = x[i + 7] * v[i] # mutate + hyp[k] = float(x[i + 7] * v[i]) # mutate - # Clip to limits - keys = ['lr0', 'iou_t', 'momentum', 'weight_decay', 'hsv_s', 'hsv_v', 'translate', 'scale', 'fl_gamma'] - limits = [(1e-5, 1e-2), (0.00, 0.70), (0.60, 0.98), (0, 0.001), (0, .9), (0, .9), (0, .9), (0, .9), (0, 3)] - for k, v in zip(keys, limits): - hyp[k] = np.clip(hyp[k], v[0], v[1]) + # Constrain to limits + for k, v in meta.items(): + hyp[k] = max(hyp[k], v[1]) # lower limit + hyp[k] = min(hyp[k], v[2]) # upper limit + hyp[k] = round(hyp[k], 5) # significant digits # Train mutation - results = train(hyp.copy()) + results = train(hyp.copy(), opt, device, wandb=wandb) # Write mutation results - print_mutation(hyp, results, opt.bucket) + print_mutation(hyp.copy(), results, yaml_file, opt.bucket) - # Plot results - # plot_evolution_results(hyp) + # Plot results + plot_evolution(yaml_file) + print(f'Hyperparameter evolution complete. Best results saved as: {yaml_file}\n' + f'Command to train a new model with these hyperparameters: $ python train.py --hyp {yaml_file}') diff --git a/tutorial.ipynb b/tutorial.ipynb index 53e5cd1ac7..5e190e212a 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -1,495 +1,1212 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "HvhYZrIZCEyo" - }, - "source": [ - "\n", - "\n", - "
\n", - " \n", - " View source on github\n", - " \n", - "\n", - " \n", - " Run in Google Colab\n", - "
\n", - "\n", - "This notebook contains software developed by Ultralytics LLC, and **is freely available for redistribution under the GPL-3.0 license**. For more information please visit https://github.com/ultralytics/yolov3 and https://www.ultralytics.com.\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 34 - }, - "colab_type": "code", - "id": "e5ylFIvlCEym", - "outputId": "fbc88edd-7b26-4735-83bf-b404b76f9c90" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "PyTorch 1.1.0 _CudaDeviceProperties(name='Tesla K80', major=3, minor=7, total_memory=11441MB, multi_processor_count=13)\n" - ] - } - ], - "source": [ - "import time\n", - "import glob\n", - "import torch\n", - "import os\n", - "\n", - "from IPython.display import Image, clear_output \n", - "print('PyTorch %s %s' % (torch.__version__, torch.cuda.get_device_properties(0) if torch.cuda.is_available() else 'CPU'))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "7mGmQbAO5pQb" - }, - "source": [ - "Clone repository and download COCO 2014 dataset (20GB):" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { "colab": { - "base_uri": "https://localhost:8080/", - "height": 221 - }, - "colab_type": "code", - "id": "tIFv0p1TCEyj", - "outputId": "e9230cff-ede4-491a-a74d-063ce77f21cd" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Cloning into 'yolov3'...\n", - "remote: Enumerating objects: 61, done.\u001b[K\n", - "remote: Counting objects: 100% (61/61), done.\u001b[K\n", - "remote: Compressing objects: 100% (44/44), done.\u001b[K\n", - "remote: Total 4781 (delta 35), reused 37 (delta 17), pack-reused 4720\u001b[K\n", - "Receiving objects: 100% (4781/4781), 4.74 MiB | 6.95 MiB/s, done.\n", - "Resolving deltas: 100% (3254/3254), done.\n", - " % Total % Received % Xferd Average Speed Time Time Time Current\n", - " Dload Upload Total Spent Left Speed\n", - "100 388 0 388 0 0 2455 0 --:--:-- --:--:-- --:--:-- 2440\n", - "100 18.8G 0 18.8G 0 0 189M 0 --:--:-- 0:01:42 --:--:-- 174M\n", - "/content/yolov3\n" - ] + "name": "YOLOv3 Tutorial", + "provenance": [], + "collapsed_sections": [], + "toc_visible": true, + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "accelerator": "GPU", + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "b257add75888401ebf17767cdc9ed439": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "state": { + "_view_name": "HBoxView", + "_dom_classes": [], + "_model_name": "HBoxModel", + "_view_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_view_count": null, + "_view_module_version": "1.5.0", + "box_style": "", + "layout": "IPY_MODEL_4b685e8b26f3496db73186063e19f785", + "_model_module": "@jupyter-widgets/controls", + "children": [ + "IPY_MODEL_0980232d74a14bdfa353a3f248bbe8ff", + "IPY_MODEL_e981f3dfbf374643b58cba7dfbef3bca" + ] + } + }, + "4b685e8b26f3496db73186063e19f785": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "state": { + "_view_name": "LayoutView", + "grid_template_rows": null, + "right": null, + "justify_content": null, + "_view_module": "@jupyter-widgets/base", + "overflow": null, + "_model_module_version": "1.2.0", + "_view_count": null, + "flex_flow": null, + "width": null, + "min_width": null, + "border": null, + "align_items": null, + "bottom": null, + "_model_module": "@jupyter-widgets/base", + "top": null, + "grid_column": null, + "overflow_y": null, + "overflow_x": null, + "grid_auto_flow": null, + "grid_area": null, + "grid_template_columns": null, + "flex": null, + "_model_name": "LayoutModel", + "justify_items": null, + "grid_row": null, + "max_height": null, + "align_content": null, + "visibility": null, + "align_self": null, + "height": null, + "min_height": null, + "padding": null, + "grid_auto_rows": null, + "grid_gap": null, + "max_width": null, + "order": null, + "_view_module_version": "1.2.0", + "grid_template_areas": null, + "object_position": null, + "object_fit": null, + "grid_auto_columns": null, + "margin": null, + "display": null, + "left": null + } + }, + "0980232d74a14bdfa353a3f248bbe8ff": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "state": { + "_view_name": "ProgressView", + "style": "IPY_MODEL_07bb32c950654e9fa401e35a0030eadc", + "_dom_classes": [], + "description": "100%", + "_model_name": "FloatProgressModel", + "bar_style": "success", + "max": 819257867, + "_view_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "value": 819257867, + "_view_count": null, + "_view_module_version": "1.5.0", + "orientation": "horizontal", + "min": 0, + "description_tooltip": null, + "_model_module": "@jupyter-widgets/controls", + "layout": "IPY_MODEL_ec3fce2f475b4f31b8caf1a0ca912af1" + } + }, + "e981f3dfbf374643b58cba7dfbef3bca": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "state": { + "_view_name": "HTMLView", + "style": "IPY_MODEL_9a1c27af326e43ca8a8b6b90cf0075db", + "_dom_classes": [], + "description": "", + "_model_name": "HTMLModel", + "placeholder": "​", + "_view_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "value": " 781M/781M [00:49<00:00, 16.7MB/s]", + "_view_count": null, + "_view_module_version": "1.5.0", + "description_tooltip": null, + "_model_module": "@jupyter-widgets/controls", + "layout": "IPY_MODEL_7cf92d6d6c704a8d8e7834783813228d" + } + }, + "07bb32c950654e9fa401e35a0030eadc": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "state": { + "_view_name": "StyleView", + "_model_name": "ProgressStyleModel", + "description_width": "initial", + "_view_module": "@jupyter-widgets/base", + "_model_module_version": "1.5.0", + "_view_count": null, + "_view_module_version": "1.2.0", + "bar_color": null, + "_model_module": "@jupyter-widgets/controls" + } + }, + "ec3fce2f475b4f31b8caf1a0ca912af1": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "state": { + "_view_name": "LayoutView", + "grid_template_rows": null, + "right": null, + "justify_content": null, + "_view_module": "@jupyter-widgets/base", + "overflow": null, + "_model_module_version": "1.2.0", + "_view_count": null, + "flex_flow": null, + "width": null, + "min_width": null, + "border": null, + "align_items": null, + "bottom": null, + "_model_module": "@jupyter-widgets/base", + "top": null, + "grid_column": null, + "overflow_y": null, + "overflow_x": null, + "grid_auto_flow": null, + "grid_area": null, + "grid_template_columns": null, + "flex": null, + "_model_name": "LayoutModel", + "justify_items": null, + "grid_row": null, + "max_height": null, + "align_content": null, + "visibility": null, + "align_self": null, + "height": null, + "min_height": null, + "padding": null, + "grid_auto_rows": null, + "grid_gap": null, + "max_width": null, + "order": null, + "_view_module_version": "1.2.0", + "grid_template_areas": null, + "object_position": null, + "object_fit": null, + "grid_auto_columns": null, + "margin": null, + "display": null, + "left": null + } + }, + "9a1c27af326e43ca8a8b6b90cf0075db": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "state": { + "_view_name": "StyleView", + "_model_name": "DescriptionStyleModel", + "description_width": "", + "_view_module": "@jupyter-widgets/base", + "_model_module_version": "1.5.0", + "_view_count": null, + "_view_module_version": "1.2.0", + "_model_module": "@jupyter-widgets/controls" + } + }, + "7cf92d6d6c704a8d8e7834783813228d": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "state": { + "_view_name": "LayoutView", + "grid_template_rows": null, + "right": null, + "justify_content": null, + "_view_module": "@jupyter-widgets/base", + "overflow": null, + "_model_module_version": "1.2.0", + "_view_count": null, + "flex_flow": null, + "width": null, + "min_width": null, + "border": null, + "align_items": null, + "bottom": null, + "_model_module": "@jupyter-widgets/base", + "top": null, + "grid_column": null, + "overflow_y": null, + "overflow_x": null, + "grid_auto_flow": null, + "grid_area": null, + "grid_template_columns": null, + "flex": null, + "_model_name": "LayoutModel", + "justify_items": null, + "grid_row": null, + "max_height": null, + "align_content": null, + "visibility": null, + "align_self": null, + "height": null, + "min_height": null, + "padding": null, + "grid_auto_rows": null, + "grid_gap": null, + "max_width": null, + "order": null, + "_view_module_version": "1.2.0", + "grid_template_areas": null, + "object_position": null, + "object_fit": null, + "grid_auto_columns": null, + "margin": null, + "display": null, + "left": null + } + }, + "c1928794b5bd400da6e7817883a0ee9c": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "state": { + "_view_name": "HBoxView", + "_dom_classes": [], + "_model_name": "HBoxModel", + "_view_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_view_count": null, + "_view_module_version": "1.5.0", + "box_style": "", + "layout": "IPY_MODEL_804fae06a69f4e11b919d8ab80822186", + "_model_module": "@jupyter-widgets/controls", + "children": [ + "IPY_MODEL_138cbb92b4fd4eaa9b7fdcbed1f57a4d", + "IPY_MODEL_28bb2eea5b114f82b201e5fa39fdfc58" + ] + } + }, + "804fae06a69f4e11b919d8ab80822186": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "state": { + "_view_name": "LayoutView", + "grid_template_rows": null, + "right": null, + "justify_content": null, + "_view_module": "@jupyter-widgets/base", + "overflow": null, + "_model_module_version": "1.2.0", + "_view_count": null, + "flex_flow": null, + "width": null, + "min_width": null, + "border": null, + "align_items": null, + "bottom": null, + "_model_module": "@jupyter-widgets/base", + "top": null, + "grid_column": null, + "overflow_y": null, + "overflow_x": null, + "grid_auto_flow": null, + "grid_area": null, + "grid_template_columns": null, + "flex": null, + "_model_name": "LayoutModel", + "justify_items": null, + "grid_row": null, + "max_height": null, + "align_content": null, + "visibility": null, + "align_self": null, + "height": null, + "min_height": null, + "padding": null, + "grid_auto_rows": null, + "grid_gap": null, + "max_width": null, + "order": null, + "_view_module_version": "1.2.0", + "grid_template_areas": null, + "object_position": null, + "object_fit": null, + "grid_auto_columns": null, + "margin": null, + "display": null, + "left": null + } + }, + "138cbb92b4fd4eaa9b7fdcbed1f57a4d": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "state": { + "_view_name": "ProgressView", + "style": "IPY_MODEL_aea8bd6f395845f696e3abedbff59423", + "_dom_classes": [], + "description": "100%", + "_model_name": "FloatProgressModel", + "bar_style": "success", + "max": 22090455, + "_view_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "value": 22090455, + "_view_count": null, + "_view_module_version": "1.5.0", + "orientation": "horizontal", + "min": 0, + "description_tooltip": null, + "_model_module": "@jupyter-widgets/controls", + "layout": "IPY_MODEL_0514774dafdf4e39bdd5a8833d1cbcb0" + } + }, + "28bb2eea5b114f82b201e5fa39fdfc58": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "state": { + "_view_name": "HTMLView", + "style": "IPY_MODEL_7dabd1f8236045729c90ae78a0d9af24", + "_dom_classes": [], + "description": "", + "_model_name": "HTMLModel", + "placeholder": "​", + "_view_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "value": " 21.1M/21.1M [00:02<00:00, 9.27MB/s]", + "_view_count": null, + "_view_module_version": "1.5.0", + "description_tooltip": null, + "_model_module": "@jupyter-widgets/controls", + "layout": "IPY_MODEL_227e357d925345f995aeea7b72750cf1" + } + }, + "aea8bd6f395845f696e3abedbff59423": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "state": { + "_view_name": "StyleView", + "_model_name": "ProgressStyleModel", + "description_width": "initial", + "_view_module": "@jupyter-widgets/base", + "_model_module_version": "1.5.0", + "_view_count": null, + "_view_module_version": "1.2.0", + "bar_color": null, + "_model_module": "@jupyter-widgets/controls" + } + }, + "0514774dafdf4e39bdd5a8833d1cbcb0": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "state": { + "_view_name": "LayoutView", + "grid_template_rows": null, + "right": null, + "justify_content": null, + "_view_module": "@jupyter-widgets/base", + "overflow": null, + "_model_module_version": "1.2.0", + "_view_count": null, + "flex_flow": null, + "width": null, + "min_width": null, + "border": null, + "align_items": null, + "bottom": null, + "_model_module": "@jupyter-widgets/base", + "top": null, + "grid_column": null, + "overflow_y": null, + "overflow_x": null, + "grid_auto_flow": null, + "grid_area": null, + "grid_template_columns": null, + "flex": null, + "_model_name": "LayoutModel", + "justify_items": null, + "grid_row": null, + "max_height": null, + "align_content": null, + "visibility": null, + "align_self": null, + "height": null, + "min_height": null, + "padding": null, + "grid_auto_rows": null, + "grid_gap": null, + "max_width": null, + "order": null, + "_view_module_version": "1.2.0", + "grid_template_areas": null, + "object_position": null, + "object_fit": null, + "grid_auto_columns": null, + "margin": null, + "display": null, + "left": null + } + }, + "7dabd1f8236045729c90ae78a0d9af24": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "state": { + "_view_name": "StyleView", + "_model_name": "DescriptionStyleModel", + "description_width": "", + "_view_module": "@jupyter-widgets/base", + "_model_module_version": "1.5.0", + "_view_count": null, + "_view_module_version": "1.2.0", + "_model_module": "@jupyter-widgets/controls" + } + }, + "227e357d925345f995aeea7b72750cf1": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "state": { + "_view_name": "LayoutView", + "grid_template_rows": null, + "right": null, + "justify_content": null, + "_view_module": "@jupyter-widgets/base", + "overflow": null, + "_model_module_version": "1.2.0", + "_view_count": null, + "flex_flow": null, + "width": null, + "min_width": null, + "border": null, + "align_items": null, + "bottom": null, + "_model_module": "@jupyter-widgets/base", + "top": null, + "grid_column": null, + "overflow_y": null, + "overflow_x": null, + "grid_auto_flow": null, + "grid_area": null, + "grid_template_columns": null, + "flex": null, + "_model_name": "LayoutModel", + "justify_items": null, + "grid_row": null, + "max_height": null, + "align_content": null, + "visibility": null, + "align_self": null, + "height": null, + "min_height": null, + "padding": null, + "grid_auto_rows": null, + "grid_gap": null, + "max_width": null, + "order": null, + "_view_module_version": "1.2.0", + "grid_template_areas": null, + "object_position": null, + "object_fit": null, + "grid_auto_columns": null, + "margin": null, + "display": null, + "left": null + } + } + } } - ], - "source": [ - "!git clone https://github.com/ultralytics/yolov3 # clone\n", - "!bash yolov3/data/get_coco2014.sh # copy COCO2014 dataset (19GB)\n", - "%cd yolov3" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "N3qM6T0W53gh" - }, - "source": [ - "Run `detect.py` to perform inference on images in `data/samples` folder:" - ] }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 477 - }, - "colab_type": "code", - "id": "zR9ZbuQCH7FX", - "outputId": "49268b66-125d-425e-dbd0-17b108914c51" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Namespace(cfg='cfg/yolov3-spp.cfg', conf_thres=0.5, data='data/coco.data', fourcc='mp4v', images='data/samples', img_size=416, nms_thres=0.5, output='output', weights='weights/yolov3-spp.weights')\n", - "Using CUDA with Apex device0 _CudaDeviceProperties(name='Tesla K80', total_memory=11441MB)\n", - "\n", - "image 1/2 data/samples/bus.jpg: 416x320 3 persons, 1 buss, 1 handbags, Done. (0.119s)\n", - "image 2/2 data/samples/zidane.jpg: 256x416 2 persons, 1 ties, Done. (0.085s)\n", - "Results saved to /content/yolov3/output\n" - ] - }, - { - "data": { - "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAMEBgUGBgYF\nBgYGBwkIBgcJBwYGCAsICQoKCgoKBggLDAsKDAkKCgr/2wBDAQICAgICAgUDAwUKBwYHCgoKCgoK\nCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgr/wAARCALQBQADASIA\nAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA\nAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3\nODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm\np6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA\nAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx\nBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK\nU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3\nuLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8347F\n5pkSP5t38P3ttaFjZzR2rzOMjfs+/wDNVi10+5kh877Gqv8AwfP96tOz0+2b99sw0e1drfxV87HY\n+wjHm94z4bOZ2WZ4dgV9vzN81Tx6a8jHvu+bd/DV+HT51uHd0Up95Pl21bhtfIkH2ncqfN8q/e21\nNS0dUbU4/ZMf7Oi52OzMu1UVU+an/wBjlW3w7l2t8y/3q3pNPRl2I+1tn/AqZZ280cXk3Nrub+7v\n+6tefKtLl5onZGm48qMqbQ3k/wBJeb5lb5PMf5l/2aZcaW6tshhyzffZn3ba3biHzI5USFfmX7tQ\nyWc3zTXltuWPb+8jT+LbXJWxVWO534XDxkchrmm/KZt+d3yvurBm0maHLvu2su1G/vV3OsWsMe5x\nyWTd5bVh3VikkLJ5Pyqu7b/easaNacX7x6nsYyicrJYws3nom1m/vf3qWC3uYW32zr8v95v/AEGt\nK6s5I9iJuDMu51aq62827502Nt3Jur6zAylKUTlqREj+0wsiI7OzNuRW/wBr+7ViSPy4/wBzud9+\n1vm+Wq0aurIJtxdf4qtLayeX8nyusu5mb+KvqMPSlKJ58qnvco65uHaNpvlTdt2fJ8y0kjSbER3V\ntq7tzJtqbyPtDLDNtx96nTKjR/Ii7t38X3a9D2fKebUkoy5SHyXjnP75l/i/3amSSVm+0v5joqbf\nv/Ky/wB6i3/fRrv+9911j+6rUsMMuxvJufu/fXZXPKXLE4OaUuaxPBv3b9n+r/hjl3LVqH9zJ/qV\n2t823/eqtbwpHGkP+qVn+dY/l/4FVuzZLqRI5plV13b12fdX+GvLxHvF04825p2cm1Ucopdvl+V9\ntaVvDcSSK6fd+ZXrN0+GGS637F+V1aXd/d/hq7b75mX51Db9zMr/AC/7Py14WIqSNadHuaVjNLJC\nsP2pmTfuddvzNU8jO3yQ7X2/e/iaq8IeGNPLRW+bbu2fdq95n2OZXhhV2b5V3V4dap7+h6VOnHqW\nob792yI6o6orfLVCZJpPnudrBf4v97+KpmuIWmDzTKsrfdXft+7VCS5dpmR5o3/vq392uJSjztQO\nlx928hzbIZXSFFLs7fMqf6yopmubzY63jIVb7qrU32OGSP8AhRPveXHSyKluy/J975VXf/FWkqnN\nqLk5fdEntdy/3vl2eZs/76pU3yQyJsYeX8if3lqwsE0iy2zzfuvl/d/7VVr6O6WTf8yfe/d7/u1n\n71TRSMK0R8d1cxwrvRQv3dzfdWoprp75hNc3cjtHtSLzG+61OaGaS3RJnV1+88bVVkkRlKWtthlf\n+GspRhKRjH3Y8rKuoXtvHteN8qy7X/vVga9cXisrpcthkVfm/u1pXk00zAu+R/d/utWDq14+5n34\n2/6rav3a78PFRj8JyVqhj6lM/wC8+8f/AB3dXManN82/fjd/CtdBqW+4bM0/Gzc1Yd48Pls/Vm+X\nb/FXsUYy5NDxsVLmiYF9avt+07F21QVXmuNmzb/utW9cWbyR56hVqnHp7rMJvJ8xK9CnKMeU82T5\nhljlWZE3fN9//ZrodI3x7ntn+Rk2srfM1V9N03bGOdu7/wAdrVhs4I5BGiMk0f8ADJ8tEqhrToz+\nI1NLtUinR9+fLf5F/wDsa7bQZnjwibU2/N+7X5VrjdH/AHKxBE3f367TRZE+x7E2/wB1dv3mqo1P\nfOj2fuWOu0W4k+ziF5sOzfxfw11ui6uNyu6Mrqu1/Mfb8v8As1wWk3KOuy28xVVvnb+7W/puqQxs\nU3/eiVmj+9XZGpzmMoyj8R3Wn6kQN8Myh1f/AEfb93/eatXT9am8ve+1vvbmrgrHWd0iXOcFfl3L\n/F/wGtCHxB5K+d8wSR9qKq/M3/Aa6OYw9+J2q69C3zpZttX5Ub+9/vUybV4IYd+//WbtzL/Ctcqu\ntbYf3fmHc+1/mqvcawk3ybJCu/b9/wC9U/DAfunT/wBtusCv0/2d/wDDWbqGuosbO8jEt91tvyst\nYN9q226ldH2xtt8qNX3f8B3VVvtUm2l3TLsnzLu/i/hqJRjI25vslPxRNDdZm85iv3fLb+GuMvJ3\ndXR/uK23/erW1PVHuomQXLFpJfkZvur/ALNZGqQ/aFb5G+V/3sa1x1I8x0UeaOjOa1SG2ml85Pv/\nAMO5vlWqtvbupYOmPLf5d3yturcbTkjdt6Mxb/lm38NQXWnpJcM8iSO38Un8K1nKn7p2RqQ5tTPW\nFJpD5czIn97726mTWVzIHfez+Z/yz/vVZa1eSTZDCqqqNu+fbSLYwzRuXhxufd9/71cNSnI0lUM2\nSN1CwpMuyT5tv/stJbxurI/nL+8ba0cn92tXybaOSHyYfuxbtrN8v3qq3Eltu+0+T86tt+VK5q1P\n3tCoVOXWRbtWdcoltv2tu2t8u6uj01na3TZuAVt27+61YNu7s0jzbWlb5U/hrQ0+aGObzo3bzl+X\n7/y7q+Ox1GXNKTPewtT4ZI7LT2T/AFM03mt8q7v4a0WuvLUI+6H5v9Wvzbv+BVzVnfTeSH/55q25\nd/3m/wBmp/7UdpI+Nqt8rbWr5DEYeUqp9DRrfDzG5cXySsN9zuVot6qybvu1m3mpRrD5iO0KSRbv\nlf5aqSal8zbNuPm2/J8q1Uk1QSM73KKrrF8nlr8u6tKOHUZe8dvtOhPeahD5yc7v3X975t1Zs0zr\nsfo2/wCZW/h/4FS3F4jKkEyMXX5X3fdaqzLBNJscrsZNqqv8NexhcPGPuozqVOWHKJe+c0hf7Tv3\nfL8tVri3DSPD9pUyr/F91d1aEljH/wAvMylG+4yp91aktdPeRc+Tv+f5fk3V9XluH5dTwcdiIx+0\n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\nvn8zZsVQ331rqpxkfP4rFc0C2s/nRsgdgrfw02OQM3kTOqt81Uo5jAm9HXYrVKt09w29H+Zf/Hq6\n4xPm8VWjI0beR1ZXebFaFu6Kqv53y/x/7VY+nnzGdH/v7fv1q2UcMi42ZVf4auPvfEeTKsadnI7f\n3lVtvzLWtp6vcSNvfd/C+5vvLWdpsMfmb4YeG2/NJW1pdn/HNGuF+7toiebKpzGvZWc0kTfOoST+\nFfvV0+l2u2ON/wB5Ky1l6HYv8joinau35v4a6Tw7ZpbrsuYV2xr83z/dqjGUjf0uzRVTemNybkX+\n7WvZWjyLseHLM27dHTNDs5PLjSG227k3L/tV0ljYoy7Id29VbfuSuj4jn9oYk1ik0Lby2Nq/L/da\npnsYWjWHft+Xc6t/C1a0ejzTbYZodu7+L+GoptPdZGd9yfwfK/zbaXL9o6aMvfMWKzmaQXPzOW+X\ndv8Au7aelj/pBmmm2CTbv/vbavrZpC3k23mfvP4ZPvLUV1Y7YV8t8lU+6y1Mox5eY97Cy90z9Qs7\naRlmRGdftG1Gb+H/AGq5vWtPmWRtk38X3lauwuI4f40k2/wMv96uY1SL7Ll9i/MzfKrbvmpxjCXv\nHvYaPwqR57r1i80LzQv5yM3yM3/oNcT4k099zJvY7vl+X71eoeIIdyt8jL8/7pv7tcZrln50bokb\nfL8yNXJWl/MerHC83vHtWnw20Ku8ybx5v3l+8rVLbxPcM6eTH5SuzRMvysrVWguIFZjZupSNvvMv\n3m/+Jqe3vv8ASPJ+zM+1V3V40Y8sD572nKX7G1eNv9JRX+Xcn8VaMLQyKfJf+DaisvzL/wACrPju\nPJbY8n7pn3LGqfd/4FV6Fu1y+EVdyN/tV59eT/lO6lU5pXEuo4VkKPtY+UqusbfN838VRR2rxyK7\nuwZanuJE+0OkiKX2b/lT5ZGpjWyKrnyVf+P5W+Va4qlSUdz0Kceb4RtqsMzTb4ZG3S7fJb/0Kh7X\na4he58pG/wBarN92kjj3fvnTciozOq/LtqaKGCSM74ZHf76/L/s159SpyzPQox9zmMKSzS8mm8l1\n+V9sUjferOuLeSa4NzsyVXbu+X71dFfQzKpuUmhXbKvy7KzJreGNXTyV+aqo83tTo5onNXivDIzu\nq4/gbZ92sjyUuJNjzSbYfufPXVala/u96bvu/MrL/DWDcaanyv5ap8vyf3mr7DLeaMtTGpy/ZKK2\n6T7n87d5bsj/AMO6rMMb2cIfY23f95V3VFMrzRlN/wA67V+X+9/tVJGqR+TAibf++m3V9dRkePiq\nkYxZJazeY3z7l/usy/eqOdnuoXRH27n+992rEivujcbv721qrswhXY7ru3/Ov92ur2h89UrS5xUt\nX2r8+W/gXfUkMz7S/wDD/s1EXePCbMKyfJt/iWo42mnm855tu35UWsqkiIyl8JfhZ5Ji6Xivt+62\nzb/wGrcMkEMP+k9W3b4/722smFYW/vOyv83zVqQtN8ifLu+99/btWvHxko83xHdRjL4jZtV2skyJ\nvSTa37v733f4q0re3s5o3d0807flZflrEhZLRnfZu3LtUx1t294tvCj7FRVTZtX5q+exFT3uY9Cj\nT/mLsLSTRtvLM6xfvW2bV/4DTobjbu+zO2GTbtb+H/eqq106r5KPuf8Ahjb+7UVxqDhne5hVdzL/\nAKv5VWvAxEpI9KnTj9ouf2ju/wBGfy9q/db/AGaRVs7hluZoWfy/l/dp822oYJEWSVJZoZP4v3i/\ndX+7RDI8UghhDeVu+b+Fv/sqxp/uzOp7xds7dLqNNjssX8Lfdap4/JkWVH27Y2/i+ZqS3VOPtJjQ\nffRZKkkjmWFf9Gydu5mZt235vu1VSpfoZRUvdIzHNGDCk0K7v4t/3VqNo7mSRrmb5kb+HdurQt/t\nMeEmhjRdvyKq/eqvNazLIyQ3OWb7qttXbU09Nncmp8JnyRpcTGFN2Wi3bv4V/wBmq1001uvzptlZ\nNu1VrVWF2UPsZCz/ADR7fvf7VE1nZqgh2Nub5U/vUpVOWRzS5oxOX1KxSFTIm52/iVWrC1K3C2ot\npky8n8S/eauw1KzhuIsw3jEt8rrs/u1g6ta+RIzzfKyqq+Yq/eWvSw/NPlb+E8ms5y5jjL6FI08n\nY3y/L8zVmQ2MNxn5FDq21f8AarpNQhhmMkL7V3fP5f8ADVGa1hnmVIdqKr/OtevCUnCR5VSMjF+w\nPNcF03J/D5bU630uTPz7tm3cv+zXReX5cm9LbcGanR2KNG3kzKn+zIn3abrOMbdBKnGMuYxYdLSO\nHzEh3tu+Xd8tLNGkM3kzDJkT5vn+atfULXbJs+bd8rL5f8S1SvLbyZt8yfeT5Gqoy97yOqNMdp9x\nD5iQbF837vyv91a6DTbhoY/4cbt25f7tYNnbv5bO8MbN95GVq2NPvJPs6zTJlt/3lojLml7pry/z\nHTaXfTLuT725NyM33ttasd0kluj75C6puSSN9u6ubsofIuPtMKN9z52V61Vmga3/AH0G4Nu+8+3+\nH+Gu6nU/mOOpDubFjrjwyKiR4RtqszL/ABf7NXF8QQwssP2nftf5vmrmvtiZitt829Yvut93/eqK\neZ2kLu7Db83y12RqHHL3Tq18UJJIxTcDH8u7b8vzUlvrSXXyb1Zldv3kbfLXMR6oixqJk2tJ8zRv\n/DU1vqUMcakp/F97d8u2t+b3CIyhE6NtUTaEfov8P96qM+zzCkMOUmf513bttZtrdQzfJvY7vuR/\nw1ZjDyK0ltuVW/utUVPhJ5uaYya4mkU/aU2eS2xP9pf4amhteDJ5K5/hjX7tXYbN5oVd5FZmT7zV\nb+yr8hdNjfKi/wC9/erD2fMbRxE4mLdaW8b+Y9srfwpurMuNHuVhZ0hw+770hrtpNNF1cCZLb+H5\nJP4flqtJoMzTH7SjMm/dtV6qMeX3So4j3zjJNHRbeR0TAX5pfl/iqn9hufkEzx7m+b93XVXmm3K+\nbbQw8q2593y7l/u1UuNH+z253wrv2fJ5a1hKmbxxHLI5q4hhjt4vk/j3Iy1TuLNPld0Ztzbv96uh\nmsIY1bZDyvzbv7tZuoRpHM0aTMnmfNu2feriqUy41ihDeOsjfe+9t+b+GrljsMn7l1Cr/DI9Z7Rz\nRyMjovzfKqs1S29n5alNjGVvuN95a+ezDC9z2cPiuXU37K6dZV3opZX3f8BqaW8hjl/fceZP8q/7\nNU9JhRcq7s235fmetGGxmaT92nC7WRpPvV8XUwf73U+jw+K5oXkI1uiyfO/lBt2z56rzTbt2+2yd\nm1N3/oTVqLavN+5Fnv8ALTf833d1KukT3yxbLJWk2fPu+Vf++qijg5xq88j1I1vcMqCM3EyQ/Mu7\n+992tCPS9redCi7dy/N/erU0/QfMkZ/llbf/AAv8v+7Wja6DDDIIfsbIY5dv3vu17+DwvtZXUTjx\nGMhT3MePS02y+d8+77y/3a07Hw3eXEccM1huMO19yp/49XQWfhdGkXZDt/e/eb+Kt/T/AAvDDH8+\n5WV/k2t/47X1uBw7jGK5T5jHYpVOZnNWHh/z497wqV3bYmb5lWr9v4Vmb50+dFb70f3a6nT9LSOG\nGNEaKXfu3L8y/L/eq9Z6DuX55liX5jt/2t1fSYePunz1Spy6HO2fh3zPnSwbb/z0/vNV+z8NzSq8\nP2byjG9dPpfhlGMkIt9m1m8ry2+X/gVadj4dhtYUR9yru3r/APZV0ypnJKtKUtDkJPC8Kwp9mRmW\nOXdL+6ptxoNtD/pkKN5X8PyfxV3kejzXSr5KKvz/AL1l/iX+Gm3nhmZZHT5Xi+7/AHdq1w1KIe0P\nMbjwvNIrfJgL825f4l/2qzLrw+9rJvfzJH2fIzf3a9R1TRYY1KJC2yNP+WP3W/3q5rUtJEjCHf8A\nPJ9xZF+Vf96vMrUeY78LWOEvNHmdxMlsyL/Asm35mrE1LR/JkZ7nzNzJt2t8vltXc6zH5d08O9fl\n+5N/BXN3lu81wjvNthZmbdM+7c23+9XgywsouR79HFROOvNPuWkDvCreWm12X5ttc/rUL2+94YWd\nPlZJdtdnrsO64CbGXd825X/hrB1iF2X5PmVfuVi4dTqUu5gLKkLPMOuzbtb+L/dqWT/SLg/Iu3bu\n3NT7izeGZ2CRsG/ib+FqjmkeSPfHtHmJt2t/DWtOnBy9wy9p7tnIz7m6ha3/AHNs21nb5v8A2asm\n73zfchYfL8tXtQZ49qK7FWTdu+6yrVS4Dv8AcZS/8Pyfer08PTgeXiJe9cz45raSPem4Oq7t396q\ncs3mLsf5FX/x6reobGVnRGQL9/bVFpvLjCCFZg33Nr/Mtd8Y8vvHJKpze6WY7d5lU/fKpu27dq0Q\nyBtqOnlv/eWo9ibjIj/uv7qt81Tw3X7zzvLb5n27V+bdVx94y9CzbxozMHhjZdvysv8Ay0/3qvw2\nLyRt+5+WT79QWsO1i6Jsb+7WzY2/mwoj/Lu/hb+KrcpRiXGUviKlnp8EP39rqz/NHWjZ6fHvVPO3\n7v8Almv3atw2NtIqJMFzJ/FtrQsNNhiYQwozLGv3v9r+9Vl+05o+6Vv7N3hdmNyv8irX1f8A8Ed9\nOmj/AGldZWK2YNL4HuEVAMmRhe2QyK+c9N0eeRlTZ8zfxf3a+q/+CQum/wBnftPahcP+88vwtOhR\n84P+nWRwcfSvhvE+Cn4fZjFven+qPnOJZKWT14/3f1P080z9mP446pcPbx+BJ4SkSOWup441IYZA\nBZsE46gcqeDg8Vzvjf4c+NfhzqA03xl4fnsnfPlSOA0cuMZ2OuVbGRnB4zzivdf2xPiv498HeI9L\n8MeFPEM+nW8tj9pme0bZJI5dlALDkABegxnPOcDEfgXxDqX7QP7PHiPSPHKxXmo6JGz2eozQZfIj\nLo2VH3xtZSRyVPOcnP8AJOY8EcISzjE5Fl9Wt9cpRlKMp8jpzcY87haKUk+XaT0unpsfm2IybKni\n6mCoSn7WKbTduV2V7aWa06ngvhbwh4m8basuieFNEuL+6YZ8u3TO1cgbmPRVyR8xIAz1rpfFv7On\nxi8FaS2t634PlNrGCZpLSZJ/KUDJZhGSVUAHLEYHc17r+zz4X0zwh8AY9et/Een6LqGthnfXLmBT\n5WXKop8wqG2gHAJ25JOCOut8O5LPwVqc934h/acsdetJ4yHtNQuYBsbqGV/NJXvx0IPsMejk/hVl\nlfK8NPHVJqpXgp80Z0YwpKSvHmjOSnPS3Ny2XRXZ0YThjDTw1N15Pmmr3TglG+103zPzsfKXhHwP\n4t8eX0um+ENCnv54YGmlSED5UUckkkD2A6k4AyTiun0/9mb43aloh16DwLOkWxnEM8qRzED0iZg+\nfQYye1emfsuJ4b/4X/4vfwlcI+m/ZpvsOzOGjNwhBXgfKOg9iOvWvO/iv+0J8SPF3irU47HxZeWe\nmGaSC3srOYxJ5AJA3YwWJHJJ9SOBgV8suG+Esp4bp5jmlSrUqVKlWnGNJwUX7N25uaUX7v3t8ytZ\nXPMWX5VhcvjiMTKUpSlKKUWrPldr3aen53Rj+Cvgf8U/iDCbvwx4QuJLcFh9pnKwxkgkEBnIDEEE\nEDOCOab45+CfxP8Ah1bfb/FfhOeG1GN13EyyxKSQAGZCQuSQOcZNe6+BvGnhz4n/AAe0jwV4N+Ki\neDtX06COO4t4yFZyoK4BcgsGI35ViRnDVU8dQ/HX4ZfCvW9O8WSWfjPSL622f2jJct5lirEKWdSN\n0inIIwx2kZJwMV7s/D7hxZCsXSnWqL2XO60HTnSjLlvyypxvVik/dbaXK9ZWSdu2WQ5esD7WLnL3\nb88eVxTteziveS6N9Op8++FvCHibxtqy6H4U0S4vrphny4EztXIG5j0VckfMSAM9a6Xxb+zp8YvB\nWktrmt+D5TaxgmaS0mSfygBkswjJKqADliMDua9P8HalL8Ef2Ux4+8N2kC6zrVxtF99ny0YZ2Vc7\nhyFVSQD8u5u+eee/Z6+P3xHufibY+GvFHiG51aw1eb7PPBeHzCjMDtdTjK4PUdME5HAI8jDcKcJ4\nT6lgc0rVVisXGE04KPs6aqaU+ZP3pX3lZqy2OWnleV0vY0cTOXtKqTTjbljzfDe+r87HlXhjwt4g\n8Z63D4c8L6XJeXtwcRQR4GfUkkgKB3JIArrNB/Zm+NviGCS5tfA08CxyFCL6VIGJHXCyEEj3Awex\nr0nwh4R0vwP+2o+jaZaRxW0kM09rDAuxIRJblioGMYHzAAcDj0xXN/H79oT4nn4maloGgeJLjS7L\nSbx7eCGxfYZCpwXdhyxJHToBjjqSqfCfDOS5PWxmezqudPEVKHJS5VdwUXzXknZat9b6Ky1COV5d\ng8JKrjZSco1JQtG2tktbtaf8MeX+KfCXiTwVq76D4r0aexu4xkxTpjcuSNynoykg4YEg461nV7x+\n2C8Ot+D/AAR4xuYiL2/09jK4IwQY4nxjH95jj6mvB6+S4uyOhw7n9XA0ZucEoyi3vyzjGavbS6Ur\nOx5Wa4KGAx0qMHeKs03vZpNX+8OvSvpDxr4xf9lr4SaB4S8CWsQ1fV4zc3t3cxBiG2rvcrnGcsqq\nDkBU5yea+ddOlig1CCef7iTKz/IG4BGeDwfpXtn7catN4o8P6nC2babSWEOFGMh8nn6MtfRcH4mt\nlPDGbZphHy4iCowjJfFCNSb52uzaSV91fRnoZTUnhctxWJpO1RckU+qUnq191je+CPxcvf2h7TV/\nhF8WIILn7VYmW2uoIRG3ysM8DjcpKspA/hOc18863pcuia1d6NOSXtLqSFyVwSVYqeO3SvSf2Oba\n5n+NtrLATthsLh5sLn5dm38PmZa5H4y3lpf/ABX8RXdgQYn1ifYQgX+Mg8D379+tXxFjMTnnA2Bz\nLHS568KtSlzvWU4JRmrvd8rbSv3+95hWqY3JaOIrO81KUbvdqyer62bLPwK8CWvxG+KOl+GNSgMl\nm8jS3qCQpuiRSxGRzzgDjnnt1r1L4z/tPeLvAPjWX4f/AA5sLGw0/RCkGHtQxkKqMqAThUHAAAzx\nnPOB4z8O/Gd38PPGuneMrK3857C43mAyFPMUghlzg4yCRnB+hr3DxR4T/Zy+Puqf8LAs/idHod5N\nGjapaXDxxkkKAflk24fGAWUspxnB5J9Hg2vjKnCdfB5JiI0cc6ylK8405ToqOihOVvhlduKd7a9b\nPfKJ1ZZXOlg6ihXck3dqLcbbJu2z1auQfFz7F8cv2ebX4zt4bWLW9Ofy7qS3DAeUshWTA53Jkhxn\nJX5ueubH7Lwu9H+BPiTxF8PtOhvPEouWHkv8zEKimNccZ4ZyBnk8Z7De+Ih+HWg/snajpfw/1Fp9\nKRVtra6AJM8v2hdzEkLuy27JAx1xwAK5z4Fx6H8B/grc/HHXJbm5udW/dWunxXW2OQB2WNcDI3Eh\nyWOdq5AAOQfv3hvqfHWGxlepBy+o8+IrQatF2lB1otJ3lsk7PmT0Vj3XT9lnVOrNq/sbzmraaNOa\n01e1u5a+EHxR/ah8QfEKy0jxT4duW01ptuotd6N9nWFMHLb9q4YY4HOTxXy//wAFdrHQNL+Dvx2i\n8PBBGfhrrklwkZ+VZ20uZpB0GPmJJHPJP0H034E/bbvNX8VQ6T4z8LWttYXc4iW6tJn3WwY4DNuz\nvHTJG3AyeelfM/8AwV6+GkPwy/Z2+MkdjeTT2upfCrxBewNczeZKC1hc71YnlvmBwTyQRkkgmvLx\n+KwuZ8P4SWCxk8bGnjKbnUq3U6d9IxSavyz73aurWve3HiqtLEZbTdGs6yjVi3KXxRvokk9bPvf/\nAIH8ykl4i2+x5GLr/FVSbUJ1b+HZs+X/AHqpzXkzM/z7k/gqhdTPJGuHr+6OU+4lWLk2rfu22Ox/\n4FWbcag8kbb0zt+6y0k0jruReQy/N/DVZpo/9oeWv8VZy3LjLmBpHjk/iWkaR1c7H+9/CtQzHbtL\n7iVT+H7tRmbKhwjbqwlsdVP3ZEzTTIzOXUf7WypYZHLK6feqsu95Aj8/7tTwruy7/Kf4NtcdQ9jC\n1pRNGGN2Hzw7FX7taNi3lqkOzLbt3mLVKz+WEJhj81bFrGi4f+L+OuOUf5j6fC4jm5S1DCnl74f4\nvv1YjttqmZNxRU+7SWqPJGHk3ff/AN2r9ja9J45vl/u1xS92Vz3aOIKsMbffm+X5c7qkS32t9xn+\nf7zVovYo0au/lt/f/wBmk/s+Fd0xO5dm779Y83MdtOtOPxGfJavuIeHdu+b5arzRIq/ImD/drTmt\n/lXKfLH81V5rWb7Q02/b8m2iUS5Vym0g3NM77P8AZX71RM2xt5flZafcKkk2ybjav/fVVLgiFG8m\nT5l+b5vu1pGMuYwqY6MRZrwKz2yIwdv4mqncTwiYJcox2/Lu31DNM/nI8L5b+KoftDru39V3f8Cr\nq9nze8ebUzDoPuLh1mUT/Iv3d1V7qR1y/nVHcXnnL5Lo1QNeiOFtj5O75N1dFOPKefWx3NIlmvPK\nhXem1d1V5L7dIzvt/wBn56qXWoecf7wb7ytVa4m8tvublb+KuuNH3TxcVjvso0vtRc7Oy1PZTb8f\n3W/u1kxzfMyI7fN91q09NXzG+/tb+Gt/hPCrYj2nwm5ZRvu3pwtbOlwutwiSPuDLWLpyTNt4+X+7\nXS6Zbu0ifOu1W/4FT5YHNzGxpcLmMfIr7X/8drZsYYW2ns3y/N8u2qOmxpCxd0wrfxV0ml2sKqrv\nD/uVl8M7nPKXNGxf0H9zMkcP3Nn3mrr9BhtmXeltvl/56bty/wDfNc9pNqi3G+ZF+X7n+zXW6FH5\ncn3Mvs3NtStDE6nw/p95cMUebcrRKy7V27dtdJpcKSMsjorIy7pfn21zuizIibHeZZmZfKXd8u1l\n+7/s10dhNDGy+dGv3fk2p91qqPu/CHLygNlvH/CNvzJCtVLyHzrg7Nrf3War0l1N5azSTLvbdvVk\nqnHcpuW5s3ZlZvkkZPlq/ckaU6nKV5IY7dlTf95f9Y1U7jezeTsyiru8z+Fqt/aS/wDoyQ4/2m+b\ndVORlkmKSnbGvzbvu/NWMpfZie5gZTlKJn3v79fJSHL/APPTd92sTVLdJtiQuoHzfdStu8hSONJt\nnzb9u2srVWmjXybZPlbds/irKPtI7H2ODp80dTkNWWGNmmT5XX+H+GuQ1hdsxLpn733f4a7LVrN9\n3751X+8qr/DXM+ILUKreSF2M/wA7Vy1JfzHu0acpanb2+oJJD+5f5o13JG1XrXUBNMZERkHy/deu\nNj1CONFTzto+67R1o2eqW0O1Gm437vvfdrzo88T4CUoHcQzboy+/jbtan210ke7hlZn+Zv4dtc3D\nrH7n5uN33WX7zbattqkMlu/k/vGZPuq9ebWdVaI6adSnGRvw6hbR7nhdklk+VGVfl/76pkc81vbr\nsdTt+Xcz/erGt7xxG0Gxdqvu+arkV08kZSZF2Mn/AI9/DXk13JVOVSPXwdXnjeRsw7Jo1muUwyvt\n2t91qfdXgt4WFy6/Mu1V3bdtZsd0hhVHb54/mT+6v8NSWt5BfWO/93L5j7kX+7trjqSjzns05c0B\n11J5kaybN7R/3k/hqK8tYbdl877zfMm35qsyf6Qyw/Kz7Nu5fl3f71JItt5e/eoVvvt/drqoazHU\n+ExNUmufLdLZ13L8yK0X3f8AZWsa8heTLv8AMY9q7tm1Vauh1BoWt2T+BfvqvytWJqF0ihfnbft/\n3vlr7DLvgOKpL3eYzZF+0TPa2yZb+H5Pmanww+Yqo82G2fKypu+ao2i+Z3SZvl+5tq7DshYec7I/\n91Ur6Wn8B4GKrTj8RXW3dbcTO6kr/wCg1T1DYq+c83nBk+6q/NurUkXylTyYdi7W+bf97/erM1KO\nTzGhkddq/fVfvLXVznjS/eTKU0yRqiOjK23bu30xmRZHh85W3Ju3NTm2Qwsm+NV3/Kzfw/7NUJIJ\ntu9Eb7tYVqnLA66VHl91FqzmEkgR3+Vm27Vras1SNv3j7hs+da5+GN1WJH/v1rWsiLMEdGRf7zfN\n8tfO4yoviieph6b/AO3Td09vLVN9xwv/ACz21pwyP5n+uVdv8TN93/drHt5h5KnzlVt38X92rX2j\nY3zzZSTn/a2/7NeBiKnMe1Rp0oxsaDfvo2R3X73+81PmvppJnhRI1T5W/efN8u2srzh9jHkzMj+b\ntVmX+H/drQW8dbcojq7sirukrzub3To9n7pct5NyiH5Xb7q/JVi2uFmkV7l8+ZFsX+8u2qNuqSXH\n3Nu1/l2/K27b96tGG1/ePO9z8nyq7L92n8RxyjOPvGlpsbtbrBvU7fm+arG2aO5EiOy7m+6v8W6q\n9v5MS+T5Ko+5W3M//stWVtX8z9zI29kb5aJSl8jGMPaTlcfFb+Wzw79219u6RtzK1CrBJGs002W+\n98qfK1TKUlVXmTZ8q7lX+Ko2t7xWZ3s1Rvv/ADP96s5QjHYdpcvKQNcwzWr3Lwsqqm75fvVZ+yws\np/cyB9n3f4qdHJMd6OmPlX5VT5mplwlzbyJNs27tv7xX3NWkY88uU5a0fd1MTUJLPS4d6I2WT59y\nbtrVz2oD7ZI3+jNuX+JvustdLr8b3FwbyHa6q+1/nrmtQjhj3Qr8r7PutXp4enzR0ieFiJc0vdMG\nSNGmfy0+79xtlV5rP9800O1/78f8X+9WtdbJMujx/c+ZlWqSq8LP8/zfdx/Etepy/ZPPqSIPLmk+\nSH+/tl8xKm8sTWod4WdN38K09Y3bHljcy/f/ANqrNrF9on8ma8YBf7vzbf8AgNHs/dLoy5oFTyxt\n/fQqd3ysrfLt/wB2q7WKRxtvRn3N/vbq2pFSZg8Kb1Vtu1v4mqvHY/vS8lsqH7zyRvUS9064/EUd\nPs/vIYedvyK38NXYI/KjdJY1wzUW8yfczj/aX/e+7UazPbt5PzP5bbvm/u1hGUo/CdX2UmWW85t0\nyfMi/f2/LVnT7qG3j2I+FX/lnJ/DWbDJNcyM7pl2b5Pn+X/vmq8175LedPNhfu/NXXRqSOSpH+U2\n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\nG3aT52R2/iZ91WbG4ubxU3oqtCnO3+L/AHqY0aeYfk4/jVk3bqs2qouxLby3Zv7v8VaSj9k5o80f\neiXFluYIymzfuRmVm+XbVG6uEudnyMv97/7KrtxJPas1siKdy/8AAf8AdqqzblPz7W+8i/3v9mue\nVOJ3U6k46kdmm6B3dF3btqN/eqK3kht0875R95UVnqeOzdW++q+Z8ybX+7VW4tXaFvO279/+r27d\n1cUjujIja82qZktpB/eX7u3/AGt1Z1zN5zNsmbcz7nXbuq81unk/vofvJ8se/wC9WfcRurb0fau/\nbtq6fu+8jOt7xUk1B1WTyfM/up822rljefbEV9/+rX+5urMurV2kXzo96t/E33VatDSLd7WPyfJb\n5fl3b91d9OUZHl4j3S6slzcXH+kou35WRo/vbq19PsXk8rO0r/dZfm3VX0ux8xvnRiy/Kir/AAtW\n7b2rtdxfeP8A0zVf4v8Aarsp7nl1JGjpOmuqrMjrI392T/2Wu/8AC+gyTQpC8LItx/qtz/d/2mrn\n/C2hwrIp34+TcsjMv3q7nw3pqN5Oy6jl8tNyK33V/wBmu6MfcMpS5Td8N6Gka/cXK/K7L826uisd\nFSOTzrN87n3IzfK3/Af71L4ftk+WZIWXyU27W+827722uv0vT7NcTW0PzKu6L+L/AHq1j/eMJVDH\ns9DeNkm/eMy/f3Nt+WrUfh547dtu75XZvMjeunsdLSZRvh3rJ8u3f81XLXQvs9u+9Pn3/wASfLU+\nzjIXtDgtQ8L7Zg8N43zbnZpG/iZawbjQ3tVXy0/1f3F3bt1el6l4fmkm+eH5W2q9ZWoeH/L/AHz2\n0brH9xlT5ttPllFEfWOb3Ueb3Wg+XC37nfF837uT7y7v7tULjQ4Zt3yZVf4ZE+9/vV6LeaO8kISZ\nFVlRvvJ/3ytZF94deOMTb13qittWplTgP2nvcqPPrrQ/OVXhkZEVf7tVL7RUmj/cvuZfvrurtbrS\n38mS1/eK33vm+6tZFxZ+XDJDZ7mf+8y/w/3q87EUzuoyOUuofJDQ+S26T/Wt/wAtG/3agns3jkUz\nOySRp8n8Lba2ptNRsXj/ACvv2hZPl3VUvkdt0z/Kd+xdr7lrxsRRly+6e3h6nKUP7NhkjZHm3CRP\n4W+VmWkRfsrRW0MbDzPm3ebtWpNQ+ztH8kOxpG3Oq/doS+RpNko/65K391axpYfm3Oz238pdt7N9\n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\nO/i/vf3dtZ95dfaIVhtvn8v5mVlr0InDUo80TOW18tok8n5pP+BLS2qwySb4XVhu2eY3y+XSsqeY\nzo+Fb5f+BVFBM+4QuVVt252at/sHNKny6lqa3gVfJR2O7/x6k+xp5aOk27/Zao4ZJo7jydmdvzKz\nJ8rf7NWLFXZGhk25b7lY1Iy5CqPuysxzWKXEJTydq/eVaoXcP/Lbeu/+8zVqws8MZePlGfb81Ubq\nNFYQfNmvN5pRm7ndy/CZkmn3KIj71/iXa3zMv+1UNxp6bvJ+6rfwtWxb27+YvnJt+b7qru3U8Wby\nO/7lTHH8q/J8u2p+1Y1lH3eYxI9D3KEtvL2bmbbJ/D/u1paboMKyqgfJXa0XyfM1ai2KK290/wBc\nvybl3eXWja2Hl7NkLfwrtrqjzR2PLxEeYraXob2uLqZGdvvLt+Xa1bGj6Sizfvty+Z9/5Pu1Lpun\npuKQwfOu5vmb5dtbGm2aSGLfCzIvy7d6/N/vV6VH3Tx60eXcvaRZWzTJMiRukfy7v4dtdv4ftkWN\nXt/lVvm+X5ttY+m2MMe1Lb54ViX5tm75v7tdh4fsbbzYXg+UMvzf7VenH4DzK0v7x1GhrN5imZGd\nfN+TdXa6LbwxRmFIWV9n+98tc34dVI5IYXm2szfIv3v++v7tdzp9ukE3/HzJumi2+Yq7q15TjlKW\nxcs9Lgjj+zQpG0m1d8n8W2tLb5luk3kqzeVsfcvy/wC9/vUy3tbbcPvff27l+XctXriFI7dnR8hf\nl8ur92RMako6uRz0kE0yO6RYfd8m7+7/ABM1Z91paLJK6QsRvXdt+6tdHLY+cuxEb7m5vmqnNbwL\n++N4ybk3P/wKp+EdOXNPU5TVNMhmf/j2yypt3M/ytWZe6akcOy3dUSRdv3/u/wC9XUSWPnMsPRPm\n+Zv4m/vVi6pDNbnzoX2DY33f4f8AaaspbnXTp+9zHI6lZ/vvn8tmX77bNq/7O2sK+08Nu2IrTN/d\n+XdXW6zsmt08yGNPM3bJNlYOoWm5WSaHZ8v3o5f/AB6uKodtPc5XVLMNl0TL7W+X/arCvLWGORUT\na3l/Nt/2tv8A47XXalb2DRvD58yFU3K0fy/N/drC1iz25d9qSfefdXnVNzvoylE5uaFI5vO+VGb5\ntrS7qVrBHUpv81YUVt38S1eutPS4vI9/Kr9zau2oGi+xvsfzNzfLtX+7/vVivdj7x3RlIns2SMtb\n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\n393zLtqzp9r5yoj8srbn2ptatJbWf59+7ayr5TbPlq3baO903n21h5rTJ+9k37a6nhf5jj+tdYme\ntvcs0qWzrGiy79u/5VWrEem37R8WzNFG/wAjf7O3dW9a6M93a/Y4eNsS7f73+7Wuvhua3t0RIcBl\n+8ybmWulYWO6iZ/Wub4jgLrTZplfYnyx/K8f3GX/AOKrIvtFSa6WdIVDNE37tv4a9Pm8N2zfunSP\n5U+by/vVmXmgpIXZIVUK6/M3y/ereOHN6dblhyyPOW02ZmX7TDGhX5vMX5qik0l7ryZEfD797Kv9\n6uuuvD940bJNBmL5t6x/eaof7F8pQ7wqfk2rG1dEafLLQ1jaUTiNW093Xy9/H3W/vVjXXnWse+GF\nflf96rV2uraLcyXCfaU2/J80kf8ADXO6lb2zSPDMm4bl+8vzM1acvML4b2OcvJYdzzfc2/8ALP72\n2qYW2WZnmm+T+Nlf7vy1q61YJaxl3mUbpVX5fvNWHJcTsxtrNMbvmRtm5dv8VLm5jCpHmNFdjTBE\ndgrLtdo2+Vammme1tWT7Sy/N+63LurJsbqcyL86k7vnX+9VxZHWNn8ltzN97d93/AGawlHuc3uxi\nW5Lzasczool+6/8Atf8AxNX7fWJoWFmlziRf4f73/Aqwn1Ldsd03Lv3Mqp93/ZqzDeQtGzojfK+3\nb/CtedUpx59TSNTrE3ZLzbbh5pvnki+997bR/aM3lnei7/8Anmr/APs1ZjXXlL5cKZiVF+9821aR\nbyeaRnRFdpPvt/DUU4zJlLlNL7a8kozt+XdvZf8A0GtDT5t0K3LzfL/tPWJY3XmIUwqf8D+61aOn\nxJN5X3d+1tq/7VehRX948utLlN21V1kkkvHj2fLs2/7tXdLjfzmd4chfk+b7sf8AtVjW83lxhPPz\nu+/H/Fu/vVs2u+ZDM8zP86r8qbd1eth4nj4iUZbnUabsZkj3/M3ypu+Wur0e4S1kRIZv9Yn3m+Wu\nO0ny5LtIZH+dfli3fxVp6ffIMJOke3ft+b5q9OMfcPFrSlGVz0XR791txNG+3b8u5v4q7LQb+aNX\nud+Ek2/w7v8AgNeX6HqyfZd8nlqI3VX/AL3/AHzXVaLrkELOm+QKyfPItEo+7YzteVz0GHWnjuok\n+Xav31/9mrSXWoVUbHjmb73l7vvVwNj4gs7phZ3LyMyxM0TKny/8Cq3a6kjRpvfYy/JLtrlqS+yd\n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\nwnDUqcpd0nQflZ4dqCT5t2xa6XS/D/2WRT5KylovlXf92m+G7Hy42R4Y/lX5Y2+81dRpemz3DedH\nCqKq7WWuiMYxOTnItJ0mGHGyFX3fc2vu+b+Kt6Hw+nmJ5NsrPs3RM/y7avaXDDEqOkO6Rf7q/M39\n6tSNWUeT5Mgfyv8AVslVyoPacpzt5oqfaH3x7P73yVz+vaf5N4IZvl875tv96u8uNnlq8yM77G3/\nAN2uY1y1toZQmxim3dub7tR9s05uY5HVLNId3nXO1PK3/wC1/u1y2rxwzXDXnlfIqfupG+9/wKuy\n1OzdZEROYZH+eRVrl/EEbrOdm7dJ8rM33flpcstzrpz5ZnC69Gk0PyQ7VZP4vl3V5n42jtrWN5rW\nFSvm/Ntr1HXGtrje947YjZvm+7XlHjBf9KdXdW3fw/dWplycp0U6kzzTxhHN9n/dzRj593y/e21w\n2vSbt0Pn7UVN3+9XZ+KrhLjzNj/OqNu2/NXmPii6fzCgfmuTlnUNpYiKj7xkapq339n3l+X5aybj\nVo5o3uTNsbft3bqra1evv3pt/wB5aw7jUn3bHf7v96q5f5ThrYj2kTrbbXAu0Qvtdfm3fw1M2tbm\n/dvt/wDZq4qDVnXcm/5W/iar1vqHmN8s2zb83zVPs4GPtpHVtrGzDo+4slH2xOHTr/HtauZXUjEr\nfx7akW+SSX5Hb+9RGPLIylUlL3Tp7e82yNNC/wC8X5W3fw1o2+pbmS6d13L/AMCrkbPVIWj3b/8A\ngX+1V2z1KaR12Ps/2W+XdW0Y++Zne6frUisk33l/u7a1G1rzo94uWZfu/d27WribHUHCqkz/ADt8\n1aNvq02GTdtT+9XVE5PiOzt/ELzY2eWxVfmZvurUq+IkDNs++v31/u/7VcnDqE0e2GP/AIDIv3at\nRsny/ZptjfxL/eWtfQw9mdtpesTSRLDNPuRl27V+Vv8Aeras9afckO+R/wCL+8v+zXDWM3mKrveN\nv2bXZvurW3Yx3iQo9tN5u51ZmZf4a46lTlOqjTj0O5s9Whjt/tKcv/Eq/Ntq0uuTSQib5n+fb/vb\nq5axurmH/j2T7ybmZfvf981oWupQxwh0fbD/ABs396vKxFTljc9jC0eaVuU2LzxAkbeTDu2x8O38\nVU7jWHtY97zYWR/ut/erKa886b7Sjrs3Mu3+9ULMklm9tN8gjb5Nv96vHrYjmie9h8L7xp/2k95n\n7THt8v5YlX7rf71QNqk0m3ztvy/3v+Wf/wAVVNbp2iDoi7Ff96v+zTJrvzGWGH5l2fI2yuKnUO6N\nGP2R8l09xDLM7t8ybflrCvG8xvJ+aLd/e+b5q0Zri5EbW29QjfcZv4qyLxv3Ozeys3y7v9mt6dT2\nmiMKlGMdzO1LfD+57b2+Vn+6tZF1Hc3HyJCzIv8AD/E1aF1cQtCm7978+35qq3F8scnkww+Udu1t\n396uzmlGN0cnL7xm/YdzMiJhtu35kq3Z8Q/+O/LTFm3TFPll3L91W+ZalhZ7e4X59u37lRKfLoOn\nTL1qsO9eVX/erQ0/93Ku/wC6tZO55JGSZPu/+O1saDeJ5fkv50oj3b2kT71EIyj7xrKPtNDqNBuE\n8tUdGZlbduX7tdZoN5IJmkT5nb7i7flrh9NuEjZEd8Kvzf7VdLY6k+5U3yCX5djRsv3a9bD1PePK\nrU/d5TvtHktvs7Ojs+59qQ+btWP/AGq3dN1KaNlufO3sqfdb+KuG0rUvMjMzuyuu392ybv8AgNbO\nn3XlqUSZdvzf7NejTqHmVKPKdha6p5ln/rmj2vtdZF/i/wBmte11S8gjF5ZzM7r8sqtFtVa4qHU9\nsIn+Vmj+VlZ923/ep1nrUzTGQXPPyqzNXo05dzzq1PmPQofEsMDRJC7AsrN8qfepsfif7R+5R1/e\nP/D/ABLXDN4ke1d4LZ/l/jZv/QVqOTxZCpVPOZEX7m2u2PJLY8+UYRmdvNrkLW/2mF2A+YeT/tVg\n6xrhWFd/BZv9Yr/NXNzeKdu57P5fn2u0kvyrWZJ4phaGVLmZfOVtrL/C1RUjy6E+/L3jZu9YSQvs\n3OF27v7zf7VY2s6w9vs3uvmf8tdr/LtrBuvFUFu72yXMau38P8VYN94kmuI2beqrGvzturjqR5pa\nHTTl7ps614ghs45pnmUmN/4W+9XD+IdcmkmkTf8ALv3JI3zbt1V9a8VJIHebbvb5mZa5PWPERaby\nUC7PvJ83zLXBU/lOyPLI3bjWrazh3/ad7N/yzX/2Wsq81bzGBTb8z1iTalukR/Oyv91qrTXDvIzw\nvH+8b726uCpH2nxHVGR1Fvd4VZt6lm/u/LVu11KSP59+w/e3f3lrk7fUJliVPJ3fP8nzVPJqk1tl\nHm27V3fN97dXFKnyw909CnUj7tzdk1VJo3+8zM+1t3y/LUlvqaMvnJbR/N/Cv/s1c+2sTNt2TKnm\nfMm6nw6w7SRuibXX7259qtXPKpLl+E7qcuWWp19rqE0i/PCqbn+Zl+9WlBeW0ciuibtv/Aq5Wx1y\nHzFeS5XYz/6vZ81XV1jEbybFVV+6396ojzSOo6GORPMiREY/L91v7tX9ri6TZ9zZ93f8yt/erDs9\nS8zbvdcKnzs1X7HVIbi4+zFGRmX5G2/d+WkOPvbmpD9m8tvMeMbkXYsnzVahg8lRCjq+1GV12fd/\n3ayLdvL2Q/KV+VvmXdWozJBHsdG2r8zfP8v+zTqe78JMafN8Q2TTYV2XPzD5921nr9CP+CTwkH7O\n2tLI4bHja5wyjGR9ktK/PmaZLpikO5EVP3vz/dr9Bv8Agk9A0H7Ousqz5z40uTj+7/olnxX4545z\nb4Bmn/z8p/mz4zj6lKHD0mtuaJ+eZjhhtXk8mZWb+GobqPzo9ju3y/LuX5lZquyXE15bxIm5gq7f\nMb5dv+1VC6Z/L8iHcqL8yMr/APfVfplStKofptHDwpmJfW7yN++mYJH8u1fmrKu43juH43eX/qtv\n/s1dDNGkMj3f3127fl/irB1S2maHe4UFmXcv+1/DUxqR5uVs9Knh+aPwnPahcStI3yLEFdlZv9ms\nS8m8lwruuW/i/hroNRt32yIU+fdj5v4a53VI0bh9qbfl3f3q76MohUwkdzE1i4eRTbw7UVn+dmf7\n1Ymob2U73XK/Lu/hrW1SP5FKTcK21G/u1i3zRbRv+Z/uu38NepR948nFYOXN7pj3rbVbybb5F+V2\njrNvFQp/tfw1qzM679m3Yy/drLmRPM3v/C33a9SnE8arg+WQmmw7WbydrfP92uo0G3dso7yNtT5P\nk+6tY2nwvE4d0X7nzba6nw/b7o2d5mI2f3K6oy94mOF983dGt/JVEf5y33Pnrt9Dt0mhZ9m3b99V\nrm/D9vMFR02jb/Fsrt9DtXbZwu7/AGv/AEKorS93mPWwtGMjV0uwtvLjTtJFu2snzLXT6Tpc0LNv\nRVEyf6z/ANlrK0VUa4SG2f52Xa7fe+Wup0OyuY2dJnZyrrsZf7tcMuaR6WHw8blu1s/Lk+zb127t\nvlq/y7v96voH9kHxFJ4J8YWF/DD9qm+0bYo/urH/ALVeJWVrZ3BSa2hyW/vf+hV6n+z7HqS+LrZ7\nDa6+aq7mibarblrKp7pGaYfmwckfqh8LfD/hXwH4J1fx/pVzu1TVnkuLq4aLaqq38K/3mrtPC3jL\n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\nVpW+oJcPBMiSIn8aq/3q7qcuY5pUY/EdtpervpMqJMissjsvzfw1srre5VZLlcyf7P8ADXnMPiJG\nYJOjMVf91tX7taUPjCZv9DmmUqv3W2fNur0aMjzsRTjKJ3y69bLPstppCZP9n71RtrDxxu8w+RZd\nu1f7tcdb+JEmkTZNhl3bm2/KtMm8TIq/vpvl3N8u77zV6NOR5NSmdtqGsPNHss79dn3tq1mzeIP9\nIZ3T5I9u+uWXxDprTKj7lRvvSbv/AGWoJPETxNtQrK025vl/u/w7q6I1OXaRzSw/Mb154kh8yb99\nu3P/AHvurWbf+JrmZSjzbP4om2f+hVz154i+ZkeOMyx/3X+9WFqHiRF/c75DF/dWlUrR6GX1flN7\nUvFT7N6OoZfmddnzVkap4ij8lraGZWbf86x/w1zGoeJNsex3UqrbXZqyrrWPLVoUfb/uvXNKpLmN\nY4fl2NbVvEEsa+S87bv7yp/47WHcahuZkSZVXf8AIu/dVSbUnkwm/wCZf4WqpNM8fz4Xaz1y1pSk\na+y5S4t9c+WWSRWLfN/vVJHM/mb/ADo/l+ZN33ayFvHSNpvO+X/ZqKbVHZhsfluG21zfF7pfwnQX\nGpTMqzfL/d+/R/aU20fOqNJ/C1YMl8Zl+f5dv3WqSO4m8xf9W3+033mrmlL7J0xlym3HqTySK8if\nIq/PUzXXmsdkONq/xNu3VjR3iSKIXh5/3ttTW918qJ97++2+sZR5T0KdSMjbh1C5Rk+VWRfm8z/2\nWtfT9Ufbs2Y/uSVzEa/NvTcR95fmq3YX21m3zN833Y1/hrmlGSOyMjs7HUH3b0m+VV+ZVaug0ed1\nhF07/ei27m/iritH1Pcyo74ZW+T5N1dBpupeduh+zKdr73/hrGUpm1OnzHRWt35cfyO2I2+Td8zV\nox3j+YvyfIz7fm/9CrHs7hL5ofnjikk+Vl/2v96r8MnmMkLorfP83+9WPNym0Izl8Rf8ybcm/a/l\n/eb+LdX6Gf8ABJos37OetSsm3f41uG2+n+h2dfnY+JGiR/lf/c+Wv0T/AOCTSIn7OesmM5U+NLgr\n/wCAdnX4544Sb4Gnf/n5D82fJeIkf+MZk/70fzPz+vI/3MVs/wByRF3f3az5IZlmlTyVCRttX+7t\nrUks3uFO9OFfcm3/ANBqFtnnQ74flV9su56/TJVOb7R+tUcL/dMe8t3LG2hfYzJ5vy/dZaxdQkRY\n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\na38K/wDs1NVUaT+78u3/AHqljt3jkR3+VWTa8lOb5V+RPm/3KXtOb4Thlh+WWpDGrxyN911Z/u0e\nY/mNv5p7Q+YV/u7flZajf5lSN7bYzfxUvi5jHl5pEi3zxvs28t/FVuC+hjQQh9v/ALNWdte1k85J\nmbdT4JrZpkdwvy/Ku7+Gsqkfc1NqcuWZsWt0jNsRGq9pbxRzM6PtRvm+VKyLe48uRXd9zf8AoVXL\neZ23b9u1f7tcnvyjqelRqcp0+mzus2+OZVWRvnWuhs7h1X7Sm1V+7t3ba4yzk8uFZkm+Vvv7q3rO\n6dsQ/KyRpu+b5t1RL4bndTkdlpd4/no7/Kv3tsdbVn5KzBE6fe+ZPu1yvhu/H8aM5+78q10+nxu0\nbpdeZvZl2fL95a87ESlzHoYWMZRL/wBhmhYb02Cb54tr/er9Ff8AglHsP7O+sPGGCt4zuCA3/XnZ\n1+ednBtuFmmfJVdu1vurX6Hf8EpnVv2d9YRFICeM7hRk5zi0tOa/HPGuTlwTO/8APD8z5PxKgocJ\nTS/nh+Z8DrHDHIyI8m1tqurfxfLRJawjLw7W+78v+1VmO3hkVPtLsiq3ybfm+al+y/aI9kyMw+b5\nlRv4a/Tox9/3T9pwdEwr7S3ib50kAbd8sbbV3Vk61HtjLzbn2/Nt+6zV1l3DumdELC2X5UZl+81c\n7qEKSRum9i0n95664noU8PDmOJ1ZR87/ADLCqbn2ru2/7Nc7qVrti3vtZ9u3av3dtdl4h0e5WPZ5\nasrfNtVvmrn9S0vdH5yIyFk37f7tdVOXuxPQhh48kjjrqNI8w71kdfmb/ZrOmtYfLXY7Z37nXdur\npNSt4Wjf54wZF3fd+ZqzVt0WPf8Ac2pt+5XpUebTsctbDwkYE9nuuN5THnP/AA1DJauZNibsN/Cy\n/LWvJbpG48nn+L/aqOb51XZEzn7u3+7XqUZRX2T5/FUYRKVvDPGvy7drfwtWtY/vG2PCq7f4l+7V\nOSNI5TIk24/dX+9UliNszOn3v7y/erf7B41SUU9Tq/D+wbUjfd/tNXb6DeSSMkNzMsUX3VZYq4HR\nbuPzjDsZHb5dy/eWut0O+dWZJpmfb8u3d96r5eaPvER7RPRNBvLOOd7OB1fzG27tnzV1nh++ZrX7\nNvXeqfJCzbd3+1XnOj6o8OxI0+dfmbav/jtdXod07H7S8+dz7vL3bd1c3tOU7KNTljynpOk3rxyJ\nNMkaGOLbt+9ur1L4L6pb2PiBdSufnW3tZHTan+z8u3/arxPRdU3NHczTKn8LrXo/w1mubrULiwtk\nWVpImaJo/wDdrxs6lKWXTUex6+VS5sxgz0r4S/Dv4b6t8CLzVfHMy2Nz428UMr6hqFwqyeXG33l/\nu1L8A9J+G/gn9rC3+Hvw68cw69pEbRtut23Rxybvu183ft5fEB/Dfgnwd4A0PWPKkh0triVYdy+X\n5jfN8396vbv+CCX7MN38SvjNefEXWZ5JdN0q2W4vGkf7u35l/wC+mr80y6nifY66HpcVyoT5qjP1\nw/avlis/g7Y6jJDJDBDZxokcf/LNttfn38T/ABY/iy+udSv3+SP5YpGbarNt/i/2a+4f2v8A4y2U\n3hmHwrDZx/ZIEOVkX7zbflr8wPix4wvbrxdc/vtkPmsrRqm1Vrrx+IjXlGMJHzvC2BnhcNKpVjy8\nx0V/oug6xa77+G3eOOL55I/kkZv97+Kvlj9o74f6ba2Vyng+5WS8mumWX7RZbfl/2Wr6J+HviTRt\nauI7DVUkitbdmW48l/mk/wC+q6rxV8AdN+I2kteaBpUdpbwozLNM27zK1y+pBztM3ziPL70T8hPi\nRB4h063mS5hkikX5X3JXlV1qHiTSbeTYkgWT70m2v0j8Wfsv6JeeJLu28RfZ38l/kkk+78tfPvx4\n+D9np6zvomgq8X/PPZ91a+zy/FYf4ZRPgcZhcVVjzQPkm11bWNWuPJf53/2q2tY8K6xpNolyUX7n\n3a328I6DpOopeW0MyFmb920TfLUXijXpry3+wIi7Vi27ttenXrKUowhE8SGFrxfvs4htU+0L5PmK\npX79afheSa6uPJT5T93dVKw8Ove33yfMGTd8q16p8KfhLf3UyXj2zbW+5trOtKlTgXQjVqVTvP2b\nfhTc+MvGVroL2citcPsim2blX/ar1/8Abi/YV8efs5/Duz+LvifSpLfRLqeOCK8uGX95I33VX+Ku\n1/ZH8Ev4X8ZWGpalZR4Vl+ZvlZq+zP8Agtt8Gdc/aJ/4JreFPFXhKLzrrwn4ghvLrbJ8zR+X5bNt\n/wBmvkKtSU8xjB+7Fn3EsHy5R7SOp+IWta5punwj7S6r/c3VufDX4mfDfRdQhutY0+O5ZX+7u27l\n/vVyXjb4P+NodW2alo9wIm+VGkq98L/2ffEPiDxJFYPpsiiRvnZvu19M8BhfYc058p8vPG1adWLh\nS5j9K/2JvE/7J3xZeF/BOr2Ol61G+37HfIqtJ/tV93WXw78E+OPCv/CN+JNHt57y1t9kV0sCqy7a\n/Iv4d/8ABPf41LqFt4k+DLyQ3MLrLEqt8zf5av0S/ZR1j9pbTdXsvA3xp8JTaXeRqqvdRv8ALcL/\nABfe/ir43NMPWpR56U+aJ9hl88NjaVq0OSZ7f8EfD+u+Dbe40f7TI1n9o2o0jfdr3T4O69bf8JZb\nb42dftG1l2tWHa+CbOHTBqBhYJM6s25NzM1afwW8a6V4T+J+PEFur6fY2811Pc3G1fLWNWbdXy0K\nNOti4Rl/Mj1K8fZ5VP8Awn5xf8Fxv2vNH+O3x0s/gn4F8QyXFj4BnkivWh3K32yT/Wf7235Vr4u0\n+3hmuvOSHft4l3Ju+auv+M2oJ42+OXjDxPC7eVqHii+uIJJE+aSOSRmX5v8Adqhb6WjKHkfC7/nV\nf4q/ZaVGNKlGEeh8HgsPzU+YjXT0jwjw7xs3JGr/ACq1Xo7FFyieZ/us9WrOz8mTZ9mZyz1PHC7T\nb03BG+9Ht+7WFb3vdPbp0eWPuxMu4tXe3V3hXZt+f+Ksq803crpMF2/eRlXa1dPNC8cgTf8AJ93a\n38VY2rW6TMzujBv+ee77tZUf5ZGVSjzQ0+I47ULMKzTb2D/eWsbX45FmX5227V3ttrqdStdrO6dN\nm52/hVa5/VPO+0M7zM6qm1I9tdlOPvWkeRUj7uhyOrWsMnm7OGZt3y1y2uWO5i/8TfL81d3qFl80\ng+VFrn9R00bW38fwrXo048rPJrU+55/q1jbRx7NtfaX/AAb52Edv+2/4pniXaD8Lb1dvb/kJab0r\n5J1rScqTsbG/+L+KvsT/AIIBWjW37aniYnv8ML3/ANOOnV8Z4q6+HWZf9e3+aPl+JFbJq7/ungX/\nAAW1aQf8FOPiYEGcjRv4f+oLY18ptdeX8n8VfWf/AAW0t5h/wUx+I8427SNG6/8AYGsa+SpFxJvd\nMnftr1uA434Gyq//AEDUP/TUToyZxeT4f/BD/wBJQ+ObbNvhRdrfw7KtQ3nXc64WqG141+T5l/vb\nqdDP82x4fl/hr6nl6Hp/FL3jbsbxPlLx7l37srV9dSDK3kurN/B8n8Nc5BN5ce+F+W/hWrEdw6yM\niblSiXxcxEpcx09nqTzYhhRd33d1Wf7eeNVSba235a5WG8mjP2aN9p+8+2ntfbRlNpP95qfNy/CY\nVNzsIdaTydjurFv7tDapthVIdvzfNXJLqgaPyZoP++WqaHUnaT5Z8Bl+7WspGHKjp21ZN64fCt9+\nmfbkhkbyNu2T+89YkepedIsLorMvzeZUys8jKZtu3f8Aw1EpFRj73ul+ab94+zafn+bbVdmfyf3m\n1X+9/stTlL58t0wP4d1P8mYyPsh3/wAO5kqPaGsYlCZdq732qf8A0GoJrSKTH8W7+7Wt9h8tV43M\nrfeX+KmtZ9EyoP8AH8v8NY85pGPL8R9HR2NtHcF5037fl+X+Kpri18yEeTDjbu2bl+9VizSFl+SF\nj/Cn8TVdW3QWoSF9v8Tq3/stfGVJe/7x+k0zG+zpDGk6Bkbf8216jkt7aNn+dim/duk+8talxY/N\ns3sqfLt3fxVUu49qojuv3m+Vv4qzlG50RxHKYOoBJXfzr1k+fb8vzLWLewxn/j2hb5V/irprqzRd\nj+TIrt8u7buWsu8tXWZ3ddnz/wAXzV1U/e0MKlTmj7xzF5azec2yHe2z7u6q0lpc28iu6LtX79bd\nxEjXDud37uX+FflqL7G8m9N7Hd/EtepRqS9lZHgYiPN8Rm2du/2j9yiy/N95q2rG3ufM2Jux/dVK\ndpeioyvOnlp/e/ire0fS03LJsVQ392nUrHPRo9ypZ2O21Fy9s3zPt2tV6x02GRWx/f8AvN92r8dm\nkitDDulWP5kZvu1oWOkzLud+E2blVv4q55VPZwN6dOPOZjQpEyPCnlN93725asW0dy0n2lEzKv8A\ny0rWuNJMjeS6bf7yrUn9m7V+zIjbY/u/71Yyqc0TeNP3zBk02Nso7/7396syaFzJ86bn3/6tmrot\nVtwsjQpCpdX+fd92s64s3WT5JsM33o1+ZVrWjzT94VaPLH3TMksvtDO+yT5U/wBWv/oVQTaennCZ\n0Z0X+9WhJIjQpN50iv8Ad+X/AHqbNdYd0+Zz/d/hrenzR90mHL1MuNPNbYkOxd/ys38LVZWZ7BU+\ndd33XVfu0TQwxbptjDzIvn2r/wCO0zy0EaJbQ72j+ZN38NddPyM5PlLkOpJHInnoy+Z822v6K/8A\ngkj8GtN/Z78PwfB3SdcuNRh0fw7KHvrmMI08sl2JpHCrwi75H2rliq4BZiCx/nDhvP3m/e29vuq3\n3q/an9sn9uL42fsD/Cyy+LPwKm0tdU1XXV0a6Grad9pj8iW0un3KuVIdJIo5FOdu5AGV1LKfyjxH\nxeJ/1x4dwcJfu51asmu8owjGL76KpJfProfBcSTrrN8vo30lKTt5pJJ/Lmf3n0/f/wDBWH9lez1G\ne7/4SH4c/wDCRQhoTft4xsdwcZXJ58zHH3d3TjPevHvHf7Z/wd+I3iWXxT4n/aK8GS3Mp/doviq1\nCQJnhIwZTtUenuSckk1+Kcnii+1fULjV9Q/eTXUj3E7JGqZlZixIVQABk9AAB2rW0+/haRU+0/vG\nX5dy7v8Ax6oznwcrcSUVQx+bVZQT5uVU6cU5fzPlS5n5u7OXH8Kzx0FCtipNXvblilfu7JXfmz94\nfBH/AAVF+A8PhqPwx8SviH4D8UQWwUQXFx4rszISM4Mm9nDtg4DcH1yTmsj4wf8ABQ34WfFexj8N\n6b8WfBukaJDgpYWnii2JkAACiQhwCoxkKAAPcgEfiHpurQwsYfmRW+VlVPu1vabq0MP3XklVYtu3\n7zf71a4vwkx+Myx5dWzms6bSi/cp80oraMppc8l5OTv1Oetw9i6uH+rzxUnG1to3a7N2u16s/Y7W\nP23/AIP678HtM+D5+JPgxYbC7MqXqeJoC8nLFRt8zAOXfJ5zkYAxk4ngn9o74ceEvEtn4s8L/Frw\nybqwnEkZGtwMp7FWAfoQSCOOCa/KK31B12zJ5asyK22H+Gul0vxA9niZ3j+b5l3fe/3a8HGeAuFr\nYmliKmaVXOlGEYPlgnFU/gta3w20e/VswXBaxFSNSWIlzRSSdloo7fcfs9F/wUh+AOrFNQ8S6D4L\nvtVjUf6UmvWp5HQjerMo/E1538X/ANr3wp8Yteg1LW/iH4atY7KMpZ2dtrMWIgTksSXyWOBk8fdH\nAr8xdJ8QTYSaaRV2t83+1WnH4hdo99zMqtu2o38Vehm/hbi87wbwmMzapKDabSp0o8zWqcnGKcrP\nXVvXXc9bE8IYjHUPZ1cVJxe/uxV/WyV/mfq34N/4KG/Duy8Nw+FvihqnhbxLBAFFtcXeuW/mMRnB\nfzC4dsHG7APrknNYfxj/AG4/CvxSsY/DVh428OaNokJGzT7XXISZQANokIYBlGMhQABx1IBH5iQ6\n8RKPJ27PvL5j/dqWTxc6mT/Z+bd/CtRivDPHY3K/7Pq5xVdNpRfuU+aUVtGU0ueS8nJ36nTPgrE1\nsL7GpjJctrfDG7XZvdr1Z+kOk/tifDnw78HtS+ED+MfCxh1K6ExvZdeiV0GVLDbvwTlFwcgDByDn\njH+Fn7WXwf8AhT47tPGUPxK8J3b2ocPbTeI7dNyupU4If5TgnBII9jX5uah4kS4ut7zKqeV80jfN\nuauY1nWEkWR0+T+LzF+9XhS8GqUcThq39p1OfDKKpvkp+6oycorbWzbet/uMv+Idx9pTn9alenZR\n92Olndfj3P008aftRfBLxZ4p1DxXqHxh8HW8uo3bzvFH4ktgqlmyQMyZ61iTftK/s5W5K3Hx/wDB\nKEdQ/iqzH85K/LDWNU8sv9m3M/8Az0WX5a4bWJPObzrnbI395vl215tbwCyjE15VamPqOUm23yx1\nbd2/vOKp4Z4WcnOWIld6vRH7EWH7X37N3h3VLfVbH9pvwJa3drMstvKPGNkrI4OVIzL6ivZoP+Cw\n37H1/bR3Xj74g/CjUL+34gu18caeqqeowJGcr+DV/PR4gtZr5lSF1aXZ92T5flrmb7T08nY23DI3\n/Aq+gyHwjlw7zwwGaVIxnbmTp05RbWz5ZJq672udOD4Gll0ZewxUknuuWLX3O6P32+Mf/BTH9mv4\nxarb6h4g/aj+GNpbWiMlnZ2/jmx2Jk5LEtNyxwATxwo4FbPhz/grt+yh4X+Ek3woX9o34SuxtpYI\nb1/H+nAJE+d26LzcO3zN82QOmQec/wA5erW+39z03fMjLXJatZv87vCxVf4vu7q7cJ4O14ZlXzCG\nb1lWrRcZy5INyi7JrVNLZWta1laxwz4Ur4fETrrFS55qzdlqn/Xy6H9Hvwg/4Ki/so/BnWZ9V0T9\nrX4T3EF3EI7y0ufH+nhJADkEETjDDkA8j5jwa9Du/wDgtf8AsMaVbyT+B/jJ8GdM1C4H7+6k+Iml\nkMevISRC3Pqa/ldvLV49uxOGqjc2TbgyP/HXq5T4PYrI8CsHg84qxpq7S9nSk4335XJNxv15WjHC\nZDicHR9lRxMlHp7sXa+9m1dfI/pGu/8AgoF+x3qWsy+Irv8AbT+GEl7Jcm4luv8AhYem7vNLbt2R\nPwc817Lov/Baj9izU9Ki074m/HX4Oa+0AHl3A8f6WuTjG4o8jruPcrgewr+VGOFLeRn8njdWjaxv\nJt8n+H+9XFk/gg+HqlSeDzarH2nxpwpyUvOUZJpvV6tX1JwPC9TCSk6OJkube6TT9U7o/qH+Jn/B\nYD9lfxzoL+CvCf7TXwp0DSnUK8Nl8QdPMrpzmPcsygIe6heemcEg/Mf7RV1/wSx/azTSB8f/AI0/\nDTxAugG4/sr/AIuhFaiDz/L83/j2u4927yY/vZxt4xk5/Cqxj43+R977+1/u1taWs21Y4fm2/wDj\n1ZY3wZrY3M45lPOq6rwVoyiowcU01aPJy8qs2mo2umzonwjUxOJVeeLnzrRNWVvS1rfI/XmL9k7/\nAIIc53ReJPhycc5HxknOP/KhVuP9lj/giiY2jj8Q/DwowBYf8LemIPp/y/1+S2nwoqts+Zt6svzV\nvaTFM0iI74+fa6s1Kp4XZ3H/AJqLGf8AgyX/AMmehDg7Fy/5mFb/AMCf+Z+q9t+y/wD8EaoVSO11\n7wAAPuBfixMf/b7mrUf7M/8AwR/jZZotd8BjbwhHxUmwPp/p1fmXounpHIiTOxLP8jM9dFptnvsR\nu43P8v8AEyt/vV5//ENs5cuX/WDGf+DJf/JHo0+B8fJX/tKsv+3n/mfo3D+zf/wSRhceTrfgYN2x\n8T5sj6f6bUv/AAzf/wAEnc/8hfwRyP8AopkvI/8AAyvzysbFIUe5+ba3y7m+XdV+OxSTc+xldVrl\nn4b5xGVv7exf/gyX/wAkdlLgTMam+aV//An/AJn6Af8ADOv/AASgRcnXPBIHcn4mzf8AybUq/s8f\n8Eq1BZdZ8F4bqf8AhZc3P/k5X5/yWtnHHG77l+T59tR/Z5o4UdHZPnZfLb/0KoXhtm9k1nuL/wDB\nkv8A5I3XAWYp2/tbEf8Agb/+SP0FP7Pf/BK0MJjrfgsHAw3/AAsuX8P+Xyo/+GdP+CUhw39seCeX\n+U/8LLlyT9ftlfAawySQ3H75dkm3/gNS29nNHH5MMPzN8vyv96tV4ZZ1LfPcX/4Ml/8AJDXAeYLf\nNsR/4G//AJI+9H/Zx/4JPT/M2r+CGwduR8S5eD6f8flNm/Zl/wCCTjNmfUvBWVUfe+Jk3A7f8vtf\nCX9myKyWy/embdu/55/7NNn0d/tBmm2ldmxP96uyn4WZzKP/ACP8X/4Ml/8AJCfAmYct1m2I/wDA\n3/8AJH3hF+zd/wAEnYZCI9Y8EhhkEf8ACzZjj1/5fakh/Zu/4JTqVEOreC89V2/Eub8/+Pyvgubw\nzDGquH27vv7X3VYg0i2t13ebI/nRbWZvvV2w8Js4a04hxn/gyX/yRzvgnMb2/tXEf+Bv/wCSPutv\n2dv+CUoAWXXPBZ443/E6Yn9b2mH9nH/gk8HEp1vwUGRsgn4nzcH/AMDetfDF/p9s80Lw/M2z+Fqp\n3mlwxx7HRt6t/E1bPwlztf8ANRYz/wAGS/8AkznfBWYa3zOv/wCBP/M+8z+zl/wSdKtnWvBGHbLE\nfE2bk/8AgbTY/wBnD/gkxDGTHrXgcKTgn/hZ0uP/AEtr4EksbPzFeGZXDfc3P92qFxYujfJc87Pm\n3fw0f8Qlzu9v9YsZ/wCDJf8AyZh/qbmLlb+06/8A4E/8z9CI/wBnf/gklI2Itf8AApIHRfihL/8A\nJtJJ+zn/AMEkyrCXX/A+0kbgfijNj2/5fa/O3y/JkCO+P4f9mm3dqlwqvC6hm+9WcvCfO4/81FjP\n/Bkv/kif9Tsf/wBDKv8A+BP/ADP0Luf2aP8Agj95he713wGGPXf8VJh/7fVWk/Zr/wCCNTYEviX4\nfdMgH4sy/wDydX5vapDNbrv85i2/asjfw1zOqK+4mZ+d33Vrl/4hZnS/5qDGf+DJf/JGy4Nx8o/8\njOv/AOBP/M/UNv2cf+CMeTG3iz4egt1H/C3ZgT/5P1BL+zX/AMEVCpE3i74dgd8/GCYf+39flv5L\n7Qj220/w1n3lmdzJM6/f+7WlPwtzp3/4yHGf+DJf/JBPgjMXtmVd/wDbz/zP1V/4Zh/4ImTBT/wl\nHw5YKflP/C35j/7f0j/sxf8ABEwkB/FXw6y3QH4wzc/+VCvyqazmt1VHtmVZP7z7arzWqbg6Q7f9\nmto+FudydlxHjf8AwbL/AOTOmh4fZhUdv7Srr/t5/wCZ+rx/Zn/4ImyMWPiz4ck4wT/wuGbp/wCD\nCmyfswf8ES2AEnir4dYXpn4wzcf+VCvyhkXyzvdF2L91dlQv5fzyQpt/i2s33ab8LM9UdOI8b/4N\nl/8AJnr0vDPMpRS/tbEL/t5//JH6wf8ADL3/AARB3q//AAlXw4z/AA/8Xjm/+WFK/wCyz/wRFl/e\nyeKPh0wPc/GOfB/8qFfkuu9o28523t9xlT5dtXrG3fabn5tv3WqJeFucxjf/AFixv/gyX/yZf/EM\n8z/6G2I/8Cf/AMkfqyP2U/8AgiHH8v8Awknw6Gex+MU//wAsKe/7KH/BEhlw+v8Aw7wf+qvzjP8A\n5UK/K+3t/OZE2SZ/2U3bqu2+mzTK877sRp/31WL8Ms5/6KPGf+DJf/Jh/wAQyzNL/kbYj/wJ/wDy\nR+n8n7JH/BEElWk134d5/hP/AAuGcf8AuQo/4ZO/4IgKrH/hIfh0Ax+Y/wDC4Z+T/wCDCvzPs9Ne\n6X/U7fkVvm+aqt5o6CRYYYVVt+37lcy8Ns3bs+IcZ/4Ml/8AJHJiPDfMYRus1rv/ALef/wAkfpu3\n7JX/AAQ7UlW8QfDkeo/4XFP/APLCkb9kz/ghux2v4j+HBI4wfjHP/wDLCvy9uLFIZtnyt8rf7q1D\n/ZybleR1w3y1pHw0zf8A6KLGf+DJf/JngYngnMKUrPMaz/7ef+Z+orfslf8ABDMLk+I/hwq7ccfG\nWcDH/gwpv/DJX/BC3aI/+El+G+Ow/wCFzz//ACxr8sJLGFZuU2Ls/wCWn3ahbT0X50mYtv8A4vur\nWr8MM75f+Shxn/gyX/yR50uEcYv+Y+r/AOBP/M/VRv2Rv+CFjcN4j+G5z2/4XNPz/wCVGkX9kb/g\nhQXBTxH8Nd2eMfGefr/4Ma/KS8sd0jb+B/eqC6hdVCJtT+Kj/iFueaf8ZDjP/Bkv/khf6pYzrj6v\n/gT/AMz9ZY/2Tv8AghgDuj8UfDfjuPjPP/8ALGpR+yt/wQ63mQeJ/hvlhg4+Mk2CP/BhX5IQw4+/\n821/vbq0rePbIkOxW+Tcn+1VPwrzpR/5KHGf+DJf/JFU+Fcf/wBB9Zf9vP8AzP1kg/ZZ/wCCJMXy\nQeJfh1z2HxgmOf8AyoVbg/Zi/wCCL8aeXB4j+HuCBgD4tzHP/k/X5PQ2u2RdibSz/erb0+F/LXEK\nru+VG+7WD8Ls5X/NQYz/AMGS/wDkjphwnjumY1v/AAJ/5n6qw/s3f8Ef1Xy7fxJ4EwD91fivNwf/\nAAOq9b/s6/8ABJ2NjLb674JPzAE/8LPmIyP+33tX5h6Om4QvDCuzftl8z+7XW6fHNGoRX3jd8zN9\n5maueXhfnHN/yPsX/wCDJf8AyR3UeEMwcf8AkaV1/wBvv/5I/RyP9nv/AIJcAbU1bwYeh5+I8p+n\n/L5Xsf7P/hL4D+DfBtzpv7PN3pk2iS6m81y+la21/H9qMcYYGRpJMNsWP5c8DBxzk/lJpEPl26yu\nit/z1r9Av+CXCJH+z/q8cRXYPGNwECjG0fZbTivzvxL4IzDIeGZYqtmlfELmiuSpJuOr3s29V0Pn\nuMuHcZluQyr1cfWrLmiuWcm469bNvVCr8CP+CaEjC3TWPCBZWGEX4hy5B7cfa6mX4Gf8E3cGNdX8\nJ8EkgfEGXg/+BdfEenx3MM3k3SK39xdvzLU0MPmW/mb921/u/d/4DX3kPDDOW/8Ake4r/wAGS/8A\nkj9Ap8D5re6zrEr/ALfl/wDJH2gnwJ/4JoTRgR6z4QZSeMfEOU5P/gXVO8/Z8/4Ja3GUvdW8FnsQ\n3xGlH/t3XxhqEbi3e1RFb/ZVNtYOoWMLQoX+Uqm3/erX/iF+cL/mfYv/AMGS/wDkj0qPh/mslf8A\ntzFL/uJL/wCSPuG7/Z0/4JOOPOvNa8DgA4LN8TZQAT/2+96qyfs1f8EiJVPma74FIPB/4unN/wDJ\ntfAGtRpHEsLuqht33f8Ae+Wuf1aRI1Z33S7nX+L5q6YeFeduP/I/xf8A4Ml/8kdy8Os1f/M+xf8A\n4Ml/8kfopJ+zD/wRvRSkuueAFDHBDfFWYf8At9VWf9l7/gi0XYXHiL4ehh94H4uTD/2/r82Lr99M\n/wAm3/Z3bqxNQW2tx5PkMd3y/NWy8Kc8X/M/xn/gyX/yQT8Oczj/AMz7F/8AgyX/AMkfp237Lf8A\nwRMMwdvEvw73kYH/ABeCbJH/AIMKiH7Kn/BEJGI/4SX4c7icNn4xT5/9OFflhfWvlsqouw/3aosq\nBTcv8jL99V/irrj4T53/ANFFjP8AwZL/AOTPBxXAeZw/5nOJfrOX/wAkfq6f2Vv+CIKEk+JfhwC3\nUn4xTZ/9OFEH7Kn/AARCik82DxL8OQ3qPjFP/wDLCvyfMj+WN6bXb+Gki3TM7wnC/wAX+1XTHwkz\nyUb/AOseN/8ABkv/AJM8WrwdmEP+ZriP/A5f/JH60w/sv/8ABFNWIh8TfDwsTzj4vzEk/wDgfWha\n/s3/APBHSGUz2fiXwAH7snxYm/8Ak6vyasLUOOU2uy/Kq/eb/aro9LhePGX2P91mVvmWol4TZ9/0\nUeN/8Gy/+TJ/1RzBf8zXEf8Agcv/AJI/VG1/Z9/4JJw82viLwJ1zkfFCU8/+BtXofgX/AMEsIpFl\nh8ReCA38JHxKkP8A7eV+YOnq8eNjsw/u79rNW/pMz3CqiIvy7Qvz/Nurln4V52o/8lFjP/Bkv/kj\naPB+P+zm2I/8Dl/8kfpdbfBj/gmhDKjW3iHwdvHCY+Ikh/8Abuuj8H/D79hbQdQW48H+IvDAuPL2\nKIvGzS5XaeNpuCDxntX5paLdbtUTem54flWTf/31XpHwjvkbxZDCdyvcPs/utXJifCvO/q7bz/Fv\nydSVv/SjrwnBmZuqrZxiY+anK/8A6Ufaevfsm/sAfGh7WDVNF0PXGtI/ItktfGdyxVc7tmIrkZ55\n5r1f9mv4Z/DT9nbSdT0b9m3T10y1utqanHZ6lNeY2nhSZnkKY9ARXAf8E8vgq/wZ+JjeNvFOgSXe\nlWSyXpdf3mNq7q+gvhh8eP2ZvjNf6v8A8Kp0a5l1+/uZGubSCJlKFW+Zn/2a+WqeHuYwhZ51ib9u\neX/yR6GJ4Bzl1mv7XxUodW5v/wCSMLx3fxaxk+Pr5V2LhvtUvkbQfXBXrXkmsfC/9j27vJrnWr3Q\njNKfMmM3ip1/HHn8fhWx+0Nrn2qa8tprySDy2ZUVW+VttfPS+HU1bTzNeQ5Mj/677u1v92uD/ULM\n6b/5G+I/8Dl/8kdy8Oc1Uf8Akd4r/wADl/8AJHrum/Dz9hjRp3fTvEHhiJyNzj/hNWPHqQbg8V0l\nlrf7L2n6c1pafEnw6tt0KnxgGVfpmY4/CvjL4sfDnW9FmZ3gkw3zqsab926vnz4nzePNJ8RWj20b\nBPN3f3V+Vf4lrtpeHOaVXeOcYn/wOX/yRxYjgLH03apnWK/8Dl/8kfp5P8KP2O/EELX8s2gXUciH\ndMvid2Ur35E+MVgeIP2ff+CfU0TSeI4PCqIqAO8/i94xtxxk/aB2r8xv+FyfFeST/kJTfud2+SOX\nav8Au7avW/xy+MFxp/kzSLLbM+3bdJ8si12rw2z6LTedYr/wZL/5I4P9Ra0rqOc4j/wJ/wDyR9y6\n/wDs/f8ABF/UMxa/4q+GgKZBEnxWaMr65xfCsA/sg/8ABCfVmMCa/wDDWY5GUi+Ms/4cLqNfnx42\n8M2HjDVHvNV0qOJV/it/4qh0Pwn4b0mPyLW2XbC25mb7zNXfDw5zeCu8/wAWn5VJf/JHm1eA8ynK\nyzKu/WT/AMz9HtM/YO/4IqGT7Tpdp4HkJHWP4sXbjH/geRXbaT+yx/wS/soFg0eLwisaDhYvH85A\nH/gXX516PqVhDGthbJCjR/dVX+Zq9l+EMdnrlp9jvLlkuNn7po127qJeHmcTjrn+Mf8A3El/8kaU\n/D7MI6xzOun5Sf8AmfbGi/CL9g7SrdLrRr3wsscZHlzL4wZwpJ4wxuD1New6V4Y0Dxr8Mrr4e6JY\nrq/hi8j2XVrbSNcRSLnoXUk9fRq+HIfgHdw+Hz4pubnybaFFZo2+VVbd92vtP9h+68S3fw8GkeGb\nMTwNGpkYv8sca15uL8Oc1pTjfO8U7/35f/JHsYTw/wAzrYafNnGJSXTnlb/0o8b+Lf7A3/BPvwYs\nes/Gv4d6XoEd84FvNr/i29sI5m7BPMuUUn2Wn+Cf2Hv2AZYY7zwF4K0q6iaQNHJY+L7ydGZfTFyw\nP0r6z/aG+CPgz9oP4FXXgbxzYNc7IpDayMvzQs38Vfl5N8H/ANo39iP4lJY721LwxHdM9ldRszNG\nv8K/8Cp1PD7OHhfaU88xUmt17SWn/kxyUvD7HfW3Snm2IXZ8z/8Akj768EfBnwz4MaG68EeC5YPJ\n/wBS8QlkA+m4mus1VPFOoy251fR5HljBS3eTTVD884B2ZOeteWfBX9szxCvhmF/E/hhjFJF/C+2S\nvY/hz4i1LxvqFtqb3LIrbmit5G/1a15y4FziWn9s4q7/AOnkv/kjureG2aw2zfENf43/APJEGoan\n4/06xRdUtrq3txyjT2ARfzKjNcL4mvfAKaNrF54p1+yt7G506WDWLm41TyUS3kG19z7x5QIONwII\nz1FehfHzxsGjGiNc7PLTftj/APQa+Yv2pJLbT/2UfHevXMzefJYQ26wqnyyNNNt2/wDfNYYbgDM6\n2PjSjm2Jvffnd16e8a1PDjNKeAlVqZzibJbc8rf+lHOQfs8f8EvgC8Gq+EGBUEsPiPMcjsf+Pz9a\nswfAP/gmekIig1Pwf5ZbaFHxBlIJ9P8Aj7618N2tqlvMEd1ZV/vf3q1NLt5lb98mf4tq/wDoVfof\n/EKM6cOZcQ4z/wAGS/8Akj5ijwZmDdlmldf9vv8A+SPtpPgL/wAE5Fn/AHeoeFRIg6L49lBHHp9q\n9KcvwN/4JzwMYv7R8JgsOVPjyTP63VfH8ciSSedNbfL8q7m+9/31U91pKLbvMjqNvzIqp935qwl4\nVZ514gxn/gyX/wAkd8eBsy5b/wBrYj/wN/8AyR9af8KO/wCCbYk2nVPCG8AjB8fSZH/k1VR/2fP+\nCZDvvk1TwgTuzz8RJuv/AIF18iatp6SXD3LfI8n+qXZtWsi90OG3ZnSGY7vmdv7tL/iFWec1v9YM\nZ/4Ml/8AJBLgXH9M2xH/AIG//kj7U1b/AIJ/fsVfF/wHqUPwmgtbe4kBgtfEOh+I579bO4AVwGRp\n3jfgruQ4JR+ChKuPzCvtNf5rxNxXfuX/AGdtfqN/wTLRU+A2rbANp8WzkELgn/RbXr71+dOreG/M\nj+zfKzr99ll2qv8As1t4U1c2w3EGdZTjMXUxEMNOkoSqScpe8qnNq23Z8sdL2VrpXbv5HC/16lmm\nYYGtXlVVKUFFzd3qpX1d30Wl7fezzTULeZmkeab7rf6tVX5l/wB6sDWLHcvyfMu75/8AZru77Q5r\nWE7Nu1k/4FWBqmlpGyTIjOn3nh3/AMNfu1OUT6OtG3unBatbTqr7Eyy/xN92vrv/AIIL2og/bI8S\nOp4b4aXmR7/2hp1fLmuae7L+7Rtuz5dq/wDjtfWf/BCuIxftf+I8RgBvhveEsPX+0NPr4jxViv8A\niHOZ2/59v80fIcSRtk2It/KfPv8AwWqsYZv+CjfxGkMpBYaQCAv/AFB7Kvj7VIc7kSFfu/J822vt\nn/gslZrc/wDBRD4h7gAD/ZI3bef+QRZV8c69ZuPndFVV/i+9ur1uBFbgXKn/ANQ1D/01EvJ/+RRQ\n/wAEf/SUYKb5Or09W8nO9Ny0y7j8ptnlqP8AdqFGk8vH8LV9Rynpe0J4ZNsn7nlv4FX+KrC3Dso+\nTb/f2vuqtbs43f79SrI8bZT/AHflqvsC9oWPtE8mxE2/N/6DTf37be237tNS3mk2zGHLL8u6r0Vn\nHtDvuH/APu1H90xlHmK0Kuys/nbl37au2trcySK4CuKt2GjpI2/ZuWtex0tm+RIvmZP4aqUhRM23\nh8lV+Td/vVbtLN48v0Xfu3fxL/s1sW+ho2xxbZZm/wC+avWuhmNd/wB5mb/x2sJSlKRtTj9oy4YY\nGw7wt8vy7asW9tNu+/t3Jt27627fQd0nzhk2/Ntakk0d4ZN+z/gTVzylynXTp+0MZrOaE7Oq/wCz\nSLC+1Ydqn+L958tbL6X5ab3pPL/eK72aru+X5v4awjUka+xPoJdJfzpUidd8a7kVVqytq9urBEUD\nylba3zbmrXm0v/SHfCs8KfO277zVE1vsk2PtULt+b+9XztSnyn2tP3viMW4t7qREhhmVD97d96s+\na1thiBIVy25VZk/i3fxV0N9p/nXEWy2UfeVmZvutVS8tU3CDYrfPuRWf5qx947JRhyGBd2syx7Pv\nIv8A481ZWoRwsy/O3zNu+X+Gt/VI/M3bblh5afw/3qy7qNJpvufw7mXb92uiHuz1OGpzcskYEsJk\nvtkz7Qvy/N92oZLWSybZI7OWf7tXbyP/AEkp5K437XWo12fZ/n/4+P4N392u7m/lW550o8xJptvD\nZ2vnQ/NubdtVfmrc0mG2kmSZIZGVX27fu1lWazRuCg3Q+bu3fxba6LSZoY7pNiNsVd/+z/wKol+7\n1FTj7SXKael6T9qMabMI38P/AMVWqunvG2weXt+6q53VFbslwo+zIrbl/er935a0reNI1TyYFULt\nX5v4f9quGVTmiehGnCIxdNST5/J+b+BW+XdULaelvarcw/Luf+//ABVda32xv9pfftddm1/4aqak\nu6Zktnwjfdj/ALtKmVOMf5TA1Zv3zcc7PutWO025ZU2eW6r91m+WtHWmhkuvJmRnXyl3Mr1j3000\njM+9URvldd/3a9CjLm904akuUZcXH25XtvObb/Ayptqpd+SuxHdpNyt8yrt2tTXu5riRkTcP9lvl\nqOfyfPX/AFbts+Rlf7tdUTL3eXmkWmk863XfNwv8P3f+BVltvWRgrsN3yqrf3qtzahuiRH6q/wAy\n/wB2qV9eJFG7u7LtX733mauqjGf2TCp/MQXRjt5vOmTlV+81fqT/AMFtJPJ/ZU0CUyFAvxBtCWDY\nI/0K+r8p7ybzpPvsrbf4q/VP/gt9HE/7KXh0zRhwvxEsztbp/wAeN/X5D4iQlHxD4YX/AE8rflSP\ngeJZc2f5b/in/wC2n5uQ3zyMj21yr/3dyf8AoVX9N1Z4d9sm5Azfd2/Mrf7Ncvp+peYr+dBtG/cu\n2rUeoOqu7u29vl3bPmWv3Lm5T6U7Oz1K2Zmfzvl/ur8tatrrDw3CeTM2N/8A47XCQ6t8w2OoXyvu\nqv3a0LXXP3yQzJmJvmRt1Zy2Ob7Z6JpPiDy9379gGdl3L/FWrHrT7Yd8zPJu3uq/dZa84s9WlWFU\n+YsrblaNfm/3a2dI1SGHbcwtIV+7ub726vOxEuU9TCxgehR+JkmYQwyt/e/3f9mtO31q8jVnuU+Z\nX3Oqtu21wdjeJKvmbFdt+7/gVa9rrG5neHcvy/6lvlb/AGq8mtWnDY9/D0YSidnb+JJWkVEdUbZt\n+akbX0htjCjtKvm7mbf8rVx0mtzQ/chZP3W5Pn3U5te8q2dHSTDfL/sq1ckpVfdSOnlpRibl3rKT\nTSvC+5t21FX5dq1kapqieX+5RnmVfmab5laqU2qJCqwu7Nu/iWqT3c214Zvl2vu3L/drOUpR3FGM\neUrXlxc7o5j+/wBq7fm+Wuf12N2kb+L/AIDWlqW+GMJbOxf723+FqybqeZVYeYx2plFX+Fv7tbRj\nKUeY5KlSEI2MPVNkKs6OwdvkRWi/9Brndcjja4a4dGVpF+7s/wBmum1aVNrfO38K7m/vVzmqXHne\nYjw7fnZk3fw13Uf5jjrcnJY5TWrXbGv+jM7N8ybvurXN6pD5NuYE/wB7bXVaozyMU3tsb+981c9q\nFokavv5O7aq/3lr1Kfux9082pR9ocrfWaK3yf7u3/ZrMmt9sjPsX/rn/AHq372O2hlDo7F9/yf7t\nZ95bozHZCuz/AGvvV1+0mcssPCRjSf6wfOw+9Vu0jSRm84MGX7rfw05oXdg6bf7u1v8A0KnwwvMy\n79o+f+GqlIqnRL9jvZkeH7q/eZv4q3bBvL2PCVX+FuKybWFNvzfw/wAVbelxwyTJDbfxfM6sn3q5\nZVIxOuNPob+nwpJjYihmf+KtrQ4Zmm850+78u2sjR7eb/XTbW+b5FX+7XR6TCm1ZnRv7u2vLrVj0\naVPmOgsfJhZPn3/w7f7v+9XRaSrMvnPuQR/wt/F/tVzumzPLL5yPsZX/AHu5PvVvWrP5x8l97N82\n1v4a8+p/KenS/vGtbxpDDHNvV0V9u3+JV/vVfaaFNmyCSVt33V+Ws7Rbj5VnuZtr/c2zJ96r0b7r\nOWFEXdJ8u2T5q5JfFqejTlDl5kWGsd3lu7rv/gZX+Zf9mpo7eZPKldFWT+7t3bf96q+5GkjOzlf4\nv9n+7U9id0Z+xr/H93d/DUumb0/5h0NqLjfv+b5PnVV2rWhawwtH88LB9m2L5fmWo9LsoZES5d2D\n/fRW+bd/wGte1t5ZI1ea2kX+Dcyfe/2q9CjGMtg5pS3KUOn+TIibFaXd91n+7Vu30tyzfaUUsqsy\nbvmrStbXzJBsRXZvvKqf+PVZtbNJm+2W0LIWf5FZa9TD04y0HL3YlGHR7Zo1mghVHb+L7y7aSfS7\naEeTNtEzfcVU+ault9BS8s1h8ldjP95vl20640ZFukSaZfubVVV+9/wKu+MeX4Tj5eY5C50ZI4wE\nRVK/MnyfeqrJpczKXm2yx/LukVfvNtrsP7J3XRS5h3Jt/vbWaqGpaPeW8I2QxjzH+df4Wrf7Jz1K\nfLLQ4i90m13fIiq7bleOSszVLd1jHnPvK/wr8v8A31XZ6npbqzPCkmxf+WkjL92srVNF2xsifvmk\n2rE3y/Mv96spR9n7xwVOWM+aJyP2GHzUTZiTd87b91QskK3DO+2FZPm/3Vrbm0/y2ZEdizbW/wBV\ntXdVK60t9x8mFd/3pWb5vlrjlUvPlJqR5PeZzWt2YkXelso3J/rF/irlLqzmjkaF4c7m+Tc/3q9H\n1azhmUJvVF+6m7+Ktb4K/sk/H79pbxRHo/wa+FGra47P5TyWtuyorL/E0jfKq1hLWHMEcRCnL32e\nLTxO0io4YfOqoq09tFmZfOgh3Kzfer9Ovg1/wblfE+6t4Nb/AGjvjNpXhmFyxl0fTU+2XCr/ALy/\nKtfQfhz/AIIIf8E8dDhjTX9d8b65IyrumbUFgXd/sqv8NeVWzbA4b3ZzN6M6lTWMJSPxHuNJmuG2\nTIzFfmZlSs+8s042TL/3xt3V+8Fx/wAEMf8AgmzJ8n/CGeKIdyN/pC+JmZt396vOvGf/AAb3/sia\nwx/4RH4v+N9IT7vlzGGda5o8Q5b/ADnuYPESpz96Ej8UryzSSR5rl9h2fxN/FUf9m7V39Wb5vmr9\nN/i5/wAG53xa0dJb74I/H3QPE8C/6qz8QW7Wtyzf3fl+Wvj745/8E9v2y/2cpLhPip8CtUitreX/\nAJCWjxfa7Zo/726OvRjmOFrfBM+rwuYYGrv7vqeDLYujZTbt/wBytSx0394iIcLI/wAi/wAVT29q\nkd8dKRfJkX78MyMrf981p2On7WG+aT+9uatJ1Iyhqe3h8Nh60bxI4dNeS1Lvt37/APlmn3WrSh01\n44w80LIGXcvy1ej0+2tVGxOZPubd3zNWhbx3MatDNM2W/h/h2151Spc1ng+XRmPHpaSTKEh/31/v\nVDeW+6Z5vtLAKv3VXd838NbK2cMknk3u1dr/AHt3zVQvLdF+RE4/+yrOUuY8LGYXllJo5q8td8m/\nYp3P81V7q3RmGHwf4NqVsXC+Yz/dXa3z7VqrJCsjH7N8g/vfw1dOp3Phcww/2jKa1SRVd/Mb/gH8\nNH2SFlVI+uxq2Y7N7hVRNwb7u5futT20dF+eP5yv8NdMsR7OEbngRo+8c6tjuVbkIrfw7dn3v9mq\nF5pPzO8EDY+7trrfsLtGUhh+9uZJP7tZV5p/zKmxQ7ffZaujieaXvBLCwOYjt08p9+1n/gj/ALzV\ndtNPuWV0d41+7uX+KnyWaWd4HR9jb/utUu6BWaZHZpW+bbXTUqe77plTpx5h9r/r2hRG/wBht1bW\nh2LsrQo8bFf4m/8AQqzLFXluPOmhaIN8y/LXR6HpaTQvDMivtfd/stUyly+8acvMdJ4d0nyYwro2\n5k3blrrNF07zFSOd1+b+Jf8A0KsbQ7VJlCJtb90yr821Vat/RPOs1Z5rb549q+Zs+WRayjGMp3Rf\n8E1tPt0hXeLldyttdWTdur79/wCCYK7PgFq6bcY8X3H4/wCi2lfCFlazQqkxdf3n3NqV96/8Ezon\ni+A+qrJFtb/hLZ885z/otrzX5B44QnHgOfN/z8p/mz4zxDrQnwzJL+aP5nxRHpc0kgR+QzKrKz/d\n/wC+at26vtaF5ldI22p5cW3/AL6qBWRdz2yN/eeH/wBmq15aRxBxtRF+/X7LTo8vun6dTxEY/aKt\n5bw2u37M7OJHZmXbWBrMPlq8L23y7d3zP/FXVTWU0k3nPbb0X5tzfLtrA8SWP7wON2+H/vna1XGn\nHY9XD4zlicPrVrDcWv2xIV2R/wC392uR1hfJVoUuY3VvmRq7jW1S3t3+zQqyfMHX7v8AwKvPPEV1\nGrtCibWX7i7/AJWrrw9PmPSp5glqjJvvJC/c3bdvzeb/ABVn3jfenZN0bfL/AHqmkuPLbyYUb5fv\neZ/dqpNK7SLsRfm+Zv8Adr0KeHiznxGaSUblG4V9rfvtxZv+BVl333X2bj/tf3q0ryZPMd+m7+Ks\n28kZofJm+4u77tbxo8sD5/FZjHlKd3NuiVHucbW+9/eX+7UljO8XybPl/gVf4qoXE0MjEp/D/C38\nNPtbh5mSOF9p/gZaJRgeDLFe/udRpsc8bfPCo2ptT5t1dHpezYnneX+8+Xdv/irldFuEZf3yM0q/\nxb66OxukmuEM6KF27kVq5qkvslfWubU6axYKpSFGQx/L838NaentCsiokys6/ernoWeOMOm2VvvL\n833a1dLvIWzDMiq6vuddvzVx1Drp1uU6/wAM+cJN6Tbdv3fM+bctehfD2zv9U8RW01gm2aGdZYo1\n/iry+zvna3RIef8Adr1f4E+LNN8N+PrLUr9/LtI5V3My/eX+Kuevzey5UEsYoy5on6r+BPFHiXQ/\n2ZrPwpD4Rns9S8Q2X2aK9kX/AFny7W2f99V5v4I8T6V+xv8AEPSf2V/C0NjeeL/F8sbeJ75U3S2t\nu3zLHu/h3fxV7J8S/wBqv4D/ABX/AGQtGt/h1qq/27oC28ulxyRbH8yP722vlOw/Zs+PXw4/ba8L\nftT/ABr1WH7N4vuPNsVafzJGjWP/AMd/2a+KzTC8vv0n0+4+hyDNaGMcoYla/wAvd9Dpv2jGnuPE\nF7D8v7m62pGv8P8AergfD+g6lrF0m9NsMfzbf/QV212v7QEkM2sX9yjt5zS75V+63l7t1VvhHC+v\nrNNBbMixxbtv3v8AvqvnqkvdPr6dP2h0Oi+EfCVrC2t+J7C1eSayZIpLj7sf+0q/3q+Y/jZ8G9N1\nTxauq/2VNJbzXDJFGsW5lXd8tfTHiDx54W8E6olheIuovsZpVWLcsNcVfeL9N1hZB9khc/M+6T7s\nNezlsv3Wp4WaU+Wryo+ddS/Zd0HT45bm8sIYhv8Am3f7v96vBPixoug+EZHSO8/1e7eyt8v/AAGv\nb/2lfjVeaDaromlWc0sU25vMaX5a+LviN42v77UjbXjsyyOzfM25d1exGdSUdDx/Z0sP702Qa14y\n3Xh+xvJFGr/wv/DWJdeOJrVtiTMwb5V3NXPapr3mNJC6bv8AarlbzXHuJkREby2fa+7/ANCrpp0f\nb/ZOCtjYU3aMj6h/ZN+FPi34uao+qpDN/Z1n8txcfdXd/d3V9Y+Afg7eWviCC5sHbYzqm1ov/Hq+\navhd/wAFA9B/ZU+Eei+FPASWtxcfY2/tS6mtVl85m/3q6C9/4KqWHijwWLvS5oYdRX7/ANni2ttr\njrRqX92kevh5YeEPeqx5j7D+P3ii2+HOi2fg+515ppL7bJEq/Kscf95lr6y/4Jca5Y6t4CutFgK/\naZbZhE8VxuWRfm+avwlm/a08V+LPFreJ/E/iG+vLmaXa0l5cfKy/wrtr7u/4J6/ts3Pgm6trxNV8\n5WlX92su1VX+Ja83FVKtCUZzjsdeFnQxNKdGlL3mffHin9rrwf4B+IF78IvEOpLb3bRbYmml+6u7\nb92vP/E3jLSfiRpMvhW8mWaxVvkkZfmkb+Fq8E/4Kha54Y1r4Xr+1F4Pv47TWNNv4/tUa/6yaFvv\nKteN/s2/tOX/AIkuIEu9TuJ5mdVlWR/lb/drhXPKPtYP3ZH0FHD4eUOWovePqr4E/s9+LU8bPNo+\npXFxEt/t+zzfd2/wr838NfUd5rGq+GvDcOlXmiRw3bJuna3Tay/w/LVD9kb+yNb0K31Sa2VZWbcz\nRv8Avd395q7j40rpqsUis2+WJl+VvmanWjGNByXxHlVpSjjFTPCvF99NqV5/xMkaTb/E1eFftreI\nLzR/2dZbaGLybPWNRhggWSLd5kit/Du/u19DeJNNttL0b7fNGw3fek+6y/7NfG/7dnjC88SeINE8\nAXM0ktjpdu14qw3G6NZJF+X5f71HDWH+sZvGUvsl53iPZ5e4r7R8+WukXm1v30YZU3fvErW02F22\nQ2z/AL3yvvbf/ZqdptrNbzRebN8jPtZlT5ttX4bfddK42+c0v9/+Gv1mUYS90+Lw8fd1J7W3hW3d\n9nlMvzfvv4q0lt3Xaj/eZfn8tvlqGGzcRs83lojP8ke6tOxsy37lHX5tq1PsY/EejGXL7plalpcL\nbpZtqN/EzfN/wKsjUdNdl85JpN/8S/wr/wDY12P9lv5LQjdEV+Vo2+aoJtDma3WYWbfMn8SfK1aU\n6alLQ55VPsn0v/wTftVtfgfqoVwwfxXM27dnObW1r4F17QftDNc71j/56/3K/Q39gi0is/g/qSQs\nCreJZmXAA/5d7cdvpXwzf6D5kLKlthV+ZvMr8a8No38Q+J3/ANPKH5VT8x4fqW4kzZ/3qf5TPJtb\n0GaJmmh2/vtvzb922uW1i1eFXRHbP3dzfdr1nXtDeOzlufJ2qz7tu3ay/wD2NcbqmivC3/Hsu1m3\nPGv92v3OnTjI+lqUzzrVtLEcJHzM0a/eZ/4mr6l/4Ij2H2P9rvX/AJMY+HN4uduM/wDEw0+vn3V9\nHTa6O+/c3yRtX03/AMEZbMwftWeIZnQAnwHdgY9Pt1jXwPivf/iHGZ3/AOfb/NHx/FEYxyavb+U+\nff8AgsJZJN/wUC+ILZU7v7J3KV/6hNnXx54g0nyZD87bK+3P+Ctun/aP28vH8pQFSumA5Xv/AGVZ\n18ieJtJdsP5zbf4VavW4Ej/xgmVf9g1D/wBNQJypy/snDr+5D/0lHmmqWflzb9indUENq0is+Mba\n3tW0l42be6ru+ZVqlHpLs2x/l+T71fU8vL7x3lOGyeTPz4/2qtxWrwypI+77u1FrVsdHm3L5Cb0/\n2q17Hw+l0yzTIyf7O37tRy+7oXI5+10maSTZHubb/DWvBoM0m1Ifu/xq1dJpvhtWQPD8qKny1p6X\n4bedorlPnZfvfLV8vP7pHwnO2eh+XtTyWH+1Wzb6PtK7eG/vNW4vh8Rw732v/wAC+7V6Pw3N5uxE\n3xr/AMtlf5d1ZS5uUcTEsbW5hVP9G37fm2tWxptiki73TczfMu3+GtCz0O883y0O1W+/5nzf8Brc\n03wu6qrPbfvf4l/hrCUZnTTMi30N7iQXiJ8iy/w0t1o7yM+Icf7P8NdlY+H32pN5eFh+Zqv/APCN\n2p+/8ssnzIy/3a5anmdtOXLLQ8wuNIhkHkvbbW+981UJdG3SM7uo3f6pl/hr0bUvC5aR/ky+z7zf\ndrE1Lw+luqQpDvbf/u1lH4/dOmMoy909tSGFpA823cv3I9ny/wDAqguLd/tW3fG8TL87L96tmS1e\n2tftKRbXVmVfO/iWq3nfvEmhh2fJub5N1eZKifaRiY1xClvIYZvlaT5l2r95f9pqzr+xTzle2kVB\ns3bpP4a6bULZLhd6WbMJE3N/vVlaha2zRrD8zOv8O3+Gk6XLqhVJcsTndWjmjjdLOZf725fm3Vz9\n9GgXZ53LfejaukuLPcu90Xbt2pu+X5a5nxBGlmxmT5FZvvKtT7GSlY4qlSP2jL1Kb7s2/fu++392\nqbXH/LHzlO7+Kn6lPukaSFP3W35t1VbVvJT988eNiqkar93/AGq3jHlPOlLml5GxZtM0a/PlV/ur\n/DWzp7JDDuR2TbtZGb71czHebm8l04V/4W+at3SV+1P5KJu/i8xf4qxrR5YlUZRkdZpt4jQpdTTb\ndzbGkrSh1C2/1PzOse75fu1zlnI8MKJCcJsZtv8AearS3ltuN55Lea332Wubl97U6uaRsf2huhZE\ntmV1T7v97/aqjeXDiPfNudfuvHWdcalMzK7zLG27a0bP/wB81F50ykzTTrj5l27vutRGMypVJdCD\nWGt5oX+fa6/Mi1zbXCOypv2S7vu/eVqvatdQhmSb5y33qwtSuv3exHXZt3Mv+1Xdh1GMTzMRKTkP\n1C4RlYzeYzq/8LVnX+sRhWSxdQn97+KorjUIUVnRFV2+/uesa81ZAqv/AHvu16UKPMcUsRLk5TZt\n9SkuNrufmX+791qbc30PmL/pkjt95l/hjrnYdYeOZk879yz7U/u1dutQhmhDw7gm37tdlOPKYSr8\npozXUdxGN+3O37yv95q/VP8A4LlTTQ/smeHmgcKT8RbQHPcfYL/ivySh1LbcPxvRv7zfdr9Zv+C7\nUxh/ZF8OkEc/Ea0BJGf+XDUK/GfEeMv+Ih8L/wDXyv8AlSPhuIavPnuXy/vT/wDbT8tluEaTZ0H8\nG5qsLfTKPJR9jf3q52S+e14++f4Ny063v/NV/wC8z/8AAq/bpS+yfVSqe7/eOoj1LDFHdX3ffqzb\n6k8zP867Ifuqtc1DcGRvLd2I/jk+781aNnfPI2/zFwybdy1zVJTN4/zHV2OpbpVCXP3k+Tb8taul\n6pt2qjybl+bcqfLXJrqCWsMUe9f/AGb/AGa1dLvJlXe8ytt+b5V+7/eriqHbR+I7e31SZoU/cqE+\n9tjfa1aS61vt/Oe83MzqryMn+zXFWeqQ3CsnnbVX/no1WG1RzGjpMzM3zbY/ljrx6y5tT2qNTlgd\nguqbVS5jT94yt8zNTJNUyzO9zv8Au+aq1zy688Nn/rsGRNn+WqRdWmiVv+mibNq1Eaci6lSB0K3D\nySsju22b7lKt1Zxqu+b51X51jTdWLb3zvGqO8ilX2/7W3+9UlvcJcSH5/N3blebbt3KtR7Mj2kPh\nLc10l2rzTSs0Tf3V21hXzTSxrNbSMn3ldW/vVtbIZoVffuEaf6vd95ao3du8cLu+1kbb+7j+9Vxj\ny+6ElzHO6nNftH9jc733fd/2a5vULf5pkmmbau1kVv4q7C+heFvO8mTDJ97/AGq5/XNPSSTy3h3f\n7SrXVRqRj7qOSVHm1kcvqFq8MmyF2f8A2v4dtYmpfKzTbPmX5UbZ8tdRq1r5e77u1fvVgatMgGx+\niv8APt/irrjU5pjjh+aPKctfW825n+638CstZ+oWzvGwT5n37vmrcvlMg/1Pyt/47WXf2TyK3zso\n+9XbGXumNTD8pjzK8ch9KW1t3jbfNHt3fNVjyUbO/wCb+KpY7UM2x33nb8tac3Kc/sZ/EWNPV/m8\nlGDf3m+7XQ6Xapa3EWxPm+6zL92s7TbVIdnnQsG2bv8Aero9LhSSP54Vbd9xmSvPrVoHRToy5zV0\n+FF2Om7d93/Z3V0NnHNGyb5FD7PvKlY9isIi8nLfN9zb/DWxZx/IyvMz+Z827+7Xmyfvczid0Y8v\nwmtZq8cfyTfe/iZf4q1dPUMrfut8UafMy/3qz7Fprjy4U2nam35f4q1LFXb/AEZwuPuurVjKXu8x\n1R980IUfa8Lw7yzbauTrM0cUybc/d27vu0Wq+XiaaH5fKbbHGn3lp+n2u0lEhb7/AN5q5fe+KB0r\nljo5Fmz861VHRF3bPn3fNVqzV5mSa2TY2397HIu5ajs4ZoULvCriTd95v/Qa19Lsd0iujtsXa77f\n4V/u1pCXvSOyPN7L3S/pdq8W3y4Y9n3ZW+7/AN81uafpqKv75Pu/L8v92q2i6bNbqqzXO+LezS7l\n3blroLWzSaRXiRXEPy16dKPuXiZfDIpx2LyTLsT/AFny/NWno+kfu/n6t9xd+3btq0unpGFTerlf\nuRwruVq17Oy8va8yNv8A7u3+L/2WuuEo0xylKUit/ZnmWI2bVTY29W/hqS30kt+5h27Nu7c396ti\n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\nZuoX3lgrv3bflqG+uvJkd/Mx/drIvNVTdh5sOzfxV20jy61blLN1qCR7djsE+9t31Yh17y7cIj7v\n9pfutXPTakm4u+1QrU23vk+Z/O3f3lWto+Zze0n8R1UOpJJIrwur7v8Ax2v14/4L4TCL9jzw4GOF\nf4k2asfb+z9Qr8Z9Lk3SLsfaV/vPX7J/8F+3Cfsc+GiQTn4l2fT/ALB2o1+L+JGniNwv/wBfK35U\nj5PO5c2dYD/FL/20/Jc3nnMrvu3L9/56WG4mm/vLu+VqpQsnmb/4G/i/iq5aLPtZN/3q/aJSPq6f\nxaGlZyP/ABn5v4dtXLW68uP5OP8AZ/u1mwTPDIIZvu/3v4au2rbvuOxX7tYyj/Md9OPU3IbhZmTf\ntRV/iX+9V6zvtsw+f5VVty7vlasO3wqrJPMqIzfLWgt4WJTeqbvur/FXNKMDup80feNu1unWzR0f\nMjbtnyf+OtVuz1GNIdibd38e7cy1zf26aPd8m3d83zVbsdQ+VEdl+VtyR159aJ3UakeY6Bbh5ttl\nc7nRfu7U/wDHavLcf6Qk1t5iN95W27qwY7iZY/nmZl/i+atGG6dVV3DY/jVfurWcoy5dDSpym5Jd\nTKUCBlDS/vWZfvVbtZEmk2Qov8P7yP8A5aVkWcyTXqJMkjo3zJWpawzRqZofkRf++t1YSjHl+Ifx\nTLqx+fDsR1Ta/wB5f71F5Dtb7Mjt5Ujrs2/N81OM263RHdvufvWk+VaerXjKNiMhVPk+Tcu3+7ur\nOpzx906Y8stjIvFmXd5MvmeSjKjfw1iahbpJC7pctlVZmWul1Cx8lZTZ+WI/7sfzfNWHdWrhRBcp\n/tfKm2lGP2izl9Tt3WF0eFVuN27dJ93btrlry1eNi83Ndz4itXVtkKbn2/J/drlrq1eaR3hhV933\ntvyrXXTqe7cuUeXY5TWLWbcqxuyj723+7WbdQ7mPz7m/vVvXlj9qmZH8z5f4aq3Gnv8A3/8AdWuy\nnU5dDn5eYwPsqDcifdb+JvvVcsbHDRl15/u1ba3TcqCNWZfm+Zau2Nn/AMs3fcrJu3f3aVSt/KXT\noxj8RY02xjVt/nK0v92tezhTzA8KMu7+9/DVezsYY/Kfycv91WX5q1Y7J7Xcj9Pvf8CrzpSibSpw\nLVvb7pFfZh1+X5f4q1NPheObzoU3bm2t8ny1Vt12yb1fKyJ/F81aljG6t874f5dsa0+blhocvL75\n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\nvc2tJt4ZG85OkPyfL/eb+9Xb6Pa7oUD7iV+X5q5jS7BLf99sZpvm+Vf/AEJa6vw5D5caQu8hRtu9\nv4vmr1sLHmgedWlKnI2rO1v4WbyYdp+95jJ91f7ta2n6b5kqCFJDui+8v3ZKn0u322rJs3K3y/vP\n4q3ND024t7ZLa52r5m1nb7q7f9mvTo05bHDKsZ9lpd55Zd9u3/lqq/dq5HpsUOOJJn+ZW/h27q3b\nPS0bfCvCK6/e/u1eh8NpNO6XKbt23yo1/wDQq6+X3iIVpS0OPutLSa2aG5dnWT5W/wBn/ZrjtT8M\nv4m8Yf2NZ6rCkdi6u9vN/E38P+7XrfirQ303w7fTb4UZV2xSSf8APRvlWubsfh7beBbe21XWE+z3\nn+qulkdW85t33vM+9trxM6xEcPQt/MVXxE5fuzE8eXUFrobM6Wtpc71RGh+8zfxf7v8AerwLWrq8\nj1q4ub+88x9vyMz/ACxr/druPi5Z39nqWp2E7xvNNLt3ebu/4Furze6tbm+WPR7C2Z5Gibd5n3Vb\ndXylBSlscUve9057xtY3k1mk9rDHsWJn/wBnd/erzfxhMY4Wmhud1zsXd6LXq/i5bzRdLh0S8ud6\nxtuVY4vmb5fu7q4C+8L3OuBM+dH5j7drJ8rf71dVGpGM/IKkZShynAQ6akl2u9FZ4X82WRn+61UN\nSv5Li+Wa2Tj7jt/E3+1XobfD25vLUQq6q7PtXc235v8Aa/2aydR0PStJjSz1W/tftbbvNkj/AOWf\n+zXrxlQlI4KlOUYHAeIrKG1kifzpJkZN26Ntu2s1Y3tYpX+0tvVt21mrqtet7G1kR9/mBvmdv4dv\n+zXLapqENxL+4SN/7jbvmWolKEjL3ojvO1Web5H3Rybdnz/NXQaPYa9JGdh80bvl3L/DXP6XqFhK\n2x5sS7921vl212ek606sjpCqQt/t1wYyo6cYnXh/3kviNLQ7waVMX/drc7du2RvlWu/8D65Msge5\n2vcNtXaqf+PVyVrJpWoYhhmt9330aT+9WhperTabfeTc6lCySN/yz/hr56vKNaUrn2eV2pSjzHu/\nhnxNNbRl7n7mz96v8O3+9Xtfwl8baVrmjtZ/uZRt3eY396vk2x8QOy/udVbayMvzf3a7L4b+OLzw\nzcJZW1+tonmr82/5W3V42I5afun29CrSjLl7n1VHoNnIq3MUKymPdt8t9q1Vk0fT9F1a2v4YWaGR\n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\naz7pU8mM7X2/N96qu4o2yaFUaP50+Stoc3NzM5JSIdLs5rMv5MaqJIv9W33Vatyz2W7hB8/yKjyL\n81Z1jb20kjzIiov3mrQ023SOZvnbzfuv/dZaxxEeY2w/vG3Cq28jTSbSzIqquzburV0+RFkVNke7\n+Dd/FWTaxPI/kzfKn3Yv7y/7VbUNn5yrv5RWVn3fKqtt/hrglzcvwndT+I17NZ71U2JlpHw/y/Lu\nrahhdW3vx/7Mv8VZdnvjQuXwV+5t+7urY0GSFt0f7t1b5UZv4aI8nNblO77HMX9PtYJJP3MPyt83\nmK3y7a6PTbWzkkF4ibdvyrtT5mrN03Tfs7L5ab0/jXZ91a6PR7JLVUTfIFV/3XzV2UaXVHPW92Ja\nt7d92PlEv8Lf3VrrPD6wrJG+/c3zfN93bWZpapN5vnozru/e7k2s1b+h2Mx2/Ou2OVt+5Pm2/wAN\nezhY8vunl4iUuXmOn8Oy+dIULx7f41+83+9XS2a7oWaZMLv2xLs3bq5bw/G7TPOgYf3m/wCBfdrr\ntNkTzVmhdtq/fj2169OPKeTKUueRs6fG8kPnbI1Vfvsv8Vb2nw23zI+4+d8sUm3ay1n6O1tdTI6I\ns6L8u1V+Vt1bem27Nb/I6sv3K6OX3R+SM3xR4ah8RTado+xti3Sz3EK/N5yr/ermfjZa3+pa5cTW\ntnbtbWsS+V/Cyt/Cteha9efYdPTfcwxG3tWdJPK3SRrXlfijVNS1TTQ+q20breXCrLJHuX5V/ir8\n/wCIakvrtvskU5SqTueL+PPDs2ta5NrFt8iq6rLGr/dbb96uUk8MvY3hvIbbZJN8ssiv/wCPV3Pi\n7T5m8QCz+2LDaLLubcu3dWb8QFe3LahYI0aeUsUX9xpP/Za8aM+SOhr7OftThPF1jc6gtnpsKZih\ni3PJt27m/i+aud1zQ9K0e4t7k7mTfuuI5n+VmX+Kuo8W/adP017mGbeNqq6/+hba881zVJo7eTzn\nVl/h8z5mpU6nu3O2nh5I4/x1rzw6s9yl4sy+b+68tvlVa4C4vr/Utaeab97t+8q/ear/AIuuLbdI\n8j7du7fH95a4u+8WJax/ZrN23KiszR/fr0qNSmoeZ5uIpykXvFN26zf6S8caTRKyrI/zVzWoM9xf\nKls+/wCT7qrWRea5c3Vw/nXLbF+ZFaks/ET2NuJEdd2/738VdVP3Y2OOpGL1H3Elyt4k29RLv2s3\n3qvXnjG5tYntkm3IqL8zfLt/3azvtltdMlzDcqvzfdb7zf7TUuuaXbXFus3nK27+6v8A6FWcoRqR\nXMyKcZx94fp/jrVZG85LxkdfubX+Wum8O+OL+O8RLyHesit5skj/AHa4OO3ezj2JbKyr825acviK\n8t1/do3yt8jVw1sFTl70UehRxU6co80j3zQfH32WxZ7nUlX91t/cxb2X+7XVeDfHFzuW/SaFkZlb\nzLh/ut/d21836b4yd91s8ygt/Ft+Wux8L+JrBV2TPI7t9xd37uvIxGF5fekfXYPNoSjG8j7B8E/F\njTb66W1mv9ss0X3ZP4tv92vQpPG3nRxJf21vCsf/ACz/APZt1fK/wt8aWFzdwpqWpWMTx/LbzM25\nv+BV7h4V8M2PxIukS58Q7JV/1TW8vysv96vDxEXGfN0PsMPifrFLmhse2fA34veHtJ8VxWdzCzbX\n2vIyblVf71for8JfGvgl/Duk61N4gjkO7ykijl2r/utX5laH8GtV+F/iCTUtl1dsturRbX8xpP4q\n+3f2YfEHgr4geB7OztvLttSt12Nasu1l/wDsqqhio4XSPU5MdOliqXLI96+JNyuvIbPSnjnhXc25\npflWvF/GDX+n3NnoIsmiaSWNkWNW2V2d14J1Lw9dXGpP4kkeONtvk/eVt33q0NN0fTvE1xYXkr/8\ne8/7/wD6aR/3amtjv3/vnm1cvh9Wi4PY/OT/AILPfCy20CTwl8QrOzaB47+S1laN96tJIu7a1fEk\niw/Okz7/AJFX7+1Wav0j/wCC5OnyX3wgtNaW5aNLXxVavFDHF8m3ays1fm1HLbLD8kP3q+uySp7b\nB83mcNenPDyt/dJo7g7lh2Kkqp8n8W1f7tVLy4aRl/c7t3y7lfcv/AqW+j2sLm2tt77du7ftaobq\n4+zRtsPyN96vdjE8+UvdEwnkq6bgfvNI33qsabD5kj+c+5W+9/8AE1Tt5nusfdYN/F/drSsbeS4d\nH3qifd+58tdFGM4nLUkWNJtUupJZoUYnd8q/3a6Kxs4fMfZI23/aX5qpWdsm1N3zNsb5fKZW3f7N\nbmn6TNHs+TcP7zV6tOPuHBU/wk2m/NGN/wDe3JG3ytW1psjrMpRN3+03zNVTT4fMTf524ru+8n/j\n1WGZ7R4nR90Tfw7a35Dkqfymr5jspgjdXRvllWvsj/gn0Ix8GtU8uYPnxRNkgY5+zW1fFUN1bQyM\n8PyfP87N/er7Q/4J3sG+CepZdGYeJ5g7J0J+zW2a/GvHtcvh/UX/AE8p/mz4njtf8IEn/eifItrd\nPbyM/wAu7Zt3M/8ADUNwrrdPZzfPDuX70Xzfd/vVUm1BIXFtC+5F+6zVdWbzIUe5fcrMvzb/AJd1\nfsns/ePr4x94iaFIVOzcm5dyL/eqjKYbiFrm2farfc3f3qtyX/mSSoIMsvzfLVBb7dJ5OxfLh+ba\n33VWolKcY6m9Gj7SWhTuI0ZdiWy5VtySbv4q0dF0G5vrhHv0Vvm/5Z/eZqZpdi9xcJM8GyJX+Ta3\nzNXoPgfwv5mN8zMvzeUsn3t1aUY8x6kcH7OKsWfDfhNN2/ZH83zSybPmb+6tdfpPhua6Vt7qpZd6\nbU/9CrR8K+F/lS5dI02vvT/4muuj0HzLcvbIsbR/xbf4a74y5Y6ESp9jlLHQ4ZIfPhT5ZH/u7d3/\nAAKpL7w/bWNv9pv0VI4fle4Z9u2tXxb8QvB/hPS3eaH7RLGm541T5VrwDx/8ate8UXTW0KNcJI22\n3t4V2qq/7VEZS5rJHl47HUMNHlcjovF3xM8MabJNbWFrJfXCtu2xxfw/3t1ebeNPiVNq90lnqUM1\nxDIjNBY2K7lVv7rNTvtF5Hn+3r+Oy/vQw/Mzf7NZl7440Hw7H5ujwqk3zBJtnzVvTifNYrMa9T3Y\nmlb3eq30K3L+HrPT7Tf/AMe/3GkX+LdWJrV54bs13wx2+6T5kkb5vL21xfiz4yXk6ywpuDqrfvv4\nd1eY+IPihrOoXG97nd/D9/7tacyPNjF/akdt448cW15dSQ21zv2/LKzf+y/3a8117VE5feyqv3F2\n1k3viy5uJtkxyrfxfxf7zVkX2rXMczfPuZv4WpyXMax974ih4gTdI00L8N8zRqtchrmnhm3+dsKt\n92uqudSLK/nP/srXP6hNNI+ySZVP3VZqXxFxkcDr7XNuzfPtrNl2TKZkRgP4q6rXNLhuI2T5flZv\nvf3q5jyXtZHtXT5d/wB7ZRE05irHdTRzfI+7b/drY0/Vo3/czcq331rn7pXsrjY8Oz56sW90kc2/\nftp8qJ+I25r660e+i1G2nmDRsrbo32svzV+pX7K/ij4e/wDBVT9ju+/Zv+KOpQt438I2+7w5dM/7\n2Zdvy/e+avyqW+S6t/3k3Neh/si/tJeLf2WvjhpXxI8H6xNC0Nwq3Sx/8to93zR1UZypyujOVOMt\nEP8AjN8AfH/wL8d6j4G8VaPcJNYzsrSbPlb/AGlrlLWbbIftKMjL8tfsf+0l8H/hv+3N8DdM/aD+\nHtvb/abrRlnv/JX7sn8St/tLX5hfEv8AZ/1jwrq8kN/YbHWXajRr8v8AwKuLHYWMo88I6GmHx3sp\neyqbnmsjeZib7h2fwvTlkSRQ8/Hy/erTvPBupafNKk0LMN/3arrpL7tk0Mmxvu/JXh+zlHY9iNaM\no3jIv6LapuRzNn/dr1v4T+Ite8NtE6fOvm7tu/8AhryrQdFmm1KJERtjOv3a+wv2U/B3gmFbS58R\naDDNL5qt5jNu2tu/u/7teVm1aNGlbl3PSytV6lX91L3j0f4D+NPFuuapbaVbabMBNb7omb5fvfL8\ntfWXgXSb/wAL6HE9/efMu1bhht2/8CrkPBfhPTLjVxreneS9vt3RKq7flro9Qkm1SRrawhkxs2su\nz5a/P8dUjWfKtD7zDyq06X7yXMz0zSb/AFLxIyWejwxzHZt3N83/AAJa+T/+CjPxU1Lw/qNh8HP7\nNutPm1CJb+XzomjeSFW27l/3mr78/YI+BN1qPi/T9Z8bQ+VZlPmt5l+b/drI/wCDkf8AZVsNf+B3\nhf8Aaw8IaRCtx4JulsdWaGLbu0+b7rfL/CrV9LwtkFCtJ15P4dkfO51mtfDVow5dGfkBY3iRtsfa\ni/xt5XzMtdLof3duzc/91W3K3+81cnY3z3EazeS2zZ8jMm3dW5o98iskj3knzbV2qn3a+zoR5Ged\nWlznT2u+1VHdPn3M1aum6gjSIly6x/MzJ/CtYOmtcyXG/wC073V2+bZVyS8eOQfaZl2s6tukT5a9\nWn73unj1pcp2Om3ltIuz7Nvddv8AH96t7TdSufs7w+dGzfdT/ZrzfS9ee1mff5e1vl2s/wB6tmx1\ni8kZ/JuP+A7/ALq13RjynH7Tllqek6X4gmjjSa5ePZ91vMX/AMerpdN1h47dNjsiyJ8k3+1XlFjr\nSKWR9qMzNvVv4lrpvD+vXMjRTTJJtZfkjk/u/wB6tIxk9yo1PdPWtE8Qfak+d49u/b/vVr2OoTNH\nvm27fup5cv3q840fWG+/M6r5e7ymZ9y7Wrb0/wAQWy7Jo5l8uP5naP5lrb4TOXvH0z8B7iC58HTy\nW7Ej+0XBJbPPlx1xWk6tbQsnzzB9y/Kqbl/3q6H9lvUINT+H13cW5+UavIOuf+WUVeVaX4gvAPLe\n5Vlb7jLLtZq/EPDJ28SuKv8Ar7Q/KqfI5RL/AIV8c/70f/bj1vSdcRoVkQtv+67f7NbC60sluEe5\nUGT5dv8AFu/2a8w03xLeSdXVk+88cNbcfiKFmZ/MUsr7bdf4mb/a/u1+9Rke/UjzHXanfO0geFGf\nb8r7nrQ8JlTqTCNjsNuSoPf5l5rj18QW02zedwZm/wD2a6bwHdFtVltWKEiBmBRs8blr888Xpxfh\npmi/6dP80eLnkLZTVfkS+Ido1eZmZc/KFU/7o+asPWmjjhV0dflX5WVv4ateL9WFr4hurRwoVjGN\nx7fKKwdU1xZI5bZHjQN8iTL/ABV6vh9O3AWU/wDYNQ/9NQN8rp/8J1GX9yP5Ip6teQNEf9YWVNqe\nWv3f96se8vLmNtm/yv3W3zP71Pm1L7QuZty/L88ituZv9msfUNQ8yzCPtV1bbuWvp5SPUjH7RS1q\n9ebY8KNsX7/lttrm9Q1BCHh+Vtv3vk+9V3XLya1V9m5dzr8qp/DXGa1qX7yWzTciN9xo32tXPKR0\ncrOhtdS+ZYep/gZX+Wun8OXXnR7HvFwyfd3/ADNXmNvqkMePJeNjIv8AC9dF4f1h7NVSG6XDJ93b\n8ytXPzcwSPUtJ1DbGY7Z2fy5du2pLi4cwxJDc+ajN8/yfdb/AGq5C18STLGV3rH/ABeYtOuPGkG5\nczMm75flSqlLoT7hsXWtbrjeiYZXbYzfw/7NZV14ghW4LzPw33F/2v71YVxrTQ74Um2PM+5NzfeX\n+9WDfa9t/c/b/wB2q/eZ9zNWVSoOMfeOyn8RW334X8vbt/jq/Z6y900qecu9vlTb/DXkt54s2yfu\nXXe3y7VX5f8Aeq74V8bTSfI6b7hfl3NWMpcw+X3z3bSb6FbT99NG6L8u2Rvmarjat9oXZ5bJuTci\n/wANcDY+KE8lLmbnd935vvf7NSal4omh8t2dVTZu276zlIvl98/KfQ1dbXY8LFNm35nrcs5EFqlt\n+72N/DvqhZ6eYmf98xH3tu37tXLOOZm3wiRTuberf+hV4MsR7/un3dOjCJNumVleb+L5V/3agupL\nbaqQ+Xn7zLV23t3kj/ffM/3ty1DcWKeS7xvGzNuV221PtuaXMa+x5TJktYVjV43Usv8A7NUNvZnc\n8jt97+H722tBrOZFHKq33mVVprW821nhTJ+X5m/i/vU+bmj7xMYy/lM7dbBlR9zn7qfN91qkj8mO\naNH+Zl+Xdv8AvUupWrWH7vZjb/DWTcXe2F9m5tzbWrrpxhPlscdSUoytKJu2epTN/oybkHzMv92t\nD7YGXy3TcI/7v8NczY6h5kY/ffLHV+x1abzPNh+Tcm35v4q6I/abMZWly2NNpEkj87ft2t87bf8A\n2Woo5kjhO+Zl+b5aof2g8M2/zlDNF+9ZqrXmpC6XenzBU+XdTjExlU94NT1SE7vn2N/erm9c1LzG\n32z8fd3Va1K6eNt6Ov7xPnXdWBq2/wAx3hdQW+58/wB2t4xucdSp75nahqSSfI6bf723+KuevNQe\nRmdP+Bsv8VaOp75N3kpy23e1ZX2N/LKRpn59v3/4q0+E5I+9rIreZ9o3pD8lW7OOZVT+5/HS2On+\nXIyv8zt/dT71WodMmjm3j5l+9Uv4viO6nH3iW1hhlk2bGba3yt/DWvZwzj/lsqrsqjDbvbtsdM7n\n3LtT+GtBY3UbETf8/wDD/DXNU5Inq4embOktD99N237vzJX6zf8ABaqVof2WdAZXxnx/ag+4+w33\nFfkxpsnmqHRNwZ9qr/dr9Zv+C1sbSfssaAq4/wCSgWvBPX/Qb6vwzxF/5Lzhz/r5W/KkfM8RRn/r\nPky/v1P/AGw/NjSWmVYobZM7v738K7q3beNI5l852fb8ybkrB0tnj2DZsOz5VatNbpGaFJk3pu/i\nbb5dfplT+Y/Ueb7MiW+Wb7KybFUTP95vvNUE0LwoUQcbdy7v71Pa8ibcn7yRF+X5f4WqD5/OEafc\n2/eVvmrOXvR+IUfdHtdXMiwujqvlpt/76/2qsQxpDt87/WNt+8lQRwlrjeOn91v71XoY3mma5mRd\n/wB1F/iVf4ttZc3KbxjzSI4YYWVkhhZf3vzqv3qfHvm+R/MU1ZjX+BEXdCu35n2s1PhsXjjCPCy7\nvv8A97dTjLmkbRjyy5iKztRIy7IVUKrNuZvmatGzjnkkWFEVlkX7u/8AipY7F1kHzL8vzI2z5quW\nlr++BO0qvzbm/ib+7Ve4d1H3izC32eGJPOZNz/Pt/irT0+4SCNNj7tr7X3fMzVRaMw7XuUz+9bf9\nnTd8tWLeR4VR0Tbu+7/e21MYmkvg5WaMN5bN89y/DJ8zLTZvsyQ7FufnZvlZvu1BaxvIyuifIrfJ\n/dWrtra2118+xWLP/Fu+WtYxhze8ctSn9krx27yRi2h+f5tvzfKq0sNnGtxDNNcsjybvm2/K3y1c\nktf3LW3lxudm/d/d/wBmrVvZw3EzJDbbfLi+T+JdtEpWjynNUp9yj5bzW6+TCqS79zrJ97bUq2s3\nlo+/5vuoqr/49WgtokzMnnZ27dn+yv8AdpbuHzJt9mjB/uv/ABUe7HRHJUiYzaSjQo7vvZW3P/s1\nnalp/lzNvh3lf9uuomtXkZHG5B5v+rVPlqjqVunlv9l+SX7zN/D/ALtX7sdInFL+8clcaP50e9H8\nvzPl2/xVXutP8mUJCmVVPvf3q3ruFI4RqF18xj+bav8ADUDW6XEvz9Y/9VGz7Wb5afN7+pzVIy5T\nm7rTXZkeNI1+b5l3fN/vVWk0tfsaQu7F2l+75W5v++q6SO3S8jE0sO1VX/Ur8v8AwGmzQyM3lpbb\nmj+X5W/hro5vdikcvLzSvE5uO3mh+eFOW+VtqfK3+9Vu3tZliXeW+58n96tj7C8ex0T9633P7u3/\nAGqdp9rNbRo9rtYMzKzfwqtRLllqKjzR90g0uxSGGTe7RLGm2t7S4UVUhT955ifPtam6fDuTY6fM\n3+18yt/erU09fLtzDMn+15i/xVzSlyy5j0qNP3ibTWcr5yJt3P8Aeb7rLXR6JapJIqb41aRfl3bf\nl21QtlSO3hheHcipugXZWlp63jfvYYY0+6u6NNrLWMZc0+ZHpxjyw941bcTTt/rpAVfa8mz7tdHp\nMKWsgRBnb83mfxbv9payNPk3Rwp90s+5v9r/AGq3dPuIVmV3dTu+Vdvy7q9KgcNanaB0mmwzLE1y\nkO7cv/j1a2ntCLdoXmVyzruj/vVl6VcRrCYfJkRZG2o33l3LWpp7eXMizfO27d9z5Vr2sPE8urLl\nj8J0OhLbXVx++/dxMm5F2/3a3tKt7WFV8lGKL975/m21iaHbpG2xEba27ymauj0mOaNQnyvuT5Nr\nfNXqR908ytHlkdHoV/IyuiTbImVmTanzL/dro4ZXhXzZtqozqyMq7mZv4t1eb+NPil8KPgzpc2t/\nFf4iaL4agjXfFNrGqRwM3+7H95q8r0v/AIK7fsdeJPiJY/CL4P6x4p+IPiHVLhYLDTfCehs8dxI3\n91pNtKVTlhzGLrUIx1kfRPii4m8UXlylhqU00VndfZvLa12JHtX5l3fxV5x8Wteh0fTYLbzljl2f\nLDG/3v8AaZf4a9G+Huk+IbH4Z3t5rej3Vrqupa9cPeaPeN89jI21VhZv71fK/wC0/rniHwv4svtV\n+wMiLB5Uqs3zLJ/s1+eZlW+t158gqPuy9Sj4o+JWiWt8by6vJizfLFHs+bdXFav8cEvtLm0reuyO\nVfNb5fm/4FXiXiv4la94m1YfbIfKCysir96tbwRpr3mqW+m/ZmeS42xQQxxbmmk/hVV/vV5dGjy/\nxZWse3g6Uq3wnreh3CatpdzNrEyrbTIvlSSOzbV/3a8q8fX3h6z+022g6ws8cbbflZv3cn8StX6J\naF4i/wCCVv7EPgXS/Cf7Xt7F4t+IN5YR3U+iW0TNb6ezLuWFxE21W/vbq+fvi9+0/wDs4fFt59J8\nD/AvwX/YF1LttbfSLDyp41/vNJ95qwxVbC4WEaifM30R9JlOR47GOSrQ5IdJS6+h8GfEPUJpFP2a\nZfl+Z2ZP4a8017UPs9xvhOVb77K9fUnxm/ZrttQ8L6j4/wDgsl5qNlZo11q9iy7pbOP/AGf4mWvk\nzXLhWuGdE+WT5WVk27a9jK61LFx50fLZ9l9XLq/KObUIZojJv3Ky/dphtE8tXR8bW+Vagt5PtSeZ\nCittX72771Ot7y/kZrN0VIt25ZK9OpH3fdPnfi1kTWcbwli+75vu1bt9euFbyZtqx/dqhMrlj++3\nq3y7akhmtZt8Lwt+7/5aR/xVzSj9kuMpR90t3yzXVuj23yf39tVr3S4bqd4YbmSNfK3bY/71dD4b\nsxdRIj2e9Oqf7tWNQ8JQsqeT+7+826svaRhLlNPY1ZfCcTY2c0WDNM2/fWw+q+VIiI7fe2/8BqLV\nNHEK+ZBNu3fw/dqz4dt7OORLmaFZTsberVFSMakec6aNOdP3Tb8I3MSr9oeWb5X2q26vsr9j9fE8\nc0V34e8H6lOsiqjtJBtVW+78rNXzX8Or/UlkhTSvAzXQh+by/s+5W/3mavuD9lf4pfEjSNQtv7Y0\nrZZ+VtlVtq+XJ/Cu2vkczqOUXyxPtMllO3LzH0Fb/Gb4/eCdQg/4SH4M2M+n3ESwLqDTwtOsK/eZ\no6+gPgv4o+HXjqyk1h/D39m6qqw7fL/d/Nu+9Wj8Bvhj8P8A9o7wM+m+JdO0/VrpYP8AVvcbZYfl\n/h2/d215r8UPhzbfst+LILzTb/xR4esZLqOJZNYT+0LGTd935vvRqtcdPCyqU+eGx1VMVFV5UZ7n\n03DrNjpdlPba9FH5jfN5i7mqHRtc0VZClnNCibdzMzferJ8H6l4p8deD49Y0Xxd4P8Q2yuqtLZ3D\nI6/L824N95qni0ixWR/tXhq12SbfmjT+GitRjGcYSR6ODcKlKUep84f8FUvBMnxx+AGtWfhzWVhG\nh2a3qyRRbkuJI23ba/KKxt5riFNjssjRb/LkT+9/dr9zP2v/AIazeM/2cPFnh3wvpMkMh8NXDRpa\n7V8yTb8q1+K2l6Ltt4baZP30O6L5l2su37y19Vw/pTnHoeJmtSlKUORGBJp7tG29GTd83lslV4dP\n/wBIR4RIr7G+Wus1LS/Ph/cxtsX5pW37WrMXT3jkG+bDQv8A6zbu/wDHq96Hu+8zzJRiZlroqSKk\nPR+qyf3l/u1q2OkvuNsEVt21flTdtq1Zw3Mm8Q7lH3d396trS7FGmKQ2GGX7m773+9XqU+fk1POl\nLmmH9hpHMkcPmMY9rfMv/fS1rw+b5i20KbkZNzL/AHafY2Nz80MMLO8ybV8xv/Hqlt7FGZJvIbcq\n7NzfdWvQoxic9SX8pDar5UboiMjb2Xy2qwq3MykPNs/6Zqm7dTntfLLum3Z/v/NTWjmhRnfzGdd3\n3v4d1dcYxOWpz8pVlG2Mh3Vvn/4Dt/vV9qf8E3FjT4GaokONq+KpguD/ANOtrXxBfKjeVsj+RlX5\nV/vV9uf8E1X3/ArVSQcjxZOGz6i1tRX4x4/K3h7P/r5T/NnxHHbtkEl/eifFkd9NdMrgK/735137\nVq+88cln533VZvk3JWHDPMswRLZSmzfK38S1aluLaOxj86bZt3bF3V+1cvucp9hyxG31891IiI8f\nlsm75qgk1N7qZYZnaRtu1I1+7urKm1CZZDN93/nrGrbqu6XNMz/Pbbn/ALsf3v8AernlCZ6uFpnd\neE18uPegWbbt+XZuZa9V8F6VD5nnTbnDI2xWX5lavKvDbbmtkdPlVt/zf7Nek2fiZNFtftly8m5l\n3KsctFNxpnoyqJQtI9QtbrStJsY7aZI4pNu9I5Pl3Vz3iL4wQrdHSv7Qjtrf5mRt33v92vGvil+0\nBYeG9BuNV1XxDb2wjt2WL7U+5m/4DXzD4o/bGtrm/u/sFy13Js8pbqb5V/2tq10wjze+z5LNM5lz\ncmH+8+kfjF8Xf7akuvBnw9Rry7ji3Sts/wDQmrxXVvGXirT45s2DKVTdLIz7vm3V5JdftQa9ptnd\nWHhV2tpr7b9qulT941YmqfHS/t7MTaleZ3ff2/xV1RjyxPmJc9R80z1DUPHniRWdHhm2yfvXaT/P\n3awte+Inn2433LCVlZ9q/wB6vJdb/aCutYuD5L+Ui/L8v8VN034lW2rXG/UkXZ/GrfxUuachxpyO\njvvHiXEj2002/a27y/7u6sW81SGaR982z5/4XqlqkmlXkazWd5GnzbvLauZvLx4X8lNzMv8AF/eq\nxx92Ru3mtJ5hlf7395aoXGsPIr/O2/Zt3M38NZP2iZYmeYKaPMdWD53/AC7vLWq5R8yLFxqCKu9N\nv+7v+9UbMnyuhx/dWjy4fM2bNzfeRqSRk+1sjJn5fvL/ABU48oubm91mZeW7yKqfeLbq53XLWZZf\nlTad3yMtdcy+WS7vtb+HbWfqWmvMyIfvSf7f3aIvmEcxq2m22qR+dC6sY03Oq/3qw7i3uY2VJoWV\nq3NU0G802ZryzT7rbmX+9V3R7fSvE8fkv8lz/d/2qYHLxyTRsE2t/vVFNNPHMro+0r/tV2V58PfJ\nVpt7Jt/irEvfDbq+9Pm/2qOWYc3NI+8P+CMv7a1z4D8RyfATxtrMh0rXJfLspLiXdHHI38O1v71f\nSf7T3wV0HxNqlwn9mxhml+8q7f8AvmvyO8Hyar4V12117Td2+1uFlTa/zblr9I/2ff2mP+FweBbF\n9b3PeWsCpdL5u6Td/tbqXtOSHLI5cZTjPll9o8i8T/AW58K3VxbR2zPbyfxSfM3/ANjWj4A/ZXs/\niFJFZw2FxHLI2x90X/LT/Zr69+Ffh/wf4y1i3sNetrcRSS7mVvm+Wv0y/Y+/Y7/YgutBs9Yns4r7\nVGTf+/Xy1Vv9mub6nHn5ub3TCniK/NyxPyJ8K/8ABF34weJ7FPEPhvRJLtZIm8qOP5fu16Zp/wCw\nXrfwX8JwzeM9HuLGaFFZpGi+XzP7u77rV++Pgz4ZfDvwlpwsvCmhW0Nv28vndUPxH+C/w1+LHg+7\n8B+OfCVpe6bexbZYTEAV/wBpW/hassZluExlLkkevgcRjsPV5+ZH4z/CP4cp/Z8U1trEexnbZbtL\nu2tXvPwr+Dvh7T7g6lrEPm/JuVf71dJ8Vv8Agmhrf7M3i9vEvwiS61nw1dS7/LuHaSWz+b7rf3v9\n6reiQutiIbz908aN959vlrX5FnWU4nLMZyPWMtpH7Jwt9WzWj7Ry96PQp698ZLn4c+KrCz0F1Q7V\nd1WX5vL+78tfSnxETQf20P2H/HnwvQqZtV8JXVv5MvzNDN5LNHu/4Eq18BaTrb/F7x5f6l4euftN\npDdfZ4vL+6vlttb/AMer9B/2SPAlz8L/AIP6vrfiSGO1tk06SRm3f8s1jZmZt1fX8MUatFKx5HGf\n1WVNp/EfzS6LNNa2P2a8dvtNvLJFKq/89I2aNl/76WtzTbh1nSSZ9pkT+L7q1haTrlhq2ra3qWm3\n6zQ3HiO+uLP5PvRyXEjVrQ280+93vG8pfmRf4a+mlHlqyPk6UuahFm/Y6xujdJHaM/8ALJtvytWl\nDdFoSkxZjs3VyscjxrmZPkj+5Iv8K1ow6lMJo96bkkXb97+H+Guuj/KefWibsN1bNIX8ltzRf8tF\n/iWrVjqj2N0juNm59rsy1grqG1d81ysK/dWPZUNvrSNG87uz/wAKNXdH3YnLLkO6t9a8m7Lvcr9/\nau35q2NH8RfY5BC91JIsjMqMqfd/3q83tdeeOTLyRq0abv725v7q1b/4SZ7NYn+0yBVT/j3/ALrN\n/FV/Z5omcf7x7Bp/i6GHy4UuVRW+bayfLWnZ+IEsoZYU+ZG3Nt/ur/drxrT/ABlFJJ9peZU3J8+5\n62bPxteSRu6OsbzN+9X/AJ6Uf4i+c+/f2Jry3vvhTfXFs0RQ69JgRdv9Hg4PvXz3pvjC2Zok37g3\nzPtr2j/gnPqo1f4H6lcgAbfFEykKMAH7NbH+tfHtn4z2bfs80m5fmdV/9lr8P8NJ8viRxU/+ntD8\nqp8tk3/I4x3+KP8A7ce/WHii2hkSZL9gflVVb+61dFY68kkcmx1V/wCH+GvCdH8aJINkdzGV+797\n5lauo0nxRusxvdmZn+6z/dr9w9p9k+l5ZnsNr4khZktrmbndu/vV3PwM1Zr/AMTXMSSZQWUhx7iR\nP8a8E0nXvJkS8+0r9/5/n3bq9b/Zm1ibUvHlysrlgdIlYEKAv+uiz0+tfnni1Uv4cZmv+nT/ADR4\n+ewf9j1m+xq/FXWPsfjXUILdmSULH84Gf+WSVzl1rUPkrCm75V+Zt33aZ8bdbNr8VNWtC64Agxn+\nE+RGa42TXoY8fOzN95fl3fNXq8BVb8CZUv8AqGof+moHZk8LZVQf9yP/AKSjbvNWe3keZIcpI/zL\nWXea0nmMj7pE+6+3+Gs6bV38wol4oZmZpWb/AJZ1l3mo3kafaRtLN822RvvLX1Eqh6Xsx+vXhkUv\nI+/Y3zqtcpq1xYMpuUj3Nu+8tW9c1bbGXWZU+fa21flZv7q1zepam/2AO7syxy7Pm+Xarf8AoVZy\nqF+zYlxePHM9zC6ny33bf4d3+zW1puuJaNv2bGZl2x793/fVcPJfXJuoraGTCyKzJ5nyoyrVu31/\nY6ec8aO3y+ZWcZR+0Llmenw+IEuLUp9sX7u5/k3K1Q6prUfyP9pjQrt83/Zri7fWoJIUSGbayp8r\nLVK/8SOsavK+5m+X5vmaqjIz5DptS8WQxXm9Lna8bqu7Z83l/wB1WrI1rXElZJrZ9qfddZGrlNQ8\nUP5jf6zP92P+JqwbzxF5jM80zKGX7qvWUveKjym9eeJE8yZ0blfl3K9SaL40mjkS5SZVVty7f722\nuA1DWE+aGG5wjNudfu7qh0vWkkuhNI7J/c3Vxyqcp1Rpw5Lo+gPC/wAQ7Z/9Tf7W+98z/LV+bxNM\ny7PtPm/wosj1454T1rEaI7qT825t9dbZ6gjWvyTecv8AH5fy7v8AdrLmkuXlH9X5Y8zPlKPT/L/f\nJCyvI/yNIm2nnTXkbzk/1jfL8z/erduNNkkkk+RX/wCBfdpy2e5tmzcf4vk+7XzPtuU++9jzGdDp\nPkwyIj/dT7v3W3f71V5LVJ1Z3h2ed96uhjsZrj5JHb5vm/2mrP1LT42cHftP3X21VOp7vvG31fmS\nsczMvlsRD5iLI3zt/eao/Lm2yzu8m3+DzH+7WrqlqrIP97cys38VY+rXEPmcuwf5dir8y/N/FXXT\nrc0AlheWPulHVm863JDrtX5tq/erAurzbcM+9huTclaesSPb2pM27K/eZW+9WHeTI2PJdSuz569H\nC22PMxVGch0c3lRqjfMd+779W7PUpo1EP3Vj+ZFZN1c9JM/mecnyN/3zuqaO48ll2oy/xMzPurvl\nE8qUeQ3JLzzs/vsbqqS6ggX9y+7+H71U5LhJpY/32za3+6y0y42LGscyL9/du3feaolLlMKlOfL7\nwTN9okaGZ8NJ8v8Au1l3zbvufw/d3VZurp42/fIz7v8AYqtJH9o+eGFXVvm+9VSl1OWVP3jOmtXb\nan7zDfw/7VJa6Tcsxi8lVb+NWrds9LSR085Ny7vl3Vct9DEjK++NW/hVWrOVTl+0KnGMp6mPZaX5\ncKo6bGZ/kq8vh2Yt+5f7yV0Wm6CnlpDcpt/2f4ttbEXh142Gzbsb5fu1zSxHKevh6PwyOHXQblYV\nE0G75tyyfxLUlrpe7aiBsbtz7fvNXZ3Wg/Y1MN0m/wCX5Gjquuiwv86P8rJuXdWHtObc9WnGPOc5\nY2csSnnH8KMvzV+sn/BaJGf9mDw7tJGPiFaZAbGf9BvuK/L5dFtlt1hR2PzKyR7dtfqN/wAFmRE3\n7MGgCZMr/wAJ9a59v9Cvua/FvEKpzcdcOS/6eVvypHx/E/8AyVeT/wCOp+UD8y4GjkVJvMk8pfuN\n/FU66g7SbHfG7a3zJUHlw28zjzm8pn+Td95V20fvljZHff8ALt/4FX6hy/zH6NKpFbFprib7Q6On\nDJ8+1/vNT445mCon3l+Z2ZvlrP8AMeGQb5v4Puqn3qspHDdR+dM6ouxd+5/vVlKP2gjU5vdL0MQW\n4D/bI4V/g/3q0NiNCmyZVdn2y7fvVQtYRLb+d5y7d3y7f4aurs+bZPvVf4qmVQ6qZbhhtlt/v+Y2\n/d+8qzaxtIvEbJIrfeZ9yqtVY5kuJNkw3Mvyo396rkapGnlpMrSf9NP9mlGRvHmlL3S5Y3SXEe+O\nNR5bbv3n3mq6WSWTyX2szJv2qn3azYN90v2ncrKvystXG+WPzlhYR7d23+Jq0jH3uY66cuX3i3C0\n6wy+Y6w7l3N/dap47j5RN8zH7jr/AHaq2pe6h/diP94v/AdtWodP3xj5NrNuVWX+Ktacfd943l73\nvIsW+9bcTTPJu3N93+7V60j/ANB8x7ndt++33d1R6bau1uj/AC7vutD/AHWq3Z+bCp86ZdjPuePb\nW9OjGXunNKpyyEjjMli1y/y7k3bVfc27dWjpq/uVe2m8v5/n8v7v+1UUa2d0G37gF+X5m+9TvtCW\nrCFHXCy/3PvUq1GXSJhKvTlG8pFyOGH7OU+Z/k/h+8tRtMn2iO5RG3t83yt8u7/apY7iFv3Kcuv8\nLfLVe6neCRoXk+ST7jb/ALtc/sJxkpHLKrCUdJErNDu+d95ZfmVvlWqd1bvJG8zrtj27q044XaHf\ns37f4vvVVm2NZuH27VXa6yP/AA1XJOJ5tarCMveMe6VJFUNtV9nzrH91lrOmt/OjR0to98br8395\na2prPbtffG25tu2NKZJYw3Ehkhmj37lRo1+8tFpxOfnhIx4YfO8tII5E3fwyPt+b/wCJqWGz2s/3\nQ2z7395q0Li1Edz9mjT5WTcs0iVcsbd/v3Pkonm/PHt+9/u10OU5fZMfcjPlOe/s+5hhS6trhWdm\n+dd/3W/2qktdJ89fs03ybl2/u/u/8Baujh0lHjdLYc72b5v7tWo9HtpIm+zbiip93+7WUpz5TWnS\nXN7xlabZpHDsELF2+V2ZfmWteG1cqMwtu2bYpPl+X/gNWbW18mNET5nb5V3L96rEeh+X8zorvG7K\n+35ttc3JOoejTdGn1IobV/s4huZmKrL93fWmttdXW1N7RhflRmX5lan2djuhVJkjVtm5Fb7zVYkj\nezt0R7mM7m37VanTw9aVXl5TeWLw1OHvVIk0dukMaJvVH8r/AFi/e/3a1dL+aMQv5iN97d/FWcti\n90qiZ1QN9yRv71a9tNZ2Vu9zc6rC32e33s3m/e/2a9zD4WvH7J5WIzjLI6Odzf0WJ47pYXuWfcq/\nu/4m/wBquk0eWHTVFhczcqnyRyNuauGh1DWFVNVvNaj0jT5F3JNMv72T/dX+Gta48TWej2ct5ptm\n0crRbXvGTfLNXsQw9TqfK4ziGnrGjE62++JnhjwXp8mvaq83lR/LKsibVX/gTfdr4I/bI/4Lc/Ef\nTJ9T+Fv7L01lptus/lz+JEhWWbb/ABLCzL8v+9Xn3/BSv9tvXrm/f4G/D7UmjVV3a5qEbfNI3/PF\nf92vhxju5xXTGjfU8aWMxNT3pSN7x18R/HnxS8RyeJ/iL4w1LXNRmbMt5qV00rn/AL6r9mP+DUX9\nlHSv+Eo8V/tmeM9Ijf8A4R+L+yfCrSQf8vUy/vZlb/ZXatfjh8Kvhn4w+KXjC08F+CNAutS1K8lV\nLa2tY/m3N91q/rM/Yd/ZV039jv8AYv8AA/7P2iWcdtfafokd5rd1/wA/GoTR+ZNu/wB1vl/4DXz3\nE+O+p4Pkh8Uj0MmwrxeL97ZGh8TNF8MWOtX9zqsO2a+l89o1b5mb+83+1Xxf+1p8DbzXmvtV052a\n3hvdy+dt3TRyfxNur6Q+NnjzWNLmmm8T6PDA7f6+OPc0cy/d+9Xz/wCMvj14P0G+W58ValC0MkW+\n4jm+Zljj+7tr80o4idOPMfSfV4VKvKfLc37KOj6TeDXprCTezNLdLI7bF3fdb/7Guy+CHg/wv8F/\nCfif9pPxVZrNN4LtZG0GO4t12NfSKywfK39371Yvxc/aos9Y8QXNhpTxvaRxbopI33Mq7vlrx79p\nf42axqn7Iuj+E31GZptc8XzXF0rfwrDHtVW2/wC992ic8TiXHn+0fb8P5dh6deMnrynz5f8AiLxt\n+0T8TtQ8R63fyXl3fXUk+pXTLub/AHd1ZOrS+IvhzM02lXU0YjbaskbsrK392vX/AIA+E/8AhBfh\nqHa2hl1XXHZ/MjPzLGv8NY/x88e+DPD+lDRIdEs59QmbdKq/M0K/3mrt9pT9tGjCPNE9bNcfVhB1\nGy5+z/8Ath6xDqcel6rO1tPDEyvIq/LdRt96Nq4T9orwz4e/4SaPXvD9tGsF6/yLDLuWPd8zV5sn\niKWfX1vba0jgRW/5Z1q+JvEFzqGmxw+dmFfm2/3a6o4OphcXGdH3YveJ+e5lmP12m1U1J28Jpo8O\nx4VZpE3fN/CtUbnT0+0NZp/c3Iv8VGm61/amll/t7I9qnyLI+7zP9mtLRbxLi1W8dN5+6277ytXq\nxqVftnzUqEeaPKZlv4dv5mE1snybf4qvReH7y3uGd4co23ft+7XXaLqVgtn/AKMitLs3N8lbOnww\n3EcU14io7Ju8uP8AhrjniP3kjuw+D5pxMrwnpU1nGPOh+ST7nyfw1r3Wn20Ni0OyNRM+5dy/Mv8A\neq6rJHcLDbPz919tS3Sw3Wm/O+3bL8/lv/FXk1ZT5+ZSPf8AYwow5kcPeeH/ALRdtDDCzQ79u6tT\nRvB+m6RajUnRWK/djb5mqz5yWszwzJGPM/1XzfeqrqEl5Gqo/wAoZtqbf4q6pYqVOHKup5VSMee5\np2/iDxVNM7w69JYWayq3kwrtWRv4a6bw38bvFvhO1mtk8S3Vw8jbt0kv3WX+7XOaDbiSzEOpQ/uF\nTe3y/drUHxm/Z2+HFilt47jjldb1WihWLzJJI/4q8+FP29XkjDm9C6dWph/f5+U6rQ/23fi74Bkh\n8Q+Evi1caVqG/dtsbpkZmVvlaT+Gvvr9ln/gtrqnjzwXP8Hv2oPD+l+Mbe6s/n1A7Ypz/wAB+7X5\nIfFz4q/sz/EfZP8ADd7q0ljlb921vs+Vv/ia4mO48W6Nfx6r4b8QSBoX3RFf4v7tet/ZbhCy9yX9\n4y/tOtKd6nvo/o5+CH7SX7H1rd3Fh4Xs73SLy8dWsbdk/cbdv3dy/LXX6X8WFtfGVppuzzbPUN3l\nXC/dX5vu1+D37In7S3x1uvE9tpWo69G0Sy738xd3lx/xbVr9Wf2RPiVZ/Eq1h1LxDqqqNNi/0Vt7\nbpJG/wBmvBxmAlRxC5pe8foGS4uhXw8n37nvf/BSr9qbwf8Asr/s1TXmpajGdS8U/wDEu0aORvkk\nkb+Jv92vyDvpL2TUjdybUeSXc3k7lWvdv+Ct/wAbvD37Tn7UXh/4O6FdzXPhT4X6csl/eQ/6qbVJ\nPmaNW/i2/drwFrp2kab7rfMybW3bq+ryvC+zpX7ny1epH29uxY3Q3DB0dnZv4lb5qoyQr5zJG+0r\nLuaNqWGZ41R5nbc3zeX/AHalkaG6h+4of7rfxbf91q9KMYSny3OaUuvKW7eztpI1eZGjRvuLH81b\nul2szXmxEbYqfM0n3lX+9WPptv5cbfvl+Vfl+b73+9XVaWsN5IYSjB1i+Zmrtp/3TmmTRx3MYHkx\nyMn3Xk3/ADL/AHatfYXhhZHh+eN/m8yptNsbmNk3vGiqjfKv/LSr0Nmn2VkRGlMb/d3+ZXp0/gOZ\nx5jGkWG3j8l5N/z/ACtJVXUN/nSv92T+7v8A4a0pF3SNC9zuZYmV1Xb96s3V23Fnm2tHtVd2/wC7\nXZGJhL3vdkZV0r+Yru8YRU+dV/havtT/AIJsY/4UXqu2ZXH/AAlc/K9B/otrxXxpfTIyuk275k3L\nuT7tfZf/AATZiaP4GaqWdCX8WTsShz/y7WvX3r8a8fYx/wCIc1Gv+flP82fC8eO2Qyj/AHonwy0j\nw7CiMf4W3PVKa8mkUn5iq/wt93/gNWNUvIbVt+/zEVN3lx/KzVzGqX0Ma+WiMVjl+Vt/zLX7t7Pm\n94+v9ty7FmS8mkuH8mbYrP8AIzVf0m4SFvLubnczfNKytXHQ3j7xDJNllT/vqtKx1hFuESGb52ba\nlc9SnzanTGt7nxHqXh/XILezSNHYq3yo1cX8VPj5beEdPfTU23Ey/N+8fbt/2q5j4kfE6z8I2bIl\ny0s3/LusP3a+Z/iV8RL++unm1K5Zpm/vPURo83Q8rMs25o+xpf8Abxb+K3xY1XxJfSfadSaRpm+8\nz/w1xVvfPb273LzL/e21gzal/aF47zzMTv3Kq07UL5I7byfO2f7O6umNOETwbGjJ4gfzHeR22/x7\nXrD1fXNS1K4GybdFH8vy1B9ohlh+cfe+7UMbJEr/AD8bqr+6VzFv7X9nh3um1f8A0Kmt4kez3JC+\nxdn+9/wGs3VNWh2/fUbfl/3axbi+eZd/zMWo5oj5TtdP8XTSSeS7sw2/xferetbxNSh853UfJ8nz\n/M1eXWtw+9X+8P8Ae+9XUeE9Y3SBJn4+6u7+H/ZqIy7GX+I61IRN/pKhm3Pt2tTlt9qt97d/v1Nb\nLIzI/wDA38P92rM1r5MghRG/vK1aE/D7xVWIxx79jL5n8VOuo9zb3Rm+X71XxZvtXd/u/epjWe6R\nt0LbV/hqoxjKIvtFC2t3kXfsUFv4mqxJpThd7oo2vuq/pdiGbf8AeXduZdldTDocM1qv+gK38Xy1\nnEqUjz2bS0kj8uZ1Vv465fWPDf2eQahpX7mZf7r16T4g0VLNnjTarr/DXnmoas7a9/Y9y+xV+b/e\nqveDm5ty94b1TVb6x+walbLu37Xmb+Kl1LR/J+f+Bf4v71aVvHZrGqI7f3dq/wDoVTXkaTZ/iqog\nYVrCm75E/u/wV2Xw4+JF/wDDPxDbaxbTyfY5pVivbdX27V/vVy62aMxTfzUjW7yWps5nU/J/F/6F\nUR96ZnUp80D9I/gr480270u28Q6VqSujKrRM33q+1f2a/wBoKa3a0tvt/km1RflZ9u5q/H/9iP4z\nJHeP8OtV1L99H8kHnP8Au9tfbvw/1rVfDN9Fcx3LFG2navy1tUp+57h4spSjV5Wfq34G/bD8U/Dq\n4hlngk1DR7p1aXc+5oWb73/Aa+kvhj+0v8OPiRaj7FrMMM//ADyaSvzJ+EPj5/Fmn/Y7m5/0dk2y\nx/xf7tYfiDxn4z+BPxIFz4evJjZTXHmou/b96uSUuXU7KOIlS0P01/bP+LOufCX4GzfEPwnq8Md1\nZ6lahYZArLdK0m1o2X/ar86/i9+0dN8dPEmveGPgtptjm8umtb+8t5f3VnuXbIzN/wB9bVWtH4+f\nHfx/+01D4S/Zv+GPirVl8YXV02pX7abcRyLb2vl+WqtH/wA9Nu7bXy3+3B+2b4U/4IzeHrP4LaF8\nONP134galE1zZ6Pqm5vs+5v+Pq52/N8zfdWvLx+W/wBouPP8MT6/Ic8llkpzjvKJ+g/7DP7OPwr+\nGHgCXxJ8QtbhsNG0dd15rF9KsUTSfxbmauK/4KXf8FavD3hv9l74meH/AIFvDbaTbfD6+t4NcmXb\nPNdSL5MXkR/3W3N9771flV+wV+2B+1t/wUY/aYRP2k/i1dXulxhWsPC9nF9n0qz3SbflgX/WN/tN\nur3T/g5b/Z61L9mDwz8FLbStXnk0HxVe3n/CQRom2Oa8jjjaBW/2VVm+Wu/C4P2PuxODMswxGNq8\n0j80fh34gm8N6TaaVNMwVUXf/vfxV7D4N8VQ6xCbN9of+8v8VeHXXzPvttzM3zbq2PDPiq5s5Ehd\n2Tan3lf7taVsPzx/vEYfFyocsZfCe6/aNuxE3Mjfeb7vy1FcXX2VgiP8v8Ua/e/2a5DR/HlhIsWm\nalcr58aM1rIsvysrfw1tXV9tjHzr8qbnbfurKn7p6MqlKtHmjsXF1KZZt80zLtl+9u/8dp9xrXys\n8Lr8vy/3flrmdS1BJZkn+1Mm1N27+9WZN4k+b9y/8X72uuNQ8+UeY6uPXry1kZMr977392pV8QNM\nyTTTK3z/ACrv+WuKXXIVmMPnN+8XajN96o5PEH75XSFSkafxPtolUj8REY8p30fiSe1hP2l42Tfu\n/eVeXxs8Kq4WMiRPuq/ytXmDeJJpNvzsqUyPxI9uoTzl3q/3d9R7Y05Zn6yf8Em9TGrfs56zcCQt\nt8aXC89v9Dszj9a+B9H8beTdNM9y2yRlby9/ytX2z/wRY1Qav+y3r92Ccf8ACwLpcHt/oNjX5q2/\niq5mkVIbmMIr/N8vzfdr8O8OKnL4i8UP/p5Q/KqfNZHCTznHpd4/+3Hueh+MrCZk+TfEzfeZv9XX\nd+H/ABqlxH/obsis6q67fvf7tfPHh/WvL2PP5bsybkZf/ia9C8O+KHjaPfMyL99I1f7rV+zSxHNr\nE+tjRme42fiC8mkiSGbb83yQyfe2/wATV7f+xTqw1H4qakhJBTQpsAjG79/Bk/59a+UNH8RXM377\n7Ssj/e+b5dtfRX/BPjXm1j4x6gsu3ePC0zNsbIP+k23P61+f+Kle/h3mUf8Ap2/zR5XENCX9h15f\n3TQ/aW1qWz+OOuwWrZZDa71/7dYq4CTxNDHu2Px9123/ADbq0P2xfEq6f+0T4isFaNWK2nzP/wBe\nkJry7/hMPORoYbDadnzNXqcC17cD5Wv+oah/6aideS0JPKsO/wDp3D/0lHeTeKpoZkR7nO5N27+9\nVebxTNKodHUp8y7v9quEt/Ek0nlzXMaxHdudo/m+WrH9sTBm8mZkG/dt2/LX0csV757n1Xm942tU\n1aPbMjwsf4tq/wB7/ZrB1K4eRpnZ5F8ld3lr8zVFc6vczbZjtIb50b+FaytSvHkYv9sYfN80K/wr\n/eqPrEpbFyw8YwJLq6hWSF0/ii/1jN935qyZPEG5nTf937zN/FS6ldeZG+/ciM3yfxfLtrBvj5it\nNs8zavzbm2s1bU6hy1MPH4jqI/ElnHsmmf5tmzzP937tQyeKkvpmRJlO5G+ZWrhm15FkT5Nqxy7t\nqt/s/wB6q3/CSOq703A/xNvrU5+Q6q+8RQyRrDC+9vu/L/drHu9YhH+jIi+X5X977tc/Jr/mQtNZ\n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\nffnc+3btqexscqtsifJ95GZN1c1bY6KdHlnyl21uiu1Hh3bfvxtu3bt1dRo95Csezflty/vJHrlr\nWF41Kedh/l3bn+7/AMCrY064f5LZ33sqfumb7v8As15sj0Y05RV2dbcQ7XFz5K71fcm5apXdz+8V\n327/AOJdldDeae6xl5o1dv4dqfdWsjUtOhWP7ZM6om372z+Kvj/tH6RRpycfdOauP31uru8ZK/xN\n8q1z2rfvJWmR8Kr7pV8r5m/3Wrqtajs1bZDDkN822T+KsTVI7maPe6NuVNywq3y10U/dPZwuF5jj\n76/CjYk2Xj+ZFWKse+3szbNqs3+3XQatZ/u3SHcm5Pnbd92svUI4ZFZLlIyyqqtIv3q2p1PZ+6fQ\nYfL+b4jltStZmmV0dWeP7i1l6lA+4QzOqMy/d/irptRWzhX7T5rbN+5I1Tcq1g30cGfJ8lmdm/1m\nz7td1GtzCxWWx5TFmsXWMpvVXV9qbqiht5pG+zOm5ldfm2VfkCQjZv8Alj+b+826n2tiI1OyNsr/\nABN/FXrU63LD3j4TNsv5eYfp9nut1+T5t/8Aq99a1vo9xcRjyRu2/L5cn8VR6fboscXnJuf7396t\ny3XzZE37QWRl+X+7/eo9pLm0PjMRR9nAq2eltJsdIdqRuy7f4lrY02zn8iTa6j51+XZVi3t3ZTC/\nzRL83mL/ABLWnpq+dhIXZ4VXc7eVtrH+9I8mty9QsdNhmkWF3Xztv+7urd0/S3mh+SGRH2bW3fwt\nS2unQzLHNDYec8e3/Wbd3+0tdD4dsYVkUiFl3bt25Pu1PtJfEc9OPtJe8VYdPMkkaeSpZfvN92tB\nrVIoG32ap8+7du+9/srWlb2aW6uiQRyNJ8sXmPUk1mjN8+13Vm2/L8q1yyqe9zHfRpxjqjnG02ZS\nNm1ZP+WrbvmX+78tL9l/dmwmjV5Nu75f4V/iram0m5mVZkTcfK/v7W+9SR6S6zY8jYqurM33lVf9\nqolL2kbSOmj2MD7H9nZLmHps+ZVr72/4KxQmb9nLR1EQfHjO3OCcY/0S75r4ijtUZndJlWNnb5V+\nbd/tV9z/APBUqNZv2ftHhaQLu8Y24GTjJ+yXfft9a/HePH/xnXD3/Xyr+VM+R4mvLiXKLfz1P/bD\n83bzTXlaS8mfIZtvzfd+X/ZrOmsfmX7NtKL/ALFdndaK/wBoVEEe7+JWf5Vqh/ZdmsLQ+TudpWVZ\nNvzV+sfu+bm6H6HKNWUbHLrY+d8jwsgX7u35t1Ja6X9/fbsxX+Fvvba6BtLhZZXhdk2/ebb96obe\nzm84eTtx/tL97/ZqZShzBGMiG0tZmuPJd22rtfa3zVorvmkCIm5vm+7/AOg0sNvNa/Olt959z/7S\n1c+ypuSZ23hX+9/8VWB2xjKJWhsILVtjp5TfNv8A4vu1Zsrf/SvOhh+6m5P9rdUUlq8dw1z9mZ9z\nMqKrbt1auiw/aWj3pvCoyu2/5v8AK06cpRjv7pt8U+U1tF0ZJFS2R2Vdu6t2z8PyTRuZPuKn8X8V\nN8P2cMS/vvut9xmf+H+GtDxUp03Q57mF2c/wRx/3qrDxnWxEYI2rYilhKEqs5aRPOviV8ZtK8I6s\n/huzvI5tSkdWSHyvmt1/ut/tU74nap4b8QeHbfQU0qOI3lv8/wBoX51+X7y18z/FxvFXw/8AigfG\nPiSGRWuLjdKrO3zN/wDs16n8RviLYX2h6B42t7yGa3uIPuqjbYf4dtfeYTCxwlKy3PyDOMwq5rip\nVHL3fsngXjLw/P4d8RXFmjsn735W/wBmnWdwfs6un31+VJP71db8arWyvvK8T6U6lLiLd8qbljb+\n7XD2lw9wqvhS6/wr8td2vxHk83uHU+F9emWZYUm2nfu3M/3a4/8AaGhhmuI762dsyfeXfWhDeJp7\nNMiMp2/3/u1z3xEuE1Sz3tc8Km35m+apl7xUfeOGsdUuYVWzun3p/BuqreKjSb4XZVb5qWZ/sswd\nEyKiurhJY9iQfx/eany8uhtGXMRtcPDu2TbaJdSmWNd+5ht/h/iqtIqMm9Ub71RSNuX7i5X+9T+G\nIe8W/tDxsu/cVVf4qI9U3MN4+X7yVQa62qUfr/eWommZlWTPzb91Irl5TaXxAgb/AFm11T7tRTa4\n7KUhumX+5WT5z/feTn+9/eojZDtd9zbar7IuU049Uu13OJm+b7/zU861MsY/fb9v8TVlyzPuNJ9p\ndYcfKakXLI0pNcubqQl3yrfw1WurhGwnkxiqTyO6B9+2m+ZlV/dsdtA+UtNJb7kT7tdjpN5/wivh\ntZ4Zt9xqCsit/wA84/4mri9Ot/NvE3hj/e3VoX2pPql0uVxFGuyJd/8ADVSfu2YuX3zsNF1uZlV3\nfIX7ter/AAjj/tTUB5y7lb7v+1XiHh2CG6mRd+B/s17j8Odmn6evk/KVT52b+GnaEY8xjM9T8WeM\nraz8PtbOjCO3g2xKvy/N/wDE18deOtSufEXjq4vA+/zJfurXufxm8YQ6X4XeGG8kVpEZdv8As14b\n4FtZtS8StMkLSu235ahc0qo48tOHMz9aP+DXH9gDTfj7+0sfj9490H7VongmKO6ihk+aP7c3+p/7\n527q+3f+Dxv42XngL/gnp4R+C+m3LRt4+8fQw3SpJt/0e1jabaw/u7tv5V9Jf8G/37KcH7NP7BHh\nu+1DSvs2q+Kol1PUDIvzsrD93mvzx/4PUdfeXxr+z/4MmDPb+Vq160fYtujWunFz5VyL7KMstjKo\nnUf2mdB/wRY/avsPBf7HHh3wxrcMjR2sCwLbwrtaNVZtvzfxNX0n4++O2g+IvDr6loXiSGc/Mstr\nb/u2j/2WWvlf/gkP8D/D3iD9mHStB1t2Zbjy54ppIP8AUszfN81fRXxk/wCCd2veFfDt54w+Hvj1\noZv+Pjyb518pl/66V+HZhGnUxs5o/a6EvZ4WF/5T56+K/wAWNK1CSaH7GqTTOzXXmRfd2/3Wr508\nfeJbmO4eHR9RjuEh3NKscvzKtaXxUuvij4Z8V3mia94bvlDJ/roU3RSK38SyfdavM7zQfEmsTl7p\n2h85fvLaszf8Cow+F93mNvbRjD+8cN8QPiRNdSvD9vj8qNtybfvf7rNVbwLJeaxfu8j3C211Ftuo\n1Xd+7/2lr0Vf2bodQkXUrx47hJk+VWgaPdWdqHgvXvBcs1npqMtsqbka3Vm+7/eru5I04ihOv8R5\nzcXnxC8F641/4Y1iaBrd/wDR/Ll27lrkdQ8B+EviFcf2V4ks4dO1eaVm+2R/Krbvu7lr1zxI3/CW\nafvsEaXVI03wMvy7tv8ACy1514w02wvPDyeJ7C8VbqGVkurdvlaNv92s8PUnQm+TQ6sZzYmGvvHk\n/iL4NeNfCfjD/hG3CiSF1aK43/Iyt91qPihNDptnBpUtzC9yrruaF926rnjLxVrGpQl7y/kkeNPl\nZn/hrhtDabxFrCzXMytFG+f3i19Dh/aYrlq1Psnw+M5cPP2S+0eheF7VLXw/BMn8LMzq33mrUn1p\n1jW22Qsuz91u+9WdHsNvsfc25Nu3+GpY9NTy0/ctujX5K5a0oxnzHPJ8qsif+y/tka3Kct/Eqr92\ntOxtfJwfm/2d396s+x+02e/5GVGZdrb/ALzVsQyIux32+a33vM+9XDianunTg5RiXdL1Kz0+Zdkf\nzyP825/u17b8B/GUNvNGn2xXbzdzxt8u6vnW51J2mE0kO4r/ABL/AHa1fCfjZ9HvornZteN/l8x/\nlryMRhalWk5RPXweMpU5+8foDHdWHjXTfJmhhVZIv9Z/d/u074e/CH+zdSm+x3Mlyu5Wl3fd/wCA\n184fCv8AaHuWht7a5vNzK/zR/wALV9M/BH4vaUqw/aXkk3DdLub5l3f7NeNKMox5Z+7E+poUsPiV\nzH2L+yP4a8Zs9tY2NnHIZG3Wqtu+Va+p41+NVzpUGmzQ2MKbGR2j+bb/AHa+av2cv2iPB+nrbXN/\nbMgVNiNa/LX1b4H+K2leMY41th9njCf6yb5t3+zVYf2Djy8xz4zB18P+8UOaJyWr/CLw34X8R6b4\n88ZvHqEmixST6bZyBdv2hl+aT/er83f2jtW8SftFfGzxBZw23+u3QRaavytDt/h+X+L+Kv0b/ak+\nJ2j+B/Clzf8AkrdTQxeayyfd2/71flD4k/aH0fw38VtS+LujzWsXlyySyx+b97b935v7y12OnTty\nR9TbL6cIw9tVXvSOp+CPwtT4V/D/AFTXjxqWk36tLHtVZfl/iZf9mvtzwt43+H/7ZX7KXib9na9m\n+1Sax4akis7iOLzGW6Vd0bL/ALrLX5lW/wC0Rf8Axk8YeI/E+g3Kw/2h+9v7OFGVWm+7u/3dtfWn\n/BMv4mzfDX4jRSXKr/Z73dvCiR/N5jN/d/76r0aMalKtGopDrU4YrCVIOP8Ah9T4PsdJ1azhPhvW\n4Zm1HT7iS1uo1i2sskLMrf8AAvlqZYzI3nJMz/wuuzbtr6Q/4Ks/Ay3+Cf7d/i7S9JHlaN4stYfE\nGmLH8u43HyzbW/h+avn/AE7R0hj8h0UIrbUbf95a+2UOb4pHwlOtHluojLWxT5vIfbt+bd/F/wB9\nVpWemp9nG/8AfP8ANsbb8y/7K0+GG2b9zDudG+ZdqN/DUsbTSW7QvDs8z5fm/ipRpc2sTeVaMdy9\no/k+TM9ttlaPavzP93+9XQ2bfu/325P4f3fzfxVk6Za+fGiI7K7Sqz7a3reGFbff8zBd23d8v+9u\nr08PTjGHvHDKUqkiyq2rQ7Ps3l+X92P7tVpI7ZUMyJu2ureW33mqaG3hvJC825gr7fL3blZdvytu\nplxbpBD9/Z5n8TfM1dtOIR5qhQ1i1hhlZ3mVF2N8zfN5a1hXiwLujTblYl3bv4l/hrb1Rmaxmtn3\nJ5i/eV1Zdv8Au1zt1cPNMsKTb/4omZf4a7qfx+8TUpyKF9eWzMYYd2+RPnVvuq1faH/BMvd/worW\nSRgHxjcbQT0H2W1/Kviq+8mZVmRGTbL+93J97/dr7W/4JmTrP8CNX2M5CeL7hQHGCP8ARbXivxr6\nQjv4bVP+vtP82fA8eQl/YTb/AJon5zeKJJobWWaD967f/FVytqqX1w0EL+b87blj+ba1dDr2+8l3\n/KVb+H+9tqtY29tYxy3l/M0McKs3zfKq/wC1X7jL4bRPfrRlHUzvEnh+5sfD83lbVmuIv4U+ZV/i\navnz4mWttoqun2lSv97fuauo+LXx8upbyb7Nqv3V8pNv3fLrw7xd4xm166+0u/zf7L1z80uY8r+J\nqY2r3T3Fxvi2vu+/trofhz8P7/xNfQoiMTu3fcrK8M6K+saoiRoxeRtvy19X/Bv4W2fgPwynifVU\njSVovl3Rbq0ic1SXu8qMnRfhbpvhrR2nvEjV1XcqsnzV5/8AE3XLDTZJLa2mjY/w11fxc+LTxxtD\navgxrtRVSvBfEniT+2Lh/Pdid/3mrOVTmmXToxj7wl5ePdMZnmzu/wBn71ULpoyrbNxb/dplvIjr\nsd2P+792obxnizzgVUYmnxEU8jsu/Zjd/DUTL8pfG5fvNUihJpA5+VWpEhSNmj2ZZvu7qOb+UmOw\n1o/Oh8/ydq0+3t0kj+RN3/AaVI23bE+7/HVm12R2+z/0GplEr4YBpvnWtwrom5lavZfhX4omaxWw\n+Vtu5kXbXktnCjLvMbKW+/XY/D/Wv7F1KLe7eV/H8u5qPs+6RKPMekNM8zNNv3Nu3bVf7tSrInl+\nd5zfM+6se8vNt5vh+43zfNU0l0lupd3+X721mp80okcsfsnQrcOzb9iuisv8VTXF1MvL/Nufci7/\nAJWrO0G6S7j8lH27vm/d/wAVatxahZDv24VNvzfw1RHNy/EcX8Zvscmg+dDH/q12ttryLwvqnk6g\nyb/49tet/GAGTwu6InKu3zMu3dXhen3Xk33/ANnU832TWMub3TqPi5oP9qaTFrFnCu2GL5mj+83+\n9XO/C7xpPoN/9geZvLkbDK33a7vS/J8QeH302Z1O5P4a8m1/TZvD2tyw+Sy7W+SrlH+UunLeB9BR\nql9bm8h+YfwMtU76xeNhhPu/c/2ayfgj4uh1zT/7Ku7lS6/KqtXXXlpu/fOjLUxkRU/lMOxjEcys\n6Kw/gq1dXWpaTqNt4w8MXPk39rcLLFIvytuVty1XvYTayjztv/Aa2PCujJ4ruho803ktJF8kzfdV\nqqn7szHEcsqR+8n/AASvmtv26PgloXxC06wjuL+1/davt+9HcRrt+b/Zav0Dtf2U/hVP8Cta+CPj\nzwza3Ona/aSRanBMqt5qstfgf/wQC/aY+Lv7OP7W3/CkLDWGGk+Jn8j7PM+2Jpl+6y/71f0HzeJN\nS+Jnhm60iB207W7T70Pc12RlVXudjzJUaC/ex3Z/MB/wV6/4Iy/FH9hLVr74u+E9Fm1D4f3mpyRQ\n31um5bHc3yxyV8GaTePpN8tzHNxv+7X9pms/CP4d/tN/BjxT+zl8YvD8F7ZazZyQXtlcxbmTcu3z\nB/tK3zbq/kQ/b+/ZL8TfsSftbeOP2a/ElvIy+HdZkis7iRflmtW+aGT/AIErLTxLjWi5x3jv/mb4\nLnpRUJSunt/kVfB/jCO+hT98u3/Py19efsv/ALa+g/AH4G/Ef4e+MDJeaf4m8EX1hZ2O3zI5LiRd\nsa/+PV+eGh69No98uH2bfl/2a9W0HxNba94fNt8ryLF95q4IylzRO+pTjy3R5pqem3ngPxIsSbRG\nyq8TbfvV9h/sH/tfeP8A4C+NNK8Z+ANVjtJvN8q8ZrdW3Qsu1tu77vy18gfES6udThjhd232rbYv\n92ug+Cvi1LW9hhe8xt+/t/hqMbhaeIpShPZlYWpVhGMl8SP2w/bi/Yz+An7YH7DviD9sn4IaG1h4\nw8G2C3urW8PzJdbtqtu2/N935q/G3x1Zw32jxakX3GNd25f4mr7H+Af/AAUq/bJ/Zz+E+sfCj4Oe\nMNH/AOEd8QWTJe6XqWnLLtZl2+Zu+992vlDxPY3N1ptwmq3jXE83mPPJtVd0jNuaubAU6mGw6oz6\nfC/IlxvXdWL3+L1O0+AesfbNJNtDtLSIsv8Avf7Vd3qGh20sm9LaTP3t1eO/s1XVzZ6lDC8MYWOX\nymjZ93y19CTaLc/aPJ3q7/d/3VpVIypzPfwf72kcZdabtO+b5EX5dtVbrQzt/cwyBf4N3zNXeTaP\n5kBSWFW+bakmz/0KqzaHcrG/7lX2oq7mrE66lGMVocJN4ZjjkRPm+9ub59u6iHRd0j7P95FX+7Xe\nL4deaP8AfW2/b/z0/wDZaS18M20LlAmyj34xKjRP0D/4Iu2kll+y3r0EkZU/8J9dHaf+vKxr80Yd\nL/fM8XzI3ysu37tfp/8A8EhbP7F+zdr0e0gt47umOc8/6HZev0r85Y9JeHanzIn3dtfiXh8v+Nhc\nT/8AXyj+VU+W4ZVuIMy/xQ/9uKFjYw26rbeT88nyvtrT0213R/ZndlRf4Vb+KpLfTYEmaPZu/ii8\n5W/9CrW02xTznd4Yyqy/d/ir9QxEYy5j9Hw/N0JrW1+VZrmFsKu1lj/vV9W/8EuLdovj1qrncV/4\nQuYKWbJ/4+rWvmKxhtreSL9/+5j/APQmr6l/4JgDb8ddYjXG1fCU23IwR/pNrxX5j4lQ5OCcbb/n\n2/zRwcXXfCeLv/I/zRzP7c1nG/7Vfihwzl3Nl8g6BfsFuN1ec6TpsMzb0m/h3fL92vV/21to/ag8\nVEhd7fYlBLdvsNvXnej6f8o2Q4T5mT/erXhGX/GK5en/AM+KX/puJ7vC8YvhvBW/580//SIlzS9P\ntreZE++ZG+TdF/FVu6tUZj9jh+dWbzWV/u1JD50aoUeNPk+RvvLtqebyWkELvteT5naNdq7f4a99\nR5p8x7svdhy8piyWbyQl4bbYqru+b+KoFiSZftML70b5fletj7HbfwTK4b5dzP8Adaq8ljCqShNw\n/h8xV2/9816VCscdaj7plSRu8LWzpuK/Pu2feas+axe6mjS5RV3fcb7q/wDAq2Gs/JkZ71FSHZu+\n/VWazhWbY6b0m+ZFX+KvVpS5ZHkSowqe6ZF9pc3kt9j+V2/5Z1Qm0d1k86ZFU7fmZf4a6VrVGZd9\nq0KRtt2/3qp6nausf2MzKit/E33V/wBmuynW93lMlhIy1Zzsmj23l7EC75vv+Yu6srUtPhkh2Iiq\ndnyeX8u3/wCKrqbjS/laHZuP+037yse/t0jhDpuBVvlVX3bv+A1p7SfNZHRHB0ub4TktRs5vkheC\nRS3yxNH8rUklmlvIsPzI/wAzeXs+8tbt9Y+ZN89mz7X3Jtbb81TW9tuuG+0+XI/lfeb726qqVPd9\n4y/s+PtTBtdLmt7Uwokjbvn/AH3zbm/2a1dN0142E3ksm5drxq3yrV+30mby1feqsrbvlrp9F015\n7MOkO3zJd25vl+WuXnNfqfuFqZkuIw6eWrt8qbfm3NUDQ/bIzDJbbXX5mWRfvLVyWPzlMnnKrR/K\nu7+GnxslwvnQ+YG+68jfe218nGnKMbn2WHqRlVOY1C1RWP8AcV/maRN21f7tYGrWG2PzpnVEk+7t\n+batdvcRvJDJNMilI13ff+9XN6vYpuLzxKpZdz/7P+7XVGnLY+mwcuU4fUNPRm2Q2HmmsXVorncx\nSzWPzE3Nu+b/AIDXaXlgnlmZAx+Zti7KxdU0u8WFZptweTcqsy7VaiVOUj6vAyicXfQw29q/ybW+\n66/3axJbVFbl/l+b5WT71dJrFjMsZ5UsvzfN/FXPNzuTZ91GX/gVKnzU46HoYinSlQ5jNvrdGhG9\nFT+/TI18sr5PKt92rs1i80fk71+Z/wCGolV4Vf5PvfK27+GvVw9Tm5T88zij1LWlww+Wxhm3t/d3\nVq6fdWy3BSRGJZNqf3lrEWaaGRofubl2p/earlnqDqzo6SD+BN23c1ehR5viPy7NJcs+U6W1H+j7\nN/7xU+RWf73+9W1pM25RshX/AG5N9c3Z6knnJHNCyqz4Vmro9HuhDcBH4iX50bbUVVUjA+eqSvPl\nOl0NXjlX7qru+dv4q63T7MzSC5hdtn+581YOjwouLzzVx/F/s109lI8ax/ZnjES7djLL8zf3q8+v\nL3rnZhcLVl8Rbt44Wwn2ZV+T5WVfmarC2aTXDBPkRvmVWb7q0mkxuWP75t+/a25q1YbeF2dJkXCo\nvzLtbc1c1Sp8MYnrRwvL7xmx6em5P9r/AGqp6tapCkzww7m/i8t/lrpI3Rf3zouWTai7Pmas+8a2\nuI3SFMfwyx/3qunIUoxp7HNXK3LRv9mSPf8AxtHX29/wU+BPwC0gq4GPF9vywyP+PW7r4vvNJeFv\nOtYVdv8Ann92vtX/AIKZ5/4ULpYXbk+LIMblz/y63Vfk3H8Irjnh5L+er+VM+D4kduJ8o/x1P/bD\n4IurPz1KO/y/7P8Ad/vVX+zorGZ4Nj/9M/4a0biGaGPzH8vP3dy/3agby41875kfZtZv726v1ZR+\nyj9C9t73vGReRwyLvRZN27btX5dtUfs8Me/yXZXVty/PW3fQzR/ubx2YR7vu/wDoO6smazfa5/ib\n/lnI/wB2lKMYl83MRtvuGLo+G2fLGy/N/vVbXzlkMKO2GTczMv8AFVNmeSREm3fL8zqtXdPuoWWV\nE3F9rMqr95VrmlGZ105R5i5Fa7Zgn3l3/JJ91lrZ0e0SFU/cx5Vv4U+9VfRdkw+RFxt+dpPl2/7S\n1u2qoWWySGN0jVm3L/tVzVJOMuU66ceYvWNutu8czW0byR/8s2eqPh34v6JZeMrvRNSs1mjhg2NH\nInzM1W21WwsbO4vLn5fLt9qKvyq3/Aq8w0vSX1bWLnVYXjXazN8vyrJX1+Q4Hm/fSPheKc0i/wDZ\nIfM7b9pXw74G+N/w1vNK0rQY4tRtZd1vNJa7XZlX+8tfHfw5vLybw7qvwK8To1tex7p9IaSL958v\n8NfW+i+JrbQ9WiS5jmeVtu6ORvu15l+118M3+1Wnxj8DWarqOmy+fcLCvyzKv3t1fUfFSPhIynFH\nj/wz1a28UaXceA9S+ZpFZbeRk+bzF/vVx/ijRb/wrrk0PQx/I25vu1f8SahbaH4oi8Z6I/7u6VX2\nx/Ltb+Ja2/iFqlh46t7fxClgsRVF3f7TVnGXKXGPL8JyEfktZrv+Xb83zNurlPEVxC6vC/zVv6he\nJCXtvm3f3v4a43XriG4kfzudtUXGJi30O5ZE3/LVPzPl/d7WFXLry1Yon9/+/VGNf3jQIm3+9VfE\naxEaHd8+/wCX7zK1Q3C/3z/3yKvTW7rGE+Zw38NVLpf+mfzLUlFCTezvsP3ajkbc1S3R3NsCc1B8\n4Ul/4aBx3DMm3p8rVKqzbtny/dqEtkLn1qRJPm96BDmZV+QBc7fvVF5zt8mKbIu1qWNfmGXoHysX\n7w+SmDeuAHxuqYbIz89FspmnRMc/+y0RCO5YaX7PZ70++3ypt/u0trlvn2VBdMjXB2fN/dqS3j8x\nv9dtZv7tHxEyOq8Mr5brNDtU16t4XuL+a3/1yqipXlPh9fsixzTOrbf/AB6u6s/E0zWaWdlbbP8A\ngdae7GJhKPMVfi1qW6xKTTK7L9ytz9gf4W3Pxk/aM8K+CbZP32reI7WCJW+Zf9Yvy15f8RNTmkvN\nk024/wAK19rf8G/XgP8A4S7/AIKAfD55oVMVrqn2h2/3V3VphY/vEY4uXs8Mz+sj4WeFbDwP4E0j\nwhplv5UGmadDbRqv+yqrX4Sf8HqVjMPih8ANV2KYvsGqQfe2nc0kdfvbpF5i1V33D5f4q/FP/g8x\n+Hk/ib9n34WfFy2i3R+GvFc1reSKu4Itwvy5b/gNY14Tlzm+CrUqcYIw/wDgl348ttM+COkPDM26\nG1j/AHKy/e+X71fT3jL9qq6ure4s3RbhI7fZ5Myfd3V+Zv8AwTl+Lj6f8EdLtdiuY4tr3S/L8v8A\ndr13W/jVNdXDJc3LLFv2ttX5mWvxLF04xxs4n7Xgqt8PCoe/ahr3wi8QWtz9vtmiuWib5VRWS3+b\n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\n9N1C28GfErVo9S06+02JVRbiT7y/N8v3vvV+qXirxXbXnhOx+K2iSKj6d804+9+7b+Fq9PHUlOpG\nrH7R5GEqyjTlSn9iX/kuzP5Qv+C1n/BOfXP2A/23vE3w1ttOZPDmsyNqvg+4VfkktZG3eXu/vRt8\ntfGv2e50+TZMm5vu/d+7X9Wf/BfT9hDwp/wUR/Ybv/iz8PbeK58ZfD+yk1TSGgX95NCq7poP++dz\nV/Lfq1r5LPDfw8M23d/ErVzV4qpFVV1+L1PQwdd0p+ylt9nzR13wrmfUrV9N+953y1z3izRZoby6\ns5k+aN90W771a/wniSx1NEj4j3Ku6ui+Lnh/+z76LW9N2sky7ZV/hrk5uY7ZcvOeR+GdUm8N+IIk\ndvkZv71fUPw71i11nRdn2zLNF91fu180+MtBSzkF/Cm0bNyf3a9I/Z78aIzCwuXjH8KM1RKMoy5i\nuWNQ9Q1SxRVd97KP738Ve7/sz+Mv+Eg0v+x7y5b7Xa/Kir95q8W1S3SVH/iT+Jo60PhF4u/4Qvxl\nb38160NtHL+9/wCudRiKftKWprg60qFWNj7EtdNmt137VVN/97/x5quQ2O7ykvbmFlk/ij+VttX/\nAA2tnqmlw3lo/mJdIrq3+9V+axf7U/nQx/KrbGb+GvGj9qJ9pDljCMjGaxDTTXKczN8qbX/9lpbf\nS5mk/fWyu0nzPt+Xy/7tbdhb3KyJvtv3Tf61vl3M3+zU8en+X5v2Z9rLu3Mybl/3q6qceUqUYS95\nH0h+wxAbf4R38ZQqf+EglJUnJB+z29fIN5oNwjM6JtdX3O0afdr7J/YyhWL4YX7KuBJr8rAjoQYI\nOR7V8r3FmizLM6MTG3ybXr8Z8OU34h8UNf8APyj+VU+L4bgp8RZpfbmh/wC3nDa9o8Nu2y2H3vm2\n1yOrWdtNcP5zqpX+7Xo3iKPy1dLb7q/P/u7q4PXF/guUj3790qr95q/XcRE/QcLTcZabGVMuza6J\n8y/L/s7a+jP+CZHnf8L/ANYE0W1h4QuARtxx9qtMV85ySbbfZZuyxq33pG+Za+h/+CXsjS/HvWSz\n7iPCEw3Z6n7Va5r8t8ToyXAuP/69v80cHGMZLhXFv+4/zRzP7dl1IP2qfFcSkfK1iEAbksbC3ryS\n3vHVZZnm+825PLb5l2/3q9L/AG/LlIf2s/FZCZ+awBHv9gt8NXksdxZxr5c0yp8zN8v3qjhRW4Oy\n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\nS+L4jDlG+Y/ll361JCvmIvdv7tJHC8iZ+9/srWrpWjvcMNkLZq/iHIhsdO3Irl2bdW1p+ks0m9E3\nLtrc0Xwe6w+c8G5f9qtVtNTTVbzEXP8AdrXl5Y8pj8UuY5y4s3tVLhG3NWbOu6TeB92tfWrpGVnh\nbDKn3awJpZpJGfeu2spSKjHmIbiaRmGxGb/aals1dWZHT/aZqRpP3a7wxanQ27sdjvvXZuo+Ef2D\nT09ftLKm9VVf7yVsNp8zWu+H5i336xdPuNs+zy/k/jauks5LYQ7N+0NVcxMtjM+xzQsPMTa6t/31\nWnpLOtyPu/K/zrS3SQ8eTz8+1/n+7TY5Idy+T8prOPvByx6noul6Ho+raemybaVTb8teP/GDT30f\nxMLZ3Zfl/wB6u50e4eO2ZLN2Vl3K/wA+5WrhfjJNcTX1tNO6lvK2s1IcY++Zfhi58y62TP8Ax7q9\n48EzbvD4j8xWC7flr500G7eG6D/Ka91+G139q8OzP8w8lNzsv3qv4Qlz7GP8WtQdtLebqjbv+AtX\nicm+SYu235q9M+MmpbbYW3n8Nu+X+9XmKcMKZdOPLG50Xg9Q1xGm/Zu+81fQ3wzkeTR1hhTPyfNt\nr5/8HxvJNG6fd3/xV9DfDe3hj099o+Tyvl/2qOb7JjL4x/jC8hkjPySAxrs2t/FXh3xC8MvcNLqV\ntbNlWr2PxNHc6hMz3KSD59u5qyW8KvfL9mezZ/4lk2U48hl73PzFj9nHXJNQ8Oy6U94vmW+1ljb+\n7XdalYbo3uUfJ/iVU+7Xk/gWN/APxOht5nYQ3j7fMb7qtXs7XLhdm/8Aj2/N/EtT8PumkuWXvHE6\nhBNDcOjvvRk+X/Zr1b9kP9pTxh+zP8TLDx54buZIfs9wrXEMb/6yPd8y15xr1ikNzI6bZEkZmf8A\n6Z/7NVrVfLuBJvw33drf3aenJymHvn9KPjT4ffC3/gsv+whpXiLwzqwi8TaZa/atB1VWXzIbtV+6\n237u5l21k/sy/tXeNtK/Zz174b/GnQb5/FXhu1m0PxHpcNr+8VlXbFcbf9pa/Mf/AIIH/wDBTC5/\nZL/aJi+AnxJ1jZ4Q8ST7YJppf+POZv8A2Wv2/wD2hPgH4Z8S3kf7QPw/vFtLqWCP+3JLOHf/AGlY\nt947f4m2/dau/AV4zthqz93oebjaFWCeIpfF9r07nj3/AAT6+M9h4p8QXnw38QXRNtrunGH7K7bl\nZtrL/F/s1/Mx+1F8O9E0X9oz4n+DNHRWttB8f6pa2rR/d8tbhtqrX78ePYdU/Y2+OFl8Wr63Ww0G\naK8vfDrTP+8S1WFtu7/ar+enXvGV54k+MnifxDqVy0jeINcvLyVmTb80kzN/7NVY2MsPUf8ALIrL\n6kK1OPN8UbnLeDVudF1ZVmTdCsvz/wALba9Z8SaTba94JuHSFi7IrRMvzV5+1mlvqT+cjMG/4E1e\nmeD7h7zR4tMd12Mm3a38NcEfiPRqS908VmtodW06awuUZXj3LuauY8GapL4T8VGGZ8bZfl3V3HjD\nT30HxhP8i+XcPtRV/u/3a4X4gaV9g1BdXtk+Tf8AO392iXve6aUZS5uY+nfDt6niDw9HeO+Fbb8q\n/wDoVVNQheO4kmh/hX+H+7XD/AXxg+oaWtg82/8A2Wbb8td9rET2q7ETe237yvUc3u2CpHllzH1l\n+xv8Un8ZeCW8PXlzun019nl/eZo9vy17D5bsXTy/mb7vnV8Qfsv+PH+HvxSs7y8m8uyuv3V02/7u\n77u6vuqUpcTeYk0ctvIi/vI1+WT+7XDWjyysfVZTW9pQ5ZDtLhmbzQiZXZU9sl4ykwp8y/L/ALy1\nZsYYVj2bNif3d9WLXTUjXfCjK+/am2iK5j1PaS92J9B/sgqE+Gt8BHtH9uS8fSGEf0r5cvLV1kkS\na23ivqj9k4Mvw7vlYjjW5AABjA8mHivmq6s/3b7522t83mV+NeG0L+IvFDXSpQ/KqfGcNTkuJM0U\nesof+3nDeIls45PtOGzIv3lrznxFdQ2twYbZGLt8yNJXpPiaBFZHhSQJCjbI5F+Xd/vV5nrVjNCT\n/q3Te235vm3f71fsGIjDlP0nC+8c5Os1vcbIX3jd88i/+g19H/8ABLKdD+0VrUEa/KfBty4b63dp\nXzXdW9tumR7mZEVd0qq//s1fQv8AwScuHP7R2tWxOVHgm4ZW3Z/5fLOvyjxQafA2YJf8+3+aPJ4x\njfhLFv8AuP8ANHOf8FA5gv7W3i6N2bH+gEY7f6BbV4vDeFZmEL/OyfxJu3V6r/wUUuriP9sTxdFG\nBtb+zwxZuP8AkH21eGyakJpvO+bbGzKrL8qtWnB8ebg3L/8ArxR/9NxO3hp8vD2C/wCvVP8A9IRt\nxyJHqGd6/Nub5auR6xD5mxJJGZfmT+H/AHWrkLjXHhX9y+GVtqfN96hvE0DQ7HlVJtn8Pzba+hjT\n5j2PaHZtrG1RNNN+9bdvX73zfxVZsfESM7fuWUxxfupmfau2vP5vEAuI0Tf+9aL5/L+XdTP+Eimh\n2/Oz7vlT591EqcpaBHFcmp6ba+JJtyp8qLHu3t/e/wB2pLXVppGd3uV2t8m5fmbdXmtv4shZVtpn\n/wDsa1P+Ene3m+RI2G7b+7f7zVv7OXUKeIhKZ6Tp+rQtcCFHZ0jTb/d2r/eq5p+sJJbyeS7FWb7u\n+vM7fxY8MrmDcV27vv8A/jrVoaX4mfzPPSbbt+Zlb722s+adM7qFaEp3PSPtjzRqm/8A5ZfMrfw1\nYkktr6z8yF2O77u3+7XE2Pie2+0Qu95tRl+ba25mq/b+LEt5F2PsTyvvN8rbaVPEcr0PRpx943Lz\n5pEfZuX7v3qydSmtpJo7Fpldvm2/Lt2/7W6sW+8QPIGeymVdz/M2zdWLfeNPNX5Jm/dvtdfu1lUq\ne9zRO2Mealc1tW1rzIWtkDfKnz7ovvf8CrKi1zzhF5MzMmzait/DWDqniqa53Ijqzqn+r37du5qy\npvE22IobnYi/Mjf7VdOHrHl4qnynpnh3VLbbFbI6l/vf71dho+rfdheZUDL8zL83zV5L4Z16Fm+e\nb7v8P92u103VN0LIjr8zbq+zlT93mPySnipxkdbb6pN57JNNIvz/AL3zF+Xb/erSSZLiSIJ93722\nP5d1ctaXm7zNnmMv3Uaata1uvMjV5nbEbbl2/dWsZUYy2PcweYVYm/G32i6e587zQ0W1l3/dqby0\nkZ0R12/e3Kn/AI7VbR50jd5ntlZfuvu+6y1NZxzSXC38O10X7q/dXb/FXnVKdrn0+HzKXKmUL61h\nluPnf+H5W+7WLqFrZyQlLl2Ib+Jq3dQ/fLv2Lt37Ub7u2su4VI5lmf5n+Zdu6vExEeWR7FPGfurn\nG61p+xl3uz/3F2VjzaOtwqzbNg2bXZfutXWX0aNItmm4fvdzbqg+w2ybkR925m+Zf4q8+pLlCnW9\nscHqmgvIzTP+6X70rN8y7qxb7RdsDPsw33dq132p280cbwum5VT5VZfvNu+9WLq2lzeYXmRQsKf6\ntU+7uo9p7p0YenGU7nD6po6W8mXTavy/LVNtJcsybJE/e/d27q7HUNPEjL56bP4dv8S1nTWKbt77\nvm+ZGo5pcnKfY5fThGJh2tk9veJbfZt/ztvZn+6tb+m6fM0e/wAnLK+1VZtvzUlvYbbjZ9mVdzf9\n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\ncJM02397uf8AhrKMuY9WjL3tTkbqxdXld081flVPk+aqc2nwwq3kq3+wtdPdafDLveHdG/8Aeb5t\n1ZeoWKRp/eO9W3baXN759Rg8UYNva/MiCBiY/v8Anfeb/drU0mH9586ZX/nn/FTb7yZJP9fJ8vyq\n0f8AFRYyT27D7NC2Pm3bm+bdWXKj6TD4ilKBu2sbx26oltsdlb7zbalhDtMf3ezb/wAtEX5W/wCB\nVU0+6M0J3o2z727+LdV2w3+WEd9m5/njZvlbb/drTm5TzcyxUeX3S3YwpJvKTNFufc+6rSxwrHut\nn2r/AAKqfdqBY9sDzPcQ7V/hVP4qsR+crM9tCqq3y1rGU4+8fEYzEe2lygv7jy/tP323Oq19o/8A\nBS9C/wACNKKkBl8WwFSemfst1Xxxb27tHxbKzx7lik3bmr7O/wCCkUaSfA3SxITtHiuAsB3/ANGu\nfzr8s44qf8Zxw9L/AKeVfypn43xjGUuKsoVt5VPygfCF3b7VdLlPkk+ZGWoI9NSV/kRmGxdi7/lW\ntO4sXkWQ7GTazfNJ8tWNN0V7eP7S6ZWbb93/AJaMtfrX1iXL7x9p9XnGRnw2eVe2mmbGzft/u/3a\nsNp7tiF0ZG/iZmrVXT/lXcixKz/xJ8u3/eq4mkwyM0LzKrb90S/wtXB7R8+/um9OjLmszkLzSYY7\nd7mY7V2/NGz/AHq4j4P+NYdH8SeO5nha2Vp4V3Q7WVty7V/3Wrq/idqj6TqEemwoyssTP+7f+7Xz\np4b8UPpvijxJZzJMWvrVm8uOX/lorfLX2+SUKlPDe1f2j4PiCvGeL9nH7JW+KV59n8ZXMLxyReZK\nzeZJ95q8+8WSPY30V5D5h3Nt/eVtePNa+2XFvreyTO3ZK0j7tzf3q5/WribUrP7S8ylGRm2/3v8A\nZr3IylI8L3TlPF2oTTaozptCsn3qzrySFbYzTbfl+4rfxUniK4VZN7p8+2ud1rVnkh8k7g397+9V\n/aKH+Il84iZ0wrf3axIpvJZofmrZgc3uijzDny2rMkj3Sb4PvUfCEfeIpP3f393+9TJB5kf3OP71\nSXCBl+5yv8NQTcMqb9w/urRI05eaRAx29ak2Oyq9RuN5yaVfu7PMpc0S+VCx7Nxy3SrWmSPHL9/7\n38NU6ktWCzLu6UhSidJbSSeTs7L/ABU2RXjZtnzbvvVHZzPJDsTbT93k4RUyn+1T93cxG/eOzO1v\n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\nsjjZu+X71Mvptuz+JF+Z2X+9UP2zzj9ptpF+X7i7vm21rGUj16NOMhGm/wBHCFJA/wB7bJ/CtMms\n0hX/AJZszfOn+1TFmtpoRsTKxptTdSeZD52Uf7q7V/iZq1p/EceOp9Ty7VbB7G4dE/hT72za1Ys0\njtvjQYP/ADzr1LxN4V8xVn2Kv8Xy/erjtZ8KTWcnnJt/ef7NfSU8R0PxfEYaUdTntLuJrNt8KMfk\n27f96us0XULpow+/dtXbtVP++qyI9NmiZd+0My1t6TYzRypawpj7rM33f96ipWOajS5Ze8db4fkh\njVbmZ2+b5dqt92u20nUsSfI7PuT738VcBpdi8MbPG/nfxJXV6be/ZofO34eP76rXnVPelzcx7OFj\n7P3ju9FvprPbvRW/vtXX6FrCXCr/AKtF2fxfLXl1jqUMkaJbeYp3q3zPW1Z69LtV7l4dm/a275ZG\nb+GuKpRlKZ6lHEcp6WurW00LeSkgj3fKyptXdUd1qiLN882xG+4y/wB5a5LS/EEzRu7u2z7qNH8y\n7qh1bXXt7rf9p+b+Bo3+X/d21jHDz7ndHFc0feOg1a+jWT98/LfKjfe3VkX148h2PMxP92P7u6sa\n68TOc/adrfwov8VUf7etpt8iOzlX+Tb91aqVGXL75p9cpRloaN5ffNLDN95W+dvu7VrIuryGZ879\npZfvM/8AFUGpeILaFd/nSfN8vlt/6FWXeX0zN9xXbfu+b5af1X3YlSzKKL7XF5dK1sky/N83mMi1\nXWN2YQwouPlWVf7tMtbzbHKnnblVNz/3qs2O9pR8iun91vlqJRlHTlOeWO9pqzV0tfs6hE+Z2b5m\nb5vl/hrdsbM+W3nIwjjfKNv3bmrH0t0WHzPtKpL/AM82+81asMsKzJC7s7Qv8393c1efKpLnNIYr\nmhymxpP7yR4ekke1n877rbq27MJcKU8lklZP4X+Va5u1vJrdVTyM7m3JV6G4k8n/AI+WZ1b/AHa5\nq1P97znbh+aUpSOhtbqG+j2edGd331b7y7a+zP28XiT4SaWJQMN4liAycc/ZrmvhqG/eSSLZbbdv\n8P3fmr7d/wCCgVybX4NaZIIlcnxNCBuOMf6Pc81+ScaxcOMsia/nq/lTPhOK1y8X5L/jqflA+ZLW\n4hk2wj5Ek/hZvu/7VasLW0zb4PnSNNv95q4iHVkhZnM+f73ybm/75rVtdVdXR4V4Xav/AAGv0+MY\n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\nvtkuZEXzdyqrblrnNY0WaNmTyfMSH5v3f/s1dNGtKXxH5hiMPC55jceHYZGDp8wV9su5P7tW9Pt4\nY4V2bQzP8jN95lrpL3T5riT59ztGm2X91tqvb2cMMxhe2XG/Kt/FWn1j3fiOP6vKNX3SGzsZFb9z\nDvDfNtrStbGbcu+LIb7+1/lWp1j8mzCIm1o/m+X+Ld/eqSCaYW8R+zM/8P3KUanNGyNI0+X4iaPZ\nC3kw7f3jf3fu0LPDCwR5vl37t392s1vOjl8mGdj8/wB7f92i4uv3zujq6fx7fu7dtaU4395SM5VI\nm9Hqzx7fJTZ/teb8rLVDUtcuVDPNMzL/AA7qwf7Qmb5JkZ5WRV+V/l/2aLy48lgn2n7vy/draMYx\n0MpVJcvxF9tYnvGZ5rn5f4V37tzVJHqTyK9y9yqeX91W/irnW1JI5j5brTP7URVeGby3i2q6R1pK\nnzQsc3tpxkbsmpOq/anvF+Zv3Ucm35v9moI5kupHuZpmZ1+9tesua8S4kSa5Xem7918u7a1Tw3SR\nyF96qnyr8v8ADWVTlUCI4iUo6m3aum9YYfMQf7P3WrSt1dUXUk2v8/7qNl2qtY9ncJ8qJy2/c+2r\n0N3DJ+9mdmXeq/u1rza0pOXNA7acubc6fT5N00dtszK3y7ZP/Qt1XZLpFm8l5l3b9y1zFvqT/ax5\nMzStsZfm+Vavzah837sSZX+HburyK3P7e/LoevQ5JRN2HU3dfO8pY2X5fmepGuPtCpClyqNs/e+Y\n/wAzLXMyah5kwT78TN8219rLVv7XMzfvjvWP/wAerLllKPMerTrcvuo6e31a2hhhT5pX/vf3v9qv\nuv8A4KQ366f8ENJleLeG8WQLt+trdV+fEeobY4k+438Db/lX+9X3z/wVCu4LP4BaPJPLsz4xtwrc\n9fst0R0+lflPGtNrjPIe3PV/KmfC8WTvxZkrv9up+UD4zbXJl+SzhjVfveYrfMtWtO1p42LpMpDR\nfMzfNXIR3XmTfvH3hl+Zl+VatR6n5NwERP4P4a/WFT5tj9E55KRJ8bPHj6D4BvLmG8aOWSDykaP5\nm+avjbWrp4ZG+dnT73zfer2T9oTxpNqGtJ4ehfy7e3i3S7fvf71eM6sySM3dV3f7zL/tV97keH+r\n4Xml9o/NOJcZ9bx3LHaJyvi2L7RalNm/cv3a5fR9Y2q1hNIyj7u3+7XT68u7d96VfK27vu7a4PxB\n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\nu/LU1tp+795sUfxbVWp5UORDHHt+d92V+6uyrml6XLfAbE+7/FVi1s5ribZ5H3vl3KlddoOgwxwD\n+Jdn9z+Kuimclcz9J8MvLl4f4V2/N/E1blr4Z3TbEmaUx/Mv+9XSeH/CkNxJ9o8jj7yLs/irobHw\nik0Y2Kqu3zblWrlE4vafynE22i3MK7PJZm/g2p92tVNPmt8edNsZV3f7O2u3bwnf2rRulszM0Xze\nX92qF94TMavM6Rjy/urIrN8zfw1nUjzfCbR5/tD9Wa/adn8lcMvz/wB2sCa/m+1H51xs/uV0d9HM\n0MrzFl3Pt2t/DXL6lDDbt8779392voY4WHJ5nFHFS5iWHVjbtGmyT5vm8z73zVu6fr3l242O3yvu\n2t/drkVnSFT95H+VUZqtJdTFAifeX5ty1Ty+MvsmscdKOp3f/CUPI29Jo96orIq/+zf7VWo/Ejze\na6XO/an+r/8AZq4CG/mRWd+DN9xvvVN9s2M298SK67FX+7RSyvmi7FSzC8LncQ+Lv9WgdmX+Py3+\nZv8AZpj6g8is5mhXc/3ZG2yf73+1XLW+oC623M6eW7fK6t/7LWrpaxxS/wCk7SrfKka/eVa0/s3l\nMvr3MbC3C3s2yFFD/dVm/iqa3t7lZIvOuVcN8rwqn8NV7ezhXytjthX3Izf3q2rWzX7ULaZ2x95m\n2Vay/lOf657xd0exmkmj+dW2/Mi79rbv9qumtdJKsIXeNn+98r7lXdUOg6P+5aZ0jZF+42z5ttdh\npGnpax+TMjNFJtbdJ96pjg77DljOWPvGHH4bTy2eSH545fkbyvvf7LVch8PzCP8AfI3+q3bo/uq3\n92ui+xw7fJk+Z/NXymb+FauLovzO8KLv+b5mqo0OWJP1jmOUm026urhXm2od33pP7tUNY0na2+H5\nvMX733l3V111pHlxvNs2lZf4n3bv9qsfUrGGPZ5Ls+7czL/FVRwvu8wvrnvHA6xZ7Yc/ciZGV/4q\n5m8h8yH9xuG5NjMyf+PV3viCH92uxFXbubatcXqcbwhpHdjK33/3X3a1p4fsOpiOU4/WrfdIf3Ox\nF+VmZ/vf3a56+haPa7vuX5VdVrrNatd0zQ+Tvj2fPt+7urndQjdmSQ22759u7d/7LXTHA8sbKJhH\nES+Iy/ImZWfeyMzfer9B/wDgvLDLcfsZaRBEQN/j+0DZ9PsN9mvz+23P2j59p+T5o/7tfoH/AMF3\n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\njzM6I7ZV9u2tvw1I6zeTcuqqv3FZ/vVz6tBNJsT5dqbqvaTqD2rq77W2v/c3fLWNRe77pvzcp7T4\nHunjgV7yaNnV1+7/ABL/ALVe3/D+8doYXmdXdfn8xfm3V84+CtaSM/ZkmVWj/ib+LdXsXgLxAlvL\nbwvMxST5vlb5VWueXPLUmXwnr+m3j3Vx9mubbcPvfaFSttredk/1LOV+aJm/9mrj/DurabcbHhuW\n3LLsRt/+d1dHpOpQqwR7ba/mtukb5d1Yy5vdfKcXumjZbNx86T/f/wBmkjjkhmZ0myPuRR/w024u\nHmhVbb5fvfNVDUtbe1h8l5o2k27tv3VrT2kdwPinUr50ZrZHXaz/ADs38NItu99cGaZ22xrulZdr\nbmrDGpXNwvyXKlWf7v8AEzV0Hh23kUpcvD919z+W3mKrV+qxxXunyVPC+7c1dH0fc2Niuu1flauk\n0/w7Gqpcuke5V+7TNHsknmV158tPnkk+XdXT6bY7Yw72ylP+en/j1ctbHSlHSR2SwvwmcvhO2uNj\nx2zBI/m/4FS3HgtFy9ydu1/ljb7ys392u00fT5poRM+5hIu5G+7/AOO0TafbRloQVUfKit977v3t\n1cUswlGV+YxlhIxPO7zQ4Y40mJYmbcnzfeh/3qzL3SUa4H2PdGrfdZn3fw13+o6W7SNbQ+YE27lZ\nl+Vt1YmpaX9jy8Ntimsw9pvImOFlDY5ZXht7hEdFcL/e+8zUR3W3zHfzFT/ZSrd1ZzWsk2x/nml3\nIzf3azrya2kgPk/cVdrrt+9SliveNPqfcvWOtPp+N+7f919z/wANWbPxMlvI+ybcP7rVyVxcpb26\n2qbdsf8AdRvl/wB2oG1p1jSJ/k3fLuVK0ljubYyhhe53reLkmjdw67V2/LTG8XQWbEJub59rNv8A\n4q4Btc8qNn3su1PkZqzZPFm2NbnfJsmXcytVfXOcpYeUT0+bxl5cOyzvJvN+78zfe/2az7zxJbTM\nZkmZjJ/ra8yuPGybW/fMflb5V/i2/wANXrHxBc3EIeSeMMy/db+Kn9YiqVmKWHnGXunbLqUMzNM9\nzJtVfm+b7y1HPqPzD52fzE27Vf7tctY6w6rvtpmbzNyMrJ/6DWjb3KbldPLYb1X5flZm2/xVEsZy\nx5UXHDXleZo7nkjTzvM/uszfN5dI2+RmTezbU+X5f4qhs2hk23KTf3kb5/lqyykSI/y7Y4tu5fu1\nnUxnKdEcPKRUuI4XbeifL8v3m3fNX2n/AMF5lU/sLGR4ywj8VQtgH/pyvK+Mb6PzI0gh+ZmRv3i/\ndr7X/wCC6Nobv9h2RSoKx+JYpHXuQLO8PHvX4B4sYj23iPwlrtUxH5UTxcfQVPN8H5yl+h+EmrR+\ndYr8zNuRWRWX/ZrlriF7W43p/ertdaX7HpsU3mNtZfl3f7tcNqFx50pP8W6v1b3T7KPxBDqk0Lq6\nzN8tdL4f+I+v6fMjw6lJuX7jbq5BULNtq1p9u7NsfcB/eqSuWB6hZ/FzxXNEIbnUmmi2N+7uF8zb\n/wB9UXHibR9QZ/7Y0GxuVaL5NsW3/wBBrhPOmjVkR+Vq1b3T/Kyc7v7v8NVGXLIylsb8mk+Br799\nbaJNb7U3fu5/u1dhuLaSza1h3Ou3b8yfNWJazO4+5tVvmbbWnpczrPvnmbC/3Vq4ilL+Uh1zwreX\nUMWxFaPZ91l+81cfq3gzVdPlO22k2r/d+bbXrWrLba5ouz5kfb8jK+1lrzvVtS8SeHZpLWab93/e\nX+L/AHqn4RxlPmOUKzW7fPwy0+4uvPGyZPmXvW1/wk1hcnZqWlRt/tL96s7WmsAwa2Tll/h/ho5o\nm3xFCiiioLG+X70qrtpaKr4QCiiinHYAooopgFFFFABRRRQAUUUUuVAKq7u9b2mTTW+kl027awVO\nG+f5q6CyjkQRpDtxtXg0SiY1T6L/AOCd+nzab4s1Px4kK/aY7P7LYXDfehkZtzN/3ytf1DfDj40w\n/HH9nfwr8R9D1hZbbVvCtvFcQ+V80c0caxyf+PV/OP4F+Gt/+zvp/hvwTqr7dQvNIh1a/haLa0P2\nhdyr/wB87a/Zf/gh/wDFKHx/8G/F/wAHbzVVkuPC91b6ja2rfNttZv8AWMrf738NdGHlyzPnsVUl\nUlofVkd8/g3ULLR7+88ma+sGngk3/wCsaP8Au14t408D6b40+K0HiiHw9CHjWQSyW8S+a0n96u2/\nbAvNS0fxH4O1vSraR4rWWaB5FX7qyLXEfFr4veDP2cfAL+PPHPiqPS7toma1t1TdPeSbflWFf71d\ntSpCj7xx04zlofDHxdv7Lwt+17Lqt9OsVvp3iKwmnd8ARoghZs9hgA/lXmv7WH7XnjD42XVz4b8E\n3rWuhb2+1XH3ZLj5W/1f91aj+I3j4/E/VNY+IN1p8lsNTaaZoJm+dRgj5j6kDJ+teHePPG1hpeiz\n+RtlZlkbaq/N8qt8zVXFmKlHD4Jxejpp/gj9L4zjJ5flK/6h4flE+MfCljNeeINYuXDFW1eb+P73\nzV2Nu3kr5PzfL/DXG/DeN76zmmmfa81/I+5v9pmrs/JTcmE3Oq/Jz8q/71eRS+A+XfUfNC8kO/Yu\nJPl+ao22L8jwq4+7/u1NcHdD8n/AttUmj27/ADkZlb7u2r+ID1/4A+KPDfgrw34h8Q+IYY5biP7O\nulqzfN5m7c22uM+JXjK88Xaxc+IdSufLT5nePd8qrVDQJENiyPt2L/d/9mrzD4+/Eh7iY+EtKmUL\n/wAvTR/+g14lajKti7HPHD+2q/3Q+HXjR/Ff7TfgVbZ/9Fh8Z6WsQ/vf6XF81e5/8Fbv+af/APcW\n/wDbOvmf9nP/AJOE8Cf9jnpf/pXFX0x/wVu/5p//ANxb/wBs6+6y6EYcMYpR7x/NH6TlUIx4Kxyj\n/NT/APSonxrQW280UjLur5o+OFoooquYAoopPn9qoBaKKKXKgCgNu5pU+8KNqKo2fepRAaowMVoe\nHr99PvPtMfXbtqhWx4I8O3vibxDbaHpsavcXUqxQKzbRuZttPm5feIqe9Cxqza5e6lqiXM0zZ3L9\n771faHwzsPgV46+F/wAN9V/a0h8eXPgnwK9w32Xw7qKt/osknmSwxrJ91pG/iWvmzU/glp3w/wDi\n1/wrXxp8TvD8N3byxrPeafdfa4I5G+bbuX7391q9G/as+KfivX/CGlfs+eGvCOhwXWl2qyXl14fu\nd32i3+6q7f738VZ168ZWgt2ctFa3Z6f/AMFPNT/Zm/aA+COi/Hv9nj4kaD4L8I6JeLpPgP4HWcvm\n3VlZ/wDLS6uWRv8Aj6kb94zN/srur4El37uKdqFleabePYX9s0M0b7ZY5F2srU1mTjfTjGUTtGsN\nslDO7Sb0FIxy3FSW6/Mc/wANBHwmv4R0/wDtLxJpump8pur+3i/76kVa/pe8TrDa2trpriZkh0iz\niWP+H5beNa/nO/Zt8O3Pib48+CPDyQ+c+oeL9NiSFfvf8fC/dr+ibx1ffY/EF5bb9zLKyIzfN8q/\nKtcuIfwxOat0OUurxJrhoXtmTy/7zbVrndUaaNmRPl3bm+at3UGkkaV7lI1XbtZV+ZqwdabzF3vu\nJZfkk+61c0vdiXH4zj/Elv8AarcI5VFXaz7vm2tXDeIlmXels7f7e77tei64sK7/ADhGEjRfN3fe\n/wCBVwPiJbnz3tkTzPnbf/dZa5KnNOR30YnD6pI9qyJMjJ5nzt8lU5LqY75NnKv8y/eq9rDbt1tC\nkjpub5V+b/gPzVlwrNuWaFG3b9sqt96ueUZndGRYt5po2810aXzP4f7tWbO4haNndJNiy7dy/wDo\nNVI/J8tbl7aSOTzdqbafCsPzWybs72leP+83+zUx/vGko80S0t+8Z2JNI7K/yr/d3V9qf8E4rprr\n4KawXzuTxdOr59fstr/jXw2skizPsRmDMqtu/hX/AHq+3f8AgmlJ5nwK1ckgkeLrgHByP+Pa1r8d\n8cp83ANT/r5T/NnxvGitkcl/eifztanqjtNv8vb/ALNUobt4d0yPs/hq/wCJtHezv7mzmkbdDcMv\nzfL/ABVSntUhX50wrfMlf0TD4D05Ei6xNGvzzNVSTWJpuHfP+y1U5i+FTvu+SmSD59p5/vf7NXy+\n4TdGva65DGqo+4f7VakfiLTWh++v3vk/2q5La7Ns+6v8NPj3quz/ANkqfsjOnbULBtu9F3L/ABLT\nJNUhZdiIqfxLtrCt/lH3/mq1G3mTq7u1VKXYzJ5tSZF379xqrdahcybpN7YX7u2pJI/MV3d/l37V\nqxa6dbM4+2PsFL+6VHYj8L+MtY0G6FzajKr96uv03x54eluC82jyb5H+ZpHqro+jeG5bf5If3q/f\n+f71TXGm6P8AadlnC3+20lVy/wAocyPVvCmheFfGHh954UaJvKZZY22/53V4f8SPCb+DdakhTlGb\n901evfC1ptN0e4meHai/w/3q5f42aXJr+lNrITPl/cZacveMvfU7ni13M9xMXemfw/8As1En3x/v\n0lB19AooooNAC7eKKKTb8uKAHKvzffo2/NnZSUsaiQ7KCeZkpbcB/s1JHHuZecNUaoZJGf8Au1Zt\nVRmXf0/jp8xJraLbZbztilVb5a0/El4ljoroX+aT/bqHS7NF2/Jv/irJ8aXyTXQsYX+WP7y1PMjJ\nR5pmHSxrlhx8tJU+m232q7RP9qjmR0nW6DYi30XZ18z5ty0ySHf9xN9WrGZGZbN38pF+X/7KnTQv\nuZUfC/wN/epROaWxTmt3+yKj7fmf+KktZPs8jHe391PnqSb/AJ47/u/xVC2+T9zDJz/H8n3afLza\nC942LeTzIQ/3m/36WSNPMTyf9ZWbYXzw/u3f5v462I7q2k2I8K/c3J8lP7BPOVFh8ufzs4XfVuFo\ndx/xpJo/lbYmVZabYq8cjSb/APx2lHYf+EljXav3Nu6rOl332VtnnbBv3VE8KcTb2G6iS1Rto2ZZ\nfm+aj4oC5rHRrcJdW/7l1Ur/ABNWVq0P2eRvn83d81WNHuI2jCfcZvvLRq0Zb50+9sq4kW6HIeJG\nLW0vz/M38LV9n/8ABMXXv+FhfBX4i/Bn+0mj1CGwj1vQ1X/npD/rNv8AwGvjDWm8yGdJodrfwV61\n/wAEzvjlZ/Br9qjwzqevOp06+uJNN1SOR9qfZ5l27m/2VaqpSlGfMKtT5qVon1lJ408Q3WsaDc+K\noWto4Ym2XElr80391v8Adr0bRbO21T4YeNvAeq6l9sfVrNrywVn8tYZl+bzF/wBr5a/RUfshfs3/\nALc/7K+hWGm2Wn6Z4r8P2Fxb2GsWlvsi+X7u7/e+WvgbTPhX48/Zd+Mln4S+J1tHaf8AEy+z281w\n25ZI/utJ81fS47BxrYaNen/29E+fw2IqU6vsZ79D3f8A4Is3Buf2XvEMhct/xcG6AYjGf9BsK/Im\n81JIWCO/3vu/7NftT/wTk8B/8K38J/EvwpA5a1i+K97Jp7lAu6B9P090OB7Gvw4l1SEsN+5j/dr+\nbPDT3fEjir/r7Q/KqcuVJvMcWvOP6mrJqUMe6HDOrfxLVmx1BMq6bt7fw7q5qTUnaT9y6/e+Valt\ndYeGR385vv8A937tfuMZH0EoSXuo72HUodzlLZl/uRrX2n/wRQuhc/tV+ICrn/knt18p/wCv6xr4\nBsdeMcaIkzfM38P3q+5f+CFV6Ln9rLxGu/cT8O7ssf8At/sK/O/Fr/k2+Z/9en+aPKzaFssqvyMj\n/gp3Io/bl8cxmVgdumk7Rn5f7MtPlrwiO7t7hQjp8zbV8z+LdXr3/BU3Uvs37fHjxVkUbDpeQV/6\nhVpXhC6mk2/zvlEfzOv8NetwBpwHlX/YNQ/9NQKwEL4Kj/hj+SOkjvEVQiPG211bbUp1B45N/nb2\nV/u1zlvfQqyJ5iqsf3V2f+PVZOqI1uZ5kVU2/IzNtb/dr6/mnGJ2Rp+6aGoX3nL51zMvyr91vvVz\nt1qiCYw/KNrbtqrVbUNY/d4+VX+7838P/Aqx7jWHa43pMu5vl3VnKR04OPLPU2G1LcpRE2Ju/i/i\no/tGH5pX27WdVRVX5t1Y8V15kiyb9x+98tPkk2q0fmf6z5lbf92uSXxHvU+Y2Li4SONf9J2D+8v/\nAKDSx3zxSfJ8m7+FWrMa6e3VNiK23arr97dU26Zm2JJHhdzO2yo5eU2lI7fwrrv2dvLe5Vw1emeC\n/FSQ2ohmufn2fKsn3tu6vB9L1Z44RND8m35v+BV1Gk+JkVVe52r8v+sX5vmqJR+1EyqSjyn074X8\nVbV+zedlGT/Vt91W/hrrtN8VFlxc3LSCNtyRq38P8VfN+h+OvJ/dzTbVZflbd81dlpfjf5kSGb7v\nzrI38VRKPc5JS949r/4TR4bMwQosifegXftZv9msfVvGTvHK/lrsb7/8X8P3a8+m8cPIw2XWW/vb\n9q1h6t8QPLiaa5mWJm+8vmtWUqfNEXNCJ5Ho+oeZJHvSNV/jj3fKtdr4ZkjjjJSONF3bWhj+Xd/t\nLXmmizWccbTTTfu9+35fvNur0Lwu32ZYn3/d+XdJ/F/vV9ZWxXL8JhTw8fhO58O/JCsIjVNyfdb7\n1ddoMiYZHTy2+7FHsritLjhnkExdZtv35N/8P92um0u5aGNJrr5UVtyfNubb/DXHLFSlqbSoxO10\neaZm/wBJm/u7JNu2rs1qjZuYQuybd5q7/wDx6szRbi2+yb4JmmaP5nX+GtKO3S82pMcFk3eWv3Vr\niqYocaRn6pZuqo+zeYUZtqvuVqwNXtnk+5bSK0m35f8AZrs1VPLSN3/e/MvkslY+sWbr5ttDNu3P\n+6j/APsq5vr0YyKjheaWh554mjSVmubban73ZuX5q5fUZptrQJ8p/vbK7nXLOGBXj85Wbezfd3Lu\nrldQtYPlmhdmlb5W+X5W3f7VV9el3CWF974TjtWvoYv+XZWeNNrSfMv/AAKuZm1h2kVPtLZXcrt9\n1a6bxJapHbtC7soX5drfxV5/rn+jXTp8zP8Ae2s/yr8tdVHGe0OepQlEs3XiKa3VHd/3qtt+X/0K\nsfUtcu4/3jzM3z/dqjNrk1vcfIi/c+fdWTretQyxs79VrqjiP5TCVHlNWz1SNrhnm3Ntdtv+zXTa\nHfR+Wjvu2feRZK8z03Uo/tG/zm+b5q7fwnqU/l+T52Xb7isn3ar2yD2fwnZWcyRsj37qqf3l/h3V\nr6e32fZD/rG+8vmf3awdPmn+0RPNMrrs3PtSt6wuvJbznfn+7s/irCVbll8RtGP8xsaX5KlU+88n\n3of9n+9VltkjM+xSrfeX+H/ZqnYrNcMzvtaLbu+X+Gr0bIsLTf8ALuv93727/drmljJfaNqdMjk8\niOLekOyX7zbd21f9mvt//gt5HHL+xS0MhI3+JIlU4yATZ3g5HcV8UTXDx2bOkLD5f4q+1v8Agt9c\nNafsSvdLbiQx+JYGyWxs/wBFuvmr8O8SK8qniLwu+1Sv+VI+ezulyZxgV5y/9tPwj+Kl9DZ29vYQ\no3yr83+9XAM38dbfj3WX1fWXmR8isvTtPmvrkRRoxr9wjE+kj7sbhY2/nygbe9b1vp7w2/B3M1bO\ng+BX+y75E2u1Q6+0OlwsiDJ3bavl5TPmjIxv33nMjupO/wC7WhpNqm754WrDuNURmOxG+Wki8TXl\nvIHR+KXwi9+R3lnojyf6naE+9u/i/wB2pI9Njt1i33Knb8zs38NcpY/EK/DeTO+1W++y1c1rTLnV\n4vPsdaDI23YgpylzClHlOuF5YSL9j/tKEj/rrUV9pMOuWv2aYK8ez5JF+avO5vDWuxMXhDOF/iV6\nm0xPHdsv+hw3RVfm2/w1MecqMY7lXxLoNxouovCfu7vlrKkZ87Grc1vWdSuBs1WxIdV/5aJ/FWHM\n7yNuakaxFopFbPBpav4ihv3/AGxSMu2nKu2hl3VAC0UUVcZAFFIrZ4NLRHYApeVNN53b91LUAAbd\nzRSKu2lrQAooooAfHHukXf0avW/2VvA2m/EX46eFvBmq7fsE2qRy37M/3YY28xv/AEGvKLH95IN/\nG2vev2WfDepWV5P4wsJZEmX91ayMn3W/i2/8BqZe77xx4qShE+sv2ttY/wCEm+M0/iq2mV7aZVit\n2V/uwrtVV/4Dtr7F/wCDf74jWfhL9q7WvDd5qvlL4i8HzQMsn7xZGjbctfn7pdrc3V5/aXiR8xwp\n92RPvN/er3f9gH9oCH9nv4+W3xatoVuIdJsrj/R5H2rM0ke1VrGnUtLnkeI5c5+wv7ZX7SnwZ+G/\nwz/4TDx7ryxLp9xG1rZx/wCtvJl/5ZrX5F/tFftQfEP9pLxxJ4w1hJokjdl021uLjdFZx/dXy1/3\nfvVmfH74jfEj9pD4gXvxF+KPxFjkVrpv7I8P2cXl21jD/Cq/3m/vNXmcmi6Pasz/ANvXU6MrblWX\n5V3f3a48Zjp1fQuMfZnqOlRFvhnLDe3ivmxuBJNG3GPnzg+39K8h8dah4S0DwXqjpNG5a1mbdGm5\nmby69T8L29lZ/Bt4IogIF0+7+QtnK5kJrw341eILXRfhnqt/ZwqhXS5otrL8vzLtr3eKFz4fLWv+\nfMfyR+gcX64PKV/1Dw/KJ86fDO3ePw7BN5PMm5tzf71dTJvhzsT5fvfN/FXP+B/9B8M2cKQ/6yJd\nm1q2lmeWP998p/utXPCOh8pU+ImjjS3jaZJmK7F2rVSS48kF5Plb723+GoLrXLaPMP2nZtfbtasa\n+8RIvyQ7Sn96l9rQXLGRqeIviU/g3wfdJbJH9ouG/dTfxL/u14TeXc1/dSXly7O8jbnZq6D4iatL\nfXsMH2reiqx2BuFaubqY04xlKR2UafLE7L9nP/k4TwJ/2Oel/wDpXFX0x/wVu/5p/wD9xb/2zr5n\n/Zz/AOThPAn/AGOel/8ApXFX0x/wVu/5p/8A9xb/ANs6+nwX/JNYr/FH80fcZZ/yReP/AMUP/Son\nxrRRRXyx8WFFFFACMMjiloorQBFXbS0UFd3FT9oAooZfmye1FPlQCt+7au1+BWr6bo/jb7Zf7d/2\nC4W1Zv8AlnN5fytXE0b3Vg6Nyv8AdqZRJ5UbUWnzLdPc3k2597M0m/7zf3quW8F42rrq763J5i7d\nszP8/wD31WENVuQhTPBqM31y38bCr9zlMOSrzXub3xDvbLVtcTUbYbpZrZWum37t0n96sBd67t9G\n4NIzvTJF+bmp5TeO4L8nCPU0bKmE6bv71RbTu+SrEMM0mfumpJaufS3/AASn8K/8Jh+338LdKmto\n5IYfEa3T+Z/0xjaT/wBlr9w/Fd1CLyWZ33edcMySL/eavyN/4IS+CpNY/besfEkyRvD4b8L6hes0\nn/LNmj8uP/gXzV+sd9Ntt/kfeJPvKz/xf71ediJe8Yv3nymRdN+7d/m+V/7n3qyNSie4ZY3s22sv\n975lrS1BrZbqSGO8Zwvzbf8A2VarXiw3UaTfbP3f/LKNflaSubm6s6oR945XVrVxG6PbZf8A5a7n\n+Vv96uS1LSUhYiZ23yP8vlv81d/qcJaRke2XLbvNb+Jq5i8sZppJSzyJMqfJtiX5f9ms5e9E6qcT\nzTVNHcRo6Iqtt2urL92sSTT3jZ7Peqn7zbl/75r0DUrFBueZY5TMrK23+GsO6tLZQ1s88hRtvzNV\n/YOnlOVW3uo4/J2fMsv72T+FarFZlZJ98ed27zFb5q3NUtUWHfbQt838O/5WrNuP3yt9p3IJNv3f\nm2tXLKjKUtS170feM2SZJVdEdkZpd25futt/hr7f/wCCZgI+BOsKUxjxfPz6/wCi2vPvXxFJHtaV\n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\n/wDj1ee+KPDbrumRFLLuVGb+7/dr6/C+9HU+IxUZc/wnlEmkzRzNC8K7q7b4f2sMl8qXj+X8mxd3\n+7UMmiwrOHdF37v4m+7XReDdLmWbf23rsWvYj7sDx6z7HZeHdN8ny2fyxt+VW/vV2vh2ztmsykaS\nHc+3dIn3lrH8Pwu0kcMI+dvu12Wh6a8d0zuikyLu/wB2uWQR93QrWenwiZtj7hJu31YhhSOGaG2f\nzZm2qjM+1dtaVxZu0zwvCuz7u5fu1FYWsNvumvF2Q/eaRk3bdtcdWnGWjOynLljzEniKzfwn4Tl8\nc3KKyw/urfcv3pP92voz/g4GRW/Ym0VpIDIq/EaxZlAzkfYr6vk/9qTVnb+xPDsbzfZPs/n+WrbV\nk+X5Wr63/wCC+8dxL+xHpyWgJk/4Tu12BRk5+w31fi3iDCMPEPhZf9Pa/wCVI+Yzip7TOMF25pf+\n2n45+JviFNofhs2ulPs3Lt2x15DeWuta3e/aphJI0jfxV1Ta9pv2iKHU+V3L5qt/6DXsfwu8ffs0\n6PCH8VeFbi8l8raixsq7f92v3OPKpXkfSS9rH4D5/wBN+HPiHULhE+xvhm27tlddL8ONF+H1n9v8\neSeTNs/0ezX5pJG/vN/dr174hftIfD3SbO4sPg98PbW2m8rbb3l187r/ALq/3q+bvFF14h8QatLq\nus3M000j7mkmatfaR2gKn7WWtQl1zxN/bV4ttDttrb+COH7tQMqbWS2/76rJWN9x+RhRHJcq2yN2\nqNfiNuX+UvJZlW+d1ct/eqwtvDCux32t96qEM0zN8/y7fldqvW7PMy/e2/3m/iqjOXulu3td0Y8z\nrXcfDXQ4Lq4abZ86xMyLt/irkbE2y/O78t/DXf8Age6/s2MO/wAiM3zs1KK5SeX2m4y88P21jm81\nKZlTzd27dXDazrU2u6t9gs5pPJjf5F/hWuh+JniIaxeyab4c3GST7+1/lVawrfwvqXhvw9N4hubZ\ni4X5G/u0x/DI5vxQ0J1hvI/hVQ/+9WbvX1p80jyuzzNlmfczVEy7aDoQ+iims2G49KBjqKKKXxAI\nq45NLRRR8QBRRRRyoBFXbS0qru5TpQy7TimAY249f4qlt4/3io/FRLwu+rOnIJJgnks5Zv4aXMiJ\nS5UftF/waW6JeeHfi18RfGGzamqeDZrJmZFZfLh2yfe/vbmr76+OUk2jeLnvHdvKml2QMqbVVq+P\n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\nf4dvzbf9mp4ftKr5zn5G/iV/vf71MwqR5veIpLXzJPkTcu7+L5adHbw/Nbfd/ubamkj8lmd02bfv\nfxUNb7pN6Ozf3G2bflropy+yeNiqc+a5VlRVjXcfl3Ns3VRvFRYWfYvzVpXSo2zzNrfN91X/AIqo\nXkKW8n7vbtk/hrXm933TljH3vePN45Nred5zbmf5Vq1Z3HmRs8yMPLXbu3/erN+0TSSI/ULVu1k3\nR/I7Lt/iavLj8J7cDZs7942CbF2qv8Lfd/3qvWd55LLMkzbv7yvWBZ3T+c1s6f6xd1aNo23CQx8f\nd2/xUvscpvTlzHYaT4keT5EmkLL92u28O6lqBVdki4k+Xa38Neb+H1fzn8yHd/wPbXa+G7ry23wX\nMaOrr95a8rGR/lPoMD71rno3h26m8zZNcsu1NsX93dXceHYnvJC/2zfKq7XXZuVq880O6RVHlou5\npV+0SSJub/gNeh+FJk/dI+5X3fJ5a181iKfLGXMfWYOXwo7HT4XkjR5uFZfkVU+XdWgsKJIsOxlP\n3k/2VqLw7bvHHF5w+Zfm2/3q6GOGZfnyrq3zeWv8NebDmjOx63LHl5jm76xSCJZrZFWRd37yR6wN\nQt/LtxNeW375nZlZW3fxV2OqadCzN/Au3d9zdtrH1i1hWEQ/ZlLqv3lX7y17WF/d7Hh5gubWxwmt\nW+63mTYvms+373ytXE+ItDtpoWTyVTzPu7fm216X4m0lLWTZND87fws23y65q+sYVt3hto2Mrfc/\nir6vCSjy8yPh8dHml7x5bfeH0SYPMm1N+7c33WWtrSdJTzNnkqWb5kb+Hb/DWvcaCk0m+aHYirtl\nVvu1Y0zT0hiDwoodv4v4dte7CXNC0j5TEaVbo3PD+lsix3LosW7/AMd/2q63TbObc3yW+9UVd275\nmrnNLaGHykdN275d0f8A7NXR6TIlwwS2dm3f+Pf7tYy/uii+UsrGLxTNlkRfllVfl27a5LxX4403\nWLi503RppGgsdqyxxy/6xv4v+BUfFv4jQeA/D8xs7mE39xEyRQr/AMs/l+9XnfwjM0Oj/wBq3nmF\ntUlZ4mb5d395qwlz850VJe6dd8ep31jwn4O8cwzMdP1rTt8X2hdzRsu5dv8As7dtfav/AAXekRP2\nP9BVxkN8RLQD/wAAL8/0r4K8Xak958F7/wADanqTNc+DdWmn07d/y0t5Pm2r/s195f8ABeJ4o/2Q\n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\n8k+827+8q197XEk0cJmMDf7v92vgc9xcqmM5Pso/QOHMv9nhPbS+0Zd5dFf9GmdX3S7E3N826s+4\nuHjLQ2ybv4n3fdq1fTPCsyJCwT5WfcnzbqqTL5jOmyOXdt/3vu/drxvby5/7p6lbCxqcyZPZw/MP\n9Tv/APQastH9li/f7RG3937y1nxslvMieS33dztv/iq4l1ugX7TDtT7zru+7XbTx/tDyamB5djPv\nvlaO58jcGfbtZvmZa5y8jtlhUuV3+a3y7/vbm+7urqdcuraSMzTP/HtXb/DXK6tdQq0mLzlfuLs/\n8er3sDiO54uOwzjuV7qSH7Pv6tG/yqv8P+zVZtReONv9Zuk+/UF5qVszF3diknzI38LLWHfaw8dx\n5KO2N+1vl+Va9unUj/MeBUjOJfvtWCyeT5zI+z/nr81YmratuJhCKr7t3+t3K1ZM18/nN9p+XdLt\n2r93bWXfX3l3bJ9pX/pkrf8AxVavYx5i1qF4dvmWyLG7L+92/Nur7d/4Je3C3P7P+rMu75fF9wp3\nHP8Ay62lfAc2sBtqXKbGbd8q/K+6vvL/AIJUTrP+z5rZRSAnjW5QEnOcWlmM1+J+P0Irw9m1/wA/\nKf5s+c4snfJmv7yPg+4vkhkEYGVVWZ/9lqoX11cx6bcu6ea/lf8AAv8AeamR3kNxMZn+VZNzbV+7\nHWX4svEs9Dub9LnY7Iy/K+35f7tfr06cef4T7CnW5YHy9+0V4sTRZpYV/wBdcKyozf8ALP8A3a8Y\n1SP7VHHc787k3bq3v2hPFH9ueMpIYV2xRt8nz1zml3D3Gm+S/wDDXr83LCNjhl73vFKNfKYps/jo\nkjG7e74q3JabUfYjMf49v8NQyL91Nmf9qtPc+Ikgb93j+KlhkdpN/nfL/dqCSR1U9/nqJpHVagqM\neY19Njea6XZNw38NbE2lu/8Aq0rntLvPs8yu74rqtL1y2lt/L+6f71V9ozlsZtxoT/O6I3/Aqrf2\nbeQuudu//ZrpPMT5f4v9mpo7e2Zf9R8y0+VBzGFpuqaxZ7U85lZX+Sum0fxtqsPyTBgWf52b5qzm\nghZd+xflf7rU5ZfJ+5D977lHLKIpSO90vULPWI/Jum8p5F2vIvytXSaVZa3bSRxWd+0oZNv3/l/4\nFXl+n/afOT+997czV634D1j+x9DfVdV+5t+Vf/ZaPhgTLl5uY8//AGlfC1zNpFtrY2sYfll2t93/\n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\nD5bP83ypudY/vbv71c3q1zi387exLbvmb+JlqTUvECTRvbIilpE+9G1YF9rkMjb03NJt/if5a9Wn\nzS5TyKnITX2qPNHHNDtbbF97+Ja/Qf8A4JKPv/Zx1rE/mY8a3PzZz/y52dfm0upQyfcdt3+y/wAt\nfoz/AMEe5PM/Zn1w7GXHjq6+93/0Oy5r8b+kCreHVT/r5T/Nny3FTvlTfmj89re58zZ9mm3LNK3y\n/wB2uW+LOqTQ+Gbn7G+3dFt/3a0obw28Z+8pbds2/wDoVeffFLxVDbtJps213mTd5bf7tftHLLmP\npoylI+UfHSvJrlxcv99pW+ZqoaNefZpmL/datTxtvk1iV3+4z7q59ZTFOrJ8wV91dEY+7ymkTp/J\nkjV38nG7+9WVfSPHhH3Y/wBmtCG8S6sU3zfe/u1mXnzbnR2Lf3ar+6Ry++U5Gy3u1RyY/g+7Ukkj\nswTYtRbTu+SpNIg29pPMd8GrFrqE0Lb/ADm2/wB2omhmYb/vUpt3X5O/+1Vf4gNyw8UOijem4f7V\nben+I3kZoU2ruriI43b5NjVdtfNjZZtjf7tLm5SZHZeZ9obfsVW+7tqeytd2Zsq/+zWPo94nkL87\nH/erb0+8QN5KJ97+Ja15uaJiafh3T/t1x9m2bPnVV3f3a6/4gf2lHpNtoltayBIYt0rf+g1zfhO7\nhj1KFLnanzbXZv8Aer1S+bTW0dtVSH7YWiVWVnp8xHNHnPCNem+z2svyYTZ8y7a84mYtMX2Y3V7n\n4/j8N6tapbQ2EltIy7vL+9Xj3iLw/NpVxvSFvKb5qj4fiNqcrmVSqz7tlJToVQSLv3UHSa/h218x\n/kHP8VWvGEwjjhs0udyL822p/DFskamZ3XGzd92sPXL57y/d96srP95aX2zHl5plMnzGrR0+aeO3\nOx/mrPjH7zD1s6SsKxsNn/AmqAkXtLvHe1MLvvdqbqU1zb7tnziordU8w+S/zLUupfvpxCjtv2f8\nBoI+H3kV9P1a5uG8n7v8PzVfurxLeNn2bf4dy1Hb2MNrGZKjvmSSEwvyfvfLWgub3x1vqW6RXeZc\nN/DWxYpuhlmhdii1ztvp73TLhPu11WgzPZ27o6KEZPmVaA+IzZL77L7q33qI7hJ1Pl7R/ElWtUsb\nZm3pG23ft+7VKPS3jmZN+0M+1Kr4hfEMXWE8zy3fO3+9WjDveH7T03fcrMt9JRm2fKSv3/7taMdw\n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\n", - "text/plain": [ - "" + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" ] - }, - "execution_count": 26, - "metadata": { - "image/jpeg": { - "width": 600 - }, - "tags": [] - }, - "output_type": "execute_result" - } - ], - "source": [ - "!python3 detect.py\n", - "Image(filename='output/zidane.jpg', width=600)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "ijTFlKcp6JVy" - }, - "source": [ - "Run `train.py` to train YOLOv3-SPP starting from a darknet53 backbone:" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "colab": {}, - "colab_type": "code", - "id": "Mupsoa0lzSPo" - }, - "outputs": [], - "source": [ - "!python3 train.py --data data/coco_64img.data --img-size 320 --epochs 3 --nosave" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "0eq1SMWl6Sfn" - }, - "source": [ - "Run `test.py` to evaluate the performance of a trained darknet or PyTorch model:" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 1000 - }, - "colab_type": "code", - "id": "0v0RFtO-WG9o", - "outputId": "6791f795-cb10-4da3-932f-c4ac47574601" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Namespace(batch_size=16, cfg='cfg/yolov3-spp.cfg', conf_thres=0.001, data='data/coco.data', img_size=416, iou_thres=0.5, nms_thres=0.5, save_json=True, weights='weights/yolov3-spp.weights')\n", - "Using CUDA device0 _CudaDeviceProperties(name='Tesla K80', total_memory=11441MB)\n", - "\n", - "Downloading https://pjreddie.com/media/files/yolov3-spp.weights\n", - " % Total % Received % Xferd Average Speed Time Time Time Current\n", - " Dload Upload Total Spent Left Speed\n", - "100 240M 100 240M 0 0 17.9M 0 0:00:13 0:00:13 --:--:-- 20.3M\n", - " Class Images Targets P R mAP F1: 100% 313/313 [11:14<00:00, 3.02s/it]\n", - " all 5e+03 3.58e+04 0.107 0.749 0.557 0.182\n", - " person 5e+03 1.09e+04 0.138 0.846 0.723 0.238\n", - " bicycle 5e+03 316 0.0663 0.696 0.474 0.121\n", - " car 5e+03 1.67e+03 0.0682 0.781 0.586 0.125\n", - " motorcycle 5e+03 391 0.149 0.785 0.657 0.25\n", - " airplane 5e+03 131 0.17 0.931 0.853 0.287\n", - " bus 5e+03 261 0.177 0.824 0.778 0.291\n", - " train 5e+03 212 0.18 0.892 0.832 0.3\n", - " truck 5e+03 352 0.106 0.656 0.497 0.183\n", - " boat 5e+03 475 0.0851 0.724 0.483 0.152\n", - " traffic light 5e+03 516 0.0448 0.723 0.485 0.0844\n", - " fire hydrant 5e+03 83 0.183 0.904 0.861 0.304\n", - " stop sign 5e+03 84 0.0838 0.881 0.791 0.153\n", - " parking meter 5e+03 59 0.066 0.627 0.508 0.119\n", - " bench 5e+03 473 0.0329 0.609 0.338 0.0625\n", - " bird 5e+03 469 0.0836 0.623 0.47 0.147\n", - " cat 5e+03 195 0.275 0.821 0.735 0.412\n", - " dog 5e+03 223 0.219 0.834 0.771 0.347\n", - " horse 5e+03 305 0.149 0.872 0.806 0.254\n", - " sheep 5e+03 321 0.199 0.822 0.693 0.321\n", - " cow 5e+03 384 0.155 0.753 0.65 0.258\n", - " elephant 5e+03 284 0.219 0.933 0.897 0.354\n", - " bear 5e+03 53 0.414 0.868 0.837 0.561\n", - " zebra 5e+03 277 0.205 0.884 0.831 0.333\n", - " giraffe 5e+03 170 0.202 0.929 0.882 0.331\n", - " backpack 5e+03 384 0.0457 0.63 0.333 0.0853\n", - " umbrella 5e+03 392 0.0874 0.819 0.596 0.158\n", - " handbag 5e+03 483 0.0244 0.592 0.214 0.0468\n", - " tie 5e+03 297 0.0611 0.727 0.492 0.113\n", - " suitcase 5e+03 310 0.13 0.803 0.56 0.223\n", - " frisbee 5e+03 109 0.134 0.862 0.778 0.232\n", - " skis 5e+03 282 0.0624 0.695 0.406 0.114\n", - " snowboard 5e+03 92 0.0958 0.717 0.504 0.169\n", - " sports ball 5e+03 236 0.0715 0.716 0.622 0.13\n", - " kite 5e+03 399 0.142 0.744 0.533 0.238\n", - " baseball bat 5e+03 125 0.0807 0.712 0.576 0.145\n", - " baseball glove 5e+03 139 0.0606 0.655 0.482 0.111\n", - " skateboard 5e+03 218 0.0926 0.794 0.684 0.166\n", - " surfboard 5e+03 266 0.0806 0.789 0.606 0.146\n", - " tennis racket 5e+03 183 0.106 0.836 0.734 0.188\n", - " bottle 5e+03 966 0.0653 0.712 0.441 0.12\n", - " wine glass 5e+03 366 0.0912 0.667 0.49 0.161\n", - " cup 5e+03 897 0.0707 0.708 0.486 0.128\n", - " fork 5e+03 234 0.0521 0.594 0.404 0.0958\n", - " knife 5e+03 291 0.0375 0.526 0.266 0.0701\n", - " spoon 5e+03 253 0.0309 0.553 0.22 0.0585\n", - " bowl 5e+03 620 0.0754 0.763 0.492 0.137\n", - " banana 5e+03 371 0.0922 0.69 0.368 0.163\n", - " apple 5e+03 158 0.0492 0.639 0.227 0.0914\n", - " sandwich 5e+03 160 0.104 0.662 0.454 0.179\n", - " orange 5e+03 189 0.052 0.598 0.265 0.0958\n", - " broccoli 5e+03 332 0.0898 0.774 0.373 0.161\n", - " carrot 5e+03 346 0.0534 0.659 0.272 0.0989\n", - " hot dog 5e+03 164 0.121 0.604 0.484 0.201\n", - " pizza 5e+03 224 0.109 0.804 0.637 0.192\n", - " donut 5e+03 237 0.149 0.755 0.594 0.249\n", - " cake 5e+03 241 0.0964 0.643 0.495 0.168\n", - " chair 5e+03 1.62e+03 0.0597 0.712 0.424 0.11\n", - " couch 5e+03 236 0.125 0.767 0.567 0.214\n", - " potted plant 5e+03 431 0.0531 0.791 0.473 0.0996\n", - " bed 5e+03 195 0.185 0.826 0.725 0.302\n", - " dining table 5e+03 634 0.062 0.801 0.502 0.115\n", - " toilet 5e+03 179 0.209 0.95 0.835 0.342\n", - " tv 5e+03 257 0.115 0.922 0.773 0.204\n", - " laptop 5e+03 237 0.172 0.814 0.714 0.284\n", - " mouse 5e+03 95 0.0716 0.853 0.696 0.132\n", - " remote 5e+03 241 0.058 0.772 0.506 0.108\n", - " keyboard 5e+03 117 0.0813 0.897 0.7 0.149\n", - " cell phone 5e+03 291 0.0381 0.646 0.396 0.072\n", - " microwave 5e+03 88 0.155 0.841 0.727 0.262\n", - " oven 5e+03 142 0.073 0.824 0.556 0.134\n", - " toaster 5e+03 11 0.121 0.636 0.212 0.203\n", - " sink 5e+03 211 0.0581 0.848 0.579 0.109\n", - " refrigerator 5e+03 107 0.0827 0.897 0.755 0.151\n", - " book 5e+03 1.08e+03 0.0519 0.564 0.166 0.0951\n", - " clock 5e+03 292 0.083 0.818 0.731 0.151\n", - " vase 5e+03 353 0.0817 0.745 0.522 0.147\n", - " scissors 5e+03 56 0.0494 0.625 0.427 0.0915\n", - " teddy bear 5e+03 245 0.14 0.816 0.635 0.24\n", - " hair drier 5e+03 11 0.0714 0.273 0.106 0.113\n", - " toothbrush 5e+03 77 0.043 0.61 0.305 0.0803\n", - "loading annotations into memory...\n", - "Done (t=5.40s)\n", - "creating index...\n", - "index created!\n", - "Loading and preparing results...\n", - "DONE (t=2.65s)\n", - "creating index...\n", - "index created!\n", - "Running per image evaluation...\n", - "Evaluate annotation type *bbox*\n", - "DONE (t=58.87s).\n", - "Accumulating evaluation results...\n", - "DONE (t=7.76s).\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.337\n", - " Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.568\n", - " Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.350\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.152\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.359\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.496\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.279\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.432\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.460\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.257\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.494\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.623\n" - ] - } - ], - "source": [ - "!python3 test.py --data data/coco.data --save-json --img-size 416 # 0.565 mAP" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "VUOiNLtMP5aG" - }, - "source": [ - "Reproduce tutorial training runs and plot training results:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 417 - }, - "colab_type": "code", - "id": "LA9qqd_NCEyB", - "outputId": "1521c334-92ef-4f9f-bb8a-916ad5e2d9c2" - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAACvAAAAV4CAYAAAB8IQgEAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAewgAAHsIBbtB1PgAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzs3Xd0FNX///HXbkhCIKEHCIQaEkBB\naujVCnwoKiCiHwS/KoqoYPmpoAgKImBDlA+IIHxEsYEFRawE6VUIQSD0HkIIJRASQpL5/cFhPrsh\nuztpm0Sej3P2nLm7d+7cnXCY98687702wzAMAQAAAAAAAAAAAAAAAAAAAPAKe2F3AAAAAAAAAAAA\nAAAAAAAAALiekMALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAA\nAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAA\nAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAA\nAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAA\nAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcAL\nAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJ\nvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAX\nkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAA\neBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAA\nAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAA\nAAAAeBEJvAAAAAAAAAAAAAAAAAAAAIAXkcALAAAAAAAAAAAAAAAAAAAAeBEJvAAK3fnz57Vs2TIt\n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\nde3aVWfOnDHfq1+/vvr166fatWvr3LlzWrZsmX7++WdlZmYqMzNTzz//vHx9fTVy5EhLx4iPj1fv\n3r114sQJlSlTRnfddZeaN2+u0qVL68CBA/rss8908OBBSVeW9x42bJi+/fbba9oJCwsztw8dOqT0\n9HRJUuXKlRUUFORUNzQ0NKenwjRz5ky99tprZtlut6tbt266+eabVbZsWe3fv19ffvml9u/frxkz\nZqhChQqW27506ZJuv/12rV692nyvUqVK6tOnj5o0aaLSpUvr8OHD+uabbxQTEyNJ+v3333X33Xdr\n6dKllpaFunjxovr06aPdu3erZMmS6t27t9q0aaOyZcvq2LFj+uqrr7R9+3ZJUkJCgh544AGtX7/e\n7bLfsbGx6tixoxISEsz3ypcvr549e6pJkyaqUKGCkpKStGvXLi1fvly7du1y28fExER16NBBsbGx\n5nuhoaG688471aBBA/n7+2vv3r36+uuvtX//fknS/PnzFRAQoA8//NDjOQAAOPNmbJEbN9xwg9q2\nbauGDRuqfPnySktL0/79+7VkyRLt2LFDknTmzBn16dNH27ZtU82aNbNt5+LFi7rrrruc4ppOnTqp\nS5cuCg0Nla+vr5KSkrR3715t3LhRGzZsUGZmZoG3ZUXt2rVVosSV28THjh1TamqqpCvX25zEGp4k\nJCSobdu22rdvn/le6dKl1a1bN7Vq1UqVKlVScnKy9u3bp5UrV+qvv/6y1K7NZlPz5s3Vpk0bhYWF\nqVy5ckpJSdGuXbv0ww8/mLHe4cOH1atXL0VHR6tMmTLXtHM13jt9+rR57kuWLKnq1atne9y8nJvi\nFAcDAIqfq/csJMnHx8dlvbS0NPXv31979+6Vj4+Punfvrk6dOqlixYo6deqUfvvtt2t+r+/du1cd\nO3bUiRMnzPciIiLUu3dvhYWFyW63a8eOHfryyy/NOhMnTlRgYKBGjRrltt8jRozQtGnTnN5r1aqV\nbrvtNtWoUUM2m00nTpzQxo0b9ccffzjFmLkRFxenAQMG6NKlS5KunKvbb79d7dq1U0hIiOx2u86e\nPavY2FitW7dO0dHReTqeo7feekujR482yz4+PurWrZu6du2qsmXL6uDBg/r666+1e/dus69dunTR\n+vXrne5RufPpp59qzJgxkqSGDRuqT58+qlu3ri5fvqwNGzbo888/V1pamiRp+vTpuv3229W7d+98\n+44AABSWzMxMp9/bvr6+buunpqbq1ltv1bp168z3goOD1adPH910000qVaqUDh8+rEWLFunvv/+W\nJP3yyy/q37+/fvzxR7dtf/755xo0aJAyMjLM98LCwtSzZ0+FhYWpdOnSOnXqlLZu3ao//vhDJ0+e\ntPQdg4KC1KFDB7Vs2VJVq1ZVQECATp06pQ0bNuiHH34w45vPPvtM1apV05QpUyy1C6CQFHYGMYB/\nNseZzUqWLGmkpaV55bhyGFXkbnT1k08+6VTX1Ww1V02cONGpvqsZhZmBFwBQXD311FNO159NmzYV\nyHEyMjKumX1t3Lhx2S47tGLFCqNixYpmPX9/f2P79u0u23aceezqrC3du3fPdtnklJQUo2fPnk79\n2LZtm9u+O85SZ+Uab3UG3iNHjhiBgYFm3fLlyxt//vnnNfXS0tKM4cOHO32/qy93M709/fTTTnWH\nDRtmnD9//pp6mZmZxpQpU5zqzpgxw2W7jrPaXO1Py5Yts+1Lenq68eijjzq1/f3337tsOzU11Wja\ntOk1/T537pzLfTZv3mz069fPOHToULaf33333WZbNpvNePXVV7MdgX7p0iVj5MiRTsdeunSpy+MC\nALLnrdjCMKzPwHvfffcZjz/+uNt4wjAMY968eU4zst1zzz0u686ZM8esFxAQYPz+++9u246LizNe\ne+21bGf2zc+2DCNnqwFkncHVE6sz8GZmZhrdu3d3qtu3b1+3s77GxsYaDz/8sLFq1apsP+/SpYsx\nevRot/FPenq6MXnyZKeZ555//nm33yk3y18bhvUZeItzHAwA8K7cPCNISEhwuu517drV6XPH65xj\nfOBqVllHly9fNlq1amXu5+fnZ8ycOTPba1hSUpIxYMAAs66vr6/b68wXX3zh1KcaNWoYy5Ytc1k/\nKSnJmD59uvHSSy9l+7mVGXjHjBlj1gkODvZ4Dvbv3288++yzxq5du7L93GoMER0dbfj6+pp1q1Sp\nku2Kj+np6caoUaOczkvHjh2NzMzMbNvNGovY7XbDx8fHmDZtWrZ/o61btzotv92sWTO33x8AgMKQ\nm3jozz//dNqnZ8+ebutnzRl54oknjAsXLlxTLyMjw3jjjTec6n700Ucu242NjTVKly7t9Jv+ww8/\nzPa6bBhXYq3vvvvOGDBgQLafb9myxWjcuLGxYMECt7P/Hj161OjUqZNTTOAqfrmKGXiBwkUCL4AC\n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\nKysJdu/eXdOnT/e48uCePXs0btw4l0mv/v7+TjPexcfHq2PHjlq+fLnLNpOTkzVz5sw8DfStV6+e\nhgwZolWrVrkdWLRz506n5OVWrVo5JRzn1IQJE8zVKdLT09WrVy+tW7fumnoZGRl65ZVXNGPGDPO9\nTp06Oc0UCAAAXHv22Wfl5+dnlrObhbdp06ZOE4k8//zzeuqpp3TmzBm3bSckJGjmzJm68cYbtXHj\nxmzrvPPOO+Yzn8zMTPXp00cfffSRyxWCMjIy9OOPPzpN9nLVbbfdZm4nJibqoYceyvZ+2qVLl/TC\nCy9oypQplu+DACh8JQq7AwCuH35+fvr444/VunVrjRs3TidOnJB0JYhYtmyZli1b5rENm82mvn37\navLkyU5LKufFgAEDdOnSJT388MPmjaaoqCiXs94FBQXp+++/V9u2bT22HRgYqFWrVumee+7RH3/8\nIenK912yZInHGWJuvfVWffnll05LOwAA4C02m01fffWVhg4dqnnz5km6MvjmmWee0ZgxY3TzzTer\nRYsWCg4Olr+/v+Lj43X48GH9+uuvOnDggMf27Xa75s6dqzZt2pg3Ql555RV9/vnn6tevn2rVqqVz\n584pKipKS5cudUpemTRpklPSxj9FaGio3nzzTQ0bNkzSlfPdpUsX9ejRQzfffLPKlCmjAwcO6Isv\nvtC+ffskXUnEtZrEMWnSJMXExJijvP/zn/9o3rx56tatmyIjIxUcHCxJOnv2rPbu3astW7Zo06ZN\nbhOHCpqfn5+++OILdejQQSdPnjT7/cUXX6hnz55q2rSpypcvr6SkJO3evVt//vmntm/fLkmaPHly\ntm1+/PHH2rt3r6Kjo5WRkaFx48bpvffeU7du3dS8eXNVqFBBGRkZOnPmjGJjY7V582ZFR0d77TsD\nwD9VQccWVj3//PPm7/Hk5GTdfPPN6tWrl7p06aJy5copISFBUVFR+uWXX5SZmalq1aqpd+/emjlz\nptt2MzMz9d133+m7775TpUqV1L59ezVv3lyVK1dWQECAEhMTtWnTJn3//fe6ePGiud/kyZOveaCS\nn20VJXPnzlW7du20Z88eSdLChQu1dOlS9ejRQ61atVLFihV18eJF7d+/X6tWrTJXJ7r33nuvaeuF\nF17QAw88IOlKkk+LFi3Ut29ftW3bVqVLl9bx48f166+/asWKFZKkxo0bq0GDBvr666899rN69eq6\n7bbbzJhpypQpmjZtmmrXri1/f3+z3mOPPZarGfCIgwEAxZWvr6++/vprtW/fXocPH1ZKSoqeeOIJ\nvf766+rWrZsaN26s8uXL69KlSzp9+rR27NihjRs3KjY21mPbffv21ciRIzV16lRJV1Yr7Nq1q1q3\nbq3bb79doaGhstvtOnHihDZv3qzffvtNycnJGjx4cK6/T3p6uv773//qv//9r6pXr6727durSZMm\nqlSpknx9fXXy5EmtXbtWS5YsMVfjsdlsmjJlSq6PKUk33XSTJk6caK70cOLECXXo0EE9evRQ165d\nVaZMGR06dEhfffWV07mrUKGCPv74Y3OgEQAAcK969er697//ba5qs3jxYm3ZskXNmjVzqvfmm29q\n+/btZj7H+++/r48//lh33HGH+ezEMIxrnp24SsS9ql69epozZ47uu+8+ZWRkKDU1VUOHDtXkyZPV\nq1cv1atXT6VKlVJiYqK2bdum33//XXFxcQoLC7umrTZt2qhTp07mfY4vv/xS69ev14ABAxQREaG0\ntDTt2rVLixYtMichGTdunF555ZU8n0cAXmAAQCG4ePGi8e677xpt27Y1SpQoYUhy+fLx8TGaNGli\nvPbaa8ahQ4cste+4/+DBgy3ts3PnTqN3794u+1OyZElj8ODBxrFjx3L8fTMyMoyvv/7aaNOmjWG3\n211+V7vdbrRp08ZYuHChkZmZmePjAABQED744AOjUqVKbq/Xrq5rDz30kHH8+HGXbW/ZssWoUqWK\npfZsNpsxZcoUj/3t3Lmzuc/YsWMtfceoqCinY7lTq1Yts97cuXM9tj137lyzfq1atTzWHzNmjKXz\nMXz4cOPAgQNO7x04cMBt22lpacbQoUNz/LeUZKxYsSLbNgcPHpzjuCun/d67d68RERGRo/66a/P8\n+fNG7969c3UerMajAADXCiq2cKwbFRXl8vivvvqqpeMFBwcb69atM8aOHWu+17lz52zbdIwPrMY1\nEydOLPC2DCNnsUhO46icxFCGYRgnT540WrdunaPv5+pv+X//93+W9q9bt66xZ8+eHMUs+/btM2rW\nrOm23aznJ6fxTXGMgwEA3uV4DfcU31hlJa7x5MSJE0bbtm1zFct5Mm7cOLfPULK+XF3TrVz3c9p/\nPz8/45NPPnHZ95ye24kTJxo2m83SsUNCQoxt27a5bS+nschVubmvAwCAt+Q1Htq1a5dTbNGnT59s\n66WlpRkPPfRQjuMDScaaNWvc9mHx4sVGYGCg5fbCwsKybefw4cNG9erVLbXx0EMPGWlpaU7vrVy5\n0mUfHdudP3++y3rt27c3640fP97t9wZgXdGdkgHAP1pAQIBGjhypNWvW6PTp0/r99981f/58TZ06\nVRMmTNC0adM0f/58rVixQufOndPWrVs1ZswYl0ssZWUYhvm6OrOPJw0aNND333+vhIQEffvtt/rg\ngw/0+uuva8aMGfrpp5+UmJioefPmqVq1ajn+vna7Xf369dPatWuVmJioJUuWaNasWZo0aZImTZqk\nWbNmacmSJTp16pTWrl2rvn37MooaAFBkDB8+XPv379frr7+uZs2aebxG1ahRQy+88IJ27typ2bNn\nKyQkxGXdpk2baufOnXrqqacUFBSUbR273a6uXbtq/fr15uwk/2SvvfaaFi9enO0oa0mqWbOm5syZ\n47S8pFW+vr768MMPtXbtWvXo0cNp+ajs1KtXT08++aQ2bNigjh075vh4+SUsLEzbtm3Tm2++qRo1\narit27hxY7399ttuY7bAwEB9//33+umnn9SxY0ePsxU2atRIL774onbu3Gk5HgUAuFaQsYUVr7zy\nij799FOX1xR/f38NGDBA0dHRat26taU2p0+frsGDB6t69epu69ntdt1xxx1as2aNRo0aVeBtFTXB\nwcFas2aN5syZo4iICLd169Wrp3Hjxl0zM85Vs2fP1rvvvquKFStm+3lgYKAeffRRbdmyRfXq1ctR\nP+vWravo6Gi99dZbuuWWW1S1alWVLFkyR214QhwMACiuqlSpolWrVmnBggUur9NX2e12RUZGavz4\n8ZZWVRg7dqz++usv9ezZU76+vi7rBQUF6b777tNTTz2V4/5f9emnn+qee+5RpUqV3Nbz8/NTv379\ntHXrVg0aNCjXx8tq1KhRWrt2rbp06eIyHi5TpoxGjhypHTt2qHHjxvl2bAAArhf169fXXXfdZZa/\n//57bdmy5Zp6vr6+mj17tlavXq1u3bq5jUMkKTw8XE899ZQ2bdrkceXmXr16ac+ePXrsscdUpkwZ\nl/V8fX1166236q233sr28xo1amjTpk3q16+fy9ghIiJC8+fP1+zZs8k3AYoRm2EYRmF3AgAAAEDx\nkZCQoI0bN+rkyZM6deqU0tPTVa5cOYWEhKhFixYKDQ3NVbtpaWlauXKl9u/fr1OnTql06dIKCQlR\n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\n115J1k6/tb8mhTkdqvBIFUakDEP60pui27xz1Ts6XMeLj+mk26uTRlWBcMvtg7kAACAASURBVHWM\nKlWUujgNTTmrj/7tol9ZGaruLsoNfc+hJC0tzcodOTk5uvjiixtsW1hYaD3qOT4+XnFxcUEzZlsa\nmDZK//zh/2p4zlxbi3grTafuqbytqpDdRg5Deqo5/7YAAKCDkFNaryqnPK70nPvkMpryjJDGeUyH\n7q683faMIrXgM1AAANpRaP+0DACAzqqpj7purM1PX0lbnpW+XdXix2UDAICONTk9UYPiY+oV59R8\ndDfal8fj0fz5863XS5YsqVVIW+3xxx/XP/7xD+Xm5mrTpk368MMPdcUVVwTEmE8++aSOHz8uqarw\nt2bxbrVRo0bpkUce0T333CO326358+frrbfeatH8AQC1NVQM3Nwi4dbuju9vR+K686jbtu7r6l2H\nfRUn/2Zkcr3diKX6RctSVeFwF4dDFV6v8opO6NXsvVq9rUBmnQw0OCGmwYJjX4XJ1X36+n/kaxdl\nX99jKJkwYYKeeOIJSdKaNWt03333Ndh29erV1nFGRkZQjdnWRv76Fv2r31k68vH/q2HH/qFIo1Km\nKRmnLsHmHJebYVrlveCXXaht4nQYujglTndfnsK/LQAAQYGcYo/qnHL8fx9WWtmn1lMsmptV3KZD\n673peso9zfbi3XCXQ78+qw+fgQIAApphmqY9t8Og1fbt26fk5GRJUn5+vpKSkjp4RgCATsHrbfxR\n1421aUofzcCaF1z4/QKAziOUd4FrqvZY99avX69LLrlEkjR27Fht2LChwbavvfaabrrpJklSZmam\nXnvttYAYs3///vrhhx8kSXv27NGAAb4fQVhcXKzevXvrxIkTOu2001RUVKTIyMgWfQ++kFMAAE3R\nGTJQsK15Ho9HSUlJOnDggCTp888/14gRI3y2GzlypHJzcyVJa9eu1fjx44NmzIa0xe+X1+NReVmJ\nunSJVHlZiSQpIjK6acflpVJYpCLCwlTurtrNN8LltOW45q7TAIDQRE4JzDEb0lY5pbTkZ0nNyCfV\nx1FdVe6pKluyK59EuJwN3nwHAAgdwZJRWl+B04ZWrlypadOmqX///oqIiFB8fLxGjx6tJ554wtrl\nxQ7FxcVavny57rjjDo0ePVpxcXEKCwtT165dNXjwYM2YMUNr164Vtc4AgKBU/ahrf4W3jbVpSh8A\n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\nBEGAIAgICQkp9zZnz54Vn8/Ozoajo6P5F6Hh5ZdfFuMJgoARI0bo7YcgCGU6FxEREVUd06dP15oD\n9OrVy+IxzX0Q0bNDIvBfNRGVUUFBAc6ePYvIyEikp6ejdu3aqFevHnr27AkXF5eK7p7JHj16hAsX\nLuDBgwd4+PAhlEolnJ2dUbt2bTRr1gz+/v6ws7Mrt/6kpqYiLCwMycnJePr0KerUqQMfHx90797d\nIh/YpKam4uzZs0hJSUFaWhpkMhlcXV3RqFEjdO7cucxvdBERUeX0rIzbSUlJiIiIgEKhgEKhgEQi\ngYuLC+rXr48OHTqU+ks2T58+xcmTJ3Hnzh08fvwYzs7OqF+/PoKDg6vU/bEUlUqFkydPIi4uDunp\n6fD29oavry+CgoIsdo60tDSEh4fj/v37ePToEeRyOVxcXNCsWTP4+fkZTJatKGq1GhcvXkRMTAwU\nCgXy8/Ph4uICHx8fBAYGmp2gAwApKSn466+/xLmZnZ0dXF1d0bx5c/j5+VXL3z8iqho4tygbpVKJ\n8PBwxMTEICsrC3Xq1EGDBg0QHByMGjVqlDrujRs3EBsbizt37iAjI0O8nhYtWqBDhw5mJSBbMlZl\nFBUVhYiICDx48ABKpRJOTk5o0qQJAgICdCbu6pKZmYmwsDDcuHEDOTk58PT0RKNGjdCzZ0/Y2NhY\n+Qosg/NgIiIiIiIiIiKi8scEXiIiIiIiIiIiIiIiIiIiIiIiIiIionJkeK9SIiIiIiIiIiIiIiIi\nIiIiIiIiIiIisigm8BIREREREREREREREREREREREREREZUjJvASERERERERERERERERERERERER\nERGVIybwEhERERERERERERERERERERERERERlSMm8BIREREREREREREREREREREREREREZUjJvAS\nERERERERERERERGRxalUKkRHRyMkJASvvPIKunTpgho1akAikUAikWD69OlWO/e+ffswduxYNG7c\nGPb29vDw8EDXrl3xySefICMjw2rnJSIiIiIiIiIylbyiO0BERERERERERERERETPnnHjxmHXrl3l\nes6srCxMmjQJ+/bt03peoVBAoVDgzJkzWLNmDXbs2IHOnTuXa9+IiIiIiIiIiDRxBV4iIiIiIiIi\nIiIiIiKyOJVKpVV2dXVF8+bNrXq+sWPHism7np6eWLx4MbZs2YKvv/4a3bp1AwAkJSVhyJAhiI2N\ntVpfiIiIiIiIiIiM4Qq8REREREREREREREREZHEdO3ZE69atERgYiMDAQDRp0gQhISGYMWOGVc63\nbt06HDp0CADg6+uLY8eOwdPTU3x97ty5WLBgAVavXo20tDS8+OKLCAsLs0pfiIiIiIiIiIiMkQiC\nIFR0J4iIiIiIiIiIiIiIiOjZp5nAO23aNISEhFgkrkqlQoMGDZCcnAwA+PvvvxEQEKCzXocOHRAR\nEQEAOHz4MAYMGGCRPhARERERERERmUNa0R0gIiIiIiIiIiIiIiIiKouwsDAxeTc4OFhn8i4AyGQy\nvPrqq2J569at5dI/IiIiIiIiIqLimMBLREREREREREREREREVVpoaKh4PGTIEIN1Bw8erLMdERER\nEREREVF5kld0B+gfSqUSUVFRAAB3d3fI5fzxEBHRs6mgoAAKhQIA4OfnB3t7+wruERnCOQoREVUn\nnKdULZynEBFRdcE5inFFcwIACAoKMljXy8sLDRo0QFJSElJTU6FQKODu7m6xvnCOQkRE1QnnKVUL\n5ylERFRdVJU5CkfiSiQqKgodO3as6G4QERGVq/Pnzxv9UIUqFucoRERUXXGeUvlxnkJERNUR5yi6\nxcXFicdNmjQxWr9JkyZISkoS25qTwHv37l2Dr0dERGDYsGEmxyMiInpWcJ5S+fG9FCIiqo4q8xyF\nCbxERERERERERERERERUpT158kQ8rlOnjtH6bm5uOtuaokGDBmbVJyIiIiIiIiLShQm8lYjmt7vP\nnz8Pb2/vCuwNERGR9SQnJ4vf7rXk9oRkHZyjEBFRdcJ5StXCeQoREVUXnKMYl5WVJR6bsi2mg4OD\neJyZmWmVPgGcoxAR0bOP85Sqhe+lEBFRdVFV5ihM4K1E5PJ/fhze3t6oX79+BfaGiIiofGiOf1Q5\ncY5CRETVFecplR/nKUREVB1xjlLxkpKSDL6u+SEh5yhERFSdcJ5S+fG9FCIiqo4q8xyl8vaMiIiI\niIiIiIiIiIiIyASOjo5IS0sDACiVSjg6Ohqsn5OTIx7XqlXLrHMx0YWIiIiIiIiILEFa0R0gIiIi\nIiIiIiIiIiIiKgsXFxfx+OHDh0brP3r0SGdbIiIiIiIiIqLywgReIiIiIiIiIiIiIiIiqtJatmwp\nHicmJhqtr1lHsy0RERERERERUXlhAi8RERERERERERERERFVaX5+fuLxhQsXDNZNTU1FUlISAMDD\nwwPu7u5W7RsRERERERERkS5M4CUiIiIiIiIiIiIiIqIqbdCgQeJxaGiowboHDx4Uj4cMGWK1PhER\nERERERERGcIEXiIiIiIiIiIiIiIiIqrSgoOD4eXlBQA4ceIELl26pLOeSqXCV199JZYnTJhQLv0j\nIiIiIiIiIiqOCbxERERERERERERERERUaYWEhEAikUAikaBXr14668hkMixZskQsT506FQ8ePChR\nb9GiRYiIiAAAdOvWDQMHDrRKn4mIiIiIiIiIjJFXdAeIiIiIiIiIiIiIiIjo2ZOYmIj169drPXfl\nyhXx+PLly1i8eLHW63369EGfPn1Kdb5Zs2Zh9+7d+OOPP3D16lX4+/tj1qxZ8PX1xePHj7F161aE\nh4cDAFxcXLB27dpSnYeIiIiIiIiIyBKYwEtEREREREREREREREQWd/v2bXzwwQd6X79y5YpWQi8A\nyOXyUifwyuVy/Pbbb5g4cSJ+//13pKSkYPny5SXq1a9fH9u3b8dzzz1XqvMQEREREREREVmCtKI7\nQERERERERERERERERGQJtWrVwv79+7Fnzx48//zzaNCgAezs7FCnTh106tQJq1atQnR0NLp27VrR\nXSUiIiIiIiKiao4r8BIREREREREREREREZHF9erVC4IglDnO9OnTMX36dLPajBgxAiNGjCjzuYmI\niIiIiIiIrIUr8BIREREREREREREREREREREREREREZUjJvASERERERERERERERERERERERERERGV\nIybwEhERERERERERERERERERERERERERlSMm8BIREREREREREREREREREREREREREZUjJvASERER\nERERERERERERERERERERERGVIybwEhERERERERERERERERERUZWmVgvIziuAWi1UdFeIiIiICADU\naiDvaeF/SSd5RXeAiIiIiIiIiIiIiIiIiIiIqDRi7mdgXXgCQqNSkJOvgoONDIP9vDCze1P41nUC\nUJjcqyxQwVYqhbJABQCoYSuHVCrRet1eLhOfKyt9MU05V1EycvF+EhEREVUJKVHAmW+AmL1AfjZg\nUwPwHQF0mQt4+VV07yoVJvASERERERERERERERERERFRlbM34h7m74hEgcaquzn5Kuy6dA/7Iu7j\njf4tEK/IwoErycgt0F75TSoBAhrWhpODDc7cfKQ3+ddcxROK7eVSDGrjiR7NPXA6/iFCo/UnGsfc\n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\niIhIaPJW+uYswYR3AbxuOLzHN7/x7xuBm4laie32RQzmoyorSNSn1I6mnKj6G0bADy/pEXJ4t/lV\nm7TbqsArrdlV0yHvpcD/MJpO312cIiIiIiIiItIsrrzySgYMGMBll13GZZddRp8+fViyZAk/+tGP\nIt7XRRddFFSIdvXq1f7wbnJyMkOHDq13n8GDBzN27NgGj7EtqRHg/dbdTCMRERERkbbAsuwqS9ma\npsHo1ERW7TrY3EOr1wDjc6Y4sxltbifOOIXH9gUJnIYVVuWyVsnywLYFvgqylUUqjBpKldz6VA/h\nqniUiIhI21ecF0YA1/bNb666q92Fd922g9+6bwdgWdRDdDaCm4dlW9/BpvHnSg7TYPLQPo3eT6TZ\n1QO8qAKvtGaJqb6lWOr6B9J0+l6vWIJFRERERERERJrc7Nmzm3sINTzzzDP+7WCq70rtzj7LVeWx\nKvCKiIiISDjyi0pYlPMp6/OKKXN7iXU5GJ2ayIjkBI6XtvybxMaY75DlWlilMpnTOFNJq12Edyvk\nr4GM+Y0TcA2lSm59agvhqniUiIhI27ZtfngB3Pw1viqp7Si867FNZrp/wl77fAD22efzXWNvvfu5\nbQeLPaMbe3iYBszNTCOlR8dG7yviqn05MFSBV1q91Im+pVje+C188uaZ5w0nTN0E3S9ptqGJiIiI\niIiISMtz6NAh1q9fD4DT6eS2225r5hG1XjUq8CrAKyIiIiIhWpt7kJkrduOxzlSeKnN7WbXrYKup\nvFs9vNuuuUt9lXIjUXG3ulCq5AY8Th0hXBWPEhERabssC/LXhrevuxT2hrqvQXNWVg13BQjbhu3W\nRfzWc7s/vAtQYtc/t3Pbjiqh38ZgGjDiogRmXJfcOsO7AEb7XslBAd62KjEVbsiC/0s785ztgc69\nmm9MIiIiIiIiItIiPffcc3i9vovrP/zhD0lMTGzmEbVeNQK837qxbRujXZUYExEREZFw5ReV1Ajv\ntha/uj6ZhzfsZ4ozW+Hdylxxvkq5jSWYKrmG6UusWLX8XOoL4VYUj9q2wFdtz13qe08pY32hX4V3\nRUREWidPWfhV/J2x4C4Lvn3cuZD+Z1g1tdmq9hpGgBCv6YTh98PRA/75jseM4VX3ZfzVk06+3adK\nc6dpcE6XBDhWe1+ldjTZ1ndY7BkdkfDuyh9fxbLthWTnHaLM7SXGaTIypRu3DenN4PPOxjRb+7nn\n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\nhNtrjG2pTu/qyvzNiYfn7/766B5TNDB27Nhi7li+fHk++9nPNtl3/fr1qaurS5IMGTIkgwcP7jJz\ntre/+puv5/8cdWLe+eX/n0+8+6v0rdh+ADdBV//lJujJJb9197NjBuc7nx/TY/Y3AF2bnFIau3PK\ne//rf2Tstv/Y57do7G97R6Eyi3eelFt3TC1pRknSI3M4AF2PAl4AAACAMmpoaMj1119ffH3//ffv\nVUi720033ZRf/epXWbFiRZYuXZonn3wyZ511VqeY8/vf/37ee++9JLsKf/cs3t3t1FNPzQ033JAr\nr7wyO3bsyPXXX58HH3ywTesHoGWVlRXpd9Cub/lXZ1eRb2tu//1ou61j7C4o3rmzUCwo7ohC4s4y\nxoc7d6ZPdVUqKyvSk5xzzjm5+eabkyQLFy7M1Vdf3WTfJ554otiePHlyl5qzHEaPPTWjx87PzoaG\nbN22JQcd1Df127YkSfr07b9/7fqtSa++Ob9Xr5xzAF8HjbX7HVTd4/Y3AF2bnFI6o8eemoxdlJ0N\nDdmy5c9JWpFPdrf7DchnGgr5eUqXT3pyDgeg6/H7rwEAAADK6JlnnsnatWuTJBMnTsz48eMb7VdV\nVZUrrrii+HrevHmdZs758+cX29/+9rebnHfGjBk5+OBdv8VhwYIF2bZtW6vXDkDXtLuguLq6Mv37\n9Er/Pr3a1O7qY/TU4saJEydm2LBhSZIlS5bkxRdfbLRfQ0NDbrvttuLradOmdak5y6myqir9+h+S\n6oMOSv9DDk3/Qw7d//aAgenft/cBfx001u6J+xuArk1OKb3KqqrW55Pd7V7VJc8nPTmHA9D1dOoC\n3gULFmTq1KkZNWpU+vTpkyFDhmTChAm5+eabi7e8lMLmzZvz8MMP5/LLL8+ECRMyePDg9OrVKwMG\nDMhxxx2XSy65JIsWLUqhUCjZnAAAAEDPtHDhwmK7pZtUzj333Eaf68g5f/e73+WNN95Ikhx//PE5\n+uijmxyrpqYmp59+epLk/fffz69//etWrRsA6JqqqqoyZ86c4utLLrkkGzZs2Kff7Nmzs2LFiiTJ\naaedlrPPPrvR8e69995UVFSkoqIikyZNKsucAED3JKcAAJ1JdUcvoDFbtmzJxRdfnAULFuz15xs3\nbszGjRvz3HPP5fbbb89DDz2UU0899YDmuvXWW/O9730v9fX1+7y3efPmrF69OqtXr87999+f008/\n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\n8CxevDjHHnvsfj1vn0H34muQcnB2sD9kFOCjfB3S3pwd7C85BSglX8OUkjOGPckswIHwNUspOVP4\nKDmFnkwBbycxceLEDBs2LEmyZMmSvPjii432a2hoyG233VZ8PW3atLKsj+7jy1/+crF96623Ntnv\nRz/6Ud5///0kyXnnnVe8Hr6psebOnVvs/1F/+tOf8tBDDyVJ+vbtmylTprRp7ZTH5ZdfXgxFw4YN\ny+LFi/Pxj3+8VWPYZ9B9yCiUi7ODlsgowEfJKZSDs4P9IacApSTjUGrOGHaTWYADIaNQas4U9iSn\n0KMV6DTuuOOOQpJCksIJJ5xQWL9+/T59rrrqqmKf0047rQNWSWdyzz33FPfDpZdeul/PrF+/vlBT\nU1NIUqisrCw8+uij+/R5/vnnC/369SskKVRXVxdWrVrV5Hhf+tKXimv4yle+Uti+ffte72/evLkw\nceLEYp/vfe97rfocKa/LL7+8+Hc1bNiwwiuvvNKmcewz6F5kFFpLRqHUZBSgKXIKrSGj0B7kFKA9\nyDg0RZ6hrWQWoBRkFJoio3Ag5BR6uopCoVBovsSXctmxY0cmT56cp556KsmunyiYMWNGamtr8847\n72TevHl59tlnkyQDBw7Ms88+mxNOOKEjl0wZrVmzJnffffdef/bb3/42jz32WJLkxBNPzN/+7d/u\n9f7nPve5fO5zn9tnrPvuuy/Tp09PklRWVmbatGn5/Oc/n6qqqixbtiz33Xdf6uvrkyQ33nhjvvvd\n7za5rj/96U859dRT8+abbxbXMX369Bx++OF5/fXXc9ddd+X1119Pkpx00klZunRp+vfv37b/EWhX\n1157bW688cYkSUVFRf7lX/4lxx13XIvPjR8/vvirCPZkn0H3IaPQHBmF9iajAM2RU2iKjEI5yClA\ne5FxSOQZSkdmAUpFRiGRUSgtOQXiBt7O5r333iv8zd/8TbE6v7GPESNGFJYtW9bRS6XMFi9e3Oy+\naOzjuuuua3K8O+64o9CnT58mn62qqirMmTNnv9a2cuXKwnHHHdfsWiZMmFBYu3Ztif7XoD3s+ZNB\nrfm45557mhzTPoPuQ0ahKTIK7U1GAVoip9AYGYVykFOA9iTjIM9QKjILUEoyCjIKpSSnQKFQHTqV\nmpqaPPbYY3n00Ufz05/+NMuXL8+GDRtSU1OT0aNH58ILL8zMmTNzyCGHdPRS6eK+8Y1v5Mwzz8yd\nd96ZRYsWpa6uLjt37szhhx+eM844I1//+tfzyU9+cr/Gqq2tzW9+85vcfffd+fnPf55XXnklmzZt\nyqBBg3LiiSfmoosuysUXX5zKysp2/qzobOwz6D5kFMrF2UE52GfQvcgplIOzg3Kx14DdZBxKzRlD\nKdlP0HPJKJSaM4VSs6foaioKhUKhoxcBAAAAAAAAAAAAAD2F8m8AAAAAAAAAAAAAKCMFvAAAAAAA\nAAAAAABQRgp4AQAAAAAAAAAAAKCMFPACAAAAAAAAAAAAQBkp4AUAAAAAAAAAAACAMlLACwAAAAAA\nAAAAAABlpIAXAAAAAAAAAAAAAMpIAS8AAAAAAAAAAAAAlJECXgAAAAAAAAAAAAAoIwW8AAAAAAAA\nAAAAAFBGCngBAAAAAAAAAAAAoIwU8AIAAAAAAAAAAABAGSngBQAAAAAAAAAAAIAyUsALAAAAAAAA\nAAAAAGWkgBcAAAAAAAAAAAAAykgBLwAAAAAAAAAAAACUkQJeAAAAAAAAAAAAACgjBbwAAAAAAAAA\nAAAAUEYKeAEAAAAAAAAAAACgjBTwAgAAAAAAAAAAAEAZKeAFAAAAAAAAAAAAgDJSwAsAAAAAAAAA\nAAAAZaSAFwAAAAAAAAAAAADKSAEvAAAAAAAAAAAAAJSRAl4AAAAAAAAAAAAAKCMFvAAAAAAAAAAA\nAABQRgp4AQAAAAAAAAAAAKCMFPACAAAAAAAAAAAAQBkp4AUAAAAAAAAAAACAMlLACwAAAAAAAAAA\nAABlpIAXAAAAAAAAAAAAAMpIAS8AAAAAAAAAAAAAlJECXgAAAAAAAAAAAAAoIwW8AAAAAAAAAAAA\nAFBGCngBAAAAAAAAAAAAoIwU8AIAAAAAAAAAAABAGSngBQAAAAAAAAAAAIAyUsALAAAAAAAAAAAA\nAGWkgBcAAAAAAAAAAAAAyuj/Ak+HcVyOTkwvAAAAAElFTkSuQmCC\n", - "text/plain": [ - "" + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HvhYZrIZCEyo" + }, + "source": [ + "\n", + "\n", + "This notebook was written by Ultralytics LLC, and is freely available for redistribution under the [GPL-3.0 license](https://choosealicense.com/licenses/gpl-3.0/). \n", + "For more information please visit https://github.com/ultralytics/yolov3 and https://www.ultralytics.com." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7mGmQbAO5pQb" + }, + "source": [ + "# Setup\n", + "\n", + "Clone repo, install dependencies and check PyTorch and GPU." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "wbvMlHd_QwMG", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "edc03bfa-6dd3-49ae-9095-405ba8cbe87d" + }, + "source": [ + "!git clone https://github.com/ultralytics/yolov3 # clone repo\n", + "%cd yolov3\n", + "%pip install -qr requirements.txt # install dependencies\n", + "\n", + "import torch\n", + "from IPython.display import Image, clear_output # to display images\n", + "\n", + "clear_output()\n", + "print('Setup complete. Using torch %s %s' % (torch.__version__, torch.cuda.get_device_properties(0) if torch.cuda.is_available() else 'CPU'))" + ], + "execution_count": 1, + "outputs": [ + { + "output_type": "stream", + "text": [ + "Setup complete. Using torch 1.7.0+cu101 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', major=7, minor=0, total_memory=16130MB, multi_processor_count=80)\n" + ], + "name": "stdout" + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4JnkELT0cIJg" + }, + "source": [ + "# 1. Inference\n", + "\n", + "`detect.py` runs inference on a variety of sources, downloading models automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases)." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "zR9ZbuQCH7FX", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 587 + }, + "outputId": "44211008-da79-4175-f719-ac265dad26eb" + }, + "source": [ + "!python detect.py --weights yolov3.pt --img 640 --conf 0.25 --source data/images/\n", + "Image(filename='runs/detect/exp/zidane.jpg', width=600)" + ], + "execution_count": 2, + "outputs": [ + { + "output_type": "stream", + "text": [ + "Namespace(agnostic_nms=False, augment=False, classes=None, conf_thres=0.25, device='', exist_ok=False, img_size=640, iou_thres=0.45, name='exp', project='runs/detect', save_conf=False, save_txt=False, source='data/images/', update=False, view_img=False, weights=['yolov3.pt'])\n", + "Using torch 1.7.0+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16130MB)\n", + "\n", + "Downloading https://github.com/ultralytics/yolov3/releases/download/v1.0/yolov3.pt to yolov3.pt...\n", + "100% 118M/118M [00:08<00:00, 14.6MB/s]\n", + "\n", + "Fusing layers... \n", + "Model Summary: 261 layers, 61922845 parameters, 0 gradients\n", + "image 1/2 /content/yolov3/data/images/bus.jpg: 640x480 4 persons, 1 buss, Done. (0.046s)\n", + "image 2/2 /content/yolov3/data/images/zidane.jpg: 384x640 2 persons, 3 ties, Done. (0.013s)\n", + "Results saved to runs/detect/exp\n", + "Done. (0.293s)\n" + ], + "name": "stdout" + }, + { + "output_type": "execute_result", + "data": { + "image/jpeg": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": { + "tags": [], + "image/jpeg": { + "width": 600 + } + }, + "execution_count": 2 + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4qbaa3iEcrcE" + }, + "source": [ + "Results are saved to `runs/detect`. A full list of available inference sources:\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0eq1SMWl6Sfn" + }, + "source": [ + "# 2. Test\n", + "Test a model on [COCO](https://cocodataset.org/#home) val or test-dev dataset to evaluate trained accuracy. Models are downloaded automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases). To show results by class use the `--verbose` flag. Note that `pycocotools` metrics may be 1-2% better than the equivalent repo metrics, as is visible below, due to slight differences in mAP computation." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eyTZYGgRjnMc" + }, + "source": [ + "## COCO val2017\n", + "Download [COCO val 2017](https://github.com/ultralytics/yolov5/blob/74b34872fdf41941cddcf243951cdb090fbac17b/data/coco.yaml#L14) dataset (1GB - 5000 images), and test model accuracy." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "WQPtK1QYVaD_", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 66, + "referenced_widgets": [ + "b257add75888401ebf17767cdc9ed439", + "4b685e8b26f3496db73186063e19f785", + "0980232d74a14bdfa353a3f248bbe8ff", + "e981f3dfbf374643b58cba7dfbef3bca", + "07bb32c950654e9fa401e35a0030eadc", + "ec3fce2f475b4f31b8caf1a0ca912af1", + "9a1c27af326e43ca8a8b6b90cf0075db", + "7cf92d6d6c704a8d8e7834783813228d" + ] + }, + "outputId": "2ac7a39f-8432-43e0-9d34-bc2c9a71ba21" + }, + "source": [ + "# Download COCO val2017\n", + "torch.hub.download_url_to_file('https://github.com/ultralytics/yolov5/releases/download/v1.0/coco2017val.zip', 'tmp.zip')\n", + "!unzip -q tmp.zip -d ../ && rm tmp.zip" + ], + "execution_count": 3, + "outputs": [ + { + "output_type": "display_data", + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "b257add75888401ebf17767cdc9ed439", + "version_minor": 0, + "version_major": 2 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=819257867.0), HTML(value='')))" + ] + }, + "metadata": { + "tags": [] + } + }, + { + "output_type": "stream", + "text": [ + "\n" + ], + "name": "stdout" + } + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "X58w8JLpMnjH", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "6850c54e-b697-40c2-f9fc-9ffda2d7052a" + }, + "source": [ + "# Run YOLOv3 on COCO val2017\n", + "!python test.py --weights yolov3.pt --data coco.yaml --img 640 --iou 0.65" + ], + "execution_count": 4, + "outputs": [ + { + "output_type": "stream", + "text": [ + "Namespace(augment=False, batch_size=32, conf_thres=0.001, data='./data/coco.yaml', device='', exist_ok=False, img_size=640, iou_thres=0.65, name='exp', project='runs/test', save_conf=False, save_json=True, save_txt=False, single_cls=False, task='val', verbose=False, weights=['yolov3.pt'])\n", + "Using torch 1.7.0+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16130MB)\n", + "\n", + "Fusing layers... \n", + "Model Summary: 261 layers, 61922845 parameters, 0 gradients\n", + "Scanning '../coco/labels/val2017' for images and labels... 4952 found, 48 missing, 0 empty, 0 corrupted: 100% 5000/5000 [00:01<00:00, 3373.28it/s]\n", + "New cache created: ../coco/labels/val2017.cache\n", + "Scanning '../coco/labels/val2017.cache' for images and labels... 4952 found, 48 missing, 0 empty, 0 corrupted: 100% 5000/5000 [00:00<00:00, 43690666.67it/s]\n", + " Class Images Targets P R mAP@.5 mAP@.5:.95: 100% 157/157 [01:19<00:00, 1.97it/s]\n", + " all 5e+03 3.63e+04 0.472 0.698 0.625 0.424\n", + "Speed: 3.6/1.6/5.2 ms inference/NMS/total per 640x640 image at batch-size 32\n", + "\n", + "Evaluating pycocotools mAP... saving runs/test/exp/yolov3_predictions.json...\n", + "loading annotations into memory...\n", + "Done (t=0.41s)\n", + "creating index...\n", + "index created!\n", + "Loading and preparing results...\n", + "DONE (t=3.78s)\n", + "creating index...\n", + "index created!\n", + "Running per image evaluation...\n", + "Evaluate annotation type *bbox*\n", + "DONE (t=78.99s).\n", + "Accumulating evaluation results...\n", + "DONE (t=11.77s).\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.433\n", + " Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.630\n", + " Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.470\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.283\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.485\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.538\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.346\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.581\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.634\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.473\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.687\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.766\n", + "Results saved to runs/test/exp\n" + ], + "name": "stdout" + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rc_KbFk0juX2" + }, + "source": [ + "## COCO test-dev2017\n", + "Download [COCO test2017](https://github.com/ultralytics/yolov5/blob/74b34872fdf41941cddcf243951cdb090fbac17b/data/coco.yaml#L15) dataset (7GB - 40,000 images), to test model accuracy on test-dev set (20,000 images). Results are saved to a `*.json` file which can be submitted to the evaluation server at https://competitions.codalab.org/competitions/20794." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "V0AJnSeCIHyJ" + }, + "source": [ + "# Download COCO test-dev2017\n", + "torch.hub.download_url_to_file('https://github.com/ultralytics/yolov5/releases/download/v1.0/coco2017labels.zip', 'tmp.zip')\n", + "!unzip -q tmp.zip -d ../ && rm tmp.zip # unzip labels\n", + "!f=\"test2017.zip\" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f # 7GB, 41k images\n", + "%mv ./test2017 ./coco/images && mv ./coco ../ # move images to /coco and move /coco next to /yolov3" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "29GJXAP_lPrt" + }, + "source": [ + "# Run YOLOv3 on COCO test-dev2017 using --task test\n", + "!python test.py --weights yolov3.pt --data coco.yaml --task test" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VUOiNLtMP5aG" + }, + "source": [ + "# 3. Train\n", + "\n", + "Download [COCO128](https://www.kaggle.com/ultralytics/coco128), a small 128-image tutorial dataset, start tensorboard and train YOLOv3 from a pretrained checkpoint for 3 epochs (note actual training is typically much longer, around **300-1000 epochs**, depending on your dataset)." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "Knxi2ncxWffW", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 66, + "referenced_widgets": [ + "c1928794b5bd400da6e7817883a0ee9c", + "804fae06a69f4e11b919d8ab80822186", + "138cbb92b4fd4eaa9b7fdcbed1f57a4d", + "28bb2eea5b114f82b201e5fa39fdfc58", + "aea8bd6f395845f696e3abedbff59423", + "0514774dafdf4e39bdd5a8833d1cbcb0", + "7dabd1f8236045729c90ae78a0d9af24", + "227e357d925345f995aeea7b72750cf1" + ] + }, + "outputId": "389207da-a1a0-4cbf-d9b8-a39546b1b76c" + }, + "source": [ + "# Download COCO128\n", + "torch.hub.download_url_to_file('https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip', 'tmp.zip')\n", + "!unzip -q tmp.zip -d ../ && rm tmp.zip" + ], + "execution_count": 5, + "outputs": [ + { + "output_type": "display_data", + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c1928794b5bd400da6e7817883a0ee9c", + "version_minor": 0, + "version_major": 2 + }, + "text/plain": [ + "HBox(children=(FloatProgress(value=0.0, max=22090455.0), HTML(value='')))" + ] + }, + "metadata": { + "tags": [] + } + }, + { + "output_type": "stream", + "text": [ + "\n" + ], + "name": "stdout" + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_pOkGLv1dMqh" + }, + "source": [ + "Train a YOLOv3 model on [COCO128](https://www.kaggle.com/ultralytics/coco128) with `--data coco128.yaml`, starting from pretrained `--weights yolov3.pt`, or from randomly initialized `--weights '' --cfg yolov3.yaml`. Models are downloaded automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases), and **COCO, COCO128, and VOC datasets are downloaded automatically** on first use.\n", + "\n", + "All training results are saved to `runs/train/` with incrementing run directories, i.e. `runs/train/exp2`, `runs/train/exp3` etc.\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "bOy5KI2ncnWd" + }, + "source": [ + "# Tensorboard (optional)\n", + "%load_ext tensorboard\n", + "%tensorboard --logdir runs" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "2fLAV42oNb7M" + }, + "source": [ + "# Weights & Biases (optional)\n", + "%pip install -q wandb \n", + "!wandb login # use 'wandb disabled' or 'wandb enabled' to disable or enable" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "1NcFxRcFdJ_O", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "2132590a-ff5e-4ab8-a20d-f8bb8ea7c42b" + }, + "source": [ + "# Train YOLOv3 on COCO128 for 3 epochs\n", + "!python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov3.pt --nosave --cache" + ], + "execution_count": 6, + "outputs": [ + { + "output_type": "stream", + "text": [ + "Using torch 1.7.0+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16130MB)\n", + "\n", + "Namespace(adam=False, batch_size=16, bucket='', cache_images=True, cfg='', data='./data/coco128.yaml', device='', epochs=3, evolve=False, exist_ok=False, global_rank=-1, hyp='data/hyp.scratch.yaml', image_weights=False, img_size=[640, 640], local_rank=-1, log_imgs=16, multi_scale=False, name='exp', noautoanchor=False, nosave=True, notest=False, project='runs/train', rect=False, resume=False, save_dir='runs/train/exp', single_cls=False, sync_bn=False, total_batch_size=16, weights='yolov3.pt', workers=8, world_size=1)\n", + "Start Tensorboard with \"tensorboard --logdir runs/train\", view at http://localhost:6006/\n", + "2020-11-26 18:51:45.386416: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1\n", + "Hyperparameters {'lr0': 0.01, 'lrf': 0.2, 'momentum': 0.937, 'weight_decay': 0.0005, 'warmup_epochs': 3.0, 'warmup_momentum': 0.8, 'warmup_bias_lr': 0.1, 'box': 0.05, 'cls': 0.5, 'cls_pw': 1.0, 'obj': 1.0, 'obj_pw': 1.0, 'iou_t': 0.2, 'anchor_t': 4.0, 'fl_gamma': 0.0, 'hsv_h': 0.015, 'hsv_s': 0.7, 'hsv_v': 0.4, 'degrees': 0.0, 'translate': 0.1, 'scale': 0.5, 'shear': 0.0, 'perspective': 0.0, 'flipud': 0.0, 'fliplr': 0.5, 'mosaic': 1.0, 'mixup': 0.0}\n", + "\n", + " from n params module arguments \n", + " 0 -1 1 928 models.common.Conv [3, 32, 3, 1] \n", + " 1 -1 1 18560 models.common.Conv [32, 64, 3, 2] \n", + " 2 -1 1 20672 models.common.Bottleneck [64, 64] \n", + " 3 -1 1 73984 models.common.Conv [64, 128, 3, 2] \n", + " 4 -1 2 164608 models.common.Bottleneck [128, 128] \n", + " 5 -1 1 295424 models.common.Conv [128, 256, 3, 2] \n", + " 6 -1 8 2627584 models.common.Bottleneck [256, 256] \n", + " 7 -1 1 1180672 models.common.Conv [256, 512, 3, 2] \n", + " 8 -1 8 10498048 models.common.Bottleneck [512, 512] \n", + " 9 -1 1 4720640 models.common.Conv [512, 1024, 3, 2] \n", + " 10 -1 4 20983808 models.common.Bottleneck [1024, 1024] \n", + " 11 -1 1 5245952 models.common.Bottleneck [1024, 1024, False] \n", + " 12 -1 1 525312 models.common.Conv [1024, 512, [1, 1]] \n", + " 13 -1 1 4720640 models.common.Conv [512, 1024, 3, 1] \n", + " 14 -1 1 525312 models.common.Conv [1024, 512, 1, 1] \n", + " 15 -1 1 4720640 models.common.Conv [512, 1024, 3, 1] \n", + " 16 -2 1 131584 models.common.Conv [512, 256, 1, 1] \n", + " 17 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 18 [-1, 8] 1 0 models.common.Concat [1] \n", + " 19 -1 1 1377792 models.common.Bottleneck [768, 512, False] \n", + " 20 -1 1 1312256 models.common.Bottleneck [512, 512, False] \n", + " 21 -1 1 131584 models.common.Conv [512, 256, 1, 1] \n", + " 22 -1 1 1180672 models.common.Conv [256, 512, 3, 1] \n", + " 23 -2 1 33024 models.common.Conv [256, 128, 1, 1] \n", + " 24 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 25 [-1, 6] 1 0 models.common.Concat [1] \n", + " 26 -1 1 344832 models.common.Bottleneck [384, 256, False] \n", + " 27 -1 2 656896 models.common.Bottleneck [256, 256, False] \n", + " 28 [27, 22, 15] 1 457725 models.yolo.Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [256, 512, 1024]]\n", + "Model Summary: 333 layers, 61949149 parameters, 61949149 gradients\n", + "\n", + "Transferred 440/440 items from yolov3.pt\n", + "Optimizer groups: 75 .bias, 75 conv.weight, 72 other\n", + "Scanning '../coco128/labels/train2017' for images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 3001.29it/s]\n", + "New cache created: ../coco128/labels/train2017.cache\n", + "Scanning '../coco128/labels/train2017.cache' for images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 985084.24it/s]\n", + "Caching images (0.1GB): 100% 128/128 [00:00<00:00, 194.34it/s]\n", + "Scanning '../coco128/labels/train2017.cache' for images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 711087.30it/s]\n", + "Caching images (0.1GB): 100% 128/128 [00:00<00:00, 133.98it/s]\n", + "NumExpr defaulting to 2 threads.\n", + "\n", + "Analyzing anchors... anchors/target = 4.26, Best Possible Recall (BPR) = 0.9946\n", + "Image sizes 640 train, 640 test\n", + "Using 2 dataloader workers\n", + "Logging results to runs/train/exp\n", + "Starting training for 3 epochs...\n", + "\n", + " Epoch gpu_mem box obj cls total targets img_size\n", + " 0/2 8.88G 0.02999 0.02589 0.008271 0.06414 155 640: 100% 8/8 [00:06<00:00, 1.23it/s]\n", + " Class Images Targets P R mAP@.5 mAP@.5:.95: 100% 8/8 [00:06<00:00, 1.19it/s]\n", + " all 128 929 0.527 0.83 0.782 0.547\n", + "\n", + " Epoch gpu_mem box obj cls total targets img_size\n", + " 1/2 8.87G 0.02966 0.02563 0.008289 0.06358 190 640: 100% 8/8 [00:02<00:00, 3.09it/s]\n", + " Class Images Targets P R mAP@.5 mAP@.5:.95: 100% 8/8 [00:01<00:00, 5.90it/s]\n", + " all 128 929 0.528 0.831 0.784 0.55\n", + "\n", + " Epoch gpu_mem box obj cls total targets img_size\n", + " 2/2 8.87G 0.02947 0.02217 0.009194 0.06083 135 640: 100% 8/8 [00:02<00:00, 3.02it/s]\n", + " Class Images Targets P R mAP@.5 mAP@.5:.95: 100% 8/8 [00:02<00:00, 3.07it/s]\n", + " all 128 929 0.528 0.834 0.784 0.55\n", + "Optimizer stripped from runs/train/exp/weights/last.pt, 124.2MB\n", + "Optimizer stripped from runs/train/exp/weights/best.pt, 124.2MB\n", + "3 epochs completed in 0.009 hours.\n", + "\n" + ], + "name": "stdout" + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "15glLzbQx5u0" + }, + "source": [ + "# 4. Visualize" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DLI1JmHU7B0l" + }, + "source": [ + "## Weights & Biases Logging 🌟 NEW\n", + "\n", + "[Weights & Biases](https://www.wandb.com/) (W&B) is now integrated with YOLOv3 for real-time visualization and cloud logging of training runs. This allows for better run comparison and introspection, as well improved visibility and collaboration for teams. To enable W&B `pip install wandb`, and then train normally (you will be guided through setup on first use). \n", + "\n", + "During training you will see live updates at [https://wandb.ai/home](https://wandb.ai/home), and you can create and share detailed [Reports](https://wandb.ai/glenn-jocher/yolov5_tutorial/reports/YOLOv5-COCO128-Tutorial-Results--VmlldzozMDI5OTY) of your results. For more information see the [YOLOv5 Weights & Biases Tutorial](https://github.com/ultralytics/yolov5/issues/1289). \n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-WPvRbS5Swl6" + }, + "source": [ + "## Local Logging\n", + "\n", + "All results are logged by default to `runs/train`, with a new experiment directory created for each new training as `runs/train/exp2`, `runs/train/exp3`, etc. View train and test jpgs to see mosaics, labels, predictions and augmentation effects. Note a **Mosaic Dataloader** is used for training (shown below), a new concept developed by Ultralytics and first featured in [YOLOv4](https://arxiv.org/abs/2004.10934)." ] - }, - "execution_count": 8, - "metadata": { - "image/png": { - "width": 800 - }, - "tags": [] - }, - "output_type": "execute_result" + }, + { + "cell_type": "code", + "metadata": { + "id": "riPdhraOTCO0" + }, + "source": [ + "Image(filename='runs/train/exp/train_batch0.jpg', width=800) # train batch 0 mosaics and labels\n", + "Image(filename='runs/train/exp/test_batch0_labels.jpg', width=800) # test batch 0 labels\n", + "Image(filename='runs/train/exp/test_batch0_pred.jpg', width=800) # test batch 0 predictions" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "OYG4WFEnTVrI" + }, + "source": [ + "> \n", + "`train_batch0.jpg` shows train batch 0 mosaics and labels\n", + "\n", + "> \n", + "`test_batch0_labels.jpg` shows test batch 0 labels\n", + "\n", + "> \n", + "`test_batch0_pred.jpg` shows test batch 0 _predictions_\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7KN5ghjE6ZWh" + }, + "source": [ + "Training losses and performance metrics are also logged to [Tensorboard](https://www.tensorflow.org/tensorboard) and a custom `results.txt` logfile which is plotted as `results.png` (below) after training completes. Here we show YOLOv3 trained on COCO128 to 300 epochs, starting from scratch (blue), and from pretrained `--weights yolov3.pt` (orange)." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "MDznIqPF7nk3" + }, + "source": [ + "from utils.plots import plot_results \n", + "plot_results(save_dir='runs/train/exp') # plot all results*.txt as results.png\n", + "Image(filename='runs/train/exp/results.png', width=800)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "lfrEegCSW3fK" + }, + "source": [ + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Zelyeqbyt3GD" + }, + "source": [ + "# Environments\n", + "\n", + "YOLOv3 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):\n", + "\n", + "- **Google Colab Notebook** with free GPU: \"Open\n", + "- **Kaggle Notebook** with free GPU: [https://www.kaggle.com/ultralytics/yolov3](https://www.kaggle.com/ultralytics/yolov3)\n", + "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) \n", + "- **Docker Image** https://hub.docker.com/r/ultralytics/yolov3. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) ![Docker Pulls](https://img.shields.io/docker/pulls/ultralytics/yolov3?logo=docker)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IEijrePND_2I" + }, + "source": [ + "# Appendix\n", + "\n", + "Optional extras below. Unit tests validate repo functionality and should be run on any PRs submitted.\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "gI6NoBev8Ib1" + }, + "source": [ + "# Re-clone repo\n", + "%cd ..\n", + "%rm -rf yolov3 && git clone https://github.com/ultralytics/yolov3\n", + "%cd yolov3" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "mcKoSIK2WSzj" + }, + "source": [ + "# Test all\n", + "%%shell\n", + "for x in yolov3 yolov3-spp yolov3-tiny; do\n", + " python test.py --weights $x.pt --data coco.yaml --img 640\n", + "done" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "FGH0ZjkGjejy" + }, + "source": [ + "# Unit tests\n", + "%%shell\n", + "export PYTHONPATH=\"$PWD\" # to run *.py. files in subdirectories\n", + "\n", + "rm -rf runs # remove runs/\n", + "for m in yolov3; do # models\n", + " python train.py --weights $m.pt --epochs 3 --img 320 --device 0 # train pretrained\n", + " python train.py --weights '' --cfg $m.yaml --epochs 3 --img 320 --device 0 # train scratch\n", + " for d in 0 cpu; do # devices\n", + " python detect.py --weights $m.pt --device $d # detect official\n", + " python detect.py --weights runs/train/exp/weights/best.pt --device $d # detect custom\n", + " python test.py --weights $m.pt --device $d # test official\n", + " python test.py --weights runs/train/exp/weights/best.pt --device $d # test custom\n", + " done\n", + " python hubconf.py # hub\n", + " python models/yolo.py --cfg $m.yaml # inspect\n", + " python models/export.py --weights $m.pt --img 640 --batch 1 # export\n", + "done" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "BSgFCAcMbk1R" + }, + "source": [ + "# VOC\n", + "for b, m in zip([24, 24, 64], ['yolov3', 'yolov3-spp', 'yolov3-tiny']): # zip(batch_size, model)\n", + " !python train.py --batch {b} --weights {m}.pt --data voc.yaml --epochs 50 --cache --img 512 --nosave --hyp hyp.finetune.yaml --project VOC --name {m}" + ], + "execution_count": null, + "outputs": [] } - ], - "source": [ - "!python3 train.py --data data/coco_16img.data --batch-size 16 --accumulate 1 --nosave && mv results.txt results_coco_16img.txt # CUSTOM TRAINING EXAMPLE\n", - "!python3 train.py --data data/coco_64img.data --batch-size 16 --accumulate 1 --nosave && mv results.txt results_coco_64img.txt \n", - "!python3 -c \"from utils import utils; utils.plot_results()\" # plot training results\n", - "Image(filename='results.png', width=800)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "14mT7T7Q6erR" - }, - "source": [ - "Extras below\n", - "\n", - "---\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "colab": {}, - "colab_type": "code", - "id": "42_zEpW6W_N1" - }, - "outputs": [], - "source": [ - "!git pull" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "colab": {}, - "colab_type": "code", - "id": "9bVTcveIOzDd" - }, - "outputs": [], - "source": [ - "%cd yolov3" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "colab": {}, - "colab_type": "code", - "id": "odMr0JFnCEyb" - }, - "outputs": [], - "source": [ - "%ls" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "colab": {}, - "colab_type": "code", - "id": "uB3v5hj_CEyI" - }, - "outputs": [], - "source": [ - "# Unit Tests\n", - "!python3 detect.py # detect 2 persons, 1 tie\n", - "!python3 test.py --data data/coco_32img.data # test mAP = 0.8\n", - "!python3 train.py --data data/coco_32img.data --epochs 3 --nosave # train 3 epochs" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "colab": {}, - "colab_type": "code", - "id": "6D0si0TNCEx5" - }, - "outputs": [], - "source": [ - "# Evolve Hyperparameters\n", - "!python3 train.py --data data/coco.data --img-size 320 --epochs 1 --evolve" - ] - } - ], - "metadata": { - "accelerator": "GPU", - "colab": { - "collapsed_sections": [], - "name": "ultralytics/YOLOv3", - "provenance": [], - "version": "0.3.2" - }, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.4" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} + ] +} \ No newline at end of file diff --git a/utils/activations.py b/utils/activations.py new file mode 100644 index 0000000000..ba6b854ddc --- /dev/null +++ b/utils/activations.py @@ -0,0 +1,72 @@ +# Activation functions + +import torch +import torch.nn as nn +import torch.nn.functional as F + + +# Swish https://arxiv.org/pdf/1905.02244.pdf --------------------------------------------------------------------------- +class Swish(nn.Module): # + @staticmethod + def forward(x): + return x * torch.sigmoid(x) + + +class Hardswish(nn.Module): # export-friendly version of nn.Hardswish() + @staticmethod + def forward(x): + # return x * F.hardsigmoid(x) # for torchscript and CoreML + return x * F.hardtanh(x + 3, 0., 6.) / 6. # for torchscript, CoreML and ONNX + + +class MemoryEfficientSwish(nn.Module): + class F(torch.autograd.Function): + @staticmethod + def forward(ctx, x): + ctx.save_for_backward(x) + return x * torch.sigmoid(x) + + @staticmethod + def backward(ctx, grad_output): + x = ctx.saved_tensors[0] + sx = torch.sigmoid(x) + return grad_output * (sx * (1 + x * (1 - sx))) + + def forward(self, x): + return self.F.apply(x) + + +# Mish https://github.com/digantamisra98/Mish -------------------------------------------------------------------------- +class Mish(nn.Module): + @staticmethod + def forward(x): + return x * F.softplus(x).tanh() + + +class MemoryEfficientMish(nn.Module): + class F(torch.autograd.Function): + @staticmethod + def forward(ctx, x): + ctx.save_for_backward(x) + return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x))) + + @staticmethod + def backward(ctx, grad_output): + x = ctx.saved_tensors[0] + sx = torch.sigmoid(x) + fx = F.softplus(x).tanh() + return grad_output * (fx + x * sx * (1 - fx * fx)) + + def forward(self, x): + return self.F.apply(x) + + +# FReLU https://arxiv.org/abs/2007.11824 ------------------------------------------------------------------------------- +class FReLU(nn.Module): + def __init__(self, c1, k=3): # ch_in, kernel + super().__init__() + self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1) + self.bn = nn.BatchNorm2d(c1) + + def forward(self, x): + return torch.max(x, self.bn(self.conv(x))) diff --git a/utils/adabound.py b/utils/adabound.py deleted file mode 100644 index 8baa378057..0000000000 --- a/utils/adabound.py +++ /dev/null @@ -1,236 +0,0 @@ -import math - -import torch -from torch.optim.optimizer import Optimizer - - -class AdaBound(Optimizer): - """Implements AdaBound algorithm. - It has been proposed in `Adaptive Gradient Methods with Dynamic Bound of Learning Rate`_. - Arguments: - params (iterable): iterable of parameters to optimize or dicts defining - parameter groups - lr (float, optional): Adam learning rate (default: 1e-3) - betas (Tuple[float, float], optional): coefficients used for computing - running averages of gradient and its square (default: (0.9, 0.999)) - final_lr (float, optional): final (SGD) learning rate (default: 0.1) - gamma (float, optional): convergence speed of the bound functions (default: 1e-3) - eps (float, optional): term added to the denominator to improve - numerical stability (default: 1e-8) - weight_decay (float, optional): weight decay (L2 penalty) (default: 0) - amsbound (boolean, optional): whether to use the AMSBound variant of this algorithm - .. Adaptive Gradient Methods with Dynamic Bound of Learning Rate: - https://openreview.net/forum?id=Bkg3g2R9FX - """ - - def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), final_lr=0.1, gamma=1e-3, - eps=1e-8, weight_decay=0, amsbound=False): - if not 0.0 <= lr: - raise ValueError("Invalid learning rate: {}".format(lr)) - if not 0.0 <= eps: - raise ValueError("Invalid epsilon value: {}".format(eps)) - if not 0.0 <= betas[0] < 1.0: - raise ValueError("Invalid beta parameter at index 0: {}".format(betas[0])) - if not 0.0 <= betas[1] < 1.0: - raise ValueError("Invalid beta parameter at index 1: {}".format(betas[1])) - if not 0.0 <= final_lr: - raise ValueError("Invalid final learning rate: {}".format(final_lr)) - if not 0.0 <= gamma < 1.0: - raise ValueError("Invalid gamma parameter: {}".format(gamma)) - defaults = dict(lr=lr, betas=betas, final_lr=final_lr, gamma=gamma, eps=eps, - weight_decay=weight_decay, amsbound=amsbound) - super(AdaBound, self).__init__(params, defaults) - - self.base_lrs = list(map(lambda group: group['lr'], self.param_groups)) - - def __setstate__(self, state): - super(AdaBound, self).__setstate__(state) - for group in self.param_groups: - group.setdefault('amsbound', False) - - def step(self, closure=None): - """Performs a single optimization step. - Arguments: - closure (callable, optional): A closure that reevaluates the model - and returns the loss. - """ - loss = None - if closure is not None: - loss = closure() - - for group, base_lr in zip(self.param_groups, self.base_lrs): - for p in group['params']: - if p.grad is None: - continue - grad = p.grad.data - if grad.is_sparse: - raise RuntimeError( - 'Adam does not support sparse gradients, please consider SparseAdam instead') - amsbound = group['amsbound'] - - state = self.state[p] - - # State initialization - if len(state) == 0: - state['step'] = 0 - # Exponential moving average of gradient values - state['exp_avg'] = torch.zeros_like(p.data) - # Exponential moving average of squared gradient values - state['exp_avg_sq'] = torch.zeros_like(p.data) - if amsbound: - # Maintains max of all exp. moving avg. of sq. grad. values - state['max_exp_avg_sq'] = torch.zeros_like(p.data) - - exp_avg, exp_avg_sq = state['exp_avg'], state['exp_avg_sq'] - if amsbound: - max_exp_avg_sq = state['max_exp_avg_sq'] - beta1, beta2 = group['betas'] - - state['step'] += 1 - - if group['weight_decay'] != 0: - grad = grad.add(group['weight_decay'], p.data) - - # Decay the first and second moment running average coefficient - exp_avg.mul_(beta1).add_(1 - beta1, grad) - exp_avg_sq.mul_(beta2).addcmul_(1 - beta2, grad, grad) - if amsbound: - # Maintains the maximum of all 2nd moment running avg. till now - torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq) - # Use the max. for normalizing running avg. of gradient - denom = max_exp_avg_sq.sqrt().add_(group['eps']) - else: - denom = exp_avg_sq.sqrt().add_(group['eps']) - - bias_correction1 = 1 - beta1 ** state['step'] - bias_correction2 = 1 - beta2 ** state['step'] - step_size = group['lr'] * math.sqrt(bias_correction2) / bias_correction1 - - # Applies bounds on actual learning rate - # lr_scheduler cannot affect final_lr, this is a workaround to apply lr decay - final_lr = group['final_lr'] * group['lr'] / base_lr - lower_bound = final_lr * (1 - 1 / (group['gamma'] * state['step'] + 1)) - upper_bound = final_lr * (1 + 1 / (group['gamma'] * state['step'])) - step_size = torch.full_like(denom, step_size) - step_size.div_(denom).clamp_(lower_bound, upper_bound).mul_(exp_avg) - - p.data.add_(-step_size) - - return loss - - -class AdaBoundW(Optimizer): - """Implements AdaBound algorithm with Decoupled Weight Decay (arxiv.org/abs/1711.05101) - It has been proposed in `Adaptive Gradient Methods with Dynamic Bound of Learning Rate`_. - Arguments: - params (iterable): iterable of parameters to optimize or dicts defining - parameter groups - lr (float, optional): Adam learning rate (default: 1e-3) - betas (Tuple[float, float], optional): coefficients used for computing - running averages of gradient and its square (default: (0.9, 0.999)) - final_lr (float, optional): final (SGD) learning rate (default: 0.1) - gamma (float, optional): convergence speed of the bound functions (default: 1e-3) - eps (float, optional): term added to the denominator to improve - numerical stability (default: 1e-8) - weight_decay (float, optional): weight decay (L2 penalty) (default: 0) - amsbound (boolean, optional): whether to use the AMSBound variant of this algorithm - .. Adaptive Gradient Methods with Dynamic Bound of Learning Rate: - https://openreview.net/forum?id=Bkg3g2R9FX - """ - - def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), final_lr=0.1, gamma=1e-3, - eps=1e-8, weight_decay=0, amsbound=False): - if not 0.0 <= lr: - raise ValueError("Invalid learning rate: {}".format(lr)) - if not 0.0 <= eps: - raise ValueError("Invalid epsilon value: {}".format(eps)) - if not 0.0 <= betas[0] < 1.0: - raise ValueError("Invalid beta parameter at index 0: {}".format(betas[0])) - if not 0.0 <= betas[1] < 1.0: - raise ValueError("Invalid beta parameter at index 1: {}".format(betas[1])) - if not 0.0 <= final_lr: - raise ValueError("Invalid final learning rate: {}".format(final_lr)) - if not 0.0 <= gamma < 1.0: - raise ValueError("Invalid gamma parameter: {}".format(gamma)) - defaults = dict(lr=lr, betas=betas, final_lr=final_lr, gamma=gamma, eps=eps, - weight_decay=weight_decay, amsbound=amsbound) - super(AdaBoundW, self).__init__(params, defaults) - - self.base_lrs = list(map(lambda group: group['lr'], self.param_groups)) - - def __setstate__(self, state): - super(AdaBoundW, self).__setstate__(state) - for group in self.param_groups: - group.setdefault('amsbound', False) - - def step(self, closure=None): - """Performs a single optimization step. - Arguments: - closure (callable, optional): A closure that reevaluates the model - and returns the loss. - """ - loss = None - if closure is not None: - loss = closure() - - for group, base_lr in zip(self.param_groups, self.base_lrs): - for p in group['params']: - if p.grad is None: - continue - grad = p.grad.data - if grad.is_sparse: - raise RuntimeError( - 'Adam does not support sparse gradients, please consider SparseAdam instead') - amsbound = group['amsbound'] - - state = self.state[p] - - # State initialization - if len(state) == 0: - state['step'] = 0 - # Exponential moving average of gradient values - state['exp_avg'] = torch.zeros_like(p.data) - # Exponential moving average of squared gradient values - state['exp_avg_sq'] = torch.zeros_like(p.data) - if amsbound: - # Maintains max of all exp. moving avg. of sq. grad. values - state['max_exp_avg_sq'] = torch.zeros_like(p.data) - - exp_avg, exp_avg_sq = state['exp_avg'], state['exp_avg_sq'] - if amsbound: - max_exp_avg_sq = state['max_exp_avg_sq'] - beta1, beta2 = group['betas'] - - state['step'] += 1 - - # Decay the first and second moment running average coefficient - exp_avg.mul_(beta1).add_(1 - beta1, grad) - exp_avg_sq.mul_(beta2).addcmul_(1 - beta2, grad, grad) - if amsbound: - # Maintains the maximum of all 2nd moment running avg. till now - torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq) - # Use the max. for normalizing running avg. of gradient - denom = max_exp_avg_sq.sqrt().add_(group['eps']) - else: - denom = exp_avg_sq.sqrt().add_(group['eps']) - - bias_correction1 = 1 - beta1 ** state['step'] - bias_correction2 = 1 - beta2 ** state['step'] - step_size = group['lr'] * math.sqrt(bias_correction2) / bias_correction1 - - # Applies bounds on actual learning rate - # lr_scheduler cannot affect final_lr, this is a workaround to apply lr decay - final_lr = group['final_lr'] * group['lr'] / base_lr - lower_bound = final_lr * (1 - 1 / (group['gamma'] * state['step'] + 1)) - upper_bound = final_lr * (1 + 1 / (group['gamma'] * state['step'])) - step_size = torch.full_like(denom, step_size) - step_size.div_(denom).clamp_(lower_bound, upper_bound).mul_(exp_avg) - - if group['weight_decay'] != 0: - decayed_weights = torch.mul(p.data, group['weight_decay']) - p.data.add_(-step_size) - p.data.sub_(decayed_weights) - else: - p.data.add_(-step_size) - - return loss diff --git a/utils/autoanchor.py b/utils/autoanchor.py new file mode 100644 index 0000000000..b678bbbd78 --- /dev/null +++ b/utils/autoanchor.py @@ -0,0 +1,152 @@ +# Auto-anchor utils + +import numpy as np +import torch +import yaml +from scipy.cluster.vq import kmeans +from tqdm import tqdm + + +def check_anchor_order(m): + # Check anchor order against stride order for YOLOv3 Detect() module m, and correct if necessary + a = m.anchor_grid.prod(-1).view(-1) # anchor area + da = a[-1] - a[0] # delta a + ds = m.stride[-1] - m.stride[0] # delta s + if da.sign() != ds.sign(): # same order + print('Reversing anchor order') + m.anchors[:] = m.anchors.flip(0) + m.anchor_grid[:] = m.anchor_grid.flip(0) + + +def check_anchors(dataset, model, thr=4.0, imgsz=640): + # Check anchor fit to data, recompute if necessary + print('\nAnalyzing anchors... ', end='') + m = model.module.model[-1] if hasattr(model, 'module') else model.model[-1] # Detect() + shapes = imgsz * dataset.shapes / dataset.shapes.max(1, keepdims=True) + scale = np.random.uniform(0.9, 1.1, size=(shapes.shape[0], 1)) # augment scale + wh = torch.tensor(np.concatenate([l[:, 3:5] * s for s, l in zip(shapes * scale, dataset.labels)])).float() # wh + + def metric(k): # compute metric + r = wh[:, None] / k[None] + x = torch.min(r, 1. / r).min(2)[0] # ratio metric + best = x.max(1)[0] # best_x + aat = (x > 1. / thr).float().sum(1).mean() # anchors above threshold + bpr = (best > 1. / thr).float().mean() # best possible recall + return bpr, aat + + bpr, aat = metric(m.anchor_grid.clone().cpu().view(-1, 2)) + print('anchors/target = %.2f, Best Possible Recall (BPR) = %.4f' % (aat, bpr), end='') + if bpr < 0.98: # threshold to recompute + print('. Attempting to improve anchors, please wait...') + na = m.anchor_grid.numel() // 2 # number of anchors + new_anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False) + new_bpr = metric(new_anchors.reshape(-1, 2))[0] + if new_bpr > bpr: # replace anchors + new_anchors = torch.tensor(new_anchors, device=m.anchors.device).type_as(m.anchors) + m.anchor_grid[:] = new_anchors.clone().view_as(m.anchor_grid) # for inference + m.anchors[:] = new_anchors.clone().view_as(m.anchors) / m.stride.to(m.anchors.device).view(-1, 1, 1) # loss + check_anchor_order(m) + print('New anchors saved to model. Update model *.yaml to use these anchors in the future.') + else: + print('Original anchors better than new anchors. Proceeding with original anchors.') + print('') # newline + + +def kmean_anchors(path='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=1000, verbose=True): + """ Creates kmeans-evolved anchors from training dataset + + Arguments: + path: path to dataset *.yaml, or a loaded dataset + n: number of anchors + img_size: image size used for training + thr: anchor-label wh ratio threshold hyperparameter hyp['anchor_t'] used for training, default=4.0 + gen: generations to evolve anchors using genetic algorithm + verbose: print all results + + Return: + k: kmeans evolved anchors + + Usage: + from utils.autoanchor import *; _ = kmean_anchors() + """ + thr = 1. / thr + + def metric(k, wh): # compute metrics + r = wh[:, None] / k[None] + x = torch.min(r, 1. / r).min(2)[0] # ratio metric + # x = wh_iou(wh, torch.tensor(k)) # iou metric + return x, x.max(1)[0] # x, best_x + + def anchor_fitness(k): # mutation fitness + _, best = metric(torch.tensor(k, dtype=torch.float32), wh) + return (best * (best > thr).float()).mean() # fitness + + def print_results(k): + k = k[np.argsort(k.prod(1))] # sort small to large + x, best = metric(k, wh0) + bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr + print('thr=%.2f: %.4f best possible recall, %.2f anchors past thr' % (thr, bpr, aat)) + print('n=%g, img_size=%s, metric_all=%.3f/%.3f-mean/best, past_thr=%.3f-mean: ' % + (n, img_size, x.mean(), best.mean(), x[x > thr].mean()), end='') + for i, x in enumerate(k): + print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg + return k + + if isinstance(path, str): # *.yaml file + with open(path) as f: + data_dict = yaml.load(f, Loader=yaml.FullLoader) # model dict + from utils.datasets import LoadImagesAndLabels + dataset = LoadImagesAndLabels(data_dict['train'], augment=True, rect=True) + else: + dataset = path # dataset + + # Get label wh + shapes = img_size * dataset.shapes / dataset.shapes.max(1, keepdims=True) + wh0 = np.concatenate([l[:, 3:5] * s for s, l in zip(shapes, dataset.labels)]) # wh + + # Filter + i = (wh0 < 3.0).any(1).sum() + if i: + print('WARNING: Extremely small objects found. ' + '%g of %g labels are < 3 pixels in width or height.' % (i, len(wh0))) + wh = wh0[(wh0 >= 2.0).any(1)] # filter > 2 pixels + + # Kmeans calculation + print('Running kmeans for %g anchors on %g points...' % (n, len(wh))) + s = wh.std(0) # sigmas for whitening + k, dist = kmeans(wh / s, n, iter=30) # points, mean distance + k *= s + wh = torch.tensor(wh, dtype=torch.float32) # filtered + wh0 = torch.tensor(wh0, dtype=torch.float32) # unfiltered + k = print_results(k) + + # Plot + # k, d = [None] * 20, [None] * 20 + # for i in tqdm(range(1, 21)): + # k[i-1], d[i-1] = kmeans(wh / s, i) # points, mean distance + # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) + # ax = ax.ravel() + # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.') + # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # plot wh + # ax[0].hist(wh[wh[:, 0]<100, 0],400) + # ax[1].hist(wh[wh[:, 1]<100, 1],400) + # fig.tight_layout() + # fig.savefig('wh.png', dpi=200) + + # Evolve + npr = np.random + f, sh, mp, s = anchor_fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma + pbar = tqdm(range(gen), desc='Evolving anchors with Genetic Algorithm') # progress bar + for _ in pbar: + v = np.ones(sh) + while (v == 1).all(): # mutate until a change occurs (prevent duplicates) + v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) + kg = (k.copy() * v).clip(min=2.0) + fg = anchor_fitness(kg) + if fg > f: + f, k = fg, kg.copy() + pbar.desc = 'Evolving anchors with Genetic Algorithm: fitness = %.4f' % f + if verbose: + print_results(k) + + return print_results(k) diff --git a/utils/datasets.py b/utils/datasets.py index 6bb818038c..7203d96299 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -1,9 +1,14 @@ +# Dataset utils and dataloaders + import glob +import logging import math import os import random import shutil import time +from itertools import repeat +from multiprocessing.pool import ThreadPool from pathlib import Path from threading import Thread @@ -14,11 +19,14 @@ from torch.utils.data import Dataset from tqdm import tqdm -from utils.utils import xyxy2xywh, xywh2xyxy +from utils.general import xyxy2xywh, xywh2xyxy +from utils.torch_utils import torch_distributed_zero_first +# Parameters help_url = 'https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' -img_formats = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.tiff', '.dng'] -vid_formats = ['.mov', '.avi', '.mp4', '.mpg', '.mpeg', '.m4v', '.wmv', '.mkv'] +img_formats = ['bmp', 'jpg', 'jpeg', 'png', 'tif', 'tiff', 'dng'] # acceptable image suffixes +vid_formats = ['mov', 'avi', 'mp4', 'mpg', 'mpeg', 'm4v', 'wmv', 'mkv'] # acceptable video suffixes +logger = logging.getLogger(__name__) # Get orientation exif tag for orientation in ExifTags.TAGS.keys(): @@ -26,6 +34,11 @@ break +def get_hash(files): + # Returns a single hash value of a list of files + return sum(os.path.getsize(f) for f in files if os.path.isfile(f)) + + def exif_size(img): # Returns exif-corrected PIL size s = img.size # (width, height) @@ -41,37 +54,104 @@ def exif_size(img): return s +def create_dataloader(path, imgsz, batch_size, stride, opt, hyp=None, augment=False, cache=False, pad=0.0, rect=False, + rank=-1, world_size=1, workers=8, image_weights=False): + # Make sure only the first process in DDP process the dataset first, and the following others can use the cache + with torch_distributed_zero_first(rank): + dataset = LoadImagesAndLabels(path, imgsz, batch_size, + augment=augment, # augment images + hyp=hyp, # augmentation hyperparameters + rect=rect, # rectangular training + cache_images=cache, + single_cls=opt.single_cls, + stride=int(stride), + pad=pad, + rank=rank, + image_weights=image_weights) + + batch_size = min(batch_size, len(dataset)) + nw = min([os.cpu_count() // world_size, batch_size if batch_size > 1 else 0, workers]) # number of workers + sampler = torch.utils.data.distributed.DistributedSampler(dataset) if rank != -1 else None + loader = torch.utils.data.DataLoader if image_weights else InfiniteDataLoader + # Use torch.utils.data.DataLoader() if dataset.properties will update during training else InfiniteDataLoader() + dataloader = loader(dataset, + batch_size=batch_size, + num_workers=nw, + sampler=sampler, + pin_memory=True, + collate_fn=LoadImagesAndLabels.collate_fn) + return dataloader, dataset + + +class InfiniteDataLoader(torch.utils.data.dataloader.DataLoader): + """ Dataloader that reuses workers + + Uses same syntax as vanilla DataLoader + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + object.__setattr__(self, 'batch_sampler', _RepeatSampler(self.batch_sampler)) + self.iterator = super().__iter__() + + def __len__(self): + return len(self.batch_sampler.sampler) + + def __iter__(self): + for i in range(len(self)): + yield next(self.iterator) + + +class _RepeatSampler(object): + """ Sampler that repeats forever + + Args: + sampler (Sampler) + """ + + def __init__(self, sampler): + self.sampler = sampler + + def __iter__(self): + while True: + yield from iter(self.sampler) + + class LoadImages: # for inference - def __init__(self, path, img_size=416): - path = str(Path(path)) # os-agnostic - files = [] - if os.path.isdir(path): - files = sorted(glob.glob(os.path.join(path, '*.*'))) - elif os.path.isfile(path): - files = [path] - - images = [x for x in files if os.path.splitext(x)[-1].lower() in img_formats] - videos = [x for x in files if os.path.splitext(x)[-1].lower() in vid_formats] - nI, nV = len(images), len(videos) + def __init__(self, path, img_size=640): + p = str(Path(path)) # os-agnostic + p = os.path.abspath(p) # absolute path + if '*' in p: + files = sorted(glob.glob(p, recursive=True)) # glob + elif os.path.isdir(p): + files = sorted(glob.glob(os.path.join(p, '*.*'))) # dir + elif os.path.isfile(p): + files = [p] # files + else: + raise Exception('ERROR: %s does not exist' % p) + + images = [x for x in files if x.split('.')[-1].lower() in img_formats] + videos = [x for x in files if x.split('.')[-1].lower() in vid_formats] + ni, nv = len(images), len(videos) self.img_size = img_size self.files = images + videos - self.nF = nI + nV # number of files - self.video_flag = [False] * nI + [True] * nV + self.nf = ni + nv # number of files + self.video_flag = [False] * ni + [True] * nv self.mode = 'images' if any(videos): self.new_video(videos[0]) # new video else: self.cap = None - assert self.nF > 0, 'No images or videos found in %s. Supported formats are:\nimages: %s\nvideos: %s' % \ - (path, img_formats, vid_formats) + assert self.nf > 0, 'No images or videos found in %s. Supported formats are:\nimages: %s\nvideos: %s' % \ + (p, img_formats, vid_formats) def __iter__(self): self.count = 0 return self def __next__(self): - if self.count == self.nF: + if self.count == self.nf: raise StopIteration path = self.files[self.count] @@ -82,7 +162,7 @@ def __next__(self): if not ret_val: self.count += 1 self.cap.release() - if self.count == self.nF: # last video + if self.count == self.nf: # last video raise StopIteration else: path = self.files[self.count] @@ -90,14 +170,14 @@ def __next__(self): ret_val, img0 = self.cap.read() self.frame += 1 - print('video %g/%g (%g/%g) %s: ' % (self.count + 1, self.nF, self.frame, self.nframes, path), end='') + print('video %g/%g (%g/%g) %s: ' % (self.count + 1, self.nf, self.frame, self.nframes, path), end='') else: # Read image self.count += 1 img0 = cv2.imread(path) # BGR assert img0 is not None, 'Image Not Found ' + path - print('image %g/%g %s: ' % (self.count, self.nF, path), end='') + print('image %g/%g %s: ' % (self.count, self.nf, path), end='') # Padded resize img = letterbox(img0, new_shape=self.img_size)[0] @@ -106,7 +186,6 @@ def __next__(self): img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 img = np.ascontiguousarray(img) - # cv2.imwrite(path + '.letterbox.jpg', 255 * img.transpose((1, 2, 0))[:, :, ::-1]) # save letterbox image return path, img, img0, self.cap def new_video(self, path): @@ -115,27 +194,19 @@ def new_video(self, path): self.nframes = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT)) def __len__(self): - return self.nF # number of files + return self.nf # number of files class LoadWebcam: # for inference - def __init__(self, pipe=0, img_size=416): + def __init__(self, pipe='0', img_size=640): self.img_size = img_size - if pipe == '0': - pipe = 0 # local camera + if pipe.isnumeric(): + pipe = eval(pipe) # local camera # pipe = 'rtsp://192.168.1.64/1' # IP camera # pipe = 'rtsp://username:password@192.168.1.64/1' # IP camera with login - # pipe = 'rtsp://170.93.143.139/rtplive/470011e600ef003a004ee33696235daa' # IP traffic camera # pipe = 'http://wmccpinetop.axiscam.net/mjpg/video.mjpg' # IP golf camera - # https://answers.opencv.org/question/215996/changing-gstreamer-pipeline-to-opencv-in-pythonsolved/ - # pipe = '"rtspsrc location="rtsp://username:password@192.168.1.64/1" latency=10 ! appsink' # GStreamer - - # https://answers.opencv.org/question/200787/video-acceleration-gstremer-pipeline-in-videocapture/ - # https://stackoverflow.com/questions/54095699/install-gstreamer-support-for-opencv-python-package # install help - # pipe = "rtspsrc location=rtsp://root:root@192.168.0.91:554/axis-media/media.amp?videocodec=h264&resolution=3840x2160 protocols=GST_RTSP_LOWER_TRANS_TCP ! rtph264depay ! queue ! vaapih264dec ! videoconvert ! appsink" # GStreamer - self.pipe = pipe self.cap = cv2.VideoCapture(pipe) # video capture object self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 3) # set buffer size @@ -184,7 +255,7 @@ def __len__(self): class LoadStreams: # multiple IP or RTSP cameras - def __init__(self, sources='streams.txt', img_size=416): + def __init__(self, sources='streams.txt', img_size=640): self.mode = 'images' self.img_size = img_size @@ -200,7 +271,7 @@ def __init__(self, sources='streams.txt', img_size=416): for i, s in enumerate(sources): # Start the thread to read frames from the video stream print('%g/%g: %s... ' % (i + 1, n, s), end='') - cap = cv2.VideoCapture(0 if s == '0' else s) + cap = cv2.VideoCapture(eval(s) if s.isnumeric() else s) assert cap.isOpened(), 'Failed to open %s' % s w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) @@ -256,55 +327,77 @@ def __len__(self): return 0 # 1E12 frames = 32 streams at 30 FPS for 30 years -class LoadImagesAndLabels(Dataset): # for training/testing - def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, - cache_images=False, single_cls=False, pad=0.0): - try: - path = str(Path(path)) # os-agnostic - parent = str(Path(path).parent) + os.sep - if os.path.isfile(path): # file - with open(path, 'r') as f: - f = f.read().splitlines() - f = [x.replace('./', parent) if x.startswith('./') else x for x in f] # local to global path - elif os.path.isdir(path): # folder - f = glob.iglob(path + os.sep + '*.*') - else: - raise Exception('%s does not exist' % path) - self.img_files = [x.replace('/', os.sep) for x in f if os.path.splitext(x)[-1].lower() in img_formats] - except: - raise Exception('Error loading data from %s. See %s' % (path, help_url)) - - n = len(self.img_files) - assert n > 0, 'No images found in %s. See %s' % (path, help_url) - bi = np.floor(np.arange(n) / batch_size).astype(np.int) # batch index - nb = bi[-1] + 1 # number of batches +def img2label_paths(img_paths): + # Define label paths as a function of image paths + sa, sb = os.sep + 'images' + os.sep, os.sep + 'labels' + os.sep # /images/, /labels/ substrings + return [x.replace(sa, sb, 1).replace('.' + x.split('.')[-1], '.txt') for x in img_paths] - self.n = n # number of images - self.batch = bi # batch index of image + +class LoadImagesAndLabels(Dataset): # for training/testing + def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, + cache_images=False, single_cls=False, stride=32, pad=0.0, rank=-1): self.img_size = img_size self.augment = augment self.hyp = hyp self.image_weights = image_weights self.rect = False if image_weights else rect self.mosaic = self.augment and not self.rect # load 4 images at a time into a mosaic (only during training) + self.mosaic_border = [-img_size // 2, -img_size // 2] + self.stride = stride - # Define labels - self.label_files = [x.replace('images', 'labels').replace(os.path.splitext(x)[-1], '.txt') - for x in self.img_files] - - # Read image shapes (wh) - sp = path.replace('.txt', '') + '.shapes' # shapefile path try: - with open(sp, 'r') as f: # read existing shapefile - s = [x.split() for x in f.read().splitlines()] - assert len(s) == n, 'Shapefile out of sync' - except: - s = [exif_size(Image.open(f)) for f in tqdm(self.img_files, desc='Reading image shapes')] - np.savetxt(sp, s, fmt='%g') # overwrites existing (if any) - - self.shapes = np.array(s, dtype=np.float64) + f = [] # image files + for p in path if isinstance(path, list) else [path]: + p = Path(p) # os-agnostic + if p.is_dir(): # dir + f += glob.glob(str(p / '**' / '*.*'), recursive=True) + elif p.is_file(): # file + with open(p, 'r') as t: + t = t.read().splitlines() + parent = str(p.parent) + os.sep + f += [x.replace('./', parent) if x.startswith('./') else x for x in t] # local to global path + else: + raise Exception('%s does not exist' % p) + self.img_files = sorted([x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in img_formats]) + assert self.img_files, 'No images found' + except Exception as e: + raise Exception('Error loading data from %s: %s\nSee %s' % (path, e, help_url)) + + # Check cache + self.label_files = img2label_paths(self.img_files) # labels + cache_path = Path(self.label_files[0]).parent.with_suffix('.cache') # cached labels + if cache_path.is_file(): + cache = torch.load(cache_path) # load + if cache['hash'] != get_hash(self.label_files + self.img_files) or 'results' not in cache: # changed + cache = self.cache_labels(cache_path) # re-cache + else: + cache = self.cache_labels(cache_path) # cache + + # Display cache + [nf, nm, ne, nc, n] = cache.pop('results') # found, missing, empty, corrupted, total + desc = f"Scanning '{cache_path}' for images and labels... {nf} found, {nm} missing, {ne} empty, {nc} corrupted" + tqdm(None, desc=desc, total=n, initial=n) + assert nf > 0 or not augment, f'No labels found in {cache_path}. Can not train without labels. See {help_url}' + + # Read cache + cache.pop('hash') # remove hash + labels, shapes = zip(*cache.values()) + self.labels = list(labels) + self.shapes = np.array(shapes, dtype=np.float64) + self.img_files = list(cache.keys()) # update + self.label_files = img2label_paths(cache.keys()) # update + if single_cls: + for x in self.labels: + x[:, 0] = 0 + + n = len(shapes) # number of images + bi = np.floor(np.arange(n) / batch_size).astype(np.int) # batch index + nb = bi[-1] + 1 # number of batches + self.batch = bi # batch index of image + self.n = n + self.indices = range(n) - # Rectangular Training https://github.com/ultralytics/yolov3/issues/232 + # Rectangular Training if self.rect: # Sort by aspect ratio s = self.shapes # wh @@ -312,6 +405,7 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r irect = ar.argsort() self.img_files = [self.img_files[i] for i in irect] self.label_files = [self.label_files[i] for i in irect] + self.labels = [self.labels[i] for i in irect] self.shapes = s[irect] # wh ar = ar[irect] @@ -325,107 +419,65 @@ def __init__(self, path, img_size=416, batch_size=16, augment=False, hyp=None, r elif mini > 1: shapes[i] = [1, 1 / mini] - self.batch_shapes = np.ceil(np.array(shapes) * img_size / 32. + pad).astype(np.int) * 32 - - # Cache labels - self.imgs = [None] * n - self.labels = [np.zeros((0, 5), dtype=np.float32)] * n - create_datasubset, extract_bounding_boxes, labels_loaded = False, False, False - nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate - np_labels_path = str(Path(self.label_files[0]).parent) + '.npy' # saved labels in *.npy file - if os.path.isfile(np_labels_path): - s = np_labels_path # print string - x = np.load(np_labels_path, allow_pickle=True) - if len(x) == n: - self.labels = x - labels_loaded = True - else: - s = path.replace('images', 'labels') - - pbar = tqdm(self.label_files) - for i, file in enumerate(pbar): - if labels_loaded: - l = self.labels[i] - # np.savetxt(file, l, '%g') # save *.txt from *.npy file - else: - try: - with open(file, 'r') as f: - l = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) - except: - nm += 1 # print('missing labels for image %s' % self.img_files[i]) # file missing - continue - - if l.shape[0]: - assert l.shape[1] == 5, '> 5 label columns: %s' % file - assert (l >= 0).all(), 'negative labels: %s' % file - assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels: %s' % file - if np.unique(l, axis=0).shape[0] < l.shape[0]: # duplicate rows - nd += 1 # print('WARNING: duplicate rows in %s' % self.label_files[i]) # duplicate rows - if single_cls: - l[:, 0] = 0 # force dataset into single-class mode - self.labels[i] = l - nf += 1 # file found - - # Create subdataset (a smaller dataset) - if create_datasubset and ns < 1E4: - if ns == 0: - create_folder(path='./datasubset') - os.makedirs('./datasubset/images') - exclude_classes = 43 - if exclude_classes not in l[:, 0]: - ns += 1 - # shutil.copy(src=self.img_files[i], dst='./datasubset/images/') # copy image - with open('./datasubset/images.txt', 'a') as f: - f.write(self.img_files[i] + '\n') - - # Extract object detection boxes for a second stage classifier - if extract_bounding_boxes: - p = Path(self.img_files[i]) - img = cv2.imread(str(p)) - h, w = img.shape[:2] - for j, x in enumerate(l): - f = '%s%sclassifier%s%g_%g_%s' % (p.parent.parent, os.sep, os.sep, x[0], j, p.name) - if not os.path.exists(Path(f).parent): - os.makedirs(Path(f).parent) # make new output folder - - b = x[1:] * [w, h, w, h] # box - b[2:] = b[2:].max() # rectangle to square - b[2:] = b[2:] * 1.3 + 30 # pad - b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(np.int) - - b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image - b[[1, 3]] = np.clip(b[[1, 3]], 0, h) - assert cv2.imwrite(f, img[b[1]:b[3], b[0]:b[2]]), 'Failure extracting classifier boxes' - else: - ne += 1 # print('empty labels for image %s' % self.img_files[i]) # file empty - # os.system("rm '%s' '%s'" % (self.img_files[i], self.label_files[i])) # remove - - pbar.desc = 'Caching labels %s (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( - s, nf, nm, ne, nd, n) - assert nf > 0 or n == 20288, 'No labels found in %s. See %s' % (os.path.dirname(file) + os.sep, help_url) - if not labels_loaded and n > 1000: - print('Saving labels to %s for faster future loading' % np_labels_path) - np.save(np_labels_path, self.labels) # save for next time + self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(np.int) * stride # Cache images into memory for faster training (WARNING: large datasets may exceed system RAM) - if cache_images: # if training + self.imgs = [None] * n + if cache_images: gb = 0 # Gigabytes of cached images - pbar = tqdm(range(len(self.img_files)), desc='Caching images') self.img_hw0, self.img_hw = [None] * n, [None] * n - for i in pbar: # max 10k images - self.imgs[i], self.img_hw0[i], self.img_hw[i] = load_image(self, i) # img, hw_original, hw_resized + results = ThreadPool(8).imap(lambda x: load_image(*x), zip(repeat(self), range(n))) # 8 threads + pbar = tqdm(enumerate(results), total=n) + for i, x in pbar: + self.imgs[i], self.img_hw0[i], self.img_hw[i] = x # img, hw_original, hw_resized = load_image(self, i) gb += self.imgs[i].nbytes pbar.desc = 'Caching images (%.1fGB)' % (gb / 1E9) - # Detect corrupted images https://medium.com/joelthchao/programmatically-detect-corrupted-image-8c1b2006c3d3 - detect_corrupted_images = False - if detect_corrupted_images: - from skimage import io # conda install -c conda-forge scikit-image - for file in tqdm(self.img_files, desc='Detecting corrupted images'): - try: - _ = io.imread(file) - except: - print('Corrupted image detected: %s' % file) + def cache_labels(self, path=Path('./labels.cache')): + # Cache dataset labels, check images and read shapes + x = {} # dict + nm, nf, ne, nc = 0, 0, 0, 0 # number missing, found, empty, duplicate + pbar = tqdm(zip(self.img_files, self.label_files), desc='Scanning images', total=len(self.img_files)) + for i, (im_file, lb_file) in enumerate(pbar): + try: + # verify images + im = Image.open(im_file) + im.verify() # PIL verify + shape = exif_size(im) # image size + assert (shape[0] > 9) & (shape[1] > 9), 'image size <10 pixels' + + # verify labels + if os.path.isfile(lb_file): + nf += 1 # label found + with open(lb_file, 'r') as f: + l = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) # labels + if len(l): + assert l.shape[1] == 5, 'labels require 5 columns each' + assert (l >= 0).all(), 'negative labels' + assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels' + assert np.unique(l, axis=0).shape[0] == l.shape[0], 'duplicate labels' + else: + ne += 1 # label empty + l = np.zeros((0, 5), dtype=np.float32) + else: + nm += 1 # label missing + l = np.zeros((0, 5), dtype=np.float32) + x[im_file] = [l, shape] + except Exception as e: + nc += 1 + print('WARNING: Ignoring corrupted image and/or label %s: %s' % (im_file, e)) + + pbar.desc = f"Scanning '{path.parent / path.stem}' for images and labels... " \ + f"{nf} found, {nm} missing, {ne} empty, {nc} corrupted" + + if nf == 0: + print(f'WARNING: No labels found in {path}. See {help_url}') + + x['hash'] = get_hash(self.label_files + self.img_files) + x['results'] = [nf, nm, ne, nc, i + 1] + torch.save(x, path) # save for next time + logging.info(f"New cache created: {path}") + return x def __len__(self): return len(self.img_files) @@ -437,15 +489,22 @@ def __len__(self): # return self def __getitem__(self, index): - if self.image_weights: - index = self.indices[index] + index = self.indices[index] # linear, shuffled, or image_weights hyp = self.hyp - if self.mosaic: + mosaic = self.mosaic and random.random() < hyp['mosaic'] + if mosaic: # Load mosaic img, labels = load_mosaic(self, index) shapes = None + # MixUp https://arxiv.org/pdf/1710.09412.pdf + if random.random() < hyp['mixup']: + img2, labels2 = load_mosaic(self, random.randint(0, self.n - 1)) + r = np.random.beta(8.0, 8.0) # mixup ratio, alpha=beta=8.0 + img = (img * r + img2 * (1 - r)).astype(np.uint8) + labels = np.concatenate((labels, labels2), 0) + else: # Load image img, (h0, w0), (h, w) = load_image(self, index) @@ -468,12 +527,13 @@ def __getitem__(self, index): if self.augment: # Augment imagespace - if not self.mosaic: - img, labels = random_affine(img, labels, - degrees=hyp['degrees'], - translate=hyp['translate'], - scale=hyp['scale'], - shear=hyp['shear']) + if not mosaic: + img, labels = random_perspective(img, labels, + degrees=hyp['degrees'], + translate=hyp['translate'], + scale=hyp['scale'], + shear=hyp['shear'], + perspective=hyp['perspective']) # Augment colorspace augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) @@ -484,28 +544,23 @@ def __getitem__(self, index): nL = len(labels) # number of labels if nL: - # convert xyxy to xywh - labels[:, 1:5] = xyxy2xywh(labels[:, 1:5]) - - # Normalize coordinates 0 - 1 - labels[:, [2, 4]] /= img.shape[0] # height - labels[:, [1, 3]] /= img.shape[1] # width + labels[:, 1:5] = xyxy2xywh(labels[:, 1:5]) # convert xyxy to xywh + labels[:, [2, 4]] /= img.shape[0] # normalized height 0-1 + labels[:, [1, 3]] /= img.shape[1] # normalized width 0-1 if self.augment: - # random left-right flip - lr_flip = True - if lr_flip and random.random() < 0.5: - img = np.fliplr(img) - if nL: - labels[:, 1] = 1 - labels[:, 1] - - # random up-down flip - ud_flip = False - if ud_flip and random.random() < 0.5: + # flip up-down + if random.random() < hyp['flipud']: img = np.flipud(img) if nL: labels[:, 2] = 1 - labels[:, 2] + # flip left-right + if random.random() < hyp['fliplr']: + img = np.fliplr(img) + if nL: + labels[:, 1] = 1 - labels[:, 1] + labels_out = torch.zeros((nL, 6)) if nL: labels_out[:, 1:] = torch.from_numpy(labels) @@ -524,6 +579,7 @@ def collate_fn(batch): return torch.stack(img, 0), torch.cat(label, 0), path, shapes +# Ancillary functions -------------------------------------------------------------------------------------------------- def load_image(self, index): # loads 1 image from dataset, returns img, original hw, resized hw img = self.imgs[index] @@ -565,8 +621,8 @@ def load_mosaic(self, index): labels4 = [] s = self.img_size - xc, yc = [int(random.uniform(s * 0.5, s * 1.5)) for _ in range(2)] # mosaic center x, y - indices = [index] + [random.randint(0, len(self.labels) - 1) for _ in range(3)] # 3 additional image indices + yc, xc = [int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border] # mosaic center x, y + indices = [index] + [self.indices[random.randint(0, self.n - 1)] for _ in range(3)] # 3 additional image indices for i, index in enumerate(indices): # Load image img, _, (h, w) = load_image(self, index) @@ -581,7 +637,7 @@ def load_mosaic(self, index): x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h elif i == 2: # bottom left x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h) - x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, max(xc, w), min(y2a - y1a, h) + x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h) elif i == 3: # bottom right x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h) x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h) @@ -603,22 +659,39 @@ def load_mosaic(self, index): # Concat/clip labels if len(labels4): labels4 = np.concatenate(labels4, 0) - # np.clip(labels4[:, 1:] - s / 2, 0, s, out=labels4[:, 1:]) # use with center crop - np.clip(labels4[:, 1:], 0, 2 * s, out=labels4[:, 1:]) # use with random_affine + np.clip(labels4[:, 1:], 0, 2 * s, out=labels4[:, 1:]) # use with random_perspective + # img4, labels4 = replicate(img4, labels4) # replicate # Augment - # img4 = img4[s // 2: int(s * 1.5), s // 2:int(s * 1.5)] # center crop (WARNING, requires box pruning) - img4, labels4 = random_affine(img4, labels4, - degrees=self.hyp['degrees'], - translate=self.hyp['translate'], - scale=self.hyp['scale'], - shear=self.hyp['shear'], - border=-s // 2) # border to remove + img4, labels4 = random_perspective(img4, labels4, + degrees=self.hyp['degrees'], + translate=self.hyp['translate'], + scale=self.hyp['scale'], + shear=self.hyp['shear'], + perspective=self.hyp['perspective'], + border=self.mosaic_border) # border to remove return img4, labels4 -def letterbox(img, new_shape=(416, 416), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True): +def replicate(img, labels): + # Replicate labels + h, w = img.shape[:2] + boxes = labels[:, 1:].astype(int) + x1, y1, x2, y2 = boxes.T + s = ((x2 - x1) + (y2 - y1)) / 2 # side length (pixels) + for i in s.argsort()[:round(s.size * 0.5)]: # smallest indices + x1b, y1b, x2b, y2b = boxes[i] + bh, bw = y2b - y1b, x2b - x1b + yc, xc = int(random.uniform(0, h - bh)), int(random.uniform(0, w - bw)) # offset x, y + x1a, y1a, x2a, y2a = [xc, yc, xc + bw, yc + bh] + img[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax] + labels = np.append(labels, [[labels[i, 0], x1a, y1a, x2a, y2a]], axis=0) + + return img, labels + + +def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True): # Resize image to a 32-pixel-multiple rectangle https://github.com/ultralytics/yolov3/issues/232 shape = img.shape[:2] # current shape [height, width] if isinstance(new_shape, int): @@ -637,8 +710,8 @@ def letterbox(img, new_shape=(416, 416), color=(114, 114, 114), auto=True, scale dw, dh = np.mod(dw, 32), np.mod(dh, 32) # wh padding elif scaleFill: # stretch dw, dh = 0.0, 0.0 - new_unpad = new_shape - ratio = new_shape[0] / shape[1], new_shape[1] / shape[0] # width, height ratios + new_unpad = (new_shape[1], new_shape[0]) + ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios dw /= 2 # divide padding into 2 sides dh /= 2 @@ -651,13 +724,22 @@ def letterbox(img, new_shape=(416, 416), color=(114, 114, 114), auto=True, scale return img, ratio, (dw, dh) -def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, border=0): +def random_perspective(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, perspective=0.0, border=(0, 0)): # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) - # https://medium.com/uruvideo/dataset-augmentation-with-random-homographies-a8f4b44830d4 # targets = [cls, xyxy] - height = img.shape[0] + border * 2 - width = img.shape[1] + border * 2 + height = img.shape[0] + border[0] * 2 # shape(h,w,c) + width = img.shape[1] + border[1] * 2 + + # Center + C = np.eye(3) + C[0, 2] = -img.shape[1] / 2 # x translation (pixels) + C[1, 2] = -img.shape[0] / 2 # y translation (pixels) + + # Perspective + P = np.eye(3) + P[2, 0] = random.uniform(-perspective, perspective) # x perspective (about y) + P[2, 1] = random.uniform(-perspective, perspective) # y perspective (about x) # Rotation and Scale R = np.eye(3) @@ -665,22 +747,31 @@ def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, # a += random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotations s = random.uniform(1 - scale, 1 + scale) # s = 2 ** random.uniform(-scale, scale) - R[:2] = cv2.getRotationMatrix2D(angle=a, center=(img.shape[1] / 2, img.shape[0] / 2), scale=s) - - # Translation - T = np.eye(3) - T[0, 2] = random.uniform(-translate, translate) * img.shape[0] + border # x translation (pixels) - T[1, 2] = random.uniform(-translate, translate) * img.shape[1] + border # y translation (pixels) + R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s) # Shear S = np.eye(3) S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # x shear (deg) S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # y shear (deg) + # Translation + T = np.eye(3) + T[0, 2] = random.uniform(0.5 - translate, 0.5 + translate) * width # x translation (pixels) + T[1, 2] = random.uniform(0.5 - translate, 0.5 + translate) * height # y translation (pixels) + # Combined rotation matrix - M = S @ T @ R # ORDER IS IMPORTANT HERE!! - if (border != 0) or (M != np.eye(3)).any(): # image changed - img = cv2.warpAffine(img, M[:2], dsize=(width, height), flags=cv2.INTER_LINEAR, borderValue=(114, 114, 114)) + M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT + if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): # image changed + if perspective: + img = cv2.warpPerspective(img, M, dsize=(width, height), borderValue=(114, 114, 114)) + else: # affine + img = cv2.warpAffine(img, M[:2], dsize=(width, height), borderValue=(114, 114, 114)) + + # Visualize + # import matplotlib.pyplot as plt + # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel() + # ax[0].imshow(img[:, :, ::-1]) # base + # ax[1].imshow(img2[:, :, ::-1]) # warped # Transform label coordinates n = len(targets) @@ -688,7 +779,11 @@ def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, # warp points xy = np.ones((n * 4, 3)) xy[:, :2] = targets[:, [1, 2, 3, 4, 1, 4, 3, 2]].reshape(n * 4, 2) # x1y1, x2y2, x1y2, x2y1 - xy = (xy @ M.T)[:, :2].reshape(n, 8) + xy = xy @ M.T # transform + if perspective: + xy = (xy[:, :2] / xy[:, 2:3]).reshape(n, 8) # rescale + else: # affine + xy = xy[:, :2].reshape(n, 8) # create new boxes x = xy[:, [0, 2, 4, 6]] @@ -704,26 +799,28 @@ def random_affine(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, # h = (xy[:, 3] - xy[:, 1]) * reduction # xy = np.concatenate((x - w / 2, y - h / 2, x + w / 2, y + h / 2)).reshape(4, n).T - # reject warped points outside of image + # clip boxes xy[:, [0, 2]] = xy[:, [0, 2]].clip(0, width) xy[:, [1, 3]] = xy[:, [1, 3]].clip(0, height) - w = xy[:, 2] - xy[:, 0] - h = xy[:, 3] - xy[:, 1] - area = w * h - area0 = (targets[:, 3] - targets[:, 1]) * (targets[:, 4] - targets[:, 2]) - ar = np.maximum(w / (h + 1e-16), h / (w + 1e-16)) # aspect ratio - i = (w > 4) & (h > 4) & (area / (area0 * s + 1e-16) > 0.2) & (ar < 10) + # filter candidates + i = box_candidates(box1=targets[:, 1:5].T * s, box2=xy.T) targets = targets[i] targets[:, 1:5] = xy[i] return img, targets +def box_candidates(box1, box2, wh_thr=2, ar_thr=20, area_thr=0.1): # box1(4,n), box2(4,n) + # Compute candidate boxes: box1 before augment, box2 after augment, wh_thr (pixels), aspect_ratio_thr, area_ratio + w1, h1 = box1[2] - box1[0], box1[3] - box1[1] + w2, h2 = box2[2] - box2[0], box2[3] - box2[1] + ar = np.maximum(w2 / (h2 + 1e-16), h2 / (w2 + 1e-16)) # aspect ratio + return (w2 > wh_thr) & (h2 > wh_thr) & (w2 * h2 / (w1 * h1 + 1e-16) > area_thr) & (ar < ar_thr) # candidates + + def cutout(image, labels): - # https://arxiv.org/abs/1708.04552 - # https://github.com/hysts/pytorch_cutout/blob/master/dataloader.py - # https://towardsdatascience.com/when-conventional-wisdom-fails-revisiting-data-augmentation-for-self-driving-cars-4831998c5509 + # Applies image cutout augmentation https://arxiv.org/abs/1708.04552 h, w = image.shape[:2] def bbox_ioa(box1, box2): @@ -768,78 +865,69 @@ def bbox_ioa(box1, box2): return labels -def reduce_img_size(path='../data/sm4/images', img_size=1024): # from utils.datasets import *; reduce_img_size() - # creates a new ./images_reduced folder with reduced size images of maximum size img_size - path_new = path + '_reduced' # reduced images path - create_folder(path_new) - for f in tqdm(glob.glob('%s/*.*' % path)): - try: - img = cv2.imread(f) - h, w = img.shape[:2] - r = img_size / max(h, w) # size ratio - if r < 1.0: - img = cv2.resize(img, (int(w * r), int(h * r)), interpolation=cv2.INTER_AREA) # _LINEAR fastest - fnew = f.replace(path, path_new) # .replace(Path(f).suffix, '.jpg') - cv2.imwrite(fnew, img) - except: - print('WARNING: image failure %s' % f) - - -def convert_images2bmp(): # from utils.datasets import *; convert_images2bmp() - # Save images - formats = [x.lower() for x in img_formats] + [x.upper() for x in img_formats] - # for path in ['../coco/images/val2014', '../coco/images/train2014']: - for path in ['../data/sm4/images', '../data/sm4/background']: - create_folder(path + 'bmp') - for ext in formats: # ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.dng'] - for f in tqdm(glob.glob('%s/*%s' % (path, ext)), desc='Converting %s' % ext): - cv2.imwrite(f.replace(ext.lower(), '.bmp').replace(path, path + 'bmp'), cv2.imread(f)) - - # Save labels - # for path in ['../coco/trainvalno5k.txt', '../coco/5k.txt']: - for file in ['../data/sm4/out_train.txt', '../data/sm4/out_test.txt']: - with open(file, 'r') as f: - lines = f.read() - # lines = f.read().replace('2014/', '2014bmp/') # coco - lines = lines.replace('/images', '/imagesbmp') - lines = lines.replace('/background', '/backgroundbmp') - for ext in formats: - lines = lines.replace(ext, '.bmp') - with open(file.replace('.txt', 'bmp.txt'), 'w') as f: - f.write(lines) - - -def recursive_dataset2bmp(dataset='../data/sm4_bmp'): # from utils.datasets import *; recursive_dataset2bmp() - # Converts dataset to bmp (for faster training) - formats = [x.lower() for x in img_formats] + [x.upper() for x in img_formats] - for a, b, files in os.walk(dataset): - for file in tqdm(files, desc=a): - p = a + '/' + file - s = Path(file).suffix - if s == '.txt': # replace text - with open(p, 'r') as f: - lines = f.read() - for f in formats: - lines = lines.replace(f, '.bmp') - with open(p, 'w') as f: - f.write(lines) - elif s in formats: # replace image - cv2.imwrite(p.replace(s, '.bmp'), cv2.imread(p)) - if s != '.bmp': - os.system("rm '%s'" % p) - - -def imagelist2folder(path='data/coco_64img.txt'): # from utils.datasets import *; imagelist2folder() - # Copies all the images in a text file (list of images) into a folder - create_folder(path[:-4]) - with open(path, 'r') as f: - for line in f.read().splitlines(): - os.system('cp "%s" %s' % (line, path[:-4])) - print(line) - - -def create_folder(path='./new_folder'): +def create_folder(path='./new'): # Create folder if os.path.exists(path): shutil.rmtree(path) # delete output folder os.makedirs(path) # make new output folder + + +def flatten_recursive(path='../coco128'): + # Flatten a recursive directory by bringing all files to top level + new_path = Path(path + '_flat') + create_folder(new_path) + for file in tqdm(glob.glob(str(Path(path)) + '/**/*.*', recursive=True)): + shutil.copyfile(file, new_path / Path(file).name) + + +def extract_boxes(path='../coco128/'): # from utils.datasets import *; extract_boxes('../coco128') + # Convert detection dataset into classification dataset, with one directory per class + + path = Path(path) # images dir + shutil.rmtree(path / 'classifier') if (path / 'classifier').is_dir() else None # remove existing + files = list(path.rglob('*.*')) + n = len(files) # number of files + for im_file in tqdm(files, total=n): + if im_file.suffix[1:] in img_formats: + # image + im = cv2.imread(str(im_file))[..., ::-1] # BGR to RGB + h, w = im.shape[:2] + + # labels + lb_file = Path(img2label_paths([str(im_file)])[0]) + if Path(lb_file).exists(): + with open(lb_file, 'r') as f: + lb = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) # labels + + for j, x in enumerate(lb): + c = int(x[0]) # class + f = (path / 'classifier') / f'{c}' / f'{path.stem}_{im_file.stem}_{j}.jpg' # new filename + if not f.parent.is_dir(): + f.parent.mkdir(parents=True) + + b = x[1:] * [w, h, w, h] # box + # b[2:] = b[2:].max() # rectangle to square + b[2:] = b[2:] * 1.2 + 3 # pad + b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(np.int) + + b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image + b[[1, 3]] = np.clip(b[[1, 3]], 0, h) + assert cv2.imwrite(str(f), im[b[1]:b[3], b[0]:b[2]]), f'box failure in {f}' + + +def autosplit(path='../coco128', weights=(0.9, 0.1, 0.0)): # from utils.datasets import *; autosplit('../coco128') + """ Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files + # Arguments + path: Path to images directory + weights: Train, val, test weights (list) + """ + path = Path(path) # images dir + files = list(path.rglob('*.*')) + n = len(files) # number of files + indices = random.choices([0, 1, 2], weights=weights, k=n) # assign each image to a split + txt = ['autosplit_train.txt', 'autosplit_val.txt', 'autosplit_test.txt'] # 3 txt files + [(path / x).unlink() for x in txt if (path / x).exists()] # remove existing + for i, img in tqdm(zip(indices, files), total=n): + if img.suffix[1:] in img_formats: + with open(path / txt[i], 'a') as f: + f.write(str(img) + '\n') # add image to txt file diff --git a/utils/evolve.sh b/utils/evolve.sh deleted file mode 100644 index 6682d0ac73..0000000000 --- a/utils/evolve.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -#for i in 0 1 2 3 -#do -# t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t utils/evolve.sh $i -# sleep 30 -#done - -while true; do - # python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --evolve --cache --device $1 --cfg yolov3-tiny3-1cls.cfg --single --adam - # python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg - - python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --evolve --weights '' --bucket ult/coco/sppa_512 --device $1 --cfg yolov3-sppa.cfg --multi -done - -# coco epoch times --img-size 416 608 --epochs 27 --batch 16 --accum 4 -# 36:34 2080ti -# 21:58 V100 -# 63:00 T4 diff --git a/utils/gcp.sh b/utils/gcp.sh deleted file mode 100755 index 0a78cea95a..0000000000 --- a/utils/gcp.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash - -# New VM -rm -rf sample_data yolov3 -git clone https://github.com/ultralytics/yolov3 -# git clone -b test --depth 1 https://github.com/ultralytics/yolov3 test # branch -# sudo apt-get install zip -#git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex -sudo conda install -yc conda-forge scikit-image pycocotools -# python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('193Zp_ye-3qXMonR1nZj3YyxMtQkMy50k','coco2014.zip')" -python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco2017.zip')" -python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1C3HewOG9akA3y456SZLBJZfNDPkBwAto','knife.zip')" -python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('13g3LqdpkNE8sPosVJT6KFXlfoMypzRP4','sm4.zip')" -sudo shutdown - -# Mount local SSD -lsblk -sudo mkfs.ext4 -F /dev/nvme0n1 -sudo mkdir -p /mnt/disks/nvme0n1 -sudo mount /dev/nvme0n1 /mnt/disks/nvme0n1 -sudo chmod a+w /mnt/disks/nvme0n1 -cp -r coco /mnt/disks/nvme0n1 - -# Kill All -t=ultralytics/yolov3:v1 -docker kill $(docker ps -a -q --filter ancestor=$t) - -# Evolve coco -sudo -s -t=ultralytics/yolov3:evolve -# docker kill $(docker ps -a -q --filter ancestor=$t) -for i in 0 1 6 7; do - docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i - sleep 30 -done - -#COCO training -n=131 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 640 --epochs 300 --batch 16 --weights '' --device 0 --cfg yolov3-spp.cfg --bucket ult/coco --name $n && sudo shutdown -n=132 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 640 --epochs 300 --batch 64 --weights '' --device 0 --cfg yolov3-tiny.cfg --bucket ult/coco --name $n && sudo shutdown diff --git a/utils/general.py b/utils/general.py new file mode 100755 index 0000000000..ca6a9f6b10 --- /dev/null +++ b/utils/general.py @@ -0,0 +1,445 @@ +# General utils + +import glob +import logging +import math +import os +import platform +import random +import re +import subprocess +import time +from pathlib import Path + +import cv2 +import matplotlib +import numpy as np +import torch +import torchvision +import yaml + +from utils.google_utils import gsutil_getsize +from utils.metrics import fitness +from utils.torch_utils import init_torch_seeds + +# Set printoptions +torch.set_printoptions(linewidth=320, precision=5, profile='long') +np.set_printoptions(linewidth=320, formatter={'float_kind': '{:11.5g}'.format}) # format short g, %precision=5 +matplotlib.rc('font', **{'size': 11}) + +# Prevent OpenCV from multithreading (to use PyTorch DataLoader) +cv2.setNumThreads(0) + + +def set_logging(rank=-1): + logging.basicConfig( + format="%(message)s", + level=logging.INFO if rank in [-1, 0] else logging.WARN) + + +def init_seeds(seed=0): + random.seed(seed) + np.random.seed(seed) + init_torch_seeds(seed) + + +def get_latest_run(search_dir='.'): + # Return path to most recent 'last.pt' in /runs (i.e. to --resume from) + last_list = glob.glob(f'{search_dir}/**/last*.pt', recursive=True) + return max(last_list, key=os.path.getctime) if last_list else '' + + +def check_git_status(): + # Suggest 'git pull' if repo is out of date + if platform.system() in ['Linux', 'Darwin'] and not os.path.isfile('/.dockerenv'): + s = subprocess.check_output('if [ -d .git ]; then git fetch && git status -uno; fi', shell=True).decode('utf-8') + if 'Your branch is behind' in s: + print(s[s.find('Your branch is behind'):s.find('\n\n')] + '\n') + + +def check_img_size(img_size, s=32): + # Verify img_size is a multiple of stride s + new_size = make_divisible(img_size, int(s)) # ceil gs-multiple + if new_size != img_size: + print('WARNING: --img-size %g must be multiple of max stride %g, updating to %g' % (img_size, s, new_size)) + return new_size + + +def check_file(file): + # Search for file if not found + if os.path.isfile(file) or file == '': + return file + else: + files = glob.glob('./**/' + file, recursive=True) # find file + assert len(files), 'File Not Found: %s' % file # assert file was found + assert len(files) == 1, "Multiple files match '%s', specify exact path: %s" % (file, files) # assert unique + return files[0] # return file + + +def check_dataset(dict): + # Download dataset if not found locally + val, s = dict.get('val'), dict.get('download') + if val and len(val): + val = [Path(x).resolve() for x in (val if isinstance(val, list) else [val])] # val path + if not all(x.exists() for x in val): + print('\nWARNING: Dataset not found, nonexistent paths: %s' % [str(x) for x in val if not x.exists()]) + if s and len(s): # download script + print('Downloading %s ...' % s) + if s.startswith('http') and s.endswith('.zip'): # URL + f = Path(s).name # filename + torch.hub.download_url_to_file(s, f) + r = os.system('unzip -q %s -d ../ && rm %s' % (f, f)) # unzip + else: # bash script + r = os.system(s) + print('Dataset autodownload %s\n' % ('success' if r == 0 else 'failure')) # analyze return value + else: + raise Exception('Dataset not found.') + + +def make_divisible(x, divisor): + # Returns x evenly divisible by divisor + return math.ceil(x / divisor) * divisor + + +def labels_to_class_weights(labels, nc=80): + # Get class weights (inverse frequency) from training labels + if labels[0] is None: # no labels loaded + return torch.Tensor() + + labels = np.concatenate(labels, 0) # labels.shape = (866643, 5) for COCO + classes = labels[:, 0].astype(np.int) # labels = [class xywh] + weights = np.bincount(classes, minlength=nc) # occurrences per class + + # Prepend gridpoint count (for uCE training) + # gpi = ((320 / 32 * np.array([1, 2, 4])) ** 2 * 3).sum() # gridpoints per image + # weights = np.hstack([gpi * len(labels) - weights.sum() * 9, weights * 9]) ** 0.5 # prepend gridpoints to start + + weights[weights == 0] = 1 # replace empty bins with 1 + weights = 1 / weights # number of targets per class + weights /= weights.sum() # normalize + return torch.from_numpy(weights) + + +def labels_to_image_weights(labels, nc=80, class_weights=np.ones(80)): + # Produces image weights based on class mAPs + n = len(labels) + class_counts = np.array([np.bincount(labels[i][:, 0].astype(np.int), minlength=nc) for i in range(n)]) + image_weights = (class_weights.reshape(1, nc) * class_counts).sum(1) + # index = random.choices(range(n), weights=image_weights, k=1) # weight image sample + return image_weights + + +def coco80_to_coco91_class(): # converts 80-index (val2014) to 91-index (paper) + # https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/ + # a = np.loadtxt('data/coco.names', dtype='str', delimiter='\n') + # b = np.loadtxt('data/coco_paper.names', dtype='str', delimiter='\n') + # x1 = [list(a[i] == b).index(True) + 1 for i in range(80)] # darknet to coco + # x2 = [list(b[i] == a).index(True) if any(b[i] == a) else None for i in range(91)] # coco to darknet + x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 67, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] + return x + + +def xyxy2xywh(x): + # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] where xy1=top-left, xy2=bottom-right + y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) + y[:, 0] = (x[:, 0] + x[:, 2]) / 2 # x center + y[:, 1] = (x[:, 1] + x[:, 3]) / 2 # y center + y[:, 2] = x[:, 2] - x[:, 0] # width + y[:, 3] = x[:, 3] - x[:, 1] # height + return y + + +def xywh2xyxy(x): + # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) + y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x + y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y + y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x + y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y + return y + + +def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None): + # Rescale coords (xyxy) from img1_shape to img0_shape + if ratio_pad is None: # calculate from img0_shape + gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new + pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding + else: + gain = ratio_pad[0][0] + pad = ratio_pad[1] + + coords[:, [0, 2]] -= pad[0] # x padding + coords[:, [1, 3]] -= pad[1] # y padding + coords[:, :4] /= gain + clip_coords(coords, img0_shape) + return coords + + +def clip_coords(boxes, img_shape): + # Clip bounding xyxy bounding boxes to image shape (height, width) + boxes[:, 0].clamp_(0, img_shape[1]) # x1 + boxes[:, 1].clamp_(0, img_shape[0]) # y1 + boxes[:, 2].clamp_(0, img_shape[1]) # x2 + boxes[:, 3].clamp_(0, img_shape[0]) # y2 + + +def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-9): + # Returns the IoU of box1 to box2. box1 is 4, box2 is nx4 + box2 = box2.T + + # Get the coordinates of bounding boxes + if x1y1x2y2: # x1, y1, x2, y2 = box1 + b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3] + b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3] + else: # transform from xywh to xyxy + b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2 + b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2 + b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2 + b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2 + + # Intersection area + inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \ + (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0) + + # Union Area + w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps + w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps + union = w1 * h1 + w2 * h2 - inter + eps + + iou = inter / union + if GIoU or DIoU or CIoU: + cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1) # convex (smallest enclosing box) width + ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1) # convex height + if CIoU or DIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1 + c2 = cw ** 2 + ch ** 2 + eps # convex diagonal squared + rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4 # center distance squared + if DIoU: + return iou - rho2 / c2 # DIoU + elif CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47 + v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2) + with torch.no_grad(): + alpha = v / ((1 + eps) - iou + v) + return iou - (rho2 / c2 + v * alpha) # CIoU + else: # GIoU https://arxiv.org/pdf/1902.09630.pdf + c_area = cw * ch + eps # convex area + return iou - (c_area - union) / c_area # GIoU + else: + return iou # IoU + + +def box_iou(box1, box2): + # https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py + """ + Return intersection-over-union (Jaccard index) of boxes. + Both sets of boxes are expected to be in (x1, y1, x2, y2) format. + Arguments: + box1 (Tensor[N, 4]) + box2 (Tensor[M, 4]) + Returns: + iou (Tensor[N, M]): the NxM matrix containing the pairwise + IoU values for every element in boxes1 and boxes2 + """ + + def box_area(box): + # box = 4xn + return (box[2] - box[0]) * (box[3] - box[1]) + + area1 = box_area(box1.T) + area2 = box_area(box2.T) + + # inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2) + inter = (torch.min(box1[:, None, 2:], box2[:, 2:]) - torch.max(box1[:, None, :2], box2[:, :2])).clamp(0).prod(2) + return inter / (area1[:, None] + area2 - inter) # iou = inter / (area1 + area2 - inter) + + +def wh_iou(wh1, wh2): + # Returns the nxm IoU matrix. wh1 is nx2, wh2 is mx2 + wh1 = wh1[:, None] # [N,1,2] + wh2 = wh2[None] # [1,M,2] + inter = torch.min(wh1, wh2).prod(2) # [N,M] + return inter / (wh1.prod(2) + wh2.prod(2) - inter) # iou = inter / (area1 + area2 - inter) + + +def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, classes=None, agnostic=False, labels=()): + """Performs Non-Maximum Suppression (NMS) on inference results + + Returns: + detections with shape: nx6 (x1, y1, x2, y2, conf, cls) + """ + + nc = prediction[0].shape[1] - 5 # number of classes + xc = prediction[..., 4] > conf_thres # candidates + + # Settings + min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height + max_det = 300 # maximum number of detections per image + time_limit = 10.0 # seconds to quit after + redundant = True # require redundant detections + multi_label = nc > 1 # multiple labels per box (adds 0.5ms/img) + merge = False # use merge-NMS + + t = time.time() + output = [torch.zeros(0, 6)] * prediction.shape[0] + for xi, x in enumerate(prediction): # image index, image inference + # Apply constraints + # x[((x[..., 2:4] < min_wh) | (x[..., 2:4] > max_wh)).any(1), 4] = 0 # width-height + x = x[xc[xi]] # confidence + + # Cat apriori labels if autolabelling + if labels and len(labels[xi]): + l = labels[xi] + v = torch.zeros((len(l), nc + 5), device=x.device) + v[:, :4] = l[:, 1:5] # box + v[:, 4] = 1.0 # conf + v[range(len(l)), l[:, 0].long() + 5] = 1.0 # cls + x = torch.cat((x, v), 0) + + # If none remain process next image + if not x.shape[0]: + continue + + # Compute conf + x[:, 5:] *= x[:, 4:5] # conf = obj_conf * cls_conf + + # Box (center x, center y, width, height) to (x1, y1, x2, y2) + box = xywh2xyxy(x[:, :4]) + + # Detections matrix nx6 (xyxy, conf, cls) + if multi_label: + i, j = (x[:, 5:] > conf_thres).nonzero(as_tuple=False).T + x = torch.cat((box[i], x[i, j + 5, None], j[:, None].float()), 1) + else: # best class only + conf, j = x[:, 5:].max(1, keepdim=True) + x = torch.cat((box, conf, j.float()), 1)[conf.view(-1) > conf_thres] + + # Filter by class + if classes: + x = x[(x[:, 5:6] == torch.tensor(classes, device=x.device)).any(1)] + + # Apply finite constraint + # if not torch.isfinite(x).all(): + # x = x[torch.isfinite(x).all(1)] + + # If none remain process next image + n = x.shape[0] # number of boxes + if not n: + continue + + # Sort by confidence + # x = x[x[:, 4].argsort(descending=True)] + + # Batched NMS + c = x[:, 5:6] * (0 if agnostic else max_wh) # classes + boxes, scores = x[:, :4] + c, x[:, 4] # boxes (offset by class), scores + i = torchvision.ops.nms(boxes, scores, iou_thres) # NMS + if i.shape[0] > max_det: # limit detections + i = i[:max_det] + if merge and (1 < n < 3E3): # Merge NMS (boxes merged using weighted mean) + # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) + iou = box_iou(boxes[i], boxes) > iou_thres # iou matrix + weights = iou * scores[None] # box weights + x[i, :4] = torch.mm(weights, x[:, :4]).float() / weights.sum(1, keepdim=True) # merged boxes + if redundant: + i = i[iou.sum(1) > 1] # require redundancy + + output[xi] = x[i] + if (time.time() - t) > time_limit: + break # time limit exceeded + + return output + + +def strip_optimizer(f='weights/best.pt', s=''): # from utils.general import *; strip_optimizer() + # Strip optimizer from 'f' to finalize training, optionally save as 's' + x = torch.load(f, map_location=torch.device('cpu')) + x['optimizer'] = None + x['training_results'] = None + x['epoch'] = -1 + x['model'].half() # to FP16 + for p in x['model'].parameters(): + p.requires_grad = False + torch.save(x, s or f) + mb = os.path.getsize(s or f) / 1E6 # filesize + print('Optimizer stripped from %s,%s %.1fMB' % (f, (' saved as %s,' % s) if s else '', mb)) + + +def print_mutation(hyp, results, yaml_file='hyp_evolved.yaml', bucket=''): + # Print mutation results to evolve.txt (for use with train.py --evolve) + a = '%10s' * len(hyp) % tuple(hyp.keys()) # hyperparam keys + b = '%10.3g' * len(hyp) % tuple(hyp.values()) # hyperparam values + c = '%10.4g' * len(results) % results # results (P, R, mAP@0.5, mAP@0.5:0.95, val_losses x 3) + print('\n%s\n%s\nEvolved fitness: %s\n' % (a, b, c)) + + if bucket: + url = 'gs://%s/evolve.txt' % bucket + if gsutil_getsize(url) > (os.path.getsize('evolve.txt') if os.path.exists('evolve.txt') else 0): + os.system('gsutil cp %s .' % url) # download evolve.txt if larger than local + + with open('evolve.txt', 'a') as f: # append result + f.write(c + b + '\n') + x = np.unique(np.loadtxt('evolve.txt', ndmin=2), axis=0) # load unique rows + x = x[np.argsort(-fitness(x))] # sort + np.savetxt('evolve.txt', x, '%10.3g') # save sort by fitness + + # Save yaml + for i, k in enumerate(hyp.keys()): + hyp[k] = float(x[0, i + 7]) + with open(yaml_file, 'w') as f: + results = tuple(x[0, :7]) + c = '%10.4g' * len(results) % results # results (P, R, mAP@0.5, mAP@0.5:0.95, val_losses x 3) + f.write('# Hyperparameter Evolution Results\n# Generations: %g\n# Metrics: ' % len(x) + c + '\n\n') + yaml.dump(hyp, f, sort_keys=False) + + if bucket: + os.system('gsutil cp evolve.txt %s gs://%s' % (yaml_file, bucket)) # upload + + +def apply_classifier(x, model, img, im0): + # applies a second stage classifier to yolo outputs + im0 = [im0] if isinstance(im0, np.ndarray) else im0 + for i, d in enumerate(x): # per image + if d is not None and len(d): + d = d.clone() + + # Reshape and pad cutouts + b = xyxy2xywh(d[:, :4]) # boxes + b[:, 2:] = b[:, 2:].max(1)[0].unsqueeze(1) # rectangle to square + b[:, 2:] = b[:, 2:] * 1.3 + 30 # pad + d[:, :4] = xywh2xyxy(b).long() + + # Rescale boxes from img_size to im0 size + scale_coords(img.shape[2:], d[:, :4], im0[i].shape) + + # Classes + pred_cls1 = d[:, 5].long() + ims = [] + for j, a in enumerate(d): # per item + cutout = im0[i][int(a[1]):int(a[3]), int(a[0]):int(a[2])] + im = cv2.resize(cutout, (224, 224)) # BGR + # cv2.imwrite('test%i.jpg' % j, cutout) + + im = im[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 + im = np.ascontiguousarray(im, dtype=np.float32) # uint8 to float32 + im /= 255.0 # 0 - 255 to 0.0 - 1.0 + ims.append(im) + + pred_cls2 = model(torch.Tensor(ims).to(d.device)).argmax(1) # classifier prediction + x[i] = x[i][pred_cls1 == pred_cls2] # retain matching class detections + + return x + + +def increment_path(path, exist_ok=True, sep=''): + # Increment path, i.e. runs/exp --> runs/exp{sep}0, runs/exp{sep}1 etc. + path = Path(path) # os-agnostic + if (path.exists() and exist_ok) or (not path.exists()): + return str(path) + else: + dirs = glob.glob(f"{path}{sep}*") # similar paths + matches = [re.search(rf"%s{sep}(\d+)" % path.stem, d) for d in dirs] + i = [int(m.groups()[0]) for m in matches if m] # indices + n = max(i) + 1 if i else 2 # increment number + return f"{path}{sep}{n}" # update path diff --git a/utils/google_app_engine/Dockerfile b/utils/google_app_engine/Dockerfile new file mode 100644 index 0000000000..0155618f47 --- /dev/null +++ b/utils/google_app_engine/Dockerfile @@ -0,0 +1,25 @@ +FROM gcr.io/google-appengine/python + +# Create a virtualenv for dependencies. This isolates these packages from +# system-level packages. +# Use -p python3 or -p python3.7 to select python version. Default is version 2. +RUN virtualenv /env -p python3 + +# Setting these environment variables are the same as running +# source /env/bin/activate. +ENV VIRTUAL_ENV /env +ENV PATH /env/bin:$PATH + +RUN apt-get update && apt-get install -y python-opencv + +# Copy the application's requirements.txt and run pip to install all +# dependencies into the virtualenv. +ADD requirements.txt /app/requirements.txt +RUN pip install -r /app/requirements.txt + +# Add the application source code. +ADD . /app + +# Run a WSGI server to serve the application. gunicorn must be declared as +# a dependency in requirements.txt. +CMD gunicorn -b :$PORT main:app diff --git a/utils/google_app_engine/additional_requirements.txt b/utils/google_app_engine/additional_requirements.txt new file mode 100644 index 0000000000..5fcc30524a --- /dev/null +++ b/utils/google_app_engine/additional_requirements.txt @@ -0,0 +1,4 @@ +# add these requirements in your app on top of the existing ones +pip==18.1 +Flask==1.0.2 +gunicorn==19.9.0 diff --git a/utils/google_app_engine/app.yaml b/utils/google_app_engine/app.yaml new file mode 100644 index 0000000000..bd162e44dd --- /dev/null +++ b/utils/google_app_engine/app.yaml @@ -0,0 +1,14 @@ +runtime: custom +env: flex + +service: yolov3app + +liveness_check: + initial_delay_sec: 600 + +manual_scaling: + instances: 1 +resources: + cpu: 1 + memory_gb: 4 + disk_size_gb: 20 \ No newline at end of file diff --git a/utils/google_utils.py b/utils/google_utils.py index 1679f0fe70..d50198fedf 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -1,17 +1,60 @@ -# This file contains google utils: https://cloud.google.com/storage/docs/reference/libraries -# pip install --upgrade google-cloud-storage +# Google utils: https://cloud.google.com/storage/docs/reference/libraries import os +import platform +import subprocess import time - - -# from google.cloud import storage - - -def gdrive_download(id='1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO', name='coco.zip'): - # https://gist.github.com/tanaikech/f0f2d122e05bf5f971611258c22c110f - # Downloads a file from Google Drive, accepting presented query - # from utils.google_utils import *; gdrive_download() +from pathlib import Path + +import torch + + +def gsutil_getsize(url=''): + # gs://bucket/file size https://cloud.google.com/storage/docs/gsutil/commands/du + s = subprocess.check_output('gsutil du %s' % url, shell=True).decode('utf-8') + return eval(s.split(' ')[0]) if len(s) else 0 # bytes + + +def attempt_download(weights): + # Attempt to download pretrained weights if not found locally + weights = weights.strip().replace("'", '') + file = Path(weights).name.lower() + + msg = weights + ' missing, try downloading from https://github.com/ultralytics/yolov3/releases/' + models = ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt'] # available models + redundant = False # offer second download option + + if file in models and not os.path.isfile(weights): + # Google Drive + # d = {'yolov5s.pt': '1R5T6rIyy3lLwgFXNms8whc-387H0tMQO', + # 'yolov5m.pt': '1vobuEExpWQVpXExsJ2w-Mbf3HJjWkQJr', + # 'yolov5l.pt': '1hrlqD1Wdei7UT4OgT785BEk1JwnSvNEV', + # 'yolov5x.pt': '1mM8aZJlWTxOg7BZJvNUMrTnA2AbeCVzS'} + # r = gdrive_download(id=d[file], name=weights) if file in d else 1 + # if r == 0 and os.path.exists(weights) and os.path.getsize(weights) > 1E6: # check + # return + + try: # GitHub + url = 'https://github.com/ultralytics/yolov3/releases/download/v1.0/' + file + print('Downloading %s to %s...' % (url, weights)) + torch.hub.download_url_to_file(url, weights) + assert os.path.exists(weights) and os.path.getsize(weights) > 1E6 # check + except Exception as e: # GCP + print('Download error: %s' % e) + assert redundant, 'No secondary mirror' + url = 'https://storage.googleapis.com/ultralytics/yolov3/ckpt/' + file + print('Downloading %s to %s...' % (url, weights)) + r = os.system('curl -L %s -o %s' % (url, weights)) # torch.hub.download_url_to_file(url, weights) + finally: + if not (os.path.exists(weights) and os.path.getsize(weights) > 1E6): # check + os.remove(weights) if os.path.exists(weights) else None # remove partial downloads + print('ERROR: Download failure: %s' % msg) + print('') + return + + +def gdrive_download(id='1n_oKgR81BJtqk75b00eAjdv03qVCQn2f', name='coco128.zip'): + # Downloads a file from Google Drive. from utils.google_utils import *; gdrive_download() t = time.time() print('Downloading https://drive.google.com/uc?export=download&id=%s as %s... ' % (id, name), end='') @@ -19,13 +62,13 @@ def gdrive_download(id='1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO', name='coco.zip'): os.remove('cookie') if os.path.exists('cookie') else None # Attempt file download - os.system("curl -c ./cookie -s -L \"https://drive.google.com/uc?export=download&id=%s\" > /dev/null" % id) + out = "NUL" if platform.system() == "Windows" else "/dev/null" + os.system('curl -c ./cookie -s -L "drive.google.com/uc?export=download&id=%s" > %s ' % (id, out)) if os.path.exists('cookie'): # large file - s = "curl -Lb ./cookie \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=%s\" -o %s" % ( - id, name) + s = 'curl -Lb ./cookie "drive.google.com/uc?export=download&confirm=%s&id=%s" -o %s' % (get_token(), id, name) else: # small file - s = "curl -s -L -o %s 'https://drive.google.com/uc?export=download&id=%s'" % (name, id) - r = os.system(s) # execute, capture return values + s = 'curl -s -L -o %s "drive.google.com/uc?export=download&id=%s"' % (name, id) + r = os.system(s) # execute, capture return os.remove('cookie') if os.path.exists('cookie') else None # Error check @@ -44,29 +87,36 @@ def gdrive_download(id='1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO', name='coco.zip'): return r -def upload_blob(bucket_name, source_file_name, destination_blob_name): - # Uploads a file to a bucket - # https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-python - - storage_client = storage.Client() - bucket = storage_client.get_bucket(bucket_name) - blob = bucket.blob(destination_blob_name) - - blob.upload_from_filename(source_file_name) - - print('File {} uploaded to {}.'.format( - source_file_name, - destination_blob_name)) - - -def download_blob(bucket_name, source_blob_name, destination_file_name): - # Uploads a blob from a bucket - storage_client = storage.Client() - bucket = storage_client.get_bucket(bucket_name) - blob = bucket.blob(source_blob_name) - - blob.download_to_filename(destination_file_name) - - print('Blob {} downloaded to {}.'.format( - source_blob_name, - destination_file_name)) +def get_token(cookie="./cookie"): + with open(cookie) as f: + for line in f: + if "download" in line: + return line.split()[-1] + return "" + +# def upload_blob(bucket_name, source_file_name, destination_blob_name): +# # Uploads a file to a bucket +# # https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-python +# +# storage_client = storage.Client() +# bucket = storage_client.get_bucket(bucket_name) +# blob = bucket.blob(destination_blob_name) +# +# blob.upload_from_filename(source_file_name) +# +# print('File {} uploaded to {}.'.format( +# source_file_name, +# destination_blob_name)) +# +# +# def download_blob(bucket_name, source_blob_name, destination_file_name): +# # Uploads a blob from a bucket +# storage_client = storage.Client() +# bucket = storage_client.get_bucket(bucket_name) +# blob = bucket.blob(source_blob_name) +# +# blob.download_to_filename(destination_file_name) +# +# print('Blob {} downloaded to {}.'.format( +# source_blob_name, +# destination_file_name)) diff --git a/utils/layers.py b/utils/layers.py deleted file mode 100644 index 35c13c9f06..0000000000 --- a/utils/layers.py +++ /dev/null @@ -1,148 +0,0 @@ -import torch.nn.functional as F - -from utils.utils import * - - -def make_divisible(v, divisor): - # Function ensures all layers have a channel number that is divisible by 8 - # https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py - return math.ceil(v / divisor) * divisor - - -class Flatten(nn.Module): - # Use after nn.AdaptiveAvgPool2d(1) to remove last 2 dimensions - def forward(self, x): - return x.view(x.size(0), -1) - - -class Concat(nn.Module): - # Concatenate a list of tensors along dimension - def __init__(self, dimension=1): - super(Concat, self).__init__() - self.d = dimension - - def forward(self, x): - return torch.cat(x, self.d) - - -class FeatureConcat(nn.Module): - def __init__(self, layers): - super(FeatureConcat, self).__init__() - self.layers = layers # layer indices - self.multiple = len(layers) > 1 # multiple layers flag - - def forward(self, x, outputs): - return torch.cat([outputs[i] for i in self.layers], 1) if self.multiple else outputs[self.layers[0]] - - -class WeightedFeatureFusion(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers, weight=False): - super(WeightedFeatureFusion, self).__init__() - self.layers = layers # layer indices - self.weight = weight # apply weights boolean - self.n = len(layers) + 1 # number of layers - if weight: - self.w = nn.Parameter(torch.zeros(self.n), requires_grad=True) # layer weights - - def forward(self, x, outputs): - # Weights - if self.weight: - w = torch.sigmoid(self.w) * (2 / self.n) # sigmoid weights (0-1) - x = x * w[0] - - # Fusion - nx = x.shape[1] # input channels - for i in range(self.n - 1): - a = outputs[self.layers[i]] * w[i + 1] if self.weight else outputs[self.layers[i]] # feature to add - na = a.shape[1] # feature channels - - # Adjust channels - if nx == na: # same shape - x = x + a - elif nx > na: # slice input - x[:, :na] = x[:, :na] + a # or a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a); x = x + a - else: # slice feature - x = x + a[:, :nx] - - return x - - -class MixConv2d(nn.Module): # MixConv: Mixed Depthwise Convolutional Kernels https://arxiv.org/abs/1907.09595 - def __init__(self, in_ch, out_ch, k=(3, 5, 7), stride=1, dilation=1, bias=True, method='equal_params'): - super(MixConv2d, self).__init__() - - groups = len(k) - if method == 'equal_ch': # equal channels per group - i = torch.linspace(0, groups - 1E-6, out_ch).floor() # out_ch indices - ch = [(i == g).sum() for g in range(groups)] - else: # 'equal_params': equal parameter count per group - b = [out_ch] + [0] * groups - a = np.eye(groups + 1, groups, k=-1) - a -= np.roll(a, 1, axis=1) - a *= np.array(k) ** 2 - a[0] = 1 - ch = np.linalg.lstsq(a, b, rcond=None)[0].round().astype(int) # solve for equal weight indices, ax = b - - self.m = nn.ModuleList([nn.Conv2d(in_channels=in_ch, - out_channels=ch[g], - kernel_size=k[g], - stride=stride, - padding=k[g] // 2, # 'same' pad - dilation=dilation, - bias=bias) for g in range(groups)]) - - def forward(self, x): - return torch.cat([m(x) for m in self.m], 1) - - -# Activation functions below ------------------------------------------------------------------------------------------- -class SwishImplementation(torch.autograd.Function): - @staticmethod - def forward(ctx, x): - ctx.save_for_backward(x) - return x * torch.sigmoid(x) - - @staticmethod - def backward(ctx, grad_output): - x = ctx.saved_tensors[0] - sx = torch.sigmoid(x) # sigmoid(ctx) - return grad_output * (sx * (1 + x * (1 - sx))) - - -class MishImplementation(torch.autograd.Function): - @staticmethod - def forward(ctx, x): - ctx.save_for_backward(x) - return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x))) - - @staticmethod - def backward(ctx, grad_output): - x = ctx.saved_tensors[0] - sx = torch.sigmoid(x) - fx = F.softplus(x).tanh() - return grad_output * (fx + x * sx * (1 - fx * fx)) - - -class MemoryEfficientSwish(nn.Module): - def forward(self, x): - return SwishImplementation.apply(x) - - -class MemoryEfficientMish(nn.Module): - def forward(self, x): - return MishImplementation.apply(x) - - -class Swish(nn.Module): - def forward(self, x): - return x * torch.sigmoid(x) - - -class HardSwish(nn.Module): # https://arxiv.org/pdf/1905.02244.pdf - def forward(self, x): - return x * F.hardtanh(x + 3, 0., 6., True) / 6. - - -class Mish(nn.Module): # https://github.com/digantamisra98/Mish - def forward(self, x): - return x * F.softplus(x).tanh() diff --git a/utils/loss.py b/utils/loss.py new file mode 100644 index 0000000000..4893c99918 --- /dev/null +++ b/utils/loss.py @@ -0,0 +1,179 @@ +# Loss functions + +import torch +import torch.nn as nn + +from utils.general import bbox_iou +from utils.torch_utils import is_parallel + + +def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 + # return positive, negative label smoothing BCE targets + return 1.0 - 0.5 * eps, 0.5 * eps + + +class BCEBlurWithLogitsLoss(nn.Module): + # BCEwithLogitLoss() with reduced missing label effects. + def __init__(self, alpha=0.05): + super(BCEBlurWithLogitsLoss, self).__init__() + self.loss_fcn = nn.BCEWithLogitsLoss(reduction='none') # must be nn.BCEWithLogitsLoss() + self.alpha = alpha + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + pred = torch.sigmoid(pred) # prob from logits + dx = pred - true # reduce only missing label effects + # dx = (pred - true).abs() # reduce missing label and false label effects + alpha_factor = 1 - torch.exp((dx - 1) / (self.alpha + 1e-4)) + loss *= alpha_factor + return loss.mean() + + +class FocalLoss(nn.Module): + # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): + super(FocalLoss, self).__init__() + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() + self.gamma = gamma + self.alpha = alpha + self.reduction = loss_fcn.reduction + self.loss_fcn.reduction = 'none' # required to apply FL to each element + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + # p_t = torch.exp(-loss) + # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability + + # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py + pred_prob = torch.sigmoid(pred) # prob from logits + p_t = true * pred_prob + (1 - true) * (1 - pred_prob) + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) + modulating_factor = (1.0 - p_t) ** self.gamma + loss *= alpha_factor * modulating_factor + + if self.reduction == 'mean': + return loss.mean() + elif self.reduction == 'sum': + return loss.sum() + else: # 'none' + return loss + + +def compute_loss(p, targets, model): # predictions, targets, model + device = targets.device + lcls, lbox, lobj = torch.zeros(1, device=device), torch.zeros(1, device=device), torch.zeros(1, device=device) + tcls, tbox, indices, anchors = build_targets(p, targets, model) # targets + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.Tensor([h['cls_pw']])).to(device) + BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.Tensor([h['obj_pw']])).to(device) + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + cp, cn = smooth_BCE(eps=0.0) + + # Focal loss + g = h['fl_gamma'] # focal loss gamma + if g > 0: + BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) + + # Losses + nt = 0 # number of targets + no = len(p) # number of outputs + balance = [4.0, 1.0, 0.4] if no == 3 else [4.0, 1.0, 0.4, 0.1] # P3-5 or P3-6 + for i, pi in enumerate(p): # layer index, layer predictions + b, a, gj, gi = indices[i] # image, anchor, gridy, gridx + tobj = torch.zeros_like(pi[..., 0], device=device) # target obj + + n = b.shape[0] # number of targets + if n: + nt += n # cumulative targets + ps = pi[b, a, gj, gi] # prediction subset corresponding to targets + + # Regression + pxy = ps[:, :2].sigmoid() * 2. - 0.5 + pwh = (ps[:, 2:4].sigmoid() * 2) ** 2 * anchors[i] + pbox = torch.cat((pxy, pwh), 1).to(device) # predicted box + iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, CIoU=True) # iou(prediction, target) + lbox += (1.0 - iou).mean() # iou loss + + # Objectness + tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * iou.detach().clamp(0).type(tobj.dtype) # iou ratio + + # Classification + if model.nc > 1: # cls loss (only if multiple classes) + t = torch.full_like(ps[:, 5:], cn, device=device) # targets + t[range(n), tcls[i]] = cp + lcls += BCEcls(ps[:, 5:], t) # BCE + + # Append targets to text file + # with open('targets.txt', 'a') as file: + # [file.write('%11.5g ' * 4 % tuple(x) + '\n') for x in torch.cat((txy[i], twh[i]), 1)] + + lobj += BCEobj(pi[..., 4], tobj) * balance[i] # obj loss + + s = 3 / no # output count scaling + lbox *= h['box'] * s + lobj *= h['obj'] * s * (1.4 if no == 4 else 1.) + lcls *= h['cls'] * s + bs = tobj.shape[0] # batch size + + loss = lbox + lobj + lcls + return loss * bs, torch.cat((lbox, lobj, lcls, loss)).detach() + + +def build_targets(p, targets, model): + # Build targets for compute_loss(), input targets(image,class,x,y,w,h) + det = model.module.model[-1] if is_parallel(model) else model.model[-1] # Detect() module + na, nt = det.na, targets.shape[0] # number of anchors, targets + tcls, tbox, indices, anch = [], [], [], [] + gain = torch.ones(7, device=targets.device) # normalized to gridspace gain + ai = torch.arange(na, device=targets.device).float().view(na, 1).repeat(1, nt) # same as .repeat_interleave(nt) + targets = torch.cat((targets.repeat(na, 1, 1), ai[:, :, None]), 2) # append anchor indices + + g = 0.5 # bias + off = torch.tensor([[0, 0], + # [1, 0], [0, 1], [-1, 0], [0, -1], # j,k,l,m + # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm + ], device=targets.device).float() * g # offsets + + for i in range(det.nl): + anchors = det.anchors[i] + gain[2:6] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain + + # Match targets to anchors + t = targets * gain + if nt: + # Matches + r = t[:, :, 4:6] / anchors[:, None] # wh ratio + j = torch.max(r, 1. / r).max(2)[0] < model.hyp['anchor_t'] # compare + # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2)) + t = t[j] # filter + + # Offsets + gxy = t[:, 2:4] # grid xy + gxi = gain[[2, 3]] - gxy # inverse + j, k = ((gxy % 1. < g) & (gxy > 1.)).T + l, m = ((gxi % 1. < g) & (gxi > 1.)).T + j = torch.stack((torch.ones_like(j),)) + t = t.repeat((off.shape[0], 1, 1))[j] + offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j] + else: + t = targets[0] + offsets = 0 + + # Define + b, c = t[:, :2].long().T # image, class + gxy = t[:, 2:4] # grid xy + gwh = t[:, 4:6] # grid wh + gij = (gxy - offsets).long() + gi, gj = gij.T # grid xy indices + + # Append + a = t[:, 6].long() # anchor indices + indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1))) # image, anchor, grid indices + tbox.append(torch.cat((gxy - gij, gwh), 1)) # box + anch.append(anchors[a]) # anchors + tcls.append(c) # class + + return tcls, tbox, indices, anch diff --git a/utils/metrics.py b/utils/metrics.py new file mode 100644 index 0000000000..79f18cff3f --- /dev/null +++ b/utils/metrics.py @@ -0,0 +1,203 @@ +# Model validation metrics + +from pathlib import Path + +import matplotlib.pyplot as plt +import numpy as np +import torch + +from . import general + + +def fitness(x): + # Model fitness as a weighted combination of metrics + w = [0.0, 0.0, 0.1, 0.9] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] + return (x[:, :4] * w).sum(1) + + +def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='precision-recall_curve.png', names=[]): + """ Compute the average precision, given the recall and precision curves. + Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. + # Arguments + tp: True positives (nparray, nx1 or nx10). + conf: Objectness value from 0-1 (nparray). + pred_cls: Predicted object classes (nparray). + target_cls: True object classes (nparray). + plot: Plot precision-recall curve at mAP@0.5 + save_dir: Plot save directory + # Returns + The average precision as computed in py-faster-rcnn. + """ + + # Sort by objectness + i = np.argsort(-conf) + tp, conf, pred_cls = tp[i], conf[i], pred_cls[i] + + # Find unique classes + unique_classes = np.unique(target_cls) + + # Create Precision-Recall curve and compute AP for each class + px, py = np.linspace(0, 1, 1000), [] # for plotting + pr_score = 0.1 # score to evaluate P and R https://github.com/ultralytics/yolov3/issues/898 + s = [unique_classes.shape[0], tp.shape[1]] # number class, number iou thresholds (i.e. 10 for mAP0.5...0.95) + ap, p, r = np.zeros(s), np.zeros(s), np.zeros(s) + for ci, c in enumerate(unique_classes): + i = pred_cls == c + n_l = (target_cls == c).sum() # number of labels + n_p = i.sum() # number of predictions + + if n_p == 0 or n_l == 0: + continue + else: + # Accumulate FPs and TPs + fpc = (1 - tp[i]).cumsum(0) + tpc = tp[i].cumsum(0) + + # Recall + recall = tpc / (n_l + 1e-16) # recall curve + r[ci] = np.interp(-pr_score, -conf[i], recall[:, 0]) # r at pr_score, negative x, xp because xp decreases + + # Precision + precision = tpc / (tpc + fpc) # precision curve + p[ci] = np.interp(-pr_score, -conf[i], precision[:, 0]) # p at pr_score + + # AP from recall-precision curve + for j in range(tp.shape[1]): + ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j]) + if plot and (j == 0): + py.append(np.interp(px, mrec, mpre)) # precision at mAP@0.5 + + # Compute F1 score (harmonic mean of precision and recall) + f1 = 2 * p * r / (p + r + 1e-16) + + if plot: + plot_pr_curve(px, py, ap, save_dir, names) + + return p, r, ap, f1, unique_classes.astype('int32') + + +def compute_ap(recall, precision): + """ Compute the average precision, given the recall and precision curves. + Source: https://github.com/rbgirshick/py-faster-rcnn. + # Arguments + recall: The recall curve (list). + precision: The precision curve (list). + # Returns + The average precision as computed in py-faster-rcnn. + """ + + # Append sentinel values to beginning and end + mrec = recall # np.concatenate(([0.], recall, [recall[-1] + 1E-3])) + mpre = precision # np.concatenate(([0.], precision, [0.])) + + # Compute the precision envelope + mpre = np.flip(np.maximum.accumulate(np.flip(mpre))) + + # Integrate area under curve + method = 'interp' # methods: 'continuous', 'interp' + if method == 'interp': + x = np.linspace(0, 1, 101) # 101-point interp (COCO) + ap = np.trapz(np.interp(x, mrec, mpre), x) # integrate + else: # 'continuous' + i = np.where(mrec[1:] != mrec[:-1])[0] # points where x axis (recall) changes + ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) # area under curve + + return ap, mpre, mrec + + +class ConfusionMatrix: + # Updated version of https://github.com/kaanakan/object_detection_confusion_matrix + def __init__(self, nc, conf=0.25, iou_thres=0.45): + self.matrix = np.zeros((nc + 1, nc + 1)) + self.nc = nc # number of classes + self.conf = conf + self.iou_thres = iou_thres + + def process_batch(self, detections, labels): + """ + Return intersection-over-union (Jaccard index) of boxes. + Both sets of boxes are expected to be in (x1, y1, x2, y2) format. + Arguments: + detections (Array[N, 6]), x1, y1, x2, y2, conf, class + labels (Array[M, 5]), class, x1, y1, x2, y2 + Returns: + None, updates confusion matrix accordingly + """ + detections = detections[detections[:, 4] > self.conf] + gt_classes = labels[:, 0].int() + detection_classes = detections[:, 5].int() + iou = general.box_iou(labels[:, 1:], detections[:, :4]) + + x = torch.where(iou > self.iou_thres) + if x[0].shape[0]: + matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() + if x[0].shape[0] > 1: + matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 1], return_index=True)[1]] + matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 0], return_index=True)[1]] + else: + matches = np.zeros((0, 3)) + + n = matches.shape[0] > 0 + m0, m1, _ = matches.transpose().astype(np.int16) + for i, gc in enumerate(gt_classes): + j = m0 == i + if n and sum(j) == 1: + self.matrix[gc, detection_classes[m1[j]]] += 1 # correct + else: + self.matrix[gc, self.nc] += 1 # background FP + + if n: + for i, dc in enumerate(detection_classes): + if not any(m1 == i): + self.matrix[self.nc, dc] += 1 # background FN + + def matrix(self): + return self.matrix + + def plot(self, save_dir='', names=()): + try: + import seaborn as sn + + array = self.matrix / (self.matrix.sum(0).reshape(1, self.nc + 1) + 1E-6) # normalize + array[array < 0.005] = np.nan # don't annotate (would appear as 0.00) + + fig = plt.figure(figsize=(12, 9)) + sn.set(font_scale=1.0 if self.nc < 50 else 0.8) # for label size + labels = (0 < len(names) < 99) and len(names) == self.nc # apply names to ticklabels + sn.heatmap(array, annot=self.nc < 30, annot_kws={"size": 8}, cmap='Blues', fmt='.2f', square=True, + xticklabels=names + ['background FN'] if labels else "auto", + yticklabels=names + ['background FP'] if labels else "auto").set_facecolor((1, 1, 1)) + fig.axes[0].set_xlabel('True') + fig.axes[0].set_ylabel('Predicted') + fig.tight_layout() + fig.savefig(Path(save_dir) / 'confusion_matrix.png', dpi=250) + except Exception as e: + pass + + def print(self): + for i in range(self.nc + 1): + print(' '.join(map(str, self.matrix[i]))) + + +# Plots ---------------------------------------------------------------------------------------------------------------- + +def plot_pr_curve(px, py, ap, save_dir='.', names=()): + fig, ax = plt.subplots(1, 1, figsize=(9, 6)) + py = np.stack(py, axis=1) + + if 0 < len(names) < 21: # show mAP in legend if < 10 classes + for i, y in enumerate(py.T): + ax.plot(px, y, linewidth=1, label=f'{names[i]} %.3f' % ap[i, 0]) # plot(recall, precision) + else: + ax.plot(px, py, linewidth=1, color='grey') # plot(recall, precision) + + ax.plot(px, py.mean(1), linewidth=3, color='blue', label='all classes %.3f mAP@0.5' % ap[:, 0].mean()) + ax.set_xlabel('Recall') + ax.set_ylabel('Precision') + ax.set_xlim(0, 1) + ax.set_ylim(0, 1) + plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left") + fig.tight_layout() + fig.savefig(Path(save_dir) / 'precision_recall_curve.png', dpi=250) diff --git a/utils/parse_config.py b/utils/parse_config.py deleted file mode 100644 index 88d7d7ede4..0000000000 --- a/utils/parse_config.py +++ /dev/null @@ -1,71 +0,0 @@ -import os - -import numpy as np - - -def parse_model_cfg(path): - # Parse the yolo *.cfg file and return module definitions path may be 'cfg/yolov3.cfg', 'yolov3.cfg', or 'yolov3' - if not path.endswith('.cfg'): # add .cfg suffix if omitted - path += '.cfg' - if not os.path.exists(path) and os.path.exists('cfg' + os.sep + path): # add cfg/ prefix if omitted - path = 'cfg' + os.sep + path - - with open(path, 'r') as f: - lines = f.read().split('\n') - lines = [x for x in lines if x and not x.startswith('#')] - lines = [x.rstrip().lstrip() for x in lines] # get rid of fringe whitespaces - mdefs = [] # module definitions - for line in lines: - if line.startswith('['): # This marks the start of a new block - mdefs.append({}) - mdefs[-1]['type'] = line[1:-1].rstrip() - if mdefs[-1]['type'] == 'convolutional': - mdefs[-1]['batch_normalize'] = 0 # pre-populate with zeros (may be overwritten later) - else: - key, val = line.split("=") - key = key.rstrip() - - if key == 'anchors': # return nparray - mdefs[-1][key] = np.array([float(x) for x in val.split(',')]).reshape((-1, 2)) # np anchors - elif (key in ['from', 'layers', 'mask']) or (key == 'size' and ',' in val): # return array - mdefs[-1][key] = [int(x) for x in val.split(',')] - else: - val = val.strip() - # TODO: .isnumeric() actually fails to get the float case - if val.isnumeric(): # return int or float - mdefs[-1][key] = int(val) if (int(val) - float(val)) == 0 else float(val) - else: - mdefs[-1][key] = val # return string - - # Check all fields are supported - supported = ['type', 'batch_normalize', 'filters', 'size', 'stride', 'pad', 'activation', 'layers', 'groups', - 'from', 'mask', 'anchors', 'classes', 'num', 'jitter', 'ignore_thresh', 'truth_thresh', 'random', - 'stride_x', 'stride_y', 'weights_type', 'weights_normalization', 'scale_x_y', 'beta_nms', 'nms_kind', - 'iou_loss', 'iou_normalizer', 'cls_normalizer', 'iou_thresh', 'probability'] - - f = [] # fields - for x in mdefs[1:]: - [f.append(k) for k in x if k not in f] - u = [x for x in f if x not in supported] # unsupported fields - assert not any(u), "Unsupported fields %s in %s. See https://github.com/ultralytics/yolov3/issues/631" % (u, path) - - return mdefs - - -def parse_data_cfg(path): - # Parses the data configuration file - if not os.path.exists(path) and os.path.exists('data' + os.sep + path): # add data/ prefix if omitted - path = 'data' + os.sep + path - - with open(path, 'r') as f: - lines = f.readlines() - - options = dict() - for line in lines: - line = line.strip() - if line == '' or line.startswith('#'): - continue - key, val = line.split('=') - options[key.strip()] = val.strip() - - return options diff --git a/utils/plots.py b/utils/plots.py new file mode 100644 index 0000000000..6b2d7a38bf --- /dev/null +++ b/utils/plots.py @@ -0,0 +1,379 @@ +# Plotting utils + +import glob +import os +import random +from copy import copy +from pathlib import Path + +import cv2 +import math +import matplotlib +import matplotlib.pyplot as plt +import numpy as np +import torch +import yaml +from PIL import Image, ImageDraw +from scipy.signal import butter, filtfilt + +from utils.general import xywh2xyxy, xyxy2xywh +from utils.metrics import fitness + +# Settings +matplotlib.use('Agg') # for writing to files only + + +def color_list(): + # Return first 10 plt colors as (r,g,b) https://stackoverflow.com/questions/51350872/python-from-color-name-to-rgb + def hex2rgb(h): + return tuple(int(h[1 + i:1 + i + 2], 16) for i in (0, 2, 4)) + + return [hex2rgb(h) for h in plt.rcParams['axes.prop_cycle'].by_key()['color']] + + +def hist2d(x, y, n=100): + # 2d histogram used in labels.png and evolve.png + xedges, yedges = np.linspace(x.min(), x.max(), n), np.linspace(y.min(), y.max(), n) + hist, xedges, yedges = np.histogram2d(x, y, (xedges, yedges)) + xidx = np.clip(np.digitize(x, xedges) - 1, 0, hist.shape[0] - 1) + yidx = np.clip(np.digitize(y, yedges) - 1, 0, hist.shape[1] - 1) + return np.log(hist[xidx, yidx]) + + +def butter_lowpass_filtfilt(data, cutoff=1500, fs=50000, order=5): + # https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy + def butter_lowpass(cutoff, fs, order): + nyq = 0.5 * fs + normal_cutoff = cutoff / nyq + return butter(order, normal_cutoff, btype='low', analog=False) + + b, a = butter_lowpass(cutoff, fs, order=order) + return filtfilt(b, a, data) # forward-backward filter + + +def plot_one_box(x, img, color=None, label=None, line_thickness=None): + # Plots one bounding box on image img + tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line/font thickness + color = color or [random.randint(0, 255) for _ in range(3)] + c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) + cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA) + if label: + tf = max(tl - 1, 1) # font thickness + t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] + c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 + cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) # filled + cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA) + + +def plot_wh_methods(): # from utils.plots import *; plot_wh_methods() + # Compares the two methods for width-height anchor multiplication + # https://github.com/ultralytics/yolov3/issues/168 + x = np.arange(-4.0, 4.0, .1) + ya = np.exp(x) + yb = torch.sigmoid(torch.from_numpy(x)).numpy() * 2 + + fig = plt.figure(figsize=(6, 3), dpi=150) + plt.plot(x, ya, '.-', label='YOLOv3') + plt.plot(x, yb ** 2, '.-', label='YOLOv5 ^2') + plt.plot(x, yb ** 1.6, '.-', label='YOLOv5 ^1.6') + plt.xlim(left=-4, right=4) + plt.ylim(bottom=0, top=6) + plt.xlabel('input') + plt.ylabel('output') + plt.grid() + plt.legend() + fig.tight_layout() + fig.savefig('comparison.png', dpi=200) + + +def output_to_target(output): + # Convert model output to target format [batch_id, class_id, x, y, w, h, conf] + targets = [] + for i, o in enumerate(output): + for *box, conf, cls in o.cpu().numpy(): + targets.append([i, cls, *list(*xyxy2xywh(np.array(box)[None])), conf]) + return np.array(targets) + + +def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max_size=640, max_subplots=16): + # Plot image grid with labels + + if isinstance(images, torch.Tensor): + images = images.cpu().float().numpy() + if isinstance(targets, torch.Tensor): + targets = targets.cpu().numpy() + + # un-normalise + if np.max(images[0]) <= 1: + images *= 255 + + tl = 3 # line thickness + tf = max(tl - 1, 1) # font thickness + bs, _, h, w = images.shape # batch size, _, height, width + bs = min(bs, max_subplots) # limit plot images + ns = np.ceil(bs ** 0.5) # number of subplots (square) + + # Check if we should resize + scale_factor = max_size / max(h, w) + if scale_factor < 1: + h = math.ceil(scale_factor * h) + w = math.ceil(scale_factor * w) + + colors = color_list() # list of colors + mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) # init + for i, img in enumerate(images): + if i == max_subplots: # if last batch has fewer images than we expect + break + + block_x = int(w * (i // ns)) + block_y = int(h * (i % ns)) + + img = img.transpose(1, 2, 0) + if scale_factor < 1: + img = cv2.resize(img, (w, h)) + + mosaic[block_y:block_y + h, block_x:block_x + w, :] = img + if len(targets) > 0: + image_targets = targets[targets[:, 0] == i] + boxes = xywh2xyxy(image_targets[:, 2:6]).T + classes = image_targets[:, 1].astype('int') + labels = image_targets.shape[1] == 6 # labels if no conf column + conf = None if labels else image_targets[:, 6] # check for confidence presence (label vs pred) + + if boxes.shape[1] and boxes.max() <= 1: # if normalized + boxes[[0, 2]] *= w # scale to pixels + boxes[[1, 3]] *= h + boxes[[0, 2]] += block_x + boxes[[1, 3]] += block_y + for j, box in enumerate(boxes.T): + cls = int(classes[j]) + color = colors[cls % len(colors)] + cls = names[cls] if names else cls + if labels or conf[j] > 0.25: # 0.25 conf thresh + label = '%s' % cls if labels else '%s %.1f' % (cls, conf[j]) + plot_one_box(box, mosaic, label=label, color=color, line_thickness=tl) + + # Draw image filename labels + if paths: + label = Path(paths[i]).name[:40] # trim to 40 char + t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] + cv2.putText(mosaic, label, (block_x + 5, block_y + t_size[1] + 5), 0, tl / 3, [220, 220, 220], thickness=tf, + lineType=cv2.LINE_AA) + + # Image border + cv2.rectangle(mosaic, (block_x, block_y), (block_x + w, block_y + h), (255, 255, 255), thickness=3) + + if fname: + r = min(1280. / max(h, w) / ns, 1.0) # ratio to limit image size + mosaic = cv2.resize(mosaic, (int(ns * w * r), int(ns * h * r)), interpolation=cv2.INTER_AREA) + # cv2.imwrite(fname, cv2.cvtColor(mosaic, cv2.COLOR_BGR2RGB)) # cv2 save + Image.fromarray(mosaic).save(fname) # PIL save + return mosaic + + +def plot_lr_scheduler(optimizer, scheduler, epochs=300, save_dir=''): + # Plot LR simulating training for full epochs + optimizer, scheduler = copy(optimizer), copy(scheduler) # do not modify originals + y = [] + for _ in range(epochs): + scheduler.step() + y.append(optimizer.param_groups[0]['lr']) + plt.plot(y, '.-', label='LR') + plt.xlabel('epoch') + plt.ylabel('LR') + plt.grid() + plt.xlim(0, epochs) + plt.ylim(0) + plt.tight_layout() + plt.savefig(Path(save_dir) / 'LR.png', dpi=200) + + +def plot_test_txt(): # from utils.plots import *; plot_test() + # Plot test.txt histograms + x = np.loadtxt('test.txt', dtype=np.float32) + box = xyxy2xywh(x[:, :4]) + cx, cy = box[:, 0], box[:, 1] + + fig, ax = plt.subplots(1, 1, figsize=(6, 6), tight_layout=True) + ax.hist2d(cx, cy, bins=600, cmax=10, cmin=0) + ax.set_aspect('equal') + plt.savefig('hist2d.png', dpi=300) + + fig, ax = plt.subplots(1, 2, figsize=(12, 6), tight_layout=True) + ax[0].hist(cx, bins=600) + ax[1].hist(cy, bins=600) + plt.savefig('hist1d.png', dpi=200) + + +def plot_targets_txt(): # from utils.plots import *; plot_targets_txt() + # Plot targets.txt histograms + x = np.loadtxt('targets.txt', dtype=np.float32).T + s = ['x targets', 'y targets', 'width targets', 'height targets'] + fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) + ax = ax.ravel() + for i in range(4): + ax[i].hist(x[i], bins=100, label='%.3g +/- %.3g' % (x[i].mean(), x[i].std())) + ax[i].legend() + ax[i].set_title(s[i]) + plt.savefig('targets.jpg', dpi=200) + + +def plot_study_txt(path='', x=None): # from utils.plots import *; plot_study_txt() + # Plot study.txt generated by test.py + fig, ax = plt.subplots(2, 4, figsize=(10, 6), tight_layout=True) + ax = ax.ravel() + + fig2, ax2 = plt.subplots(1, 1, figsize=(8, 4), tight_layout=True) + for f in [Path(path) / f'study_coco_{x}.txt' for x in ['yolov3', 'yolov3-spp', 'yolov3-tiny']]: + y = np.loadtxt(f, dtype=np.float32, usecols=[0, 1, 2, 3, 7, 8, 9], ndmin=2).T + x = np.arange(y.shape[1]) if x is None else np.array(x) + s = ['P', 'R', 'mAP@.5', 'mAP@.5:.95', 't_inference (ms/img)', 't_NMS (ms/img)', 't_total (ms/img)'] + for i in range(7): + ax[i].plot(x, y[i], '.-', linewidth=2, markersize=8) + ax[i].set_title(s[i]) + + j = y[3].argmax() + 1 + ax2.plot(y[6, :j], y[3, :j] * 1E2, '.-', linewidth=2, markersize=8, + label=f.stem.replace('study_coco_', '').replace('yolo', 'YOLO')) + + ax2.plot(1E3 / np.array([209, 140, 97, 58, 35, 18]), [34.6, 40.5, 43.0, 47.5, 49.7, 51.5], + 'k.-', linewidth=2, markersize=8, alpha=.25, label='EfficientDet') + + ax2.grid() + ax2.set_xlim(0, 30) + ax2.set_ylim(15, 50) + ax2.set_yticks(np.arange(15, 55, 5)) + ax2.set_xlabel('GPU Speed (ms/img)') + ax2.set_ylabel('COCO AP val') + ax2.legend(loc='lower right') + plt.savefig('test_study.png', dpi=300) + + +def plot_labels(labels, save_dir=''): + # plot dataset labels + c, b = labels[:, 0], labels[:, 1:].transpose() # classes, boxes + nc = int(c.max() + 1) # number of classes + colors = color_list() + + # seaborn correlogram + try: + import seaborn as sns + import pandas as pd + x = pd.DataFrame(b.transpose(), columns=['x', 'y', 'width', 'height']) + sns.pairplot(x, corner=True, diag_kind='hist', kind='scatter', markers='o', + plot_kws=dict(s=3, edgecolor=None, linewidth=1, alpha=0.02), + diag_kws=dict(bins=50)) + plt.savefig(Path(save_dir) / 'labels_correlogram.png', dpi=200) + plt.close() + except Exception as e: + pass + + # matplotlib labels + ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True)[1].ravel() + ax[0].hist(c, bins=np.linspace(0, nc, nc + 1) - 0.5, rwidth=0.8) + ax[0].set_xlabel('classes') + ax[2].scatter(b[0], b[1], c=hist2d(b[0], b[1], 90), cmap='jet') + ax[2].set_xlabel('x') + ax[2].set_ylabel('y') + ax[3].scatter(b[2], b[3], c=hist2d(b[2], b[3], 90), cmap='jet') + ax[3].set_xlabel('width') + ax[3].set_ylabel('height') + + # rectangles + labels[:, 1:3] = 0.5 # center + labels[:, 1:] = xywh2xyxy(labels[:, 1:]) * 2000 + img = Image.fromarray(np.ones((2000, 2000, 3), dtype=np.uint8) * 255) + for cls, *box in labels[:1000]: + ImageDraw.Draw(img).rectangle(box, width=1, outline=colors[int(cls) % 10]) # plot + ax[1].imshow(img) + ax[1].axis('off') + + for a in [0, 1, 2, 3]: + for s in ['top', 'right', 'left', 'bottom']: + ax[a].spines[s].set_visible(False) + plt.savefig(Path(save_dir) / 'labels.png', dpi=200) + plt.close() + + +def plot_evolution(yaml_file='data/hyp.finetune.yaml'): # from utils.plots import *; plot_evolution() + # Plot hyperparameter evolution results in evolve.txt + with open(yaml_file) as f: + hyp = yaml.load(f, Loader=yaml.FullLoader) + x = np.loadtxt('evolve.txt', ndmin=2) + f = fitness(x) + # weights = (f - f.min()) ** 2 # for weighted results + plt.figure(figsize=(10, 12), tight_layout=True) + matplotlib.rc('font', **{'size': 8}) + for i, (k, v) in enumerate(hyp.items()): + y = x[:, i + 7] + # mu = (y * weights).sum() / weights.sum() # best weighted result + mu = y[f.argmax()] # best single result + plt.subplot(6, 5, i + 1) + plt.scatter(y, f, c=hist2d(y, f, 20), cmap='viridis', alpha=.8, edgecolors='none') + plt.plot(mu, f.max(), 'k+', markersize=15) + plt.title('%s = %.3g' % (k, mu), fontdict={'size': 9}) # limit to 40 characters + if i % 5 != 0: + plt.yticks([]) + print('%15s: %.3g' % (k, mu)) + plt.savefig('evolve.png', dpi=200) + print('\nPlot saved as evolve.png') + + +def plot_results_overlay(start=0, stop=0): # from utils.plots import *; plot_results_overlay() + # Plot training 'results*.txt', overlaying train and val losses + s = ['train', 'train', 'train', 'Precision', 'mAP@0.5', 'val', 'val', 'val', 'Recall', 'mAP@0.5:0.95'] # legends + t = ['Box', 'Objectness', 'Classification', 'P-R', 'mAP-F1'] # titles + for f in sorted(glob.glob('results*.txt') + glob.glob('../../Downloads/results*.txt')): + results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T + n = results.shape[1] # number of rows + x = range(start, min(stop, n) if stop else n) + fig, ax = plt.subplots(1, 5, figsize=(14, 3.5), tight_layout=True) + ax = ax.ravel() + for i in range(5): + for j in [i, i + 5]: + y = results[j, x] + ax[i].plot(x, y, marker='.', label=s[j]) + # y_smooth = butter_lowpass_filtfilt(y) + # ax[i].plot(x, np.gradient(y_smooth), marker='.', label=s[j]) + + ax[i].set_title(t[i]) + ax[i].legend() + ax[i].set_ylabel(f) if i == 0 else None # add filename + fig.savefig(f.replace('.txt', '.png'), dpi=200) + + +def plot_results(start=0, stop=0, bucket='', id=(), labels=(), save_dir=''): + # Plot training 'results*.txt'. from utils.plots import *; plot_results(save_dir='runs/train/exp') + fig, ax = plt.subplots(2, 5, figsize=(12, 6)) + ax = ax.ravel() + s = ['Box', 'Objectness', 'Classification', 'Precision', 'Recall', + 'val Box', 'val Objectness', 'val Classification', 'mAP@0.5', 'mAP@0.5:0.95'] + if bucket: + # files = ['https://storage.googleapis.com/%s/results%g.txt' % (bucket, x) for x in id] + files = ['results%g.txt' % x for x in id] + c = ('gsutil cp ' + '%s ' * len(files) + '.') % tuple('gs://%s/results%g.txt' % (bucket, x) for x in id) + os.system(c) + else: + files = list(Path(save_dir).glob('results*.txt')) + assert len(files), 'No results.txt files found in %s, nothing to plot.' % os.path.abspath(save_dir) + for fi, f in enumerate(files): + try: + results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T + n = results.shape[1] # number of rows + x = range(start, min(stop, n) if stop else n) + for i in range(10): + y = results[i, x] + if i in [0, 1, 2, 5, 6, 7]: + y[y == 0] = np.nan # don't show zero loss values + # y /= y[0] # normalize + label = labels[fi] if len(labels) else f.stem + ax[i].plot(x, y, marker='.', label=label, linewidth=2, markersize=8) + ax[i].set_title(s[i]) + # if i in [5, 6, 7]: # share train and val loss y axes + # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) + except Exception as e: + print('Warning: Plotting error for %s; %s' % (f, e)) + + fig.tight_layout() + ax[1].legend() + fig.savefig(Path(save_dir) / 'results.png', dpi=200) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index d4cd1e8078..b330ca56a2 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -1,24 +1,45 @@ +# PyTorch utils + +import logging import math import os import time +from contextlib import contextmanager from copy import deepcopy import torch import torch.backends.cudnn as cudnn import torch.nn as nn import torch.nn.functional as F +import torchvision +logger = logging.getLogger(__name__) -def init_seeds(seed=0): - torch.manual_seed(seed) - # Reduce randomness (may be slower on Tesla GPUs) # https://pytorch.org/docs/stable/notes/randomness.html - if seed == 0: +@contextmanager +def torch_distributed_zero_first(local_rank: int): + """ + Decorator to make all processes in distributed training wait for each local_master to do something. + """ + if local_rank not in [-1, 0]: + torch.distributed.barrier() + yield + if local_rank == 0: + torch.distributed.barrier() + + +def init_torch_seeds(seed=0): + # Speed-reproducibility tradeoff https://pytorch.org/docs/stable/notes/randomness.html + torch.manual_seed(seed) + if seed == 0: # slower, more reproducible + cudnn.deterministic = True + cudnn.benchmark = False + else: # faster, less reproducible cudnn.deterministic = False cudnn.benchmark = True -def select_device(device='', apex=False, batch_size=None): +def select_device(device='', batch_size=None): # device = 'cpu' or '0' or '0,1,2,3' cpu_request = device.lower() == 'cpu' if device and not cpu_request: # if device requested other than 'cpu' @@ -32,16 +53,15 @@ def select_device(device='', apex=False, batch_size=None): if ng > 1 and batch_size: # check that batch_size is compatible with device_count assert batch_size % ng == 0, 'batch-size %g not multiple of GPU count %g' % (batch_size, ng) x = [torch.cuda.get_device_properties(i) for i in range(ng)] - s = 'Using CUDA ' + ('Apex ' if apex else '') # apex for mixed precision https://github.com/NVIDIA/apex + s = f'Using torch {torch.__version__} ' for i in range(0, ng): if i == 1: s = ' ' * len(s) - print("%sdevice%g _CudaDeviceProperties(name='%s', total_memory=%dMB)" % - (s, i, x[i].name, x[i].total_memory / c)) + logger.info("%sCUDA:%g (%s, %dMB)" % (s, i, x[i].name, x[i].total_memory / c)) else: - print('Using CPU') + logger.info(f'Using torch {torch.__version__} CPU') - print('') # skip a line + logger.info('') # skip a line return torch.device('cuda:0' if cuda else 'cpu') @@ -50,52 +70,77 @@ def time_synchronized(): return time.time() +def is_parallel(model): + return type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) + + +def intersect_dicts(da, db, exclude=()): + # Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values + return {k: v for k, v in da.items() if k in db and not any(x in k for x in exclude) and v.shape == db[k].shape} + + def initialize_weights(model): for m in model.modules(): t = type(m) if t is nn.Conv2d: pass # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') elif t is nn.BatchNorm2d: - m.eps = 1e-4 + m.eps = 1e-3 m.momentum = 0.03 - elif t in [nn.LeakyReLU, nn.ReLU, nn.ReLU6]: + elif t in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6]: m.inplace = True def find_modules(model, mclass=nn.Conv2d): - # finds layer indices matching module class 'mclass' + # Finds layer indices matching module class 'mclass' return [i for i, m in enumerate(model.module_list) if isinstance(m, mclass)] -def fuse_conv_and_bn(conv, bn): - # https://tehnokv.com/posts/fusing-batchnorm-and-conv/ - with torch.no_grad(): - # init - fusedconv = torch.nn.Conv2d(conv.in_channels, - conv.out_channels, - kernel_size=conv.kernel_size, - stride=conv.stride, - padding=conv.padding, - bias=True) - - # prepare filters - w_conv = conv.weight.clone().view(conv.out_channels, -1) - w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var))) - fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.size())) - - # prepare spatial bias - if conv.bias is not None: - b_conv = conv.bias - else: - b_conv = torch.zeros(conv.weight.size(0)) - b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(torch.sqrt(bn.running_var + bn.eps)) - fusedconv.bias.copy_(torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn) +def sparsity(model): + # Return global model sparsity + a, b = 0., 0. + for p in model.parameters(): + a += p.numel() + b += (p == 0).sum() + return b / a - return fusedconv +def prune(model, amount=0.3): + # Prune model to requested global sparsity + import torch.nn.utils.prune as prune + print('Pruning model... ', end='') + for name, m in model.named_modules(): + if isinstance(m, nn.Conv2d): + prune.l1_unstructured(m, name='weight', amount=amount) # prune + prune.remove(m, 'weight') # make permanent + print(' %.3g global sparsity' % sparsity(model)) -def model_info(model, verbose=False): - # Plots a line-by-line description of a PyTorch model + +def fuse_conv_and_bn(conv, bn): + # Fuse convolution and batchnorm layers https://tehnokv.com/posts/fusing-batchnorm-and-conv/ + fusedconv = nn.Conv2d(conv.in_channels, + conv.out_channels, + kernel_size=conv.kernel_size, + stride=conv.stride, + padding=conv.padding, + groups=conv.groups, + bias=True).requires_grad_(False).to(conv.weight.device) + + # prepare filters + w_conv = conv.weight.clone().view(conv.out_channels, -1) + w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var))) + fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.size())) + + # prepare spatial bias + b_conv = torch.zeros(conv.weight.size(0), device=conv.weight.device) if conv.bias is None else conv.bias + b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(torch.sqrt(bn.running_var + bn.eps)) + fusedconv.bias.copy_(torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn) + + return fusedconv + + +def model_info(model, verbose=False, img_size=640): + # Model information. img_size may be int or list, i.e. img_size=640 or img_size=[640, 320] n_p = sum(x.numel() for x in model.parameters()) # number parameters n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients if verbose: @@ -107,40 +152,57 @@ def model_info(model, verbose=False): try: # FLOPS from thop import profile - macs, _ = profile(model, inputs=(torch.zeros(1, 3, 480, 640),), verbose=False) - fs = ', %.1f GFLOPS' % (macs / 1E9 * 2) - except: + stride = int(model.stride.max()) + img = torch.zeros((1, 3, stride, stride), device=next(model.parameters()).device) # input + flops = profile(deepcopy(model), inputs=(img,), verbose=False)[0] / 1E9 * 2 # stride FLOPS + img_size = img_size if isinstance(img_size, list) else [img_size, img_size] # expand if int/float + fs = ', %.1f GFLOPS' % (flops * img_size[0] / stride * img_size[1] / stride) # 640x640 FLOPS + except (ImportError, Exception): fs = '' - print('Model Summary: %g layers, %g parameters, %g gradients%s' % (len(list(model.parameters())), n_p, n_g, fs)) + logger.info(f"Model Summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}") def load_classifier(name='resnet101', n=2): # Loads a pretrained model reshaped to n-class output - import pretrainedmodels # https://github.com/Cadene/pretrained-models.pytorch#torchvision - model = pretrainedmodels.__dict__[name](num_classes=1000, pretrained='imagenet') + model = torchvision.models.__dict__[name](pretrained=True) - # Display model properties - for x in ['model.input_size', 'model.input_space', 'model.input_range', 'model.mean', 'model.std']: - print(x + ' =', eval(x)) + # ResNet model properties + # input_size = [3, 224, 224] + # input_space = 'RGB' + # input_range = [0, 1] + # mean = [0.485, 0.456, 0.406] + # std = [0.229, 0.224, 0.225] # Reshape output to n classes - filters = model.last_linear.weight.shape[1] - model.last_linear.bias = torch.nn.Parameter(torch.zeros(n)) - model.last_linear.weight = torch.nn.Parameter(torch.zeros(n, filters)) - model.last_linear.out_features = n + filters = model.fc.weight.shape[1] + model.fc.bias = nn.Parameter(torch.zeros(n), requires_grad=True) + model.fc.weight = nn.Parameter(torch.zeros(n, filters), requires_grad=True) + model.fc.out_features = n return model -def scale_img(img, ratio=1.0, same_shape=True): # img(16,3,256,416), r=ratio +def scale_img(img, ratio=1.0, same_shape=False): # img(16,3,256,416), r=ratio # scales img(bs,3,y,x) by ratio - h, w = img.shape[2:] - s = (int(h * ratio), int(w * ratio)) # new size - img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize - if not same_shape: # pad/crop img - gs = 64 # (pixels) grid size - h, w = [math.ceil(x * ratio / gs) * gs for x in (h, w)] - return F.pad(img, [0, w - s[1], 0, h - s[0]], value=0.447) # value = imagenet mean + if ratio == 1.0: + return img + else: + h, w = img.shape[2:] + s = (int(h * ratio), int(w * ratio)) # new size + img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize + if not same_shape: # pad/crop img + gs = 32 # (pixels) grid size + h, w = [math.ceil(x * ratio / gs) * gs for x in (h, w)] + return F.pad(img, [0, w - s[1], 0, h - s[0]], value=0.447) # value = imagenet mean + + +def copy_attr(a, b, include=(), exclude=()): + # Copy attributes from b to a, options to only include [...] and to exclude [...] + for k, v in b.__dict__.items(): + if (len(include) and k not in include) or k.startswith('_') or k in exclude: + continue + else: + setattr(a, k, v) class ModelEMA: @@ -149,46 +211,32 @@ class ModelEMA: This is intended to allow functionality like https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage A smoothed version of the weights is necessary for some training schemes to perform well. - E.g. Google's hyper-params for training MNASNet, MobileNet-V3, EfficientNet, etc that use - RMSprop with a short 2.4-3 epoch decay period and slow LR decay rate of .96-.99 requires EMA - smoothing of weights to match results. Pay attention to the decay constant you are using - relative to your update count per epoch. - To keep EMA from using GPU resources, set device='cpu'. This will save a bit of memory but - disable validation of the EMA weights. Validation will have to be done manually in a separate - process, or after the training stops converging. This class is sensitive where it is initialized in the sequence of model init, GPU assignment and distributed training wrappers. - I've tested with the sequence in my own train.py for torch.DataParallel, apex.DDP, and single-GPU. """ - def __init__(self, model, decay=0.9999, device=''): - # make a copy of the model for accumulating moving average of weights - self.ema = deepcopy(model) - self.ema.eval() - self.updates = 0 # number of EMA updates + def __init__(self, model, decay=0.9999, updates=0): + # Create EMA + self.ema = deepcopy(model.module if is_parallel(model) else model).eval() # FP32 EMA + # if next(model.parameters()).device.type != 'cpu': + # self.ema.half() # FP16 EMA + self.updates = updates # number of EMA updates self.decay = lambda x: decay * (1 - math.exp(-x / 2000)) # decay exponential ramp (to help early epochs) - self.device = device # perform ema on different device from model if set - if device: - self.ema.to(device=device) for p in self.ema.parameters(): p.requires_grad_(False) def update(self, model): - self.updates += 1 - d = self.decay(self.updates) + # Update EMA parameters with torch.no_grad(): - if type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel): - msd, esd = model.module.state_dict(), self.ema.module.state_dict() - else: - msd, esd = model.state_dict(), self.ema.state_dict() + self.updates += 1 + d = self.decay(self.updates) - for k, v in esd.items(): + msd = model.module.state_dict() if is_parallel(model) else model.state_dict() # model state_dict + for k, v in self.ema.state_dict().items(): if v.dtype.is_floating_point: v *= d v += (1. - d) * msd[k].detach() - def update_attr(self, model): - # Assign attributes (which may change during training) - for k in model.__dict__.keys(): - if not k.startswith('_'): - setattr(self.ema, k, getattr(model, k)) + def update_attr(self, model, include=(), exclude=('process_group', 'reducer')): + # Update EMA attributes + copy_attr(self.ema, model, include, exclude) diff --git a/utils/utils.py b/utils/utils.py deleted file mode 100755 index 08ece411b2..0000000000 --- a/utils/utils.py +++ /dev/null @@ -1,1080 +0,0 @@ -import glob -import math -import os -import random -import shutil -import subprocess -import time -from copy import copy -from pathlib import Path -from sys import platform - -import cv2 -import matplotlib -import matplotlib.pyplot as plt -import numpy as np -import torch -import torch.nn as nn -import torchvision -from tqdm import tqdm - -from . import torch_utils # , google_utils - -# Set printoptions -torch.set_printoptions(linewidth=320, precision=5, profile='long') -np.set_printoptions(linewidth=320, formatter={'float_kind': '{:11.5g}'.format}) # format short g, %precision=5 -matplotlib.rc('font', **{'size': 11}) - -# Prevent OpenCV from multithreading (to use PyTorch DataLoader) -cv2.setNumThreads(0) - - -def init_seeds(seed=0): - random.seed(seed) - np.random.seed(seed) - torch_utils.init_seeds(seed=seed) - - -def check_git_status(): - if platform in ['linux', 'darwin']: - # Suggest 'git pull' if repo is out of date - s = subprocess.check_output('if [ -d .git ]; then git fetch && git status -uno; fi', shell=True).decode('utf-8') - if 'Your branch is behind' in s: - print(s[s.find('Your branch is behind'):s.find('\n\n')] + '\n') - - -def check_file(file): - # Searches for file if not found locally - if os.path.isfile(file): - return file - else: - files = glob.glob('./**/' + file, recursive=True) # find file - assert len(files), 'File Not Found: %s' % file # assert file was found - return files[0] # return first file if multiple found - - -def load_classes(path): - # Loads *.names file at 'path' - with open(path, 'r') as f: - names = f.read().split('\n') - return list(filter(None, names)) # filter removes empty strings (such as last line) - - -def labels_to_class_weights(labels, nc=80): - # Get class weights (inverse frequency) from training labels - if labels[0] is None: # no labels loaded - return torch.Tensor() - - labels = np.concatenate(labels, 0) # labels.shape = (866643, 5) for COCO - classes = labels[:, 0].astype(np.int) # labels = [class xywh] - weights = np.bincount(classes, minlength=nc) # occurences per class - - # Prepend gridpoint count (for uCE trianing) - # gpi = ((320 / 32 * np.array([1, 2, 4])) ** 2 * 3).sum() # gridpoints per image - # weights = np.hstack([gpi * len(labels) - weights.sum() * 9, weights * 9]) ** 0.5 # prepend gridpoints to start - - weights[weights == 0] = 1 # replace empty bins with 1 - weights = 1 / weights # number of targets per class - weights /= weights.sum() # normalize - return torch.from_numpy(weights) - - -def labels_to_image_weights(labels, nc=80, class_weights=np.ones(80)): - # Produces image weights based on class mAPs - n = len(labels) - class_counts = np.array([np.bincount(labels[i][:, 0].astype(np.int), minlength=nc) for i in range(n)]) - image_weights = (class_weights.reshape(1, nc) * class_counts).sum(1) - # index = random.choices(range(n), weights=image_weights, k=1) # weight image sample - return image_weights - - -def coco80_to_coco91_class(): # converts 80-index (val2014) to 91-index (paper) - # https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/ - # a = np.loadtxt('data/coco.names', dtype='str', delimiter='\n') - # b = np.loadtxt('data/coco_paper.names', dtype='str', delimiter='\n') - # x1 = [list(a[i] == b).index(True) + 1 for i in range(80)] # darknet to coco - # x2 = [list(b[i] == a).index(True) if any(b[i] == a) else None for i in range(91)] # coco to darknet - x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 67, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] - return x - - -def xyxy2xywh(x): - # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] where xy1=top-left, xy2=bottom-right - y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) - y[:, 0] = (x[:, 0] + x[:, 2]) / 2 # x center - y[:, 1] = (x[:, 1] + x[:, 3]) / 2 # y center - y[:, 2] = x[:, 2] - x[:, 0] # width - y[:, 3] = x[:, 3] - x[:, 1] # height - return y - - -def xywh2xyxy(x): - # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right - y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) - y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x - y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y - y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x - y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y - return y - - -def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None): - # Rescale coords (xyxy) from img1_shape to img0_shape - if ratio_pad is None: # calculate from img0_shape - gain = max(img1_shape) / max(img0_shape) # gain = old / new - pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding - else: - gain = ratio_pad[0][0] - pad = ratio_pad[1] - - coords[:, [0, 2]] -= pad[0] # x padding - coords[:, [1, 3]] -= pad[1] # y padding - coords[:, :4] /= gain - clip_coords(coords, img0_shape) - return coords - - -def clip_coords(boxes, img_shape): - # Clip bounding xyxy bounding boxes to image shape (height, width) - boxes[:, 0].clamp_(0, img_shape[1]) # x1 - boxes[:, 1].clamp_(0, img_shape[0]) # y1 - boxes[:, 2].clamp_(0, img_shape[1]) # x2 - boxes[:, 3].clamp_(0, img_shape[0]) # y2 - - -def ap_per_class(tp, conf, pred_cls, target_cls): - """ Compute the average precision, given the recall and precision curves. - Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. - # Arguments - tp: True positives (nparray, nx1 or nx10). - conf: Objectness value from 0-1 (nparray). - pred_cls: Predicted object classes (nparray). - target_cls: True object classes (nparray). - # Returns - The average precision as computed in py-faster-rcnn. - """ - - # Sort by objectness - i = np.argsort(-conf) - tp, conf, pred_cls = tp[i], conf[i], pred_cls[i] - - # Find unique classes - unique_classes = np.unique(target_cls) - - # Create Precision-Recall curve and compute AP for each class - pr_score = 0.1 # score to evaluate P and R https://github.com/ultralytics/yolov3/issues/898 - s = [unique_classes.shape[0], tp.shape[1]] # number class, number iou thresholds (i.e. 10 for mAP0.5...0.95) - ap, p, r = np.zeros(s), np.zeros(s), np.zeros(s) - for ci, c in enumerate(unique_classes): - i = pred_cls == c - n_gt = (target_cls == c).sum() # Number of ground truth objects - n_p = i.sum() # Number of predicted objects - - if n_p == 0 or n_gt == 0: - continue - else: - # Accumulate FPs and TPs - fpc = (1 - tp[i]).cumsum(0) - tpc = tp[i].cumsum(0) - - # Recall - recall = tpc / (n_gt + 1e-16) # recall curve - r[ci] = np.interp(-pr_score, -conf[i], recall[:, 0]) # r at pr_score, negative x, xp because xp decreases - - # Precision - precision = tpc / (tpc + fpc) # precision curve - p[ci] = np.interp(-pr_score, -conf[i], precision[:, 0]) # p at pr_score - - # AP from recall-precision curve - for j in range(tp.shape[1]): - ap[ci, j] = compute_ap(recall[:, j], precision[:, j]) - - # Plot - # fig, ax = plt.subplots(1, 1, figsize=(5, 5)) - # ax.plot(recall, precision) - # ax.set_xlabel('Recall') - # ax.set_ylabel('Precision') - # ax.set_xlim(0, 1.01) - # ax.set_ylim(0, 1.01) - # fig.tight_layout() - # fig.savefig('PR_curve.png', dpi=300) - - # Compute F1 score (harmonic mean of precision and recall) - f1 = 2 * p * r / (p + r + 1e-16) - - return p, r, ap, f1, unique_classes.astype('int32') - - -def compute_ap(recall, precision): - """ Compute the average precision, given the recall and precision curves. - Source: https://github.com/rbgirshick/py-faster-rcnn. - # Arguments - recall: The recall curve (list). - precision: The precision curve (list). - # Returns - The average precision as computed in py-faster-rcnn. - """ - - # Append sentinel values to beginning and end - mrec = np.concatenate(([0.], recall, [min(recall[-1] + 1E-3, 1.)])) - mpre = np.concatenate(([0.], precision, [0.])) - - # Compute the precision envelope - mpre = np.flip(np.maximum.accumulate(np.flip(mpre))) - - # Integrate area under curve - method = 'interp' # methods: 'continuous', 'interp' - if method == 'interp': - x = np.linspace(0, 1, 101) # 101-point interp (COCO) - ap = np.trapz(np.interp(x, mrec, mpre), x) # integrate - else: # 'continuous' - i = np.where(mrec[1:] != mrec[:-1])[0] # points where x axis (recall) changes - ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) # area under curve - - return ap - - -def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False): - # Returns the IoU of box1 to box2. box1 is 4, box2 is nx4 - box2 = box2.t() - - # Get the coordinates of bounding boxes - if x1y1x2y2: # x1, y1, x2, y2 = box1 - b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3] - b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3] - else: # transform from xywh to xyxy - b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2 - b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2 - b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2 - b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2 - - # Intersection area - inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \ - (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0) - - # Union Area - w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 - w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 - union = (w1 * h1 + 1e-16) + w2 * h2 - inter - - iou = inter / union # iou - if GIoU or DIoU or CIoU: - cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1) # convex (smallest enclosing box) width - ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1) # convex height - if GIoU: # Generalized IoU https://arxiv.org/pdf/1902.09630.pdf - c_area = cw * ch + 1e-16 # convex area - return iou - (c_area - union) / c_area # GIoU - if DIoU or CIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1 - # convex diagonal squared - c2 = cw ** 2 + ch ** 2 + 1e-16 - # centerpoint distance squared - rho2 = ((b2_x1 + b2_x2) - (b1_x1 + b1_x2)) ** 2 / 4 + ((b2_y1 + b2_y2) - (b1_y1 + b1_y2)) ** 2 / 4 - if DIoU: - return iou - rho2 / c2 # DIoU - elif CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47 - v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2) - with torch.no_grad(): - alpha = v / (1 - iou + v) - return iou - (rho2 / c2 + v * alpha) # CIoU - - return iou - - -def box_iou(box1, box2): - # https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py - """ - Return intersection-over-union (Jaccard index) of boxes. - Both sets of boxes are expected to be in (x1, y1, x2, y2) format. - Arguments: - box1 (Tensor[N, 4]) - box2 (Tensor[M, 4]) - Returns: - iou (Tensor[N, M]): the NxM matrix containing the pairwise - IoU values for every element in boxes1 and boxes2 - """ - - def box_area(box): - # box = 4xn - return (box[2] - box[0]) * (box[3] - box[1]) - - area1 = box_area(box1.t()) - area2 = box_area(box2.t()) - - # inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2) - inter = (torch.min(box1[:, None, 2:], box2[:, 2:]) - torch.max(box1[:, None, :2], box2[:, :2])).clamp(0).prod(2) - return inter / (area1[:, None] + area2 - inter) # iou = inter / (area1 + area2 - inter) - - -def wh_iou(wh1, wh2): - # Returns the nxm IoU matrix. wh1 is nx2, wh2 is mx2 - wh1 = wh1[:, None] # [N,1,2] - wh2 = wh2[None] # [1,M,2] - inter = torch.min(wh1, wh2).prod(2) # [N,M] - return inter / (wh1.prod(2) + wh2.prod(2) - inter) # iou = inter / (area1 + area2 - inter) - - -class FocalLoss(nn.Module): - # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) - def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): - super(FocalLoss, self).__init__() - self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() - self.gamma = gamma - self.alpha = alpha - self.reduction = loss_fcn.reduction - self.loss_fcn.reduction = 'none' # required to apply FL to each element - - def forward(self, pred, true): - loss = self.loss_fcn(pred, true) - # p_t = torch.exp(-loss) - # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability - - # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py - pred_prob = torch.sigmoid(pred) # prob from logits - p_t = true * pred_prob + (1 - true) * (1 - pred_prob) - alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) - modulating_factor = (1.0 - p_t) ** self.gamma - loss *= alpha_factor * modulating_factor - - if self.reduction == 'mean': - return loss.mean() - elif self.reduction == 'sum': - return loss.sum() - else: # 'none' - return loss - - -def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 - # return positive, negative label smoothing BCE targets - return 1.0 - 0.5 * eps, 0.5 * eps - - -def compute_loss(p, targets, model): # predictions, targets, model - ft = torch.cuda.FloatTensor if p[0].is_cuda else torch.Tensor - lcls, lbox, lobj = ft([0]), ft([0]), ft([0]) - tcls, tbox, indices, anchors = build_targets(p, targets, model) # targets - h = model.hyp # hyperparameters - red = 'mean' # Loss reduction (sum or mean) - - # Define criteria - BCEcls = nn.BCEWithLogitsLoss(pos_weight=ft([h['cls_pw']]), reduction=red) - BCEobj = nn.BCEWithLogitsLoss(pos_weight=ft([h['obj_pw']]), reduction=red) - - # class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 - cp, cn = smooth_BCE(eps=0.0) - - # focal loss - g = h['fl_gamma'] # focal loss gamma - if g > 0: - BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) - - # per output - nt = 0 # targets - for i, pi in enumerate(p): # layer index, layer predictions - b, a, gj, gi = indices[i] # image, anchor, gridy, gridx - tobj = torch.zeros_like(pi[..., 0]) # target obj - - nb = b.shape[0] # number of targets - if nb: - nt += nb # cumulative targets - ps = pi[b, a, gj, gi] # prediction subset corresponding to targets - - # GIoU - pxy = ps[:, :2].sigmoid() - pwh = ps[:, 2:4].exp().clamp(max=1E3) * anchors[i] - pbox = torch.cat((pxy, pwh), 1) # predicted box - giou = bbox_iou(pbox.t(), tbox[i], x1y1x2y2=False, GIoU=True) # giou(prediction, target) - lbox += (1.0 - giou).sum() if red == 'sum' else (1.0 - giou).mean() # giou loss - - # Obj - tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * giou.detach().clamp(0).type(tobj.dtype) # giou ratio - - # Class - if model.nc > 1: # cls loss (only if multiple classes) - t = torch.full_like(ps[:, 5:], cn) # targets - t[range(nb), tcls[i]] = cp - lcls += BCEcls(ps[:, 5:], t) # BCE - - # Append targets to text file - # with open('targets.txt', 'a') as file: - # [file.write('%11.5g ' * 4 % tuple(x) + '\n') for x in torch.cat((txy[i], twh[i]), 1)] - - lobj += BCEobj(pi[..., 4], tobj) # obj loss - - lbox *= h['giou'] - lobj *= h['obj'] - lcls *= h['cls'] - if red == 'sum': - bs = tobj.shape[0] # batch size - g = 3.0 # loss gain - lobj *= g / bs - if nt: - lcls *= g / nt / model.nc - lbox *= g / nt - - loss = lbox + lobj + lcls - return loss, torch.cat((lbox, lobj, lcls, loss)).detach() - - -def build_targets(p, targets, model): - # Build targets for compute_loss(), input targets(image,class,x,y,w,h) - nt = targets.shape[0] - tcls, tbox, indices, anch = [], [], [], [] - gain = torch.ones(6, device=targets.device) # normalized to gridspace gain - off = torch.tensor([[1, 0], [0, 1], [-1, 0], [0, -1]], device=targets.device).float() # overlap offsets - - style = None - multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) - for i, j in enumerate(model.yolo_layers): - anchors = model.module.module_list[j].anchor_vec if multi_gpu else model.module_list[j].anchor_vec - gain[2:] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain - na = anchors.shape[0] # number of anchors - at = torch.arange(na).view(na, 1).repeat(1, nt) # anchor tensor, same as .repeat_interleave(nt) - - # Match targets to anchors - a, t, offsets = [], targets * gain, 0 - if nt: - # r = t[None, :, 4:6] / anchors[:, None] # wh ratio - # j = torch.max(r, 1. / r).max(2)[0] < model.hyp['anchor_t'] # compare - j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n) = wh_iou(anchors(3,2), gwh(n,2)) - a, t = at[j], t.repeat(na, 1, 1)[j] # filter - - # overlaps - gxy = t[:, 2:4] # grid xy - z = torch.zeros_like(gxy) - if style == 'rect2': - g = 0.2 # offset - j, k = ((gxy % 1. < g) & (gxy > 1.)).T - a, t = torch.cat((a, a[j], a[k]), 0), torch.cat((t, t[j], t[k]), 0) - offsets = torch.cat((z, z[j] + off[0], z[k] + off[1]), 0) * g - - elif style == 'rect4': - g = 0.5 # offset - j, k = ((gxy % 1. < g) & (gxy > 1.)).T - l, m = ((gxy % 1. > (1 - g)) & (gxy < (gain[[2, 3]] - 1.))).T - a, t = torch.cat((a, a[j], a[k], a[l], a[m]), 0), torch.cat((t, t[j], t[k], t[l], t[m]), 0) - offsets = torch.cat((z, z[j] + off[0], z[k] + off[1], z[l] + off[2], z[m] + off[3]), 0) * g - - # Define - b, c = t[:, :2].long().T # image, class - gxy = t[:, 2:4] # grid xy - gwh = t[:, 4:6] # grid wh - gij = (gxy - offsets).long() - gi, gj = gij.T # grid xy indices - - # Append - indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1))) # image, anchor, grid indices - tbox.append(torch.cat((gxy - gij, gwh), 1)) # box - anch.append(anchors[a]) # anchors - tcls.append(c) # class - if c.shape[0]: # if any targets - assert c.max() < model.nc, 'Model accepts %g classes labeled from 0-%g, however you labelled a class %g. ' \ - 'See https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' % ( - model.nc, model.nc - 1, c.max()) - - return tcls, tbox, indices, anch - - -def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, multi_label=True, classes=None, agnostic=False): - """ - Performs Non-Maximum Suppression on inference results - Returns detections with shape: - nx6 (x1, y1, x2, y2, conf, cls) - """ - - # Settings - merge = True # merge for best mAP - min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height - time_limit = 10.0 # seconds to quit after - - t = time.time() - nc = prediction[0].shape[1] - 5 # number of classes - multi_label &= nc > 1 # multiple labels per box - output = [None] * prediction.shape[0] - for xi, x in enumerate(prediction): # image index, image inference - # Apply constraints - x = x[x[:, 4] > conf_thres] # confidence - x = x[((x[:, 2:4] > min_wh) & (x[:, 2:4] < max_wh)).all(1)] # width-height - - # If none remain process next image - if not x.shape[0]: - continue - - # Compute conf - x[..., 5:] *= x[..., 4:5] # conf = obj_conf * cls_conf - - # Box (center x, center y, width, height) to (x1, y1, x2, y2) - box = xywh2xyxy(x[:, :4]) - - # Detections matrix nx6 (xyxy, conf, cls) - if multi_label: - i, j = (x[:, 5:] > conf_thres).nonzero().t() - x = torch.cat((box[i], x[i, j + 5].unsqueeze(1), j.float().unsqueeze(1)), 1) - else: # best class only - conf, j = x[:, 5:].max(1) - x = torch.cat((box, conf.unsqueeze(1), j.float().unsqueeze(1)), 1)[conf > conf_thres] - - # Filter by class - if classes: - x = x[(j.view(-1, 1) == torch.tensor(classes, device=j.device)).any(1)] - - # Apply finite constraint - # if not torch.isfinite(x).all(): - # x = x[torch.isfinite(x).all(1)] - - # If none remain process next image - n = x.shape[0] # number of boxes - if not n: - continue - - # Sort by confidence - # x = x[x[:, 4].argsort(descending=True)] - - # Batched NMS - c = x[:, 5] * 0 if agnostic else x[:, 5] # classes - boxes, scores = x[:, :4].clone() + c.view(-1, 1) * max_wh, x[:, 4] # boxes (offset by class), scores - i = torchvision.ops.boxes.nms(boxes, scores, iou_thres) - if merge and (1 < n < 3E3): # Merge NMS (boxes merged using weighted mean) - try: # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) - iou = box_iou(boxes[i], boxes) > iou_thres # iou matrix - weights = iou * scores[None] # box weights - x[i, :4] = torch.mm(weights, x[:, :4]).float() / weights.sum(1, keepdim=True) # merged boxes - # i = i[iou.sum(1) > 1] # require redundancy - except: # possible CUDA error https://github.com/ultralytics/yolov3/issues/1139 - print(x, i, x.shape, i.shape) - pass - - output[xi] = x[i] - if (time.time() - t) > time_limit: - break # time limit exceeded - - return output - - -def get_yolo_layers(model): - bool_vec = [x['type'] == 'yolo' for x in model.module_defs] - return [i for i, x in enumerate(bool_vec) if x] # [82, 94, 106] for yolov3 - - -def print_model_biases(model): - # prints the bias neurons preceding each yolo layer - print('\nModel Bias Summary: %8s%18s%18s%18s' % ('layer', 'regression', 'objectness', 'classification')) - try: - multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) - for l in model.yolo_layers: # print pretrained biases - if multi_gpu: - na = model.module.module_list[l].na # number of anchors - b = model.module.module_list[l - 1][0].bias.view(na, -1) # bias 3x85 - else: - na = model.module_list[l].na - b = model.module_list[l - 1][0].bias.view(na, -1) # bias 3x85 - print(' ' * 20 + '%8g %18s%18s%18s' % (l, '%5.2f+/-%-5.2f' % (b[:, :4].mean(), b[:, :4].std()), - '%5.2f+/-%-5.2f' % (b[:, 4].mean(), b[:, 4].std()), - '%5.2f+/-%-5.2f' % (b[:, 5:].mean(), b[:, 5:].std()))) - except: - pass - - -def strip_optimizer(f='weights/best.pt'): # from utils.utils import *; strip_optimizer() - # Strip optimizer from *.pt files for lighter files (reduced by 2/3 size) - x = torch.load(f, map_location=torch.device('cpu')) - x['optimizer'] = None - print('Optimizer stripped from %s' % f) - torch.save(x, f) - - -def create_backbone(f='weights/best.pt'): # from utils.utils import *; create_backbone() - # create a backbone from a *.pt file - x = torch.load(f, map_location=torch.device('cpu')) - x['optimizer'] = None - x['training_results'] = None - x['epoch'] = -1 - for p in x['model'].parameters(): - p.requires_grad = True - s = 'weights/backbone.pt' - print('%s saved as %s' % (f, s)) - torch.save(x, s) - - -def coco_class_count(path='../coco/labels/train2014/'): - # Histogram of occurrences per class - nc = 80 # number classes - x = np.zeros(nc, dtype='int32') - files = sorted(glob.glob('%s/*.*' % path)) - for i, file in enumerate(files): - labels = np.loadtxt(file, dtype=np.float32).reshape(-1, 5) - x += np.bincount(labels[:, 0].astype('int32'), minlength=nc) - print(i, len(files)) - - -def coco_only_people(path='../coco/labels/train2017/'): # from utils.utils import *; coco_only_people() - # Find images with only people - files = sorted(glob.glob('%s/*.*' % path)) - for i, file in enumerate(files): - labels = np.loadtxt(file, dtype=np.float32).reshape(-1, 5) - if all(labels[:, 0] == 0): - print(labels.shape[0], file) - - -def crop_images_random(path='../images/', scale=0.50): # from utils.utils import *; crop_images_random() - # crops images into random squares up to scale fraction - # WARNING: overwrites images! - for file in tqdm(sorted(glob.glob('%s/*.*' % path))): - img = cv2.imread(file) # BGR - if img is not None: - h, w = img.shape[:2] - - # create random mask - a = 30 # minimum size (pixels) - mask_h = random.randint(a, int(max(a, h * scale))) # mask height - mask_w = mask_h # mask width - - # box - xmin = max(0, random.randint(0, w) - mask_w // 2) - ymin = max(0, random.randint(0, h) - mask_h // 2) - xmax = min(w, xmin + mask_w) - ymax = min(h, ymin + mask_h) - - # apply random color mask - cv2.imwrite(file, img[ymin:ymax, xmin:xmax]) - - -def coco_single_class_labels(path='../coco/labels/train2014/', label_class=43): - # Makes single-class coco datasets. from utils.utils import *; coco_single_class_labels() - if os.path.exists('new/'): - shutil.rmtree('new/') # delete output folder - os.makedirs('new/') # make new output folder - os.makedirs('new/labels/') - os.makedirs('new/images/') - for file in tqdm(sorted(glob.glob('%s/*.*' % path))): - with open(file, 'r') as f: - labels = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) - i = labels[:, 0] == label_class - if any(i): - img_file = file.replace('labels', 'images').replace('txt', 'jpg') - labels[:, 0] = 0 # reset class to 0 - with open('new/images.txt', 'a') as f: # add image to dataset list - f.write(img_file + '\n') - with open('new/labels/' + Path(file).name, 'a') as f: # write label - for l in labels[i]: - f.write('%g %.6f %.6f %.6f %.6f\n' % tuple(l)) - shutil.copyfile(src=img_file, dst='new/images/' + Path(file).name.replace('txt', 'jpg')) # copy images - - -def kmean_anchors(path='./data/coco64.txt', n=9, img_size=(640, 640), thr=0.20, gen=1000): - # Creates kmeans anchors for use in *.cfg files: from utils.utils import *; _ = kmean_anchors() - # n: number of anchors - # img_size: (min, max) image size used for multi-scale training (can be same values) - # thr: IoU threshold hyperparameter used for training (0.0 - 1.0) - # gen: generations to evolve anchors using genetic algorithm - from utils.datasets import LoadImagesAndLabels - - def print_results(k): - k = k[np.argsort(k.prod(1))] # sort small to large - iou = wh_iou(wh, torch.Tensor(k)) - max_iou = iou.max(1)[0] - bpr, aat = (max_iou > thr).float().mean(), (iou > thr).float().mean() * n # best possible recall, anch > thr - print('%.2f iou_thr: %.3f best possible recall, %.2f anchors > thr' % (thr, bpr, aat)) - print('n=%g, img_size=%s, IoU_all=%.3f/%.3f-mean/best, IoU>thr=%.3f-mean: ' % - (n, img_size, iou.mean(), max_iou.mean(), iou[iou > thr].mean()), end='') - for i, x in enumerate(k): - print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg - return k - - def fitness(k): # mutation fitness - iou = wh_iou(wh, torch.Tensor(k)) # iou - max_iou = iou.max(1)[0] - return (max_iou * (max_iou > thr).float()).mean() # product - - # Get label wh - wh = [] - dataset = LoadImagesAndLabels(path, augment=True, rect=True) - nr = 1 if img_size[0] == img_size[1] else 10 # number augmentation repetitions - for s, l in zip(dataset.shapes, dataset.labels): - wh.append(l[:, 3:5] * (s / s.max())) # image normalized to letterbox normalized wh - wh = np.concatenate(wh, 0).repeat(nr, axis=0) # augment 10x - wh *= np.random.uniform(img_size[0], img_size[1], size=(wh.shape[0], 1)) # normalized to pixels (multi-scale) - wh = wh[(wh > 2.0).all(1)] # remove below threshold boxes (< 2 pixels wh) - - # Kmeans calculation - from scipy.cluster.vq import kmeans - print('Running kmeans for %g anchors on %g points...' % (n, len(wh))) - s = wh.std(0) # sigmas for whitening - k, dist = kmeans(wh / s, n, iter=30) # points, mean distance - k *= s - wh = torch.Tensor(wh) - k = print_results(k) - - # # Plot - # k, d = [None] * 20, [None] * 20 - # for i in tqdm(range(1, 21)): - # k[i-1], d[i-1] = kmeans(wh / s, i) # points, mean distance - # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) - # ax = ax.ravel() - # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.') - # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # plot wh - # ax[0].hist(wh[wh[:, 0]<100, 0],400) - # ax[1].hist(wh[wh[:, 1]<100, 1],400) - # fig.tight_layout() - # fig.savefig('wh.png', dpi=200) - - # Evolve - npr = np.random - f, sh, mp, s = fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma - for _ in tqdm(range(gen), desc='Evolving anchors'): - v = np.ones(sh) - while (v == 1).all(): # mutate until a change occurs (prevent duplicates) - v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) - kg = (k.copy() * v).clip(min=2.0) - fg = fitness(kg) - if fg > f: - f, k = fg, kg.copy() - print_results(k) - k = print_results(k) - - return k - - -def print_mutation(hyp, results, bucket=''): - # Print mutation results to evolve.txt (for use with train.py --evolve) - a = '%10s' * len(hyp) % tuple(hyp.keys()) # hyperparam keys - b = '%10.3g' * len(hyp) % tuple(hyp.values()) # hyperparam values - c = '%10.4g' * len(results) % results # results (P, R, mAP, F1, test_loss) - print('\n%s\n%s\nEvolved fitness: %s\n' % (a, b, c)) - - if bucket: - os.system('gsutil cp gs://%s/evolve.txt .' % bucket) # download evolve.txt - - with open('evolve.txt', 'a') as f: # append result - f.write(c + b + '\n') - x = np.unique(np.loadtxt('evolve.txt', ndmin=2), axis=0) # load unique rows - np.savetxt('evolve.txt', x[np.argsort(-fitness(x))], '%10.3g') # save sort by fitness - - if bucket: - os.system('gsutil cp evolve.txt gs://%s' % bucket) # upload evolve.txt - - -def apply_classifier(x, model, img, im0): - # applies a second stage classifier to yolo outputs - im0 = [im0] if isinstance(im0, np.ndarray) else im0 - for i, d in enumerate(x): # per image - if d is not None and len(d): - d = d.clone() - - # Reshape and pad cutouts - b = xyxy2xywh(d[:, :4]) # boxes - b[:, 2:] = b[:, 2:].max(1)[0].unsqueeze(1) # rectangle to square - b[:, 2:] = b[:, 2:] * 1.3 + 30 # pad - d[:, :4] = xywh2xyxy(b).long() - - # Rescale boxes from img_size to im0 size - scale_coords(img.shape[2:], d[:, :4], im0[i].shape) - - # Classes - pred_cls1 = d[:, 5].long() - ims = [] - for j, a in enumerate(d): # per item - cutout = im0[i][int(a[1]):int(a[3]), int(a[0]):int(a[2])] - im = cv2.resize(cutout, (224, 224)) # BGR - # cv2.imwrite('test%i.jpg' % j, cutout) - - im = im[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 - im = np.ascontiguousarray(im, dtype=np.float32) # uint8 to float32 - im /= 255.0 # 0 - 255 to 0.0 - 1.0 - ims.append(im) - - pred_cls2 = model(torch.Tensor(ims).to(d.device)).argmax(1) # classifier prediction - x[i] = x[i][pred_cls1 == pred_cls2] # retain matching class detections - - return x - - -def fitness(x): - # Returns fitness (for use with results.txt or evolve.txt) - w = [0.0, 0.01, 0.99, 0.00] # weights for [P, R, mAP, F1]@0.5 or [P, R, mAP@0.5, mAP@0.5:0.95] - return (x[:, :4] * w).sum(1) - - -def output_to_target(output, width, height): - """ - Convert a YOLO model output to target format - [batch_id, class_id, x, y, w, h, conf] - """ - if isinstance(output, torch.Tensor): - output = output.cpu().numpy() - - targets = [] - for i, o in enumerate(output): - if o is not None: - for pred in o: - box = pred[:4] - w = (box[2] - box[0]) / width - h = (box[3] - box[1]) / height - x = box[0] / width + w / 2 - y = box[1] / height + h / 2 - conf = pred[4] - cls = int(pred[5]) - - targets.append([i, cls, x, y, w, h, conf]) - - return np.array(targets) - - -# Plotting functions --------------------------------------------------------------------------------------------------- -def plot_one_box(x, img, color=None, label=None, line_thickness=None): - # Plots one bounding box on image img - tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line/font thickness - color = color or [random.randint(0, 255) for _ in range(3)] - c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) - cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA) - if label: - tf = max(tl - 1, 1) # font thickness - t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] - c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 - cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) # filled - cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA) - - -def plot_wh_methods(): # from utils.utils import *; plot_wh_methods() - # Compares the two methods for width-height anchor multiplication - # https://github.com/ultralytics/yolov3/issues/168 - x = np.arange(-4.0, 4.0, .1) - ya = np.exp(x) - yb = torch.sigmoid(torch.from_numpy(x)).numpy() * 2 - - fig = plt.figure(figsize=(6, 3), dpi=150) - plt.plot(x, ya, '.-', label='yolo method') - plt.plot(x, yb ** 2, '.-', label='^2 power method') - plt.plot(x, yb ** 2.5, '.-', label='^2.5 power method') - plt.xlim(left=-4, right=4) - plt.ylim(bottom=0, top=6) - plt.xlabel('input') - plt.ylabel('output') - plt.legend() - fig.tight_layout() - fig.savefig('comparison.png', dpi=200) - - -def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max_size=640, max_subplots=16): - tl = 3 # line thickness - tf = max(tl - 1, 1) # font thickness - if os.path.isfile(fname): # do not overwrite - return None - - if isinstance(images, torch.Tensor): - images = images.cpu().numpy() - - if isinstance(targets, torch.Tensor): - targets = targets.cpu().numpy() - - # un-normalise - if np.max(images[0]) <= 1: - images *= 255 - - bs, _, h, w = images.shape # batch size, _, height, width - bs = min(bs, max_subplots) # limit plot images - ns = np.ceil(bs ** 0.5) # number of subplots (square) - - # Check if we should resize - scale_factor = max_size / max(h, w) - if scale_factor < 1: - h = math.ceil(scale_factor * h) - w = math.ceil(scale_factor * w) - - # Empty array for output - mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) - - # Fix class - colour map - prop_cycle = plt.rcParams['axes.prop_cycle'] - # https://stackoverflow.com/questions/51350872/python-from-color-name-to-rgb - hex2rgb = lambda h: tuple(int(h[1 + i:1 + i + 2], 16) for i in (0, 2, 4)) - color_lut = [hex2rgb(h) for h in prop_cycle.by_key()['color']] - - for i, img in enumerate(images): - if i == max_subplots: # if last batch has fewer images than we expect - break - - block_x = int(w * (i // ns)) - block_y = int(h * (i % ns)) - - img = img.transpose(1, 2, 0) - if scale_factor < 1: - img = cv2.resize(img, (w, h)) - - mosaic[block_y:block_y + h, block_x:block_x + w, :] = img - if len(targets) > 0: - image_targets = targets[targets[:, 0] == i] - boxes = xywh2xyxy(image_targets[:, 2:6]).T - classes = image_targets[:, 1].astype('int') - gt = image_targets.shape[1] == 6 # ground truth if no conf column - conf = None if gt else image_targets[:, 6] # check for confidence presence (gt vs pred) - - boxes[[0, 2]] *= w - boxes[[0, 2]] += block_x - boxes[[1, 3]] *= h - boxes[[1, 3]] += block_y - for j, box in enumerate(boxes.T): - cls = int(classes[j]) - color = color_lut[cls % len(color_lut)] - cls = names[cls] if names else cls - if gt or conf[j] > 0.3: # 0.3 conf thresh - label = '%s' % cls if gt else '%s %.1f' % (cls, conf[j]) - plot_one_box(box, mosaic, label=label, color=color, line_thickness=tl) - - # Draw image filename labels - if paths is not None: - label = os.path.basename(paths[i])[:40] # trim to 40 char - t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] - cv2.putText(mosaic, label, (block_x + 5, block_y + t_size[1] + 5), 0, tl / 3, [220, 220, 220], thickness=tf, - lineType=cv2.LINE_AA) - - # Image border - cv2.rectangle(mosaic, (block_x, block_y), (block_x + w, block_y + h), (255, 255, 255), thickness=3) - - if fname is not None: - mosaic = cv2.resize(mosaic, (int(ns * w * 0.5), int(ns * h * 0.5)), interpolation=cv2.INTER_AREA) - cv2.imwrite(fname, cv2.cvtColor(mosaic, cv2.COLOR_BGR2RGB)) - - return mosaic - - -def plot_lr_scheduler(optimizer, scheduler, epochs=300): - # Plot LR simulating training for full epochs - optimizer, scheduler = copy(optimizer), copy(scheduler) # do not modify originals - y = [] - for _ in range(epochs): - scheduler.step() - y.append(optimizer.param_groups[0]['lr']) - plt.plot(y, '.-', label='LR') - plt.xlabel('epoch') - plt.ylabel('LR') - plt.tight_layout() - plt.savefig('LR.png', dpi=200) - - -def plot_test_txt(): # from utils.utils import *; plot_test() - # Plot test.txt histograms - x = np.loadtxt('test.txt', dtype=np.float32) - box = xyxy2xywh(x[:, :4]) - cx, cy = box[:, 0], box[:, 1] - - fig, ax = plt.subplots(1, 1, figsize=(6, 6), tight_layout=True) - ax.hist2d(cx, cy, bins=600, cmax=10, cmin=0) - ax.set_aspect('equal') - plt.savefig('hist2d.png', dpi=300) - - fig, ax = plt.subplots(1, 2, figsize=(12, 6), tight_layout=True) - ax[0].hist(cx, bins=600) - ax[1].hist(cy, bins=600) - plt.savefig('hist1d.png', dpi=200) - - -def plot_targets_txt(): # from utils.utils import *; plot_targets_txt() - # Plot targets.txt histograms - x = np.loadtxt('targets.txt', dtype=np.float32).T - s = ['x targets', 'y targets', 'width targets', 'height targets'] - fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) - ax = ax.ravel() - for i in range(4): - ax[i].hist(x[i], bins=100, label='%.3g +/- %.3g' % (x[i].mean(), x[i].std())) - ax[i].legend() - ax[i].set_title(s[i]) - plt.savefig('targets.jpg', dpi=200) - - -def plot_labels(labels): - # plot dataset labels - c, b = labels[:, 0], labels[:, 1:].transpose() # classees, boxes - - def hist2d(x, y, n=100): - xedges, yedges = np.linspace(x.min(), x.max(), n), np.linspace(y.min(), y.max(), n) - hist, xedges, yedges = np.histogram2d(x, y, (xedges, yedges)) - xidx = np.clip(np.digitize(x, xedges) - 1, 0, hist.shape[0] - 1) - yidx = np.clip(np.digitize(y, yedges) - 1, 0, hist.shape[1] - 1) - return hist[xidx, yidx] - - fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) - ax = ax.ravel() - ax[0].hist(c, bins=int(c.max() + 1)) - ax[0].set_xlabel('classes') - ax[1].scatter(b[0], b[1], c=hist2d(b[0], b[1], 90), cmap='jet') - ax[1].set_xlabel('x') - ax[1].set_ylabel('y') - ax[2].scatter(b[2], b[3], c=hist2d(b[2], b[3], 90), cmap='jet') - ax[2].set_xlabel('width') - ax[2].set_ylabel('height') - plt.savefig('labels.png', dpi=200) - - -def plot_evolution_results(hyp): # from utils.utils import *; plot_evolution_results(hyp) - # Plot hyperparameter evolution results in evolve.txt - x = np.loadtxt('evolve.txt', ndmin=2) - f = fitness(x) - # weights = (f - f.min()) ** 2 # for weighted results - fig = plt.figure(figsize=(12, 10), tight_layout=True) - matplotlib.rc('font', **{'size': 8}) - for i, (k, v) in enumerate(hyp.items()): - y = x[:, i + 7] - # mu = (y * weights).sum() / weights.sum() # best weighted result - mu = y[f.argmax()] # best single result - plt.subplot(4, 5, i + 1) - plt.plot(mu, f.max(), 'o', markersize=10) - plt.plot(y, f, '.') - plt.title('%s = %.3g' % (k, mu), fontdict={'size': 9}) # limit to 40 characters - print('%15s: %.3g' % (k, mu)) - plt.savefig('evolve.png', dpi=200) - - -def plot_results_overlay(start=0, stop=0): # from utils.utils import *; plot_results_overlay() - # Plot training results files 'results*.txt', overlaying train and val losses - s = ['train', 'train', 'train', 'Precision', 'mAP@0.5', 'val', 'val', 'val', 'Recall', 'F1'] # legends - t = ['GIoU', 'Objectness', 'Classification', 'P-R', 'mAP-F1'] # titles - for f in sorted(glob.glob('results*.txt') + glob.glob('../../Downloads/results*.txt')): - results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T - n = results.shape[1] # number of rows - x = range(start, min(stop, n) if stop else n) - fig, ax = plt.subplots(1, 5, figsize=(14, 3.5), tight_layout=True) - ax = ax.ravel() - for i in range(5): - for j in [i, i + 5]: - y = results[j, x] - if i in [0, 1, 2]: - y[y == 0] = np.nan # dont show zero loss values - ax[i].plot(x, y, marker='.', label=s[j]) - ax[i].set_title(t[i]) - ax[i].legend() - ax[i].set_ylabel(f) if i == 0 else None # add filename - fig.savefig(f.replace('.txt', '.png'), dpi=200) - - -def plot_results(start=0, stop=0, bucket='', id=()): # from utils.utils import *; plot_results() - # Plot training 'results*.txt' as seen in https://github.com/ultralytics/yolov3#training - fig, ax = plt.subplots(2, 5, figsize=(12, 6), tight_layout=True) - ax = ax.ravel() - s = ['GIoU', 'Objectness', 'Classification', 'Precision', 'Recall', - 'val GIoU', 'val Objectness', 'val Classification', 'mAP@0.5', 'F1'] - if bucket: - os.system('rm -rf storage.googleapis.com') - files = ['https://storage.googleapis.com/%s/results%g.txt' % (bucket, x) for x in id] - else: - files = glob.glob('results*.txt') + glob.glob('../../Downloads/results*.txt') - for f in sorted(files): - try: - results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T - n = results.shape[1] # number of rows - x = range(start, min(stop, n) if stop else n) - for i in range(10): - y = results[i, x] - if i in [0, 1, 2, 5, 6, 7]: - y[y == 0] = np.nan # dont show zero loss values - # y /= y[0] # normalize - ax[i].plot(x, y, marker='.', label=Path(f).stem, linewidth=2, markersize=8) - ax[i].set_title(s[i]) - # if i in [5, 6, 7]: # share train and val loss y axes - # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) - except: - print('Warning: Plotting error for %s, skipping file' % f) - - ax[1].legend() - fig.savefig('results.png', dpi=200) diff --git a/weights/download_weights.sh b/weights/download_weights.sh new file mode 100755 index 0000000000..e3a6b38839 --- /dev/null +++ b/weights/download_weights.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# Download latest models from https://github.com/ultralytics/yolov3/releases + +python - < Date: Thu, 26 Nov 2020 22:22:03 +0100 Subject: [PATCH 0833/1185] Ignore W&B logging dir wandb/ (#1571) --- .gitignore | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 5a95798f0f..db4297e9a2 100755 --- a/.gitignore +++ b/.gitignore @@ -26,8 +26,8 @@ storage.googleapis.com runs/* data/* -!data/samples/zidane.jpg -!data/samples/bus.jpg +!data/images/zidane.jpg +!data/images/bus.jpg !data/coco.names !data/coco_paper.names !data/coco.data @@ -50,6 +50,7 @@ gcp_test*.sh *.pt *.onnx *.mlmodel +*.torchscript darknet53.conv.74 yolov3-tiny.conv.15 @@ -78,9 +79,11 @@ sdist/ var/ wheels/ *.egg-info/ +wandb/ .installed.cfg *.egg + # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. @@ -139,9 +142,9 @@ celerybeat-schedule .env # virtualenv -.venv -venv/ -ENV/ +.venv* +venv*/ +ENV*/ # Spyder project settings .spyderproject From f78f991a740e3737ad3add65f11f68d640b76e49 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Nov 2020 01:27:25 +0100 Subject: [PATCH 0834/1185] FROM nvcr.io/nvidia/pytorch:20.11-py3 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e514893da6..b2a2d14dca 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch -FROM nvcr.io/nvidia/pytorch:20.10-py3 +FROM nvcr.io/nvidia/pytorch:20.11-py3 # Install dependencies RUN pip install --upgrade pip From 152f50e8f9c9db446427ebc46865e9d04dc9d11f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Nov 2020 01:30:37 +0100 Subject: [PATCH 0835/1185] Remove ignore for git files (#1099) --- .dockerignore | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.dockerignore b/.dockerignore index a0d80d0951..666f331fed 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,5 @@ # Repo-specific DockerIgnore ------------------------------------------------------------------------------------------- -# .git +#.git .cache .idea runs @@ -8,8 +8,6 @@ coco storage.googleapis.com data/samples/* -!data/samples/zidane.jpg -!data/samples/bus.jpg **/results*.txt *.jpg @@ -20,8 +18,6 @@ data/samples/* **/*.onnx **/*.mlmodel **/*.torchscript -**/darknet53.conv.74 -**/yolov3-tiny.conv.15 # Below Copied From .gitignore ----------------------------------------------------------------------------------------- @@ -114,9 +110,9 @@ celerybeat-schedule .env # virtualenv -.venv -venv/ -ENV/ +.venv* +venv*/ +ENV*/ # Spyder project settings .spyderproject From f28f8622450142c4e79b24d4d0691aa6a76bfc57 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 27 Nov 2020 01:32:55 +0100 Subject: [PATCH 0836/1185] Ignore W&B logging dir wandb/ (#1571) --- .dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.dockerignore b/.dockerignore index 666f331fed..3c6b6ab02e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -49,6 +49,7 @@ sdist/ var/ wheels/ *.egg-info/ +wandb/ .installed.cfg *.egg From bc5c898c938875070c3493054c1b826b322ab024 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 28 Nov 2020 12:25:57 +0100 Subject: [PATCH 0837/1185] Update labels_to_image_weights() (#1576) --- utils/general.py | 15 +++++---------- utils/plots.py | 1 + 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/utils/general.py b/utils/general.py index ca6a9f6b10..fa47289e5e 100755 --- a/utils/general.py +++ b/utils/general.py @@ -2,7 +2,6 @@ import glob import logging -import math import os import platform import random @@ -12,7 +11,7 @@ from pathlib import Path import cv2 -import matplotlib +import math import numpy as np import torch import torchvision @@ -22,13 +21,10 @@ from utils.metrics import fitness from utils.torch_utils import init_torch_seeds -# Set printoptions +# Settings torch.set_printoptions(linewidth=320, precision=5, profile='long') np.set_printoptions(linewidth=320, formatter={'float_kind': '{:11.5g}'.format}) # format short g, %precision=5 -matplotlib.rc('font', **{'size': 11}) - -# Prevent OpenCV from multithreading (to use PyTorch DataLoader) -cv2.setNumThreads(0) +cv2.setNumThreads(0) # prevent OpenCV from multithreading (incompatible with PyTorch DataLoader) def set_logging(rank=-1): @@ -121,9 +117,8 @@ def labels_to_class_weights(labels, nc=80): def labels_to_image_weights(labels, nc=80, class_weights=np.ones(80)): - # Produces image weights based on class mAPs - n = len(labels) - class_counts = np.array([np.bincount(labels[i][:, 0].astype(np.int), minlength=nc) for i in range(n)]) + # Produces image weights based on class_weights and image contents + class_counts = np.array([np.bincount(x[:, 0].astype(np.int), minlength=nc) for x in labels]) image_weights = (class_weights.reshape(1, nc) * class_counts).sum(1) # index = random.choices(range(n), weights=image_weights, k=1) # weight image sample return image_weights diff --git a/utils/plots.py b/utils/plots.py index 6b2d7a38bf..9febcae550 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -20,6 +20,7 @@ from utils.metrics import fitness # Settings +matplotlib.rc('font', **{'size': 11}) matplotlib.use('Agg') # for writing to files only From fed9451454835b5ec3cd557ce22664e5e00788ea Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 29 Nov 2020 12:01:42 +0100 Subject: [PATCH 0838/1185] f.read().strip() (#1577) --- utils/datasets.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/datasets.py b/utils/datasets.py index 7203d96299..4b87004523 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -261,7 +261,7 @@ def __init__(self, sources='streams.txt', img_size=640): if os.path.isfile(sources): with open(sources, 'r') as f: - sources = [x.strip() for x in f.read().splitlines() if len(x.strip())] + sources = [x.strip() for x in f.read().strip().splitlines() if len(x.strip())] else: sources = [sources] @@ -353,7 +353,7 @@ def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, r f += glob.glob(str(p / '**' / '*.*'), recursive=True) elif p.is_file(): # file with open(p, 'r') as t: - t = t.read().splitlines() + t = t.read().strip().splitlines() parent = str(p.parent) + os.sep f += [x.replace('./', parent) if x.startswith('./') else x for x in t] # local to global path else: @@ -450,7 +450,7 @@ def cache_labels(self, path=Path('./labels.cache')): if os.path.isfile(lb_file): nf += 1 # label found with open(lb_file, 'r') as f: - l = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) # labels + l = np.array([x.split() for x in f.read().strip().splitlines()], dtype=np.float32) # labels if len(l): assert l.shape[1] == 5, 'labels require 5 columns each' assert (l >= 0).all(), 'negative labels' @@ -897,7 +897,7 @@ def extract_boxes(path='../coco128/'): # from utils.datasets import *; extract_ lb_file = Path(img2label_paths([str(im_file)])[0]) if Path(lb_file).exists(): with open(lb_file, 'r') as f: - lb = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) # labels + lb = np.array([x.split() for x in f.read().strip().splitlines()], dtype=np.float32) # labels for j, x in enumerate(lb): c = int(x[0]) # class From 430890ead83603a12c51622b633d37a5448d0e8a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 29 Nov 2020 14:21:32 +0100 Subject: [PATCH 0839/1185] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e8e05e11c3..05da4a2a07 100755 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ ![CI CPU testing](https://github.com/ultralytics/yolov3/workflows/CI%20CPU%20testing/badge.svg) BRANCH NOTICE: The [ultralytics/yolov3](https://github.com/ultralytics/yolov3) repository is now divided into two branches: -* [Master branch](https://github.com/ultralytics/yolov3/tree/master): Forward-compatible with all [YOLOv5](https://github.com/ultralytics/yolov5) models and methods (recommended). +* [Master branch](https://github.com/ultralytics/yolov3/tree/master): Forward-compatible with all [YOLOv5](https://github.com/ultralytics/yolov5) models and methods (**recommended**). ```bash $ git clone https://github.com/ultralytics/yolov3 # master branch (default) ``` -* [Archive branch](https://github.com/ultralytics/yolov3/tree/archive): Backwards-compatible with original [darknet](https://pjreddie.com/darknet/) *.cfg models (not recommended). +* [Archive branch](https://github.com/ultralytics/yolov3/tree/archive): Backwards-compatible with original [darknet](https://pjreddie.com/darknet/) *.cfg models (⚠️ no longer maintained). ```bash $ git clone -b archive https://github.com/ultralytics/yolov3 # archive branch ``` From e6d5408f5a1d4efcad9845f268be65d06b1b71be Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 29 Nov 2020 17:49:19 +0100 Subject: [PATCH 0840/1185] FROM nvcr.io/nvidia/pytorch:20.10-py3 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b2a2d14dca..e514893da6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch -FROM nvcr.io/nvidia/pytorch:20.11-py3 +FROM nvcr.io/nvidia/pytorch:20.10-py3 # Install dependencies RUN pip install --upgrade pip From 4f890d13ee1b23a79c8f58922b68a2c4856745a3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 30 Nov 2020 16:47:28 +0100 Subject: [PATCH 0841/1185] Daemon thread plots (#1578) --- test.py | 23 ++++++++++++----------- train.py | 10 +++++----- utils/plots.py | 11 ++++++++--- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/test.py b/test.py index d62afd7dec..4120057a4a 100644 --- a/test.py +++ b/test.py @@ -3,6 +3,7 @@ import json import os from pathlib import Path +from threading import Thread import numpy as np import torch @@ -206,10 +207,10 @@ def test(data, # Plot images if plots and batch_i < 3: - f = save_dir / f'test_batch{batch_i}_labels.jpg' # filename - plot_images(img, targets, paths, f, names) # labels - f = save_dir / f'test_batch{batch_i}_pred.jpg' - plot_images(img, output_to_target(output), paths, f, names) # predictions + f = save_dir / f'test_batch{batch_i}_labels.jpg' # labels + Thread(target=plot_images, args=(img, targets, paths, f, names), daemon=True).start() + f = save_dir / f'test_batch{batch_i}_pred.jpg' # predictions + Thread(target=plot_images, args=(img, output_to_target(output), paths, f, names), daemon=True).start() # Compute statistics stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy @@ -221,13 +222,6 @@ def test(data, else: nt = torch.zeros(1) - # Plots - if plots: - confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) - if wandb and wandb.run: - wandb.log({"Images": wandb_images}) - wandb.log({"Validation": [wandb.Image(str(f), caption=f.name) for f in sorted(save_dir.glob('test*.jpg'))]}) - # Print results pf = '%20s' + '%12.3g' * 6 # print format print(pf % ('all', seen, nt.sum(), mp, mr, map50, map)) @@ -242,6 +236,13 @@ def test(data, if not training: print('Speed: %.1f/%.1f/%.1f ms inference/NMS/total per %gx%g image at batch-size %g' % t) + # Plots + if plots: + confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) + if wandb and wandb.run: + wandb.log({"Images": wandb_images}) + wandb.log({"Validation": [wandb.Image(str(f), caption=f.name) for f in sorted(save_dir.glob('test*.jpg'))]}) + # Save JSON if save_json and len(jdict): w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights diff --git a/train.py b/train.py index 3471496b92..f0f778db97 100644 --- a/train.py +++ b/train.py @@ -1,12 +1,13 @@ import argparse import logging -import math import os import random import time from pathlib import Path +from threading import Thread from warnings import warn +import math import numpy as np import torch.distributed as dist import torch.nn as nn @@ -134,6 +135,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): project='YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem, name=save_dir.stem, id=ckpt.get('wandb_id') if 'ckpt' in locals() else None) + loggers = {'wandb': wandb} # loggers dict # Resume start_epoch, best_fitness = 0, 0.0 @@ -201,11 +203,9 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): # cf = torch.bincount(c.long(), minlength=nc) + 1. # frequency # model._initialize_biases(cf.to(device)) if plots: - plot_labels(labels, save_dir=save_dir) + Thread(target=plot_labels, args=(labels, save_dir, loggers), daemon=True).start() if tb_writer: tb_writer.add_histogram('classes', c, 0) - if wandb: - wandb.log({"Labels": [wandb.Image(str(x), caption=x.name) for x in save_dir.glob('*labels*.png')]}) # Anchors if not opt.noautoanchor: @@ -311,7 +311,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): # Plot if plots and ni < 3: f = save_dir / f'train_batch{ni}.jpg' # filename - plot_images(images=imgs, targets=targets, paths=paths, fname=f) + Thread(target=plot_images, args=(imgs, targets, paths, f), daemon=True).start() # if tb_writer: # tb_writer.add_image(f, result, dataformats='HWC', global_step=epoch) # tb_writer.add_graph(model, imgs) # add model to tensorboard diff --git a/utils/plots.py b/utils/plots.py index 9febcae550..8492b1a16c 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -250,7 +250,7 @@ def plot_study_txt(path='', x=None): # from utils.plots import *; plot_study_tx plt.savefig('test_study.png', dpi=300) -def plot_labels(labels, save_dir=''): +def plot_labels(labels, save_dir=Path(''), loggers=None): # plot dataset labels c, b = labels[:, 0], labels[:, 1:].transpose() # classes, boxes nc = int(c.max() + 1) # number of classes @@ -264,7 +264,7 @@ def plot_labels(labels, save_dir=''): sns.pairplot(x, corner=True, diag_kind='hist', kind='scatter', markers='o', plot_kws=dict(s=3, edgecolor=None, linewidth=1, alpha=0.02), diag_kws=dict(bins=50)) - plt.savefig(Path(save_dir) / 'labels_correlogram.png', dpi=200) + plt.savefig(save_dir / 'labels_correlogram.png', dpi=200) plt.close() except Exception as e: pass @@ -292,9 +292,14 @@ def plot_labels(labels, save_dir=''): for a in [0, 1, 2, 3]: for s in ['top', 'right', 'left', 'bottom']: ax[a].spines[s].set_visible(False) - plt.savefig(Path(save_dir) / 'labels.png', dpi=200) + plt.savefig(save_dir / 'labels.png', dpi=200) plt.close() + # loggers + for k, v in loggers.items() or {}: + if k == 'wandb' and v: + v.log({"Labels": [v.Image(str(x), caption=x.name) for x in save_dir.glob('*labels*.png')]}) + def plot_evolution(yaml_file='data/hyp.finetune.yaml'): # from utils.plots import *; plot_evolution() # Plot hyperparameter evolution results in evolve.txt From 5b46d4971992714bdb21da8b9fa29cd4eaa847b5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 1 Dec 2020 14:19:06 +0100 Subject: [PATCH 0842/1185] plot_images() scale bug fix (#1580) From https://github.com/ultralytics/yolov5/pull/1566 --- utils/plots.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/utils/plots.py b/utils/plots.py index 8492b1a16c..1bb61d67e1 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -141,9 +141,12 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max labels = image_targets.shape[1] == 6 # labels if no conf column conf = None if labels else image_targets[:, 6] # check for confidence presence (label vs pred) - if boxes.shape[1] and boxes.max() <= 1: # if normalized - boxes[[0, 2]] *= w # scale to pixels - boxes[[1, 3]] *= h + if boxes.shape[1]: + if boxes.max() <= 1: # if normalized + boxes[[0, 2]] *= w # scale to pixels + boxes[[1, 3]] *= h + elif scale_factor < 1: # absolute coords need scale if image scales + boxes *= scale_factor boxes[[0, 2]] += block_x boxes[[1, 3]] += block_y for j, box in enumerate(boxes.T): From 5ead90a9d6195491c2eab9f3dfbeaea7ac1f73a0 Mon Sep 17 00:00:00 2001 From: SergioSanchezMontesUAM <33067411+SergioSanchezMontesUAM@users.noreply.github.com> Date: Wed, 2 Dec 2020 13:01:45 +0100 Subject: [PATCH 0843/1185] Update .gitignore datasets dir (#1582) --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index db4297e9a2..91ce33fb93 100755 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,11 @@ pycocotools/* results*.txt gcp_test*.sh +# Datasets ------------------------------------------------------------------------------------------------------------- +coco/ +coco128/ +VOC/ + # MATLAB GitIgnore ----------------------------------------------------------------------------------------------------- *.m~ *.mat From eac1ba63d9b6c30ad667b57cba35a3556d6ee794 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 2 Dec 2020 14:05:29 +0100 Subject: [PATCH 0844/1185] Update matplotlib svg backend (#1583) --- utils/plots.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/plots.py b/utils/plots.py index 1bb61d67e1..c6aa48926d 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -21,7 +21,7 @@ # Settings matplotlib.rc('font', **{'size': 11}) -matplotlib.use('Agg') # for writing to files only +matplotlib.use('svg') # for writing to files only def color_list(): From 75431d89eeadba1adee27005c3c79de429cda6e9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 2 Dec 2020 15:53:23 +0100 Subject: [PATCH 0845/1185] Update matplotlib.use('Agg') tight (#1584) --- utils/autoanchor.py | 3 +-- utils/metrics.py | 6 ++---- utils/plots.py | 18 +++++++++--------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/utils/autoanchor.py b/utils/autoanchor.py index b678bbbd78..98fea9981f 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -124,13 +124,12 @@ def print_results(k): # k, d = [None] * 20, [None] * 20 # for i in tqdm(range(1, 21)): # k[i-1], d[i-1] = kmeans(wh / s, i) # points, mean distance - # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) + # fig, ax = plt.subplots(1, 2, figsize=(14, 7), tight_layout=True) # ax = ax.ravel() # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.') # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # plot wh # ax[0].hist(wh[wh[:, 0]<100, 0],400) # ax[1].hist(wh[wh[:, 1]<100, 1],400) - # fig.tight_layout() # fig.savefig('wh.png', dpi=200) # Evolve diff --git a/utils/metrics.py b/utils/metrics.py index 79f18cff3f..af32ddc5b1 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -163,7 +163,7 @@ def plot(self, save_dir='', names=()): array = self.matrix / (self.matrix.sum(0).reshape(1, self.nc + 1) + 1E-6) # normalize array[array < 0.005] = np.nan # don't annotate (would appear as 0.00) - fig = plt.figure(figsize=(12, 9)) + fig = plt.figure(figsize=(12, 9), tight_layout=True) sn.set(font_scale=1.0 if self.nc < 50 else 0.8) # for label size labels = (0 < len(names) < 99) and len(names) == self.nc # apply names to ticklabels sn.heatmap(array, annot=self.nc < 30, annot_kws={"size": 8}, cmap='Blues', fmt='.2f', square=True, @@ -171,7 +171,6 @@ def plot(self, save_dir='', names=()): yticklabels=names + ['background FP'] if labels else "auto").set_facecolor((1, 1, 1)) fig.axes[0].set_xlabel('True') fig.axes[0].set_ylabel('Predicted') - fig.tight_layout() fig.savefig(Path(save_dir) / 'confusion_matrix.png', dpi=250) except Exception as e: pass @@ -184,7 +183,7 @@ def print(self): # Plots ---------------------------------------------------------------------------------------------------------------- def plot_pr_curve(px, py, ap, save_dir='.', names=()): - fig, ax = plt.subplots(1, 1, figsize=(9, 6)) + fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True) py = np.stack(py, axis=1) if 0 < len(names) < 21: # show mAP in legend if < 10 classes @@ -199,5 +198,4 @@ def plot_pr_curve(px, py, ap, save_dir='.', names=()): ax.set_xlim(0, 1) ax.set_ylim(0, 1) plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left") - fig.tight_layout() fig.savefig(Path(save_dir) / 'precision_recall_curve.png', dpi=250) diff --git a/utils/plots.py b/utils/plots.py index c6aa48926d..12815ea28d 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -73,7 +73,7 @@ def plot_wh_methods(): # from utils.plots import *; plot_wh_methods() ya = np.exp(x) yb = torch.sigmoid(torch.from_numpy(x)).numpy() * 2 - fig = plt.figure(figsize=(6, 3), dpi=150) + fig = plt.figure(figsize=(6, 3), tight_layout=True) plt.plot(x, ya, '.-', label='YOLOv3') plt.plot(x, yb ** 2, '.-', label='YOLOv5 ^2') plt.plot(x, yb ** 1.6, '.-', label='YOLOv5 ^1.6') @@ -83,7 +83,6 @@ def plot_wh_methods(): # from utils.plots import *; plot_wh_methods() plt.ylabel('output') plt.grid() plt.legend() - fig.tight_layout() fig.savefig('comparison.png', dpi=200) @@ -145,7 +144,7 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max if boxes.max() <= 1: # if normalized boxes[[0, 2]] *= w # scale to pixels boxes[[1, 3]] *= h - elif scale_factor < 1: # absolute coords need scale if image scales + elif scale_factor < 1: # absolute coords need scale if image scales boxes *= scale_factor boxes[[0, 2]] += block_x boxes[[1, 3]] += block_y @@ -188,7 +187,6 @@ def plot_lr_scheduler(optimizer, scheduler, epochs=300, save_dir=''): plt.grid() plt.xlim(0, epochs) plt.ylim(0) - plt.tight_layout() plt.savefig(Path(save_dir) / 'LR.png', dpi=200) @@ -267,12 +265,13 @@ def plot_labels(labels, save_dir=Path(''), loggers=None): sns.pairplot(x, corner=True, diag_kind='hist', kind='scatter', markers='o', plot_kws=dict(s=3, edgecolor=None, linewidth=1, alpha=0.02), diag_kws=dict(bins=50)) - plt.savefig(save_dir / 'labels_correlogram.png', dpi=200) + plt.savefig(save_dir / 'labels_correlogram.jpg', dpi=200) plt.close() except Exception as e: pass # matplotlib labels + matplotlib.use('svg') # faster ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True)[1].ravel() ax[0].hist(c, bins=np.linspace(0, nc, nc + 1) - 0.5, rwidth=0.8) ax[0].set_xlabel('classes') @@ -295,13 +294,15 @@ def plot_labels(labels, save_dir=Path(''), loggers=None): for a in [0, 1, 2, 3]: for s in ['top', 'right', 'left', 'bottom']: ax[a].spines[s].set_visible(False) - plt.savefig(save_dir / 'labels.png', dpi=200) + + plt.savefig(save_dir / 'labels.jpg', dpi=200) + matplotlib.use('Agg') plt.close() # loggers for k, v in loggers.items() or {}: if k == 'wandb' and v: - v.log({"Labels": [v.Image(str(x), caption=x.name) for x in save_dir.glob('*labels*.png')]}) + v.log({"Labels": [v.Image(str(x), caption=x.name) for x in save_dir.glob('*labels*.jpg')]}) def plot_evolution(yaml_file='data/hyp.finetune.yaml'): # from utils.plots import *; plot_evolution() @@ -353,7 +354,7 @@ def plot_results_overlay(start=0, stop=0): # from utils.plots import *; plot_re def plot_results(start=0, stop=0, bucket='', id=(), labels=(), save_dir=''): # Plot training 'results*.txt'. from utils.plots import *; plot_results(save_dir='runs/train/exp') - fig, ax = plt.subplots(2, 5, figsize=(12, 6)) + fig, ax = plt.subplots(2, 5, figsize=(12, 6), tight_layout=True) ax = ax.ravel() s = ['Box', 'Objectness', 'Classification', 'Precision', 'Recall', 'val Box', 'val Objectness', 'val Classification', 'mAP@0.5', 'mAP@0.5:0.95'] @@ -383,6 +384,5 @@ def plot_results(start=0, stop=0, bucket='', id=(), labels=(), save_dir=''): except Exception as e: print('Warning: Plotting error for %s; %s' % (f, e)) - fig.tight_layout() ax[1].legend() fig.savefig(Path(save_dir) / 'results.png', dpi=200) From d1ad63206b84c4b82666b0a4977b5286eba26e95 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 4 Dec 2020 15:08:02 +0100 Subject: [PATCH 0846/1185] Add bias to Classify() (#1588) --- models/common.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/models/common.py b/models/common.py index f23faa1d24..90edaab23d 100644 --- a/models/common.py +++ b/models/common.py @@ -1,7 +1,6 @@ # This file contains modules common to various models import math - import numpy as np import torch import torch.nn as nn @@ -244,7 +243,7 @@ class Classify(nn.Module): def __init__(self, c1, c2, k=1, s=1, p=None, g=1): # ch_in, ch_out, kernel, stride, padding, groups super(Classify, self).__init__() self.aap = nn.AdaptiveAvgPool2d(1) # to x(b,c1,1,1) - self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False) # to x(b,c2,1,1) + self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g) # to x(b,c2,1,1) self.flat = Flatten() def forward(self, x): From dbcb192f2d6631c5414a144e3cce17568c830042 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 5 Dec 2020 11:41:17 +0100 Subject: [PATCH 0847/1185] Increase FLOPS robustness (#1589) --- utils/torch_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index b330ca56a2..cde934afc8 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -152,7 +152,7 @@ def model_info(model, verbose=False, img_size=640): try: # FLOPS from thop import profile - stride = int(model.stride.max()) + stride = int(model.stride.max()) if hasattr(model, 'stride') else 32 img = torch.zeros((1, 3, stride, stride), device=next(model.parameters()).device) # input flops = profile(deepcopy(model), inputs=(img,), verbose=False)[0] / 1E9 * 2 # stride FLOPS img_size = img_size if isinstance(img_size, list) else [img_size, img_size] # expand if int/float From 8f95dcf2530b17150345a9b9b75576a8eca7a178 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 6 Dec 2020 10:08:15 +0100 Subject: [PATCH 0848/1185] Update download_weights.sh with usage example (#1591) --- weights/download_weights.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/weights/download_weights.sh b/weights/download_weights.sh index e3a6b38839..6bb58023c9 100755 --- a/weights/download_weights.sh +++ b/weights/download_weights.sh @@ -1,5 +1,7 @@ #!/bin/bash # Download latest models from https://github.com/ultralytics/yolov3/releases +# Usage: +# $ bash weights/download_weights.sh python - < Date: Sun, 6 Dec 2020 11:55:27 +0100 Subject: [PATCH 0849/1185] Implement default class names (#1592) --- models/yolo.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/models/yolo.py b/models/yolo.py index 8978fb95c7..c388fb2d24 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -1,16 +1,16 @@ import argparse import logging -import math import sys from copy import deepcopy from pathlib import Path -sys.path.append('./') # to run '$ python *.py' files in subdirectories -logger = logging.getLogger(__name__) - +import math import torch import torch.nn as nn +sys.path.append('./') # to run '$ python *.py' files in subdirectories +logger = logging.getLogger(__name__) + from models.common import Conv, Bottleneck, SPP, DWConv, Focus, BottleneckCSP, Concat, NMS, autoShape from models.experimental import MixConv2d, CrossConv, C3 from utils.autoanchor import check_anchor_order @@ -82,6 +82,7 @@ def __init__(self, cfg='yolov3.yaml', ch=3, nc=None): # model, input channels, logger.info('Overriding model.yaml nc=%g with nc=%g' % (self.yaml['nc'], nc)) self.yaml['nc'] = nc # override yaml value self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelist, ch_out + self.names = [str(i) for i in range(self.yaml['nc'])] # default names # print([x.shape for x in self.forward(torch.zeros(1, ch, 64, 64))]) # Build strides, anchors From 4a07280884ced5d5ac3b7d7a5a54dfbff4afeb84 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 6 Dec 2020 14:58:50 +0100 Subject: [PATCH 0850/1185] Pycocotools best.pt after COCO train (#1593) --- test.py | 5 ++--- train.py | 33 ++++++++++++++++++++++----------- utils/google_utils.py | 2 +- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/test.py b/test.py index 4120057a4a..5b10e0f836 100644 --- a/test.py +++ b/test.py @@ -1,5 +1,4 @@ import argparse -import glob import json import os from pathlib import Path @@ -246,7 +245,7 @@ def test(data, # Save JSON if save_json and len(jdict): w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights - anno_json = glob.glob('../coco/annotations/instances_val*.json')[0] # annotations json + anno_json = '../coco/annotations/instances_val2017.json' # annotations json pred_json = str(save_dir / f"{w}_predictions.json") # predictions json print('\nEvaluating pycocotools mAP... saving %s...' % pred_json) with open(pred_json, 'w') as f: @@ -266,7 +265,7 @@ def test(data, eval.summarize() map, map50 = eval.stats[:2] # update results (mAP@0.5:0.95, mAP@0.5) except Exception as e: - print('ERROR: pycocotools unable to run: %s' % e) + print(f'pycocotools unable to run: {e}') # Return results if not training: diff --git a/train.py b/train.py index f0f778db97..91c8084fea 100644 --- a/train.py +++ b/train.py @@ -22,6 +22,7 @@ from tqdm import tqdm import test # import test.py to get mAP after each epoch +from models.experimental import attempt_load from models.yolo import Model from utils.autoanchor import check_anchors from utils.datasets import create_dataloader @@ -193,9 +194,9 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): # Process 0 if rank in [-1, 0]: ema.updates = start_epoch * nb // accumulate # set EMA updates - testloader = create_dataloader(test_path, imgsz_test, total_batch_size, gs, opt, + testloader = create_dataloader(test_path, imgsz_test, total_batch_size, gs, opt, # testloader hyp=hyp, cache=opt.cache_images and not opt.notest, rect=True, - rank=-1, world_size=opt.world_size, workers=opt.workers)[0] # testloader + rank=-1, world_size=opt.world_size, workers=opt.workers, pad=0.5)[0] if not opt.resume: labels = np.concatenate(dataset.labels, 0) @@ -385,15 +386,12 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): if rank in [-1, 0]: # Strip optimizers - n = opt.name if opt.name.isnumeric() else '' - fresults, flast, fbest = save_dir / f'results{n}.txt', wdir / f'last{n}.pt', wdir / f'best{n}.pt' - for f1, f2 in zip([wdir / 'last.pt', wdir / 'best.pt', results_file], [flast, fbest, fresults]): - if f1.exists(): - os.rename(f1, f2) # rename - if str(f2).endswith('.pt'): # is *.pt - strip_optimizer(f2) # strip optimizer - os.system('gsutil cp %s gs://%s/weights' % (f2, opt.bucket)) if opt.bucket else None # upload - # Finish + for f in [last, best]: + if f.exists(): # is *.pt + strip_optimizer(f) # strip optimizer + os.system('gsutil cp %s gs://%s/weights' % (f, opt.bucket)) if opt.bucket else None # upload + + # Plots if plots: plot_results(save_dir=save_dir) # save as results.png if wandb: @@ -401,6 +399,19 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): wandb.log({"Results": [wandb.Image(str(save_dir / f), caption=f) for f in files if (save_dir / f).exists()]}) logger.info('%g epochs completed in %.3f hours.\n' % (epoch - start_epoch + 1, (time.time() - t0) / 3600)) + + # Test best.pt + if opt.data.endswith('coco.yaml') and nc == 80: # if COCO + results, _, _ = test.test(opt.data, + batch_size=total_batch_size, + imgsz=imgsz_test, + model=attempt_load(best if best.exists() else last, device).half(), + single_cls=opt.single_cls, + dataloader=testloader, + save_dir=save_dir, + save_json=True, # use pycocotools + plots=False) + else: dist.destroy_process_group() diff --git a/utils/google_utils.py b/utils/google_utils.py index d50198fedf..7f07c201ea 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -17,7 +17,7 @@ def gsutil_getsize(url=''): def attempt_download(weights): # Attempt to download pretrained weights if not found locally - weights = weights.strip().replace("'", '') + weights = str(weights).strip().replace("'", '') file = Path(weights).name.lower() msg = weights + ' missing, try downloading from https://github.com/ultralytics/yolov3/releases/' From e285034b4b6992605833d4ee32d9df7177d4e32b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 6 Dec 2020 18:01:13 +0100 Subject: [PATCH 0851/1185] Hub device mismatch bug fix (#1594) --- utils/general.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/general.py b/utils/general.py index fa47289e5e..aac0e44b4b 100755 --- a/utils/general.py +++ b/utils/general.py @@ -265,7 +265,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, classes=None, detections with shape: nx6 (x1, y1, x2, y2, conf, cls) """ - nc = prediction[0].shape[1] - 5 # number of classes + nc = prediction.shape[2] - 5 # number of classes xc = prediction[..., 4] > conf_thres # candidates # Settings @@ -277,7 +277,7 @@ def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, classes=None, merge = False # use merge-NMS t = time.time() - output = [torch.zeros(0, 6)] * prediction.shape[0] + output = [torch.zeros((0, 6), device=prediction.device)] * prediction.shape[0] for xi, x in enumerate(prediction): # image index, image inference # Apply constraints # x[((x[..., 2:4] < min_wh) | (x[..., 2:4] > max_wh)).any(1), 4] = 0 # width-height From ce9feb42b4059da3539e1596d48dee1ac12341c4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 8 Dec 2020 17:03:22 -0800 Subject: [PATCH 0852/1185] Create codeql-analysis.yml (#1597) * Create codeql-analysis.yml * Update ci-testing.yml * Update codeql-analysis.yml * Update ci-testing.yml --- .github/workflows/ci-testing.yml | 5 ++- .github/workflows/codeql-analysis.yml | 54 +++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 69a5f239a5..1ae0bbb573 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -2,9 +2,12 @@ name: CI CPU testing on: # https://help.github.com/en/actions/reference/events-that-trigger-workflows push: + branches: [ master ] pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] schedule: - - cron: "0 0 * * *" + - cron: '0 0 * * *' # Runs at 00:00 UTC every day jobs: cpu-tests: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000000..1f07888509 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,54 @@ +# This action runs GitHub's industry-leading static analysis engine, CodeQL, against a repository's source code to find security vulnerabilities. +# https://github.com/github/codeql-action + +name: "CodeQL" + +on: + schedule: + - cron: '0 0 1 * *' # Runs at 00:00 UTC on the 1st of every month + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: [ 'python' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From 7e846c7d3c1ec5d2f5669767c01e451279cd9efe Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 8 Dec 2020 17:40:19 -0800 Subject: [PATCH 0853/1185] Reinstate PR curve sentinel values (#1598) --- utils/metrics.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/utils/metrics.py b/utils/metrics.py index af32ddc5b1..99d5bcfaf2 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -77,18 +77,17 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='precision def compute_ap(recall, precision): - """ Compute the average precision, given the recall and precision curves. - Source: https://github.com/rbgirshick/py-faster-rcnn. + """ Compute the average precision, given the recall and precision curves # Arguments - recall: The recall curve (list). - precision: The precision curve (list). + recall: The recall curve (list) + precision: The precision curve (list) # Returns - The average precision as computed in py-faster-rcnn. + Average precision, precision curve, recall curve """ # Append sentinel values to beginning and end - mrec = recall # np.concatenate(([0.], recall, [recall[-1] + 1E-3])) - mpre = precision # np.concatenate(([0.], precision, [0.])) + mrec = np.concatenate(([0.], recall, [recall[-1] + 0.01])) + mpre = np.concatenate(([1.], precision, [0.])) # Compute the precision envelope mpre = np.flip(np.maximum.accumulate(np.flip(mpre))) From 8d236eea3c2594cbc4ad9a3574a45bfa762a5750 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 8 Dec 2020 18:16:12 -0800 Subject: [PATCH 0854/1185] Hybrid auto-labelling support (#1599) * Introduce hybrid auto-labelling support * cleanup --- test.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test.py b/test.py index 5b10e0f836..5c8a70b93a 100644 --- a/test.py +++ b/test.py @@ -33,7 +33,8 @@ def test(data, dataloader=None, save_dir=Path(''), # for saving images save_txt=False, # for auto-labelling - save_conf=False, + save_hybrid=False, # for hybrid auto-labelling + save_conf=False, # save auto-label confidences plots=True, log_imgs=0): # number of logged images @@ -45,7 +46,6 @@ def test(data, else: # called directly set_logging() device = select_device(opt.device, batch_size=batch_size) - save_txt = opt.save_txt # save *.txt labels # Directories save_dir = Path(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) # increment run @@ -115,7 +115,7 @@ def test(data, # Run NMS targets[:, 2:] *= torch.Tensor([width, height, width, height]).to(device) # to pixels - lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_txt else [] # for autolabelling + lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling t = time_synchronized() output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres, labels=lb) t1 += time_synchronized() - t @@ -292,6 +292,7 @@ def test(data, parser.add_argument('--augment', action='store_true', help='augmented inference') parser.add_argument('--verbose', action='store_true', help='report mAP by class') parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-hybrid', action='store_true', help='save label+prediction hybrid results to *.txt') parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') parser.add_argument('--project', default='runs/test', help='save to project/name') @@ -313,7 +314,8 @@ def test(data, opt.single_cls, opt.augment, opt.verbose, - save_txt=opt.save_txt, + save_txt=opt.save_txt | opt.save_hybrid, + save_hybrid=opt.save_hybrid, save_conf=opt.save_conf, ) From 6b1fe3e9dd3dd8746ada7905b6673edad8043ad2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 8 Dec 2020 18:46:33 -0800 Subject: [PATCH 0855/1185] Normalized mosaic plotting bug fix (#1600) --- utils/plots.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/plots.py b/utils/plots.py index 12815ea28d..8fff8ec6dd 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -141,7 +141,7 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max conf = None if labels else image_targets[:, 6] # check for confidence presence (label vs pred) if boxes.shape[1]: - if boxes.max() <= 1: # if normalized + if boxes.max() <= 1.01: # if normalized with tolerance 0.01 boxes[[0, 2]] *= w # scale to pixels boxes[[1, 3]] *= h elif scale_factor < 1: # absolute coords need scale if image scales From 61fb2dbd20dd3085114e4bdf4efdecb89a4cdce2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 9 Dec 2020 07:43:58 -0800 Subject: [PATCH 0856/1185] Simplify autoshape() post-process (#1603) * Simplify autoshape() post-process * cleanup --- hubconf.py | 2 +- models/common.py | 7 +++---- requirements.txt | 4 ++-- utils/general.py | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/hubconf.py b/hubconf.py index 9067d0bd32..a0b66dc119 100644 --- a/hubconf.py +++ b/hubconf.py @@ -94,7 +94,7 @@ def yolov3_tiny(pretrained=False, channels=3, classes=80): if __name__ == '__main__': model = create(name='yolov3', pretrained=True, channels=3, classes=80) # example - model = model.fuse().autoshape() # for PIL/cv2/np inputs and NMS + model = model.autoshape() # for PIL/cv2/np inputs and NMS # Verify inference from PIL import Image diff --git a/models/common.py b/models/common.py index 90edaab23d..f26ffdd0ff 100644 --- a/models/common.py +++ b/models/common.py @@ -167,8 +167,7 @@ def forward(self, imgs, size=640, augment=False, profile=False): # Post-process for i in batch: - if y[i] is not None: - y[i][:, :4] = scale_coords(shape1, y[i][:, :4], shape0[i]) + scale_coords(shape1, y[i][:, :4], shape0[i]) return Detections(imgs, y, self.names) @@ -177,13 +176,13 @@ class Detections: # detections class for YOLOv5 inference results def __init__(self, imgs, pred, names=None): super(Detections, self).__init__() + d = pred[0].device # device + gn = [torch.tensor([*[im.shape[i] for i in [1, 0, 1, 0]], 1., 1.], device=d) for im in imgs] # normalizations self.imgs = imgs # list of images as numpy arrays self.pred = pred # list of tensors pred[0] = (xyxy, conf, cls) self.names = names # class names self.xyxy = pred # xyxy pixels self.xywh = [xyxy2xywh(x) for x in pred] # xywh pixels - d = pred[0].device # device - gn = [torch.tensor([*[im.shape[i] for i in [1, 0, 1, 0]], 1., 1.], device=d) for im in imgs] # normalizations self.xyxyn = [x / g for x, g in zip(self.xyxy, gn)] # xyxy normalized self.xywhn = [x / g for x, g in zip(self.xywh, gn)] # xywh normalized self.n = len(self.pred) diff --git a/requirements.txt b/requirements.txt index f9fc9fc298..4cb16138a0 100755 --- a/requirements.txt +++ b/requirements.txt @@ -26,5 +26,5 @@ pandas # scikit-learn==0.19.2 # for coreml quantization # extras -------------------------------------- -# thop # FLOPS computation -# pycocotools>=2.0 # COCO mAP +thop # FLOPS computation +pycocotools>=2.0 # COCO mAP diff --git a/utils/general.py b/utils/general.py index aac0e44b4b..182855126f 100755 --- a/utils/general.py +++ b/utils/general.py @@ -258,7 +258,7 @@ def wh_iou(wh1, wh2): return inter / (wh1.prod(2) + wh2.prod(2) - inter) # iou = inter / (area1 + area2 - inter) -def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, classes=None, agnostic=False, labels=()): +def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False, labels=()): """Performs Non-Maximum Suppression (NMS) on inference results Returns: From 883a5aff5a7f9bb9f22a5999088a769cb0e62431 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 10 Dec 2020 13:07:10 -0800 Subject: [PATCH 0857/1185] FReLU bias=False bug fix (#1607) --- utils/activations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/activations.py b/utils/activations.py index ba6b854ddc..24f5a30f02 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -65,7 +65,7 @@ def forward(self, x): class FReLU(nn.Module): def __init__(self, c1, k=3): # ch_in, kernel super().__init__() - self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1) + self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1, bias=False) self.bn = nn.BatchNorm2d(c1) def forward(self, x): From 1afde520d1c7920c327a6e1ea38ec6c944880c02 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 19 Dec 2020 19:01:15 -0800 Subject: [PATCH 0858/1185] Simplified PyTorch Hub loading of custom models (#1610) * Simplified PyTorch Hub loading of custom models * Update hubconf.py --- hubconf.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/hubconf.py b/hubconf.py index a0b66dc119..df7796d4ba 100644 --- a/hubconf.py +++ b/hubconf.py @@ -92,8 +92,29 @@ def yolov3_tiny(pretrained=False, channels=3, classes=80): return create('yolov3-tiny', pretrained, channels, classes) +def custom(path_or_model='path/to/model.pt'): + """YOLOv3-custom model from https://github.com/ultralytics/yolov3 + + Arguments (3 options): + path_or_model (str): 'path/to/model.pt' + path_or_model (dict): torch.load('path/to/model.pt') + path_or_model (nn.Module): torch.load('path/to/model.pt')['model'] + Returns: + pytorch model + """ + model = torch.load(path_or_model) if isinstance(path_or_model, str) else path_or_model # load checkpoint + if isinstance(model, dict): + model = model['model'] # load model + + hub_model = Model(model.yaml).to(next(model.parameters()).device) # create + hub_model.load_state_dict(model.float().state_dict()) # load state_dict + hub_model.names = model.names # class names + return hub_model + + if __name__ == '__main__': - model = create(name='yolov3', pretrained=True, channels=3, classes=80) # example + model = create(name='yolov3', pretrained=True, channels=3, classes=80) # pretrained example + # model = custom(path_or_model='path/to/model.pt') # custom example model = model.autoshape() # for PIL/cv2/np inputs and NMS # Verify inference From a21595e2e22e650b1e9f591c336e516b50a29b8f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 19 Dec 2020 19:37:04 -0800 Subject: [PATCH 0859/1185] Create Dependabot config file (#1615) * Create Dependabot config file * Update greetings.yml * Update greetings.yml * Update dependabot.yml Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- .github/dependabot.yml | 12 ++++++++++++ .github/workflows/greetings.yml | 10 +++++----- 2 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..f0b5bc9066 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: +- package-ecosystem: pip + directory: "/" + schedule: + interval: daily + time: "04:00" + open-pull-requests-limit: 10 + reviewers: + - glenn-jocher + labels: + - dependencies diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 2cbd208084..1d6ec61d2d 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -10,8 +10,8 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} pr-message: | - Hello @${{ github.actor }}, thank you for submitting a PR! To allow your work to be integrated as seamlessly as possible, we advise you to: - - Verify your PR is **up-to-date with origin/master.** If your PR is behind origin/master update by running the following, replacing 'feature' with the name of your local branch: + 👋 Hello @${{ github.actor }}, thank you for submitting a 🚀 PR! To allow your work to be integrated as seamlessly as possible, we advise you to: + - ✅ Verify your PR is **up-to-date with origin/master.** If your PR is behind origin/master update by running the following, replacing 'feature' with the name of your local branch: ```bash git remote add upstream https://github.com/ultralytics/yolov3.git git fetch upstream @@ -19,11 +19,11 @@ jobs: git rebase upstream/master git push -u origin -f ``` - - Verify all Continuous Integration (CI) **checks are passing**. - - Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ -Bruce Lee + - ✅ Verify all Continuous Integration (CI) **checks are passing**. + - ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ -Bruce Lee issue-message: | - Hello @${{ github.actor }}, thank you for your interest in 🚀 YOLOv3! Please visit our ⭐️ [Tutorials](https://github.com/ultralytics/yolov3/wiki#tutorials) to get started, where you can find quickstart guides for simple tasks like [Custom Data Training](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) all the way to advanced concepts like [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607). + 👋 Hello @${{ github.actor }}, thank you for your interest in 🚀 YOLOv3! Please visit our ⭐️ [Tutorials](https://github.com/ultralytics/yolov3/wiki#tutorials) to get started, where you can find quickstart guides for simple tasks like [Custom Data Training](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) all the way to advanced concepts like [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607). If this is a 🐛 Bug Report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you. From 7bff2d369a5966fe1c7341292ea21073c61ce777 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 22 Dec 2020 17:25:40 -0800 Subject: [PATCH 0860/1185] Update Dependabot config file (#1615) --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f0b5bc9066..9910689197 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,7 +3,7 @@ updates: - package-ecosystem: pip directory: "/" schedule: - interval: daily + interval: weekly time: "04:00" open-pull-requests-limit: 10 reviewers: From 1c39505d4eb0d6e4c81c38849338b79bb11efe2f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 22 Dec 2020 17:29:54 -0800 Subject: [PATCH 0861/1185] leaf Variable inplace bug fix (#1619) --- models/yolo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/yolo.py b/models/yolo.py index c388fb2d24..191bd77c35 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -148,8 +148,8 @@ def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is m = self.model[-1] # Detect() module for mi, s in zip(m.m, m.stride): # from b = mi.bias.view(m.na, -1) # conv.bias(255) to (3,85) - b[:, 4] += math.log(8 / (640 / s) ** 2) # obj (8 objects per 640 image) - b[:, 5:] += math.log(0.6 / (m.nc - 0.99)) if cf is None else torch.log(cf / cf.sum()) # cls + b.data[:, 4] += math.log(8 / (640 / s) ** 2) # obj (8 objects per 640 image) + b.data[:, 5:] += math.log(0.6 / (m.nc - 0.99)) if cf is None else torch.log(cf / cf.sum()) # cls mi.bias = torch.nn.Parameter(b.view(-1), requires_grad=True) def _print_biases(self): From 6ba36265fbcf7218ff69032109c3ee74709633e1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 22 Dec 2020 17:48:40 -0800 Subject: [PATCH 0862/1185] FROM nvcr.io/nvidia/pytorch:20.12-py3 (#1620) --- Dockerfile | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index e514893da6..6727548fa5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,13 @@ # Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch -FROM nvcr.io/nvidia/pytorch:20.10-py3 +FROM nvcr.io/nvidia/pytorch:20.12-py3 -# Install dependencies +# Install linux packages +RUN apt update && apt install -y screen libgl1-mesa-glx + +# Install python dependencies RUN pip install --upgrade pip -# COPY requirements.txt . -# RUN pip install -r requirements.txt +COPY requirements.txt . +RUN pip install -r requirements.txt RUN pip install gsutil # Create working directory From 865e046e11783bf13fba71634b26a3260bd90c5a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 2 Jan 2021 13:04:12 -0800 Subject: [PATCH 0863/1185] Update yolov3-tiny.yaml --- models/yolov3-tiny.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/yolov3-tiny.yaml b/models/yolov3-tiny.yaml index 85f9fbd498..ff7638cad3 100644 --- a/models/yolov3-tiny.yaml +++ b/models/yolov3-tiny.yaml @@ -22,7 +22,7 @@ backbone: [-1, 1, Conv, [256, 3, 1]], [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 9-P5/32 [-1, 1, Conv, [512, 3, 1]], - [-1, 1, nn.ZeroPad2d, [0, 1, 0, 1]], # 11 + [-1, 1, nn.ZeroPad2d, [[0, 1, 0, 1]]], # 11 [-1, 1, nn.MaxPool2d, [2, 1, 0]], # 12 ] From 7d9535f80efe6fe7b78dfc5da2f3d9fa6e606a4f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 3 Jan 2021 11:42:10 -0800 Subject: [PATCH 0864/1185] Update yolo.py nn.zeroPad2d() (#1638) --- models/yolo.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/models/yolo.py b/models/yolo.py index 191bd77c35..7ef9d501eb 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -240,9 +240,6 @@ def parse_model(d, ch): # model_dict, input_channels(3) n = 1 elif m is nn.BatchNorm2d: args = [ch[f]] - elif m is nn.ZeroPad2d: - args = [args] - c2 = ch[f] elif m is Concat: c2 = sum([ch[-1 if x == -1 else x + 1] for x in f]) elif m is Detect: From 84ad6080ae1471b3835e60e3ecb1f6a95e9394d4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 3 Jan 2021 14:37:22 -0800 Subject: [PATCH 0865/1185] Update Torch CUDA Synchronize (#1637) --- utils/torch_utils.py | 91 ++++++++++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index cde934afc8..69a31213c5 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -13,6 +13,10 @@ import torch.nn.functional as F import torchvision +try: + import thop # for FLOPS computation +except ImportError: + thop = None logger = logging.getLogger(__name__) @@ -32,44 +36,83 @@ def init_torch_seeds(seed=0): # Speed-reproducibility tradeoff https://pytorch.org/docs/stable/notes/randomness.html torch.manual_seed(seed) if seed == 0: # slower, more reproducible - cudnn.deterministic = True - cudnn.benchmark = False + cudnn.benchmark, cudnn.deterministic = False, True else: # faster, less reproducible - cudnn.deterministic = False - cudnn.benchmark = True + cudnn.benchmark, cudnn.deterministic = True, False def select_device(device='', batch_size=None): # device = 'cpu' or '0' or '0,1,2,3' - cpu_request = device.lower() == 'cpu' - if device and not cpu_request: # if device requested other than 'cpu' + s = f'Using torch {torch.__version__} ' # string + cpu = device.lower() == 'cpu' + if cpu: + os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # force torch.cuda.is_available() = False + elif device: # non-cpu device requested os.environ['CUDA_VISIBLE_DEVICES'] = device # set environment variable - assert torch.cuda.is_available(), 'CUDA unavailable, invalid device %s requested' % device # check availablity + assert torch.cuda.is_available(), f'CUDA unavailable, invalid device {device} requested' # check availability - cuda = False if cpu_request else torch.cuda.is_available() + cuda = torch.cuda.is_available() and not cpu if cuda: - c = 1024 ** 2 # bytes to MB - ng = torch.cuda.device_count() - if ng > 1 and batch_size: # check that batch_size is compatible with device_count - assert batch_size % ng == 0, 'batch-size %g not multiple of GPU count %g' % (batch_size, ng) - x = [torch.cuda.get_device_properties(i) for i in range(ng)] - s = f'Using torch {torch.__version__} ' - for i in range(0, ng): - if i == 1: - s = ' ' * len(s) - logger.info("%sCUDA:%g (%s, %dMB)" % (s, i, x[i].name, x[i].total_memory / c)) + n = torch.cuda.device_count() + if n > 1 and batch_size: # check that batch_size is compatible with device_count + assert batch_size % n == 0, f'batch-size {batch_size} not multiple of GPU count {n}' + space = ' ' * len(s) + for i, d in enumerate(device.split(',') if device else range(n)): + p = torch.cuda.get_device_properties(i) + s += f"{'' if i == 0 else space}CUDA:{d} ({p.name}, {p.total_memory / 1024 ** 2}MB)\n" # bytes to MB else: - logger.info(f'Using torch {torch.__version__} CPU') + s += 'CPU' - logger.info('') # skip a line + logger.info(f'{s}\n') # skip a line return torch.device('cuda:0' if cuda else 'cpu') def time_synchronized(): - torch.cuda.synchronize() if torch.cuda.is_available() else None + # pytorch-accurate time + if torch.cuda.is_available(): + torch.cuda.synchronize() return time.time() +def profile(x, ops, n=100, device=None): + # profile a pytorch module or list of modules. Example usage: + # x = torch.randn(16, 3, 640, 640) # input + # m1 = lambda x: x * torch.sigmoid(x) + # m2 = nn.SiLU() + # profile(x, [m1, m2], n=100) # profile speed over 100 iterations + + device = device or torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') + x = x.to(device) + x.requires_grad = True + print(torch.__version__, device.type, torch.cuda.get_device_properties(0) if device.type == 'cuda' else '') + print(f"\n{'Params':>12s}{'GFLOPS':>12s}{'forward (ms)':>16s}{'backward (ms)':>16s}{'input':>24s}{'output':>24s}") + for m in ops if isinstance(ops, list) else [ops]: + m = m.to(device) if hasattr(m, 'to') else m # device + m = m.half() if hasattr(m, 'half') and isinstance(x, torch.Tensor) and x.dtype is torch.float16 else m # type + dtf, dtb, t = 0., 0., [0., 0., 0.] # dt forward, backward + try: + flops = thop.profile(m, inputs=(x,), verbose=False)[0] / 1E9 * 2 # GFLOPS + except: + flops = 0 + + for _ in range(n): + t[0] = time_synchronized() + y = m(x) + t[1] = time_synchronized() + try: + _ = y.sum().backward() + t[2] = time_synchronized() + except: # no backward method + t[2] = float('nan') + dtf += (t[1] - t[0]) * 1000 / n # ms per op forward + dtb += (t[2] - t[1]) * 1000 / n # ms per op backward + + s_in = tuple(x.shape) if isinstance(x, torch.Tensor) else 'list' + s_out = tuple(y.shape) if isinstance(y, torch.Tensor) else 'list' + p = sum(list(x.numel() for x in m.parameters())) if isinstance(m, nn.Module) else 0 # parameters + print(f'{p:12.4g}{flops:12.4g}{dtf:16.4g}{dtb:16.4g}{str(s_in):>24s}{str(s_out):>24s}') + + def is_parallel(model): return type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) @@ -153,10 +196,10 @@ def model_info(model, verbose=False, img_size=640): try: # FLOPS from thop import profile stride = int(model.stride.max()) if hasattr(model, 'stride') else 32 - img = torch.zeros((1, 3, stride, stride), device=next(model.parameters()).device) # input - flops = profile(deepcopy(model), inputs=(img,), verbose=False)[0] / 1E9 * 2 # stride FLOPS + img = torch.zeros((1, model.yaml.get('ch', 3), stride, stride), device=next(model.parameters()).device) # input + flops = profile(deepcopy(model), inputs=(img,), verbose=False)[0] / 1E9 * 2 # stride GFLOPS img_size = img_size if isinstance(img_size, list) else [img_size, img_size] # expand if int/float - fs = ', %.1f GFLOPS' % (flops * img_size[0] / stride * img_size[1] / stride) # 640x640 FLOPS + fs = ', %.1f GFLOPS' % (flops * img_size[0] / stride * img_size[1] / stride) # 640x640 GFLOPS except (ImportError, Exception): fs = '' From 4f2341c0ad0d0cb15dad0f20bc6f4d92380804ee Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 6 Jan 2021 16:39:03 -0800 Subject: [PATCH 0866/1185] W&B ID reset on training completion (#1852) --- utils/general.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/general.py b/utils/general.py index 182855126f..22647f6cd2 100755 --- a/utils/general.py +++ b/utils/general.py @@ -350,8 +350,8 @@ def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=Non def strip_optimizer(f='weights/best.pt', s=''): # from utils.general import *; strip_optimizer() # Strip optimizer from 'f' to finalize training, optionally save as 's' x = torch.load(f, map_location=torch.device('cpu')) - x['optimizer'] = None - x['training_results'] = None + for key in 'optimizer', 'training_results', 'wandb_id': + x[key] = None x['epoch'] = -1 x['model'].half() # to FP16 for p in x['model'].parameters(): From d88829cebe0b9984a9d85f34dc5c95313ff77e65 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 7 Jan 2021 11:25:15 -0800 Subject: [PATCH 0867/1185] actions/stale@v3 (#1647) --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index d4126b8b46..0a094e237b 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,7 +7,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v1 + - uses: actions/stale@v3 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' From d9b29951c15d7d6366a92cf03d6262ba8782172d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 8 Jan 2021 10:57:40 -0800 Subject: [PATCH 0868/1185] Update google_utils.py --- utils/google_utils.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/utils/google_utils.py b/utils/google_utils.py index 7f07c201ea..4238cf8c34 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -6,6 +6,7 @@ import time from pathlib import Path +import requests import torch @@ -21,21 +22,14 @@ def attempt_download(weights): file = Path(weights).name.lower() msg = weights + ' missing, try downloading from https://github.com/ultralytics/yolov3/releases/' - models = ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt'] # available models - redundant = False # offer second download option - - if file in models and not os.path.isfile(weights): - # Google Drive - # d = {'yolov5s.pt': '1R5T6rIyy3lLwgFXNms8whc-387H0tMQO', - # 'yolov5m.pt': '1vobuEExpWQVpXExsJ2w-Mbf3HJjWkQJr', - # 'yolov5l.pt': '1hrlqD1Wdei7UT4OgT785BEk1JwnSvNEV', - # 'yolov5x.pt': '1mM8aZJlWTxOg7BZJvNUMrTnA2AbeCVzS'} - # r = gdrive_download(id=d[file], name=weights) if file in d else 1 - # if r == 0 and os.path.exists(weights) and os.path.getsize(weights) > 1E6: # check - # return + response = requests.get('https://api.github.com/repos/ultralytics/yolov3/releases/latest').json() # github api + assets = [x['name'] for x in response['assets']] # release assets ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt'] + redundant = False # second download option + if file in assets and not os.path.isfile(weights): try: # GitHub - url = 'https://github.com/ultralytics/yolov3/releases/download/v1.0/' + file + tag = response['tag_name'] # i.e. 'v1.0' + url = f'https://github.com/ultralytics/yolov3/releases/download/{tag}/{file}' print('Downloading %s to %s...' % (url, weights)) torch.hub.download_url_to_file(url, weights) assert os.path.exists(weights) and os.path.getsize(weights) > 1E6 # check @@ -53,10 +47,9 @@ def attempt_download(weights): return -def gdrive_download(id='1n_oKgR81BJtqk75b00eAjdv03qVCQn2f', name='coco128.zip'): +def gdrive_download(id='16TiPfZj7htmTyhntwcZyEEAejOUxuT6m', name='tmp.zip'): # Downloads a file from Google Drive. from utils.google_utils import *; gdrive_download() t = time.time() - print('Downloading https://drive.google.com/uc?export=download&id=%s as %s... ' % (id, name), end='') os.remove(name) if os.path.exists(name) else None # remove existing os.remove('cookie') if os.path.exists('cookie') else None From 162773d968bb77f5deb7a2b3b601e4428b2f678b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 9 Jan 2021 21:34:12 -0800 Subject: [PATCH 0869/1185] Update torch_utils.py (#1652) --- utils/torch_utils.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 69a31213c5..82fc731c02 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -3,9 +3,11 @@ import logging import math import os +import subprocess import time from contextlib import contextmanager from copy import deepcopy +from pathlib import Path import torch import torch.backends.cudnn as cudnn @@ -41,9 +43,17 @@ def init_torch_seeds(seed=0): cudnn.benchmark, cudnn.deterministic = True, False +def git_describe(): + # return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe + if Path('.git').exists(): + return subprocess.check_output('git describe --tags --long --always', shell=True).decode('utf-8')[:-1] + else: + return '' + + def select_device(device='', batch_size=None): # device = 'cpu' or '0' or '0,1,2,3' - s = f'Using torch {torch.__version__} ' # string + s = f'YOLOv3 {git_describe()} torch {torch.__version__} ' # string cpu = device.lower() == 'cpu' if cpu: os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # force torch.cuda.is_available() = False @@ -61,9 +71,9 @@ def select_device(device='', batch_size=None): p = torch.cuda.get_device_properties(i) s += f"{'' if i == 0 else space}CUDA:{d} ({p.name}, {p.total_memory / 1024 ** 2}MB)\n" # bytes to MB else: - s += 'CPU' + s += 'CPU\n' - logger.info(f'{s}\n') # skip a line + logger.info(s) # skip a line return torch.device('cuda:0' if cuda else 'cpu') @@ -225,8 +235,8 @@ def load_classifier(name='resnet101', n=2): return model -def scale_img(img, ratio=1.0, same_shape=False): # img(16,3,256,416), r=ratio - # scales img(bs,3,y,x) by ratio +def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416) + # scales img(bs,3,y,x) by ratio constrained to gs-multiple if ratio == 1.0: return img else: @@ -234,7 +244,6 @@ def scale_img(img, ratio=1.0, same_shape=False): # img(16,3,256,416), r=ratio s = (int(h * ratio), int(w * ratio)) # new size img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize if not same_shape: # pad/crop img - gs = 32 # (pixels) grid size h, w = [math.ceil(x * ratio / gs) * gs for x in (h, w)] return F.pad(img, [0, w - s[1], 0, h - s[0]], value=0.447) # value = imagenet mean From 0bc1db58d82c2482bfac1e32a3a43cfd5a533da2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 10 Jan 2021 12:02:55 -0800 Subject: [PATCH 0870/1185] GitHub API rate limit fix (#1653) --- utils/google_utils.py | 95 ++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/utils/google_utils.py b/utils/google_utils.py index 4238cf8c34..c749741419 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -12,71 +12,74 @@ def gsutil_getsize(url=''): # gs://bucket/file size https://cloud.google.com/storage/docs/gsutil/commands/du - s = subprocess.check_output('gsutil du %s' % url, shell=True).decode('utf-8') + s = subprocess.check_output(f'gsutil du {url}', shell=True).decode('utf-8') return eval(s.split(' ')[0]) if len(s) else 0 # bytes -def attempt_download(weights): - # Attempt to download pretrained weights if not found locally - weights = str(weights).strip().replace("'", '') - file = Path(weights).name.lower() - - msg = weights + ' missing, try downloading from https://github.com/ultralytics/yolov3/releases/' - response = requests.get('https://api.github.com/repos/ultralytics/yolov3/releases/latest').json() # github api - assets = [x['name'] for x in response['assets']] # release assets ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt'] - redundant = False # second download option - - if file in assets and not os.path.isfile(weights): - try: # GitHub - tag = response['tag_name'] # i.e. 'v1.0' - url = f'https://github.com/ultralytics/yolov3/releases/download/{tag}/{file}' - print('Downloading %s to %s...' % (url, weights)) - torch.hub.download_url_to_file(url, weights) - assert os.path.exists(weights) and os.path.getsize(weights) > 1E6 # check - except Exception as e: # GCP - print('Download error: %s' % e) - assert redundant, 'No secondary mirror' - url = 'https://storage.googleapis.com/ultralytics/yolov3/ckpt/' + file - print('Downloading %s to %s...' % (url, weights)) - r = os.system('curl -L %s -o %s' % (url, weights)) # torch.hub.download_url_to_file(url, weights) - finally: - if not (os.path.exists(weights) and os.path.getsize(weights) > 1E6): # check - os.remove(weights) if os.path.exists(weights) else None # remove partial downloads - print('ERROR: Download failure: %s' % msg) - print('') - return - - -def gdrive_download(id='16TiPfZj7htmTyhntwcZyEEAejOUxuT6m', name='tmp.zip'): - # Downloads a file from Google Drive. from utils.google_utils import *; gdrive_download() +def attempt_download(file): + # Attempt file download if does not exist + file = Path(str(file).strip().replace("'", '').lower()) + + if not file.exists(): + response = requests.get('https://api.github.com/repos/ultralytics/yolov3/releases/latest').json() # github api + assets = [x['name'] for x in response['assets']] # release assets ['yolov3.pt', 'yolov3-spp.pt', ...] + name = file.name + + if name in assets: + msg = f'{file} missing, try downloading from https://github.com/ultralytics/yolov3/releases/' + redundant = False # second download option + try: # GitHub + tag = response['tag_name'] # i.e. 'v1.0' + url = f'https://github.com/ultralytics/yolov3/releases/download/{tag}/{name}' + print(f'Downloading {url} to {file}...') + torch.hub.download_url_to_file(url, file) + assert file.exists() and file.stat().st_size > 1E6 # check + except Exception as e: # GCP + print(f'Download error: {e}') + assert redundant, 'No secondary mirror' + url = f'https://storage.googleapis.com/ultralytics/yolov3/ckpt/{name}' + print(f'Downloading {url} to {file}...') + os.system(f'curl -L {url} -o {file}') # torch.hub.download_url_to_file(url, weights) + finally: + if not file.exists() or file.stat().st_size < 1E6: # check + file.unlink(missing_ok=True) # remove partial downloads + print(f'ERROR: Download failure: {msg}') + print('') + return + + +def gdrive_download(id='16TiPfZj7htmTyhntwcZyEEAejOUxuT6m', file='tmp.zip'): + # Downloads a file from Google Drive. from yolov3.utils.google_utils import *; gdrive_download() t = time.time() - print('Downloading https://drive.google.com/uc?export=download&id=%s as %s... ' % (id, name), end='') - os.remove(name) if os.path.exists(name) else None # remove existing - os.remove('cookie') if os.path.exists('cookie') else None + file = Path(file) + cookie = Path('cookie') # gdrive cookie + print(f'Downloading https://drive.google.com/uc?export=download&id={id} as {file}... ', end='') + file.unlink(missing_ok=True) # remove existing file + cookie.unlink(missing_ok=True) # remove existing cookie # Attempt file download out = "NUL" if platform.system() == "Windows" else "/dev/null" - os.system('curl -c ./cookie -s -L "drive.google.com/uc?export=download&id=%s" > %s ' % (id, out)) + os.system(f'curl -c ./cookie -s -L "drive.google.com/uc?export=download&id={id}" > {out}') if os.path.exists('cookie'): # large file - s = 'curl -Lb ./cookie "drive.google.com/uc?export=download&confirm=%s&id=%s" -o %s' % (get_token(), id, name) + s = f'curl -Lb ./cookie "drive.google.com/uc?export=download&confirm={get_token()}&id={id}" -o {file}' else: # small file - s = 'curl -s -L -o %s "drive.google.com/uc?export=download&id=%s"' % (name, id) + s = f'curl -s -L -o {file} "drive.google.com/uc?export=download&id={id}"' r = os.system(s) # execute, capture return - os.remove('cookie') if os.path.exists('cookie') else None + cookie.unlink(missing_ok=True) # remove existing cookie # Error check if r != 0: - os.remove(name) if os.path.exists(name) else None # remove partial + file.unlink(missing_ok=True) # remove partial print('Download error ') # raise Exception('Download error') return r # Unzip if archive - if name.endswith('.zip'): + if file.suffix == '.zip': print('unzipping... ', end='') - os.system('unzip -q %s' % name) # unzip - os.remove(name) # remove zip to free space + os.system(f'unzip -q {file}') # unzip + file.unlink() # remove zip to free space - print('Done (%.1fs)' % (time.time() - t)) + print(f'Done ({time.time() - t:.1f}s)') return r From 166a4d590f08b55cadfebc57a11a52ff2fc2b7d3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 12 Jan 2021 23:05:32 -0800 Subject: [PATCH 0871/1185] v9.1 release (#1658) --- Dockerfile | 8 +- detect.py | 28 +++---- hubconf.py | 27 +++---- models/common.py | 119 ++++++++++++++++++++-------- models/experimental.py | 23 +----- models/export.py | 11 ++- models/yolo.py | 23 +++--- requirements.txt | 2 +- test.py | 10 ++- train.py | 105 ++++++++++++++----------- utils/activations.py | 4 +- utils/autoanchor.py | 28 ++++--- utils/datasets.py | 173 ++++++++++++++++++++++++++++++++--------- utils/general.py | 92 ++++++++++++++++++---- utils/loss.py | 42 +++++++--- utils/plots.py | 71 +++++++++++------ utils/torch_utils.py | 2 +- 17 files changed, 519 insertions(+), 249 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6727548fa5..d0a797fdf3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,12 +17,6 @@ WORKDIR /usr/src/app # Copy contents COPY . /usr/src/app -# Copy weights -#RUN python3 -c "from models import *; \ -#attempt_download('weights/yolov3.pt'); \ -#attempt_download('weights/yolov3-spp.pt'); \ -#attempt_download('weights/yolov3-tiny.pt')" - # --------------------------------------------------- Extras Below --------------------------------------------------- @@ -31,7 +25,7 @@ COPY . /usr/src/app # for v in {300..303}; do t=ultralytics/coco:v$v && sudo docker build -t $t . && sudo docker push $t; done # Pull and Run -# t=ultralytics/yolov3:latest && sudo docker pull $t && sudo docker run -it --ipc=host $t +# t=ultralytics/yolov3:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all $t # Pull and Run with local directory access # t=ultralytics/yolov3:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all -v "$(pwd)"/coco:/usr/src/coco $t diff --git a/detect.py b/detect.py index 4e4de61f34..2ccc20d31a 100644 --- a/detect.py +++ b/detect.py @@ -9,8 +9,8 @@ from models.experimental import attempt_load from utils.datasets import LoadStreams, LoadImages -from utils.general import check_img_size, non_max_suppression, apply_classifier, scale_coords, xyxy2xywh, \ - strip_optimizer, set_logging, increment_path +from utils.general import check_img_size, check_requirements, non_max_suppression, apply_classifier, scale_coords, \ + xyxy2xywh, strip_optimizer, set_logging, increment_path from utils.plots import plot_one_box from utils.torch_utils import select_device, load_classifier, time_synchronized @@ -81,12 +81,13 @@ def detect(save_img=False): # Process detections for i, det in enumerate(pred): # detections per image if webcam: # batch_size >= 1 - p, s, im0 = Path(path[i]), '%g: ' % i, im0s[i].copy() + p, s, im0, frame = path[i], '%g: ' % i, im0s[i].copy(), dataset.count else: - p, s, im0 = Path(path), '', im0s + p, s, im0, frame = path, '', im0s, getattr(dataset, 'frame', 0) - save_path = str(save_dir / p.name) - txt_path = str(save_dir / 'labels' / p.stem) + ('_%g' % dataset.frame if dataset.mode == 'video' else '') + p = Path(p) # to Path + save_path = str(save_dir / p.name) # img.jpg + txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # img.txt s += '%gx%g ' % img.shape[2:] # print string gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh if len(det): @@ -96,7 +97,7 @@ def detect(save_img=False): # Print results for c in det[:, -1].unique(): n = (det[:, -1] == c).sum() # detections per class - s += '%g %ss, ' % (n, names[int(c)]) # add to string + s += f'{n} {names[int(c)]}s, ' # add to string # Write results for *xyxy, conf, cls in reversed(det): @@ -107,23 +108,21 @@ def detect(save_img=False): f.write(('%g ' * len(line)).rstrip() % line + '\n') if save_img or view_img: # Add bbox to image - label = '%s %.2f' % (names[int(cls)], conf) + label = f'{names[int(cls)]} {conf:.2f}' plot_one_box(xyxy, im0, label=label, color=colors[int(cls)], line_thickness=3) # Print time (inference + NMS) - print('%sDone. (%.3fs)' % (s, t2 - t1)) + print(f'{s}Done. ({t2 - t1:.3f}s)') # Stream results if view_img: cv2.imshow(str(p), im0) - if cv2.waitKey(1) == ord('q'): # q to quit - raise StopIteration # Save results (image with detections) if save_img: - if dataset.mode == 'images': + if dataset.mode == 'image': cv2.imwrite(save_path, im0) - else: + else: # 'video' if vid_path != save_path: # new video vid_path = save_path if isinstance(vid_writer, cv2.VideoWriter): @@ -140,7 +139,7 @@ def detect(save_img=False): s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' print(f"Results saved to {save_dir}{s}") - print('Done. (%.3fs)' % (time.time() - t0)) + print(f'Done. ({time.time() - t0:.3f}s)') if __name__ == '__main__': @@ -163,6 +162,7 @@ def detect(save_img=False): parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') opt = parser.parse_args() print(opt) + check_requirements() with torch.no_grad(): if opt.update: # update all models (to fix SourceChangeWarning) diff --git a/hubconf.py b/hubconf.py index df7796d4ba..7b0f20115e 100644 --- a/hubconf.py +++ b/hubconf.py @@ -17,7 +17,7 @@ set_logging() -def create(name, pretrained, channels, classes): +def create(name, pretrained, channels, classes, autoshape): """Creates a specified YOLOv3 model Arguments: @@ -41,7 +41,8 @@ def create(name, pretrained, channels, classes): model.load_state_dict(state_dict, strict=False) # load if len(ckpt['model'].names) == classes: model.names = ckpt['model'].names # set class names attribute - # model = model.autoshape() # for PIL/cv2/np inputs and NMS + if autoshape: + model = model.autoshape() # for file/URI/PIL/cv2/np inputs and NMS return model except Exception as e: @@ -50,7 +51,7 @@ def create(name, pretrained, channels, classes): raise Exception(s) from e -def yolov3(pretrained=False, channels=3, classes=80): +def yolov3(pretrained=False, channels=3, classes=80, autoshape=True): """YOLOv3 model from https://github.com/ultralytics/yolov3 Arguments: @@ -61,10 +62,10 @@ def yolov3(pretrained=False, channels=3, classes=80): Returns: pytorch model """ - return create('yolov3', pretrained, channels, classes) + return create('yolov3', pretrained, channels, classes, autoshape) -def yolov3_spp(pretrained=False, channels=3, classes=80): +def yolov3_spp(pretrained=False, channels=3, classes=80, autoshape=True): """YOLOv3-SPP model from https://github.com/ultralytics/yolov3 Arguments: @@ -75,10 +76,10 @@ def yolov3_spp(pretrained=False, channels=3, classes=80): Returns: pytorch model """ - return create('yolov3-spp', pretrained, channels, classes) + return create('yolov3-spp', pretrained, channels, classes, autoshape) -def yolov3_tiny(pretrained=False, channels=3, classes=80): +def yolov3_tiny(pretrained=False, channels=3, classes=80, autoshape=True): """YOLOv3-tiny model from https://github.com/ultralytics/yolov3 Arguments: @@ -89,16 +90,17 @@ def yolov3_tiny(pretrained=False, channels=3, classes=80): Returns: pytorch model """ - return create('yolov3-tiny', pretrained, channels, classes) + return create('yolov3-tiny', pretrained, channels, classes, autoshape) -def custom(path_or_model='path/to/model.pt'): +def custom(path_or_model='path/to/model.pt', autoshape=True): """YOLOv3-custom model from https://github.com/ultralytics/yolov3 - + Arguments (3 options): path_or_model (str): 'path/to/model.pt' path_or_model (dict): torch.load('path/to/model.pt') path_or_model (nn.Module): torch.load('path/to/model.pt')['model'] + Returns: pytorch model """ @@ -109,13 +111,12 @@ def custom(path_or_model='path/to/model.pt'): hub_model = Model(model.yaml).to(next(model.parameters()).device) # create hub_model.load_state_dict(model.float().state_dict()) # load state_dict hub_model.names = model.names # class names - return hub_model + return hub_model.autoshape() if autoshape else hub_model if __name__ == '__main__': - model = create(name='yolov3', pretrained=True, channels=3, classes=80) # pretrained example + model = create(name='yolov3', pretrained=True, channels=3, classes=80, autoshape=True) # pretrained example # model = custom(path_or_model='path/to/model.pt') # custom example - model = model.autoshape() # for PIL/cv2/np inputs and NMS # Verify inference from PIL import Image diff --git a/models/common.py b/models/common.py index f26ffdd0ff..fd9d9fcdd7 100644 --- a/models/common.py +++ b/models/common.py @@ -1,7 +1,9 @@ # This file contains modules common to various models import math + import numpy as np +import requests import torch import torch.nn as nn from PIL import Image, ImageDraw @@ -29,7 +31,7 @@ def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, k super(Conv, self).__init__() self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False) self.bn = nn.BatchNorm2d(c2) - self.act = nn.LeakyReLU(0.1) if act else nn.Identity() + self.act = nn.LeakyReLU(0.1) if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) def forward(self, x): return self.act(self.bn(self.conv(x))) @@ -70,6 +72,21 @@ def forward(self, x): return self.cv4(self.act(self.bn(torch.cat((y1, y2), dim=1)))) +class C3(nn.Module): + # CSP Bottleneck with 3 convolutions + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion + super(C3, self).__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = Conv(c1, c_, 1, 1) + self.cv3 = Conv(2 * c_, c2, 1) # act=FReLU(c2) + self.m = nn.Sequential(*[Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)]) + # self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)]) + + def forward(self, x): + return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1)) + + class SPP(nn.Module): # Spatial pyramid pooling layer used in YOLOv3-SPP def __init__(self, c1, c2, k=(5, 9, 13)): @@ -89,9 +106,39 @@ class Focus(nn.Module): def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups super(Focus, self).__init__() self.conv = Conv(c1 * 4, c2, k, s, p, g, act) + # self.contract = Contract(gain=2) def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2) return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1)) + # return self.conv(self.contract(x)) + + +class Contract(nn.Module): + # Contract width-height into channels, i.e. x(1,64,80,80) to x(1,256,40,40) + def __init__(self, gain=2): + super().__init__() + self.gain = gain + + def forward(self, x): + N, C, H, W = x.size() # assert (H / s == 0) and (W / s == 0), 'Indivisible gain' + s = self.gain + x = x.view(N, C, H // s, s, W // s, s) # x(1,64,40,2,40,2) + x = x.permute(0, 3, 5, 1, 2, 4).contiguous() # x(1,2,2,64,40,40) + return x.view(N, C * s * s, H // s, W // s) # x(1,256,40,40) + + +class Expand(nn.Module): + # Expand channels into width-height, i.e. x(1,64,80,80) to x(1,16,160,160) + def __init__(self, gain=2): + super().__init__() + self.gain = gain + + def forward(self, x): + N, C, H, W = x.size() # assert C / s ** 2 == 0, 'Indivisible gain' + s = self.gain + x = x.view(N, s, s, C // s ** 2, H, W) # x(1,2,2,16,80,80) + x = x.permute(0, 3, 4, 1, 5, 2).contiguous() # x(1,16,80,2,80,2) + return x.view(N, C // s ** 2, H * s, W * s) # x(1,16,160,160) class Concat(nn.Module): @@ -128,35 +175,42 @@ def __init__(self, model): super(autoShape, self).__init__() self.model = model.eval() + def autoshape(self): + print('autoShape already enabled, skipping... ') # model already converted to model.autoshape() + return self + def forward(self, imgs, size=640, augment=False, profile=False): - # supports inference from various sources. For height=720, width=1280, RGB images example inputs are: - # opencv: imgs = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(720,1280,3) - # PIL: imgs = Image.open('image.jpg') # HWC x(720,1280,3) - # numpy: imgs = np.zeros((720,1280,3)) # HWC - # torch: imgs = torch.zeros(16,3,720,1280) # BCHW - # multiple: imgs = [Image.open('image1.jpg'), Image.open('image2.jpg'), ...] # list of images + # Inference from various sources. For height=720, width=1280, RGB images example inputs are: + # filename: imgs = 'data/samples/zidane.jpg' + # URI: = 'https://github.com/ultralytics/yolov5/releases/download/v1.0/zidane.jpg' + # OpenCV: = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(720,1280,3) + # PIL: = Image.open('image.jpg') # HWC x(720,1280,3) + # numpy: = np.zeros((720,1280,3)) # HWC + # torch: = torch.zeros(16,3,720,1280) # BCHW + # multiple: = [Image.open('image1.jpg'), Image.open('image2.jpg'), ...] # list of images p = next(self.model.parameters()) # for device and type if isinstance(imgs, torch.Tensor): # torch return self.model(imgs.to(p.device).type_as(p), augment, profile) # inference # Pre-process - if not isinstance(imgs, list): - imgs = [imgs] + n, imgs = (len(imgs), imgs) if isinstance(imgs, list) else (1, [imgs]) # number of images, list of images shape0, shape1 = [], [] # image and inference shapes - batch = range(len(imgs)) # batch size - for i in batch: - imgs[i] = np.array(imgs[i]) # to numpy - if imgs[i].shape[0] < 5: # image in CHW - imgs[i] = imgs[i].transpose((1, 2, 0)) # reverse dataloader .transpose(2, 0, 1) - imgs[i] = imgs[i][:, :, :3] if imgs[i].ndim == 3 else np.tile(imgs[i][:, :, None], 3) # enforce 3ch input - s = imgs[i].shape[:2] # HWC + for i, im in enumerate(imgs): + if isinstance(im, str): # filename or uri + im = Image.open(requests.get(im, stream=True).raw if im.startswith('http') else im) # open + im = np.array(im) # to numpy + if im.shape[0] < 5: # image in CHW + im = im.transpose((1, 2, 0)) # reverse dataloader .transpose(2, 0, 1) + im = im[:, :, :3] if im.ndim == 3 else np.tile(im[:, :, None], 3) # enforce 3ch input + s = im.shape[:2] # HWC shape0.append(s) # image shape g = (size / max(s)) # gain shape1.append([y * g for y in s]) + imgs[i] = im # update shape1 = [make_divisible(x, int(self.stride.max())) for x in np.stack(shape1, 0).max(0)] # inference shape - x = [letterbox(imgs[i], new_shape=shape1, auto=False)[0] for i in batch] # pad - x = np.stack(x, 0) if batch[-1] else x[0][None] # stack + x = [letterbox(im, new_shape=shape1, auto=False)[0] for im in imgs] # pad + x = np.stack(x, 0) if n > 1 else x[0][None] # stack x = np.ascontiguousarray(x.transpose((0, 3, 1, 2))) # BHWC to BCHW x = torch.from_numpy(x).to(p.device).type_as(p) / 255. # uint8 to fp16/32 @@ -166,7 +220,7 @@ def forward(self, imgs, size=640, augment=False, profile=False): y = non_max_suppression(y, conf_thres=self.conf, iou_thres=self.iou, classes=self.classes) # NMS # Post-process - for i in batch: + for i in range(n): scale_coords(shape1, y[i][:, :4], shape0[i]) return Detections(imgs, y, self.names) @@ -187,7 +241,7 @@ def __init__(self, imgs, pred, names=None): self.xywhn = [x / g for x, g in zip(self.xywh, gn)] # xywh normalized self.n = len(self.pred) - def display(self, pprint=False, show=False, save=False): + def display(self, pprint=False, show=False, save=False, render=False): colors = color_list() for i, (img, pred) in enumerate(zip(self.imgs, self.pred)): str = f'Image {i + 1}/{len(self.pred)}: {img.shape[0]}x{img.shape[1]} ' @@ -195,19 +249,21 @@ def display(self, pprint=False, show=False, save=False): for c in pred[:, -1].unique(): n = (pred[:, -1] == c).sum() # detections per class str += f'{n} {self.names[int(c)]}s, ' # add to string - if show or save: + if show or save or render: img = Image.fromarray(img.astype(np.uint8)) if isinstance(img, np.ndarray) else img # from np for *box, conf, cls in pred: # xyxy, confidence, class # str += '%s %.2f, ' % (names[int(cls)], conf) # label ImageDraw.Draw(img).rectangle(box, width=4, outline=colors[int(cls) % 10]) # plot + if pprint: + print(str) + if show: + img.show(f'Image {i}') # show if save: f = f'results{i}.jpg' str += f"saved to '{f}'" img.save(f) # save - if show: - img.show(f'Image {i}') # show - if pprint: - print(str) + if render: + self.imgs[i] = np.asarray(img) def print(self): self.display(pprint=True) # print results @@ -218,6 +274,10 @@ def show(self): def save(self): self.display(save=True) # save results + def render(self): + self.display(render=True) # render results + return self.imgs + def __len__(self): return self.n @@ -230,20 +290,13 @@ def tolist(self): return x -class Flatten(nn.Module): - # Use after nn.AdaptiveAvgPool2d(1) to remove last 2 dimensions - @staticmethod - def forward(x): - return x.view(x.size(0), -1) - - class Classify(nn.Module): # Classification head, i.e. x(b,c1,20,20) to x(b,c2) def __init__(self, c1, c2, k=1, s=1, p=None, g=1): # ch_in, ch_out, kernel, stride, padding, groups super(Classify, self).__init__() self.aap = nn.AdaptiveAvgPool2d(1) # to x(b,c1,1,1) self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g) # to x(b,c2,1,1) - self.flat = Flatten() + self.flat = nn.Flatten() def forward(self, x): z = torch.cat([self.aap(y) for y in (x if isinstance(x, list) else [x])], 1) # cat if list diff --git a/models/experimental.py b/models/experimental.py index a2908a15cf..2dbbf7fa32 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -22,25 +22,6 @@ def forward(self, x): return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) -class C3(nn.Module): - # Cross Convolution CSP - def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion - super(C3, self).__init__() - c_ = int(c2 * e) # hidden channels - self.cv1 = Conv(c1, c_, 1, 1) - self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False) - self.cv3 = nn.Conv2d(c_, c_, 1, 1, bias=False) - self.cv4 = Conv(2 * c_, c2, 1, 1) - self.bn = nn.BatchNorm2d(2 * c_) # applied to cat(cv2, cv3) - self.act = nn.LeakyReLU(0.1, inplace=True) - self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)]) - - def forward(self, x): - y1 = self.cv3(self.m(self.cv1(x))) - y2 = self.cv2(x) - return self.cv4(self.act(self.bn(torch.cat((y1, y2), dim=1)))) - - class Sum(nn.Module): # Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 def __init__(self, n, weight=False): # n: number of inputs @@ -124,8 +105,8 @@ def forward(self, x, augment=False): for module in self: y.append(module(x, augment)[0]) # y = torch.stack(y).max(0)[0] # max ensemble - # y = torch.cat(y, 1) # nms ensemble - y = torch.stack(y).mean(0) # mean ensemble + # y = torch.stack(y).mean(0) # mean ensemble + y = torch.cat(y, 1) # nms ensemble return y, None # inference, train output diff --git a/models/export.py b/models/export.py index 7fbc3d9599..49df43e9fe 100644 --- a/models/export.py +++ b/models/export.py @@ -15,7 +15,7 @@ import models from models.experimental import attempt_load -from utils.activations import Hardswish +from utils.activations import Hardswish, SiLU from utils.general import set_logging, check_img_size if __name__ == '__main__': @@ -43,9 +43,12 @@ # Update model for k, m in model.named_modules(): m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility - if isinstance(m, models.common.Conv) and isinstance(m.act, nn.Hardswish): - m.act = Hardswish() # assign activation - # if isinstance(m, models.yolo.Detect): + if isinstance(m, models.common.Conv): # assign export-friendly activations + if isinstance(m.act, nn.Hardswish): + m.act = Hardswish() + elif isinstance(m.act, nn.SiLU): + m.act = SiLU() + # elif isinstance(m, models.yolo.Detect): # m.forward = m.forward_export # assign forward (optional) model.model[-1].export = True # set Detect() layer export=True y = model(img) # dry run diff --git a/models/yolo.py b/models/yolo.py index 7ef9d501eb..9f47100999 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -4,15 +4,11 @@ from copy import deepcopy from pathlib import Path -import math -import torch -import torch.nn as nn - sys.path.append('./') # to run '$ python *.py' files in subdirectories logger = logging.getLogger(__name__) -from models.common import Conv, Bottleneck, SPP, DWConv, Focus, BottleneckCSP, Concat, NMS, autoShape -from models.experimental import MixConv2d, CrossConv, C3 +from models.common import * +from models.experimental import MixConv2d, CrossConv from utils.autoanchor import check_anchor_order from utils.general import make_divisible, check_file, set_logging from utils.torch_utils import time_synchronized, fuse_conv_and_bn, model_info, scale_img, initialize_weights, \ @@ -78,17 +74,18 @@ def __init__(self, cfg='yolov3.yaml', ch=3, nc=None): # model, input channels, self.yaml = yaml.load(f, Loader=yaml.FullLoader) # model dict # Define model + ch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channels if nc and nc != self.yaml['nc']: logger.info('Overriding model.yaml nc=%g with nc=%g' % (self.yaml['nc'], nc)) self.yaml['nc'] = nc # override yaml value - self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelist, ch_out + self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelist self.names = [str(i) for i in range(self.yaml['nc'])] # default names # print([x.shape for x in self.forward(torch.zeros(1, ch, 64, 64))]) # Build strides, anchors m = self.model[-1] # Detect() if isinstance(m, Detect): - s = 128 # 2x min stride + s = 256 # 2x min stride m.stride = torch.tensor([s / x.shape[-2] for x in self.forward(torch.zeros(1, ch, s, s))]) # forward m.anchors /= m.stride.view(-1, 1, 1) check_anchor_order(m) @@ -108,7 +105,7 @@ def forward(self, x, augment=False, profile=False): f = [None, 3, None] # flips (2-ud, 3-lr) y = [] # outputs for si, fi in zip(s, f): - xi = scale_img(x.flip(fi) if fi else x, si) + xi = scale_img(x.flip(fi) if fi else x, si, gs=int(self.stride.max())) yi = self.forward_once(xi)[0] # forward # cv2.imwrite('img%g.jpg' % s, 255 * xi[0].numpy().transpose((1, 2, 0))[:, :, ::-1]) # save yi[..., :4] /= si # de-scale @@ -241,13 +238,17 @@ def parse_model(d, ch): # model_dict, input_channels(3) elif m is nn.BatchNorm2d: args = [ch[f]] elif m is Concat: - c2 = sum([ch[-1 if x == -1 else x + 1] for x in f]) + c2 = sum([ch[x if x < 0 else x + 1] for x in f]) elif m is Detect: args.append([ch[x + 1] for x in f]) if isinstance(args[1], int): # number of anchors args[1] = [list(range(args[1] * 2))] * len(f) + elif m is Contract: + c2 = ch[f if f < 0 else f + 1] * args[0] ** 2 + elif m is Expand: + c2 = ch[f if f < 0 else f + 1] // args[0] ** 2 else: - c2 = ch[f] + c2 = ch[f if f < 0 else f + 1] m_ = nn.Sequential(*[m(*args) for _ in range(n)]) if n > 1 else m(*args) # module t = str(m)[8:-2].replace('__main__.', '') # module type diff --git a/requirements.txt b/requirements.txt index 4cb16138a0..3c23f2b750 100755 --- a/requirements.txt +++ b/requirements.txt @@ -17,7 +17,7 @@ tqdm>=4.41.0 # wandb # plotting ------------------------------------ -seaborn +seaborn>=0.11.0 pandas # export -------------------------------------- diff --git a/test.py b/test.py index 5c8a70b93a..c570a7889a 100644 --- a/test.py +++ b/test.py @@ -11,8 +11,8 @@ from models.experimental import attempt_load from utils.datasets import create_dataloader -from utils.general import coco80_to_coco91_class, check_dataset, check_file, check_img_size, box_iou, \ - non_max_suppression, scale_coords, xyxy2xywh, xywh2xyxy, set_logging, increment_path +from utils.general import coco80_to_coco91_class, check_dataset, check_file, check_img_size, check_requirements, \ + box_iou, non_max_suppression, scale_coords, xyxy2xywh, xywh2xyxy, set_logging, increment_path, colorstr from utils.loss import compute_loss from utils.metrics import ap_per_class, ConfusionMatrix from utils.plots import plot_images, output_to_target, plot_study_txt @@ -86,7 +86,8 @@ def test(data, img = torch.zeros((1, 3, imgsz, imgsz), device=device) # init img _ = model(img.half() if half else img) if device.type != 'cpu' else None # run once path = data['test'] if opt.task == 'test' else data['val'] # path to val/test images - dataloader = create_dataloader(path, imgsz, batch_size, model.stride.max(), opt, pad=0.5, rect=True)[0] + dataloader = create_dataloader(path, imgsz, batch_size, model.stride.max(), opt, pad=0.5, rect=True, + prefix=colorstr('test: ' if opt.task == 'test' else 'val: '))[0] seen = 0 confusion_matrix = ConfusionMatrix(nc=nc) @@ -226,7 +227,7 @@ def test(data, print(pf % ('all', seen, nt.sum(), mp, mr, map50, map)) # Print results per class - if verbose and nc > 1 and len(stats): + if (verbose or (nc <= 20 and not training)) and nc > 1 and len(stats): for i, c in enumerate(ap_class): print(pf % (names[c], seen, nt[c], p[i], r[i], ap50[i], ap[i])) @@ -302,6 +303,7 @@ def test(data, opt.save_json |= opt.data.endswith('coco.yaml') opt.data = check_file(opt.data) # check file print(opt) + check_requirements() if opt.task in ['val', 'test']: # run normally test(opt.data, diff --git a/train.py b/train.py index 91c8084fea..9f869cfd92 100644 --- a/train.py +++ b/train.py @@ -1,13 +1,12 @@ import argparse import logging +import math import os import random import time from pathlib import Path from threading import Thread -from warnings import warn -import math import numpy as np import torch.distributed as dist import torch.nn as nn @@ -28,7 +27,7 @@ from utils.datasets import create_dataloader from utils.general import labels_to_class_weights, increment_path, labels_to_image_weights, init_seeds, \ fitness, strip_optimizer, get_latest_run, check_dataset, check_file, check_git_status, check_img_size, \ - print_mutation, set_logging + check_requirements, print_mutation, set_logging, one_cycle, colorstr from utils.google_utils import attempt_download from utils.loss import compute_loss from utils.plots import plot_images, plot_labels, plot_results, plot_evolution @@ -36,15 +35,9 @@ logger = logging.getLogger(__name__) -try: - import wandb -except ImportError: - wandb = None - logger.info("Install Weights & Biases for experiment logging via 'pip install wandb' (recommended)") - def train(hyp, opt, device, tb_writer=None, wandb=None): - logger.info(f'Hyperparameters {hyp}') + logger.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) save_dir, epochs, batch_size, total_batch_size, weights, rank = \ Path(opt.save_dir), opt.epochs, opt.batch_size, opt.total_batch_size, opt.weights, opt.global_rank @@ -71,7 +64,8 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): check_dataset(data_dict) # check train_path = data_dict['train'] test_path = data_dict['val'] - nc, names = (1, ['item']) if opt.single_cls else (int(data_dict['nc']), data_dict['names']) # number classes, names + nc = 1 if opt.single_cls else int(data_dict['nc']) # number of classes + names = ['item'] if opt.single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names assert len(names) == nc, '%g names found for nc=%g dataset in %s' % (len(names), nc, opt.data) # check # Model @@ -103,6 +97,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): nbs = 64 # nominal batch size accumulate = max(round(nbs / total_batch_size), 1) # accumulate loss before optimizing hyp['weight_decay'] *= total_batch_size * accumulate / nbs # scale weight_decay + logger.info(f"Scaled weight_decay = {hyp['weight_decay']}") pg0, pg1, pg2 = [], [], [] # optimizer parameter groups for k, v in model.named_modules(): @@ -125,12 +120,12 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): # Scheduler https://arxiv.org/pdf/1812.01187.pdf # https://pytorch.org/docs/stable/_modules/torch/optim/lr_scheduler.html#OneCycleLR - lf = lambda x: ((1 + math.cos(x * math.pi / epochs)) / 2) * (1 - hyp['lrf']) + hyp['lrf'] # cosine + lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) # Logging - if wandb and wandb.run is None: + if rank in [-1, 0] and wandb and wandb.run is None: opt.hyp = hyp # add hyperparameters wandb_run = wandb.init(config=opt, resume="allow", project='YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem, @@ -163,7 +158,8 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): del ckpt, state_dict # Image sizes - gs = int(max(model.stride)) # grid size (max stride) + gs = int(model.stride.max()) # grid size (max stride) + nl = model.model[-1].nl # number of detection layers (used for scaling hyp['obj']) imgsz, imgsz_test = [check_img_size(x, gs) for x in opt.img_size] # verify imgsz are gs-multiples # DP mode @@ -186,7 +182,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): dataloader, dataset = create_dataloader(train_path, imgsz, batch_size, gs, opt, hyp=hyp, augment=True, cache=opt.cache_images, rect=opt.rect, rank=rank, world_size=opt.world_size, workers=opt.workers, - image_weights=opt.image_weights) + image_weights=opt.image_weights, quad=opt.quad, prefix=colorstr('train: ')) mlc = np.concatenate(dataset.labels, 0)[:, 0].max() # max label class nb = len(dataloader) # number of batches assert mlc < nc, 'Label class %g exceeds nc=%g in %s. Possible class labels are 0-%g' % (mlc, nc, opt.data, nc - 1) @@ -195,8 +191,9 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): if rank in [-1, 0]: ema.updates = start_epoch * nb // accumulate # set EMA updates testloader = create_dataloader(test_path, imgsz_test, total_batch_size, gs, opt, # testloader - hyp=hyp, cache=opt.cache_images and not opt.notest, rect=True, - rank=-1, world_size=opt.world_size, workers=opt.workers, pad=0.5)[0] + hyp=hyp, cache=opt.cache_images and not opt.notest, rect=True, rank=-1, + world_size=opt.world_size, workers=opt.workers, + pad=0.5, prefix=colorstr('val: '))[0] if not opt.resume: labels = np.concatenate(dataset.labels, 0) @@ -204,7 +201,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): # cf = torch.bincount(c.long(), minlength=nc) + 1. # frequency # model._initialize_biases(cf.to(device)) if plots: - Thread(target=plot_labels, args=(labels, save_dir, loggers), daemon=True).start() + plot_labels(labels, save_dir, loggers) if tb_writer: tb_writer.add_histogram('classes', c, 0) @@ -213,11 +210,13 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) # Model parameters - hyp['cls'] *= nc / 80. # scale coco-tuned hyp['cls'] to current dataset + hyp['box'] *= 3. / nl # scale to layers + hyp['cls'] *= nc / 80. * 3. / nl # scale to classes and layers + hyp['obj'] *= (imgsz / 640) ** 2 * 3. / nl # scale to image size and layers model.nc = nc # attach number of classes to model model.hyp = hyp # attach hyperparameters to model model.gr = 1.0 # iou loss ratio (obj_loss = 1.0 or iou) - model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) # attach class weights + model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights model.names = names # Start training @@ -228,9 +227,10 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): results = (0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) scheduler.last_epoch = start_epoch - 1 # do not move scaler = amp.GradScaler(enabled=cuda) - logger.info('Image sizes %g train, %g test\n' - 'Using %g dataloader workers\nLogging results to %s\n' - 'Starting training for %g epochs...' % (imgsz, imgsz_test, dataloader.num_workers, save_dir, epochs)) + logger.info(f'Image sizes {imgsz} train, {imgsz_test} test\n' + f'Using {dataloader.num_workers} dataloader workers\n' + f'Logging results to {save_dir}\n' + f'Starting training for {epochs} epochs...') for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ model.train() @@ -238,7 +238,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): if opt.image_weights: # Generate indices if rank in [-1, 0]: - cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 # class weights + cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc # class weights iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx # Broadcast if DDP @@ -289,6 +289,8 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): loss, loss_items = compute_loss(pred, targets.to(device), model) # loss scaled by batch_size if rank != -1: loss *= opt.world_size # gradient averaged between devices in DDP mode + if opt.quad: + loss *= 4. # Backward scaler.scale(loss).backward() @@ -330,7 +332,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): if rank in [-1, 0]: # mAP if ema: - ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'gr', 'names', 'stride']) + ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'gr', 'names', 'stride', 'class_weights']) final_epoch = epoch + 1 == epochs if not opt.notest or final_epoch: # Calculate mAP results, maps, times = test.test(opt.data, @@ -386,10 +388,12 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): if rank in [-1, 0]: # Strip optimizers + final = best if best.exists() else last # final model for f in [last, best]: - if f.exists(): # is *.pt - strip_optimizer(f) # strip optimizer - os.system('gsutil cp %s gs://%s/weights' % (f, opt.bucket)) if opt.bucket else None # upload + if f.exists(): + strip_optimizer(f) # strip optimizers + if opt.bucket: + os.system(f'gsutil cp {final} gs://{opt.bucket}/weights') # upload # Plots if plots: @@ -398,19 +402,24 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): files = ['results.png', 'precision_recall_curve.png', 'confusion_matrix.png'] wandb.log({"Results": [wandb.Image(str(save_dir / f), caption=f) for f in files if (save_dir / f).exists()]}) - logger.info('%g epochs completed in %.3f hours.\n' % (epoch - start_epoch + 1, (time.time() - t0) / 3600)) + if opt.log_artifacts: + wandb.log_artifact(artifact_or_path=str(final), type='model', name=save_dir.stem) # Test best.pt + logger.info('%g epochs completed in %.3f hours.\n' % (epoch - start_epoch + 1, (time.time() - t0) / 3600)) if opt.data.endswith('coco.yaml') and nc == 80: # if COCO - results, _, _ = test.test(opt.data, - batch_size=total_batch_size, - imgsz=imgsz_test, - model=attempt_load(best if best.exists() else last, device).half(), - single_cls=opt.single_cls, - dataloader=testloader, - save_dir=save_dir, - save_json=True, # use pycocotools - plots=False) + for conf, iou, save_json in ([0.25, 0.45, False], [0.001, 0.65, True]): # speed, mAP tests + results, _, _ = test.test(opt.data, + batch_size=total_batch_size, + imgsz=imgsz_test, + conf_thres=conf, + iou_thres=iou, + model=attempt_load(final, device).half(), + single_cls=opt.single_cls, + dataloader=testloader, + save_dir=save_dir, + save_json=save_json, + plots=False) else: dist.destroy_process_group() @@ -440,32 +449,35 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') - parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') + parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer') parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') parser.add_argument('--log-imgs', type=int, default=16, help='number of images for W&B logging, max 100') + parser.add_argument('--log-artifacts', action='store_true', help='log artifacts, i.e. final trained model') parser.add_argument('--workers', type=int, default=8, help='maximum number of dataloader workers') parser.add_argument('--project', default='runs/train', help='save to project/name') parser.add_argument('--name', default='exp', help='save to project/name') parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--quad', action='store_true', help='quad dataloader') opt = parser.parse_args() # Set DDP variables - opt.total_batch_size = opt.batch_size opt.world_size = int(os.environ['WORLD_SIZE']) if 'WORLD_SIZE' in os.environ else 1 opt.global_rank = int(os.environ['RANK']) if 'RANK' in os.environ else -1 set_logging(opt.global_rank) if opt.global_rank in [-1, 0]: check_git_status() + check_requirements() # Resume if opt.resume: # resume an interrupted run ckpt = opt.resume if isinstance(opt.resume, str) else get_latest_run() # specified or most recent path assert os.path.isfile(ckpt), 'ERROR: --resume checkpoint does not exist' + apriori = opt.global_rank, opt.local_rank with open(Path(ckpt).parent.parent / 'opt.yaml') as f: opt = argparse.Namespace(**yaml.load(f, Loader=yaml.FullLoader)) # replace - opt.cfg, opt.weights, opt.resume = '', ckpt, True + opt.cfg, opt.weights, opt.resume, opt.global_rank, opt.local_rank = '', ckpt, True, *apriori # reinstate logger.info('Resuming training from %s' % ckpt) else: # opt.hyp = opt.hyp or ('hyp.finetune.yaml' if opt.weights else 'hyp.scratch.yaml') @@ -476,6 +488,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): opt.save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok | opt.evolve) # increment run # DDP mode + opt.total_batch_size = opt.batch_size device = select_device(opt.device, batch_size=opt.batch_size) if opt.local_rank != -1: assert torch.cuda.device_count() > opt.local_rank @@ -488,13 +501,15 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): # Hyperparameters with open(opt.hyp) as f: hyp = yaml.load(f, Loader=yaml.FullLoader) # load hyps - if 'box' not in hyp: - warn('Compatibility: %s missing "box" which was renamed from "giou" in %s' % - (opt.hyp, 'https://github.com/ultralytics/yolov5/pull/1120')) - hyp['box'] = hyp.pop('giou') # Train logger.info(opt) + try: + import wandb + except ImportError: + wandb = None + prefix = colorstr('wandb: ') + logger.info(f"{prefix}Install Weights & Biases for YOLOv3 logging with 'pip install wandb' (recommended)") if not opt.evolve: tb_writer = None # init loggers if opt.global_rank in [-1, 0]: diff --git a/utils/activations.py b/utils/activations.py index 24f5a30f02..aa3ddf071d 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -5,8 +5,8 @@ import torch.nn.functional as F -# Swish https://arxiv.org/pdf/1905.02244.pdf --------------------------------------------------------------------------- -class Swish(nn.Module): # +# SiLU https://arxiv.org/pdf/1606.08415.pdf ---------------------------------------------------------------------------- +class SiLU(nn.Module): # export-friendly version of nn.SiLU() @staticmethod def forward(x): return x * torch.sigmoid(x) diff --git a/utils/autoanchor.py b/utils/autoanchor.py index 98fea9981f..c6e6b9daf5 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -6,6 +6,8 @@ from scipy.cluster.vq import kmeans from tqdm import tqdm +from utils.general import colorstr + def check_anchor_order(m): # Check anchor order against stride order for YOLOv3 Detect() module m, and correct if necessary @@ -20,7 +22,8 @@ def check_anchor_order(m): def check_anchors(dataset, model, thr=4.0, imgsz=640): # Check anchor fit to data, recompute if necessary - print('\nAnalyzing anchors... ', end='') + prefix = colorstr('autoanchor: ') + print(f'\n{prefix}Analyzing anchors... ', end='') m = model.module.model[-1] if hasattr(model, 'module') else model.model[-1] # Detect() shapes = imgsz * dataset.shapes / dataset.shapes.max(1, keepdims=True) scale = np.random.uniform(0.9, 1.1, size=(shapes.shape[0], 1)) # augment scale @@ -35,7 +38,7 @@ def metric(k): # compute metric return bpr, aat bpr, aat = metric(m.anchor_grid.clone().cpu().view(-1, 2)) - print('anchors/target = %.2f, Best Possible Recall (BPR) = %.4f' % (aat, bpr), end='') + print(f'anchors/target = {aat:.2f}, Best Possible Recall (BPR) = {bpr:.4f}', end='') if bpr < 0.98: # threshold to recompute print('. Attempting to improve anchors, please wait...') na = m.anchor_grid.numel() // 2 # number of anchors @@ -46,9 +49,9 @@ def metric(k): # compute metric m.anchor_grid[:] = new_anchors.clone().view_as(m.anchor_grid) # for inference m.anchors[:] = new_anchors.clone().view_as(m.anchors) / m.stride.to(m.anchors.device).view(-1, 1, 1) # loss check_anchor_order(m) - print('New anchors saved to model. Update model *.yaml to use these anchors in the future.') + print(f'{prefix}New anchors saved to model. Update model *.yaml to use these anchors in the future.') else: - print('Original anchors better than new anchors. Proceeding with original anchors.') + print(f'{prefix}Original anchors better than new anchors. Proceeding with original anchors.') print('') # newline @@ -70,6 +73,7 @@ def kmean_anchors(path='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=10 from utils.autoanchor import *; _ = kmean_anchors() """ thr = 1. / thr + prefix = colorstr('autoanchor: ') def metric(k, wh): # compute metrics r = wh[:, None] / k[None] @@ -85,9 +89,9 @@ def print_results(k): k = k[np.argsort(k.prod(1))] # sort small to large x, best = metric(k, wh0) bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr - print('thr=%.2f: %.4f best possible recall, %.2f anchors past thr' % (thr, bpr, aat)) - print('n=%g, img_size=%s, metric_all=%.3f/%.3f-mean/best, past_thr=%.3f-mean: ' % - (n, img_size, x.mean(), best.mean(), x[x > thr].mean()), end='') + print(f'{prefix}thr={thr:.2f}: {bpr:.4f} best possible recall, {aat:.2f} anchors past thr') + print(f'{prefix}n={n}, img_size={img_size}, metric_all={x.mean():.3f}/{best.mean():.3f}-mean/best, ' + f'past_thr={x[x > thr].mean():.3f}-mean: ', end='') for i, x in enumerate(k): print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg return k @@ -107,12 +111,12 @@ def print_results(k): # Filter i = (wh0 < 3.0).any(1).sum() if i: - print('WARNING: Extremely small objects found. ' - '%g of %g labels are < 3 pixels in width or height.' % (i, len(wh0))) + print(f'{prefix}WARNING: Extremely small objects found. {i} of {len(wh0)} labels are < 3 pixels in size.') wh = wh0[(wh0 >= 2.0).any(1)] # filter > 2 pixels + # wh = wh * (np.random.rand(wh.shape[0], 1) * 0.9 + 0.1) # multiply by random scale 0-1 # Kmeans calculation - print('Running kmeans for %g anchors on %g points...' % (n, len(wh))) + print(f'{prefix}Running kmeans for {n} anchors on {len(wh)} points...') s = wh.std(0) # sigmas for whitening k, dist = kmeans(wh / s, n, iter=30) # points, mean distance k *= s @@ -135,7 +139,7 @@ def print_results(k): # Evolve npr = np.random f, sh, mp, s = anchor_fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma - pbar = tqdm(range(gen), desc='Evolving anchors with Genetic Algorithm') # progress bar + pbar = tqdm(range(gen), desc=f'{prefix}Evolving anchors with Genetic Algorithm:') # progress bar for _ in pbar: v = np.ones(sh) while (v == 1).all(): # mutate until a change occurs (prevent duplicates) @@ -144,7 +148,7 @@ def print_results(k): fg = anchor_fitness(kg) if fg > f: f, k = fg, kg.copy() - pbar.desc = 'Evolving anchors with Genetic Algorithm: fitness = %.4f' % f + pbar.desc = f'{prefix}Evolving anchors with Genetic Algorithm: fitness = {f:.4f}' if verbose: print_results(k) diff --git a/utils/datasets.py b/utils/datasets.py index 4b87004523..d2002fabfc 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -15,11 +15,12 @@ import cv2 import numpy as np import torch +import torch.nn.functional as F from PIL import Image, ExifTags from torch.utils.data import Dataset from tqdm import tqdm -from utils.general import xyxy2xywh, xywh2xyxy +from utils.general import xyxy2xywh, xywh2xyxy, clean_str from utils.torch_utils import torch_distributed_zero_first # Parameters @@ -55,7 +56,7 @@ def exif_size(img): def create_dataloader(path, imgsz, batch_size, stride, opt, hyp=None, augment=False, cache=False, pad=0.0, rect=False, - rank=-1, world_size=1, workers=8, image_weights=False): + rank=-1, world_size=1, workers=8, image_weights=False, quad=False, prefix=''): # Make sure only the first process in DDP process the dataset first, and the following others can use the cache with torch_distributed_zero_first(rank): dataset = LoadImagesAndLabels(path, imgsz, batch_size, @@ -66,8 +67,8 @@ def create_dataloader(path, imgsz, batch_size, stride, opt, hyp=None, augment=Fa single_cls=opt.single_cls, stride=int(stride), pad=pad, - rank=rank, - image_weights=image_weights) + image_weights=image_weights, + prefix=prefix) batch_size = min(batch_size, len(dataset)) nw = min([os.cpu_count() // world_size, batch_size if batch_size > 1 else 0, workers]) # number of workers @@ -79,7 +80,7 @@ def create_dataloader(path, imgsz, batch_size, stride, opt, hyp=None, augment=Fa num_workers=nw, sampler=sampler, pin_memory=True, - collate_fn=LoadImagesAndLabels.collate_fn) + collate_fn=LoadImagesAndLabels.collate_fn4 if quad else LoadImagesAndLabels.collate_fn) return dataloader, dataset @@ -128,7 +129,7 @@ def __init__(self, path, img_size=640): elif os.path.isfile(p): files = [p] # files else: - raise Exception('ERROR: %s does not exist' % p) + raise Exception(f'ERROR: {p} does not exist') images = [x for x in files if x.split('.')[-1].lower() in img_formats] videos = [x for x in files if x.split('.')[-1].lower() in vid_formats] @@ -138,13 +139,13 @@ def __init__(self, path, img_size=640): self.files = images + videos self.nf = ni + nv # number of files self.video_flag = [False] * ni + [True] * nv - self.mode = 'images' + self.mode = 'image' if any(videos): self.new_video(videos[0]) # new video else: self.cap = None - assert self.nf > 0, 'No images or videos found in %s. Supported formats are:\nimages: %s\nvideos: %s' % \ - (p, img_formats, vid_formats) + assert self.nf > 0, f'No images or videos found in {p}. ' \ + f'Supported formats are:\nimages: {img_formats}\nvideos: {vid_formats}' def __iter__(self): self.count = 0 @@ -170,14 +171,14 @@ def __next__(self): ret_val, img0 = self.cap.read() self.frame += 1 - print('video %g/%g (%g/%g) %s: ' % (self.count + 1, self.nf, self.frame, self.nframes, path), end='') + print(f'video {self.count + 1}/{self.nf} ({self.frame}/{self.nframes}) {path}: ', end='') else: # Read image self.count += 1 img0 = cv2.imread(path) # BGR assert img0 is not None, 'Image Not Found ' + path - print('image %g/%g %s: ' % (self.count, self.nf, path), end='') + print(f'image {self.count}/{self.nf} {path}: ', end='') # Padded resize img = letterbox(img0, new_shape=self.img_size)[0] @@ -237,9 +238,9 @@ def __next__(self): break # Print - assert ret_val, 'Camera Error %s' % self.pipe + assert ret_val, f'Camera Error {self.pipe}' img_path = 'webcam.jpg' - print('webcam %g: ' % self.count, end='') + print(f'webcam {self.count}: ', end='') # Padded resize img = letterbox(img0, new_shape=self.img_size)[0] @@ -256,7 +257,7 @@ def __len__(self): class LoadStreams: # multiple IP or RTSP cameras def __init__(self, sources='streams.txt', img_size=640): - self.mode = 'images' + self.mode = 'stream' self.img_size = img_size if os.path.isfile(sources): @@ -267,18 +268,18 @@ def __init__(self, sources='streams.txt', img_size=640): n = len(sources) self.imgs = [None] * n - self.sources = sources + self.sources = [clean_str(x) for x in sources] # clean source names for later for i, s in enumerate(sources): # Start the thread to read frames from the video stream - print('%g/%g: %s... ' % (i + 1, n, s), end='') + print(f'{i + 1}/{n}: {s}... ', end='') cap = cv2.VideoCapture(eval(s) if s.isnumeric() else s) - assert cap.isOpened(), 'Failed to open %s' % s + assert cap.isOpened(), f'Failed to open {s}' w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps = cap.get(cv2.CAP_PROP_FPS) % 100 _, self.imgs[i] = cap.read() # guarantee first frame thread = Thread(target=self.update, args=([i, cap]), daemon=True) - print(' success (%gx%g at %.2f FPS).' % (w, h, fps)) + print(f' success ({w}x{h} at {fps:.2f} FPS).') thread.start() print('') # newline @@ -335,7 +336,7 @@ def img2label_paths(img_paths): class LoadImagesAndLabels(Dataset): # for training/testing def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, - cache_images=False, single_cls=False, stride=32, pad=0.0, rank=-1): + cache_images=False, single_cls=False, stride=32, pad=0.0, prefix=''): self.img_size = img_size self.augment = augment self.hyp = hyp @@ -357,11 +358,11 @@ def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, r parent = str(p.parent) + os.sep f += [x.replace('./', parent) if x.startswith('./') else x for x in t] # local to global path else: - raise Exception('%s does not exist' % p) + raise Exception(f'{prefix}{p} does not exist') self.img_files = sorted([x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in img_formats]) - assert self.img_files, 'No images found' + assert self.img_files, f'{prefix}No images found' except Exception as e: - raise Exception('Error loading data from %s: %s\nSee %s' % (path, e, help_url)) + raise Exception(f'{prefix}Error loading data from {path}: {e}\nSee {help_url}') # Check cache self.label_files = img2label_paths(self.img_files) # labels @@ -369,15 +370,15 @@ def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, r if cache_path.is_file(): cache = torch.load(cache_path) # load if cache['hash'] != get_hash(self.label_files + self.img_files) or 'results' not in cache: # changed - cache = self.cache_labels(cache_path) # re-cache + cache = self.cache_labels(cache_path, prefix) # re-cache else: - cache = self.cache_labels(cache_path) # cache + cache = self.cache_labels(cache_path, prefix) # cache # Display cache [nf, nm, ne, nc, n] = cache.pop('results') # found, missing, empty, corrupted, total desc = f"Scanning '{cache_path}' for images and labels... {nf} found, {nm} missing, {ne} empty, {nc} corrupted" - tqdm(None, desc=desc, total=n, initial=n) - assert nf > 0 or not augment, f'No labels found in {cache_path}. Can not train without labels. See {help_url}' + tqdm(None, desc=prefix + desc, total=n, initial=n) + assert nf > 0 or not augment, f'{prefix}No labels in {cache_path}. Can not train without labels. See {help_url}' # Read cache cache.pop('hash') # remove hash @@ -431,9 +432,9 @@ def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, r for i, x in pbar: self.imgs[i], self.img_hw0[i], self.img_hw[i] = x # img, hw_original, hw_resized = load_image(self, i) gb += self.imgs[i].nbytes - pbar.desc = 'Caching images (%.1fGB)' % (gb / 1E9) + pbar.desc = f'{prefix}Caching images ({gb / 1E9:.1f}GB)' - def cache_labels(self, path=Path('./labels.cache')): + def cache_labels(self, path=Path('./labels.cache'), prefix=''): # Cache dataset labels, check images and read shapes x = {} # dict nm, nf, ne, nc = 0, 0, 0, 0 # number missing, found, empty, duplicate @@ -465,18 +466,18 @@ def cache_labels(self, path=Path('./labels.cache')): x[im_file] = [l, shape] except Exception as e: nc += 1 - print('WARNING: Ignoring corrupted image and/or label %s: %s' % (im_file, e)) + print(f'{prefix}WARNING: Ignoring corrupted image and/or label {im_file}: {e}') - pbar.desc = f"Scanning '{path.parent / path.stem}' for images and labels... " \ + pbar.desc = f"{prefix}Scanning '{path.parent / path.stem}' for images and labels... " \ f"{nf} found, {nm} missing, {ne} empty, {nc} corrupted" if nf == 0: - print(f'WARNING: No labels found in {path}. See {help_url}') + print(f'{prefix}WARNING: No labels found in {path}. See {help_url}') x['hash'] = get_hash(self.label_files + self.img_files) x['results'] = [nf, nm, ne, nc, i + 1] torch.save(x, path) # save for next time - logging.info(f"New cache created: {path}") + logging.info(f'{prefix}New cache created: {path}') return x def __len__(self): @@ -578,6 +579,32 @@ def collate_fn(batch): l[:, 0] = i # add target image index for build_targets() return torch.stack(img, 0), torch.cat(label, 0), path, shapes + @staticmethod + def collate_fn4(batch): + img, label, path, shapes = zip(*batch) # transposed + n = len(shapes) // 4 + img4, label4, path4, shapes4 = [], [], path[:n], shapes[:n] + + ho = torch.tensor([[0., 0, 0, 1, 0, 0]]) + wo = torch.tensor([[0., 0, 1, 0, 0, 0]]) + s = torch.tensor([[1, 1, .5, .5, .5, .5]]) # scale + for i in range(n): # zidane torch.zeros(16,3,720,1280) # BCHW + i *= 4 + if random.random() < 0.5: + im = F.interpolate(img[i].unsqueeze(0).float(), scale_factor=2., mode='bilinear', align_corners=False)[ + 0].type(img[i].type()) + l = label[i] + else: + im = torch.cat((torch.cat((img[i], img[i + 1]), 1), torch.cat((img[i + 2], img[i + 3]), 1)), 2) + l = torch.cat((label[i], label[i + 1] + ho, label[i + 2] + wo, label[i + 3] + ho + wo), 0) * s + img4.append(im) + label4.append(l) + + for i, l in enumerate(label4): + l[:, 0] = i # add target image index for build_targets() + + return torch.stack(img4, 0), torch.cat(label4, 0), path4, shapes4 + # Ancillary functions -------------------------------------------------------------------------------------------------- def load_image(self, index): @@ -617,7 +644,7 @@ def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5): def load_mosaic(self, index): - # loads images in a mosaic + # loads images in a 4-mosaic labels4 = [] s = self.img_size @@ -674,6 +701,80 @@ def load_mosaic(self, index): return img4, labels4 +def load_mosaic9(self, index): + # loads images in a 9-mosaic + + labels9 = [] + s = self.img_size + indices = [index] + [self.indices[random.randint(0, self.n - 1)] for _ in range(8)] # 8 additional image indices + for i, index in enumerate(indices): + # Load image + img, _, (h, w) = load_image(self, index) + + # place img in img9 + if i == 0: # center + img9 = np.full((s * 3, s * 3, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles + h0, w0 = h, w + c = s, s, s + w, s + h # xmin, ymin, xmax, ymax (base) coordinates + elif i == 1: # top + c = s, s - h, s + w, s + elif i == 2: # top right + c = s + wp, s - h, s + wp + w, s + elif i == 3: # right + c = s + w0, s, s + w0 + w, s + h + elif i == 4: # bottom right + c = s + w0, s + hp, s + w0 + w, s + hp + h + elif i == 5: # bottom + c = s + w0 - w, s + h0, s + w0, s + h0 + h + elif i == 6: # bottom left + c = s + w0 - wp - w, s + h0, s + w0 - wp, s + h0 + h + elif i == 7: # left + c = s - w, s + h0 - h, s, s + h0 + elif i == 8: # top left + c = s - w, s + h0 - hp - h, s, s + h0 - hp + + padx, pady = c[:2] + x1, y1, x2, y2 = [max(x, 0) for x in c] # allocate coords + + # Labels + x = self.labels[index] + labels = x.copy() + if x.size > 0: # Normalized xywh to pixel xyxy format + labels[:, 1] = w * (x[:, 1] - x[:, 3] / 2) + padx + labels[:, 2] = h * (x[:, 2] - x[:, 4] / 2) + pady + labels[:, 3] = w * (x[:, 1] + x[:, 3] / 2) + padx + labels[:, 4] = h * (x[:, 2] + x[:, 4] / 2) + pady + labels9.append(labels) + + # Image + img9[y1:y2, x1:x2] = img[y1 - pady:, x1 - padx:] # img9[ymin:ymax, xmin:xmax] + hp, wp = h, w # height, width previous + + # Offset + yc, xc = [int(random.uniform(0, s)) for x in self.mosaic_border] # mosaic center x, y + img9 = img9[yc:yc + 2 * s, xc:xc + 2 * s] + + # Concat/clip labels + if len(labels9): + labels9 = np.concatenate(labels9, 0) + labels9[:, [1, 3]] -= xc + labels9[:, [2, 4]] -= yc + + np.clip(labels9[:, 1:], 0, 2 * s, out=labels9[:, 1:]) # use with random_perspective + # img9, labels9 = replicate(img9, labels9) # replicate + + # Augment + img9, labels9 = random_perspective(img9, labels9, + degrees=self.hyp['degrees'], + translate=self.hyp['translate'], + scale=self.hyp['scale'], + shear=self.hyp['shear'], + perspective=self.hyp['perspective'], + border=self.mosaic_border) # border to remove + + return img9, labels9 + + def replicate(img, labels): # Replicate labels h, w = img.shape[:2] @@ -811,12 +912,12 @@ def random_perspective(img, targets=(), degrees=10, translate=.1, scale=.1, shea return img, targets -def box_candidates(box1, box2, wh_thr=2, ar_thr=20, area_thr=0.1): # box1(4,n), box2(4,n) +def box_candidates(box1, box2, wh_thr=2, ar_thr=20, area_thr=0.1, eps=1e-16): # box1(4,n), box2(4,n) # Compute candidate boxes: box1 before augment, box2 after augment, wh_thr (pixels), aspect_ratio_thr, area_ratio w1, h1 = box1[2] - box1[0], box1[3] - box1[1] w2, h2 = box2[2] - box2[0], box2[3] - box2[1] - ar = np.maximum(w2 / (h2 + 1e-16), h2 / (w2 + 1e-16)) # aspect ratio - return (w2 > wh_thr) & (h2 > wh_thr) & (w2 * h2 / (w1 * h1 + 1e-16) > area_thr) & (ar < ar_thr) # candidates + ar = np.maximum(w2 / (h2 + eps), h2 / (w2 + eps)) # aspect ratio + return (w2 > wh_thr) & (h2 > wh_thr) & (w2 * h2 / (w1 * h1 + eps) > area_thr) & (ar < ar_thr) # candidates def cutout(image, labels): diff --git a/utils/general.py b/utils/general.py index 22647f6cd2..5126a45ac0 100755 --- a/utils/general.py +++ b/utils/general.py @@ -2,8 +2,8 @@ import glob import logging +import math import os -import platform import random import re import subprocess @@ -11,7 +11,6 @@ from pathlib import Path import cv2 -import math import numpy as np import torch import torchvision @@ -25,6 +24,7 @@ torch.set_printoptions(linewidth=320, precision=5, profile='long') np.set_printoptions(linewidth=320, formatter={'float_kind': '{:11.5g}'.format}) # format short g, %precision=5 cv2.setNumThreads(0) # prevent OpenCV from multithreading (incompatible with PyTorch DataLoader) +os.environ['NUMEXPR_MAX_THREADS'] = str(min(os.cpu_count(), 8)) # NumExpr max threads def set_logging(rank=-1): @@ -34,6 +34,7 @@ def set_logging(rank=-1): def init_seeds(seed=0): + # Initialize random number generator (RNG) seeds random.seed(seed) np.random.seed(seed) init_torch_seeds(seed) @@ -45,12 +46,41 @@ def get_latest_run(search_dir='.'): return max(last_list, key=os.path.getctime) if last_list else '' +def check_online(): + # Check internet connectivity + import socket + try: + socket.create_connection(("1.1.1.1", 53)) # check host accesability + return True + except OSError: + return False + + def check_git_status(): - # Suggest 'git pull' if repo is out of date - if platform.system() in ['Linux', 'Darwin'] and not os.path.isfile('/.dockerenv'): - s = subprocess.check_output('if [ -d .git ]; then git fetch && git status -uno; fi', shell=True).decode('utf-8') - if 'Your branch is behind' in s: - print(s[s.find('Your branch is behind'):s.find('\n\n')] + '\n') + # Suggest 'git pull' if YOLOv5 is out of date + print(colorstr('github: '), end='') + try: + if Path('.git').exists() and check_online(): + url = subprocess.check_output( + 'git fetch && git config --get remote.origin.url', shell=True).decode('utf-8')[:-1] + n = int(subprocess.check_output( + 'git rev-list $(git rev-parse --abbrev-ref HEAD)..origin/master --count', shell=True)) # commits behind + if n > 0: + s = f"⚠️ WARNING: code is out of date by {n} {'commits' if n > 1 else 'commmit'}. " \ + f"Use 'git pull' to update or 'git clone {url}' to download latest." + else: + s = f'up to date with {url} ✅' + except Exception as e: + s = str(e) + print(s) + + +def check_requirements(file='requirements.txt'): + # Check installed dependencies meet requirements + import pkg_resources + requirements = pkg_resources.parse_requirements(Path(file).open()) + requirements = [x.name + ''.join(*x.specs) if len(x.specs) else x.name for x in requirements] + pkg_resources.require(requirements) # DistributionNotFound or VersionConflict exception if requirements not met def check_img_size(img_size, s=32): @@ -97,6 +127,41 @@ def make_divisible(x, divisor): return math.ceil(x / divisor) * divisor +def clean_str(s): + # Cleans a string by replacing special characters with underscore _ + return re.sub(pattern="[|@#!¡·$€%&()=?¿^*;:,¨´><+]", repl="_", string=s) + + +def one_cycle(y1=0.0, y2=1.0, steps=100): + # lambda function for sinusoidal ramp from y1 to y2 + return lambda x: ((1 - math.cos(x * math.pi / steps)) / 2) * (y2 - y1) + y1 + + +def colorstr(*input): + # Colors a string https://en.wikipedia.org/wiki/ANSI_escape_code, i.e. colorstr('blue', 'hello world') + *args, string = input if len(input) > 1 else ('blue', 'bold', input[0]) # color arguments, string + colors = {'black': '\033[30m', # basic colors + 'red': '\033[31m', + 'green': '\033[32m', + 'yellow': '\033[33m', + 'blue': '\033[34m', + 'magenta': '\033[35m', + 'cyan': '\033[36m', + 'white': '\033[37m', + 'bright_black': '\033[90m', # bright colors + 'bright_red': '\033[91m', + 'bright_green': '\033[92m', + 'bright_yellow': '\033[93m', + 'bright_blue': '\033[94m', + 'bright_magenta': '\033[95m', + 'bright_cyan': '\033[96m', + 'bright_white': '\033[97m', + 'end': '\033[0m', # misc + 'bold': '\033[1m', + 'underline': '\033[4m'} + return ''.join(colors[x] for x in args) + f'{string}' + colors['end'] + + def labels_to_class_weights(labels, nc=80): # Get class weights (inverse frequency) from training labels if labels[0] is None: # no labels loaded @@ -271,6 +336,7 @@ def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=Non # Settings min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height max_det = 300 # maximum number of detections per image + max_nms = 30000 # maximum number of boxes into torchvision.ops.nms() time_limit = 10.0 # seconds to quit after redundant = True # require redundant detections multi_label = nc > 1 # multiple labels per box (adds 0.5ms/img) @@ -311,20 +377,19 @@ def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=Non x = torch.cat((box, conf, j.float()), 1)[conf.view(-1) > conf_thres] # Filter by class - if classes: + if classes is not None: x = x[(x[:, 5:6] == torch.tensor(classes, device=x.device)).any(1)] # Apply finite constraint # if not torch.isfinite(x).all(): # x = x[torch.isfinite(x).all(1)] - # If none remain process next image + # Check shape n = x.shape[0] # number of boxes - if not n: + if not n: # no boxes continue - - # Sort by confidence - # x = x[x[:, 4].argsort(descending=True)] + elif n > max_nms: # excess boxes + x = x[x[:, 4].argsort(descending=True)[:max_nms]] # sort by confidence # Batched NMS c = x[:, 5:6] * (0 if agnostic else max_wh) # classes @@ -342,6 +407,7 @@ def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=Non output[xi] = x[i] if (time.time() - t) > time_limit: + print(f'WARNING: NMS time limit {time_limit}s exceeded') break # time limit exceeded return output diff --git a/utils/loss.py b/utils/loss.py index 4893c99918..2cfd0967b9 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -59,6 +59,32 @@ def forward(self, pred, true): return loss +class QFocalLoss(nn.Module): + # Wraps Quality focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): + super(QFocalLoss, self).__init__() + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() + self.gamma = gamma + self.alpha = alpha + self.reduction = loss_fcn.reduction + self.loss_fcn.reduction = 'none' # required to apply FL to each element + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + + pred_prob = torch.sigmoid(pred) # prob from logits + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) + modulating_factor = torch.abs(true - pred_prob) ** self.gamma + loss *= alpha_factor * modulating_factor + + if self.reduction == 'mean': + return loss.mean() + elif self.reduction == 'sum': + return loss.sum() + else: # 'none' + return loss + + def compute_loss(p, targets, model): # predictions, targets, model device = targets.device lcls, lbox, lobj = torch.zeros(1, device=device), torch.zeros(1, device=device), torch.zeros(1, device=device) @@ -66,8 +92,8 @@ def compute_loss(p, targets, model): # predictions, targets, model h = model.hyp # hyperparameters # Define criteria - BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.Tensor([h['cls_pw']])).to(device) - BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.Tensor([h['obj_pw']])).to(device) + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device)) # weight=model.class_weights) + BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device)) # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 cp, cn = smooth_BCE(eps=0.0) @@ -79,8 +105,7 @@ def compute_loss(p, targets, model): # predictions, targets, model # Losses nt = 0 # number of targets - no = len(p) # number of outputs - balance = [4.0, 1.0, 0.4] if no == 3 else [4.0, 1.0, 0.4, 0.1] # P3-5 or P3-6 + balance = [4.0, 1.0, 0.4, 0.1] # P3-P6 for i, pi in enumerate(p): # layer index, layer predictions b, a, gj, gi = indices[i] # image, anchor, gridy, gridx tobj = torch.zeros_like(pi[..., 0], device=device) # target obj @@ -93,7 +118,7 @@ def compute_loss(p, targets, model): # predictions, targets, model # Regression pxy = ps[:, :2].sigmoid() * 2. - 0.5 pwh = (ps[:, 2:4].sigmoid() * 2) ** 2 * anchors[i] - pbox = torch.cat((pxy, pwh), 1).to(device) # predicted box + pbox = torch.cat((pxy, pwh), 1) # predicted box iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, CIoU=True) # iou(prediction, target) lbox += (1.0 - iou).mean() # iou loss @@ -112,10 +137,9 @@ def compute_loss(p, targets, model): # predictions, targets, model lobj += BCEobj(pi[..., 4], tobj) * balance[i] # obj loss - s = 3 / no # output count scaling - lbox *= h['box'] * s - lobj *= h['obj'] * s * (1.4 if no == 4 else 1.) - lcls *= h['cls'] * s + lbox *= h['box'] + lobj *= h['obj'] + lcls *= h['cls'] bs = tobj.shape[0] # batch size loss = lbox + lobj + lcls diff --git a/utils/plots.py b/utils/plots.py index 8fff8ec6dd..47cd707760 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -1,16 +1,18 @@ # Plotting utils import glob +import math import os import random from copy import copy from pathlib import Path import cv2 -import math import matplotlib import matplotlib.pyplot as plt import numpy as np +import pandas as pd +import seaborn as sns import torch import yaml from PIL import Image, ImageDraw @@ -21,7 +23,7 @@ # Settings matplotlib.rc('font', **{'size': 11}) -matplotlib.use('svg') # for writing to files only +matplotlib.use('Agg') # for writing to files only def color_list(): @@ -188,6 +190,7 @@ def plot_lr_scheduler(optimizer, scheduler, epochs=300, save_dir=''): plt.xlim(0, epochs) plt.ylim(0) plt.savefig(Path(save_dir) / 'LR.png', dpi=200) + plt.close() def plot_test_txt(): # from utils.plots import *; plot_test() @@ -220,13 +223,13 @@ def plot_targets_txt(): # from utils.plots import *; plot_targets_txt() plt.savefig('targets.jpg', dpi=200) -def plot_study_txt(path='', x=None): # from utils.plots import *; plot_study_txt() +def plot_study_txt(path='study/', x=None): # from utils.plots import *; plot_study_txt() # Plot study.txt generated by test.py fig, ax = plt.subplots(2, 4, figsize=(10, 6), tight_layout=True) ax = ax.ravel() fig2, ax2 = plt.subplots(1, 1, figsize=(8, 4), tight_layout=True) - for f in [Path(path) / f'study_coco_{x}.txt' for x in ['yolov3', 'yolov3-spp', 'yolov3-tiny']]: + for f in [Path(path) / f'study_coco_{x}.txt' for x in ['yolov5s', 'yolov5m', 'yolov5l', 'yolov5x']]: y = np.loadtxt(f, dtype=np.float32, usecols=[0, 1, 2, 3, 7, 8, 9], ndmin=2).T x = np.arange(y.shape[1]) if x is None else np.array(x) s = ['P', 'R', 'mAP@.5', 'mAP@.5:.95', 't_inference (ms/img)', 't_NMS (ms/img)', 't_total (ms/img)'] @@ -242,9 +245,9 @@ def plot_study_txt(path='', x=None): # from utils.plots import *; plot_study_tx 'k.-', linewidth=2, markersize=8, alpha=.25, label='EfficientDet') ax2.grid() + ax2.set_yticks(np.arange(30, 60, 5)) ax2.set_xlim(0, 30) - ax2.set_ylim(15, 50) - ax2.set_yticks(np.arange(15, 55, 5)) + ax2.set_ylim(29, 51) ax2.set_xlabel('GPU Speed (ms/img)') ax2.set_ylabel('COCO AP val') ax2.legend(loc='lower right') @@ -253,34 +256,24 @@ def plot_study_txt(path='', x=None): # from utils.plots import *; plot_study_tx def plot_labels(labels, save_dir=Path(''), loggers=None): # plot dataset labels + print('Plotting labels... ') c, b = labels[:, 0], labels[:, 1:].transpose() # classes, boxes nc = int(c.max() + 1) # number of classes colors = color_list() + x = pd.DataFrame(b.transpose(), columns=['x', 'y', 'width', 'height']) # seaborn correlogram - try: - import seaborn as sns - import pandas as pd - x = pd.DataFrame(b.transpose(), columns=['x', 'y', 'width', 'height']) - sns.pairplot(x, corner=True, diag_kind='hist', kind='scatter', markers='o', - plot_kws=dict(s=3, edgecolor=None, linewidth=1, alpha=0.02), - diag_kws=dict(bins=50)) - plt.savefig(save_dir / 'labels_correlogram.jpg', dpi=200) - plt.close() - except Exception as e: - pass + sns.pairplot(x, corner=True, diag_kind='auto', kind='hist', diag_kws=dict(bins=50), plot_kws=dict(pmax=0.9)) + plt.savefig(save_dir / 'labels_correlogram.jpg', dpi=200) + plt.close() # matplotlib labels matplotlib.use('svg') # faster ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True)[1].ravel() ax[0].hist(c, bins=np.linspace(0, nc, nc + 1) - 0.5, rwidth=0.8) ax[0].set_xlabel('classes') - ax[2].scatter(b[0], b[1], c=hist2d(b[0], b[1], 90), cmap='jet') - ax[2].set_xlabel('x') - ax[2].set_ylabel('y') - ax[3].scatter(b[2], b[3], c=hist2d(b[2], b[3], 90), cmap='jet') - ax[3].set_xlabel('width') - ax[3].set_ylabel('height') + sns.histplot(x, x='x', y='y', ax=ax[2], bins=50, pmax=0.9) + sns.histplot(x, x='width', y='height', ax=ax[3], bins=50, pmax=0.9) # rectangles labels[:, 1:3] = 0.5 # center @@ -329,6 +322,38 @@ def plot_evolution(yaml_file='data/hyp.finetune.yaml'): # from utils.plots impo print('\nPlot saved as evolve.png') +def profile_idetection(start=0, stop=0, labels=(), save_dir=''): + # Plot iDetection '*.txt' per-image logs. from utils.plots import *; profile_idetection() + ax = plt.subplots(2, 4, figsize=(12, 6), tight_layout=True)[1].ravel() + s = ['Images', 'Free Storage (GB)', 'RAM Usage (GB)', 'Battery', 'dt_raw (ms)', 'dt_smooth (ms)', 'real-world FPS'] + files = list(Path(save_dir).glob('frames*.txt')) + for fi, f in enumerate(files): + try: + results = np.loadtxt(f, ndmin=2).T[:, 90:-30] # clip first and last rows + n = results.shape[1] # number of rows + x = np.arange(start, min(stop, n) if stop else n) + results = results[:, x] + t = (results[0] - results[0].min()) # set t0=0s + results[0] = x + for i, a in enumerate(ax): + if i < len(results): + label = labels[fi] if len(labels) else f.stem.replace('frames_', '') + a.plot(t, results[i], marker='.', label=label, linewidth=1, markersize=5) + a.set_title(s[i]) + a.set_xlabel('time (s)') + # if fi == len(files) - 1: + # a.set_ylim(bottom=0) + for side in ['top', 'right']: + a.spines[side].set_visible(False) + else: + a.remove() + except Exception as e: + print('Warning: Plotting error for %s; %s' % (f, e)) + + ax[1].legend() + plt.savefig(Path(save_dir) / 'idetection_profile.png', dpi=200) + + def plot_results_overlay(start=0, stop=0): # from utils.plots import *; plot_results_overlay() # Plot training 'results*.txt', overlaying train and val losses s = ['train', 'train', 'train', 'Precision', 'mAP@0.5', 'val', 'val', 'val', 'Recall', 'mAP@0.5:0.95'] # legends diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 82fc731c02..231dcfd7a5 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -61,7 +61,7 @@ def select_device(device='', batch_size=None): os.environ['CUDA_VISIBLE_DEVICES'] = device # set environment variable assert torch.cuda.is_available(), f'CUDA unavailable, invalid device {device} requested' # check availability - cuda = torch.cuda.is_available() and not cpu + cuda = not cpu and torch.cuda.is_available() if cuda: n = torch.cuda.device_count() if n > 1 and batch_size: # check that batch_size is compatible with device_count From bc69220782dedeeac9cbd44f5a3b9390aa745e21 Mon Sep 17 00:00:00 2001 From: Yonghye Kwon Date: Thu, 14 Jan 2021 02:13:13 +0900 Subject: [PATCH 0872/1185] remove unused variable in def compute_loss function (#1659) remove unused variable in def compute_loss function --- utils/loss.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/utils/loss.py b/utils/loss.py index 2cfd0967b9..844d503924 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -104,7 +104,6 @@ def compute_loss(p, targets, model): # predictions, targets, model BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) # Losses - nt = 0 # number of targets balance = [4.0, 1.0, 0.4, 0.1] # P3-P6 for i, pi in enumerate(p): # layer index, layer predictions b, a, gj, gi = indices[i] # image, anchor, gridy, gridx @@ -112,7 +111,6 @@ def compute_loss(p, targets, model): # predictions, targets, model n = b.shape[0] # number of targets if n: - nt += n # cumulative targets ps = pi[b, a, gj, gi] # prediction subset corresponding to targets # Regression From 2271a2ebd87a078ce8b575cdc4c625b99a72e4ba Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 13 Jan 2021 10:26:09 -0800 Subject: [PATCH 0873/1185] check_git_status() bug fix (#1660) --- utils/general.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/utils/general.py b/utils/general.py index 5126a45ac0..a3238efa49 100755 --- a/utils/general.py +++ b/utils/general.py @@ -66,13 +66,12 @@ def check_git_status(): n = int(subprocess.check_output( 'git rev-list $(git rev-parse --abbrev-ref HEAD)..origin/master --count', shell=True)) # commits behind if n > 0: - s = f"⚠️ WARNING: code is out of date by {n} {'commits' if n > 1 else 'commmit'}. " \ - f"Use 'git pull' to update or 'git clone {url}' to download latest." + print(f"⚠️ WARNING: code is out of date by {n} {'commits' if n > 1 else 'commmit'}. " + f"Use 'git pull' to update or 'git clone {url}' to download latest.") else: - s = f'up to date with {url} ✅' + print(f'up to date with {url} ✅') except Exception as e: - s = str(e) - print(s) + print(e) def check_requirements(file='requirements.txt'): From 9f4e853c60a498bc69631ce3e62e8cb15077c43b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 13 Jan 2021 19:55:34 -0800 Subject: [PATCH 0874/1185] GitHub API rate limit fallback (#1661) --- utils/google_utils.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/utils/google_utils.py b/utils/google_utils.py index c749741419..347b11218a 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -16,28 +16,32 @@ def gsutil_getsize(url=''): return eval(s.split(' ')[0]) if len(s) else 0 # bytes -def attempt_download(file): +def attempt_download(file, repo='ultralytics/yolov3'): # Attempt file download if does not exist file = Path(str(file).strip().replace("'", '').lower()) if not file.exists(): - response = requests.get('https://api.github.com/repos/ultralytics/yolov3/releases/latest').json() # github api - assets = [x['name'] for x in response['assets']] # release assets ['yolov3.pt', 'yolov3-spp.pt', ...] - name = file.name + try: + response = requests.get(f'https://api.github.com/repos/{repo}/releases/latest').json() # github api + assets = [x['name'] for x in response['assets']] # release assets, i.e. ['yolov5s.pt', 'yolov5m.pt', ...] + tag = response['tag_name'] # i.e. 'v1.0' + except: # fallback plan + assets = ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt'] + tag = subprocess.check_output('git tag', shell=True).decode('utf-8').split('\n')[-2] + name = file.name if name in assets: - msg = f'{file} missing, try downloading from https://github.com/ultralytics/yolov3/releases/' + msg = f'{file} missing, try downloading from https://github.com/{repo}/releases/' redundant = False # second download option try: # GitHub - tag = response['tag_name'] # i.e. 'v1.0' - url = f'https://github.com/ultralytics/yolov3/releases/download/{tag}/{name}' + url = f'https://github.com/{repo}/releases/download/{tag}/{name}' print(f'Downloading {url} to {file}...') torch.hub.download_url_to_file(url, file) assert file.exists() and file.stat().st_size > 1E6 # check except Exception as e: # GCP print(f'Download error: {e}') assert redundant, 'No secondary mirror' - url = f'https://storage.googleapis.com/ultralytics/yolov3/ckpt/{name}' + url = f'https://storage.googleapis.com/{repo}/ckpt/{name}' print(f'Downloading {url} to {file}...') os.system(f'curl -L {url} -o {file}') # torch.hub.download_url_to_file(url, weights) finally: From cf5db95953644c0e661d6907d035e0de690631ff Mon Sep 17 00:00:00 2001 From: "huntr.dev | the place to protect open source" Date: Mon, 25 Jan 2021 17:39:34 +0000 Subject: [PATCH 0875/1185] Security Fix for Arbitrary Code Execution - huntr.dev (#1672) * fixed arbitary code execution * Update train.py * Full to Safe Co-authored-by: Asjid Kalam Co-authored-by: Jamie Slome Co-authored-by: Glenn Jocher --- train.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/train.py b/train.py index 9f869cfd92..91d8dfe033 100644 --- a/train.py +++ b/train.py @@ -59,7 +59,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): cuda = device.type != 'cpu' init_seeds(2 + rank) with open(opt.data) as f: - data_dict = yaml.load(f, Loader=yaml.FullLoader) # data dict + data_dict = yaml.load(f, Loader=yaml.SafeLoader) # data dict with torch_distributed_zero_first(rank): check_dataset(data_dict) # check train_path = data_dict['train'] @@ -476,7 +476,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): assert os.path.isfile(ckpt), 'ERROR: --resume checkpoint does not exist' apriori = opt.global_rank, opt.local_rank with open(Path(ckpt).parent.parent / 'opt.yaml') as f: - opt = argparse.Namespace(**yaml.load(f, Loader=yaml.FullLoader)) # replace + opt = argparse.Namespace(**yaml.load(f, Loader=yaml.SafeLoader)) # replace opt.cfg, opt.weights, opt.resume, opt.global_rank, opt.local_rank = '', ckpt, True, *apriori # reinstate logger.info('Resuming training from %s' % ckpt) else: @@ -500,7 +500,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): # Hyperparameters with open(opt.hyp) as f: - hyp = yaml.load(f, Loader=yaml.FullLoader) # load hyps + hyp = yaml.load(f, Loader=yaml.SafeLoader) # load hyps # Train logger.info(opt) From daa4600fd372d1c16e90a5ae14682ccf499b0bbe Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 16 Feb 2021 11:09:54 -0800 Subject: [PATCH 0876/1185] Update google_utils.py --- utils/google_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/google_utils.py b/utils/google_utils.py index 347b11218a..61af2f4343 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -27,7 +27,7 @@ def attempt_download(file, repo='ultralytics/yolov3'): tag = response['tag_name'] # i.e. 'v1.0' except: # fallback plan assets = ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt'] - tag = subprocess.check_output('git tag', shell=True).decode('utf-8').split('\n')[-2] + tag = subprocess.check_output('git tag', shell=True).decode().split()[-1] name = file.name if name in assets: From d3533715ba8a5bdaa597fda6fd4d366b1e5045f6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 16 Feb 2021 16:11:36 -0800 Subject: [PATCH 0877/1185] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 05da4a2a07..1518834d15 100755 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@   -![CI CPU testing](https://github.com/ultralytics/yolov3/workflows/CI%20CPU%20testing/badge.svg) +CI CPU testing BRANCH NOTICE: The [ultralytics/yolov3](https://github.com/ultralytics/yolov3) repository is now divided into two branches: * [Master branch](https://github.com/ultralytics/yolov3/tree/master): Forward-compatible with all [YOLOv5](https://github.com/ultralytics/yolov5) models and methods (**recommended**). From c1f8dd94b77a1c4a756ed2b0cc04e40b0c314185 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 22 Feb 2021 17:57:47 -0800 Subject: [PATCH 0878/1185] Update google_utils.py (#1690) --- utils/google_utils.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/utils/google_utils.py b/utils/google_utils.py index 61af2f4343..e4b115a599 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -21,13 +21,13 @@ def attempt_download(file, repo='ultralytics/yolov3'): file = Path(str(file).strip().replace("'", '').lower()) if not file.exists(): - try: - response = requests.get(f'https://api.github.com/repos/{repo}/releases/latest').json() # github api - assets = [x['name'] for x in response['assets']] # release assets, i.e. ['yolov5s.pt', 'yolov5m.pt', ...] - tag = response['tag_name'] # i.e. 'v1.0' - except: # fallback plan - assets = ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt'] - tag = subprocess.check_output('git tag', shell=True).decode().split()[-1] + # try: + # response = requests.get(f'https://api.github.com/repos/{repo}/releases/latest').json() # github api + # assets = [x['name'] for x in response['assets']] # release assets, i.e. ['yolov5s.pt', 'yolov5m.pt', ...] + # tag = response['tag_name'] # i.e. 'v1.0' + # except: # fallback plan + assets = ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt'] + tag = subprocess.check_output('git tag', shell=True).decode().split()[-1] name = file.name if name in assets: From 5d8f03020c0799a00888cd85f7109c0b9efb4a41 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 6 Apr 2021 13:26:56 +0200 Subject: [PATCH 0879/1185] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1518834d15..6e2d32161f 100755 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ $ git clone https://github.com/ultralytics/yolov3 # master branch (default) ``` * [Archive branch](https://github.com/ultralytics/yolov3/tree/archive): Backwards-compatible with original [darknet](https://pjreddie.com/darknet/) *.cfg models (⚠️ no longer maintained). ```bash -$ git clone -b archive https://github.com/ultralytics/yolov3 # archive branch +$ git clone https://github.com/ultralytics/yolov3 -b archive # archive branch ``` ** GPU Speed measures end-to-end time per image averaged over 5000 COCO val2017 images using a V100 GPU with batch size 32, and includes image preprocessing, PyTorch FP16 inference, postprocessing and NMS. EfficientDet data from [google/automl](https://github.com/google/automl) at batch size 8. From 8eb4cde090022af73db12cfa725ec4bf01d49c0e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 12 Apr 2021 18:00:47 +0200 Subject: [PATCH 0880/1185] YOLOv5 v5.0 release compatibility update for YOLOv3 (#1737) * YOLOv5 v5.0 release compatibility update * Update README * Update README * Conv act LeakyReLU(0.1) * update plots_study() * update speeds --- .gitattributes | 2 +- .github/workflows/ci-testing.yml | 9 +- .github/workflows/greetings.yml | 9 +- Dockerfile | 19 +- README.md | 114 ++++---- data/argoverse_hd.yaml | 21 ++ data/coco.yaml | 18 +- data/coco128.yaml | 18 +- data/scripts/get_argoverse_hd.sh | 62 ++++ data/scripts/get_coco.sh | 9 +- data/scripts/get_voc.sh | 6 +- data/voc.yaml | 4 +- detect.py | 43 +-- hubconf.py | 101 +++---- models/common.py | 163 ++++++++--- models/experimental.py | 9 +- models/export.py | 19 +- models/yolo.py | 57 ++-- requirements.txt | 9 +- test.py | 111 +++---- train.py | 213 ++++++++------ tutorial.ipynb | 450 ++++++++++++++++------------- utils/autoanchor.py | 19 +- utils/aws/__init__.py | 0 utils/aws/mime.sh | 26 ++ utils/aws/resume.py | 37 +++ utils/aws/userdata.sh | 27 ++ utils/datasets.py | 258 +++++++++-------- utils/general.py | 163 +++++++++-- utils/google_utils.py | 14 +- utils/loss.py | 241 +++++++-------- utils/metrics.py | 61 ++-- utils/plots.py | 58 ++-- utils/torch_utils.py | 31 +- utils/wandb_logging/__init__.py | 0 utils/wandb_logging/log_dataset.py | 24 ++ utils/wandb_logging/wandb_utils.py | 306 ++++++++++++++++++++ 37 files changed, 1807 insertions(+), 924 deletions(-) create mode 100644 data/argoverse_hd.yaml create mode 100644 data/scripts/get_argoverse_hd.sh create mode 100644 utils/aws/__init__.py create mode 100644 utils/aws/mime.sh create mode 100644 utils/aws/resume.py create mode 100644 utils/aws/userdata.sh create mode 100644 utils/wandb_logging/__init__.py create mode 100644 utils/wandb_logging/log_dataset.py create mode 100644 utils/wandb_logging/wandb_utils.py diff --git a/.gitattributes b/.gitattributes index 6c8722f6e0..dad4239eba 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ -# remove notebooks from GitHub language stats +# this drop notebooks from GitHub language stats *.ipynb linguist-vendored diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 1ae0bbb573..77ac2c3f35 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -66,14 +66,15 @@ jobs: di=cpu # inference devices # define device # train - python train.py --img 256 --batch 8 --weights weights/${{ matrix.model }}.pt --cfg models/${{ matrix.model }}.yaml --epochs 1 --device $di + python train.py --img 128 --batch 16 --weights weights/${{ matrix.model }}.pt --cfg models/${{ matrix.model }}.yaml --epochs 1 --device $di # detect python detect.py --weights weights/${{ matrix.model }}.pt --device $di python detect.py --weights runs/train/exp/weights/last.pt --device $di # test - python test.py --img 256 --batch 8 --weights weights/${{ matrix.model }}.pt --device $di - python test.py --img 256 --batch 8 --weights runs/train/exp/weights/last.pt --device $di + python test.py --img 128 --batch 16 --weights weights/${{ matrix.model }}.pt --device $di + python test.py --img 128 --batch 16 --weights runs/train/exp/weights/last.pt --device $di + python hubconf.py # hub python models/yolo.py --cfg models/${{ matrix.model }}.yaml # inspect - python models/export.py --img 256 --batch 1 --weights weights/${{ matrix.model }}.pt # export + python models/export.py --img 128 --batch 1 --weights weights/${{ matrix.model }}.pt # export shell: bash diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 1d6ec61d2d..3c3b9fc1ef 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -23,7 +23,7 @@ jobs: - ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ -Bruce Lee issue-message: | - 👋 Hello @${{ github.actor }}, thank you for your interest in 🚀 YOLOv3! Please visit our ⭐️ [Tutorials](https://github.com/ultralytics/yolov3/wiki#tutorials) to get started, where you can find quickstart guides for simple tasks like [Custom Data Training](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) all the way to advanced concepts like [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607). + 👋 Hello @${{ github.actor }}, thank you for your interest in YOLOv3 🚀! Please visit our ⭐️ [Tutorials](https://github.com/ultralytics/yolov3/wiki#tutorials) to get started, where you can find quickstart guides for simple tasks like [Custom Data Training](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) all the way to advanced concepts like [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607). If this is a 🐛 Bug Report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you. @@ -42,10 +42,11 @@ jobs: YOLOv3 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): - - **Google Colab Notebook** with free GPU: Open In Colab - - **Kaggle Notebook** with free GPU: [https://www.kaggle.com/ultralytics/yolov3](https://www.kaggle.com/ultralytics/yolov3) + - **Google Colab and Kaggle** notebooks with free GPU: Open In Colab Open In Kaggle - **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) - - **Docker Image** https://hub.docker.com/r/ultralytics/yolov3. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) ![Docker Pulls](https://img.shields.io/docker/pulls/ultralytics/yolov3?logo=docker) + - **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/AWS-Quickstart) + - **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) Docker Pulls + ## Status diff --git a/Dockerfile b/Dockerfile index d0a797fdf3..ca07c4d7ef 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,14 @@ # Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch -FROM nvcr.io/nvidia/pytorch:20.12-py3 +FROM nvcr.io/nvidia/pytorch:21.03-py3 # Install linux packages -RUN apt update && apt install -y screen libgl1-mesa-glx +RUN apt update && apt install -y zip htop screen libgl1-mesa-glx # Install python dependencies -RUN pip install --upgrade pip COPY requirements.txt . -RUN pip install -r requirements.txt -RUN pip install gsutil +RUN python -m pip install --upgrade pip +RUN pip uninstall -y nvidia-tensorboard nvidia-tensorboard-plugin-dlprof +RUN pip install --no-cache -r requirements.txt coremltools onnx gsutil notebook # Create working directory RUN mkdir -p /usr/src/app @@ -17,6 +17,9 @@ WORKDIR /usr/src/app # Copy contents COPY . /usr/src/app +# Set environment variables +ENV HOME=/usr/src/app + # --------------------------------------------------- Extras Below --------------------------------------------------- @@ -34,13 +37,13 @@ COPY . /usr/src/app # sudo docker kill $(sudo docker ps -q) # Kill all image-based -# sudo docker kill $(sudo docker ps -a -q --filter ancestor=ultralytics/yolov3:latest) +# sudo docker kill $(sudo docker ps -qa --filter ancestor=ultralytics/yolov5:latest) # Bash into running container -# sudo docker container exec -it ba65811811ab bash +# sudo docker exec -it 5a9b5863d93d bash # Bash into stopped container -# sudo docker commit 092b16b25c5b usr/resume && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco --entrypoint=sh usr/resume +# id=$(sudo docker ps -qa) && sudo docker start $id && sudo docker exec -it $id bash # Send weights to GCP # python -c "from utils.general import *; strip_optimizer('runs/train/exp0_*/weights/best.pt', 'tmp.pt')" && gsutil cp tmp.pt gs://*.pt diff --git a/README.md b/README.md index 6e2d32161f..7a3c0e87b2 100755 --- a/README.md +++ b/README.md @@ -1,35 +1,61 @@ - - + +   CI CPU testing -BRANCH NOTICE: The [ultralytics/yolov3](https://github.com/ultralytics/yolov3) repository is now divided into two branches: -* [Master branch](https://github.com/ultralytics/yolov3/tree/master): Forward-compatible with all [YOLOv5](https://github.com/ultralytics/yolov5) models and methods (**recommended**). +This repository represents Ultralytics open-source research into future object detection methods, and incorporates lessons learned and best practices evolved over thousands of hours of training and evolution on anonymized client datasets. **All code and models are under active development, and are subject to modification or deletion without notice.** Use at your own risk. + +

+
+ YOLOv5-P5 640 Figure (click to expand) + +

+
+
+ Figure Notes (click to expand) + + * GPU Speed measures end-to-end time per image averaged over 5000 COCO val2017 images using a V100 GPU with batch size 32, and includes image preprocessing, PyTorch FP16 inference, postprocessing and NMS. + * EfficientDet data from [google/automl](https://github.com/google/automl) at batch size 8. + * **Reproduce** by `python test.py --task study --data coco.yaml --iou 0.7 --weights yolov3.pt yolov3-spp.pt yolov3-tiny.pt yolov5l.pt` +
+ + +## Branch Notice + +The [ultralytics/yolov3](https://github.com/ultralytics/yolov3) repository is now divided into two branches: +* [Master branch](https://github.com/ultralytics/yolov3/tree/master): Forward-compatible with all [YOLOv5](https://github.com/ultralytics/yolov5) models and methods (**recommended** ✅). ```bash $ git clone https://github.com/ultralytics/yolov3 # master branch (default) ``` -* [Archive branch](https://github.com/ultralytics/yolov3/tree/archive): Backwards-compatible with original [darknet](https://pjreddie.com/darknet/) *.cfg models (⚠️ no longer maintained). +* [Archive branch](https://github.com/ultralytics/yolov3/tree/archive): Backwards-compatible with original [darknet](https://pjreddie.com/darknet/) *.cfg models (**no longer maintained** ⚠️). ```bash $ git clone https://github.com/ultralytics/yolov3 -b archive # archive branch ``` -** GPU Speed measures end-to-end time per image averaged over 5000 COCO val2017 images using a V100 GPU with batch size 32, and includes image preprocessing, PyTorch FP16 inference, postprocessing and NMS. EfficientDet data from [google/automl](https://github.com/google/automl) at batch size 8. +## Pretrained Checkpoints + +[assets3]: https://github.com/ultralytics/yolov3/releases +[assets5]: https://github.com/ultralytics/yolov5/releases +Model |size
(pixels) |mAPval
0.5:0.95 |mAPtest
0.5:0.95 |mAPval
0.5 |Speed
V100 (ms) | |params
(M) |FLOPS
640 (B) +--- |--- |--- |--- |--- |--- |---|--- |--- +[YOLOv3-tiny][assets3] |640 |17.6 |17.6 |34.8 |**1.2** | |8.8 |13.2 +[YOLOv3][assets3] |640 |43.3 |43.3 |63.0 |4.1 | |61.9 |156.3 +[YOLOv3-SPP][assets3] |640 |44.3 |44.3 |64.6 |4.1 | |63.0 |157.1 +| | | | | | || | +[YOLOv5l][assets5] |640 |**48.2** |**48.2** |**66.9** |3.7 | |47.0 |115.4 -## Pretrained Checkpoints -| Model | APval | APtest | AP50 | SpeedGPU | FPSGPU || params | FLOPS | -|---------- |------ |------ |------ | -------- | ------| ------ |------ | :------: | -| [YOLOv3](https://github.com/ultralytics/yolov3/releases) | 43.3 | 43.3 | 63.0 | 4.8ms | 208 || 61.9M | 156.4B -| [YOLOv3-SPP](https://github.com/ultralytics/yolov3/releases) | **44.3** | **44.3** | **64.6** | 4.9ms | 204 || 63.0M | 157.0B -| [YOLOv3-tiny](https://github.com/ultralytics/yolov3/releases) | 17.6 | 34.9 | 34.9 | **1.7ms** | **588** || 8.9M | 13.3B +
+ Table Notes (click to expand) + + * APtest denotes COCO [test-dev2017](http://cocodataset.org/#upload) server results, all other AP results denote val2017 accuracy. + * AP values are for single-model single-scale unless otherwise noted. **Reproduce mAP** by `python test.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` + * SpeedGPU averaged over 5000 COCO val2017 images using a GCP [n1-standard-16](https://cloud.google.com/compute/docs/machine-types#n1_standard_machine_types) V100 instance, and includes FP16 inference, postprocessing and NMS. **Reproduce speed** by `python test.py --data coco.yaml --img 640 --conf 0.25 --iou 0.45` + * All checkpoints are trained to 300 epochs with default settings and hyperparameters (no autoaugmentation). +
-** APtest denotes COCO [test-dev2017](http://cocodataset.org/#upload) server results, all other AP results denote val2017 accuracy. -** All AP numbers are for single-model single-scale without ensemble or TTA. **Reproduce mAP** by `python test.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` -** SpeedGPU averaged over 5000 COCO val2017 images using a GCP [n1-standard-16](https://cloud.google.com/compute/docs/machine-types#n1_standard_machine_types) V100 instance, and includes image preprocessing, FP16 inference, postprocessing and NMS. NMS is 1-2ms/img. **Reproduce speed** by `python test.py --data coco.yaml --img 640 --conf 0.25 --iou 0.45` -** All checkpoints are trained to 300 epochs with default settings and hyperparameters (no autoaugmentation). -** Test Time Augmentation ([TTA](https://github.com/ultralytics/yolov5/issues/303)) runs at 3 image sizes. **Reproduce TTA** by `python test.py --data coco.yaml --img 832 --iou 0.65 --augment` ## Requirements @@ -42,7 +68,9 @@ $ pip install -r requirements.txt ## Tutorials * [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data)  🚀 RECOMMENDED +* [Tips for Best Training Results](https://github.com/ultralytics/yolov5/wiki/Tips-for-Best-Training-Results)  ☘️ RECOMMENDED * [Weights & Biases Logging](https://github.com/ultralytics/yolov5/issues/1289)  🌟 NEW +* [Supervisely Ecosystem](https://github.com/ultralytics/yolov5/issues/2518)  🌟 NEW * [Multi-GPU Training](https://github.com/ultralytics/yolov5/issues/475) * [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36)  ⭐ NEW * [ONNX and TorchScript Export](https://github.com/ultralytics/yolov5/issues/251) @@ -58,73 +86,59 @@ $ pip install -r requirements.txt YOLOv3 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): -- **Google Colab Notebook** with free GPU: Open In Colab -- **Kaggle Notebook** with free GPU: [https://www.kaggle.com/ultralytics/yolov3](https://www.kaggle.com/ultralytics/yolov3) -- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) -- **Docker Image** https://hub.docker.com/r/ultralytics/yolov3. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) ![Docker Pulls](https://img.shields.io/docker/pulls/ultralytics/yolov3?logo=docker) +- **Google Colab and Kaggle** notebooks with free GPU: Open In Colab Open In Kaggle +- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) +- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/AWS-Quickstart) +- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) Docker Pulls ## Inference -detect.py runs inference on a variety of sources, downloading models automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases) and saving results to `runs/detect`. +`detect.py` runs inference on a variety of sources, downloading models automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases) and saving results to `runs/detect`. ```bash $ python detect.py --source 0 # webcam file.jpg # image file.mp4 # video path/ # directory path/*.jpg # glob - rtsp://170.93.143.139/rtplive/470011e600ef003a004ee33696235daa # rtsp stream - rtmp://192.168.1.105/live/test # rtmp stream - http://112.50.243.8/PLTV/88888888/224/3221225900/1.m3u8 # http stream + 'https://youtu.be/NUsoVlDFqZg' # YouTube video + 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream ``` To run inference on example images in `data/images`: ```bash $ python detect.py --source data/images --weights yolov3.pt --conf 0.25 - -Namespace(agnostic_nms=False, augment=False, classes=None, conf_thres=0.25, device='', exist_ok=False, img_size=640, iou_thres=0.45, name='exp', project='runs/detect', save_conf=False, save_txt=False, source='data/images/', update=False, view_img=False, weights=['yolov3.pt']) -Using torch 1.7.0+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16130MB) - -Downloading https://github.com/ultralytics/yolov3/releases/download/v1.0/yolov3.pt to yolov3.pt... 100% 118M/118M [00:05<00:00, 24.2MB/s] - -Fusing layers... -Model Summary: 261 layers, 61922845 parameters, 0 gradients -image 1/2 /content/yolov3/data/images/bus.jpg: 640x480 4 persons, 1 buss, Done. (0.014s) -image 2/2 /content/yolov3/data/images/zidane.jpg: 384x640 2 persons, 3 ties, Done. (0.014s) -Results saved to runs/detect/exp -Done. (0.133s) ``` - + ### PyTorch Hub -To run **batched inference** with YOLO3 and [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36): +To run **batched inference** with YOLOv5 and [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36): ```python import torch -from PIL import Image # Model -model = torch.hub.load('ultralytics/yolov3', 'yolov3', pretrained=True).autoshape() # for PIL/cv2/np inputs and NMS +model = torch.hub.load('ultralytics/yolov3', 'yolov3') # or 'yolov3_spp', 'yolov3_tiny' # Images -img1 = Image.open('zidane.jpg') -img2 = Image.open('bus.jpg') -imgs = [img1, img2] # batched list of images +dir = 'https://github.com/ultralytics/yolov3/raw/master/data/images/' +imgs = [dir + f for f in ('zidane.jpg', 'bus.jpg')] # batch of images # Inference -prediction = model(imgs, size=640) # includes NMS +results = model(imgs) +results.print() # or .show(), .save() ``` ## Training -Download [COCO](https://github.com/ultralytics/yolov3/blob/master/data/scripts/get_coco.sh) and run command below. Training times for YOLOv3/YOLOv3-SPP/YOLOv3-tiny are 6/6/2 days on a single V100 (multi-GPU times faster). Use the largest `--batch-size` your GPU allows (batch sizes shown for 16 GB devices). +Run commands below to reproduce results on [COCO](https://github.com/ultralytics/yolov3/blob/master/data/scripts/get_coco.sh) dataset (dataset auto-downloads on first use). Training times for YOLOv3/YOLOv3-SPP/YOLOv3-tiny are 6/6/2 days on a single V100 (multi-GPU times faster). Use the largest `--batch-size` your GPU allows (batch sizes shown for 16 GB devices). ```bash -$ python train.py --data coco.yaml --cfg yolov3.yaml --weights '' --batch-size 24 - yolov3-spp.yaml 24 - yolov3-tiny.yaml 64 +$ python train.py --data coco.yaml --cfg yolov3.yaml --weights '' --batch-size 24 + yolov3-spp.yaml 24 + yolov3-tiny.yaml 64 ``` - + ## Citation diff --git a/data/argoverse_hd.yaml b/data/argoverse_hd.yaml new file mode 100644 index 0000000000..df7a9361e7 --- /dev/null +++ b/data/argoverse_hd.yaml @@ -0,0 +1,21 @@ +# Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/ +# Train command: python train.py --data argoverse_hd.yaml +# Default dataset location is next to /yolov5: +# /parent_folder +# /argoverse +# /yolov5 + + +# download command/URL (optional) +download: bash data/scripts/get_argoverse_hd.sh + +# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] +train: ../argoverse/Argoverse-1.1/images/train/ # 39384 images +val: ../argoverse/Argoverse-1.1/images/val/ # 15062 iamges +test: ../argoverse/Argoverse-1.1/images/test/ # Submit to: https://eval.ai/web/challenges/challenge-page/800/overview + +# number of classes +nc: 8 + +# class names +names: [ 'person', 'bicycle', 'car', 'motorcycle', 'bus', 'truck', 'traffic_light', 'stop_sign' ] diff --git a/data/coco.yaml b/data/coco.yaml index 09e0a4f463..1bc888e619 100644 --- a/data/coco.yaml +++ b/data/coco.yaml @@ -18,15 +18,15 @@ test: ../coco/test-dev2017.txt # 20288 of 40670 images, submit to https://compe nc: 80 # class names -names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', - 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', - 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', - 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', - 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', - 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', - 'hair drier', 'toothbrush'] +names: [ 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', + 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', + 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', + 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', + 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', + 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', + 'hair drier', 'toothbrush' ] # Print classes # with open('data/coco.yaml') as f: diff --git a/data/coco128.yaml b/data/coco128.yaml index abd129d962..f9d4c96053 100644 --- a/data/coco128.yaml +++ b/data/coco128.yaml @@ -17,12 +17,12 @@ val: ../coco128/images/train2017/ # 128 images nc: 80 # class names -names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', - 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', - 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', - 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', - 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', - 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', - 'hair drier', 'toothbrush'] +names: [ 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', + 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', + 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', + 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', + 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', + 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', + 'hair drier', 'toothbrush' ] diff --git a/data/scripts/get_argoverse_hd.sh b/data/scripts/get_argoverse_hd.sh new file mode 100644 index 0000000000..caec61efed --- /dev/null +++ b/data/scripts/get_argoverse_hd.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/ +# Download command: bash data/scripts/get_argoverse_hd.sh +# Train command: python train.py --data argoverse_hd.yaml +# Default dataset location is next to /yolov5: +# /parent_folder +# /argoverse +# /yolov5 + +# Download/unzip images +d='../argoverse/' # unzip directory +mkdir $d +url=https://argoverse-hd.s3.us-east-2.amazonaws.com/ +f=Argoverse-HD-Full.zip +curl -L $url$f -o $f && unzip -q $f -d $d && rm $f &# download, unzip, remove in background +wait # finish background tasks + +cd ../argoverse/Argoverse-1.1/ +ln -s tracking images + +cd ../Argoverse-HD/annotations/ + +python3 - "$@" < 1)}, " # add to string # Write results for *xyxy, conf, cls in reversed(det): @@ -117,22 +118,25 @@ def detect(save_img=False): # Stream results if view_img: cv2.imshow(str(p), im0) + cv2.waitKey(1) # 1 millisecond # Save results (image with detections) if save_img: if dataset.mode == 'image': cv2.imwrite(save_path, im0) - else: # 'video' + else: # 'video' or 'stream' if vid_path != save_path: # new video vid_path = save_path if isinstance(vid_writer, cv2.VideoWriter): vid_writer.release() # release previous video writer - - fourcc = 'mp4v' # output video codec - fps = vid_cap.get(cv2.CAP_PROP_FPS) - w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) - h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) - vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*fourcc), fps, (w, h)) + if vid_cap: # video + fps = vid_cap.get(cv2.CAP_PROP_FPS) + w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + else: # stream + fps, w, h = 30, im0.shape[1], im0.shape[0] + save_path += '.mp4' + vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) vid_writer.write(im0) if save_txt or save_img: @@ -153,6 +157,7 @@ def detect(save_img=False): parser.add_argument('--view-img', action='store_true', help='display results') parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--nosave', action='store_true', help='do not save images/videos') parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3') parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') parser.add_argument('--augment', action='store_true', help='augmented inference') @@ -162,7 +167,7 @@ def detect(save_img=False): parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') opt = parser.parse_args() print(opt) - check_requirements() + check_requirements(exclude=('pycocotools', 'thop')) with torch.no_grad(): if opt.update: # update all models (to fix SourceChangeWarning) diff --git a/hubconf.py b/hubconf.py index 7b0f20115e..7d969b5ad6 100644 --- a/hubconf.py +++ b/hubconf.py @@ -1,8 +1,8 @@ -"""File for accessing YOLOv3 via PyTorch Hub https://pytorch.org/hub/ +"""YOLOv3 PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov3/ Usage: import torch - model = torch.hub.load('ultralytics/yolov3', 'yolov3', pretrained=True, channels=3, classes=80) + model = torch.hub.load('ultralytics/yolov3', 'yolov3tiny') """ from pathlib import Path @@ -10,10 +10,12 @@ import torch from models.yolo import Model -from utils.general import set_logging +from utils.general import check_requirements, set_logging from utils.google_utils import attempt_download +from utils.torch_utils import select_device dependencies = ['torch', 'yaml'] +check_requirements(Path(__file__).parent / 'requirements.txt', exclude=('pycocotools', 'thop')) set_logging() @@ -21,7 +23,7 @@ def create(name, pretrained, channels, classes, autoshape): """Creates a specified YOLOv3 model Arguments: - name (str): name of model, i.e. 'yolov3_spp' + name (str): name of model, i.e. 'yolov3' pretrained (bool): load pretrained weights into the model channels (int): number of input channels classes (int): number of model classes @@ -29,21 +31,23 @@ def create(name, pretrained, channels, classes, autoshape): Returns: pytorch model """ - config = Path(__file__).parent / 'models' / f'{name}.yaml' # model.yaml path try: - model = Model(config, channels, classes) + cfg = list((Path(__file__).parent / 'models').rglob(f'{name}.yaml'))[0] # model.yaml path + model = Model(cfg, channels, classes) if pretrained: fname = f'{name}.pt' # checkpoint filename attempt_download(fname) # download if not found locally ckpt = torch.load(fname, map_location=torch.device('cpu')) # load - state_dict = ckpt['model'].float().state_dict() # to FP32 - state_dict = {k: v for k, v in state_dict.items() if model.state_dict()[k].shape == v.shape} # filter - model.load_state_dict(state_dict, strict=False) # load + msd = model.state_dict() # model state_dict + csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 + csd = {k: v for k, v in csd.items() if msd[k].shape == v.shape} # filter + model.load_state_dict(csd, strict=False) # load if len(ckpt['model'].names) == classes: model.names = ckpt['model'].names # set class names attribute if autoshape: model = model.autoshape() # for file/URI/PIL/cv2/np inputs and NMS - return model + device = select_device('0' if torch.cuda.is_available() else 'cpu') # default to GPU if available + return model.to(device) except Exception as e: help_url = 'https://github.com/ultralytics/yolov5/issues/36' @@ -51,50 +55,8 @@ def create(name, pretrained, channels, classes, autoshape): raise Exception(s) from e -def yolov3(pretrained=False, channels=3, classes=80, autoshape=True): - """YOLOv3 model from https://github.com/ultralytics/yolov3 - - Arguments: - pretrained (bool): load pretrained weights into the model, default=False - channels (int): number of input channels, default=3 - classes (int): number of model classes, default=80 - - Returns: - pytorch model - """ - return create('yolov3', pretrained, channels, classes, autoshape) - - -def yolov3_spp(pretrained=False, channels=3, classes=80, autoshape=True): - """YOLOv3-SPP model from https://github.com/ultralytics/yolov3 - - Arguments: - pretrained (bool): load pretrained weights into the model, default=False - channels (int): number of input channels, default=3 - classes (int): number of model classes, default=80 - - Returns: - pytorch model - """ - return create('yolov3-spp', pretrained, channels, classes, autoshape) - - -def yolov3_tiny(pretrained=False, channels=3, classes=80, autoshape=True): - """YOLOv3-tiny model from https://github.com/ultralytics/yolov3 - - Arguments: - pretrained (bool): load pretrained weights into the model, default=False - channels (int): number of input channels, default=3 - classes (int): number of model classes, default=80 - - Returns: - pytorch model - """ - return create('yolov3-tiny', pretrained, channels, classes, autoshape) - - def custom(path_or_model='path/to/model.pt', autoshape=True): - """YOLOv3-custom model from https://github.com/ultralytics/yolov3 + """YOLOv3-custom model https://github.com/ultralytics/yolov3 Arguments (3 options): path_or_model (str): 'path/to/model.pt' @@ -106,12 +68,30 @@ def custom(path_or_model='path/to/model.pt', autoshape=True): """ model = torch.load(path_or_model) if isinstance(path_or_model, str) else path_or_model # load checkpoint if isinstance(model, dict): - model = model['model'] # load model + model = model['ema' if model.get('ema') else 'model'] # load model hub_model = Model(model.yaml).to(next(model.parameters()).device) # create hub_model.load_state_dict(model.float().state_dict()) # load state_dict hub_model.names = model.names # class names - return hub_model.autoshape() if autoshape else hub_model + if autoshape: + hub_model = hub_model.autoshape() # for file/URI/PIL/cv2/np inputs and NMS + device = select_device('0' if torch.cuda.is_available() else 'cpu') # default to GPU if available + return hub_model.to(device) + + +def yolov3(pretrained=True, channels=3, classes=80, autoshape=True): + # YOLOv3 model https://github.com/ultralytics/yolov3 + return create('yolov3', pretrained, channels, classes, autoshape) + + +def yolov3_spp(pretrained=True, channels=3, classes=80, autoshape=True): + # YOLOv3-SPP model https://github.com/ultralytics/yolov3 + return create('yolov3-spp', pretrained, channels, classes, autoshape) + + +def yolov3_tiny(pretrained=True, channels=3, classes=80, autoshape=True): + # YOLOv3-tiny model https://github.com/ultralytics/yolov3 + return create('yolov3-tiny', pretrained, channels, classes, autoshape) if __name__ == '__main__': @@ -119,9 +99,14 @@ def custom(path_or_model='path/to/model.pt', autoshape=True): # model = custom(path_or_model='path/to/model.pt') # custom example # Verify inference + import numpy as np from PIL import Image - imgs = [Image.open(x) for x in Path('data/images').glob('*.jpg')] - results = model(imgs) - results.show() + imgs = [Image.open('data/images/bus.jpg'), # PIL + 'data/images/zidane.jpg', # filename + 'https://github.com/ultralytics/yolov3/raw/master/data/images/bus.jpg', # URI + np.zeros((640, 480, 3))] # numpy + + results = model(imgs) # batched inference results.print() + results.save() diff --git a/models/common.py b/models/common.py index fd9d9fcdd7..9496b1b493 100644 --- a/models/common.py +++ b/models/common.py @@ -1,16 +1,21 @@ -# This file contains modules common to various models +# YOLOv3 common modules import math +from copy import copy +from pathlib import Path import numpy as np +import pandas as pd import requests import torch import torch.nn as nn -from PIL import Image, ImageDraw +from PIL import Image +from torch.cuda import amp from utils.datasets import letterbox -from utils.general import non_max_suppression, make_divisible, scale_coords, xyxy2xywh -from utils.plots import color_list +from utils.general import non_max_suppression, make_divisible, scale_coords, increment_path, xyxy2xywh +from utils.plots import color_list, plot_one_box +from utils.torch_utils import time_synchronized def autopad(k, p=None): # kernel, padding @@ -40,6 +45,52 @@ def fuseforward(self, x): return self.act(self.conv(x)) +class TransformerLayer(nn.Module): + # Transformer layer https://arxiv.org/abs/2010.11929 (LayerNorm layers removed for better performance) + def __init__(self, c, num_heads): + super().__init__() + self.q = nn.Linear(c, c, bias=False) + self.k = nn.Linear(c, c, bias=False) + self.v = nn.Linear(c, c, bias=False) + self.ma = nn.MultiheadAttention(embed_dim=c, num_heads=num_heads) + self.fc1 = nn.Linear(c, c, bias=False) + self.fc2 = nn.Linear(c, c, bias=False) + + def forward(self, x): + x = self.ma(self.q(x), self.k(x), self.v(x))[0] + x + x = self.fc2(self.fc1(x)) + x + return x + + +class TransformerBlock(nn.Module): + # Vision Transformer https://arxiv.org/abs/2010.11929 + def __init__(self, c1, c2, num_heads, num_layers): + super().__init__() + self.conv = None + if c1 != c2: + self.conv = Conv(c1, c2) + self.linear = nn.Linear(c2, c2) # learnable position embedding + self.tr = nn.Sequential(*[TransformerLayer(c2, num_heads) for _ in range(num_layers)]) + self.c2 = c2 + + def forward(self, x): + if self.conv is not None: + x = self.conv(x) + b, _, w, h = x.shape + p = x.flatten(2) + p = p.unsqueeze(0) + p = p.transpose(0, 3) + p = p.squeeze(3) + e = self.linear(p) + x = p + e + + x = self.tr(x) + x = x.unsqueeze(3) + x = x.transpose(0, 3) + x = x.reshape(b, self.c2, w, h) + return x + + class Bottleneck(nn.Module): # Standard bottleneck def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion @@ -87,6 +138,14 @@ def forward(self, x): return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1)) +class C3TR(C3): + # C3 module with TransformerBlock() + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): + super().__init__(c1, c2, n, shortcut, g, e) + c_ = int(c2 * e) + self.m = TransformerBlock(c_, c_, 4, n) + + class SPP(nn.Module): # Spatial pyramid pooling layer used in YOLOv3-SPP def __init__(self, c1, c2, k=(5, 9, 13)): @@ -166,7 +225,6 @@ def forward(self, x): class autoShape(nn.Module): # input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS - img_size = 640 # inference size (pixels) conf = 0.25 # NMS confidence threshold iou = 0.45 # NMS IoU threshold classes = None # (optional list) filter by class @@ -179,27 +237,33 @@ def autoshape(self): print('autoShape already enabled, skipping... ') # model already converted to model.autoshape() return self + @torch.no_grad() def forward(self, imgs, size=640, augment=False, profile=False): - # Inference from various sources. For height=720, width=1280, RGB images example inputs are: + # Inference from various sources. For height=640, width=1280, RGB images example inputs are: # filename: imgs = 'data/samples/zidane.jpg' # URI: = 'https://github.com/ultralytics/yolov5/releases/download/v1.0/zidane.jpg' - # OpenCV: = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(720,1280,3) - # PIL: = Image.open('image.jpg') # HWC x(720,1280,3) - # numpy: = np.zeros((720,1280,3)) # HWC - # torch: = torch.zeros(16,3,720,1280) # BCHW + # OpenCV: = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(640,1280,3) + # PIL: = Image.open('image.jpg') # HWC x(640,1280,3) + # numpy: = np.zeros((640,1280,3)) # HWC + # torch: = torch.zeros(16,3,320,640) # BCHW (scaled to size=640, 0-1 values) # multiple: = [Image.open('image1.jpg'), Image.open('image2.jpg'), ...] # list of images + t = [time_synchronized()] p = next(self.model.parameters()) # for device and type if isinstance(imgs, torch.Tensor): # torch - return self.model(imgs.to(p.device).type_as(p), augment, profile) # inference + with amp.autocast(enabled=p.device.type != 'cpu'): + return self.model(imgs.to(p.device).type_as(p), augment, profile) # inference # Pre-process n, imgs = (len(imgs), imgs) if isinstance(imgs, list) else (1, [imgs]) # number of images, list of images - shape0, shape1 = [], [] # image and inference shapes + shape0, shape1, files = [], [], [] # image and inference shapes, filenames for i, im in enumerate(imgs): + f = f'image{i}' # filename if isinstance(im, str): # filename or uri - im = Image.open(requests.get(im, stream=True).raw if im.startswith('http') else im) # open - im = np.array(im) # to numpy + im, f = np.asarray(Image.open(requests.get(im, stream=True).raw if im.startswith('http') else im)), im + elif isinstance(im, Image.Image): # PIL Image + im, f = np.asarray(im), getattr(im, 'filename', f) or f + files.append(Path(f).with_suffix('.jpg').name) if im.shape[0] < 5: # image in CHW im = im.transpose((1, 2, 0)) # reverse dataloader .transpose(2, 0, 1) im = im[:, :, :3] if im.ndim == 3 else np.tile(im[:, :, None], 3) # enforce 3ch input @@ -213,82 +277,101 @@ def forward(self, imgs, size=640, augment=False, profile=False): x = np.stack(x, 0) if n > 1 else x[0][None] # stack x = np.ascontiguousarray(x.transpose((0, 3, 1, 2))) # BHWC to BCHW x = torch.from_numpy(x).to(p.device).type_as(p) / 255. # uint8 to fp16/32 + t.append(time_synchronized()) - # Inference - with torch.no_grad(): + with amp.autocast(enabled=p.device.type != 'cpu'): + # Inference y = self.model(x, augment, profile)[0] # forward - y = non_max_suppression(y, conf_thres=self.conf, iou_thres=self.iou, classes=self.classes) # NMS + t.append(time_synchronized()) - # Post-process - for i in range(n): - scale_coords(shape1, y[i][:, :4], shape0[i]) + # Post-process + y = non_max_suppression(y, conf_thres=self.conf, iou_thres=self.iou, classes=self.classes) # NMS + for i in range(n): + scale_coords(shape1, y[i][:, :4], shape0[i]) - return Detections(imgs, y, self.names) + t.append(time_synchronized()) + return Detections(imgs, y, files, t, self.names, x.shape) class Detections: - # detections class for YOLOv5 inference results - def __init__(self, imgs, pred, names=None): + # detections class for YOLOv3 inference results + def __init__(self, imgs, pred, files, times=None, names=None, shape=None): super(Detections, self).__init__() d = pred[0].device # device gn = [torch.tensor([*[im.shape[i] for i in [1, 0, 1, 0]], 1., 1.], device=d) for im in imgs] # normalizations self.imgs = imgs # list of images as numpy arrays self.pred = pred # list of tensors pred[0] = (xyxy, conf, cls) self.names = names # class names + self.files = files # image filenames self.xyxy = pred # xyxy pixels self.xywh = [xyxy2xywh(x) for x in pred] # xywh pixels self.xyxyn = [x / g for x, g in zip(self.xyxy, gn)] # xyxy normalized self.xywhn = [x / g for x, g in zip(self.xywh, gn)] # xywh normalized - self.n = len(self.pred) + self.n = len(self.pred) # number of images (batch size) + self.t = tuple((times[i + 1] - times[i]) * 1000 / self.n for i in range(3)) # timestamps (ms) + self.s = shape # inference BCHW shape - def display(self, pprint=False, show=False, save=False, render=False): + def display(self, pprint=False, show=False, save=False, render=False, save_dir=''): colors = color_list() for i, (img, pred) in enumerate(zip(self.imgs, self.pred)): - str = f'Image {i + 1}/{len(self.pred)}: {img.shape[0]}x{img.shape[1]} ' + str = f'image {i + 1}/{len(self.pred)}: {img.shape[0]}x{img.shape[1]} ' if pred is not None: for c in pred[:, -1].unique(): n = (pred[:, -1] == c).sum() # detections per class - str += f'{n} {self.names[int(c)]}s, ' # add to string + str += f"{n} {self.names[int(c)]}{'s' * (n > 1)}, " # add to string if show or save or render: - img = Image.fromarray(img.astype(np.uint8)) if isinstance(img, np.ndarray) else img # from np for *box, conf, cls in pred: # xyxy, confidence, class - # str += '%s %.2f, ' % (names[int(cls)], conf) # label - ImageDraw.Draw(img).rectangle(box, width=4, outline=colors[int(cls) % 10]) # plot + label = f'{self.names[int(cls)]} {conf:.2f}' + plot_one_box(box, img, label=label, color=colors[int(cls) % 10]) + img = Image.fromarray(img.astype(np.uint8)) if isinstance(img, np.ndarray) else img # from np if pprint: - print(str) + print(str.rstrip(', ')) if show: - img.show(f'Image {i}') # show + img.show(self.files[i]) # show if save: - f = f'results{i}.jpg' - str += f"saved to '{f}'" - img.save(f) # save + f = self.files[i] + img.save(Path(save_dir) / f) # save + print(f"{'Saved' * (i == 0)} {f}", end=',' if i < self.n - 1 else f' to {save_dir}\n') if render: self.imgs[i] = np.asarray(img) def print(self): self.display(pprint=True) # print results + print(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {tuple(self.s)}' % self.t) def show(self): self.display(show=True) # show results - def save(self): - self.display(save=True) # save results + def save(self, save_dir='runs/hub/exp'): + save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/hub/exp') # increment save_dir + Path(save_dir).mkdir(parents=True, exist_ok=True) + self.display(save=True, save_dir=save_dir) # save results def render(self): self.display(render=True) # render results return self.imgs - def __len__(self): - return self.n + def pandas(self): + # return detections as pandas DataFrames, i.e. print(results.pandas().xyxy[0]) + new = copy(self) # return copy + ca = 'xmin', 'ymin', 'xmax', 'ymax', 'confidence', 'class', 'name' # xyxy columns + cb = 'xcenter', 'ycenter', 'width', 'height', 'confidence', 'class', 'name' # xywh columns + for k, c in zip(['xyxy', 'xyxyn', 'xywh', 'xywhn'], [ca, ca, cb, cb]): + a = [[x[:5] + [int(x[5]), self.names[int(x[5])]] for x in x.tolist()] for x in getattr(self, k)] # update + setattr(new, k, [pd.DataFrame(x, columns=c) for x in a]) + return new def tolist(self): # return a list of Detections objects, i.e. 'for result in results.tolist():' - x = [Detections([self.imgs[i]], [self.pred[i]], self.names) for i in range(self.n)] + x = [Detections([self.imgs[i]], [self.pred[i]], self.names, self.s) for i in range(self.n)] for d in x: for k in ['imgs', 'pred', 'xyxy', 'xyxyn', 'xywh', 'xywhn']: setattr(d, k, getattr(d, k)[0]) # pop out of list return x + def __len__(self): + return self.n + class Classify(nn.Module): # Classification head, i.e. x(b,c1,20,20) to x(b,c2) diff --git a/models/experimental.py b/models/experimental.py index 2dbbf7fa32..622791540c 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -1,4 +1,4 @@ -# This file contains experimental modules +# YOLOv3 experimental modules import numpy as np import torch @@ -58,7 +58,7 @@ def forward(self, x): class GhostBottleneck(nn.Module): # Ghost Bottleneck https://github.com/huawei-noah/ghostnet - def __init__(self, c1, c2, k, s): + def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride super(GhostBottleneck, self).__init__() c_ = c2 // 2 self.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # pw @@ -115,11 +115,12 @@ def attempt_load(weights, map_location=None): model = Ensemble() for w in weights if isinstance(weights, list) else [weights]: attempt_download(w) - model.append(torch.load(w, map_location=map_location)['model'].float().fuse().eval()) # load FP32 model + ckpt = torch.load(w, map_location=map_location) # load + model.append(ckpt['ema' if ckpt.get('ema') else 'model'].float().fuse().eval()) # FP32 model # Compatibility updates for m in model.modules(): - if type(m) in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6]: + if type(m) in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU]: m.inplace = True # pytorch 1.7.0 compatibility elif type(m) is Conv: m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility diff --git a/models/export.py b/models/export.py index 49df43e9fe..99189601a0 100644 --- a/models/export.py +++ b/models/export.py @@ -1,4 +1,4 @@ -"""Exports a YOLOv5 *.pt model to ONNX and TorchScript formats +"""Exports a YOLOv3 *.pt model to ONNX and TorchScript formats Usage: $ export PYTHONPATH="$PWD" && python models/export.py --weights ./weights/yolov3.pt --img 640 --batch 1 @@ -17,12 +17,16 @@ from models.experimental import attempt_load from utils.activations import Hardswish, SiLU from utils.general import set_logging, check_img_size +from utils.torch_utils import select_device if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--weights', type=str, default='./yolov3.pt', help='weights path') # from yolov3/models/ parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='image size') # height, width parser.add_argument('--batch-size', type=int, default=1, help='batch size') + parser.add_argument('--dynamic', action='store_true', help='dynamic ONNX axes') + parser.add_argument('--grid', action='store_true', help='export Detect() layer grid') + parser.add_argument('--device', default='cpu', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') opt = parser.parse_args() opt.img_size *= 2 if len(opt.img_size) == 1 else 1 # expand print(opt) @@ -30,7 +34,8 @@ t = time.time() # Load PyTorch model - model = attempt_load(opt.weights, map_location=torch.device('cpu')) # load FP32 model + device = select_device(opt.device) + model = attempt_load(opt.weights, map_location=device) # load FP32 model labels = model.names # Checks @@ -38,7 +43,7 @@ opt.img_size = [check_img_size(x, gs) for x in opt.img_size] # verify img_size are gs-multiples # Input - img = torch.zeros(opt.batch_size, 3, *opt.img_size) # image size(1,3,320,192) iDetection + img = torch.zeros(opt.batch_size, 3, *opt.img_size).to(device) # image size(1,3,320,192) iDetection # Update model for k, m in model.named_modules(): @@ -50,14 +55,14 @@ m.act = SiLU() # elif isinstance(m, models.yolo.Detect): # m.forward = m.forward_export # assign forward (optional) - model.model[-1].export = True # set Detect() layer export=True + model.model[-1].export = not opt.grid # set Detect() layer grid export y = model(img) # dry run # TorchScript export try: print('\nStarting TorchScript export with torch %s...' % torch.__version__) f = opt.weights.replace('.pt', '.torchscript.pt') # filename - ts = torch.jit.trace(model, img) + ts = torch.jit.trace(model, img, strict=False) ts.save(f) print('TorchScript export success, saved as %s' % f) except Exception as e: @@ -70,7 +75,9 @@ print('\nStarting ONNX export with onnx %s...' % onnx.__version__) f = opt.weights.replace('.pt', '.onnx') # filename torch.onnx.export(model, img, f, verbose=False, opset_version=12, input_names=['images'], - output_names=['classes', 'boxes'] if y is None else ['output']) + output_names=['classes', 'boxes'] if y is None else ['output'], + dynamic_axes={'images': {0: 'batch', 2: 'height', 3: 'width'}, # size(1,3,640,640) + 'output': {0: 'batch', 2: 'y', 3: 'x'}} if opt.dynamic else None) # Checks onnx_model = onnx.load(f) # load onnx model diff --git a/models/yolo.py b/models/yolo.py index 9f47100999..706ea20e12 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -1,14 +1,15 @@ +# YOLOv3 YOLO-specific modules + import argparse import logging import sys from copy import deepcopy -from pathlib import Path sys.path.append('./') # to run '$ python *.py' files in subdirectories logger = logging.getLogger(__name__) from models.common import * -from models.experimental import MixConv2d, CrossConv +from models.experimental import * from utils.autoanchor import check_anchor_order from utils.general import make_divisible, check_file, set_logging from utils.torch_utils import time_synchronized, fuse_conv_and_bn, model_info, scale_img, initialize_weights, \ @@ -50,7 +51,7 @@ def forward(self, x): self.grid[i] = self._make_grid(nx, ny).to(x[i].device) y = x[i].sigmoid() - y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + self.grid[i].to(x[i].device)) * self.stride[i] # xy + y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + self.grid[i]) * self.stride[i] # xy y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh z.append(y.view(bs, -1, self.no)) @@ -63,7 +64,7 @@ def _make_grid(nx=20, ny=20): class Model(nn.Module): - def __init__(self, cfg='yolov3.yaml', ch=3, nc=None): # model, input channels, number of classes + def __init__(self, cfg='yolov3.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classes super(Model, self).__init__() if isinstance(cfg, dict): self.yaml = cfg # model dict @@ -71,13 +72,16 @@ def __init__(self, cfg='yolov3.yaml', ch=3, nc=None): # model, input channels, import yaml # for torch hub self.yaml_file = Path(cfg).name with open(cfg) as f: - self.yaml = yaml.load(f, Loader=yaml.FullLoader) # model dict + self.yaml = yaml.load(f, Loader=yaml.SafeLoader) # model dict # Define model ch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channels if nc and nc != self.yaml['nc']: - logger.info('Overriding model.yaml nc=%g with nc=%g' % (self.yaml['nc'], nc)) + logger.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}") self.yaml['nc'] = nc # override yaml value + if anchors: + logger.info(f'Overriding model.yaml anchors with anchors={anchors}') + self.yaml['anchors'] = round(anchors) # override yaml value self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelist self.names = [str(i) for i in range(self.yaml['nc'])] # default names # print([x.shape for x in self.forward(torch.zeros(1, ch, 64, 64))]) @@ -107,7 +111,7 @@ def forward(self, x, augment=False, profile=False): for si, fi in zip(s, f): xi = scale_img(x.flip(fi) if fi else x, si, gs=int(self.stride.max())) yi = self.forward_once(xi)[0] # forward - # cv2.imwrite('img%g.jpg' % s, 255 * xi[0].numpy().transpose((1, 2, 0))[:, :, ::-1]) # save + # cv2.imwrite(f'img_{si}.jpg', 255 * xi[0].cpu().numpy().transpose((1, 2, 0))[:, :, ::-1]) # save yi[..., :4] /= si # de-scale if fi == 2: yi[..., 1] = img_size[0] - yi[..., 1] # de-flip ud @@ -210,45 +214,30 @@ def parse_model(d, ch): # model_dict, input_channels(3) pass n = max(round(n * gd), 1) if n > 1 else n # depth gain - if m in [Conv, Bottleneck, SPP, DWConv, MixConv2d, Focus, CrossConv, BottleneckCSP, C3]: + if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, DWConv, MixConv2d, Focus, CrossConv, BottleneckCSP, + C3, C3TR]: c1, c2 = ch[f], args[0] - - # Normal - # if i > 0 and args[0] != no: # channel expansion factor - # ex = 1.75 # exponential (default 2.0) - # e = math.log(c2 / ch[1]) / math.log(2) - # c2 = int(ch[1] * ex ** e) - # if m != Focus: - - c2 = make_divisible(c2 * gw, 8) if c2 != no else c2 - - # Experimental - # if i > 0 and args[0] != no: # channel expansion factor - # ex = 1 + gw # exponential (default 2.0) - # ch1 = 32 # ch[1] - # e = math.log(c2 / ch1) / math.log(2) # level 1-n - # c2 = int(ch1 * ex ** e) - # if m != Focus: - # c2 = make_divisible(c2, 8) if c2 != no else c2 + if c2 != no: # if not output + c2 = make_divisible(c2 * gw, 8) args = [c1, c2, *args[1:]] - if m in [BottleneckCSP, C3]: - args.insert(2, n) + if m in [BottleneckCSP, C3, C3TR]: + args.insert(2, n) # number of repeats n = 1 elif m is nn.BatchNorm2d: args = [ch[f]] elif m is Concat: - c2 = sum([ch[x if x < 0 else x + 1] for x in f]) + c2 = sum([ch[x] for x in f]) elif m is Detect: - args.append([ch[x + 1] for x in f]) + args.append([ch[x] for x in f]) if isinstance(args[1], int): # number of anchors args[1] = [list(range(args[1] * 2))] * len(f) elif m is Contract: - c2 = ch[f if f < 0 else f + 1] * args[0] ** 2 + c2 = ch[f] * args[0] ** 2 elif m is Expand: - c2 = ch[f if f < 0 else f + 1] // args[0] ** 2 + c2 = ch[f] // args[0] ** 2 else: - c2 = ch[f if f < 0 else f + 1] + c2 = ch[f] m_ = nn.Sequential(*[m(*args) for _ in range(n)]) if n > 1 else m(*args) # module t = str(m)[8:-2].replace('__main__.', '') # module type @@ -257,6 +246,8 @@ def parse_model(d, ch): # model_dict, input_channels(3) logger.info('%3s%18s%3s%10.0f %-40s%-30s' % (i, f, n, np, t, args)) # print save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist layers.append(m_) + if i == 0: + ch = [] ch.append(c2) return nn.Sequential(*layers), sorted(save) diff --git a/requirements.txt b/requirements.txt index 3c23f2b750..fd187eb56c 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,19 +1,18 @@ # pip install -r requirements.txt # base ---------------------------------------- -Cython matplotlib>=3.2.2 numpy>=1.18.5 opencv-python>=4.1.2 Pillow -PyYAML>=5.3 +PyYAML>=5.3.1 scipy>=1.4.1 -tensorboard>=2.2 torch>=1.7.0 torchvision>=0.8.1 tqdm>=4.41.0 # logging ------------------------------------- +tensorboard>=2.4.1 # wandb # plotting ------------------------------------ @@ -21,8 +20,8 @@ seaborn>=0.11.0 pandas # export -------------------------------------- -# coremltools==4.0 -# onnx>=1.8.0 +# coremltools>=4.1 +# onnx>=1.8.1 # scikit-learn==0.19.2 # for coreml quantization # extras -------------------------------------- diff --git a/test.py b/test.py index c570a7889a..0b7f61c106 100644 --- a/test.py +++ b/test.py @@ -13,7 +13,6 @@ from utils.datasets import create_dataloader from utils.general import coco80_to_coco91_class, check_dataset, check_file, check_img_size, check_requirements, \ box_iou, non_max_suppression, scale_coords, xyxy2xywh, xywh2xyxy, set_logging, increment_path, colorstr -from utils.loss import compute_loss from utils.metrics import ap_per_class, ConfusionMatrix from utils.plots import plot_images, output_to_target, plot_study_txt from utils.torch_utils import select_device, time_synchronized @@ -36,8 +35,10 @@ def test(data, save_hybrid=False, # for hybrid auto-labelling save_conf=False, # save auto-label confidences plots=True, - log_imgs=0): # number of logged images - + wandb_logger=None, + compute_loss=None, + half_precision=True, + is_coco=False): # Initialize/load model and set device training = model is not None if training: # called by train.py @@ -53,47 +54,46 @@ def test(data, # Load model model = attempt_load(weights, map_location=device) # load FP32 model - imgsz = check_img_size(imgsz, s=model.stride.max()) # check img_size + gs = max(int(model.stride.max()), 32) # grid size (max stride) + imgsz = check_img_size(imgsz, s=gs) # check img_size # Multi-GPU disabled, incompatible with .half() https://github.com/ultralytics/yolov5/issues/99 # if device.type != 'cpu' and torch.cuda.device_count() > 1: # model = nn.DataParallel(model) # Half - half = device.type != 'cpu' # half precision only supported on CUDA + half = device.type != 'cpu' and half_precision # half precision only supported on CUDA if half: model.half() # Configure model.eval() - is_coco = data.endswith('coco.yaml') # is COCO dataset - with open(data) as f: - data = yaml.load(f, Loader=yaml.FullLoader) # model dict + if isinstance(data, str): + is_coco = data.endswith('coco.yaml') + with open(data) as f: + data = yaml.load(f, Loader=yaml.SafeLoader) check_dataset(data) # check nc = 1 if single_cls else int(data['nc']) # number of classes iouv = torch.linspace(0.5, 0.95, 10).to(device) # iou vector for mAP@0.5:0.95 niou = iouv.numel() # Logging - log_imgs, wandb = min(log_imgs, 100), None # ceil - try: - import wandb # Weights & Biases - except ImportError: - log_imgs = 0 - + log_imgs = 0 + if wandb_logger and wandb_logger.wandb: + log_imgs = min(wandb_logger.log_imgs, 100) # Dataloader if not training: - img = torch.zeros((1, 3, imgsz, imgsz), device=device) # init img - _ = model(img.half() if half else img) if device.type != 'cpu' else None # run once - path = data['test'] if opt.task == 'test' else data['val'] # path to val/test images - dataloader = create_dataloader(path, imgsz, batch_size, model.stride.max(), opt, pad=0.5, rect=True, - prefix=colorstr('test: ' if opt.task == 'test' else 'val: '))[0] + if device.type != 'cpu': + model(torch.zeros(1, 3, imgsz, imgsz).to(device).type_as(next(model.parameters()))) # run once + task = opt.task if opt.task in ('train', 'val', 'test') else 'val' # path to train/val/test images + dataloader = create_dataloader(data[task], imgsz, batch_size, gs, opt, pad=0.5, rect=True, + prefix=colorstr(f'{task}: '))[0] seen = 0 confusion_matrix = ConfusionMatrix(nc=nc) names = {k: v for k, v in enumerate(model.names if hasattr(model, 'names') else model.module.names)} coco91class = coco80_to_coco91_class() - s = ('%20s' + '%12s' * 6) % ('Class', 'Images', 'Targets', 'P', 'R', 'mAP@.5', 'mAP@.5:.95') + s = ('%20s' + '%12s' * 6) % ('Class', 'Images', 'Labels', 'P', 'R', 'mAP@.5', 'mAP@.5:.95') p, r, f1, mp, mr, map50, map, t0, t1 = 0., 0., 0., 0., 0., 0., 0., 0., 0. loss = torch.zeros(3, device=device) jdict, stats, ap, ap_class, wandb_images = [], [], [], [], [] @@ -107,22 +107,22 @@ def test(data, with torch.no_grad(): # Run model t = time_synchronized() - inf_out, train_out = model(img, augment=augment) # inference and training outputs + out, train_out = model(img, augment=augment) # inference and training outputs t0 += time_synchronized() - t # Compute loss - if training: - loss += compute_loss([x.float() for x in train_out], targets, model)[1][:3] # box, obj, cls + if compute_loss: + loss += compute_loss([x.float() for x in train_out], targets)[1][:3] # box, obj, cls # Run NMS targets[:, 2:] *= torch.Tensor([width, height, width, height]).to(device) # to pixels lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling t = time_synchronized() - output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres, labels=lb) + out = non_max_suppression(out, conf_thres=conf_thres, iou_thres=iou_thres, labels=lb, multi_label=True) t1 += time_synchronized() - t # Statistics per image - for si, pred in enumerate(output): + for si, pred in enumerate(out): labels = targets[targets[:, 0] == si, 1:] nl = len(labels) tcls = labels[:, 0].tolist() if nl else [] # target class @@ -147,15 +147,17 @@ def test(data, with open(save_dir / 'labels' / (path.stem + '.txt'), 'a') as f: f.write(('%g ' * len(line)).rstrip() % line + '\n') - # W&B logging - if plots and len(wandb_images) < log_imgs: - box_data = [{"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, - "class_id": int(cls), - "box_caption": "%s %.3f" % (names[cls], conf), - "scores": {"class_score": conf}, - "domain": "pixel"} for *xyxy, conf, cls in pred.tolist()] - boxes = {"predictions": {"box_data": box_data, "class_labels": names}} # inference-space - wandb_images.append(wandb.Image(img[si], boxes=boxes, caption=path.name)) + # W&B logging - Media Panel Plots + if len(wandb_images) < log_imgs and wandb_logger.current_epoch > 0: # Check for test operation + if wandb_logger.current_epoch % wandb_logger.bbox_interval == 0: + box_data = [{"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, + "class_id": int(cls), + "box_caption": "%s %.3f" % (names[cls], conf), + "scores": {"class_score": conf}, + "domain": "pixel"} for *xyxy, conf, cls in pred.tolist()] + boxes = {"predictions": {"box_data": box_data, "class_labels": names}} # inference-space + wandb_images.append(wandb_logger.wandb.Image(img[si], boxes=boxes, caption=path.name)) + wandb_logger.log_training_progress(predn, path, names) if wandb_logger and wandb_logger.wandb_run else None # Append to pycocotools JSON dictionary if save_json: @@ -179,7 +181,7 @@ def test(data, tbox = xywh2xyxy(labels[:, 1:5]) scale_coords(img[si].shape[1:], tbox, shapes[si][0], shapes[si][1]) # native-space labels if plots: - confusion_matrix.process_batch(pred, torch.cat((labels[:, 0:1], tbox), 1)) + confusion_matrix.process_batch(predn, torch.cat((labels[:, 0:1], tbox), 1)) # Per target class for cls in torch.unique(tcls_tensor): @@ -210,24 +212,24 @@ def test(data, f = save_dir / f'test_batch{batch_i}_labels.jpg' # labels Thread(target=plot_images, args=(img, targets, paths, f, names), daemon=True).start() f = save_dir / f'test_batch{batch_i}_pred.jpg' # predictions - Thread(target=plot_images, args=(img, output_to_target(output), paths, f, names), daemon=True).start() + Thread(target=plot_images, args=(img, output_to_target(out), paths, f, names), daemon=True).start() # Compute statistics stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy if len(stats) and stats[0].any(): p, r, ap, f1, ap_class = ap_per_class(*stats, plot=plots, save_dir=save_dir, names=names) - p, r, ap50, ap = p[:, 0], r[:, 0], ap[:, 0], ap.mean(1) # [P, R, AP@0.5, AP@0.5:0.95] + ap50, ap = ap[:, 0], ap.mean(1) # AP@0.5, AP@0.5:0.95 mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean() nt = np.bincount(stats[3].astype(np.int64), minlength=nc) # number of targets per class else: nt = torch.zeros(1) # Print results - pf = '%20s' + '%12.3g' * 6 # print format + pf = '%20s' + '%12i' * 2 + '%12.3g' * 4 # print format print(pf % ('all', seen, nt.sum(), mp, mr, map50, map)) # Print results per class - if (verbose or (nc <= 20 and not training)) and nc > 1 and len(stats): + if (verbose or (nc < 50 and not training)) and nc > 1 and len(stats): for i, c in enumerate(ap_class): print(pf % (names[c], seen, nt[c], p[i], r[i], ap50[i], ap[i])) @@ -239,9 +241,11 @@ def test(data, # Plots if plots: confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) - if wandb and wandb.run: - wandb.log({"Images": wandb_images}) - wandb.log({"Validation": [wandb.Image(str(f), caption=f.name) for f in sorted(save_dir.glob('test*.jpg'))]}) + if wandb_logger and wandb_logger.wandb: + val_batches = [wandb_logger.wandb.Image(str(f), caption=f.name) for f in sorted(save_dir.glob('test*.jpg'))] + wandb_logger.log({"Validation": val_batches}) + if wandb_images: + wandb_logger.log({"Bounding Box Debugger/Images": wandb_images}) # Save JSON if save_json and len(jdict): @@ -269,10 +273,10 @@ def test(data, print(f'pycocotools unable to run: {e}') # Return results + model.float() # for training if not training: s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' print(f"Results saved to {save_dir}{s}") - model.float() # for training maps = np.zeros(nc) + map for i, c in enumerate(ap_class): maps[c] = ap[i] @@ -287,7 +291,7 @@ def test(data, parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') parser.add_argument('--iou-thres', type=float, default=0.6, help='IOU threshold for NMS') - parser.add_argument('--task', default='val', help="'val', 'test', 'study'") + parser.add_argument('--task', default='val', help='train, val, test, speed or study') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') parser.add_argument('--augment', action='store_true', help='augmented inference') @@ -305,7 +309,7 @@ def test(data, print(opt) check_requirements() - if opt.task in ['val', 'test']: # run normally + if opt.task in ('train', 'val', 'test'): # run normally test(opt.data, opt.weights, opt.batch_size, @@ -321,16 +325,21 @@ def test(data, save_conf=opt.save_conf, ) + elif opt.task == 'speed': # speed benchmarks + for w in opt.weights: + test(opt.data, w, opt.batch_size, opt.img_size, 0.25, 0.45, save_json=False, plots=False) + elif opt.task == 'study': # run over a range of settings and save/plot - for weights in ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt']: - f = 'study_%s_%s.txt' % (Path(opt.data).stem, Path(weights).stem) # filename to save to - x = list(range(320, 800, 64)) # x axis + # python test.py --task study --data coco.yaml --iou 0.7 --weights yolov3.pt yolov3-spp.pt yolov3-tiny.pt + x = list(range(256, 1536 + 128, 128)) # x axis (image sizes) + for w in opt.weights: + f = f'study_{Path(opt.data).stem}_{Path(w).stem}.txt' # filename to save to y = [] # y axis for i in x: # img-size - print('\nRunning %s point %s...' % (f, i)) - r, _, t = test(opt.data, weights, opt.batch_size, i, opt.conf_thres, opt.iou_thres, opt.save_json, + print(f'\nRunning {f} point {i}...') + r, _, t = test(opt.data, w, opt.batch_size, i, opt.conf_thres, opt.iou_thres, opt.save_json, plots=False) y.append(r + t) # results and times np.savetxt(f, y, fmt='%10.4g') # save os.system('zip -r study.zip study_*.txt') - plot_study_txt(f, x) # plot + plot_study_txt(x=x) # plot diff --git a/train.py b/train.py index 91d8dfe033..ff7d96b772 100644 --- a/train.py +++ b/train.py @@ -4,6 +4,7 @@ import os import random import time +from copy import deepcopy from pathlib import Path from threading import Thread @@ -29,14 +30,15 @@ fitness, strip_optimizer, get_latest_run, check_dataset, check_file, check_git_status, check_img_size, \ check_requirements, print_mutation, set_logging, one_cycle, colorstr from utils.google_utils import attempt_download -from utils.loss import compute_loss +from utils.loss import ComputeLoss from utils.plots import plot_images, plot_labels, plot_results, plot_evolution -from utils.torch_utils import ModelEMA, select_device, intersect_dicts, torch_distributed_zero_first +from utils.torch_utils import ModelEMA, select_device, intersect_dicts, torch_distributed_zero_first, is_parallel +from utils.wandb_logging.wandb_utils import WandbLogger, check_wandb_resume logger = logging.getLogger(__name__) -def train(hyp, opt, device, tb_writer=None, wandb=None): +def train(hyp, opt, device, tb_writer=None): logger.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) save_dir, epochs, batch_size, total_batch_size, weights, rank = \ Path(opt.save_dir), opt.epochs, opt.batch_size, opt.total_batch_size, opt.weights, opt.global_rank @@ -60,10 +62,19 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): init_seeds(2 + rank) with open(opt.data) as f: data_dict = yaml.load(f, Loader=yaml.SafeLoader) # data dict - with torch_distributed_zero_first(rank): - check_dataset(data_dict) # check - train_path = data_dict['train'] - test_path = data_dict['val'] + is_coco = opt.data.endswith('coco.yaml') + + # Logging- Doing this before checking the dataset. Might update data_dict + loggers = {'wandb': None} # loggers dict + if rank in [-1, 0]: + opt.hyp = hyp # add hyperparameters + run_id = torch.load(weights).get('wandb_id') if weights.endswith('.pt') and os.path.isfile(weights) else None + wandb_logger = WandbLogger(opt, Path(opt.save_dir).stem, run_id, data_dict) + loggers['wandb'] = wandb_logger.wandb + data_dict = wandb_logger.data_dict + if wandb_logger.wandb: + weights, epochs, hyp = opt.weights, opt.epochs, opt.hyp # WandbLogger might update weights, epochs if resuming + nc = 1 if opt.single_cls else int(data_dict['nc']) # number of classes names = ['item'] if opt.single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names assert len(names) == nc, '%g names found for nc=%g dataset in %s' % (len(names), nc, opt.data) # check @@ -74,16 +85,18 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): with torch_distributed_zero_first(rank): attempt_download(weights) # download if not found locally ckpt = torch.load(weights, map_location=device) # load checkpoint - if hyp.get('anchors'): - ckpt['model'].yaml['anchors'] = round(hyp['anchors']) # force autoanchor - model = Model(opt.cfg or ckpt['model'].yaml, ch=3, nc=nc).to(device) # create - exclude = ['anchor'] if opt.cfg or hyp.get('anchors') else [] # exclude keys + model = Model(opt.cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create + exclude = ['anchor'] if (opt.cfg or hyp.get('anchors')) and not opt.resume else [] # exclude keys state_dict = ckpt['model'].float().state_dict() # to FP32 state_dict = intersect_dicts(state_dict, model.state_dict(), exclude=exclude) # intersect model.load_state_dict(state_dict, strict=False) # load logger.info('Transferred %g/%g items from %s' % (len(state_dict), len(model.state_dict()), weights)) # report else: - model = Model(opt.cfg, ch=3, nc=nc).to(device) # create + model = Model(opt.cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create + with torch_distributed_zero_first(rank): + check_dataset(data_dict) # check + train_path = data_dict['train'] + test_path = data_dict['val'] # Freeze freeze = [] # parameter names to freeze (full or partial) @@ -120,18 +133,15 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): # Scheduler https://arxiv.org/pdf/1812.01187.pdf # https://pytorch.org/docs/stable/_modules/torch/optim/lr_scheduler.html#OneCycleLR - lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] + if opt.linear_lr: + lf = lambda x: (1 - x / (epochs - 1)) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear + else: + lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) - # Logging - if rank in [-1, 0] and wandb and wandb.run is None: - opt.hyp = hyp # add hyperparameters - wandb_run = wandb.init(config=opt, resume="allow", - project='YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem, - name=save_dir.stem, - id=ckpt.get('wandb_id') if 'ckpt' in locals() else None) - loggers = {'wandb': wandb} # loggers dict + # EMA + ema = ModelEMA(model) if rank in [-1, 0] else None # Resume start_epoch, best_fitness = 0, 0.0 @@ -141,10 +151,14 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): optimizer.load_state_dict(ckpt['optimizer']) best_fitness = ckpt['best_fitness'] + # EMA + if ema and ckpt.get('ema'): + ema.ema.load_state_dict(ckpt['ema'].float().state_dict()) + ema.updates = ckpt['updates'] + # Results if ckpt.get('training_results') is not None: - with open(results_file, 'w') as file: - file.write(ckpt['training_results']) # write results.txt + results_file.write_text(ckpt['training_results']) # write results.txt # Epochs start_epoch = ckpt['epoch'] + 1 @@ -158,7 +172,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): del ckpt, state_dict # Image sizes - gs = int(model.stride.max()) # grid size (max stride) + gs = max(int(model.stride.max()), 32) # grid size (max stride) nl = model.model[-1].nl # number of detection layers (used for scaling hyp['obj']) imgsz, imgsz_test = [check_img_size(x, gs) for x in opt.img_size] # verify imgsz are gs-multiples @@ -171,13 +185,6 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) logger.info('Using SyncBatchNorm()') - # EMA - ema = ModelEMA(model) if rank in [-1, 0] else None - - # DDP mode - if cuda and rank != -1: - model = DDP(model, device_ids=[opt.local_rank], output_device=opt.local_rank) - # Trainloader dataloader, dataset = create_dataloader(train_path, imgsz, batch_size, gs, opt, hyp=hyp, augment=True, cache=opt.cache_images, rect=opt.rect, rank=rank, @@ -189,8 +196,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): # Process 0 if rank in [-1, 0]: - ema.updates = start_epoch * nb // accumulate # set EMA updates - testloader = create_dataloader(test_path, imgsz_test, total_batch_size, gs, opt, # testloader + testloader = create_dataloader(test_path, imgsz_test, batch_size * 2, gs, opt, # testloader hyp=hyp, cache=opt.cache_images and not opt.notest, rect=True, rank=-1, world_size=opt.world_size, workers=opt.workers, pad=0.5, prefix=colorstr('val: '))[0] @@ -201,18 +207,26 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): # cf = torch.bincount(c.long(), minlength=nc) + 1. # frequency # model._initialize_biases(cf.to(device)) if plots: - plot_labels(labels, save_dir, loggers) + plot_labels(labels, names, save_dir, loggers) if tb_writer: tb_writer.add_histogram('classes', c, 0) # Anchors if not opt.noautoanchor: check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) + model.half().float() # pre-reduce anchor precision + + # DDP mode + if cuda and rank != -1: + model = DDP(model, device_ids=[opt.local_rank], output_device=opt.local_rank, + # nn.MultiheadAttention incompatibility with DDP https://github.com/pytorch/pytorch/issues/26698 + find_unused_parameters=any(isinstance(layer, nn.MultiheadAttention) for layer in model.modules())) # Model parameters hyp['box'] *= 3. / nl # scale to layers hyp['cls'] *= nc / 80. * 3. / nl # scale to classes and layers hyp['obj'] *= (imgsz / 640) ** 2 * 3. / nl # scale to image size and layers + hyp['label_smoothing'] = opt.label_smoothing model.nc = nc # attach number of classes to model model.hyp = hyp # attach hyperparameters to model model.gr = 1.0 # iou loss ratio (obj_loss = 1.0 or iou) @@ -227,6 +241,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): results = (0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) scheduler.last_epoch = start_epoch - 1 # do not move scaler = amp.GradScaler(enabled=cuda) + compute_loss = ComputeLoss(model) # init loss class logger.info(f'Image sizes {imgsz} train, {imgsz_test} test\n' f'Using {dataloader.num_workers} dataloader workers\n' f'Logging results to {save_dir}\n' @@ -256,7 +271,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): if rank != -1: dataloader.sampler.set_epoch(epoch) pbar = enumerate(dataloader) - logger.info(('\n' + '%10s' * 8) % ('Epoch', 'gpu_mem', 'box', 'obj', 'cls', 'total', 'targets', 'img_size')) + logger.info(('\n' + '%10s' * 8) % ('Epoch', 'gpu_mem', 'box', 'obj', 'cls', 'total', 'labels', 'img_size')) if rank in [-1, 0]: pbar = tqdm(pbar, total=nb) # progress bar optimizer.zero_grad() @@ -286,7 +301,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): # Forward with amp.autocast(enabled=cuda): pred = model(imgs) # forward - loss, loss_items = compute_loss(pred, targets.to(device), model) # loss scaled by batch_size + loss, loss_items = compute_loss(pred, targets.to(device)) # loss scaled by batch_size if rank != -1: loss *= opt.world_size # gradient averaged between devices in DDP mode if opt.quad: @@ -317,9 +332,10 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): Thread(target=plot_images, args=(imgs, targets, paths, f), daemon=True).start() # if tb_writer: # tb_writer.add_image(f, result, dataformats='HWC', global_step=epoch) - # tb_writer.add_graph(model, imgs) # add model to tensorboard - elif plots and ni == 3 and wandb: - wandb.log({"Mosaics": [wandb.Image(str(x), caption=x.name) for x in save_dir.glob('train*.jpg')]}) + # tb_writer.add_graph(torch.jit.trace(model, imgs, strict=False), []) # add model graph + elif plots and ni == 10 and wandb_logger.wandb: + wandb_logger.log({"Mosaics": [wandb_logger.wandb.Image(str(x), caption=x.name) for x in + save_dir.glob('train*.jpg') if x.exists()]}) # end batch ------------------------------------------------------------------------------------------------ # end epoch ---------------------------------------------------------------------------------------------------- @@ -331,23 +347,26 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): # DDP process 0 or single-GPU if rank in [-1, 0]: # mAP - if ema: - ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'gr', 'names', 'stride', 'class_weights']) + ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'gr', 'names', 'stride', 'class_weights']) final_epoch = epoch + 1 == epochs if not opt.notest or final_epoch: # Calculate mAP - results, maps, times = test.test(opt.data, - batch_size=total_batch_size, + wandb_logger.current_epoch = epoch + 1 + results, maps, times = test.test(data_dict, + batch_size=batch_size * 2, imgsz=imgsz_test, model=ema.ema, single_cls=opt.single_cls, dataloader=testloader, save_dir=save_dir, + verbose=nc < 50 and final_epoch, plots=plots and final_epoch, - log_imgs=opt.log_imgs if wandb else 0) + wandb_logger=wandb_logger, + compute_loss=compute_loss, + is_coco=is_coco) # Write with open(results_file, 'a') as f: - f.write(s + '%10.4g' * 7 % results + '\n') # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) + f.write(s + '%10.4g' * 7 % results + '\n') # append metrics, val_loss if len(opt.name) and opt.bucket: os.system('gsutil cp %s gs://%s/results/results%s.txt' % (results_file, opt.bucket, opt.name)) @@ -359,72 +378,77 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): for x, tag in zip(list(mloss[:-1]) + list(results) + lr, tags): if tb_writer: tb_writer.add_scalar(tag, x, epoch) # tensorboard - if wandb: - wandb.log({tag: x}) # W&B + if wandb_logger.wandb: + wandb_logger.log({tag: x}) # W&B # Update best mAP fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] if fi > best_fitness: best_fitness = fi + wandb_logger.end_epoch(best_result=best_fitness == fi) # Save model - save = (not opt.nosave) or (final_epoch and not opt.evolve) - if save: - with open(results_file, 'r') as f: # create checkpoint - ckpt = {'epoch': epoch, - 'best_fitness': best_fitness, - 'training_results': f.read(), - 'model': ema.ema, - 'optimizer': None if final_epoch else optimizer.state_dict(), - 'wandb_id': wandb_run.id if wandb else None} + if (not opt.nosave) or (final_epoch and not opt.evolve): # if save + ckpt = {'epoch': epoch, + 'best_fitness': best_fitness, + 'training_results': results_file.read_text(), + 'model': deepcopy(model.module if is_parallel(model) else model).half(), + 'ema': deepcopy(ema.ema).half(), + 'updates': ema.updates, + 'optimizer': optimizer.state_dict(), + 'wandb_id': wandb_logger.wandb_run.id if wandb_logger.wandb else None} # Save last, best and delete torch.save(ckpt, last) if best_fitness == fi: torch.save(ckpt, best) + if wandb_logger.wandb: + if ((epoch + 1) % opt.save_period == 0 and not final_epoch) and opt.save_period != -1: + wandb_logger.log_model( + last.parent, opt, epoch, fi, best_model=best_fitness == fi) del ckpt + # end epoch ---------------------------------------------------------------------------------------------------- # end training - if rank in [-1, 0]: - # Strip optimizers - final = best if best.exists() else last # final model - for f in [last, best]: - if f.exists(): - strip_optimizer(f) # strip optimizers - if opt.bucket: - os.system(f'gsutil cp {final} gs://{opt.bucket}/weights') # upload - # Plots if plots: plot_results(save_dir=save_dir) # save as results.png - if wandb: - files = ['results.png', 'precision_recall_curve.png', 'confusion_matrix.png'] - wandb.log({"Results": [wandb.Image(str(save_dir / f), caption=f) for f in files - if (save_dir / f).exists()]}) - if opt.log_artifacts: - wandb.log_artifact(artifact_or_path=str(final), type='model', name=save_dir.stem) - + if wandb_logger.wandb: + files = ['results.png', 'confusion_matrix.png', *[f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R')]] + wandb_logger.log({"Results": [wandb_logger.wandb.Image(str(save_dir / f), caption=f) for f in files + if (save_dir / f).exists()]}) # Test best.pt logger.info('%g epochs completed in %.3f hours.\n' % (epoch - start_epoch + 1, (time.time() - t0) / 3600)) if opt.data.endswith('coco.yaml') and nc == 80: # if COCO - for conf, iou, save_json in ([0.25, 0.45, False], [0.001, 0.65, True]): # speed, mAP tests + for m in (last, best) if best.exists() else (last): # speed, mAP tests results, _, _ = test.test(opt.data, - batch_size=total_batch_size, + batch_size=batch_size * 2, imgsz=imgsz_test, - conf_thres=conf, - iou_thres=iou, - model=attempt_load(final, device).half(), + conf_thres=0.001, + iou_thres=0.7, + model=attempt_load(m, device).half(), single_cls=opt.single_cls, dataloader=testloader, save_dir=save_dir, - save_json=save_json, - plots=False) + save_json=True, + plots=False, + is_coco=is_coco) + # Strip optimizers + final = best if best.exists() else last # final model + for f in last, best: + if f.exists(): + strip_optimizer(f) # strip optimizers + if opt.bucket: + os.system(f'gsutil cp {final} gs://{opt.bucket}/weights') # upload + if wandb_logger.wandb and not opt.evolve: # Log the stripped model + wandb_logger.wandb.log_artifact(str(final), type='model', + name='run_' + wandb_logger.wandb_run.id + '_model', + aliases=['last', 'best', 'stripped']) + wandb_logger.finish_run() else: dist.destroy_process_group() - - wandb.run.finish() if wandb and wandb.run else None torch.cuda.empty_cache() return results @@ -453,13 +477,18 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer') parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') - parser.add_argument('--log-imgs', type=int, default=16, help='number of images for W&B logging, max 100') - parser.add_argument('--log-artifacts', action='store_true', help='log artifacts, i.e. final trained model') parser.add_argument('--workers', type=int, default=8, help='maximum number of dataloader workers') parser.add_argument('--project', default='runs/train', help='save to project/name') + parser.add_argument('--entity', default=None, help='W&B entity') parser.add_argument('--name', default='exp', help='save to project/name') parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') parser.add_argument('--quad', action='store_true', help='quad dataloader') + parser.add_argument('--linear-lr', action='store_true', help='linear LR') + parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') + parser.add_argument('--upload_dataset', action='store_true', help='Upload dataset as W&B artifact table') + parser.add_argument('--bbox_interval', type=int, default=-1, help='Set bounding-box image logging interval for W&B') + parser.add_argument('--save_period', type=int, default=-1, help='Log model after every "save_period" epoch') + parser.add_argument('--artifact_alias', type=str, default="latest", help='version of dataset artifact to be used') opt = parser.parse_args() # Set DDP variables @@ -471,13 +500,14 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): check_requirements() # Resume - if opt.resume: # resume an interrupted run + wandb_run = check_wandb_resume(opt) + if opt.resume and not wandb_run: # resume an interrupted run ckpt = opt.resume if isinstance(opt.resume, str) else get_latest_run() # specified or most recent path assert os.path.isfile(ckpt), 'ERROR: --resume checkpoint does not exist' apriori = opt.global_rank, opt.local_rank with open(Path(ckpt).parent.parent / 'opt.yaml') as f: opt = argparse.Namespace(**yaml.load(f, Loader=yaml.SafeLoader)) # replace - opt.cfg, opt.weights, opt.resume, opt.global_rank, opt.local_rank = '', ckpt, True, *apriori # reinstate + opt.cfg, opt.weights, opt.resume, opt.batch_size, opt.global_rank, opt.local_rank = '', ckpt, True, opt.total_batch_size, *apriori # reinstate logger.info('Resuming training from %s' % ckpt) else: # opt.hyp = opt.hyp or ('hyp.finetune.yaml' if opt.weights else 'hyp.scratch.yaml') @@ -504,18 +534,13 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): # Train logger.info(opt) - try: - import wandb - except ImportError: - wandb = None - prefix = colorstr('wandb: ') - logger.info(f"{prefix}Install Weights & Biases for YOLOv3 logging with 'pip install wandb' (recommended)") if not opt.evolve: tb_writer = None # init loggers if opt.global_rank in [-1, 0]: - logger.info(f'Start Tensorboard with "tensorboard --logdir {opt.project}", view at http://localhost:6006/') + prefix = colorstr('tensorboard: ') + logger.info(f"{prefix}Start with 'tensorboard --logdir {opt.project}', view at http://localhost:6006/") tb_writer = SummaryWriter(opt.save_dir) # Tensorboard - train(hyp, opt, device, tb_writer, wandb) + train(hyp, opt, device, tb_writer) # Evolve hyperparameters (optional) else: @@ -589,7 +614,7 @@ def train(hyp, opt, device, tb_writer=None, wandb=None): hyp[k] = round(hyp[k], 5) # significant digits # Train mutation - results = train(hyp.copy(), opt, device, wandb=wandb) + results = train(hyp.copy(), opt, device) # Write mutation results print_mutation(hyp.copy(), results, yaml_file, opt.bucket) diff --git a/tutorial.ipynb b/tutorial.ipynb index 5e190e212a..b8969bc45f 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -16,7 +16,7 @@ "accelerator": "GPU", "widgets": { "application/vnd.jupyter.widget-state+json": { - "b257add75888401ebf17767cdc9ed439": { + "8815626359d84416a2f44a95500580a4": { "model_module": "@jupyter-widgets/controls", "model_name": "HBoxModel", "state": { @@ -28,15 +28,15 @@ "_view_count": null, "_view_module_version": "1.5.0", "box_style": "", - "layout": "IPY_MODEL_4b685e8b26f3496db73186063e19f785", + "layout": "IPY_MODEL_3b85609c4ce94a74823f2cfe141ce68e", "_model_module": "@jupyter-widgets/controls", "children": [ - "IPY_MODEL_0980232d74a14bdfa353a3f248bbe8ff", - "IPY_MODEL_e981f3dfbf374643b58cba7dfbef3bca" + "IPY_MODEL_876609753c2946248890344722963d44", + "IPY_MODEL_8abfdd8778e44b7ca0d29881cb1ada05" ] } }, - "4b685e8b26f3496db73186063e19f785": { + "3b85609c4ce94a74823f2cfe141ce68e": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "state": { @@ -87,12 +87,12 @@ "left": null } }, - "0980232d74a14bdfa353a3f248bbe8ff": { + "876609753c2946248890344722963d44": { "model_module": "@jupyter-widgets/controls", "model_name": "FloatProgressModel", "state": { "_view_name": "ProgressView", - "style": "IPY_MODEL_07bb32c950654e9fa401e35a0030eadc", + "style": "IPY_MODEL_78c6c3d97c484916b8ee167c63556800", "_dom_classes": [], "description": "100%", "_model_name": "FloatProgressModel", @@ -107,30 +107,30 @@ "min": 0, "description_tooltip": null, "_model_module": "@jupyter-widgets/controls", - "layout": "IPY_MODEL_ec3fce2f475b4f31b8caf1a0ca912af1" + "layout": "IPY_MODEL_9dd0f182db5d45378ceafb855e486eb8" } }, - "e981f3dfbf374643b58cba7dfbef3bca": { + "8abfdd8778e44b7ca0d29881cb1ada05": { "model_module": "@jupyter-widgets/controls", "model_name": "HTMLModel", "state": { "_view_name": "HTMLView", - "style": "IPY_MODEL_9a1c27af326e43ca8a8b6b90cf0075db", + "style": "IPY_MODEL_a3dab28b45c247089a3d1b8b09f327de", "_dom_classes": [], "description": "", "_model_name": "HTMLModel", "placeholder": "​", "_view_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", - "value": " 781M/781M [00:49<00:00, 16.7MB/s]", + "value": " 781M/781M [08:43<00:00, 1.56MB/s]", "_view_count": null, "_view_module_version": "1.5.0", "description_tooltip": null, "_model_module": "@jupyter-widgets/controls", - "layout": "IPY_MODEL_7cf92d6d6c704a8d8e7834783813228d" + "layout": "IPY_MODEL_32451332b7a94ba9aacddeaa6ac94d50" } }, - "07bb32c950654e9fa401e35a0030eadc": { + "78c6c3d97c484916b8ee167c63556800": { "model_module": "@jupyter-widgets/controls", "model_name": "ProgressStyleModel", "state": { @@ -145,7 +145,7 @@ "_model_module": "@jupyter-widgets/controls" } }, - "ec3fce2f475b4f31b8caf1a0ca912af1": { + "9dd0f182db5d45378ceafb855e486eb8": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "state": { @@ -196,7 +196,7 @@ "left": null } }, - "9a1c27af326e43ca8a8b6b90cf0075db": { + "a3dab28b45c247089a3d1b8b09f327de": { "model_module": "@jupyter-widgets/controls", "model_name": "DescriptionStyleModel", "state": { @@ -210,7 +210,7 @@ "_model_module": "@jupyter-widgets/controls" } }, - "7cf92d6d6c704a8d8e7834783813228d": { + "32451332b7a94ba9aacddeaa6ac94d50": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "state": { @@ -261,7 +261,7 @@ "left": null } }, - "c1928794b5bd400da6e7817883a0ee9c": { + "0fffa335322b41658508e06aed0acbf0": { "model_module": "@jupyter-widgets/controls", "model_name": "HBoxModel", "state": { @@ -273,15 +273,15 @@ "_view_count": null, "_view_module_version": "1.5.0", "box_style": "", - "layout": "IPY_MODEL_804fae06a69f4e11b919d8ab80822186", + "layout": "IPY_MODEL_a354c6f80ce347e5a3ef64af87c0eccb", "_model_module": "@jupyter-widgets/controls", "children": [ - "IPY_MODEL_138cbb92b4fd4eaa9b7fdcbed1f57a4d", - "IPY_MODEL_28bb2eea5b114f82b201e5fa39fdfc58" + "IPY_MODEL_85823e71fea54c39bd11e2e972348836", + "IPY_MODEL_fb11acd663fa4e71b041d67310d045fd" ] } }, - "804fae06a69f4e11b919d8ab80822186": { + "a354c6f80ce347e5a3ef64af87c0eccb": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "state": { @@ -332,50 +332,50 @@ "left": null } }, - "138cbb92b4fd4eaa9b7fdcbed1f57a4d": { + "85823e71fea54c39bd11e2e972348836": { "model_module": "@jupyter-widgets/controls", "model_name": "FloatProgressModel", "state": { "_view_name": "ProgressView", - "style": "IPY_MODEL_aea8bd6f395845f696e3abedbff59423", + "style": "IPY_MODEL_8a919053b780449aae5523658ad611fa", "_dom_classes": [], "description": "100%", "_model_name": "FloatProgressModel", "bar_style": "success", - "max": 22090455, + "max": 22091032, "_view_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", - "value": 22090455, + "value": 22091032, "_view_count": null, "_view_module_version": "1.5.0", "orientation": "horizontal", "min": 0, "description_tooltip": null, "_model_module": "@jupyter-widgets/controls", - "layout": "IPY_MODEL_0514774dafdf4e39bdd5a8833d1cbcb0" + "layout": "IPY_MODEL_5bae9393a58b44f7b69fb04816f94f6f" } }, - "28bb2eea5b114f82b201e5fa39fdfc58": { + "fb11acd663fa4e71b041d67310d045fd": { "model_module": "@jupyter-widgets/controls", "model_name": "HTMLModel", "state": { "_view_name": "HTMLView", - "style": "IPY_MODEL_7dabd1f8236045729c90ae78a0d9af24", + "style": "IPY_MODEL_d26c6d16c7f24030ab2da5285bf198ee", "_dom_classes": [], "description": "", "_model_name": "HTMLModel", "placeholder": "​", "_view_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", - "value": " 21.1M/21.1M [00:02<00:00, 9.27MB/s]", + "value": " 21.1M/21.1M [00:02<00:00, 9.36MB/s]", "_view_count": null, "_view_module_version": "1.5.0", "description_tooltip": null, "_model_module": "@jupyter-widgets/controls", - "layout": "IPY_MODEL_227e357d925345f995aeea7b72750cf1" + "layout": "IPY_MODEL_f7767886b2364c8d9efdc79e175ad8eb" } }, - "aea8bd6f395845f696e3abedbff59423": { + "8a919053b780449aae5523658ad611fa": { "model_module": "@jupyter-widgets/controls", "model_name": "ProgressStyleModel", "state": { @@ -390,7 +390,7 @@ "_model_module": "@jupyter-widgets/controls" } }, - "0514774dafdf4e39bdd5a8833d1cbcb0": { + "5bae9393a58b44f7b69fb04816f94f6f": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "state": { @@ -441,7 +441,7 @@ "left": null } }, - "7dabd1f8236045729c90ae78a0d9af24": { + "d26c6d16c7f24030ab2da5285bf198ee": { "model_module": "@jupyter-widgets/controls", "model_name": "DescriptionStyleModel", "state": { @@ -455,7 +455,7 @@ "_model_module": "@jupyter-widgets/controls" } }, - "227e357d925345f995aeea7b72750cf1": { + "f7767886b2364c8d9efdc79e175ad8eb": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "state": { @@ -517,7 +517,7 @@ "colab_type": "text" }, "source": [ - "\"Open" + "\"Open" ] }, { @@ -528,8 +528,8 @@ "source": [ "\n", "\n", - "This notebook was written by Ultralytics LLC, and is freely available for redistribution under the [GPL-3.0 license](https://choosealicense.com/licenses/gpl-3.0/). \n", - "For more information please visit https://github.com/ultralytics/yolov3 and https://www.ultralytics.com." + "This is the **official YOLOv3 🚀 notebook** authored by **Ultralytics**, and is freely available for redistribution under the [GPL-3.0 license](https://choosealicense.com/licenses/gpl-3.0/). \n", + "For more information please visit https://github.com/ultralytics/yolov5 and https://www.ultralytics.com. Thank you!" ] }, { @@ -550,25 +550,25 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "edc03bfa-6dd3-49ae-9095-405ba8cbe87d" + "outputId": "9b022435-4197-41fc-abea-81f86ce857d0" }, "source": [ - "!git clone https://github.com/ultralytics/yolov3 # clone repo\n", - "%cd yolov3\n", + "!git clone https://github.com/ultralytics/yolov5 # clone repo\n", + "%cd yolov5\n", "%pip install -qr requirements.txt # install dependencies\n", "\n", "import torch\n", "from IPython.display import Image, clear_output # to display images\n", "\n", "clear_output()\n", - "print('Setup complete. Using torch %s %s' % (torch.__version__, torch.cuda.get_device_properties(0) if torch.cuda.is_available() else 'CPU'))" + "print(f\"Setup complete. Using torch {torch.__version__} ({torch.cuda.get_device_properties(0).name if torch.cuda.is_available() else 'CPU'})\")" ], - "execution_count": 1, + "execution_count": 31, "outputs": [ { "output_type": "stream", "text": [ - "Setup complete. Using torch 1.7.0+cu101 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', major=7, minor=0, total_memory=16130MB, multi_processor_count=80)\n" + "Setup complete. Using torch 1.8.1+cu101 (Tesla V100-SXM2-16GB)\n" ], "name": "stdout" } @@ -582,7 +582,9 @@ "source": [ "# 1. Inference\n", "\n", - "`detect.py` runs inference on a variety of sources, downloading models automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases)." + "`detect.py` runs YOLOv3 inference on a variety of sources, downloading models automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases), and saving results to `runs/detect`. Example inference sources are:\n", + "\n", + " " ] }, { @@ -591,38 +593,35 @@ "id": "zR9ZbuQCH7FX", "colab": { "base_uri": "https://localhost:8080/", - "height": 587 + "height": 534 }, - "outputId": "44211008-da79-4175-f719-ac265dad26eb" + "outputId": "c9a308f7-2216-4805-8003-eca8dd0dc30d" }, "source": [ "!python detect.py --weights yolov3.pt --img 640 --conf 0.25 --source data/images/\n", "Image(filename='runs/detect/exp/zidane.jpg', width=600)" ], - "execution_count": 2, + "execution_count": null, "outputs": [ { "output_type": "stream", "text": [ "Namespace(agnostic_nms=False, augment=False, classes=None, conf_thres=0.25, device='', exist_ok=False, img_size=640, iou_thres=0.45, name='exp', project='runs/detect', save_conf=False, save_txt=False, source='data/images/', update=False, view_img=False, weights=['yolov3.pt'])\n", - "Using torch 1.7.0+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16130MB)\n", - "\n", - "Downloading https://github.com/ultralytics/yolov3/releases/download/v1.0/yolov3.pt to yolov3.pt...\n", - "100% 118M/118M [00:08<00:00, 14.6MB/s]\n", + "YOLOv3 🚀 v5.0-1-g0f395b3 torch 1.8.1+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16160.5MB)\n", "\n", "Fusing layers... \n", - "Model Summary: 261 layers, 61922845 parameters, 0 gradients\n", - "image 1/2 /content/yolov3/data/images/bus.jpg: 640x480 4 persons, 1 buss, Done. (0.046s)\n", - "image 2/2 /content/yolov3/data/images/zidane.jpg: 384x640 2 persons, 3 ties, Done. (0.013s)\n", + "Model Summary: 224 layers, 7266973 parameters, 0 gradients, 17.0 GFLOPS\n", + "image 1/2 /content/yolov5/data/images/bus.jpg: 640x480 4 persons, 1 bus, Done. (0.008s)\n", + "image 2/2 /content/yolov5/data/images/zidane.jpg: 384x640 2 persons, 2 ties, Done. (0.008s)\n", "Results saved to runs/detect/exp\n", - "Done. (0.293s)\n" + "Done. (0.087)\n" ], "name": "stdout" }, { "output_type": "execute_result", "data": { - "image/jpeg": "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\n", + "image/jpeg": "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\n", "text/plain": [ "" ] @@ -633,20 +632,10 @@ "width": 600 } }, - "execution_count": 2 + "execution_count": 38 } ] }, - { - "cell_type": "markdown", - "metadata": { - "id": "4qbaa3iEcrcE" - }, - "source": [ - "Results are saved to `runs/detect`. A full list of available inference sources:\n", - " " - ] - }, { "cell_type": "markdown", "metadata": { @@ -654,7 +643,7 @@ }, "source": [ "# 2. Test\n", - "Test a model on [COCO](https://cocodataset.org/#home) val or test-dev dataset to evaluate trained accuracy. Models are downloaded automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases). To show results by class use the `--verbose` flag. Note that `pycocotools` metrics may be 1-2% better than the equivalent repo metrics, as is visible below, due to slight differences in mAP computation." + "Test a model's accuracy on [COCO](https://cocodataset.org/#home) val or test-dev datasets. Models are downloaded automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases). To show results by class use the `--verbose` flag. Note that `pycocotools` metrics may be ~1% better than the equivalent repo metrics, as is visible below, due to slight differences in mAP computation." ] }, { @@ -673,32 +662,32 @@ "id": "WQPtK1QYVaD_", "colab": { "base_uri": "https://localhost:8080/", - "height": 66, + "height": 65, "referenced_widgets": [ - "b257add75888401ebf17767cdc9ed439", - "4b685e8b26f3496db73186063e19f785", - "0980232d74a14bdfa353a3f248bbe8ff", - "e981f3dfbf374643b58cba7dfbef3bca", - "07bb32c950654e9fa401e35a0030eadc", - "ec3fce2f475b4f31b8caf1a0ca912af1", - "9a1c27af326e43ca8a8b6b90cf0075db", - "7cf92d6d6c704a8d8e7834783813228d" + "8815626359d84416a2f44a95500580a4", + "3b85609c4ce94a74823f2cfe141ce68e", + "876609753c2946248890344722963d44", + "8abfdd8778e44b7ca0d29881cb1ada05", + "78c6c3d97c484916b8ee167c63556800", + "9dd0f182db5d45378ceafb855e486eb8", + "a3dab28b45c247089a3d1b8b09f327de", + "32451332b7a94ba9aacddeaa6ac94d50" ] }, - "outputId": "2ac7a39f-8432-43e0-9d34-bc2c9a71ba21" + "outputId": "81521192-cf67-4a47-a4cc-434cb0ebc363" }, "source": [ "# Download COCO val2017\n", "torch.hub.download_url_to_file('https://github.com/ultralytics/yolov5/releases/download/v1.0/coco2017val.zip', 'tmp.zip')\n", "!unzip -q tmp.zip -d ../ && rm tmp.zip" ], - "execution_count": 3, + "execution_count": null, "outputs": [ { "output_type": "display_data", "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "b257add75888401ebf17767cdc9ed439", + "model_id": "8815626359d84416a2f44a95500580a4", "version_minor": 0, "version_major": 2 }, @@ -726,55 +715,57 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "6850c54e-b697-40c2-f9fc-9ffda2d7052a" + "outputId": "2340b131-9943-4cd6-fd3a-8272aeb0774f" }, "source": [ "# Run YOLOv3 on COCO val2017\n", - "!python test.py --weights yolov3.pt --data coco.yaml --img 640 --iou 0.65" + "!python test.py --weights yolov5x.pt --data coco.yaml --img 640 --iou 0.65" ], - "execution_count": 4, + "execution_count": null, "outputs": [ { "output_type": "stream", "text": [ - "Namespace(augment=False, batch_size=32, conf_thres=0.001, data='./data/coco.yaml', device='', exist_ok=False, img_size=640, iou_thres=0.65, name='exp', project='runs/test', save_conf=False, save_json=True, save_txt=False, single_cls=False, task='val', verbose=False, weights=['yolov3.pt'])\n", - "Using torch 1.7.0+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16130MB)\n", + "Namespace(augment=False, batch_size=32, conf_thres=0.001, data='./data/coco.yaml', device='', exist_ok=False, img_size=640, iou_thres=0.65, name='exp', project='runs/test', save_conf=False, save_hybrid=False, save_json=True, save_txt=False, single_cls=False, task='val', verbose=False, weights=['yolov5x.pt'])\n", + "YOLOv3 🚀 v5.0-1-g0f395b3 torch 1.8.1+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16160.5MB)\n", + "\n", + "Downloading https://github.com/ultralytics/yolov5/releases/download/v5.0/yolov5x.pt to yolov5x.pt...\n", + "100% 168M/168M [00:05<00:00, 32.3MB/s]\n", "\n", "Fusing layers... \n", - "Model Summary: 261 layers, 61922845 parameters, 0 gradients\n", - "Scanning '../coco/labels/val2017' for images and labels... 4952 found, 48 missing, 0 empty, 0 corrupted: 100% 5000/5000 [00:01<00:00, 3373.28it/s]\n", - "New cache created: ../coco/labels/val2017.cache\n", - "Scanning '../coco/labels/val2017.cache' for images and labels... 4952 found, 48 missing, 0 empty, 0 corrupted: 100% 5000/5000 [00:00<00:00, 43690666.67it/s]\n", - " Class Images Targets P R mAP@.5 mAP@.5:.95: 100% 157/157 [01:19<00:00, 1.97it/s]\n", - " all 5e+03 3.63e+04 0.472 0.698 0.625 0.424\n", - "Speed: 3.6/1.6/5.2 ms inference/NMS/total per 640x640 image at batch-size 32\n", + "Model Summary: 476 layers, 87730285 parameters, 0 gradients, 218.8 GFLOPS\n", + "\u001b[34m\u001b[1mval: \u001b[0mScanning '../coco/val2017' images and labels... 4952 found, 48 missing, 0 empty, 0 corrupted: 100% 5000/5000 [00:01<00:00, 3102.29it/s]\n", + "\u001b[34m\u001b[1mval: \u001b[0mNew cache created: ../coco/val2017.cache\n", + " Class Images Labels P R mAP@.5 mAP@.5:.95: 100% 157/157 [01:23<00:00, 1.87it/s]\n", + " all 5000 36335 0.745 0.627 0.68 0.49\n", + "Speed: 5.3/1.6/6.9 ms inference/NMS/total per 640x640 image at batch-size 32\n", "\n", - "Evaluating pycocotools mAP... saving runs/test/exp/yolov3_predictions.json...\n", + "Evaluating pycocotools mAP... saving runs/test/exp/yolov5x_predictions.json...\n", "loading annotations into memory...\n", - "Done (t=0.41s)\n", + "Done (t=0.48s)\n", "creating index...\n", "index created!\n", "Loading and preparing results...\n", - "DONE (t=3.78s)\n", + "DONE (t=5.08s)\n", "creating index...\n", "index created!\n", "Running per image evaluation...\n", "Evaluate annotation type *bbox*\n", - "DONE (t=78.99s).\n", + "DONE (t=90.51s).\n", "Accumulating evaluation results...\n", - "DONE (t=11.77s).\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.433\n", - " Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.630\n", - " Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.470\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.283\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.485\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.538\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.346\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.581\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.634\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.473\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.687\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.766\n", + "DONE (t=15.16s).\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.504\n", + " Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.688\n", + " Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.546\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.351\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.551\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.644\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.382\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.629\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.681\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.524\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.735\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.827\n", "Results saved to runs/test/exp\n" ], "name": "stdout" @@ -788,7 +779,7 @@ }, "source": [ "## COCO test-dev2017\n", - "Download [COCO test2017](https://github.com/ultralytics/yolov5/blob/74b34872fdf41941cddcf243951cdb090fbac17b/data/coco.yaml#L15) dataset (7GB - 40,000 images), to test model accuracy on test-dev set (20,000 images). Results are saved to a `*.json` file which can be submitted to the evaluation server at https://competitions.codalab.org/competitions/20794." + "Download [COCO test2017](https://github.com/ultralytics/yolov5/blob/74b34872fdf41941cddcf243951cdb090fbac17b/data/coco.yaml#L15) dataset (7GB - 40,000 images), to test model accuracy on test-dev set (**20,000 images, no labels**). Results are saved to a `*.json` file which should be **zipped** and submitted to the evaluation server at https://competitions.codalab.org/competitions/20794." ] }, { @@ -799,9 +790,9 @@ "source": [ "# Download COCO test-dev2017\n", "torch.hub.download_url_to_file('https://github.com/ultralytics/yolov5/releases/download/v1.0/coco2017labels.zip', 'tmp.zip')\n", - "!unzip -q tmp.zip -d ../ && rm tmp.zip # unzip labels\n", + "!unzip -q tmp.zip -d ../ && rm tmp.zip # unzip labels\n", "!f=\"test2017.zip\" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f # 7GB, 41k images\n", - "%mv ./test2017 ./coco/images && mv ./coco ../ # move images to /coco and move /coco next to /yolov3" + "%mv ./test2017 ../coco/images # move to /coco" ], "execution_count": null, "outputs": [] @@ -835,37 +826,37 @@ "id": "Knxi2ncxWffW", "colab": { "base_uri": "https://localhost:8080/", - "height": 66, + "height": 65, "referenced_widgets": [ - "c1928794b5bd400da6e7817883a0ee9c", - "804fae06a69f4e11b919d8ab80822186", - "138cbb92b4fd4eaa9b7fdcbed1f57a4d", - "28bb2eea5b114f82b201e5fa39fdfc58", - "aea8bd6f395845f696e3abedbff59423", - "0514774dafdf4e39bdd5a8833d1cbcb0", - "7dabd1f8236045729c90ae78a0d9af24", - "227e357d925345f995aeea7b72750cf1" + "0fffa335322b41658508e06aed0acbf0", + "a354c6f80ce347e5a3ef64af87c0eccb", + "85823e71fea54c39bd11e2e972348836", + "fb11acd663fa4e71b041d67310d045fd", + "8a919053b780449aae5523658ad611fa", + "5bae9393a58b44f7b69fb04816f94f6f", + "d26c6d16c7f24030ab2da5285bf198ee", + "f7767886b2364c8d9efdc79e175ad8eb" ] }, - "outputId": "389207da-a1a0-4cbf-d9b8-a39546b1b76c" + "outputId": "b41ac253-9e1b-4c26-d78b-700ea0154f43" }, "source": [ "# Download COCO128\n", "torch.hub.download_url_to_file('https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip', 'tmp.zip')\n", "!unzip -q tmp.zip -d ../ && rm tmp.zip" ], - "execution_count": 5, + "execution_count": null, "outputs": [ { "output_type": "display_data", "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "c1928794b5bd400da6e7817883a0ee9c", + "model_id": "0fffa335322b41658508e06aed0acbf0", "version_minor": 0, "version_major": 2 }, "text/plain": [ - "HBox(children=(FloatProgress(value=0.0, max=22090455.0), HTML(value='')))" + "HBox(children=(FloatProgress(value=0.0, max=22091032.0), HTML(value='')))" ] }, "metadata": { @@ -900,7 +891,7 @@ "source": [ "# Tensorboard (optional)\n", "%load_ext tensorboard\n", - "%tensorboard --logdir runs" + "%tensorboard --logdir runs/train" ], "execution_count": null, "outputs": [] @@ -925,90 +916,87 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "2132590a-ff5e-4ab8-a20d-f8bb8ea7c42b" + "outputId": "e715d09c-5d93-4912-a0df-9da0893f2014" }, "source": [ "# Train YOLOv3 on COCO128 for 3 epochs\n", "!python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov3.pt --nosave --cache" ], - "execution_count": 6, + "execution_count": null, "outputs": [ { "output_type": "stream", "text": [ - "Using torch 1.7.0+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16130MB)\n", + "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", + "YOLOv3 🚀 v5.0-2-g54d6516 torch 1.8.1+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16160.5MB)\n", "\n", - "Namespace(adam=False, batch_size=16, bucket='', cache_images=True, cfg='', data='./data/coco128.yaml', device='', epochs=3, evolve=False, exist_ok=False, global_rank=-1, hyp='data/hyp.scratch.yaml', image_weights=False, img_size=[640, 640], local_rank=-1, log_imgs=16, multi_scale=False, name='exp', noautoanchor=False, nosave=True, notest=False, project='runs/train', rect=False, resume=False, save_dir='runs/train/exp', single_cls=False, sync_bn=False, total_batch_size=16, weights='yolov3.pt', workers=8, world_size=1)\n", - "Start Tensorboard with \"tensorboard --logdir runs/train\", view at http://localhost:6006/\n", - "2020-11-26 18:51:45.386416: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1\n", - "Hyperparameters {'lr0': 0.01, 'lrf': 0.2, 'momentum': 0.937, 'weight_decay': 0.0005, 'warmup_epochs': 3.0, 'warmup_momentum': 0.8, 'warmup_bias_lr': 0.1, 'box': 0.05, 'cls': 0.5, 'cls_pw': 1.0, 'obj': 1.0, 'obj_pw': 1.0, 'iou_t': 0.2, 'anchor_t': 4.0, 'fl_gamma': 0.0, 'hsv_h': 0.015, 'hsv_s': 0.7, 'hsv_v': 0.4, 'degrees': 0.0, 'translate': 0.1, 'scale': 0.5, 'shear': 0.0, 'perspective': 0.0, 'flipud': 0.0, 'fliplr': 0.5, 'mosaic': 1.0, 'mixup': 0.0}\n", + "Namespace(adam=False, artifact_alias='latest', batch_size=16, bbox_interval=-1, bucket='', cache_images=True, cfg='', data='./data/coco128.yaml', device='', entity=None, epochs=3, evolve=False, exist_ok=False, global_rank=-1, hyp='data/hyp.scratch.yaml', image_weights=False, img_size=[640, 640], label_smoothing=0.0, linear_lr=False, local_rank=-1, multi_scale=False, name='exp', noautoanchor=False, nosave=True, notest=False, project='runs/train', quad=False, rect=False, resume=False, save_dir='runs/train/exp', save_period=-1, single_cls=False, sync_bn=False, total_batch_size=16, upload_dataset=False, weights='yolov3.pt', workers=8, world_size=1)\n", + "\u001b[34m\u001b[1mtensorboard: \u001b[0mStart with 'tensorboard --logdir runs/train', view at http://localhost:6006/\n", + "2021-04-12 10:29:58.539457: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcudart.so.11.0\n", + "\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.2, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0\n", + "\u001b[34m\u001b[1mwandb: \u001b[0mInstall Weights & Biases for YOLOv3 logging with 'pip install wandb' (recommended)\n", "\n", " from n params module arguments \n", - " 0 -1 1 928 models.common.Conv [3, 32, 3, 1] \n", + " 0 -1 1 3520 models.common.Focus [3, 32, 3] \n", " 1 -1 1 18560 models.common.Conv [32, 64, 3, 2] \n", - " 2 -1 1 20672 models.common.Bottleneck [64, 64] \n", + " 2 -1 1 18816 models.common.C3 [64, 64, 1] \n", " 3 -1 1 73984 models.common.Conv [64, 128, 3, 2] \n", - " 4 -1 2 164608 models.common.Bottleneck [128, 128] \n", + " 4 -1 1 156928 models.common.C3 [128, 128, 3] \n", " 5 -1 1 295424 models.common.Conv [128, 256, 3, 2] \n", - " 6 -1 8 2627584 models.common.Bottleneck [256, 256] \n", + " 6 -1 1 625152 models.common.C3 [256, 256, 3] \n", " 7 -1 1 1180672 models.common.Conv [256, 512, 3, 2] \n", - " 8 -1 8 10498048 models.common.Bottleneck [512, 512] \n", - " 9 -1 1 4720640 models.common.Conv [512, 1024, 3, 2] \n", - " 10 -1 4 20983808 models.common.Bottleneck [1024, 1024] \n", - " 11 -1 1 5245952 models.common.Bottleneck [1024, 1024, False] \n", - " 12 -1 1 525312 models.common.Conv [1024, 512, [1, 1]] \n", - " 13 -1 1 4720640 models.common.Conv [512, 1024, 3, 1] \n", - " 14 -1 1 525312 models.common.Conv [1024, 512, 1, 1] \n", - " 15 -1 1 4720640 models.common.Conv [512, 1024, 3, 1] \n", - " 16 -2 1 131584 models.common.Conv [512, 256, 1, 1] \n", - " 17 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", - " 18 [-1, 8] 1 0 models.common.Concat [1] \n", - " 19 -1 1 1377792 models.common.Bottleneck [768, 512, False] \n", - " 20 -1 1 1312256 models.common.Bottleneck [512, 512, False] \n", - " 21 -1 1 131584 models.common.Conv [512, 256, 1, 1] \n", - " 22 -1 1 1180672 models.common.Conv [256, 512, 3, 1] \n", - " 23 -2 1 33024 models.common.Conv [256, 128, 1, 1] \n", - " 24 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", - " 25 [-1, 6] 1 0 models.common.Concat [1] \n", - " 26 -1 1 344832 models.common.Bottleneck [384, 256, False] \n", - " 27 -1 2 656896 models.common.Bottleneck [256, 256, False] \n", - " 28 [27, 22, 15] 1 457725 models.yolo.Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [256, 512, 1024]]\n", - "Model Summary: 333 layers, 61949149 parameters, 61949149 gradients\n", + " 8 -1 1 656896 models.common.SPP [512, 512, [5, 9, 13]] \n", + " 9 -1 1 1182720 models.common.C3 [512, 512, 1, False] \n", + " 10 -1 1 131584 models.common.Conv [512, 256, 1, 1] \n", + " 11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 12 [-1, 6] 1 0 models.common.Concat [1] \n", + " 13 -1 1 361984 models.common.C3 [512, 256, 1, False] \n", + " 14 -1 1 33024 models.common.Conv [256, 128, 1, 1] \n", + " 15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 16 [-1, 4] 1 0 models.common.Concat [1] \n", + " 17 -1 1 90880 models.common.C3 [256, 128, 1, False] \n", + " 18 -1 1 147712 models.common.Conv [128, 128, 3, 2] \n", + " 19 [-1, 14] 1 0 models.common.Concat [1] \n", + " 20 -1 1 296448 models.common.C3 [256, 256, 1, False] \n", + " 21 -1 1 590336 models.common.Conv [256, 256, 3, 2] \n", + " 22 [-1, 10] 1 0 models.common.Concat [1] \n", + " 23 -1 1 1182720 models.common.C3 [512, 512, 1, False] \n", + " 24 [17, 20, 23] 1 229245 models.yolo.Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [128, 256, 512]]\n", + "Model Summary: 283 layers, 7276605 parameters, 7276605 gradients, 17.1 GFLOPS\n", "\n", - "Transferred 440/440 items from yolov3.pt\n", - "Optimizer groups: 75 .bias, 75 conv.weight, 72 other\n", - "Scanning '../coco128/labels/train2017' for images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 3001.29it/s]\n", - "New cache created: ../coco128/labels/train2017.cache\n", - "Scanning '../coco128/labels/train2017.cache' for images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 985084.24it/s]\n", - "Caching images (0.1GB): 100% 128/128 [00:00<00:00, 194.34it/s]\n", - "Scanning '../coco128/labels/train2017.cache' for images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 711087.30it/s]\n", - "Caching images (0.1GB): 100% 128/128 [00:00<00:00, 133.98it/s]\n", - "NumExpr defaulting to 2 threads.\n", + "Transferred 362/362 items from yolov3.pt\n", + "Scaled weight_decay = 0.0005\n", + "Optimizer groups: 62 .bias, 62 conv.weight, 59 other\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mScanning '../coco128/labels/train2017.cache' images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 796544.38it/s]\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mCaching images (0.1GB): 100% 128/128 [00:00<00:00, 176.73it/s]\n", + "\u001b[34m\u001b[1mval: \u001b[0mScanning '../coco128/labels/train2017.cache' images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 500812.42it/s]\n", + "\u001b[34m\u001b[1mval: \u001b[0mCaching images (0.1GB): 100% 128/128 [00:00<00:00, 134.10it/s]\n", + "Plotting labels... \n", "\n", - "Analyzing anchors... anchors/target = 4.26, Best Possible Recall (BPR) = 0.9946\n", + "\u001b[34m\u001b[1mautoanchor: \u001b[0mAnalyzing anchors... anchors/target = 4.26, Best Possible Recall (BPR) = 0.9946\n", "Image sizes 640 train, 640 test\n", "Using 2 dataloader workers\n", "Logging results to runs/train/exp\n", "Starting training for 3 epochs...\n", "\n", - " Epoch gpu_mem box obj cls total targets img_size\n", - " 0/2 8.88G 0.02999 0.02589 0.008271 0.06414 155 640: 100% 8/8 [00:06<00:00, 1.23it/s]\n", - " Class Images Targets P R mAP@.5 mAP@.5:.95: 100% 8/8 [00:06<00:00, 1.19it/s]\n", - " all 128 929 0.527 0.83 0.782 0.547\n", + " Epoch gpu_mem box obj cls total labels img_size\n", + " 0/2 3.29G 0.04368 0.065 0.02127 0.1299 183 640: 100% 8/8 [00:03<00:00, 2.21it/s]\n", + " Class Images Labels P R mAP@.5 mAP@.5:.95: 100% 4/4 [00:04<00:00, 1.09s/it]\n", + " all 128 929 0.605 0.657 0.666 0.434\n", "\n", - " Epoch gpu_mem box obj cls total targets img_size\n", - " 1/2 8.87G 0.02966 0.02563 0.008289 0.06358 190 640: 100% 8/8 [00:02<00:00, 3.09it/s]\n", - " Class Images Targets P R mAP@.5 mAP@.5:.95: 100% 8/8 [00:01<00:00, 5.90it/s]\n", - " all 128 929 0.528 0.831 0.784 0.55\n", + " Epoch gpu_mem box obj cls total labels img_size\n", + " 1/2 6.65G 0.04556 0.0651 0.01987 0.1305 166 640: 100% 8/8 [00:01<00:00, 5.18it/s]\n", + " Class Images Labels P R mAP@.5 mAP@.5:.95: 100% 4/4 [00:01<00:00, 2.72it/s]\n", + " all 128 929 0.61 0.66 0.669 0.438\n", "\n", - " Epoch gpu_mem box obj cls total targets img_size\n", - " 2/2 8.87G 0.02947 0.02217 0.009194 0.06083 135 640: 100% 8/8 [00:02<00:00, 3.02it/s]\n", - " Class Images Targets P R mAP@.5 mAP@.5:.95: 100% 8/8 [00:02<00:00, 3.07it/s]\n", - " all 128 929 0.528 0.834 0.784 0.55\n", - "Optimizer stripped from runs/train/exp/weights/last.pt, 124.2MB\n", - "Optimizer stripped from runs/train/exp/weights/best.pt, 124.2MB\n", - "3 epochs completed in 0.009 hours.\n", - "\n" + " Epoch gpu_mem box obj cls total labels img_size\n", + " 2/2 6.65G 0.04624 0.06923 0.0196 0.1351 182 640: 100% 8/8 [00:01<00:00, 5.19it/s]\n", + " Class Images Labels P R mAP@.5 mAP@.5:.95: 100% 4/4 [00:03<00:00, 1.27it/s]\n", + " all 128 929 0.618 0.659 0.671 0.438\n", + "3 epochs completed in 0.007 hours.\n", + "\n", + "Optimizer stripped from runs/train/exp/weights/last.pt, 14.8MB\n", + "Optimizer stripped from runs/train/exp/weights/best.pt, 14.8MB\n" ], "name": "stdout" } @@ -1031,9 +1019,9 @@ "source": [ "## Weights & Biases Logging 🌟 NEW\n", "\n", - "[Weights & Biases](https://www.wandb.com/) (W&B) is now integrated with YOLOv3 for real-time visualization and cloud logging of training runs. This allows for better run comparison and introspection, as well improved visibility and collaboration for teams. To enable W&B `pip install wandb`, and then train normally (you will be guided through setup on first use). \n", + "[Weights & Biases](https://wandb.ai/site?utm_campaign=repo_yolo_notebook) (W&B) is now integrated with YOLOv3 for real-time visualization and cloud logging of training runs. This allows for better run comparison and introspection, as well improved visibility and collaboration for teams. To enable W&B `pip install wandb`, and then train normally (you will be guided through setup on first use). \n", "\n", - "During training you will see live updates at [https://wandb.ai/home](https://wandb.ai/home), and you can create and share detailed [Reports](https://wandb.ai/glenn-jocher/yolov5_tutorial/reports/YOLOv5-COCO128-Tutorial-Results--VmlldzozMDI5OTY) of your results. For more information see the [YOLOv5 Weights & Biases Tutorial](https://github.com/ultralytics/yolov5/issues/1289). \n", + "During training you will see live updates at [https://wandb.ai/home](https://wandb.ai/home?utm_campaign=repo_yolo_notebook), and you can create and share detailed [Reports](https://wandb.ai/glenn-jocher/yolov5_tutorial/reports/YOLOv5-COCO128-Tutorial-Results--VmlldzozMDI5OTY) of your results. For more information see the [YOLOv5 Weights & Biases Tutorial](https://github.com/ultralytics/yolov5/issues/1289). \n", "\n", "" ] @@ -1119,12 +1107,23 @@ "\n", "YOLOv3 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):\n", "\n", - "- **Google Colab Notebook** with free GPU: \"Open\n", - "- **Kaggle Notebook** with free GPU: [https://www.kaggle.com/ultralytics/yolov3](https://www.kaggle.com/ultralytics/yolov3)\n", - "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) \n", - "- **Docker Image** https://hub.docker.com/r/ultralytics/yolov3. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) ![Docker Pulls](https://img.shields.io/docker/pulls/ultralytics/yolov3?logo=docker)\n", + "- **Google Colab and Kaggle** notebooks with free GPU: \"Open \"Open\n", + "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/GCP-Quickstart)\n", + "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/AWS-Quickstart)\n", + "- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/Docker-Quickstart) \"Docker\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6Qu7Iesl0p54" + }, + "source": [ + "# Status\n", + "\n", + "![CI CPU testing](https://github.com/ultralytics/yolov5/workflows/CI%20CPU%20testing/badge.svg)\n", "\n", - "\n" + "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov5/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 training ([train.py](https://github.com/ultralytics/yolov5/blob/master/train.py)), testing ([test.py](https://github.com/ultralytics/yolov5/blob/master/test.py)), inference ([detect.py](https://github.com/ultralytics/yolov5/blob/master/detect.py)) and export ([export.py](https://github.com/ultralytics/yolov5/blob/master/models/export.py)) on MacOS, Windows, and Ubuntu every 24 hours and on every commit.\n" ] }, { @@ -1146,8 +1145,8 @@ "source": [ "# Re-clone repo\n", "%cd ..\n", - "%rm -rf yolov3 && git clone https://github.com/ultralytics/yolov3\n", - "%cd yolov3" + "%rm -rf yolov5 && git clone https://github.com/ultralytics/yolov5\n", + "%cd yolov5" ], "execution_count": null, "outputs": [] @@ -1158,11 +1157,33 @@ "id": "mcKoSIK2WSzj" }, "source": [ - "# Test all\n", - "%%shell\n", - "for x in yolov3 yolov3-spp yolov3-tiny; do\n", - " python test.py --weights $x.pt --data coco.yaml --img 640\n", - "done" + "# Reproduce\n", + "for x in 'yolov3', 'yolov3-spp', 'yolov3-tiny':\n", + " !python test.py --weights {x}.pt --data coco.yaml --img 640 --conf 0.25 --iou 0.45 # speed\n", + " !python test.py --weights {x}.pt --data coco.yaml --img 640 --conf 0.001 --iou 0.65 # mAP" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "GMusP4OAxFu6" + }, + "source": [ + "# PyTorch Hub\n", + "import torch\n", + "\n", + "# Model\n", + "model = torch.hub.load('ultralytics/yolov5', 'yolov3')\n", + "\n", + "# Images\n", + "dir = 'https://github.com/ultralytics/yolov5/raw/master/data/images/'\n", + "imgs = [dir + f for f in ('zidane.jpg', 'bus.jpg')] # batch of images\n", + "\n", + "# Inference\n", + "results = model(imgs)\n", + "results.print() # or .show(), .save()" ], "execution_count": null, "outputs": [] @@ -1195,6 +1216,35 @@ "execution_count": null, "outputs": [] }, + { + "cell_type": "code", + "metadata": { + "id": "gogI-kwi3Tye" + }, + "source": [ + "# Profile\n", + "from utils.torch_utils import profile \n", + "\n", + "m1 = lambda x: x * torch.sigmoid(x)\n", + "m2 = torch.nn.SiLU()\n", + "profile(x=torch.randn(16, 3, 640, 640), ops=[m1, m2], n=100)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "RVRSOhEvUdb5" + }, + "source": [ + "# Evolve\n", + "!python train.py --img 640 --batch 64 --epochs 100 --data coco128.yaml --weights yolov3.pt --cache --noautoanchor --evolve\n", + "!d=runs/train/evolve && cp evolve.* $d && zip -r evolve.zip $d && gsutil mv evolve.zip gs://bucket # upload results (optional)" + ], + "execution_count": null, + "outputs": [] + }, { "cell_type": "code", "metadata": { @@ -1202,7 +1252,7 @@ }, "source": [ "# VOC\n", - "for b, m in zip([24, 24, 64], ['yolov3', 'yolov3-spp', 'yolov3-tiny']): # zip(batch_size, model)\n", + "for b, m in zip([64, 48, 32, 16], ['yolov3', 'yolov3-spp', 'yolov3-tiny']): # zip(batch_size, model)\n", " !python train.py --batch {b} --weights {m}.pt --data voc.yaml --epochs 50 --cache --img 512 --nosave --hyp hyp.finetune.yaml --project VOC --name {m}" ], "execution_count": null, diff --git a/utils/autoanchor.py b/utils/autoanchor.py index c6e6b9daf5..8d62474f28 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -37,17 +37,21 @@ def metric(k): # compute metric bpr = (best > 1. / thr).float().mean() # best possible recall return bpr, aat - bpr, aat = metric(m.anchor_grid.clone().cpu().view(-1, 2)) + anchors = m.anchor_grid.clone().cpu().view(-1, 2) # current anchors + bpr, aat = metric(anchors) print(f'anchors/target = {aat:.2f}, Best Possible Recall (BPR) = {bpr:.4f}', end='') if bpr < 0.98: # threshold to recompute print('. Attempting to improve anchors, please wait...') na = m.anchor_grid.numel() // 2 # number of anchors - new_anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False) - new_bpr = metric(new_anchors.reshape(-1, 2))[0] + try: + anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False) + except Exception as e: + print(f'{prefix}ERROR: {e}') + new_bpr = metric(anchors)[0] if new_bpr > bpr: # replace anchors - new_anchors = torch.tensor(new_anchors, device=m.anchors.device).type_as(m.anchors) - m.anchor_grid[:] = new_anchors.clone().view_as(m.anchor_grid) # for inference - m.anchors[:] = new_anchors.clone().view_as(m.anchors) / m.stride.to(m.anchors.device).view(-1, 1, 1) # loss + anchors = torch.tensor(anchors, device=m.anchors.device).type_as(m.anchors) + m.anchor_grid[:] = anchors.clone().view_as(m.anchor_grid) # for inference + m.anchors[:] = anchors.clone().view_as(m.anchors) / m.stride.to(m.anchors.device).view(-1, 1, 1) # loss check_anchor_order(m) print(f'{prefix}New anchors saved to model. Update model *.yaml to use these anchors in the future.') else: @@ -98,7 +102,7 @@ def print_results(k): if isinstance(path, str): # *.yaml file with open(path) as f: - data_dict = yaml.load(f, Loader=yaml.FullLoader) # model dict + data_dict = yaml.load(f, Loader=yaml.SafeLoader) # model dict from utils.datasets import LoadImagesAndLabels dataset = LoadImagesAndLabels(data_dict['train'], augment=True, rect=True) else: @@ -119,6 +123,7 @@ def print_results(k): print(f'{prefix}Running kmeans for {n} anchors on {len(wh)} points...') s = wh.std(0) # sigmas for whitening k, dist = kmeans(wh / s, n, iter=30) # points, mean distance + assert len(k) == n, print(f'{prefix}ERROR: scipy.cluster.vq.kmeans requested {n} points but returned only {len(k)}') k *= s wh = torch.tensor(wh, dtype=torch.float32) # filtered wh0 = torch.tensor(wh0, dtype=torch.float32) # unfiltered diff --git a/utils/aws/__init__.py b/utils/aws/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/utils/aws/mime.sh b/utils/aws/mime.sh new file mode 100644 index 0000000000..c319a83cfb --- /dev/null +++ b/utils/aws/mime.sh @@ -0,0 +1,26 @@ +# AWS EC2 instance startup 'MIME' script https://aws.amazon.com/premiumsupport/knowledge-center/execute-user-data-ec2/ +# This script will run on every instance restart, not only on first start +# --- DO NOT COPY ABOVE COMMENTS WHEN PASTING INTO USERDATA --- + +Content-Type: multipart/mixed; boundary="//" +MIME-Version: 1.0 + +--// +Content-Type: text/cloud-config; charset="us-ascii" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Content-Disposition: attachment; filename="cloud-config.txt" + +#cloud-config +cloud_final_modules: +- [scripts-user, always] + +--// +Content-Type: text/x-shellscript; charset="us-ascii" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Content-Disposition: attachment; filename="userdata.txt" + +#!/bin/bash +# --- paste contents of userdata.sh here --- +--// diff --git a/utils/aws/resume.py b/utils/aws/resume.py new file mode 100644 index 0000000000..faad8d2474 --- /dev/null +++ b/utils/aws/resume.py @@ -0,0 +1,37 @@ +# Resume all interrupted trainings in yolov5/ dir including DDP trainings +# Usage: $ python utils/aws/resume.py + +import os +import sys +from pathlib import Path + +import torch +import yaml + +sys.path.append('./') # to run '$ python *.py' files in subdirectories + +port = 0 # --master_port +path = Path('').resolve() +for last in path.rglob('*/**/last.pt'): + ckpt = torch.load(last) + if ckpt['optimizer'] is None: + continue + + # Load opt.yaml + with open(last.parent.parent / 'opt.yaml') as f: + opt = yaml.load(f, Loader=yaml.SafeLoader) + + # Get device count + d = opt['device'].split(',') # devices + nd = len(d) # number of devices + ddp = nd > 1 or (nd == 0 and torch.cuda.device_count() > 1) # distributed data parallel + + if ddp: # multi-GPU + port += 1 + cmd = f'python -m torch.distributed.launch --nproc_per_node {nd} --master_port {port} train.py --resume {last}' + else: # single-GPU + cmd = f'python train.py --resume {last}' + + cmd += ' > /dev/null 2>&1 &' # redirect output to dev/null and run in daemon thread + print(cmd) + os.system(cmd) diff --git a/utils/aws/userdata.sh b/utils/aws/userdata.sh new file mode 100644 index 0000000000..890606b76a --- /dev/null +++ b/utils/aws/userdata.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# AWS EC2 instance startup script https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html +# This script will run only once on first instance start (for a re-start script see mime.sh) +# /home/ubuntu (ubuntu) or /home/ec2-user (amazon-linux) is working dir +# Use >300 GB SSD + +cd home/ubuntu +if [ ! -d yolov5 ]; then + echo "Running first-time script." # install dependencies, download COCO, pull Docker + git clone https://github.com/ultralytics/yolov5 && sudo chmod -R 777 yolov5 + cd yolov5 + bash data/scripts/get_coco.sh && echo "Data done." & + sudo docker pull ultralytics/yolov5:latest && echo "Docker done." & + python -m pip install --upgrade pip && pip install -r requirements.txt && python detect.py && echo "Requirements done." & + wait && echo "All tasks done." # finish background tasks +else + echo "Running re-start script." # resume interrupted runs + i=0 + list=$(sudo docker ps -qa) # container list i.e. $'one\ntwo\nthree\nfour' + while IFS= read -r id; do + ((i++)) + echo "restarting container $i: $id" + sudo docker start $id + # sudo docker exec -it $id python train.py --resume # single-GPU + sudo docker exec -d $id python utils/aws/resume.py # multi-scenario + done <<<"$list" +fi diff --git a/utils/datasets.py b/utils/datasets.py index d2002fabfc..fcaa3415b8 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -20,12 +20,13 @@ from torch.utils.data import Dataset from tqdm import tqdm -from utils.general import xyxy2xywh, xywh2xyxy, clean_str +from utils.general import check_requirements, xyxy2xywh, xywh2xyxy, xywhn2xyxy, xyn2xy, segment2box, segments2boxes, \ + resample_segments, clean_str from utils.torch_utils import torch_distributed_zero_first # Parameters help_url = 'https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' -img_formats = ['bmp', 'jpg', 'jpeg', 'png', 'tif', 'tiff', 'dng'] # acceptable image suffixes +img_formats = ['bmp', 'jpg', 'jpeg', 'png', 'tif', 'tiff', 'dng', 'webp', 'mpo'] # acceptable image suffixes vid_formats = ['mov', 'avi', 'mp4', 'mpg', 'mpeg', 'm4v', 'wmv', 'mkv'] # acceptable video suffixes logger = logging.getLogger(__name__) @@ -119,9 +120,8 @@ def __iter__(self): class LoadImages: # for inference - def __init__(self, path, img_size=640): - p = str(Path(path)) # os-agnostic - p = os.path.abspath(p) # absolute path + def __init__(self, path, img_size=640, stride=32): + p = str(Path(path).absolute()) # os-agnostic absolute path if '*' in p: files = sorted(glob.glob(p, recursive=True)) # glob elif os.path.isdir(p): @@ -136,6 +136,7 @@ def __init__(self, path, img_size=640): ni, nv = len(images), len(videos) self.img_size = img_size + self.stride = stride self.files = images + videos self.nf = ni + nv # number of files self.video_flag = [False] * ni + [True] * nv @@ -181,7 +182,7 @@ def __next__(self): print(f'image {self.count}/{self.nf} {path}: ', end='') # Padded resize - img = letterbox(img0, new_shape=self.img_size)[0] + img = letterbox(img0, self.img_size, stride=self.stride)[0] # Convert img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 @@ -199,8 +200,9 @@ def __len__(self): class LoadWebcam: # for inference - def __init__(self, pipe='0', img_size=640): + def __init__(self, pipe='0', img_size=640, stride=32): self.img_size = img_size + self.stride = stride if pipe.isnumeric(): pipe = eval(pipe) # local camera @@ -243,7 +245,7 @@ def __next__(self): print(f'webcam {self.count}: ', end='') # Padded resize - img = letterbox(img0, new_shape=self.img_size)[0] + img = letterbox(img0, self.img_size, stride=self.stride)[0] # Convert img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 @@ -256,9 +258,10 @@ def __len__(self): class LoadStreams: # multiple IP or RTSP cameras - def __init__(self, sources='streams.txt', img_size=640): + def __init__(self, sources='streams.txt', img_size=640, stride=32): self.mode = 'stream' self.img_size = img_size + self.stride = stride if os.path.isfile(sources): with open(sources, 'r') as f: @@ -272,19 +275,25 @@ def __init__(self, sources='streams.txt', img_size=640): for i, s in enumerate(sources): # Start the thread to read frames from the video stream print(f'{i + 1}/{n}: {s}... ', end='') - cap = cv2.VideoCapture(eval(s) if s.isnumeric() else s) + url = eval(s) if s.isnumeric() else s + if 'youtube.com/' in url or 'youtu.be/' in url: # if source is YouTube video + check_requirements(('pafy', 'youtube_dl')) + import pafy + url = pafy.new(url).getbest(preftype="mp4").url + cap = cv2.VideoCapture(url) assert cap.isOpened(), f'Failed to open {s}' w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) - fps = cap.get(cv2.CAP_PROP_FPS) % 100 + self.fps = cap.get(cv2.CAP_PROP_FPS) % 100 + _, self.imgs[i] = cap.read() # guarantee first frame thread = Thread(target=self.update, args=([i, cap]), daemon=True) - print(f' success ({w}x{h} at {fps:.2f} FPS).') + print(f' success ({w}x{h} at {self.fps:.2f} FPS).') thread.start() print('') # newline # check for common shapes - s = np.stack([letterbox(x, new_shape=self.img_size)[0].shape for x in self.imgs], 0) # inference shapes + s = np.stack([letterbox(x, self.img_size, stride=self.stride)[0].shape for x in self.imgs], 0) # shapes self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal if not self.rect: print('WARNING: Different stream shapes detected. For optimal performance supply similarly-shaped streams.') @@ -297,9 +306,10 @@ def update(self, index, cap): # _, self.imgs[index] = cap.read() cap.grab() if n == 4: # read every 4th frame - _, self.imgs[index] = cap.retrieve() + success, im = cap.retrieve() + self.imgs[index] = im if success else self.imgs[index] * 0 n = 0 - time.sleep(0.01) # wait time + time.sleep(1 / self.fps) # wait time def __iter__(self): self.count = -1 @@ -313,7 +323,7 @@ def __next__(self): raise StopIteration # Letterbox - img = [letterbox(x, new_shape=self.img_size, auto=self.rect)[0] for x in img0] + img = [letterbox(x, self.img_size, auto=self.rect, stride=self.stride)[0] for x in img0] # Stack img = np.stack(img, 0) @@ -331,7 +341,7 @@ def __len__(self): def img2label_paths(img_paths): # Define label paths as a function of image paths sa, sb = os.sep + 'images' + os.sep, os.sep + 'labels' + os.sep # /images/, /labels/ substrings - return [x.replace(sa, sb, 1).replace('.' + x.split('.')[-1], '.txt') for x in img_paths] + return ['txt'.join(x.replace(sa, sb, 1).rsplit(x.split('.')[-1], 1)) for x in img_paths] class LoadImagesAndLabels(Dataset): # for training/testing @@ -345,6 +355,7 @@ def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, r self.mosaic = self.augment and not self.rect # load 4 images at a time into a mosaic (only during training) self.mosaic_border = [-img_size // 2, -img_size // 2] self.stride = stride + self.path = path try: f = [] # image files @@ -352,37 +363,42 @@ def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, r p = Path(p) # os-agnostic if p.is_dir(): # dir f += glob.glob(str(p / '**' / '*.*'), recursive=True) + # f = list(p.rglob('**/*.*')) # pathlib elif p.is_file(): # file with open(p, 'r') as t: t = t.read().strip().splitlines() parent = str(p.parent) + os.sep f += [x.replace('./', parent) if x.startswith('./') else x for x in t] # local to global path + # f += [p.parent / x.lstrip(os.sep) for x in t] # local to global path (pathlib) else: raise Exception(f'{prefix}{p} does not exist') self.img_files = sorted([x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in img_formats]) + # self.img_files = sorted([x for x in f if x.suffix[1:].lower() in img_formats]) # pathlib assert self.img_files, f'{prefix}No images found' except Exception as e: raise Exception(f'{prefix}Error loading data from {path}: {e}\nSee {help_url}') # Check cache self.label_files = img2label_paths(self.img_files) # labels - cache_path = Path(self.label_files[0]).parent.with_suffix('.cache') # cached labels + cache_path = (p if p.is_file() else Path(self.label_files[0]).parent).with_suffix('.cache') # cached labels if cache_path.is_file(): - cache = torch.load(cache_path) # load - if cache['hash'] != get_hash(self.label_files + self.img_files) or 'results' not in cache: # changed - cache = self.cache_labels(cache_path, prefix) # re-cache + cache, exists = torch.load(cache_path), True # load + if cache['hash'] != get_hash(self.label_files + self.img_files) or 'version' not in cache: # changed + cache, exists = self.cache_labels(cache_path, prefix), False # re-cache else: - cache = self.cache_labels(cache_path, prefix) # cache + cache, exists = self.cache_labels(cache_path, prefix), False # cache # Display cache - [nf, nm, ne, nc, n] = cache.pop('results') # found, missing, empty, corrupted, total - desc = f"Scanning '{cache_path}' for images and labels... {nf} found, {nm} missing, {ne} empty, {nc} corrupted" - tqdm(None, desc=prefix + desc, total=n, initial=n) + nf, nm, ne, nc, n = cache.pop('results') # found, missing, empty, corrupted, total + if exists: + d = f"Scanning '{cache_path}' images and labels... {nf} found, {nm} missing, {ne} empty, {nc} corrupted" + tqdm(None, desc=prefix + d, total=n, initial=n) # display cache results assert nf > 0 or not augment, f'{prefix}No labels in {cache_path}. Can not train without labels. See {help_url}' # Read cache cache.pop('hash') # remove hash - labels, shapes = zip(*cache.values()) + cache.pop('version') # remove version + labels, shapes, self.segments = zip(*cache.values()) self.labels = list(labels) self.shapes = np.array(shapes, dtype=np.float64) self.img_files = list(cache.keys()) # update @@ -433,6 +449,7 @@ def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, r self.imgs[i], self.img_hw0[i], self.img_hw[i] = x # img, hw_original, hw_resized = load_image(self, i) gb += self.imgs[i].nbytes pbar.desc = f'{prefix}Caching images ({gb / 1E9:.1f}GB)' + pbar.close() def cache_labels(self, path=Path('./labels.cache'), prefix=''): # Cache dataset labels, check images and read shapes @@ -445,13 +462,20 @@ def cache_labels(self, path=Path('./labels.cache'), prefix=''): im = Image.open(im_file) im.verify() # PIL verify shape = exif_size(im) # image size - assert (shape[0] > 9) & (shape[1] > 9), 'image size <10 pixels' + segments = [] # instance segments + assert (shape[0] > 9) & (shape[1] > 9), f'image size {shape} <10 pixels' + assert im.format.lower() in img_formats, f'invalid image format {im.format}' # verify labels if os.path.isfile(lb_file): nf += 1 # label found with open(lb_file, 'r') as f: - l = np.array([x.split() for x in f.read().strip().splitlines()], dtype=np.float32) # labels + l = [x.split() for x in f.read().strip().splitlines()] + if any([len(x) > 8 for x in l]): # is segment + classes = np.array([x[0] for x in l], dtype=np.float32) + segments = [np.array(x[1:], dtype=np.float32).reshape(-1, 2) for x in l] # (cls, xy1...) + l = np.concatenate((classes.reshape(-1, 1), segments2boxes(segments)), 1) # (cls, xywh) + l = np.array(l, dtype=np.float32) if len(l): assert l.shape[1] == 5, 'labels require 5 columns each' assert (l >= 0).all(), 'negative labels' @@ -463,19 +487,21 @@ def cache_labels(self, path=Path('./labels.cache'), prefix=''): else: nm += 1 # label missing l = np.zeros((0, 5), dtype=np.float32) - x[im_file] = [l, shape] + x[im_file] = [l, shape, segments] except Exception as e: nc += 1 print(f'{prefix}WARNING: Ignoring corrupted image and/or label {im_file}: {e}') - pbar.desc = f"{prefix}Scanning '{path.parent / path.stem}' for images and labels... " \ + pbar.desc = f"{prefix}Scanning '{path.parent / path.stem}' images and labels... " \ f"{nf} found, {nm} missing, {ne} empty, {nc} corrupted" + pbar.close() if nf == 0: print(f'{prefix}WARNING: No labels found in {path}. See {help_url}') x['hash'] = get_hash(self.label_files + self.img_files) - x['results'] = [nf, nm, ne, nc, i + 1] + x['results'] = nf, nm, ne, nc, i + 1 + x['version'] = 0.1 # cache version torch.save(x, path) # save for next time logging.info(f'{prefix}New cache created: {path}') return x @@ -515,16 +541,9 @@ def __getitem__(self, index): img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment) shapes = (h0, w0), ((h / h0, w / w0), pad) # for COCO mAP rescaling - # Load labels - labels = [] - x = self.labels[index] - if x.size > 0: - # Normalized xywh to pixel xyxy format - labels = x.copy() - labels[:, 1] = ratio[0] * w * (x[:, 1] - x[:, 3] / 2) + pad[0] # pad width - labels[:, 2] = ratio[1] * h * (x[:, 2] - x[:, 4] / 2) + pad[1] # pad height - labels[:, 3] = ratio[0] * w * (x[:, 1] + x[:, 3] / 2) + pad[0] - labels[:, 4] = ratio[1] * h * (x[:, 2] + x[:, 4] / 2) + pad[1] + labels = self.labels[index].copy() + if labels.size: # normalized xywh to pixel xyxy format + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], ratio[0] * w, ratio[1] * h, padw=pad[0], padh=pad[1]) if self.augment: # Augment imagespace @@ -637,19 +656,25 @@ def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5): img_hsv = cv2.merge((cv2.LUT(hue, lut_hue), cv2.LUT(sat, lut_sat), cv2.LUT(val, lut_val))).astype(dtype) cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR, dst=img) # no return needed - # Histogram equalization - # if random.random() < 0.2: - # for i in range(3): - # img[:, :, i] = cv2.equalizeHist(img[:, :, i]) + +def hist_equalize(img, clahe=True, bgr=False): + # Equalize histogram on BGR image 'img' with img.shape(n,m,3) and range 0-255 + yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV if bgr else cv2.COLOR_RGB2YUV) + if clahe: + c = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) + yuv[:, :, 0] = c.apply(yuv[:, :, 0]) + else: + yuv[:, :, 0] = cv2.equalizeHist(yuv[:, :, 0]) # equalize Y channel histogram + return cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR if bgr else cv2.COLOR_YUV2RGB) # convert YUV image to RGB def load_mosaic(self, index): # loads images in a 4-mosaic - labels4 = [] + labels4, segments4 = [], [] s = self.img_size yc, xc = [int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border] # mosaic center x, y - indices = [index] + [self.indices[random.randint(0, self.n - 1)] for _ in range(3)] # 3 additional image indices + indices = [index] + random.choices(self.indices, k=3) # 3 additional image indices for i, index in enumerate(indices): # Load image img, _, (h, w) = load_image(self, index) @@ -674,23 +699,21 @@ def load_mosaic(self, index): padh = y1a - y1b # Labels - x = self.labels[index] - labels = x.copy() - if x.size > 0: # Normalized xywh to pixel xyxy format - labels[:, 1] = w * (x[:, 1] - x[:, 3] / 2) + padw - labels[:, 2] = h * (x[:, 2] - x[:, 4] / 2) + padh - labels[:, 3] = w * (x[:, 1] + x[:, 3] / 2) + padw - labels[:, 4] = h * (x[:, 2] + x[:, 4] / 2) + padh + labels, segments = self.labels[index].copy(), self.segments[index].copy() + if labels.size: + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padw, padh) # normalized xywh to pixel xyxy format + segments = [xyn2xy(x, w, h, padw, padh) for x in segments] labels4.append(labels) + segments4.extend(segments) # Concat/clip labels - if len(labels4): - labels4 = np.concatenate(labels4, 0) - np.clip(labels4[:, 1:], 0, 2 * s, out=labels4[:, 1:]) # use with random_perspective - # img4, labels4 = replicate(img4, labels4) # replicate + labels4 = np.concatenate(labels4, 0) + for x in (labels4[:, 1:], *segments4): + np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective() + # img4, labels4 = replicate(img4, labels4) # replicate # Augment - img4, labels4 = random_perspective(img4, labels4, + img4, labels4 = random_perspective(img4, labels4, segments4, degrees=self.hyp['degrees'], translate=self.hyp['translate'], scale=self.hyp['scale'], @@ -704,9 +727,9 @@ def load_mosaic(self, index): def load_mosaic9(self, index): # loads images in a 9-mosaic - labels9 = [] + labels9, segments9 = [], [] s = self.img_size - indices = [index] + [self.indices[random.randint(0, self.n - 1)] for _ in range(8)] # 8 additional image indices + indices = [index] + random.choices(self.indices, k=8) # 8 additional image indices for i, index in enumerate(indices): # Load image img, _, (h, w) = load_image(self, index) @@ -737,34 +760,34 @@ def load_mosaic9(self, index): x1, y1, x2, y2 = [max(x, 0) for x in c] # allocate coords # Labels - x = self.labels[index] - labels = x.copy() - if x.size > 0: # Normalized xywh to pixel xyxy format - labels[:, 1] = w * (x[:, 1] - x[:, 3] / 2) + padx - labels[:, 2] = h * (x[:, 2] - x[:, 4] / 2) + pady - labels[:, 3] = w * (x[:, 1] + x[:, 3] / 2) + padx - labels[:, 4] = h * (x[:, 2] + x[:, 4] / 2) + pady + labels, segments = self.labels[index].copy(), self.segments[index].copy() + if labels.size: + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padx, pady) # normalized xywh to pixel xyxy format + segments = [xyn2xy(x, w, h, padx, pady) for x in segments] labels9.append(labels) + segments9.extend(segments) # Image img9[y1:y2, x1:x2] = img[y1 - pady:, x1 - padx:] # img9[ymin:ymax, xmin:xmax] hp, wp = h, w # height, width previous # Offset - yc, xc = [int(random.uniform(0, s)) for x in self.mosaic_border] # mosaic center x, y + yc, xc = [int(random.uniform(0, s)) for _ in self.mosaic_border] # mosaic center x, y img9 = img9[yc:yc + 2 * s, xc:xc + 2 * s] # Concat/clip labels - if len(labels9): - labels9 = np.concatenate(labels9, 0) - labels9[:, [1, 3]] -= xc - labels9[:, [2, 4]] -= yc + labels9 = np.concatenate(labels9, 0) + labels9[:, [1, 3]] -= xc + labels9[:, [2, 4]] -= yc + c = np.array([xc, yc]) # centers + segments9 = [x - c for x in segments9] - np.clip(labels9[:, 1:], 0, 2 * s, out=labels9[:, 1:]) # use with random_perspective - # img9, labels9 = replicate(img9, labels9) # replicate + for x in (labels9[:, 1:], *segments9): + np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective() + # img9, labels9 = replicate(img9, labels9) # replicate # Augment - img9, labels9 = random_perspective(img9, labels9, + img9, labels9 = random_perspective(img9, labels9, segments9, degrees=self.hyp['degrees'], translate=self.hyp['translate'], scale=self.hyp['scale'], @@ -792,8 +815,8 @@ def replicate(img, labels): return img, labels -def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True): - # Resize image to a 32-pixel-multiple rectangle https://github.com/ultralytics/yolov3/issues/232 +def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32): + # Resize and pad image while meeting stride-multiple constraints shape = img.shape[:2] # current shape [height, width] if isinstance(new_shape, int): new_shape = (new_shape, new_shape) @@ -808,7 +831,7 @@ def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scale new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding if auto: # minimum rectangle - dw, dh = np.mod(dw, 32), np.mod(dh, 32) # wh padding + dw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh padding elif scaleFill: # stretch dw, dh = 0.0, 0.0 new_unpad = (new_shape[1], new_shape[0]) @@ -825,7 +848,8 @@ def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scale return img, ratio, (dw, dh) -def random_perspective(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, perspective=0.0, border=(0, 0)): +def random_perspective(img, targets=(), segments=(), degrees=10, translate=.1, scale=.1, shear=10, perspective=0.0, + border=(0, 0)): # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) # targets = [cls, xyxy] @@ -877,37 +901,38 @@ def random_perspective(img, targets=(), degrees=10, translate=.1, scale=.1, shea # Transform label coordinates n = len(targets) if n: - # warp points - xy = np.ones((n * 4, 3)) - xy[:, :2] = targets[:, [1, 2, 3, 4, 1, 4, 3, 2]].reshape(n * 4, 2) # x1y1, x2y2, x1y2, x2y1 - xy = xy @ M.T # transform - if perspective: - xy = (xy[:, :2] / xy[:, 2:3]).reshape(n, 8) # rescale - else: # affine - xy = xy[:, :2].reshape(n, 8) - - # create new boxes - x = xy[:, [0, 2, 4, 6]] - y = xy[:, [1, 3, 5, 7]] - xy = np.concatenate((x.min(1), y.min(1), x.max(1), y.max(1))).reshape(4, n).T - - # # apply angle-based reduction of bounding boxes - # radians = a * math.pi / 180 - # reduction = max(abs(math.sin(radians)), abs(math.cos(radians))) ** 0.5 - # x = (xy[:, 2] + xy[:, 0]) / 2 - # y = (xy[:, 3] + xy[:, 1]) / 2 - # w = (xy[:, 2] - xy[:, 0]) * reduction - # h = (xy[:, 3] - xy[:, 1]) * reduction - # xy = np.concatenate((x - w / 2, y - h / 2, x + w / 2, y + h / 2)).reshape(4, n).T - - # clip boxes - xy[:, [0, 2]] = xy[:, [0, 2]].clip(0, width) - xy[:, [1, 3]] = xy[:, [1, 3]].clip(0, height) + use_segments = any(x.any() for x in segments) + new = np.zeros((n, 4)) + if use_segments: # warp segments + segments = resample_segments(segments) # upsample + for i, segment in enumerate(segments): + xy = np.ones((len(segment), 3)) + xy[:, :2] = segment + xy = xy @ M.T # transform + xy = xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2] # perspective rescale or affine + + # clip + new[i] = segment2box(xy, width, height) + + else: # warp boxes + xy = np.ones((n * 4, 3)) + xy[:, :2] = targets[:, [1, 2, 3, 4, 1, 4, 3, 2]].reshape(n * 4, 2) # x1y1, x2y2, x1y2, x2y1 + xy = xy @ M.T # transform + xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]).reshape(n, 8) # perspective rescale or affine + + # create new boxes + x = xy[:, [0, 2, 4, 6]] + y = xy[:, [1, 3, 5, 7]] + new = np.concatenate((x.min(1), y.min(1), x.max(1), y.max(1))).reshape(4, n).T + + # clip + new[:, [0, 2]] = new[:, [0, 2]].clip(0, width) + new[:, [1, 3]] = new[:, [1, 3]].clip(0, height) # filter candidates - i = box_candidates(box1=targets[:, 1:5].T * s, box2=xy.T) + i = box_candidates(box1=targets[:, 1:5].T * s, box2=new.T, area_thr=0.01 if use_segments else 0.10) targets = targets[i] - targets[:, 1:5] = xy[i] + targets[:, 1:5] = new[i] return img, targets @@ -1016,19 +1041,24 @@ def extract_boxes(path='../coco128/'): # from utils.datasets import *; extract_ assert cv2.imwrite(str(f), im[b[1]:b[3], b[0]:b[2]]), f'box failure in {f}' -def autosplit(path='../coco128', weights=(0.9, 0.1, 0.0)): # from utils.datasets import *; autosplit('../coco128') +def autosplit(path='../coco128', weights=(0.9, 0.1, 0.0), annotated_only=False): """ Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files - # Arguments - path: Path to images directory - weights: Train, val, test weights (list) + Usage: from utils.datasets import *; autosplit('../coco128') + Arguments + path: Path to images directory + weights: Train, val, test weights (list) + annotated_only: Only use images with an annotated txt file """ path = Path(path) # images dir - files = list(path.rglob('*.*')) + files = sum([list(path.rglob(f"*.{img_ext}")) for img_ext in img_formats], []) # image files only n = len(files) # number of files indices = random.choices([0, 1, 2], weights=weights, k=n) # assign each image to a split + txt = ['autosplit_train.txt', 'autosplit_val.txt', 'autosplit_test.txt'] # 3 txt files [(path / x).unlink() for x in txt if (path / x).exists()] # remove existing + + print(f'Autosplitting images from {path}' + ', using *.txt labeled images only' * annotated_only) for i, img in tqdm(zip(indices, files), total=n): - if img.suffix[1:] in img_formats: + if not annotated_only or Path(img2label_paths([str(img)])[0]).exists(): # check label with open(path / txt[i], 'a') as f: f.write(str(img) + '\n') # add image to txt file diff --git a/utils/general.py b/utils/general.py index a3238efa49..dbdcd39601 100755 --- a/utils/general.py +++ b/utils/general.py @@ -1,9 +1,10 @@ -# General utils +# YOLOv3 general utils import glob import logging import math import os +import platform import random import re import subprocess @@ -12,6 +13,7 @@ import cv2 import numpy as np +import pandas as pd import torch import torchvision import yaml @@ -23,6 +25,7 @@ # Settings torch.set_printoptions(linewidth=320, precision=5, profile='long') np.set_printoptions(linewidth=320, formatter={'float_kind': '{:11.5g}'.format}) # format short g, %precision=5 +pd.options.display.max_columns = 10 cv2.setNumThreads(0) # prevent OpenCV from multithreading (incompatible with PyTorch DataLoader) os.environ['NUMEXPR_MAX_THREADS'] = str(min(os.cpu_count(), 8)) # NumExpr max threads @@ -46,40 +49,75 @@ def get_latest_run(search_dir='.'): return max(last_list, key=os.path.getctime) if last_list else '' +def isdocker(): + # Is environment a Docker container + return Path('/workspace').exists() # or Path('/.dockerenv').exists() + + +def emojis(str=''): + # Return platform-dependent emoji-safe version of string + return str.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else str + + def check_online(): # Check internet connectivity import socket try: - socket.create_connection(("1.1.1.1", 53)) # check host accesability + socket.create_connection(("1.1.1.1", 443), 5) # check host accesability return True except OSError: return False def check_git_status(): - # Suggest 'git pull' if YOLOv5 is out of date + # Recommend 'git pull' if code is out of date print(colorstr('github: '), end='') try: - if Path('.git').exists() and check_online(): - url = subprocess.check_output( - 'git fetch && git config --get remote.origin.url', shell=True).decode('utf-8')[:-1] - n = int(subprocess.check_output( - 'git rev-list $(git rev-parse --abbrev-ref HEAD)..origin/master --count', shell=True)) # commits behind - if n > 0: - print(f"⚠️ WARNING: code is out of date by {n} {'commits' if n > 1 else 'commmit'}. " - f"Use 'git pull' to update or 'git clone {url}' to download latest.") - else: - print(f'up to date with {url} ✅') + assert Path('.git').exists(), 'skipping check (not a git repository)' + assert not isdocker(), 'skipping check (Docker image)' + assert check_online(), 'skipping check (offline)' + + cmd = 'git fetch && git config --get remote.origin.url' + url = subprocess.check_output(cmd, shell=True).decode().strip().rstrip('.git') # github repo url + branch = subprocess.check_output('git rev-parse --abbrev-ref HEAD', shell=True).decode().strip() # checked out + n = int(subprocess.check_output(f'git rev-list {branch}..origin/master --count', shell=True)) # commits behind + if n > 0: + s = f"⚠️ WARNING: code is out of date by {n} commit{'s' * (n > 1)}. " \ + f"Use 'git pull' to update or 'git clone {url}' to download latest." + else: + s = f'up to date with {url} ✅' + print(emojis(s)) # emoji-safe except Exception as e: print(e) -def check_requirements(file='requirements.txt'): - # Check installed dependencies meet requirements - import pkg_resources - requirements = pkg_resources.parse_requirements(Path(file).open()) - requirements = [x.name + ''.join(*x.specs) if len(x.specs) else x.name for x in requirements] - pkg_resources.require(requirements) # DistributionNotFound or VersionConflict exception if requirements not met +def check_requirements(requirements='requirements.txt', exclude=()): + # Check installed dependencies meet requirements (pass *.txt file or list of packages) + import pkg_resources as pkg + prefix = colorstr('red', 'bold', 'requirements:') + if isinstance(requirements, (str, Path)): # requirements.txt file + file = Path(requirements) + if not file.exists(): + print(f"{prefix} {file.resolve()} not found, check failed.") + return + requirements = [f'{x.name}{x.specifier}' for x in pkg.parse_requirements(file.open()) if x.name not in exclude] + else: # list or tuple of packages + requirements = [x for x in requirements if x not in exclude] + + n = 0 # number of packages updates + for r in requirements: + try: + pkg.require(r) + except Exception as e: # DistributionNotFound or VersionConflict if requirements not met + n += 1 + print(f"{prefix} {e.req} not found and is required by YOLOv3, attempting auto-update...") + print(subprocess.check_output(f"pip install '{e.req}'", shell=True).decode()) + + if n: # if packages updated + source = file.resolve() if 'file' in locals() else requirements + s = f"{prefix} {n} package{'s' * (n > 1)} updated per {source}\n" \ + f"{prefix} ⚠️ {colorstr('bold', 'Restart runtime or rerun command for updates to take effect')}\n" + print(emojis(s)) # emoji-safe def check_img_size(img_size, s=32): @@ -90,14 +128,28 @@ def check_img_size(img_size, s=32): return new_size +def check_imshow(): + # Check if environment supports image displays + try: + assert not isdocker(), 'cv2.imshow() is disabled in Docker environments' + cv2.imshow('test', np.zeros((1, 1, 3))) + cv2.waitKey(1) + cv2.destroyAllWindows() + cv2.waitKey(1) + return True + except Exception as e: + print(f'WARNING: Environment does not support cv2.imshow() or PIL Image.show() image displays\n{e}') + return False + + def check_file(file): # Search for file if not found - if os.path.isfile(file) or file == '': + if Path(file).is_file() or file == '': return file else: files = glob.glob('./**/' + file, recursive=True) # find file - assert len(files), 'File Not Found: %s' % file # assert file was found - assert len(files) == 1, "Multiple files match '%s', specify exact path: %s" % (file, files) # assert unique + assert len(files), f'File Not Found: {file}' # assert file was found + assert len(files) == 1, f"Multiple files match '{file}', specify exact path: {files}" # assert unique return files[0] # return file @@ -220,6 +272,50 @@ def xywh2xyxy(x): return y +def xywhn2xyxy(x, w=640, h=640, padw=0, padh=0): + # Convert nx4 boxes from [x, y, w, h] normalized to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) + y[:, 0] = w * (x[:, 0] - x[:, 2] / 2) + padw # top left x + y[:, 1] = h * (x[:, 1] - x[:, 3] / 2) + padh # top left y + y[:, 2] = w * (x[:, 0] + x[:, 2] / 2) + padw # bottom right x + y[:, 3] = h * (x[:, 1] + x[:, 3] / 2) + padh # bottom right y + return y + + +def xyn2xy(x, w=640, h=640, padw=0, padh=0): + # Convert normalized segments into pixel segments, shape (n,2) + y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) + y[:, 0] = w * x[:, 0] + padw # top left x + y[:, 1] = h * x[:, 1] + padh # top left y + return y + + +def segment2box(segment, width=640, height=640): + # Convert 1 segment label to 1 box label, applying inside-image constraint, i.e. (xy1, xy2, ...) to (xyxy) + x, y = segment.T # segment xy + inside = (x >= 0) & (y >= 0) & (x <= width) & (y <= height) + x, y, = x[inside], y[inside] + return np.array([x.min(), y.min(), x.max(), y.max()]) if any(x) else np.zeros((1, 4)) # xyxy + + +def segments2boxes(segments): + # Convert segment labels to box labels, i.e. (cls, xy1, xy2, ...) to (cls, xywh) + boxes = [] + for s in segments: + x, y = s.T # segment xy + boxes.append([x.min(), y.min(), x.max(), y.max()]) # cls, xyxy + return xyxy2xywh(np.array(boxes)) # cls, xywh + + +def resample_segments(segments, n=1000): + # Up-sample an (n,2) segment + for i, s in enumerate(segments): + x = np.linspace(0, len(s) - 1, n) + xp = np.arange(len(s)) + segments[i] = np.concatenate([np.interp(x, xp, s[:, i]) for i in range(2)]).reshape(2, -1).T # segment xy + return segments + + def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None): # Rescale coords (xyxy) from img1_shape to img0_shape if ratio_pad is None: # calculate from img0_shape @@ -244,7 +340,7 @@ def clip_coords(boxes, img_shape): boxes[:, 3].clamp_(0, img_shape[0]) # y2 -def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-9): +def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7): # Returns the IoU of box1 to box2. box1 is 4, box2 is nx4 box2 = box2.T @@ -280,7 +376,7 @@ def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, eps= elif CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47 v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2) with torch.no_grad(): - alpha = v / ((1 + eps) - iou + v) + alpha = v / (v - iou + (1 + eps)) return iou - (rho2 / c2 + v * alpha) # CIoU else: # GIoU https://arxiv.org/pdf/1902.09630.pdf c_area = cw * ch + eps # convex area @@ -322,11 +418,12 @@ def wh_iou(wh1, wh2): return inter / (wh1.prod(2) + wh2.prod(2) - inter) # iou = inter / (area1 + area2 - inter) -def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False, labels=()): - """Performs Non-Maximum Suppression (NMS) on inference results +def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False, multi_label=False, + labels=()): + """Runs Non-Maximum Suppression (NMS) on inference results Returns: - detections with shape: nx6 (x1, y1, x2, y2, conf, cls) + list of detections, on (n,6) tensor per image [xyxy, conf, cls] """ nc = prediction.shape[2] - 5 # number of classes @@ -338,7 +435,7 @@ def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=Non max_nms = 30000 # maximum number of boxes into torchvision.ops.nms() time_limit = 10.0 # seconds to quit after redundant = True # require redundant detections - multi_label = nc > 1 # multiple labels per box (adds 0.5ms/img) + multi_label &= nc > 1 # multiple labels per box (adds 0.5ms/img) merge = False # use merge-NMS t = time.time() @@ -412,18 +509,20 @@ def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=Non return output -def strip_optimizer(f='weights/best.pt', s=''): # from utils.general import *; strip_optimizer() +def strip_optimizer(f='best.pt', s=''): # from utils.general import *; strip_optimizer() # Strip optimizer from 'f' to finalize training, optionally save as 's' x = torch.load(f, map_location=torch.device('cpu')) - for key in 'optimizer', 'training_results', 'wandb_id': - x[key] = None + if x.get('ema'): + x['model'] = x['ema'] # replace model with ema + for k in 'optimizer', 'training_results', 'wandb_id', 'ema', 'updates': # keys + x[k] = None x['epoch'] = -1 x['model'].half() # to FP16 for p in x['model'].parameters(): p.requires_grad = False torch.save(x, s or f) mb = os.path.getsize(s or f) / 1E6 # filesize - print('Optimizer stripped from %s,%s %.1fMB' % (f, (' saved as %s,' % s) if s else '', mb)) + print(f"Optimizer stripped from {f},{(' saved as %s,' % s) if s else ''} {mb:.1f}MB") def print_mutation(hyp, results, yaml_file='hyp_evolved.yaml', bucket=''): diff --git a/utils/google_utils.py b/utils/google_utils.py index e4b115a599..61af2f4343 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -21,13 +21,13 @@ def attempt_download(file, repo='ultralytics/yolov3'): file = Path(str(file).strip().replace("'", '').lower()) if not file.exists(): - # try: - # response = requests.get(f'https://api.github.com/repos/{repo}/releases/latest').json() # github api - # assets = [x['name'] for x in response['assets']] # release assets, i.e. ['yolov5s.pt', 'yolov5m.pt', ...] - # tag = response['tag_name'] # i.e. 'v1.0' - # except: # fallback plan - assets = ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt'] - tag = subprocess.check_output('git tag', shell=True).decode().split()[-1] + try: + response = requests.get(f'https://api.github.com/repos/{repo}/releases/latest').json() # github api + assets = [x['name'] for x in response['assets']] # release assets, i.e. ['yolov5s.pt', 'yolov5m.pt', ...] + tag = response['tag_name'] # i.e. 'v1.0' + except: # fallback plan + assets = ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt'] + tag = subprocess.check_output('git tag', shell=True).decode().split()[-1] name = file.name if name in assets: diff --git a/utils/loss.py b/utils/loss.py index 844d503924..a2c5cce795 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -85,117 +85,132 @@ def forward(self, pred, true): return loss -def compute_loss(p, targets, model): # predictions, targets, model - device = targets.device - lcls, lbox, lobj = torch.zeros(1, device=device), torch.zeros(1, device=device), torch.zeros(1, device=device) - tcls, tbox, indices, anchors = build_targets(p, targets, model) # targets - h = model.hyp # hyperparameters - - # Define criteria - BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device)) # weight=model.class_weights) - BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device)) - - # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 - cp, cn = smooth_BCE(eps=0.0) - - # Focal loss - g = h['fl_gamma'] # focal loss gamma - if g > 0: - BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) - - # Losses - balance = [4.0, 1.0, 0.4, 0.1] # P3-P6 - for i, pi in enumerate(p): # layer index, layer predictions - b, a, gj, gi = indices[i] # image, anchor, gridy, gridx - tobj = torch.zeros_like(pi[..., 0], device=device) # target obj - - n = b.shape[0] # number of targets - if n: - ps = pi[b, a, gj, gi] # prediction subset corresponding to targets - - # Regression - pxy = ps[:, :2].sigmoid() * 2. - 0.5 - pwh = (ps[:, 2:4].sigmoid() * 2) ** 2 * anchors[i] - pbox = torch.cat((pxy, pwh), 1) # predicted box - iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, CIoU=True) # iou(prediction, target) - lbox += (1.0 - iou).mean() # iou loss - - # Objectness - tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * iou.detach().clamp(0).type(tobj.dtype) # iou ratio - - # Classification - if model.nc > 1: # cls loss (only if multiple classes) - t = torch.full_like(ps[:, 5:], cn, device=device) # targets - t[range(n), tcls[i]] = cp - lcls += BCEcls(ps[:, 5:], t) # BCE - - # Append targets to text file - # with open('targets.txt', 'a') as file: - # [file.write('%11.5g ' * 4 % tuple(x) + '\n') for x in torch.cat((txy[i], twh[i]), 1)] - - lobj += BCEobj(pi[..., 4], tobj) * balance[i] # obj loss - - lbox *= h['box'] - lobj *= h['obj'] - lcls *= h['cls'] - bs = tobj.shape[0] # batch size - - loss = lbox + lobj + lcls - return loss * bs, torch.cat((lbox, lobj, lcls, loss)).detach() - - -def build_targets(p, targets, model): - # Build targets for compute_loss(), input targets(image,class,x,y,w,h) - det = model.module.model[-1] if is_parallel(model) else model.model[-1] # Detect() module - na, nt = det.na, targets.shape[0] # number of anchors, targets - tcls, tbox, indices, anch = [], [], [], [] - gain = torch.ones(7, device=targets.device) # normalized to gridspace gain - ai = torch.arange(na, device=targets.device).float().view(na, 1).repeat(1, nt) # same as .repeat_interleave(nt) - targets = torch.cat((targets.repeat(na, 1, 1), ai[:, :, None]), 2) # append anchor indices - - g = 0.5 # bias - off = torch.tensor([[0, 0], - # [1, 0], [0, 1], [-1, 0], [0, -1], # j,k,l,m - # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm - ], device=targets.device).float() * g # offsets - - for i in range(det.nl): - anchors = det.anchors[i] - gain[2:6] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain - - # Match targets to anchors - t = targets * gain - if nt: - # Matches - r = t[:, :, 4:6] / anchors[:, None] # wh ratio - j = torch.max(r, 1. / r).max(2)[0] < model.hyp['anchor_t'] # compare - # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2)) - t = t[j] # filter - - # Offsets +class ComputeLoss: + # Compute losses + def __init__(self, model, autobalance=False): + super(ComputeLoss, self).__init__() + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device)) + BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device)) + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get('label_smoothing', 0.0)) # positive, negative BCE targets + + # Focal loss + g = h['fl_gamma'] # focal loss gamma + if g > 0: + BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) + + det = model.module.model[-1] if is_parallel(model) else model.model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(det.nl, [4.0, 1.0, 0.25, 0.06, .02]) # P3-P7 + self.ssi = list(det.stride).index(16) if autobalance else 0 # stride 16 index + self.BCEcls, self.BCEobj, self.gr, self.hyp, self.autobalance = BCEcls, BCEobj, model.gr, h, autobalance + for k in 'na', 'nc', 'nl', 'anchors': + setattr(self, k, getattr(det, k)) + + def __call__(self, p, targets): # predictions, targets, model + device = targets.device + lcls, lbox, lobj = torch.zeros(1, device=device), torch.zeros(1, device=device), torch.zeros(1, device=device) + tcls, tbox, indices, anchors = self.build_targets(p, targets) # targets + + # Losses + for i, pi in enumerate(p): # layer index, layer predictions + b, a, gj, gi = indices[i] # image, anchor, gridy, gridx + tobj = torch.zeros_like(pi[..., 0], device=device) # target obj + + n = b.shape[0] # number of targets + if n: + ps = pi[b, a, gj, gi] # prediction subset corresponding to targets + + # Regression + pxy = ps[:, :2].sigmoid() * 2. - 0.5 + pwh = (ps[:, 2:4].sigmoid() * 2) ** 2 * anchors[i] + pbox = torch.cat((pxy, pwh), 1) # predicted box + iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, CIoU=True) # iou(prediction, target) + lbox += (1.0 - iou).mean() # iou loss + + # Objectness + tobj[b, a, gj, gi] = (1.0 - self.gr) + self.gr * iou.detach().clamp(0).type(tobj.dtype) # iou ratio + + # Classification + if self.nc > 1: # cls loss (only if multiple classes) + t = torch.full_like(ps[:, 5:], self.cn, device=device) # targets + t[range(n), tcls[i]] = self.cp + lcls += self.BCEcls(ps[:, 5:], t) # BCE + + # Append targets to text file + # with open('targets.txt', 'a') as file: + # [file.write('%11.5g ' * 4 % tuple(x) + '\n') for x in torch.cat((txy[i], twh[i]), 1)] + + obji = self.BCEobj(pi[..., 4], tobj) + lobj += obji * self.balance[i] # obj loss + if self.autobalance: + self.balance[i] = self.balance[i] * 0.9999 + 0.0001 / obji.detach().item() + + if self.autobalance: + self.balance = [x / self.balance[self.ssi] for x in self.balance] + lbox *= self.hyp['box'] + lobj *= self.hyp['obj'] + lcls *= self.hyp['cls'] + bs = tobj.shape[0] # batch size + + loss = lbox + lobj + lcls + return loss * bs, torch.cat((lbox, lobj, lcls, loss)).detach() + + def build_targets(self, p, targets): + # Build targets for compute_loss(), input targets(image,class,x,y,w,h) + na, nt = self.na, targets.shape[0] # number of anchors, targets + tcls, tbox, indices, anch = [], [], [], [] + gain = torch.ones(7, device=targets.device) # normalized to gridspace gain + ai = torch.arange(na, device=targets.device).float().view(na, 1).repeat(1, nt) # same as .repeat_interleave(nt) + targets = torch.cat((targets.repeat(na, 1, 1), ai[:, :, None]), 2) # append anchor indices + + g = 0.5 # bias + off = torch.tensor([[0, 0], + # [1, 0], [0, 1], [-1, 0], [0, -1], # j,k,l,m + # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm + ], device=targets.device).float() * g # offsets + + for i in range(self.nl): + anchors = self.anchors[i] + gain[2:6] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain + + # Match targets to anchors + t = targets * gain + if nt: + # Matches + r = t[:, :, 4:6] / anchors[:, None] # wh ratio + j = torch.max(r, 1. / r).max(2)[0] < self.hyp['anchor_t'] # compare + # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2)) + t = t[j] # filter + + # Offsets + gxy = t[:, 2:4] # grid xy + gxi = gain[[2, 3]] - gxy # inverse + j, k = ((gxy % 1. < g) & (gxy > 1.)).T + l, m = ((gxi % 1. < g) & (gxi > 1.)).T + j = torch.stack((torch.ones_like(j),)) + t = t.repeat((off.shape[0], 1, 1))[j] + offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j] + else: + t = targets[0] + offsets = 0 + + # Define + b, c = t[:, :2].long().T # image, class gxy = t[:, 2:4] # grid xy - gxi = gain[[2, 3]] - gxy # inverse - j, k = ((gxy % 1. < g) & (gxy > 1.)).T - l, m = ((gxi % 1. < g) & (gxi > 1.)).T - j = torch.stack((torch.ones_like(j),)) - t = t.repeat((off.shape[0], 1, 1))[j] - offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j] - else: - t = targets[0] - offsets = 0 - - # Define - b, c = t[:, :2].long().T # image, class - gxy = t[:, 2:4] # grid xy - gwh = t[:, 4:6] # grid wh - gij = (gxy - offsets).long() - gi, gj = gij.T # grid xy indices - - # Append - a = t[:, 6].long() # anchor indices - indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1))) # image, anchor, grid indices - tbox.append(torch.cat((gxy - gij, gwh), 1)) # box - anch.append(anchors[a]) # anchors - tcls.append(c) # class - - return tcls, tbox, indices, anch + gwh = t[:, 4:6] # grid wh + gij = (gxy - offsets).long() + gi, gj = gij.T # grid xy indices + + # Append + a = t[:, 6].long() # anchor indices + indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1))) # image, anchor, grid indices + tbox.append(torch.cat((gxy - gij, gwh), 1)) # box + anch.append(anchors[a]) # anchors + tcls.append(c) # class + + return tcls, tbox, indices, anch diff --git a/utils/metrics.py b/utils/metrics.py index 99d5bcfaf2..666b8c7ec1 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -15,7 +15,7 @@ def fitness(x): return (x[:, :4] * w).sum(1) -def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='precision-recall_curve.png', names=[]): +def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names=()): """ Compute the average precision, given the recall and precision curves. Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. # Arguments @@ -35,12 +35,11 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='precision # Find unique classes unique_classes = np.unique(target_cls) + nc = unique_classes.shape[0] # number of classes, number of detections # Create Precision-Recall curve and compute AP for each class px, py = np.linspace(0, 1, 1000), [] # for plotting - pr_score = 0.1 # score to evaluate P and R https://github.com/ultralytics/yolov3/issues/898 - s = [unique_classes.shape[0], tp.shape[1]] # number class, number iou thresholds (i.e. 10 for mAP0.5...0.95) - ap, p, r = np.zeros(s), np.zeros(s), np.zeros(s) + ap, p, r = np.zeros((nc, tp.shape[1])), np.zeros((nc, 1000)), np.zeros((nc, 1000)) for ci, c in enumerate(unique_classes): i = pred_cls == c n_l = (target_cls == c).sum() # number of labels @@ -55,25 +54,28 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='precision # Recall recall = tpc / (n_l + 1e-16) # recall curve - r[ci] = np.interp(-pr_score, -conf[i], recall[:, 0]) # r at pr_score, negative x, xp because xp decreases + r[ci] = np.interp(-px, -conf[i], recall[:, 0], left=0) # negative x, xp because xp decreases # Precision precision = tpc / (tpc + fpc) # precision curve - p[ci] = np.interp(-pr_score, -conf[i], precision[:, 0]) # p at pr_score + p[ci] = np.interp(-px, -conf[i], precision[:, 0], left=1) # p at pr_score # AP from recall-precision curve for j in range(tp.shape[1]): ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j]) - if plot and (j == 0): + if plot and j == 0: py.append(np.interp(px, mrec, mpre)) # precision at mAP@0.5 - # Compute F1 score (harmonic mean of precision and recall) + # Compute F1 (harmonic mean of precision and recall) f1 = 2 * p * r / (p + r + 1e-16) - if plot: - plot_pr_curve(px, py, ap, save_dir, names) + plot_pr_curve(px, py, ap, Path(save_dir) / 'PR_curve.png', names) + plot_mc_curve(px, f1, Path(save_dir) / 'F1_curve.png', names, ylabel='F1') + plot_mc_curve(px, p, Path(save_dir) / 'P_curve.png', names, ylabel='Precision') + plot_mc_curve(px, r, Path(save_dir) / 'R_curve.png', names, ylabel='Recall') - return p, r, ap, f1, unique_classes.astype('int32') + i = f1.mean(0).argmax() # max F1 index + return p[:, i], r[:, i], ap, f1[:, i], unique_classes.astype('int32') def compute_ap(recall, precision): @@ -145,12 +147,12 @@ def process_batch(self, detections, labels): if n and sum(j) == 1: self.matrix[gc, detection_classes[m1[j]]] += 1 # correct else: - self.matrix[gc, self.nc] += 1 # background FP + self.matrix[self.nc, gc] += 1 # background FP if n: for i, dc in enumerate(detection_classes): if not any(m1 == i): - self.matrix[self.nc, dc] += 1 # background FN + self.matrix[dc, self.nc] += 1 # background FN def matrix(self): return self.matrix @@ -166,8 +168,8 @@ def plot(self, save_dir='', names=()): sn.set(font_scale=1.0 if self.nc < 50 else 0.8) # for label size labels = (0 < len(names) < 99) and len(names) == self.nc # apply names to ticklabels sn.heatmap(array, annot=self.nc < 30, annot_kws={"size": 8}, cmap='Blues', fmt='.2f', square=True, - xticklabels=names + ['background FN'] if labels else "auto", - yticklabels=names + ['background FP'] if labels else "auto").set_facecolor((1, 1, 1)) + xticklabels=names + ['background FP'] if labels else "auto", + yticklabels=names + ['background FN'] if labels else "auto").set_facecolor((1, 1, 1)) fig.axes[0].set_xlabel('True') fig.axes[0].set_ylabel('Predicted') fig.savefig(Path(save_dir) / 'confusion_matrix.png', dpi=250) @@ -181,13 +183,14 @@ def print(self): # Plots ---------------------------------------------------------------------------------------------------------------- -def plot_pr_curve(px, py, ap, save_dir='.', names=()): +def plot_pr_curve(px, py, ap, save_dir='pr_curve.png', names=()): + # Precision-recall curve fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True) py = np.stack(py, axis=1) - if 0 < len(names) < 21: # show mAP in legend if < 10 classes + if 0 < len(names) < 21: # display per-class legend if < 21 classes for i, y in enumerate(py.T): - ax.plot(px, y, linewidth=1, label=f'{names[i]} %.3f' % ap[i, 0]) # plot(recall, precision) + ax.plot(px, y, linewidth=1, label=f'{names[i]} {ap[i, 0]:.3f}') # plot(recall, precision) else: ax.plot(px, py, linewidth=1, color='grey') # plot(recall, precision) @@ -197,4 +200,24 @@ def plot_pr_curve(px, py, ap, save_dir='.', names=()): ax.set_xlim(0, 1) ax.set_ylim(0, 1) plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left") - fig.savefig(Path(save_dir) / 'precision_recall_curve.png', dpi=250) + fig.savefig(Path(save_dir), dpi=250) + + +def plot_mc_curve(px, py, save_dir='mc_curve.png', names=(), xlabel='Confidence', ylabel='Metric'): + # Metric-confidence curve + fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True) + + if 0 < len(names) < 21: # display per-class legend if < 21 classes + for i, y in enumerate(py): + ax.plot(px, y, linewidth=1, label=f'{names[i]}') # plot(confidence, metric) + else: + ax.plot(px, py.T, linewidth=1, color='grey') # plot(confidence, metric) + + y = py.mean(0) + ax.plot(px, y, linewidth=3, color='blue', label=f'all classes {y.max():.2f} at {px[y.argmax()]:.3f}') + ax.set_xlabel(xlabel) + ax.set_ylabel(ylabel) + ax.set_xlim(0, 1) + ax.set_ylim(0, 1) + plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left") + fig.savefig(Path(save_dir), dpi=250) diff --git a/utils/plots.py b/utils/plots.py index 47cd707760..8b90bd8d07 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -15,7 +15,7 @@ import seaborn as sns import torch import yaml -from PIL import Image, ImageDraw +from PIL import Image, ImageDraw, ImageFont from scipy.signal import butter, filtfilt from utils.general import xywh2xyxy, xyxy2xywh @@ -31,7 +31,7 @@ def color_list(): def hex2rgb(h): return tuple(int(h[1 + i:1 + i + 2], 16) for i in (0, 2, 4)) - return [hex2rgb(h) for h in plt.rcParams['axes.prop_cycle'].by_key()['color']] + return [hex2rgb(h) for h in matplotlib.colors.TABLEAU_COLORS.values()] # or BASE_ (8), CSS4_ (148), XKCD_ (949) def hist2d(x, y, n=100): @@ -54,7 +54,7 @@ def butter_lowpass(cutoff, fs, order): return filtfilt(b, a, data) # forward-backward filter -def plot_one_box(x, img, color=None, label=None, line_thickness=None): +def plot_one_box(x, img, color=None, label=None, line_thickness=3): # Plots one bounding box on image img tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line/font thickness color = color or [random.randint(0, 255) for _ in range(3)] @@ -68,6 +68,20 @@ def plot_one_box(x, img, color=None, label=None, line_thickness=None): cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA) +def plot_one_box_PIL(box, img, color=None, label=None, line_thickness=None): + img = Image.fromarray(img) + draw = ImageDraw.Draw(img) + line_thickness = line_thickness or max(int(min(img.size) / 200), 2) + draw.rectangle(box, width=line_thickness, outline=tuple(color)) # plot + if label: + fontsize = max(round(max(img.size) / 40), 12) + font = ImageFont.truetype("Arial.ttf", fontsize) + txt_width, txt_height = font.getsize(label) + draw.rectangle([box[0], box[1] - txt_height + 4, box[0] + txt_width, box[1]], fill=tuple(color)) + draw.text((box[0], box[1] - txt_height + 1), label, fill=(255, 255, 255), font=font) + return np.asarray(img) + + def plot_wh_methods(): # from utils.plots import *; plot_wh_methods() # Compares the two methods for width-height anchor multiplication # https://github.com/ultralytics/yolov3/issues/168 @@ -223,38 +237,39 @@ def plot_targets_txt(): # from utils.plots import *; plot_targets_txt() plt.savefig('targets.jpg', dpi=200) -def plot_study_txt(path='study/', x=None): # from utils.plots import *; plot_study_txt() +def plot_study_txt(path='', x=None): # from utils.plots import *; plot_study_txt() # Plot study.txt generated by test.py fig, ax = plt.subplots(2, 4, figsize=(10, 6), tight_layout=True) - ax = ax.ravel() + # ax = ax.ravel() fig2, ax2 = plt.subplots(1, 1, figsize=(8, 4), tight_layout=True) - for f in [Path(path) / f'study_coco_{x}.txt' for x in ['yolov5s', 'yolov5m', 'yolov5l', 'yolov5x']]: + # for f in [Path(path) / f'study_coco_{x}.txt' for x in ['yolov3-tiny', 'yolov3', 'yolov3-spp', 'yolov5l']]: + for f in sorted(Path(path).glob('study*.txt')): y = np.loadtxt(f, dtype=np.float32, usecols=[0, 1, 2, 3, 7, 8, 9], ndmin=2).T x = np.arange(y.shape[1]) if x is None else np.array(x) s = ['P', 'R', 'mAP@.5', 'mAP@.5:.95', 't_inference (ms/img)', 't_NMS (ms/img)', 't_total (ms/img)'] - for i in range(7): - ax[i].plot(x, y[i], '.-', linewidth=2, markersize=8) - ax[i].set_title(s[i]) + # for i in range(7): + # ax[i].plot(x, y[i], '.-', linewidth=2, markersize=8) + # ax[i].set_title(s[i]) j = y[3].argmax() + 1 - ax2.plot(y[6, :j], y[3, :j] * 1E2, '.-', linewidth=2, markersize=8, + ax2.plot(y[6, 1:j], y[3, 1:j] * 1E2, '.-', linewidth=2, markersize=8, label=f.stem.replace('study_coco_', '').replace('yolo', 'YOLO')) ax2.plot(1E3 / np.array([209, 140, 97, 58, 35, 18]), [34.6, 40.5, 43.0, 47.5, 49.7, 51.5], 'k.-', linewidth=2, markersize=8, alpha=.25, label='EfficientDet') - ax2.grid() - ax2.set_yticks(np.arange(30, 60, 5)) - ax2.set_xlim(0, 30) - ax2.set_ylim(29, 51) + ax2.grid(alpha=0.2) + ax2.set_yticks(np.arange(20, 60, 5)) + ax2.set_xlim(0, 57) + ax2.set_ylim(15, 55) ax2.set_xlabel('GPU Speed (ms/img)') ax2.set_ylabel('COCO AP val') ax2.legend(loc='lower right') - plt.savefig('test_study.png', dpi=300) + plt.savefig(str(Path(path).name) + '.png', dpi=300) -def plot_labels(labels, save_dir=Path(''), loggers=None): +def plot_labels(labels, names=(), save_dir=Path(''), loggers=None): # plot dataset labels print('Plotting labels... ') c, b = labels[:, 0], labels[:, 1:].transpose() # classes, boxes @@ -271,7 +286,12 @@ def plot_labels(labels, save_dir=Path(''), loggers=None): matplotlib.use('svg') # faster ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True)[1].ravel() ax[0].hist(c, bins=np.linspace(0, nc, nc + 1) - 0.5, rwidth=0.8) - ax[0].set_xlabel('classes') + ax[0].set_ylabel('instances') + if 0 < len(names) < 30: + ax[0].set_xticks(range(len(names))) + ax[0].set_xticklabels(names, rotation=90, fontsize=10) + else: + ax[0].set_xlabel('classes') sns.histplot(x, x='x', y='y', ax=ax[2], bins=50, pmax=0.9) sns.histplot(x, x='width', y='height', ax=ax[3], bins=50, pmax=0.9) @@ -295,13 +315,13 @@ def plot_labels(labels, save_dir=Path(''), loggers=None): # loggers for k, v in loggers.items() or {}: if k == 'wandb' and v: - v.log({"Labels": [v.Image(str(x), caption=x.name) for x in save_dir.glob('*labels*.jpg')]}) + v.log({"Labels": [v.Image(str(x), caption=x.name) for x in save_dir.glob('*labels*.jpg')]}, commit=False) def plot_evolution(yaml_file='data/hyp.finetune.yaml'): # from utils.plots import *; plot_evolution() # Plot hyperparameter evolution results in evolve.txt with open(yaml_file) as f: - hyp = yaml.load(f, Loader=yaml.FullLoader) + hyp = yaml.load(f, Loader=yaml.SafeLoader) x = np.loadtxt('evolve.txt', ndmin=2) f = fitness(x) # weights = (f - f.min()) ** 2 # for weighted results diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 231dcfd7a5..6535b2ab1b 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -1,8 +1,10 @@ -# PyTorch utils +# YOLOv3 PyTorch utils +import datetime import logging import math import os +import platform import subprocess import time from contextlib import contextmanager @@ -43,17 +45,24 @@ def init_torch_seeds(seed=0): cudnn.benchmark, cudnn.deterministic = True, False -def git_describe(): +def date_modified(path=__file__): + # return human-readable file modification date, i.e. '2021-3-26' + t = datetime.datetime.fromtimestamp(Path(path).stat().st_mtime) + return f'{t.year}-{t.month}-{t.day}' + + +def git_describe(path=Path(__file__).parent): # path must be a directory # return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe - if Path('.git').exists(): - return subprocess.check_output('git describe --tags --long --always', shell=True).decode('utf-8')[:-1] - else: - return '' + s = f'git -C {path} describe --tags --long --always' + try: + return subprocess.check_output(s, shell=True, stderr=subprocess.STDOUT).decode()[:-1] + except subprocess.CalledProcessError as e: + return '' # not a git repository def select_device(device='', batch_size=None): # device = 'cpu' or '0' or '0,1,2,3' - s = f'YOLOv3 {git_describe()} torch {torch.__version__} ' # string + s = f'YOLOv3 🚀 {git_describe() or date_modified()} torch {torch.__version__} ' # string cpu = device.lower() == 'cpu' if cpu: os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # force torch.cuda.is_available() = False @@ -73,7 +82,7 @@ def select_device(device='', batch_size=None): else: s += 'CPU\n' - logger.info(s) # skip a line + logger.info(s.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else s) # emoji-safe return torch.device('cuda:0' if cuda else 'cpu') @@ -120,7 +129,7 @@ def profile(x, ops, n=100, device=None): s_in = tuple(x.shape) if isinstance(x, torch.Tensor) else 'list' s_out = tuple(y.shape) if isinstance(y, torch.Tensor) else 'list' p = sum(list(x.numel() for x in m.parameters())) if isinstance(m, nn.Module) else 0 # parameters - print(f'{p:12.4g}{flops:12.4g}{dtf:16.4g}{dtb:16.4g}{str(s_in):>24s}{str(s_out):>24s}') + print(f'{p:12}{flops:12.4g}{dtf:16.4g}{dtb:16.4g}{str(s_in):>24s}{str(s_out):>24s}') def is_parallel(model): @@ -182,7 +191,7 @@ def fuse_conv_and_bn(conv, bn): # prepare filters w_conv = conv.weight.clone().view(conv.out_channels, -1) w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var))) - fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.size())) + fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.shape)) # prepare spatial bias b_conv = torch.zeros(conv.weight.size(0), device=conv.weight.device) if conv.bias is None else conv.bias @@ -205,7 +214,7 @@ def model_info(model, verbose=False, img_size=640): try: # FLOPS from thop import profile - stride = int(model.stride.max()) if hasattr(model, 'stride') else 32 + stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32 img = torch.zeros((1, model.yaml.get('ch', 3), stride, stride), device=next(model.parameters()).device) # input flops = profile(deepcopy(model), inputs=(img,), verbose=False)[0] / 1E9 * 2 # stride GFLOPS img_size = img_size if isinstance(img_size, list) else [img_size, img_size] # expand if int/float diff --git a/utils/wandb_logging/__init__.py b/utils/wandb_logging/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/utils/wandb_logging/log_dataset.py b/utils/wandb_logging/log_dataset.py new file mode 100644 index 0000000000..d7a521f141 --- /dev/null +++ b/utils/wandb_logging/log_dataset.py @@ -0,0 +1,24 @@ +import argparse + +import yaml + +from wandb_utils import WandbLogger + +WANDB_ARTIFACT_PREFIX = 'wandb-artifact://' + + +def create_dataset_artifact(opt): + with open(opt.data) as f: + data = yaml.load(f, Loader=yaml.SafeLoader) # data dict + logger = WandbLogger(opt, '', None, data, job_type='Dataset Creation') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default='data/coco128.yaml', help='data.yaml path') + parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') + parser.add_argument('--project', type=str, default='YOLOv5', help='name of W&B Project') + opt = parser.parse_args() + opt.resume = False # Explicitly disallow resume check for dataset upload job + + create_dataset_artifact(opt) diff --git a/utils/wandb_logging/wandb_utils.py b/utils/wandb_logging/wandb_utils.py new file mode 100644 index 0000000000..d8f50ae8a8 --- /dev/null +++ b/utils/wandb_logging/wandb_utils.py @@ -0,0 +1,306 @@ +import json +import sys +from pathlib import Path + +import torch +import yaml +from tqdm import tqdm + +sys.path.append(str(Path(__file__).parent.parent.parent)) # add utils/ to path +from utils.datasets import LoadImagesAndLabels +from utils.datasets import img2label_paths +from utils.general import colorstr, xywh2xyxy, check_dataset + +try: + import wandb + from wandb import init, finish +except ImportError: + wandb = None + +WANDB_ARTIFACT_PREFIX = 'wandb-artifact://' + + +def remove_prefix(from_string, prefix=WANDB_ARTIFACT_PREFIX): + return from_string[len(prefix):] + + +def check_wandb_config_file(data_config_file): + wandb_config = '_wandb.'.join(data_config_file.rsplit('.', 1)) # updated data.yaml path + if Path(wandb_config).is_file(): + return wandb_config + return data_config_file + + +def get_run_info(run_path): + run_path = Path(remove_prefix(run_path, WANDB_ARTIFACT_PREFIX)) + run_id = run_path.stem + project = run_path.parent.stem + model_artifact_name = 'run_' + run_id + '_model' + return run_id, project, model_artifact_name + + +def check_wandb_resume(opt): + process_wandb_config_ddp_mode(opt) if opt.global_rank not in [-1, 0] else None + if isinstance(opt.resume, str): + if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): + if opt.global_rank not in [-1, 0]: # For resuming DDP runs + run_id, project, model_artifact_name = get_run_info(opt.resume) + api = wandb.Api() + artifact = api.artifact(project + '/' + model_artifact_name + ':latest') + modeldir = artifact.download() + opt.weights = str(Path(modeldir) / "last.pt") + return True + return None + + +def process_wandb_config_ddp_mode(opt): + with open(opt.data) as f: + data_dict = yaml.load(f, Loader=yaml.SafeLoader) # data dict + train_dir, val_dir = None, None + if isinstance(data_dict['train'], str) and data_dict['train'].startswith(WANDB_ARTIFACT_PREFIX): + api = wandb.Api() + train_artifact = api.artifact(remove_prefix(data_dict['train']) + ':' + opt.artifact_alias) + train_dir = train_artifact.download() + train_path = Path(train_dir) / 'data/images/' + data_dict['train'] = str(train_path) + + if isinstance(data_dict['val'], str) and data_dict['val'].startswith(WANDB_ARTIFACT_PREFIX): + api = wandb.Api() + val_artifact = api.artifact(remove_prefix(data_dict['val']) + ':' + opt.artifact_alias) + val_dir = val_artifact.download() + val_path = Path(val_dir) / 'data/images/' + data_dict['val'] = str(val_path) + if train_dir or val_dir: + ddp_data_path = str(Path(val_dir) / 'wandb_local_data.yaml') + with open(ddp_data_path, 'w') as f: + yaml.dump(data_dict, f) + opt.data = ddp_data_path + + +class WandbLogger(): + def __init__(self, opt, name, run_id, data_dict, job_type='Training'): + # Pre-training routine -- + self.job_type = job_type + self.wandb, self.wandb_run, self.data_dict = wandb, None if not wandb else wandb.run, data_dict + # It's more elegant to stick to 1 wandb.init call, but useful config data is overwritten in the WandbLogger's wandb.init call + if isinstance(opt.resume, str): # checks resume from artifact + if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): + run_id, project, model_artifact_name = get_run_info(opt.resume) + model_artifact_name = WANDB_ARTIFACT_PREFIX + model_artifact_name + assert wandb, 'install wandb to resume wandb runs' + # Resume wandb-artifact:// runs here| workaround for not overwriting wandb.config + self.wandb_run = wandb.init(id=run_id, project=project, resume='allow') + opt.resume = model_artifact_name + elif self.wandb: + self.wandb_run = wandb.init(config=opt, + resume="allow", + project='YOLOv5' if opt.project == 'runs/train' else Path(opt.project).stem, + name=name, + job_type=job_type, + id=run_id) if not wandb.run else wandb.run + if self.wandb_run: + if self.job_type == 'Training': + if not opt.resume: + wandb_data_dict = self.check_and_upload_dataset(opt) if opt.upload_dataset else data_dict + # Info useful for resuming from artifacts + self.wandb_run.config.opt = vars(opt) + self.wandb_run.config.data_dict = wandb_data_dict + self.data_dict = self.setup_training(opt, data_dict) + if self.job_type == 'Dataset Creation': + self.data_dict = self.check_and_upload_dataset(opt) + else: + prefix = colorstr('wandb: ') + print(f"{prefix}Install Weights & Biases for YOLOv5 logging with 'pip install wandb' (recommended)") + + def check_and_upload_dataset(self, opt): + assert wandb, 'Install wandb to upload dataset' + check_dataset(self.data_dict) + config_path = self.log_dataset_artifact(opt.data, + opt.single_cls, + 'YOLOv5' if opt.project == 'runs/train' else Path(opt.project).stem) + print("Created dataset config file ", config_path) + with open(config_path) as f: + wandb_data_dict = yaml.load(f, Loader=yaml.SafeLoader) + return wandb_data_dict + + def setup_training(self, opt, data_dict): + self.log_dict, self.current_epoch, self.log_imgs = {}, 0, 16 # Logging Constants + self.bbox_interval = opt.bbox_interval + if isinstance(opt.resume, str): + modeldir, _ = self.download_model_artifact(opt) + if modeldir: + self.weights = Path(modeldir) / "last.pt" + config = self.wandb_run.config + opt.weights, opt.save_period, opt.batch_size, opt.bbox_interval, opt.epochs, opt.hyp = str( + self.weights), config.save_period, config.total_batch_size, config.bbox_interval, config.epochs, \ + config.opt['hyp'] + data_dict = dict(self.wandb_run.config.data_dict) # eliminates the need for config file to resume + if 'val_artifact' not in self.__dict__: # If --upload_dataset is set, use the existing artifact, don't download + self.train_artifact_path, self.train_artifact = self.download_dataset_artifact(data_dict.get('train'), + opt.artifact_alias) + self.val_artifact_path, self.val_artifact = self.download_dataset_artifact(data_dict.get('val'), + opt.artifact_alias) + self.result_artifact, self.result_table, self.val_table, self.weights = None, None, None, None + if self.train_artifact_path is not None: + train_path = Path(self.train_artifact_path) / 'data/images/' + data_dict['train'] = str(train_path) + if self.val_artifact_path is not None: + val_path = Path(self.val_artifact_path) / 'data/images/' + data_dict['val'] = str(val_path) + self.val_table = self.val_artifact.get("val") + self.map_val_table_path() + if self.val_artifact is not None: + self.result_artifact = wandb.Artifact("run_" + wandb.run.id + "_progress", "evaluation") + self.result_table = wandb.Table(["epoch", "id", "prediction", "avg_confidence"]) + if opt.bbox_interval == -1: + self.bbox_interval = opt.bbox_interval = (opt.epochs // 10) if opt.epochs > 10 else 1 + return data_dict + + def download_dataset_artifact(self, path, alias): + if isinstance(path, str) and path.startswith(WANDB_ARTIFACT_PREFIX): + dataset_artifact = wandb.use_artifact(remove_prefix(path, WANDB_ARTIFACT_PREFIX) + ":" + alias) + assert dataset_artifact is not None, "'Error: W&B dataset artifact doesn\'t exist'" + datadir = dataset_artifact.download() + return datadir, dataset_artifact + return None, None + + def download_model_artifact(self, opt): + if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): + model_artifact = wandb.use_artifact(remove_prefix(opt.resume, WANDB_ARTIFACT_PREFIX) + ":latest") + assert model_artifact is not None, 'Error: W&B model artifact doesn\'t exist' + modeldir = model_artifact.download() + epochs_trained = model_artifact.metadata.get('epochs_trained') + total_epochs = model_artifact.metadata.get('total_epochs') + assert epochs_trained < total_epochs, 'training to %g epochs is finished, nothing to resume.' % ( + total_epochs) + return modeldir, model_artifact + return None, None + + def log_model(self, path, opt, epoch, fitness_score, best_model=False): + model_artifact = wandb.Artifact('run_' + wandb.run.id + '_model', type='model', metadata={ + 'original_url': str(path), + 'epochs_trained': epoch + 1, + 'save period': opt.save_period, + 'project': opt.project, + 'total_epochs': opt.epochs, + 'fitness_score': fitness_score + }) + model_artifact.add_file(str(path / 'last.pt'), name='last.pt') + wandb.log_artifact(model_artifact, + aliases=['latest', 'epoch ' + str(self.current_epoch), 'best' if best_model else '']) + print("Saving model artifact on epoch ", epoch + 1) + + def log_dataset_artifact(self, data_file, single_cls, project, overwrite_config=False): + with open(data_file) as f: + data = yaml.load(f, Loader=yaml.SafeLoader) # data dict + nc, names = (1, ['item']) if single_cls else (int(data['nc']), data['names']) + names = {k: v for k, v in enumerate(names)} # to index dictionary + self.train_artifact = self.create_dataset_table(LoadImagesAndLabels( + data['train']), names, name='train') if data.get('train') else None + self.val_artifact = self.create_dataset_table(LoadImagesAndLabels( + data['val']), names, name='val') if data.get('val') else None + if data.get('train'): + data['train'] = WANDB_ARTIFACT_PREFIX + str(Path(project) / 'train') + if data.get('val'): + data['val'] = WANDB_ARTIFACT_PREFIX + str(Path(project) / 'val') + path = data_file if overwrite_config else '_wandb.'.join(data_file.rsplit('.', 1)) # updated data.yaml path + data.pop('download', None) + with open(path, 'w') as f: + yaml.dump(data, f) + + if self.job_type == 'Training': # builds correct artifact pipeline graph + self.wandb_run.use_artifact(self.val_artifact) + self.wandb_run.use_artifact(self.train_artifact) + self.val_artifact.wait() + self.val_table = self.val_artifact.get('val') + self.map_val_table_path() + else: + self.wandb_run.log_artifact(self.train_artifact) + self.wandb_run.log_artifact(self.val_artifact) + return path + + def map_val_table_path(self): + self.val_table_map = {} + print("Mapping dataset") + for i, data in enumerate(tqdm(self.val_table.data)): + self.val_table_map[data[3]] = data[0] + + def create_dataset_table(self, dataset, class_to_id, name='dataset'): + # TODO: Explore multiprocessing to slpit this loop parallely| This is essential for speeding up the the logging + artifact = wandb.Artifact(name=name, type="dataset") + img_files = tqdm([dataset.path]) if isinstance(dataset.path, str) and Path(dataset.path).is_dir() else None + img_files = tqdm(dataset.img_files) if not img_files else img_files + for img_file in img_files: + if Path(img_file).is_dir(): + artifact.add_dir(img_file, name='data/images') + labels_path = 'labels'.join(dataset.path.rsplit('images', 1)) + artifact.add_dir(labels_path, name='data/labels') + else: + artifact.add_file(img_file, name='data/images/' + Path(img_file).name) + label_file = Path(img2label_paths([img_file])[0]) + artifact.add_file(str(label_file), + name='data/labels/' + label_file.name) if label_file.exists() else None + table = wandb.Table(columns=["id", "train_image", "Classes", "name"]) + class_set = wandb.Classes([{'id': id, 'name': name} for id, name in class_to_id.items()]) + for si, (img, labels, paths, shapes) in enumerate(tqdm(dataset)): + height, width = shapes[0] + labels[:, 2:] = (xywh2xyxy(labels[:, 2:].view(-1, 4))) * torch.Tensor([width, height, width, height]) + box_data, img_classes = [], {} + for cls, *xyxy in labels[:, 1:].tolist(): + cls = int(cls) + box_data.append({"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, + "class_id": cls, + "box_caption": "%s" % (class_to_id[cls]), + "scores": {"acc": 1}, + "domain": "pixel"}) + img_classes[cls] = class_to_id[cls] + boxes = {"ground_truth": {"box_data": box_data, "class_labels": class_to_id}} # inference-space + table.add_data(si, wandb.Image(paths, classes=class_set, boxes=boxes), json.dumps(img_classes), + Path(paths).name) + artifact.add(table, name) + return artifact + + def log_training_progress(self, predn, path, names): + if self.val_table and self.result_table: + class_set = wandb.Classes([{'id': id, 'name': name} for id, name in names.items()]) + box_data = [] + total_conf = 0 + for *xyxy, conf, cls in predn.tolist(): + if conf >= 0.25: + box_data.append( + {"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, + "class_id": int(cls), + "box_caption": "%s %.3f" % (names[cls], conf), + "scores": {"class_score": conf}, + "domain": "pixel"}) + total_conf = total_conf + conf + boxes = {"predictions": {"box_data": box_data, "class_labels": names}} # inference-space + id = self.val_table_map[Path(path).name] + self.result_table.add_data(self.current_epoch, + id, + wandb.Image(self.val_table.data[id][1], boxes=boxes, classes=class_set), + total_conf / max(1, len(box_data)) + ) + + def log(self, log_dict): + if self.wandb_run: + for key, value in log_dict.items(): + self.log_dict[key] = value + + def end_epoch(self, best_result=False): + if self.wandb_run: + wandb.log(self.log_dict) + self.log_dict = {} + if self.result_artifact: + train_results = wandb.JoinedTable(self.val_table, self.result_table, "id") + self.result_artifact.add(train_results, 'result') + wandb.log_artifact(self.result_artifact, aliases=['latest', 'epoch ' + str(self.current_epoch), + ('best' if best_result else '')]) + self.result_table = wandb.Table(["epoch", "id", "prediction", "avg_confidence"]) + self.result_artifact = wandb.Artifact("run_" + wandb.run.id + "_progress", "evaluation") + + def finish_run(self): + if self.wandb_run: + if self.log_dict: + wandb.log(self.log_dict) + wandb.run.finish() From be29298b5c752d4db0098ed50fb48228c145cb8c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 12 Apr 2021 18:18:05 +0200 Subject: [PATCH 0881/1185] Created using Colaboratory --- tutorial.ipynb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tutorial.ipynb b/tutorial.ipynb index b8969bc45f..ca2d391dee 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -517,7 +517,7 @@ "colab_type": "text" }, "source": [ - "\"Open" + "\"Open" ] }, { @@ -529,7 +529,7 @@ "\n", "\n", "This is the **official YOLOv3 🚀 notebook** authored by **Ultralytics**, and is freely available for redistribution under the [GPL-3.0 license](https://choosealicense.com/licenses/gpl-3.0/). \n", - "For more information please visit https://github.com/ultralytics/yolov5 and https://www.ultralytics.com. Thank you!" + "For more information please visit https://github.com/ultralytics/yolov3 and https://www.ultralytics.com. Thank you!" ] }, { @@ -553,8 +553,8 @@ "outputId": "9b022435-4197-41fc-abea-81f86ce857d0" }, "source": [ - "!git clone https://github.com/ultralytics/yolov5 # clone repo\n", - "%cd yolov5\n", + "!git clone https://github.com/ultralytics/yolov3 # clone repo\n", + "%cd yolov3\n", "%pip install -qr requirements.txt # install dependencies\n", "\n", "import torch\n", @@ -563,7 +563,7 @@ "clear_output()\n", "print(f\"Setup complete. Using torch {torch.__version__} ({torch.cuda.get_device_properties(0).name if torch.cuda.is_available() else 'CPU'})\")" ], - "execution_count": 31, + "execution_count": null, "outputs": [ { "output_type": "stream", @@ -719,7 +719,7 @@ }, "source": [ "# Run YOLOv3 on COCO val2017\n", - "!python test.py --weights yolov5x.pt --data coco.yaml --img 640 --iou 0.65" + "!python test.py --weights yolov3.pt --data coco.yaml --img 640 --iou 0.65" ], "execution_count": null, "outputs": [ @@ -1145,8 +1145,8 @@ "source": [ "# Re-clone repo\n", "%cd ..\n", - "%rm -rf yolov5 && git clone https://github.com/ultralytics/yolov5\n", - "%cd yolov5" + "%rm -rf yolov3 && git clone https://github.com/ultralytics/yolov3\n", + "%cd yolov3" ], "execution_count": null, "outputs": [] @@ -1175,10 +1175,10 @@ "import torch\n", "\n", "# Model\n", - "model = torch.hub.load('ultralytics/yolov5', 'yolov3')\n", + "model = torch.hub.load('ultralytics/yolov3', 'yolov3') # or 'yolov3_spp', 'yolov3_tiny'\n", "\n", "# Images\n", - "dir = 'https://github.com/ultralytics/yolov5/raw/master/data/images/'\n", + "dir = 'https://github.com/ultralytics/yolov3/raw/master/data/images/'\n", "imgs = [dir + f for f in ('zidane.jpg', 'bus.jpg')] # batch of images\n", "\n", "# Inference\n", From b9849003c8579694c18be1f1e414afa52c9dfc80 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 12 Apr 2021 23:38:05 +0200 Subject: [PATCH 0882/1185] Created using Colaboratory --- tutorial.ipynb | 241 +++++++++++++++++++++++++------------------------ 1 file changed, 124 insertions(+), 117 deletions(-) diff --git a/tutorial.ipynb b/tutorial.ipynb index ca2d391dee..7f58e734ee 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -16,7 +16,7 @@ "accelerator": "GPU", "widgets": { "application/vnd.jupyter.widget-state+json": { - "8815626359d84416a2f44a95500580a4": { + "355d9ee3dfc4487ebcae3b66ddbedce1": { "model_module": "@jupyter-widgets/controls", "model_name": "HBoxModel", "state": { @@ -28,15 +28,15 @@ "_view_count": null, "_view_module_version": "1.5.0", "box_style": "", - "layout": "IPY_MODEL_3b85609c4ce94a74823f2cfe141ce68e", + "layout": "IPY_MODEL_8209acd3185441e7b263eead5e8babdf", "_model_module": "@jupyter-widgets/controls", "children": [ - "IPY_MODEL_876609753c2946248890344722963d44", - "IPY_MODEL_8abfdd8778e44b7ca0d29881cb1ada05" + "IPY_MODEL_b81d30356f7048b0abcba35bde811526", + "IPY_MODEL_7fcbf6b56f2e4b6dbf84e48465c96633" ] } }, - "3b85609c4ce94a74823f2cfe141ce68e": { + "8209acd3185441e7b263eead5e8babdf": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "state": { @@ -87,12 +87,12 @@ "left": null } }, - "876609753c2946248890344722963d44": { + "b81d30356f7048b0abcba35bde811526": { "model_module": "@jupyter-widgets/controls", "model_name": "FloatProgressModel", "state": { "_view_name": "ProgressView", - "style": "IPY_MODEL_78c6c3d97c484916b8ee167c63556800", + "style": "IPY_MODEL_6ee48f9f3af444a7b02ec2f074dec1f8", "_dom_classes": [], "description": "100%", "_model_name": "FloatProgressModel", @@ -107,30 +107,30 @@ "min": 0, "description_tooltip": null, "_model_module": "@jupyter-widgets/controls", - "layout": "IPY_MODEL_9dd0f182db5d45378ceafb855e486eb8" + "layout": "IPY_MODEL_b7d819ed5f2f4e39a75a823792ab7249" } }, - "8abfdd8778e44b7ca0d29881cb1ada05": { + "7fcbf6b56f2e4b6dbf84e48465c96633": { "model_module": "@jupyter-widgets/controls", "model_name": "HTMLModel", "state": { "_view_name": "HTMLView", - "style": "IPY_MODEL_a3dab28b45c247089a3d1b8b09f327de", + "style": "IPY_MODEL_3af216dd7d024739b8168995800ed8be", "_dom_classes": [], "description": "", "_model_name": "HTMLModel", "placeholder": "​", "_view_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", - "value": " 781M/781M [08:43<00:00, 1.56MB/s]", + "value": " 781M/781M [00:11<00:00, 71.1MB/s]", "_view_count": null, "_view_module_version": "1.5.0", "description_tooltip": null, "_model_module": "@jupyter-widgets/controls", - "layout": "IPY_MODEL_32451332b7a94ba9aacddeaa6ac94d50" + "layout": "IPY_MODEL_763141d8de8a498a92ffa66aafed0c5a" } }, - "78c6c3d97c484916b8ee167c63556800": { + "6ee48f9f3af444a7b02ec2f074dec1f8": { "model_module": "@jupyter-widgets/controls", "model_name": "ProgressStyleModel", "state": { @@ -145,7 +145,7 @@ "_model_module": "@jupyter-widgets/controls" } }, - "9dd0f182db5d45378ceafb855e486eb8": { + "b7d819ed5f2f4e39a75a823792ab7249": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "state": { @@ -196,7 +196,7 @@ "left": null } }, - "a3dab28b45c247089a3d1b8b09f327de": { + "3af216dd7d024739b8168995800ed8be": { "model_module": "@jupyter-widgets/controls", "model_name": "DescriptionStyleModel", "state": { @@ -210,7 +210,7 @@ "_model_module": "@jupyter-widgets/controls" } }, - "32451332b7a94ba9aacddeaa6ac94d50": { + "763141d8de8a498a92ffa66aafed0c5a": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "state": { @@ -550,7 +550,7 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "9b022435-4197-41fc-abea-81f86ce857d0" + "outputId": "56f7b795-7a7b-46a1-8c5e-d06040187a85" }, "source": [ "!git clone https://github.com/ultralytics/yolov3 # clone repo\n", @@ -563,12 +563,12 @@ "clear_output()\n", "print(f\"Setup complete. Using torch {torch.__version__} ({torch.cuda.get_device_properties(0).name if torch.cuda.is_available() else 'CPU'})\")" ], - "execution_count": null, + "execution_count": 1, "outputs": [ { "output_type": "stream", "text": [ - "Setup complete. Using torch 1.8.1+cu101 (Tesla V100-SXM2-16GB)\n" + "Setup complete. Using torch 1.8.1+cu101 (Tesla P100-PCIE-16GB)\n" ], "name": "stdout" } @@ -593,35 +593,35 @@ "id": "zR9ZbuQCH7FX", "colab": { "base_uri": "https://localhost:8080/", - "height": 534 + "height": 521 }, - "outputId": "c9a308f7-2216-4805-8003-eca8dd0dc30d" + "outputId": "bd41a070-3498-42e1-ac1b-3900ac0c2ec2" }, "source": [ "!python detect.py --weights yolov3.pt --img 640 --conf 0.25 --source data/images/\n", "Image(filename='runs/detect/exp/zidane.jpg', width=600)" ], - "execution_count": null, + "execution_count": 5, "outputs": [ { "output_type": "stream", "text": [ - "Namespace(agnostic_nms=False, augment=False, classes=None, conf_thres=0.25, device='', exist_ok=False, img_size=640, iou_thres=0.45, name='exp', project='runs/detect', save_conf=False, save_txt=False, source='data/images/', update=False, view_img=False, weights=['yolov3.pt'])\n", - "YOLOv3 🚀 v5.0-1-g0f395b3 torch 1.8.1+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16160.5MB)\n", + "Namespace(agnostic_nms=False, augment=False, classes=None, conf_thres=0.25, device='', exist_ok=False, img_size=640, iou_thres=0.45, name='exp', nosave=False, project='runs/detect', save_conf=False, save_txt=False, source='data/images/', update=False, view_img=False, weights=['yolov3.pt'])\n", + "YOLOv3 🚀 v9.5.0-1-gbe29298 torch 1.8.1+cu101 CUDA:0 (Tesla P100-PCIE-16GB, 16280.875MB)\n", "\n", "Fusing layers... \n", - "Model Summary: 224 layers, 7266973 parameters, 0 gradients, 17.0 GFLOPS\n", - "image 1/2 /content/yolov5/data/images/bus.jpg: 640x480 4 persons, 1 bus, Done. (0.008s)\n", - "image 2/2 /content/yolov5/data/images/zidane.jpg: 384x640 2 persons, 2 ties, Done. (0.008s)\n", - "Results saved to runs/detect/exp\n", - "Done. (0.087)\n" + "Model Summary: 261 layers, 61922845 parameters, 0 gradients, 156.3 GFLOPS\n", + "image 1/2 /content/yolov3/data/images/bus.jpg: 640x480 4 persons, 1 bus, Done. (0.026s)\n", + "image 2/2 /content/yolov3/data/images/zidane.jpg: 384x640 2 persons, 3 ties, Done. (0.025s)\n", + "Results saved to runs/detect/exp2\n", + "Done. (0.119s)\n" ], "name": "stdout" }, { "output_type": "execute_result", "data": { - "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAMEBgUGBgYFBgYGBwkIBgcJBwYGCAsICQoKCgoKBggLDAsKDAkKCgr/2wBDAQICAgICAgUDAwUKBwYHCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgr/wAARCALQBQADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8347F5pkSP5t38P3ttaFjZzR2rzOMjfs+/wDNVi10+5kh877Gqv8AwfP96tOz0+2b99sw0e1drfxV87HY+wjHm94z4bOZ2WZ4dgV9vzN81Tx6a8jHvu+bd/DV+HT51uHd0Up95Pl21bhtfIkH2ncqfN8q/e21NS0dUbU4/ZMf7Oi52OzMu1UVU+an/wBjlW3w7l2t8y/3q3pNPRl2I+1tn/AqZZ280cXk3Nrub+7v+6tefKtLl5onZGm48qMqbQ3k/wBJeb5lb5PMf5l/2aZcaW6tshhyzffZn3ba3biHzI5USFfmX7tQyWc3zTXltuWPb+8jT+LbXJWxVWO534XDxkchrmm/KZt+d3yvurBm0maHLvu2su1G/vV3OsWsMe5xyWTd5bVh3VikkLJ5Pyqu7b/easaNacX7x6nsYyicrJYws3nom1m/vf3qWC3uYW32zr8v95v/AEGtK6s5I9iJuDMu51aq62827502Nt3Jur6zAylKUTlqREj+0wsiI7OzNuRW/wBr+7ViSPy4/wBzud9+1vm+Wq0aurIJtxdf4qtLayeX8nyusu5mb+KvqMPSlKJ58qnvco65uHaNpvlTdt2fJ8y0kjSbER3Vtq7tzJtqbyPtDLDNtx96nTKjR/Ii7t38X3a9D2fKebUkoy5SHyXjnP75l/i/3amSSVm+0v5joqbfv/Ky/wB6i3/fRrv+9911j+6rUsMMuxvJufu/fXZXPKXLE4OaUuaxPBv3b9n+r/hjl3LVqH9zJ/qV2t823/eqtbwpHGkP+qVn+dY/l/4FVuzZLqRI5plV13b12fdX+GvLxHvF04825p2cm1Ucopdvl+V9taVvDcSSK6fd+ZXrN0+GGS637F+V1aXd/d/hq7b75mX51Db9zMr/AC/7Py14WIqSNadHuaVjNLJCsP2pmTfuddvzNU8jO3yQ7X2/e/iaq8IeGNPLRW+bbu2fdq95n2OZXhhV2b5V3V4dap7+h6VOnHqWob792yI6o6orfLVCZJpPnudrBf4v97+KpmuIWmDzTKsrfdXft+7VCS5dpmR5o3/vq392uJSjztQOlx928hzbIZXSFFLs7fMqf6yopmubzY63jIVb7qrU32OGSP8AhRPveXHSyKluy/J975VXf/FWkqnNqLk5fdEntdy/3vl2eZs/76pU3yQyJsYeX8if3lqwsE0iy2zzfuvl/d/7VVr6O6WTf8yfe/d7/u1n71TRSMK0R8d1cxwrvRQv3dzfdWoprp75hNc3cjtHtSLzG+61OaGaS3RJnV1+88bVVkkRlKWtthlf+GspRhKRjH3Y8rKuoXtvHteN8qy7X/vVga9cXisrpcthkVfm/u1pXk00zAu+R/d/utWDq14+5n342/6rav3a78PFRj8JyVqhj6lM/wC8+8f/AB3dXManN82/fjd/CtdBqW+4bM0/Gzc1Yd48Pls/Vm+Xb/FXsUYy5NDxsVLmiYF9avt+07F21QVXmuNmzb/utW9cWbyR56hVqnHp7rMJvJ8xK9CnKMeU82T5hljlWZE3fN9//ZrodI3x7ntn+Rk2srfM1V9N03bGOdu7/wAdrVhs4I5BGiMk0f8ADJ8tEqhrToz+I1NLtUinR9+fLf5F/wDsa7bQZnjwibU2/N+7X5VrjdH/AHKxBE3f367TRZE+x7E2/wB1dv3mqo1PfOj2fuWOu0W4k+ziF5sOzfxfw11ui6uNyu6Mrqu1/Mfb8v8As1wWk3KOuy28xVVvnb+7W/puqQxsU3/eiVmj+9XZGpzmMoyj8R3Wn6kQN8Myh1f/AEfb93/eatXT9am8ve+1vvbmrgrHWd0iXOcFfl3L/F/wGtCHxB5K+d8wSR9qKq/M3/Aa6OYw9+J2q69C3zpZttX5Ub+9/vUybV4IYd+//WbtzL/CtcqutbYf3fmHc+1/mqvcawk3ybJCu/b9/wC9U/DAfunT/wBtusCv0/2d/wDDWbqGuosbO8jEt91tvystYN9q226ldH2xtt8qNX3f8B3VVvtUm2l3TLsnzLu/i/hqJRjI25vslPxRNDdZm85iv3fLb+GuMvJ3dXR/uK23/erW1PVHuomQXLFpJfkZvur/ALNZGqQ/aFb5G+V/3sa1x1I8x0UeaOjOa1SG2ml85Pv/AMO5vlWqtvbupYOmPLf5d3yturcbTkjdt6Mxb/lm38NQXWnpJcM8iSO38Un8K1nKn7p2RqQ5tTPWFJpD5czIn97726mTWVzIHfez+Z/yz/vVZa1eSTZDCqqqNu+fbSLYwzRuXhxufd9/71cNSnI0lUM2SN1CwpMuyT5tv/stJbxurI/nL+8ba0cn92tXybaOSHyYfuxbtrN8v3qq3Eltu+0+T86tt+VK5q1P3tCoVOXWRbtWdcoltv2tu2t8u6uj01na3TZuAVt27+61YNu7s0jzbWlb5U/hrQ0+aGObzo3bzl+X7/y7q+Ox1GXNKTPewtT4ZI7LT2T/AFM03mt8q7v4a0WuvLUI+6H5v9Wvzbv+BVzVnfTeSH/55q25d/3m/wBmp/7UdpI+Nqt8rbWr5DEYeUqp9DRrfDzG5cXySsN9zuVot6qybvu1m3mpRrD5iO0KSRbvlf5aqSal8zbNuPm2/J8q1Uk1QSM73KKrrF8nlr8u6tKOHUZe8dvtOhPeahD5yc7v3X975t1Zs0zrsfo2/wCZW/h/4FS3F4jKkEyMXX5X3fdaqzLBNJscrsZNqqv8NexhcPGPuozqVOWHKJe+c0hf7Tv3fL8tVri3DSPD9pUyr/F91d1aEljH/wAvMylG+4yp91aktdPeRc+Tv+f5fk3V9XluH5dTwcdiIx+0YLK6tvfcKry6bN5ezZ+7b/lpG+35q7BfDiNa+XNC37xtq7m27qdY+DXuN0m/hX/1f8NfY4ej7lz5XGYjm+E5C10e/Ece+2+fdtXb81XF8P7bqPztwkVGV9vyrt/2a7ux8KzRyJCkLM6/Nt3/ACtU7eDXkmj811Ty2+f91ub5q1lTjGZwRrcp5wuihpJIPmZGf/v2tQDwrMzHyXbZ93aqV6ovg/y5FT7zL99VT7y0kngvM3nfZmQbWZFWuKpR5vdN6dbl+0eUyeG7mO4Dp0Zf/Hqfp+jzQtLNczZK/wAP92vS28HmaOL/AEXa21n/AOA1m3HhWaxmm32fySIv+1uX/drxsVR+yejh63N7xysmnwxqrwp5rtztV/4f/iqJLRLVVT7HIo2bd27+Kuqj8Nos29BiKRdySN/d/u1UvrN/MhhmtmH/AE0rzJRl9hnbGpLm1Obmt5LfPkoxdvmdqpGzTzks33MrRbvL37WrevtPmkuNk3zLI27958tZd1bJZ3mz94Xk/vN8taxl9kr4vhM9YUt2SFJtq/8AXX5vlqb7PNdTPNM6r5iLsVf4f9qnzW8KM72yKpX+KrDWf7vYJtoXb95vmrS8fi5iPe5iCGSZrdYfObYvy7v7zLUNxcFVaNHaM/Mu3/ZqzInkxhGm+79xf7tZN1I7L9/HzfPu/irejTlUkYyqcseWRDM0Plu8kzfc+6v8VZ0cszN87qPm+fy/m2rVm6Z7iTyfl2xpt8yNdu6qk0nlqXh2hG+4y161GmeZWqSjL3SNpEZfJjhXb/D/ALVIq/ut83zf3fmpkbIrDftC7P4fvbqVVTCPHBtH8MbN/FXV7P7RjGt7xGq3O48Z2/N8vy7qfIszRq6Pj+9u+9VhbXbJs3/MqfP8u75qVbVMt5j/ADfe2rTfvfEbxqe5ykSXj/Y3DzSBv4Kt2zIsa70y+/dtb/0KmW8aW6tcvM21fl3bPutWlHYO1vvmhYf3JF/irel8ISrT5CssYM/7l2Rm/vfLUNxpsysNm4fLtfd92tVdI+UvezbXZP71X9I8Ga14hMh0DQri+EWzzRFEWC5zjOOnQ/lXrYalXxNRU6MXKT2STbfyWpxuTnLlgm32RyMmkvtY72Z93y/N92si+sXkupk2MNvy7a9Pl+E3jiRk2+BtTz3JtWx/Ks7Ufg98Q1K/ZvBGqvlfmxYt/hXrxyPOv+gap/4BL/I5qmDxcv8Al1L/AMBf+R5Lqmkutrvdm3r8yMtc1qmmlv8Ab+8te0X3wT+JchMa/D/WCGXLEWLnn8qwr74BfFhi0dv8NNZ2Hp/oD/4U45HnX2sNU/8AAJf5HDUy/Hy/5dS/8Bf+R4Vqlrc28jI6fKv8VUvJmkH8TbvmdVr2DV/2cPjTJBttvhTrROMcabIf6Vz837Mvx5H7v/hUXiHH95NKl/wq5ZJnXLf6tU/8Al/kY/2fj/h9lL/wF/5HARw+Wd+9v92rlrbTSXGx5mZW/vV2sP7NXx13Av8ACDxGfc6VL/hWlZ/s7fG5U82X4P66GxjH9kyf4Vw1clzxx/3Wp/4BL/I6Y5djv+fUv/AX/kcfb2fksr/+Oq1adrbvMqo/ys33Pm212Np+z38ZwUf/AIVbrqKFyR/ZsgOfyrRh+AXxcjRm/wCFZa3uP3f+JZJ/hXHLJM7/AOgSr/4Ll/kdtPLsY96cvuf+Rx0cMkbbEfdWhaxO3753Zd38O77tdVbfAr4tyuwufhrrgCr8pOnyfN+lWbX4G/FpVDn4b6wGAYLmwfgflXPLI8++zhKv/guf+R108uxcf+XcvuZy6wvtabDf7W6jzN0iPvZR8uzzK7OP4KfFRkIj+HWsq+xuXsXxu/KlPwQ+KrBVk+H2rnav/QPf/CsP7Cz3m1wtX/wXP/I744HFdIP7mcpCtzNIRDtbb/DJUMizKuwQ7dqfe/iVq69vgt8Vf4PhtrQ29D9jf/CiL4HfGK/lW1sfhVr8zf8APOLTJGZvwAzWryXPErvCVf8AwXL/ACNYYLEOWsH9zOJmjhb5PmLL8yM33t396mzSTRsr7Fd1Tb9+utv/AIEfF21Lx/8ACsfECSl8SRPpsgKH6EVUk+CfxeWUlPhfr2W6gabJgfpTjkmfSj/ulX/wXL/Ip4LF/wAj+5nNtM7EI0+xV/hWp7eZGwn3X/i+atmT4J/GHIZPhdrudvP/ABKpOP0q5pv7Pnx9vibuy+C/iaZVfaJY9GmcH8Qtb/2FnahzSwtRf9uS/wAh+wxKlrB/czJh1CazmKO6uzJj+98taVvqD+WHd2LfeWnx/Bf4zwztK/w21zcG2lTpsn+FaWn/AAC+Pl7CZbL4O+Jp4ifkeHSJmVT6ZC1vHJc6pLmlhqi/7cl/kc88PjFK/I/uZlyakkP+pdVZm3M1QNqzzK3nPk7/AJljeuhP7Pn7RbhQ3wT8VAAYLDQJ92P7v3awPEnw1+JnhWyl1rxB4F1a0toCBPNdafIiQ5O0biRgckDnuacsmzOMHUlh5pLVvklZLu9NDlqU8Sot8jsvJmbqGoJMrbPlXb/E9ULjWCtsE6j+9WfNep5g42/8DqrdaomXTf8ALs+balcUY8u55NbFS6FqTUHaNXCMwas261J2kOeBs3Lu/iaq8l58pmhfb8vytWXdawFjb58t/dpyOeNbl0Ld1fTbt4mVFZfn2vWfNdJI3zuwH8DVTuNSuJOqLt/u1Va82/Oh/wC+a56nNE9CjiveNCS+eF98aMwX+Kh77cyzvN96s0zP5nzzcf3aljuEab9z/DXFWifS4XEc3KlI0HuPNGxH+ZvvbqktZ3jbY75C/das/wA5JJGdPvMnyK1WrW3uZJkT+7/FXHUjyxPfw+I5S/G7yHZM2/8A3v4ateSjR/I+NtUoflben975quRqixsyOzM38P8AdrllHlPeo4jmHqvk7dif7+7+KpJJJvOTf/wHdUTRuI9kz7t33amVXjiCTP8Adb5t1YSid8a0dgX5meB+iv8A+PVK8z+SJnfLt/d/hqDa8fKHhmoZtqt3bdtSlLmNvrRbVtuAk3y/+zVGJk/jT5o3qFpJ2jZPOyy/NtX71NaRFz8ir/Czf3qcaPMH1rm0JJ7h1Vnd1dW/8dqDzHkHmK/8X3aTa7s0Py//ABVV2byZN6JtK/K3z1v7PliclXGcurLM0yLh0h3fwtTFk2q2x2D/AN3fVJrpFY+Vu/21qP7chXncm7+Jq3jGR52IxkbFybUJvlfyVVm+Zqq3E3mKd83FRtMm5tnzL/BVRr5/M2bFUN99a6qcZHz+KxXNAtrP50bIHYK38NNjkDN5EzqrfNVKOYwJvR12K1SrdPcNvR/mX/x6uuMT5vFVoyNG3kdWV3mxWhbuiqr+d8v8f+1WPp58xnR/7+379atlHDIuNmVX+Grj73xHkyrGnZyO395Vbb8y1raer3Ejb33fwvub7y1nabDH5m+GHhtvzSVtaXZ/xzRrhfu7aInmyqcxr2VnNJE3zqEk/hX71dPpdrtjjf8AeSstZeh2L/I6Ip2rt+b+Guk8O2aW67LmFdsa/N8/3aoxlI39Ls0VU3pjcm5F/u1r2Vo8i7HhyzNu3R0zQ7OTy40httu5Ny/7VdJY2KMuyHdvVW37kro+I5/aGJNYpNC28tjavy/3WqZ7GFo1h37fl3OrfwtWtHo8022GaHbu/i/hqKbT3WRnfcn8Hyv822ly/aOmjL3zFis5mkFz8zlvl3b/ALu2npY/6QZpptgk27/722r62aQt5Nt5n7z+GT7y1FdWO2FfLfJVPustTKMeXmPewsvdM/ULO2kZZkRnX7RtRm/h/wBqub1rT5lkbZN/F95WrsLiOH+NJNv8DL/ermNUi+y5fYvzM3yq275qcYwl7x72Gj8Kkee69YvNC80L+cjN8jN/6DXE+JNPfcyb2O75fl+9XqHiCHcrfIy/P+6b+7XGa5Z+dG6JG3y/MjVyVpfzHqxwvN7x7Vp8NtCrvMm8eb95fvK1S28T3DOnkx+Urs0TL8rK1VoLiBWY2bqUjb7zL95v/iant77/AEjyfszPtVd1eNGPLA+e9pyl+xtXjb/SUV/l3J/FWjC0MinyX/g2orL8y/8AAqz47jyW2PJ+6Z9yxqn3f+BVehbtcvhFXcjf7VefXk/5TupVOaVxLqOFZCj7WPlKrrG3zfN/FUUdq8ciu7sGWp7iRPtDpIil9m/5U+WRqY1siq58lX/j+VvlWuKpUlHc9CnHm+EbarDM02+GRt0u3yW/9Coe12uIXufKRv8AWqzfdpI4937503IqMzqvy7amihgkjO+GR3++vy/7NefUqcsz0KMfc5jCks0vJpvJdflfbFI33qzri3kmuDc7MlV27vl+9XRX0MyqblJoV2yr8uysya3hjV08lfmqqPN7U6OaJzV4rwyM7quP4G2fdrI8lLiTY80m2H7nz11WpWv7vem77vzKy/w1g3Gmp8r+WqfL8n95q+wy3mjLUxqcv2Situk+5/O3eW7I/wDDuqzDG9nCH2Nt3/eVd1RTK80ZTf8AOu1fl/vf7VSRqkfkwIm3/vpt1fXUZHj4qpGMWSWs3mN8+5f7rMv3qjnZ7qF0R9u5/vfdqxIr7o3G7+9taq7MIV2O67t/zr/drq9ofPVK0ucVLV9q/Plv4F31JDM+0v8Aw/7NRF3jwmzCsnybf4lqONpp5vOebbt+VFrKpIiMpfCX4WeSYul4r7futs2/8Bq3DJBDD/pPVt2+P+9trJhWFv7zsr/N81akLTfIny7vvff27Vrx8ZKPN8R3UYy+I2bVdrJMib0k2t+7+993+KtK3t7OaN3dPNO35WX5axIWS0Z32bty7VMdbdveLbwo+xUVU2bV+avnsRU97mPQo0/5i7C0k0bbyzOsX71tm1f+A06G427vszthk27W/h/3qqtdOq+Sj7n/AIY2/u1Fcag4Z3uYVXcy/wCr+VVrwMRKSPSp04/aLn9o7v8ARn8vav3W/wBmkVbO4ZbmaFn8v5f3afNtqGCRFklSWaGT+L94v3V/u0QyPFIIYQ3lbvm/hb/7Ksaf7szqe8XbO3S6jTY7LF/C33WqePyZFlR9u2Nv4vmakt1Tj7SY0H30WSpJI5lhX/RsnbuZmbdt+b7tVUqX6GUVL3SMxzRgwpNCu7+Lf91ajaO5kka5m+ZG/h3bq0Lf7THhJoY0Xb8iqv3qrzWsyyMkNzlm+6rbV21NPTZ3JqfCZ8kaXExhTdlot27+Ff8AZqtdNNbr86bZWTbtVa1VhdlD7GQs/wA0e373+1RNZ2aoIdjbm+VP71KVTlkc0uaMTl9SsUhUyJudv4lVqwtStwtqLaZMvJ/Ev3mrsNSs4biLMN4xLfK67P7tYOrWvkSM83ysqqvmKv3lr0sPzT5W/hPJrOcuY4y+hSNPJ2N8vy/M1ZkNjDcZ+RQ6ttX/AGq6TUIYZjJC+1d3z+X/AA1RmtYZ5lSHaiq/zrXrwlJwkeVUjIxfsDzXBdNyfw+W1Ot9Lkz8+7Zt3L/s10Xl+XJvS23Bmp0dijRt5Myp/syJ92m6zjG3QSpxjLmMWHS0jh8xId7bvl3fLSzRpDN5MwyZE+b5/mrX1C12ybPm3fKy+X/EtUry28mbfMn3k+RqqMve8jqjTHafcQ+YkGxfN+78r/dWug024aGP+HG7duX+7WDZ27+WzvDGzfeRlatjT7yT7Os0yZbf95aIy5pe6a8v8x02l30y7k+9uTcjN97bWrHdJJbo++Quqbkkjfburm7KHyLj7TCjfc+dletVZoGt/wB9BuDbvvPt/h/hrup1P5jjqQ7mxY648MiokeEbarMy/wAX+zVxfEEMLLD9p37X+b5q5r7YmYrbfNvWL7rfd/3qinmdpC7uw2/N8tdkahxy906tfFCSSMU3Ax/Lu2/L81Jb60l18m9WZXb95G3y1zEeqIsaiZNrSfM0b/w1Nb6lDHGpKfxfe3fLtrfm9wiMoROjbVE2hH6L/D/eqjPs8wpDDlJn+dd27bWba3UM3yb2O77kf8NWYw8itJbblVv7rVFT4SebmmMmuJpFP2lNnktsT/aX+GpobXgyeSuf4Y1+7V2GzeaFXeRWZk+81W/sq/IXTY3yov8Avf3qw9nzG0cROJi3WlvG/mPbK38KbqzLjR7lYWdIcPu+9Ia7aTTRdXAmS2/h+ST+H5arSaDM0x+0ozJv3bVeqjHl90qOI984yTR0W3kdEwF+aX5f4qp/Ybn5BM8e5vm/d11V5ptyvm20MPKtufd8u5f7tVLjR/s9ud8K79nyeWtYSpm8cRyyOauIYY7eL5P49yMtU7izT5XdGbc27/eroZrCGNW2Q8r827+7WbqEaRzNGkzJ5nzbtn3q4qlMuNYoQ3jrI33vvbfm/hq5Y7DJ+5dQq/wyPWe0c0cjI6L83yqrNUtvZ+WpTYxlb7jfeWvnswwvc9nD4rl1N+yunWVd6KWV93/AamlvIY5f33HmT/Kv+zVPSYUXKu7Nt+X5nrRhsZmk/dpwu1kaT71fF1MH+91Po8PiuaF5CNbosnzv5Qbds+eq8027dvtsnZtTd/6E1ai2rzfuRZ7/AC03/N93dSrpE98sWyyVpNnz7vlX/vqoo4OcavPI9SNb3DKgjNxMkPzLu/vfdrQj0va3nQou3cvzf3q1NP0HzJGf5ZW3/wAL/L/u1o2ugwwyCH7GyGOXb977te/g8L7WV1E48RjIU9zHj0tNsvnfPu+8v92tOx8N3lxHHDNYbjDtfcqf+PV0Fn4XRpF2Q7f3v3m/irf0/wALwwx/PuVlf5Nrf+O19bgcO4xiuU+Yx2KVTmZzVh4f8+Pe8Kld22Jm+ZVq/b+FZm+dPnRW+9H92up0/S0jhhjRGil37ty/Mvy/3qvWeg7l+eZYl+Y7f9rdX0mHj7p89Uqcuhztn4d8z50sG2/89P7zVfs/Dc0qvD9m8oxvXT6X4ZRjJCLfZtZvK8tvl/4FWnY+HYbWFEfcq7t6/wD2VdMqZySrSlLQ5CTwvCsKfZkZljl3S/uqbcaDbQ/6ZCjeV/D8n8Vd5Ho810q+Sir8/wC9Zf4l/hpt54ZmWR0+V4vu/wB3atcNSiHtDzG48LzSK3yYC/NuX+Jf9qsy68Pvayb38yR9nyM392vUdU0WGNSiQtsjT/lj91v96ua1LSRIwh3/ADyfcWRflX/erzK1HmO/C1jhLzR5ncTJbMi/wLJt+ZqxNS0fyZGe58zcybdrfL5bV3Osx+XdPDvX5fuTfwVzd5bvNcI7zbYWZm3TPu3Nt/vV4MsLKLke/RxUTjrzT7lpA7wq3lptdl+bbXP61C9vveGFnT5WSXbXZ67DuuAmxl3fNuV/4awdYhdl+T5lX7lYuHU6lLuYCypCzzDrs27W/i/3alk/0i4PyLt27tzU+4s3hmdgkbBv4m/hao5pHkj3x7R5ibdrfw1rTpwcvcMvae7ZyM+5uoWt/wBzbNtZ2+b/ANmrJu9833IWHy/LV7UGePaiuxVk3bvusq1UuA7/AHGUv/D8n3q9PD04Hl4iXvXM+Oa2kj3puDqu7d/eqnLN5i7H+RV/8eq3qGxlZ0RkC/f21Raby4wghWYN9za/zLXfGPL7xySqc3ulmO3eZVP3yqbtu3atEMgbajp5b/3lqPYm4yI/7r+6rfNU8N1+887y2+Z9u1fm3VcfeMvQs28aMzB4Y2Xb8rL/AMtP96r8Ni8kbfuflk+/UFrDtYuibG/u1s2Nv5sKI/y7v4W/iq3KUYlxlL4ipZ6fBD9/a6s/zR1o2enx71Tzt+7/AJZr92rcNjbSKiTBcyfxba0LDTYYmEMKMyxr97/a/vVZftOaPulb+zd4XZjcr/Iq16f+znpdy8V/bWljI0s80EcUaIWaV/mAwBySTgYrk9N0eeRlTZ8zfxf3a+mf+CUtvHpP7Zvw9+0CRwfHemx4STYQTLgHODxkgkdwCOM5r9C8McW8u4up4tR5vZ060rbX5aM3a/S9rXPRyLEeyzeM7X5VN29ISZseGf2SP2pPGT30Xhf9nfxpetpl21pqKQ+Grkm2nX70Tgp8rjjKnkZGRzXD67oOueF9ZufDvibRrrTtQspmivLG+t2imgkU4KOjAFWB6gjNfpN/wUz/AOCoH7Sf7Pf7S9x8E/gvcaVpNhollay3V1caal1NfSzRLKQ3mZCIqsqgKA2dxLHIC5X7W114P/4KCf8ABNy2/baufBFhpvj3wdOtlrFxZ3BjTylnWOaEBmO+M+dHMiOS6Fiqsdzb/wCgsp8QOJvZ5fjs3wVOnhMbKEISp1HKcJVF+79omkuWfeL93rro/uMNnOP5aNbE0kqdVpJqV2nLa6aWj8tup+fPgnwJ42+JPiODwh8PfCWpa5qt1n7Pp2lWT3E0mBkkIgJIA5J7Ctb4m/Aj41fBc2v/AAtv4UeIfDYvd32N9a0mW3Wfb94IXUBiMjIHIyPWv1v/AGQf2W/Hv7P37DukQfsy6f4T0/4i+L9LtNQ13xD4juJbiDdKhcMDCH8zy0cLGi4iyWc78tv7XwB8H/2ifFnwh8X/AAv/AOCgPi3wH4r0LVLBvL1PSLZrdraPaS5lV4Y4l8shZElXDIykkngr8vmHjtSw+ZVXQpU5YelU9m4uo1Xmk7OpCKi4cqeqjKXNJLpfTz63F0YV5OEYuEXa13zvo2la1vJu7Pw/0fwn4p8RWOoap4f8NahfW2k2wudVuLOzeWOyhLBBJKygiNNzKu5sDLAdTXU6n+zH+0ZovgI/FPWPgZ4stfDgt1uG1u40CdLYQsQFkMhXAQ5GG6HI55r78/4IdX+j/D7wB8a9c1HV459I0W/tZZLgSJ80MEV2zy7QxABQA5yVODgnGa+cvjz/AMFdv2rPjhNrfhldfh8PeENadoJdD0S1ijuBYk4MX2p1aTeycMwwCS2FCnbX3MOL+Kc04txeU5Xg6bpYaVPnqVKkleNSEZWjFQfv6y3dtFe19fWWZZhiMxqYfD0ouNNxvJtrRpOyVt9/LueEfDb9nn48fGK1lv8A4VfBzxL4it4G2zXOj6LNPGjehdFKg+2c1k+Pfhr8Q/hZrZ8NfEvwNq+gagF3fY9Y0+S2kK/3gsgBI9xxX7IeKdb+O/xb+APgvWv+CXvxT8CadoFhpMcFzpuowJLLCqwx+Va7tsiQuikh43VWBx83OK+Zf+CgXx0+PUP7HjfBL9uj9nG9PjGXW4ZPDfjrRjB/ZBK7mEhljLhLkoJUMAVdyMz/ACYAPz2QeKec53nFOh9WoqM6nI6XtWsTTV2nOUJxjGSVrtQbaT8jiwfEOKxWJjD2cbN2cea1SPm00k7btI+BPBPgPxt8SvEcHg/4eeEdS1zVbnP2fTtJsnuJpABkkIgJwACSegAya1vib8CPjV8Fza/8Lb+FHiHw2L3d9jfWtJlt1n2/eCF1AYjIyByMj1r9Brr4gab/AMEqf+CeXgzxF8KPB2mP8RPifbwXN/q14/2hQzQecZThsOIo5I0SNcRhnLndlt7P2Av28fE37efiHW/2O/2yPD2k+JNP8SaRNNY3cVmLV3MWHeFxEVGQoMiSIFdGjJycgp34jxE4ilhsRnODwEZ5bQlKMpOpatOMHyzqQjbl5YtOylK8lF6q+m086xrpzxVKinQg2m7+80nZyS2svN62Pzg8N+FPFPjK/fSvCHhrUNVuo7aW4kttNs3nkWGNS8khVASEVQWZugAJOBXX+D/2U/2mfiB4Vj8ceB/gD4w1fR5lZoNS0/w9cSwyqvUoyoQ4GCOM8givt7/gkD8Nv+FM/t7fF74TXN07S+H9JurGIJIsiSRR6hEodmB+9t2cY/iYHaRiuV+IH/Ba79ojU/2j4bf4fWOmaP4Is/EEdoujSack9xe2izhWaWVuVkdc8RlQmQMsQXbpxvG/FGOz+vl2QYOnVjSp06rqVKjimqkXJJRUW7y+y72VnfdW0q5rmFbGToYOlGSjGMuaTa0krpWS3fT01Pg6eCe1ne2uYXjkjYrJG6kMrA4IIPQ02vtP/guj8P8Aw74T/a203xVoyeXc+JfCsF3qcawqqtLHLJAJNw+8SkaA5HGwcnPHxZX3PC2fU+J+HsNmkIcirRUuW97PZq9lezTSdlfex62X4tY/BU8QlbmV7di94Y8P33i3xLp3hXSyv2nU76G0t9+ceZI4Rc4BOMkdAT7V+mvx4/aE+Fv/AAR68IeE/wBn34EfCjRNf8a3WiLd+IfEepW/kvMhkYeZK0f7yQySCbZGZMRIij5hivg79iEaKf2wfhn/AMJD5H2T/hNtO837Tu2Z89Nv3ec7sY7ZxnjNew/8FrP7S/4bt1X7djyv+Ef037F97/VeTz14+/5nTj8c18RxbgqHE3HOByLHXeFVKrWlC7UaklKMIqVmm1G7la9tdbnk5jShj82o4SrrT5ZTa2Ummkr27XufQC+JPhT/AMFfv2TPG2u6r8NdH8K/FTwNCt6mp2Ft5jXCrFI8Y8zb5rQyhJozGS+xgjjccCvzMr73/wCCCH2j/hb/AMQ/tez+y/8AhEIvt/mbsbvtA257Y2+b159O9fC/ir+z/wDhJ9S/snyvsv2+b7N5G7Z5e87du/5sYxjdzjrzWnAtCGR8TZvkOGb+rUXRnTi25Kn7WDcoJu7teN0r2SenW9ZRBYTH4nB078keVxW9uZar8NEe1f8ABND4PeAvjl+2b4Q8C/EqCG50kSz3s2n3AQx3z28LzJA6sRuRmQblAbcoIIwSR9d/tS/8FZPi7+yb8ctZ/Z8+G37NfhrStD8OXC2umRX1tNGbiLaCssSQNGiRsCCoAPHU54Hyd/wTL/Z58eftB/tV6Jb+CfGF54cXwwy61qHiCytxJJaxwuu1EDfIXkZggD5XBYlXClT91ftCf8FpP2efhX8XJvhzovwo1HxiNB1BrXUtejngijilRgshttysZdpBGT5YJX5SVw1fF+INCWaeIMMPDAf2lGGH96hzumqMnNtVHL4G5rRJ+9Zel/LzmDxGcqCo+3ShrC/Lyu+99rtaW3PJ/wDgqD4M8AfF39iLwF+2ZqPwns/BHjbWNQgW/sYreOOa8juI5CRKfkabAhSVGIZ1RiCACxHl3wS/4LRftBfBD4VaJ8J9F+F3ge7s9Csxa2tw+nTQO8YJILJBKke7nlgo3Hk5Ykn2j/gqVp8X7av7JHhn9tT4IfEHUbzwr4fDDUPCVxaIptWllEUs77CSs0bBUdWLrsO9GVdxk/NRVZ2CIpJJwAByTXreHnD+ScUcErB5xSVT2Ner+6nz3w75naleVpPli93pr1sdOS4LC4/KvZYmPNyzl7rv7jv8Ouui/M/XX/gnd/wUX/aF/bH8ba/J458AeE9E8I+FtJN1rOrWMdwHErZ8uMNLOVXhJHZiDgR9twNfkt/wWB+PVh+0ZqPxQ+L+jaNaWVhqE8cenR2lmsJkt45oo45pNoy8rqA7MxJy2M4AA/QH48sv/BO//gmJon7Ptk32bx58V99z4kKnEsEDohuFP+7GYbbHfdIR3r8p/wBr9zH+zh4ocDOLaH/0oiryOGuHMkWBz3PstoKlh5UqtGgo3tKFOLU6mrd+eovdfRRt1OLDYLCRwuNxlCCjBwnGFuqSd5fN7eSPg2S8RbfY8jF1/iqpNqE6t/Ds2fL/AL1U5ryZmf59yfwVQupnkjXD1/PnKfkMqxcm1b922x2P/AqzbjUHkjbemdv3WWkmkddyLyGX5v4arNNH/tDy1/irOW5cZcwNI8cn8S0jSOrnY/3v4VqGY7dpfcSqfw/dqMzZUOEbdWEtjqp+7ImaaZGZy6j/AGtlSwyOWV0+9VZd7yBH5/3anhXdl3+U/wAG2uOoexha0omjDG7D54dir92tGxby1SHZlt27zFqlZ/LCEwx+ati1jRcP/F/HXHKP8x9PhcRzcpahhTy98P8AF9+rEdttUzJuKKn3aS1R5Iw8m77/APu1fsbXpPHN8v8Adril7srnu0cQVYY2+/N8vy53VIlvtb7jP8/3mrRexRo1d/Lb+/8A7NJ/Z8K7pidy7N336x5uY7adacfiM+S1fcQ8O7d83y1XmiRV+RMH+7WnNb/KuU+WP5qrzWs32hpt+35NtEolyrlNpBuaZ32f7K/eqJm2NvL8rLT7hUkm2TcbV/76qpcEQo3kyfMvzfN92tIxlzGFTHRiLNeBWe2RGDt/E1U7ieETBLlGO35d2+oZpn85HhfLfxVD9odd2/qu7/gVdXs+b3jzamYdB9xcOsyif5F+7uqvdSOuX86o7i885fJdGqBr0RwtsfJ3fJuropx5Tz62O5pEs155UK702ruqvJfbpGd9v+z89VLrUPOP94N95WqtcTeW33Nyt/FXXGj7p4uKx32UaX2oudnZanspt+P7rf3ayY5vmZEdvm+61aemr5jff2t/DW/wnhVsR7T4Tcso33b04WtnS4XW4RJH3BlrF05Jm28fL/drpdMt3aRPnXarf8Cp8sDm5jY0uFzGPkV9r/8AjtbNjDC209m+X5vl21R02NIWLumFb+Kuk0u1hVVd4f8AcrL4Z3OeUuaNi/oP7mZI4fubPvNXX6DDbMu9LbfL/wA9N25f++a57SbVFuN8yL8v3P8AZrrdCj8uT7mX2bm2pWhidT4f0+8uGKPNuVolZdq7du2uk0uFJGWR0VkZd0vz7a53RZkRNjvMszMvlLu+Xay/d/2a6OwmhjZfOjX7vybU+61VH3fhDl5QGy3j/hG35khWql5D51wdm1v7rNV6S6m8tZpJl3tu3qyVTjuU3Lc2bsys3ySMny1fuSNKdTlK8kMduypv+8v+saqdxvZvJ2ZRV3eZ/C1W/tJf/Rkhx/tN826qcjLJMUlO2Nfm3fd+asZS+zE9zAynKUTPvf36+SkOX/56bvu1iapbpNsSF1A+b7qVt3kKRxpNs+bft21laq00a+TbJ8rbtn8VZR9pHY+xwdPmjqchqywxs0yfK6/w/wANchrC7ZiXTP3vu/w12WrWb7v3zqv95VX+GuZ8QWoVW8kLsZ/nauWpL+Y92jTlLU7e31BJIf3L/NGu5I2q9a6gJpjIiMg+X7r1xseoRxoqedtH3XaOtGz1S2h2o03G/d977tedHnifASlA7iGbdGX38bdrU+2ukj3cMrM/zN/Dtrm4dY/c/Nxu+6y/ebbVttUhkt38n94zJ91XrzazqrRHTTqU4yN+HULaPc8Lsksnyoyr8v8A31TI55re3XY6nb8u5n+9WNb3jiNoNi7Vfd81XIrp5IykyLsZP/Hv4a8mu5KpyqR6+Dq88byNmHZNGs1ymGV9u1vutT7q8FvCwuXX5l2qu7btrNjukMKo7fPH8yf3V/hqS1vIL6x3/u5fMfci/wB3bXHUlHnPZpy5oDrqTzI1k2b2j/vJ/DUV5aw27L533m+ZNvzVZk/0hlh+Vn2bdy/Lu/3qSRbby9+9Qrffb+7XVQ1mOp8JiapNc+W6WzruX5kVovu/7K1jXkLyZd/mMe1d2zaqtXQ6g0LW7J/Av31X5WrE1C6RQvztv2/73y19hl3wHFUl7vMZsi/aJntbZMt/D8nzNT4YfMVUebDbPlZU3fNUbRfM7pM3y/c21dh2QsPOdkf+6qV9LT+A8DFVpx+IrrbutuJndSV/9BqnqGxV855vODJ91V+bdWpIvlKnkw7F2t82/wC9/vVmalHJ5jQyOu1fvqv3lrq5zxpfvJlKaZI1RHRlbbt3b6YzIsjw+crbk3bmpzbIYWTfGq7/AJWb+H/ZqhJBNt3ojfdrCtU5YHXSo8vuotWcwkkCO/ys23atbVmqRt+8fcNnzrXPwxuqxI/9+ta1kRZgjoyL/eb5vlr53GVF8UT1MPTf/bpu6e3lqm+44X/lntrThkfzP9cq7f4mb7v+7WPbzDyVPnKrbv4v7tWvtGxvnmyknP8Atbf9mvAxFTmPao06UY2NBv30bI7r97/eanzX00kzwokap8rfvPm+XbWV5w+xjyZmR/N2qzL/AA/7taC3jrblEdXdkVd0ledze6dHs/dLlvJuUQ/K7fdX5KsW1ws0ivcvnzIti/3l21Rt1SS4+5t2v8u35W3bfvVow2v7x53ufk+VXZfu0/iOOUZx940tNjdrdYN6nb83zVY2zR3IkR2Xc33V/i3VXt/JiXyfJVH3K25n/wDZasrav5n7mRt7I3y0SlL5GMYe0nK4+K38tnh37tr7d0jbmVqFWCSNZppst975U+VqmUpKqvMmz5V3Kv8AFUbW94rM72ao33/mf71ZyhGOw7S5eUga5hmtXuXhZVVN3y/eqz9lhZT+5kD7Pu/xU6OSY70dMfKvyqnzNTLhLm3kSbZt3bf3ivuatIx55cpy1o+7qYmoSWelw70Rssnz7k3bWrntQH2yRv8ARm3L/E33WWul1+N7i4N5DtdVfa/z1zWoRwx7oV+V9n3Wr08PT5o6RPCxEuaXumDJGjTP5afd+42yq81n++aaHa/9+P8Ai/3q1rrZJl0eP7nzMq1SVXhZ/n+b7uP4lr1OX7J59SRB5c0nyQ/39svmJU3lia1DvCzpu/hWnrG7Y8sbmX7/APtVZtYvtE/kzXjAL/d+bb/wGj2ful0Zc0Cp5Y2/voVO75WVvl2/7tV2sUjjbejPub/e3VtSKkzB4U3qrbdrfxNVeOx/el5LZUP3nkjeol7p1x+Io6fZ/eQw87fkVv4auwR+VG6Sxrhmot5k+5nH+0v+992o1me3byfmfy23fN/drCMpR+E6vspMst5zbpk+ZF+/t+WrOn3UNvHsR8Kv/LOT+Gs2GSa5kZ3TLs3yfP8AL/3zVea98lvOnmwv3fmrro1JHJUj/Kbcl9DGodLn/WL8ysvzf99Uv26FkHyRna/z7n2/LWPb3ieSqeYxT/ZpJ72OOTej4/vq1dkZe8eZW90172eGe4RAi/d/hf8A9Cqx532fbD2/gZV3VjrdQsrunySK33dn3f8Adqb7T9oWJoblVf8A2q6acub4jil7sjZ+1LuTY+7anzts+7/s1t6LFtl3pMuJF+VWi+Zv71c9Yq8ypDNNsSR/8tXYeH9N85vJRFX51Zmkro5faE85o6fpT3W3f13/ACRsnyr/AL1bsPh3czMjq80iK3mR/d+X+7Uul6ftBezRQ+z+J/4q6O10b7RGEQbWVtm1v4quMeWPvC5omFp+h/Z1abyYyrJtfa+7bT5PDkKxF/tK7F+b93/C1dXa6DulXybNfN+9tZPlqxZ6L5KvClmz7n2/Kn8VRyw+IfOecat4dmt5P3yM67dzR+V95v8AerEv9FtrcD5edjMrN91f9mvUdY8PpLM6P52/+BlT+KsXUtFmFn8kKsivu27aOXmCMjzDUNJeH/SXSNk2f8s/4d396sO68P3jLLDA7OrJuTdXp974Z+0RtBMjfvH3vuT5VrOuPC9+qvsRSfvP/srXLKjy6le1PMJtBRVl85Gfb8yMsXzVNY6ait/qWxH823b81dxeeF/LkEyJI67/AOH+KiHwztVvJhkUSbt7N95VrzMZh4VNGdtHESOc0/TUa62PCuzbteORPvVvx+HXWEJ9maV9jbl/9lq1b6T9kUpc2y7vuOuz5l/2qtWbOszQyPJhm2/NF822vlsVgYxq3jE+iweK93lZSh0tJIR5O5N3/Lu33lqa30vcslh+8VNq7W3fxVanjtkZZv7vzbv7rVYsy/lbPJZnVfk/u/8AAqzjh4yp/CepLGSjLkiQ2Okv5MkLou/YuyON9vzVv2Ni7RxzJuyzqssap8sdVYVeS3ihS3b93t/eVuaXawyRpFMmBvVv+BV7uCw1tTzcViOhp6ToYZhDNDtaH5vl/irWs9JhuIzDC7I7L/wKo9LmTef3zeVu2+YqfNW/pqvHPsTblvldpF+8v96vpMPR948CtW5jMOg/6O/2Z/461rPR3dVjm3NtXc7f3q1LWz+XzE2/vPueZ92tSx0lLyZJ5o9g+83l/wAVetGj2PLqVDPsdBhlVZnmb5m3Mq/Lt/2a2LPwrDdI5mh3S7N2373/AHzW/o/hlGjEJX5Gf/WL81dLpfhW/t8eXMv+xJGn8NdEqPumEqxw8Ph1J49727PtX5fl+VaLzw/NcWoRN21olTbt+aSvQ4fDKJGqbGY72+9/DWfdaKi2cMN1uaNV/wB2uSVMcah5dc+GXhbf5PlNJ8qK33ttctrmi+TdSpNbbdqV6tr2jfvpU+Vvn+XzPl21xviS18mR08mRVkfbu37ty1w1qJ1063KeWeINMhb5Hdk3PuRW+61crqlvNHv2bW2vu+VflX+H5a9H17T4bht4tt7Rv/F/yzX/AGa5HWLGOEi53rt+bev92vNqUaXLY9ClWv8AaPPtWs3mnEkz/wCrXbE396uc1Rkjj+Sbd/D5jJ8zf7tdv4iExh3/AMbL93eu3bXE6pHNHDN5L7VV93y/w15dSjL7MT0qOI0Oe1HUI5pNiOzJs2tI33aozSQ+Y0O+R1z91flqXUpI5LgQ+Szovzbdnyt/tVTuNQjmk2JJhNvzf3VatoUugSrRkJdXELIjzJIny7Nyv8yrVG4mdV2FG+V/ut/47U9w7xxjeik/e2r/AHaq+dumW2SPb8ufMrrjHlOSpLm+Ijk2LDv2Y/56tWfNDbQtlIdrN/FVq6Z5vkSZkT+Flpqqkiok3Cr8qybN1dHLzR5jn5v5itHbwrIjo+7bU9jZvuKIkm9m2r/C1N3JC290Zmb5f31XrOGbyW2Ox3Pu3Uvdpl048xYs/JWZIZ9vyrt+b+9XT6PYxyzt5KM3lqqqzfdrAsbEY8+a23Irfd3/ADV2Xh87Y0dEyfu7V+8tZ81ocp1fYLdjorxyRLDMsqr95ZP4latvT9LgjUeciu0n39vy7as6Lp9s6p8kbSt8vyo25f8Aere03Rd7Dem9o1/u/Ltq6fvSMKlP+UpWen289mqQ9W+dFj+8v+9X0F/wTJsbWw/bP+G5uo5Gjfxzpu0xsAS/nDackHgMVyO4z0615FHY2f2jYlsqPu3ytH937v3Vr2D9inxX4U+HP7Snw58a+MNbj07R9I8WWN5qF9cKxWCFJ1dmYKCeAOwr9O8Msu+vZri6ibvSw1eSSV+ZuDp2/wDJ7/K3U9bh/De1xdR3+CnN+t1y/qfpD+3z/wAEovEX7XP7QF38ZfhV8YtEsrq4gtrTxHpWro7G0kihQIyNCGOWi8s+W6rjhgxDgL5P+3F8Tvgd+x3+xbaf8E7vgp8Q38R+Iby4Evi3VdPlj8uPE/mTpPsdvKkeRFUQAkrGnztyN/zV/wAFWv2kvDfjf9uTxb4n+CPxCs9b0ie1soU1HRL52hlkhtY45AHUhZAGVgGQspHIJr5bvPiRq0JdhBbMQu7mN8n9a+l4W4gyWWAy2GeZnOpRwqpzhQVDl5akY+6pzTbmqbuo6K9k3c68FnOXQpUI4zEuUadmoKFrSS0u1uo9D9YPg/4i+GH/AAU+/Yr8N/s2XPxjk8KfFPwNFDFpz6jcgNqJiiZFZEVw1xC8KgOV+eJ0DFWGPMx0/wCCdvwF/Y8+F/iL4if8FCfjq2vvcabLD4f8MeHNanglmk4HmQCR0e5m3MuEKeUnLSblPy/lSvxn1+yuEuEsYISvzRyKXDA+ow3FVtV/aH8XahcPLqTW900Q2LLPJK+T6Alulems54cw2JqUMuzirQwdSo6jpRoe/Ft80o063xQjJ9EnbVJ6u9f25lFKo4UcVOFKT5nFQ1V3dqMt0n6aH6e/8Er/ABJ4P0j9lf8AaVtbnxDZWCz+GS1nBqWpQpL5Rtb2JS2SufnliTdgKXcAckCvg61a2W5ja9jkeESAypE4VmXPIBIIBx0JB+hrx2//AGhvGFpvSHQdPZlOCSzgA/8AfVZN7+1N40tdqHw5pqyE8oyyED8Q1fYZXx/wLlGcY/H/AFmcnipQlb2cly8lNQte7ve176dvM9TC8U8P0MVWre0k/aNO3K9LJL5n7NS/8E0fh38aND8N/F//AIJn/tHweG4n0a3XW7O48SXLzrPsDeZLJAWeGc5xJCVVQw+UIPlrov24vEOm/AH/AIJv3X7OH7TfxvsPiL8R766iGnL9t3Xlu5uPNSZtxMxSJFcebIBv3BOAcV+Gqftr/FHRLiSXRdK06BsYZoZJ0bHvtkFUpf22PiLcTm5v/D+ku0nMkrecx3e5MnNfBLP+GcRmOGqZhnFStRw9RVIJ4a1ZuLvGMq9+ZpXs9E2tDzY5rldXEU/bYqU4wkpK9P3tNk572P22+F198Hf+CqX7FPhn9mjXPiknh34peA44o9LbWJEZr9o4WQNGm8NcRPCoDlRvidAxDDHmbX7OP7Jfwr/4JKprH7T/AO1R8ZdK1HXV0ua08OaBobYknVinmeQsxR7iZvlTG1UjUszMQcp+Gdj+2l8QkkWaHw7pUc0Q37oxMNp9Qd/Fav8Aw2L8S9ckW41zTbCZwuC8sk0hA9AS9ZYziPg3kr5fh83q0surzc50FQvL3nzThCrvGEn05XZXXV36pYnL5KdGniZRoTd3Dk11d2lLon6H68f8EfvjNbeOv24vif8AFrx/4ktbKfxD4cvr921K/jQ4N5FOygsRlY4kYkgYVI8nAFfDskkJ+KDSi6h8v+3yfO89fL2+f97fnbtxzuzjHOa+c9P/AGofFl118PWK4OGyJF/9mq7B+0V4keIzNpumlduV2JIdxzjH3q+py7xP8NMqz3F46liZ2r06VNQ9lK0FSUoqz63UtrK1utz3MLi8tp4qpXpzdpqKtbblTX6n6g/8F3PEPh7xH+0d4QuvD3iCwv418Cwl2sryOXaHuJpUJ2k4DRujqTwysCMivh6vI2/aF8UAZbRLA/u933n6f99VHcftGeI0fZFpOncfeLh+P/Hq34U8XPDfhfh7D5VHFVKipR5eb2UlfVu9tbb92b5fjMBl+Bhh1NvlVr2se3eF/EF94T8S6d4q0wKbnTL6G7tw5IG+Nw65wQcZA6EH3r9NPj5+z38L/wDgsH4P8J/tB/AT4raFoPja20RbTxB4b1S5814kEjHy5RHmSMxyGbbIYyJUZT8oAr8V5P2k/FKR5/sbTA2cbT5n/wAVUcX7VXj/AEqX7dpunWELp92WF5VZfxD15vE/ilwDneLw2PwGYVMPiqHMoT9i5xcZq0oSg7KSdk97pq61McfXwuLlCvRquFSF7PlurPdNdUfs6nhn4Vf8Egv2S/G+iax8SdI8U/FTxzCtkmmafc+WbdWikSM+Xu81YYt80hlITexVBtODXzl/wTN/Yb+DH7Z2s+J7X4sfFy60ZtEtI3s9F0ieGK8uQ2d1yWmR18mPaFYKpOXGWQY3fm/q37XPj0SSXdxoumyuV3tJKspZz9S9Yl5+2l8SLSISxeE9GbIycCXj/wAfrjwXHnCGFynGKlm9VY7FyjKeI9hquWyUY072UVFOKV76t32txRxGGoYeqvrElVqNNz5e2yS2slp+p+sP/BOP4xfCD9ir9vHxL4J8VfEjS9R8MahFdeH7XxvGWS1JWdHhnJyVWNzGFZssqkht+wFj3fxC/wCCHPi34g+Mb7xz+z/+0B4S1Dwnq91Jd6XNfSys8ccjlhGJIFkSYKCAJARu67RX4r3n7cvxHtpfLHhHRf8AgSTcf+RKZZ/8FGPjVpQeystG063iBJ2wT3KKx+glrXH8c8OvOHmuUZvOjXqU4Qq82H9pGpyX5Zct48stX8Lt5IxxOY4WGJeIw+JcJtJSvDmTts7aWfofuD+1Jc/A79gr/gnXqf7E2g/FXTPF/jTxPqm/VoLSUbrZzLFLLM8cbsYFVIYkRXbLsd20jeB83/8ABLL4HeFfjd+1zosfjjWtOttK8NRPrdzbX15HG161vhkiRX/1mGxI4wQI4nzgV+X8/wDwUB+KCF3l8HaFvByQVnyT/wB/Kgk/4KE/FSIgjwPoQB77Z/8A45XZlvGXBmX8N43AU8yqvEYpznUrui789RKLlGCaUUkkkk9O5lSznKMNgqtH28ueo23Pl6vS6XTTbU/Sz/gop+0vL+1L+1Nr/jewvfN0PTZP7K8OBH3IbOFmAkBHXzHLyZ9HA7V8rftHeDPEXxC+CmveDvCdmtxqF9BGttC0yxhiJkY/MxAHCnrXzpc/8FFfijChKeCvD5b+FSk/P/kSq7f8FHfi4kYY+A/Dxbb8wCz8H0/1lfT4fxB8OMPw6smpVJxoqn7LSDvyuPK3e2/W7T11ZvLiXhuGAeD5pKHLy6Rd7NW+8464/YW/aYeTKeBrYj/sMW3/AMXUD/sG/tNlsR+CLcBVwv8AxObb/wCLr0zRv28vjjrkipZ/DvQDvxtGyfv/ANtK9e+Gfi39sH4lzNaaP8G9PkmePfZRQ2VyxuR6r8/T3r88lgvByK1xOI+5f/Kz4udPgKE9a1W/ov8A5E+Um/YE/abBLjwhbkkcj+17br/38qAf8E//ANpxl2N4HteDkE6xbf8Axyv1T/Zj/Yr/AGkfiLq9sv7St/4d+G+nXC5828hmkuB6fuQ5YfjivS9Y/wCCedsnjWx0Lwp8f7LVNOmvvKvNRTw1Mojizjco87JP4Vj9W8F3L/e8R9y/+VlqPAkNVUq/d/8Aan4uz/8ABP8A/ajkO7/hBbUt6nWrb/45UR/4J9/tUHA/4Qe1Azn/AJDNr/8AHK/W74l/8E9/2qvB2vX1ppPi3wQbRJm+wLqXmRXEkXUOyedx8vNdBoH7FvhnSPDMeo/Ez9oa3k1JlDSWPhjwZd3EaZGdvms+3dWc8J4KL4sXifuX/wArLjPgWW1Wr93/ANqfjmn/AAT+/amU7f8AhBbXnuNZtcD8PMqxD+wD+06pBk8EW3y9P+Jzbf8AxdfqlqX7Pn9sytD4A8WXYbcRF/bHh9l8znAGEm+U/XNeYfHD9n79v74T2suu6N8MvDmsaXH9yZEnjkk4yPlMny/jURwHgpU2xeJ+5f8Ays6IYjginL+NUXy/+1Pg22/YQ/aPTa8nge2DL/1GLb/4ur8X7Ef7RuVVvBlsu1cbv7Wt/wD4uvSNf/bJ/aE8K6pJpOv/AA20GCaIYkj2T7g393/WVn/8N7/F0bd3gfQVz97Mc/H/AJErmq5d4Hw0lisV9y/+VnsYarwvL+HVn/X/AG6cxbfsYftBwqEfwtbnnOf7Ug4/8fq7bfse/H22gyvhe3MpbJb+0YP/AIuuli/bu+JUi7h4O0Tn7o2Tf/HKng/bl+I0/wAq+EtEB91m/wDjlck8v8CeuLxX3L/5UerTnkmnLOX9fI5Zv2PvjyzAP4at3XdnH9owc/X56mX9kD41JEdnhCAOPuf8TKDGPT79dOv7cHxCYKF8K6KWLYZQs3H/AI/Uq/ts/EGSMtH4V0cnbkKY5v8A4usnl/gNHfF4r7l/8qOh4jKIvWcv6+Rx0n7H3xzkkMknhOA+w1OD/wCLqGX9jn48Stz4UgUe2pwH+b12LftwfEeMEv4Q0bAOGfbNj/0Oobj9uz4gwnavhTRM7sAFZv8A4ur/ALO8CP8AoLxX3L/5UR7fJd+eX9fI4ib9iz4/lCq+FIGBOSv9qQf/ABdULv8AYf8A2h5590fg+JU9P7Xt/wD4uu/uv28/iZbyso8H6GVX+LZN/wDHKoz/APBQj4oRS+WPBWhd/mMc+OP+2lbU8B4Fx0WLxX3L/wCVGNWtkUvinL+vkcHP+wx+0lv3ReCbYn+8NXth/wCz1Rf9gz9pl02f8IPb8nLf8Tm2/wDjld1ef8FHvivaKWPgjw6SBnG2fp/38qg//BTX4truK+A/Dhx0AS45/wDItdEMu8EJaLFYr7l/8rPPqVOGoy96pP7v+AcZL+wV+1KwwvgW3Pu2tWuf/RlV5P8Agn9+1NI5c+Bbfn/qN2v/AMcrtJ/+CoHxbjTcngPw3nGcGO4/+O1UP/BU74yAE/8ACv8Awxz935bjn/yLWqy/wStpisT9y/8AlZzyqcKy3q1Pu/8AtTkT/wAE+/2qdpT/AIQC1I/7Ddr/APHKhf8A4J6ftYOdqeBbNF2441q1/wDjldif+Cqfxm8woPh74Y4Gc7bj/wCO01f+Cq3xjZcjwB4XB90uf/jtbRwPgt0xWJ+5f/KzjnDg6W9Wp93/ANqcrD/wT4/arUqx8C2ile/9s2v/AMcq7L+wp+0vo2nS6heeBIZI7eJpJEh1S3diAMnCh8seOg5PaultP+CpfxiuQCfh94aXPqlx/wDHa+gP2Pf2k/Ff7Rena7d+KdD06yfSprdIl08SAN5gkJ3b2b+4OnrXrZNwp4T8RZhDL8FicQ6s72vypaJye9Psi8FlXCeY4lYehVqczva9uiv/ACnw7pEa7wrBwScEEfMK6zS7d1kTfD8zfM237tafxtso7j49eLHUGMr4kuug+9+8ak0O3n3L/dr8TzHB/UcZVw978kpRvtflbV7dL2PiMRSlQrzp3vytr7nY1tHt/MZYUh+81dLY2aSTGGNMrH833fvf7NZej27j5H+8r/LtrprfT5Fj3un+0is23dXFzcpzylyF3SdN8uTyZodzMm3cvy7a3dLidmSF3bb/AHv71QWMMMkLWz2zFP4V+9WxZ2/8b220fdX+61Pm5iJR5vhNGyEkKxQ7N4/hkb+Jq3tL1Dy02zTZ+Tcqqm75qw7dZsfaYN0R3bkb7qx/7K1qWFtbW9ujTQ+Tufb8yfd/2quBMi1czQqsWxFT5d0qr/eqnqFwkm+HYw/uKtLPdTW7NZzeTMsbbl+X5apXl1Myr/q96tu20c3KXEkWTbNsRG3qm1lrPkmkupvkmbH93Z/tUyS4SPMzuwRn+9/7NTPtUN0okeZok+ZYpFT5d1TKXKe3l0e4XUkMkj3Oze8fyorJu21j6zJtmT5GVmdtqxt8taNxIkluiO+yTb8jbvlb/ZrHupEkmWG5f5fvbv4lauSUub7R93gXyqKaMPUFSMtB5yszfNtX+GuR1mP9ykcLqy72+X+9XXa03lwvMnKsv/Aq5TXIdzJ5aNt27kZflrnlLm9496lGMdeYry3CKyIiL+8+V6t2t9tkXznVF2fdb+KsRrzayPvzt/vJVeTUt0iyPwuz/Vt/FXNHnPzCVTmO60XWIWX9/Nxub5f4lrW026trdt7uzbvm+avO9J1ZIVRN7M33vmrXXXnXP+krt+75f96vGxPtfe7G1OXL70jtlvkurUu7thv4l/iX/wBlp39qP5aCzhZ0+ZmZZfmauQHiR0hZEk3bflfdV+z1jzIza+dsVXVt1eBUouU+ZHtYWXN9o62x1iS2dIX3Z37F+Xc21vmq41x5kZ+7v+9u+7XN299JdFB521l+/wDP/DWhZyIrFH8xWX5otyfeqKFGfOe5TqezjyyNrzHkmebyWMm7au1vl/3qfdXEMe6aa5VW2fLt+7uqpb3EFwqf8sw3yvN5v3aJLeOZUTf/AAfekT73+7Xt4OnzfEZYip/LIjuNkm1E4eRfvL8tZtxb3klx878L8jbfl21uLB9oX/UtujqO6tY7yHY4+6n3v7y19Pg17P3TzK2IjH3TCk0/zI1dONvzOzP/AA0tvsa8f52ZpPuN97/vmr0luhkCJCwib5fm+792nx2m5UuoU2bovlXf/FXv05R6ni1qntJycivqFvCsYeGHemzdu37ay7qQzTP5iMrf3VTbV+8t33eXcjftTcm5/u1l3TS+dve52nZt3N92t5S5feOen/dKF1CkanzpmUK25F27laqkzbcuH+ZvlZf7tas1v5kcfnTN5n3VaqElu/2xt6bH/wCei1wYip7p6NOMiCNXm2P+7T+5Vu385VD72eZm2/eqNYPMmTyX/dKu5/k+81W4YMZTzmb5vkZa+axlT3rnsYWPuk9nL9ouJXfh97fL/DVuG8eRnS5T5V+42z+GqqshUon36tL94IEYjZ8v8VeZUfN7x6dGjy+8WY2tppN/nbSqbX3JViCbzmX7Z95flXc/y7arR280LJs+ceVudf4t1SW6+Yr/ALlh/Du+98tc/uSNKnuwNe1+03lwk0D43fK/+1V+PyVmhtprlQVdml3J96sSz3syJ+8zH8z/AC/L/u1s6XI80x/0be0f3amVP3tDjlU5o6mxbh2bZ9pVCv8Ayz2feWtK1VP9dCiurfNuZvmWsuxW8YI7vx833fvVpx7LiHzoUjjPlL/Dt+7XNUjOUeUI8kpFhreby2ms0VnX725PlVaS3tPMkbzn+78rfxbv9qmwu8kPkO8jj7rtsqWOPdGuyZdu7aiqm3atTGE4mcpR5vd2EWNFkREhy0j7Hbzd3+7TZoXVf9TtLfLu/u1IsaW+XQ/LI/3VqteX0MzOiI0bx/8AAvlrrpVJc+iOKt70TA1CPdJ8+52+ZUXftrDvpt2XhgXP8asnzLXQ6hIkLLN5zM8fzbv4vmrD1CGb7Q/nOxRk3Oy/LXv4X3TwcRExbxUmV4RJ+6X5vMb+GoL6zhjVHfzHH3kXb/FWhND5MbSvtZN/3W/iqC8V2kLu7BWT5o1bdXdGPtDhqRjGPvGck0Nu0nzsjt/Ez7qs2Nxc3ipvRVaFOdv8X+9TGjTzD8nH8asm7dVm1VF2JbeW7N/d/irSUfsnNHmj70S4stzBGU2b9yMys3y7ao3Vwlzs+Rl/vf8A2VXbiSe1ZrZEU7l/4D/u1VZtyn59rfeRf73+zXPKnE7qdScdSOzTdA7ui7t21G/vVFbyQ26ed8o+8qKz1PHZurffVfM+ZNr/AHaq3Fq7Qt523fv/ANXt27q4pHdGRG15tUzJbSD+8v3dv+1urOuZvOZtkzbmfc67d1Xmt08n99D95Plj3/erPuI3Vt6PtXft21dP3feRnW94qSag6rJ5Pmf3U+bbVyxvPtiK+/8A1a/3N1Zl1au0i+dHvVv4m+6rVoaRbvax+T5LfL8u7furvpyjI8vEe6XVkubi4/0lF2/KyNH97dWvp9i8nlZ2lf7rL826q+l2PmN86MWX5UVf4Wrdt7V2u4vvH/pmq/xf7VdlPc8upI0dJ011VZkdZG/uyf8Astd/4X0GSaFIXhZFuP8AVbn+7/tNXP8AhbQ4VkU78fJuWRmX71dz4b01G8nZdRy+Wm5Fb7q/7Nd0Y+4ZSlym74b0NI1+4uV+V2X5t1dFY6KkcnnWb53PuRm+Vv8AgP8AepfD9snyzJCy+Sm3a33m3fe211+l6fZria2h+ZV3Rfxf71ax/vGEqhj2ehvGyTfvGZfv7m2/LVqPw88du23d8rs3mRvXT2OlpMo3w71k+Xbv+arlroX2e3fenz7/AOJPlqfZxkL2hwWoeF9sweG8b5tzs0jfxMtYNxob2qr5af6v7i7t26vS9S8PzSTfPD8rbVesrUPD/l/vnto3WP7jKnzbafLKKI+sc3uo83utB8uFv3O+L5v3cn3l3f3aoXGhwzbvkyq/wyJ97/er0W80d5IQkyKrKjfeT/vlayL7w68cYm3rvVFbatTKnAftPe5UefXWh+cqvDIyIq/3aqX2ipNH+5fcy/fXdXa3Wlv5Mlr+8VvvfN91ayLiz8uGSGz3M/8AeZf4f71ediKZ3UZHKXUPkhofJbdJ/rW/5aN/u1BPZvHIpmdkkjT5P4W21tTaajYvH+V9+0LJ8u6ql8jtumf5Tv2LtfcteNiKMuX3T28PU5Sh/ZsMkbI824SJ/C3ysy0iL9laK2hjYeZ827zdq1JqH2do/kh2NI251X7tCXyNJslH/XJW/urWNLD8252e2/lLtvZvuRH+VV+Vfn+atuz85bjZDwY1+81YulzQSKqTncPveZu3fd/vVoabeOrFJpmZWdfKZv4t1ephafu2OLEVPaHWaO0MCrsdWeT5nVf/AEKuh0/943n3U/mn+Bdv3VrldMh/fB4dyOv3F/vLXT6OEaOKa83b2b7q/d/3a9mlGx5tSUuY6TS7ePy0m2SYX5ol27l/75rttL0lIVDzQfP95F/9lrA8O2/l4+95TN92u90Wxm8lJnttz/e2yfeVa9aMuWB51SXLL4jR0HRofs6BIdu5NzN/drqNL8O7oY32bUb5UaodHs/Ot1mmtW2RtsRY/wCKujhh+VExho33bmX5v+BU5e8cHtvf94zTpP2fe9m8OPKZdzfxVmaho9tGPtSIu1f4fvV1lxFDHjft/eJuST+GsHXLdJIW8lNyxy7mWFtv3v4q5qkf5TWMjgvElj51zs+zM4VF+9/erhPEFq8jfcw8jsjbvlaNq9K8RWs1rJL+5+dXVnbd/DXE+KbV5pHh3szSJu27K5KkeY7KdTmPMtYsZpVljdFRo/k/2f8AvquJ8QaT8rJM/mov32/hr0zW7OG3m2b/AJ2RmZW/u1xHia1+0M/nTNsVNjL/AMs2X+8rVxVKZ2U582p5v4i0+2mt3RLbDr9z+Fq4DxNZ3yyJ/q8/xrv/APHq9P1i1eSdHh+YL8kUjV534ou386a5ddhk+VFjX/x6uSVPlOunW7nA6o0ylk8lt8aN81ZscsM0mxPuM+19y/MzVq6tHMt9Md/y7NyNWHJIm7Y42H7zLv8Au1hyxOzm5tIkrXf2VsoMov8ADsqlcTG3b98m5ZP4anaZGU+T/F9zd96q9xcbW+R1I27WZV+b/drWMeb3iZSj9oiMkMm5E6/dVViqPzizSpM6jb91Y/ur/wDZUrSPGrO8O2X+9v2/LVdpIdzfPv2/7FXy8pzc0Ze6WRJC2zzplf8AhbzFrRtWDQu+xQWVdm2sqxXy9ieT8n3trfNuq5Gybi6bdjJ91f4aipHqbUeeO5uae3lzFJk2tt/iTdtrrNDk8mOLf5Zfb97/AOxritPuv9I2SOrfL8+7+KtjTdSkVfMm2p83/jtc8o8p2xl9k9T8N3kMcbPNMuPu/L8rf7NdRot5MtqLb5VO355F+7Xmvh/VkCo+/fHH/qvMf71dPpevPI6Inlptf5938VVR90KkjtY5kh2PDCrlV2ytGnzL/eq7BKzab5u3adjHAHTrXNLqCSRIjzM0i/N8rfKv/Aa39Om8zQxNKCP3Tbv1r9u8FnfOMf8A9g1T/wBKge7wvKMsXWt/z7l+aOVulhWQ/Y0Uru3bvutWJq0m5nhSbcv95v4q19WmhZUf7SybflVttZF4okj3oV/d/Kqs33q/KoysfB1InP30n2e8TyfkZv733ayppIbiR0eFVDPuZf71bGuKlw7onKKu6KSNN3/Aawry3TzA6W2z+Hdu/vV2xlGRxy934jJ1eJPOZ/M/vbq57VG+/wCZwPK+7t/irodQhSFpk+V/n+9XN3yzSRzP8u9m+ZVrKUvcKp83OYOoqjRrMg3t/Dt/u1QRFaP5E+Vv4mq7cRwsrQzQsu3/AGtqrVK9aGNQkbqqL8u3+GuCt/Kjup8nOPtf3Mm5/wC/tX/arTt714Y/73zfN/s1kNIkduknQL/D/dqSO68uQ735/wBlK82pThserh6h1Gm6lCyb/Obb/data31CGaHY02U3/ulj+VmrkrG8TaqTfIf9/wC9Vyz1HzpvOm+T+GKvNqYePQ9jD4iXwnUrIfJeRJlyqbH8ylW68tQlyilmT/SFWsKTVpvnfzsbfufxVOkzt86fLuT7zfe3VzSp8p0xrc0uUtXN0mF82HC7/k2/w1FNLeSS7IYVwqMvzOq7v+A0xZvmRPtSs/3tv8NR+TdSM291+b5kVfutUcsfiOiNSXwxM7VIQyrM6MpZ/wDe2/7NYeoafCrfO+FrpLi3eP8A5ed396sqe3Rpmh8ldsny7mrqp+7A563J9o5u+snjU79q7fu1n3Fqkn91j/eat28jtmVnR2Yfd/4FVBrEyTP/AH9v8SfLXpYfmlqeTiDGmsYXDbnZtvy1nXVq43b/ALq/d3V0U1n5cf3Gb/d/irS0P4X+IfF2oW1tpumzP9o/1SrFur0KfkeLiPdicJDod5qF8LazhkZ5H2osabq+rf2Bf+CW/wAWv2vvG0Og6bYSQ2ULq2pak1qzeTH9792v8Un+zX03/wAE3P8AgjzefFjxVpU3jOwupHaf9/b+Q0EUK/e3SSN/eX+7X7b/AA5/Z58GfCfQU+GPwQsNL8KadDYLZJdabb/6Szf8tJt395v71dNTFRpw0PErSnUl/dPze+B//BJ34D/B3VLZNY8NX2o6xDOqabot1YfabmZl+80kcfyx/wDAq+uLXwD4k+GetSX7+NrHwfdw6WsVloui6XDJdLGq7lVY41ZlZmr1T4qeF4f2bvBaW3gDWLfQra+vP+Ko8d65ceZcxx/xLBu+ZpGrxyL9v/4V6D4T8SQ/s2eEJ38QWUTLB4u8S6Zu+0bfvTbfvMtcVTFc0uVl08Py+8jl/CvxQT4P3WpeNvj98PLzVZdS+bTdS8cXq2zyNu+6sP3m/wC+a7vwX/wU0/4J56L4LW21o6amszMy3Gm6Ho0ki28i/wALSV8ReLfhh8Vv2n/G0Xj74reONQ8Q6je27NPqk1vJtjjZvlWGNflVf92qmufsSv8ABbxlpGt23wc8VeKtLjt1nnt5L/7D9quN33d393/0KudwqSl7j5TROlT3PsDxR/wUN+BV3rNr4nufiF4JfTVLQweHb7SVRo23fK0tzKvzVwvxS+O3iTXJpofCvjnwjqOkattli03Q2WRbfd/CzLXjPxA8Fp8XPDb+FdY/Y80Hw3bSSx7bq68Q/afL/wBn7v3q1/Cv7GPxI8K/Dyz13QYfBdtZ2M7eba6PK3m+X/DuasvelFe8TKMPiZufDHRf2jtH1j/hLbbwTp99Asv+i3FrKrK393crfxV3mg/Ej4naa9zqvxX/AGY9U8R2l15jT6hH5byeX/eVV+XateP6X+0NrHw/aXwr4z1WPFvLuijtZdyrtr3X4A/tufBzXri2sIdVvEC/8fkMkXlrWftlEJUZSjFxPMvit/wT1/YA/buhv5ktLjwl4kvLNks75bVoJ7ebb8vmf8Cr8yPj9/wSv/a3/Zn8ZXPhXVfhvJ4q0ppW/s7xBp8EjR3EK/ekZtvy1+6/iz4mfsr/ABC1pPCuj+MNF0zXI3826Zv3DR/wruk+6zLXZ/Dv4Y/Ejwr4fubzQPj9Z+IIfK22FveIsvmL/d+b5dtdUcTGpG03dDo1q+Hn7p/Mp44+Bz6LpqarZ21xb3McrRXum3jqrx7V+8q/e21wEdnDG3yOr1/Rn+3N+x78Fvjx4Nurz4i/CjSdD8QzQMsHibQUji3Mq/dZV+81fjH+2N+xzpvwR157/wAH+JI9StI7PzZbdl2zxt/FuVayrU6Uo80GfQZfnHNPkmfOTWfQI64X7+1fmpY7WRVkDo3zNt/3qteWkjLsttv8T7qmhs3j2zfKSv8ADXm/D7p7/N7Qz5I3WMJ5PzN/eWq7Wf7nZ5C5V/vba12jmRRNH93fVC+V45nm2b93+d1bRjORn7SEdjEvI3be7w/d/i3ferH1BflE3ksvybdtb2oRpIvlx8Lv27t1YeoRzRspPI/3q6acffOKtWnuc5ffvH8x3xt+Xb/FWJfrM0iIUXDbvu/w1t30b7t6f99VhX3neWybNy/3a9GnE8utWl9oo3XkhTx/wKqUknzEbPm/2at3SptG9/vJ92qsm+OT5ErrjE45S94rsu1N3zUx442j2fxbvu0+TzG+R9zfxbf7tPhjk/5ada0jEjmLenr5siu833f7tfan/BL2MR6H4wAXH+k2X/oM1fGFjGke3Yn/AH1X2f8A8EvUddC8YGRcMbixzzn+Gav0fwijbj/CelT/ANNzPpOEv+Sgpf8Ab3/pLPKPjc+z47+K5NuNviC65X/roadoMkM0ImCNv3fI3+z/ALVP+NpT/hePiuIY51+6LY6/6w1DoMe2MeTwdy7Wb5q+Hz73s8xX/Xyf/pTPEx/u46r/AIpfmzq9BRFuPJTa25l+9/DXTWMcefJSbhpfk+SuY0dnmZnMyn5vu10+m/6QphSFt2/5If7teRzcupwyidDptvDIqOj7v92tayhmeYfdCRszRRr/ABf71Y+lw4kG+Zl2/NtrXsZPvTb2f5dyfL81Rzcxlzfyl+3tUjbz53+Zm/h+b5aurcCNt/X5F2R7flqrb3ULqY9jH/ZWnyyfZWMaooRvmdt9aD6+8N1C8/1yTIqbovvL/wCg7ayLwQx26eTNIdvy+d/EzVYvE2OJtm7cnzrWczXO7zo/LVvu+Wr/ADUS/lHTiNuLl5GeadMt95/7tRzXTxKr+fu+fai/e2tVLVmk+5DeqybFaVV/h/2apSTJ5O/exH3V+eplKEj28HGEf8RqXWoIzDztsyxy/wBz7zVm+Yka4uZl3M/yNs/hqtJcQ3GLYPtCy7trVJ9udrZnuU+Rn2ouyuGX90+zy+p0ZT1DZJJ5yPgbvnk/2f7rVzeuRxyKqIjbFb/gVa2qXSNal0mZEb726sDWL54wy9V/jasYxme9Tl9mRzEl5tdk8liP4V31UluUjb765/ip0mxZCkM2dv39v96q19JjCfw7fvbanmjzH5p7OXQeuoJGyzfMxWrtvqSSKqPMu+sZrqHzBI77FX+FaFXdMskLyDb83yv96sqlOlJm8Y8x0a6o7YQq2W/u/NWvZ6gm1N77Gbarr/8AY1yFvK63Su7sn8S7WrZt7iaKRftib2+75lcVbAwlLmideHqezmdfb6skMivM/lbfl+X5t1bmn6h5irNHefN8q/8AAa4rT7hJJm+RnX/lk1btnMdyP/ef/d2rXP8AU4R2+I76eJ/mOqsZEVTNNCxMku1Gb7vy1qWdw6sn8O75t33tq/xVzenLNJG6Q3P3pflkX7tb+myTbET+HbtdVWuzD049TT2kuX3S/HIkLK8ULHc23zI//ZqsyWsjRs/kqHX5mkX+7UViwVTN8u3+6z1PMs0cjum77v8AE/y7a9zDx5TgnUluyvdK8cg2Ovy/M+6qlxcJbwvczfuk/ikb7tF1cZha5meNXjZkRY/vVk3V1jKTTbU+7tavUiebUl73vEclwJN7+cz+Z/49VLbMzPzHlvlSht6L+5eP/eX+7TjLbNjY+1v71ay5eUUZAFh8tNj7P4dzfdZqr6hDDGyb3VWZNz7XqPbBJIyeT8zP86s//j1WZLe2uPnG1/L+Xd/drya3xHpUKkpR1Kcbor7N/wDubfu09Y7aORPn2My/6tnpsKp5ypsZh/B8v3qWbY0hTZlP7q14OIj7/unt4ep7t+UtW7P9l2IMfe83c/zNVvyfLWJ4fM+7tZf4f++qqW8GNiPbM3y7dy1qxwpJcLbfMm2Jvvf+g15laUeU9OlL+YS32Kyvvb73ysr1OLdFk/fXTFV+9I38VOt18uP/AEnzPl/8epwh+zKHd1P8P3P4a5+aP2RylEnaORbdUttyP8rPJ/C22rcMiMQk6KG37naP7rLUFjDNNEmP9T95d38NWo40Me93YN935V+Vqly5jjk5RjsamnqGZ5ndtm9XX+7u/vVr2NzNNIzudvl/Lu2VjW7JG0MUCYf+7v8AvLWxDceZI8KfMzfdbd8y1MnPm2FH3Y3LscyTR/ang2iP5f8Ae/3agkj+wWZhvH3D7yeWm35f7tXY1SNSiTSJtlVvLk/hqpcLunMM0kjD73zPURlze6Ty+01CaRFjDpNsCrvdf4t1Z+qTQyMiQJsTb8zQr826pN0LebNs3Ju2rtqpcWciqfJ3NIy7V8v7rV04WPLLmMa/vU+WJRvtlyv2lnUqu3ezVUuoZnWSZNv91/4vlrTaOZVa2hRQ6xbv3n3W3fxVFNbzW6k+cp8z5flr38PzS1keHiI8srGM1vDIokdF2/3d9U5LWHyX2Js+fdu/hate4hSdfO/i/vf3dtZ95dfaIVhtvn8v5mVlr0InDUo80TOW18tok8n5pP8AgS0tqsMkm+F1YbtnmN8vl0rKnmM6PhW+X/gVRQTPuELlVbdudmrf7BzSp8upamt4FXyUdju/8epPsaeWjpNu/wBlqjhkmjuPJ2Z2/MrMnyt/s1YsVdkaGTblvuVjUjLkKo+7KzHNYpcQlPJ2r95Vqhdw/wDLbeu/+8zVqws8MZePlGfb81UbqNFYQfNmvN5pRm7ndy/CZkmn3KIj71/iXa3zMv8AtVDcaem7yfuq38LVsW9u/mL5ybfm+6q7t1PFm8jv+5Uxx/KvyfLtqftWNZR93mMSPQ9yhLby9m5m2yfw/wC7WlpugwrKqB8ldrRfJ8zVqLYorb3T/XL8m5d3l1o2th5ezZC38K7a6o80djy8RHmK2l6G9ri6mRnb7y7fl2tWxo+kos377cvmff8Ak+7Uum6em4pDB867m+Zvl21sabZpIYt8LMi/Lt3r83+9XpUfdPHrR5dy9pFlbNMkyJG6R/Lu/h212/h+2RY1e3+VW+b5fm21j6bYwx7UtvnhWJfm2bvm/u12Hh+xtvNheD5Qy/N/tV6cfgPMrS/vHUaGs3mKZkZ1835N1drotvDFGYUhZX2f73y1zfh1UjkhhebazN8i/e/76/u13On26QTf8fMm6aLb5irurXlOOUpbFyz0uCOP7NCkbSbV3yfxba0tvmW6TeSrN5Wx9y/L/vf71Mt7W23D7339u5fl3LV64hSO3Z0fIX5fLq/dkTGpKOrkc9JBNMjukWH3fJu/u/xM1Z91paLJK6QsRvXdt+6tdHLY+cuxEb7m5vmqnNbwL++N4ybk3P8A8CqfhHTlzT1OU1TTIZn/AOPbLKm3cz/K1Zl7pqRw7Ld1RJF2/f8Au/71dRJY+cyw9E+b5m/ib+9WLqkM1ufOhfYNjfd/h/2mrKW5106fvcxyOpWf775/LZl++2zav+ztrCvtPDbtiK0zf3fl3V1us7JrdPMhjTzN2yTZWDqFpuVkmh2fL96OX/x6uKodtPc5XVLMNl0TL7W+X/arCvLWGORUTa3l/Nt/2tv/AI7XXalb2DRvD58yFU3K0fy/N/drC1iz25d9qSfefdXnVNzvoylE5uaFI5vO+VGb5trS7qVrBHUpv81YUVt38S1eutPS4vI9/Kr9zau2oGi+xvsfzNzfLtX+7/vVivdj7x3RlIns2SMtbQ2ysrfwr8qr/eardiYWmZ3kbf5W6Blb5ttZbXn2GRX2KwZ9qbt33aYusKzI72zY+4v+7XbhvhIqVDs9JuEjmSF3k3tL8qr/AHa6zQ44bi4WFE/d7fk/2Wrz7RbmFm2Qvvdovvbtvy12fhXUnlX98m0bdu1fvV6tGXLE8+p7x6jocfkrs+0/8stu5a7nRW3QxzTop3JuTzP4W/2q838I6hbeWpmhZm8rZtZtu6u30fVHmh+0u7b2dd25PmavSp8so8p5dc9K0G6na1ieb91LHudJFb5a6K1unvIzNJ8/7pmeRa4Kw1izjs47VH2NIzNu3/w1vaXrkMduAjrjytqbmrSMuh50v7p0MMjr++WaNl+/tb+7/u1jax9muN6GFn/ifb/DuqX+1E+zpNbTKjeUyuv95f8AarI1K8QxtCk23d9xVqOX+Ur2nLEwvEjQ2rPs8xV3fd835vu1xeqSp9sTf5n3W+ZU+7XVas1y29YfL3/x+d/d/vLXMa03yuA6hFX51b+Lb/FXNUidNGRxWvbN7O8MiJv2rJ/E26uI1yzWS3ltnfIb+Fv71d34keGaGTY/zLFuWRmridaaG4k87Zgtt/1f3a45RPRjU5Tz/wARJ5cJhd23/fXy/mVa878YWaMx3IpVvlSvR/Elvf8A2hoYUWPdLv8AMZ/4dv3a4bxVDNJCzpbRp839/wDirlqU/tHTTkeZeIPPSZYd7M/8arXK6g0zXDPs2O39567XxBAkUbzJbMjx/wDLRX+7XF3ypNJiab5m2/NsrilGX8p2U5fCNW6RpGe6ufm27dv+f4qivGSRhIjsEX5t396mtj5tiZ2/Lu2feqNleSHZHwq/dVUqI+7sVL3pkd1N5jJ5iblZ9u7+7T22RyMET5Pm81W/u/7NRLDu+dPn/wB3+Kp1W53NMnyqz7l3PXRzmEf5RLeR/kdIW3Mn3VWtJbNG3Q/Zl+aL/e3VDD+8k3zblbfuWRavWqpFbibZub723dtrCpzHXRjEfDazyQ7HdU8z5av2K/YQ0Gzeypt3Mv8ADUVn8rfu0ZQvLsvzVoqqLcBPO+8isit91mrklI9CNPmjzF7Sb7yykKWzfdbZu/hrotL1KGHH77cWiVkZf71c3DJ9lZN77ZG+barfd/vVb0+5T7Qu99u75katqMo82hjU5up2tjq1t5SoHXLffuP9qvQNHlQ+DVlAOPsrnBOfWvHrWaZpGm8/a8ny/f8Al/75r1jw3dK/w6S63BgLOUkk4zjd/hX7b4Ku+cY9/wDUNU/9KgfQcLJLF11/07f5o5yZoZpC7zZj+9BJ/F/ustZmqTIszIi79v8AzzpYbyaTfvRn/ufLtqreeTaqzusnnM25fm2qv+y1fkMa3KfFSjzGfqk2632Wbsg2Y2/d2/7Nc1qz3McjwPJ95F3svzLu/wB6tm+kubjfO7xh2Tb8yfdasLVPmY2czqv3vvfLW/teUw9nzGRfXSQzOny7WTanz1z2rXjpI/2Z9q7fvL/erV1pYY2R0OxWb7y/NXP30bm3b7w2v8+3+Gp9pGQo0yjqF5uXYiNn+Pd96s2aTzNkJ243fxf3qkummkb53/g+bclZsmoeX8j7VH97+81ZSkbRLrSW3k7872b5drf3lomm/c7JplG3bs2vWZ9ukmUwzPs+b5f+BUn2ny2/hAj/AIWrjlT9/wB07o1Pd5Tfjut0zOiYdvvf7tWrNv3ZfeuN/wDF/DWDa6h8wd593zfNV6x1J49yJIqLu3J8v3qwrUZnZRre7qbiyOuI3flU/h/irRhk+0Rs7v8ALt27VrFtdReS3b98rN92r8d1C0I2XPyx/M6t/erlqQud9OX8pfhhh2qjpvaR9qKv3v8AgVWFuEk2fJsf+JW/5Z1TtdQmuFZEdkRv4lqz/pMiqg2uVbbXNKEubU6Y1OWPukM0fnXB/wBJ4/grI1NUaTy5kYhfuba0rrzdwT7Nna3zqrfdqrqtu6xr5L42/cVXrWnHl5UZy97Uy/s++TEiMit/DI/8VQR2X2hmhm4H+/VqSHzP3Lzcr83+1XQeBfhzrHiq8httHs2keSVV2+Vu+9/s130Y++ebiJcsRnw7+HP/AAk2qW9nN8jSSr5W5GbdX6r/ALAP7FfhvR9M0258N+D7W/1mS9VpZr6DzWX5f4Y/4a8s/YO/Zb0Twt4403Ur/Spr+6sd32qRbVWgjk/u/wC01fpF+zLq9/8ADG6u9A+Ffw6vLvxDql1591qmqOq21nDu/vf8tJNv3VWtqlbl2PnMRW5pcp9P/A3wjeeGPBdonjbTbW11Lb5UW23WPc3+yq0z4wfHr4K/APQP7d+Kniy3WWF/3Vjbxb5ZpP4VWNf4qu+Cl+Ilno9ze3lra3N66eYt9qMu1Wkb+H/ZVa+WP2l/2fbzxRHqU/xR8f2d4983mWtjodvJuXa3zNu/hVf71c060tLbGHLA4P8Aa9/bJ8WftB+HrTTPhJ8N43fULryIrrUl+2XNiu370UC/u45P9pvu1o/smf8ABOvWdU8Pvr3xU+NE1jLcKq3unyWSyysv/XRvl+b/AGa6D9kv4K+EvC/iaDw74M0qaGwtV8/7VcXDSXNxM33tv8NfaPhzwNBpmmtiHyJZFz9ocKzL/wB9VtSlzRugb5jz7XPB+i/Bf4Yp4P8ABnhiN20+3Vl1jULWPy1+b+KvnH4pal4t8YFL+GGPVnkTdtW82qu3+7XvnxnuPAei6bcN4y+IcmuyzTsn9mteeXHuVflVlX73+7Xw7+0d4os7G+stYm8SeHYXum2RW9jebHjX/a+b+7WVStKUiPZ83xHNfFS4/wCEHszrfiHwlfW33pfsduvmt/vKq1leHf2nPhj4quH8PaJ4km0p2dVnsbiJkkZv4lrmr79u7XvhrJPoPwr8H6TtuItqXXiK3a7kbavzNury7w78PfFHx41C51i88f8A9ircXrTy28ekrBA0jfeZZPvbaw5pz1pm0eXlsz0T46/st/DG5kl8beH/ABDeTeJLza0unxt+6aP+6zf3qf8Asl26fC/4pQp4h/Z5mn06SVWutS1C/wB7fL/Esar/AOO1hfD/AOFfhfwz44t/D1/8XZrm8t4t25d3kKv+1u/i/wBqtj4mTePPB+uR674J8eeKLm2hZV+0aT4f/dqv+y3/AC0/3quUqjjZmXL714nrnj/UPFXxd8a3Gpab+zxo9vYrdLcRah4ksNsce3+FYl/vf7VdKv7ZHxD+Atj/AGl4wv8AwHrEUd1t/sfT5drRq3/LNY1+7Wf8OP8AgpRo/wAMdJ0rTfiF8N/E2uWrSr9q1LVLWGJW+Xb91l3Uz4hfBH9hX9uDxR/wmH7Nl/caV4ptf3uraTpM7LFqTfxRsrfLu/2v4ayk4zhyS91mnLKnLmR2d9/wUg/Z4+NkNt4D+IXw9k0F7qLfFeQ3Xybv9la+Y/23f2Xfh78RtJvfij8Mdet9SNnp0y7bf5XmXb92T+9838Va/ij9nn4P+D9Qm8PfFT4o+D/CeuW8uyLw6uvfa7qNf4d237rf7NRaL8L/ABV4bhuNSfXpNX0e+umVLqFNqqq/dXb/ALtRGUqPu812TKXN76Vj8j9b0+5tdSlttSh+zur7XhVf9W392o2t0+WFLncF/hr9NPi1/wAEi7P4zatL4z+HXi2ztZ7z/j4sWfayt97dt2/3a+O/2gv2I/H/AMB7iayvEjuQrM3mQy7m+X/0Kt/q8pQ50fQ4LNqE4xhI8Kkt3WHf0ZXasu+hkZPv4Pyt/ercuLVPM8mZ2H+7/erP1KNFh2WzqR/Ezf3qxpy5fcketKMJe9E53VFTy3TP+18vy1gapG8m596+V/Atb19+93o521jahG8au7lWZt3yr/dr0KfNLlPMrS5fhOY1BWZPuMv8SstYt8sMWUfdub+L+7XR6hH9qlKD5X/u/wB2sC9jTa298n+9XfT0908mpKXMY0ypDJsHztJ8v+zVORC0jJ53zbN1Wrr9yzP94VCkfy70fI/j3V083vGBBDvXG87t33mqaFAGXYn3qTydzbEdf9mpLdXVs9dr/eqvhI5mXNPX5mR/7ny19nf8EwiDoPi8j/n5ssj0+WavjS0jhVdj7sr/ABV9lf8ABMJy+heLywwftNln/vmav0jwi/5L/CelT/03M+o4R/5H9L/t7/0lnlPxqm2/HjxYgAI/4SC43Fu37w1V0uTbcKLaHd/tN/DUnxwM3/C+PFyxy5J1y6wPT94aq6TJtjXDsD/Btr4jiD/ke4r/AK+T/wDSmeLj+b69V/xS/NnX6XI+77jKG+Xd/C1dRpMiNAsNy+8fwfNt21xGl3otmVzN8rJtZfvV0Ol3iTQq0MKtKr/eryJR93U4ZbnaafcFl5fYq/c2vWzp9518lF837y/3Wrj7PUXVlebam7/nn92tjTdShEwRLpf95vustBHKblrM6zRTu7THZs8vbtqx501xIXwu6P5n8xPlb/gNYq6tNHCkKIx2/wC3t8ula+S5kXyNu1vl3K27bTlLsXysu6tqCKuzzGB2bt38NYl7qE0aF4uFkbbuj/hqO8vnWPMz7l2bvlesi91R5G3um7b9xd9Z+05vhHEnurxoRs6+Y/z7vl2rWa2oIJFSFOfvJt+7WfeXSSKdh2j+Pc3/AKDWfLceRCH+0ttVfvfeqZfCejhZe9zG22oJC/yQsN27duXd8tQXGsPGuyP51VPn/utWW+pIyrCkzYVNqtUclw6rJCjZC/3Xrml70rH0uHrSly2JtQvnuI2DxxrE38NY+pXaKzpsykiL8u+lurxJIWR/u/8AfO2snUdS2ln+XC/L8tH2j3I1pfFIoMzu29E+6m1lqCZpmXY+3K/3f7tLIz7iUC/e/iqG437sf+PVjKPQ+Zo4eRXjj86d/wD2WrNqrzKrom0/x/7VR6e0KrvRGG19u6rdnG8bbE3ZZ/vVhKXKd8cCWLNUkjR0TL/d/wBmtS3t0ZPOh3b/AO9I9U7dJDIu9Mt/srWtart3p8zsv92ueUhfVZFvSvtLfvkTYN3yblrZsbc253o7fKnybm+9VCztv3ZmfawZdv8Au1qWtv8AMv2NPNVV+bzGrH4iOWMY25TV0i6dW/cxsQ3yvu+6v+zXSaPHHMrB/vr/ABVzel3k1um/7MsiMm52b/x2t7S7qJd6OrK2xW+V/vV1UY+9flMuaMYG7BdQ/wCuuYW/hVWV/mZv71STTeXZuQnKu21l/u1kWMgl3u6NsaX/AFn3fm/2almu3Zvs0L5C/wAOyvWo6e8c1Sp1KOoTXjR/P825P9W3y/NWPOs7Mfk8xf7y1q6lHNJK7xuyMvzbf71ULqNPuImVb+KvSjUt7zOeUoy0KCw+Yjp8zjf977u6o185MfZiy7U+ZfvVaa1eFg7n5WX71VfL8uRPs275vuf7VOUoS0OaMeUVWRspDtVu22nRyQtiH7yt9/b/ABU5bV1kYvDj+Ld95adFYvDGvz7WZvk2xfLXBWlCR208RykM0O3/AFL7Ds27mepoYXaPfC+x/wD0L+9UsdnayY2PJIV+5tT5as2tqkatCqMzs3yf/E7a8HES5T3MLU5o3Qun2MMa/aUtlXd8zzbvvVdt7V5v9d5mfl2L/Dtq0umTRwtDDDG3yfdX7q1aj0lGVUudwdvmZV/hrxqkuadz14/BYq/Z3X7m5N3+tVqfHD5jb3/3h/dWr32JFjeZJvNdf4W/hp32GFs/Iz7otzbfl21EuSWhfMQQwuqpNc8NJ/qt38NWYY0kxOm5dr7dzfdp9rYzSRlHh3xr9zan3attH5MZhhtmdVX72373/AqqnGUpcqOSpUjGPvCWbTPOqTeXnzW/eMn8Natr50kPkvtz/wA9FTbWfG0Jh+SHcrJu+ZGVlq9pk0jTffYxL9xWb5q19n7vKc6rf3jTYXL4hublQN6tuZdzNtWoNSkP33/esv3WjanKv7z/AEOFmO6okt0VvJdG+XdURo/DGJp7b3blK5mhjmREf5tvz/J/47Uas8a7Eutm1G/d/wB6p76N3t1T5mib+FX+as2TY28Ju/eLt2yV3UaP90yqVJdCyGto7OKb77Rtu3SP/wCOrVaSb7Ysbwjb97bUULO2xJ3WIR/cj/utTftCthEmkfc+3dIm2vWpx+yefKPtPeIL7eqvC9su6P8Ai31kXCwlPJ+YO332rS1CNPM3v8u1d21WrI1KYSK7p8iq+12V67IxMpUylNJMsyRnyz+9b5m/i2/3aa9x5jK+zYG/8dptwqHe77lDfKsjN97/AHabCsNwy2021gq7ttacsTllHl90s6XsYMjyL5sku7ar/wANaDLCsmyENlfvsy1ShVIdjujMy/c8ur9vlo3d02tu3IrVjUkZez94fZs/+0W2srKyf+PU+ON5pPOd/kb5dv8AtVHn7KzjfJ++2/x1chVJlLxjZu+Xcqfdry8RI7KcZdCKxsfJkeb+98yL97bV+yt3uJvJhmYts37VSoYYXVRCjthV+eSRPvf7VXIZlhxD5ys23a21az9/4hyl/KQrbo67N/Kvu+WrMaQ27ffk+Xb838TVHJcQqwTzGJ2feVKRri22p+5kLr825d1ddOPMeZX/AHnMy9atDHGZt+6P+P8AvVs6fNZtG3nWef8ApoyfdX+GsGzkc3n2b5odybt2z5Wrc0uZFZXkO3a+395/E392vWoRueJW5onY6KqLDA7zNsZPu7du5a7jw7HD5MUycfdZGX5dtcDolx9lWPfDtWP5k+b5t1dj4bvEkhQJZ7mZ/uxtXqU480bnjYjl5jvtEukjKI8yyuzt+7j/AIv96uw02TdYq/ygbVb723/vmuC0O6+0YmQMzfdVfu7a6zT77y2+eZXEaruVl3fNWhzfEdla3VzMq73Xy9m/b/EtXproLMXR1Kr/AOPVh2OpPDuS2udn2j/XtJF8rf7tW4byBgyJMoiVWbdJ8tTzFRo9CzI3kyfJD/Budd9Zt80Mjec6cf3W/hqaS6tm33MO4LGu7zG/iX+9WbcapbTX0aOi7GRnRl+bdXPKsddPD9yDUm8yPzoYfNGxlVWfbXO6hZpHD5PkwvtTc3zfMv8Au/7Na11cedC+P4XbYrVh3U0CxlE5RflRd/3axqVDqjRlEytQg86P7RNNxvXarL93/gNY2qfLcb5nyyqz7VrbvpH8tvJuViK/f+T7tc1rV1YW6vv5bf8AdV655VOY6Y05dSvdb1K+dCzI33o2T7rf3qx7yGG6UlHZ1Z9u2b+GrGsa88kLzJN8y/LukrmtS8Q+VG8N1Mrhm3Iv8K1yVJc3wnRCPSQXzOuxI3XdGu/cv/xVZGtahbW5l8mZkb+7tqjrXiia3tWe2O5938L/AC1yXiDxg8d0qQvHtVG+Xf8Aeaufm+ydtOUuU27rxAscgebdsX7n+0396qC+IEaTYu53ZvkZq4+68UQs3nJ8jr833/l3VUt/FE8lwD5zKy/3v4q7sPEwrS5j17Rtc+yqr/aY2VV+RfvV3/hDWJpoxEjqs396vEPCfiIbh5M3zb/n+SvR/CuoJtCTXO12Tc7f3a9KlLm+I4an909o0XVraHYj+XCzIrJJ96uz0HXHkaK6e5Ybfk2q/wB7/aryPQb52mhmtplO5Nv+9XcaLqSTR7/s0aFvl3M+2vUhJHnVn05T0bTfEG24W5G0Ddt2t81dLa6k8ca/PGiN92vPdI1CH7KmbmR2VlV/k+8tdPoMnzbJvnDI3zfe2/xVvGUebyOGpGJ1Ed5eNC0LzZ3ffZUp8cN7HEu94X+Xay/7VVbWPdCh+07UVVZ9rK3zVZh2TXHybUZvl/eU+WJEoy90ydajh85EmtlIX+JX+Vq5nxFJ+7W2Ta7bWZ5G/wA/drrdU8wzM7pt2pu2/wAVchrUcMcO3eyp93zPustc1T3TaG5xPiKZLhXdywDRMqx7P/Qa4jVFRVW2e5bY27Yuz7tdv4kaDzD9j2qyvtfdXF+JJLaNltvs+59+5W/iZf71ckpWkejCWhxviq1tri3ZLYs6LFtSTf8AM1cPr1pM1vHNZTZ8ncvzfw13mqLCsmxEaINuXav8X+7XKaxaosO9JmQyP91k+XbXNKJ0U9jzTxBaveQuiOzQs25o64/UtK27/k2D7u1q9R1SxhhD73XMnyoy/wANcl4g0ZGuvLm+fb92T+9Xn1PeO6n/ADHEzWqLGZl/vr/s/LSNC8f+jOkeV+ZW3VsTWLyTb0+6v3l27lZaij0uGWR5nh2/3/8A4muOU/sm/LKWxkR2czM1zN5iL/Bt/ipi2+6bcjs21v8Avmte60/gukMi/P8Ae/2aotaeXMN6Nlpdyt/erb4oaClDl5R1q3kzjZDvVX3eW1Wobh/O+xony7NyR0+1t0WPe8m9v9lf/HasWLwyHzkTcrMyt5iVjU/lOmnzRiT28dy2zyU3KyfearkK+XIIUT5lX52X+FqdZ2sxjML7lC/6pd9W5NNSFVd3Ywsv8X3laoj8Oh1KU+YrsyWKs87tnZ8+5d1XbVbaKaOCZIdq7fm/+Jp0MM6yF3dlZv4l/hpq27qv2abgt83mbfu/3aPi+EJR5SeG4hjk+ROVdtm5/u/7VeweEl8r4UqpPAsZ+T3GX5ryFrf7PNDG+1wyr8395q9d8Ks7fCf5mJIsrkHcMHhnFftfgnJvOcf/ANgtT/0qB9Bwwn9crX/59v8ANHBR6pC1v9pLtvV9z+X8zbahvdRRp5Eh8x1+6qyf+hNVHdPbt5P+r3Ju3L91lqvJqXmQt5Xmb/7v3a/F5Vj5uOH7C3135PzpDHub79YGvSO2+ZJvk27kVv71XbzVvJVnhfHzrurF1jUPtELom5t33FX7tRGtLmuZywsTKvrh2k+fhf42/u1zuqTec/z3Klf7v96tK+utirv+dtn9/wCVWrIvo5mVd+3d952WtI1uaXumX1flmZ2pR7rht6Y/hVmf71ZV5sZvuKo/gZkrQul8zbs2v/d+SqF8r/K8z8L/AA1rGXtCJUyncO6/Ojqyf7S1BJqCbd+9d27/AL5qO8ZNron8Pzbaz5pvLYQvHubq1ax7mMvdmadvqG2TZs2/7Va1jNC0yTbPmXdtWuUjuE/g+Y/x/P8AerR028dWaabhm/i30qkZ/ZNqMpc51kd4jRD73zL8/wAladldvIu/5v8AYrlrW8dlx9p5Vv4q37G+eRdgTKbP93bXBOPNI9ej8Bu2Nx+5SF9ys331X+KtNV3fvN+xv46wtPkSOH/XMzKn8Va6s7bZim9pPv8Az/w1xVI8tU76ceaER+o7/McI/wAzf8tKozQpJh5nUt/Gy1oyR+XGHROVX5/7u2mW9ik2fu/3vm+WrjGPLzGVaPNLlKNjpdzcSeXs2v8Ad3L/AA19HfsX/BPxz428UQab4VsNQlu9Qf7PYWtv96Zv4mZv4Vrz34DfD3SvEXii2tvEnFvJdKl15MW6SNd38P8Aeav1t/Y9+GmlfBfxF4a03wToOzxTq37+1s1iVm0+zZvlaRv4Wb722uylpHmkfOZpWlH3EfQf7Fv7HE3hpbLRfiEjJLawxyfZbG12bW/i3O1fXGpeAdH0icaroWg6VHKu1P342Ksa1bub6Hw9o1os2u6bazKkf2yW7dV3f3q+SP2wNO8YweNTrnhv4reIdYhvnaKLSLCz3QW7MvzL95d1TVqez+D3jx404QXvnu3jJ9burpNP8N+PNLheblo7V/P+X+L5f/Ha+Y/iV+0J4t1rXLzwB4WezsVt7hotSvLho5ZY4938Kru27q8Z1j/htXRdaSGb4PyWMMcSwJqGpaktqs0e75VWOP5q9c+FPwtT4aabL8Zf2h5vD/hXTdPeS6XT4Z1iW8Zf4mZv30zVyzS1lNGnxQjyHrXwQ1fwH8APCr/ET4l6xpelK0TLbzanKz31x/d8iD+L/gK1l/Ff9tr4kaxo93beHvhvNoOix2Uk/wDb3jLUo7F75f4fJi+9t/8AHq8W8eftKab4km1T45eAPAOjldPX7Ra+KvGTyeRGv3VWDzP/AB1Y1r5r8J/C/wCJ37fnx5uvFXxC+Md5r0G7zdUuriLyoreFV/1ca/dgWoVaOIjy/ZNYw5IEXxE/au/aN/aS8ZWHw6+CejR3UC3TJOuk7vIt933ppp/vN/31U3xA+CPhf4a6Dcw2dnpOseIbW183xDrl5KzQW67fmt4F3fNJu/iavqjRdS/Za+Gvhu1/Za+APifw7pVu2lyXvjXxFNdKktjCvzNuk/hXbu+9XwB+1x/wUy+BviLWdc+Fv7LXgxb/AMOaDLJbp4qvIt0epTN8rNHH96Tc3/LRqvD1MNT92GpnKnX+KZm+H7fw34s1h7nWPEP2izsUjW1tbN1T7VNI3lxwx/xN81fQ2h2fwf0HXNU8B+Lfijo+gQ+GdNZ/GV5ay+e1j8u77LD/AAtcMvy/7NfEX7JXhP4nax4/tvjB45SbTfDug+dq95faha+XH5yxt5Kq33du7+Fa89t/Elh4H+0eJ/H/AIwW+k1jV5tRvJrjd5V5IzM3/AqVatyRLp04y1Pr7xN+0xc3nhhrn4G/C6Pwx4Gs5WR/EmtQLJqWqNu+983yqu2qtr8cPj9ps1t42sPiLrmrWkL/APINt5Y/L27flVo1+6teReHf20dB+I11Z6N4nnsYNKhg2263Vv8AuF/7Z1778MdN8T3Ghr4q+A8PhXUWk2xXWnwxL/pTbd23b977tc8cVRnK8jX2M/hien/AT9szxD4+1XT/AAl8WvBmkvZ3Hy+TfWCu8m5tv3tvy19Q+KvhP8OvAfwz1HR/gb9l8I61rE6y+I9U8P8Altc2q/eW1X/nnu/5aba+SP2Vf2tvgtpPxkvfDf7VPwht/DF7oqSOt1b7mit1X7vyt975v/Qa7rwj4hf4f/EzxJ4q+EvxLutc8PeKriS9lutUVd7eZ95W3fd/2a562MdKTUZfeaRwrqbxPN/26Pgbf6potr8QhbWaap4fZU1TyUXzLxZF/dyM22sz4O/EDXtL0uz0TU55prZv3kULP8sfy/xVteMNU8SX2g6rba3qTP8AatyfvpdytGrfKv8AwGvM7q617SfD8iTSQxMq/wCsX+7XFWzLnnHQ7KeWyjTlc+mfhT8dLDTPESWdzZ7HmuN3nLKqqsf8W3+9/wACr3b9oz9iXwL+0F8C7q/1XwBDcOsTXFlq1rdbZV3L/s1+YeqePPFWh61bX9hfw3Lx2qxRRtF8u3duavtX9hX9uLVbJYfDfjy/aIr8zTMjLEqt/Dt/u16VHHOjGM90eVWwvf3T8yv23P2Fde+BMlxrdhqtrcvCypFHbuy7l/4FXyheXyfMiQ43P/49/tV/Qt+2Z+yzoP7SWgzeIfCv2W+tNY01kuI7ODzPssi/N53+zX8/nxu8G6l8OfilrngO8hk83Tb9leSbcrMtemksRHnid2V4ypH91Pc5TUZE3M8219vy/L/FWLqChV8x/My33v8AarTvbibkbNyfd3L/AA1lyrhSmGf+63+zXRT5uU6qkjn9QYKxm8liW+X5W2/LWLfKjN8/Cr81bl4vms6Qp83+9WPfRPJuf73y130pRPNqGPfTfP8Acb+6q1U8vbtd/lXf92rtwvyrlmX/AGarTJD8rp83+9W0eaRzczKskO5h5gbDVZtU8tvk+6v3KZt2bn2Z/wBn+7U0LOXZN9WLl6Fyz+7v35/h+avsj/gmGyPovjBkP/LzZcDp92avjm1jk2qn8K19kf8ABMdI00TxcIhwJ7Ef+OzV+l+Eji+P8I12qf8ApuZ9LwcpLiClf+9/6Szxv44s3/C+fF5EPK6/dbW/7aGqGns6qif886s/H+WcfHbxa0UmB/wkF0u3b/00NZGn3yXGCm4fJ/FXxHEH/I8xX/Xyf/pTPHx+uOq/4pfmzrtLkdoVd3+Va27W8+yyfu3/AN+uUsZH2BEfaF+9/tVs2N07ZhdFcf71eNLm2OWXwnV6XdQqvCfIy7d2+tKG8fzB5Kb1ZPlVv4a5iGT91shdV3Vdt2vFhCb9rf8Ajy1XwmXxHTR61CsZs3hZ/wC/8+1agm1SGNnbyWwq/dX5lrIa48vZ94nbtdart+5ZpoXkBVPu/wB6iMfcHzGhdX22AQ71+6v3k3VlaheOtw6QzRpudmVf4abdXTy/vn3bvvI396su4kmVnhmdWXZ/49RGMio7heTTrGqPc7T/ALPzVUa7dWaZPnLbqb5kM0n+sbCoy/8AAqptM+0JBN838W2lKJ00+5JJM8a+S7/e/u0yS4RZhGjt9z5t1R3E3mbXeZS/8H96qF9Ik3yb9yt/drnlHlPWwuI5eWJZuLh4V2O6urfMm6su8uklk2O6pu/i/houpkUh9i7l/h31VuJvMjZHRVC/3fu1j73xHvwxEZadi5Nbo3+rT5qrbXmZU2ba0riPy/n8n738K1Tkh2x+ciYdfmTdXHKXuHoUcKRLC+fkTcf7q1YXzpY/v4Zf4lpLdUKs7zbdv91alt4/l+Tayqm/a3y1zSly7Hs4fB80S3Z2z3A2I8ibvmrX0+ZNrQyblDPs3f3ao2qutuod1X5PurV2zhhkhXem3/Zaufmi37xljMHyrSJqaeP9IML7WRfm8tW+9W1DJbKqzJbbX+6/92sfTVmhjCTOvzVoWbIkj/JsXZ8m35qrlifNzjOmX7KZJJDbGHZu/wCea1q2N15WbaRlVN21Gk+8tYcM/wBnZ/ulf4drfNVyO3+Xfv2fP/e/irpo6SvI4pbnR299t/chN/ly/djqW6vNqy3ifJt/hj+ZvmrLsYX2k+czbf7v8VW7dnbdsRvlf72+vUo8nKcMoz+0RXM1tIrWzOz/AD/7rVRvgkn+pHzbtyRr8q1oXFucfaHTc0b7kVfm8yodQt3muEfYqrvX5VrsjU9y5lKMpFLznY5k2o3+9/FRDZodsiPs2/Kq1O1vtma58lnDfNupLO2SH9y77X+8rUpS7mPxTJJIXjZYZm2FkXZtp7W/lje6+Vu+XbJ/ep63DzBt6Nt/8eq59nSRU/fLcMyb9rP93/ergxFblOmjHmKMNrhgltJ5X+0q1oaesKqXv3+dn27v9qkjtXa8TyUZj/Gqv8talrazKx3zcyP+6XbXzmIqTlLlPoMHT5YXJLOxZVR32vKz79s1XLhZl3P5Kuy/c8v+GkjtrlVhh87zNv3/AJfu1dsrW8Wz+fn+8u3btrglKX2T1Kclze8UIYX8wu9srq3DU6OFIz51yW3fdVf4anhhMU3k23Lsm5FZ6uRab51u+xPKRn3Nu+83+7V0qcakia1b2cNSnZx3MkiTO6rF91l/iWrccKXLNCkOxlZvmVfvf71XrO1MkgeF1CRrtlWRPmarENvNubY8bLs/ufMtelTw84zseXWxEOTmMy4t7mG3CImGj+/u+ZdtWdPtfOVEfllbc+1NrVpLaz/Pv3bWVfKbZ8tW7bR3um8+2sPNaZP3sm/bXU8L/Mcf1rrEz1t7lmlS2dY0WXft3/Kq1Yj02/aPi2Zoo3+Rv9nburetdGe7tfscPG2Jdv8Ae/3a118NzW9uiJDgMv3mTcy10rCx3UTP61zfEcBdabNMr7E+WP5Xj+4y/wDxVZF9oqTXSzpCoZom/dt/DXp83hu2b906R/KnzeX96sy80FJC7JCqhXX5m+X71bxw5vTrcsOWR5y2mzMy/aYY0K/N5i/NUUmkvdeTIj4ffvZV/vV1114fvGjZJoMxfNvWP7zVD/YvlKHeFT8m1Y2rojT5ZaGsbSicRq2nu6+Xv4+6396sa6861j3wwr8r/vVau11bRbmS4T7Sm35Pmkj/AIa53Ure2aR4Zk3Dcv3l+ZmrTl5hfDexzl5LDueb7m3/AJZ/e21TC2yzM803yfxsr/d+WtXWrBLWMu8yjdKq/L95qw5LidmNtZpjd8yNs3Lt/ipc3MYVI8xorsaYIjsFZdrtG3yrU00z2tqyfaWX5v3W5d1ZNjdTmRfnUnd86/3quLI6xs/ktuZvvbvu/wCzWEo9zm92MS3JebVjmdFEv3X/ANr/AOJq/b6xNCws0ucSL/D/AHv+BVhPqW7Y7puXfuZVT7v+zVmG8haNnRG+V9u3+Fa86pTjz6mkanWJuyXm23DzTfPJF97722j+0ZvLO9F3/wDPNX/9mrMa68pfLhTMSov3vm2rSLeTzSM6IrtJ99v4ainGZMpcppfbXklGdvy7t7L/AOg1oafNuhW5eb5f9p6xLG68xCmFT/gf3WrR0+JJvK+7v2ttX/ar0KK/vHl1pcpu2quskkl48ez5dm3/AHau6XG/nM7w5C/J833Y/wDarGt5vLjCefnd9+P+Ld/erZtd8yGZ5mf51X5U27q9bDxPHxEoy3Oo03YzJHv+ZvlTd8tdXo9wlrIiQzf6xPvN8tcdpPlyXaQyP86/LFu/irT0++QYSdI9u/b83zV6cY+4eLWlKMrnouj37rbiaN9u35dzfxV2Wg380avc78JJt/h3f8Bry/Q9WT7Lvk8tRG6q/wDe/wC+a6rRdcghZ03yBWT55FolH3bGdryuegw608d1Eny7V++v/s1aS61CqjY8czfe8vd96uBsfEFndMLO5eRmWJmiZU+X/gVW7XUkaNN77GX5JdtctSX2Tto05HXf2h5cfkzSMvy/dWsy8uIbiEJsYtH96NX+as2TVkjjE1s7Mv3dzJ8tZ0+sQrIEbdvkTf5zfw/7VcVSod9OmbGpXUMLI77vlTdtVKwtW1iaTNtC+xN/3o1+Vay7jXZpF3vcs6qzeU3/AMVWbfeIPJhR0fcy/Knzbf8AvquWpUlE6o0eYtahrX2iF7VHxu3K3y/Nu/vVzOua1D5Zs/lYfd/2vlX71VtW1vddPC8yp/F81cfr2pI29IZo3Kv+9/e/NWHtDo9jIta14ihWPyd8m7duf/arivEHiqVXKbIx/wBNN/3v9ml8QagmnxqNjZ2fIrP8u6uO1rWAzfJtHyfNTlIcYjda8YXOZUR2H8Kt/E1cdr3ip2kaaa5+Zf7r7ttO8Qaoke3ekn8W9t/y1y958zPs+7s+b+LdWVOMzb4S3ceKImUpC7Nul3fvP/Zav6Lqj3F0yXKZMf8ADJXISfNdrP5Ku0L7U3fwrXQaHbzRKibFI3bt0iV1RlEiVPm949O8L3k0cKPC/wA33vu16R4U1KZduz5nbbvVq8r8KiZZIUd2zJ8z7Ur0jw3Hc28bTeWo2/KrM/8ArN1dlGXu2OGpH7R674dmSFrdneMBvlVY5Vb/AIFXW6XeJHvR037Zf4mrz3QVtljt9luuN/3V+Vt1dp4daOZY5k/1v8a13xlM46kTvdHuoZreF3Rv7rqvzNXXaTcJGqpvYM3/AH1XCaLNDNGsPmqpX5k3LXXaTcbriJ3hzt/ih/vV2xqezOCpGUjtNNvE8scrC2zajf8APTbVyONI/kn2rLI+7zP4masTSdSht08mZ94bcyf3l/3lq1Lqt40f7mbeWTc25fmrpj7sOZHH74/WJvs8yedNsKtu3fxf7VcTrmqItw8PnL5bSt8zfMzVta1qmGXzHzJH81cXrWqTJIzPZttVfvL/AAtWMvjNo+6c54hvIZP3MMPl+XKqtJt+9XJatcfbJEuRMrLs2qy/e21taxdPfTGZ/kXft3Mtc1qVxMzN8i+XIjN5jP8Adb+7XHU5JTO2n2MbVr52bY7yM8aqu1fu/wDAa5nWozHvvJkjLx/8tPvV019F82+a5j3yfLE33Wrm9ctxGyXNy67pEZUrmqHXF9DndSt0S1R3hUL/AHvvN/u1z2sRJ8kyQs8jN/C/ytXRag32qGTziqDavzR/3v7u2sbWP3jh04/iVvuqteVW907aPvSOZuLVJ2aH7N80f3mVflqC1hSOQ+T97/vqrs2+aR32Kqf3qbHC8bZdG2fdZv8AZrzZR9/mZ6NOXL7pk31qFtWm+bc38VV4LfyYUR4WIV/4q3LiNI1MKfN/EjVRukSZVd/LzGrLt/u1pGfKaS94qx/vF+dI12tU9nZ+XcbyisG/hb5lqPynj2TTQ7W+9t/vVoWdxvuE+SNUV9v+1upSlM1pxhyly3X5XhSFi396rstm7f6Sj8LtVlk2t/47VbT1eZWTzm++zfvE/hq5GyXqh3fbIyfwp96lGnLm90rm9wRo/Kk+eFnT5v8Aap8dok0iTBGYr/Du+apPs0wRHe1ZQ3/LRn+ZlqXdNMweF1C7m+VV+Zlol7r90IxnL4ih5L+Z/pNtIyt825vvLXrvhg7/AIVAlA2dPn+XGB/HxXmVxZv9oZ38wL/H/srXp/hoxv8AC0eW+VNhPhiev3+a/a/BF3zrMH/1C1P/AEqB9BwtGSxNW/8AI/zR5JeXDrC0Lp86/cVm3Mq1k6k3nW7F33q33m/vVueTsmfzoWH95f4mrH1SHdI8UPyD+7/er8MrS5fhPFp+9E5vVDcyRtDE+WV/urL8rVl3X2xd801sqL951jfdWnqln5Nw8rxsDGu35azLizDM1y82Pl2uq/LUxl3kWZepSBlaHZGv8O3/AGapyRurbN+4MtackKXUap8qL93d/s1Wmsfs8LoX37fubkrSnWjEzqYfmlzIxNSbdCkKeXjZ8se3/a+9WdeL5jNCm3O/5619SjdV3w/7K7WrJuFmhjlTO12fdu/2a9CnKMYHn1qfNMxLxbaOTf53z/x/JWPqEzw5SFPm/jZq2L6ZIyZvl/4F95qxNTkhaY/J/vV2UzjqR98heaCFv3jyFmq/aXF1JLvd9p+7t2VlyfNIzoy/7tW9PjdptiO2KuUeYuJ0mnzHycI+5lT5Grb0ubzI96PJu+981YWhxmRm2bd38O6un0bT5mj2TPgM/wB5a5alPlPVo/Cauj28O3f97b83+Vrct7e8upopkZvKZP3X7rbVPS7SH/Voiq38Lfdrf0mHyz88zRj7qL97bXHL+8ejTjL3RbWBJGELuxVX+fctbHhvw7DqmqfY4bbzXZf3q7/4f71JbWMy5Tdnbt+XZ/FXT+EdFe41iJEh3Sfwbf4d1Y+zjLQ3qRlGHMfS37Enwj0Oz14eM9bh85LNldI9m7cyr8tfpL+yP4BufDN5e/GbxJNavqWpP/oG394/l7flZl/hWvlj/gnX8HbnWNF0rw09neL9uumkv5JIv9XH/F8392vv/wATa54Y+DfhWbUrDR45/wCz7fytIs2TatxI3yx7qcvd91nwGMrSrYiR0Pw70ebWlvr/AOKmq6fqEzStLbxzWv8Ax6x/eXd/8VXIftS/tQfDX4e6Omm6V42stUmk2/Z45tO85V/veWy/+hV5n4r+L3xRm8L33hKw8KxWmpas0b65q00v3o2X/UxrXkPxK+HusapHN4qubKTVbyx05lSOR1RI1/8AQVWvOlKvKMuTQdKjScrSPG/2kP8Agol8VLPUH1+58VedbWNwy6No9qu6RWb/AJaMzfNXz54u/ay8Q+Jr+2+Inxgvbq5VZd0VjfXTMsn+ztZvu/7tQ/GzWNW/4SLUbDwveQski+VdXEMW5d38Sxs1eBeM9D1LxV4kgbUryS4trOJVt45v4m/3a5rU49fePXoYWUtIns+vftYfG/8Aao8Zab4Amv7qz8P28X2eK3ht12WNr/0zX7qs395q9T+PH7V/iT4Z+BbX4Cfs06xNpkaxQrex28Stc3ky/wCsmnn/ALv+zXgvge11D4feH4vCvh7y01LUtz3V591o4/4VovNDTTbP+xNH3TXV1K0t/fbtzM275VVqa5doy9fM0+q81W3Kc98RPEHxO+IHh2X4XaU9xHp91debr1xZu32nWJm/56t95o1+7tr0H4U/AfwN+zX4a0bx5+0Civb3l15uk+G43XzLpY/m+b+7H/tV3/h3xh4V/Zt+C8/ja80HRbTV1WP7Leax8z3E38McC/xf7VfFXxe+J3xR+P8A4uk8f/EjxldaxeTK0Vv/AMsoo4/+ecca/Kq1sqsFpCI44OrWn/dieu/Hb9u74kfFTXNZv9S1jTRbSW7W+jeF9Li2abp8O75dyr/rG21826hq2q+JtS+3+M9Vjd1+XzFT5Y1/uqv8K1u6L8O9Vb/Q0tlQSfNt2bdtaVj8EdVa68l0Z/n+6q0pVoSleTO2GVy25R/gzQ5ry1TUvD3i23dFXakPlfxV6p8J5viXBrEF54P1JtL1K1iZPOsZWXzG/hZv7tP+CP7Ob3l5aXOpWEkcLSruXft+X/dr9FfgD+yn4G/4R2K5vbONE2b/AN4iqzf7Tf7NeNi8RQcowZ6uDyOpKLkeAfCv4O+KviN+5+IUP9pX/wB77ZNLvdmb7y/7tfYHwp+BNnb+GYba5T7yfJHs+VlX5fu/3a6/4f8Awj0Twz4ia80rSo1ibb8qrXunh2x0m3+z6VNo8Jjj+XcsW1trf7VcVSpGU79D06eUQoxPmfxZ8Bb/AFazazttE+Vf4lT5f++a8g8ffCubwixe80yaVWl2I0cFfpBP4Y0ewgFzCAu5e1ea/GL4F+HviJor2cNv5LK7O3lv8zf8CrGpGMpB/Z/NGXKflj468B39ncfbNNtmeLeqt5zfNt3V9KfsE2/wv1jxNFZ+LfFrWbzbV+ztFv2rVX9oT4G3Pgu6EMMMjKu5/lTctaf7DdroM3xOsdH1m2hilupVW3kaL5pv9n/ZruwVb3vZ3PkMywfs+Zo+if2lLPxV8DdJj+IXwcmmitI4JEvNNhfZHeRt95vmr8qf+CvGg+FfjBryfF3RPD1vomqrp0fn2tvFt+1L/e3f3q/bv9qf9m7V/G/wb8iC8UfYV8+KaNs7o9v3Wr8av+ClHgebSfhfqXid9sU1jdLFLHMnzMv+zX0sYzjKMo6RPm8NU5a/LL4j8zVjdt6O7M+7a+6qklvMYTCXx5f92ta4ZJG/hDt/DUE0aLJwinb99q9mnKHIezUj7hzlxZ+Xu2Jjb/Ft+9WJfWrs+xONtdlcQ+c2zYuW/vf3ax9S03y8v5PLfwrW1OWvMjllT7HH38e19rj+CqfkeYT8nH96uhvNJSSQfuV+Ws64i2syZ+St4ynI5pR5TJj2LtTvTo4/LX/aX+JaszQ/x7NrbvvU37Om75+q10c5lGJLbq/y73bc1fY//BMbaNF8YKvQXNkB/wB8zV8bQt82w8/JX2L/AMEv33aN4xX+7c2P/oM9fpPhD/yX2E9Kn/puZ9Pwhb/WClb+9/6SzxD493Aj+P3i9C/3vEV1/wCjGrF09naQINwMjfeWtH9oVGPx+8YTRnD/APCSXSgev7w1kafN5TK7v91K+Lz6PNnmK/6+T/8ASmeNj/8Afqv+KX5s6bT1haQp823+Kt+1kSONETajb/kZfvVy2nq82x/OZT97atbFjdPGzP1Lf+PV5HwnD9g6Ozut032VIWwv+z81aEM0LQvMiYP3dsnytWTZt5cio+7fH99av28kPyud25n3f71HxESNC1j8tV3ncWTdu/8AiqWRZvLdJXw33kqKO587emViZXX93t/honk/dGFH3Ns+dmetYx+0Z/EUbyJ1489lVk2/L/DWZdKnlSwujP8AJ8jbttad5saQu+7d/wAtdtUrqH5vkTKf3v4qv7IRlyyMeSRPMZJht/hqtLD8xCblX+LdWlcQ7mCJHtZaoTske95tq/N/31WMoyN6ZWX5mWHzNoX7lMmCRt5Lv833ljalVngLJ5e4b/u1FJJuY5T+L5maolTOyjU9n7xnXkj/ADb/AJfk3fcqqZLZmKPuP8NT3gPlnejZZ93zNVC4k6h//wBqo5fsnpxxR1t0s32hdibW3/PVObZHJG8yMx3fw1p31vMq733FlfaG21VuC7N8iM25Pk2vXzvtI/Cfq2Hw3LHUrR72kd3Rfm+5tqeGONYx5xwP9+o2VI8og2v/AAL/AHafbzP52/5nf7vy1lKUz0qdGMTSs98kgR4cf7X+zV+OFJFHmdPuturNhvI42Ub95b5fuVfhk8uTe+512fw1yS5+fmMsVR5ocpfhaSWEbE2hU/v1fjaGGPztjbf49397+7WP9pcf6S7/APfNTWtwm37TsyzP8ys23/gVddKMn8R8Rjqfs5SubMciK3yR/N/B8n3q1LW4e4jjhdJP3nzq2z5a56yukb/l5y2/atb1nM8McTzJ91tybq6eY8LlNWG83xqjv833XWN60LVYW274G8qNNzqz/wDfNY1jJ5jMlsiru+/JHVqOaRm86Z2Qqv8Ayz+bd/stXVRqSlHlM5Rj8Rfkmf5P3LbG+Z/nqOa+gZShhVWbdvbNU5tSmZfJmdRt+Xb/APE1C3zNs87/ALZtXTzGUo83vE8cjxsI9mE2fLTFZFkG/n+Fv7tV1mjm3XO1vufd+792kW+2qsyIy/xbZPu/NSqVOUiNPlNSxjtrj53fYW+by2qzGvnbhtVdr/Nu/irLhuoVkRPP3qqfM2/+L+Kr6yQzRo8j4Mfzf7VeXiKkpyR10aMYxNWys5p5k2DYnzfdT+KtfT7cxr99mEf9771Zul6gjZmmmaTc3y7n2t92r0OpQ7ljR1H99fvMv/Aq8upze15T1adSnGlozUt4/Lbzkl3M33/3vy028muYV8mD5k3Lv/iZqitby5bcmxhJNEy/Kn8NL5jySIHTZIq7Umaop0+Wr7x1+0pypE1pI67blEjzu+9/Cq1q2do91JjfvZn/AIv4VqlYr9skRFRokX5vLX5d1dDZw2ki/c/e/Lv8t9rV6eHw8fiieXiMVy+6vhGWel+djZD5e2X+H/lpVqHSfLkZJpmUL83l7Pu1fs9P+0Rl5hwvzbf7tX7WxxMk1tbZjkf72/7terRw549TERMr+ybmeEO4+99yt3TdJaG3jm+xyeVv2o0bbq0tN0dIVeF33orfe3bttb3h3wy9vDjZuDS/e37a7Y4ePVHDUrS5vdM/S/Du3DpMzpJLtX/Z/wB6ty10FZIVtnfy93+qb+81dFpvhm2jt4dj7/4nWtjTdF87L7IQ/wDyy2/N5dbSokrESi+U4G+8LpD5UyWuDu/1i1i6v4ZdrgwmHzV/iZkr1abQdtw6OnmFvv7m+WsjXvDfl3Ucy/IzL93+9RGjynYsV2PJbzQX8xvs1tC6Rqu5W3bo2rn77SXjtTNNbMu1/u/e3fNXst54deO3/c221vm83/pov+1XMXnhuFoTNs2ltzPHtp+yidtPEc0eU8t1rTYZpNidF3bmX+Ff4a4zxFpvkys78q3y/wC7XrWqeHbPyXfY0P8AdVkrhPFWmpGux32eS+2Ld/Eq1nKMTf2zPN9at90Z2bfvbtzLXM3E3+lCHZs2t8y766zxRDsk3wzyB/4P7tcTqy/uzIXXK/M7VzezFKpAat5FZtvSH54327l+bdTl1SZXaOZ/m/g3P95axmvodzJ53H/fPy1A2rJc3Hyfw/fas+XmOaVTlOjhv4fMVE+7/E1TQ6hNtZPlTd9/5q5i21xI92/c7b/4asrqUca/675GT52+9uWseWXNzEe05Ycp0P25I41tndgdm7ctPbUPld3nZlX52/hrnv7aST7j4f70Xy1F/bDyL9/e7fM+2qjTjLY5vbe4dZHqUNvb/aXdpEkdflVK0YdQeb5E8wbV+Zo/urXE2usIoEKPiL7y7v71XrPVHW5SF33pJ8rLv2100aPL8JwVq3N8J6DpmpfKHeRiV/2vu10VjqUO6H5/kb+GvP8ARryHy97vHvV/vb61rHWE875Jm3N8y7q9alGMYnmVJHcprE0cT73V12bYtv3t26tFdWhtYX2XMcrr9zan8W6uGi14WapYJu+X5t396rMeseWqJG+4M235n3NurrPMlGXNzHp2n+IHvMP5ytt++zfL/wCO1rWuvW3ls8c2GZtzq275WrzLS/ESSAOm7zV+X7v3a2LHXEkZN/Lxvv8AmespS+0a0T0yHXJmh8yHcNz7drfNu+WtK18Rw7j5k2122713/e/2ttedaTrjlgkMzKrf3m+7V2bXEhkd9m7bFt3N/FXFUqcvxHp06J3c3iTzGCJNJEy/61Wb5Vasq68RXNrI0M253/3vl21yS+JN0aJGkm2P/wBBqG41aZo2Tzo9iru2s/zMteXWrRiz06OHlI6S58UPt2fKfM+4v+zWLqHirdbyokKj5/lZvmauduNWma33u6na7M3zfw/3ao3F8F+dLlkVvvRtXDLEc0viPQjh5RldGjeapNcR+dC+0SPt3fe+7XPatqyW9vJM9s2z7ryR/eb/AHf9moWvJo7hntpsIu75Y/utWFrl5NIqQzOyDd8m1/8Ax2s+b+U3jR+1Ipa9rEzffm3/ADbd1cpqWrPLHLsRl/8AHt1a2rSPcfOiYCvXPX3nW+XeXfu+Zo1raMuaVmYex5feMrULj7VGEd2dv7tZsOm3EjPsdW/2v7v+zWncbJpMbNu35vvfep9rbu0Ox0Yru+8qfeq/acsAjT98y4dLdpD2f/Zra0HSpmkZPmc/dqW1052ydijd/eWtvT9Ptlii2Q/7O5qKdaHOaVMOb/hez3NsRGRliVdv96vRNBt3t7XZvjCQ/MrRp91q4zwzp6Mo8yRt7ffk3/xV3Ogwo21E+4vy7lf5t1ejRkeZWp8sDtvDawtGkP29V3fPuZK7DR1NncQon3WT+FK4zQXht49gfcuz7y/xba6izuiY1+eRFb5ty/w/8Br0KcpcpwVKZ22kXyBURPLDN/D/ABV0mj6lA8Y2PIjfw/Pt3V5/pGrQTW4m2fJ83zNF826tvS9WSNUtYUZvL+4y/wAK12wjzHnVNj0W1vHtWzH+6E3y7l/hantq3kLLcw3MKvH8v+181crb6wkioUuZGDfws392pV1xPM+e5XbJ821q7Y/AcHL73umjq14j25R9v/Af4q5TWLqG2Evzq/mfN5dXLq9+0K009zkLuZmZ/l//AGa5jXNWRpPO2xoPK/iXc26spbGsYyMrUJ3ib59qjd8sa7vu1g6jJ/f8v5mZ5Vq/qF9ukWFJmf5/vb/u/wC9WPcfZlXfNI0Uyvt8xW+9XFU/vHZGU+XQyNQkkmZZrx2wsX3o2/1bVzusalDJHveZvlTZLuRl+atfWr547zZczK+35fMjb5V/u7q5DxJrDx24hL+aVRv3LP8Ad3Vyeh00utyvPKjRyeQ+Nv3Gb7u6sDVr6FpCJpmRm+VFX5lam3msbm2b5HX7zsq7ttZ91qEM87Rl4xt/irzcRKNP4juo8nwiRzTSMyJB5qKvz7vl+Wp5QmwP8qfxbV+7WbHcI8jb3UK38P8AtVpWrJNMEd9+2LbtV/lX/arzanve8ehGMRNqSfuYfmfZVL940Zd4413P8u1dzbaszSQsk32aRnSN/wCH5d1QNHDGxzcL/Ez7fvVnT68x0R94bH5LQna+9F/vL96kjtnWQedDIis27dJ/DVnTbVGZs/L/AL1TxokNx8j4WT7+7/lo1axlLm0NuXmhqTWipDYv5KM6K2591TWcabtjvsVl3J5a/wDjtR28e6HZ1Zf4d/y1citYWVIX+RVT5tv3qPacoRpyY638ldPjtkdS33vLkb5ttTx/vLxIUs8Nt2+Yrfw0yzW2tvnmRVZf+eifeVqsx+Yqw/Zk2+Z8vnVEZfFYrl+0QTNDHux5m/7v+y1el+HUB+FuxYgAbCfCYx/frzq4t/MYeSGD/e+V/lb/AGq9I8PxhPhlsxtH2CbjrjO6v2vwOd86zD/sFqf+lQPe4a5vrdb/AAP80eWR2vlxpZzP/H/F8u2s3WIdrfOi5/8AZa1mb5lm/eNKv3tq7lZf9qsy+t5Y5d/zMi/L93atfhk583MmeRRjGPunL6lp7x7k+VfMbbub5ttZs1ukzHY+1f8Ano33d1dHq1nHH1T/AHKz5rWHzGjtoWXd/Cv96uf2sY6nZHDykYclrtVke2Xa33938VUbousghd9jN9xa2ZmtlkXEPmfwsv8AEv8AvVj6lLbRx74XYFfmT+KroztU+EmVHliZOpLDIz/ufnXn5f4a57UXdZHQn5V+bbW9qU3y70K7m+bcv/s1c9q9wNr84Zk+Vm+7Xq4fY4K1M5+88xpN7purJuGZdybPvfxN/DWlqCOqPMj71X+Hf/FWZdM8e55h95K9Sn72h49Sn7xXX95cDL42/L/wGtXSYx5gOxvl+XbWbD500ibEUsv39tdFo9pj6Sf7FdPL7gUYzlI3NJsfM5+6yt86766rQ9NS4w/k5VWxtasXR7GGVfn/AIm2o1dloenooZ0C72XbXJU7M9mjTlze8WtLsEkZ9k0Y+fau7+9XUabo728afJ95Nybl3baqeHbcQqj3McbBfl3NXV2FmkjPJDcq4Xb96uOpGXxHq06dKUYpEOk6X5ylILZstF95f71emfAXwimreLre21W5YLuXfcfd2rXKabZfZ7h3jmZG+4vyfLur3b9kP4U63488VWc3h7TY79VlXzY2bb827/x6lHlcRY6MY4WTP1u/ZK+FOm/DP4Z6LDbbrq81KwVrJZF+6rfM25q1vGEj+OvHiTWFst5pfhtdlrb26/Leag38Un+zHXGfAP41eJ9e8SS/DeGzaKbSdNaJmX/l3Xbtbb/tNX0V8K/CPhfS/DMNhYRR+YsrS3En3mZvvM1cMv3kryPzapzJyPOND/Zr1KGFdV8SXLXVxskuNXmb/VLIzfLHHu/hWvnX9rjwb4vvvM+HulJbvaK6tcafp6N5cO5vl86Rf9Yzf3fu19SftCfFC+1vTIPA/gIXn2mSfY5tU+VV+7ub+81eaftlfEzwv+zP8K7fTdHS1PiprJVih3+Z9jkZW3TMv8Un93+7UuVKNKXY68LRk6sbbn5i/Gj4av4T1ObR9YS3udXbd5sMO1fssf8AtKvyq3+zXg+gfC3VY9Yge53QrJP/AKU0nzMq/wCzX0BY69rGrLI+sbUnvLhpJ2kXczbv9qsK6h+2X0eiWz7ZvN3TyMn3f92vmamKjf4T7/C5VOlh+aRw3iLwe+patPqttZRwQw7Yk/vNHt+Zqy4/Elh4Z1LzrnSrd0t/me3k+Xc235a9Pvo7DQfDGuGaFmnjt22M38Tf3Vrx3VtB8YeMNHm1u20qOB5k/wBW0u5qKdT23vIwo4flZ4r8ZvE/xI+Nnj648YeJ5ldY38rTbVflgs41/hjX+Hd/E1ZOk+DfEcbxubbaFf8AiT5a9T0P4J+P7qF5byzjTyZdreZL91q6qx/Z0+JbWsVzYaUt5u3b1t7jdt2/w12VqyjGNmdeFwspu7OS8A+A9Y3R6k9hJcS7/kWNl+b/AHq7nxNZ2ek2qasmiTQyKu6Xcn3f+BVZ8N+EfiLoOqeTdeErqFI0/wBX5W7/AL5rtvFmueHpPC+zXka3favm29wu3buryK9aPMe9Rw0eXmRjfDvx/olnshunVE3q21v/AGWvvb9lXXE8SWdto9nIyJIqq8lxtb5f4a+Crz4d+Etb0m21XR7xVbfuT7P91v8Adr65/Yt16aOxSO1n3vHt/wBcm1v92uLESheMkejh4ycHBo+0ZdP8K+FbX+1tYufnX5XZV3eZVvwT4i0r4heJjo+m20zJDtVty7f92l15/wC3PBdnc6rNa/uUVpdrbWZqT4O3GiaP4gj1j+1rWPajOkbS/wANdcKlKP8AhPPrRnGlJxjqe4W/wlbULBJgm0bflWue8Y/DK+0O3juAjKD8r7a73wF4+s9ejCJqNuyBtqqtanjHyrq0XO1l/ir2ZYfAV8LzwPi6ea5nhsdyTPi79pb4dvq2gyv9m+aGJmST/wCKr5n+Bf8AYnh/4sWb6x+7aO82xTL/AAtur9AvGXhWw8WCWxvIcbd33fvV4P4T/ZB0q18YX0NzDcT2011vguNu3y23fKteVhYxjV0OnPeWpSjM+x5YLZvhqNE169WeK5sNsdwv3WXbX4x/8FY/hzo+tf8ACTaDePNHpWl6XNcJJGzfvLr70Kt/s1+vXg+K6+Hvga58H+LTJdRQt5dq6/Mvl7a/O7/gsN8LZ7z4J+J/EPhW5ke3jtfPfy23P975vlr6aMvejA+AnKPt7n4GrcGTyxc7fOZdsrf7VM2J5flvt37/AOGtW+0/7LuhdMP8zfd+bduqs2mtIV2bhEzfPuT5q9eMoQ91nurmqQMy48mdtnl7f93+Gsy6skWOR0RifvJ89b0lqnmL5e1f9plqrdWqFmR3VQ3/AC02U4ygOVPl3ObmtfOV1dFx/svWVqGmw2+R975/4v7tdXNpvkwtDs+Zl+8q1mXGmzLG2+Fm+fbW1OpKWpyVI/ZOXuLeCNy/k/xfdqpcRw7nfZW9dafubY7/AHfl21m3MCRs2/cq11xlzHNyozWj+benT+OvsL/gl1uOi+MmOMG5sduP92evkSZE3b0Rifu7a+uv+CXAxo3jMbcf6VY/+gz1+n+EOvH+F9Kn/puZ9Fwj/wAj+l/29/6SzwP9oyZ/+GgvGK7sgeIrvj/tqaxNNuPL2JN0krZ/aOwfj94yOSCviW6/9GGub0+R2XYzt/srXxmff8jzFf8AXyf/AKUzyMf/AL9V/wAUvzZ1Oj3SNuRHw38DfxVu29w6yLDs27vv1yelzG3l3p81b1nN5jK78bvvN/drxvfOTl5pnSWl4nl7HT5l+V/n+8taVjcfJsSFflf+KsG3mh2+WduWb5P9qtXS5nkYxv5itu+9VRlH4jGUZmxbt+73zR/IvyrJ/FUMlxM0jOkfH3tzJ95qYskm9Rsbfs/75pZLh/nhO5F3fw/N81aR96Bj8I6WaaSMom7aq/eVP/QqryxI20P/AMCqeN5mZk+Vxt3eX/E1OjXd8kPyVUZcxPL9ozJraG3XeifKz/w/xVnXUMO95Htox/drcvLdFtVfYo3LuTbWXdL8q7AzL96plI1jyGJcQozF0P8A31WddSeYp4kEMbrvb+9W7dW7qGfO0N83+zWPdW/mK/f/AHanm5jojLlMy8m3/P5mTsrIuroN877Xdf7v92tPUI0jU+TuG35X+Tbt/wBmsS+XbJshfaf71Ryx5jXmker3lr9nk3pueJfl3VmzW6TM2zaF/grcuLdFHnHcR8qbW/hqo1rDJH/CN391a+PlL7R/QcY83wmTHYuzLM77gv36lW1SSRnhhZSvzfLVo2b+cSnzfd+an+RNC0SeSzOzsrt/DWHtOY648kYFdWeFUR9uG/8AHqkt5nikOxNoX+9822nL5xjy6Kf8/epm5GzD/H/epx973ZHBipR5fdJ4bi5aP9zNHs2Ns/vNVuHZJbNbI7P/ABf7W2qEbfZ2xN827/x2prW+e0be78L/AMtP7td0fhsj4fMOXn9407WSGFfJRGb+H7ta+nq8kHzpn+78+2se1mfcr71/3lq5b6hN5j7JsCRNqMq/LWrj7uh4EvdmbemyJ8qbFRt3zMv8VTLNNJHI/nLuX+L/AJ6L/s1nW/7uz++2/ZuRtv3quBPLg8ya5/g+ZWStIS5dSOX7I+GRI4XSGNgmz7rPVeS4+ZPOYsd/yU6Tfuf7M6xFv4WqnL50kjuky7fK2vC1dPP9oxkWbjUElk8l32t/s/dWoFvILyQJsYfNtX978tVmbbI6Kioqr8zN/FTI7xN2+Ty97L8jfdWueUuccTY+1Jb/ALlJF/dv8isv3mq/p9x84+eNh/sp8y1z6373EiI6Kr7fmaN6sW00KyK6bi2zduauOfNy+Z0x930Or02b95++mX5f71acepTKzBEXfs3Purn9LbanD7y339yfdrUhZP8Alt137t1cXNzTvI6YxlGBuWt8hhUIJF3fL5i/w/7tWVmSaNfJRti/Ju8373+1WXayJH8+xTtXbEy7mbbV2Jk2Lvs2H8KfPt3V1UafNL3iKlSMYmxpLNMqTecrPHtX5vvfLXXaDbpMrv5Ledv+Xb/dauP01vmVEhVNz/Kyp8tdt4fXzpPIRGR2Vd/l17mFp+6eFiqkoysdDo+mvIzb3b5flZl+7XQ6TpO1o5tmxGXd/stVHQbXdbxecmGh/wCeb10liqM4f92rr8u1Xr1KcYx+E4alTlLuk6D8rPDtQSfNu2LXS6X4f+yyKfJWUtF8q7/u03w3Y+XGyPDH8q/LG33mrqNL02e4bzo4VRVXay10RjGJyc5FpOkww42Qq+77m193zfxVvQ+H08xPJtlZ9m6Jn+XbV7S4YYlR0h3SL/dX5m/vVqRqyjyfJkD+V/q2Sq5UHtOU5280VPtD749n975K5/XtP8m8EM3y+d823+9XeXGzy1eZGd9jb/7tcxrlrbQyhNjFNu7c33aj7ZpzcxyOqWaQ7vOudqeVv/2v92uW1eOGa4a88r5FT91I33v+BV2Wp2brIiJzDI/zyKtcv4gjdZzs3bpPlZm+78tLlluddOfLM4XXo0mh+SHarJ/F8u6vM/G0dtaxvNawqV835tteo641tcb3vHbEbN833a8o8YL/AKU6u6tu/h+6tTLk5Top1JnmnjCOb7P+7mjHz7vl+9trhtek3bofP2oqbv8Aers/FVwlx5mx/nVG3bfmrzHxRdP5hQPzXJyzqG0sRFR94yNU1b7+z7y/L8tZNxq0c0b3Jm2Nv27t1VtavX3702/7y1h3GpPu2O/3f71Vy/ynDWxHtInW22uBdohfa6/Nu/hqZta3N+7fb/7NXFQas67k3/K38TVet9Q8xvlm2bfm+ap9nAx9tI6ttY2YdH3Fko+2Jw6df49rVzK6kYlb+PbUi3ySS/I7f3qIx5ZGUqkpe6dPb3m2RpoX/eL8rbv4a0bfUtzJdO67l/4FXI2eqQtHu3/8C/2qu2epTSOux9n+y3y7q2jH3zM73T9akVkm+8v93bWo2tedHvFyzL937u3a1cTY6g4VUmf52+atG31abDJu2p/erqicnxHZ2/iF5sbPLYqvzM33VqVfESBm2ffX76/3f9quTh1CaPbDH/wGRfu1ajZPl+zTbG/iX+8ta+hh7M7bS9YmkiWGafcjLt2r8rf71bVnrT7kh3yP/F/eX/ZrhrGbzFV3vG37Nrs33VrbsY7xIUe2m83c6szMv8NcdSpynVRpx6Hc2erQx2/2lOX/AIlX5ttWl1yaSETfM/z7f97dXLWN1cw/8eyfeTczL97/AL5rQtdShjhDo+2H+Nm/vV5WIqcsbnsYWjzStymxeeIEjbyYd22Ph2/iqncaw9rHvebCyP8Adb+9WU155032lHXZuZdv96oWZJLN7ab5BG3ybf71ePWxHNE97D4X3jT/ALSe8z9pj2+X8sSr91v96oG1SaTb5235f73/ACz/APiqprdO0QdEXYr/AL1f9mmTXfmMsMPzLs+RtlcVOod0aMfsj5Lp7iGWZ3b5k2/LWFeN5jeT80W7+983zVozXFyI2tt6hG+4zfxVkXjfudm9lZvl3f7Nb06ntNEYVKMY7mdqW+H9z23t8rP91ayLqO5uPkSFmRf4f4mrQuriFoU3fvfn2/NVW4vljk8mGHyjt2tu/vV2c0oxujk5feM37DuZkRMNt2/MlW7PiH/x35aYs26Yp8su5fuq3zLUsLPb3C/Pt2/cqJT5dB06ZetVh3ryq/71aGn/ALuVd/3VrJ3PJIyTJ93/AMdrY0G8Ty/JfzpRHu3tIn3qIRlH3jWUfaaHUaDcJ5ao6MzK27cv3a6zQbyQTNInzO33F2/LXD6bcJGyI74Vfm/2q6Wx1J9ypvkEvy7GjZfu162Hqe8eVWp+7ynfaPJbfZ2dHZ9z7Uh83asf+1W7pupTRstz529lT7rfxVw2lal5kZmd2V12/u2Td/wGtnT7ry1KJMu35v8AZr0adQ8ypR5TsLXVPMs/9c0e19rrIv8AF/s1r2uqXkEYvLOZndfllVotqrXFQ6nthE/ys0fysrPu2/71Os9amaYyC55+VWZq9GnLuedWp8x6FD4lhgaJIXYFlZvlT71Nj8T/AGj9yjr+8f8Ah/iWuGbxI9q7wWz/AC/xs3/oK1HJ4shUqnnMiL9zbXbHklsefKMIzO3m1yFrf7TC7AfMPJ/2qwdY1wrCu/gs3+sV/mrm5vFO3c9n8vz7XaSX5VrMk8UwtDKlzMvnK21l/haoqR5dCffl7xs3esJIX2bnC7d395v9qsbWdYe32b3XzP8Alrtf5dtYN14qgt3e2S5jV2/h/irBvvEk1xGzb1VY1+dt1cdSPNLQ6acvdNnWvEENnHNM8ykxv/C33q4fxDrk0k0ib/l37kkb5t26q+teKkkDvNt3t8zMtcnrHiItN5KBdn3k+b5lrgqfynZHlkbtxrVtZw7/ALTvZv8Almv/ALLWVeat5jApt+Z6xJtS3SI/nZX+61Vprh3kZ4Xj/eN97dXBUj7T4jqjI6i3u8Ks29Szf3flq3a6lJH8+/Yfvbv7y1ydvqEyxKnk7vn+T5qnk1Sa2yjzbdq7vm+9urilT5Ye6ehTqR925uyaqk0b/eZmfa275flqS31NGXzkto/m/hX/ANmrn21iZtuyZU8z5k3U+HWHaSN0Ta6/e3PtVq55VJcvwndTlyy1OvtdQmkX54VTc/zMv3q0oLy2jkV0Tdt/4FXK2OuQ+YryXK7Gf/V7Pmq6usYjeTYqqv3W/vVEeaR1HQxyJ5kSIjH5fut/dq/tcXSbPubPu7/mVv71YdnqXmbd7rhU+dmq/Y6pDcXH2YoyMy/I237vy0hx97c1Ifs3lt5jxjci7Fk+arUMHkqIUdX2oyuuz7v+7WRbt5eyH5Svyt8y7q1GZII9jo21fmb5/l/2adT3fhJjT5viGyabCuy5+YfPu2s9ej6AGT4akO4bFlP8wHXl686mmS6YpDuRFT978/3a9G8PRmP4bCNn2EWU3zD+H738q/a/A6bedZhf/oFqf+lQPo+HKThiattuR/mjzMxww2ryeTMrN/DUN1H50ex3b5fl3L8ys1XZLia8t4kTcwVdvmN8u3/aqhdM/l+RDuVF+ZGV/wDvqv59qVpVDmo4eFMxL63eRv30zBI/l2r81ZV3G8dw/G7y/wDVbf8A2auhmjSGR7v767dvy/xVg6pbTNDvcKCzLuX/AGv4amNSPNytnpU8PzR+E57ULiVpG+RYgrsrN/s1iXk3kuFd1y38X8NdBqNu+2RCnz7sfN/DXO6pGjcPtTb8u7+9XfRlEKmEjuYmsXDyKbeHais/zsz/AHqxNQ3sp3uuV+Xd/DWtqkfyKUm4VtqN/drFvmi2jf8AM/3Xb+GvUo+8eTisHLm90x71tqt5Nt8i/K7R1m3ioU/2v4a1Zmdd+zbsZfu1lzInmb3/AIW+7XqU4njVcHyyE02HazeTtb5/u11Gg27tlHeRtqfJ8n3VrG0+F4nDui/c+bbXU+H7fdGzvMxGz+5XVGXvExwvvm7o1v5Koj/OW+589dvoduk0LPs27fvqtc34ft5gqOm0bf4tldvodq7bOF3f7X/oVRWl7vMethaMZGrpdhbeXGnaSLdtZPmWun0nS5oWbeiqJk/1n/stZWiqjXCQ2z/Oy7Xb73y11Oh2VzGzpM7OVddjL/drhlzSPSw+Hjct2tn5cn2beu3dt8tX+Xd/vV9A/sg+IpPBPjCwv4YftU32jbFH91Y/9qvErK1s7gpNbQ5Lf3v/AEKvU/2fY9SXxdbPYbXXzVXc0TbVbctZVPdIzTD82Dkj9UPhb4f8K+A/BOr+P9Kud2qas8lxdXDRbVVW/hX+81dp4W8Za94f8Kvq/wBsbdJaqkULL821l+Zq8+0rxtrGj+C49N8SQ27XF49vE7bf3axt97av92qnib4gWzalcaPol/G6R3HleTC3zR/LXm1KnN7p+Zxp/vfeK/iD46P4D1aPUtEg8/WFuvN+2TS/u7eNV/55/wATV8RftLftA+IfiVql/wCNpr+adpNSkuPMkb/Wfw/NXrfxz1y8s7/WrmbaIbO1ZUXzf9Y235trV8m/EC8/taOysIYmjT/WxKv3dteZi4Q155H0WT041KsTJh1vxPfTPcpcyFW+Z1Z/u7v4Vrfsbi5Wa33wrujRv3itVLw/Y+Zbx22z5P8AZT5lrtPA/gua41KG2s7NZY2fc3mfe/4DXzlTEUuX3T9Fp058nvGF4ivtV1ZTYWGlSNbzNueSH5mrn1+Cfxa8SWKXL6lHo9lv+S6vFZfOX+Kvqe88E/C74b+BZviR8QtTjsbGxTfLH95rhv4Y468d8YfGLxb8WNNi8W63pVn4c8G287JYfal23N5H/u1vl+IpRjKLPPxWFlTfMtDw/wAVfDHTdDhTSrP4/XE100StKrRMqszN/wCg/wC1UvgnwX480WZI/DHxRsZEkb5FuL1o2Zv91mrK8dfED4Pw3kzw6VCgVtssi3DeZIv/ALLWDfeOPhXqlu6aR5ltNIny/vd22niPZyj7pphZOnLnke9Wev8AxR8M3STeJPDbXMcLqzSWvzbl/ibdW/q2peG/iF4Ru5nsLO4h3Ku26i2yx/8AfVeM/CX49X+k3iaVN4umu2hiVU+1bV/75r0Tw78YvB+rR3OiaxZQzxzS7kuF+Vl/vV5EuenP3T6KjUo1qRt+H/hn4Y/sWGawS4tfLf8AdLDtkRmr0j4f6TqXw71C21Kw1u4htm2rtWL5mZmrmNB0XwfcWkL+FdSurdJG/wBSs+75v4vl/u133ibxI+j+HdNsrnxDH5TXmyJVt/m+7/eqJS5pe8VGPs5H0R4T8RaDqnh1LbU7m6kuIVVYlkl/9Crs/h7oqX2oRzL9lCTPuX5l3Kv+1Xgnw50PStWtFv57+a4juIt3+tZdzV7f+zvofh24m87zt6Lu3NcS/M1VCM5T5UKtyRpSPpTwCulWumo14kburfu/n21va9rN3b2EjWc21JP+en8NcXpzeDZzHZwTW6vH8rLHPUXiH+1LGxl/sLU/MZdxSO4fcrf7Ne1KoqMOU+Lng4V8Xzv8SbS9VFzqkqxPld+167f4aWNtqGp3KXNvG6KnyqrfxV5HpWpXKyGa8mjhmX5pVr0v4ReJHW7CfKyzN8zLXHg8VGGIi5bcw8/wMlg3ym3400NLXSp7ZBny923d/Etfmz/wVA+I2n/C34d6lZ+IZpmsdeiazg8n5v8AWfLu/wCA/er9O/ia00OiPc20G9/KZdq/3dtfih/wWy+MP9vXkHwom01ZraGy3/ao22yLN5n3f++a+wVH967S0PzKNP2mIUT8tPE3h1NF1ibR7O586GJ9qXUn3pFrNm092KwyP89dVfaLtuij3O/y/m/vMv8As1VTS4VhV9nyr8u5V/hrr9ty+6fVUaMYwOWmtfL/ANGSFtzVRl0lNjJ8qjf8q118mj7ZGMyMyN8u7Z92qs2kl5CnkqqR/KlEanu2iP2PMchcQzQ/uUdSG+4rLVC8sX5eNNy/3WrrbrS3+1fP8rbN3l7Pu1l6lp8Z+4ny/eaumnU+E5JYeMeaTOJ1axRN2+FW/wBqsK4s8A7U+b/arttYsbYLsfbvZG3LXMahawqzp8wVf4v71dlORw1Iw6mDffd2Oiqf4WWvrP8A4Jehho3jLOcfabHbn/dnr5Ru49y79n3m27v4q+sP+CYMaxaT4zjXtdWX/oM9fqng+78f4T0qf+m5nt8Ke7n9Jf4v/SWfPn7SEu39oDxlC/3f+Eju2/8AIhrk7dkWVPn+9XW/tGr/AMX/APGZ+U/8VHdcf9tGrj7WRFk8z5T/AHK+OzyX/C5iv+vk/wD0pnjY6P8AttX/ABS/NnQafJuby3/hX7396tfTpN2Pk3L/ALX3a5eGTlXP3d+7733q2tNm8sId/wAyvury/fOXlOmt7j5n/fMh+9WrY3TsvnI6qW/hb+9XLw3Dqzl3+992tnT7h1Yfdx91V2VEveM5ROnhk85Vm2fw7W21L8kkPyJn/gf3ayLe8RlZ8MqL99quxzIy7IX2bl3bquMebYwlEsq0fmb5vl3fKn8NTKyeSsKbt0f3t3zbqq28k3k75Pnf7u5fmp8Mjsw/fcbNv+9/tVfKjD+6Pnt8Rp++VdqNs3fd/wB2sq7jcR7Plx975m+9WjeXkyv/AK5cL95WrMvl3Tb97Z/8dVaZZn3TJIwRE+RU/wC+qzrqNI5vItk+9/47WrqEh8z53+X/AGU+asm6fd9//Wt/tfw1MTaJja0tyu1PlZN/97c1c9qW9fuD5mf/AJaV0GoO8at/C/3vmT5WrA1SHG15H/4DUSiax2Pari186RoU+9/tf3qg2/u40d/+BKlaq2e64OxGI2feanSeTEvzp87fKrbP4q+Fl7x/QGDqc0DFa3RXXenzSfN5ar96mfZUmUeSkn+xWpbxzI3+kpG3/jzbabfWPlvvSHaqpuT+Go5oxNvaMxWt03vC+5N3/j1QSQvtVf4FbanzVpXlnub+L/gNVGXb9+Flb7zV0KVzkxlSHIVZLjbuR5MMzbWoWYxt5P2fcNv3mf5ahulhhbek25arxuVkd0dXX727+7/s120o8stT4zMKnMbtlcedMm+ZlVU+6v3a0obx5Lcwo+z/AGv4q5zTpH2h+7VrWbPtP2bbu/jZmreEYx1Z8/KU+c6TSbiZpGT5U/hRm/8AQquXH+sfzkZDsVU/76rCTVtqi2mSN9vyrtq9HqFzND52xVH3fv1EZT5tRSlzaF+ZYcv8izM33tq/d21R+yQzLK6blX7qbX+9RNqDxw/u3yGfbtVvu02PyZ1Z0fay/dp+/wDEEteUGWPc0m9i6/eWRf4qpNHbNvuX+dd/y/PuqzfM6yLNJNv3fxLUK2/ys/kqC38LfLSjKQL3vhK0d9tVoXRVZX3fMtaFnfIwZ3hVf4fMX+KqsduJ2Uum7cv3d33amk8yFRGj8fe2rRKMZe6VHnOj024eRf3KeYzJ/e21prcfZ1PkupZv4f4VrmNPuts0saQswVdz7v4a2bPY0aB5m2x/fb+Kud0ff1Or2nuWOhs7uGE+ciMq/d+WtNLtJFSzhRnK/Mm2sOxWa4+REUo0W5Pl+Zfmrd0+WzjiCJtfb8y7f4a6adLlncxnJVIWia+myTKrTTJzvVV2r92uv8M3lsu/fufcm3c1clpW+OL/AFO91Tckjfdaun8NyfaNs0yNEq/wqv3q9zC0z57Ec3OegaDM9zCNjxptbdKq/dauq0G1tm3XO9pIm+bbsVVWuF0uZLVY4fIWNGXcit8zbv4a67RrqZpbe58za33mXf8Aeb/dr0adP7RwSkejeH4/O8p0f7ybUX+9XZabawsEtk+QfK21V+9XE+H7jy1T54ztbc6xt8q13nh9vtEf77yzKyqrtH8zL/8AE1rGPLEn/CdBo9n5Nr5Lopdmb7v3dtW5l248ubLKn8TfNVeGa8tYV+fP+z95d1WZCjKX8jY2z96zJ96o5oyKjEqagqR7kd1y23Zt+61cz4gjS0j2XLspaXcvy/dauj1DZHH5z+Yd3zRR7fu1jaozRw/ImWaLd83zbaxlLlNIxOV1hUuml/crCm75FZf8/NXH68sMgEqc/e2fNXXa1CGuDC7+YN3mbo/vfd+WuN8QSQwq5d+d7SfMm3d/wKsuc3jznn3jC68uGaZ9vlbN21fvLXk/jpvMjaG2RVRdzRN/Ev8AwKvVPFU3mJvtodu5PnVfutXl3jC3hjjbZbMsvzebub5WqObqzX4fhPKvFKeTI6JuzIm5F2/erzDxRCity+CvzOuz7tekeKP3kjoiMpX5X3NXm3iCP/Xec+7bu2L/ABUub+Uzqe8cF4imdY5dm37/AN5a5ua4/fbH53J81dF4hWZf+WON392uUvF+zsfm3v8A3a2jyyOWUeUtW93tYo6ZVa0bebdH8j7f/Zq52GTdJ5KDFaNvePGqoNu3b/FWkokRkasF4jbod7K3+zUkd47Mdj/ef7y/3aoQ3Wfvj71WM7vuO3y7ay/xBzSNKxutuzyvm+Xa6slalnIkapM6K53/AHawre5RWWXeq7vlT+9WnYs8f39vzP8AIy1UdiZRN7TbjyFMexfu/wATVpWO+SPjcu59y7v4ax9PWFtvnD73yu1a9nN9onXzplfd8v8Ad+7R7QI0zTt5PM+ffkL/AA/3qvWtr50/nPwsf8Tf+y1Rs4xt2JuRa07ePZIg6IrfLTlW0kyo0zW09Zljih/5Zt8u7+KtuwaaFETep2/3X/8AQqx7P95H8j5WP5XVavxzMg8lHX5trLuavNqVvtHdRw/MblvqEy3SzB13r827ftq39qRd3nP5r/wL/drFVnXZNGy/3fl+ZqveZNMpeEL8rqqM38S15OKqHvYOjJF9Lj5Yk2bVb5tzJ/DTbiTbIkKbmf5m2qvy1VhZ23o42Ps+Vd9NW6muFD79zsu568mpyyqns048seUluZpo23w+WnmIvzbvlaqlxff6O80M+/dx9yo9QYMv8OGX7yp/FWfcaj5sapZwNt/ij3fd/wBqnTlt5DlHlkTtqj/wJhVX7zJVeSRHs9iOzbU+XdUdzsWZEh2/7W56q3kkyqzzI2FX5mX5q6Y8vN7phKPNEgmk2ugmfL/88/4apX0cM0ju7thf++d1TeT9oVXhmb5fmRv4qrXVi8dwqbGK/eZa6pc3wnHKn7pRk7TO7JtfY9WIZJlVkMzMq/Lu/vVNeWLzLv2bAv8ACyUn2eaPYibfv/3flo5eaMSffiTWMKK3yPv+fc6ru+b/AHq0bVbZvkR2iVf4W/vf71Z/lzW7s8PG75dy/dq3ayIbcJ50gl+ZtzfdpKXKXGJtaTqDr883+sVPl/4FW9p1x5OxJpm3Sf3U+bbXKW801ufkm+ZV3Ju/irSt9QS4eCZEkRP41V/vV3U5cxzSox+I7bS9XfSZUSZFZZHZfm/hrZXW9yqyXK5k/wBn+GvOYfESMwSdGYq/7rav3a0ofGEzf6HNMpVfuts+bdXo0ZHnYinGUTvl162WfZbTSEyf7P3qjbWHjjd5h8iy7dq/3a4638SJNImybDLu3Nt+VaZN4mRV/fTfLub5d33mr0acjyalM7bUNYeaPZZ367PvbVrNm8Qf6QzunyR7d9csviHTWmVH3Kjfek3f+y1BJ4ieJtqFZWm3N8v93+HdXRGpy7SOaWH5jevPEkPmTfvt25/733VrNv8AxNczKUebZ/FE2z/0KuevPEXzMjxxmWP+6/3qwtQ8SIv7nfIYv7q0qlaPQy+r8pval4qfZvR1DL8zrs+asjVPEUfktbQzKzb/AJ1j/hrmNQ8SbY9jupVW2uzVlXWseWrQo+3/AHXrmlUlzGscPy7Gtq3iCWNfJedt395U/wDHaw7jUNzMiTKq7/kXfuqpNqTyYTf8y/wtVSaZ4/nwu1nrlrSlI19lylxb658sskisW+b/AHqkjmfzN/nR/L8ybvu1kLeOkbTed8v+zUU2qOzDY/LcNtrm+L3S/hOguNSmZVm+X+79+j+0pto+dUaT+FqwZL4zL8/y7futUkdxN5i/6tv9pvvNXNKX2TpjLlNuPUnkkV5E+RV+epmuvNY7IcbV/ibdurGjvEkUQvDz/vbamt7r5UT7399t9YyjynoU6kZG3DqFyjJ8qsi/N5n/ALLWvp+qPt2bMf3JK5iNfm3puI+8vzVbsL7azb5m+b7sa/w1zSjJHZGR2djqD7t6TfKq/MqtXQaPO6wi6d/vRbdzfxVxWj6nuZUd8MrfJ8m6ug03UvO3Q/ZlO197/wANYylM2p0+Y6K1u/Lj+R2xG3ybvmatGO8fzF+T5Gfb83/oVY9ncJfND88cUknysv8Atf71X4ZPMZIXRW+f5v8AerHm5TaEZy+Iv+ZNuTftfy/vN/Fur0zw65f4Y+YV2E2Mxwe3368sfEjRI/yv/ufLXqnhlU/4Vqixn5TZTY/8er9s8C23nuY3/wCgSp/6VTPqMij+/m/7r/NHnt5H+5itn+5Ii7v7tZ8kMyzSp5KhI22r/d21qSWb3CnenCvuTb/6DULbPOh3w/Kr7Zdz1/PkqnN9o1o4X+6Y95buWNtC+xmTzfl+6y1i6hIixu6bR91nWN/vNXRX1u7M+xNyK21v9paytYVIdsH2Zl2oyp5f3v8Adp0/dPVp0/7pyGuRXMzffkVY2+Zvu/N/7NXO6sfLb7NMjJt/irq9Us90n2l3ztXYism5WrmdS86Ni820p/drvo8vxGv1X3DmL3ZIzIgVl3bflrJuo+S/3Ntb2rQpG2P4W+Xy1rKns3DSfuWAVflr2cPLljc4K2D5YnO3lmlwz7Jtzbty/wC7VWOw/wBKeR/+AVrzWe5m/c/w/dp32fy4N8m3/YbZXfGpKMeU8epg483NIi0+zSZvkTCr9/d/FXS6OszRjeioW+VmWsaxhdFX523b/wC58tdFpMflrsRN27/b/hraNTkMJYXlOi8OxoNls+4r/Ht/irudFt/tHluiMzxoq7WX7v8Au1xuhyOrIyQqhrufDLPJInd2/vfKtVKXNE2o0Yxl7vU6fQbONVLwwySvHFuVY9q11ulRzeVbzIm3+J1b+GsHQVSSNIYfLZV3bpN38Vdbodm81uj+Su5fmfa+7dWTX2melTpxL+k28zWvz229G+b5f4f92vVf2f2ez8XWSeR5paWPyvMT737z7tcFZ2MK2fnbN7q/7j59qq1dz8KbeaHxZDNYW0yXEm1U2v8Aeb+9Xn4upyYWpM6qeF+uTjQl9o/S74m+G4bT4ZS/EzwZ4psLzWtAtYWk06RvMjXb/s/xf7tfMHwX+Jut/FzxlqtnbPJJqlxPJdXEdvFt3MzfdVa+P/DP7SXxy8E/FbxVHZ63cSaRb6pI1/DNuZY/m27a+z/2Q/i54Bk1Cw+IWgww/wBtLexyrG0G1ZGr4fKM3nJSdXY8XijhChlyl7GXNJamT+1t8IfiX4VvNLstb8PXji4+ZpGT93GzL91q+cLjwref29NDqUKxxWfyRf7392v2s+K8ejeLvA3/AAmfjzSLGWBtOxArL8vnMv8AD/eavzg/aO+FvhvQ7BP7N8yaaS6knlVYvu/8Crtz/FUI0oqG8j5zhTC162KenwnhOmrbWypGkPlSyS7du37tegeFfFPhLQYY45LmMTyP/oqsn3o1/wBZI3+yteQeKtUvrWZLO2hbz1+5I275V/vV5r8VvjRqWh6bqei6Dcs1xfQfYpbpW+aOH+Lb/vV8pTjKpLlW5+jYiUMPDlR6b8fP2sPDHxO8SXOt68kieCvB8XkaXpqvsbVLrd/rmX+7uWvh74/ftWePPi14mmnub+4trCz3Jp1rHL8sa/w/LU/xI8XQ6ho6eG7CHyYN/wA/z7mZv7zV4zqWoPcTTwWyb3j/AIv71fQ5bl8YyakfJ5tjJThaMiDXvjJ4q85oZnbZ/vbv+BVF4d+N17Z3W+a5bLfK67qyNQ025jXzr22x5nzbWasi80mGVftKbVb/AGa+jp4XDOlySjY+TlWxUZX5j3bwZ8XptQmFyb/ey/eVW/8AZq9K8K/Eie/uGmS8k27l/d7q+QdNnv8ATXVra4kT/davR/APxKvLEJvmb/b3fxV5WKy5xu4HuZbm84+7UPqez/ac1v4b6lazJc3gtYdzvCr7vmavXfit+1emqaf4Pe2RY45r1ZZZPNbbuZfu7f71fFs3iiPxJqEWnxzcfe2q9bPxG8bPp+l6BpX2m4LWNw0+3zf4tv8AEteQ8JHSx9HDNpSpvnP1y/ZX+Muj61p6/wBvTbYo/mf978y/L/DXvPwv+IfgzSW/4SrVbOGSzXcqyNPtRWr8PvDf7bHifwHo722j6kyySffZvm3f3qitf+Ch3xyWzv8ARNK8W3Ahuk3RRrb7ttYxwmL2ggxObYaKP308Pfth/s1W/iR/Dd5qFvDcyT/6M0gXbGv+1JXpWkfETwP4igku/BviKzlRfmfbdb1r+Z7wz8Wvj34y1ppn8Q6ldy3Uv+rhT/vpa++v2Nf2nvGHw7htPCXjGwvoYm8tW+1W7Kzf8CrGthsdh4c9SzMMux2ExNW0vdP1Vm1r+0rUXP8Aq3ZvmXb/ABV2nwN8RSw+IvJuQqlW+RVrwvwH8RrbxhoMWq28yusy7lkjr0P4U6tdQ+JYXhdg6tudl+avBWInGpFy/mPezTDwqZdNf3T6A+OHiZvDHg6XXLi5W3tTbMtxMx+Vf7tfzQft1fFi8+M37Sni3xiniS4vIW1JrW1jaX5I1jba3lrX7ff8Fef2lY/hJ+yVcbtSEV3q0v2Ow2ffZtvzMq/7Nfz+XSw6lqCXN/c75vNZmmX5fM3N83/Aq/WsJKNajGbPx7BYb9/KZjw6bDI3/LRmb5v+BVLcaXc+Tsmh3L91mj+7Wva6OnmSp5P7tn3I0laVrpcEf7l7Zm3Ju87ZTqVPZyPoadH2hx7abMtr/o1ssifwf7NULjTX8vztnz7/APV/7VegtYpGzfuV2fwL/drJ1LTobdvMd1VvvP8A7tZKvzR1H9VjGRxmoaVM0e+ZGLr/ABL/ABVl3WmzRsyOWV/7ytXZXCosrJ9mZwz7f7v/AAKsDW7Xb5u75GX7rbN1dVOpI46lOH8xwWpaSFaV5k3N82xv4q5fVNJTaHfhv4a9F1PT4JIX2bS38bVyuuWe0SD+H+7Xo0ec8rER5ZXOA1KzmikL9fn+8tfVH/BMeEQ6T4xwxObmyPP+7NXzZrFvt+d4cbvlWvpj/gmlF5Wm+MRnObiy/wDQZq/V/B//AJL/AAnpU/8ATUz2eFVbPaX/AG9/6Sz5w/aTYx/tC+MJFlVf+Kju+G7/ALw1xm1Fb5E4b/brsv2kZU/4aD8YqzFc+JrsZP8A10NcarJu3u643ba+Lz/3c7xX/Xyf/pTPKxijLF1X/el+bLkM5HyId+3+KtW1vnX5ERWb+81YNrNJyiOrD/ZarsN0I8fw7q8s5ZRhE6WzvH2r8isW/wDHa1NPuJI5C8x3fwp89c1b3m1F8l/4N3zPWnp906/O83y/edWoM6lO51lneH78gX5l2+W3/oVXYbjzId6PJ833/n/9Brmre+jV1m87f/DV23vk3BE+X/e/hq+b+U4qkToo7qFVDmFkOzanzUkl87R8Iylk/wBW1ZC6hu/10i/u/wC7SRapDlPJf7qbZfn3bq0+Iw9maUkkednmbdqbd2/5agkvXVkf+Gqbao8jFEMaj/nntqvJqiOrOm1v4du+p5v5TSnEtXl1DIu/5vubU/hrImussu9Pm/2v4qbc3ifxt95qz5b7zJndnz8nzUe/8RrH3iLVrqHa2+bdJ97/AIFWBfSPJIzuGfd9yr99cPMu8uvy/wALfxVlyS7mPzMP/ZaylI1jyH0ZHHIpVJhnd/dp0dv9sm+SFYgqMzeZ95mqfy/LfyX++su7dv8AvL/DVn7Okcab+m5vlr4ipGXU/X8LjJR90zY4X2/O/wA6tt2r/F/u1DqFqkkbHfuZn2s0n3q2ZrF45IoXhVVjbcirVWbT0kkKJH838C1zxO/23LtI52+t5priUfdVU/76qjdWs3mKjpjcu75XreurOaR22W33v4l/u1i3kcbSedt+VflSuyMTixFaW5j3lq8ay7NvzJtfctZ8kbrI0MyrtrauoxGjb4eP7rVSnt3WTf5Kq+z7391a9Wjzch8lmFT2kiPTZNrL87bW/wBitjTlmmKR/d/vNsqnZ26Ltd+Qu1vm/hrWs49q/fbLfxVtKXszzI+9ISOF5mX7NM29X27q0o98J3vBIh/jWT/2WmR2/k/cSPCvt/2matLT7GGNWffu3fM7M3zVzyqFxjEreT5jCTyWLfN+72bamWzuVXZAjRJ975au2tq6xssbyKV+dV2bvmqS1hh+0M8/mAyOqqv+1S5uxfLzGdeRQtMjvHubft2/xbqhu4fJX54Wbb/Fs+Zq9I+F3wgX4kpfz3GutZm0mQKy2+9n3bv9oY6frXVz/so2lzEUm8dTlyc+Z9iGf/Q6+9yXwu434gy6nmGAwynRnflfPTV7ScXpKSa1T3R6mGyfMcTRVSnC8X5r/M8KNvBGqzP8vy7v9r/danRqkkqujx71+V1Va9wn/ZLs51Cv45lGO408f/F0xP2RLCMEJ45lGev/ABLx/wDF16i8FPEe93g1/wCDaX/yZ0RyHNV/y7/Ff5njCzOrfuduN3z/AN6tS1aZpPkf/tm3y16on7IumqF3eNpSydHFgAf/AEOr1p+zDbWgIXxrK5PQyWQOP/H60Xgt4jLbBr/wZS/+TD+wM0lvD8V/medaau6MJDuD7/nXZ/DXTaUz7kjS23Mz7flTbXT237OFrby+YfF8rgfdVrQcf+PVq23wXtrZdq+I5znhmEeCR6ferop+DXiItZYRf+DKX/yZl/q/m62p/jH/ADOftVS3l86Z1RP4Fb+L+GtnS7iazmaG5T915S7vL/hb+Fa1bf4YWkUgabUzKigBUaDgY/GrEfgFIp3mXVXw5yR5XP55r0KfhDx/HfCL/wAGUv8A5M4a3DGdTndUv/Jo/wCZd0CRJJNt5M2+F9jR7f8AZ+XbXYaDdPHshSaFW2fxfe/4DXJafoLWEm437SJnPllcDP51p2MjWYJYl3LZ3ZxiupeFHHyVvqi/8GU//kzgnwjnz2pf+TR/zPUPDd150my53YkfZ9/5l3V3mi6slqyQv/yzTam35WZl/vV4bpvje604Nts1YtjcQ+3OPwrdsvjbd2YBHh6JyDk75yc/+O0v+IT8ff8AQKv/AAZT/wDkyY8HZ9H/AJdf+TR/zPfdJuHVU4Xay7nZm3KtX9Nvt1usyIxPlbpV3fKrbq8EtP2jLyzgWGHwnCNvpdsAfw21ZtP2nb604TwdAQeubs5P47azl4Tcfv8A5hF/4Mp//JmkeEs9X/Lr/wAmj/me03rLJthhm3MvzPu+bdWLqG+OFvs20fN92OvS/wBmX9kb9r79qHwRa/ETRfB2ieHdA1KJpNO1XxBrTo14oZl3RxRRPIFypwzhQwwVJBBrlv2vP2af2n/2StD/AOEr+Ifw+0u/8PSXSWw8Q6DrLTQpK4Yqro8aSx52kbmTbkgbskCvk6fDOZ184eVwlSeIvy8ntqV+bbl+Ozknpyp3vpY4aeTYyWL9hePPtbnjv2338tzzzVGRZJd+4fJt+X5dtcR4qmRrP/Q0U7fl2t8275azLr40XVzE6f2GFZjkP9rJI/8AHab4Rl8YfFbxZpvw88FeEX1LWNZvY7TTbKKQbppXOFXnAA9WJAABJIAJr3q/hLx9SpupPCpRSu26tJJJbttz0SPZfC+cQi26aSX96P8AmcT4pkH2VoXfYNvyLs+7XlnjiaHy5cvs/wBrZX6WaP8A8EIP2u/Feix6r4h8deCdDubiP95pdze3Ezwj+6zQwshP+6zD3NfK/wC2P/wTO+PH7KtzZ6V8Y7eCGw1OSVNM1vSZFuLW7ZApZQch0YBgdsiqTyQCASPlsp4dzHOsx+pYGVKpV1tFVqV3bV8t5+9om/dvprscWHy6ri63sqbjKXZSjr6a6/I+I/FXnTzNsdgy/wDLRk+Zq4PXrOaSSWf7T95/vbfmX/Zr7z/Zo/4JCfHX9tnVb1PhJqCfYNNkSLU9b1YLDbWjSBiozuLyNhSSsasRkEgAjPefH7/g2U/at+FPhG68cad8RNI8U2dhayXOoReHlb7RBFGpZmEU/lmXAH3Y9zHoFNXjOFc2yzNVluKlShWdvddakmm9k/ftFu6sm03dW3Ir5ViKNb2FRxU+znH8ddPmfkv4gW1+yPsLNtf+GuM1C3jdnf5v9mvqn42fsd2vgT4d6l45h8evdvpypJ9mk00IJN0ioRuEhx97PQ9K+aNWt1Enku+F/urTzrhzOeFcXHCZlT5JyjzJc0ZaNtXvFtbp+Z5uaZbi8uqqniI2bV909NujZzY3qzJ90U+3abc53s3yf36ffRoku9EZf7tQLNMrK7wq7L/D/erzeb+Y8o0Ybr5WfZ91Ktwyfu/O3s/+7WXDO7ZjRFz975f4a0LV42j+RG3M/wB3+7WUo8poadlImVff/B95a19NLtIm9MfJWTYxwrHsR8j+9/drZsVfcqTOqq1R7TlLjT5zWsfOkKee6o6/drbsGhl+/wAHZ8jKtYtrD5hX7y/PuVvvfLWxp9p+7V49yqv+t3JXPUrGsaPLI17FX++EX/gVbumrcyR702qGTc/+zWdpSPtT59iM3yfL96tK1heRTCm4+Z/FXLUxUfhZ20cLItx2aRqs4mxF/wChNWjZr9l3JNCroy7n/vU6xsfMWONwrL/D81WWRIZsQosu1/7lebiMVGMbHsUcDy2Yy2j+ysnkptLPtXy/mqzHM/l73ePar7kkV6HjdsfI2/8Ah3fxf7tSx2ci/uXRtn8S/ery6laVSMYnr0aPL8IKzw2/32fc25G2/wAP/wATUUN1JJ8nkrs/jaP7tT3UDyRlIdq/Nt2qnzLTlsUhhZLaZd8n3fk+9XO46ndGnymRJMkkv2aa22K25Ytv96qrXjtIh6J8ys2yrsmnvCpd7mb/AK5t/DUE1nebfsxf733ZN+3dXauQ55U+WXu7lNVdZV2Pn5Nvy/8AoVSyRpqDFHRg+/8Ah/8AHqsrp+6Rsortt/e7aks7F5I1S2Rl27d235mat40+YzlGdPczZLGHc8RhZG2KqMq7W/4C1Tw6a8cjb0Vvl3bm+9/u1pNY/wCnEXMLB9n72P8Au/3dtTLpqSSb97Lu+626uj2JyuMfekc7eWu23cSblZk3fL/CtRrpaXDQv+73t/wGtqazS4uFTZt2vt3L/wCzUl1Z7pEdH2BW+Zl+61bRp8sfdOepzSkZsenvFIkMztkfM0kablX/AGaLrTdrb5ZWLr8qL/C1bCw7m/czbh/BItM1TS3WT7Y+35ovkbf/AKv/AIDWEo25Wa049DH8mEBXmf59m5NtWWvHtFSZ3+7tVtqf+g1DfF0ZYU24Vdrs393/AGaz7q4eZUmRGWJV27VraMvshVpx3iasmoIyvGkzIVbd81RLrkLbpk+/I/8AF975ayby6hmX/RnZjGnz1XuL54Y/kRlRv4q9ChL3PePJrUftG/JrUn+u8759vzRqtV217C7HuZP93fXOS6g6sPJf5mf+Kof7QkVmd34X5n+Wu+nPm3OSWF9pqdVHrB8xn+b5du9Wb5adea1tt+rfM33Y22/N/wDE1zUd9cou9JlG6ludSn8nY7/N/Ay1ftIxOmjl85QLuoah5ibE3Yb+Jf71Y+o6lNDGNn3mfa7b9tR3GoPIqfPg1l3DPJuM24/73/oVZe25h/2a6fvcoy81CZWXD4Zn+b5KoTXzzMrojMn3UarjR/aJNjuu7ZVZrErCv3vl3VhUrGjy2XxcpT+0TQ7/AN58zfc3J92hrhGbf/s/8s3qdbPbvd0Ulv7zVHJYPHDvRP8AZ+X7v/Aq5ZVv5jnqYKZXWT5flDbW/hX/ANmpqqjSf3fl2/71Sx27xyI7/KrJteSnN8q/Inzf7lL2nN8Jwyw/LLUhjV45G+66s/3aPMfzG3809ofMK/3dvystRv8AMqRvbbGb+Kl8XMY8vNIkW+eN9m3lv4qtwX0MaCEPt/8AZqztr2snnJMzbqfBNbNMjuF+X5V3fw1lUj7mptTlyzNi1ukZtiI1XtLeKOZnR9qN83ypWRb3HlyK7vub/wBCq5bzO27ft2r/AHa5PflHU9KjU5Tp9NndZt8cyqsjfOtdDZ3Dqv2lNqr93bu21xlnJ5cKzJN8rff3VvWd07Yh+VkjTd83zbqiXw3O6nI7LS7x/PR3+VfvbY62rPyVmCJ0+98yfdrlfDd+P40Zz935Vrp9Pjdo3S68zezLs+X7y152IlLmPQwsYyiX/sM0LDemwTfPFtf71ereHyj/AA7UxggGylxnt96vMrODbcLNM+Sq7drfdWvTvDqqfh+qKMgWkoGT7sK/bPAWTln+ZX/6BKn/AKVTPqMogoTkl2OHWOGORkR5NrbVdW/i+WiS1hGXh2t935f9qrMdvDIqfaXZFVvk2/N81L9l+0R7JkZh83zKjfw1/P0Y+/7p6uDomFfaW8TfOkgDbvljbau6snWo9sZebc+35tv3Wausu4d0zohYWy/KjMv3mrndQhSSN03sWk/vPXXE9Cnh4cxxOrKPnf5lhVNz7V3bf9mud1K12xb32s+3btX7u2uy8Q6PcrHs8tWVvm2q3zVz+paXuj85EZCyb9v92uqnL3YnoQw8eSRx11GkeYd6yOvzN/s1nTWsPlrsds79zru3V0mpW8LRv88YMi7vu/M1Zq26LHv+5tTb9yvSo82nY5a2HhIwJ7PdcbymPOf+GoZLVzJsTdhv4WX5a15LdI3Hk8/xf7VRzfOq7Imc/d2/3a9SjKK+yfP4qjCJSt4Z41+Xbtb+Fq1rH942x4VXb/Ev3apyRpHKZEm3H7q/3qksRtmZ0+9/eX71b/YPGqSinqdX4f2Dakb7v9pq7fQbySRkhuZlii+6rLFXA6Ldx+cYdjI7fLuX7y11uh3zqzJNMz7fl27vvVfLzR94iPaJ6JoN5ZxzvZwOr+Y23ds+aus8P3zNa/Zt671T5IWbbu/2q850fVHh2JGnzr8zbV/8drq9DunY/aXnzufd5e7burm9pynZRqcseU9J0m9eORJpkjQxxbdv3t1epfBfVLex8QLqVz8629rI6bU/2fl2/wC1Xiei6puaO5mmVP4XWvR/hrNc3WoXFhbIsrSRM0TR/wC7XjZ1KUsumo9j18qlzZjBnpXwl+Hfw31b4EXmq+OZlsbnxt4oZX1DULhVk8uNvvL/AHal+Aek/DfwT+1hb/D34deOYde0iNo23W7bo45N33a+bv28viA/hvwT4O8AaHrHlSQ6W1xKsO5fL8xvm+b+9Xt3/BBL9mG7+JXxmvPiLrM8kum6VbLcXjSP93b8y/8AfTV+aZdTxPsddD0uK5UJ81Rn64ftXyxWfwdsdRkhkhghs40SOP8A5Zttr8+/if4sfxZfXOpX7/JH8sUjNtVm2/xf7NfcP7X/AMZbKbwzD4Vhs4/skCHKyL95tvy1+YHxY8YXt14uuf32yHzWVo1Taq114/ERryjGEj53hbAzwuGlUqx5eY6K/wBF0HWLXffw27xxxfPJH8kjN/vfxV8sftHfD/TbWyuU8H3KyXk10yy/aLLb8v8AstX0T8PfEmja1cR2GqpJFa27Mtx5L/NJ/wB9V1Xir4A6b8RtJa80DSo7S3hRmWaZt3mVrl9SDnaZvnEeX3on5CfEiDxDp1vMlzDJFIvyvuSvKrrUPEmk28mxJAsn3pNtfpH4s/Zf0S88SXdt4i+zv5L/ACSSfd+Wvn348fB+z09Z30TQVeL/AJ57PurX2eX4rD/DKJ8DjMLiqseaB8k2uraxq1x5L/O/+1W1rHhXWNJtEuSi/c+7W+3hHQdJ1FLy2hmQszfu2ib5ai8Ua9NeW/2BEXasW3dtr069ZSlGEIniQwteL99nENqn2hfJ8xVK/frT8LyTXVx5KfKfu7qpWHh172++T5gybvlWvVPhT8Jb+6mS8e2ba33NtZ1pUqcC6EatSqd5+zb8Kbnxl4ytdBezkVrh9kU2zcq/7Vev/txfsK+PP2c/h3Z/F3xPpUlvol1PHBFeXDL+8kb7qr/FXa/sj+CX8L+MrDUtSso8Ky/M3ys1fZn/AAW2+DOuftE/8E1vCnirwlF5114T8QQ3l1tk+Zo/L8tm2/7NfIVakp5jGD92LPuJYPlyj2kdT8Qta1zTdPhH2l1X+5urc+GvxM+G+i6hDdaxp8dyyv8Ad3bdy/3q5Lxt8H/G0OrbNS0e4ETfKjSVe+F/7PviHxB4kisH02RRI3zs33a+meAwvsOac+U+XnjatOrFwpcx+lf7E3if9k74svC/gnV7HS9ajfb9jvkVWk/2q+7rL4d+CfHHhX/hG/Emj2895a2+yK6WBVZdtfkX8O/+Ce/xqXULbxJ8GXkhuYXWWJVb5m/y1fol+yjrH7S2m6vZeBvjT4Sm0u8jVVe6jf5bhf4vvfxV8bmmHrUo89KfNE+wy+eGxtK1aHJM9v8Agj4f13wbb3Gj/aZGs/tG1Gkb7te6fB3Xrb/hLLbfGzr9o2su1qw7XwTZw6YNQMLBJnVm3JuZmrT+C3jXSvCfxPx4gt1fT7G3mup7m42r5axqzbq+WhRp1sXCMv5kepXj7PKp/wCE/OL/AILjfteaP8dvjpZ/BPwL4hkuLHwDPJFetDuVvtkn+s/3tvyrXxdp9vDNdeckO/bxLuTd81df8ZtQTxt8cvGHieF28rUPFF9cQSSJ80kckjMvzf7tULfS0ZQ8j4Xf86r/ABV+y0qMaVKMI9D4PBYfmp8xGunpHhHh3jZuSNX+VWq9HYouUTzP91nq1Z2fkybPszOWep44Xabem4I33o9v3awre97p7dOjyx92Jl3Fq726u8K7Nvz/AMVZV5pu5XSYLt+8jKu1q6eaF45Am/5Pu7W/irG1a3SZmd0YN/zz3fdrKj/LIyqUeaGnxHHahZhWabewf7y1ja/HIsy/O23au9ttdTqVrtZ3Tps3O38KrXP6p532hneZnVU2pHtrspx960jyKkfd0OR1a1hk83ZwzNu+WuW1yx3MX/ib5fmru9QsvmkHyotc/qOmja2/j+Fa9GnHlZ5Nan3PP9WsbaOPZtr6O/4J02sdtZeMDEhUNc2Xy9uFm6V4brWk5UnY2N/8X8Ve+f8ABPq2a2sfFYb+K4sz/wCOzV+s+EGvH+F9Kn/puZ6fC6tn9J/4v/SWfLP7TRkX9oHxkEGc+Ibr+H/poa4Rrry/k/ir0X9qC2mT4++LZht2nX7k/wDkQ15xIuJN7pk79tfF59H/AIXMVzf8/J/+lM8fGSi8XV/xS/Nj45ts2+FF2t/Dsq1DeddzrhaobXjX5PmX+9up0M/zbHh+X+GvG5ehz/FL3jbsbxPlLx7l37srV9dSDK3kurN/B8n8Nc5BN5ce+F+W/hWrEdw6yMiblSiXxcxEpcx09nqTzYhhRd33d1Wf7eeNVSba235a5WG8mjP2aN9p+8+2ntfbRlNpP95qfNy/CYVNzsIdaTydjurFv7tDapthVIdvzfNXJLqgaPyZoP8Avlqmh1J2k+WfAZfu1rKRhyo6dtWTeuHwrffpn25IZG8jbtk/vPWJHqXnSLC6KzL83mVMrPIymbbt3/w1EpFRj73ul+ab94+zafn+bbVdmfyf3m1X+9/stTlL58t0wP4d1P8AJmMj7Id/8O5kqPaGsYlCZdq732qf/QagmtIpMfxbv7ta32Hy1Xjcyt95f4qa1n0TKg/x/L/DWPOaRjy/EfR0djbR3BedN+35fl/iqa4tfMhHkw427tm5fvVYs0hZfkhY/wAKfxNV1bdBahIX2/xOrf8AstfGVJe/7x+k0zG+zpDGk6Bkbf8ANteo5Le2jZ/nYpv3bpPvLWpcWPzbN7Kny7d38VVLuPaqI7r95vlb+Ks5RudEcRymDqASV3869ZPn2/L8y1i3sMZ/49oW+Vf4q6a6s0XY/kyK7fLu27lrLvLV1md3XZ8/8XzV1U/e0MKlTmj7xzF5azec2yHe2z7u6q0lpc28iu6LtX79bdxEjXDud37uX+FflqL7G8m9N7Hd/EtepRqS9lZHgYiPN8Rm2du/2j9yiy/N95q2rG3ufM2Jux/dVKdpeioyvOnlp/e/ire0fS03LJsVQ392nUrHPRo9ypZ2O21Fy9s3zPt2tV6x02GRWx/f+833avx2aSK0MO6VY/mRm+7WhY6TMu534TZuVW/irnlU9nA3p0485mNCkTI8KeU33fvblqxbR3LSfaUTMq/8tK1rjSTI3kum3+8q1J/Zu1fsyI22P7v+9WMqnNE3jT989g/YH+E+qfGT4n2nwi0LU7e0vfEmuWVhBdXgcxxPIzKGfYC2BnsPy61+l0//AAQ68IeBZJV+Nf7amgaAt1fvFoLPpscRvIlxhmE9ymJPmGY0LhePnOePhH/gkfJNYfto+BRbStFIPHuko7RsRkNMVYcdiCQfUGvpL/gs/qOp3v7eviG1vr2aWGz0jTIrKOVyVhjNqjlUB6Au7tgd2J71/VXh/i+KcxyvKMly3G/VacsPWqykqcJybjiZRsudabr5X0vZn0GGnj6lShhMPV9nFwlJvlTek7dfU4z9tf8A4J+fGP8AYo1y2k8VSQ634b1KRl0vxPplvIIGYE4hnDDEExUbgm5gRnazbW29D+xX/wAEyfil+1noFx8UPEHiW28FeBbNn83xFq1sxa6VFYu9uhKLJGhXa8jOqqcgFirKPftN1HUfGf8AwQi1C5+M9/MRpmoCLwfcXczB5I4r6NLdFJUlgCZogORsTG5QMr7h8Q/iH+xz8Iv+Cdnwv0r44eCde8RfD3VtH02GCDRJJZEa4Ft5w+0OksBbLiRsEAF0zsBUY9jMfETi7D5Osuprnxn1qphXVp01LmVNKTnCnKSh7Rp25G+VNS8iK+dZlDDewir1faOnzRSd+VXuk3bma6XtufJ3xy/4I5614d+Fd78X/wBmT496L8S9O0iCWXVrWySOObEYDOIGilljlZUJYxlkbA+XeWC15b+xJ/wTy8d/tweHfF2seCPiBo+jz+GUt0gtdUhlYXc8xYqrOgPlJtjkO8BzuCjZg7h9ifs8/t3/APBO/wCDlr4kP7I37MfxHlvZtJa71fTdI0qa5jlhgDESTBrqVYo13ENKV+VWPXoeW/4I5+Ph4X+Bv7QvxL0HShBc6bAmq20AdRGuy2vpY4wAgAwVIyBjBGFGOZnxh4iZdwnmNSupqrSnQVGpWp04TkqlSMZRnTi5QstlJWunffZPMs7oZdXlNNSi4cspRim+ZpNNJtfM8z+Pv/BKX4Vfs9/CTVvEXjL9t3wvF4w0jTFuJfC01oqmeYgEQRhZmnO4H5W8nnglVXJXS+HH/BGGS28A6b46/ah/ad8O/DxtYto5bHTJ40eSMugfy5XnlhUSqDhkTeAR9418UX/ibxDqviObxhqWt3U+q3F615PqMsxMz3BfeZS/UsW+bPXPNfof4k/bV/Y1/aV8G+GfCP8AwUr/AGffFHh7xXp+jxPYa59iuY0uYJo0P2yIxlJRHKyFwpSRAOVdsmvf4jh4k5Dg8PTpY2piOeUnVnSoUXVglFcqpUnZSjzX5m3KSVvn2Y5Z5g6cIxqud2+ZxhHmWisox0ur77s8I/bI/wCCXvjP9mL4ap8dfBHxS0jxz4Ie4iifVNOjMc0IlJVJGVWeNoi21N6yE7nUbQOapfsVf8Eyfij+1noFx8UPEPia28FeBbNn83xFq1qzNdKisXe3RiivGhXa8jOqqcgFirKPbP2qf2fU8HfsG33j39hL9pnXtd+Dl1qqz+IfCNyFk2EyGOSVZvLSZI1k8rfbOuDnzSTgVo/8FGdR1Hwr/wAEwPgj4Y+FN/N/wh+o2liusTW0zMs8gsxLGkjbRkGXznIO354x8uR8vnYPjPibHZVhcvw+Mi8RiMTOj7aVLknSjCHO1UotKKr9FHWDutbmNLNMfWw9OjCqnOc3HmcbOKSu+aL05/LY4D43/wDBG/xDofwxuvit+y58cdL+KNnpiSHUdO0u2X7U5TaStv5EkyzuFbcYyVbA+UOWC14l+xF+xZ4m/bY+JGr/AA60DxtY6BLpGhS6hLPf2skpcqyxpGFXGAZHQMxOVUkhXI2n2X/ghp4i8f2H7Xt14c8OT3DaJqHhm5fxFArHygsZUwysMEbhKwVScHEjgHkg+0f8Eyrfwvo3/BTn47aF4DuY5dGWHUTaup3/AHdTi4VyoO0FnGBwcDlsBqvN+K+LuFsHm+XV8Sq9bDUYVqVbkjFpTnyuM4pOHMt46arV+TxOY5ll9LE0JVOeUIqUZWS3drNbX7dzitH/AOCH/hnR7XT/AAz8X/2zPDmheMdTT/RdBtLNJVkZmKoIvOnhlmyRjIjXnIGcZPx/+0/+zZ4+/ZP+MF/8GviLNZz3tnDFPDe6dIzQXUEi7kkQsqsO6kEAhlYcjBMHiv4k+OfGX7R1x8TfE/iW6vddn8WLdPqNxJucSLcDZjPAVQqhVHyqqhQAABX1l/wX0WJf2lfB5SCJWbwOpeRYwHb/AEy4ABbGSBjgHgZOOpr6DKcZxhkvFmCwGa41YmGLpVZNKnGCpzp8kvccVeUbS5fe10vozsw1TM8LmNKjiKvtFUjJ/ClyuNnpbda21PhKus+A/gCb4q/Gvwl8NobI3H9ueIrOykhG75o5JlV87SCAFLEkEYAPIrk69C/ZL8Y23w//AGn/AIfeM7y1E0OneMNPlljO77ouEBI2kHIByPcdD0r9JzapiKWVV50PjUJOP+JRdvxPdxLnHDzcN7O3rbQ+sv8Agtb8f/GOgfF/Qv2Y/h7rVzoXhXwz4btpX0nSZGtoZJpM+WpVCAyRxJEEXGFy2OvHSf8ABJr4i+Jf2nPgL8Vf2P8A4sX0viPThoAn0KLWJHn+ziRXjMYZjlVSVYJEAIKNuZcHkeW/8FwfAmp+Gv2zv+EunsnW08R+GrOe2uNp2yPEGgdQTxlfLQkDoGU45ye4/wCCFmh3XhnU/ip8eL6wkOnaH4XS28/Y2JH3NcOi9iQsCkjkjcvTPP4FjMHldHwGw+JoRXtIwpVIySXN7d1I3ae/M5txbve10fHVaWHjwhCpBLmSjJPrz8y6976HwNf2N3pl9Npt/bvFPbytFNFIpDI6kgqQehBBFe7f8Ey/i34E+Cn7aPg/xr8R5YoNLaaexe/nKBLKS4heFJmLA7VDOAzArtUkk4BB8O1vUv7Y1m71f7OsP2q6km8pCSqbmLbRkk4Gcckn3r68/wCCJnwY8D/FX9qu98QeONFi1FPCfh9tS021urRZYBdmaKOOVt3AZNzMnB+YBgQUFfrvHeLweD4Ix9XHRbp+xkpKLs/eXLZPWzu99Ut9T6TN6lKllNaVVacrTt5q36nuX7Zn/BLT9sb46ftG618U/h78cNMutE1q8WWxi1fXLqCTTYtoxCESN18tDkLsOSOSMk5yf+Cq+saf8EP2HPhx+yN8Q/Hv/CWePIri3vLnUpZBJLHDCkqtMS4LhC0nkxk7WdY2JJ2sp+f/ANpb/gqD+2J41+OGr6r4X+K2s+E9L0zWJotH8P6W4gS2ijkKqs4A/fv8uW8zcNxYABcKPoX4teLf+G8v+CRt7+0F8Y/DMP8Awmvga9aK28QW+moJLpo54UkddoXZFLHKBIq4QSRFgvyKo/FqeU8X5HWyCvxFKlPC06tOEY0kozhOcXGnzvlXNFac6g0m+ktz5aOGzLCSwc8a4unGUUlFWabVo301Xe34lP8AaG8Y+Kf2MP8Agkz8M/h58MzL4b1zx6YrjXL/AE7fBcsssRuZiZAQyyMDBGTnPlqUGFAA8Z/4JJ/tO/EzwD+174e+H954x1K70DxfLJp2paZdXcksRlaMtDMqsSFkEiIN4GdrMOhr1P8A4KM2t18Vv+CZfwG+M2j6Qy22j2ltZXqxK5FuHtFhyck4XzLYLls8svPPPzl/wTD8B6l4/wD25/h9ZWFk8qabrH9qXbqpIijtkaXexHQblReeMsBznB97I8FleN8Mc4rY6EXUnPFyqtpNqcZTtq7u8UouOumljswlLD1chxMqyXM3UcvVN2+7Sx5l/wAFvvhPZfBr4qfF3wZonh6HTdOkvIb7TLO2hKRLBcPDMBGvQKC7AAfKNpAAAwPyc1SHZJ5P3jtZv92v2I/4L7+L7fxv+0H8WZbW2EK6eLHTi43ZkaBLdGY5P94EcYGAPcn8idWs3+d3hYqv8X3d1fkniPiMVVWTzxH8SWCouV97vmvfzfU+T4ldWccLKW7pRv8AichdW7qrP8zCqDWrwr8nylq3Ly1ePbsThqo3Nk24Mj/x18BGpynyHLzGfD5nmM/zYX7+2tO3bC70+Yf7P3qhjhS3kZ/J43Vo2sbybfJ/h/vVEpdzWnT5i3p8aeYqOGbd95dlbdnbvN8k0P7vf8+6s+xj43+R977+1/u1taWs21Y4fm2/+PVyyqR5fdOynRiaFnbv5Zm8lnZfm2763rGPzoD/AKM2xlVmjaszT4UVW2fM29WX5q3tJimaREd8fPtdWavPrVj06eHizY0exdVSHy1Xb9z5vvVsafb7m854WQx/Kn93/gNM0XT0jkRJnYln+Rmeui02z32I3cbn+X+Jlb/eryfrXNLlPZo4X3SPT7VFU/udki/5+Wr66em3Dw/My1YsbFIUe5+ba3y7m+XdV+OxSTc+xldVrgqVuWR6VHD+03MtbPbh34T+L56sJbzKzJ5Lf9dP4WrRktbOOON33L8nz7aj+zzRwo6OyfOy+W3/AKFWMZfDJHVGjy+6Vvsszfvw+xtq7WakXT7byw7/AMTfIy/e3VfWGSSG4/fLsk2/8BqW3s5o4/Jhh+Zvl+V/vVtyzluXGnGPxGNcaXZ3UhdNuxfk/wCBVBL4fh2h7lGLr95W/u/w10v9myKyWy/embdu/wCef+zTZ9Hf7QZptpXZsT/er0aNP3QlGHL7pzVvpaW8nyBi/wAyurfw1ZtdMRYfOSGbK/cjX7zf7Vbk3hmGNVcPt3ff2vuqxBpFtbru82R/Oi2szfer0adGPLoccv5TmJdNfKx/bG27fvTfM1VvsDrtmd/njbb/ABfe/vV2N/p9s80Lw/M2z+Fqp3mlwxx7HRt6t/E1dPs+U4ZU/iuc79khaMo6MvmfM0i/3qh+xJZw+ZCm9Gba3+zW9JY2fmK8MyuG+5uf7tULixdG+S552fNu/hp+z15Tn5ZSkY8apJ/qX3OrfdVf4aLqD9233vv/ADqzfL/s1d8vyZAjvj+H/Zpt3apcKrwuoZvvVlKPKZ8pzerWvlt5zp87feVqwLyaTzR/cVN23Z96uk1SGa3Xf5zFt+1ZG/hrmdUV9xMz87vurXD8J1L3oEEl9MzNB5yoW/26zr7UGVim/wCT+9uq55L7Qj220/w1n3lmdzJM6/f+7W9GW5nWw8qnwkMc3nKju+9Y2/ufepjXTr/rtzFvuL/eqw1nNbqqPbMqyf3n21XmtU3B0h2/7NdUa3N7sTqwuW82g5r55d/z/Pt27qZJNNtVJudv8W6kkXyzvdF2L91dlQv5fzyQpt/i2s33aqVafLofQYfKfcigEyecr7/9ylb98u93kZm/ib7tV13tG3nO29vuMqfLtq9Y277Tc/Nt+61ZSrRjG5p/ZREtm8bbPlG7+89Syae7J86YH+z/ABVct7fzmRNkmf8AZTduq7b6bNMrzvuxGn/fVc0sRp8Q/wCyeWJhyaCkipvfYzfcb+7TJtNjjVvLfjf87f3q66z017pf9Tt+RW+b5qq3mjoJFhhhVW37fuVyfWoy0ZwYvK/d0OVm0hFXG/afN+df9moJLH946P8ANt+VK6W4sUhm2fK3yt/urUP9nJuV5HXDfLWlPERj9o+VxmFlGRzFxZvHs2Q8fdfa21dtM+ywrGqFGb/Z31vSWMKzcpsXZ/y0+7ULaei/OkzFt/8AF91a3lW9w8ephzCm09933Nyt/DvqNbPdcLsT+P8AhrZvLHdI2/gf3qguoXVQibU/iqeaXui+r/zFOOF/vwu3y1djjmkkZ/MVGZ9v+ztqGGHH3/m2v97dWlbx7ZEh2K3ybk/2qr4YGlGM4ljT1aNkTZ97761t6azqph8njeu3/aWsqG12yLsTaWf71benwv5a4hVd3yo33a5vhO+j7ux0Oko/8c0hTf8A6pfl2112n2sO3zo9yvu2vufcu5a5fR03CF4YV2b9svmf3a63T45o1CK+8bvmZvvMzVxVI80z1cLU5Ym3Z2G79z5efutukr0fQURvA6orBla1k57HO6uB0iHy7dZXRW/5616FoMUY8JJDEgKeQ4VVHbLcV+2eA0OTPsy/7BKn/pVM+lyio5VJX7P9DlFtYZdlsjsZNy/u1/harUtrcx/uYfm2uzPtermnx3MM3k3SK39xdvzLU0MPmW/mb921/u/d/wCA1+DU6M+Y3o1pRlfmMDCMqJDbSTIzfeV6wdcs/Ojd3hj/ALvl/wAVdlqEbi3e1RFb/ZVNtYOoWMLQoX+Uqm3/AHq6PZ8p7mHrfaOI1q3fzGuXtlES/L97+Jqwr2zf54fmfd8vmL91a6zWo0jiWF3VQ277v+98tc/q0iRqzvul3Ov8XzV2UqMuU9aOIiclqVrc2qsiQKQzbfuVk6hD98OmHX7y1011++mf5Nv+zu3ViagttbjyfIY7vl+auyEJR6CqVqUTAuF3Sb03CRl2pVFo3t/4Gcs21/71al9a+Wyqi7D/AHaosqBTcv8AIy/fVf4q76cbHyWYVOb4SKRPs+7em7d/Ev3qLWP7Pdb0Rm/2lpxkfyxvTa7fw0kW6ZneE4X+L/arsjHmifN1q3Ka+lx+ZcBPO2qz/Mzferp9HkfzfOR/Kdfvsv8AFXK2FqHHKbXZflVfvN/tV0elwvHjL7H+6zK3zLUVOaRH1jlOu0u827fJT+LczMtdLpV88dwr3O3/AGGWuN09XjxsdmH93ftZq39Jme4VURF+XaF+f5t1cVSXunXHFR+yd5oeobbgJc/JKvyxMvzK1etfs/68mn+JvOmm+aO1kVI2+7N+7bateG6LdbtUTem54flWTf8A99V6R8I75G8WQwncr3D7P7rV5mYU51sHJHfluK9liozJvil+z/4q/aE0HSn8Kwx3OoWaNbfZY38z5d25Vr7K/wCCPfhbxf8ABT4b+K9N1jQ9Qsrp7uGGeGb5fl3fw/7K1t/8E8vgq/wZ+JjeNvFOgSXelWSyXpdf3mNq7q+gvhh8eP2ZvjNf6v8A8Kp0a5l1+/uZGubSCJlKFW+Zn/2a+FqqnGhyP4j2MZWqVMU3yc0Opyv7TmuTLvR5pHMMS72X7vzV8RePrHTZNeu33ybppfNlaT5lVf8AZr6n/aG1z7VNeW015JB5bMqKrfK22vnpfDqatp5mvIcmR/8AXfd2t/u15MY+yZ6EfdgeWaPq1h4f1R/sd5u/jlVvu7a9L8G/H+wtbaW1v9YmSwVdu2SX+L/Z/u1538WPhzreizM7wSYb51WNN+7dXz58T5vHmk+IrR7aNgnm7v7q/Kv8S16FHDupLmiefiq1CPu1T608XR+GPE1r9s8MeGLi5E0TM9006+Xt/wCBV8+/Gi38Z6Mvnf8ACt45rf7rSQorMse35d1eY/8AC5PivJJ/yEpv3O7fJHLtX/d21et/jl8YLjT/ACZpFltmfbtuk+WRa9WFPFU5RbR48vqM+ZRZ5d8QfiB4J1Czlhm8HtFPDuX5vlryHVrVNcvPs+j6a23eu6OP5q9u8beGbDxhqj3mq6VHEq/xW/8AFUOh+E/Dekx+Ra2y7YW3MzfeZq9ehW9h70nqeFisJKvP3YnK/C74B3OpXiXOqwthm+f+FdtfSfh34Z2FrpsSabCq+Snzxqv3q5bR9SsIY1sLZIUaP7qq/wAzV7L8IY7PXLT7HeXLJcbP3TRrt3VrWxyrQDD5b7HVfEdd8MNP0qz8Jprd4lmj2rR79z/vG3N/yzr9A/2ePCuifGj9mnVPAvifzXsLu1aN4WXcsn93/wAer4kh+Ad3D4fPim5ufJtoUVmjb5VVt33a+0/2H7rxLd/DwaR4ZsxPA0amRi/yxxrXz+Pjy1YSPqsBH2mAqQmfm7+3l+xHqX7OPxWhvPGmiTP4U17b/Z18vyrDJ/drX+Hf7Bt54i0+z8Q/C7xbD5Eksb/Z5Nr7mX7y1+rv7Q3wR8GftB/Aq68DeObBrnZFIbWRl+aFm/ir8vJvg/8AtG/sR/EpLHe2peGI7pnsrqNmZo1/hX/gVaVa05YWNSn7zj8SPNw2GpQxLo1fkz7P/ZV/Z78beEL63v8AxRCv2aGJfK8mBVbd/FX0p4u0nwlfNYQvokbz+asUU0i/Oqt8zfNXzf8ABX9szxCvhmF/E/hhjFJF/C+2SvY/hz4i1LxvqFtqb3LIrbmit5G/1a15H1irK66yPSxGBlH4djtvHsGmeGNBR41by1i3RM38TV8lfHzxpeaP8KfiH4hsLzyn/wCEXvILeRn/AOei7d3+z96voD4+eNg0Y0RrnZ5ab9sf/oNfMX7Ukltp/wCyj47165mbz5LCG3WFU+WRpptu3/vmuLCR9pmsEo7SOmph/Z5VN1Ox+b2j6HMqok1y0h+zr5s38LN/erdsdJhaEQwzKqb9m1k+Vmqa1tUt5gjurKv97+9WppdvMrfvkz/FtX/0Kv2Bw5ocyPicL7vukMOg3nnCZHjDxv8APCr7W27altdPmhV4ZkjWRl+61bsciSSedNbfL8q7m+9/31U91pKLbvMjqNvzIqp935q46lOctz16fuxOKvLab7Q6WzxqV3Km6Lc1Ys2j3KyPNI/m90X/AGq73VtPSS4e5b5Hk/1S7Nq1kXuhw27M6QzHd8zt/do9nLmsKpGEtjgNc0e5jdkmhZP4tqvuXbXK32mv814m4rv3L/s7a9U1bTkmg87fGsWz/dZv96ub1bw35kf2b5Wdfvssu1V/2a7KcYxPDxVP3vdPNNQt5maR5pvut/q1VfmX/erA1ix3L8nzLu+f/Zru77Q5rWE7Nu1k/wCBVgappaRskyIzp954d/8ADXfTlE8StG3unBatbTqr7Eyy/wATfdr2/wDYQt1gsPE+0/entCR/wGWvKNc092X92jbdny7V/wDHa9j/AGJovKsvEeEA3TWpyO/EtfqvhAkuPsLbtU/9NzOzhdWz6nb+9/6Sz5h/acsIJfjT4qk80gtrlyCAv/TQ15VqkOdyJCv3fk+bbXt/7RNktx8YfE+4DB1u4G4L/tmvI9es3Hzuiqq/xfe3V8Xn8eXPMV/18n/6UzwsZ/vdX/FL8zBTfJ1enq3k53puWmXcflNs8tR/u1CjSeXj+Fq8XlOb2hPDJtk/c8t/Aq/xVYW4dlHybf7+191VrdnG7/fqVZHjbKf7vy1X2Be0LH2ieTYibfm/9Bpv79tvbb92mpbzSbZjDll+XdV6Kzj2h33D/gH3aj+6YyjzFaFXZWfzty79tXbW1uZJFcBXFW7DR0kbfs3LWvY6WzfIkXzMn8NVKQombbw+Sq/Ju/3qt2lm8eX6Lv3bv4l/2a2LfQ0bY4tsszf981etdDMa7/vMzf8AjtYSlKUjanH7RlwwwNh3hb5fl21Yt7abd9/buTbt31t2+g7pPnDJt+ba1JJo7wyb9n/AmrnlLlOunT9oYzWc0J2dV/2aRYX2rDtU/wAX7z5a2X0vy03vSeX+8V3s1Xd8vzfw1hGpI19ifQS6S/nSpE67413IqrVlbV7dWCIoHlK21vm3NWvNpf8ApDvhWeFPnbd95qia32SbH2qF2/N/er52pT5T7Wn73xGLcW91IiQwzKh+9u+9WfNa2wxAkK5bcqsyfxbv4q6G+0/zriLZbKPvKzM33WqpeWqbhBsVvn3IrP8ANWPvHZKMOQwLu1mWPZ95F/8AHmrK1COFmX52+Zt3y/w1v6pH5m7bcsPLT+H+9WXdRpNN9z+Hcy7fu10Q92epw1OblkjAlhMl9smfaF+X5vu1DJayWTbJHZyz/dq7eR/6SU8lcb9rrUa7Ps/z/wDHx/Bu/u13c38q3POlHmJNNt4bO186H5tzbtqr81bmkw20kyTJDIyq+3b92sqzWaNwUG6Hzd27+LbXRaTNDHdJsRtirv8A9n/gVRL93qKnH2kuU09L0n7UY02YRv4f/iq1V09422Dy9v3VXO6ordkuFH2ZFbcv71fu/LWlbxpGqeTAqhdq/N/D/tVwyqc0T0I04RGLpqSfP5PzfwK3y7qhbT0t7VbmH5dz/wB/+KrrW+2N/tL79rrs2v8Aw1U1Jd0zJbPhG+7H/dpUypxj/KfTP/BKnTb7Q/2u/hnrkd2UbUPHOnKqoeVj8/y2B+oZgfY1+nP7dP7TX/BOXTf2gL74b/tefs86jrfiDwzDbfYdZ0+xV/tFvNAk6ozpPE5CtIw8t9yjJIxvYV+TX7M/xc1T4CXvhb42aLpVrqF54Uu11S2s7wt5U8kEhkCsUIbBK9jXm/7e37Y/ib9uH9pjX/2jdV8J23hj+2Ut4E0ay1CScW8UMSxRh5GC+Y+1RuYKgJGQq1/RfEs8s4WoZDWlSqODwSt7Ks6U1OclUk+dKTs+eS5bWtLyLzKjToV8PUkny+z+zLlabd9/mz7m/by/4KOX/wC1LomnfBr4UeCU8G/DbRCn2LQYkiV7to8rC7rGoWFEQgLAhKqcks+F29D+xv8A8FMPC3w8+EUn7LH7XXwyPjn4dyDy7ELDFJPpsWWfy/LcKJlEm1kberxHJVjhFX8in1jU7iRkS8nH+y0hWmT39x5w/wBMZzs+VlnPy1MvE7g+pkEMnWSuNKMueLVdqcam/tFU9nzc9/tX1Wj93Qbx2WPALD+wtFO697VP+a9r38/lsftl4v8A+Cn37Kf7PPwz1XwT/wAE6/gBceG9Z16Ird+JdVto0e0YYCuA7zPclQX2q7KiM27DZZT41+xx+3T4X/Zx+D3xe+H3jTwdqutaj8RdIMNnfWt5GqpO0U8TGXeMqMXDvvG8kqF2gMWH5ZTa7etEiveS7lb518w/LVO+1u7ijdn1C4Xav3vMLM1GD8Q+FKeW1sG8qnU9tKE6k54mUqk3TkpQ5punzWi0rJWVr6XbZjHHZdSw8qbouXM023NuTaaau7X0Psa1urmyuY72zneKaGQPFLG2GRgcggjoQa/QOD/gpp+w9+0x4O0Ww/bv/Zn1DUvEGhWSQR6zpQEwuW2gSOGSWCSIOwLeVl1BPU1+EF3q+oSycajcK23+KU/40+DVbq4fbLeSP5e07fNO2va4i8Vcl4ndKeKy6pCpSbcKlPEOnOPNZStKNNaSSs07jx+f4THcrqUWpRvZxnZq++qXU/aL9rf/AIKSfB/xT+zzL+yR+x38Grnwf4PuLhGv726dIpbiIP5jxCJC5+dwhaR5GZgpUjnNVP2N/wDgph4W+Hnwik/ZY/a6+GR8c/DuQeXYhYYpJ9Niyz+X5bhRMok2sjb1eI5KscIq/j3p/iG+lVzPNKBu3LtkNWo9e1BVd3v597fLuydy15v+vfB8ckeVvKZOLn7XneIk6vtf+fvtOTmU/NO1tLWbRxf2zln1R4f6s2m+a/O+bm/m5rXuftp4t/4Kf/sqfs7/AA01TwV/wTq+AE/hvWdejIu/EurWsavaMMBHAd53uSoL7UdljRmztbLKfEv+Cd37bnh39jz4z+I/ip8RPC+q+IDr2gT2jNY3KCX7Q0qThn8z7wZ4wGbOVDFgrkbT+YsXiO9LjbfOB5X3VJ+Wr9r4ouzMkM08hjblW840Yfj7hTD5RisBLK51Fibe1nPESlVnbbmm4c3u9ErJdtXfOGfZdChUoPDt8/xNzbk+13y306H1g2vW7eMT4n+wv5R1P7V9m84btvmb9m/bjOON233x2r3b/gpD+2d4Q/bZ+K2hePvBvgzUdGg0rw3FYTR6nPG7yS+Y8r7QnAVWkZQxOWADFUJKj86rPxBfLCqfaZWKtuVo87v92tnSdcaILcxXM7L93czHdur2cX435RUzTD5hUyuTq0IzjB+3dkpqKldezs9Irc9iPEmGxGIhWdB80E0ve72v08j3OgEqQynBHQivJbHU5JV3797bs/eP3q1bXXJHZ3ikcfL/AKljtb/arpq/SWo0/wDmVt/9xl/8qPapZ+qqv7P8f+Afpr8Nv+Cnv7NPxi+D2g/B7/goR8Br3xdP4dtxHaeKbUrPPORwHbLxSxOUWMOyyN5hXcwHSsD9qH/gpf8ACS8+AN7+yp+xJ8G7nwP4W1KXGq6nIyQz3cDDEsXlxlzmTbGryvIzMgKEYNfnXJr1zD9xHT91uX95upW8QvHbur+bhvl6/KrV+d0fEvg/D5lDEwyepyxn7SNL61L2Mal786p+z5U76pfCuiPIisrp1VUVN2T5lHnfKnvdR2/Q+6f+CZn7c3wb/Yv1rxPefFP4SXWsSa3aRx2et6RDDJeWwXO62xM6AQyEhmKsDlBlX+XbxXwf/bY1T4B/te6j+078J/hzp2l6dqWoXXn+DYJilt9gnfc1qrKPkIwrKwXaroCE2jZXyJLrBhCwvPI27+JTVJtRu8PDNKy7X3blb+GvWreNXDVTH4zF1smlKWLgoVU8Q3GUUrJKPs7LTqrNbqzbv0vFYGdWrVlSu6iSleTs0vLofq/rf7bH/BIT42anJ8SPjX+yLrVr4nv2MmqiwtgUlmJyzl4LmESsSTl2QM3U15h+2v8A8FLPC/xu+Dlt+y9+zl8HY/BPgG0ukkljJjSW7SNvMSMQxDZCvmZkb5nZ2CnI+YN+bOpXF3DGq211KZPvbdxw1ZN1qF+gbF5KdqblVXPyt/drzMs8S+FsDi6OK/s2tV9i1KlCpjJzhTa2cIunZNLRXvb11POhiMuwtWM3CUuXWKlNtRfkmunQ/TP9h/8A4KPeHvgP8LNU/Zq/aM+GMnjn4eapcb4rFpI5G09WJaVFilG2VGkCSBdybH3OCS1eqt/wUz/YY/Zl8N6q37Cf7L13p/iXWbGSBta1iJIhakjKEs8s8kqK4RjCCiMVHPFfjBquo3IVsXs/8K7mc/erntT1e+l81GnlX5mZN0h+WujHeI3B+b4+pi6uVVEqslKpTjipRpVJK3vTpqCTeivtd6u7bM8Vi8sq1pVJUZe87yiptRk+7VrH1j8UNOk+MVpq8Hj7Vby9m1ydp9TvXn3TzytJ5jSM7A5YvySc5ya8ok/Yk+DskPkG+1sKTnAvY/8A43XgOp6pqjsVGpXGxv70pb+tc/f3eoxK+7Urgtvwi+c3zL+dfT5l4ucK53VjWxuRxqSjHlTdRaRV2kv3e2rNcTneX4uSdbCKTStq+n3H0jJ+wN8D5Dk32vD5cYF/H09P9VUR/wCCfPwJLlzfa/z1H2+LB/8AIVfKt5qd7BIGTVrovv8Al/ft9386z7zUdUZj5eoT7P8Aanbd/OuP/iIfAf8A0T0P/Bi/+VnE8zyR/wDMDH7/AP7U+uD/AME9vgUW3f2n4i4z/wAxGPv/ANsqcP8Agn58Cwwb+0PEBI6f8TCPj/yFXx02p62zB01af+7tadv++utPh1PW5mXfqs4+f+Gdv8ab8QeAv+ieh/4Gv/lZUM0yd7YKP3/8A+y4f2D/AIKQFSmoa9kdzfx8/X91VqD9if4PWxBhvdaGBj/j8j/+N18f2upapt+fVLn5f4vPb/GtvTNSv5Zkht9TuPm+ZlaRvm/WueXiL4fx/wCaep/+DF/8rNlmmU3t9TX3/wDAPrCL9j/4TxcpcatnOcm7T/43Vq3/AGVfhnbSiWO71UkDABukx/6BXzNo93rB/ez6hK3zfIqzN93866LSrq8KrNJdXH93b5priqeJXh4t+G6f/gxf/Kzrp5hlstsKvv8A+AfQ1v8As8eA7crtuNRO0YAa4X/4irkHwV8IW5UpcX3y9jOvJ9fu14Xpup6hLJ5qX0qFX/e7ifmrdtr2984+TeyOW+bazn5a5ZeJPhwnb/Vmn/4MX/ys7I4/AvfDpfP/AIB67F8IfCkKqoluyEGF3Srx/wCO1MPhh4byCZLrg5H70D+QrzDRdRuNizXV84f7mybPzVeivLg2kkUch3SfLiRi1Yy8TPDfm14Yp/8Agxf/ACo6oYzB8vNGivv/AOAegN8LfDTsrmS63L91xMMgenSpF+G3h5ZFlD3GV6Eup/8AZa4EXUjSR/O+V6tuP3f7tT2M8zxn7I7ff+75h+7SfiT4bf8ARL0//Bi/+VG0MVhmrqkvv/4B2zfDTw65O6S5wwwVEigfotTL4B0FAMedlVwrbxlR7cVyOlw+YiXL3Mof76qzFt3/AAGtW0S6eNXlimX+Dcw+9/tV1UvEfw4n8PDNP/wYv/lYfXMPLel+P/ANqLwHoUTBgZyQcjdIOP0p6+CtGBDP5rkZxvYHGfwqlawySSLsw7N95VX/AMeqza25nb7Xbo6Fn+RWFdtHxB8PJ6Lhymv+4i/+VjlicNGP8Jff/wAAnTwfo0b+ZHG4OMZ3Dp+VKfCOjkY2OD/eBGf5Vet9DF5aCLyxtZvvsdu2nXGkBLpI5rgfd2qqr97/AIFXUvEDgBfDw7T/APBi/wDlZzrFYSX/AC5X3/8AAMs+CtEIUBJBtORgj/CkfwPosgIlMzZILZYckDHpVwaWzXRS5QlNv9/azVQ1LSr+3iUoiDe/zLn5WrT/AIiBwFb/AJJ6n/4MX/ysyni8FF/wF9//AACB/hh4YdizLP8AMCCPMGDn8KZcfCvw1chRLPd/L6SgZ+vy81T1KwnRmeAzbF/5aSSL92svU9MnSNo453lMm1Ym3D5l/vVMuP8AgGGv+r1P/wAGL/5Wccsxy2DusMvv/wCAbI+DPg8MH33m4HO4zjP/AKDQfg14Q3tIj3alv7sq8f8AjtcbNBcIxRbqVmba33Cq7qpXVreBiIWbePmlZnLfLXK/Efw/5uX/AFdp/wDgxf8Aysc8wy6muZ4Zff8A8A7a7+AngW8yZGvVJGCyTKCf/HaoN+zH8OXBV7nUyCcnN0v/AMRXH6qskqhBeNGv3U3OfmrY+Cv7K/7Rf7SviePRvgz8M9b1x3fynktY3WNWX+JpG+VVrN+Ivh7y8z4cp/8Agxf/ACsn+2MsjK0qCXz/AOAasn7Lnw3kIzd6qMYwFuk7f8Aph/ZV+GRJb7TqmSck/ak/+Ir7C+DX/Buz8Xbq3g1v9o7456f4ZhcsZtH00m8uFX/eX5Vr6D8Of8EH/wDgn9ocMaa/4p8ea5IyrumbVBAu72Vf4a8yv4ueF2GdpcPU/wDwYv8A5WaU8ywtX4MI3/Xofl5P+y38Nrn/AF11qhOc5+0pn/0CmSfsp/DGTGbnVB/u3KDP/jlfq/cf8EQf+CdMg8v/AIRnxdDuRv36+KnZt396vOfGf/Bv7+yjrDk+EPjX490hPu7JZYp1rmXjP4VPbh6n/wCDF/8AKz0aGYUlLSg0fm/P+yH8K7mQyy3msFj1P2xP/iKYP2PfhQCWN3rBJOSTdp/8br6q+Lf/AAbwfGrRklvvgh+0Zo3iaBf9VZ+IEktblm/u/L8tfH/x0/YH/bc/ZzkuE+KvwZ1qK2t5f+Qlo+bu2aP+9ujr0YeK3hnV+Hh6n/4MX/ys9nDYzDV95cvqjXX9j74UJ9261f8A8Co//jdSw/sl/C6AbY7rVgM5/wCPtP8A4ivBIJ71L86Wt5NFKv34Z2dW/wC+c1p2IvlYb9Tuf725pDWkvErw6cdeG6f/AIMX/wArPZoYJV43jP8AA9xP7L3w2IIE+pjLZBFwnB/74qZP2bPh4gws+o4/6+E/+IryJEktlBW5lLSfc2yP8zVoQT6nGDDPqE25v4d527a5ZeJ3hx/0TNP/AMGL/wCVms8vqxdnL8D04fs3fDsNkSah7j7QvP8A47RL+zh4Clk8xrzUx7C5THt/BXlqGaSTyLy7ddr8t5x3VQvJrpTsS4lx6+Yf71S/E3w3f/NMU/8AwYv/AJUeXiMOqbbauesS/ss/DSZy73Gp5Y5P+kp/8RTJf2VPhlKQxutVUjptuk/+Irxa4vb6RnH2112t8+1jVSW6vZGb7NezIP73mHbTj4neHD/5pmn/AODF/wDKj5nF1sHTV5UE/n/wD3F/2TPhhJy95qxwMf8AH2nT/vik/wCGS/hbgD7TqvAIz9rTv/wCvFI31G4VVS9uA2cblkO1qe1ver88d9M5X+HzDWs/E/w6pxV+Gqf/AIMX/wArPKWOyxy/3Vff/wAA9n/4ZH+Fe8SG41UnGObmPken+rqB/wBjf4RuxJudYGRggXif/EV43u1JoykM83zbmSTzD8tZd42o5WP7bKHb7zLKf8aqn4n+HU3/AMk1TX/cRf8AysbxeVf9Aq+//gHuo/Yx+EIGDdawRnJBvE6/9+6kT9jz4UIjILzWMNjP+lx9v+2dfOEs9/aXYZdUnQ7vutK3+NSf2pdqWlTUrlpG+bb5p/xreXiT4eKOnDdP/wAGL/5WZRzHKnLTCL7/APgH0jH+yR8LovuXmsfX7Yn/AMRU9r+yx8NLRNkdzqh92uUJz6/cr5xsb/VJbjzprm4jVvmT5zXRaHHeTRPFPdyOVbP+tO1qUvEjw7ir/wCrdP8A8GL/AOVl/wBo5Y/+YVff/wAA98sv2fPAdgu23m1D6m4XP/oNaEPwi8KQLtWS7PuZV6+v3eteUaIbidQq3TN+6YL++KqrVvaLcX1orPcK5eMqPMOdsi1nHxG8OZO64ap/+DF/8rG8zy2l/wAwq+//AIB6LbfDzQrU5jluD6hnU5/8drWttOtrTTxpsW7yghXk84Of8a4eyiu4lSZp8+Z9zaK7DTVdNAVZcKwibJJz681+l+GfFvCecZli6eAyaGFlChOUpKfNzRTjeD9yNk7p3122PVyrMMFiak1SpKLUW9+mmmwg8Naech3lYHHBfHT6AVYGm26xrEC21egAAz+QrJWULue2D+rw5/8AHqtFQkQfcERfv5NfnUfELw7Wi4ap/wDgxf8AyszjmmB6Ul9//AJxoNiu4K0gDMWI3DGT+FVbjwVotyhjlEpBOSN/f8qfLa3Lzec0BdF+bcx27awvEdrKJAyySB4fRvl2tTXiF4dXt/q3T/8ABi/+VnZSzLD20hb5lm8+EfhK92+d9p+X7u2UcfpVKX4DeCpozG9zf4Jz/r1/+Jrltbnlt4HNsSyjcrLuK/8AAq898Q6tco7RR3Eqsv3VEx2tXRR8QPD6e3DlNf8AcRf/ACs64ZlTteKPXpf2afh3KBvuNT4IIP2peo/4DUcn7L3w3lJMl1qhDDBBuUI/9ArwaTV76NvJhurj5fveZKfu1Vm1TUmkXZdSfN8zfvD92uuPHXAD24ep/wDga/8AlZlWzanCN3G/zPfH/ZP+GUgO6+1fLHJP2tM/+gVBL+x/8KpQQ17rPzdSLxOf/IdfPV5rF8JHb7fOuf4vNP8AjWdd6vqjReVLqE+xd3Kyn/GtFxzwGo/8k9T/APA1/wDKzya2d4KMbulf5/8AAPpOX9jn4UzIEbUNaGO4vI+R6f6vpTof2PfhTbqFjvdYwO32tP8A43Xypca3eyMTHqVx8v8AC0zfL+tOttc1adkji1ScH+FhM3+NJ8ecA/8ARP0//A1/8rPOeeZZf/d19/8AwD6xt/2TvhfbYMdzqvyrgZu0OB/3xVyH9mr4dwjCz6ic9Sblf/iK+Y9F1q+df315cNIv8X2g/wCNdDY6zdzXCma6kVdm5VaQ1jPxC4BTs+Hof+DF/wDKx/23lslf6svv/wCAfQ0HwE8EWyhYbjUBtGF/0heP/Hamg+Cfg+3IaOe9yO5mX/4mvC4b+/jjEiXbyt95f3x+WtTS9YmbMM1wyurbnXJ3Vzz8Q/D9b8OU/wDwYv8A5WdEc2y/ph19/wDwD23T/hh4e01w8FzdkgY+eVTx/wB81raboNnpWowanZySLLbyiSPLDG4fhXjlnq108CJFM7H/AGWNeqfA7xbpug+PLK/1WTbZxyrvMi53L/FWdTxE8P1C3+rdN/8AcRf/ACsl51l8XdYdff8A8A+lfD3/AAUV+Pfhf4fXPw50bTfDkdpd2pt5bo6bIbjYVKnDebgHB9Kwvgp+2h8VfgBoWp6H8OtF8PQtq+BqF/c6c8lzIoOSm/zBhT3wBmvvD4kftGfs1fFP9kbSU+G0Vkuv6IlvLp6vZLHI0kf3scc18taf+zB8bvht+2d4V/aV+NN3aDTvF9x5ljamQPujWP8Au9F/2a+fxniT4Y0EpLhalLT/AJ+JW/8AKR6WV5zg8x5qc6fI77b3fTseReNP2qviZ48uWudatdKUs+4Lb2jqFPtlzWIPjZ4x3ITDZEIcqhhbb7DG7pX0n8fLPSjq19NBaRrKZd8iLEFIj3bvSq/wk0q08QrNNFpKKscW7aYw3/fVeLPxZ8K1HXhKl/4NX/yo+mp0/aHg9v8AtI+MIbt7648NaDcytAYla4sXYID/ABKPMADe9ef+LjaeNdVOr61pluZD0WNCFAznAySf1r7T8QeKvAvgnVEsLzTLfUXKM0qraqyw1xl74i0DVll26RaM3zPueMbYa9DB+KfhhUhePCtKP/cVf/KjzcbKlRnyyhzHyK3gHwizMx0SLLnJPOemOtZ158IPCV4csbpOuPLmAx9OK7f9pP4xSeHrddG0bTHeOXc3mlwBXxr8Q/iDrN1qRtri8m2yMxz5pK7q9GPif4cyjpwvT/8ABi/+VHnzxOAo6ypJf16H0Bc/s8eCLh941HVY/aK6UD/0Cq4/Zn8AgY/tTWMYxzdp/wDEV8j6n4x1J2kha9nP+15p/wAa5a88ZaxPOiR6hdeWzbX3TN/311ran4i+HFf/AJpen/4MX/yo4qmdZfTdlSX3/wDAPubRf2cfAeh3K3Vvf6rIy9pbpcH8kBrudCsbfw7fLf6cmHUABX5HHevFfhx/wUB8P/sw/CbRfDPg+K0vboWbf2neXdos5mZv9+ty9/4Kk6N4n8FC70qO1h1Bfv8A2e3Cttrkn4k+HUXpwnTf/cRf/Kj0qeLy1K9op+v/AAD6D1L42+OdV0X+wLme3FtkYRIyOn/AsfpX05/wS8/aiubT4lR/APxDooZPENrJBpF7ZqQ0U6RvIfO3PypVWAKjIbHGCSPx/P7WfirxL4qPiPxD4gvrmeWXazXU+EZf4V219u/so/FJ/AHxL8HfFVSD9mMVycNgESQkHn6Oa+jyvFeH/HvDmcOlkUMLUwmHnVjOM+aXMoykrWhG1nHXe60sbYephcdSnToqz/qx+hPin9rrwf4B+IF78IvEOpLb3bRbYmml+6u7b92vP/E3jLSfiRpMvhW8mWaxVvkkZfmkb+Fq8E/4Kha54Y1r4Xr+1F4Pv47TWNNv4/tUa/6yaFvvKteN/s2/tOX/AIkuIEu9TuJ5mdVlWR/lb/dr+Rlzyj7WD92R61HD4eUOWovePqr4E/s9+LU8bPNo+pXFxEt/t+zzfd2/wr838NfUd5rGq+GvDcOlXmiRw3bJuna3Tay/w/LVD9kb+yNb0K31Sa2VZWbczRv+93f3mruPjSumqxSKzb5YmX5W+ZqdaMY0HJfEeVWlKOMVM8K8X302pXn/ABMkaTb/ABNXhX7a3iC80f8AZ1ltoYvJs9Y1GGCBZIt3mSK38O7+7X0N4k0220vRvt80bDd96T7rL/s18b/t2eMLzxJ4g0TwBczSS2Ol27XirDcbo1kkX5fl/vUcNYf6xm8ZS+yXneI9nl7ivtHz5a6RebW/fRhlTd+8StbTYXbZDbP+98r723/2anabazW80XmzfIz7WZU+bbV+G33XSuNvnNL/AH/4a/WZRhL3T4vDx93UntbeFbd32eUy/N++/irSW3ddqP8AeZfn8tvlqGGzcRs83lojP8ke6tOxsy37lHX5tq1PsY/EejGXL7plalpcLbpZtqN/EzfN/wACrI1HTXZfOSaTf/Ev8K//AGNdj/Zb+S0I3RFflaNvmqCbQ5mt1mFm3zJ/EnytWlOmpS0OeVT7J51daKjQO/kwzL8r/M+5mrB17QftDNc71j/56/3K9LvtFhj+eEbxIu1FVVrm7/QfMhZUtsKvzN5la06f2jzcRV908m1vQZomaaHb++2/Nv3ba5bWLV4VdEds/d3N92vWde0N47OW58narPu27drL/wDY1xuqaK8Lf8ey7Wbc8a/3a6adOMjyKlM861bSxHCR8zNGv3mf+Jq9S/ZCs/sdrr8ezH7237YzxJXIavo6bXR337m+SNq9B/Zjtmt4tdLoAWnh4H0ev03wjv8A6+4W/ap/6bmdnDUYxz+lb+9/6Sz5v/aAsUk+K3iQgr82sT7lK/7ZryTxBpPkyH522V7v8b9O874k+IZCmVbVLgHcvfca8p8TaS7Yfzm2/wAKtXxnEMf+FvFf9fJ/+lM+czDm+u1Y/wB6X5s801Sz8ubfsU7qghtWkVnxjbW9q2kvGzb3Vd3zKtUo9Jdm2P8AL8n3q8bl5feOMpw2TyZ+fH+1VuK1eGVJH3fd2otatjo825fITen+1WvY+H0umWaZGT/Z2/dqOX3dC5HP2ukzSSbI9zbf4a14NBmk2pD93+NWrpNN8NqyB4flRU+WtPS/DbztFcp87L975avl5/dI+E52z0Py9qeSw/2q2bfR9pXbw395q3F8PiOHe+1/+Bfdq9H4bm83Yib41/5bK/y7qylzco4mJY2tzCqf6Nv2/NtatjTbFJF3um5m+Zdv8NaFnod55vlodqt9/wAz5v8AgNbmm+F3VVZ7b97/ABL/AA1hKMzppmRb6G9xILxE+RZf4aW60d5GfEOP9n+GuysfD77Um8vCw/M1X/8AhG7U/f8Allk+ZGX+7XLU8ztpy5ZaHmFxpEMg8l7ba33vmqhLo26Rnd1G7/VMv8Nejal4XLSP8mX2feb7tYmpeH0t1SFId7b/APdrKPx+6dMZRl7p7akMLSB5tu5fuR7Pl/4FUFxbv9q2743iZfnZfvVsyWr21r9pSLa6syr538S1W8794k0MOz5NzfJurzJUT7SMTGuIUt5DDN8rSfMu1fvL/tNWdf2Kecr20ioNm7dJ/DXTahbJcLvSzZhIm5v96srULW2aNYfmZ1/h2/w0nS5dUKpLlic7q0c0cbpZzL/e3L826ufvo0C7PO5b70bV0lxZ7l3ui7du1N3y/LXM+II0s2MyfIrN95VqfYyUrHFUqR+0ZepTfdm379332/u1Ta4/5Y+cp3fxU/Up90jSQp+62/Nuqrat5KfvnjxsVUjVfu/7VbxjynnSlzS8jYs2maNfnyq/3V/hrZ09khh3I7Jt2sjN96uZjvNzeS6cK/8AC3zVu6Sv2p/JRN38XmL/ABVjWjyxKoyjI6zTbxGhS6mm27m2NJWlDqFt/qfmdY93y/drnLOR4YUSE4TYzbf7zVaW8ttxvPJbzW++y1zcvvanVzSNj+0N0LIlsyuqfd/vf7VUby4cR75tzr9146zrjUpmZXeZY23bWjZ/++ai86ZSZpp1x8y7d33WojGZUqkuh7D4eYN8F5GQYzpd1gf9/K+c2uEdlTfsl3fd+8rV9DeF23fAt2kO7Ok3e73/ANZXzVqV1+72I67Nu5l/2q/fvFayyLh6/wD0CQ/9JpnTn7k6OH/w/wCQ/ULhGVjN5jOr/wALVnX+sRhWSxdQn97+KorjUIUVnRFV2+/uesa81ZAqv/e+7X5DCjzHy0sRLk5TZt9SkuNrufmX+791qbc30PmL/pkjt95l/hjrnYdYeOZk879yz7U/u1dutQhmhDw7gm37tdlOPKYSr8pozXUdxGN+3O37yv8Aeao47qaJWS2fZtbayt/FWTDqW24fjejf3m+7T11Kb5od+U/vMtb8suU4albmlc2luEaTZ0H8G5qsLfTKPJR9jf3q52S+e14++f4Ny063v/NV/wC8z/8AAqcpfZFKp7v946iPUsMUd1fd9+rNvqTzM/zrsh+6q1zUNwZG8t3Yj+OT7vzVo2d88jb/ADFwybdy1zVJTN4/zHV2OpbpVCXP3k+Tb8taul6pt2qjybl+bcqfLXJrqCWsMUe9f/Zv9mtXS7yZV3vMrbfm+Vfu/wB6uKodtH4jt7fVJmhT9yoT722N9rVpLrW+3857zczOqvIyf7NcVZ6pDcKyedtVf+ejVYbVHMaOkzMzfNtj+WOvHrLm1Pao1OWB2C6ptVLmNP3jK3zM1Mk1TLM73O/7vmqtc8uvPDZ/67BkTZ/lqkXVpolb/pomzatRGnIupUgdCtw8krI7ttm+5SrdWcarvm+dV+dY03Vi2987xqjvIpV9v+1t/vVJb3CXEh+fzd25Xm27dyrUezI9pD4S3NdJdq800rNE391dtYV800sazW0jJ95XVv71bWyGaFX37hGn+r3feWqN3bvHC7vtZG2/u4/vVcY8vuhJcxzupzX7R/Y3O9933f8AZrm9Qt/mmSaZtq7WRW/irsL6F4W87yZMMn3v9quf1zT0kk8t4d3+0q11UakY+6jklR5tZHL6havDJshdn/2v4dtYmpfKzTbPmX5UbZ8tdRq1r5e77u1fvVgatMgGx+iv8+3+KuuNTmmOOH5o8py19bzbmf7rfwKy1n6hbO8bBPmffu+aty+UyD/U/K3/AI7WXf2TyK3zso+9XbGXumNTD8pjzK8ch9KW1t3jbfNHt3fNVjyUbO/5v4qljtQzbHfedvy1pzcpz+xn8RY09X+byUYN/eb7tdDpdqlrcRbE+b7rMv3aztNtUh2edCwbZu/3q6PS4Ukj+eFW3fcZkrz61aB0U6Muc1dPhRdjpu3fd/2d1dDZxzRsm+RQ+z7ypWPYrCIvJy3zfc2/w1sWcfyMrzM/mfNu/u15sn73M4ndGPL8JrWavHH8k33v4mX+KtXT1DK37rfFGnzMv96s+xaa48uFNp2pt+X+KtSxV2/0ZwuPuurVjKXu8x1R980IUfa8Lw7yzbauTrM0cUybc/d27vu0Wq+XiaaH5fKbbHGn3lp+n2u0lEhb7/3mrl974oHSuWOjkWbPzrVUdEXds+fd81WrNXmZJrZNjbf3sci7lqOzhmhQu8KuJN33m/8AQa19Lsd0iujtsXa77f4V/u1pCXvSOyPN7L3S/pdq8W3y4Y9n3ZW+7/3zW5p+moq/vk+78vy/3araLps1uqrNc74t7NLuXduWugtbNJpFeJFcQ/LXp0o+5eJl8MinHYvJMuxP9Z8vzVp6PpH7v5+rfcXft27atLp6RhU3q5X7kcK7latezsvL2vMjb/7u3+L/ANlrrhKNMcpSlIrf2Z5liNm1U2NvVv4akt9JLfuYduzbu3N/erYt9N87fNMOI2+Vl/ib+7tq3JH9ojX7TtRdi/KyV3R5Kkipe7H3jnV0Pdcb/lZvl27vvVV1DR9sgR0ZQrfvWb5lau1hs7b7Q0yWfnPG219r/wAVMutJdpi8f3lX5GZ/l/4FWsfdkY1pLk948x1Lw7H57hE4X+Ff9r/ZrDvtO8jbbTOsI2/uvlr03UNB8qOW8dP9ptqfe3fxbq5bxBodnJL8/Rv9VtrlxFSPwnnxlCUzzvUNNk8yOKGNVbc3y/e3f7VTeHfh7r3izWo9B0S2a4mvH8q1ht4mkaaT+7tWuo0LwFqXjTWLfw9pWiXE13cOsEEdvFueRmav2S/4Jgf8E0fDH7Nnhiz+J3xLsYb7xdcRLJBG8S7NNVl+6v8A00/2q4oyVSrGETnx2NpYWlJs+f8A9gD/AIINaPdaNafEf9ryBnE0Ucll4ahfDNH95fOb+H/dr9B7X4f+Cvg54XTwV8NPB+n6Ho8UW2Kz0m1WJdv+038VeoMqbCBXnvxm12DRrAtM+0fxf7Vc3EK+rYHT5nzeBrVMXjo855n4x1+3tsrEGl2/8865STxBCzKdi7G+b723a1ZXiv4laJBIYUv4dzK37uR9tcRJ4uttVulvBqXlIr7dqv8AK1fkmI9mpn7Fl2DoRpe8z0m78SQiEfZrjLbf9X/do0/xZpzolvczNE7My/N92vL9Q8bY02Qw3MLlpV23CvuVVqjp/izVbP8A0bUvLzHL961b5WX+GuX2nLC6PVjl9CUfiPZriaCKY3KHzpP+WSxvS/20n2WS2uYVlST5fJkTcrf8BavGbHx5r3h23vtS1XWPt8Mcu6KG3i2yQru+7/tVtW/xOmvI5X8hlVov9HkZvvf7taU6s1Exll8Ho3cpfG79h79i79oBoj8YPgjpbX7RNEuraOn2WdVb+80f3mr4u+N//BB3SNHvH1X9mT43yXULK3kaD4si2tu/hVZl/wDQmr6/1r4qPafZg6NdPJ8sse/ay/8AxVTQfEabT1uEnuY5Ujt2ZPJl3MrV6WGz/HUbwvzGdHDTwsuejOSl+B+O/wAbP2Vfj9+zfNFD8Y/hvfaYm/Yl9Cvm2kkitt/1i/LXDXFuG2wwzKV/jbf91a/dSPxponjrSx4M8c6VY6lpVwn+n6feRK8Uy/8AAq+Mv22f+CS3hHVLCb4xfsS6kbcKjPf+A9Vus+d/e+yP/wC02r6TA5thcauSXuz7Ho0c/qxfs8XHT+ZfqfnrdfuZAg8tlV22M33v/wBmse+WG4bdvVdr/PWz4m0/VfDuvXPhvxVpVxpWoWcuy60++t/Llt2/2lrHutn2p0f5D/E38Neh9qxljcRSr+9CXumX8m50toWHz7mbbu20v2G5WbZM6qyp/f8Alar9rH5URTbhl+6396plt0mm3o7bf9patS5ZRsfHYyn7TmRX/s879iW+3zNvzU5bPdCzJ8qr8qLHWhDZzbQ7wqgXds+bczU63ieNj5MPyyfP833t1Epe0PI9nGNjEvrHy43mcNu2bVWsXULV418wR7WX+Jq6y83rMd9tyzf71YOoW94uoSvsjxvXb83/AI9XRHl5tCfZ+6c7cH7ZiZEX+9uZPmZqqLHuk+f76/M6/wB2tK8017iR7nzvm3/xf+y1TbT5oZGm2K5k+5/drpjUjzcsjj9nIls43vLhXd2/dsu1Vau40m3RdtztU+Ym35q47SLV47hHkh2uv3o67jwrb7m+0yfNtT/Vt91q1jL3NCffOi0m1RWG92RV+Vmat/SVeQN9sdfJVtiLN8ysv+zUOhafDN/pM0zLu2t5ez71dDp9i8sf75I/OZ/kj2fw/wCzWkTjqxl8UR9qrRshfzHTYu+Rf7392us0Nd3h5FBPKP8Ae69TWHp9j9nkV5oWVlba3+0tdHZIY9OVGIYhSCVOQTzmv3TwPi/7azCX/ULU/wDSoHu8Nz/f1V/cf5ozUhmW6L7/AJpvvtJ/6DVuNoZo1mgRVf5vu/8AxNPhhWGTzpkm+58u1NzbqfpNjtdrxU+f+JW/hr8ajT92585HFDLiN7m3Xypmf7y7Vb+GsfXLebyXd3Zm+6jKn3a6C+V7aFXl8tP+eUcaVgeJp3s7d32KAvzbf4q3jROyOYe9Y4DxUqNayOlyzLv2/wB3c1eYeKrpJLr50ZVVtrxr/DXpfi5PMhlSFI96/NtX7q15h4q3sxn+6rfM/wAnzM1dVGMInTDMOWNkYd5JuXekzRvu+b+KoGum3K/3V/iaq1xdXKyOm3dt++1V5fOZW+fC/e2q1dUfdicWJzKUpDru42yM6PGRv+9WPqU3mSedvZTs/v8Ay1PfXDyDy0fDN9xttZl8z/Km/d/e2/xVpKJ5dbGc3ulZZvLk+cKy/wAVT6XfbZmk+b/4ms+6ZJGCb1H+ytLZ3CfKm/b8/wB3+9WUo8xx/Wpc2h0+mz7ZCiOx3fwt/DXQafqSRxgvz/erjrW6SOPY/wB37v8Au1uaTcfvPJeeuWUeVs6KOI/mOr0+4hgk3w/8Cratb7z5vOeZmZfvfL8rVyNnefMmblSrfL/s1uWOpOZE+dW3LXFUj9o9CjWlsdj4fvPtEfnO6p833V+9XQWerfZ5A6PIybNqN/drhtPupvkwY1Hn/PIr7WX/AIDW9Y6ojM0cm3zf4JJP/Qax5Ym/tOaNj6W/ZF8Vf2l8QtK0HW/EO+1k1SNGhV9sX3q/Xb9r74e+H9Z8J+HvEtkzEeFrWJrWRW+WNWjxX4a/AnUrmHxxbTWcMnmNcQtF/F8277y/3a/Yz4i+NPFWtfstaD4q8T6fOsGsWq2cDN8v7yNfl/8AQa8PN8LX9leEeaJ6GT16EsbBTlyyufLXxx8VQ/8ACSBHeSWW62/dbdtrqfgvZ2Gn2MmL9T5lvuZVavF/id4sfT5Gmd2edpVWWaR/mXa33a7X4V+Mkh8M/b5rZYUZGRmZtv8AwKvz+o58vKfqdFx9pZnOftAePLDwrqypYXmfOn2Iqxf3v4q4m1+MGlaTp8t5fpsiji2v/emrjfj58WJv7cub+51KF910yxLs2syr/FXzr42+MlyrN9muZPMV2bdv2qu6vWwdGXLFI8zMqkOaTNb9pD4wQ61eSXXnSS7Xbyrf7vkrXyz4m8QzXl083nf8tWZVb+Guk+I3jq/1dX+0zSOzP88m771eYa9rgW48lNufup/tV9Hh6fNLlPgMxxyjLkLPmXOrXC2dr5hdn27q9a+GvwF03UrEf29tt3b5vMk+ZVrkvAdvo+kWcOq6leR+dJ/D/dr0HS/FifYXSG88pN23cv3q9KVSNP3IbnnUY+0lz1TE+JX7H9zqelteeGNYhl2/fhWvErj4K+PPDd43+gSFVba7R7mr6x8N+MLaxhR01Nm3L86t93dWlofiDR7fWIRNp9vMjfM7Mn8K/M1XTx8oR5ZRMsRgYzqc0JHjfwD/AGcfiR8VtcTw94e8MX15eQv88KxfMv8AtfNX2bf/AAw+I9/4Lj+Evg/daeJYraGwi+XJimi2rIMD0CPXef8ABLv49+Fda/a41WbVbW1SG4s1gt2ZFVV2r/dr074NXmk/8N8C/wBQt0ktD4x1N2jLfKV/0gjn8q/Y/CXFUa2U8SrltbCTv6ctQ+k4bjVpUa8m/s6fieB/Hr9jX9oHRf2XX0a78YXGqPI0dxq/mbmdo1+7GtfL3wV8Val4B8UR2E/mW81vOq/MzfKv+7X7+fH7SfDHijwf/ZWj6bCkFwu+VY13bv7u6vxT/wCCj/w3h/Z9/aKtNbs7Nrey1iVtyqvyLIq/3q/nn2dCdL2dM6KebV41Y1JS8j9LP+Cf/wAZH1LS7W1Fzsm2f6xpf9Ztr6f8Va/ZeI/9PuUVHZtyyN91a/LT/gnv8YodWkhtt8aOrbEkWX5q/QbRdal+xw2d75yeXErfvPutXz8uajTlCZ9Th5fWK/tS18WJIbXQYbaZ98HzNLtTd/3ytfml4w8RW3jLx9rGtveb/Mv5EiZm+VY1+VVr74+O3i59P8A6hqt5NthsbCaVVX5Wb5f4a/OHw/fvJZwwzbklm3Ovyf3m3fNX1PCGFipTqng8RYiPtYUjbs2hkhV0RXZk2vIv3Vq3Y2r28wMKLI397f8ALtqG3unbZNv3tu3eWv8A6FWto9vux5033l3fc/8AHa+85InjUakeTWRoWOn/AGrEyOy7XVvu/K1aEGnpIzzpMp3bm3fd/wC+aZp9q8iv+53N8rJGzfL/ALtbFrZzKzFE/wBd8m1U+7/u1py+4aSrc2sfskFnpb/fuSqI3yqv+7/FVmTT3/2m2pt2r/7LWhptil1tmufluG/iZ921au29vJJbNM6ZH8G5fvVrTjDYx9p7vMzjtQ8PwyMUhdYi23ytyfN/u1z2peHZrhZofs27b/tV6Hc6a9xJ8ltuib7+75tq1Tbw3NHMvkosKr8ybauNP4TmqS5o+h49rHh3c7w52uybdrfwtXJa54Z+8iJ5bq/9zbur3LU/CrpcSvsb92+5ZF/irlNU8JpcSPC9hI7796SN/DW1OPvHj1qh4xrHhHMZhRFxJ/EtdD8EtKGlDVI9pBZ4c+nAfpXSah4ddt1sk0e6N23KsTU7wxpLaWZy2QZQjFG6r1r9M8J1/wAZ5hX5VP8A03M6+GakZ8QUv+3v/SWfP3xe8NJdeMdYmhdhNLqMhTC/7RryfxN4T2tvuZmO776qvy19K+P/AA3Nc69eTblbzZ34H8K5/irzPxR4UtmWV3tsiRq+Nz+N84xX/Xyf/pTPnMfL/bqv+KX5s+ePEGjuZm5xt/h2VQt9Jm3K6IrN/tf3a9Z8TeD0VWuURh/s1zDeE7lZPkTf/stXhSic3MjK03R52Vk+X5v4q6bS9BRdruiqdu35av6LoM7L89tt/urXT6P4bdpF3plF+9HWXvS90rmM3R/CP7tXg2oWet2LwPbQyb02uqxfPtX5lrp9F8N20atvhkd/7u77tbdrocLTBHSSIt8zxx/equXlkZHBx+Ddyslmm5Nu7cy/NU9n4Zm270g+X7u1V/ir0q38N/a0byT8kcq7vk2s1aVv4Pe4X5EYf7Ozaq0csJEylM860/wS/wAvyNvXb/q23bq6LTfDKK+zydzr8qrJXoOm/D37ORMlg3zffmb5t3+1trX0rwKjXUk0ztt+780X3m/hrOVM2jUlE4HT/CLlhM9mw+XbtX7tXJPA9z9o2THYrfLub7q16NF4LS6VEHyGN/uq1adp4HsxGLZ7NijJ95q5qlOR1RqRPINS8EOqv9mhWVfK3Ksf8TLXNat8Pf3J89PMk+83+zX0JdeBbYLLM8MYeOL5WZPmWsLWvA8MjP8AOq+Yu35Yvut/tVEqfMbRqfynKQq6xqiSbW3tvaR/lWoJN9psRLbeJmb95G3y/wDAqJrh7ebHzGJlZU3fdX+7WfcahcybtiNlX+f5/u153LKJ+gx7k0cfnTK77c7mZmV6rapZw+T/AMfKxBv73/stTx3bvvezEKPs+X/d/wB6o7i6hffLc2yod6ruVt22q9nyrQupU93lkc9qVm7QvvSMoybfm/h/2q4/xEqNHMj7f7vmR/3a7e+leS1dLPbvbds8z7rLXHeKIY5tyfZsKr/P/D/vbaz9ieTWjy+8cPqTeXJs3sRSxzWzbfX7vzfxUupLFHmZJmRpPmT/AHapfbELIkPyv/z02/drKUeaBy832jbsZE2kof8AvqtjQ2kjkPOxPvLurnNNmkjVIXnXH95vvVq2d0kjCaF2YbG+Vqz9n7vvExknPmOh+3Ha77ONn/AqsrI8kLJ9xfK+833V3Viw6hDNC9tv3fut23+7/wACqWK6hhYW2/5VTb8zbqj2c+W3KXCpyyuWLiR7eP8A0lN+3+L/ANmrO1G+mjs2SF9xVdybvvN/tVYvrrcvk7ONyqjM9ZerSOtw77NqMm3ctVGMuawqlT+U978FzrP+zs06twdFvMH/AL+18q3lzDHEPsyMu35d26vqbwQY/wDhm19jZUaJejP080V8malMk2dkPz/e2/3Vr968VoXyTIP+wWH/AKTA9DP5JUMLf+Rfkindas/2hYXdWP8AeWs3UL7ywV37tvy1DfXXkyO/mY/u1kXmqpuw82HZv4q/I6R8TWrcpZutQSPbsdgn3tu+rEOveXbhEfd/tL91q56bUk3F32qFam298nzP527+8q1tHzOb2k/iOqh1JJJFeF1fd/47U39pbleFvutxu/2a5nS5N0i7H2lf7z1rR3CfKh3H5K1+GRHNzGqbzzmV33bl+/8APSw3E0395d3ytVKFk8zf/A38X8VXLRZ9rJv+9WUpFU/i0NKzkf8AjPzfw7auWt15cfycf7P92s2CZ4ZBDN93+9/DV21bd9x2K/drGUf5jvpx6m5DcLMyb9qKv8S/3qvWd9tmHz/KqtuXd8rVh2+FVZJ5lRGb5a0FvCxKb1Td91f4q5pRgd1Pmj7xt2t062aOj5kbds+T/wAdardnqMaQ7E27v4925lrm/t00e75Nu75vmq3Y6h8qI7L8rbkjrz60Tuo1I8x0C3DzbbK53Oi/d2p/47V5bj/SEmtvMRvvK23dWDHcTLH88zMv8XzVow3Tqqu4bH8ar91azlGXLoaVOU3JLqZSgQMoaX96zL96rdrIk0myFF/h/eR/8tKyLOZJr1EmSR0b5krUtYZo1M0PyIv/AH1urCUY8vxD+KZdWPz4diOqbX+8v96i8h2t9mR28qR12bfm+anGbdboju33P3rSfKtPVrxlGxGQqnyfJuXb/d3VnU54+6dMeWWxkXizLu8mXzPJRlRv4axNQt0khd0uWyqszLXS6hY+Ssps/LEf92P5vmrDurVwoguU/wBr5U20ox+0Wcvqdu6wujwqtxu3bpPu7dtcteWrxsXm5rufEVq6tshTc+35P7tctdWrzSO8MKvu+9t+Va66dT3blyjy7HKaxazblWN2Ufe2/wB2s26h3Mfn3N/erevLH7VMyP5ny/w1VuNPf+//ALq12U6nLoc/LzGB9lQbkT7rfxN96rljY4aMuvP92rbW6blQRqzL83zLV2xs/wDlm77lZN27+7SqVv5S6dGMfiLGm2Matv8AOVpf7ta9nCnmB4UZd397+Gq9nYwx+U/k5f7qsvzVqx2T2u5H6fe/4FXnSlE2lTgWre33SK+zDr8vy/xVqafC8c3nQpu3Ntb5Plqrbrtk3q+VkT+L5q1LGN1b53w/y7Y1p83LDQ5eX3y9p9rdbvkDff8Al+f7tb9nGgtxv3Ef6tNy/NurJ0+H7RtTfIEk++392tiyZI42tkmb5UVfMX5vm/3q4pXlL3Tqp+7ys0dNhmWREm2/IrL83y1pbf3iwpyv8W3+H/ZqnYx/apA86MzzL88jfdb/AHa2bRd8Z+dRti27WTbub+7WfNyxOmO4/wAmGSRZNm5mVmRm/hWtLS4UWWJ4dxXb8jM3y/8AAqo2zIyqkMMiyfxbvu1saLb3N5JFeQphV+VFV/lWrpxh8R0e0l9k6DTWhktv321om+55db+l6b+7R027JH3P/wDE1k6PapNEiTJ8zPu3M/y/8BrptJs/OZETb9752/vV6WHlze6c8qnNEsafpKQwuIYWBZtyNt+7WlbxusgdE3fLu+5T9PhuYY1h8xn2pteppLNI03zbirfLF5f8VdNPnLp1CXT5vm2eWwb+CSNvlqSPeszbHbZs2vti3f8AfVQW9ncxsz723r/Fs+X/AHa09LtLmGEvv80Kvz/Jt211xly+8VKX2h0Nl5y+dv8AvfcVk27f71T29i/l/Oih/vfN/FV61017hdlzNGwVF/1fys1W5rbFvsL+Vu/4FureM5ROSp70TktWhhlkV7kLtjdt8bfN/u1yOqad9qk+xzIzpvVn+WvQdUt4ZLaXf+7Vk/hTdXY/su/CVPFXixvGGt2dvNp8O37Gtw/+sZfvf7y152ZYilh6UqkzjjH2MD6N/wCCX/7IGm+CJE+NPxJtrV9YuNy6Tbybf9Fh2/eZf7zV+ieheI9KsLSO2u7lYxt+8z/LXxLp3xqs/DP+gabND5zQbPLb7qt/D/47XP8Ai79rTUtr6gqSW4X9xFIt1uVmVf4V/hr4mjm2JjjPbQPMx1OOJgoyP0Sutc023sft7XKiLs+75a+Yv2sviheWWl6q+k38OIWy+5vurXzov7fHiSPQbTRL7WFjSafa0kn3dq/8tF/2t1eZ/tIfHh/EngiXxDo9y13Nbz+VqNxNcfNMrf7P8K17GMxk83oq552GpxwdXnOM8ffHC8utUkRNV87zF27l+ZW+b7u7+Fqx7X44X9nb/wDH5Mkkn3FX5lavEvHXxB022b+yra/aSZn37o/u/wDAazNN+IU1hZ/Zv7S8pVfa/wDFXx9XLakp8qPtctziVOPxH1N4d+Oty9vs1W5VE2fuo/u7v9qpbz4i3PiSN7Cw1j7P8isjN95a+XNP+KUN9Iba5hZHjT5ZmlVfmWut0v4lQ+IIYrl9eVJWRvN2t821fu15OIwU6J9TRzql7I+jtB+IFta2z6bf6/5vz/vfl/8AHant/iRZ2ObOzv5PJ83dAzPt2/7NfPA8aX9vavDYXKjzt37xvm+b/ZrO1b4ieJNF0+K5h1iSRd/meTMm35vuttasPqs3H3RfXnUlpI+jdS+KVtqEySJNveFvk/u/8CoX4kaba3CTWfy+c6q21/vbv4mr500/4mQ6q6PDeMjqm64Vfl3VteH9evLr7keXhRl85flX73ys1ZRw/vHVHE+0peZ9IaT460pZP9JuWhmWVWabdu/4DXf+GfiBp6/Z3R2YyM32eRXX7v8Aer5f0/xU8McRmdcM22VYV/i/vVreD/HF5HYyLbP5Kea3kbf+edTOi1PmpnHWrQ5PhPRv2xv2J/gb+3F4fhtprlfDnxCVW/snxdGi+VI38MNz/eVv738Nfk38afg38Uf2efiJefCX42eFZNI1rT7hkRd3yXi/wzQt/wAtI2/vV+qdr8UvtVpbw/bJPI2/e2bW/wB2q37Snwx+HP7ZHwVk+G3xIto/7b02Bn8F+JpF/wBJ0+Zf+WbSfeaNv7rV9nkub1eT6vivlI8lVquGnzUvh/lPyUjhfaqbMn+D56u2qoqNC77lX7yt/D/s1qeNPh74n+GvjC/8DeMLNbe/sbpom/hWRf4ZF/3qoWqhV+f5gv3/AOKvYqPl0HKpGt7yLCtNJCqedt+dWX/apbXfNI01zDsVZdibqW3/AHKu8NywMn+xu21b8iGO3EKJvDfNub+GnGVonHKJm3kkMMZaFG/3W+9WPfW+6KV4fk2/wsv3q32hdWHmCPym+batULrT08kIhbDS/Oq/w1pzcsomfvnMzWIhX+JWb5vLVPlaqf2N5I/O8na3zfLu+7XSXFmJI/kTDL/D/eqrdaW8cf3G2sn+srb2nv3MPZx5TK0uzuZFH2aRleT+L+Ja7LwvYzW8yQ7923/nolY2n6Y+4bJtn8MUiptb/erpdHsZI2VJnbdJt+b/AHa7sPyyPNrylG521jCnyl5vNVUX/V/NXT2rfZ7z/XL8qfIyp/DWT4fhhmhRLaaHaz7kjjT+L+Kt61t/9HVJX+Vm+TcnzV6NOnCR5dat2LVrawybrq5m3Iqbljb71XraJRp4iRNo2EADjFV/nWVU8vDMm1mZPl/4D/tVctolhgEcW7Azt39evev3DwSio5vj7f8AQLU/9Kge1wxO+Mrf9e5fmiG38mb/AFL7Bt2qvzNt/wB2rLbFtWS2i+Tdtbc/zf7O6oWjeSRVSFtq/LuVquNYpHMv77en/PNvlr8g5mfHRqGdqESXAXZcyD91t2/wrWTfRzXUZ3uxTyt27+FttdDdQzX37mEsWj+/5ifw1j3yzeWqI8eyNNr7qs0jWl0PPfFy+XGUuX2M0X3q8r8UWvmW3nWbq0avuRmdvvV6x4wkSaFJkhX5mb7vzLu/vV5n4kjfa6Xnkl/vfu/lVWqoxlylxxB57fLLJJ8j7lb/AMdaq91JtjV3hw6/eZa1tQaG2ZvkXdu+fbWYypMzok+5W/i/u11fD7oqlafIY01w8kbd/mXYzJ93bWdfRvH++SH5meugutH8yRUcNhk27ao3WjuqMiRt8rbd33lWq5uX3Tikc7Mz+Z5OzP8AEtLC25jsTeG/h/2q0brR3WYL8zfLtqKPTdrNDs+9/EtTUj2IiuUfp8m2ZXmfG3+8v3q2rG6SGRJv4Nn3l/h/3qy/LRfkdGZl/hq3b/KrJHu/6Zba56kTppyN6zkfbvfaV27kjrStbrzI/n3ASLtrB02V7XbHNMy/wvurVt9nll3dv4di15eI5vhPUoy9z3TZsdWuYZEcJ91PvL/DXQaXN9ujWaYMwV1bb/7NXKwxzSLvR/mj+5tevUPgh8P7rxVqBd4WI37POZdrVz4en7SdmaVK0cNSlKR0vw71T/hD9c03xPeOyPb3Su7btystfuP+y94p8Pftq/sFX/ws0q/3a94biWXTvMX978q+ZDIv+98y1+O/xi+G+meFPCqabC6veNF80avu2rtrf/4Jtf8ABSXxV+xj8aNO1LXLy4m0yGX7Lf2twzN9qsWb95/wJfvL/u17/wBXpKjyo+UhjKs8Z7W56D+0do+sWsl5Z3NnJDfWtxtlj3/NHJ/Fup3wj/tWbwvc20yed+63xNv+Zdq/NXvP/BULQ/h/rnxc0n4/fCrVrS78LfELRo72C5g/1Zm2/Mvy/wAVeLfD3R0ghm037fsga3byF+6u3b91v71fk2d4L6pinBfCfuuS5j9fwEKq+L7R8V/tKfEy2s/Gl/C7srWtw0XlyJ825fvV89+IPHX26aV0ud7M7Nu316X+3pZ3/hn4jX9qjttml3Juf7zV82x6k/nb3dldf4f71e5luDpyoRkfOZ3mVWFeVI321Ca6mZ33YX/x6uY8U3U8OpLMi/w/I1aWm34mZUm+f/Zql4xXf5fOF+7ur0KEPZ1/ePjsRUc46SK9rr2p3GyFPm2/M9dt4Y1p5nSG5v8Ayv8AelrlfDekw+XvT7/8H+1XfeHdL8K68YrfWLNYivy+cvystd0vZSi00PC06svikd74T1DwlJCs154thVY0X5Wf5m/2a+hfgr8Ifhp8SvBtzrdt4wt5b2OJlt4Y/mbd/tV8leIv2edN8QN9p8E6rIVVdzR/aK1fhL+zr+1FHqyp4GuJi0m7b5dxt3bfm+7Xm1sLKXvUqp9HhYx5eSVJ/wCI+n/2bfgTrej/ABqS80fUoRcWsv8ArGn27v8AZVa988Bz6tp3xzjmjvSl5HqlzunzuO/EgLe/evizwX8J/wBtjUtQS80SHUIrlpWiaaOXazSbvurX1p8KZPiJ4d8WaSNPsBf+JrYiOSCVgPNuAhWTJ+u41+w+EWHqU8k4mlJ3vg5/+kVD6TK8PRhhq0YJpuL39GfYVn+0vNa6f/ZWvPI80Nvt27ttfAf/AAXU8eeG/GXw08Ia14e1JRPZ62Fe3+XzG3feavYf2vta8eeF/hTeeLbm5sbPUoYvPnWO48xo2/u7q/Kjx78RPHfxm16O48Z6xJfeXLuih3MyLX865Rhq8sYq0pe5E+TxUvY/up/Ez6G/4J8/Fi58P+Orezmv1hSSXdLI3zeZ/s/71frl8NfF02oaHbagnnPaTW+7bJ8zV+Mn7LPhXVdP8aWEypnbcK21l+7X61fAW+k/4Re1d3kaOGBV8lv4mrgzWUfrH7r7R9lw/UlChzTMf/goN8RLPwr8DW0HTZv9N1q6js3kkf8A1MLfM21f738NfH2gtCot9jrn/noy/dWvSf27Pie/jv4vR+GNKdW03Q7f/Slb70lwzfLt/wB1a850GB1ZHh8v5X3bpK/SOHcH9Xy+PN9o+RznGfWcwm4nV6eEaMJC+/yfm8zZ95a6DR7Uz4mdGRF5RVf5mrH0PHyB5oy//LXb91v9mum0eGGGRXSGP5n+Zq+kjH3Tzo4rl92RrabHNbtv+zM8jLsRW/iroLKFlUJs/dsny/xbWrN0+18zbc/vN2zcrL91a6Ox0iFY1WF/lb5nZf71aU6f2jf61L7JHDb/AGO8V/JUiRdqSM+3b/wGtCO1ea3MqJhvlR2jdV/8dp0OnpcNI9z9+OX5a1bXTxCqIlnt27dm1KvllzEVMRKMTKk0m8imST5R5bfP/u1X/sXd8k0EkXlvuRli3LJXWRaWjTL/AKNl2X7yp/49VyPQ3+SH7TuSP7m7+KumnT9w46mKnLY4HUvDu6Sa5tofJ8x9m3b/AOPVz+reGZt0kzx4ddy/N/er1680CGaNIXhYuv8AyzZ/masq48Lu0m+5dd+9m+7t21fs2cFatKR4nqHg94V87ydiyN+9kjXbuauc8SaONLulcSu3m54cYxj0/Ovcb7w+8W/f/E/ysyfw15d8YbD7Ff2mVILCTORjOCtfpHhUpLjnCX7VP/Tcz0+E534jpL/F/wCks8w1zw2t7dvOu5CRuKg431xXirwWHjkhjeOL+Lds3V7n/wAIzHd6Zb3UsDfPbj5x9K53WfB73CtCkMcoj3Oqtu/76r4/O4RlnWJX/Tyf/pTPn8fKX1+q/wC9L82fOfiDwTM1rsmdWeOVl/dxfMy/w7q5q48CvaM0/wBjYtsVv7q19Bax4NmMn7mKSbd/07/N8tc/qnw7trqQLNYNGVbft3turxJR5TllL+U8r03wrNHcbFhZ3Xarrt+7XV+GfDdreTLLc7Yk+b5Wrr7HwXGsfzpJv+9t27d1XdP8L20EZ2QMx+bZt/irl5eU1jIzLTw+kcafuVYM3yMq1vab4PhmukuUjVH3bHmki/hrU0nRZrfZ9mDFWRdkbfdWu00fw+7bYUeOWNfmeRfvbqn/ABEylE5O18OusabLb70v3v8A0Guk0Pwak2zfD80bbpY5E+9/wKur0/wyiuiXUMexfmSFf/Qq6PR/CMMiP5KfeRWdmp+zM5S5TkLXwTttB5z7vm3fu/4v9mtO38Jwxsv+h+bt+/JXaadoLtmZEX5fu/w1Ym0naqOnmbI02bV+61EuX4Qj/eOQtvB8MCvss4ZJvN3bvu1pW+jwyM3yKsUafdb5a3bjR5rhd7pnc3/j1OuLNJF2TIpb+FV/u1zy973jeMjmptHtpoXS2dS8ifxJXO6x4fhWx+SHb97zV/vV38lv5M37lF2/dVtn/oVYviKzSeQo6fdTajL83zNUcv2jXmPkbWNcRY2htod235E+b7q/3qZb3FmzJ8kfzfM0n96sNdUfcHmffIq7f3fy1PbzOvzo8iD70Ue3+GvPjH3veP1SXJE3ZpnhUPDe4Rl3bdv/AI7UV1HDuMMyZT7+5f4v9mqXnSNMNibQy7fmb+KmyTXLXSu7L+7/AL1KXuyFUlSUSWSOzyyfMjqv3WSuQ8UW7tHI95MyvJ8ybn+6v92uq1C5TzBC9zlV++y/ermvGF0kkMjo6uioyJuX5qiXunj4qVP3kedeIfmUOhyivt3bKyZLjcySbNp37dy/w1d8QTTeTvR8u331Ws6JoWVt7tv21ly/ZPMqSNKxa1kbzo/3rKnzLW5b3U0NuvkouyT/AL6WsfRtk0iIk25v4/krftbP5ofnZ/8AgFT7vwi5fd5izbrCsWya2bZtVvlqaSN7eIb4WQ/7vzU/R4YbfLumx1fc/wA3ytV64bbH/o0Pz7N25v4a05eWRXvS1MxpPM+eaaMhvuMyfdqlqUcKsiLNvT+Nv4a1Ly4hhRpkh3n+792szUWRkSVE2Mqbty1MYilyr7R7v4Kbd+zc7qSc6HenPr/ra+QNajmaNnR2+VtytX2B4Jbf+zgzJnnRL3H/AJFr5G1yRJLffIm3b975K/dvFLTJMh/7BY/+kwPU4jd8NhP8C/JHF6lNcjKO6kVj3Fx8xfYrCtfXNizP5P8AFWK1vt3vHu3L822vx+PvRPialQgkm8wLs+YNUdv+8k2D7392pfsb/wAH/AttTWdkI2MvzBl+b5lrWPUx5ZSkS2av52+ZOa2rOTdJtmTnZ/eqjb2Mqzecj8SfwtWrb2MLSfJ13f6ys5S5jSNORbtU8zZ2C7ldatQ/KyvLuyq7aZa2v2dVD7Xdm+etKOGFWWZ/MO7cvyr8tZylE6KdGew2G3kkb+//ALK1dhhaFV2W2TJt+VakjtZvs4e02iT5V+797+9V23sX3f6SF+ZNq7XrCVaB6MMORrbxrDv+bLN/ElEcm24Lvu/d/LuZank098/cY7t2756dHDDJbp97HyrurGVS5vGnKUhVH2mNfOfJ/wB6rNuu350+fy/4aS3tUVdkMf8AF8n+zWrY6R9nw/lq25fnrhlU5TvjRkyDTw7Lv+X7v3Wf71adizyTNv8A4k+8v8NMgs0VUdCwRvl/3q0rG33R7Jpv9rav8VZ+2Y5Yf4S7Yrtk3wjcjfJKq/e/3q0VZ4XXykklRfv/ACbW3VDptvtjVERQ3/j1a8NvIYV2TL8zs1Y7fZKVGUh2mqhU+c+d25nVv/Qatxvu27E2jYzfL/DTvsiR26uEy2+rCwolv5MM21lRtn+01c1SXMdNOjOPumVeWcLfI+4q38Uf8NZ+pWMdw2yH7m/bub+KupksZpFXYjFZFVfl+b+Gsy4jubiFZvO+bf8A98stR7TljzHTGicfrFq+Hd0+bdt2qvzbawtT0l4/4F+ZPvSV297ZpIvkuiu2/wCdt9Y+oWe5gjpwv8Vaxre6VKnJe9E4G80d4ZGmuU3hk3bqgm0fnznhVX27ol/vV1Wpaf5bKm9XDf8APP5t1VGsEWF4URQZF3bf4q3lWvuOOH9w5CTS3lja53+UW/iZfu1LZ6TN5hR33/7tb8mjoyrJ5P3fmVWpfsdssPzowlVfnVaca3vBKjH3bFW1t0hUJDym7a+2pYbzduREV9u7azLU726R4SFF+b5nkb+L/ZqvJJDHMrujIrfKv8VRF80uaUTmxXu7Fy286b/RvOVfm3eWq/eatXTV81R59ttbd8zM/wA1Ztq3lsJkfJbc23Z92r9jN5n75ZtjNL8jMn/oVFSUpXSOOKtys6HTVkgUpD8qK237/wAta+nxvbLvttvzSrv8usvSYUmJS5h81pPlRo/l2/8AAa19PjSSZf8Ax7+Hb/vVxSly6ndGP2TXsFFvCj/u2C7tyt97/eWtDTW2lHmdiZPvbqzre13N5MKZ3f8AjtaVsvmMz3Lsrt8v7uspcvNzo6I80tEadva2fmec7btrbtu/5v8Ad/3av6L/AKP/AKNNO2/733NqstZMdvdeZ+5mVkmT5vm/eVraQqW3l/aXaJf+mjbtrVtGQ4y97lOw0u3hbbMm1fL+bb/drrdHheaOJ4XaIsu3/e/2qwPDckMcfl3Pls3y7fk+auq0nTYYbtLxLmRHVNu3buVt1d9H3TnqS5tTQs99vIg370b5Nrf+hVakV5RG8O7asW1YasafDDMywpCzN97d/e/2auw2b+W6Rrt213U4++Tzcu8jLsbOZ4/PTl2+6y1tSW8lvGr+cwdXVmZaktdFeDdbIkmWdf8AdWrTae8Nsz2zqw+83+1XVGPNMmVSPKFrNcwsj71y3zeWybmZakkZAqzb5GRUZv3n3dzVUuIbmxZ5ryGbfsXypFf5V/3lql4o8RWfg/Q31vU900K/JFaw/ekk/hXbSlLl94uMYxXvSKN9ND4g8TWPgy2RW+1Sr9tWN/3kcP8AEy17LD4q0Hw3odnYeGN0Z0+38pYdnyqqttryn4NxwtY3HjbUEmttavpWWW3mXb5duv3VX+7WX488dTW+oTCGZvObd5XlvtX73zV8Tm9aeOr8kdkeVPEc2sT0Hxt8cv7J26t9v8t/ueS3zK3+1Xm+tfFt5NQe2eZndpWZFhf723+KvKfEnjy/1y8ubm83JB96JZH21x3iDx9c2cLecP3sf3FVv4q5sPg5ROOVSXKetap8WrmwjSbWNS81Ld28qbY3mR7v7tYGvfFpNWt3mg1KaNJPmlhZvnavHZvipNdXT2015v8AM271b/0GsDVtehuJvkmZBub95u+Za9ajTlH3eWyOGpKB1WoeLn1bUvtKQyJLI0kXzP8A6v8Au1SbxNqumxqIUV5lXO6T+KuM1bxdCyuiQ/NHt+b+KRqqt4yubrY/nKzfdaP/ANlpyw/wyjua06nKdlF423OZriZWeSVju2fMv+zWxoPxceGNLB/JtkZVR/L+b+L/AGq8wm1ZJI/Jtkx5n3938LULLc2Z/fbW+X5GWuHEUL/EdsMRVhrzH0F4Z+I0M0Ys7O5mfbKzSrN/D/dZf7y11LeItS1JY7DUkjuUX/VNH8u3/wCxr500HXNSWSHvJ/e+8zNXq/g/XtVvL3fczfIvzKrP92vCxlNUavMfSZfWnWja51FnHeWeobEhYbn3Iv8AC3+81d/b2qaa0NtD9omtJkX95M3977yr/wACrN8O2dhqVuk2n2bJtVftDTfxN/ervrPww8mm/aUh8xY9q+XGm7y/9qvP5qUo27nuU8PV+yOXS0t3RLKbymXaqL/E1dXpscOmwpHbTxod3/LZflVdtZVvp5tdQ+021szRsm1ZPvfd/wBmtm38P2euaa/9pSyPtf51VtrLtopx5fcOfGe1ia2jww31nsuUwu9WuGVNq7f9mr9vpWpNfO9nNhPmaKNvvrU3hfR4brVrbR97XT3FrviVV3Mqr95Wr0K18B6bcLbm2muCI0ZXXbtXc396u+GDnU9654NbGSp/4j4n/bw+EPiHxJoo8T21tHcX2kp5vmNF89xH/wA893+z96vkCKJIZGhhDMVav12+JnwbTxJpFxol+i3iSRbdqxfvIY6/LH46fCPVfgP8dNR+HWpQyRWd5K15oi/3o2+Zl3V7GBxU6l6M1sRRxHs5afaMmGZFUPM/yr97bV1fs0cgR93975azbNkNyiIn97za0IZHlUfuVlb7vlsu1q7Obm909OMftDprPzmEP7tDHt+Vfvbf71Rf2fcw7d9mx+9tZfut/tVpL9j87yY03Lt+9tqOGPEx852+aJv4N22lGOpqYt1pO6aZN/zfxstQSaakil3mYsybYlb7rba17iOZZo3ebc3/AC13fLuprIn2cedCyuv8TJ93/gNdTjzanHzRjzGJZ2LzTYmhZFX+Gt3RrG5hvPOublWSP5ait1+0QOkM2/zG+eRmrV0m3uY5khhgkcL8v3PlavVwsZHjYqUY7nZeG1hWGNIdqM0XzeX95q6CxVGj+07G+Vlbc396uW0uORYUmR2V1l+9s210Me+aBkaZV/v/AD7d3+1XdGieLVle5pWq225538tZd2/bJ/FuqxHCsECxEkAIM4OSOKpQttkijmh3N5X3o/7v95qvp5YYFHyuchge3rX7d4JyvnWPX/ULU/8ASoHu8Ju+Lrf9e5fmiWOSGFv3cPmfN95X27W21ZdXMbTfaI0fyvut8zbv96q1vC8Kyu8zfvF3bl209FS3jLukkg2fMrfeWvx2NT3uU+R5BGuXbT0tZpvlX5t2/wDirn9WvJriF9kKtufanz/+hVp6hvaNXh+7s+aNfvNWNqkkMymF0w7fNuV605mTy++cP4uXZl5nZdv/AHytea+KI0ZZH353bVr0vXkebzUdMqyfvdzfNXCavpv2mQ21zDs8v5dv8X+zV85pGPKefXGlvcSOkKMzs+2n2eivHGd9ts28fKn8VdZHoLzXDpbfK0fy7m+XdVuLwwi2/l2yMz/xtW0ZQH7PmOQk0FG+583mfxVRk0RNmxE3/P8A6vZ83+9XosPhU3kaeZujZU+6qU5vC6KrDyNyt8q7lq+b7MROjOR5Y3h0LcSh4cTKnz+Z/dqhdaLNGo2PtbZ/dr1ibwTMsnkyp8jf3k2/8CrO1Lwn57ND9jZVj+X7n3qFKcTKVLl+JnmMGlvIpjc5f+Nmp8Gm7W37M7V2qq12eoeC0hzNbJlf/Hqzl09LdVR4Wdlf5NtTUpy5JWLp+6YwtfLX7jMZE+VZPurVmPeW8tOWj/i/hauq0P4X+IfE1wf7Htmd1TcsarXMXGk3mk3Ettfow2y7WXY25fm+auCVGcjeOKhT6nU/Dnw3c+JNaTSk6zOuyNf4q+pPhb4Zt/AVwlzebfssa/6VJv3KrL81eG/AfxF8N9H8caakOqxm5mlVU8xNu1v4t1e3ftZeLLDwv8N7/R/D2pbb68t2g8tZf9XuX/WV04fD+z96XxHmY3GVakuX7J4l8Xv2pFvviJfHStYjmhjuGT5m+9XCeI/G3/CZM2t200cVzG25I1+ZdqrXzzr1rdeH9Sf7TqvmNJu37X3V1PgvUr+O3+02E2/au371dP2ji5ZH1r8Cf24fFvh34er8AfHN5HPoUN19q0O4un3Np8jfejXd/DXvfgH4sJeXFo7uzxsisy/w/wC9X5oeINceRn3p8y17B+zv+0LHMraPqV5JHcwr87SS/K22vkOJsr+sRVWB+gcIZzDCz+rT+0d3/wAFJNDs9U8cHX7BJClxFu+58qttr46utJvIZC7/APfVfVvx4+JWm+PtJgvL+5meS3+Vmb5ty/wrXjLafpWpbkS5jG7721a87KKkqeGUJI789w8a2Jcos86jjmhbf/49Ud8v9oTrbRorbfvbv4q63WfCP2GRXhT727+Cqmn+FftTb3/75r1qctj5lU5RdpRGaTZ+XboiQqp/g/2aZezzW7P5M2GWunh0V7e3VHTdIvy7mqva+DY7++VJNyn+9975qrmhz8x2+zvDlicnY+MPEmjzYttVuE/6Zxv96vUPhT+1V8SPBeoQ3lhK22P5Uk3bW2/xVT0X4K2Gvaglm9ysKr97zH+9/wACr66/Zl/4Js/Cvxd9gufE2tyOlwu91jTcse7+KuLFVMM/dmehgaOb05Xpv3SP9m39tq2v/E1tYeJNKmBaVmi2y/xf7Ne4fC3WI7n41Wmuxnylmv55l77QyuQP1xXpvh3/AIJV+Bvh/pMV/wCGNQW4SFfNWaa1Vm+avNvh74eZPjrD4aT5TDqtxCMDpsEg/pX614QKP9h8T8r0+pT/APSKh9vldTFVaUvbb2MT/gpl4jh0H9nbX9Re0Yrcr5cG77rN/s1+cfwN8Dtq1y07pv3bXZq/Yn9rj9mf/heHwXvfCX2b52i3W+5/vN975a+Avhn+zT4t+H91qFh4hs5oXt/lTd8zN81fzvg8bSw+AnTUvePl82w1SOOjKfwnT/AXwGYdct4fJjzG6s8nzbV/4FX1t46+Nln8IPha+qo8f2zylitVhb7szLtVtv8Adrx/4T+Gr3w/p/8Ab2sQ+THH+8lmb+FV/wDQq84+I3xGvvid4qmv7mRls4W8qwhjfb5i/wB5lroynAf2jX55fZMquYSw+F5IblGHUNSvtUudS1u/a7ubxmlnmb7zTN95q6PQbo/aFR7zc+3ci7Pu1z+k6fDDJvR5MK+75vm210uixw7ldPkWNfu7PmZq/UKPJCHLE+Xmm3zHY6XDDIpd4VCN8z/L8zN/s11+j2tz5yTbN0apufcv3v8AZrlNHU3Cqk1yzhfuRsn3f9qu20eK5VsTXKkKm5Pk+XdXfT96BjzS+0dT4Zt0Zt7usUTfMiyN8tdNpdnbX0KYRdituSRmrA8MqjPsSbLx/O2371dnpMc1xG29I03bdm3726t/hD20uhJDo7wxiF3jy3+1/DWnZ6clv89s8MkU0X3VX7tT2lm8zR3PkrEi/NtZPm3VdhhWFvOm8sKvzfLW5UqnYq2FmkbJ+5b5fvt/erYt9JtrjZMltCzfwrv+b/ep1nY/6R86fKzruVa1bPTXkZUd1AX7jfxbaIyOeUio2k20iuiQrGV/1W75qy7zw6jM7zc/w128empfWuIYdyq+1WqGbRYG8y5e2V/3u1JK6KfunBKoeX6x4bh2nzE81FX5V/irw/8AaR0/7Bf6SOf3kMrfP97qnWvqjWtBTa/7tf8AZVflr5z/AGxbOSz1HQRKSSYLjr7GOv0nwsSfG2FflU/9NyPa4Nk3xJRv2l/6Syp4f0Z7jwtp0iMyq9lDuCr975RWZqnhm8aZvN3INrOkka7VX/eWvR/BmjS3Pw20R44iC+nw7WK8fcFLqHhm5aU7I1dfu/7W6vj87Vs5xNv+fk//AEpni5hP/b6v+KX5s8b1bwukO7YjY2fJ/tVk3fgpGuE2JG/lpv8AMj/i/wD2a9i1HwqjL5IfY7fN92sa68LzQ7njRWCvt+X5q8OtGPKckZHmH/CJmNjvRWVvmWSo/wDhHoVt2uYYV2N8qN/dr0m50O2jWXZDsH3n/wBpqz28NyW+H8mMLI3+8qtXHKPMbxjy/CctpOhPHC7okZ8yL7sjbfmrstD8P7Fi2QqRJ/d/vU3S9DT7ZvmhZx8reX/tV12i6ci3CNNNs2/8s/4azkOT5iLSfD3lqrvbK4X/AJZqv3q6G08Mu3kuifN8rMu//wAdq7otrDJG6I+4fM/lr/yzaug0nSXupkfCpF8rNG3+1REzlzSMmHw26qERGJb+6ny0smhfZ48ojF/mXayf+PV19npm2NPJ5WP7jf3aJrNG3/aZPlbo395qmp/MEZfzHGyad5cex4ZG3Lt+b5m3f/E1n3Vr9lby3kUqybfL2/xV1uoafDHbj528xm2pH/C3/Aqy7rSoWvHh8lXPzL5f+1/s1hL3ionI3Fnsj2TbYtzbt2z7v+1WTqFukaskNgzuq7vMrurzw/MyxPCiqv3XXf8AMtZF5paR3iwzJvjb5nZW+6tTKoan5uQzPMu+H5X3/ulq1as8f7533bf+WLM25qwbG8vLVndP3X8UW371XrGd75ldyodfl3Vyy/mP1CWIjKldmurX7BPLTa/8KyN8rVJ9tigRtm4v/Eu/dUFmr/aPtME25mXZub5ttSSQJbun7ltzfKkmzbWceQ8+tiOaPuhcfvlM3ylV++2+uS8VXzq0lzDJt2/KitW9qV19lkOzy5EXlpF/vf7Vcf4gm85me56MrbmX+Gs5SPN5pc3McnqRupvuIu1v71Jptm/2pYLlG+/t/wBqpVt5pNk2/cPl+b+7W7o+mw7t72yuW/hb+H/gVc0pco6cfae8SabpdtDIltbQsVX5vm/iroLHT5FkXenDfMm7+9RpOlzRys/zY2fPt+9W9Db20i/ZpE2rIv3v4lpQ5feHyGa0fkqyfZt27+JUqX7P9ojVHtmfb8vyvt/76qb51kWL5dvm/eb73+ytQ3C3NxHM7wq3lt/q9u6r9n7uge0k5amZeW8KsOwb5mWsbUP3iy7NzN/AtbV15jRnzkkt1jT5I2i+7VC8kgjtGuUTft+X5WqqXNH3TOUYy8j27wVgfs1vg5xod70/7a18iaxE7Qsjuyov8VfXXgtz/wAM0ySSNk/2FfEn/v7XyJeM8xfZyNu7a33a/dPFBWybIf8AsFj/AOkwPW4jlGOFwl/5F+SOM1aF2b/XMG+9838VUfsczMkmznZ8+2trULcfaG3vgf3W+7Vfb919+Nv8Vfj0tj4upGUinDa7T88P3quLB5n7nr/fp0dn50y8bm3fPtrRsUTaZk+6r7W+So5kdVGiV4bXavyJurVsbG52xO6KgVtyMv8Ae/2qmgtoWcIm3ZH99lrSjsXZU2TNj5d9c9SpynVHBy7Edtpbr84RSd+5mq5b6fatI33sbPl3Vp2dm8sw8mP/AHG3/eqwumgR73fY27+KuaVTmjrI6qeFlzRK9lb/ALxSn/LNP87ql+ywvNG77nP3n8t/lX/ZqRbOZpNmxU2/xL/FVy3sHkbenlqv97+9XHKpKPwnpqhHm+EhjsYWO/8Aebo/vrJU0Nqkcmzydrt95Wq/BCYVh2bnP3WbZu3VZjt4WWHzn+Wb+JvvNtauOVaf2jtp4VfFIpw2MKws6Q/8B/8AiquQWNyzfvk+ZV3bV/u1fjtdsmx/4fmRauWOnzTEu9ssK7fvLUyre6dEcP7xRt7dEyny4j+/u/hq5Dp/lTJ5M3muvzOqrVhrGGObyZvmfYzJu+78taGmKnkyzOipIrbIt33qz9tLluFTD82hLp9jbLIqI+5mi+dtvzLV/TdNdpGhmRdrfLtb+6v/ALNRa2Lxqmx42+RV/wBpm/vVrWcbyqsKQxqy7vNZvvVnUrcsviD6tIS1s442WHyMhn+TdU66fNDI81zCyLJuaJamt7Xy1HnI3/Af4asMzrGn3nZV2rJWEqnve6bex5YxKE0ZVo5rZG3bdysr/eWqEweFghhVPvbtyVsXTQCBYYH2CP8Aur/31VbVLN47dZn3bfvLTjLmL5Z8hy19DNHM6Q+XvX5vlX+Gsa8he4kL3MPnNH8y7k+Vv92uu1bTYbpXmSTduX5GX5a5/ULNrht77R/dXdWnukcsonNXFukjH7NCqNJ/47UFxGjbEmRsxuyfd+9W3dWsMMs32naNsqtuj/u0xrO88v54967922tvae4ZS7GHHZzNI/3Y0X+H+98tMWN2jdI/mZU2u1bMdrC0L3PnK33t0a/dWq8cSKrbIVUN95mojH7RnKp9kxLqPzV+Taj/AHdtVGhvJFZHTYy/Kv8AtVs3lq8B+5/tfcqs1uklykw+ZmTbuVPu10xlb7J5lSXNLlZBa28zSeZcopP8TfdVlra0ezea437FRVRm+/8Aw1Bo8KSN5ezG3+HZu21sadYu0w3tuVUb7v8AF/tVlUlyy0RFOPM9ZFrSY5Jp97w4P3d1dHY2cLbnmeNkkX5W+b5mqjbx20eN6M8i/Oqr81bWmx7meHfGF3bkXZXHzc0eaR6FKNqliSPT38tEtvk3bd+75dq/xVfhs5o42hhdlRfu7vvM1WoY4fL/AHPzOyfNGybvMq7Hp800nmeTlflX94n3ax9pKR2RjDm0KlrazSzLcvw+z7rfw1v6TYpcKHdM/Nu3bKit9PSaNbZ/Lfd/31W3pWkvcKh85l3S/wCrb+GtY+9ykShKL3NrSbeGRvOTpD8ny/3m/vV2+j2u6FA+4lfl+auY0uwS3/fbGab5vlX/ANCWur8OQ+XGkLvIUbbvb+L5q9bCx5oHnVpSpyNqztb+Fm8mHafveYyfdX+7Wtp+m+ZKghSQ7ovvL92Sp9Lt9tqybNyt8v7z+KtzQ9NuLe2S2udq+ZtZ2+6u3/Zr06NOWxwyrGfZaXeeWXfbt/5aqv3auR6bFDjiSZ/mVv4du6t2z0tG3wrwiuv3v7tXofDaTTulym7dt8qNf/Qq6+X3iIVpS0OPutLSa2aG5dnWT5W/2f8AZrjtT8Mv4m8Yf2NZ6rCkdi6u9vN/E38P+7XrfirQ303w7fTb4UZV2xSSf89G+Va5ux+Htt4Ft7bVdYT7Pef6q6WR1bzm3fe8z722vEzrERw9C38xVfETl+7MTx5dQWuhszpa2lzvVEaH7zN/F/u/3q8C1q6vI9auLm/vPMfb8jM/yxr/AHa7j4uWd/Z6lqdhO8bzTS7d3m7v+Bbq83urW5vlj0ewtmeRom3eZ91W3V8pQUpbHFL3vdOe8bWN5NZpPawx7FiZ/wDZ3f3q838YTGOFpobndc7F3ei16v4uW80XS4dEvLnesbblWOL5m+X7u6uAvvC9zrgTPnR+Y+3ayfK3+9XVRqRjPyCpGUocpwEOmpJdrvRWeF/NlkZ/utVDUr+S4vlmtk4+47fxN/tV6G3w9uby1EKuquz7V3Nt+b/a/wBmsnUdD0rSY0s9Vv7X7W27zZI/+Wf+zXrxlQlI4KlOUYHAeIrKG1kifzpJkZN26Ntu2s1Y3tYpX+0tvVt21mrqtet7G1kR9/mBvmdv4dv+zXLapqENxL+4SN/7jbvmWolKEjL3ojvO1Web5H3Rybdnz/NXQaPYa9JGdh80bvl3L/DXP6XqFhK2x5sS7921vl212ek606sjpCqQt/t1wYyo6cYnXh/3kviNLQ7waVMX/drc7du2RvlWu/8AA+uTLIHudr3DbV2qn/j1clayaVqGIYZrfd99Gk/vVoaXq02m33k3OpQskjf8s/4a+eryjWlK59nldqUo8x7v4Z8TTW0Ze5+5s/er/Dt/vV7X8JfG2la5o7Wf7mUbd3mN/er5NsfEDsv7nVW2sjL8392uy+G/ji88M3CWVtfraJ5q/Nv+Vt1eNiOWn7p9vQq0oy5e59VR6DZyKtzFCspj3bfLfatVZNH0/RdWtr+GFmhkb/R/MlZmkb+Jv9pawvAPjL7ZpOy/vI0MMrLtX5d3+1Q3ipJr5YrmbeluzeV8zf8AjtTRrcs/eNa2FhWPq/wL4N8Pa1qFt4h0ezWK8ktVR5I28uONf4vlr0S3+HsMccsKWEm1n2o25f8Avqvm39nf4mWGpeKrOzubyZotvyRzfdjb/wBmr7t8HaX4f1jQEfR4hM6xL/pTNtVv+A17uBrVK0LwkfDZ7lcacuZnkV98NbbS7lLm2voXlb5Z1+823b91q+O/+Cs37Fd58RPAdx4z8AabHZ6jocX26CNkZpJFjXcyq391q+/fH3h3R/D6y3V1CsJV9zeX8qyfLXN6lqWia9pAvNes1vbab/Q/LZty/vFZdzVvLEezr899jx6WEnKN/sn89lrqE01nDc3On/Z3miXf833WrVt5HWPfDDtljVVfzPvfN/FXpv7aHwTm+C37RGr+GDprNpdx+/sLxU+ST5m3ba87t5Ps5/cJhf4d1erTqe2ipLqevT5+QmzdSMEd9w2bd23+GlkkuYWlmmtv3G3bFMr7dzU6OV2ZbZ/MV2Xcu37rUy437Ve5h+Rv/HV/2q3px98uVSJBcQpJvtpk3nbu3M/8VN2eTIHeZlXd8256hkupvtDuj/7K+Z/tUBoZrh7Z3Vnj+b/Zrrpxl8Jw1JQ+IkhW58tHhRfN+ZXXZ8tdBose7Y+9lk3f3vlX5axLVfOm2Qo27b/u10mkxosnk214odfllZl+9Xq4ePKeZiOV8rubOjyJHdfZp929UX5m+6y1tx2MEMOYYVkb7+1vmrM0/ZIqpv2bfvq33Wrdsyb6NIZkUeX/ABK+1mWuqMvtHmVI/EmETTeXE80zDc6r5i/dX/gNXo42B8qfaSGKnb0IzUK2L28m+GbDN8ryfw7aktUnVFj2nzAcAZ754r9q8E4xjnWPt/0C1P8A0qB7vC0eXFVl/wBO5fmjQtVhVpNkMYC/Kit823+9SMySTNcojN5fy7W+6y/3qVdn2hJvs23/AHk+7UTXfmKqD5n3/NGvy7f7vzV+Iy5ovQ+a5fdKd5sjs2dNrS/Ns/2f7tc1qm9nYb5MNt3+WldCsP2hmCIu7+L+81Z2oWcNqyuJtsf3XX/araPuwH7Pm+ycXq2kpFHcOiMzr/y02fM1czq1mImZ4drs3+t/vL/vV6Bq9r9lkESPv/2v96sn+xPMuGdIFUN9/an3mpxl73KafV+bY5XR/Cs1wu+bdlfmRV/5aV0mi+C0uI0+zW0kok/1u75dv+1XX+H/AA35ipC6SebC67VWL/0Ku20jwe7pFNsjI3fxL826u2jH3jT6vy6Hm9r4DhazTfZ8Kv8AF95m3UN8P3Yr/oeUjfcklexx+DUuJvntmE0cvzeWn3v92luvA9tbx74Y5JPMl+638NdHu05kypT+0eK3XhD5Wgez3Rt95l+9XP6h4TS181I7ZmXZt3f3v92vfZvA8NtZ+XNCqybm/wBrbWJr3glLXfcPDCU2f6z+7/tLS5oyOeVPljeR8/Xng/arQzW3+kfe/dt/47TPDvw1m1TVksktmmaRljiWNNzbm/hr0rWtNhvl2aDZ+cyttuLj+GNf7zVc0fxp4S+Gtrv8PW32/WfK2pfRptjt2+78taqMYx1PJxWIjT+EvQ6HoP7Pfgu+trxIz4gvlVZ4V/5d4f7rf7VfL3xO8UW11qVzc2yQ/N/Cq/xV6T8QrrxV4u1Bry/uZNm/c80jtukZvvVwGv6LolvCEmvFLf7SUvi1Z5/PKUjyXUpb+a4W8015Eljfcm1f4q1td+L3jDX7NdE168uLiVYvkkZ/4as+KNctoXYWEKsqy7VZU/8AHq4vVvEDxSbH25/2ajl9/mNI8xwXjaO/kvC81zkq38VXfhr4qubFntpvuM2395UPjRvtUjFNpXZuTbXNWtxcwtvR8Or/AHt9XH+6OXmel641s0bujq4ZdztWBY6lc6Lqi6lZvt+T96qt96oND8SPdW/2aZ/mX+Km3kKMrTfKV+7RKMKnuyHGpOlPmiem6x4g1WTw7DqTpus5tv77/arndN8Y3drdN/q9jfd+SvTP2E/Fnw38Ra5N+z98YLOGPRPFG21t9Wm/1mn3TN+7kX/Zrn/2zv2SfiR+xj8XJ/Afjl2u9OuH8/RtWhX91eQt91lavMrZVS5ZTpRPWo51V5488il/wkyX1q8KPGzN99tn/oNWPDeqJDdLZ71YbfkZl3V5xDq1zGqok2f4vmrV03WpGm85/kZf4d1eJKj7Pmcj06eKUpczPSdYntpLUI6Kq/xt/wCg0zRdRSGT7T8qbfl+WuIm8WblW1f5f/HqSHxE8MezG1t25Pm+9WVOhOULHcsbScj0/TdesLi8SaG88qZZfm/utX2r+yP8ZP7PtdP0F5lk23EbeYv3W3fw1+c3hvxJPcX3+kzL+8bdu219Q/s0+JLizuLP7HMvyyqvzPt+X+9Xl5hTnGOp9Dk+MpVpcvMftJ8NfiBpXijQX0jUpoXCxK1u2/a23+7Xxf8ADo2i/tiuZwghHifUchzgYzNitD4Q/FS5sZkea8aaBty7Y5drMv8AerkvhvqS3X7QkOrM+8S6vdSlnP3gwkOT+dfrngvVcuH+Kb9MFP8A9IqH1+HhShdxZ9V614ss5dS5eOKFX/dNv/8AHq8H+K3h+w8QeOBc2aKltJuWWRdu5l/3q7L4saf4k1LTQdBGx5vlVl/8e2159qVvqvhPwvfa/wCM7zyYrW1bbGvzM0n8LV/LVCM6uIvH7R89mFSNSrblPEP2ofilYTTxfD3w3N8lqm66kWdd3/XP5a800GG18tprxGD71+X/AHqzLrUpfEGtzarNt824Zt25f4d1bOlw21xM73k3k/dVK/ZMow9LCYeK+0fJYyd6tzY0ux+zTbJtvyt/ndXR6bBtk2Rwb/7qr/E1YunWrmPZ9s3J/GrN96uh0tUtWhRCsq7fkkV/utX0FPkkeNKR1fheOaPy98DK/lbXaaVf/Ha7LSWmhXZCWR1ZdzN8ystcZpt5bLiREkdf41bau3/drorHWLZY2RN25Zf7ny13U/g905ZShI7nw7J5l0jzQ53bvNbf8qtt+Wup0GSe4sY7l/LZ5P4m/wBmuC03WEVvJeZVDbdi/wATNXVafqkLKvkP/q/mf+61bRlzC96J3WmzvGuyHywv3dyv95a0LGRJ5D5CL5qv+9WT5q5XT9UT5N7/ADfe+atSG+S3ka8hkXYqLvbd81a/CZ80v5jp7OQxwqkN4u6SX5m+9W3p/kzRuiJICzt5Sr/EtcpY6hMzjyXhwv8Arfk+Za6PR9UhVkdJPlZ6uJjUl9k6/SfJnt0y+11T541/iWrlxGnlh4YVXa+5FX5qzNPuraKb9zMu5vm+58yrWh9oh3K+/G5d23bW8fh5jjl7plalpv7p5vlLsn3m+7XzD+3hbSWeteHLaaSNpBa3Bcx+5jNfUF1fbbiWG2mVwvytHIn3Wr5k/b4Yyax4akZFDG3ut2zp1i6V+j+FKtxthvSf/puR9Fwc4PiWjb+9/wCkSPQPhVp3274UeHxlAF0eDJPUZQVe1Hw+iw/wptTbuVPmb/aq58FoFl+EXhuRQpC6Hb/J/ebYK1brTbw/8e1qz+Y3zRs/3Vr5PPP+Rtif+vk//SmfPY+X/ClW/wAUvzZ5/faPDNJKjWzfudu7dF8rLWdqHh9LdiiWcfzffZn+Zf8AZ213MypH5ibM+X/C38VUNUsEmG+5h+dvm3M9eDW2JpyPPtS8P2ccbw2ybXX+Ksu+s/Mj8nzpPl2r5bLXX61bxvveF9rr/d/iWsK88mF22TtIFX5tvy1wyNfi2KGn6Z+7RIdqv/HI33t1dLpGn+WqO6bf9nd/6FWMtxNJGjwIy+X8v91mrpPD7Q3EexPOTd/eT5Was/fA1tH010jRPJVPMl2o3/PStiPZGFT5k/e7W3fLTrGNJLdZvJ37dqp8+1qWa38yTfN5JTb8+5vutVfY1MZS/lLcV6n2na+3Yv3o4/l3UT3CNcNDs2rv/hfctZUWpJHI0KfNM3zIrfepW1JLfd+8UH+7WVSXKSS6hHcxyNND5eGTdtkf7v8As1mX29mL2yKryMvlNu+7/ean32qQyTbEm+VotqNIi/NVaGbzmi+Rf7yK38NRL3tjaMixcWs0zeSkm/8AvySfxVWbw+kkbvO+Ts+793dW1ptvNJGj3iKob5nZXqe60vzFd403Bvu7n+7WMom0D8drW+S4ZH8/59u5Fatax8mHDpyzfNurnbJXjkjE0Ma7fl/3f9qt7T3dl3o+N3zJ/vV5vtD7ipiJS5jUhuHsbpN+1lkf/d+b+7Us0011H50d/Hv+b93I1VWvJlZvJ4lj2l/97+9Ve8uvLX7T8pdn3I393+9VVKhzxpuRnatePskCTM7/AGj5lb+H/ZrntQmdg/zso/3PlWtrUmmmn3xztmbd/H8tZjQ/K6Q/MWTd+8+6zVh7bmj7xcaJQs7FJPmRP9lG/vV0Ghw+XdIk21WX+Gqlnbw2bMk23d97/darenyWzKXfcPm3Iy/w1jzIqPLHludDZW/kRmZH+Vk/esv3ttT27QsVudjK8f8ADt21W0ybzIzM/wAu5du5qka6SPCPzuXbub+9/s10RiTUlCIqzTRtve5XZI+1Vki+ZaikaaRNifKzLtdm/u02adIV87Yvy7WZd/8A47Ucl0jqEmhVkm+ZF/i21pH3vdOaUipqGy4j/ffP8m1Jo3rC1aSKzhaG2hX7nz/7LVp310iyNCkPyKvy7X+9XN6ndbn2PtZm+bbt+9WtOMI7EVJH0L4Dcn9mNnI/5gV9x/39r5EvLjhXmdkO75P71fW/w+AX9lxtpJ/4kV/jPbmbivjnVNSdpNj7WOz+H+Kv2zxRV8lyH/sFj/6TA9biRp4XBp/8+1+SM3Uo08x7jfn5/mqsq7ZFdE3JRMzySNC+7C/9805WhXYnk/8AAq/GD5unH7Mi7DZbtjoiov3mX+9V2wt4X+T94u5Nvy/w1Ss50WZe277q1raX50LeZsYrv/4FWVSR34enYv2cKWsfko652/w1r2Nu7bHmiVdz7dqr/wCPVTswn+p6H/dre021mST9yjH5d25q86tU5feZ7NKhzbGjaWO0LsRv+ArVmbTYfLV4U+Rm2/3tv+1T9Ftdmdk33X+dW+9Wu9jI0QSbazb9rs38Vccqx6csLDksYElj5cy+S7bmXbTrO1MczIn3vvPGyfe/2q3bizSOZX+/5fypueq0luisu+H73zfKtctSp7xEKMea5Ts12yJNCjbmXbu/hrStbHdMzw2zN86tuamR6bsXZNc7Yt22Jl/iq9HJDHvhhTajbfKVm+7WMqnN7p6NGjHdkUlq8VwvnO3D/wAP8VX7VZlX9zMrBfvr/dqBbWGT5JnZkV/4f71TxK/mHy5t3ybfu7aUqn2TdU/7xMq+QPueYjfd/i/3qv2ckMdwmxF+6v3U+9WfHdv8v2mZdv3UVa0tPnRmTYjfK25mX+Gp5kX7GPN8Jq2tvCrDyIZLhf8A0GtCxdEmTyYWbb/sVSsxC7bIZd/z7t0f8Na8LfZ4U8652/7qfNtrOPvBKjMkjmmb3PmtvVk2qv8Ad21JJ5jhEtnXaq7XX/2aljjQS796h1f/ANlpJpIYZG8l2Z12/e+Wn/DMPZ8xJNJ5Mi3Lwxt8ir5a/wCs3f7VVNT/ANcE+x7mkXcy/wAK1LcT+XumttpZl+dmXczVVZXkb7+1f4/MXdR7xZQkS5+yqgRYXVv3qqu75f4axtR03zCfJdUZXbezL/rF/wBmukktZnkVPlVdm7d97d/dqv8AZbwTTP8Ad3fP8zf+g1vT97Y5JS5fdOSns4VVoY/MKq+7a3zUyb7TaxbJnUpJ97+L/vmuhvtL3R/Oi7JPm3b/AL1Zk2kpGvyJ/Fubb/EtVGMFscdapIxHs7lIV2Ivzbt6rVO5tfLZkhTc33n8z+Fv9mt2Sze4ZkhdURX3/wC1/tVV+zzTXCwpD/eX5l/8eraPxnFUlKUdDJWHazI80bf3m/iVqj+zwzbZ4XV5P4f9qtKS1n3Sp5MZ2vt+b71VdxRtk0Ko0fzp8lbQ5ubmZySkQ6XZzWZfyY1USRf6tvuq1blnst3CD5/kVHkX5qzrG3tpJHmRFRfvNWhptukczfO3m/df+6y1jiI8xth/eNuFVt5Gmk2lmRVVdm3dWrp8iLIqbI938G7+Ksm1ieR/Jm+VPuxf3l/2q2obPzlXfyisrPu+VVbb/DXBLm5fhO6n8Rr2az3qpsTLSPh/l+XdW1DC6tvfj/2Zf4qy7PfGhcvgr9zb93dWxoMkLbo/3bq3yozfw0R5Oa3Kd32OYv6fawSSfuYflb5vMVvl210em2tnJILxE27flXanzNWbpum/Z2Xy03p/Guz7q10ej2SWqom+QKr/ALr5q7KNLqjnre7EtW9u+7HyiX+Fv7q11nh9YVkjffub5vm+7trM0tUm83z0Z13fvdybWat/Q7GY7fnXbHK2/cnzbf4a9nCx5fdPLxEpcvMdP4dl86QoXj2/xr95v96uls13Qs0yYXftiXZu3Vy3h+N2medAw/vN/wAC+7XXabInmrNC7bV+/Htr16ceU8mUpc8jZ0+N5IfO2Rqq/fZf4q3tPhtvmR9x875YpNu1lrP0dra6mR0RZ0X5dqr8rbq29Nt2a3+R1ZfuV0cvuj8kZvijw1D4im07R9jbFulnuIV+bzlX+9XM/Gy1v9S1y4mtbO3a2tYl8r+Flb+Fa9C168+w6em+5hiNvas6SeVukjWvK/FGqalqmmh9Vto3W8uFWWSPcvyr/FX5/wAQ1JfXbfZIpylUnc8X8eeHZta1ybWLb5FV1WWNX+62371cpJ4ZexvDeQ22ySb5ZZFf/wAerufF2nzN4gFn9sWG0WXc25du6s34gK9uW1CwRo08pYov7jSf+y140Z8kdDX2c/anCeLrG51BbPTYUzFDFueTbt3N/F81c7rmh6Vo9xb3J3Mm/dcRzP8AKzL/ABV1Hi37Tp+mvcwzbxtVXX/0LbXnmuapNHbyec6sv8PmfM1KnU925208PJHH+OteeHVnuUvFmXzf3Xlt8qrXAXF9f6lrTzTfvdv3lX7zVf8AF1xbbpHkfbt3b4/vLXF33ixLWP7NZu25UVmaP79elRqU1DzPNxFOUi94pu3Wb/SXjjSaJWVZH+aua1BnuL5Utn3/ACfdVayLzXLm6uH865bYvzIrUln4iextxIjru3/e/irqp+7Gxx1Ixeo+4kuVvEm3qJd+1m+9V688Y3NrE9sk25FRfmb5dv8Au1nfbLa6ZLmG5Vfm+633m/2mpdc0u2uLdZvOVt391f8A0Ks5QjUiuZkU4zj7w/T/AB1qsjecl4yOv3Nr/LXTeHfHF/HeIl5DvWRW82SR/u1wcdu9nHsS2VlX5ty05fEV5br+7Rvlb5GrhrYKnL3oo9Cjip05R5pHvmg+Pvstiz3OpKv7rb+5i3sv92uq8G+OLnct+k0LIzK3mXD/AHW/u7a+b9N8ZO+62eZQW/i2/LXY+F/E1gq7Jnkd2+4u793XkYjC8vvSPrsHm0JRjeR9g+Cfixpt9dLazX+2WaL7sn8W3+7XoUnjbzo4kv7a3hWP/ln/AOzbq+V/hb40sLm7hTUtSsYnj+W3mZtzf8Cr3Dwr4ZsfiRdIlz4h2Sr/AKpreX5WX+9Xh4iLjPm6H2GHxP1ilzQ2PbPgb8XvD2k+K4rO5hZtr7XkZNyqv96v0V+EvjXwS/h3Sdam8QRyHd5SRRy7V/3Wr8ytD+DWq/C/xBJqWy6u2W3Votr+Y0n8Vfbv7MPiDwV8QPA9nZ23l22pW67GtWXay/8A2VVQxUcLpHqcmOnSxVLlke9fEm5XXkNnpTxzwrubc0vyrXi/jBr/AE+5s9BFk0TSSxsixq2yuzuvBOpeHrq41J/Ekjxxtt8n7ytu+9Whpuj6d4muLC8lf/j3n/f/APTSP+7U1sd+/wDfPNq5fD6tFwex+cn/AAWe+FltoEnhL4hWdm0Dx38lrK0b71aSRd21q+JJFh+dJn3/ACKv39qs1fpH/wAFydPkvvhBaa0ty0aWviq1eKGOL5Nu1lZq/NqOW2WH5IfvV9dklT22D5vM4a9OeHlb+6TR3B3LDsVJVT5P4tq/3aqXlw0jL+53bvl3K+5f+BUt9HtYXNtbb327d2/a1Q3Vx9mjbYfkb71e7GJ58pe6JhPJV03A/eaRvvVY02HzJH859yt97/4mqdvM91j7rBv4v7taVjbyXDo+9UT7v3PlrooxnE5akixpNql1JLNCjE7vlX+7XRWNnD5j7JG2/wC0vzVSs7ZNqbvmbY3y+Uytu/2a3NP0maPZ8m4f3mr1acfcOCp/hJtN+aMb/wC9uSNvlatrTZHWZSibv9pvmaqmnw+Ym/ztxXd95P8Ax6rDM9o8To+6Jv4dtb8hyVP5TV8x2UwRuro3yyrTnAZyqPuz3A61QhuraGRnh+T5/nZv71W42IgDOwchfmKdCe9ftPgpHlzvHr/qFqf+lQPoOGl/tNX/AAP80W7W6e3kZ/l3bNu5n/hqG4V1uns5vnh3L96L5vu/3qqTagkLi2hfci/dZqurN5kKPcvuVmX5t/y7q/FfZ+8fMRj7xE0KQqdm5Ny7kX+9VGUw3ELXNs+1W+5u/vVbkv8AzJJUEGWX5vlqgt9uk8nYvlw/Ntb7qrUSlOMdTejR9pLQp3EaMuxLZcq25JN38VaOi6Dc31wj36K3zf8ALP7zNTNLsXuLhJng2RK/ybW+Zq9B8D+F/MxvmZl+bylk+9urSjHmPUjg/ZxViz4b8Jpu37I/m+aWTZ8zf3Vrr9J8NzXStvdVLLvTan/oVaPhXwv8qXLpGm196f8AxNddHoPmW5e2RY2j/i2/w13xlyx0IlT7HKWOhwyQ+fCnyyP/AHdu7/gVSX3h+2sbf7TfoqRw/K9wz7dtavi34heD/Celu80P2iWNNzxqnyrXgHj/AONWveKLpraFGuEkbbb28K7VVf8AaojKXNZI8vHY6hho8rkdF4u+JnhjTZJrawtZL64Vt22OL+H+9urzbxp8SptXuks9ShmuIZEZoLGxXcqt/dZqd9ovI8/29fx2X96GH5mb/ZrMvfHGg+HY/N0eFUm+YJNs+at6cT5rFZjXqe7E0re71W+hW5fw9Z6fab/+Pf7jSL/FurE1q88N2a74Y7fdJ8ySN83l7a4vxZ8ZLydZYU3B1Vv338O6vMfEHxQ1nULje9zu/h+/92tOZHmxi/tSO28ceOLa8upIba537fllZv8A2X+7XmuvaonL72VV+4u2sm98WXNxNsmOVb+L+L/easi+1a5jmb59zN/C1OS5jWPvfEUPECbpGmhfhvmaNVrkNc08M2/zthVvu11VzqRZX85/9la5/UJppH2STKp+6rNS+IuMjgdfa5t2b59tZsuyZTMiMB/FXVa5pcNxGyfL8rN97+9XMeS9rI9q6fLv+9soiacxVjupo5vkfdt/u1safq0b/uZuVb761z90r2VxseHZ89WLe6SObfv20+VE/Ebc19daPfRajbTzBo2Vt0b7WX5q/Ur9lfxR8Pf+Cqn7Hd9+zf8AFHUoW8b+Ebfd4cumf97Mu35fvfNX5VLfJdW/7ybmvQ/2Rf2kvFv7LXxw0r4keD9YmhaG4VbpY/8AltHu+aOqjOVOV0Zypxloh/xm+APj/wCBfjvUfA3irR7hJrGdlaTZ8rf7S1ylrNtkP2lGRl+Wv2P/AGkvg/8ADf8Abm+BumftB/D23t/tN1oyz3/kr92T+JW/2lr8wviX+z/rHhXV5Ib+w2Osu1GjX5f+BVxY7CxlHnhHQ0w+O9lL2VTc81kbzMTfcOz+F6csiSKHn4+X71ad54N1LT5pUmhZhv8Au1XXSX3bJoZNjfd+SvD9nKOx7Ea0ZRvGRf0W1TcjmbP+7Xrfwn8Ra94baJ0+dfN3bd/8NeefDT4c+I/Hvi+18M+GLEz3FwSyR+aqDCqWYksQBgA19sfAL9mTXPh94c07xv8AEn4WXKabc3rQ2utSRM9rLPGQZI0cfI7qjKSoJI3DI5rqfDXEmb4T2uXYCrWg5ct4U5SXNa/LeKettbb21OrBYqFGpd1VF+bS/M3/AID+NPFuuapbaVbabMBNb7omb5fvfL8telfDAPpPxis0u5gGgvplldsYyFcHNerfs1/ALxv+0L4uvx8EPA11rv8AZNuJr0QQrBHboc7VaSUqm9sHam7c21sA4OPIDN/wjvxWvG122msmttUuUuoLiBlkhbc6lGQjKsDwQRkGv0rwi4c4gwmX8T4DEYOpTrSwcoqnKElNynCpypRa5ryv7qtr0P0bJ8fh6mFqz9tGfLFttNWSVz6x0m/1LxIyWejwxzHZt3N83/Alr5P/AOCjPxU1Lw/qNh8HP7NutPm1CJb+XzomjeSFW27l/wB5q+mf2Rv2gf2Z/A3i+01r4v8AjmWCzjX97bpo9xMR/s/IhrH/AOC3XxO/ZN/bL0bwX8Qv2Z/FIvfFnhmdrK6sptFuLMT6e4zw8iKvyt2Jz6V+W8OeDfG8JOtXyzERt8MXRqL/ANtPj804lw8aqjTnGUX2aZ+cljeJG2x9qL/G3lfMy10uh/d27Nz/AN1W3K3+81QwfC/x6DiXR0wq4BNzGM/k1a2mfD/xfbsslxCRwBtWZPl/WvsKHh7x1DfK8R/4Kn/8iefWzHBT/wCXsfvRPa77VUd0+fczVq6bqCNIiXLrH8zMn8K10/wt/ZM/af8Ai3FLqvwy+DfiPxFDbORNd6RpElxGhPYsgIB9s5rJ8UfDD4l+Cdem8N+N/Ct5peoW8o+02Oq2pgliPoyPhh+VdFDhHimtiJYaGCqupHeKpycl6q118zzKuKw6V1NfeXtNvLaRdn2be67f4/vVvabqVz9neHzo2b7qf7NcVpmm+I7OV2ewQqwwVMoOa0LdNfRmPTccBfMHAr1o8B8aR/5l1f8A8FT/AMjjWMoKWsl953+l+IJo40muXj2fdbzF/wDHq6XTdYeO3TY7IsifJN/tVX8Ofsh/tc614ei8VaP+zT41uNOuoTPDdQeGrh0nhIyHXCfMCOQR1HSuT0/xJNp90Y9UjmjeJjG8EynKEcHI7H2rmwfC3EuOlKNDCVJuO6jCUretk7bdS/rVKMdZI9d0TxB9qT53j279v+9WvY6hM0e+bbt+6nly/erjfhJ4Z+I/xbvZbH4Z/DvX/EM1oGLLo+jz3YiRv7/lodv44rofHng/4nfBeC1v/it8LPE/hu1lfEVxqvh+4hikb+6GdACfbOa0fDXEFPFrCvC1FV/k5Jc3/gNr/gRKtSkubmVjq7PVIHVUtnba33m37q3tJ1a2hZPnmD7l+VU3L/vV5D4W+JehaxqbWmnXjj9wWZdjK2B15Ix3rqtL8QXgHlvcqyt9xll2s1cmNy/MMqxXsMbRlSna/LOLi7PZ2aTsZ+0jKHMnc9b0nXEaFZELb/uu3+zWwutLJbhHuVBk+Xb/ABbv9mvMNN8S3knV1ZPvPHDW3H4ihZmfzFLK+23X+Jm/2v7tZRkYVI8x12p3ztIHhRn2/K+56+cf269h1Hw0YidnkXW3P1ir25fEFtNs3ncGZv8A9mvCf225mfUPDsbFDthuiChz1MVfo/hXOMuOcKvKp/6bkfScGQtxHRf+L/0iR7X8Eiv/AAqDw0zbVP8AYtuqqf8AcHzVta00ccKujr8q/Kyt/DXJfBzWBb/Cfw/ayFcNpFsu70+QVs6priyRy2yPGgb5EmX+Kvjc7nbOsT/18n/6UzwcfT/4UK0v70vzZT1a8gaI/wCsLKm1PLX7v+9WPeXlzG2zf5X7rb5n96nzal9oXM25fl+eRW3M3+zWPqGoeZZhH2q6tt3LXhykZRj9opa1evNseFG2L9/y221zeoaghDw/K2373yfeq7rl5Naq+zcu51+VU/hrjNa1L95LZpuRG+40b7WrnlI6OVnQ2upfMsPU/wADK/y10/hy686PY94uGT7u/wCZq8xt9Uhjx5LxsZF/heui8P6w9mqpDdLhk+7t+ZWrn5uYJHqWk6htjMds7P5cu3bUlxcOYYkhufNRm+f5Put/tVyFr4kmWMrvWP8Ai8xadceNINy5mZN3y/KlVKXQn3DYuta3XG9Ewyu2xm/h/wBmsq68QQrcF5n4b7i/7X96sK41pod8KTbHmfcm5vvL/erBvte2/uft/wC7VfvM+5mrKpUHGPvHZT+Irb78L+Xt2/x1fs9Ze6aVPOXe3ypt/hryW88WbZP3Lrvb5dqr8v8AvVd8K+NppPkdN9wvy7mrGUuYfL757tpN9Ctp++mjdF+XbI3zNVxtW+0Ls8tk3JuRf4a4Gx8UJ5KXM3O77vzfe/2ak1LxRND5bs6qmzdt31nKRfL75+U+hq62ux4WKbNvzPW5ZyILVLb93sb+HfVCz08xM/75iPvbdv3auWcczNvhEinc29W/9CrwZYj3/dPu6dGESbdMrK838Xyr/u1BdSW21Uh8vP3mWrtvbvJH+++Z/vblqG4sU8l3jeNmbcrttqfbc0uY19jymTJawrGrxupZf/Zqht7M7nkdvvfw/e21oNZzIo5VW+8yqtNa3m2s8KZPy/M38X96nzc0feJjGX8pnbrYMqPuc/dT5vutUkfkxzRo/wAzL8u7f96l1K1aw/d7Mbf4aybi72wvs3Nuba1ddOMJ8tjjqSlGVpRN2z1KZv8ARk3IPmZf7taH2wMvlum4R/3f4a5mx1DzIx+++WOr9jq03mebD8m5NvzfxV0R+02YytLlsabSJJH52/btb522/wDstRRzJHCd8zL83y1Q/tB4Zt/nKGaL96zVWvNSF0u9PmCp8u6nGJjKp7wanqkJ3fPsb+9XN65qXmNvtn4+7uq1qV08bb0df3ifOu6sDVt/mO8LqC33Pn+7W8Y3OOpU98+pPhtMJP2TDM46+Hr8nH1mr4pvNQeRmdP+Bsv8VfaPwzJk/ZBJHU+G9Q/P99XxV9jfyykaZ+fb9/8Air9n8U3bJsh/7Bo/+kwPoOIkpYXBN/8APtfkit5n2jekPyVbs45lVP7n8dLY6f5cjK/zO391PvVah0yaObePmX71fjT+L4jwqcfeJbWGGWTZsZtrfK38Na9nDOP+WyquyqMNu9u2x0zufcu1P4a0FjdRsRN/z/w/w1zVOSJ6uHpmzpLQ/fTdt+78yVu6bP5bF4ZmUMvzq38VYOmyeaodE3Bn2qv92t3TYXkj/h/76+9Xl1tj2MPTqy5bHRaS0yrFDbJnd/e/hXdW7bxpHMvnOz7fmTclYOls8ewbNh2fKrVprdIzQpMm9N38TbfLrzKn8x6fN9mRLfLN9lZNiqJn+833mqCaF4UKIONu5d396nteRNuT95Ii/L8v8LVB8/nCNPubfvK3zVnL3o/EKPuj2urmRYXR1Xy02/8AfX+1ViGNIdvnf6xtv3kqCOEtcbx0/ut/eq9DG80zXMyLv+6i/wASr/FtrLm5TeMeaRHDDCyskMLL+9+dV+9T4983yP5imrMa/wACIu6FdvzPtZqfDYvHGEeFl3ff/vbqcZc0jaMeWXMRWdqJGXZCqhVZtzN8zVo2cc8kiwoissi/d3/xUsdi6yD5l+X5kbZ81XLS1/fAnaVX5tzfxN/dqvcO6j7xZhb7PDEnnMm5/n2/xVp6fcJBGmx9219r7vmZqotGYdr3KZ/etv8As6bvlqxbyPCqOibd33f722pjE0l8HKzRhvLZvnuX4ZPmZabN9mSHYtz87N8rN92oLWN5GV0T5Fb5P7q1dtbW2uvn2KxZ/wCLd8taxjDm945alP7JXjt3kjFtD8/zbfm+VVpYbONbiGaa5ZHk3fNt+Vvlq5Ja/uWtvLjc7N+7+7/s1at7OG4mZIbbb5cXyfxLtolK0eU5qlPuUfLea3XyYVSXfudZPvbalW1m8tH3/N91FVf/AB6tBbRJmZPOzt27P9lf7tLdw+ZNvs0YP91/4qPdjojkqRMZtJRoUd33srbn/wBms7UtP8uZt8O8r/t11E1q8jI43IPN/wBWqfLVHUrdPLf7L8kv3mb+H/dq/djpE4pf3jkrjR/Oj3o/l+Z8u3+Kq91p/kyhIUyqp97+9W9dwpHCNQuvmMfzbV/hqBrdLiX5+sf+qjZ9rN8tPm9/U5qkZcpzd1prsyPGka/N8y7vm/3qrSaWv2NIXdi7S/d8rc3/AH1XSR26XkYmlh2qq/6lfl/4DTZoZGby0ttzR/L8rfw10c3uxSOXl5pXic3HbzQ/PCnLfK21Plb/AHqt29rMsS7y33Pk/vVsfYXj2OifvW+5/d2/7VO0+1mto0e12sGZlZv4VWolyy1FR5o+6QaXYpDDJvdoljTbW9pcKKqQp+88xPn2tTdPh3JsdPmb/a+ZW/vVqaevl25hmT/a8xf4q5pS5Zcx6VGn7xNprOV85E27n+833WWuj0S1SSRU3xq0i/Lu2/LtqhbKkdvDC8O5FTdAuytLT1vG/ewwxp91d0abWWsYy5p8yPTjHlh7xq24mnb/AF0gKvteTZ92uj0mFLWQIgzt+bzP4t3+0tZGnybo4U+6Wfc3+1/tVu6fcQrMru6nd8q7fl3V6VA4a1O0DpNNhmWJrlId25f/AB6tbT2hFu0LzK5Z13R/3qy9KuI1hMPkyIsjbUb7y7lrU09vLmRZvnbdu+58q17WHieXVlyx+E6HQltrq4/ffu4mTci7f7tb2lW9rCq+SjFF+98/zbaxNDt0jbYiNtbd5TNXR6THNGoT5X3J8m1vmr1I+6eZWjyyOj0K/kZXRJtkTKzJtT5l/u10cMrwr5s21UZ1ZGVdzM38W6vN/GnxS+FHwZ0ubW/iv8RNF8NQRrvim1jVI4Gb/dj+81eV6X/wV2/Y68SfESx+EXwf1jxT8QfEOqXCwWGm+E9DZ47iRv7rSbaUqnLDmMXWoRjrI+ifFFxN4ovLlLDUpporO6+zeW1rsSPavzLu/irzj4ta9Do+mwW3nLHLs+WGN/vf7TL/AA16N8PdJ8Q2PwzvbzW9HurXVdS164e80e8b57GRtqrCzf3q+V/2n9c8Q+F/Fl9qv2BkRYPKlVm+ZZP9mvzzMq31uvPkFR92XqUfFHxK0S1vjeXV5MWb5Yo9nzbq4rV/jgl9pc2lb12Ryr5rfL83/Aq8S8V/ErXvE2rD7ZD5QWVkVfvVreCNNe81S3037MzyXG2KCGOLc00n8Kqv96vLo0eX+LK1j28HSlW+E9b0O4TVtLuZtYmVbaZF8qSR2bav+7XlXj6+8PWf2m20HWFnjjbb8rN+7k/iVq/RLQvEX/BK39iHwLpfhP8Aa9vYvFvxBvLCO6n0S2iZrfT2ZdywuIm2q397dXz98Xv2n/2cPi28+k+B/gX4L/sC6l22tvpFh5U8a/3mk+81YYqthcLCNRPmb6I+kynI8djHJVockOkpdfQ+DPiHqE0in7NMvy/M7Mn8Neaa9qH2e43wnKt99levqT4zfs122oeF9R8f/BZLzUbKzRrrV7Fl3S2cf+z/ABMtfJmuXCtcM6J8snysrJt217GV1qWLjzo+Wz7L6uXV+Uc2oQzRGTfuVl+7TDaJ5auj42t8q1Bbyfak8yFFbav3t33qdb3l/IzWboqRbtyyV6dSPu+6fO/FrIms43hLF93zfdq3b69cK3kzbVj+7VCZXLH99vVvl21JDNazb4Xhb93/AMtI/wCKuaUfslxlKPulu+Wa6t0e2+T+/tqte6XDdTvDDcyRr5W7bH/erofDdmLqJEez3p1T/dqxqHhKFlTyf3f3m3Vl7SMJcpp7GrL4TibGzmiwZpm3762H1XypERHb723/AIDUWqaOIV8yCbdu/h+7Vnw7b2cciXM0KynY29WqKkY1I8500ac6fum34RuYlX7Q8s3yvtVt1fZX7H6+J45orvw94P1KdZFVHaSDaqt935Wavmv4dX+pLJCmleBmuhD83l/Z9yt/vM1fcH7K/wAUviRpGoW39saVss/K2yq21fLk/hXbXyOZ1HKL5Yn2mSynbl5j6Ct/jN8fvBOoQf8ACQ/Bmxn0+4iWBdQaeFp1hX7zNHX0B8F/FHw68dWUmsP4e/s3VVWHb5f7v5t33q0fgN8Mfh/+0d4GfTfEunafq10sH+re42yw/L/Dt+7trzX4ofDm2/Zb8WQXmm3/AIo8PWMl1HEsmsJ/aFjJu+7833o1WuOnhZVKfPDY6qmKiq8qM9z6bh1mx0uyntteij8xvm8xdzVDo2uaKshSzmhRNu5mZvvVk+D9S8U+OvB8esaL4u8H+IbZXVWls7hkdfl+bcG+81TxaRYrI/2rw1a7JNvzRp/DRWoxjOMJI9HBuFSlKPU+cP8Agql4Jk+OPwA1qz8OaysI0OzW9WSKLclxJG27bX5RWNvNcQpsdlkaLf5cif3v7tfuZ+1/8NZvGf7OHizw74X0mSGQ+Grho0tdq+ZJt+Va/FbS9F228NtMn76HdF8y7WXb95a+q4f0pzj0PEzWpSlKHIjAk092jbejJu+by2Sq8On/AOkI8IkV9jfLXWalpfnw/uY22L80rb9rVmLp7xyDfNhoX/1m3d/49XvQ933meZKMTMtdFSRUh6P1WT+8v92tWx0l9xtgitu2r8qbttWrOG5k3iHco+7u/vVtaXYo0xSGwwy/c3fe/wB6vUp8/JqedKXNMP7DSOZI4fMYx7W+Zf8Avpa14fN8xbaFNyMm5l/u0+xsbn5oYYWd5k2r5jf+PVLb2KMyTeQ25V2bm+6tehRjE56kv5SG1Xyo3REZG3svltVhVuZlIebZ/wBM1Tdupz2vll3Tbs/3/mprRzQozv5jOu7738O6uuMYnLU5+UqyjbGQ7q3z/wDAdv8AerQtVij0gLGRsERxg9uaxL5UbytkfyMq/Kv96te0YnQctnIhYH8M1+z+DC/4Wcf/ANgtT/0qB73DP+81V/cf5oox3010yuAr/vfnXftWr7zxyWfnfdVm+TclYcM8yzBEtlKbN8rfxLVqW4to7GPzptm3dsXdX43y+5ynzXLEbfXz3UiIjx+WybvmqCTU3uplhmdpG27UjX7u6sqbUJlkM33f+esatuq7pc0zP89tuf8Aux/e/wB6ueUJnq4Wmd14TXy496BZtu35dm5lr1XwXpUPmedNucMjbFZfmVq8q8Ntua2R0+VW3/N/s16TZ+Jk0W1+2XLybmXcqxy0U3GmejKolC0j1C1utK0mxjtpkjik270jk+XdXPeIvjBCt0dK/tCO2t/mZG3fe/3a8a+KX7QFh4b0G41XVfENvbCO3ZYvtT7mb/gNfMPij9sa2ub+7+wXLXcmzylupvlX/a2rXTCPN77Pks0zmXNyYf7z6R+MXxd/tqS68GfD1GvLuOLdK2z/ANCavFdW8ZeKtPjmzYMpVN0sjPu+bdXkl1+1Br2m2d1YeFXa2mvtv2q6VP3jViap8dL+3sxNqV5nd9/b/FXVGPLE+Ylz1HzTPUNQ8eeJFZ0eGbbJ+9dpP8/drC174iefbjfcsJWVn2r/AHq8l1v9oK61i4Pkv5SL8vy/xU3TfiVbatcb9SRdn8at/FS5pyHGnI6O+8eJcSPbTTb9rbvL/u7qxbzVIZpH3zbPn/heqWqSaVeRrNZ3kafNu8tq5m8vHhfyU3My/wAX96rHH3ZG7ea0nmGV/vf3lqhcaw8iv87b9m3czfw1k/aJliZ5gpo8x1YPnf8ALu8tarlHzIsXGoIq702/7u/71RsyfK6HH91aPLh8zZs3N95GpJGT7WyMmfl+8v8AFTjyi5ub3WZl5bvIqp94turndctZll+VNp3fIy11zL5ZLu+1v4dtZ+paa8zIh+9J/t/doi+YRzGrabbapH50LqxjTc6r/erDuLe5jZUmhZWrc1TQbzTZmvLNPutuZf71XdHt9K8Tx+S/yXP93/apgcvHJNGwTa3+9UU008cyuj7Sv+1XZXnw98lWm3sm3+KsS98Nur70+b/ao5Zhzc0j7w/4Iy/trXPgPxHJ8BPG2syHStcl8uykuJd0ccjfw7W/vV9J/tPfBXQfE2qXCf2bGGaX7yrt/wC+a/I7wfJqvhXXbXXtN3b7W4WVNr/NuWv0j/Z9/aY/4XB4FsX1vc95awKl0vm7pN3+1upe05IcsjlxlOM+WX2jyLxP8BbnwrdXFtHbM9vJ/FJ8zf8A2NaPgD9lez+IUkVnDYXEcsjbH3Rf8tP9mvr34V+H/B/jLWLew162txFJLuZW+b5a/TL9j79jv9iC60Gz1iezivtUZN/79fLVW/2a5vqcefm5vdMKeIr83LE/Jf4Xf8EsPi34D1XTfil4e8N3WomeZbGytLOEtJLLMwgRFUdSWcCv1c+LP7FH7TPiv/glb4F/Zm0XwbHL4z0bWUuNU0ptZtlVIVlvGA80yeW2BLFwGP6V2/8AwVM8C+DPhz/wT88Tz/D7To7AwalpTwT2rkOrC/gIYMOQR61478aP2hfjrov/AAR2+HXxa0n4u+IrbxRqPiFYL/xDDq0q3lxH51+u15g25hiNByf4B6V+xcN0c8XDeULLZ0kv7R09pGT/AHvsVyt8sleFubmStK9mna51QbvP22r5ena/5nz1+wj8Uf2+/wBnv4ieLvhB+zj8L31jU4YJpfE3hXWdNZ0spbcFTMR5kRjlHKBQ37wlVCudgr5v1STxv8S/iVdzXenXepeI9e1qV5rW2syZ7m9mlJZFiQZ3tIxARR1OAK+1/wDgg5d3V9+1B4zvb25kmmm8EyPLLK5ZnY3tsSxJ5JJ5zXi3/BOOaztv+Ci3g271GaKOCHXdQlllnYBIwtpctvJPAAxnPbGa/dauc0sq4lz2vHCU/bYahRqynFOMqsvZ1JWk7vRciUdLpbuVlb7TgyDnlmOV3Z0pL00ZN/w6k/bz/wCEN/4Tb/hRNx5H2P7T9h/tS1+27MZx9n8zzN+P+WeN+eNueK+f9a0XWfDer3Xh/wARaTc2F/ZTvBeWV7A0U0EqkhkdGAZWBBBBAIIr9gLLTtXg+NEfxdvP+CvWgz266gJpPCudPXS2t882whF7gLs+UPzJ/FuLfNXxf/wWa8TfA/xp+1NaeKPg74s0vWLq48OwJ4lutHvFnhNyjMseXQbS/k+WDhm4VQQpHPn8AeJmfcQ8Rxy3HU4VIzg5qdKlXpqnKNvcn7aK5k09JxtrpbU+FxGFp06XNF/e1r9x8jV6J+yZ8GrH9oP9pDwf8HdVuLmKy1zWY4tQlswPNW3UGSUqTwDsRsMc464OMHzuvpj/AIJDaxpGj/t7eDjq8ir9pgv7e2LQq2Zms5doyfuHryOe3Qmv1DjDH4rK+E8fjMN/Ep0aso26SjBtP5PU5aMVOtGL2bR9B/t+f8FMPij+zH8X1/Zg/ZTtdH8PaH4J061sp5TpiXDNJ5KsIUEmVSKNGjX7u4srZbGBU3xS8a6N/wAFMf8AgmdrPxw8d6DBZ+P/AIXXM7vdaXDhJAqxvJhWJIilgYFlzxJDuHA2n5I/4KM6dqOl/txfEy31QsZH8TyzIWjC/u5FV4+B/sMvPfqeTX0x/wAEtZ4fDP7BX7Qvi7xJLt0ltMnhXfapIvmLp827hjhyfNiG08dPU1+HZjwtkXDPAWU59ltJRxlOeFn7WP8AEqurKCqKUt5KanLR300XY7oValXETpyfuu+na2x+ftfTf/BKLUf2b/DH7TD/ABA/aP8AGGk6VbeHtFnvdAXWkHkSXqkYfcwK+Yib2jXG5n27PnCg/MlFfvfEOTriDJMRlsqsqSrRcXKFuZJ72umtVo/Jvbc8+nP2dRStex9n+Pf+C2P7WNx8X77XfAF/okHhaLVW/szQZdGSRZrVXwgklYCbc6gFiGXBY4C8Adb/AMFvvh94SkHw2+P8PhtNC8S+LNLki1/SnWNZmMcULoZcEF5I/MMRfaeAgJG1Qee/4J4/sVeFPBvhtP29f2xbiHQ/Anh5Fv8Aw7p+pKQ+pzKQYrlk+80W/b5UYBadyuAUwJPEv23v2rPEn7bn7RE3jK2Se30aN107wjpV4yRm1td3ymTDFRJI5LuxYgZC7iqLj8bybI+H/wDiIuG/1Yw8aVDL4VIYmtBWjUlKKjGi2tKk4P35yd+V7tS0O2dSp9WftXdytZdvM+9viB41+P8A+z//AME9PhRe/wDBPnwTHqtpcaVbya3eaZpR1G4h3wCWSUQ7PmLzmXzHKfKQBhc8aH7A3xa/bD/aL8K+OdC/bs+Hvk+CJNBZBqOu+HhpjTBwyzRbNqCSLyg7M+35CBzzxhfFL9oTwr/wRz/Z38Ifs9+CtMuvF/i3VLaW/mXWNVf7LZsx/ezBVHyxGbcscMe3IV2Z92Wdn7LP7f8A4e/4KW6R4i/ZA+O/haXwtqfiHQ5xa6l4U1WWFbyMDMkaBtzRuqfNtYyRyKrhlx8rfjmJynM8Vwni8wo5ZCphJV51Fj2l9a9l7W7qqHMpvls9bpW15bXZ2qcY1lFys7fD0vbY/MrTrrR9F8Y3zaRcNLYRzSpaSMxJki3/ACEkqpOVA/hH0HSuw03xhbM0Sb9wb5n21x3x68D3/wAAfip4i+GGuXcc1x4f12fTXuIiGWQxuyh+CcZABx1GcHkGuWs/Gezb9nmk3L8zqv8A7LXoeM2Ko1uLoVaMuaMqNNp9002n81qZ4JNUrPuz36w8UW0MiTJfsD8qqrf3WrorHXkkjk2Oqv8Aw/w14To/jRJBsjuYyv3fvfMrV1Gk+KN1mN7szM/3Wf7tfkntPsnXyzPYbXxJCzJbXM3O7d/eryX9qHUBqFzozK+Qi3Ax6cpWxpOveTIl59pX7/z/AD7t1cj8d9Sm1ObS5pX3YSbBAAHVemK/SPCad+PcKvKp/wCm5n0vB0X/AKwUm/73/pLPYvhrrX2X4baNDblo5RpUI34z/CK2brWofJWFN3yr8zbvu1514A14w+DtOtt64FlGo/2W21oSa9DHj52ZvvL8u75q+Lz6rfO8Uv8Ap5P/ANKZ5GMp2xlX/FL82bd5qz28jzJDlJH+Zay7zWk8xkfdIn3X2/w1nTau/mFEvFDMzNKzf8s6y7zUbyNPtI2lm+bbI33lrxZVDn9mP168Mil5H37G+dVrlNWuLBlNyke5t33lq3rmrbYy6zKnz7W2r8rN/dWub1LU3+wB3dmWOXZ83y7Vb/0Ks5VC/ZsS4vHjme5hdT5b7tv8O7/Zra03XEtG37NjMy7Y9+7/AL6rh5L65N1FbQyYWRWZPM+VGVat2+v7HTznjR2+XzKzjKP2hcsz0+HxAlxalPti/d3P8m5WqHVNaj+R/tMaFdvm/wCzXF2+tQSQokM21lT5WWqV/wCJHWNXlfczfL83zNVRkZ8h02peLIYrzelzteN1Xds+by/7qtWRrWuJKyTWz7U+66yNXKah4ofzG/1mf7sf8TVg3niLzGZ5pmUMv3Vespe8VHlN688SJ5kzo3K/LuV6k0XxpNHIlykyqrbl2/3ttcBqGsJ80MNzhGbc6/d3VDpetJJdCaR2T+5urjlU5TqjThyXR9AeF/iHbP8A6m/2t975n+Wr83iaZl2fafN/hRZHrxzwnrWI0R3Un5tzb662z1BGtfkm85f4/L+Xd/u1lzSXLyj+r8seZnylHp/l/vkhZXkf5GkTbTzpryN5yf6xvl+Z/vVu3GmySSSfIr/8C+7Tls9zbNm4/wAXyfdr5n23Kffex5jOh0nyYZER/up937rbv96q8lqk6s7w7PO+9XQx2M1x8kjt83zf7TVn6lp8bODv2n7r7aqnU933jb6vzJWOZmXy2Ih8xFkb52/vNUflzbZZ3eTb/B5j/drV1S1VkH+9uZWb+KsfVriHzOXYP8uxV+Zfm/irrp1uaASwvLH3Sjqzedbkh12r821fvVgXV5tuGfew3JuStPWJHt7UmbdlfvMrferDvJkbHkupXZ89ejhbbHmYqjOQ6Obyo1RvmO/d9+rdnqU0aiH7qx/Mism6uekmfzPOT5G/753VNHceSy7UZf4mZn3V3yieVKPIbkl552f32N1VJdQQL+5fd/D96qclwk0sf77Ztb/dZaZcbFjWOZF+/u3bvvNUSlymFSnPl94Jm+0SNDM+Gk+X/drLvm3fc/h+7uqzdXTxt++Rn3f7FVpI/tHzwwq6t833qqUupyyp+8fVHwsjP/DIoiwcnw7qAweuczV8i2uk3LMYvJVW/jVq+wvhTEP+GWI4SMg6HfDB/wB6avma30MSMr741b+FVav2LxXny5LkGv8AzCx/9JgfUZ9GMsPg7/8APtfkjHstL8uFUdNjM/yVeXw7MW/cv95K6LTdBTy0huU2/wCz/FtrYi8OvGw2bdjfL92vxCWI5TzcPR+GRw66DcrComg3fNuWT+JaktdL3bUQNjdufb95q7O60H7Gphuk3/L8jR1XXRYX+dH+Vk3LurD2nNuerTjHnOcsbOWJTzj+FGX5q3dGt5vMR9/y/L91tu6pl0W2W3WFHY/MrJHt21o2tnbW0KI6MV/j3fw1yVKnNHmPUo7sWBo5FSbzJPKX7jfxVOuoO0mx3xu2t8yVB5cNvM485vKZ/k3feVdtH75Y2R33/Lt/4FXDy/zFSqRWxaa4m+0OjpwyfPtf7zU+OOZgqJ95fmdmb5az/MeGQb5v4Puqn3qspHDdR+dM6ouxd+5/vVlKP2gjU5vdL0MQW4D/AGyOFf4P96tDYjQpsmVXZ9su371ULWES2/necu3d8u3+Grq7Pm2T71X+KplUOqmW4YbZbf7/AJjb937yrNrG0i8Rskit95n3Kq1VjmS4k2TDcy/Kjf3quRqkaeWkytJ/00/2aUZG8eaUvdLljdJcR7441Hltu/efearpZJZPJfazMm/aqfdrNg33S/adysq/Ky1cb5Y/OWFhHt3bf4mrSMfe5jrpy5feLcLTrDL5jrDuXc391qnjuPlE3zMfuOv92qtqXuof3Yj/AHi/8B21ah0/fGPk2s25VZf4q1px933jeXve8ixb71txNM8m7c33f7tXrSP/AEHzHud2377fd3VHptq7W6P8u77rQ/3Wq3Z+bCp86ZdjPuePbW9OjGXunNKpyyEjjMli1y/y7k3bVfc27dWjpq/uVe2m8v5/n8v7v+1UUa2d0G37gF+X5m+9TvtCWrCFHXCy/wBz71KtRl0iYSr05RvKRcjhh+zlPmf5P4fvLUbTJ9ojuURt7fN8rfLu/wBqljuIW/cpy6/wt8tV7qd4JGheT5JPuNv+7XP7CcZKRyyqwlHSRKzQ7vnfeWX5lb5VqndW7yRvM67Y9u6tOOF2h37N+3+L71VZtjWbh9u1V2usj/w1XJOJ5tarCMveMe6VJFUNtV9nzrH91lrOmt/OjR0to98br8395a2prPbtffG25tu2NKZJYw3Ehkhmj37lRo1+8tFpxOfnhIx4YfO8tII5E3fwyPt+b/4mpYbPaz/dDbPvf3mrQuLUR3P2aNPlZNyzSJVyxt3+/c+Sieb88e373+7XQ5Tl9kx9yM+U57+z7mGFLq2uFZ2b513/AHW/2qktdJ89fs03ybl2/u/u/wDAWro4dJR43S2HO9m+b+7VqPR7aSJvs24oqfd/u1lKc+U1p0lze8ZWm2aRw7BCxdvldmX5lrXhtXKjMLbtm2KT5fl/4DVm1tfJjRE+Z2+Vdy/eqxHofl/M6K7xuyvt+bbXNyTqHo03Rp9SKG1f7OIbmZiqy/d31prbXV1tTe0YX5UZl+ZWp9nY7oVSZI1bZuRW+81WJI3s7dEe5jO5t+1Wp08PWlV5eU3li8NTh71SJNHbpDGib1R/K/1i/e/3a1dL+aMQv5iN97d/FWcti90qiZ1QN9yRv71a9tNZ2Vu9zc6rC32e33s3m/e/2a9zD4WvH7J5WIzjLI6Odzf0WJ47pYXuWfcq/u/4m/2q6TR5YdNUWFzNyqfJHI25q4aHUNYVU1W81qPSNPkXck0y/vZP91f4a1rjxNZ6PZy3mm2bRytFte8ZN8s1exDD1Op8rjOIaesaMTrb74meGPBenya9qrzeVH8sqyJtVf8AgTfdr4I/bI/4Lc/EfTJ9T+Fv7L01lptus/lz+JEhWWbb/EsLMvy/71eff8FK/wBtvXrm/f4G/D7UmjVV3a5qEbfNI3/PFf8Adr4cY7ucV0xo31PGljMTU96Uje8dfEfx58UvEcnif4i+MNS1zUZmzLealdNK5/76r9mP+DUX9lHSv+Eo8V/tmeM9Ijf/AIR+L+yfCrSQf8vUy/vZlb/ZXatfjh8Kvhn4w+KXjC08F+CNAutS1K8lVLa2tY/m3N91q/rM/Yd/ZV039jv9i/wP+z9olnHbX2n6JHea3df8/GoTR+ZNu/3W+X/gNfPcT476ng+SHxSPQybCvF4v3tkaHxM0XwxY61f3Oqw7Zr6Xz2jVvmZv7zf7VfF/7WnwNvNea+1XTnZreG93L523dNHJ/E26vpD42ePNY0uaabxPo8MDt/r449zRzL9371fP/jL49eD9BvlufFWpQtDJFvuI5vmZY4/u7a/NKOInTjzH0n1eFSryny3N+yjo+k3g16awk3szS3SyO2xd33W/+xrsvgh4P8L/AAX8J+J/2k/FVms03gu1kbQY7i3XY19IrLB8rf3fvVi/Fz9qiz1jxBc2GlPG9pHFuikjfcyru+WvHv2l/jZrGqfsi6P4TfUZmm1zxfNcXSt/CsMe1Vbb/vfdonPE4lx5/tH2/D+XYenXjJ68p8+X/iLxt+0T8TtQ8R63fyXl3fXUk+pXTLub/d3Vk6tL4i+HMzTaVdTRiNtqyRuysrf3a9f+APhP/hBfhqHa2hl1XXHZ/MjPzLGv8NY/x88e+DPD+lDRIdEs59QmbdKq/M0K/wB5q7faU/bRowjzRPWzXH1YQdRsufs//th6xDqcel6rO1tPDEyvIq/LdRt96Nq4T9orwz4e/wCEmj17w/bRrBev8iwy7lj3fM1ebJ4iln19b22tI4EVv+WdavibxBc6hpscPnZhX5tv92uqODqYXFxnR92L3ifnuZZj9dptVNSdvCaaPDseFWaRN3zfwrVG509PtDWaf3NyL/FRputf2ppZf7eyPap8iyPu8z/ZrS0W8S4tVvHTefutu+8rV6salX7Z81KhHmjymZb+Hb+ZhNbJ8m3+Kr0Xh+8t7hneHKNt37fu112i6lYLZ/6MitLs3N8lbOnww3EcU14io7Ju8uP+GuOeI/eSO7D4PmnEyvCelTWcY86H5JPufJ/DWvdafbQ2LQ7I1Ez7l3L8y/3quqyR3Cw2z8/dfbUt0sN1pvzvt2y/P5b/AMVeTVlPn5lI9/2MKMOZHD3nh/7RdtDDCzQ79u6tTRvB+m6RajUnRWK/djb5mqz5yWszwzJGPM/1XzfeqrqEl5Gqo/yhm2pt/irqlipU4cq6nlVIx57mnb+IPFU0zvDr0lhZrKreTCu1ZG/hrpvDfxu8W+E7Wa2TxLdXDyNu3SS/dZf7tc5oNuJLMQ6lD+4VN7fL92tQfGb9nb4cWKW3juOOV1vVaKFYvMkkj/irz4U/b1eSMOb0Lp1amH9/n5TqtD/bd+LvgGSHxD4S+LVxpWob922xumRmZW+VpP4a++v2Wf8AgtrqnjzwXP8AB79qDw/pfjG3urP59QO2Kc/8B+7X5IfFz4q/sz/EfZP8N3urSWOVv3bW+z5W/wDia4mO48W6Nfx6r4b8QSBoX3RFf4v7tet/ZbhCy9yX94y/tOtKd6nvo/o5+CH7SX7H1rd3Fh4Xs73SLy8dWsbdk/cbdv3dy/LXX6X8WFtfGVppuzzbPUN3lXC/dX5vu1+D37In7S3x1uvE9tpWo69G0Sy738xd3lx/xbVr9Wf2RPiVZ/Eq1h1LxDqqqNNi/wBFbe26SRv9mvBxmAlRxC5pe8foGS4uhXw8n37nvf8AwUq/am8H/sr/ALNU15qWoxnUvFP/ABLtGjkb5JJG/ib/AHa/IO+kvZNSN3JtR5JdzeTuVa92/wCCt/xu8PftOftReH/g7oV3Nc+FPhfpyyX95D/qptUk+Zo1b+Lb92vAWunaRpvut8zJtbdur6vK8L7OlfufLV6kfb27FjdDcMHR2dm/iVvmqjJCvnMkb7Ssu5o2pYZnjVHmdtzfN5f92pZGhuofuKH+638W3/davSjGEp8tzmlLrylu3s7aSNXmRo0b7ix/NW7pdrM15sRG2KnzNJ95V/vVj6bb+XG375flX5fm+9/vV1WlrDeSGEowdYvmZq7af905pk0cdzGB5McjJ915N/zL/dq19heGFkeH543+bzKm02xuY2Te8aKqN8q/8tKvQ2afZWREaUxv93f5lenT+A5nHmMaRYbePyXk3/P8rSVV1Df50r/dk/u7/wCGtKRd0jQvc7mWJldV2/erN1dtxZ5trR7VXdv+7XZGJhL3vdkZV0r+Yru8YRU+dV/har9sFbQ9u8MDCwyv41DfTIyuk275k3LuT7tT2mU0bMhDfu2JweD1NftHgtGP9r47/sGqf+lQPb4bdsVVj/cf5o51pHh2FEY/wtueqU15NIpPzFV/hb7v/AasapeQ2rb9/mIqbvLj+VmrmNUvoY18tEYrHL8rb/mWvyj2fN7x8z7bl2LMl5NJcP5M2xWf5Gar+k3CQt5dzc7mb5pWVq46G8feIZJssqf99VpWOsItwiQzfOzbUrnqU+bU6Y1vc+I9S8P65Bb2aRo7FW+VGri/ip8fLbwjp76am24mX5v3j7dv+1XMfEj4nWfhGzZEuWlm/wCXdYfu18z/ABK+Il/fXTzalcs0zf3nqI0eboeVmWbc0fY0v+3i38VvixqviS+k+06k0jTN95n/AIa4q3vnt7d7l5l/vbawZtS/tC8d55mJ37lVadqF8kdt5PnbP9ndXTGnCJ4NjRk8QP5jvI7bf49r1h6vrmpalcDZNuij+X5ag+0Qyw/OPvfdqGNkiV/n43VX90rmLf2v7PDvdNq/+hU1vEj2e5IX2Ls/3v8AgNZuqatDt++o2/L/ALtYtxfPMu/5mLUc0R8p2un+LppJPJd2Ybf4vvVvWt4mpQ+c7qPk+T5/mavLrW4fer/eH+996uo8J6xukCTPx91d38P+zURl2Mv8R1qQib/SVDNufbtanLb7Vb727/fqa2WRmR/4G/h/u1ZmtfJkEKI395WrQn4feKqxGOPfsZfM/ip11Hube6M3y/eq+LN9q7v9371Maz3SNuhbav8ADVRjGURfaKFtbvIu/YoLfxNViTSnC73RRtfdV/S7EM2/7y7tzLsrqYdDhmtV/wBAVv4vlrOJUpHns2lpJH5czqrfx1y+seG/s8g1DSv3My/3Xr0nxBoqWbPGm1XX+GvPNQ1Z217+x7l9ir83+9Ve8HNzbl7w3qmq31j9g1K2Xdv2vM38VLqWj+T8/wDAv8X96tK3js1jVEdv7u1f/QqmvI0mz/FVRAwrWFN3yJ/d/grsvhx8SL/4Z+IbbWLaeT7HNKsV7bq+3av96uXWzRmKb+aka3eS1NnM6n5P4v8A0Koj70zOpT5oH6R/BXx5pt3pdt4h0rUldGVWiZvvV9q/s1/tBTW7Wlt9v8k2qL8rPt3NX4//ALEfxmSO8f4darqX76P5IPOf93tr7d+H+tar4ZvormO5Yo207V+WtqlP3PcPFlKUavKz7d/bv/aW1K6/Zl1H4VX2qpNbeJbm1ls4ZZgZVkinjmkIHXYNoBPYsPWr/wCyt8Qv2bP2vf2AbX9iP41/GvTfBHiDw/qbT6VeX8ccKNCkxlSVGkKRSMRNLGy71kOC2CMk/I37RPjB/F9l4enaTIhiuFCnquTHx+lWbT4XeFNEsNA1nWvDj3tvqenW9xKPtbplnQE42kY5zX7zgo8P5J4UZficdVrU6k8RKtTnSjCUqdWHNBPlm0nHljqnu32OmlWlSlrrdW+R9M/8E4/En7Pn7GH7bHxC8OeK/wBpDw3qOgW3hee00zxTGzxW18yzQzMikgqZAsbDarsHYBY2kJFfNP7IHxZ+H/wf/bL8N/FL4hTGTw3Z65cjUpo7ZpQLeeKaEyGPG5lAl3FQCxUEAE8V2Xjb4FfBn4i6v4Z+CPwB8LX0XjrUna81SS21E3SW9ljhDG7HEhwSPWvlv9p3xncfsr6V4w8RXfhGLXLjwleT2n9k38skSzzLP9nAcxEOMOwYhSM7cV9TkOfcJcSf2vjYzxE3PDQjXco04NxpwnFypqDaU5JydnaKdraaH6FwbKawGPStpSk1v1TP0sP/AAT+/wCCYDeKz8dD+2hpn/CBlv7S/wCETGr23neX9/7Pv3+fsz8vleV5235d2/5q+Uv27Pip+zv8V/jrdar+zH8KdP8ADHhmxt1s4ZtPgNumqsnH2r7PhVgBGAFChmA3v8zED4y/4Jk/Fb4rfthfHeXw78Tb6yt9OnCGLS9NsfKhtw0m3Adi0rn33EV9Q/8ABe34Dav/AME2rT4Oa38G9WkisPGUl9b+IZriATg3KJG8SqZc7BhmyByfWvn+HPEfhrK8zWNx2NxuLlCLhTU404xjF2vzRhNKpN2V5zu+tr2a+HrU5uPLGKXocJXS/B34peIvgl8U9A+LfhKOB9R8PapFe2sV1HuikKNko467WGVOCCAeCDg180/swfG34gfE3xnf6P4s1iO5todLM8QS0jjw/mIucqAejGuM/aM8X6hpHx11KyivZo0W3tyCkpAXMKdq/Tc+8TspjwQs6o4WVajWm6LhNqDaalzXtzq3u2t1uYU6DVblk7dbn7o/GT4Z/wDBPX/gpjrFj8e9H/ai0/4feKZtLt4/Eul6nJBGzMqDAdLhot8iAiMyxsyMsa8cZrhf2t/2jf2YP2av2Pf+GF/2O/GVv4pl1m8kPjDxEB5w27kd281VEUkkhWONTHuVI4iCd21q/GDR/iPFIsem6lqbfaEVmtpFuDtZW/hraudZu1Qf6Y3ypudvOLV/NeXcd4TC18NSxEK9bB4WSnRoTrQ5Yyj8HNJUVKcYX9yLdlZbrR+39UjUg5wkrvd2/wCCfql+wT8Iv+CbHjv4D+LNc/ax+I66f4ptpJRBBd6y9k9lbCPMc1lGjYvJS2/KFZcFFHlgHL43/BM34FfslfFL40alr37Q/wAWtJtNL8NyrcaL4a8QSpZprQ3nbJM8jeWUTCloAxLlufkVg/5YalrlzJMkw1SZNq7t28/NWZN4yvd2Ib+Xhv3v7w19DjPFvFYqlmUacsRB4vl5f30WqCWjVJOl7qkrp2aezT5lzHLHBJOOzt5b+up/RN+2p8B/g1+2j4gsv+Ei/wCCjPhHQvDWkKP7H8K6fPYtBBJt2tM7G8HmykEqGIARflUDLlvij9sP9j34Nfso6NoXjP4TftfeG/HeoT6lhtHtIYnmiCYYTfuZZkKAjBEmzORjf8wH5VjxVOsph/tKf94u1GaQ7qjk8XX3nB0mcpGv8U5WvH4U8S8z4UjQw9OrOeFp3XsbUIxknfeSo82rd278ze71uXVwsat21q+uv+Z++3xM139g/wD4Kt+DvC/ibxj+0Fb/AA6+IWjaSIL+DU2jhUZO6SLE5RJ0Dh2jaOQMBJ8wydoT4GfDD/gnd/wTR8ST/HbxP+1jaeOfEcWnzw6JYaKYZnQOmG2Q27yYkYAoJJJEjAcg4zuH4Dt4y1OTaft86p/10NMj8ZahAoT+0n3q33fONea+NIQwEsoo1MRDLpXvQVWnpGTbcFVdDnUHdq2umjbvc0+ry5udpc3ez/K59lftg/GDVfil408RfGHU4orS68R+JJr14o0AWLzWdwnAGcDAz1OMnJJNeOaP428m6aZ7ltkjK3l7/lavIf8AhNpp0a4lvJWU8CJmJq7b+KrmaRUhuYwiv83y/N92vM4z4rw/FObRxVDD+whGnCnGHNzWUFZa2j08jTD4adKFm79T3PQ/GVhMyfJviZvvM3+rru/D/jVLiP8A0N2RWdVddv3v92vnjw/rXl7Hn8t2ZNyMv/xNeheHfFDxtHvmZF++kav91q+MliObWJ1xozPcbPxBeTSRJDNt+b5IZPvbf4mrN8bakdRmhbaQELjJXGenNcjo/iK5m/ffaVkf73zfLtrUbWX1mNJpQu9V+Yocg1+m+D9fm8QcJHyqf+mpn03ClGSzulN/3v8A0lnfeGtce20W3is2yUhTevvirMniaGPdsfj7rtv+bdXBDxUlpAtkjRq3l7dze1R/8Jh5yNDDYbTs+Zq+H4hr2z3FL/p5U/8ASmeVi8PJ4+o/7z/M7ybxVNDMiPc53Ju3f3qrzeKZpVDo6lPmXd/tVwlv4kmk8ua5jWI7tztH83y1Y/tiYM3kzMg37tu35a8GWK98f1Xm942tU1aPbMjwsf4tq/3v9msHUrh5GmdnkXyV3eWvzNUVzq9zNtmO0hvnRv4VrK1K8eRi/wBsYfN80K/wr/eqPrEpbFyw8YwJLq6hWSF0/ii/1jN935qyZPEG5nTf937zN/FS6ldeZG+/ciM3yfxfLtrBvj5itNs8zavzbm2s1bU6hy1MPH4jqI/ElnHsmmf5tmzzP937tQyeKkvpmRJlO5G+ZWrhm15FkT5Nqxy7tqt/s/3qrf8ACSOq703A/wATb61OfkOqvvEUMkawwvvb7vy/3ax7vWIR/oyIvl+V/e+7XPya/wCZC01nNv8A4Xb+Jqz5taRrdnRJP91komTGJr3GuQ/OPmX97u27v/QaWx1TbmMOzJJ92SuRvNSe5U+duVvvf7VX9Pu55o47n/VL91FZvmb/AGq5K0eY7KZ6b4d1BFaNHdVPy7K6+2u4b6XzvtMjL91FjfbXmGi6g62p/ffe2/6z7tdRpd8YlEOxkVVX95/C1YRlGPu8x0xo9kc82jzRsU2KfL/i3fe/4F/FQ0aW9w0EcKu+z523fdraktXEYSZ/uvt8v+KkuLe5aN0hKl1+Wvj/AGnN8R+g06PMc4y+TJstk3bvv7n+Zao3kflu8yfIrP8AdX+Jq2b61SNm2MzFlXbWHeXH3pZnYsr7kjWtY1OaHunpU8L7vKc/fSJMzpMm6sLUlhWT99J5YrZ1SORWKJcspb5vmrG1RXkczfMrr8yL/C1dtGXuHV/Z/u6RMe+bciTI+9/4pG+7WBqK2f8AqfM2M38VbF19pmm2P0Z/urWXqDeWvkvtZt/8P8VepRxHwnnYrK5cvMZDb5PMeRGXa33qGnebefs2xFRf+BNSszqyuj7/ALzbW/u0lrGkmx0K7WTc3zf3q9CNaLifK4rAzpyL8MKSQ/P8zf7PzUyT5t8Lp/urUunw/Z22JMrp/H/tVaksfvSQo21f9n7tY1Kh53sZy0ZkzW+1Vfzud/3V/iq5ounPtbZ8v+zsq3b6TGsiTI//AALZWppun21yrIjsZV+Z/k21Eqn9446lM+hvh1AIv2dEtwwYf2PdjPrzLXhFhoqNJstrZU/vNs+9X0B8P4PL+BUcEgz/AMSy6BGfUyV5PpemvMqoibPnbav91a/afFpxeS8Pr/qFj/6TA+gz9L2WDT/kX5IzbPQ7Zdzo/wDBtWT+7V9bJ5LhIZtwRtu+Ra3rXQ7ZWTzrZcSfLt/vNVmbTRHtSGwXydn3a/DKlSHwnl0JSiYUmnfuVhT98y7tit/FWfcaTItwXtrZRGr/AL3d/wCy11raXcyRlIbNR8n3o/vMtQyaG6Wav9jV1VfkjWX5lrmqS9melTlzbnLzaebiQI9tJhn+6v3l2/xVWazmVfJRPl/jZk3NXYRaS7Wzp9mkRFXf9z+Gq13p0f2V4fm2fe2su35awlKXwnTT/mOSuLVJo/OTbuZ/vVUkZ5I0m+7u++v3dtdDcWKSQu/2b5P4W/irEuNPm/uRtKybvLV/vfNWfN7vKa/3iOHYshSeba7Ju3feZamtW85lhfbtZdyN93c1H2PdCg+x7JF/iX/aqeO18nYHffK33KXuRIjKRYs4bmSSJCVVdm75f4a0I4Z41W2dF2L8zMqfxU2zsXZ0f5fm/vfLWxHp7tHsSFt2/wCRt/3V/vVySqHoU7/EVFsUmj37Knj8u4ZLN3jC7vnkb+GlaDeG2fK/3dy/db/eq1a2SbkuYUYRs33ZF+9Vx5ZqJ0U5E1hH+7aaFFJ+75bfKu2tOzX7G7XNnDu+8v7tN21v7tLpVrDIoeFmVW/hkStmysYVkSZI1T5/nb+7RzTOqNT2exlWMf775LZVK/Nu3bq0mt3XaIXZzIn+sVflVv4lqSa0RdSdERvl2v8Au0/hrJ+NnjhPhv8AD+bUvDztNqcz7YFVf3Vuv8TN/tV6uFw9XETjY480zShluG55y97+U7nQfBNzeRp9vvLexST5lkupdjbdv92tBfhg9xZyw6J4z0u7uY03W9vJLtX/AGa+I4fjd4z1LXpb+8166eS42rceZLubav8ADXR6D8cvFVrfJdWesSJJG+7asv8Adr6GngadP7J+aY/iXMMVV5oS5Yns/wAZvFXxa+GsLWeveDNPjtvveZprM25v95v4q8ruvipf3FoupWviFV8tvn2y/d/2a7W4+MUfxK8A33hvxg+97ja1u0b7pFb/AOyr5S8eXeq+B/FDJbXLRpH5iy2q/dZa640YdIniyxeKqSvOpI9b1D9orxbpuobLbxPJ/wB9feqCH9p7xOzDztY/d79yxt96vK9S1Dw9Haw39s/mpNEsqNJ95W/iWsG68WWbzOn2aPbv27t1V7Kl/KNYnFR+1I+iof2ltYhjDpqv3l2vGz/+PVNa/tMX9wwRL/5lf5l3fe/2a+arXxPpskmx93+z8/3asf8ACQabEu/7TJu30vq2Hlq4h9axUvtH0lqX7QmvSRj7Hfxodu3av8X+01SQ/tD+IXhihS9YfL8zbvm3f3q+arjxVD5izf2kzfLjb/dotfHDruS5vI3Tf8tP2FLpEXt8RGPxn0+37QmqzSbJtYkYLB8it821qsn4/X80gd7yOXd8ybv/AGavmqHxk7fxqf8AgVI3jK/U7PtHy1H1WG6iH1nEfzyPpmz/AGhpoXZLnVN3mf8ALOP7rVctfj99oZEsPFDRMqbfvbvmr5Sm8ZXjP532ln/h/wB2o/8AhMoYVZPtKr8/3VSl9XpS15R+3xS+3I+rtQ+N3iTa6W3iRZpZE2/M23d/tVGvxq1vT187UtSmilk++0d1/D/s18pv8RNrfPeNtX5fl+XbVab4tTKvkpebgyf3qtUIR15SY1cRH7R9oaP8evD1wrQzeNmtvkVUa6f5lb+7ur1jwjcaJr1rDf6br1rf7l2tJDP5n+7X5fX3j77Wqv5zBlf+Jv4q6b4W/FLx/pOqInhrxDdW0i/xQysqr/tba05XHYxkpVNZSP051jXtE0m3ijS//eqm1Lfd95v7q1V8TfGbwB8EbGPWNVe31PXJomS301k3RQ/3d3+1Xx3b/tCeJ7jybzUtea5uLODZA395v4mqlJ42vPGniJZtQvGY/ebc+6oi5SkZ+z5Y/EfXXwz8feKvi14i/tjxa63Vs0TbLNfljj/iXbWf+2F+0xbfDL4W3k2ia232prPy7VVT5d33fvf7NcZ4D8XQ6V4QS8sL+SP5V/2fmr5T/bg+Ll/428WLojvGsNquzyY//Qq1lHl+EVJ+0lzHguqXOq+J76bXtVvJJrm6laW4mk+ZmZq9S/ZB/Yq+Nv7ZHxd0/wCD3wd8H3eq6nfXEaZt7fclvGzfNJJ/dVa534c+CdX8eeItN8H+FdEa/u76eO3gt1T/AFzM33a/pO/ZO/ZQ+G//AAQd/wCCTPjX9rvxpplo3xHHg2S7uLxk+ZLiZdttap/tbmXd9K3hDlpc89iqtZyqqjDf8j54/wCCbf8AwTN+BvhT9rh/2UPhnNHqUXwtij1P4zeMm2+ZqWqfK0Onwt/DGrfe2/3a/U7xZDpt19pRJlhMP3WVv4q+Ff8Ag2n0maH9kLX/AI3ePXkbxN8R9fuNZ1a/umy0ytM235v7tfYHxO8QWdu815C63EMiN5U0fzL/ALVfknFGN+s4ySX2T9I4fwTw1G8ux578ZLPTP7FZ9YSzumZW3rJ/6FXwT+1B8H7XUtQbxP4eSQfat0UtrGyskK/7K17f8ZPjTqV5qV5o9hfxtF5+12b7yqv3dteLeKfiBpusWo0q/v44Nrt5Um7azNXzeFnKW7PbjhY+05nufHvib4Q69ot1ea3rtzdIiy7ovLTb93+GoPFljN4w/Zz0nTbzzm/s3xyqpcXEW39zJH833a9d+LvjLTbHS/s15qv9pSSbldVT/UyL/Ey/+zV5pZ+NpNe+Gut2d/YRomn3tvexLG3935fu16FSpXnS54n0OUVI0cQozOo+D7aJqnxE1jw89ntfT/D0n9msvzKsnl/K1fFfje6vL24lvNRud9y0snmzM/3vm+7X2V8H9Pv5Ne8QeOfDd+zyafo0k6Qq67pNy/d2/wAVfCvjPxJNLfTJsVEaWRvL/iVt3zLV5LTnWrzkYcQSjGhYbY6hpGlTx2Fr+9nupdnmN/DWj4ksZtEtfLfcV/iz/e/u1jeA7LTr7xpYvqR3RM//AAHcv3a6j4rSJb24eFF2ebt3V9HiFy4iFPufn81zRk2ZGh77y1d0RY1/hVq0dIW8sYftTpJ5bfw7qq+DYXa1R/l2yP8AxV0t1ZpJDv8AOVAv3F20qnNzSMpa0lpqVtO8SPYzM/8AC3y/f+atqx8XXMezZMzLt27pP4Vrk9Qh8y4Kb2VW2tuWtvTYd3zx7v7y/wCzXnVox+I3wdWcauj0O+8M332pD5O7bN8/zV0UPh68uYd/ksu35lhj+X/vquS8F/K299rMrqybq99+G+l2HiK4jmgddquuyFf/AGavDxlT2crn0cf31I8x8M/C258UeIBZwurI25l/3v8AZq74q+EV54f8RW+g3Ls0cf72eT721f8AZ217+3gnSvAjDxK/lwvbuzRQxp/epfh7oOieLPiM0z3MKXKy7UvLr7qx/wB6vOjinKfN9k4Hg579T578O/B/Uvjd8UofhLYaxNoNrfQL5F5fN5G5m+6zf7NenfH7/gkh/wAM0fDePxr4q1WSHX47rbYatap9ps/LaP8A1m5t275m+7X2Vb/sT2fxeWHxDoT2o1a3i3Ws1w26JmX7vzfw17BP+xL8ffEnhGPwf8Q9YZrCGLcvl6izJG235Vhr6LL81lh+WNOPzOatl9HFx5amkj+cvUPBlz4R1680SS0keazlZJ2kgZP3n97a396uh0e6mjsR9pdvlXb/ALtfqt+1x/wTV8MeF57GFP7Q17W9e16zs1uL7a0vnNJ833f4VjrhP+CiH/BNn4afBfS9Qs/ha8b3Om2dusW3a7yMy7pK9avmmGxH8RnJ/ZWJoT9nA+Kfgi/xEXWJLz4faVNeSSRNE/lp83lt/DX2Z+z78UPjf8F/B8viq70G4tbqa1aDTbeSXb+8Zdu5t392pv8Agi54H8BxeNpbD4i6V9pSS88ho5Pl+zsy/eavr7/gsD+z7Y/Db4b+C/iR8N9P3aJbzSWGttb/AHbdpPmjmk/2W+7XkxhDF47kPoKdGvl+GjPm+I+BraH7Cs32+8865uJZJ724Z9zSTM25mak+0JcMyIm5fuqzJ95v71SfJDv2Ooimf/WKv3v9qq6x7ZDH8zlk/wCWdfWunGEOU86MrT5hqSTNt+8zqu1l2Vcs/tPltDbWbOkf8KpSraQyKltO+5vK2/d+bdVu3s59pG9drfK8jN97/drkj70fM3lzEmi/vpFme5jVW+Z12/Mv+zXYaWvzwiYqdzszbWrntA0fyZmkeGF03N8yv97/AHq6zT7cf8uyLv2bZfL/APZa9DDx9nozz63vF/TYUmupU+XYyfe/iq+s3k27w/MHX5VVUVd397dTLNfJtfORI9rNtXbUL33l25e5hkcM+3y12/u69WjzchleMd5FDVtkyp5IaNlbc/y/eWsa6vJmke2mCpu2tE0O1l/4FWzqypMreTN5X+1t+9WDeW+2GW5877r/ADfJ96u+jGMfiMZe7rEoveeZJLDDNGG+7t21ctm/4p5mVM/uXwBznrWf/qo/JeFisnzeY33Wq9ayGTw28jMpzDJyBx/FX7b4ORis0x1v+gaf/pUD1+G1fE1pf9O5fmjhbyaaONvJtt259rNv+Za5rWrhG3u+51X/AGtu5q2dW1Sb7OZn3YVWV1VfmriLy8Ox5kTG5/vf3q/JpR5o+6fEynzSuMuLy5VUh+07Ubcz/wCz/s1qaPdQWqm/v/uRruaRf/Qa5+FYrp2S2hYBk3eZ/tbq5n4pfEKwtV/sTSpvlt3b7RJv+Vm/vVzVv5Tlq4j3TM+LHjqxvry51KGbY0nzbV+ZV/3a8E8ZeKPt146b62PHni8XE2xHz8m2uCuJJry92Iitub71L+7E8/l5S1Hqrxrv85lVf7tTQ+dI38WGXd/eq54f8J3l2vyQ71kfbXTN4Lm0+NPOh27dvy1pyi5oHJxw/d3vn5PkqrfTOsjb9qL935v4q39aW2tWaBPv/e27Pu1g6kqTf6xFbb97dUSLj8Rj3W+Rj2DfxVWVX+5sXNX2h3ebsG3dVbycKnybd33m3Uv8JfwkfnZ+T5v73y1e0W4eOb5G+VfmqrN8sfH+7SW7OPnQZ2/+hU/hJPVvBN5Nq0aQvhnb5fmfbXc6b4PS8jZDy/8Atfw15J4K1j7HdRTO/K7a9r8KaklxarNC+5ZF27l+bbTjIzqR5omRfaK9kyWr7X+f+H+GlttHudweZP3Xzbd1bEi+ddNvhZVjlbc2z7zVNHa2zMuxGXb/AOPU/h1MYy5TM0y38q6/1O8b/u10tir+SqJtSL+8tZ62W1lTZlVb+H+KryyfY7dt/wDu0lHlKl73vI4/xpeJpt8+xPlkl3MzV5r8SNBm+yxa3psnzruZ9td38WI3t7WGZLlnG/e1ctperJq1vJYb1YN/DIn3Vo5eWRpGUpQKHgfxMmsWPkvdf6TGn3WrpljeRXT73ybmVa8l1YXngfxY4hRkG/dt/wBmvUvCepQ65ZpqSP8Ad+8u2l/dCS+0LJDunUp8m1PvNUGUWQf+g1rXlvFtZERvv1nzxxhVR5vn/vVUZAVLXVrnwP4s07xVpk3leTcKzzV+lP7NPxQ034reC7LUkeOWWSBWlbzV+8v8NfnNcaXZatYvprso/dNt/i3NXtH/AATm+Klz4N+JUXwu8SXn2e2vLjZbs3/PRvu/99V10Ze4eVjMPzfCfc3xCiuYTaLcLgfvNv0+Xivqb4a+E/CnjP4T+DBq17b/ALvT7ZJSgzIo2DK/+O185fGvTZtLtNFtZmPEU21T/DyldR428Q+Ovg1+xB40+O+mWtzMuheBpZLHarbftEsYii+7/d3bq/Y+KaV/CDJor/n5U/8ASqhyU3dRU+p+YPxm/be+JGrftsePPjT8H/idrXheVvEE1jolxod60EkNnD+5j+b/AIDu/wCBV9B/GjU9Q8X/ALLV3rninVLjUbvUdEs7m/vbt90tzM7RO8jk/edmJY56k1+atlPc2zrctc5f78sjfeZm+Zq/RjxzOD+xdazuw+bwrphJ+ogrz/DGLjleeP8A6hpf+kzP1ThOKWBx6X/Pp/lI4X/gn58Sv+FK/tDeHtY0FIYUmvVS6aT723+H/wAer9Zf+Dpq30f4w/8ABIf4fftCaa8bzaD400u4imX+Hzo2jkX/AL6Va/EPwrqD2OsWmo21yqSW8qusjfeXbX66fF74n2P7U/8Awbl/Ev4Xatfx6hrfhHS49VttvzN+5mWTd/3zur8hjKUKyZ8NGUbuB+bf/BP/AFKLVfFV/dRyK3/EjIYr6+bHWH+1vcT2vx71N4UZ98NqNo/64JWV/wAEt9Z+3fEHWrDDDy/DofaenM0deqfFv9nr4hfGr49X9l8PvD8+p3c8UCJbWkO+QkQLX7JmNWNPwKwspv8A5in+VQz5JPFuK7HhskyXVn51q0e9f9v7tdT4B8aJrVr/AGTc3K+bC3yN/FJ/s1yd54d1Xwrq1zoPiGwuLS5t5ZIpYbqJkkWRfvblrmhrT+GfFiebuWOR12t/tV+KLklHmiduHqTjPl+yex6t5M0azJHu+dvl3fdrnr5XaTzt8brv3bf4q39FjTXNJTVbYfMyMzeXt+Vqo3Gjw+csMMjMnzNK2z+L+9RKpy+6eh7GMveMUzSGZnh8wL/B5jbqg8yaP9yPmDPudmatB9DEe6ZNzqvzI1V7rSfLV5nfyX2fP/tVlKQ40e5Sa4dZPn3EL/FuqC4unuN+xFG3/wAdq42nu670Rm+fb81Rw6JMtwdiNsb5t22sJc8Y8xtGnzSI7e6u2h2TJ8v8LLW9psyLHDC6M3z/ADsv3qp2dg/mO+zYip/301aFna3K3Cwof9p1b+7XJUlPlOynTgdNp948q7E3Af3f4ttdRpWsfu4Xhdk2/wCtX+KuN0uCb7OuyP5m/wBvbtrqND/fL9phRmj/AL2za3y1w1K3sdT0aeFjI7rSte3XG4zSb/u7mT5q7fwncNLHNF5bqse0IW79eleX2104khm875Y1216D8NRi0utsxkUurBj3zmv0vwTxMp+JuCj3VX/01M+kyLB+yx8J+v5MkvtQl+3TIoUmOVgHY528+lI+pJbgzWc0kn8P935qo38yw63dCZt26ZsH+5zUunxpM0UzvudUZm3L8tfAcTY3l4jxi/6e1P8A0tnHXy+U605eb/M0o5kZUmRGaRfmdVl20lvdO0zzW3mBPuyt/ep1rZw7Umh5LLtbd95alk0+aTDoWDx/wr/Ev+1Xz8sd7w1l/uDftW7YjvtWRtv+zRMr3S7Lm42tGjbl+7tX+9SzWs5uJbZNqJt3f7P/AO1Uc0LrMnkp/wAsmXdIvzf7tb0a0qn2jKph4xhsU763mMf2l32/PudV+bctc7qVs7QvNNDHmRGVFVK6uazeGFzC+Cr7mVf4WrOutNhuITM6N9/97/D8tejhqnLH3pHlVqPNocJqG+PaiW0ats+7Iny1j6gHtbrzhuQMyt8v8P8Au12WqaHbXcjonmbd275vu1QfRUhdN8O5W+/t+Za9WNSPxHnVMP8AzHI3SpJarNCn3Z9qSK23dVSaL98zpuy332V66m68NQxxsZvkfd8u7+JqoXli+nr50M251VU3Mm7d/tVpzcxj9Xlz+6YMNgkKqiJv8z5fmrSsVSJQjwqrr8m7d92ntp7+c7787n27dtT2NjlVtkT5PvIzJurmrbHRTo8s+Uu2t0V2o8O7b9+Nt27durqNHvIVj2b8tuX95I9ctawvGpTzsP8ALu3P93/gVbGnXD/JbO+9lT90zfd/2a82R6Macoq7OtuIdri58ld6vuTctUru5/eK77d/8S7K6G8091jLzRq7fw7U+6tZGpadCsf2yZ1RNv3tn8VfH/aP0ijTk4+6c1cfvrdXd4yV/ib5VrntW/eStMj4VX3Sr5XzN/utXVa1HZq2yGHIb5tsn8VYmqR3M0e90bcqblhVvlrop+6ezhcLzHH31+FGxJsvH8yKsVY99vZm2bVZv9uug1az/dukO5NyfO277tZeoRwyKyXKRllVVaRfvVtTqez90+gw+X83xHLalazNMro6s8f3FrL1KB9whmdUZl+7/FXTaitnCv2nzW2b9yRqm5VrBvo4M+T5LM7N/rNn3a7qNbmFistjymLNYusZTequr7U3VFDbzSN9mdNzK6/Nsq/IEhGzf8sfzf3m3U+1sRGp2Rtlf4m/ir1qdblh7x8Jm2X8vMP0+z3W6/J82/8A1e+ta30e4uIx5I3bfl8uT+Ko9Pt0WOLzk3P97+9W5br5sib9oLIy/L/d/vUe0lzaHxmIo+zgVbPS2k2OkO1I3Zdv8S1sabZz+RJtdR86/Lsqxb27sphf5ol+bzF/iWtPTV87CQuzwqu528rbWP8AekeTW5ep694Mgf8A4U/HbuQSdOnBOMZyXrz7T9LeaH5IZEfZtbd/C1eleE0UfDKJFjZ/9BlBR8ZJ+bI9PauX8O2MKyKRCy7t27cn3a/bPFybjknD0l/0Cx/9JpnvZ5BToYS//PtfkirDp5kkjTyVLL95vu1oNapFA2+zVPn3bt33v9la0rezS3V0SCORpPli8x6kms0Zvn2u6s235flWvweVT3uY8ijTjHVHONpsykbNqyf8tW3fMv8Ad+Wl+y/uzYTRq8m3d8v8K/xVtTaTczKsyJuPlf39rfepI9JdZseRsVXVmb7yqv8AtVEpe0jaR00exgfY/s7Jcw9NnzKtV9Ss/M3uLOP/AGNr/eX+9XQx2qMzukyrGzt8q/Nu/wBqqtxYwuomhfak3y7m+Xc3/stc0pe+ejT5pR90468015WkvJnyGbb833fl/wBms6ax+Zfs20ov+xXZ3Wiv9oVEEe7+JWf5Vqh/ZdmsLQ+TudpWVZNvzUv3fNzdDSUaso2OXWx875HhZAv3dvzbqS10v7++3Ziv8Lfe210DaXCyyvC7Jt+82371Q29nN5w8nbj/AGl+9/s1MpQ5gjGRDaWszXHku7bV2vtb5q0V3zSBETc3zfd/9BpYbea1+dLb7z7n/wBpaufZU3JM7bwr/e/+KrA7YxlErQ2EFq2x08pvm3/xfdqzZW/+ledDD91Nyf7W6opLV47hrn7Mz7mZUVW3bq1dFh+0tHvTeFRldt/zf5WnTlKMd/dNvinymtoujJIqWyOyrt3Vu2fh+SaNzJ9xU/i/ipvh+zhiX9991vuMz/w/w1oeKlOm6HPcwuzn+COP+9VYeM62IjBG1bEUsJQlVnLSJ518SvjNpXhHVn8N2d5HNqUjqyQ+V81uv91v9qnfE7VPDfiDw7b6CmlRxG8t/n+0L86/L95a+Z/i43ir4f8AxQPjHxJDIrXFxulVnb5m/wD2a9T+I3xFsL7Q9A8bW95DNb3EH3VRtsP8O2vvMJhY4SlZbn5BnGYVc1xUqjl7v2TwLxl4fn8O+IrizR2T978rf7NOs7g/Z1dPvr8qSf3q6341WtlfeV4n0p1KXEW75U3LG392uHtLh7hVfCl1/hX5a7tfiPJ5vcOp8L69MsywpNtO/duZ/u1x/wC0NDDNcR31s7Zk+8u+tCG8TT2aZEZTt/v/AHa574iXCapZ72ueFTb8zfNUy94qPvHDWOqXMKrZ3T70/g3VVvFRpN8Lsqt81LM/2WYOiZFRXVwksexIP4/vNT5eXQ2jLmI2uHh3bJttEupTLGu/cw2/w/xVWkVGTeqN96opG3L9xcr/AHqfwxD3i39oeNl37iqr/FRHqm5hvHy/eSqDXW1Sj9f7y1E0zMqyZ+bfupFcvKbS+IEDf6za6p92optcdlKQ3TL/AHKyfOf77yc/3v71EbIdrvubbVfZFymnHql2u5xM3zff+annWpljH77ft/iasuWZ9xpPtLrDj5TUi5ZGlJrlzdSEu+Vb+Gq11cI2E8mMVSeR3QPv203zMqv7tjtoHylppLfcifdrsdJvP+EV8NrPDNvuNQVkVv8AnnH/ABNXF6db+beJvDH+9urQvtSfVLpcriKNdkS7/wCGqk/dsxcvvnYaLrczKru+Qv3a9X+Ecf8AamoDzl3K33f9qvEPDsEN1Mi78D/Zr3H4c7NP09fJ+Uqnzs38NO0Ix5jGZ6n4s8ZW1n4fa2dGEdvBtiVfl+b/AOJr468dalc+IvHVxeB9/mS/dWvc/jN4wh0vwu8MN5IrSIy7f9mvDfAtrNqXiVpkhaV22/LULmlVHHlpw5mfrR/wa4/sAab8ff2lj8fvHug/atE8ExR3UUMnzR/bm/1P/fO3dX27/wAHjfxsvPAX/BPTwj8F9NuWjbx94+hhulSTb/o9rG021h/d3bfyr6S/4N/v2U4P2af2CPDd9qGlfZtV8VRLqeoGRfnZWH7vNfnj/wAHqOvvL41/Z/8ABkwZ7fytWvWj7Ft0a104ufKuRfZRllsZVE6j+0zoP+CLH7V9h4L/AGOPDvhjW4ZGjtYFgW3hXa0aqzbfm/iavpPx98dtB8ReHX1LQvEkM5+ZZbW3/dtH/sstfK//AASH+B/h7xB+zDpWg627Mtx5c8U0kH+pZm+b5q+ivjJ/wTu17wr4dvPGHw98etDN/wAfHk3zr5TL/wBdK/DswjTqY2c0ftdCXs8LC/8AKfPXxX+LGlahJND9jVJpnZrrzIvu7f7rV86ePvEtzHcPDo+ox3CQ7mlWOX5lWtL4qXXxR8M+K7zRNe8N3yhk/wBdCm6KRW/iWT7rV5neaD4k1icvdO0PnL95bVmb/gVGHwvu8xt7aMYf3jhviB8SJrqV4ft8flRtuTb97/dZqreBZLzWL93ke4W2uott1Gq7v3f+0teir+zdDqEi6lePHcJMnyq0DR7qztQ8F694Llms9NRltlTcjW6s33f71d3JGnEUJ1/iPObi8+IXgvXGv/DGsTQNbv8A6P5cu3ctcjqHgPwl8Qrj+yvElnDp2rzSs32yP5Vbd93cteueJG/4SzT99gjS6pGm+Bl+Xdt/hZa868YabYXnh5PE9heKt1DKyXVu3ytG3+7WeHqToTfJodWM5sTDX3jyfxF8GvGvhPxh/wAI24USQurRXG/5GVvutR8UJodNs4NKluYXuVddzQvu3Vc8ZeKtY1KEveX8kjxp8rM/8NcNobTeItYWa5mVoo3z+8WvocP7TFctWp9k+HxnLh5+yX2j0Lwvapa+H4Jk/hZmdW+81ak+tOsa22yFl2fut33qzo9ht9j7m3Jt2/w1LHpqeWn7lt0a/JXLWlGM+Y55PlVkT/2X9sjW5Tlv4lVfu1p2Nr5OD83+zu/vVn2P2mz3/IyozLtbf95q2IZEXY77fNb73mferhxNT3TpwcoxLul6lZ6fMuyP55H+bc/3a9t+A/jKG3mjT7Yrt5u542+XdXzrc6k7TCaSHcV/iX+7Wr4T8bPo99Fc7Nrxv8vmP8teRiMLUq0nKJ6+DxlKnP3j9AY7qw8a6b5M0MKrJF/rP7v92nfD34Q/2bqU32O5kuV3K0u77v8AwGvnD4V/tD3LQ29tc3m5lf5o/wCFq+mfgj8XtKVYftLySbhul3N8y7v9mvGlGUY8s/difU0KWHxK5j7F/ZH8NeM2e2sbGzjkMjbrVW3fKtfU8a/Gq50qDTZobGFNjI7R/Nt/u181fs5ftEeD9PW2ub+2ZAqbEa1+Wvq3wP8AFbSvGMca2w+zxhP9ZN827/ZqsP7Bx5eY58Zg6+H/AHihzROS1f4ReG/C/iPTfHnjN49Qk0WKSfTbOQLt+0MvzSf71fm7+0dq3iT9or42eILOG2/126CLTV+Vodv8Py/xfxV+jf7UnxO0fwP4Uub/AMlbqaGLzWWT7u3/AHq/KHxJ+0Po/hv4ral8XdHmtYvLlkllj837237vzf3lrsdOnbkj6m2X04Rh7aqvekdT8Efhanwr+H+qa8eNS0m/VpY9qrL8v8TL/s19ueFvG/w//bK/ZS8Tfs7Xs32qTWPDUkVncRxeYy3SrujZf91lr8yrf9oi/wDjJ4w8R+J9BuVh/tD97f2cKMqtN93d/u7a+tP+CZfxNm+GvxGikuVX+z3u7eFEj+bzGb+7/wB9V6NGNSlWjUUh1qcMVhKkHH/D6nwfY6Tq1nCfDetwzNqOn3ElrdRrFtZZIWZW/wCBfLUyxmRvOSZn/hddm3bX0h/wVZ+Blv8ABP8Abv8AF2l6SPK0bxZaw+INMWP5dxuPlm2t/D81fP8Ap2jpDH5DooRW2o2/7y19soc3xSPhKdaPLdRGWtinzeQ+3b827+L/AL6rSs9NT7ON/wC+f5tjbfmX/ZWnww2zfuYdzo3zLtRv4aljaaS3aF4dnmfL838VKNLm1ibyrRjuXtH8nyZnttsrR7V+Z/u/3q6Gzb93++3J/D+7+b+KsnTLXz40RHZXaVWfbW9bwwrb7/mYLu27vl/3t1enh6cYw944ZSlUkWVW1aHZ9m8vy/ux/dqtJHbKhmRN211by2+81TQ28N5IXm3MFfb5e7crLt+Vt1MuLdIIfv7PM/ib5mrtpxCPNUKGsWsMMrO8youxvmb5vLWsK8WBd0abcrEu7d/Ev8NbeqMzWM1s+5PMX7yurLt/3a526uHmmWFJt/8AFEzL/DXdT+P3ialORQvry2ZjDDu3yJ86t91Wq7bE/wDCMOVBH7iTHGT/ABdqzb7yZlWZEZNsv73cn3v92tCFw/hSVoyQPs0uC45H3utftHg875rjv+waf/pUD2OG4P61Wb/59y/NHlniiSaG1lmg/eu3/wAVXK2qpfXDQQv5vztuWP5trV0Ovb7yXf8AKVb+H+9tqtY29tYxy3l/M0McKs3zfKq/7VfkcvhtE+IrRlHUzvEnh+5sfD83lbVmuIv4U+ZV/iavnz4mWttoqun2lSv97fuauo+LXx8upbyb7Nqv3V8pNv3fLrw7xd4xm166+0u/zf7L1z80uY8r+JqY2r3T3Fxvi2vu+/trofhz8P7/AMTX0KIjE7t33KyvDOivrGqIkaMXkbb8tfV/wb+Ftn4D8Mp4n1VI0laL5d0W6tInNUl7vKjJ0X4W6b4a0dp7xI1dV3KrJ81ef/E3XLDTZJLa2mjY/wANdX8XPi08cbQ2r4Ma7UVUrwXxJ4k/ti4fz3Ynf95qzlU5pl06MY+8JeXj3TGZ5s7v9n71ULpoyrbNxb/dplvIjrsd2P8Au/dqG8Z4s84FVGJp8RFPI7Lv2Y3fw1Ey/KXxuX7zVIoSaQOflVqRIUjZo9mWb7u6jm/lJjsNaPzofP8AJ2rT7e3SSP5E3f8AAaVI23bE+7/HVm12R2+z/wBBqZRK+GAab51rcK6JuZWr2X4V+KJmsVsPlbbuZF215LZwoy7zGylvv12Pw/1r+xdSi3u3lfx/Luaj7PukSjzHpDTPMzTb9zbt21X+7UqyJ5fnec3zPurHvLzbeb4fuN83zVNJdJbqXd/l+9tZqfNKJHLH7J0K3Ds2/YrorL/FU1xdTLy/zbn3Iu/5WrO0G6S7j8lH27vm/d/xVq3FqFkO/bhU2/N/DVEc3L8Rxfxm+xyaD50Mf+rXa22vIvC+qeTqDJv/AI9tet/GAGTwu6InKu3zMu3dXhen3Xk33/2dTzfZNYy5vdOo+Lmg/wBqaTFrFnCu2GL5mj+83+9XO/C7xpPoN/8AYHmby5Gwyt92u70vyfEHh99NmdTuT+GvJtf02bw9rcsPksu1vkq5R/lLpy3gfQUapfW5vIfmH8DLVO+sXjYYT7v3P9msn4I+Lodc0/8Asq7uVLr8qq1ddeWm7986MtTGRFT+Uw7GMRzKzorD+CrV1dalpOo23jDwxc+Tf2twssUi/K25W3LVe9hNrKPO2/8AAa2PCujJ4ruho803ktJF8kzfdVqqn7szHEcsqR+lDfG7Tf2hf2fvh98TIHT7dLb3lrqyr1E8XkKSfrnIr9fv2R/2ePhb44/4J6eH/h54/wDDlrd6f4w8GW7anFOinzVkgU1/PX+wvD4i0XQvEnhDV7qR7bT9Qiazjb7gLqwdl9m2Kfwr+ij9jfVpvHX7E3gPwxpF2bTVNO8H2CxqOsiiFcH8RX7fxIpx8IcmXapU/wDSqh5b5G218j+cz/gr1/wRl+KP7CWrX3xd8J6LNqHw/vNTkihvrdNy2O5vljkq18X7s6f+wYl2n/LPwlpJH529f0n6z8I/h3+038GPFP7OXxi8PwXtlrNnJBe2VzFuZNy7fMH+0rfNur+dn9vj4Zx/Bn9nvx38HFnEy+FCuiiRh98W13HBn8dlYeHdSnUynPGtGsNK/wD4DPU+/wCBIVIZdj03zL2Tt90tD4s8H+MI76FP3y7f8/LX15+y/wDtr6D8Afgb8R/h74wMl5p/ibwRfWFnY7fMjkuJF2xr/wCPV+eGh69No98uH2bfl/2a9W0HxNba94fNt8ryLF95q/FYylzRPl6lOPLdHpH/AATd8OXHhf49eIdPZR5T+Fd8bAfe/wBIhr6E8P8A7U/j79mr9r2bxF8P9VS0lRreO8Z4VctC9ugbBb7vBrwz/gndqE178ZtahuGJNv4adI8/3ftENZf7UXiWPTP2uNZtGuioW3sy2P4c20dfseeYeniPAnDU57PFP8qhz4SpVp4lSW6R+on7cX7GfwE/bA/Yd8Qftk/BDQ2sPGHg2wW91a3h+ZLrdtVt235vu/NX42+OrOG+0eLUi+4xru3L/E1fY/wD/wCClX7ZP7Ofwn1j4UfBzxho/wDwjviCyZL3S9S05ZdrMu3zN33vu18oeJ7G5utNuE1W8a4nm8x55NqrukZtzV+IYCnUw2HVGfT4X5HQ43rurF7/ABep2nwD1j7ZpJtodpaRFl/3v9qu71DQ7aWTeltJn726vHf2arq5s9ShheGMLHL5TRs+75a+hJtFuftHk71d/u/7q0qkZU5nv4P97SOMutN2nfN8iL8u2qt1oZ2/uYZAv8G75mrvJtH8yApLCrfNtSTZ/wChVWbQ7lY3/cq+1FXc1YnXUoxitDhJvDMcciJ833tzfPt3UQ6LukfZ/vIq/wB2u8Xw680f76237f8Anp/7LSWvhm2hcoE2Ue/GJUaJxi6O8ceyaHbt/harEOl/vmeL5kb5WXb92ulPhkys7/d+b5lbd81EekvDtT5kT7u2sqkToox5ShY2MNuq23k/PJ8r7a09Ntd0f2Z3ZUX+FW/iqS302BJmj2bv4ovOVv8A0KtbTbFPOd3hjKrL93+KvHxEYy5j1sPzdCa1tflWa5hbCrtZY/71eg/D2ForecncQUj2lmz2NcdYw21vJF+//cx/+hNXbeBwFiuI1PygptBXBHBr9E8D4cnihgLdqv8A6ZmfTZQ28VG/n+RTvrFBqczbnLyTOdg7L/eq/pOmwzNvSb+Hd8v3akcr9qnZlUO0hUEt/Dmr+j6f8o2Q4T5mT/er8v4ol/xk2NT/AOftT/0uRvOMXUlbuXNL0+2t5kT75kb5N0X8VW7q1RmP2OH51ZvNZX+7UkPnRqhR40+T5G+8u2p5vJaQQu+15Pmdo12rt/hrwVHmnzEy92HLymLJZvJCXhttiqu75v4qgWJJl+0wvvRvl+V62Psdt/BMrhvl3M/3WqvJYwqkoTcP4fMVdv8A3zXpUKxx1qPumVJG7wtbOm4r8+7Z95qz5rF7qaNLlFXd9xvur/wKthrPyZGe9RUh2bvv1Vms4Vm2Om9JvmRV/ir1aUuWR5EqMKnumRfaXN5LfY/ldv8AlnVCbR3WTzpkVTt+Zl/hrpWtUZl32rQpG23b/eqnqdq6x/YzMqK38TfdX/Zrsp1vd5TJYSMtWc7Jo9t5exAu+b7/AJi7qytS0+GSHYiKp2fJ5fy7f/iq6m40v5Wh2bj/ALTfvKx7+3SOEOm4FW+VVfdu/wCA1p7SfNZHRHB0ub4TktRs5vkheCRS3yxNH8rUklmlvIsPzI/zN5ez7y1u31j5k3z2bPtfcm1tvzVNb2264b7T5cj+V95vvbqqpU933jL+z4+1MG10ua3tTCiSNu+f99825v8AZrV03TXjYTeSybl2vGrfKtX7fSZvLV96qytu+Wun0XTXnsw6Q7fMl3bm+X5a5ec1+p+4WpmS4jDp5au3ypt+bc1QND9sjMMlttdfmZZF+8tXJY/OUyecqtH8q7v4afGyXC+dD5gb7ryN97bXycacoxufZYepGVU5jULVFY/3Ff5mkTdtX+7WBq1htj86Z1RJPu7fm2rXb3EbyQyTTIpSNd33/vVzer2Kbi88SqWXc/8As/7tdUactj6bBy5Th9Q09GbZDYeaaxdWiudzFLNY/MTc275v+A12l5YJ5ZmQMfmbYuysXVNLvFhWabcHk3KrMu1WolTlI+rwMonF30MNvav8m1vuuv8AdrEltUVuX+X5vlZPvV0msWMyxnlSy/N838Vc83O5Nn3UZf8AgVKnzU46HoYinSlQ5jNvrdGhG9FT+/TI18sr5PKt92rs1i80fk71+Z/4aiVXhV/k+98rbv4a9XD1OblPzzOKPUtaXDD5bGGbe393dWrp91bLcFJEYlk2p/eWsRZpoZGh+5uXan95quWeoOrOjpIP4E3bdzV6FHm+I/Ls0lyz5TpbUf6Ps3/vFT5FZ/vf71bWkzblGyFf9uTfXN2epJ5yRzQsqs+FZq6PR7oQ3AR+Il+dG21FVVIwPnqkrz5T2TwiNvw+hBJGLaXJ79WrN0+zM0guYXbZ/ufNWr4YZR4FicsMfZpCT6ctVOykeNY/szxiJduxll+Zv71fsHjK7ZJw6/8AqEj/AOk0z67M6EqmHwvlBfki3bxwthPsyr8nysq/M1WFs0muGCfIjfMqs33VpNJjcsf3zb9+1tzVqw28Ls6TIuFRfmXa25q/BqlT4YxOOOF5feM2PT03J/tf7VU9WtUhSZ4YdzfxeW/y10kbov750XLJtRdnzNWfeNbXEbpCmP4ZY/71XTkKUY09jmrlblo3+zJHv/jaOqElrtY3O9Vf7rfJ8tbt5pLwt51rCrt/zz+7VGRX8kOEUfIypuTdRUpwLoy5TLurPz1KO/y/7P8Ad/vVX+zorGZ4Nj/9M/4a0biGaGPzH8vP3dy/3agby41875kfZtZv726oUfsov23ve8ZF5HDIu9Fk3btu1fl21R+zwx7/ACXZXVty/PW3fQzR/ubx2YR7vu/+g7qyZrN9rn+Jv+Wcj/dpSjGJfNzEbb7hi6Phtnyxsvzf71W185ZDCjthk3MzL/FVNmeSREm3fL8zqtXdPuoWWVE3F9rMqr95VrmlGZ105R5i5Fa7Zgn3l3/JJ91lrZ0e0SFU/cx5Vv4U+9VfRdkw+RFxt+dpPl2/7S1u2qoWWySGN0jVm3L/ALVc1STjLlOunHmL1jbrbvHM1tG8kf8AyzZ6o+Hfi/oll4yu9E1KzWaOGDY0cifMzVbbVbCxs7i8ufl8u32oq/Krf8CrzDS9JfVtYudVheNdrM3y/KslfX5Dgeb99I+F4pzSL/2SHzO2/aV8O+Bvjf8ADW80rStBji1G1l3W80lrtdmVf7y18d/Dm8vJvDuq/ArxOjW17Hun0hpIv3ny/wANfW+i+JrbQ9WiS5jmeVtu6ORvu15l+118M3+1Wnxj8DWarqOmy+fcLCvyzKv3t1fUfFSPhIynFHj/AMM9WtvFGl3HgPUvmaRWW3kZPm8xf71cf4o0W/8ACuuTQ9DH8jbm+7V/xJqFtofiiLxnoj/u7pVfbH8u1v4lrb+IWqWHjq3t/EKWCxFUXd/tNWcZcpcY8vwnIR+S1mu/5dvzfM26uU8RXELq8L/NW/qF4kJe2+bd/e/hrjdeuIbiR/O521RcYmLfQ7lkTf8ALVPzPl/d7WFXLry1Yon9/wDv1RjX940CJt/vVXxGsRGh3fPv+X7zK1Q3C/3z/wB8ir01u6xhPmcN/DVS6X/pn8y1JRQk3s77D92o5G3NUt0dzbAnNQfOFJf+GgcdwzJt6fK1Sqs27Z8v3ahLZC59akST5vegQ5mVfkAXO371Rec7fJimyLtaljX5hl6B8rF+8Pkpg3rgB8bqmGyM/PRbKZp0THP/ALLREI7lhpfs9nvT77fKm3+7S2uW+fZUF0yNcHZ8392pLePzG/121m/u0fETI6rwyvlus0O1TXq3he4v5rf/AFyqipXlPh9fsixzTOrbf/Hq7qz8TTNZpZ2Vts/4HWnuxiYSjzFX4talusSk0yuy/crc/YH+Ftz8ZP2jPCvgm2T99q3iO1giVvmX/WL8teX/ABE1OaS82TTbj/Ctfa3/AAb9eA/+Eu/4KAfD55oVMVrqn2h2/wB1d1aYWP7xGOLl7PDM/rI+FnhWw8D+BNI8IaZb+VBpmnQ20ar/ALKqtfhJ/wAHqVjMPih8ANV2KYvsGqQfe2nc0kdfvbpF5i1V33D5f4q/FP8A4PMfh5P4m/Z9+Fnxctot0fhrxXNa3kiruCLcL8uW/wCA1jXhOXOb4KtSpxgjD/4Jd+PLbTPgjpDwzNuhtY/3Ky/e+X71fT3jL9qq6ure4s3RbhI7fZ5Myfd3V+Zv/BOX4uPp/wAEdLtdiuY4tr3S/L8v92vXdb+NU11cMlzcssW/a21fmZa/EsXTjHGzifteCq3w8Kh79qGvfCLxBa3P2+2aK5aJvlVFZLf5vl+WvKvF2ofCy0y/+hyyR3CrtVFXd/wGvK/E3xFdbGYQ3k0QkT/lncbdu37teI+OPiFc3WoTXM2sNLMv/H02/bu/u1pRVX4eYKkqHPzSPW/it4/8K6Pb3l9Z2cMRkf70d1uaNl+7tXd8tfNnxI+NV5rDNpVtPMSu4O1vcbPvf3ttYXjj4lX+pRy2cNtazRTf62O4+9/vbq4Vdck+0PeWdqsMXy/LG1ejh6NWXxbHBUxsPhge3fCi68PeH7W08T+MJLdEhTcnmMzL/u7a4f8AaI8YeAPHGuPqvg/wwthffduri1dlW4/3l+7Xn2s+NLieFrN7nA/55791Zmk6sLy8Uvufc3zs3zVpHByjzSbDEZpT9lyQMjxZp9/cafcJsVGX+633q5fwrHDDfLHsY7fvqv8AFXqfiHS7OTT5P9J3S/d2/wCzXCw6L/Z128yHaNu7dXp4WtH6tKJ8pjpSqVec6ixk8u3QQozfw7ZKmbUZo2f/AENVTftT5/u1haHcTKrbIfl3bvvVLc303lt/CjfeZq55UrS1iT7SPL7xrTalCp3/AHCv/oX96ga4kjffyG+VWX/2auea6SaNX6t93/ZqRdSeFlj37l+66r/DWUsPzRsRHFWkb0379Sjncu370f8AeqrNvkuNzv8Ad/hVPvUumXELRomxd27c7bvu1p3K2f2NUWFd0f3q4pS5Jcp0+05/ecg8L69d6bf/AOu+Xcu3c9fQXwZ8fbrpLY37GWR925X/APHa+Zo5vLuN8abt38TV6D8LtWmj1RE38KyrXnZhho1I8x62T5hOnXjGUvdP0s/Zl8aQzSb7+8kRfKZ0jk/iavs34HePptvnXN5IdPj/AHrQyfIsf975q/PD9mjWnjVLZ0kuPlXYq/KrNt+9Xsni79pTR/DujxeG9Nv98ELK2s3DO21v4tsf+7XzFFTniLRP0mlioYjDF/8A4KdftueKviPdj4BfBTU9Lht4dy6veSy7Z5N3/LNf7u2vyk+K0Pj9r6XStV+0TfZ5WiTbuVWZfvf71cj4t/aA1rVv2h/FHjbVNakX+0PEVw8CK+1fJ3fu/wDx1a9x0/44fDfxV4VtodS1JWuo5du2aL7q/wAXzV9xDBf2dGLnHmf8x8x7SljY/u58vL9k8u+Cfxe174b+Plie5kjWaVYrqFn+Vo2/2a/Wn/gnHcw/FL4q6HpNpYeWt226JvK2xLtb5W/2flr8sfixN4G1rUIde0GzjSaOVf3y/wAS/d219/f8EmPi+3hCfTda0+8ju72wRoVj+80a7t21WqMTXoUXGrym+WxxM3Uw/N732T17/gujrGlXH7XvhHQNNljZrDwbJZCTb97y5F3f98tXx9YtDcXRheza23fcX/np/tV1/wDwWR/aB/tP9uH4dWrXDJP/AMI5dXF/5kvzeXNIu3cv/Aa5SxtbmZleMM67Fb5vvN/dr6/AL61ho1v5j4vH/wCxYl4ZfYtzepoQW8yqgRJPm3bFb7rf7NT2un+XI7Ikasr/AHWXdtqWHT0j8uF5l3tu3sv3t392ren2McfyImx2+baybv8AgTV6tPD8sfdOH2kqgabao8aXPV/m3/JtWr9nNlAiIwRXZd3/AKFTbW10+3ZU3yI33VXf8tWLiG2kjPnTMm2XduV/lVa7IU+aPwlQ5ia3ZI9z+TlNm1mZ9v8AwGmX+yS3ZLZ1zs27f+ebU+RUuGFs/wC8/usqblVdtQzWt5HG8xRkeNNzK38S1p7GUT06EY81jD1BtpO5GVv4JGX5dtYt98siwyXLY37f3afMtbmoRoqs++QN96JvK+81Y+pQpJI0zw/Kv/LOR9u7/gVbRlyyOiWHjy3kYd5G6xMsybv4lb/4mteAlvCcmCAfs0oyO33qrahBbMw8jajbW2Rs/wB1v7tXLZQ/hpk6Zt3z9ea/Y/BySeb45/8AUNP/ANKgehklJRxVW38j/NHk2oQ/Zmx1Pzb1X7y15F+1N8TE8N6HH4M012+0t89xcRt/D/davbPESw6dY3GsXnywxxNLLuX5lVa+KviRrl58RfFVzfwiSX7VKzRK33tv8O6vyLmlI/Os0l7P3TzrWNY1LVrppnfJ/wDZqteH/B2q6xcL9mhZ9332X5q9x+Bv7IHiT4lXyNDpTGPfu3N8y19R+Bf2J/B/gPyrzWPJdoU3y7v4f9n/AHq09nGMfePAeIl8MYnh/wCzL+zNBGqeKvE/7q3hTzW2r83+7Wh+0Z8ZLOzmfRNKvdkcMXlKsfy/u67j9or45WHhHR/+EQ8Lpa26Q7llaH5fu/8As1fFvjjxlf69qT3E0zFv7zfxVjKXtCqceX3iHxN4qv8AVLp5nmb5vlVf4dtc7cTSSMz/AHfmpsl5tkO8sy/7NNWYNL99sN/epRibR5ZFmGR1hZ/PbP8Ad/hpkjea4T7p+9upPM2q33jz/doZkk3eW/z/AMCt/do+H4g5ZRDa8i7H4ZX+RqI18uTyU+f+JGanMvmK+R/wKm/xA7Pm/wA/LVgWfL+YfPuMlTx2IWHZvwf4FaorCT5d6Q4Vf4a0Y5I2kWd03bf9il8IvckQWfnRtsdNo+7/AL1dN4VtUuLhN7qpZ/4nrFe33ZfZyPu7auWqTWNxG6chfm/3amURf4Tvtahm0uxhuUdmP3Xqj/ayNgPcqzf3qZNqlzfeHXhkdsbF/wC+q52TWt1vE7pg/d/8epylHluL4Ze6ej+C9StmnG+ZflrsJms5labyd+19rs3y/LXlHgvUlhvPIQZDOqt8/wAtenSXD3FuHRIwG+VP9r/aq4GFT4zmvirHB/wjUqb8rXzrqMiR6mU/2/lZa+hfilJ9n8LmF0+ZU+bd/FXzjq0/l6kyd9/zVlyG9OPKd58PdWmWRbZ9uGqt8aPCvlj+2LZPlrO8D3nl6hE4/v8Ay16h4p0mbXvDaJs37k3U485Upcsrnivw/wDEU3h3Xo5t7bWZVr6XhZNa8P2+pWwVVkT5NtfLGs2NzompvAybWjb5a+gP2e/Ey654b+xzfO1vtO3+9T+0FSPNHmLV9ZPD9xPvfw1Hod5Na6ojom397uZmb5a6TWNJ87e8Lqy/M0W5vvVzV1C9rl4du5X/AIq0fvaGMZQ6n2P+zVqFjrGl3+q2kmWljtlmQfdVlVxx+GK/az9kb4v+Hdf/AGQvh38W/h1cq954R09fD3iWzjkIaOW3IQlgOu5QG/4FX4hfsbG3n+HdxewS58y4VSmc7ML0/Mmv1R/4JmfCfxF8K/2efHh1lbm1v/El3Z61p9vdndHd2EqiQSRDsRux+FfuWfUpVPCHJVf7dS//AIFUPHxFSNOUklvsforFqlhq+lad8XfC211aJWu1jX/WRt96v50v+Cvk8culfHG4jb5W8XX7KT6HVeK/oG/Yu8RnXfh5eaDc7cWN15aIvZf7tfgx/wAFMPhn4g+Kms/G/wACeENPkub1td126t7eJcs62t3LcsAP9yFq4fDWD+oZ5Se6w8l/5LM/ROCnFZXjqn2XRb/CVz8gbxRJGJk+Xd/47XR/C/WkW+WG6ucqz7flrnWk8u3NtNuRlTbTdFmez1VXR9qK27dv+9X4zKPJM+YjZo+zP2CNJi0743a3PAi7ZvDTNuVs5/0iGvJ/289TbSv2vdYnj72tluO7p/o0dewf8E8rqLUvFuoX7gecNDZSR/dM0RH8q8b/AOCi0JX9prWZliyWs7M/lbx1+1Y7/kx2F5v+gl/lUOKD5cW/Q634U69Dr+iRvM/3k27l+WovFGiyQtNv2vu+4q/w/wC1XmHwF8ZPDfLp83CM/wB3/ar27XI/7S09LhDn5Pk//ar8R5Z851VPd1Ob+E+gz6X4qea2+ZpGV/lf7rV9U2/h/wAyxttV3rNK0S7mX5W/2q+cfA9x/ZviCPzvLTzGXe0n3a+pPDOmw3Wl2z2G1921X8t/lWscV3PbymVoyUjL/sOGSSVP3ij5n3bf4qhm8K7fk8qNv7zN/wAtF/vV2cWj/O8zp8u/5GX/ANmqWHRZo2Donys/z/7P/Aa4Iy97mPW5eY45fDsIHnJbNj+63zfNVa68NzNM3lQ7g3zO33dtd/b6L8/kukmVZv3i/wANQto1ybzeifMsW2X5PvNWsZF8qPN/+EfupJpPO8z737rb/DVabw26t51zD8yvu27/ALtemXnh942Z54WR12/Lt+9VSTQfOje5RPm+Zt3+1/dquXm94qnzROAj0vKtsmU1NZ6fM100c0y/vNvy7PmWuqvNHezj857ZfvbnVl3fLVGaxhWRvL2gN/E33lry8RTnI9XC/AUre38zZZ+TCu6Vn3SLu+Wut8FYEVwocNtKjI/GuY8txtnR5FX/ANlrpfAkkslrO0wG7eOQc561+g+CcZR8T8F6Vf8A01M+jyjl+tRt5/kSecp1WZmfcquVK/3a2Le4gZXRXZVZ9qfN/wCg1zGq25Oq3DRL1fMjf3eatafrVtb2f77cxWXbtZfm3V+T8VR/4yTGt/8AP6p/6XI6pStUfqdZDdeWwhmeMqu0bt27/gTVat7rztsW9lmZ2+bd95a53T9Q3fvkRl+b/vqtK1uEkuw+/P73cjbP/Ha8GnHlj7ope9K8jUmjRt37mOTa/wB6P+KqrRzRr/pLxoI5Wba3zKy1JHev8sNtCsSLufdG/wA26nyTOy75kUbvl2t8yr/wKuqj7xjWiUNzysyFFVJF3eZ5X97+FqpfY9t1strn5Nmf+Bf71bUlu8m3Ztx93cq1Ev2OGRfnjVd/z7ov9mvUp1IxjocFTD/aM2GR928wxumz5tvyt/wGotQhs2s1S/8Al2/Nu/iZqv3UKtGyPbRhpF/5afwrVKS3jmdI25C/89P4a6aco81xRjywMi5tdqMHhaRm2/vPustZM0KLM9480Mpk/uxfdrodQs0jxbXMG9P+Wsbfd2/w1lyQ/vPMh3IrLt+5826unm5jqjTj7pjQqjeY/wAuxtyptpI9PDKqRWzblT52ZtrKtaDWm26aEOzLGnyNIvzf8Cqdbd1uI3+6kn3lqZS5S/Zd2Q6RYI0iPcwrtX5F3f3a6/TbWz8yK2+6v3l3S/K1YNmsLW/nJbRo6xfIyv8AL/u10WiyWduy74fnk+58n3awjHmmRKnyxsZlkqW+/wCzTb337lb/ANmq/CryRiW5hVfLTc26sqORGm+R12Ku1G3bflresY0aWP596yfLtb+7/tVzfVeWPvHRg8RDnMnUNJ3XGy2dWWRd37n7tUb7T4Vgl3vtaZ9qsy7ttdZHapC3yfM0K7UkVfu1TvLNLiObzrVmVvmt41/ho9n7sUfV4PER+ycBcaNC3yfZm/h3x/dasbVNLf7QyTI0iqjNEzS/davQdS0+bavnfKyurbVSse80W1W38mGzW2VpW+9/49WVSj1PqcPiuXU8u1zQ/tFudm0bvm2s1cNq1rDb3R3wqu6LajR/dr17XLGGNXSFFeJW2LJIm2uL8RaTtm2WyY8v+LZ8rVzSjyy5uU9KWOhKHvHE3NujLs2bR/Gy/wAVZ9xJvk2SIyeZ8yK38VbWqWrpcC2Ty0/vs1Zd1bw25NsjszRv8+7+KunDx5veR8Zn1TlgVwqbm877sf3FZ/mWiO923CTeZG3l7vvfwtUd0IoVZEdUP92qzRzXDPeJ8nybtyr/AA17uHjGUD8mzKXNP3TpdLvNsgLurD/x2up8NapCzJv3I38bSfdrgdNaRYd6Pvf73zPXQaTeos7pNCoGzajbqyqPl0OTB4WdSZ9FeELjz/hrDcu2c2UpJK+7dqxtN1SBoRCky75Nq7tn/oNXvAsjn4OwSZJYabNz7/PXGaffNt2Xn3vlWJlr9d8ZFB5Hw7zf9AkP/SaZ9tisPJ0qKttFL8jvPtzSS/vo2Pz/ACf7VbGntDcYh37VWL5P96uJtdYe3aLzpGKtKqbfvbf9pq6O01aFd/kxeay7WT5tu3/ar8G5bdDnlg5RidVH+7j2TTRgNt+b+L/gNV9Qt/Lh875VVvut/FVZNShmj2PlZJEoW8Ty/M3rtmTDM1aR5ubU4sTheWN+UpahNvjif92VjVll/h+Wsa68ncH3/Lv2/K1at5cQLZsjooSN9qsq/NWJeSPNIH3xhlX7uyuv2cJanj1JSo6lW6vprWSSFEVvm2vt/hrP+2PHy6MXX7m5/lp80iWcjJvVmk+b5j/FVKS8e0kV5kWTav8AqW+5/vVhyolVJT1HzTPclER9+35nXf8AdqnI3mQPeZYOrbdzL91qcuoTXUoRE3N/DGv8VZV5cOofzdw+f56JU/d906I1I815DJFdLpHf52/vK9bGkzbRshh3J/Dt+9/tVh+e8Vwuzcm7/wAd/vNW1prXJlXztpVU2p5bVxVo8ux1YWUZVToLHfCy7H3xSMq7W/8AHVrZtbyGzj+eTyW+ZW21z1jbvcSLbQ7ZFZ1+X+7UHjzxRbaLobfabzykunZIvk/iWsMPh5YutGCOvF42lgcLKozk/ih48v8AUGmsNHvNiwqzIqv823+9Wt+zr4q+1aXqUOqvCvk7fu/eZa4hYbaRWv7x/vK33U+aSsb4f+Jv+Ed0/wAQ2fnSb2fzYlr9KwtOOHoxjA/HsZiJ4qtKc/tHV/EXx9Db+IrqPTXba3+oaT5tv+7Ulx44m8TeGWtvtnmM1vsaFvu/drynVPG0OtSx6qjxujf6pf4VqnZ+NLzR4bh/tO9G+Zlb+H/ZrWMZfaMOXljY57xp4Zv9FYeHtZTat1un05l/u7qX4d3TzWM/h7UtrM25oPk+bdXD+LviXqWueKvO1C8kfy2/dbn+Vf8AZrW0XXNl9Hre/bL/AMtVV6qXJKRUecf4i0W50mR0kfO52b/d/wBmuD8QSI0zJ5fzf3q9c8ZW9nrUKarYP8zLuljryDxtDNb3pR/k/wB2lKMTSPwmZb/LcL91tz02aRFun+6GZ/u/xVHpt2i3A85MfP8AJUszJJqT+S+4bv7lTzcpfuiMybS7hs/w1XuIXjjbZ8zN83zVa+zlpFmR/vfc/wBmlmhdfnkfe1Vyi+EwbqPbJvd9x/u1HIu35CmK1NQs0jf59uG+7WfIzqv+7/eqYFRIFXHJpfu/OvVad96Ty+opu5P8mgYrSPu+Y4+amt/fBprM+Pubv9qlb5iv8NVylcrHFvMHNWLMIkZbOHbj/gNQrJtX7i0I5jk2P81Ll7kiyLtbzEf5qns5JGb+HctRzSIsfyfxfxLV7w/Z+dIsju2Vf5l/vVUdifsmzo2xpP38yt/Ftat7+0o7e12PxtTcrLXOeekcmyGH5P46g1rWkmtRDDNs2/L8tHwklHWNQ+2ah533Ru/75r9NP+DaXQ7O8/bi0HWL+FtlnazTpNv+638Py1+Xm52kXZ8y1+rf/BuDpM0P7R0GsI+1YbBtjK+3c27/ANBrbCx/f8pw5j7tA/ps0rUY7nSVuIZg4ZMqy1+f3/Bf/wCDFt+0D+wF498GtazTX1nYNqOmxr8376H5lavtLQdcubfSVe5h2Lt/4DXjn7S2oaJ4i8M3+n6rbRyi4sJoNsn3W3Ltr0qmH5YTPGp1nTqxkfzX/wDBPv4n3kHgCXw3NcyRSw/Kit91dv3q+ktH1K51Ngkj7/L+Xc33l3V8d6v4d1/9lT9srxj8Fp4dkcetyPZxzL96GRtysrf8Cr2/S/FXjCdg3k4Vvm3K/wB2vx7PsCqWMk4R1kft2S5l7TARS6HfeNNak0zfZujJu+42/wC9XhXjbxRcx3E1mkyxJI26WT+Jq0/GnjzxI0MiXj/vY22xSK+5VrxzxLqGt6g0syOz+Zub79cVDD1Yx946cViox94s+ItbtrxWm+VnV/mZX27lrndS162jzsh3rJ8v36y9RuL/AHohfbu+8u+sxVubpmKI277rV6tHD80uaZ81iMZJz9021v3Wbe83+8rVds9STyx8mxVf5KwbGzv2X7M77trf3a6G10dGZY4UZn2Y27a3kocpz/WJS903YdchvIxa22mqzL8ryb/vVj6tY/Z5C8w3bl/hqy1reWeLZNysvzNI33aZrEn2O1KXM0Zdk+Zt9cs4xpStE29pzRMZm8tVdEb+9tZ6RtQS6xvTG35dtV7rUPPt1SF1A37fmqD7VCqsic/JWnLOpH3jmlU+yTSXO3cnzbPvJTdztN58O5k/u021WSSFvvbtv3WpGZI38nzMj+6v3anlZjzc0TX0q8JBSSFt38Tf3q05LzdGX3rtbb8q1gRq8Mfkw8NsrVtWS4ZH+78n3tny1zVKMPiiXGpP4TQ0mxSa6CIjGvafgT8J9S8W30cMNg2/cv8AD83/AAFq88+Hfgn/AISDVIk/56fd+f8Air3rUPi5pvwv8NJ8MfBu1NSuLX/ibXnm7mt1X+Ff9qvncbOpKfJT3Pey3Dyl70j0bxJ8WtB+F+kxeAPD1ztu9ipcXi/eVv4trVW8L+JLHxFY/wBlQwyR7YGSWNpdzKv97/vmvljxR8SPM8RS3szsfn+9u+61ei/AXxlbah4sT7ZeMqyIq+dD83y/7VdFDK6dGMZH1uHx8f4VI4b9qT9hfVdHjPxF8APNdabfNvWOT/WK38W3/Zr50tfDnimPVF0SFrpWkfbtjf5lav3Q/Zd+Cfhv4xSN4e1J7O5s5NNkb7L9nZpF2/8ALT/ZrmfG3/BG/wCCGh/Gq0+LV/4kXR7O1ZZ5dH2My3TL8zfN/CtfZ4bGYf6rH2j2Pl8VlmK+uSdHm5T8aP7H8ZeCvEU3h7Xtakja3+ae3uH/AHke6vob9kD9r7w9+zA1/r2t63eXiyRfuNNtW/1k38P+7XOf8FbPCNn4F/4KF+OrPTbSOCzvILG6sFh27fLa3Vd3/jtfPVncTRtsRF+X+JvvV6VTJsHj6UZT6nhQzrHZZiZcnxRPRPjn+0H4/wDjJ+0TJ8ffHlypmvtsEUcLNttbeP8A1cdfdXwP8Qv4q8A6Zr03lyzLEsXzf7vytX5z/wBnprmi3Wkv8zsu5Pk/ir7c/wCCefie28YfCtLCbafsq/Pu+9u+61ep9VjToRhD4YnmU8bXxGMlUqvmlI97+xwxI6Im8xtulb+7SWtvcsq7XbLfLt/2au/Y5biSJ4XVGjfY235V20q2t3CyJc3imVW3/wCzV0aMT0JVJhDZ3MMhfqvyq+6tJdNf7Ozz7Qdn+rVfvUSQzTQq9y6p/st/Cv8AwGr0apCsX2l5JfMbZtVPl+9XoRp/DE2oVoop2dncttcTR4VNqbU+Zf8Ae/vVLJbOyvD8z7l3bmT7tbOn6PYLIJrNJA7Ozyr/AHamm095oXSH7+791/u0/ZxjM9jDylzcxx+r6SnlmZLbcvlfJXJ3djNCu+HzJUj/ALy7ttei65psMkbTIiq3yqkO9vlb+L5a5bUrU25ZIpo2XYrNIqfxf3f96so0+WV2exH3onF39iJlR/sf75k+Vv8AZq3Cgi0J0I4EL8Z+tbdxpttcMl5NbNv2MyfJ92s+5hit7eSJ8lQh3ce3NfrPg6n/AGxjv+wap/6VA9TKafLWn/hf6HhXx8864+H95pNvcxq940aRbXbcy7vmWsP9nn9iSfUJrTxP4qkjtLPazr9ob5v+BU79pD4oaT4B17RtNeGNyzSTuqp83y/d3Vwt9+29r+rSQeG9NvPJt40VIo93y1+RU5TpxPyLOoyqY6UeY+zm8U+A/hzocWieEobWJ412+ZH/AOzV458bv2gNSjsbjTbaSMBvuSRv/rP9pq4q1+IQk0NNVvNY3Oy/dkl+b/gNeF/Gz4xPfM0drNnd8u3+6tTKU5Hl06cYHM/FjxxeaxqUjvfs3zV5pdaghmb99z/H89R61r1zfXUrvMxO2sxLhNob/vqlGJ08vuFuS6eRm2PgP/E1FvI6gd9tV1b5V2fxVatLZ5Gx/wABar+ySW1kQqrn5m2/99U7a8ap8m41Yt9PeGPyf4lqOZUjYohZT/tfdanLYrm7CKvkr5z8t/s1D9q3RqPvf32qTzP3bfdVmWoYVmmk2TTLto/vEe9KBoWrPMR/Cu/+Kr1qu2M+duB3fJVKzk/d4Sf5v92ryvuj8z+Jf71EthfaL1rskjCZ3VqQxwx4SZF3/wB6sLT7pGZ5P/HW/irZs5hIq+Tt+b/bqJf3Q5jet1SbTXR0yVX5FWuFuL6aOaVJnUlX+7/drrYbx7LdC6NsZa4TxRNNa61LC6bQzfJVe5yExly+6dR4T1ZLeRHTd8zfOtey2d5Mvh2F0+f5Pl3fw18+eH9UeGZN6bm3V7Z4buPtHhuN0f8A2k3VRE+bm5kYnxSvJv7FmR0bKru+Zq+e9ZkdtQdtn8Ve6/Fq8f8AseTCbvn+6teCXs264ft81LlRvT3Ok8Et/pip/DuWvd/DbvqGisg6bPusn3q8C8Gs8c4fzPlr6G+HLPcaLEnzKuz/AL6olsTI8a+N3hN7O4S/httqN/FR+z34lXw94si87lJv3TR16l8YPCsOqWL232bYqpvVq8E0ye58N+I1m+60cu7a1HwwJjLmjyn1pqFnCrM6IvzfdaOuS1yx8uRf3W/crN975a6Pw3qn/CQ+H7TUofnZol+61VtSsdzF3T5Wb5KI8pnLmvyntf7Bs0v9jeJLUnEa3Vs6JnO0lZAf/Qa/oz/Zy+Glh8VP+Cffw+bQfIOsRfDy2g067IwUlFuB5bMOdu9a/nN/YSSaPTvEsc0SqRNacr3+WWv2P/4IZft32euaXqX7LvjHWD52ialcLpIlkXCxeYx2LX7XxLVqUvCHJJw/5+VP/Sqhyxp0qladOps0dD/wSS/bYXx/8RPEHwu8cQw2GvabqU2k6tZru+W4hkZflr51/Zu0LSvEv/BXi58M65ZJPZX/AMQfEttd28vKvG6Xysp+oJqT4paEf2CP+C0Gs+IfGem6hbeDPiVq0epadfabEqotxJ95fm+X733qxv2d/Fh0z/gqefGlphQnj/XLpQ3PykXbYP4Gujw/hF5bnNWP2sNL/wBJmfVcBVWsuzOjU2hTl91pf5H5W/8ABaz/AIJz65+wH+294m+GttpzJ4c1mRtV8H3Cr8klrI27y9396Nvlr41+z3OnybJk3N937v3a/qz/AOC+n7CHhT/goj+w3f8AxZ+HtvFc+Mvh/ZSappDQL+8mhVd00H/fO5q/lv1a18lnhv4eGbbu/iVq/Gq8VUiqq6/F6nymDrulP2Utvs+aPpn/AIJkXjT+ONbjJzjRCc/9to64r9v+xa6/aM1zcoJFpZtF6/8AHuldd/wTEtltviRrscS/INAwD/22jql+3vo89v8AG67161wwltbeOZW6cRLX65jnzeB2F/7Cn+VQ1fL9bfofMnhnVJvDfiCJHb5Gb+9X1D8O9YtdZ0XZ9syzRfdX7tfNPjLQUs5BfwptGzcn92vSP2e/GiMwsLl4x/CjNX4rKMoy5jq5Y1D1DVLFFV33so/vfxV7v+zP4y/4SDS/7HvLlvtdr8qKv3mrxbVLdJUf+JP4mjrQ+EXi7/hC/GVvfzXrQ20cv73/AK51GIp+0pamuDrSoVY2PsS102a3XftVU3/3v/Hmq5DY7vKS9uYWWT+KP5W21f8ADa2eqaXDeWj+Yl0iurf71X5rF/tT+dDH8qtsZv4a8aP2on2kOWMIyMZrENNNcpzM3yptf/2Wlt9LmaT99bK7SfM+35fL/u1t2FvcrIm+2/dN/rW+Xczf7NTx6f5fm/Zn2su7czJuX/erqpx5SpRhL3kc/JpPmMqeSobYu/c/zLVG80G4RmdE2ur7naNPu11dxp6Md8aKPM+bc33WX/ZqrcWaLMszoxMbfJteteXrEv2fNvscNr2jw27bLYfe+bbXI6tZ201w/nOqlf7tejeIo/LV0tvur8/+7urg9cX+C5SPfv3Sqv3mrhxETqwtNxlpsZUy7NronzL8v+ztre8GmX/ShNFtYMoxtxxzisGSTbb7LN2WNW+9I3zLW14DkaRLrc+4goC2c5ODX33grGS8TMFftV/9NTPpsqjJYuLfn+RS1S8c6jcxoR8s5VAG6tUFveOqyzPN95tyeW3zLt/vVU8Q3ccetXLLF0uWUr75+9UcdxZxr5c0yp8zN8v3q/KuK1y8QY3/AK+1P/S2U5fvZerOh02+hiZH87ezfNu+6tbFhqSNMyQzbiv3F+7trjdJuIfOl3uu2P5f9qtWO8SO3i2fON7eUv8AEtfOxpxK5jpYby5W2U20OxtzM8jNtVqtrdItqsPks0n3du/+GuSW8fbsSZYxu+dZP4f92rENwkimeZGRV/h3blZa6KcvZil73wnVf2l9nWSN3b5W3LHH/wAs6hkuobi4dPO3DZuij8r7zbvm+asdbqFYVENmv7z5vvfeqaPU3877NNHtdX2p8v3lrshU6nPF+9yl9FhXek3mMPvJt+9S3kiTSIXmYbdvzVUW88xt6chfuSf7NPhkhZBsf5t/9z7q11U+Y0jThLcbLb7b5vMg+Zf+Wn8NUZrW/uJnxwW/2/vf7VaS+TcKfOkk27vkaR6j8l3lH2l8n5vmZq29pFnTTp8xktb7Wi+8LdWZXb73zVFbr5kcT3KSebH99vvVqzW8NsoSFNir8yKq/KtUJp0j+/OqM0vzt/e/2axliPsm3seWXNIfDHCqq8kflq1XNP1JGmTEysFf5V+7urMmvIWxvnVEj+9tbatQ2+rWCs298v8AfXd93bUU6nvcxliKfNEsaTH5jeTI6lvN3I38P/Aq6rT/ADiv2nYp8v5XXbXI6DdWrXw/cq0K/cZfl/3a6XTZJobYpvyixfJ/e3bq9mOFPksHjuV6m5NFcrG6Q2ak7l/75qK4Xy13xbWG/b5bfw1HHcJDGv77D/3ldvvUbnkZYftKn5NzbazlThy6H2WBx0YxKGsWrzWjJ5LM7fN+7f7tZGpaXDcRt/rFaNPkVfm3N/eZq37eHbuM8Mm6Rvnkb7tI+jp5jPDNx/47XLUpxie9RzCR59qGjzMuy/SMp/C1c3rWhwtG++Ndm/7rfLXoN9o8y3CvcopRXb5VT5WrN1bS0+z7Hhyu/wCbd91q4akYfaOx4zqeLa1oNzDOERF2/wC0n8NYOpaO7SeZbJIyf7ler+INHhZm+9tX/VN/E1cxqGivIj+SmI9u5P7y1zU6kPhPMzHEe2gedSabud5pkYFf71VPsfnTL53Cbv4a7XUvDcLRiRPut99Wesq60eaMb4YVO37td1PFRUeU+MlhZyqmE1uI22Q7VZfv1cs7mSOLe8Pytt3r/wCzVNLZ/ff5Vaoo7d1Xe6ct9/8Au1MsR7h7mW5Tyy5mfQ3w/d5PgbE6Mdx0y52nvnMledaHs+0IsKyMjJub/er0T4flk+BUXmDaV0u5BAPTBkrzfR7xIrgyfN8ybfv1+0+Mkr5Bw5/2CQ/9Jpn1uCwUa3MpLbQ6KzaS33TO7B/9n5q6PTNSfcJndnXZtdWX7tcYt0I4xv8A3Urffb+6tbGjXU0ca2c028Q/fb/er8HlsXiMvhGB2NvfQtZpcwuxaR2/dt96pZL5/MPnWys/ytBGv93/AOKrI0/UHZoVe5kxJFslkjf/AFa1ejuJoZEuXT5N7bv7zf3aujKcZe8fMYzC+zEupHYB3fcW+bb/ALNZ1zFCv+kpM0L793y/Nuq9cMFk/fP8qxfKzVnMYbiNLkeZiNWr0cPKEY8x8Zjo+8Z+qIkyvCk251bc6/3t1ZO65t4fJRIy8j7fmrXuLX7RcCaZ1Yfdba+1qpLazeQ/nPtlX7qsu6meVGN5cqKK/u5ilu+197DdH826qV1C/mbEePYrfvVVdzf7taFv9pdvO+b938y+X/FUN5Cl1I6IjIfveYv97+61ZVJcp10/eM+GNIGCXMLSIr/Ku75V3VrW7Iy7O2//AHaoNC8mwb2Dq/yzNV6z/wBVvmdVZV3O2371cU/fnyx0OyjPkgbenWd75rzJu+Vfn2/dX5vlavL/AIja1f8AiLXDc3kzOti7LBD95P8Aer1TVtesPDPw9ub+5eNb24XZEq/ejX+9Xh9xq25pnfa7N/rf71fVZTlqwseefxHw+e5tPG1/ZQ+CJLca1Dx9mflV+f8AhauB8QaxNayav5N/+8ktWb5k21sXGsQ/an875dv3WkXburjvE+oPJcSOU37lZNu3+Gva5keDGXMc74X8TyX2mvZu+3y33LVbxJr01vZvDC+3cm165LQ9S+y63cWzuqrv+bb/AA1Z1nVHm3Ojtt+7U/Ea8v2jntSkK3hmL7h/drQ0fxE9rsff9779Y+rXEzMfT/x6q0Nw8Mmz7o/vVXvDPSl8bTTWqIk/8G3atcR4q1Z7i6Z3m37XrO+3urDfM33/AOGq11cb2MzPv+ep+yVFdSezkjmmCdBVv54p2fft3N93+9Wfp94isf3K/e/iq5DcJNcStvXf91F/hWqiEi6sPnAp8zL97cvy/NTrhvOJR0bd92ls5t3yI2P4an2/aF8nDfN92iRJlX0ICj5GO37tULyPZIX2bS3/AHzWpJI8LOm//gNUbqNt29ujfw0cvuDiUWjEY3r/AHf/AB6omVBtf+7Usy7JsO7fLTX+6amBYxsK3+9TY1SRfmFO2p5fzPxtoVkA/eL92q/wmhLbxou6SnyRoyq+aiWfbJj+KpFkRmbZ8q/wU/hMyGRvmCfMK19PuPslq+yT52X71ZTHkO/PzVJJIVX5Pl20vhAueXMq+cz7T/HuqrcR/vPv7v8AdomumkkV3fK1Esg3BE+7Rze+KI61jMjq7v8A71fr1/wbr6GF+Ik9/Mv+rtY1Vt/3vmr8hbFWkulR143V+y3/AAbo2MMnifU0eNUElvCu6Rvut/Cq11YL+KeZm3N7DQ/d+G+vG8M9Wc+Uvy79zbq8H/aCh1K40+5hEMgDJt2s3/jtetabrW3R4ZvtKv8ALt+X+KvOvihrFtNG6Xm5EZGXaqfM1etWlGUbHz655H4Uf8F0PgjeeD/HnhX9pnRIdzLL/ZustGm3y/8AnnIzf+O14z8P/ipqWuaFDZ2t+vmbdz+X8tfp3/wUi+Fvhv4+fA/xX8N0hWaa4sJGsNy/NHNGu6P/AMeWvxh+B/iCbQbiXwxrULQ3lncNBP5n3lZflZa+Dz7CxrR5o/ZP0HhvHyivZSkeo+Ntems7x7OZFdmRX/2f/wBquI1rxEn2fZD8rf8AoNdL4sv5ri1d0jVw38X8S1wGqSbpN77lG7+Kvmox93lkfS4itzakEl0j/vl/4EzVWs7qbzC7u2yopo2bckKfNv8Am3PSSXDxxhNn3U+fbW0Y3PHqS5joNL1az8z/AFKsN/ztXT6fq0PmK8KcbNu6vNPOdWZ0f5fvfera0G+nuF8n7SxH91WqpU5Sjy9DOMonS+JvGlhHCkKQ7m+5uX5mZq5TVr57pdjou+P77Vt3Glww/wCu8sbvubfvVlappVsvHkbhJ8qbayjGJpUqS+Ex1keNvs2PmX5qmhyyqMr5rf3qmaxKqnyfN/ufepjW8xXfNt++yuq1fuSMSb5Gz2Zflp8MTsfLSLPz/wAX3ahjjdJmdPu7P4f4astJbSMqu7Db8yMrferP/CVH3S3Zw/vGz/F8tdHpOhvcXUNnHD5u75vl/irDs1e4/wBG2Km5Fauz8LskNiPJttr7/vbvu1wYyc40rxOnD8kp+8dVJqln4B8Oslncr9rZFVdq/NG1cHrXiSaxie5v5mNzM7PLM332b/4mtLxE2pahJ5yWy7Y1+9/eavK/iL4uTQ9Sks9Sm33iou23j+7H/vVz5Xl1Ss/5mz0q2KlGPLD4S5Lr1zcTPc314w3P/DXf/D7xF4k8MtBqulWczN95dybVZa+en13VdVvA8shyW/dKteqeBNd+Jul6cdSe+kks44NryXS/u41/3q+ixeXVI0uWJhTxWIpS5oM+w/gd/wAFfPGf7H3iKy1RfhbFqDRov+kQX/ltt/iXb/EtfYPgf/gv/wDsX/tDwPZfGfwvdeD7hYFi3TKTHNub5tzCvxK8UeNptc1BpjMs25PvL93/AIDWV9smuG+fbtb+7So8NwrYflm3GR6dPjKrhf4kFNn0X/wVd+Onwo/aG/bq8Q/EL4Faw174Yh0uzsLC6aLarNHH823+8tfPI3huZNy1FGr7lfzF/wCA1Lbwo0jpvbb96vrcNRVChCn/ACnxGKxEsZip1nG3MzqfA+oPa3SoNvzJ/F/DX2D/AME69DfT18R6U9s0aRtut/n+VfM+6y18XaLdQ299E7plPl+Va/RH9h/w2lj4FufEKJGEvoo03bPvbf4d1dfN7vKclH+PE9ks7P7Ooebc6L/Ft3Nuqe3t7OOTf5y7Puouz5v96rl1aw2Nos1m8m1U+dlp8ln9om85HbKpu2/w7qdOPunr8w/TdJTzXQ3KqjfNEq/erRtYUkuG2o22NP4k+bbUelf6tUR+WTa+162NO094pt7ou77sSt/FXXTjbQ2oykP0ezhjtVdEZ0k+bzF/i/2qufYZrhWeZ13Mu3y4027f+BVdsVSSNXZNn/TPZUqKiqs3zJu+5Ry8vvHu4eUzmdY0XaoeFGx8v75vux1yGoabCyzpvxGzs+7Z95q9D1RfMt/9Yynd80a/d/2WrjvEFrjMPy7vv7m/iaspS6nvYVc0oxOaax3bfs0TKNi/L/eWsHXrdYtTnt4yFGQAc9MgV1Fn9p85POf5W/8AHa5vxYEXWbkwtuXAKk9/kFfqfg3K+a49f9Q1T/0qB9JhMP7Jyfkz83/2zvH02tfHTWNKhvWa30eKOziXZ/F95q8z+Gun3OueKLazQbjNKqqzfdq1+0Brb6p8fPF04fcs2syfN/u/LTvAMkOi2dzr1y+Ps8X7pf70lfkPwn4bjeaWKn/iOu+MXjz7DeTaPpV5ugt08r92/wAu5a8f1zXJtQkMzuzNTvEWuPqF89y82fM+ashm8xi+/NL4viMOUb5j+WXfrUkK+Yi92/u0kcLyJn73+ytaulaO9ww2Qtmr+IciGx07ciuXZt1bWn6SzSb0Tcu2tzRfB7rD5zwbl/2q1W01NNVvMRc/3a15eWPKY/FLmOcuLN7VS4RtzVmzruk3gfdrX1q6RlZ4Wwyp92sCaWaSRn3rtrKUiox5iG4mkZhsRm/2mpbNXVmR0/2makaT92u8MWp0Nu7HY7712bqPhH9g09PX7SypvVVX+8lbDafM1rvh+Yt9+sXT7jbPs8v5P42rpLOS2EOzftDVXMTLYzPsc0LDzE2urf8AfVaeks63I+78r/OtLdJDx5PPz7X+f7tNjkh3L5Pyms4+8HLHqei6Xoej6tp6bJtpVNvy14/8YNPfR/Ewtndl+X/erudHuHjtmSzdlZdyv8+5WrhfjJNcTX1tNO6lvK2s1IcY++Zfhi58y62TP/Hur3jwTNu8PiPzFYLt+WvnTQbt4boP8pr3X4bXf2rw7M/zDyU3Oy/eq/hCXPsY/wAWtQdtLebqjbv+AtXicm+SYu235q9M+MmpbbYW3n8Nu+X+9XmKcMKZdOPLG50Xg9Q1xGm/Zu+81fQ3wzkeTR1hhTPyfNtr5/8AB8byTRun3d/8VfQ3w3t4Y9PfaPk8r5f9qjm+yYy+Mf4wvIZIz8kgMa7NrfxV4d8QvDL3DS6lbWzZVq9j8TR3OoTM9ykg+fbuaslvCr3y/Zns2f8AiWTZTjyGXvc/MWP2cdck1Dw7LpT3i+Zb7WWNv7td1qVhuje5R8n+JVT7teT+BY38A/E6G3mdhDePt8xvuq1eztcuF2b/AOPb838S1Pw+6aS5Ze8ep/sSwywW/iZXl3KZrQp7fLLxVT4X/tKeL/2Z/wBqnVfHnhm8ljFv4hmaeKNv9bH5p3LWt+xzapbJ4meOYMJLm3baP4OJPlrxj4vgp8YvEUpkwx1mcYP93ea/aOJkv+IN5Kv+nlT/ANKqHDDm9vI/oq8afD74W/8ABZf9hDSvEXhnVhF4m0y1+1aDqqsvmQ3ar91tv3dzLtr8/P2aNW1zwB+1rZ3vj7TrifVLK71WDWLeGLMhuTa3MUuF9Q7E49q80/4IH/8ABTC5/ZL/AGiYvgJ8SdY2eEPEk+2CaaX/AI85m/8AZa96+HGNd/4KZ6jNpl2TBcfEHXJWlgj8wvb77pn2juTHux9RUeFNWdTKs4ozfurDyt6NSPtOFqUaeBzSsvidGX4KVmfcn/BPr4z2HinxBefDfxBdE22u6cYfsrtuVm2sv8X+zX8zH7UXw70TRf2jPif4M0dFa20Hx/qlratH93y1uG2qtfvx49h1T9jb44WXxavrdbDQZory98OtM/7xLVYW27v9qv56de8ZXniT4yeJ/EOpXLSN4g1y8vJWZNvzSTM3/s1flmNjLD1H/LI+Cy+pCtTjzfFG56f/AME1bO5sPipr9tJjYNBbaSuD/r4q6L9sXRIdX8Y62hhYyiG2MbKM/wDLJaq/sCWhtfi7rpOfm0E8s2T/AK+Kt/8AaHla5+MGp6YzrseGAYbt+5Wv1nG/8mPwv/YU/wAqh0yl+/b8j5LmtodW06awuUZXj3LuauY8GapL4T8VGGZ8bZfl3V3HjDT30HxhP8i+XcPtRV/u/wB2uF+IGlfYNQXV7ZPk3/O392vxeXve6dlGUubmPp3w7ep4g8PR3jvhW2/Kv/oVVNQheO4kmh/hX+H+7XD/AAF8YPqGlrYPNv8A9lm2/LXfaxE9quxE3tt+8r1HN7tgqR5Zcx9Zfsb/ABSfxl4Jbw9eXO6fTX2eX95mj2/LXsPluxdPL+Zvu+dXxB+y/wCPH+HvxSs7y8m8uyuv3V02/wC7u+7ur7qlKXE3mJNHLbyIv7yNflk/u1w1o8srH1WU1vaUOWQ7S4Zm80ImV2VPbJeMpMKfMvy/7y1ZsYYVj2bNif3d9WLXTUjXfCjK+/am2iK5j1PaS92JnXdrDJhJLXarfxM+1V21QvLV1kkSa23ity+t3l2o6K4VvkXb92q11Z/u33zttb5vMrojT6oqNWXNyxOG8RLZxyfacNmRfvLXnPiK6htbgw2yMXb5kaSvSfE0CKyPCkgSFG2RyL8u7/erzPWrGaEn/Vum9tvzfNu/3q4sRGHKephfeOcnWa3uNkL7xu+eRf8A0Gum+G0iML5Yx8u9GB9c7v8ACuUure23TI9zMiKu6VVf/wBmrf8Ag87GG/jJyFaIqc5yCGr7nwXa/wCIm4JLtV/9NTPfyqP+0xl6/kZfiWbbrl7HK7H/AEhiMduazobwrMwhf52T+JN26ovGN3cL4nvoowNpu3ViW461jyakJpvO+bbGzKrL8qtX5lxPHmz/AB3/AF9qf+ls5qvu15erNuORI9QzvX5tzfLVyPWIfM2JJIzL8yfw/wC61chca48K/uXwyttT5vvUN4mgaHY8qpNs/h+bbXgxp8xh7Q7NtY2qJppv3rbt6/e+b+KrNj4iRnb9yymOL91Mz7V215/N4gFxGib/AN60Xz+X8u6mf8JFNDt+dn3fKnz7qJU5S0COK5NT0218STblT5UWPdvb+9/u1Ja6tNIzu9yu1vk3L8zbq81t/FkLKttM/wD9jWp/wk7283yJGw3bf3b/AHmrf2cuoU8RCUz0nT9Wha4EKOzpGm3+7tX+9VzT9YSS3k8l2Ks33d9eZ2/ix4ZXMG4rt3ff/wDHWrQ0vxM/meek23b8zK33ttZ806Z3UK0JTuekfbHmjVN//LL5lb+GrEkltfWfmQux3fd2/wB2uJsfE9t9ohd7zajL821tzNV+38WJbyLsfYnlfeb5W20qeI5XoejTj7xuXnzSI+zcv3fvVk6lNbSTR2LTK7fNt+Xbt/2t1Yt94geQM9lMq7n+Ztm6sW+8aeavyTN+7fa6/drKpU97midsY81K5ratrXmQtbIG+VPn3Rfe/wCBVlRa55wi8mZmTZtRW/hrB1TxVNc7kR1Z1T/V79u3c1ZU3ibbEUNzsRfmRv8Aarpw9Y8vFU+U9M8O6pbbYrZHUv8Ae/3q7DR9W+7C8yoGX5mX5vmryXwzr0LN8833f4f7tdrpuqboWRHX5m3V9nKn7vMfklPFTjI6231Sbz2SaaRfn/e+Yvy7f71aSTJcSRBPu/e2x/LurlrS83eZs8xl+6jTVrWt15kavM7Yjbcu37q1jKjGWx7mDzCrE342+0XT3PneaGi2su/7tTeWkjOiOu3725U/8dqto86Ru8z2ysv3X3fdZams45pLhb+Ha6L91furt/irzqlO1z6fD5lLlTKF9awy3Hzv/D8rfdrF1C1s5ISly7EN/E1buofvl37F279qN93bWXcKkcyzP8z/ADLt3V4mIjyyPYp4z91c43WtP2Mu92f+4uysebR1uFWbZsGza7L91q6y+jRpFs03D97ubdUH2G2TciPu3M3zL/FXn1JcoU63tjg9U0F5GaZ/3S/elZvmXdWLfaLtgZ9mG+7tWu+1O3mjjeF03KqfKrL95t33qxdW0ubzC8yKFhT/AFap93dR7T3Tow9OMp3OH1TR0t5Mum1fl+WqbaS5Zk2SJ+9+7t3V2OoaeJGXz02fw7f4lrOmsU3b33fN8yNRzS5OU+xy+nCMT07wTbfZ/g0tsw6afcjBP+1JXmmm6fM0e/ycsr7VVm2/NXqnhWHb8LVh8sD/AEKcbR9XrgdG0/zPkhfHz/Osj/dr948ZZcuQ8N/9gkP/AEmmejlKjz1v8X+Y3T7GaVk851cqu35vu1o6bbzRscOxDfKm77tWIdNMcEcMNtt/i3f/ABVWlsfOzYPM2N+1vL+9/wABr8EjU5TfGU/c5mSaWzyQqVRUDJt2yferRVXjs1R3VV3qz7m/h3feqvp+l7Wb/WMPuurLV6GFJDsRI2+7t3fd2/71dXtGfDZhLlG3Vim24mmnzt+baq1R8x1VHhh3+Z8m5V2/8Cati6bzGbZHJKrJtb/Zb+7WZfLM3zzOzKu1fLZtrbq7aM48tuU+JzD4uaJl3W+a8e2Ta5V/3W19rVn/ALmSR5vmDx/MjK3zSNWrJCjMkybWLPt27Pu/8Cqmtv5l0yJCyMz7VZv7taSlzQ908fl+0MZXt5vtk07R+XtX5V/1n+9UV5HbXUY3+ZFt+8rfdZq0ZrRGhXy9u/ft3bGakWxm8vZ8ruvzfu12+WtcNSTlqjro0zHa1RZkSF2H+z/Cv/Aas6LYPdagltNM0sXm7pd38S1alt4W3u/mJ8/3m+81P8A2r+MtW1+wsJlf+ybJnn2t91v7q/7Vd+W4f22J16Hl5xiPquG5Y/aPOfid44e81SfSrPaI7d2VV2feb/ZrgdLvB5k1s8y+Yz/dan+KLpLfxNf23zEtu+VvlZa5KPUraHWvs1zuUbN26vs4x9nG58DzTlPmZU8Xao9rM+98fPt3N/D/ALtY2oap/aWn79/zbdu5Xql481aO81BpERm3bvmrmrfUJrXd3T7v3vu1EZfZOj4jl/E8n9n+IpJId21vvL/tU2TUppoT2/2dlM8YNuvldI+W+Zv9mqlrcbY97vurWOxXMNuJMzP/AAlX2tVa4mhY7HT7tLcSOzM4f/Z+aqsr7lFL7Q4j5JnEe9Pu/wB6o5Wdfn/ipIW+Y8fL/dpxUbd79f71Ei/hFs5N0y1d0tHlmkjT+9urPs5Ns/P96r+jzeXeGZd33/m20v7opGpDHtkK9NvzVZjkfOUm27m+X+9UM0YwNnP+1Sx3XlxmBP4fv0pcsTP4hLyFJG3pu+X+L+JqpTyeaV/ib+7sq150zfPs+RU+838VQSKh3eT95qAM+4jT5nwuWqm0bj+PdWj5O5m39F/iqrNG+3eiUR900K6HaPu/8BoLbWb5P+A0/wDiaPf/ALtRSfe3ZzTjIBwERG807zHHyJwP7tRxkg5xkU5sKcZpAO3Sffcf8CoaTzDv3/71RMH6sKVW+UjtQBatI5bmeO1QBjO4RGJ7k4FfaXw1/wCCDX7a3xg8Ka94u+GsGjaxp3ha0F3r13Ym4ZLWP8YgZGxltiAttVmxtUkfGehyb9YskZP+XuP5v+BCv66/+CXf7HHxG8I/se+PrjV/Emgv/wALb8NhdBFjqBuFtAbe6hBneNSoOZlJVC5XDA4YFR9jklPhrD8OYzH5mlKpCpQhTi5Simpyl7T4Wm3GCcuyt12cz9q6sYx21v8Aofzy/s9f8EJv2tP2kPivp3wp+F3i3wndapfszkyXNzHDbxKMvNK/k/KijqcEnICgsQD+hf7M/wCyR8av+CK/xTfwJ+0uLLVRqNnHdWN94TuWuLa8iB2lo2nWJhhgVKsqsMZxggnvPEP7MP7Tf7Hn7Yfhr4R+AfHWlf8ACeXNzbHw9qXh7WU275/kVJBKFMeclWSVQHU8B1YZwP277b9pnSv2jdV8O/tZeNY9e8V6fBDE17a3EbWxtyu+IwpGiLEhDbtmxDliSoJOf3LBeGPBuYcUYaWAr05YKpQdRQ55+2k+ZJTjrbkV0nfW91ZvWPkV26tBxqJ3Tt5f8OfSdv8A8FYfgxDYx2Y+HnilNhydi2/P/kWuJ+In/BRb4a+Mdy6f4S8RQBgAWcQ54+khqP4Of8EWP2uPip4Mg8Z65deHvCSXkaS2en+ILuX7U8TKGV2SCOQRZBHyuQ4IIZRXh37TX7I/xy/ZI8WQ+FfjL4VFqt4JG0rVLSYTWmoIjbWaKQdxwSjBXUMpZRuGfUy3hPwXznNJZdgsTGpXjf3Y1m27b8vSVuvK3bqcs8FOFPmlFpGp4q/aF8J+I7meVdE1CNZHJXCoCM/Rq+BPjt+wZr/jH456p8TPhT4i0vTtM1ZxPcWWpNKJFuD99hsRhhvrX05SxxvLIsUalmYgKB3Ne/V8D/D6qrSoz/8ABkjTDV6mFmpU3qeS/Av/AII2ftwftRPIvwc8N2eswQyGG51JWkhsoZAqsUa4lVYw+GU7N27BBxzS/tC/8EF/2+P2d9NbxF8WvB9jZaSpUyavaztd2kW5gqiSWBXWIlmCgORkkAZr9f8A9uz4z+J/+Ce37Lnww/Zf/ZvvX8Malq2lNe6/qdowN2Nqp5pDkZDyzyOxcYKiIKu1eBm/8Er/ANrf4g/tQ+JfFH7In7UniGbxnoniLw3cS2j61JvnXaQs0PmDDsGRy4JOUMQKkZr+eqnh3ldbJ6nFeHwEHlsJS9x1av1iVKE+SVRO/s09HJRa2W70v9DLM8RKaoyn73orX7dz8LJf+CeHxPdht8ZeH9oOdpef/wCN1ufC7/gkj+0r8cPH+n/DT4V3+j6trWpSFLSxt5JRnAyzMzRhURQCWZiFUAkkV9g/FXwXL8OPif4j+H0ySK2h65d2BEzAt+5maPkgDJ+XrgfQVneGvE3iLwbr1p4p8Ja7d6ZqdhOs1lqFhcNFNBIOjo6kFSPUGv2qfgF4d4nL3VwVKXNKN4OVSbjdq8XJJptbXSadtmeV/aWK5/ef4HFP/wAGq/8AwVPcH/infCPK4P8AxVkHP61R8Tf8GzH/AAU9+F3ha98b694Q8Oz2GlwNcXi6br0dzMsajLMsUeXfA5woJx2r6Qj/AG7P21J5Vhh/ad8dO7sAiJ4hnJYnoAA1faP7b3xj+KP7Lf8AwTz8L/Ab4g/EjVtY+I3xEtWfxJeanqMk9xbWjYe4iDFjtUBktsdGBkPXNfkGaeDeLyXNsvwVeOHqTxVXkUYfWOZQiuapPWpZRhHffVrQ7YY/nhKSurLy+XQ/Gj4Jf8Elf2qf2iPEraD8G/D0HiG7twgumshMIbYPnaZpWQRxA7WwXYZ2nHSvUPGv/BtV/wAFQfDemXHiOf4f6LdW8C7ja6XrkV1OB/sxRku59lBPtX6jf8EqLnXvEn7AHxL8D/s2a1Zab8Uo9UmlS4nRQ/7yGMWzbnJGCI50RiAqvkkdWaz+xr8Kf+Cv2kftGaJqPxq8XeIIPCdnen/hIh4i8SQXtvcW+07kjjWVyztgBXUDaSCTjOfL4h4K4Vwmb5lTw/1fDwwTt7PEVqqrVrQUrwSlFWne0LKTel+hrTxeIcIXu79UlZH4K+Of2Bviz8PbTV5vEGsaZb3GhxTtfafOs8U8bwhvMiZXjBVwVIw2MEYOK+f7r5rjZ/ef/vqv2f8A+C0Ou/D7xJ+038Wbz4d+Q1vHpUtvqUtsuEkvo7PZcEfMQSJAVYgLllbgnLN+L16rSMmw4bbt+Vq+a8UOFMh4ew2U4rLKEqP1qj7ScJycnFvldtddL28+x0YKvVrc6m78rsSSSQy4REVf4qZHDBJcb+nyfP8AL/47UCyQ2+1Eh3t91/nq1YW9zeTLGkLbm+7X5LGMTv8AiNfwrYzX2qJbJtb/AGWf5q9Hg0dtNsW2Ju+ba23+Ks7wB4PvLOFdVv7ZovtCMq/J91f4trV0nibXrPRdFfVbny38uLbFG3y/NXkYqt+95YRuejhcPzayNT9nzwC/xB+IiabebZrPT7W41G/h27ttvbwtIzf+O18YeINRuPGni3UPEz8ve38ku1U+6u75V/75r9MP+CTXwr8T/EjxB4/1vwT4ek1XWm8IXVrYWqqzfvJvl2rWh/wW6/YD+HH7N/w6+BfjPw/8N9P8L+KtWt7yy8U2emuqrcLDGrLI0f8Ae3My7q9XKcdQw9aVGXxM9rH5VVnTw/s/tHxH+yP+zxqPxe+IFnYP91pfkVk3LurY/bk+J/hnVviI/wAHPhRZW9poHhVFtb+4s5dy6pfKv72T/dVvurXtvhLw/afs4fsSeKv2gNURYNVmiXSvDTRsySNdXHy7o/8AdXc1fDtmXkgyzMXZ90srdWb+Jv8Aer38u5sTUlWnsvhDi7D4fJcJRwcP4so80v0QCN45Nny7Vq1DCi/cfb/F8tJGqL8n3y3+zUjRvu2Rpt/v7vu17R+cS2FaTj+L/eqS3O4+Xt+9/Fv+7UO6Ers8n5Vb7y1csLczQ5RFpykKPPEkST7LNH5Ltu+9X0B+zV+1V4w+BPjTwx9p17b4P1SdrfxHbzLuW13femX+7tr5+aNFmVs7i3y1r+Ire5vvh5Klna+dLb3Cskkf3lVvvU+Xmiac0r+6fr/4Z1nwr4ys01P4e63b6xYXn+qutPuFkWRdu7d96rjOlvMl46Mo+7t/9mr8XPDvjXX/AIa6na674Y8SalZ6la/8eraffNH5Pzfwqrba+0fgR/wVM0Sz+FM2m/G/SvtXibS0/wBAmtU2/wBoRt/z0/uyLV060afxHXCUJH2/p8KTTfJIpMjbXb7rKu371b+k5b7+5Qz/ALpVT5mrxD9l39pXwB+0locuseG7mSw1G3+a60e8lVZ1/wBpf7y17ZY6gjTJNc+Yjr8iR7a1jW9p8J6NGMpQN2zi81pbmG23/L87bvu06SJ45tiIv7x/n8z5VjqGxkmhjf8AiWT5tzP8qr/EtTFopv3yPlVT5l27t1axkerh+bl0KWpWsJkKPuCfd3L83zVyniSzSHfvmVvn+T+9Xa6hCgs3+X5GTdt/irifE1y821Nnmqv3I2+X/gVctapLofU5a+aRg6aqfaGRIVZ2bd8qferkvGsXl6/dQmU8Kg3rxgeWvNdx4bt3a4MKW22Vk/h+Zf8AvquR8axMfG9xEF2s0sfB7Eqtfq3g075zj/8AsGqf+lQPpsPOLlJeTPx++NENxafHjxLaAfN/bEykt/vVB4q1aHT9Ft9EQbWj+dv96us/aY8OyaX+1H4qgvDwNRa4DL/EteZeINQ+338k+zf89fkkfgPwnF/71Nf3inL+9lO+iGNGb2pY7V5GxXTeG/Cd5qEyeTbb/wC8uyqjHmOWU4xIPD+g/aGX5flr0nwn4JRYVuZoVC/w/wC1Wn4H+Hr2savdIr7vm+Zfu1Z8UeKLbw/F9jR18yNdqsy/drb4fdMeaVSXKiLVprCxt/J8lV/hdq5TXdcj2l3uWO7ms3WvFlzfM3nfxP8AeV/vVjXl49xGOxrPmmXy+5oQ6lePJcvM53bv7tVGmIXZTppvm2eXz0qPy3ib95Ux934iveFEkZk+5xtpbNvm8j73yfPTWj3b9n+7VixjHmK+/bt/8eqhRl9ks26zM5T7q1tadI7Qqj7cR/3f4qorbzXEf7lNm3+L+9V2FXhjGxKCZe8WWt5pmZ0RlLfe21DIs0JPkp82/b8tamm/MuX+bb/e/iqxHo6TSLCkjAs+6l/dJ/wlPSdSns22IWxXO/FWXz7aGb/prXZ3Hhm5tY2eHcR/47XE/En5bZEmVi6t/wB81HL7xpCWpxtmSlyAf71ez/C3VHXR7iz87/WRbvlrxWP7w5zXqPwzvoYdKldH/wCWXyrV83LEqsc58Vr0TaosL7fl+/XKWse+4WtLxhfPeaxJv+Yq+3dVXSLd7ifYlMfwxOy+H+nvNcfOmNu1v92vVLfxZpvhuNYXudu377R/NXnmhwzaRpiuIVYqn3lrO1bULm6lZ9/8X3t1RL+6ZfEeo3nxQ02YN8m59m7buqBvihc3H/Hgiwp/d2V5jDHeTTD52+Vfuqta1qHsVZJH5VN1Eeb4iuX3eUl+IHiK5kvLS/uXb9zLvVY/4a9v8JeIn17wpa6lsWVvKVWZVrwrUoX1axkTZtCruf5a6T4C+OvsdnP4Yv5stC/7j/ZWnEnl9w+yv2OZHe38ReZtz51sfkGB0krxn4yxBfit4jYwHadYnLEt1+c167+xTefbLfxIxfcVktMnGO0teSfFBHvPjD4mijAcprVx8p/3zX7TxNHm8HclX/Typ/6VUOBXjXkcT4g1DUvDuoWnifR0aO5t3X9591q/Wn/gklrU3i/9sf4Va94luN82riSW8kkPLyTadOWJ9yzfrX5ReJrF9Q02aF/m2xbkVf7tfb3wJ+PGqfsx+E/BPx50dz9o8NWel3I5xlSsUbj8Vdh+NYeGKSyrO7f9A0v/AEmZ97wk+bBZh/16f5SP1N/bF/Z21X4w/Anx38GoL+W48Z6TfNFoytulurq3b7sca/8APHa3/jtfzMfG/wAE+LPgr8bNS+HvjLTZrO/0nVJLWaGZNvzK22v6pviX40uv2gPgt4b/AGxP2d/GE9nJr2jLpeuzaay+aqyfd+b/AJZsrfxf7Vfjn/wXK/4JreIfCWpeF/Gfh1LfUvF2rJJJqmh6fO11eLGu399Lt3NuZmr4fmpY7KOaUo80du/mj8jo8+BzbkjGXLL7vI+cv2Dtk3xC1G8yC7+Hzlh0/wBdF09qT9ou7Ft8e9UYEsRBbfIP+uKV6N+x7+xN+1R8CfBa/G340/B7VvD3h/Vov7N06+1S1MH2i4YiXaqNhsbI3OSAOK+z/wBnP/ggzYfttaVbftReOv2g7Tw9o+sTNDbaZaaY010jW7GAl2JCAExkjnoa+8zKrCj4F4WUnp9af5VD6SnRnWxbhBa2PyC+Lnh/7dpf9pQ7t8Ls+7bXB6hp7+IND3+SzfuvnVkr+mzwZ/wbbf8ABN3whpEt/wDER/F/ijam+X7RqXkR/wC1+7jWqOp/8EYf+CFc6p4Mvvgr/Z0906+VcR+IbiOTc33drM3/ALLX4U84wSlqz1qWW42rH93HY/mO+FmsTeHfFSQyrgM2Pmr6JhP9pQwukOVuIN22P5q/fn4Of8G7/wDwRTl1GbxZ4b+EGp66ltcTQSrqniOaWDdH95tq7a6HUPBX/BFb9kS7m8Mah+z54K0+e0kVbO0bTWvLiX+795mqK2a4Kjyzb0kdOHyXMsZzU4QcpR8j+e/w/wCC/FuoTJN4b8PahcPHLtRrGzkkZf8AgKrX3f8As96X8VPH3w5017z4e+JP7Rtbf7PKraDcbpmX+Lbtr9Y779uH9lr4K+EtG1lfhfoXhuXWIWk0nw9a6NCmoeXu2qzxov7v/gVc18Lv+CvPhXXfGWseGtf8JQwJYzqbeaGRctH/AMBrircQ5fGav+R7+X8J57Ti5wht5o+KfC/7OP7RviqHzNK+Bvii4RbfdK0mjSL5n+7Xf+Ff+Cfv7WPiSFUh+COrWisyr5l48ce1f+BNX3Ha/wDBUT4Jy2rTCKYvGjHyU4b/AL5rjfit/wAFk/g74B0K6ns9JuJ7rZ/o0ef4v9qpjn+W8t0/wNZZHxDKfJ7K3zR4FD/wSg/a9mj8xNC0NE27vLutcXzWb/gK7azfEH/BKb9shLNifBWj3Kf88bXXo9y/7X+01Ubj/g4D16bR45H0LTneKWRZWjuPmb5v7tcR47/4OFfiJLpV1b+HNHs7WVp/3V1v3PGv+0rVhLiOlKN4wZ6EeG84pytOcIlTWv8Agmt+3RNbtbJ8AL+UrKyxbb23b/gX3q4DxV/wS4/bvsmd5/2YNZnC/cks7iF//Hd1TaT/AMHB3xe0fxn/AGjc30dzA1nJb+U27/WN92SqviH/AILu/tAeKrZdHsdcl0rdKrNfW8i7v8tWE88jKPvUpHpUcgx8Ze7Whb5ngnxY/Z6/aE+EvmH4nfAfxho0Sy48+88PTeWrfxfMqsu2sT4Nzw3K6pLBdRyATopC/eTG75W96+vvAX/BbD496bMLfVvFlprFsqq0qX0aybl/iVt3y1zX7W/xp+Gf7QEvh74m+D/hvoeg61eQ3KeIp9EsFgF6wMZiaQJwzKGk56/Ng9K/T/BLGUK/iZgoqNpWq/8ApqZ9Fgcpx+FqRqycZQW7Utb27Hxd48vZI/FOowLKwBvpDk/7xrmLrWtkeYXx/Duatfx5Pb3HizVpba4Yj7fNGy7v4hIQ35EA/jXG61JtZXR1+X+Fmr4HiaF+I8Zp/wAvan/pbPCxk25ya7siuvEm3akMLN/Cn+1VaTxVbJu/c43fxLWHq15tkOxGXd96suaSaWNdiZSP/b21xQw8JRPna2InE6qPxY+0+TNtbdt3N8u6nN4wn2o7pGqfdRv4mrjbSWZ2L/N+7+Vfn/hqyrzLMnnfxN825K1jh4bHH9cqyOwtdcS5jffc7d3zff3Vbj8RPHJE6bnWNv4f4a46NraFv3PmO/8Ae2fdq8rTMrPv+9/C38VRUpyidFPEc0Tq4/FTyMyCbf8Axbd23a1WrDxVM22Hev8At/3v++q4/hY96J977m6pLe4fcYXfYdy/eauGpRnL3j28LiPh7noGl+Lrlplttit/d8v5ttaK+ILmaNUvE8z+6u75t1ee2s1yrGazT5t+1GV/lrVtdUufLbfNw3y7d+7/AIDXBKPLM+lw8jpr7XJVWZMyQt5W92X+GsnUtYmmxG958u35P9qmRzSWrND8yxtt2bvvL/e3VBqEf7sbIdv9xWX71KXKej7SMYlGS6htpPOd8bn+bbUH9pJIy/O2Ff8A1bfxU7UkTbvhmbd8rfN92qMjeTIsJRsbPn8v+Gt6MeaR4OMxHLzHXaHq0yyN53l4ZNz7f4t1dr4f1SaNVd3V/mX7r/NtrxrSdcms45PORj/stXa+Hdc3Wqs7shZPm/2f7tfcU5e6fj8j1vR9aE0gfylXy2+7I/zf7tbWj300zb0uWi85vu/e2steb6DrUCx+TD0bbvb7vzf3q7DQdVdS77Iy/m/d/vNRKUEdOHrS2kdtY3H2NUTezvH80si/8tP+A1ajvN0z3UIbzJnVdqv/ALP92sOLUppLPZt2yNuZ2/h+9VhpraNneH50XazV5tan9o9zC4qX2S3qV55bAOm4/d3L81QNcTXNwHmgjlC/61W+8rUyRnaMW0PDsm6JpKfG1zLCba5K/Ku5mX+9Xz2IVKR9JRrVeSJVWDzpBNDCv32V/nqNY87ntl/2fLb+9WmljM23emxVXdt+7uZqtLp/+jojou/71edWjCOqPVw8u5xWoaa8P3E3sqM3zbt22si+09Li55MgMiqz12mqWSQt/pO1X+4zf3axb6z2/OEmabb+93P/AA1lGXMerRl72pyN1Yuryu6eavyqnyfNVObT4YVbyVb/AGFrp7rT4Zd7w7o3/vN826svULFI0/vHerbttLm98+oweKOp8MRGP4bpEyuSLKUEN1PLVxmkw/vPnTK/88/4q7vTNp8DsEcsPskoDL1P3q4Kxknt2H2aFsfNu3N826v3fxoV8g4a/wCwOH/pFM9TKqsFOrfq/wDM3bWN47dUS22Oyt95ttSwh2mP7vZt/wCWiL8rf8Cqpp90ZoTvRtn3t38W6rthv8sI77Nz/PGzfK23+7X4PzcpOZYqPL7pbsYUk3lJmi3PufdVpY4Vj3Wz7V/gVU+7UCx7YHme4h2r/CqfxVYj85WZ7aFVVvlrWMpx94+IxmI9tLlBf3Hl/afvtudVqpcWe6P7Z/Gvyo38Natvbu0fFsrPHuWKTduamXFujWqO8MyBvmfzH+9/wGto1re8fM4inKpPYwbu32q6XKfJJ8yMtQR6akr/ACIzDYuxd/yrWncWLyLIdjJtZvmk+WrGm6K9vH9pdMrNt+7/AMtGWn9Yly+8cv1ecZGfDZ5V7aaZsbN+3+7/AHasNp7tiF0ZG/iZmrVXT/lXcixKz/xJ8u3/AHquJpMMjNC8yq2/dEv8LVwe0fPv7pvToy5rM5C80mGO3e5mO1dvzRs/3q4j4P8AjWHR/EnjuZ4WtlaeFd0O1lbcu1f91q6v4nao+k6hHpsKMrLEz/u3/u186eG/FD6b4o8SWcyTFr61ZvLjl/5aK3y19vklCpTw3tX9o+D4grxni/Zx+yVvilefZ/GVzC8ckXmSs3mSfeavPvFkj2N9FeQ+Ydzbf3lbXjzWvtlxb63skzt2StI+7c396uf1q4m1Kz+0vMpRkZtv97/Zr3IylI8L3TlPF2oTTaozptCsn3qzrySFbYzTbfl+4rfxUniK4VZN7p8+2ud1rVnkh8k7g397+9V/aKH+Il84iZ0wrf3axIpvJZofmrZgc3uijzDny2rMkj3Sb4PvUfCEfeIpP3f393+9TJB5kf3OP71SXCBl+5yv8NQTcMqb9w/urRI05eaRAx29ak2Oyq9RuN5yaVfu7PMpc0S+VCx7Nxy3SrWmSPHL9/738NU6ktWCzLu6UhSidJbSSeTs7L/FTZFeNm2fNu+9UdnM8kOxNtP3eThFTKf7VP3dzEb947M7W/vNUF0zxr8nB2U9piy4mk+X71MkV5FP75WWl8Og5EDL5ihEfbJtqG4DpDh91WrhflR4X+eqszO6N87FVo+If2dSvI2G+cq1RMoZ99Sts279nzVFMvaq+EuO42HO7bu2nNSbUZN9Mt13ueean2umUdFqhy3I8pko9NfZ/DUjR7V87fTRJkYC4NZklvQ5HOuWeHyPtcf/AKEK/qX/AOCSd7eL+yJ+0aq3coEHhjdABIf3Z+wX5yvoeB09K/mI+CHw08TfF/4p6P4D8JQK95d3itmR1VY40+eSQkkcKis2OpxgZJAr+iH/AIJf/tqfD39lvxV4m8EfG6PUJPBvjSwjt717OIyrazKSnmOgIbYY5JAxTL8LhW7fsXBeS5tmnh5nDwdCVR+0w0opLWbpVPaTjHvJRtp5pdTlq1IQxEOZ23/E8y/Ycurm9/bV+GF1eXEksr+OtNLySuWZj9oTqT1r7R8ZeCfDfjr/AILyWtl4muFWOws7TUbWFkQia4g0tJIl+cjGGAf5QzZToOWX5/8AHF3+wH+zj+1j8M/iV+zN8VvEniLQdI1221HxPHPYGQWqxTqwELyLCzsVByhU4AB3knaMz9rj9srQ9Y/4KETftY/s5akb2HS7mxk0q41TT3jiumgt0hfMZKyeU4VhzsfDHhTX7Dm+BzTi7P3i8BRq0YVsuxFKMqlOUHCpKpFRjJNe63a67x95HJCUKNLlk07ST07H2n+2frP/AATy+JfxmutN/aG/bE8aaJrXh5ltv+Ec0rULiC106QKCWREtGG9shjJuYngZwqgeMf8ABT/9rL9kn4sfsseGPg58KvixfeOvEGj6vBJbazqFrM1xFBHE8bvPO8cQd3DKCQrFipLAHDVq+M/jF/wSS/bumsvjF+0HrGs+A/GcdtFBrlvAJkN6URcZeKKaOZF5RZMRylQAwACgeK/8FAf2yv2f/ih4C8O/syfsp/C+y07wP4TmZ7bWL3TNt1LLkr/o7OzSJE4w7vJiWVtu4Dad3wnBHC1aGcZTQq4bHKphJXmqvs4Yei1FqThNU71YzltGMryTvKWmu9eqnCbTjZ9r3f8AkfJ9XPDupR6N4gsNYlEhW0vIpmEMmx8K4b5WwcHjg4OKp0V/VU4xnBxezPJPvb/gu3bya545+GXxNsHkfS9Z8JzJZvvymVlWXIGOpWdMnPIA9OeB/wCCJ/hzUda/bgs9WsxL5OkeG9Qubso2F2MiwANxyN0q8eoB7V3XwR/bd/ZH/aS/Zn0b9l3/AIKEf2pDeeHpQmieLrW3c7Io02Qu0kO6RZgjNGd0bI6orMSxrbuf2wf2A/2DPhV4m8M/sHXWq+I/G/iKzEUfia/tnkjtmBIRpHnSMYjDu6pHGVZlUPxyP5spy4ky3gKrwLHLa0sU1OhCoof7O6c5u1V1dklCWqa5rrZX09N+yliFiOZW3t1v2sfHv7ZXi7T/AB3+1f8AEXxZpTyNbXnjC/aBpJN5ZBMygg4HBA4HYYHOM15pXv3/AAT8+JH7Kfg/9oKfxZ+2j4d/tnSrmxmNpealYtf2sF6zAma5twrtPuXeAdr4ZgdpOGTjv2wfE3wB8YftDeIfEP7MvhiXSfB9xcKbC1eMxIz7R5kkUR5hiZ9zLGfug9EGEX9pynH1cFmkMgjhKqp0aMGq7S9lK1o8ile/NbW1r6O6Ss3xTipQ9pdXb26nq/8AwSV/Zph+O/7Tdv4z8UWit4Z8BRrrGqyTD9286k/ZomPu6mQ54KwsD1rgv2/P2lp/2qf2nNf+I1pdtJottL/Z3htCeFsYSQjAdvMYvKe4MmO1en+Bf2yPgL+z7/wTR1z4SfDHW72D4jeLr2ePxXPd2HlJa2jcSSrPynlfZ18tRu3h2dyqjBPxKvxk+ELkBPir4bOemNct/wD4uvmsno1MXxtjc9zVeyVP/Z8NGp7r5ItOpVSe6qTsoyX2Y22ZrN2oRpw1vq/0XyP0/wD2V7/wB/wT4/4Jvj9tXSPCdnrfjzxrM1lp1zc+YY4g08iRW7cqVjUQPK+zaZGAXdgIy8N+z7/wWr/aTg+L2n23xxOj634W1XUY4NRtbbSEgmsYXbaXgaPBbbkHbJv3BcZBO4c9+xh/wU1/Yn8Qfsy/8MS/toatBqPh4XZ/sXWdP1JJxBEZDKquIn86No5MlHjD5V9pUKp3eg29t/wQt/ZYuNM+O2r/ABm1rXRa3qvoVhq7z+Rd3cZDqsYe3gjldSAdrybP7wIr8jxv+rVHMM2p8S5ZVxmKr1ajpVYRVVOk9KMadRStScFo9murey64uo4w9lNRSSuttet11PBv+C4X7M3w/wD2cPihr0HwysYdP0jxT4KudVXSIGfbZzMJ45QgbIWNmTeqg4XcygKoUV+Is1vMq74du77rV+sn/BUj/gob4C/bQ8X+JviDYeLdNsdHtPDFxp/hrSbjWoJJlgEch3sqMR5sjsWKrnGVTLbQT+UckyTWju4+Rf8AvqvzDxhlmNPJshoZjVU8TChJVPeU2nzKyk03eSVk3d3aer3O/L+VzqOK0voU7PT3mkPz7G/j/wBqun8C+GbrVtUi022Te7Ovy/erC0eJJPn+7/F8v3q90/Z48MwtcjUprBnb7z7f4VX+LdX4TiJyp0pXPbw9P21WJT8Sa5b6Pp8Vgk0bvZp8/l/wrXk/j7xdc65Jt85hDG3yba6r49al/ZesXFjbTY85md12/dX+7XllxeJdRNt3Y+7t/irmwWFjpPc76uKlT/dn6ef8G/Pxavvh3458QajaWE00MGkfariTz9v+r+8qrTP2wtJ/aB/4KJftXTfFfx/4buJfC2jxNZaXpNnudLGz3f6zb97dI33q+e/+CP37QulfCL9qLSdP8Q3VnDp2oBrW8W++6yt/DX7R+HvFnwd/ZMste/aS+J3xK8JaL4L0pLjUPKSeMz3m1d0UMafxfN8tTSwl8zcXufreR43J6WSfW6qvUhH3f8j8Xf8AguDceHvhr45+H/7IXgPdHYeEfDMes65DG25f7Qul+Xd/tLGv/j1fDW/d8mzc392vU/2rv2mL/wDbA/af8fftIeIdPW2HjLxBNeWdqv8Ay72/3Yo/+ArtrzC4037O29/+AV+hYOjGhQjA/C8+zKpm+ZzxNSWrC3Z2X5+v8dTySf6xPl2L9yoY4/3ex3w396rG1/4NrfJt+aurlieSNXZuXYjfe+dmrY021eWFk2Lj+HbWNJN91Jkwu7/gNdj4P0lL5VQr8zfw0yJe6ZN5Yzww7/vvt/uVom4+x/DvVbn5d8dvub+Fq2te0V41/cpu/h+9WT4zP2X4S6mEh5by1bd/D81ZyKpnlEep/Z4mvZ5llmb7sbVd0+SZVa5cfeffuasKxtZrqUMseRW62+KFkz/wGg1+E7f4d+Ptb8J6tBrGg63cWN5ayq0Vxay7W3f/ABNfdn7MP/BU12mh8MftIaas8TMqReJLFfnVW+VfMj/2a/N+x1SaFldE2stdR4f8RTLCN/8Avbdm6plH+U1w+Iq09j90tB1vSvF3hu28YeDb+G/0q4+a3vLeVWVv9lv7rf7NSyTTR3O9zIiMm/cv8Nfkz+zX+1l8YP2edSe8+GfiFYra4+a8028XzbSb/aaP+Fq+pvhp/wAFWJrqaHTfip8K7X7NM/m3F9oNw0bbv91v4f4qX1iUdGj3cHmFCMfe0Z9htffavuQ/Lt/hbbWBqVj5ly+9F2fLsZpfmaofhz8X/AHxq0GLxF8NPE9vfpJ80Vm21ZYf95avSRvJCLZztk83c21Pl/3azrVos+owNRSipxkV9Nt92zybZY2b76r91q868cxovxPnijXj7XDgE9PlTivVNBtZvtSQfZpNy/Lub7teZePFeP4uyhhgi9t+q/7Kdq/X/Be39sY9L/oGqf8ApUD6fL6/tKko/wB1/ofmd/wUi0v/AIRv9qLxBd20OwX1lC33Nv3lr540rRrzU50jRGYv83ypX2p+3R8HfEnxs/a+m03R7Dzo7fSYV8uFN25v71dT8Gf+CZ+q6W0Oq+PYfscEn31+8yrX5VTgvtH4pm9aNPMJwXc+QvA/wR1vXJoXhs5m8xtrMqfdr2/wj8CbPwtYrea3/ooVW3s33t1fUXi7Sf2df2edGmRPJvJIYtqxyfI33fu/LXxh+0J+09N4o1Saw8PWy21uv/PP/wBBqpVI/ZPN9nOp6D/id8StN0WH+x9A2rt+Z5P4q8c17xJLqFyzu+//AHqx9W1q51SZnvJmZmb7rNSRq8j/AO03+392op+8b8vL7xN5010yuif8BpWh2wt3ZqmsbJI4w7uy/wC1U81qir02/N8jVRPxe8Zd1Dvfd977vzVJ85I3sodv4anmt4Vh2bF2/wDj1QvIki/+PPS+2VKMSNlO5v8Ae+8tWYV2zb3Vcf3lpkaom5U+633P4qtMx8pMIv8Ad/4FSXuy94Udje8Pyw3MCo/8P+xV6exTzNkJYLsX7tY/h9d1xsfcxb+61dPb2bpyibv7rK1HLGQ5PlM6xaSOTe7sqf3Wb71alncPHdfO7Mjfd/2agnsY2kV03SM33l/u0jW7rIH2Nt/h20fCTHmlA6/TptNmj2Pc7mX5nXZXlfxskha6RLbjc27bXVWupTWbbPOYGuF+Klx9ouYn3/71OPMVT+I5BPvCu88D332XQ5nd8FU/hrgq6jR5vsPh65ldP4dtEo8xrU2Od1Kd7q8kkk+9vre8G6bPNMjJ/wACZv4a5+CJ7ib/AHmr0Lwvpz2dj9p2fw/dojsKp8Jf1aVLa1CQvjctYyxwzN8/K0mtaptkaJPmLNurPt752Xe7/Lup/ZMeX7R0FvdQpCqJ/D8qN/FUsbSXUmdn/fVUrFXmVT5O2tyxtvs8fz/Lu/hWlGH2QlV5S7pOmpHbSuE/gavPJ9Wm8M+NHmhm2rv+Za9Ek1ISN9jS5UL/AHf4qwtH+BHxd+MXi6LQfhj8OtW1q+updsEOn2DSyTN/sqtVKIqcoyPpr9jj9obwj4HmvLDxhKba11ZI2S+VWdYXjD4VlVSSG3dexHvke2R/GH9lLVr+S8XUNCnuZmLyzNojF3Y9WLGLJPua6b9gz/g2G/4KA/GfTIdY+MOnQ+ANEuHV0k1yfbc+X/1xX5lr9Hvgl/wam/skeBraGf4nfGbxRr10sOydbHy7aNm/8eZq/TOHfFrOeHclp5WqFGrTptuPtIttczba0klu272vra9rGM8JzzumfmI3j/8AZhkh85xoLJ0DHRePp/qq9D8JeDR8UH07wZ4O8JHXF1ZY49M0iz08zfaFIBjVIQpyMAEDHGO2K/UyT/g2u/4J0NJbFIvFgSDbvj/tv/Wf+O/LXyx+wv4P0L4a/wDBV3RPAHhpHi0zQPG2s6fp6yuWZIIIbyJASepCqOe9fqPB/iZjc/y/Mq9TC0IfV6MqiUItKTSk7TvJ3jpsrdT7bhDCOng8wTe9Jr8JEHgz9gD/AIKeeE/CX/CKeBPhb4u0bRbhNz6Rp/iSG0gYEdGgW4UA+xXNPtv2Bf8Agp/4dvW16x+HXiuyuUT5ryDxZbxyBf8AeW5BxX6t/F39qv4b/CK3P9vazGsm/atfGn7U/wDwVv04eHLrRfh5f2s1wZZF3LL8zR7fu7f71fk1f6RuYUk1DL8K/wDuHL/5M8jA8JV8XZttL+vI+Ividpv7VWuasfhr8WPFXiHWLnT5g40nVPFP24QSYKhgpmdQcEjI7E1+nH/BOH4S6J8JP2ftD07xd8SYZ3RZZvsvmCNIHkkaRoypJzgsRnvjOBnFfj54i/a0m8J6hc/Ga5uYbwX11Ikscy/6THJu/irFs/8AgqT4ztbyO2sL+4jRnZkVW2sv+z/tV+ecb+MnEvHGVU8txOGo0qMJ8/LSi43lZpN80pbJva1763srfYYHg/AYWTlSqyUmrcztovKyR/R5B418HwKlomsW0ny9pFNc78TvC37O2seG5/EvxI0HQprSzj81ry6hQFQvo33q/Cr4S/8ABVHxnNcW1lrfiS4V5rqO3gj3MzNIzfw16/8AtOftvfEvwHotnpXjDUo5XhiW4TS7iJpFmbbujZl/2a/MqWb1KfuzpnYuEKcZc1Osz7y0f43fCLT/AAZe/B74ZWt14Z0zV3kS3ubOVnut0jfeVW+7ur83v2j/ANnj41/sMftTXfxd+MXiS38Z6P4gtW/4QjxBq1vtttNb+Lz4/wDn4VfurW5+xT+2xpXjjxY2sa3eMbi4ut3mMnzR/wC7/dr6p/aUvvg1+018DtX+AvjCdkttQ/fadqN7tlls7xfmjm/76/hrhp47nlKNZ/4fI+qw2AlgpxlhvhfxefzPz1174ueA9e1a88f+KvEk1zPqC/uLrULpnvL7/dX/AJZx/wCzXl9n8Rpv+FlQ6r4A84W0zsjMvyqy1698Cf8Agk74z0mbUfiB+118XdPs9Nsb2RLVtLl8+W8j3bo/L/hjXbUn7R3jz4LfDmzTQfgD8E76+TR4Ge41S8ibc3+03y1206PNFa83MdNbMqVGteH2e5Mmm/FTS5X1vxJqSwwMi+RC3ysyt/EzV86/tGfEzXrdryCz1hXdXZd0b7mVa9W1LxN4w+K2i2sPijxzefYJrJXSz01Vj2qy/L81ZGj/AAA+C0dxFc3+iXl+6/LE2qXrPub/AGlX71d8MjxMve0R8niOJI+1l7OVz4lvPiN4q+2LDC7YklZf3KMzSf8AfP8AFWjbt8TtcUPpvgzXLtZH+9b6XM3zf981+gPhXwj4A8Jag03hvwHoth5nzOtvYRqv+y3zV00etXMby+TqrRLt/wBXb/Km3+KvYpZXhqceWR5VbHY7Ee85H5wN8Ef2h9S8nUtK+D/iS88yX7sdlt2r/wACp/iL4S/tUaPH51/8EPFEUUe3fItluVW/h+61fo7NeXlzcD55pXjT+/taobi+vDCUS5uFXr5fm7f/AB6r+p4WJnGtjPszPy+vrj496PeJDeeFPEln/wBM/wCzZG+bd/u19Vfsp+J/GviPwLcR+MtKu7VrW6CW32yDY0i7eWx+Ar3bXPtLrNeQXLYb/W/PuZv+BVyFpuN7cyMWILLhn6nrzX6V4NYShDxMwVSO6VX/ANNTPpMhxWNjifZVJ8ylf8Fc8H8f6Vb6X4p1ee3yTJqcszMDkeYzN8v5EVxGpYM/z+Xhm/hr0b4uW0za3qDEzAG6bH93Ga87urWaaHyfJ+b+Dd/DX53xJH/jIsU/+ntT/wBLZz4uUnOXq/zMC+s3mco7sy7/AJ/k+as24s9rGzTzPm/h/irrxpe5lfYqj/po1TLoO1mSHan8btt3K3+zXBTqR2PnMRTlI5X+x08svv2bdv3qaunXMbG5mm3pv3J/FXeWPhl5YXmmtm2bN3yp92kbwjcrIf3Oz+L5l+9WntoRkc31WUoKSOMsrF0jhd3bLfNuVf8A0Kr9vo811MEhdtypu3bN22tubQEb5NjKGWpF059yO/y7vllVflpVKkJS94ujRnExV09/7/8AHtfzPu/8Bp/2F23zTJsRf4mSuh+x+X5UL2zbG+R2ZPu1Jb6Hc3DFPup91q4KlaEo8qPawuFn8Rg2envb7Psybov+ee/7v+7WlYwQsQwTD/Mvlr97/gVXLfQ4ZIfMdGX+H+6y/wC7RHbvbs88Ls6L8vlt8rNXBI+jwdOUR9vCW3zOjDbtZ2kf7tOuIXW1cuNw/jX+7Vux01JpvJ2b/LX51b+Kn3Gn+dZiHY0Qb5vlqeX7J7NGnzR0OaurF2mKImxFi+9J826siaz/AHgld5Ei/iWN/mautbSXaPZM6n+Gs/8Asl51dHeMBVbbXRRlA8PGYOXPzM4C11IzXDed8pb5k/urW5o+seYyo9+wH8Fcku9pN7vmTf8AJtT71La6k8fz71xX2EJfyn5BKPL8R6xpuvcFPOVlZF3+Y+3ctdz4f8Q2ybZkmZo2b5WWvDNC1nYyeT8/95pH+9/s13Gh+KnXc/n4ST76q/3WqK2Il8I6cep7HpmvJdSK+y4cs+3y4327f9qt/T7xNrJcozOzfw/xV5Z4f1y2lX/XNlX2/K1dZo+tM0eyG5YOrr5sleTiMRPWCPcwtP4ZHb2mzkzQs5mX+Fv9Wq1fhazaNd75ZnVU/i3Vzel6k74hS/8A3bff2/xV0ujzukZd3X5v4V/hrw8RufUYXXc1Ft0aGO2eTe7ff8xflWrs32beuEZF/hbZ/wCg1UgkEcYdH2/N8zbPvUv9oeYuxH8xl+Xatcso80PdPToylza/CZWpx2crN9mTj+Ld97/gVc3eW9nawsiTTZV/4vmZv/sa6HUrzyYVm3xn+KX/AL6rB1a8hVXmmlVmkl2p8v8AF/CtEf7x206kYGVdM8OLnzl3Mnz7vlZV/wBqszUJJ5rX5J98X92tS8+xpvmT55pPlf5t3/Aa56+kmkjdESRdv/LNaz66HqUcV7OZ2ukBIvARCsSq2koy3turgIJJmtTcwOvzP8m77u2u+0qRH+H7OCxX7HNyep+9XmU0bvtRH3fP97f92v3rxnhKeQ8Npf8AQJD/ANJpnVPMZYRp9zoLFprGFn+3rs8pWZtm1a1rWOG4zJvyyv8ALtf7q/3q5/TZvtMiQv8AMipt2tW5Z/uLlLx32wr/AAtX4DKM+blOCtmntomlYyPCG3jeqv8AIv3VZa0VsUmZ/nZWkT5P97/dqlZzQ3C+dC+NqbmVl/8AHau2sc0g2O6yLIny7k+Vf/sqXN7usjy5VOaRPb27x7NjruX+L+H/AIFSHT0m2wwpJhW2qrP8q/8AfVXrDTLm3gRNi/K3977y1qw2dtcRibZHvZP4v4a56dYytzfZMRtI+1Mr+TIFb7zb/wDx2thtLtmjj+zI2xflT5PutWla6L5bRvCilWfdtWtKGzkuLcW03yfP/q2f/wBmqeaMmk5Fxo+5zSObXTZvsYWZ/MG7ay7PvU29s4dNs2d9sSKrPLN975dtdCump88MKK6N9xWf7teeftReLD4F+Hd48Lq8twqwRRr/AHm/+xruoQlWxEYHNi5Rw+FlUfRHkln4k/4Trx7rGpbFW3tbVktfOuNy7dv3q+dfGmoTaB48a5SZQs0zI7Rvt+Wux8D+NE0PWNVsIEWJLi3VZZF+Zo683+L0iXX+nwo2/czK1fpdGn7OjGkfj1WpPEV5TcjM1jVJLy4vNGm+XvAv8O2sHS9chjmbTbybake7ZVG41aa8VLxOXX5XXd/drnteuJluH1KB8Kz7tu+tRR/lL/i6NzcS3ML7g38NcfdTPdKUf5TH9yt268Rf2lpOxNu9fuVzl1Huk3pu2f7VHvyHEv6PdJGrQ3L5Rk+6v8NVJLhIZsmZvl/hqKNvs7B9/wAtMnBlcuE20FlopDcfvkf5f7tVriNFZvKTaGqOKV4n21Z+1QyITs5quYPhKW35s05PvClk+VmSm1RXxCP901ImSy1G/wB008fIyf3anlCRr6e0a437l/vMtWZFh+dN7f738NVdNb5dm/duq1cyiSEp0VU/hrOUp/CZ+5zkEkkbbtn3qj85Gbp/wH+9SPOnl/u3yf8AZpi7Np+fbVFD92z7gxUVxGjSNIU/3/npzbNuzp/tU/anlsjv/wAC/vUE/aKkzfvOOPk/76qu/wB01Zmjzl/u7aqfwfjTj7pcYj7VtswOauTWs0kn3/vVTsXzcL8ma6RYEmtg+za+3alVGMxS5UYFwkiybJui1C0bL9zpWtdWqeWibMP/ABLVDy3iIx12/PUC5j27/gnAhH7W3h8t1+yX3/pLLXr3/BS34y/Fj4b/ABZ0LSvh/wDEbWNGtpvDommt9Ov3iR38+VdxCnk4AGfavI/+CcygftbeHc9fsl9/6SS12v8AwVjx/wALr8OFv+hWX/0pmr9zyfE4nBeCWLqUJuEvrS1i2nqqXVanFNqWNV+xyHwH/aF/aE8V+MV0/VfjJ4iuIlhZmSXVpSCdvpmvY7/4rfGmwjW5HjnVJUQZfF6/6814H+yppqXmvX135O6OG1Xd/e+Zq+gVs4W2xp92RG2K38VfiWN4mz6ElbGVf/Bk/wDM48Xyqpoj7g/4J8+LvCfxP8G2R8ceH4NSvA5jke5t1keRgvQ5HWvtfw98CvgvqGnxNc/CnQmnfh0TTo+P0r8q/wBiv4np8M/HEWgvNNFb3E+9I/u/N/F81fpz4b+PHw38G/De58VeP/GWn6Pp1nBuuta1KXbFbr/Erf3m/wBmvWwHFedTw1p4qpdf9PJf5nl1FUlU5YFzxx8B/g7pMLsPhxosA2ZVVsEDH9K+U/2v/jt+yr+yjo6X3xNk0iwvJ4WMGg29sr30hH3Ssajcqt/eavCv21v+C6Wr+Mrq/wDhj+xtYf2fZSRNa3XxC1aBvtd0v3Wayhb/AFa/7TfNX5V+O/FPibxX4uvdf8X+I7zV9Qmnbz7/AFG4aWWX/eZ6ipxNn1aVli6v/gyX+Z6uCy+75qjPrXx//wAFNdc+IurzHwjp0fhjSYnUWtvCA1zIP7zyDp/u1na/+0n428W6BHeWnxV1fTNQj5R7HVJFikX/AG0zw1fIO98ZD45qwup38YCJdvt/368+pmXEPtLxx1X/AMGT/wAz1FhoxleKPoXT/wBoD9pnWIT/AGD448VXmDhpIb2Zv61U1D47ftgC4a1tfE/jHOcKVmmb+teLab8RPGujqE0rxNdWwX7vlS7avD41fFvem34haplfu/6W3y1pDNs/hvjKv/gyf+Ztyp/ZX3H6PfCm58Z+KP2LTN45vLy41m88Makt1LfMTMzEzqu4nvt2j6Yr4+8KfB+2haKF7m1kmZv9THPG0i/7TKtfVXwJ1DX/ABH/AME+0vtTvZ7rULnwhqwM0jkyO2bkLz69BXxj8JfBOq+BfElt4qv3k+0w/N5e77395Wr9W8YfaV8myCc5Xk8LFtvVtuMLtvuzz6FRU/aWetz7S/Yv/Zfv/Fvi6yeHSvtFusvzbW+Zm/2a2P8AgsdqFtdftDeGP2afDvmNpfwt8Mq10u7cralefvG3f7Sx7Vr7X/4JY6H8Pbr4Tv8AtCaqkNto+j6XNf6lJt+WFbeNpJPm/wCA1+cnijXtT+NHxC8U/HLxI7Pf+MvENxq0rSfeWORv3Uf/AAGPbX4rTj7OhdnHTqPnlVkeN3ngWa+0/fCjKY9uxq4vUvPtbiazmdkVX2vu/ir6D1DSYVXYHZEX5UjrkfFXwoTxpH5EP7u5bau5fu7f71clbBxxf+I9LD42cPi+E4Dw7dQ2tv52yRP4fubq+uP2Q/Deg+JtBks33STSKrL8m3d/s18neNvh54q+Gd5BZ+IYG8u4T9xIv3GX/wCKr2z9iX4tJofxJ02zvJo5LJZW82OT5dvy/wDoNfF59g8RTpuB9TlGKoVKsXL4TU/ai/ZN8aeIvGH9o/D3Qbi+Zkbda26Mzf8AAa5T4M/8E5f2iviZ4nt7b/hANS03TWlX7RqWoReUsa/xMu771fob4V1azj0C38VaVcRm+a4ZZfsqfL97cvlt/u1u+LP2irDQ47zXviR4wkt9I03Tftk8zRfu4VVfur/tNXJgs1n7ONOEfePpa2V5fOXtec+Bf+Cxnhv4afsxeK/hf+zZ8DfDFnpl54b8KLq/iDWIVX7TdXlx8v7xv+A7q+M/iF8Y/in8ULK203x38QdU1WztW3W9pcXTNFH/ALq16B+1H8adb/ae+OPiT4161JIF1S4WLS4bj/WQ2cfyxL/3z83/AAKvJ5rU28hfZuTb8lfo+Gw0XShOovePhsRjKsas6dGTUH0Es7jawRH4/wB2r7SPJGA7b3/g21mQq8M2/d8rP86tVy3uETMz/Kn/ACy2128vunnSkS28myb98i71/i30s10NrP5NUdUZ4ZEvPlZPuvt/hqBbnaQjzMf760uYZr2snmSbH3K/91q9l+Degp/Zb6rcpt+Vdn+1Ximh3KXEyJMfuv8Adr3v4e+Rb+FxMJtz/wB5qfLzGcpFLxhZpDdvsRpUXdvjVvmriPi8ws/hvJZ/KryXC/Ktd74mk8yMvt2p/e/2q80+Nl0kfh6KL5t32hV3N91v71Eub7IoL3zgLKKHT7Vf3eX27qZNdJcfP/C3+1UdxIjRqibm3Lu/3aqx3AZv92o983j8RbhkRlZ9m0fx1qWN1ux5U3y/e/3aw47j+NHbG+r0Nwn2dE3baA97nOw0HXLm3uAEmZVb5dtdz4f1yFdsaRqTv2srfNXk+m3STTbAjBdv+sb7q1q/8JhDplwn2BGeRf8Al43fLuqvdKPZ9P8AFlz8P9Qj8Q23iG60qeGXzYri1naOT/gKr96uv1T/AIKkftSyaOmg+HvG1udq+V/al1YK9zt+7Xy42sXOpahLf6lfyS3DN/rJHrc8O2v22ZX+81R7GlKV2VRxOIofBKx6Bq37Q/7Q/iaZtS1740+JJZW/5537RLu/3Vr7L+BHxF8SW/7PmlfE3xHdTazqNjp095K17MS1yYZJCqMx5wQgXJ7V8H6tdWtisNtBcqWk++q19qfB9Fh/Y6jWZyqjw5qG44GVGZ8/lX6/4NU4wzbHJf8AQNU/9KgfacH4qtWxtdyk3+7lv6xOQuP2zvDFn8ZJPip4b8NzRLeRRxPZ3EXzW7fxf71dH8WP+Cgm3QWtbDclxNE29tnyt8vytXytJ4i0qzXZpqb9vG5vvf71UL64sNcVvt9t5is+394+2vyH2cYnwlaXtqvPLWRzPxi+PHiHx5qjzXl9JJ5m7f8AvflrzS5vri+m86R2J/hr2K8+EvgnWbX5JpLQqm3dH81YF18C9Y0+YPYOt7C3+qWNNrVUY+8HwwOGsdNubhRv+b5vvVtaf4f8yRcv92u20f4SaqrLbJpUxO/7qr91q1tN+EevPcNbx2DBv71b+zI9p/McTFpsNra/Ii4V6z9UmRV+R1WvTrj4FeP75fLsNKZg393+9WQ37NPxguZFR/BkjIzfPN5qrtX+9S5BRrRkedXMe1TvfLN/eqFVTn/vnbXsln+yD4tkk/4mviTSbBNqv5lxeq23/eq237N/wx0dvtPiH4tQv95mjsbfd93/AGqy5YfCXzfaR4psc/3dq/LV2zt3WP54WU/7Ve1aX8KfgCyqltealfTNKrRL5qqrR/xfL/er1P4f/sm+HvHV8mm+DPgteTNcS7Eur64ZlX5fmZv4VX/eq40+Y55Yjl3PlLSLe5hbf5GTv+9XW2du81uj/edl/hb71ffXh39mf9mb4Q6PPbeLfhjpvibxJ9n8q1jVma0s22/eb+81YWg/s2/DTVNY+2ar4YV3ZVaXTbOLYka/7P8As1XLTM/b1f5T4l+yvaxrv3Dc1MjiRbrY8O4/d3fw1+iUP7PPwKtbo2z/AAl02K3hZW3KjeY3y/MrV5t8WvgV8H/Mlu/CvgOFIlbbLIr0/Zlyrcvu8p8V6hYoreckLNt/u15t45mM15sHRa+7dD/Zl03XN7p4VWNPmZZvmVWrTu/2KfgtY2Ym13wxb3N20W54YWb5qXLHlCFbll8J+dWk2JurgJiui8QWM9loax7P9lttfeOk/sE/CvVNUhmTwfDZwSL/AM92Rfl/2q67w7+xP8AdJ86HUvAcepvv3RW9xKzL93/x6nCMf5gljJSlpE/NDw1pH2i6R50wiv8AN/s139xZXjWYs9MtriZ1X5Vt4mbdX6KWXwf+FHhqFE0H4N+H7OX5lVZLJZG/3vmrpPDPwjub6H7Xc6bp9nDbory+XbwxxW6/xMzKv3aUuWOpP1iVSZ+V0fwp+KniC8CaV8OteuVk+55OlyNu/wDHa+ov2Vv+CFf/AAUc/an0yPX/AIf/AACvrLTJuftmq3C26/8Aj1fof/wSY+Cz/wDBRb9py/8AD2l+cnwt8Cyq+rXkabV1KRW/1at/dZlr97vC3hHw94K8P23hnwtpMFlY2cQjtbWBNqRr6CuiNShQjdwvITWJxWkHaPc/nY+EH/Bod+2jqzw3fxL+LvhnRIpP9bHHK0zxr/wGvp/4ff8ABoF8GbfT4/8AhYf7S+sveNFtnfS9OVl/4D5lfs1swPljH4GuR+HPi9/G8Op+I4Jt1m2qTWthhfl8uFtrNu/2m3Vnic2nTpuUYRj6L/O4U8opuXNUnKXz/wArH5zfB3/g1P8A2Dvhx4ng13xx468UeKoIJAyafcNHbLJ/10ZPmavvX4Ffsn/sw/sv6RHpHwK+Cvh7w3DCm0XFjYL5zfWVvm/8er0jc3c1ka1bzXnyIjbPvNXxONzrEyd4HuYfC0o+6WrrxVZKjGGZWEf3m3VxGv8Axshs5pIIbmNpFbair/eri/j78QrfwLobusjIkcTO23+HbXyav7V3/CG/b/GetnfbNKrQW7JuaT+LatfPVsdmGIu3I+nweWUILmlHmPtPWPjVcaP4fXWtV1FbTzpFiiVm5aT/AGf71fkV8L/iI/w8/wCCiF58Rb66jZrLxrrU0srnarlvtQP0BLfrXtmm/tbeAPj94ulv/i1qt94ZttPv1ntfMRl/4DHXy7d3/hu0/ae1zUb7Fxpa+ItUfLHIkj3T7Sf0NfvHgxUqzyHiNT/6BJ/+k1D6zJ8NTo0a6jFK8X+TLn7fX7bt54k8VXdsl5NbPay/PCu7arN93/8Aar4q8YfFabWGW8m1Jre9mf8Ail+VvlrR/bi8babq3jee5s9RZ0kddkkdxuZVX7q7v9mvmjVvGk0l0yJc5C/d3V+M08LSlC6PJWIqUpcszsPG3jrWPFXljWLyQXML+Vu+6rL/ALX96uKuPEGvWEjQxw+dubbEyv8AMrUxfEH2hvJd1DyP8rSV9mfsd/8ABHzxd+0P+z4f2tviz8aNB+GHw4S5YWviTxLbtLPfhflb7NAv3lVvl3NW0MLSStI9KWMoRjF31Pnbw74R+Iug6LZ/EL+29N0prN1uLCS4v1Z/l+b5o619H/aY1X4xeJtXPj/xlcX+q3Uu9Fkl3Ky/d2r/AHa+mr79i/8A4I1+HrBf+E2/bk+InjL7KzLOug6dDaW03+7u3Mq1xnj74I/8EmvDscWt/BaHxRDeKrfZb661xpG8z+FmVa5JQy2Xxz947q1XHxpRUIWj5nI/Cfxd4q8I+KUfw9DIf4W8lNv3q/RD9iHXtNsdcitvjxpv9sahMm+10u8bbHa7vuSN/e+X+GvyQ1T4gal8NfGe+bW5r+2Vma1uN33l3fLur6r+Ff7cXhXxVr2meMUmaz1lbCO11L7ROqpIsa/Ky15mKwtOPvRReFzD937Pn/xH7YfDWz0nwt4rstW/4QzSr/QZv3U9g8XmNbq3/LRd33q1f2k/2RfAPxH00/EP4f2dr9ssoma40m9TbBeQsv7yP5f9mvkH9kP/AIKC/Ca/8PC78R+KYb4WaM0sfn7YlVfvbmb+Kpf2af8Agof4hvv2ltV8H+Jri9vfCeu6jI2mwPLtW3t9vyrH/erLC46UI8jiRmWUyrVVVpz+z9/kfAOuX2ifCX4i3nwZ1vWI47631SZ9Gs9nl7rVpG2qv97b92um0u8t1VIf4tzMjM38VeWf8HFfh/w5Z/t+WNt8Lbq609v+EZtdRtVtfla3aSRv/iab+zn4i8bap8MtMvPHepefcqyq8yrtZl/vNX6LhZVqmDjKfU/Mak6dLGTproz2qLU5+P8ASVk8xP3qrF92ry3k1qoPksHk+V137VWuVs9W+zzboSu3Zu8tU+8v97/ZrX026uZLrfvaRG2ruX+Fv9qrlHl1O+nW+wdXp+9o2h+0szfL93+L/Zp+5JJAknnRJJuZFb7y7W/iqhpa3ir5T7Y1jbc/8Tbf/iq2Psr3G3fPvX725krlqS5Tvp1PsmNrGmw3EMyb+G/iWuRurKSzuXDmT5mPDnvntXeTWv2WN9m3Kt8ism1V3fxNXL+LorWK9C2YITc2cSblzx92v0rwYd/EXB+lT/01M9vI3J5lTv5/kzxr4i6Ib7U7uEkoHLEqDgcn71cJceHUtWebfkM33W/hr3TxV4VN7a+a0bASKHJ/2d1ef+JvCqNM3+hqkf8AeZ6/L+J6kpcQ4yP/AE9qf+ls1q/xpX7v8zgE0lGV32fOr/M3/stWbXT7mE+ds3rtXcu//wBBrebQUMizTJ86ru+X+Jakj0Gbzt/k/Lt3ba+ejU5dDhqR5veQ3SdJhuFebyNrtt2fP96rS+H/AC1WZoVmC/dZX+9WvoOhpayOk3ludu5V/u1uaf4TMcRhm01Sjfw7tu3+LdSlV5ocxtTpy/lPOrzw/wCTF5zo22RvuqvzLVJtBuZJNj/M+z7zN95a9R1Dwj8yySIzBdzfN91qzpPCaNIkiIxH3dqp93+9TjWnL3WRKjLnsonCLodyrjy+qv8AxVdXTUt2CTQ5RV27o/mbdXSyeHYYwiP8zMu3b/E1WbPw7IFWb7S25V+dmSsZSh8Uj0sNTlzcpyseizSQtCiMq7/+Wi/d3VlXWl2cbO7/ACqv8Lfe213WqaXeMuya5XYvypI38Vc7q1vctJNtmjKqq72/2qzp1OY9yjHlloYJXy408v8Ah+ZP722pGuJo5tn2WRxs3fL96mX023Z/Ei/M7L/eqH7Z5x+020i/L9xd3zba1jKR69GnGQjTf6OEKSB/vbZP4Vpk1mkK/wDLNmb50/2qYs1tNCNiZWNNqbqTzIfOyj/dXav8TNWtP4jjx1PqeXarYPY3Don8Kfe2bWrFmkdt8aDB/wCedepeJvCvmKs+xV/i+X71cdrPhSazk85Nv7z/AGa+kp4jofi+Iw0o6nPaXcTWbb4UY/Jt2/71dZouoXTRh9+7au3aqf8AfVZEemzRMu/aGZa29JsZo5UtYUx91mb7v+9RUrHNRpcsveOt8PyQxqtzM7fN8u1W+7XbaTqWJPkdn3J97+KuA0uxeGNnjfzv4krq9Nvfs0Pnb8PH99VrzqnvS5uY9nCx9n7x3ei301nt3orf32rr9C1hLhV/1aLs/i+WvLrHUoZI0S28xTvVvmetqz16Xar3Lw7N+1t3yyM38NcVSjKUz1KOI5T0tdWtpoW8lJBHu+VlTau6o7rVEWb55tiN9xl/vLXJaX4gmaN3d22fdRo/mXdUOra69vdb/tPzfwNG/wAv+7trGOHn3O6OK5o+8dBq19Gsn75+W+VG+9urIvrx5DseZif7sf3d1Y114mc5+07W/hRf4qo/29bTb5EdnKv8m37q1UqMuX3zT65SjLQ0by++aWGb7yt87fd2rWRdXkMz537Sy/eZ/wCKoNS8QW0K7/Ok+b5fLb/0Ksu8vpmb7iu2/d83y0/qvuxKlmUUeq6C0k/w43eblmspsOQP9rmvMVjdmEMKLj5VlX+7XpPhlwPhaJC5IFhOST1/jrzyx3tKPkV0/ut8tfuPjGpLIuHEl/zCQ/8ASaZ3ZpiEqVCT6xT/ACNXS1+zqET5nZvmZvm+X+Gt2xsz5becjCON8o2/duasfS3RYfM+0qkv/PNvvNWrDLCsyQu7O0L/ADf3dzV/Pcqkuc82GK5ocpsaT+8keHpJHtZ/O+626tuzCXClPJZJWT+F/lWubtbya3VU8jO5tyVehuJPJ/4+WZ1b/drmrU/3vOduH5pSlI6G1uob6PZ50Z3ffVvvLtrWiurZdttNbbH3/wAXy/w1yEN+8kkWy227f4fu/NWtZ6s65TyVfb8qbn+7XFKnKPvROyn7szrLW4hk2wj5Ek/hZvu/7VasLW0zb4PnSNNv95q4iHVkhZnM+f73ybm/75rVtdVdXR4V4Xav/AacYx57m3N/MdPH8reS8ypGu7bJInzV8n/t6ePEvPE2m+A0dcWe28umVPm3fw19G6n4kTTrW5uby+VGWJnRvK+VdtfBHxa8YXnjDxpqnieaZm+2XTfe/hVflVf92vqeHsL7TF+1l9k+T4rx31fAxpR+2clpmvFfE1xamZYkuLdk3NWD4uuHkhe2fkxqqvVbxRffYNUS8875f9ml1TVIdQt/tj/P5y/Mtfe8v2j82+E88m1AafcPDcrwrttVflpl3B/aFr5Py7WX7y1L4s06PdK6bUXf8n+1WNp946/upvl2/KlPlQSlMz7q3urHd2RmpkkjzbpFdvmrW1S3+1Wp2P8AN975awnieBz6Uy4/CEgKBlxTJJE28VMpWQh/mP8AvVHPCit/8TSlIqPmR7fMzv8AvUwllb56e33zs+7Ss26P56UTQbTWV2bpTqKctgCpGj2hNn/fVR1LJJuVS6YK0yJblzT1/ds+/dt/hq55iLjZDlf4kqlZyJ5Owp81WtrrIQj/AHan4jIim+Vm/wDHaZJIm3Y7sp/u0sjOzb6Yzbmx/F/eqTQfHJwqJ/6DToIYWVqjSR4+j/dqTzn8obP+BVfoZy+KxHcbVjLtxWezbqs3zlhhvl/2aqnk5NL4jWmPgO2ZCP71dhb28clur7MfLXGhtrq5/hrs9JndrON0m3bk+61UTWKl1b7lyn/fVZslt97ZBuNdFcwusfmPDtrLuFfcdibaDH4fiPXP+CdUZj/aw0BXAP8Ao19tI/69Za7H/gq+qn40eHGIJx4YHA/6+Zq5X/gnnE6/tX+H3f8A59L7/wBJZa7L/gqmm/40eHe3/FMD5v8At4mr9lwH/Ji8X/2FL8qRg/8AfI+n+Zy37H+jvJoesar9mXYssaRSN97+9X0P4J03R7q087yfPuPvJ/D5deYfsg+A7aT4Nw6lczTRNqGqSbWjib94qr/er2XS9JttHX7NDYSSt5W7dJ/6Dur8FxFGUqtzgrc0q7scb401a50PxMr2G2B4/nRlb7tRftBfHzxz8btH0rwl4k1DZomiwK0Wkx/6uaZfvTSf3mqb4jaK8MKarqVmyNcM33lrz/Wr5I0SGzTG77y1hToe7bmLpxieeeMYbOC1mv0tlTy03LtTbXhV3I01y8rvuLOx3ete0/FRrm18Pzb5vmk++u+vFXh8v79ejh48sD1MPyqmMeNVUU5Y3kpT3/2fWpbeGRmDhcf+zVudHMyHyXLKnZq9E+DfwdvPHN8LmaBvs0LfOzL97/ZrO+Gvw51Lx54mttEs7OZ1kl3SyRr8qx/xNX2T8Jfgrf8AiDULb4dfDfT22RyxxXEirubb/eXb95qiXPKPLE4sZiZUz1v4W6Bb6T+yxH4d0dBGseg3sUKp0ViZun4mvk6TQX+2fYIUwscux5N25t275q+5fE3w/f4O/DrUPAcSSCTSdFlGJvvFzCZDn8WNfLnwt+GviHxprS2em6bIqM677pvlVf8Aar9m8V4t5Rw9f/oFj/6TTPKjU0cj6w+G/wAYNX+E/wDwSK8T/CLRHkTUfiF4th0G3bzV3R2O3zLuRf8AZ2qq/wDAq8Ek0m2sdL8iFFhWNFSLy0/hWvUvjF/YOg6L4Y+Hugozw+HdNk+0XDJu+0XUn3pP/Za80uI7zXJPJeFj8/3fu7mr8WjH20vdL9p0exz39izX14+yNnaR1Wu68N/DvTfDGi/8JJ4kh8lm/wBV5n97+81dJ8O/hfZ2Ni/iLW91vEvy26/7tcR8dviw8zP4b0p1XduX5f8Ax6lWxEMLS5Y/EKXK/Q8x+N3ii28a3klhDbedbR/OjbP/AEGvGLvUtS+H/ihP7Bm/eKm9f92vUraz8y6+0/Nll27ttcD8RNFe28QLfww7oZk2oypXku2I/ivmOqjWnT96J6B4I/4KKXvw68KDwn8QtE1K/aDdPZrZ3Hlp523au5q8p+Lv7Z3xU/aI+yaP4huY7LSrX5V0+z3L9ob+9K38Vcl8QNHS+0+Qwwtvj+ZN38X+7XncUz2dxt3421tgcqyylL2lOFpHtRx2Kr0uVyPT1ukn8v5GP+0qfLWdd2aNC29PmrH0PXJtvzu2G+XdW3HcJMrQ9vvbq9nmOSXPGZhXSPbr5LorfxJUc2yFU2btjf3a1dQhQR7HmVqzZInm/c+XsZXpy5hx194lhkmmj+yzJ8jfLWXNvs7h4XnUlW27v9mrLB47hfOf5VenapbvfW/nBF8yH/x6iWxcSx4XZFut7oq/PX0N4XkL+C7a6+0svmLuaNk+61fOHhu4f7ZG+z5m+XbX0Bodx5fgdZnfd5fzRR0RlymVSJpXkL6hYyo7r+7Xd9371eOfHiTy9Jtrbfs/f7mhr0iPxM62YT+KRN25a8Z+M2sXmoalFHN9xXZkpSJw8feOSjvJmjKO9RvJ82xxTKOCKfMjq5R63DxR7A9Wobh5I/nm2p/s1QTp+NPaT+D+7THyo1G1J/uJ8sO37qUsNw8u1Efhv4f4qzF+Y/J96r1jNNHJ+5g8x2/u/wB6szLlOkhj03TbUXl47E/wr/E1amk+Orm482HQ9HVVX5WauRnjaE79avMOv/LFW3NUkPirWBYvpWnzfZrVv9bHH/FV/CHxHb3V9pWiyJf+JL3zb+SLclrCu7yf96vt74LaiLz9hldSMW0N4W1Ntuc9Dcfma/OW11D5lcI3/oVfoZ8B3B/4J9I4XA/4RHVsAf71zX654N/8jjHf9g1T/wBKgfYcEpLGYhL/AJ9S/NHxXpusPdXzoj8yfc21ryLpmn7H1jW22N96GFNzLXAJqdyrDyXk/efKixpuauw0JvCvguGLW/HkK395J/qNB3/Krf3pm/8AZa/IvhPi+U6nwrpOuasq3Oiab9mtPNVP7S1K42r/ALy13eoX3wl+HLQ2Gq+Kpta1hdz3Cr+7trdf7qr/AMtK8M8RfFTxb4w1KOa/vMW1u6/YrGH5YrdV+6qrXOX2ralcXz3N5eM8kjbmap5plfF8R9J2v7QHgy3meG2hj+zq25o1+8zVUvP2sNH0Ni+m+G7eVm/ik+avnGK6mjjLo/zM1Ps7O81OZHSGRi38WynyzlpJhywPbNe/bE8Z3CyW2lTtbJJ91Y/l/wCA1xV98dPiLr0vkvqsy7vv7X/8dp3gn4E+PPGd5HZ6bokxaTbt+Wvqr9nH/gl74n8TTRX/AIw8vTrdZVaXzvm3L/Ftq/Y296RjKtTpy92J8v8AhvRfiX8QrxNKsIby7Mj42x7m3bq+n/2e/wDglb8afikyX+vaDdafbLt837VE25q+8/hD+zT8Af2S/Bdz4217+y7e2s7ffLeahtjkb5vvLur5o/bE/wCCziWsN54D/Zmf7HFNuin1Bn8zzP8Aajp81KHwmcVUre9ex6Rpf7Gv7LX7Mc1s/wATtY0+81WS33Raasqs/wB77rN/DXfah4g0258OjRPDFtZ6PZXHzxR6XF96Nl+6zfxV+Xvw5+IniTxZ8QLn4heOdZuL+9m+Z5rqVpK99b9pzXVsYLC8muES1i2xSK3y1HPVI9j7x9dQ+BfhFpOi/wBveKvFUKf3odu6Vv8AgVcr4m/aM+Ang2NU8Nw3V3NuVNzbf++v92vib4tftRa3qEkltYXmfk2xSM3/ALLXEWnjrX/Fmool5eMfM+bc396sv38pGvs48p90t+098H9SuHFzY3lt95Uh/d/vP4vlqfxB+0l+zfqGivYJo91EFiXz1aJd3/Af73zV8cW+nvfN/wAtMbfvK1al5pdh4d0s3Mzx/c2p5jfxVpH2sY3bJ5YylyntV5+014DXW7iz8JeHry20tdyxSXnyu3/AaJP2lvDcMcKeH9NkaeFtss00W7/K182trH9sXvlaVN/s7v71dd4R+G/iTxBNDbfvNjN8/wAv3t3+1R7OUve5glyU9j27/hfmpapH9ms4VQru3Rxr/rNzVt+E9Q8beJmltrCFlmkXduk3MsfzVH8N/wBnn+zbUfbLDY6qru275lWvfvAeh+G9Ls/s1hFbonlR/wCkN97dWkacacfiMZVPabI5X4ffBvWL6N9b1t/KVZVV5JPmaT+9trwD/gqB+1Y+gIv7HvwguFgn1JY5/Ft9Zj97a2/8Nv8A7zfeavo79qf9pLQfgD8HNT+J1/rEYuLVNul2MMH/AB9XDfLHGv8A7NX5l/AHQ9Y+Knxqi8VeObuafUNY1uO41Sb/AGpJPu/7q7ttRDkky6dH2ceaR/TV/wAG737KWnfsyf8ABO7w5evp3k6n4ukbVL12TDNH92Ef98/N+NfeJJOMV5t+ypYWHhv4BeEvDFmipFp+g28Cqv8AsxrXo5mRByRV1+f2judWFlTVBWMD4r+JIvBfww8Q+LWmMX9n6NcXCyL/AAssbFf/AB7Fct+zZpLeHv2fvClrdERzyaJHdXW7/npN+8Zv++mrj/8AgpR8QJfAX7CfxT8UaXtknsfB9xIqbu33f8a/L/xj+3n+3H8WvAOg+GPBetR6FpS6Xaosml3X79Y/JVVX/gVeHnFSVPDKNviPUy+nTxdVx57WP198X/HD4QfD6DzvGXxD0qw/uCa9VS1fI/7Tf/BeP9kz4La23gnwPb33ivVt7JIthF+4hZf7zV+bt98HfGHiC4+3/GP4tahNbx7mltbi8Zm8yuT03xl+yj8LZLzVZvAd14n1j7R8+5WjRf73/Aq+Tti37spRXotfvPo8PgcvpyvJSl+CPp/4lf8ABSP4oftD3R1O+0GLR9Ml3fZbGA/M392uE8VfGqaHw69tbaIuoXUkqqkc33lb+9/31Xzf46/a+8c65rESeCfhXZ6RayOsEUP3njb7qt/3zXo/g3xlf+GPCt9q/iqa1h1VYIWt45vn2xt/FURw0YbHqwxMKn7uJYsfG3jDxBrmoQ+LbaGGJUjfzpk2xw/7rV5n8evHmofD7w14j8c+FdRjuJbWSRra6kbCzI8uwsT/ALSsefeuW1L4u63481zxP4J0bW7i6abbO8ccvzbW+XatdL4p+EGq/ETwNcfBy0jMd3cWi2uy5l2FWiwSGY9PuHOa/ePBqEHkvEdtnhJf+k1D6DLZtUa1t1F/qfJnwr8A/EL9sP44aH8H/BOlySaz4q1dbPTreP8A1bSN95pG/hVV+Zm/2a+5vjb/AMENf2VP2ara20P45ftT+M9f1w26/wBo2PgTwzC9vYt/Eu5m3SbW+XdXhf7HPgv4i/sD/tYWXxc8S3Nm9vpuh6klncWsqyNa3EkLLE23+Jqwfjd+3V4w+KHjy38eX/iS8iuVsI4vmuNqqy/e/wB7c33q/F6mIlh4eypRPHwuEo1H9YxMv+3T17wb/wAEj/8Agnf8UL6Sztf+CkHiDRrlv+XDWvBsKyR7v4fvfer374//ALbnwr8A+Ebj9kPwlqMepeHvhjpen6To1v8AZVjguI1j/eTeX/eZvmr80r74669qnio6xDeSRSq6sm19qs1c78Xviff+LPFUnip9v2+6iWK9k3f6zavy7q4KtXGYmPJPb+tz0o1snw0ZTo/F/e/Q7H9qTxH8Or7W5db8H6Ja6bNMzNLHZptX5v4dv3a8cj8TX8iukMzJ8m1dr/M1Mg0/VdfmSGYKjbt3zLXT+HfgD8SPFFu15pRhwv8Ae+X+KuqjBOHLPc+YxWZYipVk18Jm6B4F8beLozczQTLZ7lTzpPurXs3wh/ZHspIf7e1LWFuIo4v3sK/drj9N+CvxR0XUIvC+rePIdN8xt/ls25W/utX0/wDsG/sTyftIeMtY+Hmv/tE6xpt5ZwbUutLVfL8xl+Xd/u1x4xVoJy5oqJlhac8RU9xSuY/xSm8GfD34f2WjeErOx8P20MWy6mbdumb+9u/3q1P2Rf2rIdN8bWXizxpq9nFo/huLeuqK27azf7P+1X2f8M/2SfgJ+wva6d4c+KOveGfG+p61p10mt6l8QLJXgtY925bhVZv3bKqtX5a/tofGD4Y/Gz9qrxn4n+COh6bp3g9bpdO0aHTbXyILiOH5WuFj/wBpt22uLJcLHNcTOlf4ftG+PzbGZTaUv/ATf/a2+Pk37c37X2u/Hia28q0uorew0aHbtZrO3+VWb/aZt1el+F7pNN023htodsUcGxFj/h214Z8GRZ2t41zPtaaNP3W5Pu163oN9H5azI6rt+Xy1/vV+mU6P1eEYI+Kp4iWKryqz3kegaTvureL9+qps2zqsX3v+BV1mlTPblEtoWVPupt+6tcB4f1qOJ0R7lYV+95ddto+qblE6bWaRP3rLL8u2s6kOvMehTrHbaTC7XG93Zt3313/L/vVtwt9nsxv+9t+Td/drldL1hJrcpM+14/7r/wDoVXjrXmb0e2aJF27FZ9yyVwVI856dHEc0NDQuLn9ym+2Vzt/esv8Ae/hWuV8YrslhGQSWkJwMckittdSRWdHTG751jVvl/wB6sLxbc/aDbndkgOchMDGRX6P4MXj4l4NPtV/9NTPpuHpKWYQt5/kyafRjf6LAix5Vo0Z2rldc8PpdJsSFU2/Kzb91dtpk62+lQlZWwYhvRl9v4ar6hp7pdfZoZlf5V8plTb/wGvyriv8A5KTGX/5+1P8A0tnRzXqzXm/zPNrvwfZyTM6bWb/2X+9TY9Bfb50KSEb9v3PvV6ND4bRrhv3Kt5m3fI38NOfw7PHMr20LLt/2PvV8pUxHNLlbOiNE5PRfC9sk3nQo0x/jVovlWuls9F+1W6O8Kqn3dzfK1bGj+G9rK8tzJtX5W+fctdfpvh+GS3+zfZY32vuRpP4fl+7WMq0Y7nZGjLocC3gndCdnlhG+bzPvL/wGs/UPClztaaaFkdf4lT5a9X/seHyV8m2V/LT/AFa/LVW48NpNH5m+N42f5/LesJ4qXwhUwsYnjV54XdWZEs4Wf/llI3/sq1QuNJmWPzvs67W/8er1XVPDtt9oYpZrhV2vIvzbmrkfEelvbsyI/wAi/fatadbmlymtOjKMOaRw99Z+ZI0KJH+7+aVWT5V/+KrjtatUDTIkKqG3NL5cW2u/1eZ41+R9kSv8y7PmauM8SfaW8wJwJP4mT7rV20ZHVh5csveOE1aO2hw/ysyttT5m+b/gNZrRusz5RdjfLub+GtrWEmjtGd4t7N8q7flWueW4eNvLwrfO21lfctdq5pR909ijJe6TfIsbQu6j/a27dtSwzPNGJlhXZGnzSb/utVSTzpl/ffKi/K+3+KrdvvaFNiR/e/hq483UjFRjKMjqdY8PoY5JHhkT/gG7c392uR1jwrDJsT5d7fLtr1TWNNjbfbJcyIvm7lVW3LXOaxos0bMnk+YkPzfu/wD2aumjWlL4j8wxGHhc8xuPDsMjB0+YK+2Xcn92ren28McK7NoZn+Rm+8y10l7p81xJ8+52jTbL+621Xt7OGGYwvbLjflW/irT6x7vxHH9XlGr7pDZ2Mit+5h3hvm21pWtjNuXfFkN9/a/yrU6x+TZhETa0fzfL/Fu/vVJBNMLeI/Zmf+H7lKNTmjZGkafL8RNHshbyYdv7xv7v3aFnhhYI83y7927+7Wa3nRy+TDOx+f72/wC7RcXX753R1dP49v3du2tKcb+8pGcqkTej1Z49vkps/wBrzflZaoalrlyoZ5pmZf4d1YP9oTN8kyM8rIq/K/y/7NF5ceSwT7T935fu1tGMY6GUqkuX4i+2sT3jM81z8v8ACu/duapI9SeRXuXuVTy/uq38Vc62pJHMfLdaZ/aiKrwzeW8W1XSOtJU+aFjm9tOMjdk1J1X7U94vzN+6jk2/N/s1BHMl1I9zNMzOv3tr1lzXiXEiTXK703fuvl3bWqeG6SOQvvVU+Vfl/hrKpyqBEcRKUdT3Pwgqf8KlRYxgfYJwMfV685t1dUXUk2v8/wC6jZdqrXongxv+LQo/X/QLg8fV68xhu4ZP3szsy71X92tfsHjK5/2Jw64/9Akf/SaZ9fnDTw+Fv/IvyR0+nybpo7bZmVvl2yf+hbquyXSLN5LzLu37lrmLfUn+1jyZmlbYy/N8q1fm1D5v3Ykyv8O3dX87Vuf29+XQ5KHJKJuw6m7r53lLGy/L8z1I1x9oVIUuVRtn73zH+ZlrmZNQ8yYJ9+Jm+ba+1lq39rmZv3x3rH/49WXLKUeY9WnW5fdR09vq1tDDCnzSv/e/vf7VWrHXIYX37d+75dv97/armY9Q2xxJ9xv4G3/Kv96pLfWkh/c3LeUG2sjf7X/Aay9jPp8J2RqX6nUtrky/JZwxqv3vMVvmWrWna08bF0mUhovmZvmrkI7rzJv3j7wy/My/KtWo9T8m4CIn8H8NbqnzbE88lIk+Nnjx9B8A3lzDeNHLJB5SNH8zfNXxtrV08MjfOzp975vvV7J+0J40m1DWk8PQv5dvbxbpdv3v96vGdWZJGbuq7v8AeZf9qvvcjw/1fC80vtH5pxLjPreO5Y7ROV8WxfaLUps37l+7XL6PrG1WsJpGUfd2/wB2un15d2770q+Vt3fd21wfiCOa3vGuIX5/javaj7x4FP3SzrUz3jGF+K5a8t3gm+TcwrdtbxNThVPmR1/i/vVT1axm8tkR927/AL6olErmM61vk8wQu+f9mpdQt0ulD2yKrf7NZMy3MM3z8H+7UllfeSzbn6/3qfwj5SOSOW3kKFv96nrsmj+T5WWrkkCXy70dfuVmyRvby7G6rU/EUPlhEZ2VE/3jU8bJPD84+ZagZXR/n+Wq5Rx3Eoo8zeaKocRkf3x9anm56dqiC7WWpJt7S+1TyhIu2EZjkTZt+b79XJF2qdnX/wAdas+zDsv3K0RvZN833f7tTAkgmkfazyJ81VfM+b5Eqe+Xg/O2P7rPUKqnlr8n/fVP+8T8Q9XT7mz7tO8xF3b3/wBxagj2LN9/+CpJmhxvzupBIq3Tb2AFRs3lr70s33/wqP761US4/COrr/C8if2fEjov3PvNXHq2eDXV+E2RtPEaP8/+1T5kFQ05pvMZvn+VvlqjNDvZsfKPu1dmVI5/nG7bVSdvN27H3bd1RL3dDH3JHrv/AAT4iCftW6G+/cTbXv8A6SyV2H/BU0MfjR4dIUn/AIpkdP8Ar4mrkv8Agn2f+MqtBHX/AEW95/7dZK7f/gp1bC9+Nnhy1Emxn8ORorf711KK/asu/wCTGYv/ALCl+VI5J/72vQ9U/Z58Pw6L8C/D1mEuE8y189o5P9quj1DULbTVed03Iy/xPu3f7tPi/wCJT4V07R7OZW+y6Xb2/lr8vzLGu6uL8dahc6fp+HdmmmfZuX/lnX4HUlOUpNHn+9KfMcx8QPFd5rmoNDCGeGH5UaR//Za5ePSUt7eS/vNv+wsj/erUu5kt1k+0vtdm/u0uk+Bdc8XTp+5mwybkX+FqujRn8ZtGpyv3jxD42NH5aWcybGml3bV/hWvL9Ut0VTs+Xc9eiftBW/2f4mT6Jbah5v2GCOJ9v3Vk2/NXAXVjeTR7ztdl/hWu2nGfKenT+Ey1QtWx4d0G81u+hs7CGR5Zm2RL/eb+6tVrHS5vMCOrKzfd+Svt/wD4Jw/sl3Orf8Xv8VWCtBb3HlaNayRbt0n/AD2rojR5jPFYj2MTW/ZV/ZD8SaTo9ho9hYSS67qksf2hV+bbH/zz/wDiq/WP4K/sP/D39kP4Hv4w8YQxjV7iJn3Kv+rbb5jKrf7Ndl/wTz/YRtvBOk/8Lo+LVh9nubhGewhvItrRx7fl/wC+q8p/4KVftUal8SvFMPwz8Hzf8S2ziki3WbKqxt91v++q0rcuGhdfEfPSqSxHvTPm74n67a+Ptf1jWTGTBqDSDbI2SU27OT9BXHQ2KaTp/wDZulafDbwtAqu0aqu7b/tVsW9tFaaZ9nDllWM5Zuc9c1xPjLXftFydN0e/k/eJudmT5Vr9Z8WIueS8Pt/9AsP/AEmB1RheJzMnnaheN50Nw8sm6N2+98u6u9+G3wuh+XWNbTZEvywLI3zf981B8P8Awe8khurrcWjbbtb5f++f7y1r/ETxtZ+D9JbyZleZovkWP7y1+J1sRSwVK4SOf/aS+IVh4b0u30HSrlo5mfZKsdfNl5Nc6tNJ5yMXb52krqfHHiy68TapLqV5czM0kv3W+7HXMyR+ZJvR2RN25o1r52piPrEuaQ+WUoxGTf8AEo0z7a/yiRNqN/C396vO/GGvQ+c0Oxs/wKr1v/ELxgkcaaVpiSOzfKq7vlWvPtaZAzO+7zm+bbvq6Me5tD4TJuLf7RM6O+5pN3ys1cB4/wBBfStU81E+ST+Ff4Wr0SLyvtnnTblH8FYPim6ttShmtnTO5Pkb+7XqYeUoSO+jLl944Kxu3t22/wB2t2x1TzF8nr/Fu31zdxH9mlZD/C9W7G4/g3/NXqfYOw6aW6hk3R/eb+JVqBpHbbvHP3ty1V+1P1R03qn3tlWrX5UV3dWf/drQzj7pG0b3HyOjD+41EPnN987uzf7tWmj+X7/Kv/DTZLPbcGbewb/ZqdfhHKXUr6bZvY6wsKchvmir2/R7zyPh6jv823au7Z/s15NNpPnWcV+isz2/y7l+9tr0m1kh/wCFftHMinbKuxv7rU/fIkY11fT28Oyb7uyvKviBM82ulN/3Vr0PVL5P3rzPuG/5d38NeXeILh7rWbiV33fPt3VBpRKVFFIrbqr4jYFXApaKKoCRY0Xl3x/srU6ahc7fs9nujVuy1X8z5XcnJ/2qWO6mVfkpfELlRKLG8lk3ujf9dGqRlhhUpczMf9mOq8l5cyffmZh/dqJiWbdml/dFyls6htXybZML/F/tV+iX7PTNN/wTojPUnwdq+P8Avq5r85beF7iQIn/Amr9HP2f0WD/gnWiK/C+DtX+b/gVzX7B4O/8AI3x3/YNU/wDSoH2HBkUsZXt/z6l+cT4GtZodFhZ4Zle62/NJ/wA8/wDdrNlvXuJDNNNudvmdmf71QtM7D7/C0kbJJ8ju3zfcr8dmfFe/9o3NJ+aze8mh2hvlWo7WxudSvFhh+Z5H+7VqSFI9Hhtkmw/8a16Z+zn4M0S68SR3/iRI0gh+d2kfau2nGIjY+Af7F/xF+L18JtN8N3D26/62bym2r/tNX0Ev7Mv7OXwJhhtvH/xCsbrUlVfNsbfayxt/dZq439oD9ve/8I+B3+HXwfmj0mO43JLJYuys0O35VavkiTxtr2tak+pXmpSPPI/zzMzNuolUlKPukSp825+kHw/+OnwD+HccM2m2sN1cNLul27dqrWp4u/4Kg+Hvh3o7zeGNNjiuG3M9rIisq/3a/OJvG1xptiYYbmRX+8+2uY1nX7y/kV5ppC/97f8Aw1lKM6m8hxpwUT239p79ub4tftEapN/wlXjC+ubbzWX7PJLtRV/hXateP6WlzfXS/LisiGHzm2Abmauo8N6b5MyNMjKG+WtIxjEfuRPTvA7WtnpG/ftK/f8Al+9TvEHiy/WMw280ixfd3bvl21V0Ev5K20L79v3Nv8NXrHwjqWs3z2yQsxk+9troMvf5zC03RNS1S63+W0hZ/k3fNXrXgn4bPb26zXW0Ns3bv7tdR8Kf2f7mGz/t7VbPEUarsZnrttc0fStH02TY8YMabVXZU80Sebm+E4q3hs9JhFy8O5I13M275mb/AGa8v8eeKL/xVrn2LTd3l72/d10fxK8XfaJ/sdttHzbdsbVT+H+g6Da3D63r1zHiT5kj+981R7TmJjRnH3j0P9nv4Pw+IFhl1VIbdYf3sv2ivprwfpfgDwjpkUO+H7Zubzd3/jtfJN58eLDw+zw2dyscX3d3+z/drB1T9pPWLqRUfWG8hX3bt+1qy9p9k19jzR94/QlfGHhtpt6bYopPlRfN+78v3v8AdrA8UfETStOZ7mw1ViYWVkVZflX5fvV+f2oftVa3bvvtNYmYxp/z1rDvP2ovG2oRyo+pSbG3ebt+61KPNLRkxo8p1n7aXxO1P4v/ABWtPB8OqtPp+h/v5Y1ZvLa4k/8AiVrqP2P7Gz034jaVf+R80OpW+5WXd8u75mrwrwGz65NLqty6vNNO0r7q91+CrfYdSS8s/leGWNk2tt3Mtc1Sp7OrE58R/Kf0x/sl/tFWGp/DvSLO9uWdo7VV87d95dtez33xt8N2dqlzM+5W4VVb5mr8nP2M/jxef8Ivav8AbNm2Jf3ay/dWvpi1+Jl5qkYs/t7NF5XySL8u6vbpyhUhdxPM5p0/d5juf+CiPxPs/ij+xx8XPBPh6xk2XHgHUAkjJ96ZY933v+A1+SnwB+OtnN8G9A1u5v4UH9g26SqrbpGZV2/NX6Z3lm/irw/rfhjUrzzINU0a6snVn3LJ50LLu2/8Cr8Avhv8QvEPhXQ9S+F2pTNDd+GdevNLuo1+XcsczKtfO8Rx5sMpRXwn0XDtaNKrI+vfiB8etKufOhhud+75/Mb73+9Xifi74kW2rTzXNntiaSX/AIE1ebar4qvL682fatm5dyfPXO33iS4t7r7T/aSokKbdqpur4WVacj7KnjIy0Pa/C98+rXiarretxxtHu+98q7a4342fHy51LxE9homqsbaO3WBfm+9XmmqfELXplWztr+OFG+//AHq53Ut8zM9y7Ft3ztv+9WtOVWUbSIljIxj7h75+wL4ihs/jxeXOsfZ2ims1l86T7u5W+7Xvnxh8ZjTtL13x1AuAZpLlVRuAHkzjPp835V+f+l+INe8N6out6DfyWlzD8rtvb94v91q+wfiXrMkn7LTa5ekO82g2UkpPcuYs/qa/e/ByMlk3Eb6fVJ/+k1D6XhnG06mFxClvGN36WZ4j4y+LHifxZJse/mKKvyeZL/D/AHa5+38B+Cdd8C6xqupaxdQ67avHLpFvb7fLkX/losm7/gNYl14ks5I9iTbFX7yr95ql0W6triORJpv9Z8yLH/8AFV+IfBq5HL7alWlrK5w2pXlzY3DGF/49u1vvbqfpcmpahJ5E1nvf73y/xNXT+NPh/o6TLeaPqXnSsm+eFv4WrL0fXE8O3EdzNb7drr95K6ZKlOHu+8ePUUva8sixcW+uaTb/AGx9BvNv/PRbdm2/8BroPDf7Qn/CO2/9lfb5Eb+7cIy17T+zz8fvDf8Ab1tD4h0e3lRn8po5ol/eLXvWvSfsZ6feRXfjz4XaTqVtJ8zqsSxNG38O1lrzY1MJU9ypeMkbU8PWTvB80T458NzeLfjlrlrB4EeTU9RkfZFb2aM7f981+mH/AATC/wCCdH/BQH4RTXHxG1n4J6e9tqEvm2q3mvQwSs395v8AZr2//gln8Uv2Z/Dnjy3+Hvw7+Hnh3RzfJJcNeWtnD5/lqv8AFI3zfer7rn+Knhu1uv7Nt4Y2j3fLJCqqq1yYh4Tlt0PbwuGxeElzw3Pxn/4OCfhD+0l8HPAXgnx18XfFuiyv48164sL7R9DRvKsYYYd0cPm/xN/6FX5h6LCkLGCBNkW9dsa/w1+qP/Bzr+2J4P8AiX4q+H37HPhKaO4ufCt7J4h8UNCys1vI0flxQt/tMvzV+VOn3kDats+XEn8Sr/47X2mQYOhhMDH2ceW+vqfnud1KtTMJqcuY9G+HupTabDLB5ylmfdub+7XceHfFybfk3LtT7zN8rNXk2m6hJaqyIm1WT7y/w1f8M+MMRpveQur/AHl/hWvaqfAedR933T6H0XxVDuSZ3Xatvt+ZN3/Aq63T/Eb2scU32lVfZu2qvyr/AHa8F0LxIt1dIiTfMu35Weu20fxnN5LJ57bl+V91c0eY64ylGR7PY+IIV3+VuDSLulZW2qzVqw61Db27v9tkzH/qoZJdy15N4b8VI9uYZvk/6afwtXR2+sp8n77O5FrGUftHXh6x31hrlzbzF3m+6v8AF97c1Lql3HdJEVO1lB3Rf3Olcxa63N9+Z13t97/ZrT0+6a7DydQDgMepxkV+i+Dcb+I+Db7Vf/TUz67hef8AwqQj6/kzo7K7lNpG8gZhEgXy1bkr7VdjmtpE+0+dIrsn8XzN/vVzNpq9ukjQRSEGP75WTGW/u1a03XEYzJDPHu3/AHWf+L/er8p4tt/b+M5/+ftT/wBLZ0KpKOKm13f5nV2dun2MpDN975v96r0drNHh/wDWN8qvCzfKtY1jrCWqql593Z87L83zVr2uoJ+5SEs4m+avh61OXNzcp7OHrcxu6bY2s376G2U7v96tnT7e5jj+RF+ZmbdJ/C3+1XPQ6sm1PJjYN/d3/LWhDrx+0JbQzKGZWZ7ff/7NXnSlKU+WR3+05jaaJ1mFzCn8Py/3Vaqt8u3dMgUbk/u7arTa4kLMiOpdvuqvzbaz9S162tY2mubloyz7WaR/++ajl5dipVOb3WQaps+xzXmyRPMXY6r/ABVx+uSPNC1t/AsStWvrNxc3CunnSOPKV3Xzf4q5m+1J03ec+G/5ZMr/APoVdMYy925cZfZOX8TbJJlhxIxb+Jv71cV4ksZmhkeaZv3fzO1d9qUcxm3p87/wf/FVxHiaSF43h8n5t3zfN96vVo/vdjGM+WZ534hZ5N+x2Td8yL96sKS3mhDwj+FN27Z8u6up1uBJbpdiNCqpt/vbqx7uOOP93Cm0/wAfl1304np08Ry6lGO3ePdPN5hP+1/FWhp+n+cf9Svy/wB1vu/7VNWR4YQ6WzKn+18ytWjpMfltD8+yKZPnbb8kn/Aq09/4i62JjytHockKQ4hSdZWb/lo1ZGoQySM9s+5m27vM2V0l1YuJGj+4n3t1ZOo2ryW7vchjt+5tb7tT7sZe6fE1PeOYuNNe4VXebLN/yzX5vlqhFp80amYOreZ/d+8tbC21wrIlzNMsW/5ZNvzMtFro8LXUPk2EmJEYsu/5l/3lrblhGXvHPKPu3iUrOzmuI/kRdyv+93fNVn+zXkhim3r/ALS/drasdBe3jldH3MzfN5abVWra+H4bqY74Y/l+8zS+Wq1nzRfwmdSjKJyVxpaRrJ+5be3/AC33/LurBvNPeGGP5M7VbYv8LV3+oaDDGfOSGRiyN/qW+Vq5TVLN41be7A/M3zP81dtPljDQ4KkeX4jkbyZ4WXztqLu2/L/DtqlqWouq/uXz/Cm5v4as6sba3aWaZJG3J/vVzepalNCzJsUt/Bu+7XVTjKUos8mtU5fdLv25E2uk3K/Nu3/eok1KFwdgZpNv3lrnm1rbv2JtT7u3ZV+3uplm2O+dybt23+H+7XdKny+8c/NKRr2+oOtvseFtq/6pVqza3UNqXlf5U+81ZtrJIrJNH5ixs33f7rVfh03z5Bvl3N83yt93dXHUjCUrMr35aH0F4GlEnwSjlkPH9mXPPTjMnP5V5at08d0mzd5W/cjf3vlr1PwOxPwURmiVf+JbcfIg4AzJxXmNrY7k+R921NyNH81frHjRLlyPh1f9Qkf/AEmmfbZvrQwn/Xtfkixbt5cm/equ0X3W+7UqxzPh3Zf+A/Nupmnw+ZCN6b9z/d21Z2+ZtdIliX7u1W+9X8+xnJx9w4I+7GJDJbzQ22+F1R/4f/iqns5kb7k3yqn3du1d1RyQozPjbH5e5WVm+anx2rw26PBM2P4Vk+as51JSjy9jrp1JR90kkmufL875W/iT593/AHzUtrqDzNEnkso+/tb7q/8AAapN/o/3DIrfd+X7tSWm/ck3nM6r8z7qco80IxO2NaMYaG3askkDzPud9+5VX+FqmupnsrV7l7xVWOJnfc33WrOW8RG+R2V2+/8AN8tYXxW8SRaTov8AZUMqr5yN/tV34XDe2nGETnxmMjQw8ps8j+I2uQ6xr1/qtzC37xPvN/FXm99qaW8jvHMw/wCBV0HiyZ2V4U+cK7bJGevPNSu3eb55l3f3q+9pU4xpcsT8vqT9pVlN7li8vkkZvvb/AOJW+7WFqMCXXm/w/wC1/darElxHLJsR9pjXc3z0tts8tt7/ADM/z1vymXunJ3Vvc2N9+5fipY9aQt5Nzyf9muh1TSIREZvJ5b/vmuHvrhLe+l2HaVb+5T+2OPvF3UrOzumEyQ/O393+KsS6tZIpG/dbQtalnqyN/rguV/8AHasTWcN4vyP96l8RfwmBBczW3yDpVmZDfL52V/8AZqs32iuql0f7v3/krMVnhk+R6kv4gIeFsZpXm81drJ83rVvEOoxAqwEu3G31qpPC8LlHGMUAMf7xprLnkU5m3UgbdzQWLHhm4NKykmmKu2lrQCzZt83rWhbs6/I7sQyVm25KkfdrRRt1vn2qYmMiO5kf+4p/2qgLSN8vZf4qmkjRW+/j/Z2VUkYLnY+P4fmqZS5vdFykjNs+5Iuf9qmtJGFZGT7v3KZCybmR0zQ8if8A2NPlgWQyfN8+ykoop/ZKiFdR4LXzNPZEG5t9csxwOK6TwT++tXtv9ujmFU+E3bpfLj/cyL81ULqHZ8+f4P4av6mqW8ImTd9/bt2VQmk8tc9C38NHMYSPX/8AgnuGX9qjRAX58i93L7/ZZK9Z/bp0BfEf7VHgXS5Y1McunW6yMy5wBdTH+leU/wDBPuNP+GqNCl3Ek2t71/69pK9+/aY0yLVf2t/CaSSOBb+GfPdU/i2zy7f/AB6v2jAP/jRmL/7Cl+VI4qq/2len+Z2OqalbRyXDp5ezd8it95dtcJ46l/tC8FrNMrMvz7pH+7W3c/6l3MPz/wC1L95mri4rXUvGHiZLdJt0K/K3l/Nur8Gp0+afKcXtJRlzGl8Pvhjc+ONcie23SwtLsVdjNu/2v92vuf8AZ1/YMhm+HWreNvFX7nSdJ0i6v7242fLHHHG0jLu/u7VrL/4J+/sn3/jnXLCyTTbrbcSr5q7dvlx19vf8FZJdB/ZK/wCCRfxY17w9M1vcXHhePSIm+6/nXTeSu3/gLNXv08PGjhbnLF/WMZFH8wvinXE8VeKdV8QRzM4vtUuJ4mZv+WbSNt/8d21nxx3KyKidP49taGjaO5tIS+07YlH/AAGrnkwwzDemAzbdypXGfSc1jpPgd8Kdb+KXjTTvA2iWEj3mrXUdrZqq/ekkbatf0rfsFf8ABN/RtL0nQbnxVoNrFpvhfSbe3+WD91cXCr+8kVf96vzA/wCDaT9l3RPj1+3NpureJ7BrjTPCekzavIpT920i/LGrf8Cav6CvjJ4ts/Cfha40Dw3bJbwKnziH5fM/2VrsoyjGJ4eOqTrVf7p88ft0fHt/CPhW88JeFbxbG12bHaNdu5VXbtWvy48c6ii6lePM7YkuN67n3N81fW37ZHizUtSkENtdSPEr73Vl/vfer498YWc17q8t5bRrsb7zL/FXNWj7SV5GMfgM6eV5tFmkVTuMD4BGDnBrj/DPh+FZPOd5LmX5l+5u+au503Sbi4EWjsS0k77BvOSS54/nWr4q8O2Hwst4rB5F+0yMyxRt8zK38Nfr3i7Up0MjyCUumFj/AOkwNOZLQ47WtYh8G2rTXkK/a2Xavz/Nt/u7a8W8deKNS1q+e5vLnarfLFCv8NejeLmudUhuHmmWW4kdm87b8qr/AHf96vNvEmmW1n5r3Nzt27W3L/FX86YiU8RLml8I5S5vhOWvoHkX532/w7W/i/2q4/xV4qmVja6bu86Pcu2P7q1qeKvESX15JbaVu2/daT7tcffN/AjyMzf3vvVxU/5Xsa05Rj7sjEvZnW6d33O7J93+7WLfiFVLybXb/wAeX/ard1Q7oykdsyLs+eT+9XD+PNfsNFtHgtXxK33mr1KEZOR004zqe6Zmu+KIdPjOyZX/ANquR1PxPPLlLPdjP3mrNv8AU7jUpjJK5x/CKgZscCvZp0Yx3PTp0VAGZ5GZ35NSRvtPXH+1TKK6OU0kbOn3SLGEHzf71aELPJD86NXPWMgjkXY9dHpqm8XG/lf4aOUktRK6ts37v7tacVvJIqv94/3m/hpun6akki/Jkr8ybkrYktPKVJoXXay7WWnze6YS+L3g0G1S4hlsn2v5iMu6P+GtuS1ez8AvZ3PmZjlX7v3vlrO8GyQrrH2Z9qbl/i+7urpvG32ZvCMt5Ci75Jfm2v8AdpRIkeY+JNQSOxld32t/drgJH3ylg9dJ4w1FJYfLR/vfermQDnLVJ00/hBhkcUKu2looNQopGOBxS0AFFFFVygFLHhm4NCx7l+em8sPSnHYmRaiuEjj2Inzfx1+iX7PmD/wTkT38G6x/6FdV+ce75sV+jn7Pv/KOJP8AsTNY/wDQrqv13wb/AORvjv8AsGn/AOlQPseDV/tlf/r1L84n50xk7tnf+9uqxDIkd0oyvy1T3t605ZnXPz1+Pnxso8xuTaw7TL/s/LV+L4gaxYw/Y7O5ZNyVySyOn8dL5zsfnfijluHKy1faveahM8tzNvbd95qktbpLZV/vVQbZjilE0i9GoCUTRuNRnui6Oyr/ALtJa2fmSCGY/wDAqqQLDK338VZW6VF+dvlV6v4RcvuGzpOmoI1m2LuXd8tdHosyKqF5vl/u1wn9pzRt8kzfLVjTb52z515Mw/uq9EdjLlmet6HfbrpfJvI02t/FXsvw18R/DTwCn9q+NvE9ncTL86wxv96vlttQ0q3tWmuZrpfk+SP7Rt+asDUdViumzskd1+6zS7qzlGXQrlj1PtLxt+214CgD6boN4qRqnyL/ABV5r4w/au/4SBX8m/bDJ91flr5wS4ST/XQ7v71Ss1mql0jVWap9n7oRjE9Sb4oaM159tub/AHDbu+/96mXnxSs7iZPs1+sQb7+1/vf7NeTNePHI3yL/AHals3825Akfcn3sGrgOUTuNe8dPeXAh3rs/urWReeJPM3/v2X+H71YU198v8P8AwGo/Odl42/N81Ll/mJj7ppnVHbKbtr/epJNSmjt2S2mbe1UIrpyu/f8A8CqW1vPnZH2tTCXunrXwhjabw/Dsdd6/e/hr2z4c3X2dvM+Y+Wm99qbtq14H8FdSddLkskmYlbj5VZv4a9r+Hd463ywpuCTLsb+GvLrR9/3jz8RH3j7x/Y58ZPJDZwojSIr7FVV2tur7g8ByTXlv/plyqIy/Jt+9ur8z/wBlvxIlrqDw+cybvL+WOVvmZW/u193/AAl+LiQ6ampWEO9422SrJ8yr/tba9LA1vdtM8qpTlL4T2zwPpOsf29CsNyyQrcf6xn+8v+1X4W/tqeCL/wCEP7eHxg8GeT5cbeL5L23VflVobj94tftp4d+L81nqx/sG5hieaJt9xJ8ywsy/3a/M/wD4KsfC1Na/aw/4Wp52+HXPD9vFcXjRbfOmh+Xd/vbanNPZVsM4HpZTKdPERTPj/UtSv9vzp5RV9u7d96s+4k/cu77Q7fMPk+9Xd3ngHUNQuBYaPA1zMzf3P7tc78RvDmp/DB9Li8d6NdaU+u2bXmjNfWrJ9qt1ba0kO77y7v4q+Jll9WpG8In1Uq3s5ayOcvI5reUvs+Vk3fNVNm2sN6b1hXc7N8qtXG+LPjpZ6XI1no9q1w6/K8kn3a838Q+PvE3iOeRrzUpFjkP+pjbatdmFyWvUj7/uoyliP5T03xJ8WtB0e4ltoU+2T7tu2F9yr/wKvtn4mXIuP2LlvHULv8K6c+30JEBxX5j6VuOoR4Xdlq/TH4s7rf8AYdIjxlfCWnAflBX9BeE+CoYbJc9jHrhpf+kzPpeGqknhMe3/AM+n+TPiOz8aTNceS9tlFl+WRq0rPxwin76oN+3bXC/PDcNs8xPn/ibctXoWdpNiP/tV+OyyvDVN4nx9PGV6fwSPRbfxNNeL+5maV/4/9mqlxffapPs3nfMrf3v4qw/D+pXNvKqCH5G/5aVZ1iz8mZrm2mwu/wCasKeS0KctDSpmVWUfekdn4A8J+M/FmoJp/gLR7rVb9tzxWtn80n/Aa0tY1D4x2M7+Htb0HWra6t5dz291YSb93/fNcx8M/iN4k+F+uWHjzw9eSQzabeRzqyvs+7/u19p33/BQ8+MPDFlr1neTXVzdf8fVrbwK0kn+zuZflWvXwPC2VZi7TfLI8XH8SZnltpUo3izK/wCCd/7QVj8F/ii/i34u6DeaUsem+UuqX1u0UTKzbtys1fTf7Vn/AAXI+Hvwz+Hd7o/wQ1ux8VeMb61b+wbfT/3lrp7f89p5P9n+Ff71fFnxq+LXj/41aLcaV4h1W1s7a+t9iabY2+75d3yr81fPHiX4d6x4Lwtz4emtrTbuVvIZV21lmfh7Qy+rHEKfNB/ZO7L/ABEx2YUvq8klIdrXjDxh468Ua18SPiJr02s+IvEF011q2pXTbpJpv/ZV/wBmqMbzQ6kroihG/hb+9SRxPGreS8bPv3f8BqPd/piQoiu9aRhy+7EzlOc580jo7hvJ0+W5dG3bf4q5fRdceC7ZN+5d/wDC3zVv3myaw3o/3l+fbXCrcwrfMj/K+9vl+7tp/EaUdz1Tw74k/eJDI/y/3m+9Xb+H/Ej42CZWeb5v7teLaHqnkyBw+3/a+9XZaPrUqtsdGdtn3v4aylR5jo5uU9e0vXHuIUm+aJWdv93bXV6D4kd4US2mjRG+bzJH/h/iryXR/EMMMiohYMybnb7y7q6PR9QgaFPPfJZPnVX+VazlR/mHGp72h6rY65cySCF5o3Vm/wC+v7tdp4MvzfJckk/Ky/J2Xr0rxvT9ciWZNkylFRlb5a9P+EMolsbt1nDqzoUx2HzV+geDtOS8RsHLyqf+mpn1/CdTnzqn/wBvf+ksl1C6a31e4isZ1QGbfcFV+YjPNaunatuuEdNuxXbdI23/AIDXMa1Kttrt3LNtIaZwGZ+nPTbVq11S2jmX/Vh22s7bP++Vr8x4rp+2z7Fxf/P2p/6Wy3W9njpv+8/zO5tdV+0XDv525m2t5i/8tK14dUhtLj9zC277yNv/APHa4OHWnjYPbPslmdt7L81WYdam2pHDfyF403N867mr4zFUfd5Ynp4fGe8d7b+IGhuInR97bP8AU/e3VpW+tzMxhjm3bvlfy/8Ax1a85t751VJppv3X3maT71a+k6oiyeZC7Mv8NePXw7lVPVp4qMtUdlJrVzMu93VJV+Xav96qt9qUMcfnTfN/e8z5tzVi3F0i3m/ZvCoreZv+8v8AdqGS+eONdu3+981Ycvs+Y2lU5pFjWNQeNvOTy1Zv4Wb5l/3a5241KaaUP5y7d3zNUt/qSfZ5ZJn3bW3IzfN97+GsDUr6GOHY6KvzMj7V+6v96tKPNLcunUjEmvNUjhjcu8aDzflZX/hrm9evbaGxdH275Pm8tvm+aodV1yGON4bN2x/Hub5t397bXJeINcmvpjZpeRh1+ZpGf5m217GFoy5jmxGI5eUr69ND5zwQ+X+7Rfu/Kv8A9lWPJH9ouHTdkt91l+9VbUNagupC6bf3fy+Wr7mWqf8AbTo0XzfumfdE0f8Aer144fmjGxH9ocupuwzJDb/fYoqf99f7ta+m3CR2apMm6JfuR/3a5eC6eO4KO64k+bd/drWtb6OTa7vJ83y/NVSo8vwkVMzjOWp7hcWc0cju+0/N/vfNWbqmmpdW/wAkPHlfvdvy7a2lZxcP9m8yFW3Inzfw1JDb+dK6eTuRlVX3fd3V50pSjqZxlCRx3/CMWat9pSSR/nX5qn0/w6i3Hmw+d8v3m27mbd/erp20/ddeT5Me5m/hrS0vRdzNv+R12/Ky/LJSlKIcq5eWJiW/htI2/veZ/eX5t26rj+GhZt52xcM/zbq6eGzRdjmRS2759zfdqWTTpreGSZ7aMvN8rrG+5VrQipT5TgdQ0Xy4dn2bZ87b1ri/EmizKsvkptT5vlX/AOKr1PWh9njWGGFVZk+6zbt3+1XEeIoXmjdPJ5b5vl+61XCc46nn1ox10PGddtPszKjovzfN8rfLXD63ZvNcPNav8sb/AD/P96vSfFVi6q/ksqCNvkbyvmrktU0lJG8t/wByW+438Ne5h48sOZnzleO5xMNu8f79PmG7czSfw1oafcXUm77TGzL/ALX8VWptNmWTyblFYNS2Mc0jvbTOuF+ZW3V3y5ZHDL3eU0LG1875NjRIybt275VbdW5odpc3UyQud6t/y0rN0+3DKba5dj/fX+Fa6rRbHy1S2hZW2/d2p92vPqctM76fvHsXhG1nt/hGlrIxaQafOCT3OXrzq3tYbWNfs0G12RW27NrV6f4ZTyfh0kcZ+7aTAZPu1eeXkUN1dDzplj/dfKzJ95q/W/GOi6mS8PSte2Ej/wCk0z7LN5RjhcL/AIF+SH6TshbyURiWb5W27VWmx2pt8Q7Msu7aqp97/eo+0Qt8kM2x2/h2/NU8Pk2wKJNJuZ1bdtr8C+rxjUPMp1I8vLKIq6bNNtd0V327kZUqG6jLwjfOzxsnzqvy7a0lj8uOWG26/K3zN96s273xsYUuYyW+9Ht27aylQ5feKjWjTK0kjwyJ86o2z7u/dVaPVolYpCjff3f7zVV1K8CSMIUX5trP8vy1lw3ztM2xF2M3/LOuqnRjL0I+uSjLQ3o7raxuUkVE3fdb+Fv/AGWvNfiZ4k+2axtd8RKjKu1PlZq6nUtSh0/TZZt8jMyfIrJ81eG+NvF1zcXU1zNKy/3Pmr6HKcHGnKUjws6xk6lJQKmt3TzedNbTZ+bbtrhda3rI3zrvV62rHWHaN33s27+H+7WJr0yTS+d/6FXvQPmZGb53+3y1Tw3SRyBN/Lfe21n3Fwkcfyc1TivEkmZxuDr8u3dQUavijXktdNeKGZt7LXBzSSSSNMXyzVratcSTN/u1msjt1StBxlcrZOeXY1Zs9VubOZXSRtq/w1C0Pl7eflamsh27kWpkafEbsOuJeK6TIuGqhq2n+SouYU+RvustUPnUVpaPqkKt9mv/AJ0b5V3fw1IuWW5mxO8Mnmd60murbULEo8aiZfuNT9R8OTAfarSZHik+ZdtZcgmtpNjqytQP4huHVvnopWbd2prNjgVfMiwUYWlooqAHwLubIq9bsnl799Uo1/5Zn+KpoWRW2P8Awv8AxUTMZE8kjK3/AI7UEyoy79n8dLNJtb5JN1I0u77+3/gNARIoup+tNkG3kvk0rYx8lMf7xoKEooooNBH+6a6T4fyJFJNvT/gVc2/3TXRfD+VFu33pVx2M5fAdTqFv5kO9H3fw1k3Vu/nP/s/N9yujms0ht12bfm/iWsi6hdm3u7ZpfEc56t/wT+jK/tSaAw2qDa3vyr/16yV9O/HpYNO+OEXiG5jUiPwnFBGf4gz3M3Svmj9gGJ/+GntCfbwLW85/7dpK+i/2tL/7F48sI1KqZtJjBO7BIWWU4/Wv2XB+74E4v/sKX5UjixH8dehgnXLm+mM00PyLEzvGyV7L+wP+znrHxe8ZQpJpUnk30qv+7Ta0a7q+cobua4ki01LlovOlWKWRX+ZV3V+1H/BG/wDZR03/AIQ3S/F1h5awwzxw/f8Amb+KvxvLqVKVTnkeViXJU+WG59ofsb/sX6B8FfBNtf3kMYnmtV807fm21+WX/B2d+0XBq/wO8N/B/wAI3Ey2OqeL4kuvLuP3U32dWb7tfsp+0p8X9E+FXw51C3h1SGG5WxYBWfDKv3a/mq/4OAPiJ4Y8WfF74b+A/DepXReGyutUv7WS682NZGbbGy/71d1ScqtPnn8jvw+Fp0K8Yw6fEfBun2M0caP5KudnzVKghkmCX9hu+b5dtaVnZeYq/N8rfw/3qsx6LukCI7b91cX2z0JW+E/bD/g028Gy2E3xW8XxQxxQNolna+dt3SRs0jNt3V+iP7R3i5LfNnZzKFj+RGX7tfnJ/wAG0PxUtvBfgX4teCby8hRrrS7HUUZfvK0bNGy/7vzV9gfFL4oWGrXks1tC0vnL8i+V/wCPV20fePDxMeXlPDP2gpvtVnNqt7M32nfsVv4VWvEdB+Eut+LNW8mzs5EST7snlbo46+i7vw3qvxA1SZHsNsTf6pl+Wovjd8Sfh1+yX4PhtoJIZvEF9Fs07T12yTs2370n+zU4ipSpwvMy5XzaSPkrx3oy/DX4ny6XcwmUaVcW7yR8DfhEcj8a888ZeNte8VeIpvE+sCNrmZ22Rt/yxX+7XQeJfFuteObm+8X+IJS95emSSYsPqAPwAA/CvOtU1CG1jm/fZX7rfP8ANX6P4z1H/YXD774WP/pNM1+ymyO8WG3Vrm5uYUXbu27/AJa8O+KHjD7drDw2c2yPbtWFX3LurpviR48RbR9K0253vs2quz5dv97/AHq80j02a+unuXVvm+bctfz1GtKvsXGXNuZt2yXErbLrG5t33Pmps2ivGz3OpXKt5f3P4f8AvqtSaztrWF5rmFTt/wDHa4jx14uKwulteRpDv+eT+9/s1vGjE2jT5pmP8SPF1nZRultMoVvmfb91a8R8R65c61fPLJMzIG+TdWh438X3OuXjwxTN5StXPKMDFe9haHs4XZ7VGl7OI1V3U5V20Ku2hW3V2cqOgFXbS0UURAkVvmyP4a3PDt1I0gT/AGq5/cfu1e0e+eGZE3/xUpRIlE9Z8O25WFfuhvvL8n3atX1h+73iHd8vzSfw1neC9U3xo833W+Wusks4bhfvsibfkqvscpjKJx1nvt9W+0oigq+5GWuj8aXv2fwSXTbhn3PJv+ZflrD1axfTZvMhh+VX3basa1Nc6t4BvLOGHbtt2dt38O2oJ9n7545qN295cM+eP4ahjh82THrTWOFr0r9k7wn4S8dfHXQvB/jOwkubC+uGSeON9u75WoqS5Y8x1xjzaRPNmBXgiivsX4lf8E6NB1Oea++GPiGSwLXDCKx1D5olX/erwjxj+yR8b/BzO914PmuoVf5prH94u3+9XNSxmHq7SNp4WvS3ieY0Vf1Hw7rWmStDf6ZNC6/eWSJl/wDQqqfZbnbu8lv++a6ozRhcjop3kuv3kxTeAKQuZCsfmz6UlFFBQrNur9Gf2fP+UcSf9iZrH/oV1X5y1+jX7Pn/ACjiT/sTNY/9Cuq/X/Bv/kcY7/sGqf8ApUD7Dg3/AHyv/wBe5fmj85k+8KGG00lKx3GvyL3T48Siil3fLtqSeZCUHPeiigdkSK3ylD96mD5l2fw0csv0o+98iD5qBRHrzt/2vStKyVLWHf8ALtV/mqhHCjf71TXV4qxeVC/P8VVzESVxNSvjeXG/HyDov92qrOQ386WRm3mmVIy1bs8ak72pl1Ih27P7tQq2T8v8NDNu7VXxFcrF2D1NWbf93C29P4Kgjbc3z/eanzSbcIjttqSZIduRVxu3UrNlV2cn71Vy20kUsTMrbw/NAFqbfCn38j/ZqLzAv3Hx/fqNpy2Pm6U3zB/cH50Adf8ADXxA+l6wltv2pI/8X8Ve9+CNatm1S28l2c7/AO592vly2umguUuU3Eq33lr234X+LIdUhhm+04dU2uu/5lrjxlPmic9anzQPrv4L65c6Lr9lfvMu2OX5W2/LX1V4N+LFta2ahLnaWdvmZvlkX+LbXwT4J+IlhCI3v9VjhRf70qqq13cX7XfwF8AWq3/ibxrFd3EL7fsNs25v/Ha8b2uIheMInlexq8vwn2w3xo+15fTUkb/Zjf8AirnNU/Zr1v8AbmuLn4Y6V4wh0bxxHpdxP4Ih1BP3WpX0a7ltWZvu+Yvy7v71fGXij/gsB8OPD6TWvwy+Gt3Kyrtgnm2pHt/usrV5P8Qf+CtX7SHjG4SbwTBZeGp45d9reaeWaeFv4WVv4Wrow9HH1JxlKBtSw+JjNTXun3/+w/8A8E6/ivD8QbzxP+0/pWpeCfD3g+Ka7+Jeva5b+Ra6TYw/NLGrN8skkm3av+9XwF/wVJ/bw1r/AIKA/tm6n8adA03+zvBmg28eh/D3Rdm1bPRbf93D8v8Aek/1jf71WP2pf+Cq3/BRT9sX4b2HwS/aP/ar17XvDdjbx/atFjSO0ivmX7rXLRqv2ll/6aV4HDEjQ/PCq/Jt217kIxjK6iepzSUPi1OV8V/NqDzJ0Z6y62fFUSRXHl7MCsatTSnIuaDG8mrQqn96v0m+Odwtn+wnNPKdoTwppuSO3NuK/OLwbZ/atchR3xtfdX6JftJyGD/gn/eyKenhTTO/+3b1+veGH/Ipzz/sGl/6TM+v4Y1wmPj/ANOn+Uj4WWZLiH5HXbVmxjjmkZEfdtri7PXpIVMPr91j/DW5pesfdSN/95l/ir8dPipROphRFwmdyrWza2qX2nvbTf63duRq53T75LhhMnH9+uhtbh1nWG25Vk+8rVpT3I5oX5ZEcMf7uXSb+HI2fe317j+y5+xz+1T4806O58LfDe9bRr5mlg1CC3Zo9qqzbty/d+VWrxq7s+ft9sm14/4f4f8Aeav3K/4N7/8Agqh+w/4c+Alp+zN8bfENt4V8ZPc/2fK+qhVs72Nt3lMsjfd3bq6cPjfqVWNSx52PwksbS5Iux+Qmv/tTeAPh2raR8P8AwaPEGt2dzifULlP3Uckbf3f4vu1+1v7J/wAPv2IP2zf+CW/jLx/8btM8Pt4gtPAd9qN79h2pc6XD9lZlby/vKyyKa+Mf2TP+CWi/DL/gqB4ttfj54GhvPhvdeJLi5t9Us4Fls2t5rhvL/e/dX5WXb81fVX/Bej9mz4Z/8E7v2XNc+NP7Jvh6405/iFpyeCtUt7eTNpZ290dxuN277zKrKq0sfmlfMa0Vz/CceCy+hgY88Yb733Pwc0FU/su1/wBJmcNEzeZ/eX+Gq02oPF4khttn+si+fbWja6Wmm2KQ9oYtm5n/ALtcbpOqTap463o+7a2xPn+7WcfePZR6T/rNNJ+9t/u159eLt1B3TdnftavQ7dvMsf3L7tytv2pXGXGmus0yb87Zdzt96spbG9GPvO5DY3j+YUT5GX726uw0PV4FjVJpm/3o65SOF4mRNnzrWlpsvk3B+7/wGtYxHU909B0nVE2q8L7i25dtdHo+oTSMqI8bIz/e3fNXnljqvlwhERmP8ddBo99DIqwsnlbfut/DUyp/aM41OWVj0Wz1gOyfvtu379ez/s8zRz2epvHISC8J2kY28PXzrZ6ttkZH2srfd/2a91/ZRuFm07WVA5EsBY7s5yHr9B8IqfL4gYR+VT/01M+u4Pqc3EFJf4v/AElkuvarAfFl9aTP928kC5X7vzGrH9uWklqnkuqP9193zNtrhfHWvmx+IGrRm5XZ9vnBU/7xrMXx4kcfyTr/AHdrV+a8T4WU8+xTj/z9n/6UznxOLgsZUj/el+bPSrfxA8PmbH+Rl2o0f8NXLfxZbxqEeaNGX5V+626vK5PG32iGKf7Sp/2Vaj/hLv3b7IV+V1+6q18tUwfNGXMa4fGcp7Pa69C3lvNNGV+9LGv8Na0fiKS1d4d/3fm2xv8ANXiOl+LplLbzJ8z/AHWbd/wGtuP4gJb3D6g9z9odk27m+XbXjVsHyn0OHxkJQjKx63/wkieWfkkiaHavlt825f71VdS8cWyyM8J2Bd3lRs25tv8AtV5n/wAJ07Ls+0sf3XzbX/h/iqje+NvMRJhMpSNdr7vvba5I4Pl956nd9eh0O/1DxY/lvczXKoNm7y/4v93bWPqviJ2jR3mYq3zOy/K1cNeeLnjkFtbOvzfL9371Zd94svW3Qo6u/wB7dv8A9WtaUcDUlyyPPqY/llY6PX/EE2353w+7564nVPFFzud98OPu7f4t1UtW8SujN51yu9v7r1yl9qzztLDDMqn7ySfe+9XvYXCy92MkcGIzE2pNc3SNc3L4Xf8Ad3fxU/T7pLiNn3qvzfeb/wBlrkpr2ZW2QuqKvzMv3t1bGm3k0j/I/mps2o2zbXrewjTieX/aHNI7OG+huoVT7Mvy/fVv4lq/a6gkeZHTytvzbWTcq1zelyTeX++uW3b9v3K1luLqTcnVt38X92s6lGEYF/XJc3NI+kIdQeSRHTdsV/7n3lrQhkST95cou2Nlbdv2rXDWviCaOEO/mOjPsSRm/eLWzp/iAyTfutzRrxukf7zf7S15VbByPbw+Mpcp2NjdObjzvJhd5v8Almvy7V/2a2LWRLdmk35bb8y7N23/AGmrkNP1q5dv+PlVWNvvN/DWjY6lbLIs2xk27v49u5qwjhPetLY6Y4vqzrIblLqM3CQxu6p/47/C1VppJWZzbNhmVm/efdZqrafqELfvPtmw/wDLWqV9qz3Tf6HtUSfdaZPmpRw3vPlFLF+7qUfEW+FWzMrlov8Alp8vl/7NefaxJ5Nr5kk292TZ5i/w112qXjtepO/l+XH/AAt/y0rn9WgSWGSOF/MCuvyx7Vruo4flPNrYiMpSZwesWsMl0z+Y37yL5N38X/Aa5rWNOQRlIbZijbmdv4d38S13Wp2e2Ty327V+Xy2+9/wGufvtPnWTYifOzs37z7telGjGR5NaS2kcLfWqeXl+GX5tv3WqmbflEhRc7d3mL93dXT61p/2xm2Qxuyt97Z96s0aX9on/AH0PzRv8+19u1q7Y0Tz/AGkuYk8O26bd95w6/wDj1dVo8CQzfvkY+Z/t7flrJ0fT5ftHzpy3zbfvMtdNp8KW7ZebJZsrtT5drVjWw/NO5tTrRien6CVT4a5hQ4FjMVU/8Crzu786Vvtlzt2/KrtIny7v9mvR/DP/ACT5MNn/AEWXlvq3WuN/s3zMJC6hfv7mT5a/X/Fmk3kuQX6YWP8A6TA+yz+rbC4N96a/JGVHap5i+cjfL8y/JtVv/sasLN/pMW+bdGyfLGv3d1LNYTNMtz9pVnVNvzfe/wB2mLb21r8m/wCVvk2/7W6vxGpheXU+a+uTHTfafLmlRGQLt2M33W/vVR1C+hWH7MHb5X3KzfK26rF95253SFX2vtl3P/D/ALNZWrSwq+x0Zzt/5af8s6qnhf7opYozbr7ZIpSGZdv3fm+6y1HY2s00n2Ysyfxbf7tTxxwwxvsmX+86tVm10+2kk89ptkzRb9rfdrf6qowI+tHMeOmgs7H7Nv3vJuVPn+avAvHGmvZ6hPbdXb7+2vZfih4mtrbXrPRPOjQR7mdpP4mrzL4hx2010LxJty/eZY678HTjTieRjcQ61TlPOILx7Wb+L+78z1T1qZ5GD722t/CtWNZmh8xnRPu1lX115kY2Phdv8Kferq5eU54lO4m8z50+U7qpSSPv379u75qmvN67kfd8v+zVCQ+Wdm9tqtSFH+Ukm2Mx2Ozbf4abHEWX/b/utUDSN5Z2fK38fz1Pp7edJ9/5v9qnGRUv7pXkXaNjpwr0zenmBNny1b1W0eNVd3/2flrP+dGHyUviCJJJb7t3l/NVdkZD861btZOf3xxVqS1SaFUoDm5SrpOsTWVwm58p/ErVtalp+la1Z/abOZUk+81c/eWZtmHerOl3H7l4XnxVRlylSj9pFCaF4pWhz92ihv8AXH+KijmNApsnanUMN3WpAVWx9/mpF+Zh3FRqu72pyBOfn7f3aCZbkzK6MPN5Vvu1EXOA3y4oZn27KYx+bPpQSDH5s+lNf7ppzL/t0BS1BoD/AHjSUUjHA4oAWt7wDIV1FzvxtXdurB74re+H7/8AE48sorGRNvzUES0iehra7bOLhtrP96qV9bpHNvG3C/w1oyXUMdr5OzezP8i/3ayb5nf7/wAzM9Bzx00PVf2EFiT9qHQvKxg217nH/XtJXu37ZMhh+IOlzl0GNGAjyuTuMsleA/sF3DyftU6ChdTm0vdwXt/o0te8/tooJPH+lh1ZlGjjAX1M0lfseGbj4D4u3/QUvypHBiJ/7RfyOF+HSwXPiK0e5+ZvN3bdu77tf0Of8EmNF8WP+wRF46+GTWf9t3sszWrasVSFpFXbGq/3a/ni0OH+w7q2uXfyp2dd0bPtVVr9ef8AgkZ+1Lovw5+DlnpX7Rmq3lh4It5ZLiy1KO48uO3ul+Zl2r975a/FKWIq0o+5ExjThKr755/8QP8Agop+0V8XNU174aeJ/A1jd6w3iCazv7e6vGVrdoW2su6vyP8A20virJ8YP2zvEusJCttbaWy6Xa28b7ljWNfm2t/vbq/XHxB40/YM0z44ax8e9N8bX1zDea9qWoy2MkWzdGysytX4h2mtW3i74j6/4th3GLU9burqBpPvKskzMv8A47XoSceSJ14eNRc0pHTxrlvsybXP95VqSNblbxETckX3tzfxVNaxvGq/PlW++1S6bp/2zUmkfbu/2nqfdLlGMT9LP+CEeqXLfFDxLo8MO3+0PAcyyqv3ZFWZfm+Wv0R/4V3c6lceYnmBJIvmj2fdavz+/wCDeNbCH9ojW7C/v42iX4fag3k7vu/vFavr39p79udPDX2zwB8FvLmvIf3V5qkafu7fcv8AC38TVvLERpxPGrx980f2hv2mvAH7MmkvonhLTbfWvFs0G2K137Y7P/ppNXwX448ZeJPHXiS48YeMNYk1XU7p5HuL6R9yx7v+Wcf91a1PFFxeXuoXGpalqsl5f3G55by4ZmaRm/2mrzjxJ4iNnILCwm82Xdu+98sa/wB7/ar53FVp1J3kClGXwnS/axD4WlvmXaI7WR8DtgE188+MviBqupXFxbWyKieay7o5f9Zur3eOaeT4a3MzMryHTrg5HQnD182yxpYyHzkV32bmj/h3fxV+veNMZSyPhtL/AKBI/wDpNMdpOSsVF0r7Urpf3O2JdzPJC275qp6tfW1vG3kusSLEy+X/ABNS63ryWy744eG3bI9//j1c3q11NJbx3+pIrK3yo2/btr8Lj7vum0Y8xl+KtecWro77Itm7az/M1eF/Evx0+r3j2NmyhF+Vttbnxg+I3nu+n6bdNu+622vMCWLfMcmvYwOFly88z1cLh+WN5BSMueRS0V6vKd4UjLnkUtFSA2L79OpFXbS1XxAFPt5HjkD/AO392mUm4qwokB3Xg3XHjm3u+dv3FWvTdP1B7yEb33btv/Av9mvDvD999nuNm/FeqeDNWeaNETafn/ielH3TmqROh1TRzqlk3+h5K/xf+y1k6bCn2O50yb5PMRo/ufw12tjJItizvt+b+Gub1zT3t77fZ/IG+Zt38S/7NXL+6KmeAataGw1Oe06eXKy177/wTr+H2s+K/jta63bR4ttLs5rq4btt27a8d8bacbnxncw2y8SOrbq/QX/glD8GrCL4S678S5kbfeaothYfL8skca7pPm/3q8/Mq31fCyZ6ODUZ143PRpPDMdrbx74WYb13sv8ADVy3sZrSGSZJt6/3VT+9XoWoeDXa+GYY1XZ/D93/AL6rOm8P2dqpt0tmMi/LEv3lr42o5z5bH2mHnCx5V4k+HngnxJH9m1Lwlpt5u+aVri3Vmrz3Xv2T/gVqrb4fAclqzbt7W9wyt/3zXvl/oLqqbLZUSN9u1v7v96ua1rTYYbh0O6Ir/DG27d/drSjjMQrxUth1MDhanvOJ8zeJv2E/hdqf7nRPEmoWMn8XmKrrXlnjL9hnx7pe+fwxPb6lEqfOqPtkZt3y7Vr7M1DTUt5GjdF/22X+Kov7Ff8AcokLI+zd5n97dXVRzTEwd5S0PNqZJhpS9z3T84vFnwk8eeDLw2fiHwreWx7eZbttrBk0yeFtkylTuxX6dT6PBHIXvLX7RuVfluolf/0KuW8Qfs//AAl8XGVNb+HVmC3zy3FunlSM27+8texRzilKPvHm1Mkr/YZ+dL27xln2fdr9F/2fQf8Ah3GgPX/hDNY/9Cuq838YfsGfDfVpJpvCWvXmnPu/1Nwu9F+X/vqvbfA/gC58C/sXXfgBrlJpLbwrqkQkj+628TsP/QhX7h4K4ujic3x/I/8AmGqf+lQPe4TwtfD4yv7Rf8u5fmj8vyMd/wAqGXdir13ot5azPbTQtvjfa2KgksblIw7wt/wKvyc+GUkQUU9oXU/PTSpWgsb/ABr9acu/HFGxvSjlTQT8Qd/nzQp2t8lJTQS2aCiTzvL+6cUskzSSM/8AepjDd1ooFyoVvmYmkopeWNBAsmVfikX5fn2Zpu75sU7+D8ar3TQX5Nu9P1pJm3/O4o/hLUYVvvmjmARVfvT9ybt1MBxyKEVzUi3Qr/eNCt/B0/2qMfwfxUHIBWq+EXMxY1zz61d0nWtY0kv/AGbctGZPvtVEsW60cqakSjzF/UtZ8Q3Ehh1DUpnPdTJWfuPIY8/3q0bXUklhFtefNt/1Tbfu1YXQnvJPtNnfwzIrfxPtb/vmiPILm5TH+8n3/lrY8OafG0h1K7Rtkf8Ad/vVfjsfD1nb+dqUMbO3/LOP+9UI1I3G2GzTyoV+7HVSJlItWcj3UzS/wt9/5614dn+p34+WsjTV2zfcU7f7tdFY26SR4RMt/tVUfeI+E47xlvWSJN/zL8tYVb/jtUjvhGm3b/s1gUG1P4TqfhfavJrC3Ozcq1+gn7Q9m17+wXdWi9W8LaZ+jW5r4K+G8f2azuLx32BU+Rq+/PjBcRN+wv8AaZMFG8KaWevqbev1zwufNlOd/wDYNL/0mZ9dwt/uuP8A+vT/ACkfm9d+H7yFm+T5f722qhW5s5G+dlr0aSOzulKeR/uMv8VZF54XS53ZTYrV+S8sT4mNSX2jC0zxLcxzLmb/AIE1dr4f1hJsbHXaqferi9Q8M3OnyF4UZlX7tLpOoXOnsu+baq/7dSVKMZHsdvdQyWYh343L/laqX9tYXUL2bvsX7q/3qxfC/iK1kgRLl1Zv71b9wvnfvkO7zH+Zv71ZmXwnNeI/2hvj9baTF8MYvjV4sXQYbhZYtI/t6byEkX7rKu7+GvozUv2v/wBrf9pb4S+Evgh+1L8Zda8ReD/DN59o8L6PcN8vnN8qyTMvzS7d3y7vu18vfEbR3juItbttqmNvnr9lv+CMvwF/ZC/bk/Yh8SfCXVdEtbbxjpOrW+o3HiSaJmlj02P5plX/AJ57fu/7VZVYxX90qpz+z90+Bv2qPhH8N/hH+yroPxOsPiFZt4q8QeI5rVPCKwN9pt7OFf3l1N/dVpNqr/er5T8AWV7f6u1xbDLj59tfv3/wU2/4JZfsjXH7IMfj7TfHepa94r8RWi2HwqtrOz2NIy7Wbf8A9M1XdX5z/sT/APBJP4tftDeKNUs/APhaS5n0fzP7bkvt0UFuse5mZmX+FvLatqco0qW9zjhWlL3ZqzPn2z0/UtLUQXkLIZIFbaybW21TtdD+0NI/k7R95K7/AOOXxWtvi58VG17SvAum+GNP0/S4dI03w/pbsyRx2+6Npmkb5mkkZWZm/wBqsfR9P/0V5JkUFn+796rjrHmZ6OFlzfaONk0HypPnf59/92o20ncrOm7d/u13lxoaIp875Tt+Vtv+srHk0J45G+Tb5j7nXdVxjyyNKn8pjW0bwrvmf+Kte1mfzN/+396mR2KQj54W+ZPlX71TW9juk+fdtj+5urblhI8mo+SoaMOobV2O+1f9n+GvoT9i68NzZ+Io2X5o5rYMfwkr5yhj2szp1b7m7+KvoT9hwyHTvEhkj2/vrX+Utfo3hNC3HmFflU/9NzPruCK3PxFRX+L/ANIkeX/GvWZLf4peIAjNui1WfP8Au7zXLf8ACWPgDev3KvfHNj/wuDxKqO2H1mdX/wBn5zXGMrxtsRMqv/LRa+Gz+nH+28U/+nk//SmePjakv7QrR/vS/NnRx+KppFCPCrKvzfNVy18RbrlZt7f3nrkFun8zZCG+b5mkWpIb65X99vZVVtrL5tfOVMPGXMXTxEonb2/iZI5N6TMFbcu7dU0Pi5BHs85TtfburjYdWRWT54/9U33qgTVJFjXhf73y1wVMHSl9k76ONnH3Tum8YTNIro7MnlbX+ek/4Sgbhsm+Vv8AvmuHhvnaUoX3M1WIdScrseZlCv8ALuSsY4Hk91HRHGc252MniR5FSbepC/f/AL1QXeuPNb/J8jN83365htYRoh5Zb5n/AOBVDcX03khN+fn+9V08HGOhz1cRKW5qahrEzfOdr/8ATRv4azrjVHuJNnyqf7y1Ukn27nRlLL/tVVWZ5Nv3t396vRp0fsnDKtOJoW949w33N38KyVv6PvjjWFNrrs2v81YGlwu8ez+NvuLXQ6LDcyPskhwsf975fmrSVP3TONSR0GnrNHsT5l+T51atu3t5lZEhdkOz59v8VYmmvcwxvDcpGdz/AHt/zVt6WzwyJNtY/P8AxfdkWuSVP3veNY1pHpl59pi2TPDsWTds+b5asRatNZzb0vGEWxWZf7zVl3urL5LI7qQy7kZU+7WXHq03nB4X2lf71aywvMdMcVyneabrX7tLlIWU7922Rvu/7VdFa6pHcxpN52/zHZXVfvLXmtjfQ7Yt8yt91tv8P+7XT+H/ABAkbfO6yRN8yKv3VasZYOPNsdMcZLuegx3UKrG7vIjt821f7tQ3jJJ87ybGV/k3P/DXOWurQ3O+Ge8kd/8Ad+6392lvtedo1SF2jf8A2ko+reRtLFR5CzePNqcnk+dt8tdibn+Vqz7y38uTGxoj95P7rLTmkdfke53Hb87SJ81VtSuP3aQw3KttlVWXb81dEcP7pySxRl6h53mHydv+q2/vE+7/AHax9UheFUme5Z/MTbtX+Fq3bmPzI5p/tPzq3yrWXNbpNcNN++RGVdnmfd/4DW9PD+8ccq3Nuc+ummZYv3KruZtjb/lamx6OskpdLPcf4/n/APHq6q30NJm2WtnxHuVvl+7/ALVX7HQ0hUbE3mT5Xk2bflrtjRgc/tmcjb6Pcr+5hdgVb5Nq7a39Jt3sU87e29Zf9X/z0XbWzb+H42f9yFKRy7dq/wALNWja+G3VNkkPm7X+fcn3v92j6sP6xE1tEhCeDBDjy/8AR5OB/DktXKeSkO9Emk+/95vm213QgZdLa3XJPlMB8vU89qw7rS/LjmfYqPD/AHn21+s+J9FyyjI12w0f/SYH2nE82sHgbf8APpflE5iSFGk3p/wL/ab/AGqpXCw7rgwpz/B5n95f7tbuq2qANND5bI332X73+1WDqUbyQumyNx8qxbXr8g+q9eU+O9tEydQv3baiTqHbd5/l/wALVkXF1iJcw7W/3q0NUmRoTDCi7V+aVl+X/drCurxI/Nd33vtVVVvurVxwfu+6ZyxRZtbhIZWjeCMrJ825k+7/ALNTLI9nDJePCr+TFu2/8CrPs9Qti62z2zD5FVlb7tZ3xO1qHS/Al68LtmOJtskf3l3fLWcsLOMveia+25jwD4tfFRNY8aaleJNytx97d/6DXOyePH1SHZ526ua8RL/rZvl3s/zN97dWPZ6pNDIfkqIx5TG/N7x0V9Ik1wz/AN77/wDtVmyfM4R/4f4akt7gyw/vPl/2v71RXi7tkzvhqCOWERk2z7jjlv4azry2dlb+9vq08iNMu/buX7lNupt3zpD/AB0ehcfdMqQJDnKfLup1vcOs6zBcU6ZnVnKbQWeqzb1X7/NOUh8p01vHDqlnwnK/wrWFdW6WuYXRlP8ABV/wjqyWt0IZn4Z60fGWgzW+L9Ifkk+b5aRPwyscuY2jkHzZ/wB6tnSbX7VAUf8Au1ntC9wq702lan0uR7e4/efdoCQzULWaGMpv+X+Cs+OTy2ztrodZVLi23oi7dn8Nc9JvWSguPvETM0jk5pVXbTU6/hT6qJoFFFFH2gClVj9zfik/4Bmj/geakBd3y7aSikY4HFXL+6Am3b82adRStyu+lEmQlFFFHKUFbfgWR49aV0P+zWJWr4P+XWEcpkrUkVPhPQ7xnaNfnX5f4l+8tZdxdJGp/c4Zk3VoXF09yqwv92sHVJsK3yYXb8qs9X7kTmPYf+CfCNd/tU6TM6bRFZ3jr75t3H9a+jv2sLeF/iRptzJGCyaKNrHt+9krwL/gm7pQk+OtvrzqAWt7hF+bn/UvX0L+1dOIvHGlqJGJOmgmLPGPMf5q/YMNb/iBGMt/0FL8qRwV05Yj3TyLxJC8MUd4j/3W+9X15+xPrz/FD4I3/wAKL/VY47j+0pEsFklZlVmhZV+WvjvxJvvf3KIse1NvzP8AK1dv+zX8Vrz4d6pczQ3LM0d5bzrHv2t8rfw7a/FsLU/e8pnLllSNv4sWHif4I/Cb4haN44SO31fT9BuINsifLM0jeWskf/AWr4x+FUDx2jFPn+X5fk+7X6lf8Fndc8B+Pf8AgnHo3xpsIoU1vUtcs9L+0Rr800bbpJFb/d21+ZXgSzSPTo977N33l/iruqRpKXuHXhuaOHXPudXu3WqfPtZv/Hqm0d3XUndtquz/ACf3fu0kCo1vs8nC/dWP+Kn2sKW0YmdPMPm/KqvU8oe9sfYH/BK/Xtb0n4vanqWg6xJb3Fx4PuoJWjZlZo2Zd3/oK19D+OL618LWLPcvJmTc7t93ctfJH7APxCm+H/jjVtYfSftzzeHLiCC183aqszL8zV6pr2tar4y1I6x4nuZEaTa3lq/yR/7K15mOxHs5csdzzsRHm1iS+LvGl54g86bSt0MX8Ks/3l/2awk0ua4maNIcK2399/e/2aluLqztbf7Tqu1FX5ov723+7VW61x2sRc3k32O1+bZDt/eyf3dteZ78Y80jKNM62OBYvh1dW4IAWxuBkNnH3+9fLWueJvPZ7PTX3FX2vJsr6U07UIdT+Cl1fWsTQq+k3YVSeVwJB+fFfLFx9jtYXMyNmP5ot1ftHjRJ/wBh8N2/6BIf+k0yo6Fa8W2sYftNzNu2y7v3n8VeT/F34i+RbTQR3Pzbm2r0+9XRfEzxtbW9tNsuWRF+b5v4q+ffFXiK58R6q9/NwD9xfSvxjL8L7T3pHrYPD/bZUurqa8uHuLl8u33mqOiivoPhPSCiiiqjsAUUUUSkBc0+GFoi7puqO4sHj5TmptKu4rdZFuXONvyIKn09od3+kuoH93dWMvdkZe9GRlEbOGGKA27mtPVI9NkuGENyr/7VUprN41zvX/gNVGXNuacyGwSFJg6jNd/4C1aG4u0R3+feu35K88VvLf5K2vC+ofZbwfPj+41XykSifQWm3yfY98zrtb79YXibVPtEMiPeKnl/dXZuZqoaX4ge40N33r8vy1zt9qzzTtvdh8u16XNzHPHmiZGqNCNQa837ZVT5GVPu1+0v7KvwR/4VD+yf4F8AfYNlw2jR6jfyRr964uP3jM3/AH0tfld+xv8As6ar+1Z+094P+BuiOuNW1aN9SZvvR2cP7yVv++Vr93PE3hu2jmfR9NRktreJYLJd+7y4412r/wCOrXkZpK8LM9HAy5avNKJ4dqHhPzlbfu+X+FvvVjXGkuuIURQ7N8jK3zV6zrmivbzbERU/h2q3zM1cjq2g7V4hz/F935q+ZrSlGWh9RRrR+KJ5jr2n+ZI8c22It8u2T+KuK8QafCzK6eWHX7vl/wB3+7XpviTS7xZNn2ZRD935vvNXF65a2yrLZwzQr/DtX71cUf3nvLQ9iniPaQOEuLOb7Zvj2lZNzbflpq2P+tDvIrLKo8uRvvVoapa7djw7d6uyxTNF80f/AMVUEzIsaJMjGRdv7xa09pCUrlyjzRuV2s/uwvMrsr/uvlpF86HzIZodq/xs3y/N/s1ft5I2khTydpX5d33adJavPuNzeK4j3bVZ/l3VcanLuTKP8pg31rPJHhLZt2xt7ferY1hFtfgRq4hHCaBfED32SGiHT5rq3GxG2/eZWXarVo+JrSGT4V6tZiIRpJo12pUdBmN8/wA6/oDwE5f7cx7j/wBAtT/0qmd+Uc/1ivzfyP8AQ/Mbw34Xv9a1p/tkLHdL/rF/ir1vSfhH4YXSnm1iwjkTytyNt+7XXfDv4V6bp2lrrFzHH5S/N8y7dv8A8VXK/F74hW2lrJbabc/d+Vdvy/LXwq5IrmPxv35zPLvil4X8Daey/wBlWDRP/Ftf5a8/lsUWT5Pu/wB5q1/EGtSalcO/nMV3/wAX3qp29q903mCo5uY6I+77pUh0ma6/1Kfd/vUv/CM6kq7xDuFdLoul7m+40qfxNWtdR2dpb796jb8q/wC1VcqJjLseezaTc26/vrZh/tVXa3f7ipXX6xqkNwGTYrLWRb29t53qzfwrUy/ulRqGMUfhKVY2YZH92t9NIs2/1iferRtdC01o13w7lp8oe0Zx6283UJTvss+MeV/wKvQ9N8M6JcYT7M3/AAGui0TwfoMMqv8A2bDt2bd01HKTKsePx6ReTfchZto3fKtOGh6kzbPscmf4dy172sem6XZva2Gm2+1vmdmiXdWKuh3PiLUEcQ72V/4Up8sQ9pI8butJv7OPzrm1ZV/vNUUaxPJhn42/3a9H+MmgpoukxLs+fdtZq8+02DdMsv8ACv36g15vcLdj4ZmvId+9VH+1TL3Q3sF/1i7WFdFZ/u7Mv/33urC1y53Myb8/w7d1BnGU5GUW2sSetM3O336c4yd3rTaDaIoYrR5jr/q3pKKuMSiSNsHe/wD+1Usb7W3pxUC71+THzVL87Y+7/utUGZMD50gff1+/VmE/88+WV6qRqi/f3VatvNZgifKy/wAW+jnIlH3jc0k+Wy70+999a6Cx2La750z/AH1WsDS5EmZP3e7+Gt6SRILAyOmAqfJt+VmoEcL4yuPO1Zk/hWsqJPMkEP8Aef71SalcPd3zzP8A36seH7f7Vq0cPbfWsTX4Ynaw2b6L4RZF+9JFur7c+PErw/8ABOYyxk7h4L0jB/G2r401fUbbTbeGzdG27fusvy19q/HuzOof8E/ZbSDjf4Q0vb+dua/W/C582U55/wBg0v8A0mZ9bwmmsJj7/wDPp/kz89tH8WTW6t9pfctdTpOsQ3UKO/zL/tVwl/ot/p8jJMjUyx1K8sZB87Y/u1+Pnx3LGXvRPS2sbK8Uokasuz7tYmreEUjj3pD/ALX3ab4b8Xoy+TM6ru+V2rrPtFtcQ+dDt+593furSMiLTOK06P7KyTRpg13fhnU4bixa2mT738X92sfWNH3Ik0MOC3+zTNHknspt5mYL/d20EzNfxdpfnafKjorBk2oypX0d/wAEN/jI/wANv2vPD/hjXvEOpW2i61fx6dq1rZ3TItxD97ay/wAS7v4a8EvJE1DTVTzsPs+638VZPwD8aXnwk+OGleKoXxLY6jDdRbv7yybmqJ04VKckKXMf0QR/tP8A7HnxW/bE0fwfqvhLUNHtPBeuNomh2eqaivkQ7d0lzcNH/CzNtVa8u/ZO8FeLL/4qeLPA+hftAar4N8NeOfEN5YX8mjxKslxp7TNtVWb7rMrferxj4nfDvwNJ8dvD37QmleNtJ1uHx9YTa59jsZ1Z9L8uNdzSL/DubctdD/wTh+JXh74+ftHRaJrviT7NYSSzNpax/K00y7tu5v4V3VxYiE48vIzzuWrWxPNLSx8bf8FZPgN8OP2cv+ChXiz4QfBjw5qFn4Y0XT9PTSnvl3fa28v99cK38Ss1eS6DYpJpYe5RkdXZWX+Kv1Y/bB+FPw9/bq8B+J/iXr2jx3njj4b6yunf2Lotwvm6lp8LfvJPMX+Lbu2/7tfmNoWr+G/F2paxqXhTw9Np1guqXCWFjcXXmyxwq21VaT+9XZGp7Slc78vlKVfkZl/YYZo2CQ8R/N+8rP1TS0ZmSBP7rbVrrG01GZN/7oqitu+9UV1YpcKr/ZmJX+Ja1jL7J21v5jg5NNmjbfs2/P8AJHt+7U9rZhd3nPs/irdvtLmjnPyb9yfMy/dqFdNhhkbzoWKqv3lrqjseLUqe9eJgLv2h7ny9y/L833dtfQf7F0AgsPEKZyfOts/lJXiq2KyZQ87k+9Xt37G9s9vZeICxB3SWpyvTO2TNfo3hR/yXmF9Kn/puZ9RwGn/rLQb/AL3/AKRI8K+OtqW+LPiTK5Da1Oc+nzmuJaPy12b2/wDZa9F+N1u0vxT8RyBE2rq8+5j/AL5rh7q3kVNibflT7zfxV8Xnn/I7xX/Xyf8A6UzxsdUlHMa3+OX5sypGeHdvRt38FMaQMp2bdy/eq59nuYY13ybfkqvH/rDv2/N97an3q8XlkRGUSLzkXr87LQziMN5O13k/h/u1JDbuyum/bt+41OmhRsOm7ev8TfxVyyjyyOynLmhzCQtNHGvo393+KpVuMQ+fs3M38NFrGkakPw33qGhRZEhO4q3zbv7tZSidEZe6PkuNq/uU+VU/h+akMjyN5+9fm+VPmpI4CqnyduPu/LU1tp+795sUfxbVWp5UORDHHt+d92V+6uyrml6XLfAbE+7/ABVYtbOa4m2eR975dypXXaDoMMcA/iXZ/c/iropnJXM/SfDLy5eH+FdvzfxNW5a+Gd02xJmlMfzL/vV0nh/wpDcSfaPI4+8i7P4q6Gx8IpNGNiqrt825Vq5ROL2n8pxNtotzCuzyWZv4NqfdrVTT5rfHnTbGVd3+ztrt28J39q0bpbMzNF83l/dqhfeEzGrzOkY8v7qyKzfM38NZ1I83wm0ef7Q/Vmv2nZ/JXDL8/wDdrAmv5vtR+dcbP7ldHfRzNDK8xZdz7drfw1y+pQw27fO+/d/dr6GOFhyeZxRxUuYlh1Y27Rpsk+b5vM+981bun695duNjt8r7trf3a5FZ0hU/eR/lVGarSXUxQIn3l+bctU8vjL7JrHHSjqd3/wAJQ8jb0mj3qisir/7N/tVaj8SPN5rpc79qf6v/ANmrgIb+ZFZ34M33G+9U32zYzb3xIrrsVf7tFLK+aLsVLMLwudxD4u/1aB2Zf4/Lf5m/2aY+oPIrOZoV3P8AdkbbJ/vf7Vctb6gLrbczp5bt8rq3/staulrHFL/pO0q3ypGv3lWtP7N5TL69zGwtwt7NshRQ/wB1Wb+Kpre3uVki865Vw3yvCqfw1Xt7OFfK2O2FfcjN/eratbNftQtpnbH3mbZVrL+U5/rnvF3R7GaSaP51bb8yLv2tu/2q6a10kqwhd42f73yvuVd1Q6Do/wC5aZ0jZF+42z5ttdhpGnpax+TMjNFJtbdJ96pjg77DljOWPvGHH4bTy2eSH545fkbyvvf7LVch8PzCP98jf6rduj+6rf3a6L7HDt8mT5n81fKZv4Vq4ui/M7wou/5vmaqjQ5Yk/WOY42dJHvjHMcMzgHd2qvrGk7W3w/N5i/e+8u6tHVIjB4geLptmHJOfTmpdSsYY9nkuz7tzMv8AFX6n4h0efKcnfbDx/wDSYH3XGOI9ngstfeivyicDrFnthz9yJkZX/irmbyHzIf3G4bk2MzJ/49Xe+IIf3a7EVdu5tq1xepxvCGkd2Mrff/dfdr8zp4fsfC1MRynH61b7pD+52IvyszP97+7XPX0LR7Xd9y/KrqtdZrVrumaHyd8ez59v3d1c7qEbsySG23fPt3bv/Za6Y4HljZRMI4iXxGX5EzKz72Rmb71c18Wle78NzQw7R5n3t33ttdXtuftHz7T8nzR/3a5P4sSbdPTZuiPzfNs/8drkzHC+zwrkduFrx5uU+bdc0+2maVC/3Xrm7yzSPc6bcLWlr2pPJqUqu+G3/dWol/fJsyuG/wDHa+U+LRHpR+H3inDK6qr7FVVT73+1VtmS8gYJJudv4qimtXDfvCxVvl21CsgjkRNjfL9xd1OISiQXCvHNs2KV/vVG0ybdjp8q/dapLp0kLbE/36oXk7x4kR/mqvcCN/hLMkL3C5jT7v3WqpcQtGuzHzfxtSR3jxYdDy33vmq1HIky7+rf3TWZcpcupnQsYZN/da9E8G61pvirRZtB1P8A13lbYm/u1wd1YzIvnJytO0fVbnQ75byHcpoHpI0tU0m60XUJLO5Rl2v95v4qrTQ+SwdOVZK66+jtvHGjjVYfluY12s33a5Vle1keGaRsr/C1HL9omIlrcZj2z7v92s/UI/LkLp93/aq1eSJuZ0T/AIFWfM+6TO/5auMiojA27mikVdtLTNQopD8vz4paACm7dvzZp6feFJU+6AUU3P3aU/N8maIgLRRRR8QBSMueRS0UcoBWr4PV21hNj4rKrT8J7/7VXYmSv8NSKXwnaXDItqPm/wBZu+b+7WBrEm3ds6/3fvVt3kjrA0f3VWsDyZtS1aCzhhYmSVV+WiX8xgfTf/BPOzew+I+hRykF547uVyOx8h69p/a0Rm8daYf4f7LAf2HmvXD/ALHei2lh8VNLa3UKkdnKEQptKt5Dbq739qtW/wCE+0uQu20aV90DOT5j1+xYGUf+IEYxr/oKX5UjyZ1IuvzHjmvW8ysiF1likT5F+61V/BNi9x4otJtNds+btbb/AOgtVjUo7/VNSWzs0x8+yLb8zV9Cfsm/sm+IfGmrLPbeFbq6upmV7O3t4tvzf89JP9mvxXC0Z1JmcsRClE8k/wCCkPxB8T2/7MPw8+C+qQ3CQXXiKbUovMf5f3cfl/8As1fPvhfENnDshVVjT71fUv8AwXD8Dn4Z/E/4X/DfUb9brU10O6v9S8l9yQtJIqqq/wDfNfMuixosaJD86Lt2K33q7uX3z0Kc5OlC5u2ph8vfNMzD726lWZGhEJT5v9yrvhnwzf8AiTVLXQdKhmuLm6uFjit44t25m/hWtD4lfDHxn8J/EX9j+LdK+zTb22x7lk3f8CX+KnGXKV9s9K/ZT/c6pfzQtGv+i7d0i/L/AL1e1LeXOrXDw6UnzRvteaZPkXdXjv7JOm22qXmow38MjpHbrLKv/Avlr1zxJ4qs7O4/srTYI43X7qx/eX/erycdKlGrzHl1pctWxFq1xYaAN7zfabz5l/vIv+6tcT4k1C8EM2sPeK00MX/AF/3a2vst1cyb7y8VFb5vO+9trkviJqT2+mw6Vsxudmlrx61aX2zHm5j1HwTI0n7OrSzRk7tGvSUz1GZeK+QPGnipY43s7ObcjfMzN/DX1x4PkD/syzOjdNBvgCPbzRX54fGPxzFYPL4e0yZmuZPluJP4VX+7X7v4uUJYjJOG1/1Bw/8ASaZ1YajKtPQ5n4meNn12+/s61uWe2h+Uf7VckuMcUrAt1NIq7a/LKNONOHLE92MfZx5QVccmlpGOBxQrbq1+EsWiiinHYAooopgOjj8yVUP8VDRPtZ9mQv8AFTaWOR49yJ0aswEqSGbayh32rUdFXyoCSaRGbeny062nMUoZRwKhqS3jfd/s1ApRO+8G6w81q9tM7bWT+H+Kq2qXjx5m2fd/u/erG8O6klrJvmfb/do1jXHmm+5xvpy90x5T6p/4IveOx4O/4KZ/DCXztg1a7utLn/3ZoWVf/Hq/cjXtBSx8+wSH5o5WRlm+996v53/+CfHiF/D37c/wk1p5mZrfx9p/zL/tTKv/ALNX9InjSzRdW1ATQsrfapG+Zv8AaryMdR5pG9OpyxPKfEuj2d0r+TDJCy/K275mWuM1aGGOeZHTcsfy7fK+98v3q9J8Sectu0bzMrN/F/d/2VriNUs90LTWz5Xyvn8z71eJWo8vuuJ6dHFcu55T4is5o5Hh8nasn/LST7tcLrlgm6XfDsdflVf4f96vUfFFsk0jpH5ibvvs38VcJrVrDDHNM7/OrfeauPlpS91Ht4XEcx55rFrmN8vu+8v91qobphGjzWfKqvy/xNW9qlrNZ3H7na+35fmbcrVlSWsLTJN5zLt3fK396sp0+V2jHQ9eNT3SrDG87SwzJHs2723L83/AWq3Z2/mKj9WX5vu1Fb6f9okea8RRIz/JtrWhV1s/3MOdvyvH/dq+WMpxM5S5feD+z3jkRJvu7d+6NvmVqZr8DL4K1GDdknTpwCVx1Rq19Nhdlj+Rc/3tny0zVLe1eGe2UEwtGVwR1Uiv3/wGp8mdZg/+oWp/6VA9LJKntK9Vf3H+aPiDWvH02n6HPps15t2ysGjX7qt/s14D441681a+d5psru/v16/+0xbw+H/GV3ptnbLDFM7Mir/vfNXlFv4dutQk3vbKV3/xV+e017SlE/JqkfZ1ZHJw2M11J5wh+X+9XQ6XoW2Nbl027W3V0Fv4ZsdN3b3Xev8ADWZrmtWdirJDNg7PmrYz+IS61CHTV2QhQfvba5zWNceRzBJNz/e31R1LXHumd0Rs7flaqLfN87/e/wBqlzcxUYltrhPMCI+fl+WrNv8AOo2J8/8AG1U4Y3kkCJ0rW03S5ZtrojZ/jqOWYvhC1WZhv2fL935q0tNXzm+dGVd3y1Nb6P5G15nY7vvbv4mrQ0+z2y/O6rtrQjm5dS7o9v5arvm/2katRtW8lVd/vb/vbP4qzluraGPZCm5qb/aEClt/y/8ATPd97/apSCXMdBp+nzaq2z77t8v/AAKu60HwnZ6DYia5dd/91vvf8Crz/QfElnp6rNM/zL821XrTuviJc30DW9u+8NubbJ/dqZe9rEOWUuU4X9o7Ura4voLa3m37f4l+61cNoVt8u/yd27+GtP4mX1zqGvL9p+UKn3ah0eNLdWHyk7Pu76Rr8MNSbWr57WFYYXbDJ861zV5MZmxs4/vVf1i+eaT7+Qvy1lSOm7ATbT+H3R04yEc7Dg0jDI4of7pp25NuacTRiUUUA7e3P8NSUOX5m+c4qXzFPzpubb/epiqjLn5s09f/AB2gzJI1jaNX+bP8dW7Pf5nnGNiN/wB2qm5Fj378n7vy1e0xn4Kbg3+1VcpMjf01Xl27/u/e2qtWPFGqJDpJTGG2/I2/5qk0W3O5Xf5VrG+I12rSR20fy/7NOK5SPtnJv9010fw9037VqyzOm7b93/Zrna7X4d2otbGa/k/u7aZtU+Eh8Yapu1BofO3iNdv3/u19/fFuYQfsDRTEDA8IaT1/7d6/ObVm8y/km+bDSs1foh8bWCf8E9N3UDwbpP8A7bV+t+F//Ipzz/sGl/6TM+t4VVsDj/8Ar0/ykfFF1bWGpWrNIin/AHqw9Y8BecrPbJg/wruqbTtVeT/lhs8v+9/FXT6TfR3S4MKlv4F/u1+Rcx8T/eieVtbX+l3DI4ZWWuh8NeLHtYwk3zfNt3NXT+JvC9hqlq9/bKu7+7/FXE3mi3mmt53ksqr92nL+aJftOY9F0vWrbVF8l3yPvbV/vVJqGj741ubbaP4dtcBoesXNjMvzso313Hh/xBDqGIZn+6+7d/epxl7pEy1o9vcs374fKvy7a5fx3b/ZdUhmSFsLPXZTW/kyfabZ2+Z/k21g+NtPmvlivLlG+X5mVaqMf5RS5j7/AP2JZpvin8K/CNnc2cNmNJ066066ks2/eTfeZVkrC/4J8eILPS/2gLGbXrm4g01tUmgezs9ytJuk8vb8vzLtrs/+CWqeAPF37F/jnRPDsN1N4o0nxbp9+8kny+Tp+1vOkX/0GvMvh7eal4P/AGltetvD141s1rq7T2TK3zeSzbttEY81GXIcsoylXPufxT+0T4i/4I+/HHxJ4mb9muC5sPiF4QuZ/Cr6zOIvs8kbMquy/wAWGb/gW6vzh+E8mpapoN9rGq+T9tvr+S6uo4V2xeZJI0jKv93burv/APgrh4y+PvxA+Pvhjxx8aviVqeurceGo7Tw+s4WOK1s1VW8tY1/2v4q4z4I2rzeF5Em2sv2hfl/2lX71c8aMqcbnVhKcadU3mtUaQPM+3cnzxr93/dqCbSkWQ2sXzq33tqVu/Z/Lb50+X733futVaRXt5Hm37tu7bt+63+zWlOPNM6K0uWBy81m7SGzeFfli+8vyrVRdPRV81PufxMtbt8uxdhm/1i/Myr/47UMmmpDMzpyNu3/Zrt+zZng1Jc1W8TBW1hb5ETb/ABOzfw17F+ypbJbwa6FdTmW3zt+kleX3EfyvM+7ezKqt/s16r+y3EUtNccOCr3ELKQMdnr9G8J/+S7wvpU/9NzPq+BJc/FFB/wCP/wBIkeNfGW1B+JOvYTKnVZmdf73zmuKvLFJZk2QqW+Xau2vUfidoUkvxD1qZZdobUpnw3f5jXPXHhmFmV5rZk/utXxmeR5s7xV/+fk//AEpng5jWtmVb/HL82efSWfmQvvjbc3+q/h21VuNN2sg2Ln+Na7u+8LTW43ptdPmVFase60OFgmxPvP8APuryvc+Ewpy974jlmt5lykKN8zfd/u09dPfcnyfL/F838X+7W1No77vJ87au/wCXy/uqtRLprtMYX27925f9quWUT0sPU93lM2PT32b3Xb833Wf5qmWyeNdi7S33ttaUMKRtsSFSv96nQQvGyo6Ns/vMtYyiehT3MtbF5NzQow+T7v8AtVftbF5lRIQq/wAPzfxVLAschZIYW+ZvvMlbml6Wkql7bk/d+aol/KORNoWk+Xb73+7/AHdld34Z8LmT959mjYf+PVR8M6Huj8mdGHmJt3bdzbf9mvV/BvhdDl/J8uLYqPHGnzNWlPkictT3iDQfBrraxQmFmEi7t237tdboPgd2V/MtmH8PmeV96um0PwrDZwtNclvmZdkbfw11lnpNtaqHeHEUjbNuzdtrOVb7Jj7CBwX/AAr/AMxWtjbSb5Pmikj+b5qyNc8D2y5SFN38X+7XslrpNnMrfPvVX2pt/vVQ1DwXYLC8KWzY3fN/dojLm+IUqZ836hZ/Z4wZrZtuz7q1y+uWLrG6PDgr92u81zTXmkaBIcqrs21f7tcdq1uitshTllbbuf8Ahr9F+r+6fKU63LI5Zi7XCpDMr+Z8u1v4dtPWGaFVgdGETfM+1/mb5qdcK8kjwlGYL99tn96pLeGFdltbWzbY12/vK6KeHtC8Tb23tPdHSWaKpdHZmaX7u77tOW1IzN827Z8vl/NSWilpPubhu2/K/wB2nstst2Y4XkKr8u77u2uijh7fZOeVb3CzpNnC0nnGZn8x922uh0mRFmf51+6pX5PmVa5qzW5kYfPuH8W5K6LTWmuE3oivtf5mX5WqpYOUfjJ+sc3unQ6XHtuP3zrtZflXZ/DXQ6fGjXEU32lmO3y33NWFpbIjI6P5vyfvVk+Wuo8OxldkM9tGn/AqwqUYRNIy9w6/wfZvFD9mk2na7Lu/vL/vV2GmWME0KI6SbI/9Uslcr4ZaGH+CTbJF80a/ers9Lk2wo824qu1fmf5v+BVw1I8srx+EuMoyjYuNYpNuCQxuy/xN/eqRbV5IxD0ff87LT0kT7RNG7xsn8P8ADtanIyXFul5M8jHZs3b9vy0uXsRKXKcFr8Mdt42eDAdUuYweeG4WtXWrBGaeb5S+z5VX71ZevqqeOmWNcgXMQAYdeFrb1KTzI2kgTJh+4qxfMrV+nceJf2blKf8Az4j/AOkxP0Hjdx/s/K3/ANOY/lE4TXrW2ms3RI2WSTciq3y//s1x+sXX2NUfZ80e1XjVd3zV3muWsbSOjvh/mZVZfm3VyGpWn2Jkd3Vk2/dVv++q/PqdM/Pub7RxusPDeySzO+X835l+6zVyOpRwNIz7JIy27fu/hrttUj8n5EkmL/3W/u1yuoWb3i+d9mVVZv8AWK//AI7XoYWPxKRnze+Y7w2SyG5fd/Cv+9/tVxfxesoWs4kSFg7O37xn/wBn5a9Alh3TH5GRWTbtauQ+L2nvb+G01B0V0tbqOX/gO75m3Vx51h1Uy+fL9k6cHW5cTFSPkHxBa/Y9Uld3+ZZW30+zZA29EY7vuVvfGbw9Np/iKa8hhbyZH3xf7tc3pbbmbY7f7tfmkf7x9R8RamkO3+6v8Tf3az7r+JML/vK9WbyZEU79y/7VUJpPOY/7X/j1P4ZBKMSORvNC7EVV/wBmqNwok27+Garc33VQPgf7NVmciTZsZqfL7pUSpL/rClCzTR/x4NXG035WkfpVV7dlByPu+tLmNOaMi7Y6s8kohm+ZP9yrl5psN3++T+5/crDU+WM5rqvAz2epI2n3O3zNvyM1EiJR/lM7w/rVzoOobN+6Nn+f/arY1aOz1KP7fpu3Lf8ALOsjxFov2W6KJtG3+L+9Wbbahc6fwjsv+0tTy8xXvDtQV1B38f7NU1+X71Wb65+1S+bvzVb7/tiq/ulREVtpzTw27mm+X70qrtoiULRRRTlsAUUUituo9wBaGXdiiimArM7cvSUUitvbFZgCrtpaKKACtjwWv/E0WaP7y1jK2eDW14Ng3XDzdlq47Cl8Jv6szrCzydG/u1r/AAD8IzeLviBbbE/dWrNOzM33dtc94gn/AHexP4q+0/8AgkP+xn48/aEk1nUvDGgzXO5lt4pPI/1ar8zM1T7OVT3EefiqnsaHMaf7OOnT2vxYsW8ghBDPliMf8smr1jxx8FfEXxs+K2keFvCeiXuqajc2fl2en2EO93k3sVJ9Bz1r374g/wDBO7Uf2e/DJ+J0sbyTWEEcepCdQptWkcRqBjqzFuR2ANbH7LviDU7bxFp+jeGNXbS9TXWVnXUbeH97ghFRN/8AdyHO33r9ryrDxpeB2KjP/oKT/CkeB7R1KXMjE+BP/BInQfhHq1tqX7Q2txprk0S3D+H7FvNntZGb5Vkb7u6vq3wn8PdK+Gvh2Wz8K6DJoVqsX/H1ffNcyL/vLXf+JJrDT/F194kjhuPEmrSOqXV95W35lX+Fvu1558Trrxnr0n2a9maC2k3K9naxNLLu/wBpvu1+URiqceWETJUf3vMz8bf+C3Grf2l+31p2g/aZJY9L8HWbRMzbvmkZmavCNPtXVvPf/lp/er07/gpxZu3/AAUZ8T6VePIr2OmWkT+c25t3l7v/AGavOLOHzpAj3Kr5bVwy+I+ljH91FnuH7JenfYdZ1Pxgk0aT2tk0Fv5z7WXzF/eSL/tKtQftHx22reE7DVU1KM/ZZ18pVl3yeXu27m/vbq5v4P8AxY0T4a6tNc+PLBr3SZE23Edvu3r8vysv97/dq/8AtG/Hrwx8VrrTLDwNo8lrpdnYQpPI1ksX2iRfu7V+8qrUS96pYyjz/Ea37Ndxr32e7s9NSR/MTa0kf+9/6DXrjaVZ6T5t/MitMybt0n8VeVfst3D2y6jPbOq/ul+bzf738Nek3Fwk0j793krF+93fw189mcX9ZvE82tz8w2+ZLiN7+aGN7fY3y/3v96vGPih4y87WpLCzTzdqY8yN/lWuk+JXxNext5tE0GaSG5mX/XKm5fm+WvIPGGpJ4P0ebUtbud02z7sn8TV5nL7afKRTjzep9T+D559N/YzvLuJ8yQ+FtUkRgc8gTsDX5c3d5cahcveXMrPJI2WZq/Sj4PavJr3/AAT4n1iXOZ/CGstz6ZugP0Ffmh5ntX9LeKMFDIuHu6wkF/5LTPZwEeVzXZjg27mikVdtLX46eiFFFFTzAFFFFUAUMdvWikZd1AC0UUUAFFFFTaYC/dapYztRnZ//ALKlmhRbVJg/zf3aYvzff+796jlMx6yTffBw1Cs8jHe+TTJGy3yU9Ng46VIHd/syatPof7RHgLV7WXy3t/G+lyLI3/X1HX9QvxChS41698mzVUW4Zom3/wCsr+Vv4fag2leN9G1VGw9nrNrKrbf7sytX9TnjDUEuLq3v9i7brTrWf/eZreNq48VT5uWREpcvvHBeIJt0bJIm4Rt821/u1xfihYbfda745vl+X/ZrstcuJlWXZCsvmM3yx/LtrifEXk/8toVT+4y/w15tajzaG9OpKUjgdcjma+3j5Xji/wCAtXC63bv5jvvVNy/vVZ/mVq7/AMTTIzP5KLsb5fMWuE8Qb0hXyX85mVllVv7q/wAVebOlGjK57GHqSicHqEMK+a802yJX+61ZMyzSKnyKrrLt2s/3q2dUvIYf9S+zc+5P4ttZLNE3yO7I7P8AeWKo9jzS5uY9SniPcCzhmvIUmSFQ6pul8n7tXNPtZt3k+ZJ8z7Nu3726jT7O2SHa/wAi/e3f7VXbXfb3CukzOn3vJX5f+BNSp0+WroOpU5Y8xb0+NLWzms4bnHlv8jM+5lb+6tV9XbyJJnmbAVMsfT5c1es4ZnjjTfGHm3M8aru+X+GsTxrP9g0DU7hgD5FhKxBXrtjPb8K/evAxp55mCX/QLU/9Kgexw1Uc8VWb/wCfb/NHwl+0RqFtr/xSu0d5H2vtT+L5q4q4utN0G18m5dR/tL81W/GWvPda/c6lN/rZpWavN/El9PdXDfvGC72r85hH91FH5nUl7SrKUi94m8bvdGVC/wDB8rL/ABVx11qE11Lvkm3Nt21O1reXDL5aN/3zWto/gXUr5kRLZn3fxbaqMbkxkc5BbzSfchZq19L8LXl0yfuW+Z/u7K9J8D/APVrxftNzats/i2rXZXHgfQPBOmrc6rAsUS/KrN96tOWFOXvGftPf908x0P4b3Jj86/RlT+P5f/Za1pLXQ/D9l9xd7P8AI38W2q3i74rabbzNb6JC2F+Xds+9XFy61rGsTec/X/aqJS5jT3pam5qWvQySecnWqEmvXPl/IWDfd2rTFtbWEGa/dl2/3q2vB9x4evFcw2DS7U+9J95v92p5uUj3zAW88Q3G7ZDINv8AeT71QNB4n3b/ALHIv+01eoWOraHZsAmnR7F++s1X77V/CV9CpfR1R/vfu/us1Iv3vsnktnda2v8Ax82zf3vmrVs9aeZRvfb8nybf4a7xbbwHfE+SlxEP9pN1VrzwHol5bG50y5xt/h27a0+H4SJHmfij/iaa4JvLbCr/AN9Uy6keGEH5V/vf3ttXdY2R60/k9IX2bqxNW1BGmcb2/u/dqPt+6aGbdS+ZIRvYhXqCl65NJT+I2iHBFIq44FCrtpyfeFUEgZdu6mKNq7yKk+8xSmqNvSgOYdG3zBEqS43x7k602nq7qmwfN/vUEj4W8xW7N/erS0mBJNvz7mrNt1cM+9M1saDGhmRP7396gmR1Fuk0dutyk20Km3dt3VwvinU31TVHn37gvy7q7XXdQTS9DZ/lQ7PkXdXnRdnJduu7mojzjgLCpllCJ/E1ekaXappvhuJAn+u+auA0S2+0X6J/tV3Oragn+jabHtTy0Vt1P7QVJfZMnVNK+bzpOGWvvX47Ar/wTxKqQP8AijtIA3dOttXxEslteW+9EZ9rN95K+4vjzEJP+CfkkQXg+ENKAH421fr/AIYa5Pnn/YNL/wBJmfXcKaYPHv8A6dP8pH5+6fcMW2P1+9WzZzPGyuPlb7y7XrEjhmttu9P/AB/dWrZ/M2/fX5DHY+M5jo7K++QI77tq/wBypNQ0m21CEuiK52/drHtZHXc5f/c+etWzuvLK/d+WtTLlkcnq3hu4sZj95N3zVJpd2beRE+ZStd/qGl22tWXyQru/hZa4/WNDezm2Q7i38W1Ky5UaR/lZ1tjq32jS4kd9/wAv3V/hqDWl+1W/91GrD8N332VhC+3av3K39QkS4s3dHUfxKtVGX8xnUjOR9if8EWdW1XVPiN4z+CFheeUPGHgi8giaP5WaSP5lWrf/AAhqL4p/4SqzSNJrVvKut27zWZW2t83/AAGvDf8AgnH8Vtb+EP7W3gXxVZzR25bXo7O6aSXav2eb923/AKFXv/xgk174L/tReNPh7co0ljp+tzeVDJ8q7ZG8xW3fxfe+9W1GPNKSOWp7soM5v/gplJpXiZfAPiHTLyaabT/D6xXCyS7tsjSN/wB81zH7PsLr4G+0zQ+an2j5l2fdar/7QVunijRfO8+PyVg3RQxpuZW/u0vwH002fwrs3udyPJLI7r/EvzfdauepFxid1GMvanS3Cv5P2l7bb82379ZuqMkKpsmxF95l/utVy/ZDIZodoVk+X5/mX5vu1zuuagkDSJ52359u7+Fmp0Y/akTipfylW6unVvOm2/M+3dUUl5t2pC6jb99t1UZtQRnOxNqfe+akMiNJs3/e+bdXYeJzTjL3i8sUN43ko/yt8zt/8TXrH7Nlutvp+qJGfl3w7cnJ6P1ryq1byvnTc6K235vvbdtes/s5MHstUdIiil4cZXHZ6/RfCdW47wvpU/8ATcz7DgP/AJKih6T/APSJHDePjt8Z6rstvNYapKef4fmNY91HbNmN0Ztqfe/hre8dW7r411V0kfedQkOAvBXdWfZwwz4mRN6/e2r/AHa+OzqX/C3iv+vk/wD0pnzuacqzGsv78vzZkXGn+c6pBCoP3/Mb/wAeqjqGi2zY32y7vu10clvC2XLzfu3bY0ifwtSjTXkgKPbfeXcu5/mryJS5djgj7vvHBXWgujfc3bn+ZqpSaTCq75o2PlvtTbXZalofkyJs+VG+Xy93zVkXFn5e5IYWST7v+zWFSM+Y9rB1OaJzv9nwxt58O4vv27V/vVN9heXdvRnH3dy/dWtBrG5+V3di/wB3cvy7lpiWkMaPvG5/vblfbWEonrUY+8VLOx8mTYjthf4pF/1ldH4ds7ZcJHD8v3l+T71Y9vbozZ2b1/2v9quo0CzhW4E25sKq7/8A7GsJfGbyjGO0TvfAunorLNHC29fldZE/h/2a9i8J+H7O4t4X+9u/iX71eceB9NeRVuftLLuVVRZP4f8A9qvZvBdnNJGiCCNl2ru/vK1ZyqGNSMOpsWemTQrsdPM27VSPbWxHZ7pE85/nklbzWX7rbaks1e0Vpprb7ybUVn+ZasRw3Kr+5EcZk+40kX3f71c0ZSlLmOeXu7iW9nDJ5Uz/ACIzbkj+6zNU02nzXUchWHa0P3V/iZf4atxr+5eaBIwu/Zt2/eq1ZrtZnW2kRdi/d+6y1tGpymfLynyJ4gb7Qd/3trr919qt/vVyeuQ7ZHmfl97fKtb+qahmzZEdVC/cb726uX1SREy/k8Ltby/4v96v2Gn72h8NHlUbsxZPOVtibS6/eZvvLT4bdLeF3eFvm+b79X49Nma9d/JXLbf3lW7fw55jFJ0kA/vfxVqpUoijzxMaRWg7xpFt+8v8VSw281xtR/7nzyRp8rV0LeFXmhTybbcuxV2tTZPDM0O1GhkXdu+Xf97+KtvaUvskL4jAhjeOQwpu+X7+7+GtvS5PMVZsKPmZdtRS6W9vHvlhmZ1fd9yraWr2sg85G/ePt+WorYiMoijH3/dNvTbhGjRHjZgz/wC7urp9HvvtCoj7tkf93+H/AGa5K1X7OzI6NsWXdFuf7vy1saTqCRK0Pk7W2blb+81cPtoG3LLqejeF79FuETYqy/xL/s112n6xDC0sKfM7SqssK/w15Zp+teZCJp/mf7rf7X/Aq27HxVNH87yfe+Xdu/vVy1ImkfM9IsdYtplCJCvyv87Kn8X+1VptUe8j3wbd6vt+avPbfxE/l/uXjzH/ABN/FV6PxRNI2+bayt8u6P8AhaspS5ZGsY8wa1db/GJu+OLiMnIwOAv+FbGqavDbyPI8myRv9b5b1zF7fmbUX1CQbSHDHK9Me34Vma1r3nyDe8mz73ytX6dx0k8vylt/8uI/+kxPvuOVFZdla/6cr8olnV768upGuUDJEysrybK42+1BLiaazuUb/Y+T+L/ZqbWNQuWk8yGaZArL8slULjUt0MyJDh2bdK0f8S/7NfAUZQjH3j87qcvumVqnnXDHYkizLFtRWrA1KGZyIZuGV/4k+X/9qt268l2fyvMi2/Mvz7ty1k30HlzCHy+PlZGV90daxxUI6lyozkZkMP7tvOeNhsb7v3mrA+Kdul94D1O2S5j3rZSbdvytuVfvV1Mi21ux37cK+3bt+bdXI/FrfD4H1ObfvRrVlfdU4/FQ+qzX901wtGXtoHg3hW48PfFLwmnhjxDeLDqtqvyTTf8ALRa888b/AA18Q+A9X+z39tMsbS/Kyp8rL/erN1TUNT0PVPtmmloju/hrufDX7REOoWv9k/ELR4dRSRFHmMvzKq1+XrXQ+o5eXY4aa3huoTsjZnX5vmrEmX98UC17JZ+EPhL4quWn8PeLPsDyN89ncfdVf96sbxd8CfENrGbzR4Y71FbbutZVZv8AvmtI/wB0nm5jy9mdfk343Uxt6/6n/wAe/iq9rHhfXtJm/wBM0e4Tcm5PMgZdtZu1448v97/aWl9k3NGyvIVZftNTSSaPdMUkmUfLt3Vl2UUt1OsIT5m/iq7e+DtSgXekbNtGXap5CfdGXWh2zxt9juVP+yv8VU9NuJ9M1BJgWRlbGajltdS01t7pIn91qZLcTTcO+6qkUdB4kuPMaG/R93mJ87NXPTS+YvlpWnb3MWq2gsp22sv3G/2qy5oXgkaF+GWpiOMRtMZtxzTlbPBpPL96Cx1BbbzRSMu6tAFopGOBxSI3Y/hQA6iiil8IBSv940gOORQG3c0viJiFFFFP7ZQUUUUuUAre8GnCzv8A3krBre8NxhdPd06/79TIiXwFiffcXwRIWPzr8v8AFX9En/BAPwn4Y+Cf7Iov/FulNDp/9qW76prEdvuka4m+byW/3Vr8Iv2O/hpZ/GL9o/wn4A1JV+z32vQteNJ/q1hWRWk3f7O2v6y/hl+yB8Pf2ZPh5rvgrwzfR3XhXWpk1S3025iX/R7jyVX7392to0ZVIvllaR4eYV5RlGNvdPlX/gqZ/bOtw3PiL4Pa+JPh68du+sWEhCNHe+Yqoyq3zOpyD7YrkP8Agn1pXwg8P/DXU/iv4ssvtPiG18RtZacjjKRRG3jYOR/vFh+FbH/BSH9nTxPoHgu3+NngnXC2hy3kdr4m0uSTAgbpCyL/ABDeVGa8z/Yk1zTdS07xF8MdRvBDJfRi8sWmP7vzIwAy8c7ipxx6V+3ZTTlS8EcTF+9/tK/KmcMnCSemh9I+IPjRpWtal9m+2bYmlXbHap8rL/FWdrXiywWN7bTblrcN/Dt3btrfdavMPDem6rDfPDDZ/Nv2r5afL/vLXVX0KaHbpeX9z5T7t7rcPt2qtfjtSUojp8t4n4c/8FAdem8Uf8FG/ijql5eee0eqLb7l/h2xqu2uS0mNJtqP91V3f8Cpf2g9cTxR+2D8UfGEMqyJceLbpVkj+7tVtq7abp7fKsycNs+bbXHGPMe7P4IxJbxQzCH5T8/3v4ahVv8Als6fN91F+7t/2qmWZG/c/wB5vnZqbNJ8u9+F3feo+IiX7uPunrP7Pa2dvDfb3Xe0S/NJLt210/izxQ8Nq8Ns+F/5ayK/3q4b4Ptcm1uYbBJHdlXbHt3bm3fdrV8ZRppNxJ/bzrF5abvLavnM0lP255mIj+8uc9r2pDTPM8Q63c+c6xfLCv8Ad/h3V85fHH4g3HiHU/sK3LMN26RWfdt/2a9C+LPj2eLTptZu3URp+6t41/5af8Br5+vLuS+upLub78jbmrXL8NeXtJnpYGjGUeeR+jn7Pf8AyjcT/sS9Y/8AQrqvzfr9IP2e/wDlG4n/AGJesf8AoV1X5vM2OBX9AeK//IlyD/sFj/6TA1wnx1PUFXHJpaKK/GYncAbdzRSKu2lqgCiiigBd7etJRSK26l8QDtqfwUBDI3FJVzSdPm1KbyYev3qcfemTKXKV44HZtv8AFW/4B+Fnjz4neKLPwV8PfDGoazq99LttdP021aWWRv8AZVaTTdBm/taKw3LukdfmZa+gvGvwY+Ov7K37PfgT9prwhqv9jxfEfU9QsdE1DTbpo76NbXasrLt+ZVbd96qqcsYnP7SUp8sT518XeENb8G376Tr1s8U0MrRSq38MittZf95ay12eXX1r4f8AB8fif/gln8Q/iJ8U9VjRNF+IOl2fw886BWnvL2bzGvVWT7zKse1m+981fJLMitv/AIa54y5om0WMJR23gYFSLsZl2feqJR82PSpoWh3/ACfw1XoVLcuaRO8V9HdJw8Msbr/vLItf1J3WoXN54Z0G8vPmkbw9p7eWqfeVrWOv5bLLZK6Fj96WP/0Ja/p1vtUhs/B+g2fzPNJ4X03/AFiNtWNbWP8AirnxHwnLiPhMvxFcQq2yZ2i2/daP5fmrh/El0kau6Iyy/d3NW1rmsPwnkq7K25tvzba4/XNQdVDzzeYvzb2Zf71cfs+b3hwlKxz2uXiR3Dvc2yqV+VW3/drhfEl6itMls80fmbf3n3q6fxNdTQ/JPtRdn+sb5vvVxGuTeTcSI75+60W37qtXn4iPvHqYepynL6nMkkjujqX8/dtZPurVBpo1ZspIRuVpfk+WNf8AZq5r0z/8sU3/AD7tyfLuZqzWjS1i33O4rGu51WX7rf8As1c3+I9OnK8NC3Zq/R5tm35Ukkfc22tbT981vG8yNmZPn/uyL/vViWsxbYo24k+bzFXa3/Aq0LO4eP7/AJ0asnyLHtZW+atI046GntDa01bmDHk7V8tPvL/Cv92uc+JtwsfgbX7qTcQuj3LNnqcQtmtq1vn+ztDDuMi7l3N/FWF8Unx8P/ELhw+NFuuSMZ/ctX7d4FK+fZhL/qFqf+lQPoOGZ82Jr/8AXuX5o/NbXJPtV000MrP/ALX96qFv4Z/tKYOerPUWo6g8Ko8f+7Wn4R8XabZyD7Ym4b/utX55HY/NJc8jqvAfwRTWJUfyfkVvmZk27q9o8I/CHwlo8K3OpvH95UX59rL/ALVeZ2fxkttJhVLDy/LX7u371Ynir47alMsnk3O7cn9+n7b3fciZ+znKXMep/Fr4z+Ffhvo7Q6OYzeeQyoflr5X8dfFTxL4vvnmv7xvL3fKu6meItW1XxVqD3M0zPtqnH4ZEgDv93+7Sl70eZm1OMaf2ShDHJcSb/mLr92txVSxs0mZ+P/QWqCOwS0XZs+Zf4f4aiuPtl9hE+7911o5UHmZ+qatcalfbPm2b/lrpPD95HptqMuu7726s6z0NLdvOmT5vuqtalvZ2e1Ud8/7Lfdo5Qv71iyL68vmZPLZVb7/+1XQaPoNy1qjujKPvJuqv4T0+zvJm+zW3mOrLsVfurV3xdDDdXhhudVm+4qy28Lbdv+zVe4Tzc2xauJPD2jx77/VbdJo33eWr1k+KPihpVjp62Hhvc1xIn71mT5Vb/ZrmfGngV47FdV0rzGRV+dWfcy1y+n71Vkd2Wsyo/wAxozXW23d0fczfM7f7VYV1I8sxd6uX1xt+R0Zd1ZxJ3ke9BrGIU35F96dRV8qNAooopgLsb0oXofpQzbqFO00pbEcrHwru+d3qSNU8yo1Z4/4Ny06ESbt2zmlykyLNvHMz/J/3z/erotFj2r+8TKr/ALFY2mw7bhXTmuo09U0+3e6/hVPvURlymcpcxiePtQSaOKwWHb/Furmqt65qE2oalJNI+4L8qVUqjePuxNvwJatNrKOEyV+b5a1vEEgm1R5tmxl/h/u1V8DLHb29xdhPnVfk/wB6rVwu6NpnfcW+/wD3acY85lKXvD9Lvvs67H6feWvvv40xpcfsFtGM7W8I6X+X+j1+e+51jHzbP9pq/Qj4vlR+wYpbOP8AhEdKz/5L1+u+GC5cpzz/ALBpf+kzPsOFHfCY/wD69P8AKR8A3Fj8+90/75ptrN5Eyo/T/arY8nerSPu/4DVKSxQSB0+dl+8tfkEf5j4otW6pcSM8LqP7+6pBdTRtvd9rbqr2cscVxsdKuXEaXH93a38W37tMDb0HWiu37y/wtu/iq/faemqQsj/e+98v3a5O3kmt1Z4U3bfuLu+9XTaHfboxvTKf+zUS5ufUzMC40/7DdeSU+Xd8yr96tBmM1mYfJX5k/u/NWrqVjDeKzoiod21f71ZM0b2Hzypz/tUGhZ+H/iq58L+LrHWLP/j5sb+G5t/96Nlav1A/aW+GOifGz9o3RfiQibLTxp4FsdSguPtSqnneTtZW/wB1lr8mtUvIIboO6fumb52av0V+C3ijXvif+yL8LvGdheNLd+Edem0S4kmb/ljt3Rrt/u104KX+0rzOfFQ/dXPPrXS5pJrzwvMkcvlyyReZs+9tb7y11U3h2bwj4dtIfsawwtFu8mT+Jq2bzw/C3iK/s5ns0v5rprhFVWXcrfwrW58VNah8Xfs86Df23hVrKXwveTWWrXHm/wDH00jfKzf7q1eMp8tWRWHqc1L4jyDXtas7VPMm+VlTdtX+KuL1jWvLmdJI96f3m/vVc17VJo2m877zPtiXfu2r/erkLy+/0gb+f95qwp+8RXqSjHQtnUN27zivzfeq7Z3X74RhGVfu7q5xtQRZH3+W6N/eSr9jceWuwv8Ae/u1t/hOCUTqNPvkkjaEcf7X96vZ/wBm+4e5sdUkZifmhxk57PXhFnfJ8kPyv83zLXuH7MVx9ostXbYikPACEOez1+i+FH/Je4X0qf8ApuZ9XwGv+MooPyn/AOkSOO8fiCPx3qcpMrML+bA37UDbj1rNjm8uZUR9hZWXcv3dtWfH95s8f6y7xnZHfy7gejfMaz4rp45P3zq5V9yK3ytXx+ef8jrE/wDXyf8A6Uz5/NZR/tKt/jl+bL8mF+S1dnRUXdu/vVb3JH88cLNui2/N95azYblJI96Jlo9zL/DtqeO4uUtV3v8A7XzfeVf7teZynncvN8I3VFSONnR+Nu35qx7pkht22W2/5d26N/u7q0by4RbeVHRsfMzeZ/7LWPcXD+UgR4y33dzfxVz1OY9LBy/eFS8kEjbEtVRvupVWOP8A0jM0LP8ANtSprpoZJld/n2/LuX5d1VppN0nkvt+/uZV/iWuOUox90+gp7D4ZHmZ0R2yr7dtbfhqR1m8m5dVVfuKz/ern1aCaTYny7U3Ve0nUHtXV32ttf+5u+Wsai933Tfm5T2nwPdPHAr3k0bOrr93+Jf8Aar2/4f3jtDC8zq7r8/mL826vnHwVrSRn7Mkyq0f8Tfxbq9i8BeIEt5beF5mKSfN8rfKq1zy55aky+E9f028e6uPs1zbbh977QqVttbzsn+pZyvzRM3/s1cf4d1bTbjY8Ny25ZdiNv/zuro9J1KFWCPbbX81t0jfLurGXN7r5Ti900bLZuPnSf7/+zSRxyQzM6TZH3Io/4abcXDzQqtt8v3vmqhqWtvaw+S80bSbd237q1p7SO4HxTqV86M1sjrtZ/nZv4aRbd764M0zttjXdKy7W3NWGNSubhfkuVKs/3f4maug8O28ilLl4fuvufy28xVav1WOK90+Sp4X3bmro+j7mxsV12r8rV0mn+HY1VLl0j3Kv3aZo9kk8yuvPlp88kny7q6fTbHbGHe2Up/z0/wDHq5a2OlKOkjslhfhM5fCdtcbHjtmCR/N/wKluPBaLl7k7dr/LG33lZv7tdpo+nzTQiZ9zCRdyN93/AMdom0+2jLQgqo+VFb733fvbq4pZhKMr8xjLCRied3mhwxxpMSxM25Pm+9D/AL1Zl7pKNcD7HujVvusz7v4a7/UdLdpGtofMCbdysy/K26sTUtL+x5eG2xTWYe03kTHCyhscsrw29wiOiuF/vfeZqI7rb5jv5ip/spVu6s5rWSbY/wA80u5Gb+7WdeTW0kB8n7irtddv3qUsV7xp9T7l6x1p9Pxv3b/uvuf+GrNn4mS3kfZNuH91q5K4uUt7dbVNu2P+6jfL/u1A2tOsaRP8m75dypWksdzbGUML3O9bxck0buHXau35aY3i6CzYhNzfPtZt/wDFXANrnlRs+9l2p8jNWbJ4s2xrc75Nky7mVqr65zlLDyie76ffGbwob6J2Yi3kKljzkZ/wrh7zxJbTMZkmZjJ/ra2/Cupi4+Cp1MfNjTLlsDvt8zj9K8lsfEFzcQh5J4wzL91v4q/T/EGtGGUZQn1oR/8ASYH3nGtKTwOW8vSivyidsupQzM0z3Mm1V+b5vvLUc+o/MPnZ/MTbtV/u1y1jrDqu+2mZvM3Iysn/AKDWjb3KbldPLYb1X5flZm2/xV+XSxnLHlR8LHDXleZo7nkjTzvM/uszfN5dI2+RmTezbU+X5f4qhs2hk23KTf3kb5/lqyykSI/y7Y4tu5fu1nUxnKdEcPKRUuI4XbeifL8v3m3fNXAfHqNP+FT63M6b/LspG+VNteiX0fmRpBD8zMjfvF+7XFfGyz+0fCnXYU3FI9NkeVW/i2/3ayxGM9pQ5eY2o4WMalz4w1aPzrFfmZtyKyKy/wCzXLXEL2txvT+9Xa60v2PTYpvMbay/Lu/3a4bULjzpSf4t1fN+6elH4gh1SaF1dZm+Wul8P/EfX9PmR4dSk3L9xt1cgqFm21a0+3dm2PuA/vVJXLA9Qs/i54rmiENzqTTRbG/d3C+Zt/76ouPE2j6gz/2xoNjcq0XybYtv/oNcJ500asiPytWre6f5WTnd/d/hqoy5ZGUtjfk0nwNffvrbRJrfam793P8Adq7DcW0lm1rDuddu35k+asS1mdx9zarfM22tPS5nWffPM2F/urVxFKX8pDrnhW8uoYtiK0ez7rL95q4/VvBmq6fKdttJtX+7822vWtWW21zRdnzI+35GV9rLXneral4k8OzSWs037v8AvL/F/vVPwjjKfMcoVmt2+fhlp9xdeeNkyfMvetr/AISawuTs1LSo2/2l+9WdrTWAYNbJyy/w/wANHNE2+IoUUUVBY3y/elVdtLRVfCAUUUU47AFFFFMAooooAKKKKACiiilyoBVXd3re0yaa30kum3bWCpw3z/NXQWUciCNIduNq8GiUTGqfRf8AwTv0+bTfFmp+PEhX7THZ/ZbC4b70MjNuZv8Avla/qG+HHxph+OP7O/hX4j6HrCy22reFbeK4h8r5o5o41jk/8er+cfwL8Nb/APZ30/w34J1V9uoXmkQ6tfwtFtaH7Qu5V/7521+y/wDwQ/8AilD4/wDg34v+Dt5qqyXHhe6t9RtbVvm22s3+sZW/3v4a6MPLlmfPYqpKpLQ7j/go28nhv9ljU/D1/JiTUUspoiW4l2XcQOPzrwD9gXwFD4o0W41eTTVmNrrEqh40BlUmCIjGe3Wvd/8AgrzbXD/CXSbm2gZreCURNJt4UNIjD9RXhP7Hvxu8DfAH9nTxJ498XeLo9NlTX5FsbdU3T3cgtosJEP73Nft2EqRpeCmKl/1Er8qZzU4ylTsdvq3ijwB4CttS1jXtehhms7qRZVa4VfJ+b5VZa+H/ANrD9rzxh8bLq58N+Cb1rXQt7farj7slx8rf6v8AurXP/Gb4yXPxW8V3usanbSWNrfXX2r7HJ96Rt3ytI396vKvHnjaw0vRZ/I2ysyyNtVfm+VW+Zq/nrG4+cp+69DelGV+U+MfCljNeeINYuXDFW1eb+P73zV2Nu3kr5PzfL/DXG/DeN76zmmmfa81/I+5v9pmrs/JTcmE3Oq/Jz8q/71d9L4D2X1HzQvJDv2LiT5fmqNti/I8KuPu/7tTXB3Q/J/wLbVJo9u/zkZlb7u2r+ID1/wCAPijw34K8N+IfEPiGGOW4j+zrpas3zeZu3NtrjPiV4yvPF2sXPiHUrny0+Z3j3fKq1Q0CRDYsj7di/wB3/wBmrzD4+/Eh7iY+EtKmUL/y9NH/AOg14lajKti7HPHD+2q/3TjPiR40fxZq7JbP/osPyxD+9/tVzZOeTRSAY716tOMacOWJ60YxhHlifpD+z3/yjcT/ALEvWP8A0K6r83y23mv0g/Z7/wCUbif9iXrH/oV1X5vMu6v2nxY/5EuQf9gsf/SYHHhPjqeotFFFfjHMdwUUUnz+1UAtFFFLlQBQG3c0qfeFG1FUbPvUogNUYGK0PD1++n3n2mPrt21QrY8EeHb3xN4httD02NXuLqVYoFZto3M22nzcvvEVPehY1ZtcvdS1RLmaZs7l+996vtD4Z2HwK8dfC/4b6r+1pD48ufBPgV7hvsvh3UVb/RZJPMlhjWT7rSN/EtfNmp/BLTvh/wDFr/hWvjT4neH4bu3ljWe80+6+1wRyN823cv3v7rV6N+1Z8U/Fev8AhDSv2fPDXhHQ4LrS7VZLy68P3O77Rb/dVdv97+Ks69eMrQW7OWitbs9P/wCCnmp/szftAfBHRfj3+zx8SNB8F+EdEvF0nwH8DrOXzbqys/8AlpdXLI3/AB9SN+8Zm/2V3V8CS793FO1CyvNNvHsL+2aGaN9ssci7WVqazJxvpxjKJ2jWG2ShndpN6CkY5bipLdfmOf4aCPhNfwjp/wDaXiTTdNT5TdX9vF/31Iq1/S94nWG1tbXTXEzJDpFnEsf8Py28a1/Od+zb4dufE3x58EeHkh859Q8X6bEkK/e/4+F+7X9E3jq++x+ILy237mWVkRm+b5V+Va5cQ/hic1bocpdXiTXDQvbMnl/3m2rXO6o00bMifLu3N81buoNJI0r3KRqu3ayr8zVg603mLvfcSy/JJ91q5pe7EuPxnH+JLf7VbhHKoq7Wfd821q4bxEsy70tnb/b3fdr0XXFhXf5wjCRovm7vvf8AAq4HxEtz572yJ5nztv8A7rLXJU5pyO+jE4fVJHtWRJkZPM+dvkqnJdTHfJs5V/mX71XtYbdutoUkdNzfKvzf8B+asuFZtyzQo27ftlVvvVzyjM7oyLFvNNG3mujS+Z/D/dqzZ3ELRs7pJsWXbuX/ANBqpH5PlrcvbSRyebtTbT4Vh+a2Tdne0rx/3m/2amP940lHmiWlv3jOxJpHZX+Vf7u6ofHTG4+G2uG4JGdHuw5PGP3bg1VWSRZn2IzBmVW3fwr/AL1XdYhF78P9Qt5WGJdNuEYjnqrCv23wLnzZ5mH/AGC1P/SoH0fCitiq/wD17l+aPyq1PVHabf5e3/ZqlDdvDumR9n8NX/E2jvZ39zZzSNuhuGX5vl/iqlPapCvzphW+ZK/OYfAfnsiRdYmjX55mqpJrE03Dvn/ZaqcxfCp33fJTJB8+08/3v9mr5fcJujXtdchjVUfcP9qtSPxFprQ/fX73yf7Vcltdm2fdX+Gnx71XZ/7JU/ZGdO2oWDbd6LuX+JaZJqkLLsRFT+JdtYVv8o+/81Wo28ydXd2qpS7GZPNqTIu/fuNVbrULmTdJvbC/d21JJH5iu7v8u/atWLXTrZnH2x9gpf3So7EfhfxlrGg3QubUZVfvV1+m+PPD0twXm0eTfI/zNI9VdH0bw3Lb/JD+9X7/AM/3qmuNN0f7Tss4W/22kquX+UOZHq3hTQvCvjDw+88KNE3lMssbbf8AO6vD/iR4TfwbrUkKcozfumr174WtNpuj3Ezw7UX+H+9XL/GzS5Nf0ptZCZ8v7jLTl7xl76nc8Wu5nuJi70z+H/2aiT74/wB+koOvoFFFFBoAXbxRRSbflxQA5V+b79G35s7KSljUSHZQTzMlLbgP9mpI49zLzhqjVDJIz/3as2qozLv6fx0+Yk1tFtst52xSqt8tafiS8Sx0V0L/ADSf7dQ6XZou35N/8VZPjS+Sa6FjC/yx/eWp5kZKPNMw6WNcsOPlpKn022+1XaJ/tUcyOk63QbEW+i7OvmfNuWmSQ7/uJvq1YzIzLZu/lIvy/wD2VOmhfcyo+F/gb+9Sic0tinNbv9kVH2/M/wDFX318aW8n9gPKk8eENKA597evgib/AJ47/u/xV96/HBHf/gn+yIdpPhDSucdObev1/wAMFfKc8X/UNL/0mZ9lwpf6nj7/APPp/lI+HLeTzIQ/3m/36WSNPMTyf9ZWbYXzw/u3f5v462I7q2k2I8K/c3J8lfkX2D4rnKiw+XP52cLvq3C0O4/40k0fytsTKstNsVeORpN//jtKOw/8JLGu1fubd1WdLvvsrbPO2DfuqJ4U4m3sN1ElqjbRsyy/N81HxQFzWOjW4S6t/wBy6qV/iasrVofs8jfP5u75qsaPcRtGE+4zfeWjVoy3zp97ZVxIt0OQ8SMWtpfn+Zv4Wr7P/wCCYuvf8LC+CvxF+DP9pNHqENhHrehqv/PSH/Wbf+A18Ya03mQzpNDtb+CvWv8Agmd8crP4NftUeGdT151OnX1xJpuqRyPtT7PMu3c3+yrVVKUoz5hVqfNStE+spPGniG61jQbnxVC1tHDE2y4ktfmm/ut/u16Notnbap8MPG3gPVdS+2Pq1m15YKz+WsMy/N5i/wC18tfoqP2Qv2b/ANuf9lfQrDTbLT9M8V+H7C4t7DWLS32RfL93d/vfLXwNpnwr8efsu/GSz8JfE62jtP8AiZfZ7ea4bcskf3Wk+avpcdg41sNGvT/7eifP4bEVKdX2M9+h8R+JNWdbrfv3qybfm+XdXOXmpJCwR3+993/Zrv8A9srwqnwx/aQ8U+CbaRnt7e/+0WDbFXdbyfNG22vIpdUhLDfuY/3a+e+E9SN5Q5TVk1KGPdDhnVv4lqzY6gmVdN29v4d1c1JqTtJ+5dfvfKtS2usPDI7+c33/AO792lGRUoSXuo72HUodzlLZl/uRrXvf7JtytzZ646k/6y34PbiSvlmx14xxoiTN8zfw/er6S/YmuRdab4iffuPn22T+ElfpHhN/yXmF9Kn/AKbmfU8DQtxLRf8Ai/8ASJHNfEeVf+Fga3G0zZ/tCYnaM/LvPy1kx3dvcKEdPmbavmfxbqg+KGqiH4na+EkUeXq04I2/7ZrNXU0m3+d8oj+Z1/hr4vPdM7xX/Xyf/pTPnM0p/wDCnW/xy/NnSR3iKoRHjba6ttqU6g8cm/zt7K/3a5y3voVZE8xVWP7q7P8Ax6rJ1RGtzPMiqm35GZtrf7teZzTjE4o0/dNDUL7zl865mX5V+633q5261RBMYflG1t21VqtqGsfu8fKr/d+b+H/gVY9xrDtcb0mXc3y7qzlI6cHHlnqbDaluUoibE3fxfxUf2jD80r7drOqoqr826seK68yRZN+4/e+WnySbVaPzP9Z8ytv+7XJL4j3qfMbFxcJHGv8ApOwf3l/9BpY754pPk+Td/CrVmNdPbqmxFbbtV1+9uqbdMzbEkjwu5nbZUcvKbSkdv4V137O3lvcq4avTPBfipIbUQzXPz7PlWT723dXg+l6s8cImh+Tb83/Aq6jSfEyKqvc7V+X/AFi/N81RKP2omVSUeU+nfC/irav2bzsoyf6tvuq38NddpviosuLm5aQRtuSNW/h/ir5v0Px15P7uabarL8rbvmrstL8b/MiQzfd+dZG/iqJR7nJKXvHtf/CaPDZmCFFkT70C79rN/s1j6t4yd45X8tdjff8A4v4fu159N44eRhsust/e37VrD1b4geXE01zMsTN95fNaspU+aIuaETyPR9Q8ySPekar/ABx7vlWu18MyRxxkpHGi7trQx/Lu/wBpa800Wazjjaaab93v2/L95t1eheF2+zLE+/7vy7pP4v8Aer6ytiuX4TCnh4/Cdz4d+SFYRGqbk+633q67QZEwyOnlt92KPZXFaXHDPIJi6zbfvyb/AOH+7XTaXctDGk118qK25Pm3Nt/hrjlipS1NpUYna6PNMzf6TN/d2SbdtXZrVGzcwhdk27zV3/8Aj1Zmi3Ft9k3wTNM0fzOv8NaUdul5tSY4LJu8tfurXFUxQ40jP1SzdVR9m8wozbVfcrVgavbPJ9y2kVpNvy/7Ndmqp5aRu/735l8lkrH1izdfNtoZt25/3Uf/ANlXN9ejGRUcLzS0PPPE0aSs1zbbU/e7Ny/NXL6jNNtaBPlP97ZXc65ZwwK8fnKzb2b7u5d1crqFrB8s0Ls0rfK3y/K27/aqvr0u4SwvvfCcdq19DF/y7KzxptaT5l/4FXMzaw7SKn2lsruV2+6tdN4ktUjt2hd2UL8u1v4q8/1z/Rrp0+Zn+9tZ/lX5a6qOM9oc9ShKJZuvEU1uqO7/AL1W2/L/AOhVj6lrl3H+8eZm+f7tUZtcmt7j5EX7nz7qydb1qGWNnfqtdUcR/KYSo8p9V/Da43/s1rcMTj+x708+zS14fod9H5aO+7Z95Fkr2P4S3Ak/ZPjudxIOg3zZ/wCBTV4P4T1Kfy/J87Lt9xWT7tfrfiXU5cpyT/sHj/6TA+04shfB5d/16X5ROys5kjZHv3VU/vL/AA7q19Pb7Psh/wBY33l8z+7WDp80/wBoieaZXXZufalb1hdeS3nO/P8Ad2fxV+PyrcsviPkYx/mNjS/JUqn3nk+9D/s/3qstskZn2KVb7y/w/wCzVOxWa4Znfa0W3d8v8NXo2RYWm/5d1/u/e3f7tc0sZL7RtTpkcnkRxb0h2S/ebbu2r/s1x/xRhhuPhvroebLNpsibv7rN/s/3a7ia4eOzZ0hYfL/FXD/FRobL4Y69fpCskq2DN/d8tdy/NWf1qUjWVHlPjH4qX0Nnb29hCjfKvzf71cAzfx1t+PdZfV9ZeZHyKy9O0+a+uRFGjGrjEmPuxuFjb+fKBt71vW+nvDb8HczVs6D4Ff7LvkTa7VDr7Q6XCyIMndtq+XlM+aMjG/fecyO6k7/u1oaTapu+eFqw7jVEZjsRvlpIvE15byB0fil8Ivfkd5Z6I8n+p2hPvbv4v92pI9Njt1i33Knb8zs38NcpY/EK/DeTO+1W++y1c1rTLnV4vPsdaDI23YgpylzClHlOuF5YSL9j/tKEj/rrUV9pMOuWv2aYK8ez5JF+avO5vDWuxMXhDOF/iV6m0xPHdsv+hw3RVfm2/wANTHnKjGO5V8S6DcaLqLwn7u75aypGfOxq3Nb1nUrgbNVsSHVf+WifxVhzO8jbmpGsRaKRWzwaWr+Iob9/2xSMu2nKu2hl3VAC0UUVcZAFFIrZ4NLRHYApeVNN53b91LUAAbdzRSKu2lrQAooooAfHHukXf0avW/2VvA2m/EX46eFvBmq7fsE2qRy37M/3YY28xv8A0GvKLH95IN/G2vev2WfDepWV5P4wsJZEmX91ayMn3W/i2/8AAamXu+8ceKkoRPrL9rbWP+Em+M0/iq2mV7aZVit2V/uwrtVV/wCA7a+xf+Df74jWfhL9q7WvDd5qvlL4i8HzQMsn7xZGjbctfn7pdrc3V5/aXiR8xwp92RPvN/er3f8AYB/aAh/Z7+Plt8WraFbiHSbK4/0eR9qzNJHtVaxp1LS55HiOXOfqr/wU9+I3grW/2cZ9GbWoY9Qk1G1Sytj9+4dHBcD2VQx/Cvys+Lut61Dd2elWDEpHG00fmyfJFIx2Fwvc7Rg+wFbni74q/E34/fHKX4n/ABL8fxXGZ5hpPh6zi2W1jAUIAX+8395q4r47WllN4itZ7y8nVRp5QxxvgYLNz9a/YqWJ9t4C4yf/AFFJfhSHFezkctdWaPdP/aXiFX3Kqsqy/Kv+7WJ461DwloHgvVHSaNy1rM26NNzM3l1Pb6f4es1KfY1Xau5dz7ty1zPxq8QWui/DPVb+zhVCulzRbWX5fmXbX8+r95Vi0VR96rFHzp8M7d4/DsE3k8ybm3N/vV1Mm+HOxPl+9838Vc/4H/0HwzZwpD/rIl2bWraWZ5Y/33yn+61fUwjoerU+ImjjS3jaZJmK7F2rVSS48kF5Plb723+GoLrXLaPMP2nZtfbtasa+8RIvyQ7Sn96l9rQXLGRqeIviU/g3wfdJbJH9ouG/dTfxL/u14TeXc1/dSXly7O8jbnZq6D4iatLfXsMH2reiqx2BuFaubqY04xlKR2UafLEKKKKo0P0g/Z7/AOUbif8AYl6x/wChXVfm/X6Qfs9/8o3E/wCxL1j/ANCuq/N+v2XxY/5EuQf9gsf/AEmBw4T46nqFFFFfix3CMMjiloorQBFXbS0UFd3FT9oAooZfmye1FPlQCt+7au1+BWr6bo/jb7Zf7d/2C4W1Zv8AlnN5fytXE0b3Vg6Nyv8AdqZRJ5UbUWnzLdPc3k2597M0m/7zf3quW8F42rrq763J5i7dszP8/wD31WENVuQhTPBqM31y38bCr9zlMOSrzXub3xDvbLVtcTUbYbpZrZWum37t0n96sBd67t9G4NIzvTJF+bmp5TeO4L8nCPU0bKmE6bv71RbTu+SrEMM0mfumpJaufS3/AASn8K/8Jh+338LdKmto5IYfEa3T+Z/0xjaT/wBlr9w/Fd1CLyWZ33edcMySL/eavyN/4IS+CpNY/besfEkyRvD4b8L6hes0n/LNmj8uP/gXzV+sd9Ntt/kfeJPvKz/xf71ediJe8Yv3nymRdN+7d/m+V/7n3qyNSie4ZY3s22sv975lrS1BrZbqSGO8Zwvzbf8A2VarXiw3UaTfbP3f/LKNflaSubm6s6oR945XVrVxG6PbZf8A5a7n+Vv96uS1LSUhYiZ23yP8vlv81d/qcJaRke2XLbvNb+Jq5i8sZppJSzyJMqfJtiX5f9ms5e9E6qcTzTVNHcRo6Iqtt2urL92sSTT3jZ7Peqn7zbl/75r0DUrFBueZY5TMrK23+GsO6tLZQ1s88hRtvzNV/YOnlOVW3uo4/J2fMsv72T+FarFZlZJ98ed27zFb5q3NUtUWHfbQt838O/5WrNuP3yt9p3IJNv3fm2tXLKjKUtS170feM2SZJVdEdkZpd25futt/hrYMYk8HTwncN1nKPlPPRunvWTJHtaVBMuyN9y/P/wCPVtGQjwxNLvPFtIQynkAA4r9p8DoyWf5jf/oFqf8ApUD6fhWFsTWl/wBO5fmj8z/jp4bfwv8AEi/heFkt7iff+8ri9auNtqnloo2/w19V/tUfClPFnhd9dsH3zwt8y+V8zf8AAq+SNehubeQWdyjK8bbZa/MsNW54nwWIozo1PeKD75GX5/4ql8t2XYNtQK22T/Z/u1Pbx/effk/3a7Obmkc/2B8caeZ845+7UbMiyN89SeZ5cZb+Gq/yeYetMB5zHJvdKuWsbzN8ifMv391Vlj/eM7u2Nn/j1aFnC8O19jb/ALz7amMeYiUSXb9nVt6bvk3VWvbx5JlRH+T/AGaTUL6ZZGh34Zvvr/dqpG0zNwn+/RER0Ol3lyq70euo8P6XNfTRo8n3tv8AHXJaLE8zhN+0f7Ner/DnR4fJ8z7Kqbfli3J/49T5eUcubkN1NN8nSbews9rH/lrtqa+8DzSaTNvhVk8r/d+b/ZrrvB/hWHb9qmddy/N8qrtatPxBbJcM9sj7Pl/u/LWspGEZfzHxF4r0z+yNeutN+b93K33qz67j4/aGmj+PJtnzCRPmb/arh6zO+n8IUUitupaUdiwpfmWkpFbIpgKW280/bvxsprIFApwY5L0uZAEP3q09LhSZvnXH8Py1ST7wrc0O3TztjvtpmMjXhaGztn+fbtT564nUbp7y8eY/xPXS+Lrp7XTvJR23M38X92uTUEDBoCnHqxa1vDlm6yNN/Eq7k3VmW6+dNsrqtN0/ybXydm5/vfNVfEVU5ugkbfZ2+fcf4q1Ix9ot/kRhu+b5qz5V27UgjbG/73/stW7G8Ty9nzGp5eU5/iJLq12oHTlv92vu343K3/DAzIDtP/CJaUPpzb18NSRo0P3GX/gVfc/xtLL+wW23kjwlpf8AO3r9d8L/APkTZ5/2DS/9JmfacKf7nj/+vT/KR8BTxvCyom1j/eqxYXE02Wf5T92msJvM/efKrUscZjbfvr8kifHmowk3B4fvfdTdQJplk2b1H+z/AA1Bp9w6N5fysy/xM1W1jSTLvH83+zR/hM/cFt7hJJFhcM396rEcyXEOzO35dvy/e21Vh+WPdv2r/eqZW24dEZ1/j/hpa/ET8USW2vvst4IUT/crZuv32ns/3dq/erHWRJFXCfd/iq3HdTSW/k/xL99f71WP4fhOX1uHbcOkLt937zVzeg6hJo+vLdrMyvG+4bf7y/MtdR4i3qx/2v8Ax2uEupdt57K3zNWZpT94/pW/4Ik/tBQ+NP2c4YfOZ7q4sFVoZvlVZNu2voT9rD9mbw9+1d8HY9N8SaD9j1zT1ZdD1KHbvaRfuqzV+Q//AAQp+P1/pug6n4S1LW/Ljjuo2TddfMq7fl2x1+3n7Hvjf/hZel6n4Ytk+3JZ3SvdNJ96Hcvy/wDAa9rDY2q7QlL3Tx62Ejyua+I/Bb/gsB4BuvCPi7wN42udNjtru60OTSNZXdul+0W7fK0n+8tfFz6om77mx2r9qP8Ag5A+Adgfg/qHi3QdKkF7perR39vNDb7vLj+7Krf/ABVfh7PeeZJvd2wq/IzferjxFOVKVgwdT2t2/iNBtQT75TD0+TVv3Y3sy/32WsRrzaF3v8rURX/y7C6tXLKXKd/L7x0On+IBGyfI2zd8rV9Wf8E+9QW/0rxQMcx3FoC2c5+WWvi+O8eP597I33v9lq+uv+CaV19q0fxa2zG2eyGfX5Zq/SPCX/kvcL6VP/Tcz6rgqMVxFRt/e/8ASZHB/GTxA9n8ZPEsSsny6xcDkZ/5aGs/T9e8+HZcj5W+ba33v92sL496zJbfHPxWqP8AKPENyG+X0kNYsfiiaGH/AFO4/wC196vjc+/5HeKS/wCfk/8A0pnzWZ6ZlW/xS/NnokesI1u8aPiKOXcu2ql54utoY2mdFdV+b71cTL4gu5G2P9xvufPUcEm6b53Vf71eVLl5jijGXLdHR6h4oe8uNiPsVvurVdbpGl3u+1ldfl+9WRHMkb70RmLfK9SrJD5g2fK38TNUy5eh10ZRibsNxuZHtn5bd8uz5asRzKJFV3z8rfwVjreTf67+997b/dq3b3CQwvshbd/Buf8Ahrm5UejTNSNvP3Ike7b9z5qk855EWabav9xVqlDcboymz/f/ANqprfybnL/ad+5v87aXLzQOnlRZWbyY49n3G+/u/vVLDrU1vJFcw7flfbtVqrx3Dx24heaNdy/Nt+am/Isfr/srRTiYVNzsNL8VJJCH3qfm+9u+9WzY+NJYZEdvM2TfxM/3a82t5prfaJLZm+b5FVPmWtG3vH8tf3Db2Rv4/wDx6rjRjKJ5lao6cj0abxw8cH7l/mVNr/Nu+WsHVvHE11sthcsWX+L+7XL/ANoXkm5C/wAkabfv1QvLp9y/PsX5tu2q+rmPtub4jc8N3/nN8k22Vfm87dtr0Lw3q20JeWyKjN9/a+7c396vFdAvkvJV3/IzP95a9G8LXkcMm9LmTcqbUVfutUylLlPa5Y/ZPXdNvoJLdJkmxNvb7vzfKv8Ae/u102g3iKySJu/haVY/m215roerPCyPbTN5jbV27vvf3q7DQdY09Llkjm/e71Xyf4vmrmlKrGI+U9N8P3kMkiO53fLu2r/FW7p8kNuqTI7B/NZ9sP8AF/vVxnhfVEVQ7uqNHuZP727+7XU2sk21XdN25lZNvy/99V52IxH2Tqp04yjHlNS8/eIHmST94+7csVZetNc3Mb7HjhibcvmSf7P92r81/wDZ4mmhdn2/M+77tZOoQwXG25SGQ/P8kO/7teRPERp/ZPQo4X4XGJzmrW6CZC80kT/di3fdkrnNW0n7K32a5Tzl3s8Xz7lX/arttSW2uI186Ft0jbVWN/u1gaxYpbwCFEZF+98vzK1Y/XPaRtc7f7N5o8x5Z4s0/wA6N/k37dzN5ny/NXmXiC1ma8dPO/g+evZPEmiu0ZkmTbL/ABqv3a848QaDMscySIy7U2v8v8NevhMRyzj7x5OKwMtzzbXN8DbHTcy/NuWuZ1i+/ct+/bGz7qpXba9pqLan7yuvyu1cL4is33M6fJ5nzV7lGp7/ACnhVKfLLQ+t/g5M7fsbxzE8jw5qP6NPXzn4LuHZk3zMDv8AkZv7tfRPwZVl/YwjWTk/8I3qOf8AvqevnDwbavJIkL7sL/47X7T4mK+UZH/2DR/9JgfV8XK+Cy//AK9L8onovh+6haYQu8jJ/A23+Kut0lkW1/fIu/c3mqz7vl/3a5bw3ZpJMqIq4rr9NjtoZFTDSmZdrMv+zX4zWj7x8jGVjSs1+yx70Thv4d33alWN2kZ/J+6/mI3+zRDawtc/Pcq7xp86r/6DWlY/vI1mdP8AVozbv4v92vPqc0TriVdszW8n7najPuikkfd97+GvKv2nNQfR/gz4lmSZUT7EqIv+823bXr+pSQTWCbHkQt8yx7N1fP8A+29qkP8AwrtvB+murI1wtxesq/N5m75Vb/0KscLGftb/AGS6ko8p8c2ts+oXXzx16b8O/hskdv8A2lfosQX7nmL96rPwp+Ef9pSf2xqSYgjfd/vVsfFr4haP4djOiaJcruhWvaj7vvHDLmloYPjDxRZ6DZvDCMbfl+X+KvLtV1i51O586SZsfw0/Wtdn1q486Zv+A1TjjeWTatH95m0Y8sRA27mlVNxwtaGneG7i8RrmUNFDH/rZGX7tLcLa225LBPN/2mo98Ob+UzmVwv3KvaNr2q6PKv2a5YJv3eX/AAtTFjUE/aZsf7NT2MkNq29LbNKQuc2JPiB4tkj/ANG2xjbt+WKoY/EHjCST7S+q3CfwsqtTH1CTyRDsX5vm2rUtja3OoTrDIjEyfcpxjzGXNyxOh8F3H/CQLcaf4ks47kMnySMvzf8AfVc94w8DxafC2q6RIrx5+eFfvR11ENna+HdP+zWzs1zIn72T+6v92orfTWmt/wDSXWGGT77NTFGU+c8yTr+FOZc8irWtWq6fqk1sj5Ct8jVU8z2rM6h1FFFXyoAoLbeaRjgcUn3/AGxS+0A6iiijlAKKRjgcUK26iIC0UUVQBS/wfjQGK06P5uBQBs+DdHu9Z1mPT7OzeWWZ1ijRU3FpG+VV2/71ftV4F/4J3+BvhT8B/BeiXnj+1stStdDt5/EelzWSvI11N80nzfe3Krba+Lf+CBP7H9h+1f8At6eGPDviSzkm0Tw3FJ4l1lVi3L5dr80as38O6TbX7GftOfA/wR8bNcuLl7mTRdRsb/fLdWfyrdL/AA7l/wBmt6NOXJzI+czKvzVeQ+Nvjh+zL8KNDtYJ9H8yRI0/dfKqrIrfxNXlX/CpdE0+3lhh1JoYvvrDGi/99LXrfxw+E/jbQfEt14bm8QzSwqi/Zdz/ACsq/wAVeUa94V8VaOxSa83n/lky/wDs1eXWlVcruJy0Y04x0K3gjRLPTPH9qYZixEUm3Emc/Iai+OFkLjxNav5W4/YAuP8AgbUvw90i/tPG1pPezksEk3Koyv3D3qf4z6bNf69a7GYKtqudrYx87c1+uYRSl4AY5f8AUWvypGp57Do/zJN5zSBVrzn9qu6Sz+D2ozIP9c8cDbf4dzV7JZ6LNHNvdFG35XZl+aSvFv27o4dL+F+n2aO2+81mON1ZPuqvzV+EYelz4qJthOapVPGbXUP7NsYFs03pDEqv/vbap614m2/6h8Lt+bc9Y9xqD/ZfOSZv9nbWbJcvNIru+6vqua8D1Ix5ZNl3UteeZV/iP/oVYeoaxcySMiOyt/6DT7q4eBf9YrLWbeXCMv8As1jKXc0jsZeoSGS6+/uqKiT/AFx+lFaHTH4QooorMZ+kH7PP/KN1P+xL1j/0K6r836/SD9nn/lG6n/Yl6x/6FdV+b9ftfit/yJcg/wCwWP8A6TA4cJ8dT1Ciiivxg7gpVXc2z86bt+bNDLupR2AWkZc8GlpCd33KYC0UcAUUAHBFFFIq7aAFoop0XQ/Sp5gE2utJRS7RxUk8yBPvCrunrukGU3D+6tVkV+Plx81amhWvmXsSf8CoJP02/wCCAPgN4bP4pfFqaHZtgsdGtZlT+83mSL/3ztr781K4hW1eF32bX3bVr58/4JBeAZPh7+wPot/qttHFceMtcvNWuFZPm8lW8uJm/wCArXvF9N8zIm11/ut8qqv+9Xj1qjlVlEr2P2ipIsDEW0a/NGjN/ebb/tVTmZ/mTyYWeFG8pmX5lp02oom+FIdv8PzN/C1V7q6ka4MPk8bf9Yr/AC1P2TeMfeKGpW/nbP3zfu/71ZWoWaTKfveZ97zP4q244/OuFR4coqbnbf8A53VBdW8zQyTTfw/xRtu21nP2h20eXVo4rWtNn3O8KNv3/LHt+XbWPcaGvkul5tz8uyNlruJrNbpnRz/B91U+9/wKsjU9M3Wr/I27ay7Vf722r5eZeZrLb3jgtc8P+Swv97Db9yNfmrIvrfbGJkhkTsrL8u1a7W6t91v9pghXzVT51k+VlrCurSGS18lHVn3/AN37y0f3pGManL7pyTabbWcjbIWU/eVmrSEAtfDckLsJMWzkkchsgn+tTXlnbW1x/pKK0km75mXau2mFEXQXRWJX7O205xwQcc/Sv1/wPSjxBmLX/QJU/wDSqZ9fwo08TW/wP80eP6to6NbvZzRM6zf61f4d3+zXxX+1F4Rs/C/i50sLZk86VvN3fdr7zks5lmltvOVlbc27+Kvl/wDbS8FfbLdNehhwGdvu/wCzX43ga0frNuY+azCj7TC866HyzjZIJuOPm+arVuyM3nPJz/s1DJsjkZHTd/vUscaRtw9fRR2PnV8I+4bco2f+PU6GDaocbWbZUW794EdN1aAhRV3pDllT5FqeXsIYsfl7UT5lqVrhId3ko3/fVKtv5m5If++qRbcx/wCyNnzL/FQKUftFSRTN87jeW/vU+GF1+TZ/F/DVq3hTaqI/8e75kqaOHMjb0Xb/AHquOxMvM0fDlvuugiOzru/hr13wbeJp6hHRSsfzfNXmXhGFGukT5VP8FepaT4fudQjRzD5QVPvf89KvlhIUvdgeg+F/HWmnT3TyVRvuouz5q1F1ZNSVPs1rv2/Ku6vO9N8O38d8qGaT+Jm3V1+m3Ft4f0nfdXKs+z5VZvm3Ue7E55e8eKftdeG3VrfW0h27fldv71eGV9G/Hi4m8QfD+91KbbvjZW2/7NfOVKR3UZe4IwyOKWm5+7Tl+/8AlSNgpf4PxpvCr9KWgApyLtGKbUi/eCPSlsTLcsQp5kmE2/7y103h+12tvf5f96sDS4ftEjJs2LXSTSf2fpst191fK21BlLnOe8XXz3WqPDvXEPy/LWTSySeZKZH/AIvmojj81tnrWhtH3YmhoVr5lwH+b6V0sDeZu+fB/iVazdPh+zWq7E5b+Kp4ZHT92nCt9xqXwnPKRbbZIvkdNvzbaqLMkbHzH+b7qLV+P97HvR+dv/fVU5oUti00yKxZ/k3fw0c32SY/CXrO4eTYPOwy/Ltr72+M4P8AwwiwVhx4T0zBb629fnzHqLxyZfa3+zX6B/GNz/wwX5mCT/wiGlnp3/0ev1/ww/5E+ef9g0v/AEmZ9pwp/uWPf/Tp/lI+EJIfOc7/AOL+Jvu1UVvvI7tlfu1o3UHmKiPDtDL/AOPVWkh8uTzkRTt/u1+QR2Pih1oqxMUT5T/FWlZzWytsebcW/wDHay2aGQbNnzN/d+9uqeONI5hv+/IlEtgNONi0eyFMj+Kk8yHy9/RFqrHJ+8+TduX5amEM3yJDyjfeanHmDkLFvIi/xq39yjy9w853Zf8AeqBYHjff53Ozd/u1ZjuIW3v5e5W+/T5gMDXm8yR1PCx/+PVw998t0/b5q7XXJjJcSw7GVV/ib+H/AGa43U+bpuMfWpl8WhrTjyn0x/wTC+Kt18PPj3ZNE0ZS6XY/mf3v4a/oJ/4JLfFm/b9o3WvDd/Nutdc0tVXd8q+Yv8VfzHfAHxs/gD4k6V4kVGcWl/DK6r/d3Lur+h79gnXtN1CbRPjHoOpXUdvZ3Czu0e3/AFLL/F/7LXRTqRjGSZ5GZ1pYaqp/ZPq7/grP8B4fjJ8C9Z0q003znuLCSB2V/lk3Lt2tX8p/j/wnqvw98bax4E15GS70fUZrO4Xbt+ZW/wDQa/sNuNc0r4nfD3UtGmmW5+0WEn2K8ki/ds235Wr+U3/go98MfE/w5/aw8VXPiRGE2rapNdbvK2fxba9CvaphYzj0OTBuEMT/AIjwncF++/y/w/xULM5ZUd9oaoVkeRt4jwF+5T1VJG2F2+X+9Xl8x7XwlppH3Nv+5/dr65/4Jhn/AIknjBf7tzZD/wAdmr5B3Oy/O+1v9mvr/wD4JjBho3jAnvc2WP8Avmav0fwj/wCS8wvpU/8ATcz6jgxW4jov/F/6RI8K/aFkd/j14vTZwviG6+b/ALaGuYhuk2tJNwyptSun/aGL/wDC9vGEQ/j8R3Q/8iGuVt43ZdkKfKtfHZ7/AMjvFf8AXyf/AKUz57M/ezCt/il+bL0M27B/vf3vvVI1xMuVT7jffaoFd1Vn8lS1I0yKoR32mT5f+BV5RxRiXvMdlR0+UfxrvqzDN8xm8lXl+XYtVF+aRX8nPy/dWrkJ8tvJh2nd81TI2pxhGZcw6/6SkLNtT/V76uRs7Qr5gZd3/fVVFRNu9H2t/tVcFvuX/WY3J96uf3YnoU48pat5oY1XyNyfI2/d825qtQpCu1IUw7fw7arWscPkjhm/3atWak4KTNt+7tb+GseaZ2x5uXmRP9nf7OcP935fmpV2Qr8n3vvbaSDf86J/vf71OY3PmB4YW3Knz/PXQc9YVmk8zzng+Rvlfa9TW8iRzK/2n5I0bcuymNC0IfznwG+43+zUkEky7Rv37fmfd92toxPExHx8shsk1s1uZvmXd/EqVQuoyJF2eYq7/uird1HuZdm1U/2fl+b+KqepSTbdnnb/APgH3avl5Tm5vsnPafevJMiQ8FW/1jV23h/XE8lkd9jL825f4a8u02abzF+dv95a6CzvgzB9+4158ZfzH0R7N4b8UeXHFvuV+Zf4fvf71dx4X1u2WcOkqpuX591eB+H/ABQlqu+YqpVPkZa6jRfHASZvMm3fPudW/iWolzSjoVHl+0fSXh3xNDJHGiPHsVVbds+81ddpWseZBKiJHs/56fxLXzjofxAbzBNNMzpu3RQ/3WrqtK+IlzJMjw/Id/zs38S14uKjPm5kexg4xPaZPED2zLDpupRsrNtljb5mZf71Nm1aGa9DpDDlbfDbXb7v/wAVXndr4yeScv5yn+Hcv3m/2q0rPWnvo1fZsVW+fd8vzfw14lapy+9I+nwuHv8ACdW115qx3LvsK2/zq38P+9Ve4jcK+z96qt86slVLNk8s2yQswk+/N/eqz50z/Om5VV/lXf8AeWuD20paQPTjh6X2jntctdyp+6+Vvlf5vu/7VcLrGl3MzSpbOp8ttu7/AOKr0XULX7RE0bwsgkfcn+9XMalY2saumxlddyyqsXzbq9PBS9vM8TMKMactjx3xho/l7vJ2qfNbzd33a898Sab5TPEX3BX+Rtle8a5ocLK7ujOm3b8y/wDj1ee+KPDbrumRFLLuVGb+7/dr6/C+9HU+IxUZc/wntHwstXh/ZB+yuo3Dw7qIIH1nr52+H9rDJfKl4/l/JsXd/u19M/Dm3Mf7MYt2AH/EkvgQT0yZa8C8G6XMs2/tvXYtfuniW7ZNkn/YNH/0mB7nGLf1LL7f8+l+UTsvDum+T5bP5Y2/Krf3q7Xw7Z2zWZSNJDufbukT7y1j+H4XaSOGEfO33a7LQ9NeO6Z3RSZF3f7tfjMj4uPu6Faz0+ETNsfcJN2+rEMKRwzQ2z+bM21UZn2rtrSuLN2meF4V2fd3L92orC1ht9014uyH7zSMm7btrjq04y0Z2U5cseYk8RWb+E/Ccvjm5RWWH91b7l+9J/u18q/Ha8m1XQ7m/vE+0brhXlbb8zfN/FX0N+1Jqzt/Ynh2N5vsn2fz/LVtqyfL8rV88/FCF5PBt8lh9/yv3Sr8zVth6cIxM/bSqS0+E8w8TfEKbQ/DZtdKfZuXbtjryG8tda1u9+1TCSRpG/irqm17TftEUOp8ruXzVb/0GvY/hd4+/Zp0eEP4q8K3F5L5W1FjZV2/7taR5VK8hy9rH4D5/wBN+HPiHULhE+xvhm27tlddL8ONF+H1n9v8eSeTNs/0ezX5pJG/vN/dr174hftIfD3SbO4sPg98PbW2m8rbb3l187r/ALq/3q+bvFF14h8QatLqus3M000j7mkmatfaR2gKn7WWtQl1zxN/bV4ttDttrb+COH7tQMqbWS2/76rJWN9x+RhRHJcq2yN2qNfiNuX+UvJZlW+d1ct/eqwtvDCux32t96qEM0zN8/y7fldqvW7PMy/e2/3m/iqjOXulu3td0Y8zrXcfDXQ4Lq4abZ86xMyLt/irkbE2y/O78t/DXf8Age6/s2MO/wAiM3zs1KK5SeX2m4y88P21jm81KZlTzd27dXDazrU2u6t9gs5pPJjf5F/hWuh+JniIaxeyab4c3GST7+1/lVawrfwvqXhvw9N4hubZi4X5G/u0x/DI5vxQ0J1hvI/hVQ/+9WbvX1p80jyuzzNlmfczVEy7aDoQ+iims2G49KBjqKKKXxAIq45NLRRR8QBRRRRyoBFXbS0qru5TpQy7TimAY249f4qlt4/3io/FRLwu+rOnIJJgnks5Zv4aXMiJS5UftF/waW6JeeHfi18RfGGzamqeDZrJmZFZfLh2yfe/vbmr76+OUk2jeLnvHdvKml2QMqbVVq+PP+Dea0s/g58OvGOoaq7Qy2/h+3tftEa/euriTzGj/wC/arX1d8aviJ4eutLXUrq8hfyWZoo2dV3V2U6sPZHyWKcqlY+WP2uPFmm2vjCz+23W77VB+9jh/wBn+KvFtQ8ZWF9uhO1Sqfwv/D/u1e/aY+JWleNfHxtobCREt4ttvMqbl+Zvm2tXlmqeIobXc8L/ACqrbG2fM1eLWxHNPlN4e6jsvCd79p8XQBJlK5l4Axn5TT/idOsWt2wKZLW4CnH+0a5X4TXsl14+thKQCEkxj+IbGrc+MG9vEVoI5FTZaZZm92YD9RX69gqkl9H/ABjf/QWvypBF8xl2947TN8/mlX3bm/8AQa+bf+CgGqRyr4Y0dbmRna8mnlhZ9y/d+Vq9xm1pLW1W5mbfKvyytH/F/tV8sftha1c6t8QtKtJm+W3tZGi+fd8rN96vxHCyhLERR2YOP708xuptyhPu1VuLpFxAn3vvfLRcSOqtvfj+7uqtdS+XGHSGvbl7x6luWVitqF5uXf2rPvJtu3f92rV1Nt++/wArf3apNvaPe6bl2VXulRKv/LWik2/Nmlo+E3CiiijlA/SD9nn/AJRup/2Jesf+hXVfm/X6Qfs8/wDKN1P+xL1j/wBCuq/N1G7H8K/afFZXyXIP+wWP/pMDhwnx1PUdRQw3daK/FDuCimqMrinFd3FABRRRV8qAKKC23mkVdtMBeCKXadu6hW29qAGOMrml8JMgY7jSUm75sUtMoKXcdu2hhtXFC4b5O9Zkx3JLdXDL/tVv+HLCbUb6Kws+biaVYItv8TM23/2asGNEUAua+hP+Ccvwgs/jP+1p4F8IahCz2f8Abcd7qP7rcvk2/wC8b/0FaitUjTpyl2FGMqlWMUftB8LPDKfCn4K+CfhpDbLEmg+FLOzlb7vzeXub5f8AearGrao8m5ESMxfeXa235aZ4s1ya61y5nv8Ac4kut0S71/1bfd21zepXG75Em3H+H+9/wKvlI1faT5n1PWq0fZqxY+1TSTK7vG6r8rL/AHv7tC3xe4TyZmX+F12fK1ZbTJdQt5txk72+ValtZPKuFR9vyr8kn96vQjLml7xzxp8psxs8lps2YfZtiqOZfs6ukn+ysvz/ACtUUN00y/67c6/xL/DUUc1sqrv5dnbey/MrUc0fiOjl/lHNC/kult+7WT5m/vKtZVxax3VvK/3fkbYzVof6M2XgTcV+XduqrfQwrvnTb9751/u1VPYVSXKc1eWexm3zbmZ1bayf6vbXPajpqPm2T91tl3eZ/tV1OrfKuxAzs33Fb5WZf9muY1SN4VZz5mJG3RNu3L/wKum3LHU4+b3vdMO+LtL0YozbU8z/ANlqs8Z/s+SJ4wuY2BUdB14q/fX1tJI1tNcqrRxfJ8+2qJIFi5WTOEb5j+NfrvgnCEc7zCy1+q1P/SoH23CElLE1tf8Al2/zRxDQ7bib7NZqh835/wDppXln7Tngv/hIvBNzctCryRqz/wC6teyzKtxdBP4Vi3blTduaub8SaDYa1o89teJJ/pETJLGybvL+WvwGMpRqxcTzJU41sLyH5ma1pP8AZuoTWbx7vLb726qGHVjv+Xb/ALFegfHTwj/wi/iq5h+7ulb5dteeyN+89q+zpfvIRZ8hKPJPlZF5iLGe/wA33qt2uqBCUf5l2VR2hW+T71OVZNy7Dz96nylG5b3yNj58f3Vp7SR+cz7Mlqxo45t3lp/vbqtWt1tk2TOqlv4qqJlyovbZuyZ/2qmWR2Vdgz/C6tUEVx91P7z1PD/pDeWtUHuG14ZvktbpXdMbf4a9k8H+NIVhS2ePLRpuVVrwuzjeGZHM25v9l66bRNUurVvMfdj/AGmpR934jOpHm+E9d1bxheXV150MKqq/NtX+9WPdapqOrXBmmdid21I/7tc3H4301secW3t/Ev3Vrb0L4g+G4VSaZFkdX+dvu0+axPw/ZJPiJpd5cfDe9sPIYLJB95k+avmaWNo5WRhyvDV9jTeLPD3izwq+lWd1Gr7Gby2/vV8n+ONGl0XxNd2Uibdtw22g2oe7LlMeiiig6QopGOBxS0AKn3hUsKuxb/dqJRuNTwr90VmRLc1dBgeRlTZ/uVP4vvHhtEsy/Lffq14ZjRlVJk27v4mrn/El4L3VJJE4VflWq90iPvFGtDQ7dJJWebd/sbapRQPM42c1p6aqJMLZ+mfvVRVSX2TV/wBav31X/wBmqu37xt/k/df5KvrDHJG1Zl1vt5tnzfN/DS5oxiY+zNfS5kklG9MBvlqe8t/MjCPtcqn8P8NZek3yeds+6W/vVrwsk0Z+fYd3zNRHYqUTFuoXjuVdPut99a/QT4yyFP2AVkB5/wCEP0nn/wABq+D7q1RszI27/ar7t+O+6L/gn3J6r4Q0r+dtX694YO+U55/2DS/9JmfYcJv/AGPHr/p0/wAmfDdrfPIoSZP/ALKpWjSTbcom3a27bWHZ322b+Iqvzbm+7W1FeQSRkQzZLLX5DzcsT4zl5ZleGN4WPnJ96rS7WjDpub/e/hpVt3ZmTeq7v/HabHHPCzb/AJt3yoq/w0fEHLyj44ZIPn61ZhWaSPbs2/J8lQpHcsE2dP7tTRs63P32/wCBU5e6RERm8tvJ27mZPmajzNsbDG35PmZadNHM0iu83H8LMtRXEyeS6Tvhv71KS5g+EwdY2bpX35Lf3a5S7YSNsT/x6um1aZ41O9Np2ferl7hjIx3n+Kj/AAm1Pcn0a4+yX6TbsfNX7L/8Ek/2jE1r4A/8Il/as00iq1vdNH8rfL8y1+Lu5lO9etfaf/BJH40P4Y+KqeD7yRtmobVijVvvSf8A7Nc9enOpSlynnZ5hnXwM0j93f2c/2nIfB9mnhLx/rW3TpGVF/vQ7v4t1flv/AMF+vhDpWofErVPiL4PuY7m2s71ZUa1+ZWt5vl3V9k+NNHmttmq6PMxh2xs/z/Kzf/FV4R+1X4Bf4neHdS0G7f5NY0aRJZJt3ysvzLt/2t1edk2ZV6K+qVz4PJM0q/WFQqfZPx2kVFdvkZX/ALrU+Nk279jbm/hqbWNL1DSdSutKvE2y2c7QOv8AtK22ooY3/ubW2f8AfNe7KPQ/Q4y5o3LEapIzBOd1fYH/AATLVRo3i9lGM3Nl/wCgzV8iRqiqd4ytfXv/AATQTZo/i4KwK/aLLaR/uzV+keEqkuPcL6VP/Tcz63g124jor/F/6Szwr9oREPx58WsIW3f8JFdfN/20Ncqruql9nzf3Vrrf2g02/HjxUSvH/CRXTf8AkQ1y/l/N5ao3zPuRq+Ozu39uYpf9PJ/+lM+bzPm/tCt/il+bEhk2rvTd8zfdp7N5279xt2/xNU0UE3yps2/xfL/dohgPzP8ANhv738NeV9g4/thDE7TMd+1fvPWhZq8knyIu1fuVWjt3j++6/wB7dVm2ZCwT74ao+yaxj7+hoRnyY9nys392rlmz7hv2tt+bczVRtm3SfIm1v4GarUNvtkCXO5mX77LXPKPMenSiXY1Rt8ny7W+6qtViz+aHzH3I235lb5t1VYY3WRZoYf49taNuzs2/f8v3flT71R7stjsUuYkt0RvKmcfJs+6v8VSJavIxcXjOsKfOuz7tLHC6xo6fOf4dvzbf9mp4ftKr5zn5G/iV/vf71MwqR5veIpLXzJPkTcu7+L5adHbw/Nbfd/ubamkj8lmd02bfvfxUNb7pN6Ozf3G2bflropy+yeNiqc+a5VlRVjXcfl3Ns3VRvFRYWfYvzVpXSo2zzNrfN91X/iqheQpbyfu9u2T+Gteb3fdOWMfe9483jk2t53nNuZ/lWrVnceZGzzIw8tdu7f8AerN+0TSSI/ULVu1k3R/I7Lt/iavLj8J7cDZs7942CbF2qv8AC33f96r1neeSyzJM27+8r1gWd0/nNbOn+sXdWjaNtwkMfH3dv8VL7HKb05cx2Gk+JHk+RJpCy/drtvDupagVXZIuJPl2t/DXm/h9X85/Mh3f8D212vhu68tt8FzGjq6/eWvKxkf5T6DA+9a56N4dupvM2TXLLtTbF/d3V3Hh2J7yQv8AbN8qrtddm5WrzzQ7pFUeWi7mlX7RJIm5v+A16H4UmT90j7lfd8nlrXzWIp8sZcx9Zg5fCjsdPheSNHm4Vl+RVT5d1aCwokiw7GU/eT/ZWovDtu8ccXnD5l+bb/eroY4Zl+fKurfN5a/w15sOaM7HrcseXmObvrFIIlmtkVZF3fvJHrA1C38u3E15bfvmdmVlbd/FXY6pp0LM38C7d33N22sfWLWFYRD9mUuq/eVfvLXtYX93seHmC5tbHCa1b7reZNi+az7fvfK1cT4i0O2mhZPJVPM+7t+bbXpfibSUtZNk0Pzt/CzbfLrmr6xhW3eG2jYyt9z+Kvq8JKPLzI+Hx0eaXvHWeDbZIfgObZwNv9lXYOemCZK8b0nSU8zZ5Klm+ZG/h2/w17l4bt1X4Sm1miCD+zrhXXsPv5ryzTNPSGIPCih2/i/h21+8+JbTybJE/wDoGj/6TA6uNLrC5e1/z6X5RNzw/pbIsdy6LFu/8d/2q63TbObc3yW+9UVd275mrnNLaGHykdN275d0f/s1dHpMiXDBLZ2bd/49/u1+Oy/unxMXyllYxeKZssiL8sqr8u3bXJeK/HGm6xcXOm6NNI0FjtWWOOX/AFjfxf8AAqPi38RoPAfh+Y2dzCb+4iZIoV/5Z/L96vO/hGZodH/tW88wtqkrPEzfLu/vNWEufnOipL3Trvj1O+seE/B3jmGZjp+tadvi+0LuaNl3Lt/2du2vCPFGpJ5MlhMnzN81er+LtSe8+C9/4G1PUma58G6tNPp27/lpbyfNtX/ZrwyS6e6U6leJuVk+Vfu7qJfETTly+6zwf4j6Fc6X4onhSNtn3kb/AHq5zzrhR99gK9X8dXmm6lqmblNzfd/3VrmtQ8BwszTWsy+Uy/eD1fLM6+Y5O31a8t2DpMwrptB+ImkC3Fh4k0fzkb780Z+asi88I3NuzbHyn8LVQm0ieKTy/MUk1oP3ep3LXHw11lv9GuFt2b+Gaib4f6VJH52m6layqz/djlrgJLaaNv8AVtt/vVNCupIuYJW/4C9HNL4ZC9mdPefD+/hdvJhU/wDA6rN4XvIVR3TarJ/frGTWtXtFBS8k3f7TU0a3qTf8vLf3vmalze6HL/MdFa2cNuyPNcqrK3zr96tqGR7zZD5jOFX+/trirXVn8xZJpuV/vVv+HfE0K6pG7/Ntf5lb+Kjm5hcvuHoOj6Homh2f2m88tJWVW8vZWV4k8TG8Y6b9jj+zN9+P+HbVu8l03XLhZodWjSST5dsj7aIfDum2sJmv7nzP7qq25v8AdojymSl/dOOl8KeGdVsZFgdoLn70S/w1xF3aTWd08EowyttNeu61oNna2ralZvHEf4l3/Mq1wHjaSw1K8a7sCvmR8S7f4qJfEbU5HOAE9Kcq7aFXbQzY4FL4TYWgNu5oYbutIq7akBaKRjgcUtXHYAoopdjelMA/g/GlaR2WlWPb99PmpfLf7j9aXKjMYoI+VDx3rtvgl4bh1zxnbSXO1orX9/KrDcrKv8NcfBD8wXNfQn7NXw5tlsV17UIZEEj7tzL8rL/drGtUjRhqc+KrezpSPsT4K/tTeMPgp8H7jwX4SSFJ9a1ePUri6b70e2Py1j/4DVKT40fFH4hak954q8W3XlRsyxQtP+72t95tteZWlvNfXCb9uyN2Tds+bb/dWuhhjMNq6JNHskdfNbZ8y14ft6tSR89GpKT94t+INavJr4F7ld6t96Nv4W/9mpVDzfJMm1t38TVWhhsLaZEuRHMytuSNl3bv96pri6kmuGS2s1iT70rNUSlyxL5TrPhOnk+NrOPaD8k2GK4P3DWj8apnXxHbwRKNzaf95ug+dqzfhUoHjqyO5WzDJtO7LY2Gr/xyuDF4js0W3Z/9Dy2JdoI3txX7dlf/ACj3jeb/AKC1+VIPhjocfJpthYyNc397uYJ86qny18k/tYapZ6h8cJrW2+VLPTo4k/8AQq+n9e1D7Pbb5n/hZU+f+H/4qvjn4uXqap8U9Zu4Yfl81URWbcy7Vr8Xy2PNX5jtwP8AF5jAl+b5KhvIXaFkRMLv3f71XI7dCux9oP8AeqvfXibWRP4fvf7Ve/yo9P8AxGRNb7c1HI22H50w1PupH3NDs3f7v8NU5pnk3I75qYxNIkH8W+iiiqlsbBSL8u40tFKIH6Qfs8/8o3U/7EvWP/Qrqvzfr9IP2ef+Ubqf9iXrH/oV1X5v1+0+K3/IlyD/ALBY/wDpMDhwnx1PUIztOXGRQ43nJpvXbTq/F47HcG7c2+ikVdtLTAKKKKzAR/umnK3bZndTX+6aFXHAoAcVY9qP4/xoY5bikKbuDxitCNmFFFL91PrWZYbG9KGb5VoVttG3a3I+Wq+EB9vvZxF8vzfxV+kH/BDX4O3lv4l8V/H54Gb+xdLj0nTm3/KtxcfNJ/5DWvzp0S0lvNQiVOBvX5ttfth/wTn+E/8AwpT9jfw3Z6lCsWoeIribW9WVdysvmfLEv/fK/wDj1eRnGI9jhH5npZPhfrOM9D2i+iSTe8zqvmJ8vy7q564VFbek0b/wsy/w/wC9WjqFwkrMjo0bK38T/My1l/aobVmfepLP83y18jha04e9I+ixWFK3lo0ium3K/wAS/LuqWOGDKb/m8v8AhptxMjYh3xosn3I9/wA1Ekc23y9igfdXb81evQlzazPFqU+WZFJqU0V0qTcIqMqMvy/99VHcalOWhdHYKr/Ky/7vzLTbqRvu/Y9vlptfc/8ArP8AarMmZLaTZbTKBvZZWb+Gu2jHm91HPL92bK6h51u00M21v7rfe/2qguNWhmV2srnczJ95vlrJtr2G1mebC7PurJJ95qikvN8b3EyMPL/5ZtXdTpzicUqnMTXEyTKby2TfIyfPu/h/2qwNTXzpnR7yPa3y/wCzVu9voZIVkdGiVUVtv8SrWNqV15as7w+Zt+Z2+7t/+KrflMoyKF02mx75kRS391lVmZf726q0eZdIbY28tE2CR1JzVHWrx5IHhhmt2RX2fu/4atWEijQvNReBE5APtmv1vwVhFZ1mHL/0C1P/AEqB9twfK+KrP/p3L80YDTTRwxrsZlVGVFj/AIW/2qxtckuLyGR9jJIvzMsfyrt21cmaG43pM7I7MrLtes7WryaOxmyVZ9jKys/zV+A+zlGem55NKtFQPjL9qyxhvtWluUfL+a33a8EmaRZG2c19EfG7R/t2qXaIkbM27ZXgeqWr29w8KH5l+X/Zr6ihHlpRPm6kuarLmM5bd3z/AHv9mrcMChc7GojVmb9y6/Kn3aGmeNtnzf7u6to+8TLm5hsjeSqpDTIVQyF/4qV1dm5p3lPtH8IpBIsQs7Kp2fN/erSs5DC2/ZuaqFu3SP7wZdtW4WSNU3/+O1UiTSsZE8xYXdd33t1dJo+n/wBqYh8ln3cKq1ws2oeQ2U5K/wAVdH4K8bPpd0iO+4fd21PxBL3Tb1D4d62rb7aGRU/grJvvC2vab99G/vLuSvXtH+IlneadDD+53fxbv4qW48TaVds/nabC6q/z7YqKcomMubmPIdL1zWdHul4YfP8AK392tTxxodt470p9VgRVvIV+bd/y0rubzw34M8SSBLbbaT/e2yVb0v4S3Nq2+0v43j/uxtTj8IlLld+U+XpoJreZ45kwV+VqZnJ612/x08G/8Ij4sZIn3JcJv/3Wrh1XbWnKdsZc0RQ27mikVdtLSKFVX3Vf0/5mEOzP8W6qEbDdnexrd8NQxzSMmzlv4amRlM1ZvJ0/RXmLsr+V8rVxrM7MXfq1dH43uBbwx6bF/F80tc/b2/mZfY2F/u0+ZFR90uaX5MJCTYNXJIyJt43bfvfLWXHHNHMuz738O6tKKRmjG/70dHvmcpRNfTZHaHzmh+X5dtQ6pbuqibY25vut/dqzpsyCLe/z/wAPy1FqkbqvD7xt/v8A3aI/3jP4fhMmS4fbnfyv8VbmkyOzfI+Rt+7WE3yts7/xVoabePbrscUw5u5u3EMzKP7lfcnx4Tzf2AJY1bGfCOl4I+tvXwzZz+fC3z79yfxV92fGdFk/YLKBcg+EdLwP/Aev1zwud8pzv/sGl/6TM+z4V0weP/69P8pH55tG8bfK/H92rGlyfZ5EfDLt/wBqrF9a/MxRFX+7uqlI3lrv2NivyM+LjLmN9bxJI/kjbc38VSrJNNJsT/vmsSxurlWZ/lxWnZ3+66SEv87fM9A5fEX2WONw7o26mf6tfMfduqe6kmjVU37hsqHb5g+/8mzc0jPQOQ/c8ny+c2GT5VaqepL5MZLpu/2t9WZWeM/PD5x+6rf7NZ2qt5a+c52qz/dpx5+UmXLI57WLwtv4Ynf96sNvmYvWxrVx95E/i/hrGpG9PYK7/wDZv8ay+CfizomvB1RYb+Nvm+796uAq1pN09nfxzI+Nrbt1AVI88LH9I/wh8P6l8Qv2WdJ+MGm20NxYNKsEskfytGzL8skleaeMvAt/dabd6zoFy0otWZ/MjbdXD/8ABGP9paH4ofst6j8B/FuvNCjQSQXC/wAW5V/dN/s/erQ+HPxI1X4P/EK8+EXxIvPtFvHcNAl5JF8qx/7VKrk0cTR+s4de9H4j8rzfBU8vzRTjpc/Kr9sfwOngv9obxCiWzQ299dfaLWNn3N8y/M3/AH1ury+H/VHen++1fdn/AAVo+Dtm0cPxL0HTY9kN1Iktxu+aaNvustfDNrCjf6N8oVf7zVvJNwiz7nLsRDFYWLH6evmN5bpsZfu7q+v/APgmmjx6L4tV8Em4sjke6zV8kWquzNsO5t33m/u19df8E2Tu0fxa3rc2fH/AZq/RvCX/AJL3C+lT/wBNzPtuClbiSj/29/6RI8Q+Puz/AIXj4udl3ga/c5T/ALaGues7W28tZndlMn3K6347Wu743+KF2L83iG5bcf8Aroa5lYUVgmzmT5V/vV8dnvL/AG3iv+vk/wD0pnz+ZytjqzX88vzZFJFuVk6fPtZv4qfDG8ah9/zbPu7PvVI1m+7+Jtvy7qdItzHGqQo2Y/uNXly5Dh5ve1K0mRF9xgu75FqW1VFXL8fxf71KqpMrb933/m3Utvb7d0kL7t3y7aykbU5e9EuW7ozJ91P/AGWrluPMk+d2Ct8q1BZ2/wAo3ov+0tXrPfErO+5v/Hq5/dPVpyLdtHDG6QpM23b91qsiGG3xsk3Fm+dt9V7fzmwiSLtZdv8A9jVq1je4bfInG77tZ8vKdnN7vulm2berQxvsff8AMy/dqzFb+ZD+8TaqtVO3CQt86YVW3ffq1GUWFfOfPybmZf4qqP8AeOeQeWjTOk24r/Cu/wD9Bp6yPFtZ9zJs+6vzf99UkLQvJ5zx+Wnlfd/i3f7NSQySLC8O9Q7fcbfW9P3ZHjYzmlsVpPmKOm5h93b93bVC+mSNf4dsO75t1X5Fe52vMmfl+9/DuqnqUNmpZHdWRtu9fvKrV0nHGPL8R5Uv2m3/AIN2779WbX94uxw3/AabIqLIGj6VYhx5yuifK38P+1Xi8yPoIx5iza26FfMjjw7fKlaNqmZEfHy7vnqpDCkaq6SM21vvN/FV21hmkf5Pvf7VRLm+ydtGJs6KqW7KmMszfP8APXXaLJCtx5Pk/LtXczfwrXJ6Xa7sfZnzI332/u12Whx7I0y6su/5mrzcRKZ7uFj2O38P3Ft5kaI/Ej133hmaFpvs0ybfLb5Nz/NXnGiyQqyRyQsoX+9/E3+zXX6FI8zR3MN78y/wsu5m/wCBV4FT3uY+jw8pRPVvDdwY40hm+5G+1tv3q7W3jE8KXMzttk+WJa8z8P3SWsjW8KN53yyvul3K3y13fh+dJIUciP8Ady/Iv8S15vLGnL3T2Iy5oamm0LtbvMm3cq/3Kw9XtIZVR32n5fmkX5drV0Sf6n5EVir7tu75mrO1KztmWR96/Km5vk+Vfmr1MJ73unkYzlOLvtPtriTznSRvMRt6yfeWsTUNDtre1kSGTe3/ADzX5q6rUtPuZpGfzl+X+FnrEu2dGNnBDv8A4UZV2qu7/ar6bCRltFnxWYe9zOxpaZbKngk2rDj7JKDg+u6vOv7L+zq9ym0Q7ti7q9Mso3fww0ccQDGCQKue/wA2K4u40+aRdkyNG2zcyr/DX774lTtlGRf9g0f/AEmB18YQ5sFgP+vS/KJm6P50MSQwt80n3dvy1f1jxJbeGdMa/mudrqn7r/ab/ZqnfWv2PF4qM38TfJ92vKPil44fULoWENyxSNPlXf8Aw1+Pz+I+Epx98wfFniDUvGXjTfePubdti2/N8v8AFXex6lDoun6H9js1kSO/aK6VU/1e5fl/4DXGeCbWG3sTquxvNm/1Uezd8taOoeJLO10G60q5dkmuIN1qu/5lkX7rUpR5Y8pfNzfCHxU1qw0fxBBrdy7Q2mof6LqNuybo9u75Wb/0GvFvirqiaDeTW2muzWDfNZf7K/71d54q16z8UeG5X1iFsN+7aPd8zMv3q8Z8UagmszS6VNNJ/ovyru/i/u1n7ppGP8xyt1cTSSPc3LttZ/4arWfiLU9LVw/zQ/3m/ho1C6muJnt/ubf4Veq1vIkjPbTfP5ny1fLzGxsQ69DeQ75nU/3qq3C2cm14UVNtYOoWt5pswTe3ltSQ6xJ8qSfrSDl/lNCSFAweb/gG2qupahDBH5EMK/7bfxU2S6RkZ8sStUJ980hffndVy+EqPvfERySNI2+kyGHBWpI7V2Vn9qlW12rh0o5UXzRKx+4PrTo5HVg6NytTpa+YSWX/AIDUn2FF+4agRu+GfEkc0KWV583zfJu/hre+y6k0zPp82V+9XBw27rcfI+K7zwnqTxwoknzv/C1BlL+6QXi63dK9hczMEZP4lrNTwy9vvkfaVVf4l+9Xd6hqVh5av5G41SuLVLiT9ynzN/DVxjMiXus8jnjkinaKRMYblabXXeOPCr731K3++v3465Gj/EdUZcwUUUUe+UFFFFHMgClCljhaWLofpTmyozioJluKu9k+ROf4mpHV2P8AdajG1dvyt/srVizs5riZIURvm/8AQqrmROx0/wALfh5qXjzxFDpVnDuXer3Df3Vr6+8H+B007T4dBsvM8mPb8v3d1Zv7IPwt0HwP4Q/tjxPpM1xqGobZfMX7sK/wq1ewx+KPDEcM8KabHskXam5f/QWrxMVW9tK0Tw8RW9tU5bnLNoOsRKYXSOLa/wArf3f9qpbXw7DbyKb+WR3/AI/9n/vmtS81rSmkRHePYy7nX+Hbu+WmyXln5zbPlK7m3L/drzpfvI2OL3Y+6VLeGzhVvJhWU793zf8AoNQNcuN3nbd0n3vL+7Vm4VJmZzMyKvzbt/zNUDKnzOY127t21azlyx3kXGXue8dP8I5JpvH9tK+zYUl2gdR8jVc+P8xi8QWvlJukNiNo/wCBtVH4PFG8fW0kM8mDBIGjZePuGtH46zRQeKbKWcttWxyAvc72r96y3ll9HvGf9ha/KkF1Y4G38OJNG9/fuyBn+Ztv8VfEvjG8e88fa9eRupaTVptu1dv8VfaXjjxVZ+G/D9zf/bGxJEzvG0v+rbbXxHDsvNQurxPmWaeSRmb/AGmr8ey+MT0sD8LZA0jtu86b73/jtQyWPmR74d2f9pq01sxJGziHb/D9ynR6bMI9mF/4FXsnb8PKYjaTCy797fLWZqNktv8AMiY9q7D+x3klDuMLs3bW/irH8Uaa8No03b+GlKPKXTlzHN0UUVB0Cb19aWiitAP0g/Z5/wCUbqf9iXrH/oV1X5v1+kH7PP8AyjdT/sS9Y/8AQrqvzeZscCv2fxW/5EuQf9gsf/SYHDhPjqeotFFFfi/947gooopgFFFIzeiVmA5RuNCfeFNf7ppY8pQAqv8ALx+FJIibsRmlYfNj1pKqQCLv705/vGkop8qAKXc8h+akUN61JCuXAc/epe6Znr/7F/wUufjf8efDfw9SFtmralGkr/wrGrbpP/Ha/cXVobC12aboO2Gxt4o7eyhVfljjjXaq/wDjtfn7/wAEX/gz9jXWvjfqulRuLGBtO06SZNv7yT7zbv7yrX3tcSTRwmYwN/u/3a+Bz3FyqYzk+yj9A4cy/wBnhPbS+0Zd5dFf9GmdX3S7E3N826s+4uHjLQ2ybv4n3fdq1fTPCsyJCwT5WfcnzbqqTL5jOmyOXdt/3vu/drxvby5/7p6lbCxqcyZPZw/MP9Tv/wDQastH9li/f7RG3937y1nxslvMieS33dztv/iq4l1ugX7TDtT7zru+7XbTx/tDyamB5djPvvlaO58jcGfbtZvmZa5y8jtlhUuV3+a3y7/vbm+7urqdcuraSMzTP/HtXb/DXK6tdQq0mLzlfuLs/wDHq97A4jueLjsM47le6kh+z7+rRv8AKq/w/wCzVZtReONv9Zuk+/UF5qVszF3diknzI38LLWHfaw8dx5KO2N+1vl+Va9unUj/MeBUjOJfvtWCyeT5zI+z/AJ6/NWJq2rbiYQiq+7d/rdytWTNfP5zfafl3S7dq/d21l3195d2yfaV/6ZK3/wAVWr2MeYtaheHb5lsixuy/vdvzbq2tJmz4OE20nFtIcMc5xurhptYDbUuU2M275V+V91dnoMsZ8BiQfdW1lHJ7AsP6V+w+DEEs5x9v+gWp/wClQPs+C5Xxlf8A69y/NHHXF8kMgjAyqqzP/stVC+urmPTbl3TzX8r/AIF/vNTI7yG4mMz/ACrJubav3Y6y/Fl4lnodzfpc7HZGX5X2/L/dr8QnTjz/AAnzNOtywPl79orxYmizSwr/AK64VlRm/wCWf+7XjGqR/ao47nfncm7dW9+0J4o/tzxlJDCu2KNvk+euc0u4e403yX/hr1+blhGxwy973ilGvlMU2fx0SRjdvd8VbktNqPsRmP8AHt/hqGRfupsz/tVp7nxEkDfu8fxUsMjtJv8AO+X+7UEkjqp7/PUTSOq1BUY8xr6bG810uybhv4a2JtLd/wDVpXPaXefZ5ld3xXVaXrltLb+X90/3qr7RnLYzbjQn+d0Rv+BVW/s28hdc7d/+zXSeYny/xf7NTR29sy/6j5lp8qDmMLTdU1iz2p5zKyv8ldNo/jbVYfkmDAs/zs3zVnNBCy79i/K/3Wpyy+T9yH733KOWURSkd7peoWesR+TdN5TyLteRflauk0qy1u2kjis79pQybfv/AC/8Cry/T/tPnJ/e+9uZq9b8B6x/Y+hvquq/c2/Kv/stHwwJly83Mef/ALSvha5m0i21sbWMPyy7W+7/AL1eG19A+NvFln4j02/hvHzDMrLEv3tteATBFmfZ93dT5uY3pjaKKKDYlgP7xQ4rpfDS/Z5Xnd9u1Nz7f4a5+xh3Scjd/erpppIdL8OvKj/Oy7drLU/FIwlvoc3rF9/aWqS3Mjs3bNWdJk8hPJcKwb5ttZ0a/NvFaenw/aGXen/AafxDkJdKizDZDt/2t1TJvjZf92ri6Wkm7ftbbS/2eVXGzHyVXwkcyHWd5/y28j733lqSZluY2hdGVKgt4fL++mV+7uVasrC6t8ny1HL9kPd5inJp6s2+Onra+WRvmqeON5ptj/LUv2fcuxIfm/vNT+EYiK8b7Iptvz/ItfffxpkC/sEGQN/zKOlkH/wHr4E+zuuU+Yn/ANBr75+NikfsCldhJHhHShgfW3r9f8MP+RTnn/YNL/0mZ9hwp/ueP/69P8pHwVc3HmTeS6bv92qzKm0O6NtWrKo64kmjxt/u1Ktv5keOu75ttfkMvePjI+6VIYfMO/qKuW8yWr/6nll/75oht1jbYE+XdTVh23D/ACMF/wBqlzIcpcxM19959/zbPu05pn8vYlRRRw/65x937tS/IzB3RlH96q5Y/ET78Szbtt43/wC1/wACrN1Ro2V/kZt3y7anbzlUun3W6bWrPvr4Q2+zf/F/FSBRly2MHVJELkbPutVCb5tz7PvVevpEkbekP3qz5Gz/AANQbQG1NbofMXZ96oMfvAuKt29u7SeZ5O6lzIuW59k/8Et/jvN8IfiNaSzXMf8ApE+147hvlZv4a+0/2kfiFpHxO+IVvr2laCti8lmv2xd3yNcf3lr8r/hZdTaRHFqlg7QyRvueRU+avuv9m39qnwl8TtDtfA3xIeG2v7WLZa3UkSqzNXtZLj6WCr+/8Mj5DiDKpY+HND4j2ib4C+Lfjt+zbqr6xon2qw2TW9vMqs22RVb5Wr8qNa8O3/hnWrvQdSt/Jns52ieH723a1fv9/wAE4Lyw0vUPEHwP8c38b6R4os9thNIq7d23crK1fkh/wVO/Z3f9n/8AbC8SaPb2fl2GoXTTRMv/AI83/Aq681p4ed50jmya+H5KUtP8z5xjV2kZIfl/3a+tf+Cb8ax6L4rC8j7RZ8/8Bmr5PtY3yHL4WvrD/gm/s/sTxV5aYH2iz5PU/LNX1XhN/wAl5hfSp/6bmfqXBcubiSj/ANvf+kSPH/jox/4XT4phdWA/t65ZX/u/vDXNeX+8TyeS33Gk/wDHq6X46KX+N3ikAKSNdudo/wC2hrmbeSWEbETb/CzN/DXx2ef8jvFf9fJ/+lM+czPTMK3+KX5smaP94d78L/yzqKZf33nI+x/4lo+eSTyelOaP94H35aRNvy15EY8pzS+EZ5PmL5z+Wdz0+1j8uOSZPlLP96nRqkmLZ4fu/fVf4aFLxx5Taqfx7qXxRF7seUnhj8pw/nfe+9V9bvy32Q3OF/2UrP8AOdV2I6/N8u6pI7h4/wDRn+f+F/n+9WMonqUfdgasMnkso2fP/A1WfOeXY/k8bvnjX+GsyG4+YR79qr/eepIWQqyJ5gMn/LSN/u1h9s64yNX9yqu7ybwrfd+7Uy3HnSMU3Afd2t92syGTcu9JtwZ/96rDXD+c6Ptx975aOb7JFSXMi5DNMriF0+6/zsv3ammkSSP7m1N38X3lqrDMi5jmPLL92rMcz7i/7tg3y/NXRH+U8rEcvLoElvJJE3+kfKv91KgvFT5/J3bWSrZt3+zo6Pv3fwx/w1XuGfbvNzt3ffVlrWP8qPN+H4jziS38lvs2/wC98u3Z/FT7ddzYdPm/2qmmDyXXz7nH8bbP4v71TLbozoifc+9uavO9n7vvH1FGUZFm1tHhUb0q6tvLEyYT73/jtJZ2qSRpv4b7y7q1bO1hkXycNt/ibbXFU54nsYenzajrGFFy6csy/Pt/vV02m27QwpNsUs38X92su1tUj2wpIv8Ad8xvlWtnTfkXY7/xfNtrzMRKUtj2sPTtD3jf0ffeTRpC7blX/gK12uk3Dqrwv+7Rvm8z/ZrjNHj8pjcv8is+1Nr/AHq6XSrh2aJNi5b5WXf8qrXk1pc0j0MPH3dTuPD+oGNkd412qnySfxV2+i6l5LJvlVopPm8z7rV5npvnW7LM7sqb/wCH7q11mk6o7SDZ8qL/AHk3bq8+VP3uU9WnU5oHpFjqFtIrP1SN/mk+781OuLx7iMpD99lVmjkSub0nVEa4/wBGufkX+Fl/hrQbWkuoRDPc52/eaP8Air1cLyR908nGe0KOsN5as8fzyt8rbfvVgTR3NvdSO6Llfm2s/wAv/fNauuXEKRsm/ak33Grm7i4fznhR8L/Fur6DDxjGPMj5XHRkdLZO0vhws7qSYHBK9O4rlNQeHy1+zbm+7v8AmrpdMkYeEPNVcH7LIQD+Nedav4gfT/MmmmVEW33PG3y7a/c/E+dsnyFr/oGj/wCkwPQ4sV8Hgb/8+1+UTI+J3ij+zdNTQoVZp5FZmk/2a8Zjs5ta1x7Z7aN2kf5ZGbayrV/UvGVz4m1S7ufOzE3zW+5/ur/dqxoumx28L39y7O+35G/551+UUY+6fBS+PmiaV00el6fsRPu2+1FVvu153qF9NqV00zyeWsabUZvmrd8SapczXImtpv3XlbW/vVwPjLxFNbw/Y4PkLbmZvvUv8IfDEg8aa88+pBNNmZ45G/f7V+61ch4wuIWmZLN95X5dyptqaG4CwmF9z+Z/t/drDuoprC7aG8m2/eZG3U+VGvumJq+yS3+0pDsm31jCZxJvR/m37q2bhrm6mZ/3bNvrKuoEhbzk/wCBKtHwmkYwN+3WHXNNRJpl3Knz/LXP6lphs3x/dq7o+rJHebPJ+X7u6ta80+G8h3w/NL/GtEthfCcms0ynDpuX+61TwTQ/LvRfl+bbUmp6bNbybmh2lv4aqbnjYj7rKtLlLi+Y0LeRC2/Zj/ZpfLRVV3+9Wesz7Vbdt/2hUv2p41+/u21JPKX1lRYfkeopJ4Wb7nH3qprcbv4G25p3mfMU/wDHq0KLPmJ5n31Vv/Qq3dC1B4WTY+0qtcyq7vnT+GrtrcvHJ/wDa9TzGfunWzao80yeYdqfera0uZJFb5Pu/c3f3a4+G4eTYm/dtrs/D8Pmafv3qZPvfN/dp/4SZDtUt7aS1Kb12f7VeceMPDK6XMt3bPuWT+Fa7LxRq0Ufyw7vlTa9c1Oj6pb+e4bbt20xxlynKUUs0bwzMjpgrSUHSFFFKoy3NKWwDo8fwVIsacv2qFW29qmjhdvv8/3afL9ozGLHuY8fLXuf7LXwQfxtqEfirUrZvsVnKuxWT/WSV518NPh7ceMdWFu7+VbxsrXEzf3f9mvqf4P65Z+D0l8N2yKLaNldVZPmas6kvZnBjK3ucsT6T8M+B9N0nQXcW3nSyRbtu35VWsW48J2GqaeiJprW5+9KsyVf8P8AjKfVvDdvMkzErAq7o2+9838VLdatquqQmF7/AHvu+Xy02t/u158qdOOi2PI5eWJyN94NtmZprBG/i/h+9WXN4fubWT5/MSZk2vt+bbXYw6s9vdPD9jZ1Vfmk/i2/xUNqGmyXzH7G0x3ruaP+7XP9XpSYbHEfPAsqO7Hc2x/M+9Un2tFl8lN27Z95q6S+sdHuL5U2SKGfCKyfMtMutC0pXb99t2/M/wDs1wVsLLnL5eUf8HXup/HdrIV+RVlB/wC/bVr/AByis18Q2l5dTqoWwIw/T7zc0z4avp9v43htYDGkjCQnauDJ8hri/wBsvxJe6b4m07SLVwBNpRc+o/eMM/pX7tlaUPo+4tf9Ra/KkONPmlyniH7RXjhNQ0u5ttKdhCsTbG/i214V4V0vdpaXOyRvnVV+eu8+K0k1v4XuIZgrSySqqNu+7WF4RtdukpC+0D7rfw1+R4GnyxZ6mHjy0hI7JFPkum4/7P8AFT00lJJvnRf+BPWs0KblgHzbaoSW80k29ywNehzS2NY+7rIhuLP7sezlf+BVz/jK2hbSZnSHdtT/AL5rr7PZIp/c43PtrH8eafDHo92+xtixMybaPekX9o8nf7ppaKKZ1BRQrIV96KiMQP0g/Z7/AOUbif8AYl6x/wChXVfm/X6Qfs+cf8E21x/0Jes/+hXVfm8rbq/avFb/AJEuQf8AYLH/ANJgcOE+Op6i0UUV+MHcIfmbfmlDbuaF2c7aRV20viARVw3PpTqKKXwgFKvQ/SkoqQE37mNLRSMu6r+GQC0Ab+1FLyppgCr8xra8DaNNrXiC20yC2aZ2lXbGv8XzVip94V9K/wDBM/4JXPxd/aO0W2dF+zWc/wBovWk+6sa/Nub/AGa48XWjh8PKb6GmHoyr4iMP5j9O/wBkr4V2vwh+AOg+D7Z/Ku5rL7Vfq3/LOSRf7v8Au16ZJYTRtFvdWeP5nk37d1TtY/6Y+91fa+1WVPl2/wCzU50/7Ux3pIrruVm/vf7tfk+JxXtsRKUj9mwuHjh8NGPYwptPudqfaEZf3rb2j/iX+GqFxptzbskdskjf34d/zf71dra6enmGZIV/3W+61V9W8PvI2/ZM3mRN8y/wqv8ADurnVb3kE8PS5eZnE/Z3hk2dW3/O3+zUkk025Sibm/jaRflkro4fDcPkh3h8ot/e/iWs28sfLXyU+8sW7d/Eta0anN7xy+x5o80jmtUmdeX2q/3lVfmX/drk9WvLP7cIQ/kzSbldfu11niJYbhvvsj7dybk+b5a4XxNdQzaeZHjUFX+ZtnzN/tV7uWytK72PCzDD+7oZeoX6XCv9jdl8t9vmLWRdXVzMzO9yxMb7k+fbU91ePj7mFVNqqv8Ae/vVzepas8MzTecu5l2Ov8K19Lh6nQ+NxlPlkWNUmh8tn+b5U3Osf3t396ub1a5xb+dvYlt3zN/Ey1JqXiBJo3tkRS0ifejasC+1yGRt6bmk2/xP8terT5pcp5FTkJr7VHmjjmh2tti+9/Etej+GcN8L1/e7wbCb589fv140upQyfcdt3+y/y1654PlVfg0JnyoGnXJOeoGZK/afBtWzjHf9g1T/ANKgfW8Eu+PxD/6dS/OJ5nb3PmbPs025ZpW+X+7XLfFnVJofDNz9jfbui2/7taUN4beM/eUtu2bf/Qq8++KXiqG3aTTZtrvMm7y2/wB2vxrllzHx8ZSkfKPjpXk1y4uX++0rfM1UNGvPs0zF/utWp423yaxK7/cZ91c+spinVk+YK+6uiMfd5TSJ0/kyRq7+Tjd/erKvpHjwj7sf7NaEN4l1Ypvm+9/drMvPm3OjsW/u1X90jl98pyNlvdqjkx/B92pJJHZgmxai2nd8lSaRBt7SeY74NWLXUJoW3+c23+7UTQzMN/3qU27r8nf/AGqr/EBuWHih0Ub03D/arb0/xG8jNCm1d1cRHG7fJsartr5sbLNsb/dpc3KTI7LzPtDb9iq33dtT2VruzNlX/wBmsfR7xPIX52P+9W3p94gbyUT738S1rzc0TE0/Dun/AG64+zbNnzqq7v7tdf8AED+0o9JttEtrWQJDFulb/wBBrm/Cd3DHqUKXO1Pm2uzf71eqXzaa2jtqqQ/bC0Sqys9PmI5o854Rr032e1l+TCbPmXbXnEzFpi+zG6vc/H8fhvVrVLaGwktpGXd5f3q8e8ReH5tKuN6Qt5TfNUfD8RtTlcyqVWfdspKdCqCRd+6g6TX8O2vmP8g5/iq14wmEccNmlzuRfm21P4YtkjUzO642bvu1h65fPeX7vvVlZ/vLS+2Y8vNMpk+Y1aOnzTx252P81Z8Y/eYetnSVhWNhs/4E1QEi9pd472phd97tTdSmubfds+cVFbqnmHyX+Zal1L99OIUdt+z/AIDQR8PvIr6fq1zcN5P3f4fmq/dXiW8bPs2/w7lqO3sYbWMyVHfMkkJhfk/e+WtBc3vjrfUt0iu8y4b+GtixTdDLNC7FFrnbfT3umXCfdrqtBmezt3R0UIyfMq0B8RmyX32X3VvvV96/Gtt/7AxdCBnwhpZH/kvXwpqljbM29I2279v3a+7PjXb7v2CDbK2P+KS0pQfxt6/X/DHXKc7/AOwaX/pMz7LhR3weP/69P8pHwGusJ5nlu+dv96tGHe8P2npu+5WZb6SjNs+Ulfv/AN2tGO4e2jCPtx93bX5DKMYyufG/ZJbfevM0O8f3qkkWFmR3TBk+Wq011OJN6Ju3f3f4aiWaaS4SF0YBv4qQSjyli4t/9tg23/vmq8av5e/zmI/jp/2h1uPv/dfbTG+VVTfuT+81L3ugvd5hJGfOx5lP/stZ2qKqyfc3bf4lrRkt0uN2zctMbQ55ov4f71EolnNzWbtJ8nA/vVCbGZ12bN3y/wANdP8A8I/5Kqj/APA6kbwn5S74X4b7v+zTjEz5uU5C006a4uvISNifate80+bT1jieHYy/f3Vu/D/Rba68eQ2Tur/Oqv8A3a9C/ah1rwR4i1fw94a8B+A4dGHh/S2ttW1D7b5rapcM27zP9lVX7q1nKITqX5TA8G2v/EjV/vf31/urWnazzaTcLqtm+2aP/VN/dqv4NV5ND2bMbX2tuq9cRyRtKfJ+X7u5a3p7GNSMZaH2D+xb+3NqVjJZ+D/G2vNaTQp/oGpebtbd/Cq12/8AwVO0HVfjj8O2+MupaU02o6TErPNbxf66Pb95mr4A0+6vNJukubZ2/c/Mu371fUfwN/bAfxF8M9S+Dnj+/jZ7rTWt4rq63bWX/a/2q1jWnS0+ycFXDxn7/U+R/L8ldnzff/iSvq7/AIJzNnRvFKkYIns8/wDfM1fMOs6b9h1i5tra5V0hnZFZX3Ky7q+n/wDgnTn+yvFmQB/pNn0/3Zq/RvCb/kvML6VP/Tcz7bgdy/1ho3/vf+kSPG/jkUT42+KlMTBv7duWV/X94a5qO385ld41zv3bv71dL8dlQ/GfxSWbaf7eufm9P3hrnY1/eNs+6v8Adevjs8/5HeK/6+T/APSmfO5jJf2hW/xy/NiBXW4EMnyt/dX5ql2pI3k7GLbfu79u2ntC7R74H27fu0ohLQ7P3j7fvfJ8zV4/2DkjKW8iNdm5k37fm+9UCypCVRPm+fazbNy1buFQ7odm1tm5Vaq7RC3dnfzAI/4mquZBH4rC+Z5f+kiH5lptoySKuz+9/FUUzbf3Xk//ABNSbdtwyJJt3JtrGR3x2LMNw/2dkeDf821G3/dqeOaHaPn+X+CqTFNqu7t8y7akVkaFpEdW/uVly/aOqPOaX2tI4fJ6bl/herNjL5kaTP8AN8rbt1ZUf+qTfyV+bdVyN/JZXR2X5Nv+zS5UKUpGtbSecud/3f4f71WLdtyvNMija/y7X3Vm2s27Y7/LuT5NtXbObazO5VGb5mVnreJx1uXoaFjMVVdj7n2bVjX5aZcrBsKOjMZPlpkbAyIkKYXZu3Sfw0jMis2987fl8tfu/wC9V/4Tg92XunGX1r5LtM+7bu/v1LYrvj87yVbd9z/aWrGqRp882/I2fdp1vHtVY1Tjb8jKlR7GfKe3Rlyk9rbpM2Xh/h/75rVtWeFl/fbl/u1ShjeO3/cup/2a0bVfm2eTtG2vPrUZRPawtT/wIu2Me5Vab/lp/Ey/MtaOm3HnS7PJj+X7q/d3L/8AFVm29ykbF96/991dtZEutjwpsMnzfc+XdXj4inL7J7NOtKUuVyOg02R45g+xSzP/ABfwrXRabfJHCiI+1tm7d/8AFVyVi32eOKa5Crt3KzK33mrXjvNuJpLnai/NuVP9mvJqe9I9Gm4xOxtbra2938zcyq67/wCGug0vUPs00XnQ7k3bn3VxOl655bLv/wBIWRP3rK+1l+X5Vrd0nUplji2PDjeq7ZG+7XLKPKd8akTvtJ1GG3YvN0/ur/tVpLq1hG0iJtfy4vnk3bf4ttcTp+uOZGdEVjGjNt3/ADNWjJqkMLI7p/rE3fe+Wrw/PGRjiJQkaeuXEP2hEuZtiNKyfN93/erntQ1K2hm8mN8Ov8Wz5WqXWL+Z42hfaRvVkZvm/wDHqwdUvEW382ZtzKny7vvV7uFre57x8xi6fNJyPSdHS4vvAnlWjhpZbSVYiG/iO4Dn615V4p+E3xVutFns9F0dTLcjbMXvIhuHrktVnwz8UfEPhG1XSozHdCeTdELndtiz1AwRgd8Vz/iH9srxRp2uTadpmhaVJDDN5bSSCTJx94jD8iv6Mnn/AIZ8WZNl9PNqtenVw9KNO0EraJJu/LK9+W620eup62MxvDWY4SgsbOcZU4qPur08n2OftP2YvjQlwh/sC3jVW6m/iPHpw1dHqfwG+J4tvI07w/Gw27SrXsQ4/wC+qvWX7VPjCWyS6utA0zdIcqsaScD8XqjqX7YPi+0lkih8O6XlO8iyf/F1z/UfBiMr/WsT9y/+VnlQocD30rVfw/8AkTlLz9mH44OS0XhuMgggKmpQjb+b9K5PWP2Nv2h7243x+DoWG/duOrW4/wDZ66rVv2//AIj6fN5UPg/Q5CPvLtmyP/IlYdx/wUp+J0RITwR4f47Ms/8A8cpfUfBff61ifuX/AMrGqPA3/P2r9y/+ROef9iP9pBFaRPA0DMynC/2xbfL/AOP1jX37Bf7UupzNLP4KtVI+4TrNsf8A2euwX/gpn8WiQT4E8OYPQ7Lj/wCO0y6/4KefFS3GR4F8On5f7k/3v+/lV9T8GJe99axP3L/5WEcNwN0q1fw/+ROGb9gD9qcWjQjwBaFy2Q39tWv/AMcqhP8A8E8P2ry+6P4f2h/7jlr/APHK78f8FQ/jGyGT/hAPDIA6gpcZP/kWqkv/AAVV+MiqHT4eeGcHqClxkf8AkWo+oeC//QVifuX/AMrNPYcEW/i1fu/+1OKj/wCCdv7WET7ovAVoM/8AUbtfl/8AIlbuhfsHftRwZGoeA7RQRgkazbE/pJWmf+CrnxnySvw88LlR32XP/wAdqWD/AIKpfGl0WWb4deGVRjgER3H/AMdp/UfBeOv1rE/cv/lZLocDf8/av3f/AGpR1X9gH9oS6QmHwbakj7v/ABNLcZ/8frmr/wD4JzftTOxMPge0ceg1q2H83r1jwb/wUs8f+IZxbaj4O0GFs4IQTc/nJXW6l+2t8Tre386x8MaDJu+6WSbA+v7yksD4LS0WKxP3L/5WQqPA1P3vbVfuX/yJ85r/AME6f2smTa3gG0GemdctTt/8iUi/8E5f2slBA8CWgz6a5a//AByvVPEP/BSP446KzLH8PvDL7Wxylx/8drAk/wCCrnxpiQs/w78Lgjtsuf8A47Q8v8F4/wDMVifuX/ys0jS4HltVq/d/9qcYn/BOj9q8gq/gG2A3ZGNctf8A45SJ/wAE6f2s1BUeAbTP95tctf8A45XZD/grD8Zud3w58MDH+xcf/HaVv+Cr/wAZVfb/AMK88L/98XP/AMdo+o+C9v8AesT9y/8AlZXsOCf+ftX7l/8AInIJ/wAE7v2shFg+A7UMPu41u1/+OVLD/wAE8v2r1H7zwHabv7w1u1/+OV1p/wCCrXxmwGHw98L4P+xc/wDx2g/8FW/jKOB8PPDBPpsuP/jtH9n+C/8A0FYn7l/8rEqHBEdqtX7l/wDInP2f7AH7VEGC/gW1POcf21a//HK6HT/2JP2l4bcRT+B7ZMDGI9Zt/wD4uprT/gqh8Y7ghH+HfhoMfRLj/wCO1dP/AAVD+KkcZkn8DeGxt64W45/8i01gfBf/AKCsT9y/+Vk+w4H/AOftX7l/8icxqf7Bv7UF1K0ieBrZjuyrDWbYf+1Kji/YE/acEarJ4HthtGcLrNt97/vuunt/+CoPxjuX/d/D/wANY7jZcZ/9G1dP/BTL4rKGZ/BHhtQq5O5Ljn2/1vWj6j4L2/3rE/cv/lZLocC/8/av3L/5E8w1T/gnV+1bcXHnQeArQ7upGt2o/nJVX/h3J+1r/wBE+tP/AAeWv/xyvSj/AMFRvjC0vlxfDzw37FluMf8Ao2lvf+CoHxnjtzPZfD/wyxX7yOlxn/0bS+p+C8v+YrE/cv8A5Waxo8E/8/av3f8A2p5r/wAO4/2tP+hAtP8AweWv/wAco/4dx/taf9CBaf8Ag8tf/jldr/w9j+NP/ROfC/8A3xc//HaP+Hsfxp/6Jz4X/wC+Ln/47VfUfBj/AKCsT9y/+Vl+w4K/5+1fuX/yJxcf/BOb9rQct8PrP/weWv8A8cq7pn/BOb9qKS7jXUPBNtFGWXfINatjt/APXoHhL/gpj8evF+qx6Rpvw28MvI/UrHcYH/kWvXtG/av+ItzGBqfh3RVkC/P5SSgE+gy5rKdDwUpL3sXifuX/AMrOar/qJD3ZVqv3f/ann/hf9jP4teGNJj0y08K2o2jMji/h+Zv++q11/Zg+M0Uonh8NQqw6bdQhx/6FXZN+1Z4xTIbQdK3B9pBEn/xdMm/au8dJsRfDOlbmGcEydP8Avqud4bwQlvi8T9y/+VnO6PAL3rVfuX/yJ1nw18AeONC0RtM1/SFVpBkk3EbAH8GroYvBuqrIZ2i+cH5DuXgfnXMfCv47+KPHN3NbapoVqoiAO+zjfHP+8xrsZfGOpqp2WkJbOVVsjK/3utS8B4HdcXifuX/ys5o4bw8V0q1b7l/8gcpqHw18bx3sk2nxKyOrLhJlThvqaSDwL8QbcqsmkrIsabV2XSLn9a27/wCJup2dzHGLCBkkGMhWyD+dE3xN1NWXyLO2fPVBu3fhzWNTKvA7ri8V9y/+VFPCeH0d61b7l/8AIHOyeAfiXI27+yo1bbgMLiPj/wAeqpJ8OvinNGI20CDcFI3tdx//ABVdM/xS12P5ZbSyRiMpuD4P/j1D/Fy5t4Q86WjOekcatz+OamOWeBdv97xX3L/5UDwnh7/z+rfcv/kDO+Gfws8WeHfG0HiTxAwZIg4yJlOMxlegPqa539qj4NfEb4neMdN1PwXo8dxbQab5M8pu442VvMc4w5GeCK7zwf8AEzUfEniaHRrjT4EhmD4eIMWBCFuTnA6VoeP9R+KOnTrH8PfClpqCG33NJd3CpiTJ+XBde2Ofev1nJci4FzXw1r4HLnia2D9veXLByre0Sg7KMab91Llb917vUaoeHqldVqv3L/5A+PviL+xb+0Z4hhtrHSvBkEkUcu+RpdXtwT+b0ul/sU/tFWcYR/CNsNn3R/atv/8AF17rcfED9usayLa2/Z+0A2eObhtXhz+X2rP6VqWvjL9sJ3H2r4M6Ii98alHn/wBKK+fo+HXA8YWjh8x+dCf/AMpOlU+Abfx6n4f/ACJ4Kv7Gn7QDgmTwvbKSMfLqUHyj/vurQ/Y0+NJCRt4TtgqptyNRhz/6FXuq+Lv2tyxDfB/RQAeD/aEfI/8AAipovFf7Ve0mb4S6PnPAW/j6f9/60/4h3wT/ANA+Yf8Agif/AMpE4cAPevV/D/5E+fj+xj8b443SDwpD935M6nB/8XWP4y/Yn/aP1TQJ7TS/B1u08yBdp1e3GM9eS9fTg8VftS7xn4T6Tgrk/wCnx8H0/wBfWV4x8cftoWGkmfwZ8DdEvrzeAIZ9UhVcdzk3K/zo/wCIecE2/wB3zD/wRP8A+UlRhwCmrV6n4f8AyJ8Z/wDDuP8Aa0/6EC0/8Hlr/wDHKP8Ah3H+1p/0IFp/4PLX/wCOV9P/APC0/wDgpZ/0a14X/wDB7b//ACbR/wALT/4KWf8ARrXhf/we2/8A8m0v+Ie8E/8AQPmP/gif/wApOj/jBP8An/U/D/5E+YP+Hcf7Wn/QgWn/AIPLX/45Qf8AgnH+1oeD4AtP/B5a/wDxyvp//haf/BS3/o1rwv8A+D23/wDk2j/haf8AwUs/6Na8L/8Ag9t//k2n/wAQ94J/6B8x/wDBE/8A5SH/ABgn/P8Aqfh/8idj8HvhP448JfsVr8G9d0yOLxAPDOpWZtFuUZfOlM/lrvBK8715zgZ5r4tb/gnF+1qeR8P7T/weWv8A8cr72tvHXxI8Pfs66h8Tfil4TtNK8S6VoF9f3+kwTCWGN4FldF3JI+4MqIThyfmPQ8D5A/4ex/Gn/onPhf8A74uf/jtfQcf4DgOGEy2hndStT5KKjTUVaXIlFfvE4NqWiurKzvoZYahwLeTp1qr112/+ROK/4dx/taf9E/tP/B5a/wDxyk/4dyfta/8ARPrT/wAHlr/8crtv+Hsfxp/6Jz4X/wC+Ln/47R/w9j+NP/ROvC//AHxc/wDx2vzf6j4Lv/mKxP3L/wCVnV7Dgr/n7U/r/t04r/h3H+1p/wBCBaf+Dy1/+OU3/h3D+1r1PgC0P/cdtf8A45Xb/wDD2P40/wDROfC//fFz/wDHaP8Ah7H8af8AonPhf/vi5/8AjtV9R8GP+grE/cv/AJWHsOCv+ftX7l/8icV/w7j/AGtP+hAtP/B5a/8Axyj/AIdx/taf9CBaf+Dy1/8Ajldr/wAPY/jT/wBE58L/APfFz/8AHaP+Hsfxp/6Jz4X/AO+Ln/47S+peC/8A0FYn7l/8rD2HBX/P2r9y/wDkTiv+Hcf7Wn/QgWn/AIPLX/45R/w7j/a0/wChAtP/AAeWv/xyu0b/AIKyfGkDP/CufC//AHxc/wDx2hv+CsnxpAz/AMK58L/98XP/AMdp/UfBj/oKxP3L/wCVh7Dgr/n7V+5f/InF/wDDuP8Aa0/6EC0/8Hlr/wDHKP8Ah3H+1p/0IFp/4PLX/wCOV2v/AA9j+NP/AETnwv8A98XP/wAdo/4ex/Gn/onPhf8A74uf/jtH1HwY/wCgrE/cv/lYew4K/wCftX7l/wDInE/8O4v2tN27/hAbT/weWv8A8cpf+Hcf7Wn/AEIFp/4PLX/45XpGjf8ABUn4u63GbWDwJ4ZS8P8AqY3S42yH0B83rVC4/wCCrHxvtpmt5vhv4XR0bayslz/8dpfU/Bf/AKCsT9y/+Vi9hwX/AM/av4f/ACJw8f8AwTj/AGsiw8z4f2gHf/ieWv8A8cr7Z/4JvfAy8/Zo0HV9Y+JNvb2mr6gUt47aPbMRCRl2Lx5GcgcV87+Af+Clnx48eeI7bw7p3wz8OSS3MojRYorjJY9uZa+9/D/hS3v7Czk1K6cTyWiNeCIbVjlK7iozk4rxc6oeBEKPssVjMUk+yV//AE0z18nwHC9XEe0w85trvt/6Sj0TTPi74GtExLfyE55PkPkj8q1bP41/DJZWF1qjsrY+ZrSTt9Fri9I+EmgX8ImuNRvFHcIU5/8AHa6LTP2dfCN64WXWdSXK5XDxjn/vmvjHlv0a5R1x2N+5f/KT7hUsO4rc6OL46fCKJ939uyHnAP2GXgf981ZuPj58GpQXj12QF2GV/s+XgHr/AA1n237JPgqeHzz4i1XA7Bosn/xyrUf7H3gGRjjxRqxA7AxZH/jlZrL/AKNMf+Y7G/cv/lJoqNGPulS++NvwqeV2t9dkI2lVb7DJu29v4awdU+KvgK7RWg1hg38ebST5v/Ha6GX9kTwaCUh1/VmY/c5ix+PyVzOofs9+GLOZoF8QXuVJG5gmAR2Py9a2p5b9G37OOxv3L/5SRUpUOXW5zOr+KvC95OXTUJHGSQTAw/pXH6syXzq8NxsVRt2qnOM5rrNd+HWj6ZOI7bUpnUHErMV+X9K5q+0tbZ3FuzPtkKYbg5FejQy76O9PWONxnzS/+UnlVsLlc7qTl/XyOQ1XRNbmDC3t1kOc7vMALt/eOaxNT8GeMLmdwLZGiKfuhFIibW9+ea6XVvEOoabIyJaI+DgYycn0+tcnqfxi16wLL/ZVrlBkhg33f++q97DYDwHfvQxeK+aX/wAqPm8VhuGHJqpOfy//AGTL1X4Z+PrjIs9LQEr95rpMZ9etY0/wY+J1w29tMiVmfc7LdRnH+7k1b1D9pjxJaMUTSNNBVcvv8zj/AMerPH7Vvi3d5baBpeexUSEf+hV7NLL/AAV5fdxWJ+5f/Kzx6tDgm3vVav3L/wCRF/4Ut8TyVjXRYlj/AIl+2R5/PdXqPhjw5q9h8MB4ZvoFS8+wzxGPzAwDMXxyOO4rzSD9qHxbI6o3h/TTnrt8z/4qrtv+0j4klG+TQ7HGcYUSE5/76r6fhrOPCfhnFVa2ExFZupB03zRuuVtN2tBa6Lv6HTleO4MyitOpRq1G5RcXzK+jt2itdChdfAv4iGPFpYwLuXDBrpcr+Oa808dfsl/HzxH4lS+stDsjbxwldzahGCT9M16v4g/aa8RaLa/aV8NWLARlizyuAMV45bf8FNPHl74kvNHtfhzoxhtmISVriXLY9ea+fjl/gnusViPu/wDuZxww3AnLpVqfd/8Aannmv/8ABPD9p+/unktfDmnMrNkZ1iIf1rHb/gmv+1WTn/hF9M/8HUP+Nehar/wVU+JdhI8cfwy0FinUNPMP/Zqpf8PaPigeR8K9A/8AAif/AOKq/qPgp/0FYj7n/wDKzWGG4H6Van9f9unO6J/wTr/agtYXiu/DGmKD0H9sRH+tR3H/AATo/amlfJ8N6a3zZ3DWYR/Wu60n/gqT8TNRT5/hloSv6Ceb/Gi//wCCpHxNsjtHwy0Nj6edP/8AFVH1PwT/AOgrEfc//lZDocDc2tWp93/2p52P+CbX7U3O/wAL6Yc/9RqH/GlH/BNz9qf/AKFXSh9NZh/xru1/4KqfE9ip/wCFZeH8H7x+0T8f+PVKn/BU34myjKfDPQfu5/183/xVH1HwT/6CsR9z/wDlZXseBv8An7U+7/7U4P8A4dwftR5x/wAItpeP+wzF/jUh/wCCb/7TZw58N6duH/UZi/xrtx/wVO+JaDfP8NNAVT91/tE2D+tRt/wVX+JQGV+GGhdcczzf40/7P8FP+grEfd/9zF7HgaP/AC9qfd/9qceP+CcX7TOf+Ra00D21iL/GlT/gnV+1FGqxDwzppVf+ozD/AI11b/8ABV74lBii/DHQQf8Aanm/+KpU/wCCrXxPZtrfC7QR/wBt5/8A4qmsD4Kf9BWI+5//ACsaocD9KtT7v/tTnIP+Ce37TsChV8Madgdv7Yh/xrQtv2B/2loAWHhnTQx6/wDE2i/xrXX/AIKr/Ekjc3wx0PHtPN/8VV7Tv+CoHxGu5Ak/wy0ZQ33Cs03zfrT+o+Cn/QViPuf/AMrJ+r8Df8/an3f/AGpT0/8AYZ+P0TB5/DlgrbcM39qRn+tdT4a/Ze/aH0mOS3u9As3jP3VGqR4P61d8O/t/+O9bIWTwJpCE9Assv+Ndhp37VPxC1BFmPhPSYomztlkkk28fjSWB8E+mKxH3P/5WZyw/AcdHVqfd/wDamG37KXiy/iB1HwXYCXfw63qDav8Ad4Nc1rv7B/i/V/Nh/si0CSAgH7avFel3H7V2t2G2O80HTncpuYwzOV/nViH9p7xDPp7XqeHLFSMHa0j9D361p9R8F9vrWI+7/wC5h7LgP/n9U+7/AO1Pk/Xv+CaX7SsWpyroeh6bNb7v3UjatEpx7gmoLT/gm5+1OkgE/hbTNobOf7ah/wAa+hPGn7cHxE0ATnR/AmkzCEZ3TSy4I/A159B/wVG+KjTGGb4V6GpHpPN/8VUPL/BTrisR9z/+VmkafAvL/Gqfd/8AanNr/wAE/P2l7fT3hh8NaY0hTaudWi/xrnp/+Cbn7VLS+ZH4V0zHp/bUP+NelXf/AAVI+IUFwbdPhvoeV++Wnm4/WoJP+CpfxQCmSL4Y6CVHVjPN/wDFUfUfBT/oKxH3P/5WP2PAv/P2p93/ANqeeL/wTY/ao3iQ+GNMyGz/AMhqH/GtCL/gnX+0+iHd4X03J7LrMX+NdY//AAVV+KkbfP8AC7QMeouJ/wD4qr0P/BUP4lSQea3wz0IfS5m/xpPA+CnXFYj7n/8AKwdHgbrVqfd/9qcAf+CdX7U4kJHhjTto+7/xOof8asRf8E8v2pduZfDWmA/9hiL/ABrtl/4KifEpsEfDLRBnsZ5v8aQ/8FQ/iiEDn4YaFjGT+/m4/Wn9R8FI/wDMViPuf/ysPY8DSf8AFqfd/wDanJQf8E9/2mo1O/w3p59F/teH/Gqk3/BPD9qWWUlfDGmKD1xrMP8AjXbD/gqP8Tdm9vhjoQ9B9om5/WlP/BUn4mbcj4XaHk/d/wBIm+b9aj6j4J/9BWI+5/8AysPq/A0f+XtT7v8A7U5PTv8Agnv+03asHfw1p2QMc6vEf61r2/7Bf7Q4t2iuPDlhknII1WL/ABrYtf8AgqD8T7iLzT8MNDX2M83+NWB/wU88fjHm/DjRhn0mm/xo+o+Cf/QViPuf/wArF9X4G/5+1Pu/+1Obuf2CP2jnO+PQLHOM4GrRfe/OvqL4nfDLxh4k/ZSb4WaVp6Ta1/YFja/Z/tCqpliMO8b2IXA2NznnFfP3/Dz/AOIJGV+HOife/wCe83T161E//BTn4rTz7bX4daBGgHJladifycV9FkuceEvDuGxVLC4ms1iIOnK8W3Zpr3fcVnq97+h6OAxnB+W0qsKVWbVSPK7ro77e6tdTlk/YP/acjYlfBVr0x/yF7b/4ukf9g/8Aab2/L4EtCf8AsMW3/wAXXYJ/wUr+LAjDT+AvDwJ9Fn6f9/Ken/BSj4rlA58A6Bg8nCz8D1/1lfOfUfBn/oKxP3L/AOVnlfVuB/8An7V/D/5E4qP9gv8AadVh/wAUVajHrrFt/wDF0+T9gv8AaXaZXHgq2wv/AFGLb/4uu1/4eS/FLdtHgjw8SBlsJPx/5Epo/wCClHxRMXmHwR4eHttn/wDjlT9R8F/+grE/cv8A5WDo8DL/AJe1fuX/AMicdH+wX+0kUKz+B7Y4+7/xOLb/AOLpI/2Cv2lUO4eDbUD+6dXt/wD4uuxH/BSb4stEZh4D8PADswnyf/IlKv8AwUi+Lhj81vA/hwBl3KAlx/8AHKSwPgt0xWJ+5f8Aysf1fgjl/i1fuX/yJyqfsJftGiPL+CLVn/7C1v8A/F0L+w3+0qpYnwJbEEYx/bFt/wDF11K/8FJviyzbT4F8PAj7wKT/APxyh/8AgpL8WowrnwL4eKlsfLHcf/Haby/wY+J4rE/cv/lYex4Ij/y9q/cv/kTlh+w5+0vIY9/gG0XH3ydYtj/7PWh/wxF+0N9mMf8Awhlru9f7Vt//AIutpP8AgpN8VS7B/A/h0DOFG2fJ/wDIlXV/4KJfFA2T3h8G+HhsjLY2z9v+2lNYPwYlLTFYn7l/8rJlh+ButWr9y/8AkTh/A37CH7R2k+I7jVNW8GW0SnPkumr25z+T1qax+w78fLstLF4Rt5ZC+4FtUgH/ALPXQeA/+Ci3xV8V209ze+CPD0YjbagiE/Pp1kNa2oft8/Eq1hD2/gvQ3IOHY+dgf+P1DwPgv/0FYn7l/wDKwlhuBuZXq1fuX/yJyvh/9jP9oCxsXt7rwhboWkzj+1IDn8nqxP8AsdfHtovLj8J25P8AeOpwf/F10+nft5fEW8gSWXwnoa7unyzcj/v5Sz/t3/EqJiB4O0TAGcFZs/8AoyrjgfBi3+9Yn7l/8rM5YfgWUuZ1qv3L/wCROPk/Yx+Pi/6vwhA3GOdUg/8Ai6gP7GP7RSsWi8IW6jbjaNXg/wDi660ft+fE8u0f/CH6BlRlhib/AOOVH/w8D+J+WU+DNBBHTib/AOOVp9S8GtvrOJ+5f/KzH6rwDzfxqv3L/wCROUH7Ff7QxVI38HW+M5b/AImtv/8AF17z+x18G/Hvwg07XrTxzpUdqb2a3a18u4jk3BRIGzsJx94da8zX/goF8TGQk+DNCDDsVm/+OVDe/t/fE+6spbW38LaPBLLEypLHFKWjJGNwzJjI6816+QZl4TcNZpDMcJiK8qkOaylG6d4uL2guj01Wp6WW4ngrJsXHE0atRyjeya01TX8q79zg/jjIg+NvipHG7/ieXPHp+8Nc9b/vG6qn99tn3qq3WqX+qajNqmoX73F1dStJLPMS0kjk5LMTySTzmpbeTy1/fPvVf4tlfjGOxMcbj6uItZTlKSXa7b/U/PcVWWIxM5r7Tb+93Lp+zLgumz5Pvb6W6VPLEyf3P4XqD7QjNveFWRvl3MlRXVw7Rs6Pg/7P3dtcXvfaM/djSJbi73SfIkY/hRv4ttQXEaQ4HzbG/vNSec7M8Lop+T5G/vVHJNMsafI2F/hZaUpS+FBTp83vC/aEnymxTt+Z1amfaEjZv3O7+61OuJIYo1R0Xc3zVXa42/PMm5vvIq/xVjLY76dvtEse+SQzJ8n/AEzZvvVOvkNDs/h/2ap/aIZF3v8AeqZZkbaiD51/8dqDcvQt9nXeNqr/ABrvq5bzSRyb3TerfLtas6FvtDbLqFfm/iq/FJsk+zTbWVvuVO0+YUv7pdguizG2+zK4Xa27f/FWhbSJHMCiMrN/Cq/NurNh7b/lbd93ZVyO481vvsn8Tt1rWMebc4K0pRloaq3CeSqeTlf4l/ipitP+72TbG/g+Xa23/aqKznk3Nvfeuzcn+zTmuIfOSaZNzr8r7XrXl5fhOTm94//Z\n", + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAMEBgUGBgYFBgYGBwkIBgcJBwYGCAsICQoKCgoKBggLDAsKDAkKCgr/2wBDAQICAgICAgUDAwUKBwYHCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgr/wAARCALQBQADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8347F5pkSP5t38P3ttaFjZzR2rzOMjfs+/wDNVi10+5kh877Gqv8AwfP96tOz0+2b99sw0e1drfxV87HY+wjHm94z4bOZ2WZ4dgV9vzN81Tx6a8jHvu+bd/DV+HT51uHd0Up95Pl21bhtfIkH2ncqfN8q/e21NS0dUbU4/ZMf7Oi52OzMu1UVU+an/wBjlW3w7l2t8y/3q3pNPRl2I+1tn/AqZZ280cXk3Nrub+7v+6tefKtLl5onZGm48qMqbQ3k/wBJeb5lb5PMf5l/2aZcaW6tshhyzffZn3ba3biHzI5USFfmX7tQyWc3zTXltuWPb+8jT+LbXJWxVWO534XDxkchrmm/KZt+d3yvurBm0maHLvu2su1G/vV3OsWsMe5xyWTd5bVh3VikkLJ5Pyqu7b/easaNacX7x6nsYyicrJYws3nom1m/vf3qWC3uYW32zr8v95v/AEGtK6s5I9iJuDMu51aq62827502Nt3Jur6zAylKUTlqREj+0wsiI7OzNuRW/wBr+7ViSPy4/wBzud9+1vm+Wq0aurIJtxdf4qtLayeX8nyusu5mb+KvqMPSlKJ58qnvco65uHaNpvlTdt2fJ8y0kjSbER3Vtq7tzJtqbyPtDLDNtx96nTKjR/Ii7t38X3a9D2fKebUkoy5SHyXjnP75l/i/3amSSVm+0v5joqbfv/Ky/wB6i3/fRrv+9911j+6rUsMMuxvJufu/fXZXPKXLE4OaUuaxPBv3b9n+r/hjl3LVqH9zJ/qV2t823/eqtbwpHGkP+qVn+dY/l/4FVuzZLqRI5plV13b12fdX+GvLxHvF04825p2cm1Ucopdvl+V9taVvDcSSK6fd+ZXrN0+GGS637F+V1aXd/d/hq7b75mX51Db9zMr/AC/7Py14WIqSNadHuaVjNLJCsP2pmTfuddvzNU8jO3yQ7X2/e/iaq8IeGNPLRW+bbu2fdq95n2OZXhhV2b5V3V4dap7+h6VOnHqWob792yI6o6orfLVCZJpPnudrBf4v97+KpmuIWmDzTKsrfdXft+7VCS5dpmR5o3/vq392uJSjztQOlx928hzbIZXSFFLs7fMqf6yopmubzY63jIVb7qrU32OGSP8AhRPveXHSyKluy/J975VXf/FWkqnNqLk5fdEntdy/3vl2eZs/76pU3yQyJsYeX8if3lqwsE0iy2zzfuvl/d/7VVr6O6WTf8yfe/d7/u1n71TRSMK0R8d1cxwrvRQv3dzfdWoprp75hNc3cjtHtSLzG+61OaGaS3RJnV1+88bVVkkRlKWtthlf+GspRhKRjH3Y8rKuoXtvHteN8qy7X/vVga9cXisrpcthkVfm/u1pXk00zAu+R/d/utWDq14+5n342/6rav3a78PFRj8JyVqhj6lM/wC8+8f/AB3dXManN82/fjd/CtdBqW+4bM0/Gzc1Yd48Pls/Vm+Xb/FXsUYy5NDxsVLmiYF9avt+07F21QVXmuNmzb/utW9cWbyR56hVqnHp7rMJvJ8xK9CnKMeU82T5hljlWZE3fN9//ZrodI3x7ntn+Rk2srfM1V9N03bGOdu7/wAdrVhs4I5BGiMk0f8ADJ8tEqhrToz+I1NLtUinR9+fLf5F/wDsa7bQZnjwibU2/N+7X5VrjdH/AHKxBE3f367TRZE+x7E2/wB1dv3mqo1PfOj2fuWOu0W4k+ziF5sOzfxfw11ui6uNyu6Mrqu1/Mfb8v8As1wWk3KOuy28xVVvnb+7W/puqQxsU3/eiVmj+9XZGpzmMoyj8R3Wn6kQN8Myh1f/AEfb93/eatXT9am8ve+1vvbmrgrHWd0iXOcFfl3L/F/wGtCHxB5K+d8wSR9qKq/M3/Aa6OYw9+J2q69C3zpZttX5Ub+9/vUybV4IYd+//WbtzL/CtcqutbYf3fmHc+1/mqvcawk3ybJCu/b9/wC9U/DAfunT/wBtusCv0/2d/wDDWbqGuosbO8jEt91tvystYN9q226ldH2xtt8qNX3f8B3VVvtUm2l3TLsnzLu/i/hqJRjI25vslPxRNDdZm85iv3fLb+GuMvJ3dXR/uK23/erW1PVHuomQXLFpJfkZvur/ALNZGqQ/aFb5G+V/3sa1x1I8x0UeaOjOa1SG2ml85Pv/AMO5vlWqtvbupYOmPLf5d3yturcbTkjdt6Mxb/lm38NQXWnpJcM8iSO38Un8K1nKn7p2RqQ5tTPWFJpD5czIn97726mTWVzIHfez+Z/yz/vVZa1eSTZDCqqqNu+fbSLYwzRuXhxufd9/71cNSnI0lUM2SN1CwpMuyT5tv/stJbxurI/nL+8ba0cn92tXybaOSHyYfuxbtrN8v3qq3Eltu+0+T86tt+VK5q1P3tCoVOXWRbtWdcoltv2tu2t8u6uj01na3TZuAVt27+61YNu7s0jzbWlb5U/hrQ0+aGObzo3bzl+X7/y7q+Ox1GXNKTPewtT4ZI7LT2T/AFM03mt8q7v4a0WuvLUI+6H5v9Wvzbv+BVzVnfTeSH/55q25d/3m/wBmp/7UdpI+Nqt8rbWr5DEYeUqp9DRrfDzG5cXySsN9zuVot6qybvu1m3mpRrD5iO0KSRbvlf5aqSal8zbNuPm2/J8q1Uk1QSM73KKrrF8nlr8u6tKOHUZe8dvtOhPeahD5yc7v3X975t1Zs0zrsfo2/wCZW/h/4FS3F4jKkEyMXX5X3fdaqzLBNJscrsZNqqv8NexhcPGPuozqVOWHKJe+c0hf7Tv3fL8tVri3DSPD9pUyr/F91d1aEljH/wAvMylG+4yp91aktdPeRc+Tv+f5fk3V9XluH5dTwcdiIx+0YLK6tvfcKry6bN5ezZ+7b/lpG+35q7BfDiNa+XNC37xtq7m27qdY+DXuN0m/hX/1f8NfY4ej7lz5XGYjm+E5C10e/Ece+2+fdtXb81XF8P7bqPztwkVGV9vyrt/2a7ux8KzRyJCkLM6/Nt3/ACtU7eDXkmj811Ty2+f91ub5q1lTjGZwRrcp5wuihpJIPmZGf/v2tQDwrMzHyXbZ93aqV6ovg/y5FT7zL99VT7y0kngvM3nfZmQbWZFWuKpR5vdN6dbl+0eUyeG7mO4Dp0Zf/Hqfp+jzQtLNczZK/wAP92vS28HmaOL/AEXa21n/AOA1m3HhWaxmm32fySIv+1uX/drxsVR+yejh63N7xysmnwxqrwp5rtztV/4f/iqJLRLVVT7HIo2bd27+Kuqj8Nos29BiKRdySN/d/u1UvrN/MhhmtmH/AE0rzJRl9hnbGpLm1Obmt5LfPkoxdvmdqpGzTzks33MrRbvL37WrevtPmkuNk3zLI27958tZd1bJZ3mz94Xk/vN8taxl9kr4vhM9YUt2SFJtq/8AXX5vlqb7PNdTPNM6r5iLsVf4f9qnzW8KM72yKpX+KrDWf7vYJtoXb95vmrS8fi5iPe5iCGSZrdYfObYvy7v7zLUNxcFVaNHaM/Mu3/ZqzInkxhGm+79xf7tZN1I7L9/HzfPu/irejTlUkYyqcseWRDM0Plu8kzfc+6v8VZ0cszN87qPm+fy/m2rVm6Z7iTyfl2xpt8yNdu6qk0nlqXh2hG+4y161GmeZWqSjL3SNpEZfJjhXb/D/ALVIq/ut83zf3fmpkbIrDftC7P4fvbqVVTCPHBtH8MbN/FXV7P7RjGt7xGq3O48Z2/N8vy7qfIszRq6Pj+9u+9VhbXbJs3/MqfP8u75qVbVMt5j/ADfe2rTfvfEbxqe5ykSXj/Y3DzSBv4Kt2zIsa70y+/dtb/0KmW8aW6tcvM21fl3bPutWlHYO1vvmhYf3JF/irel8ISrT5CssYM/7l2Rm/vfLUNxpsysNm4fLtfd92tVdI+UveTYdk6BqU2VuGyIww44f2r7rh3gvirimhOtlOFlWjB2bjaydr21a6HhY/Ocuy+ajiKii3qrnPyaS+1jvZn3fL833ayL6xeS6mTYw2/LtrtZdNtpNrCPkdcniqV14dMmPJmUfLhsjrX0y8IvEj/oW1P8AyX/5I8SpxFkcv+Xy/H/I871TSXW13uzb1+ZGWua1TTS3+395a9auvA09wGVbiMBvvcnr+VZN18KL+XckN3bKh7Et/hTj4R+JH2stn/5L/wDJHFUz3KJf8vl+P+R4jqlrc28jI6fKv8VUvJmkH8TbvmdVr2LUPgLrl1F5cGpWKnGOd/8A8TWS/wCzR4qYbRrmngeoaTP/AKDVS8I/Ee1/7Nn/AOS//JGX9uZTa3tV+P8AkeaRw+Wd+9v92rlrbTSXGx5mZW/vV6HH+zZ4mUgvrdgcd90n/wATV22+AHiGL55NR04tjGRv/wDia5KvhF4mSjpllT/yX/5I6I57ky/5fL8f8jhrez8llf8A8dVq07W3eZVR/lZvufNtrs4PgjrkTqf7UswB2Uv1/wC+auRfCDVIwxGoWuT0OG4/SuWXg94mv/mV1P8AyX/5I6ocQZH1rr8f8jkY4ZI22I+6tC1idv3zuy7v4d33a6WP4WamW/f38BAXCkFufrxUsHw21OLBN5b5AIUgtwD+Fc8vBzxQ+zldT74//JHVT4hyCP8AzER/H/IwFhfa02G/2t1HmbpEfeyj5dnmV1H/AAgN6sZ8u7hDFTyScbj36Uh8AX7hRJeQHaMdD/hWS8GfFFy1yyp/5L/8kdq4n4eW2Ij+P+RgwrczSEQ7W2/wyVDIsyrsEO3an3v4lavUvgz+yX8cv2i/G0Xw4+BHw91PxTrbxGX+z9FtZJnjiDKhlkIXEcYZ0BkchRuGSM1758Uf+CB//BUf4VeEB4z8Qfsz3d7ZIoaeDw7qdtqdzGP9qC1kkkPuVUgYOcV42Y8C8U5PjIYTHUI0qs/hhOrSjJ+kZTTf3Hdh88yivF1KdW8Vu0pNfgj4qmjhb5PmLL8yM33t396mzSTRsr7Fd1Tb9+ulm+GOoYbyb+JSzZIJbj9Kbb/CbX728S3sZoZJp3CRwxB2ZmJwFUBckk9q95eDvihy65XU++H/AMkc74q4ev8A7zH8f8jmmmdiEafYq/wrU9vMjYT7r/xfNX3BoX/Bt1/wVi8R6HZeILb4EaZaJe2iTR2+oeKrCCeJXUMBJG8waN8HlGAZTwQCCKur/wAG1H/BWuEmcfBPQndRkAeN9Oy3tzMBXxjyqtFuMqtFNf8AT+h/8sPUWbYNu93/AOAy/wAj4hh1CazmKO6uzJj+98taVvqD+WHd2LfeWuwH7Gf7SMHxun/Z6T4cavceO7fUZLGTwla6ZNNfefGCzoIkUs2FUvuGRsG7O3mvpvSP+DdH/grNqGgrra/AGyiWWHzorO58X6dHOvGQpQz5Vv8AZOD64r3cw4O4gyFU55jTjR9orw56tKPMns43mrrzWhw089y7EyfsqnNbe0ZO3rofGsmpJD/qXVWZtzNUDas8yt5z5O/5ljeu4+NP7KX7QH7PPjZ/hr8dPAl/4V1uCISGw1mxkhkkhLMokjLLiSIsjASISp2nBOK8u1WRtN1CW0edJJInKMF6KRRnHB3EOQ4Gljsfh3ClV+CV4yjLS+ji2npqZ0c5wGNqyp0Zpyjutbr7yzqGoJMrbPlXb/E9ULjWCtsE6j+9WfNep5g42/8AA6q3WqJl03/Ls+balfPxjy7hWxUuhak1B2jVwjMGrNutSdpDngbNy7v4mqvJefKZoX2/L8rVl3WsBY2+fLf3acjnjW5dC3dX027eJlRWX59r1nzXSSN87sB/A1U7jUriTqi7f7tVWvNvzof++a56nNE9CjiveNCS+eF98aMwX+Kh77cyzvN96s0zP5nzzcf3aljuEab9z/DXFWifS4XEc3KlI0HuPNGxH+ZvvbqktZ3jbY75C/das/zkkkZ0+8yfIrVatbe5kmRP7v8AFXHUjyxPfw+I5S/G7yHZM2//AHv4ateSjR/I+NtUoflben975quRqixsyOzM38P92uWUeU96jiOYeq+Tt2J/v7v4qkkkm85N/wDwHdUTRuI9kz7t33amVXjiCTP91vm3VhKJ3xrR2BfmZ4H6K/8A49UrzP5Imd8u393+GoNrx8oeGahm2q3dt21KUuY2+tFtW24CTfL/AOzVGJk/jT5o3qFpJ2jZPOyy/NtX71NaRFz8ir/Czf3qcaPMH1rm0JJ7h1Vnd1dW/wDHag8x5B5iv/F92k2u7ND8v/xVV2byZN6JtK/K3z1v7PliclXGcurLM0yLh0h3fwtTFk2q2x2D/wB3fVJrpFY+Vu/21qP7chXncm7+Jq3jGR52IxkbFybUJvlfyVVm+Zqq3E3mKd83FRtMm5tnzL/BVRr5/M2bFUN99a6qcZHz+KxXNAtrP50bIHYK38NNjkDN5EzqrfNVKOYwJvR12K1SrdPcNvR/mX/x6uuMT5vFVoyNG3kdWV3mxWhbuiqr+d8v8f8AtVj6efMZ0f8Av7fv1q2UcMi42ZVf4auPvfEeTKsadnI7f3lVtvzLWtp6vcSNvfd/C+5vvLWdpsMfmb4YeG2/NJW1pdn/ABzRrhfu7aInmyqcxr2VnNJE3zqEk/hX71dPpdrtjjf95Ky1l6HYv8joinau35v4a6Tw7ZpbrsuYV2xr83z/AHaoxlI39Ls0VU3pjcm5F/u1r2Vo8i7HhyzNu3R0zQ7OTy40httu5Ny/7VdJY2KMuyHdvVW37kro+I5/aGJNYpNC28tjavy/3WqZ7GFo1h37fl3OrfwtWtHo8022GaHbu/i/hqKbT3WRnfcn8Hyv822ly/aOmjL3zFis5mkFz8zlvl3b/u7aelj/AKQZpptgk27/AO9tq+tmkLeTbeZ+8/hk+8tRXVjthXy3yVT7rLUyjHl5j3sLL3TP1CztpGWZEZ1+0bUZv4f9qub1rT5lkbZN/F95WrsLiOH+NJNv8DL/AHq5jVIvsuX2L8zN8qtu+anGMJe8e9ho/CpHnuvWLzQvNC/nIzfIzf8AoNcT4k099zJvY7vl+X71eoeIIdyt8jL8/wC6b+7XGa5Z+dG6JG3y/MjVyVpfzHqxwvN7x7Vp8NtCrvMm8eb95fvK1S28T3DOnkx+Urs0TL8rK1VoLiBWY2bqUjb7zL95v/iant77/SPJ+zM+1V3V40Y8sD572nKX7G1eNv8ASUV/l3J/FWjC0MinyX/g2orL8y/8CrPjuPJbY8n7pn3LGqfd/wCBVehbtcvhFXcjf7VefXk/5TupVOaVxLqOFZCj7WPlKrrG3zfN/FUUdq8ciu7sGWp7iRPtDpIil9m/5U+WRqY1siq58lX/AI/lb5VriqVJR3PQpx5vhG2qwzNNvhkbdLt8lv8A0Kh7Xa4he58pG/1qs33aSOPd++dNyKjM6r8u2pooYJIzvhkd/vr8v+zXn1KnLM9CjH3OYwpLNLyabyXX5X2xSN96s64t5Jrg3OzJVdu75fvV0V9DMqm5SaFdsq/LsrMmt4Y1dPJX5qqjze1Ojmic1eK8MjO6rj+Btn3ayPJS4k2PNJth+589dVqVr+73pu+78ysv8NYNxpqfK/lqny/J/eavsMt5oy1ManL9korbpPufzt3luyP/AA7qswxvZwh9jbd/3lXdUUyvNGU3/Ou1fl/vf7VSRqkfkwIm3/vpt1fXUZHj4qpGMWSWs3mN8+5f7rMv3qjnZ7qF0R9u5/vfdqxIr7o3G7+9taq7MIV2O67t/wA6/wB2ur2h89UrS5xUtX2r8+W/gXfUkMz7S/8AD/s1EXePCbMKyfJt/iWo42mnm855tu35UWsqkiIyl8JfhZ5Ji6Xivt+62zb/AMBq3DJBDD/pPVt2+P8AvbayYVhb+87K/wA3zVqQtN8ifLu+99/btWvHxko83xHdRjL4jZtV2skyJvSTa37v733f4q0re3s5o3d0807flZflrEhZLRnfZu3LtUx1t294tvCj7FRVTZtX5q+exFT3uY9CjT/mLsLSTRtvLM6xfvW2bV/4DTobjbu+zO2GTbtb+H/eqq106r5KPuf+GNv7tRXGoOGd7mFV3Mv+r+VVrwMRKSPSp04/aLn9o7v9Gfy9q/db/ZpFWzuGW5mhZ/L+X92nzbahgkRZJUlmhk/i/eL91f7tEMjxSCGEN5W75v4W/wDsqxp/uzOp7xds7dLqNNjssX8Lfdap4/JkWVH27Y2/i+ZqS3VOPtJjQffRZKkkjmWFf9Gydu5mZt235vu1VSpfoZRUvdIzHNGDCk0K7v4t/wB1ajaO5kka5m+ZG/h3bq0Lf7THhJoY0Xb8iqv3qrzWsyyMkNzlm+6rbV21NPTZ3JqfCZ8kaXExhTdlot27+Ff9mq1001uvzptlZNu1VrVWF2UPsZCz/NHt+9/tUTWdmqCHY25vlT+9SlU5ZHNLmjE5fUrFIVMibnb+JVasLUrcLai2mTLyfxL95q7DUrOG4izDeMS3yuuz+7WDq1r5EjPN8rKqr5ir95a9LD80+Vv4TyaznLmOMvoUjTydjfL8vzNWZDYw3GfkUOrbV/2q6TUIYZjJC+1d3z+X/DVGa1hnmVIdqKr/ADrXrwlJwkeVUjIxfsDzXBdNyfw+W1Ot9Lkz8+7Zt3L/ALNdF5flyb0ttwZqdHYo0beTMqf7Mifdpus4xt0EqcYy5jFh0tI4fMSHe275d3y0s0aQzeTMMmRPm+f5q19Qtdsmz5t3ysvl/wAS1SvLbyZt8yfeT5Gqoy97yOqNMdp9xD5iQbF837vyv91a6DTbhoY/4cbt25f7tYNnbv5bO8MbN95GVq2NPvJPs6zTJlt/3lojLml7pry/zHTaXfTLuT725NyM33ttasd0kluj75C6puSSN9u6ubsofIuPtMKN9z52V61Vmga3/fQbg277z7f4f4a7qdT+Y46kO5sWOuPDIqJHhG2qzMv8X+zVxfEEMLLD9p37X+b5q5r7YmYrbfNvWL7rfd/3qinmdpC7uw2/N8tdkahxy906tfFCSSMU3Ax/Lu2/L81Jb60l18m9WZXb95G3y1zEeqIsaiZNrSfM0b/w1Nb6lDHGpKfxfe3fLtrfm9wiMoROjbVE2hH6L/D/AHqoz7PMKQw5SZ/nXdu21m2t1DN8m9ju+5H/AA1ZjDyK0ltuVW/utUVPhJ5uaYya4mkU/aU2eS2xP9pf4amhteDJ5K5/hjX7tXYbN5oVd5FZmT7zVb+yr8hdNjfKi/7396sPZ8xtHETiYt1pbxv5j2yt/Cm6sy40e5WFnSHD7vvSGu2k00XVwJktv4fkk/h+Wq0mgzNMftKMyb921Xqox5fdKjiPfOMk0dFt5HRMBfml+X+Kqf2G5+QTPHub5v3ddVeabcr5ttDDyrbn3fLuX+7VS40f7PbnfCu/Z8nlrWEqZvHEcsjmriGGO3i+T+PcjLVO4s0+V3Rm3Nu/3q6GawhjVtkPK/Nu/u1m6hGkczRpMyeZ827Z96uKpTLjWKEN46yN977235v4auWOwyfuXUKv8Mj1ntHNHIyOi/N8qqzVLb2flqU2MZW+433lr57MML3PZw+K5dTfsrp1lXeillfd/wABqaW8hjl/fceZP8q/7NU9JhRcq7s235fmetGGxmaT92nC7WRpPvV8XUwf73U+jw+K5oXkI1uiyfO/lBt2z56rzTbt2+2ydm1N3/oTVqLavN+5Fnv8tN/zfd3Uq6RPfLFsslaTZ8+75V/76qKODnGrzyPUjW9wyoIzcTJD8y7v733a0I9L2t50KLt3L8396tTT9B8yRn+WVt/8L/L/ALtaNroMMMgh+xshjl2/e+7Xv4PC+1ldROPEYyFPcx49LTbL53z7vvL/AHa07Hw3eXEccM1huMO19yp/49XQWfhdGkXZDt/e/eb+Kt/T/C8MMfz7lZX+Ta3/AI7X1uBw7jGK5T5jHYpVOZnNWHh/z497wqV3bYmb5lWr9v4Vmb50+dFb70f3a6nT9LSOGGNEaKXfu3L8y/L/AHqvWeg7l+eZYl+Y7f8Aa3V9Jh4+6fPVKnLoc7Z+HfM+dLBtv/PT+81X7Pw3NKrw/ZvKMb10+l+GUYyQi32bWbyvLb5f+BVp2Ph2G1hRH3Ku7ev/ANlXTKmckq0pS0OQk8LwrCn2ZGZY5d0v7qm3Gg20P+mQo3lfw/J/FXeR6PNdKvkoq/P+9Zf4l/hpt54ZmWR0+V4vu/3dq1w1KIe0PMbjwvNIrfJgL825f4l/2qzLrw+9rJvfzJH2fIzf3a9R1TRYY1KJC2yNP+WP3W/3q5rUtJEjCHf88n3FkX5V/wB6vMrUeY78LWOEvNHmdxMlsyL/AALJt+ZqxNS0fyZGe58zcybdrfL5bV3Osx+XdPDvX5fuTfwVzd5bvNcI7zbYWZm3TPu3Nt/vV4MsLKLke/RxUTjrzT7lpA7wq3lptdl+bbXP61C9vveGFnT5WSXbXZ67DuuAmxl3fNuV/wCGsHWIXZfk+ZV+5WLh1OpS7mAsqQs8w67Nu1v4v92pZP8ASLg/Iu3bu3NT7izeGZ2CRsG/ib+FqjmkeSPfHtHmJt2t/DWtOnBy9wy9p7tnIz7m6ha3/c2zbWdvm/8AZqybvfN9yFh8vy1e1Bnj2orsVZN277rKtVLgO/3GUv8Aw/J96vTw9OB5eIl71zPjmtpI96bg6ru3f3qpyzeYux/kVf8Ax6reobGVnRGQL9/bVFpvLjCCFZg33Nr/ADLXfGPL7xySqc3ulmO3eZVP3yqbtu3atEMgbajp5b/3lqPYm4yI/wC6/uq3zVPDdfvPO8tvmfbtX5t1XH3jL0LNvGjMweGNl2/Ky/8ALT/eq/DYvJG37n5ZPv1Baw7WLomxv7tbNjb+bCiP8u7+Fv4qtylGJcZS+IqWenwQ/f2urP8ANHWjZ6fHvVPO37v+Wa/dq3DY20iokwXMn8W2tCw02GJhDCjMsa/e/wBr+9Vl+05o+6UNQsFFhI+QCgO1V9MV9Vfssf8ABDP9tz9rX4V+E/jd4AHhKx8L+LZrkW+oarr+Hs4IWKefLFGjtteRXjVU3OGQ71jUhj846hpkqaHdO0eSLZyT/d4Nfpx8ZvjR8Uvhd/wbV/CjU/hv42vtButa1ldG1G70eX7NLLYm71IvDvjwyh/IQOQQXG4MSHbP9GeFXEHE2ScJww+RzpwrYvH06HNUi5qKnRm+ZRTV2nFNa2drPRs/PuKMPg8TmPPiE3GFJysna9pLT8T5h/bI/wCCEH7bX7Hfw0uvjHqK+HvGXhvSrV7nX73wlfSPJpcSkAyywzxxO8fOS0Yfaqsz7VG6vk74TfCb4i/HX4kaP8IvhJ4Tudc8R6/eLa6TpdptDzyEE9WIVFCgszsQqqrMxABI/Q3/AINwf2pfjtF+2Fc/s5X/AIw1bWfBviPw7e3l7pWoXjzwWFzAqut1GHb92W/1TbR8/mJuB2KV+lv+CMvwI+C/wL/bI/a28YaRr8UieC/FUmj2Ijt4GFjpZnubiQqIWd+DCqFQqj9wBgtlI/2TNPFHingHC5tgc8VPFYnC0qVWjUpxlBVY1qnsoqpBOXK4TevLL3o6Kz95/KUcnweZzoVMPeEJtxkm07cqvo9L3Xloz5Q/4hl/29/+Fe/8JX/wmnw+/tj7B9o/4Rb+2bj7R5mM/Z/O8jyPM/hz5nl7v49vzV8Yv+yT+0DZftM237H+v/D6fSfiDda/Do6aHq08cGLmVlEf71m8sxsGVlkVijqyspYMM/rBpvxI/wCCLum/tFRftU/8PVvivceNItWF+dQudbvGjkO7mBov7M2fZyv7vyABH5fyABeK8r/af/ar/ZT/AGvf+C4v7PnxA/Zv199WtLDXNEsNb8QW+lywpfXSXzPEFExRnVQ6oXKKQM4MgCgcHCniR4kTxmIp5lhp1KSw9Wr7SeDq4eNKrCPMoXlJqpTeyek2+yNcblOUqnB0ZpS54xspqfMm7X02f4HmngX/AINqP+Cg/ibxNrWieKtW8C+HLPSrgRWOsXuvSTwauP8AnrbrBE8qp/13SJuR8vXHlvgD/gip+218Uv2j/GP7OfgPS/DOoS+A9Sis/EviyHxFGdJtnlVnjHmAGVnKqd0IjMsZwJETIr3P/g45/a6+Mesftk/8M1aH471bTPCnhDQ7GZ9Isbx4Ibu/uIvPa5kCN+9ZY5I0Xd9zD7QN7FqX/BHb/gph+zf8FfgN44/Yn/a51vW/DGg+Nb6e4sfHXhtJI57Rri28qcTzW379HHlRGKULJgsyvtRRXXguI/Gep4ex4nUqVepXp05QoU6Em6cJON6q/ec1WXJeXslZXlo7R5XnUwmQLNPqfvRUW05OS1a+ztZK+l/87md8V/8Ag2n/AG/PAPhWTxF4K8QeB/GlzFkvo2iaxLBcuPVDdwxRt34Lg+gJ4r4b+GvwX+Knxf8Aivp3wN+HPga/1PxbqupGwstCSMRzNcAncjeYVEezaxdnKqgVixAUkfsd+yv+xP4X8DeOrv44f8Ehv+Cn+meMdftLF2uPh98QNU/tCw1G3YhSt4LR4p4lUuCsnk5D7Rldxrj/APghr/wm1v4//aw/ax+Keh28vxW0RZ4tT0OPT7a3Md5uu7m5QRxFdm+4t0QgBVJT7zHO3hy3xd4hy3h/NcXiq9LGSw0aXIpUamFrKrVn7NRq0pXXs02pc8ZJNJxvd+7pVyPC1cVRhCLpqblf3lOLUVe8ZLr5Nf8AB8PP/Bst+3sPh7/wlf8Awmvw9/tj+z/tH/CLDWbj7R5m3P2bzvs/keZ/Dnf5e7+Pb81fCXxI+C3xQ+EPxZ1H4GfEzwhPo3irStTFhf6TeyIrRTkjaN+7YUYMrLIGKMrBgxUg12H/AA3T+1z/AML9/wCGnP8Ahf3ib/hM/wC0/t39q/2tLjdnPk+Xu2eRt/d+Rjy/L+Tbt4r9Fv8Ag4H0rRvE8v7Mf7T+taTb2nibxDYRw6vokyIN0Q+yXQjfa/mFY5J5U4LAeZ95Tjd9lg+IeP8AhXinA5XxFXo4mGOjV5JU6bpulVpQ9o4W5nz02tFJ8sr6u2z4KmFyzG4OpWwsZQdNxum78ybtfyfkeHeEf+Dbb/gotr3jX/hGfEUfgrQ9OGlw3beIrvxH51sZXUE2gSGNpjMhJVj5YiypKyONpbyf9vf/AIJCftZf8E+NBtPHnxPt9F13wpeXMdqvibwzetLBBcuHKwyxypHLGSEbDbDGeBv3HbX2r/wc1ftWfHbwT8QvBX7NHgf4gX+i+FdT8LnWdatNKuGgfUpzdSxIk7oQzxIIQyx52lmLMGKoV5/4I+KNV+Kf/BtD8UV+I8z603hjxXJb6LJqM8kj2wF7p0yFWLZBV7mUgZxg4IIJB+L4f498UJ5HlHE2Z1qEsNjK9Kg6EKTUlGpN01U9o5/HdX5bONn8l6GJyzJ1ia+Doxkp04uXM3pdK9rW289z8pKKKK/qA+PP1m/YC8T6Z/wTl/4Ik+Nv28PBfhy3j+I/jrVn03Q9XvgJSqC5+yWwRGG0JEwubjZgiRkG8lQoXwj/AIJ8/wDBZj9tfwl+2F4R/wCF1/tA654s8J+JfEVvp3iXSdfuFlhjhuZfL8+HK/uGiaQSAR7VITaRtOK9o+Kd8fi7/wAGx3hG+8Mvdv8A8IR4phi1pDc7iuzUriHDfLyn+lwsq8bQU5O3n82/2cfCGr/ED9oTwL4G0HzvtuseMNNs7U277ZBJJdRoCpwcEE5zg4xX868K8NcPcVYDibGZ3h4VK08XiaUpTSlKnTpRUacYyd3FQjaUXFq101srfU4zF4rB1cHTw8moqEGktE23d3XW70Z9Nf8ABeb9nHwd+zl/wUN1+1+H3hoaTo/i7S7bxFDZxNmFZ7hpFuTGMfIrTxSNsGQpYhcLhV+MgSDkGv0j/wCDnbx7pPiL9tzwv4KsJJWuPDvgCBb7M2UV57meVQFx8rbNpJycgrwMc/m5X6L4R43HZj4aZViMZd1HRjdt3bS0jJt6tyik/meXnlOnSzetGG3M/wCvvPa9A/4KQft9+FtDs/DXh79sb4jWlhp9slvZWkPiy6CQRIAqIo38KoAAHYAAdK/TD/gnT+0/+0n8Af8Agm38S/8AgpH+138efFnir7bE2n/DXQ/E+uz3EM0qOYUkWNn6y3TbN2MrHbuw4Jz+UX7Ln7Pvi/8Aap/aD8J/s++BomOoeKNYitPOCbhbQ/emuGH92OJXkPshr7m/4OA/2gvCHhbWPAn/AATW+BsgtvCHwl0a2bVbWF8h78wBII3P8TRW53E92umzytfF+InD+Q59n2A4SweEpRniJe3xE404KUcNSknL3krp1qlqaaf8yeh35VicThsNVx1SbaiuWKbdnN//ACK1+4b/AMG6nxU8H+If+CkHibxL8aNZS98aeL/DOoS6FqmpZaW51CS4juLra5biV4lmb7pJVXAK8hvRvjN+z9/wckXP7Smst4Q+JXiu50641+ebSNU0fxpZWuj/AGYSnymFu0wEabAv7p493UEMSc+c/wDBvf8As3fA3xDrvxK/bY+OWlR6tb/BjTIdQ0fTSjuba48q4uGvfL4SR0jtmEasWAdi2AyxsMfxl/wcoft/ap8W5PGngu18IaV4ZjumNn4On0IXELwbjsWecsJ3k243NG8akjIVRxXyHEOVcRZt4q5nLhfB4bEexoUaVZYyF6cJ8rlCFCzvrBpyVlG+72O7C1sLQyaisZUnHmlJx9m9Wr2bl89up6l/wcya74Wi0z4H+APGeq6bqXxU03w/cTeKL/TrfYGt3SFN+Nw2RyXMc7RoVJAV8FeQ/wCHnjnUvJ8TalFjObp1z6c1+3P/AAWk8BfA39rH9hn4Z/8ABWf4deEo/DfibxZc2umeJ7Uu5N/mOaPY2BseSCW1kRZSEMkWNxO2NR+F/wAQruVfGWpoTwuoSYX/AIFX5hxMqNLwVynBrmVShia9OrGSS5Kqc3UhFJtcsZO0bP4bXs7pe9l0pLiKvU0tKEWmusdLP1dtSrJeItvseRi6/wAVVJtQnVv4dmz5f96qc15MzP8APuT+CqF1M8ka4evxTlPelWLk2rfu22Ox/wCBVm3GoPJG29M7fustJNI67kXkMvzfw1WaaP8A2h5a/wAVZy3LjLmBpHjk/iWkaR1c7H+9/CtQzHbtL7iVT+H7tRmbKhwjbqwlsdVP3ZEzTTIzOXUf7WypYZHLK6feqsu95Aj8/wC7U8K7su/yn+DbXHUPYwtaUTRhjdh88OxV+7WjYt5apDsy27d5i1Ss/lhCYY/NWxaxouH/AIv4645R/mPp8LiOblLUMKeXvh/i+/ViO22qZk3FFT7tJao8kYeTd9//AHav2Nr0njm+X+7XFL3ZXPdo4gqwxt9+b5flzuqRLfa33Gf5/vNWi9ijRq7+W39//ZpP7PhXdMTuXZu+/WPNzHbTrTj8RnyWr7iHh3bvm+Wq80SKvyJg/wB2tOa3+Vcp8sfzVXmtZvtDTb9vybaJRLlXKbSDc0zvs/2V+9UTNsbeX5WWn3CpJNsm42r/AN9VUuCIUbyZPmX5vm+7WkYy5jCpjoxFmvArPbIjB2/iaqdxPCJglyjHb8u7fUM0z+cjwvlv4qh+0Ou7f1Xd/wACrq9nze8ebUzDoPuLh1mUT/Iv3d1V7qR1y/nVHcXnnL5Lo1QNeiOFtj5O75N1dFOPKefWx3NIlmvPKhXem1d1V5L7dIzvt/2fnqpdah5x/vBvvK1Vriby2+5uVv4q640fdPFxWO+yjS+1Fzs7LU9lNvx/db+7WTHN8zIjt833WrT01fMb7+1v4a3+E8KtiPafCbllG+7enC1s6XC63CJI+4MtYunJM23j5f7tdLplu7SJ867Vb/gVPlgc3MbGlwuYx8ivtf8A8drZsYYW2ns3y/N8u2qOmxpCxd0wrfxV0ml2sKqrvD/uVl8M7nPKXNGxf0H9zMkcP3Nn3mrr9BhtmXeltvl/56bty/8AfNc9pNqi3G+ZF+X7n+zXW6FH5cn3Mvs3NtStDE6nw/p95cMUebcrRKy7V27dtdJpcKSMsjorIy7pfn21zuizIibHeZZmZfKXd8u1l+7/ALNdHYTQxsvnRr935Nqfdaqj7vwhy8oDZbx/wjb8yQrVS8h864Oza391mq9JdTeWs0ky723b1ZKpx3KblubN2ZWb5JGT5av3JGlOpyleSGO3ZU3/AHl/1jVTuN7N5OzKKu7zP4Wq39pL/wCjJDj/AGm+bdVORlkmKSnbGvzbvu/NWMpfZie5gZTlKJn3v79fJSHL/wDPTd92sTVLdJtiQuoHzfdStu8hSONJtnzb9u2srVWmjXybZPlbds/irKPtI7H2ODp80dTkNWWGNmmT5XX+H+GuQ1hdsxLpn733f4a7LVrN93751X+8qr/DXM+ILUKreSF2M/ztXLUl/Me7Rpylqdvb6gkkP7l/mjXckbVetdQE0xkRGQfL91642PUI40VPO2j7rtHWjZ6pbQ7Uabjfu+992vOjzxPgJSgdxDNujL7+Nu1qfbXSR7uGVmf5m/h21zcOsfufm43fdZfvNtq22qQyW7+T+8Zk+6r15tZ1Vojpp1KcZG/DqFtHueF2SWT5UZV+X/vqmRzzW9uux1O35dzP96sa3vHEbQbF2q+75quRXTyRlJkXYyf+Pfw15NdyVTlUj18HV543kbMOyaNZrlMMr7drfdan3V4LeFhcuvzLtVd23bWbHdIYVR2+eP5k/ur/AA1Ja3kF9Y7/AN3L5j7kX+7trjqSjzns05c0B11J5kaybN7R/wB5P4aivLWG3ZfO+83zJt+arMn+kMsPys+zbuX5d3+9SSLbeXv3qFb77f3a6qGsx1PhMTVJrny3S2ddy/MitF93/ZWsa8heTLv8xj2ru2bVVq6HUGha3ZP4F++q/K1YmoXSKF+dt+3/AHvlr7DLvgOKpL3eYzZF+0TPa2yZb+H5Pmanww+Yqo82G2fKypu+ao2i+Z3SZvl+5tq7DshYec7I/wDdVK+lp/AeBiq04/EV1t3W3EzupK/+g1T1DYq+c83nBk+6q/NurUkXylTyYdi7W+bf97/erM1KOTzGhkddq/fVfvLXVznjS/eTKU0yRqiOjK23bu30xmRZHh85W3Ju3NTm2Qwsm+NV3/Kzfw/7NUJIJtu9Eb7tYVqnLA66VHl91FqzmEkgR3+Vm27Vras1SNv3j7hs+da5+GN1WJH/AL9a1rIizBHRkX+83zfLXzuMqL4onqYem/8At03dPby1TfccL/yz21pwyP5n+uVdv8TN93/drHt5h5KnzlVt38X92rX2jY3zzZSTn/a2/wCzXgYipzHtUadKMbGg376Nkd1+9/vNT5r6aSZ4USNU+Vv3nzfLtrK84fYx5MzI/m7VZl/h/wB2tBbx1tyiOruyKu6SvO5vdOj2fuly3k3KIfldvur8lWLa4WaRXuXz5kWxf7y7ao26pJcfc27X+Xb8rbtv3q0YbX94873PyfKrsv3afxHHKM4+8aWmxu1usG9Tt+b5qsbZo7kSI7Lub7q/xbqr2/kxL5Pkqj7lbcz/APstWVtX8z9zI29kb5aJSl8jGMPaTlcfFb+Wzw79219u6RtzK1CrBJGs002W+98qfK1TKUlVXmTZ8q7lX+Ko2t7xWZ3s1Rvv/M/3qzlCMdh2ly8pA1zDNavcvCyqqbvl+9Vn7LCyn9zIH2fd/ip0ckx3o6Y+VflVPmamXCXNvIk2zbu2/vFfc1aRjzy5TlrR93UxNQks9Lh3ojZZPn3Ju2tXPagPtkjf6M25f4m+6y10uvxvcXBvIdrqr7X+eua1COGPdCvyvs+61enh6fNHSJ4WIlzS90wZI0aZ/LT7v3G2VXms/wB800O1/wC/H/F/vVrXWyTLo8f3PmZVqkqvCz/P833cfxLXqcv2Tz6kiDy5pPkh/v7ZfMSpvLE1qHeFnTd/CtPWN2x5Y3Mv3/8AaqzaxfaJ/JmvGAX+7823/gNHs/dLoy5oFTyxt/fQqd3ysrfLt/3artYpHG29Gfc3+9urakVJmDwpvVW27W/iaq8dj+9LyWyofvPJG9RL3Trj8RR0+z+8hh52/Irfw1dgj8qN0ljXDNRbzJ9zOP8AaX/e+7UazPbt5PzP5bbvm/u1hGUo/CdX2UmWW85t0yfMi/f2/LVnT7qG3j2I+FX/AJZyfw1mwyTXMjO6Zdm+T5/l/wC+arzXvkt5082F+781ddGpI5Kkf5TbkvoY1Dpc/wCsX5lZfm/76pft0LIPkjO1/n3Pt+Wse3vE8lU8xin+zST3sccm9Hx/fVq7Iy948yt7pr3s8M9wiBF+7/C//oVWPO+z7Ye38DKu6sdbqFld0+SRW+7s+7/u1N9p+0LE0Nyqv/tV005c3xHFL3ZGz9qXcmx921PnbZ93/Zrb0WLbLvSZcSL8qtF8zf3q56xV5lSGabYkj/5auw8P6b5zeSiKvzqzNJXRy+0J5zR0/Snutu/rv+SNk+Vf96t2Hw7uZmR1eaRFbzI/u/L/AHal0vT9oL2aKH2fxP8AxV0dro32iMIg2srbNrfxVcY8sfeFzRMLT9D+zq03kxlWTa+1922nyeHIViL/AGldi/N+7/haurtdB3Sr5Nmvm/e2sny1Ys9F8lXhSzZ9z7flT+Ko5YfEPnPONW8OzW8n75Gddu5o/K+83+9WJf6LbW4Hy87GZWb7q/7Neo6x4fSWZ0fzt/8AAyp/FWLqWizCz+SFWRX3bdtHLzBGR5hqGkvD/pLpGybP+Wf8O7+9WHdeH7xllhgdnVk3Jur0+98M/aI2gmRv3j733J8q1nXHhe/VX2IpP3n/ANla5ZUeXUr2p5hNoKKsvnIz7fmRli+aprHTUVv9S2I/m27fmruLzwv5cgmRJHXf/D/FRD4Z2q3kwyKJN29m+8q15mMw8KmjO2jiJHOafpqNdbHhXZt2vHIn3q34/DrrCE+zNK+xty/+y1at9J+yKUubZd33HXZ8y/7VWrNnWZoZHkwzbfmi+bbXy2KwMY1bxifRYPFe7yspQ6WkkI8ncm7/AJd2+8tTW+l7lksP3iptXa27+KrU8dsjLN/d+bd/darFmX8rZ5LM6r8n93/gVZxw8ZU/hPUljJRlyRIbHSX8mSF0XfsXZHG+35q37Gxdo45k3ZZ1WWNU+WOqsKvJbxQpbt+72/vK3NLtYZI0imTA3q3/AAKvdwWGtqebisR0NPSdDDMIZodrQ/N8v8Va1npMNxGYYXZHZf8AgVR6XMm8/vm8rdt8xU+at/TVeOfYm3LfK7SL95f71fSYej7x4FatzGYdB/0d/sz/AMda1no7uqxzbm2rudv71alrZ/L5ibf3n3PM+7WpY6Sl5Mk80ewfeby/4q9aNHseXUqGfY6DDKqzPM3zNuZV+Xb/ALNbFn4VhukczQ7pdm7b97/vmt/R/DKNGISvyM/+sX5q6XS/Ct/b48uZf9iSNP4a6JUfdMJVjh4fDqTx73t2favy/L8q0Xnh+a4tQibtrRKm3b80lehw+GUSNU2Mx3t97+Gs+60VFs4Ybrc0ar/u1ySpjjUPLrnwy8Lb/J8ppPlRW+9trltc0XybqVJrbbtSvVte0b99Knyt8/y+Z8u2uN8SWvkyOnkyKsj7d2/duWuGtROunW5TyzxBpkLfI7sm59yK33WrldUt5o9+za2193yr8q/w/LXo+vafDcNvFtvaN/4v+Wa/7NcjrFjHCRc712/NvX+7Xm1KNLlsehSrX+0efatZvNOJJn/1a7Ym/vVzmqMkcfyTbv4fMZPmb/drt/EQmMO/+Nl+7vXbtridUjmjhm8l9qq+75f4a8upRl9mJ6VHEaHPajqEc0mxHZk2bWkb7tUZpIfMaHfI65+6vy1LqUkclwIfJZ0X5tuz5W/2qp3GoRzSbEkwm35v7qtW0KXQJVoyEuriFkR5kkT5dm5X+ZVqjcTOq7CjfK/3W/8AHanuHeOMb0Un721f7tVfO3TLbJHt+XPmV1xjynJUlzfERybFh37Mf89WrPmhtoWykO1m/iq1dM83yJMyJ/Cy01VSRUSbhV+VZNm6ujl5o8xz838xWjt4VkR0fdtqexs33FESTezbV/ham7khbe6MzN8v76r1nDN5LbHY7n3bqXu0y6ceYsWfkrMkM+35V2/N/erp9HsY5Z28lGby1VVZvu1gWNiMefNbbkVvu7/mrsvD52xo6Jk/d2r95az5rQ5Tq+wW7HRXjkiWGZZVX7yyfxK1ben6XBGo85FdpPv7fl21Z0XT7Z1T5I2lb5flRty/71b2m6LvYb03tGv935dtXT96RhUp/wApy/jW70nTPBkwmcB7pStvHH97cQfvfhk/hX6+/AjWv2K7r/gg98IfD37flubfwHr08mljUbK1lDabfC81B7e6BtgZI2HkMC6q25nIkVkd6/Ib4+QWsHh22ENsqSNqAaQx/dGY24FfVF1+2r8Ofi9/wSZ+HX7Dh+G+opq3hjXpby61a6uons3VJrp0KgLuLMbqQFCAECKQ77iB+9YfL8Hlfg9lmat1Y82Yqc5UpKNSHJTqxi6ba92Ssmm7676WR8Nip1cRxFVwy5dKVkmrp3abv3Wp7hpP7cf/AASK/wCCT/w38Q6l/wAE4jqXxJ+J/ifT2t7XXddhuJIbNA6lI7mSRLbbAGzJ5dum+Vo1EjqAjL8ef8E1/wDgp741/YY/an1b41+KNDXxDonjiZo/iBZRRAXMsbzmZri2+ZUEyOzMFb5GDMh27g6ea3Pg3worvEuhWbOwJVY0Hy4rOv8Awn4cj3bNMtvlTcALc819JlniP4a4fLMbhMbg8Vi5YxJVqtepCVScY/BHmXKoqG8FFKzs+iPPr5NmzrU506kIKn8Kimkr797363P0da4/4NoH8cn9rl/FGsm6L/2wfhWbK++y/bP9Z5H2XydufM58r7R9mz8v+q+Wvmn4yf8ABTr4e/tBf8FU/Af7Y+t/DSHwv4J8F+KNMa1h0rSIv7UudOtJ1ZZbsq4E05UABQ22NAqLu27n+Y59E0FWBl0mJEK/KQgzWVd6ZpXmS7ViCp8oKIMM1LJ/ELgXLsRUrYlY7FTdKdGDr1oT9lTmrSjCyirtJXlJSk7LUzxGV5lUShD2cFdSfLFq7W1/8tEe5/8ABXn9pf4Rftcft4+Lfjd8DdYu9Q8OX1tYW1lfXlg9sbg29rHA0iI/zhGKZXeqNg8qDXrn/BLD9uP9hn4ffs7+Ov2JP29/hqX8K+N9Vhu4/FGl6KsksZVMAXMkOLgeS6q8LoJCjSyDCr1+GtRshbGRYrZGYHBJbAU+lYWpSzwbUDPE5bLJuyMfWvXx/i3wBiuDqHDcsLio0aEaSpzjUhGrF0bck1Jacy5U78tvIwpZHmccfLFc8OaTd002nzbq3Y/Y/wCBHxs/4ID/APBMvxbcftEfs+/GHxt498Vtp0tlYadDHcTyxxyY3hRJb2sK5AAJkYkAHaM9fk39jj/gsL8QP2dv29vGP7WnjTwhBqeifE7VZG8c6HZxjzobV5zJGbQlkUywggLv+WRdwYqzCRfgO/1LWImkWDUXI/3zuWqS6vrAIafWJwpGSyyH5T6V83gfEjw2o0saszw2MxtTF01SqTr1Kcpezi7qMXHkUUpWkrK/Mk73R3SybNp1KSozp01B3Simld9Xe99NPQ/acXX/AAbRf8J3/wANef8ACU619s8z+2f+FWfYr77L9t/1nk/ZfJ2583nyvtH2bPy/6r5a+O/+ClX/AAUn1L/goL+1JpXxOufDbaJ4M8KTC08KaYIQbxbLzhI81x+8KNO+ASqsEUKiAnBkb4htNU1Vjl9VuGdU3OvmHbWzpV3qDbWurpv9rLbqWQ+LnAXD2aRzGvSx2LrU4OnSliK1OfsoS0koJcqTa0cneTWlzrxHCubYui6UZ0qcW7tRi1zNbX3+7Y+9P+C5n7cH7P37df7RHhH4h/s86zqd9pukeB4bC/m1HS2tdlw08s5jUOdzFPO2McbdyHYzqQxv/Ab9u/8AZz8A/wDBFX4ofsU+JNa1ePx94m8VfatJsIdILwTRPJZv5nnbtiqn2MhtxD5lTYrgMV+FtLuY58eZAxwcNv4rQgtrV1+0yTIy4ygjT7x3fdqqfjf4bYfhvAZDHAYr2ODqU6tN89LmcqU+ePM7WabeqSWm1jqhwLnlbFVcT7enzVE09JWs1Z2KFFa4trWMfNZo3yb/AL1R3QslcJDFECPvFlGK+7/4m64Vvb+zq/30/wDM4X4V5na/1iH3S/yPtn/gk5/wVA+FP7NXw98Y/sfftn+Gr/xF8HvG1vJm1tLQXD6bcTBYp8qHR/Ikj+ZihLxvErRrudjX0T8J/ij/AMG7v7AvjiD9qD4L+OPFvjvxTaF5PDuiC2u7l9NeRWUtGtxDbxKwVyu6aR2XqvzAGvyTk8lULbYgx4CmqF2JhHI6ygKehX+CvynPPF/w4zzM8TiadHH4aOKt7enRrU4U62nK3ONnrJaScXFyV77tntYbgXPKFCCdWjPk+FyjJuPo/LpfY99+IX7XWk/tWft3Q/tQ/tk+H73WfDWp+KLabX/Dmj3PltFo8bhVsYGyvypCAucozkMSys5evY/+CyPxq/4JhfGDxB4Mm/4J6/Dmx0u7srCVfE+p6B4bfRtPmjO3yYDavHGXuEbzC0wQZDKC8vHl/BOoTXlqpdNQlIVN3Ofmrn9R1fxDDEJo9SmORkhZSMV9hHx84BWbZfj8Ng8XSjg4OnTpQqwjRcWuVc9O/vcq21Wyveyt5k+As4jQq051qbdR3cnFuV99H0ufor/wRi/a3/Y+/Yk8V/EP49fH241R/Glp4UaD4e2MGkGe3uZWJaWISLkxTuyxBXcIioJcvlgp+QviZ8RPFfxd+ImufFLx1qbXms+ItVn1HU7lhjzJ5pC7kDsMscAcAYA6V4nqOveI4ZjGmvXibv8ApsflrOPivxYkpjl1+8AX+L7Q3zV6uXfSB4HwXEWLzqGBxEq+JVOMnKVNqMaasowWnLFtuUld3k7nFiOB82eFhh3Whywu1ZPVvq+76LyP0p/4I/f8FN/Dn/BPrx/4m8O/GLwjqPiH4d+ONPSDXtO05Y5ZbaeMOI51hlZUlVkkeORCy5VgcnYEb6Muvgr/AMGx/ivU2+I8P7RnizRbW4f7U3hOKXUVihA5MAV7J5gDyMCUnn5WHGPxEn8X+LkDFvEd4pX+Hz2qtceNfGgx/wAVBege1w3+NfOZ34qcFZvndXNsEsfgq9ZRVV4erTiqnIrRcoyU1zRWikrO3qyqPDuZYahGhUdKpGN7c0W7X3s9NH2P1m/4Kv8A/BUT4GftHfBzwb+xh+xT4F1Pw78LfBcqSM99H5B1B4UaK3jSLe7+Sis0m+VvMkeQFlUpub8yvEHwItdc1u71keJJITdztI8Ytd2MnOM7hXB3fjvxmkTCPxVfhv4R9pb/ABqpN4++IBhUnxVfhgnzbLlvvfnXZR8Q/CP/AFeo5NWymvVo05yqJzqe/KpO/NOcozi5SlfW+nRJJI5qmUZ7HFSrxrxUmktFpZbJJrRHcSfs22kjZPi2THp9iH/xdRN+zFZkjZ4xlXaML/oQ4/8AH657SL/4q69Ki2fiPUsNt2gXTf417H8LP2UP2oPiNcfZtLj8QzzMvmWcMZkb7UP9nj7tckuLfAyK1yGp/wCDZ/8Ay0xqYbiCnPXEq/8AhX+R5wf2WrXcW/4TaXJ6/wCgj/4umH9lOwKbD4zkPOcmwH/xdfoD+yL/AMEdvi34u16CT9qPx4vgbTLlcg6pcSvOnp+5U7v++q9N1X/gh98N4fiLYad4V/an1fVtJm1LZfXA02RY0h3fw/PurL/XLwHcv+RFU/8ABs//AJaL2PEsNVXX/gK/yPyvk/ZQsZTubxtLn1+wD/4umH9ky0OP+K6lGDnjTx/8XX6EfFr/AIITfH7wz4o1JdD+PVrDZC4b+zYb/UTFO0O7crNHv/u12PhD/gjv8G/D3hFbv4r/ALV2uXepuqtJa+GfD91OkfGdvnMdu6s6nGHgJH4shqf+DZ//AC00hDiSW2JX/gK/+RPzIX9k6zUYHjiX/wAF4x/6HUkf7KlghBPjSY46f6CP/i6+/wDxP/wS/wDAHihI7H4bfFvxnaNC7CN9TtMNcfN8oba/ymvFvjj/AMEnv23PhLby69oOqX+raVHnbL9tZZZO4+Vj8tTHi7wEntkFT/wdP/5adNOPE0Ja4xR/7dX/AMifOkP7NGnxMrf8JVISvQ/Yx/8AFVbX9n+1ULt8TuNoxn7IP/iqxNd0j4y+E9Tk0nX9a1KGaL/WRm6Ytu/u9aqjxH4/Gzd4ivV/v5lauWrxf4BU9JcPVf8AwdP/AOWnt4bC8Yz/AIeYR/8AAV/8idfB8EoYU2HxLI2DkE2w4/8AHqsW3wjjtk+XX2L5yXNsP/iq5mDxH4obLjX705+6pmNW7XxH4ilGwa1clv8AamNcc+M/o+L/AJpyr/4On/8ALj06eXcfO1swj/4BH/5A3T8Jo3wJNeZgDnBthz9eeakX4UWCLhNSII4H7ngD6ZrEj8Q68duNauGJbDL5pqRdY12SNni1y7LFflUueKyfGn0elvw5V/8AB0//AJcdDwPiFF65lH/wCP8A8gaknwltJZC76w3PYQD/ABqOX4PWspz/AG44Hp9nH/xVZR8Q+IooiJNVucA4aTzTVe88Ua6mUTXrlWLYH741f+uX0e/+icq/+Dp//LiPqHH+/wDaUf8AwCP/AMgaj/A61dSp8RyYJzj7MP8A4qq1z+z5Z3Em8eKZlH90Ww/+KrJvvFPiqOVlXX7oIv8AEJW/xrMuvGvjFZ9qeJL1fvf8tmx/OtqfGX0flouHav8A4On/APLjCrgOPH8WYx/8Aj/8gdG/7ONmzbx4rkB9RZj/AOKqs/7MFk67D4xlwTk/6EOf/H64/UPiD46gQk+K70cZwtyw4/OsiT4k/EAFmXxrqRA+6BeN/jXRDi/wClouHqv/AIOn/wDLTgqYTjWEtcfH/wABX/yJ6G/7Ldq4wfG031NiCf8A0OoZP2TrORy7eOZuf+nAf/F15xd/E74hBd0fjvVVOM4+2N/jVJvi18TNrf8AFdal833MXj/41suLvATl/wCSfq/+DZ//AC05pYbjJ742P/gK/wDkT1H/AIZIsSpQ+OJcH/qHj/4uo3/ZBs2GE8eyqMYwNOH/AMXXlp+LvxPL+X/wnOp8L94Xr/41Gnxb+JzLkfELVM+96/8AjWseL/Ajpw/V/wDBs/8A5acs8FxW98ZH/wABX/yJ6yn7I9mhVl8dygr0xpw/+LqDxL+znc+GtCl1bSteN81speWCS3EeUAyxB3HkDnHevONO+K3xKkwz+OtUI/27x/8AGvffBt/qGsfBEX2q3klxcS6Xc+bNK25mOZByfpX1XDOX+DviFDGYHL8pqYepToTqKbqzduWyVl7SSveSeqa01R5eNq8QZU6dSrXUk5JW5V/kux45o6ozD73zf99V1ul27rIm+H5m+Ztv3a5/QbNLlkfLIVf/AL6rstDt59y/3a/laUfdPtPeNbR7fzGWFIfvNXS2NmkkxhjTKx/N9373+zWXo9u4+R/vK/y7a6a30+RY97p/tIrNt3VPNykSlyF3SdN8uTyZodzMm3cvy7a3dLidmSF3bb/e/vVBYwwyQtbPbMU/hX71bFnb/wAb220fdX+61Pm5iJR5vhNGyEkKxQ7N4/hkb+Jq3tL1Dy02zTZ+Tcqqm75qw7dZsfaYN0R3bkb7qx/7K1qWFtbW9ujTQ+Tufb8yfd/2quBMi1czQqsWxFT5d0qr/eqnqFwkm+HYw/uKtLPdTW7NZzeTMsbbl+X5apXl1Myr/q96tu20c3KXEkWTbNsRG3qm1lrPkmkupvkmbH93Z/tUyS4SPMzuwRn+9/7NTPtUN0okeZok+ZYpFT5d1TKXKe3l0e4XUkMkj3Oze8fyorJu21j6zJtmT5GVmdtqxt8taNxIkluiO+yTb8jbvlb/AGax7qRJJlhuX+X727+JWrklLm+0fd4F8qimjD1BUjLQecrM3zbV/hrkdZj/AHKRwurLvb5f71ddrTeXC8ycqy/8CrlNch3Mnlo23buRl+WueUub3j3qUYx15ivLcIrIiIv7z5Xq3a322RfOdUXZ91v4qxGvNrI+/O3+8lV5NS3SLI/C7P8AVt/FXNHnPzCVTmO60XWIWX9/Nxub5f4lrW026trdt7uzbvm+avO9J1ZIVRN7M33vmrXXXnXP+krt+75f96vGxPtfe7G1OXL70jtlvkurUu7thv4l/iX/ANlp39qP5aCzhZ0+ZmZZfmauQHiR0hZEk3bflfdV+z1jzIza+dsVXVt1eBUouU+ZHtYWXN9o62x1iS2dIX3Z37F+Xc21vmq41x5kZ+7v+9u+7XN299JdFB521l+/8/8ADWhZyIrFH8xWX5otyfeqKFGfOe5TqezjyyNrzHkmebyWMm7au1vl/wB6n3VxDHummuVVtny7fu7qqW9xBcKn/LMN8rzeb92iS3jmVE3/AMH3pE+9/u17eDp83xGWIqfyyI7jZJtROHkX7y/LWbcW95JcfO/C/I235dtbiwfaF/1Lbo6jurWO8h2OPup97+8tfT4Nez908ytiIx90wpNP8yNXTjb8zsz/AMNLb7GvH+dmaT7jfe/75q9JboZAiQsIm+X5vu/dp8dpuVLqFNm6L5V3/wAVe/TlHqeLWqe0nJyK+oW8Kxh4Yd6bN27ftrLupDNM/mIyt/dVNtX7y3fd5dyN+1Nybn+7WXdNL5297nadm3c33a3lLl9456f90oXUKRqfOmZQrbkXbuVqqTNty4f5m+Vl/u1qzW/mRx+dM3mfdVqoSW7/AGxt6bH/AOei1wYip7p6NOMiCNXm2P8Au0/uVbt/OVQ+9nmZtv3qjWDzJk8l/wB0q7n+T7zVbhgxlPOZvm+Rlr5rGVPeuexhY+6T2cv2i4ld+H3t8v8ADVuG8eRnS5T5V+42z+GqqshUon36tL94IEYjZ8v8VeZUfN7x6dGjy+8WY2tppN/nbSqbX3JViCbzmX7Z95flXc/y7arR280LJs+ceVudf4t1SW6+Yr/uWH8O773y1z+5I0qe7A17X7TeXCTQPjd8r/7VX4/JWaG2muVBV2aXcn3qxLPezIn7zMfzP8vy/wC7WzpcjzTH/Rt7R/dqZU/e0OOVTmjqbFuHZtn2lUK/8s9n3lrStVT/AF0KK6t825m+Zay7Fbxgju/Hzfd+9WnHsuIfOhSOM+Uv8O37tc1SM5R5QjySkWGt5vLaazRWdfvbk+VVpLe08yRvOf7vyt/Fu/2qbC7yQ+Q7yOPuu2ypY490a7Jl27tqKqbdq1MYTiZylHm93YRY0WRESHLSPsdvN3f7tNmhdV/1O0t8u7+7Uixpb5dD8sj/AHVqteX0MzOiI0bx/wDAvlrrpVJc+iOKt70TA1CPdJ8+52+ZUXftrDvpt2XhgXP8asnzLXQ6hIkLLN5zM8fzbv4vmrD1CGb7Q/nOxRk3Oy/LXv4X3TwcRExbxUmV4RJ+6X5vMb+GoL6zhjVHfzHH3kXb/FWhND5MbSvtZN/3W/iqC8V2kLu7BWT5o1bdXdGPtDhqRjGPvGck0Nu0nzsjt/Ez7qs2Nxc3ipvRVaFOdv8AF/vUxo08w/Jx/GrJu3VZtVRdiW3luzf3f4q0lH7JzR5o+9EuLLcwRlNm/cjMrN8u2qN1cJc7PkZf73/2VXbiSe1ZrZEU7l/4D/u1VZtyn59rfeRf73+zXPKnE7qdScdSOzTdA7ui7t21G/vVFbyQ26ed8o+8qKz1PHZurffVfM+ZNr/dqrcWrtC3nbd+/wD1e3burikd0ZEbXm1TMltIP7y/d2/7W6s65m85m2TNuZ9zrt3Vea3Tyf30P3k+WPf96s+4jdW3o+1d+3bV0/d95Gdb3ipJqDqsnk+Z/dT5ttXLG8+2Ir7/APVr/c3VmXVq7SL50e9W/ib7qtWhpFu9rH5Pkt8vy7t+6u+nKMjy8R7pdWS5uLj/AElF2/KyNH97dWvp9i8nlZ2lf7rL826q+l2PmN86MWX5UVf4Wrdt7V2u4vvH/pmq/wAX+1XZT3PLqSNHSdNdVWZHWRv7sn/std/4X0GSaFIXhZFuP9Vuf7v+01c/4W0OFZFO/HyblkZl+9Xc+G9NRvJ2XUcvlpuRW+6v+zXdGPuGUpcpu+G9DSNfuLlfldl+bdXRWOipHJ51m+dz7kZvlb/gP96l8P2yfLMkLL5Kbdrfebd97bXX6Xp9muJraH5lXdF/F/vVrH+8YSqGPZ6G8bJN+8Zl+/ubb8tWo/Dzx27bd3yuzeZG9dPY6WkyjfDvWT5du/5quWuhfZ7d96fPv/iT5an2cZC9ocFqHhfbMHhvG+bc7NI38TLWDcaG9qq+Wn+r+4u7dur0vUvD80k3zw/K21XrK1Dw/wCX++e2jdY/uMqfNtp8sooj6xze6jze60Hy4W/c74vm/dyfeXd/dqhcaHDNu+TKr/DIn3v96vRbzR3khCTIqsqN95P++VrIvvDrxxibeu9UVtq1MqcB+097lR59daH5yq8MjIir/dqpfaKk0f7l9zL99d1drdaW/kyWv7xW+9833VrIuLPy4ZIbPcz/AN5l/h/vV52IpndRkcpdQ+SGh8lt0n+tb/lo3+7UE9m8cimZ2SSNPk/hbbW1NpqNi8f5X37Qsny7qqXyO26Z/lO/Yu19y142Ioy5fdPbw9TlKH9mwyRsjzbhIn8LfKzLSIv2VoraGNh5nzbvN2rUmofZ2j+SHY0jbnVfu0JfI0myUf8AXJW/urWNLD8252e2/lLtvZvuRH+VV+Vfn+atuz85bjZDwY1+81YulzQSKqTncPveZu3fd/vVoabeOrFJpmZWdfKZv4t1ephafu2OLEVPaHWaO0MCrsdWeT5nVf8A0Kuh0/8AeN591P5p/gXb91a5XTIf3weHcjr9xf7y10+jhGjimvN29m+6v3f92vZpRsebUlLmOk0u3j8tJtkmF+aJdu5f++a7bS9JSFQ80Hz/AHkX/wBlrA8O2/l4+95TN92u90Wxm8lJnttz/e2yfeVa9aMuWB51SXLL4jR0HRofs6BIdu5NzN/drqNL8O7oY32bUb5UaodHs/Ot1mmtW2RtsRY/4q6OGH5UTGGjfduZfm/4FTl7xwe29/3jNOk/Z972bw48pl3N/FWZqGj20Y+1Ii7V/h+9XWXEUMeN+394m5JP4awdct0khbyU3LHLuZYW2/e/irmqR/lNYyOC8SWPnXOz7MzhUX7396uE8QWryN9zDyOyNu+Vo2r0rxFazWskv7n51dWdt38NcT4ptXmkeHezNIm7bsrkqR5jsp1OY8y1ixmlWWN0VGj+T/Z/76rifEGk/KyTP5qL99v4a9M1uzht5tm/52RmZW/u1xHia1+0M/nTNsVNjL/yzZf7ytXFUpnZTnzanm/iLT7aa3dEtsOv3P4WrgPE1nfLIn+rz/Gu/wD8er0/WLV5J0eH5gvyRSNXnfii7fzprl12GT5UWNf/AB6uSVPlOunW7nA6o0ylk8lt8aN81ZscsM0mxPuM+19y/MzVq6tHMt9Md/y7NyNWHJIm7Y42H7zLv+7WHLE7Obm0iStd/ZWygyi/w7KpXExt2/fJuWT+Gp2mRlPk/wAX3N33qr3Fxtb5HUjbtZlX5v8AdrWMeb3iZSj9oiMkMm5E6/dVViqPzizSpM6jb91Y/ur/APZUrSPGrO8O2X+9v2/LVdpIdzfPv2/7FXy8pzc0Ze6WRJC2zzplf+FvMWtG1YNC77FBZV2bayrFfL2J5Pyfe2t826rkbJuLpt2Mn3V/hqKkeptR547m5p7eXMUmTa23+JN22us0OTyY4t/ll9v3v/sa4rT7r/SNkjq3y/Pu/irY03UpFXzJtqfN/wCO1zyjynbGX2T1Pw3eQxxs80y4+78vyt/s11Gi3ky2otvlU7fnkX7tea+H9WQKj798cf8AqvMf71dPpevPI6Inlptf5938VVR90Kkip+0N5R8KWHlhCy3oV2UYIbY2RVz4NS3EfgGy8vIUSSkkL/00asX443i3HhayiaYtIt6CQG+UfI3btWn8IbpYfANqMsB9pcSEem81/RuYa/RxwX/YY/yqnwUHGXGtV/8ATtf+2mxdLCsh+xopXdu3fdasTVpNzPCk25f7zfxVr6tNCyo/2lk2/KrbayLxRJHvQr+7+VVZvvV+FxlY96pE5++k+z3ieT8jN/e+7WVNJDcSOjwqoZ9zL/erY1xUuHdE5RV3RSRpu/4DWFeW6eYHS22fw7t396u2MoyOOXu/EZOrxJ5zP5n97dXPao33/M4Hlfd2/wAVdDqEKQtMnyv8/wB6ubvlmkjmf5d7N8yrWUpe4VT5ucwdRVGjWZBvb+Hb/dqgiK0fyJ8rfxNV24jhZWhmhZdv+1tVapXrQxqEjdVRfl2/w1wVv5Ud1Pk5x9r+5k3P/f2r/tVp2968Mf8Ae+b5v9mshpEjt0k6Bf4f7tSR3XlyHe/P+ylebUpw2PVw9Q6jTdShZN/nNt/utWtb6hDNDsabKb/3Sx/KzVyVjeJtVJvkP+/96rlnqPnTedN8n8MVebUw8eh7GHxEvhOpWQ+S8iTLlU2P5lKt15ahLlFLMn+kKtYUmrTfO/nY2/c/iqdJnb50+Xcn3m+9urmlT5TpjW5pcpaubpML5sOF3/Jt/hqKaW8kl2QwrhUZfmdV3f8AAaYs3zIn2pWf723+Go/JupGbe6/N8yKv3WqOWPxHRGpL4YmdqkIZVmdGUs/+9t/2aw9Q0+FW+d8LXSXFu8f/AC87v71ZU9ujTND5K7ZPl3NXVT92Bz1uT7Rzd9ZPGp37V2/drPuLVJP7rH+81bt5HbMrOjsw+7/wKqDWJkmf+/t/iT5a9LD80tTycQY01jC4bc7Nt+Ws66tXG7f91fu7q6Kaz8uP7jN/u/xVpaH8L/EPi7ULa203TZn+0f6pVi3V6FPyPFxHuxOEh0O81C+FtZwyM8j7UWNN1fVv7Av/AAS3+LX7X3jaHQdNsJIbKF1bUtSa1ZvJj+9+7X+KT/Zr6b/4Juf8Eebz4seKtKm8Z2F1I7T/AL+38hoIoV+9ukkb+8v92v23+HP7PPgz4T6Cnwx+CFhpfhTTobBbJLrTbf8A0lm/5aTbv7zf3q6amKjThoeJWlOpL+6fm98D/wDgk78B/g7qlsmseGr7UdYhnVNN0W6sPtNzMy/eaSOP5Y/+BV9cWvgHxJ8M9akv38bWPg+7h0tYrLRdF0uGS6WNV3KqxxqzKzNXqnxU8Lw/s3eC0tvAGsW+hW19ef8AFUeO9cuPMuY4/wCJYN3zNI1eORft/wDwr0Hwn4kh/Zs8ITv4gsomWDxd4l0zd9o2/em2/eZa4qmK5pcrLp4fl95HL+FfignwfutS8bfH74eXmqy6l82m6l44vVtnkbd91YfvN/3zXd+C/wDgpp/wTz0XwWttrR01NZmZluNN0PRpJFt5F/haSviLxb8MPit+0/42i8ffFbxxqHiHUb23Zp9Umt5NscbN8qwxr8qr/u1U1z9iV/gt4y0jW7b4OeKvFWlx26zz28l/9h+1XG77u7+7/wChVzuFSUvcfKaJ0qe59geKP+ChvwKu9ZtfE9z8QvBL6apaGDw7faSqNG275WluZV+auF+KXx28Sa5NND4V8c+EdR0jVtssWm6GyyLb7v4WZa8Z+IHgtPi54bfwrrH7Hmg+G7aSWPbdXXiH7T5f+z9371a/hX9jH4keFfh5Z67oMPgu2s7GdvNtdHlbzfL/AIdzVl70or3iZRh8TNz4Y6L+0do+sf8ACW23gnT76BZf9FuLWVWVv7u5W/irvNB+JHxO017nVfiv+zHqniO0uvMafUI/LeTy/wC8qr8u1a8f0v8AaG1j4ftL4V8Z6rHi3l3RR2su5V217r8Af23Pg5r1xbWEOq3iBf8Aj8hki8taz9sohKjKUYuJ5l8Vv+Cev7AH7d0N/MlpceEvEl5ZslnfLatBPbzbfl8z/gVfmR8fv+CV/wC1v+zP4yufCuq/DeTxVpTSt/Z3iDT4JGjuIV+9Izbflr91/FnxM/ZX+IWtJ4V0fxhouma5G/m3TN+4aP8AhXdJ91mWuz+Hfwx+JHhXw/c3mgfH6z8QQ+VtsLe8RZfMX+783y7a6o4mNSNpu6HRrV8PP3T+ZTxx8Dn0XTU1Wztri3uY5WivdNvHVXj2r95V+9trgI7OGNvkdXr+jP8Abm/Y9+C3x48G3V58RfhRpOh+IZoGWDxNoKRxbmVfusq/eavxj/bG/Y5034I689/4P8SR6laR2fmy27Ltnjb+Lcq1lWp0pR5oM+gy/OOafJM+cms+gR1wv39q/NSx2sirIHRvmbb/AL1WvLSRl2W23+J91TQ2bx7ZvlJX+GvN+H3T3+b2hnyRusYTyfmb+8tV2s/3OzyFyr/e21rtHMiiaP7u+qF8rxzPNs37v87q2jGcjP2kI7GJeRu293h+7/Fu+9WPqC/KJvJZfk27a3tQjSRfLj4Xft3bqw9QjmjZSeR/vV004++cVatPc5y+/eP5jvjb8u3+KsS/WZpEQouG3fd/hrbvo33b0/76rCvvO8tk2bl/u16NOJ5datL7RRuvJCnj/gVUpJPmI2fN/s1bulTaN7/eT7tVZN8cnyJXXGJxyl7xXZdqbvmpjxxtHs/i3fdp8nmN8j7m/i2/3afDHJ/y061pGJHMW9PXzZFd5vu/3a+k/h6u34ERKB/zC7nj8ZK+cbGNI9uxP++q+jvh6HX4ERCQfN/ZdznB95K/evo+K2f5n/2B1f8A0umfK8Wf7tR/6+R/Jnm+it5bI2zG3+7XaaDJDNCJgjb93yN/s/7Vcho7Iyqn975n/vV1mgx7Yx5PB3LtZvmr+f8A4j6j4Tq9BRFuPJTa25l+9/DXTWMcefJSbhpfk+SuY0dnmZnMyn5vu10+m/6QphSFt2/5If7tTzcupEonQ6bbwyKjo+7/AHa1rKGZ5h90JGzNFGv8X+9WPpcOJBvmZdvzba17GT7029n+Xcny/NUc3MZc38pft7VI28+d/mZv4fm+Wrq3Ajbf1+Rdke35aq291C6mPYx/2Vp8sn2VjGqKEb5nbfWg+vvDdQvP9ckyKm6L7y/+g7ayLwQx26eTNIdvy+d/EzVYvE2OJtm7cnzrWczXO7zo/LVvu+Wr/NRL+UdOI24uXkZ5p0y33n/u1HNdPEqv5+759qL97a1UtWaT7kN6rJsVpVX+H/ZqlJMnk797EfdX56mUoSPbwcYR/wARqXWoIzDztsyxy/3PvNWb5iRri5mXcz/I2z+Gq0lxDcYtg+0LLu2tUn252tme5T5Gfai7K4Zf3T7PL6nRlPUNkknnI+Bu+eT/AGf7rVzeuRxyKqIjbFb/AIFWtql0jWpdJmRG+9urA1i+eMMvVf42rGMZnvU5fZkcxJebXZPJYj+Fd9VJblI2++uf4qdJsWQpDNnb9/b/AHqrX0mMJ/Dt+9tqeaPMfmns5dB66gkbLN8zFau2+pJIqo8y76xmuofMEjvsVf4VoVd0yyQvINvzfK/3qyqU6UmbxjzHRrqjthCrZb+781a9nqCbU3vsZtquv/2Nchbyut0ru7J/Eu1q2be4mikX7Ym9vu+ZXFWwMJS5onXh6ns5nX2+rJDIrzP5W35fl+bdW5p+oeYqzR3nzfKv/Aa4rT7hJJm+RnX/AJZNW7ZzHcj/AN5/93atc/1OEdviO+nif5jqrGRFUzTQsTJLtRm+78talncOrJ/Du+bd97av8Vc3pyzSRukNz96X5ZF+7W/psk2xE/h27XVVrsw9OPU09pLl90vxyJCyvFCx3Nt8yP8A9mqzJayNGz+SodfmaRf7tRWLBVM3y7f7rPU8yzRyO6bvu/xP8u2vcw8eU4J1Jbsr3SvHINjr8vzPuqpcXCW8L3M37pP4pG+7RdXGYWuZnjV42ZEWP71ZN1dYyk021Pu7Wr1Inm1Je97xHJcCTe/nM/mf+PVS2zMz8x5b5Uobei/uXj/3l/u04y2zY2Ptb+9WsuXlFGQBYfLTY+z+Hc33Waq+oQwxsm91VmTc+16j2wSSMnk/Mz/OrP8A+PVZkt7a4+cbX8v5d392vJrfEelQqSlHUpxuivs3/wC5t+7T1jto5E+fYzL/AKtnpsKp5ypsZh/B8v3qWbY0hTZlP7q14OIj7/unt4ep7t+UtW7P9l2IMfe83c/zNVvyfLWJ4fM+7tZf4f8AvqqlvBjYj2zN8u3ctascKSXC23zJtib73/oNeZWlHlPTpS/mEt9isr72+98rK9Ti3RZP310xVfvSN/FTrdfLj/0nzPl/8epwh+zKHd1P8P3P4a5+aP2RylEnaORbdUttyP8AKzyfwttq3DIjEJOiht+52j+6y1BYwzTRJj/U/eXd/DVqONDHvd2Dfd+VflapcuY45OUY7Gpp6hmeZ3bZvV1/u7v71a9jczTSM7nb5fy7tlY1uyRtDFAmH/u7/vLWxDceZI8KfMzfdbd8y1MnPm2FH3Y3LscyTR/ang2iP5f97/dqCSP7BZmG8fcPvJ5abfl/u1djVI1KJNIm2VW8uT+Gqlwu6cwzSSMPvfM9RGXN7pPL7TUJpEWMOk2wKu91/i3Vn6pNDIyJAmxNvzNCvzbqk3Qt5s2zcm7au2qlxZyKp8nc0jLtXy/utXThY8suYxr+9T5YlG+2XK/aWdSq7d7NVS6hmdZJk2/3X/i+WtNo5lVraFFDrFu/efdbd/FUU1vNbqT5ynzPl+Wvfw/NLWR4eIjyysYzW8MiiR0Xb/d31TktYfJfYmz5927+Fq17iFJ187+L+9/d21n3l19ohWG2+fy/mZWWvQicNSjzRM5bXy2iTyfmk/4EtLarDJJvhdWG7Z5jfL5dKyp5jOj4Vvl/4FUUEz7hC5VW3bnZq3+wc0qfLqWpreBV8lHY7v8Ax6k+xp5aOk27/Zao4ZJo7jydmdvzKzJ8rf7NWLFXZGhk25b7lY1Iy5CqPuysxzWKXEJTydq/eVaoXcP/AC23rv8A7zNWrCzwxl4+UZ9vzVRuo0VhB82a83mlGbud3L8JmSafcoiPvX+JdrfMy/7VQ3Gnpu8n7qt/C1bFvbv5i+cm35vuqu7dTxZvI7/uVMcfyr8ny7an7VjWUfd5jEj0PcoS28vZuZtsn8P+7WlpugwrKqB8ldrRfJ8zVqLYorb3T/XL8m5d3l1o2th5ezZC38K7a6o80djy8RHmK2l6G9ri6mRnb7y7fl2tWxo+kos377cvmff+T7tS6bp6bikMHzrub5m+XbWxptmkhi3wsyL8u3evzf71elR908etHl3L2kWVs0yTIkbpH8u7+HbXb+H7ZFjV7f5Vb5vl+bbWPptjDHtS2+eFYl+bZu+b+7XYeH7G282F4PlDL83+1Xpx+A8ytL+8dRoazeYpmRnXzfk3V2ui28MUZhSFlfZ/vfLXN+HVSOSGF5trM3yL97/vr+7Xc6fbpBN/x8ybpotvmKu6teU45SlsXLPS4I4/s0KRtJtXfJ/FtrS2+ZbpN5Ks3lbH3L8v+9/vUy3tbbcPvff27l+XctXriFI7dnR8hfl8ur92RMako6uRz0kE0yO6RYfd8m7+7/EzVn3WloskrpCxG9d237q10ctj5y7ERvubm+aqc1vAv743jJuTc/8AwKp+EdOXNPU5TVNMhmf/AI9ssqbdzP8AK1Zl7pqRw7Ld1RJF2/f+7/vV1Elj5zLD0T5vmb+Jv71YuqQzW586F9g2N93+H/aaspbnXTp+9zHI6lZ/vvn8tmX77bNq/wCztrCvtPDbtiK0zf3fl3V1us7JrdPMhjTzN2yTZWDqFpuVkmh2fL96OX/x6uKodtPc5XVLMNl0TL7W+X/arCvLWGORUTa3l/Nt/wBrb/47XXalb2DRvD58yFU3K0fy/N/drC1iz25d9qSfefdXnVNzvoylE5uaFI5vO+VGb5trS7qVrBHUpv8ANWFFbd/EtXrrT0uLyPfyq/c2rtqBovsb7H8zc3y7V/u/71Yr3Y+8d0ZSJ7NkjLW0NsrK38K/Kq/3mq3YmFpmd5G3+VugZW+bbWW159hkV9isGfam7d92mLrCsyO9s2PuL/u124b4SKlQ7PSbhI5khd5N7S/Kq/3a6zQ44bi4WFE/d7fk/wBlq8+0W5hZtkL73aL727b8tdn4V1J5V/fJtG3btX71erRlyxPPqe8eo6HH5K7PtP8Ayy27lrudFbdDHNOincm5PM/hb/arzfwjqFt5amaFmbytm1m27q7fR9UeaH7S7tvZ13bk+Zq9Knyyjynl1z0rQbqdrWJ5v3Use50kVvlrorW6e8jM0nz/ALpmeRa4Kw1izjs47VH2NIzNu3/w1vaXrkMduAjrjytqbmrSMuh50v7p0MMjr++WaNl+/tb+7/u1jax9muN6GFn/AIn2/wAO6pf7UT7Ok1tMqN5TK6/3l/2qyNSvEMbQpNt3fcVajl/lK9pyxMLxI0Nqz7PMVd33fN+b7tcXqkqfbE3+Z91vmVPu11WrNctvWHy9/wDH5393+8tcxrTfK4DqEVfnVv4tv8Vc1SJ00ZHFa9s3s7wyIm/asn8Tbq4jXLNZLeW2d8hv4W/vV3fiR4ZoZNj/ADLFuWRmridaaG4k87Zgtt/1f3a45RPRjU5Tz/xEnlwmF3bf99fL+ZVrzvxhZozHcilW+VK9H8SW9/8AaGhhRY90u/zGf+Hb92uG8VQzSQs6W0afN/f/AIq5alP7R005HmXiDz0mWHezP/Gq1yuoNM1wz7Njt/eeu18QQJFG8yWzI8f/AC0V/u1xd8qTSYmm+ZtvzbK4pRl/KdlOXwjVukaRnurn5tu3b/n+KorxkkYSI7BF+bd/eprY+bYmdvy7tn3qjZXkh2R8Kv3VVKiPu7FS96ZHdTeYyeYm5Wfbu/u09tkcjBE+T5vNVv7v+zUSw7vnT5/93+Kp1W53NMnyqz7l3PXRzmEf5RLeR/kdIW3Mn3VWtJbNG3Q/Zl+aL/e3VDD+8k3zblbfuWRavWqpFbibZub723dtrCpzHXRjEfDazyQ7HdU8z5av2K/YQ0Gzeypt3Mv8NRWfyt+7RlC8uy/NWiqotwE877yKyK33WauSUj0I0+aPMXtJvvLKQpbN91tm7+Gui0vUoYcfvtxaJWRl/vVzcMn2Vk3vtkb5tqt93+9VvT7lPtC7327vmRq2oyjzaGNTm6l74j3sNx4fto4wHb7UDJKP4jtatj4ZyuvhKDy1O1Gcy4Of4z2rk/GDvLYJPIxLNOMgNx0PbtW78PbiJfDqSS4It95AEu35ix+9X9GZhL/jnDBP/qMf5VT4elGP+utZP/n1+sTspmhmkLvNmP70En8X+6y1mapMizMiLv2/886WG8mk370Z/wC58u2qt55NqrO6yeczbl+baq/7LV+BRrcp9HKPMZ+qTbrfZZuyDZjb93b/ALNc1qz3McjwPJ95F3svzLu/3q2b6S5uN87vGHZNvzJ91qwtU+ZjZzOq/e+98tb+15TD2fMZF9dJDM6fLtZNqfPXPateOkj/AGZ9q7fvL/erV1pYY2R0OxWb7y/NXP30bm3b7w2v8+3+Gp9pGQo0yjqF5uXYiNn+Pd96s2aTzNkJ243fxf3qkummkb53/g+bclZsmoeX8j7VH97+81ZSkbRLrSW3k7872b5drf3lomm/c7JplG3bs2vWZ9ukmUwzPs+b5f8AgVJ9p8tv4QI/4WrjlT9/3TujU93lN+O63TM6Jh2+9/u1as2/dl9643/xfw1g2uofMHefd83zVesdSePciSKi7tyfL96sK1GZ2Ua3u6m4sjriN35VP4f4q0YZPtEbO7/Lt27VrFtdReS3b98rN92r8d1C0I2XPyx/M6t/erlqQud9OX8pfhhh2qjpvaR9qKv3v+BVYW4STZ8mx/4lb/lnVO11Ca4VkR2RG/iWrP8ApMiqg2uVbbXNKEubU6Y1OWPukM0fnXB/0nj+CsjU1RpPLmRiF+5trSuvN3BPs2drfOqt92quq27rGvkvjb9xVetaceXlRnL3tTL+z75MSIyK38Mj/wAVQR2X2hmhm4H+/VqSHzP3Lzcr83+1XQeBfhzrHiq8httHs2keSVV2+Vu+9/s130Y++ebiJcsRnw7+HP8Awk2qW9nN8jSSr5W5GbdX6r/sA/sV+G9H0zTbnw34Ptb/AFmS9VpZr6DzWX5f4Y/4a8s/YO/Zb0Twt4403Ur/AEqa/urHd9qkW1VoI5P7v+01fpF+zLq9/wDDG6u9A+Ffw6vLvxDql1591qmqOq21nDu/vf8ALSTb91VrapW5dj5zEVuaXKfT/wADfCN54Y8F2ieNtNtbXUtvlRbbdY9zf7KrTPjB8evgr8A9A/t34qeLLdZYX/dWNvFvlmk/hVY1/iq74KX4iWej3N7eWtrc3rp5i32oy7VaRv4f9lVr5Y/aX/Z9vPFEepT/ABR8f2d4983mWtjodvJuXa3zNu/hVf71c060tLbGHLA4P9r39snxZ+0H4etNM+Enw3jd9QuvIiutSX7Zc2K7fvRQL+7jk/2m+7Wj+yZ/wTr1nVPD7698VPjRNYy3Cqt7p8lkssrL/wBdG+X5v9mug/ZL+CvhLwv4mg8O+DNKmhsLVfP+1XFw0lzcTN97b/DX2j4c8DQaZprYh8iWRc/aHCsy/wDfVbUpc0boG+Y8+1zwfovwX+GKeD/BnhiN20+3Vl1jULWPy1+b+KvnH4pal4t8YFL+GGPVnkTdtW82qu3+7XvnxnuPAei6bcN4y+IcmuyzTsn9mteeXHuVflVlX73+7Xw7+0d4os7G+stYm8SeHYXum2RW9jebHjX/AGvm/u1lUrSlIj2fN8RzXxUuP+EHszrfiHwlfW33pfsduvmt/vKq1leHf2nPhj4quH8PaJ4km0p2dVnsbiJkkZv4lrmr79u7XvhrJPoPwr8H6TtuItqXXiK3a7kbavzNury7w78PfFHx41C51i88f/2KtxetPLbx6SsEDSN95lk+9trDmnPWmbR5eWzPRPjr+y38MbmSXxt4f8Q3k3iS82tLp8bfumj/ALrN/ep/7Jdunwv+KUKeIf2eZp9OklVrrUtQv97fL/Esar/47WF8P/hX4X8M+OLfw9f/ABdmuby3i3bl3eQq/wC1u/i/2q2PiZN488H65Hrvgnx54oubaFlX7RpPh/8Adqv+y3/LT/eq5SqONmZcvvXieueP9Q8VfF3xrcalpv7PGj29it0txFqHiSw2xx7f4ViX+9/tV0q/tkfEP4C2P9peML/wHrEUd1t/sfT5drRq3/LNY1+7Wf8ADj/gpRo/wx0nStN+IXw38Ta5atKv2rUtUtYYlb5dv3WXdTPiF8Ef2Ff24PFH/CYfs2X9xpXim1/e6tpOkzssWpN/FGyt8u7/AGv4ayk4zhyS91mnLKnLmR2d9/wUg/Z4+NkNt4D+IXw9k0F7qLfFeQ3Xybv9la+Y/wBt39l34e/EbSb34o/DHXrfUjZ6dMu23+V5l2/dk/vfN/FWv4o/Z5+D/g/UJvD3xU+KPg/wnrlvLsi8Orr32u6jX+Hdt+63+zUWi/C/xV4bhuNSfXpNX0e+umVLqFNqqq/dXb/u1EZSo+7zXZMpc3vpWPyP1vT7m11KW21KH7O6vteFV/1bf3aja3T5YUudwX+Gv00+LX/BIuz+M2rS+M/h14ts7We8/wCPixZ9rK33t23b/dr47/aC/Yj8f/Ae4msrxI7kKzN5kMu5vl/9Crf6vKUOdH0OCzahOMYSPCpLd1h39GV2rLvoZGT7+D8rf3q3Li1TzPJmdh/u/wB6s/Uo0WHZbOpH8TN/erGnLl9yR60owl70TndUVPLdM/7Xy/LWBqkbybn3r5X8C1vX373ejnbWNqEbxq7uVZm3fKv92vQp80uU8ytLl+E5jUFZk+4y/wASstYt8sMWUfdub+L+7XR6hH9qlKD5X/u/3awL2NNrb3yf71d9PT3TyakpcxjTKkMmwfO0ny/7NU5ELSMnnfNs3Vauv3LM/wB4VCkfy70fI/j3V083vGBBDvXG87t33mqaFAGXYn3qTydzbEdf9mpLdXVs9dr/AHqr4SOZlzT1+Zkf+58tfRXgL5vgVHztzpdzz6cyV88WkcKrsfdlf4q+iPh+zN8C4mYYP9mXOfzkr97+j5/yP8z/AOwOr/6XTPmeKv8AdaP/AF8j+TPOdDm2yKn3vu72auo0uTbcKLaHd/tN/DXJaW0zTNsm3Fkrp9Jk2xrh2B/g21/P8tz6n3zr9Lkfd9xlDfLu/hauo0mRGgWG5feP4Pm27a4jS70WzK5m+Vk2sv3q6HS7xJoVaGFWlV/vUpR93UiW52mn3BZeX2Kv3Nr1s6fedfJRfN+8v91q4+z1F1ZXm2pu/wCef3a2NN1KETBEul/3m+6y0EcpuWszrNFO7tMdmzy9u2rHnTXEhfC7o/mfzE+Vv+A1irq00cKQojHb/t7fLpWvkuZF8jbtb5dytu205S7F8rLuragirs8xgdm7d/DWJe6hNGheLhZG27o/4ajvL51jzM+5dm75XrIvdUeRt7pu2/cXfWftOb4RxJ7q8aEbOvmP8+75dq1mtqCCRUhTn7ybfu1n3l0kinYdo/j3N/6DWfLceRCH+0ttVfvfeqZfCejhZe9zG22oJC/yQsN27duXd8tQXGsPGuyP51VPn/utWW+pIyrCkzYVNqtUclw6rJCjZC/3Xrml70rH0uHrSly2JtQvnuI2DxxrE38NY+pXaKzpsykiL8u+lurxJIWR/u/987aydR1LaWf5cL8vy0faPcjWl8UigzO7b0T7qbWWoJmmZdj7cr/d/u0sjPuJQL97+Kobjfux/wCPVjKPQ+Zo4eRXjj86d/8A2WrNqrzKrom0/wAf+1UentCq70Rhtfbuq3ZxvG2xN2Wf71YSlynfHAlizVJI0dEy/wB3/ZrUt7dGTzod2/8AvSPVO3SQyLvTLf7K1rWq7d6fM7L/AHa55SF9VkW9K+0t++RNg3fJuWtmxtzbnejt8qfJub71ULO2/dmZ9rBl2/7talrb/Mv2NPNVV+bzGrH4iOWMY25TV0i6dW/cxsQ3yvu+6v8As10mjxxzKwf76/xVzel3k1um/wCzLIjJudm/8dre0u6iXejqytsVvlf71dVGPvX5TLmjGBuwXUP+uuYW/hVWV/mZv71STTeXZuQnKu21l/u1kWMgl3u6NsaX/Wfd+b/ZqWa7dm+zQvkL/Dsr1qOnvHNUqdSjqE140fz/ADbk/wBW3y/NWPOs7Mfk8xf7y1q6lHNJK7xuyMvzbf71ULqNPuImVb+KvSjUt7zOeUoy0KCw+Yjp8zjf977u6o185MfZiy7U+ZfvVaa1eFg7n5WX71VfL8uRPs275vuf7VOUoS0OaMeUVWRspDtVu22nRyQtiH7yt9/b/FTltXWRi8OP4t33lp0Vi8Ma/PtZm+TbF8tcFaUJHbTxHKQzQ7f9S+w7Nu5nqaGF2j3wvsf/ANC/vVLHZ2smNjySFfubU+WrNrapGrQqjM7N8n/xO2vBxEuU9zC1OaN0Lp9jDGv2lLZV3fM82771Xbe1eb/XeZn5di/w7atLpk0cLQwwxt8n3V+6tWo9JRlVLncHb5mVf4a8apLmnc9ePwWKv2d1+5uTd/rVanxw+Y29/wDeH91avfYkWN5km811/hb+GnfYYWz8jPui3Nt+XbUS5JaF8xBDC6qk1zw0n+q3fw1ZhjSTE6bl2vt3N92n2tjNJGUeHfGv3Nqfdq20fkxmGG2Z1Vfvbfvf8CqqcZSlyo5KlSMY+8JZtM86pN5efNb94yfw1q2vnSQ+S+3P/PRU21nxtCYfkh3KybvmRlZavaZNI0332MS/cVm+atfZ+7ynOq39402Fy+Ibm5UDerbmXczbVqDUpD99/wB6y/daNqcq/vP9DhZjuqJLdFbyXRvl3VEaPwxiae2925SuZoY5kRH+bb8/yf8AjtRqzxrsS62bUb93/eqe+jd7dU+Zom/hV/mrNk2NvCbv3i7dsld1Gj/dMqlSXQshraOzim++0bbt0j/+OrVaSb7Ysbwjb97bUULO2xJ3WIR/cj/utTftCthEmkfc+3dIm2vWpx+yefKPtPeIL7eqvC9su6P+LfWRcLCU8n5g7ffatLUI08ze/wAu1d21WrI1KYSK7p8iq+12V67IxMpUylNJMsyRnyz+9b5m/i2/3aa9x5jK+zYG/wDHabcKh3u+5Q3yrIzfe/3abCsNwy2021gq7ttacsTllHl90s6XsYMjyL5sku7ar/w1oMsKybIQ2V++zLVKFUh2O6MzL9zy6v2+Wjd3Ta27citWNSRl7P3h9mz/AO0W2srKyf8Aj1PjjeaTznf5G+Xb/tVHn7KzjfJ++2/x1chVJlLxjZu+Xcqfdry8RI7KcZdCKxsfJkeb+98yL97bV+yt3uJvJhmYts37VSoYYXVRCjthV+eSRPvf7VXIZlhxD5ys23a21az9/wCIcpfykK26Ouzfyr7vlqzGkNu335Pl2/N/E1RyXEKsE8xidn3lSka4ttqfuZC6/NuXdXXTjzHmV/3nMy9atDHGZt+6P+P+9Wzp81m0bedZ5/6aMn3V/hrBs5HN59m+aHcm7ds+Vq3NLmRWV5Dt2vt/efxN/dr1qEbniVuaJ2OiqiwwO8zbGT7u3buWu48Oxw+TFMnH3WRl+XbXA6JcfZVj3w7Vj+ZPm+bdXY+G7xJIUCWe5mf7sbV6lOPNG542I5eY77RLpIyiPMsrs7fu4/4v96uw02TdYq/ygbVb723/AL5rgtDuvtGJkDM33VX7u2us0++8tvnmVxGq7lZd3zVoc3xHZWt1czKu918vZv2/xLV6a6CzF0dSq/8Aj1YdjqTw7ktrnZ9o/wBe0kXyt/u1bhvIGDIkyiJVZt0ny1PMVGj0LMjeTJ8kP8G5131m3zQyN5zpx/db+GppLq2bfcw7gsa7vMb+Jf71ZtxqltNfRo6LsZGdGX5t1c8qx108P3INSbzI/Ohh80bGVVZ9tc7qFmkcPk+TC+1NzfN8y/7v+zWtdXHnQvj+F22K1Yd1NAsZROUX5UXf92salQ6o0ZRMrUIPOj+0TTcb12qy/d/4DWNqny3G+Z8sqs+1a276R/LbyblYiv3/AJPu1zWtXVhbq+/lt/3VeueVTmOmNOXUr3W9SvnQsyN96Nk+6396se8hhulJR2dWfbtm/hqxrGvPJC8yTfMvy7pK5rUvEPlRvDdTK4ZtyL/CtclSXN8J0Qj0kF8zrsSN13Rrv3L/APFVka1qFtbmXyZmRv7u2qOteKJre1Z7Y7n3fwv8tcl4g8YPHdKkLx7VRvl3/eaufm+ydtOUuU27rxAscgebdsX7n+0396qC+IEaTYu53ZvkZq4+68UQs3nJ8jr833/l3VUt/FE8lwD5zKy/3v4q7sPEwrS5j17Rtc+yqr/aY2VV+RfvV3/hDWJpoxEjqs396vEPCfiIbh5M3zb/AJ/kr0fwrqCbQk1ztdk3O392vSpS5viOGp/dPaNF1a2h2I/lwsyKySfers9B1x5GiunuWG35Nqv97/aryPQb52mhmtplO5Nv+9XcaLqSTR7/ALNGhb5dzPtr1ISR51Z9OU9G03xBtuFuRtA3bdrfNXS2upPHGvzxojfdrz3SNQh+ypm5kdlZVf5PvLXT6DJ82yb5wyN833tv8VbxlHm8jhqRidRHeXjQtC82d332VKfHDexxLveF/l2sv+1VW1j3QoftO1FVWfayt81WYdk1x8m1Gb5f3lPliRKMvdMnWo4fORJrZSF/iV/lauZ8RSfu1tk2u21meRv8/drrdU8wzM7pt2pu2/xVyGtRwxw7d7Kn3fM+6y1zVPdNobnE+IpkuFd3LANEyrHs/wDQa4jVFRVW2e5bY27Yuz7tdv4kaDzD9j2qyvtfdXF+JJLaNltvs+59+5W/iZf71ckpWkejCWhxviq1tri3ZLYs6LFtSTf8zVw+vWkzW8c1lNnydy/N/DXeaosKybERog25dq/xf7tcprFqiw70mZDI/wB1k+XbXNKJ0U9jzTxBaveQuiOzQs25o64/UtK27/k2D7u1q9R1SxhhD73XMnyoy/w1yXiDRka68ub59v3ZP71efU947qf8xxM1qixmZf76/wCz8tI0Lx/6M6R5X5lbdWxNYvJNvT7q/eXbuVlqKPS4ZZHmeHb/AH//AImuOU/sm/LKWxkR2czM1zN5iL/Bt/ipi2+6bcjs21v++a17rT+C6QyL8/3v9mqLWnlzDejZaXcrf3q2+KGgpQ5eUdat5M42Q71V93ltVqG4fzvsaJ8uzckdPtbdFj3vJvb/AGV/8dqxYvDIfORNyszK3mJWNT+U6afNGJPbx3LbPJTcrJ95quQr5cghRPmVfnZf4Wp1nazGMwvuUL/ql31bk01IVV3djCy/xfeVqiPw6HUpT5iuzJYqzzu2dnz7l3VdtVtopo4Jkh2rt+b/AOJp0MM6yF3dlZv4l/hpq27qv2abgt83mbfu/wB2j4vhCUeUp+IniNqiR5GJ2wCc8etaXhJ5Y9KXG0glshuwz1qj4pt2t7WBdwYHblx3ODVnwsivpX+sZWy2GzgHHO2v6JzOUv8AiWzBNf8AQY/yrHw9Ff8AGc1b/wDPpf8Atp1EeqQtb/aS7b1fc/l/M22ob3UUaeRIfMdfuqsn/oTVR3T27eT/AKvcm7cv3WWq8mpeZC3leZv/ALv3a/nmVY+0jh+wt9d+T86Qx7m+/WBr0jtvmSb5Nu5Fb+9V281byVZ4Xx867qxdY1D7RC6Jubd9xV+7URrS5rmcsLEyr64dpPn4X+Nv7tc7qk3nP89ypX+7/erSvrrYq7/nbZ/f+VWrIvo5mVd+3d952WtI1uaXumX1flmZ2pR7rht6Y/hVmf71ZV5sZvuKo/gZkrQul8zbs2v/AHfkqhfK/wArzPwv8Naxl7QiVMp3Duvzo6sn+0tQSagm3fvXdu/75qO8ZNron8Pzbaz5pvLYQvHubq1ax7mMvdmadvqG2TZs2/7Va1jNC0yTbPmXdtWuUjuE/g+Y/wAfz/erR028dWaabhm/i30qkZ/ZNqMpc51kd4jRD73zL8/yVp2V28i7/m/2K5a1vHZcfaeVb+Kt+xvnkXYEymz/AHdtcE480j16PwG7Y3H7lIX3KzffVf4q01Xd+837G/jrC0+RI4f9czMqfxVrqzttmKb2k+/8/wDDXFUjy1Tvpx5oRH6jv8xwj/M3/LSqM0KSYeZ1LfxstaMkflxh0TlV+f8Au7aZb2KTZ+7/AHvm+WrjGPLzGVaPNLlKNjpdzcSeXs2v93cv8NfR37F/wT8c+NvFEGm+FbDUJbvUH+z2Frb/AHpm/iZm/hWvPfgN8PdK8ReKLa28ScW8l0qXXkxbpI13fw/3mr9bf2PfhppXwX8ReGtN8E6Ds8U6t+/tbNYlZtPs2b5Wkb+Fm+9trspaR5pHzmaVpR9xH0H+xb+xxN4aWy0X4hIyS2sMcn2Wxtdm1v4tztX1xqXgHR9InGq6FoOlRyrtT9+NirGtW7m+h8PaNaLNrum2sypH9slu3Vd396vkj9sDTvGMHjU654b+K3iHWIb52ii0iws90FuzL8y/eXdU1ans/g948eNOEF757t4yfW7q6TT/AA3480uF5uWjtX8/5f4vl/8AHa+Y/iV+0J4t1rXLzwB4WezsVt7hotSvLho5ZY4938Kru27q8Z1j/htXRdaSGb4PyWMMcSwJqGpaktqs0e75VWOP5q9c+FPwtT4aabL8Zf2h5vD/AIV03T3kul0+GdYlvGX+Jmb99M1cs0tZTRp8UI8h618ENX8B/ADwq/xE+JesaXpStEy282pys99cf3fIg/i/4CtZfxX/AG2viRrGj3dt4e+G82g6LHZST/294y1KOxe+X+HyYvvbf/Hq8W8eftKab4km1T45eAPAOjldPX7Ra+KvGTyeRGv3VWDzP/HVjWvmvwn8L/id+358ebrxV8QvjHea9Bu83VLq4i8qK3hVf9XGv3YFqFWjiI8v2TWMOSBF8RP2rv2jf2kvGVh8Ovgno0d1At0yTrpO7yLfd96aaf7zf99VN8QPgj4X+Gug3MNnZ6TrHiG1tfN8Q65eSs0Fuu35reBd3zSbv4mr6o0XUv2Wvhr4btf2WvgD4n8O6Vbtpcl7418RTXSpLYwr8zbpP4V27vvV8Aftcf8ABTL4G+ItZ1z4W/steDFv/DmgyyW6eKryLdHqUzfKzRx/ek3N/wAtGq8PUw1P3Yamcqdf4pmb4ft/DfizWHudY8Q/aLOxSNbW1s3VPtU0jeXHDH/E3zV9DaHZ/B/Qdc1TwH4t+KOj6BD4Z01n8ZXlrL57WPy7vssP8LXDL8v+zXxF+yV4T+J2seP7b4weOUm03w7oPnaveX2oWvlx+csbeSqt93bu/hWvPbfxJYeB/tHifx/4wW+k1jV5tRvJrjd5V5IzM3/AqVatyRLp04y1Pr7xN+0xc3nhhrn4G/C6Pwx4Gs5WR/EmtQLJqWqNu+983yqu2qtr8cPj9ps1t42sPiLrmrWkL/8AINt5Y/L27flVo1+6teReHf20dB+I11Z6N4nnsYNKhg2263Vv+4X/ALZ1778MdN8T3Ghr4q+A8PhXUWk2xXWnwxL/AKU23dt2/e+7XPHFUZyvI19jP4Ynp/wE/bM8Q+PtV0/wl8WvBmkvZ3Hy+TfWCu8m5tv3tvy19Q+KvhP8OvAfwz1HR/gb9l8I61rE6y+I9U8P+W1zar95bVf+ee7/AJaba+SP2Vf2tvgtpPxkvfDf7VPwht/DF7oqSOt1b7mit1X7vyt975v/AEGu68I+IX+H/wATPEnir4S/Eu61zw94quJL2W61RV3t5n3lbd93/ZrnrYx0pNRl95pHCupvE83/AG6Pgbf6potr8QhbWaap4fZU1TyUXzLxZF/dyM22sz4O/EDXtL0uz0TU55prZv3kULP8sfy/xVteMNU8SX2g6rba3qTP9q3J++l3K0at8q/8BrzO6ute0nw/Ik0kMTKv+sX+7XFWzLnnHQ7KeWyjTlc+mfhT8dLDTPESWdzZ7HmuN3nLKqqsf8W3+9/wKvdv2jP2JfAv7QXwLur/AFXwBDcOsTXFlq1rdbZV3L/s1+YeqePPFWh61bX9hfw3Lx2qxRRtF8u3duavtX9hX9uLVbJYfDfjy/aIr8zTMjLEqt/Dt/u16VHHOjGM90eVWwvf3T8yv23P2Fde+BMlxrdhqtrcvCypFHbuy7l/4FXyheXyfMiQ43P/AOPf7Vf0Lftmfss6D+0loM3iHwr9lvrTWNNZLiOzg8z7LIvzed/s1/P58bvBupfDn4pa54DvIZPN02/ZXkm3KzLXppLER54ndleMqR/dT3OU1GRNzPNtfb8vy/xVi6goVfMfzMt97/arTvbibkbNyfd3L/DWXKuFKYZ/7rf7NdFPm5TqqSOf1BgrGbyWJb5flbb8tYt8qM3z8KvzVuXi+azpCnzf71Y99E8m5/vfLXfSlE82oY99N8/3G/uqtVPL27Xf5V3/AHau3C/KuWZf9mq0yQ/K6fN/vVtHmkc3MyrJDuYeYGw1WbVPLb5Pur9ymbdm59mf9n+7U0LOXZN9WLl6Fyz+7v35/h+avoXwCwPwNjdQCP7MuSB26yV8+Wscm1U/hWvoPwKiL8DESP7o0q5A/OSv3/6Pzi8/zO3/AEB1f/S6Z8vxQpLC0b/8/I/kzy7SW/eHZB937rV0ens6qif8865W1mm+V4X2j7u3ZW5p98lxgpuHyfxV/P0j6v4jrtLkdoVd3+Va27W8+yyfu3/365SxkfYER9oX73+1WzY3TtmF0Vx/vVEubYJfCdXpd1Cq8J8jLt3b60obx/MHkpvVk+VW/hrmIZP3WyF1XdV23a8WEJv2t/48tV8Jl8R00etQrGbN4Wf+/wDPtWoJtUhjZ28lsKv3V+ZayGuPL2feJ27XWq7fuWaaF5AVT7v96iMfcHzGhdX22AQ71+6v3k3VlaheOtw6QzRpudmVf4abdXTy/vn3bvvI396su4kmVnhmdWXZ/wCPURjIqO4Xk06xqj3O0/7PzVUa7dWaZPnLbqb5kM0n+sbCoy/8Cqm0z7QkE3zfxbaUonTT7kkkzxr5Lv8Ae/u0yS4RZhGjt9z5t1R3E3mbXeZS/wDB/eqhfSJN8m/crf3a55R5T1sLiOXliWbi4eFdjurq3zJurLvLpJZNjuqbv4v4aLqZFIfYu5f4d9VbibzI2R0VQv8Ad+7WPvfEe/DERlp2Lk1ujf6tPmqtteZlTZtrSuI/L+fyfvfwrVOSHbH5yJh1+ZN1ccpe4ehRwpEsL5+RNx/urVhfOlj+/hl/iWkt1QqzvNt2/wB1alt4/l+Tayqm/a3y1zSly7Hs4fB80S3Z2z3A2I8ibvmrX0+ZNrQyblDPs3f3ao2qutuod1X5PurV2zhhkhXem3/Zaufmi37xljMHyrSJqaeP9IML7WRfm8tW+9W1DJbKqzJbbX+6/wDdrH01ZoYwkzr81aFmyJI/ybF2fJt+aq5Ynzc4zpl+ymSSQ2xh2bv+ea1q2N15WbaRlVN21Gk+8tYcM/2dn+6V/h2t81XI7f5d+/Z8/wDe/irpo6SvI4pbnR299t/chN/ly/djqW6vNqy3ifJt/hj+ZvmrLsYX2k+czbf7v8VW7dnbdsRvlf72+vUo8nKcMoz+0RXM1tIrWzOz/P8A7rVRvgkn+pHzbtyRr8q1oXFucfaHTc0b7kVfm8yodQt3muEfYqrvX5VrsjU9y5lKMpFLznY5k2o3+9/FRDZodsiPs2/Kq1O1vtma58lnDfNupLO2SH9y77X+8rUpS7mPxTJJIXjZYZm2FkXZtp7W/lje6+Vu+XbJ/ep63DzBt6Nt/wDHqufZ0kVP3y3DMm/az/d/3q4MRW5Tpox5ijDa4YJbSeV/tKtaGnrCql79/nZ9u7/apI7V2vE8lGY/xqr/AC1qWtrMrHfNzI/7pdtfOYipOUuU+gwdPlhcks7FlVHfa8rPv2zVcuFmXc/kq7L9zy/4aSO2uVWGHzvM2/f+X7tXbK1vFs/n5/vLt27a4JSl9k9SnJc3vFCGF/MLvbK6tw1OjhSM+dclt33VX+Gp4YTFN5Nty7JuRWerkWm+dbvsTykZ9zbvvN/u1dKnGpImtW9nDUp2cdzJIkzuqxfdZf4lq3HClyzQpDsZWb5lX73+9V6ztTJIHhdQka7ZVkT5mqxDbzbm2PGy7P7nzLXpU8POM7Hl1sRDk5jMuLe5htwiJho/v7vmXbVnT7XzlRH5ZW3PtTa1aS2s/wA+/dtZV8ptny1bttHe6bz7aw81pk/eyb9tdTwv8xx/WusTPW3uWaVLZ1jRZd+3f8qrViPTb9o+LZmijf5G/wBnburetdGe7tfscPG2Jdv97/drXXw3Nb26IkOAy/eZNzLXSsLHdRM/rXN8RwF1ps0yvsT5Y/leP7jL/wDFVkX2ipNdLOkKhmib9238NenzeG7Zv3TpH8qfN5f3qzLzQUkLskKqFdfmb5fvVvHDm9Otyw5ZHnLabMzL9phjQr83mL81RSaS915MiPh9+9lX+9XXXXh+8aNkmgzF829Y/vNUP9i+Uod4VPybVjauiNPlloaxtKJxGrae7r5e/j7rf3qxrrzrWPfDCvyv+9Vq7XVtFuZLhPtKbfk+aSP+Gud1K3tmkeGZNw3L95fmZq05eYXw3sc5eSw7nm+5t/5Z/e21TC2yzM803yfxsr/d+WtXWrBLWMu8yjdKq/L95qw5LidmNtZpjd8yNs3Lt/ipc3MYVI8xorsaYIjsFZdrtG3yrU00z2tqyfaWX5v3W5d1ZNjdTmRfnUnd86/3quLI6xs/ktuZvvbvu/7NYSj3Ob3YxLcl5tWOZ0US/df/AGv/AImr9vrE0LCzS5xIv8P97/gVYT6lu2O6bl37mVU+7/s1ZhvIWjZ0Rvlfbt/hWvOqU48+ppGp1ibsl5ttw803zyRfe+9to/tGbyzvRd//ADzV/wD2asxrryl8uFMxKi/e+batIt5PNIzoiu0n32/hqKcZkylyml9teSUZ2/Lu3sv/AKDWhp826Fbl5vl/2nrEsbrzEKYVP+B/datHT4km8r7u/a21f9qvQor+8eXWlym7aq6ySSXjx7Pl2bf92rulxv5zO8OQvyfN92P/AGqxreby4wnn53ffj/i3f3q2bXfMhmeZn+dV+VNu6vWw8Tx8RKMtzqNN2MyR7/mb5U3fLXV6PcJayIkM3+sT7zfLXHaT5cl2kMj/ADr8sW7+KtPT75BhJ0j279vzfNXpxj7h4taUoyuei6PfutuJo327fl3N/FXZaDfzRq9zvwkm3+Hd/wABry/Q9WT7Lvk8tRG6q/8Ae/75rqtF1yCFnTfIFZPnkWiUfdsZ2vK56DDrTx3USfLtX76/+zVpLrUKqNjxzN97y933q4Gx8QWd0ws7l5GZYmaJlT5f+BVbtdSRo03vsZfkl21y1JfZO2jTkdd/aHlx+TNIy/L91azLy4huIQmxi0f3o1f5qzZNWSOMTWzsy/d3Mny1nT6xCsgRt2+RN/nN/D/tVxVKh306ZsaldQwsjvu+VN21UrC1bWJpM20L7E3/AHo1+Vay7jXZpF3vcs6qzeU3/wAVWbfeIPJhR0fcy/Knzbf++q5alSUTqjR5i1qGtfaIXtUfG7crfL827+9XM65rUPlmz+Vh93/a+VfvVW1bW9108LzKn8XzVx+vakjb0hmjcq/739781Ye0Oj2Mi1rXiKFY/J3ybt25/wDarivEHiqVXKbIx/003/e/2aXxBqCafGo2NnZ8is/y7q47WtYDN8m0fJ81OUhxiN1rxhc5lRHYfwq38TVx2veKnaRpprn5l/uvu207xBqiR7d6Sfxb23/LXL3nzM+z7uz5v4t1ZU4zNvhLdx4oiZSkLs26Xd+8/wDZav6Lqj3F0yXKZMf8MlchJ812s/kq7QvtTd/CtdBodvNEqJsUjdu3SJXVGUSJU+b3j07wveTRwo8L/N977tekeFNSmXbs+Z2271avK/ComWSFHdsyfM+1K9I8Nx3NvG03lqNvyqzP/rN1dlGXu2OGpH7R674dmSFrdneMBvlVY5Vb/gVdbpd4ke9HTftl/iavPdBW2WO32W643/dX5W3V2nh1o5ljmT/W/wAa13xlM46kTvdHuoZreF3Rv7rqvzNXXaTcJGqpvYM3/fVcJos0M0aw+aqlfmTctddpNxuuIneHO3+KH+9XbGp7M4KkZSO0028TyxysLbNqN/z021cjjSP5J9qyyPu8z+JmrE0nUobdPJmfeG3Mn95f95atS6reNH+5m3lk3NuX5q6Y+7DmRx++P1ib7PMnnTbCrbt38X+1XE65qiLcPD5y+W0rfM3zM1bWtaphl8x8yR/NXF61qkySMz2bbVX7y/wtWMvjNo+6c54hvIZP3MMPl+XKqtJt+9XJatcfbJEuRMrLs2qy/e21taxdPfTGZ/kXft3Mtc1qVxMzN8i+XIjN5jP91v7tcdTklM7afYxtWvnZtjvIzxqq7V+7/wABrmdajMe+8mSMvH/y0+9XTX0Xzb5rmPfJ8sTfdaub1y3EbJc3LrukRlSuaodcX0Od1K3RLVHeFQv977zf7tc9rESfJMkLPIzfwv8AK1dFqDfaoZPOKoNq/NH/AHv7u2sbWP3jh04/iVvuqteVW907aPvSOZuLVJ2aH7N80f3mVflqC1hSOQ+T97/vqrs2+aR32Kqf3qbHC8bZdG2fdZv9mvNlH3+Zno05cvumTfWoW1ab5tzfxVXgt/JhRHhYhX/ircuI0jUwp838SNVG6RJlV38vMasu3+7WkZ8ppL3irH+8X50jXa1T2dn5dxvKKwb+FvmWo/KePZNNDtb723+9WhZ3G+4T5I1RX2/7W6lKUzWnGHKXLdfleFIWLf3quy2bt/pKPwu1WWTa3/jtVtPV5lZPOb77N+8T+GrkbJeqHd9sjJ/Cn3qUacub3Sub3BGj8qT54WdPm/2qfHaJNIkwRmK/w7vmqT7NMER3tWUN/wAtGf5mWpd00zB4XULub5VX5mWiXuv3QjGcviOd8UpMlshljf5pMhpOo4PFXfDMbyaPEyAvt3bkIwD8x4zTfHlu0dukjBhmbADdhg1J4VEg0eMx7SrbldWbp8x+av6JzOX/ABzVgX/1Gv8AKsfEYSMv9eaq/wCnX6xLF5cOsLQunzr9xWbcyrWTqTedbsXferfeb+9W55OyZ/OhYf3l/iasfVId0jxQ/IP7v96v5urS5fhPvafvROb1Q3MkbQxPllf7qy/K1Zd19sXfNNbKi/edY33Vp6pZ+TcPK8bAxrt+Wsy4swzNcvNj5drqvy1MZd5FmXqUgZWh2Rr/AA7f9mqckbq2zfuDLWnJCl1GqfKi/d3f7NVprH7PC6F9+37m5K0p1oxM6mH5pcyMTUm3QpCnl42fLHt/2vvVnXi+YzQptzv+etfUo3Vd8P8Asrtasm4WaGOVM7XZ927/AGa9CnKMYHn1qfNMxLxbaOTf53z/AMfyVj6hM8OUhT5v42ati+mSMmb5f+BfeasTU5IWmPyf71dlM46kffIXmghb948hZqv2lxdSS73fafu7dlZcnzSM6Mv+7VvT43abYjtirlHmLidJp8x8nCPuZU+Rq29Lm8yPejybvvfNWFocZkZtm3d/Durp9G0+Zo9kz4DP95a5alPlPVo/Cauj28O3f97b83+Vrct7e8upopkZvKZP3X7rbVPS7SH/AFaIqt/C33a39Jh8s/PM0Y+6i/e21xy/vHo04y90W1gSRhC7sVV/n3LWx4b8Ow6pqn2OG2812X96u/8Ah/vUltYzLlN2du35dn8VdP4R0V7jWIkSHdJ/Bt/h3Vj7OMtDepGUYcx9LfsSfCPQ7PXh4z1uHzks2V0j2btzKvy1+kv7I/gG58M3l78ZvEk1q+pak/8AoG394/l7flZl/hWvlj/gnX8HbnWNF0rw09neL9uumkv5JIv9XH/F8392vv8A8Ta54Y+DfhWbUrDR45/7Pt/K0izZNq3EjfLHupy933WfAYytKtiJHQ/DvR5taW+v/ipqun6hM0rS28c1r/x6x/eXd/8AFVyH7Uv7UHw1+HujppuleNrLVJpNv2eObTvOVf73lsv/AKFXmfiv4vfFGbwvfeErDwrFaalqzRvrmrTS/ejZf9TGteQ/Er4e6xqkc3iq5spNVvLHTmVI5HVEjX/0FVrzpSryjLk0HSo0nK0jxv8AaQ/4KJfFSz1B9fufFXnW1jcMujaParukVm/5aMzfNXz54u/ay8Q+Jr+2+Inxgvbq5VZd0VjfXTMsn+ztZvu/7tQ/GzWNW/4SLUbDwveQski+VdXEMW5d38Sxs1eBeM9D1LxV4kgbUryS4trOJVt45v4m/wB2ua1OPX3j16GFlLSJ7Pr37WHxv/ao8Zab4Amv7qz8P28X2eK3ht12WNr/ANM1+6rN/eavU/jx+1f4k+GfgW1+An7NOsTaZGsUK3sdvErXN5Mv+smnn/u/7NeC+B7XUPh94fi8K+HvLTUtS3PdXn3Wjj/hWi80NNNs/wCxNH3TXV1K0t/fbtzM275VVqa5doy9fM0+q81W3Kc98RPEHxO+IHh2X4XaU9xHp91debr1xZu32nWJm/56t95o1+7tr0H4U/AfwN+zX4a0bx5+0Civb3l15uk+G43XzLpY/m+b+7H/ALVd/wCHfGHhX9m34Lz+NrzQdFtNXVY/st5rHzPcTfwxwL/F/tV8VfF74nfFH4/+LpPH/wASPGV1rF5MrRW//LKKOP8A55xxr8qrWyqwWkIjjg6taf8Adieu/Hb9u74kfFTXNZv9S1jTRbSW7W+jeF9Li2abp8O75dyr/rG21826hq2q+JtS+3+M9Vjd1+XzFT5Y1/uqv8K1u6L8O9Vb/Q0tlQSfNt2bdtaVj8EdVa68l0Z/n+6q0pVoSleTO2GVy25R/gzQ5ry1TUvD3i23dFXakPlfxV6p8J5viXBrEF54P1JtL1K1iZPOsZWXzG/hZv7tP+CP7Ob3l5aXOpWEkcLSruXft+X/AHa/RX4A/sp+Bv8AhHYrm9s40TZv/eIqs3+03+zXjYvEUHKMGerg8jqSi5HgHwr+Dvir4jfufiFD/aV/977ZNLvdmb7y/wC7X2B8KfgTZ2/hmG2uU+8nyR7PlZV+X7v92uv+H/wj0Twz4ia80rSo1ibb8qrXunh2x0m3+z6VNo8Jjj+XcsW1trf7VcVSpGU79D06eUQoxPmfxZ8Bb/VrNrO20T5V/iVPl/75ryDx98K5vCLF7zTJpVaXYjRwV+kE/hjR7CAXMIC7l7V5r8YvgX4e+ImivZw2/ksrs7eW/wAzf8CrGpGMpB/Z/NGXKflj468B39ncfbNNtmeLeqt5zfNt3V9KfsE2/wAL9Y8TRWfi3xa1m821fs7Rb9q1V/aE+Btz4LuhDDDIyruf5U3LWn+w3a6DN8TrHR9ZtoYpbqVVt5Gi+ab/AGf9mu7BVve9nc+QzLB+z5mj6J/aUs/FXwN0mP4hfByaaK0jgkS802F9kd5G33m+avyp/wCCvGg+FfjBryfF3RPD1vomqrp0fn2tvFt+1L/e3f3q/bv9qf8AZu1fxv8ABvyILxR9hXz4po2zuj2/davxq/4KUeB5tJ+F+peJ32xTWN0sUscyfMy/7NfSxjOMoyjpE+bw1Tlr8sviPzNWN23o7sz7tr7qqSW8xhMJfHl/3a1rhkkb+EO38NQTRosnCKdv32r2acoch7NSPuHOXFn5e7YmNv8AFt+9WJfWrs+xONtdlcQ+c2zYuW/vf3ax9S03y8v5PLfwrW1OWvMjllT7HH38e19rj+CqfkeYT8nH96uhvNJSSQfuV+Ws64i2syZ+St4ynI5pR5TJj2LtTvTo4/LX/aX+JaszQ/x7NrbvvU37Om75+q10c5lGJLbq/wAu923NX0F4HwnwKXb0Gl3WPzkr57hb5th5+SvoPwIc/AdP+wVddfrJX759Hv8A5H2Zf9gdX/0umfM8VW+q0bf8/I/kzx3S7jy2CO/LVt6eztIEG4GRvvLXN2quzeenD7tu2t7T5vKZXd/upX4Hy8x9SdNp6wtIU+bb/FW/ayJHGiJtRt/yMv3q5bT1ebY/nMp+9tWtixunjZn6lv8Ax6p+Ej7B0dndbpvsqQthf9n5q0IZoWheZEwfu7ZPlasmzby5FR92+P761ft5Iflc7tzPu/3qPiIkaFrH5arvO4sm7d/8VSyLN5bpK+G+8lRR3Pnb0ysTK6/u9v8ADRPJ+6MKPubZ87M9axj9oz+Io3kTrx57KrJt+X+Gsy6VPKlhdGf5PkbdtrTvNjSF33bv+Wu2qV1D83yJlP738VX9kIy5ZGPJInmMkw2/w1Wlh+YhNyr/ABbq0riHcwRI9rLVCdkj3vNtX5v++qxlGRvTKy/Myw+ZtC/cpkwSNvJd/m+8sbUqs8BZPL3Df92opJNzHKfxfMzVEqZ2Uans/eM68kf5t/y/Ju+5VUyWzMUfcf4anvAfLO9Gyz7vmaqFxJ1D/wD7VRy/ZPTjijrbpZvtC7E2tv8AnqnNsjkjeZGY7v4a0763mVd77iyvtDbaq3Bdm+RGbcnybXr532kfhP1bD4bljqVo97SO7ovzfc21PDHGsY844H+/UbKkeUQbX/gX+7T7eZ/O3/M7/d+WspSmelToxiaVnvkkCPDj/a/2avxwpIo8zp91t1ZsN5HGyjfvLfL9yr8Mnlyb33Ouz+GuSXPz8xliqPNDlL8LSSwjYm0Kn9+r8bQwx+dsbb/Hu/vf3ax/tLj/AEl3/wC+amtbhNv2nZlmf5lZtv8AwKuulGT+I+Ix1P2cpXNmORFb5I/m/g+T71alrcPcRxwukn7z51bZ8tc9ZXSN/wAvOW37Vres5nhjieZPutuTdXTzHhcpqw3m+NUd/m+66xvWharC23fA3lRpudWf/vmsaxk8xmS2RV3ffkjq1HNIzedM7IVX/ln827/ZauqjUlKPKZyjH4i/JM/yfuW2N8z/AD1HNfQMpQwqrNu3tmqc2pTMvkzOo2/Lt/8Aiahb5m2ed/2zaunmMpR5veJ45HjYR7MJs+WmKyLIN/P8Lf3arrNHNuudrfc+7937tIt9tVZkRl/i2yfd+alUqcpEafKaljHbXHzu+wt83ltVmNfO3Daq7X+bd/FWXDdQrIiefvVU+Zt/8X8VX1khmjR5HwY/m/2q8vEVJTkjro0YxiatlZzTzJsGxPm+6n8Va+n25jX77MI/733qzdL1BGzNNM0m5vl3Ptb7tXodSh3LGjqP76/eZf8AgVeXU5va8p6tOpTjS0ZqW8flt5yS7mb7/wC9+Wm3k1zCvkwfMm5d/wDEzVFa3ly25NjCSaJl+VP4aXzHkkQOmyRV2pM1RTp8tX3jr9pTlSJrSR123KJHnd97+FVrVs7R7qTG/ezP/F/CtUrFftkiIqNEi/N5a/LurobOG0kX7n735d/lvtavTw+Hj8UTy8RiuX3V8Iyz0vzsbIfL2y/w/wDLSrUOk+XIyTTMoX5vL2fdq/Z6f9ojLzDhfm2/3av2tjiZJra2zHI/3t/3a9Wjhzx6mIiZX9k3M8Idx977lbum6S0NvHN9jk8rftRo23Vpabo6Qq8LvvRW+9u3ba3vDvhl7eHGzcGl+9v212xw8eqOGpWlze6Z+l+HduHSZnSSXav+z/vVuWugrJCts7+Xu/1Tf3mrotN8M20dvDsff/E61sabovnZfZCH/wCWW35vLraVElYiUXynA33hdIfKmS1wd3+sWsXV/DLtcGEw+av8TMlerTaDtuHR08wt9/c3y1ka94b8u6jmX5GZfu/3qI0eU7Fiux5LeaC/mN9mtoXSNV3K27dG1c/faS8dqZprZl2v937275q9lvPDrx2/7m22t83m/wDTRf8AarmLzw3C0Jm2bS25nj20/ZRO2niOaPKeW61psM0mxOi7tzL/AAr/AA1xniLTfJlZ35Vvl/3a9a1Tw7Z+S77Gh/uqyVwnirTUjXY77PJfbFu/iVazlGJv7Znm+tW+6M7Nv3t25lrmbib/AEoQ7Nm1vmXfXWeKIdkm+GeQP/B/dridWX92ZC65X5naub2YpVIDVvIrNt6Q/PG+3cvzbqcuqTK7RzP838G5/vLWM19DuZPO4/75+WoG1ZLm4+T+H77Vny8xzSqcp0cN/D5ion3f4mqaHUJtrJ8qbvv/ADVzFtriR7t+523/AMNWV1KONf8AXfIyfO33ty1jyy5uYj2nLDlOh+3JHGts7sDs3blp7ah8ru87Mq/O38Nc9/bSSfcfD/ei+Wov7YeRfv73b5n21UacZbHN7b3DrI9Sht7f7S7tIkjr8qpWjDqDzfInmDavzNH91a4m11hFAhR8RfeXd/eq9Z6o63KQu+9JPlZd+2umjR5fhOCtW5vhPQdM1L5Q7yMSv+192uisdSh3Q/P8jfw15/o15D5e93j3q/3t9a1jrCed8kzbm+Zd1etSjGMTzKkjuU1iaOJ97q67NsW3727dWiurQ2sL7LmOV1+5tT+LdXDRa8LNUsE3fL827+9VmPWPLVEjfcGbb8z7m3V1nmSjLm5j07T/ABA95h/OVtv32b5f/Ha1rXXrby2eObDM251bd8rV5lpfiJJAHTd5q/L937tbFjriSMm/l433/M9ZSl9o1onpkOuTND5kO4bn27W+bd8taVr4jh3HzJtrtt3rv+9/tba860nXHLBIZmVW/vN92rs2uJDI77N22Lbub+KuKpU5fiPTp0Tu5vEnmMESaSJl/wBarN8qtWVdeIrm1kaGbc7/AO98u2uSXxJujRI0k2x/+g1DcatM0bJ50exV3bWf5mWvLrVoxZ6dHDykdJc+KH27PlPmfcX/AGaxdQ8VbreVEhUfP8rN8zVztxq0zW+93U7XZm+b+H+7VG4vgvzpcsit96Nq4ZYjml8R6EcPKMro0bzVJriPzoX2iR9u7733a57VtWS3t5Jntm2fdeSP7zf7v+zULXk0dwz202EXd8sf3WrC1y8mkVIZnZBu+Ta//jtZ838pvGj9qRS17WJm+/Nv+bburlNS1Z5Y5diMv/j26tbVpHuPnRMBXrnr7zrfLvLv3fM0a1tGXNKzMPY8vvGVqFx9qjCO7O392s2HTbiRn2Orf7X93/ZrTuNk0mNm3b833vvU+1t3aHY6MV3feVPvVftOWARp++ZcOlu0h7P/ALNbWg6VM0jJ8zn7tS2unO2TsUbv7y1t6fp9ssUWyH/Z3NRTrQ5zSphzf8L2e5tiIyMsSrt/vV6JoNu9va7N8YSH5laNPutXGeGdPRlHmSNvb78m/wDirudBhRtqJ9xfl3K/zbq9GjI8ytT5YHbeG1haNIft6ru+fcyV2GjqbO4hRPusn8KVxmgvDbx7A+5dn3l/i211FndExr88iK3zbl/h/wCA16FOUuU4KlM7bSL5AqInlhm/h/irpNH1KB4xseRG/h+fburz/SNWgmtxNs+T5vmaL5t1bel6skapawozeX9xl/hWu2EeY86psei2t49q2Y/3Qm+Xcv8AC1PbVvIWW5huYVeP5f8Aa+auVt9YSRUKXMjBv4Wb+7Uq64nmfPcrtk+ba1dsfgODl973TR1a8R7co+3/AID/ABVymsXUNsJfnV/M+by6uXV79oVpp7nIXczMz/L/APs1zGuasjSedtjQeV/Eu5t1ZS2NYxkZWoTvE3z7VG75Y13fdrB1GT+/5fzMzyrV/UL7dIsKTM/z/e3/AHf96se4+zKu+aRoplfb5it96uKp/eOyMp8uhkahJJMyzXjthYvvRt/q2rndY1KGSPe8zfKmyXcjL81a+tXzx3my5mV9vy+ZG3yr/d3VyHiTWHjtxCX80qjfuWf7u6uT0Oml1uV55UaOTyHxt+4zfd3VgatfQtIRNMyM3yoq/MrU281jc2zfI6/edlXdtrPutQhnnaMvGNv8VebiJRp/Ed1Hk+ESOaaRmRIPNRV+fd8vy1PKE2B/lT+Lav3azY7hHkbe6hW/h/2q0rVkmmCO+/bFt2q/yr/tV5tT3vePQjGIm1JP3MPzPsql+8aMu8ca7n+Xau5ttWZpIWSb7NIzpG/8Py7qgaOGNjm4X+Jn2/erOn15joj7w2PyWhO196L/AHl+9SR2zrIPOhkRWbduk/hqzptqjM2fl/3qnjRIbj5Hwsn393/LRq1jKXNobcvNDUmtFSGxfyUZ0Vtz7qms403bHfYrLuTy1/8AHajt490Ozqy/w7/lq5FawsqQv8iqnzbfvUe05QjTkx1v5K6fHbI6lvveXI3zbanj/eXiQpZ4bbt8xW/hplmttbfPMiqy/wDPRPvK1WY/MVYfsybfM+XzqiMvisVy/aOe8eCIWEWA+8T4JPQ8Gn+FrYSaApCKxZmG0nGeTS/ENI10+BlBBM2Tg5DcH5ql8LIf+Edt5i/Cu6n5M43MRX9E5i/+OaMC/wDqNf5Vj4bDxlLjuqv+nS/OJcjtfLjSzmf+P+L5dtZusQ7W+dFz/wCy1rM3zLN+8aVfvbV3Ky/7VZl9byxy7/mZF+X7u1a/m6c+bmTP0CjGMfdOX1LT3j3J8q+Y23c3zbazZrdJmOx9q/8APRvu7q6PVrOOPqn+5WfNaw+Y0dtCy7v4V/vVz+1jHU7I4eUjDktdqsj2y7W+/u/iqjdF1kELvsZvuLWzM1ssi4h8z+Fl/iX/AHqx9Slto498LsCvzJ/FV0Z2qfCTKjyxMnUlhkZ/3Pzrz8v8Nc9qLusjoT8q/Ntre1Kb5d6FdzfNuX/2aue1e4G1+cMyfKzfdr1cPscFamc/eeY0m903Vk3DMu5Nn3v4m/hrS1BHVHmR96r/AA7/AOKsy6Z49zzD7yV6lP3tDx6lP3iuv7y4GXxt+X/gNaukxjzAdjfL8u2s2HzppE2IpZfv7a6LR7TH0k/2K6eX3AoxnKRuaTY+Zz91lb51311Wh6alxh/Jyqtja1Yuj2MMq/P/ABNtRq7LQ9PRQzoF3su2uSp2Z7NGnLm94taXYJIz7Jox8+1d396uo03R3t40+T7ybk3Lu21U8O24hVHuY42C/LuaursLNJGeSG5Vwu371cdSMviPVp06UoxSIdJ0vzlKQWzZaL7y/wB6vTPgL4RTVvF1vbarcsF3LvuPu7VrlNNsvs9w7xzMjfcX5Pl3V7t+yH8Kdb8eeKrObw9psd+qyr5sbNt+bd/49SjyuIsdGMcLJn63fslfCnTfhn8M9Fhtt11ealYK1ksi/dVvmbc1a3jCR/HXjxJrC2W80vw2uy1t7dflvNQb+KT/AGY64z4B/GrxPr3iSX4bw2bRTaTprRMy/wDLuu3a23/aavor4V+EfC+l+GYbCwij8xZWluJPvMzfeZq4ZfvJXkfm1TmTkecaH+zXqUMK6r4kuWurjZJcavM3+qWRm+WOPd/CtfOv7XHg3xffeZ8PdKS3e0V1a40/T0by4dzfL50i/wCsZv7v3a+pP2hPihfa3pkHgfwELz7TJPsc2qfKq/d3N/eavNP2yviZ4X/Zn+FdvpujpanxU1kqxQ7/ADPscjK26Zl/ik/u/wB2pcqUaUux14WjJ1Y23PzF+NHw1fwnqc2j6wlvc6u27zYYdq/ZY/8AaVflVv8AZrwfQPhbqsesQPc7oVkn/wBKaT5mVf8AZr6Asde1jVlkfWNqT3lw0k7SLuZt3+1WFdQ/bL6PRLZ9s3m7p5GT7v8Au18zUxUb/Cff4XKp0sPzSOG8ReD31LVp9VtrKOCGHbEn95o9vzNWXH4ksPDOpedc6Vbulv8AM9vJ8u5tvy16ffR2Gg+GNcM0LNPHbtsZv4m/urXjuraD4w8YaPNrdtpUcDzJ/q2l3NRTqe295GFHD8rPFfjN4n+JHxs8fXHjDxPMrrG/labar8sFnGv8Ma/w7v4mrJ0nwb4jjeNzbbQr/wASfLXqeh/BPx/dQvLeWcaeTLtbzJfutXVWP7OnxLa1iubDSlvN27etvcbtu3+GuytWUYxszrwuFlN3ZyXgHwHrG6PUnsJLiXf8ixsvzf71dz4ms7PSbVNWTRJoZFXdLuT7v/Aqs+G/CPxF0HVPJuvCV1Ckaf6vyt3/AHzXbeLNc8PSeF9mvI1u+1fNt7hdu3dXkV60eY96jho8vMjG+Hfj/RLPZDdOqJvVtrf+y197fsq64niSzttHs5GRJFVXkuNrfL/DXwVefDvwlrek22q6PeKrb9yfZ/ut/u19c/sW69NHYpHaz73j2/65Nrf7tcWIlC8ZI9HDxk4ODR9oy6f4V8K2v9raxc/Ovyuyru8yrfgnxFpXxC8THR9NtpmSHarbl2/7tLrz/wBueC7O51Wa1/corS7W2szUnwduNE0fxBHrH9rWse1GdI2l/hrrhUpR/wAJ59aM40pOMdT3C3+ErahYJME2jb8q1z3jH4ZX2h28dwEZQflfbXe+AvH1nr0YRNRt2QNtVVrU8Y+VdWi52sv8VezLD4CvheeB8XTzXM8NjuSZ8XftLfDt9W0GV/s3zQxMySf/ABVfM/wL/sTw/wDFizfWP3bR3m2KZf4W3V+gXjLwrYeLBLY3kONu77v3q8H8J/sg6Va+ML6G5huJ7aa63wXG3b5bbvlWvKwsYxq6HTnvLUpRmfY8sFs3w1Gia9erPFc2G2O4X7rLtr8Y/wDgrH8OdH1r/hJtBvHmj0rS9LmuEkjZv3l196FW/wBmv168HxXXw98DXPg/xaZLqKFvLtXX5l8vbX53f8FhvhbPefBPxP4h8K3Mj28dr57+W25/vfN8tfTRl70YHwE5R9vc/A1bgyeWLnb5zLtlb/apmxPL8t9u/f8Aw1q32n/Zd0Lph/mb7vzbt1Vm01pCuzcImb59yfNXrxlCHus91c1SBmXHkzts8vb/ALv8NZl1ZIscjojE/eT563pLVPMXy9q/7TLVW6tULMjuqhv+WmynGUByp8u5zc1r5yurouP9l6ytQ02G3yPvfP8Axf3a6ubTfJhaHZ8zL95VrMuNNmWNt8LN8+2tqdSUtTkqR+ycvcW8Ebl/J/i+7VS4jh3O+yt660/c2x3+78u2s25gSNm37lWuuMuY5uVGa0fzb06fx19AeAiT8AlKEA/2TdY/OSvBpkTdvRGJ+7tr3nwCv/FglXp/xKbr+clf0F9Ht3z/ADP/ALA6v/pdM+T4q/3Wj/18j+TPDobh2k+/kVt6bceXsSbpJWDD93+JSr1p6fI7LsZ2/wBla/Az606nR7pG3Ij4b+Bv4q3be4dZFh2bd3365PS5jby70+at6zm8xld+N33m/u1Hvi5eaZ0lpeJ5ex0+Zflf5/vLWlY3HybEhX5X/irBt5odvlnblm+T/arV0uZ5GMb+YrbvvVUZR+IxlGZsW7fu980fyL8qyfxVDJcTNIzpHx97cyfeamLJJvUbG37P++aWS4f54TuRd38PzfNWkfegY/COlmmkjKJu2qv3lT/0Kq8sSNtD/wDAqnjeZmZPlcbd3l/xNTo13fJD8lVGXMTy/aMya2ht13onys/8P8VZ11DDveR7aMf3a3Ly3RbVX2KNy7k21l3S/KuwMy/eqZSNY8hiXEKMxdD/AN9VnXUnmKeJBDG672/vVu3Vu6hnztDfN/s1j3Vv5iv3/wB2p5uY6Iy5TMvJt/z+Zk7KyLq6DfO+13X+7/drT1CNI1Pk7ht+V/k27f8AZrEvl2ybIX2n+9UcseY15pHq95a/Z5N6bniX5d1Zs1ukzNs2hf4K3Li3RR5x3EfKm1v4aqNawyR/wjd/dWvj5S+0f0HGPN8Jkx2LsyzO+4L9+pVtUkkZ4YWUr83y1aNm/nEp833fmp/kTQtEnkszs7K7fw1h7TmOuPJGBXVnhVEfbhv/AB6pLeZ4pDsTaF/vfNtpy+cY8uin/P3qZuRsw/x/3qcfe92RwYqUeX3SeG4uWj/czR7NjbP7zVbh2SWzWyOz/wAX+1tqhG32dsTfNu/8dqa1vntG3u/C/wDLT+7XdH4bI+HzDl5/eNO1khhXyURm/h+7Wvp6vJB86Z/u/PtrHtZn3K+9f95auW+oTeY+ybAkTajKvy1q4+7oeBL3Zm3psifKmxUbd8zL/FUyzTSRyP5y7l/i/wCei/7NZ1v+7s/vtv2bkbb96rgTy4PMmuf4PmVkrSEuXUjl+yPhkSOF0hjYJs+6z1XkuPmTzmLHf8lOk37n+zOsRb+Fqpy+dJI7pMu3ytrwtXTz/aMZFm41BJZPJd9rf7P3VqBbyC8kCbGHzbV/e/LVZm2yOioqKq/MzfxUyO8Tdvk8vey/I33VrnlLnHE2PtSW/wC5SRf3b/IrL95qv6fcfOPnjYf7KfMtc+t+9xIiOiq+35mjerFtNCsium4ts3bmrjnzcvmdMfd9Dq9Nm/efvpl+X+9WnHqUyswRF37Nz7q5/S22pw+8t9/cn3a1IWT/AJbdd+7dXFzc07yOmMZRgblrfIYVCCRd3y+Yv8P+7VlZkmjXyUbYvybvN+9/tVl2siR/PsU7V2xMu5m21diZNi77Nh/Cnz7d1dVGnzS94ipUjGJsaSzTKk3nKzx7V+b73y112g26TK7+S3nb/l2/3Wrj9Nb5lRIVTc/ysqfLXbeH186TyERkdlXf5de5hafunhYqpKMrHQ6PpryM292+X5WZfu10Ok6TtaObZsRl3f7LVR0G13W8XnJhof8Anm9dJYqjOH/dq6/LtV69SnGMfhOGpU5S7pOg/Kzw7UEnzbti10ul+H/ssinyVlLRfKu/7tN8N2Plxsjwx/Kvyxt95q6jS9NnuG86OFUVV2stdEYxicnORaTpMMONkKvu+5tfd838Vb0Ph9PMTybZWfZuiZ/l21e0uGGJUdId0i/3V+Zv71akaso8nyZA/lf6tkquVB7TlOdvNFT7Q++PZ/e+Suf17T/JvBDN8vnfNt/vV3lxs8tXmRnfY2/+7XMa5a20MoTYxTbu3N92o+2ac3McjqlmkO7zrnanlb/9r/drltXjhmuGvPK+RU/dSN97/gVdlqdm6yIicwyP88irXL+II3Wc7N26T5WZvu/LS5ZbnXTnyzOF16NJofkh2qyfxfLurzPxtHbWsbzWsKlfN+bbXqOuNbXG97x2xGzfN92vKPGC/wClOrurbv4furUy5OU6KdSZ5p4wjm+z/u5ox8+75fvba4bXpN26Hz9qKm7/AHq7PxVcJceZsf51Rt235q8x8UXT+YUD81ycs6htLERUfeMjVNW+/s+8vy/LWTcatHNG9yZtjb9u7dVbWr19+9Nv+8tYdxqT7tjv93+9Vcv8pw1sR7SJ1ttrgXaIX2uvzbv4ambWtzfu32/+zVxUGrOu5N/yt/E1XrfUPMb5Ztm35vmqfZwMfbSOrbWNmHR9xZKPticOnX+Pa1cyupGJW/j21It8kkvyO396iMeWRlKpKXunT295tkaaF/3i/K27+GtG31LcyXTuu5f+BVyNnqkLR7t//Av9qrtnqU0jrsfZ/st8u6tox98zO90/WpFZJvvL/d21qNrXnR7xcsy/d+7t2tXE2OoOFVJn+dvmrRt9Wmwybtqf3q6onJ8R2dv4hebGzy2Kr8zN91alXxEgZtn31++v93/ark4dQmj2wx/8BkX7tWo2T5fs02xv4l/vLWvoYezO20vWJpIlhmn3Iy7dq/K3+9W1Z60+5Id8j/xf3l/2a4axm8xVd7xt+za7N91a27GO8SFHtpvN3OrMzL/DXHUqcp1Uaceh3Nnq0Mdv9pTl/wCJV+bbVpdcmkhE3zP8+3/e3Vy1jdXMP/Hsn3k3My/e/wC+a0LXUoY4Q6Pth/jZv71eViKnLG57GFo80rcpsXniBI28mHdtj4dv4qp3GsPax73mwsj/AHW/vVlNeedN9pR12bmXb/eqFmSSze2m+QRt8m3+9Xj1sRzRPew+F940/wC0nvM/aY9vl/LEq/db/eqBtUmk2+dt+X+9/wAs/wD4qqa3TtEHRF2K/wC9X/Zpk135jLDD8y7PkbZXFTqHdGjH7I+S6e4hlmd2+ZNvy1hXjeY3k/NFu/vfN81aM1xciNrbeoRvuM38VZF437nZvZWb5d3+zW9Op7TRGFSjGO5nalvh/c9t7fKz/dWsi6jubj5EhZkX+H+Jq0Lq4haFN37359vzVVuL5Y5PJhh8o7drbv71dnNKMbo5OX3jN+w7mZETDbdvzJVuz4h/8d+WmLNumKfLLuX7qt8y1LCz29wvz7dv3KiU+XQdOmXrVYd68qv+9Whp/wC7lXf91aydzySMkyfd/wDHa2NBvE8vyX86UR7t7SJ96iEZR941lH2mh1Gg3CeWqOjMytu3L92us0G8kEzSJ8zt9xdvy1w+m3CRsiO+FX5v9qulsdSfcqb5BL8uxo2X7teth6nvHlVqfu8p32jyW32dnR2fc+1IfN2rH/tVu6bqU0bLc+dvZU+638VcNpWpeZGZndlddv7tk3f8BrZ0+68tSiTLt+b/AGa9GnUPMqUeU7C11TzLP/XNHtfa6yL/ABf7Na9rql5BGLyzmZ3X5ZVaLaq1xUOp7YRP8rNH8rKz7tv+9TrPWpmmMgueflVmavRpy7nnVqfMehQ+JYYGiSF2BZWb5U+9TY/E/wBo/co6/vH/AIf4lrhm8SPau8Fs/wAv8bN/6CtRyeLIVKp5zIi/c212x5JbHnyjCMzt5tcha3+0wuwHzDyf9qsHWNcKwrv4LN/rFf5q5ubxTt3PZ/L8+12kl+VazJPFMLQypczL5yttZf4WqKkeXQn35e8bN3rCSF9m5wu3d/eb/arG1nWHt9m918z/AJa7X+XbWDdeKoLd3tkuY1dv4f4qwb7xJNcRs29VWNfnbdXHUjzS0OmnL3TZ1rxBDZxzTPMpMb/wt96uH8Q65NJNIm/5d+5JG+bduqvrXipJA7zbd7fMzLXJ6x4iLTeSgXZ95Pm+Za4Kn8p2R5ZG7ca1bWcO/wC072b/AJZr/wCy1lXmreYwKbfmesSbUt0iP52V/utVaa4d5GeF4/3jfe3VwVI+0+I6oyOot7vCrNvUs3935at2upSR/Pv2H727+8tcnb6hMsSp5O75/k+ap5NUmtso823au75vvbq4pU+WHunoU6kfdubsmqpNG/3mZn2tu+X5akt9TRl85LaP5v4V/wDZq59tYmbbsmVPM+ZN1Ph1h2kjdE2uv3tz7VaueVSXL8J3U5cstTr7XUJpF+eFU3P8zL96tKC8to5FdE3bf+BVytjrkPmK8lyuxn/1ez5qurrGI3k2Kqr91v71RHmkdR0McieZEiIx+X7rf3av7XF0mz7mz7u/5lb+9WHZ6l5m3e64VPnZqv2OqQ3Fx9mKMjMvyNt+78tIcfe3NSH7N5beY8Y3IuxZPmq1DB5KiFHV9qMrrs+7/u1kW7eXsh+Ur8rfMu6tRmSCPY6NtX5m+f5f9mnU934SY0+b4jB+INnHBpUE6BhvuPus2exqfwcC/hyIcAoZG+71XJqD4iXEc9hCIVICzDcC2cHaaueBo418Nq8l2yFt+wr/AAfMea/obN6nJ9GPAt/9Br/9JrHxmDpf8bBqxjt7JfnEuGOGG1eTyZlZv4ahuo/Oj2O7fL8u5fmVmq7JcTXlvEibmCrt8xvl2/7VULpn8vyIdyovzIyv/wB9V/MVStKofptHDwpmJfW7yN++mYJH8u1fmrKu43juH43eX/qtv/s1dDNGkMj3f3127fl/irB1S2maHe4UFmXcv+1/DUxqR5uVs9Knh+aPwnPahcStI3yLEFdlZv8AZrEvJvJcK7rlv4v4a6DUbd9siFPn3Y+b+Gud1SNG4fam35d396u+jKIVMJHcxNYuHkU28O1FZ/nZn+9WJqG9lO91yvy7v4a1tUj+RSk3CttRv7tYt80W0b/mf7rt/DXqUfePJxWDlze6Y9621W8m2+Rfldo6zbxUKf7X8NaszOu/Zt2Mv3ay5kTzN7/wt92vUpxPGq4PlkJpsO1m8na3z/drqNBt3bKO8jbU+T5PurWNp8LxOHdF+5822up8P2+6NneZiNn9yuqMveJjhffN3RrfyVRH+ct9z567fQ7dJoWfZt2/fVa5vw/bzBUdNo2/xbK7fQ7V22cLu/2v/QqitL3eY9bC0YyNXS7C28uNO0kW7ayfMtdPpOlzQs29FUTJ/rP/AGWsrRVRrhIbZ/nZdrt975a6nQ7K5jZ0mdnKuuxl/u1wy5pHpYfDxuW7Wz8uT7NvXbu2+Wr/AC7v96voH9kHxFJ4J8YWF/DD9qm+0bYo/urH/tV4lZWtncFJraHJb+9/6FXqf7PsepL4utnsNrr5qruaJtqtuWsqnukZph+bByR+qHwt8P8AhXwH4J1fx/pVzu1TVnkuLq4aLaqq38K/3mrtPC3jLXvD/hV9X+2NuktVSKFl+bay/M1efaV421jR/Bcem+JIbdri8e3idtv7tY2+9tX+7VTxN8QLZtSuNH0S/jdI7jyvJhb5o/lrzalTm90/M40/3vvFfxB8dH8B6tHqWiQefrC3Xm/bJpf3dvGq/wDPP+Jq+Iv2lv2gfEPxK1S/8bTX807SalJceZI3+s/h+avW/jnrl5Z3+tXM20Q2dqyovm/6xtvzbWr5N+IF5/a0dlYQxNGn+tiVfu7a8zFwhrzyPosnpxqVYmTDrfie+me5S5kKt8zqz/d3fwrW/Y3Fys1vvhXdGjfvFaqXh+x8y3jttnyf7KfMtdp4H8FzXGpQ21nZrLGz7m8z73/Aa+cqYily+6fotOnPk94wvEV9qurKbCw0qRreZtzyQ/M1c+vwT+LXiSxS5fUo9Hst/wAl1eKy+cv8VfU954J+F3w38CzfEj4hanHY2Nim+WP7zXDfwxx1474w+MXi34sabF4t1vSrPw54Nt52Sw+1LtubyP8A3a3y/EUoxlFnn4rCypvmWh4f4q+GOm6HCmlWfx+uJrpolaVWiZVZmb/0H/aqXwT4L8eaLMkfhj4o2MiSN8i3F60bM3+6zVleOviB8H4byZ4dKhQK22WRbhvMkX/2WsG+8cfCvVLd00jzLaaRPl/e7ttPEezlH3TTCydOXPI96s9f+KPhm6SbxJ4ba5jhdWaS1+bcv8Tbq39W1Lw38QvCN3M9hZ3EO5V23UW2WP8A76rxn4S/Hq/0m8TSpvF0120MSqn2rav/AHzXonh34xeD9WjudE1iyhnjml3JcL8rL/eryJc9Ofun0VGpRrUjb8P/AAz8Mf2LDNYJcWvlv+6WHbIjNXpHw/0nUvh3qFtqVhrdxDbNtXasXzMzNXMaDovg+4tIX8K6ldW6SN/qVn3fN/F8v92u+8TeJH0fw7ptlc+IY/Ka82RKtv8AN93+9USlzS94qMfZyPojwn4i0HVPDqW2p3N1JcQqqxLJL/6FXZ/D3RUvtQjmX7KEmfcvzLuVf9qvBPhzoelataLfz381xHcRbv8AWsu5q9v/AGd9D8O3E3nedvRd25riX5mqoRnKfKhVuSNKR9KeAV0q101GvEjd1b938+2t7XtZu7ewkazm2pJ/z0/hri9ObwbOY7OCa3V4/lZY56i8Q/2pY2Mv9han5jLuKR3D7lb/AGa9qVRUYcp8XPBwr4vnf4k2l6qLnVJVifK79r12/wANLG21DU7lLm3jdFT5VVv4q8j0rUrlZDNeTRwzL80q16X8IvEjrdhPlZZm+ZlrjweKjDERctuYef4GSwb5Tb8aaGlrpU9sgz5e7bu/iWvzZ/4KgfEbT/hb8O9Ss/EM0zWOvRNZweT83+s+Xd/wH71fp38TWmh0R7m2g3v5TLtX+7tr8UP+C2Xxh/t68g+FE2mrNbQ2W/7VG22RZvM+7/3zX2Co/vXaWh+ZRp+0xCiflp4m8OpousTaPZ3PnQxPtS6k+9ItZs2nuxWGR/nrqr7Rdt0Ue53+X8395l/2aqppcKwq+z5V+Xcq/wANdftuX3T6qjRjGBy01r5f+jJC25qoy6Smxk+VRv8AlWuvk0fbIxmRmRvl3bPu1Vm0kvIU8lVSP5UojU920R+x5jkLiGaH9yjqQ33FZaoXli/LxpuX+61dbdaW/wBq+f5W2bvL2fdrL1LT4z9xPl+81dNOp8JySw8Y80mcTq1iibt8Kt/tVhXFngHanzf7VdtrFjbBdj7d7I25a5jULWFWdPmCr/F/erspyOGpGHUwb77ux0VT/Cy17h4GwPgGOv8AyCbr+cleKXce5d+z7zbd38Ve2+CEEXwHCdhpV1/OSv6H+jy75/mf/YHV/wDS6Z8ZxauXDUF/08j+TPCI5tv7l+n3qt27IsqfP96qsK/ePytU9rIiyeZ8p/uV+DRkfV8p0Gnybm8t/wCFfvf3q19Ok3Y+Tcv+192uXhk5Vz93fu+996trTZvLCHf8yvup++HKdNb3HzP++ZD96tWxunZfOR1Ut/C396uXhuHVnLv977tbOn3Dqw+7j7qrsqJe8ZyidPDJ5yrNs/h2ttqX5JIfkTP/AAP7tZFveIys+GVF++1XY5kZdkL7Ny7t1XGPNsYSiWVaPzN83y7vlT+GplZPJWFN26P7275t1VbeSbyd8nzv93cvzU+GR2YfvuNm3/e/2qvlRh/dHz2+I0/fKu1G2bvu/wC7WVdxuI9ny4+98zferRvLyZX/ANcuF+8rVmXy7pt+9s/+OqtMsz7pkkYIifIqf99VnXUaRzeRbJ97/wAdrV1CQ+Z87/L/ALKfNWTdPu+//rW/2v4amJtExtaW5Xanysm/+9uaue1Lev3B8zP/AMtK6DUHeNW/hf73zJ8rVgapDja8j/8AAaiUTWOx7VcWvnSNCn3v9r+9UG393Gjv/wACVK1Vs91wdiMRs+81Ok8mJfnT52+VW2fxV8LL3j+gMHU5oGK1uiuu9Pmk+by1X71M+ypMo8lJP9itS3jmRv8ASUjb/wAebbTb6x8t96Q7VVNyfw1HNGJt7RmK1um94X3Ju/8AHqgkhfaq/wACttT5q0ryz3N/F/wGqjLt+/Cyt95q6FK5yYypDkKslxt3I8mGZtrULMY28n7PuG37zP8ALUN0sMLb0m3LVeNysjujq6/e3f3f9mu2lHllqfGZhU5jdsrjzpk3zMqqn3V+7WlDePJbmFH2f7X8Vc5p0j7Q/dq1rNn2n7Nt3fxszVvCMY6s+flKfOdJpNxM0jJ8qfwozf8AoVXLj/WP5yMh2Kqf99VhJq21RbTJG+35V21ej1C5mh87Yqj7v36iMp82opS5tC/MsOX+RZmb721fu7ao/ZIZlldNyr91Nr/eom1B44f3b5DPt2q33abH5M6s6PtZfu0/f+IJa8oMse5pN7F1+8si/wAVUmjtm33L/Ou/5fn3VZvmdZFmkm37v4lqFbf5WfyVBb+FvlpRlIF73wlaO+2q0Loqsr7vmWtCzvkYM7wqv8PmL/FVWO3E7KXTduX7u77tTSeZCojR+PvbVolGMvdKjznR6bcPIv7lPMZk/vba01uPs6nyXUs38P8ACtcxp91tmljSFmCrufd/DWzZ7GjQPM22P77fxVzuj7+p1e09yx0NndwwnzkRlX7vy1ppdpIqWcKM5X5k21h2KzXHyIilGi3J8vzL81buny2ccQRNr7fmXb/DXTTpcs7mM5KpC0TX02SZVaaZOd6qu1fu11/hm8tl379z7k27mrktK3xxf6ne6puSRvutXT+G5PtG2aZGiVf4VX71e5haZ89iObnPQNBme5hGx402tulVfutXVaDa2zbrne0kTfNt2KqrXC6XMlqscPkLGjLuRW+Zt38Nddo11M0tvc+Ztb7zLv8AvN/u16NOn9o4JSPRvD8fneU6P95NqL/erstNtYWCWyfIPlbaq/erifD9x5ap88Z2tudY2+Va7zw+32iP995ZlZVV2j+Zl/8Aia1jHliT/hOg0ez8m18l0UuzN937u2rcy7ceXNllT+JvmqvDNeWsK/Pn/Z+8u6rMhRlL+RsbZ+9Zk+9Uc0ZFRiVNQVI9yO65bbs2/dauZ8QRpaR7Ll2UtLuX5futXR6hsjj85/MO75oo9v3axtUZo4fkTLNFu+b5ttYylymkYnK6wqXTS/uVhTd8isv+fmrj9eWGQCVOfvbPmrrtahDXBhd/MG7zN0f3vu/LXG+IJIYVcu/O9pPmTbu/4FWXObx5zz7xhdeXDNM+3ytm7av3lryfx03mRtDbIqou5om/iX/gVeqeKpvMTfbQ7dyfOq/davLvGFvDHG2y2ZZfm83c3ytUc3Vmvw/CeVeKU8mR0TdmRNyLt+9XmHiiFFbl8Ffmddn3a9I8UfvJHREZSvyvuavNvEEf+u85923dsX+KlzfymdT3jgvEUzrHLs2/f+8tc3Ncfvtj87k+aui8QrMv/LHG7+7XKXi/Z2Pzb3/u1tHlkcso8pat7vaxR0yq1o2826P5H2/+zVzsMm6TyUGK0be8eNVQbdu3+KtJRIjI1YLxG3Q72Vv9mpI7x2Y7H+8/3l/u1Qhus/fH3qsZ3fcdvl21l/iDmkaVjdbdnlfN8u11ZK1LORI1SZ0Vzv8Au1hW9yissu9V3fKn96tOxZ4/v7fmf5GWqjsTKJvabceQpj2L93+Jq0rHfJHxuXc+5d38NY+nrC23zh975Xatezm+0Tr50yvu+X+792j2gRpmnbyeZ8+/IX+H+9V61tfOn85+Fj/ib/2WqNnGNuxNyLWnbx7JEHRFb5acq2kmVGma2nrMscUP/LNvl3fxVt2DTQoib1O3+6//AKFWPZ/vI/kfKx/K6rV+OZkHko6/NtZdzV5tSt9o7qOH5jct9QmW6WYOu9fm3b9tW/tSLu85/Nf+Bf7tYqs67Jo2X+78vzNV7zJplLwhfldVRm/iWvJxVQ97B0ZIvpcfLEmzarfNuZP4abcSbZEhTcz/ADNtVflqrCztvRxsfZ8q76at1NcKH37nZdz15NTllVPZpx5Y8pLczTRtvh8tPMRfm3fK1VLi+/0d5oZ9+7j7lR6gwZf4cMv3lT+Ks+41HzY1Szgbb/FHu+7/ALVOnLbyHKPLInbVH/gTCqv3mSq8kiPZ7Edm2p8u6o7nYsyJDt/2tz1VvJJlVnmRsKvzMvzV0x5eb3TCUeaJBNJtdBM+X/55/wANUr6OGaR3d2wv/fO6pvJ+0KrwzN8vzI38VVrqxeO4VNjFfvMtdUub4TjlT90oydpndk2vserEMkyqyGZmVfl3f3qmvLF5l37NgX+FkpPs80exE2/f/u/LRy80Yk+/EmsYUVvkff8APudV3fN/vVo2q2zfIjtEq/wt/e/3qz/Lmt3Z4eN3y7l+7Vu1kQ24TzpBL8zbm+7SUuUuMTa0nUHX55v9YqfL/wACre0648nYk0zbpP7qfNtrlLeaa3PyTfMq7k3fxVpW+oJcPBMiSIn8aq/3q7qcuY5pUY/EdtpervpMqJMissjsvzfw1srre5VZLlcyf7P8Necw+IkZgk6MxV/3W1fu1pQ+MJm/0OaZSq/dbZ826vRoyPOxFOMonfLr1ss+y2mkJk/2fvVG2sPHG7zD5Fl27V/u1x1v4kSaRNk2GXdubb8q0ybxMir++m+Xc3y7vvNXo05Hk1KZ22oaw80eyzv12fe2rWbN4g/0hndPkj2765ZfEOmtMqPuVG+9Ju/9lqCTxE8TbUKytNub5f7v8O6uiNTl2kc0sPzG9eeJIfMm/fbtz/3vurWbf+JrmZSjzbP4om2f+hVz154i+ZkeOMyx/wB1/vVhah4kRf3O+Qxf3VpVK0ehl9X5Te1LxU+zejqGX5nXZ81ZGqeIo/Ja2hmVm3/Osf8ADXMah4k2x7HdSqttdmrKutY8tWhR9v8AuvXNKpLmNY4fl2NbVvEEsa+S87bv7yp/47WHcahuZkSZVXf8i791VJtSeTCb/mX+FqqTTPH8+F2s9ctaUpGvsuUuLfXPllkkVi3zf71SRzP5m/zo/l+ZN33ayFvHSNpvO+X/AGaim1R2YbH5bhttc3xe6X8J0FxqUzKs3y/3fv0f2lNtHzqjSfwtWDJfGZfn+Xb91qkjuJvMX/Vt/tN95q5pS+ydMZcptx6k8kivInyKvz1M115rHZDjav8AE27dWNHeJIoheHn/AHttTW918qJ97++2+sZR5T0KdSMjbh1C5Rk+VWRfm8z/ANlrX0/VH27NmP7klcxGvzb03EfeX5qt2F9tZt8zfN92Nf4a5pRkjsjI7Ox1B929JvlVfmVWroNHndYRdO/3otu5v4q4rR9T3MqO+GVvk+TdXQabqXnbofsyna+9/wCGsZSmbU6fMdFa3flx/I7Yjb5N3zNWjHeP5i/J8jPt+b/0KsezuEvmh+eOKST5WX/a/wB6r8MnmMkLorfP83+9WPNym0Izl8RT8dvK2mwJIytsmwzd92DVvwbJJb+HVZdoEm8bm7fMaoeNmzp9uHXDeZzhcDoa0PBcGfD8L7sbpjj/AL6Nf0PnUv8AjmDAt/8AQc//AEmsfJYCHN4kVl/05X5wNq8j/cxWz/ckRd392s+SGZZpU8lQkbbV/u7a1JLN7hTvThX3Jt/9BqFtnnQ74flV9su56/mGVTm+0frVHC/3THvLdyxtoX2Myeb8v3WWsXUJEWN3TaPus6xv95q6K+t3Zn2JuRW2t/tLWVrCpDtg+zMu1GVPL+9/u06funq06f8AdOQ1yK5mb78irG3zN935v/Zq53Vj5bfZpkZNv8VdXqlnuk+0u+dq7EVk3K1czqXnRsXm2lP7td9Hl+I1+q+4cxe7JGZECsu7b8tZN1HyX+5tre1aFI2x/C3y+WtZU9m4aT9ywCr8tezh5csbnBWwfLE528s0uGfZNubduX/dqrHYf6U8j/8AAK15rPczfuf4fu077P5cG+Tb/sNsrvjUlGPKePUwcebmkRafZpM3yJhV+/u/irpdHWZoxvRULfKzLWNYwuir87bt/wDc+Wui0mPy12Im7d/t/wANbRqchhLC8p0Xh2NBstn3Ff49v8Vdzotv9o8t0RmeNFXay/d/3a43Q5HVkZIVQ13PhlnkkTu7f3vlWqlLmibUaMYy93qdPoNnGql4YZJXji3Kse1a63So5vKt5kTb/E6t/DWDoKpJGkMPlsq7t0m7+Kut0Ozea3R/JXcvzPtfdurJr7TPSp04l/SbeZrX57bejfN8v8P+7Xqv7P7PZ+LrJPI80tLH5XmJ979592uCs7GFbPztm91f9x8+1Vau5+FNvND4shmsLaZLiTaqbX+8396vPxdTkwtSZ1U8L9cnGhL7R+l3xN8Nw2nwyl+JngzxTYXmtaBawtJp0jeZGu3/AGf4v92vmD4L/E3W/i54y1Wztnkk1S4nkuriO3i27mZvuqtfH/hn9pL45eCfit4qjs9buJNIt9Uka/hm3MsfzbdtfZ/7Ifxc8AyahYfELQYYf7aW9jlWNoNqyNXw+UZvOSk6ux4vFHCFDLlL2MuaS1Mn9rb4Q/EvwreaXZa34evHFx8zSMn7uNmX7rV84XHhW8/t6aHUoVjis/ki/wB7+7X7WfFePRvF3gb/AITPx5pFjLA2nYgVl+XzmX+H+81fnB+0d8LfDeh2Cf2b5k00l1JPKqxfd/4FXbn+KoRpRUN5HznCmFr1sU9PhPCdNW2tlSNIfKlkl27dv3a9A8K+KfCWgwxxyXMYnkf/AEVWT70a/wCskb/ZWvIPFWqX1rMlnbQt56/ckbd8q/3q81+K3xo1LQ9N1PRdBuWa4voPsUt0rfNHD/Ft/wB6vlKcZVJcq3P0bEShh4cqPTfj5+1h4Y+J3iS51vXkkTwV4Pi8jS9NV9japdbv9cy/3dy18PfH79qzx58WvE009zf3FtYWe5NOtY5fljX+H5an+JHi6HUNHTw3YQ+TBv8An+fczN/eavGdS1B7iaeC2Te8f8X96vocty+MZNSPk82xkpwtGRBr3xk8Vec0Mzts/wB7d/wKovDvxuvbO63zXLZb5XXdWRqGm3Ma+de22PM+bazVkXmkwyr9pTarf7NfR08LhnS5JRsfJyrYqMr8x7t4M+L02oTC5N/vZfvKrf8As1eleFfiRPf3DTJeSbdy/u91fIOmz3+murW1xIn+61ej+AfiVeWITfM3+3u/irysVlzjdwPcy3N5x92ofU9n+05rfw31K1mS5vBaw7neFX3fM1eu/Fb9q9NU0/we9sixxzXqyyyea23cy/d2/wB6vi2bxRH4k1CLT45uPvbVetn4jeNn0/S9A0r7TcFrG4afb5v8W3+Ja8h4SOlj6OGbSlTfOfrl+yv8ZdH1rT1/t6bbFH8z/vfmX5f4a95+F/xD8GaS3/CVarZwyWa7lWRp9qK1fh94b/bY8T+A9He20fUmWST77N827+9UVr/wUO+OS2d/omleLbgQ3Sboo1t922sY4TF7QQYnNsNFH76eHv2w/wBmq38SP4bvNQt4bmSf/RmkC7Y1/wBqSvStI+IngfxFBJd+DfEVnKi/M+263rX8z3hn4tfHvxlrTTP4h1K7lupf9XCn/fS199fsa/tPeMPh3DaeEvGNhfQxN5at9qt2Vm/4FWNbDY7Dw56lmYZdjsJiatpe6fqrNrX9pWouf9W7N8y7f4q7T4G+IpYfEXk3IVSrfIq14X4D+I1t4w0GLVbeZXWZdyyR16H8KdWuofEsLwuwdW3Oy/NXgrETjUi5fzHvZph4VMumv7p9AfHDxM3hjwdLrlxcrb2ptmW4mY/Kv92v5oP26vixefGb9pTxb4xTxJcXkLak1raxtL8kaxttby1r9vv+CvP7Ssfwk/ZKuN2pCK71aX7HYbPvs235mVf9mv5/LpYdS1BLm/ud83mszTL8vmbm+b/gVfrWElGtRjNn49gsN+/lMx4dNhkb/lozN83/AAKpbjS7nydk0O5fus0f3a17XR08yVPJ/ds+5GkrStdLgj/cvbM25N3nbKdSp7OR9DTo+0OPbTZltf8ARrZZE/g/2aoXGmv5fnbPn3/6v/ar0FrFI2b9yuz+Bf7tZOpadDbt5juqt95/92slX5o6j+qxjI4zUNKmaPfMjF1/iX+Ksu602aNmRyyv/eVq7K4VFlZPszOGfb/d/wCBVga3a7fN3fIy/dbZurqp1JHHUpw/mOC1LSQrSvMm5vm2N/FXL6ppKbQ78N/DXoup6fBJC+zaW/jauV1yz2iQfw/3a9GjznlYiPLK5wGpWc0Uhfr8/wB5a9j8GIU+BWxSf+QVdYP4yV5jrFvt+d4cbvlWvUvCibPgiVznGlXX/tSv6L+jz/yPsz/7A6v/AKVTPieL1bCUP+vkfyZ8/K3lyLIjqn+y1S7UVvkThv8AbqKORFZUfcnz7fmqVWTdvd1xu21+A/DE+wjyyjzFyGcj5EO/b/FWra3zr8iIrN/easG1mk5RHVh/stV2G6EeP4d1UEowidLZ3j7V+RWLf+O1qafcSRyF5ju/hT565q3vNqL5L/wbvmetPT7p1+d5vl+86tQZ1KdzrLO8P35AvzLt8tv/AEKrsNx5kO9Hk+b7/wA//oNc1b30aus3nb/4au298m4Iny/738NXzfynFUidFHdQqocwsh2bU+akkvnaPhGUsn+rashdQ3f66Rf3f92ki1SHKeS/3U2y/Pu3Vp8Rh7M0pJI87PM27U27t/y1BJeurI/8NU21R5GKIY1H/PPbVeTVEdWdNrfw7d9TzfymlOJavLqGRd/zfc2p/DWRNdZZd6fN/tfxU25vE/jb7zVny33mTO7Pn5Pmo9/4jWPvEWrXUO1t826T73/AqwL6R5JGdwz7vuVfvrh5l3l1+X+Fv4qy5JdzH5mH/stZSkax5D6MjjkUqkwzu/u06O3+2TfJCsQVGZvM+8zVP5flv5L/AH1l3bt/3l/hqz9nSONN/Tc3y18RUjLqfr+Fxko+6ZscL7fnf51bbtX+L/dqHULVJI2O/czPtZpPvVszWLxyRQvCqrG25FWqs2npJIUSP5v4Frnid/tuXaRzt9bzTXEo+6qp/wB9VRurWbzFR0xuXd8r1vXVnNI7bLb738S/3axbyONpPO2/KvypXZGJxYitLcx7y1eNZdm35k2vuWs+SN1kaGZV21tXUYjRt8PH91qpT27rJv8AJVX2fe/urXq0ebkPkswqe0kR6bJtZfnba3+xWxpyzTFI/u/3m2VTs7dF2u/IXa3zfw1rWce1fvtlv4q2lL2Z5kfekJHC8zL9mmber7d1aUe+E73gkQ/xrJ/7LTI7fyfuJHhX2/7TNWlp9jDGrPv3bvmdmb5q55VC4xiVvJ8xhJ5LFvm/d7NtTLZ3KrsgRok+98tXbS1dYyiPIpX51XZu+apVto0laUFssQSCeOK/QuA/DLijxFWIlkyhahy83PLl+PmtbR3+F3PGznP8uyRwWKv797WV9rX/ADM28ihaZHePc2/bt/i3VDdw+Svzws23+LZ8zVsvbo5LEncWzuzzTZ7NLlSs0jkk537ua+//AOJZPE7mvaj/AODP/tTxlx/kC6y/8B/4JjG3gjVZn+X5d3+1/utTo1SSVXR496/K6qtas2nQTgK7Nx6EVGmj2kYIUvz7j/ChfRj8Tb3ao/8Agz/7UqPiBw+us/8AwH/glRZnVv3O3G75/wC9WpatM0nyP/2zb5arjSLMBcBty/dYHmrdq72mdjlvTzDnFWvoy+Ji2VH/AMGf/ah/r/w/Ldy/8B/4Jtaau6MJDuD7/nXZ/DXTaUz7kjS23Mz7flTbXCwahcQSCQENjoG6Cr8HjLWLdSIzHyME/Nkj863h9GrxLTvJUf8AwZ/9qZf6+5Cv5v8AwH/gno9qqW8vnTOqJ/Arfxfw1s6XcTWczQ3KfuvKXd5f8LfwrXlMfxI15CC1taOFAAV4iRx+NTR/FjxRFI0qx2uWOT+6P/xWa76f0cvEaO6o/wDgz/7U463G2Rzndc3/AID/AME960CRJJNt5M2+F9jR7f8AZ+XbXYaDdPHshSaFW2fxfe/4DXzFZ/HXxtZNmJLIjdna0LYz/wB9Vdtf2k/iFaEslvppJbO5rd85/B66l9HnxFStal/4M/8AtThnxdk8tub7v+CfY3hu686TZc7sSPs+/wDMu6u80XVktWSF/wDlmm1NvyszL/er4Rsv2wfixYbvs9tpALY3H7G/P5PWta/t4/Gu0wU0/QGwc/PYSHP/AJFpf8S8eIvaj/4M/wDtSI8WZPH+b7v+CfoBpNw6qnC7WXc7M25Vq/pt9ut1mRGJ8rdKu75VbdXyz+w543/bc/bp+Ndt8B/gdovhCG6+xS3upapqllcJZadaxgAyzNG7sAXZI1CqSXkUcDJH30//AATV+Is8dx8O/h9/wUF+FepfEi1gLXHhS48NbQsirlkcR6hJcRqMjLmIkDnbzivz/ibgPH8I5gsDmmKowqtKTinUm4xeilPkpyUI+crd9j18HnGHxtL2lGEnHbZK77K7V/keRXrLJthhm3MvzPu+bdWLqG+OFvs20fN92Ovl/wDaR/af/bT/AGV/jT4i/Z/+L3h/w5Z694dvjb3ZgsJminQgNHPExkBaKSNlkRiASrjIByB59c/8FCvjtdIUk03w8M9SthKD/wCja+xwv0fuPsfhYYnDuhOnNKUZKrdSi1dNPl1TWqOB8WZTTquNTmTWjXL/AME+wNUZFkl37h8m35fl21xHiqZGs/8AQ0U7fl2t8275ao/8E9PAX7bv/BSTx5q/hX4ZTeE9F0nQLeK48QeJ9YsbnyLXzH2pCgjcmSZwJGVPlBETZdeM/Vvif/gkL408eaFfaT+zL+3z8MPG3izSk/4mWhXWkiKOMg7SHe2vLh4TuBA3xnngkc18BxFwJjOGc1eXZji6EK0bOSUqklBS+H2ko05Rhe6tzNaO+x7eFzvC4uh7SjCTj00Svbeybu/kfCvimQfZWhd9g2/Iuz7teWeOJofLly+z/a2VIfF/7R+u/F//AIUND4Eil8YTa9/YI8PRWZ843/neR9nxvxu8z5euPfFfoFb/APBAOHRvD1noX7VP/BQLwD4L8Vaqp/s7Q7KwSRJSTtASS6ureSb5iAdsYwTgE8V3cS+GedcH+xeaYijB1k3BRlOpKSVryUadOT5Vf4rW8xYPiLAY/m9lGT5d7pJLyu2tfI/KHxV508zbHYMv/LRk+Zq4PXrOaSSWf7T95/vbfmX/AGa+v/8Ago//AME2vjr/AME8/iDpfhr4uanp2uaT4htZpvD3ibRhL9nuRG+2SFhIoMcyBo2ZPmUCVcM3OPkTxisdlPIkTuxUAhd3tXBnPh9neScM0OIJVKVXCVpKMJ058121J7WTVuSSd9U1Zq5eFzjB43GSwcVJVIq7TVu3+aOC8QLa/ZH2Fm2v/DXGahbxuzv83+zXb65vnZUk25+9XNatbqJPJd8L/dWvjKMuXQ6a0TmxvVmT7op9u025zvZvk/v0++jRJd6Iy/3agWaZWV3hV2X+H+9XXzfzHMaMN18rPs+6lW4ZP3fnb2f/AHay4Z3bMaIufvfL/DWhavG0fyI25n+7/drKUeU0NOykTKvv/g+8ta+ml2kTemPkrJsY4Vj2I+R/e/u1s2KvuVJnVVao9pylxp85rWPnSFPPdUdfu1t2DQy/f4Oz5GVaxbWHzCv3l+fcrfe+WtjT7T92rx7lVf8AW7krnqVjWNHlka9ir/fCL/wKt3TVuZI96bVDJuf/AGaztKR9qfPsRm+T5fvVpWsLyKYU3HzP4q5amKj8LO2jhZFuOzSNVnE2Iv8A0Jq0bNfsu5JoVdGXc/8Aep1jY+YscbhWX+H5qssiQzYhRZdr/wByvNxGKjGNj2KOB5bMZbR/ZWTyU2ln2r5fzVZjmfy97vHtV9ySK9Dxu2Pkbf8Aw7v4v92pY7ORf3Lo2z+JfvV5dStKpGMT16NHl+EFZ4bf77Pubcjbf4f/AImoobqST5PJXZ/G0f3anuoHkjKQ7V+bbtVPmWnLYpDCyW0y75Pu/J96udx1O6NPlMiSZJJfs01tsVtyxbf71VWvHaRD0T5lZtlXZNPeFS73M3/XNv4agms7zb9mL/e+7Jv27q7VyHPKnyy93cpqrrKux8/Jt+X/ANCqWSNNQYo6MH3/AMP/AI9VldP3SNlFdtv73bUlnYvJGqWyMu3bu2/MzVvGnzGcozp7mbJYw7niMLI2xVRlXa3/AAFqnh0145G3orfLu3N97/drSax/04i5hYPs/ex/3f7u2pl01JJN+9l3fdbdXR7E5XGPvSOdvLXbbuJNysybvl/hWo10tLhoX/d72/4DW1NZpcXCps27X27l/wDZqS6s90iOj7ArfMy/dato0+WPunPU5pSM2PT3ikSGZ2yPmaSNNyr/ALNF1pu1t8srF1+VF/hathYdzfuZtw/gkWmappbrJ9sfb80XyNv/ANX/AMBrCUbcrNacehj+TCArzP8APs3Jtqy149oqTO/3dqttT/0Gob4ujLCm3Crtdm/u/wCzWfdXDzKkyIyxKu3atbRl9kKtOO8TVk1BGV40mZCrbvmqJdchbdMn35H/AIvvfLWTeXUMy/6M7MY0+eq9xfPDH8iMqN/FXoUJe57x5Naj9o35Nak/13nfPt+aNVqu2vYXY9zJ/u765yXUHVh5L/Mz/wAVQ/2hIrM7vwvzP8td9OfNucksL7TU6qPWD5jP83y7d6s3y0681rbb9W+Zvuxtt+b/AOJrmo765Rd6TKN1Lc6lP5Ox3+b+Blq/aRidNHL5ygXdQ1DzE2Juw38S/wB6sfUdSmhjGz7zPtdt+2o7jUHkVPnway7hnk3Gbcf97/0Ksvbcw/7NdP3uUZeahMrLh8Mz/N8lUJr55mV0RmT7qNVxo/tEmx3Xdsqs1iVhX73y7qwqVjR5bL4uUp/aJod/7z5m+5uT7tDXCM2//Z/5ZvU62e3e7opLf3mqOSweOHeif7Py/d/4FXLKt/Mc9TBTK6yfL8oba38K/wDs1NVUaT+78u3/AHqljt3jkR3+VWTa8lOb5V+RPm/3KXtOb4Thlh+WWpDGrxyN911Z/u0eY/mNv5p7Q+YV/u7flZajf5lSN7bYzfxUvi5jHl5pEi3zxvs28t/FVuC+hjQQh9v/ALNWdte1k85JmbdT4JrZpkdwvy/Ku7+Gsqkfc1NqcuWZsWt0jNsRGq9pbxRzM6PtRvm+VKyLe48uRXd9zf8AoVXLeZ23b9u1f7tcnvyjqelRqcp0+mzus2+OZVWRvnWuhs7h1X7Sm1V+7t3ba4yzk8uFZkm+Vvv7q3rO6dsQ/KyRpu+b5t1RL4bndTkdlpd4/no7/Kv3tsdbVn5KzBE6fe+ZPu1yvhu/H8aM5+78q10+nxu0bpdeZvZl2fL95a87ESlzHoYWMZRKvje0mtdPhd4wqzTb0w2cjB5rT8DWhm0GJ5YyUBYq56K281neOoWXT4ZJJCWEoXb2Xg1q+BI45vD1qzoMrK6rlvvZYmv6Kzd830XcA5f9Bz/9JrHyeWU+XxPrxX/PhfnA6FY4Y5GRHk2ttV1b+L5aJLWEZeHa33fl/wBqrMdvDIqfaXZFVvk2/N81L9l+0R7JkZh83zKjfw1/MEY+/wC6ftODomFfaW8TfOkgDbvljbau6snWo9sZebc+35tv3Wausu4d0zohYWy/KjMv3mrndQhSSN03sWk/vPXXE9Cnh4cxxOrKPnf5lhVNz7V3bf8AZrndStdsW99rPt27V+7trsvEOj3Kx7PLVlb5tqt81c/qWl7o/ORGQsm/b/drqpy92J6EMPHkkcddRpHmHesjr8zf7NZ01rD5a7HbO/c67t1dJqVvC0b/ADxgyLu+78zVmrbose/7m1Nv3K9KjzadjlrYeEjAns91xvKY85/4ahktXMmxN2G/hZflrXkt0jceTz/F/tVHN86rsiZz93b/AHa9SjKK+yfP4qjCJSt4Z41+Xbtb+Fq1rH942x4VXb/Ev3apyRpHKZEm3H7q/wB6pLEbZmdPvf3l+9W/2Dxqkop6nV+H9g2pG+7/AGmrt9BvJJGSG5mWKL7qssVcDot3H5xh2Mjt8u5fvLXW6HfOrMk0zPt+Xbu+9V8vNH3iI9onomg3lnHO9nA6v5jbd2z5q6zw/fM1r9m3rvVPkhZtu7/arznR9UeHYkafOvzNtX/x2ur0O6dj9pefO593l7tu6ub2nKdlGpyx5T0nSb145EmmSNDHFt2/e3V6l8F9Ut7HxAupXPzrb2sjptT/AGfl2/7VeJ6Lqm5o7maZU/hda9H+Gs1zdahcWFsiytJEzRNH/u142dSlLLpqPY9fKpc2YwZ6V8Jfh38N9W+BF5qvjmZbG58beKGV9Q1C4VZPLjb7y/3al+Aek/DfwT+1hb/D34deOYde0iNo23W7bo45N33a+bv28viA/hvwT4O8AaHrHlSQ6W1xKsO5fL8xvm+b+9Xt3/BBL9mG7+JXxmvPiLrM8kum6VbLcXjSP93b8y/99NX5pl1PE+x10PS4rlQnzVGfrh+1fLFZ/B2x1GSGSGCGzjRI4/8Alm22vz7+J/ix/Fl9c6lfv8kfyxSM21Wbb/F/s19w/tf/ABlspvDMPhWGzj+yQIcrIv3m2/LX5gfFjxhe3Xi65/fbIfNZWjVNqrXXj8RGvKMYSPneFsDPC4aVSrHl5jor/RdB1i1338Nu8ccXzyR/JIzf738VfLH7R3w/021srlPB9ysl5NdMsv2iy2/L/stX0T8PfEmja1cR2GqpJFa27Mtx5L/NJ/31XVeKvgDpvxG0lrzQNKjtLeFGZZpm3eZWuX1IOdpm+cR5feifkJ8SIPEOnW8yXMMkUi/K+5K8qutQ8SaTbybEkCyfek21+kfiz9l/RLzxJd23iL7O/kv8kkn3flr59+PHwfs9PWd9E0FXi/557PurX2eX4rD/AAyifA4zC4qrHmgfJNrq2satceS/zv8A7VbWseFdY0m0S5KL9z7tb7eEdB0nUUvLaGZCzN+7aJvlqLxRr015b/YERdqxbd22vTr1lKUYQieJDC14v32cQ2qfaF8nzFUr9+tPwvJNdXHkp8p+7uqlYeHXvb75PmDJu+Va9U+FPwlv7qZLx7Ztrfc21nWlSpwLoRq1Kp3n7NvwpufGXjK10F7ORWuH2RTbNyr/ALVev/txfsK+PP2c/h3Z/F3xPpUlvol1PHBFeXDL+8kb7qr/ABV2v7I/gl/C/jKw1LUrKPCsvzN8rNX2Z/wW2+DOuftE/wDBNbwp4q8JReddeE/EEN5dbZPmaPy/LZtv+zXyFWpKeYxg/diz7iWD5co9pHU/ELWtc03T4R9pdV/ubq3Phr8TPhvouoQ3WsafHcsr/d3bdy/3q5Lxt8H/ABtDq2zUtHuBE3yo0lXvhf8As++IfEHiSKwfTZFEjfOzfdr6Z4DC+w5pz5T5eeNq06sXClzH6V/sTeJ/2Tviy8L+CdXsdL1qN9v2O+RVaT/ar7usvh34J8ceFf8AhG/Emj2895a2+yK6WBVZdtfkX8O/+Ce/xqXULbxJ8GXkhuYXWWJVb5m/y1fol+yjrH7S2m6vZeBvjT4Sm0u8jVVe6jf5bhf4vvfxV8bmmHrUo89KfNE+wy+eGxtK1aHJM9v+CPh/XfBtvcaP9pkaz+0bUaRvu17p8Hdetv8AhLLbfGzr9o2su1qw7XwTZw6YNQMLBJnVm3JuZmrT+C3jXSvCfxPx4gt1fT7G3mup7m42r5axqzbq+WhRp1sXCMv5kepXj7PKp/4T84v+C437Xmj/AB2+Oln8E/AviGS4sfAM8kV60O5W+2Sf6z/e2/KtfF2n28M115yQ79vEu5N3zV1/xm1BPG3xy8YeJ4XbytQ8UX1xBJInzSRySMy/N/u1Qt9LRlDyPhd/zqv8VfstKjGlSjCPQ+DwWH5qfMRrp6R4R4d42bkjV/lVqvR2KLlE8z/dZ6tWdn5Mmz7MzlnqeOF2m3puCN96Pb92sK3ve6e3To8sfdiZdxau9urvCuzb8/8AFWVeabuV0mC7fvIyrtaunmheOQJv+T7u1v4qxtWt0mZndGDf88933ayo/wAsjKpR5oafEcdqFmFZpt7B/vLWNr8cizL87bdq72211OpWu1ndOmzc7fwqtc/qnnfaGd5mdVTake2uynH3rSPIqR93Q5HVrWGTzdnDM275a5bXLHcxf+Jvl+au71Cy+aQfKi1z+o6aNrb+P4Vr0aceVnk1qfc8/wBWsbaOPZtr0PQolj+D0kUabQNMuQAvb7/SuY1rScqTsbG/+L+Kuv0OAp8LmgP/AD4T/rvr+jPo9a5/mf8A2B1f/S6Z8JxirYag/wDp5H8mfOF1vjlKJ83/AAComuvL+T+KtPWrOWG63pt2VlSLiTe6ZO/bX4Fy/wAx9ZGUZQHxzbZt8KLtb+HZVqG867nXC1Q2vGvyfMv97dToZ/m2PD8v8NRy9Cvil7xt2N4nyl49y792Vq+upBlbyXVm/g+T+Gucgm8uPfC/LfwrViO4dZGRNypRL4uYiUuY6ez1J5sQwou77u6rP9vPGqpNtbb8tcrDeTRn7NG+0/efbT2vtoym0n+81Pm5fhMKm52EOtJ5Ox3Vi392htU2wqkO35vmrkl1QNH5M0H/AHy1TQ6k7SfLPgMv3a1lIw5UdO2rJvXD4Vvv0z7ckMjeRt2yf3nrEj1LzpFhdFZl+bzKmVnkZTNt27/4aiUiox973S/NN+8fZtPz/NtquzP5P7zar/e/2Wpyl8+W6YH8O6n+TMZH2Q7/AOHcyVHtDWMShMu1d77VP/oNQTWkUmP4t392tb7D5arxuZW+8v8AFTWs+iZUH+P5f4ax5zSMeX4j6OjsbaO4Lzpv2/L8v8VTXFr5kI8mHG3ds3L96rFmkLL8kLH+FP4mq6tugtQkL7f4nVv/AGWvjKkvf94/SaZjfZ0hjSdAyNv+ba9RyW9tGz/OxTfu3SfeWtS4sfm2b2VPl27v4qqXce1UR3X7zfK38VZyjc6I4jlMHUAkrv516yfPt+X5lrFvYYz/AMe0LfKv8VdNdWaLsfyZFdvl3bdy1l3lq6zO7rs+f+L5q6qfvaGFSpzR945i8tZvObZDvbZ93dVaS0ubeRXdF2r9+tu4iRrh3O793L/Cvy1F9jeTem9ju/iWvUo1JeysjwMRHm+IzbO3f7R+5RZfm+81bVjb3PmbE3Y/uqlO0vRUZXnTy0/vfxVvaPpablk2Kob+7TqVjno0e5Us7Hbai5e2b5n27Wq9Y6bDIrY/v/eb7tX47NJFaGHdKsfzIzfdrQsdJmXc78Js3KrfxVzyqezgb06ceczHhSIo8KeUfu/f3LX6Ff8ABMr/AIIzfAn9sv8AZBv/ANqz45/tBaz4Ls9N8UzQ3kiQ2sNlDpdpGr3UjzTnClt+BMcJF5T7kkzlfhK70ouDE6YwPmVa/S/9kHQPEWpf8G1fxtg0rR7yaSTxVeXUawQMS9vFJpbTSDA5RUjlLN0AR89DX734R5vnWX8L46OV4p4apWxeAouolFuMakq0XZSTWm/ytsz4TjPD4epjaDrQ51GFWVvNcnYlj/4I8/8ABLH9sTw5rPhX/gnD+29fX3j7Q7WS6XSfEN5HcxXqKpAXyzb28qxmTYpuI/MWPeMoxZRXwH8Lv2FP2l/iv+1if2LNF+H72vjy21SWy1fT725jWPTRDzPPLKrFDFGoL7kLbxgR7yyhvTv+CJHhT4o+J/8Agph8M5/hdBdb9K1OW+164t1bZBpaxOtyZSCAqMj+UMnBeVBgkgH9Lv2afF3wHn/4OI/jVp2iaPAus3HgOG2tbv7I4/4mEUdkb3afMKhmQDLbAT5bAEfMZf6IzfivirwxzDNMsjjJ5hGngniqbqqMqlKaqKnapKHJzU3fn1SaUWlZXb/PaGCwWb0qNZ01Sbqcj5b2krX0vez6fM8N1L/gkj/wRd/Z98RWP7O37UX7fWr/APCzLgJHeNZalbWNvbyzH90JIzb3CWnBVsTzZIIc4VhXx1/wUg/4JheM/wDgnn8fPD/w01vx1H4g8M+L0WXw34og04wu6CRI5opYC5AliLqcK5VldGypYqn3B+05/wAFif2UPg3+0J4w+F/xp/4JA+GbnxTo+v3EGr3uqLprT3sm8kXJZ9PZnEqlZVck7lkByc5ryj/gsl+1D+018cL74GwfF/8AYcv/AIUeD7W6TUfDUOraoLv+0TI0KmF/s4jS22Rog+zuqzoGz8oYCvO4DzbxWw3EmAnmlSo8Piqc5VPb1sI1OSp88Z4WFNqaSdrwSkuR3dkk1rmVDJZ4SoqKXNBpLljPRXs1NvT56anrfxM/4N/f+CeH7JcbfFv9rP8AbZ1/S/Ay2VvaQ2lzHbWd1camUHmGOUJKZkYh3W3jhMiKDukcIzHxP4M/8EhP2Qf22P2qPFOnfse/tNeIz8FfBmh2l14h8X63oitL9ukJLWVtLIIA6+XHJI0zxL5WANsoIc9d/wAHTHjLXrv9ov4ZfD6W8b+y7DwVPqNvbhjgXFxePFIxGcfdtogDjPB5rwP/AII6/Gv9uz9m3xb44+NX7KfwBuPiB4R0vQ45fiVpMhMcH2SJ/MV4pNwP2tU83YqLK2x5T5TgEqcN/wDER8d4V/61PPJPG1qdqcKjo06EU6iivigl7WUU1GcmlzySae7MX/ZVPOvqf1dezi9WuZyel+/w90uiPpHwt/wTE/4IU/tBeIU+BX7O37fXiM+PL0tBpMl1fRTw3M6g5Co9nDHcZwSEjlBYD5Tivi/xN/wS+/aQsP2/r/8A4J7+ENNi1jxLbalttdUYfZrWXTSgmXUXLk+XGIGDsoLMGzGu98A/ePwC/ai/4I0/8FHfjLonwh1n9iTUvhj8Q/EV2V8P+JPCaR2bWl+qNIk0d1YtGyyqybkeSBl3AFhjNbP/AATN+AcP7JH/AAXG+LHwZ+K/jLUvFWvXvg64vvB/irxBctd32oW081tcNJPMW5uDESsjMuXaNyNoOG5cDxvxbwdRzSOLrYl16OElWjh8ZGlNuamo+1p1qLipUo3fPBpPS6e9rqZdgsfKi4RhyymouVNtaWvyuMtm+jOO1f8A4JLf8EV/2d9ds/2fP2p/2/tVT4kyoq6hJa6pbWFtayS/6rzIzbzpZgKVbFxNkghzhWFfG/8AwU3/AOCXvxQ/4Jx+PtPhv9fTxR4H8RIW8L+MYLdIRcSKoaS3lhEjmKRNwIOSsikMpyHRPLf21PCfxQ8F/tc/Efw58ZLa7TxNH4z1CTVGvFYPM8k7SLMNxJKSI6uhyQVdSCQQa/Rz/gqNpWq/D/8A4IUfs/8Aw+/aE0+4Xx+l9pw02K+t3+02cSWtwTHIS+UZLZ4I2DbvmAGxSMp9bhMTxVwdneR1a2cTx8MylyVKc1C15U3UVahyKLhCD+Je9HlkutrcM4YLH4fERjQVN0VdNX725ZXvdvps7oXwT/wb/wD7HPhz4A+Bv2rv2if2xNb8O+D7nwVaax40ivbW1s9891EssSW87lvIAEiReUUnkldfkZS4VeA/aZ/4JIfsK+Pv2P8AxZ+13/wTS/aZ1nxVa/D+GWTxJo+sKLgXCxiOSTa3kQSW7JCzSfMjq4XAK4Jrqf8Agu74h164/wCCeP7I+n3Gs3TwX/hWG7vonnYrcTppOnhJXBPzOBNKAx5HmN6moP8Agg1qF/B+wR+14kN5Kgt/BxlgCyEeXIdL1PLL6H5V5H90elfF4PNuP6PBMeNq+cVZzhiVBUOWmqLpfWvYSjNKF5N3bU9HFWS1Sa9CdDLJZg8vjQSThfm15r8nMmtdPTqflhRRRX9dnw5+r/8AwSO1fW/2Wv8Agjf+0X+154YuoLTXby4nstG1CFoxNbyQW0cMDluoKzXpdVbuAQPm5/LvwN8RPGfw4+IWlfFPwf4hurLXtG1WLUtP1OKU+bHcxyCRZNx6ncMnPXvmv1E/4JH6Rrf7Uv8AwRu/aL/ZF8L2UF3rlncT3ujWEKxGa5lnto5oE29SWmsiqu3cgAjbx+XXgb4eeMviP8QdK+Fvg7w9dXuvazqsWnafpkUR82W5kkEax7T0O445xjvivxbgD6n/AK1cVfXuX2v1iPPe38D2EfZc1/s8vNvpufQZn7T6lgvZ3tyu3+Lmd7ed7H6Yf8HJeg23j7TfgJ+1hp9taRp4v8FyW85jMfmEbYLuIZB3OoF1Jg5Krntu5/LWv1K/4OS9dtvAOmfAT9lDT57R08IeC5LiYRrH5ijbBaRcD5kQi1kwMBWx328fmx40+Dvxc+HGhaN4o+Ifws8R6DpniO2+0+HtR1rQ7i1g1SHCnzLeSVFWdMOh3ISMMvqK6PA2vGn4Y5dCpJJSdb2Sb1cFVqOFk9W1Cz06EcRRbzeq0tuW/ryq/wCJ+0v/AATi/ZG+MHxD/wCCFcXwj+B3jbSfC2v/ABW1G9udS8RTk/6Pp8t59nuOYFLSSta2xiCkgjftLJt48f8ACX/BEP8AaJ/Zq1V/2iP+CZf7fvhvxV448IwXEV/Y29nBE5l8phJaLiW6hd3+6IbhVXOCzDGR0GlePPHXjX/g2PFr+z3Y6tBc6FFLpfitbWctOLNNUaS+dSiAmJo5QzqMbYncMzBWLfHX/BCI/Gcf8FLPAo+EBv8AyD9p/wCEv+zZ8n+x/KbzvtH8Ozd5W3d/y18rHzba/HMrwXGDwHFecUMwpUqdLFYp1MPUoU6kaygk+WtKT5lCULQhGOi1etz3q1TA+0wVCVKTcoQtJSacb9YpaXT1dz2X/ggN4B+JXxQ/4KpeJvib8dP7Qn8VeFPD+q32vnxMh/tFNSmlS0fzEmHmpKPOlVjgFfunGcH4x/bu+OHif9oz9sH4ifFzxVq0t3LqXiq8SyMkocQ2cUrRW0KkEjYkKIoxxxnnOa/WL9nT4o/DfwR/wcg/FXwN4Dl2w+MfCr2Wqm78tc6tDbWt1MsBPzFT5L5Uclg5xtUEfk7+3d8EPE37On7YXxF+EfinSJLOXTfFd49krxBBNZyytLbTIBxseF42GOxxgYwP0Tw/zOjnXiXXx9ekqVStl2DnRhs40pczqRXkqjS06cp5WZ0ZYfKI0ou6jVqKT7yVrP7j9CPE+v8AiL9rv/g2pj8QeLdRj1HWPhX4ihgjvb6SNpBDaXSwRqHY5VltLxIxjDMqgc7vm/HLxrHIbyR1TqFXP4V+xvibQPEX7Iv/AAbUR+H/ABbpken6v8U/EUM6WV9HGshhu7tZo2CtyzNaWaSDGWUMDxt+X8htes0mlYvjDoeD/FxX4b4gTpw8Ns0eGt9X/tmr7O21vZy5rW05efmtbQ+w4dg555SU/i+rq/8A4ErfO1jznUrV442eO24Z65vVIdknk/eO1m/3a7/Vrfb+56bvmRlrktWs3+d3hYqv8X3d1fzjh63MfZ4inKJyF1buqs/zMKoNavCvyfKWrcvLV49uxOGqjc2TbgyP/HXpxqcp5/LzGfD5nmM/zYX7+2tO3bC70+Yf7P3qhjhS3kZ/J43Vo2sbybfJ/h/vVEpdzWnT5i3p8aeYqOGbd95dlbdnbvN8k0P7vf8APurPsY+N/kfe+/tf7tbWlrNtWOH5tv8A49XLKpHl907KdGJoWdu/lmbyWdl+bbvresY/OgP+jNsZVZo2rM0+FFVtnzNvVl+at7SYpmkRHfHz7XVmrz61Y9Onh4s2NHsXVUh8tV2/c+b71bGn2+5vOeFkMfyp/d/4DTNF09I5ESZ2JZ/kZnrotNs99iN3G5/l/iZW/wB6vJ+tc0uU9mjhfdI9PtUVT+52SL/n5avrp6bcPD8zLVixsUhR7n5trfLub5d1X47FJNz7GV1WuCpW5ZHpUcP7Tcy1s9uHfhP4vnqwlvMrMnkt/wBdP4WrRktbOOON33L8nz7aj+zzRwo6OyfOy+W3/oVYxl8MkdUaPL7pW+yzN+/D7G2rtZqRdPtvLDv/ABN8jL97dV9YZJIbj98uyTb/AMBqW3s5o4/Jhh+Zvl+V/vVtyzluXGnGPxGNcaXZ3UhdNuxfk/4FUEvh+HaHuUYuv3lb+7/DXS/2bIrJbL96Zt27/nn/ALNNn0d/tBmm2ldmxP8Aer0aNP3QlGHL7pzVvpaW8nyBi/zK6t/DVm10xFh85IZsr9yNfvN/tVuTeGYY1Vw+3d9/a+6rEGkW1uu7zZH86LazN96vRp0Y8uhxy/lOYl018rH9sbbt+9N8zVW+wOu2Z3+eNtv8X3v71djf6fbPNC8PzNs/haqd5pcMcex0berfxNXT7PlOGVP4rnO/ZIWjKOjL5nzNIv8AeqH7ElnD5kKb0Ztrf7Nb0ljZ+YrwzK4b7m5/u1QuLF0b5LnnZ827+Gn7PXlOfllKRjxqkn+pfc6t91V/houoP3bfe+/86s3y/wCzV3y/JkCO+P4f9mm3dqlwqvC6hm+9WUo8pnynN6ta+W3nOnzt95WrAvJpPNH9xU3bdn3q6TVIZrdd/nMW37Vkb+GuZ1RX3EzPzu+6tcPwnUvegQSX0zM0HnKhb/brOvtQZWKb/k/vbqueS+0I9ttP8NZ95ZncyTOv3/u1vRluZ1sPKp8JDHN5yo7vvWNv7n3qY106/wCu3MW+4v8Aeqw1nNbqqPbMqyf3n21XmtU3B0h2/wCzXVGtze7E6sLlvNoOa+eXf8/z7du6mSTTbVSbnb/FupJF8s73Rdi/dXZUL+X88kKbf4trN92qlWny6H0GHyn3IoBMnnK+/wD3KVv3y73eRmb+Jvu1XXe0bec7b2+4yp8u2r1jbvtNz8237rVlKtGMbmn9lES2bxts+Ubv7z1LJp7snzpgf7P8VXLe385kTZJn/ZTduq7b6bNMrzvuxGn/AH1XNLEafEP+yeWJhyaCkipvfYzfcb+7TJtNjjVvLfjf87f3q66z017pf9Tt+RW+b5qq3mjoJFhhhVW37fuVyfWoy0ZwYvK/d0OVm0hFXG/afN+df9moJLH946P8235UrpbixSGbZ8rfK3+6tQ/2cm5XkdcN8taU8RGP2j5XGYWUZHMXFm8ezZDx919rbV20z7LCsaoUZv8AZ31vSWMKzcpsXZ/y0+7ULaei/OkzFt/8X3VreVb3Dx6mHMKbT33fc3K38O+o1s91wuxP4/4a2byx3SNv4H96oLqF1UIm1P4qnml7ovq/8xTjhf78Lt8tXY45pJGfzFRmfb/s7ahhhx9/5tr/AHt1aVvHtkSHYrfJuT/aqvhgaUYziWNPVo2RNn3vvrW3prOqmHyeN67f9payobXbIuxNpZ/vVt6fC/lriFV3fKjfdrm+E76Pu7HQ6Sj/AMc0hTf/AKpfl2112n2sO3zo9yvu2vufcu5a5fR03CF4YV2b9svmf3a63T45o1CK+8bvmZvvMzVxVI80z1cLU5Ylb4gweRo8K4bm4U7m6n5Wrb+GdvC/hiHfyXMgIb7v3jWR8QYSnhy2kIG43Q3keu1q6L4SxLN4Wt0lQMC8gQbeSd5+Wv6JziDj9FzAr/qOf/pNY+Py2pbxOryf/PhfnA3ltYZdlsjsZNy/u1/harUtrcx/uYfm2uzPtermnx3MM3k3SK39xdvzLU0MPmW/mb921/u/d/4DX8006M+Y/XKNaUZX5jAwjKiQ20kyM33lesHXLPzo3d4Y/wC75f8AFXZahG4t3tURW/2VTbWDqFjC0KF/lKpt/wB6uj2fKe5h632jiNat38xrl7ZREvy/e/iasK9s3+eH5n3fL5i/dWus1qNI4lhd1UNu+7/vfLXP6tIkas77pdzr/F81dlKjLlPWjiInJala3NqrIkCkM237lZOoQ/fDph1+8tdNdfvpn+Tb/s7t1YmoLbW48nyGO75fmrshCUegqlalEwLhd0m9NwkZdqVRaN7f+BnLNtf+9WpfWvlsqouw/wB2qLKgU3L/ACMv31X+Ku+nGx8lmFTm+EikT7Pu3pu3fxL96i1j+z3W9EZv9pacZH8sb02u38NJFumZ3hOF/i/2q7Ix5onzdatymvpcfmXATztqs/zM33q6fR5H83zkfynX77L/ABVythahxym12X5VX7zf7VdHpcLx4y+x/usyt8y1FTmkR9Y5TrtLvNu3yU/i3MzLXS6VfPHcK9zt/wBhlrjdPV48bHZh/d37Wat/SZnuFVERfl2hfn+bdXFUl7p1xxUfsneaHqG24CXPySr8sTL8ytXrX7P+vJp/ibzppvmjtZFSNvuzfu22rXhui3W7VE3pueH5Vk3/APfVekfCO+RvFkMJ3K9w+z+61eZmFOdbByR35bivZYqMyb4pfs/+Kv2hNB0p/CsMdzqFmjW32WN/M+XduVa+yv8Agj34W8X/AAU+G/ivTdY0PULK6e7hhnhm+X5d38P+ytbf/BPL4Kv8GfiY3jbxToEl3pVksl6XX95jau6voL4YfHj9mb4zX+r/APCqdGuZdfv7mRrm0giZShVvmZ/9mvhaqpxocj+I9jGVqlTFN8nNDqcr+05rky70eaRzDEu9l+781fEXj6x02TXrt98m6aXzZWk+ZVX/AGa+p/2htc+1TXltNeSQeWzKiq3yttr56Xw6mraeZryHJkf/AF33drf7teTGPsmehH3YHlmj6tYeH9Uf7Hebv45Vb7u2vS/Bvx/sLW2ltb/WJksFXbtkl/i/2f7ted/Fj4c63oszO8EmG+dVjTfu3V8+fE+bx5pPiK0e2jYJ5u7+6vyr/EtehRw7qS5onn4qtQj7tU+tPF0fhjxNa/bPDHhi4uRNEzPdNOvl7f8AgVfPvxot/GejL53/AAreOa3+60kKKzLHt+XdXmP/AAuT4rySf8hKb9zu3yRy7V/3dtXrf45fGC40/wAmaRZbZn27bpPlkWvVhTxVOUW0ePL6jPmUWeXfEH4geCdQs5YZvB7RTw7l+b5a8h1a1TXLz7Po+mtt3rujj+avbvG3hmw8Yao95qulRxKv8Vv/ABVDofhPw3pMfkWtsu2FtzM33mavXoVvYe9J6nhYrCSrz92Jyvwu+AdzqV4lzqsLYZvn/hXbX0n4d+Gdha6bEmmwqvkp88ar96uW0fUrCGNbC2SFGj+6qv8AM1ey/CGOz1y0+x3lyyXGz900a7d1a1scq0Aw+W+x1XxHXfDDT9Ks/Caa3eJZo9q0e/c/7xtzf8s6/QP9njwronxo/Zp1TwL4n817C7tWjeFl3LJ/d/8AHq+JIfgHdw+Hz4pubnybaFFZo2+VVbd92vtP9h+68S3fw8GkeGbMTwNGpkYv8sca18/j48tWEj6rAR9pgKkJn5u/t5fsR6l+zj8Vobzxpokz+FNe2/2dfL8qwyf3a1/h3+wbeeItPs/EPwu8Ww+RJLG/2eTa+5l+8tfq7+0N8EfBn7QfwKuvA3jmwa52RSG1kZfmhZv4q/Lyb4P/ALRv7EfxKSx3tqXhiO6Z7K6jZmaNf4V/4FWlWtOWFjUp+84/EjzcNhqUMS6NX5M+z/2Vf2e/G3hC+t7/AMUQr9mhiXyvJgVW3fxV9KeLtJ8JXzWEL6JG8/mrFFNIvzqrfM3zV83/AAV/bM8Qr4ZhfxP4YYxSRfwvtkr2P4c+ItS8b6hbam9yyK25oreRv9WteR9Yqyuusj0sRgZR+HY7bx7BpnhjQUeNW8tYt0TN/E1fJXx88aXmj/Cn4h+IbC88p/8AhF7yC3kZ/wDnou3d/s/er6A+PnjYNGNEa52eWm/bH/6DXzF+1JJbaf8Aso+O9euZm8+Swht1hVPlkaabbt/75riwkfaZrBKO0jpqYf2eVTdTsfm9o+hzKqJNctIfs6+bN/Czf3q3bHSYWhEMMyqm/ZtZPlZqmtbVLeYI7qyr/e/vVqaXbzK375M/xbV/9Cr9gcOaHMj4nC+77pDDoN55wmR4w8b/ADwq+1tu2pbXT5oVeGZI1kZfutW7HIkknnTW3y/Ku5vvf99VPdaSi27zI6jb8yKqfd+auOpTnLc9en7sTiry2m+0Ols8aldypui3NWLNo9ysjzSP5vdF/wBqu91bT0kuHuW+R5P9UuzatZF7ocNuzOkMx3fM7f3aPZy5rCqRhLY4DXNHuY3ZJoWT+Lar7l21yt9pr/NeJuK79y/7O2vVNW05JoPO3xrFs/3Wb/erm9W8N+ZH9m+VnX77LLtVf9muynGMTw8VT973TzTULeZmkeab7rf6tVX5l/3qwNYsdy/J8y7vn/2a7u+0Oa1hOzbtZP8AgVYGqaWkbJMiM6feeHf/AA1305RPErRt7pwWrW06q+xMsv8AE33a3tJiVfADRY4+xzDH/fVQ65p7sv7tG27Pl2r/AOO1dsY/+KPZDjm2l6e+6v6I+j0ks/zO3/QHV/8AS6Z+d8ZK2Go2/wCfkfyZ4V4i022O7ZN/s/KlcvqkOdyJCv3fk+bbXomraeki+Xhdv3dypXHa9ZuPndFVV/i+9ur8DlHlPqI/AYKb5Or09W8nO9Ny0y7j8ptnlqP92oUaTy8fwtWXKV7Qnhk2yfueW/gVf4qsLcOyj5Nv9/a+6q1uzjd/v1KsjxtlP935ar7AvaFj7RPJsRNvzf8AoNN/ftt7bfu01LeaTbMYcsvy7qvRWce0O+4f8A+7Uf3TGUeYrQq7Kz+duXftq7a2tzJIrgK4q3YaOkjb9m5a17HS2b5Ei+Zk/hqpSFEzbeHyVX5N3+9Vu0s3jy/Rd+7d/Ev+zWxb6GjbHFtlmb/vmr1roZjXf95mb/x2sJSlKRtTj9oy4YYGw7wt8vy7asW9tNu+/t3Jt27627fQd0nzhk2/Ntakk0d4ZN+z/gTVzylynXTp+0MZrOaE7Oq/7NIsL7Vh2qf4v3ny1svpflpvek8v94rvZqu75fm/hrCNSRr7E+gl0l/OlSJ13xruRVWrK2r26sERQPKVtrfNuatebS/9Id8Kzwp87bvvNUTW+yTY+1Qu35v71fO1KfKfa0/e+Ixbi3upESGGZUP3t33qz5rW2GIEhXLblVmT+Ld/FXQ32n+dcRbLZR95WZm+61VLy1TcINit8+5FZ/mrH3jslGHIYF3azLHs+8i/+PNWVqEcLMvzt8zbvl/hrf1SPzN225YeWn8P96su6jSab7n8O5l2/droh7s9Thqc3LJGBLCZL7ZM+0L8vzfdqGS1ksm2SOzln+7V28j/ANJKeSuN+11qNdn2f5/+Pj+Dd/dru5v5VuedKPMSabbw2dr50Pzbm3bVX5q3NJhtpJkmSGRlV9u37tZVms0bgoN0Pm7t38W2ui0maGO6TYjbFXf/ALP/AAKol+71FTj7SXKael6T9qMabMI38P8A8VWqunvG2weXt+6q53VFbslwo+zIrbl/er935a0reNI1TyYFULtX5v4f9quGVTmiehGnCJneIGTS9Hm1L7NllAVFb5c5OM/rX6tf8EiP2lNa/ZG/4Ig+P/2jNG8LQ69P4V+I88y6PcztGtzFI2lxSRh1BKEpK5VsMA2CVYZB/KXxxC6eGLrzpAxWSPyyG/h3CvS/gv8Atz/H3wP+xp4n/Yo8PXukDwX4n1oXt+JtJR7tGxGXRJegVzHESWVnBiXYyDcG/ojhnA5fhPo/YrNJ0FUf9oUvaJuS9pTpxhaF1sv3kldWdpN30R+cZ9HEY3jejg4S5V7FtbaNt3fnpFfcfWnxM/4OH7fwv8PdW8L/ALFf7Dfhn4Wa7r4Yap4gAhkK5R1EqQ29vAHnUuWV5S6qc5Rtxr88/A/x9+N/w1+M9v8AtC+EfiXrdp42tdUbUT4ka/ke7muHYmRppHJMwk3MJA+RIrsrAhiDQ1poZLryZkZ18pdzK9Y99NNIzPvVEb5XXf8Adru4Y8d8p4Yw9fD5dkNJKtpUcqtSpKatbllKopScbacrdrdDnxvAksVOMquMk+Xa0YpL0Ssr+Z+o/h3/AIORPA/iKy0nxr8f/wDgnp4T8TfEPRY8WHiixvYolhZWLxmH7RbTzWwDHOFlbnLDGcD4j/bQ/wCCiP7QP7c/xssfjJ8Z7+0WLR3jGgeFtPaZNM05EZWZY42kLbpCoMkm7e3AyFVFXwR7ua4kZE3D/Zb5ajn8nz1/1bts+Rlf7tY8OeMHD3C2YvHZbw/ShVacU3Wqz5Iu91TU+ZU07u/IlpptoPE8F1cZQUK2Mk4/4Yq/ra1/mfSn/BSj/gon4p/4KQfFfQfin4q+GmmeGJNC8MRaUlrp17JP5xDtLJKzPjAMsjlUC5RSFLSEbzX/AOCeH/BSP4yf8E4fiVqfjX4Y6Xpes6d4gtIrTxB4e1lpBDdJHJvR0aNgY5kBkVX+YAStlGyMfOk2obokR+qv8y/3apX14kUbu7su1fvfeZq+gpePWDlwwuHf7CpPBKPL7N1Jtct+bdpy0eqd7p6p3OSXAbWL+t/W5e0ve/Kv87H6wXf/AAcYfAvwRFdeNPgf/wAE0/BXhvxzcxP/AMVBLe2oCu4+dna3s4ppQTyV8xC3c18D+Kv24/2g/E/7WF9+2vB8S5dK8fXWt/2kuq6RMYltjgItuiljm3EQEPluWDRja+4E58BvJvOk++ytt/ip8EkNw2yZFfy9rbf4a4uHfFrJOFp1p4DIqfNVjyTc61Wq5Qe8L1Of3H1itH1TJxfCVbFqKqYuVou6tGMde+ltfM/Xnw5/wcj+A/EllpPjb4+/8E9/CXif4h6LHiw8UWF9DEsLKxeMw/aLaea2AY5wsrc5YYzgfDv7dH7fn7Qf/BQT4qJ8RfjXqsUNvZReRoXhjSTKmn6WhA3eVE7sfMcgF5CSzkAZCqir8+afqXmK/nQbRv3Ltq1HqDqru7tvb5d2z5lqeHfFXh3hLMnj8syGlCrZpN1qs+RPVqmp8ypp31UEtNNtDPFcL4jG0vZVsXJx/wAMVf1ta/zPqH9tX/gpB4z/AG0/gT8JPgdr3wn0rQrf4VaH9gh1Cwu5pX1BhFFAH2ucRL5UEIKEuS4Zt4DbFf8AsS/8FGfHP7FfwQ+LXwT8PfCHTdfg+KmhCwmv7+5niewbypYS+1OJU8q4mGwFDvKtvIUo3zRDq3zDY6hfK+6q/drQtdc/fJDMmYm+ZG3V6b8cMvWQf2L/AGJS+q8/Pye1qW5vae1vf4v4nvWvbpa2hx/6p1Prft/rMue1r8q2ty/loUl07UHGUsZjk4GIjTxo+rscLpVycjIxA3T8q3LPVpVhVPmLK25WjX5v92tnSNUhh23MLSFfu7m+9ur6Cr9K7Oaf/Msp/wDgyX/yIUvDvCVN8RL/AMBX+Z1X7Ef7Xnx//YN+OEHxw+CmnrNeCylstS0jU7WZ7PUbaQAmKZY2RiA6pIpDAh41PIyD963f/Bw5oGmJdfEfwF/wTG8Oab8TLuBluvFc0yMDIwwzu0dpHcSKeMoZVJHG7vX582N4kq+ZsV237v8AgVa9rrG5neHcvy/6lvlb/ar804q8bcj4qzBY7NOH6VSqkouSr1oOUU7qM+Tl54+Ur9tj6XLuAquGo+zo42SW9uSLs+6ve3yOe+PPx0+O37SP7Qmr/tK/FKxlvvEesast9Kjaaz20IQqIrdIpAw8mNFSNUbd8qgMWJJP03/wUS/4LF/Gn/goP+z14d+A2vfs36d4ai06/h1DXNUtWlumvbuKNkVrZXiX7HH+8kyu6RiCF343BvBpNbmh+5CyfutyfPupza95Vs6OkmG+X/ZVq9HF/SIwmMxeX4ipkFFzwX8C1WaVPRRskkk0klZSTSsmrNXIj4cwpU6kVjZ2qfF7q1/E7P/gnj/wUx/as/wCCdet39t8N9F/4SDwvq7q+q+D9eS4NoZQVzcQbGH2ecouwuAwYY3q+xNv078UP+DiDxxpvgXUfDf7IP7EXhz4Z6rrscj63rxQXDi4dCpuI44IIFaZSdyyTeYMjlDXxPNqiQqsLuzbv4lqk93NteGb5dr7ty/3a8TO/Gzh3Ps4/tPMOG6M6zs5P21VKbjt7SEbQnbpzxZthuAq2Gw/sqWOmo9Pdjp6N6r5HG6T8RfjFofxStvjhY+KNc/4S611pdXi8RzzSS3ZvllEouGlfLO+8biWJyc5zmv0j0X/g4s0DxlpNlq37U/8AwTo8IeMfFukr/wASvXbeSONIiDuUol1bXEkHOCSkh55AFfnvqW+GMJbOxf723+FqybqeZVYeYx2plFX+Fv7tenxL49ZbxlClLNMhpSdJNQlGtVpyina8VKnyvlf8t7eRx4fgT+zeb2OMkubdOMWn8nfXzPXP+Civ/BSX47f8FGfH2k+JvinpFhoekaBbyweHvDWkeb9ntvMfc8rGRiZJ2CxqzjaCIlwq85+brm0s2fddRrlhjLHGRW7q0qbW+dv4V3N/ernNUuPO8xHh2/OzJu/hr1sL9IXL6eR0soXD2GeFpawpybnGL11SlB+97z97d3eurOefAsoYiWIWNmpy3aVm/ue2i0IbjRfDMqg3UEJA5XfKcfzqpJ4f8ACMwyx2gXqVN0R/7NWXqjPIxTe2xv73zVz2oWiRq+/k7tqr/eWqj438PWuuF8F/4BD/AOVkS4Pxr/5j6r+b/wDkjqX8JfCcnDxWH3cYN8en/fdQnwb8G9x3Q6bk9R9v6/8Aj9efXsdtDKHR2L7/AJP92s+8t0ZjshXZ/tferf8A4jfkP/RM4P8A8Ah/8rMP9UcU/wDmOqfe/wDM9Pbwh8FwQWGmg84/4mR/+Lp48H/B0kOI9O46H+0Dx/4/XkLQu7B02/3drf8AoVPhheZl37R8/wDDTfjbw+v+aZwf/gEP/lZUOEcY/wDmOqfe/wD5I9ih8NfCxcPCLD6i+z/7NVmDQ/h9DzbizHbK3X/2VeVWsKbfm/h/irb0uOGSZIbb+L5nVk+9WEvHHh2P/NMYP/wCH/ys2XCGNvb+0Kv3v/5I9Fi0nwspzDHb8ntNnn86tW9lpiPvtkTI4+V8/wBa5LR7eb/XTbW+b5FX+7XR6TCm1ZnRv7u2uKp48cOx/wCaWwX/AIBD/wCVnXDgvHT/AOZjV+9//JGtDJNHgRE/KMYxmrsV94ijAMXn4HI/dZ/HpTNNmeWXzkfYyv8AvdyferetWfzj5L72b5trfw1yy8eeG07f6qYH/wAAh/8AKjshwRmD3zOsvm//AJIyE1LxUqqE8/CD5f8AR84/Spv7Z8bkgA3WQeALb/7Gul0W4+VZ7mba/wBzbMn3qvRvus5YURd0ny7ZPmrB+PnDfNrwngf/AACH/wAqOqHAuYOPMs1r/wDgT/8Akji21Txu0iuVu9y8Kfs3I9vu1INY8fLIHCXe5fWz6f8AjtdtuRpIzs5X+L/Z/u1PYndGfsa/x/d3fw0Px64bX/NJ4H/wXD/5UbQ4CzJq/wDa1f8A8Cf/AMkcEdX8fShhsuyMfMFs+P0WpV1v4kArtjvcqMLix5A/75r0bS7KGREuXdg/30Vvm3f8BrXtbeWSNXmtpF/g3Mn3v9quql478NT24UwP/gEP/lQlwHmb3zav/wCBS/8AkjyNNb+JkcgVY77cDwDY8j/x2pDrfxUYgtDqDEZI3afnH/jle0Wtr5kg2Irs33lVP/Hqs2tmkzfbLaFkLP8AIrLXdR8b+HKmi4WwX/gEP/lY5cA5lGP/ACNq/wD4E/8A5I8Qi1v4rqfNit9Q5X7w07t/3xQ2v/FdZPKeG/DnoDpoB/8AQK+hbfQUvLNYfJXYz/eb5dtOuNGRbpEmmX7m1VVfvf8AAq6V428PrbhjBf8AgEP/AJWYLgPMX/zNa/8A4E//AJI+dm1n4qJtDW1+Mcr/AMS7H/slI+t/FGZC7wX7KSMt/Z/U4/3PSvoH+yd10UuYdybf721mqhqWj3lvCNkMY8x/nX+Fq0/4jZw/b/kmcH/4BD/5WZT4EzCMtM0rfe//AJI8Ck1Dx3vKywXe5sghrPr/AOO0241XxtJxci649bbH5/LXtGp6W6szwpJsX/lpIy/drK1TRdsbIn75pNqxN8vzL/eqZeNnD8Ff/VjB/wDgEP8A5Wck+C8dF3WZ1vvf/wAkeSi78TeZny7gtn/nhz/KkN/4jjYuRMpIyT5GOPyr0KbT/LZkR2LNtb/VbV3VSutLfcfJhXf96Vm+b5a5X46cPc3L/qvgv/AIf/KwqcFY+mrvMq33v/5I4O4OqTHzLiCT5h97ycZH5VSktIfuSxfePRiea9A1azhmUJvVF+6m7+Ktb4K/sk/H79pbxRHo/wAGvhRq2uOz+U8lrbsqKy/xNI3yqtZvxz4d5eZ8LYL/AMAh/wDKyP8AVLGQdpZpWXzf/wAkeStbWLEIyrkEBRuoGk2TAyi0BBP3hmv0u+DX/BuV8T7q3g1v9o74zaV4ZhcsZdH01Ptlwq/7y/KtfQfhz/ggh/wTx0OGNNf13xvrkjKu6ZtQWBd3+yq/w15lf6RXB+Hdp8M4L/wCH/ys1p8GZpV1hmFd/N//ACR+KEum207ETW24jk5zmoZLHRz9+OIZ/wBvGf1r9zbj/ghj/wAE2ZPk/wCEM8UQ7kb/AEhfEzM27+9XnXjP/g3v/ZE1hj/wiPxf8b6Qn3fLmMM61zR+krwW/wDmmcF/4BD/AOVno0OCM15rPM8SvRy/+SPxxuNL8Nu5kuVi3HqWmP8AjSHRfDIOTBDk88yn/Gv0V+Ln/Bud8WtHSW++CPx90DxPAv8AqrPxBbta3LN/d+X5a+Pvjn/wT2/bL/ZykuE+KnwK1SK2t5f+Qlo8X2u2aP8Avbo69CH0hOE6vwcM4L/wCH/ys9rDcA4uvvnmJj6yl/8AJnla6N4YX7sEA/7a/wD16lh0nREISGGPLH5QHPP05qhb2qR3x0pF8mRfvwzIyt/3zWnY6ftYb5pP725q1l488NuN3wtgv/AIf/Kz2cP4T5lXjeOe4n/wKX/yZILG1cEpbqcNnKjoam+ySRKD9mZQeR8laUen21qo2JzJ9zbu+Zq0LeO5jVoZpmy38P8ADtrkl4+8N/8ARKYH/wAAh/8AKjWfhJnEXZ55if8AwKX/AMmc8trIWwtsxJ6gJ1ofzHJdwSQRkn9K3Fs4ZJPJvdq7X+9u+aqF5bovyInH/wBlUvx94bf/ADSeB/8AAIf/ACo8vEeF2a0rv+2sQ/8At6X/AMmZEllp0jFpIkJJ5ye9Mey0hmBZI89vnx/WpbhfMZ/urtb59q1VkhWRj9m+Qf3v4acPH3ht78KYH/wCH/yo+YxfAGY0ld5pWfq3/wDJEjabosnLRxnj/np2/OmjTdC6COLof+Wn/wBenR2b3Cqibg33dy/danto6L88fzlf4a1n4/cOQim+FcF/4BD/AOVnlrgrHOX/ACMav3v/AOSIRpPh9j5gghOflB39fbrUTeHvCpzutoeRg/vj/jU/2F2jKQw/e3Mkn92sq80/5lTYodvvstVS8feHJy14VwS/7ch/8qB8D43/AKGNX73/APJFn+w/BROzy7Uknp9o6n86mTRvCwDRJDBzjcBMc+3euZks0s7wOj7G3/dapd0Cs0yOzSt822uiXjxw6lpwtgv/AACH/wArMo8G4xy/5GNX73/8kdJFp/h5TiLys9sTH/Gp7ay01PltY0OOeGz+Nc9Yq8tx500LRBvmX5a6PQ9LSaF4ZkV9r7v9lqmXjtw7FX/1VwX/AIBD/wCVl/6m45/8zGr97/8Aki/aR6nb/wDHnbyjIz8sZP8ASr0N/wCLwoEEdyQeRtts59+lbWh2qTKETa37plX5tqq1b+iedZqzzW3zx7V8zZ8si1MfHXhuTuuFcF/4BD/5WOXB2Op/8zKt97/+SOB1jUPE13bLHrXn+UJMr5sO0bsHvgds1c0PWPH1rpyW2gi8NsCdghtd65zzztOea6X4t2skPhu0mdlIkuxt2rj+Fq3vhKnl+B7GYHG+eRSWb5fvnmv17HeJmU0vBjDZ7LI8M6c8S6f1dxj7KLtU99Lktze7vy3956nzWHyDEVOLKmDWNqJqnf2l3zP4fdbvtr36HGnxH8ZJMr5eqHoCBp3/ANhUq+MfjaY/LT+09qcELpY4+uEr2JWRdz2yN/eeH/2arXlpHEHG1EX79fk0fHHh29v9VcF/4BD/AOVn2seDcd/0Nq//AIFL/wCSPDh4p+MiAqBqQDEkj+zup/74qtc6/wDE9lMd2t+BnJD2OP8A2Wve5rKaSbzntt6L825vl21geJLH94HG7fD/AN87Wprxx4bvb/VbBf8AgEP/AJWdlLgnMnH/AJG+IX/b0v8A5I8Tub/xbcRiS5juCqdGNtgL+lUprvUWTZMz4PPKf/Wr0vW1S3t3+zQqyfMHX7v/AAKvPPEV1GrtCibWX7i7/lauij43cPT/AOaXwS/7ch/8rOuPA+Z2us6xH/gUv/kzMkSBwDIQcMOS3eo5IbB1LS7CGGCWbg1WkuPLbyYUb5fveZ/dqpNK7SLsRfm+Zv8Adrrj4z8PS/5pjBf+AQ/+VmNbgvNYRu85xD/7el/8mXns9EYkOY8secy8/wA6hfTPCzgmQQHd1Jn6/rWPeTJ5jv03fxVm3kjND5M33F3fdrVeM2QKP/JM4P8A8Ah/8rPKrcJY+EbvNq7/AO3pf/JHTSad4OdQssltjGBm67en3qdDpvhKNQkJtgD0AuOv61wFxNDIxKfw/wALfw0+1uHmZI4X2n+BlpPxp4eX/NM4P/wCH/ys858LY3m/5Gdb/wACf/yR6JDp+iREGFIuBgfvM4H51aiWBBmMr8xwDnOTXJaLcIy/vkZpV/i310djdJNcIZ0ULt3IrVzy8b+H07f6sYP/AMAh/wDKxrhXHSV/7Srf+BP/AOSNWCfUoOIPMGwY4T7tSwahraP+4eTcPSPJ/lTYWeOMOm2VvvL833a1dLvIWzDMiq6vuddvzVhPxw4eX/NL4L/wCH/ys6I8H4//AKGdb/wJ/wDyRDZa345t2DWT3eQvBFvu4/Fa1tH8T/GhdQhn0NNUa4icPD5Gm7mDeoAStGzvna3RIef92vV/gT4s03w34+stSv38u0jlXczL95f4qyqeOXD8YacLYJ/9uQ/+Vky4Tx0XdZnW/wDAn/8AJGjo/wC1L/wVp8PeFF8OaNN8QLfStThMMSJ4BXFwmMFUc2mW4OOD3rnPh/8AtMf8FGPgTrt98P8AwJe+K9C1fVkAvdL/AOENi+2zqeQNslsZcHrxwa/YX4l/tV/Af4r/ALIWjW/w61Vf7d0BbeXS45Itj+ZH97bXynYfs2fHr4cftteFv2p/jXqsP2bxfcebYq0/mSNGsf8A47/s14GO8e+GKCUocI4CWn/PuGn/AJSPSyjhDG5jzQrZviIvtzSd30+0fD3i34+f8FDdbuXHjCXxg0qOd63HhFYyrd+BbjFZcXxX/bluCqwQ+K5NmNqp4XyB6ceRX6JftASQzaxf3KO3nNLvlX7reXu3VW+EcL6+s00FsyLHFu2/e/76rxJ/SM4WSv8A6nZf/wCC4f8Ayo+np+GWbVP+Z1iP/Apf/JnwDL8XP2+IphqN1pvircYyiyTeDFI2+263wPqOa5DxLdftNeIL0X3ifwx4hmmPCtN4cK556ACIV+pXiDx54W8E6olheIuovsZpVWLcsNcVfeL9N1hZB9khc/M+6T7sNejg/pC8MVYX/wBUMAvSnD/5UebjfDnNKFTl/teu/WUv/kz81Ljw98bbdWluvA2tRgn53k8PMO3qY6w9TvvFllk6ulzBjP8ArrfZj8wMV9Y/tK/Gq80G1XRNKs5pYptzeY0vy18XfEbxtf32pG2vHZlkdm+Zty7q9CPj/wAPSjpwlgf/AACH/wAqPPlwDjaKvPNqy+b/APki1Jq8JOX1NRgdpgP5GoG1PSYxtfVYRkYAa5H+Nec6pr3mNJC6bv8AarlbzXHuJkREby2fa+7/ANCrel468OV/+aSwP/guH/yo4anCWNpvTNq//gUv/kj6H8KeHfE2rxtqXgvQ7++SI7XnsLZ51Q+hKggV2ei337SOnXK3GiaB4gWXgKYtBZv08s0/4Xf8FA9B/ZU+Eei+FPASWtxcfY2/tS6mtVl85m/3q6C9/wCCqlh4o8Fi70uaGHUV+/8AZ4trba5Knj3kEXpwdgX/ANw4f/Kj0qfAeJ5dc6qp/wCJ/wDyRH4h+Pf7ZthZJ4f8T614jtYXUMlrd6GsW4diAYhkV23wW/aj/wCCoHhnTX0v4Gal44e2miIaPSPBi3QZee/2Z/fmvmib9rTxX4s8Wt4n8T+Ib68uZpdrSXlx8rL/AArtr7u/4J6/ts3Pgm6trxNV85WlX92su1VX+Ja5MT9IXh3D2lPg/A6f3If/ACo3wvAGMxV6dPOa9305pWf/AJOeZ6h/wUB/4KnaBfv4Y1f4k+L7O6KbW0+68JwJLt6fca2yPTpWLrv7T/8AwUd8Z6T/AGHrmq+Lr60LBvJbwhGQT2ORb5r6j/4Kha54Y1r4Xr+1F4Pv47TWNNv4/tUa/wCsmhb7yrXjf7Nv7Tl/4kuIEu9TuJ5mdVlWR/lb/drFfSI4ZlTVSPCGAs/+ncP/AJUetT8LswmrTznEJ+r/APkzy3wl4z/4KCaVfmbwjoHjppwwysPhKSbnsNpgI/DFd4f2rf8AgrtpUH2Ey/EC2Xrt/wCFeoh9Ov2QGv1U/ZG/sjW9Ct9UmtlWVm3M0b/vd395q7j40rpqsUis2+WJl+Vvmaip9IXhaFJzXB+Ab/69w/8AlRwVPDzNoYlUv7YxH/gUv/kz8V9Z/aV/4Ke6tIH1u68cysOhl8Fr/wDI1c54/wDj1+3je+CW0D4j3fimPQtQnUbNQ8LrDFNIh+UBzAMkHsDX6z+JNNttL0b7fNGw3fek+6y/7NfG/wC3Z4wvPEniDRPAFzNJLY6XbteKsNxujWSRfl+X+9TyT6QPDGY4/kXB2Xxa6qnC/wD6aDM/D/NMJheZ5ziJX6OUrf8ApZ8OL4j+MSHiHUuBnnTen/jlT23jH44IR9l/tTO3AK6YCcfXZXuOm2s1vNF5s3yM+1mVPm21fht910rjb5zS/wB/+Gvuf+I2cOt2/wBWMH/4BD/5WeBS4HzCS1zOsvm//kjwVfGnx9hBIGrAZyc6SP8A43U48eftGchTrXI5A0jr/wCQ6+hobNxGzzeWiM/yR7q07GzLfuUdfm2rR/xGrh21/wDVfBf+AQ/+VnUuBcxTt/atf/wJ/wDyR81+Evi/8Q7XxvbaV4zuJZ1uLhILi3u7dY3jLkAP90EEZzjuPzr2jUdNdl85JpN/8S/wr/8AY14v8RbZov2lmtGjKEa3ZKVJzjiKvpKbQ5mt1mFm3zJ/EnytWfjhlmSJZLmeX4SnhnisMqk400oxu1GS0SSuuZq9k2rX2RPAuLxzeNwmIrSqKlUcYuTu9Lrd3ettr2XQ86utFRoHfyYZl+V/mfczVg69oP2hmud6x/8APX+5Xpd9osMfzwjeJF2oqqtc3f6D5kLKlthV+ZvMr8Hp0/tH1+Iq+6eTa3oM0TNNDt/fbfm37ttctrFq8KuiO2fu7m+7XrOvaG8dnLc+TtVn3bdu1l/+xrjdU0V4W/49l2s2541/u1006cZHkVKZ51q2liOEj5maNfvM/wDE1VhbeRoclrnGIXGcdOtdZq+jptdHffub5I2rAu4H/ewYAY7gB9a/oD6Pl/7fzK//AEB1f/S6Z+ecaRjHDULf8/I/kzynWNPRo2+7833l2VxXiDSfJkPztsr1fWNLd1k85N33lfcv8VcT4m0l2w/nNt/hVq/BakT6KXN8J5pqln5c2/Yp3VBDatIrPjG2t7VtJeNm3uq7vmVapR6S7Nsf5fk+9WXLy+8SU4bJ5M/Pj/aq3FavDKkj7vu7UWtWx0ebcvkJvT/arXsfD6XTLNMjJ/s7fu1HL7uhcjn7XSZpJNke5tv8Na8GgzSbUh+7/GrV0mm+G1ZA8PyoqfLWnpfht52iuU+dl+98tXy8/ukfCc7Z6H5e1PJYf7VbNvo+0rt4b+81bi+HxHDvfa//AAL7tXo/Dc3m7ETfGv8Ay2V/l3VlLm5RxMSxtbmFU/0bft+ba1bGm2KSLvdNzN8y7f4a0LPQ7zzfLQ7Vb7/mfN/wGtzTfC7qqs9t+9/iX+GsJRmdNMyLfQ3uJBeInyLL/DS3WjvIz4hx/s/w12Vj4ffak3l4WH5mq/8A8I3an7/yyyfMjL/drlqeZ205cstDzC40iGQeS9ttb73zVQl0bdIzu6jd/qmX+GvRtS8LlpH+TL7PvN92sTUvD6W6pCkO9t/+7WUfj906YyjL3T21IYWkDzbdy/cj2fL/AMCqC4t3+1bd8bxMvzsv3q2ZLV7a1+0pFtdWZV87+Jared+8SaGHZ8m5vk3V5kqJ9pGJjXEKW8hhm+VpPmXav3l/2mrOv7FPOV7aRUGzduk/hrptQtkuF3pZswkTc3+9WVqFrbNGsPzM6/w7f4aTpcuqFUlyxOd1aOaON0s5l/vbl+bdXP30aBdnnct96Nq6S4s9y73Rdu3am75flrmfEEaWbGZPkVm+8q1PsZKVjiqVI/aMvUpvuzb9+777f3aptcf8sfOU7v4qfqU+6RpIU/dbfm3VVtW8lP3zx42KqRqv3f8AareMeU86UuaXkbFm0zRr8+VX+6v8NbOnskMO5HZNu1kZvvVzMd5ubyXThX/hb5q3dJX7U/kom7+LzF/irGtHliVRlGR1mm3iNCl1NNt3NsaStKHULb/U/M6x7vl+7XOWcjwwokJwmxm2/wB5qtLeW243nkt5rffZa5uX3tTq5pEvi68Wbw7ND5JRhsyD/F8w+asvwrJ5Wlys4LoZsNGO/ApviG9muLBvMcIdwDxbuevFVtBkaG2eRpAE3EAFsfNgc1/SGURl/wASwY9f9Ry/9JonwGLk/wDiJFBr/ny/zmT6w1vNC/z7XX5kWuba4R2VN+yXd937ytV7VrqEMyTfOW+9WFqV1+72I67Nu5l/2q/n3DqMYn12IlJyH6hcIysZvMZ1f+Fqzr/WIwrJYuoT+9/FUVxqEKKzoiq7ff3PWNeasgVX/vfdr0oUeY4pYiXJymzb6lJcbXc/Mv8Ad+61Nub6HzF/0yR2+8y/wx1zsOsPHMyed+5Z9qf3au3WoQzQh4dwTb92uynHlMJV+U0ZrqO4jG/bnb95X+81Rx3U0Ssls+za21lb+KsmHUttw/G9G/vN92nrqU3zQ78p/eZa35Zcpw1K3NK5tLcI0mzoP4NzVYW+mUeSj7G/vVzsl89rx98/wblp1vf+ar/3mf8A4FTlL7IpVPd/vHUR6lhijur7vv1Zt9SeZn+ddkP3VWuahuDI3lu7Efxyfd+atGzvnkbf5i4ZNu5a5qkpm8f5jq7HUt0qhLn7yfJt+WtXS9U27VR5Ny/NuVPlrk11BLWGKPev/s3+zWrpd5Mq73mVtvzfKv3f71cVQ7aPxHb2+qTNCn7lQn3tsb7WrSXWt9v5z3m5mdVeRk/2a4qz1SG4Vk87aq/89Gqw2qOY0dJmZm+bbH8sdePWXNqe1RqcsDsF1TaqXMafvGVvmZqZJqmWZ3ud/wB3zVWueXXnhs/9dgyJs/y1SLq00St/00TZtWojTkXUqQOhW4eSVkd22zfcpVurONV3zfOq/Osabqxbe+d41R3kUq+3/a2/3qkt7hLiQ/P5u7crzbdu5VqPZke0h8Jbmuku1eaaVmib+6u2sK+aaWNZraRk+8rq396trZDNCr79wjT/AFe77y1Ru7d44Xd9rI2393H96rjHl90JLmOd1Oa/aP7G53vu+7/s1zeoW/zTJNM21drIrfxV2F9C8Led5MmGT73+1XP65p6SSeW8O7/aVa6qNSMfdRySo82sjl9QtXhk2Quz/wC1/DtrE1L5WabZ8y/KjbPlrqNWtfL3fd2r96sDVpkA2P0V/n2/xV1xqc0xxw/NHlOWvrebcz/db+BWWs/ULZ3jYJ8z793zVuXymQf6n5W/8drLv7J5Fb52UfertjL3TGph+Ux5leOQ+lLa27xtvmj27vmqx5KNnf8AN/FUsdqGbY77zt+WtOblOf2M/iLGnq/zeSjBv7zfdrodLtUtbiLYnzfdZl+7WdptqkOzzoWDbN3+9XR6XCkkfzwq277jMlefWrQOinRlzmrp8KLsdN277v8As7q6GzjmjZN8ih9n3lSsexWEReTlvm+5t/hrYs4/kZXmZ/M+bd/drzZP3uZxO6MeX4TWs1eOP5JvvfxMv8VaunqGVv3W+KNPmZf71Z9i01x5cKbTtTb8v8Valirt/ozhcfddWrGUvd5jqj75oQo+14Xh3lm21cnWZo4pk25+7t3fdotV8vE00Py+U22ONPvLT9PtdpKJC33/ALzVy+98UDpXLHRyLNn51qqOiLu2fPu+arVmrzMk1smxtv72ORdy1HZwzQoXeFXEm77zf+g1r6XY7pFdHbYu132/wr/drSEvekdkeb2Xul/S7V4tvlwx7Puyt93/AL5rc0/TUVf3yfd+X5f7tVtF02a3VVmud8W9ml3Lu3LXQWtmk0ivEiuIflr06UfcvEy+GRTjsXkmXYn+s+X5q09H0j938/VvuLv27dtWl09Iwqb1cr9yOFdytWvZ2Xl7XmRt/wDd2/xf+y11wlGmOUpSkVv7M8yxGzaqbG3q38NSW+klv3MO3Zt3bm/vVsW+m+dvmmHEbfKy/wATf3dtW5I/tEa/adqLsX5WSu6PJUkVL3Y+8c6uh7rjf8rN8u3d96quoaPtkCOjKFb96zfMrV2sNnbfaGmSz85422vtf+KmXWku0xeP7yr8jM/y/wDAq1j7sjGtJcnvHmOpeHY/PcInC/wr/tf7NYd9p3kbbaZ1hG3918tem6hoPlRy3jp/tNtT727+LdXLeINDs5Jfn6N/qttcuIqR+E8+MoSmed6hpsnmRxQxqrbm+X727/aqbw78Pde8Wa1HoOiWzXE14/lWsNvE0jTSf3dq11GheAtS8aaxb+HtK0S4mu7h1ggjt4tzyMzV+yX/AATA/wCCaPhj9mzwxZ/E74l2MN94uuIlkgjeJdmmqy/dX/pp/tVxRkqlWMInPjsbSwtKTZ8//sAf8EGtHutGtPiP+15AziaKOSy8NQvhmj+8vnN/D/u1+g9r8P8AwV8HPC6eCvhp4P0/Q9Hii2xWek2qxLt/2m/ir1BlTYQK89+M2uwaNYFpn2j+L/arm4hX1bA6fM+bwNapi8dHnPM/GOv29tlYg0u3/nnXKSeIIWZTsXY3zfe27WrK8V/ErRIJDCl/DuZW/dyPtriJPF1tqt0t4NS8pFfbtV/lavyTEezUz9iy7B0I0veZ6Td+JIRCPs1xltv+r/u0af4s050S3uZmidmZfm+7Xl+oeNsabIYbmFy0q7bhX3Kq1R0/xZqtn/o2peXmOX71q3ysv8NcvtOWF0erHL6Eo/EezXE0EUxuUPnSf8sljel/tpPssltcwrKkny+TIm5W/wCAtXjNj4817w7b32parrH2+GOXdFDbxbZIV3fd/wBqtq3+J015HK/kMqtF/o8jN97/AHa0p1ZqJjLL4PRu5S+N37D37F37QDRH4wfBHS2v2iaJdW0dPss6q395o/vNXxd8b/8Agg7pGj3j6r+zJ8b5LqFlbyNB8WRbW3fwqsy/+hNX1/rXxUe0+zB0a6eT5ZY9+1l/+KqaD4jTaetwk9zHKkduzJ5Mu5lavSw2f46jeF+Yzo4aeFlz0ZyUvwPx3+Nn7Kvx+/Zvmih+Mfw3vtMTfsS+hXzbSSRW2/6xflrhri3DbYYZlK/xtv8AurX7qR+NNE8daWPBnjnSrHUtKuE/0/T7yJXimX/gVfGX7bP/AASW8I6pYTfGL9iXUjbhUZ7/AMB6rdZ87+99kf8A9ptX0mBzbC41ckvdn2PRo5/Vi/Z4uOn8y/U/PW6/cyBB5bKrtsZvvf8A7NY98sNw27eq7X+etnxNp+q+HdeufDfirSrjStQs5dl1p99b+XLbt/tLWPdbPtTo/wAh/ib+GvQ+1YyxuIpV/ehL3TL+Tc6W0LD59zNt3baX7DcrNsmdVZU/v/K1X7WPyoim3DL91v71TLbpNNvR22/7S1alyyjY+OxlP2nMiv8A2ed+xLfb5m35qctnuhZk+VV+VFjrQhs5tod4VQLu2fNuZqdbxPGx8mH5ZPn+b726iUvaHkezjGxiX1j5cbzOG3bNqrWLqFq8a+YI9rL/ABNXWXm9ZjvtuWb/AHqwdQt7xdQlfZHjeu35v/Hq6I8vNoT7P3Tnbg/bMTIi/wB7cyfMzVUWPdJ8/wB9fmdf7taV5pr3Ej3PnfNv/i/9lqm2nzQyNNsVzJ9z+7XTGpHm5ZHH7ORLZxveXCu7t+7Zdqq1dxpNui7bnap8xNvzVx2kWrx3CPJDtdfvR13HhW33N9pk+ban+rb7rVrGXuaE++dFpNqisN7sir8rM1b+kq8gb7Y6+SrbEWb5lZf9modC0+Gb/SZpmXdtby9n3q6HT7F5Y/3yR+cz/JHs/h/2a0icdWMviich8YkkTw9Z5LOPtK7pD03bG4rofgwk8/gmzhhyRvlLf7P7w1jfGyyNt4ZtTJEVcX23J7jY1dB8EI5bjwLaLHH8kUkrOVOSTvOK/pLMYyn9GjA8v/Qa/wAqx8Fh6ns+Oqz/AOnS/OJ1aQzLdF9/zTffaT/0GrcbQzRrNAiq/wA33f8A4mnwwrDJ50yTfc+Xam5t1P0mx2u14qfP/Erfw1/Pkafu3Pt44oZcRvc26+VMz/eXarfw1j65bzeS7u7M33UZU+7XQXyvbQq8vlp/zyjjSsDxNO9nbu+xQF+bb/FW8aJ2RzD3rHAeKlRrWR0uWZd+3+7uavMPFV0kl186Mqq2141/hr0vxcnmQypCke9fm2r91a8w8Vb2Yz/dVvmf5PmZq6qMYROmGYcsbIw7yTcu9Jmjfd838VQNdNuV/ur/ABNVa4urlZHTbu2/faq8vnMrfPhfvbVauqPuxOLE5lKUh13cbZGdHjI3/erH1KbzJPO3sp2f3/lqe+uHkHlo+Gb7jbazL5n+VN+7+9t/irSUTy62M5vdKyzeXJ84Vl/iqfS77bM0nzf/ABNZ90ySME3qP9laWzuE+VN+35/u/wB6spR5jj+tS5tDp9Nn2yFEdju/hb+Gug0/UkjjBfn+9XHWt0kcex/u/d/3a3NJuP3nkvPXLKPK2dFHEfzHV6fcQwSb4f8AgVbVrfefN5zzMzL975flauRs7z5kzcqVb5f9mtyx1JzInzq25a4qkftHoUa0tjsfD959oj853VPm+6v3q6Cz1b7PIHR5GTZtRv7tcNp91N8mDGo8/wCeRX2sv/Aa3rHVEZmjk2+b/BJJ/wCg1jyxN/ac0bH0t+yL4q/tL4haVoOt+Id9rJqkaNCr7YvvV+u37X3w98P6z4T8PeJbJmI8LWsTWsit8satHivw1+BOpXMPji2ms4ZPMa4haL+L5t33l/u1+xnxF8aeKta/Za0HxV4n0+dYNYtVs4Gb5f3ka/L/AOg14eb4Wv7K8I80T0Mnr0JY2CnLllc+Wvjj4qh/4SQI7ySy3W37rbttdT8F7Ow0+xkxfqfMt9zKrV4v8TvFj6fI0zuzztKqyzSP8y7W+7Xa/CvxkkPhn7fNbLCjIyMzNt/4FX5/Uc+XlP1Oi4+0sznP2gPHlh4V1ZUsLzPnT7EVYv738VcTa/GDStJ0+W8v02RRxbX/AL01cb8fPixN/blzf3OpQvuumWJdm1mVf4q+dfG3xkuVZvs1zJ5iuzbt+1V3V62Doy5YpHmZlUhzSZrftIfGCHWryS686SXa7eVb/d8la+WfE3iGa8unm87/AJasyq38NdJ8RvHV/q6v9pmkdmf55N33q8w17XAtx5Kbc/dT/ar6PD0+aXKfAZjjlGXIWfMudWuFs7XzC7Pt3V618NfgLpupWI/t7bbu3zeZJ8yrXJeA7fR9Is4dV1K8j86T+H+7XoOl+LE+wukN55Sbtu5fvV6UqkafuQ3POox9pLnqmJ8Sv2P7nU9La88MaxDLt+/CteJXHwV8eeG7xv8AQJCqttdo9zV9Y+G/GFtYwo6amzbl+dW+7urS0PxBo9vrEIm0+3mRvmdmT+Ffmarp4+UI8somWIwMZ1OaEjxv4B/s4/Ej4ra4nh7w94Yvry8hf54Vi+Zf9r5q+of+Hef7aXw2sbOy0TwlNpR1Rt32xmWTav8Aur92vaP+CXfx78K61+1xqs2q2tqkNxZrBbsyKqrtX+7X6hahq3gy+SHVdZtoZhHcf6PGv3VX/erycZj8HKs4zgb4J4rDyU4yPyP+PX7Gv7QOi/suvo134wuNUeRo7jV/M3M7Rr92Na+Xvgr4q1LwD4ojsJ/Mt5redV+Zm+Vf92v38+P2k+GPFHg/+ytH02FILhd8qxru3f3d1fin/wAFH/hvD+z7+0Vaa3Z2bW9lrErblVfkWRV/vVxezoTpezpn0tPNq8asakpeR+ln/BP/AOMj6lpdrai52TbP9Y0v+s219P8AirX7LxH/AKfcoqOzblkb7q1+Wn/BPf4xQ6tJDbb40dW2JIsvzV+g2i61L9jhs73zk8uJW/efdavn5c1GnKEz6nDy+sV/alr4sSQ2ugw20z74PmaXam7/AL5WvzS8YeIrbxl4+1jW3vN/mX8iRMzfKsa/Kq198fHbxc+n+AdQ1W8m2w2NhNKqr8rN8v8ADX5w+H795LOGGbcks251+T+8275q+p4QwsVKdU8HiLER9rCkbdm0MkKuiK7Mm15F+6tW7G1e3mBhRZG/vb/l21Db3Ttsm3723bvLX/0KtbR7fdjzpvvLu+5/47X3nJE8ajUjyayNCx0/7ViZHZdrq33flatCDT0kZ50mU7tzbvu/980zT7V5Ff8Ac7m+VkjZvl/3a2LWzmVmKJ/rvk2qn3f92tOX3DSVbm1j9k+TfiPFt/aq8hwFxr9gp9hiHmvrSTT3/wBptqbdq/8AstfKfxLEs37XSic7WbxFp+SWzjIh719k29vJJbNM6ZH8G5fvV/QnjNGLyDhlP/oDh/6RTPzngmaWOzNv/n8/zkcdqHh+GRikLrEW2+VuT5v92ue1Lw7NcLND9m3bf9qvQ7nTXuJPktt0Tff3fNtWqbeG5o5l8lFhVfmTbX4HGn8J9vUlzR9Dx7WPDu53hztdk27W/hauS1zwz95ETy3V/wC5t3V7lqfhV0uJX2N+7fcsi/xVymqeE0uJHhewkd9+9JG/hranH3jx61Q8Y1jwjmMwoi4k/iWvONdsTa+IZbDptkVfl9wOlfRmoeHXbdbJNHujdtyrE1eF+NrF4/inLYbGDG8gG09QSqcfrX7/AOAK/wCF7Mn/ANQlX/0qmfnnGdRTw9G3/PyP5M5zXvCqNC/kuwmZ/k+WvP8AxN4T2tvuZmO776qvy19Dax4TmWMJlW3Jt2/3V/2q4LxR4UtmWV3tsiRq/BZR9w+h5j548QaO5mbnG3+HZVC30mbcrois3+1/dr1nxN4PRVa5RGH+zXMN4TuVk+RN/wDstXPKI+ZGVpujzsrJ8vzfxV02l6Ci7XdFU7dvy1f0XQZ2X57bb/dWun0fw27SLvTKL96Osvel7pXMZuj+Ef3avBtQs9bsXge2hk3ptdVi+favzLXT6L4bto1bfDI7/wB3d92tu10OFpgjpJEW+Z44/vVXLyyMjg4/Bu5WSzTcm3duZfmqez8Mzbd6QfL93aq/xV6Vb+G/taN5J+SOVd3ybWatK38HvcL8iMP9nZtVaOWEiZSmedaf4Jf5fkbeu3/Vtu3V0Wm+GUV9nk7nX5VWSvQdN+Hv2ciZLBvm+/M3zbv9rbWvpXgVGupJpnbb935ovvN/DWcqZtGpKJwOn+EXLCZ7Nh8u3av3auSeB7n7RsmOxW+Xc33Vr0aLwWl0qIPkMb/dVq07TwPZiMWz2bFGT7zVzVKcjqjUieQal4IdVf7NCsq+VuVY/wCJlrmtW+Hv7k+enmSfeb/Zr6EuvAtsFlmeGMPHF8rMnzLWFrXgeGRn+dV8xdvyxfdb/aqJU+Y2jU/lOUhV1jVEk2tvbe0j/KtQSb7TYiW28TM37yNvl/4FRNcPbzY+YxMrKm77q/3az7jULmTdsRsq/wA/z/drzuWUT9Bj3Jo4/OmV3253MzMr1W1Szh8n/j5WIN/e/wDZanju3fe9mIUfZ8v+7/vVHcXUL75bm2VDvVdytu21Xs+VaF1Knu8sjntSs3aF96RlGTb838P+1XH+IlRo5kfb/d8yP+7Xb30ryWrpZ7d7btnmfdZa47xRDHNuT7NhVf5/4f8Ae21n7E8mtHl944fUm8uTZvYiljmtm2+v3fm/ipdSWKPMyTMjSfMn+7VL7YhZEh+V/wDnpt+7WUo80Dl5vtG3YyJtJQ/99VsaG0kch52J95d1c5ps0kapC864/vN96tWzukkYTQuzDY3ytWfs/d94mMk58x0P247XfZxs/wCBVZWR5IWT7i+V95vururFh1CGaF7bfu/dbtv93/gVSxXUMLC23/KqbfmbdUezny25S4VOWVx+p+alqY5/mIIw3r71nT3csFlIsJBYfMq9/rVzULnfGYghwCArFs9qyr93jJbBCsm0sK/o/KIy/wCJZccv+o1f+k0T4LGz/wCNhUXH/ny/zmUNS1fz5Cicrs+9/drBvLmGOIfZkZdvy7t1X9Um2yMkM37tvlf/AIDWHqUyTZ2Q/P8Ae2/3Vr8DjT90+qlL3veKd1qz/aFhd1Y/3lrN1C+8sFd+7b8tQ3115Mjv5mP7tZF5qqbsPNh2b+Ku2keXWrcpZutQSPbsdgn3tu+rEOveXbhEfd/tL91q56bUk3F32qFam298nzP527+8q1tHzOb2k/iOqh1JJJFeF1fd/wCO1N/aW5Xhb7rcbv8AZrmdLk3SLsfaV/vPWtHcJ8qHcfkrX4ZEc3MapvPOZXfduX7/AM9LDcTTf3l3fK1UoWTzN/8AA38X8VXLRZ9rJv8AvVlKRVP4tDSs5H/jPzfw7auWt15cfycf7P8AdrNgmeGQQzfd/vfw1dtW3fcdiv3axlH+Y76cepuQ3CzMm/air/Ev96r1nfbZh8/yqrbl3fK1YdvhVWSeZURm+WtBbwsSm9U3fdX+KuaUYHdT5o+8bdrdOtmjo+ZG3bPk/wDHWq3Z6jGkOxNu7+PduZa5v7dNHu+Tbu+b5qt2OofKiOy/K25I68+tE7qNSPMdAtw822yudzov3dqf+O1eW4/0hJrbzEb7ytt3Vgx3Eyx/PMzL/F81aMN06qruGx/Gq/dWs5Rly6GlTlNyS6mUoEDKGl/esy/eq3ayJNJshRf4f3kf/LSsizmSa9RJkkdG+ZK1LWGaNTND8iL/AN9bqwlGPL8Q/imXVj8+HYjqm1/vL/eovIdrfZkdvKkddm35vmpxm3W6I7t9z960nyrT1a8ZRsRkKp8nybl2/wB3dWdTnj7p0x5ZbGReLMu7yZfM8lGVG/hrE1C3SSF3S5bKqzMtdLqFj5Kymz8sR/3Y/m+asO6tXCiC5T/a+VNtKMftFnL6nbusLo8Krcbt26T7u3bXLXlq8bF5ua7nxFaurbIU3Pt+T+7XLXVq80jvDCr7vvbflWuunU925co8uxymsWs25VjdlH3tv92s26h3Mfn3N/erevLH7VMyP5ny/wANVbjT3/v/AO6tdlOpy6HPy8xgfZUG5E+638Tfeq5Y2OGjLrz/AHattbpuVBGrMvzfMtXbGz/5Zu+5WTdu/u0qlb+UunRjH4ixptjGrb/OVpf7ta9nCnmB4UZd397+Gq9nYwx+U/k5f7qsvzVqx2T2u5H6fe/4FXnSlE2lTgWre33SK+zDr8vy/wAVamnwvHN50KbtzbW+T5aq267ZN6vlZE/i+atSxjdW+d8P8u2NafNyw0OXl98vafa3W75A33/l+f7tb9nGgtxv3Ef6tNy/NurJ0+H7RtTfIEk++392tiyZI42tkmb5UVfMX5vm/wB6uKV5S906qfu8rNHTYZlkRJtvyKy/N8taW394sKcr/Ft/h/2ap2Mf2qQPOjM8y/PI33W/3a2bRd8Z+dRti27WTbub+7WfNyxOmO4/yYZJFk2bmZWZGb+Fa0tLhRZYnh3FdvyMzfL/AMCqjbMjKqQwyLJ/Fu+7Wxotvc3kkV5CmFX5UVX+VaunGHxHR7SX2ToNNaGS2/fbWib7nl1v6Xpv7tHTbskfc/8A8TWTo9qk0SJMnzM+7cz/AC/8BrptJs/OZETb9752/vV6WHlze6c8qnNEsafpKQwuIYWBZtyNt+7WlbxusgdE3fLu+5T9PhuYY1h8xn2pteppLNI03zbirfLF5f8AFXTT5y6dQl0+b5tnlsG/gkjb5akj3rM2x22bNr7Yt3/fVQW9ncxsz723r/Fs+X/drT0u0uYYS+/zQq/P8m3bXXGXL7xUpfaHQ2XnL52/733FZNu3+9U9vYv5fzoof73zfxVetdNe4XZczRsFRf8AV/KzVbmtsW+wv5W7/gW6t4zlE5KnvROS1aGGWRXuQu2N23xt83+7XI6pp32qT7HMjOm9Wf5a9B1S3hktpd/7tWT+FN1dj+y78JU8VeLG8Ya3Z282nw7fsa3D/wCsZfvf7y152ZYilh6UqkzjjH2MD6N/4Jf/ALIGm+CJE+NPxJtrV9YuNy6Tbybf9Fh2/eZf7zV+ieheI9KsLSO2u7lYxt+8z/LXxLp3xqs/DP8AoGmzQ+c0Gzy2+6rfw/8Ajtc/4u/a01La+oKkluF/cRSLdblZlX+Ff4a+Jo5tiY4z20DzMdTjiYKMj9ErrXNNt7H7e1yoi7Pu+WvmL9rL4oXllpeqvpN/DiFsvub7q186L+3x4kj0G00S+1hY0mn2tJJ93av/AC0X/a3V5n+0h8eH8SeCJfEOj3LXc1vP5Wo3E1x80yt/s/wrXsYzGTzeirnnYanHB1ec4zx98cLy61SRE1XzvMXbuX5lb5vu7v4WrHtfjhf2dv8A8fkySSfcVfmVq8S8dfEHTbZv7Ktr9pJmffuj+7/wGszTfiFNYWf2b+0vKVX2v/FXx9XLakp8qPtctziVOPxH1N4d+Oty9vs1W5VE2fuo/u7v9qpbz4i3PiSN7Cw1j7P8isjN95a+XNP+KUN9Iba5hZHjT5ZmlVfmWut0v4lQ+IIYrl9eVJWRvN2t821fu15OIwU6J9TRzql7I+jtB+IFta2z6bf6/wCb8/735f8Ax2p7f4kWdjmzs7+TyfN3QMz7dv8As188Dxpf29q8NhcqPO3fvG+b5v8AZrO1b4ieJNF0+K5h1iSRd/meTMm35vuttasPqs3H3RfXnUlpI+jdS+KVtqEySJNveFvk/u/8CoX4kaba3CTWfy+c6q21/vbv4mr500/4mQ6q6PDeMjqm64Vfl3VteH9evLr7keXhRl85flX73ys1ZRw/vHVHE+0peZ9IaT460pZP9JuWhmWVWabdu/4DXf8Ahn4gaev2d0dmMjN9nkV1+7/er5f0/wAVPDHEZnXDNtlWFf4v71a3g/xxeR2Mi2z+Snmt5G3/AJ51M6LU+amcdatDk+E9G/bG/Yn+Bv7cXh+G2muV8OfEJVb+yfF0aL5Ujfww3P8AeVv738Nfk38afg38Uf2efiJefCX42eFZNI1rT7hkRd3yXi/wzQt/y0jb+9X6p2vxS+1WlvD9sk8jb97Ztb/dqt+0p8Mfhz+2R8FZPht8SLaP+29NgZ/BfiaRf9J0+Zf+WbSfeaNv7rV9nkub1eT6vivlI8lVquGnzUvh/lPyUjhfaqbMn+D56u2qoqNC77lX7yt/D/s1qeNPh74n+GvjC/8AA3jCzW3v7G6aJv4VkX+GRf8AeqhaqFX5/mC/f/ir2Kj5dByqRre8iwrTSQqnnbfnVl/2qW13zSNNcw7FWXYm6lt/3Ku8NywMn+xu21b8iGO3EKJvDfNub+GnGVonHKJm3kkMMZaFG/3W+9WPfW+6KV4fk2/wsv3q32hdWHmCPym+batULrT08kIhbDS/Oq/w1pzcsomfvnMzWIhX+JWb5vLVPlaqf2N5I/O8na3zfLu+7XSXFmJI/kTDL/D/AHqq3WlvHH9xtrJ/rK29p79zD2ceUytLs7mRR9mkZXk/i/iWuy8L2M1vMkO/dt/56JWNp+mPuGybZ/DFIqbW/wB6ul0exkjZUmdt0m35v92u7D8sjza8pRudtYwp8pebzVVF/wBX81dPat9nvP8AXL8qfIyp/DWT4fhhmhRLaaHaz7kjjT+L+Kt61t/9HVJX+Vm+TcnzV6NOnCR5dat2OH/aCib/AIRaynMxIa/G1G6gbHrb+B0TyfDa2ji2/M828K+G/wBY1ZX7RoI8L2O6Ng324Bjtwp+R+nvWx8B4nf4eWRVFXE8rBh1b94etf0dmK5fo2YJL/oMf5Vj4GE/+M2qv/p2v/bTsLfyZv9S+wbdqr8zbf92rLbFtWS2i+Tdtbc/zf7O6oWjeSRVSFtq/LuVquNYpHMv77en/ADzb5a/AuZn08ahnahElwF2XMg/dbdv8K1k30c11Gd7sU8rdu/hbbXQ3UM19+5hLFo/v+Yn8NY98s3lqiPHsjTa+6rNI1pdDz3xcvlxlLl9jNF96vK/FFr5lt51m6tGr7kZnb71eseMJEmhSZIV+Zm+78y7v71eZ+JI32ul55Jf737v5VVqqMZcpccQee3yyySfI+5W/8daq91JtjV3hw6/eZa1tQaG2ZvkXdu+fbWYypMzok+5W/i/u11fD7oqlafIY01w8kbd/mXYzJ93bWdfRvH++SH5meugutH8yRUcNhk27ao3WjuqMiRt8rbd33lWq5uX3Tikc7Mz+Z5OzP8S0sLbmOxN4b+H/AGq0brR3WYL8zfLtqKPTdrNDs+9/EtTUj2IiuUfp8m2ZXmfG3+8v3q2rG6SGRJv4Nn3l/h/3qy/LRfkdGZl/hq3b/KrJHu/6Zba56kTppyN6zkfbvfaV27kjrStbrzI/n3ASLtrB02V7XbHNMy/wvurVt9nll3dv4di15eI5vhPUoy9z3TZsdWuYZEcJ91PvL/DXQaXN9ujWaYMwV1bb/wCzVysMc0i70f5o/ubXr1D4IfD+68VagXeFiN+zzmXa1c+Hp+0nZmlStHDUpSkdL8O9U/4Q/XNN8T3jsj290ru27crLX7j/ALL3inw9+2r+wVf/AAs0q/3a94biWXTvMX978q+ZDIv+98y1+O/xi+G+meFPCqabC6veNF80avu2rtrf/wCCbX/BSXxV+xj8aNO1LXLy4m0yGX7Lf2twzN9qsWb95/wJfvL/ALte/wDV6So8qPlIYyrPGe1ueg/tHaPrFrJeWdzZyQ31rcbZY9/zRyfxbqd8I/7Vm8L3NtMnnfut8Tb/AJl2r81e8/8ABULQ/h/rnxc0n4/fCrVrS78LfELRo72C5g/1Zm2/Mvy/xV4t8PdHSCGbTft+yBrdvIX7q7dv3W/vV+TZ3gvqmKcF8J+65LmP1/AQqr4vtHxX+0p8TLaz8aX8Luyta3DReXInzbl+9Xz34g8dfbppXS53szs27fXpf7elnf8Ahn4jX9qjttml3Juf7zV82x6k/nb3dldf4f71e5luDpyoRkfOZ3mVWFeVI321Ca6mZ33YX/x6uY8U3U8OpLMi/wAPyNWlpt+JmVJvn/2apeMV3+Xzhfu7q9ChD2df3j47EVHOOkiva69qdxshT5tvzPXbeGNaeZ0hub/yv96WuV8N6TD5e9Pv/wAH+1XfeHdL8K68YrfWLNYivy+cvystd0vZSi00PC06svikd74T1DwlJCs154thVY0X5Wf5m/2a+hfgr8Ifhp8SvBtzrdt4wt5b2OJlt4Y/mbd/tV8leIv2edN8QN9p8E6rIVVdzR/aK1fhL+zr+1FHqyp4GuJi0m7b5dxt3bfm+7Xm1sLKXvUqp9HhYx5eSVJ/4j6f/Zt+BOt6P8akvNH1KEXFrL/rGn27v9lVr9BbXUviRoPg9LS/1KQszqy3Xm+Ztr8o/Bfwn/bY1LUEvNEh1CK5aVommjl2s0m77q19n/AXVP28PCNumleJ7az1WG3ZYIrW4uF81m2/er5/MMFWUud6noU8Fh5UrLmUj6ns/wBpea10/wDsrXnkeaG327d22vgP/gup488N+Mvhp4Q1rw9qSiez1sK9v8vmNu+81ew/tfa1488L/Cm88W3NzY2epQxefOsdx5jRt/d3V+VHj34ieO/jNr0dx4z1iS+8uXdFDuZkWubKMNXljFWlL3Inj4qXsf3U/iZ9Df8ABPn4sXPh/wAdW9nNfrCkku6WRvm8z/Z/3q/XL4a+LptQ0O21BPOe0mt922T5mr8ZP2WfCuq6f40sJlTO24VtrL92v1q+At9J/wAIvau7yNHDAq+S38TVwZrKP1j919o+y4fqShQ5pmP/AMFBviJZ+Ffga2g6bN/putXUdm8kj/6mFvmbav8Ae/hr4+0FoVFvsdc/89GX7q16T+3Z8T38d/F6PwxpTq2m6Hb/AOlK33pLhm+Xb/urXnOgwOrI8Pl/K+7dJX6Rw7g/q+Xx5vtHyOc4z6zmE3E6vTwjRhIX3+T83mbPvLXQaPamfEzoyIvKKr/M1Y+h4+QPNGX/AOWu37rf7NdNo8MMMiukMfzP8zV9JGPunnRxXL7sjW02Oa3bf9mZ5GXYit/FXQWULKoTZ+7ZPl/i2tWbp9r5m25/ebtm5WX7q10djpEKxqsL/K3zOy/3q0p0/tG/1qX2T4z+LMYi/bP8tTwPEum4JXHaDtX2xHavNbmVEw3yo7Ruq/8AjtfFnxiR/wDhtp45Ov8AwlOnA/8AkCvuq108QqiJZ7du3ZtSv37xnUnkXDVv+gOH/pNM+D4TrSp4zMX3qv8AORlSaTeRTJJ8o8tvn/3ar/2Lu+SaCSLy33IyxblkrrItLRpl/wBGy7L95U/8eq5Hob/JD9p3JH9zd/FX4bTp+4fW1MVOWxwOpeHd0k1zbQ+T5j7Nu3/x6uf1bwzNukmePDruX5v71evXmgQzRpC8LF1/5Zs/zNWVceF3aTfcuu/ezfd27av2bOCtWlI8T1Dwe8K+d5OxZG/eyRrt3NXy18UrIQftIT2PzN/xOLRenJyIq+877w+8W/f/ABP8rMn8NfEXxmtjF+2DPa8g/wDCRWA6eohr978BFJZ5mKf/AECVP/S6Z8JxbO9Cj/18X5M7vVvC6XExeNWi+Td5f3d1cZ4q8Fh45IY3ji/i3bN1e96t4TRvmmhY/Jt8yuV1nwe9wrQpDHKI9zqrbv8Avqvwj2cZaH0fNL4j5z8QeCZmtdkzqzxysv7uL5mX+HdXNXHgV7Rmn+xsW2K391a+gtY8GzGT9zFJNu/6d/m+Wuf1T4d211IFmsGjKtv2723VhKPKOUv5TyvTfCs0dxsWFnddquu37tdX4Z8N2t5MstztiT5vlauvsfBcax/Okm/723bt3Vd0/wAL20EZ2QMx+bZt/irl5eU1jIzLTw+kcafuVYM3yMq1vab4PhmukuUjVH3bHmki/hrU0nRZrfZ9mDFWRdkbfdWu00fw+7bYUeOWNfmeRfvbqn/ETKUTk7Xw66xpstvvS/e/9BrpND8GpNs3w/NG26WORPvf8Crq9P8ADKK6JdQx7F+ZIV/9Cro9H8IwyI/kp95FZ2an7MzlLlOQtfBO20HnPu+bd+7/AIv9mtO38Jwxsv8Aofm7fvyV2mnaC7ZmRF+X7v8ADVibSdqo6eZsjTZtX7rUS5fhCP8AeOQtvB8MCvss4ZJvN3bvu1pW+jwyM3yKsUafdb5a3bjR5rhd7pnc3/j1OuLNJF2TIpb+FV/u1zy973jeMjmptHtpoXS2dS8ifxJXO6x4fhWx+SHb97zV/vV38lv5M37lF2/dVtn/AKFWL4is0nkKOn3U2oy/N8zVHL9o15j5G1jXEWNobaHdt+RPm+6v96mW9xZsyfJH83zNJ/erDXVH3B5n3yKu3938tT28zr86PIg+9FHt/hrz4x973j9UlyRN2aZ4VDw3uEZd23b/AOO1FdRw7jDMmU+/uX+L/Zql50jTDYm0Mu35m/ipsk1y10ruy/u/71KXuyFUlSUSWSOzyyfMjqv3WSuQ8UW7tHI95MyvJ8ybn+6v92uq1C5TzBC9zlV++y/ermvGF0kkMjo6uioyJuX5qiXunj4qVP3kedeIfmUOhyivt3bKyZLjcySbNp37dy/w1d8QTTeTvR8u331Ws6JoWVt7tv21ly/ZPMqSNKxa1kbzo/3rKnzLW5b3U0NuvkouyT/vpax9G2TSIiTbm/j+St+1s/mh+dn/AOAVPu/CLl93mLNusKxbJrZtm1W+WppI3t4hvhZD/u/NT9Hhht8u6bHV9z/N8rVeuG2x/wCjQ/Ps3bm/hrTl5ZFe9LUy5pHkXe7q4b7p28iqV+Adgcnbn5s9PxrUvmhKEovJPpjFZl9gKHBIKZO4V/Q2Ur/jmnHL/qNX/pNE+GxVlx9R1/5dfrIwtYzJ86Kzfxbq5XWo5mjZ0dvlbcrV1usSOzKURtrfcauZ1yRJLffIm3b975K/B6fuwPqK0uY4vUprkZR3Uise4uPmL7FYVr65sWZ/J/irFa3273j3bl+bbW0feiebUqEEk3mBdnzBqjt/3kmwfe/u1L9jf+D/AIFtqazshGxl+YMvzfMtax6mPLKUiWzV/O3zJzW1ZybpNsyc7P71UbexlWbzkfiT+Fq1bexhaT5Ou7/WVnKXMaRpyLdqnmbOwXcrrVqH5WV5d2VXbTLW1+zqofa7s3z1pRwwqyzP5h3bl+VflrOUonRToz2Gw28kjf3/APZWrsMLQquy2yZNvyrUkdrN9nD2m0SfKv3fvf3qu29i+7/SQvzJtXa9YSrQPRhhyNbeNYd/zZZv4kojk23Bd937v5dzLU8mnvn7jHdu3fPTo4YZLdPvY+Vd1YyqXN405SkKo+0xr5z5P+9Vm3Xb86fP5f8ADSW9qirshj/i+T/ZrVsdI+z4fy1bcvz1wyqcp3xoyZBp4dl3/L937rP96tOxZ5Jm3/xJ95f4aZBZoqo6FgjfL/vVpWNvuj2TTf7W1f4qz9sxyw/wl2xXbJvhG5G+SVV+9/vVoqzwuvlJJKi/f+Ta26odNt9saoiKG/8AHq14beQwrsmX5nZqx2+yUqMpDtNVCp8587tzOrf+g1bjfdt2JtGxm+X+GnfZEjt1cJlt9WFhRLfyYZtrKjbP9pq5qkuY6adGcfdMq8s4W+R9xVv4o/4az9SsY7htkP3N+3c38VdTJYzSKuxGKyKq/L838NZlxHc3EKzed82//vllqPacseY6Y0Tj9YtXw7unzbtu1V+bbWFqekvH/AvzJ96Su3vbNJF8l0V23/O2+sfULPcwR04X+KtY1vdKlTkveicDeaO8MjTXKbwybt1QTaPz5zwqr7d0S/3q6rUtP8tlTerhv+efzbqqNYIsLwoigyLu2/xVvKtfcccP7hyEmlvLG1zv8ot/Ey/dqWz0mbzCjvv/AN2t+TR0ZVk8n7vzKrUv2O2WH50YSqvzqtONb3glRj7tira26QqEh5TdtfbUsN5u3IiK+3dtZlqd7dI8JCi/N8zyN/F/s1XkkhjmV3RkVvlX+Koi+aXNKJzYr3di5bedN/o3nKvzbvLVfvNWrpq+ao8+22tu+Zmf5qzbVvLYTI+S25tuz7tX7GbzP3yzbGaX5GZP/QqKkpSukccVblZ0OmrJApSH5UVtv3/lrX0+N7Zd9tt+aVd/l1l6TCkxKXMPmtJ8qNH8u3/gNa+nxpJMv/j38O3/AHq4pS5dTujH7Jr2Ci3hR/3bBd25W+9/vLWhprbSjzOxMn3t1Z1va7m8mFM7v/Ha0rZfMZnuXZXb5f3dZS5ebnR0R5paI07e1s/M8523bW3bd/zf7v8Au1f0X/R/9Gmnbf8Ae+5tVlrJjt7rzP3MyskyfN837ytbSFS28v7S7RL/ANNG3bWraMhxl73KdhpdvC22ZNq+X823+7XW6PC80cTwu0RZdv8Avf7VYHhuSGOPy7ny2b5dvyfNXVaTpsMN2l4lzIjqm3bt3K26u+j7pz1Jc2poWe+3kQb96N8m1v8A0KrUivKI3h3bVi2rDVjT4YZmWFIWZvvbv73+zV2Gzfy3SNdu2u6nH3yebl3kZdjZzPH56cu33WWtqS3kt41fzmDq6szLUlrorwbrZEkyzr/urVptPeG2Z7Z1Yfeb/arqjHmmTKpHlC1muYWR965b5vLZNzMtSSMgVZt8jIqM37z7u5qqXENzYs815DNv2L5Uiv8AKv8AvLVLxR4is/B+hvrep7poV+SK1h+9JJ/Cu2lKXL7xcYxivekUb6aHxB4msfBlsit9qlX7asb/ALyOH+Jlr2WHxVoPhvQ7Ow8Mbozp9v5Sw7PlVVbbXlPwbjhaxuPG2oJNba1fSsstvMu3y7dfuqv92svx546mt9QmEMzec27yvLfav3vmr4nN608dX5I7I8qeI5tYnoPjb45f2Tt1b7f5b/c8lvmVv9qvN9a+Lbyag9s8zO7SsyLC/wB7b/FXlPiTx5f65eXNzebkg+9Esj7a47xB4+ubOFvOH72P7iq38Vc2HwconHKpLlPWtU+LVzYRpNrGpealu7eVNsbzI9392sDXvi0mrW7zQalNGknzSws3ztXjs3xUmurp7aa83+Zt3q3/AKDWBq2vQ3E3yTMg3N+83fMtetRpyj7vLZHDUlA6rUPFz6tqX2lIZElkaSL5n/1f92qTeJtV02NRCivMq53SfxVxmreLoWV0SH5o9vzfxSNVVvGVzdbH85Wb7rR/+y05Yf4ZR3NadTlOyi8bbnM1xMrPJKx3bPmX/ZrY0H4uPDGlg/k2yMqo/l/N/F/tV5hNqySR+TbJjzPv7v4WoWW5sz++2t8vyMtcOIoX+I7YYirDXmPoLwz8RoZoxZ2dzM+2VmlWb+H+6y/3lrqW8RalqSx2GpJHcov+qaP5dv8A9jXzpoOuakskPeT+995mavV/B+vareXu+5m+RfmVWf7teFjKao1eY+ky+tOtG1zqLOO8s9Q2JCw3PuRf4W/3mrv7e1TTWhtoftE1pMi/vJm/vfeVf+BVm+HbOw1K3SbT7Nk2qv2hpv4m/vV31n4YeTTftKQ+Yse1fLjTd5f+1Xn81KUbdz3KeHq/ZHLpaW7ollN5TLtVF/iaur02OHTYUjtp40O7/lsvyqu2sq3082uofaba2Zo2Tasn3vu/7NbNv4fs9c01/wC0pZH2v86q21l20U48vuHPjPaxNbR4Yb6z2XKYXerXDKm1dv8As1ft9K1Jr53s5sJ8zRRt99am8L6PDdatbaPva6e4td8Squ5lVfvK1ehWvgPTbhbc201wRGjK67dq7m/vV3wwc6nvXPBrYyVP/EfE/wC3h8IfEPiTRR4ntraO4vtJTzfMaL57iP8A557v9n71fIEUSQyNDCGYq1frt8TPg2niTSLjRL9FvEki27Vi/eQx1+WPx0+Eeq/Af46aj8OtShkis7yVrzRF/vRt8zLur2MDip1L0ZrYijiPZy0+0ZMMyKoeZ/lX722rq/Zo5Aj7v73y1m2bIblERP73m1oQyPKo/crK33fLZdrV2c3N7p6cY/aHTWfnMIf3aGPb8q/e2/3qi/s+5h277Nj97ay/db/arSX7H53kxpuXb97bUcMeJj5zt80TfwbttKMdTUxbrSd00yb/AJv42WoJNNSRS7zMWZNsSt91tta9xHMs0bvNub/lru+XdTWRPs486Fldf4mT7v8AwGupx5tTj5ox5jEs7F5psTQsir/DW7o1jcw3nnXNyrJH8tRW6/aIHSGbf5jfPIzVq6Tb3McyQwwSOF+X7nytXq4WMjxsVKMdzsvDawrDGkO1GaL5vL+81dBYqjR/adjfKytub+9XLaXHIsKTI7K6y/e2ba6GPfNAyNMq/wB/59u7/arujRPFqyvc4v8AaMEX/CJ2j4AkbVA7DuQ0bnNbXwHUp8M7N1uZFDyy+YqHPHmt2rC/aLLDwppySKu4Xgwy/wAQ2Pyfet/9nxlT4eWgYlAZJiWDdf3jV/RmZ6/RswX/AGGv8qx8HQ97jOr/ANe//kTuY5IYW/dw+Z833lfbtbbVl1cxtN9ojR/K+63zNu/3qrW8LwrK7zN+8XduXbT0VLeMu6SSDZ8yt95a/n+NT3uU+r5BGuXbT0tZpvlX5t2/+Kuf1a8muIX2Qq259qfP/wChVp6hvaNXh+7s+aNfvNWNqkkMymF0w7fNuV605mTy++cP4uXZl5nZdv8A3ytea+KI0ZZH353bVr0vXkebzUdMqyfvdzfNXCavpv2mQ21zDs8v5dv8X+zV85pGPKefXGlvcSOkKMzs+2n2eivHGd9ts28fKn8VdZHoLzXDpbfK0fy7m+XdVuLwwi2/l2yMz/xtW0ZQH7PmOQk0FG+583mfxVRk0RNmxE3/AD/6vZ83+9XosPhU3kaeZujZU+6qU5vC6KrDyNyt8q7lq+b7MROjOR5Y3h0LcSh4cTKnz+Z/dqhdaLNGo2PtbZ/dr1ibwTMsnkyp8jf3k2/8CrO1Lwn57ND9jZVj+X7n3qFKcTKVLl+JnmMGlvIpjc5f+Nmp8Gm7W37M7V2qq12eoeC0hzNbJlf/AB6s5dPS3VUeFnZX+TbU1KcuSVi6fumMLXy1+4zGRPlWT7q1Zj3lvLTlo/4v4WrqtD+F/iHxNcH+x7ZndU3LGq1zFxpN5pNxLbX6MNsu1l2NuX5vmrglRnI3jioU+p1Pw58N3PiTWk0pOszrsjX+KvqT4W+GbfwFcJc3m37LGv8ApUm/cqsvzV4b8B/EXw30fxxpqQ6rGbmaVVTzE27W/i3V7d+1l4ssPC/w3v8AR/D2pbb68t2g8tZf9XuX/WV04fD+z96XxHmY3GVakuX7J4l8Xv2pFvviJfHStYjmhjuGT5m+9XCeI/G3/CZM2t200cVzG25I1+ZdqrXzzr1rdeH9Sf7TqvmNJu37X3V1PgvUr+O3+02E2/au371dP2ji5ZH1r8Cf24fFvh34er8AfHN5HPoUN19q0O4un3Np8jfejXd/DXvfgH4sJeXFo7uzxsisy/w/71fmh4g1x5GfenzLXsH7O/7Qscyto+pXkkdzCvztJL8rba+Q4myv6xFVYH6BwhnMMLP6tP7R3f8AwUk0Oz1TxwdfsEkKXEW77nyq22vjq60m8hkLv/31X1b8ePiVpvj7SYLy/uZnkt/lZm+bcv8ACteMtp+laluRLmMbvvbVrzsoqSp4ZQkjvz3DxrYlyizzqOOaFt//AI9Ud8v9oTrbRorbfvbv4q63WfCP2GRXhT727+Cqmn+FftTb3/75r1qctj5lU5RdpRGaTZ+XboiQqp/g/wBmmXs81uz+TNhlrp4dFe3t1R03SL8u5qr2vg2O/vlSTcp/vfe+aq5oc/Mdvs7w5YnJ2PjDxJo82LbVbhP+mcb/AHq9Q+FP7VXxI8F6hDeWErbY/lSTdtbb/FVPRfgrYa9qCWb3Kwqv3vMf73/Aq+uv2Zf+CbPwr8XfYLnxNrcjpcLvdY03LHu/irixVTDP3ZnoYGjm9OV6b90j/Zt/batr/wATW1h4k0qYFpWaLbL/ABf7NfavgX4naP4phjvLOwktXWLd533lb/ZrH8O/8Eq/A3w/0mK/8MagtwkK+as01qrN81b3h/4S/wBkXj6XbW0kf2fbuZl+X/gNfJ5knze5L3T6/AzxdaP74+ff+CmXiOHQf2dtf1F7Rityvlwbvus3+zX5x/A3wO2rXLTum/dtdmr9if2uP2Z/+F4fBe98JfZvnaLdb7n+833vlr4C+Gf7NPi34f3WoWHiGzmhe3+VN3zM3zVODxtLD4CdNS94+fzbDVI46Mp/CdP8BfAZh1y3h8mPMbqzyfNtX/gVfW3jr42Wfwg+Fr6qjx/bPKWK1WFvuzMu1W2/3a8f+E/hq98P6f8A29rEPkxx/vJZm/hVf/Qq84+I3xGvvid4qmv7mRls4W8qwhjfb5i/3mWujKcB/aNfnl9kyq5hLD4XkhuUYdQ1K+1S51LW79ru5vGaWeZvvNM33mro9Buj9oVHvNz7dyLs+7XP6Tp8MMm9Hkwr7vm+bbXS6LHDuV0+RY1+7s+Zmr9Qo8kIcsT5eabfMdjpcMMil3hUI3zP8vzM3+zXX6Pa3PnJNs3Rqm59y/e/2a5TR1NwqpNcs4X7kbJ93/arttHiuVbE1ypCpuT5Pl3V30/egY80vtHU+GbdGbe7rFE3zIsjfLXTaXZ219CmEXYrbkkZqwPDKoz7Emy8fztt+9XZ6THNcRtvSNN23Zt+9urf4Q9tLofCXxqtDD+3ibSQj/ka9KBIPGCLev0Es9OS3+e2eGSKaL7qr92vgP43nP8AwUEDCIp/xV+kHYRyOLav0QhhWFvOm8sKvzfLX794yf8AIh4b/wCwSH/pNM+P4Ym1jMdb/n6/zkVbCzSNk/ct8v32/vVsW+k21xsmS2hZv4V3/N/vU6zsf9I+dPlZ13KtatnpryMqO6gL9xv4ttfhEZH1UpFRtJtpFdEhWMr/AKrd81Zd54dRmd5uf4a7ePTUvrXEMO5VfarVDNosDeZcvbK/73akldFP3TglUPL9Y8Nw7T5ieair8q/xV+ffxytRF+3NJancP+Kn0wHzOvK2/X86/TzWtBTa/wC7X/ZVflr81v2g7Zo/+Ch0trJyf+Ev0lTn/dtq/evAdXzvMf8AsEqf+lUz43iaTdClf+dfkz6m1bQX85kR2C/KrbU+9XMap4ZvGmbzdyDazpJGu1V/3lr2XXtBdl2QQsvz7UZkrC1DwzctKdkauv3f9rdX4Xy8vwn03OeN6t4XSHdsRsbPk/2qybvwUjXCbEjfy03+ZH/F/wDs17FqPhVGXyQ+x2+b7tY114Xmh3PGisFfb8vzVzVox5RxkeYf8ImY2O9FZW+ZZKj/AOEehW3a5hhXY3yo392vSbnQ7aNZdkOwfef/AGmrPbw3Jb4fyYwsjf7yq1cco8xvGPL8Jy2k6E8cLuiRnzIvuyNt+auy0Pw/sWLZCpEn93+9TdL0NPtm+aFnHyt5f+1XXaLpyLcI002zb/yz/hrOQ5PmItJ8PeWqu9srhf8Almq/erobTwy7eS6J83ysy7//AB2rui2sMkboj7h8z+Wv/LNq6DSdJe6mR8KkXys0bf7VETOXNIyYfDbqoREYlv7qfLSyaF9njyiMX+ZdrJ/49XX2embY08nlY/uN/doms0bf9pk+Vujf3mqan8wRl/McbJp3lx7Hhkbcu35vmbd/8TWfdWv2VvLeRSrJt8vb/FXW6hp8MduPnbzGbakf8Lf8CrLutKha8eHyVc/Mvl/7X+zWEveKicjcWeyPZNti3Nu3bPu/7VZOoW6RqyQ2DO6ru8yu6vPD8zLE8KKq/ddd/wAy1kXmlpHeLDMm+Nvmdlb7q1Mqhqfm5DM8y74flff+6WrVqzx/vnfdt/5YszbmrBsby8tWd0/dfxRbfvVesZ3vmV3Kh1+XdXLL+Y/UJYiMqV2a6tfsE8tNr/wrI3ytUn22KBG2bi/8S791QWav9o+0wTbmZdm5vm21JJAlu6fuW3N8qSbNtZx5Dz62I5o+6Fx++UzfKVX77b65LxVfOrSXMMm3b8qK1b2pXX2WQ7PLkReWkX+9/tVx/iCbzmZ7noytuZf4azlI83mlzcxyepG6m+4i7W/vUmm2b/alguUb7+3/AGqlW3mk2Tb9w+X5v7tbuj6bDu3vbK5b+Fv4f+BVzSlyjpx9p7xJpul20MiW1tCxVfm+b+KugsdPkWRd6cN8ybv71Gk6XNHKz/NjZ8+371b0NvbSL9mkTasi/e/iWlDl94fIZrR+SrJ9m3bv4lSpfs/2iNUe2Z9vy/K+3/vqpvnWRYvl2+b95vvf7K1DcLc3EczvCreW3+r27qv2fu6B7STlqZOpwpGoMfG7llrK1BS0LBQS235VFa2oea8JEkMkIQDZE8eNvNUZ2WGza4aMtg4wDiv6JydNfRqxy/6jV/6TRPg8UlLj2j0/dfrI5jW5E27Nm7b/ABLXN6xE7Qsjuyov8VdBr0z7W3/N/E7Vz14zzF9nI27trfdr8Ipx5T6qtKETjNWhdm/1zBvvfN/FVH7HMzJJs52fPtra1C3H2ht74H91vu1X2/dffjb/ABVctjz6kZSKcNrtPzw/eq4sHmfuev8Afp0dn50y8bm3fPtrRsUTaZk+6r7W+So5kdVGiV4bXavyJurVsbG52xO6KgVtyMv97/aqaC2hZwibdkf32WtKOxdlTZM2Pl31z1KnKdUcHLsR22luvzhFJ37marlvp9q0jfexs+XdWnZ2byzDyY/9xt/3qsLpoEe932Nu/irmlU5o6yOqnhZc0SvZW/7xSn/LNP8AO6pfssLzRu+5z95/Lf5V/wBmpFs5mk2bFTb/ABL/ABVct7B5G3p5ar/e/vVxyqSj8J6aoR5vhIY7GFjv/ebo/vrJU0Nqkcmzydrt95Wq/BCYVh2bnP3WbZu3VZjt4WWHzn+Wb+JvvNtauOVaf2jtp4VfFIpw2MKws6Q/8B/+Kq5BY3LN++T5lXdtX+7V+O12ybH/AIfmRauWOnzTEu9ssK7fvLUyre6dEcP7xRt7dEyny4j+/u/hq5Dp/lTJ5M3muvzOqrVhrGGObyZvmfYzJu+78taGmKnkyzOipIrbIt33qz9tLluFTD82hLp9jbLIqI+5mi+dtvzLV/TdNdpGhmRdrfLtb+6v/s1FrYvGqbHjb5FX/aZv71a1nG8qrCkMasu7zWb71Z1K3LL4g+rSEtbOONlh8jIZ/k3VOunzQyPNcwsiybmiWpre18tR5yN/wH+GrDM6xp952VdqyVhKp73um3seWMShNGVaOa2Rt23crK/3lqhMHhYIYVT727clbF00AgWGB9gj/ur/AN9VW1SzeO3WZ9237y04y5i+WfIctfQzRzOkPl71+b5V/hrGvIXuJC9zD5zR/Mu5Plb/AHa67VtNhuleZJN25fkZflrn9Qs2uG3vtH91d1ae6Ryyic1cW6SMfs0Ko0n/AI7UFxGjbEmRsxuyfd+9W3dWsMMs32naNsqtuj/u0xrO88v54967922tvae4ZS7GHHZzNI/3Y0X+H+98tMWN2jdI/mZU2u1bMdrC0L3PnK33t0a/dWq8cSKrbIVUN95mojH7RnKp9kxLqPzV+Taj/d21UaG8kVkdNjL8q/7VbN5avAfuf7X3KrNbpJcpMPmZk27lT7tdMZW+yeZUlzS5WQWtvM0nmXKKT/E33VZa2tHs3muN+xUVUZvv/wANQaPCkjeXsxt/h2bttbGnWLtMN7blVG+7/F/tVlUlyy0RFOPM9ZFrSY5Jp97w4P3d1dHY2cLbnmeNkkX5W+b5mqjbx20eN6M8i/Oqr81bWmx7meHfGF3bkXZXHzc0eaR6FKNqliSPT38tEtvk3bd+75dq/wAVX4bOaONoYXZUX7u77zNVqGOHy/3PzOyfNGybvMq7Hp800nmeTlflX94n3ax9pKR2RjDm0KlrazSzLcvw+z7rfw1v6TYpcKHdM/Nu3bKit9PSaNbZ/Lfd/wB9Vt6VpL3CofOZd0v+rb+GtY+9ykShKL3NrSbeGRvOTpD8ny/3m/vV2+j2u6FA+4lfl+auY0uwS3/fbGab5vlX/wBCWur8OQ+XGkLvIUbbvb+L5q9bCx5oHnVpSpyNqztb+Fm8mHafveYyfdX+7Wtp+m+ZKghSQ7ovvL92Sp9Lt9tqybNyt8v7z+KtzQ9NuLe2S2udq+ZtZ2+6u3/Zr06NOWxwyrGfZaXeeWXfbt/5aqv3auR6bFDjiSZ/mVv4du6t2z0tG3wrwiuv3v7tXofDaTTulym7dt8qNf8A0Kuvl94iFaUtDj7rS0mtmhuXZ1k+Vv8AZ/2a47U/DL+JvGH9jWeqwpHYurvbzfxN/D/u1634q0N9N8O302+FGVdsUkn/AD0b5Vrm7H4e23gW3ttV1hPs95/qrpZHVvObd97zPvba8TOsRHD0LfzFV8ROX7sxPHl1Ba6GzOlraXO9URofvM38X+7/AHq8C1q6vI9auLm/vPMfb8jM/wAsa/3a7j4uWd/Z6lqdhO8bzTS7d3m7v+Bbq83urW5vlj0ewtmeRom3eZ91W3V8pQUpbHFL3vdOe8bWN5NZpPawx7FiZ/8AZ3f3q838YTGOFpobndc7F3ei16v4uW80XS4dEvLnesbblWOL5m+X7u6uAvvC9zrgTPnR+Y+3ayfK3+9XVRqRjPyCpGUocpwEOmpJdrvRWeF/NlkZ/utVDUr+S4vlmtk4+47fxN/tV6G3w9uby1EKuquz7V3Nt+b/AGv9msnUdD0rSY0s9Vv7X7W27zZI/wDln/s168ZUJSOCpTlGBwHiKyhtZIn86SZGTdujbbtrNWN7WKV/tLb1bdtZq6rXrextZEff5gb5nb+Hb/s1y2qahDcS/uEjf+4275lqJShIy96I7ztVnm+R90cm3Z8/zV0Gj2GvSRnYfNG75dy/w1z+l6hYStsebEu/dtb5dtdnpOtOrI6QqkLf7dcGMqOnGJ14f95L4jS0O8GlTF/3a3O3btkb5Vrv/A+uTLIHudr3DbV2qn/j1clayaVqGIYZrfd99Gk/vVoaXq02m33k3OpQskjf8s/4a+eryjWlK59nldqUo8x7v4Z8TTW0Ze5+5s/er/Dt/vV7X8JfG2la5o7Wf7mUbd3mN/er5NsfEDsv7nVW2sjL8392uy+G/ji88M3CWVtfraJ5q/Nv+Vt1eNiOWn7p9vQq0oy5e59VR6DZyKtzFCspj3bfLfatVZNH0/RdWtr+GFmhkb/R/MlZmkb+Jv8AaWsLwD4y+2aTsv7yNDDKy7V+Xd/tUN4qSa+WK5m3pbs3lfM3/jtTRrcs/eNa2FhWPq/wL4N8Pa1qFt4h0ezWK8ktVR5I28uONf4vlr0S3+HsMccsKWEm1n2o25f++q+bf2d/iZYal4qs7O5vJmi2/JHN92Nv/Zq+7fB2l+H9Y0BH0eITOsS/6UzbVb/gNe7ga1StC8JHw2e5XGnLmZ5FffDW20u5S5tr6F5W+WdfvNt2/davjv8A4KzfsV3nxE8B3HjPwBpsdnqOhxfboI2RmkkWNdzKrf3Wr798feHdH8PrLdXUKwlX3N5fyrJ8tc3qWpaJr2kC816zW9tpv9D8tm3L+8Vl3NW8sR7Ovz32PHpYSco3+yfz2WuoTTWcNzc6f9neaJd/zfdatW3kdY98MO2WNVV/M+9838Vem/tofBOb4LftEav4YOms2l3H7+wvFT5JPmbdtrzu3k+zn9wmF/h3V6tOp7aKkup69Pn5CbN1IwR33DZt3bf4aWSS5haWaa2/cbdsUyvt3NTo5XZltn8xXZdy7futTLjftV7mH5G/8dX/AGq3px98uVSJBcQpJvtpk3nbu3M/8VN2eTIHeZlXd8256hkupvtDuj/7K+Z/tUBoZrh7Z3Vnj+b/AGa66cZfCcNSUPiJIVufLR4UXzfmV12fLXQaLHu2PvZZN3975V+WsS1XzptkKNu2/wC7XSaTGiyeTbXih1+WVmX71erh48p5mI5Xyu5s6PIkd19mn3b1Rfmb7rLW3HYwQw5hhWRvv7W+aszT9kiqm/Zt++rfdat2zJvo0hmRR5f8SvtZlrqjL7R5lSPxJnnn7RPnN4NsHmYsTqCjIOFH7t+1b37P8UUvw4soZgcvLOUHZgHJNY37Stklt4UsZA25jqIG4dCPLetn4A27XPw3sXiYiaKSUxKG+9+9Nf0RmaUfo2YK3/Qa/wAqx8HSjy8bVV/06X/tp6DarCrSbIYwF+VFb5tv96kZkkma5RGby/l2t91l/vUq7PtCTfZtv+8n3aia78xVQfM+/wCaNfl2/wB35q/nOXNF6H2nL7pTvNkdmzptaX5tn+z/AHa5rVN7Ow3yYbbv8tK6FYftDMERd38X95qztQs4bVlcTbY/uuv+1W0fdgP2fN9k4vVtJSKO4dEZnX/lps+Zq5nVrMRMzw7XZv8AW/3l/wB6vQNXtfssgiR9/wDtf71ZP9ieZcM6QKob7+1PvNTjL3uU0+r82xyuj+FZrhd827K/Mir/AMtK6TRfBaXEafZraSUSf63d8u3/AGq6/wAP+G/MVIXSTzYXXaqxf+hV22keD3dIptkZG7+Jfm3V20Y+8afV+XQ83tfAcLWab7PhV/i+8zbqG+H7sV/0PKRvuSSvY4/BqXE3z2zCaOX5vLT73+7S3Xge2t498McknmS/db+Guj3acyZUp/aPFbrwh8rQPZ7o2+8y/ern9Q8Jpa+akdszLs27v73+7Xvs3geG2s/LmhVZNzf7W2sTXvBKWu+4eGEps/1n93/aWlzRkc8qfLG8j5+vPB+1Whmtv9I+9+7b/wAdpnh34azapqyWSWzTNIyxxLGm5tzfw16VrWmw3y7NBs/OZW23Fx/DGv8Aearmj+NPCXw1td/h62+36z5W1L6NNsdu33flrVRjGOp5OKxEafwl6HQ9B/Z78F31teJGfEF8qrPCv/LvD/db/ar5e+J3ii2utSubm2SH5v4VX+KvSfiFdeKvF2oNeX9zJs37nmkdt0jN96uA1/RdEt4Qk14pb/aSl8WrPP55SkeS6lLfzXC3mmvIksb7k2r/ABVra78XvGGv2a6Jr15cXEqxfJIz/wANWfFGuW0LsLCFWVZdqsqf+PVxereIHik2Ptz/ALNRy+/zGkeY4LxtHfyXhea5yVb+Krvw18VXNiz2033Gbb+8qHxo32qRim0rs3JtrmrW4uYW3o+HV/vb6uP90cvM9L1xrZo3dHVwy7nasCx1K50XVF1Kzfb8n71Vb71QaH4ke6t/s0z/ADL/ABU28hRlab5Sv3aJRhU92Q41J0p80T03WPEGqyeHYdSdN1nNt/ff7Vc7pvjG7tbpv9Xsb7vyV6Z+wn4s+G/iLXJv2fvjBZwx6J4o22tvq03+s0+6Zv3ci/7Nc/8Atnfsk/Ej9jH4uT+A/HLtd6dcP5+jatCv7q8hb7rK1eZWyqlyynSietRzqrzx55FL/hJkvrV4UeNmb77bP/QaseG9USG6Wz3qw2/IzLurziHVrmNVRJs/xfNWrputSNN5z/Iy/wAO6vElR9nzOR6dPFKUuZnpOsT20lqEdFVf42/9Bpmi6ikMn2n5U2/L8tcRN4s3Ktq/y/8Aj1JD4ieGPZja27cnzferKnQnKFjuWNpOR6fpuvWFxeJNDeeVMsvzf3Wr7V/ZH+Mn9n2un6C8yybbiNvMX7rbv4a/Obw34knuL7/SZl/eNu3ba+of2afElxZ3Fn9jmX5ZVX5n2/L/AHq8vMKc4x1PocnxlKtLl5j9pPhr8QNK8UaC+kalNC4WJWt237W2/wB2sPVodKtfEEjvbL5EnzeZJ8qq392vlv4Q/FS5sZkea8aaBty7Y5drMv8Aer1bw/8AEm88Taa3+ntPbrcbn3P/AOhV8risRaEuY+qp06EZXUjqNa8WWcupcvHFCr/um3/+PV4P8VvD9h4g8cC5s0VLaTcssi7dzL/vV2XxY0/xJqWmg6CNjzfKrL/49trz7UrfVfCfhe+1/wAZ3nkxWtq22NfmZpP4WrwKEZ1cReP2jw8wqRqVbcp4h+1D8UrCaeL4e+G5vktU3XUizru/65/LXmmgw2vltNeIwfevy/71Zl1qUviDW5tVm2+bcM27cv8ADurZ0uG2uJne8m8n7qpX7JlGHpYTDxX2j5LGTvVubGl2P2abZNt+Vv8AO6uj02DbJsjg3/3VX+JqxdOtXMez7ZuT+NWb71dDpapatCiFZV2/JIr/AHWr6CnySPGlI6vwvHNH5e+BlfytrtNKv/jtdlpLTQrshLI6su5m+ZWWuM028tlxIiSOv8attXb/ALtdFY6xbLGyJu3LL/c+Wu6n8HunLKUJHc+HZPMukeaHO7d5rb/lVtvy11OgyT3FjHcv5bPJ/E3+zXBabrCK3kvMqhtuxf4mauq0/VIWVfIf/V/M/wDdatoy5he9E+N/jXtH/BQAbCNo8X6Tgg8YxbV+iVjIk8h8hF81X/erJ81fnL8Yrgt+3etyx/5mzSmJP0t6/QSG+S3ka8hkXYqLvbd81fvvjK7ZDw3/ANgkP/SaZ8fw039bxuv/AC8f5s6ezkMcKpDeLukl+ZvvVt6f5M0boiSAs7eUq/xLXKWOoTM48l4cL/rfk+Za6PR9UhVkdJPlZ6/Con01SX2Tr9J8me3TL7XVPnjX+JauXEaeWHhhVdr7kVfmrM0+6topv3My7m+b7nzKtaH2iHcr78bl3bdtbx+HmOOXumVqWm/unm+Uuyfeb7tfl7+0pZTRf8FLpbKVlZz4z0UEr0JKWn+NfqJdX224lhtplcL8rRyJ91q/L/8AaUZn/wCCnEjOVUnxtouSnQfLaV+7+AitnmY/9glT/wBKpnynFDi8PS5f51+TP0L1LSftDPD8oEfy/N95ax9R8PosP8KbU27lT5m/2q7Wa3SRmdCrBU+7/easu6028P8Ax7WrP5jfNGz/AHVr8Ql8J9BGXvHn99o8M0kqNbN+527t0XystZ2oeH0t2KJZx/N99mf5l/2dtdzMqR+YmzPl/wALfxVQ1SwSYb7mH52+bcz1yVtjqpyPPtS8P2ccbw2ybXX+Ksu+s/Mj8nzpPl2r5bLXX61bxvveF9rr/d/iWsK88mF22TtIFX5tvy1wyNfi2KGn6Z+7RIdqv/HI33t1dLpGn+WqO6bf9nd/6FWMtxNJGjwIy+X8v91mrpPD7Q3EexPOTd/eT5Was/fA1tH010jRPJVPMl2o3/PStiPZGFT5k/e7W3fLTrGNJLdZvJ37dqp8+1qWa38yTfN5JTb8+5vutVfY1MZS/lLcV6n2na+3Yv3o4/l3UT3CNcNDs2rv/hfctZUWpJHI0KfNM3zIrfepW1JLfd+8UH+7WVSXKSS6hHcxyNND5eGTdtkf7v8As1mX29mL2yKryMvlNu+7/ean32qQyTbEm+VotqNIi/NVaGbzmi+Rf7yK38NRL3tjaMixcWs0zeSkm/8AvySfxVWbw+kkbvO+Ts+793dW1ptvNJGj3iKob5nZXqe60vzFd403Bvu7n+7WMom0D8drW+S4ZH8/59u5Fatax8mHDpyzfNurnbJXjkjE0Ma7fl/3f9qt7T3dl3o+N3zJ/vV5vtD7ipiJS5jUhuHsbpN+1lkf/d+b+7Us0011H50d/Hv+b93I1VWvJlZvJ4lj2l/97+9Ve8uvLX7T8pdn3I393+9VVKhzxpuRnatePskCTM7/AGj5lb+H/ZrntQmdg/zso/3PlWtrUmmmn3xztmbd/H8tZjQ/K6Q/MWTd+8+6zVh7bmj7xcaJQs7FJPmRP9lG/vV0Ghw+XdIk21WX+Gqlnbw2bMk23d97/darenyWzKXfcPm3Iy/w1jzIqPLHludDZW/kRmZH+Vk/esv3ttT27QsVudjK8f8ADt21W0ybzIzM/wAu5du5qka6SPCPzuXbub+9/s10RiTUlCIqzTRtve5XZI+1Vki+ZaikaaRNifKzLtdm/u02adIV87Yvy7WZd/8A47Ucl0jqEmhVkm+ZF/i21pH3vdOaUijqziSDe4WQgAJMrcViancNDbsqxg5U8nse1aeo3CmQ28cYCKBtIbrWFr06rIsJAJK5CEfe5r+icoUY/Rtx1v8AoMX/AKTRPhsY/wDjPKT/AOnX6yMHUrp2Zhs+6lYN5ccK8zsh3fJ/eq5qkzwXDQpMzBn3fN/D/s1iapqTtJsfax2fw/xV+CR96B9NUlCWhm6lGnmPcb8/P81VlXbIrom5KJmeSRoX3YX/AL5pytCuxPJ/4FWZVOP2ZF2Gy3bHRFRfvMv96rthbwv8n7xdybfl/hqlZzosy9t33VrW0vzoW8zYxXf/AMCrKpI78PTsX7OFLWPyUdc7f4a17G3dtjzRKu59u1V/8eqnZhP9T0P+7W9ptrMkn7lGPy7tzV51apy+8z2aVDm2NG0sdoXYjf8AAVqzNpsPlq8KfIzbf723/ap+i2uzOyb7r/OrferXexkaIJNtZt+12b+KuOVY9OWFhyWMCSx8uZfJdtzLtp1namOZkT733njZPvf7VbtxZpHMr/f8v5U3PVaS3RWXfD975vlWuWpU94iFGPNcp2a7ZEmhRtzLt3fw1pWtjumZ4bZm+dW3NTI9N2LsmudsW7bEy/xVejkhj3wwptRtvlKzfdrGVTm909GjRjuyKS1eK4Xznbh/4f4qv2qzKv7mZWC/fX+7UC2sMnyTOzIr/wAP96p4lfzD5c275Nv3dtKVT7Juqf8AeJlXyB9zzEb7v8X+9V+zkhjuE2Iv3V+6n3qz47t/l+0zLt+6irWlp86MybEb5W3My/w1PMi/Yx5vhNW1t4VYeRDJcL/6DWhYuiTJ5MLNt/2KpWYhdtkMu/5926P+GteFvs8Kedc7f91Pm21nH3glRmSRzTN7nzW3qybVX+7tqSTzHCJbOu1V2uv/ALNSxxoJd+9Q6v8A+y0k0kMMjeS7M67fvfLT/hmHs+Ykmk8mRbl4Y2+RV8tf9Zu/2qqan/rgn2Pc0i7mX+FaluJ/L3TW20sy/OzLuZqqsryN9/av8fmLuo94soSJc/ZVQIsLq371VXd8v8NY2o6b5hPkuqMrtvZl/wBYv+zXSSWszyKnyquzdu+9u/u1X+y3gmmf7u75/mb/ANBren72xySly+6clPZwqrQx+YVV921vmpk32m1i2TOpST738X/fNdDfaXuj+dF2SfNu3/erMm0lI1+RP4tzbf4lqoxgtjjrVJGI9ncpCuxF+bdvVap3Nr5bMkKbm+8/mfwt/s1uyWb3DMkLqiK+/wD2v9qqv2eaa4WFIf7y/Mv/AI9W0fjOKpKUo6GSsO1mR5o2/vN/ErVH9nhm2zwuryfw/wC1WlJaz7pU8mM7X2/N96qu4o2yaFUaP50+Stoc3NzM5JSIdLs5rMv5MaqJIv8AVt91Wrcs9lu4QfP8io8i/NWdY29tJI8yIqL95q0NNt0jmb52837r/wB1lrHER5jbD+8bcKrbyNNJtLMiqq7Nu6tXT5EWRU2R7v4N38VZNrE8j+TN8qfdi/vL/tVtQ2fnKu/lFZWfd8qq23+GuCXNy/Cd1P4jXs1nvVTYmWkfD/L8u6tqGF1be/H/ALMv8VZdnvjQuXwV+5t+7urY0GSFt0f7t1b5UZv4aI8nNblO77HMX9PtYJJP3MPyt83mK3y7a6PTbWzkkF4ibdvyrtT5mrN03Tfs7L5ab0/jXZ91a6PR7JLVUTfIFV/3XzV2UaXVHPW92Jat7d92PlEv8Lf3VrrPD6wrJG+/c3zfN93bWZpapN5vnozru/e7k2s1b+h2Mx2/Ou2OVt+5Pm2/w17OFjy+6eXiJS5eY6fw7L50hQvHt/jX7zf71dLZruhZpkwu/bEuzdurlvD8btM86Bh/eb/gX3a67TZE81ZoXbav349tevTjynkylLnkbOnxvJD52yNVX77L/FW9p8Nt8yPuPnfLFJt2stZ+jtbXUyOiLOi/LtVflbdW3ptuzW/yOrL9yujl90fkjN8UeGofEU2naPsbYt0s9xCvzecq/wB6uZ+Nlrf6lrlxNa2du1taxL5X8LK38K16Fr159h09N9zDEbe1Z0k8rdJGteV+KNU1LVNND6rbRut5cKsske5flX+Kvz/iGpL67b7JFOUqk7ni/jzw7NrWuTaxbfIquqyxq/3W2/erlJPDL2N4byG22STfLLIr/wDj1dz4u0+ZvEAs/tiw2iy7m3Lt3Vm/EBXty2oWCNGnlLFF/caT/wBlrxoz5I6Gvs5+1OE8XWNzqC2emwpmKGLc8m3bub+L5q53XND0rR7i3uTuZN+64jmf5WZf4q6jxb9p0/TXuYZt42qrr/6FtrzzXNUmjt5POdWX+HzPmalTqe7c7aeHkjj/AB1rzw6s9yl4sy+b+68tvlVa4C4vr/Utaeab97t+8q/ear/i64tt0jyPt27t8f3lri77xYlrH9ms3bcqKzNH9+vSo1Kah5nm4inKRe8U3brN/pLxxpNErKsj/NXNagz3F8qWz7/k+6q1kXmuXN1cP51y2xfmRWpLPxE9jbiRHXdv+9/FXVT92NjjqRi9R9xJcreJNvUS79rN96r154xubWJ7ZJtyKi/M3y7f92s77ZbXTJcw3Kr833W+83+01Lrml21xbrN5ytu/ur/6FWcoRqRXMyKcZx94fp/jrVZG85LxkdfubX+Wum8O+OL+O8RLyHesit5skj/drg47d7OPYlsrKvzblpy+Iry3X92jfK3yNXDWwVOXvRR6FHFTpyjzSPfNB8ffZbFnudSVf3W39zFvZf7tdV4N8cXO5b9JoWRmVvMuH+6393bXzfpvjJ33WzzKC38W35a7Hwv4msFXZM8ju33F3fu68jEYXl96R9dg82hKMbyPsHwT8WNNvrpbWa/2yzRfdk/i2/3a9Ck8bedHEl/bW8Kx/wDLP/2bdXyv8LfGlhc3cKalqVjE8fy28zNub/gVe4eFfDNj8SLpEufEOyVf9U1vL8rL/erw8RFxnzdD7DD4n6xS5obHtnwN+L3h7SfFcVncws219ryMm5VX+9X6K/CXxr4Jfw7pOtTeII5Du8pIo5dq/wC61fmVofwa1X4X+IJNS2XV2y26tFtfzGk/ir7d/Zh8QeCviB4Hs7O28u21K3XY1qy7WX/7KqoYqOF0j1OTHTpYqlyyPeviTcrryGz0p454V3NuaX5Vrxfxg1/p9zZ6CLJomkljZFjVtldndeCdS8PXVxqT+JJHjjbb5P3lbd96tDTdH07xNcWF5K//AB7z/v8A/ppH/dqa2O/f++ebVy+H1aLg9j85P+Cz3wsttAk8JfEKzs2geO/ktZWjferSSLu2tXxJIsPzpM+/5FX7+1Wav0j/AOC5OnyX3wgtNaW5aNLXxVavFDHF8m3ays1fm1HLbLD8kP3q+uySp7bB83mcNenPDyt/dJo7g7lh2Kkqp8n8W1f7tVLy4aRl/c7t3y7lfcv/AAKlvo9rC5trbe+3bu37WqG6uPs0bbD8jfer3YxPPlL3RMJ5Kum4H7zSN96rGmw+ZI/nPuVvvf8AxNU7eZ7rH3WDfxf3a0rG3kuHR96on3fufLXRRjOJy1JFjSbVLqSWaFGJ3fKv92uisbOHzH2SNt/2l+aqVnbJtTd8zbG+XymVt3+zW5p+kzR7Pk3D+81erTj7hwVP8JNpvzRjf/e3JG3ytW1psjrMpRN3+03zNVTT4fMTf524ru+8n/j1WGZ7R4nR90Tfw7a35DkqfynGftMSZ8IWKLKCBqY3AevlvWp8Bk3/AA209fNJDSzfIFz83mNWF+0W9u3ha0ECEf8AEzG8n18t62vgTM0fw3ssR5QPNv29SfMbFf0RmceX6N2CX/Ua/wAqx8LRXNx1VX/TpfnE9Atbp7eRn+Xds27mf+GobhXW6ezm+eHcv3ovm+7/AHqqTagkLi2hfci/dZqurN5kKPcvuVmX5t/y7q/nb2fvH2cY+8RNCkKnZuTcu5F/vVRlMNxC1zbPtVvubv71W5L/AMySVBBll+b5aoLfbpPJ2L5cPzbW+6q1EpTjHU3o0faS0KdxGjLsS2XKtuSTd/FWjoug3N9cI9+it83/ACz+8zUzS7F7i4SZ4NkSv8m1vmavQfA/hfzMb5mZfm8pZPvbq0ox5j1I4P2cVYs+G/Cabt+yP5vmlk2fM391a6/SfDc10rb3VSy702p/6FWj4V8L/Kly6Rptfen/AMTXXR6D5luXtkWNo/4tv8Nd8ZcsdCJU+xyljocMkPnwp8sj/wB3bu/4FUl94ftrG3+036KkcPyvcM+3bWr4t+IXg/wnpbvND9oljTc8ap8q14B4/wDjVr3ii6a2hRrhJG229vCu1VX/AGqIylzWSPLx2OoYaPK5HReLviZ4Y02Sa2sLWS+uFbdtji/h/vbq828afEqbV7pLPUoZriGRGaCxsV3Krf3WanfaLyPP9vX8dl/ehh+Zm/2azL3xxoPh2PzdHhVJvmCTbPmrenE+axWY16nuxNK3u9VvoVuX8PWen2m//j3+40i/xbqxNavPDdmu+GO33SfMkjfN5e2uL8WfGS8nWWFNwdVb99/DurzHxB8UNZ1C43vc7v4fv/drTmR5sYv7UjtvHHji2vLqSG2ud+35ZWb/ANl/u15rr2qJy+9lVfuLtrJvfFlzcTbJjlW/i/i/3mrIvtWuY5m+fczfwtTkuY1j73xFDxAm6RpoX4b5mjVa5DXNPDNv87YVb7tdVc6kWV/Of/ZWuf1CaaR9kkyqfuqzUviLjI4HX2ubdm+fbWbLsmUzIjAfxV1WuaXDcRsny/Kzfe/vVzHkvayPauny7/vbKImnMVY7qaOb5H3bf7tbGn6tG/7mblW++tc/dK9lcbHh2fPVi3ukjm379tPlRPxG3NfXWj30Wo208waNlbdG+1l+av1K/ZX8UfD3/gqp+x3ffs3/ABR1KFvG/hG33eHLpn/ezLt+X73zV+VS3yXVv+8m5r0P9kX9pLxb+y18cNK+JHg/WJoWhuFW6WP/AJbR7vmjqozlTldGcqcZaIf8ZvgD4/8AgX471HwN4q0e4SaxnZWk2fK3+0tcpazbZD9pRkZflr9j/wBpL4P/AA3/AG5vgbpn7Qfw9t7f7TdaMs9/5K/dk/iVv9pa/ML4l/s/6x4V1eSG/sNjrLtRo1+X/gVcWOwsZR54R0NMPjvZS9lU3PNZG8zE33Ds/henLIkih5+Pl+9WneeDdS0+aVJoWYb/ALtV10l92yaGTY33fkrw/ZyjsexGtGUbxkX9FtU3I5mz/u1638J/EWveG2idPnXzd23f/DXlWg6LNNqUSIjbGdfu19hfsp+DvBMK2lz4i0GGaXzVbzGbdtbd/d/3a8rNq0aNK3Luellar1Kv7qXvHo/wH8aeLdc1S20q202YCa33RM3y/e+X5a+svAuk3/hfQ4nv7z5l2rcMNu3/AIFXH+DfCulS6r/b1g0DWwTdGAu3CVh6t+1l+zZeStbW3x08Lqu3awOtQbfz3c18VPBY3NW44WjKVt+WLla+17J2vZn3mGlVp0v3kuZn0ZpN/qXiRks9HhjmOzbub5v+BLXyf/wUZ+KmpeH9RsPg5/Zt1p82oRLfy+dE0byQq23cv+81fUn7Afx3/Y91r4m6Lp/ir9pjwQ9xqE6W9noya/BLc3EzsFSGONWLO7MQAoBJJAFVf+DkDXf2R/EuneGvFnhL40eELf4ieBrxdO1rwdLqUdvqgsZkDrm1YiUBchsFejA9DX1HDXBmMdVzq0pqSV4xcZJ272seBm2Y4ulWVOEG0+yPzLsbxI22PtRf428r5mWul0P7u3Zuf+6rblb/AHmrzu0+J/gmQZfxPYgKvG+4VSf1rZ0r4rfD2Flkn8fWK52jaLlfl/WvtKGUZpD/AJcT/wDAZf5Hn1qdaf2X9x6Fa77VUd0+fczVq6bqCNIiXLrH8zMn8K1wFj8XPh0s/mS/EfSSys2Ga7Qf1q3/AMLn+GjShZPiJo7AurEtdoR/OvUhlmZPT2M//AZf5Hk1aGIW0H9zPU9NvLaRdn2be67f4/vVvabqVz9neHzo2b7qf7NeNaF8bfh896ba28aaVK8p2JCl6rNIfQAda1pfjZ4D0m6e01Px/ptpKMZgub1UZVPTg4NdkcszCLt7GX/gL/yOT2OKU9YP7me06X4gmjjSa5ePZ91vMX/x6ul03WHjt02OyLInyTf7VeAWP7Q/weUMG+JWhpudt4OoR/Mv51v6H+098GA6TXXxV0QD7ojl1SLgevWtI5ZmXWjL/wABf+RUaOK5fgf3M8y+KN39r/bSW6Yg7vFGm8joceRX3bY6hM0e+bbt+6nly/er89vGfirQtb/aWj8XaVrFtc6fJrtlNHewyh4mjXyvmDDqBg/lX1pcftH/AAZ8OCCfXPiZo9jEX+V7i7VFdhyQN2Mmv3rxiw2JnkfDkYQbawkE7Jv7NM+O4bo1qmLxqjFu1R9PNnt9nqkDqqWzttb7zb91b2k6tbQsnzzB9y/Kqbl/3q+ffDn7V3wE1PUvsulfF/QZmaEkxW+qI8hx14BJrptN/aK+GiZjl+I2lkH7pW82sa/DFg8bGetKX/gL/wAj6aWHxNruD+5n0HpOuI0KyIW3/ddv9mthdaWS3CPcqDJ8u3+Ld/s186+Hv2w/gDq+tW/hyw+OPhWa8urlYINPt9Zh8yWZm2rGq7slixAA6knFerR+IoWZn8xSyvtt1/iZv9r+7VzpV6DSqRcb901+ZyV6FWD9+LXqrHXanfO0geFGfb8r7nr8zv2iRG3/AAUxYRZKnxvouM9/lta/RFfEFtNs3ncGZv8A9mvzo/aHlMf/AAUjkm+UlfGmjn5TwcLa1+5+A0lLPcxt/wBAlT/0qmfJ8TQ5cNS/xr8mfprvRv3nyr/Ci/8As1UNaaOOFXR1+VflZW/hqv8A2x9nVrWR1IbavmVT1TXFkjltkeNA3yJMv8VfhHOfRRp/aKerXkDRH/WFlTanlr93/erHvLy5jbZv8r91t8z+9T5tS+0Lmbcvy/PIrbmb/ZrH1DUPMswj7VdW27lrnlI3jH7RS1q9ebY8KNsX7/lttrm9Q1BCHh+Vtv3vk+9V3XLya1V9m5dzr8qp/DXGa1qX7yWzTciN9xo32tXPKR0crOhtdS+ZYep/gZX+Wun8OXXnR7HvFwyfd3/M1eY2+qQx48l42Mi/wvXReH9YezVUhulwyfd2/MrVz83MEj1LSdQ2xmO2dn8uXbtqS4uHMMSQ3PmozfP8n3W/2q5C18STLGV3rH/F5i0648aQblzMybvl+VKqUuhPuGxda1uuN6JhldtjN/D/ALNZV14ghW4LzPw33F/2v71YVxrTQ74Um2PM+5NzfeX+9WDfa9t/c/b/AN2q/eZ9zNWVSoOMfeOyn8RW334X8vbt/jq/Z6y900qecu9vlTb/AA15LeeLNsn7l13t8u1V+X/eq74V8bTSfI6b7hfl3NWMpcw+X3z3bSb6FbT99NG6L8u2Rvmarjat9oXZ5bJuTci/w1wNj4oTyUuZud33fm+9/s1JqXiiaHy3Z1VNm7bvrOUi+X3z8p9DV1tdjwsU2bfmetyzkQWqW37vY38O+qFnp5iZ/wB8xH3tu37tXLOOZm3wiRTuberf+hV4MsR7/un3dOjCJNumVleb+L5V/wB2oLqS22qkPl5+8y1dt7d5I/33zP8Ae3LUNxYp5LvG8bM25XbbU+25pcxr7HlMmS1hWNXjdSy/+zVDb2Z3PI7fe/h+9trQazmRRyqt95lVaa1vNtZ4Uyfl+Zv4v71Pm5o+8TGMv5TO3WwZUfc5+6nzfdapI/JjmjR/mZfl3b/vUupWrWH7vZjb/DWTcXe2F9m5tzbWrrpxhPlscdSUoytKJu2epTN/oybkHzMv92tD7YGXy3TcI/7v8NczY6h5kY/ffLHV+x1abzPNh+Tcm35v4q6I/abMZWly2NNpEkj87ft2t87bf/ZaijmSOE75mX5vlqh/aDwzb/OUM0X71mqteakLpd6fMFT5d1OMTGVT3iZ7+Ke6EYGGP61g+NbiSCeMRnGY+vpyat2UzHV4irr+8Q71De1ZPxD8wXsRicBjBhSWxjk81/RWVK/0b8av+oxflRPgsXP/AIzik/8Ap1+sjmNQ1JJPkdNv97b/ABVz15qDyMzp/wADZf4q0dT3ybvJTltu9qyvsb+WUjTPz7fv/wAVfgHwn00fe1kVvM+0b0h+SrdnHMqp/c/jpbHT/LkZX+Z2/up96rUOmTRzbx8y/eqX8XxHdTj7xLawwyybNjNtb5W/hrXs4Zx/y2VV2VRht3t22Omdz7l2p/DWgsbqNiJv+f8Ah/hrmqckT1cPTNnSWh++m7b935krd02fy2LwzMoZfnVv4qwdNk81Q6JuDPtVf7tbumwvJH/D/wB9fery62x7GHp1ZctjotJaZVihtkzu/vfwrurdt40jmXznZ9vzJuSsHS2ePYNmw7PlVq01ukZoUmTem7+Jtvl15lT+Y9Pm+zIlvlm+ysmxVEz/AHm+81QTQvChRBxt3Lu/vU9ryJtyfvJEX5fl/haoPn84Rp9zb95W+as5e9H4hR90e11cyLC6Oq+Wm3/vr/aqxDGkO3zv9Y237yVBHCWuN46f3W/vVehjeaZrmZF3/dRf4lX+LbWXNym8Y80iOGGFlZIYWX9786r96nx75vkfzFNWY1/gRF3Qrt+Z9rNT4bF44wjwsu77/wDe3U4y5pG0Y8suYis7USMuyFVCqzbmb5mrRs455JFhRFZZF+7v/ipY7F1kHzL8vzI2z5quWlr++BO0qvzbm/ib+7Ve4d1H3izC32eGJPOZNz/Pt/irT0+4SCNNj7tr7X3fMzVRaMw7XuUz+9bf9nTd8tWLeR4VR0Tbu+7/AHttTGJpL4OVmjDeWzfPcvwyfMy02b7MkOxbn52b5Wb7tQWsbyMronyK3yf3Vq7a2ttdfPsViz/xbvlrWMYc3vHLUp/ZK8du8kYtofn+bb83yqtLDZxrcQzTXLI8m75tvyt8tXJLX9y1t5cbnZv3f3f9mrVvZw3EzJDbbfLi+T+JdtEpWjynNUp9yj5bzW6+TCqS79zrJ97bUq2s3lo+/wCb7qKq/wDj1aC2iTMyednbt2f7K/3aW7h8ybfZowf7r/xUe7HRHJUiYzaSjQo7vvZW3P8A7NZ2paf5czb4d5X/AG66ia1eRkcbkHm/6tU+WqOpW6eW/wBl+SX7zN/D/u1fux0icUv7xyVxo/nR70fy/M+Xb/FVe60/yZQkKZVU+9/ereu4UjhGoXXzGP5tq/w1A1ulxL8/WP8A1UbPtZvlp83v6nNUjLlObutNdmR40jX5vmXd83+9VaTS1+xpC7sXaX7vlbm/76rpI7dLyMTSw7VVf9Svy/8AAabNDIzeWltuaP5flb+Gujm92KRy8vNK8Tm47eaH54U5b5W2p8rf71W7e1mWJd5b7nyf3q2PsLx7HRP3rfc/u7f9qnafazW0aPa7WDMys38KrUS5Zaio80fdINLsUhhk3u0Sxptre0uFFVIU/eeYnz7Wpunw7k2OnzN/tfMrf3q1NPXy7cwzJ/teYv8AFXNKXLLmPSo0/eJtNZyvnIm3c/3m+6y10eiWqSSKm+NWkX5d235dtULZUjt4YXh3IqboF2Vpaet4372GGNPurujTay1jGXNPmR6cY8sPeNW3E07f66QFX2vJs+7XR6TClrIEQZ2/N5n8W7/aWsjT5N0cKfdLPub/AGv9qt3T7iFZld3U7vlXb8u6vSoHDWp2gdJpsMyxNcpDu3L/AOPVrae0It2heZXLOu6P+9WXpVxGsJh8mRFkbajfeXctamnt5cyLN87bt33PlWvaw8Ty6suWPwnQ6EttdXH7793EybkXb/dre0q3tYVXyUYov3vn+bbWJodukbbERtrbvKZq6PSY5o1CfK+5Pk2t81epH3TzK0eWR0ehX8jK6JNsiZWZNqfMv92ujhleFfNm2qjOrIyruZm/i3V5v40+KXwo+DOlza38V/iJovhqCNd8U2sapHAzf7sf3mryvS/+Cu37HXiT4iWPwi+D+seKfiD4h1S4WCw03wnobPHcSN/daTbSlU5Ycxi61CMdZH0T4ouJvFF5cpYalNNFZ3X2by2tdiR7V+Zd38VecfFrXodH02C285Y5dnywxv8Ae/2mX+GvRvh7pPiGx+Gd7ea3o91a6rqWvXD3mj3jfPYyNtVYWb+9Xyv+0/rniHwv4svtV+wMiLB5Uqs3zLJ/s1+eZlW+t158gqPuy9Sj4o+JWiWt8by6vJizfLFHs+bdXFav8cEvtLm0reuyOVfNb5fm/wCBV4l4r+JWveJtWH2yHygsrIq/erW8Eaa95qlvpv2ZnkuNsUEMcW5ppP4VVf71eXRo8v8AFlax7eDpSrfCet6HcJq2l3M2sTKttMi+VJI7NtX/AHa8q8fX3h6z+022g6ws8cbbflZv3cn8StX6JaF4i/4JW/sQ+BdL8J/te3sXi34g3lhHdT6JbRM1vp7Mu5YXETbVb+9ur5++L37T/wCzh8W3n0nwP8C/Bf8AYF1LttbfSLDyp41/vNJ95qwxVbC4WEaifM30R9JlOR47GOSrQ5IdJS6+h8GfEPUJpFP2aZfl+Z2ZP4a8017UPs9xvhOVb77K9fUnxm/ZrttQ8L6j4/8Agsl5qNlZo11q9iy7pbOP/Z/iZa+TNcuFa4Z0T5ZPlZWTbtr2MrrUsXHnR8tn2X1cur8o5tQhmiMm/crL92mG0Ty1dHxtb5VqC3k+1J5kKK21fvbvvU63vL+Rms3RUi3blkr06kfd90+d+LWRNZxvCWL7vm+7Vu3164VvJm2rH92qEyuWP77erfLtqSGa1m3wvC37v/lpH/FXNKP2S4ylH3S3fLNdW6PbfJ/f21WvdLhup3hhuZI18rdtj/vV0PhuzF1EiPZ706p/u1Y1DwlCyp5P7v7zbqy9pGEuU09jVl8JxNjZzRYM0zb99bD6r5UiIjt97b/wGotU0cQr5kE27d/D92rPh23s45EuZoVlOxt6tUVIxqR5zpo050/dNvwjcxKv2h5Zvlfarbq+yv2P18TxzRXfh7wfqU6yKqO0kG1Vb7vys1fNfw6v9SWSFNK8DNdCH5vL+z7lb/eZq+4P2V/il8SNI1C2/tjStln5W2VW2r5cn8K7a+RzOo5RfLE+0yWU7cvMfQVv8Zvj94J1CD/hIfgzYz6fcRLAuoNPC06wr95mjr6A+C/ij4deOrKTWH8Pf2bqqrDt8v8Ad/Nu+9Wj8Bvhj8P/ANo7wM+m+JdO0/VrpYP9W9xtlh+X+Hb93bXmvxQ+HNt+y34sgvNNv/FHh6xkuo4lk1hP7QsZN33fm+9Gq1x08LKpT54bHVUxUVXlRnufTcOs2Ol2U9tr0UfmN83mLuaodG1zRVkKWc0KJt3MzN96snwfqXinx14Pj1jRfF3g/wAQ2yuqtLZ3DI6/L824N95qni0ixWR/tXhq12SbfmjT+GitRjGcYSR6ODcKlKUep84f8FUvBMnxx+AGtWfhzWVhGh2a3qyRRbkuJI23ba/KKxt5riFNjssjRb/LkT+9/dr9zP2v/hrN4z/Zw8WeHfC+kyQyHw1cNGlrtXzJNvyrX4raXou23htpk/fQ7ovmXay7fvLX1XD+lOceh4ma1KUpQ5EYEmnu0bb0ZN3zeWyVXh0//SEeESK+xvlrrNS0vz4f3MbbF+aVt+1qzF0945Bvmw0L/wCs27v/AB6veh7vvM8yUYmZa6KkipD0fqsn95f7tatjpL7jbBFbdtX5U3batWcNzJvEO5R93d/era0uxRpikNhhl+5u+9/vV6lPn5NTzpS5ph/YaRzJHD5jGPa3zL/30ta8Pm+YttCm5GTcy/3afY2Nz80MMLO8ybV8xv8Ax6pbexRmSbyG3Kuzc33Vr0KMYnPUl/KQ2q+VG6IjI29l8tqsKtzMpDzbP+mapu3U57Xyy7pt2f7/AM1NaOaFGd/MZ13fe/h3V1xjE5anPynnH7Qg2+FrQNICf7S4C9CNjc1f+DMkQ+HlqsqHAmkIYN/00asz9oID/hG7BolAQ3S5A9djVP8ACWaNfA1pBIhw7SkMPUSE1/QmaK/0cMEv+ox/lVPhcOv+M6qr/p0vzidxHfTXTK4Cv+9+dd+1avvPHJZ+d91Wb5NyVhwzzLMES2Ups3yt/EtWpbi2jsY/Om2bd2xd1fz9y+5yn2fLEbfXz3UiIjx+WybvmqCTU3uplhmdpG27UjX7u6sqbUJlkM33f+esatuq7pc0zP8APbbn/ux/e/3q55QmerhaZ3XhNfLj3oFm27fl2bmWvVfBelQ+Z5025wyNsVl+ZWryrw225rZHT5Vbf83+zXpNn4mTRbX7ZcvJuZdyrHLRTcaZ6MqiULSPULW60rSbGO2mSOKTbvSOT5d1c94i+MEK3R0r+0I7a3+Zkbd97/drxr4pftAWHhvQbjVdV8Q29sI7dli+1PuZv+A18w+KP2xra5v7v7BctdybPKW6m+Vf9ratdMI83vs+SzTOZc3Jh/vPpH4xfF3+2pLrwZ8PUa8u44t0rbP/AEJq8V1bxl4q0+ObNgylU3SyM+75t1eSXX7UGvabZ3Vh4Vdraa+2/arpU/eNWJqnx0v7ezE2pXmd339v8VdUY8sT5iXPUfNM9Q1Dx54kVnR4Ztsn712k/wA/drC174iefbjfcsJWVn2r/eryXW/2grrWLg+S/lIvy/L/ABU3TfiVbatcb9SRdn8at/FS5pyHGnI6O+8eJcSPbTTb9rbvL/u7qxbzVIZpH3zbPn/heqWqSaVeRrNZ3kafNu8tq5m8vHhfyU3My/xf3qscfdkbt5rSeYZX+9/eWqFxrDyK/wA7b9m3czfw1k/aJliZ5gpo8x1YPnf8u7y1quUfMixcagirvTb/ALu/71RsyfK6HH91aPLh8zZs3N95GpJGT7WyMmfl+8v8VOPKLm5vdZmXlu8iqn3i26ud1y1mWX5U2nd8jLXXMvlku77W/h21n6lprzMiH70n+392iL5hHMatpttqkfnQurGNNzqv96sO4t7mNlSaFlatzVNBvNNma8s0+625l/vVd0e30rxPH5L/ACXP93/apgcvHJNGwTa3+9UU008cyuj7Sv8AtV2V58PfJVpt7Jt/irEvfDbq+9Pm/wBqjlmHNzSPvD/gjL+2tc+A/EcnwE8bazIdK1yXy7KS4l3RxyN/Dtb+9X0n+098FdB8TapcJ/ZsYZpfvKu3/vmvyO8Hyar4V12117Td2+1uFlTa/wA25a/SP9n39pj/AIXB4FsX1vc95awKl0vm7pN3+1upe05IcsjlxlOM+WX2jyLxP8BbnwrdXFtHbM9vJ/FJ8zf/AGNaPgD9lez+IUkVnDYXEcsjbH3Rf8tP9mvr34V+H/B/jLWLew162txFJLuZW+b5a/TL9j79jv8AYgutBs9Yns4r7VGTf+/Xy1Vv9mub6nHn5ub3TCniK/NyxPyJ8K/8EXfjB4nsU8Q+G9Eku1kibyo4/l+7VL/gn5+xb4c+Jv8AwWS0r9iX9ol/EA0C1jnn1bRdK16Wy857fSvtiwvJCQ4jZlAby2RyGJV1PNf0leDPhl8O/CWnCy8KaFbQ2/by+d1fml+zH+0r8GvBH/Bwr8Y/2Vr79lfw5d+LfFWtR3uj/FMN/wATHS4Lfw3BJJaBZFfbG4Vh+5aEnzG8zzfl2+/lMY4bCY6tRp8840J2293WPv3f8u+mvY+r4fqYym683Z+47W3Wq1+X3n42/tnXGofsx/t1/ET4DeFfiX49m8FeDviHe6XFZP4vlF3NYw3JRk87G0OyAgOUOMgkNg5+pf8Agqt+15/wRy8YfseeEfh7/wAEz/h7f+FfGV5FBbeIf7A0m50YppSoGksdZkIC6vKZVhZWLXGHiZ/OH3ZM/wD4ODf24v2ffjp8dfEn7OHgL9ibwt4T8V+A/iDqVvr/AMTbZ0Go620cjRvuEEUQZZGHmMZzMwONpQ7i2n/wW4/ZJ/Zo+AX7CH7Ivj/4IfBHRfDeu+L/AASJPEWp6Ukgm1J2sbG6LTlnPnP511KRI+5wpVAwRFUfpOD+qVpZTUxNKdKrO9lGUVGXLDm5qnL8SaV0t1dp+f3cZqq8M6qkpO9ldWdle7736H5weCPHvjn4ZeJrfxp8N/GmreH9ZtN/2TVtD1GW0uYdylG2SxMrrlWZTg8gkdDVr4j/ABa+Kvxj1qLxJ8XfiZ4h8VajBbC3hv8AxJrU99PHCGLCNXmdmCgsx2g4yxPev3X+AX/BMT9nf/glJ+yX4a+K3jb/AIJ++Jf2oPjT4stlkvdO07wc99baQJY45Ht2jnEsFpHCD5fnmNriaRmwqxllioftif8ABOj9m3/gon/wT+8b/tR+Fv8Agnzrf7Nnxi8BaVc3kei6loi6NBfw2kTTtGyqkVtdQyw7wJ9kcscsahmEa4k0XiBk88cpqi3ScvZqreG97X5b8/Jf7VvkCznDOsny+7e3Np+W9vM/Beiiiv0Y9s/Qv/gjZ/wST+D/AO1X8NvG/wC2z+3V4r1Hwv8ABDwFbS7ruyvRbPqt1CFluMvsd/s8UWFYRqHkkmVI23I4r6d+Dvwc/wCDZD/goz8QYP2TfgL4G8Z/DzxffGSPw1ry3l9bPqkkasxSJ7ua5iZiiFgs8aMwOF+c4rnPi7YSfBX/AINOvBdh4UW8QePvF8EuvObTYWEmqXM3z4Y4T/Q4FVz94bOBu4/LX9l3xrrfw3/aW+HvxB8Nmf7fonjbSr6zFshaRpIruJ1CqCNxJGAMjOcV+Z0sJmHE0sdjFi6lJ0qk6dKMJcsV7NJXkvtc0t79NrdPBjTrY91avtJR5ZNRSdlp1a63Z237SnwY/ac/4Jf/ALWHij4FS+Ptc8NeI/D10YrfXvDOqz2J1OxkAeC6ieFw3lyxlW27iVOUbDIwHm3xJ+N/xp+Ms8Fz8X/i94o8VyWqkW0niTxBc3zQg9Qpndtv4V+kX/B2X8OtH8M/t9eEfHmnJKtx4m+G9u9/mDEbSW93cQqwfPzNs2AjA2hV5O7j8ta+s4bxkc5yXDZhUivaTgru3XZ262umejgaqxWFhWklzNf8OfoH/wAE8f2gP+CB/wAPP2d7fw9+3X+yJ478TfERdRmfUtbtr2W5tbiEkeV5Kw3lqIVUcFGR2zlvMYMFT7/vv2Rv+DfXxP8A8E7db/b58RfsY694E8Bzafcpot5q+pX1pq+oP/q4JLCH7fMrPJN8kPmfKxQuy+T85/CL4M698NvC3xa8NeJfjH4JuvEvhTT9btrjxD4estQ+ySalZpIrS24mCsY96gqSBnBOCpww/fHxF8Uv+CV//Bxr8OIP2NPhj438c/D3xB4C0ttU8FaQ2nx6fBAqwi3UizjkktbqGANEpizHKiMwhdFaRq+F4zwNfLsdSxMKuJjRlLmqzjUk40432UU9LvrtFbJ7LyM0pToVYzUpqLd5NNtJdrf1bzPxs+C/xN0S1+JPhX4pfFK/8Rajouma9ZXWqN/a8kmpnTbadP3UdwrxP5q28YjRlaPaVXaUwMfrp8Ev2sP+CJf/AAUt+K2ifskeGv2b/jr44vNdvBLHpvijxTrFzp9osSlnvLjztadY44l3EvtLc7VDMyqfxt8ZfDzX/hFN4h+FPiuIJqnhm/1HStRUKwAnt5pYZMBgCBuQ9QDX2r/wQS/4Ksf8E/f+Cb3grxfb/H74SeKE8c+ItSiA8b6LZQ34k00BdtmEZ43tkSQGRgm/ziwLEeVGo/YPGzK5YzhrKsZg41Z1YYeKpqlNx+JQtJpatLfTXppuvgOFcO6uKzapSUnJVpWUXbeUtfkZ/wDwXHh/Y3/YI/ag0z4Tf8EuNe8VfDrxhp2kPb/FFvBXjS+hsVLMklvasxlaRrgDLyAOI1BiG0yb9n6Hf8Ed/wDgo9+0/rn/AAT21X9q79va10TQPhF8OPCsdhovjK8F5Nrfiua12wy3cks87LMWdRACF3T3MhUMDGwb85v+C6P/AATU+BHwD8K+Df8AgoL+yJ8V9a8VfD34yalLczNrl3JeyQ3lyj3kcyXUgErpKnmZS4zMrxNudyxCdd/wTd/4OJfiL8LfCPw1/Yb/AGhfgL4L8S/DC1jt/C2p6gbd47w6bK3kq0ySO1vMI1cb1aNfMRMMQxLn8WzHKf7e4Lw7wcHiJxfvyqPlqrlvzpc1/euuVJ3srWvufeV8N9cyqHslztbt6S03369Nb2Pjz9ob9rST9tj/AIKRSftQt8P9L8LQ+JfHthPaaNpVsiCCFJ4kRpnRR59wyqHlmIy8jMcKMKP0vsdeSSOTY6q/8P8ADXy1/wAFyv2J/hr+xP8A8FT/AA3D8FPCFh4e8J+Nl0zxBpuiabMBDYzm8aG5SKHrBEZIi6oBsXzCqYVdi+r6T4o3WY3uzMz/AHWf7tcXFOMwWLy/L6uEXLSlT91PdJWVnvqtnqeJxFOnWp4eVJWjy6fhoew2viSFmS2uZud27+9Xwf8AG26W4/b7a6HIPi/Sz+Qt6+rtJ17yZEvPtK/f+f5926vkH4wX73H7a7agZAWPifTW3ADqBBX6R4AT5s+zL/sDq/8ApdM/MOKIv6rRv/z8X5M/Q+bXPIjKW26KXb9771R3WtQ+SsKbvlX5m3fdrj4PEzybt7r83/jrVFJr0MePnZm+8vy7vmr8ElW5j6ynT5YG3eas9vI8yQ5SR/mWsu81pPMZH3SJ919v8NZ02rv5hRLxQzMzSs3/ACzrLvNRvI0+0jaWb5tsjfeWsZVC/Zj9evDIpeR9+xvnVa5TVriwZTcpHubd95at65q22Musyp8+1tq/Kzf3Vrm9S1N/sAd3Zljl2fN8u1W/9CrOVQv2bEuLx45nuYXU+W+7b/Du/wBmtrTdcS0bfs2MzLtj37v++q4eS+uTdRW0MmFkVmTzPlRlWrdvr+x08540dvl8ys4yj9oXLM9Ph8QJcWpT7Yv3dz/JuVqh1TWo/kf7TGhXb5v+zXF2+tQSQokM21lT5WWqV/4kdY1eV9zN8vzfM1VGRnyHTal4shivN6XO143Vd2z5vL/uq1ZGta4krJNbPtT7rrI1cpqHih/Mb/WZ/ux/xNWDeeIvMZnmmZQy/dV6yl7xUeU3rzxInmTOjcr8u5XqTRfGk0ciXKTKqtuXb/e21wGoawnzQw3OEZtzr93dUOl60kl0JpHZP7m6uOVTlOqNOHJdH0B4X+Ids/8Aqb/a33vmf5avzeJpmXZ9p83+FFkevHPCetYjRHdSfm3NvrrbPUEa1+Sbzl/j8v5d3+7WXNJcvKP6vyx5mfKUen+X++SFleR/kaRNtPOmvI3nJ/rG+X5n+9W7cabJJJJ8iv8A8C+7Tls9zbNm4/xfJ92vmfbcp997HmM6HSfJhkRH+6n3futu/wB6q8lqk6s7w7PO+9XQx2M1x8kjt83zf7TVn6lp8bODv2n7r7aqnU933jb6vzJWOZmXy2Ih8xFkb52/vNUflzbZZ3eTb/B5j/drV1S1VkH+9uZWb+KsfVriHzOXYP8ALsVfmX5v4q66dbmgEsLyx90o6s3nW5Iddq/NtX71YF1ebbhn3sNybkrT1iR7e1Jm3ZX7zK33qw7yZGx5LqV2fPXo4W2x5mKozkOjm8qNUb5jv3ffq3Z6lNGoh+6sfzIrJurnpJn8zzk+Rv8AvndU0dx5LLtRl/iZmfdXfKJ5Uo8huSXnnZ/fY3VUl1BAv7l938P3qpyXCTSx/vtm1v8AdZaZcbFjWOZF+/u3bvvNUSlymFSnPl940PD0xbXkEp+Yhvl9ODVb4j5/tCErjIgyM/7xp3hmaQ+IYUlySytyV/2TR8Qonl1KELCHAgycn/aNf0Llsv8Ajm7HP/qMX5UT4XEw/wCM3pL/AKdf/JHIzWrttT95hv4f9qktdJuWYxeSqt/GrVu2elpI6ecm5d3y7quW+hiRlffGrfwqrV/PEqnL9o+vpxjKepj2Wl+XCqOmxmf5KvL4dmLfuX+8ldFpugp5aQ3Kbf8AZ/i21sReHXjYbNuxvl+7XNLEcp6+Ho/DI4ddBuVhUTQbvm3LJ/EtSWul7tqIGxu3Pt+81dndaD9jUw3Sb/l+Ro6rrosL/Oj/ACsm5d1Ye05tz1acY85zljZyxKecfwoy/NW7o1vN5iPv+X5futt3VMui2y26wo7H5lZI9u2tG1s7a2hRHRiv8e7+GuSpU5o8x6lHdiwNHIqTeZJ5S/cb+Kp11B2k2O+N21vmSoPLht5nHnN5TP8AJu+8q7aP3yxsjvv+Xb/wKuHl/mKlUiti01xN9odHThk+fa/3mp8cczBUT7y/M7M3y1n+Y8Mg3zfwfdVPvVZSOG6j86Z1Rdi79z/erKUftBGpze6XoYgtwH+2Rwr/AAf71aGxGhTZMquz7Zdv3qoWsIlt/O85du75dv8ADV1dnzbJ96r/ABVMqh1Uy3DDbLb/AH/Mbfu/eVZtY2kXiNkkVvvM+5VWqscyXEmyYbmX5Ub+9VyNUjTy0mVpP+mn+zSjI3jzSl7pcsbpLiPfHGo8tt37z7zVdLJLJ5L7WZk37VT7tZsG+6X7TuVlX5WWrjfLH5ywsI9u7b/E1aRj73MddOXL7xbhadYZfMdYdy7m/utU8dx8om+Zj9x1/u1VtS91D+7Ef7xf+A7atQ6fvjHybWbcqsv8Va04+77xvL3veRYt9624mmeTdub7v92r1pH/AKD5j3O7b99vu7qj021drdH+Xd91of7rVbs/NhU+dMuxn3PHtrenRjL3TmlU5ZCRxmSxa5f5dybtqvubdurR01f3KvbTeX8/z+X93/aqKNbO6Db9wC/L8zfep32hLVhCjrhZf7n3qVajLpEwlXpyjeUi5HDD9nKfM/yfw/eWo2mT7RHcojb2+b5W+Xd/tUsdxC37lOXX+FvlqvdTvBI0LyfJJ9xt/wB2uf2E4yUjllVhKOkiVmh3fO+8svzK3yrVO6t3kjeZ12x7d1accLtDv2b9v8X3qqzbGs3D7dqrtdZH/hquScTza1WEZe8Y90qSKobar7PnWP7rLWdNb+dGjpbR743X5v7y1tTWe3a++NtzbdsaUySxhuJDJDNHv3KjRr95aLTic/PCRjww+d5aQRyJu/hkfb83/wATUsNntZ/uhtn3v7zVoXFqI7n7NGnysm5ZpEq5Y27/AH7nyUTzfnj2/e/3a6HKcvsmPuRnynPf2fcwwpdW1wrOzfOu/wC63+1UlrpPnr9mm+Tcu39393/gLV0cOko8bpbDnezfN/dq1Ho9tJE32bcUVPu/3aylOfKa06S5veMrTbNI4dghYu3yuzL8y1rw2rlRmFt2zbFJ8vy/8Bqza2vkxoifM7fKu5fvVYj0Py/mdFd43ZX2/Ntrm5J1D0abo0+pFDav9nENzMxVZfu7601trq62pvaML8qMy/MrU+zsd0KpMkats3IrfearEkb2duiPcxnc2/arU6eHrSq8vKbyxeGpw96pEmjt0hjRN6o/lf6xfvf7taul/NGIX8xG+9u/irOWxe6VRM6oG+5I396te2ms7K3e5udVhb7Pb72bzfvf7Ne5h8LXj9k8rEZxlkdHO5v6LE8d0sL3LPuVf3f8Tf7VdJo8sOmqLC5m5VPkjkbc1cNDqGsKqarea1HpGnyLuSaZf3sn+6v8Na1x4ms9Hs5bzTbNo5Wi2veMm+WavYhh6nU+VxnENPWNGJ1t98TPDHgvT5Ne1V5vKj+WVZE2qv8AwJvu18Eftkf8FufiPpk+p/C39l6ay023Wfy5/EiQrLNt/iWFmX5f96vPv+Clf7bevXN+/wADfh9qTRqq7tc1CNvmkb/niv8Au18OMd3OK6Y0b6njSxmJqe9KRveOviP48+KXiOTxP8RfGGpa5qMzZlvNSumlc/8AfVfsx/wai/so6V/wlHiv9szxnpEb/wDCPxf2T4VaSD/l6mX97Mrf7K7Vr8cPhV8M/GHxS8YWngvwRoF1qWpXkqpbW1rH825vutX9Zn7Dv7Kum/sd/sX+B/2ftEs47a+0/RI7zW7r/n41CaPzJt3+63y/8Br57ifHfU8HyQ+KR6GTYV4vF+9sjQ+Jmi+GLHWr+51WHbNfS+e0at8zN/eb/ar4v/a0+Bt5rzX2q6c7Nbw3u5fO27po5P4m3V9IfGzx5rGlzTTeJ9Hhgdv9fHHuaOZfu/er5/8AGXx68H6DfLc+KtShaGSLfcRzfMyxx/d21+aUcROnHmPpPq8KlXlPlub9lHR9JvBr01hJvZmlulkdti7vut/9jXZfBDwf4X+C/hPxP+0n4qs1mm8F2sjaDHcW67GvpFZYPlb+796sX4uftUWeseILmw0p43tI4t0Ukb7mVd3y149+0v8AGzWNU/ZF0fwm+ozNNrni+a4ulb+FYY9qq23/AHvu0TnicS48/wBo+34fy7D068ZPXlPny/8AEXjb9on4nah4j1u/kvLu+upJ9SumXc3+7urJ1aXxF8OZmm0q6mjEbbVkjdlZW/u16/8AAHwn/wAIL8NQ7W0Muq647P5kZ+ZY1/hrH+Pnj3wZ4f0oaJDolnPqEzbpVX5mhX+81dvtKfto0YR5onrZrj6sIOo2XP2f/wBsPWIdTj0vVZ2tp4YmV5FX5bqNvvRtXCftFeGfD3/CTR694fto1gvX+RYZdyx7vmavNk8RSz6+t7bWkcCK3/LOtXxN4gudQ02OHzswr823+7XVHB1MLi4zo+7F7xPz3Msx+u02qmpO3hNNHh2PCrNIm75v4Vqjc6en2hrNP7m5F/io03Wv7U0sv9vZHtU+RZH3eZ/s1paLeJcWq3jpvP3W3feVq9WNSr9s+alQjzR5TMt/Dt/Mwmtk+Tb/ABVei8P3lvcM7w5Rtu/b92uu0XUrBbP/AEZFaXZub5K2dPhhuI4prxFR2Td5cf8ADXHPEfvJHdh8HzTiZXhPSprOMedD8kn3Pk/hrXutPtobFodkaiZ9y7l+Zf71XVZI7hYbZ+fuvtqW6WG6035327Zfn8t/4q8mrKfPzKR7/sYUYcyOHvPD/wBou2hhhZod+3dWpo3g/TdItRqTorFfuxt8zVZ85LWZ4ZkjHmf6r5vvVV1CS8jVUf5QzbU2/wAVdUsVKnDlXU8qpGPPc07fxB4qmmd4deksLNZVbyYV2rI38NdN4b+N3i3wnazWyeJbq4eRt26SX7rL/drnNBtxJZiHUof3Cpvb5fu1qD4zfs7fDixS28dxxyut6rRQrF5kkkf8VefCn7eryRhzehdOrUw/v8/KdVof7bvxd8AyQ+IfCXxauNK1Dfu22N0yMzK3ytJ/DX31+yz/AMFtdU8eeC5/g9+1B4f0vxjb3Vn8+oHbFOf+A/dr8kPi58Vf2Z/iPsn+G73VpLHK37trfZ8rf/E1xMdx4t0a/j1Xw34gkDQvuiK/xf3a9b+y3CFl7kv7xl/adaU71PfR/Rz8EP2kv2PrW7uLDwvZ3ukXl46tY27J+427fu7l+Wuv0v4sLa+MrTTdnm2eobvKuF+6vzfdr8Hv2RP2lvjrdeJ7bStR16Noll3v5i7vLj/i2rX6s/sifEqz+JVrDqXiHVVUabF/orb23SSN/s14OMwEqOIXNL3j9AyXF0K+Hk+/c97/AOClX7U3g/8AZX/ZqmvNS1GM6l4p/wCJdo0cjfJJI38Tf7tfkHfSXsmpG7k2o8ku5vJ3Kte7f8Fb/jd4e/ac/ai8P/B3Qrua58KfC/Tlkv7yH/VTapJ8zRq38W37teAtdO0jTfdb5mTa27dX1eV4X2dK/c+Wr1I+3t2LG6G4YOjs7N/ErfNVGSFfOZI32lZdzRtSwzPGqPM7bm+by/7tSyNDdQ/cUP8Adb+Lb/utXpRjCU+W5zSl15S3b2dtJGrzI0aN9xY/mrd0u1ma82IjbFT5mk+8q/3qx9Nt/Ljb98vyr8vzfe/3q6rS1hvJDCUYOsXzM1dtP+6c0yaOO5jA8mORk+68m/5l/u1a+wvDCyPD88b/ADeZU2m2NzGyb3jRVRvlX/lpV6GzT7KyIjSmN/u7/Mr06fwHM48xjSLDbx+S8m/5/laSquob/Olf7sn93f8Aw1pSLukaF7ncyxMrqu371ZurtuLPNtaPaq7t/wB2uyMTCXve7I8v/aIEn/COWRygUXoDIn8LbGqb4TrF/wAIDZeaA4aSUY7r87UftISlvDNmrFvmvwwDLjA8t6k+EUcMfw9s5pF3EzSnCt6O33q/ojGQUvo54Jf9Rj/KqfA0ny8dVl/06X5xN9pHh2FEY/wtueqU15NIpPzFV/hb7v8AwGrGqXkNq2/f5iKm7y4/lZq5jVL6GNfLRGKxy/K2/wCZa/CPZ83vH2ftuXYsyXk0lw/kzbFZ/kZqv6TcJC3l3NzuZvmlZWrjobx94hkmyyp/31WlY6wi3CJDN87NtSuepT5tTpjW9z4j1Lw/rkFvZpGjsVb5UauL+Knx8tvCOnvpqbbiZfm/ePt2/wC1XMfEj4nWfhGzZEuWlm/5d1h+7XzP8SviJf31082pXLNM3956iNHm6HlZlm3NH2NL/t4t/Fb4sar4kvpPtOpNI0zfeZ/4a4q3vnt7d7l5l/vbawZtS/tC8d55mJ37lVadqF8kdt5PnbP9ndXTGnCJ4NjRk8QP5jvI7bf49r1h6vrmpalcDZNuij+X5ag+0Qyw/OPvfdqGNkiV/n43VX90rmLf2v7PDvdNq/8AoVNbxI9nuSF9i7P97/gNZuqatDt++o2/L/u1i3F88y7/AJmLUc0R8p2un+LppJPJd2Ybf4vvVvWt4mpQ+c7qPk+T5/mavLrW4fer/eH+996uo8J6xukCTPx91d38P+zURl2Mv8R1qQib/SVDNufbtanLb7Vb727/AH6mtlkZkf8Agb+H+7Vma18mQQojf3latCfh94qrEY49+xl8z+KnXUe5t7ozfL96r4s32ru/3fvUxrPdI26Ftq/w1UYxlEX2ihbW7yLv2KC38TVYk0pwu90UbX3Vf0uxDNv+8u7cy7K6mHQ4ZrVf9AVv4vlrOJUpHns2lpJH5czqrfx1y+seG/s8g1DSv3My/wB169J8QaKlmzxptV1/hrzzUNWdte/se5fYq/N/vVXvBzc25e8N6pqt9Y/YNStl3b9rzN/FS6lo/k/P/Av8X96tK3js1jVEdv7u1f8A0KpryNJs/wAVVEDCtYU3fIn93+Cuy+HHxIv/AIZ+IbbWLaeT7HNKsV7bq+3av96uXWzRmKb+aka3eS1NnM6n5P4v/QqiPvTM6lPmgfpH8FfHmm3el23iHStSV0ZVaJm+9X2r+zX+0FNbtaW32/yTaovys+3c1fj/APsR/GZI7x/h1qupfvo/kg85/wB3tr7d+H+tar4ZvormO5Yo207V+WtqlP3PcPFlKUavKz9W/A37Yfin4dXEMs8EmoaPdOrS7n3NCzfe/wCA1+dnwM+NngW//wCDra8+IOq6i1taeIL+Sw0xkj3q91P4bjgijY5G0M/yg8/MVGOcj2X4e/Em517wreN9pHlx2UjGNhk7gpIU/lX4wfCnSPjp+0f8epPFPhHxq0HjX7UdbGvPetaSw3EcqFZo5IVzE6uUK7ANuBjGBX1vCOX08ZhMfOtUUIOk6bb6c/X0XLqfc8I0lKniZ1ZKMFDlbf8Ae6+isfR3/BcX9ir9pr4L/t2fF344eMfgz4jh8C+I/H1xfaR40OkSHTLj7YftEcYuFBjDjcybSwbMbcDGK+rf+C9Xia/8FfsFfsHeMtLGbrSfCdte23710/eRaXo7r8yEMvKjlSCOxB5r57/bv/al/wCCvF9+y+/7P/7Tf7V2keJPCMNhaT63YaQ8Jv7iATJHAt7cJbRyzAyMjEO7byoZ9xANfIH7SP7bf7RHxn+EngXwZ+0F8ftU8T6L4Njk0nwb4bupfMmsYVWMmQhUHmDDpGssjNJtQRghEUD6rCQqYjC4DGYyvR5MLKUZSjKTUk6fIt4q0ne7W1tn0PsaNanVoUcRUqw5KbabTdn7tl031P6Df+Cgv7UP/BS/4s/sw/Db9sv/AII5+M9M8U+HNX0nf4w8NaFo9hq15HLIEKvEJkZ5Ghk8yCaBB5iMASmBIU+b/Glz/wAF6Pit/wAE4vil8bf24f2ydB+B2gQaJJFZeHfEfhGx0+/12E/LJA89uqzaeZc+TEgRppnbZsRHDt+dv/BJL9qr/go14N8bXHw+/YN+PMvhyG/JkvNC8RMs2lSSyFEM32WaOaMTHYg81ED7VA3Y4r1r/guj4b/4K9/D/T/Aup/8FKvj7p3iPQvFN40XhzR/CV8Y9LtrqGMt5ktrHbwRCbbKwEpV3wxXcBxXzOByrL8FXhhqVXCOlGfMqrgpVuW/Ny2acW+nNfbZXPOpSwFCSgqtLlTvzNXla97bW8rn560VJcW72zhHYHK5BWtDTNHsLqUR3U8iZXLMpBxX6tj+I8py2jTq1p+7UvytJu9rX29T6HF5xl+DpwqVJ+7PZpN3t6ep+wf/AATi8JaZ/wAFQP8AggZ49/4J4eA/FVrL8UPh7rMmq+H9E1AiIshuvttrsdm2lJmN1bb8gRu43gKVL/Ov/BNP/ghp+3n43/bd8F/8L2/Zt8Q+DPB3hTxRbap4q1rxLZiCCSC1lEvkQFm/0lpWjEQMW9R5m8naM18ufs7/ABF+If7NPxDj+IfwI+O/iPwZ4lW28uLU/D+oeSbiAujmCTHEsbMiFo3DI20ZBxX1R8Xv+Cvn/BUD4veBx4D8R/to63p1kYh9qufC+l2Ol3cwH964tIY5RnuFZQcnOc1+VV+IvqVfFU8rxEFRxEnJ88anNTlJJSceVWd90naz3vrfwP7VpR9o8NUXJNt6qV03vay18iL/AILk/Ea7/wCCjP8AwWCk+Ef7L1w/jC5sksPBPh+K0KpFc6hHJIbhI5HYKY1uJZVMxKpiNmBKAOfEv+Cg3/BJX9qX/gmZrHhZf2lm0K50TxXuFl4j8H3kl7bxyxlTNbss0cDiZEZXClQjg/K52vt8x8OeDJ/AHinTvG/gvx7q2k6tpV1He6ZqtjL5U9tPGwdJY3TBR1YAhgcgiu9/a3/at/ab/bl1vSNd/am/aA1nxfNoFq1rpcdxa21tBaIxBdkhto44/Mbau6TbvfYu5jtGPbwXFOW5W8JhMJiF9Wpw5Z3hLnbS0asrb6u/nv06KWd4LD+zp0qn7uKs7xd32t0Pp/8Ab9/4N3fin8KPAvgT42f8E8v+En+NPgrxL4XtbrVJ7W2glv4rmSNHW5it4QGe1nWQMiqJGi2sJHYFXPs3/Bvv/wAEvv2mf2UP2iNU/b1/bN8IzfCnwV4N8J6gkMvjG8SwluJJU2SyzRu4MFvFEJHZ5wqkmMqGwWT4p/ZO/wCCkn7c/wCxPpUfgv8AZ+/ao8Q6f4fRGW08OatDBqOn2+5mdvJt7pJEgyzMx8sJuJJOai/a1/4KT/t3/tsaLJ4Q+P37UGv6j4dkjUXPhzTEg0zT7jayuvnW9qkaTkMqsDIG2kAjFeDiuJcfjMDPLK+MpyozvF1XCp7Vwb1XKlyc1tL3tbz1OOpnPtaLw86qcXo5csua3pa1yX4ueIV/bx/bc8Sav4SvLexj+KvxRuoNHunMjxQx32otFBI275iAroxHHcAAYAy5P+CIv/BVdPiW3wqT9ijxg9+t2bcX6wRDTGPXeL8uLbZj+IyY7deK828Eahqvgm1sNZ8Ja7d6ff6XKtzp2p2spjntpkfekqMvKurAMCOQQDX1If8Agvf/AMFXV8Gf8IU37XD58jyDqP8AwimlfbdvTd532bO7/a+93znmv3LxV4jxGR5PkKwEqfs54WNvaKpeyjDla5E+j1Ts9rdT4vg7M/qOPzL2TXLKq7cyl3lZ6fij6R/4LiXfh39h/wD4JF/An/gl1qfjrSNa8dWktpqHiW1tdTd5rSKCOd3lEe7cIXubho4jIArLC21QU+Tj/wDgm3/wQa8F+HvDvwy/4KLftuftaeCPDPwyktdM8V2ejzXZtnu9wWeG2urm5MUduN3l7tnmlxuRSpYOPzl+JWr+KvjX4wvvih8Xvin4i8T+INRdTfazr+oPd3dwVUIu+WUliFVVUDOAFAGABVaXwZb6zDBp174v1Ke2tRshhmuNywjb0VSMKPpX4rQzrLMLkqwdHHyhOcpSqzVJtyc9ZKN7cvZPV6Xtc+8hmGEhhfZQrNNtuTUd7727H0r/AMFkv+CjPgf9vv8A4KF2vxf+Hd9qh8A+EY7PSPDr6lFsM0ME7ST3aRKSUWWRmZQ3zlFj3BT8irpv7b/wQtk2jxRcxBiokX+zJjkD0wvFfPWm/AvwpdBftGt3vzpuUxun8ttdLpf7LXw+vCv2rxJqybkztV4sg+n3KrFY7w/xmEoUHVqRjRjyxsund3i7t79CcRLI8VTpwlKSUFZWX56M+gNJ/bo+BGo6jbafb+OZYzLcLFGLjTZ1UbjjJbZgcnqeBXnvxFv45v2qxqBOV/4SCxYnpkDyf8K8M+P/AMIPDnwnl0mPw/rF3di/jmab7VtymwpjG0D+8a7XwNdP/bXhe5JyUt9Kxk/3YoQP5V+0+DeTZRhcVi8fl1SUoVMJWXvWvpOGuytqmfCcf5dhKGWYXEYeTalVS19JeS7H3dFr3ks6WD52v8y02TxNDHu2Px9123/NurhJPGSFdiPGGkX7zVD/AMJh5yNDDYbTs+Zq/kiWIPZjh5853k3iqaGZEe5zuTdu/vVXm8UzSqHR1KfMu7/arhLfxJNJ5c1zGsR3bnaP5vlqx/bEwZvJmZBv3bdvy1zyxXvnV9V5veNrVNWj2zI8LH+Lav8Ae/2awdSuHkaZ2eRfJXd5a/M1RXOr3M22Y7SG+dG/hWsrUrx5GL/bGHzfNCv8K/3qj6xKWxcsPGMCS6uoVkhdP4ov9Yzfd+asmTxBuZ03/d+8zfxUupXXmRvv3IjN8n8Xy7awb4+YrTbPM2r825trNW1OoctTDx+I6iPxJZx7Jpn+bZs8z/d+7UMnipL6ZkSZTuRvmVq4ZteRZE+Tascu7arf7P8Aeqt/wkjqu9NwP8Tb61OfkOqvvEUMkawwvvb7vy/3ax7vWIR/oyIvl+V/e+7XPya/5kLTWc2/+F2/ias+bWka3Z0ST/dZKJkxia9xrkPzj5l/e7tu7/0GlsdU25jDsySfdkrkbzUnuVPnblb73+1V/T7ueaOO5/1S/dRWb5m/2q5K0eY7KZ6b4d1BFaNHdVPy7K6+2u4b6XzvtMjL91FjfbXmGi6g62p/ffe2/wCs+7XUaXfGJRDsZFVV/efwtWEZRj7vMdMaPZHPNo80bFNiny/4t33v+BfxUNGlvcNBHCrvs+dt33a2pLVxGEmf7r7fL/ipLi3uWjdISpdflr4/2nN8R+g06PMc4y+TJstk3bvv7n+Zao3kflu8yfIrP91f4mrZvrVI2bYzMWVdtYd5cfelmdiyvuSNa1jU5oe6elTwvu8pz99IkzOkybqwtSWFZP30nlitnVI5FYolyylvm+asbVFeRzN8yuvzIv8AC1dtGXuHV/Z/u6RMe+bciTI+9/4pG+7WBqK2f+p8zYzfxVsXX2mabY/Rn+6tZeoN5a+S+1m3/wAP8VepRxHwnnYrK5cvMZDb5PMeRGXa33qGnebefs2xFRf+BNSszqyuj7/vNtb+7SWsaSbHQrtZNzfN/er0I1ouJ8risDOnIvwwpJD8/wAzf7PzUyT5t8Lp/urUunw/Z22JMrp/H/tVaksfvSQo21f9n7tY1Kh53sZy0ZH4XgCa1DIZhn5/lH8XymtTXrV59RRkbpD025zyah0LTY4NRjuEOflIzt9q17iyivJ8ZO9Uzgema/oXLJ/8c0Y53/5jY/lRPz7GQ/4zqkv+nT/ORStdGRWV/lf/AGq0LDRUaTZbWyp/ebZ96rum6H8/nXKeYN3yrv8Au1t6XprzKqImz522r/dWv505oydj69R/e2Zm2eh2y7nR/wCDasn92r62TyXCQzbgjbd8i1vWuh2ysnnWy4k+Xb/earM2miPakNgvk7Pu1hUqQ+E9KhKUTCk079ysKfvmXdsVv4qz7jSZFuC9tbKI1f8Ae7v/AGWutbS7mSMpDZqPk+9H95lqGTQ3SzV/sauqr8kay/Mtc1SXsz0qcubc5ebTzcSBHtpMM/3V+8u3+KqzWcyr5KJ8v8bMm5q7CLSXa2dPs0iIq7/ufw1Wu9Oj+yvD82z721l2/LWEpS+E6af8xyVxapNH5ybdzP8AeqpIzyRpN93d99fu7a6G4sUkhd/s3yfwt/FWJcafN/cjaVk3eWr/AHvmrPm93lNf7xHDsWQpPNtdk3bvvMtTWrecywvt2su5G+7uaj7HuhQfY9ki/wAS/wC1U8dr5OwO++VvuUvciRGUixZw3MkkSEqq7N3y/wANaEcM8arbOi7F+ZmVP4qbZ2Ls6P8AL83975a2I9Pdo9iQtu3/ACNv+6v96uSVQ9Cnf4iotik0e/ZU8fl3DJZu8YXd88jfw0rQbw2z5X+7uX7rf71WrWyTclzCjCNm+7Iv3quPLNROinImsI/3bTQopP3fLb5V21p2a/Y3a5s4d33l/dpu2t/dpdKtYZFDwsyq38MiVs2VjCsiTJGqfP8AO392jmmdUans9jKsY/33yWyqV+bdu3VpNbuu0QuzmRP9Yq/KrfxLUk1oi6k6IjfLtf8Adp/DWT8bPHCfDf4fzal4edptTmfbAqr+6t1/iZv9qvVwuHq4icbHHmmaUMtw3POXvfync6D4JubyNPt95b2KSfMsl1Lsbbt/u1oL8MHuLOWHRPGel3dzGm63t5Jdq/7NfEcPxu8Z6lr0t/ea9dPJcbVuPMl3NtX+Guj0H45eKrW+S6s9YkSSN921Zf7tfQ08DTp/ZPzTH8S5hiqvNCXLE9n+M3ir4tfDWFrPXvBmnx233vM01mbc3+838VeV3XxUv7i0XUrXxCq+W3z7Zfu/7NdrcfGKP4leAb7w34wfe9xta3aN90it/wDZV8pePLvVfA/ihktrlo0j8xZbVfustdcaMOkTxZYvFVJXnUket6h+0V4t03UNlt4nk/76+9UEP7T3idmHnax+737ljb71eV6lqHh6O1hv7Z/NSaJZUaT7yt/EtYN14ss3mdPs0e3ft3bqr2VL+UaxOKj9qR9FQ/tLaxDGHTVfvLteNn/8eqa1/aYv7hgiX/zK/wAy7vvf7NfNVr4n02STY+7/AGfn+7Vj/hINNiXf9pk3b6X1bDy1cQ+tYqX2j6S1L9oTXpIx9jv40O3btX+L/aapIf2h/ELwxQpesPl+Zt3zbv71fNVx4qh8xZv7SZvlxt/u0Wvjh13Jc3kbpv8Alp+wpdIi9viIx+M+n2/aE1WaTZNrEjBYPkVvm2tVk/H6/mkDveRy7vmTd/7NXzVD4ydv41P/AAKkbxlfqdn2j5aj6rDdRD6ziP55H0zZ/tDTQuyXOqbvM/5Zx/darlr8fvtDIlh4oaJlTb97d81fKU3jK8Z/O+0s/wDD/u1H/wAJlDCrJ9pVfn+6qUvq9KWvKP2+KX25H1dqHxu8SbXS28SLNLIm35m27v8AaqNfjVrenr52palNFLJ99o7r+H/Zr5Tf4ibW+e8bavy/L8u2q03xamVfJS83Bk/vVaoQjrykxq4iP2j7Q0f49eHrhWhm8bNbfIqo10/zK393dXrHhG40TXrWG/03XrW/3LtaSGfzP92vy+vvH32tVfzmDK/8TfxV03wt+KXj/SdURPDXiG6tpF/ihlZVX/a21pyuOxjJSqaykfpzrGvaJpNvFGl/+9VNqW+77zf3Vqr4m+M3gD4I2Mesaq9vqeuTRMlvprJuih/u7v8Aar47t/2hPE9x5N5qWvNc3FnBsgb+838TVSk8bXnjTxEs2oXjMfvNufdURcpSM/Z8sfiPrr4Z+PvFXxa8Rf2x4tdbq2aJtlmvyxx/xLtrP/bC/aYtvhl8LbybRNbb7U1n5dqqp8u77v3v9muM8B+LodK8IJeWF/JH8q/7PzV8p/twfFy/8beLF0R3jWG1XZ5Mf/oVayjy/CKk/aS5jwXVLnVfE99Nr2q3kk1zdStLcTSfMzM1epfsg/sVfG39sj4u6f8AB74O+D7vVdTvriNM29vuS3jZvmkk/uqtc78OfBOr+PPEWm+D/CuiNf3d9PHbwW6p/rmZvu1/Sd+yd+yh8N/+CDv/AASZ8a/td+NNMtG+I48GyXdxeMnzJcTLttrVP9rcy7vpW8IctLnnsVVrOVVUYb/kfPH/AATb/wCCZvwN8KftcP8AsofDOaPUovhbFHqfxm8ZNt8zUtU+VodPhb+GNW+9t/u1+p3iyHTbr7SiTLCYfusrfxV8K/8ABtPpM0P7IWv/ABu8evI3ib4j6/cazq1/dNlplaZtvzf3a+wPid4gs7d5ryF1uIZEbypo/mX/AGq/JOKMb9Zxkkvsn6Rw/gnhqN5djz34yWemf2Kz6wlndMytvWT/ANCr4J/ag+D9rqWoN4n8PJIPtW6KW1jZWSFf9la9v+Mnxp1K81K80ewv42i8/a7N95VX7u2vFvFPxA03WLUaVf38cG128qTdtZmr5vCzlLdntxwsfacz3Pj3xN8Ide0W6vNb125ukRZd0Xlpt+7/AA1B4ssZvGH7Oek6beec39m+OVVLi4i2/uZI/m+7Xrvxd8ZabY6X9mvNV/tKSTcrqqf6mRf4mX/2avNLPxtJr3w11uzv7CNE0+9t72JY2/u/L92vQqVK86XPE+hyipGjiFGZ1HwfbRNU+ImseHns9r6f4ek/s1l+ZVk8v5Wr4r8b3V5e3Et5qNzvuWlk82Zn+9833a+yvg/p9/Jr3iDxz4bv2eTT9GknSFXXdJuX7u3+KvhXxn4kmlvpk2KiNLI3l/xK275lq8lpzrV5yMOIJRjQsNsdQ0jSp47C1/ez3UuzzG/hrR8SWM2iWvlvuK/xZ/vf3axvAdlp1940sX1I7omf/gO5fu11HxWkS3tw8KLs83bur6PELlxEKfc/P5rmjJsyND33lq7oixr/AAq1aOkLeWMP2p0k8tv4d1VfBsLtao/y7ZH/AIq6W6s0kh3+cqBfuLtpVObmkZS1pLTUrad4kexmZ/4W+X7/AM1bVj4uuY9myZmXbt3SfwrXJ6hD5lwU3sqttbctbemw7vnj3f3l/wBmvOrRj8Rvg6s41dHod94ZvvtSHyd22b5/mroofD15cw7/ACWXb8ywx/L/AN9VyXgv5W3vtZldWTdXvvw30uw8RXEc0DrtV12Qr/7NXh4yp7OVz6OP76keY+Gfhbc+KPEAs4XVkbcy/wC9/s1d8VfCK88P+IrfQbl2aOP97PJ97av+ztr39vBOleBGHiV/Lhe3dmihjT+9S/D3QdE8WfEZpnuYUuVl2peXX3Vj/vV50cU5T5vsnA8HPfqfPfh34P6l8bvilD8JbDWJtBtb6BfIvL5vI3M33Wb/AGa9O+P3/BJD/hmj4bx+NfFWqyQ6/HdbbDVrVPtNn5bR/wCs3Nu3fM33a+yrf9iez+Lyw+IdCe1GrW8W61muG3RMy/d+b+GvYJ/2Jfj74k8Ix+D/AIh6wzWEMW5fL1FmSNtvyrDX0WX5rLD8sacfmc1bL6OLjy1NJH85eoeDLnwjr15oklpI81nKyTtJAyfvP721v71dDo91NHYj7S7fKu3/AHa/Vb9rj/gmr4Y8Lz2MKf2hr2t69r1nZrcX21pfOaT5vu/wrHXCf8FEP+CbPw0+C+l6hZ/C143udNs7dYtu13kZl3SV61fNMNiP4jOT+ysTQn7OB8U/BF/iIusSXnw+0qa8kkiaJ/LT5vLb+Gvsz9n34ofG/wCC/g+XxVd6DcWt1NatBptvJLt/eMu3c27+7U3/AARc8D+A4vG0th8RdK+0pJeeQ0cny/Z2ZfvNX19/wWB/Z9sfht8N/BfxI+G+n7tEt5pLDW2t/u27SfNHNJ/st92vJjCGLx3IfQU6NfL8NGfN8R8DW0P2FZvt9551zcSyT3twz7mkmZtzM1J9oS4ZkRNy/dVmT7zf3qk+SHfsdRFM/wDrFX73+1VdY9shj+Zyyf8ALOvrXTjCHKedGVp8w1JJm2/eZ1Xay7KuWf2ny2htrNnSP+FUpVtIZFS2nfc3lbfu/Nuq3b2c+0jeu1vleRm+9/u1yR96Pmby5iTRf30izPcxqrfM67fmX/ZrsNLX54RMVO52ZtrVz2gaP5MzSPDC6bm+ZX+9/vV1mn24/wCXZF37Nsvl/wDstehh4+z0Z59b3i/psKTXUqfLsZPvfxVfWbybd4fmDr8qqqKu7+9uplmvk2vnIke1m2rtqF77y7cvcwyOGfb5a7f3derR5uQyvGO8ihq2yZU8kNGytuf5fvLWNdXkzSPbTBU3bWiaHay/8CrZ1ZUmVvJm8r/a2/erBvLfbDLc+d91/m+T71d9GMY/EYy93WJ5p+0LcpN4dto1dPl1EAqoxj929O+FO2H4fwXBKbt8irGBlpPnNR/H5Wj8K2SGN8NfhhIejfI1J8MWJ+H1v5gCqs8m12Xg/Oa/orHqP/Eu2DX/AFFv8qp+dR97jes/+nS/OJoXk00cbeTbbtz7Wbf8y1zWtXCNvd9zqv8AtbdzVs6tqk32czPuwqsrqq/NXEXl4djzImNz/e/vV+EyjzR90+mlPmlcZcXlyqpD9p2o25n/ANn/AGa1NHuoLVTf3/3I13NIv/oNc/CsV07JbQsAybvM/wBrdXM/FL4hWFqv9iaVN8tu7faJN/ys396uat/KctXEe6ZnxY8dWN9eXOpQzbGk+bavzKv+7XgnjLxR9uvHTfWx488Xi4m2I+fk21wVxJNeXuxEVtzfepf3Ynn8vKWo9VeNd/nMqr/dqaHzpG/iwy7v71XPD/hO8u1+SHesj7a6ZvBc2nxp50O3bt+WtOUXNA5OOH7u98/J8lVb6Z1kbftRfu/N/FW/rS21qzQJ9/723Z92sHUlSb/WIrbfvbqiRcfiMe63yMewb+Kqyq/3Ni5q+0O7zdg27qreThU+Tbu+826l/hL+Ej87PyfN/e+Wr2i3DxzfI3yr81VZvlj4/wB2kt2cfOgzt/8AQqfwknq3gm8m1aNIXwzt8vzPtrudN8HpeRsh5f8A2v4a8k8Fax9juopnfldte1+FNSS4tVmhfcsi7dy/NtpxkZ1I80TIvtFeyZLV9r/P/D/DS22j3O4PMn7r5tu6tiRfOum3wsqxytubZ95qmjtbZmXYjLt/8ep/DqYxlymZplv5V1/qd43/AHa6WxV/JVE2pF/eWs9bLaypsyqt/D/FV5ZPsdu2/wD3aSjylS973kcf40vE02+fYnyyS7mZq81+JGgzfZYtb02T513M+2u7+LEb29rDMlyzjfvauW0vVk1a3ksN6sG/hkT7q0cvLI0jKUoFDwP4mTWLHyXuv9JjT7rV0yxvIrp975NzKteS6sLzwP4scQoyDfu2/wCzXqXhPUodcs01JH+795dtL+6El9oWSHdOpT5NqfeaoMosg/8AQa1ry3i2siI336z544wqo83z/wB6qjICpa6tc+B/FmneKtMm8rybhWeav0p/Zp+KGm/FbwXZakjxyyyQK0reav3l/hr85rjS7LVrF9NdlH7ptv8AFuavaP8AgnN8VLnwb8Sovhd4kvPs9teXGy3Zv+ejfd/76rroy9w8rGYfm+E/SnwZrGp+G4by4ZFWFrdxKzf3dh+Wvib/AIIy+HdI8U/tgvpOuTbLdvCt0zsBk8T23SvviLw3Mvgm8spn+5YylVb+H5DX5jfsN/EbVvg/q3xM+Kmg20kt7oXwi1ee0SMNnzXktoUb5eeGlB/CvtsgpKPD2ZJdYx/9uPouGZOeR5hGfSMf/bjg/wBp79pG9+O37V/xH8UaTrNxBpWoa9LZWOnxORG9lbMEiDA9cGMOPciuPtdK0y/fzb6xSRlBxK3VQOcDscnt3xXmvw787/hJbdppt7MjtI7feZ2Usa9Dh1OK21NLKRh+8XIB+p/wrCguXgGt/wBfl+UD2aMF/qpUjH+f/wCRPoT/AIJ+fEr/AIUr+0N4e1jQUhhSa9VLppPvbf4f/Hq/WX/g6at9H+MP/BIf4fftCaa8bzaD400u4imX+Hzo2jkX/vpVr8Q/CuoPY6xaajbXKpJbyq6yN95dtfrp8XvifY/tT/8ABuX8S/hdq1/HqGt+EdLj1W22/M37mZZN3/fO6vhYylCsmfKRlG7gfi9b6hHqdjb3cbhswgEqO+TWpFPPZygwoz7m27a474a3f2zwvG+0jbIRg9uAf61718M/2dfiB8Zb+Gy+Hfh6bUrm6A8q1s4t8n3a+24oqxp8NZZKb+zL/wBtPq85hJ5Rgox7P/205CSZLqz861aPev8At/drqfAPjRNatf7JublfNhb5G/ik/wBmuTvPDuq+FdWudB8Q2FxaXNvLJFLDdRMkiyL97ctc0Nafwz4sTzdyxyOu1v8Aar4Jcko80T53D1Jxny/ZPY9W8maNZkj3fO3y7vu1z18rtJ52+N137tv8Vb+ixprmkpqtsPmZGZvL2/K1UbjR4fOWGGRmT5mlbZ/F/eolU5fdPQ9jGXvGKZpDMzw+YF/g8xt1QeZNH+5HzBn3OzNWg+hiPdMm51X5kaq91pPlq8zv5L7Pn/2qylIcaPc2dPYjw3vLE4hfnP1rkri6e437EUbf/Ha66wjP/CO+UMn9y4GfxrmYdEmW4OxG2N827bX7143OUeHeGH/1Bw/9IpnzHC8OfG43/r4/zZHb3V20OyZPl/hZa3tNmRY4YXRm+f52X71U7OwfzHfZsRU/76atCztblbhYUP8AtOrf3a/nOpKfKfc06cDptPvHlXYm4D+7/FtrqNK1j93C8Lsm3/Wr/FXG6XBN9nXZH8zf7e3bXUaH++X7TCjNH/e2bW+WuGpW9jqejTwsZHEftX3/ANvvdEdndmWK4BLjB6x1p+CJfLuvD02Pu2+nn5hnpHFWJ+09MZrjQ8vkLBMo/NK1fBShF0IA5/0ezPP+4lf2f4EVHLhyUv8AqExP/p2J894h0vZ5Fgof9Po/lI+iLfVJpo1f5WK/8tG/h/4DU76kluDNZzSSfw/3fmrItZvKmb7S+8t/F/dq9p8aTNFM77nVGZty/LX8Rzx3vH2cculKPMaUcyMqTIjNIvzOqy7aS3unaZ5rbzAn3ZW/vU61s4dqTQ8ll2tu+8tSyafNJh0LB4/4V/iX/arCWO943WX+4N+1btiO+1ZG2/7NEyvdLsubja0aNuX7u1f71LNazm4ltk2om3d/s/8A7VRzQusyeSn/ACyZd0i/N/u1vRrSqfaMqmHjGGxTvreYx/aXfb8+51X5ty1zupWztC800MeZEZUVUrq5rN4YXML4KvuZV/has6602G4hMzo33/3v8Py16OGqcsfekeVWo82hwmob49qJbRq2z7sifLWPqAe1uvOG5AzK3y/w/wC7XZapodtdyOieZt3bvm+7VB9FSF03w7lb7+35lr1Y1I/EedUw/wDMcjdKklqs0Kfdn2pIrbd1VJov3zOm7LffZXrqbrw1DHGxm+R93y7v4mqheWL6evnQzbnVVTcybt3+1WnNzGP1eXP7pgw2CQqqIm/zPl+atKxVIlCPCquvybt33ae2nv5zvvzufbt21PY2OVW2RPk+8jMm6uatsdFOjyz5S7a3RXajw7tv3423bt26uo0e8hWPZvy25f3kj1y1rC8alPOw/wAu7c/3f+BVsadcP8ls772VP3TN93/ZrzZHoxpyirs624h2uLnyV3q+5Ny1Su7n94rvt3/xLsrobzT3WMvNGrt/DtT7q1kalp0Kx/bJnVE2/e2fxV8f9o/SKNOTj7pzVx++t1d3jJX+JvlWue1b95K0yPhVfdKvlfM3+61dVrUdmrbIYchvm2yfxViapHczR73RtypuWFW+Wuin7p7OFwvMcffX4UbEmy8fzIqxVj329mbZtVm/266DVrP926Q7k3J87bvu1l6hHDIrJcpGWVVVpF+9W1Op7P3T6DD5fzfEctqVrM0yujqzx/cWsvUoH3CGZ1RmX7v8VdNqK2cK/afNbZv3JGqblWsG+jgz5Pkszs3+s2fdruo1uYWKy2PKYs1i6xlN6q6vtTdUUNvNI32Z03Mrr82yr8gSEbN/yx/N/ebdT7WxEanZG2V/ib+KvWp1uWHvHwmbZfy8w/T7Pdbr8nzb/wDV761rfR7i4jHkjdt+Xy5P4qj0+3RY4vOTc/3v71bluvmyJv2gsjL8v93+9R7SXNofGYij7OBVs7FkCzpGFSNmXaeq1r6Zbyy28jRyAfOowVzmnXKSpZPHwyKQVkH8QzV3wmkssci4Plq25yB7etf0LlT/AOOZce5f9Bq/KifmWN5f9faV/wDn1+si7Y6bDNIsLuvnbf8Ad3Vu6fpbzQ/JDIj7Nrbv4WpbXToZljmhsPOePb/rNu7/AGlrofDtjCsikQsu7du3J92v5y9pL4j6+nH2kveKsOnmSSNPJUsv3m+7Wg1qkUDb7NU+fdu3fe/2VrSt7NLdXRII5Gk+WLzHqSazRm+fa7qzbfl+Va5ZVPe5jvo04x1RzjabMpGzasn/AC1bd8y/3flpfsv7s2E0avJt3fL/AAr/ABVtTaTczKsyJuPlf39rfepI9JdZseRsVXVmb7yqv+1USl7SNpHTR7GB9j+zslzD02fMq1X1Kz8ze4s4/wDY2v8AeX+9XQx2qMzukyrGzt8q/Nu/2qq3FjC6iaF9qTfLub5dzf8Astc0pe+ejT5pR90468015WkvJnyGbb833fl/2azprH5l+zbSi/7FdndaK/2hUQR7v4lZ/lWqH9l2awtD5O52lZVk2/NS/d83N0NJRqyjY5dbHzvkeFkC/d2/NupLXS/v77dmK/wt97bXQNpcLLK8Lsm37zbfvVDb2c3nDyduP9pfvf7NTKUOYIxkQ2lrM1x5Lu21dr7W+atFd80gRE3N833f/QaWG3mtfnS2+8+5/wDaWrn2VNyTO28K/wB7/wCKrA7YxlErQ2EFq2x08pvm3/xfdqzZW/8ApXnQw/dTcn+1uqKS1eO4a5+zM+5mVFVt26tXRYftLR703hUZXbf83+Vp05SjHf3Tb4p8praLoySKlsjsq7d1btn4fkmjcyfcVP4v4qb4fs4Yl/ffdb7jM/8AD/DWh4qU6boc9zC7Of4I4/71Vh4zrYiMEbVsRSwlCVWctInnXxK+M2leEdWfw3Z3kc2pSOrJD5XzW6/3W/2qd8TtU8N+IPDtvoKaVHEby3+f7Qvzr8v3lr5n+LjeKvh/8UD4x8SQyK1xcbpVZ2+Zv/2a9T+I3xFsL7Q9A8bW95DNb3EH3VRtsP8ADtr7zCYWOEpWW5+QZxmFXNcVKo5e79k8C8ZeH5/DviK4s0dk/e/K3+zTrO4P2dXT76/Kkn96ut+NVrZX3leJ9KdSlxFu+VNyxt/drh7S4e4VXwpdf4V+Wu7X4jyeb3DqfC+vTLMsKTbTv3bmf7tcf+0NDDNcR31s7Zk+8u+tCG8TT2aZEZTt/v8A3a574iXCapZ72ueFTb8zfNUy94qPvHDWOqXMKrZ3T70/g3VVvFRpN8Lsqt81LM/2WYOiZFRXVwksexIP4/vNT5eXQ2jLmI2uHh3bJttEupTLGu/cw2/w/wAVVpFRk3qjfeqKRty/cXK/3qfwxD3i39oeNl37iqr/ABUR6puYbx8v3kqg11tUo/X+8tRNMzKsmfm37qRXLym0viBA3+s2uqfdqKbXHZSkN0y/3KyfOf77yc/3v71EbIdrvubbVfZFymnHql2u5xM3zff+annWpljH77ft/iasuWZ9xpPtLrDj5TUi5ZGlJrlzdSEu+Vb+Gq11cI2E8mMVSeR3QPv203zMqv7tjtoHylppLfcifdrsdJvP+EV8NrPDNvuNQVkVv+ecf8TVxenW/m3ibwx/vbq0L7Un1S6XK4ijXZEu/wDhqpP3bMXL752Gi63Myq7vkL92vV/hHH/amoDzl3K33f8AarxDw7BDdTIu/A/2a9x+HOzT9PXyflKp87N/DTtCMeYxmep+LPGVtZ+H2tnRhHbwbYlX5fm/+Jr468dalc+IvHVxeB9/mS/dWvc/jN4wh0vwu8MN5IrSIy7f9mvDfAtrNqXiVpkhaV22/LULmlVHHlpw5mfrR/wa4/sAab8ff2lj8fvHug/atE8ExR3UUMnzR/bm/wBT/wB87d1fbv8AweN/Gy88Bf8ABPTwj8F9NuWjbx94+hhulSTb/o9rG021h/d3bfyr6S/4N/v2U4P2af2CPDd9qGlfZtV8VRLqeoGRfnZWH7vNfnj/AMHqOvvL41/Z/wDBkwZ7fytWvWj7Ft0a104ufKuRfZRllsZVE6j+0zoP+CLH7V9h4L/Y48O+GNbhkaO1gWBbeFdrRqrNt+b+Jq+k/H3x20HxF4dfUtC8SQzn5lltbf8AdtH/ALLLXyv/AMEh/gf4e8Qfsw6VoOtuzLceXPFNJB/qWZvm+avor4yf8E7te8K+Hbzxh8PfHrQzf8fHk3zr5TL/ANdK/DswjTqY2c0ftdCXs8LC/wDKfPXxX+LGlahJND9jVJpnZrrzIvu7f7rV86ePvEtzHcPDo+ox3CQ7mlWOX5lWtL4qXXxR8M+K7zRNe8N3yhk/10KbopFb+JZPutXmd5oPiTWJy907Q+cv3ltWZv8AgVGHwvu8xt7aMYf3jhviB8SJrqV4ft8flRtuTb97/dZqreBZLzWL93ke4W2uott1Gq7v3f8AtLXoq/s3Q6hIupXjx3CTJ8qtA0e6s7UPBeveC5ZrPTUZbZU3I1urN93+9XdyRpxFCdf4jzm4vPiF4L1xr/wxrE0DW7/6P5cu3ctcjqHgPwl8Qrj+yvElnDp2rzSs32yP5Vbd93cteueJG/4SzT99gjS6pGm+Bl+Xdt/hZa868YabYXnh5PE9heKt1DKyXVu3ytG3+7WeHqToTfJodWM5sTDX3jyfxF8GvGvhPxh/wjbhRJC6tFcb/kZW+61HxQmh02zg0qW5he5V13NC+7dVzxl4q1jUoS95fySPGnysz/w1w2htN4i1hZrmZWijfP7xa+hw/tMVy1an2T4fGcuHn7JfaPQvC9qlr4fgmT+FmZ1b7zVqT606xrbbIWXZ+63ferOj2G32Pubcm3b/AA1LHpqeWn7lt0a/JXLWlGM+Y55PlVkT/wBl/bI1uU5b+JVX7tadja+Tg/N/s7v71Z9j9ps9/wAjKjMu1t/3mrYhkRdjvt81vveZ96uHE1PdOnByjEu6XqVnp8y7I/nkf5tz/dr234D+MobeaNPtiu3m7njb5d1fOtzqTtMJpIdxX+Jf7tavhPxs+j30Vzs2vG/y+Y/y15GIwtSrSconr4PGUqc/eP0BjurDxrpvkzQwqskX+s/u/wB2nfD34Q/2bqU32O5kuV3K0u77v/Aa+cPhX+0PctDb21zebmV/mj/havpn4I/F7SlWH7S8km4bpdzfMu7/AGa8aUZRjyz92J9TQpYfErmPsX9kfw14zZ7axsbOOQyNutVbd8q19Txr8arnSoNNmhsYU2MjtH823+7XzV+zl+0R4P09ba5v7ZkCpsRrX5a+rfA/xW0rxjHGtsPs8YT/AFk3zbv9mqw/sHHl5jnxmDr4f94oc0TktX+EXhvwv4j03x54zePUJNFikn02zkC7ftDL80n+9X5u/tHat4k/aK+NniCzhtv9dugi01flaHb/AA/L/F/FX6N/tSfE7R/A/hS5v/JW6mhi81lk+7t/3q/KHxJ+0Po/hv4ral8XdHmtYvLlkllj837237vzf3lrsdOnbkj6m2X04Rh7aqvekdT8Efhanwr+H+qa8eNS0m/VpY9qrL8v8TL/ALNfbnhbxv8AD/8AbK/ZS8Tfs7Xs32qTWPDUkVncRxeYy3SrujZf91lr8yrf9oi/+MnjDxH4n0G5WH+0P3t/Zwoyq033d3+7tr60/wCCZfxNm+GvxGikuVX+z3u7eFEj+bzGb+7/AN9V6NGNSlWjUUh1qcMVhKkHH/D6nwfY6Tq1nCfDetwzNqOn3ElrdRrFtZZIWZW/4F8tTLGZG85Jmf8Ahddm3bX0h/wVZ+Blv8E/27/F2l6SPK0bxZaw+INMWP5dxuPlm2t/D81fP+naOkMfkOihFbajb/vLX2yhzfFI+Ep1o8t1EZa2KfN5D7dvzbv4v++q0rPTU+zjf++f5tjbfmX/AGVp8MNs37mHc6N8y7Ub+GpY2mkt2heHZ5ny/N/FSjS5tYm8q0Y7l7R/J8mZ7bbK0e1fmf7v96uhs2/d/vtyfw/u/m/irJ0y18+NER2V2lVn21vW8MK2+/5mC7tu75f97dXp4enGMPeOGUpVJFlVtWh2fZvL8v7sf3arSR2yoZkTdtdW8tvvNU0NvDeSF5tzBX2+Xu3Ky7flbdTLi3SCH7+zzP4m+Zq7acQjzVChrFrDDKzvMqLsb5m+by1rCvFgXdGm3KxLu3fxL/DW3qjM1jNbPuTzF+8rqy7f92udurh5plhSbf8AxRMy/wANd1P4/eJqU5Hm/wC0PcW8nh6zSEtuN6GkU9FbY1VvhtIIvAtuHkA3SSeWB8xzvP8ADU/7QLRSeGbSSOJlb+0cOWXAJ2N09qp+AriP/hBrOLf84aYLuXhcua/oTMfe+jtg/wDsLf5VT88jTlPjisv+nS/OIniiSaG1lmg/eu3/AMVXK2qpfXDQQv5vztuWP5trV0Ovb7yXf8pVv4f722q1jb21jHLeX8zQxwqzfN8qr/tV+Dy+G0T6StGUdTO8SeH7mx8PzeVtWa4i/hT5lX+Jq+fPiZa22iq6faVK/wB7fuauo+LXx8upbyb7Nqv3V8pNv3fLrw7xd4xm166+0u/zf7L1z80uY8r+JqY2r3T3Fxvi2vu+/trofhz8P7/xNfQoiMTu3fcrK8M6K+saoiRoxeRtvy19X/Bv4W2fgPwynifVUjSVovl3Rbq0ic1SXu8qMnRfhbpvhrR2nvEjV1XcqsnzV5/8TdcsNNkktraaNj/DXV/Fz4tPHG0Nq+DGu1FVK8F8SeJP7YuH892J3/eas5VOaZdOjGPvCXl490xmebO7/Z+9VC6aMq2zcW/3aZbyI67Hdj/u/dqG8Z4s84FVGJp8RFPI7Lv2Y3fw1Ey/KXxuX7zVIoSaQOflVqRIUjZo9mWb7u6jm/lJjsNaPzofP8natPt7dJI/kTd/wGlSNt2xPu/x1Ztdkdvs/wDQamUSvhgGm+da3CuibmVq9l+FfiiZrFbD5W27mRdteS2cKMu8xspb79dj8P8AWv7F1KLe7eV/H8u5qPs+6RKPMekNM8zNNv3Nu3bVf7tSrInl+d5zfM+6se8vNt5vh+43zfNU0l0lupd3+X721mp80okcsfsnQrcOzb9iuisv8VTXF1MvL/Nufci7/las7QbpLuPyUfbu+b93/FWrcWoWQ79uFTb838NURzcvxHF/Gb7HJoPnQx/6tdrba8i8L6p5OoMm/wDj21638YAZPC7oicq7fMy7d1eF6fdeTff/AGdTzfZNYy5vdOo+Lmg/2ppMWsWcK7YYvmaP7zf71c78LvGk+g3/ANgeZvLkbDK33a7vS/J8QeH302Z1O5P4a8m1/TZvD2tyw+Sy7W+SrlH+UunLeB9BRql9bm8h+YfwMtU76xeNhhPu/c/2ayfgj4uh1zT/AOyru5UuvyqrV115abv3zoy1MZEVP5TDsYxHMrOisP4KtXV1qWk6jbeMPDFz5N/a3CyxSL8rblbctV72E2so87b/AMBrY8K6Mniu6GjzTeS0kXyTN91WqqfuzMcRyypH7o/8E4bu1/bh/Zig+JOn2Mc99ZabOmrlfvR3EULL83+y1fDH/Btz8MPA3xn/AG5fFvwu+JOkw32i638HdZtr61nUFXVrmx9ag/4Ib/tK/Fv9nT9oTV/gbZ6ww0fxRp1xAbeZtsTSrG21l/3q1P8Ag2T0jU9b/wCChutWGj3hguj8LNUMLr1JF3Y8V+gcOSmuH8xi+kY/+3HuZHTpLIswnD7UY/8Atx5F/wAFSP8Agjl8R/2BfHj/ABf8Oac958P9Q1aW2tb+IZWzd87IXPqccV8PeONQk0zxHaXSyYAg+76/Ma/pm/4L3anBdf8ABIL4laJqkCLf2eu6FKI5F+eMnVLZGI9+Tk991fzJfE2N21KAmMlDb4YkfKOT/iKbl7XgSu0tVVV/ujqXlkXT4NmpS5k6mn/kuh2vg/xhHfQp++Xb/n5a+vP2X/219B+APwN+I/w98YGS80/xN4IvrCzsdvmRyXEi7Y1/8er88ND16bR75cPs2/L/ALNeraD4mtte8Pm2+V5Fi+81fnkZS5onh1KceW6Mrw14fbw1Zy6aQNvnl0IHUFV5r6O/YR/a88f/AAC8b6X4w8AapHaTCbybxmgVt0LLtbbu+78tfPGkXc11bMJiT5UhjXPoAMVk/B7xZHa6qsDXm3a53bf4ea+04xw9PE8MZdTns4y/9tPqcwnUp5NgZR3UX/7aftb+3F+xn8BP2wP2HfEH7ZPwQ0NrDxh4NsFvdWt4fmS63bVbdt+b7vzV+NvjqzhvtHi1IvuMa7ty/wATV9j/AAD/AOClX7ZP7Ofwn1j4UfBzxho//CO+ILJkvdL1LTll2sy7fM3fe+7Xyh4nsbm6024TVbxriebzHnk2qu6Rm3NX5/gKdTDYdUZ9PhfkfLON67qxe/xep2nwD1j7ZpJtodpaRFl/3v8Aaru9Q0O2lk3pbSZ+9urx39mq6ubPUoYXhjCxy+U0bPu+WvoSbRbn7R5O9Xf7v+6tKpGVOZ7+D/e0jjLrTdp3zfIi/LtqrdaGdv7mGQL/AAbvmau8m0fzICksKt821JNn/oVVm0O5WN/3KvtRV3NWJ11KMYrQ4sWQtk+wnJxkHnGc/wD66gh0XdI+z/eRV/u1s31qyeIvsciknzkUg984rorXwzbQuUCbK/oLxtclw7wx/wBgcP8A0imfH8J0+bGY9dqr/ORxi6O8ceyaHbt/harEOl/vmeL5kb5WXb92ulPhkys7/d+b5lbd81EekvDtT5kT7u2v54qRPuqMeUoWNjDbqtt5PzyfK+2tPTbXdH9md2VF/hVv4qkt9NgSZo9m7+KLzlb/ANCrW02xTznd4Yyqy/d/irx8RGMuY9bD83Q8i/afjdLjRDIgU+TOGA9QUzWz4Ij8ybw/ET96CwHPPWOOs39q2KKC50KGB9yCGcj6kxk1qeBuLnw9jP8AqLDp/wBc46/s7wEXLwu0v+gTE/8Ap2J8v4jtvKMFf/n/AB/KR73DpqQts3yF2Zvl/wBn+9WtpOmwzNvSb+Hd8v3abYsjRM4RQzfKvzfw1q6Pp/yjZDhPmZP96v4KlL37SP1GMYdC5pen21vMiffMjfJui/iq3dWqMx+xw/OrN5rK/wB2pIfOjVCjxp8nyN95dtTzeS0ghd9ryfM7RrtXb/DUKPNPmKl7sOXlMWSzeSEvDbbFVd3zfxVAsSTL9phfejfL8r1sfY7b+CZXDfLuZ/utVeSxhVJQm4fw+Yq7f++a9KhWOOtR90ypI3eFrZ03Ffn3bPvNWfNYvdTRpcoq7vuN91f+BVsNZ+TIz3qKkOzd9+qs1nCs2x03pN8yKv8AFXq0pcsjyJUYVPdMi+0ubyW+x/K7f8s6oTaO6yedMiqdvzMv8NdK1qjMu+1aFI227f71U9TtXWP7GZlRW/ib7q/7NdlOt7vKZLCRlqznZNHtvL2IF3zff8xd1ZWpafDJDsRFU7Pk8v5dv/xVdTcaX8rQ7Nx/2m/eVj39ukcIdNwKt8qq+7d/wGtPaT5rI6I4OlzfCclqNnN8kLwSKW+WJo/lakks0t5Fh+ZH+ZvL2feWt2+sfMm+ezZ9r7k2tt+apre23XDfafLkfyvvN97dVVKnu+8Zf2fH2pg2ulzW9qYUSRt3z/vvm3N/s1q6bprxsJvJZNy7XjVvlWr9vpM3lq+9VZW3fLXT6Lprz2YdIdvmS7tzfL8tcvOa/U/cLUzJcRh08tXb5U2/NuaoGh+2RmGS22uvzMsi/eWrksfnKZPOVWj+Vd38NPjZLhfOh8wN915G+9tr5ONOUY3PssPUjKqcxqFqisf7iv8AM0ibtq/3awNWsNsfnTOqJJ93b821a7e4jeSGSaZFKRru+/8Aerm9XsU3F54lUsu5/wDZ/wB2uqNOWx9Ng5cpw+oaejNshsPNNYurRXO5ilmsfmJubd83/Aa7S8sE8szIGPzNsXZWLqml3iwrNNuDyblVmXarUSpykfV4GUTi76GG3tX+Ta33XX+7WJLaorcv8vzfKyferpNYsZljPKll+b5v4q55udybPuoy/wDAqVPmpx0PQxFOlKhzGbfW6NCN6Kn9+mRr5ZXyeVb7tXZrF5o/J3r8z/w1EqvCr/J975W3fw16uHqc3KfnmcUepa0uGHy2MM29v7u6tXT7q2W4KSIxLJtT+8tYizTQyND9zcu1P7zVcs9QdWdHSQfwJu27mr0KPN8R+XZpLlnym9chRphR3IdQMAtyRnvWl4Kdlt5FWIY835nJxgYFYct95sBiaFgCcIze1bfgi6EIZZDhFk37sdDgV/Q+XqcfoyY//sNj+VE/KsXrx5S/69frI7TQ1eOVfuqu752/irrdPszNILmF22f7nzVg6PCi4vPNXH8X+zXT2UjxrH9meMRLt2MsvzN/er+Za8veufoGFwtWXxFu3jhbCfZlX5PlZV+ZqsLZpNcME+RG+ZVZvurSaTG5Y/vm379rbmrVht4XZ0mRcKi/Mu1tzVzVKnwxietHC8vvGbHp6bk/2v8Aaqnq1qkKTPDDub+Ly3+WukjdF/fOi5ZNqLs+Zqz7xra4jdIUx/DLH/eq6chSjGnsc1crctG/2ZI9/wDG0dUJLXaxud6q/wB1vk+Wt280l4W861hV2/55/dqjIr+SHCKPkZU3JuoqU4F0Zcpl3Vn56lHf5f8AZ/u/3qr/AGdFYzPBsf8A6Z/w1o3EM0MfmP5efu7l/u1A3lxr53zI+zazf3t1Qo/ZRftve94yLyOGRd6LJu3bdq/Ltqj9nhj3+S7K6tuX56276GaP9zeOzCPd93/0HdWTNZvtc/xN/wAs5H+7SlGMS+bmI233DF0fDbPljZfm/wB6ra+cshhR2wybmZl/iqmzPJIiTbvl+Z1Wrun3ULLKibi+1mVV+8q1zSjM66co8xcitdswT7y7/kk+6y1s6PaJCqfuY8q38KfeqvouyYfIi42/O0ny7f8AaWt21VCy2SQxukas25f9quapJxlynXTjzF6xt1t3jma2jeSP/lmz1R8O/F/RLLxld6JqVms0cMGxo5E+Zmq22q2FjZ3F5c/L5dvtRV+VW/4FXmGl6S+raxc6rC8a7WZvl+VZK+vyHA8376R8LxTmkX/skPmdt+0r4d8DfG/4a3mlaVoMcWo2su63mktdrsyr/eWvjv4c3l5N4d1X4FeJ0a2vY90+kNJF+8+X+GvrfRfE1toerRJcxzPK23dHI33a8y/a6+Gb/arT4x+BrNV1HTZfPuFhX5ZlX726vqPipHwkZTijx/4Z6tbeKNLuPAepfM0istvIyfN5i/3q4/xRot/4V1yaHoY/kbc33av+JNQttD8UReM9Ef8Ad3Sq+2P5drfxLW38QtUsPHVvb+IUsFiKou7/AGmrOMuUuMeX4TkI/JazXf8ALt+b5m3VyniK4hdXhf5q39QvEhL23zbv738Ncbr1xDcSP53O2qLjExb6Hcsib/lqn5ny/u9rCrl15asUT+//AH6oxr+8aBE2/wB6q+I1iI0O759/y/eZWqG4X++f++RV6a3dYwnzOG/hqpdL/wBM/mWpKKEm9nfYfu1HI25qlujubYE5qD5wpL/w0DjuGZNvT5WqVVm3bPl+7UJbIXPrUiSfN70CHMyr8gC52/eqLznb5MU2RdrUsa/MMvQPlYv3h8lMG9cAPjdUw2Rn56LZTNOiY5/9loiEdyw0v2ez3p99vlTb/dpbXLfPsqC6ZGuDs+b+7UlvH5jf67azf3aPiJkdV4ZXy3WaHapr1bwvcX81v/rlVFSvKfD6/ZFjmmdW2/8Aj1d1Z+Jpms0s7K22f8DrT3YxMJR5ir8WtS3WJSaZXZfuVufsD/C25+Mn7RnhXwTbJ++1bxHawRK3zL/rF+WvL/iJqc0l5smm3H+Fa+1v+DfrwH/wl3/BQD4fPNCpitdU+0O3+6u6tMLH94jHFy9nhmf1kfCzwrYeB/AmkeENMt/Kg0zTobaNV/2VVa/CT/g9SsZh8UPgBquxTF9g1SD7207mkjr97dIvMWqu+4fL/FX4p/8AB5j8PJ/E37Pvws+LltFuj8NeK5rW8kVdwRbhfly3/AaxrwnLnN8FWpU4wRh/8Eu/HltpnwR0h4Zm3Q2sf7lZfvfL96vp7xl+1VdXVvcWbotwkdvs8mZPu7q/M3/gnL8XH0/4I6Xa7FcxxbXul+X5f7teu638aprq4ZLm5ZYt+1tq/My1+JYunGONnE/a8FVvh4VD37UNe+EXiC1uft9s0Vy0TfKqKyW/zfL8teVeLtQ+Flpl/wDQ5ZI7hV2qiru/4DXlfib4iutjMIbyaISJ/wAs7jbt2/drxHxx8Qrm61Ca5m1hpZl/4+m37d392tKKq/DzBUlQ5+aR638VvH/hXR7e8vrOzhiMj/ejutzRsv3dq7vlr5s+JHxqvNYZtKtp5iV3B2t7jZ97+9trC8cfEq/1KOWzhtrWaKb/AFsdx97/AHt1cKuuSfaHvLO1WGL5fljavRw9GrL4tjgqY2HwwPbvhRdeHvD9raeJ/GEluiQpuTzGZl/3dtcP+0R4w8AeONcfVfB/hhbC++7dXFq7Ktx/vL92vPtZ8aXE8LWb3OB/zz37qzNJ1YXl4pfc+5vnZvmrSODlHmk2GIzSn7LkgZHizT7+40+4TYqMv91vvVy/hWOGG+WPYx2/fVf4q9T8Q6XZyafJ/pO6X7u3/ZrhYdF/s67eZDtG3dur08LWj9WlE+Ux0pVKvOdRYyeXboIUZv4dslTNqM0bP/oaqm/anz/drC0O4mVW2Q/Lu3feqW5vpvLb+FG+8zVzypWlrEn2keX3jWm1KFTv+4V/9C/vUDXEkb7+Q3yqy/8As1c810k0av1b7v8As1IupPCyx79y/ddV/hrKWH5o2IjirSN6b9+pRzuXb96P+9VWbfJcbnf7v8Kp96l0y4haNE2Lu3bnbd92tO5Wz+xqiwruj+9XFKXJLlOn2nP7zkHhfXrvTb//AF3y7l27nr6C+DPj7ddJbG/YyyPu3K//AI7XzNHN5dxvjTdu/iavQfhdq00eqIm/hWVa87MMNGpHmPWyfMJ068Yyl7p+ln7MvjSGaTff3kiL5TOkcn8TV9m/A7x9Nt865vJDp8f71oZPkWP+981fnh+zRrTxqls6SXHyrsVflVm2/er2Txd+0po/h3R4vDem3++CFlbWbhnba38W2P8A3a+Yoqc8RaJ+k0sVDEYYv/8ABTr9tzxV8R7sfAL4KanpcNvDuXV7yWXbPJu/5Zr/AHdtflJ8VofH7X0ular9om+zytEm3cqsy/e/3q5Hxb+0BrWrftD+KPG2qa1Iv9oeIrh4EV9q+Tu/d/8Ajq17jp/xw+G/irwrbQ6lqStdRy7ds0X3V/i+avuIYL+zoxc48z/mPmPaUsbH93Pl5fsnl3wT+L2vfDfx8sT3MkazSrFdQs/ytG3+zX60/wDBOO5h+KXxV0PSbSw8tbtt0TeVtiXa3yt/s/LX5Y/FibwNrWoQ69oNnGk0cq/vl/iX7u2vv7/gkx8X28IT6brWn3kd3e2CNCsf3mjXdu2q1Ria9Ci41eU3y2OJm6mH5ve+yevf8F0dY0q4/a98I6BpssbNYeDZLISbfveXIu7/AL5avj6xaG4ujC9m1tu+4v8Az0/2q6//AILI/tA/2n+3D8OrVrhkn/4Ry6uL/wAyX5vLmkXbuX/gNcpY2tzMyvGGddit833m/u19fgF9aw0a38x8Xj/9ixLwy+xbm9TQgt5lVAiSfNu2K33W/wBmp7XT/LkdkSNWV/usu7bUsOnpH5cLzLvbdvZfvbv7tW9PsY4/kRNjt821k3f8CavVp4flj7pw+0lUDTbVHjS56v8ANv8Ak2rV+zmygREYIrsu7/0Km2trp9uypvkRvuqu/wCWrFxDbSRnzpmTbLu3K/yqtdkKfNH4SocxNbske5/JymzazM+3/gNMv9kluyWzrnZt2/8APNqfIqXDC2f95/dZU3Kq7ahmtbyON5ijI8abmVv4lrT2Monp0Ix5rGHqDbSdyMrfwSMvy7axb75ZFhkuWxv2/u0+Za3NQjRVZ98gb70TeV95qx9ShSSRpnh+Vf8AlnI+3d/wKtoy5ZHRLDx5byPL/j0kkfhy0WQZzfAhu33G6e1Vfh/BM3gmC5gxw0iM393LmtL9olIF8O2JgXaPtvMe7Ow7G4pnwzsIr34dW/mLjZO5De+81/QWPqRj9HfByf8A0GP8qp+aKlzeINaMf+fS/OJn6hD9mbHU/NvVfvLXkX7U3xMTw3ocfgzTXb7S3z3FxG38P91q9s8RLDp1jcaxefLDHE0su5fmVVr4q+JGuXnxF8VXN/CJJftUrNErfe2/w7q/A+aUj1s0l7P3TzrWNY1LVrppnfJ/9mq14f8AB2q6xcL9mhZ9332X5q9x+Bv7IHiT4lXyNDpTGPfu3N8y19R+Bf2J/B/gPyrzWPJdoU3y7v4f9n/erT2cYx948B4iXwxieH/sy/szQRqnirxP+6t4U81tq/N/u1oftGfGSzs5n0TSr3ZHDF5SrH8v7uu4/aK+OVh4R0f/AIRDwulrbpDuWVofl+7/AOzV8W+OPGV/r2pPcTTMW/vN/FWMpe0Kpx5feIfE3iq/1S6eZ5m+b5VX+HbXO3E0kjM/3fmpsl5tkO8sy/7NNWYNL99sN/epRibR5ZFmGR1hZ/PbP93+GmSN5rhPun726k8zarfePP8AdoZkk3eW/wA/8Ct/do+H4g5ZRDa8i7H4ZX+RqI18uTyU+f8AiRmpzL5ivkf8Cpv8QOz5v8/LVgWfL+YfPuMlTx2IWHZvwf4FaorCT5d6Q4Vf4a0Y5I2kWd03bf8AYpfCL3JEFn50bbHTaPu/71dN4VtUuLhN7qpZ/wCJ6xXt92X2cj7u2rlqk1jcRunIX5v92plEX+E77WoZtLsYblHZj916o/2sjYD3Ks396mTapc33h14ZHbGxf++q52TWt1vE7pg/d/8AHqcpR5bi+GXuno/gvUrZpxvmX5a7CZrOZWm8nftfa7N8vy15R4L1JYbzyEGQzqrfP8tenSXD3FuHRIwG+VP9r/aq4GFT4zmvirHB/wAI1Km/K1866jIkeplP9v5WWvoX4pSfZ/C5hdPmVPm3fxV846tP5epMnff81ZchvTjynefD3VplkW2fbhqrfGjwr5Y/ti2T5azvA955eoROP7/y16h4p0mbXvDaJs37k3U485Upcsrnivw/8RTeHdejm3ttZlWvpeFk1rw/b6lbBVWRPk218sazY3Oiam8DJtaNvlr6A/Z78TLrnhv7HN87W+07f71P7QVI80eYtX1k8P3E+9/DUeh3k1rqiOibf3u5mZvlrpNY0nzt7wurL8zRbm+9XNXUL2uXh27lf+KtH72hjGUOp7jp3xFuvB+taP8AEzwtqUlve2wTy3hfb5U6FSjL+Ve5f8G6firVPA/7ft54s0pGZrH4f38kyqSMx/arNW6fWtL/AIJY/sS/D/8Abr8K+KvBOv8AihbDUbHw/Pe6IGfrNGhZl/SsT/g30W8b9tLxGLFo94+GGoEq653KL2wLAD1wCfwr9F4ahCXDuPin7zjG/wD5MexlHPHJMydtOWNv/Jj9Y/8Ag4jbR/GH/BIjxf8AEjw/Im26vtCFxsXG8Nqdsf5gV/NP8XdDj0/4Naf4uubGUjUPEFzY21yPuK8MVvKwPvtmH51/Q/8A8FgPE76x/wAEQ/ido0pUf2f4h0JI1X+Ff7VtuK/NP4JfsHP+2F/wQX+K/wAQfDGnyXHib4XfFyXXNNihj3PNb/2ZYrcRj/gGG/4BUUISXBFek9/a2/CBeEcFwXKotvaJ/wDpKZ+W94okjEyfLu/8dro/hfrSLfLDdXOVZ9vy1zrSeXbm2m3IyptpuizPZ6qro+1Fbdu3/er87lHkmeTGzR7E9jFYzOkO3bI28FTnOQK8psr7+xNf8yHvKd3zfd5r07Sr5tQ02C5fGTHg4+przXxTZ/Z5y8cP3gWr7ziP/knMtv8Ayy/9tPo84fLlOC9Jf+2n0b8Kdeh1/RI3mf7ybdy/LUXijRZIWm37X3fcVf4f9qvMPgL4yeG+XT5uEZ/u/wC1Xt2uR/2lp6XCHPyfJ/8AtV+f8s+c+Zqe7qc38J9Bn0vxU81t8zSMr/K/3Wr6pt/D/mWNtqu9ZpWiXcy/K3+1Xzj4HuP7N8QR+d5aeYy72k+7X1J4Z02G60u2ew2vu2q/lv8AKtY4rue3lMrRkpGX/YcMkkqfvFHzPu2/xVDN4V2/J5Ubf3mb/lov96uzi0f53mdPl3/Iy/8As1Sw6LNGwdE+Vn+f/Z/4DXBGXvcx63LzHz94jtli+KBto4yB9ugAUnJ52V6PdeG5mmbyodwb5nb7u2uK8Y2ph+O5tGYgjV7Zc9x/q69ubRrk3m9E+ZYtsvyfeav6I8bH/wAY/wAMf9gcP/SKZ8Zwkr43MP8Ar6/zkeb/APCP3Uk0nneZ9791t/hqtN4bdW865h+ZX3bd/wB2vTLzw+8bM88LI67fl2/eqpJoPnRvconzfM27/a/u1/P3Lze8fcU+aJwEel5VtkymprPT5mumjmmX95t+XZ8y11V5o72cfnPbL97c6su75aozWMKyN5e0Bv4m+8teXiKc5Hq4X4DwL9rhPLudBTywuVumBHcFo6ueByguPDxYkKILDJXr/q46r/thKRfaA3zYMNxt3emY6l8FM4OgsPvC3scYP/TOPFf2P4EJx4akv+oTE/8Ap2J8p4j/APIowX/X+P5SPpGxnR7kvvyi/KV/u1u29xAyuiuyqz7U+b/0GuQ+zuzb0TlkVpW/u1pafrVtb2f77cxWXbtZfm3V/A1SP2pH6rGR1kN15bCGZ4yq7Ru3bv8AgTVat7rztsW9lmZ2+bd95a53T9Q3fvkRl+b/AL6rStbhJLsPvz+93I2z/wAdqKceWPulS96V5GpNGjbv3Mcm1/vR/wAVVWjmjX/SXjQRys21vmVlqSO9f5YbaFYkXc+6N/m3U+SZ2XfMijd8u1vmVf8AgVdVH3jGtEobnlZkKKqSLu8zyv738LVS+x7brZbXPybM/wDAv96tqS3eTbs24+7uVaiX7HDIvzxqu/590X+zXqU6kYx0OCph/tGbDI+7eYY3TZ8235W/4DUWoQ2bWapf/Lt+bd/EzVfuoVaNke2jDSL/AMtP4VqlJbxzOkbchf8Anp/DXTTlHmuKMeWBkXNrtRg8LSM239591lrJmhRZnvHmhlMn92L7tdDqFmkeLa5g3p/y1jb7u3+GsuSH955kO5FZdv3Pm3V083MdUacfdMaFUbzH+XY25U20kenhlVIrZtyp87M21lWtBrTbdNCHZljT5GkX5v8AgVTrbutxG/3Uk+8tTKXKX7LuyHSLBGkR7mFdq/Iu7+7XX6ba2fmRW33V+8u6X5WrBs1ha385LaNHWL5GV/l/3a6LRZLO3Zd8Pzyfc+T7tYRjzTIlT5Y2MyyVLff9mm3vv3K3/s1X4VeSMS3MKr5abm3VlRyI03yOuxV2o27b8tb1jGjSx/PvWT5drf3f9qub6ryx946MHiIc5k6hpO642WzqyyLu/c/dqjfafCsEu99rTPtVmXdtrrI7VIW+T5mhXakir92qd5ZpcRzedasyt81vGv8ADR7P3Yo+rweIj9k4C40aFvk+zN/Dvj+61Y2qaW/2hkmRpFVGaJml+61eg6lp821fO+VldW2qlY95otqtv5MNmtsrSt97/wAerKpR6n1OHxXLqeXa5of2i3OzaN3zbWauG1a1ht7o74VXdFtRo/u169rljDGrpCivErbFkkTbXF+ItJ2zbLZMeX/Fs+Vq5pR5Zc3KelLHQlD3jibm3Rl2bNo/jZf4qz7iTfJskRk8z5kVv4q2tUtXS4Fsnlp/fZqy7q3htybZHZmjf5938VdOHjze8j4zPqnLArhU3N533Y/uKz/MtEd7tuEm8yNvL3fe/hao7oRQqyI6of7tVmjmuGe8T5Pk3blX+Gvdw8Yygfk2ZS5p+6dFZXDSLsLhhjjb0rpPBt5HbsY3bbl8lm+7jFcboRyQTIWY5JJat3TLmOGdklQYZOGJxg1/QuXLl+jPj1/1Gx/KifnUaMqniHQj/wBOn/7eelaLrDtGheZcSJ/F/wDE102m6pA0IhSZd8m1d2z/ANBrzTTdQkENuiOxdUrptPvm27Lz73yrEy1/L9Tkl8R+uUcDVh8UTvPtzSS/vo2Pz/J/tVsae0NxiHftVYvk/wB6uJtdYe3aLzpGKtKqbfvbf9pq6O01aFd/kxeay7WT5tu3/arHlt0OyWDlGJ1Uf7uPZNNGA235v4v+A1X1C38uHzvlVW+638VVk1KGaPY+VkkShbxPL8zeu2ZMMzVpHm5tTixOF5Y35SlqE2+OJ/3ZWNWWX+H5axrrydwff8u/b8rVq3lxAtmyOihI32qyr81Yl5I80gffGGVfu7K6/ZwlqePUlKjqVbq+mtZJIURW+ba+3+Gs/wC2PHy6MXX7m5/lp80iWcjJvVmk+b5j/FVKS8e0kV5kWTav+pb7n+9WHKiVUlPUfNM9yURH37fmdd/3apyN5kD3mWDq23cy/danLqE11KERNzfwxr/FWVeXDqH83cPn+eiVP3fdOiNSPNeQyRXS6R3+dv7yvWxpM20bIYdyfw7fvf7VYfnvFcLs3Ju/8d/vNW1prXJlXztpVU2p5bVxVo8ux1YWUZVToLHfCy7H3xSMq7W/8dWtm1vIbOP55PJb5lbbXPWNu9xIttDtkVnX5f7tQePPFFtouht9pvPKS6dki+T+Jaww+Hli60YI68XjaWBwsqjOT+KHjy/1BprDR7zYsKsyKr/Nt/vVrfs6+KvtWl6lDqrwr5O37v3mWuIWG2kVr+8f7yt91PmkrG+H/ib/AIR3T/ENn50m9n82Ja/SsLTjh6MYwPx7GYieKrSnP7R1fxF8fQ2/iK6j0122t/qGk+bb/u1JceOJvE3hlrb7Z5jNb7Ghb7v3a8p1TxtDrUseqo8bo3+qX+Fap2fjS80eG4f7TvRvmZW/h/2a1jGX2jDl5Y2Oe8aeGb/RWHh7WU2rdbp9OZf7u6l+Hd081jP4e1LazNuaD5Pm3Vw/i74l6lrnirztQvJH8tv3W5/lX/ZrW0XXNl9Hre/bL/y1VXqpckpFR5x/iLRbnSZHSR87nZv93/Zrg/EEiNMyeX8396vXPGVvZ61Cmq2D/My7pY68g8bQzW96Uf5P92lKMTSPwmZb/LcL91tz02aRFun+6GZ/u/xVHpt2i3A85MfP8lSzMkmpP5L7hu/uVPNyl+6IzJtLuGz/AA1XuIXjjbZ8zN83zVa+zlpFmR/vfc/2aWaF1+eR97VXKL4TBuo9sm933H+7Uci7fkKYrU1CzSN/n24b7tZ8jOq/7v8AeqYFRIFXHJpfu/OvVad96Ty+opu5P8mgYrSPu+Y4+amt/fBprM+Pubv9qlb5iv8ADVcpXKxxbzBzVizCJGWzh24/4DUKybV+4tCOY5Nj/NS5e5Isi7W8xH+ap7OSRm/h3LUc0iLH8n8X8S1e8P2fnSLI7tlX+Zf71VHYn7Js6NsaT9/MrfxbWre/tKO3tdj8bU3Ky1znnpHJshh+T+OoNa1pJrUQwzbNvy/LR8JJR1jUPtmoed90bv8Avmv00/4NpdDs7z9uLQdYv4W2WdrNOk2/7rfw/LX5ebnaRdnzLX6t/wDBuDpM0P7R0GsI+1YbBtjK+3c27/0GtsLH9/ynDmPu0D+mzStRjudJW4hmDhkyrLX5/f8ABf8A+DFt+0D+wF498GtazTX1nYNqOmxr8376H5lavtLQdcubfSVe5h2Lt/4DXjn7S2oaJ4i8M3+n6rbRyi4sJoNsn3W3Ltr0qmH5YTPGp1nTqxkfzX/8E+/ifeQeAJfDc1zJFLD8qK33V2/er6S0fUrnU2CSPv8AL+Xc33l3V8d6v4d1/wDZU/bK8Y/BaeHZHHrcj2ccy/ehkbcrK3/Aq9v0vxV4wnYN5OFb5tyv92vx7PsCqWMk4R1kft2S5l7TARS6HfeNNak0zfZujJu+42/71eFeNvFFzHcTWaTLEkjbpZP4mrT8aePPEjQyJeP+9jbbFIr7lWvHPEuoa3qDSzI7P5m5vv1xUMPVjH3jpxWKjH3iz4i1u2vFab5WdX+ZlfbuWud1LXraPOyHesny/frL1G4v96IX27vvLvrMVbm6ZiiNu+61erRw/NLmmfNYjGSc/dNtb91m3vN/vK1XbPUk8sfJsVX+SsGxs79l+zO+7a392uhtdHRmWOFGZ9mNu2t5KHKc/wBYlL3Tdh1yG8jFrbaarMvyvJv+9WPq1j9nkLzDduX+GrLWt5Z4tk3Ky/M0jfdpmsSfY7UpczRl2T5m31yzjGlK0Tb2nNExmby1V0Rv721npG1BLrG9Mbfl21XutQ8+3VIXUDft+aoPtUKqyJz8lacs6kfeOaVT7JNJc7dyfNs+8lN3O03nw7mT+7TbVZJIW+9u2/dakZkjfyfMyP7q/dqeVmPNzRNfSrwkFJIW3fxN/erTkvN0Zfeu1tvyrWBGrwx+TDw2ytW1ZLhkf7vyfe2fLXNUow+KJcak/hNDSbFJroIiMa9p+BPwn1LxbfRww2Db9y/w/N/wFq88+Hfgn/hINUiT/np935/4q961D4uab8L/AA0nwx8G7U1K4tf+Jteebua3Vf4V/wBqvncbOpKfJT3Pey3Dyl70j0bxJ8WtB+F+kxeAPD1ztu9ipcXi/eVv4trVW8L+JLHxFY/2VDDJHtgZJY2l3Mq/3v8AvmvljxR8SPM8RS3szsfn+9u+61ei/AXxlbah4sT7ZeMqyIq+dD83y/7VdFDK6dGMZH1uHx8f4VI4b9qT9hfVdHjPxF8APNdabfNvWOT/AFit/Ft/2a+dLXw54pj1RdEha6VpH27Y3+ZWr90P2Xfgn4b+MUjeHtSezubOTTZG+y/Z2aRdv/LT/ZrmfG3/AARv+CGh/Gq0+LV/4kXR7O1ZZ5dH2My3TL8zfN/CtfZ4bGYf6rH2j2Pl8VlmK+uSdHm5T8aP7H8ZeCvEU3h7Xtakja3+ae3uH/eR7q+hv2QP2vvD37MDX+va3rd5eLJF+4021b/WTfw/7tc5/wAFbPCNn4F/4KF+OrPTbSOCzvILG6sFh27fLa3Vd3/jtfPVncTRtsRF+X+JvvV6VTJsHj6UZT6nhQzrHZZiZcnxRPRPjn+0H4/+Mn7RMnx98eXKma+2wRRws221t4/9XHX3V8D/ABC/irwDpmvTeXLMsSxfN/u/K1fnP/Z6a5ot1pL/ADOy7k+T+Kvtz/gnn4ntvGHwrSwm2n7Kvz7vvbvutXqfVY06EYQ+GJ5lPG18RjJVKr5pSPe/scMSOiJvMbbpW/u0lrb3LKu12y3y7f8AZq79jluJInhdUaN9jbflXbSra3cLIlzeKZVbf/s1dGjE9CVSYQ2dzDIX6r8qvurSXTX+zs8+0HZ/q1X71EkM00Kvcuqf7Lfwr/wGr0apCsX2l5JfMbZtVPl+9XoRp/DE2oVoop2dncttcTR4VNqbU+Zf97+9Usls7K8PzPuXduZPu1s6fo9gsgms0kDs7PKv92pptPeaF0h+/u/df7tP2cYzPYw8pc3Mcfq+kp5ZmS23L5XyVyd3YzQrvh8yVI/7y7ttei65psMkbTIiq3yqkO9vlb+L5a5bUrU25ZIpo2XYrNIqfxf3f96so0+WV2exH3oniH7RcKr4Y0+Z7fbI16MN6rsan/CO2U/DyGZ/mG+Q43fd+c1pftU2yDwfpl4YirvqPdcYGx+Km+C1jAPhLaX025kMswkULn/lo1fu2axl/wAS6YNR/wCgx/lVPzrD0/8AjZNeP/TlfnA4D4+edcfD+80m3uY1e8aNItrtuZd3zLWH+zz+xJPqE1p4n8VSR2lntZ1+0N83/Aqd+0h8UNJ8A69o2mvDG5ZpJ3VU+b5fu7q4W+/be1/VpIPDem3nk28aKkUe75a/Bacp04medRlUx0o8x9nN4p8B/DnQ4tE8JQ2sTxrt8yP/ANmrxz43ftAalHY3Gm20kYDfckjf/Wf7TVxVr8QhJoaareaxudl+7JL83/Aa8L+Nnxie+Zo7WbO75dv91amUpyPLp04wOZ+LHji81jUpHe/ZvmrzS61BDM377n+P56j1rXrm+upXeZidtZiXCbQ3/fVKMTp5fcLcl08jNsfAf+JqLeR1A77arq3yrs/iq1aWzyNj/gLVf2SS2siFVc/M23/vqnbXjVPk3GrFvp7wx+T/ABLUcypGxRCyn/a+61OWxXN2EVfJXzn5b/ZqH7VujUfe/vtUnmfu2+6rMtQwrNNJsmmXbR/eI96UDQtWeYj+Fd/8VXrVdsZ87cDu+SqVnJ+7wk/zf7tXlfdH5n8S/wB6iWwvtF612SRhM7q1IY4Y8JMi7/71YWn3SMzyf+Ot/FWzZzCRV8nb83+3US/uhzG9bqk2mujpkqvyKtcLcX00c0qTOpKv93+7XWw3j2W6F0bYy1wniiaa11qWF02hm+Sq9zkJjLl906jwnqyW8iOm75m+da9ls7yZfDsLp8/yfLu/hr588P6o8Myb03Nur2zw3cfaPDcbo/8AtJuqiJ83NzIxPileTf2LMjo2VXd8zV896zI7ag7bP4q91+LV4/8AY8mE3fP91a8EvZt1w/b5qXKjenudJ4Jb/TFT+Hcte7+G3fUNFZB02fdZPvV4F4NZ45w/mfLX0N8OWe40WJPmVdn/AH1RLYmR418bvCb2dwl/DbbUb+Kj9nvxKvh7xZF53KTfumjr1L4weFYdUsXtvs2xVTerV4Jpk9z4b8RrN91o5d21qPhgTGXNHlPrTULOFWZ0Rfm+60dclrlj5ci/ut+5Wb73y10fhvVP+Eh8P2mpQ/OzRL91qralY7mLunys3yUR5TOXNflPX/8Agm5+1Trv7Kn7QFj4tsZ9tpI7JdQl/k8uRDFJu/4CzV7Z/wAG2nga++If7eHibw3pMqpfP8ItZfT2ckKJxcWQTJHbJx+NfDNlLJaXPl3MG3MZ+aOvv7/g1t8VaX4V/wCCnUj6rcrEt98OdUtYizAZc3FmwHPshr77hicoZBmU4/yx/wDbj6TJqUamT4+E9nFf+3HqP7af7YNz8WP+CZfxo+Eviu1isvEOk+INK0/V7Jc/LPbazb5xn2Br6E/4NObTR/Ev7EHxU8C6/ZJcWmp/EKaOeGQZWSNtNtEdT+BH518g/wDBd74M+Jv2X/2h/jBpkmizR+HPihc2WsaRdQxbYPPF1FJInpn5WzjvivqP/g10uJfD/wCwr8QfHVlIFl0n4rSNMSuQYm02yBB9siu2olPgmrKP2qif/pJ5uXSnDgqspbRrW+Xu3/U/I3/gtZ/wTn1z9gP9t7xN8NbbTmTw5rMjar4PuFX5JLWRt3l7v70bfLXxr9nudPk2TJub7v3fu1/Vn/wX0/YQ8Kf8FEf2G7/4s/D23iufGXw/spNU0hoF/eTQqu6aD/vnc1fy36ta+Szw38PDNt3fxK1fBV4qpFVV1+L1PCwdd0p+ylt9nzR1PgWcz6Ark5xIwz+VYfizRpo727tZk+ZH3RZ+9W14BgjttB8mIfKsxx+Qrd+K/h86fcwa5pwUpNGFlT+GvreJHfhzLP8ADL/20+0zrl/snBekv/bTyXwzqk3hvxBEjt8jN/er6h+HesWus6Ls+2ZZovur92vmnxloKWcgv4U2jZuT+7XpH7PfjRGYWFy8Y/hRmr4SUZRlzHzXLGoeoapYoqu+9lH97+Kvd/2Z/GX/AAkGl/2PeXLfa7X5UVfvNXi2qW6So/8AEn8TR1ofCLxd/wAIX4yt7+a9aG2jl/e/9c6jEU/aUtTXB1pUKsbH2Ja6bNbrv2qqb/73/jzVchsd3lJe3MLLJ/FH8rbav+G1s9U0uG8tH8xLpFdW/wB6r81i/wBqfzoY/lVtjN/DXjR+1E+0hyxhGR8rfElZD+0tIqHLHW7PGB3xFX0jb6XM0n762V2k+Z9vy+X/AHa+dfiGhX9qZUlUk/29YbgMZPEOa+rI9P8AL837M+1l3bmZNy/71f0b41K3D/DH/YHD/wBIpnxHCMVLHZi1/wA/n+cjn5NJ8xlTyVDbF37n+Zao3mg3CMzom11fc7Rp92uruNPRjvjRR5nzbm+6y/7NVbizRZlmdGJjb5Nr1+A8vWJ957Pm32OG17R4bdtlsPvfNtrkdWs7aa4fznVSv92vRvEUflq6W33V+f8A3d1cHri/wXKR79+6VV+81cOIidWFpuMtNj51/bMAW/8AD4AxiC5HHTGY8UvgxXaTQFbgm2sMf9+48U39spojeeH0ty+xYrnaJDkjmOl8FDzH0BQu7NvYjHr+7jr+v/ApNcOT/wCwTE/+nIny/iSmsowf/X+P5SPeVvXZWRHU7W2ptf7zU63vHVZZnm+825PLb5l2/wB6sqW8VW3+Vzv2uv8Atf3qmjuLONfLmmVPmZvl+9X8H1o8sT9MpyOh02+hiZH87ezfNu+6tbFhqSNMyQzbiv3F+7trjdJuIfOl3uu2P5f9qtWO8SO3i2fON7eUv8S1zxpxNuY6WG8uVtlNtDsbczPIzbVara3SLarD5LNJ93bv/hrklvH27EmWMbvnWT+H/dqxDcJIpnmRkVf4d25WWuinL2Ype98J1X9pfZ1kjd2+Vtyxx/8ALOoZLqG4uHTztw2boo/K+8275vmrHW6hWFRDZr+8+b733qmj1N/O+zTR7XV9qfL95a7IVOpzxfvcpfRYV3pN5jD7ybfvUt5Ik0iF5mG3b81VFvPMbenIX7kn+zT4ZIWQbH+bf/c+6tdVPmNI04S3Gy2+2+bzIPmX/lp/DVGa1v7iZ8cFv9v73+1Wkvk3CnzpJNu75Gkeo/Jd5R9pfJ+b5matvaRZ006fMZLW+1ovvC3VmV2+981RW6+ZHE9yknmx/fb71as1vDbKEhTYq/MiqvyrVCadI/vzqjNL87f3v9msZYj7Jt7HllzSHwxwqqvJH5atVzT9SRpkxMrBX+Vfu7qzJryFsb51RI/vbW2rUNvq1grNvfL/AH13fd21FOp73MZYinzRLGkx+Y3kyOpbzdyN/D/wKuq0/wA4r9p2KfL+V121yOg3Vq18P3KtCv3GX5f92ul02SaG2Kb8osXyf3t26vZjhT5LB47lepuTRXKxukNmpO5f++aiuF8td8W1hv2+W38NRx3CQxr++w/95Xb71G55GWH7Sp+Tc22s5U4cuh9lgcdGMShrFq81oyeSzO3zfu3+7WRqWlw3Ebf6xWjT5FX5tzf3mat+3h27jPDJukb55G+7SPo6eYzwzcf+O1y1KcYnvUcwkefaho8zLsv0jKfwtXN61ocLRvvjXZv+63y16DfaPMtwr3KKUV2+VU+VqzdW0tPs+x4crv8Am3fdauGpGH2jseM6ni2taDcwzhERdv8AtJ/DWDqWju0nmWySMn+5Xq/iDR4WZvvbV/1TfxNXMahoryI/kpiPbuT+8tc1OpD4TzMxxHtoHnUmm7neaZGBX+9VT7H50y+dwm7+Gu11Lw3C0YkT7rffVnrKutHmjG+GFTt+7XdTxUVHlPjJYWcqpkWcCRXYVAAVB3gfSrrTmFidu5Tjcvpz1pfsojkaUhQc9qZNHubdsJGMHPSv6Myyrf6L+Pl/1Gx/KifG0sDy+LOGpPrQb/GZraTdXM2IbaSRj9793/D/AL1dPoez7QiwrIyMm5v96uS0+F40E0zqnzKu1X+b5a6nR7xIrgyfN8ybfv1/MsqnNA/oDC5XHk96J0Vm0lvumd2D/wCz81dHpmpPuEzuzrs2urL92uMW6EcY3/upW++391a2NGupo41s5pt4h++3+9US2JxGXwjA7G3voWs0uYXYtI7fu2+9Usl8/mHzrZWf5WgjX+7/APFVkafqDs0KvcyYki2SyRv/AKtavR3E0MiXLp8m9t395v7tXRlOMvePmMZhfZiXUjsA7vuLfNt/2azrmKFf9JSZoX37vl+bdV64YLJ++f5Vi+VmrOYw3EaXI8zEatXo4eUIx5j4zHR94z9URJleFJtzq251/vbqyd1zbw+SiRl5H2/NWvcWv2i4E0zqw+6219rVSW1m8h/OfbKv3VZd1M8qMby5UUV/dzFLd9r72G6P5t1UrqF/M2I8exW/eqq7m/3a0Lf7S7ed837v5l8v+KobyFLqR0RGQ/e8xf7391qyqS5Trp+8Z8MaQMEuYWkRX+Vd3yrurWt2Rl2dt/8Au1QaF5Ng3sHV/lmar1n/AKrfM6qyrudtv3q4p+/PljodlGfJA29Os73zXmTd8q/Pt+6vzfK1eX/EbWr/AMRa4bm8mZ1sXZYIfvJ/vV6pq2vWHhn4e3N/cvGt7cLsiVfvRr/erw+41bc0zvtdm/1v96vqspy1YWPPP4j4fPc2nja/sofBEluNah4+zPyq/P8AwtXA+INYmtZNX8m//eSWrN8yba2LjWIftT+d8u37rSLt3Vx3ifUHkuJHKb9ysm3b/DXtcyPBjLmOd8L+J5L7TXs3fb5b7lqt4k16a3s3hhfbuTa9cloepfZdbuLZ3VV3/Nt/hqzrOqPNudHbb92p+I15ftHPalIVvDMX3D+7Who/iJ7XY+/7336x9WuJmY+n/j1Vobh4ZNn3R/eqveGelL42mmtURJ/4Nu1a4jxVqz3F0zvNv2vWd9vdWG+Zvv8A8NVrq43sZmff89T9kqK6k9nJHNME6CrfzxTs+/bub7v96s/T7xFY/uV+9/FVyG4Sa4lbeu/7qL/CtVEJF1YfOBT5mX725fl+anXDecSjo277tLZzbvkRsfw1Pt+0L5OG+b7tEiTKvoQFHyMdv3aoXkeyQvs2lv8AvmtSSR4WdN//AAGqN1G27e3Rv4aOX3BxKLRiMb1/u/8Aj1RMqDa/92pZl2TYd2+Wmv8AdNTAsY2Fb/epsapIvzCnbU8v5n420KyAfvF+7Vf4TQlt40XdJT5I0ZVfNRLPtkx/FUiyIzNs+Vf4KfwmZDI3zBPmFa+n3H2S1fZJ87L96spjyHfn5qkkkKr8ny7aXwgXPLmVfOZ9p/j3VVuI/wB59/d/u0TXTSSK7vlaiWQbgifdo5vfFEdaxmR1d3/3q/Xr/g3X0ML8RJ7+Zf8AV2saq2/73zV+QtirSXSo68bq/Zb/AIN0bGGTxPqaPGqCS3hXdI33W/hVa6sF/FPMzbm9hofu/DfXjeGerOfKX5d+5t1eD/tBQ6lcafcwiGQBk27Wb/x2vWtN1rbo8M32lX+Xb8v8VedfFDWLaaN0vNyIyMu1U+Zq9atKMo2Pn1zyPwo/4LofBG88H+PPCv7TOiQ7mWX+zdZaNNvl/wDPORm/8drxn4f/ABU1LXNChs7W/XzNu5/L+Wv07/4KRfC3w38fPgf4r+G6QrNNcWEjWG5fmjmjXdH/AOPLX4w/A/xBNoNxL4Y1qFobyzuGgn8z7ysvystfB59hY1o80fsn6Dw3j5RXspSPUfG2vTWd49nMiuzIr/7P/wC1XEa14iT7Psh+Vv8A0Gul8WX81xau6Rq4b+L+Ja4DVJN0m99yjd/FXzUY+7yyPpcRW5tSCS6R/wB8v/Amaq1ndTeYXd22VFNGzbkhT5t/zbnpJLh44wmz7qfPtraMbnj1Jcx0Gl6tZ+Z/qVYb/naun0/VofMV4U42bd1eaec6szo/y/e+9W1oN9PcL5P2liP7qtVSpylHl6GcZROl8TeNLCOFIUh3N9zcvzMzVymrXz3S7HRd8f32rbuNLhh/13ljd9zb96srVNKtl48jcJPlTbWUYxNKlSXwmOsjxt9mx8y/NU0OWVRlfNb+9UzWJVU+T5v9z71Ma3mK75tv32V1Wr9yRiTfI2ezL8tPhidj5aRZ+f8Ai+7UMcbpMzp93Z/D/DVlpLaRlV3YbfmRlb71Z/4So+6W7OH942f4vlro9J0N7i6hs44fN3fN8v8AFWHZq9x/o2xU3IrV2fhdkhsR5Nttff8Ae3fdrgxk5xpXidOH5JT946qTVLPwD4dZLO5X7WyKq7V+aNq4PWvEk1jE9zfzMbmZ2eWZvvs3/wATWl4ibUtQk85LZdsa/e/vNXlfxF8XJoepSWepTb7xUXbbx/dj/wB6ufK8uqVn/M2elWxUox5YfCXJdeubiZ7m+vGG5/4a7/4feIvEnhloNV0qzmZvvLuTarLXz0+u6rqt4HlkOS37pVr1TwJrvxN0vTjqT30klnHBteS6X93Gv+9X0WLy6pGlyxMKeKxFKXNBn2H8Dv8Agr54z/Y+8RWWqL8LYtQaNF/0iC/8ttv8S7f4lr7B8D/8F/8A9i/9oeB7L4z+F7rwfcLAsW6ZSY5tzfNuYV+JXijxtNrmoNMZlm3J95fu/wDAayvtk1w3z7drf3aVHhuFbD8s24yPTp8ZVcL/ABIKbPov/gq78dPhR+0N+3V4h+IXwK1hr3wxDpdnYWF00W1WaOP5tv8AeWvnkbw3Mm5aijV9yv5i/wDAalt4UaR03tt+9X1uGoqhQhT/AJT4jFYiWMxU6zjbmZ1PgfUHtbpUG35k/i/hr7B/4J16G+nr4j0p7Zo0jbdb/P8AKvmfdZa+LtFuobe+id0yny/Ktfoj+w/4bSx8C3PiFEjCX0Uabtn3tv8ADurr5vd5Tko/x4nslnZ/Z1DzbnRf4tu5t1T29vZxyb/OXZ91F2fN/vVcurWGxtFms3k2qnzstPks/tE3nI7ZVN23+HdTpx909fmH6bpKea6G5VUb5olX71aNrCklw21G2xp/Enzbaj0r/VqiPyybX2vWxp2nvFNvdF3fdiVv4q66cbaG1GUh+j2cMdqrojOknzeYv8X+1Vz7DNcKzzOu5l2+XGm3b/wKrtiqSRq7Js/6Z7KlRUVVm+ZN33KOXl9493DymczrGi7VDwo2Pl/fN92OuQ1DTYWWdN+I2dn3bPvNXoeqL5lv/rGU7vmjX7v+y1cd4gtcZh+Xd9/c38TVlKXU97CrmlGJ4F+15bxxeB9MaKIoP7TTaD3HlSVd+BGmvN8ELC4Nw0Yaa4AJbC/61qq/tf8A2j/hA9MMzZB1YED0/dSVp/Ay1eT9n2wmG0hJLlwG/wCuz1+4ZlL/AI5zwj/6jH+VU+Io0LeKOIh/04X5wPgf9s7x9NrXx01jSob1mt9Hijs4l2fxfeavM/hrp9zrnii2s0G4zSqqs33atftAa2+qfHzxdOH3LNrMnzf7vy07wDJDotnc69cvj7PF+6X+9JX4J8J5GN5pYqf+I674xePPsN5No+lXm6C3Tyv3b/LuWvH9c1ybUJDM7szU7xFrj6hfPcvNnzPmrIZvMYvvzS+L4jDlG+Y/ll361JCvmIvdv7tJHC8iZ+9/srWrpWjvcMNkLZq/iHIhsdO3Irl2bdW1p+ks0m9E3Ltrc0Xwe6w+c8G5f9qtVtNTTVbzEXP92teXljymPxS5jnLize1UuEbc1Zs67pN4H3a19aukZWeFsMqfdrAmlmkkZ967aylIqMeYhuJpGYbEZv8Aaals1dWZHT/aZqRpP3a7wxanQ27sdjvvXZuo+Ef2DT09ftLKm9VVf7yVsNp8zWu+H5i336xdPuNs+zy/k/jauks5LYQ7N+0NVcxMtjM+xzQsPMTa6t/31WnpLOtyPu/K/wA60t0kPHk8/Ptf5/u02OSHcvk/Kazj7wcsep6Lpeh6Pq2npsm2lU2/LXj/AMYNPfR/Ewtndl+X/erudHuHjtmSzdlZdyv8+5WrhfjJNcTX1tNO6lvK2s1IcY++Zfhi58y62TP/AB7q948EzbvD4j8xWC7flr500G7eG6D/ACmvdfhtd/avDsz/ADDyU3Oy/eq/hCXPsY/xa1B20t5uqNu/4C1eJyb5Ji7bfmr0z4yaltthbefw275f71eYpwwpl048sbnReD1DXEab9m77zV9DfDOR5NHWGFM/J822vn/wfG8k0bp93f8AxV9DfDe3hj099o+Tyvl/2qOb7JjL4x/jC8hkjPySAxrs2t/FXh3xC8MvcNLqVtbNlWr2PxNHc6hMz3KSD59u5qyW8KvfL9mezZ/4lk2U48hl73PzFj9nHXJNQ8Oy6U94vmW+1ljb+7XdalYbo3uUfJ/iVU+7Xk/gWN/APxOht5nYQ3j7fMb7qtXs7XLhdm/+Pb838S1Pw+6aS5Ze8cRqUE0M8iO+9GT5P9mux/Yw+PPiH9mz4+aX8WPDU7pNYqVlWM8vEzLuX8cVzviCySCeWSPbIkjMzf8ATP8A2a57wsxTVQQQPkOc+nFfdcNW/wBW8zX92P8A7cfRZLzf2NjfSP8A7cfu3/wWP+Kfwj/bg/4Ihv8AtK6XsutY8NalpDWl2SpdDNew28obb0yHPH+zXln/AAbi/GzTvhx+w78XPDtzZXV99s8WSm4srSLeyLJYW6JLj6owr83fDn7X3jPwl+yZ8RP2O9Tumm0PxM+n3mnJJJk280F9BOyj22oa/Sn/AINv/gs3in9i7x58WtF1WW1vNI+Jb2mqJFH5hudPaws2dNvdhlip7EmurKVGpwNUhVentUl90bHHW9rT4LrzprX2ib9Pdu/uPuv/AIJ9fGew8U+ILz4b+ILom213TjD9ldtys21l/i/2a/mY/ai+HeiaL+0Z8T/BmjorW2g+P9UtbVo/u+Wtw21Vr9+PHsOqfsbfHCy+LV9brYaDNFeXvh1pn/eJarC23d/tV/PTr3jK88SfGTxP4h1K5aRvEGuXl5KzJt+aSZm/9mr43Gxlh6j/AJZHyWX1IVqceb4o3MTwlZyWOmvbSZ+WdtuVxxgV6V4h0i313wLMywsXMamJl+auIFubaSSM55cn5jk16J4OuHvNHi013XYybdrfw19XxH/yT2Wf4Zf+2n3Geu2S4L0f/tp4rNbQ6tp01hcoyvHuXc1cx4M1SXwn4qMMz42y/LuruPGGnvoPjCf5F8u4fair/d/u1wvxA0r7BqC6vbJ8m/52/u18LL3vdPnKMpc3MfTvh29TxB4ejvHfCtt+Vf8A0KqmoQvHcSTQ/wAK/wAP92uH+AvjB9Q0tbB5t/8Ass235a77WIntV2Im9tv3leo5vdsFSPLLmPrL9jf4pP4y8Et4evLndPpr7PL+8zR7flr2Hy3Yunl/M33fOr4g/Zf8eP8AD34pWd5eTeXZXX7q6bf93d93dX3VKUuJvMSaOW3kRf3ka/LJ/drhrR5ZWPqspre0ocsj5R+JC/8AGVgUf9B+w/lDX1vbJeMpMKfMvy/7y18nfExI1/a4CBNq/wDCRaf8uegxDX2Fa6aka74UZX37U21/QXjUr8P8Mf8AYHD/ANIpnzXB82sfmC/6ev8AORnXdrDJhJLXarfxM+1V21QvLV1kkSa23ity+t3l2o6K4VvkXb92q11Z/u33zttb5vMr8FjT6o+7jVlzcsThvES2ccn2nDZkX7y15z4iuobW4MNsjF2+ZGkr0nxNAisjwpIEhRtkci/Lu/3q8z1qxmhJ/wBW6b22/N827/erixEYcp6mF94+cf2vYhDqeiIJA/7u4+cfWPip/BbtEmhyJ1W3syPrsSq37XCRx6royRs2fKn3Kxzg5j796f4SyLDSMHP+i2vX/cSv668C7Ph6dv8AoExP/pyJ8d4k/wDIowb/AOn8fykextcOyn7TMzs3zbqjhvCszCF/nZP4k3bqyZL25+VE27W+V23fLUEmpCabzvm2xsyqy/KrV/C8480ZH6H8MjbjkSPUM71+bc3y1cj1iHzNiSSMy/Mn8P8AutXIXGuPCv7l8MrbU+b71DeJoGh2PKqTbP4fm21nGnzEe0OzbWNqiaab9627ev3vm/iqzY+IkZ2/cspji/dTM+1dtefzeIBcRom/960Xz+X8u6mf8JFNDt+dn3fKnz7qJU5S0COK5NT0218STblT5UWPdvb+9/u1Ja6tNIzu9yu1vk3L8zbq81t/FkLKttM//wBjWp/wk7283yJGw3bf3b/eat/Zy6hTxEJTPSdP1aFrgQo7Okabf7u1f71XNP1hJLeTyXYqzfd315nb+LHhlcwbiu3d9/8A8datDS/Ez+Z56TbdvzMrfe21nzTpndQrQlO56R9seaNU3/8ALL5lb+GrEkltfWfmQux3fd2/3a4mx8T232iF3vNqMvzbW3M1X7fxYlvIux9ieV95vlbbSp4jleh6NOPvG5efNIj7Ny/d+9WTqU1tJNHYtMrt8235du3/AGt1Yt94geQM9lMq7n+Ztm6sW+8aeavyTN+7fa6/drKpU97midsY81K5ratrXmQtbIG+VPn3Rfe/4FWVFrnnCLyZmZNm1Fb+GsHVPFU1zuRHVnVP9Xv27dzVlTeJtsRQ3OxF+ZG/2q6cPWPLxVPlPTPDuqW22K2R1L/e/wB6uw0fVvuwvMqBl+Zl+b5q8l8M69CzfPN93+H+7Xa6bqm6FkR1+Zt1fZyp+7zH5JTxU4yOtt9Um89kmmkX5/3vmL8u3+9WkkyXEkQT7v3tsfy7q5a0vN3mbPMZfuo01a1rdeZGrzO2I23Lt+6tYyoxlse5g8wqxN+NvtF09z53mhotrLv+7U3lpIzojrt+9uVP/HaraPOkbvM9srL91933WWprOOaS4W/h2ui/dX7q7f4q86pTtc+nw+ZS5UyhfWsMtx87/wAPyt92sXULWzkhKXLsQ38TVu6h++XfsXbv2o33dtZdwqRzLM/zP8y7d1eJiI8sj2KeM/dXON1rT9jLvdn/ALi7Kx5tHW4VZtmwbNrsv3WrrL6NGkWzTcP3u5t1QfYbZNyI+7czfMv8VefUlyhTre2OD1TQXkZpn/dL96Vm+Zd1Yt9ou2Bn2Yb7u1a77U7eaON4XTcqp8qsv3m3ferF1bS5vMLzIoWFP9Wqfd3Ue0906MPTjKdzgPEel/YoWfZtHy/LVHTbI3cJwX/1gGFTNdT47tGTRnmkjCEFQEPVeRWR4Tt0msZGcHiX5SPXAr+lcpcv+JV8w/7Do/8ApNA+OUIx8asIv+oZ/nUIrWye3vEtvs2/523sz/dWt/TdPmaPf5OWV9qqzbfmpLew23Gz7Mq7m/76rX0bT/M+SF8fP86yP92v5p5uU/oajGMYDdPsZpWTznVyq7fm+7WjptvNGxw7EN8qbvu1Yh00xwRww223+Ld/8VVpbHzs2DzNjftby/vf8BqY1OU48ZT9zmZJpbPJCpVFQMm3bJ96tFVeOzVHdVXerPub+Hd96q+n6XtZv9Yw+66stXoYUkOxEjb7u3d93b/vV1e0Z8NmEuUbdWKbbiaafO35tqrVHzHVUeGHf5nyblXb/wACati6bzGbZHJKrJtb/Zb+7WZfLM3zzOzKu1fLZtrbq7aM48tuU+JzD4uaJl3W+a8e2Ta5V/3W19rVn/uZJHm+YPH8yMrfNI1askKMyTJtYs+3bs+7/wACqmtv5l0yJCyMz7VZv7taSlzQ908fl+0MZXt5vtk07R+XtX5V/wBZ/vVFeR211GN/mRbfvK33WatGa0RoV8vbv37d2xmpFsZvL2fK7r837tdvlrXDUk5ao66NMx2tUWZEhdh/s/wr/wABqzotg91qCW00zSxebul3fxLVqW3hbe7+Ynz/AHm+81P8A2r+MtW1+wsJlf8AsmyZ59rfdb+6v+1XfluH9tideh5ecYj6rhuWP2jzn4neOHvNUn0qz2iO3dlVdn3m/wBmuB0u8HmTWzzL5jP91qf4oukt/E1/bfMS275W+Vlrko9Stoda+zXO5Rs3bq+zjH2cbnwPNOU+ZlTxdqj2sz73x8+3c38P+7WNqGqf2lp+/f8ANt27leqXjzVo7zUGkRGbdu+auat9Qmtd3dPu/e+7URl9k6PiOX8Tyf2f4ikkh3bW+8v+1TZNSmmhPb/Z2Uzxg26+V0j5b5m/2aqWtxtj3u+6tY7Fcw24kzM/8JV9rVWuJoWOx0+7S3EjszOH/wBn5qqyvuUUvtDiPkmcR70+7/eqOVnX5/4qSFvmPHy/3acVG3e/X+9RIv4RbOTdMtXdLR5ZpI0/vbqz7OTbPz/eq/o83l3hmXd9/wCbbS/uikakMe2Qr02/NVmOR85Sbbub5f71QzRjA2c/7VLHdeXGYE/h+/SlyxM/iEvIUkbem75f4v4mqlPJ5pX+Jv7uyrXnTN8+z5FT7zfxVBIqHd5P3moAz7iNPmfC5aqbRuP491aPk7mbf0X+Kqs0b7d6JRH3TQrodo+7/wABoLbWb5P+A0/+Jo9/+7UUn3t2c04yAcBERvNO8xx8icD+7UcZIOcZFObCnGaQDt0n33H/AAKhpPMO/f8A71RMH6sKVW+UjtQBMsm1fn5Vv4qbuTy9mzaVelaQSR+W6f8AAqYv9zq1VE0LFhzdI78Bm/hr9jP+DfPUnsfFFzYJcsiTJGz7vmr4e/4Ja/8ABOFf+Cj37S3g79nPSfiHF4Xu/ES3U9xrN5bNOltBbxyTSlIUAMsnlxttRnRWPBdc5r2Twf4z+NX/AAS2/a+8Wfs++GvGnhSTUPD3iqXw9q3iC/s7mawQxT+W9ztXbLsXliApbAIAbjP1OB4ZzKviIU6co8zhGpy3d+SWz2t5Wvc6a/DWOx1NRp8t3FStfo9uh/RFZ6gi6PF/yyRfm+V/vV5X8ZJLzUI3e2lZU+VWZX+avI/+Cs/7Qvj3/gnt+yF8PPjb8D/2qvAfi/V/EcsNvJp2p6QssfiGF4SzahpgtrjdHboQMh2mXEyfvQ2Fk/MzVP8AgvT+23q4cXWh+AxvOW2aFcDn1/4+a7spyDHZ5glisLZxu1reOqdno1/XrdHlUODc4xdHnpctvNtbeqPvT4haTeXF5cvc2zIjSttZflr8dP8AgoV8IU+CH7T8niTw9ZvHpXij/SA38K3X/LT/AL6r3HVf+CyX7Wmsb/tWj+DV8xdrlNHnGR+NxXiP7R/7Snjr9qPTodP+JekaOhtpA9tcaZaPFJE3TILOw6Z7d6WJ8PM+qxtFQ/8AAv8AgHs5fwjnuErKb5f/AAL/AIBxsOuTatarN5ylmX7q1j6lIk0jd130thp8WnQiC3kfaBj5jzX1D/wTL/4JVftA/wDBUb4hax4L+EuraZoWh+G7aG58S+KtdWQ21p5r7Y4UESM0s7hZXVPlUrC+514z8fmfhpn2XUZYutKnCnHVtz0X4dz6XEZZiqdHnqNJLfU+TrqHay/Jx97bVWZU8wfPt/2a/Y7xR/waweDfH2i3+kfsmf8ABSzwL458ZaQv/E08P3VpFDHEQdrB3tLq6kgO4FRviPIwSOTX5O/EL4R+JPhZ481j4afEfw9eaVr/AIf1SfT9Z0y84ltbqFzHJGwHGVZSOMj0NcGTcF5nnjmsHUpycbXTcotX2dpRTs++x5tDK62Mk/ZSTtvun9zSOOktwyO/zfc/76qbR75LOZN/3d1aZ0GyLmTdJkjBw9fZP/BLr/ght8Zf+CmWha78TbH4gaX4E+Hvh2/W01fxbr0ckpmlEZllS2iUKshiQxtIXkjVRKmCxyB6WYeHmd5VhHicZUpwgt25d9kkldt9krlV8kxuGpupUcUl5/8AAPl6x+zXjLeIm/av8L1nakX+3N+8VU/gXf8Adr9R/i9/wbJXMfwe1r4l/sGft2eEPjG3hyxmn1XQbeKKOaUxxtJ5MEtpcXKGdwuFjk8sEkfOK/Pz9kP9kf41/txfH/Rf2cfgRocF54g1l3PmX8/k2tjbxjdLc3EmCUijXJOAzHhVVmZVPl4PgzMMzw9TEYarT5Kfx3k4uOl/eUoppWT6BRy+tXpucJRtHfW1vW6PLmVFY7H4WqF181xs/vP/AN9V+ytr/wAGun7PmkX9l8KfiV/wVZ8I6T8SbuCFJfCUGkWhkF3KoKRRRS38dxKpLLtPlozgghRnFfnd/wAFEP8Agmz8ff8Agm58a4fg58fIbCc3+ni98P8AiDQbppLLVLXcVLxl1V1dHBR43VWUgEbkZHbmyrhLG5xi/YYWrTc7XSblG67x5ormXpfuRh8DUxUuSnJX+av6XWvyPn2SSGXCIir/ABUyOGCS439Pk+f5f/HaikNvZzGGKHeQ21stViwt7m8mWNIW3N92vn6uGeGrzoz3i2n6p2ZyTi4zcXujX8K2M19qiWybW/2Wf5q9Hg0dtNsW2Ju+ba23+Ks7wB4PvLOFdVv7ZovtCMq/J91f4trV0nibXrPRdFfVbny38uLbFG3y/NXh4qt+95YRud+Fw/NrI1P2fPAL/EH4iJpt5tms9PtbjUb+Hbu229vC0jN/47Xxh4g1G48aeLdQ8TPy97fyS7VT7q7vlX/vmv0w/wCCTXwr8T/EjxB4/wBb8E+HpNV1pvCF1a2Fqqs37yb5dq1of8Fuv2A/hx+zf8OvgX4z8P8Aw30/wv4q1a3vLLxTZ6a6qtwsMassjR/3tzMu6vVynHUMPWlRl8TPax+VVZ08P7P7R8R/sj/s8aj8XviBZ2D/AHWl+RWTcu6tj9uT4n+GdW+Ij/Bz4UWVvaaB4VRbW/uLOXcuqXyr+9k/3Vb7q17b4S8P2n7OH7Enir9oDVEWDVZol0rw00bMkjXVx8u6P/dXc1fDtmXkgyzMXZ90srdWb+Jv96vfy7mxNSVaey+EOLsPh8lwlHBw/iyjzS/RAI3jk2fLtWrUMKL9x9v8Xy0kaovyffLf7NSNG+7ZGm3+/u+7XtH5xLYVpOP4v96pLc7j5e3738W/7tQ7oSuzyflVvvLVywtzNDlEWnKQo88SRJPss0fku2771fQH7NX7VXjD4E+NPDH2nXtvg/VJ2t/EdvMu5bXd96Zf7u2vn5o0WZWzuLfLWv4it7m++HkqWdr50tvcKySR/eVW+9T5eaJpzSv7p+v/AIZ1nwr4ys01P4e63b6xYXn+qutPuFkWRdu7d96rjOlvMl46Mo+7t/8AZq/Fzw7411/4a6na674Y8SalZ6la/wDHq2n3zR+T838Kq22vtH4Ef8FTNEs/hTNpvxv0r7V4m0tP9AmtU2/2hG3/AD0/uyLV060afxHXCUJH2/p8KTTfJIpMjbXb7rKu371b+k5b7+5Qz/ulVPmavEP2Xf2lfAH7SWhy6x4buZLDUbf5rrR7yVVnX/aX+8te2WOoI0yTXPmI6/Ike2tY1vafCejRjKUDds4vNaW5htt/y/O277tOkieObYiL+8f5/M+VY6hsZJoY3/iWT5tzP8qr/EtTFopv3yPlVT5l27t1axkerh+bl0KWpWsJkKPuCfd3L83zVyniSzSHfvmVvn+T+9Xa6hCgs3+X5GTdt/irifE1y821Nnmqv3I2+X/gVctapLofU5a+aR8+ftkeWvgHTgqKGbWgxZVxn91JWr8C7MS/s36bOBIGE12DLG+Nq+a9Zn7ZCCP4d6YGg2OdZXO07l/1Mn8Xeuv/AGbdOe+/Zd0xY0AIvLhg59RO9fumae99HLB/9hj/ACqnxmHlH/iKuJ/7B1+cD8j/AI0Q3Fp8ePEtoB839sTKS3+9UHirVodP0W30RBtaP52/3q6z9pjw7Jpf7UfiqC8PA1FrgMv8S15l4g1D7ffyT7N/z1+DR+A8LF/71Nf3inL+9lO+iGNGb2pY7V5GxXTeG/Cd5qEyeTbb/wC8uyqjHmOWU4xIPD+g/aGX5flr0nwn4JRYVuZoVC/w/wC1Wn4H+Hr2savdIr7vm+Zfu1Z8UeKLbw/F9jR18yNdqsy/drb4fdMeaVSXKiLVprCxt/J8lV/hdq5TXdcj2l3uWO7ms3WvFlzfM3nfxP8AeV/vVjXl49xGOxrPmmXy+5oQ6lePJcvM53bv7tVGmIXZTppvm2eXz0qPy3ib95Ux934iveFEkZk+5xtpbNvm8j73yfPTWj3b9n+7VixjHmK+/bt/8eqhRl9ks26zM5T7q1tadI7Qqj7cR/3f4qorbzXEf7lNm3+L+9V2FXhjGxKCZe8WWt5pmZ0RlLfe21DIs0JPkp82/b8tamm/MuX+bb/e/iqxHo6TSLCkjAs+6l/dJ/wlPSdSns22IWxXO/FWXz7aGb/prXZ3Hhm5tY2eHcR/47XE/En5bZEmVi6t/wB81HL7xpCWpxtmSlyAf71ez/C3VHXR7iz87/WRbvlrxWP7w5zXqPwzvoYdKldH/wCWXyrV83LEqsc58Vr0TaosL7fl+/XKWse+4WtLxhfPeaxJv+Yq+3dVXSLd7ifYlMfwxOy+H+nvNcfOmNu1v92vVLfxZpvhuNYXudu377R/NXnmhwzaRpiuIVYqn3lrO1bULm6lZ9/8X3t1RL+6ZfEeo3nxQ02YN8m59m7buqBvihc3H/Hgiwp/d2V5jDHeTTD52+Vfuqta1qHsVZJH5VN1Eeb4iuX3eUl+IHiK5kvLS/uXb9zLvVY/4a9v8JeIn17wpa6lsWVvKVWZVrwrUoX1axkTZtCruf5a6T4C+OvsdnP4Yv5stC/7j/ZWnEnl9w9H1u5xIRMiscZ+VPlrmfDYB1A7lyBESefcVoa/qySXah58nZ937u6s3w/eWtjf+fdsAnlkcgnnj0r7/hWhVxGQZlSppuTjFJLVv4tj6TIqdWplWNhBXbUbJav7Rc8X2x3xXiwFTtCSMwwSMZ/nX7af8Glnxq8Dp8E/id+zprOpwx6nd+K01WC3dsNLFLaQwHH4xV+JviDWtP1GzMUNwWZSPLXYQMZ969H/AGFv2vfGv7Fn7QWj/GHwleyRxW9wo1GKP/ltDn5lPrXZRynMo8E1cOqMud1U1Hld7e7ra17aG9LA45cMVKLpS5nO9rO9vd6H75/ti/s7ar8YfgT47+DUF/LceM9Jvmi0ZW3S3V1bt92ONf8Anjtb/wAdr+Zj43+CfFnwV+NmpfD3xlps1nf6TqklrNDMm35lbbX79fH3/gu9/wAE/vHtrpPxO+F37Q+u+H/Fl7oh07xLaweEr9ZRGwzlZfJKBlbPzKT96vyf/wCCoWq/sn/Hi50X4i/AD4oDWPEE0jDXLa40m+gcAAESPLcRLvdjn7pNcUslzTF5V+8oSU47e7Lm81sfnNDJM7wWaWhhari+vK+Xy6HzzNL56xTFgS0QJI6fhXW+ErpLWYbHZ9o+7XDaNbXVnpcNteujSqvz+WOM5PSv2f8A2fv+DW7xLc6HpPin49/tL6PpK3lnDcGx0TT5LiaNnUMFZ22r0NTxdzYHh/LoV04yUZJp6P7PQ/Q86wteWWYOny2aTuuq+E/Hz4ueH/t2l/2lDu3wuz7ttcHqGnv4g0Pf5LN+6+dWSv6bPBn/AAbbf8E3fCGkS3/xEfxf4o2pvl+0al5Ef+1+7jWqOp/8EYf+CFc6p4Mvvgr/AGdPdOvlXEfiG4jk3N93azN/7LX5o84wSlqzw6WW42rH93HY/mO+FmsTeHfFSQyrgM2Pmr6JhP8AaUMLpDlbiDdtj+av35+Dn/Bu/wD8EU5dRm8WeG/hBqeupbXE0Eq6p4jmlg3R/ebau2uh1DwV/wAEVv2RLubwxqH7PngrT57SRVs7RtNa8uJf7v3maorZrgqPLNvSR04fJcyxnNThBylHyP57/D/gvxbqEyTeG/D2oXDxy7Uaxs5JGX/gKrX3f+z3pfxU8ffDnTXvPh74k/tG1t/s8qtoNxumZf4tu2v1jvv24f2Wvgr4S0bWV+F+heG5dYhaTSfD1ro0Kah5e7arPGi/u/8AgVc18Lv+CvPhXXfGWseGtf8ACUMCWM6m3mhkXLR/8BrircQ5fGav+R7+X8J57Ti5wht5o/Eb4n+GvFH/AA2rF4WvfD16mrTeJtLhXTZ7cpO8ri32JsPILbhgd8iv0i8K/wDBP39rHxJCqQ/BHVrRWZV8y8eOPav/AAJq+PP2u/jX4e8Z/wDBaB/jnp8T/wBnH4l+HL7Ztw2yFbHcMev7s1+unxW/4LJ/B3wDoV1PZ6TcT3Wz/Ro8/wAX+1X9DeOGa4TDcOcLzk/iwUGtOnJTPi+EcrzbFZhmNOjDWNZqWq0d5aHgUP8AwSg/a9mj8xNC0NE27vLutcXzWb/gK7azfEH/AASm/bISzYnwVo9yn/PG116Pcv8Atf7TVRuP+DgPXptHjkfQtOd4pZFlaO4+Zvm/u1xHjv8A4OFfiJLpV1b+HNHs7WVp/wB1db9zxr/tK1fzhLiOlKN4wZ+kx4bzinK05wiVNa/4Jrft0TW7WyfAC/lKyssW29t2/wCBfergPFX/AAS4/bvsmd5/2YNZnC/cks7iF/8Ax3dU2k/8HB3xe0fxn/aNzfR3MDWclv5Tbv8AWN92SqviH/gu7+0B4qtl0ex1yXSt0qs19byLu/y1YTzyMo+9SkelRyDHxl7taFvmfCH/AAUR+DHxh+C/ijw/o3xf+GOueGbi4iuzaxa1YGDztrRbzGejKCR06ZFcn4WJk0nS/LcE/Y7cA++xRXrH/BVr9sX4h/tbal4Em8f+Kf7Vbw/Z36WsrNl085oCwY9OsYrkND0u8+K3jDwh4U8NQQW13q2l+H9JtBGoVPP+xWtsHOO5cbmPUkk9a/tTwGqqrw5KSVr4TE/+nYnw/ifh6mGyrCQm0+WvC7X+GTL7ag/2VESZtrfNuas261rZHmF8fw7mpI53uLPzJt0cy7orq33f6uZW2yL/AMBZaxdak2sro6/L/CzV/Ek4e/sfc1qnNDmiRXXiTbtSGFm/hT/aqtJ4qtk3fucbv4lrD1a82yHYjLu+9WXNJNLGuxMpH/t7a64YeEong1sROJ1Ufix9p8mba27bub5d1ObxhPtR3SNU+6jfxNXG2kszsX+b938q/P8Aw1ZV5lmTzv4m+bclaxw8Njj+uVZHYWuuJcxvvudu75vv7qtx+InjkidNzrG38P8ADXHRtbQt+58x3/vbPu1eVpmVn3/e/hb+KoqU5ROiniOaJ1cfip5GZBNv/i27tu1qtWHiqZtsO9f9v+9/31XH8LHvRPvfc3VJb3D7jC77DuX7zVw1KM5e8e3hcR8Pc9A0vxdctMttsVv7vl/NtrRXxBczRql4nmf3V3fNurz21muVYzWafNv2oyv8tatrqlz5bb5uG+Xbv3f8BrglHlmfS4eR019rkqrMmZIW8re7L/DWTqWsTTYje8+Xb8n+1TI5pLVmh+ZY227N33l/vbqg1CP92NkO3+4rL96lLlPR9pGMSjJdQ20nnO+Nz/NtqD+0kkZfnbCv/q2/ip2pIm3fDM275W+b7tUZG8mRYSjY2fP5f8Nb0Y80jwcZiOXmOu0PVplkbzvLwybn2/xbq7Xw/qk0aq7ur/Mv3X+bbXjWk65NZxyecjH/AGWrtfDuubrVWd2Qsnzf7P8Adr7inL3T8fket6PrQmkD+Uq+W33ZH+b/AHa2tHvppm3pctF5zfd+9tZa830HWoFj8mHo23e33fm/vV2Gg6q6l32Rl/N+7/eaiUoI6cPWltI7axuPsaom9neP5pZF/wCWn/AatR3m6Z7qEN5kzqu1X/2f7tYcWpTSWezbtkbczt/D96rDTW0bO8Pzou1mrza1P7R7mFxUvslvUrzy2AdNx+7uX5qga4mubgPNBHKF/wBarfeVqZIztGLaHh2TdE0lPja5lhNtclflXczL/er57EKlI+ko1qvJEqrB50gmhhX77K/z1Gsedz2y/wCz5bf3q00sZm2702Kq7tv3dzNVpdP/ANHRHRd/3q86tGEdUerh5dzitQ014fuJvZUZvm3bttZF9p6XFzyZAZFVnrtNUskhb/Sdqv8AcZv7tYt9Z7fnCTNNt/e7n/hrKMuY9WjL3tTzj4kWkkXhu7lchlDRBWK8/eFZHw5gEmi3EgBLC4woH+6K6r4tWluvg27nSNlYSR5LHO75xXP/AAuhWTw9cttyVvRg4zj5RX9M5Q/+OWMwf/UdH/0mgfEyrf8AG6MJL/qGf51C/b2vzIggYmP7/nfeb/drU0mH9586ZX/nn/FTb7yZJP8AXyfL8qtH/FRYyT27D7NC2Pm3bm+bdX8wcqP6Cw+IpSgbtrG8duqJbbHZW+822pYQ7TH93s2/8tEX5W/4FVTT7ozQnejbPvbv4t1XbDf5YR32bn+eNm+Vtv8AdrTm5TzcyxUeX3S3YwpJvKTNFufc+6rSxwrHutn2r/Aqp92oFj2wPM9xDtX+FU/iqxH5ysz20KqrfLWsZTj7x8RjMR7aXKC/uPL+0/fbc6rVS4s90f2z+NflRv4a1be3do+LZWePcsUm7c1MuLdGtUd4ZkDfM/mP97/gNbRrW94+ZxFOVSexg3dvtV0uU+ST5kZagj01JX+RGYbF2Lv+Va07ixeRZDsZNrN80ny1Y03RXt4/tLplZtv3f+WjLT+sS5feOX6vOMjPhs8q9tNM2Nm/b/d/u1YbT3bELoyN/EzNWqun/Ku5FiVn/iT5dv8AvVcTSYZGaF5lVt+6Jf4Wrg9o+ff3TenRlzWZyF5pMMdu9zMdq7fmjZ/vVxHwf8aw6P4k8dzPC1srTwruh2srbl2r/utXV/E7VH0nUI9NhRlZYmf92/8Adr508N+KH03xR4ks5kmLX1qzeXHL/wAtFb5a+3yShUp4b2r+0fB8QV4zxfs4/ZK3xSvPs/jK5heOSLzJWbzJPvNXn3iyR7G+ivIfMO5tv7ytrx5rX2y4t9b2SZ27JWkfdub+9XP61cTalZ/aXmUoyM23+9/s17kZSkeF7pyni7UJptUZ02hWT71Z15JCtsZptvy/cVv4qTxFcKsm90+fbXO61qzyQ+Sdwb+9/eq/tFD/ABEvnETOmFb+7WJFN5LND81bMDm90UeYc+W1Zkke6TfB96j4Qj7xFJ+7+/u/3qZIPMj+5x/eqS4QMv3OV/hqCbhlTfuH91aJGnLzSIGO3rUmx2VXqNxvOTSr93Z5lLmiXyoWPZuOW6Va0yR45fv/AHv4ap1JasFmXd0pClE6S2kk8nZ2X+KmyK8bNs+bd96o7OZ5Idibafu8nCKmU/2qfu7mI37x2Z2t/eaoLpnjX5ODsp7TFlxNJ8v3qZIryKf3ystL4dByIGXzFCI+2TbUNwHSHD7qtXC/Kjwv89VZmd0b52KrR8Q/s6leRsN85VqiZQz76lbZt37PmqKZe1V8JcdxsOd23dtOak2oyb6Zbrvc881PtdMo6LVDluR5TJR6a+z+GpGj2r52+miTIwFwazJBpH/v5Wl2Ivz9KTb5itSqzq2Xer5kB+4H/BpL4E/Ynv8A4z6X468bfF/xFbfG/ThfxeCvBo0/y9NurBrO4W5mMypJ5sixmQ7WaDZtUgS7jswP+Dg34Wf8E0fCvx18SeNf2bvj94p1n4yat8QdSf4k+ErmxMmnWEpkYzbZnhh8lllyqqjXAYZyU2hn8x/4NZWhT/gqD8LnluYYx/YuvhRLMqFydOuwFUEjc3P3Rk4BOMAkedf8Ff8AR9S0P/gqF8d7LVbRoZX+Jep3CoxGTHLMZY247Mjq341+pZDgKj4upVPbz0wtKVrqzV3Hkty/Ct+/M73P0HLaL+u05c7/AIUHbT0ttt19ep6R/wAFNf8Aglv8Of2Ff2Vv2fPj74N+Let6/f8Axc8L/b9asNU06GKG2mNtb3QaAoxKII7qOPYxkJaNn3gMI192/ZG/4IR/s3/Dz9l/Tf20P+CwH7SVz8LfDniGNG8O+ErC6t4b2VJlV7aWSUrOzyyR75PskUJkRAGdlKyRp3n/AAXnu9AsP2Df2Db/AMV2AutLg8KW0mpWpVmE1uNL0cyJhHRjlQRgOp54ZTyPtf8A4K+f8FCfgD+xh4B+F3jL4lf8E89H+MfgLxHp7jw1rupR2f2XR5DFE6WypcWk3lNLAFdcbdywsMHyzjz63EXEmJyvA4fDylKpXnXUpR5Izcac3aMXK0U7dbXstOxMsdjqmHpQg25Tc7tWTtF7JvRH5y/tuf8ABDn9lnUv2PNZ/b//AOCVn7UVx8QfBPhi2eXxJ4f1d0uLmOKHm5ljmjjiaN4kaORraaFW8vdIJPuI35c1+5Phz/grv8Rvj/8AsMfGW+/4J4/8EYl0Dw7DoVxY+LPEnh7VLOCzsjPbmOSU21pbW8t7NFBIXKwktEpV3Kp1/Davs+DMRndSjiKGZO7pztHmlCU0mr2nyO110bs2ntax6uVzxbhOFfo9LtN2ts7BX7I+D/Enif8AYu/4NV5vE/gnU49M1r4u+J57eXUNPljSXyLy9a3lUuhyzNZ2TxHOXVXI+Xb8v43V+yXhHw74n/bQ/wCDVabwz4K0mLUta+EXiae4lsNPiiaXyLO9a4lYovKstnevKejsqE/Nu+aeNeXkwHtbez+s0ua+1vetfyva4s1tajzfDzxv+P6n5p/8E8/2gfFf7L/7bPwy+NXhHW5bGXSvGFkl+0cwQT2Msqw3UDkkDY8DyIc8YbPGMj7G/wCDqP4Qp4B/4KT2vxDtbe1ji8ceBNPvpDCI1d54GltGZwvzE7IIgGbqBgEhcD44/wCCef7P/ir9qD9tr4ZfBXwloct/JqvjCye/SOEOsNjFKs11M4IxsSBJHOeMLjBzg/ZH/B0/8WT8Q/8AgpVZ/Dewa3mXwV4F0/T2W32NKJ7h5btlcrlgds8WEbpnIHz5JjeX/X3Ceytzexqc/fk5o8v/AJNe3zCrb+2KfLvyyv6XVvxPzSr+jib/AIJs/GP9oT/giF8DP2MPhp8aNB+Heg32g6brfxM12WPzBNYyRPfvFGkJVJt1zNHI7NIinydxZskH+e34p/BT4yfAvXLfwx8bfhL4m8HandWa3drp3irQbjT55rdiQsyR3CIzRkqwDAYJU88V+zH/AAWP+InxD+Kf/Bv3+z741+BWn6zbeBbi00CHxnBHcF2ht4LA28Ed0URfMiF3GBvIVDIsJ25ZMefxusTjMXlcMLUUVKrpNpSipKL5XZuze/KursYZtz1amHVOSV5b7q9tPXrbzOHvP+CNP7d37AHw78U/tU/8Ehv29rH4i2Nz4buLDxFaeD7JP7Sv7bK+bHZxxNdw3E8fzOpR47hCp8nMhAPw5/wTD/4KdeOP+CZPx58T/HDTPhLpXjTU/Efhy50q6GvXUkNxbyvIsqzLMAzY85EaVCMyqu3cjYdfqf8A4NPz8df+G7fEo8EnUf8AhBf+EJm/4Tjbn7H5vmL9h35+Xz/M8zZj5tnnY+XfXxx+1R8Il+PX/BTH4h/Bz9jnwbq/iI+Ifilqtp4S0eGINPcMbqUtjoFiUiRt7kBIl3OVCsRWAh7XMsdlGbSjWioQlKpyqDcXf3ajjbWNrp3Wl2OiuavVw2JamrJuVrO3aVu3TyOQ+Hngn9oP9v39rq38O+CLO71z4g/EfxbJcmVHlbbczytLLcyP8zRwxAvI8hJ2JGzE/LX6T/8AB1F8Xvh/aH4I/sfDxh/wlPjv4f8Ah6S68W+IJjE1yBPBbRRichSyTT+Q1w0e5cK0bFWDow7EH9mr/g2U/ZoIB0T4g/tdfEPQ+eslroFq5/B4rJHX/ZlvZY/4I4/3H48fGP4wfEn9oD4pa78afjB4qn1vxP4l1GS+1rVLhEVriZzyQqBURQMBUUBVUBVAAArbARlxLnlHMaUeXCYZSVJ2s6kpLlckulNLRd3r5KqKePxcK8VanTuo/wB5vS/p27nGJYG4vJCr7Msd3+1XSeBfDN1q2qRabbJvdnX5fvVjWEKPcOScYYn5fvV7h+zx4Zha5GpTWDO33n2/wqv8W6v5k4gm6eZYr/HP/wBKZ8k6ftcbL1f5lPxJrlvo+nxWCTRu9mnz+X/CteT+PvF1zrkm3zmEMbfJtrqvj1qX9l6xcWNtNjzmZ3Xb91f7teWXF4l1E23dj7u3+KvFwWFjpPc6auKlT/dn6ef8G/Pxavvh3458QajaWE00MGkfariTz9v+r+8qrTP2wtJ/aB/4KJftXTfFfx/4buJfC2jxNZaXpNnudLGz3f6zb97dI33q+e/+CP37QulfCL9qLSdP8Q3VnDp2oBrW8W++6yt/DX7R+HvFnwd/ZMste/aS+J3xK8JaL4L0pLjUPKSeMz3m1d0UMafxfN8tTSwl8zcXufreR43J6WSfW6qvUhH3f8j8Xf8AguDceHvhr45+H/7IXgPdHYeEfDMes65DG25f7Qul+Xd/tLGv/j1fDW/d8mzc392vU/2rv2mL/wDbA/af8fftIeIdPW2HjLxBNeWdqv8Ay72/3Yo/+ArtrzC4037O29/+AV+hYOjGhQjA/C8+zKpm+ZzxNSWrC3Z2X5+v8dTySf6xPl2L9yoY4/3ex3w396rG1/4NrfJt+aurlieSNXZuXYjfe+dmrY021eWFk2Lj+HbWNJN91Jkwu7/gNdj4P0lL5VQr8zfw0yJe6ZN5Yzww7/vvt/uVom4+x/DvVbn5d8dvub+Fq2te0V41/cpu/h+9WT4zP2X4S6mEh5by1bd/D81ZyKpnlEep/Z4mvZ5llmb7sbVd0+SZVa5cfeffuasKxtZrqUMseRW62+KFkz/wGg1+E7f4d+Ptb8J6tBrGg63cWN5ayq0Vxay7W3f/ABNfdn7MP/BU12mh8MftIaas8TMqReJLFfnVW+VfMj/2a/N+x1SaFldE2stdR4f8RTLCN/8Avbdm6plH+U1w+Iq09j90tB1vSvF3hu28YeDb+G/0q4+a3vLeVWVv9lv7rf7NSyTTR3O9zIiMm/cv8Nfkz+zX+1l8YP2edSe8+GfiFYra4+a8028XzbSb/aaP+Fq+pvhp/wAFWJrqaHTfip8K7X7NM/m3F9oNw0bbv91v4f4qX1iUdGj3cHmFCMfe0Z9htffavuQ/Lt/hbbWBqVj5ly+9F2fLsZpfmaofhz8X/AHxq0GLxF8NPE9vfpJ80Vm21ZYf95avSRvJCLZztk83c21Pl/3azrVos+owNRSipxkeA/t2RInwv0Z1tliLa4u4J0P7mWu3/Y+0xLv9lWxnKBmSe7ZSW6fv34rjf29Yni+F+jxyQyKU11V3N0P7mWu//YsE0f7LWmSoVAaa+GWTP/LaSv37MF/xzjgkv+gx/lVPjcNU5vFCu/8ApwvzgfmF/wAFItL/AOEb/ai8QXdtDsF9ZQt9zb95a+eNK0a81OdI0RmL/N8qV9qft0fB3xJ8bP2vptN0ew86O30mFfLhTdub+9XU/Bn/AIJn6rpbQ6r49h+xwSffX7zKtfhdOC+0ebm9aNPMJwXc+QvA/wAEdb1yaF4bOZvMbazKn3a9v8I/Amz8LWK3mt/6KFVt7N97dX1F4u0n9nX9nnRpkTybySGLascnyN937vy18YftCftPTeKNUmsPD1sttbr/AM8//QaqVSP2TzfZzqeg/wCJ3xK03RYf7H0Dau35nk/irxzXvEkuoXLO77/96sfVtaudUmZ7yZmZm+6zUkavI/8AtN/t/dqKfvG/Ly+8TedNdMron/AaVodsLd2aprGySOMO7sv+1U81qir02/N8jVRPxe8Zd1Dvfd977vzVJ85I3sodv4anmt4Vh2bF2/8Aj1QvIki/+PPS+2VKMSNlO5v977y1ZhXbNvdVx/eWmRqiblT7rfc/iq0zHykwi/3f+BUl7sveFHY3vD8sNzAqP/D/ALFXp7FPM2Qlguxfu1j+H13XGx9zFv7rV09vZunKJu/usrUcsZDk+UzrFpI5N7uyp/dZvvVqWdw8d187syN93/ZqCexjaRXTdIzfeX+7SNbusgfY23+HbR8JMeaUDr9Om02aPY9zuZfmddleV/GySFrpEtuNzbttdVa6lNZts85ga4X4qXH2i5iff/vU48xVP4jkE+8K7zwPffZdDmd3wVT+GuCrqNHm+w+HrmV0/h20SjzGtTY53Up3urySST72+t7wbps80yMn/Amb+Gufgie4m/3mr0Lwvpz2dj9p2fw/dojsKp8Jf1aVLa1CQvjctYyxwzN8/K0mtaptkaJPmLNurPt752Xe7/Lup/ZMeX7R0FvdQpCqJ/D8qN/FUsbSXUmdn/fVUrFXmVT5O2tyxtvs8fz/AC7v4VpRh9kJVeUu6TpqR20rhP4GrzyfVpvDPjR5oZtq7/mWvRJNSEjfY0uVC/3f4qwtH+BHxd+MXi6LQfhj8OtW1q+updsEOn2DSyTN/sqtVKIqcoyO1tdWh16xtr3+L+Dam7bV7Q9NstTvFhuZ5ApGWMQGR+FfdP7Bn/BsN/wUB+M+mQ6x8YdOh8AaJcOrpJrk+258v/rivzLX6PfBL/g1N/ZI8DW0M/xO+M3ijXrpYdk62Pl20bN/48zV2ZfnGMyqcpYao4N726nVhcTjcHJvDzcb7n4E694RsNL0p9StL2WUKVCllABycYq58FvgR8X/ANorx3bfDb4K+Bb/AMQazdkCGy0+2aRh7nHQe9fsn/wWq/4Io/sbfscf8E8/FPx/+Di+IE1zQ73SobZb/VPNiYT38ELkrtGPldse9dt/waM+EvCEX7KHxK+IEnh+zGtn4iGx/tZoF89bZbC0cRB+oXc7naO7GvvYcR5ouCKuOdZ+0VRJS0ul7um3mfXUMfmUsgnWlUfOp2vptpoeVfsV/wDBqBc+O/Ao8U/tq/FLXfCuo3USPaaF4VuLZ5rfIyRO0sMihv8AZWvZ7n/g0c/YctIXnuP2l/imqou5i0+mYA9z9kr9E/i7+1X8N/hFbn+3tZjWTftWvjT9qf8A4K36cPDl1ovw8v7Wa4Msi7ll+Zo9v3dv96vzPEeJud001DEyb+X+ReBhxBi2pOo1H5f5Hxpff8Ekf+Cc37Lv7R+ltpXibxh8SJPDuoLcXfh3xJdWElheEfcSeGO2DSx5wSm4BsYOQSD+svwAvdE8SaVH4/8AFnxADLdZa3spplRbcDgIV7V+HviL9rSbwnqFz8Zrm5hvBfXUiSxzL/pMcm7+KsWz/wCCpPjO1vI7awv7iNGdmRVbay/7P+1Xw+a8T55nc4yx03U5dFfp8kfU1cthi4KPtGn/ADM/o8g8a+D4FS0TWLaT5e0imud+J3hb9nbWPDc/iX4kaDoU1pZx+a15dQoCoX0b71fhV8Jf+CqPjOa4trLW/ElwrzXUdvBHuZmaRm/hr1/9pz9t74l+A9Fs9K8YalHK8MS3CaXcRNIszbd0bMv+zXnUs3qU/dnTOBcIU4y5qdZn3lo/xu+EWn+DL34PfDK1uvDOmau8iW9zZys91ukb7yq33d1fm9+0f+zx8a/2GP2prv4u/GLxJb+M9H8QWrf8IR4g1a3222mt/F58f/Pwq/dWtz9in9tjSvHHixtY1u8Y3FxdbvMZPmj/AN3+7X1T+0pffBr9pr4Hav8AAXxhOyW2ofvtO1G92yy2d4vzRzf99fw1w08dzylGs/8AD5H1WGwEsFOMsN8L+Lz+Z+euvfFzwHr2rXnj/wAVeJJrmfUF/cXWoXTPeX3+6v8Ayzj/ANmvL7P4jTf8LKh1XwB5wtpnZGZflVlr174E/wDBJ3xnpM2o/ED9rr4u6fZ6bY3siWraXL58t5Hu3R+X/DGu2pP2jvHnwW+HNmmg/AH4J318mjwM9xql5E25v9pvlrtp0eaK15uY6a2ZUqNa8Ps9z5l+JY1u2/akLa4xW8GuWLuznBGRCVJP0xWt+0Z8TNet2vILPWFd1dl3RvuZVrk/Hur3fjr44Lq+s3RaTUryyMktvhSFaOIDb6ELjH0r2vR/gB8Fo7iK5v8ARLy/dflibVL1n3N/tKv3q/qDx3yytiuG+FOVpcuBgn/4BSPw7g3OHhc0zaUNeevJ/wDk0j4lvPiN4q+2LDC7YklZf3KMzSf98/xVo27fE7XFD6b4M1y7WR/vW+lzN83/AHzX6A+FfCPgDwlqDTeG/Aei2HmfM629hGq/7LfNXTR61cxvL5OqtEu3/V2/ypt/ir8GpZXhqceWR9hWx2OxHvOR+cDfBH9ofUvJ1LSvg/4kvPMl+7HZbdq/8Cp/iL4S/tUaPH51/wDBDxRFFHt3yLZblVv4futX6OzXl5c3A+eaV40/v7WqG4vrwwlEubhV6+X5u3/x6r+p4WJnGtjPszPyw8UQfEC1uI7fx7oGo6e6q3kRahAyE8/NtyBnt+lev/ATxVfeFvEnhDxlLG6y6TqdjdRgjBxDKjIR9QgI+orq/wDgpafM1/wrP5hYvBeZLPuOd0PfvXI+F18yXQEIJ3WWnDHr+5ir+yfA6nCPD84x2+qYn/05E+X8Q51f7EwXO7v28dflM29Usfss13qT8zXV7JdXDK+5fOkZmZf/AB6uY1LBn+fy8M38Ndz46tX2ybPOVN3y/wB3bXEXVrNND5Pk/N/Bu/hr+IuX4Wff1ZSlEwL6zeZyjuzLv+f5PmrNuLPaxs08z5v4f4q68aXuZX2Ko/6aNUy6DtZkh2p/G7bdyt/s1106kdjwcRTlI5X+x08svv2bdv3qaunXMbG5mm3pv3J/FXeWPhl5YXmmtm2bN3yp92kbwjcrIf3Oz+L5l+9WntoRkc31WUoKSOMsrF0jhd3bLfNuVf8A0Kr9vo811MEhdtypu3bN22tubQEb5NjKGWpF059yO/y7vllVflpVKkJS94ujRnExV09/7/8AHtfzPu/8Bp/2F23zTJsRf4mSuh+x+X5UL2zbG+R2ZPu1Jb6Hc3DFPup91q4KlaEo8qPawuFn8Rg2envb7Psybov+ee/7v+7WlYwQsQwTD/Mvlr97/gVXLfQ4ZIfMdGX+H+6y/wC7RHbvbs88Ls6L8vlt8rNXBI+jwdOUR9vCW3zOjDbtZ2kf7tOuIXW1cuNw/jX+7Vux01JpvJ2b/LX51b+Kn3Gn+dZiHY0Qb5vlqeX7J7NGnzR0OaurF2mKImxFi+9J826siaz/AHgld5Ei/iWN/mautbSXaPZM6n+Gs/8Asl51dHeMBVbbXRRlA8PGYOXPzM4C11IzXDed8pb5k/urW5o+seYyo9+wH8Fcku9pN7vmTf8AJtT71La6k8fz71xX2EJfyn5BKPL8R6xpuvcFPOVlZF3+Y+3ctdz4f8Q2ybZkmZo2b5WWvDNC1nYyeT8/95pH+9/s13Gh+KnXc/n4ST76q/3WqK2Il8I6cep7HpmvJdSK+y4cs+3y4327f9qt/T7xNrJcozOzfw/xV5Z4f1y2lX/XNlX2/K1dZo+tM0eyG5YOrr5sleTiMRPWCPcwtP4ZHb2mzkzQs5mX+Fv9Wq1fhazaNd75ZnVU/i3Vzel6k74hS/8A3bff2/xV0ujzukZd3X5v4V/hrw8RufUYXXc1Ft0aGO2eTe7ff8xflWrs32beuEZF/hbZ/wCg1UgkEcYdH2/N8zbPvUv9oeYuxH8xl+Xatcso80PdPToylza/CZWpx2crN9mTj+Ld97/gVc3eW9nawsiTTZV/4vmZv/sa6HUrzyYVm3xn+KX/AL6rB1a8hVXmmlVmkl2p8v8AF/CtEf7x206kYHD/ABfVh4JuJTIGZzFkEYZRvGN1c/8ACrzm8MXaq2U+2Hcnr8i10XxgWzHgq8mRt0zyRBzvzj5xxXLfDIynw9drGXOLnO1O/wAor+lMo/5RYzC3/QdH/wBJoHwFetyeL2Gn/wBQ7/OodBdSQr+5EzbYf71EEkzWpuYHX5n+Td93bTL64jkXfvbYvy/7TVTmjd9qI+75/vb/ALtfzRKnKWiP1yWcSoyOgsWmsYWf7euzylZm2bVrWtY4bjMm/LK/y7X+6v8Aern9Nm+0yJC/zIqbdrVuWf7i5S8d9sK/wtWUoz5uU4a2ae2iaVjI8IbeN6q/yL91WWtFbFJmf52VpE+T/e/3apWc0NwvnQvjam5lZf8Ax2rtrHNINjusiyJ8u5PlX/7Klze7rI8uVTmkT29u8ezY67l/i/h/4FSHT0m2wwpJhW2qrP8AKv8A31V6w0y5t4ETYvyt/e+8tasNnbXEYm2R72T+L+GuenWMrc32TEbSPtTK/kyBW+82/wD8drYbS7Zo4/syNsX5U+T7rVpWui+W0bwopVn3bVrShs5Li3FtN8nz/wCrZ/8A2ap5oyaTkXGj7nNI5tdNm+xhZn8wbtrLs+9Tb2zh02zZ32xIqs8s33vl210K6anzwworo33FZ/u155+1F4sPgX4d3jwury3CrBFGv95v/sa7qEJVsRGBzYuUcPhZVH0R5JZ+JP8AhOvHusalsVbe1tWS18643Lt2/er518aahNoHjxrlJlCzTMjtG+35a7HwP40TQ9Y1WwgRYkuLdVlkX5mjrzf4vSJdf6fCjb9zMrV+l0afs6MaR+PVak8RXlNyMzWNUkvLi80ab5e8C/w7awdL1yGOZtNvJtqR7tlUbjVprxUvE5dfldd392ue164mW4fUoHwrPu2761FH+Uv+Lo3NxLcwvuDfw1x91M90pR/lMf3K3brxF/aWk7E271+5XOXUe6Tem7Z/tUe/IcS/o90katDcvlGT7q/w1UkuEhmyZm+X+Goo2+zsH3/LTJwZXLhNtBZaKQ3H75H+X+7Va4jRWbyk2hqjileJ9tWftUMiE7OarmD4Slt+bNOT7wpZPlZkptUV8Qj/AHTUiZLLUb/dNPHyMn92p5Qka+ntGuN+5f7zLVmRYfnTe3+9/DVXTW+XZv3bqtXMokhKdFVP4azlKfwmfuc5BJJG27Z96o/ORm6f8B/vUjzp5f7t8n/Zpi7Np+fbVFD92z7gxUVxGjSNIU/3/npzbNuzp/tU/anlsjv/AMC/vUE/aKkzfvOOPk/76qu/3TVmaPOX+7tqp/B+NOPulxiPtW2zA5q5NazSSff+9VOxfNwvyZrpFgSa2D7Nr7dqVUYzFLlRgXCSLJsm6LULRsv3Ola11ap5aJsw/wDEtUPLeIjHXb89QLmIfL7yU+GBZpFjB53AUSLjb/ep9oqrcxn/AGx/OtYpKokNSu0fUv7J3xf+If7Inxg8G/Gn4PXUTeIvBeqxX+mG6tjJFPIhJeORFIJjdS6MAwO1jhgcEfc//BRn/gs/8LP+ChH7OL+DfFX/AATY8J6L8Tb6W0k1T4nxzl7iBoVCs1uyQRz4ZQEEc00qKnBWQhWX4J+H1slx4hAkQsqQszAenA/rXpC2cLbY0+7IjbFb+Kv0LjPPcvyHPKEFhFKVGMeSXPKLS6RfK9UrbO6Pqs/zunlGYQoxop8kVZ8zVl203WnU9h/bT/4KBfHz/go3+zx8F/gFD+zC1ha/CHQf7Mt9T8PQXt4+pyCGGAOFIIhXybeEFCZGLqzbwGCL9Df8E+v+Cuf7cv7NPwQX9lH9qD9gzxH8cfhtb25h0zTvEPh+9a9tIgUMVqXnt54p7WMp8kTxbkyArhERB89/sV/E9Phn44i0F5pore4n3pH935v4vmr9OfDfx4+G/g34b3Pirx/4y0/R9Os4N11rWpS7Yrdf4lb+83+zXjQ4qynH5V9Tq4GPs4tyS55XUm221L4k7t7P8D5+pxi6kFQWFi43v8T0e+j3Pkj/AIKGf8Fdv23/ANpT4HN+yj+zP+wd4h+B3w1ubdYtS07QtAvFvbuIs7SWweCCCKC1kL/PEke58EM5R3Q/mH408NeI/hverpnxE8P3ug3LruS31q0e1dh6hZQpIr7e/bW/4Lpav4yur/4Y/sbWH9n2UkTWt18QtWgb7XdL91msoW/1a/7TfNX5V+O/FPibxX4uvdf8X+I7zV9Qmnbz7/UbhpZZf95nrsyrjbD5PReHwODjGLd370m231bd235tnr5fxPUo0+WOHjFb7t/eevLr2hv9zWbQ/S4X/GvqP/gmN/wVf+Ov/BL74iax4w+EVrpGv6H4ltYbfxJ4X1uaQWt2In3RzI0TgxTorSor/MoEz7kbjH5yb3xkPjmrC6nfxgIl2+3/AH66cw48lmOGlhsRhITpy3Tk9evbvqddbiepXpunOinF+bP3y1P/AIOgfCfhXQ7/AFv9jT/gmX4G8G+MtYH/ABN/EMk8U8UrE7mLpZWttJOSxJG+UYPJBr82fhz+0z8a/Af7WOlftkagieJPGun+Mk8TXE/iKxNxHqF+J/PZpl4zufJ+UqVyCpUgEfImm/ETxro6hNK8TXVsF+75Uu2rw+NXxb3pt+IWqZX7v+lt8teXlnEuBymnUjh8DFe0VpNznJtdryu7eWxz4fPYYdSVOglzb+83+LP0x/4K3f8ABYjx7/wVhv8AwZot58BdL8F6b4OS5e2s7fUDqF5cXU4QTObhooikW2JMQqvBBLM5C7d3/gmH/wAFpv2qf+CfPhKX4GyeHdC+JHw7v7kyN4M8R6u/naajhvNSzkVnW3jkLbnjaORC2WCqzuzfnjrR1zWPAe+1mnkv7m0iYyI5Eju20sc+p5qD4S+CdV8C+JLbxVfvJ9ph+by933v7ytXo8XV6OUYOhlOGowWHcFPlknK0nKTupX5r+d7+Z0Z9j1l9KnhqUY8ripWab1bfW9z9vPiX/wAFfv2wP2m/hNffs5f8E4/2WvBnwP0LWbd4LnVNJ1YrqEDSEGR7NrWGCO1dhuUyCN3w25WRgGHzv/wT7/bO1b/ghV+1D8QPAXxi/Zo8M/EfxNeaTaJeeINH1pob/STJ+9+yx3UsDjy5AQ0sQRSzpGS52Ba+jf8Agljofw9uvhO/7QmqpDbaPo+lzX+pSbflhW3jaST5v+A1+cnijXtT+NHxC8U/HLxI7Pf+MvENxq0rSfeWORv3Uf8AwGPbXyFHN50coqYNUYKnU+L4rytrrLm5n958nT4ixiw86bjFRe+ju/V3ufo94v8A+Dhr9iz4ka/d+O/H/wDwRu8Ja9q16ytfatrN7pd1dXDBQql5ZdNZnIVVUEngADtXxZ/wVJ/4Kifsl/tr+CNB8E/A/wD4JweEPhHqeianJcXnibSjAt3PGy7fsyi0gt0aMn5iZRIQQNmz5i3j+oaTCq7A7Ii/Kkdcj4q+FCeNI/Ih/d3LbV3L93b/AHq5svzGvgK8K2EilOG3vVGlpbZztt0tY2wmfYihVVRJJLb4vy5jgtDvoYla62SJubH3M19bfsh+G9B8TaDJZvukmkVWX5Nu7/Zr5O8bfDzxV8M7yCz8QwN5dwn7iRfuMv8A8VXtn7EvxaTQ/iTptneTRyWSyt5scny7fl/9Br834mpYupOpOe8m2/Vu7PcyrGUcRiFOezNT9qL9k3xp4i8Yf2j8PdBuL5mRt1rbozN/wGuU+DP/AATl/aK+Jnie3tv+EA1LTdNaVftGpahF5Sxr/Ey7vvV+hvhXVrOPQLfxVpVxGb5rhll+yp8v3ty+W3+7W74s/aKsNDjvNe+JHjCS30jTdN+2TzNF+7hVV+6v+01edgs1n7ONOEfePo62V5fOXtec+Bf+Cxnhv4afsxeK/hf+zZ8DfDFnpl54b8KLq/iDWIVX7TdXlx8v7xv+A7q+M/iF8Y/in8ULK203x38QdU1WztW3W9pcXTNFH/urXoH7Ufxp1v8Aae+OPiT4161JIF1S4WLS4bj/AFkNnH8sS/8AfPzf8Cryea1NvIX2bk2/JX6PhsNF0oTqL3j4bEYyrGrOnRk1B9BLO42sER+P92r7SPJGA7b3/g21mQq8M2/d8rP86tVy3uETMz/Kn/LLbXby+6edKRLbybJv3yLvX+LfSzXQ2s/k1R1RnhkS8+Vk+6+3+GoFudpCPMx/vrS5hmvayeZJsfcr/wB1q9l+Degp/Zb6rcpt+Vdn+1Ximh3KXEyJMfuv92ve/h75Fv4XEwm3P/eany8xnKRS8YWaQ3b7EaVF3b41b5q4j4vMLP4byWfyq8lwvyrXe+JpPMjL7dqf3v8AarzT42XSR+Hoovm3faFXc33W/vUS5vsigvfOAsoodPtV/d5fbupk10lx8/8AC3+1UdxIjRqibm3Lu/3aqx3AZv8AdqPfN4/EW4ZEZWfZtH8daljdbseVN8v3v92sOO4/jR2xvq9DcJ9nRN22gPe5zsNB1y5t7gBJmVW+XbXc+H9chXbGkak79rK3zV5Ppt0k02wIwXb/AKxvurWr/wAJhDplwn2BGeRf+Xjd8u6q90o9n0/xZc/D/UI/ENt4hutKnhl82K4tZ2jk/wCAqv3q6/VP+CpH7UsmjpoPh7xtbnavlf2pdWCvc7fu18uNrFzqWoS3+pX8ktwzf6yR63PDtr9tmV/vNUexpSldlUcTiKHwSsez+Avi98Xfij4huZfiX8Q9U1lVti6Q3sv7tJNwG4J0BwSM+9enfDT9uD4yfs66vP4V0WWPWfDySiVvD2oECNd6DcY3HKEkknPGTXjnwgNrF4hmtoJ1ZjYFmVe3zrWt4x+Hkt6uq/EW78SWNnY2bwwyRSXS+fLIyDaFQ1++ZjSX/EueDj/1GP8AKqfN0cZWjxhUrRk7+z36/ZPWLj9s7wxZ/GST4qeG/Dc0S3kUcT2dxF81u38X+9XR/Fj/AIKCbdBa1sNyXE0Tb22fK3y/K1fK0niLSrNdmmpv28bm+9/vVQvriw1xW+323mKz7f3j7a/BPZxie7Wl7arzy1kcz8Yvjx4h8eao815fSSeZu3/vflrzS5vri+m86R2J/hr2K8+EvgnWbX5JpLQqm3dH81YF18C9Y0+YPYOt7C3+qWNNrVUY+8HwwOGsdNubhRv+b5vvVtaf4f8AMkXL/drttH+Emqqy2yaVMTv+6q/datbTfhHrz3DW8dgwb+9W/syPafzHExabDa2vyIuFes/VJkVfkdVr064+BXj++Xy7DSmYN/d/vVkN+zT8YLmRUfwZIyM3zzeaq7V/vUuQUa0ZHnVzHtU73yzf3qhVU5/75217JZ/sg+LZJP8Aia+JNJsE2q/mXF6rbf8Aeq237N/wx0dvtPiH4tQv95mjsbfd93/arLlh8JfN9pHimxz/AHdq/LV2zt3WP54WU/7Ve1aX8KfgCyqltealfTNKrRL5qqrR/wAXy/3q9T+H/wCyb4e8dXyab4M+C15M1xLsS6vrhmVfl+Zm/hVf96rjT5jnliOXc+UtIt7mFt/kZO/71dbZ27zW6P8Aedl/hb71ffXh39mf9mb4Q6PPbeLfhjpvibxJ9n8q1jVma0s22/eb+81YWg/s2/DTVNY+2ar4YV3ZVaXTbOLYka/7P+zVctMz9vV/lPiX7K9rGu/cNzUyOJFutjw7j93d/DX6JQ/s8/Aq1ujbP8JdNit4WVtyo3mN8vzK1ebfFr4FfB/zJbvwr4DhSJW2yyK9P2Zcq3L7vKfFeoWKK3nJCzbf7tebeOZjNebB0Wvu3Q/2ZdN1ze6eFVjT5mWb5lVq07v9in4LWNmJtd8MW9zdtFueGFm+alyx5QhW5ZfCfnVpNibq4CYrovEFjPZaGsez/ZbbX3jpP7BPwr1TVIZk8Hw2cEi/892Rfl/2q67w7+xP8AdJ86HUvAcepvv3RW9xKzL93/x6nCMf5gljJSlpE/NDw1pH2i6R50wiv83+zXf3FleNZiz0y2uJnVflW3iZt1fopZfB/wCFHhqFE0H4N+H7OX5lVZLJZG/3vmrpPDPwjub6H7Xc6bp9nDbory+XbwxxW6/xMzKv3aUuWOpP1iVSZ+V0fwp+KniC8CaV8OteuVk+55OlyNu/8dr6i/ZW/wCCFf8AwUc/an0yPX/h/wDAK+stMm5+2arcLbr/AOPV+h//AASY+Cz/APBRb9py/wDD2l+cnwt8Cyq+rXkabV1KRW/1at/dZlr97vC3hHw94K8P23hnwtpMFlY2cQjtbWBNqRr6CuiNShQjdwvITWJxWkHaPc/nY+EH/Bod+2jqzw3fxL+LvhnRIpP9bHHK0zxr/wABr6f+H3/BoF8GbfT4/wDhYf7S+sveNFtnfS9OVl/4D5lfs1swPljH4GuR+HPi9/G8Op+I4Jt1m2qTWthhfl8uFtrNu/2m3Vnic2nTpuUYRj6L/O4U8opuXNUnKXz/AMrH5zfB3/g1P/YO+HHieDXfHHjrxR4qggkDJp9w0dssn/XRk+Zq+9fgV+yf+zD+y/pEekfAr4K+HvDcMKbRcWNgvnN9ZW+b/wAer0jc3c1ka1bzXnyIjbPvNXxONzrEyd4HuYfC0o+6WrrxVZKjGGZWEf3m3VxGv/GyGzmkghuY2kVtqKv96uL+PvxCt/Auhu6yMiRxM7bf4dtfJq/tXf8ACG/b/GetnfbNKrQW7JuaT+LatfPVsdmGIu3I+nweWUILmlHmH/8ABwz4/vNc/wCCTPjiDUJlj+16xoiRws3LMupW7HH97gV80f8ABuV8ZoPgx+wL8RvENxdIg/4WgQqyvtXnT7QHJ9+BXD/8FYv2qbL9o/8AY68anXLW7028tdW06TTbK5Rgrg3kQZUz2C5P4Vif8EantLT/AIJvfEPVvEVjHNpFt8TmM+5uQ50+1AyPSv1TATnPwhxDn/0EL8qZ79PDQp4JwjFb3t06G3+31+27eeJPFV3bJeTWz2svzwru2qzfd/8A2q+KvGHxWm1hlvJtSa3vZn/il+VvlrR/bi8babq3jee5s9RZ0kddkkdxuZVX7q7v9mvmjVvGk0l0yJc5C/d3V+e08LSlC6OZYipSlyzOw8beOtY8VeWNYvJBcwv5W77qsv8Atf3q4q48Qa9YSNDHD525tsTK/wAytTF8QfaG8l3UPI/ytJX2Z+x3/wAEfPF37Q/7Ph/a2+LPxo0H4YfDhLlha+JPEtu0s9+F+Vvs0C/eVW+Xc1bQwtJK0j0pYyhGMXfU+dvDvhH4i6Dotn8Qv7b03Sms3W4sJLi/Vn+X5vmjrX0f9pjVfjF4m1c+P/GVxf6rdS70WSXcrL93av8Adr6avv2L/wDgjX4esF/4Tb9uT4ieMvsrMs66Dp0NpbTf7u7cyrXGePvgj/wSa8Oxxa38FofFEN4qt9lvrrXGkbzP4WZVrklDLZfHP3jurVcfGlFQhaPmcj8J/F3irwj4pR/D0Mh/hbyU2/er9EP2Ide02x1yK2+PGm/2xqEyb7XS7xtsdru+5I3975f4a/JDVPiBqXw18Z75tbmv7ZWZrW43feXd8u6vqv4V/txeFfFWvaZ4xSZrPWVsI7XUvtE6qkixr8rLXmYrC04+9FF4XMP3fs+f/Efth8NbPSfC3iuy1b/hDNKv9Bm/dT2DxeY1urf8tF3ferV/aT/ZF8A/EfTT8Q/h/Z2v2yyiZrjSb1NsF5Cy/vI/l/2a+Qf2Q/8AgoL8Jr/w8LvxH4phvhZozSx+ftiVV+9uZv4ql/Zp/wCCh/iG+/aW1Xwf4muL298J67qMjabA8u1be32/Ksf96ssLjpQjyOJGZZTKtVVWnP7P3+R+VvxJ8JH4fftG3/hHA2ad4lWOFFXAWPzFKKPopA/CvetLvLdVSH+LczIzN/FXnn/BWu00mx/bc+KsXgVGs7Zp45NPEYw0JewhcY9CGas39nPxF421T4ZaZeeO9S8+5VlV5lXazL/eav7J8ZXOfC3C7fXBU/8A0imfgnDrjSzTHw7Vpf8ApUj2qLU5+P8ASVk8xP3qrF92ry3k1qoPksHk+V137VWuVs9W+zzboSu3Zu8tU+8v97/ZrX026uZLrfvaRG2ruX+Fv9qv5+lHl1PvKdb7B1en72jaH7SzN8v3f4v9mn7kkkCSedEkm5kVvvLtb+KqGlreKvlPtjWNtz/xNt/+KrY+yvcbd8+9fvbmSuWpLlO+nU+yfHf/AAUziSPXfCZQghre95H+9DXIeFI5Ptfh5IxljZabtB55MMVdl/wU4txa614QhGAPIviFCYxloTk1zHgZI28SeFEVSQbfR8hTycwwZr+xPAt/8Y9P/sFxH/pxHy/iFd5Hgf8Ar9H8pHo3irw+88bWb/J+6+ZV+Vf96uOuPDqWrPNvyGb7rfw17t4w8I+fG/7llVvm/wCA7q898TeFUaZv9DVI/wC8z1/DdSpKXun6HH+8cAmkoyu+z51f5m/9lqza6fcwnztm9dq7l3/+g1vNoKGRZpk+dV3fL/EtSR6DN52/yfl27ttYRqcuhzVI83vIbpOkw3CvN5G1227Pn+9VpfD/AJarM0KzBfusr/erX0HQ0tZHSby3O3cq/wB2tzT/AAmY4jDNpqlG/h3bdv8AFupSq80OY2p05fynnV54f8mLznRtsjfdVfmWqTaDcySbH+Z9n3mb7y16jqHhH5lkkRmC7m+b7rVnSeE0aRJERiPu7VT7v96nGtOXusiVGXPZROEXQ7lXHl9Vf+Krq6aluwSaHKKu3dH8zbq6WTw7DGER/mZl27f4mqzZ+HZAqzfaW3KvzsyVjKUPikelhqcublOVj0WaSFoURlXf/wAtF+7urKutLs42d3+VV/hb722u61TS7xl2TXK7F+VJG/irndWt7lpJts0ZVVXe3+1WdOpzHuUY8stDBK+XGnl/w/Mn97bUjXE0c2z7LI42bvl+9TL6bbs/iRfmdl/vVD9s84/abaRfl+4u75ttaxlI9ejTjIRpv9HCFJA/3tsn8K0yazSFf+WbM3zp/tUxZraaEbEysabU3UnmQ+dlH+6u1f4matafxHHjqfU8u1WwexuHRP4U+9s2tWLNI7b40GD/AM869S8TeFfMVZ9ir/F8v3q47WfCk1nJ5ybf3n+zX0lPEdD8XxGGlHU57S7iazbfCjH5Nu3/AHq6zRdQumjD7921du1U/wC+qyI9NmiZd+0My1t6TYzRypawpj7rM33f96ipWOajS5Ze8db4fkhjVbmZ2+b5dqt92u20nUsSfI7PuT738VcBpdi8MbPG/nfxJXV6be/ZofO34eP76rXnVPelzcx7OFj7P3ju9FvprPbvRW/vtXX6FrCXCr/q0XZ/F8teXWOpQyRolt5inerfM9bVnr0u1XuXh2b9rbvlkZv4a4qlGUpnqUcRynpa6tbTQt5KSCPd8rKm1d1R3WqIs3zzbEb7jL/eWuS0vxBM0bu7ts+6jR/Mu6odW117e63/AGn5v4Gjf5f93bWMcPPud0cVzR946DVr6NZP3z8t8qN97dWRfXjyHY8zE/3Y/u7qxrrxM5z9p2t/Ci/xVR/t62m3yI7OVf5Nv3VqpUZcvvmn1ylGWhT+Kd20nhW8t5Bl1mjycYwNwrn/AIbyoukXEbOFLTnaxOOdoq38QdUhuPD8sSTSZdlHlv7MDurE8IXDxabIkcSsftG7DNjsK/pLKaNvou46P/UdH8qJ+e4zGR/4iXQq9qLX4zOqa4vLpWtkmX5vm8xkWq6xuzCGFFx8qyr/AHaZa3m2OVPO3Kqbn/vVZsd7Sj5FdP7rfLX81yjKOnKfeSx3tNWaulr9nUInzOzfMzfN8v8ADW7Y2Z8tvORhHG+Ubfu3NWPpbosPmfaVSX/nm33mrVhlhWZIXdnaF/m/u7mrz5VJc5pDFc0OU2NJ/eSPD0kj2s/nfdbdW3ZhLhSnkskrJ/C/yrXN2t5NbqqeRnc25KvQ3Enk/wDHyzOrf7tc1an+95ztw/NKUpHQ2t1DfR7POjO776t95dta0V1bLttprbY+/wDi+X+GuQhv3kki2W23b/D935q1rPVnXKeSr7flTc/3a4pU5R96J2U/dmdZa3EMm2EfIkn8LN93/arVha2mbfB86Rpt/vNXEQ6skLM5nz/e+Tc3/fNatrqrq6PCvC7V/wCA04xjz3Nub+Y6eP5W8l5lSNd22SRPmr5P/b08eJeeJtN8Bo64s9t5dMqfNu/hr6N1PxImnWtzc3l8qMsTOjeV8q7a+CPi14wvPGHjTVPE80zN9sum+9/Cq/Kq/wC7X1PD2F9pi/ay+yfJ8V476vgY0o/bOS0zXivia4tTMsSXFuybmrB8XXDyQvbPyY1VXqt4ovvsGqJeed8v+zS6pqkOoW/2x/n85fmWvveX7R+bfCeeTagNPuHhuV4V22qvy0y7g/tC18n5drL95al8WadHuldNqLv+T/arG0+8df3U3y7flSnyoJSmZ91b3Vju7IzUySR5t0iu3zVrapb/AGq1Ox/m+98tYTxPA59KZcfhCQFAy4pkkibeKmUrIQ/zH/eqOeFFb/4mlKRUfMj2+Znf96mEsrfPT2++dn3aVm3R/PSiaDaayuzdKdRTlsAVI0e0Js/76qOpZJNyqXTBWmRLcuaev7tn37tv8NXPMRcbIcr/ABJVKzkTydhT5qtbXWQhH+7U/EZEU3ys3/jtMkkTbsd2U/3aWRnZt9MZtzY/i/vVJoPjk4VE/wDQadBDCytUaSPH0f7tSec/lDZ/wKr9DOXxWI7jasZduKz2bdVm+csMN8v+zVU8nJpfEa0x8B2zIR/ersLe3jkt1fZj5a40NtdXP8NdnpM7tZxuk27cn3WqiaxUurfcuU/76rNktvvbINxrormF1j8x4dtZdwr7jsTbQY/D8RlPFhdjorfN8tFvGi3cfyN8sg+X8aszxupV5KW1j3XScY+cfN+NTD40ax+KJ9JfCWLzvE0g2glbNmGexDJXtngnTdHurTzvJ8+4+8n8Pl1498CtMh1fxwbCaaRA9nJzGDk4K8cV7vpek22jr9mhsJJW8rduk/8AQd1fT+JdFz4l5v7kf1O3jNSeeNL+WP6nG+NNWudD8TK9htgeP50ZW+7UX7QXx88c/G7R9K8JeJNQ2aJosCtFpMf+rmmX700n95qm+I2ivDCmq6lZsjXDN95a8/1q+SNEhs0xu+8tfn1Oh7tuY+apxieeeMYbOC1mv0tlTy03LtTbXhV3I01y8rvuLOx3ete0/FRrm18Pzb5vmk++u+vFXh8v79ejh48sD1MPyqmMeNVUU5Y3kpT3/wBn1qW3hkZg4XH/ALNW50czIfJcsqdmr0T4N/B288c3wuZoG+zQt87Mv3v9ms74a/DnUvHnia20Szs5nWSXdLJGvyrH/E1fZPwl+Ct/4g1C2+HXw309tkcscVxIq7m2/wB5dv3mqJc8o8sTixmJlTPFtH0WY+JV0DS12Osrwwhf4cAgY/AVpyaC/wBs+wQphY5djybtzbt3zVNqVjP8P/jHqeipG7S6VrV3aAN13I7x8/j1rvPhb8NfEPjTWls9N02RUZ133TfKq/7Vfb8exbzPC3/58x/OR7fGE7Ymg/8Ap3H82fWHw3+MGr/Cf/gkV4n+EWiPImo/ELxbDoNu3mrujsdvmXci/wCztVV/4FXgkmk21jpfkQosKxoqReWn8K16l8Yv7B0HRfDHw90FGeHw7psn2i4ZN32i6k+9J/7LXmlxHea5J5Lwsfn+793c1fCxj7aXunyXtOj2Oe/sWa+vH2Rs7SOq13Xhv4d6b4Y0X/hJPEkPks3+q8z+9/eauk+Hfwvs7GxfxFre63iX5bdf92uI+O3xYeZn8N6U6ru3L8v/AI9SrYiGFpcsfiFLlfoeY/G7xRbeNbySwhtvOto/nRtn/oNeMXepal8P/FCf2DN+8VN6/wC7XqVtZ+Zdfafmyy7d22uB+ImivbeIFv4Yd0MybUZUryXbEfxXzHVRrTp+9E9A8Ef8FFL34deFB4T+IWialftBuns1s7jy087btXc1eU/F39s74qftEfZNH8Q3MdlpVr8q6fZ7l+0N/elb+KuS+IGjpfafIYYW3x/Mm7+L/drzuKZ7O4278ba2wOVZZSl7SnC0j2o47FV6XK5Hp63ST+X8jH/aVPlrOu7NGhbenzVj6Hrk2353bDfLurbjuEmVoe33t1ezzHJLnjMwrpHt18l0Vv4kqObZCqbN2xv7tauoQoI9jzK1ZskTzfufL2Mr05cw46+8SwyTTR/ZZk+RvlrLm32dw8LzqSrbd3+zVlg8dwvnP8qvTtUt3vrfzgi+ZD/49RLYuJY8Lsi3W90Vfnr6G8LyF/BdtdfaWXzF3NGyfdavnDw3cP8AbI32fM3y7a+gNDuPL8DrM77vL+aKOiMuUyqRNK8hfULGVHdf3a7vu/erxz48SeXpNtbb9n7/AHNDXpEfiZ1swn8Uibty14z8ZtYvNQ1KKOb7iuzJSkTh4+8clHeTNGUd6jeT5tjimUcEU+ZHVyj1uHij2B6tQ3DyR/PNtT/ZqgnT8ae0n8H92mPlRqNqT/cT5Ydv3UpYbh5dqI/Dfw/xVmL8x+T71XrGaaOT9zB5jt/d/vVmZcp0kMem6bai8vHYn+Ff4mrU0nx1c3Hmw6Ho6qq/KzVyM8bQnfrV5h1/5Yq25qkh8VawLF9K0+b7Nat/rY4/4qv4Q+I91+A0Yj8WXL6jqCPfy6Zue2T/AJYrvTg++cVh/HHXXt/iDd6fPKGhTyHWEHHzeWvzEfxH0qn+yRc/aPGuofKR/wASo9Wz/wAtUrO/aJuTD8Wb5ZSSvlQbVH/XJa/esx/5R1wf/YY/yqny9D3eKqlv+ff/AMiVtN1h7q+dEfmT7m2teRdM0/Y+sa22xvvQwpuZa4BNTuVYeS8n7z5UWNNzV2GhN4V8Fwxa348hW/vJP9RoO/5Vb+9M3/stfgnwn0nKdT4V0nXNWVbnRNN+zWnmqn9palcbV/3lru9QvvhL8OWhsNV8VTa1rC7nuFX93bW6/wB1V/5aV4Z4i+Kni3xhqUc1/eYtrd1+xWMPyxW6r91VWucvtW1K4vnuby8Z5JG3M1TzTK+L4j6Ttf2gPBlvM8NtDH9nVtzRr95mqpeftYaPobF9N8N28rN/FJ81fOMV1NHGXR/mZqfZ2d5qcyOkMjFv4tlPlnLSTDlge2a9+2J4zuFkttKna2ST7qx/L/wGuKvvjp8Rdel8l9VmXd9/a/8A47TvBPwJ8eeM7yOz03RJi0m3b8tfVX7OP/BL3xP4mmiv/GHl6dbrKrS+d825f4ttX7G3vSMZVqdOXuxPl/w3ovxL+IV4mlWEN5dmR8bY9zbt1fT/AOz3/wAErfjT8UmS/wBe0G60+2Xb5v2qJtzV95/CH9mn4A/sl+C7nxtr39l29tZ2++W81DbHI3zfeXdXzR+2J/wWcS1hvPAf7Mz/AGOKbdFPqDP5nmf7UdPmpQ+Eziqlb3r2PSNL/Y1/Za/Zjmtn+J2safearJb7otNWVWf733Wb+Gu+1DxBptz4dGieGLaz0eyuPnij0uL70bL91m/ir8vfhz8RPEniz4gXPxC8c6zcX97N8zzXUrSV7637TmurYwWF5NcIlrFtikVvlqOeqR7H3j66h8C/CLSdF/t7xV4qhT+9Dt3St/wKuV8TftGfATwbGqeG4bq7m3Km5tv/AH1/u18TfFr9qLW9QkktrC8z8m2KRm/9lriLTx1r/izUUS8vGPmfNub+9WX7+UjX2ceU+6W/ae+D+pXDi5sby2+8qQ/u/wB5/F8tT+IP2kv2b9Q0V7BNHuogsS+erRLu/wCA/wB75q+OLfT3vm/5aY2/eVq1LzS7Dw7pZuZnj+5tTzG/irSPtYxu2TyxlLlParz9prwGut3Fn4S8PXltpa7likvPldv+A0SftLeG4Y4U8P6bI08LbZZpot3+Vr5tbWP7YvfK0qb/AGd396uu8I/DfxJ4gmhtv3mxm+f5fvbv9qj2cpe9zBLkp7Ht3/C/NS1SP7NZwqhXdujjX/Wbmrb8J6h428TNLbWELLNIu7dJuZY/mqP4b/s8/wBm2o+2WGx1VXdt3zKte/eA9D8N6XZ/ZrCK3RPKj/0hvvbq0jTjTj8RjKp7TZHK/D74N6xfRvretv5SrKqvJJ8zSf3tteAf8FQP2rH0BF/Y9+EFwsE+pLHP4tvrMfvbW3/ht/8Aeb7zV9HftT/tJaD8Afg5qfxOv9YjFxapt0uxhg/4+rhvljjX/wBmr8y/gDoesfFT41ReKvHN3NPqGsa3HcapN/tSSfd/3V3baiHJJl06Ps480j+mr/g3e/ZS079mT/gnd4cvX07ydT8XSNql67Jhmj+7CP8Avn5vxr7xJJxivNv2VLCw8N/ALwl4Ys0VItP0G3gVV/2Y1r0czIg5Iq6/P7R3OrCypqgrGB8V/EkXgv4YeIfFrTGL+z9GuLhZF/hZY2K/+PYrlv2bNJbw9+z94UtboiOeTRI7q63f89Jv3jN/301cf/wUo+IEvgL9hP4p+KNL2yT2Pg+4kVN3b7v+Nfl/4x/bz/bj+LXgHQfDHgvWo9C0pdLtUWTS7r9+sfkqqr/wKvDzipKnhlG3xHqZfTp4uq489rH6++L/AI4fCD4fQed4y+IelWH9wTXqqWr5H/ab/wCC8f7JnwW1tvBPge3vvFerb2SRbCL9xCy/3mr83b74O+MPEFx9v+Mfxa1Ca3j3NLa3F4zN5lcnpvjL9lH4WyXmqzeA7rxPrH2j59ytGi/3v+BV8nbFv3ZSivRa/efR4fA5fTleSlL8EfT/AMSv+CkfxQ/aHujqd9oMWj6ZLu+y2MB+Zv7tcJ4q+NU0Ph17a20RdQupJVVI5vvK397/AL6r5v8AHX7X3jnXNYiTwT8K7PSLWR1gih+88bfdVv8AvmvR/BvjK/8ADHhW+1fxVNaw6qsELW8c3z7Y2/iqI4aMNj1YYmFT93E8m/bi8Z+NPEnwD8V2/iexCqJ9PdW8vCoftEfCmvDPgH+1949+B37NmsfC/wAE+K0gTU/FDX2oaVM2EmU28USv7H5XGfaum/ae+Md34y8EeMfCsWuPcx/bLO6kVpMgAzIAB+OK579lz9j5/wBpL4R6n4g0WHGp6drkkHmtOI4/JMEbYYntlj+dfquAp05+E+IXT6wvypnpqc4YVyjvc4v4V+AfiF+2H8cND+D/AIJ0uSTWfFWrrZ6dbx/6tpG+80jfwqq/Mzf7Nfc3xt/4Ia/sqfs1W1tofxy/an8Z6/rht1/tGx8CeGYXt7Fv4l3M26Ta3y7q8L/Y58F/EX9gf9rCy+LniW5s3t9N0PUks7i1lWRrW4khZYm2/wATVg/G79urxh8UPHlv48v/ABJeRXK2EcXzXG1VZfvf725vvV+dVMRLDw9lSicmFwlGo/rGJl/26eveDf8Agkf/AME7/ihfSWdr/wAFIPEGjXLf8uGteDYVkj3fw/e+9Xv3x/8A23PhX4B8I3H7IfhLUY9S8PfDHS9P0nRrf7KscFxGsf7yby/7zN81fmlffHXXtU8VHWIbySKVXVk2vtVmrnfi98T7/wAWeKpPFT7ft91EsV7Ju/1m1fl3VwVauMxMeSe39bnpRrZPhoynR+L+9+h2P7UniP4dX2ty634P0S102aZmaWOzTavzfw7fu145H4mv5FdIZmT5Nq7X+ZqZBp+q6/MkMwVG3bvmWun8O/AH4keKLdrzSjDhf73y/wAVdVGCcOWe58xisyxFSrJr4TN0DwL428XRm5mgmWz3KnnSfdWvZvhD+yPZSQ/29qWsLcRRxfvYV+7XH6b8FfijouoReF9W8eQ6b5jb/LZtyt/davp/9g39ieT9pDxlrHw81/8AaJ1jTbyzg2pdaWq+X5jL8u7/AHa48Yq0E5c0VEywtOeIqe4pXMf4pTeDPh78P7LRvCVnY+H7aGLZdTNu3TN/e3f71an7Iv7VkOm+NrLxZ401ezi0fw3FvXVFbdtZv9n/AGq+z/hn+yT8BP2F7XTvDnxR17wz431PWtOuk1vUviBZK8FrHu3LcKrN+7ZVVq/LX9tD4wfDH42ftVeM/E/wR0PTdO8HrdLp2jQ6ba+RBcRw/K1wsf8AtNu21xZLhY5riZ0r/D9o3x+bYzKbSl/4Cd3+0t8dbX9qv47+JvjbY2zJbeJNRzbIwwxijRYEJ9ysYP411/he6TTdNt4baHbFHBsRY/4dteG+BGNvp+ntnlHU8j0evWtBvo/LWZHVdvy+Wv8Aer+y/GeLp8PcMQXTBwX/AJJTPyThuq62PxtR7yqN/e2z0DSd91bxfv1VNm2dVi+9/wACrrNKme3KJbQsqfdTb91a4Dw/rUcToj3Kwr97y67bR9U3KJ02s0ifvWWX5dtfz5Uh15j7anWO20mF2uN7uzbvvrv+X/erbhb7PZjf97b8m7+7XK6XrCTW5SZ9rx/3X/8AQqvHWvM3o9s0SLt2Kz7lkrgqR5z06OI5oaHyx/wU9kEmqeC9wXzBaXvmFfXdDx+Fcr4CBXxP4S2EZ8nR8fXyYK6D/gpZMZtZ8JHywgNvesFU8ctDzWB4BcDxR4SdiMCHR8k8dIYK/sbwL04fnf8A6BMR/wCnInh+IDvw/gWv+f0fymfYOtaL9utVREyrbWZq47XPD6XSbEhVNvys2/dXfPcpCpdHYBvvRsn/AKDWfqGnul19mhmV/lXymVNv/Aa/hLEfHqfomHleNjza78H2ckzOm1m/9l/vU2PQX2+dCkhG/b9z71ejQ+G0a4b9yreZt3yN/DTn8OzxzK9tCy7f9j71ebUxHNLlbO6NE5PRfC9sk3nQo0x/jVovlWuls9F+1W6O8Kqn3dzfK1bGj+G9rK8tzJtX5W+fctdfpvh+GS3+zfZY32vuRpP4fl+7WMq0Y7nZGjLocC3gndCdnlhG+bzPvL/wGs/UPClztaaaFkdf4lT5a9X/ALHh8lfJtlfy0/1a/LVW48NpNH5m+N42f5/LesJ4qXwhUwsYnjV54XdWZEs4Wf8A5ZSN/wCyrVC40mZY/O+zrtb/AMer1XVPDtt9oYpZrhV2vIvzbmrkfEelvbsyI/yL99q1p1uaXKa06Mow5pHD31n5kjQokf7v5pVZPlX/AOKrjtatUDTIkKqG3NL5cW2u/wBXmeNfkfZEr/Muz5mrjPEn2lvMCcCT+Jk+61dtGR1YeXLL3jhNWjtocP8AKzK21Pmb5v8AgNZrRusz5RdjfLub+GtrWEmjtGd4t7N8q7flWueW4eNvLwrfO21lfctdq5pR909ijJe6TfIsbQu6j/a27dtSwzPNGJlhXZGnzSb/ALrVUk86Zf33yovyvt/iq3b72hTYkf3v4auPN1IxUYyjI6nWPD6GOSR4ZE/4Bu3N/drkdY8KwybE+Xe3y7a9U1jTY232yXMiL5u5VVty1zmsaLNGzJ5PmJD837v/ANmrpo1pS+I/MMRh4XPMbjw7DIwdPmCvtl3J/dq3p9vDHCuzaGZ/kZvvMtdJe6fNcSfPudo02y/uttV7ezhhmML2y435Vv4q0+se78Rx/V5Rq+6Q2djIrfuYd4b5ttaVrYzbl3xZDff2v8q1Osfk2YRE2tH83y/xbv71SQTTC3iP2Zn/AIfuUo1OaNkaRp8vxE0eyFvJh2/vG/u/doWeGFgjzfLv3bv7tZredHL5MM7H5/vb/u0XF1++d0dXT+Pb93btrSnG/vKRnKpE3o9WePb5KbP9rzflZaoalrlyoZ5pmZf4d1YP9oTN8kyM8rIq/K/y/wCzReXHksE+0/d+X7tbRjGOhlKpLl+IvtrE94zPNc/L/Cu/duapI9SeRXuXuVTy/uq38Vc62pJHMfLdaZ/aiKrwzeW8W1XSOtJU+aFjm9tOMjS1+6afTHkkuuHceWjYzjPTj0qt4dWPyJJXZsq2cK2O1VNQu2uo/Mk+ZSf3Rxnae/NP0ecQIzO2FLAE+lf0Ll3KvoyY/wD7DY/lRPiKtWUuOKUn/wA+n+cjo7V03rDD5iD/AGfutWlbq6oupJtf5/3UbLtVax7O4T5UTlt+59tXobuGT97M7Mu9V/drX8x1pScuaB+g05c250+nybpo7bZmVvl2yf8AoW6rsl0izeS8y7t+5a5i31J/tY8mZpW2MvzfKtX5tQ+b92JMr/Dt3V5Fbn9vfl0PXockom7DqbuvneUsbL8vzPUjXH2hUhS5VG2fvfMf5mWuZk1DzJgn34mb5tr7WWrf2uZm/fHesf8A49WXLKUeY9WnW5fdR09vq1tDDCnzSv8A3v73+1Vqx1yGF9+3fu+Xb/e/2q5mPUNscSfcb+Bt/wAq/wB6pLfWkh/c3LeUG2sjf7X/AAGsvYz6fCdkal+p1La5MvyWcMar97zFb5lq1p2tPGxdJlIaL5mb5q5CO68yb94+8MvzMvyrVqPU/JuAiJ/B/DW6p82xPPJSJPjZ48fQfAN5cw3jRyyQeUjR/M3zV8ba1dPDI3zs6fe+b71eyftCeNJtQ1pPD0L+Xb28W6Xb97/erxnVmSRm7qu7/eZf9qvvcjw/1fC80vtH5pxLjPreO5Y7ROV8WxfaLUps37l+7XL6PrG1WsJpGUfd2/3a6fXl3bvvSr5W3d93bXB+II5re8a4hfn+Nq9qPvHgU/dLOtTPeMYX4rlry3eCb5NzCt21vE1OFU+ZHX+L+9VPVrGby2RH3bv++qJRK5jOtb5PMELvn/ZqXULdLpQ9siq3+zWTMtzDN8/B/u1JZX3ks25+v96n8I+Ujkjlt5Chb/ep67Jo/k+Vlq5JAl8u9HX7lZskb28uxuq1PxFD5YRGdlRP941PGyTw/OPmWoGV0f5/lquUcdxKKPM3miqHEZH98fWp5uenaogu1lqSbe0vtU8oSLthGY5E2bfm+/VyRdqnZ1/8das+zDsv3K0RvZN833f7tTAkgmkfazyJ81VfM+b5Eqe+Xg/O2P7rPUKqnlr8n/fVP+8T8Q9XT7mz7tO8xF3b3/3FqCPYs33/AOCpJmhxvzupBIq3Tb2AFRs3lr70s33/AMKj++tVEuPwjq6/wvIn9nxI6L9z7zVx6tng11fhNkbTxGj/AD/7VPmQVDTmm8xm+f5W+WqM0O9mx8o+7V2ZUjn+cbttVJ283bsfdt3VEvd0MfckUJLdGZ977t1JbRut4nyN98fzqaRtrf8As1T6ZB9sv4oN+wvIgVv95q0pfGg6o+m/2YI1k+I8obOBpcpIH+8le7ahqFtpqvO6bkZf4n3bv92vBP2b5pIfHs5hGWbS5QBnGfnjr0rx1qFzp+n4d2aaZ9m5f+WdfTeJPP8A6yO38kf1PR4zUv7cuv5Y/qcx8QPFd5rmoNDCGeGH5UaR/wD2WuXj0lLe3kv7zb/sLI/3q1LuZLdZPtL7XZv7tLpPgXXPF06fuZsMm5F/havhqNGfxnzManK/ePEPjY0flpZzJsaaXdtX+Fa8v1S3RVOz5dz16J+0Fb/Z/iZPoltqHm/YYI4n2/dWTb81cBdWN5NHvO12X+Fa7acZ8p6dP4TLVC1bHh3QbzW76GzsIZHlmbZEv95v7q1WsdLm8wI6srN935K+3/8AgnD+yXc6t/xe/wAVWCtBb3HlaNayRbt0n/PauiNHmM8ViPYxNb9lX9kPxJpOj2Gj2FhJLruqSx/aFX5tsf8Azz/+Kr9Y/gr+w/8AD39kP4Hv4w8YQxjV7iJn3Kv+rbb5jKrf7Ndl/wAE8/2EbbwTpP8Awuj4tWH2e5uEZ7CG8i2tHHt+X/vqvKf+ClX7VGpfErxTD8M/B83/ABLbOKSLdZsqrG33W/76rSty4aF18R89KpLEe9M/JS0Sy8Y/tl6s81uJrfUPGGqSGOU5yrSTtz+HNfVMNimk6f8A2bpWnw28LQKrtGqru2/7VfKfwtjSL9rkQyP8q+INQUlhnIxMK+jvGWu/aLk6bo9/J+8Tc7MnyrX1fH0HPH4V/wDTmP5yPuuMIc2Jof8AXuP5s5mTztQvG86G4eWTdG7fe+XdXe/Db4XQ/LrGtpsiX5YFkb5v++ag+H/g95JDdXW4tG23a3y/98/3lrX+Injaz8H6S3kzK8zRfIsf3lr4GtiKWCpXPj5HP/tJfEKw8N6Xb6DpVy0czPslWOvmy8mudWmk85GLt87SV1PjjxZdeJtUl1K8uZmaSX7rfdjrmZI/Mk3o7Im7c0a187UxH1iXNIfLKUYjJv8AiUaZ9tf5RIm1G/hb+9XnfjDXofOaHY2f4FV63/iF4wSONNK0xJHZvlVd3yrXn2tMgZnfd5zfNt31dGPc2h8Jk3Fv9omdHfc0m75WauA8f6C+lap5qJ8kn8K/wtXokXlfbPOm3KP4KwfFN1balDNbOmdyfI392vUw8pQkd9GXL7xwVjdvbtt/u1u2OqeYvk9f4t2+ubuI/s0rIf4Xq3Y3H8G/5q9T7B2HTS3UMm6P7zfxKtQNI7bd45+9uWqv2p+qOm9U+9sq1a/Kiu7qz/7taGcfdI2je4+R0Yf3Goh85vvnd2b/AHatNH8v3+Vf+GmyWe24M29g3+zU6/COUupX02zex1hYU5DfNFXt+j3nkfD1Hf5tu1d2z/ZryabSfOs4r9FZnt/l3L97bXpNrJD/AMK/aOZFO2Vdjf3Wp++RIxrq+nt4dk33dleVfECZ5tdKb/urXoeqXyfvXmfcN/y7v4a8u8QXD3Ws3Ervu+fbuqDSiUqKKRW3VXxGwKuBS0UVQEixovLvj/ZWp01C52/Z7PdGrdlqv5nyu5OT/tUsd1Mq/JS+IXKiUWN5LJvdG/66NUjLDCpS5mY/7MdV5Ly5k+/MzD+7UTEs27NL+6LlPZv2QLqOTx1qUEMeAukkk+p82OsL9peWeT40X1tGMjy7f/0Stav7GuD481Mgf8wg5P8A21jqj+0pPHD8W9RCLhjDb7n/AO2S1+/Zj/yjtg/+wx/lVPlqMY/62VF/07/+ROVtZodFhZ4Zle62/NJ/zz/3azZb17iQzTTbnb5nZn+9ULTOw+/wtJGySfI7t833K/n+Z9J7/wBo3NJ+aze8mh2hvlWo7WxudSvFhh+Z5H+7VqSFI9Hhtkmw/wDGtemfs5+DNEuvEkd/4kSNIIfndpH2rtpxiI2PgH+xf8Rfi9fCbTfDdw9uv+tm8ptq/wC01fQS/sy/s5fAmGG28f8AxCsbrUlVfNsbfayxt/dZq439oD9ve/8ACPgd/h18H5o9JjuNySyWLsrNDt+VWr5Ik8ba9rWpPqV5qUjzyP8APMzM26iVSUo+6RKnzbn6QfD/AOOnwD+HccM2m2sN1cNLul27dqrWp4u/4Kg+Hvh3o7zeGNNjiuG3M9rIisq/3a/OJvG1xptiYYbmRX+8+2uY1nX7y/kV5ppC/wDe3/w1lKM6m8hxpwUT239p79ub4tftEapN/wAJV4wvrm281l+zyS7UVf4V2rXj+lpc310vy4rIhh85tgG5mrqPDem+TMjTIyhvlrSMYxH7kT07wO1rZ6Rv37Sv3/l+9TvEHiy/WMw280ixfd3bvl21V0Ev5K20L79v3Nv8NXrHwjqWs3z2yQsxk+9troMvf5zC03RNS1S63+W0hZ/k3fNXrXgn4bPb26zXW0Ns3bv7tdR8Kf2f7mGz/t7VbPEUarsZnrttc0fStH02TY8YMabVXZU80Sebm+E4q3hs9JhFy8O5I13M275mb/Zry/x54ov/ABVrn2LTd3l72/d10fxK8XfaJ/sdttHzbdsbVT+H+g6Da3D63r1zHiT5kj+981R7TmJjRnH3j0P9nv4Pw+IFhl1VIbdYf3sv2ivprwfpfgDwjpkUO+H7Zubzd3/jtfJN58eLDw+zw2dyscX3d3+z/drB1T9pPWLqRUfWG8hX3bt+1qy9p9k19jzR94/QlfGHhtpt6bYopPlRfN+78v3v92sDxR8RNK05nubDVWJhZWRVl+Vfl+9X5/ah+1Vrdu++01iZjGn/AD1rDvP2ovG2oRyo+pSbG3ebt+61KPNLRkxo8p1n7aXxO1P4v/Fa08Hw6q0+n6H+/ljVm8triT/4la6j9j+xs9N+I2lX/kfNDqVvuVl3fLu+Zq8K8Bs+uTS6rcurzTTtK+6vdfgq32HUkvLP5XhljZNrbdzLXNUqezqxOfEfyn9Mf7Jf7RVhqfw70izvblnaO1VfO3feXbXs998bfDdnapczPuVuFVW+Zq/Jz9jP48Xn/CL2r/bNm2Jf3ay/dWvpi1+Jl5qkYs/t7NF5XySL8u6vbpyhUhdxPM5p0/d5juf+CiPxPs/ij+xx8XPBPh6xk2XHgHUAkjJ96ZY933v+A1+SnwB+OtnN8G9A1u5v4UH9g26SqrbpGZV2/NX6Z3lm/irw/rfhjUrzzINU0a6snVn3LJ50LLu2/wDAq/AL4b/ELxD4V0PUvhdqUzQ3fhnXrzS7qNfl3LHMyrXzvEcebDKUV8J9Fw7WjSqyPr34gfHrSrnzoYbnfu+fzG+9/vV4n4u+JFtq081zZ7Ymkl/4E1ebar4qvL682fatm5dyfPXO33iS4t7r7T/aSokKbdqpur4WVacj7KnjIy0Pa/C98+rXiarretxxtHu+98q7a4342fHy51LxE9homqsbaO3WBfm+9XmmqfELXplWztr+OFG+/wD3q53Ut8zM9y7Ft3ztv+9WtOVWUbSIljIxj7hvWWqzS+FvF8dysb/arO0dZl/vLdR5UfhXp37M/wAXZvAPwS1TRkmkCyeIHuBGkm0E+REDn24rwKWS43OVkePKhJlLN+8AOQGz6EA1r+GvFC6NpsthISVllyVP3egH9K/V8JF/8QnxNv8AoIX5Uz3MrxlOOWSqVOjt89D0Xxl8WPE/iyTY9/MUVfk8yX+H+7XP2/gPwTrvgXWNV1LWLqHXbV45dIt7fb5ci/8ALRZN3/AaxLrxJZyR7Em2Kv3lX7zVLot1bXEciTTf6z5kWP8A+Kr80+DVyF7alWlrK5w2pXlzY3DGF/49u1vvbqfpcmpahJ5E1nvf73y/xNXT+NPh/o6TLeaPqXnSsm+eFv4WrL0fXE8O3EdzNb7drr95K6ZKlOHu+8ePUUva8sixcW+uaTb/AGx9BvNv/PRbdm2/8BroPDf7Qn/CO2/9lfb5Eb+7cIy17T+zz8fvDf8Ab1tD4h0e3lRn8po5ol/eLXvWvSfsZ6feRXfjz4XaTqVtJ8zqsSxNG38O1lrzY1MJU9ypeMkbU8PWTvB80T458NzeLfjlrlrB4EeTU9RkfZFb2aM7f981+mH/AATC/wCCdH/BQH4RTXHxG1n4J6e9tqEvm2q3mvQwSs395v8AZr2//gln8Uv2Z/Dnjy3+Hvw7+Hnh3RzfJJcNeWtnD5/lqv8AFI3zfer7rn+Knhu1uv7Nt4Y2j3fLJCqqq1yYh4Tlt0PbwuGxeElzw3Pxn/4OCfhD+0l8HPAXgnx18XfFuiyv48164sL7R9DRvKsYYYd0cPm/xN/6FX5h6LCkLGCBNkW9dsa/w1+qP/Bzr+2J4P8AiX4q+H37HPhKaO4ufCt7J4h8UNCys1vI0flxQt/tMvzV+VOn3kDats+XEn8Sr/47X2mQYOhhMDH2ceW+vqfnud1KtTMJqcuY9Z8IFoPD1q5kyVDHcf8AeNdL4d8XJt+Tcu1PvM3ys1cnoLbfBiOvy4tpCMdvvVg+GfGGI03vIXV/vL/Ctf0t42f8k9w1/wBgcP8A0imfFcN+7icWv77/ADZ9D6L4qh3JM7rtW32/Mm7/AIFXW6f4je1jim+0qr7N21V+Vf7teC6F4kW6ukRJvmXb8rPXbaP4zm8lk89ty/K+6v56jzH18ZSjI9nsfEEK7/K3BpF3SsrbVZq1Ydaht7d3+2yZj/1UMku5a8m8N+Kke3MM3yf9NP4Wro7fWU+T99nci1jKP2jrw9Y8f/4KAXc1zqnhdJXJK292Tu65LRE1T8BlW1/wqSDjyNJBA/65Q1F+3BeS3t/4bknYF/JutwHbmKm+Bph/afhqVicLBpucdeIov8K/r/wOu8gnf/oFxH/pyJx8dv8A4xzAf9fl/wC3n2N9umkPnTR/6v5fJjb+H/ZqxHNbSJ9p86RXZP4vmb/ermLHWLZWaGF8eX97bL/F/dq3puuIxmSGePdv+6z/AMX+9X8LYr4ffPu8LUktYnV2dun2MpDN975v96r0drNHh/8AWN8qvCzfKtY1jrCWqql593Z87L83zVr2uoJ+5SEs4m+avArU5c3Nyn0GHrcxu6bY2s376G2U7v8AerZ0+3uY4/kRfmZm3Sfwt/tVz0OrJtTyY2Df3d/y1oQ68ftCW0MyhmVme33/APs1edKUpT5ZHf7TmNponWYXMKfw/L/dVqq3y7d0yBRuT+7tqtNriQsyI6l2+6q/NtrP1LXra1jaa5uWjLPtZpH/AO+ajl5dipVOb3WQaps+xzXmyRPMXY6r/FXH65I80LW38CxK1a+s3FzcK6edI48pXdfN/irmb7UnTd5z4b/lkyv/AOhV0xjL3blxl9k5fxNskmWHEjFv4m/vVxXiSxmaGR5pm/d/M7V32pRzGbenzv8Awf8AxVcR4mkheN4fJ+bd83zfer1aP73YxjPlmed+IWeTfsdk3fMi/erCkt5oQ8I/hTdu2fLurqdbgSW6XYjQqqbf726se7jjj/dwptP8fl1304np08Ry6lGO3ePdPN5hP+1/FWhp+n+cf9Svy/3W+7/tU1ZHhhDpbMqf7XzK1aOkx+W0Pz7Ipk+dtvySf8CrT3/iLrYmPK0ehyQpDiFJ1lZv+WjVkahDJIz2z7mbbu8zZXSXVi4kaP7ife3Vk6javJbu9yGO37m1vu1Puxl7p8TU945i4017hVd5ss3/ACzX5vlqhFp80amYOreZ/d+8tbC21wrIlzNMsW/5ZNvzMtFro8LXUPk2EmJEYsu/5l/3lrblhGXvHPKPu3iUrOzmuI/kRdyv+93fNVn+zXkhim3r/tL92tqx0F7eOV0fczN83lptVatr4fhupjvhj+X7zNL5arWfNF/CZ1KMonJXGlpGsn7lt7f8t9/y7qwbzT3hhj+TO1W2L/C1d/qGgwxnzkhkYsjf6lvlauU1SzeNW3uwPzN8z/NXbT5Yw0OCpHl+I5G8meFl87ai7tvy/wAO2qWpai6r+5fP8Kbm/hqzqxtrdpZpkkbcn+9XN6lqU0LMmxS38G77tdVOMpSizya1Tl90u/bkTa6Tcr827f8Aeok1KFwdgZpNv3lrnm1rbv2JtT7u3ZV+3uplm2O+dybt23+H+7XdKny+8c/NKRsWl28kQgdCqj/VgdhVqC6jtS0krYUDLVm2BkaRZIw4iYnKN/C2KvJYi7lUlugO1W6Zr9+y6MZfRpx6f/QbH8qJ8jWUpca0l/07/WRr2czzKLi5k2ovyqu/buX+9Wwt08d0mzd5W/cjf3vlrMsFudvnPDHt/hjjT7q1sWtjuT5H3bU3I0fzV/LeKly+6foGH96RYt28uTfvVXaL7rfdqVY5nw7sv/Afm3UzT4fMhG9N+5/u7as7fM2ukSxL93arferz4zk4+4evH3YxIZLeaG23wuqP/D/8VU9nMjfcm+VU+7t2ruqOSFGZ8bY/L3Kys3zU+O1eG3R4Jmx/CsnzVnOpKUeXsddOpKPukkk1z5fnfK38SfPu/wC+altdQeZok8llH39rfdX/AIDVJv8AR/uGRW+78v3aktN+5JvOZ1X5n3U5R5oRidsa0Yw0Nu1ZJIHmfc779yqv8LVNdTPZWr3L3iqscTO+5vutWct4iN8jsrt9/wCb5awvit4ki0nRf7KhlVfORv8AarvwuG9tOMInPjMZGhh5TZ5H8Rtch1jXr/VbmFv3ifeb+KvN77U0t5HeOZh/wKug8WTOyvCnzhXbZIz155qV27zfPMu7+9X3tKnGNLlifl9SftKspvcsXl8kjN97f/ErfdrC1GBLrzf4f9r+61WJLiOWTYj7TGu5vnpbbZ5bb3+Zn+et+Uy905O6t7mxvv3L8VLHrSFvJueT/s10OqaRCIjN5PLf981w99cJb30uw7Srf3Kf2xx94u6lZ2d0wmSH52/u/wAVYl1ayRSN+62ha1LPVkb/AFwXK/8AjtWJrOG8X5H+9S+Iv4TAguZrb5B0qzMhvl87K/8As1Wb7RXVS6P937/yVmKzwyfI9SX8QEPC2M0rzeau1k+b1q3iHUYgVYCXbjb61UnheFyjjGKAGP8AeNNZc8inM26kDbuaCxY8M3BpWUk0xV20taAWbNvm9a0LdnX5HdiGSs23JUj7taKNut8+1TExkR3Mj/3FP+1UBaRvl7L/ABVNJGit9/H+zsqpIwXOx8fw/NUylze6LlJGbZ9yRc/7VNaSMKyMn3fuUyFk3Mjpmh5E/wDsafLAshk+b59lJRRT+yVEK6jwWvmaeyINzb65ZjgcV0ngn99avbf7dHMKp8Ju3S+XH+5kX5qoXUOz58/wfw1f1NUt4RMm77+3bsqhNJ5a56Fv4aOYwkU/mTf8/wDH8610nwl0U+IPH2k6dKimNtRiDMy/dXO6uekjTPnfMzV6X+y9o8OofEa1R3kUQwSXLqv8W0fL/wCPVUJe8hSjoj0/9nG4S28ezSuBgaZL1/30P9K9F8dS/wBoXgtZplZl+fdI/wB2vMfgOdvjOUhAxOnyBQWxklkFdrFa6l4w8TJbpNuhX5W8v5t1fV+IkOfiZr+5H9T0+M5yhnl/7q/U0vh98MbnxxrkT226WFpdirsZt3+1/u19z/s6/sGQzfDrVvG3ir9zpOk6RdX97cbPljjjjaRl3f3dq1l/8E/f2T7/AMc65YWSabdbbiVfNXbt8uOvt7/grJLoP7JX/BIv4sa94ema3uLjwvHpETfdfzrpvJXb/wABZq8Cnh40cLc+Ji/rGMij+YXxTrieKvFOq+II5mcX2qXE8TM3/LNpG2/+O7az447lZFROn8e2tDRtHc2kJfadsSj/AIDVzyYYZhvTAZtu5UrjPpOax0nwO+FOt/FLxpp3gbRLCR7zVrqO1s1VfvSSNtWv6Vv2Cv8Agm/o2l6ToNz4q0G1i03wvpNvb/LB+6uLhV/eSKv+9X5gf8G0n7LuifHr9ubTdW8T2DXGmeE9Jm1eRSn7tpF+WNW/4E1f0FfGTxbZ+E/C1xoHhu2S3gVPnEPy+Z/srXZRlGMTw8dUnWq/3T54/bo+Pb+EfCt54S8K3i2Nrs2O0a7dyqu3atflx451FF1K8eZ2xJcb13Pub5q+tv2yPFmpalIIba6keJX3urL/AHvvV8e+MLOa91eW8to12N95l/irmrR9pK8jGPwHxF4KkmH7U8skSEufEN/hQcHnzq+nPDPh+FZPOd5LmX5l+5u+avnb4M6Hd6/+2fBoNuN0tx4mv4wG5z/rs/1r7X8VeHbD4WW8Vg8i/aZGZYo2+Zlb+GvsPEKpToYvDTl/z6j+cj7PjGaWLoL/AKdx/NnHa1rEPg21aa8hX7Wy7V+f5tv93bXi3jrxRqWtXz3N5c7Vb5YoV/hr0bxc1zqkNw80yy3Ejs3nbflVf7v+9Xm3iTTLaz817m527drbl/ir8ixEp4iXNL4T5GUub4Tlr6B5F+d9v8O1v4v9quP8VeKplY2um7vOj3Ltj+6tanirxEl9eSW2lbtv3Wk+7XH3zfwI8jM39771cVP+V7GtOUY+7IxL2Z1und9zuyfd/u1i34hVS8m12/8AHl/2q3dUO6MpHbMi7Pnk/vVw/jzX7DRbR4LV8St95q9ShGTkdNOM6numZrviiHT4zsmV/wDarkdT8Tzy5Sz3Yz95qzb/AFO41KYySucfwioGbHAr2adGMdz06dFQBmeRmd+TUkb7T1x/tUyiujlNJGzp90ixhB83+9WhCzyQ/OjVz1jII5F2PXR6apvFxv5X+GjlJLUSurbN+7+7WnFbySKr/eP95v4abp+mpJIvyZK/Mm5K2JLTylSaF12su1lp83umEvi94NBtUuIZbJ9r+YjLuj/hrbktXs/AL2dz5mY5V+7975azvBskK6x9mfam5f4vu7q6bxt9mbwjLeQou+SX5tr/AHaUSJHmPiTUEjsZXd9rf3a4CR98pYPXSeMNRSWHy0f733q5kA5y1SdNP4QYZHFCrtpaKDUKKRjgcUtABRRRVcoBSx4ZuDQse5fnpvLD0px2JkeyfsdSRnxvqUarhhpJLf8Af1Kw/wBp1yPjDqcZ6NBb/wDopa1/2Njnx/qY/wCoOf8A0bHWH+1F/wAlm1H/AK4W/wD6KWv3zMP+UdsH/wBhj/KqfL0Uv9bKn/Xv/wCROCjJ3bO/97dViGRI7pRlflqnvb1pyzOufnr8APp5R5jcm1h2mX/Z+Wr8XxA1ixh+x2dyybkrklkdP46XznY/O/FHLcOVlq+1e81CZ5bmbe277zVJa3SWyr/eqg2zHFKJpF6NQEomjcajPdF0dlX/AHaS1s/MkEMx/wCBVUgWGVvv4qyt0qL87fKr1fwi5fcNnSdNQRrNsXcu75a6PRZkVULzfL/drhP7Tmjb5Jm+WrGm3ztnzryZh/dV6I7GXLM9b0O+3XS+TeRptb+KvZfhr4j+GngFP7V8beJ7O4mX51hjf71fLbahpVvatNczXS/J8kf2jb81YGo6rFdNnZI7r91ml3VnKMuhXLHqfaXjb9trwFAH03QbxUjVPkX+KvNfGH7V3/CQK/k37YZPur8tfOCXCSf66Hd/eqVms1UukaqzVPs/dCMYnqTfFDRmvPttzf7ht3ff+9TLz4pWdxMn2a/WIN9/a/3v9mvJmvHjkb5F/u1LZv5tyBI+5PvYNXAconca946e8uBDvXZ/dWsi88SeZv8A37L/AA/erCmvvl/h/wCA1H5zsvG35vmpcv8AMTH3TTOqO2U3bX+9SSalNHbsltM29qoRXTld+/8A4FUtrefOyPtamEvdPWvhDG03h+HY671+9/DXtnw5uvs7eZ8x8tN77U3bVrwP4K6k66XJZJMxK3Hyqzfw17X8O7x1vlhTcEmXY38NeXWj7/vHn4iPvH3j+xz4yeSGzhRGkRX2KqrtbdX3B4DkmvLf/TLlURl+Tb97dX5n/st+JEtdQeHzmTd5fyxyt8zK392vu/4S/FxIdNTUrCHe8bbJVk+ZV/2ttelga3u2meVUpyl8J7Z4H0nWP7ehWG5ZIVuP9Yz/AHl/2q/C39tTwRf/AAh/bw+MHgzyfLjbxfJe26r8qtDcfvFr9tPDvxfms9WP9g3MMTzRNvuJPmWFmX+7X5n/APBVj4WprX7WH/C1PO3w654ft4ri8aLb500Py7v97bU5p7KthnA9LKZTp4iKZ8f6lqV/t+dPKKvt3bvvVn3En7l3faHb5h8n3q7u88A6hqFwLDR4GuZmb+5/drnfiN4c1P4YPpcXjvRrrSn12za80Zr61ZPtVurbWkh3feXd/FXxMsvq1I3hE+qlW9nLWRzl5HNbyl9nysm75qps21hvTesK7nZvlVq43xZ8dLPS5Gs9HtWuHX5Xkk+7Xm/iHx94m8RzyNealIsch/1MbbVrswuS16kff91GUsR/Kett470O+17/AIR62mE1w7Nlo23KgUE/e/CtJAv2aaSQjCJlQf71eO/CTP8AwnNtxn93J+HyGvVtVnaGzlEeNxjOM1+u4DBUaPhxWpLb2y/KB66qyXDNSX99f+2mDZ+NJmuPJe2yiy/LI1aVn44RT99UG/btrhfnhuG2eYnz/wATblq9CztJsR/9qvgpZXhqm8T52njK9P4JHotv4mmvF/czNK/8f+zVS4vvtUn2bzvmVv738VYfh/Urm3lVBD8jf8tKs6xZ+TM1zbTYXf8ANWFPJaFOWhpUzKrKPvSOz8AeE/GfizUE0/wFo91qt+254rWz+aT/AIDWlrGofGOxnfw9reg61bXVvLue3urCTfu/75rmPhn8RvEnwv1yw8eeHrySGbTbyOdWV9n3f92vtO+/4KHnxh4Ystes7ya6ubr/AI+rW3gVpJP9ncy/KtevgeFsqzF2m+WR4uP4kzPLbSpRvFmV/wAE7/2grH4L/FF/Fvxd0G80pY9N8pdUvrdoomVm3blZq+m/2rP+C5Hw9+Gfw7vdH+CGt2PirxjfWrf2Db6f+8tdPb/ntPJ/s/wr/er4s+NXxa8f/GrRbjSvEOq2tnbX1vsTTbG33fLu+Vfmr548S/DvWPBeFufD01tabdyt5DKu2ssz8PaGX1Y4hT5oP7J3Zf4iY7MKX1eSSkO1rxh4w8deKNa+JHxE16bWfEXiC6a61bUrpt0k03/sq/7NUY3mh1JXRFCN/C396kjieNW8l42ffu/4DUe7/TEhRFd60jDl92JnKc5z5pHrOmMV8AM7A5FlKSD/AMCryHRdceC7ZN+5d/8AC3zV65pDLL8OywPDWMvI/wCBV4QtzCt8yP8AK+9vl+7tr998aFfIOGv+wOH/AKRTPn+G/wDecX/jf5s9U8O+JP3iQyP8v95vvV2/h/xI+NgmVnm+b+7Xi2h6p5MgcPt/2vvV2Wj61KrbHRnbZ97+Gv5+lR5j6zm5T17S9ce4hSb5olZ2/wB3bXV6D4kd4US2mjRG+bzJH/h/iryXR/EMMMiohYMybnb7y7q6PR9QgaFPPfJZPnVX+VazlR/mHGp72hi/tY30t7d6GZZFfbHcbWXuMx4rQ8FSEy+H3ViCLewwV6jEcdcz+0Nex3k2kCJwwjjmHAx3Sug8DsRHobCTBENphsZx8qV/W/gen/YU/wDsFxH/AKciRxxLm4YwD/6e/wDyZ9AW948LbLO5Ubtr3TKvzN/ere07Vt1wjpt2K7bpG2/8Bri7W48pVubl1fzE/wBYz/8Asta9rqltHMv+rDttZ22f98rX8RYqn7aPLI+swdb2cos7m11X7RcO/nbmba3mL/y0rXh1SG0uP3MLbvvI2/8A8drg4daeNg9s+yWZ23svzVZh1qbakcN/IXjTc3zruavExVH3eWJ7mHxnvHe2/iBobiJ0fe2z/U/e3VpW+tzMxhjm3bvlfy//AB1a85t751VJppv3X3maT71a+k6oiyeZC7Mv8NePXw7lVPVp4qMtUdlJrVzMu93VJV+Xav8AeqrfalDHH503zf3vM+bc1YtxdIt5v2bwqK3mb/vL/dqGS+eONdu3+981Ycvs+Y2lU5pFjWNQeNvOTy1Zv4Wb5l/3a5241KaaUP5y7d3zNUt/qSfZ5ZJn3bW3IzfN97+GsDUr6GOHY6KvzMj7V+6v96tKPNLcunUjEmvNUjhjcu8aDzflZX/hrm9evbaGxdH275Pm8tvm+aodV1yGON4bN2x/Hub5t397bXJeINcmvpjZpeRh1+ZpGf5m217GFoy5jmxGI5eUr69ND5zwQ+X+7Rfu/Kv/ANlWPJH9ouHTdkt91l+9VbUNagupC6bf3fy+Wr7mWqf9tOjRfN+6Z90TR/3q9eOH5oxsR/aHLqbsMyQ2/wB9iip/31/u1r6bcJHZqkybol+5H/drl4Lp47go7riT5t392ta1vo5Nru8nzfL81VKjy/CRUzOM5anuFxZzRyO77T83+981Zuqaal1b/JDx5X73b8u2tpWcXD/ZvMhVtyJ838NSQ2/nSunk7kZVV933d1edKUo6mcZQkcd/wjFmrfaUkkf51+ap9P8ADqLcebD53y/ebbuZt396unbT9115Pkx7mb+GtLS9F3M2/wCR12/Ky/LJSlKIcq5eWJiW/htI2/veZ/eX5t26rj+GhZt52xcM/wA26unhs0XY5kUtu+fc33alk06a3hkme2jLzfK6xvuVa0IqU+U4HUNF8uHZ9m2fO29a4vxJosyrL5KbU+b5V/8Aiq9T1ofZ41hhhVWZPus27d/tVxHiKF5o3TyeW+b5futVwnOOp59aMddDxnXbT7Myo6L83zfK3y1w+t2bzXDzWr/LG/z/AD/er0nxVYuqv5LKgjb5G8r5q5LVNJSRvLf9yW+438Ne5h48sOZnzleO5xMNu8f79PmG7czSfw1oafcXUm77TGzL/tfxVam02ZZPJuUVg1LYxzSO9tM64X5lbdXfLlkcMvd5TR02Mq+5YGVChP3vlDZrb0K1ku7kQqnyscFvSsuzjeONopHYsvVR91a6LwjC0yMqfe8zj5ckcCv3nL7Q+jRj/wDsNj+VE+cqe9xvS/69P/242LHRbm3ibe7NJs/76q/b2sNrGv2aDa7Irbdm1qt28dtGyJsXzI3/AHTM9LeRQ3V0POmWP918rMn3mr+XJYeUqsp/EfoVGVKMfdH6TshbyURiWb5W27VWmx2pt8Q7Msu7aqp97/eo+0Qt8kM2x2/h2/NU8Pk2wKJNJuZ1bdtrn+rxjUO+nUjy8soirps0213RXfbuRlSobqMvCN87PGyfOq/LtrSWPy45Ybbr8rfM33qzbvfGxhS5jJb70e3btrKVDl94qNaNMrSSPDInzqjbPu791Vo9WiVikKN9/d/vNVXUrwJIwhRfm2s/y/LWXDfO0zbEXYzf8s66qdGMvQj65KMtDejutrG5SRUTd91v4W/9lrzX4meJPtmsbXfESoyrtT5Waup1LUodP02WbfIzMnyKyfNXhvjbxdc3F1NczSsv9z5q+hynBxpylI8LOsZOpSUCprd083nTW02fm27a4XWt6yN8671etqx1h2jd97Nu/h/u1ia9Mk0vnf8AoVe9A+ZkZvnf7fLVPDdJHIE38t97bWfcXCRx/JzVOK8SSZnG4Ovy7d1BRq+KNeS1014oZm3stcHNJJJI0xfLNWtq1xJM3+7WayO3VK0HGVytk55djVmz1W5s5ldJG2r/AA1C0Pl7eflamsh27kWpkafEbsOuJeK6TIuGqhq2n+SouYU+RvustUPnUVpaPqkKt9mv/nRvlXd/DUi5ZbmbE7wyeZ3rSa6ttQsSjxqJl+41P1Hw5MB9qtJkeKT5l21lyCa2k2OrK1A/iG4dW+eilZt3ams2OBV8yLBRhaWiioAfAu5sir1uyeXv31SjX/lmf4qmhZFbY/8AC/8AFRMxkTySMrf+O1BMqMu/Z/HSzSbW+STdSNLu+/t/4DQESKLqfrTZBt5L5NK2MfJTH+8aChKKKKDQR/umuk+H8iRSTb0/4FXNv9010Xw/lRbt96VcdjOXwHU6hb+ZDvR938NZN1bv5z/7Pzfcro5rNIbddm35v4lrIuoXZt7u2aXxHOZvktxs2ru/hWva/wBkOOHTm1zxBcpkR2gtombruY/w149b27yMvZf71eyfBGdNM8Gzxwqqfabg/Nv+ZlUUn7rXqRV+FGv8E5PJ8XyymMMq6fKWUjORla+u/wBgf9nPWPi94yhSTSpPJvpVf92m1o13V8bfDISy+J1tI7hohPH5byIcFVLrmv3k/wCCN/7KOm/8Ibpfi6w8tYYZ44fv/M38Vff8bUqb4oc5fyR/U7uPpS/ta0N+WP6n2h+xv+xfoHwV8E21/eQxiea1XzTt+bbX5Zf8HZ37RcGr/A7w38H/AAjcTLY6p4viS68u4/dTfZ1Zvu1+yn7Snxf0T4VfDnULeHVIYblbFgFZ8Mq/dr+ar/g4A+InhjxZ8Xvhv4D8N6ldF4bK61S/tZLrzY1kZtsbL/vV8hUnKrT55/I8HD4WnQrxjDp8R8G6fYzRxo/kq52fNUqCGSYJf2G75vl21pWdl5ir83yt/D/eqzHou6QIjtv3VxfbPQlb4T9sP+DTbwbLYTfFbxfFDHFA2iWdr523dJGzSM23dX6I/tHeLkt82dnMoWP5EZfu1+cn/BtD8VLbwX4F+LXgm8vIUa60ux1FGX7ytGzRsv8Au/NX2B8UvihYateSzW0LS+cvyL5X/j1dtH3jw8THl5Twz9oKb7VZzarezN9p37Fb+FVrxHQfhLrfizVvJs7OREk+7J5W6OOvou78N6r8QNUmR7DbE3+qZflqL43fEn4dfsl+D4baCSGbxBfRbNO09dsk7Nt+9J/s1OIqUqcLzMuV82kj8fvgrfWXw7/4KIS3Oq2puItK8Y6zG8KkDeVF0gH54r6J8ZeNte8VeIpvE+sCNrmZ22Rt/wAsV/u18o+EtXutd/bGvNeviPPvPFOpXE2R/G7Tsf1NfROqahDaxzfvsr91vn+avX8TKlsdhv8ArzH85H23GWmKw7f/AD6j+bI7xYbdWubm5hRdu7bv+WvDvih4w+3aw8NnNsj27VhV9y7q6b4kePEW0fStNud77Nqrs+Xb/e/3q80j02a+unuXVvm+bctflUa0q+x8jGXNuZt2yXErbLrG5t33Pmps2ivGz3OpXKt5f3P4f++q1JrO2tYXmuYVO3/x2uI8deLisLpbXkaQ7/nk/vf7NbxoxNo0+aZj/EjxdZ2UbpbTKFb5n2/dWvEfEeuXOtXzyyTMyBvk3VoeN/F9zrl48MUzeUrVzyjAxXvYWh7OF2e1RpeziNVd1OVdtCrtoVt1dnKjoBV20tFFEQJFb5sj+Gtzw7dSNIE/2q5/cfu1e0e+eGZE3/xUpRIlE9Z8O25WFfuhvvL8n3atX1h+73iHd8vzSfw1neC9U3xo833W+Wusks4bhfvsibfkqvscpjKJx1nvt9W+0oigq+5GWuj8aXv2fwSXTbhn3PJv+ZflrD1axfTZvMhh+VX3basa1Nc6t4BvLOGHbtt2dt38O2oJ9n7545qN295cM+eP4ahjh82THrTWOFr0r9k7wn4S8dfHXQvB/jOwkubC+uGSeON9u75WoqS5Y8x1xjzaRPNmBXgiivsX4lf8E6NB1Oea++GPiGSwLXDCKx1D5olX/erwjxj+yR8b/BzO914PmuoVf5prH94u3+9XNSxmHq7SNp4WvS3ieY0Vf1Hw7rWmStDf6ZNC6/eWSJl/9Cqp9ludu7yW/wC+a6ozRhcjop3kuv3kxTeAKQuZCsfmz6UlFFBR7B+xw27x9qf/AGCD/wCjY6wP2ov+Szal/wBcLf8A9ErW7+xt/wAj9qf/AGBz/wCjY6wv2ov+Szal/wBcLf8A9ErX77mP/KOuD/7DH+VU+Wo/8lbU/wCvf6xPP0+8KGG00lKx3GvwT3T6kSiil3fLtqSeZCUHPeiigdkSK3ylD96mD5l2fw0csv0o+98iD5qBRHrzt/2vStKyVLWHf8u1X+aqEcKN/vVNdXirF5UL8/xVXMRJXE1K+N5cb8fIOi/3aqs5DfzpZGbeaZUjLVuzxqTvamXUiHbs/u1CrZPy/wANDNu7VXxFcrF2D1NWbf8AdwtvT+CoI23N8/3mp80m3CI7bakmSHbkVcbt1KzZVdnJ+9VcttJFLEzK28PzQBam3wp9/I/2ai8wL9x8f36jactj5ulN8wf3B+dAHX/DXxA+l6wltv2pI/8AF/FXvfgjWrZtUtvJdnO/+592vly2umguUuU3Eq33lr234X+LIdUhhm+04dU2uu/5lrjxlPmic9anzQPrv4L65c6Lr9lfvMu2OX5W2/LX1V4N+LFta2ahLnaWdvmZvlkX+LbXwT4J+IlhCI3v9VjhRf70qqq13cX7XfwF8AWq3/ibxrFd3EL7fsNs25v/AB2vG9riIXjCJ5XsavL8J9sN8aPteX01JG/2Y3/irnNU/Zr1v9ua4ufhjpXjCHRvHEel3E/giHUE/dalfRruW1Zm+75i/Lu/vV8ZeKP+CwHw48PpNa/DL4a3crKu2Cebake3+6ytXk/xB/4K1ftIeMbhJvBMFl4anjl32t5p5Zp4W/hZW/haujD0cfUnGUoG1LD4mM1Ne6ff/wCw/wD8E6/ivD8QbzxP+0/pWpeCfD3g+Ka7+Jeva5b+Ra6TYw/NLGrN8skkm3av+9XwF/wVJ/bw1r/goD+2bqfxp0DTf7O8GaDbx6H8PdF2bVs9Ft/3cPy/3pP9Y3+9Vj9qX/gqt/wUU/bF+G9h8Ev2j/2q9e17w3Y28f2rRY0jtIr5l+61y0ar9pZf+mleBwxI0Pzwqvybdte5CMYyuonqc0lD4tTlfFfzag8ydGesutnxVEkVx5ezArGrU0pyOl+EgJ8c23p5cv8A6Aa9F8aXsVhpxnlnKg4GB35rzz4QRk+M4WJ+7HIcfVTXRfGbUTaJbQA/fU8bsd6+5w3/ACQFb/r6vygfQRXNwvUX99f+2lRZkuIfkddtWbGOOaRkR922uLs9ekhUw+v3WP8ADW5pesfdSN/95l/ir4I+ZlE6mFEXCZ3KtbNrapfae9tN/rd25GrndPvkuGEycf366G1uHWdYbblWT7ytWlPcjmhflkRwx/u5dJv4cjZ97fXuP7Ln7HP7VPjzTo7nwt8N71tGvmaWDUILdmj2qrNu3L935VavGruz5+32ybXj/h/h/wB5q/cr/g3v/wCCqH7D/hz4CWn7M3xt8Q23hXxk9z/Z8r6qFWzvY23eUyyN93durpw+N+pVY1LHnY/CSxtLki7H5Ca/+1N4A+HatpHw/wDBo8Qa3Z3OJ9QuU/dRyRt/d/i+7X7W/sn/AA+/Yg/bN/4Jb+MvH/xu0zw+3iC08B32o3v2HalzpcP2VmVvL+8rLIpr4x/ZM/4JaL8Mv+CoHi21+PngaG8+G914kuLm31SzgWWza3muG8v9791flZdvzV9Vf8F6P2bPhn/wTu/Zc1z40/sm+HrjTn+IWnJ4K1S3t5M2lnb3R3G43bvvMqsqrSx+aV8xrRXP8Jx4LL6GBjzxhvvfc/BzQVT+y7X/AEmZw0TN5n95f4arTag8XiSG22f6yL59taNrpaabYpD2hi2bmf8Au1xuk6pNqnjrej7trbE+f7tZx949lH0PoBz8Ngev+gzdP+BV4BeLt1B3Tdnftavf/DrCT4bhlOQbKbkD/erxC4011mmTfnbLudvvV+7eNP8AyIOGv+wOH/pFM8PhxJ4vGX/nf5shsbx/MKJ8jL97dXYaHq8Cxqk0zf70dcpHC8TImz51rS02Xybg/d/4DX4TGJ9JU909B0nVE2q8L7i25dtdHo+oTSMqI8bIz/e3fNXnljqvlwhERmP8ddBo99DIqwsnlbfut/DUyp/aM41OWViz8Xb0Xkmn/NkokgP5rXX+DHUaXpLknAt4MkdfurXn/j25a4ltiWBAD7QO3Su28JOI/DNjIei2yH17V/WHglHlyaov+oWv/wCnImnG0ubhTAP/AKe//Jnrel61bXGyF3+X+Dcn3a2/7ctJLVPJdUf7r7vmbbXlWn+Ivsuz/SV2MjfLVhfHiRx/JOv93a1fxhiMLKWx69HGQ5Yo9Kt/EDw+Zsf5GXajR/w1ct/FlvGoR5o0ZflX7rbq8rk8bfaIYp/tKn/ZVqP+Eu/dvshX5XX7qrXmVMHzRlzHoYfGcp7Pa69C3lvNNGV+9LGv8Na0fiKS1d4d/wB35tsb/NXiOl+LplLbzJ8z/dZt3/Aa24/iAlvcPqD3P2h2Tbub5dteNWwfKfQ4fGQlCMrHrf8AwkieWfkkiaHavlt825f71VdS8cWyyM8J2Bd3lRs25tv+1Xmf/CdOy7PtLH91821/4f4qo3vjbzESYTKUjXa+7722uSOD5feep3fXodDv9Q8WP5b3M1yqDZu8v+L/AHdtY+q+InaNHeZirfM7L8rVw154ueOQW1s6/N8v3fvVl33iy9bdCjq7/e3b/wDVrWlHA1Jcsjz6mP5ZWOj1/wAQTbfnfD7vnridU8UXO533w4+7t/i3VS1bxK6M3nXK72/uvXKX2rPO0sMMyqfvJJ9771e9hcLL3YyRwYjMTak1zdI1zcvhd/3d38VP0+6S4jZ96r833m/9lrkpr2ZW2QuqKvzMv3t1bGm3k0j/ACP5qbNqNs2163sI04nl/wBoc0js4b6G6hVPsy/L99W/iWr9rqCR5kdPK2/NtZNyrXN6XJN5f765bdv2/crWW4upNydW3fxf3azqUYRgX9clzc0j6Qh1B5JEdN2xX/ufeWtCGRJP3lyi7Y2Vt2/atcNa+IJo4Q7+Y6M+xJGb94tbOn+IDJN+63NGvG6R/vN/tLXlVsHI9vD4ylynY2N05uPO8mF3m/5Zr8u1f9mti1kS3ZpN+W2/Muzdt/2mrkNP1q5dv+PlVWNvvN/DWjY6lbLIs2xk27v49u5qwjhPetLY6Y4vqzrIblLqM3CQxu6p/wCO/wALVWmklZnNs2GZWb9591mqtp+oQt+8+2bD/wAtapX2rPdN/oe1RJ91pk+alHDe8+UUsX7upR8Rb4VbMyuWi/5afL5f+zXn2sSeTa+ZJNvdk2eYv8Nddql47XqTv5flx/wt/wAtK5/VoElhkjhfzArr8se1a7qOH5Tza2IjKUmcHrFrDJdM/mN+8i+Td/F/wGua1jTkEZSG2Yo25nb+Hd/Etd1qdntk8t9u1fl8tvvf8Brn77T51k2Inzs7N+8+7XpRoxkeTWktpHC31qnl5fhl+bb91qpm35RIUXO3d5i/d3V0+taf9sZtkMbsrfe2ferNGl/aJ/30PzRv8+19u1q7Y0Tz/aS5iOygK6e73AxIMf8AAua6LwKIgkm9Cd0mDh8cYrMuLSSGxlkkUAnB2k5K8itv4fGIWcrM5DefjG3IwQBX79gafN9G/HL/AKjI/lRPl51IrjOlL/p2/wD246KZo4YQ9si/c+633qW786Vvtlzt2/KrtIny7v8AZqW1j3XELjnbu+b/AOKrQ/s3zMJC6hfv7mT5a/nKWHlHc+5jiOYyo7VPMXzkb5fmX5Nqt/8AY1YWb/SYt826Nk+WNfu7qWawmaZbn7SrOqbfm+9/u0xbe2tfk3/K3ybf9rdWNTC8upX1yY6b7T5c0qIyBduxm+6396qOoX0Kw/Zg7fK+5Wb5W3VYvvO3O6Qq+19su5/4f9msrVpYVfY6M52/8tP+WdVTwv8AdFLFGbdfbJFKQzLt+7833WWo7G1mmk+zFmT+Lb/dqeOOGGN9ky/3nVqs2un20knntNsmaLftb7tb/VVGBH1o5jx00FnY/Zt+95Nyp8/zV4F44017PUJ7bq7ff217L8UPE1tba9Z6J50aCPcztJ/E1eZfEOO2muheJNuX7zLHXfg6cacTyMbiHWqcp5xBePazfxf3fmeqetTPIwfe21v4VqxrM0PmM6J92sq+uvMjGx8Lt/hT71dXLynPEp3E3mfOnyndVKSR9+/ft3fNU15vXcj7vl/2aoSHyzs3ttVqQo/ykk2xmOx2bb/DTY4iy/7f91qgaRvLOz5W/j+ep9PbzpPv/N/tU4yKl/dK8i7RsdOFemb08wJs+Wreq2jxqru/+z8tZ/zow+Sl8QRJJLfdu8v5qrsjIfnWrdrJz++OKtSWqTQqlAc3KVdJ1iayuE3PlP4latrUtP0rWrP7TZzKkn3mrn7yzNsw71Z0u4/cvC8+KqMuUqUftIoTQvFK0Ofu0UN/rj/FRRzGgU2TtTqGG7rUgKrY+/zUi/Mw7io1Xd7U5AnPz9v7tBMtyZldGHm8q33aiLnAb5cUMz7dlMY/Nn0oJBj82fSmv9005l/26Apag0B/vGkopGOBxQAtb3gGQrqLnfjau7dWD3xW98P3/wCJx5ZRWMibfmoIlpE9DW122cXDbWf71Ur63SObeNuF/hrRkuoY7Xydm9mf5F/u1k3zO/3/AJmZ6DnjpoZ18yW/7yD/AMdr2HwDatpnhW2ldI4lkhLxLs+bc1eNR777Vraz+V/MlVXVf96vdIYz9jS2dG2QwhEjX+GsaspRat3OetU/eIk+CEUUvxBtRMuQqlsbc9CDX9Iv/BJjRfFj/sEReOvhk1n/AG3eyzNatqxVIWkVdsar/dr+bD4VXbWXi+K4SRVIjPLNgdRX7V/8EjP2pdF+HPwcs9K/aM1W8sPBFvLJcWWpR3Hlx290vzMu1fvfLX3fiFXq0uInyL7Ef1Pe4vhCWe+9/LH9Tz/4gf8ABRT9or4uapr3w08T+BrG71hvEE1nf291eMrW7QttZd1fkf8AtpfFWT4wftneJdYSFba20tl0u1t433LGsa/Ntb/e3V+uPiDxp+wZpnxw1j496b42vrmG817UtRlsZItm6NlZlavxDtNatvF3xH1/xbDuMWp63dXUDSfeVZJmZf8Ax2vkpOPJE+fw8ai5pSOnjXLfZk2uf7yrUka3K3iIm5Ivvbm/iqa1jeNV+fKt99ql03T/ALZqTSPt3f7T1PulyjGJ+ln/AAQj1S5b4oeJdHhh2/2h4DmWVV+7IqzL83y1+iP/AAru51K48xPMCSRfNHs+61fn9/wbxrYQ/tEa3YX9/G0S/D7UG8nd9394rV9e/tPftzp4a+2eAPgt5c15D+6vNUjT93b7l/hb+Jq3liI04njV4++aP7Q37TXgD9mTSX0TwlptvrXi2aDbFa79sdn/ANNJq+C/HHjLxJ468SXHjDxhrEmq6ndPI9xfSPuWPd/yzj/urWp4ouLy91C41LUtVkvL+43PLeXDMzSM3+01eceJPERs5BYWE3my7t33vljX+9/tV87iq06k7yBSjL4T5Z8G6hHp37TMupS5VY9dvm47f62vRfGXxA1XUri4trZFRPNZd0cv+s3V5RpU8y/HS6nVVeQ6xeEZ6EkyV3ksaWMh85Fd9m5o/wCHd/FX1/igpSzLBpf8+If+lSPsOMVJ43D2/wCfUfzZUXSvtSul/c7Yl3M8kLbvmqnq19bW8beS6xIsTL5f8TUut68lsu+OHht2yPf/AOPVzerXU0lvHf6kisrfKjb9u2vzqPu+6fLRjzGX4q15xaujvsi2btrP8zV4X8S/HT6vePY2bKEX5W21ufGD4jee76fpt0277rba8wJYt8xya9jA4WXLzzPVwuH5Y3kFIy55FLRXq8p3hSMueRS0VIDYvv06kVdtLVfEAU+3keOQP/t/dplJuKsKJAd14N1x45t7vnb9xVr03T9Qe8hG9927b/wL/Zrw7w/ffZ7jZvxXqngzVnmjRE2n5/4npR905qkTodU0c6pZN/oeSv8AF/7LWTpsKfY7nTJvk8xGj+5/DXa2Mki2LO+35v4a5vXNPe3vt9n8gb5m3fxL/s1cv7oqZ4Bq1obDU57Tp5crLXvv/BOv4faz4r+O1rrdtHi20uzmurhu23btrx3xtpxufGdzDbLxI6tur9Bf+CUPwasIvhLrvxLmRt95qi2Fh8vyyRxruk+b/erz8yrfV8LJno4NRnXjc9Gk8Mx2tvHvhZhvXey/w1ct7Ga0hkmSbev91U/vV6FqHg12vhmGNV2fw/d/76rOm8P2dqpt0tmMi/LEv3lr42o5z5bH2mHnCx5V4k+HngnxJH9m1Lwlpt5u+aVri3Vmrz3Xv2T/AIFaq2+HwHJas27e1vcMrf8AfNe+X+guqpstlRI327W/u/3q5rWtNhhuHQ7oiv8ADG27d/drSjjMQrxUth1MDhanvOJ8zeJv2E/hdqf7nRPEmoWMn8XmKrrXlnjL9hnx7pe+fwxPb6lEqfOqPtkZt3y7Vr7M1DTUt5GjdF/22X+Kov7Ff9yiQsj7N3mf3t1dVHNMTB3lLQ82pkmGlL3PdPzi8WfCTx54MvDZ+IfCt5bHt5lu22sGTTJ4W2TKVO7Ffp1Po8Eche8tftG5V+W6iV//AEKuW8Qfs/8Awl8XGVNb+HVmC3zy3FunlSM27+8texRzilKPvHm1Mkr/AGGfI/7HcLRePtULDH/EoI/8ix1z/wC1CrH4y6icf8sLf/0UtfUsn7OvgD4SavP4p8FzXcZux9mktJ2yqAgNkE8/w968Y/aI+BPivXNdl+Ilk1ubO5jRVBl+dSihT8v4V/SGNxFOv9HLBTi9HjH+VU+C9jWocYVYSWqpr/20+fyMd/yoZd2KvXei3lrM9tNC2+N9rYqCSxuUjDvC3/Aq/Bz6JSRBRT2hdT89NKlaCxv8a/WnLvxxRsb0o5U0E/EHf580KdrfJSU0Etmgok87y/unFLJM0kjP/epjDd1ooFyoVvmYmkopeWNBAsmVfikX5fn2Zpu75sU7+D8ar3TQX5Nu9P1pJm3/ADuKP4S1GFb75o5gEVX70/cm7dTAccihFc1It0K/3jQrfwdP9qjH8H8VByAVqvhFzMWNc8+tXdJ1rWNJL/2bctGZPvtVEsW60cqakSjzF/UtZ8Q3Ehh1DUpnPdTJWfuPIY8/3q0bXUklhFtefNt/1Tbfu1YXQnvJPtNnfwzIrfxPtb/vmiPILm5TH+8n3/lrY8OafG0h1K7Rtkf93+9V+Ox8PWdv52pQxs7f8s4/71QjUjcbYbNPKhX7sdVImUi1ZyPdTNL/AAt9/wCeteHZ/qd+PlrI01ds33FO3+7XRWNukkeETLf7VVH3iPhOO8Zb1kiTf8y/LWFW/wCO1SO+Eabdv+zWBQbU/hOy+Ddu7eIftOOFjYZ/Ct74p6JLq1zbyR9I4+fzNUvg7blZnnYYG3Cn14roPFepQ22qxWc6gq0IYZPfJr7jCe9wBW/6+r8oH0NP/kmKn/Xz9Inl934fvIWb5Pl/vbaqFbmzkb52WvRpI7O6Up5H+4y/xVkXnhdLndlNitXxPLE+WjUl9owtM8S3Mcy5m/4E1dr4f1hJsbHXaqferi9Q8M3OnyF4UZlX7tLpOoXOnsu+baq/7dSVKMZHsdvdQyWYh343L/laqX9tYXUL2bvsX7q/3qxfC/iK1kgRLl1Zv71b9wvnfvkO7zH+Zv71ZmXwnNeI/wBob4/W2kxfDGL41eLF0GG4WWLSP7em8hJF+6yru/hr6M1L9r/9rf8AaW+EvhL4IftS/GXWvEXg/wAM3n2jwvo9w3y+c3yrJMy/NLt3fLu+7Xy98RtHeO4i1u22qY2+ev2W/wCCMvwF/ZC/bk/Yh8SfCXVdEtbbxjpOrW+o3HiSaJmlj02P5plX/nnt+7/tVlVjFf3SqnP7P3T4G/ao+Efw3+Ef7Kug/E6w+IVm3irxB4jmtU8IrA32m3s4V/eXU391Wk2qv96vlPwBZXt/q7XFsMuPn21+/f8AwU2/4JZfsjXH7IMfj7TfHepa94r8RWi2HwqtrOz2NIy7Wbf/ANM1XdX5z/sT/wDBJP4tftDeKNUs/APhaS5n0fzP7bkvt0UFuse5mZmX+FvLatqco0qW9zjhWlL3ZqzPOfDdrPZfDyK2uo2V1sZNysMEZ3GvN7XQ/tDSP5O0feSvcPH/AIy0nx9d6j4k0PwTaeHrNoDbW+j2UzPHAsEYgyHbklvK3kn+Jya820fT/wDRXkmRQWf7v3q/f/Ga3+r/AA03/wBAcP8A0imeZww74nF6/bf5s42TQfKk+d/n3/3ajbSdys6bt3+7XeXGhoinzvlO35W2/wCsrHk0J45G+Tb5j7nXdX4NGPLI+oqfymNbRvCu+Z/4q17WZ/M3/wC396mR2KQj54W+ZPlX71TW9juk+fdtj+5urblhI8mo+SoReIJzL5Kkj5Q2AO3Su98NTbPBEExONlmxz9Aa891lArowBwwJBPeu+8Pc+AI9w/5cn/8AZq/q7wVVsqqf9g1f/wBOROrjKXNwfl7/AOnr/wDbzCuNecRrMjtlV3f8BqP/AISx8Ab1+5WLcSbpCUdtsnyv/s1UZXjbYiZVf+Wi1/JMqcdwpVJbHRx+KppFCPCrKvzfNVy18RbrlZt7f3nrkFun8zZCG+b5mkWpIb65X99vZVVtrL5tcNTDxlzHfTxEonb2/iZI5N6TMFbcu7dU0Pi5BHs85TtfburjYdWRWT54/wDVN96oE1SRY14X+98tcFTB0pfZO+jjZx907pvGEzSK6OzJ5W1/npP+EoG4bJvlb/vmuHhvnaUoX3M1WIdScrseZlCv8u5KxjgeT3UdEcZzbnYyeJHkVJt6kL9/+9UF3rjzW/yfIzfN9+uYbWEaIeWW+Z/+BVDcX03khN+fn+9V08HGOhz1cRKW5qahrEzfOdr/APTRv4azrjVHuJNnyqf7y1Ukn27nRlLL/tVVWZ5Nv3t396vRp0fsnDKtOJoW949w33N38KyVv6PvjjWFNrrs2v8ANWBpcLvHs/jb7i10Oiw3Mj7JIcLH/e+X5q0lT90zjUkdBp6zR7E+Zfk+dWrbt7eZWRIXZDs+fb/FWJpr3MMbw3KRnc/3t/zVt6WzwyJNtY/P/F92Ra5JU/e941jWkemXn2mLZM8OxZN2z5vlqxFq01nNvS8YRbFZl/vNWXe6svksjupDLuRlT7tZcerTecHhfaV/vVrLC8x0xxXKd5putfu0uUhZTv3bZG+7/tV0VrqkdzGk3nb/ADHZXVfvLXmtjfQ7Yt8yt91tv8P+7XT+H/ECRt87rJE3zIq/dVqxlg482x0xxku56DHdQqsbu8iO3zbV/u1DeMknzvJsZX+Tc/8ADXOWurQ3O+Ge8kd/937rf3aW+152jVIXaN/9pKPq3kbSxUeQs3jzanJ5PnbfLXYm5/las+8t/LkxsaI/eT+6y05pHX5Hudx2/O0ifNVbUrj92kMNyrbZVVl2/NXRHD+6cksUZeoed5h8nb/qtv7xPu/3ax9UheFUme5Z/MTbtX+Fq3bmPzI5p/tPzq3yrWXNbpNcNN++RGVdnmfd/wCA1vTw/vHHKtzbnPrppmWL9yq7mbY2/wCVqbHo6ySl0s9x/j+f/wAerqrfQ0mbZa2fEe5W+X7v+1V+x0NIVGxN5k+V5Nm35a7Y0YHP7Znn/iXTntNBmBJwjqAAmO4rR+E/7rSZrpJDuW85iH8Y2Ditj4maMlv4Ku54CpSGZAVX+FmcU34E6Wb/AMO3chgEirfYKkZJ+RenvX7zltH/AI55xsf+otflSPmK1WP+tlOX/Tv/AOSNlNHdowybo137n2/w1N5KQ70SaT7/AN5vm210V5pc00zJDbM7Kn3t+3/x3+Ko7rS/LjmfYqPD/efbX4FLDyPrFV/lOYkhRpN6f8C/2m/2qpXCw7rgwpz/AAeZ/eX+7W7qtqgDTQ+WyN99l+9/tVg6lG8kLpsjcfKsW16n6r15Re2iZOoX7ttRJ1Dtu8/y/wCFqyLi6xEuYdrf71aGqTI0JhhRdq/NKy/L/u1hXV4kfmu7732qqq33Vq44P3fdM5Yos2twkMrRvBGVk+bcyfd/2amWR7OGS8eFX8mLdt/4FWfZ6hbF1tntmHyKrK33azvidrUOl+BL14XbMcTbZI/vLu+Ws5YWcZe9E19tzHgHxa+Kiax401K8Sblbj727/wBBrnZPHj6pDs87dXNeIl/1s3y72f5m+9urHs9UmhkPyVEY8pjfm946K+kSa4Z/733/AParNk+Zwj/w/wANSW9wZYf3ny/7X96orxd2yZ3w1BHLCIybZ9xxy38NZ15bOyt/e31aeRGmXft3L9ym3U2750h/jo9C4+6ZUgSHOU+XdTre4dZ1mC4p0zOrOU2gs9Vm3qv3+acpD5TpreOHVLPhOV/hWsK6t0tcwujKf4Kv+EdWS1uhDM/DPWj4y0Ga3xfpD8knzfLSJ+GVjlzG0cg+bP8AvVs6Ta/aoCj/AN2s9oXuFXem0rU+lyPb3H7z7tASGahazQxlN/y/wVnxyeW2dtdDrKpcW29EXbs/hrnpN6yUFx94iZmkcnNKq7aanX8KfVRNAoooo+0AUqsfub8Un/AM0f8AA81IC7vl20lFIxwOKuX90BNu35s06ilbld9KJMhKKKKOUoK2/Asjx60rof8AZrErV8H/AC6wjlMlakip8J6HeM7Rr86/L/Ev3lrLuLpI1P7nDMm6tC4unuVWF/u1g6pNhW+TC7flVnq/cicxp/DWxTWPHFv9ph+SF/N2/wB6vdtCt7aRpbzyV+WI7WryH4G6UjyXniGZF+5tXc9e06IyWukoiO25ss0O75en3q5qlvaLlOapGUqq5TjPCrNHqZlU4KxZ6/7Qr71/Yn15/ih8Eb/4UX+qxx3H9pSJYLJKzKrNCyr8tfBHhmFp76SJGUEwH75wOor2r9mv4rXnw71S5mhuWZo7y3nWPftb5W/h2197x7O3FHL/AHI/qfQ8aJPNX/hX6m38WLDxP8EfhN8QtG8cJHb6vp+g3EG2RPlmaRvLWSP/AIC1fGPwqgeO0Yp8/wAvy/J92v1K/wCCzuueA/Hv/BOPRvjTYRQprepa5Z6X9ojX5po23SSK3+7tr8yvAlmkenR732bvvL/FXyFSNJS9w+fw3NHDrn3Or3brVPn2s3/j1TaO7rqTu21XZ/k/u/dpIFRrfZ5OF+6sf8VPtYUtoxM6eYfN+VVep5Q97Y+wP+CV+va3pPxe1PUtB1iS3uLjwfdQStGzKzRsy7v/AEFa+h/HF9a+FrFnuXkzJud2+7uWvkj9gH4hTfD/AMcatrD6T9uebw5cQQWvm7VVmZfmavVNe1rVfGWpHWPE9zIjSbW8tX+SP/ZWvMx2I9nLljuediI82sSXxd40vPEHnTaVuhi/hVn+8v8As1hJpc1xM0aQ4Vtv77+9/s1LcXVna2/2nVdqKvzRf3tv92qt1rjtYi5vJvsdr82yHb+9k/u7a8z34x5pGUaZ8waNbF/j1dWytt26xe8g5wB5p6/hXT654m89ns9NfcVfa8myuFiuDJ8Uru5t3eIPqN0VOeVBL8Z+hrp7j7HawuZkbMfzRbq+58UG1mWDt/z4h/6VI+y4w0xeH/69R/Nla8W2sYftNzNu2y7v3n8VeT/F34i+RbTQR3Pzbm2r0+9XRfEzxtbW9tNsuWRF+b5v4q+ffFXiK58R6q9/NwD9xfSvh8vwvtPekeLg8P8AbZUurqa8uHuLl8u33mqOiivoPhPSCiiiqjsAUUUUSkBc0+GFoi7puqO4sHj5TmptKu4rdZFuXONvyIKn09od3+kuoH93dWMvdkZe9GRlEbOGGKA27mtPVI9NkuGENyr/AO1VKazeNc71/wCA1UZc25pzIbBIUmDqM13/AIC1aG4u0R3+feu35K88VvLf5K2vC+ofZbwfPj+41XykSifQWm3yfY98zrtb79YXibVPtEMiPeKnl/dXZuZqoaX4ge40N33r8vy1zt9qzzTtvdh8u16XNzHPHmiZGqNCNQa837ZVT5GVPu1+0v7KvwR/4VD+yf4F8AfYNlw2jR6jfyRr964uP3jM3/fS1+V37G/7Omq/tWftPeD/AIG6I641bVo31Jm+9HZw/vJW/wC+Vr93PE3hu2jmfR9NRktreJYLJd+7y4412r/46teRmkrwsz0cDLlq80onh2oeE/OVt+75f4W+9WNcaS64hRFDs3yMrfNXrOuaK9vNsRFT+HarfMzVyOraDtXiHP8AF935q+ZrSlGWh9RRrR+KJ5jr2n+ZI8c22It8u2T+KuK8QafCzK6eWHX7vl/3f7tem+JNLvFk2fZlEP3fm+81cXrlrbKstnDNCv8ADtX71cUf3nvLQ9iniPaQOEuLOb7Zvj2lZNzbflpq2P8ArQ7yKyyqPLkb71aGqWu3Y8O3erssUzRfNH/8VUEzIsaJMjGRdv7xa09pCUrlyjzRuV2s/uwvMrsr/uvlpF86HzIZodq/xs3y/N/s1ft5I2khTydpX5d33adJavPuNzeK4j3bVZ/l3VcanLuTKP8AKedfF+Nl0W0ZoSp+1HcxOcnaa8w+Khit/hqlwDl9shC+4Y1618aImXwvZybXAN7zlMAnY1cN4x8OJq/wog+0RuEfzNrDocOc/pX9S1nH/iWfL2v+g1/lWPy/EX/18xPN/wA+f1gfInhvwvf61rT/AGyFjul/1i/xV63pPwj8MLpTzaxYRyJ5W5G2/drrvh38K9N07S11i5jj8pfm+Zdu3/4quV+L3xCttLWS2025+78q7fl+WvyBckVzGXvzmeXfFLwv4G09l/sqwaJ/4tr/AC15/LYosnyfd/vNWv4g1qTUrh385iu/+L71U7e1e6bzBUc3MdEfd90qQ6TNdf6lPu/3qX/hGdSVd4h3Cul0XS9zfcaVP4mrWuo7O0t9+9Rt+Vf9qq5UTGXY89m0m5t1/fWzD/aqu1u/3FSuv1jVIbgMmxWWsi3t7bzvVm/hWpl/dKjUMYo/CUqxswyP7tb6aRZt/rE+9Wja6FprRrvh3LT5Q9ozj1t5uoSnfZZ8Y8r/AIFXoem+GdEuMJ9mb/gNdFong/QYZVf+zYduzbumo5SZVjx+PSLyb7kLNtG75Vpw0PUmbZ9jkz/DuWve1j03S7N7Ww0232t8zs0S7qxV0O58RagjiHeyv/ClPliHtJHjd1pN/Zx+dc2rKv8Aeaoo1ieTDPxt/u16P8ZNBTRdJiXZ8+7azV59psG6ZZf4V+/UGvN7hbsfDM15Dv3qo/2qZe6G9gv+sXawrorP93Zl/wDvvdWFrlzuZk35/h27qDOMpyMottYk9aZudvv05xk7vWm0G0RQxWjzHX/VvSUVcYlEkbYO9/8A9qpY32tvTioF3r8mPmqX52x93/daoMyYHzpA+/r9+rMJ/wCefLK9VI1Rfv7qtW3mswRPlZf4t9HORKPvG5pJ8tl3p977610FjsW13zpn++q1gaXIkzJ+73fw1vSSJBYGR0wFT5Nvys1AjhfGVx52rMn8K1lRJ5kgh/vP96pNSuHu755n/v1Y8P2/2rVo4e2+tYmvwxPS/AGnnSobaA/8tFLH8jWD8aLqe28R2vlMRmy7f77V1elXEVvqlppqhx+7bAK8fdNZHxT8OnWL6G4ikw6W+AP+BGvt8I+bgCt/19X5QPoKHu8L1Ob+f/5E5DR/Fk1urfaX3LXU6TrEN1Cjv8y/7VcJf6Lf6fIyTI1MsdSvLGQfO2P7tfBnzfLGXvRPS2sbK8Uokasuz7tYmreEUjj3pD/tfdpvhvxejL5Mzqu75Xaus+0W1xD50O37n3d+6tIyItM4rTo/srJNGmDXd+GdThuLFraZPvfxf3ax9Y0fciTQw4Lf7NM0eSeym3mZgv8Ad20EzNfxdpfnafKjorBk2oypX0d/wQ3+Mj/Db9rzw/4Y17xDqVtoutX8enata2d0yLcQ/e2sv8S7v4a8EvJE1DTVTzsPs+638VZPwD8aXnwk+OGleKoXxLY6jDdRbv7yybmqJ04VKckKXMf0QR/tP/sefFb9sTR/B+q+EtQ0e08F642iaHZ6pqK+RDt3SXNw0f8ACzNtVa8u/ZO8FeLL/wCKnizwPoX7QGq+DfDXjnxDeWF/Jo8SrJcae0zbVVm+6zK33q8Y+J3w78DSfHbw9+0JpXjbSdbh8fWE2ufY7GdWfS/LjXc0i/w7m3LXQ/8ABOH4leHvj5+0dFomu+JPs1hJLM2lrH8rTTLu27m/hXdXFiITjy8jPO5atbE80tLHy5/wUW+EHw6+AX7W/wAQ/g38I7aaPw74evhaaWLlt7uotoyXJ77nLMPZhXz/AKDYpJpYe5RkdXZWX+Kvo/8Aba8QXfxR/bh8XXuuaabqS78RQWM9rp8wJuBFHFb7Y2HGWEfB9TXh+hav4b8XalrGpeFPD02nWC6pcJYWNxdebLHCrbVVpP71f0T4zy5uHOGn/wBQcP8A0imcHCzbx2Ji/wCd/mzL+wwzRsEh4j+b95WfqmlozMkCf3W2rXWNpqMyb/3RVFbd96orqxS4VX+zMSv8S1+Dxl9k+rrfzHByabNG2/Zt+f5I9v3antbMLu859n8Vbt9pc0c5+TfuT5mX7tQrpsMMjedCxVV+8tdUdjxalT3rxOK8SGY+R5+NwDAbemOMV3Xh3934GhYEcWTHn6E1yHjuIRTW2DnKMc+vSuy8Ox58FW8YxzZHr05Br+rfBb/kV1P+wav/AOnInTxdf/UzL7/8/H/7ecJfWu7d3DNu3VntH5a7N7f+y10F5bvIrPsj2r99qzLq3kVNibflT7zfxV/J5hTqSiZUjPDu3o27+CmNIGU7Nu5fvVc+z3MMa75NvyVXj/1h37fm+9tT71ZcsjqjKJF5yL1+dloZxGG8na7yfw/3akht3ZXTft2/canTQo2HTdvX+Jv4q5ZR5ZHZTlzQ5hIWmjjX0b+7/FUq3GIfP2bmb+Gi1jSNSH4b71DQosiQncVb5t392spROiMvdHyXG1f3KfKqfw/NSGR5G8/evzfKnzUkcBVT5O3H3flqa20/d+82KP4tqrU8qHIhjj2/O+7K/dXZVzS9LlvgNifd/iqxa2c1xNs8j73y7lSuu0HQYY4B/Euz+5/FXRTOSuZ+k+GXly8P8K7fm/iaty18M7ptiTNKY/mX/erpPD/hSG4k+0eRx95F2fxV0Nj4RSaMbFVXb5tyrVyicXtP5TibbRbmFdnkszfwbU+7WqmnzW+POm2Mq7v9nbXbt4Tv7Vo3S2ZmaL5vL+7VC+8JmNXmdIx5f3VkVm+Zv4azqR5vhNo8/wBofqzX7Ts/krhl+f8Au1gTX832o/OuNn9yujvo5mhleYsu59u1v4a5fUoYbdvnffu/u19DHCw5PM4o4qXMSw6sbdo02SfN83mfe+at3T9e8u3Gx2+V921v7tcis6QqfvI/yqjNVpLqYoET7y/NuWqeXxl9k1jjpR1O7/4Sh5G3pNHvVFZFX/2b/aq1H4kebzXS537U/wBX/wCzVwEN/Mis78Gb7jfeqb7ZsZt74kV12Kv92illfNF2KlmF4XO4h8Xf6tA7Mv8AH5b/ADN/s0x9QeRWczQruf7sjbZP97/arlrfUBdbbmdPLdvldW/9lrV0tY4pf9J2lW+VI1+8q1p/ZvKZfXuY2FuFvZtkKKH+6rN/FU1vb3KyRedcq4b5XhVP4ar29nCvlbHbCvuRm/vVtWtmv2oW0ztj7zNsq1l/Kc/1z3i7o9jNJNH86tt+ZF37W3f7VdNa6SVYQu8bP975X3Ku6odB0f8ActM6Rsi/cbZ822uw0jT0tY/JmRmik2tuk+9Uxwd9hyxnLH3jzL466Glp8LdQuJIiHjuYQriPGQZFGDVD9lrTWvfB+pSGN8LqBw69AfLTiux/aYghh+DepK+WcXNv5THsvmrWV+xpp7XfgPVZolXeNVYBm7fuo6/cctp8vgFjI/8AUUvypHz9StzcQwl/c/zOzm026urhXm2od33pP7tUNY0na2+H5vMX733l3V111pHlxvNs2lZf4n3bv9qsfUrGGPZ5Ls+7czL/ABV+JRwvu8x7v1z3jgdYs9sOfuRMjK/8VczeQ+ZD+43DcmxmZP8Ax6u98QQ/u12Iq7dzbVri9TjeENI7sZW+/wDuvu1rTw/YdTEcpx+tW+6Q/udiL8rMz/e/u1z19C0e13fcvyq6rXWa1a7pmh8nfHs+fb93dXO6hG7Mkhtt3z7d27/2WumOB5Y2UTCOIl8Rl+RMys+9kZm+9XNfFpXu/Dc0MO0eZ97d97bXV7bn7R8+0/J80f8Adrk/ixJt09Nm6I/N82z/AMdrkzHC+zwrkduFrx5uU+bdc0+2maVC/wB165u8s0j3Om3C1pa9qTyalKrvht/3VqJf3ybMrhv/AB2vlPi0R6Ufh94pwyuqq+xVVU+9/tVbZkvIGCSbnb+KoprVw37wsVb5dtQrII5ETY3y/cXdTiEokFwrxzbNilf71RtMm3Y6fKv3WqS6dJC2xP8AfqheTvHiRH+aq9wI3+EsyQvcLmNPu/daqlxC0a7MfN/G1JHePFh0PLfe+arUciTLv6t/dNZlyly6mdCxhk391r0TwbrWm+KtFm0HU/8AXeVtib+7XB3VjMi+cnK07R9VudDvlvIdymgekjS1TSbrRdQks7lGXa/3m/iqtND5LB05Vkrrr6O28caONVh+W5jXazfdrlWV7WR4ZpGyv8LUcv2iYiWtxmPbPu/3az9Qj8uQun3f9qrV5Im5nRP+BVnzPukzv+WrjIqIwNu5opFXbS0zUKKQ/L8+KWgApu3b82aen3hSVPugFFNz92lPzfJmiIC0UUUfEAUjLnkUtFHKAVq+D1dtYTY+Kyq0/Ce/+1V2Jkr/AA1IpfCdpcMi2o+b/Wbvm/u1gaxJt3bOv9371bd5I6wNH91VrA8mbUtWgs4YWJklVflol/MYHqvwf01Lfw3Z216//HxK0srL/DXqcceUeSN90Zz/AAbdq1j+EdAs7WzTyfkSO3Xauzaytt+at+3h8tFfzpGHlHerJ/FiuVVI+1XL3PM9tH26OD8Kp5mpNHs3boWG3OM8iur8E2L3Hii0m012z5u1tv8A6C1cv4Ltbq91tbSz3eZJGQu0ZPUV9afsm/sm+IfGmrLPbeFbq6upmV7O3t4tvzf89JP9mv0Dj6jKpxO7fyR/U+k41xEaOca/yr9TyT/gpD8QfE9v+zD8PPgvqkNwkF14im1KLzH+X93H5f8A7NXz74XxDZw7IVVY0+9X1L/wXD8Dn4Z/E/4X/DfUb9brU10O6v8AUvJfckLSSKqqv/fNfMuixosaJD86Lt2K33q+P5ffPEpzk6ULm7amHy980zMPvbqVZkaEQlPm/wByrvhnwzf+JNUtdB0qGa4ubq4WOK3ji3bmb+Fa0PiV8MfGfwn8Rf2P4t0r7NNvbbHuWTd/wJf4qcZcpX2z0r9lP9zql/NC0a/6Lt3SL8v+9XtS3lzq1w8OlJ80b7XmmT5F3V47+yTpttql5qMN/DI6R26yyr/wL5a9c8SeKrOzuP7K02CON1+6sf3l/wB6vJx0qUavMeXWly1bEWrXFhoA3vN9pvPmX+8i/wC6tcT4k1C8EM2sPeK00MX/AABf92tr7LdXMm+8vFRW+bzvvba5L4iak9vpsOlbMbnZpa8etWl9sx5uY8I05w/jySSWEuDdzFkz1+9Vnxp4qWON7Ozm3I3zMzfw1lTytF4luJEYg/aZQCPckV578Y/HMVg8vh7TJma5k+W4k/hVf7tfpPiLQliM1wa/6cQ/OR91xTRnVx1C3/PuP5s5n4meNn12+/s61uWe2h+Uf7VckuMcUrAt1NIq7a+ao0404csTzIx9nHlBVxyaWkY4HFCturX4SxaKKKcdgCiiimA6OPzJVQ/xUNE+1n2ZC/xU2ljkePcidGrMBKkhm2sod9q1HRV8qAkmkRm3p8tOtpzFKGUcCoakt433f7NQKUTvvBusPNavbTO21k/h/iqtql48eZtn3f7v3qxvDupJayb5n2/3aNY1x5pvucb6cvdMeU+qf+CL3jseDv8Agpn8MJfO2DVru60uf/dmhZV/8er9yNe0FLHz7BIfmjlZGWb733q/nf8A+CfHiF/D37c/wk1p5mZrfx9p/wAy/wC1Mq/+zV/SJ40s0XVtQE0LK32qRvmb/aryMdR5pG9OpyxPKfEuj2d0r+TDJCy/K275mWuM1aGGOeZHTcsfy7fK+98v3q9J8Sectu0bzMrN/F/d/wBla4jVLPdC01s+V8r5/M+9XiVqPL7rienRxXLueU+IrOaOR4fJ2rJ/y0k+7XC65YJul3w7HX5VX+H/AHq9R8UWyTSOkfmJu++zfxVwmtWsMMc0zv8AOrfeauPlpS91Ht4XEcx55rFrmN8vu+8v91qobphGjzWfKqvy/wATVvapazWdx+52vt+X5m3K1ZUlrC0yTecy7d3yt/erKdPldox0PXjU90qwxvO0sMyR7Nu9ty/N/wABardnb+YqP1Zfm+7UVvp/2iR5rxFEjP8AJtrWhV1s/wBzDnb8rx/3avljKcTOUuX3jz79oq1mtfC9gr7SGvgxIbJBKNxWHZeHpL/4LQahIy7VM4jDDGDvPeul/aRRl8EacWUZ/tEcquB/q3rW+DWhW2sfBa3+148tXnLKV+9+9av6hxUeT6MuA/7DZflWPzOT9px7X/69L84nynrXj6bT9Dn02a827ZWDRr91W/2a8B8ca9eatfO802V3f369f/aYt4fD/jK702ztlhimdmRV/wB75q8ot/Dt1qEm97ZSu/8Air8bpr2lKJrUj7OrI5OGxmupPOEPy/3q6HS9C2xrcum3a26ugt/DNjpu7e671/hrM1zWrOxVkhmwdnzVsZ/EJdahDpq7IQoP3ttc5rGuPI5gkm5/vb6o6lrj3TO6I2dvytVFvm+d/vf7VLm5ioxLbXCeYER8/L8tWbf51GxPn/jaqcMbySBE6Vrabpcs210Rs/x1HLMXwharMw37Pl+781aWmr5zfOjKu75amt9H8ja8zsd33t38TVoafZ7ZfndV21oRzcupd0e38tV3zf7SNWo2reSqu/3t/wB7Z/FWct1bQx7IU3NTf7QgUtv+X/pnu+9/tUpBLmOg0/T5tVbZ992+X/gVd1oPhOz0GxE1y67/AO633v8AgVef6D4ks9PVZpn+Zfm2q9ad18RLm+ga3t33htzbZP7tTL3tYhyylynC/tHalbXF9BbW82/b/Ev3WrhtCtvl3+Tu3fw1p/Ey+udQ15ftPyhU+7UOjxpbqw+UnZ93fSNfhhqTa1fPawrDC7YZPnWuavJjM2NnH96r+sXzzSffyF+WsqR03YCbafw+6OnGQjnYcGkYZHFD/dNO3JtzTiaMSiigHb25/hqShy/M3znFS+Yp+dNzbf71MVUZc/Nmnr/47QZkkaxtGr/Nn+Ordnv8zzjGxG/7tVNyLHv35P3flq9pjPwU3Bv9qq5SZG/pqvLt3/d+9tVaseKNUSHSSmMNt+Rt/wA1SaLbncrv8q1jfEa7VpI7aP5f9mnFcpH2zk3+6a6P4e6b9q1ZZnTdt+7/ALNc7Xa/Du1FrYzX8n93bTNqnwmxouoef8QLe2E28JG4+9935DV7xtqLWet28W9drQZZW7/Ma5rwG3mfEOOYZw7THn/cNaXxTneLXrdcZU2gz/301fbYb/k39b/r8vyge/R93hWp/j/+RJbq2sNStWaRFP8AvVh6x4C85We2TB/hXdU2naq8n/LDZ5f97+Kun0m+julwYVLfwL/dr4fmPl/70Tytra/0u4ZHDKy10PhrxY9rGEm+b5tu5q6fxN4XsNUtXv7ZV3f3f4q4m80W801vO8llVfu05fzRL9pzHoul61baovku+R97av8AeqTUNH3xrc220fw7a4DQ9YubGZfnZRvruPD/AIgh1DEMz/dfdu/vU4y90iZa0e3uWb98PlX5dtcv47t/suqQzJC2FnrsprfyZPtNs7fM/wAm2sHxtp818sV5co3y/MyrVRj/ACilzH3/APsSzTfFP4V+EbO5s4bMaTp11p11JZt+8m+8yrJWF/wT48QWel/tAWM2vXNxBprapNA9nZ7laTdJ5e35fmXbXZ/8EtU8AeLv2L/HOieHYbqbxRpPi3T795JPl8nT9redIv8A6DXmXw9vNS8H/tLa9beHrxrZrXV2nsmVvm8lm3baIx5qMuQ5ZRlKudx+028n7NH7busa3oXhc2h8J+JrPVrHSb9cY8tYbqNH9jxk9wc14h8J5NS1TQb7WNV8n7bfX8l1dRwrti8ySRpGVf7u3dXpH7bfivxj43+OPi7xV4812TUdVvLaBp72SMIzqLKJYxheBiMIv/Aa4P4I2rzeF5Em2sv2hfl/2lX71fu3jRGS4e4afbBw/wDSKZ5HDCUcbir/AM7/ADZvNao0geZ9u5PnjX7v+7UE2lIshtYvnVvvbUrd+z+W3zp8v3vu/daq0ivbyPNv3bd23b91v9mvwWnHmmfU1pcsDl5rN2kNm8K/LF95flWqi6eir5qfc/iZa3b5di7DN/rF+ZlX/wAdqGTTUhmZ05G3b/s12/ZszwakuareJ5f8U44o5rIRqQSshbP1Wup8NoD4TtEz1s15+q1gfGdWF5YyPnLJJgn0G3FdD4Vj3+F7KPGd1qoxj1Ff1b4Lf8iqp/2DV/8A05E9Di+XNwZl7/6eP85mPeWaLFsRMp95lz96su8sUlmTZCpb5dq7a7T/AIR2RfuybF+9tao7jwzCzK81syf3Wr+UeXm+I86NY8+ks/MhffG25v8AVfw7aq3Gm7WQbFz/ABrXd33haa3G9Nrp8yorVj3WhwsE2J95/n3Uvc+E3py974jlmt5lykKN8zfd/u09dPfcnyfL/F838X+7W1No77vJ87au/wCXy/uqtRLprtMYX27925f9quWUT0sPU93lM2PT32b3Xb833Wf5qmWyeNdi7S33ttaUMKRtsSFSv96nQQvGyo6Ns/vMtYyiehT3MtbF5NzQow+T7v8AtVftbF5lRIQq/wAPzfxVLAschZIYW+ZvvMlbml6Wkql7bk/d+aol/KORNoWk+Xb73+7/AHdld34Z8LmT959mjYf+PVR8M6Huj8mdGHmJt3bdzbf9mvV/BvhdDl/J8uLYqPHGnzNWlPkictT3iDQfBrraxQmFmEi7t237tdboPgd2V/MtmH8PmeV96um0PwrDZwtNclvmZdkbfw11lnpNtaqHeHEUjbNuzdtrOVb7Jj7CBwX/AAr/AMxWtjbSb5Pmikj+b5qyNc8D2y5SFN38X+7XslrpNnMrfPvVX2pt/vVQ1DwXYLC8KWzY3fN/dojLm+IUqZ836hZ/Z4wZrZtuz7q1y+uWLrG6PDgr92u81zTXmkaBIcqrs21f7tcdq1uitshTllbbuf8Ahr9F+r+6fKU63LI5Zi7XCpDMr+Z8u1v4dtPWGaFVgdGETfM+1/mb5qdcK8kjwlGYL99tn96pLeGFdltbWzbY12/vK6KeHtC8Tb23tPdHSWaKpdHZmaX7u77tOW1IzN827Z8vl/NSWilpPubhu2/K/wB2nstst2Y4XkKr8u77u2uijh7fZOeVb3CzpNnC0nnGZn8x922uh0mRFmf51+6pX5PmVa5qzW5kYfPuH8W5K6LTWmuE3oivtf5mX5WqpYOUfjJ+sc3unQ6XHtuP3zrtZflXZ/DXQ6fGjXEU32lmO3y33NWFpbIjI6P5vyfvVk+Wuo8OxldkM9tGn/AqwqUYRNIy9w6/wfZvFD9mk2na7Lu/vL/vV2GmWME0KI6SbI/9Uslcr4ZaGH+CTbJF80a/ers9Lk2wo824qu1fmf5v+BVw1I8srx+EuMoyjY4T9rG3QfBDVZFRSUntsv3z5yVg/sQQNcfDvVY0yD/bZyw7fuY66L9rOT/iyetR70ZftFttwMbT56ZrA/Ybih/4Vzq077s/20VO19vBhjr9owEf+NF4u3/QUvypHjVXy5zF/wB3/M9evrWztZPnh83y/l+98rVia1YIzTzfKX2fKq/erqJI4VjbyUV9q7dsiVz2pSeZG0kCZMP3FWL5lavxmMfsyPV5ov3jhNetbaazdEjZZJNyKrfL/wDs1x+sXX2NUfZ80e1XjVd3zV3muWsbSOjvh/mZVZfm3VyGpWn2Jkd3Vk2/dVv++q6qdMfN9o43WHhvZJZnfL+b8y/dZq5HUo4GkZ9kkZbdv3fw122qR+T8iSTF/wC6392uV1Cze8XzvsyqrN/rFf8A8dr0MLH4lIz5vfMd4bJZDcvu/hX/AHv9quL+L1lC1nEiQsHZ2/eM/wDs/LXoEsO6Y/IyKybdrVyHxe097fw2moOiulrdRy/8B3fM26uPOsOqmXz5fsnTg63LiYqR8g+ILX7Hqkru/wAyytvp9myBt6Ix3fcre+M3h6bT/EU15DC3kyPvi/3a5vS23M2x2/3a/NI/3j6j4i1NIdv91f4m/u1n3X8SYX/eV6s3kyIp37l/2qoTSecx/wBr/wAep/DIJRiRyN5oXYiqv+zVG4USbd/DNVub7qoHwP8AZqszkSbNjNT5fdKiVJf9YUoWaaP+PBq42m/K0j9KqvbsoOR931pcxpzRkXbHVnklEM3zJ/uVcvNNhu/3yf3P7lYanyxnNdV4Gez1JG0+52+Zt+RmokRKP8pneH9audB1DZv3Rs/z/wC1Wxq0dnqUf2/TduW/5Z1keItF+y3RRNo2/wAX96s221C50/hHZf8AaWp5eYr3h2oK6g7+P9mqa/L96rN9c/apfN35qt9/2xVf3SoiK205p4bdzTfL96VV20RKFooopy2AKKKRW3Ue4AtDLuxRRTAVmduXpKKRW3tiswBV20tFFABWx4LX/iaLNH95axlbPBra8Gwbrh5uy1cdhS+E39WZ1hZ5Ojf3a1/gH4Rm8XfEC22J+6tWadmZvu7a57xBP+72J/FX2n/wSH/Yz8eftCSazqXhjQZrncy28Unkf6tV+Zmap9nKp7iPPxVT2NDmMDS9BvJrxbaG24b+Jvlr0H4efs/a98QNSg8PeHbC51a+u4He2sdOi3uXAJBb+7X3l4R/4JJvpfinTLnWbm3jijVf7bm1SL93Yr/ur95m/u11HijTPhp8LvHMHwh/Z9c6NJosTG/1KCz2SzzsDgbv7u3+Gt8Ng40ppzPn41pTasfm3/wSn+Engf4y/tTjw14+Mxs7Xw9c3kKW6gu8yywKgGeP4zX69+E/h7pXw18Oy2fhXQZNCtVi/wCPq++a5kX/AHlr8uP+CGV/Jpn7aN5eQ6K9/Inge+2QxkBgfPtvmBPA/wDr1+ofxOuvGevSfZr2ZoLaTcr2drE0su7/AGm+7X6Bxy2s8fKvsx/U+t45pqXEPM/5Y/qfjb/wW41b+0v2+tO0H7TJLHpfg6zaJmbd80jMzV4Rp9q6t57/APLT+9Xp3/BTizdv+CjPifSrx5Fex0y0ifzm3Nu8vd/7NXnFnD50gR7lV8tq/PpfEccY/uos9w/ZL077DrOp+MEmjSe1smgt/Ofay+Yv7yRf9pVqD9o+O21bwnYaqmpRn7LOvlKsu+Ty923c397dXN/B/wCLGifDXVprnx5YNe6TIm24jt929fl+Vl/vf7tX/wBo349eGPitdaZYeBtHktdLs7CFJ5Gsli+0SL93av3lVaiXvVLGUef4jW/ZruNe+z3dnpqSP5ibWkj/AN7/ANBr1xtKs9J82/mRWmZN26T+KvKv2W7h7ZdRntnVf3S/N5v97+GvSbi4SaR9+7yVi/e7v4a+ezOL+s3iebW5+YbfMlxG9/NDG9vsb5f73+9XjHxQ8ZedrUlhZp5u1MeZG/yrXSfEr4mvY282iaDNJDczL/rlTcvzfLXkHjDUk8H6PNqWt3O6bZ92T+Jq8zl9tPlIpx5vU5TxnrVz4e0q/wBYtmzLCG2MOfmLbQf1rwu7vLjULl7y5lZ5JGyzNXrfj28N/wDDW5v+hntYpPzZT/WvHfM9q/aeOYRWOwz6+xh+cj9K4hjbEUX/ANO4/mxwbdzRSKu2lr4o+fCiiip5gCiiiqAKGO3rRSMu6gBaKKKACiiiptMBfutUsZ2ozs//ANlSzQotqkwf5v7tMX5vv/d+9RymY9ZJvvg4ahWeRjvfJpkjZb5KemwcdKkDu/2ZNWn0P9ojwFq9rL5b2/jfS5Fkb/r6jr+oX4hQpca9e+TZqqLcM0Tb/wDWV/K38PtQbSvG+jaqjYez1m1lVtv92ZWr+pzxhqCXF1b3+xdt1p1rP/vM1vG1ceKp83LIiUuX3jgvEE26NkkTcI2+ba/3a4vxQsNvutd8c3y/L/s12WuXEyrLshWXzGb5Y/l21xPiLyf+W0Kp/cZf4a82tR5tDenUlKRwOuRzNfbx8rxxf8BauF1u3fzHfeqbl/eqz/MrV3/iaZGZ/JRdjfL5i1wniDekK+S/nMyssqt/dX+KvNnSjRlc9jD1JROD1CGFfNeabZEr/dasmZZpFT5FV1l27Wf71bOqXkMP+pfZufcn8W2slmib5Hdkdn+8sVR7Hmlzcx6lPEe4FnDNeQpMkKh1TdL5P3auafazbvJ8yT5n2bdv3t1Gn2dskO1/kX727/aq7a77e4V0mZ0+95K/L/wJqVOny1dB1KnLHmPO/wBpeNLXwJZWUchZY9YH3nyVPlPwPatj4H3y2XwUtWmlxHunLf7P71qy/wBqFWXwJpjyMgeTVNxROy+W+3+tZOg+IE0D9n6CbzVyyXJMbHO7ErHpX9N49Rl9GnAr/qNf5Vj8+pVf+M5qyf8Az6X5xPl79ojULbX/AIpXaO8j7X2p/F81cVcXWm6Da+Tcuo/2l+arfjLXnutfudSm/wBbNKzV5v4kvp7q4b94wXe1fjEI/uoo7akvaVZSkXvE3jd7oyoX/g+Vl/irjrrUJrqXfJNubbtqdrW8uGXy0b/vmtbR/AupXzIiWzPu/i21UY3JjI5yC3mk+5CzVr6X4WvLpk/ct8z/AHdlek+B/gHq14v2m5tW2fxbVrsrjwPoHgnTVudVgWKJflVm+9WnLCnL3jP2nv8AunmOh/De5MfnX6Mqfx/L/wCy1rSWuh+H7L7i72f5G/i21W8XfFbTbeZrfRIWwvy7tn3q4uXWtY1ibzn6/wC1USlzGnvS1NzUtehkk85OtUJNeufL+QsG+7tWmLa2sIM1+7Lt/vVteD7jw9eK5hsGl2p96T7zf7tTzcpHvmAt54huN2yGQbf7yfeqBoPE+7f9jkX/AGmr1Cx1bQ7NgE06PYv31mq/fav4SvoVL6OqP979391mpF+99k8ls7rW1/4+bZv73zVq2etPMo3vt+T5Nv8ADXeLbeA74nyUuIh/tJuqteeA9EvLY3OmXONv8O3bWnw/CRI8z8Uf8TTXBN5bYVf++qZdSPDCD8q/3v722rusbI9afyekL7N1YmragjTON7f3fu1H2/dNDNupfMkI3sQr1BS9cmkp/EbRDgikVccChV205PvCqCQMu3dTFG1d5FSfeYpTVG3pQHMOjb5giVJcb49ydabT1d1TYPm/3qCR8LeYrdm/vVpaTAkm359zVm26uGfema2NBjQzIn97+9QTI6i3SaO3W5SbaFTbu27q4XxTqb6pqjz79wX5d1drruoJpehs/wAqHZ8i7q86Ls5Lt13c1EeccBYVMsoRP4mr0jS7VNN8NxIE/wBd81cBolt9ov0T/arudW1BP9G02Panlorbqf2gqS+yS+D9PMXi23uH4ZVcY/4Cai+Lyka1aOpUE24Hzf7xrT8IzW91qsMkW47Wk5ZfY1V+Klus+o2+5Mn7PhT/AMCNfc4b3vD6t/19X5QPoKT5eFaj/wCnn/yJzGn3DFtj9fvVs2czxsrj5W+8u16xI4ZrbbvT/wAf3Vq2fzNv318PHY+a5jo7K++QI77tq/3Kk1DSbbUIS6Irnb92se1kddzl/wDc+etWzuvLK/d+WtTLlkcnq3hu4sZj95N3zVJpd2beRE+ZStd/qGl22tWXyQru/hZa4/WNDezm2Q7i38W1Ky5UaR/lZ1tjq32jS4kd9/y/dX+GoNaX7Vb/AN1GrD8N332VhC+3av3K39QkS4s3dHUfxKtVGX8xnUjOR9if8EWdW1XVPiN4z+CFheeUPGHgi8giaP5WaSP5lWrf/CGovin/AISqzSNJrVvKut27zWZW2t83/Aa8N/4Jx/FbW/hD+1t4F8VWc0duW16Ozumkl2r9nm/dt/6FXv8A8YJNe+C/7UXjT4e3KNJY6frc3lQyfKu2RvMVt38X3vvVtRjzSkjlqe7KDOI/aX1BNS8ca7f28jvv06H5nbksLOMHJ+oNZf7PsLr4G+0zQ+an2j5l2fdam/FGaPVdX1WWFAFmgIVV5xmIDFaXwH002fwrs3udyPJLI7r/ABL833Wr9z8a1bh/hv8A7BIf+k0zyuG1J43FW/nf5s6W4V/J+0vbbfm2/frN1RkhVNk2IvvMv91quX7IZDNDtCsny/P8y/N92ud1zUEgaRPO2/Pt3fws1fgtGP2pH0OKl/KVbq6dW86bb8z7d1RSXm3akLqNv323VRm1BGc7E2p975qQyI0mzf8Ae+bdXYeJzTjL3jj/AI0tE1xp5iJOUkJPbOV6V0vhFcaHpoUcm2ix/wB8iuZ+M+PP08I7FQsgUv1x8ldP4PAbRtMUDrbQjn/dFf1Z4LK2VVP+wav/AOnInqcXf8kZl/8A18f5zOijXyYQiW3mlZf4v4aW6jtmzG6M21Pvfw1YW0eFm2TMz7v4V+VlqazhhnxMib1+9tX+7X8pRkeZLlj7pkXGn+c6pBCoP3/Mb/x6qOoaLbNjfbLu+7XRyW8LZcvN+7dtjSJ/C1KNNeSAo9t95dy7n+aplLl2Jj7vvHBXWgujfc3bn+ZqpSaTCq75o2PlvtTbXZalofkyJs+VG+Xy93zVkXFn5e5IYWST7v8As1hUjPmPawdTmic7/Z8MbefDuL79u1f71TfYXl3b0Zx93cv3VrQaxufld3Yv93cvy7lpiWkMaPvG5/vblfbWEonrUY+8VLOx8mTYjthf4pF/1ldH4ds7ZcJHD8v3l+T71Y9vbozZ2b1/2v8AarqNAs4VuBNubCqu/wD+xrCXxm8oxjtE73wLp6KyzRwtvX5XWRP4f9mvYvCfh+zuLeF/vbv4l+9XnHgfTXkVbn7Sy7lVUWT+H/8Aar2bwXZzSRoggjZdq7v7ytWcqhjUjDqbFnpk0K7HTzNu1Uj21sR2e6RPOf55JW81l+622pLNXtFaaa2+8m1FZ/mWrEcNyq/uRHGZPuNJF93+9XNGUpS5jnl7u4lvZwyeVM/yIzbkj+6zNU02nzXUchWHa0P3V/iZf4atxr+5eaBIwu/Zt2/eq1ZrtZnW2kRdi/d+6y1tGpymfLynyJ4gb7Qd/wB7a6/dfarf71cnrkO2R5n5fe3yrW/qmoZs2RHVQv3G+9url9UkRMv5PC7W8v8Ai/3q/YafvaHw0eVRuzFk85W2JtLr95m+8tPht0t4Xd4W+b5vv1fj02Zr138lctt/eVbt/DnmMUnSQD+9/FWqlSiKPPExpFaDvGkW37y/xVLDbzXG1H/ufPJGnytXQt4VeaFPJtty7FXa1Nk8MzQ7UaGRd275d/3v4q29pS+yQviMCGN45DCm75fv7v4a29Lk8xVmwo+Zl21FLpb28e+WGZnV933KtpavayDzkb94+35aitiIyiKMff8AdNvTbhGjRHjZgz/7u6un0e++0KiPu2R/3f4f9muStV+zsyOjbFl3Rbn+78tbGk6gkStD5O1tm5W/vNXD7aBtyy6no3he/RbhE2Ksv8S/7Nddp+sQwtLCnzO0qrLCv8NeWafrXmQiaf5n+63+1/wKtux8VTR/O8n3vl3bv71ctSJpHzHftP6pBd/A7U4IYlyLi33si/xecnWsj9ieWSP4d6qIdu7+2jjd/wBco6z/AI96wL34UX9srKdssGW7t+9WqP7J+rNp/g7UYmXKPqhww6q3lpX7LgXy+BuL/wCwpflSPNkubOo/4f8AM+gZtfTb8n34/vM3yr/u1j6pq8NvI8jybJG/1vlvWJceKpnmd5n2LH/di/8AQqwNa17z5BveTZ975Wr8Zpx97mlI9OUYx90s6vfXl1I1ygZImVleTZXG32oJcTTWdyjf7Hyfxf7NTaxqFy0nmQzTIFZflkqhcaluhmRIcOzbpWj/AIl/2a66MoRj7xNTl90ytU864Y7EkWZYtqK1YGpQzORDNwyv/Eny/wD7Vbt15Ls/leZFt+Zfn3blrJvoPLmEPl8fKyMr7o61jioR1LlRnIzIYf3bec8bDY33fvNWB8U7dL7wHqdslzHvWyk27flbcq/erqZFtrdjv24V9u3b826uR+LW+HwPqc2/ejWrK+6px+Kh9Vmv7prhaMvbQPBvCtx4e+KXhNPDHiG8WHVbVfkmm/5aLXnnjf4a+IfAer/Z7+2mWNpflZU+Vl/vVm6pqGp6Hqn2zTS0R3fw13Phr9oiHULX+yfiFo8OopIijzGX5lVa/L1rofUcvLscNNbw3UJ2Rszr83zViTL++KBa9ks/CHwl8VXLT+HvFn2B5G+ezuPuqv8AvVjeLvgT4htYzeaPDHeorbd1rKrN/wB81pH+6Tzcx5ezOvyb8bqY29f9T/49/FV7WPC+vaTN/pmj3Cbk3J5kDLtrN2vHHl/vf7S0vsm5o2V5CrL9pqaSTR7pikkyj5du6suyilup1hCfM38VXb3wdqUC70jZtoy7VPIT7oy60O2eNvsdyp/2V/iqnptxPpmoJMCyMrYzUctrqWmtvdJE/utTJbiabh33VUijoPElx5jQ36Pu8xPnZq56aXzF8tK07e5i1W0FlO21l+43+1WXNC8EjQvwy1MRxiNpjNuOacrZ4NJ5fvQWOoLbeaKRl3VoAtFIxwOKRG7H8KAHUUUUvhAKV/vGkBxyKA27ml8RMQooop/bKCiiilygFb3g04Wd/wC8lYNb3huMLp7unX/fqZES+AsT77i+CJCx+dfl/ir+iT/ggH4T8MfBP9kUX/i3Smh0/wDtS3fVNYjt90jXE3zeS3+6tfhF+x38NLP4xftH+E/AGpKv2e+16FrxpP8AVrCsitJu/wBnbX9Zfwy/ZA+Hv7Mnw813wV4Zvo7rwrrUyapb6bcxL/o9x5Kr97+7W0aMqkXyytI8PMK8oyjG3ungX7btr8Q/Evj9fEP7NfjCKHwWtqtxq9vc3CweTdL/ABLu+ZlZap6L4e/Zb0X4Sr8btL17/hIfFFxYTW15cs+9I7jyjuauQ/4KIfsk/GzVvBo+Jf7Ot1cXyXTfZ/EGhwy7ZI1VflaJf4q8q/Zc8TR6j8OvEHwp8SQTabey6G9zFb30HlLHcRoVkXb97cy13YWnOlyp+8ec5U5V17p8L/8ABEjWbfRP2ybm4upHVJPBt5G3ljJIM9sSPyBr9aNa8WWCxvbabctbhv4du7dtb7rV+Qn/AAR1jupv2tbiOziLyHwjeYwMkfvrfkV+q19Cmh26Xl/c+U+7e63D7dqrX1/HspRzzT+WP6n2nGtv7eV/5Y/qfhz/AMFAdem8Uf8ABRv4o6peXnntHqi2+5f4dsartrktJjSbaj/dVd3/AAKl/aD1xPFH7YPxR8YQyrIlx4tulWSP7u1W2rtpunt8qzJw2z5ttfBRjzHmT+CMSW8UMwh+U/P97+GoVb/ls6fN91F+7t/2qmWZG/c/3m+dmps0ny734Xd96j4iJfu4+6es/s9rZ28N9vdd7RL80ku3bXT+LPFDw2rw2z4X/lrIr/erhvg+1ybW5hsEkd2Vdse3dubd92tXxlGmk3En9vOsXlpu8tq+czSU/bnmYiP7y5z2vakNM8zxDrdz5zrF8sK/3f4d1fOXxx+INx4h1P7CtyzDdukVn3bf9mvQviz49ni06bWbt1EafureNf8Alp/wGvn68u5L66ku5vvyNuatcvw15e0melgaMZR55Hqvij/kkh/7B1v/AOyV5NXrPij/AJJIf+wdb/8AsleSs2OBX6lx7/v2G/68x/OR9rxH/vFL/AvzYKuOTS0UV8PE+dANu5opFXbS1QBRRRQAu9vWkopFbdS+IB21P4KAhkbikq5pOnzalN5MPX71OPvTJlLlK8cDs23+Kt/wD8LPHnxO8UWfgr4e+GNQ1nV76Xba6fptq0ssjf7KrSaboM39rRWG5d0jr8zLX0F41+DHx1/ZW/Z78CftNeENV/seL4j6nqFjomoabdNHfRra7VlZdvzKrbvvVVTljE5/aSlPlifOvi7whrfg2/fSdetnimhlaKVW/hkVtrL/ALy1lrs8uvrXw/4Pj8T/APBLP4h/ET4p6rGiaL8QdLs/h550CtPeXs3mNeqsn3mVY9rN975q+SWZFbf/AA1zxlzRNosYSjtvAwKkXYzLs+9USj5selTQtDv+T+Gq9CpblzSJ3ivo7pOHhljdf95ZFr+pO61C5vPDOg3l580jeHtPby1T7ytax1/LZZbJXQsfvSx/+hLX9Ot9qkNn4P0Gz+Z5pPC+m/6xG2rGtrH/ABVz4j4TlxHwmX4iuIVbZM7RbfutH8vzVw/iS6SNXdEZZfu7mra1zWH4TyVdlbc235ttcfrmoOqh55vMX5t7Mv8Aerj9nze8OEpWOe1y8SO4d7m2VSvyq2/7tcL4kvUVpktnmj8zb+8+9XT+JrqaH5J9qLs/1jfN96uI1ybybiRHfP3Wi2/dVq8/ER949TD1OU5fU5kkkd0dS/n7trJ91aoNNGrNlJCNytL8nyxr/s1c16Z/+WKb/n3bk+XczVmtGlrFvudxWNdzqsv3W/8AZq5v8R6dOV4aFuzV+jzbNvypJI+5tta2n75reN5kbMyfP/dkX/erEtZi2xRtxJ83mKu1v+BVoWdw8f3/ADo1ZPkWPayt81aRpx0NPaHD/tOxtH4I06MquF1IBSv8I8t/lrldfvYbX9lXz5UIMK3LAr1K+a26un/aXuVl8EafD8xZNVwWbv8Au3rj/E1xj9lWZEiWVo1uW2scbfnav6Rxi5vo1YH/ALDX+VY+EU/+M0rP/p1+sT411yT7VdNNDKz/AO1/eqhb+Gf7SmDnqz1FqOoPCqPH/u1p+EfF2m2cg+2JuG/7rV+Mx2PQlzyOq8B/BFNYlR/J+RW+ZmTbur2jwj8IfCWjwrc6m8f3lRfn2sv+1Xmdn8ZLbSYVSw8vy1+7t+9WJ4q+O2pTLJ5Nzu3J/fp+2933Imfs5ylzHqfxa+M/hX4b6O0OjmM3nkMqH5a+V/HXxU8S+L755r+8by93yrupniLVtV8Vag9zNMz7apx+GRIA7/d/u0pe9HmZtTjGn9koQxyXEm/5i6/drcVUsbNJmfj/ANBaoI7BLRdmz5l/h/hqK4+2X2ET7v3XWjlQeZn6pq1xqV9s+bZv+Wuk8P3kem2oy67vvbqzrPQ0t286ZPm+6q1qW9nZ7VR3z/st92jlC/vWLIvry+Zk8tlVvv8A+1XQaPoNy1qjujKPvJuqv4T0+zvJm+zW3mOrLsVfurV3xdDDdXhhudVm+4qy28Lbdv8As1XuE83NsWriTw9o8e+/1W3SaN93lq9ZPij4oaVY6eth4b3NcSJ+9Zk+VW/2a5nxp4FeOxXVdK8xkVfnVn3Mtcvp+9VZHdlrMqP8xozXW23d0fczfM7f7VYV1I8sxd6uX1xt+R0Zd1ZxJ3ke9BrGIU35F96dRV8qNAooopgLsb0oXofpQzbqFO00pbEcrHwru+d3qSNU8yo1Z4/4Ny06ESbt2zmlykyLNvHMz/J/3z/erotFj2r+8TKr/sVjabDtuFdOa6jT1TT7d7r+FU+9RGXKZylzGJ4+1BJo4rBYdv8AFurmqt65qE2oalJNI+4L8qVUqjePuxNvwJatNrKOEyV+b5a1vEEgm1R5tmxl/h/u1V8DLHb29xdhPnVfk/3qtXC7o2md9xb7/wDdpxjzmUpe8a3w8uG/tuK3boVYr/3ya1vHFvHcXyI4P/Hv2+prD+H5b/hJbYEEfK/Xv8prc8aSoNYgidT/AKjO4dvmNfcYb3eAK3/X1flA+ipa8LVP+vn/AMicncWPz73T/vmm2s3kTKj9P9qtjyd6tI+7/gNUpLFBIHT52X7y18LH+Y+YLVuqXEjPC6j+/uqQXU0bb3fa26q9nLHFcbHSrlxGlx/d2t/Ft+7TA29B1ort+8v8Lbv4qv32npqkLI/3vvfL92uTt5JrdWeFN237i7vvV02h326Mb0yn/s1Eubn1MzAuNP8AsN15JT5d3zKv3q0GYzWZh8lfmT+781aupWMN4rOiKh3bV/vVkzRvYfPKnP8AtUGhZ+H/AIqufC/i6x1iz/4+bG/hubf/AHo2Vq/UD9pb4Y6J8bP2jdF+JCJstPGngWx1KC4+1Kqed5O1lb/dZa/JrVLyCG6Dun7pm+dmr9Ffgt4o174n/si/C7xnYXjS3fhHXptEuJJm/wCWO3dGu3+7XTgpf7SvM58VD91c8g1DS3g8Ry6LJIHKXZhLqOGw23Ir0ibw7N4R8O2kP2NYYWi3eTJ/E1cp43s7lPjDc2sqR+bJqyHbEpC5cqQB+dewfFTWofF37POg39t4Vayl8L3k1lq1x5v/AB9NI3ys3+6tfvPjbH/hE4d/7BI/+k0zwOHJfvcVr9v9WeQa9rVnap5k3ysqbtq/xVxesa15czpJHvT+8396rmvapNG03nfeZ9sS7921f71cheX3+kDfz/vNX4FT9496vUlGOhbOobt3nFfm+9V2zuv3wjCMq/d3VzjagiyPv8t0b+8lX7G48tdhf7392tv8JwSiZnxVuFnewVV+6snzf3vu811/hF2/sTTHBORbQ4I6/dFcV8Sp1lNkocEqsmcfVa7Hwuxbw1YkD/l0jGAfRRX9W+C3/Irqf9g1f/05E9Di7/kjMv8A+vj/ADmdOvkrIkztM7/N95tq7v8AaqaOby5lRH2FlZdy/d21nWt5tO94WCRr8yt/FVqK6eOT986uVfcit8rV/KZ5kpQL8mF+S1dnRUXdu/vVb3JH88cLNui2/N95azYblJI96Jlo9zL/AA7anjuLlLVd7/7XzfeVf7tPlI5eb4RuqKkcbOj8bdvzVj3TJDbtstt/y7t0b/d3Vo3lwi28qOjY+Zm8z/2Wse4uH8pAjxlvu7m/irnqcx6WDl+8Kl5IJG2JaqjfdSqscf8ApGZoWf5tqVNdNDJMrv8APt+Xcvy7qrTSbpPJfb9/cyr/ABLXHKUY+6fQU9h8MjzM6I7ZV9u2tvw1I6zeTcuqqv3FZ/vVz6tBNJsT5dqbqvaTqD2rq77W2v8A3N3y1jUXu+6b83Ke0+B7p44Fe8mjZ1dfu/xL/tV7f8P7x2hheZ1d1+fzF+bdXzj4K1pIz9mSZVaP+Jv4t1exeAvECW8tvC8zFJPm+VvlVa55c8tSZfCev6bePdXH2a5ttw+99oVK22t52T/Us5X5omb/ANmrj/DurabcbHhuW3LLsRt/+d1dHpOpQqwR7ba/mtukb5d1Yy5vdfKcXumjZbNx86T/AH/9mkjjkhmZ0myPuRR/w024uHmhVbb5fvfNVDUtbe1h8l5o2k27tv3VrT2kdwPinUr50ZrZHXaz/Ozfw0i2731wZpnbbGu6Vl2tuasMalc3C/JcqVZ/u/xM1dB4dt5FKXLw/dfc/lt5iq1fqscV7p8lTwvu3NXR9H3NjYrrtX5WrpNP8OxqqXLpHuVfu0zR7JJ5ldefLT55JPl3V0+m2O2MO9spT/np/wCPVy1sdKUdJHZLC/CZy+E7a42PHbMEj+b/AIFS3HgtFy9ydu1/ljb7ys392u00fT5poRM+5hIu5G+7/wCO0TafbRloQVUfKit977v3t1cUswlGV+YxlhIxPO7zQ4Y40mJYmbcnzfeh/wB6sy90lGuB9j3Rq33WZ938Nd/qOlu0jW0PmBNu5WZflbdWJqWl/Y8vDbYprMPabyJjhZQ2OWV4be4RHRXC/wB77zNRHdbfMd/MVP8AZSrd1ZzWsk2x/nml3Izf3azrya2kgPk/cVdrrt+9SliveNPqfcvWOtPp+N+7f919z/w1Zs/EyW8j7Jtw/utXJXFylvbrapt2x/3Ub5f92oG1p1jSJ/k3fLuVK0ljubYyhhe5ufFTxGuq+CLyFHGN8Pyj/fFZnwY8QLougXSsp+e96g452LisLxRqX2jRJYTu/h2lu/zCsvw/rbaTZSIXOx3JZR0PAr9vy/Ee08B8XP8A6il+VI8adFxz6Ef7n+Z7BN4y8uHZZ3k3m/d+Zvvf7NZ954ktpmMyTMxk/wBbXmVx42Ta375j8rfKv8W3+Gr1j4gubiEPJPGGZfut/FX4n9YiqVme1LDzjL3Ttl1KGZmme5k2qvzfN95ajn1H5h87P5ibdqv92uWsdYdV320zN5m5GVk/9BrRt7lNyunlsN6r8vyszbf4qiWM5Y8qLjhryvM0dzyRp53mf3WZvm8ukbfIzJvZtqfL8v8AFUNm0Mm25Sb+8jfP8tWWUiRH+XbHFt3L92s6mM5Tojh5SKlxHC7b0T5fl+8275q4D49Rp/wqfW5nTf5dlI3yptr0S+j8yNIIfmZkb94v3a4r42Wf2j4U67Cm4pHpsjyq38W3+7WWIxntKHLzG1HCxjUufGGrR+dYr8zNuRWRWX/ZrlriF7W43p/ertdaX7HpsU3mNtZfl3f7tcNqFx50pP8AFur5v3T0o/EEOqTQurrM3y10vh/4j6/p8yPDqUm5fuNurkFQs22rWn27s2x9wH96pK5YHqFn8XPFc0QhudSaaLY37u4XzNv/AH1RceJtH1Bn/tjQbG5Vovk2xbf/AEGuE86aNWRH5WrVvdP8rJzu/u/w1UZcsjKWxvyaT4Gvv31tok1vtTd+7n+7V2G4tpLNrWHc67dvzJ81YlrM7j7m1W+ZttaelzOs++eZsL/dWriKUv5SHXPCt5dQxbEVo9n3WX7zVx+reDNV0+U7baTav935ttetasttrmi7PmR9vyMr7WWvO9W1LxJ4dmktZpv3f95f4v8AeqfhHGU+Y5QrNbt8/DLT7i688bJk+Ze9bX/CTWFydmpaVG3+0v3qztaawDBrZOWX+H+GjmibfEUKKKKgsb5fvSqu2loqvhAKKKKcdgCiiimAUUUUAFFFFABRRRS5UAqru71vaZNNb6SXTbtrBU4b5/mroLKORBGkO3G1eDRKJjVPov8A4J36fNpvizU/HiQr9pjs/sthcN96GRm3M3/fK1/UN8OPjTD8cf2d/CvxH0PWFlttW8K28VxD5XzRzRxrHJ/49X84/gX4a3/7O+n+G/BOqvt1C80iHVr+FotrQ/aF3Kv/AHztr9l/+CH/AMUofH/wb8X/AAdvNVWS48L3VvqNrat8221m/wBYyt/vfw10YeXLM+exVSVSWh9WR3z+DdQstHv7zyZr6waeCTf/AKxo/wC7Xg3xg8E6b4x8WXfiqHw/ArxabdCWSCJfNaTY3zV6N+2Bealo/iPwdrelW0jxWss0DyKv3VkWvO/j78VPB37P3wg1Lxf438UxaZeXGmzraWwXdNeSGIhViX+9Xe6kKMlI5aMZymkfjR/wR68VeH/BX7U+o+I/Et+ltbW/gq9PmyOFAbz7bGc17n+1h+154w+Nl1c+G/BN61roW9vtVx92S4+Vv9X/AHVr4o/Zca2X4kSi8fEZ0yTIzgMRJGQM/UD8q9i8eeNrDS9Fn8jbKzLI21V+b5Vb5mr0fEzE1KfEXInpyR/U+34zUnntl/LH9T4x8KWM154g1i5cMVbV5v4/vfNXY27eSvk/N8v8Ncb8N43vrOaaZ9rzX8j7m/2mauz8lNyYTc6r8nPyr/vV8vS+A8l9R80LyQ79i4k+X5qjbYvyPCrj7v8Au1NcHdD8n/AttUmj27/ORmVvu7av4gPX/gD4o8N+CvDfiHxD4hhjluI/s66WrN83mbtzba4z4leMrzxdrFz4h1K58tPmd493yqtUNAkQ2LI+3Yv93/2avMPj78SHuJj4S0qZQv8Ay9NH/wCg14lajKti7HPHD+2q/wB04z4keNH8WauyWz/6LD8sQ/vf7Vc2Tnk0UgGO9erTjGnDlietGMYR5YnrXij/AJJIf+wdb/8AsleTFtvNes+KP+SSH/sHW/8A7JXkrLur7vj3/fsN/wBeY/nI+k4j/wB4pf4F+bFooor4bmPnQoopPn9qoBaKKKXKgCgNu5pU+8KNqKo2fepRAaowMVoeHr99PvPtMfXbtqhWx4I8O3vibxDbaHpsavcXUqxQKzbRuZttPm5feIqe9Cxqza5e6lqiXM0zZ3L9771faHwzsPgV46+F/wAN9V/a0h8eXPgnwK9w32Xw7qKt/osknmSwxrJ91pG/iWvmzU/glp3w/wDi1/wrXxp8TvD8N3byxrPeafdfa4I5G+bbuX7391q9G/as+KfivX/CGlfs+eGvCOhwXWl2qyXl14fud32i3+6q7f738VZ168ZWgt2ctFa3Z6f/AMFPNT/Zm/aA+COi/Hv9nj4kaD4L8I6JeLpPgP4HWcvm3VlZ/wDLS6uWRv8Aj6kb94zN/srur4El37uKdqFleabePYX9s0M0b7ZY5F2srU1mTjfTjGUTtGsNslDO7Sb0FIxy3FSW6/Mc/wANBHwmv4R0/wDtLxJpump8pur+3i/76kVa/pe8TrDa2trpriZkh0iziWP+H5beNa/nO/Zt8O3Pib48+CPDyQ+c+oeL9NiSFfvf8fC/dr+ibx1ffY/EF5bb9zLKyIzfN8q/KtcuIfwxOat0OUurxJrhoXtmTy/7zbVrndUaaNmRPl3bm+at3UGkkaV7lI1XbtZV+ZqwdabzF3vuJZfkk+61c0vdiXH4zj/Elv8AarcI5VFXaz7vm2tXDeIlmXels7f7e77tei64sK7/ADhGEjRfN3fe/wCBVwPiJbnz3tkTzPnbf/dZa5KnNOR30YnD6pI9qyJMjJ5nzt8lU5LqY75NnKv8y/eq9rDbt1tCkjpub5V+b/gPzVlwrNuWaFG3b9sqt96ueUZndGRYt5po2810aXzP4f7tWbO4haNndJNiy7dy/wDoNVI/J8tbl7aSOTzdqbafCsPzWybs72leP+83+zUx/vGko80Tiv2hLjzPC9nCZ2bZqOQrfw5RjXMavN5/7OdxZmcJGIrkTZfHBZjW78dznQLc/N/x/rgMM4Hlt371j2GmQax8KVspZXUNb3AbAyPvmv6Pxsr/AEacC/8AqNf5Vj4in7vGVb/r1+sT4I1PVHabf5e3/ZqlDdvDumR9n8NX/E2jvZ39zZzSNuhuGX5vl/iqlPapCvzphW+ZK/F4fAexIkXWJo1+eZqqSaxNNw75/wBlqpzF8Knfd8lMkHz7Tz/e/wBmr5fcJujXtdchjVUfcP8AarUj8Raa0P31+98n+1XJbXZtn3V/hp8e9V2f+yVP2RnTtqFg23ei7l/iWmSapCy7ERU/iXbWFb/KPv8AzVajbzJ1d3aqlLsZk82pMi79+41VutQuZN0m9sL93bUkkfmK7u/y79q1YtdOtmcfbH2Cl/dKjsR+F/GWsaDdC5tRlV+9XX6b488PS3BebR5N8j/M0j1V0fRvDctv8kP71fv/AD/eqa403R/tOyzhb/baSq5f5Q5kereFNC8K+MPD7zwo0TeUyyxtt/zurw/4keE38G61JCnKM37pq9e+FrTabo9xM8O1F/h/vVy/xs0uTX9KbWQmfL+4y05e8Ze+p3PFruZ7iYu9M/h/9mok++P9+koOvoFFFFBoAXbxRRSbflxQA5V+b79G35s7KSljUSHZQTzMlLbgP9mpI49zLzhqjVDJIz/3as2qozLv6fx0+Yk1tFtst52xSqt8tafiS8Sx0V0L/NJ/t1Dpdmi7fk3/AMVZPjS+Sa6FjC/yx/eWp5kZKPNMw6WNcsOPlpKn022+1XaJ/tUcyOk63QbEW+i7OvmfNuWmSQ7/ALib6tWMyMy2bv5SL8v/ANlTpoX3MqPhf4G/vUonNLYu+B4pI9dty+Od/Xr901a+IUoh1mB9xBNtgYOP4jVbwWceJIYc52q/P/ATUvxLEsmqwQxHBNvyducDca+6w0b8AVl/09X5QPpKN/8AVap/18/+RKtvJ5kIf7zf79LJGnmJ5P8ArKzbC+eH927/ADfx1sR3VtJsR4V+5uT5K+H+wfMc5UWHy5/Ozhd9W4Wh3H/Gkmj+VtiZVlptirxyNJv/APHaUdh/4SWNdq/c27qs6XffZW2edsG/dUTwpxNvYbqJLVG2jZll+b5qPigLmsdGtwl1b/uXVSv8TVlatD9nkb5/N3fNVjR7iNown3Gb7y0atGW+dPvbKuJFuhyHiRi1tL8/zN/C1fZ//BMXXv8AhYXwV+IvwZ/tJo9QhsI9b0NV/wCekP8ArNv/AAGvjDWm8yGdJodrfwV61/wTO+OVn8Gv2qPDOp686nTr64k03VI5H2p9nmXbub/ZVqqlKUZ8wq1PmpWie8X+q3938RINW1lmWb7XbNK7pg4ATDY9wAa+gNFs7bVPhh428B6rqX2x9Ws2vLBWfy1hmX5vMX/a+WuL+M/h/Tvif+27D4L8PS2ttb6zrui6ZbS28eyJN8NrBvA7DPzV6hpnwr8efsu/GSz8JfE62jtP+Jl9nt5rhtyyR/daT5q/ozxlw08Rw7w/Vj0wsLrycYHxWSVvZYqvTfxOTt63Z8R+JNWdbrfv3qybfm+XdXOXmpJCwR3+993/AGa7/wDbK8Kp8Mf2kPFPgm2kZ7e3v/tFg2xV3W8nzRttryKXVISw37mP92v53+E+pjeUOU1ZNShj3Q4Z1b+Jas2OoJlXTdvb+HdXNSak7SfuXX73yrUtrrDwyO/nN9/+792lGRUoSXuo2PHFxHcTQGOHywA+E9Old14UbPhexYdrVev0rzC9vBdwxYfO3d169q9H8LyBfBNvIzHC2rZI9s1/WHgr/wAimp/2DV//AE5E6eMFbg7L1/08f/t5sW9wkkWPPb5k3fL83y/3anju7e4UI6fM21fM/i3VythrCLGHhdVVf4dtaK6mk2/zvlEfzOv8Nfyf8J58qfvHSR3iKoRHjba6ttqU6g8cm/zt7K/3a5y3voVZE8xVWP7q7P8Ax6rJ1RGtzPMiqm35GZtrf7tPmnGIRp+6aGoX3nL51zMvyr91vvVzt1qiCYw/KNrbtqrVbUNY/d4+VX+7838P/Aqx7jWHa43pMu5vl3VnKR04OPLPU2G1LcpRE2Ju/i/io/tGH5pX27WdVRVX5t1Y8V15kiyb9x+98tPkk2q0fmf6z5lbf92uSXxHvU+Y2Li4SONf9J2D+8v/AKDSx3zxSfJ8m7+FWrMa6e3VNiK23arr97dU26Zm2JJHhdzO2yo5eU2lI7fwrrv2dvLe5Vw1emeC/FSQ2ohmufn2fKsn3tu6vB9L1Z44RND8m35v+BV1Gk+JkVVe52r8v+sX5vmqJR+1EyqSjyn074X8VbV+zedlGT/Vt91W/hrrtN8VFlxc3LSCNtyRq38P8VfN+h+OvJ/dzTbVZflbd81dlpfjf5kSGb7vzrI38VRKPc5JS949r/4TR4bMwQosifegXftZv9msfVvGTvHK/lrsb7/8X8P3a8+m8cPIw2XWW/vb9q1h6t8QPLiaa5mWJm+8vmtWUqfNEXNCJ5Ho+oeZJHvSNV/jj3fKtdr4ZkjjjJSONF3bWhj+Xd/tLXmmizWccbTTTfu9+35fvNur0Lwu32ZYn3/d+XdJ/F/vV9ZWxXL8JhTw8fhO58O/JCsIjVNyfdb71ddoMiYZHTy2+7FHsritLjhnkExdZtv35N/8P92um0u5aGNJrr5UVtyfNubb/DXHLFSlqbSoxO10eaZm/wBJm/u7JNu2rs1qjZuYQuybd5q7/wDx6szRbi2+yb4JmmaP5nX+GtKO3S82pMcFk3eWv3VriqYocaRn6pZuqo+zeYUZtqvuVqwNXtnk+5bSK0m35f8AZrs1VPLSN3/e/MvkslY+sWbr5ttDNu3P+6j/APsq5vr0YyKjheaWh554mjSVmubban73ZuX5q5fUZptrQJ8p/vbK7nXLOGBXj85Wbezfd3LurldQtYPlmhdmlb5W+X5W3f7VV9el3CWF974TjtWvoYv+XZWeNNrSfMv/AAKuZm1h2kVPtLZXcrt91a6bxJapHbtC7soX5drfxV5/rn+jXTp8zP8Ae2s/yr8tdVHGe0OepQlEty6q9ztt52BfJBA7453Vl6/qUtgU2OcHnaO9VtK1KSXWUttoAZDu9elUfiHexWs0YfqIsj8zX9BZXVv9HvGSj/0Fr8qR8tWp8vE0I/3P8x1nqkbXDPNuba7bf9mum0O+j8tHfds+8iyV5npupR/aN/nN83zV2/hPUp/L8nzsu33FZPu1+E+2R9F7P4TsrOZI2R791VP7y/w7q19Pb7Psh/1jfeXzP7tYOnzT/aInmmV12bn2pW9YXXkt5zvz/d2fxVhKtyy+I2jH+Y2NL8lSqfeeT70P+z/eqy2yRmfYpVvvL/D/ALNU7FZrhmd9rRbd3y/w1ejZFhab/l3X+797d/u1zSxkvtG1OmRyeRHFvSHZL95tu7av+zXH/FGGG4+G+uh5ss2myJu/us3+z/druJrh47NnSFh8v8VcP8VGhsvhjr1+kKySrYM393y13L81Z/WpSNZUeU+MfipfQ2dvb2EKN8q/N/vVwDN/HW3491l9X1l5kfIrL07T5r65EUaMauMSY+7G4WNv58oG3vW9b6e8NvwdzNWzoPgV/su+RNrtUOvtDpcLIgyd22r5eUz5oyMb995zI7qTv+7WhpNqm754WrDuNURmOxG+Wki8TXlvIHR+KXwi9+R3lnojyf6naE+9u/i/3akj02O3WLfcqdvzOzfw1ylj8Qr8N5M77Vb77LVzWtMudXi8+x1oMjbdiCnKXMKUeU64XlhIv2P+0oSP+utRX2kw65a/Zpgrx7PkkX5q87m8Na7ExeEM4X+JXqbTE8d2y/6HDdFV+bb/AA1MecqMY7lXxLoNxouovCfu7vlrKkZ87Grc1vWdSuBs1WxIdV/5aJ/FWHM7yNuakaxFopFbPBpav4ihv3/bFIy7acq7aGXdUALRRRVxkAUUitng0tEdgCl5U03ndv3UtQABt3NFIq7aWtACiiigB8ce6Rd/Rq9b/ZW8Dab8Rfjp4W8Gart+wTapHLfsz/dhjbzG/wDQa8osf3kg38ba96/ZZ8N6lZXk/jCwlkSZf3VrIyfdb+Lb/wABqZe77xx4qShE+sv2ttY/4Sb4zT+KraZXtplWK3ZX+7Cu1VX/AIDtr7F/4N/viNZ+Ev2rta8N3mq+UviLwfNAyyfvFkaNty1+ful2tzdXn9peJHzHCn3ZE+8396vd/wBgH9oCH9nv4+W3xatoVuIdJsrj/R5H2rM0ke1VrGnUtLnkeI5c5+wv7ZX7SnwZ+G/wz/4TDx7ryxLp9xG1rZx/628mX/lmtfkN+0x+1B8Qf2k/Fd14w1qOeOONZF061nuN0VnHjavlr/u/eqj8fviN8SP2kPiBe/EX4o/EWORWum/sjw/ZxeXbWMP8Kr/eb+81eX3+jaRaW80i69c3CGGTcol+Vdw/hrlxGOnWqLtc0px9nJHkX7PkVvN47kiurjykbT5AW3Y/iSvVPHWoeEtA8F6o6TRuWtZm3RpuZm8uvJvgKto3jaU3qKyLp8hww77kruvjV4gtdF+Geq39nCqFdLmi2svy/Mu2vrvE6LfFit/JH9T63i/3uIEv7q/U+dPhnbvH4dgm8nmTc25v96upk3w52J8v3vm/irn/AAP/AKD4Zs4Uh/1kS7NrVtLM8sf775T/AHWrxIR0PGqfETRxpbxtMkzFdi7VqpJceSC8nyt97b/DUF1rltHmH7Ts2vt2tWNfeIkX5IdpT+9S+1oLljI1PEXxKfwb4Puktkj+0XDfupv4l/3a8JvLua/upLy5dneRtzs1dB8RNWlvr2GD7VvRVY7A3CtXN1MacYylI7KNPliFFFFUaHrPij/kkh/7B1v/AOyV5NXrPij/AJJIf+wdb/8AsleTV9vx7/v2G/68x/OR9FxH/vFL/AvzYUUUV8IfOiMMjiloorQBFXbS0UFd3FT9oAooZfmye1FPlQCt+7au1+BWr6bo/jb7Zf7d/wBguFtWb/lnN5fytXE0b3Vg6Nyv92plEnlRtRafMt09zeTbn3szSb/vN/eq5bwXjauurvrcnmLt2zM/z/8AfVYQ1W5CFM8GozfXLfxsKv3OUw5KvNe5vfEO9stW1xNRthulmtla6bfu3Sf3qwF3ru30bg0jO9MkX5uanlN47gvycI9TRsqYTpu/vVFtO75KsQwzSZ+6aklq59Lf8Ep/Cv8AwmH7ffwt0qa2jkhh8RrdP5n/AExjaT/2Wv3D8V3UIvJZnfd51wzJIv8AeavyN/4IS+CpNY/besfEkyRvD4b8L6hes0n/ACzZo/Lj/wCBfNX6x30223+R94k+8rP/ABf71ediJe8Yv3nymRdN+7d/m+V/7n3qyNSie4ZY3s22sv8Ae+Za0tQa2W6khjvGcL823/2VarXiw3UaTfbP3f8AyyjX5Wkrm5urOqEfeOV1a1cRuj22X/5a7n+Vv96uS1LSUhYiZ23yP8vlv81d/qcJaRke2XLbvNb+Jq5i8sZppJSzyJMqfJtiX5f9ms5e9E6qcTzTVNHcRo6Iqtt2urL92sSTT3jZ7Peqn7zbl/75r0DUrFBueZY5TMrK23+GsO6tLZQ1s88hRtvzNV/YOnlOVW3uo4/J2fMsv72T+FarFZlZJ98ed27zFb5q3NUtUWHfbQt838O/5WrNuP3yt9p3IJNv3fm2tXLKjKUtS170fePOPjpNG/hy3CocnUeWH3eEYYqLwRaC/wDhxHbsZkCmRt0KfM3znvU3x3Up4fgjWUFF1EbQGzn5G5qHwDdtF4GtlMhG0y4ZG+ZRvbNf0Tmqmvo0YFf9Rr/9JrHx1CN+Nav/AF6X5xPiX46eG38L/Ei/heFkt7iff+8ri9auNtqnloo2/wANfVf7VHwpTxZ4XfXbB988LfMvlfM3/Aq+SNehubeQWdyjK8bbZa/EsNW54nt4ijOjU94oPvkZfn/iqXy3Zdg21ArbZP8AZ/u1Pbx/effk/wB2uzm5pHP9gfHGnmfOOfu1GzIsjfPUnmeXGW/hqv8AJ5h60wHnMcm90q5axvM3yJ8y/f3VWWP94zu7Y2f+PVoWcLw7X2Nv+8+2pjHmIlEl2/Z1bem75N1Vr28eSZUR/k/2aTUL6ZZGh34Zvvr/AHaqRtMzcJ/v0REdDpd5cqu9HrqPD+lzX00aPJ97b/HXJaLE8zhN+0f7Ner/AA50eHyfM+yqm35Ytyf+PU+XlHLm5DdTTfJ0m3sLPax/5a7amvvA80mkzb4VZPK/3fm/2a67wf4Vh2/apnXcvzfKq7WrT8QWyXDPbI+z5f7vy1rKRhGX8x8ReK9M/sjXrrTfm/dyt96s+u4+P2hpo/jybZ8wkT5m/wBquHrM76fwhRSK26lpR2LCl+ZaSkVsimApbbzT9u/GymsgUCnBjkvS5kAQ/erT0uFJm+dcfw/LVJPvCtzQ7dPO2O+2mYyNeFobO2f59u1PnridRunvLx5j/E9dL4uuntdO8lHbczfxf3a5NQQMGgKcerFrW8OWbrI038SruTdWZbr502yuq03T/JtfJ2bn+981V8RVTm6CRt9nb59x/irUjH2i3+RGG75vmrPlXbtSCNsb/vf+y1bsbxPL2fManl5Tn+I2fCtssevQSA5O18/L/sml+IaFtVgKNtJt8E+241J4WVf7XhYIRw3Vs/wmk8fFxqcLJ2t//ZjX2+G/5N9W/wCvq/8AbD6aj/yStT/r5/8AInMTxvCyom1j/eqxYXE02Wf5T92msJvM/efKrUscZjbfvr4qJ86ajCTcHh+991N1AmmWTZvUf7P8NQafcOjeX8rMv8TNVtY0ky7x/N/s0f4TP3Bbe4SSRYXDN/eqxHMlxDszt+Xb8v3ttVYflj3b9q/3qmVtuHRGdf4/4aWvxE/FEltr77LeCFE/3K2br99p7P8Ad2r96sdZEkVcJ93+Krcd1NJb+T/Ev31/vVY/h+E5fW4dtw6Qu33fvNXN6DqEmj68t2szK8b7ht/vL8y11HiLerH/AGv/AB2uEupdt57K3zNWZpT94/SD9mrxhceOP2ivhn4vYHzbvxP4fZhIMfMstupB/Fa/br9rD9mbw9+1d8HY9N8SaD9j1zT1ZdD1KHbvaRfuqzV+BX7EurynWfhvrFzOwMfiCwfzO4VbxcH8ABX9HP7Hvjf/AIWXpep+GLZPtyWd0r3TSfeh3L8v/Aa/o7xZxEoZHw3G+jwkL/8AgFM+Jyugp1cVJbqb/Nn4Lf8ABYDwDdeEfF3gbxtc6bHbXd1ocmkayu7dL9ot2+VpP95a+Ln1RN33NjtX7Uf8HIHwDsD8H9Q8W6DpUgvdL1aO/t5obfd5cf3ZVb/4qvw9nvPMk3u7YVfkZvvV/P8AiKcqUrHvYOp7W7fxGg2oJ98ph6fJq37sb2Zf77LWI15tC73+VqIr/wCXYXVq5ZS5Tv5feOs0C++2QOFB2oRtJ716t4blH/CuRIf4bObv6F68a8DSGSK5LKQdynPY9eleuaFNs+FE03TbZXR/IyV/WPgp/wAimp/2C1//AE5E14yS/wBUMv8A+vv/AMmcvY+JHhZdjR/c/wB6trT9e8+HZcj5W+ba33v92vMLXxBJ8syP8rN83yVsR+KJoYf9TuP+196v5Plvyo45e7I9Ej1hGt3jR8RRy7l21UvPF1tDG0zorqvzferiZfEF3I2x/uN9z56jgk3TfO6r/eoly8woxly3R0eoeKHvLjYj7Fb7q1XW6Rpd7vtZXX5fvVkRzJG+9EZi3yvUqyQ+YNnyt/EzVMuXoddGUYm7DcbmR7Z+W3fLs+WrEcyiRVd8/K38FY63k3+u/vfe2/3at29wkML7IW3fwbn/AIa5uVHo0zUjbz9yJHu2/c+apPOeRFmm2r/cVapQ3G6Mps/3/wDaqa38m5y/2nfub/O2ly80Dp5UWVm8mOPZ9xvv7v71Sw61NbyRXMO35X27Vaq8dw8duIXmjXcvzbfmpvyLH6/7K0U4mFTc7DS/FSSQh96n5vvbvvVs2PjSWGRHbzNk38TP92vNreaa32iS2Zvm+RVT5lrRt7x/LX9w29kb+P8A8eq40YyieZWqOnI9Gm8cPHB+5f5lTa/zbvlrB1bxxNdbLYXLFl/i/u1y/wDaF5JuQv8AJGm379ULy6fcvz7F+bbtqvq5j7bm+I3PDd/5zfJNtlX5vO3ba9C8N6ttCXlsiozff2vu3N/erxXQL5LyVd/yMz/eWvRvC15HDJvS5k3Km1FX7rVMpS5T2uWP2T13Tb6CS3SZJsTb2+783yr/AHv7tdNoN4iskibv4WlWP5ttea6Hqzwsj20zeY21du77396uw0HWNPS5ZI5v3u9V8n+L5q5pSqxiPlPTfD95DJIjud3y7tq/xVu6fJDbqkyOwfzWfbD/ABf71cZ4X1RFUO7qjR7mT+9u/u11NrJNtV3TduZWTb8v/fVediMR9k6qdOMox5TUvP3iB5kk/ePu3LFWXrTXNzG+x44Ym3L5kn+z/dq/Nf8A2eJpoXZ9vzPu+7WTqEMFxtuUhkPz/JDv+7XkTxEaf2T0KOF+Fxic5q1ugmQvNJE/3Yt33ZK5zVtJ+yt9muU85d7PF8+5V/2q7bUltriNfOhbdI21Vjf7tYGsWKW8AhRGRfvfL8ytWP1z2kbXO3+zeaPMeWeLNP8AOjf5N+3czeZ8vzV5l4gtZmvHTzv4Pnr2TxJortGZJk2y/wAar92vOPEGgzLHMkiMu1Nr/L/DXr4TEcs4+8eTisDLc4rSlaPxFDDIoJAY7h/umsb4uXHk3sSmVgDa/dVc5+Y101lYpBqcT7W3puVyfoa5T4xwvLqFvsfb/o3X/gRr+m8nlf6OuN/7DF+VE/PcTDl4sppf8+//AJI4/T9VcXHzvhl+VK7vwXcOzJvmYHf8jN/drzrT43W5/fJurv8AwbavJIkL7sL/AOO1+GRie5KJ6L4fuoWmELvIyfwNt/irrdJZFtf3yLv3N5qs+75f92uW8N2aSTKiKuK6/TY7aGRUw0pmXazL/s1zVo+8bRlY0rNfsse9E4b+Hd92pVjdpGfyfuv5iN/s0Q2sLXPz3Ku8afOq/wDoNaVj+8jWZ0/1aM27+L/drz6nNE64lXbM1vJ+52oz7opJH3fe/hryr9pzUH0f4M+JZkmVE+xKiL/vNt216/qUkE1gmx5ELfMsezdXz/8AtvapD/wrtvB+murI1wtxesq/N5m75Vb/ANCrHCxn7W/2S6ko8p8c2ts+oXXzx16b8O/hskdv/aV+ixBfueYv3qs/Cn4R/wBpSf2xqSYgjfd/vVsfFr4haP4djOiaJcruhWvaj7vvHDLmloYPjDxRZ6DZvDCMbfl+X+KvLtV1i51O586SZsfw0/Wtdn1q486Zv+A1TjjeWTatH95m0Y8sRA27mlVNxwtaGneG7i8RrmUNFDH/AK2Rl+7S3C2ttuSwTzf9pqPfDm/lM5lcL9yr2ja9qujyr9muWCb93l/wtTFjUE/aZsf7NT2MkNq29LbNKQuc2JPiB4tkj/0bbGNu35Yqhj8QeMJJPtL6rcJ/Cyq1MfUJPJEOxfm+batS2Nrc6hOsMiMTJ9ynGPMZc3LE6HwXcf8ACQLcaf4ks47kMnySMvzf99Vz3jDwPFp8LarpEivHn54V+9HXUQ2dr4d0/wCzWzs1zIn72T+6v92orfTWmt/9JdYYZPvs1MUZT5zzJOv4U5lzyKta1arp+qTWyPkK3yNVTzPaszqHUUUVfKgCgtt5pGOBxSff9sUvtAOoooo5QCikY4HFCtuoiAtFFFUAUv8AB+NAYrTo/m4FAGz4N0e71nWY9Ps7N5ZZnWKNFTcWkb5VXb/vV+1XgX/gnf4G+FPwH8F6JeeP7Wy1K10O3n8R6XNZK8jXU3zSfN97cqttr4t/4IE/sf2H7V/7enhjw74ks5JtE8NxSeJdZVYty+Xa/NGrN/Duk21+xn7TnwP8EfGzXLi5e5k0XUbG/wB8t1Z/Kt0v8O5f9mt6NOXJzI+czKvzVeQ+Nvjh+zL8KNDtYJ9H8yRI0/dfKqrIrfxNXlX/AAqXRNPt5YYdSaGL76wxov8A30tet/HD4T+NtB8S3XhubxDNLCqL9l3P8rKv8VeUa94V8VaOxSa83n/lky/+zV5daVVyu4nLRjTjHQ5PxB4fsLO42Jct9z5WWWufbS0EFwVTfiNh+lb2peH9S+X7TMxf+JVXctUbvQ7l7WdfmChd3yv7feryJRnKt8zePxI8Q+AMH2jx06lSdthIcD/eSt39qu6Sz+D2ozIP9c8cDbf4dzVnfszQGf4jugI402UkEdRuTirn7d0cOl/C/T7NHbfeazHG6sn3VX5q/QfEil7TjJf4I/qfZcWJy4gt/dj+p4za6h/ZtjAtmm9IYlV/97bVPWvE23/UPhdvzbnrHuNQf7L5yTN/s7azZLl5pFd33V4nNeB4sY8smy7qWvPMq/xH/wBCrD1DWLmSRkR2Vv8A0Gn3Vw8C/wCsVlrNvLhGX/ZrGUu5pHYy9QkMl19/dUVEn+uP0orQ6Y/CFFFFZjPWfFH/ACSQ/wDYOt//AGSvJq9Z8Uf8kkP/AGDrf/2SvJq+947/AN9w3/XqP5yPouI/94pf4F+bCiiivhj50KVV3Ns/Om7fmzQy7qUdgFpGXPBpaQnd9ymAtFHAFFABwRRRSKu2gBaKKdF0P0qeYBNrrSUUu0cVJPMgT7wq7p67pBlNw/urVZFfj5cfNWpoVr5l7En/AAKgk/Tb/ggD4DeGz+KXxamh2bYLHRrWZU/vN5ki/wDfO2vvzUriFbV4XfZtfdtWvnz/AIJBeAZPh7+wPot/qttHFceMtcvNWuFZPm8lW8uJm/4Cte8X03zMibXX+63yqq/71ePWqOVWUSvY/aKkiwMRbRr80aM395tv+1VOZn+ZPJhZ4UbymZfmWnTaiib4Uh2/w/M38LVXurqRrgw+Txt/1iv8tT9k3jH3ihqVv52z9837v+9WVqFmkyn73mfe8z+KtuOPzrhUeHKKm523/wCd1QXVvM0Mk038P8UbbttZz9odtHl1aOK1rTZ9zvCjb9/yx7fl21j3Ghr5Lpebc/LsjZa7iazW6Z0c/wAH3VT73/AqyNT0zdav8jbtrLtV/vbavl5l5mstveOC1zw/5LC/3sNv3I1+asi+t9sYmSGROysvy7Vrtbq33W/2mCFfNVPnWT5WWsK6tIZLXyUdWff/AHfvLR/ekYxqcvunjHx+sIbHw7aiOJl3X4OW7jY9N+HAjg+HtvO1uj7pHDAjOcyMP6VpftM2cdr4asmcZlfUc7gmBt2NUfwxt42+GFm1xErEvMYm83aVAkbNfv2cOMPo0YF/9Rr/APSax8xgnH/Xirzf8+v1iYWraOjW72c0TOs3+tX+Hd/s18V/tReEbPwv4udLC2ZPOlbzd33a+85LOZZpbbzlZW3Nu/ir5f8A20vBX2y3TXoYcBnb7v8As1/PmBrR+s25j7HMKPtMLzrofLONkgm44+b5qtW7Izec8nP+zUMmyORkdN3+9SxxpG3D19FHY+dXwj7htyjZ/wCPU6GDaocbWbZUW794EdN1aAhRV3pDllT5FqeXsIYsfl7UT5lqVrhId3ko3/fVKtv5m5If++qRbcx/7I2fMv8AFQKUftFSRTN87jeW/vU+GF1+TZ/F/DVq3hTaqI/8e75kqaOHMjb0Xb/eq47Ey8zR8OW+66CI7Ou7+GvXfBt4mnqEdFKx/N81eZeEYUa6RPlU/wAFepaT4fudQjRzD5QVPvf89KvlhIUvdgeg+F/HWmnT3TyVRvuouz5q1F1ZNSVPs1rv2/Ku6vO9N8O38d8qGaT+Jm3V1+m3Ft4f0nfdXKs+z5VZvm3Ue7E55e8eKftdeG3VrfW0h27fldv71eGV9G/Hi4m8QfD+91KbbvjZW2/7NfOVKR3UZe4IwyOKWm5+7Tl+/wDlSNgpf4PxpvCr9KWgApyLtGKbUi/eCPSlsTLcsQp5kmE2/wC8tdN4ftdrb3+X/erA0uH7RIybNi10k0n9n6bLdfdXyttQZS5znvF1891qjw71xD8vy1k0sknmSmR/4vmojj81tnrWhtH3YmhoVr5lwH+b6V0sDeZu+fB/iVazdPh+zWq7E5b+Kp4ZHT92nCt9xqXwnPKRbbZIvkdNvzbaqLMkbHzH+b7qLV+P97HvR+dv/fVU5oUti00yKxZ/k3fw0c32SY/Cb/gidpdbgVpOVRwU/wCAmtTxng3sYBUMIc5bvyeKwvAV28niiGJ2HKPx/wABNbfjOcpqKREKR9m3AbcnOTX3OG/5N/W/6+r8oH0tF/8AGKVH/f8A/kTAkh85zv8A4v4m+7VRW+8ju2V+7WjdQeYqI8O0Mv8A49VaSHy5PORFO3+7Xw0dj5kdaKsTFE+U/wAVaVnNbK2x5txb/wAdrLZoZBs2fM393726p440jmG/78iUS2A042LR7IUyP4qTzIfL39EWqscn7z5N25flqYQzfIkPKN95qceYOQsW8iL/ABq39yjy9w853Zf96oFgeN9/nc7N3+7VmO4hbe/l7lb79PmAwNebzJHU8LH/AOPVw998t0/b5q7XXJjJcSw7GVV/ib+H/ZrjdT5um4x9amXxaGtOPKfY/wCx1qD6b4W8EaopBa31CKUbvVbon+lfu1/wSW+LN+37RuteG7+bda65paqu75V8xf4q/A79nXVU0D4N6DrjDIsoZJyB32TO39K/Z79gnXtN1CbRPjHoOpXUdvZ3Czu0e3/Usv8AF/7LX9B+Mc4w4f4cT/6A4f8ApNM+DwVd4fF4mXT2j/Nn1d/wVn+A8Pxk+Bes6Vaab5z3FhJA7K/yybl27Wr+U/x/4T1X4e+NtY8Ca8jJd6PqM1ncLt2/Mrf+g1/Ybca5pXxO+HupaNNMtz9osJPsV5JF+7ZtvytX8pv/AAUe+GPif4c/tYeKrnxIjCbVtUmut3lbP4ttfile1TCxnHoe1g3CGJ/xHhO4L99/l/h/ioWZyyo77Q1QrI8jbxHgL9ynqqSNsLt8v96vL5j2vhOu8CM7Jdbum5do/OvW9D5+EVx/143n/oUleRfD5naG68zGdydPxr17QsD4ST5/58rz/wBCkr+svBP/AJFFT/sFr/8ApyJfGn/JJZf/ANff/kzxGGR2bZs4X+KrkN0m1pJuGVNqVTh8xVaE/wAT7as28bsuyFPlWv5OOeXvF6Gbdg/3v733qka4mXKp9xvvtUCu6qz+SpakaZFUI77TJ8v/AAKgUYl7zHZUdPlH8a76swzfMZvJV5fl2LVRfmkV/Jz8v3Vq5CfLbyYdp3fNUyNqcYRmXMOv+kpCzbU/1e+rkbO0K+YGXd/31VRUTbvR9rf7VXBb7l/1mNyfern92J6FOPKWreaGNV8jcnyNv3fNuarUKQrtSFMO38O2q1rHD5I4Zv8Adq1ZqTgpM237u1v4ax5pnbHm5eZE/wBnf7OcP935fmpV2Qr8n3vvbaSDf86J/vf71OY3PmB4YW3Knz/PXQc9YVmk8zzng+Rvlfa9TW8iRzK/2n5I0bcuymNC0IfznwG+43+zUkEky7Rv37fmfd92toxPExHx8shsk1s1uZvmXd/EqVQuoyJF2eYq7/uird1HuZdm1U/2fl+b+KqepSTbdnnb/wDgH3avl5Tm5vsnPafevJMiQ8FW/wBY1dt4f1xPJZHfYy/NuX+GvLtNmm8xfnb/AHlroLO+DMH37jXnxl/MfRHs3hvxR5ccW+5X5l/h+9/vV3HhfW7ZZw6Sqm5fn3V4H4f8UJarvmKqVT5GWuo0XxwEmbzJt3z7nVv4lqJc0o6FR5ftH0l4d8TQyRxojx7FVW3bPvNXXaVrHmQSoiR7P+en8S1846H8QG8wTTTM6bt0UP8Adauq0r4iXMkyPD8h3/OzfxLXi4qM+bmR7GDjE9pk8QPbMsOm6lGys22WNvmZl/vU2bVoZr0OkMOVt8Ntdvu//FV53a+MnknL+cp/h3L95v8AarSs9ae+jV9mxVb593y/N/DXiVqnL70j6fC4e/wnVtdeasdy77Ctv86t/D/vVXuI3Cvs/eqrfOrJVSzZPLNskLMJPvzf3qs+dM/zpuVVf5V3/eWuD20paQPTjh6X2jntctdyp+6+Vvlf5vu/7VcLrGl3MzSpbOp8ttu7/wCKr0XULX7RE0bwsgkfcn+9XMalY2saumxlddyyqsXzbq9PBS9vM8TMKMactjyXW9MW1vlkjXBEr+YB0ziuJ+Jdt588RPaLg7c85NeteM9LWCxe6UsQCqgsOvPWuE8QaQb2AXcca70BXc3celf1fkXvfRvxt/8AoMX5UT8fzBP/AFxp6f8ALv8AWR5XJpM0czQvCu6u2+H9rDJfKl4/l/JsXd/u1DJosKzh3Rd+7+Jvu10Xg3S5lm39t67Fr8Xj7sD0az7HZeHdN8ny2fyxt+VW/vV2vh2ztmsykaSHc+3dIn3lrH8Pwu0kcMI+dvu12Wh6a8d0zuikyLu/3a5ZBH3dCtZ6fCJm2PuEm7fViGFI4ZobZ/NmbaqMz7V21pXFm7TPC8K7Pu7l+7UVhaw2+6a8XZD95pGTdt21x1acZaM7KcuWPMSeIrN/CfhOXxzcorLD+6t9y/ek/wB2vlX47Xk2q6Hc394n2jdcK8rbfmb5v4q+hv2pNWdv7E8OxvN9k+z+f5attWT5flavnn4oQvJ4NvksPv8AlfulX5mrbD04RiZ+2lUlp8J5h4m+IU2h+Gza6U+zcu3bHXkN5a61rd79qmEkjSN/FXVNr2m/aIodT5Xcvmq3/oNex/C7x9+zTo8IfxV4VuLyXytqLGyrt/3a0jyqV5Dl7WPwHz/pvw58Q6hcIn2N8M23dsrrpfhxovw+s/t/jyTyZtn+j2a/NJI395v7tevfEL9pD4e6TZ3Fh8Hvh7a203lbbe8uvndf91f71fN3ii68Q+INWl1XWbmaaaR9zSTNWvtI7QFT9rLWoS654m/tq8W2h221t/BHD92oGVNrJbf99VkrG+4/IwojkuVbZG7VGvxG3L/KXksyrfO6uW/vVYW3hhXY77W+9VCGaZm+f5dvyu1XrdnmZfvbf7zfxVRnL3S3b2u6MeZ1ruPhrocF1cNNs+dYmZF2/wAVcjYm2X53flv4a7/wPdf2bGHf5EZvnZqUVyk8vtNxl54ftrHN5qUzKnm7t26uG1nWptd1b7BZzSeTG/yL/CtdD8TPEQ1i9k03w5uMkn39r/Kq1hW/hfUvDfh6bxDc2zFwvyN/dpj+GRzfihoTrDeR/Cqh/wDerN3r60+aR5XZ5myzPuZqiZdtB0IfRRTWbDcelAx1FFFL4gEVccmlooo+IAoooo5UAirtpaVV3cp0oZdpxTAMbcev8VS28f7xUfiol4XfVnTkEkwTyWcs38NLmREpcqP2i/4NLdEvPDvxa+IvjDZtTVPBs1kzMisvlw7ZPvf3tzV99fHKSbRvFz3ju3lTS7IGVNqq1fHn/BvNaWfwc+HXjHUNVdoZbfw/b2v2iNfvXVxJ5jR/9+1Wvq741fETw9daWupXV5C/kszRRs6rursp1YeyPksU5VKx8sftceLNNtfGFn9tut32qD97HD/s/wAVeLah4ysL7dCdqlU/hf8Ah/3avftMfErSvGvj420NhIiW8W23mVNy/M3zbWryzVPEUNrueF/lVW2Ns+Zq8WtiOafKbw91GzqF959x8kyld7fL93dVC+vkaCb+P5GVG2+1c22pTPI0zvgx/N8v8S1beZrm0kdXjQrEzO3+8DtrzvbSUlfuVTlzTR4/+yw5j+JjuoBI0yU4Pf54+Kz/APgoBqkcq+GNHW5kZ2vJp5YWfcv3flaj9n6/XTfHUl0wYgafIDt6/eSuJ/bC1q51b4haVaTN8tvayNF8+75Wb71foniI4vi9Rf8AJH9T7jilXz//ALdj+p5jdTblCfdqrcXSLiBPvfe+Wi4kdVbe/H93dVa6l8uMOkNfLy948W3LKxW1C83Lv7Vn3k23bv8Au1auptv33+Vv7tUm3tHvdNy7Kr3SolX/AJa0Um35s0tHwm4UUUUcoHrPij/kkf8A3Drf/wBkryavWfFH/JJD/wBg63/9kryRG7H8K+748V8bhv8Ar1H85H0XEf8AvFL/AAL82OooYbutFfBHzoUU1RlcU4ru4oAKKKKvlQBRQW280irtpgLwRS7Tt3UK23tQAxxlc0vhJkDHcaSk3fNilplBS7jt20MNq4oXDfJ3rMmO5Jbq4Zf9qt/w5YTajfRWFnzcTSrBFt/iZm2/+zVgxoigFzX0J/wTl+EFn8Z/2tPAvhDUIWez/tuO91H91uXybf8AeN/6CtRWqRp05S7CjGVSrGKP2g+FnhlPhT8FfBPw0htliTQfClnZyt935vL3N8v+81WNW1R5NyIkZi+8u1tvy0zxZrk11rlzPf7nEl1uiXev+rb7u2ub1K43fIk24/w/3v8AgVfKRq+0nzPqetVo+zVix9qmkmV3eN1X5WX+9/doW+L3CeTMy/wuuz5WrLaZLqFvNuMne3yrUtrJ5VwqPt+Vfkk/vV6EZc0veOeNPlNmNnktNmzD7NsVRzL9nV0k/wBlZfn+VqihummX/XbnX+Jf4aijmtlVd/Ls7b2X5lajmj8R0cv8o5oX8l0tv3ayfM395VrKuLWO6t5X+78jbGatD/Rmy8Cbivy7t1Vb6GFd86bfvfOv92qp7CqS5Tmryz2M2+bczOrbWT/V7a57UdNR82yfutsu7zP9qup1b5V2IGdm+4rfKzL/ALNcxqkbwqznzMSNuibduX/gVdNuWOpx83ve6eO/tR728LWTZcp/aYCb/wDrm/T2qL4Q2tvP8NbQSSIreZLjPf8AeNxU/wC1ReJN4X0+18wFo79cAenlvTPgxOyfDi2y0ZQPKBnqreY1fvGdxt9GfBJL/mNf/pNY+fwLjLjWpd/8uv1iWGh23E32azVD5vz/APTSvLP2nPBf/CReCbm5aFXkjVn/AN1a9lmVbi6CfwrFu3Km7c1c34k0Gw1rR57a8ST/AEiJkljZN3l/LX8zRlKNWLifocqca2F5D8zNa0n+zdQms3j3eW33t1UMOrHf8u3/AGK9A+OnhH/hF/FVzD93dK3y7a89kb957V9nS/eQiz5CUeSfKyLzEWM9/m+9Vu11QISj/MuyqO0K3yfepyrJuXYefvU+Uo3Le+RsfPj+6tPaSPzmfZktWNHHNu8tP97dVq1utsmyZ1Ut/FVRMuVF7bN2TP8AtVMsjsq7Bn+F1aoIrj7qf3nqeH/SG8taoPcNrwzfJa3Su6Y2/wANeyeD/GkKwpbPHlo03Kq14XZxvDMjmbc3+y9dNomqXVq3mPux/tNSj7vxGdSPN8J67q3jC8urrzoYVVV+bav96se61TUdWuDNM7E7tqR/3a5uPxvprY84tvb+JfurW3oXxB8Nwqk0yLI6v87fdp81ifh+ySfETS7y4+G97YeQwWSD7zJ81fM0sbRysjDleGr7Gm8WeHvFnhV9Ks7qNX2M3lt/er5P8caNLovia7spE27bhttBtQ92XKY9FFFB0hRSMcDiloAVPvCpYVdi3+7USjcanhX7orMiW5q6DA8jKmz/AHKn8X3jw2iWZflvv1a8Mxoyqkybd38TVz/iS8F7qkkicKvyrVe6RH3ijWhodukkrPNu/wBjbVKKB5nGzmtPTVRJhbP0z96qKqS+yav+tX76r/7NVdv3jb/J+6/yVfWGOSNqzLrfbzbPm+b+GlzRjEx9ma+lzJJKN6YDfLU95b+ZGEfa5VP4f4ay9Jvk87Z90t/erXhZJoz8+w7vmaiOxUoi+CIWj8Y27ocBkk3D/gJrT+IN21vrVvGGxut//ZjUfhK3QeJIp0bdw43f8BNRfFSTZqtuRHki34b0+Y19zhve4Arf9fV+UD6Oh/yS1T/r5/8AIle1vnkUJMn/ANlUrRpJtuUTbtbdtrDs77bN/EVX5tzfdraivIJIyIZsllr4bm5YnzPLyzK8MbwsfOT71Wl2tGHTc3+9/DSrbuzMm9V3f+O02OOeFm3/ADbvlRV/ho+IOXlHxwyQfP1qzCs0ke3Zt+T5KhSO5YJs6f3amjZ1ufvt/wACpy90iIjN5beTt3MyfM1HmbY2GNvyfMy06aOZpFd5uP4WZaiuJk8l0nfDf3qUlzB8Jg6xs3SvvyW/u1yl2wkbYn/j1dNq0zxqd6bTs+9XL3DGRjvP8VH+E2p7n1D8Kn8v9mmGTpt0e8P/AI9LX37/AMEk/wBoxNa+AP8AwiX9qzTSKrW900fyt8vzLX5/fDViP2Xgw6/2HfH9Zq7L/gkj8aH8MfFVPB95I2zUNqxRq33pP/2a/dvHCnOpw3w3y/8AQHD/ANIpnw1LDvEUsel/z8f5s/d39nP9pyHwfZp4S8f61t06RlRf70O7+LdX5b/8F+vhDpWofErVPiL4PuY7m2s71ZUa1+ZWt5vl3V9k+NNHmttmq6PMxh2xs/z/ACs3/wAVXhH7VfgF/id4d1LQbt/k1jRpElkm3fKy/Mu3/a3V/OGTZlXor6pXPLyTNKv1hUKn2T8dpFRXb5GV/wC61PjZNu/Y25v4am1jS9Q0nUrrSrxNstnO0Dr/ALSttqKGN/7m1tn/AHzXuyj0P0OMuaNzrPh9sMd2yHOWT+tew6AF/wCFUTAjj7Fd5/76kryDwCu2K6wc/Mn9a9f0DA+FEvGf9Cu+B/vSV/WXgomspqL/AKha/wD6cib8a/8AJJYD/r7/APJnicKozBxA27d96rSu6qX2fN/dWooo/LZPk+Xfuq15fzeWqN8z7kav5Pjb4TllzCQybV3pu+Zvu09m87d+427f4mqaKCb5U2bf4vl/u0QwH5n+bDf3v4aPsB9sIYnaZjv2r9560LNXkk+RF2r9yq0du8f33X+9uqzbMhYJ98NUfZNYx9/Q0Iz5Mez5Wb+7VyzZ9w37W2/NuZqo2zbpPkTa38DNVqG32yBLnczL99lrnlHmPTpRLsao2+T5drfdVWqxZ/ND5j7kbb8yt826qsMbrIs0MP8AHtrRt2dm37/l+78qfeqPdlsdilzEluiN5Uzj5Nn3V/iqRLV5GLi8Z1hT512fdpY4XWNHT5z/AA7fm2/7NTw/aVXznPyN/Er/AHv96mYVI83vEUlr5knyJuXd/F8tOjt4fmtvu/3NtTSR+SzO6bNv3v4qGt90m9HZv7jbNvy10U5fZPGxVOfNcqyoqxruPy7m2bqo3iosLPsX5q0rpUbZ5m1vm+6r/wAVULyFLeT93t2yfw1rze77pyxj73vHm8cm1vO85tzP8q1as7jzI2eZGHlrt3b/AL1Zv2iaSRH6hat2sm6P5HZdv8TV5cfhPbgbNnfvGwTYu1V/hb7v+9V6zvPJZZkmbd/eV6wLO6fzmtnT/WLurRtG24SGPj7u3+Kl9jlN6cuY7DSfEjyfIk0hZfu123h3UtQKrskXEny7W/hrzfw+r+c/mQ7v+B7a7Xw3deW2+C5jR1dfvLXlYyP8p9Bgfetc9G8O3U3mbJrll2pti/u7q7jw7E95IX+2b5VXa67NytXnmh3SKo8tF3NKv2iSRNzf8Br0PwpMn7pH3K+75PLWvmsRT5Yy5j6zBy+FHY6fC8kaPNwrL8iqny7q0FhRJFh2Mp+8n+ytReHbd444vOHzL823+9XQxwzL8+VdW+by1/hrzYc0Z2PW5Y8vMc3fWKQRLNbIqyLu/eSPWBqFv5duJry2/fM7MrK27+Kux1TToWZv4F27vubttY+sWsKwiH7MpdV+8q/eWvawv7vY8PMFza2PMPibGsfhi6LqA5mQEq3B+YVw2m6bDf6PKki8mXCttzjgV6R8Z9NWw8NT+bGRIXT5Tx5fzDjFcj4DhE2gXSRoTK1xhMLn+EV/VuRSX/EtmNa/6DF+VE/Gc0V+Nqaf/Pr9ZHIX3h9EmDzJtTfu3N91lra0nSU8zZ5Klm+ZG/h2/wANa9xoKTSb5odiKu2VW+7VjTNPSGIPCih2/i/h21+NQlzQtIvEaVbo3PD+lsix3LosW7/x3/arrdNs5tzfJb71RV3bvmauc0toYfKR03bvl3R/+zV0ekyJcMEtnZt3/j3+7WMv7oovlLKxi8UzZZEX5ZVX5du2uS8V+ONN1i4udN0aaRoLHassccv+sb+L/gVHxb+I0HgPw/MbO5hN/cRMkUK/8s/l+9XnfwjM0Oj/ANq3nmFtUlZ4mb5d395qwlz850VJe6dd8ep31jwn4O8cwzMdP1rTt8X2hdzRsu5dv+zt214R4o1JPJksJk+Zvmr1fxdqT3nwXv8AwNqepM1z4N1aafTt3/LS3k+bav8As14ZJdPdKdSvE3KyfKv3d1EviJpy5fdZ4P8AEfQrnS/FE8KRts+8jf71c551wo++wFer+OrzTdS1TNym5vu/7q1zWoeA4WZprWZfKZfvB6vlmdfMcnb6teW7B0mYV02g/ETSBbiw8SaP5yN9+aM/NWReeEbm3Ztj5T+FqoTaRPFJ5fmKSa0H7vU7lrj4a6y3+jXC27N/DNRN8P8ASpI/O03UrWVWf7sctcBJbTRt/q22/wB6poV1JFzBK3/AXo5pfDIXszp7z4f38Lt5MKn/AIHVZvC95CqO6bVZP79Yya1q9ooKXkm7/aamjW9Sb/l5b+98zUub3Q5f5jorWzht2R5rlVZW+dfvVtQyPebIfMZwq/39tcVa6s/mLJNNyv8Aerf8O+JoV1SN3+ba/wAyt/FRzcwuX3D0HR9D0TQ7P7TeeWkrKreXsrK8SeJjeMdN+xx/Zm+/H/Dtq3eS6brlws0OrRpJJ8u2R9tEPh3TbWEzX9z5n91Vbc3+7RHlMlL+6cdL4U8M6rYyLA7QXP3ol/hriLu0ms7p4JRhlbaa9d1rQbO1tW1KzeOI/wAS7/mVa4DxtJYaleNd2BXzI+Jdv8VEviNqcjnACelOVdtCrtoZscCl8JsLQG3c0MN3WkVdtSAtFIxwOKWrjsAUUUuxvSmAfwfjStI7LSrHt++nzUvlv9x+tLlRmMUEfKh47123wS8Nw654ztpLna0Vr+/lVhuVlX+GuPgh+YLmvoT9mr4c2y2K69qEMiCR925l+Vl/u1jWqRow1OfFVvZ0pH2J8Ff2pvGHwU+D9x4L8JJCk+tavHqVxdN96PbH5ax/8BqlJ8aPij8QtSe88VeLbryo2ZYoWn/d7W+822vMrS3mvrhN+3ZG7Ju2fNt/urXQwxmG1dEmj2SOvmts+Za8P29WpI+ejUlJ+8W/EGtXk18C9yu9W+9G38Lf+zUqh5vkmTa27+JqrQw2FtMiXIjmZW3JGy7t3+9U1xdSTXDJbWaxJ96VmqJS5Yl8pajVLfajorD5vmZahe+Sa0mSzhVd1s3zfw9KkMKSSIj7XDJ/f+bbUOpXx8iSCOzyI42UeXLtVlxWFH+IubuVD3bcp43+z6bVfHMsl42EXTpCeM/xJXmv7WGqWeofHCa1tvlSz06OJP8A0Ku8+D1ytp4nmlYgD+z5AefdenvXjnxcvU1T4p6zdww/L5qois25l2rX6p4gxvxhf+5H9T7rijTP2/7sf1MCX5vkqG8hdoWREwu/d/vVcjt0K7H2g/3qr314m1kT+H73+1Xy/Kjw/wDEZE1vtzUcjbYfnTDU+6kfc0Ozd/u/w1TmmeTcjvmpjE0iQfxb6KKKqWxsFIvy7jS0Uoges+KP+SSH/sHW/wD7JXk1es+KP+SSH/sHW/8A7JXk1fd8d/77hv8Ar1H85H0XEf8AvFL/AAL82EZ2nLjIocbzk03rtp1fCx2PnQ3bm30UirtpaYBRRRWYCP8AdNOVu2zO6mv900KuOBQA4qx7Ufx/jQxy3FIU3cHjFaEbMKKKX7qfWsyw2N6UM3yrQrbaNu1uR8tV8ID7feziL5fm/ir9IP8Aghr8Hby38S+K/j88DN/Yulx6Tpzb/lW4uPmk/wDIa1+dOiWkt5qESpwN6/Ntr9sP+Cc/wn/4Up+xv4bs9ShWLUPEVxNrerKu5WXzPliX/vlf/Hq8jOMR7HCPzPSyfC/WcZ6HtF9Ekm95nVfMT5fl3Vz1wqK29Jo3/hZl/h/3q0dQuElZkdGjZW/if5mWsv7VDasz71JZ/m+WvkcLWnD3pH0WKwpW8tGkV025X+Jfl3VLHDBlN/zeX/DTbiZGxDvjRZPuR7/mokjm2+XsUD7q7fmr16EubWZ4tSnyzIpNSmiulSbhFRlRl+X/AL6qO41KctC6OwVX+Vl/3fmWm3Ujfd+x7fLTa+5/9Z/tVmTMltJstplA3ssrN/DXbRjze6jnl+7NldQ863aaGba391vvf7VQXGrQzK7WVzuZk+83y1k217DazPNhdn3Vkk+81RSXm+N7iZGHl/8ALNq7qdOcTilU5ia4mSZTeWyb5GT5938P+1WBqa+dM6PeR7W+X/Zq3e30MkKyOjRKqK23+JVrG1K68tWd4fM2/M7fd2//ABVb8plGR5V+06LL/hFbJ7fAY6kOCASy+W/zbh1qP4RZk+HNpbRQq7vJKfmXp+8aov2kLnzvDVnEksDJHqO0CHt8jUz4R3og8C2YZlG2aTarfxfOa/d83iv+JbMEl/0Gv8qx4GDny8ZVJf8ATv8AWJ0zTTRwxrsZlVGVFj/hb/arG1yS4vIZH2Mki/Myx/Ku3bVyZobjekzsjsysu16ztavJo7GbJVn2MrKz/NX8y+zlGem59/SrRUD4y/assYb7VpblHy/mt92vBJmkWRtnNfRHxu0f7dql2iJGzNu2V4Hqlq9vcPCh+Zfl/wBmvqKEeWlE+bqS5qsuYzlt3fP97/Zq3DAoXOxqI1Zm/cuvyp92hpnjbZ83+7uraPvEy5uYbI3kqqQ0yFUMhf8AipXV2bmneU+0fwikEixCzsqnZ8396tKzkMLb9m5qoW7dI/vBl21bhZI1Tf8A+O1UiTSsZE8xYXdd33t1dJo+n/2piHyWfdwqrXCzah5DZTkr/FXR+CvGz6XdIjvuH3dtT8QS9029Q+Hetq2+2hkVP4Kyb7wtr2m/fRv7y7kr17R/iJZ3mnQw/ud38W7+KluPE2lXbP52mwuqv8+2KinKJjLm5jyHS9c1nR7peGHz/K392tTxxodt470p9VgRVvIV+bd/y0rubzw34M8SSBLbbaT/AHtslW9L+EtzatvtL+N4/wC7G1OPwiUuV35T5emgmt5njmTBX5WpmcnrXb/HTwb/AMIj4sZIn3JcJv8A91q4dV21pynbGXNEUNu5opFXbS0ihVV91X9P+ZhDsz/FuqhGw3Z3sa3fDUMc0jJs5b+GpkZTNWbydP0V5i7K/lfK1cazOzF36tXR+N7gW8MemxfxfNLXP29v5mX2Nhf7tPmRUfdLml+TCQk2DVySMibeN2373y1lxxzRzLs+9/DurSikZoxv+9HR75nKUTX02R2h85ofl+XbUOqW7qom2Nub7rf3as6bMgi3v8/8Py1FqkbqvD7xt/v/AHaI/wB4z+H4TJkuH2538r/FW5pMjs3yPkbfu1hN8rbO/wDFWhpt49uuxxTDm7nX+GI5RrkDfwbW/wDQTUPxNhE19EoOCbfAb0+Y0/wVcedq0Z8wtlG5P0NWfHEUcuoR71yfs/yj8TX3GEf/ABgFZ/8AT1flA+lp+7wrU/6+f/InCtG8bfK/H92rGlyfZ5EfDLt/2qsX1r8zFEVf7u6qUjeWu/Y2K+HPmYy5jfW8SSP5I23N/FUqyTTSbE/75rEsbq5Vmf5cVp2d/uukhL/O3zPQOXxF9ljjcO6Nupn+rXzH3bqnupJo1VN+4bKh2+YPv/Js3NIz0DkP3PJ8vnNhk+VWqnqS+TGS6bv9rfVmVnjPzw+cfuq3+zWdqreWvnOdqs/3aceflJlyyOe1i8Lb+GJ3/erDb5mL1sa1cfeRP4v4axqRvT2PqD4a8/sur/2Ar7+c1ePfs3+NZfBPxZ0TXg6osN/G3zfd+9XsPw0/5NeX/sBX385q+adJuns7+OZHxtbdur988Z/+RBw1/wBgcP8A0imfL5DHnr4xf9PH+bP6R/hD4f1L4hfss6T8YNNtobiwaVYJZI/laNmX5ZJK808ZeBb+60271nQLlpRasz+ZG26uH/4Ix/tLQ/FD9lvUfgP4t15oUaCSC4X+Lcq/um/2fvVofDn4kar8H/iFefCL4kXn2i3juGgS8ki+VY/9qvwKrk0cTR+s4de9H4j5PN8FTy/NFOOlz8qv2x/A6eC/2hvEKJbNDb3119otY2fc3zL8zf8AfW6vL4f9Ud6f77V92f8ABWj4O2bRw/EvQdNj2Q3UiS3G75po2+6y18M2sKN/o3yhV/vNW8k3CLPucuxEMVhYs6L4esxt7lGjK7WXAP417F4fU/8ACqZVz1s7rp/vSV5F4Hz5d1lif3i4J9OcV694f/5JXJx/y53X/oUlf1h4Kf8AIpqf9gtf/wBORPT4z04Ry/8A6+v/ANvPH7fy9rSbNw/551oWdrbeWszuymT7lMtbPGxNi/M27dVpYUVgmzmT5V/vV/J/unNKXu80SKSLcrJ0+fazfxU+GN41D7/m2fd2feqRrN938Tbfl3U6RbmONUhRsx/canLkJ5ve1K0mRF9xgu75FqW1VFXL8fxf71KqpMrb933/AJt1Lb2+3dJC+7d8u2spG1OXvRLlu6MyfdT/ANlq5bjzJPndgrfKtQWdv8o3ov8AtLV6z3xKzvub/wAern909WnIt20cMbpCkzbdv3WqyIYbfGyTcWb5231Xt/ObCJIu1l2//Y1atY3uG3yJxu+7WfLynZze77pZtm3q0Mb7H3/My/dqzFb+ZD+8TaqtVO3CQt86YVW3ffq1GUWFfOfPybmZf4qqP9455B5aNM6Tbiv8K7//AEGnrI8W1n3Mmz7q/N/31SQtC8nnPH5aeV93+Ld/s1JDJIsLw71Dt9xt9b0/dkeNjOaWxWk+Yo6bmH3dv3dtUL6ZI1/h2w7vm3VfkV7na8yZ+X738O6qepQ2alkd1ZG271+8qtXSccY8vxHlS/abf+Ddu+/Vm1/eLscN/wABpsiosgaPpViHHnK6J8rfw/7VeLzI+gjHmLNrboV8yOPDt8qVo2qZkR8fLu+eqkMKRqrpIzbW+838VXbWGaR/k+9/tVEub7J20YmzoqpbsqYyzN8/z112iyQrceT5Py7V3M38K1yel2u7H2Z8yN99v7tdloceyNMurLv+Zq83ESme7hY9jt/D9xbeZGiPxI9d94Zmhab7NMm3y2+Tc/zV5xoskKskckLKF/vfxN/s11+hSPM0dzDe/Mv8LLuZv+BV4FT3uY+jw8pRPVvDdwY40hm+5G+1tv3q7W3jE8KXMzttk+WJa8z8P3SWsjW8KN53yyvul3K3y13fh+dJIUciP93L8i/xLXm8sacvdPYjLmhqabQu1u8ybdyr/crD1e0hlVHfafl+aRfl2tXRJ/qfkRWKvu27vmas7UrO2ZZH3r8qbm+T5V+avUwnve6eRjOU8k+N9rF/wg11eKJNzPHuEvVf3i1y/wAIrJLnwnfPyzfbMBAM5+Ra7T492sw8A3s7yjCyRAqW/wCmi1ynwPeQ+GryCOAsWvSobGAuUUfe7V/VmQxf/EtmNSf/ADGr/wBJon4zm75uN4O3/Lr9ZGxceH4ZFZ3Rdqp825/vf7tZ39l/Z1e5TaId2xd1dHNb39wzw21sv+xHu/8AHqqXGnzSLsmRo22bmVf4a/FqNQ68RT5jN0fzoYkhhb5pPu7flq/rHiS28M6Y1/Nc7XVP3X+03+zVO+tfseLxUZv4m+T7teUfFLxw+oXQsIblikafKu/+GifxHLTj75g+LPEGpeMvGm+8fc27bFt+b5f4q72PUodF0/Q/sdmsiR37RXSqn+r3L8v/AAGuM8E2sNvYnVdjebN/qo9m75a0dQ8SWdroN1pVy7JNcQbrVd/zLIv3WpSjyx5S+bm+EPiprVho/iCDW7l2htNQ/wBF1G3ZN0e3d8rN/wCg14t8VdUTQbya2012awb5rL/ZX/ervPFWvWfijw3K+sQthv3bR7vmZl+9XjPijUE1maXSpppP9F+Vd38X92s/dNIx/mOVuriaSR7m5dtrP/DVaz8RanpauH+aH+838NGoXU1xM9v9zb/Cr1Wt5EkZ7ab5/M+Wr5eY2NiHXobyHfM6n+9VW4Wzk2vCiptrB1C1vNNmCb28tqSHWJPlST9aQcv8poSQoGDzf8A21V1LUIYI/IhhX/bb+KmyXSMjPliVqhPvmkL787quXwlR974iOSRpG30mQw4K1JHauys/tUq2u1cOlHKi+aJWP3B9adHI6sHRuVqdLXzCSy/8BqT7Ci/cNQI3fDPiSOaFLK8+b5vk3fw1vfZdSaZn0+bK/erg4bd1uPkfFd54T1J44UST53/hagyl/dILxdbulewuZmCMn8S1mp4Ze33yPtKqv8S/eru9Q1Kw8tX8jcapXFqlxJ+5T5m/hq4xmRL3WeRzxyRTtFImMNytNrrvHHhV976lb/fX78dcjR/iOqMuYKKKKPfKCiiijmQBShSxwtLF0P0pzZUZxUEy3FXeyfInP8TUjq7H+61GNq7flb/ZWrFnZzXEyQojfN/6FVcyJ2On+Fvw81Lx54ih0qzh3LvV7hv7q19feD/A6adp8Og2XmeTHt+X7u6s39kH4W6D4H8If2x4n0ma41DUNsvmL92Ff4VavYY/FHhiOGeFNNj2SLtTcv8A6C1eJiq3tpWieHiK3tqnLc5ZtB1iJTC6RxbX+Vv7v+1Utr4dht5FN/LI7/x/7P8A3zWpea1pTSIjvHsZdzr/AA7d3y02S8s/ObZ8pXc25f7tedL95Gxxe7H3Spbw2cKt5MKynfu+b/0GoGuXG7ztu6T73l/dqzcKkzM5mZFX5t2/5mqBlT5nMa7d27atZy5Y7yLjL3PeF+0TeY1y5XZ/Bt+8tU7yRIbCYW/zyNGf5VbiuEhZ7mGZseVteORPlqC4uoRE9zNHsXy2by4/72K0p8sq0fUcJR50eQfAm0t73xrJHdSFEFhI24DvuSvA/GN4954+168jdS0mrTbdq7f4q9q+GuvxeGtUvtVmbaqaXKM7sY5WvC4dl5qF1eJ8yzTySMzf7TV+teIKi+KXf+SP6n3/ABQrZzJ/3Y/qQNI7bvOm+9/47UMlj5ke+Hdn/aatNbMSRs4h2/w/cp0emzCPZhf+BV8mfPfDymI2kwsu/e3y1majZLb/ADImPauw/sd5JQ7jC7N21v4qx/FGmvDaNN2/hpSjyl05cxzdFFFQdAm9fWloorQD1nxR/wAkkP8A2Drf/wBkryavWfFH/JJD/wBg63/9kryVmxwK+547/wB9w3/XqP5yPouI/wDeKX+BfmxaKKK+F/vHzoUUUUwCiikZvRKzAco3GhPvCmv900seUoAVX+Xj8KSRE3YjNKw+bHrSVUgEXf3pz/eNJRT5UAUu55D81Iob1qSFcuA5+9S90zPX/wBi/wCClz8b/jz4b+HqQts1bUo0lf8AhWNW3Sf+O1+4urQ2Frs03QdsNjbxR29lCq/LHHGu1V/8dr8/f+CL/wAGfsa618b9V0qNxYwNp2nSTJt/eSfebd/eVa+9riSaOEzGBv8Ad/u18DnuLlUxnJ9lH6Bw5l/s8J7aX2jLvLor/o0zq+6XYm5vm3Vn3Fw8ZaG2Td/E+77tWr6Z4VmRIWCfKz7k+bdVSZfMZ02Ry7tv+9937teN7eXP/dPUrYWNTmTJ7OH5h/qd/wD6DVlo/ssX7/aI2/u/eWs+Nkt5kTyW+7udt/8AFVxLrdAv2mHan3nXd92u2nj/AGh5NTA8uxn33ytHc+RuDPt2s3zMtc5eR2ywqXK7/Nb5d/3tzfd3V1OuXVtJGZpn/j2rt/hrldWuoVaTF5yv3F2f+PV72BxHc8XHYZx3K91JD9n39Wjf5VX+H/Zqs2ovHG3+s3SffqC81K2Zi7uxST5kb+FlrDvtYeO48lHbG/a3y/Kte3TqR/mPAqRnEv32rBZPJ85kfZ/z1+asTVtW3EwhFV927/W7lasma+fzm+0/Lul27V+7trLvr7y7tk+0r/0yVv8A4qtXsY8xzHx3mim0CzZIVRjdgybWzk7Gpnw4uyvgy1RXB8uSQtGwyG+c1m/FjUJLvRrWOWNUb7USylcNnaetJ8PyBokMmwDYz72LfeUMT/Wv37NIL/iXDBL/AKjH+VU+aw8/+MtqP/p3+sTqri+SGQRgZVVZn/2WqhfXVzHpty7p5r+V/wAC/wB5qZHeQ3Exmf5Vk3NtX7sdZfiy8Sz0O5v0udjsjL8r7fl/u1/Oc6cef4T7KnW5YHy9+0V4sTRZpYV/11wrKjN/yz/3a8Y1SP7VHHc787k3bq3v2hPFH9ueMpIYV2xRt8nz1zml3D3Gm+S/8NevzcsI2OGXve8Uo18pimz+OiSMbt7virclptR9iMx/j2/w1DIv3U2Z/wBqtPc+Ikgb93j+KlhkdpN/nfL/AHagkkdVPf56iaR1WoKjHmNfTY3mul2TcN/DWxNpbv8A6tK57S7z7PMru+K6rS9ctpbfy/un+9VfaM5bGbcaE/zuiN/wKq39m3kLrnbv/wBmuk8xPl/i/wBmpo7e2Zf9R8y0+VBzGFpuqaxZ7U85lZX+Sum0fxtqsPyTBgWf52b5qzmghZd+xflf7rU5ZfJ+5D977lHLKIpSO90vULPWI/Jum8p5F2vIvytXSaVZa3bSRxWd+0oZNv3/AJf+BV5fp/2nzk/vfe3M1et+A9Y/sfQ31XVfubflX/2Wj4YEy5ebmPP/ANpXwtczaRba2NrGH5Zdrfd/3q8Nr6B8beLLPxHpt/DePmGZWWJfvba8AmCLM+z7u6nzcxvTG0UUUGxLAf3ihxXS+Gl+zyvO77dqbn2/w1z9jDuk5G7+9XTTSQ6X4deVH+dl27WWp+KRhLfQ5vWL7+0tUluZHZu2as6TJ5CeS4Vg3zbazo1+beK09Ph+0Mu9P+A0/iHIS6VFmGyHb/tbqmTfGy/7tXF0tJN2/a22l/s8quNmPkqvhI5kOs7z/lt5H3vvLUkzLcxtC6MqVBbw+X99Mr93cq1ZWF1b5PlqOX7Ie7zFOTT1Zt8dPW18sjfNU8cbzTbH+Wpfs+5diQ/N/ean8IzU8DL5fiSJBJ8uH2r/AMBNaXj24aHUYgOnkdfxNZ3geFovEkQYsTtfr/D8pq18RN39sW4ETN/o/wDD/vGvusN/yQFb/r6vygfRUf8Aklan/Xz/AORMO5uPMm8l03f7tVmVNod0batWVR1xJNHjb/dqVbfzI8dd3zba+Gl7x81H3SpDD5h39RVy3mS1f/U8sv8A3zRDbrG2wJ8u6mrDtuH+Rgv+1S5kOUuYma++8+/5tn3ac0z+XsSooo4f9c4+792pfkZg7oyj+9VcsfiJ9+JZt228b/8Aa/4FWbqjRsr/ACM275dtTt5yqXT7rdNrVn318IbfZv8A4v4qQKMuWxg6pIhcjZ91qoTfNufZ96r19Ikjb0h+9WfI2f4GoNoH098Nv+TXB/2Ar7+c1fMtuh8xdn3q+m/houf2X1Uj/mB3v85a+aLe3dpPM8ndX7340O2QcNf9gcP/AEimfNcP/wC9Yz/r4/zZ9k/8Et/jvN8IfiNaSzXMf+kT7XjuG+Vm/hr7T/aR+IWkfE74hW+vaVoK2LyWa/bF3fI1x/eWvyv+Fl1NpEcWqWDtDJG+55FT5q+6/wBm39qnwl8TtDtfA3xIeG2v7WLZa3UkSqzNX47kuPpYKv7/AMMjDiDKpY+HND4j2ib4C+Lfjt+zbqr6xon2qw2TW9vMqs22RVb5Wr8qNa8O3/hnWrvQdSt/Jns52ieH723a1fv9/wAE4Lyw0vUPEHwP8c38b6R4os9thNIq7d23crK1fkh/wVO/Z3f9n/8AbC8SaPb2fl2GoXTTRMv/AI83/Aq681p4ed50jmya+H5KUtP8zwrwngC4CqANy9Pxr1nw8Avwvfk4+x3OSPq9eT+EwwhmJ6Erj9a9Z8OoH+F7ICQGs7kZ/wCBPX9JeCv/ACKqn/YLX/8ATkT67jN34Ry9/wDT1/8At55lZsRCsLowH3lb+7Vry/3ieTyW+40n/j1VoY/3mxNrbfu1Yt5JYRsRNv8ACzN/DX8onJL3SZo/3h3vwv8AyzqKZf33nI+x/wCJaPnkk8npTmj/AHgfflpE2/LUxjyly+EZ5PmL5z+Wdz0+1j8uOSZPlLP96nRqkmLZ4fu/fVf4aFLxx5Taqfx7qXxRF7seUnhj8pw/nfe+9V9bvy32Q3OF/wBlKz/OdV2I6/N8u6pI7h4/9Gf5/wCF/n+9WMonqUfdgasMnkso2fP/AANVnznl2P5PG7541/hrMhuPmEe/aq/3nqSFkKsieYDJ/wAtI3+7WH2zrjI1f3Kq7vJvCt937tTLcedIxTcB93a33azIZNy70m3Bn/3qsNcP5zo+3H3vlo5vskVJcyLkM0yuIXT7r/Oy/dqaaRJI/ubU3fxfeWqsMyLmOY8sv3asxzPuL/u2DfL81dEf5TysRy8ugSW8kkTf6R8q/wB1KgvFT5/J3bWSrZt3+zo6Pv3fwx/w1XuGfbvNzt3ffVlrWP8AKjzfh+I84kt/Jb7Nv+98u3Z/FT7ddzYdPm/2qmmDyXXz7nH8bbP4v71TLbozoifc+9uavO9n7vvH1FGUZFm1tHhUb0q6tvLEyYT73/jtJZ2qSRpv4b7y7q1bO1hkXycNt/ibbXFU54nsYenzajrGFFy6csy/Pt/vV02m27QwpNsUs38X92su1tUj2wpIv93zG+Va2dN+Rdjv/F822vMxEpS2Paw9O0PeN/R995NGkLtuVf8AgK12uk3Dqrwv+7Rvm8z/AGa4zR4/KY3L/IrPtTa/3q6XSrh2aJNi5b5WXf8AKq15NaXNI9DDx93U7jw/qBjZHeNdqp8kn8VdvoupeSyb5VaKT5vM+61eZ6b51uyzO7Km/wDh+6tdZpOqO0g2fKi/3k3bq8+VP3uU9WnU5oHpFjqFtIrP1SN/mk+781OuLx7iMpD99lVmjkSub0nVEa4/0a5+Rf4WX+GtBtaS6hEM9znb95o/4q9XC8kfdPJxntDhv2ggg+HV6+5Wcywhz3/1i1yHwHMieHr2VFU7LzOHbj7i9u9dR8fZo1+H12ifdlliKH/totcd8FZZF8P3cSuApuyWz/uLX9SZJyx+jVjrf9Bq/KifkeaKX+vFNf8ATr9ZHZ3U32xl+f54/laRfu/7tR6g8Plr9m3N93f81Vbi6ePZsTYzJuXd/FWTq/iB9P8AMmmmVEW33PG3y7a/C6dRfEj060ZdTI+J3ij+zdNTQoVZp5FZmk/2a8Zjs5ta1x7Z7aN2kf5ZGbayrV/UvGVz4m1S7ufOzE3zW+5/ur/dqxoumx28L39y7O+35G/5512UY+6cMvj5omldNHpen7ET7tvtRVb7ted6hfTaldNM8nlrGm1Gb5q3fEmqXM1yJrab915W1v71cD4y8RTW8P2OD5C25mb71L/CHwxIPGmvPPqQTTZmeORv3+1futXIeMLiFpmSzfeV+XcqbamhuAsJhfc/mf7f3aw7qKawu2hvJtv3mRt1PlRr7piavskt/tKQ7Jt9YwmcSb0f5t+6tm4a5upmf92zb6yrqBIW85P+BKtHwmkYwN+3WHXNNRJpl3Knz/LXP6lphs3x/dq7o+rJHebPJ+X7u6ta80+G8h3w/NL/ABrRLYXwnJrNMpw6bl/utU8E0Py70X5fm21JqemzW8m5odpb+Gqm542I+6yrS5S4vmNC3kQtv2Y/2aXy0VVd/vVnrM+1W3bf9oVL9qeNfv7ttSTyl9ZUWH5HqKSeFm+5x96qa3G7+Btuad5nzFP/AB6tCiz5ieZ99Vb/ANCrd0LUHhZNj7Sq1zKru+dP4au2ty8cn/ANr1PMZ+6dbNqjzTJ5h2p96trS5kkVvk+79zd/drj4bh5Nib922uz8Pw+Zp+/epk+98392n/hJkO1S3tpLUpvXZ/tV5x4w8Mrpcy3ds+5ZP4VrsvFGrRR/LDu+VNr1zU6Pqlv57htu3bTHGXKcpRSzRvDMyOmCtJQdIUUUqjLc0pbAOjx/BUixpy/aoVbb2qaOF2+/z/dp8v2jMYse5jx8te5/stfBB/G2oR+KtStm+xWcq7FZP9ZJXnXw0+Htx4x1YW7v5VvGytcTN/d/2a+p/g/rln4PSXw3bIoto2V1Vk+ZqzqS9mcGMre5yxPpPwz4H03SdBdxbedLJFu27flVaxbjwnYapp6Immtbn70qzJV/w/4yn1bw3bzJMxKwKu6NvvfN/FS3WrarqkJhe/3vu+Xy02t/u158qdOOi2PI5eWJyN94NtmZprBG/i/h+9WXN4fubWT5/MSZk2vt+bbXYw6s9vdPD9jZ1Vfmk/i2/wAVDahpsl8x+xtMd67mj/u1z/V6UmGxxHzwLKjux3NsfzPvVJ9rRZfJTdu2feaukvrHR7i+VNkihnwisnzLTLrQtKV2/fbdvzP/ALNcFbCy5y+XlObWPU9RXZbJ/HtqW9022sLN7i+uVDeTJuVvurxWnfappWhRzTCaOEr8zMqfNJXlXxD+I1xqZeysXxG0bfK33lq6KjTqQj5lUqPNVR4z4hu5rPw/eyQuylrdlJXrjiuF8K6Xu0tLnZI3zqq/PXXePZDH4YuFUDc+1VJOMEnrVDwja7dJSF9oH3W/hr9a4/j/AMZLJ/3I/qffcVf8jVv+6v1EjskU+S6bj/s/xU9NJSSb50X/AIE9azQpuWAfNtqhJbzSTb3LA18ZzS2PmY+7rIhuLP7sezlf+BVz/jK2hbSZnSHdtT/vmuvs9kin9zjc+2sfx5p8Mej3b7G2LEzJto96Rf2jyd/umloopnUFFCshX3oqIxA9Z8Uf8kkP/YOt/wD2SvJq9Z8VHHwiOP8AoHW//sleSq26vvOO/wDfsN/15j+cj6LiP/eKX+BfmxaKKK+GPnRD8zb80obdzQuznbSKu2l8QCKuG59KdRRS+EApV6H6UlFSAm/cxpaKRl3VfwyAWgDf2opeVNMAVfmNbXgbRpta8QW2mQWzTO0q7Y1/i+asVPvCvpX/AIJn/BK5+Lv7R2i2zov2azn+0XrSfdWNfm3N/s1x4utHD4eU30NMPRlXxEYfzH6d/slfCu1+EPwB0HwfbP5V3NZfar9W/wCWcki/3f8Adr0ySwmjaLe6s8fzPJv27qnax/0x97q+19qsqfLt/wBmpzp/2pjvSRXXcrN/e/3a/J8TivbYiUpH7NhcPHD4aMexhTafc7U+0Iy/vW3tH/Ev8NULjTbm3ZI7ZJG/vw7/AJv96u1tdPTzDMkK/wC633Wqvq3h95G37Jm8yJvmX+FV/h3Vzqt7yCeHpcvMzifs7wybOrb/AJ2/2akkmm3KUTc38bSL8sldHD4bh8kO8PlFv738S1m3lj5a+Sn3li3bv4lrWjU5veOX2PNHmkc1qkzry+1X+8qr8y/7tcnq15Z/bhCH8maTcrr92us8RLDcN99kfbuTcnzfLXC+JrqGbTzI8agq/wAzbPmb/ar3ctlaV3seFmGH93Qy9Qv0uFf7G7L5b7fMWsi6urmZmd7liY33J8+2p7q8fH3MKqbVVf7396ub1LVnhmabzl3Mux1/hWvpcPU6HxuMp8sixqk0Pls/zfKm51j+9u/vVzerXOLfzt7Etu+Zv4mWpNS8QJNG9siKWkT70bVgX2uQyNvTc0m3+J/lr1afNLlPIqchl/ES/F7ptoylSA3XuODxT/B10i6PHayScNu/i6fMax/EV5FdWiBGJIk5w2V6Gm6TqENtDAs0bqF3t5gr+h8yX/HOmD/7DH+VU+VpS/4yqo/7n/yJ0dvc+Zs+zTblmlb5f7tct8WdUmh8M3P2N9u6Lb/u1pQ3ht4z95S27Zt/9Crz74peKobdpNNm2u8ybvLb/dr+fOWXMfTxlKR8o+OleTXLi5f77St8zVQ0a8+zTMX+61anjbfJrErv9xn3Vz6ymKdWT5gr7q6Ix93lNInT+TJGrv5ON396sq+kePCPux/s1oQ3iXVim+b7392sy8+bc6Oxb+7Vf3SOX3ynI2W92qOTH8H3akkkdmCbFqLad3yVJpEG3tJ5jvg1YtdQmhbf5zbf7tRNDMw3/epTbuvyd/8Aaqv8QG5YeKHRRvTcP9qtvT/EbyM0KbV3VxEcbt8mxqu2vmxss2xv92lzcpMjsvM+0Nv2Krfd21PZWu7M2Vf/AGax9HvE8hfnY/71ben3iBvJRPvfxLWvNzRMTT8O6f8Abrj7Ns2fOqru/u11/wAQP7Sj0m20S2tZAkMW6Vv/AEGub8J3cMepQpc7U+ba7N/vV6pfNpraO2qpD9sLRKrKz0+YjmjznhGvTfZ7WX5MJs+ZdtecTMWmL7Mbq9z8fx+G9WtUtobCS2kZd3l/erx7xF4fm0q43pC3lN81R8PxG1OVzKpVZ92ykp0KoJF37qDpNfw7a+Y/yDn+KrXjCYRxw2aXO5F+bbU/hi2SNTM7rjZu+7WHrl895fu+9WVn+8tL7Zjy80ymT5jVo6fNPHbnY/zVnxj95h62dJWFY2Gz/gTVASL2l3jvamF33u1N1Ka5t92z5xUVuqeYfJf5lqXUv304hR237P8AgNBHw+8ivp+rXNw3k/d/h+ar91eJbxs+zb/DuWo7exhtYzJUd8ySQmF+T975a0Fze+Ot9S3SK7zLhv4a2LFN0Ms0LsUWudt9Pe6ZcJ92uq0GZ7O3dHRQjJ8yrQHxEng2cjxFDEpyHV8n/gJq18QWH9pQpkAi3yuf940eHbWBPEkM0KEAb15X/ZNHj+yludXgKZwYAoIHfca+7wycuAa1v+fq/KB9NRXNwtU/6+f/ACJzK6wnmeW752/3q0Yd7w/aem77lZ0GiMW2GLJX73y/LWjG9xbxiNo8jG3bivh5UnGV7HzXLLl2H2+9eZod4/vVJIsLMjumDJ8tQTS3Yk8xIGO7+6Pu1EpupLhIXgkAb+LFLkn2CVOUehNcW/8AtsG2/wDfNV41fy9/nMR/HUu+4W46N8rY+7TGhlULHtZk/vMKXJV+yg5VzbDJGfOx5lP/ALLWdqiqsn3N23+Ja05bIz52RyL+FRt4fupovuD+90olSn2K5ZdjmprN2k+Tgf3qhNjM67Nm75f4a6geG5IVVHQ/7fFSt4PeJd0GcN93j7tVGlPsR70eh7V8NIXP7MyQAEsdFvQPzlr57vNPm09Y4nh2Mv391fTXwoswvwasrCQqQbOdGPbl3FcL+0/rHgvxLq3h7w54B8ARaOvh/S2t9W1EXnnHVLhm3eZ/sqq/dWv3fxphJ5Bw1Zf8wcP/AEimfMZC39axX/Xx/mzn/Btr/wASNX+9/fX+6tadrPNpNwuq2b7Zo/8AVN/dqDwdHI2ieW0ZUq+1t4q7cRyI0n7jj7u5a/CqcJW2PoalPm0sfYP7Fv7c2pWMln4P8ba81pNCn+gal5u1t38KrXb/APBU7QdV+OPw7b4y6lpTTajpMSs81vF/ro9v3mavgDT7m90m6S5tmb9z8y7fvV9R/A79sBvEHwy1L4O/EG/jLXWmtbxXd3u2sv8Atf7VaxnWpaW904KuE5/ft7x8t+G4vJjmT5vvD7wx616t4f4+GDEj/lyuP5vXm0dimnapfWcUyyRx3BWN0fIIBNek+H8n4YMMZ/0K44/F6/q3wVTWVVP+wWv/AOnInocY3XB+X3/5+/8AyZ5jZ7I/k2Nn7ySf3qtR2/nMrvGud+7d/eqrbqvkjd8jf+g1djX942z7q/3Xr+UDk5kIFdbgQyfK391fmqXakjeTsYtt+7v27ae0LtHvgfbt+7SiEtDs/ePt+98nzNUfYKjKW8iNdm5k37fm+9UCypCVRPm+fazbNy1buFQ7odm1tm5Vaq7RC3dnfzAI/wCJqrmQR+KwvmeX/pIh+ZabaMkirs/vfxVFM23915P/AMTUm3bcMiSbdybaxkd8dizDcP8AZ2R4N/zbUbf92p45odo+f5f4KpMU2q7u3zLtqRWRoWkR1b+5WXL9o6o85pfa0jh8npuX+F6s2MvmRpM/zfK27dWVH/qk38lfm3VcjfyWV0dl+Tb/ALNLlQpSka1tJ5y53/d/h/vVYt23K80yKNr/AC7X3Vm2s27Y7/LuT5NtXbObazO5VGb5mVnreJx1uXoaFjMVVdj7n2bVjX5aZcrBsKOjMZPlpkbAyIkKYXZu3Sfw0jMis2987fl8tfu/71X/AITg92XunGX1r5LtM+7bu/v1LYrvj87yVbd9z/aWrGqRp882/I2fdp1vHtVY1Tjb8jKlR7GfKe3Rlyk9rbpM2Xh/h/75rVtWeFl/fbl/u1ShjeO3/cup/wBmtG1X5tnk7Rtrz61GUT2sLU/8CLtjHuVWm/5afxMvzLWjptx50uzyY/l+6v3dy/8AxVZtvcpGxfev/fdXbWRLrY8KbDJ833Pl3V4+Ipy+yezTrSlLlcjoNNkeOYPsUsz/AMX8K10Wm3yRwoiPtbZu3f8AxVclYt9njimuQq7dysyt95q147zbiaS52ovzblT/AGa8mp70j0abjE7G1utrb3fzNzKrrv8A4a6DS9Q+zTRedDuTdufdXE6Xrnlsu/8A0hZE/esr7WX5flWt3SdSmWOLY8ON6rtkb7tcso8p3xqRO+0nUYbdi83T+6v+1WkurWEbSIm1/Li+eTdt/i21xOn645kZ0RWMaM23f8zVoyapDCyO6f6xN33vlq8PzxkY4iUJFD45T58H3CFyAZ1VV7HDg5ri/ht4h0rSdInt7zUI4JWudyiQjBG0Cux8XRJrelzaRfAGOQqVcnJB7Hd9a89u/h+bSEzNrCnAyFMOCf1r+pfDXiTw9x3hbiuFuI8dLCyliPaqShKV1ywtZxjJaODvdLRq19bfknEeBzmnxDDMcFSVRKHLulZ3e92u+ljo9a8Z2KRMLLW4JGZepcN5f+7XF+M/Ecw0Oa10h3eW6G2baNxYepx0pZPDhjkihN4N033f3fA/HNcrq/jHT9M1WbTYl85YZvLaYNtBx1I9hXdR4N8BJS9ziCq/+4M//lR5GIzHih6zwkV/28v/AJIzNO0jV5LtFW2aJVOd0qEDHpXTazOLe1ENhA8gI2bQueKit9RSa0S6eMrv5CA5OPWql74ptbOV4jAxKerYrsXCHgVGV/7fq/8Agqf/AMqOKGO4kvph1/4Ev8zndRstbRiU026bO5QsUR4/+xri9b8LeLrq5ynhnUHG/duFu3+FdnqXxqtNPkMQ0F5GHULcDI/8drIl/aW06LIPhaQkdvtY/wDiaX+qHgVv/rBU/wDBU/8A5UNZhxH1wy/8CX+Zxk3gzxrCjSr4N1J2ZWwotW+X9Kxbv4b/ABJ1ad5Z/B+oqV+4XtG/wr0Zf2obE4P/AAh8uD0P20f/ABFMuP2qdMtxk+EJTx/z+jr6fcqv9UvAp6/2/U/8FT/+VDWM4j/6BV/4Ev8AM8tk+GXxJS0eIeA9TZ93DCyf/Cs24+FHxPD7k+HurN/24v8A4V68v7WNk0ZkPgeUY7G/HP8A45VZv2w9OVA//CBz89R/aA4/8cqP9TvAn/ooKv8A4Kn/APKi/r/Etv8AdV/4Ev8A5I8pT4TfFCF98XgHVhn/AKcX+X9K6Hw38PviL/y++BtSjBGCXsnB/lXYn9svTeSPAUxA7/2iP/iKki/bBsnRZX8ATqrHAb+0Af8A2Sn/AKoeBUdf9YKn/gqf/wAqE8dxH/0Cr/wJf/JHOat8IfFdzC0kHhe7JX7oFswJrk9U+CvxJQlo/BWpSD0jtGP9K9p8MftL6L4in+zv4fktmzjDXQb/ANlrqbz4gi3hE0Ok+aD023GB+e2kuEPAiWi4gqf+Cp//ACohZhxFT976srf4l/mfMK/CP4pMmxvh/q4z0zYv8v6Ui/B74pKCo8A6uM+li/8AhXuet/tJNorMr+BZZNpx8t+B/wCyVhy/tl6dEpZvAM2R2/tEf/EUPg7wJX/NQVf/AAVP/wCVGkcx4jlthY/+BL/M8pj+EXxPYFX+H+sAbu1i/wDhSJ8IvimAVHw/1fP95rF/8K9VH7aGm85+H84x/wBRBf8A4inH9s7S1bafAU3/AIMB/wDEUf6oeBNv+Sgq/wDgqf8A8qK+v8S/9Aq/8CX/AMkeXR/CX4peTz4D1YMPu4sX/wAKkt/hT8UB/rPAWrbv732F/wDCvTv+GytNwGHgKYg/9REf/EUp/bJ00cDwFOT6f2gP/iKP9T/An/ooKv8A4Kn/APKhLH8SrbCr/wACX/yRwFj8MviVEAX8D6pjrg2T/wCFdNpvg3x2lsEn8HainbCWrj+lb1t+1/Y3DBB4CmBPb+0B/wDEVZb9rDSI4zJN4RlUL/0+j/4imuEPAn/ooKn/AIKn/wDKifr3En/QKv8AwJf/ACRwOrfDr4hTTNIvgrU2O75WWzf/AAqOL4Y+PxEvmeC9T4GcLZv978q9Bt/2r7O5OE8Dzf8AgeP/AIirR/af01QzP4TkUKuTm9HJ9PuUv9UPAm3/ACUFT/wVP/5UQ8dxF/0Cr/wJf5ni2tfB34nm4E0XgPU33dTHZucfpVM/B74qD/mnur/+AD/4V7QP2tLJpPLTwLP7E34A/wDQKfcftX2kVu08XgaZyv3k+3gEf+OUf6peBMv+agqf+Cp//KjWOY8S/wDQKv8AwJf/ACR4n/wp/wCKn/RPdY/8AH/wo/4U/wDFT/onusf+AD/4V61/w2lpv/RP5/8AwYr/APEUf8Npab/0T+f/AMGK/wDxFV/qh4Ff9D+p/wCCp/8Ayov+0OJ/+gVf+BL/AOSPKIvhB8U+/wAPdW/Gwf8AwrT0D4I/EfUdRjtrvwbqVujMu+WW2ZQv4mvW/Cv7T8ni/VE0nSPh5O0j9T/aAwP/AByvSbHWZbsfvrMRsByPNyM+nSsp8LeA9Ne9xDUX/cGf/wAqOermvEMNJYaK/wC3l/mcT4W+HVz4Y0uPSrTSsbBmR9n32rX/ALJ1OCUTw2EquOgRDiukfU40yCoyG2kFqbJqrxlV+yZZhnHmDpWD4T8A5b8RVf8AwTP/AOVHO8dn3XDr71/mei/CbxhplnojaZrN2kLSLkm4IUA/jXUxeKvB4f7SfEtsH3YQ+YvAry/4f+G5vHl1LbQSPB5QBLiIyDn8RXTyfBK8VTt1+MnqFNuRlf733qh8HeAXXiGr/wCCZ/8Ayo5Vi86V4+wX3r/Ml1bWdPtL+SSx8Q2zowZcQzADDVDF40trQhZLtJViTA8qQLmqV58L5bOaOJtZDCT+Jbc8H060SfC+RceXrsbk/wAKwnP5ZrCpwP4BPfiKr/4Jn/8AKinic8jvQX3r/MkfxqJXz9rRWK8PjpVNvGE9wogIi3BWHmO3FSN8NZoztl1mNCRld0R5/WmzfD62gh3v4jiLn7qLATn8c4qY8EeAFv8Ako6v/gmf/wAqB4nO/wDnwvvX+ZWuNN0++jluNQ8RRSN/CPMHHy9lryTWdG8TC9lE2nyyr5jYniQn5a9Zm8HvEhk+37lHdIScfXnis3VtJubGykuCysohZ+Tjiq/1J8AOZP8A1hqtx/6cz/8AlRrSxueKStQX3r/M+evF+g6v4j0xNO0XTJruX7QjtFBGWO0ZycDt0q5pPgbxlbRhH8OXg2/dBt2/wq9puvTaPqbJpmpJHdKCjKrKWxn0P0rWTxn42lx5eozNnptgU5/8dr3cRw/wHxDUWNxuMqRnJJfu/ZOPL0fvSTvqfrfEGV5lmuO9vg6tHkcV8UpJ/gmrGangvxVKNz6LcpuGOLc/LV8eAtWISNtGlCqm3PlnNSf8Jh45zj7dPnOMfZ16/wDfNO/4Svx9nb9qucg4I+zDr/3zXP8A6heGH/QdiPuof/JHgvhniB71sP8A+Bz/APkSg/gXWoY3SHRLv7vy5iJrB8eeB/G9x4XuF0/wveyzSoF8uKAlhnrgCuuTxR8QZCQk902Bk4tQcD/vmq+p+P8AxZotv9s1jWmtIcgebcxpGufTLACn/qH4YWt9exH3Uf8A5IqPDXEMWn7XD/8Agc//AJE8H/4U/wDFT/onusf+AD/4Uf8ACn/ip/0T3WP/AAAf/CvaP+F1t/0UCx/8CYaP+F1t/wBFAsf/AAJhpf6h+GH/AEHYj7qH/wAkb/6v8Sf8/MP/AOBz/wDkTxf/AIU/8VP+ie6x/wCAD/4UH4PfFM8H4e6v/wCAD/4V7R/wutv+igWP/gTDR/wutv8AooFj/wCBMNH+ofhj/wBB2I+6j/8AJB/q/wASf8/MP/4HP/5E5nXfD+t33w8/4R2z0qeW/wDscMf2SOImTeu3cu3rkYP5V543wd+Kh5Hw91f/AMAH/wAK9Ou/jR4c8HapD4hFxHqk7Ss3k2lwpySOSzDIXr6c/wArv/DaWm/9E/n/APBiv/xFdOLybwszionnObSoVKaUIxjBzvBaptxhJJu7ur9NjPjLG5rTx9KGDpRqJU0pPmWkrvTddLP5nkv/AAp/4qf9E91j/wAAH/wo/wCFP/FT/onusf8AgA/+Fes/8Npad/0T6f8A8GI/+N0v/DaWm/8ARP5//Biv/wARXL/qh4Ey/wCagqf+Cp//ACo+Q/tDif8A6BV/4Ev/AJI8l/4U/wDFT/onusf+AD/4Un/Cnfip1Pw91g/9uL/4V63/AMNpab/0T+f/AMGK/wDxFH/DaWm/9E/n/wDBiv8A8RVf6oeBX/Q/qf8Agqf/AMqD+0OJ/wDoFX/gS/8AkjyX/hT/AMVP+ie6x/4AP/hR/wAKf+Kn/RPdY/8AAB/8K9Z/4bS07/on0/8A4MR/8bo/4bS07/on0/8A4MR/8bpf6o+BP/RQVP8AwVP/AOVB/aHE/wD0Cr/wJf8AyR5N/wAKf+Kn/RPdY/8AAB/8KP8AhT/xU/6J7rH/AIAP/hXrJ/bT00DP/Cv5/wDwYr/8RQf209NAz/wr+f8A8GK//EU/9UPAr/of1P8AwVP/AOVB/aHE/wD0Cr/wJf8AyR5N/wAKf+Kn/RPdY/8AAB/8KP8AhT/xU/6J7rH/AIAP/hXrX/DaWm/9E/n/APBiv/xFH/DaWm/9E/n/APBiv/xFH+qHgV/0P6n/AIKn/wDKg/tDif8A6BV/4Ev/AJI8l/4U98VN27/hX2sf+AD/AOFH/Cn/AIqf9E91j/wAf/CvadG/a30zWmNtB4MlS4I/dQvfj94fQHZVS4/bItbWZref4dzq6NtYNqQ/+N0v9UfAn/ooKn/gqf8A8qD+0OJ/+gVf+BL/AOSPI4fg78UmcB/h9q4HfNi/+FfoP/wS00PwR8FfB2reLfHviTTNK1TUZUtYrHUZVimEJGXc7jkDIAr5p8D/ALTU3j3X7fw7ovw6uWuLmURxhb0Nlj2+5X2Fpf7GepajbwSv4+hiaSBXmU6cx8pyu7YTv5x6142c8KfR8dD2WI4kqwv/ANOZv/3Cz1soxfGMsT7ShgYza6OSX/tyPp3Sf2g/ghboRL8UtByGwSdVjyf1ra079ob4ASTstz8XPDZVtvzSavEv/s1fMmm/8E/9U1CHzj8T7dB6f2Sx/wDalbVj/wAEzdZvWC/8LdtkJGRu0Zv/AI7Xxb4D+jJKP/JVVv8AwRU/+Un3P9t+Jriv+EqH/gyP/wAmfS8P7Qv7OccnHxp8MEk4z/bMQ2r/AN9VauP2i/2a5kMsfxr8LguclDq8Xyj+Ifer51g/4JQa/PCZl+NVpgdv7Dbn/wAjVOn/AASV1uQnb8crMgdcaC+R+HnVmuBPoxR/5qut/wCCKn/yg0Wd+J8fdeUw/wDBkf8A5M9u1H9oP9nnzXaD4z+GWG0qrDVot23t/FXO6t8dPgdcRhofi74cDfx/8TWI7v1ry5/+CTniINsT4z2rE9MaE3/x6sK8/wCCauq2c7QP8YLQlSQT/YzYBHb/AFtbU+A/ozL4eKq3/gif/wApIqZ34nOOuVQ/8GR/+TO5134v/B2a4Zl+JmjygFiCt9Gf61w2sfEr4e3bK8XjvTUVRjbHcpnG761zurfsLajpcvlj4mW0gBxIw0xht/8AIlYV5+yVqNsWEfjaFyrlSPsJByP+B16OH4G+jdS1XFFZ/wDcCf8A8pPJr5p4hzupZZD/AMDj/wDJmjrfjzwuAwh8R2MpDfeS5XLt/ePNc9rHjHR5J2U69bPEyfuhA4G1v9qqWp/AG/012RvESSY4G21PJ9PvVzd/4Fm08ssuoAlBkjyu3r1r3sPwZ9Hz4ocR1X/3Bn/8qPm8VmHGUm1PAxX/AG8v/kjR1bxFZTsUtL2IEjG8ycZ9aw7q/Mrl2u0Vi+52TnH+7WdeJDZsUe5TKrls8Yqn/acQfy9vPqGyK9mlwb4EKPu8QVf/AAVP/wCVHj1sfxM/iwqX/by/+SNK7u/OjWJSAoOdvU5+tJBeeQoAhBIBGSfWqkdwsjBAOT6HNWobVZV3mXHOMBSea/UcrzjwGwvCNPh3G4/6zQhN1FzQrxfM76+5COyk18z5+vR4hnjXiYU+WTVtHF6fNsdLqDOpWFNgYYJ3ZNch4q+HLeKNWTVJdcMWyMqI1tgc5753V1GtqdEt/tMpDKELE5xgCvLLT9pzTb3XLrRrfwpKRbMR5xvRhse23iuSMfotbrl/8uzaK4wtpf8A8kKWqfsm2epzNM3jqZNxzj7AD/7PWcf2LdPJz/wsGb/wWj/45VzUf2vtO0+Roj4GmYp1/wCJgB/7JVT/AIbT008j4fz/APgxH/xFVb6Ln93/AMuzSMeNOl//ACmXdP8A2RrCwiMX/CcSOD66eBj/AMfpk37IdnMdz+Pps5zn+zx/8XU2m/tZWGor8vgiZG/um/B/9kpb39rKxsjtbwPOx9BfD/4ip5votf3f/Lsl/wCuV9b/APlMo/8ADGWmnO7x7Mc+unD/AOLpf+GNdOHTx5IPppo/+OVMv7X1g2D/AMINJg9T/aI4/wDHKkj/AGt7GUZTwPL0z/yEB/8AEUW+i1/d/wDLsd+M/P8A8plf/hjnTun/AAnUmPT+zh/8cpT+x1phIY+O58jv9gH/AMXU5/a405Bvk8Eyqp6MdQGD/wCOVEf2wdNAyPAs3XH/AB/j/wCIp8v0W/7v/l2Lm4yXf/ymH/DH+m5yPHEv/gvH/wAXT0/ZFsURYx47lwvQf2eP/i6hP7ZGmBtn/CCzZ99QH/xFKv7Ymns20+Aph/3EB/8AEUL/AIlc/u/+XY1/rn0v/wCUy5D+ylZQAKnjaXA7fYB/8XVuD9me1tyTH4vfJ6n7CP8A4ussftgaYV3HwNPj/r/H/wARVuy/apsbtwjeCZ03fcP20HP/AI5Tt9Fz+7/5di/4zLz/APKZsW3wBsbdg/8AwkTs2MFjajn/AMerotD8E3OjRNB/bzTRn+BoMD/0KsnQvjNb62wVPD7xk+twD/7LXVadqF5qCLMbARRNnbLJN8vH4Ukvot9OX/y7M5f63x0d/wDyQguPB3hm8XN3o0LOG+WRV2kL/drndZ+BnhPWUkilZkVwRgLnGfxrrbzUrSxYRzTIxK7j5bbgPxqeBlnsTeqwAGDtY44PetLfRf293/y7Dn4v8/8AyQ8Uuf2MdKlmaS38eTxqT8qnTwSB6Z30QfsZ6dERv8fTMAc4/s4f/HK9E8T/ABIk8PCYw6A1yIRkkXG3I/75NcRH+1hbvKYX8AXCket+P/iKhx+i515f/Ls0VTjK27/8kLEP7LlnBam2Txk/K7QxsBx/4/WTJ+xlp7yeYPH8w9v7NH/xytC4/ax0y3nNufB0pK/eJvgMf+OUxv2tbIKZF8CzFR/F9vH/AMRRb6Ln93/y7Dm4y/r2ZRH7GGnhxJ/wsCbIOf8AkGj/AOOVbT9kWwQEf8JzLz6aeP8A4umP+1/ZRn5vAM2PX+0R/wDEVbi/asspIfN/4QqUe328f/EUmvoudeX/AMuwcuMut/8AyQq/8MhWe/d/wn02B0H9njj/AMfqVf2TbYdfHcp/7h4/+LqRf2rrJsH/AIQiYZ9b4f8AxFIf2rbUKH/4QabGMn/Txx/45Tt9FyP8v/l2HNxlJ9f/ACmOi/ZVtIsg+N5SD2NgP/i6hm/ZKtJWLL47lXPUDTx/8XTx+1jZ+XvPgeUHsPt45/8AHKT/AIaytMZ/4QWbn7uNQX5v/HKm30Wv7v8A5dh/xmUe/wD5TJLL9lWzs2DjxtKxAxzYD/4ur8f7N9isJhk8VSNk5z9jA/8AZqoW37VVtcReYPA0y+xvx/8AEVL/AMNSaaMb/CEoz6XgP/stH/HLX93/AMuw/wCMy8//ACQv2P7PVvYagl/F4rkJXOUNmMHIwf461v8AhUVv/wBBx/8AwHH+Ncx/w1RphGR4Ql6/8/o6ev3KWP8Aaks5JCn/AAhUwA/iN8P/AIivay/P/o6ZTQdLC1Yxi3e1sU9duqfY78JmniDgabp0JuKbvtTevzTOm/4VFb/9Bx//AAHH+NH/AAqK3/6Dj/8AgOP8a58ftMWgQO/g6Zc9vtg/+Jpy/tKWrIH/AOEOmweTi8HA9fu16H+uXgH/ANBEf/AcT/8AInV/rD4lf8/X91L/ACN7/hUVv/0HH/8AAcf40f8ACorf/oOP/wCA4/xrE/4aRsN20eFZCQMti7HH/jtNH7SmnmLzP+EVlHt9rH/xNH+ufgF/0ER/8BxP/wAiJ8R+JK/5ev7qX+Ru/wDCorf/AKDj/wDgOP8AGj/hUVv/ANBx/wDwHH+NYS/tJWrRGX/hEJAB2a9Az/47Tl/aPtTGJW8JSAMu5QL0HP8A45SXGfgC/wDmIj/4Dif/AJEf+sPiVa/tX91L/I2/+FRW/wD0HH/8Bx/jR/wqK3/6Dj/+A4/xrCX9pO0Ztp8IygjqPtg4/wDHKV/2krRFD/8ACITEE4yLsf8AxNP/AFy8A0r/AFiP/gOJ/wDkQ/1i8Sl/y9f3Uv8AI3P+FRW//Qcf/wABx/jR/wAKit/+g4//AIDj/GsNf2krJmIPhOQc4Gbwc/8AjtW1+P1kbN7w+HGASMsR9rHb/gNC4z8Am9MRH/wHE/8AyInxF4kr/l6/upf5HZWGhJY+Hv8AhHxclh5Lx+btwfmzzj8a57/hUVv/ANBx/wDwHH+NYWifHuXxvpc50vQmsWVtola6Dnn0+UYqhq3jHxPHap9m1m6JQ4kkW5IzXh8VeM3hXCtRw1PDTxcKcEoyjzQjFbcvvuMm0krtr5t3tnlMuMcDKrVpV1SlVk5Suou73vs0t3oreh1n/Corf/oOP/4Dj/Gj/hUVv/0HH/8AAcf41zGkeKvEU1opl8QXOZDnc07E/hRc+J/FCSErrl2Btzt8818xHxg8Lmr/ANkVf/A//tz1nm3Hi/5jl/4BD/5A6f8A4VFb/wDQcf8A8Bx/jR/wqK3/AOg4/wD4Dj/GuNbxh4vkYx/8JFcKyDLbZ2qD/hMvF+XB8RXYJ6f6S3FV/wARe8L72/sir/4H/wDbkf21x3e315f+AQ/+QO5/4VFb/wDQdf8A8Bx/8VWvNpsHhzwPPpc14GWO0lXzWwm4tuIA565OK8yTxn4qMZJ8QXob0Nw3+NQXfibWtRTyb/V72VCOInmJGfXFKXjbwPgMNXlleV1IVp05QTlP3fetv70tLpPRX0st2cGZx4jzlU4Zhi1OEXzJcqWvyivxEt5E8wq6f8B/u1ct/wB43VU/vts+9WfBJtb5HXLfd+X5qt28nlr++feq/wAWyv5gj5no/wB0un7MuC6bPk+9vpbpU8sTJ/c/heoPtCM294VZG+XcyVFdXDtGzo+D/s/d20ve+0ae7GkS3F3uk+RIx/CjfxbaguI0hwPm2N/eak852Z4XRT8nyN/eqOSaZY0+RsL/AAstKUpfCgp0+b3hftCT5TYp2/M6tTPtCRs37nd/danXEkMUao6Lub5qrtcbfnmTc33kVf4qxlsd9O32iWPfJIZk+T/pmzfeqdfIaHZ/D/s1T+0QyLvf71TLMjbUQfOv/jtQbl6Fvs67xtVf4131ct5pI5N7pvVvl2tWdC32htl1CvzfxVfik2SfZptrK33KnafMKX90uwXRZjbfZlcLtbdv/irQtpEjmBRGVm/hVfm3Vmw9t/ytu+7sq5Hcea332T+J261rGPNucFaUoy0NVbhPJVPJyv8AEv8AFTFaf93sm2N/B8u1tv8AtVFZzybm3vvXZuT/AGac1xD5yTTJudflfa9a8vL8Jyc3vH//2Q==\n", "text/plain": [ "" ] @@ -632,7 +632,7 @@ "width": 600 } }, - "execution_count": 38 + "execution_count": 5 } ] }, @@ -664,30 +664,30 @@ "base_uri": "https://localhost:8080/", "height": 65, "referenced_widgets": [ - "8815626359d84416a2f44a95500580a4", - "3b85609c4ce94a74823f2cfe141ce68e", - "876609753c2946248890344722963d44", - "8abfdd8778e44b7ca0d29881cb1ada05", - "78c6c3d97c484916b8ee167c63556800", - "9dd0f182db5d45378ceafb855e486eb8", - "a3dab28b45c247089a3d1b8b09f327de", - "32451332b7a94ba9aacddeaa6ac94d50" + "355d9ee3dfc4487ebcae3b66ddbedce1", + "8209acd3185441e7b263eead5e8babdf", + "b81d30356f7048b0abcba35bde811526", + "7fcbf6b56f2e4b6dbf84e48465c96633", + "6ee48f9f3af444a7b02ec2f074dec1f8", + "b7d819ed5f2f4e39a75a823792ab7249", + "3af216dd7d024739b8168995800ed8be", + "763141d8de8a498a92ffa66aafed0c5a" ] }, - "outputId": "81521192-cf67-4a47-a4cc-434cb0ebc363" + "outputId": "f7e4fb76-74db-4810-c705-b416bc862b52" }, "source": [ "# Download COCO val2017\n", "torch.hub.download_url_to_file('https://github.com/ultralytics/yolov5/releases/download/v1.0/coco2017val.zip', 'tmp.zip')\n", "!unzip -q tmp.zip -d ../ && rm tmp.zip" ], - "execution_count": null, + "execution_count": 3, "outputs": [ { "output_type": "display_data", "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "8815626359d84416a2f44a95500580a4", + "model_id": "355d9ee3dfc4487ebcae3b66ddbedce1", "version_minor": 0, "version_major": 2 }, @@ -715,57 +715,54 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "2340b131-9943-4cd6-fd3a-8272aeb0774f" + "outputId": "71a0355d-fe5b-4c8a-9ed2-f824dc776272" }, "source": [ "# Run YOLOv3 on COCO val2017\n", "!python test.py --weights yolov3.pt --data coco.yaml --img 640 --iou 0.65" ], - "execution_count": null, + "execution_count": 4, "outputs": [ { "output_type": "stream", "text": [ - "Namespace(augment=False, batch_size=32, conf_thres=0.001, data='./data/coco.yaml', device='', exist_ok=False, img_size=640, iou_thres=0.65, name='exp', project='runs/test', save_conf=False, save_hybrid=False, save_json=True, save_txt=False, single_cls=False, task='val', verbose=False, weights=['yolov5x.pt'])\n", - "YOLOv3 🚀 v5.0-1-g0f395b3 torch 1.8.1+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16160.5MB)\n", - "\n", - "Downloading https://github.com/ultralytics/yolov5/releases/download/v5.0/yolov5x.pt to yolov5x.pt...\n", - "100% 168M/168M [00:05<00:00, 32.3MB/s]\n", + "Namespace(augment=False, batch_size=32, conf_thres=0.001, data='./data/coco.yaml', device='', exist_ok=False, img_size=640, iou_thres=0.65, name='exp', project='runs/test', save_conf=False, save_hybrid=False, save_json=True, save_txt=False, single_cls=False, task='val', verbose=False, weights=['yolov3.pt'])\n", + "YOLOv3 🚀 v9.5.0-1-gbe29298 torch 1.8.1+cu101 CUDA:0 (Tesla P100-PCIE-16GB, 16280.875MB)\n", "\n", "Fusing layers... \n", - "Model Summary: 476 layers, 87730285 parameters, 0 gradients, 218.8 GFLOPS\n", - "\u001b[34m\u001b[1mval: \u001b[0mScanning '../coco/val2017' images and labels... 4952 found, 48 missing, 0 empty, 0 corrupted: 100% 5000/5000 [00:01<00:00, 3102.29it/s]\n", + "Model Summary: 261 layers, 61922845 parameters, 0 gradients, 156.3 GFLOPS\n", + "\u001b[34m\u001b[1mval: \u001b[0mScanning '../coco/val2017' images and labels... 4952 found, 48 missing, 0 empty, 0 corrupted: 100% 5000/5000 [00:01<00:00, 3320.65it/s]\n", "\u001b[34m\u001b[1mval: \u001b[0mNew cache created: ../coco/val2017.cache\n", - " Class Images Labels P R mAP@.5 mAP@.5:.95: 100% 157/157 [01:23<00:00, 1.87it/s]\n", - " all 5000 36335 0.745 0.627 0.68 0.49\n", - "Speed: 5.3/1.6/6.9 ms inference/NMS/total per 640x640 image at batch-size 32\n", + " Class Images Labels P R mAP@.5 mAP@.5:.95: 100% 157/157 [01:44<00:00, 1.50it/s]\n", + " all 5000 36335 0.642 0.61 0.621 0.416\n", + "Speed: 13.8/1.1/14.9 ms inference/NMS/total per 640x640 image at batch-size 32\n", "\n", - "Evaluating pycocotools mAP... saving runs/test/exp/yolov5x_predictions.json...\n", + "Evaluating pycocotools mAP... saving runs/test/exp/yolov3_predictions.json...\n", "loading annotations into memory...\n", - "Done (t=0.48s)\n", + "Done (t=0.42s)\n", "creating index...\n", "index created!\n", "Loading and preparing results...\n", - "DONE (t=5.08s)\n", + "DONE (t=5.00s)\n", "creating index...\n", "index created!\n", "Running per image evaluation...\n", "Evaluate annotation type *bbox*\n", - "DONE (t=90.51s).\n", + "DONE (t=78.37s).\n", "Accumulating evaluation results...\n", - "DONE (t=15.16s).\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.504\n", - " Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.688\n", - " Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.546\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.351\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.551\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.644\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.382\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.629\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.681\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.524\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.735\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.827\n", + "DONE (t=11.12s).\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.433\n", + " Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.630\n", + " Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.470\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.284\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.485\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.538\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.346\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.581\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.634\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.474\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.687\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.766\n", "Results saved to runs/test/exp\n" ], "name": "stdout" @@ -916,61 +913,72 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "e715d09c-5d93-4912-a0df-9da0893f2014" + "outputId": "3638328f-e897-40d5-c49f-3dfbcea258a9" }, "source": [ "# Train YOLOv3 on COCO128 for 3 epochs\n", "!python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov3.pt --nosave --cache" ], - "execution_count": null, + "execution_count": 6, "outputs": [ { "output_type": "stream", "text": [ - "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", - "YOLOv3 🚀 v5.0-2-g54d6516 torch 1.8.1+cu101 CUDA:0 (Tesla V100-SXM2-16GB, 16160.5MB)\n", + "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov3 ✅\n", + "YOLOv3 🚀 v9.5.0-1-gbe29298 torch 1.8.1+cu101 CUDA:0 (Tesla P100-PCIE-16GB, 16280.875MB)\n", "\n", "Namespace(adam=False, artifact_alias='latest', batch_size=16, bbox_interval=-1, bucket='', cache_images=True, cfg='', data='./data/coco128.yaml', device='', entity=None, epochs=3, evolve=False, exist_ok=False, global_rank=-1, hyp='data/hyp.scratch.yaml', image_weights=False, img_size=[640, 640], label_smoothing=0.0, linear_lr=False, local_rank=-1, multi_scale=False, name='exp', noautoanchor=False, nosave=True, notest=False, project='runs/train', quad=False, rect=False, resume=False, save_dir='runs/train/exp', save_period=-1, single_cls=False, sync_bn=False, total_batch_size=16, upload_dataset=False, weights='yolov3.pt', workers=8, world_size=1)\n", "\u001b[34m\u001b[1mtensorboard: \u001b[0mStart with 'tensorboard --logdir runs/train', view at http://localhost:6006/\n", - "2021-04-12 10:29:58.539457: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcudart.so.11.0\n", + "2021-04-12 21:26:33.963524: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcudart.so.11.0\n", "\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.2, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0\n", - "\u001b[34m\u001b[1mwandb: \u001b[0mInstall Weights & Biases for YOLOv3 logging with 'pip install wandb' (recommended)\n", + "\u001b[34m\u001b[1mwandb: \u001b[0mInstall Weights & Biases for YOLOv5 logging with 'pip install wandb' (recommended)\n", "\n", " from n params module arguments \n", - " 0 -1 1 3520 models.common.Focus [3, 32, 3] \n", + " 0 -1 1 928 models.common.Conv [3, 32, 3, 1] \n", " 1 -1 1 18560 models.common.Conv [32, 64, 3, 2] \n", - " 2 -1 1 18816 models.common.C3 [64, 64, 1] \n", + " 2 -1 1 20672 models.common.Bottleneck [64, 64] \n", " 3 -1 1 73984 models.common.Conv [64, 128, 3, 2] \n", - " 4 -1 1 156928 models.common.C3 [128, 128, 3] \n", + " 4 -1 2 164608 models.common.Bottleneck [128, 128] \n", " 5 -1 1 295424 models.common.Conv [128, 256, 3, 2] \n", - " 6 -1 1 625152 models.common.C3 [256, 256, 3] \n", + " 6 -1 8 2627584 models.common.Bottleneck [256, 256] \n", " 7 -1 1 1180672 models.common.Conv [256, 512, 3, 2] \n", - " 8 -1 1 656896 models.common.SPP [512, 512, [5, 9, 13]] \n", - " 9 -1 1 1182720 models.common.C3 [512, 512, 1, False] \n", - " 10 -1 1 131584 models.common.Conv [512, 256, 1, 1] \n", - " 11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", - " 12 [-1, 6] 1 0 models.common.Concat [1] \n", - " 13 -1 1 361984 models.common.C3 [512, 256, 1, False] \n", - " 14 -1 1 33024 models.common.Conv [256, 128, 1, 1] \n", - " 15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", - " 16 [-1, 4] 1 0 models.common.Concat [1] \n", - " 17 -1 1 90880 models.common.C3 [256, 128, 1, False] \n", - " 18 -1 1 147712 models.common.Conv [128, 128, 3, 2] \n", - " 19 [-1, 14] 1 0 models.common.Concat [1] \n", - " 20 -1 1 296448 models.common.C3 [256, 256, 1, False] \n", - " 21 -1 1 590336 models.common.Conv [256, 256, 3, 2] \n", - " 22 [-1, 10] 1 0 models.common.Concat [1] \n", - " 23 -1 1 1182720 models.common.C3 [512, 512, 1, False] \n", - " 24 [17, 20, 23] 1 229245 models.yolo.Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [128, 256, 512]]\n", - "Model Summary: 283 layers, 7276605 parameters, 7276605 gradients, 17.1 GFLOPS\n", + " 8 -1 8 10498048 models.common.Bottleneck [512, 512] \n", + " 9 -1 1 4720640 models.common.Conv [512, 1024, 3, 2] \n", + " 10 -1 4 20983808 models.common.Bottleneck [1024, 1024] \n", + " 11 -1 1 5245952 models.common.Bottleneck [1024, 1024, False] \n", + " 12 -1 1 525312 models.common.Conv [1024, 512, [1, 1]] \n", + " 13 -1 1 4720640 models.common.Conv [512, 1024, 3, 1] \n", + " 14 -1 1 525312 models.common.Conv [1024, 512, 1, 1] \n", + " 15 -1 1 4720640 models.common.Conv [512, 1024, 3, 1] \n", + " 16 -2 1 131584 models.common.Conv [512, 256, 1, 1] \n", + " 17 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 18 [-1, 8] 1 0 models.common.Concat [1] \n", + " 19 -1 1 1377792 models.common.Bottleneck [768, 512, False] \n", + " 20 -1 1 1312256 models.common.Bottleneck [512, 512, False] \n", + " 21 -1 1 131584 models.common.Conv [512, 256, 1, 1] \n", + " 22 -1 1 1180672 models.common.Conv [256, 512, 3, 1] \n", + " 23 -2 1 33024 models.common.Conv [256, 128, 1, 1] \n", + " 24 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 25 [-1, 6] 1 0 models.common.Concat [1] \n", + " 26 -1 1 344832 models.common.Bottleneck [384, 256, False] \n", + " 27 -1 2 656896 models.common.Bottleneck [256, 256, False] \n", + " 28 [27, 22, 15] 1 457725 models.yolo.Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [256, 512, 1024]]\n", + "Model Summary: 333 layers, 61949149 parameters, 61949149 gradients, 156.4 GFLOPS\n", + "\n", + "Transferred 440/440 items from yolov3.pt\n", + "\n", + "WARNING: Dataset not found, nonexistent paths: ['/content/coco128/images/train2017']\n", + "Downloading https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip ...\n", + "100% 21.1M/21.1M [00:01<00:00, 13.6MB/s]\n", + "Dataset autodownload success\n", "\n", - "Transferred 362/362 items from yolov3.pt\n", "Scaled weight_decay = 0.0005\n", - "Optimizer groups: 62 .bias, 62 conv.weight, 59 other\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mScanning '../coco128/labels/train2017.cache' images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 796544.38it/s]\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mCaching images (0.1GB): 100% 128/128 [00:00<00:00, 176.73it/s]\n", - "\u001b[34m\u001b[1mval: \u001b[0mScanning '../coco128/labels/train2017.cache' images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 500812.42it/s]\n", - "\u001b[34m\u001b[1mval: \u001b[0mCaching images (0.1GB): 100% 128/128 [00:00<00:00, 134.10it/s]\n", + "Optimizer groups: 75 .bias, 75 conv.weight, 72 other\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mScanning '../coco128/labels/train2017' images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 3076.66it/s]\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mNew cache created: ../coco128/labels/train2017.cache\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mCaching images (0.1GB): 100% 128/128 [00:00<00:00, 217.17it/s]\n", + "\u001b[34m\u001b[1mval: \u001b[0mScanning '../coco128/labels/train2017.cache' images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 797727.95it/s]\n", + "\u001b[34m\u001b[1mval: \u001b[0mCaching images (0.1GB): 100% 128/128 [00:00<00:00, 149.28it/s]\n", "Plotting labels... \n", "\n", "\u001b[34m\u001b[1mautoanchor: \u001b[0mAnalyzing anchors... anchors/target = 4.26, Best Possible Recall (BPR) = 0.9946\n", @@ -980,23 +988,22 @@ "Starting training for 3 epochs...\n", "\n", " Epoch gpu_mem box obj cls total labels img_size\n", - " 0/2 3.29G 0.04368 0.065 0.02127 0.1299 183 640: 100% 8/8 [00:03<00:00, 2.21it/s]\n", - " Class Images Labels P R mAP@.5 mAP@.5:.95: 100% 4/4 [00:04<00:00, 1.09s/it]\n", - " all 128 929 0.605 0.657 0.666 0.434\n", + " 0/2 9.3G 0.02899 0.02444 0.007403 0.06083 161 640: 100% 8/8 [00:11<00:00, 1.49s/it]\n", + " Class Images Labels P R mAP@.5 mAP@.5:.95: 100% 4/4 [00:12<00:00, 3.18s/it]\n", + " all 128 929 0.738 0.738 0.79 0.559\n", "\n", " Epoch gpu_mem box obj cls total labels img_size\n", - " 1/2 6.65G 0.04556 0.0651 0.01987 0.1305 166 640: 100% 8/8 [00:01<00:00, 5.18it/s]\n", - " Class Images Labels P R mAP@.5 mAP@.5:.95: 100% 4/4 [00:01<00:00, 2.72it/s]\n", - " all 128 929 0.61 0.66 0.669 0.438\n", + " 1/2 9.08G 0.02946 0.02422 0.007518 0.0612 182 640: 100% 8/8 [00:06<00:00, 1.23it/s]\n", + " Class Images Labels P R mAP@.5 mAP@.5:.95: 100% 4/4 [00:02<00:00, 1.92it/s]\n", + " all 128 929 0.748 0.723 0.792 0.56\n", "\n", " Epoch gpu_mem box obj cls total labels img_size\n", - " 2/2 6.65G 0.04624 0.06923 0.0196 0.1351 182 640: 100% 8/8 [00:01<00:00, 5.19it/s]\n", - " Class Images Labels P R mAP@.5 mAP@.5:.95: 100% 4/4 [00:03<00:00, 1.27it/s]\n", - " all 128 929 0.618 0.659 0.671 0.438\n", - "3 epochs completed in 0.007 hours.\n", + " 2/2 12.2G 0.02798 0.02146 0.007992 0.05744 188 640: 100% 8/8 [00:06<00:00, 1.21it/s]\n", + " Class Images Labels P R mAP@.5 mAP@.5:.95: 100% 4/4 [00:02<00:00, 1.36it/s]\n", + " all 128 929 0.76 0.716 0.79 0.558\n", + "3 epochs completed in 0.014 hours.\n", "\n", - "Optimizer stripped from runs/train/exp/weights/last.pt, 14.8MB\n", - "Optimizer stripped from runs/train/exp/weights/best.pt, 14.8MB\n" + "Optimizer stripped from runs/train/exp/weights/last.pt, 124.3MB\n" ], "name": "stdout" } From 331df67aacd9ed3177430a75e5208c8d896d0938 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 19 Apr 2021 12:37:10 +0200 Subject: [PATCH 0883/1185] Create FUNDING.yaml (#1743) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should set up a "Sponsor" button on the repository to allow users and organizations to help with the development of YOLOv5 with financial contributions! I feel like 10 sponsors could really help fund Ultralytics' caffeine ☕ addiction and get YOLOv5 🚀 developed and deployed faster than ever! 😃 --- .github/FUNDING.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..3da386f7e7 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,5 @@ +# These are supported funding model platforms + +github: glenn-jocher +patreon: ultralytics +open_collective: ultralytics From af7b923bfa45a1594738d3b69a69ea736d05713d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 12 May 2021 14:28:11 +0200 Subject: [PATCH 0884/1185] Created using Colaboratory --- tutorial.ipynb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tutorial.ipynb b/tutorial.ipynb index 7f58e734ee..0a36ec0682 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -563,7 +563,7 @@ "clear_output()\n", "print(f\"Setup complete. Using torch {torch.__version__} ({torch.cuda.get_device_properties(0).name if torch.cuda.is_available() else 'CPU'})\")" ], - "execution_count": 1, + "execution_count": null, "outputs": [ { "output_type": "stream", @@ -601,7 +601,7 @@ "!python detect.py --weights yolov3.pt --img 640 --conf 0.25 --source data/images/\n", "Image(filename='runs/detect/exp/zidane.jpg', width=600)" ], - "execution_count": 5, + "execution_count": null, "outputs": [ { "output_type": "stream", @@ -681,7 +681,7 @@ "torch.hub.download_url_to_file('https://github.com/ultralytics/yolov5/releases/download/v1.0/coco2017val.zip', 'tmp.zip')\n", "!unzip -q tmp.zip -d ../ && rm tmp.zip" ], - "execution_count": 3, + "execution_count": null, "outputs": [ { "output_type": "display_data", @@ -721,7 +721,7 @@ "# Run YOLOv3 on COCO val2017\n", "!python test.py --weights yolov3.pt --data coco.yaml --img 640 --iou 0.65" ], - "execution_count": 4, + "execution_count": null, "outputs": [ { "output_type": "stream", @@ -899,9 +899,10 @@ "id": "2fLAV42oNb7M" }, "source": [ - "# Weights & Biases (optional)\n", - "%pip install -q wandb \n", - "!wandb login # use 'wandb disabled' or 'wandb enabled' to disable or enable" + "# Weights & Biases (optional)\n", + "%pip install -q wandb\n", + "import wandb\n", + "wandb.login()" ], "execution_count": null, "outputs": [] @@ -919,7 +920,7 @@ "# Train YOLOv3 on COCO128 for 3 epochs\n", "!python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov3.pt --nosave --cache" ], - "execution_count": 6, + "execution_count": null, "outputs": [ { "output_type": "stream", From 11c554c31e7c8ad48049fc746110626a97967325 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 12 May 2021 18:38:37 +0200 Subject: [PATCH 0885/1185] Creado con Colaboratory --- tutorial.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorial.ipynb b/tutorial.ipynb index 0a36ec0682..b17aa25c6a 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -1186,7 +1186,7 @@ "model = torch.hub.load('ultralytics/yolov3', 'yolov3') # or 'yolov3_spp', 'yolov3_tiny'\n", "\n", "# Images\n", - "dir = 'https://github.com/ultralytics/yolov3/raw/master/data/images/'\n", + "dir = 'https://ultralytics.com/images/'\n", "imgs = [dir + f for f in ('zidane.jpg', 'bus.jpg')] # batch of images\n", "\n", "# Inference\n", From 69eecec7beed4285bef15fbf0893732f8a4d138d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 12 May 2021 18:40:32 +0200 Subject: [PATCH 0886/1185] Update https://ultralytics.com/images/zidane.jpg (#1759) --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7a3c0e87b2..3f195830c7 100755 --- a/README.md +++ b/README.md @@ -120,12 +120,11 @@ import torch # Model model = torch.hub.load('ultralytics/yolov3', 'yolov3') # or 'yolov3_spp', 'yolov3_tiny' -# Images -dir = 'https://github.com/ultralytics/yolov3/raw/master/data/images/' -imgs = [dir + f for f in ('zidane.jpg', 'bus.jpg')] # batch of images +# Image +img = 'https://ultralytics.com/images/zidane.jpg' # Inference -results = model(imgs) +results = model(img) results.print() # or .show(), .save() ``` From 26cb451811b7aca5ddd069d03167c1db9b711a6b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 12 May 2021 19:50:15 +0200 Subject: [PATCH 0887/1185] Update README.md (#1760) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3f195830c7..faf5d29959 100755 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ $ pip install -r requirements.txt * [Supervisely Ecosystem](https://github.com/ultralytics/yolov5/issues/2518)  🌟 NEW * [Multi-GPU Training](https://github.com/ultralytics/yolov5/issues/475) * [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36)  ⭐ NEW -* [ONNX and TorchScript Export](https://github.com/ultralytics/yolov5/issues/251) +* [TorchScript, ONNX, CoreML Export](https://github.com/ultralytics/yolov5/issues/251) 🚀 * [Test-Time Augmentation (TTA)](https://github.com/ultralytics/yolov5/issues/303) * [Model Ensembling](https://github.com/ultralytics/yolov5/issues/318) * [Model Pruning/Sparsity](https://github.com/ultralytics/yolov5/issues/304) From 47ac6833cac21d1274f94907a010cff90fe2b064 Mon Sep 17 00:00:00 2001 From: Peretz Cohen Date: Thu, 27 May 2021 07:50:12 -0700 Subject: [PATCH 0888/1185] Add Open in Kaggle badge (#1773) * Update tutorial.ipynb add Open in Kaggle badge * Update tutorial.ipynb Open badge in same window * add space between badges * add space 2 * remove align left Co-authored-by: Glenn Jocher --- tutorial.ipynb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tutorial.ipynb b/tutorial.ipynb index b17aa25c6a..617c5c5238 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -517,7 +517,8 @@ "colab_type": "text" }, "source": [ - "\"Open" + "\"Open", + "\"Kaggle\"" ] }, { @@ -1267,4 +1268,4 @@ "outputs": [] } ] -} \ No newline at end of file +} From 4d0c2e6eee14db122f2e0814de284b2dce1306b8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 30 May 2021 18:55:56 +0200 Subject: [PATCH 0889/1185] YOLOv5 v5.0 release compatibility update for YOLOv3 --- README.md | 2 +- data/GlobalWheat2020.yaml | 55 +++++++++ data/SKU-110K.yaml | 52 +++++++++ data/VisDrone.yaml | 61 ++++++++++ data/argoverse_hd.yaml | 4 +- data/coco.yaml | 4 +- data/coco128.yaml | 2 +- data/hyp.finetune_objects365.yaml | 28 +++++ data/objects365.yaml | 102 ++++++++++++++++ data/scripts/get_argoverse_hd.sh | 11 +- data/scripts/get_coco.sh | 2 +- data/scripts/get_coco128.sh | 17 +++ data/scripts/get_voc.sh | 115 ++++++++---------- data/voc.yaml | 2 +- detect.py | 54 +++++---- hubconf.py | 117 ++++++++----------- models/common.py | 51 ++++---- models/experimental.py | 16 +-- models/export.py | 149 +++++++++++++++--------- models/yolo.py | 113 +++++++++++------- requirements.txt | 5 +- test.py | 48 ++++---- train.py | 92 +++++++-------- utils/activations.py | 60 +++++++--- utils/autoanchor.py | 5 +- utils/aws/resume.py | 2 +- utils/aws/userdata.sh | 2 +- utils/datasets.py | 83 +++++++------ utils/flask_rest_api/README.md | 68 +++++++++++ utils/flask_rest_api/example_request.py | 13 +++ utils/flask_rest_api/restapi.py | 37 ++++++ utils/general.py | 147 ++++++++++++++++++----- utils/google_utils.py | 61 ++++++---- utils/metrics.py | 2 +- utils/plots.py | 67 ++++++----- utils/torch_utils.py | 13 ++- utils/wandb_logging/log_dataset.py | 4 +- utils/wandb_logging/wandb_utils.py | 72 +++++++----- 38 files changed, 1201 insertions(+), 537 deletions(-) create mode 100644 data/GlobalWheat2020.yaml create mode 100644 data/SKU-110K.yaml create mode 100644 data/VisDrone.yaml create mode 100644 data/hyp.finetune_objects365.yaml create mode 100644 data/objects365.yaml create mode 100644 data/scripts/get_coco128.sh create mode 100644 utils/flask_rest_api/README.md create mode 100644 utils/flask_rest_api/example_request.py create mode 100644 utils/flask_rest_api/restapi.py diff --git a/README.md b/README.md index faf5d29959..257d0f6462 100755 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ $ python detect.py --source data/images --weights yolov3.pt --conf 0.25 ### PyTorch Hub -To run **batched inference** with YOLOv5 and [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36): +To run **batched inference** with YOLOv3 and [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36): ```python import torch diff --git a/data/GlobalWheat2020.yaml b/data/GlobalWheat2020.yaml new file mode 100644 index 0000000000..ca2a49e2c9 --- /dev/null +++ b/data/GlobalWheat2020.yaml @@ -0,0 +1,55 @@ +# Global Wheat 2020 dataset http://www.global-wheat.com/ +# Train command: python train.py --data GlobalWheat2020.yaml +# Default dataset location is next to YOLOv3: +# /parent_folder +# /datasets/GlobalWheat2020 +# /yolov3 + + +# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] +train: # 3422 images + - ../datasets/GlobalWheat2020/images/arvalis_1 + - ../datasets/GlobalWheat2020/images/arvalis_2 + - ../datasets/GlobalWheat2020/images/arvalis_3 + - ../datasets/GlobalWheat2020/images/ethz_1 + - ../datasets/GlobalWheat2020/images/rres_1 + - ../datasets/GlobalWheat2020/images/inrae_1 + - ../datasets/GlobalWheat2020/images/usask_1 + +val: # 748 images (WARNING: train set contains ethz_1) + - ../datasets/GlobalWheat2020/images/ethz_1 + +test: # 1276 images + - ../datasets/GlobalWheat2020/images/utokyo_1 + - ../datasets/GlobalWheat2020/images/utokyo_2 + - ../datasets/GlobalWheat2020/images/nau_1 + - ../datasets/GlobalWheat2020/images/uq_1 + +# number of classes +nc: 1 + +# class names +names: [ 'wheat_head' ] + + +# download command/URL (optional) -------------------------------------------------------------------------------------- +download: | + from utils.general import download, Path + + # Download + dir = Path('../datasets/GlobalWheat2020') # dataset directory + urls = ['https://zenodo.org/record/4298502/files/global-wheat-codalab-official.zip', + 'https://github.com/ultralytics/yolov5/releases/download/v1.0/GlobalWheat2020_labels.zip'] + download(urls, dir=dir) + + # Make Directories + for p in 'annotations', 'images', 'labels': + (dir / p).mkdir(parents=True, exist_ok=True) + + # Move + for p in 'arvalis_1', 'arvalis_2', 'arvalis_3', 'ethz_1', 'rres_1', 'inrae_1', 'usask_1', \ + 'utokyo_1', 'utokyo_2', 'nau_1', 'uq_1': + (dir / p).rename(dir / 'images' / p) # move to /images + f = (dir / p).with_suffix('.json') # json file + if f.exists(): + f.rename((dir / 'annotations' / p).with_suffix('.json')) # move to /annotations diff --git a/data/SKU-110K.yaml b/data/SKU-110K.yaml new file mode 100644 index 0000000000..f4aea8b55e --- /dev/null +++ b/data/SKU-110K.yaml @@ -0,0 +1,52 @@ +# SKU-110K retail items dataset https://github.com/eg4000/SKU110K_CVPR19 +# Train command: python train.py --data SKU-110K.yaml +# Default dataset location is next to YOLOv3: +# /parent_folder +# /datasets/SKU-110K +# /yolov3 + + +# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] +train: ../datasets/SKU-110K/train.txt # 8219 images +val: ../datasets/SKU-110K/val.txt # 588 images +test: ../datasets/SKU-110K/test.txt # 2936 images + +# number of classes +nc: 1 + +# class names +names: [ 'object' ] + + +# download command/URL (optional) -------------------------------------------------------------------------------------- +download: | + import shutil + from tqdm import tqdm + from utils.general import np, pd, Path, download, xyxy2xywh + + # Download + datasets = Path('../datasets') # download directory + urls = ['http://trax-geometry.s3.amazonaws.com/cvpr_challenge/SKU110K_fixed.tar.gz'] + download(urls, dir=datasets, delete=False) + + # Rename directories + dir = (datasets / 'SKU-110K') + if dir.exists(): + shutil.rmtree(dir) + (datasets / 'SKU110K_fixed').rename(dir) # rename dir + (dir / 'labels').mkdir(parents=True, exist_ok=True) # create labels dir + + # Convert labels + names = 'image', 'x1', 'y1', 'x2', 'y2', 'class', 'image_width', 'image_height' # column names + for d in 'annotations_train.csv', 'annotations_val.csv', 'annotations_test.csv': + x = pd.read_csv(dir / 'annotations' / d, names=names).values # annotations + images, unique_images = x[:, 0], np.unique(x[:, 0]) + with open((dir / d).with_suffix('.txt').__str__().replace('annotations_', ''), 'w') as f: + f.writelines(f'./images/{s}\n' for s in unique_images) + for im in tqdm(unique_images, desc=f'Converting {dir / d}'): + cls = 0 # single-class dataset + with open((dir / 'labels' / im).with_suffix('.txt'), 'a') as f: + for r in x[images == im]: + w, h = r[6], r[7] # image width, height + xywh = xyxy2xywh(np.array([[r[1] / w, r[2] / h, r[3] / w, r[4] / h]]))[0] # instance + f.write(f"{cls} {xywh[0]:.5f} {xywh[1]:.5f} {xywh[2]:.5f} {xywh[3]:.5f}\n") # write label diff --git a/data/VisDrone.yaml b/data/VisDrone.yaml new file mode 100644 index 0000000000..59f1cd5105 --- /dev/null +++ b/data/VisDrone.yaml @@ -0,0 +1,61 @@ +# VisDrone2019-DET dataset https://github.com/VisDrone/VisDrone-Dataset +# Train command: python train.py --data VisDrone.yaml +# Default dataset location is next to YOLOv3: +# /parent_folder +# /VisDrone +# /yolov3 + + +# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] +train: ../VisDrone/VisDrone2019-DET-train/images # 6471 images +val: ../VisDrone/VisDrone2019-DET-val/images # 548 images +test: ../VisDrone/VisDrone2019-DET-test-dev/images # 1610 images + +# number of classes +nc: 10 + +# class names +names: [ 'pedestrian', 'people', 'bicycle', 'car', 'van', 'truck', 'tricycle', 'awning-tricycle', 'bus', 'motor' ] + + +# download command/URL (optional) -------------------------------------------------------------------------------------- +download: | + from utils.general import download, os, Path + + def visdrone2yolo(dir): + from PIL import Image + from tqdm import tqdm + + def convert_box(size, box): + # Convert VisDrone box to YOLO xywh box + dw = 1. / size[0] + dh = 1. / size[1] + return (box[0] + box[2] / 2) * dw, (box[1] + box[3] / 2) * dh, box[2] * dw, box[3] * dh + + (dir / 'labels').mkdir(parents=True, exist_ok=True) # make labels directory + pbar = tqdm((dir / 'annotations').glob('*.txt'), desc=f'Converting {dir}') + for f in pbar: + img_size = Image.open((dir / 'images' / f.name).with_suffix('.jpg')).size + lines = [] + with open(f, 'r') as file: # read annotation.txt + for row in [x.split(',') for x in file.read().strip().splitlines()]: + if row[4] == '0': # VisDrone 'ignored regions' class 0 + continue + cls = int(row[5]) - 1 + box = convert_box(img_size, tuple(map(int, row[:4]))) + lines.append(f"{cls} {' '.join(f'{x:.6f}' for x in box)}\n") + with open(str(f).replace(os.sep + 'annotations' + os.sep, os.sep + 'labels' + os.sep), 'w') as fl: + fl.writelines(lines) # write label.txt + + + # Download + dir = Path('../VisDrone') # dataset directory + urls = ['https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-train.zip', + 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-val.zip', + 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-test-dev.zip', + 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-test-challenge.zip'] + download(urls, dir=dir) + + # Convert + for d in 'VisDrone2019-DET-train', 'VisDrone2019-DET-val', 'VisDrone2019-DET-test-dev': + visdrone2yolo(dir / d) # convert VisDrone annotations to YOLO labels diff --git a/data/argoverse_hd.yaml b/data/argoverse_hd.yaml index df7a9361e7..29d49b8807 100644 --- a/data/argoverse_hd.yaml +++ b/data/argoverse_hd.yaml @@ -1,9 +1,9 @@ # Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/ # Train command: python train.py --data argoverse_hd.yaml -# Default dataset location is next to /yolov5: +# Default dataset location is next to YOLOv3: # /parent_folder # /argoverse -# /yolov5 +# /yolov3 # download command/URL (optional) diff --git a/data/coco.yaml b/data/coco.yaml index 1bc888e619..8714e6a33f 100644 --- a/data/coco.yaml +++ b/data/coco.yaml @@ -1,6 +1,6 @@ # COCO 2017 dataset http://cocodataset.org # Train command: python train.py --data coco.yaml -# Default dataset location is next to /yolov3: +# Default dataset location is next to YOLOv3: # /parent_folder # /coco # /yolov3 @@ -30,6 +30,6 @@ names: [ 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', ' # Print classes # with open('data/coco.yaml') as f: -# d = yaml.load(f, Loader=yaml.FullLoader) # dict +# d = yaml.safe_load(f) # dict # for i, x in enumerate(d['names']): # print(i, x) diff --git a/data/coco128.yaml b/data/coco128.yaml index f9d4c96053..ef1f6c62fb 100644 --- a/data/coco128.yaml +++ b/data/coco128.yaml @@ -1,6 +1,6 @@ # COCO 2017 dataset http://cocodataset.org - first 128 training images # Train command: python train.py --data coco128.yaml -# Default dataset location is next to /yolov3: +# Default dataset location is next to YOLOv3: # /parent_folder # /coco128 # /yolov3 diff --git a/data/hyp.finetune_objects365.yaml b/data/hyp.finetune_objects365.yaml new file mode 100644 index 0000000000..2b104ef2d9 --- /dev/null +++ b/data/hyp.finetune_objects365.yaml @@ -0,0 +1,28 @@ +lr0: 0.00258 +lrf: 0.17 +momentum: 0.779 +weight_decay: 0.00058 +warmup_epochs: 1.33 +warmup_momentum: 0.86 +warmup_bias_lr: 0.0711 +box: 0.0539 +cls: 0.299 +cls_pw: 0.825 +obj: 0.632 +obj_pw: 1.0 +iou_t: 0.2 +anchor_t: 3.44 +anchors: 3.2 +fl_gamma: 0.0 +hsv_h: 0.0188 +hsv_s: 0.704 +hsv_v: 0.36 +degrees: 0.0 +translate: 0.0902 +scale: 0.491 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +mosaic: 1.0 +mixup: 0.0 diff --git a/data/objects365.yaml b/data/objects365.yaml new file mode 100644 index 0000000000..1cac32f4e2 --- /dev/null +++ b/data/objects365.yaml @@ -0,0 +1,102 @@ +# Objects365 dataset https://www.objects365.org/ +# Train command: python train.py --data objects365.yaml +# Default dataset location is next to YOLOv3: +# /parent_folder +# /datasets/objects365 +# /yolov3 + +# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] +train: ../datasets/objects365/images/train # 1742289 images +val: ../datasets/objects365/images/val # 5570 images + +# number of classes +nc: 365 + +# class names +names: [ 'Person', 'Sneakers', 'Chair', 'Other Shoes', 'Hat', 'Car', 'Lamp', 'Glasses', 'Bottle', 'Desk', 'Cup', + 'Street Lights', 'Cabinet/shelf', 'Handbag/Satchel', 'Bracelet', 'Plate', 'Picture/Frame', 'Helmet', 'Book', + 'Gloves', 'Storage box', 'Boat', 'Leather Shoes', 'Flower', 'Bench', 'Potted Plant', 'Bowl/Basin', 'Flag', + 'Pillow', 'Boots', 'Vase', 'Microphone', 'Necklace', 'Ring', 'SUV', 'Wine Glass', 'Belt', 'Monitor/TV', + 'Backpack', 'Umbrella', 'Traffic Light', 'Speaker', 'Watch', 'Tie', 'Trash bin Can', 'Slippers', 'Bicycle', + 'Stool', 'Barrel/bucket', 'Van', 'Couch', 'Sandals', 'Basket', 'Drum', 'Pen/Pencil', 'Bus', 'Wild Bird', + 'High Heels', 'Motorcycle', 'Guitar', 'Carpet', 'Cell Phone', 'Bread', 'Camera', 'Canned', 'Truck', + 'Traffic cone', 'Cymbal', 'Lifesaver', 'Towel', 'Stuffed Toy', 'Candle', 'Sailboat', 'Laptop', 'Awning', + 'Bed', 'Faucet', 'Tent', 'Horse', 'Mirror', 'Power outlet', 'Sink', 'Apple', 'Air Conditioner', 'Knife', + 'Hockey Stick', 'Paddle', 'Pickup Truck', 'Fork', 'Traffic Sign', 'Balloon', 'Tripod', 'Dog', 'Spoon', 'Clock', + 'Pot', 'Cow', 'Cake', 'Dinning Table', 'Sheep', 'Hanger', 'Blackboard/Whiteboard', 'Napkin', 'Other Fish', + 'Orange/Tangerine', 'Toiletry', 'Keyboard', 'Tomato', 'Lantern', 'Machinery Vehicle', 'Fan', + 'Green Vegetables', 'Banana', 'Baseball Glove', 'Airplane', 'Mouse', 'Train', 'Pumpkin', 'Soccer', 'Skiboard', + 'Luggage', 'Nightstand', 'Tea pot', 'Telephone', 'Trolley', 'Head Phone', 'Sports Car', 'Stop Sign', + 'Dessert', 'Scooter', 'Stroller', 'Crane', 'Remote', 'Refrigerator', 'Oven', 'Lemon', 'Duck', 'Baseball Bat', + 'Surveillance Camera', 'Cat', 'Jug', 'Broccoli', 'Piano', 'Pizza', 'Elephant', 'Skateboard', 'Surfboard', + 'Gun', 'Skating and Skiing shoes', 'Gas stove', 'Donut', 'Bow Tie', 'Carrot', 'Toilet', 'Kite', 'Strawberry', + 'Other Balls', 'Shovel', 'Pepper', 'Computer Box', 'Toilet Paper', 'Cleaning Products', 'Chopsticks', + 'Microwave', 'Pigeon', 'Baseball', 'Cutting/chopping Board', 'Coffee Table', 'Side Table', 'Scissors', + 'Marker', 'Pie', 'Ladder', 'Snowboard', 'Cookies', 'Radiator', 'Fire Hydrant', 'Basketball', 'Zebra', 'Grape', + 'Giraffe', 'Potato', 'Sausage', 'Tricycle', 'Violin', 'Egg', 'Fire Extinguisher', 'Candy', 'Fire Truck', + 'Billiards', 'Converter', 'Bathtub', 'Wheelchair', 'Golf Club', 'Briefcase', 'Cucumber', 'Cigar/Cigarette', + 'Paint Brush', 'Pear', 'Heavy Truck', 'Hamburger', 'Extractor', 'Extension Cord', 'Tong', 'Tennis Racket', + 'Folder', 'American Football', 'earphone', 'Mask', 'Kettle', 'Tennis', 'Ship', 'Swing', 'Coffee Machine', + 'Slide', 'Carriage', 'Onion', 'Green beans', 'Projector', 'Frisbee', 'Washing Machine/Drying Machine', + 'Chicken', 'Printer', 'Watermelon', 'Saxophone', 'Tissue', 'Toothbrush', 'Ice cream', 'Hot-air balloon', + 'Cello', 'French Fries', 'Scale', 'Trophy', 'Cabbage', 'Hot dog', 'Blender', 'Peach', 'Rice', 'Wallet/Purse', + 'Volleyball', 'Deer', 'Goose', 'Tape', 'Tablet', 'Cosmetics', 'Trumpet', 'Pineapple', 'Golf Ball', + 'Ambulance', 'Parking meter', 'Mango', 'Key', 'Hurdle', 'Fishing Rod', 'Medal', 'Flute', 'Brush', 'Penguin', + 'Megaphone', 'Corn', 'Lettuce', 'Garlic', 'Swan', 'Helicopter', 'Green Onion', 'Sandwich', 'Nuts', + 'Speed Limit Sign', 'Induction Cooker', 'Broom', 'Trombone', 'Plum', 'Rickshaw', 'Goldfish', 'Kiwi fruit', + 'Router/modem', 'Poker Card', 'Toaster', 'Shrimp', 'Sushi', 'Cheese', 'Notepaper', 'Cherry', 'Pliers', 'CD', + 'Pasta', 'Hammer', 'Cue', 'Avocado', 'Hamimelon', 'Flask', 'Mushroom', 'Screwdriver', 'Soap', 'Recorder', + 'Bear', 'Eggplant', 'Board Eraser', 'Coconut', 'Tape Measure/Ruler', 'Pig', 'Showerhead', 'Globe', 'Chips', + 'Steak', 'Crosswalk Sign', 'Stapler', 'Camel', 'Formula 1', 'Pomegranate', 'Dishwasher', 'Crab', + 'Hoverboard', 'Meat ball', 'Rice Cooker', 'Tuba', 'Calculator', 'Papaya', 'Antelope', 'Parrot', 'Seal', + 'Butterfly', 'Dumbbell', 'Donkey', 'Lion', 'Urinal', 'Dolphin', 'Electric Drill', 'Hair Dryer', 'Egg tart', + 'Jellyfish', 'Treadmill', 'Lighter', 'Grapefruit', 'Game board', 'Mop', 'Radish', 'Baozi', 'Target', 'French', + 'Spring Rolls', 'Monkey', 'Rabbit', 'Pencil Case', 'Yak', 'Red Cabbage', 'Binoculars', 'Asparagus', 'Barbell', + 'Scallop', 'Noddles', 'Comb', 'Dumpling', 'Oyster', 'Table Tennis paddle', 'Cosmetics Brush/Eyeliner Pencil', + 'Chainsaw', 'Eraser', 'Lobster', 'Durian', 'Okra', 'Lipstick', 'Cosmetics Mirror', 'Curling', 'Table Tennis' ] + + +# download command/URL (optional) -------------------------------------------------------------------------------------- +download: | + from pycocotools.coco import COCO + from tqdm import tqdm + + from utils.general import download, Path + + # Make Directories + dir = Path('../datasets/objects365') # dataset directory + for p in 'images', 'labels': + (dir / p).mkdir(parents=True, exist_ok=True) + for q in 'train', 'val': + (dir / p / q).mkdir(parents=True, exist_ok=True) + + # Download + url = "https://dorc.ks3-cn-beijing.ksyun.com/data-set/2020Objects365%E6%95%B0%E6%8D%AE%E9%9B%86/train/" + download([url + 'zhiyuan_objv2_train.tar.gz'], dir=dir, delete=False) # annotations json + download([url + f for f in [f'patch{i}.tar.gz' for i in range(51)]], dir=dir / 'images' / 'train', + curl=True, delete=False, threads=8) + + # Move + train = dir / 'images' / 'train' + for f in tqdm(train.rglob('*.jpg'), desc=f'Moving images'): + f.rename(train / f.name) # move to /images/train + + # Labels + coco = COCO(dir / 'zhiyuan_objv2_train.json') + names = [x["name"] for x in coco.loadCats(coco.getCatIds())] + for cid, cat in enumerate(names): + catIds = coco.getCatIds(catNms=[cat]) + imgIds = coco.getImgIds(catIds=catIds) + for im in tqdm(coco.loadImgs(imgIds), desc=f'Class {cid + 1}/{len(names)} {cat}'): + width, height = im["width"], im["height"] + path = Path(im["file_name"]) # image filename + try: + with open(dir / 'labels' / 'train' / path.with_suffix('.txt').name, 'a') as file: + annIds = coco.getAnnIds(imgIds=im["id"], catIds=catIds, iscrowd=None) + for a in coco.loadAnns(annIds): + x, y, w, h = a['bbox'] # bounding box in xywh (xy top-left corner) + x, y = x + w / 2, y + h / 2 # xy to center + file.write(f"{cid} {x / width:.5f} {y / height:.5f} {w / width:.5f} {h / height:.5f}\n") + + except Exception as e: + print(e) diff --git a/data/scripts/get_argoverse_hd.sh b/data/scripts/get_argoverse_hd.sh index caec61efed..ad36976868 100644 --- a/data/scripts/get_argoverse_hd.sh +++ b/data/scripts/get_argoverse_hd.sh @@ -2,10 +2,10 @@ # Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/ # Download command: bash data/scripts/get_argoverse_hd.sh # Train command: python train.py --data argoverse_hd.yaml -# Default dataset location is next to /yolov5: +# Default dataset location is next to YOLOv3: # /parent_folder # /argoverse -# /yolov5 +# /yolov3 # Download/unzip images d='../argoverse/' # unzip directory @@ -25,7 +25,7 @@ import json from pathlib import Path annotation_files = ["train.json", "val.json"] -print("Converting annotations to YOLOv5 format...") +print("Converting annotations to YOLOv3 format...") for val in annotation_files: a = json.load(open(val, "rb")) @@ -36,7 +36,7 @@ for val in annotation_files: img_name = a['images'][img_id]['name'] img_label_name = img_name[:-3] + "txt" - obj_class = annot['category_id'] + cls = annot['category_id'] # instance class id x_center, y_center, width, height = annot['bbox'] x_center = (x_center + width / 2) / 1920. # offset and scale y_center = (y_center + height / 2) / 1200. # offset and scale @@ -46,11 +46,10 @@ for val in annotation_files: img_dir = "./labels/" + a['seq_dirs'][a['images'][annot['image_id']]['sid']] Path(img_dir).mkdir(parents=True, exist_ok=True) - if img_dir + "/" + img_label_name not in label_dict: label_dict[img_dir + "/" + img_label_name] = [] - label_dict[img_dir + "/" + img_label_name].append(f"{obj_class} {x_center} {y_center} {width} {height}\n") + label_dict[img_dir + "/" + img_label_name].append(f"{cls} {x_center} {y_center} {width} {height}\n") for filename in label_dict: with open(filename, "w") as file: diff --git a/data/scripts/get_coco.sh b/data/scripts/get_coco.sh index b39a782127..310f5be579 100755 --- a/data/scripts/get_coco.sh +++ b/data/scripts/get_coco.sh @@ -2,7 +2,7 @@ # COCO 2017 dataset http://cocodataset.org # Download command: bash data/scripts/get_coco.sh # Train command: python train.py --data coco.yaml -# Default dataset location is next to /yolov3: +# Default dataset location is next to YOLOv3: # /parent_folder # /coco # /yolov3 diff --git a/data/scripts/get_coco128.sh b/data/scripts/get_coco128.sh new file mode 100644 index 0000000000..721c15c3df --- /dev/null +++ b/data/scripts/get_coco128.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# COCO128 dataset https://www.kaggle.com/ultralytics/coco128 +# Download command: bash data/scripts/get_coco128.sh +# Train command: python train.py --data coco128.yaml +# Default dataset location is next to YOLOv3: +# /parent_folder +# /coco128 +# /yolov3 + +# Download/unzip images and labels +d='../' # unzip directory +url=https://github.com/ultralytics/yolov5/releases/download/v1.0/ +f='coco128.zip' # or 'coco2017labels-segments.zip', 68 MB +echo 'Downloading' $url$f ' ...' +curl -L $url$f -o $f && unzip -q $f -d $d && rm $f & # download, unzip, remove in background + +wait # finish background tasks diff --git a/data/scripts/get_voc.sh b/data/scripts/get_voc.sh index 13b83c28d7..28cf007e7d 100644 --- a/data/scripts/get_voc.sh +++ b/data/scripts/get_voc.sh @@ -2,10 +2,10 @@ # PASCAL VOC dataset http://host.robots.ox.ac.uk/pascal/VOC/ # Download command: bash data/scripts/get_voc.sh # Train command: python train.py --data voc.yaml -# Default dataset location is next to /yolov5: +# Default dataset location is next to YOLOv3: # /parent_folder # /VOC -# /yolov5 +# /yolov3 start=$(date +%s) mkdir -p ../tmp @@ -29,34 +29,27 @@ echo "Completed in" $runtime "seconds" echo "Splitting dataset..." python3 - "$@" <train.txt cat 2007_train.txt 2007_val.txt 2007_test.txt 2012_train.txt 2012_val.txt >train.all.txt -python3 - "$@" <= 1 - p, s, im0, frame = path[i], '%g: ' % i, im0s[i].copy(), dataset.count + p, s, im0, frame = path[i], f'{i}: ', im0s[i].copy(), dataset.count else: - p, s, im0, frame = path, '', im0s, getattr(dataset, 'frame', 0) + p, s, im0, frame = path, '', im0s.copy(), getattr(dataset, 'frame', 0) p = Path(p) # to Path save_path = str(save_dir / p.name) # img.jpg txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # img.txt s += '%gx%g ' % img.shape[2:] # print string gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh + imc = im0.copy() if opt.save_crop else im0 # for opt.save_crop if len(det): # Rescale boxes from img_size to im0 size det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() @@ -108,9 +107,12 @@ def detect(save_img=False): with open(txt_path + '.txt', 'a') as f: f.write(('%g ' * len(line)).rstrip() % line + '\n') - if save_img or view_img: # Add bbox to image - label = f'{names[int(cls)]} {conf:.2f}' - plot_one_box(xyxy, im0, label=label, color=colors[int(cls)], line_thickness=3) + if save_img or opt.save_crop or view_img: # Add bbox to image + c = int(cls) # integer class + label = None if opt.hide_labels else (names[c] if opt.hide_conf else f'{names[c]} {conf:.2f}') + plot_one_box(xyxy, im0, label=label, color=colors(c, True), line_thickness=opt.line_thickness) + if opt.save_crop: + save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True) # Print time (inference + NMS) print(f'{s}Done. ({t2 - t1:.3f}s)') @@ -153,10 +155,12 @@ def detect(save_img=False): parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold') parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS') + parser.add_argument('--max-det', type=int, default=1000, help='maximum number of detections per image') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--view-img', action='store_true', help='display results') parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes') parser.add_argument('--nosave', action='store_true', help='do not save images/videos') parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3') parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') @@ -165,14 +169,16 @@ def detect(save_img=False): parser.add_argument('--project', default='runs/detect', help='save results to project/name') parser.add_argument('--name', default='exp', help='save results to project/name') parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)') + parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels') + parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences') opt = parser.parse_args() print(opt) - check_requirements(exclude=('pycocotools', 'thop')) - - with torch.no_grad(): - if opt.update: # update all models (to fix SourceChangeWarning) - for opt.weights in ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt']: - detect() - strip_optimizer(opt.weights) - else: - detect() + check_requirements(exclude=('tensorboard', 'pycocotools', 'thop')) + + if opt.update: # update all models (to fix SourceChangeWarning) + for opt.weights in ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt']: + detect(opt=opt) + strip_optimizer(opt.weights) + else: + detect(opt=opt) diff --git a/hubconf.py b/hubconf.py index 7d969b5ad6..683e22f748 100644 --- a/hubconf.py +++ b/hubconf.py @@ -2,24 +2,13 @@ Usage: import torch - model = torch.hub.load('ultralytics/yolov3', 'yolov3tiny') + model = torch.hub.load('ultralytics/yolov3', 'yolov3_tiny') """ -from pathlib import Path - import torch -from models.yolo import Model -from utils.general import check_requirements, set_logging -from utils.google_utils import attempt_download -from utils.torch_utils import select_device - -dependencies = ['torch', 'yaml'] -check_requirements(Path(__file__).parent / 'requirements.txt', exclude=('pycocotools', 'thop')) -set_logging() - -def create(name, pretrained, channels, classes, autoshape): +def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): """Creates a specified YOLOv3 model Arguments: @@ -27,85 +16,81 @@ def create(name, pretrained, channels, classes, autoshape): pretrained (bool): load pretrained weights into the model channels (int): number of input channels classes (int): number of model classes + autoshape (bool): apply YOLOv3 .autoshape() wrapper to model + verbose (bool): print all information to screen + device (str, torch.device, None): device to use for model parameters Returns: - pytorch model + YOLOv3 pytorch model """ + from pathlib import Path + + from models.yolo import Model, attempt_load + from utils.general import check_requirements, set_logging + from utils.google_utils import attempt_download + from utils.torch_utils import select_device + + check_requirements(Path(__file__).parent / 'requirements.txt', exclude=('tensorboard', 'pycocotools', 'thop')) + set_logging(verbose=verbose) + + fname = Path(name).with_suffix('.pt') # checkpoint filename try: - cfg = list((Path(__file__).parent / 'models').rglob(f'{name}.yaml'))[0] # model.yaml path - model = Model(cfg, channels, classes) - if pretrained: - fname = f'{name}.pt' # checkpoint filename - attempt_download(fname) # download if not found locally - ckpt = torch.load(fname, map_location=torch.device('cpu')) # load - msd = model.state_dict() # model state_dict - csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 - csd = {k: v for k, v in csd.items() if msd[k].shape == v.shape} # filter - model.load_state_dict(csd, strict=False) # load - if len(ckpt['model'].names) == classes: - model.names = ckpt['model'].names # set class names attribute - if autoshape: - model = model.autoshape() # for file/URI/PIL/cv2/np inputs and NMS - device = select_device('0' if torch.cuda.is_available() else 'cpu') # default to GPU if available + if pretrained and channels == 3 and classes == 80: + model = attempt_load(fname, map_location=torch.device('cpu')) # download/load FP32 model + else: + cfg = list((Path(__file__).parent / 'models').rglob(f'{name}.yaml'))[0] # model.yaml path + model = Model(cfg, channels, classes) # create model + if pretrained: + ckpt = torch.load(attempt_download(fname), map_location=torch.device('cpu')) # load + msd = model.state_dict() # model state_dict + csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 + csd = {k: v for k, v in csd.items() if msd[k].shape == v.shape} # filter + model.load_state_dict(csd, strict=False) # load + if len(ckpt['model'].names) == classes: + model.names = ckpt['model'].names # set class names attribute + if autoshape: + model = model.autoshape() # for file/URI/PIL/cv2/np inputs and NMS + device = select_device('0' if torch.cuda.is_available() else 'cpu') if device is None else torch.device(device) return model.to(device) except Exception as e: help_url = 'https://github.com/ultralytics/yolov5/issues/36' - s = 'Cache maybe be out of date, try force_reload=True. See %s for help.' % help_url + s = 'Cache may be out of date, try `force_reload=True`. See %s for help.' % help_url raise Exception(s) from e -def custom(path_or_model='path/to/model.pt', autoshape=True): - """YOLOv3-custom model https://github.com/ultralytics/yolov3 +def custom(path='path/to/model.pt', autoshape=True, verbose=True, device=None): + # YOLOv3 custom or local model + return _create(path, autoshape=autoshape, verbose=verbose, device=device) - Arguments (3 options): - path_or_model (str): 'path/to/model.pt' - path_or_model (dict): torch.load('path/to/model.pt') - path_or_model (nn.Module): torch.load('path/to/model.pt')['model'] - Returns: - pytorch model - """ - model = torch.load(path_or_model) if isinstance(path_or_model, str) else path_or_model # load checkpoint - if isinstance(model, dict): - model = model['ema' if model.get('ema') else 'model'] # load model - - hub_model = Model(model.yaml).to(next(model.parameters()).device) # create - hub_model.load_state_dict(model.float().state_dict()) # load state_dict - hub_model.names = model.names # class names - if autoshape: - hub_model = hub_model.autoshape() # for file/URI/PIL/cv2/np inputs and NMS - device = select_device('0' if torch.cuda.is_available() else 'cpu') # default to GPU if available - return hub_model.to(device) - - -def yolov3(pretrained=True, channels=3, classes=80, autoshape=True): +def yolov3(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): # YOLOv3 model https://github.com/ultralytics/yolov3 - return create('yolov3', pretrained, channels, classes, autoshape) - + return _create('yolov3', pretrained, channels, classes, autoshape, verbose, device) -def yolov3_spp(pretrained=True, channels=3, classes=80, autoshape=True): +def yolov3_spp(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): # YOLOv3-SPP model https://github.com/ultralytics/yolov3 - return create('yolov3-spp', pretrained, channels, classes, autoshape) - + return _create('yolov3-spp', pretrained, channels, classes, autoshape, verbose, device) -def yolov3_tiny(pretrained=True, channels=3, classes=80, autoshape=True): +def yolov3_tiny(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): # YOLOv3-tiny model https://github.com/ultralytics/yolov3 - return create('yolov3-tiny', pretrained, channels, classes, autoshape) + return _create('yolov3-tiny', pretrained, channels, classes, autoshape, verbose, device) if __name__ == '__main__': - model = create(name='yolov3', pretrained=True, channels=3, classes=80, autoshape=True) # pretrained example - # model = custom(path_or_model='path/to/model.pt') # custom example + model = _create(name='yolov3', pretrained=True, channels=3, classes=80, autoshape=True, verbose=True) # pretrained + # model = custom(path='path/to/model.pt') # custom # Verify inference + import cv2 import numpy as np from PIL import Image - imgs = [Image.open('data/images/bus.jpg'), # PIL - 'data/images/zidane.jpg', # filename - 'https://github.com/ultralytics/yolov3/raw/master/data/images/bus.jpg', # URI - np.zeros((640, 480, 3))] # numpy + imgs = ['data/images/zidane.jpg', # filename + 'https://github.com/ultralytics/yolov5/releases/download/v1.0/zidane.jpg', # URI + cv2.imread('data/images/bus.jpg')[:, :, ::-1], # OpenCV + Image.open('data/images/bus.jpg'), # PIL + np.zeros((320, 640, 3))] # numpy results = model(imgs) # batched inference results.print() diff --git a/models/common.py b/models/common.py index 9496b1b493..0b4e600459 100644 --- a/models/common.py +++ b/models/common.py @@ -13,8 +13,8 @@ from torch.cuda import amp from utils.datasets import letterbox -from utils.general import non_max_suppression, make_divisible, scale_coords, increment_path, xyxy2xywh -from utils.plots import color_list, plot_one_box +from utils.general import non_max_suppression, make_divisible, scale_coords, increment_path, xyxy2xywh, save_one_box +from utils.plots import colors, plot_one_box from utils.torch_utils import time_synchronized @@ -215,32 +215,34 @@ class NMS(nn.Module): conf = 0.25 # confidence threshold iou = 0.45 # IoU threshold classes = None # (optional list) filter by class + max_det = 1000 # maximum number of detections per image def __init__(self): super(NMS, self).__init__() def forward(self, x): - return non_max_suppression(x[0], conf_thres=self.conf, iou_thres=self.iou, classes=self.classes) + return non_max_suppression(x[0], self.conf, iou_thres=self.iou, classes=self.classes, max_det=self.max_det) -class autoShape(nn.Module): +class AutoShape(nn.Module): # input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS conf = 0.25 # NMS confidence threshold iou = 0.45 # NMS IoU threshold classes = None # (optional list) filter by class + max_det = 1000 # maximum number of detections per image def __init__(self, model): - super(autoShape, self).__init__() + super(AutoShape, self).__init__() self.model = model.eval() def autoshape(self): - print('autoShape already enabled, skipping... ') # model already converted to model.autoshape() + print('AutoShape already enabled, skipping... ') # model already converted to model.autoshape() return self @torch.no_grad() def forward(self, imgs, size=640, augment=False, profile=False): # Inference from various sources. For height=640, width=1280, RGB images example inputs are: - # filename: imgs = 'data/samples/zidane.jpg' + # filename: imgs = 'data/images/zidane.jpg' # URI: = 'https://github.com/ultralytics/yolov5/releases/download/v1.0/zidane.jpg' # OpenCV: = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(640,1280,3) # PIL: = Image.open('image.jpg') # HWC x(640,1280,3) @@ -271,7 +273,7 @@ def forward(self, imgs, size=640, augment=False, profile=False): shape0.append(s) # image shape g = (size / max(s)) # gain shape1.append([y * g for y in s]) - imgs[i] = im # update + imgs[i] = im if im.data.contiguous else np.ascontiguousarray(im) # update shape1 = [make_divisible(x, int(self.stride.max())) for x in np.stack(shape1, 0).max(0)] # inference shape x = [letterbox(im, new_shape=shape1, auto=False)[0] for im in imgs] # pad x = np.stack(x, 0) if n > 1 else x[0][None] # stack @@ -285,7 +287,7 @@ def forward(self, imgs, size=640, augment=False, profile=False): t.append(time_synchronized()) # Post-process - y = non_max_suppression(y, conf_thres=self.conf, iou_thres=self.iou, classes=self.classes) # NMS + y = non_max_suppression(y, self.conf, iou_thres=self.iou, classes=self.classes, max_det=self.max_det) # NMS for i in range(n): scale_coords(shape1, y[i][:, :4], shape0[i]) @@ -311,29 +313,32 @@ def __init__(self, imgs, pred, files, times=None, names=None, shape=None): self.t = tuple((times[i + 1] - times[i]) * 1000 / self.n for i in range(3)) # timestamps (ms) self.s = shape # inference BCHW shape - def display(self, pprint=False, show=False, save=False, render=False, save_dir=''): - colors = color_list() - for i, (img, pred) in enumerate(zip(self.imgs, self.pred)): - str = f'image {i + 1}/{len(self.pred)}: {img.shape[0]}x{img.shape[1]} ' + def display(self, pprint=False, show=False, save=False, crop=False, render=False, save_dir=Path('')): + for i, (im, pred) in enumerate(zip(self.imgs, self.pred)): + str = f'image {i + 1}/{len(self.pred)}: {im.shape[0]}x{im.shape[1]} ' if pred is not None: for c in pred[:, -1].unique(): n = (pred[:, -1] == c).sum() # detections per class str += f"{n} {self.names[int(c)]}{'s' * (n > 1)}, " # add to string - if show or save or render: + if show or save or render or crop: for *box, conf, cls in pred: # xyxy, confidence, class label = f'{self.names[int(cls)]} {conf:.2f}' - plot_one_box(box, img, label=label, color=colors[int(cls) % 10]) - img = Image.fromarray(img.astype(np.uint8)) if isinstance(img, np.ndarray) else img # from np + if crop: + save_one_box(box, im, file=save_dir / 'crops' / self.names[int(cls)] / self.files[i]) + else: # all others + plot_one_box(box, im, label=label, color=colors(cls)) + + im = Image.fromarray(im.astype(np.uint8)) if isinstance(im, np.ndarray) else im # from np if pprint: print(str.rstrip(', ')) if show: - img.show(self.files[i]) # show + im.show(self.files[i]) # show if save: f = self.files[i] - img.save(Path(save_dir) / f) # save + im.save(save_dir / f) # save print(f"{'Saved' * (i == 0)} {f}", end=',' if i < self.n - 1 else f' to {save_dir}\n') if render: - self.imgs[i] = np.asarray(img) + self.imgs[i] = np.asarray(im) def print(self): self.display(pprint=True) # print results @@ -343,10 +348,14 @@ def show(self): self.display(show=True) # show results def save(self, save_dir='runs/hub/exp'): - save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/hub/exp') # increment save_dir - Path(save_dir).mkdir(parents=True, exist_ok=True) + save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/hub/exp', mkdir=True) # increment save_dir self.display(save=True, save_dir=save_dir) # save results + def crop(self, save_dir='runs/hub/exp'): + save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/hub/exp', mkdir=True) # increment save_dir + self.display(crop=True, save_dir=save_dir) # crop results + print(f'Saved results to {save_dir}\n') + def render(self): self.display(render=True) # render results return self.imgs diff --git a/models/experimental.py b/models/experimental.py index 622791540c..867c8db5cd 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -110,25 +110,27 @@ def forward(self, x, augment=False): return y, None # inference, train output -def attempt_load(weights, map_location=None): +def attempt_load(weights, map_location=None, inplace=True): + from models.yolo import Detect, Model + # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a model = Ensemble() for w in weights if isinstance(weights, list) else [weights]: - attempt_download(w) - ckpt = torch.load(w, map_location=map_location) # load + ckpt = torch.load(attempt_download(w), map_location=map_location) # load model.append(ckpt['ema' if ckpt.get('ema') else 'model'].float().fuse().eval()) # FP32 model # Compatibility updates for m in model.modules(): - if type(m) in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU]: - m.inplace = True # pytorch 1.7.0 compatibility + if type(m) in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Model]: + m.inplace = inplace # pytorch 1.7.0 compatibility elif type(m) is Conv: m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility if len(model) == 1: return model[-1] # return model else: - print('Ensemble created with %s\n' % weights) - for k in ['names', 'stride']: + print(f'Ensemble created with {weights}\n') + for k in ['names']: setattr(model, k, getattr(model[-1], k)) + model.stride = model[torch.argmax(torch.tensor([m.stride.max() for m in model])).int()].stride # max stride return model # return ensemble diff --git a/models/export.py b/models/export.py index 99189601a0..8da43b3a5e 100644 --- a/models/export.py +++ b/models/export.py @@ -1,34 +1,43 @@ -"""Exports a YOLOv3 *.pt model to ONNX and TorchScript formats +"""Exports a YOLOv3 *.pt model to TorchScript, ONNX, CoreML formats Usage: - $ export PYTHONPATH="$PWD" && python models/export.py --weights ./weights/yolov3.pt --img 640 --batch 1 + $ python path/to/models/export.py --weights yolov3.pt --img 640 --batch 1 """ import argparse import sys import time +from pathlib import Path -sys.path.append('./') # to run '$ python *.py' files in subdirectories +sys.path.append(Path(__file__).parent.parent.absolute().__str__()) # to run '$ python *.py' files in subdirectories import torch import torch.nn as nn +from torch.utils.mobile_optimizer import optimize_for_mobile import models from models.experimental import attempt_load from utils.activations import Hardswish, SiLU -from utils.general import set_logging, check_img_size +from utils.general import colorstr, check_img_size, check_requirements, file_size, set_logging from utils.torch_utils import select_device if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default='./yolov3.pt', help='weights path') # from yolov3/models/ + parser.add_argument('--weights', type=str, default='./yolov3.pt', help='weights path') parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='image size') # height, width parser.add_argument('--batch-size', type=int, default=1, help='batch size') - parser.add_argument('--dynamic', action='store_true', help='dynamic ONNX axes') - parser.add_argument('--grid', action='store_true', help='export Detect() layer grid') parser.add_argument('--device', default='cpu', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--include', nargs='+', default=['torchscript', 'onnx', 'coreml'], help='include formats') + parser.add_argument('--half', action='store_true', help='FP16 half-precision export') + parser.add_argument('--inplace', action='store_true', help='set YOLOv3 Detect() inplace=True') + parser.add_argument('--train', action='store_true', help='model.train() mode') + parser.add_argument('--optimize', action='store_true', help='optimize TorchScript for mobile') # TorchScript-only + parser.add_argument('--dynamic', action='store_true', help='dynamic ONNX axes') # ONNX-only + parser.add_argument('--simplify', action='store_true', help='simplify ONNX model') # ONNX-only + parser.add_argument('--opset-version', type=int, default=12, help='ONNX opset version') # ONNX-only opt = parser.parse_args() opt.img_size *= 2 if len(opt.img_size) == 1 else 1 # expand + opt.include = [x.lower() for x in opt.include] print(opt) set_logging() t = time.time() @@ -41,11 +50,16 @@ # Checks gs = int(max(model.stride)) # grid size (max stride) opt.img_size = [check_img_size(x, gs) for x in opt.img_size] # verify img_size are gs-multiples + assert not (opt.device.lower() == 'cpu' and opt.half), '--half only compatible with GPU export, i.e. use --device 0' # Input img = torch.zeros(opt.batch_size, 3, *opt.img_size).to(device) # image size(1,3,320,192) iDetection # Update model + if opt.half: + img, model = img.half(), model.half() # to FP16 + if opt.train: + model.train() # training mode (no grid construction in Detect layer) for k, m in model.named_modules(): m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility if isinstance(m, models.common.Conv): # assign export-friendly activations @@ -53,52 +67,79 @@ m.act = Hardswish() elif isinstance(m.act, nn.SiLU): m.act = SiLU() - # elif isinstance(m, models.yolo.Detect): - # m.forward = m.forward_export # assign forward (optional) - model.model[-1].export = not opt.grid # set Detect() layer grid export - y = model(img) # dry run - - # TorchScript export - try: - print('\nStarting TorchScript export with torch %s...' % torch.__version__) - f = opt.weights.replace('.pt', '.torchscript.pt') # filename - ts = torch.jit.trace(model, img, strict=False) - ts.save(f) - print('TorchScript export success, saved as %s' % f) - except Exception as e: - print('TorchScript export failure: %s' % e) - - # ONNX export - try: - import onnx - - print('\nStarting ONNX export with onnx %s...' % onnx.__version__) - f = opt.weights.replace('.pt', '.onnx') # filename - torch.onnx.export(model, img, f, verbose=False, opset_version=12, input_names=['images'], - output_names=['classes', 'boxes'] if y is None else ['output'], - dynamic_axes={'images': {0: 'batch', 2: 'height', 3: 'width'}, # size(1,3,640,640) - 'output': {0: 'batch', 2: 'y', 3: 'x'}} if opt.dynamic else None) - - # Checks - onnx_model = onnx.load(f) # load onnx model - onnx.checker.check_model(onnx_model) # check onnx model - # print(onnx.helper.printable_graph(onnx_model.graph)) # print a human readable model - print('ONNX export success, saved as %s' % f) - except Exception as e: - print('ONNX export failure: %s' % e) - - # CoreML export - try: - import coremltools as ct - - print('\nStarting CoreML export with coremltools %s...' % ct.__version__) - # convert model from torchscript and apply pixel scaling as per detect.py - model = ct.convert(ts, inputs=[ct.ImageType(name='image', shape=img.shape, scale=1 / 255.0, bias=[0, 0, 0])]) - f = opt.weights.replace('.pt', '.mlmodel') # filename - model.save(f) - print('CoreML export success, saved as %s' % f) - except Exception as e: - print('CoreML export failure: %s' % e) + elif isinstance(m, models.yolo.Detect): + m.inplace = opt.inplace + m.onnx_dynamic = opt.dynamic + # m.forward = m.forward_export # assign forward (optional) + + for _ in range(2): + y = model(img) # dry runs + print(f"\n{colorstr('PyTorch:')} starting from {opt.weights} ({file_size(opt.weights):.1f} MB)") + + # TorchScript export ----------------------------------------------------------------------------------------------- + if 'torchscript' in opt.include or 'coreml' in opt.include: + prefix = colorstr('TorchScript:') + try: + print(f'\n{prefix} starting export with torch {torch.__version__}...') + f = opt.weights.replace('.pt', '.torchscript.pt') # filename + ts = torch.jit.trace(model, img, strict=False) + (optimize_for_mobile(ts) if opt.optimize else ts).save(f) + print(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') + except Exception as e: + print(f'{prefix} export failure: {e}') + + # ONNX export ------------------------------------------------------------------------------------------------------ + if 'onnx' in opt.include: + prefix = colorstr('ONNX:') + try: + import onnx + + print(f'{prefix} starting export with onnx {onnx.__version__}...') + f = opt.weights.replace('.pt', '.onnx') # filename + torch.onnx.export(model, img, f, verbose=False, opset_version=opt.opset_version, input_names=['images'], + training=torch.onnx.TrainingMode.TRAINING if opt.train else torch.onnx.TrainingMode.EVAL, + do_constant_folding=not opt.train, + dynamic_axes={'images': {0: 'batch', 2: 'height', 3: 'width'}, # size(1,3,640,640) + 'output': {0: 'batch', 2: 'y', 3: 'x'}} if opt.dynamic else None) + + # Checks + model_onnx = onnx.load(f) # load onnx model + onnx.checker.check_model(model_onnx) # check onnx model + # print(onnx.helper.printable_graph(model_onnx.graph)) # print + + # Simplify + if opt.simplify: + try: + check_requirements(['onnx-simplifier']) + import onnxsim + + print(f'{prefix} simplifying with onnx-simplifier {onnxsim.__version__}...') + model_onnx, check = onnxsim.simplify( + model_onnx, + dynamic_input_shape=opt.dynamic, + input_shapes={'images': list(img.shape)} if opt.dynamic else None) + assert check, 'assert check failed' + onnx.save(model_onnx, f) + except Exception as e: + print(f'{prefix} simplifier failure: {e}') + print(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') + except Exception as e: + print(f'{prefix} export failure: {e}') + + # CoreML export ---------------------------------------------------------------------------------------------------- + if 'coreml' in opt.include: + prefix = colorstr('CoreML:') + try: + import coremltools as ct + + print(f'{prefix} starting export with coremltools {ct.__version__}...') + assert opt.train, 'CoreML exports should be placed in model.train() mode with `python export.py --train`' + model = ct.convert(ts, inputs=[ct.ImageType('image', shape=img.shape, scale=1 / 255.0, bias=[0, 0, 0])]) + f = opt.weights.replace('.pt', '.mlmodel') # filename + model.save(f) + print(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') + except Exception as e: + print(f'{prefix} export failure: {e}') # Finish - print('\nExport complete (%.2fs). Visualize with https://github.com/lutzroeder/netron.' % (time.time() - t)) + print(f'\nExport complete ({time.time() - t:.2f}s). Visualize with https://github.com/lutzroeder/netron.') diff --git a/models/yolo.py b/models/yolo.py index 706ea20e12..934cab69df 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -1,11 +1,16 @@ -# YOLOv3 YOLO-specific modules +"""YOLOv3-specific modules + +Usage: + $ python path/to/models/yolo.py --cfg yolov3.yaml +""" import argparse import logging import sys from copy import deepcopy +from pathlib import Path -sys.path.append('./') # to run '$ python *.py' files in subdirectories +sys.path.append(Path(__file__).parent.parent.absolute().__str__()) # to run '$ python *.py' files in subdirectories logger = logging.getLogger(__name__) from models.common import * @@ -23,9 +28,9 @@ class Detect(nn.Module): stride = None # strides computed during build - export = False # onnx export + onnx_dynamic = False # ONNX export parameter - def __init__(self, nc=80, anchors=(), ch=()): # detection layer + def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer super(Detect, self).__init__() self.nc = nc # number of classes self.no = nc + 5 # number of outputs per anchor @@ -36,23 +41,28 @@ def __init__(self, nc=80, anchors=(), ch=()): # detection layer self.register_buffer('anchors', a) # shape(nl,na,2) self.register_buffer('anchor_grid', a.clone().view(self.nl, 1, -1, 1, 1, 2)) # shape(nl,1,na,1,1,2) self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv + self.inplace = inplace # use in-place ops (e.g. slice assignment) def forward(self, x): # x = x.copy() # for profiling z = [] # inference output - self.training |= self.export for i in range(self.nl): x[i] = self.m[i](x[i]) # conv bs, _, ny, nx = x[i].shape # x(bs,255,20,20) to x(bs,3,20,20,85) x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous() if not self.training: # inference - if self.grid[i].shape[2:4] != x[i].shape[2:4]: + if self.grid[i].shape[2:4] != x[i].shape[2:4] or self.onnx_dynamic: self.grid[i] = self._make_grid(nx, ny).to(x[i].device) y = x[i].sigmoid() - y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + self.grid[i]) * self.stride[i] # xy - y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh + if self.inplace: + y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + self.grid[i]) * self.stride[i] # xy + y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh + else: # for YOLOv5 on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953 + xy = (y[..., 0:2] * 2. - 0.5 + self.grid[i]) * self.stride[i] # xy + wh = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i].view(1, self.na, 1, 1, 2) # wh + y = torch.cat((xy, wh, y[..., 4:]), -1) z.append(y.view(bs, -1, self.no)) return x if self.training else (torch.cat(z, 1), x) @@ -72,7 +82,7 @@ def __init__(self, cfg='yolov3.yaml', ch=3, nc=None, anchors=None): # model, in import yaml # for torch hub self.yaml_file = Path(cfg).name with open(cfg) as f: - self.yaml = yaml.load(f, Loader=yaml.SafeLoader) # model dict + self.yaml = yaml.safe_load(f) # model dict # Define model ch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channels @@ -84,18 +94,20 @@ def __init__(self, cfg='yolov3.yaml', ch=3, nc=None, anchors=None): # model, in self.yaml['anchors'] = round(anchors) # override yaml value self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelist self.names = [str(i) for i in range(self.yaml['nc'])] # default names - # print([x.shape for x in self.forward(torch.zeros(1, ch, 64, 64))]) + self.inplace = self.yaml.get('inplace', True) + # logger.info([x.shape for x in self.forward(torch.zeros(1, ch, 64, 64))]) # Build strides, anchors m = self.model[-1] # Detect() if isinstance(m, Detect): s = 256 # 2x min stride + m.inplace = self.inplace m.stride = torch.tensor([s / x.shape[-2] for x in self.forward(torch.zeros(1, ch, s, s))]) # forward m.anchors /= m.stride.view(-1, 1, 1) check_anchor_order(m) self.stride = m.stride self._initialize_biases() # only run once - # print('Strides: %s' % m.stride.tolist()) + # logger.info('Strides: %s' % m.stride.tolist()) # Init weights, biases initialize_weights(self) @@ -104,24 +116,23 @@ def __init__(self, cfg='yolov3.yaml', ch=3, nc=None, anchors=None): # model, in def forward(self, x, augment=False, profile=False): if augment: - img_size = x.shape[-2:] # height, width - s = [1, 0.83, 0.67] # scales - f = [None, 3, None] # flips (2-ud, 3-lr) - y = [] # outputs - for si, fi in zip(s, f): - xi = scale_img(x.flip(fi) if fi else x, si, gs=int(self.stride.max())) - yi = self.forward_once(xi)[0] # forward - # cv2.imwrite(f'img_{si}.jpg', 255 * xi[0].cpu().numpy().transpose((1, 2, 0))[:, :, ::-1]) # save - yi[..., :4] /= si # de-scale - if fi == 2: - yi[..., 1] = img_size[0] - yi[..., 1] # de-flip ud - elif fi == 3: - yi[..., 0] = img_size[1] - yi[..., 0] # de-flip lr - y.append(yi) - return torch.cat(y, 1), None # augmented inference, train + return self.forward_augment(x) # augmented inference, None else: return self.forward_once(x, profile) # single-scale inference, train + def forward_augment(self, x): + img_size = x.shape[-2:] # height, width + s = [1, 0.83, 0.67] # scales + f = [None, 3, None] # flips (2-ud, 3-lr) + y = [] # outputs + for si, fi in zip(s, f): + xi = scale_img(x.flip(fi) if fi else x, si, gs=int(self.stride.max())) + yi = self.forward_once(xi)[0] # forward + # cv2.imwrite(f'img_{si}.jpg', 255 * xi[0].cpu().numpy().transpose((1, 2, 0))[:, :, ::-1]) # save + yi = self._descale_pred(yi, fi, si, img_size) + y.append(yi) + return torch.cat(y, 1), None # augmented inference, train + def forward_once(self, x, profile=False): y, dt = [], [] # outputs for m in self.model: @@ -134,15 +145,34 @@ def forward_once(self, x, profile=False): for _ in range(10): _ = m(x) dt.append((time_synchronized() - t) * 100) - print('%10.1f%10.0f%10.1fms %-40s' % (o, m.np, dt[-1], m.type)) + if m == self.model[0]: + logger.info(f"{'time (ms)':>10s} {'GFLOPS':>10s} {'params':>10s} {'module'}") + logger.info(f'{dt[-1]:10.2f} {o:10.2f} {m.np:10.0f} {m.type}') x = m(x) # run y.append(x if m.i in self.save else None) # save output if profile: - print('%.1fms total' % sum(dt)) + logger.info('%.1fms total' % sum(dt)) return x + def _descale_pred(self, p, flips, scale, img_size): + # de-scale predictions following augmented inference (inverse operation) + if self.inplace: + p[..., :4] /= scale # de-scale + if flips == 2: + p[..., 1] = img_size[0] - p[..., 1] # de-flip ud + elif flips == 3: + p[..., 0] = img_size[1] - p[..., 0] # de-flip lr + else: + x, y, wh = p[..., 0:1] / scale, p[..., 1:2] / scale, p[..., 2:4] / scale # de-scale + if flips == 2: + y = img_size[0] - y # de-flip ud + elif flips == 3: + x = img_size[1] - x # de-flip lr + p = torch.cat((x, y, wh, p[..., 4:]), -1) + return p + def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is class frequency # https://arxiv.org/abs/1708.02002 section 3.3 # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1. @@ -157,15 +187,16 @@ def _print_biases(self): m = self.model[-1] # Detect() module for mi in m.m: # from b = mi.bias.detach().view(m.na, -1).T # conv.bias(255) to (3,85) - print(('%6g Conv2d.bias:' + '%10.3g' * 6) % (mi.weight.shape[1], *b[:5].mean(1).tolist(), b[5:].mean())) + logger.info( + ('%6g Conv2d.bias:' + '%10.3g' * 6) % (mi.weight.shape[1], *b[:5].mean(1).tolist(), b[5:].mean())) # def _print_weights(self): # for m in self.model.modules(): # if type(m) is Bottleneck: - # print('%10.3g' % (m.w.detach().sigmoid() * 2)) # shortcut weights + # logger.info('%10.3g' % (m.w.detach().sigmoid() * 2)) # shortcut weights def fuse(self): # fuse model Conv2d() + BatchNorm2d() layers - print('Fusing layers... ') + logger.info('Fusing layers... ') for m in self.model.modules(): if type(m) is Conv and hasattr(m, 'bn'): m.conv = fuse_conv_and_bn(m.conv, m.bn) # update conv @@ -177,20 +208,20 @@ def fuse(self): # fuse model Conv2d() + BatchNorm2d() layers def nms(self, mode=True): # add or remove NMS module present = type(self.model[-1]) is NMS # last layer is NMS if mode and not present: - print('Adding NMS... ') + logger.info('Adding NMS... ') m = NMS() # module m.f = -1 # from m.i = self.model[-1].i + 1 # index self.model.add_module(name='%s' % m.i, module=m) # add self.eval() elif not mode and present: - print('Removing NMS... ') + logger.info('Removing NMS... ') self.model = self.model[:-1] # remove return self - def autoshape(self): # add autoShape module - print('Adding autoShape... ') - m = autoShape(self) # wrap model + def autoshape(self): # add AutoShape module + logger.info('Adding AutoShape... ') + m = AutoShape(self) # wrap model copy_attr(m, self, include=('yaml', 'nc', 'hyp', 'names', 'stride'), exclude=()) # copy attributes return m @@ -266,12 +297,12 @@ def parse_model(d, ch): # model_dict, input_channels(3) model.train() # Profile - # img = torch.rand(8 if torch.cuda.is_available() else 1, 3, 640, 640).to(device) + # img = torch.rand(8 if torch.cuda.is_available() else 1, 3, 320, 320).to(device) # y = model(img, profile=True) - # Tensorboard + # Tensorboard (not working https://github.com/ultralytics/yolov5/issues/2898) # from torch.utils.tensorboard import SummaryWriter - # tb_writer = SummaryWriter() - # print("Run 'tensorboard --logdir=models/runs' to view tensorboard at http://localhost:6006/") - # tb_writer.add_graph(model.model, img) # add model to tensorboard + # tb_writer = SummaryWriter('.') + # logger.info("Run 'tensorboard --logdir=models' to view tensorboard at http://localhost:6006/") + # tb_writer.add_graph(torch.jit.trace(model, img, strict=False), []) # add model graph # tb_writer.add_image('test', img[0], dataformats='CWH') # add model to tensorboard diff --git a/requirements.txt b/requirements.txt index fd187eb56c..1c07c65115 100755 --- a/requirements.txt +++ b/requirements.txt @@ -21,9 +21,10 @@ pandas # export -------------------------------------- # coremltools>=4.1 -# onnx>=1.8.1 +# onnx>=1.9.0 # scikit-learn==0.19.2 # for coreml quantization # extras -------------------------------------- -thop # FLOPS computation +# Cython # for pycocotools https://github.com/cocodataset/cocoapi/issues/172 pycocotools>=2.0 # COCO mAP +thop # FLOPS computation diff --git a/test.py b/test.py index 0b7f61c106..396beef6e1 100644 --- a/test.py +++ b/test.py @@ -18,6 +18,7 @@ from utils.torch_utils import select_device, time_synchronized +@torch.no_grad() def test(data, weights=None, batch_size=32, @@ -38,7 +39,8 @@ def test(data, wandb_logger=None, compute_loss=None, half_precision=True, - is_coco=False): + is_coco=False, + opt=None): # Initialize/load model and set device training = model is not None if training: # called by train.py @@ -49,7 +51,7 @@ def test(data, device = select_device(opt.device, batch_size=batch_size) # Directories - save_dir = Path(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) # increment run + save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok) # increment run (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir # Load model @@ -71,7 +73,7 @@ def test(data, if isinstance(data, str): is_coco = data.endswith('coco.yaml') with open(data) as f: - data = yaml.load(f, Loader=yaml.SafeLoader) + data = yaml.safe_load(f) check_dataset(data) # check nc = 1 if single_cls else int(data['nc']) # number of classes iouv = torch.linspace(0.5, 0.95, 10).to(device) # iou vector for mAP@0.5:0.95 @@ -104,22 +106,21 @@ def test(data, targets = targets.to(device) nb, _, height, width = img.shape # batch size, channels, height, width - with torch.no_grad(): - # Run model - t = time_synchronized() - out, train_out = model(img, augment=augment) # inference and training outputs - t0 += time_synchronized() - t + # Run model + t = time_synchronized() + out, train_out = model(img, augment=augment) # inference and training outputs + t0 += time_synchronized() - t - # Compute loss - if compute_loss: - loss += compute_loss([x.float() for x in train_out], targets)[1][:3] # box, obj, cls + # Compute loss + if compute_loss: + loss += compute_loss([x.float() for x in train_out], targets)[1][:3] # box, obj, cls - # Run NMS - targets[:, 2:] *= torch.Tensor([width, height, width, height]).to(device) # to pixels - lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling - t = time_synchronized() - out = non_max_suppression(out, conf_thres=conf_thres, iou_thres=iou_thres, labels=lb, multi_label=True) - t1 += time_synchronized() - t + # Run NMS + targets[:, 2:] *= torch.Tensor([width, height, width, height]).to(device) # to pixels + lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling + t = time_synchronized() + out = non_max_suppression(out, conf_thres, iou_thres, labels=lb, multi_label=True, agnostic=single_cls) + t1 += time_synchronized() - t # Statistics per image for si, pred in enumerate(out): @@ -135,6 +136,8 @@ def test(data, continue # Predictions + if single_cls: + pred[:, 5] = 0 predn = pred.clone() scale_coords(img[si].shape[1:], predn[:, :4], shapes[si][0], shapes[si][1]) # native-space pred @@ -185,8 +188,8 @@ def test(data, # Per target class for cls in torch.unique(tcls_tensor): - ti = (cls == tcls_tensor).nonzero(as_tuple=False).view(-1) # prediction indices - pi = (cls == pred[:, 5]).nonzero(as_tuple=False).view(-1) # target indices + ti = (cls == tcls_tensor).nonzero(as_tuple=False).view(-1) # target indices + pi = (cls == pred[:, 5]).nonzero(as_tuple=False).view(-1) # prediction indices # Search for detections if pi.shape[0]: @@ -307,7 +310,7 @@ def test(data, opt.save_json |= opt.data.endswith('coco.yaml') opt.data = check_file(opt.data) # check file print(opt) - check_requirements() + check_requirements(exclude=('tensorboard', 'pycocotools', 'thop')) if opt.task in ('train', 'val', 'test'): # run normally test(opt.data, @@ -323,11 +326,12 @@ def test(data, save_txt=opt.save_txt | opt.save_hybrid, save_hybrid=opt.save_hybrid, save_conf=opt.save_conf, + opt=opt ) elif opt.task == 'speed': # speed benchmarks for w in opt.weights: - test(opt.data, w, opt.batch_size, opt.img_size, 0.25, 0.45, save_json=False, plots=False) + test(opt.data, w, opt.batch_size, opt.img_size, 0.25, 0.45, save_json=False, plots=False, opt=opt) elif opt.task == 'study': # run over a range of settings and save/plot # python test.py --task study --data coco.yaml --iou 0.7 --weights yolov3.pt yolov3-spp.pt yolov3-tiny.pt @@ -338,7 +342,7 @@ def test(data, for i in x: # img-size print(f'\nRunning {f} point {i}...') r, _, t = test(opt.data, w, opt.batch_size, i, opt.conf_thres, opt.iou_thres, opt.save_json, - plots=False) + plots=False, opt=opt) y.append(r + t) # results and times np.savetxt(f, y, fmt='%10.4g') # save os.system('zip -r study.zip study_*.txt') diff --git a/train.py b/train.py index ff7d96b772..8f7866093b 100644 --- a/train.py +++ b/train.py @@ -32,7 +32,7 @@ from utils.google_utils import attempt_download from utils.loss import ComputeLoss from utils.plots import plot_images, plot_labels, plot_results, plot_evolution -from utils.torch_utils import ModelEMA, select_device, intersect_dicts, torch_distributed_zero_first, is_parallel +from utils.torch_utils import ModelEMA, select_device, intersect_dicts, torch_distributed_zero_first, de_parallel from utils.wandb_logging.wandb_utils import WandbLogger, check_wandb_resume logger = logging.getLogger(__name__) @@ -52,24 +52,23 @@ def train(hyp, opt, device, tb_writer=None): # Save run settings with open(save_dir / 'hyp.yaml', 'w') as f: - yaml.dump(hyp, f, sort_keys=False) + yaml.safe_dump(hyp, f, sort_keys=False) with open(save_dir / 'opt.yaml', 'w') as f: - yaml.dump(vars(opt), f, sort_keys=False) + yaml.safe_dump(vars(opt), f, sort_keys=False) # Configure plots = not opt.evolve # create plots cuda = device.type != 'cpu' init_seeds(2 + rank) with open(opt.data) as f: - data_dict = yaml.load(f, Loader=yaml.SafeLoader) # data dict - is_coco = opt.data.endswith('coco.yaml') + data_dict = yaml.safe_load(f) # data dict # Logging- Doing this before checking the dataset. Might update data_dict loggers = {'wandb': None} # loggers dict if rank in [-1, 0]: opt.hyp = hyp # add hyperparameters run_id = torch.load(weights).get('wandb_id') if weights.endswith('.pt') and os.path.isfile(weights) else None - wandb_logger = WandbLogger(opt, Path(opt.save_dir).stem, run_id, data_dict) + wandb_logger = WandbLogger(opt, save_dir.stem, run_id, data_dict) loggers['wandb'] = wandb_logger.wandb data_dict = wandb_logger.data_dict if wandb_logger.wandb: @@ -78,12 +77,13 @@ def train(hyp, opt, device, tb_writer=None): nc = 1 if opt.single_cls else int(data_dict['nc']) # number of classes names = ['item'] if opt.single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names assert len(names) == nc, '%g names found for nc=%g dataset in %s' % (len(names), nc, opt.data) # check + is_coco = opt.data.endswith('coco.yaml') and nc == 80 # COCO dataset # Model pretrained = weights.endswith('.pt') if pretrained: with torch_distributed_zero_first(rank): - attempt_download(weights) # download if not found locally + weights = attempt_download(weights) # download if not found locally ckpt = torch.load(weights, map_location=device) # load checkpoint model = Model(opt.cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create exclude = ['anchor'] if (opt.cfg or hyp.get('anchors')) and not opt.resume else [] # exclude keys @@ -330,9 +330,9 @@ def train(hyp, opt, device, tb_writer=None): if plots and ni < 3: f = save_dir / f'train_batch{ni}.jpg' # filename Thread(target=plot_images, args=(imgs, targets, paths, f), daemon=True).start() - # if tb_writer: - # tb_writer.add_image(f, result, dataformats='HWC', global_step=epoch) - # tb_writer.add_graph(torch.jit.trace(model, imgs, strict=False), []) # add model graph + if tb_writer: + tb_writer.add_graph(torch.jit.trace(de_parallel(model), imgs, strict=False), []) # model graph + # tb_writer.add_image(f, result, dataformats='HWC', global_step=epoch) elif plots and ni == 10 and wandb_logger.wandb: wandb_logger.log({"Mosaics": [wandb_logger.wandb.Image(str(x), caption=x.name) for x in save_dir.glob('train*.jpg') if x.exists()]}) @@ -358,6 +358,7 @@ def train(hyp, opt, device, tb_writer=None): single_cls=opt.single_cls, dataloader=testloader, save_dir=save_dir, + save_json=is_coco and final_epoch, verbose=nc < 50 and final_epoch, plots=plots and final_epoch, wandb_logger=wandb_logger, @@ -367,8 +368,6 @@ def train(hyp, opt, device, tb_writer=None): # Write with open(results_file, 'a') as f: f.write(s + '%10.4g' * 7 % results + '\n') # append metrics, val_loss - if len(opt.name) and opt.bucket: - os.system('gsutil cp %s gs://%s/results/results%s.txt' % (results_file, opt.bucket, opt.name)) # Log tags = ['train/box_loss', 'train/obj_loss', 'train/cls_loss', # train loss @@ -392,7 +391,7 @@ def train(hyp, opt, device, tb_writer=None): ckpt = {'epoch': epoch, 'best_fitness': best_fitness, 'training_results': results_file.read_text(), - 'model': deepcopy(model.module if is_parallel(model) else model).half(), + 'model': deepcopy(de_parallel(model)).half(), 'ema': deepcopy(ema.ema).half(), 'updates': ema.updates, 'optimizer': optimizer.state_dict(), @@ -411,41 +410,38 @@ def train(hyp, opt, device, tb_writer=None): # end epoch ---------------------------------------------------------------------------------------------------- # end training if rank in [-1, 0]: - # Plots + logger.info(f'{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.\n') if plots: plot_results(save_dir=save_dir) # save as results.png if wandb_logger.wandb: files = ['results.png', 'confusion_matrix.png', *[f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R')]] wandb_logger.log({"Results": [wandb_logger.wandb.Image(str(save_dir / f), caption=f) for f in files if (save_dir / f).exists()]}) - # Test best.pt - logger.info('%g epochs completed in %.3f hours.\n' % (epoch - start_epoch + 1, (time.time() - t0) / 3600)) - if opt.data.endswith('coco.yaml') and nc == 80: # if COCO - for m in (last, best) if best.exists() else (last): # speed, mAP tests - results, _, _ = test.test(opt.data, - batch_size=batch_size * 2, - imgsz=imgsz_test, - conf_thres=0.001, - iou_thres=0.7, - model=attempt_load(m, device).half(), - single_cls=opt.single_cls, - dataloader=testloader, - save_dir=save_dir, - save_json=True, - plots=False, - is_coco=is_coco) - - # Strip optimizers - final = best if best.exists() else last # final model - for f in last, best: - if f.exists(): - strip_optimizer(f) # strip optimizers - if opt.bucket: - os.system(f'gsutil cp {final} gs://{opt.bucket}/weights') # upload - if wandb_logger.wandb and not opt.evolve: # Log the stripped model - wandb_logger.wandb.log_artifact(str(final), type='model', - name='run_' + wandb_logger.wandb_run.id + '_model', - aliases=['last', 'best', 'stripped']) + + if not opt.evolve: + if is_coco: # COCO dataset + for m in [last, best] if best.exists() else [last]: # speed, mAP tests + results, _, _ = test.test(opt.data, + batch_size=batch_size * 2, + imgsz=imgsz_test, + conf_thres=0.001, + iou_thres=0.7, + model=attempt_load(m, device).half(), + single_cls=opt.single_cls, + dataloader=testloader, + save_dir=save_dir, + save_json=True, + plots=False, + is_coco=is_coco) + + # Strip optimizers + for f in last, best: + if f.exists(): + strip_optimizer(f) # strip optimizers + if wandb_logger.wandb: # Log the stripped model + wandb_logger.wandb.log_artifact(str(best if best.exists() else last), type='model', + name='run_' + wandb_logger.wandb_run.id + '_model', + aliases=['latest', 'best', 'stripped']) wandb_logger.finish_run() else: dist.destroy_process_group() @@ -497,7 +493,7 @@ def train(hyp, opt, device, tb_writer=None): set_logging(opt.global_rank) if opt.global_rank in [-1, 0]: check_git_status() - check_requirements() + check_requirements(exclude=('pycocotools', 'thop')) # Resume wandb_run = check_wandb_resume(opt) @@ -506,8 +502,9 @@ def train(hyp, opt, device, tb_writer=None): assert os.path.isfile(ckpt), 'ERROR: --resume checkpoint does not exist' apriori = opt.global_rank, opt.local_rank with open(Path(ckpt).parent.parent / 'opt.yaml') as f: - opt = argparse.Namespace(**yaml.load(f, Loader=yaml.SafeLoader)) # replace - opt.cfg, opt.weights, opt.resume, opt.batch_size, opt.global_rank, opt.local_rank = '', ckpt, True, opt.total_batch_size, *apriori # reinstate + opt = argparse.Namespace(**yaml.safe_load(f)) # replace + opt.cfg, opt.weights, opt.resume, opt.batch_size, opt.global_rank, opt.local_rank = \ + '', ckpt, True, opt.total_batch_size, *apriori # reinstate logger.info('Resuming training from %s' % ckpt) else: # opt.hyp = opt.hyp or ('hyp.finetune.yaml' if opt.weights else 'hyp.scratch.yaml') @@ -515,7 +512,7 @@ def train(hyp, opt, device, tb_writer=None): assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' opt.img_size.extend([opt.img_size[-1]] * (2 - len(opt.img_size))) # extend to 2 sizes (train, test) opt.name = 'evolve' if opt.evolve else opt.name - opt.save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok | opt.evolve) # increment run + opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok | opt.evolve)) # DDP mode opt.total_batch_size = opt.batch_size @@ -526,11 +523,12 @@ def train(hyp, opt, device, tb_writer=None): device = torch.device('cuda', opt.local_rank) dist.init_process_group(backend='nccl', init_method='env://') # distributed backend assert opt.batch_size % opt.world_size == 0, '--batch-size must be multiple of CUDA device count' + assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' opt.batch_size = opt.total_batch_size // opt.world_size # Hyperparameters with open(opt.hyp) as f: - hyp = yaml.load(f, Loader=yaml.SafeLoader) # load hyps + hyp = yaml.safe_load(f) # load hyps # Train logger.info(opt) diff --git a/utils/activations.py b/utils/activations.py index aa3ddf071d..92a3b5eaa5 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -19,23 +19,6 @@ def forward(x): return x * F.hardtanh(x + 3, 0., 6.) / 6. # for torchscript, CoreML and ONNX -class MemoryEfficientSwish(nn.Module): - class F(torch.autograd.Function): - @staticmethod - def forward(ctx, x): - ctx.save_for_backward(x) - return x * torch.sigmoid(x) - - @staticmethod - def backward(ctx, grad_output): - x = ctx.saved_tensors[0] - sx = torch.sigmoid(x) - return grad_output * (sx * (1 + x * (1 - sx))) - - def forward(self, x): - return self.F.apply(x) - - # Mish https://github.com/digantamisra98/Mish -------------------------------------------------------------------------- class Mish(nn.Module): @staticmethod @@ -70,3 +53,46 @@ def __init__(self, c1, k=3): # ch_in, kernel def forward(self, x): return torch.max(x, self.bn(self.conv(x))) + + +# ACON https://arxiv.org/pdf/2009.04759.pdf ---------------------------------------------------------------------------- +class AconC(nn.Module): + r""" ACON activation (activate or not). + AconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is a learnable parameter + according to "Activate or Not: Learning Customized Activation" . + """ + + def __init__(self, c1): + super().__init__() + self.p1 = nn.Parameter(torch.randn(1, c1, 1, 1)) + self.p2 = nn.Parameter(torch.randn(1, c1, 1, 1)) + self.beta = nn.Parameter(torch.ones(1, c1, 1, 1)) + + def forward(self, x): + dpx = (self.p1 - self.p2) * x + return dpx * torch.sigmoid(self.beta * dpx) + self.p2 * x + + +class MetaAconC(nn.Module): + r""" ACON activation (activate or not). + MetaAconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is generated by a small network + according to "Activate or Not: Learning Customized Activation" . + """ + + def __init__(self, c1, k=1, s=1, r=16): # ch_in, kernel, stride, r + super().__init__() + c2 = max(r, c1 // r) + self.p1 = nn.Parameter(torch.randn(1, c1, 1, 1)) + self.p2 = nn.Parameter(torch.randn(1, c1, 1, 1)) + self.fc1 = nn.Conv2d(c1, c2, k, s, bias=True) + self.fc2 = nn.Conv2d(c2, c1, k, s, bias=True) + # self.bn1 = nn.BatchNorm2d(c2) + # self.bn2 = nn.BatchNorm2d(c1) + + def forward(self, x): + y = x.mean(dim=2, keepdims=True).mean(dim=3, keepdims=True) + # batch-size 1 bug/instabilities https://github.com/ultralytics/yolov5/issues/2891 + # beta = torch.sigmoid(self.bn2(self.fc2(self.bn1(self.fc1(y))))) # bug/unstable + beta = torch.sigmoid(self.fc2(self.fc1(y))) # bug patch BN layers removed + dpx = (self.p1 - self.p2) * x + return dpx * torch.sigmoid(beta * dpx) + self.p2 * x diff --git a/utils/autoanchor.py b/utils/autoanchor.py index 8d62474f28..51ed803455 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -3,7 +3,6 @@ import numpy as np import torch import yaml -from scipy.cluster.vq import kmeans from tqdm import tqdm from utils.general import colorstr @@ -76,6 +75,8 @@ def kmean_anchors(path='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=10 Usage: from utils.autoanchor import *; _ = kmean_anchors() """ + from scipy.cluster.vq import kmeans + thr = 1. / thr prefix = colorstr('autoanchor: ') @@ -102,7 +103,7 @@ def print_results(k): if isinstance(path, str): # *.yaml file with open(path) as f: - data_dict = yaml.load(f, Loader=yaml.SafeLoader) # model dict + data_dict = yaml.safe_load(f) # model dict from utils.datasets import LoadImagesAndLabels dataset = LoadImagesAndLabels(data_dict['train'], augment=True, rect=True) else: diff --git a/utils/aws/resume.py b/utils/aws/resume.py index faad8d2474..4b0d4246b5 100644 --- a/utils/aws/resume.py +++ b/utils/aws/resume.py @@ -19,7 +19,7 @@ # Load opt.yaml with open(last.parent.parent / 'opt.yaml') as f: - opt = yaml.load(f, Loader=yaml.SafeLoader) + opt = yaml.safe_load(f) # Get device count d = opt['device'].split(',') # devices diff --git a/utils/aws/userdata.sh b/utils/aws/userdata.sh index 890606b76a..5846fedb16 100644 --- a/utils/aws/userdata.sh +++ b/utils/aws/userdata.sh @@ -7,7 +7,7 @@ cd home/ubuntu if [ ! -d yolov5 ]; then echo "Running first-time script." # install dependencies, download COCO, pull Docker - git clone https://github.com/ultralytics/yolov5 && sudo chmod -R 777 yolov5 + git clone https://github.com/ultralytics/yolov5 -b master && sudo chmod -R 777 yolov5 cd yolov5 bash data/scripts/get_coco.sh && echo "Data done." & sudo docker pull ultralytics/yolov5:latest && echo "Docker done." & diff --git a/utils/datasets.py b/utils/datasets.py index fcaa3415b8..481b79a901 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -1,6 +1,7 @@ # Dataset utils and dataloaders import glob +import hashlib import logging import math import os @@ -36,9 +37,12 @@ break -def get_hash(files): - # Returns a single hash value of a list of files - return sum(os.path.getsize(f) for f in files if os.path.isfile(f)) +def get_hash(paths): + # Returns a single hash value of a list of paths (files or dirs) + size = sum(os.path.getsize(p) for p in paths if os.path.exists(p)) # sizes + h = hashlib.md5(str(size).encode()) # hash sizes + h.update(''.join(paths).encode()) # hash paths + return h.hexdigest() # return hash def exif_size(img): @@ -172,12 +176,12 @@ def __next__(self): ret_val, img0 = self.cap.read() self.frame += 1 - print(f'video {self.count + 1}/{self.nf} ({self.frame}/{self.nframes}) {path}: ', end='') + print(f'video {self.count + 1}/{self.nf} ({self.frame}/{self.frames}) {path}: ', end='') else: # Read image self.count += 1 - img0 = cv2.imread(path) # BGR + img0 = cv2.imread(path, -1) # BGR (-1 is IMREAD_UNCHANGED) assert img0 is not None, 'Image Not Found ' + path print(f'image {self.count}/{self.nf} {path}: ', end='') @@ -193,7 +197,7 @@ def __next__(self): def new_video(self, path): self.frame = 0 self.cap = cv2.VideoCapture(path) - self.nframes = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT)) + self.frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT)) def __len__(self): return self.nf # number of files @@ -270,26 +274,27 @@ def __init__(self, sources='streams.txt', img_size=640, stride=32): sources = [sources] n = len(sources) - self.imgs = [None] * n + self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n self.sources = [clean_str(x) for x in sources] # clean source names for later - for i, s in enumerate(sources): - # Start the thread to read frames from the video stream + for i, s in enumerate(sources): # index, source + # Start thread to read frames from video stream print(f'{i + 1}/{n}: {s}... ', end='') - url = eval(s) if s.isnumeric() else s - if 'youtube.com/' in url or 'youtu.be/' in url: # if source is YouTube video + if 'youtube.com/' in s or 'youtu.be/' in s: # if source is YouTube video check_requirements(('pafy', 'youtube_dl')) import pafy - url = pafy.new(url).getbest(preftype="mp4").url - cap = cv2.VideoCapture(url) + s = pafy.new(s).getbest(preftype="mp4").url # YouTube URL + s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam + cap = cv2.VideoCapture(s) assert cap.isOpened(), f'Failed to open {s}' w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) - self.fps = cap.get(cv2.CAP_PROP_FPS) % 100 + self.fps[i] = max(cap.get(cv2.CAP_PROP_FPS) % 100, 0) or 30.0 # 30 FPS fallback + self.frames[i] = max(int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback _, self.imgs[i] = cap.read() # guarantee first frame - thread = Thread(target=self.update, args=([i, cap]), daemon=True) - print(f' success ({w}x{h} at {self.fps:.2f} FPS).') - thread.start() + self.threads[i] = Thread(target=self.update, args=([i, cap]), daemon=True) + print(f" success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)") + self.threads[i].start() print('') # newline # check for common shapes @@ -298,18 +303,17 @@ def __init__(self, sources='streams.txt', img_size=640, stride=32): if not self.rect: print('WARNING: Different stream shapes detected. For optimal performance supply similarly-shaped streams.') - def update(self, index, cap): - # Read next stream frame in a daemon thread - n = 0 - while cap.isOpened(): + def update(self, i, cap): + # Read stream `i` frames in daemon thread + n, f = 0, self.frames[i] + while cap.isOpened() and n < f: n += 1 # _, self.imgs[index] = cap.read() cap.grab() - if n == 4: # read every 4th frame + if n % 4: # read every 4th frame success, im = cap.retrieve() - self.imgs[index] = im if success else self.imgs[index] * 0 - n = 0 - time.sleep(1 / self.fps) # wait time + self.imgs[i] = im if success else self.imgs[i] * 0 + time.sleep(1 / self.fps[i]) # wait time def __iter__(self): self.count = -1 @@ -317,12 +321,12 @@ def __iter__(self): def __next__(self): self.count += 1 - img0 = self.imgs.copy() - if cv2.waitKey(1) == ord('q'): # q to quit + if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit cv2.destroyAllWindows() raise StopIteration # Letterbox + img0 = self.imgs.copy() img = [letterbox(x, self.img_size, auto=self.rect, stride=self.stride)[0] for x in img0] # Stack @@ -383,7 +387,7 @@ def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, r cache_path = (p if p.is_file() else Path(self.label_files[0]).parent).with_suffix('.cache') # cached labels if cache_path.is_file(): cache, exists = torch.load(cache_path), True # load - if cache['hash'] != get_hash(self.label_files + self.img_files) or 'version' not in cache: # changed + if cache['hash'] != get_hash(self.label_files + self.img_files): # changed cache, exists = self.cache_labels(cache_path, prefix), False # re-cache else: cache, exists = self.cache_labels(cache_path, prefix), False # cache @@ -470,7 +474,7 @@ def cache_labels(self, path=Path('./labels.cache'), prefix=''): if os.path.isfile(lb_file): nf += 1 # label found with open(lb_file, 'r') as f: - l = [x.split() for x in f.read().strip().splitlines()] + l = [x.split() for x in f.read().strip().splitlines() if len(x)] if any([len(x) > 8 for x in l]): # is segment classes = np.array([x[0] for x in l], dtype=np.float32) segments = [np.array(x[1:], dtype=np.float32).reshape(-1, 2) for x in l] # (cls, xy1...) @@ -490,20 +494,23 @@ def cache_labels(self, path=Path('./labels.cache'), prefix=''): x[im_file] = [l, shape, segments] except Exception as e: nc += 1 - print(f'{prefix}WARNING: Ignoring corrupted image and/or label {im_file}: {e}') + logging.info(f'{prefix}WARNING: Ignoring corrupted image and/or label {im_file}: {e}') pbar.desc = f"{prefix}Scanning '{path.parent / path.stem}' images and labels... " \ f"{nf} found, {nm} missing, {ne} empty, {nc} corrupted" pbar.close() if nf == 0: - print(f'{prefix}WARNING: No labels found in {path}. See {help_url}') + logging.info(f'{prefix}WARNING: No labels found in {path}. See {help_url}') x['hash'] = get_hash(self.label_files + self.img_files) x['results'] = nf, nm, ne, nc, i + 1 - x['version'] = 0.1 # cache version - torch.save(x, path) # save for next time - logging.info(f'{prefix}New cache created: {path}') + x['version'] = 0.2 # cache version + try: + torch.save(x, path) # save cache for next time + logging.info(f'{prefix}New cache created: {path}') + except Exception as e: + logging.info(f'{prefix}WARNING: Cache directory {path.parent} is not writeable: {e}') # path not writeable return x def __len__(self): @@ -634,10 +641,10 @@ def load_image(self, index): img = cv2.imread(path) # BGR assert img is not None, 'Image Not Found ' + path h0, w0 = img.shape[:2] # orig hw - r = self.img_size / max(h0, w0) # resize image to img_size - if r != 1: # always resize down, only resize up if training with augmentation - interp = cv2.INTER_AREA if r < 1 and not self.augment else cv2.INTER_LINEAR - img = cv2.resize(img, (int(w0 * r), int(h0 * r)), interpolation=interp) + r = self.img_size / max(h0, w0) # ratio + if r != 1: # if sizes are not equal + img = cv2.resize(img, (int(w0 * r), int(h0 * r)), + interpolation=cv2.INTER_AREA if r < 1 and not self.augment else cv2.INTER_LINEAR) return img, (h0, w0), img.shape[:2] # img, hw_original, hw_resized else: return self.imgs[index], self.img_hw0[index], self.img_hw[index] # img, hw_original, hw_resized diff --git a/utils/flask_rest_api/README.md b/utils/flask_rest_api/README.md new file mode 100644 index 0000000000..324c2416dc --- /dev/null +++ b/utils/flask_rest_api/README.md @@ -0,0 +1,68 @@ +# Flask REST API +[REST](https://en.wikipedia.org/wiki/Representational_state_transfer) [API](https://en.wikipedia.org/wiki/API)s are commonly used to expose Machine Learning (ML) models to other services. This folder contains an example REST API created using Flask to expose the YOLOv5s model from [PyTorch Hub](https://pytorch.org/hub/ultralytics_yolov5/). + +## Requirements + +[Flask](https://palletsprojects.com/p/flask/) is required. Install with: +```shell +$ pip install Flask +``` + +## Run + +After Flask installation run: + +```shell +$ python3 restapi.py --port 5000 +``` + +Then use [curl](https://curl.se/) to perform a request: + +```shell +$ curl -X POST -F image=@zidane.jpg 'http://localhost:5000/v1/object-detection/yolov5s'` +``` + +The model inference results are returned as a JSON response: + +```json +[ + { + "class": 0, + "confidence": 0.8900438547, + "height": 0.9318675399, + "name": "person", + "width": 0.3264600933, + "xcenter": 0.7438579798, + "ycenter": 0.5207948685 + }, + { + "class": 0, + "confidence": 0.8440024257, + "height": 0.7155083418, + "name": "person", + "width": 0.6546785235, + "xcenter": 0.427829951, + "ycenter": 0.6334488392 + }, + { + "class": 27, + "confidence": 0.3771208823, + "height": 0.3902671337, + "name": "tie", + "width": 0.0696444362, + "xcenter": 0.3675483763, + "ycenter": 0.7991207838 + }, + { + "class": 27, + "confidence": 0.3527112305, + "height": 0.1540903747, + "name": "tie", + "width": 0.0336618312, + "xcenter": 0.7814827561, + "ycenter": 0.5065554976 + } +] +``` + +An example python script to perform inference using [requests](https://docs.python-requests.org/en/master/) is given in `example_request.py` diff --git a/utils/flask_rest_api/example_request.py b/utils/flask_rest_api/example_request.py new file mode 100644 index 0000000000..ff21f30f93 --- /dev/null +++ b/utils/flask_rest_api/example_request.py @@ -0,0 +1,13 @@ +"""Perform test request""" +import pprint + +import requests + +DETECTION_URL = "http://localhost:5000/v1/object-detection/yolov5s" +TEST_IMAGE = "zidane.jpg" + +image_data = open(TEST_IMAGE, "rb").read() + +response = requests.post(DETECTION_URL, files={"image": image_data}).json() + +pprint.pprint(response) diff --git a/utils/flask_rest_api/restapi.py b/utils/flask_rest_api/restapi.py new file mode 100644 index 0000000000..b0df747220 --- /dev/null +++ b/utils/flask_rest_api/restapi.py @@ -0,0 +1,37 @@ +""" +Run a rest API exposing the yolov5s object detection model +""" +import argparse +import io + +import torch +from PIL import Image +from flask import Flask, request + +app = Flask(__name__) + +DETECTION_URL = "/v1/object-detection/yolov5s" + + +@app.route(DETECTION_URL, methods=["POST"]) +def predict(): + if not request.method == "POST": + return + + if request.files.get("image"): + image_file = request.files["image"] + image_bytes = image_file.read() + + img = Image.open(io.BytesIO(image_bytes)) + + results = model(img, size=640) # reduce size=320 for faster inference + return results.pandas().xyxy[0].to_json(orient="records") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Flask API exposing YOLOv3 model") + parser.add_argument("--port", default=5000, type=int, help="port number") + args = parser.parse_args() + + model = torch.hub.load("ultralytics/yolov5", "yolov5s", force_reload=True) # force_reload to recache + app.run(host="0.0.0.0", port=args.port) # debug=True causes Restarting with stat diff --git a/utils/general.py b/utils/general.py index dbdcd39601..af33c63389 100755 --- a/utils/general.py +++ b/utils/general.py @@ -9,11 +9,14 @@ import re import subprocess import time +from itertools import repeat +from multiprocessing.pool import ThreadPool from pathlib import Path import cv2 import numpy as np import pandas as pd +import pkg_resources as pkg import torch import torchvision import yaml @@ -30,10 +33,10 @@ os.environ['NUMEXPR_MAX_THREADS'] = str(min(os.cpu_count(), 8)) # NumExpr max threads -def set_logging(rank=-1): +def set_logging(rank=-1, verbose=True): logging.basicConfig( format="%(message)s", - level=logging.INFO if rank in [-1, 0] else logging.WARN) + level=logging.INFO if (verbose and rank in [-1, 0]) else logging.WARN) def init_seeds(seed=0): @@ -49,16 +52,30 @@ def get_latest_run(search_dir='.'): return max(last_list, key=os.path.getctime) if last_list else '' -def isdocker(): +def is_docker(): # Is environment a Docker container return Path('/workspace').exists() # or Path('/.dockerenv').exists() +def is_colab(): + # Is environment a Google Colab instance + try: + import google.colab + return True + except Exception as e: + return False + + def emojis(str=''): # Return platform-dependent emoji-safe version of string return str.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else str +def file_size(file): + # Return file size in MB + return Path(file).stat().st_size / 1e6 + + def check_online(): # Check internet connectivity import socket @@ -74,7 +91,7 @@ def check_git_status(): print(colorstr('github: '), end='') try: assert Path('.git').exists(), 'skipping check (not a git repository)' - assert not isdocker(), 'skipping check (Docker image)' + assert not is_docker(), 'skipping check (Docker image)' assert check_online(), 'skipping check (offline)' cmd = 'git fetch && git config --get remote.origin.url' @@ -91,10 +108,19 @@ def check_git_status(): print(e) +def check_python(minimum='3.7.0', required=True): + # Check current python version vs. required python version + current = platform.python_version() + result = pkg.parse_version(current) >= pkg.parse_version(minimum) + if required: + assert result, f'Python {minimum} required by YOLOv3, but Python {current} is currently installed' + return result + + def check_requirements(requirements='requirements.txt', exclude=()): # Check installed dependencies meet requirements (pass *.txt file or list of packages) - import pkg_resources as pkg prefix = colorstr('red', 'bold', 'requirements:') + check_python() # check python version if isinstance(requirements, (str, Path)): # requirements.txt file file = Path(requirements) if not file.exists(): @@ -110,8 +136,11 @@ def check_requirements(requirements='requirements.txt', exclude=()): pkg.require(r) except Exception as e: # DistributionNotFound or VersionConflict if requirements not met n += 1 - print(f"{prefix} {e.req} not found and is required by YOLOv3, attempting auto-update...") - print(subprocess.check_output(f"pip install '{e.req}'", shell=True).decode()) + print(f"{prefix} {r} not found and is required by YOLOv3, attempting auto-update...") + try: + print(subprocess.check_output(f"pip install '{r}'", shell=True).decode()) + except Exception as e: + print(f'{prefix} {e}') if n: # if packages updated source = file.resolve() if 'file' in locals() else requirements @@ -131,7 +160,8 @@ def check_img_size(img_size, s=32): def check_imshow(): # Check if environment supports image displays try: - assert not isdocker(), 'cv2.imshow() is disabled in Docker environments' + assert not is_docker(), 'cv2.imshow() is disabled in Docker environments' + assert not is_colab(), 'cv2.imshow() is disabled in Google Colab environments' cv2.imshow('test', np.zeros((1, 1, 3))) cv2.waitKey(1) cv2.destroyAllWindows() @@ -143,12 +173,19 @@ def check_imshow(): def check_file(file): - # Search for file if not found - if Path(file).is_file() or file == '': + # Search/download file (if necessary) and return path + file = str(file) # convert to str() + if Path(file).is_file() or file == '': # exists return file - else: + elif file.startswith(('http://', 'https://')): # download + url, file = file, Path(file).name + print(f'Downloading {url} to {file}...') + torch.hub.download_url_to_file(url, file) + assert Path(file).exists() and Path(file).stat().st_size > 0, f'File download failed: {url}' # check + return file + else: # search files = glob.glob('./**/' + file, recursive=True) # find file - assert len(files), f'File Not Found: {file}' # assert file was found + assert len(files), f'File not found: {file}' # assert file was found assert len(files) == 1, f"Multiple files match '{file}', specify exact path: {files}" # assert unique return files[0] # return file @@ -161,18 +198,54 @@ def check_dataset(dict): if not all(x.exists() for x in val): print('\nWARNING: Dataset not found, nonexistent paths: %s' % [str(x) for x in val if not x.exists()]) if s and len(s): # download script - print('Downloading %s ...' % s) if s.startswith('http') and s.endswith('.zip'): # URL f = Path(s).name # filename + print(f'Downloading {s} ...') torch.hub.download_url_to_file(s, f) - r = os.system('unzip -q %s -d ../ && rm %s' % (f, f)) # unzip - else: # bash script + r = os.system(f'unzip -q {f} -d ../ && rm {f}') # unzip + elif s.startswith('bash '): # bash script + print(f'Running {s} ...') r = os.system(s) - print('Dataset autodownload %s\n' % ('success' if r == 0 else 'failure')) # analyze return value + else: # python script + r = exec(s) # return None + print('Dataset autodownload %s\n' % ('success' if r in (0, None) else 'failure')) # print result else: raise Exception('Dataset not found.') +def download(url, dir='.', unzip=True, delete=True, curl=False, threads=1): + # Multi-threaded file download and unzip function + def download_one(url, dir): + # Download 1 file + f = dir / Path(url).name # filename + if not f.exists(): + print(f'Downloading {url} to {f}...') + if curl: + os.system(f"curl -L '{url}' -o '{f}' --retry 9 -C -") # curl download, retry and resume on fail + else: + torch.hub.download_url_to_file(url, f, progress=True) # torch download + if unzip and f.suffix in ('.zip', '.gz'): + print(f'Unzipping {f}...') + if f.suffix == '.zip': + s = f'unzip -qo {f} -d {dir} && rm {f}' # unzip -quiet -overwrite + elif f.suffix == '.gz': + s = f'tar xfz {f} --directory {f.parent}' # unzip + if delete: # delete zip file after unzip + s += f' && rm {f}' + os.system(s) + + dir = Path(dir) + dir.mkdir(parents=True, exist_ok=True) # make directory + if threads > 1: + pool = ThreadPool(threads) + pool.imap(lambda x: download_one(*x), zip(url, repeat(dir))) # multi-threaded + pool.close() + pool.join() + else: + for u in tuple(url) if isinstance(url, str) else url: + download_one(u, dir) + + def make_divisible(x, divisor): # Returns x evenly divisible by divisor return math.ceil(x / divisor) * divisor @@ -419,7 +492,7 @@ def wh_iou(wh1, wh2): def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False, multi_label=False, - labels=()): + labels=(), max_det=300): """Runs Non-Maximum Suppression (NMS) on inference results Returns: @@ -429,9 +502,12 @@ def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=Non nc = prediction.shape[2] - 5 # number of classes xc = prediction[..., 4] > conf_thres # candidates + # Checks + assert 0 <= conf_thres <= 1, f'Invalid Confidence threshold {conf_thres}, valid values are between 0.0 and 1.0' + assert 0 <= iou_thres <= 1, f'Invalid IoU {iou_thres}, valid values are between 0.0 and 1.0' + # Settings min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height - max_det = 300 # maximum number of detections per image max_nms = 30000 # maximum number of boxes into torchvision.ops.nms() time_limit = 10.0 # seconds to quit after redundant = True # require redundant detections @@ -550,14 +626,14 @@ def print_mutation(hyp, results, yaml_file='hyp_evolved.yaml', bucket=''): results = tuple(x[0, :7]) c = '%10.4g' * len(results) % results # results (P, R, mAP@0.5, mAP@0.5:0.95, val_losses x 3) f.write('# Hyperparameter Evolution Results\n# Generations: %g\n# Metrics: ' % len(x) + c + '\n\n') - yaml.dump(hyp, f, sort_keys=False) + yaml.safe_dump(hyp, f, sort_keys=False) if bucket: os.system('gsutil cp evolve.txt %s gs://%s' % (yaml_file, bucket)) # upload def apply_classifier(x, model, img, im0): - # applies a second stage classifier to yolo outputs + # Apply a second stage classifier to yolo outputs im0 = [im0] if isinstance(im0, np.ndarray) else im0 for i, d in enumerate(x): # per image if d is not None and len(d): @@ -591,14 +667,33 @@ def apply_classifier(x, model, img, im0): return x -def increment_path(path, exist_ok=True, sep=''): - # Increment path, i.e. runs/exp --> runs/exp{sep}0, runs/exp{sep}1 etc. +def save_one_box(xyxy, im, file='image.jpg', gain=1.02, pad=10, square=False, BGR=False, save=True): + # Save image crop as {file} with crop size multiple {gain} and {pad} pixels. Save and/or return crop + xyxy = torch.tensor(xyxy).view(-1, 4) + b = xyxy2xywh(xyxy) # boxes + if square: + b[:, 2:] = b[:, 2:].max(1)[0].unsqueeze(1) # attempt rectangle to square + b[:, 2:] = b[:, 2:] * gain + pad # box wh * gain + pad + xyxy = xywh2xyxy(b).long() + clip_coords(xyxy, im.shape) + crop = im[int(xyxy[0, 1]):int(xyxy[0, 3]), int(xyxy[0, 0]):int(xyxy[0, 2]), ::(1 if BGR else -1)] + if save: + cv2.imwrite(str(increment_path(file, mkdir=True).with_suffix('.jpg')), crop) + return crop + + +def increment_path(path, exist_ok=False, sep='', mkdir=False): + # Increment file or directory path, i.e. runs/exp --> runs/exp{sep}2, runs/exp{sep}3, ... etc. path = Path(path) # os-agnostic - if (path.exists() and exist_ok) or (not path.exists()): - return str(path) - else: + if path.exists() and not exist_ok: + suffix = path.suffix + path = path.with_suffix('') dirs = glob.glob(f"{path}{sep}*") # similar paths matches = [re.search(rf"%s{sep}(\d+)" % path.stem, d) for d in dirs] i = [int(m.groups()[0]) for m in matches if m] # indices n = max(i) + 1 if i else 2 # increment number - return f"{path}{sep}{n}" # update path + path = Path(f"{path}{sep}{n}{suffix}") # update path + dir = path if path.suffix == '' else path.parent # directory + if not dir.exists() and mkdir: + dir.mkdir(parents=True, exist_ok=True) # make directory + return path diff --git a/utils/google_utils.py b/utils/google_utils.py index 61af2f4343..340fab1328 100644 --- a/utils/google_utils.py +++ b/utils/google_utils.py @@ -16,40 +16,57 @@ def gsutil_getsize(url=''): return eval(s.split(' ')[0]) if len(s) else 0 # bytes +def safe_download(file, url, url2=None, min_bytes=1E0, error_msg=''): + # Attempts to download file from url or url2, checks and removes incomplete downloads < min_bytes + file = Path(file) + try: # GitHub + print(f'Downloading {url} to {file}...') + torch.hub.download_url_to_file(url, str(file)) + assert file.exists() and file.stat().st_size > min_bytes # check + except Exception as e: # GCP + file.unlink(missing_ok=True) # remove partial downloads + print(f'Download error: {e}\nRe-attempting {url2 or url} to {file}...') + os.system(f"curl -L '{url2 or url}' -o '{file}' --retry 3 -C -") # curl download, retry and resume on fail + finally: + if not file.exists() or file.stat().st_size < min_bytes: # check + file.unlink(missing_ok=True) # remove partial downloads + print(f'ERROR: Download failure: {error_msg or url}') + print('') + + def attempt_download(file, repo='ultralytics/yolov3'): # Attempt file download if does not exist - file = Path(str(file).strip().replace("'", '').lower()) + file = Path(str(file).strip().replace("'", '')) if not file.exists(): + # URL specified + name = file.name + if str(file).startswith(('http:/', 'https:/')): # download + url = str(file).replace(':/', '://') # Pathlib turns :// -> :/ + safe_download(file=name, url=url, min_bytes=1E5) + return name + + # GitHub assets + file.parent.mkdir(parents=True, exist_ok=True) # make parent dir (if required) try: response = requests.get(f'https://api.github.com/repos/{repo}/releases/latest').json() # github api assets = [x['name'] for x in response['assets']] # release assets, i.e. ['yolov5s.pt', 'yolov5m.pt', ...] tag = response['tag_name'] # i.e. 'v1.0' except: # fallback plan assets = ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt'] - tag = subprocess.check_output('git tag', shell=True).decode().split()[-1] + try: + tag = subprocess.check_output('git tag', shell=True, stderr=subprocess.STDOUT).decode().split()[-1] + except: + tag = 'v9.5.0' # current release - name = file.name if name in assets: - msg = f'{file} missing, try downloading from https://github.com/{repo}/releases/' - redundant = False # second download option - try: # GitHub - url = f'https://github.com/{repo}/releases/download/{tag}/{name}' - print(f'Downloading {url} to {file}...') - torch.hub.download_url_to_file(url, file) - assert file.exists() and file.stat().st_size > 1E6 # check - except Exception as e: # GCP - print(f'Download error: {e}') - assert redundant, 'No secondary mirror' - url = f'https://storage.googleapis.com/{repo}/ckpt/{name}' - print(f'Downloading {url} to {file}...') - os.system(f'curl -L {url} -o {file}') # torch.hub.download_url_to_file(url, weights) - finally: - if not file.exists() or file.stat().st_size < 1E6: # check - file.unlink(missing_ok=True) # remove partial downloads - print(f'ERROR: Download failure: {msg}') - print('') - return + safe_download(file, + url=f'https://github.com/{repo}/releases/download/{tag}/{name}', + # url2=f'https://storage.googleapis.com/{repo}/ckpt/{name}', # backup url (optional) + min_bytes=1E5, + error_msg=f'{file} missing, try downloading from https://github.com/{repo}/releases/') + + return str(file) def gdrive_download(id='16TiPfZj7htmTyhntwcZyEEAejOUxuT6m', file='tmp.zip'): diff --git a/utils/metrics.py b/utils/metrics.py index 666b8c7ec1..323c84b6c8 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -145,7 +145,7 @@ def process_batch(self, detections, labels): for i, gc in enumerate(gt_classes): j = m0 == i if n and sum(j) == 1: - self.matrix[gc, detection_classes[m1[j]]] += 1 # correct + self.matrix[detection_classes[m1[j]], gc] += 1 # correct else: self.matrix[self.nc, gc] += 1 # background FP diff --git a/utils/plots.py b/utils/plots.py index 8b90bd8d07..2ae36523f3 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -16,7 +16,6 @@ import torch import yaml from PIL import Image, ImageDraw, ImageFont -from scipy.signal import butter, filtfilt from utils.general import xywh2xyxy, xyxy2xywh from utils.metrics import fitness @@ -26,12 +25,25 @@ matplotlib.use('Agg') # for writing to files only -def color_list(): - # Return first 10 plt colors as (r,g,b) https://stackoverflow.com/questions/51350872/python-from-color-name-to-rgb - def hex2rgb(h): +class Colors: + # Ultralytics color palette https://ultralytics.com/ + def __init__(self): + # hex = matplotlib.colors.TABLEAU_COLORS.values() + hex = ('FF3838', 'FF9D97', 'FF701F', 'FFB21D', 'CFD231', '48F90A', '92CC17', '3DDB86', '1A9334', '00D4BB', + '2C99A8', '00C2FF', '344593', '6473FF', '0018EC', '8438FF', '520085', 'CB38FF', 'FF95C8', 'FF37C7') + self.palette = [self.hex2rgb('#' + c) for c in hex] + self.n = len(self.palette) + + def __call__(self, i, bgr=False): + c = self.palette[int(i) % self.n] + return (c[2], c[1], c[0]) if bgr else c + + @staticmethod + def hex2rgb(h): # rgb order (PIL) return tuple(int(h[1 + i:1 + i + 2], 16) for i in (0, 2, 4)) - return [hex2rgb(h) for h in matplotlib.colors.TABLEAU_COLORS.values()] # or BASE_ (8), CSS4_ (148), XKCD_ (949) + +colors = Colors() # create instance for 'from utils.plots import colors' def hist2d(x, y, n=100): @@ -44,6 +56,8 @@ def hist2d(x, y, n=100): def butter_lowpass_filtfilt(data, cutoff=1500, fs=50000, order=5): + from scipy.signal import butter, filtfilt + # https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy def butter_lowpass(cutoff, fs, order): nyq = 0.5 * fs @@ -54,32 +68,32 @@ def butter_lowpass(cutoff, fs, order): return filtfilt(b, a, data) # forward-backward filter -def plot_one_box(x, img, color=None, label=None, line_thickness=3): - # Plots one bounding box on image img - tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line/font thickness - color = color or [random.randint(0, 255) for _ in range(3)] +def plot_one_box(x, im, color=(128, 128, 128), label=None, line_thickness=3): + # Plots one bounding box on image 'im' using OpenCV + assert im.data.contiguous, 'Image not contiguous. Apply np.ascontiguousarray(im) to plot_on_box() input image.' + tl = line_thickness or round(0.002 * (im.shape[0] + im.shape[1]) / 2) + 1 # line/font thickness c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) - cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA) + cv2.rectangle(im, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA) if label: tf = max(tl - 1, 1) # font thickness t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 - cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) # filled - cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA) + cv2.rectangle(im, c1, c2, color, -1, cv2.LINE_AA) # filled + cv2.putText(im, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA) -def plot_one_box_PIL(box, img, color=None, label=None, line_thickness=None): - img = Image.fromarray(img) - draw = ImageDraw.Draw(img) - line_thickness = line_thickness or max(int(min(img.size) / 200), 2) - draw.rectangle(box, width=line_thickness, outline=tuple(color)) # plot +def plot_one_box_PIL(box, im, color=(128, 128, 128), label=None, line_thickness=None): + # Plots one bounding box on image 'im' using PIL + im = Image.fromarray(im) + draw = ImageDraw.Draw(im) + line_thickness = line_thickness or max(int(min(im.size) / 200), 2) + draw.rectangle(box, width=line_thickness, outline=color) # plot if label: - fontsize = max(round(max(img.size) / 40), 12) - font = ImageFont.truetype("Arial.ttf", fontsize) + font = ImageFont.truetype("Arial.ttf", size=max(round(max(im.size) / 40), 12)) txt_width, txt_height = font.getsize(label) - draw.rectangle([box[0], box[1] - txt_height + 4, box[0] + txt_width, box[1]], fill=tuple(color)) + draw.rectangle([box[0], box[1] - txt_height + 4, box[0] + txt_width, box[1]], fill=color) draw.text((box[0], box[1] - txt_height + 1), label, fill=(255, 255, 255), font=font) - return np.asarray(img) + return np.asarray(im) def plot_wh_methods(): # from utils.plots import *; plot_wh_methods() @@ -135,7 +149,6 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max h = math.ceil(scale_factor * h) w = math.ceil(scale_factor * w) - colors = color_list() # list of colors mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) # init for i, img in enumerate(images): if i == max_subplots: # if last batch has fewer images than we expect @@ -166,7 +179,7 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max boxes[[1, 3]] += block_y for j, box in enumerate(boxes.T): cls = int(classes[j]) - color = colors[cls % len(colors)] + color = colors(cls) cls = names[cls] if names else cls if labels or conf[j] > 0.25: # 0.25 conf thresh label = '%s' % cls if labels else '%s %.1f' % (cls, conf[j]) @@ -274,7 +287,6 @@ def plot_labels(labels, names=(), save_dir=Path(''), loggers=None): print('Plotting labels... ') c, b = labels[:, 0], labels[:, 1:].transpose() # classes, boxes nc = int(c.max() + 1) # number of classes - colors = color_list() x = pd.DataFrame(b.transpose(), columns=['x', 'y', 'width', 'height']) # seaborn correlogram @@ -285,7 +297,8 @@ def plot_labels(labels, names=(), save_dir=Path(''), loggers=None): # matplotlib labels matplotlib.use('svg') # faster ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True)[1].ravel() - ax[0].hist(c, bins=np.linspace(0, nc, nc + 1) - 0.5, rwidth=0.8) + y = ax[0].hist(c, bins=np.linspace(0, nc, nc + 1) - 0.5, rwidth=0.8) + # [y[2].patches[i].set_color([x / 255 for x in colors(i)]) for i in range(nc)] # update colors bug #3195 ax[0].set_ylabel('instances') if 0 < len(names) < 30: ax[0].set_xticks(range(len(names))) @@ -300,7 +313,7 @@ def plot_labels(labels, names=(), save_dir=Path(''), loggers=None): labels[:, 1:] = xywh2xyxy(labels[:, 1:]) * 2000 img = Image.fromarray(np.ones((2000, 2000, 3), dtype=np.uint8) * 255) for cls, *box in labels[:1000]: - ImageDraw.Draw(img).rectangle(box, width=1, outline=colors[int(cls) % 10]) # plot + ImageDraw.Draw(img).rectangle(box, width=1, outline=colors(cls)) # plot ax[1].imshow(img) ax[1].axis('off') @@ -321,7 +334,7 @@ def plot_labels(labels, names=(), save_dir=Path(''), loggers=None): def plot_evolution(yaml_file='data/hyp.finetune.yaml'): # from utils.plots import *; plot_evolution() # Plot hyperparameter evolution results in evolve.txt with open(yaml_file) as f: - hyp = yaml.load(f, Loader=yaml.SafeLoader) + hyp = yaml.safe_load(f) x = np.loadtxt('evolve.txt', ndmin=2) f = fitness(x) # weights = (f - f.min()) ** 2 # for weighted results diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 6535b2ab1b..9114112a7b 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -72,11 +72,12 @@ def select_device(device='', batch_size=None): cuda = not cpu and torch.cuda.is_available() if cuda: - n = torch.cuda.device_count() - if n > 1 and batch_size: # check that batch_size is compatible with device_count + devices = device.split(',') if device else range(torch.cuda.device_count()) # i.e. 0,1,6,7 + n = len(devices) # device count + if n > 1 and batch_size: # check batch_size is divisible by device_count assert batch_size % n == 0, f'batch-size {batch_size} not multiple of GPU count {n}' space = ' ' * len(s) - for i, d in enumerate(device.split(',') if device else range(n)): + for i, d in enumerate(devices): p = torch.cuda.get_device_properties(i) s += f"{'' if i == 0 else space}CUDA:{d} ({p.name}, {p.total_memory / 1024 ** 2}MB)\n" # bytes to MB else: @@ -133,9 +134,15 @@ def profile(x, ops, n=100, device=None): def is_parallel(model): + # Returns True if model is of type DP or DDP return type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) +def de_parallel(model): + # De-parallelize a model: returns single-GPU model if model is of type DP or DDP + return model.module if is_parallel(model) else model + + def intersect_dicts(da, db, exclude=()): # Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values return {k: v for k, v in da.items() if k in db and not any(x in k for x in exclude) and v.shape == db[k].shape} diff --git a/utils/wandb_logging/log_dataset.py b/utils/wandb_logging/log_dataset.py index d7a521f141..fae76b048f 100644 --- a/utils/wandb_logging/log_dataset.py +++ b/utils/wandb_logging/log_dataset.py @@ -9,7 +9,7 @@ def create_dataset_artifact(opt): with open(opt.data) as f: - data = yaml.load(f, Loader=yaml.SafeLoader) # data dict + data = yaml.safe_load(f) # data dict logger = WandbLogger(opt, '', None, data, job_type='Dataset Creation') @@ -17,7 +17,7 @@ def create_dataset_artifact(opt): parser = argparse.ArgumentParser() parser.add_argument('--data', type=str, default='data/coco128.yaml', help='data.yaml path') parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') - parser.add_argument('--project', type=str, default='YOLOv5', help='name of W&B Project') + parser.add_argument('--project', type=str, default='YOLOv3', help='name of W&B Project') opt = parser.parse_args() opt.resume = False # Explicitly disallow resume check for dataset upload job diff --git a/utils/wandb_logging/wandb_utils.py b/utils/wandb_logging/wandb_utils.py index d8f50ae8a8..12bd320cc3 100644 --- a/utils/wandb_logging/wandb_utils.py +++ b/utils/wandb_logging/wandb_utils.py @@ -1,3 +1,4 @@ +"""Utilities and tools for tracking runs with Weights & Biases.""" import json import sys from pathlib import Path @@ -9,7 +10,7 @@ sys.path.append(str(Path(__file__).parent.parent.parent)) # add utils/ to path from utils.datasets import LoadImagesAndLabels from utils.datasets import img2label_paths -from utils.general import colorstr, xywh2xyxy, check_dataset +from utils.general import colorstr, xywh2xyxy, check_dataset, check_file try: import wandb @@ -35,8 +36,9 @@ def get_run_info(run_path): run_path = Path(remove_prefix(run_path, WANDB_ARTIFACT_PREFIX)) run_id = run_path.stem project = run_path.parent.stem + entity = run_path.parent.parent.stem model_artifact_name = 'run_' + run_id + '_model' - return run_id, project, model_artifact_name + return entity, project, run_id, model_artifact_name def check_wandb_resume(opt): @@ -44,9 +46,9 @@ def check_wandb_resume(opt): if isinstance(opt.resume, str): if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): if opt.global_rank not in [-1, 0]: # For resuming DDP runs - run_id, project, model_artifact_name = get_run_info(opt.resume) + entity, project, run_id, model_artifact_name = get_run_info(opt.resume) api = wandb.Api() - artifact = api.artifact(project + '/' + model_artifact_name + ':latest') + artifact = api.artifact(entity + '/' + project + '/' + model_artifact_name + ':latest') modeldir = artifact.download() opt.weights = str(Path(modeldir) / "last.pt") return True @@ -54,8 +56,8 @@ def check_wandb_resume(opt): def process_wandb_config_ddp_mode(opt): - with open(opt.data) as f: - data_dict = yaml.load(f, Loader=yaml.SafeLoader) # data dict + with open(check_file(opt.data)) as f: + data_dict = yaml.safe_load(f) # data dict train_dir, val_dir = None, None if isinstance(data_dict['train'], str) and data_dict['train'].startswith(WANDB_ARTIFACT_PREFIX): api = wandb.Api() @@ -73,11 +75,23 @@ def process_wandb_config_ddp_mode(opt): if train_dir or val_dir: ddp_data_path = str(Path(val_dir) / 'wandb_local_data.yaml') with open(ddp_data_path, 'w') as f: - yaml.dump(data_dict, f) + yaml.safe_dump(data_dict, f) opt.data = ddp_data_path class WandbLogger(): + """Log training runs, datasets, models, and predictions to Weights & Biases. + + This logger sends information to W&B at wandb.ai. By default, this information + includes hyperparameters, system configuration and metrics, model metrics, + and basic data metrics and analyses. + + By providing additional command line arguments to train.py, datasets, + models and predictions can also be logged. + + For more on how this logger is used, see the Weights & Biases documentation: + https://docs.wandb.com/guides/integrations/yolov5 + """ def __init__(self, opt, name, run_id, data_dict, job_type='Training'): # Pre-training routine -- self.job_type = job_type @@ -85,16 +99,17 @@ def __init__(self, opt, name, run_id, data_dict, job_type='Training'): # It's more elegant to stick to 1 wandb.init call, but useful config data is overwritten in the WandbLogger's wandb.init call if isinstance(opt.resume, str): # checks resume from artifact if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): - run_id, project, model_artifact_name = get_run_info(opt.resume) + entity, project, run_id, model_artifact_name = get_run_info(opt.resume) model_artifact_name = WANDB_ARTIFACT_PREFIX + model_artifact_name assert wandb, 'install wandb to resume wandb runs' # Resume wandb-artifact:// runs here| workaround for not overwriting wandb.config - self.wandb_run = wandb.init(id=run_id, project=project, resume='allow') + self.wandb_run = wandb.init(id=run_id, project=project, entity=entity, resume='allow') opt.resume = model_artifact_name elif self.wandb: self.wandb_run = wandb.init(config=opt, resume="allow", - project='YOLOv5' if opt.project == 'runs/train' else Path(opt.project).stem, + project='YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem, + entity=opt.entity, name=name, job_type=job_type, id=run_id) if not wandb.run else wandb.run @@ -110,17 +125,17 @@ def __init__(self, opt, name, run_id, data_dict, job_type='Training'): self.data_dict = self.check_and_upload_dataset(opt) else: prefix = colorstr('wandb: ') - print(f"{prefix}Install Weights & Biases for YOLOv5 logging with 'pip install wandb' (recommended)") + print(f"{prefix}Install Weights & Biases for YOLOv3 logging with 'pip install wandb' (recommended)") def check_and_upload_dataset(self, opt): assert wandb, 'Install wandb to upload dataset' check_dataset(self.data_dict) - config_path = self.log_dataset_artifact(opt.data, + config_path = self.log_dataset_artifact(check_file(opt.data), opt.single_cls, - 'YOLOv5' if opt.project == 'runs/train' else Path(opt.project).stem) + 'YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem) print("Created dataset config file ", config_path) with open(config_path) as f: - wandb_data_dict = yaml.load(f, Loader=yaml.SafeLoader) + wandb_data_dict = yaml.safe_load(f) return wandb_data_dict def setup_training(self, opt, data_dict): @@ -158,7 +173,8 @@ def setup_training(self, opt, data_dict): def download_dataset_artifact(self, path, alias): if isinstance(path, str) and path.startswith(WANDB_ARTIFACT_PREFIX): - dataset_artifact = wandb.use_artifact(remove_prefix(path, WANDB_ARTIFACT_PREFIX) + ":" + alias) + artifact_path = Path(remove_prefix(path, WANDB_ARTIFACT_PREFIX) + ":" + alias) + dataset_artifact = wandb.use_artifact(artifact_path.as_posix()) assert dataset_artifact is not None, "'Error: W&B dataset artifact doesn\'t exist'" datadir = dataset_artifact.download() return datadir, dataset_artifact @@ -171,8 +187,8 @@ def download_model_artifact(self, opt): modeldir = model_artifact.download() epochs_trained = model_artifact.metadata.get('epochs_trained') total_epochs = model_artifact.metadata.get('total_epochs') - assert epochs_trained < total_epochs, 'training to %g epochs is finished, nothing to resume.' % ( - total_epochs) + is_finished = total_epochs is None + assert not is_finished, 'training is finished, can only resume incomplete runs.' return modeldir, model_artifact return None, None @@ -187,18 +203,18 @@ def log_model(self, path, opt, epoch, fitness_score, best_model=False): }) model_artifact.add_file(str(path / 'last.pt'), name='last.pt') wandb.log_artifact(model_artifact, - aliases=['latest', 'epoch ' + str(self.current_epoch), 'best' if best_model else '']) + aliases=['latest', 'last', 'epoch ' + str(self.current_epoch), 'best' if best_model else '']) print("Saving model artifact on epoch ", epoch + 1) def log_dataset_artifact(self, data_file, single_cls, project, overwrite_config=False): with open(data_file) as f: - data = yaml.load(f, Loader=yaml.SafeLoader) # data dict + data = yaml.safe_load(f) # data dict nc, names = (1, ['item']) if single_cls else (int(data['nc']), data['names']) names = {k: v for k, v in enumerate(names)} # to index dictionary self.train_artifact = self.create_dataset_table(LoadImagesAndLabels( - data['train']), names, name='train') if data.get('train') else None + data['train'], rect=True, batch_size=1), names, name='train') if data.get('train') else None self.val_artifact = self.create_dataset_table(LoadImagesAndLabels( - data['val']), names, name='val') if data.get('val') else None + data['val'], rect=True, batch_size=1), names, name='val') if data.get('val') else None if data.get('train'): data['train'] = WANDB_ARTIFACT_PREFIX + str(Path(project) / 'train') if data.get('val'): @@ -206,7 +222,7 @@ def log_dataset_artifact(self, data_file, single_cls, project, overwrite_config= path = data_file if overwrite_config else '_wandb.'.join(data_file.rsplit('.', 1)) # updated data.yaml path data.pop('download', None) with open(path, 'w') as f: - yaml.dump(data, f) + yaml.safe_dump(data, f) if self.job_type == 'Training': # builds correct artifact pipeline graph self.wandb_run.use_artifact(self.val_artifact) @@ -243,16 +259,12 @@ def create_dataset_table(self, dataset, class_to_id, name='dataset'): table = wandb.Table(columns=["id", "train_image", "Classes", "name"]) class_set = wandb.Classes([{'id': id, 'name': name} for id, name in class_to_id.items()]) for si, (img, labels, paths, shapes) in enumerate(tqdm(dataset)): - height, width = shapes[0] - labels[:, 2:] = (xywh2xyxy(labels[:, 2:].view(-1, 4))) * torch.Tensor([width, height, width, height]) box_data, img_classes = [], {} - for cls, *xyxy in labels[:, 1:].tolist(): + for cls, *xywh in labels[:, 1:].tolist(): cls = int(cls) - box_data.append({"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, + box_data.append({"position": {"middle": [xywh[0], xywh[1]], "width": xywh[2], "height": xywh[3]}, "class_id": cls, - "box_caption": "%s" % (class_to_id[cls]), - "scores": {"acc": 1}, - "domain": "pixel"}) + "box_caption": "%s" % (class_to_id[cls])}) img_classes[cls] = class_to_id[cls] boxes = {"ground_truth": {"box_data": box_data, "class_labels": class_to_id}} # inference-space table.add_data(si, wandb.Image(paths, classes=class_set, boxes=boxes), json.dumps(img_classes), @@ -294,7 +306,7 @@ def end_epoch(self, best_result=False): if self.result_artifact: train_results = wandb.JoinedTable(self.val_table, self.result_table, "id") self.result_artifact.add(train_results, 'result') - wandb.log_artifact(self.result_artifact, aliases=['latest', 'epoch ' + str(self.current_epoch), + wandb.log_artifact(self.result_artifact, aliases=['latest', 'last', 'epoch ' + str(self.current_epoch), ('best' if best_result else '')]) self.result_table = wandb.Table(["epoch", "id", "prediction", "avg_confidence"]) self.result_artifact = wandb.Artifact("run_" + wandb.run.id + "_progress", "evaluation") From 044eb9142b13796abfe3634070eaa27c60c167b3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 30 May 2021 19:40:48 +0200 Subject: [PATCH 0890/1185] Update README.md (#1777) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 257d0f6462..04012af4d6 100755 --- a/README.md +++ b/README.md @@ -152,9 +152,9 @@ Ultralytics is a U.S.-based particle physics and AI startup with over 6 years of - **Edge AI** integrated into custom iOS and Android apps for realtime **30 FPS video inference.** - **Custom data training**, hyperparameter evolution, and model exportation to any destination. -For business inquiries and professional support requests please visit us at https://www.ultralytics.com. +For business inquiries and professional support requests please visit us at https://ultralytics.com. ## Contact -**Issues should be raised directly in the repository.** For business inquiries or professional support requests please visit https://www.ultralytics.com or email Glenn Jocher at glenn.jocher@ultralytics.com. +**Issues should be raised directly in the repository.** For business inquiries or professional support requests please visit https://ultralytics.com or email Glenn Jocher at glenn.jocher@ultralytics.com. From ab7ff9dd4c8b8e5a2c282fee93e975887a91ff7b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 31 May 2021 10:40:13 +0200 Subject: [PATCH 0891/1185] Revert "`cv2.imread(img, -1)` for IMREAD_UNCHANGED" (#1778) --- utils/datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/datasets.py b/utils/datasets.py index 481b79a901..35aa430aaa 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -181,7 +181,7 @@ def __next__(self): else: # Read image self.count += 1 - img0 = cv2.imread(path, -1) # BGR (-1 is IMREAD_UNCHANGED) + img0 = cv2.imread(path) # BGR assert img0 is not None, 'Image Not Found ' + path print(f'image {self.count}/{self.nf} {path}: ', end='') From 66e54d3d2cc0e98f63d6447d578f15ce77016f6e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 6 Jun 2021 18:50:08 +0200 Subject: [PATCH 0892/1185] Update stale.yml (#1784) --- .github/workflows/stale.yml | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 0a094e237b..e9adff9899 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -10,8 +10,26 @@ jobs: - uses: actions/stale@v3 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' - stale-pr-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' + stale-issue-message: | + 👋 Hello, this issue has been automatically marked as stale because it has not had recent activity. Please note it will be closed if no further activity occurs. + + Access additional [YOLOv3](https://ultralytics.com/yolov5) 🚀 resources: + - **Wiki** – https://github.com/ultralytics/yolov3/wiki + - **Tutorials** – https://github.com/ultralytics/yolov3#tutorials + - **Docs** – https://docs.ultralytics.com + + Access additional [Ultralytics](https://ultralytics.com) ⚡ resources: + - **Ultralytics HUB** – https://ultralytics.com/pricing + - **Vision API** – https://ultralytics.com/yolov5 + - **About Us** – https://ultralytics.com/about + - **Join Our Team** – https://ultralytics.com/work + - **Contact Us** – https://ultralytics.com/contact + + Feel free to inform us of any other **issues** you discover or **feature requests** that come to mind in the future. Pull Requests (PRs) are also always welcomed! + + Thank you for your contributions to YOLOv3 🚀 and Vision AI ⭐! + + stale-pr-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions YOLOv3 🚀 and Vision AI ⭐.' days-before-stale: 30 days-before-close: 5 exempt-issue-labels: 'documentation,tutorial' From 1be31704c9c690929e4f6e6d950f40755ef2dcdc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 21:27:16 +0200 Subject: [PATCH 0893/1185] Bump pip from 18.1 to 19.2 in /utils/google_app_engine (#1787) Bumps [pip](https://github.com/pypa/pip) from 18.1 to 19.2. - [Release notes](https://github.com/pypa/pip/releases) - [Changelog](https://github.com/pypa/pip/blob/main/NEWS.rst) - [Commits](https://github.com/pypa/pip/compare/18.1...19.2) --- updated-dependencies: - dependency-name: pip dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- utils/google_app_engine/additional_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/google_app_engine/additional_requirements.txt b/utils/google_app_engine/additional_requirements.txt index 5fcc30524a..2f81c8b400 100644 --- a/utils/google_app_engine/additional_requirements.txt +++ b/utils/google_app_engine/additional_requirements.txt @@ -1,4 +1,4 @@ # add these requirements in your app on top of the existing ones -pip==18.1 +pip==19.2 Flask==1.0.2 gunicorn==19.9.0 From 7eb23e3c1d387cdcefbad266046af369a9f40399 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 14 Nov 2021 22:22:59 +0100 Subject: [PATCH 0894/1185] YOLOv5 v6.0 compatibility update (#1857) * Initial commit * Initial commit * Cleanup * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix precommit errors * Remove TF builds from CI * export last.pt * Created using Colaboratory * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .dockerignore | 10 +- .github/ISSUE_TEMPLATE/bug-report.md | 55 -- .github/ISSUE_TEMPLATE/bug-report.yml | 85 ++ .github/ISSUE_TEMPLATE/config.yml | 8 + .github/ISSUE_TEMPLATE/feature-request.md | 27 - .github/ISSUE_TEMPLATE/feature-request.yml | 50 + .github/ISSUE_TEMPLATE/question.md | 13 - .github/ISSUE_TEMPLATE/question.yml | 33 + .github/dependabot.yml | 31 +- .github/workflows/ci-testing.yml | 48 +- .github/workflows/codeql-analysis.yml | 66 +- .github/workflows/greetings.yml | 29 +- .github/workflows/rebase.yml | 10 +- .github/workflows/stale.yml | 10 +- .gitignore | 20 +- .pre-commit-config.yaml | 66 ++ CONTRIBUTING.md | 94 ++ Dockerfile | 29 +- LICENSE | 2 +- README.md | 351 +++++--- data/Argoverse.yaml | 67 ++ data/GlobalWheat2020.yaml | 68 +- data/SKU-110K.yaml | 38 +- data/VisDrone.yaml | 32 +- data/argoverse_hd.yaml | 21 - data/coco.yaml | 65 +- data/coco128.yaml | 48 +- data/hyp.finetune.yaml | 38 - data/hyp.finetune_objects365.yaml | 28 - data/hyps/hyp.scratch-high.yaml | 34 + data/hyps/hyp.scratch-low.yaml | 34 + data/hyps/hyp.scratch-med.yaml | 34 + data/{ => hyps}/hyp.scratch.yaml | 5 +- data/objects365.yaml | 174 ++-- data/scripts/download_weights.sh | 18 + data/scripts/get_argoverse_hd.sh | 61 -- data/scripts/get_coco.sh | 22 +- data/scripts/get_coco128.sh | 20 +- data/scripts/get_voc.sh | 116 --- data/voc.yaml | 91 +- data/xView.yaml | 102 +++ detect.py | 252 ++++-- export.py | 369 ++++++++ hubconf.py | 46 +- models/common.py | 378 ++++++-- models/experimental.py | 84 +- models/export.py | 145 --- models/tf.py | 465 ++++++++++ models/yolo.py | 204 +++-- models/yolov3-spp.yaml | 6 +- models/yolov3-tiny.yaml | 6 +- models/yolov3.yaml | 6 +- requirements.txt | 30 +- setup.cfg | 51 ++ test.py | 349 ------- train.py | 658 +++++++------- tutorial.ipynb | 847 +++++++---------- utils/__init__.py | 18 + utils/activations.py | 7 +- utils/augmentations.py | 277 ++++++ utils/autoanchor.py | 91 +- utils/autobatch.py | 57 ++ utils/aws/mime.sh | 26 - utils/aws/resume.py | 37 - utils/aws/userdata.sh | 27 - utils/callbacks.py | 76 ++ utils/datasets.py | 851 +++++++++--------- utils/{google_utils.py => downloads.py} | 34 +- utils/flask_rest_api/README.md | 68 -- utils/flask_rest_api/example_request.py | 13 - utils/flask_rest_api/restapi.py | 37 - utils/general.py | 564 +++++++----- utils/google_app_engine/Dockerfile | 25 - .../additional_requirements.txt | 4 - utils/google_app_engine/app.yaml | 14 - utils/loggers/__init__.py | 156 ++++ utils/loggers/wandb/README.md | 147 +++ utils/{aws => loggers/wandb}/__init__.py | 0 .../wandb}/log_dataset.py | 13 +- utils/loggers/wandb/sweep.py | 41 + utils/loggers/wandb/sweep.yaml | 143 +++ utils/loggers/wandb/wandb_utils.py | 532 +++++++++++ utils/loss.py | 42 +- utils/metrics.py | 136 ++- utils/plots.py | 443 ++++----- utils/torch_utils.py | 188 ++-- utils/wandb_logging/__init__.py | 0 utils/wandb_logging/wandb_utils.py | 318 ------- val.py | 367 ++++++++ weights/download_weights.sh | 12 - 90 files changed, 6655 insertions(+), 4158 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug-report.md create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature-request.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml delete mode 100644 .github/ISSUE_TEMPLATE/question.md create mode 100644 .github/ISSUE_TEMPLATE/question.yml create mode 100644 .pre-commit-config.yaml create mode 100644 CONTRIBUTING.md mode change 100755 => 100644 README.md create mode 100644 data/Argoverse.yaml delete mode 100644 data/argoverse_hd.yaml delete mode 100644 data/hyp.finetune.yaml delete mode 100644 data/hyp.finetune_objects365.yaml create mode 100644 data/hyps/hyp.scratch-high.yaml create mode 100644 data/hyps/hyp.scratch-low.yaml create mode 100644 data/hyps/hyp.scratch-med.yaml rename data/{ => hyps}/hyp.scratch.yaml (90%) create mode 100755 data/scripts/download_weights.sh delete mode 100644 data/scripts/get_argoverse_hd.sh delete mode 100644 data/scripts/get_voc.sh create mode 100644 data/xView.yaml create mode 100644 export.py delete mode 100644 models/export.py create mode 100644 models/tf.py create mode 100644 setup.cfg delete mode 100644 test.py create mode 100644 utils/augmentations.py create mode 100644 utils/autobatch.py delete mode 100644 utils/aws/mime.sh delete mode 100644 utils/aws/resume.py delete mode 100644 utils/aws/userdata.sh create mode 100644 utils/callbacks.py rename utils/{google_utils.py => downloads.py} (83%) delete mode 100644 utils/flask_rest_api/README.md delete mode 100644 utils/flask_rest_api/example_request.py delete mode 100644 utils/flask_rest_api/restapi.py delete mode 100644 utils/google_app_engine/Dockerfile delete mode 100644 utils/google_app_engine/additional_requirements.txt delete mode 100644 utils/google_app_engine/app.yaml create mode 100644 utils/loggers/__init__.py create mode 100644 utils/loggers/wandb/README.md rename utils/{aws => loggers/wandb}/__init__.py (100%) rename utils/{wandb_logging => loggers/wandb}/log_dataset.py (61%) create mode 100644 utils/loggers/wandb/sweep.py create mode 100644 utils/loggers/wandb/sweep.yaml create mode 100644 utils/loggers/wandb/wandb_utils.py delete mode 100644 utils/wandb_logging/__init__.py delete mode 100644 utils/wandb_logging/wandb_utils.py create mode 100644 val.py delete mode 100755 weights/download_weights.sh diff --git a/.dockerignore b/.dockerignore index 3c6b6ab02e..6c2f2b9b77 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,17 +8,21 @@ coco storage.googleapis.com data/samples/* -**/results*.txt +**/results*.csv *.jpg # Neural Network weights ----------------------------------------------------------------------------------------------- -**/*.weights **/*.pt **/*.pth **/*.onnx **/*.mlmodel **/*.torchscript - +**/*.torchscript.pt +**/*.tflite +**/*.h5 +**/*.pb +*_saved_model/ +*_web_model/ # Below Copied From .gitignore ----------------------------------------------------------------------------------------- # Below Copied From .gitignore ----------------------------------------------------------------------------------------- diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md deleted file mode 100644 index 3f7d83a407..0000000000 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -name: "🐛 Bug report" -about: Create a report to help us improve -title: '' -labels: bug -assignees: '' - ---- - -Before submitting a bug report, please be aware that your issue **must be reproducible** with all of the following, otherwise it is non-actionable, and we can not help you: - - **Current repo**: run `git fetch && git status -uno` to check and `git pull` to update repo - - **Common dataset**: coco.yaml or coco128.yaml - - **Common environment**: Colab, Google Cloud, or Docker image. See https://github.com/ultralytics/yolov3#environments - -If this is a custom dataset/training question you **must include** your `train*.jpg`, `test*.jpg` and `results.png` figures, or we can not help you. You can generate these with `utils.plot_results()`. - - -## 🐛 Bug -A clear and concise description of what the bug is. - - -## To Reproduce (REQUIRED) - -Input: -``` -import torch - -a = torch.tensor([5]) -c = a / 0 -``` - -Output: -``` -Traceback (most recent call last): - File "/Users/glennjocher/opt/anaconda3/envs/env1/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3331, in run_code - exec(code_obj, self.user_global_ns, self.user_ns) - File "", line 5, in - c = a / 0 -RuntimeError: ZeroDivisionError -``` - - -## Expected behavior -A clear and concise description of what you expected to happen. - - -## Environment -If applicable, add screenshots to help explain your problem. - - - OS: [e.g. Ubuntu] - - GPU [e.g. 2080 Ti] - - -## Additional context -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000000..affe6aae2b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,85 @@ +name: 🐛 Bug Report +# title: " " +description: Problems with YOLOv3 +labels: [bug, triage] +body: + - type: markdown + attributes: + value: | + Thank you for submitting a YOLOv3 🐛 Bug Report! + + - type: checkboxes + attributes: + label: Search before asking + description: > + Please search the [issues](https://github.com/ultralytics/yolov3/issues) to see if a similar bug report already exists. + options: + - label: > + I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov3/issues) and found no similar bug report. + required: true + + - type: dropdown + attributes: + label: YOLOv3 Component + description: | + Please select the part of YOLOv3 where you found the bug. + multiple: true + options: + - "Training" + - "Validation" + - "Detection" + - "Export" + - "PyTorch Hub" + - "Multi-GPU" + - "Evolution" + - "Integrations" + - "Other" + validations: + required: false + + - type: textarea + attributes: + label: Bug + description: Provide console output with error messages and/or screenshots of the bug. + placeholder: | + 💡 ProTip! Include as much information as possible (screenshots, logs, tracebacks etc.) to receive the most helpful response. + validations: + required: true + + - type: textarea + attributes: + label: Environment + description: Please specify the software and hardware you used to produce the bug. + placeholder: | + - YOLO: YOLOv3 🚀 v6.0-67-g60e42e1 torch 1.9.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB) + - OS: Ubuntu 20.04 + - Python: 3.9.0 + validations: + required: false + + - type: textarea + attributes: + label: Minimal Reproducible Example + description: > + When asking a question, people will be better able to provide help if you provide code that they can easily understand and use to **reproduce** the problem. + This is referred to by community members as creating a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). + placeholder: | + ``` + # Code to reproduce your issue here + ``` + validations: + required: false + + - type: textarea + attributes: + label: Additional + description: Anything else you would like to share? + + - type: checkboxes + attributes: + label: Are you willing to submit a PR? + description: > + (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. + See the YOLOv3 [Contributing Guide](https://github.com/ultralytics/yolov3/blob/master/CONTRIBUTING.md) to get started. + options: + - label: Yes I'd like to help by submitting a PR! diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..02be0529fc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: Slack + url: https://join.slack.com/t/ultralytics/shared_invite/zt-w29ei8bp-jczz7QYUmDtgo6r6KcMIAg + about: Ask on Ultralytics Slack Forum + - name: Stack Overflow + url: https://stackoverflow.com/search?q=YOLOv3 + about: Ask on Stack Overflow with 'YOLOv3' tag diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md deleted file mode 100644 index 87db3eacbf..0000000000 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: "🚀 Feature request" -about: Suggest an idea for this project -title: '' -labels: enhancement -assignees: '' - ---- - -## 🚀 Feature - - -## Motivation - - - -## Pitch - - - -## Alternatives - - - -## Additional context - - diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 0000000000..53cf234475 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,50 @@ +name: 🚀 Feature Request +description: Suggest a YOLOv3 idea +# title: " " +labels: [enhancement] +body: + - type: markdown + attributes: + value: | + Thank you for submitting a YOLOv3 🚀 Feature Request! + + - type: checkboxes + attributes: + label: Search before asking + description: > + Please search the [issues](https://github.com/ultralytics/yolov3/issues) to see if a similar feature request already exists. + options: + - label: > + I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov3/issues) and found no similar feature requests. + required: true + + - type: textarea + attributes: + label: Description + description: A short description of your feature. + placeholder: | + What new feature would you like to see in YOLOv3? + validations: + required: true + + - type: textarea + attributes: + label: Use case + description: | + Describe the use case of your feature request. It will help us understand and prioritize the feature request. + placeholder: | + How would this feature be used, and who would use it? + + - type: textarea + attributes: + label: Additional + description: Anything else you would like to share? + + - type: checkboxes + attributes: + label: Are you willing to submit a PR? + description: > + (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. + See the YOLOv3 [Contributing Guide](https://github.com/ultralytics/yolov3/blob/master/CONTRIBUTING.md) to get started. + options: + - label: Yes I'd like to help by submitting a PR! diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index 2c22aea70a..0000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: "❓Question" -about: Ask a general question -title: '' -labels: question -assignees: '' - ---- - -## ❔Question - - -## Additional context diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml new file mode 100644 index 0000000000..decb214859 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -0,0 +1,33 @@ +name: ❓ Question +description: Ask a YOLOv3 question +# title: " " +labels: [question] +body: + - type: markdown + attributes: + value: | + Thank you for asking a YOLOv3 ❓ Question! + + - type: checkboxes + attributes: + label: Search before asking + description: > + Please search the [issues](https://github.com/ultralytics/yolov3/issues) and [discussions](https://github.com/ultralytics/yolov3/discussions) to see if a similar question already exists. + options: + - label: > + I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov3/issues) and [discussions](https://github.com/ultralytics/yolov3/discussions) and found no similar questions. + required: true + + - type: textarea + attributes: + label: Question + description: What is your question? + placeholder: | + 💡 ProTip! Include as much information as possible (screenshots, logs, tracebacks etc.) to receive the most helpful response. + validations: + required: true + + - type: textarea + attributes: + label: Additional + description: Anything else you would like to share? diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9910689197..c1b3d5d514 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,12 +1,23 @@ version: 2 updates: -- package-ecosystem: pip - directory: "/" - schedule: - interval: weekly - time: "04:00" - open-pull-requests-limit: 10 - reviewers: - - glenn-jocher - labels: - - dependencies + - package-ecosystem: pip + directory: "/" + schedule: + interval: weekly + time: "04:00" + open-pull-requests-limit: 10 + reviewers: + - glenn-jocher + labels: + - dependencies + + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + time: "04:00" + open-pull-requests-limit: 5 + reviewers: + - glenn-jocher + labels: + - dependencies diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 77ac2c3f35..e777173374 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -1,6 +1,8 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + name: CI CPU testing -on: # https://help.github.com/en/actions/reference/events-that-trigger-workflows +on: # https://help.github.com/en/actions/reference/events-that-trigger-workflows push: branches: [ master ] pull_request: @@ -16,9 +18,9 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - python-version: [3.8] - model: ['yolov3-tiny'] # models to test + os: [ ubuntu-latest, macos-latest, windows-latest ] + python-version: [ 3.9 ] + model: [ 'yolov3-tiny' ] # models to test # Timeout: https://stackoverflow.com/a/59076067/4521646 timeout-minutes: 50 @@ -37,23 +39,27 @@ jobs: python -c "from pip._internal.locations import USER_CACHE_DIR; print('::set-output name=dir::' + USER_CACHE_DIR)" - name: Cache pip - uses: actions/cache@v1 + uses: actions/cache@v2.1.6 with: path: ${{ steps.pip-cache.outputs.dir }} key: ${{ runner.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('requirements.txt') }} restore-keys: | ${{ runner.os }}-${{ matrix.python-version }}-pip- + # Known Keras 2.7.0 issue: https://github.com/ultralytics/yolov5/pull/5486 - name: Install dependencies run: | python -m pip install --upgrade pip pip install -qr requirements.txt -f https://download.pytorch.org/whl/cpu/torch_stable.html - pip install -q onnx + pip install -q onnx tensorflow-cpu keras==2.6.0 # wandb # extras python --version pip --version pip list shell: bash + # - name: W&B login + # run: wandb login 345011b3fb26dc8337fd9b20e53857c1d403f2aa + - name: Download data run: | # curl -L -o tmp.zip https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip @@ -63,18 +69,26 @@ jobs: - name: Tests workflow run: | # export PYTHONPATH="$PWD" # to run '$ python *.py' files in subdirectories - di=cpu # inference devices # define device + di=cpu # device - # train - python train.py --img 128 --batch 16 --weights weights/${{ matrix.model }}.pt --cfg models/${{ matrix.model }}.yaml --epochs 1 --device $di - # detect - python detect.py --weights weights/${{ matrix.model }}.pt --device $di + # Train + python train.py --img 64 --batch 32 --weights ${{ matrix.model }}.pt --cfg ${{ matrix.model }}.yaml --epochs 1 --device $di + # Val + python val.py --img 64 --batch 32 --weights ${{ matrix.model }}.pt --device $di + python val.py --img 64 --batch 32 --weights runs/train/exp/weights/last.pt --device $di + # Detect + python detect.py --weights ${{ matrix.model }}.pt --device $di python detect.py --weights runs/train/exp/weights/last.pt --device $di - # test - python test.py --img 128 --batch 16 --weights weights/${{ matrix.model }}.pt --device $di - python test.py --img 128 --batch 16 --weights runs/train/exp/weights/last.pt --device $di - python hubconf.py # hub - python models/yolo.py --cfg models/${{ matrix.model }}.yaml # inspect - python models/export.py --img 128 --batch 1 --weights weights/${{ matrix.model }}.pt # export + # Export + python models/yolo.py --cfg ${{ matrix.model }}.yaml # build PyTorch model + # python models/tf.py --weights ${{ matrix.model }}.pt # build TensorFlow model (YOLOv3 not supported) + python export.py --img 64 --batch 1 --weights runs/train/exp/weights/last.pt --include torchscript onnx # export + # Python + python - <=1.7`. To install run: + [**Python>=3.6.0**](https://www.python.org/) with all [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) installed including [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). To get started: ```bash + $ git clone https://github.com/ultralytics/yolov3 + $ cd yolov3 $ pip install -r requirements.txt ``` ## Environments - + YOLOv3 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): - + - **Google Colab and Kaggle** notebooks with free GPU: Open In Colab Open In Kaggle - **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) - **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/AWS-Quickstart) - **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) Docker Pulls - - + + ## Status - - ![CI CPU testing](https://github.com/ultralytics/yolov3/workflows/CI%20CPU%20testing/badge.svg) - - If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 training ([train.py](https://github.com/ultralytics/yolov3/blob/master/train.py)), testing ([test.py](https://github.com/ultralytics/yolov3/blob/master/test.py)), inference ([detect.py](https://github.com/ultralytics/yolov3/blob/master/detect.py)) and export ([export.py](https://github.com/ultralytics/yolov3/blob/master/models/export.py)) on MacOS, Windows, and Ubuntu every 24 hours and on every commit. - + + CI CPU testing + + If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 training ([train.py](https://github.com/ultralytics/yolov3/blob/master/train.py)), validation ([val.py](https://github.com/ultralytics/yolov3/blob/master/val.py)), inference ([detect.py](https://github.com/ultralytics/yolov3/blob/master/detect.py)) and export ([export.py](https://github.com/ultralytics/yolov3/blob/master/export.py)) on MacOS, Windows, and Ubuntu every 24 hours and on every commit. diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml index e86c57744b..a4db1efb29 100644 --- a/.github/workflows/rebase.yml +++ b/.github/workflows/rebase.yml @@ -1,10 +1,9 @@ -name: Automatic Rebase # https://github.com/marketplace/actions/automatic-rebase +name: Automatic Rebase on: issue_comment: types: [created] - jobs: rebase: name: Rebase @@ -14,8 +13,9 @@ jobs: - name: Checkout the latest code uses: actions/checkout@v2 with: - fetch-depth: 0 + token: ${{ secrets.ACTIONS_TOKEN }} + fetch-depth: 0 # otherwise, you will fail to push refs to dest repo - name: Automatic Rebase - uses: cirrus-actions/rebase@1.3.1 + uses: cirrus-actions/rebase@1.5 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.ACTIONS_TOKEN }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index e9adff9899..330184e879 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,3 +1,5 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + name: Close stale issues on: schedule: @@ -7,19 +9,19 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v3 + - uses: actions/stale@v4 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: | 👋 Hello, this issue has been automatically marked as stale because it has not had recent activity. Please note it will be closed if no further activity occurs. - Access additional [YOLOv3](https://ultralytics.com/yolov5) 🚀 resources: + Access additional [YOLOv3](https://ultralytics.com/yolov3) 🚀 resources: - **Wiki** – https://github.com/ultralytics/yolov3/wiki - **Tutorials** – https://github.com/ultralytics/yolov3#tutorials - **Docs** – https://docs.ultralytics.com Access additional [Ultralytics](https://ultralytics.com) ⚡ resources: - - **Ultralytics HUB** – https://ultralytics.com/pricing + - **Ultralytics HUB** – https://ultralytics.com/hub - **Vision API** – https://ultralytics.com/yolov5 - **About Us** – https://ultralytics.com/about - **Join Our Team** – https://ultralytics.com/work @@ -29,7 +31,7 @@ jobs: Thank you for your contributions to YOLOv3 🚀 and Vision AI ⭐! - stale-pr-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions YOLOv3 🚀 and Vision AI ⭐.' + stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions YOLOv3 🚀 and Vision AI ⭐.' days-before-stale: 30 days-before-close: 5 exempt-issue-labels: 'documentation,tutorial' diff --git a/.gitignore b/.gitignore index 91ce33fb93..5f8cab5500 100755 --- a/.gitignore +++ b/.gitignore @@ -19,26 +19,19 @@ *.avi *.data *.json - *.cfg +!setup.cfg !cfg/yolov3*.cfg storage.googleapis.com runs/* data/* +!data/hyps/* !data/images/zidane.jpg !data/images/bus.jpg -!data/coco.names -!data/coco_paper.names -!data/coco.data -!data/coco_*.data -!data/coco_*.txt -!data/trainvalno5k.shapes !data/*.sh -pycocotools/* -results*.txt -gcp_test*.sh +results*.csv # Datasets ------------------------------------------------------------------------------------------------------------- coco/ @@ -53,9 +46,14 @@ VOC/ # Neural Network weights ----------------------------------------------------------------------------------------------- *.weights *.pt +*.pb *.onnx *.mlmodel *.torchscript +*.tflite +*.h5 +*_saved_model/ +*_web_model/ darknet53.conv.74 yolov3-tiny.conv.15 @@ -84,7 +82,7 @@ sdist/ var/ wheels/ *.egg-info/ -wandb/ +/wandb/ .installed.cfg *.egg diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..48e752f448 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,66 @@ +# Define hooks for code formations +# Will be applied on any updated commit files if a user has installed and linked commit hook + +default_language_version: + python: python3.8 + +# Define bot property if installed via https://github.com/marketplace/pre-commit-ci +ci: + autofix_prs: true + autoupdate_commit_msg: '[pre-commit.ci] pre-commit suggestions' + autoupdate_schedule: quarterly + # submodules: true + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.0.1 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace + - id: check-case-conflict + - id: check-yaml + - id: check-toml + - id: pretty-format-json + - id: check-docstring-first + + - repo: https://github.com/asottile/pyupgrade + rev: v2.23.1 + hooks: + - id: pyupgrade + args: [--py36-plus] + name: Upgrade code + + - repo: https://github.com/PyCQA/isort + rev: 5.9.3 + hooks: + - id: isort + name: Sort imports + + # TODO + #- repo: https://github.com/pre-commit/mirrors-yapf + # rev: v0.31.0 + # hooks: + # - id: yapf + # name: formatting + + # TODO + #- repo: https://github.com/executablebooks/mdformat + # rev: 0.7.7 + # hooks: + # - id: mdformat + # additional_dependencies: + # - mdformat-gfm + # - mdformat-black + # - mdformat_frontmatter + + # TODO + #- repo: https://github.com/asottile/yesqa + # rev: v1.2.3 + # hooks: + # - id: yesqa + + - repo: https://github.com/PyCQA/flake8 + rev: 3.9.2 + hooks: + - id: flake8 + name: PEP8 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..0ef52f638d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,94 @@ +## Contributing to YOLOv3 🚀 + +We love your input! We want to make contributing to YOLOv3 as easy and transparent as possible, whether it's: + +- Reporting a bug +- Discussing the current state of the code +- Submitting a fix +- Proposing a new feature +- Becoming a maintainer + +YOLOv3 works so well due to our combined community effort, and for every small improvement you contribute you will be +helping push the frontiers of what's possible in AI 😃! + +## Submitting a Pull Request (PR) 🛠️ + +Submitting a PR is easy! This example shows how to submit a PR for updating `requirements.txt` in 4 steps: + +### 1. Select File to Update + +Select `requirements.txt` to update by clicking on it in GitHub. +

PR_step1

+ +### 2. Click 'Edit this file' + +Button is in top-right corner. +

PR_step2

+ +### 3. Make Changes + +Change `matplotlib` version from `3.2.2` to `3.3`. +

PR_step3

+ +### 4. Preview Changes and Submit PR + +Click on the **Preview changes** tab to verify your updates. At the bottom of the screen select 'Create a **new branch** +for this commit', assign your branch a descriptive name such as `fix/matplotlib_version` and click the green **Propose +changes** button. All done, your PR is now submitted to YOLOv3 for review and approval 😃! +

PR_step4

+ +### PR recommendations + +To allow your work to be integrated as seamlessly as possible, we advise you to: + +- ✅ Verify your PR is **up-to-date with upstream/master.** If your PR is behind upstream/master an + automatic [GitHub actions](https://github.com/ultralytics/yolov3/blob/master/.github/workflows/rebase.yml) rebase may + be attempted by including the /rebase command in a comment body, or by running the following code, replacing 'feature' + with the name of your local branch: + + ```bash + git remote add upstream https://github.com/ultralytics/yolov3.git + git fetch upstream + git checkout feature # <----- replace 'feature' with local branch name + git merge upstream/master + git push -u origin -f + ``` + +- ✅ Verify all Continuous Integration (CI) **checks are passing**. +- ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase + but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ — Bruce Lee + +## Submitting a Bug Report 🐛 + +If you spot a problem with YOLOv3 please submit a Bug Report! + +For us to start investigating a possible problem we need to be able to reproduce it ourselves first. We've created a few +short guidelines below to help users provide what we need in order to get started. + +When asking a question, people will be better able to provide help if you provide **code** that they can easily +understand and use to **reproduce** the problem. This is referred to by community members as creating +a [minimum reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). Your code that reproduces +the problem should be: + +* ✅ **Minimal** – Use as little code as possible that still produces the same problem +* ✅ **Complete** – Provide **all** parts someone else needs to reproduce your problem in the question itself +* ✅ **Reproducible** – Test the code you're about to provide to make sure it reproduces the problem + +In addition to the above requirements, for [Ultralytics](https://ultralytics.com/) to provide assistance your code +should be: + +* ✅ **Current** – Verify that your code is up-to-date with current + GitHub [master](https://github.com/ultralytics/yolov3/tree/master), and if necessary `git pull` or `git clone` a new + copy to ensure your problem has not already been resolved by previous commits. +* ✅ **Unmodified** – Your problem must be reproducible without any modifications to the codebase in this + repository. [Ultralytics](https://ultralytics.com/) does not provide support for custom code ⚠️. + +If you believe your problem meets all of the above criteria, please close this issue and raise a new one using the 🐛 ** +Bug Report** [template](https://github.com/ultralytics/yolov3/issues/new/choose) and providing +a [minimum reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) to help us better +understand and diagnose your problem. + +## License + +By contributing, you agree that your contributions will be licensed under +the [GPL-3.0 license](https://choosealicense.com/licenses/gpl-3.0/) diff --git a/Dockerfile b/Dockerfile index ca07c4d7ef..1284242289 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,7 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + # Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch -FROM nvcr.io/nvidia/pytorch:21.03-py3 +FROM nvcr.io/nvidia/pytorch:21.10-py3 # Install linux packages RUN apt update && apt install -y zip htop screen libgl1-mesa-glx @@ -8,7 +10,9 @@ RUN apt update && apt install -y zip htop screen libgl1-mesa-glx COPY requirements.txt . RUN python -m pip install --upgrade pip RUN pip uninstall -y nvidia-tensorboard nvidia-tensorboard-plugin-dlprof -RUN pip install --no-cache -r requirements.txt coremltools onnx gsutil notebook +RUN pip install --no-cache -r requirements.txt coremltools onnx gsutil notebook wandb>=0.12.2 +RUN pip install --no-cache -U torch torchvision numpy Pillow +# RUN pip install --no-cache torch==1.10.0+cu113 torchvision==0.11.1+cu113 -f https://download.pytorch.org/whl/cu113/torch_stable.html # Create working directory RUN mkdir -p /usr/src/app @@ -17,27 +21,29 @@ WORKDIR /usr/src/app # Copy contents COPY . /usr/src/app +# Downloads to user config dir +ADD https://ultralytics.com/assets/Arial.ttf /root/.config/Ultralytics/ + # Set environment variables -ENV HOME=/usr/src/app +# ENV HOME=/usr/src/app -# --------------------------------------------------- Extras Below --------------------------------------------------- +# Usage Examples ------------------------------------------------------------------------------------------------------- # Build and Push # t=ultralytics/yolov3:latest && sudo docker build -t $t . && sudo docker push $t -# for v in {300..303}; do t=ultralytics/coco:v$v && sudo docker build -t $t . && sudo docker push $t; done # Pull and Run # t=ultralytics/yolov3:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all $t # Pull and Run with local directory access -# t=ultralytics/yolov3:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all -v "$(pwd)"/coco:/usr/src/coco $t +# t=ultralytics/yolov3:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all -v "$(pwd)"/datasets:/usr/src/datasets $t # Kill all # sudo docker kill $(sudo docker ps -q) # Kill all image-based -# sudo docker kill $(sudo docker ps -qa --filter ancestor=ultralytics/yolov5:latest) +# sudo docker kill $(sudo docker ps -qa --filter ancestor=ultralytics/yolov3:latest) # Bash into running container # sudo docker exec -it 5a9b5863d93d bash @@ -45,8 +51,11 @@ ENV HOME=/usr/src/app # Bash into stopped container # id=$(sudo docker ps -qa) && sudo docker start $id && sudo docker exec -it $id bash -# Send weights to GCP -# python -c "from utils.general import *; strip_optimizer('runs/train/exp0_*/weights/best.pt', 'tmp.pt')" && gsutil cp tmp.pt gs://*.pt - # Clean up # docker system prune -a --volumes + +# Update Ubuntu drivers +# https://www.maketecheasier.com/install-nvidia-drivers-ubuntu/ + +# DDP test +# python -m torch.distributed.run --nproc_per_node 2 --master_port 1 train.py --epochs 3 diff --git a/LICENSE b/LICENSE index 9e419e0421..92b370f0e0 100644 --- a/LICENSE +++ b/LICENSE @@ -671,4 +671,4 @@ into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. \ No newline at end of file +. diff --git a/README.md b/README.md old mode 100755 new mode 100644 index 04012af4d6..1d961c3c7a --- a/README.md +++ b/README.md @@ -1,160 +1,273 @@ - - -  +
+

+ + +

+
+
+ CI CPU testing + YOLOv3 Citation + Docker Pulls +
+ Open In Colab + Open In Kaggle + Join Forum +
+
+ + +
+

+YOLOv3 🚀 is a family of object detection architectures and models pretrained on the COCO dataset, and represents Ultralytics + open-source research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours of research and development. +

+ + + +
+ +##
Documentation
+ +See the [YOLOv3 Docs](https://docs.ultralytics.com) for full documentation on training, testing and deployment. + +##
Quick Start Examples
+ +
+Install + +[**Python>=3.6.0**](https://www.python.org/) is required with all +[requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) installed including +[**PyTorch>=1.7**](https://pytorch.org/get-started/locally/): + -CI CPU testing - -This repository represents Ultralytics open-source research into future object detection methods, and incorporates lessons learned and best practices evolved over thousands of hours of training and evolution on anonymized client datasets. **All code and models are under active development, and are subject to modification or deletion without notice.** Use at your own risk. - -

-
- YOLOv5-P5 640 Figure (click to expand) - -

-
-
- Figure Notes (click to expand) - - * GPU Speed measures end-to-end time per image averaged over 5000 COCO val2017 images using a V100 GPU with batch size 32, and includes image preprocessing, PyTorch FP16 inference, postprocessing and NMS. - * EfficientDet data from [google/automl](https://github.com/google/automl) at batch size 8. - * **Reproduce** by `python test.py --task study --data coco.yaml --iou 0.7 --weights yolov3.pt yolov3-spp.pt yolov3-tiny.pt yolov5l.pt` -
- - -## Branch Notice - -The [ultralytics/yolov3](https://github.com/ultralytics/yolov3) repository is now divided into two branches: -* [Master branch](https://github.com/ultralytics/yolov3/tree/master): Forward-compatible with all [YOLOv5](https://github.com/ultralytics/yolov5) models and methods (**recommended** ✅). ```bash -$ git clone https://github.com/ultralytics/yolov3 # master branch (default) -``` -* [Archive branch](https://github.com/ultralytics/yolov3/tree/archive): Backwards-compatible with original [darknet](https://pjreddie.com/darknet/) *.cfg models (**no longer maintained** ⚠️). -```bash -$ git clone https://github.com/ultralytics/yolov3 -b archive # archive branch +$ git clone https://github.com/ultralytics/yolov3 +$ cd yolov3 +$ pip install -r requirements.txt ``` -## Pretrained Checkpoints - -[assets3]: https://github.com/ultralytics/yolov3/releases -[assets5]: https://github.com/ultralytics/yolov5/releases - -Model |size
(pixels) |mAPval
0.5:0.95 |mAPtest
0.5:0.95 |mAPval
0.5 |Speed
V100 (ms) | |params
(M) |FLOPS
640 (B) ---- |--- |--- |--- |--- |--- |---|--- |--- -[YOLOv3-tiny][assets3] |640 |17.6 |17.6 |34.8 |**1.2** | |8.8 |13.2 -[YOLOv3][assets3] |640 |43.3 |43.3 |63.0 |4.1 | |61.9 |156.3 -[YOLOv3-SPP][assets3] |640 |44.3 |44.3 |64.6 |4.1 | |63.0 |157.1 -| | | | | | || | -[YOLOv5l][assets5] |640 |**48.2** |**48.2** |**66.9** |3.7 | |47.0 |115.4 - - -
- Table Notes (click to expand) - - * APtest denotes COCO [test-dev2017](http://cocodataset.org/#upload) server results, all other AP results denote val2017 accuracy. - * AP values are for single-model single-scale unless otherwise noted. **Reproduce mAP** by `python test.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` - * SpeedGPU averaged over 5000 COCO val2017 images using a GCP [n1-standard-16](https://cloud.google.com/compute/docs/machine-types#n1_standard_machine_types) V100 instance, and includes FP16 inference, postprocessing and NMS. **Reproduce speed** by `python test.py --data coco.yaml --img 640 --conf 0.25 --iou 0.45` - * All checkpoints are trained to 300 epochs with default settings and hyperparameters (no autoaugmentation).
+
+Inference -## Requirements +Inference with YOLOv3 and [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36). Models automatically download +from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases). -Python 3.8 or later with all [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) dependencies installed, including `torch>=1.7`. To install run: -```bash -$ pip install -r requirements.txt -``` +```python +import torch +# Model +model = torch.hub.load('ultralytics/yolov3', 'yolov3') # or yolov3-spp, yolov3-tiny, custom -## Tutorials +# Images +img = 'https://ultralytics.com/images/zidane.jpg' # or file, Path, PIL, OpenCV, numpy, list -* [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data)  🚀 RECOMMENDED -* [Tips for Best Training Results](https://github.com/ultralytics/yolov5/wiki/Tips-for-Best-Training-Results)  ☘️ RECOMMENDED -* [Weights & Biases Logging](https://github.com/ultralytics/yolov5/issues/1289)  🌟 NEW -* [Supervisely Ecosystem](https://github.com/ultralytics/yolov5/issues/2518)  🌟 NEW -* [Multi-GPU Training](https://github.com/ultralytics/yolov5/issues/475) -* [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36)  ⭐ NEW -* [TorchScript, ONNX, CoreML Export](https://github.com/ultralytics/yolov5/issues/251) 🚀 -* [Test-Time Augmentation (TTA)](https://github.com/ultralytics/yolov5/issues/303) -* [Model Ensembling](https://github.com/ultralytics/yolov5/issues/318) -* [Model Pruning/Sparsity](https://github.com/ultralytics/yolov5/issues/304) -* [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607) -* [Transfer Learning with Frozen Layers](https://github.com/ultralytics/yolov5/issues/1314)  ⭐ NEW -* [TensorRT Deployment](https://github.com/wang-xinyu/tensorrtx) +# Inference +results = model(img) +# Results +results.print() # or .show(), .save(), .crop(), .pandas(), etc. +``` -## Environments +
-YOLOv3 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): -- **Google Colab and Kaggle** notebooks with free GPU: Open In Colab Open In Kaggle -- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) -- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/AWS-Quickstart) -- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) Docker Pulls +
+Inference with detect.py -## Inference +`detect.py` runs inference on a variety of sources, downloading models automatically from +the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases) and saving results to `runs/detect`. -`detect.py` runs inference on a variety of sources, downloading models automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases) and saving results to `runs/detect`. ```bash $ python detect.py --source 0 # webcam - file.jpg # image - file.mp4 # video + img.jpg # image + vid.mp4 # video path/ # directory path/*.jpg # glob - 'https://youtu.be/NUsoVlDFqZg' # YouTube video + 'https://youtu.be/Zgi9g1ksQHc' # YouTube 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream ``` -To run inference on example images in `data/images`: -```bash -$ python detect.py --source data/images --weights yolov3.pt --conf 0.25 -``` - - -### PyTorch Hub - -To run **batched inference** with YOLOv3 and [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36): -```python -import torch +
-# Model -model = torch.hub.load('ultralytics/yolov3', 'yolov3') # or 'yolov3_spp', 'yolov3_tiny' +
+Training -# Image -img = 'https://ultralytics.com/images/zidane.jpg' -# Inference -results = model(img) -results.print() # or .show(), .save() -``` + -## Training +
-Run commands below to reproduce results on [COCO](https://github.com/ultralytics/yolov3/blob/master/data/scripts/get_coco.sh) dataset (dataset auto-downloads on first use). Training times for YOLOv3/YOLOv3-SPP/YOLOv3-tiny are 6/6/2 days on a single V100 (multi-GPU times faster). Use the largest `--batch-size` your GPU allows (batch sizes shown for 16 GB devices). -```bash -$ python train.py --data coco.yaml --cfg yolov3.yaml --weights '' --batch-size 24 - yolov3-spp.yaml 24 - yolov3-tiny.yaml 64 -``` - +
+Tutorials +* [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data)  🚀 RECOMMENDED +* [Tips for Best Training Results](https://github.com/ultralytics/yolov3/wiki/Tips-for-Best-Training-Results)  ☘️ + RECOMMENDED +* [Weights & Biases Logging](https://github.com/ultralytics/yolov5/issues/1289)  🌟 NEW +* [Roboflow for Datasets, Labeling, and Active Learning](https://github.com/ultralytics/yolov5/issues/4975)  🌟 NEW +* [Multi-GPU Training](https://github.com/ultralytics/yolov5/issues/475) +* [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36)  ⭐ NEW +* [TorchScript, ONNX, CoreML Export](https://github.com/ultralytics/yolov5/issues/251) 🚀 +* [Test-Time Augmentation (TTA)](https://github.com/ultralytics/yolov5/issues/303) +* [Model Ensembling](https://github.com/ultralytics/yolov5/issues/318) +* [Model Pruning/Sparsity](https://github.com/ultralytics/yolov5/issues/304) +* [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607) +* [Transfer Learning with Frozen Layers](https://github.com/ultralytics/yolov5/issues/1314)  ⭐ NEW +* [TensorRT Deployment](https://github.com/wang-xinyu/tensorrtx) -## Citation +
-[![DOI](https://zenodo.org/badge/146165888.svg)](https://zenodo.org/badge/latestdoi/146165888) +##
Environments
+ +Get started in seconds with our verified environments. Click each icon below for details. + + + +##
Integrations
+ + + +|Weights and Biases|Roboflow ⭐ NEW| +|:-:|:-:| +|Automatically track and visualize all your YOLOv3 training runs in the cloud with [Weights & Biases](https://wandb.ai/site?utm_campaign=repo_yolo_readme)|Label and export your custom datasets directly to YOLOv3 for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | + + +##
Why YOLOv5
+ +

+
+ YOLOv3-P5 640 Figure (click to expand) +

+
+
+ Figure Notes (click to expand) -## About Us +* **COCO AP val** denotes mAP@0.5:0.95 metric measured on the 5000-image [COCO val2017](http://cocodataset.org) dataset over various inference sizes from 256 to 1536. +* **GPU Speed** measures average inference time per image on [COCO val2017](http://cocodataset.org) dataset using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) V100 instance at batch-size 32. +* **EfficientDet** data from [google/automl](https://github.com/google/automl) at batch size 8. +* **Reproduce** by `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt` +
-Ultralytics is a U.S.-based particle physics and AI startup with over 6 years of expertise supporting government, academic and business clients. We offer a wide range of vision AI services, spanning from simple expert advice up to delivery of fully customized, end-to-end production solutions, including: -- **Cloud-based AI** systems operating on **hundreds of HD video streams in realtime.** -- **Edge AI** integrated into custom iOS and Android apps for realtime **30 FPS video inference.** -- **Custom data training**, hyperparameter evolution, and model exportation to any destination. +### Pretrained Checkpoints + +[assets]: https://github.com/ultralytics/yolov5/releases +[TTA]: https://github.com/ultralytics/yolov5/issues/303 + +|Model |size
(pixels) |mAPval
0.5:0.95 |mAPval
0.5 |Speed
CPU b1
(ms) |Speed
V100 b1
(ms) |Speed
V100 b32
(ms) |params
(M) |FLOPs
@640 (B) +|--- |--- |--- |--- |--- |--- |--- |--- |--- +|[YOLOv5n][assets] |640 |28.4 |46.0 |**45** |**6.3**|**0.6**|**1.9**|**4.5** +|[YOLOv5s][assets] |640 |37.2 |56.0 |98 |6.4 |0.9 |7.2 |16.5 +|[YOLOv5m][assets] |640 |45.2 |63.9 |224 |8.2 |1.7 |21.2 |49.0 +|[YOLOv5l][assets] |640 |48.8 |67.2 |430 |10.1 |2.7 |46.5 |109.1 +|[YOLOv5x][assets] |640 |50.7 |68.9 |766 |12.1 |4.8 |86.7 |205.7 +| | | | | | | | | +|[YOLOv5n6][assets] |1280 |34.0 |50.7 |153 |8.1 |2.1 |3.2 |4.6 +|[YOLOv5s6][assets] |1280 |44.5 |63.0 |385 |8.2 |3.6 |16.8 |12.6 +|[YOLOv5m6][assets] |1280 |51.0 |69.0 |887 |11.1 |6.8 |35.7 |50.0 +|[YOLOv5l6][assets] |1280 |53.6 |71.6 |1784 |15.8 |10.5 |76.8 |111.4 +|[YOLOv5x6][assets]
+ [TTA][TTA]|1280
1536 |54.7
**55.4** |**72.4**
72.3 |3136
- |26.2
- |19.4
- |140.7
- |209.8
- -For business inquiries and professional support requests please visit us at https://ultralytics.com. +
+ Table Notes (click to expand) +* All checkpoints are trained to 300 epochs with default settings and hyperparameters. +* **mAPval** values are for single-model single-scale on [COCO val2017](http://cocodataset.org) dataset.
Reproduce by `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` +* **Speed** averaged over COCO val images using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) instance. NMS times (~1 ms/img) not included.
Reproduce by `python val.py --data coco.yaml --img 640 --conf 0.25 --iou 0.45` +* **TTA** [Test Time Augmentation](https://github.com/ultralytics/yolov5/issues/303) includes reflection and scale augmentations.
Reproduce by `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment` -## Contact +
-**Issues should be raised directly in the repository.** For business inquiries or professional support requests please visit https://ultralytics.com or email Glenn Jocher at glenn.jocher@ultralytics.com. +##
Contribute
+ +We love your input! We want to make contributing to YOLOv3 as easy and transparent as possible. Please see our [Contributing Guide](CONTRIBUTING.md) to get started, and fill out the [YOLOv3 Survey](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to send us feedback on your experiences. Thank you to all our contributors! + + + + +##
Contact
+ +For YOLOv3 bugs and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues). For business inquiries or +professional support requests please visit [https://ultralytics.com/contact](https://ultralytics.com/contact). + +
+ + diff --git a/data/Argoverse.yaml b/data/Argoverse.yaml new file mode 100644 index 0000000000..9be3ae79a5 --- /dev/null +++ b/data/Argoverse.yaml @@ -0,0 +1,67 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/ +# Example usage: python train.py --data Argoverse.yaml +# parent +# ├── yolov3 +# └── datasets +# └── Argoverse ← downloads here + + +# 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, ..] +path: ../datasets/Argoverse # dataset root dir +train: Argoverse-1.1/images/train/ # train images (relative to 'path') 39384 images +val: Argoverse-1.1/images/val/ # val images (relative to 'path') 15062 images +test: Argoverse-1.1/images/test/ # test images (optional) https://eval.ai/web/challenges/challenge-page/800/overview + +# Classes +nc: 8 # number of classes +names: ['person', 'bicycle', 'car', 'motorcycle', 'bus', 'truck', 'traffic_light', 'stop_sign'] # class names + + +# Download script/URL (optional) --------------------------------------------------------------------------------------- +download: | + import json + + from tqdm import tqdm + from utils.general import download, Path + + + def argoverse2yolo(set): + labels = {} + a = json.load(open(set, "rb")) + for annot in tqdm(a['annotations'], desc=f"Converting {set} to YOLOv3 format..."): + img_id = annot['image_id'] + img_name = a['images'][img_id]['name'] + img_label_name = img_name[:-3] + "txt" + + cls = annot['category_id'] # instance class id + x_center, y_center, width, height = annot['bbox'] + x_center = (x_center + width / 2) / 1920.0 # offset and scale + y_center = (y_center + height / 2) / 1200.0 # offset and scale + width /= 1920.0 # scale + height /= 1200.0 # scale + + img_dir = set.parents[2] / 'Argoverse-1.1' / 'labels' / a['seq_dirs'][a['images'][annot['image_id']]['sid']] + if not img_dir.exists(): + img_dir.mkdir(parents=True, exist_ok=True) + + k = str(img_dir / img_label_name) + if k not in labels: + labels[k] = [] + labels[k].append(f"{cls} {x_center} {y_center} {width} {height}\n") + + for k in labels: + with open(k, "w") as f: + f.writelines(labels[k]) + + + # Download + dir = Path('../datasets/Argoverse') # dataset root dir + urls = ['https://argoverse-hd.s3.us-east-2.amazonaws.com/Argoverse-HD-Full.zip'] + download(urls, dir=dir, delete=False) + + # Convert + annotations_dir = 'Argoverse-HD/annotations/' + (dir / 'Argoverse-1.1' / 'tracking').rename(dir / 'Argoverse-1.1' / 'images') # rename 'tracking' to 'images' + for d in "train.json", "val.json": + argoverse2yolo(dir / annotations_dir / d) # convert VisDrone annotations to YOLO labels diff --git a/data/GlobalWheat2020.yaml b/data/GlobalWheat2020.yaml index ca2a49e2c9..10a2d3fca8 100644 --- a/data/GlobalWheat2020.yaml +++ b/data/GlobalWheat2020.yaml @@ -1,43 +1,41 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license # Global Wheat 2020 dataset http://www.global-wheat.com/ -# Train command: python train.py --data GlobalWheat2020.yaml -# Default dataset location is next to YOLOv3: -# /parent_folder -# /datasets/GlobalWheat2020 -# /yolov3 - - -# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] -train: # 3422 images - - ../datasets/GlobalWheat2020/images/arvalis_1 - - ../datasets/GlobalWheat2020/images/arvalis_2 - - ../datasets/GlobalWheat2020/images/arvalis_3 - - ../datasets/GlobalWheat2020/images/ethz_1 - - ../datasets/GlobalWheat2020/images/rres_1 - - ../datasets/GlobalWheat2020/images/inrae_1 - - ../datasets/GlobalWheat2020/images/usask_1 - -val: # 748 images (WARNING: train set contains ethz_1) - - ../datasets/GlobalWheat2020/images/ethz_1 - -test: # 1276 images - - ../datasets/GlobalWheat2020/images/utokyo_1 - - ../datasets/GlobalWheat2020/images/utokyo_2 - - ../datasets/GlobalWheat2020/images/nau_1 - - ../datasets/GlobalWheat2020/images/uq_1 - -# number of classes -nc: 1 - -# class names -names: [ 'wheat_head' ] - - -# download command/URL (optional) -------------------------------------------------------------------------------------- +# Example usage: python train.py --data GlobalWheat2020.yaml +# parent +# ├── yolov3 +# └── datasets +# └── GlobalWheat2020 ← downloads here + + +# 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, ..] +path: ../datasets/GlobalWheat2020 # dataset root dir +train: # train images (relative to 'path') 3422 images + - images/arvalis_1 + - images/arvalis_2 + - images/arvalis_3 + - images/ethz_1 + - images/rres_1 + - images/inrae_1 + - images/usask_1 +val: # val images (relative to 'path') 748 images (WARNING: train set contains ethz_1) + - images/ethz_1 +test: # test images (optional) 1276 images + - images/utokyo_1 + - images/utokyo_2 + - images/nau_1 + - images/uq_1 + +# Classes +nc: 1 # number of classes +names: ['wheat_head'] # class names + + +# Download script/URL (optional) --------------------------------------------------------------------------------------- download: | from utils.general import download, Path # Download - dir = Path('../datasets/GlobalWheat2020') # dataset directory + dir = Path(yaml['path']) # dataset root dir urls = ['https://zenodo.org/record/4298502/files/global-wheat-codalab-official.zip', 'https://github.com/ultralytics/yolov5/releases/download/v1.0/GlobalWheat2020_labels.zip'] download(urls, dir=dir) diff --git a/data/SKU-110K.yaml b/data/SKU-110K.yaml index f4aea8b55e..183d3637b4 100644 --- a/data/SKU-110K.yaml +++ b/data/SKU-110K.yaml @@ -1,39 +1,39 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license # SKU-110K retail items dataset https://github.com/eg4000/SKU110K_CVPR19 -# Train command: python train.py --data SKU-110K.yaml -# Default dataset location is next to YOLOv3: -# /parent_folder -# /datasets/SKU-110K -# /yolov3 +# Example usage: python train.py --data SKU-110K.yaml +# parent +# ├── yolov3 +# └── datasets +# └── SKU-110K ← downloads here -# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] -train: ../datasets/SKU-110K/train.txt # 8219 images -val: ../datasets/SKU-110K/val.txt # 588 images -test: ../datasets/SKU-110K/test.txt # 2936 images +# 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, ..] +path: ../datasets/SKU-110K # dataset root dir +train: train.txt # train images (relative to 'path') 8219 images +val: val.txt # val images (relative to 'path') 588 images +test: test.txt # test images (optional) 2936 images -# number of classes -nc: 1 +# Classes +nc: 1 # number of classes +names: ['object'] # class names -# class names -names: [ 'object' ] - -# download command/URL (optional) -------------------------------------------------------------------------------------- +# Download script/URL (optional) --------------------------------------------------------------------------------------- download: | import shutil from tqdm import tqdm from utils.general import np, pd, Path, download, xyxy2xywh # Download - datasets = Path('../datasets') # download directory + dir = Path(yaml['path']) # dataset root dir + parent = Path(dir.parent) # download dir urls = ['http://trax-geometry.s3.amazonaws.com/cvpr_challenge/SKU110K_fixed.tar.gz'] - download(urls, dir=datasets, delete=False) + download(urls, dir=parent, delete=False) # Rename directories - dir = (datasets / 'SKU-110K') if dir.exists(): shutil.rmtree(dir) - (datasets / 'SKU110K_fixed').rename(dir) # rename dir + (parent / 'SKU110K_fixed').rename(dir) # rename dir (dir / 'labels').mkdir(parents=True, exist_ok=True) # create labels dir # Convert labels diff --git a/data/VisDrone.yaml b/data/VisDrone.yaml index 59f1cd5105..945f05b40f 100644 --- a/data/VisDrone.yaml +++ b/data/VisDrone.yaml @@ -1,24 +1,24 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license # VisDrone2019-DET dataset https://github.com/VisDrone/VisDrone-Dataset -# Train command: python train.py --data VisDrone.yaml -# Default dataset location is next to YOLOv3: -# /parent_folder -# /VisDrone -# /yolov3 +# Example usage: python train.py --data VisDrone.yaml +# parent +# ├── yolov3 +# └── datasets +# └── VisDrone ← downloads here -# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] -train: ../VisDrone/VisDrone2019-DET-train/images # 6471 images -val: ../VisDrone/VisDrone2019-DET-val/images # 548 images -test: ../VisDrone/VisDrone2019-DET-test-dev/images # 1610 images +# 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, ..] +path: ../datasets/VisDrone # dataset root dir +train: VisDrone2019-DET-train/images # train images (relative to 'path') 6471 images +val: VisDrone2019-DET-val/images # val images (relative to 'path') 548 images +test: VisDrone2019-DET-test-dev/images # test images (optional) 1610 images -# number of classes -nc: 10 +# Classes +nc: 10 # number of classes +names: ['pedestrian', 'people', 'bicycle', 'car', 'van', 'truck', 'tricycle', 'awning-tricycle', 'bus', 'motor'] -# class names -names: [ 'pedestrian', 'people', 'bicycle', 'car', 'van', 'truck', 'tricycle', 'awning-tricycle', 'bus', 'motor' ] - -# download command/URL (optional) -------------------------------------------------------------------------------------- +# Download script/URL (optional) --------------------------------------------------------------------------------------- download: | from utils.general import download, os, Path @@ -49,7 +49,7 @@ download: | # Download - dir = Path('../VisDrone') # dataset directory + dir = Path(yaml['path']) # dataset root dir urls = ['https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-train.zip', 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-val.zip', 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-test-dev.zip', diff --git a/data/argoverse_hd.yaml b/data/argoverse_hd.yaml deleted file mode 100644 index 29d49b8807..0000000000 --- a/data/argoverse_hd.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/ -# Train command: python train.py --data argoverse_hd.yaml -# Default dataset location is next to YOLOv3: -# /parent_folder -# /argoverse -# /yolov3 - - -# download command/URL (optional) -download: bash data/scripts/get_argoverse_hd.sh - -# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] -train: ../argoverse/Argoverse-1.1/images/train/ # 39384 images -val: ../argoverse/Argoverse-1.1/images/val/ # 15062 iamges -test: ../argoverse/Argoverse-1.1/images/test/ # Submit to: https://eval.ai/web/challenges/challenge-page/800/overview - -# number of classes -nc: 8 - -# class names -names: [ 'person', 'bicycle', 'car', 'motorcycle', 'bus', 'truck', 'traffic_light', 'stop_sign' ] diff --git a/data/coco.yaml b/data/coco.yaml index 8714e6a33f..1d89a3a033 100644 --- a/data/coco.yaml +++ b/data/coco.yaml @@ -1,35 +1,44 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license # COCO 2017 dataset http://cocodataset.org -# Train command: python train.py --data coco.yaml -# Default dataset location is next to YOLOv3: -# /parent_folder -# /coco -# /yolov3 +# Example usage: python train.py --data coco.yaml +# parent +# ├── yolov3 +# └── datasets +# └── coco ← downloads here -# download command/URL (optional) -download: bash data/scripts/get_coco.sh +# 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, ..] +path: ../datasets/coco # dataset root dir +train: train2017.txt # train images (relative to 'path') 118287 images +val: val2017.txt # train images (relative to 'path') 5000 images +test: test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794 -# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] -train: ../coco/train2017.txt # 118287 images -val: ../coco/val2017.txt # 5000 images -test: ../coco/test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794 +# Classes +nc: 80 # number of classes +names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', + 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', + 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', + 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', + 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', + 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', + 'hair drier', 'toothbrush'] # class names -# number of classes -nc: 80 -# class names -names: [ 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', - 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', - 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', - 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', - 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', - 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', - 'hair drier', 'toothbrush' ] +# Download script/URL (optional) +download: | + from utils.general import download, Path -# Print classes -# with open('data/coco.yaml') as f: -# d = yaml.safe_load(f) # dict -# for i, x in enumerate(d['names']): -# print(i, x) + # Download labels + segments = False # segment or box labels + dir = Path(yaml['path']) # dataset root dir + url = 'https://github.com/ultralytics/yolov5/releases/download/v1.0/' + urls = [url + ('coco2017labels-segments.zip' if segments else 'coco2017labels.zip')] # labels + download(urls, dir=dir.parent) + + # Download data + urls = ['http://images.cocodataset.org/zips/train2017.zip', # 19G, 118k images + 'http://images.cocodataset.org/zips/val2017.zip', # 1G, 5k images + 'http://images.cocodataset.org/zips/test2017.zip'] # 7G, 41k images (optional) + download(urls, dir=dir / 'images', threads=3) diff --git a/data/coco128.yaml b/data/coco128.yaml index ef1f6c62fb..19e8d8001e 100644 --- a/data/coco128.yaml +++ b/data/coco128.yaml @@ -1,28 +1,30 @@ -# COCO 2017 dataset http://cocodataset.org - first 128 training images -# Train command: python train.py --data coco128.yaml -# Default dataset location is next to YOLOv3: -# /parent_folder -# /coco128 -# /yolov3 +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) +# Example usage: python train.py --data coco128.yaml +# parent +# ├── yolov3 +# └── datasets +# └── coco128 ← downloads here -# download command/URL (optional) -download: https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip +# 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, ..] +path: ../datasets/coco128 # dataset root dir +train: images/train2017 # train images (relative to 'path') 128 images +val: images/train2017 # val images (relative to 'path') 128 images +test: # test images (optional) -# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] -train: ../coco128/images/train2017/ # 128 images -val: ../coco128/images/train2017/ # 128 images +# Classes +nc: 80 # number of classes +names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', + 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', + 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', + 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', + 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', + 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', + 'hair drier', 'toothbrush'] # class names -# number of classes -nc: 80 -# class names -names: [ 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', - 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', - 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', - 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', - 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', - 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', - 'hair drier', 'toothbrush' ] +# Download script/URL (optional) +download: https://ultralytics.com/assets/coco128.zip diff --git a/data/hyp.finetune.yaml b/data/hyp.finetune.yaml deleted file mode 100644 index 1b84cff95c..0000000000 --- a/data/hyp.finetune.yaml +++ /dev/null @@ -1,38 +0,0 @@ -# Hyperparameters for VOC finetuning -# python train.py --batch 64 --weights yolov5m.pt --data voc.yaml --img 512 --epochs 50 -# See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials - - -# Hyperparameter Evolution Results -# Generations: 306 -# P R mAP.5 mAP.5:.95 box obj cls -# Metrics: 0.6 0.936 0.896 0.684 0.0115 0.00805 0.00146 - -lr0: 0.0032 -lrf: 0.12 -momentum: 0.843 -weight_decay: 0.00036 -warmup_epochs: 2.0 -warmup_momentum: 0.5 -warmup_bias_lr: 0.05 -box: 0.0296 -cls: 0.243 -cls_pw: 0.631 -obj: 0.301 -obj_pw: 0.911 -iou_t: 0.2 -anchor_t: 2.91 -# anchors: 3.63 -fl_gamma: 0.0 -hsv_h: 0.0138 -hsv_s: 0.664 -hsv_v: 0.464 -degrees: 0.373 -translate: 0.245 -scale: 0.898 -shear: 0.602 -perspective: 0.0 -flipud: 0.00856 -fliplr: 0.5 -mosaic: 1.0 -mixup: 0.243 diff --git a/data/hyp.finetune_objects365.yaml b/data/hyp.finetune_objects365.yaml deleted file mode 100644 index 2b104ef2d9..0000000000 --- a/data/hyp.finetune_objects365.yaml +++ /dev/null @@ -1,28 +0,0 @@ -lr0: 0.00258 -lrf: 0.17 -momentum: 0.779 -weight_decay: 0.00058 -warmup_epochs: 1.33 -warmup_momentum: 0.86 -warmup_bias_lr: 0.0711 -box: 0.0539 -cls: 0.299 -cls_pw: 0.825 -obj: 0.632 -obj_pw: 1.0 -iou_t: 0.2 -anchor_t: 3.44 -anchors: 3.2 -fl_gamma: 0.0 -hsv_h: 0.0188 -hsv_s: 0.704 -hsv_v: 0.36 -degrees: 0.0 -translate: 0.0902 -scale: 0.491 -shear: 0.0 -perspective: 0.0 -flipud: 0.0 -fliplr: 0.5 -mosaic: 1.0 -mixup: 0.0 diff --git a/data/hyps/hyp.scratch-high.yaml b/data/hyps/hyp.scratch-high.yaml new file mode 100644 index 0000000000..07ad9fc295 --- /dev/null +++ b/data/hyps/hyp.scratch-high.yaml @@ -0,0 +1,34 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# Hyperparameters for high-augmentation COCO training from scratch +# python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300 +# See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials + +lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) +lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf) +momentum: 0.937 # SGD momentum/Adam beta1 +weight_decay: 0.0005 # optimizer weight decay 5e-4 +warmup_epochs: 3.0 # warmup epochs (fractions ok) +warmup_momentum: 0.8 # warmup initial momentum +warmup_bias_lr: 0.1 # warmup initial bias lr +box: 0.05 # box loss gain +cls: 0.3 # cls loss gain +cls_pw: 1.0 # cls BCELoss positive_weight +obj: 0.7 # obj loss gain (scale with pixels) +obj_pw: 1.0 # obj BCELoss positive_weight +iou_t: 0.20 # IoU training threshold +anchor_t: 4.0 # anchor-multiple threshold +# anchors: 3 # anchors per output layer (0 to ignore) +fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) +hsv_h: 0.015 # image HSV-Hue augmentation (fraction) +hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) +hsv_v: 0.4 # image HSV-Value augmentation (fraction) +degrees: 0.0 # image rotation (+/- deg) +translate: 0.1 # image translation (+/- fraction) +scale: 0.9 # image scale (+/- gain) +shear: 0.0 # image shear (+/- deg) +perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 +flipud: 0.0 # image flip up-down (probability) +fliplr: 0.5 # image flip left-right (probability) +mosaic: 1.0 # image mosaic (probability) +mixup: 0.1 # image mixup (probability) +copy_paste: 0.1 # segment copy-paste (probability) diff --git a/data/hyps/hyp.scratch-low.yaml b/data/hyps/hyp.scratch-low.yaml new file mode 100644 index 0000000000..3f9849c9fa --- /dev/null +++ b/data/hyps/hyp.scratch-low.yaml @@ -0,0 +1,34 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# Hyperparameters for low-augmentation COCO training from scratch +# python train.py --batch 64 --cfg yolov5n6.yaml --weights '' --data coco.yaml --img 640 --epochs 300 --linear +# See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials + +lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) +lrf: 0.01 # final OneCycleLR learning rate (lr0 * lrf) +momentum: 0.937 # SGD momentum/Adam beta1 +weight_decay: 0.0005 # optimizer weight decay 5e-4 +warmup_epochs: 3.0 # warmup epochs (fractions ok) +warmup_momentum: 0.8 # warmup initial momentum +warmup_bias_lr: 0.1 # warmup initial bias lr +box: 0.05 # box loss gain +cls: 0.5 # cls loss gain +cls_pw: 1.0 # cls BCELoss positive_weight +obj: 1.0 # obj loss gain (scale with pixels) +obj_pw: 1.0 # obj BCELoss positive_weight +iou_t: 0.20 # IoU training threshold +anchor_t: 4.0 # anchor-multiple threshold +# anchors: 3 # anchors per output layer (0 to ignore) +fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) +hsv_h: 0.015 # image HSV-Hue augmentation (fraction) +hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) +hsv_v: 0.4 # image HSV-Value augmentation (fraction) +degrees: 0.0 # image rotation (+/- deg) +translate: 0.1 # image translation (+/- fraction) +scale: 0.5 # image scale (+/- gain) +shear: 0.0 # image shear (+/- deg) +perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 +flipud: 0.0 # image flip up-down (probability) +fliplr: 0.5 # image flip left-right (probability) +mosaic: 1.0 # image mosaic (probability) +mixup: 0.0 # image mixup (probability) +copy_paste: 0.0 # segment copy-paste (probability) diff --git a/data/hyps/hyp.scratch-med.yaml b/data/hyps/hyp.scratch-med.yaml new file mode 100644 index 0000000000..d1f480bcb2 --- /dev/null +++ b/data/hyps/hyp.scratch-med.yaml @@ -0,0 +1,34 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# Hyperparameters for medium-augmentation COCO training from scratch +# python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300 +# See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials + +lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) +lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) +momentum: 0.937 # SGD momentum/Adam beta1 +weight_decay: 0.0005 # optimizer weight decay 5e-4 +warmup_epochs: 3.0 # warmup epochs (fractions ok) +warmup_momentum: 0.8 # warmup initial momentum +warmup_bias_lr: 0.1 # warmup initial bias lr +box: 0.05 # box loss gain +cls: 0.3 # cls loss gain +cls_pw: 1.0 # cls BCELoss positive_weight +obj: 0.7 # obj loss gain (scale with pixels) +obj_pw: 1.0 # obj BCELoss positive_weight +iou_t: 0.20 # IoU training threshold +anchor_t: 4.0 # anchor-multiple threshold +# anchors: 3 # anchors per output layer (0 to ignore) +fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) +hsv_h: 0.015 # image HSV-Hue augmentation (fraction) +hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) +hsv_v: 0.4 # image HSV-Value augmentation (fraction) +degrees: 0.0 # image rotation (+/- deg) +translate: 0.1 # image translation (+/- fraction) +scale: 0.9 # image scale (+/- gain) +shear: 0.0 # image shear (+/- deg) +perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 +flipud: 0.0 # image flip up-down (probability) +fliplr: 0.5 # image flip left-right (probability) +mosaic: 1.0 # image mosaic (probability) +mixup: 0.1 # image mixup (probability) +copy_paste: 0.0 # segment copy-paste (probability) diff --git a/data/hyp.scratch.yaml b/data/hyps/hyp.scratch.yaml similarity index 90% rename from data/hyp.scratch.yaml rename to data/hyps/hyp.scratch.yaml index 44f26b6658..31f6d142e2 100644 --- a/data/hyp.scratch.yaml +++ b/data/hyps/hyp.scratch.yaml @@ -1,10 +1,10 @@ +# YOLOv5 🚀 by Ultralytics, GPL-3.0 license # Hyperparameters for COCO training from scratch # python train.py --batch 40 --cfg yolov5m.yaml --weights '' --data coco.yaml --img 640 --epochs 300 # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials - lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) -lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf) +lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) momentum: 0.937 # SGD momentum/Adam beta1 weight_decay: 0.0005 # optimizer weight decay 5e-4 warmup_epochs: 3.0 # warmup epochs (fractions ok) @@ -31,3 +31,4 @@ flipud: 0.0 # image flip up-down (probability) fliplr: 0.5 # image flip left-right (probability) mosaic: 1.0 # image mosaic (probability) mixup: 0.0 # image mixup (probability) +copy_paste: 0.0 # segment copy-paste (probability) diff --git a/data/objects365.yaml b/data/objects365.yaml index 1cac32f4e2..3472f0f6b9 100644 --- a/data/objects365.yaml +++ b/data/objects365.yaml @@ -1,102 +1,112 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license # Objects365 dataset https://www.objects365.org/ -# Train command: python train.py --data objects365.yaml -# Default dataset location is next to YOLOv3: -# /parent_folder -# /datasets/objects365 -# /yolov3 +# Example usage: python train.py --data Objects365.yaml +# parent +# ├── yolov3 +# └── datasets +# └── Objects365 ← downloads here -# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] -train: ../datasets/objects365/images/train # 1742289 images -val: ../datasets/objects365/images/val # 5570 images -# number of classes -nc: 365 +# 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, ..] +path: ../datasets/Objects365 # dataset root dir +train: images/train # train images (relative to 'path') 1742289 images +val: images/val # val images (relative to 'path') 80000 images +test: # test images (optional) -# class names -names: [ 'Person', 'Sneakers', 'Chair', 'Other Shoes', 'Hat', 'Car', 'Lamp', 'Glasses', 'Bottle', 'Desk', 'Cup', - 'Street Lights', 'Cabinet/shelf', 'Handbag/Satchel', 'Bracelet', 'Plate', 'Picture/Frame', 'Helmet', 'Book', - 'Gloves', 'Storage box', 'Boat', 'Leather Shoes', 'Flower', 'Bench', 'Potted Plant', 'Bowl/Basin', 'Flag', - 'Pillow', 'Boots', 'Vase', 'Microphone', 'Necklace', 'Ring', 'SUV', 'Wine Glass', 'Belt', 'Monitor/TV', - 'Backpack', 'Umbrella', 'Traffic Light', 'Speaker', 'Watch', 'Tie', 'Trash bin Can', 'Slippers', 'Bicycle', - 'Stool', 'Barrel/bucket', 'Van', 'Couch', 'Sandals', 'Basket', 'Drum', 'Pen/Pencil', 'Bus', 'Wild Bird', - 'High Heels', 'Motorcycle', 'Guitar', 'Carpet', 'Cell Phone', 'Bread', 'Camera', 'Canned', 'Truck', - 'Traffic cone', 'Cymbal', 'Lifesaver', 'Towel', 'Stuffed Toy', 'Candle', 'Sailboat', 'Laptop', 'Awning', - 'Bed', 'Faucet', 'Tent', 'Horse', 'Mirror', 'Power outlet', 'Sink', 'Apple', 'Air Conditioner', 'Knife', - 'Hockey Stick', 'Paddle', 'Pickup Truck', 'Fork', 'Traffic Sign', 'Balloon', 'Tripod', 'Dog', 'Spoon', 'Clock', - 'Pot', 'Cow', 'Cake', 'Dinning Table', 'Sheep', 'Hanger', 'Blackboard/Whiteboard', 'Napkin', 'Other Fish', - 'Orange/Tangerine', 'Toiletry', 'Keyboard', 'Tomato', 'Lantern', 'Machinery Vehicle', 'Fan', - 'Green Vegetables', 'Banana', 'Baseball Glove', 'Airplane', 'Mouse', 'Train', 'Pumpkin', 'Soccer', 'Skiboard', - 'Luggage', 'Nightstand', 'Tea pot', 'Telephone', 'Trolley', 'Head Phone', 'Sports Car', 'Stop Sign', - 'Dessert', 'Scooter', 'Stroller', 'Crane', 'Remote', 'Refrigerator', 'Oven', 'Lemon', 'Duck', 'Baseball Bat', - 'Surveillance Camera', 'Cat', 'Jug', 'Broccoli', 'Piano', 'Pizza', 'Elephant', 'Skateboard', 'Surfboard', - 'Gun', 'Skating and Skiing shoes', 'Gas stove', 'Donut', 'Bow Tie', 'Carrot', 'Toilet', 'Kite', 'Strawberry', - 'Other Balls', 'Shovel', 'Pepper', 'Computer Box', 'Toilet Paper', 'Cleaning Products', 'Chopsticks', - 'Microwave', 'Pigeon', 'Baseball', 'Cutting/chopping Board', 'Coffee Table', 'Side Table', 'Scissors', - 'Marker', 'Pie', 'Ladder', 'Snowboard', 'Cookies', 'Radiator', 'Fire Hydrant', 'Basketball', 'Zebra', 'Grape', - 'Giraffe', 'Potato', 'Sausage', 'Tricycle', 'Violin', 'Egg', 'Fire Extinguisher', 'Candy', 'Fire Truck', - 'Billiards', 'Converter', 'Bathtub', 'Wheelchair', 'Golf Club', 'Briefcase', 'Cucumber', 'Cigar/Cigarette', - 'Paint Brush', 'Pear', 'Heavy Truck', 'Hamburger', 'Extractor', 'Extension Cord', 'Tong', 'Tennis Racket', - 'Folder', 'American Football', 'earphone', 'Mask', 'Kettle', 'Tennis', 'Ship', 'Swing', 'Coffee Machine', - 'Slide', 'Carriage', 'Onion', 'Green beans', 'Projector', 'Frisbee', 'Washing Machine/Drying Machine', - 'Chicken', 'Printer', 'Watermelon', 'Saxophone', 'Tissue', 'Toothbrush', 'Ice cream', 'Hot-air balloon', - 'Cello', 'French Fries', 'Scale', 'Trophy', 'Cabbage', 'Hot dog', 'Blender', 'Peach', 'Rice', 'Wallet/Purse', - 'Volleyball', 'Deer', 'Goose', 'Tape', 'Tablet', 'Cosmetics', 'Trumpet', 'Pineapple', 'Golf Ball', - 'Ambulance', 'Parking meter', 'Mango', 'Key', 'Hurdle', 'Fishing Rod', 'Medal', 'Flute', 'Brush', 'Penguin', - 'Megaphone', 'Corn', 'Lettuce', 'Garlic', 'Swan', 'Helicopter', 'Green Onion', 'Sandwich', 'Nuts', - 'Speed Limit Sign', 'Induction Cooker', 'Broom', 'Trombone', 'Plum', 'Rickshaw', 'Goldfish', 'Kiwi fruit', - 'Router/modem', 'Poker Card', 'Toaster', 'Shrimp', 'Sushi', 'Cheese', 'Notepaper', 'Cherry', 'Pliers', 'CD', - 'Pasta', 'Hammer', 'Cue', 'Avocado', 'Hamimelon', 'Flask', 'Mushroom', 'Screwdriver', 'Soap', 'Recorder', - 'Bear', 'Eggplant', 'Board Eraser', 'Coconut', 'Tape Measure/Ruler', 'Pig', 'Showerhead', 'Globe', 'Chips', - 'Steak', 'Crosswalk Sign', 'Stapler', 'Camel', 'Formula 1', 'Pomegranate', 'Dishwasher', 'Crab', - 'Hoverboard', 'Meat ball', 'Rice Cooker', 'Tuba', 'Calculator', 'Papaya', 'Antelope', 'Parrot', 'Seal', - 'Butterfly', 'Dumbbell', 'Donkey', 'Lion', 'Urinal', 'Dolphin', 'Electric Drill', 'Hair Dryer', 'Egg tart', - 'Jellyfish', 'Treadmill', 'Lighter', 'Grapefruit', 'Game board', 'Mop', 'Radish', 'Baozi', 'Target', 'French', - 'Spring Rolls', 'Monkey', 'Rabbit', 'Pencil Case', 'Yak', 'Red Cabbage', 'Binoculars', 'Asparagus', 'Barbell', - 'Scallop', 'Noddles', 'Comb', 'Dumpling', 'Oyster', 'Table Tennis paddle', 'Cosmetics Brush/Eyeliner Pencil', - 'Chainsaw', 'Eraser', 'Lobster', 'Durian', 'Okra', 'Lipstick', 'Cosmetics Mirror', 'Curling', 'Table Tennis' ] +# Classes +nc: 365 # number of classes +names: ['Person', 'Sneakers', 'Chair', 'Other Shoes', 'Hat', 'Car', 'Lamp', 'Glasses', 'Bottle', 'Desk', 'Cup', + 'Street Lights', 'Cabinet/shelf', 'Handbag/Satchel', 'Bracelet', 'Plate', 'Picture/Frame', 'Helmet', 'Book', + 'Gloves', 'Storage box', 'Boat', 'Leather Shoes', 'Flower', 'Bench', 'Potted Plant', 'Bowl/Basin', 'Flag', + 'Pillow', 'Boots', 'Vase', 'Microphone', 'Necklace', 'Ring', 'SUV', 'Wine Glass', 'Belt', 'Monitor/TV', + 'Backpack', 'Umbrella', 'Traffic Light', 'Speaker', 'Watch', 'Tie', 'Trash bin Can', 'Slippers', 'Bicycle', + 'Stool', 'Barrel/bucket', 'Van', 'Couch', 'Sandals', 'Basket', 'Drum', 'Pen/Pencil', 'Bus', 'Wild Bird', + 'High Heels', 'Motorcycle', 'Guitar', 'Carpet', 'Cell Phone', 'Bread', 'Camera', 'Canned', 'Truck', + 'Traffic cone', 'Cymbal', 'Lifesaver', 'Towel', 'Stuffed Toy', 'Candle', 'Sailboat', 'Laptop', 'Awning', + 'Bed', 'Faucet', 'Tent', 'Horse', 'Mirror', 'Power outlet', 'Sink', 'Apple', 'Air Conditioner', 'Knife', + 'Hockey Stick', 'Paddle', 'Pickup Truck', 'Fork', 'Traffic Sign', 'Balloon', 'Tripod', 'Dog', 'Spoon', 'Clock', + 'Pot', 'Cow', 'Cake', 'Dinning Table', 'Sheep', 'Hanger', 'Blackboard/Whiteboard', 'Napkin', 'Other Fish', + 'Orange/Tangerine', 'Toiletry', 'Keyboard', 'Tomato', 'Lantern', 'Machinery Vehicle', 'Fan', + 'Green Vegetables', 'Banana', 'Baseball Glove', 'Airplane', 'Mouse', 'Train', 'Pumpkin', 'Soccer', 'Skiboard', + 'Luggage', 'Nightstand', 'Tea pot', 'Telephone', 'Trolley', 'Head Phone', 'Sports Car', 'Stop Sign', + 'Dessert', 'Scooter', 'Stroller', 'Crane', 'Remote', 'Refrigerator', 'Oven', 'Lemon', 'Duck', 'Baseball Bat', + 'Surveillance Camera', 'Cat', 'Jug', 'Broccoli', 'Piano', 'Pizza', 'Elephant', 'Skateboard', 'Surfboard', + 'Gun', 'Skating and Skiing shoes', 'Gas stove', 'Donut', 'Bow Tie', 'Carrot', 'Toilet', 'Kite', 'Strawberry', + 'Other Balls', 'Shovel', 'Pepper', 'Computer Box', 'Toilet Paper', 'Cleaning Products', 'Chopsticks', + 'Microwave', 'Pigeon', 'Baseball', 'Cutting/chopping Board', 'Coffee Table', 'Side Table', 'Scissors', + 'Marker', 'Pie', 'Ladder', 'Snowboard', 'Cookies', 'Radiator', 'Fire Hydrant', 'Basketball', 'Zebra', 'Grape', + 'Giraffe', 'Potato', 'Sausage', 'Tricycle', 'Violin', 'Egg', 'Fire Extinguisher', 'Candy', 'Fire Truck', + 'Billiards', 'Converter', 'Bathtub', 'Wheelchair', 'Golf Club', 'Briefcase', 'Cucumber', 'Cigar/Cigarette', + 'Paint Brush', 'Pear', 'Heavy Truck', 'Hamburger', 'Extractor', 'Extension Cord', 'Tong', 'Tennis Racket', + 'Folder', 'American Football', 'earphone', 'Mask', 'Kettle', 'Tennis', 'Ship', 'Swing', 'Coffee Machine', + 'Slide', 'Carriage', 'Onion', 'Green beans', 'Projector', 'Frisbee', 'Washing Machine/Drying Machine', + 'Chicken', 'Printer', 'Watermelon', 'Saxophone', 'Tissue', 'Toothbrush', 'Ice cream', 'Hot-air balloon', + 'Cello', 'French Fries', 'Scale', 'Trophy', 'Cabbage', 'Hot dog', 'Blender', 'Peach', 'Rice', 'Wallet/Purse', + 'Volleyball', 'Deer', 'Goose', 'Tape', 'Tablet', 'Cosmetics', 'Trumpet', 'Pineapple', 'Golf Ball', + 'Ambulance', 'Parking meter', 'Mango', 'Key', 'Hurdle', 'Fishing Rod', 'Medal', 'Flute', 'Brush', 'Penguin', + 'Megaphone', 'Corn', 'Lettuce', 'Garlic', 'Swan', 'Helicopter', 'Green Onion', 'Sandwich', 'Nuts', + 'Speed Limit Sign', 'Induction Cooker', 'Broom', 'Trombone', 'Plum', 'Rickshaw', 'Goldfish', 'Kiwi fruit', + 'Router/modem', 'Poker Card', 'Toaster', 'Shrimp', 'Sushi', 'Cheese', 'Notepaper', 'Cherry', 'Pliers', 'CD', + 'Pasta', 'Hammer', 'Cue', 'Avocado', 'Hamimelon', 'Flask', 'Mushroom', 'Screwdriver', 'Soap', 'Recorder', + 'Bear', 'Eggplant', 'Board Eraser', 'Coconut', 'Tape Measure/Ruler', 'Pig', 'Showerhead', 'Globe', 'Chips', + 'Steak', 'Crosswalk Sign', 'Stapler', 'Camel', 'Formula 1', 'Pomegranate', 'Dishwasher', 'Crab', + 'Hoverboard', 'Meat ball', 'Rice Cooker', 'Tuba', 'Calculator', 'Papaya', 'Antelope', 'Parrot', 'Seal', + 'Butterfly', 'Dumbbell', 'Donkey', 'Lion', 'Urinal', 'Dolphin', 'Electric Drill', 'Hair Dryer', 'Egg tart', + 'Jellyfish', 'Treadmill', 'Lighter', 'Grapefruit', 'Game board', 'Mop', 'Radish', 'Baozi', 'Target', 'French', + 'Spring Rolls', 'Monkey', 'Rabbit', 'Pencil Case', 'Yak', 'Red Cabbage', 'Binoculars', 'Asparagus', 'Barbell', + 'Scallop', 'Noddles', 'Comb', 'Dumpling', 'Oyster', 'Table Tennis paddle', 'Cosmetics Brush/Eyeliner Pencil', + 'Chainsaw', 'Eraser', 'Lobster', 'Durian', 'Okra', 'Lipstick', 'Cosmetics Mirror', 'Curling', 'Table Tennis'] -# download command/URL (optional) -------------------------------------------------------------------------------------- +# Download script/URL (optional) --------------------------------------------------------------------------------------- download: | from pycocotools.coco import COCO from tqdm import tqdm - from utils.general import download, Path + from utils.general import Path, download, np, xyxy2xywhn # Make Directories - dir = Path('../datasets/objects365') # dataset directory + dir = Path(yaml['path']) # dataset root dir for p in 'images', 'labels': (dir / p).mkdir(parents=True, exist_ok=True) for q in 'train', 'val': (dir / p / q).mkdir(parents=True, exist_ok=True) - # Download - url = "https://dorc.ks3-cn-beijing.ksyun.com/data-set/2020Objects365%E6%95%B0%E6%8D%AE%E9%9B%86/train/" - download([url + 'zhiyuan_objv2_train.tar.gz'], dir=dir, delete=False) # annotations json - download([url + f for f in [f'patch{i}.tar.gz' for i in range(51)]], dir=dir / 'images' / 'train', - curl=True, delete=False, threads=8) + # Train, Val Splits + for split, patches in [('train', 50 + 1), ('val', 43 + 1)]: + print(f"Processing {split} in {patches} patches ...") + images, labels = dir / 'images' / split, dir / 'labels' / split - # Move - train = dir / 'images' / 'train' - for f in tqdm(train.rglob('*.jpg'), desc=f'Moving images'): - f.rename(train / f.name) # move to /images/train + # Download + url = f"https://dorc.ks3-cn-beijing.ksyun.com/data-set/2020Objects365%E6%95%B0%E6%8D%AE%E9%9B%86/{split}/" + if split == 'train': + download([f'{url}zhiyuan_objv2_{split}.tar.gz'], dir=dir, delete=False) # annotations json + download([f'{url}patch{i}.tar.gz' for i in range(patches)], dir=images, curl=True, delete=False, threads=8) + elif split == 'val': + download([f'{url}zhiyuan_objv2_{split}.json'], dir=dir, delete=False) # annotations json + download([f'{url}images/v1/patch{i}.tar.gz' for i in range(15 + 1)], dir=images, curl=True, delete=False, threads=8) + download([f'{url}images/v2/patch{i}.tar.gz' for i in range(16, patches)], dir=images, curl=True, delete=False, threads=8) - # Labels - coco = COCO(dir / 'zhiyuan_objv2_train.json') - names = [x["name"] for x in coco.loadCats(coco.getCatIds())] - for cid, cat in enumerate(names): - catIds = coco.getCatIds(catNms=[cat]) - imgIds = coco.getImgIds(catIds=catIds) - for im in tqdm(coco.loadImgs(imgIds), desc=f'Class {cid + 1}/{len(names)} {cat}'): - width, height = im["width"], im["height"] - path = Path(im["file_name"]) # image filename - try: - with open(dir / 'labels' / 'train' / path.with_suffix('.txt').name, 'a') as file: - annIds = coco.getAnnIds(imgIds=im["id"], catIds=catIds, iscrowd=None) - for a in coco.loadAnns(annIds): - x, y, w, h = a['bbox'] # bounding box in xywh (xy top-left corner) - x, y = x + w / 2, y + h / 2 # xy to center - file.write(f"{cid} {x / width:.5f} {y / height:.5f} {w / width:.5f} {h / height:.5f}\n") + # Move + for f in tqdm(images.rglob('*.jpg'), desc=f'Moving {split} images'): + f.rename(images / f.name) # move to /images/{split} - except Exception as e: - print(e) + # Labels + coco = COCO(dir / f'zhiyuan_objv2_{split}.json') + names = [x["name"] for x in coco.loadCats(coco.getCatIds())] + for cid, cat in enumerate(names): + catIds = coco.getCatIds(catNms=[cat]) + imgIds = coco.getImgIds(catIds=catIds) + for im in tqdm(coco.loadImgs(imgIds), desc=f'Class {cid + 1}/{len(names)} {cat}'): + width, height = im["width"], im["height"] + path = Path(im["file_name"]) # image filename + try: + with open(labels / path.with_suffix('.txt').name, 'a') as file: + annIds = coco.getAnnIds(imgIds=im["id"], catIds=catIds, iscrowd=None) + for a in coco.loadAnns(annIds): + x, y, w, h = a['bbox'] # bounding box in xywh (xy top-left corner) + xyxy = np.array([x, y, x + w, y + h])[None] # pixels(1,4) + x, y, w, h = xyxy2xywhn(xyxy, w=width, h=height, clip=True)[0] # normalized and clipped + file.write(f"{cid} {x:.5f} {y:.5f} {w:.5f} {h:.5f}\n") + except Exception as e: + print(e) diff --git a/data/scripts/download_weights.sh b/data/scripts/download_weights.sh new file mode 100755 index 0000000000..50aec183ab --- /dev/null +++ b/data/scripts/download_weights.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# Download latest models from https://github.com/ultralytics/yolov3/releases +# Example usage: bash path/to/download_weights.sh +# parent +# └── yolov3 +# ├── yolov3.pt ← downloads here +# ├── yolov3-spp.pt +# └── ... + +python - <train.txt -cat 2007_train.txt 2007_val.txt 2007_test.txt 2012_train.txt 2012_val.txt >train.all.txt - -mkdir ../VOC ../VOC/images ../VOC/images/train ../VOC/images/val -mkdir ../VOC/labels ../VOC/labels/train ../VOC/labels/val - -python3 - "$@" <= cls >= 0, f'incorrect class index {cls}' + + # Write YOLO label + if id not in shapes: + shapes[id] = Image.open(file).size + box = xyxy2xywhn(box[None].astype(np.float), w=shapes[id][0], h=shapes[id][1], clip=True) + with open((labels / id).with_suffix('.txt'), 'a') as f: + f.write(f"{cls} {' '.join(f'{x:.6f}' for x in box[0])}\n") # write label.txt + except Exception as e: + print(f'WARNING: skipping one label for {file}: {e}') + + + # Download manually from https://challenge.xviewdataset.org + dir = Path(yaml['path']) # dataset root dir + # urls = ['https://d307kc0mrhucc3.cloudfront.net/train_labels.zip', # train labels + # 'https://d307kc0mrhucc3.cloudfront.net/train_images.zip', # 15G, 847 train images + # 'https://d307kc0mrhucc3.cloudfront.net/val_images.zip'] # 5G, 282 val images (no labels) + # download(urls, dir=dir, delete=False) + + # Convert labels + convert_labels(dir / 'xView_train.geojson') + + # Move images + images = Path(dir / 'images') + images.mkdir(parents=True, exist_ok=True) + Path(dir / 'train_images').rename(dir / 'images' / 'train') + Path(dir / 'val_images').rename(dir / 'images' / 'val') + + # Split + autosplit(dir / 'images' / 'train') diff --git a/detect.py b/detect.py index c2bec17e60..1ae4c3c402 100644 --- a/detect.py +++ b/detect.py @@ -1,98 +1,147 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Run inference on images, videos, directories, streams, etc. + +Usage: + $ python path/to/detect.py --weights yolov3.pt --source 0 # webcam + img.jpg # image + vid.mp4 # video + path/ # directory + path/*.jpg # glob + 'https://youtu.be/Zgi9g1ksQHc' # YouTube + 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream +""" + import argparse -import time +import os +import sys from pathlib import Path import cv2 import torch import torch.backends.cudnn as cudnn -from models.experimental import attempt_load -from utils.datasets import LoadStreams, LoadImages -from utils.general import check_img_size, check_requirements, check_imshow, non_max_suppression, apply_classifier, \ - scale_coords, xyxy2xywh, strip_optimizer, set_logging, increment_path, save_one_box -from utils.plots import colors, plot_one_box -from utils.torch_utils import select_device, load_classifier, time_synchronized +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.datasets import IMG_FORMATS, VID_FORMATS, LoadImages, LoadStreams +from utils.general import (LOGGER, check_file, check_img_size, check_imshow, check_requirements, colorstr, + increment_path, non_max_suppression, print_args, scale_coords, strip_optimizer, xyxy2xywh) +from utils.plots import Annotator, colors, save_one_box +from utils.torch_utils import select_device, time_sync @torch.no_grad() -def detect(opt): - source, weights, view_img, save_txt, imgsz = opt.source, opt.weights, opt.view_img, opt.save_txt, opt.img_size - save_img = not opt.nosave and not source.endswith('.txt') # save inference images - webcam = source.isnumeric() or source.endswith('.txt') or source.lower().startswith( - ('rtsp://', 'rtmp://', 'http://', 'https://')) +def run(weights=ROOT / 'yolov3.pt', # model.pt path(s) + source=ROOT / 'data/images', # file/dir/URL/glob, 0 for webcam + imgsz=640, # inference size (pixels) + conf_thres=0.25, # confidence threshold + iou_thres=0.45, # NMS IOU threshold + max_det=1000, # maximum detections per image + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + view_img=False, # show results + save_txt=False, # save results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_crop=False, # save cropped prediction boxes + nosave=False, # do not save images/videos + classes=None, # filter by class: --class 0, or --class 0 2 3 + agnostic_nms=False, # class-agnostic NMS + augment=False, # augmented inference + visualize=False, # visualize features + update=False, # update all models + project=ROOT / 'runs/detect', # save results to project/name + name='exp', # save results to project/name + exist_ok=False, # existing project/name ok, do not increment + line_thickness=3, # bounding box thickness (pixels) + hide_labels=False, # hide labels + hide_conf=False, # hide confidences + half=False, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + ): + source = str(source) + save_img = not nosave and not source.endswith('.txt') # save inference images + is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) + is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://')) + webcam = source.isnumeric() or source.endswith('.txt') or (is_url and not is_file) + if is_url and is_file: + source = check_file(source) # download # Directories - save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok) # increment run + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir - # Initialize - set_logging() - device = select_device(opt.device) - half = device.type != 'cpu' # half precision only supported on CUDA - # Load model - model = attempt_load(weights, map_location=device) # load FP32 model - stride = int(model.stride.max()) # model stride - imgsz = check_img_size(imgsz, s=stride) # check img_size - names = model.module.names if hasattr(model, 'module') else model.names # get class names - if half: - model.half() # to FP16 - - # Second-stage classifier - classify = False - if classify: - modelc = load_classifier(name='resnet101', n=2) # initialize - modelc.load_state_dict(torch.load('weights/resnet101.pt', map_location=device)['model']).to(device).eval() - - # Set Dataloader - vid_path, vid_writer = None, None + device = select_device(device) + model = DetectMultiBackend(weights, device=device, dnn=dnn) + stride, names, pt, jit, onnx = model.stride, model.names, model.pt, model.jit, model.onnx + imgsz = check_img_size(imgsz, s=stride) # check image size + + # Half + half &= pt and device.type != 'cpu' # half precision only supported by PyTorch on CUDA + if pt: + model.model.half() if half else model.model.float() + + # Dataloader if webcam: view_img = check_imshow() cudnn.benchmark = True # set True to speed up constant image size inference - dataset = LoadStreams(source, img_size=imgsz, stride=stride) + dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt and not jit) + bs = len(dataset) # batch_size else: - dataset = LoadImages(source, img_size=imgsz, stride=stride) + dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt and not jit) + bs = 1 # batch_size + vid_path, vid_writer = [None] * bs, [None] * bs # Run inference - if device.type != 'cpu': - model(torch.zeros(1, 3, imgsz, imgsz).to(device).type_as(next(model.parameters()))) # run once - t0 = time.time() - for path, img, im0s, vid_cap in dataset: - img = torch.from_numpy(img).to(device) - img = img.half() if half else img.float() # uint8 to fp16/32 - img /= 255.0 # 0 - 255 to 0.0 - 1.0 - if img.ndimension() == 3: - img = img.unsqueeze(0) + if pt and device.type != 'cpu': + model(torch.zeros(1, 3, *imgsz).to(device).type_as(next(model.model.parameters()))) # warmup + dt, seen = [0.0, 0.0, 0.0], 0 + for path, im, im0s, vid_cap, s in dataset: + t1 = time_sync() + im = torch.from_numpy(im).to(device) + im = im.half() if half else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + if len(im.shape) == 3: + im = im[None] # expand for batch dim + t2 = time_sync() + dt[0] += t2 - t1 # Inference - t1 = time_synchronized() - pred = model(img, augment=opt.augment)[0] + visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False + pred = model(im, augment=augment, visualize=visualize) + t3 = time_sync() + dt[1] += t3 - t2 - # Apply NMS - pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, opt.classes, opt.agnostic_nms, - max_det=opt.max_det) - t2 = time_synchronized() + # NMS + pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det) + dt[2] += time_sync() - t3 - # Apply Classifier - if classify: - pred = apply_classifier(pred, modelc, img, im0s) + # Second-stage classifier (optional) + # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s) - # Process detections - for i, det in enumerate(pred): # detections per image + # Process predictions + for i, det in enumerate(pred): # per image + seen += 1 if webcam: # batch_size >= 1 - p, s, im0, frame = path[i], f'{i}: ', im0s[i].copy(), dataset.count + p, im0, frame = path[i], im0s[i].copy(), dataset.count + s += f'{i}: ' else: - p, s, im0, frame = path, '', im0s.copy(), getattr(dataset, 'frame', 0) + p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0) p = Path(p) # to Path - save_path = str(save_dir / p.name) # img.jpg - txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # img.txt - s += '%gx%g ' % img.shape[2:] # print string + save_path = str(save_dir / p.name) # im.jpg + txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # im.txt + s += '%gx%g ' % im.shape[2:] # print string gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh - imc = im0.copy() if opt.save_crop else im0 # for opt.save_crop + imc = im0.copy() if save_crop else im0 # for save_crop + annotator = Annotator(im0, line_width=line_thickness, example=str(names)) if len(det): # Rescale boxes from img_size to im0 size - det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() + det[:, :4] = scale_coords(im.shape[2:], det[:, :4], im0.shape).round() # Print results for c in det[:, -1].unique(): @@ -103,21 +152,22 @@ def detect(opt): for *xyxy, conf, cls in reversed(det): if save_txt: # Write to file xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh - line = (cls, *xywh, conf) if opt.save_conf else (cls, *xywh) # label format + line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format with open(txt_path + '.txt', 'a') as f: f.write(('%g ' * len(line)).rstrip() % line + '\n') - if save_img or opt.save_crop or view_img: # Add bbox to image + if save_img or save_crop or view_img: # Add bbox to image c = int(cls) # integer class - label = None if opt.hide_labels else (names[c] if opt.hide_conf else f'{names[c]} {conf:.2f}') - plot_one_box(xyxy, im0, label=label, color=colors(c, True), line_thickness=opt.line_thickness) - if opt.save_crop: + label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}') + annotator.box_label(xyxy, label, color=colors(c, True)) + if save_crop: save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True) - # Print time (inference + NMS) - print(f'{s}Done. ({t2 - t1:.3f}s)') + # Print time (inference-only) + LOGGER.info(f'{s}Done. ({t3 - t2:.3f}s)') # Stream results + im0 = annotator.result() if view_img: cv2.imshow(str(p), im0) cv2.waitKey(1) # 1 millisecond @@ -127,10 +177,10 @@ def detect(opt): if dataset.mode == 'image': cv2.imwrite(save_path, im0) else: # 'video' or 'stream' - if vid_path != save_path: # new video - vid_path = save_path - if isinstance(vid_writer, cv2.VideoWriter): - vid_writer.release() # release previous video writer + if vid_path[i] != save_path: # new video + vid_path[i] = save_path + if isinstance(vid_writer[i], cv2.VideoWriter): + vid_writer[i].release() # release previous video writer if vid_cap: # video fps = vid_cap.get(cv2.CAP_PROP_FPS) w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) @@ -138,47 +188,57 @@ def detect(opt): else: # stream fps, w, h = 30, im0.shape[1], im0.shape[0] save_path += '.mp4' - vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) - vid_writer.write(im0) + vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) + vid_writer[i].write(im0) + # Print results + t = tuple(x / seen * 1E3 for x in dt) # speeds per image + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t) if save_txt or save_img: s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' - print(f"Results saved to {save_dir}{s}") + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + if update: + strip_optimizer(weights) # update model (to fix SourceChangeWarning) - print(f'Done. ({time.time() - t0:.3f}s)') - -if __name__ == '__main__': +def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--weights', nargs='+', type=str, default='yolov3.pt', help='model.pt path(s)') - parser.add_argument('--source', type=str, default='data/images', help='source') # file/folder, 0 for webcam - parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)') - parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold') - parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS') - parser.add_argument('--max-det', type=int, default=1000, help='maximum number of detections per image') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov3.pt', help='model path(s)') + parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob, 0 for webcam') + parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') + parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--view-img', action='store_true', help='display results') + parser.add_argument('--view-img', action='store_true', help='show results') parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes') parser.add_argument('--nosave', action='store_true', help='do not save images/videos') - parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3') + parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3') parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--visualize', action='store_true', help='visualize features') parser.add_argument('--update', action='store_true', help='update all models') - parser.add_argument('--project', default='runs/detect', help='save results to project/name') + parser.add_argument('--project', default=ROOT / 'runs/detect', help='save results to project/name') parser.add_argument('--name', default='exp', help='save results to project/name') parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)') parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels') parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') opt = parser.parse_args() - print(opt) - check_requirements(exclude=('tensorboard', 'pycocotools', 'thop')) + opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand + print_args(FILE.stem, opt) + return opt - if opt.update: # update all models (to fix SourceChangeWarning) - for opt.weights in ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt']: - detect(opt=opt) - strip_optimizer(opt.weights) - else: - detect(opt=opt) + +def main(opt): + check_requirements(exclude=('tensorboard', 'thop')) + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/export.py b/export.py new file mode 100644 index 0000000000..ce23cf5be1 --- /dev/null +++ b/export.py @@ -0,0 +1,369 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Export a PyTorch model to TorchScript, ONNX, CoreML, TensorFlow (saved_model, pb, TFLite, TF.js,) formats +TensorFlow exports authored by https://github.com/zldrobit + +Usage: + $ python path/to/export.py --weights yolov3.pt --include torchscript onnx coreml saved_model pb tflite tfjs + +Inference: + $ python path/to/detect.py --weights yolov3.pt + yolov3.onnx (must export with --dynamic) + yolov3_saved_model + yolov3.pb + yolov3.tflite + +TensorFlow.js: + $ cd .. && git clone https://github.com/zldrobit/tfjs-yolov5-example.git && cd tfjs-yolov5-example + $ npm install + $ ln -s ../../yolov5/yolov3_web_model public/yolov3_web_model + $ npm start +""" + +import argparse +import json +import os +import subprocess +import sys +import time +from pathlib import Path + +import torch +import torch.nn as nn +from torch.utils.mobile_optimizer import optimize_for_mobile + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import Conv +from models.experimental import attempt_load +from models.yolo import Detect +from utils.activations import SiLU +from utils.datasets import LoadImages +from utils.general import (LOGGER, check_dataset, check_img_size, check_requirements, colorstr, file_size, print_args, + url2file) +from utils.torch_utils import select_device + + +def export_torchscript(model, im, file, optimize, prefix=colorstr('TorchScript:')): + # TorchScript model export + try: + LOGGER.info(f'\n{prefix} starting export with torch {torch.__version__}...') + f = file.with_suffix('.torchscript.pt') + + ts = torch.jit.trace(model, im, strict=False) + d = {"shape": im.shape, "stride": int(max(model.stride)), "names": model.names} + extra_files = {'config.txt': json.dumps(d)} # torch._C.ExtraFilesMap() + (optimize_for_mobile(ts) if optimize else ts).save(f, _extra_files=extra_files) + + LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') + except Exception as e: + LOGGER.info(f'{prefix} export failure: {e}') + + +def export_onnx(model, im, file, opset, train, dynamic, simplify, prefix=colorstr('ONNX:')): + # ONNX export + try: + check_requirements(('onnx',)) + import onnx + + LOGGER.info(f'\n{prefix} starting export with onnx {onnx.__version__}...') + f = file.with_suffix('.onnx') + + torch.onnx.export(model, im, f, verbose=False, opset_version=opset, + training=torch.onnx.TrainingMode.TRAINING if train else torch.onnx.TrainingMode.EVAL, + do_constant_folding=not train, + input_names=['images'], + output_names=['output'], + dynamic_axes={'images': {0: 'batch', 2: 'height', 3: 'width'}, # shape(1,3,640,640) + 'output': {0: 'batch', 1: 'anchors'} # shape(1,25200,85) + } if dynamic else None) + + # Checks + model_onnx = onnx.load(f) # load onnx model + onnx.checker.check_model(model_onnx) # check onnx model + # LOGGER.info(onnx.helper.printable_graph(model_onnx.graph)) # print + + # Simplify + if simplify: + try: + check_requirements(('onnx-simplifier',)) + import onnxsim + + LOGGER.info(f'{prefix} simplifying with onnx-simplifier {onnxsim.__version__}...') + model_onnx, check = onnxsim.simplify( + model_onnx, + dynamic_input_shape=dynamic, + input_shapes={'images': list(im.shape)} if dynamic else None) + assert check, 'assert check failed' + onnx.save(model_onnx, f) + except Exception as e: + LOGGER.info(f'{prefix} simplifier failure: {e}') + LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') + LOGGER.info(f"{prefix} run --dynamic ONNX model inference with: 'python detect.py --weights {f}'") + except Exception as e: + LOGGER.info(f'{prefix} export failure: {e}') + + +def export_coreml(model, im, file, prefix=colorstr('CoreML:')): + # CoreML export + ct_model = None + try: + check_requirements(('coremltools',)) + import coremltools as ct + + LOGGER.info(f'\n{prefix} starting export with coremltools {ct.__version__}...') + f = file.with_suffix('.mlmodel') + + model.train() # CoreML exports should be placed in model.train() mode + ts = torch.jit.trace(model, im, strict=False) # TorchScript model + ct_model = ct.convert(ts, inputs=[ct.ImageType('image', shape=im.shape, scale=1 / 255, bias=[0, 0, 0])]) + ct_model.save(f) + + LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') + except Exception as e: + LOGGER.info(f'\n{prefix} export failure: {e}') + + return ct_model + + +def export_saved_model(model, im, file, dynamic, + tf_nms=False, agnostic_nms=False, topk_per_class=100, topk_all=100, iou_thres=0.45, + conf_thres=0.25, prefix=colorstr('TensorFlow saved_model:')): + # TensorFlow saved_model export + keras_model = None + try: + import tensorflow as tf + from tensorflow import keras + + from models.tf import TFDetect, TFModel + + LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') + f = str(file).replace('.pt', '_saved_model') + batch_size, ch, *imgsz = list(im.shape) # BCHW + + tf_model = TFModel(cfg=model.yaml, model=model, nc=model.nc, imgsz=imgsz) + im = tf.zeros((batch_size, *imgsz, 3)) # BHWC order for TensorFlow + y = tf_model.predict(im, tf_nms, agnostic_nms, topk_per_class, topk_all, iou_thres, conf_thres) + inputs = keras.Input(shape=(*imgsz, 3), batch_size=None if dynamic else batch_size) + outputs = tf_model.predict(inputs, tf_nms, agnostic_nms, topk_per_class, topk_all, iou_thres, conf_thres) + keras_model = keras.Model(inputs=inputs, outputs=outputs) + keras_model.trainable = False + keras_model.summary() + keras_model.save(f, save_format='tf') + + LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') + except Exception as e: + LOGGER.info(f'\n{prefix} export failure: {e}') + + return keras_model + + +def export_pb(keras_model, im, file, prefix=colorstr('TensorFlow GraphDef:')): + # TensorFlow GraphDef *.pb export https://github.com/leimao/Frozen_Graph_TensorFlow + try: + import tensorflow as tf + from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2 + + LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') + f = file.with_suffix('.pb') + + m = tf.function(lambda x: keras_model(x)) # full model + m = m.get_concrete_function(tf.TensorSpec(keras_model.inputs[0].shape, keras_model.inputs[0].dtype)) + frozen_func = convert_variables_to_constants_v2(m) + frozen_func.graph.as_graph_def() + tf.io.write_graph(graph_or_graph_def=frozen_func.graph, logdir=str(f.parent), name=f.name, as_text=False) + + LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') + except Exception as e: + LOGGER.info(f'\n{prefix} export failure: {e}') + + +def export_tflite(keras_model, im, file, int8, data, ncalib, prefix=colorstr('TensorFlow Lite:')): + # TensorFlow Lite export + try: + import tensorflow as tf + + from models.tf import representative_dataset_gen + + LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') + batch_size, ch, *imgsz = list(im.shape) # BCHW + f = str(file).replace('.pt', '-fp16.tflite') + + converter = tf.lite.TFLiteConverter.from_keras_model(keras_model) + converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS] + converter.target_spec.supported_types = [tf.float16] + converter.optimizations = [tf.lite.Optimize.DEFAULT] + if int8: + dataset = LoadImages(check_dataset(data)['train'], img_size=imgsz, auto=False) # representative data + converter.representative_dataset = lambda: representative_dataset_gen(dataset, ncalib) + converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] + converter.target_spec.supported_types = [] + converter.inference_input_type = tf.uint8 # or tf.int8 + converter.inference_output_type = tf.uint8 # or tf.int8 + converter.experimental_new_quantizer = False + f = str(file).replace('.pt', '-int8.tflite') + + tflite_model = converter.convert() + open(f, "wb").write(tflite_model) + LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') + + except Exception as e: + LOGGER.info(f'\n{prefix} export failure: {e}') + + +def export_tfjs(keras_model, im, file, prefix=colorstr('TensorFlow.js:')): + # TensorFlow.js export + try: + check_requirements(('tensorflowjs',)) + import re + + import tensorflowjs as tfjs + + LOGGER.info(f'\n{prefix} starting export with tensorflowjs {tfjs.__version__}...') + f = str(file).replace('.pt', '_web_model') # js dir + f_pb = file.with_suffix('.pb') # *.pb path + f_json = f + '/model.json' # *.json path + + cmd = f"tensorflowjs_converter --input_format=tf_frozen_model " \ + f"--output_node_names='Identity,Identity_1,Identity_2,Identity_3' {f_pb} {f}" + subprocess.run(cmd, shell=True) + + json = open(f_json).read() + with open(f_json, 'w') as j: # sort JSON Identity_* in ascending order + subst = re.sub( + r'{"outputs": {"Identity.?.?": {"name": "Identity.?.?"}, ' + r'"Identity.?.?": {"name": "Identity.?.?"}, ' + r'"Identity.?.?": {"name": "Identity.?.?"}, ' + r'"Identity.?.?": {"name": "Identity.?.?"}}}', + r'{"outputs": {"Identity": {"name": "Identity"}, ' + r'"Identity_1": {"name": "Identity_1"}, ' + r'"Identity_2": {"name": "Identity_2"}, ' + r'"Identity_3": {"name": "Identity_3"}}}', + json) + j.write(subst) + + LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') + except Exception as e: + LOGGER.info(f'\n{prefix} export failure: {e}') + + +@torch.no_grad() +def run(data=ROOT / 'data/coco128.yaml', # 'dataset.yaml path' + weights=ROOT / 'yolov3.pt', # weights path + imgsz=(640, 640), # image (height, width) + batch_size=1, # batch size + device='cpu', # cuda device, i.e. 0 or 0,1,2,3 or cpu + include=('torchscript', 'onnx', 'coreml'), # include formats + half=False, # FP16 half-precision export + inplace=False, # set Detect() inplace=True + train=False, # model.train() mode + optimize=False, # TorchScript: optimize for mobile + int8=False, # CoreML/TF INT8 quantization + dynamic=False, # ONNX/TF: dynamic axes + simplify=False, # ONNX: simplify model + opset=12, # ONNX: opset version + topk_per_class=100, # TF.js NMS: topk per class to keep + topk_all=100, # TF.js NMS: topk for all classes to keep + iou_thres=0.45, # TF.js NMS: IoU threshold + conf_thres=0.25 # TF.js NMS: confidence threshold + ): + t = time.time() + include = [x.lower() for x in include] + tf_exports = list(x in include for x in ('saved_model', 'pb', 'tflite', 'tfjs')) # TensorFlow exports + imgsz *= 2 if len(imgsz) == 1 else 1 # expand + file = Path(url2file(weights) if str(weights).startswith(('http:/', 'https:/')) else weights) + + # Load PyTorch model + device = select_device(device) + assert not (device.type == 'cpu' and half), '--half only compatible with GPU export, i.e. use --device 0' + model = attempt_load(weights, map_location=device, inplace=True, fuse=True) # load FP32 model + nc, names = model.nc, model.names # number of classes, class names + + # Input + gs = int(max(model.stride)) # grid size (max stride) + imgsz = [check_img_size(x, gs) for x in imgsz] # verify img_size are gs-multiples + im = torch.zeros(batch_size, 3, *imgsz).to(device) # image size(1,3,320,192) BCHW iDetection + + # Update model + if half: + im, model = im.half(), model.half() # to FP16 + model.train() if train else model.eval() # training mode = no Detect() layer grid construction + for k, m in model.named_modules(): + if isinstance(m, Conv): # assign export-friendly activations + if isinstance(m.act, nn.SiLU): + m.act = SiLU() + elif isinstance(m, Detect): + m.inplace = inplace + m.onnx_dynamic = dynamic + # m.forward = m.forward_export # assign forward (optional) + + for _ in range(2): + y = model(im) # dry runs + LOGGER.info(f"\n{colorstr('PyTorch:')} starting from {file} ({file_size(file):.1f} MB)") + + # Exports + if 'torchscript' in include: + export_torchscript(model, im, file, optimize) + if 'onnx' in include: + export_onnx(model, im, file, opset, train, dynamic, simplify) + if 'coreml' in include: + export_coreml(model, im, file) + + # TensorFlow Exports + if any(tf_exports): + pb, tflite, tfjs = tf_exports[1:] + assert not (tflite and tfjs), 'TFLite and TF.js models must be exported separately, please pass only one type.' + model = export_saved_model(model, im, file, dynamic, tf_nms=tfjs, agnostic_nms=tfjs, + topk_per_class=topk_per_class, topk_all=topk_all, conf_thres=conf_thres, + iou_thres=iou_thres) # keras model + if pb or tfjs: # pb prerequisite to tfjs + export_pb(model, im, file) + if tflite: + export_tflite(model, im, file, int8=int8, data=data, ncalib=100) + if tfjs: + export_tfjs(model, im, file) + + # Finish + LOGGER.info(f'\nExport complete ({time.time() - t:.2f}s)' + f"\nResults saved to {colorstr('bold', file.parent.resolve())}" + f'\nVisualize with https://netron.app') + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') + parser.add_argument('--weights', type=str, default=ROOT / 'yolov3.pt', help='weights path') + parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640, 640], help='image (h, w)') + parser.add_argument('--batch-size', type=int, default=1, help='batch size') + parser.add_argument('--device', default='cpu', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--half', action='store_true', help='FP16 half-precision export') + parser.add_argument('--inplace', action='store_true', help='set YOLOv3 Detect() inplace=True') + parser.add_argument('--train', action='store_true', help='model.train() mode') + parser.add_argument('--optimize', action='store_true', help='TorchScript: optimize for mobile') + parser.add_argument('--int8', action='store_true', help='CoreML/TF INT8 quantization') + parser.add_argument('--dynamic', action='store_true', help='ONNX/TF: dynamic axes') + parser.add_argument('--simplify', action='store_true', help='ONNX: simplify model') + parser.add_argument('--opset', type=int, default=13, help='ONNX: opset version') + parser.add_argument('--topk-per-class', type=int, default=100, help='TF.js NMS: topk per class to keep') + parser.add_argument('--topk-all', type=int, default=100, help='TF.js NMS: topk for all classes to keep') + parser.add_argument('--iou-thres', type=float, default=0.45, help='TF.js NMS: IoU threshold') + parser.add_argument('--conf-thres', type=float, default=0.25, help='TF.js NMS: confidence threshold') + parser.add_argument('--include', nargs='+', + default=['torchscript', 'onnx'], + help='available formats are (torchscript, onnx, coreml, saved_model, pb, tflite, tfjs)') + opt = parser.parse_args() + print_args(FILE.stem, opt) + return opt + + +def main(opt): + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/hubconf.py b/hubconf.py index 683e22f748..d610aa3672 100644 --- a/hubconf.py +++ b/hubconf.py @@ -1,56 +1,61 @@ -"""YOLOv3 PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov3/ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov5/ Usage: import torch - model = torch.hub.load('ultralytics/yolov3', 'yolov3_tiny') + model = torch.hub.load('ultralytics/yolov3', 'yolov3') """ import torch def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): - """Creates a specified YOLOv3 model + """Creates a specified model Arguments: name (str): name of model, i.e. 'yolov3' pretrained (bool): load pretrained weights into the model channels (int): number of input channels classes (int): number of model classes - autoshape (bool): apply YOLOv3 .autoshape() wrapper to model + autoshape (bool): apply .autoshape() wrapper to model verbose (bool): print all information to screen device (str, torch.device, None): device to use for model parameters Returns: - YOLOv3 pytorch model + pytorch model """ from pathlib import Path - from models.yolo import Model, attempt_load - from utils.general import check_requirements, set_logging - from utils.google_utils import attempt_download + from models.experimental import attempt_load + from models.yolo import Model + from utils.downloads import attempt_download + from utils.general import check_requirements, intersect_dicts, set_logging from utils.torch_utils import select_device - check_requirements(Path(__file__).parent / 'requirements.txt', exclude=('tensorboard', 'pycocotools', 'thop')) + file = Path(__file__).resolve() + check_requirements(exclude=('tensorboard', 'thop', 'opencv-python')) set_logging(verbose=verbose) - fname = Path(name).with_suffix('.pt') # checkpoint filename + save_dir = Path('') if str(name).endswith('.pt') else file.parent + path = (save_dir / name).with_suffix('.pt') # checkpoint path try: + device = select_device(('0' if torch.cuda.is_available() else 'cpu') if device is None else device) + if pretrained and channels == 3 and classes == 80: - model = attempt_load(fname, map_location=torch.device('cpu')) # download/load FP32 model + model = attempt_load(path, map_location=device) # download/load FP32 model else: cfg = list((Path(__file__).parent / 'models').rglob(f'{name}.yaml'))[0] # model.yaml path model = Model(cfg, channels, classes) # create model if pretrained: - ckpt = torch.load(attempt_download(fname), map_location=torch.device('cpu')) # load - msd = model.state_dict() # model state_dict + ckpt = torch.load(attempt_download(path), map_location=device) # load csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 - csd = {k: v for k, v in csd.items() if msd[k].shape == v.shape} # filter + csd = intersect_dicts(csd, model.state_dict(), exclude=['anchors']) # intersect model.load_state_dict(csd, strict=False) # load if len(ckpt['model'].names) == classes: model.names = ckpt['model'].names # set class names attribute if autoshape: model = model.autoshape() # for file/URI/PIL/cv2/np inputs and NMS - device = select_device('0' if torch.cuda.is_available() else 'cpu') if device is None else torch.device(device) return model.to(device) except Exception as e: @@ -60,7 +65,7 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbo def custom(path='path/to/model.pt', autoshape=True, verbose=True, device=None): - # YOLOv3 custom or local model + # custom or local model return _create(path, autoshape=autoshape, verbose=verbose, device=device) @@ -68,26 +73,31 @@ def yolov3(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True # YOLOv3 model https://github.com/ultralytics/yolov3 return _create('yolov3', pretrained, channels, classes, autoshape, verbose, device) + def yolov3_spp(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): # YOLOv3-SPP model https://github.com/ultralytics/yolov3 return _create('yolov3-spp', pretrained, channels, classes, autoshape, verbose, device) + def yolov3_tiny(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): # YOLOv3-tiny model https://github.com/ultralytics/yolov3 return _create('yolov3-tiny', pretrained, channels, classes, autoshape, verbose, device) if __name__ == '__main__': - model = _create(name='yolov3', pretrained=True, channels=3, classes=80, autoshape=True, verbose=True) # pretrained + model = _create(name='yolov3-tiny', pretrained=True, channels=3, classes=80, autoshape=True, verbose=True) # pretrained # model = custom(path='path/to/model.pt') # custom # Verify inference + from pathlib import Path + import cv2 import numpy as np from PIL import Image imgs = ['data/images/zidane.jpg', # filename - 'https://github.com/ultralytics/yolov5/releases/download/v1.0/zidane.jpg', # URI + Path('data/images/zidane.jpg'), # Path + 'https://ultralytics.com/images/zidane.jpg', # URI cv2.imread('data/images/bus.jpg')[:, :, ::-1], # OpenCV Image.open('data/images/bus.jpg'), # PIL np.zeros((320, 640, 3))] # numpy diff --git a/models/common.py b/models/common.py index 0b4e600459..82b348aebb 100644 --- a/models/common.py +++ b/models/common.py @@ -1,9 +1,16 @@ -# YOLOv3 common modules +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Common modules +""" +import json import math +import platform +import warnings from copy import copy from pathlib import Path +import cv2 import numpy as np import pandas as pd import requests @@ -12,10 +19,11 @@ from PIL import Image from torch.cuda import amp -from utils.datasets import letterbox -from utils.general import non_max_suppression, make_divisible, scale_coords, increment_path, xyxy2xywh, save_one_box -from utils.plots import colors, plot_one_box -from utils.torch_utils import time_synchronized +from utils.datasets import exif_transpose, letterbox +from utils.general import (LOGGER, check_requirements, check_suffix, colorstr, increment_path, make_divisible, + non_max_suppression, scale_coords, xywh2xyxy, xyxy2xywh) +from utils.plots import Annotator, colors, save_one_box +from utils.torch_utils import time_sync def autopad(k, p=None): # kernel, padding @@ -25,26 +33,27 @@ def autopad(k, p=None): # kernel, padding return p -def DWConv(c1, c2, k=1, s=1, act=True): - # Depthwise convolution - return Conv(c1, c2, k, s, g=math.gcd(c1, c2), act=act) - - class Conv(nn.Module): # Standard convolution def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups - super(Conv, self).__init__() + super().__init__() self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False) self.bn = nn.BatchNorm2d(c2) - self.act = nn.LeakyReLU(0.1) if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) + self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) def forward(self, x): return self.act(self.bn(self.conv(x))) - def fuseforward(self, x): + def forward_fuse(self, x): return self.act(self.conv(x)) +class DWConv(Conv): + # Depth-wise convolution class + def __init__(self, c1, c2, k=1, s=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups + super().__init__(c1, c2, k, s, g=math.gcd(c1, c2), act=act) + + class TransformerLayer(nn.Module): # Transformer layer https://arxiv.org/abs/2010.11929 (LayerNorm layers removed for better performance) def __init__(self, c, num_heads): @@ -70,31 +79,21 @@ def __init__(self, c1, c2, num_heads, num_layers): if c1 != c2: self.conv = Conv(c1, c2) self.linear = nn.Linear(c2, c2) # learnable position embedding - self.tr = nn.Sequential(*[TransformerLayer(c2, num_heads) for _ in range(num_layers)]) + self.tr = nn.Sequential(*(TransformerLayer(c2, num_heads) for _ in range(num_layers))) self.c2 = c2 def forward(self, x): if self.conv is not None: x = self.conv(x) b, _, w, h = x.shape - p = x.flatten(2) - p = p.unsqueeze(0) - p = p.transpose(0, 3) - p = p.squeeze(3) - e = self.linear(p) - x = p + e - - x = self.tr(x) - x = x.unsqueeze(3) - x = x.transpose(0, 3) - x = x.reshape(b, self.c2, w, h) - return x + p = x.flatten(2).unsqueeze(0).transpose(0, 3).squeeze(3) + return self.tr(p + self.linear(p)).unsqueeze(3).transpose(0, 3).reshape(b, self.c2, w, h) class Bottleneck(nn.Module): # Standard bottleneck def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion - super(Bottleneck, self).__init__() + super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, 1, 1) self.cv2 = Conv(c_, c2, 3, 1, g=g) @@ -107,15 +106,15 @@ def forward(self, x): class BottleneckCSP(nn.Module): # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion - super(BottleneckCSP, self).__init__() + super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, 1, 1) self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False) self.cv3 = nn.Conv2d(c_, c_, 1, 1, bias=False) self.cv4 = Conv(2 * c_, c2, 1, 1) self.bn = nn.BatchNorm2d(2 * c_) # applied to cat(cv2, cv3) - self.act = nn.LeakyReLU(0.1, inplace=True) - self.m = nn.Sequential(*[Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)]) + self.act = nn.SiLU() + self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n))) def forward(self, x): y1 = self.cv3(self.m(self.cv1(x))) @@ -126,12 +125,12 @@ def forward(self, x): class C3(nn.Module): # CSP Bottleneck with 3 convolutions def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion - super(C3, self).__init__() + super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, 1, 1) self.cv2 = Conv(c1, c_, 1, 1) self.cv3 = Conv(2 * c_, c2, 1) # act=FReLU(c2) - self.m = nn.Sequential(*[Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)]) + self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n))) # self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)]) def forward(self, x): @@ -146,10 +145,26 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): self.m = TransformerBlock(c_, c_, 4, n) +class C3SPP(C3): + # C3 module with SPP() + def __init__(self, c1, c2, k=(5, 9, 13), n=1, shortcut=True, g=1, e=0.5): + super().__init__(c1, c2, n, shortcut, g, e) + c_ = int(c2 * e) + self.m = SPP(c_, c_, k) + + +class C3Ghost(C3): + # C3 module with GhostBottleneck() + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): + super().__init__(c1, c2, n, shortcut, g, e) + c_ = int(c2 * e) # hidden channels + self.m = nn.Sequential(*(GhostBottleneck(c_, c_) for _ in range(n))) + + class SPP(nn.Module): - # Spatial pyramid pooling layer used in YOLOv3-SPP + # Spatial Pyramid Pooling (SPP) layer https://arxiv.org/abs/1406.4729 def __init__(self, c1, c2, k=(5, 9, 13)): - super(SPP, self).__init__() + super().__init__() c_ = c1 // 2 # hidden channels self.cv1 = Conv(c1, c_, 1, 1) self.cv2 = Conv(c_ * (len(k) + 1), c2, 1, 1) @@ -157,13 +172,33 @@ def __init__(self, c1, c2, k=(5, 9, 13)): def forward(self, x): x = self.cv1(x) - return self.cv2(torch.cat([x] + [m(x) for m in self.m], 1)) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning + return self.cv2(torch.cat([x] + [m(x) for m in self.m], 1)) + + +class SPPF(nn.Module): + # Spatial Pyramid Pooling - Fast (SPPF) layer for by Glenn Jocher + def __init__(self, c1, c2, k=5): # equivalent to SPP(k=(5, 9, 13)) + super().__init__() + c_ = c1 // 2 # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = Conv(c_ * 4, c2, 1, 1) + self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2) + + def forward(self, x): + x = self.cv1(x) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning + y1 = self.m(x) + y2 = self.m(y1) + return self.cv2(torch.cat([x, y1, y2, self.m(y2)], 1)) class Focus(nn.Module): # Focus wh information into c-space def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups - super(Focus, self).__init__() + super().__init__() self.conv = Conv(c1 * 4, c2, k, s, p, g, act) # self.contract = Contract(gain=2) @@ -172,6 +207,34 @@ def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2) # return self.conv(self.contract(x)) +class GhostConv(nn.Module): + # Ghost Convolution https://github.com/huawei-noah/ghostnet + def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups + super().__init__() + c_ = c2 // 2 # hidden channels + self.cv1 = Conv(c1, c_, k, s, None, g, act) + self.cv2 = Conv(c_, c_, 5, 1, None, c_, act) + + def forward(self, x): + y = self.cv1(x) + return torch.cat([y, self.cv2(y)], 1) + + +class GhostBottleneck(nn.Module): + # Ghost Bottleneck https://github.com/huawei-noah/ghostnet + def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride + super().__init__() + c_ = c2 // 2 + self.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # pw + DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw + GhostConv(c_, c2, 1, 1, act=False)) # pw-linear + self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False), + Conv(c1, c2, 1, 1, act=False)) if s == 2 else nn.Identity() + + def forward(self, x): + return self.conv(x) + self.shortcut(x) + + class Contract(nn.Module): # Contract width-height into channels, i.e. x(1,64,80,80) to x(1,256,40,40) def __init__(self, gain=2): @@ -179,11 +242,11 @@ def __init__(self, gain=2): self.gain = gain def forward(self, x): - N, C, H, W = x.size() # assert (H / s == 0) and (W / s == 0), 'Indivisible gain' + b, c, h, w = x.size() # assert (h / s == 0) and (W / s == 0), 'Indivisible gain' s = self.gain - x = x.view(N, C, H // s, s, W // s, s) # x(1,64,40,2,40,2) + x = x.view(b, c, h // s, s, w // s, s) # x(1,64,40,2,40,2) x = x.permute(0, 3, 5, 1, 2, 4).contiguous() # x(1,2,2,64,40,40) - return x.view(N, C * s * s, H // s, W // s) # x(1,256,40,40) + return x.view(b, c * s * s, h // s, w // s) # x(1,256,40,40) class Expand(nn.Module): @@ -193,64 +256,183 @@ def __init__(self, gain=2): self.gain = gain def forward(self, x): - N, C, H, W = x.size() # assert C / s ** 2 == 0, 'Indivisible gain' + b, c, h, w = x.size() # assert C / s ** 2 == 0, 'Indivisible gain' s = self.gain - x = x.view(N, s, s, C // s ** 2, H, W) # x(1,2,2,16,80,80) + x = x.view(b, s, s, c // s ** 2, h, w) # x(1,2,2,16,80,80) x = x.permute(0, 3, 4, 1, 5, 2).contiguous() # x(1,16,80,2,80,2) - return x.view(N, C // s ** 2, H * s, W * s) # x(1,16,160,160) + return x.view(b, c // s ** 2, h * s, w * s) # x(1,16,160,160) class Concat(nn.Module): # Concatenate a list of tensors along dimension def __init__(self, dimension=1): - super(Concat, self).__init__() + super().__init__() self.d = dimension def forward(self, x): return torch.cat(x, self.d) -class NMS(nn.Module): - # Non-Maximum Suppression (NMS) module - conf = 0.25 # confidence threshold - iou = 0.45 # IoU threshold - classes = None # (optional list) filter by class - max_det = 1000 # maximum number of detections per image - - def __init__(self): - super(NMS, self).__init__() - - def forward(self, x): - return non_max_suppression(x[0], self.conf, iou_thres=self.iou, classes=self.classes, max_det=self.max_det) +class DetectMultiBackend(nn.Module): + # MultiBackend class for python inference on various backends + def __init__(self, weights='yolov3.pt', device=None, dnn=True): + # Usage: + # PyTorch: weights = *.pt + # TorchScript: *.torchscript.pt + # CoreML: *.mlmodel + # TensorFlow: *_saved_model + # TensorFlow: *.pb + # TensorFlow Lite: *.tflite + # ONNX Runtime: *.onnx + # OpenCV DNN: *.onnx with dnn=True + super().__init__() + w = str(weights[0] if isinstance(weights, list) else weights) + suffix, suffixes = Path(w).suffix.lower(), ['.pt', '.onnx', '.tflite', '.pb', '', '.mlmodel'] + check_suffix(w, suffixes) # check weights have acceptable suffix + pt, onnx, tflite, pb, saved_model, coreml = (suffix == x for x in suffixes) # backend booleans + jit = pt and 'torchscript' in w.lower() + stride, names = 64, [f'class{i}' for i in range(1000)] # assign defaults + + if jit: # TorchScript + LOGGER.info(f'Loading {w} for TorchScript inference...') + extra_files = {'config.txt': ''} # model metadata + model = torch.jit.load(w, _extra_files=extra_files) + if extra_files['config.txt']: + d = json.loads(extra_files['config.txt']) # extra_files dict + stride, names = int(d['stride']), d['names'] + elif pt: # PyTorch + from models.experimental import attempt_load # scoped to avoid circular import + model = torch.jit.load(w) if 'torchscript' in w else attempt_load(weights, map_location=device) + stride = int(model.stride.max()) # model stride + names = model.module.names if hasattr(model, 'module') else model.names # get class names + elif coreml: # CoreML *.mlmodel + import coremltools as ct + model = ct.models.MLModel(w) + elif dnn: # ONNX OpenCV DNN + LOGGER.info(f'Loading {w} for ONNX OpenCV DNN inference...') + check_requirements(('opencv-python>=4.5.4',)) + net = cv2.dnn.readNetFromONNX(w) + elif onnx: # ONNX Runtime + LOGGER.info(f'Loading {w} for ONNX Runtime inference...') + check_requirements(('onnx', 'onnxruntime-gpu' if torch.has_cuda else 'onnxruntime')) + import onnxruntime + session = onnxruntime.InferenceSession(w, None) + else: # TensorFlow model (TFLite, pb, saved_model) + import tensorflow as tf + if pb: # https://www.tensorflow.org/guide/migrate#a_graphpb_or_graphpbtxt + def wrap_frozen_graph(gd, inputs, outputs): + x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=""), []) # wrapped + return x.prune(tf.nest.map_structure(x.graph.as_graph_element, inputs), + tf.nest.map_structure(x.graph.as_graph_element, outputs)) + + LOGGER.info(f'Loading {w} for TensorFlow *.pb inference...') + graph_def = tf.Graph().as_graph_def() + graph_def.ParseFromString(open(w, 'rb').read()) + frozen_func = wrap_frozen_graph(gd=graph_def, inputs="x:0", outputs="Identity:0") + elif saved_model: + LOGGER.info(f'Loading {w} for TensorFlow saved_model inference...') + model = tf.keras.models.load_model(w) + elif tflite: # https://www.tensorflow.org/lite/guide/python#install_tensorflow_lite_for_python + if 'edgetpu' in w.lower(): + LOGGER.info(f'Loading {w} for TensorFlow Edge TPU inference...') + import tflite_runtime.interpreter as tfli + delegate = {'Linux': 'libedgetpu.so.1', # install https://coral.ai/software/#edgetpu-runtime + 'Darwin': 'libedgetpu.1.dylib', + 'Windows': 'edgetpu.dll'}[platform.system()] + interpreter = tfli.Interpreter(model_path=w, experimental_delegates=[tfli.load_delegate(delegate)]) + else: + LOGGER.info(f'Loading {w} for TensorFlow Lite inference...') + interpreter = tf.lite.Interpreter(model_path=w) # load TFLite model + interpreter.allocate_tensors() # allocate + input_details = interpreter.get_input_details() # inputs + output_details = interpreter.get_output_details() # outputs + self.__dict__.update(locals()) # assign all variables to self + + def forward(self, im, augment=False, visualize=False, val=False): + # MultiBackend inference + b, ch, h, w = im.shape # batch, channel, height, width + if self.pt: # PyTorch + y = self.model(im) if self.jit else self.model(im, augment=augment, visualize=visualize) + return y if val else y[0] + elif self.coreml: # CoreML *.mlmodel + im = im.permute(0, 2, 3, 1).cpu().numpy() # torch BCHW to numpy BHWC shape(1,320,192,3) + im = Image.fromarray((im[0] * 255).astype('uint8')) + # im = im.resize((192, 320), Image.ANTIALIAS) + y = self.model.predict({'image': im}) # coordinates are xywh normalized + box = xywh2xyxy(y['coordinates'] * [[w, h, w, h]]) # xyxy pixels + conf, cls = y['confidence'].max(1), y['confidence'].argmax(1).astype(np.float) + y = np.concatenate((box, conf.reshape(-1, 1), cls.reshape(-1, 1)), 1) + elif self.onnx: # ONNX + im = im.cpu().numpy() # torch to numpy + if self.dnn: # ONNX OpenCV DNN + self.net.setInput(im) + y = self.net.forward() + else: # ONNX Runtime + y = self.session.run([self.session.get_outputs()[0].name], {self.session.get_inputs()[0].name: im})[0] + else: # TensorFlow model (TFLite, pb, saved_model) + im = im.permute(0, 2, 3, 1).cpu().numpy() # torch BCHW to numpy BHWC shape(1,320,192,3) + if self.pb: + y = self.frozen_func(x=self.tf.constant(im)).numpy() + elif self.saved_model: + y = self.model(im, training=False).numpy() + elif self.tflite: + input, output = self.input_details[0], self.output_details[0] + int8 = input['dtype'] == np.uint8 # is TFLite quantized uint8 model + if int8: + scale, zero_point = input['quantization'] + im = (im / scale + zero_point).astype(np.uint8) # de-scale + self.interpreter.set_tensor(input['index'], im) + self.interpreter.invoke() + y = self.interpreter.get_tensor(output['index']) + if int8: + scale, zero_point = output['quantization'] + y = (y.astype(np.float32) - zero_point) * scale # re-scale + y[..., 0] *= w # x + y[..., 1] *= h # y + y[..., 2] *= w # w + y[..., 3] *= h # h + y = torch.tensor(y) + return (y, []) if val else y class AutoShape(nn.Module): - # input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS + # input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS conf = 0.25 # NMS confidence threshold iou = 0.45 # NMS IoU threshold - classes = None # (optional list) filter by class + classes = None # (optional list) filter by class, i.e. = [0, 15, 16] for COCO persons, cats and dogs + multi_label = False # NMS multiple labels per box max_det = 1000 # maximum number of detections per image def __init__(self, model): - super(AutoShape, self).__init__() + super().__init__() self.model = model.eval() def autoshape(self): - print('AutoShape already enabled, skipping... ') # model already converted to model.autoshape() + LOGGER.info('AutoShape already enabled, skipping... ') # model already converted to model.autoshape() + return self + + def _apply(self, fn): + # Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers + self = super()._apply(fn) + m = self.model.model[-1] # Detect() + m.stride = fn(m.stride) + m.grid = list(map(fn, m.grid)) + if isinstance(m.anchor_grid, list): + m.anchor_grid = list(map(fn, m.anchor_grid)) return self @torch.no_grad() def forward(self, imgs, size=640, augment=False, profile=False): # Inference from various sources. For height=640, width=1280, RGB images example inputs are: - # filename: imgs = 'data/images/zidane.jpg' - # URI: = 'https://github.com/ultralytics/yolov5/releases/download/v1.0/zidane.jpg' + # file: imgs = 'data/images/zidane.jpg' # str or PosixPath + # URI: = 'https://ultralytics.com/images/zidane.jpg' # OpenCV: = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(640,1280,3) - # PIL: = Image.open('image.jpg') # HWC x(640,1280,3) + # PIL: = Image.open('image.jpg') or ImageGrab.grab() # HWC x(640,1280,3) # numpy: = np.zeros((640,1280,3)) # HWC # torch: = torch.zeros(16,3,320,640) # BCHW (scaled to size=640, 0-1 values) # multiple: = [Image.open('image1.jpg'), Image.open('image2.jpg'), ...] # list of images - t = [time_synchronized()] + t = [time_sync()] p = next(self.model.parameters()) # for device and type if isinstance(imgs, torch.Tensor): # torch with amp.autocast(enabled=p.device.type != 'cpu'): @@ -261,14 +443,15 @@ def forward(self, imgs, size=640, augment=False, profile=False): shape0, shape1, files = [], [], [] # image and inference shapes, filenames for i, im in enumerate(imgs): f = f'image{i}' # filename - if isinstance(im, str): # filename or uri - im, f = np.asarray(Image.open(requests.get(im, stream=True).raw if im.startswith('http') else im)), im + if isinstance(im, (str, Path)): # filename or uri + im, f = Image.open(requests.get(im, stream=True).raw if str(im).startswith('http') else im), im + im = np.asarray(exif_transpose(im)) elif isinstance(im, Image.Image): # PIL Image - im, f = np.asarray(im), getattr(im, 'filename', f) or f + im, f = np.asarray(exif_transpose(im)), getattr(im, 'filename', f) or f files.append(Path(f).with_suffix('.jpg').name) if im.shape[0] < 5: # image in CHW im = im.transpose((1, 2, 0)) # reverse dataloader .transpose(2, 0, 1) - im = im[:, :, :3] if im.ndim == 3 else np.tile(im[:, :, None], 3) # enforce 3ch input + im = im[..., :3] if im.ndim == 3 else np.tile(im[..., None], 3) # enforce 3ch input s = im.shape[:2] # HWC shape0.append(s) # image shape g = (size / max(s)) # gain @@ -278,29 +461,30 @@ def forward(self, imgs, size=640, augment=False, profile=False): x = [letterbox(im, new_shape=shape1, auto=False)[0] for im in imgs] # pad x = np.stack(x, 0) if n > 1 else x[0][None] # stack x = np.ascontiguousarray(x.transpose((0, 3, 1, 2))) # BHWC to BCHW - x = torch.from_numpy(x).to(p.device).type_as(p) / 255. # uint8 to fp16/32 - t.append(time_synchronized()) + x = torch.from_numpy(x).to(p.device).type_as(p) / 255 # uint8 to fp16/32 + t.append(time_sync()) with amp.autocast(enabled=p.device.type != 'cpu'): # Inference y = self.model(x, augment, profile)[0] # forward - t.append(time_synchronized()) + t.append(time_sync()) # Post-process - y = non_max_suppression(y, self.conf, iou_thres=self.iou, classes=self.classes, max_det=self.max_det) # NMS + y = non_max_suppression(y, self.conf, iou_thres=self.iou, classes=self.classes, + multi_label=self.multi_label, max_det=self.max_det) # NMS for i in range(n): scale_coords(shape1, y[i][:, :4], shape0[i]) - t.append(time_synchronized()) + t.append(time_sync()) return Detections(imgs, y, files, t, self.names, x.shape) class Detections: - # detections class for YOLOv3 inference results + # detections class for inference results def __init__(self, imgs, pred, files, times=None, names=None, shape=None): - super(Detections, self).__init__() + super().__init__() d = pred[0].device # device - gn = [torch.tensor([*[im.shape[i] for i in [1, 0, 1, 0]], 1., 1.], device=d) for im in imgs] # normalizations + gn = [torch.tensor([*(im.shape[i] for i in [1, 0, 1, 0]), 1, 1], device=d) for im in imgs] # normalizations self.imgs = imgs # list of images as numpy arrays self.pred = pred # list of tensors pred[0] = (xyxy, conf, cls) self.names = names # class names @@ -314,47 +498,59 @@ def __init__(self, imgs, pred, files, times=None, names=None, shape=None): self.s = shape # inference BCHW shape def display(self, pprint=False, show=False, save=False, crop=False, render=False, save_dir=Path('')): + crops = [] for i, (im, pred) in enumerate(zip(self.imgs, self.pred)): - str = f'image {i + 1}/{len(self.pred)}: {im.shape[0]}x{im.shape[1]} ' - if pred is not None: + s = f'image {i + 1}/{len(self.pred)}: {im.shape[0]}x{im.shape[1]} ' # string + if pred.shape[0]: for c in pred[:, -1].unique(): n = (pred[:, -1] == c).sum() # detections per class - str += f"{n} {self.names[int(c)]}{'s' * (n > 1)}, " # add to string + s += f"{n} {self.names[int(c)]}{'s' * (n > 1)}, " # add to string if show or save or render or crop: - for *box, conf, cls in pred: # xyxy, confidence, class + annotator = Annotator(im, example=str(self.names)) + for *box, conf, cls in reversed(pred): # xyxy, confidence, class label = f'{self.names[int(cls)]} {conf:.2f}' if crop: - save_one_box(box, im, file=save_dir / 'crops' / self.names[int(cls)] / self.files[i]) + file = save_dir / 'crops' / self.names[int(cls)] / self.files[i] if save else None + crops.append({'box': box, 'conf': conf, 'cls': cls, 'label': label, + 'im': save_one_box(box, im, file=file, save=save)}) else: # all others - plot_one_box(box, im, label=label, color=colors(cls)) + annotator.box_label(box, label, color=colors(cls)) + im = annotator.im + else: + s += '(no detections)' im = Image.fromarray(im.astype(np.uint8)) if isinstance(im, np.ndarray) else im # from np if pprint: - print(str.rstrip(', ')) + LOGGER.info(s.rstrip(', ')) if show: im.show(self.files[i]) # show if save: f = self.files[i] im.save(save_dir / f) # save - print(f"{'Saved' * (i == 0)} {f}", end=',' if i < self.n - 1 else f' to {save_dir}\n') + if i == self.n - 1: + LOGGER.info(f"Saved {self.n} image{'s' * (self.n > 1)} to {colorstr('bold', save_dir)}") if render: self.imgs[i] = np.asarray(im) + if crop: + if save: + LOGGER.info(f'Saved results to {save_dir}\n') + return crops def print(self): self.display(pprint=True) # print results - print(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {tuple(self.s)}' % self.t) + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {tuple(self.s)}' % + self.t) def show(self): self.display(show=True) # show results - def save(self, save_dir='runs/hub/exp'): - save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/hub/exp', mkdir=True) # increment save_dir + def save(self, save_dir='runs/detect/exp'): + save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/detect/exp', mkdir=True) # increment save_dir self.display(save=True, save_dir=save_dir) # save results - def crop(self, save_dir='runs/hub/exp'): - save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/hub/exp', mkdir=True) # increment save_dir - self.display(crop=True, save_dir=save_dir) # crop results - print(f'Saved results to {save_dir}\n') + def crop(self, save=True, save_dir='runs/detect/exp'): + save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/detect/exp', mkdir=True) if save else None + return self.display(crop=True, save=save, save_dir=save_dir) # crop results def render(self): self.display(render=True) # render results @@ -385,7 +581,7 @@ def __len__(self): class Classify(nn.Module): # Classification head, i.e. x(b,c1,20,20) to x(b,c2) def __init__(self, c1, c2, k=1, s=1, p=None, g=1): # ch_in, ch_out, kernel, stride, padding, groups - super(Classify, self).__init__() + super().__init__() self.aap = nn.AdaptiveAvgPool2d(1) # to x(b,c1,1,1) self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g) # to x(b,c2,1,1) self.flat = nn.Flatten() diff --git a/models/experimental.py b/models/experimental.py index 867c8db5cd..81fc9bb222 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -1,18 +1,22 @@ -# YOLOv3 experimental modules +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Experimental modules +""" +import math import numpy as np import torch import torch.nn as nn -from models.common import Conv, DWConv -from utils.google_utils import attempt_download +from models.common import Conv +from utils.downloads import attempt_download class CrossConv(nn.Module): # Cross Convolution Downsample def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False): # ch_in, ch_out, kernel, stride, groups, expansion, shortcut - super(CrossConv, self).__init__() + super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, (1, k), (1, s)) self.cv2 = Conv(c_, c2, (k, 1), (s, 1), g=g) @@ -25,11 +29,11 @@ def forward(self, x): class Sum(nn.Module): # Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 def __init__(self, n, weight=False): # n: number of inputs - super(Sum, self).__init__() + super().__init__() self.weight = weight # apply weights boolean self.iter = range(n - 1) # iter object if weight: - self.w = nn.Parameter(-torch.arange(1., n) / 2, requires_grad=True) # layer weights + self.w = nn.Parameter(-torch.arange(1.0, n) / 2, requires_grad=True) # layer weights def forward(self, x): y = x[0] # no weight @@ -43,86 +47,66 @@ def forward(self, x): return y -class GhostConv(nn.Module): - # Ghost Convolution https://github.com/huawei-noah/ghostnet - def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups - super(GhostConv, self).__init__() - c_ = c2 // 2 # hidden channels - self.cv1 = Conv(c1, c_, k, s, None, g, act) - self.cv2 = Conv(c_, c_, 5, 1, None, c_, act) - - def forward(self, x): - y = self.cv1(x) - return torch.cat([y, self.cv2(y)], 1) - - -class GhostBottleneck(nn.Module): - # Ghost Bottleneck https://github.com/huawei-noah/ghostnet - def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride - super(GhostBottleneck, self).__init__() - c_ = c2 // 2 - self.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # pw - DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw - GhostConv(c_, c2, 1, 1, act=False)) # pw-linear - self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False), - Conv(c1, c2, 1, 1, act=False)) if s == 2 else nn.Identity() - - def forward(self, x): - return self.conv(x) + self.shortcut(x) - - class MixConv2d(nn.Module): - # Mixed Depthwise Conv https://arxiv.org/abs/1907.09595 - def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): - super(MixConv2d, self).__init__() - groups = len(k) + # Mixed Depth-wise Conv https://arxiv.org/abs/1907.09595 + def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): # ch_in, ch_out, kernel, stride, ch_strategy + super().__init__() + n = len(k) # number of convolutions if equal_ch: # equal c_ per group - i = torch.linspace(0, groups - 1E-6, c2).floor() # c2 indices - c_ = [(i == g).sum() for g in range(groups)] # intermediate channels + i = torch.linspace(0, n - 1E-6, c2).floor() # c2 indices + c_ = [(i == g).sum() for g in range(n)] # intermediate channels else: # equal weight.numel() per group - b = [c2] + [0] * groups - a = np.eye(groups + 1, groups, k=-1) + b = [c2] + [0] * n + a = np.eye(n + 1, n, k=-1) a -= np.roll(a, 1, axis=1) a *= np.array(k) ** 2 a[0] = 1 c_ = np.linalg.lstsq(a, b, rcond=None)[0].round() # solve for equal weight indices, ax = b - self.m = nn.ModuleList([nn.Conv2d(c1, int(c_[g]), k[g], s, k[g] // 2, bias=False) for g in range(groups)]) + self.m = nn.ModuleList( + [nn.Conv2d(c1, int(c_), k, s, k // 2, groups=math.gcd(c1, int(c_)), bias=False) for k, c_ in zip(k, c_)]) self.bn = nn.BatchNorm2d(c2) - self.act = nn.LeakyReLU(0.1, inplace=True) + self.act = nn.SiLU() def forward(self, x): - return x + self.act(self.bn(torch.cat([m(x) for m in self.m], 1))) + return self.act(self.bn(torch.cat([m(x) for m in self.m], 1))) class Ensemble(nn.ModuleList): # Ensemble of models def __init__(self): - super(Ensemble, self).__init__() + super().__init__() - def forward(self, x, augment=False): + def forward(self, x, augment=False, profile=False, visualize=False): y = [] for module in self: - y.append(module(x, augment)[0]) + y.append(module(x, augment, profile, visualize)[0]) # y = torch.stack(y).max(0)[0] # max ensemble # y = torch.stack(y).mean(0) # mean ensemble y = torch.cat(y, 1) # nms ensemble return y, None # inference, train output -def attempt_load(weights, map_location=None, inplace=True): +def attempt_load(weights, map_location=None, inplace=True, fuse=True): from models.yolo import Detect, Model # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a model = Ensemble() for w in weights if isinstance(weights, list) else [weights]: ckpt = torch.load(attempt_download(w), map_location=map_location) # load - model.append(ckpt['ema' if ckpt.get('ema') else 'model'].float().fuse().eval()) # FP32 model + if fuse: + model.append(ckpt['ema' if ckpt.get('ema') else 'model'].float().fuse().eval()) # FP32 model + else: + model.append(ckpt['ema' if ckpt.get('ema') else 'model'].float().eval()) # without layer fuse # Compatibility updates for m in model.modules(): if type(m) in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Model]: m.inplace = inplace # pytorch 1.7.0 compatibility + if type(m) is Detect: + if not isinstance(m.anchor_grid, list): # new Detect Layer compatibility + delattr(m, 'anchor_grid') + setattr(m, 'anchor_grid', [torch.zeros(1)] * m.nl) elif type(m) is Conv: m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility diff --git a/models/export.py b/models/export.py deleted file mode 100644 index 8da43b3a5e..0000000000 --- a/models/export.py +++ /dev/null @@ -1,145 +0,0 @@ -"""Exports a YOLOv3 *.pt model to TorchScript, ONNX, CoreML formats - -Usage: - $ python path/to/models/export.py --weights yolov3.pt --img 640 --batch 1 -""" - -import argparse -import sys -import time -from pathlib import Path - -sys.path.append(Path(__file__).parent.parent.absolute().__str__()) # to run '$ python *.py' files in subdirectories - -import torch -import torch.nn as nn -from torch.utils.mobile_optimizer import optimize_for_mobile - -import models -from models.experimental import attempt_load -from utils.activations import Hardswish, SiLU -from utils.general import colorstr, check_img_size, check_requirements, file_size, set_logging -from utils.torch_utils import select_device - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default='./yolov3.pt', help='weights path') - parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='image size') # height, width - parser.add_argument('--batch-size', type=int, default=1, help='batch size') - parser.add_argument('--device', default='cpu', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--include', nargs='+', default=['torchscript', 'onnx', 'coreml'], help='include formats') - parser.add_argument('--half', action='store_true', help='FP16 half-precision export') - parser.add_argument('--inplace', action='store_true', help='set YOLOv3 Detect() inplace=True') - parser.add_argument('--train', action='store_true', help='model.train() mode') - parser.add_argument('--optimize', action='store_true', help='optimize TorchScript for mobile') # TorchScript-only - parser.add_argument('--dynamic', action='store_true', help='dynamic ONNX axes') # ONNX-only - parser.add_argument('--simplify', action='store_true', help='simplify ONNX model') # ONNX-only - parser.add_argument('--opset-version', type=int, default=12, help='ONNX opset version') # ONNX-only - opt = parser.parse_args() - opt.img_size *= 2 if len(opt.img_size) == 1 else 1 # expand - opt.include = [x.lower() for x in opt.include] - print(opt) - set_logging() - t = time.time() - - # Load PyTorch model - device = select_device(opt.device) - model = attempt_load(opt.weights, map_location=device) # load FP32 model - labels = model.names - - # Checks - gs = int(max(model.stride)) # grid size (max stride) - opt.img_size = [check_img_size(x, gs) for x in opt.img_size] # verify img_size are gs-multiples - assert not (opt.device.lower() == 'cpu' and opt.half), '--half only compatible with GPU export, i.e. use --device 0' - - # Input - img = torch.zeros(opt.batch_size, 3, *opt.img_size).to(device) # image size(1,3,320,192) iDetection - - # Update model - if opt.half: - img, model = img.half(), model.half() # to FP16 - if opt.train: - model.train() # training mode (no grid construction in Detect layer) - for k, m in model.named_modules(): - m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility - if isinstance(m, models.common.Conv): # assign export-friendly activations - if isinstance(m.act, nn.Hardswish): - m.act = Hardswish() - elif isinstance(m.act, nn.SiLU): - m.act = SiLU() - elif isinstance(m, models.yolo.Detect): - m.inplace = opt.inplace - m.onnx_dynamic = opt.dynamic - # m.forward = m.forward_export # assign forward (optional) - - for _ in range(2): - y = model(img) # dry runs - print(f"\n{colorstr('PyTorch:')} starting from {opt.weights} ({file_size(opt.weights):.1f} MB)") - - # TorchScript export ----------------------------------------------------------------------------------------------- - if 'torchscript' in opt.include or 'coreml' in opt.include: - prefix = colorstr('TorchScript:') - try: - print(f'\n{prefix} starting export with torch {torch.__version__}...') - f = opt.weights.replace('.pt', '.torchscript.pt') # filename - ts = torch.jit.trace(model, img, strict=False) - (optimize_for_mobile(ts) if opt.optimize else ts).save(f) - print(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') - except Exception as e: - print(f'{prefix} export failure: {e}') - - # ONNX export ------------------------------------------------------------------------------------------------------ - if 'onnx' in opt.include: - prefix = colorstr('ONNX:') - try: - import onnx - - print(f'{prefix} starting export with onnx {onnx.__version__}...') - f = opt.weights.replace('.pt', '.onnx') # filename - torch.onnx.export(model, img, f, verbose=False, opset_version=opt.opset_version, input_names=['images'], - training=torch.onnx.TrainingMode.TRAINING if opt.train else torch.onnx.TrainingMode.EVAL, - do_constant_folding=not opt.train, - dynamic_axes={'images': {0: 'batch', 2: 'height', 3: 'width'}, # size(1,3,640,640) - 'output': {0: 'batch', 2: 'y', 3: 'x'}} if opt.dynamic else None) - - # Checks - model_onnx = onnx.load(f) # load onnx model - onnx.checker.check_model(model_onnx) # check onnx model - # print(onnx.helper.printable_graph(model_onnx.graph)) # print - - # Simplify - if opt.simplify: - try: - check_requirements(['onnx-simplifier']) - import onnxsim - - print(f'{prefix} simplifying with onnx-simplifier {onnxsim.__version__}...') - model_onnx, check = onnxsim.simplify( - model_onnx, - dynamic_input_shape=opt.dynamic, - input_shapes={'images': list(img.shape)} if opt.dynamic else None) - assert check, 'assert check failed' - onnx.save(model_onnx, f) - except Exception as e: - print(f'{prefix} simplifier failure: {e}') - print(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') - except Exception as e: - print(f'{prefix} export failure: {e}') - - # CoreML export ---------------------------------------------------------------------------------------------------- - if 'coreml' in opt.include: - prefix = colorstr('CoreML:') - try: - import coremltools as ct - - print(f'{prefix} starting export with coremltools {ct.__version__}...') - assert opt.train, 'CoreML exports should be placed in model.train() mode with `python export.py --train`' - model = ct.convert(ts, inputs=[ct.ImageType('image', shape=img.shape, scale=1 / 255.0, bias=[0, 0, 0])]) - f = opt.weights.replace('.pt', '.mlmodel') # filename - model.save(f) - print(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') - except Exception as e: - print(f'{prefix} export failure: {e}') - - # Finish - print(f'\nExport complete ({time.time() - t:.2f}s). Visualize with https://github.com/lutzroeder/netron.') diff --git a/models/tf.py b/models/tf.py new file mode 100644 index 0000000000..4076c9eab5 --- /dev/null +++ b/models/tf.py @@ -0,0 +1,465 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +TensorFlow, Keras and TFLite versions of +Authored by https://github.com/zldrobit in PR https://github.com/ultralytics/yolov5/pull/1127 + +Usage: + $ python models/tf.py --weights yolov3.pt + +Export: + $ python path/to/export.py --weights yolov3.pt --include saved_model pb tflite tfjs +""" + +import argparse +import logging +import sys +from copy import deepcopy +from pathlib import Path + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +# ROOT = ROOT.relative_to(Path.cwd()) # relative + +import numpy as np +import tensorflow as tf +import torch +import torch.nn as nn +from tensorflow import keras + +from models.common import C3, SPP, SPPF, Bottleneck, BottleneckCSP, Concat, Conv, DWConv, Focus, autopad +from models.experimental import CrossConv, MixConv2d, attempt_load +from models.yolo import Detect +from utils.activations import SiLU +from utils.general import LOGGER, make_divisible, print_args + + +class TFBN(keras.layers.Layer): + # TensorFlow BatchNormalization wrapper + def __init__(self, w=None): + super().__init__() + self.bn = keras.layers.BatchNormalization( + beta_initializer=keras.initializers.Constant(w.bias.numpy()), + gamma_initializer=keras.initializers.Constant(w.weight.numpy()), + moving_mean_initializer=keras.initializers.Constant(w.running_mean.numpy()), + moving_variance_initializer=keras.initializers.Constant(w.running_var.numpy()), + epsilon=w.eps) + + def call(self, inputs): + return self.bn(inputs) + + +class TFPad(keras.layers.Layer): + def __init__(self, pad): + super().__init__() + self.pad = tf.constant([[0, 0], [pad, pad], [pad, pad], [0, 0]]) + + def call(self, inputs): + return tf.pad(inputs, self.pad, mode='constant', constant_values=0) + + +class TFConv(keras.layers.Layer): + # Standard convolution + def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None): + # ch_in, ch_out, weights, kernel, stride, padding, groups + super().__init__() + assert g == 1, "TF v2.2 Conv2D does not support 'groups' argument" + assert isinstance(k, int), "Convolution with multiple kernels are not allowed." + # TensorFlow convolution padding is inconsistent with PyTorch (e.g. k=3 s=2 'SAME' padding) + # see https://stackoverflow.com/questions/52975843/comparing-conv2d-with-padding-between-tensorflow-and-pytorch + + conv = keras.layers.Conv2D( + c2, k, s, 'SAME' if s == 1 else 'VALID', use_bias=False if hasattr(w, 'bn') else True, + kernel_initializer=keras.initializers.Constant(w.conv.weight.permute(2, 3, 1, 0).numpy()), + bias_initializer='zeros' if hasattr(w, 'bn') else keras.initializers.Constant(w.conv.bias.numpy())) + self.conv = conv if s == 1 else keras.Sequential([TFPad(autopad(k, p)), conv]) + self.bn = TFBN(w.bn) if hasattr(w, 'bn') else tf.identity + + # activations + if isinstance(w.act, nn.LeakyReLU): + self.act = (lambda x: keras.activations.relu(x, alpha=0.1)) if act else tf.identity + elif isinstance(w.act, nn.Hardswish): + self.act = (lambda x: x * tf.nn.relu6(x + 3) * 0.166666667) if act else tf.identity + elif isinstance(w.act, (nn.SiLU, SiLU)): + self.act = (lambda x: keras.activations.swish(x)) if act else tf.identity + else: + raise Exception(f'no matching TensorFlow activation found for {w.act}') + + def call(self, inputs): + return self.act(self.bn(self.conv(inputs))) + + +class TFFocus(keras.layers.Layer): + # Focus wh information into c-space + def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None): + # ch_in, ch_out, kernel, stride, padding, groups + super().__init__() + self.conv = TFConv(c1 * 4, c2, k, s, p, g, act, w.conv) + + def call(self, inputs): # x(b,w,h,c) -> y(b,w/2,h/2,4c) + # inputs = inputs / 255 # normalize 0-255 to 0-1 + return self.conv(tf.concat([inputs[:, ::2, ::2, :], + inputs[:, 1::2, ::2, :], + inputs[:, ::2, 1::2, :], + inputs[:, 1::2, 1::2, :]], 3)) + + +class TFBottleneck(keras.layers.Layer): + # Standard bottleneck + def __init__(self, c1, c2, shortcut=True, g=1, e=0.5, w=None): # ch_in, ch_out, shortcut, groups, expansion + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) + self.cv2 = TFConv(c_, c2, 3, 1, g=g, w=w.cv2) + self.add = shortcut and c1 == c2 + + def call(self, inputs): + return inputs + self.cv2(self.cv1(inputs)) if self.add else self.cv2(self.cv1(inputs)) + + +class TFConv2d(keras.layers.Layer): + # Substitution for PyTorch nn.Conv2D + def __init__(self, c1, c2, k, s=1, g=1, bias=True, w=None): + super().__init__() + assert g == 1, "TF v2.2 Conv2D does not support 'groups' argument" + self.conv = keras.layers.Conv2D( + c2, k, s, 'VALID', use_bias=bias, + kernel_initializer=keras.initializers.Constant(w.weight.permute(2, 3, 1, 0).numpy()), + bias_initializer=keras.initializers.Constant(w.bias.numpy()) if bias else None, ) + + def call(self, inputs): + return self.conv(inputs) + + +class TFBottleneckCSP(keras.layers.Layer): + # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): + # ch_in, ch_out, number, shortcut, groups, expansion + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) + self.cv2 = TFConv2d(c1, c_, 1, 1, bias=False, w=w.cv2) + self.cv3 = TFConv2d(c_, c_, 1, 1, bias=False, w=w.cv3) + self.cv4 = TFConv(2 * c_, c2, 1, 1, w=w.cv4) + self.bn = TFBN(w.bn) + self.act = lambda x: keras.activations.relu(x, alpha=0.1) + self.m = keras.Sequential([TFBottleneck(c_, c_, shortcut, g, e=1.0, w=w.m[j]) for j in range(n)]) + + def call(self, inputs): + y1 = self.cv3(self.m(self.cv1(inputs))) + y2 = self.cv2(inputs) + return self.cv4(self.act(self.bn(tf.concat((y1, y2), axis=3)))) + + +class TFC3(keras.layers.Layer): + # CSP Bottleneck with 3 convolutions + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): + # ch_in, ch_out, number, shortcut, groups, expansion + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) + self.cv2 = TFConv(c1, c_, 1, 1, w=w.cv2) + self.cv3 = TFConv(2 * c_, c2, 1, 1, w=w.cv3) + self.m = keras.Sequential([TFBottleneck(c_, c_, shortcut, g, e=1.0, w=w.m[j]) for j in range(n)]) + + def call(self, inputs): + return self.cv3(tf.concat((self.m(self.cv1(inputs)), self.cv2(inputs)), axis=3)) + + +class TFSPP(keras.layers.Layer): + # Spatial pyramid pooling layer used in YOLOv3-SPP + def __init__(self, c1, c2, k=(5, 9, 13), w=None): + super().__init__() + c_ = c1 // 2 # hidden channels + self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) + self.cv2 = TFConv(c_ * (len(k) + 1), c2, 1, 1, w=w.cv2) + self.m = [keras.layers.MaxPool2D(pool_size=x, strides=1, padding='SAME') for x in k] + + def call(self, inputs): + x = self.cv1(inputs) + return self.cv2(tf.concat([x] + [m(x) for m in self.m], 3)) + + +class TFSPPF(keras.layers.Layer): + # Spatial pyramid pooling-Fast layer + def __init__(self, c1, c2, k=5, w=None): + super().__init__() + c_ = c1 // 2 # hidden channels + self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) + self.cv2 = TFConv(c_ * 4, c2, 1, 1, w=w.cv2) + self.m = keras.layers.MaxPool2D(pool_size=k, strides=1, padding='SAME') + + def call(self, inputs): + x = self.cv1(inputs) + y1 = self.m(x) + y2 = self.m(y1) + return self.cv2(tf.concat([x, y1, y2, self.m(y2)], 3)) + + +class TFDetect(keras.layers.Layer): + def __init__(self, nc=80, anchors=(), ch=(), imgsz=(640, 640), w=None): # detection layer + super().__init__() + self.stride = tf.convert_to_tensor(w.stride.numpy(), dtype=tf.float32) + self.nc = nc # number of classes + self.no = nc + 5 # number of outputs per anchor + self.nl = len(anchors) # number of detection layers + self.na = len(anchors[0]) // 2 # number of anchors + self.grid = [tf.zeros(1)] * self.nl # init grid + self.anchors = tf.convert_to_tensor(w.anchors.numpy(), dtype=tf.float32) + self.anchor_grid = tf.reshape(self.anchors * tf.reshape(self.stride, [self.nl, 1, 1]), + [self.nl, 1, -1, 1, 2]) + self.m = [TFConv2d(x, self.no * self.na, 1, w=w.m[i]) for i, x in enumerate(ch)] + self.training = False # set to False after building model + self.imgsz = imgsz + for i in range(self.nl): + ny, nx = self.imgsz[0] // self.stride[i], self.imgsz[1] // self.stride[i] + self.grid[i] = self._make_grid(nx, ny) + + def call(self, inputs): + z = [] # inference output + x = [] + for i in range(self.nl): + x.append(self.m[i](inputs[i])) + # x(bs,20,20,255) to x(bs,3,20,20,85) + ny, nx = self.imgsz[0] // self.stride[i], self.imgsz[1] // self.stride[i] + x[i] = tf.transpose(tf.reshape(x[i], [-1, ny * nx, self.na, self.no]), [0, 2, 1, 3]) + + if not self.training: # inference + y = tf.sigmoid(x[i]) + xy = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i] # xy + wh = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] + # Normalize xywh to 0-1 to reduce calibration error + xy /= tf.constant([[self.imgsz[1], self.imgsz[0]]], dtype=tf.float32) + wh /= tf.constant([[self.imgsz[1], self.imgsz[0]]], dtype=tf.float32) + y = tf.concat([xy, wh, y[..., 4:]], -1) + z.append(tf.reshape(y, [-1, 3 * ny * nx, self.no])) + + return x if self.training else (tf.concat(z, 1), x) + + @staticmethod + def _make_grid(nx=20, ny=20): + # yv, xv = torch.meshgrid([torch.arange(ny), torch.arange(nx)]) + # return torch.stack((xv, yv), 2).view((1, 1, ny, nx, 2)).float() + xv, yv = tf.meshgrid(tf.range(nx), tf.range(ny)) + return tf.cast(tf.reshape(tf.stack([xv, yv], 2), [1, 1, ny * nx, 2]), dtype=tf.float32) + + +class TFUpsample(keras.layers.Layer): + def __init__(self, size, scale_factor, mode, w=None): # warning: all arguments needed including 'w' + super().__init__() + assert scale_factor == 2, "scale_factor must be 2" + self.upsample = lambda x: tf.image.resize(x, (x.shape[1] * 2, x.shape[2] * 2), method=mode) + # self.upsample = keras.layers.UpSampling2D(size=scale_factor, interpolation=mode) + # with default arguments: align_corners=False, half_pixel_centers=False + # self.upsample = lambda x: tf.raw_ops.ResizeNearestNeighbor(images=x, + # size=(x.shape[1] * 2, x.shape[2] * 2)) + + def call(self, inputs): + return self.upsample(inputs) + + +class TFConcat(keras.layers.Layer): + def __init__(self, dimension=1, w=None): + super().__init__() + assert dimension == 1, "convert only NCHW to NHWC concat" + self.d = 3 + + def call(self, inputs): + return tf.concat(inputs, self.d) + + +def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3) + LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}") + anchors, nc, gd, gw = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'] + na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors + no = na * (nc + 5) # number of outputs = anchors * (classes + 5) + + layers, save, c2 = [], [], ch[-1] # layers, savelist, ch out + for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, args + m_str = m + m = eval(m) if isinstance(m, str) else m # eval strings + for j, a in enumerate(args): + try: + args[j] = eval(a) if isinstance(a, str) else a # eval strings + except NameError: + pass + + n = max(round(n * gd), 1) if n > 1 else n # depth gain + if m in [nn.Conv2d, Conv, Bottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv, BottleneckCSP, C3]: + c1, c2 = ch[f], args[0] + c2 = make_divisible(c2 * gw, 8) if c2 != no else c2 + + args = [c1, c2, *args[1:]] + if m in [BottleneckCSP, C3]: + args.insert(2, n) + n = 1 + elif m is nn.BatchNorm2d: + args = [ch[f]] + elif m is Concat: + c2 = sum(ch[-1 if x == -1 else x + 1] for x in f) + elif m is Detect: + args.append([ch[x + 1] for x in f]) + if isinstance(args[1], int): # number of anchors + args[1] = [list(range(args[1] * 2))] * len(f) + args.append(imgsz) + else: + c2 = ch[f] + + tf_m = eval('TF' + m_str.replace('nn.', '')) + m_ = keras.Sequential([tf_m(*args, w=model.model[i][j]) for j in range(n)]) if n > 1 \ + else tf_m(*args, w=model.model[i]) # module + + torch_m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # module + t = str(m)[8:-2].replace('__main__.', '') # module type + np = sum(x.numel() for x in torch_m_.parameters()) # number params + m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params + LOGGER.info(f'{i:>3}{str(f):>18}{str(n):>3}{np:>10} {t:<40}{str(args):<30}') # print + save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist + layers.append(m_) + ch.append(c2) + return keras.Sequential(layers), sorted(save) + + +class TFModel: + def __init__(self, cfg='yolov3.yaml', ch=3, nc=None, model=None, imgsz=(640, 640)): # model, channels, classes + super().__init__() + if isinstance(cfg, dict): + self.yaml = cfg # model dict + else: # is *.yaml + import yaml # for torch hub + self.yaml_file = Path(cfg).name + with open(cfg) as f: + self.yaml = yaml.load(f, Loader=yaml.FullLoader) # model dict + + # Define model + if nc and nc != self.yaml['nc']: + LOGGER.info(f"Overriding {cfg} nc={self.yaml['nc']} with nc={nc}") + self.yaml['nc'] = nc # override yaml value + self.model, self.savelist = parse_model(deepcopy(self.yaml), ch=[ch], model=model, imgsz=imgsz) + + def predict(self, inputs, tf_nms=False, agnostic_nms=False, topk_per_class=100, topk_all=100, iou_thres=0.45, + conf_thres=0.25): + y = [] # outputs + x = inputs + for i, m in enumerate(self.model.layers): + if m.f != -1: # if not from previous layer + x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers + + x = m(x) # run + y.append(x if m.i in self.savelist else None) # save output + + # Add TensorFlow NMS + if tf_nms: + boxes = self._xywh2xyxy(x[0][..., :4]) + probs = x[0][:, :, 4:5] + classes = x[0][:, :, 5:] + scores = probs * classes + if agnostic_nms: + nms = AgnosticNMS()((boxes, classes, scores), topk_all, iou_thres, conf_thres) + return nms, x[1] + else: + boxes = tf.expand_dims(boxes, 2) + nms = tf.image.combined_non_max_suppression( + boxes, scores, topk_per_class, topk_all, iou_thres, conf_thres, clip_boxes=False) + return nms, x[1] + + return x[0] # output only first tensor [1,6300,85] = [xywh, conf, class0, class1, ...] + # x = x[0][0] # [x(1,6300,85), ...] to x(6300,85) + # xywh = x[..., :4] # x(6300,4) boxes + # conf = x[..., 4:5] # x(6300,1) confidences + # cls = tf.reshape(tf.cast(tf.argmax(x[..., 5:], axis=1), tf.float32), (-1, 1)) # x(6300,1) classes + # return tf.concat([conf, cls, xywh], 1) + + @staticmethod + def _xywh2xyxy(xywh): + # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + x, y, w, h = tf.split(xywh, num_or_size_splits=4, axis=-1) + return tf.concat([x - w / 2, y - h / 2, x + w / 2, y + h / 2], axis=-1) + + +class AgnosticNMS(keras.layers.Layer): + # TF Agnostic NMS + def call(self, input, topk_all, iou_thres, conf_thres): + # wrap map_fn to avoid TypeSpec related error https://stackoverflow.com/a/65809989/3036450 + return tf.map_fn(lambda x: self._nms(x, topk_all, iou_thres, conf_thres), input, + fn_output_signature=(tf.float32, tf.float32, tf.float32, tf.int32), + name='agnostic_nms') + + @staticmethod + def _nms(x, topk_all=100, iou_thres=0.45, conf_thres=0.25): # agnostic NMS + boxes, classes, scores = x + class_inds = tf.cast(tf.argmax(classes, axis=-1), tf.float32) + scores_inp = tf.reduce_max(scores, -1) + selected_inds = tf.image.non_max_suppression( + boxes, scores_inp, max_output_size=topk_all, iou_threshold=iou_thres, score_threshold=conf_thres) + selected_boxes = tf.gather(boxes, selected_inds) + padded_boxes = tf.pad(selected_boxes, + paddings=[[0, topk_all - tf.shape(selected_boxes)[0]], [0, 0]], + mode="CONSTANT", constant_values=0.0) + selected_scores = tf.gather(scores_inp, selected_inds) + padded_scores = tf.pad(selected_scores, + paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]], + mode="CONSTANT", constant_values=-1.0) + selected_classes = tf.gather(class_inds, selected_inds) + padded_classes = tf.pad(selected_classes, + paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]], + mode="CONSTANT", constant_values=-1.0) + valid_detections = tf.shape(selected_inds)[0] + return padded_boxes, padded_scores, padded_classes, valid_detections + + +def representative_dataset_gen(dataset, ncalib=100): + # Representative dataset generator for use with converter.representative_dataset, returns a generator of np arrays + for n, (path, img, im0s, vid_cap, string) in enumerate(dataset): + input = np.transpose(img, [1, 2, 0]) + input = np.expand_dims(input, axis=0).astype(np.float32) + input /= 255 + yield [input] + if n >= ncalib: + break + + +def run(weights=ROOT / 'yolov3.pt', # weights path + imgsz=(640, 640), # inference size h,w + batch_size=1, # batch size + dynamic=False, # dynamic batch size + ): + # PyTorch model + im = torch.zeros((batch_size, 3, *imgsz)) # BCHW image + model = attempt_load(weights, map_location=torch.device('cpu'), inplace=True, fuse=False) + y = model(im) # inference + model.info() + + # TensorFlow model + im = tf.zeros((batch_size, *imgsz, 3)) # BHWC image + tf_model = TFModel(cfg=model.yaml, model=model, nc=model.nc, imgsz=imgsz) + y = tf_model.predict(im) # inference + + # Keras model + im = keras.Input(shape=(*imgsz, 3), batch_size=None if dynamic else batch_size) + keras_model = keras.Model(inputs=im, outputs=tf_model.predict(im)) + keras_model.summary() + + LOGGER.info('PyTorch, TensorFlow and Keras models successfully verified.\nUse export.py for TF model export.') + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default=ROOT / 'yolov3.pt', help='weights path') + parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') + parser.add_argument('--batch-size', type=int, default=1, help='batch size') + parser.add_argument('--dynamic', action='store_true', help='dynamic batch size') + opt = parser.parse_args() + opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand + print_args(FILE.stem, opt) + return opt + + +def main(opt): + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/models/yolo.py b/models/yolo.py index 934cab69df..f398d3f971 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -1,27 +1,32 @@ -"""YOLOv3-specific modules +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +YOLO-specific modules Usage: $ python path/to/models/yolo.py --cfg yolov3.yaml """ import argparse -import logging import sys from copy import deepcopy from pathlib import Path -sys.path.append(Path(__file__).parent.parent.absolute().__str__()) # to run '$ python *.py' files in subdirectories -logger = logging.getLogger(__name__) +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +# ROOT = ROOT.relative_to(Path.cwd()) # relative from models.common import * from models.experimental import * from utils.autoanchor import check_anchor_order -from utils.general import make_divisible, check_file, set_logging -from utils.torch_utils import time_synchronized, fuse_conv_and_bn, model_info, scale_img, initialize_weights, \ - select_device, copy_attr +from utils.general import LOGGER, check_version, check_yaml, make_divisible, print_args +from utils.plots import feature_visualization +from utils.torch_utils import (copy_attr, fuse_conv_and_bn, initialize_weights, model_info, scale_img, select_device, + time_sync) try: - import thop # for FLOPS computation + import thop # for FLOPs computation except ImportError: thop = None @@ -31,20 +36,18 @@ class Detect(nn.Module): onnx_dynamic = False # ONNX export parameter def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer - super(Detect, self).__init__() + super().__init__() self.nc = nc # number of classes self.no = nc + 5 # number of outputs per anchor self.nl = len(anchors) # number of detection layers self.na = len(anchors[0]) // 2 # number of anchors self.grid = [torch.zeros(1)] * self.nl # init grid - a = torch.tensor(anchors).float().view(self.nl, -1, 2) - self.register_buffer('anchors', a) # shape(nl,na,2) - self.register_buffer('anchor_grid', a.clone().view(self.nl, 1, -1, 1, 1, 2)) # shape(nl,1,na,1,1,2) + self.anchor_grid = [torch.zeros(1)] * self.nl # init anchor grid + self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2) self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv self.inplace = inplace # use in-place ops (e.g. slice assignment) def forward(self, x): - # x = x.copy() # for profiling z = [] # inference output for i in range(self.nl): x[i] = self.m[i](x[i]) # conv @@ -52,50 +55,55 @@ def forward(self, x): x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous() if not self.training: # inference - if self.grid[i].shape[2:4] != x[i].shape[2:4] or self.onnx_dynamic: - self.grid[i] = self._make_grid(nx, ny).to(x[i].device) + if self.onnx_dynamic or self.grid[i].shape[2:4] != x[i].shape[2:4]: + self.grid[i], self.anchor_grid[i] = self._make_grid(nx, ny, i) y = x[i].sigmoid() if self.inplace: - y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + self.grid[i]) * self.stride[i] # xy + y[..., 0:2] = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i] # xy y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh - else: # for YOLOv5 on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953 - xy = (y[..., 0:2] * 2. - 0.5 + self.grid[i]) * self.stride[i] # xy - wh = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i].view(1, self.na, 1, 1, 2) # wh + else: # for on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953 + xy = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i] # xy + wh = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh y = torch.cat((xy, wh, y[..., 4:]), -1) z.append(y.view(bs, -1, self.no)) return x if self.training else (torch.cat(z, 1), x) - @staticmethod - def _make_grid(nx=20, ny=20): - yv, xv = torch.meshgrid([torch.arange(ny), torch.arange(nx)]) - return torch.stack((xv, yv), 2).view((1, 1, ny, nx, 2)).float() + def _make_grid(self, nx=20, ny=20, i=0): + d = self.anchors[i].device + if check_version(torch.__version__, '1.10.0'): # torch>=1.10.0 meshgrid workaround for torch>=0.7 compatibility + yv, xv = torch.meshgrid([torch.arange(ny).to(d), torch.arange(nx).to(d)], indexing='ij') + else: + yv, xv = torch.meshgrid([torch.arange(ny).to(d), torch.arange(nx).to(d)]) + grid = torch.stack((xv, yv), 2).expand((1, self.na, ny, nx, 2)).float() + anchor_grid = (self.anchors[i].clone() * self.stride[i]) \ + .view((1, self.na, 1, 1, 2)).expand((1, self.na, ny, nx, 2)).float() + return grid, anchor_grid class Model(nn.Module): def __init__(self, cfg='yolov3.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classes - super(Model, self).__init__() + super().__init__() if isinstance(cfg, dict): self.yaml = cfg # model dict else: # is *.yaml import yaml # for torch hub self.yaml_file = Path(cfg).name - with open(cfg) as f: + with open(cfg, encoding='ascii', errors='ignore') as f: self.yaml = yaml.safe_load(f) # model dict # Define model ch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channels if nc and nc != self.yaml['nc']: - logger.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}") + LOGGER.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}") self.yaml['nc'] = nc # override yaml value if anchors: - logger.info(f'Overriding model.yaml anchors with anchors={anchors}') + LOGGER.info(f'Overriding model.yaml anchors with anchors={anchors}') self.yaml['anchors'] = round(anchors) # override yaml value self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelist self.names = [str(i) for i in range(self.yaml['nc'])] # default names self.inplace = self.yaml.get('inplace', True) - # logger.info([x.shape for x in self.forward(torch.zeros(1, ch, 64, 64))]) # Build strides, anchors m = self.model[-1] # Detect() @@ -107,53 +115,42 @@ def __init__(self, cfg='yolov3.yaml', ch=3, nc=None, anchors=None): # model, in check_anchor_order(m) self.stride = m.stride self._initialize_biases() # only run once - # logger.info('Strides: %s' % m.stride.tolist()) # Init weights, biases initialize_weights(self) self.info() - logger.info('') + LOGGER.info('') - def forward(self, x, augment=False, profile=False): + def forward(self, x, augment=False, profile=False, visualize=False): if augment: - return self.forward_augment(x) # augmented inference, None - else: - return self.forward_once(x, profile) # single-scale inference, train + return self._forward_augment(x) # augmented inference, None + return self._forward_once(x, profile, visualize) # single-scale inference, train - def forward_augment(self, x): + def _forward_augment(self, x): img_size = x.shape[-2:] # height, width s = [1, 0.83, 0.67] # scales f = [None, 3, None] # flips (2-ud, 3-lr) y = [] # outputs for si, fi in zip(s, f): xi = scale_img(x.flip(fi) if fi else x, si, gs=int(self.stride.max())) - yi = self.forward_once(xi)[0] # forward + yi = self._forward_once(xi)[0] # forward # cv2.imwrite(f'img_{si}.jpg', 255 * xi[0].cpu().numpy().transpose((1, 2, 0))[:, :, ::-1]) # save yi = self._descale_pred(yi, fi, si, img_size) y.append(yi) + y = self._clip_augmented(y) # clip augmented tails return torch.cat(y, 1), None # augmented inference, train - def forward_once(self, x, profile=False): + def _forward_once(self, x, profile=False, visualize=False): y, dt = [], [] # outputs for m in self.model: if m.f != -1: # if not from previous layer x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers - if profile: - o = thop.profile(m, inputs=(x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPS - t = time_synchronized() - for _ in range(10): - _ = m(x) - dt.append((time_synchronized() - t) * 100) - if m == self.model[0]: - logger.info(f"{'time (ms)':>10s} {'GFLOPS':>10s} {'params':>10s} {'module'}") - logger.info(f'{dt[-1]:10.2f} {o:10.2f} {m.np:10.0f} {m.type}') - + self._profile_one_layer(m, x, dt) x = m(x) # run y.append(x if m.i in self.save else None) # save output - - if profile: - logger.info('%.1fms total' % sum(dt)) + if visualize: + feature_visualization(x, m.type, m.i, save_dir=visualize) return x def _descale_pred(self, p, flips, scale, img_size): @@ -173,6 +170,30 @@ def _descale_pred(self, p, flips, scale, img_size): p = torch.cat((x, y, wh, p[..., 4:]), -1) return p + def _clip_augmented(self, y): + # Clip augmented inference tails + nl = self.model[-1].nl # number of detection layers (P3-P5) + g = sum(4 ** x for x in range(nl)) # grid points + e = 1 # exclude layer count + i = (y[0].shape[1] // g) * sum(4 ** x for x in range(e)) # indices + y[0] = y[0][:, :-i] # large + i = (y[-1].shape[1] // g) * sum(4 ** (nl - 1 - x) for x in range(e)) # indices + y[-1] = y[-1][:, i:] # small + return y + + def _profile_one_layer(self, m, x, dt): + c = isinstance(m, Detect) # is final layer, copy input as inplace fix + o = thop.profile(m, inputs=(x.copy() if c else x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPs + t = time_sync() + for _ in range(10): + m(x.copy() if c else x) + dt.append((time_sync() - t) * 100) + if m == self.model[0]: + LOGGER.info(f"{'time (ms)':>10s} {'GFLOPs':>10s} {'params':>10s} {'module'}") + LOGGER.info(f'{dt[-1]:10.2f} {o:10.2f} {m.np:10.0f} {m.type}') + if c: + LOGGER.info(f"{sum(dt):10.2f} {'-':>10s} {'-':>10s} Total") + def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is class frequency # https://arxiv.org/abs/1708.02002 section 3.3 # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1. @@ -180,47 +201,33 @@ def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is for mi, s in zip(m.m, m.stride): # from b = mi.bias.view(m.na, -1) # conv.bias(255) to (3,85) b.data[:, 4] += math.log(8 / (640 / s) ** 2) # obj (8 objects per 640 image) - b.data[:, 5:] += math.log(0.6 / (m.nc - 0.99)) if cf is None else torch.log(cf / cf.sum()) # cls + b.data[:, 5:] += math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum()) # cls mi.bias = torch.nn.Parameter(b.view(-1), requires_grad=True) def _print_biases(self): m = self.model[-1] # Detect() module for mi in m.m: # from b = mi.bias.detach().view(m.na, -1).T # conv.bias(255) to (3,85) - logger.info( + LOGGER.info( ('%6g Conv2d.bias:' + '%10.3g' * 6) % (mi.weight.shape[1], *b[:5].mean(1).tolist(), b[5:].mean())) # def _print_weights(self): # for m in self.model.modules(): # if type(m) is Bottleneck: - # logger.info('%10.3g' % (m.w.detach().sigmoid() * 2)) # shortcut weights + # LOGGER.info('%10.3g' % (m.w.detach().sigmoid() * 2)) # shortcut weights def fuse(self): # fuse model Conv2d() + BatchNorm2d() layers - logger.info('Fusing layers... ') + LOGGER.info('Fusing layers... ') for m in self.model.modules(): - if type(m) is Conv and hasattr(m, 'bn'): + if isinstance(m, (Conv, DWConv)) and hasattr(m, 'bn'): m.conv = fuse_conv_and_bn(m.conv, m.bn) # update conv delattr(m, 'bn') # remove batchnorm - m.forward = m.fuseforward # update forward + m.forward = m.forward_fuse # update forward self.info() return self - def nms(self, mode=True): # add or remove NMS module - present = type(self.model[-1]) is NMS # last layer is NMS - if mode and not present: - logger.info('Adding NMS... ') - m = NMS() # module - m.f = -1 # from - m.i = self.model[-1].i + 1 # index - self.model.add_module(name='%s' % m.i, module=m) # add - self.eval() - elif not mode and present: - logger.info('Removing NMS... ') - self.model = self.model[:-1] # remove - return self - def autoshape(self): # add AutoShape module - logger.info('Adding AutoShape... ') + LOGGER.info('Adding AutoShape... ') m = AutoShape(self) # wrap model copy_attr(m, self, include=('yaml', 'nc', 'hyp', 'names', 'stride'), exclude=()) # copy attributes return m @@ -228,9 +235,20 @@ def autoshape(self): # add AutoShape module def info(self, verbose=False, img_size=640): # print model information model_info(self, verbose, img_size) + def _apply(self, fn): + # Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers + self = super()._apply(fn) + m = self.model[-1] # Detect() + if isinstance(m, Detect): + m.stride = fn(m.stride) + m.grid = list(map(fn, m.grid)) + if isinstance(m.anchor_grid, list): + m.anchor_grid = list(map(fn, m.anchor_grid)) + return self + def parse_model(d, ch): # model_dict, input_channels(3) - logger.info('\n%3s%18s%3s%10s %-40s%-30s' % ('', 'from', 'n', 'params', 'module', 'arguments')) + LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}") anchors, nc, gd, gw = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'] na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors no = na * (nc + 5) # number of outputs = anchors * (classes + 5) @@ -241,24 +259,24 @@ def parse_model(d, ch): # model_dict, input_channels(3) for j, a in enumerate(args): try: args[j] = eval(a) if isinstance(a, str) else a # eval strings - except: + except NameError: pass - n = max(round(n * gd), 1) if n > 1 else n # depth gain - if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, DWConv, MixConv2d, Focus, CrossConv, BottleneckCSP, - C3, C3TR]: + n = n_ = max(round(n * gd), 1) if n > 1 else n # depth gain + if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv, + BottleneckCSP, C3, C3TR, C3SPP, C3Ghost]: c1, c2 = ch[f], args[0] if c2 != no: # if not output c2 = make_divisible(c2 * gw, 8) args = [c1, c2, *args[1:]] - if m in [BottleneckCSP, C3, C3TR]: + if m in [BottleneckCSP, C3, C3TR, C3Ghost]: args.insert(2, n) # number of repeats n = 1 elif m is nn.BatchNorm2d: args = [ch[f]] elif m is Concat: - c2 = sum([ch[x] for x in f]) + c2 = sum(ch[x] for x in f) elif m is Detect: args.append([ch[x] for x in f]) if isinstance(args[1], int): # number of anchors @@ -270,11 +288,11 @@ def parse_model(d, ch): # model_dict, input_channels(3) else: c2 = ch[f] - m_ = nn.Sequential(*[m(*args) for _ in range(n)]) if n > 1 else m(*args) # module + m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # module t = str(m)[8:-2].replace('__main__.', '') # module type - np = sum([x.numel() for x in m_.parameters()]) # number params + np = sum(x.numel() for x in m_.parameters()) # number params m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params - logger.info('%3s%18s%3s%10.0f %-40s%-30s' % (i, f, n, np, t, args)) # print + LOGGER.info(f'{i:>3}{str(f):>18}{n_:>3}{np:10.0f} {t:<40}{str(args):<30}') # print save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist layers.append(m_) if i == 0: @@ -285,11 +303,13 @@ def parse_model(d, ch): # model_dict, input_channels(3) if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('--cfg', type=str, default='yolov3.yaml', help='model.yaml') + parser.add_argument('--cfg', type=str, default='yolov3yaml', help='model.yaml') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--profile', action='store_true', help='profile model speed') + parser.add_argument('--test', action='store_true', help='test all yolo*.yaml') opt = parser.parse_args() - opt.cfg = check_file(opt.cfg) # check file - set_logging() + opt.cfg = check_yaml(opt.cfg) # check YAML + print_args(FILE.stem, opt) device = select_device(opt.device) # Create model @@ -297,12 +317,20 @@ def parse_model(d, ch): # model_dict, input_channels(3) model.train() # Profile - # img = torch.rand(8 if torch.cuda.is_available() else 1, 3, 320, 320).to(device) - # y = model(img, profile=True) + if opt.profile: + img = torch.rand(8 if torch.cuda.is_available() else 1, 3, 640, 640).to(device) + y = model(img, profile=True) + + # Test all models + if opt.test: + for cfg in Path(ROOT / 'models').rglob('yolo*.yaml'): + try: + _ = Model(cfg) + except Exception as e: + print(f'Error in {cfg}: {e}') # Tensorboard (not working https://github.com/ultralytics/yolov5/issues/2898) # from torch.utils.tensorboard import SummaryWriter # tb_writer = SummaryWriter('.') - # logger.info("Run 'tensorboard --logdir=models' to view tensorboard at http://localhost:6006/") + # LOGGER.info("Run 'tensorboard --logdir=models' to view tensorboard at http://localhost:6006/") # tb_writer.add_graph(torch.jit.trace(model, img, strict=False), []) # add model graph - # tb_writer.add_image('test', img[0], dataformats='CWH') # add model to tensorboard diff --git a/models/yolov3-spp.yaml b/models/yolov3-spp.yaml index 38dcc449f0..04593a47d2 100644 --- a/models/yolov3-spp.yaml +++ b/models/yolov3-spp.yaml @@ -1,9 +1,9 @@ -# parameters +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters nc: 80 # number of classes depth_multiple: 1.0 # model depth multiple width_multiple: 1.0 # layer channel multiple - -# anchors anchors: - [10,13, 16,30, 33,23] # P3/8 - [30,61, 62,45, 59,119] # P4/16 diff --git a/models/yolov3-tiny.yaml b/models/yolov3-tiny.yaml index ff7638cad3..04f9b446a6 100644 --- a/models/yolov3-tiny.yaml +++ b/models/yolov3-tiny.yaml @@ -1,9 +1,9 @@ -# parameters +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters nc: 80 # number of classes depth_multiple: 1.0 # model depth multiple width_multiple: 1.0 # layer channel multiple - -# anchors anchors: - [10,14, 23,27, 37,58] # P4/16 - [81,82, 135,169, 344,319] # P5/32 diff --git a/models/yolov3.yaml b/models/yolov3.yaml index f2e7613554..3d041bb393 100644 --- a/models/yolov3.yaml +++ b/models/yolov3.yaml @@ -1,9 +1,9 @@ -# parameters +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters nc: 80 # number of classes depth_multiple: 1.0 # model depth multiple width_multiple: 1.0 # layer channel multiple - -# anchors anchors: - [10,13, 16,30, 33,23] # P3/8 - [30,61, 62,45, 59,119] # P4/16 diff --git a/requirements.txt b/requirements.txt index 1c07c65115..22b51fc490 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,30 +1,36 @@ # pip install -r requirements.txt -# base ---------------------------------------- +# Base ---------------------------------------- matplotlib>=3.2.2 numpy>=1.18.5 opencv-python>=4.1.2 -Pillow +Pillow>=7.1.2 PyYAML>=5.3.1 +requests>=2.23.0 scipy>=1.4.1 torch>=1.7.0 torchvision>=0.8.1 tqdm>=4.41.0 -# logging ------------------------------------- +# Logging ------------------------------------- tensorboard>=2.4.1 # wandb -# plotting ------------------------------------ +# Plotting ------------------------------------ +pandas>=1.1.4 seaborn>=0.11.0 -pandas -# export -------------------------------------- -# coremltools>=4.1 -# onnx>=1.9.0 -# scikit-learn==0.19.2 # for coreml quantization +# Export -------------------------------------- +# coremltools>=4.1 # CoreML export +# onnx>=1.9.0 # ONNX export +# onnx-simplifier>=0.3.6 # ONNX simplifier +# scikit-learn==0.19.2 # CoreML quantization +# tensorflow>=2.4.1 # TFLite export +# tensorflowjs>=3.9.0 # TF.js export -# extras -------------------------------------- +# Extras -------------------------------------- +# albumentations>=1.0.3 # Cython # for pycocotools https://github.com/cocodataset/cocoapi/issues/172 -pycocotools>=2.0 # COCO mAP -thop # FLOPS computation +# pycocotools>=2.0 # COCO mAP +# roboflow +thop # FLOPs computation diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000000..4ca0f0d7aa --- /dev/null +++ b/setup.cfg @@ -0,0 +1,51 @@ +# Project-wide configuration file, can be used for package metadata and other toll configurations +# Example usage: global configuration for PEP8 (via flake8) setting or default pytest arguments + +[metadata] +license_file = LICENSE +description-file = README.md + + +[tool:pytest] +norecursedirs = + .git + dist + build +addopts = + --doctest-modules + --durations=25 + --color=yes + + +[flake8] +max-line-length = 120 +exclude = .tox,*.egg,build,temp +select = E,W,F +doctests = True +verbose = 2 +# https://pep8.readthedocs.io/en/latest/intro.html#error-codes +format = pylint +# see: https://www.flake8rules.com/ +ignore = + E731 # Do not assign a lambda expression, use a def + F405 + E402 + F841 + E741 + F821 + E722 + F401 + W504 + E127 + W504 + E231 + E501 + F403 + E302 + F541 + + +[isort] +# https://pycqa.github.io/isort/docs/configuration/options.html +line_length = 120 +multi_line_output = 0 diff --git a/test.py b/test.py deleted file mode 100644 index 396beef6e1..0000000000 --- a/test.py +++ /dev/null @@ -1,349 +0,0 @@ -import argparse -import json -import os -from pathlib import Path -from threading import Thread - -import numpy as np -import torch -import yaml -from tqdm import tqdm - -from models.experimental import attempt_load -from utils.datasets import create_dataloader -from utils.general import coco80_to_coco91_class, check_dataset, check_file, check_img_size, check_requirements, \ - box_iou, non_max_suppression, scale_coords, xyxy2xywh, xywh2xyxy, set_logging, increment_path, colorstr -from utils.metrics import ap_per_class, ConfusionMatrix -from utils.plots import plot_images, output_to_target, plot_study_txt -from utils.torch_utils import select_device, time_synchronized - - -@torch.no_grad() -def test(data, - weights=None, - batch_size=32, - imgsz=640, - conf_thres=0.001, - iou_thres=0.6, # for NMS - save_json=False, - single_cls=False, - augment=False, - verbose=False, - model=None, - dataloader=None, - save_dir=Path(''), # for saving images - save_txt=False, # for auto-labelling - save_hybrid=False, # for hybrid auto-labelling - save_conf=False, # save auto-label confidences - plots=True, - wandb_logger=None, - compute_loss=None, - half_precision=True, - is_coco=False, - opt=None): - # Initialize/load model and set device - training = model is not None - if training: # called by train.py - device = next(model.parameters()).device # get model device - - else: # called directly - set_logging() - device = select_device(opt.device, batch_size=batch_size) - - # Directories - save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok) # increment run - (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir - - # Load model - model = attempt_load(weights, map_location=device) # load FP32 model - gs = max(int(model.stride.max()), 32) # grid size (max stride) - imgsz = check_img_size(imgsz, s=gs) # check img_size - - # Multi-GPU disabled, incompatible with .half() https://github.com/ultralytics/yolov5/issues/99 - # if device.type != 'cpu' and torch.cuda.device_count() > 1: - # model = nn.DataParallel(model) - - # Half - half = device.type != 'cpu' and half_precision # half precision only supported on CUDA - if half: - model.half() - - # Configure - model.eval() - if isinstance(data, str): - is_coco = data.endswith('coco.yaml') - with open(data) as f: - data = yaml.safe_load(f) - check_dataset(data) # check - nc = 1 if single_cls else int(data['nc']) # number of classes - iouv = torch.linspace(0.5, 0.95, 10).to(device) # iou vector for mAP@0.5:0.95 - niou = iouv.numel() - - # Logging - log_imgs = 0 - if wandb_logger and wandb_logger.wandb: - log_imgs = min(wandb_logger.log_imgs, 100) - # Dataloader - if not training: - if device.type != 'cpu': - model(torch.zeros(1, 3, imgsz, imgsz).to(device).type_as(next(model.parameters()))) # run once - task = opt.task if opt.task in ('train', 'val', 'test') else 'val' # path to train/val/test images - dataloader = create_dataloader(data[task], imgsz, batch_size, gs, opt, pad=0.5, rect=True, - prefix=colorstr(f'{task}: '))[0] - - seen = 0 - confusion_matrix = ConfusionMatrix(nc=nc) - names = {k: v for k, v in enumerate(model.names if hasattr(model, 'names') else model.module.names)} - coco91class = coco80_to_coco91_class() - s = ('%20s' + '%12s' * 6) % ('Class', 'Images', 'Labels', 'P', 'R', 'mAP@.5', 'mAP@.5:.95') - p, r, f1, mp, mr, map50, map, t0, t1 = 0., 0., 0., 0., 0., 0., 0., 0., 0. - loss = torch.zeros(3, device=device) - jdict, stats, ap, ap_class, wandb_images = [], [], [], [], [] - for batch_i, (img, targets, paths, shapes) in enumerate(tqdm(dataloader, desc=s)): - img = img.to(device, non_blocking=True) - img = img.half() if half else img.float() # uint8 to fp16/32 - img /= 255.0 # 0 - 255 to 0.0 - 1.0 - targets = targets.to(device) - nb, _, height, width = img.shape # batch size, channels, height, width - - # Run model - t = time_synchronized() - out, train_out = model(img, augment=augment) # inference and training outputs - t0 += time_synchronized() - t - - # Compute loss - if compute_loss: - loss += compute_loss([x.float() for x in train_out], targets)[1][:3] # box, obj, cls - - # Run NMS - targets[:, 2:] *= torch.Tensor([width, height, width, height]).to(device) # to pixels - lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling - t = time_synchronized() - out = non_max_suppression(out, conf_thres, iou_thres, labels=lb, multi_label=True, agnostic=single_cls) - t1 += time_synchronized() - t - - # Statistics per image - for si, pred in enumerate(out): - labels = targets[targets[:, 0] == si, 1:] - nl = len(labels) - tcls = labels[:, 0].tolist() if nl else [] # target class - path = Path(paths[si]) - seen += 1 - - if len(pred) == 0: - if nl: - stats.append((torch.zeros(0, niou, dtype=torch.bool), torch.Tensor(), torch.Tensor(), tcls)) - continue - - # Predictions - if single_cls: - pred[:, 5] = 0 - predn = pred.clone() - scale_coords(img[si].shape[1:], predn[:, :4], shapes[si][0], shapes[si][1]) # native-space pred - - # Append to text file - if save_txt: - gn = torch.tensor(shapes[si][0])[[1, 0, 1, 0]] # normalization gain whwh - for *xyxy, conf, cls in predn.tolist(): - xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh - line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format - with open(save_dir / 'labels' / (path.stem + '.txt'), 'a') as f: - f.write(('%g ' * len(line)).rstrip() % line + '\n') - - # W&B logging - Media Panel Plots - if len(wandb_images) < log_imgs and wandb_logger.current_epoch > 0: # Check for test operation - if wandb_logger.current_epoch % wandb_logger.bbox_interval == 0: - box_data = [{"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, - "class_id": int(cls), - "box_caption": "%s %.3f" % (names[cls], conf), - "scores": {"class_score": conf}, - "domain": "pixel"} for *xyxy, conf, cls in pred.tolist()] - boxes = {"predictions": {"box_data": box_data, "class_labels": names}} # inference-space - wandb_images.append(wandb_logger.wandb.Image(img[si], boxes=boxes, caption=path.name)) - wandb_logger.log_training_progress(predn, path, names) if wandb_logger and wandb_logger.wandb_run else None - - # Append to pycocotools JSON dictionary - if save_json: - # [{"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236}, ... - image_id = int(path.stem) if path.stem.isnumeric() else path.stem - box = xyxy2xywh(predn[:, :4]) # xywh - box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner - for p, b in zip(pred.tolist(), box.tolist()): - jdict.append({'image_id': image_id, - 'category_id': coco91class[int(p[5])] if is_coco else int(p[5]), - 'bbox': [round(x, 3) for x in b], - 'score': round(p[4], 5)}) - - # Assign all predictions as incorrect - correct = torch.zeros(pred.shape[0], niou, dtype=torch.bool, device=device) - if nl: - detected = [] # target indices - tcls_tensor = labels[:, 0] - - # target boxes - tbox = xywh2xyxy(labels[:, 1:5]) - scale_coords(img[si].shape[1:], tbox, shapes[si][0], shapes[si][1]) # native-space labels - if plots: - confusion_matrix.process_batch(predn, torch.cat((labels[:, 0:1], tbox), 1)) - - # Per target class - for cls in torch.unique(tcls_tensor): - ti = (cls == tcls_tensor).nonzero(as_tuple=False).view(-1) # target indices - pi = (cls == pred[:, 5]).nonzero(as_tuple=False).view(-1) # prediction indices - - # Search for detections - if pi.shape[0]: - # Prediction to target ious - ious, i = box_iou(predn[pi, :4], tbox[ti]).max(1) # best ious, indices - - # Append detections - detected_set = set() - for j in (ious > iouv[0]).nonzero(as_tuple=False): - d = ti[i[j]] # detected target - if d.item() not in detected_set: - detected_set.add(d.item()) - detected.append(d) - correct[pi[j]] = ious[j] > iouv # iou_thres is 1xn - if len(detected) == nl: # all targets already located in image - break - - # Append statistics (correct, conf, pcls, tcls) - stats.append((correct.cpu(), pred[:, 4].cpu(), pred[:, 5].cpu(), tcls)) - - # Plot images - if plots and batch_i < 3: - f = save_dir / f'test_batch{batch_i}_labels.jpg' # labels - Thread(target=plot_images, args=(img, targets, paths, f, names), daemon=True).start() - f = save_dir / f'test_batch{batch_i}_pred.jpg' # predictions - Thread(target=plot_images, args=(img, output_to_target(out), paths, f, names), daemon=True).start() - - # Compute statistics - stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy - if len(stats) and stats[0].any(): - p, r, ap, f1, ap_class = ap_per_class(*stats, plot=plots, save_dir=save_dir, names=names) - ap50, ap = ap[:, 0], ap.mean(1) # AP@0.5, AP@0.5:0.95 - mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean() - nt = np.bincount(stats[3].astype(np.int64), minlength=nc) # number of targets per class - else: - nt = torch.zeros(1) - - # Print results - pf = '%20s' + '%12i' * 2 + '%12.3g' * 4 # print format - print(pf % ('all', seen, nt.sum(), mp, mr, map50, map)) - - # Print results per class - if (verbose or (nc < 50 and not training)) and nc > 1 and len(stats): - for i, c in enumerate(ap_class): - print(pf % (names[c], seen, nt[c], p[i], r[i], ap50[i], ap[i])) - - # Print speeds - t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + (imgsz, imgsz, batch_size) # tuple - if not training: - print('Speed: %.1f/%.1f/%.1f ms inference/NMS/total per %gx%g image at batch-size %g' % t) - - # Plots - if plots: - confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) - if wandb_logger and wandb_logger.wandb: - val_batches = [wandb_logger.wandb.Image(str(f), caption=f.name) for f in sorted(save_dir.glob('test*.jpg'))] - wandb_logger.log({"Validation": val_batches}) - if wandb_images: - wandb_logger.log({"Bounding Box Debugger/Images": wandb_images}) - - # Save JSON - if save_json and len(jdict): - w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights - anno_json = '../coco/annotations/instances_val2017.json' # annotations json - pred_json = str(save_dir / f"{w}_predictions.json") # predictions json - print('\nEvaluating pycocotools mAP... saving %s...' % pred_json) - with open(pred_json, 'w') as f: - json.dump(jdict, f) - - try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb - from pycocotools.coco import COCO - from pycocotools.cocoeval import COCOeval - - anno = COCO(anno_json) # init annotations api - pred = anno.loadRes(pred_json) # init predictions api - eval = COCOeval(anno, pred, 'bbox') - if is_coco: - eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.img_files] # image IDs to evaluate - eval.evaluate() - eval.accumulate() - eval.summarize() - map, map50 = eval.stats[:2] # update results (mAP@0.5:0.95, mAP@0.5) - except Exception as e: - print(f'pycocotools unable to run: {e}') - - # Return results - model.float() # for training - if not training: - s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' - print(f"Results saved to {save_dir}{s}") - maps = np.zeros(nc) + map - for i, c in enumerate(ap_class): - maps[c] = ap[i] - return (mp, mr, map50, map, *(loss.cpu() / len(dataloader)).tolist()), maps, t - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(prog='test.py') - parser.add_argument('--weights', nargs='+', type=str, default='yolov3.pt', help='model.pt path(s)') - parser.add_argument('--data', type=str, default='data/coco128.yaml', help='*.data path') - parser.add_argument('--batch-size', type=int, default=32, help='size of each image batch') - parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)') - parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') - parser.add_argument('--iou-thres', type=float, default=0.6, help='IOU threshold for NMS') - parser.add_argument('--task', default='val', help='train, val, test, speed or study') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') - parser.add_argument('--augment', action='store_true', help='augmented inference') - parser.add_argument('--verbose', action='store_true', help='report mAP by class') - parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') - parser.add_argument('--save-hybrid', action='store_true', help='save label+prediction hybrid results to *.txt') - parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') - parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') - parser.add_argument('--project', default='runs/test', help='save to project/name') - parser.add_argument('--name', default='exp', help='save to project/name') - parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') - opt = parser.parse_args() - opt.save_json |= opt.data.endswith('coco.yaml') - opt.data = check_file(opt.data) # check file - print(opt) - check_requirements(exclude=('tensorboard', 'pycocotools', 'thop')) - - if opt.task in ('train', 'val', 'test'): # run normally - test(opt.data, - opt.weights, - opt.batch_size, - opt.img_size, - opt.conf_thres, - opt.iou_thres, - opt.save_json, - opt.single_cls, - opt.augment, - opt.verbose, - save_txt=opt.save_txt | opt.save_hybrid, - save_hybrid=opt.save_hybrid, - save_conf=opt.save_conf, - opt=opt - ) - - elif opt.task == 'speed': # speed benchmarks - for w in opt.weights: - test(opt.data, w, opt.batch_size, opt.img_size, 0.25, 0.45, save_json=False, plots=False, opt=opt) - - elif opt.task == 'study': # run over a range of settings and save/plot - # python test.py --task study --data coco.yaml --iou 0.7 --weights yolov3.pt yolov3-spp.pt yolov3-tiny.pt - x = list(range(256, 1536 + 128, 128)) # x axis (image sizes) - for w in opt.weights: - f = f'study_{Path(opt.data).stem}_{Path(w).stem}.txt' # filename to save to - y = [] # y axis - for i in x: # img-size - print(f'\nRunning {f} point {i}...') - r, _, t = test(opt.data, w, opt.batch_size, i, opt.conf_thres, opt.iou_thres, opt.save_json, - plots=False, opt=opt) - y.append(r + t) # results and times - np.savetxt(f, y, fmt='%10.4g') # save - os.system('zip -r study.zip study_*.txt') - plot_study_txt(x=x) # plot diff --git a/train.py b/train.py index 8f7866093b..9098b348ce 100644 --- a/train.py +++ b/train.py @@ -1,147 +1,178 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Train a model on a custom dataset + +Usage: + $ python path/to/train.py --data coco128.yaml --weights yolov3.pt --img 640 +""" import argparse -import logging import math import os import random +import sys import time from copy import deepcopy +from datetime import datetime from pathlib import Path -from threading import Thread import numpy as np +import torch import torch.distributed as dist import torch.nn as nn -import torch.nn.functional as F -import torch.optim as optim -import torch.optim.lr_scheduler as lr_scheduler -import torch.utils.data import yaml from torch.cuda import amp from torch.nn.parallel import DistributedDataParallel as DDP -from torch.utils.tensorboard import SummaryWriter +from torch.optim import SGD, Adam, lr_scheduler from tqdm import tqdm -import test # import test.py to get mAP after each epoch +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +import val # for end-of-epoch mAP from models.experimental import attempt_load from models.yolo import Model from utils.autoanchor import check_anchors +from utils.autobatch import check_train_batch_size +from utils.callbacks import Callbacks from utils.datasets import create_dataloader -from utils.general import labels_to_class_weights, increment_path, labels_to_image_weights, init_seeds, \ - fitness, strip_optimizer, get_latest_run, check_dataset, check_file, check_git_status, check_img_size, \ - check_requirements, print_mutation, set_logging, one_cycle, colorstr -from utils.google_utils import attempt_download +from utils.downloads import attempt_download +from utils.general import (LOGGER, NCOLS, check_dataset, check_file, check_git_status, check_img_size, + check_requirements, check_suffix, check_yaml, colorstr, get_latest_run, increment_path, + init_seeds, intersect_dicts, labels_to_class_weights, labels_to_image_weights, methods, + one_cycle, print_args, print_mutation, strip_optimizer) +from utils.loggers import Loggers +from utils.loggers.wandb.wandb_utils import check_wandb_resume from utils.loss import ComputeLoss -from utils.plots import plot_images, plot_labels, plot_results, plot_evolution -from utils.torch_utils import ModelEMA, select_device, intersect_dicts, torch_distributed_zero_first, de_parallel -from utils.wandb_logging.wandb_utils import WandbLogger, check_wandb_resume +from utils.metrics import fitness +from utils.plots import plot_evolve, plot_labels +from utils.torch_utils import EarlyStopping, ModelEMA, de_parallel, select_device, torch_distributed_zero_first -logger = logging.getLogger(__name__) +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) -def train(hyp, opt, device, tb_writer=None): - logger.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) - save_dir, epochs, batch_size, total_batch_size, weights, rank = \ - Path(opt.save_dir), opt.epochs, opt.batch_size, opt.total_batch_size, opt.weights, opt.global_rank +def train(hyp, # path/to/hyp.yaml or hyp dictionary + opt, + device, + callbacks + ): + save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze, = \ + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ + opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze # Directories - wdir = save_dir / 'weights' - wdir.mkdir(parents=True, exist_ok=True) # make dir - last = wdir / 'last.pt' - best = wdir / 'best.pt' - results_file = save_dir / 'results.txt' + w = save_dir / 'weights' # weights dir + (w.parent if evolve else w).mkdir(parents=True, exist_ok=True) # make dir + last, best = w / 'last.pt', w / 'best.pt' + + # Hyperparameters + if isinstance(hyp, str): + with open(hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) # Save run settings with open(save_dir / 'hyp.yaml', 'w') as f: yaml.safe_dump(hyp, f, sort_keys=False) with open(save_dir / 'opt.yaml', 'w') as f: yaml.safe_dump(vars(opt), f, sort_keys=False) - - # Configure - plots = not opt.evolve # create plots + data_dict = None + + # Loggers + if RANK in [-1, 0]: + loggers = Loggers(save_dir, weights, opt, hyp, LOGGER) # loggers instance + if loggers.wandb: + data_dict = loggers.wandb.data_dict + if resume: + weights, epochs, hyp = opt.weights, opt.epochs, opt.hyp + + # Register actions + for k in methods(loggers): + callbacks.register_action(k, callback=getattr(loggers, k)) + + # Config + plots = not evolve # create plots cuda = device.type != 'cpu' - init_seeds(2 + rank) - with open(opt.data) as f: - data_dict = yaml.safe_load(f) # data dict - - # Logging- Doing this before checking the dataset. Might update data_dict - loggers = {'wandb': None} # loggers dict - if rank in [-1, 0]: - opt.hyp = hyp # add hyperparameters - run_id = torch.load(weights).get('wandb_id') if weights.endswith('.pt') and os.path.isfile(weights) else None - wandb_logger = WandbLogger(opt, save_dir.stem, run_id, data_dict) - loggers['wandb'] = wandb_logger.wandb - data_dict = wandb_logger.data_dict - if wandb_logger.wandb: - weights, epochs, hyp = opt.weights, opt.epochs, opt.hyp # WandbLogger might update weights, epochs if resuming - - nc = 1 if opt.single_cls else int(data_dict['nc']) # number of classes - names = ['item'] if opt.single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names - assert len(names) == nc, '%g names found for nc=%g dataset in %s' % (len(names), nc, opt.data) # check - is_coco = opt.data.endswith('coco.yaml') and nc == 80 # COCO dataset + init_seeds(1 + RANK) + with torch_distributed_zero_first(LOCAL_RANK): + data_dict = data_dict or check_dataset(data) # check if None + train_path, val_path = data_dict['train'], data_dict['val'] + nc = 1 if single_cls else int(data_dict['nc']) # number of classes + names = ['item'] if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names + assert len(names) == nc, f'{len(names)} names found for nc={nc} dataset in {data}' # check + is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO dataset # Model + check_suffix(weights, '.pt') # check weights pretrained = weights.endswith('.pt') if pretrained: - with torch_distributed_zero_first(rank): + with torch_distributed_zero_first(LOCAL_RANK): weights = attempt_download(weights) # download if not found locally ckpt = torch.load(weights, map_location=device) # load checkpoint - model = Model(opt.cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create - exclude = ['anchor'] if (opt.cfg or hyp.get('anchors')) and not opt.resume else [] # exclude keys - state_dict = ckpt['model'].float().state_dict() # to FP32 - state_dict = intersect_dicts(state_dict, model.state_dict(), exclude=exclude) # intersect - model.load_state_dict(state_dict, strict=False) # load - logger.info('Transferred %g/%g items from %s' % (len(state_dict), len(model.state_dict()), weights)) # report + model = Model(cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create + exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else [] # exclude keys + csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 + csd = intersect_dicts(csd, model.state_dict(), exclude=exclude) # intersect + model.load_state_dict(csd, strict=False) # load + LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}') # report else: - model = Model(opt.cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create - with torch_distributed_zero_first(rank): - check_dataset(data_dict) # check - train_path = data_dict['train'] - test_path = data_dict['val'] + model = Model(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create # Freeze - freeze = [] # parameter names to freeze (full or partial) + freeze = [f'model.{x}.' for x in range(freeze)] # layers to freeze for k, v in model.named_parameters(): v.requires_grad = True # train all layers if any(x in k for x in freeze): - print('freezing %s' % k) + LOGGER.info(f'freezing {k}') v.requires_grad = False + # Image size + gs = max(int(model.stride.max()), 32) # grid size (max stride) + imgsz = check_img_size(opt.imgsz, gs, floor=gs * 2) # verify imgsz is gs-multiple + + # Batch size + if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size + batch_size = check_train_batch_size(model, imgsz) + # Optimizer nbs = 64 # nominal batch size - accumulate = max(round(nbs / total_batch_size), 1) # accumulate loss before optimizing - hyp['weight_decay'] *= total_batch_size * accumulate / nbs # scale weight_decay - logger.info(f"Scaled weight_decay = {hyp['weight_decay']}") - - pg0, pg1, pg2 = [], [], [] # optimizer parameter groups - for k, v in model.named_modules(): - if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter): - pg2.append(v.bias) # biases - if isinstance(v, nn.BatchNorm2d): - pg0.append(v.weight) # no decay - elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter): - pg1.append(v.weight) # apply decay + accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing + hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay + LOGGER.info(f"Scaled weight_decay = {hyp['weight_decay']}") + + g0, g1, g2 = [], [], [] # optimizer parameter groups + for v in model.modules(): + if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter): # bias + g2.append(v.bias) + if isinstance(v, nn.BatchNorm2d): # weight (no decay) + g0.append(v.weight) + elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter): # weight (with decay) + g1.append(v.weight) if opt.adam: - optimizer = optim.Adam(pg0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999)) # adjust beta1 to momentum + optimizer = Adam(g0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999)) # adjust beta1 to momentum else: - optimizer = optim.SGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) + optimizer = SGD(g0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) - optimizer.add_param_group({'params': pg1, 'weight_decay': hyp['weight_decay']}) # add pg1 with weight_decay - optimizer.add_param_group({'params': pg2}) # add pg2 (biases) - logger.info('Optimizer groups: %g .bias, %g conv.weight, %g other' % (len(pg2), len(pg1), len(pg0))) - del pg0, pg1, pg2 + optimizer.add_param_group({'params': g1, 'weight_decay': hyp['weight_decay']}) # add g1 with weight_decay + optimizer.add_param_group({'params': g2}) # add g2 (biases) + LOGGER.info(f"{colorstr('optimizer:')} {type(optimizer).__name__} with parameter groups " + f"{len(g0)} weight, {len(g1)} weight (no decay), {len(g2)} bias") + del g0, g1, g2 - # Scheduler https://arxiv.org/pdf/1812.01187.pdf - # https://pytorch.org/docs/stable/_modules/torch/optim/lr_scheduler.html#OneCycleLR + # Scheduler if opt.linear_lr: lf = lambda x: (1 - x / (epochs - 1)) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear else: lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] - scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) - # plot_lr_scheduler(optimizer, scheduler, epochs) + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) # EMA - ema = ModelEMA(model) if rank in [-1, 0] else None + ema = ModelEMA(model) if RANK in [-1, 0] else None # Resume start_epoch, best_fitness = 0, 0.0 @@ -156,80 +187,70 @@ def train(hyp, opt, device, tb_writer=None): ema.ema.load_state_dict(ckpt['ema'].float().state_dict()) ema.updates = ckpt['updates'] - # Results - if ckpt.get('training_results') is not None: - results_file.write_text(ckpt['training_results']) # write results.txt - # Epochs start_epoch = ckpt['epoch'] + 1 - if opt.resume: - assert start_epoch > 0, '%s training to %g epochs is finished, nothing to resume.' % (weights, epochs) + if resume: + assert start_epoch > 0, f'{weights} training to {epochs} epochs is finished, nothing to resume.' if epochs < start_epoch: - logger.info('%s has been trained for %g epochs. Fine-tuning for %g additional epochs.' % - (weights, ckpt['epoch'], epochs)) + LOGGER.info(f"{weights} has been trained for {ckpt['epoch']} epochs. Fine-tuning for {epochs} more epochs.") epochs += ckpt['epoch'] # finetune additional epochs - del ckpt, state_dict - - # Image sizes - gs = max(int(model.stride.max()), 32) # grid size (max stride) - nl = model.model[-1].nl # number of detection layers (used for scaling hyp['obj']) - imgsz, imgsz_test = [check_img_size(x, gs) for x in opt.img_size] # verify imgsz are gs-multiples + del ckpt, csd # DP mode - if cuda and rank == -1 and torch.cuda.device_count() > 1: + if cuda and RANK == -1 and torch.cuda.device_count() > 1: + LOGGER.warning('WARNING: DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n' + 'See Multi-GPU Tutorial at https://github.com/ultralytics/yolov5/issues/475 to get started.') model = torch.nn.DataParallel(model) # SyncBatchNorm - if opt.sync_bn and cuda and rank != -1: + if opt.sync_bn and cuda and RANK != -1: model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) - logger.info('Using SyncBatchNorm()') + LOGGER.info('Using SyncBatchNorm()') # Trainloader - dataloader, dataset = create_dataloader(train_path, imgsz, batch_size, gs, opt, - hyp=hyp, augment=True, cache=opt.cache_images, rect=opt.rect, rank=rank, - world_size=opt.world_size, workers=opt.workers, - image_weights=opt.image_weights, quad=opt.quad, prefix=colorstr('train: ')) - mlc = np.concatenate(dataset.labels, 0)[:, 0].max() # max label class - nb = len(dataloader) # number of batches - assert mlc < nc, 'Label class %g exceeds nc=%g in %s. Possible class labels are 0-%g' % (mlc, nc, opt.data, nc - 1) + train_loader, dataset = create_dataloader(train_path, imgsz, batch_size // WORLD_SIZE, gs, single_cls, + hyp=hyp, augment=True, cache=opt.cache, rect=opt.rect, rank=LOCAL_RANK, + workers=workers, image_weights=opt.image_weights, quad=opt.quad, + prefix=colorstr('train: '), shuffle=True) + mlc = int(np.concatenate(dataset.labels, 0)[:, 0].max()) # max label class + nb = len(train_loader) # number of batches + assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}' # Process 0 - if rank in [-1, 0]: - testloader = create_dataloader(test_path, imgsz_test, batch_size * 2, gs, opt, # testloader - hyp=hyp, cache=opt.cache_images and not opt.notest, rect=True, rank=-1, - world_size=opt.world_size, workers=opt.workers, - pad=0.5, prefix=colorstr('val: '))[0] + if RANK in [-1, 0]: + val_loader = create_dataloader(val_path, imgsz, batch_size // WORLD_SIZE * 2, gs, single_cls, + hyp=hyp, cache=None if noval else opt.cache, rect=True, rank=-1, + workers=workers, pad=0.5, + prefix=colorstr('val: '))[0] - if not opt.resume: + if not resume: labels = np.concatenate(dataset.labels, 0) - c = torch.tensor(labels[:, 0]) # classes + # c = torch.tensor(labels[:, 0]) # classes # cf = torch.bincount(c.long(), minlength=nc) + 1. # frequency # model._initialize_biases(cf.to(device)) if plots: - plot_labels(labels, names, save_dir, loggers) - if tb_writer: - tb_writer.add_histogram('classes', c, 0) + plot_labels(labels, names, save_dir) # Anchors if not opt.noautoanchor: check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) model.half().float() # pre-reduce anchor precision + callbacks.run('on_pretrain_routine_end') + # DDP mode - if cuda and rank != -1: - model = DDP(model, device_ids=[opt.local_rank], output_device=opt.local_rank, - # nn.MultiheadAttention incompatibility with DDP https://github.com/pytorch/pytorch/issues/26698 - find_unused_parameters=any(isinstance(layer, nn.MultiheadAttention) for layer in model.modules())) + if cuda and RANK != -1: + model = DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK) # Model parameters - hyp['box'] *= 3. / nl # scale to layers - hyp['cls'] *= nc / 80. * 3. / nl # scale to classes and layers - hyp['obj'] *= (imgsz / 640) ** 2 * 3. / nl # scale to image size and layers + nl = de_parallel(model).model[-1].nl # number of detection layers (to scale hyps) + hyp['box'] *= 3 / nl # scale to layers + hyp['cls'] *= nc / 80 * 3 / nl # scale to classes and layers + hyp['obj'] *= (imgsz / 640) ** 2 * 3 / nl # scale to image size and layers hyp['label_smoothing'] = opt.label_smoothing model.nc = nc # attach number of classes to model model.hyp = hyp # attach hyperparameters to model - model.gr = 1.0 # iou loss ratio (obj_loss = 1.0 or iou) model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights model.names = names @@ -237,53 +258,47 @@ def train(hyp, opt, device, tb_writer=None): t0 = time.time() nw = max(round(hyp['warmup_epochs'] * nb), 1000) # number of warmup iterations, max(3 epochs, 1k iterations) # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training + last_opt_step = -1 maps = np.zeros(nc) # mAP per class results = (0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) scheduler.last_epoch = start_epoch - 1 # do not move scaler = amp.GradScaler(enabled=cuda) + stopper = EarlyStopping(patience=opt.patience) compute_loss = ComputeLoss(model) # init loss class - logger.info(f'Image sizes {imgsz} train, {imgsz_test} test\n' - f'Using {dataloader.num_workers} dataloader workers\n' - f'Logging results to {save_dir}\n' + LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n' + f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' + f"Logging results to {colorstr('bold', save_dir)}\n" f'Starting training for {epochs} epochs...') for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ model.train() - # Update image weights (optional) + # Update image weights (optional, single-GPU only) if opt.image_weights: - # Generate indices - if rank in [-1, 0]: - cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc # class weights - iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights - dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx - # Broadcast if DDP - if rank != -1: - indices = (torch.tensor(dataset.indices) if rank == 0 else torch.zeros(dataset.n)).int() - dist.broadcast(indices, 0) - if rank != 0: - dataset.indices = indices.cpu().numpy() - - # Update mosaic border + cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc # class weights + iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights + dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx + + # Update mosaic border (optional) # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs) # dataset.mosaic_border = [b - imgsz, -b] # height, width borders - mloss = torch.zeros(4, device=device) # mean losses - if rank != -1: - dataloader.sampler.set_epoch(epoch) - pbar = enumerate(dataloader) - logger.info(('\n' + '%10s' * 8) % ('Epoch', 'gpu_mem', 'box', 'obj', 'cls', 'total', 'labels', 'img_size')) - if rank in [-1, 0]: - pbar = tqdm(pbar, total=nb) # progress bar + mloss = torch.zeros(3, device=device) # mean losses + if RANK != -1: + train_loader.sampler.set_epoch(epoch) + pbar = enumerate(train_loader) + LOGGER.info(('\n' + '%10s' * 7) % ('Epoch', 'gpu_mem', 'box', 'obj', 'cls', 'labels', 'img_size')) + if RANK in [-1, 0]: + pbar = tqdm(pbar, total=nb, ncols=NCOLS, bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}') # progress bar optimizer.zero_grad() for i, (imgs, targets, paths, _) in pbar: # batch ------------------------------------------------------------- ni = i + nb * epoch # number integrated batches (since train start) - imgs = imgs.to(device, non_blocking=True).float() / 255.0 # uint8 to float32, 0-255 to 0.0-1.0 + imgs = imgs.to(device, non_blocking=True).float() / 255 # uint8 to float32, 0-255 to 0.0-1.0 # Warmup if ni <= nw: xi = [0, nw] # x interp - # model.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou) - accumulate = max(1, np.interp(ni, xi, [1, nbs / total_batch_size]).round()) + # compute_loss.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou) + accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round()) for j, x in enumerate(optimizer.param_groups): # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 2 else 0.0, x['initial_lr'] * lf(epoch)]) @@ -296,14 +311,14 @@ def train(hyp, opt, device, tb_writer=None): sf = sz / max(imgs.shape[2:]) # scale factor if sf != 1: ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) - imgs = F.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) + imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) # Forward with amp.autocast(enabled=cuda): pred = model(imgs) # forward loss, loss_items = compute_loss(pred, targets.to(device)) # loss scaled by batch_size - if rank != -1: - loss *= opt.world_size # gradient averaged between devices in DDP mode + if RANK != -1: + loss *= WORLD_SIZE # gradient averaged between devices in DDP mode if opt.quad: loss *= 4. @@ -311,234 +326,203 @@ def train(hyp, opt, device, tb_writer=None): scaler.scale(loss).backward() # Optimize - if ni % accumulate == 0: + if ni - last_opt_step >= accumulate: scaler.step(optimizer) # optimizer.step scaler.update() optimizer.zero_grad() if ema: ema.update(model) + last_opt_step = ni - # Print - if rank in [-1, 0]: + # Log + if RANK in [-1, 0]: mloss = (mloss * i + loss_items) / (i + 1) # update mean losses - mem = '%.3gG' % (torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0) # (GB) - s = ('%10s' * 2 + '%10.4g' * 6) % ( - '%g/%g' % (epoch, epochs - 1), mem, *mloss, targets.shape[0], imgs.shape[-1]) - pbar.set_description(s) - - # Plot - if plots and ni < 3: - f = save_dir / f'train_batch{ni}.jpg' # filename - Thread(target=plot_images, args=(imgs, targets, paths, f), daemon=True).start() - if tb_writer: - tb_writer.add_graph(torch.jit.trace(de_parallel(model), imgs, strict=False), []) # model graph - # tb_writer.add_image(f, result, dataformats='HWC', global_step=epoch) - elif plots and ni == 10 and wandb_logger.wandb: - wandb_logger.log({"Mosaics": [wandb_logger.wandb.Image(str(x), caption=x.name) for x in - save_dir.glob('train*.jpg') if x.exists()]}) - + mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G' # (GB) + pbar.set_description(('%10s' * 2 + '%10.4g' * 5) % ( + f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])) + callbacks.run('on_train_batch_end', ni, model, imgs, targets, paths, plots, opt.sync_bn) # end batch ------------------------------------------------------------------------------------------------ - # end epoch ---------------------------------------------------------------------------------------------------- # Scheduler - lr = [x['lr'] for x in optimizer.param_groups] # for tensorboard + lr = [x['lr'] for x in optimizer.param_groups] # for loggers scheduler.step() - # DDP process 0 or single-GPU - if rank in [-1, 0]: + if RANK in [-1, 0]: # mAP - ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'gr', 'names', 'stride', 'class_weights']) - final_epoch = epoch + 1 == epochs - if not opt.notest or final_epoch: # Calculate mAP - wandb_logger.current_epoch = epoch + 1 - results, maps, times = test.test(data_dict, - batch_size=batch_size * 2, - imgsz=imgsz_test, - model=ema.ema, - single_cls=opt.single_cls, - dataloader=testloader, - save_dir=save_dir, - save_json=is_coco and final_epoch, - verbose=nc < 50 and final_epoch, - plots=plots and final_epoch, - wandb_logger=wandb_logger, - compute_loss=compute_loss, - is_coco=is_coco) - - # Write - with open(results_file, 'a') as f: - f.write(s + '%10.4g' * 7 % results + '\n') # append metrics, val_loss - - # Log - tags = ['train/box_loss', 'train/obj_loss', 'train/cls_loss', # train loss - 'metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', - 'val/box_loss', 'val/obj_loss', 'val/cls_loss', # val loss - 'x/lr0', 'x/lr1', 'x/lr2'] # params - for x, tag in zip(list(mloss[:-1]) + list(results) + lr, tags): - if tb_writer: - tb_writer.add_scalar(tag, x, epoch) # tensorboard - if wandb_logger.wandb: - wandb_logger.log({tag: x}) # W&B + callbacks.run('on_train_epoch_end', epoch=epoch) + ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights']) + final_epoch = (epoch + 1 == epochs) or stopper.possible_stop + if not noval or final_epoch: # Calculate mAP + results, maps, _ = val.run(data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + model=ema.ema, + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + plots=False, + callbacks=callbacks, + compute_loss=compute_loss) # Update best mAP fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] if fi > best_fitness: best_fitness = fi - wandb_logger.end_epoch(best_result=best_fitness == fi) + log_vals = list(mloss) + list(results) + lr + callbacks.run('on_fit_epoch_end', log_vals, epoch, best_fitness, fi) # Save model - if (not opt.nosave) or (final_epoch and not opt.evolve): # if save + if (not nosave) or (final_epoch and not evolve): # if save ckpt = {'epoch': epoch, 'best_fitness': best_fitness, - 'training_results': results_file.read_text(), 'model': deepcopy(de_parallel(model)).half(), 'ema': deepcopy(ema.ema).half(), 'updates': ema.updates, 'optimizer': optimizer.state_dict(), - 'wandb_id': wandb_logger.wandb_run.id if wandb_logger.wandb else None} + 'wandb_id': loggers.wandb.wandb_run.id if loggers.wandb else None, + 'date': datetime.now().isoformat()} # Save last, best and delete torch.save(ckpt, last) if best_fitness == fi: torch.save(ckpt, best) - if wandb_logger.wandb: - if ((epoch + 1) % opt.save_period == 0 and not final_epoch) and opt.save_period != -1: - wandb_logger.log_model( - last.parent, opt, epoch, fi, best_model=best_fitness == fi) + if (epoch > 0) and (opt.save_period > 0) and (epoch % opt.save_period == 0): + torch.save(ckpt, w / f'epoch{epoch}.pt') del ckpt + callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi) + + # Stop Single-GPU + if RANK == -1 and stopper(epoch=epoch, fitness=fi): + break + + # Stop DDP TODO: known issues shttps://github.com/ultralytics/yolov5/pull/4576 + # stop = stopper(epoch=epoch, fitness=fi) + # if RANK == 0: + # dist.broadcast_object_list([stop], 0) # broadcast 'stop' to all ranks + + # Stop DPP + # with torch_distributed_zero_first(RANK): + # if stop: + # break # must break all DDP ranks # end epoch ---------------------------------------------------------------------------------------------------- - # end training - if rank in [-1, 0]: - logger.info(f'{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.\n') - if plots: - plot_results(save_dir=save_dir) # save as results.png - if wandb_logger.wandb: - files = ['results.png', 'confusion_matrix.png', *[f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R')]] - wandb_logger.log({"Results": [wandb_logger.wandb.Image(str(save_dir / f), caption=f) for f in files - if (save_dir / f).exists()]}) - - if not opt.evolve: - if is_coco: # COCO dataset - for m in [last, best] if best.exists() else [last]: # speed, mAP tests - results, _, _ = test.test(opt.data, - batch_size=batch_size * 2, - imgsz=imgsz_test, - conf_thres=0.001, - iou_thres=0.7, - model=attempt_load(m, device).half(), - single_cls=opt.single_cls, - dataloader=testloader, - save_dir=save_dir, - save_json=True, - plots=False, - is_coco=is_coco) - - # Strip optimizers - for f in last, best: - if f.exists(): - strip_optimizer(f) # strip optimizers - if wandb_logger.wandb: # Log the stripped model - wandb_logger.wandb.log_artifact(str(best if best.exists() else last), type='model', - name='run_' + wandb_logger.wandb_run.id + '_model', - aliases=['latest', 'best', 'stripped']) - wandb_logger.finish_run() - else: - dist.destroy_process_group() + # end training ----------------------------------------------------------------------------------------------------- + if RANK in [-1, 0]: + LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.') + for f in last, best: + if f.exists(): + strip_optimizer(f) # strip optimizers + if f is best: + LOGGER.info(f'\nValidating {f}...') + results, _, _ = val.run(data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + model=attempt_load(f, device).half(), + iou_thres=0.65 if is_coco else 0.60, # best pycocotools results at 0.65 + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + save_json=is_coco, + verbose=True, + plots=True, + callbacks=callbacks, + compute_loss=compute_loss) # val best model with plots + if is_coco: + callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi) + + callbacks.run('on_train_end', last, best, plots, epoch, results) + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}") + torch.cuda.empty_cache() return results -if __name__ == '__main__': +def parse_opt(known=False): parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default='yolov3.pt', help='initial weights path') + parser.add_argument('--weights', type=str, default=ROOT / 'yolov3.pt', help='initial weights path') parser.add_argument('--cfg', type=str, default='', help='model.yaml path') - parser.add_argument('--data', type=str, default='data/coco128.yaml', help='data.yaml path') - parser.add_argument('--hyp', type=str, default='data/hyp.scratch.yaml', help='hyperparameters path') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') + parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch.yaml', help='hyperparameters path') parser.add_argument('--epochs', type=int, default=300) - parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs') - parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='[train, test] image sizes') + parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') parser.add_argument('--rect', action='store_true', help='rectangular training') parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') - parser.add_argument('--notest', action='store_true', help='only test final epoch') + parser.add_argument('--noval', action='store_true', help='only validate final epoch') parser.add_argument('--noautoanchor', action='store_true', help='disable autoanchor check') - parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters') + parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') - parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') + parser.add_argument('--cache', type=str, nargs='?', const='ram', help='--cache images in "ram" (default) or "disk"') parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer') parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') - parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') - parser.add_argument('--workers', type=int, default=8, help='maximum number of dataloader workers') - parser.add_argument('--project', default='runs/train', help='save to project/name') - parser.add_argument('--entity', default=None, help='W&B entity') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name') parser.add_argument('--name', default='exp', help='save to project/name') parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') parser.add_argument('--quad', action='store_true', help='quad dataloader') parser.add_argument('--linear-lr', action='store_true', help='linear LR') parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') - parser.add_argument('--upload_dataset', action='store_true', help='Upload dataset as W&B artifact table') - parser.add_argument('--bbox_interval', type=int, default=-1, help='Set bounding-box image logging interval for W&B') - parser.add_argument('--save_period', type=int, default=-1, help='Log model after every "save_period" epoch') - parser.add_argument('--artifact_alias', type=str, default="latest", help='version of dataset artifact to be used') - opt = parser.parse_args() - - # Set DDP variables - opt.world_size = int(os.environ['WORLD_SIZE']) if 'WORLD_SIZE' in os.environ else 1 - opt.global_rank = int(os.environ['RANK']) if 'RANK' in os.environ else -1 - set_logging(opt.global_rank) - if opt.global_rank in [-1, 0]: + parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') + parser.add_argument('--freeze', type=int, default=0, help='Number of layers to freeze. backbone=10, all=24') + parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') + parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') + + # Weights & Biases arguments + parser.add_argument('--entity', default=None, help='W&B: Entity') + parser.add_argument('--upload_dataset', action='store_true', help='W&B: Upload dataset as artifact table') + parser.add_argument('--bbox_interval', type=int, default=-1, help='W&B: Set bounding-box image logging interval') + parser.add_argument('--artifact_alias', type=str, default='latest', help='W&B: Version of dataset artifact to use') + + opt = parser.parse_known_args()[0] if known else parser.parse_args() + return opt + + +def main(opt, callbacks=Callbacks()): + # Checks + if RANK in [-1, 0]: + print_args(FILE.stem, opt) check_git_status() - check_requirements(exclude=('pycocotools', 'thop')) + check_requirements(exclude=['thop']) # Resume - wandb_run = check_wandb_resume(opt) - if opt.resume and not wandb_run: # resume an interrupted run + if opt.resume and not check_wandb_resume(opt) and not opt.evolve: # resume an interrupted run ckpt = opt.resume if isinstance(opt.resume, str) else get_latest_run() # specified or most recent path assert os.path.isfile(ckpt), 'ERROR: --resume checkpoint does not exist' - apriori = opt.global_rank, opt.local_rank - with open(Path(ckpt).parent.parent / 'opt.yaml') as f: + with open(Path(ckpt).parent.parent / 'opt.yaml', errors='ignore') as f: opt = argparse.Namespace(**yaml.safe_load(f)) # replace - opt.cfg, opt.weights, opt.resume, opt.batch_size, opt.global_rank, opt.local_rank = \ - '', ckpt, True, opt.total_batch_size, *apriori # reinstate - logger.info('Resuming training from %s' % ckpt) + opt.cfg, opt.weights, opt.resume = '', ckpt, True # reinstate + LOGGER.info(f'Resuming training from {ckpt}') else: - # opt.hyp = opt.hyp or ('hyp.finetune.yaml' if opt.weights else 'hyp.scratch.yaml') - opt.data, opt.cfg, opt.hyp = check_file(opt.data), check_file(opt.cfg), check_file(opt.hyp) # check files + opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \ + check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' - opt.img_size.extend([opt.img_size[-1]] * (2 - len(opt.img_size))) # extend to 2 sizes (train, test) - opt.name = 'evolve' if opt.evolve else opt.name - opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok | opt.evolve)) + if opt.evolve: + opt.project = str(ROOT / 'runs/evolve') + opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume + opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) # DDP mode - opt.total_batch_size = opt.batch_size device = select_device(opt.device, batch_size=opt.batch_size) - if opt.local_rank != -1: - assert torch.cuda.device_count() > opt.local_rank - torch.cuda.set_device(opt.local_rank) - device = torch.device('cuda', opt.local_rank) - dist.init_process_group(backend='nccl', init_method='env://') # distributed backend - assert opt.batch_size % opt.world_size == 0, '--batch-size must be multiple of CUDA device count' + if LOCAL_RANK != -1: + assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' + assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' - opt.batch_size = opt.total_batch_size // opt.world_size - - # Hyperparameters - with open(opt.hyp) as f: - hyp = yaml.safe_load(f) # load hyps + assert not opt.evolve, '--evolve argument is not compatible with DDP training' + torch.cuda.set_device(LOCAL_RANK) + device = torch.device('cuda', LOCAL_RANK) + dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") # Train - logger.info(opt) if not opt.evolve: - tb_writer = None # init loggers - if opt.global_rank in [-1, 0]: - prefix = colorstr('tensorboard: ') - logger.info(f"{prefix}Start with 'tensorboard --logdir {opt.project}', view at http://localhost:6006/") - tb_writer = SummaryWriter(opt.save_dir) # Tensorboard - train(hyp, opt, device, tb_writer) + train(opt.hyp, opt, device, callbacks) + if WORLD_SIZE > 1 and RANK == 0: + LOGGER.info('Destroying process group... ') + dist.destroy_process_group() # Evolve hyperparameters (optional) else: @@ -570,23 +554,27 @@ def train(hyp, opt, device, tb_writer=None): 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) 'mosaic': (1, 0.0, 1.0), # image mixup (probability) - 'mixup': (1, 0.0, 1.0)} # image mixup (probability) - - assert opt.local_rank == -1, 'DDP mode not implemented for --evolve' - opt.notest, opt.nosave = True, True # only test/save final epoch + 'mixup': (1, 0.0, 1.0), # image mixup (probability) + 'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) + + with open(opt.hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + if 'anchors' not in hyp: # anchors commented in hyp.yaml + hyp['anchors'] = 3 + opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir) # only val/save final epoch # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices - yaml_file = Path(opt.save_dir) / 'hyp_evolved.yaml' # save best result here + evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' if opt.bucket: - os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket) # download evolve.txt if exists + os.system(f'gsutil cp gs://{opt.bucket}/evolve.csv {save_dir}') # download evolve.csv if exists - for _ in range(300): # generations to evolve - if Path('evolve.txt').exists(): # if evolve.txt exists: select best hyps and mutate + for _ in range(opt.evolve): # generations to evolve + if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate # Select parent(s) parent = 'single' # parent selection method: 'single' or 'weighted' - x = np.loadtxt('evolve.txt', ndmin=2) + x = np.loadtxt(evolve_csv, ndmin=2, delimiter=',', skiprows=1) n = min(5, len(x)) # number of previous results to consider x = x[np.argsort(-fitness(x))][:n] # top n mutations - w = fitness(x) - fitness(x).min() # weights + w = fitness(x) - fitness(x).min() + 1E-6 # weights (sum > 0) if parent == 'single' or len(x) == 1: # x = x[random.randint(0, n - 1)] # random selection x = x[random.choices(range(n), weights=w)[0]] # weighted selection @@ -597,7 +585,7 @@ def train(hyp, opt, device, tb_writer=None): mp, s = 0.8, 0.2 # mutation probability, sigma npr = np.random npr.seed(int(time.time())) - g = np.array([x[0] for x in meta.values()]) # gains 0-1 + g = np.array([meta[k][0] for k in hyp.keys()]) # gains 0-1 ng = len(meta) v = np.ones(ng) while all(v == 1): # mutate until a change occurs (prevent duplicates) @@ -612,12 +600,26 @@ def train(hyp, opt, device, tb_writer=None): hyp[k] = round(hyp[k], 5) # significant digits # Train mutation - results = train(hyp.copy(), opt, device) + results = train(hyp.copy(), opt, device, callbacks) # Write mutation results - print_mutation(hyp.copy(), results, yaml_file, opt.bucket) + print_mutation(results, hyp.copy(), save_dir, opt.bucket) # Plot results - plot_evolution(yaml_file) - print(f'Hyperparameter evolution complete. Best results saved as: {yaml_file}\n' - f'Command to train a new model with these hyperparameters: $ python train.py --hyp {yaml_file}') + plot_evolve(evolve_csv) + LOGGER.info(f'Hyperparameter evolution finished\n' + f"Results saved to {colorstr('bold', save_dir)}\n" + f'Use best hyperparameters example: $ python train.py --hyp {evolve_yaml}') + + +def run(**kwargs): + # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolov3.pt') + opt = parse_opt(True) + for k, v in kwargs.items(): + setattr(opt, k, v) + main(opt) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/tutorial.ipynb b/tutorial.ipynb index 617c5c5238..828e434f6b 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -6,7 +6,6 @@ "name": "YOLOv3 Tutorial", "provenance": [], "collapsed_sections": [], - "toc_visible": true, "include_colab_link": true }, "kernelspec": { @@ -16,9 +15,10 @@ "accelerator": "GPU", "widgets": { "application/vnd.jupyter.widget-state+json": { - "355d9ee3dfc4487ebcae3b66ddbedce1": { + "eeda9d6850e8406f9bbc5b06051b3710": { "model_module": "@jupyter-widgets/controls", "model_name": "HBoxModel", + "model_module_version": "1.5.0", "state": { "_view_name": "HBoxView", "_dom_classes": [], @@ -28,17 +28,19 @@ "_view_count": null, "_view_module_version": "1.5.0", "box_style": "", - "layout": "IPY_MODEL_8209acd3185441e7b263eead5e8babdf", + "layout": "IPY_MODEL_1e823c45174a4216be7234a6cc5cfd99", "_model_module": "@jupyter-widgets/controls", "children": [ - "IPY_MODEL_b81d30356f7048b0abcba35bde811526", - "IPY_MODEL_7fcbf6b56f2e4b6dbf84e48465c96633" + "IPY_MODEL_cd8efd6c5de94ea8848a7d5b8766a4d6", + "IPY_MODEL_a4ec69c4697c4b0e84e6193be227f63e", + "IPY_MODEL_9a5694c133be46df8d2fe809b77c1c35" ] } }, - "8209acd3185441e7b263eead5e8babdf": { + "1e823c45174a4216be7234a6cc5cfd99": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", + "model_module_version": "1.2.0", "state": { "_view_name": "LayoutView", "grid_template_rows": null, @@ -87,118 +89,76 @@ "left": null } }, - "b81d30356f7048b0abcba35bde811526": { + "cd8efd6c5de94ea8848a7d5b8766a4d6": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_view_name": "HTMLView", + "style": "IPY_MODEL_d584167143f84a0484006dded3fd2620", + "_dom_classes": [], + "description": "", + "_model_name": "HTMLModel", + "placeholder": "​", + "_view_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "value": "100%", + "_view_count": null, + "_view_module_version": "1.5.0", + "description_tooltip": null, + "_model_module": "@jupyter-widgets/controls", + "layout": "IPY_MODEL_b9a25c0d425c4fe4b8cd51ae6a301b0d" + } + }, + "a4ec69c4697c4b0e84e6193be227f63e": { "model_module": "@jupyter-widgets/controls", "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", "state": { "_view_name": "ProgressView", - "style": "IPY_MODEL_6ee48f9f3af444a7b02ec2f074dec1f8", + "style": "IPY_MODEL_654525fe1ed34d5fbe1c36ed80ae1c1c", "_dom_classes": [], - "description": "100%", + "description": "", "_model_name": "FloatProgressModel", "bar_style": "success", - "max": 819257867, + "max": 818322941, "_view_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", - "value": 819257867, + "value": 818322941, "_view_count": null, "_view_module_version": "1.5.0", "orientation": "horizontal", "min": 0, "description_tooltip": null, "_model_module": "@jupyter-widgets/controls", - "layout": "IPY_MODEL_b7d819ed5f2f4e39a75a823792ab7249" + "layout": "IPY_MODEL_09544845070e47baafc5e37d45ff23e9" } }, - "7fcbf6b56f2e4b6dbf84e48465c96633": { + "9a5694c133be46df8d2fe809b77c1c35": { "model_module": "@jupyter-widgets/controls", "model_name": "HTMLModel", + "model_module_version": "1.5.0", "state": { "_view_name": "HTMLView", - "style": "IPY_MODEL_3af216dd7d024739b8168995800ed8be", + "style": "IPY_MODEL_1066f1d5b6104a3dae19f26269745bd0", "_dom_classes": [], "description": "", "_model_name": "HTMLModel", "placeholder": "​", "_view_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", - "value": " 781M/781M [00:11<00:00, 71.1MB/s]", + "value": " 780M/780M [00:03<00:00, 200MB/s]", "_view_count": null, "_view_module_version": "1.5.0", "description_tooltip": null, "_model_module": "@jupyter-widgets/controls", - "layout": "IPY_MODEL_763141d8de8a498a92ffa66aafed0c5a" - } - }, - "6ee48f9f3af444a7b02ec2f074dec1f8": { - "model_module": "@jupyter-widgets/controls", - "model_name": "ProgressStyleModel", - "state": { - "_view_name": "StyleView", - "_model_name": "ProgressStyleModel", - "description_width": "initial", - "_view_module": "@jupyter-widgets/base", - "_model_module_version": "1.5.0", - "_view_count": null, - "_view_module_version": "1.2.0", - "bar_color": null, - "_model_module": "@jupyter-widgets/controls" - } - }, - "b7d819ed5f2f4e39a75a823792ab7249": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "state": { - "_view_name": "LayoutView", - "grid_template_rows": null, - "right": null, - "justify_content": null, - "_view_module": "@jupyter-widgets/base", - "overflow": null, - "_model_module_version": "1.2.0", - "_view_count": null, - "flex_flow": null, - "width": null, - "min_width": null, - "border": null, - "align_items": null, - "bottom": null, - "_model_module": "@jupyter-widgets/base", - "top": null, - "grid_column": null, - "overflow_y": null, - "overflow_x": null, - "grid_auto_flow": null, - "grid_area": null, - "grid_template_columns": null, - "flex": null, - "_model_name": "LayoutModel", - "justify_items": null, - "grid_row": null, - "max_height": null, - "align_content": null, - "visibility": null, - "align_self": null, - "height": null, - "min_height": null, - "padding": null, - "grid_auto_rows": null, - "grid_gap": null, - "max_width": null, - "order": null, - "_view_module_version": "1.2.0", - "grid_template_areas": null, - "object_position": null, - "object_fit": null, - "grid_auto_columns": null, - "margin": null, - "display": null, - "left": null + "layout": "IPY_MODEL_dd3a70e1ef4547ec8d3463749ce06285" } }, - "3af216dd7d024739b8168995800ed8be": { + "d584167143f84a0484006dded3fd2620": { "model_module": "@jupyter-widgets/controls", "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", "state": { "_view_name": "StyleView", "_model_name": "DescriptionStyleModel", @@ -210,80 +170,10 @@ "_model_module": "@jupyter-widgets/controls" } }, - "763141d8de8a498a92ffa66aafed0c5a": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "state": { - "_view_name": "LayoutView", - "grid_template_rows": null, - "right": null, - "justify_content": null, - "_view_module": "@jupyter-widgets/base", - "overflow": null, - "_model_module_version": "1.2.0", - "_view_count": null, - "flex_flow": null, - "width": null, - "min_width": null, - "border": null, - "align_items": null, - "bottom": null, - "_model_module": "@jupyter-widgets/base", - "top": null, - "grid_column": null, - "overflow_y": null, - "overflow_x": null, - "grid_auto_flow": null, - "grid_area": null, - "grid_template_columns": null, - "flex": null, - "_model_name": "LayoutModel", - "justify_items": null, - "grid_row": null, - "max_height": null, - "align_content": null, - "visibility": null, - "align_self": null, - "height": null, - "min_height": null, - "padding": null, - "grid_auto_rows": null, - "grid_gap": null, - "max_width": null, - "order": null, - "_view_module_version": "1.2.0", - "grid_template_areas": null, - "object_position": null, - "object_fit": null, - "grid_auto_columns": null, - "margin": null, - "display": null, - "left": null - } - }, - "0fffa335322b41658508e06aed0acbf0": { - "model_module": "@jupyter-widgets/controls", - "model_name": "HBoxModel", - "state": { - "_view_name": "HBoxView", - "_dom_classes": [], - "_model_name": "HBoxModel", - "_view_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_view_count": null, - "_view_module_version": "1.5.0", - "box_style": "", - "layout": "IPY_MODEL_a354c6f80ce347e5a3ef64af87c0eccb", - "_model_module": "@jupyter-widgets/controls", - "children": [ - "IPY_MODEL_85823e71fea54c39bd11e2e972348836", - "IPY_MODEL_fb11acd663fa4e71b041d67310d045fd" - ] - } - }, - "a354c6f80ce347e5a3ef64af87c0eccb": { + "b9a25c0d425c4fe4b8cd51ae6a301b0d": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", + "model_module_version": "1.2.0", "state": { "_view_name": "LayoutView", "grid_template_rows": null, @@ -332,56 +222,14 @@ "left": null } }, - "85823e71fea54c39bd11e2e972348836": { - "model_module": "@jupyter-widgets/controls", - "model_name": "FloatProgressModel", - "state": { - "_view_name": "ProgressView", - "style": "IPY_MODEL_8a919053b780449aae5523658ad611fa", - "_dom_classes": [], - "description": "100%", - "_model_name": "FloatProgressModel", - "bar_style": "success", - "max": 22091032, - "_view_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "value": 22091032, - "_view_count": null, - "_view_module_version": "1.5.0", - "orientation": "horizontal", - "min": 0, - "description_tooltip": null, - "_model_module": "@jupyter-widgets/controls", - "layout": "IPY_MODEL_5bae9393a58b44f7b69fb04816f94f6f" - } - }, - "fb11acd663fa4e71b041d67310d045fd": { - "model_module": "@jupyter-widgets/controls", - "model_name": "HTMLModel", - "state": { - "_view_name": "HTMLView", - "style": "IPY_MODEL_d26c6d16c7f24030ab2da5285bf198ee", - "_dom_classes": [], - "description": "", - "_model_name": "HTMLModel", - "placeholder": "​", - "_view_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "value": " 21.1M/21.1M [00:02<00:00, 9.36MB/s]", - "_view_count": null, - "_view_module_version": "1.5.0", - "description_tooltip": null, - "_model_module": "@jupyter-widgets/controls", - "layout": "IPY_MODEL_f7767886b2364c8d9efdc79e175ad8eb" - } - }, - "8a919053b780449aae5523658ad611fa": { + "654525fe1ed34d5fbe1c36ed80ae1c1c": { "model_module": "@jupyter-widgets/controls", "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", "state": { "_view_name": "StyleView", "_model_name": "ProgressStyleModel", - "description_width": "initial", + "description_width": "", "_view_module": "@jupyter-widgets/base", "_model_module_version": "1.5.0", "_view_count": null, @@ -390,9 +238,10 @@ "_model_module": "@jupyter-widgets/controls" } }, - "5bae9393a58b44f7b69fb04816f94f6f": { + "09544845070e47baafc5e37d45ff23e9": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", + "model_module_version": "1.2.0", "state": { "_view_name": "LayoutView", "grid_template_rows": null, @@ -441,9 +290,10 @@ "left": null } }, - "d26c6d16c7f24030ab2da5285bf198ee": { + "1066f1d5b6104a3dae19f26269745bd0": { "model_module": "@jupyter-widgets/controls", "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", "state": { "_view_name": "StyleView", "_model_name": "DescriptionStyleModel", @@ -455,9 +305,10 @@ "_model_module": "@jupyter-widgets/controls" } }, - "f7767886b2364c8d9efdc79e175ad8eb": { + "dd3a70e1ef4547ec8d3463749ce06285": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", + "model_module_version": "1.2.0", "state": { "_view_name": "LayoutView", "grid_template_rows": null, @@ -517,20 +368,20 @@ "colab_type": "text" }, "source": [ - "\"Open", - "\"Kaggle\"" + "\"Open" ] }, { "cell_type": "markdown", "metadata": { - "id": "HvhYZrIZCEyo" + "id": "t6MPjfT5NrKQ" }, "source": [ - "\n", + "\n", + "\n", "\n", - "This is the **official YOLOv3 🚀 notebook** authored by **Ultralytics**, and is freely available for redistribution under the [GPL-3.0 license](https://choosealicense.com/licenses/gpl-3.0/). \n", - "For more information please visit https://github.com/ultralytics/yolov3 and https://www.ultralytics.com. Thank you!" + "This is the **official YOLOv3 🚀 notebook** by **Ultralytics**, and is freely available for redistribution under the [GPL-3.0 license](https://choosealicense.com/licenses/gpl-3.0/). \n", + "For more information please visit https://github.com/ultralytics/yolov3 and https://ultralytics.com. Thank you!" ] }, { @@ -551,27 +402,32 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "56f7b795-7a7b-46a1-8c5e-d06040187a85" + "outputId": "2e5d0950-2978-4304-856f-3b39f0d6627c" }, "source": [ - "!git clone https://github.com/ultralytics/yolov3 # clone repo\n", + "!git clone https://github.com/ultralytics/yolov3 -b update/yolov5_v6.0_release # clone\n", "%cd yolov3\n", - "%pip install -qr requirements.txt # install dependencies\n", + "%pip install -qr requirements.txt # install\n", "\n", "import torch\n", - "from IPython.display import Image, clear_output # to display images\n", - "\n", - "clear_output()\n", - "print(f\"Setup complete. Using torch {torch.__version__} ({torch.cuda.get_device_properties(0).name if torch.cuda.is_available() else 'CPU'})\")" + "from yolov3 import utils\n", + "display = utils.notebook_init() # checks" ], - "execution_count": null, + "execution_count": 1, "outputs": [ { "output_type": "stream", + "name": "stderr", "text": [ - "Setup complete. Using torch 1.8.1+cu101 (Tesla P100-PCIE-16GB)\n" - ], - "name": "stdout" + "YOLOv3 🚀 v9.5.0-20-g9d10fe5 torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Setup complete ✅\n" + ] } ] }, @@ -585,7 +441,15 @@ "\n", "`detect.py` runs YOLOv3 inference on a variety of sources, downloading models automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases), and saving results to `runs/detect`. Example inference sources are:\n", "\n", - " " + "```shell\n", + "python detect.py --source 0 # webcam\n", + " img.jpg # image \n", + " vid.mp4 # video\n", + " path/ # directory\n", + " path/*.jpg # glob\n", + " 'https://youtu.be/Zgi9g1ksQHc' # YouTube\n", + " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", + "```" ] }, { @@ -593,58 +457,51 @@ "metadata": { "id": "zR9ZbuQCH7FX", "colab": { - "base_uri": "https://localhost:8080/", - "height": 521 + "base_uri": "https://localhost:8080/" }, - "outputId": "bd41a070-3498-42e1-ac1b-3900ac0c2ec2" + "outputId": "499c53a7-95f7-4fc1-dab8-7a660b813546" }, "source": [ - "!python detect.py --weights yolov3.pt --img 640 --conf 0.25 --source data/images/\n", - "Image(filename='runs/detect/exp/zidane.jpg', width=600)" + "!python detect.py --weights yolov3.pt --img 640 --conf 0.25 --source data/images\n", + "display.Image(filename='runs/detect/exp/zidane.jpg', width=600)" ], - "execution_count": null, + "execution_count": 3, "outputs": [ { "output_type": "stream", + "name": "stdout", "text": [ - "Namespace(agnostic_nms=False, augment=False, classes=None, conf_thres=0.25, device='', exist_ok=False, img_size=640, iou_thres=0.45, name='exp', nosave=False, project='runs/detect', save_conf=False, save_txt=False, source='data/images/', update=False, view_img=False, weights=['yolov3.pt'])\n", - "YOLOv3 🚀 v9.5.0-1-gbe29298 torch 1.8.1+cu101 CUDA:0 (Tesla P100-PCIE-16GB, 16280.875MB)\n", + "\u001b[34m\u001b[1mdetect: \u001b[0mweights=['yolov3.pt'], source=data/images, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False\n", + "YOLOv3 🚀 v9.5.0-20-g9d10fe5 torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n", "\n", "Fusing layers... \n", - "Model Summary: 261 layers, 61922845 parameters, 0 gradients, 156.3 GFLOPS\n", - "image 1/2 /content/yolov3/data/images/bus.jpg: 640x480 4 persons, 1 bus, Done. (0.026s)\n", - "image 2/2 /content/yolov3/data/images/zidane.jpg: 384x640 2 persons, 3 ties, Done. (0.025s)\n", - "Results saved to runs/detect/exp2\n", - "Done. (0.119s)\n" - ], - "name": "stdout" - }, - { - "output_type": "execute_result", - "data": { - "image/jpeg": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": { - "tags": [], - "image/jpeg": { - "width": 600 - } - }, - "execution_count": 5 + "Model Summary: 261 layers, 61922845 parameters, 0 gradients\n", + "image 1/2 /content/yolov3/data/images/bus.jpg: 640x480 4 persons, 1 bus, 1 tie, Done. (0.020s)\n", + "image 2/2 /content/yolov3/data/images/zidane.jpg: 384x640 2 persons, 3 ties, Done. (0.020s)\n", + "Speed: 0.5ms pre-process, 19.8ms inference, 1.2ms NMS per image at shape (1, 3, 640, 640)\n", + "Results saved to \u001b[1mruns/detect/exp\u001b[0m\n" + ] } ] }, + { + "cell_type": "markdown", + "metadata": { + "id": "hkAzDWJ7cWTr" + }, + "source": [ + "        \n", + "" + ] + }, { "cell_type": "markdown", "metadata": { "id": "0eq1SMWl6Sfn" }, "source": [ - "# 2. Test\n", - "Test a model's accuracy on [COCO](https://cocodataset.org/#home) val or test-dev datasets. Models are downloaded automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases). To show results by class use the `--verbose` flag. Note that `pycocotools` metrics may be ~1% better than the equivalent repo metrics, as is visible below, due to slight differences in mAP computation." + "# 2. Validate\n", + "Validate a model's accuracy on [COCO](https://cocodataset.org/#home) val or test-dev datasets. Models are downloaded automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases). To show results by class use the `--verbose` flag. Note that `pycocotools` metrics may be ~1% better than the equivalent repo metrics, as is visible below, due to slight differences in mAP computation." ] }, { @@ -653,8 +510,8 @@ "id": "eyTZYGgRjnMc" }, "source": [ - "## COCO val2017\n", - "Download [COCO val 2017](https://github.com/ultralytics/yolov5/blob/74b34872fdf41941cddcf243951cdb090fbac17b/data/coco.yaml#L14) dataset (1GB - 5000 images), and test model accuracy." + "## COCO val\n", + "Download [COCO val 2017](https://github.com/ultralytics/yolov3/blob/master/data/coco.yaml) dataset (1GB - 5000 images), and test model accuracy." ] }, { @@ -663,49 +520,43 @@ "id": "WQPtK1QYVaD_", "colab": { "base_uri": "https://localhost:8080/", - "height": 65, + "height": 48, "referenced_widgets": [ - "355d9ee3dfc4487ebcae3b66ddbedce1", - "8209acd3185441e7b263eead5e8babdf", - "b81d30356f7048b0abcba35bde811526", - "7fcbf6b56f2e4b6dbf84e48465c96633", - "6ee48f9f3af444a7b02ec2f074dec1f8", - "b7d819ed5f2f4e39a75a823792ab7249", - "3af216dd7d024739b8168995800ed8be", - "763141d8de8a498a92ffa66aafed0c5a" + "eeda9d6850e8406f9bbc5b06051b3710", + "1e823c45174a4216be7234a6cc5cfd99", + "cd8efd6c5de94ea8848a7d5b8766a4d6", + "a4ec69c4697c4b0e84e6193be227f63e", + "9a5694c133be46df8d2fe809b77c1c35", + "d584167143f84a0484006dded3fd2620", + "b9a25c0d425c4fe4b8cd51ae6a301b0d", + "654525fe1ed34d5fbe1c36ed80ae1c1c", + "09544845070e47baafc5e37d45ff23e9", + "1066f1d5b6104a3dae19f26269745bd0", + "dd3a70e1ef4547ec8d3463749ce06285" ] }, - "outputId": "f7e4fb76-74db-4810-c705-b416bc862b52" + "outputId": "56199bac-5a5e-41eb-8892-bf387a1ec7cb" }, "source": [ - "# Download COCO val2017\n", - "torch.hub.download_url_to_file('https://github.com/ultralytics/yolov5/releases/download/v1.0/coco2017val.zip', 'tmp.zip')\n", - "!unzip -q tmp.zip -d ../ && rm tmp.zip" + "# Download COCO val\n", + "torch.hub.download_url_to_file('https://ultralytics.com/assets/coco2017val.zip', 'tmp.zip')\n", + "!unzip -q tmp.zip -d ../datasets && rm tmp.zip" ], - "execution_count": null, + "execution_count": 4, "outputs": [ { "output_type": "display_data", "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "355d9ee3dfc4487ebcae3b66ddbedce1", + "model_id": "eeda9d6850e8406f9bbc5b06051b3710", "version_minor": 0, "version_major": 2 }, "text/plain": [ - "HBox(children=(FloatProgress(value=0.0, max=819257867.0), HTML(value='')))" + " 0%| | 0.00/780M [00:00

\n", + "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", + "

\n", "\n", - "All training results are saved to `runs/train/` with incrementing run directories, i.e. `runs/train/exp2`, `runs/train/exp3` etc.\n" + "Train a YOLOv3 model on the [COCO128](https://www.kaggle.com/ultralytics/coco128) dataset with `--data coco128.yaml`, starting from pretrained `--weights yolov3.pt`, or from randomly initialized `--weights '' --cfg yolov3yaml`.\n", + "\n", + "- **Pretrained [Models](https://github.com/ultralytics/yolov3/tree/master/models)** are downloaded\n", + "automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases)\n", + "- **[Datasets](https://github.com/ultralytics/yolov3/tree/master/data)** available for autodownload include: [COCO](https://github.com/ultralytics/yolov3/blob/master/data/coco.yaml), [COCO128](https://github.com/ultralytics/yolov3/blob/master/data/coco128.yaml), [VOC](https://github.com/ultralytics/yolov3/blob/master/data/VOC.yaml), [Argoverse](https://github.com/ultralytics/yolov3/blob/master/data/Argoverse.yaml), [VisDrone](https://github.com/ultralytics/yolov3/blob/master/data/VisDrone.yaml), [GlobalWheat](https://github.com/ultralytics/yolov3/blob/master/data/GlobalWheat2020.yaml), [xView](https://github.com/ultralytics/yolov3/blob/master/data/xView.yaml), [Objects365](https://github.com/ultralytics/yolov3/blob/master/data/Objects365.yaml), [SKU-110K](https://github.com/ultralytics/yolov3/blob/master/data/SKU-110K.yaml).\n", + "- **Training Results** are saved to `runs/train/` with incrementing run directories, i.e. `runs/train/exp2`, `runs/train/exp3` etc.\n", + "

\n" ] }, { @@ -887,7 +684,7 @@ "id": "bOy5KI2ncnWd" }, "source": [ - "# Tensorboard (optional)\n", + "# Tensorboard (optional)\n", "%load_ext tensorboard\n", "%tensorboard --logdir runs/train" ], @@ -915,25 +712,25 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "3638328f-e897-40d5-c49f-3dfbcea258a9" + "outputId": "28039ba4-b23b-4e59-ea0e-e1f8f7df0cdb" }, "source": [ "# Train YOLOv3 on COCO128 for 3 epochs\n", - "!python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov3.pt --nosave --cache" + "!python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov3.pt --cache" ], - "execution_count": null, + "execution_count": 8, "outputs": [ { "output_type": "stream", + "name": "stdout", "text": [ + "\u001b[34m\u001b[1mtrain: \u001b[0mweights=yolov3.pt, cfg=, data=coco128.yaml, hyp=data/hyps/hyp.scratch.yaml, epochs=3, batch_size=16, imgsz=640, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, evolve=None, bucket=, cache=ram, image_weights=False, device=, multi_scale=False, single_cls=False, adam=False, sync_bn=False, workers=8, project=runs/train, name=exp, exist_ok=False, quad=False, linear_lr=False, label_smoothing=0.0, patience=100, freeze=0, save_period=-1, local_rank=-1, entity=None, upload_dataset=False, bbox_interval=-1, artifact_alias=latest\n", "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov3 ✅\n", - "YOLOv3 🚀 v9.5.0-1-gbe29298 torch 1.8.1+cu101 CUDA:0 (Tesla P100-PCIE-16GB, 16280.875MB)\n", + "YOLOv3 🚀 v9.5.0-20-g9d10fe5 torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n", "\n", - "Namespace(adam=False, artifact_alias='latest', batch_size=16, bbox_interval=-1, bucket='', cache_images=True, cfg='', data='./data/coco128.yaml', device='', entity=None, epochs=3, evolve=False, exist_ok=False, global_rank=-1, hyp='data/hyp.scratch.yaml', image_weights=False, img_size=[640, 640], label_smoothing=0.0, linear_lr=False, local_rank=-1, multi_scale=False, name='exp', noautoanchor=False, nosave=True, notest=False, project='runs/train', quad=False, rect=False, resume=False, save_dir='runs/train/exp', save_period=-1, single_cls=False, sync_bn=False, total_batch_size=16, upload_dataset=False, weights='yolov3.pt', workers=8, world_size=1)\n", - "\u001b[34m\u001b[1mtensorboard: \u001b[0mStart with 'tensorboard --logdir runs/train', view at http://localhost:6006/\n", - "2021-04-12 21:26:33.963524: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcudart.so.11.0\n", - "\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.2, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0\n", - "\u001b[34m\u001b[1mwandb: \u001b[0mInstall Weights & Biases for YOLOv5 logging with 'pip install wandb' (recommended)\n", + "\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.1, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0\n", + "\u001b[34m\u001b[1mWeights & Biases: \u001b[0mrun 'pip install wandb' to automatically track and visualize YOLOv3 🚀 runs (RECOMMENDED)\n", + "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train', view at http://localhost:6006/\n", "\n", " from n params module arguments \n", " 0 -1 1 928 models.common.Conv [3, 32, 3, 1] \n", @@ -965,49 +762,121 @@ " 26 -1 1 344832 models.common.Bottleneck [384, 256, False] \n", " 27 -1 2 656896 models.common.Bottleneck [256, 256, False] \n", " 28 [27, 22, 15] 1 457725 models.yolo.Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [256, 512, 1024]]\n", - "Model Summary: 333 layers, 61949149 parameters, 61949149 gradients, 156.4 GFLOPS\n", - "\n", - "Transferred 440/440 items from yolov3.pt\n", - "\n", - "WARNING: Dataset not found, nonexistent paths: ['/content/coco128/images/train2017']\n", - "Downloading https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip ...\n", - "100% 21.1M/21.1M [00:01<00:00, 13.6MB/s]\n", - "Dataset autodownload success\n", + "Model Summary: 333 layers, 61949149 parameters, 61949149 gradients, 156.3 GFLOPs\n", "\n", + "Transferred 439/439 items from yolov3.pt\n", "Scaled weight_decay = 0.0005\n", - "Optimizer groups: 75 .bias, 75 conv.weight, 72 other\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mScanning '../coco128/labels/train2017' images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 3076.66it/s]\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mNew cache created: ../coco128/labels/train2017.cache\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mCaching images (0.1GB): 100% 128/128 [00:00<00:00, 217.17it/s]\n", - "\u001b[34m\u001b[1mval: \u001b[0mScanning '../coco128/labels/train2017.cache' images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 797727.95it/s]\n", - "\u001b[34m\u001b[1mval: \u001b[0mCaching images (0.1GB): 100% 128/128 [00:00<00:00, 149.28it/s]\n", - "Plotting labels... \n", + "\u001b[34m\u001b[1moptimizer:\u001b[0m SGD with parameter groups 72 weight, 75 weight (no decay), 75 bias\n", + "\u001b[34m\u001b[1malbumentations: \u001b[0mversion 1.0.3 required by YOLOv3, but version 0.1.12 is currently installed\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mScanning '../datasets/coco128/labels/train2017.cache' images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00" + "

\"Weights

" ] }, { @@ -1043,67 +912,25 @@ "source": [ "## Local Logging\n", "\n", - "All results are logged by default to `runs/train`, with a new experiment directory created for each new training as `runs/train/exp2`, `runs/train/exp3`, etc. View train and test jpgs to see mosaics, labels, predictions and augmentation effects. Note a **Mosaic Dataloader** is used for training (shown below), a new concept developed by Ultralytics and first featured in [YOLOv4](https://arxiv.org/abs/2004.10934)." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "riPdhraOTCO0" - }, - "source": [ - "Image(filename='runs/train/exp/train_batch0.jpg', width=800) # train batch 0 mosaics and labels\n", - "Image(filename='runs/train/exp/test_batch0_labels.jpg', width=800) # test batch 0 labels\n", - "Image(filename='runs/train/exp/test_batch0_pred.jpg', width=800) # test batch 0 predictions" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "OYG4WFEnTVrI" - }, - "source": [ - "> \n", + "All results are logged by default to `runs/train`, with a new experiment directory created for each new training as `runs/train/exp2`, `runs/train/exp3`, etc. View train and val jpgs to see mosaics, labels, predictions and augmentation effects. Note an Ultralytics **Mosaic Dataloader** is used for training (shown below), which combines 4 images into 1 mosaic during training.\n", + "\n", + "> \n", "`train_batch0.jpg` shows train batch 0 mosaics and labels\n", "\n", - "> \n", - "`test_batch0_labels.jpg` shows test batch 0 labels\n", + "> \n", + "`test_batch0_labels.jpg` shows val batch 0 labels\n", "\n", - "> \n", - "`test_batch0_pred.jpg` shows test batch 0 _predictions_\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "7KN5ghjE6ZWh" - }, - "source": [ - "Training losses and performance metrics are also logged to [Tensorboard](https://www.tensorflow.org/tensorboard) and a custom `results.txt` logfile which is plotted as `results.png` (below) after training completes. Here we show YOLOv3 trained on COCO128 to 300 epochs, starting from scratch (blue), and from pretrained `--weights yolov3.pt` (orange)." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "MDznIqPF7nk3" - }, - "source": [ + "> \n", + "`test_batch0_pred.jpg` shows val batch 0 _predictions_\n", + "\n", + "Training results are automatically logged to [Tensorboard](https://www.tensorflow.org/tensorboard) and [CSV](https://github.com/ultralytics/yolov5/pull/4148) as `results.csv`, which is plotted as `results.png` (below) after training completes. You can also plot any `results.csv` file manually:\n", + "\n", + "```python\n", "from utils.plots import plot_results \n", - "plot_results(save_dir='runs/train/exp') # plot all results*.txt as results.png\n", - "Image(filename='runs/train/exp/results.png', width=800)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "lfrEegCSW3fK" - }, - "source": [ - "\n" + "plot_results('path/to/results.csv') # plot 'results.csv' as 'results.png'\n", + "```\n", + "\n", + "\"COCO128" ] }, { @@ -1116,10 +943,10 @@ "\n", "YOLOv3 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):\n", "\n", - "- **Google Colab and Kaggle** notebooks with free GPU: \"Open \"Open\n", - "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/GCP-Quickstart)\n", - "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/AWS-Quickstart)\n", - "- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/Docker-Quickstart) \"Docker\n" + "- **Google Colab and Kaggle** notebooks with free GPU: \"Open \"Open\n", + "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart)\n", + "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/AWS-Quickstart)\n", + "- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) \"Docker\n" ] }, { @@ -1130,9 +957,9 @@ "source": [ "# Status\n", "\n", - "![CI CPU testing](https://github.com/ultralytics/yolov5/workflows/CI%20CPU%20testing/badge.svg)\n", + "![CI CPU testing](https://github.com/ultralytics/yolov3/workflows/CI%20CPU%20testing/badge.svg)\n", "\n", - "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov5/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 training ([train.py](https://github.com/ultralytics/yolov5/blob/master/train.py)), testing ([test.py](https://github.com/ultralytics/yolov5/blob/master/test.py)), inference ([detect.py](https://github.com/ultralytics/yolov5/blob/master/detect.py)) and export ([export.py](https://github.com/ultralytics/yolov5/blob/master/models/export.py)) on MacOS, Windows, and Ubuntu every 24 hours and on every commit.\n" + "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 training ([train.py](https://github.com/ultralytics/yolov3/blob/master/train.py)), testing ([val.py](https://github.com/ultralytics/yolov3/blob/master/val.py)), inference ([detect.py](https://github.com/ultralytics/yolov3/blob/master/detect.py)) and export ([export.py](https://github.com/ultralytics/yolov3/blob/master/export.py)) on MacOS, Windows, and Ubuntu every 24 hours and on every commit.\n" ] }, { @@ -1146,20 +973,6 @@ "Optional extras below. Unit tests validate repo functionality and should be run on any PRs submitted.\n" ] }, - { - "cell_type": "code", - "metadata": { - "id": "gI6NoBev8Ib1" - }, - "source": [ - "# Re-clone repo\n", - "%cd ..\n", - "%rm -rf yolov3 && git clone https://github.com/ultralytics/yolov3\n", - "%cd yolov3" - ], - "execution_count": null, - "outputs": [] - }, { "cell_type": "code", "metadata": { @@ -1168,8 +981,8 @@ "source": [ "# Reproduce\n", "for x in 'yolov3', 'yolov3-spp', 'yolov3-tiny':\n", - " !python test.py --weights {x}.pt --data coco.yaml --img 640 --conf 0.25 --iou 0.45 # speed\n", - " !python test.py --weights {x}.pt --data coco.yaml --img 640 --conf 0.001 --iou 0.65 # mAP" + " !python val.py --weights {x}.pt --data coco.yaml --img 640 --task speed # speed\n", + " !python val.py --weights {x}.pt --data coco.yaml --img 640 --conf 0.001 --iou 0.65 # mAP" ], "execution_count": null, "outputs": [] @@ -1184,7 +997,7 @@ "import torch\n", "\n", "# Model\n", - "model = torch.hub.load('ultralytics/yolov3', 'yolov3') # or 'yolov3_spp', 'yolov3_tiny'\n", + "model = torch.hub.load('ultralytics/yolov3', 'yolov3')\n", "\n", "# Images\n", "dir = 'https://ultralytics.com/images/'\n", @@ -1203,23 +1016,23 @@ "id": "FGH0ZjkGjejy" }, "source": [ - "# Unit tests\n", + "# CI Checks\n", "%%shell\n", "export PYTHONPATH=\"$PWD\" # to run *.py. files in subdirectories\n", - "\n", "rm -rf runs # remove runs/\n", - "for m in yolov3; do # models\n", - " python train.py --weights $m.pt --epochs 3 --img 320 --device 0 # train pretrained\n", - " python train.py --weights '' --cfg $m.yaml --epochs 3 --img 320 --device 0 # train scratch\n", + "for m in yolov3-tiny; do # models\n", + " python train.py --img 64 --batch 32 --weights $m.pt --epochs 1 --device 0 # train pretrained\n", + " python train.py --img 64 --batch 32 --weights '' --cfg $m.yaml --epochs 1 --device 0 # train scratch\n", " for d in 0 cpu; do # devices\n", + " python val.py --weights $m.pt --device $d # val official\n", + " python val.py --weights runs/train/exp/weights/best.pt --device $d # val custom\n", " python detect.py --weights $m.pt --device $d # detect official\n", " python detect.py --weights runs/train/exp/weights/best.pt --device $d # detect custom\n", - " python test.py --weights $m.pt --device $d # test official\n", - " python test.py --weights runs/train/exp/weights/best.pt --device $d # test custom\n", " done\n", " python hubconf.py # hub\n", - " python models/yolo.py --cfg $m.yaml # inspect\n", - " python models/export.py --weights $m.pt --img 640 --batch 1 # export\n", + " python models/yolo.py --cfg $m.yaml # build PyTorch model\n", + " python models/tf.py --weights $m.pt # build TensorFlow model\n", + " python export.py --img 64 --batch 1 --weights $m.pt --include torchscript onnx # export\n", "done" ], "execution_count": null, @@ -1232,11 +1045,11 @@ }, "source": [ "# Profile\n", - "from utils.torch_utils import profile \n", + "from utils.torch_utils import profile\n", "\n", "m1 = lambda x: x * torch.sigmoid(x)\n", "m2 = torch.nn.SiLU()\n", - "profile(x=torch.randn(16, 3, 640, 640), ops=[m1, m2], n=100)" + "results = profile(input=torch.randn(16, 3, 640, 640), ops=[m1, m2], n=100)" ], "execution_count": null, "outputs": [] @@ -1261,8 +1074,8 @@ }, "source": [ "# VOC\n", - "for b, m in zip([64, 48, 32, 16], ['yolov3', 'yolov3-spp', 'yolov3-tiny']): # zip(batch_size, model)\n", - " !python train.py --batch {b} --weights {m}.pt --data voc.yaml --epochs 50 --cache --img 512 --nosave --hyp hyp.finetune.yaml --project VOC --name {m}" + "for b, m in zip([24, 24, 64], ['yolov3', 'yolov3-spp', 'yolov3-tiny']): # zip(batch_size, model)\n", + " !python train.py --batch {b} --weights {m}.pt --data VOC.yaml --epochs 50 --cache --img 512 --nosave --hyp hyp.finetune.yaml --project VOC --name {m}" ], "execution_count": null, "outputs": [] diff --git a/utils/__init__.py b/utils/__init__.py index e69de29bb2..309830c830 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -0,0 +1,18 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +utils/initialization +""" + + +def notebook_init(): + # For notebooks + print('Checking setup...') + from IPython import display # to display images and clear console output + + from utils.general import emojis + from utils.torch_utils import select_device # imports + + display.clear_output() + select_device(newline=False) + print(emojis('Setup complete ✅')) + return display diff --git a/utils/activations.py b/utils/activations.py index 92a3b5eaa5..ae2fef1c8c 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -1,4 +1,7 @@ -# Activation functions +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Activation functions +""" import torch import torch.nn as nn @@ -16,7 +19,7 @@ class Hardswish(nn.Module): # export-friendly version of nn.Hardswish() @staticmethod def forward(x): # return x * F.hardsigmoid(x) # for torchscript and CoreML - return x * F.hardtanh(x + 3, 0., 6.) / 6. # for torchscript, CoreML and ONNX + return x * F.hardtanh(x + 3, 0.0, 6.0) / 6.0 # for torchscript, CoreML and ONNX # Mish https://github.com/digantamisra98/Mish -------------------------------------------------------------------------- diff --git a/utils/augmentations.py b/utils/augmentations.py new file mode 100644 index 0000000000..16685044ea --- /dev/null +++ b/utils/augmentations.py @@ -0,0 +1,277 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Image augmentation functions +""" + +import math +import random + +import cv2 +import numpy as np + +from utils.general import LOGGER, check_version, colorstr, resample_segments, segment2box +from utils.metrics import bbox_ioa + + +class Albumentations: + # Albumentations class (optional, only used if package is installed) + def __init__(self): + self.transform = None + try: + import albumentations as A + check_version(A.__version__, '1.0.3', hard=True) # version requirement + + self.transform = A.Compose([ + A.Blur(p=0.01), + A.MedianBlur(p=0.01), + A.ToGray(p=0.01), + A.CLAHE(p=0.01), + A.RandomBrightnessContrast(p=0.0), + A.RandomGamma(p=0.0), + A.ImageCompression(quality_lower=75, p=0.0)], + bbox_params=A.BboxParams(format='yolo', label_fields=['class_labels'])) + + LOGGER.info(colorstr('albumentations: ') + ', '.join(f'{x}' for x in self.transform.transforms if x.p)) + except ImportError: # package not installed, skip + pass + except Exception as e: + LOGGER.info(colorstr('albumentations: ') + f'{e}') + + def __call__(self, im, labels, p=1.0): + if self.transform and random.random() < p: + new = self.transform(image=im, bboxes=labels[:, 1:], class_labels=labels[:, 0]) # transformed + im, labels = new['image'], np.array([[c, *b] for c, b in zip(new['class_labels'], new['bboxes'])]) + return im, labels + + +def augment_hsv(im, hgain=0.5, sgain=0.5, vgain=0.5): + # HSV color-space augmentation + if hgain or sgain or vgain: + r = np.random.uniform(-1, 1, 3) * [hgain, sgain, vgain] + 1 # random gains + hue, sat, val = cv2.split(cv2.cvtColor(im, cv2.COLOR_BGR2HSV)) + dtype = im.dtype # uint8 + + x = np.arange(0, 256, dtype=r.dtype) + lut_hue = ((x * r[0]) % 180).astype(dtype) + lut_sat = np.clip(x * r[1], 0, 255).astype(dtype) + lut_val = np.clip(x * r[2], 0, 255).astype(dtype) + + im_hsv = cv2.merge((cv2.LUT(hue, lut_hue), cv2.LUT(sat, lut_sat), cv2.LUT(val, lut_val))) + cv2.cvtColor(im_hsv, cv2.COLOR_HSV2BGR, dst=im) # no return needed + + +def hist_equalize(im, clahe=True, bgr=False): + # Equalize histogram on BGR image 'im' with im.shape(n,m,3) and range 0-255 + yuv = cv2.cvtColor(im, cv2.COLOR_BGR2YUV if bgr else cv2.COLOR_RGB2YUV) + if clahe: + c = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) + yuv[:, :, 0] = c.apply(yuv[:, :, 0]) + else: + yuv[:, :, 0] = cv2.equalizeHist(yuv[:, :, 0]) # equalize Y channel histogram + return cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR if bgr else cv2.COLOR_YUV2RGB) # convert YUV image to RGB + + +def replicate(im, labels): + # Replicate labels + h, w = im.shape[:2] + boxes = labels[:, 1:].astype(int) + x1, y1, x2, y2 = boxes.T + s = ((x2 - x1) + (y2 - y1)) / 2 # side length (pixels) + for i in s.argsort()[:round(s.size * 0.5)]: # smallest indices + x1b, y1b, x2b, y2b = boxes[i] + bh, bw = y2b - y1b, x2b - x1b + yc, xc = int(random.uniform(0, h - bh)), int(random.uniform(0, w - bw)) # offset x, y + x1a, y1a, x2a, y2a = [xc, yc, xc + bw, yc + bh] + im[y1a:y2a, x1a:x2a] = im[y1b:y2b, x1b:x2b] # im4[ymin:ymax, xmin:xmax] + labels = np.append(labels, [[labels[i, 0], x1a, y1a, x2a, y2a]], axis=0) + + return im, labels + + +def letterbox(im, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32): + # Resize and pad image while meeting stride-multiple constraints + shape = im.shape[:2] # current shape [height, width] + if isinstance(new_shape, int): + new_shape = (new_shape, new_shape) + + # Scale ratio (new / old) + r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) + if not scaleup: # only scale down, do not scale up (for better val mAP) + r = min(r, 1.0) + + # Compute padding + ratio = r, r # width, height ratios + new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) + dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding + if auto: # minimum rectangle + dw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh padding + elif scaleFill: # stretch + dw, dh = 0.0, 0.0 + new_unpad = (new_shape[1], new_shape[0]) + ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios + + dw /= 2 # divide padding into 2 sides + dh /= 2 + + if shape[::-1] != new_unpad: # resize + im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR) + top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) + left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) + im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border + return im, ratio, (dw, dh) + + +def random_perspective(im, targets=(), segments=(), degrees=10, translate=.1, scale=.1, shear=10, perspective=0.0, + border=(0, 0)): + # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(0.1, 0.1), scale=(0.9, 1.1), shear=(-10, 10)) + # targets = [cls, xyxy] + + height = im.shape[0] + border[0] * 2 # shape(h,w,c) + width = im.shape[1] + border[1] * 2 + + # Center + C = np.eye(3) + C[0, 2] = -im.shape[1] / 2 # x translation (pixels) + C[1, 2] = -im.shape[0] / 2 # y translation (pixels) + + # Perspective + P = np.eye(3) + P[2, 0] = random.uniform(-perspective, perspective) # x perspective (about y) + P[2, 1] = random.uniform(-perspective, perspective) # y perspective (about x) + + # Rotation and Scale + R = np.eye(3) + a = random.uniform(-degrees, degrees) + # a += random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotations + s = random.uniform(1 - scale, 1 + scale) + # s = 2 ** random.uniform(-scale, scale) + R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s) + + # Shear + S = np.eye(3) + S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # x shear (deg) + S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # y shear (deg) + + # Translation + T = np.eye(3) + T[0, 2] = random.uniform(0.5 - translate, 0.5 + translate) * width # x translation (pixels) + T[1, 2] = random.uniform(0.5 - translate, 0.5 + translate) * height # y translation (pixels) + + # Combined rotation matrix + M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT + if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): # image changed + if perspective: + im = cv2.warpPerspective(im, M, dsize=(width, height), borderValue=(114, 114, 114)) + else: # affine + im = cv2.warpAffine(im, M[:2], dsize=(width, height), borderValue=(114, 114, 114)) + + # Visualize + # import matplotlib.pyplot as plt + # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel() + # ax[0].imshow(im[:, :, ::-1]) # base + # ax[1].imshow(im2[:, :, ::-1]) # warped + + # Transform label coordinates + n = len(targets) + if n: + use_segments = any(x.any() for x in segments) + new = np.zeros((n, 4)) + if use_segments: # warp segments + segments = resample_segments(segments) # upsample + for i, segment in enumerate(segments): + xy = np.ones((len(segment), 3)) + xy[:, :2] = segment + xy = xy @ M.T # transform + xy = xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2] # perspective rescale or affine + + # clip + new[i] = segment2box(xy, width, height) + + else: # warp boxes + xy = np.ones((n * 4, 3)) + xy[:, :2] = targets[:, [1, 2, 3, 4, 1, 4, 3, 2]].reshape(n * 4, 2) # x1y1, x2y2, x1y2, x2y1 + xy = xy @ M.T # transform + xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]).reshape(n, 8) # perspective rescale or affine + + # create new boxes + x = xy[:, [0, 2, 4, 6]] + y = xy[:, [1, 3, 5, 7]] + new = np.concatenate((x.min(1), y.min(1), x.max(1), y.max(1))).reshape(4, n).T + + # clip + new[:, [0, 2]] = new[:, [0, 2]].clip(0, width) + new[:, [1, 3]] = new[:, [1, 3]].clip(0, height) + + # filter candidates + i = box_candidates(box1=targets[:, 1:5].T * s, box2=new.T, area_thr=0.01 if use_segments else 0.10) + targets = targets[i] + targets[:, 1:5] = new[i] + + return im, targets + + +def copy_paste(im, labels, segments, p=0.5): + # Implement Copy-Paste augmentation https://arxiv.org/abs/2012.07177, labels as nx5 np.array(cls, xyxy) + n = len(segments) + if p and n: + h, w, c = im.shape # height, width, channels + im_new = np.zeros(im.shape, np.uint8) + for j in random.sample(range(n), k=round(p * n)): + l, s = labels[j], segments[j] + box = w - l[3], l[2], w - l[1], l[4] + ioa = bbox_ioa(box, labels[:, 1:5]) # intersection over area + if (ioa < 0.30).all(): # allow 30% obscuration of existing labels + labels = np.concatenate((labels, [[l[0], *box]]), 0) + segments.append(np.concatenate((w - s[:, 0:1], s[:, 1:2]), 1)) + cv2.drawContours(im_new, [segments[j].astype(np.int32)], -1, (255, 255, 255), cv2.FILLED) + + result = cv2.bitwise_and(src1=im, src2=im_new) + result = cv2.flip(result, 1) # augment segments (flip left-right) + i = result > 0 # pixels to replace + # i[:, :] = result.max(2).reshape(h, w, 1) # act over ch + im[i] = result[i] # cv2.imwrite('debug.jpg', im) # debug + + return im, labels, segments + + +def cutout(im, labels, p=0.5): + # Applies image cutout augmentation https://arxiv.org/abs/1708.04552 + if random.random() < p: + h, w = im.shape[:2] + scales = [0.5] * 1 + [0.25] * 2 + [0.125] * 4 + [0.0625] * 8 + [0.03125] * 16 # image size fraction + for s in scales: + mask_h = random.randint(1, int(h * s)) # create random masks + mask_w = random.randint(1, int(w * s)) + + # box + xmin = max(0, random.randint(0, w) - mask_w // 2) + ymin = max(0, random.randint(0, h) - mask_h // 2) + xmax = min(w, xmin + mask_w) + ymax = min(h, ymin + mask_h) + + # apply random color mask + im[ymin:ymax, xmin:xmax] = [random.randint(64, 191) for _ in range(3)] + + # return unobscured labels + if len(labels) and s > 0.03: + box = np.array([xmin, ymin, xmax, ymax], dtype=np.float32) + ioa = bbox_ioa(box, labels[:, 1:5]) # intersection over area + labels = labels[ioa < 0.60] # remove >60% obscured labels + + return labels + + +def mixup(im, labels, im2, labels2): + # Applies MixUp augmentation https://arxiv.org/pdf/1710.09412.pdf + r = np.random.beta(32.0, 32.0) # mixup ratio, alpha=beta=32.0 + im = (im * r + im2 * (1 - r)).astype(np.uint8) + labels = np.concatenate((labels, labels2), 0) + return im, labels + + +def box_candidates(box1, box2, wh_thr=2, ar_thr=20, area_thr=0.1, eps=1e-16): # box1(4,n), box2(4,n) + # Compute candidate boxes: box1 before augment, box2 after augment, wh_thr (pixels), aspect_ratio_thr, area_ratio + w1, h1 = box1[2] - box1[0], box1[3] - box1[1] + w2, h2 = box2[2] - box2[0], box2[3] - box2[1] + ar = np.maximum(w2 / (h2 + eps), h2 / (w2 + eps)) # aspect ratio + return (w2 > wh_thr) & (h2 > wh_thr) & (w2 * h2 / (w1 * h1 + eps) > area_thr) & (ar < ar_thr) # candidates diff --git a/utils/autoanchor.py b/utils/autoanchor.py index 51ed803455..0c202c4965 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -1,28 +1,32 @@ -# Auto-anchor utils +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Auto-anchor utils +""" + +import random import numpy as np import torch import yaml from tqdm import tqdm -from utils.general import colorstr +from utils.general import LOGGER, colorstr, emojis + +PREFIX = colorstr('AutoAnchor: ') def check_anchor_order(m): - # Check anchor order against stride order for YOLOv3 Detect() module m, and correct if necessary - a = m.anchor_grid.prod(-1).view(-1) # anchor area + # Check anchor order against stride order for Detect() module m, and correct if necessary + a = m.anchors.prod(-1).view(-1) # anchor area da = a[-1] - a[0] # delta a ds = m.stride[-1] - m.stride[0] # delta s if da.sign() != ds.sign(): # same order - print('Reversing anchor order') + LOGGER.info(f'{PREFIX}Reversing anchor order') m.anchors[:] = m.anchors.flip(0) - m.anchor_grid[:] = m.anchor_grid.flip(0) def check_anchors(dataset, model, thr=4.0, imgsz=640): # Check anchor fit to data, recompute if necessary - prefix = colorstr('autoanchor: ') - print(f'\n{prefix}Analyzing anchors... ', end='') m = model.module.model[-1] if hasattr(model, 'module') else model.model[-1] # Detect() shapes = imgsz * dataset.shapes / dataset.shapes.max(1, keepdims=True) scale = np.random.uniform(0.9, 1.1, size=(shapes.shape[0], 1)) # augment scale @@ -30,39 +34,39 @@ def check_anchors(dataset, model, thr=4.0, imgsz=640): def metric(k): # compute metric r = wh[:, None] / k[None] - x = torch.min(r, 1. / r).min(2)[0] # ratio metric + x = torch.min(r, 1 / r).min(2)[0] # ratio metric best = x.max(1)[0] # best_x - aat = (x > 1. / thr).float().sum(1).mean() # anchors above threshold - bpr = (best > 1. / thr).float().mean() # best possible recall + aat = (x > 1 / thr).float().sum(1).mean() # anchors above threshold + bpr = (best > 1 / thr).float().mean() # best possible recall return bpr, aat - anchors = m.anchor_grid.clone().cpu().view(-1, 2) # current anchors - bpr, aat = metric(anchors) - print(f'anchors/target = {aat:.2f}, Best Possible Recall (BPR) = {bpr:.4f}', end='') - if bpr < 0.98: # threshold to recompute - print('. Attempting to improve anchors, please wait...') - na = m.anchor_grid.numel() // 2 # number of anchors + anchors = m.anchors.clone() * m.stride.to(m.anchors.device).view(-1, 1, 1) # current anchors + bpr, aat = metric(anchors.cpu().view(-1, 2)) + s = f'\n{PREFIX}{aat:.2f} anchors/target, {bpr:.3f} Best Possible Recall (BPR). ' + if bpr > 0.98: # threshold to recompute + LOGGER.info(emojis(f'{s}Current anchors are a good fit to dataset ✅')) + else: + LOGGER.info(emojis(f'{s}Anchors are a poor fit to dataset ⚠️, attempting to improve...')) + na = m.anchors.numel() // 2 # number of anchors try: anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False) except Exception as e: - print(f'{prefix}ERROR: {e}') + LOGGER.info(f'{PREFIX}ERROR: {e}') new_bpr = metric(anchors)[0] if new_bpr > bpr: # replace anchors anchors = torch.tensor(anchors, device=m.anchors.device).type_as(m.anchors) - m.anchor_grid[:] = anchors.clone().view_as(m.anchor_grid) # for inference m.anchors[:] = anchors.clone().view_as(m.anchors) / m.stride.to(m.anchors.device).view(-1, 1, 1) # loss check_anchor_order(m) - print(f'{prefix}New anchors saved to model. Update model *.yaml to use these anchors in the future.') + LOGGER.info(f'{PREFIX}New anchors saved to model. Update model *.yaml to use these anchors in the future.') else: - print(f'{prefix}Original anchors better than new anchors. Proceeding with original anchors.') - print('') # newline + LOGGER.info(f'{PREFIX}Original anchors better than new anchors. Proceeding with original anchors.') -def kmean_anchors(path='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=1000, verbose=True): +def kmean_anchors(dataset='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=1000, verbose=True): """ Creates kmeans-evolved anchors from training dataset Arguments: - path: path to dataset *.yaml, or a loaded dataset + dataset: path to data.yaml, or a loaded dataset n: number of anchors img_size: image size used for training thr: anchor-label wh ratio threshold hyperparameter hyp['anchor_t'] used for training, default=4.0 @@ -77,12 +81,11 @@ def kmean_anchors(path='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=10 """ from scipy.cluster.vq import kmeans - thr = 1. / thr - prefix = colorstr('autoanchor: ') + thr = 1 / thr def metric(k, wh): # compute metrics r = wh[:, None] / k[None] - x = torch.min(r, 1. / r).min(2)[0] # ratio metric + x = torch.min(r, 1 / r).min(2)[0] # ratio metric # x = wh_iou(wh, torch.tensor(k)) # iou metric return x, x.max(1)[0] # x, best_x @@ -90,24 +93,24 @@ def anchor_fitness(k): # mutation fitness _, best = metric(torch.tensor(k, dtype=torch.float32), wh) return (best * (best > thr).float()).mean() # fitness - def print_results(k): + def print_results(k, verbose=True): k = k[np.argsort(k.prod(1))] # sort small to large x, best = metric(k, wh0) bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr - print(f'{prefix}thr={thr:.2f}: {bpr:.4f} best possible recall, {aat:.2f} anchors past thr') - print(f'{prefix}n={n}, img_size={img_size}, metric_all={x.mean():.3f}/{best.mean():.3f}-mean/best, ' - f'past_thr={x[x > thr].mean():.3f}-mean: ', end='') + s = f'{PREFIX}thr={thr:.2f}: {bpr:.4f} best possible recall, {aat:.2f} anchors past thr\n' \ + f'{PREFIX}n={n}, img_size={img_size}, metric_all={x.mean():.3f}/{best.mean():.3f}-mean/best, ' \ + f'past_thr={x[x > thr].mean():.3f}-mean: ' for i, x in enumerate(k): - print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg + s += '%i,%i, ' % (round(x[0]), round(x[1])) + if verbose: + LOGGER.info(s[:-2]) return k - if isinstance(path, str): # *.yaml file - with open(path) as f: + if isinstance(dataset, str): # *.yaml file + with open(dataset, errors='ignore') as f: data_dict = yaml.safe_load(f) # model dict from utils.datasets import LoadImagesAndLabels dataset = LoadImagesAndLabels(data_dict['train'], augment=True, rect=True) - else: - dataset = path # dataset # Get label wh shapes = img_size * dataset.shapes / dataset.shapes.max(1, keepdims=True) @@ -116,19 +119,19 @@ def print_results(k): # Filter i = (wh0 < 3.0).any(1).sum() if i: - print(f'{prefix}WARNING: Extremely small objects found. {i} of {len(wh0)} labels are < 3 pixels in size.') + LOGGER.info(f'{PREFIX}WARNING: Extremely small objects found. {i} of {len(wh0)} labels are < 3 pixels in size.') wh = wh0[(wh0 >= 2.0).any(1)] # filter > 2 pixels # wh = wh * (np.random.rand(wh.shape[0], 1) * 0.9 + 0.1) # multiply by random scale 0-1 # Kmeans calculation - print(f'{prefix}Running kmeans for {n} anchors on {len(wh)} points...') + LOGGER.info(f'{PREFIX}Running kmeans for {n} anchors on {len(wh)} points...') s = wh.std(0) # sigmas for whitening k, dist = kmeans(wh / s, n, iter=30) # points, mean distance - assert len(k) == n, print(f'{prefix}ERROR: scipy.cluster.vq.kmeans requested {n} points but returned only {len(k)}') + assert len(k) == n, f'{PREFIX}ERROR: scipy.cluster.vq.kmeans requested {n} points but returned only {len(k)}' k *= s wh = torch.tensor(wh, dtype=torch.float32) # filtered wh0 = torch.tensor(wh0, dtype=torch.float32) # unfiltered - k = print_results(k) + k = print_results(k, verbose=False) # Plot # k, d = [None] * 20, [None] * 20 @@ -145,17 +148,17 @@ def print_results(k): # Evolve npr = np.random f, sh, mp, s = anchor_fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma - pbar = tqdm(range(gen), desc=f'{prefix}Evolving anchors with Genetic Algorithm:') # progress bar + pbar = tqdm(range(gen), desc=f'{PREFIX}Evolving anchors with Genetic Algorithm:') # progress bar for _ in pbar: v = np.ones(sh) while (v == 1).all(): # mutate until a change occurs (prevent duplicates) - v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) + v = ((npr.random(sh) < mp) * random.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) kg = (k.copy() * v).clip(min=2.0) fg = anchor_fitness(kg) if fg > f: f, k = fg, kg.copy() - pbar.desc = f'{prefix}Evolving anchors with Genetic Algorithm: fitness = {f:.4f}' + pbar.desc = f'{PREFIX}Evolving anchors with Genetic Algorithm: fitness = {f:.4f}' if verbose: - print_results(k) + print_results(k, verbose) return print_results(k) diff --git a/utils/autobatch.py b/utils/autobatch.py new file mode 100644 index 0000000000..4fbf32bc9a --- /dev/null +++ b/utils/autobatch.py @@ -0,0 +1,57 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Auto-batch utils +""" + +from copy import deepcopy + +import numpy as np +import torch +from torch.cuda import amp + +from utils.general import LOGGER, colorstr +from utils.torch_utils import profile + + +def check_train_batch_size(model, imgsz=640): + # Check training batch size + with amp.autocast(): + return autobatch(deepcopy(model).train(), imgsz) # compute optimal batch size + + +def autobatch(model, imgsz=640, fraction=0.9, batch_size=16): + # Automatically estimate best batch size to use `fraction` of available CUDA memory + # Usage: + # import torch + # from utils.autobatch import autobatch + # model = torch.hub.load('ultralytics/yolov3', 'yolov3', autoshape=False) + # print(autobatch(model)) + + prefix = colorstr('AutoBatch: ') + LOGGER.info(f'{prefix}Computing optimal batch size for --imgsz {imgsz}') + device = next(model.parameters()).device # get model device + if device.type == 'cpu': + LOGGER.info(f'{prefix}CUDA not detected, using default CPU batch-size {batch_size}') + return batch_size + + d = str(device).upper() # 'CUDA:0' + properties = torch.cuda.get_device_properties(device) # device properties + t = properties.total_memory / 1024 ** 3 # (GiB) + r = torch.cuda.memory_reserved(device) / 1024 ** 3 # (GiB) + a = torch.cuda.memory_allocated(device) / 1024 ** 3 # (GiB) + f = t - (r + a) # free inside reserved + LOGGER.info(f'{prefix}{d} ({properties.name}) {t:.2f}G total, {r:.2f}G reserved, {a:.2f}G allocated, {f:.2f}G free') + + batch_sizes = [1, 2, 4, 8, 16] + try: + img = [torch.zeros(b, 3, imgsz, imgsz) for b in batch_sizes] + y = profile(img, model, n=3, device=device) + except Exception as e: + LOGGER.warning(f'{prefix}{e}') + + y = [x[2] for x in y if x] # memory [2] + batch_sizes = batch_sizes[:len(y)] + p = np.polyfit(batch_sizes, y, deg=1) # first degree polynomial fit + b = int((f * fraction - p[1]) / p[0]) # y intercept (optimal batch size) + LOGGER.info(f'{prefix}Using batch-size {b} for {d} {t * fraction:.2f}G/{t:.2f}G ({fraction * 100:.0f}%)') + return b diff --git a/utils/aws/mime.sh b/utils/aws/mime.sh deleted file mode 100644 index c319a83cfb..0000000000 --- a/utils/aws/mime.sh +++ /dev/null @@ -1,26 +0,0 @@ -# AWS EC2 instance startup 'MIME' script https://aws.amazon.com/premiumsupport/knowledge-center/execute-user-data-ec2/ -# This script will run on every instance restart, not only on first start -# --- DO NOT COPY ABOVE COMMENTS WHEN PASTING INTO USERDATA --- - -Content-Type: multipart/mixed; boundary="//" -MIME-Version: 1.0 - ---// -Content-Type: text/cloud-config; charset="us-ascii" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Content-Disposition: attachment; filename="cloud-config.txt" - -#cloud-config -cloud_final_modules: -- [scripts-user, always] - ---// -Content-Type: text/x-shellscript; charset="us-ascii" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Content-Disposition: attachment; filename="userdata.txt" - -#!/bin/bash -# --- paste contents of userdata.sh here --- ---// diff --git a/utils/aws/resume.py b/utils/aws/resume.py deleted file mode 100644 index 4b0d4246b5..0000000000 --- a/utils/aws/resume.py +++ /dev/null @@ -1,37 +0,0 @@ -# Resume all interrupted trainings in yolov5/ dir including DDP trainings -# Usage: $ python utils/aws/resume.py - -import os -import sys -from pathlib import Path - -import torch -import yaml - -sys.path.append('./') # to run '$ python *.py' files in subdirectories - -port = 0 # --master_port -path = Path('').resolve() -for last in path.rglob('*/**/last.pt'): - ckpt = torch.load(last) - if ckpt['optimizer'] is None: - continue - - # Load opt.yaml - with open(last.parent.parent / 'opt.yaml') as f: - opt = yaml.safe_load(f) - - # Get device count - d = opt['device'].split(',') # devices - nd = len(d) # number of devices - ddp = nd > 1 or (nd == 0 and torch.cuda.device_count() > 1) # distributed data parallel - - if ddp: # multi-GPU - port += 1 - cmd = f'python -m torch.distributed.launch --nproc_per_node {nd} --master_port {port} train.py --resume {last}' - else: # single-GPU - cmd = f'python train.py --resume {last}' - - cmd += ' > /dev/null 2>&1 &' # redirect output to dev/null and run in daemon thread - print(cmd) - os.system(cmd) diff --git a/utils/aws/userdata.sh b/utils/aws/userdata.sh deleted file mode 100644 index 5846fedb16..0000000000 --- a/utils/aws/userdata.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# AWS EC2 instance startup script https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html -# This script will run only once on first instance start (for a re-start script see mime.sh) -# /home/ubuntu (ubuntu) or /home/ec2-user (amazon-linux) is working dir -# Use >300 GB SSD - -cd home/ubuntu -if [ ! -d yolov5 ]; then - echo "Running first-time script." # install dependencies, download COCO, pull Docker - git clone https://github.com/ultralytics/yolov5 -b master && sudo chmod -R 777 yolov5 - cd yolov5 - bash data/scripts/get_coco.sh && echo "Data done." & - sudo docker pull ultralytics/yolov5:latest && echo "Docker done." & - python -m pip install --upgrade pip && pip install -r requirements.txt && python detect.py && echo "Requirements done." & - wait && echo "All tasks done." # finish background tasks -else - echo "Running re-start script." # resume interrupted runs - i=0 - list=$(sudo docker ps -qa) # container list i.e. $'one\ntwo\nthree\nfour' - while IFS= read -r id; do - ((i++)) - echo "restarting container $i: $id" - sudo docker start $id - # sudo docker exec -it $id python train.py --resume # single-GPU - sudo docker exec -d $id python utils/aws/resume.py # multi-scenario - done <<<"$list" -fi diff --git a/utils/callbacks.py b/utils/callbacks.py new file mode 100644 index 0000000000..43e81a7c51 --- /dev/null +++ b/utils/callbacks.py @@ -0,0 +1,76 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Callback utils +""" + + +class Callbacks: + """" + Handles all registered callbacks for Hooks + """ + + # Define the available callbacks + _callbacks = { + 'on_pretrain_routine_start': [], + 'on_pretrain_routine_end': [], + + 'on_train_start': [], + 'on_train_epoch_start': [], + 'on_train_batch_start': [], + 'optimizer_step': [], + 'on_before_zero_grad': [], + 'on_train_batch_end': [], + 'on_train_epoch_end': [], + + 'on_val_start': [], + 'on_val_batch_start': [], + 'on_val_image_end': [], + 'on_val_batch_end': [], + 'on_val_end': [], + + 'on_fit_epoch_end': [], # fit = train + val + 'on_model_save': [], + 'on_train_end': [], + + 'teardown': [], + } + + def register_action(self, hook, name='', callback=None): + """ + Register a new action to a callback hook + + Args: + hook The callback hook name to register the action to + name The name of the action for later reference + callback The callback to fire + """ + assert hook in self._callbacks, f"hook '{hook}' not found in callbacks {self._callbacks}" + assert callable(callback), f"callback '{callback}' is not callable" + self._callbacks[hook].append({'name': name, 'callback': callback}) + + def get_registered_actions(self, hook=None): + """" + Returns all the registered actions by callback hook + + Args: + hook The name of the hook to check, defaults to all + """ + if hook: + return self._callbacks[hook] + else: + return self._callbacks + + def run(self, hook, *args, **kwargs): + """ + Loop through the registered actions and fire all callbacks + + Args: + hook The name of the hook to check, defaults to all + args Arguments to receive from + kwargs Keyword Arguments to receive from + """ + + assert hook in self._callbacks, f"hook '{hook}' not found in callbacks {self._callbacks}" + + for logger in self._callbacks[hook]: + logger['callback'](*args, **kwargs) diff --git a/utils/datasets.py b/utils/datasets.py index 35aa430aaa..462d561a56 100755 --- a/utils/datasets.py +++ b/utils/datasets.py @@ -1,35 +1,41 @@ -# Dataset utils and dataloaders +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Dataloaders and dataset utils +""" import glob import hashlib -import logging -import math +import json import os import random import shutil import time from itertools import repeat -from multiprocessing.pool import ThreadPool +from multiprocessing.pool import Pool, ThreadPool from pathlib import Path from threading import Thread +from zipfile import ZipFile import cv2 import numpy as np import torch import torch.nn.functional as F -from PIL import Image, ExifTags -from torch.utils.data import Dataset +import yaml +from PIL import ExifTags, Image, ImageOps +from torch.utils.data import DataLoader, Dataset, dataloader, distributed from tqdm import tqdm -from utils.general import check_requirements, xyxy2xywh, xywh2xyxy, xywhn2xyxy, xyn2xy, segment2box, segments2boxes, \ - resample_segments, clean_str +from utils.augmentations import Albumentations, augment_hsv, copy_paste, letterbox, mixup, random_perspective +from utils.general import (LOGGER, check_dataset, check_requirements, check_yaml, clean_str, segments2boxes, xyn2xy, + xywh2xyxy, xywhn2xyxy, xyxy2xywhn) from utils.torch_utils import torch_distributed_zero_first # Parameters -help_url = 'https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' -img_formats = ['bmp', 'jpg', 'jpeg', 'png', 'tif', 'tiff', 'dng', 'webp', 'mpo'] # acceptable image suffixes -vid_formats = ['mov', 'avi', 'mp4', 'mpg', 'mpeg', 'm4v', 'wmv', 'mkv'] # acceptable video suffixes -logger = logging.getLogger(__name__) +HELP_URL = 'https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' +IMG_FORMATS = ['bmp', 'jpg', 'jpeg', 'png', 'tif', 'tiff', 'dng', 'webp', 'mpo'] # acceptable image suffixes +VID_FORMATS = ['mov', 'avi', 'mp4', 'mpg', 'mpeg', 'm4v', 'wmv', 'mkv'] # acceptable video suffixes +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) # DPP +NUM_THREADS = min(8, os.cpu_count()) # number of multiprocessing threads # Get orientation exif tag for orientation in ExifTags.TAGS.keys(): @@ -60,36 +66,63 @@ def exif_size(img): return s -def create_dataloader(path, imgsz, batch_size, stride, opt, hyp=None, augment=False, cache=False, pad=0.0, rect=False, - rank=-1, world_size=1, workers=8, image_weights=False, quad=False, prefix=''): - # Make sure only the first process in DDP process the dataset first, and the following others can use the cache - with torch_distributed_zero_first(rank): +def exif_transpose(image): + """ + Transpose a PIL image accordingly if it has an EXIF Orientation tag. + Inplace version of https://github.com/python-pillow/Pillow/blob/master/src/PIL/ImageOps.py exif_transpose() + + :param image: The image to transpose. + :return: An image. + """ + exif = image.getexif() + orientation = exif.get(0x0112, 1) # default 1 + if orientation > 1: + method = {2: Image.FLIP_LEFT_RIGHT, + 3: Image.ROTATE_180, + 4: Image.FLIP_TOP_BOTTOM, + 5: Image.TRANSPOSE, + 6: Image.ROTATE_270, + 7: Image.TRANSVERSE, + 8: Image.ROTATE_90, + }.get(orientation) + if method is not None: + image = image.transpose(method) + del exif[0x0112] + image.info["exif"] = exif.tobytes() + return image + + +def create_dataloader(path, imgsz, batch_size, stride, single_cls=False, hyp=None, augment=False, cache=False, pad=0.0, + rect=False, rank=-1, workers=8, image_weights=False, quad=False, prefix='', shuffle=False): + if rect and shuffle: + LOGGER.warning('WARNING: --rect is incompatible with DataLoader shuffle, setting shuffle=False') + shuffle = False + with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP dataset = LoadImagesAndLabels(path, imgsz, batch_size, - augment=augment, # augment images - hyp=hyp, # augmentation hyperparameters - rect=rect, # rectangular training + augment=augment, # augmentation + hyp=hyp, # hyperparameters + rect=rect, # rectangular batches cache_images=cache, - single_cls=opt.single_cls, + single_cls=single_cls, stride=int(stride), pad=pad, image_weights=image_weights, prefix=prefix) batch_size = min(batch_size, len(dataset)) - nw = min([os.cpu_count() // world_size, batch_size if batch_size > 1 else 0, workers]) # number of workers - sampler = torch.utils.data.distributed.DistributedSampler(dataset) if rank != -1 else None - loader = torch.utils.data.DataLoader if image_weights else InfiniteDataLoader - # Use torch.utils.data.DataLoader() if dataset.properties will update during training else InfiniteDataLoader() - dataloader = loader(dataset, - batch_size=batch_size, - num_workers=nw, - sampler=sampler, - pin_memory=True, - collate_fn=LoadImagesAndLabels.collate_fn4 if quad else LoadImagesAndLabels.collate_fn) - return dataloader, dataset - - -class InfiniteDataLoader(torch.utils.data.dataloader.DataLoader): + nw = min([os.cpu_count() // WORLD_SIZE, batch_size if batch_size > 1 else 0, workers]) # number of workers + sampler = None if rank == -1 else distributed.DistributedSampler(dataset, shuffle=shuffle) + loader = DataLoader if image_weights else InfiniteDataLoader # only DataLoader allows for attribute updates + return loader(dataset, + batch_size=batch_size, + shuffle=shuffle and sampler is None, + num_workers=nw, + sampler=sampler, + pin_memory=True, + collate_fn=LoadImagesAndLabels.collate_fn4 if quad else LoadImagesAndLabels.collate_fn), dataset + + +class InfiniteDataLoader(dataloader.DataLoader): """ Dataloader that reuses workers Uses same syntax as vanilla DataLoader @@ -108,7 +141,7 @@ def __iter__(self): yield next(self.iterator) -class _RepeatSampler(object): +class _RepeatSampler: """ Sampler that repeats forever Args: @@ -123,9 +156,10 @@ def __iter__(self): yield from iter(self.sampler) -class LoadImages: # for inference - def __init__(self, path, img_size=640, stride=32): - p = str(Path(path).absolute()) # os-agnostic absolute path +class LoadImages: + # image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4` + def __init__(self, path, img_size=640, stride=32, auto=True): + p = str(Path(path).resolve()) # os-agnostic absolute path if '*' in p: files = sorted(glob.glob(p, recursive=True)) # glob elif os.path.isdir(p): @@ -135,8 +169,8 @@ def __init__(self, path, img_size=640, stride=32): else: raise Exception(f'ERROR: {p} does not exist') - images = [x for x in files if x.split('.')[-1].lower() in img_formats] - videos = [x for x in files if x.split('.')[-1].lower() in vid_formats] + images = [x for x in files if x.split('.')[-1].lower() in IMG_FORMATS] + videos = [x for x in files if x.split('.')[-1].lower() in VID_FORMATS] ni, nv = len(images), len(videos) self.img_size = img_size @@ -145,12 +179,13 @@ def __init__(self, path, img_size=640, stride=32): self.nf = ni + nv # number of files self.video_flag = [False] * ni + [True] * nv self.mode = 'image' + self.auto = auto if any(videos): self.new_video(videos[0]) # new video else: self.cap = None assert self.nf > 0, f'No images or videos found in {p}. ' \ - f'Supported formats are:\nimages: {img_formats}\nvideos: {vid_formats}' + f'Supported formats are:\nimages: {IMG_FORMATS}\nvideos: {VID_FORMATS}' def __iter__(self): self.count = 0 @@ -176,23 +211,23 @@ def __next__(self): ret_val, img0 = self.cap.read() self.frame += 1 - print(f'video {self.count + 1}/{self.nf} ({self.frame}/{self.frames}) {path}: ', end='') + s = f'video {self.count + 1}/{self.nf} ({self.frame}/{self.frames}) {path}: ' else: # Read image self.count += 1 img0 = cv2.imread(path) # BGR - assert img0 is not None, 'Image Not Found ' + path - print(f'image {self.count}/{self.nf} {path}: ', end='') + assert img0 is not None, f'Image Not Found {path}' + s = f'image {self.count}/{self.nf} {path}: ' # Padded resize - img = letterbox(img0, self.img_size, stride=self.stride)[0] + img = letterbox(img0, self.img_size, stride=self.stride, auto=self.auto)[0] # Convert - img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 + img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB img = np.ascontiguousarray(img) - return path, img, img0, self.cap + return path, img, img0, self.cap, s def new_video(self, path): self.frame = 0 @@ -204,18 +239,12 @@ def __len__(self): class LoadWebcam: # for inference + # local webcam dataloader, i.e. `python detect.py --source 0` def __init__(self, pipe='0', img_size=640, stride=32): self.img_size = img_size self.stride = stride - - if pipe.isnumeric(): - pipe = eval(pipe) # local camera - # pipe = 'rtsp://192.168.1.64/1' # IP camera - # pipe = 'rtsp://username:password@192.168.1.64/1' # IP camera with login - # pipe = 'http://wmccpinetop.axiscam.net/mjpg/video.mjpg' # IP golf camera - - self.pipe = pipe - self.cap = cv2.VideoCapture(pipe) # video capture object + self.pipe = eval(pipe) if pipe.isnumeric() else pipe + self.cap = cv2.VideoCapture(self.pipe) # video capture object self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 3) # set buffer size def __iter__(self): @@ -230,45 +259,36 @@ def __next__(self): raise StopIteration # Read frame - if self.pipe == 0: # local camera - ret_val, img0 = self.cap.read() - img0 = cv2.flip(img0, 1) # flip left-right - else: # IP camera - n = 0 - while True: - n += 1 - self.cap.grab() - if n % 30 == 0: # skip frames - ret_val, img0 = self.cap.retrieve() - if ret_val: - break + ret_val, img0 = self.cap.read() + img0 = cv2.flip(img0, 1) # flip left-right # Print assert ret_val, f'Camera Error {self.pipe}' img_path = 'webcam.jpg' - print(f'webcam {self.count}: ', end='') + s = f'webcam {self.count}: ' # Padded resize img = letterbox(img0, self.img_size, stride=self.stride)[0] # Convert - img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 + img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB img = np.ascontiguousarray(img) - return img_path, img, img0, None + return img_path, img, img0, None, s def __len__(self): return 0 -class LoadStreams: # multiple IP or RTSP cameras - def __init__(self, sources='streams.txt', img_size=640, stride=32): +class LoadStreams: + # streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams` + def __init__(self, sources='streams.txt', img_size=640, stride=32, auto=True): self.mode = 'stream' self.img_size = img_size self.stride = stride if os.path.isfile(sources): - with open(sources, 'r') as f: + with open(sources) as f: sources = [x.strip() for x in f.read().strip().splitlines() if len(x.strip())] else: sources = [sources] @@ -276,43 +296,49 @@ def __init__(self, sources='streams.txt', img_size=640, stride=32): n = len(sources) self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n self.sources = [clean_str(x) for x in sources] # clean source names for later + self.auto = auto for i, s in enumerate(sources): # index, source # Start thread to read frames from video stream - print(f'{i + 1}/{n}: {s}... ', end='') + st = f'{i + 1}/{n}: {s}... ' if 'youtube.com/' in s or 'youtu.be/' in s: # if source is YouTube video check_requirements(('pafy', 'youtube_dl')) import pafy s = pafy.new(s).getbest(preftype="mp4").url # YouTube URL s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam cap = cv2.VideoCapture(s) - assert cap.isOpened(), f'Failed to open {s}' + assert cap.isOpened(), f'{st}Failed to open {s}' w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) self.fps[i] = max(cap.get(cv2.CAP_PROP_FPS) % 100, 0) or 30.0 # 30 FPS fallback self.frames[i] = max(int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback _, self.imgs[i] = cap.read() # guarantee first frame - self.threads[i] = Thread(target=self.update, args=([i, cap]), daemon=True) - print(f" success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)") + self.threads[i] = Thread(target=self.update, args=([i, cap, s]), daemon=True) + LOGGER.info(f"{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)") self.threads[i].start() - print('') # newline + LOGGER.info('') # newline # check for common shapes - s = np.stack([letterbox(x, self.img_size, stride=self.stride)[0].shape for x in self.imgs], 0) # shapes + s = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0].shape for x in self.imgs]) self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal if not self.rect: - print('WARNING: Different stream shapes detected. For optimal performance supply similarly-shaped streams.') + LOGGER.warning('WARNING: Stream shapes differ. For optimal performance supply similarly-shaped streams.') - def update(self, i, cap): + def update(self, i, cap, stream): # Read stream `i` frames in daemon thread - n, f = 0, self.frames[i] + n, f, read = 0, self.frames[i], 1 # frame number, frame array, inference every 'read' frame while cap.isOpened() and n < f: n += 1 # _, self.imgs[index] = cap.read() cap.grab() - if n % 4: # read every 4th frame + if n % read == 0: success, im = cap.retrieve() - self.imgs[i] = im if success else self.imgs[i] * 0 + if success: + self.imgs[i] = im + else: + LOGGER.warning('WARNING: Video stream unresponsive, please check your IP camera connection.') + self.imgs[i] *= 0 + cap.open(stream) # re-open stream if signal was lost time.sleep(1 / self.fps[i]) # wait time def __iter__(self): @@ -327,28 +353,31 @@ def __next__(self): # Letterbox img0 = self.imgs.copy() - img = [letterbox(x, self.img_size, auto=self.rect, stride=self.stride)[0] for x in img0] + img = [letterbox(x, self.img_size, stride=self.stride, auto=self.rect and self.auto)[0] for x in img0] # Stack img = np.stack(img, 0) # Convert - img = img[:, :, :, ::-1].transpose(0, 3, 1, 2) # BGR to RGB, to bsx3x416x416 + img = img[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW img = np.ascontiguousarray(img) - return self.sources, img, img0, None + return self.sources, img, img0, None, '' def __len__(self): - return 0 # 1E12 frames = 32 streams at 30 FPS for 30 years + return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years def img2label_paths(img_paths): # Define label paths as a function of image paths sa, sb = os.sep + 'images' + os.sep, os.sep + 'labels' + os.sep # /images/, /labels/ substrings - return ['txt'.join(x.replace(sa, sb, 1).rsplit(x.split('.')[-1], 1)) for x in img_paths] + return [sb.join(x.rsplit(sa, 1)).rsplit('.', 1)[0] + '.txt' for x in img_paths] + +class LoadImagesAndLabels(Dataset): + # train_loader/val_loader, loads images and labels for training and validation + cache_version = 0.6 # dataset labels *.cache version -class LoadImagesAndLabels(Dataset): # for training/testing def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, cache_images=False, single_cls=False, stride=32, pad=0.0, prefix=''): self.img_size = img_size @@ -360,6 +389,7 @@ def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, r self.mosaic_border = [-img_size // 2, -img_size // 2] self.stride = stride self.path = path + self.albumentations = Albumentations() if augment else None try: f = [] # image files @@ -367,29 +397,29 @@ def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, r p = Path(p) # os-agnostic if p.is_dir(): # dir f += glob.glob(str(p / '**' / '*.*'), recursive=True) - # f = list(p.rglob('**/*.*')) # pathlib + # f = list(p.rglob('*.*')) # pathlib elif p.is_file(): # file - with open(p, 'r') as t: + with open(p) as t: t = t.read().strip().splitlines() parent = str(p.parent) + os.sep f += [x.replace('./', parent) if x.startswith('./') else x for x in t] # local to global path # f += [p.parent / x.lstrip(os.sep) for x in t] # local to global path (pathlib) else: raise Exception(f'{prefix}{p} does not exist') - self.img_files = sorted([x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in img_formats]) - # self.img_files = sorted([x for x in f if x.suffix[1:].lower() in img_formats]) # pathlib + self.img_files = sorted(x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in IMG_FORMATS) + # self.img_files = sorted([x for x in f if x.suffix[1:].lower() in IMG_FORMATS]) # pathlib assert self.img_files, f'{prefix}No images found' except Exception as e: - raise Exception(f'{prefix}Error loading data from {path}: {e}\nSee {help_url}') + raise Exception(f'{prefix}Error loading data from {path}: {e}\nSee {HELP_URL}') # Check cache self.label_files = img2label_paths(self.img_files) # labels - cache_path = (p if p.is_file() else Path(self.label_files[0]).parent).with_suffix('.cache') # cached labels - if cache_path.is_file(): - cache, exists = torch.load(cache_path), True # load - if cache['hash'] != get_hash(self.label_files + self.img_files): # changed - cache, exists = self.cache_labels(cache_path, prefix), False # re-cache - else: + cache_path = (p if p.is_file() else Path(self.label_files[0]).parent).with_suffix('.cache') + try: + cache, exists = np.load(cache_path, allow_pickle=True).item(), True # load dict + assert cache['version'] == self.cache_version # same version + assert cache['hash'] == get_hash(self.label_files + self.img_files) # same hash + except: cache, exists = self.cache_labels(cache_path, prefix), False # cache # Display cache @@ -397,20 +427,17 @@ def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, r if exists: d = f"Scanning '{cache_path}' images and labels... {nf} found, {nm} missing, {ne} empty, {nc} corrupted" tqdm(None, desc=prefix + d, total=n, initial=n) # display cache results - assert nf > 0 or not augment, f'{prefix}No labels in {cache_path}. Can not train without labels. See {help_url}' + if cache['msgs']: + LOGGER.info('\n'.join(cache['msgs'])) # display warnings + assert nf > 0 or not augment, f'{prefix}No labels in {cache_path}. Can not train without labels. See {HELP_URL}' # Read cache - cache.pop('hash') # remove hash - cache.pop('version') # remove version + [cache.pop(k) for k in ('hash', 'version', 'msgs')] # remove items labels, shapes, self.segments = zip(*cache.values()) self.labels = list(labels) self.shapes = np.array(shapes, dtype=np.float64) self.img_files = list(cache.keys()) # update self.label_files = img2label_paths(cache.keys()) # update - if single_cls: - for x in self.labels: - x[:, 0] = 0 - n = len(shapes) # number of images bi = np.floor(np.arange(n) / batch_size).astype(np.int) # batch index nb = bi[-1] + 1 # number of batches @@ -418,6 +445,20 @@ def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, r self.n = n self.indices = range(n) + # Update labels + include_class = [] # filter labels to include only these classes (optional) + include_class_array = np.array(include_class).reshape(1, -1) + for i, (label, segment) in enumerate(zip(self.labels, self.segments)): + if include_class: + j = (label[:, 0:1] == include_class_array).any(1) + self.labels[i] = label[j] + if segment: + self.segments[i] = segment[j] + if single_cls: # single-class training, merge all classes into 0 + self.labels[i][:, 0] = 0 + if segment: + self.segments[i][:, 0] = 0 + # Rectangular Training if self.rect: # Sort by aspect ratio @@ -443,74 +484,61 @@ def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, r self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(np.int) * stride # Cache images into memory for faster training (WARNING: large datasets may exceed system RAM) - self.imgs = [None] * n + self.imgs, self.img_npy = [None] * n, [None] * n if cache_images: + if cache_images == 'disk': + self.im_cache_dir = Path(Path(self.img_files[0]).parent.as_posix() + '_npy') + self.img_npy = [self.im_cache_dir / Path(f).with_suffix('.npy').name for f in self.img_files] + self.im_cache_dir.mkdir(parents=True, exist_ok=True) gb = 0 # Gigabytes of cached images self.img_hw0, self.img_hw = [None] * n, [None] * n - results = ThreadPool(8).imap(lambda x: load_image(*x), zip(repeat(self), range(n))) # 8 threads + results = ThreadPool(NUM_THREADS).imap(lambda x: load_image(*x), zip(repeat(self), range(n))) pbar = tqdm(enumerate(results), total=n) for i, x in pbar: - self.imgs[i], self.img_hw0[i], self.img_hw[i] = x # img, hw_original, hw_resized = load_image(self, i) - gb += self.imgs[i].nbytes - pbar.desc = f'{prefix}Caching images ({gb / 1E9:.1f}GB)' + if cache_images == 'disk': + if not self.img_npy[i].exists(): + np.save(self.img_npy[i].as_posix(), x[0]) + gb += self.img_npy[i].stat().st_size + else: + self.imgs[i], self.img_hw0[i], self.img_hw[i] = x # im, hw_orig, hw_resized = load_image(self, i) + gb += self.imgs[i].nbytes + pbar.desc = f'{prefix}Caching images ({gb / 1E9:.1f}GB {cache_images})' pbar.close() def cache_labels(self, path=Path('./labels.cache'), prefix=''): # Cache dataset labels, check images and read shapes x = {} # dict - nm, nf, ne, nc = 0, 0, 0, 0 # number missing, found, empty, duplicate - pbar = tqdm(zip(self.img_files, self.label_files), desc='Scanning images', total=len(self.img_files)) - for i, (im_file, lb_file) in enumerate(pbar): - try: - # verify images - im = Image.open(im_file) - im.verify() # PIL verify - shape = exif_size(im) # image size - segments = [] # instance segments - assert (shape[0] > 9) & (shape[1] > 9), f'image size {shape} <10 pixels' - assert im.format.lower() in img_formats, f'invalid image format {im.format}' - - # verify labels - if os.path.isfile(lb_file): - nf += 1 # label found - with open(lb_file, 'r') as f: - l = [x.split() for x in f.read().strip().splitlines() if len(x)] - if any([len(x) > 8 for x in l]): # is segment - classes = np.array([x[0] for x in l], dtype=np.float32) - segments = [np.array(x[1:], dtype=np.float32).reshape(-1, 2) for x in l] # (cls, xy1...) - l = np.concatenate((classes.reshape(-1, 1), segments2boxes(segments)), 1) # (cls, xywh) - l = np.array(l, dtype=np.float32) - if len(l): - assert l.shape[1] == 5, 'labels require 5 columns each' - assert (l >= 0).all(), 'negative labels' - assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels' - assert np.unique(l, axis=0).shape[0] == l.shape[0], 'duplicate labels' - else: - ne += 1 # label empty - l = np.zeros((0, 5), dtype=np.float32) - else: - nm += 1 # label missing - l = np.zeros((0, 5), dtype=np.float32) - x[im_file] = [l, shape, segments] - except Exception as e: - nc += 1 - logging.info(f'{prefix}WARNING: Ignoring corrupted image and/or label {im_file}: {e}') - - pbar.desc = f"{prefix}Scanning '{path.parent / path.stem}' images and labels... " \ - f"{nf} found, {nm} missing, {ne} empty, {nc} corrupted" - pbar.close() + nm, nf, ne, nc, msgs = 0, 0, 0, 0, [] # number missing, found, empty, corrupt, messages + desc = f"{prefix}Scanning '{path.parent / path.stem}' images and labels..." + with Pool(NUM_THREADS) as pool: + pbar = tqdm(pool.imap(verify_image_label, zip(self.img_files, self.label_files, repeat(prefix))), + desc=desc, total=len(self.img_files)) + for im_file, l, shape, segments, nm_f, nf_f, ne_f, nc_f, msg in pbar: + nm += nm_f + nf += nf_f + ne += ne_f + nc += nc_f + if im_file: + x[im_file] = [l, shape, segments] + if msg: + msgs.append(msg) + pbar.desc = f"{desc}{nf} found, {nm} missing, {ne} empty, {nc} corrupted" + pbar.close() + if msgs: + LOGGER.info('\n'.join(msgs)) if nf == 0: - logging.info(f'{prefix}WARNING: No labels found in {path}. See {help_url}') - + LOGGER.warning(f'{prefix}WARNING: No labels found in {path}. See {HELP_URL}') x['hash'] = get_hash(self.label_files + self.img_files) - x['results'] = nf, nm, ne, nc, i + 1 - x['version'] = 0.2 # cache version + x['results'] = nf, nm, ne, nc, len(self.img_files) + x['msgs'] = msgs # warnings + x['version'] = self.cache_version # cache version try: - torch.save(x, path) # save cache for next time - logging.info(f'{prefix}New cache created: {path}') + np.save(path, x) # save cache for next time + path.with_suffix('.cache.npy').rename(path) # remove .npy suffix + LOGGER.info(f'{prefix}New cache created: {path}') except Exception as e: - logging.info(f'{prefix}WARNING: Cache directory {path.parent} is not writeable: {e}') # path not writeable + LOGGER.warning(f'{prefix}WARNING: Cache directory {path.parent} is not writeable: {e}') # not writeable return x def __len__(self): @@ -532,12 +560,9 @@ def __getitem__(self, index): img, labels = load_mosaic(self, index) shapes = None - # MixUp https://arxiv.org/pdf/1710.09412.pdf + # MixUp augmentation if random.random() < hyp['mixup']: - img2, labels2 = load_mosaic(self, random.randint(0, self.n - 1)) - r = np.random.beta(8.0, 8.0) # mixup ratio, alpha=beta=8.0 - img = (img * r + img2 * (1 - r)).astype(np.uint8) - labels = np.concatenate((labels, labels2), 0) + img, labels = mixup(img, labels, *load_mosaic(self, random.randint(0, self.n - 1))) else: # Load image @@ -552,9 +577,7 @@ def __getitem__(self, index): if labels.size: # normalized xywh to pixel xyxy format labels[:, 1:] = xywhn2xyxy(labels[:, 1:], ratio[0] * w, ratio[1] * h, padw=pad[0], padh=pad[1]) - if self.augment: - # Augment imagespace - if not mosaic: + if self.augment: img, labels = random_perspective(img, labels, degrees=hyp['degrees'], translate=hyp['translate'], @@ -562,38 +585,39 @@ def __getitem__(self, index): shear=hyp['shear'], perspective=hyp['perspective']) - # Augment colorspace - augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) + nl = len(labels) # number of labels + if nl: + labels[:, 1:5] = xyxy2xywhn(labels[:, 1:5], w=img.shape[1], h=img.shape[0], clip=True, eps=1E-3) - # Apply cutouts - # if random.random() < 0.9: - # labels = cutout(img, labels) + if self.augment: + # Albumentations + img, labels = self.albumentations(img, labels) + nl = len(labels) # update after albumentations - nL = len(labels) # number of labels - if nL: - labels[:, 1:5] = xyxy2xywh(labels[:, 1:5]) # convert xyxy to xywh - labels[:, [2, 4]] /= img.shape[0] # normalized height 0-1 - labels[:, [1, 3]] /= img.shape[1] # normalized width 0-1 + # HSV color-space + augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) - if self.augment: - # flip up-down + # Flip up-down if random.random() < hyp['flipud']: img = np.flipud(img) - if nL: + if nl: labels[:, 2] = 1 - labels[:, 2] - # flip left-right + # Flip left-right if random.random() < hyp['fliplr']: img = np.fliplr(img) - if nL: + if nl: labels[:, 1] = 1 - labels[:, 1] - labels_out = torch.zeros((nL, 6)) - if nL: + # Cutouts + # labels = cutout(img, labels, p=0.5) + + labels_out = torch.zeros((nl, 6)) + if nl: labels_out[:, 1:] = torch.from_numpy(labels) # Convert - img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 + img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB img = np.ascontiguousarray(img) return torch.from_numpy(img), labels_out, self.img_files[index], shapes @@ -611,13 +635,13 @@ def collate_fn4(batch): n = len(shapes) // 4 img4, label4, path4, shapes4 = [], [], path[:n], shapes[:n] - ho = torch.tensor([[0., 0, 0, 1, 0, 0]]) - wo = torch.tensor([[0., 0, 1, 0, 0, 0]]) - s = torch.tensor([[1, 1, .5, .5, .5, .5]]) # scale + ho = torch.tensor([[0.0, 0, 0, 1, 0, 0]]) + wo = torch.tensor([[0.0, 0, 1, 0, 0, 0]]) + s = torch.tensor([[1, 1, 0.5, 0.5, 0.5, 0.5]]) # scale for i in range(n): # zidane torch.zeros(16,3,720,1280) # BCHW i *= 4 if random.random() < 0.5: - im = F.interpolate(img[i].unsqueeze(0).float(), scale_factor=2., mode='bilinear', align_corners=False)[ + im = F.interpolate(img[i].unsqueeze(0).float(), scale_factor=2.0, mode='bilinear', align_corners=False)[ 0].type(img[i].type()) l = label[i] else: @@ -633,55 +657,34 @@ def collate_fn4(batch): # Ancillary functions -------------------------------------------------------------------------------------------------- -def load_image(self, index): - # loads 1 image from dataset, returns img, original hw, resized hw - img = self.imgs[index] - if img is None: # not cached - path = self.img_files[index] - img = cv2.imread(path) # BGR - assert img is not None, 'Image Not Found ' + path - h0, w0 = img.shape[:2] # orig hw +def load_image(self, i): + # loads 1 image from dataset index 'i', returns im, original hw, resized hw + im = self.imgs[i] + if im is None: # not cached in ram + npy = self.img_npy[i] + if npy and npy.exists(): # load npy + im = np.load(npy) + else: # read image + path = self.img_files[i] + im = cv2.imread(path) # BGR + assert im is not None, f'Image Not Found {path}' + h0, w0 = im.shape[:2] # orig hw r = self.img_size / max(h0, w0) # ratio if r != 1: # if sizes are not equal - img = cv2.resize(img, (int(w0 * r), int(h0 * r)), - interpolation=cv2.INTER_AREA if r < 1 and not self.augment else cv2.INTER_LINEAR) - return img, (h0, w0), img.shape[:2] # img, hw_original, hw_resized + im = cv2.resize(im, (int(w0 * r), int(h0 * r)), + interpolation=cv2.INTER_AREA if r < 1 and not self.augment else cv2.INTER_LINEAR) + return im, (h0, w0), im.shape[:2] # im, hw_original, hw_resized else: - return self.imgs[index], self.img_hw0[index], self.img_hw[index] # img, hw_original, hw_resized - - -def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5): - r = np.random.uniform(-1, 1, 3) * [hgain, sgain, vgain] + 1 # random gains - hue, sat, val = cv2.split(cv2.cvtColor(img, cv2.COLOR_BGR2HSV)) - dtype = img.dtype # uint8 - - x = np.arange(0, 256, dtype=np.int16) - lut_hue = ((x * r[0]) % 180).astype(dtype) - lut_sat = np.clip(x * r[1], 0, 255).astype(dtype) - lut_val = np.clip(x * r[2], 0, 255).astype(dtype) - - img_hsv = cv2.merge((cv2.LUT(hue, lut_hue), cv2.LUT(sat, lut_sat), cv2.LUT(val, lut_val))).astype(dtype) - cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR, dst=img) # no return needed - - -def hist_equalize(img, clahe=True, bgr=False): - # Equalize histogram on BGR image 'img' with img.shape(n,m,3) and range 0-255 - yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV if bgr else cv2.COLOR_RGB2YUV) - if clahe: - c = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) - yuv[:, :, 0] = c.apply(yuv[:, :, 0]) - else: - yuv[:, :, 0] = cv2.equalizeHist(yuv[:, :, 0]) # equalize Y channel histogram - return cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR if bgr else cv2.COLOR_YUV2RGB) # convert YUV image to RGB + return self.imgs[i], self.img_hw0[i], self.img_hw[i] # im, hw_original, hw_resized def load_mosaic(self, index): - # loads images in a 4-mosaic - + # 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic labels4, segments4 = [], [] s = self.img_size - yc, xc = [int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border] # mosaic center x, y + yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y indices = [index] + random.choices(self.indices, k=3) # 3 additional image indices + random.shuffle(indices) for i, index in enumerate(indices): # Load image img, _, (h, w) = load_image(self, index) @@ -720,6 +723,7 @@ def load_mosaic(self, index): # img4, labels4 = replicate(img4, labels4) # replicate # Augment + img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp['copy_paste']) img4, labels4 = random_perspective(img4, labels4, segments4, degrees=self.hyp['degrees'], translate=self.hyp['translate'], @@ -732,11 +736,11 @@ def load_mosaic(self, index): def load_mosaic9(self, index): - # loads images in a 9-mosaic - + # 9-mosaic loader. Loads 1 image + 8 random images into a 9-image mosaic labels9, segments9 = [], [] s = self.img_size indices = [index] + random.choices(self.indices, k=8) # 8 additional image indices + random.shuffle(indices) for i, index in enumerate(indices): # Load image img, _, (h, w) = load_image(self, index) @@ -764,7 +768,7 @@ def load_mosaic9(self, index): c = s - w, s + h0 - hp - h, s, s + h0 - hp padx, pady = c[:2] - x1, y1, x2, y2 = [max(x, 0) for x in c] # allocate coords + x1, y1, x2, y2 = (max(x, 0) for x in c) # allocate coords # Labels labels, segments = self.labels[index].copy(), self.segments[index].copy() @@ -779,7 +783,7 @@ def load_mosaic9(self, index): hp, wp = h, w # height, width previous # Offset - yc, xc = [int(random.uniform(0, s)) for _ in self.mosaic_border] # mosaic center x, y + yc, xc = (int(random.uniform(0, s)) for _ in self.mosaic_border) # mosaic center x, y img9 = img9[yc:yc + 2 * s, xc:xc + 2 * s] # Concat/clip labels @@ -805,199 +809,6 @@ def load_mosaic9(self, index): return img9, labels9 -def replicate(img, labels): - # Replicate labels - h, w = img.shape[:2] - boxes = labels[:, 1:].astype(int) - x1, y1, x2, y2 = boxes.T - s = ((x2 - x1) + (y2 - y1)) / 2 # side length (pixels) - for i in s.argsort()[:round(s.size * 0.5)]: # smallest indices - x1b, y1b, x2b, y2b = boxes[i] - bh, bw = y2b - y1b, x2b - x1b - yc, xc = int(random.uniform(0, h - bh)), int(random.uniform(0, w - bw)) # offset x, y - x1a, y1a, x2a, y2a = [xc, yc, xc + bw, yc + bh] - img[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax] - labels = np.append(labels, [[labels[i, 0], x1a, y1a, x2a, y2a]], axis=0) - - return img, labels - - -def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32): - # Resize and pad image while meeting stride-multiple constraints - shape = img.shape[:2] # current shape [height, width] - if isinstance(new_shape, int): - new_shape = (new_shape, new_shape) - - # Scale ratio (new / old) - r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) - if not scaleup: # only scale down, do not scale up (for better test mAP) - r = min(r, 1.0) - - # Compute padding - ratio = r, r # width, height ratios - new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) - dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding - if auto: # minimum rectangle - dw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh padding - elif scaleFill: # stretch - dw, dh = 0.0, 0.0 - new_unpad = (new_shape[1], new_shape[0]) - ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios - - dw /= 2 # divide padding into 2 sides - dh /= 2 - - if shape[::-1] != new_unpad: # resize - img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) - top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) - left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) - img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border - return img, ratio, (dw, dh) - - -def random_perspective(img, targets=(), segments=(), degrees=10, translate=.1, scale=.1, shear=10, perspective=0.0, - border=(0, 0)): - # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) - # targets = [cls, xyxy] - - height = img.shape[0] + border[0] * 2 # shape(h,w,c) - width = img.shape[1] + border[1] * 2 - - # Center - C = np.eye(3) - C[0, 2] = -img.shape[1] / 2 # x translation (pixels) - C[1, 2] = -img.shape[0] / 2 # y translation (pixels) - - # Perspective - P = np.eye(3) - P[2, 0] = random.uniform(-perspective, perspective) # x perspective (about y) - P[2, 1] = random.uniform(-perspective, perspective) # y perspective (about x) - - # Rotation and Scale - R = np.eye(3) - a = random.uniform(-degrees, degrees) - # a += random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotations - s = random.uniform(1 - scale, 1 + scale) - # s = 2 ** random.uniform(-scale, scale) - R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s) - - # Shear - S = np.eye(3) - S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # x shear (deg) - S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # y shear (deg) - - # Translation - T = np.eye(3) - T[0, 2] = random.uniform(0.5 - translate, 0.5 + translate) * width # x translation (pixels) - T[1, 2] = random.uniform(0.5 - translate, 0.5 + translate) * height # y translation (pixels) - - # Combined rotation matrix - M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT - if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): # image changed - if perspective: - img = cv2.warpPerspective(img, M, dsize=(width, height), borderValue=(114, 114, 114)) - else: # affine - img = cv2.warpAffine(img, M[:2], dsize=(width, height), borderValue=(114, 114, 114)) - - # Visualize - # import matplotlib.pyplot as plt - # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel() - # ax[0].imshow(img[:, :, ::-1]) # base - # ax[1].imshow(img2[:, :, ::-1]) # warped - - # Transform label coordinates - n = len(targets) - if n: - use_segments = any(x.any() for x in segments) - new = np.zeros((n, 4)) - if use_segments: # warp segments - segments = resample_segments(segments) # upsample - for i, segment in enumerate(segments): - xy = np.ones((len(segment), 3)) - xy[:, :2] = segment - xy = xy @ M.T # transform - xy = xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2] # perspective rescale or affine - - # clip - new[i] = segment2box(xy, width, height) - - else: # warp boxes - xy = np.ones((n * 4, 3)) - xy[:, :2] = targets[:, [1, 2, 3, 4, 1, 4, 3, 2]].reshape(n * 4, 2) # x1y1, x2y2, x1y2, x2y1 - xy = xy @ M.T # transform - xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]).reshape(n, 8) # perspective rescale or affine - - # create new boxes - x = xy[:, [0, 2, 4, 6]] - y = xy[:, [1, 3, 5, 7]] - new = np.concatenate((x.min(1), y.min(1), x.max(1), y.max(1))).reshape(4, n).T - - # clip - new[:, [0, 2]] = new[:, [0, 2]].clip(0, width) - new[:, [1, 3]] = new[:, [1, 3]].clip(0, height) - - # filter candidates - i = box_candidates(box1=targets[:, 1:5].T * s, box2=new.T, area_thr=0.01 if use_segments else 0.10) - targets = targets[i] - targets[:, 1:5] = new[i] - - return img, targets - - -def box_candidates(box1, box2, wh_thr=2, ar_thr=20, area_thr=0.1, eps=1e-16): # box1(4,n), box2(4,n) - # Compute candidate boxes: box1 before augment, box2 after augment, wh_thr (pixels), aspect_ratio_thr, area_ratio - w1, h1 = box1[2] - box1[0], box1[3] - box1[1] - w2, h2 = box2[2] - box2[0], box2[3] - box2[1] - ar = np.maximum(w2 / (h2 + eps), h2 / (w2 + eps)) # aspect ratio - return (w2 > wh_thr) & (h2 > wh_thr) & (w2 * h2 / (w1 * h1 + eps) > area_thr) & (ar < ar_thr) # candidates - - -def cutout(image, labels): - # Applies image cutout augmentation https://arxiv.org/abs/1708.04552 - h, w = image.shape[:2] - - def bbox_ioa(box1, box2): - # Returns the intersection over box2 area given box1, box2. box1 is 4, box2 is nx4. boxes are x1y1x2y2 - box2 = box2.transpose() - - # Get the coordinates of bounding boxes - b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3] - b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3] - - # Intersection area - inter_area = (np.minimum(b1_x2, b2_x2) - np.maximum(b1_x1, b2_x1)).clip(0) * \ - (np.minimum(b1_y2, b2_y2) - np.maximum(b1_y1, b2_y1)).clip(0) - - # box2 area - box2_area = (b2_x2 - b2_x1) * (b2_y2 - b2_y1) + 1e-16 - - # Intersection over box2 area - return inter_area / box2_area - - # create random masks - scales = [0.5] * 1 + [0.25] * 2 + [0.125] * 4 + [0.0625] * 8 + [0.03125] * 16 # image size fraction - for s in scales: - mask_h = random.randint(1, int(h * s)) - mask_w = random.randint(1, int(w * s)) - - # box - xmin = max(0, random.randint(0, w) - mask_w // 2) - ymin = max(0, random.randint(0, h) - mask_h // 2) - xmax = min(w, xmin + mask_w) - ymax = min(h, ymin + mask_h) - - # apply random color mask - image[ymin:ymax, xmin:xmax] = [random.randint(64, 191) for _ in range(3)] - - # return unobscured labels - if len(labels) and s > 0.03: - box = np.array([xmin, ymin, xmax, ymax], dtype=np.float32) - ioa = bbox_ioa(box, labels[:, 1:5]) # intersection over area - labels = labels[ioa < 0.60] # remove >60% obscured labels - - return labels - - def create_folder(path='./new'): # Create folder if os.path.exists(path): @@ -1005,7 +816,7 @@ def create_folder(path='./new'): os.makedirs(path) # make new output folder -def flatten_recursive(path='../coco128'): +def flatten_recursive(path='../datasets/coco128'): # Flatten a recursive directory by bringing all files to top level new_path = Path(path + '_flat') create_folder(new_path) @@ -1013,15 +824,14 @@ def flatten_recursive(path='../coco128'): shutil.copyfile(file, new_path / Path(file).name) -def extract_boxes(path='../coco128/'): # from utils.datasets import *; extract_boxes('../coco128') +def extract_boxes(path='../datasets/coco128'): # from utils.datasets import *; extract_boxes() # Convert detection dataset into classification dataset, with one directory per class - path = Path(path) # images dir shutil.rmtree(path / 'classifier') if (path / 'classifier').is_dir() else None # remove existing files = list(path.rglob('*.*')) n = len(files) # number of files for im_file in tqdm(files, total=n): - if im_file.suffix[1:] in img_formats: + if im_file.suffix[1:] in IMG_FORMATS: # image im = cv2.imread(str(im_file))[..., ::-1] # BGR to RGB h, w = im.shape[:2] @@ -1029,7 +839,7 @@ def extract_boxes(path='../coco128/'): # from utils.datasets import *; extract_ # labels lb_file = Path(img2label_paths([str(im_file)])[0]) if Path(lb_file).exists(): - with open(lb_file, 'r') as f: + with open(lb_file) as f: lb = np.array([x.split() for x in f.read().strip().splitlines()], dtype=np.float32) # labels for j, x in enumerate(lb): @@ -1048,24 +858,179 @@ def extract_boxes(path='../coco128/'): # from utils.datasets import *; extract_ assert cv2.imwrite(str(f), im[b[1]:b[3], b[0]:b[2]]), f'box failure in {f}' -def autosplit(path='../coco128', weights=(0.9, 0.1, 0.0), annotated_only=False): +def autosplit(path='../datasets/coco128/images', weights=(0.9, 0.1, 0.0), annotated_only=False): """ Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files - Usage: from utils.datasets import *; autosplit('../coco128') + Usage: from utils.datasets import *; autosplit() Arguments - path: Path to images directory - weights: Train, val, test weights (list) - annotated_only: Only use images with an annotated txt file + path: Path to images directory + weights: Train, val, test weights (list, tuple) + annotated_only: Only use images with an annotated txt file """ path = Path(path) # images dir - files = sum([list(path.rglob(f"*.{img_ext}")) for img_ext in img_formats], []) # image files only + files = sorted(x for x in path.rglob('*.*') if x.suffix[1:].lower() in IMG_FORMATS) # image files only n = len(files) # number of files + random.seed(0) # for reproducibility indices = random.choices([0, 1, 2], weights=weights, k=n) # assign each image to a split txt = ['autosplit_train.txt', 'autosplit_val.txt', 'autosplit_test.txt'] # 3 txt files - [(path / x).unlink() for x in txt if (path / x).exists()] # remove existing + [(path.parent / x).unlink(missing_ok=True) for x in txt] # remove existing print(f'Autosplitting images from {path}' + ', using *.txt labeled images only' * annotated_only) for i, img in tqdm(zip(indices, files), total=n): if not annotated_only or Path(img2label_paths([str(img)])[0]).exists(): # check label - with open(path / txt[i], 'a') as f: - f.write(str(img) + '\n') # add image to txt file + with open(path.parent / txt[i], 'a') as f: + f.write('./' + img.relative_to(path.parent).as_posix() + '\n') # add image to txt file + + +def verify_image_label(args): + # Verify one image-label pair + im_file, lb_file, prefix = args + nm, nf, ne, nc, msg, segments = 0, 0, 0, 0, '', [] # number (missing, found, empty, corrupt), message, segments + try: + # verify images + im = Image.open(im_file) + im.verify() # PIL verify + shape = exif_size(im) # image size + assert (shape[0] > 9) & (shape[1] > 9), f'image size {shape} <10 pixels' + assert im.format.lower() in IMG_FORMATS, f'invalid image format {im.format}' + if im.format.lower() in ('jpg', 'jpeg'): + with open(im_file, 'rb') as f: + f.seek(-2, 2) + if f.read() != b'\xff\xd9': # corrupt JPEG + ImageOps.exif_transpose(Image.open(im_file)).save(im_file, 'JPEG', subsampling=0, quality=100) + msg = f'{prefix}WARNING: {im_file}: corrupt JPEG restored and saved' + + # verify labels + if os.path.isfile(lb_file): + nf = 1 # label found + with open(lb_file) as f: + l = [x.split() for x in f.read().strip().splitlines() if len(x)] + if any([len(x) > 8 for x in l]): # is segment + classes = np.array([x[0] for x in l], dtype=np.float32) + segments = [np.array(x[1:], dtype=np.float32).reshape(-1, 2) for x in l] # (cls, xy1...) + l = np.concatenate((classes.reshape(-1, 1), segments2boxes(segments)), 1) # (cls, xywh) + l = np.array(l, dtype=np.float32) + nl = len(l) + if nl: + assert l.shape[1] == 5, f'labels require 5 columns, {l.shape[1]} columns detected' + assert (l >= 0).all(), f'negative label values {l[l < 0]}' + assert (l[:, 1:] <= 1).all(), f'non-normalized or out of bounds coordinates {l[:, 1:][l[:, 1:] > 1]}' + _, i = np.unique(l, axis=0, return_index=True) + if len(i) < nl: # duplicate row check + l = l[i] # remove duplicates + if segments: + segments = segments[i] + msg = f'{prefix}WARNING: {im_file}: {nl - len(i)} duplicate labels removed' + else: + ne = 1 # label empty + l = np.zeros((0, 5), dtype=np.float32) + else: + nm = 1 # label missing + l = np.zeros((0, 5), dtype=np.float32) + return im_file, l, shape, segments, nm, nf, ne, nc, msg + except Exception as e: + nc = 1 + msg = f'{prefix}WARNING: {im_file}: ignoring corrupt image/label: {e}' + return [None, None, None, None, nm, nf, ne, nc, msg] + + +def dataset_stats(path='coco128.yaml', autodownload=False, verbose=False, profile=False, hub=False): + """ Return dataset statistics dictionary with images and instances counts per split per class + To run in parent directory: export PYTHONPATH="$PWD/yolov3" + Usage1: from utils.datasets import *; dataset_stats('coco128.yaml', autodownload=True) + Usage2: from utils.datasets import *; dataset_stats('../datasets/coco128_with_yaml.zip') + Arguments + path: Path to data.yaml or data.zip (with data.yaml inside data.zip) + autodownload: Attempt to download dataset if not found locally + verbose: Print stats dictionary + """ + + def round_labels(labels): + # Update labels to integer class and 6 decimal place floats + return [[int(c), *(round(x, 4) for x in points)] for c, *points in labels] + + def unzip(path): + # Unzip data.zip TODO: CONSTRAINT: path/to/abc.zip MUST unzip to 'path/to/abc/' + if str(path).endswith('.zip'): # path is data.zip + assert Path(path).is_file(), f'Error unzipping {path}, file not found' + ZipFile(path).extractall(path=path.parent) # unzip + dir = path.with_suffix('') # dataset directory == zip name + return True, str(dir), next(dir.rglob('*.yaml')) # zipped, data_dir, yaml_path + else: # path is data.yaml + return False, None, path + + def hub_ops(f, max_dim=1920): + # HUB ops for 1 image 'f': resize and save at reduced quality in /dataset-hub for web/app viewing + f_new = im_dir / Path(f).name # dataset-hub image filename + try: # use PIL + im = Image.open(f) + r = max_dim / max(im.height, im.width) # ratio + if r < 1.0: # image too large + im = im.resize((int(im.width * r), int(im.height * r))) + im.save(f_new, 'JPEG', quality=75, optimize=True) # save + except Exception as e: # use OpenCV + print(f'WARNING: HUB ops PIL failure {f}: {e}') + im = cv2.imread(f) + im_height, im_width = im.shape[:2] + r = max_dim / max(im_height, im_width) # ratio + if r < 1.0: # image too large + im = cv2.resize(im, (int(im_width * r), int(im_height * r)), interpolation=cv2.INTER_LINEAR) + cv2.imwrite(str(f_new), im) + + zipped, data_dir, yaml_path = unzip(Path(path)) + with open(check_yaml(yaml_path), errors='ignore') as f: + data = yaml.safe_load(f) # data dict + if zipped: + data['path'] = data_dir # TODO: should this be dir.resolve()? + check_dataset(data, autodownload) # download dataset if missing + hub_dir = Path(data['path'] + ('-hub' if hub else '')) + stats = {'nc': data['nc'], 'names': data['names']} # statistics dictionary + for split in 'train', 'val', 'test': + if data.get(split) is None: + stats[split] = None # i.e. no test set + continue + x = [] + dataset = LoadImagesAndLabels(data[split]) # load dataset + for label in tqdm(dataset.labels, total=dataset.n, desc='Statistics'): + x.append(np.bincount(label[:, 0].astype(int), minlength=data['nc'])) + x = np.array(x) # shape(128x80) + stats[split] = {'instance_stats': {'total': int(x.sum()), 'per_class': x.sum(0).tolist()}, + 'image_stats': {'total': dataset.n, 'unlabelled': int(np.all(x == 0, 1).sum()), + 'per_class': (x > 0).sum(0).tolist()}, + 'labels': [{str(Path(k).name): round_labels(v.tolist())} for k, v in + zip(dataset.img_files, dataset.labels)]} + + if hub: + im_dir = hub_dir / 'images' + im_dir.mkdir(parents=True, exist_ok=True) + for _ in tqdm(ThreadPool(NUM_THREADS).imap(hub_ops, dataset.img_files), total=dataset.n, desc='HUB Ops'): + pass + + # Profile + stats_path = hub_dir / 'stats.json' + if profile: + for _ in range(1): + file = stats_path.with_suffix('.npy') + t1 = time.time() + np.save(file, stats) + t2 = time.time() + x = np.load(file, allow_pickle=True) + print(f'stats.npy times: {time.time() - t2:.3f}s read, {t2 - t1:.3f}s write') + + file = stats_path.with_suffix('.json') + t1 = time.time() + with open(file, 'w') as f: + json.dump(stats, f) # save stats *.json + t2 = time.time() + with open(file) as f: + x = json.load(f) # load hyps dict + print(f'stats.json times: {time.time() - t2:.3f}s read, {t2 - t1:.3f}s write') + + # Save, print and return + if hub: + print(f'Saving {stats_path.resolve()}...') + with open(stats_path, 'w') as f: + json.dump(stats, f) # save stats.json + if verbose: + print(json.dumps(stats, indent=2, sort_keys=False)) + return stats diff --git a/utils/google_utils.py b/utils/downloads.py similarity index 83% rename from utils/google_utils.py rename to utils/downloads.py index 340fab1328..cd653078e9 100644 --- a/utils/google_utils.py +++ b/utils/downloads.py @@ -1,10 +1,15 @@ -# Google utils: https://cloud.google.com/storage/docs/reference/libraries +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Download utils +""" import os import platform import subprocess import time +import urllib from pathlib import Path +from zipfile import ZipFile import requests import torch @@ -19,30 +24,32 @@ def gsutil_getsize(url=''): def safe_download(file, url, url2=None, min_bytes=1E0, error_msg=''): # Attempts to download file from url or url2, checks and removes incomplete downloads < min_bytes file = Path(file) - try: # GitHub + assert_msg = f"Downloaded file '{file}' does not exist or size is < min_bytes={min_bytes}" + try: # url1 print(f'Downloading {url} to {file}...') torch.hub.download_url_to_file(url, str(file)) - assert file.exists() and file.stat().st_size > min_bytes # check - except Exception as e: # GCP + assert file.exists() and file.stat().st_size > min_bytes, assert_msg # check + except Exception as e: # url2 file.unlink(missing_ok=True) # remove partial downloads - print(f'Download error: {e}\nRe-attempting {url2 or url} to {file}...') + print(f'ERROR: {e}\nRe-attempting {url2 or url} to {file}...') os.system(f"curl -L '{url2 or url}' -o '{file}' --retry 3 -C -") # curl download, retry and resume on fail finally: if not file.exists() or file.stat().st_size < min_bytes: # check file.unlink(missing_ok=True) # remove partial downloads - print(f'ERROR: Download failure: {error_msg or url}') + print(f"ERROR: {assert_msg}\n{error_msg}") print('') -def attempt_download(file, repo='ultralytics/yolov3'): +def attempt_download(file, repo='ultralytics/yolov3'): # from utils.downloads import *; attempt_download() # Attempt file download if does not exist file = Path(str(file).strip().replace("'", '')) if not file.exists(): # URL specified - name = file.name + name = Path(urllib.parse.unquote(str(file))).name # decode '%2F' to '/' etc. if str(file).startswith(('http:/', 'https:/')): # download url = str(file).replace(':/', '://') # Pathlib turns :// -> :/ + name = name.split('?')[0] # parse authentication https://url.com/file.txt?auth... safe_download(file=name, url=url, min_bytes=1E5) return name @@ -50,7 +57,7 @@ def attempt_download(file, repo='ultralytics/yolov3'): file.parent.mkdir(parents=True, exist_ok=True) # make parent dir (if required) try: response = requests.get(f'https://api.github.com/repos/{repo}/releases/latest').json() # github api - assets = [x['name'] for x in response['assets']] # release assets, i.e. ['yolov5s.pt', 'yolov5m.pt', ...] + assets = [x['name'] for x in response['assets']] # release assets, i.e. ['yolov3.pt'...] tag = response['tag_name'] # i.e. 'v1.0' except: # fallback plan assets = ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt'] @@ -70,7 +77,7 @@ def attempt_download(file, repo='ultralytics/yolov3'): def gdrive_download(id='16TiPfZj7htmTyhntwcZyEEAejOUxuT6m', file='tmp.zip'): - # Downloads a file from Google Drive. from yolov3.utils.google_utils import *; gdrive_download() + # Downloads a file from Google Drive. from yolov3.utils.downloads import *; gdrive_download() t = time.time() file = Path(file) cookie = Path('cookie') # gdrive cookie @@ -97,8 +104,8 @@ def gdrive_download(id='16TiPfZj7htmTyhntwcZyEEAejOUxuT6m', file='tmp.zip'): # Unzip if archive if file.suffix == '.zip': print('unzipping... ', end='') - os.system(f'unzip -q {file}') # unzip - file.unlink() # remove zip to free space + ZipFile(file).extractall(path=file.parent) # unzip + file.unlink() # remove zip print(f'Done ({time.time() - t:.1f}s)') return r @@ -111,6 +118,9 @@ def get_token(cookie="./cookie"): return line.split()[-1] return "" +# Google utils: https://cloud.google.com/storage/docs/reference/libraries ---------------------------------------------- +# +# # def upload_blob(bucket_name, source_file_name, destination_blob_name): # # Uploads a file to a bucket # # https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-python diff --git a/utils/flask_rest_api/README.md b/utils/flask_rest_api/README.md deleted file mode 100644 index 324c2416dc..0000000000 --- a/utils/flask_rest_api/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# Flask REST API -[REST](https://en.wikipedia.org/wiki/Representational_state_transfer) [API](https://en.wikipedia.org/wiki/API)s are commonly used to expose Machine Learning (ML) models to other services. This folder contains an example REST API created using Flask to expose the YOLOv5s model from [PyTorch Hub](https://pytorch.org/hub/ultralytics_yolov5/). - -## Requirements - -[Flask](https://palletsprojects.com/p/flask/) is required. Install with: -```shell -$ pip install Flask -``` - -## Run - -After Flask installation run: - -```shell -$ python3 restapi.py --port 5000 -``` - -Then use [curl](https://curl.se/) to perform a request: - -```shell -$ curl -X POST -F image=@zidane.jpg 'http://localhost:5000/v1/object-detection/yolov5s'` -``` - -The model inference results are returned as a JSON response: - -```json -[ - { - "class": 0, - "confidence": 0.8900438547, - "height": 0.9318675399, - "name": "person", - "width": 0.3264600933, - "xcenter": 0.7438579798, - "ycenter": 0.5207948685 - }, - { - "class": 0, - "confidence": 0.8440024257, - "height": 0.7155083418, - "name": "person", - "width": 0.6546785235, - "xcenter": 0.427829951, - "ycenter": 0.6334488392 - }, - { - "class": 27, - "confidence": 0.3771208823, - "height": 0.3902671337, - "name": "tie", - "width": 0.0696444362, - "xcenter": 0.3675483763, - "ycenter": 0.7991207838 - }, - { - "class": 27, - "confidence": 0.3527112305, - "height": 0.1540903747, - "name": "tie", - "width": 0.0336618312, - "xcenter": 0.7814827561, - "ycenter": 0.5065554976 - } -] -``` - -An example python script to perform inference using [requests](https://docs.python-requests.org/en/master/) is given in `example_request.py` diff --git a/utils/flask_rest_api/example_request.py b/utils/flask_rest_api/example_request.py deleted file mode 100644 index ff21f30f93..0000000000 --- a/utils/flask_rest_api/example_request.py +++ /dev/null @@ -1,13 +0,0 @@ -"""Perform test request""" -import pprint - -import requests - -DETECTION_URL = "http://localhost:5000/v1/object-detection/yolov5s" -TEST_IMAGE = "zidane.jpg" - -image_data = open(TEST_IMAGE, "rb").read() - -response = requests.post(DETECTION_URL, files={"image": image_data}).json() - -pprint.pprint(response) diff --git a/utils/flask_rest_api/restapi.py b/utils/flask_rest_api/restapi.py deleted file mode 100644 index b0df747220..0000000000 --- a/utils/flask_rest_api/restapi.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -Run a rest API exposing the yolov5s object detection model -""" -import argparse -import io - -import torch -from PIL import Image -from flask import Flask, request - -app = Flask(__name__) - -DETECTION_URL = "/v1/object-detection/yolov5s" - - -@app.route(DETECTION_URL, methods=["POST"]) -def predict(): - if not request.method == "POST": - return - - if request.files.get("image"): - image_file = request.files["image"] - image_bytes = image_file.read() - - img = Image.open(io.BytesIO(image_bytes)) - - results = model(img, size=640) # reduce size=320 for faster inference - return results.pandas().xyxy[0].to_json(orient="records") - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Flask API exposing YOLOv3 model") - parser.add_argument("--port", default=5000, type=int, help="port number") - args = parser.parse_args() - - model = torch.hub.load("ultralytics/yolov5", "yolov5s", force_reload=True) # force_reload to recache - app.run(host="0.0.0.0", port=args.port) # debug=True causes Restarting with stat diff --git a/utils/general.py b/utils/general.py index af33c63389..820e35d945 100755 --- a/utils/general.py +++ b/utils/general.py @@ -1,5 +1,9 @@ -# YOLOv3 general utils +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +General utils +""" +import contextlib import glob import logging import math @@ -7,11 +11,15 @@ import platform import random import re -import subprocess +import shutil +import signal import time +import urllib from itertools import repeat from multiprocessing.pool import ThreadPool from pathlib import Path +from subprocess import check_output +from zipfile import ZipFile import cv2 import numpy as np @@ -21,9 +29,8 @@ import torchvision import yaml -from utils.google_utils import gsutil_getsize -from utils.metrics import fitness -from utils.torch_utils import init_torch_seeds +from utils.downloads import gsutil_getsize +from utils.metrics import box_iou, fitness # Settings torch.set_printoptions(linewidth=320, precision=5, profile='long') @@ -32,18 +39,96 @@ cv2.setNumThreads(0) # prevent OpenCV from multithreading (incompatible with PyTorch DataLoader) os.environ['NUMEXPR_MAX_THREADS'] = str(min(os.cpu_count(), 8)) # NumExpr max threads +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # root directory -def set_logging(rank=-1, verbose=True): - logging.basicConfig( - format="%(message)s", - level=logging.INFO if (verbose and rank in [-1, 0]) else logging.WARN) + +def set_logging(name=None, verbose=True): + # Sets level and returns logger + rank = int(os.getenv('RANK', -1)) # rank in world for Multi-GPU trainings + logging.basicConfig(format="%(message)s", level=logging.INFO if (verbose and rank in (-1, 0)) else logging.WARNING) + return logging.getLogger(name) + + +LOGGER = set_logging(__name__) # define globally (used in train.py, val.py, detect.py, etc.) + + +class Profile(contextlib.ContextDecorator): + # Usage: @Profile() decorator or 'with Profile():' context manager + def __enter__(self): + self.start = time.time() + + def __exit__(self, type, value, traceback): + print(f'Profile results: {time.time() - self.start:.5f}s') + + +class Timeout(contextlib.ContextDecorator): + # Usage: @Timeout(seconds) decorator or 'with Timeout(seconds):' context manager + def __init__(self, seconds, *, timeout_msg='', suppress_timeout_errors=True): + self.seconds = int(seconds) + self.timeout_message = timeout_msg + self.suppress = bool(suppress_timeout_errors) + + def _timeout_handler(self, signum, frame): + raise TimeoutError(self.timeout_message) + + def __enter__(self): + signal.signal(signal.SIGALRM, self._timeout_handler) # Set handler for SIGALRM + signal.alarm(self.seconds) # start countdown for SIGALRM to be raised + + def __exit__(self, exc_type, exc_val, exc_tb): + signal.alarm(0) # Cancel SIGALRM if it's scheduled + if self.suppress and exc_type is TimeoutError: # Suppress TimeoutError + return True + + +class WorkingDirectory(contextlib.ContextDecorator): + # Usage: @WorkingDirectory(dir) decorator or 'with WorkingDirectory(dir):' context manager + def __init__(self, new_dir): + self.dir = new_dir # new dir + self.cwd = Path.cwd().resolve() # current dir + + def __enter__(self): + os.chdir(self.dir) + + def __exit__(self, exc_type, exc_val, exc_tb): + os.chdir(self.cwd) + + +def try_except(func): + # try-except function. Usage: @try_except decorator + def handler(*args, **kwargs): + try: + func(*args, **kwargs) + except Exception as e: + print(e) + + return handler + + +def methods(instance): + # Get class/instance methods + return [f for f in dir(instance) if callable(getattr(instance, f)) and not f.startswith("__")] + + +def print_args(name, opt): + # Print argparser arguments + LOGGER.info(colorstr(f'{name}: ') + ', '.join(f'{k}={v}' for k, v in vars(opt).items())) def init_seeds(seed=0): - # Initialize random number generator (RNG) seeds + # Initialize random number generator (RNG) seeds https://pytorch.org/docs/stable/notes/randomness.html + # cudnn seed 0 settings are slower and more reproducible, else faster and less reproducible + import torch.backends.cudnn as cudnn random.seed(seed) np.random.seed(seed) - init_torch_seeds(seed) + torch.manual_seed(seed) + cudnn.benchmark, cudnn.deterministic = (False, True) if seed == 0 else (True, False) + + +def intersect_dicts(da, db, exclude=()): + # Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values + return {k: v for k, v in da.items() if k in db and not any(x in k for x in exclude) and v.shape == db[k].shape} def get_latest_run(search_dir='.'): @@ -52,81 +137,136 @@ def get_latest_run(search_dir='.'): return max(last_list, key=os.path.getctime) if last_list else '' +def user_config_dir(dir='Ultralytics', env_var='YOLOV3_CONFIG_DIR'): + # Return path of user configuration directory. Prefer environment variable if exists. Make dir if required. + env = os.getenv(env_var) + if env: + path = Path(env) # use environment variable + else: + cfg = {'Windows': 'AppData/Roaming', 'Linux': '.config', 'Darwin': 'Library/Application Support'} # 3 OS dirs + path = Path.home() / cfg.get(platform.system(), '') # OS-specific config dir + path = (path if is_writeable(path) else Path('/tmp')) / dir # GCP and AWS lambda fix, only /tmp is writeable + path.mkdir(exist_ok=True) # make if required + return path + + +def is_writeable(dir, test=False): + # Return True if directory has write permissions, test opening a file with write permissions if test=True + if test: # method 1 + file = Path(dir) / 'tmp.txt' + try: + with open(file, 'w'): # open file with write permissions + pass + file.unlink() # remove file + return True + except OSError: + return False + else: # method 2 + return os.access(dir, os.R_OK) # possible issues on Windows + + def is_docker(): - # Is environment a Docker container + # Is environment a Docker container? return Path('/workspace').exists() # or Path('/.dockerenv').exists() def is_colab(): - # Is environment a Google Colab instance + # Is environment a Google Colab instance? try: import google.colab return True - except Exception as e: + except ImportError: return False +def is_pip(): + # Is file in a pip package? + return 'site-packages' in Path(__file__).resolve().parts + + +def is_ascii(s=''): + # Is string composed of all ASCII (no UTF) characters? (note str().isascii() introduced in python 3.7) + s = str(s) # convert list, tuple, None, etc. to str + return len(s.encode().decode('ascii', 'ignore')) == len(s) + + +def is_chinese(s='人工智能'): + # Is string composed of any Chinese characters? + return re.search('[\u4e00-\u9fff]', s) + + def emojis(str=''): # Return platform-dependent emoji-safe version of string return str.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else str -def file_size(file): - # Return file size in MB - return Path(file).stat().st_size / 1e6 +def file_size(path): + # Return file/dir size (MB) + path = Path(path) + if path.is_file(): + return path.stat().st_size / 1E6 + elif path.is_dir(): + return sum(f.stat().st_size for f in path.glob('**/*') if f.is_file()) / 1E6 + else: + return 0.0 def check_online(): # Check internet connectivity import socket try: - socket.create_connection(("1.1.1.1", 443), 5) # check host accesability + socket.create_connection(("1.1.1.1", 443), 5) # check host accessibility return True except OSError: return False +@try_except +@WorkingDirectory(ROOT) def check_git_status(): # Recommend 'git pull' if code is out of date + msg = ', for updates see https://github.com/ultralytics/yolov3' print(colorstr('github: '), end='') - try: - assert Path('.git').exists(), 'skipping check (not a git repository)' - assert not is_docker(), 'skipping check (Docker image)' - assert check_online(), 'skipping check (offline)' - - cmd = 'git fetch && git config --get remote.origin.url' - url = subprocess.check_output(cmd, shell=True).decode().strip().rstrip('.git') # github repo url - branch = subprocess.check_output('git rev-parse --abbrev-ref HEAD', shell=True).decode().strip() # checked out - n = int(subprocess.check_output(f'git rev-list {branch}..origin/master --count', shell=True)) # commits behind - if n > 0: - s = f"⚠️ WARNING: code is out of date by {n} commit{'s' * (n > 1)}. " \ - f"Use 'git pull' to update or 'git clone {url}' to download latest." - else: - s = f'up to date with {url} ✅' - print(emojis(s)) # emoji-safe - except Exception as e: - print(e) + assert Path('.git').exists(), 'skipping check (not a git repository)' + msg + assert not is_docker(), 'skipping check (Docker image)' + msg + assert check_online(), 'skipping check (offline)' + msg + + cmd = 'git fetch && git config --get remote.origin.url' + url = check_output(cmd, shell=True, timeout=5).decode().strip().rstrip('.git') # git fetch + branch = check_output('git rev-parse --abbrev-ref HEAD', shell=True).decode().strip() # checked out + n = int(check_output(f'git rev-list {branch}..origin/master --count', shell=True)) # commits behind + if n > 0: + s = f"⚠️ YOLOv3 is out of date by {n} commit{'s' * (n > 1)}. Use `git pull` or `git clone {url}` to update." + else: + s = f'up to date with {url} ✅' + print(emojis(s)) # emoji-safe -def check_python(minimum='3.7.0', required=True): +def check_python(minimum='3.6.2'): # Check current python version vs. required python version - current = platform.python_version() - result = pkg.parse_version(current) >= pkg.parse_version(minimum) - if required: - assert result, f'Python {minimum} required by YOLOv3, but Python {current} is currently installed' - return result + check_version(platform.python_version(), minimum, name='Python ', hard=True) + +def check_version(current='0.0.0', minimum='0.0.0', name='version ', pinned=False, hard=False): + # Check version vs. required version + current, minimum = (pkg.parse_version(x) for x in (current, minimum)) + result = (current == minimum) if pinned else (current >= minimum) # bool + if hard: # assert min requirements met + assert result, f'{name}{minimum} required by YOLOv3, but {name}{current} is currently installed' + else: + return result -def check_requirements(requirements='requirements.txt', exclude=()): + +@try_except +def check_requirements(requirements=ROOT / 'requirements.txt', exclude=(), install=True): # Check installed dependencies meet requirements (pass *.txt file or list of packages) prefix = colorstr('red', 'bold', 'requirements:') check_python() # check python version if isinstance(requirements, (str, Path)): # requirements.txt file file = Path(requirements) - if not file.exists(): - print(f"{prefix} {file.resolve()} not found, check failed.") - return - requirements = [f'{x.name}{x.specifier}' for x in pkg.parse_requirements(file.open()) if x.name not in exclude] + assert file.exists(), f"{prefix} {file.resolve()} not found, check failed." + with file.open() as f: + requirements = [f'{x.name}{x.specifier}' for x in pkg.parse_requirements(f) if x.name not in exclude] else: # list or tuple of packages requirements = [x for x in requirements if x not in exclude] @@ -135,25 +275,33 @@ def check_requirements(requirements='requirements.txt', exclude=()): try: pkg.require(r) except Exception as e: # DistributionNotFound or VersionConflict if requirements not met - n += 1 - print(f"{prefix} {r} not found and is required by YOLOv3, attempting auto-update...") - try: - print(subprocess.check_output(f"pip install '{r}'", shell=True).decode()) - except Exception as e: - print(f'{prefix} {e}') + s = f"{prefix} {r} not found and is required by YOLOv3" + if install: + print(f"{s}, attempting auto-update...") + try: + assert check_online(), f"'pip install {r}' skipped (offline)" + print(check_output(f"pip install '{r}'", shell=True).decode()) + n += 1 + except Exception as e: + print(f'{prefix} {e}') + else: + print(f'{s}. Please install and rerun your command.') if n: # if packages updated source = file.resolve() if 'file' in locals() else requirements s = f"{prefix} {n} package{'s' * (n > 1)} updated per {source}\n" \ f"{prefix} ⚠️ {colorstr('bold', 'Restart runtime or rerun command for updates to take effect')}\n" - print(emojis(s)) # emoji-safe + print(emojis(s)) -def check_img_size(img_size, s=32): - # Verify img_size is a multiple of stride s - new_size = make_divisible(img_size, int(s)) # ceil gs-multiple - if new_size != img_size: - print('WARNING: --img-size %g must be multiple of max stride %g, updating to %g' % (img_size, s, new_size)) +def check_img_size(imgsz, s=32, floor=0): + # Verify image size is a multiple of stride s in each dimension + if isinstance(imgsz, int): # integer i.e. img_size=640 + new_size = max(make_divisible(imgsz, int(s)), floor) + else: # list i.e. img_size=[640, 480] + new_size = [max(make_divisible(x, int(s)), floor) for x in imgsz] + if new_size != imgsz: + print(f'WARNING: --img-size {imgsz} must be multiple of max stride {s}, updating to {new_size}') return new_size @@ -172,53 +320,114 @@ def check_imshow(): return False -def check_file(file): +def check_suffix(file='yolov3.pt', suffix=('.pt',), msg=''): + # Check file(s) for acceptable suffix + if file and suffix: + if isinstance(suffix, str): + suffix = [suffix] + for f in file if isinstance(file, (list, tuple)) else [file]: + s = Path(f).suffix.lower() # file suffix + if len(s): + assert s in suffix, f"{msg}{f} acceptable suffix is {suffix}" + + +def check_yaml(file, suffix=('.yaml', '.yml')): + # Search/download YAML file (if necessary) and return path, checking suffix + return check_file(file, suffix) + + +def check_file(file, suffix=''): # Search/download file (if necessary) and return path + check_suffix(file, suffix) # optional file = str(file) # convert to str() if Path(file).is_file() or file == '': # exists return file - elif file.startswith(('http://', 'https://')): # download - url, file = file, Path(file).name - print(f'Downloading {url} to {file}...') - torch.hub.download_url_to_file(url, file) - assert Path(file).exists() and Path(file).stat().st_size > 0, f'File download failed: {url}' # check + elif file.startswith(('http:/', 'https:/')): # download + url = str(Path(file)).replace(':/', '://') # Pathlib turns :// -> :/ + file = Path(urllib.parse.unquote(file).split('?')[0]).name # '%2F' to '/', split https://url.com/file.txt?auth + if Path(file).is_file(): + print(f'Found {url} locally at {file}') # file already exists + else: + print(f'Downloading {url} to {file}...') + torch.hub.download_url_to_file(url, file) + assert Path(file).exists() and Path(file).stat().st_size > 0, f'File download failed: {url}' # check return file else: # search - files = glob.glob('./**/' + file, recursive=True) # find file + files = [] + for d in 'data', 'models', 'utils': # search directories + files.extend(glob.glob(str(ROOT / d / '**' / file), recursive=True)) # find file assert len(files), f'File not found: {file}' # assert file was found assert len(files) == 1, f"Multiple files match '{file}', specify exact path: {files}" # assert unique return files[0] # return file -def check_dataset(dict): - # Download dataset if not found locally - val, s = dict.get('val'), dict.get('download') - if val and len(val): +def check_dataset(data, autodownload=True): + # Download and/or unzip dataset if not found locally + # Usage: https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128_with_yaml.zip + + # Download (optional) + extract_dir = '' + if isinstance(data, (str, Path)) and str(data).endswith('.zip'): # i.e. gs://bucket/dir/coco128.zip + download(data, dir='../datasets', unzip=True, delete=False, curl=False, threads=1) + data = next((Path('../datasets') / Path(data).stem).rglob('*.yaml')) + extract_dir, autodownload = data.parent, False + + # Read yaml (optional) + if isinstance(data, (str, Path)): + with open(data, errors='ignore') as f: + data = yaml.safe_load(f) # dictionary + + # Parse yaml + path = extract_dir or Path(data.get('path') or '') # optional 'path' default to '.' + for k in 'train', 'val', 'test': + if data.get(k): # prepend path + data[k] = str(path / data[k]) if isinstance(data[k], str) else [str(path / x) for x in data[k]] + + assert 'nc' in data, "Dataset 'nc' key missing." + if 'names' not in data: + data['names'] = [f'class{i}' for i in range(data['nc'])] # assign class names if missing + train, val, test, s = (data.get(x) for x in ('train', 'val', 'test', 'download')) + if val: val = [Path(x).resolve() for x in (val if isinstance(val, list) else [val])] # val path if not all(x.exists() for x in val): print('\nWARNING: Dataset not found, nonexistent paths: %s' % [str(x) for x in val if not x.exists()]) - if s and len(s): # download script + if s and autodownload: # download script + root = path.parent if 'path' in data else '..' # unzip directory i.e. '../' if s.startswith('http') and s.endswith('.zip'): # URL f = Path(s).name # filename - print(f'Downloading {s} ...') + print(f'Downloading {s} to {f}...') torch.hub.download_url_to_file(s, f) - r = os.system(f'unzip -q {f} -d ../ && rm {f}') # unzip + Path(root).mkdir(parents=True, exist_ok=True) # create root + ZipFile(f).extractall(path=root) # unzip + Path(f).unlink() # remove zip + r = None # success elif s.startswith('bash '): # bash script print(f'Running {s} ...') r = os.system(s) else: # python script - r = exec(s) # return None - print('Dataset autodownload %s\n' % ('success' if r in (0, None) else 'failure')) # print result + r = exec(s, {'yaml': data}) # return None + print(f"Dataset autodownload {f'success, saved to {root}' if r in (0, None) else 'failure'}\n") else: raise Exception('Dataset not found.') + return data # dictionary + + +def url2file(url): + # Convert URL to filename, i.e. https://url.com/file.txt?auth -> file.txt + url = str(Path(url)).replace(':/', '://') # Pathlib turns :// -> :/ + file = Path(urllib.parse.unquote(url)).name.split('?')[0] # '%2F' to '/', split https://url.com/file.txt?auth + return file + def download(url, dir='.', unzip=True, delete=True, curl=False, threads=1): - # Multi-threaded file download and unzip function + # Multi-threaded file download and unzip function, used in data.yaml for autodownload def download_one(url, dir): # Download 1 file f = dir / Path(url).name # filename - if not f.exists(): + if Path(url).is_file(): # exists in current path + Path(url).rename(f) # move to dir + elif not f.exists(): print(f'Downloading {url} to {f}...') if curl: os.system(f"curl -L '{url}' -o '{f}' --retry 9 -C -") # curl download, retry and resume on fail @@ -227,12 +436,11 @@ def download_one(url, dir): if unzip and f.suffix in ('.zip', '.gz'): print(f'Unzipping {f}...') if f.suffix == '.zip': - s = f'unzip -qo {f} -d {dir} && rm {f}' # unzip -quiet -overwrite + ZipFile(f).extractall(path=dir) # unzip elif f.suffix == '.gz': - s = f'tar xfz {f} --directory {f.parent}' # unzip - if delete: # delete zip file after unzip - s += f' && rm {f}' - os.system(s) + os.system(f'tar xfz {f} --directory {f.parent}') # unzip + if delete: + f.unlink() # remove zip dir = Path(dir) dir.mkdir(parents=True, exist_ok=True) # make directory @@ -242,7 +450,7 @@ def download_one(url, dir): pool.close() pool.join() else: - for u in tuple(url) if isinstance(url, str) else url: + for u in [url] if isinstance(url, (str, Path)) else url: download_one(u, dir) @@ -257,7 +465,7 @@ def clean_str(s): def one_cycle(y1=0.0, y2=1.0, steps=100): - # lambda function for sinusoidal ramp from y1 to y2 + # lambda function for sinusoidal ramp from y1 to y2 https://arxiv.org/pdf/1812.01187.pdf return lambda x: ((1 - math.cos(x * math.pi / steps)) / 2) * (y2 - y1) + y1 @@ -355,6 +563,18 @@ def xywhn2xyxy(x, w=640, h=640, padw=0, padh=0): return y +def xyxy2xywhn(x, w=640, h=640, clip=False, eps=0.0): + # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] normalized where xy1=top-left, xy2=bottom-right + if clip: + clip_coords(x, (h - eps, w - eps)) # warning: inplace clip + y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) + y[:, 0] = ((x[:, 0] + x[:, 2]) / 2) / w # x center + y[:, 1] = ((x[:, 1] + x[:, 3]) / 2) / h # y center + y[:, 2] = (x[:, 2] - x[:, 0]) / w # width + y[:, 3] = (x[:, 3] - x[:, 1]) / h # height + return y + + def xyn2xy(x, w=640, h=640, padw=0, padh=0): # Convert normalized segments into pixel segments, shape (n,2) y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) @@ -405,90 +625,16 @@ def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None): return coords -def clip_coords(boxes, img_shape): +def clip_coords(boxes, shape): # Clip bounding xyxy bounding boxes to image shape (height, width) - boxes[:, 0].clamp_(0, img_shape[1]) # x1 - boxes[:, 1].clamp_(0, img_shape[0]) # y1 - boxes[:, 2].clamp_(0, img_shape[1]) # x2 - boxes[:, 3].clamp_(0, img_shape[0]) # y2 - - -def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7): - # Returns the IoU of box1 to box2. box1 is 4, box2 is nx4 - box2 = box2.T - - # Get the coordinates of bounding boxes - if x1y1x2y2: # x1, y1, x2, y2 = box1 - b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3] - b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3] - else: # transform from xywh to xyxy - b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2 - b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2 - b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2 - b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2 - - # Intersection area - inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \ - (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0) - - # Union Area - w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps - w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps - union = w1 * h1 + w2 * h2 - inter + eps - - iou = inter / union - if GIoU or DIoU or CIoU: - cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1) # convex (smallest enclosing box) width - ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1) # convex height - if CIoU or DIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1 - c2 = cw ** 2 + ch ** 2 + eps # convex diagonal squared - rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + - (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4 # center distance squared - if DIoU: - return iou - rho2 / c2 # DIoU - elif CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47 - v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2) - with torch.no_grad(): - alpha = v / (v - iou + (1 + eps)) - return iou - (rho2 / c2 + v * alpha) # CIoU - else: # GIoU https://arxiv.org/pdf/1902.09630.pdf - c_area = cw * ch + eps # convex area - return iou - (c_area - union) / c_area # GIoU - else: - return iou # IoU - - -def box_iou(box1, box2): - # https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py - """ - Return intersection-over-union (Jaccard index) of boxes. - Both sets of boxes are expected to be in (x1, y1, x2, y2) format. - Arguments: - box1 (Tensor[N, 4]) - box2 (Tensor[M, 4]) - Returns: - iou (Tensor[N, M]): the NxM matrix containing the pairwise - IoU values for every element in boxes1 and boxes2 - """ - - def box_area(box): - # box = 4xn - return (box[2] - box[0]) * (box[3] - box[1]) - - area1 = box_area(box1.T) - area2 = box_area(box2.T) - - # inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2) - inter = (torch.min(box1[:, None, 2:], box2[:, 2:]) - torch.max(box1[:, None, :2], box2[:, :2])).clamp(0).prod(2) - return inter / (area1[:, None] + area2 - inter) # iou = inter / (area1 + area2 - inter) - - -def wh_iou(wh1, wh2): - # Returns the nxm IoU matrix. wh1 is nx2, wh2 is mx2 - wh1 = wh1[:, None] # [N,1,2] - wh2 = wh2[None] # [1,M,2] - inter = torch.min(wh1, wh2).prod(2) # [N,M] - return inter / (wh1.prod(2) + wh2.prod(2) - inter) # iou = inter / (area1 + area2 - inter) + if isinstance(boxes, torch.Tensor): # faster individually + boxes[:, 0].clamp_(0, shape[1]) # x1 + boxes[:, 1].clamp_(0, shape[0]) # y1 + boxes[:, 2].clamp_(0, shape[1]) # x2 + boxes[:, 3].clamp_(0, shape[0]) # y2 + else: # np.array (faster grouped) + boxes[:, [0, 2]] = boxes[:, [0, 2]].clip(0, shape[1]) # x1, x2 + boxes[:, [1, 3]] = boxes[:, [1, 3]].clip(0, shape[0]) # y1, y2 def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False, multi_label=False, @@ -601,39 +747,48 @@ def strip_optimizer(f='best.pt', s=''): # from utils.general import *; strip_op print(f"Optimizer stripped from {f},{(' saved as %s,' % s) if s else ''} {mb:.1f}MB") -def print_mutation(hyp, results, yaml_file='hyp_evolved.yaml', bucket=''): - # Print mutation results to evolve.txt (for use with train.py --evolve) - a = '%10s' * len(hyp) % tuple(hyp.keys()) # hyperparam keys - b = '%10.3g' * len(hyp) % tuple(hyp.values()) # hyperparam values - c = '%10.4g' * len(results) % results # results (P, R, mAP@0.5, mAP@0.5:0.95, val_losses x 3) - print('\n%s\n%s\nEvolved fitness: %s\n' % (a, b, c)) +def print_mutation(results, hyp, save_dir, bucket): + evolve_csv, results_csv, evolve_yaml = save_dir / 'evolve.csv', save_dir / 'results.csv', save_dir / 'hyp_evolve.yaml' + keys = ('metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', + 'val/box_loss', 'val/obj_loss', 'val/cls_loss') + tuple(hyp.keys()) # [results + hyps] + keys = tuple(x.strip() for x in keys) + vals = results + tuple(hyp.values()) + n = len(keys) + # Download (optional) if bucket: - url = 'gs://%s/evolve.txt' % bucket - if gsutil_getsize(url) > (os.path.getsize('evolve.txt') if os.path.exists('evolve.txt') else 0): - os.system('gsutil cp %s .' % url) # download evolve.txt if larger than local + url = f'gs://{bucket}/evolve.csv' + if gsutil_getsize(url) > (os.path.getsize(evolve_csv) if os.path.exists(evolve_csv) else 0): + os.system(f'gsutil cp {url} {save_dir}') # download evolve.csv if larger than local + + # Log to evolve.csv + s = '' if evolve_csv.exists() else (('%20s,' * n % keys).rstrip(',') + '\n') # add header + with open(evolve_csv, 'a') as f: + f.write(s + ('%20.5g,' * n % vals).rstrip(',') + '\n') - with open('evolve.txt', 'a') as f: # append result - f.write(c + b + '\n') - x = np.unique(np.loadtxt('evolve.txt', ndmin=2), axis=0) # load unique rows - x = x[np.argsort(-fitness(x))] # sort - np.savetxt('evolve.txt', x, '%10.3g') # save sort by fitness + # Print to screen + print(colorstr('evolve: ') + ', '.join(f'{x.strip():>20s}' for x in keys)) + print(colorstr('evolve: ') + ', '.join(f'{x:20.5g}' for x in vals), end='\n\n\n') # Save yaml - for i, k in enumerate(hyp.keys()): - hyp[k] = float(x[0, i + 7]) - with open(yaml_file, 'w') as f: - results = tuple(x[0, :7]) - c = '%10.4g' * len(results) % results # results (P, R, mAP@0.5, mAP@0.5:0.95, val_losses x 3) - f.write('# Hyperparameter Evolution Results\n# Generations: %g\n# Metrics: ' % len(x) + c + '\n\n') + with open(evolve_yaml, 'w') as f: + data = pd.read_csv(evolve_csv) + data = data.rename(columns=lambda x: x.strip()) # strip keys + i = np.argmax(fitness(data.values[:, :7])) # + f.write('# YOLOv3 Hyperparameter Evolution Results\n' + + f'# Best generation: {i}\n' + + f'# Last generation: {len(data)}\n' + + '# ' + ', '.join(f'{x.strip():>20s}' for x in keys[:7]) + '\n' + + '# ' + ', '.join(f'{x:>20.5g}' for x in data.values[i, :7]) + '\n\n') yaml.safe_dump(hyp, f, sort_keys=False) if bucket: - os.system('gsutil cp evolve.txt %s gs://%s' % (yaml_file, bucket)) # upload + os.system(f'gsutil cp {evolve_csv} {evolve_yaml} gs://{bucket}') # upload def apply_classifier(x, model, img, im0): - # Apply a second stage classifier to yolo outputs + # Apply a second stage classifier to YOLO outputs + # Example model = torchvision.models.__dict__['efficientnet_b0'](pretrained=True).to(device).eval() im0 = [im0] if isinstance(im0, np.ndarray) else im0 for i, d in enumerate(x): # per image if d is not None and len(d): @@ -654,11 +809,11 @@ def apply_classifier(x, model, img, im0): for j, a in enumerate(d): # per item cutout = im0[i][int(a[1]):int(a[3]), int(a[0]):int(a[2])] im = cv2.resize(cutout, (224, 224)) # BGR - # cv2.imwrite('test%i.jpg' % j, cutout) + # cv2.imwrite('example%i.jpg' % j, cutout) im = im[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 im = np.ascontiguousarray(im, dtype=np.float32) # uint8 to float32 - im /= 255.0 # 0 - 255 to 0.0 - 1.0 + im /= 255 # 0 - 255 to 0.0 - 1.0 ims.append(im) pred_cls2 = model(torch.Tensor(ims).to(d.device)).argmax(1) # classifier prediction @@ -667,33 +822,20 @@ def apply_classifier(x, model, img, im0): return x -def save_one_box(xyxy, im, file='image.jpg', gain=1.02, pad=10, square=False, BGR=False, save=True): - # Save image crop as {file} with crop size multiple {gain} and {pad} pixels. Save and/or return crop - xyxy = torch.tensor(xyxy).view(-1, 4) - b = xyxy2xywh(xyxy) # boxes - if square: - b[:, 2:] = b[:, 2:].max(1)[0].unsqueeze(1) # attempt rectangle to square - b[:, 2:] = b[:, 2:] * gain + pad # box wh * gain + pad - xyxy = xywh2xyxy(b).long() - clip_coords(xyxy, im.shape) - crop = im[int(xyxy[0, 1]):int(xyxy[0, 3]), int(xyxy[0, 0]):int(xyxy[0, 2]), ::(1 if BGR else -1)] - if save: - cv2.imwrite(str(increment_path(file, mkdir=True).with_suffix('.jpg')), crop) - return crop - - def increment_path(path, exist_ok=False, sep='', mkdir=False): # Increment file or directory path, i.e. runs/exp --> runs/exp{sep}2, runs/exp{sep}3, ... etc. path = Path(path) # os-agnostic if path.exists() and not exist_ok: - suffix = path.suffix - path = path.with_suffix('') + path, suffix = (path.with_suffix(''), path.suffix) if path.is_file() else (path, '') dirs = glob.glob(f"{path}{sep}*") # similar paths matches = [re.search(rf"%s{sep}(\d+)" % path.stem, d) for d in dirs] i = [int(m.groups()[0]) for m in matches if m] # indices n = max(i) + 1 if i else 2 # increment number - path = Path(f"{path}{sep}{n}{suffix}") # update path - dir = path if path.suffix == '' else path.parent # directory - if not dir.exists() and mkdir: - dir.mkdir(parents=True, exist_ok=True) # make directory + path = Path(f"{path}{sep}{n}{suffix}") # increment path + if mkdir: + path.mkdir(parents=True, exist_ok=True) # make directory return path + + +# Variables +NCOLS = 0 if is_docker() else shutil.get_terminal_size().columns # terminal window size diff --git a/utils/google_app_engine/Dockerfile b/utils/google_app_engine/Dockerfile deleted file mode 100644 index 0155618f47..0000000000 --- a/utils/google_app_engine/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM gcr.io/google-appengine/python - -# Create a virtualenv for dependencies. This isolates these packages from -# system-level packages. -# Use -p python3 or -p python3.7 to select python version. Default is version 2. -RUN virtualenv /env -p python3 - -# Setting these environment variables are the same as running -# source /env/bin/activate. -ENV VIRTUAL_ENV /env -ENV PATH /env/bin:$PATH - -RUN apt-get update && apt-get install -y python-opencv - -# Copy the application's requirements.txt and run pip to install all -# dependencies into the virtualenv. -ADD requirements.txt /app/requirements.txt -RUN pip install -r /app/requirements.txt - -# Add the application source code. -ADD . /app - -# Run a WSGI server to serve the application. gunicorn must be declared as -# a dependency in requirements.txt. -CMD gunicorn -b :$PORT main:app diff --git a/utils/google_app_engine/additional_requirements.txt b/utils/google_app_engine/additional_requirements.txt deleted file mode 100644 index 2f81c8b400..0000000000 --- a/utils/google_app_engine/additional_requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -# add these requirements in your app on top of the existing ones -pip==19.2 -Flask==1.0.2 -gunicorn==19.9.0 diff --git a/utils/google_app_engine/app.yaml b/utils/google_app_engine/app.yaml deleted file mode 100644 index bd162e44dd..0000000000 --- a/utils/google_app_engine/app.yaml +++ /dev/null @@ -1,14 +0,0 @@ -runtime: custom -env: flex - -service: yolov3app - -liveness_check: - initial_delay_sec: 600 - -manual_scaling: - instances: 1 -resources: - cpu: 1 - memory_gb: 4 - disk_size_gb: 20 \ No newline at end of file diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py new file mode 100644 index 0000000000..bf55fec860 --- /dev/null +++ b/utils/loggers/__init__.py @@ -0,0 +1,156 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Logging utils +""" + +import os +import warnings +from threading import Thread + +import pkg_resources as pkg +import torch +from torch.utils.tensorboard import SummaryWriter + +from utils.general import colorstr, emojis +from utils.loggers.wandb.wandb_utils import WandbLogger +from utils.plots import plot_images, plot_results +from utils.torch_utils import de_parallel + +LOGGERS = ('csv', 'tb', 'wandb') # text-file, TensorBoard, Weights & Biases +RANK = int(os.getenv('RANK', -1)) + +try: + import wandb + + assert hasattr(wandb, '__version__') # verify package import not local dir + if pkg.parse_version(wandb.__version__) >= pkg.parse_version('0.12.2') and RANK in [0, -1]: + wandb_login_success = wandb.login(timeout=30) + if not wandb_login_success: + wandb = None +except (ImportError, AssertionError): + wandb = None + + +class Loggers(): + # Loggers class + def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, include=LOGGERS): + self.save_dir = save_dir + self.weights = weights + self.opt = opt + self.hyp = hyp + self.logger = logger # for printing results to console + self.include = include + self.keys = ['train/box_loss', 'train/obj_loss', 'train/cls_loss', # train loss + 'metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', # metrics + 'val/box_loss', 'val/obj_loss', 'val/cls_loss', # val loss + 'x/lr0', 'x/lr1', 'x/lr2'] # params + for k in LOGGERS: + setattr(self, k, None) # init empty logger dictionary + self.csv = True # always log to csv + + # Message + if not wandb: + prefix = colorstr('Weights & Biases: ') + s = f"{prefix}run 'pip install wandb' to automatically track and visualize YOLOv3 🚀 runs (RECOMMENDED)" + print(emojis(s)) + + # TensorBoard + s = self.save_dir + if 'tb' in self.include and not self.opt.evolve: + prefix = colorstr('TensorBoard: ') + self.logger.info(f"{prefix}Start with 'tensorboard --logdir {s.parent}', view at http://localhost:6006/") + self.tb = SummaryWriter(str(s)) + + # W&B + if wandb and 'wandb' in self.include: + wandb_artifact_resume = isinstance(self.opt.resume, str) and self.opt.resume.startswith('wandb-artifact://') + run_id = torch.load(self.weights).get('wandb_id') if self.opt.resume and not wandb_artifact_resume else None + self.opt.hyp = self.hyp # add hyperparameters + self.wandb = WandbLogger(self.opt, run_id) + else: + self.wandb = None + + def on_pretrain_routine_end(self): + # Callback runs on pre-train routine end + paths = self.save_dir.glob('*labels*.jpg') # training labels + if self.wandb: + self.wandb.log({"Labels": [wandb.Image(str(x), caption=x.name) for x in paths]}) + + def on_train_batch_end(self, ni, model, imgs, targets, paths, plots, sync_bn): + # Callback runs on train batch end + if plots: + if ni == 0: + if not sync_bn: # tb.add_graph() --sync known issue https://github.com/ultralytics/yolov5/issues/3754 + with warnings.catch_warnings(): + warnings.simplefilter('ignore') # suppress jit trace warning + self.tb.add_graph(torch.jit.trace(de_parallel(model), imgs[0:1], strict=False), []) + if ni < 3: + f = self.save_dir / f'train_batch{ni}.jpg' # filename + Thread(target=plot_images, args=(imgs, targets, paths, f), daemon=True).start() + if self.wandb and ni == 10: + files = sorted(self.save_dir.glob('train*.jpg')) + self.wandb.log({'Mosaics': [wandb.Image(str(f), caption=f.name) for f in files if f.exists()]}) + + def on_train_epoch_end(self, epoch): + # Callback runs on train epoch end + if self.wandb: + self.wandb.current_epoch = epoch + 1 + + def on_val_image_end(self, pred, predn, path, names, im): + # Callback runs on val image end + if self.wandb: + self.wandb.val_one_image(pred, predn, path, names, im) + + def on_val_end(self): + # Callback runs on val end + if self.wandb: + files = sorted(self.save_dir.glob('val*.jpg')) + self.wandb.log({"Validation": [wandb.Image(str(f), caption=f.name) for f in files]}) + + def on_fit_epoch_end(self, vals, epoch, best_fitness, fi): + # Callback runs at the end of each fit (train+val) epoch + x = {k: v for k, v in zip(self.keys, vals)} # dict + if self.csv: + file = self.save_dir / 'results.csv' + n = len(x) + 1 # number of cols + s = '' if file.exists() else (('%20s,' * n % tuple(['epoch'] + self.keys)).rstrip(',') + '\n') # add header + with open(file, 'a') as f: + f.write(s + ('%20.5g,' * n % tuple([epoch] + vals)).rstrip(',') + '\n') + + if self.tb: + for k, v in x.items(): + self.tb.add_scalar(k, v, epoch) + + if self.wandb: + self.wandb.log(x) + self.wandb.end_epoch(best_result=best_fitness == fi) + + def on_model_save(self, last, epoch, final_epoch, best_fitness, fi): + # Callback runs on model save event + if self.wandb: + if ((epoch + 1) % self.opt.save_period == 0 and not final_epoch) and self.opt.save_period != -1: + self.wandb.log_model(last.parent, self.opt, epoch, fi, best_model=best_fitness == fi) + + def on_train_end(self, last, best, plots, epoch, results): + # Callback runs on training end + if plots: + plot_results(file=self.save_dir / 'results.csv') # save results.png + files = ['results.png', 'confusion_matrix.png', *(f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R'))] + files = [(self.save_dir / f) for f in files if (self.save_dir / f).exists()] # filter + + if self.tb: + import cv2 + for f in files: + self.tb.add_image(f.stem, cv2.imread(str(f))[..., ::-1], epoch, dataformats='HWC') + + if self.wandb: + self.wandb.log({"Results": [wandb.Image(str(f), caption=f.name) for f in files]}) + # Calling wandb.log. TODO: Refactor this into WandbLogger.log_model + if not self.opt.evolve: + wandb.log_artifact(str(best if best.exists() else last), type='model', + name='run_' + self.wandb.wandb_run.id + '_model', + aliases=['latest', 'best', 'stripped']) + self.wandb.finish_run() + else: + self.wandb.finish_run() + self.wandb = WandbLogger(self.opt) diff --git a/utils/loggers/wandb/README.md b/utils/loggers/wandb/README.md new file mode 100644 index 0000000000..bae57bdabf --- /dev/null +++ b/utils/loggers/wandb/README.md @@ -0,0 +1,147 @@ +📚 This guide explains how to use **Weights & Biases** (W&B) with YOLOv3 🚀. UPDATED 29 September 2021. +* [About Weights & Biases](#about-weights-&-biases) +* [First-Time Setup](#first-time-setup) +* [Viewing runs](#viewing-runs) +* [Advanced Usage: Dataset Versioning and Evaluation](#advanced-usage) +* [Reports: Share your work with the world!](#reports) + +## About Weights & Biases +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. + +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: + + * [Debug](https://wandb.ai/wandb/getting-started/reports/Visualize-Debug-Machine-Learning-Models--VmlldzoyNzY5MDk#Free-2) model performance in real time + * [GPU usage](https://wandb.ai/wandb/getting-started/reports/Visualize-Debug-Machine-Learning-Models--VmlldzoyNzY5MDk#System-4) visualized automatically + * [Custom charts](https://wandb.ai/wandb/customizable-charts/reports/Powerful-Custom-Charts-To-Debug-Model-Peformance--VmlldzoyNzY4ODI) for powerful, extensible visualization + * [Share insights](https://wandb.ai/wandb/getting-started/reports/Visualize-Debug-Machine-Learning-Models--VmlldzoyNzY5MDk#Share-8) interactively with collaborators + * [Optimize hyperparameters](https://docs.wandb.com/sweeps) efficiently + * [Track](https://docs.wandb.com/artifacts) datasets, pipelines, and production models + +## First-Time Setup +
+ Toggle Details +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. + +W&B will create a cloud **project** (default is 'YOLOv3') 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: + + ```shell + $ python train.py --project ... --name ... + ``` + +YOLOv3 notebook example: Open In Colab Open In Kaggle +Screen Shot 2021-09-29 at 10 23 13 PM + + +
+ +## Viewing Runs +
+ Toggle Details +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: + + * Training & Validation losses + * Metrics: Precision, Recall, mAP@0.5, mAP@0.5:0.95 + * Learning Rate over time + * A bounding box debugging panel, showing the training progress over time + * GPU: Type, **GPU Utilization**, power, temperature, **CUDA memory usage** + * System: Disk I/0, CPU utilization, RAM memory usage + * Your trained model as W&B Artifact + * Environment: OS and Python types, Git repository and state, **training command** + +

Weights & Biases dashboard

+ + +
+ +## Advanced Usage +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. +
+

1. Visualize and Version Datasets

+ 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. +
+ Usage + Code $ python utils/logger/wandb/log_dataset.py --project ... --name ... --data .. + + ![Screenshot (64)](https://user-images.githubusercontent.com/15766192/128486078-d8433890-98a3-4d12-8986-b6c0e3fc64b9.png) +
+ +

2: Train and Log Evaluation simultaneousy

+ This is an extension of the previous section, but it'll also training after uploading the dataset. This also evaluation Table + Evaluation table compares your predictions and ground truths across the validation set for each epoch. It uses the references to the already uploaded datasets, + so no images will be uploaded from your system more than once. +
+ Usage + Code $ python utils/logger/wandb/log_dataset.py --data .. --upload_data + +![Screenshot (72)](https://user-images.githubusercontent.com/15766192/128979739-4cf63aeb-a76f-483f-8861-1c0100b938a5.png) +
+ +

3: Train using dataset artifact

+ 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 + can be used to train a model directly from the dataset artifact. This also logs evaluation +
+ Usage + Code $ python utils/logger/wandb/log_dataset.py --data {data}_wandb.yaml + +![Screenshot (72)](https://user-images.githubusercontent.com/15766192/128979739-4cf63aeb-a76f-483f-8861-1c0100b938a5.png) +
+ +

4: Save model checkpoints as artifacts

+ To enable saving and versioning checkpoints of your experiment, pass `--save_period n` with the base cammand, where `n` represents checkpoint interval. + You can also log both the dataset and model checkpoints simultaneously. If not passed, only the final model will be logged + +
+ Usage + Code $ python train.py --save_period 1 + +![Screenshot (68)](https://user-images.githubusercontent.com/15766192/128726138-ec6c1f60-639d-437d-b4ee-3acd9de47ef3.png) +
+ +
+ +

5: Resume runs from checkpoint artifacts.

+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. + +
+ Usage + Code $ python train.py --resume wandb-artifact://{run_path} + +![Screenshot (70)](https://user-images.githubusercontent.com/15766192/128728988-4e84b355-6c87-41ae-a591-14aecf45343e.png) +
+ +

6: Resume runs from dataset artifact & checkpoint artifacts.

+ Local dataset or model checkpoints are not required. This can be used to resume runs directly on a different device + 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 + train from _wandb.yaml file and set --save_period + +
+ Usage + Code $ python train.py --resume wandb-artifact://{run_path} + +![Screenshot (70)](https://user-images.githubusercontent.com/15766192/128728988-4e84b355-6c87-41ae-a591-14aecf45343e.png) +
+ +
+ + +

Reports

+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 YOLOv5 models ([link](https://wandb.ai/glenn-jocher/yolov5_tutorial/reports/YOLOv5-COCO128-Tutorial-Results--VmlldzozMDI5OTY)). + +Weights & Biases Reports + + +## Environments + +YOLOv3 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): + +- **Google Colab and Kaggle** notebooks with free GPU: Open In Colab Open In Kaggle +- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) +- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/AWS-Quickstart) +- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) Docker Pulls + + +## Status + +![CI CPU testing](https://github.com/ultralytics/yolov3/workflows/CI%20CPU%20testing/badge.svg) + +If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 training ([train.py](https://github.com/ultralytics/yolov3/blob/master/train.py)), validation ([val.py](https://github.com/ultralytics/yolov3/blob/master/val.py)), inference ([detect.py](https://github.com/ultralytics/yolov3/blob/master/detect.py)) and export ([export.py](https://github.com/ultralytics/yolov3/blob/master/export.py)) on MacOS, Windows, and Ubuntu every 24 hours and on every commit. diff --git a/utils/aws/__init__.py b/utils/loggers/wandb/__init__.py similarity index 100% rename from utils/aws/__init__.py rename to utils/loggers/wandb/__init__.py diff --git a/utils/wandb_logging/log_dataset.py b/utils/loggers/wandb/log_dataset.py similarity index 61% rename from utils/wandb_logging/log_dataset.py rename to utils/loggers/wandb/log_dataset.py index fae76b048f..d3c77430ff 100644 --- a/utils/wandb_logging/log_dataset.py +++ b/utils/loggers/wandb/log_dataset.py @@ -1,16 +1,16 @@ import argparse -import yaml - from wandb_utils import WandbLogger +from utils.general import LOGGER + WANDB_ARTIFACT_PREFIX = 'wandb-artifact://' def create_dataset_artifact(opt): - with open(opt.data) as f: - data = yaml.safe_load(f) # data dict - logger = WandbLogger(opt, '', None, data, job_type='Dataset Creation') + logger = WandbLogger(opt, None, job_type='Dataset Creation') # TODO: return value unused + if not logger.wandb: + LOGGER.info("install wandb using `pip install wandb` to log the dataset") if __name__ == '__main__': @@ -18,6 +18,9 @@ def create_dataset_artifact(opt): parser.add_argument('--data', type=str, default='data/coco128.yaml', help='data.yaml path') parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') parser.add_argument('--project', type=str, default='YOLOv3', help='name of W&B Project') + parser.add_argument('--entity', default=None, help='W&B entity') + parser.add_argument('--name', type=str, default='log dataset', help='name of W&B run') + opt = parser.parse_args() opt.resume = False # Explicitly disallow resume check for dataset upload job diff --git a/utils/loggers/wandb/sweep.py b/utils/loggers/wandb/sweep.py new file mode 100644 index 0000000000..5e24f96e13 --- /dev/null +++ b/utils/loggers/wandb/sweep.py @@ -0,0 +1,41 @@ +import sys +from pathlib import Path + +import wandb + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[3] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH + +from train import parse_opt, train +from utils.callbacks import Callbacks +from utils.general import increment_path +from utils.torch_utils import select_device + + +def sweep(): + wandb.init() + # Get hyp dict from sweep agent + hyp_dict = vars(wandb.config).get("_items") + + # Workaround: get necessary opt args + opt = parse_opt(known=True) + opt.batch_size = hyp_dict.get("batch_size") + opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok or opt.evolve)) + opt.epochs = hyp_dict.get("epochs") + opt.nosave = True + opt.data = hyp_dict.get("data") + opt.weights = str(opt.weights) + opt.cfg = str(opt.cfg) + opt.data = str(opt.data) + opt.hyp = str(opt.hyp) + opt.project = str(opt.project) + device = select_device(opt.device, batch_size=opt.batch_size) + + # train + train(hyp_dict, opt, device, callbacks=Callbacks()) + + +if __name__ == "__main__": + sweep() diff --git a/utils/loggers/wandb/sweep.yaml b/utils/loggers/wandb/sweep.yaml new file mode 100644 index 0000000000..c7790d75f6 --- /dev/null +++ b/utils/loggers/wandb/sweep.yaml @@ -0,0 +1,143 @@ +# Hyperparameters for training +# To set range- +# Provide min and max values as: +# parameter: +# +# min: scalar +# max: scalar +# OR +# +# Set a specific list of search space- +# parameter: +# values: [scalar1, scalar2, scalar3...] +# +# You can use grid, bayesian and hyperopt search strategy +# For more info on configuring sweeps visit - https://docs.wandb.ai/guides/sweeps/configuration + +program: utils/loggers/wandb/sweep.py +method: random +metric: + name: metrics/mAP_0.5 + goal: maximize + +parameters: + # hyperparameters: set either min, max range or values list + data: + value: "data/coco128.yaml" + batch_size: + values: [64] + epochs: + values: [10] + + lr0: + distribution: uniform + min: 1e-5 + max: 1e-1 + lrf: + distribution: uniform + min: 0.01 + max: 1.0 + momentum: + distribution: uniform + min: 0.6 + max: 0.98 + weight_decay: + distribution: uniform + min: 0.0 + max: 0.001 + warmup_epochs: + distribution: uniform + min: 0.0 + max: 5.0 + warmup_momentum: + distribution: uniform + min: 0.0 + max: 0.95 + warmup_bias_lr: + distribution: uniform + min: 0.0 + max: 0.2 + box: + distribution: uniform + min: 0.02 + max: 0.2 + cls: + distribution: uniform + min: 0.2 + max: 4.0 + cls_pw: + distribution: uniform + min: 0.5 + max: 2.0 + obj: + distribution: uniform + min: 0.2 + max: 4.0 + obj_pw: + distribution: uniform + min: 0.5 + max: 2.0 + iou_t: + distribution: uniform + min: 0.1 + max: 0.7 + anchor_t: + distribution: uniform + min: 2.0 + max: 8.0 + fl_gamma: + distribution: uniform + min: 0.0 + max: 0.1 + hsv_h: + distribution: uniform + min: 0.0 + max: 0.1 + hsv_s: + distribution: uniform + min: 0.0 + max: 0.9 + hsv_v: + distribution: uniform + min: 0.0 + max: 0.9 + degrees: + distribution: uniform + min: 0.0 + max: 45.0 + translate: + distribution: uniform + min: 0.0 + max: 0.9 + scale: + distribution: uniform + min: 0.0 + max: 0.9 + shear: + distribution: uniform + min: 0.0 + max: 10.0 + perspective: + distribution: uniform + min: 0.0 + max: 0.001 + flipud: + distribution: uniform + min: 0.0 + max: 1.0 + fliplr: + distribution: uniform + min: 0.0 + max: 1.0 + mosaic: + distribution: uniform + min: 0.0 + max: 1.0 + mixup: + distribution: uniform + min: 0.0 + max: 1.0 + copy_paste: + distribution: uniform + min: 0.0 + max: 1.0 diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py new file mode 100644 index 0000000000..7087e4e95e --- /dev/null +++ b/utils/loggers/wandb/wandb_utils.py @@ -0,0 +1,532 @@ +"""Utilities and tools for tracking runs with Weights & Biases.""" + +import logging +import os +import sys +from contextlib import contextmanager +from pathlib import Path +from typing import Dict + +import pkg_resources as pkg +import yaml +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[3] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH + +from utils.datasets import LoadImagesAndLabels, img2label_paths +from utils.general import LOGGER, check_dataset, check_file + +try: + import wandb + + assert hasattr(wandb, '__version__') # verify package import not local dir +except (ImportError, AssertionError): + wandb = None + +RANK = int(os.getenv('RANK', -1)) +WANDB_ARTIFACT_PREFIX = 'wandb-artifact://' + + +def remove_prefix(from_string, prefix=WANDB_ARTIFACT_PREFIX): + return from_string[len(prefix):] + + +def check_wandb_config_file(data_config_file): + wandb_config = '_wandb.'.join(data_config_file.rsplit('.', 1)) # updated data.yaml path + if Path(wandb_config).is_file(): + return wandb_config + return data_config_file + + +def check_wandb_dataset(data_file): + is_trainset_wandb_artifact = False + is_valset_wandb_artifact = False + if check_file(data_file) and data_file.endswith('.yaml'): + with open(data_file, errors='ignore') as f: + data_dict = yaml.safe_load(f) + is_trainset_wandb_artifact = (isinstance(data_dict['train'], str) and + data_dict['train'].startswith(WANDB_ARTIFACT_PREFIX)) + is_valset_wandb_artifact = (isinstance(data_dict['val'], str) and + data_dict['val'].startswith(WANDB_ARTIFACT_PREFIX)) + if is_trainset_wandb_artifact or is_valset_wandb_artifact: + return data_dict + else: + return check_dataset(data_file) + + +def get_run_info(run_path): + run_path = Path(remove_prefix(run_path, WANDB_ARTIFACT_PREFIX)) + run_id = run_path.stem + project = run_path.parent.stem + entity = run_path.parent.parent.stem + model_artifact_name = 'run_' + run_id + '_model' + return entity, project, run_id, model_artifact_name + + +def check_wandb_resume(opt): + process_wandb_config_ddp_mode(opt) if RANK not in [-1, 0] else None + if isinstance(opt.resume, str): + if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): + if RANK not in [-1, 0]: # For resuming DDP runs + entity, project, run_id, model_artifact_name = get_run_info(opt.resume) + api = wandb.Api() + artifact = api.artifact(entity + '/' + project + '/' + model_artifact_name + ':latest') + modeldir = artifact.download() + opt.weights = str(Path(modeldir) / "last.pt") + return True + return None + + +def process_wandb_config_ddp_mode(opt): + with open(check_file(opt.data), errors='ignore') as f: + data_dict = yaml.safe_load(f) # data dict + train_dir, val_dir = None, None + if isinstance(data_dict['train'], str) and data_dict['train'].startswith(WANDB_ARTIFACT_PREFIX): + api = wandb.Api() + train_artifact = api.artifact(remove_prefix(data_dict['train']) + ':' + opt.artifact_alias) + train_dir = train_artifact.download() + train_path = Path(train_dir) / 'data/images/' + data_dict['train'] = str(train_path) + + if isinstance(data_dict['val'], str) and data_dict['val'].startswith(WANDB_ARTIFACT_PREFIX): + api = wandb.Api() + val_artifact = api.artifact(remove_prefix(data_dict['val']) + ':' + opt.artifact_alias) + val_dir = val_artifact.download() + val_path = Path(val_dir) / 'data/images/' + data_dict['val'] = str(val_path) + if train_dir or val_dir: + ddp_data_path = str(Path(val_dir) / 'wandb_local_data.yaml') + with open(ddp_data_path, 'w') as f: + yaml.safe_dump(data_dict, f) + opt.data = ddp_data_path + + +class WandbLogger(): + """Log training runs, datasets, models, and predictions to Weights & Biases. + + This logger sends information to W&B at wandb.ai. By default, this information + includes hyperparameters, system configuration and metrics, model metrics, + and basic data metrics and analyses. + + By providing additional command line arguments to train.py, datasets, + models and predictions can also be logged. + + For more on how this logger is used, see the Weights & Biases documentation: + https://docs.wandb.com/guides/integrations/yolov5 + """ + + def __init__(self, opt, run_id=None, job_type='Training'): + """ + - Initialize WandbLogger instance + - Upload dataset if opt.upload_dataset is True + - Setup trainig processes if job_type is 'Training' + + arguments: + opt (namespace) -- Commandline arguments for this run + run_id (str) -- Run ID of W&B run to be resumed + job_type (str) -- To set the job_type for this run + + """ + # Pre-training routine -- + self.job_type = job_type + self.wandb, self.wandb_run = wandb, None if not wandb else wandb.run + self.val_artifact, self.train_artifact = None, None + self.train_artifact_path, self.val_artifact_path = None, None + self.result_artifact = None + self.val_table, self.result_table = None, None + self.bbox_media_panel_images = [] + self.val_table_path_map = None + self.max_imgs_to_log = 16 + self.wandb_artifact_data_dict = None + self.data_dict = None + # It's more elegant to stick to 1 wandb.init call, + # but useful config data is overwritten in the WandbLogger's wandb.init call + if isinstance(opt.resume, str): # checks resume from artifact + if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): + entity, project, run_id, model_artifact_name = get_run_info(opt.resume) + model_artifact_name = WANDB_ARTIFACT_PREFIX + model_artifact_name + assert wandb, 'install wandb to resume wandb runs' + # Resume wandb-artifact:// runs here| workaround for not overwriting wandb.config + self.wandb_run = wandb.init(id=run_id, + project=project, + entity=entity, + resume='allow', + allow_val_change=True) + opt.resume = model_artifact_name + elif self.wandb: + self.wandb_run = wandb.init(config=opt, + resume="allow", + project='YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem, + entity=opt.entity, + name=opt.name if opt.name != 'exp' else None, + job_type=job_type, + id=run_id, + allow_val_change=True) if not wandb.run else wandb.run + if self.wandb_run: + if self.job_type == 'Training': + if opt.upload_dataset: + if not opt.resume: + self.wandb_artifact_data_dict = self.check_and_upload_dataset(opt) + + if opt.resume: + # resume from artifact + if isinstance(opt.resume, str) and opt.resume.startswith(WANDB_ARTIFACT_PREFIX): + self.data_dict = dict(self.wandb_run.config.data_dict) + else: # local resume + self.data_dict = check_wandb_dataset(opt.data) + else: + self.data_dict = check_wandb_dataset(opt.data) + self.wandb_artifact_data_dict = self.wandb_artifact_data_dict or self.data_dict + + # write data_dict to config. useful for resuming from artifacts. Do this only when not resuming. + self.wandb_run.config.update({'data_dict': self.wandb_artifact_data_dict}, + allow_val_change=True) + self.setup_training(opt) + + if self.job_type == 'Dataset Creation': + self.data_dict = self.check_and_upload_dataset(opt) + + def check_and_upload_dataset(self, opt): + """ + Check if the dataset format is compatible and upload it as W&B artifact + + arguments: + opt (namespace)-- Commandline arguments for current run + + returns: + Updated dataset info dictionary where local dataset paths are replaced by WAND_ARFACT_PREFIX links. + """ + assert wandb, 'Install wandb to upload dataset' + config_path = self.log_dataset_artifact(opt.data, + opt.single_cls, + 'YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem) + LOGGER.info(f"Created dataset config file {config_path}") + with open(config_path, errors='ignore') as f: + wandb_data_dict = yaml.safe_load(f) + return wandb_data_dict + + def setup_training(self, opt): + """ + Setup the necessary processes for training YOLO models: + - Attempt to download model checkpoint and dataset artifacts if opt.resume stats with WANDB_ARTIFACT_PREFIX + - Update data_dict, to contain info of previous run if resumed and the paths of dataset artifact if downloaded + - Setup log_dict, initialize bbox_interval + + arguments: + opt (namespace) -- commandline arguments for this run + + """ + self.log_dict, self.current_epoch = {}, 0 + self.bbox_interval = opt.bbox_interval + if isinstance(opt.resume, str): + modeldir, _ = self.download_model_artifact(opt) + if modeldir: + self.weights = Path(modeldir) / "last.pt" + config = self.wandb_run.config + opt.weights, opt.save_period, opt.batch_size, opt.bbox_interval, opt.epochs, opt.hyp = str( + self.weights), config.save_period, config.batch_size, config.bbox_interval, config.epochs, \ + config.hyp + data_dict = self.data_dict + if self.val_artifact is None: # If --upload_dataset is set, use the existing artifact, don't download + self.train_artifact_path, self.train_artifact = self.download_dataset_artifact(data_dict.get('train'), + opt.artifact_alias) + self.val_artifact_path, self.val_artifact = self.download_dataset_artifact(data_dict.get('val'), + opt.artifact_alias) + + if self.train_artifact_path is not None: + train_path = Path(self.train_artifact_path) / 'data/images/' + data_dict['train'] = str(train_path) + if self.val_artifact_path is not None: + val_path = Path(self.val_artifact_path) / 'data/images/' + data_dict['val'] = str(val_path) + + if self.val_artifact is not None: + self.result_artifact = wandb.Artifact("run_" + wandb.run.id + "_progress", "evaluation") + self.result_table = wandb.Table(["epoch", "id", "ground truth", "prediction", "avg_confidence"]) + self.val_table = self.val_artifact.get("val") + if self.val_table_path_map is None: + self.map_val_table_path() + if opt.bbox_interval == -1: + self.bbox_interval = opt.bbox_interval = (opt.epochs // 10) if opt.epochs > 10 else 1 + train_from_artifact = self.train_artifact_path is not None and self.val_artifact_path is not None + # Update the the data_dict to point to local artifacts dir + if train_from_artifact: + self.data_dict = data_dict + + def download_dataset_artifact(self, path, alias): + """ + download the model checkpoint artifact if the path starts with WANDB_ARTIFACT_PREFIX + + arguments: + path -- path of the dataset to be used for training + alias (str)-- alias of the artifact to be download/used for training + + returns: + (str, wandb.Artifact) -- path of the downladed dataset and it's corresponding artifact object if dataset + is found otherwise returns (None, None) + """ + if isinstance(path, str) and path.startswith(WANDB_ARTIFACT_PREFIX): + artifact_path = Path(remove_prefix(path, WANDB_ARTIFACT_PREFIX) + ":" + alias) + dataset_artifact = wandb.use_artifact(artifact_path.as_posix().replace("\\", "/")) + assert dataset_artifact is not None, "'Error: W&B dataset artifact doesn\'t exist'" + datadir = dataset_artifact.download() + return datadir, dataset_artifact + return None, None + + def download_model_artifact(self, opt): + """ + download the model checkpoint artifact if the resume path starts with WANDB_ARTIFACT_PREFIX + + arguments: + opt (namespace) -- Commandline arguments for this run + """ + if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): + model_artifact = wandb.use_artifact(remove_prefix(opt.resume, WANDB_ARTIFACT_PREFIX) + ":latest") + assert model_artifact is not None, 'Error: W&B model artifact doesn\'t exist' + modeldir = model_artifact.download() + epochs_trained = model_artifact.metadata.get('epochs_trained') + total_epochs = model_artifact.metadata.get('total_epochs') + is_finished = total_epochs is None + assert not is_finished, 'training is finished, can only resume incomplete runs.' + return modeldir, model_artifact + return None, None + + def log_model(self, path, opt, epoch, fitness_score, best_model=False): + """ + Log the model checkpoint as W&B artifact + + arguments: + path (Path) -- Path of directory containing the checkpoints + opt (namespace) -- Command line arguments for this run + epoch (int) -- Current epoch number + fitness_score (float) -- fitness score for current epoch + best_model (boolean) -- Boolean representing if the current checkpoint is the best yet. + """ + model_artifact = wandb.Artifact('run_' + wandb.run.id + '_model', type='model', metadata={ + 'original_url': str(path), + 'epochs_trained': epoch + 1, + 'save period': opt.save_period, + 'project': opt.project, + 'total_epochs': opt.epochs, + 'fitness_score': fitness_score + }) + model_artifact.add_file(str(path / 'last.pt'), name='last.pt') + wandb.log_artifact(model_artifact, + aliases=['latest', 'last', 'epoch ' + str(self.current_epoch), 'best' if best_model else '']) + LOGGER.info(f"Saving model artifact on epoch {epoch + 1}") + + def log_dataset_artifact(self, data_file, single_cls, project, overwrite_config=False): + """ + Log the dataset as W&B artifact and return the new data file with W&B links + + arguments: + data_file (str) -- the .yaml file with information about the dataset like - path, classes etc. + single_class (boolean) -- train multi-class data as single-class + project (str) -- project name. Used to construct the artifact path + overwrite_config (boolean) -- overwrites the data.yaml file if set to true otherwise creates a new + file with _wandb postfix. Eg -> data_wandb.yaml + + returns: + the new .yaml file with artifact links. it can be used to start training directly from artifacts + """ + self.data_dict = check_dataset(data_file) # parse and check + data = dict(self.data_dict) + nc, names = (1, ['item']) if single_cls else (int(data['nc']), data['names']) + names = {k: v for k, v in enumerate(names)} # to index dictionary + self.train_artifact = self.create_dataset_table(LoadImagesAndLabels( + data['train'], rect=True, batch_size=1), names, name='train') if data.get('train') else None + self.val_artifact = self.create_dataset_table(LoadImagesAndLabels( + data['val'], rect=True, batch_size=1), names, name='val') if data.get('val') else None + if data.get('train'): + data['train'] = WANDB_ARTIFACT_PREFIX + str(Path(project) / 'train') + if data.get('val'): + data['val'] = WANDB_ARTIFACT_PREFIX + str(Path(project) / 'val') + path = Path(data_file).stem + path = (path if overwrite_config else path + '_wandb') + '.yaml' # updated data.yaml path + data.pop('download', None) + data.pop('path', None) + with open(path, 'w') as f: + yaml.safe_dump(data, f) + + if self.job_type == 'Training': # builds correct artifact pipeline graph + self.wandb_run.use_artifact(self.val_artifact) + self.wandb_run.use_artifact(self.train_artifact) + self.val_artifact.wait() + self.val_table = self.val_artifact.get('val') + self.map_val_table_path() + else: + self.wandb_run.log_artifact(self.train_artifact) + self.wandb_run.log_artifact(self.val_artifact) + return path + + def map_val_table_path(self): + """ + Map the validation dataset Table like name of file -> it's id in the W&B Table. + Useful for - referencing artifacts for evaluation. + """ + self.val_table_path_map = {} + LOGGER.info("Mapping dataset") + for i, data in enumerate(tqdm(self.val_table.data)): + self.val_table_path_map[data[3]] = data[0] + + def create_dataset_table(self, dataset: LoadImagesAndLabels, class_to_id: Dict[int,str], name: str = 'dataset'): + """ + Create and return W&B artifact containing W&B Table of the dataset. + + arguments: + dataset -- instance of LoadImagesAndLabels class used to iterate over the data to build Table + class_to_id -- hash map that maps class ids to labels + name -- name of the artifact + + returns: + dataset artifact to be logged or used + """ + # TODO: Explore multiprocessing to slpit this loop parallely| This is essential for speeding up the the logging + artifact = wandb.Artifact(name=name, type="dataset") + img_files = tqdm([dataset.path]) if isinstance(dataset.path, str) and Path(dataset.path).is_dir() else None + img_files = tqdm(dataset.img_files) if not img_files else img_files + for img_file in img_files: + if Path(img_file).is_dir(): + artifact.add_dir(img_file, name='data/images') + labels_path = 'labels'.join(dataset.path.rsplit('images', 1)) + artifact.add_dir(labels_path, name='data/labels') + else: + artifact.add_file(img_file, name='data/images/' + Path(img_file).name) + label_file = Path(img2label_paths([img_file])[0]) + artifact.add_file(str(label_file), + name='data/labels/' + label_file.name) if label_file.exists() else None + table = wandb.Table(columns=["id", "train_image", "Classes", "name"]) + class_set = wandb.Classes([{'id': id, 'name': name} for id, name in class_to_id.items()]) + for si, (img, labels, paths, shapes) in enumerate(tqdm(dataset)): + box_data, img_classes = [], {} + for cls, *xywh in labels[:, 1:].tolist(): + cls = int(cls) + box_data.append({"position": {"middle": [xywh[0], xywh[1]], "width": xywh[2], "height": xywh[3]}, + "class_id": cls, + "box_caption": "%s" % (class_to_id[cls])}) + img_classes[cls] = class_to_id[cls] + boxes = {"ground_truth": {"box_data": box_data, "class_labels": class_to_id}} # inference-space + table.add_data(si, wandb.Image(paths, classes=class_set, boxes=boxes), list(img_classes.values()), + Path(paths).name) + artifact.add(table, name) + return artifact + + def log_training_progress(self, predn, path, names): + """ + Build evaluation Table. Uses reference from validation dataset table. + + arguments: + predn (list): list of predictions in the native space in the format - [xmin, ymin, xmax, ymax, confidence, class] + path (str): local path of the current evaluation image + names (dict(int, str)): hash map that maps class ids to labels + """ + class_set = wandb.Classes([{'id': id, 'name': name} for id, name in names.items()]) + box_data = [] + total_conf = 0 + for *xyxy, conf, cls in predn.tolist(): + if conf >= 0.25: + box_data.append( + {"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, + "class_id": int(cls), + "box_caption": f"{names[cls]} {conf:.3f}", + "scores": {"class_score": conf}, + "domain": "pixel"}) + total_conf += conf + boxes = {"predictions": {"box_data": box_data, "class_labels": names}} # inference-space + id = self.val_table_path_map[Path(path).name] + self.result_table.add_data(self.current_epoch, + id, + self.val_table.data[id][1], + wandb.Image(self.val_table.data[id][1], boxes=boxes, classes=class_set), + total_conf / max(1, len(box_data)) + ) + + def val_one_image(self, pred, predn, path, names, im): + """ + Log validation data for one image. updates the result Table if validation dataset is uploaded and log bbox media panel + + arguments: + pred (list): list of scaled predictions in the format - [xmin, ymin, xmax, ymax, confidence, class] + predn (list): list of predictions in the native space - [xmin, ymin, xmax, ymax, confidence, class] + path (str): local path of the current evaluation image + """ + if self.val_table and self.result_table: # Log Table if Val dataset is uploaded as artifact + self.log_training_progress(predn, path, names) + + if len(self.bbox_media_panel_images) < self.max_imgs_to_log and self.current_epoch > 0: + if self.current_epoch % self.bbox_interval == 0: + box_data = [{"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, + "class_id": int(cls), + "box_caption": f"{names[cls]} {conf:.3f}", + "scores": {"class_score": conf}, + "domain": "pixel"} for *xyxy, conf, cls in pred.tolist()] + boxes = {"predictions": {"box_data": box_data, "class_labels": names}} # inference-space + self.bbox_media_panel_images.append(wandb.Image(im, boxes=boxes, caption=path.name)) + + def log(self, log_dict): + """ + save the metrics to the logging dictionary + + arguments: + log_dict (Dict) -- metrics/media to be logged in current step + """ + if self.wandb_run: + for key, value in log_dict.items(): + self.log_dict[key] = value + + def end_epoch(self, best_result=False): + """ + commit the log_dict, model artifacts and Tables to W&B and flush the log_dict. + + arguments: + best_result (boolean): Boolean representing if the result of this evaluation is best or not + """ + if self.wandb_run: + with all_logging_disabled(): + if self.bbox_media_panel_images: + self.log_dict["BoundingBoxDebugger"] = self.bbox_media_panel_images + try: + wandb.log(self.log_dict) + except BaseException as e: + LOGGER.info(f"An error occurred in wandb logger. The training will proceed without interruption. More info\n{e}") + self.wandb_run.finish() + self.wandb_run = None + + self.log_dict = {} + self.bbox_media_panel_images = [] + if self.result_artifact: + self.result_artifact.add(self.result_table, 'result') + wandb.log_artifact(self.result_artifact, aliases=['latest', 'last', 'epoch ' + str(self.current_epoch), + ('best' if best_result else '')]) + + wandb.log({"evaluation": self.result_table}) + self.result_table = wandb.Table(["epoch", "id", "ground truth", "prediction", "avg_confidence"]) + self.result_artifact = wandb.Artifact("run_" + wandb.run.id + "_progress", "evaluation") + + def finish_run(self): + """ + Log metrics if any and finish the current W&B run + """ + if self.wandb_run: + if self.log_dict: + with all_logging_disabled(): + wandb.log(self.log_dict) + wandb.run.finish() + + +@contextmanager +def all_logging_disabled(highest_level=logging.CRITICAL): + """ source - https://gist.github.com/simon-weber/7853144 + A context manager that will prevent any logging messages triggered during the body from being processed. + :param highest_level: the maximum logging level in use. + This would only need to be changed if a custom level greater than CRITICAL is defined. + """ + previous_level = logging.root.manager.disable + logging.disable(highest_level) + try: + yield + finally: + logging.disable(previous_level) diff --git a/utils/loss.py b/utils/loss.py index a2c5cce795..dfde60adfd 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -1,9 +1,12 @@ -# Loss functions +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Loss functions +""" import torch import torch.nn as nn -from utils.general import bbox_iou +from utils.metrics import bbox_iou from utils.torch_utils import is_parallel @@ -15,7 +18,7 @@ def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#iss class BCEBlurWithLogitsLoss(nn.Module): # BCEwithLogitLoss() with reduced missing label effects. def __init__(self, alpha=0.05): - super(BCEBlurWithLogitsLoss, self).__init__() + super().__init__() self.loss_fcn = nn.BCEWithLogitsLoss(reduction='none') # must be nn.BCEWithLogitsLoss() self.alpha = alpha @@ -32,7 +35,7 @@ def forward(self, pred, true): class FocalLoss(nn.Module): # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): - super(FocalLoss, self).__init__() + super().__init__() self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() self.gamma = gamma self.alpha = alpha @@ -62,7 +65,7 @@ def forward(self, pred, true): class QFocalLoss(nn.Module): # Wraps Quality focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): - super(QFocalLoss, self).__init__() + super().__init__() self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() self.gamma = gamma self.alpha = alpha @@ -88,7 +91,7 @@ def forward(self, pred, true): class ComputeLoss: # Compute losses def __init__(self, model, autobalance=False): - super(ComputeLoss, self).__init__() + self.sort_obj_iou = False device = next(model.parameters()).device # get model device h = model.hyp # hyperparameters @@ -105,9 +108,9 @@ def __init__(self, model, autobalance=False): BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) det = model.module.model[-1] if is_parallel(model) else model.model[-1] # Detect() module - self.balance = {3: [4.0, 1.0, 0.4]}.get(det.nl, [4.0, 1.0, 0.25, 0.06, .02]) # P3-P7 + self.balance = {3: [4.0, 1.0, 0.4]}.get(det.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 self.ssi = list(det.stride).index(16) if autobalance else 0 # stride 16 index - self.BCEcls, self.BCEobj, self.gr, self.hyp, self.autobalance = BCEcls, BCEobj, model.gr, h, autobalance + self.BCEcls, self.BCEobj, self.gr, self.hyp, self.autobalance = BCEcls, BCEobj, 1.0, h, autobalance for k in 'na', 'nc', 'nl', 'anchors': setattr(self, k, getattr(det, k)) @@ -126,14 +129,18 @@ def __call__(self, p, targets): # predictions, targets, model ps = pi[b, a, gj, gi] # prediction subset corresponding to targets # Regression - pxy = ps[:, :2].sigmoid() * 2. - 0.5 + pxy = ps[:, :2].sigmoid() * 2 - 0.5 pwh = (ps[:, 2:4].sigmoid() * 2) ** 2 * anchors[i] pbox = torch.cat((pxy, pwh), 1) # predicted box iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, CIoU=True) # iou(prediction, target) lbox += (1.0 - iou).mean() # iou loss # Objectness - tobj[b, a, gj, gi] = (1.0 - self.gr) + self.gr * iou.detach().clamp(0).type(tobj.dtype) # iou ratio + score_iou = iou.detach().clamp(0).type(tobj.dtype) + if self.sort_obj_iou: + sort_id = torch.argsort(score_iou) + b, a, gj, gi, score_iou = b[sort_id], a[sort_id], gj[sort_id], gi[sort_id], score_iou[sort_id] + tobj[b, a, gj, gi] = (1.0 - self.gr) + self.gr * score_iou # iou ratio # Classification if self.nc > 1: # cls loss (only if multiple classes) @@ -157,8 +164,7 @@ def __call__(self, p, targets): # predictions, targets, model lcls *= self.hyp['cls'] bs = tobj.shape[0] # batch size - loss = lbox + lobj + lcls - return loss * bs, torch.cat((lbox, lobj, lcls, loss)).detach() + return (lbox + lobj + lcls) * bs, torch.cat((lbox, lobj, lcls)).detach() def build_targets(self, p, targets): # Build targets for compute_loss(), input targets(image,class,x,y,w,h) @@ -170,7 +176,7 @@ def build_targets(self, p, targets): g = 0.5 # bias off = torch.tensor([[0, 0], - # [1, 0], [0, 1], [-1, 0], [0, -1], # j,k,l,m + [1, 0], [0, 1], [-1, 0], [0, -1], # j,k,l,m # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm ], device=targets.device).float() * g # offsets @@ -183,17 +189,17 @@ def build_targets(self, p, targets): if nt: # Matches r = t[:, :, 4:6] / anchors[:, None] # wh ratio - j = torch.max(r, 1. / r).max(2)[0] < self.hyp['anchor_t'] # compare + j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t'] # compare # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2)) t = t[j] # filter # Offsets gxy = t[:, 2:4] # grid xy gxi = gain[[2, 3]] - gxy # inverse - j, k = ((gxy % 1. < g) & (gxy > 1.)).T - l, m = ((gxi % 1. < g) & (gxi > 1.)).T - j = torch.stack((torch.ones_like(j),)) - t = t.repeat((off.shape[0], 1, 1))[j] + j, k = ((gxy % 1 < g) & (gxy > 1)).T + l, m = ((gxi % 1 < g) & (gxi > 1)).T + j = torch.stack((torch.ones_like(j), j, k, l, m)) + t = t.repeat((5, 1, 1))[j] offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j] else: t = targets[0] diff --git a/utils/metrics.py b/utils/metrics.py index 323c84b6c8..c8fcac5f0c 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -1,13 +1,16 @@ -# Model validation metrics +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Model validation metrics +""" +import math +import warnings from pathlib import Path import matplotlib.pyplot as plt import numpy as np import torch -from . import general - def fitness(x): # Model fitness as a weighted combination of metrics @@ -68,6 +71,8 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names # Compute F1 (harmonic mean of precision and recall) f1 = 2 * p * r / (p + r + 1e-16) + names = [v for k, v in names.items() if k in unique_classes] # list: only classes that have data + names = {i: v for i, v in enumerate(names)} # to dict if plot: plot_pr_curve(px, py, ap, Path(save_dir) / 'PR_curve.png', names) plot_mc_curve(px, f1, Path(save_dir) / 'F1_curve.png', names, ylabel='F1') @@ -88,8 +93,8 @@ def compute_ap(recall, precision): """ # Append sentinel values to beginning and end - mrec = np.concatenate(([0.], recall, [recall[-1] + 0.01])) - mpre = np.concatenate(([1.], precision, [0.])) + mrec = np.concatenate(([0.0], recall, [1.0])) + mpre = np.concatenate(([1.0], precision, [0.0])) # Compute the precision envelope mpre = np.flip(np.maximum.accumulate(np.flip(mpre))) @@ -127,7 +132,7 @@ def process_batch(self, detections, labels): detections = detections[detections[:, 4] > self.conf] gt_classes = labels[:, 0].int() detection_classes = detections[:, 5].int() - iou = general.box_iou(labels[:, 1:], detections[:, :4]) + iou = box_iou(labels[:, 1:], detections[:, :4]) x = torch.where(iou > self.iou_thres) if x[0].shape[0]: @@ -157,30 +162,135 @@ def process_batch(self, detections, labels): def matrix(self): return self.matrix - def plot(self, save_dir='', names=()): + def plot(self, normalize=True, save_dir='', names=()): try: import seaborn as sn - array = self.matrix / (self.matrix.sum(0).reshape(1, self.nc + 1) + 1E-6) # normalize + array = self.matrix / ((self.matrix.sum(0).reshape(1, -1) + 1E-6) if normalize else 1) # normalize columns array[array < 0.005] = np.nan # don't annotate (would appear as 0.00) fig = plt.figure(figsize=(12, 9), tight_layout=True) sn.set(font_scale=1.0 if self.nc < 50 else 0.8) # for label size labels = (0 < len(names) < 99) and len(names) == self.nc # apply names to ticklabels - sn.heatmap(array, annot=self.nc < 30, annot_kws={"size": 8}, cmap='Blues', fmt='.2f', square=True, - xticklabels=names + ['background FP'] if labels else "auto", - yticklabels=names + ['background FN'] if labels else "auto").set_facecolor((1, 1, 1)) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') # suppress empty matrix RuntimeWarning: All-NaN slice encountered + sn.heatmap(array, annot=self.nc < 30, annot_kws={"size": 8}, cmap='Blues', fmt='.2f', square=True, + xticklabels=names + ['background FP'] if labels else "auto", + yticklabels=names + ['background FN'] if labels else "auto").set_facecolor((1, 1, 1)) fig.axes[0].set_xlabel('True') fig.axes[0].set_ylabel('Predicted') fig.savefig(Path(save_dir) / 'confusion_matrix.png', dpi=250) + plt.close() except Exception as e: - pass + print(f'WARNING: ConfusionMatrix plot failure: {e}') def print(self): for i in range(self.nc + 1): print(' '.join(map(str, self.matrix[i]))) +def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7): + # Returns the IoU of box1 to box2. box1 is 4, box2 is nx4 + box2 = box2.T + + # Get the coordinates of bounding boxes + if x1y1x2y2: # x1, y1, x2, y2 = box1 + b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3] + b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3] + else: # transform from xywh to xyxy + b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2 + b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2 + b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2 + b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2 + + # Intersection area + inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \ + (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0) + + # Union Area + w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps + w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps + union = w1 * h1 + w2 * h2 - inter + eps + + iou = inter / union + if GIoU or DIoU or CIoU: + cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1) # convex (smallest enclosing box) width + ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1) # convex height + if CIoU or DIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1 + c2 = cw ** 2 + ch ** 2 + eps # convex diagonal squared + rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4 # center distance squared + if DIoU: + return iou - rho2 / c2 # DIoU + elif CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47 + v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2) + with torch.no_grad(): + alpha = v / (v - iou + (1 + eps)) + return iou - (rho2 / c2 + v * alpha) # CIoU + else: # GIoU https://arxiv.org/pdf/1902.09630.pdf + c_area = cw * ch + eps # convex area + return iou - (c_area - union) / c_area # GIoU + else: + return iou # IoU + + +def box_iou(box1, box2): + # https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py + """ + Return intersection-over-union (Jaccard index) of boxes. + Both sets of boxes are expected to be in (x1, y1, x2, y2) format. + Arguments: + box1 (Tensor[N, 4]) + box2 (Tensor[M, 4]) + Returns: + iou (Tensor[N, M]): the NxM matrix containing the pairwise + IoU values for every element in boxes1 and boxes2 + """ + + def box_area(box): + # box = 4xn + return (box[2] - box[0]) * (box[3] - box[1]) + + area1 = box_area(box1.T) + area2 = box_area(box2.T) + + # inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2) + inter = (torch.min(box1[:, None, 2:], box2[:, 2:]) - torch.max(box1[:, None, :2], box2[:, :2])).clamp(0).prod(2) + return inter / (area1[:, None] + area2 - inter) # iou = inter / (area1 + area2 - inter) + + +def bbox_ioa(box1, box2, eps=1E-7): + """ Returns the intersection over box2 area given box1, box2. Boxes are x1y1x2y2 + box1: np.array of shape(4) + box2: np.array of shape(nx4) + returns: np.array of shape(n) + """ + + box2 = box2.transpose() + + # Get the coordinates of bounding boxes + b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3] + b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3] + + # Intersection area + inter_area = (np.minimum(b1_x2, b2_x2) - np.maximum(b1_x1, b2_x1)).clip(0) * \ + (np.minimum(b1_y2, b2_y2) - np.maximum(b1_y1, b2_y1)).clip(0) + + # box2 area + box2_area = (b2_x2 - b2_x1) * (b2_y2 - b2_y1) + eps + + # Intersection over box2 area + return inter_area / box2_area + + +def wh_iou(wh1, wh2): + # Returns the nxm IoU matrix. wh1 is nx2, wh2 is mx2 + wh1 = wh1[:, None] # [N,1,2] + wh2 = wh2[None] # [1,M,2] + inter = torch.min(wh1, wh2).prod(2) # [N,M] + return inter / (wh1.prod(2) + wh2.prod(2) - inter) # iou = inter / (area1 + area2 - inter) + + # Plots ---------------------------------------------------------------------------------------------------------------- def plot_pr_curve(px, py, ap, save_dir='pr_curve.png', names=()): @@ -201,6 +311,7 @@ def plot_pr_curve(px, py, ap, save_dir='pr_curve.png', names=()): ax.set_ylim(0, 1) plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left") fig.savefig(Path(save_dir), dpi=250) + plt.close() def plot_mc_curve(px, py, save_dir='mc_curve.png', names=(), xlabel='Confidence', ylabel='Metric'): @@ -221,3 +332,4 @@ def plot_mc_curve(px, py, save_dir='mc_curve.png', names=(), xlabel='Confidence' ax.set_ylim(0, 1) plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left") fig.savefig(Path(save_dir), dpi=250) + plt.close() diff --git a/utils/plots.py b/utils/plots.py index 2ae36523f3..16ae44a7e1 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -1,9 +1,10 @@ -# Plotting utils +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Plotting utils +""" -import glob import math import os -import random from copy import copy from pathlib import Path @@ -12,15 +13,17 @@ import matplotlib.pyplot as plt import numpy as np import pandas as pd -import seaborn as sns +import seaborn as sn import torch -import yaml from PIL import Image, ImageDraw, ImageFont -from utils.general import xywh2xyxy, xyxy2xywh +from utils.general import (LOGGER, Timeout, check_requirements, clip_coords, increment_path, is_ascii, is_chinese, + try_except, user_config_dir, xywh2xyxy, xyxy2xywh) from utils.metrics import fitness # Settings +CONFIG_DIR = user_config_dir() # Ultralytics settings dir +RANK = int(os.getenv('RANK', -1)) matplotlib.rc('font', **{'size': 11}) matplotlib.use('Agg') # for writing to files only @@ -46,6 +49,105 @@ def hex2rgb(h): # rgb order (PIL) colors = Colors() # create instance for 'from utils.plots import colors' +def check_font(font='Arial.ttf', size=10): + # Return a PIL TrueType Font, downloading to CONFIG_DIR if necessary + font = Path(font) + font = font if font.exists() else (CONFIG_DIR / font.name) + try: + return ImageFont.truetype(str(font) if font.exists() else font.name, size) + except Exception as e: # download if missing + url = "https://ultralytics.com/assets/" + font.name + print(f'Downloading {url} to {font}...') + torch.hub.download_url_to_file(url, str(font), progress=False) + try: + return ImageFont.truetype(str(font), size) + except TypeError: + check_requirements('Pillow>=8.4.0') # known issue https://github.com/ultralytics/yolov5/issues/5374 + + +class Annotator: + if RANK in (-1, 0): + check_font() # download TTF if necessary + + # Annotator for train/val mosaics and jpgs and detect/hub inference annotations + def __init__(self, im, line_width=None, font_size=None, font='Arial.ttf', pil=False, example='abc'): + assert im.data.contiguous, 'Image not contiguous. Apply np.ascontiguousarray(im) to Annotator() input images.' + self.pil = pil or not is_ascii(example) or is_chinese(example) + if self.pil: # use PIL + self.im = im if isinstance(im, Image.Image) else Image.fromarray(im) + self.draw = ImageDraw.Draw(self.im) + self.font = check_font(font='Arial.Unicode.ttf' if is_chinese(example) else font, + size=font_size or max(round(sum(self.im.size) / 2 * 0.035), 12)) + else: # use cv2 + self.im = im + self.lw = line_width or max(round(sum(im.shape) / 2 * 0.003), 2) # line width + + def box_label(self, box, label='', color=(128, 128, 128), txt_color=(255, 255, 255)): + # Add one xyxy box to image with label + if self.pil or not is_ascii(label): + self.draw.rectangle(box, width=self.lw, outline=color) # box + if label: + w, h = self.font.getsize(label) # text width, height + outside = box[1] - h >= 0 # label fits outside box + self.draw.rectangle([box[0], + box[1] - h if outside else box[1], + box[0] + w + 1, + box[1] + 1 if outside else box[1] + h + 1], fill=color) + # self.draw.text((box[0], box[1]), label, fill=txt_color, font=self.font, anchor='ls') # for PIL>8.0 + self.draw.text((box[0], box[1] - h if outside else box[1]), label, fill=txt_color, font=self.font) + else: # cv2 + p1, p2 = (int(box[0]), int(box[1])), (int(box[2]), int(box[3])) + cv2.rectangle(self.im, p1, p2, color, thickness=self.lw, lineType=cv2.LINE_AA) + if label: + tf = max(self.lw - 1, 1) # font thickness + w, h = cv2.getTextSize(label, 0, fontScale=self.lw / 3, thickness=tf)[0] # text width, height + outside = p1[1] - h - 3 >= 0 # label fits outside box + p2 = p1[0] + w, p1[1] - h - 3 if outside else p1[1] + h + 3 + cv2.rectangle(self.im, p1, p2, color, -1, cv2.LINE_AA) # filled + cv2.putText(self.im, label, (p1[0], p1[1] - 2 if outside else p1[1] + h + 2), 0, self.lw / 3, txt_color, + thickness=tf, lineType=cv2.LINE_AA) + + def rectangle(self, xy, fill=None, outline=None, width=1): + # Add rectangle to image (PIL-only) + self.draw.rectangle(xy, fill, outline, width) + + def text(self, xy, text, txt_color=(255, 255, 255)): + # Add text to image (PIL-only) + w, h = self.font.getsize(text) # text width, height + self.draw.text((xy[0], xy[1] - h + 1), text, fill=txt_color, font=self.font) + + def result(self): + # Return annotated image as array + return np.asarray(self.im) + + +def feature_visualization(x, module_type, stage, n=32, save_dir=Path('runs/detect/exp')): + """ + x: Features to be visualized + module_type: Module type + stage: Module stage within model + n: Maximum number of feature maps to plot + save_dir: Directory to save results + """ + if 'Detect' not in module_type: + batch, channels, height, width = x.shape # batch, channels, height, width + if height > 1 and width > 1: + f = f"stage{stage}_{module_type.split('.')[-1]}_features.png" # filename + + blocks = torch.chunk(x[0].cpu(), channels, dim=0) # select batch index 0, block by channels + n = min(n, channels) # number of plots + fig, ax = plt.subplots(math.ceil(n / 8), 8, tight_layout=True) # 8 rows x n/8 cols + ax = ax.ravel() + plt.subplots_adjust(wspace=0.05, hspace=0.05) + for i in range(n): + ax[i].imshow(blocks[i].squeeze()) # cmap='gray' + ax[i].axis('off') + + print(f'Saving {save_dir / f}... ({n}/{channels})') + plt.savefig(save_dir / f, dpi=300, bbox_inches='tight') + plt.close() + + def hist2d(x, y, n=100): # 2d histogram used in labels.png and evolve.png xedges, yedges = np.linspace(x.min(), x.max(), n), np.linspace(y.min(), y.max(), n) @@ -68,54 +170,6 @@ def butter_lowpass(cutoff, fs, order): return filtfilt(b, a, data) # forward-backward filter -def plot_one_box(x, im, color=(128, 128, 128), label=None, line_thickness=3): - # Plots one bounding box on image 'im' using OpenCV - assert im.data.contiguous, 'Image not contiguous. Apply np.ascontiguousarray(im) to plot_on_box() input image.' - tl = line_thickness or round(0.002 * (im.shape[0] + im.shape[1]) / 2) + 1 # line/font thickness - c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) - cv2.rectangle(im, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA) - if label: - tf = max(tl - 1, 1) # font thickness - t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] - c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 - cv2.rectangle(im, c1, c2, color, -1, cv2.LINE_AA) # filled - cv2.putText(im, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA) - - -def plot_one_box_PIL(box, im, color=(128, 128, 128), label=None, line_thickness=None): - # Plots one bounding box on image 'im' using PIL - im = Image.fromarray(im) - draw = ImageDraw.Draw(im) - line_thickness = line_thickness or max(int(min(im.size) / 200), 2) - draw.rectangle(box, width=line_thickness, outline=color) # plot - if label: - font = ImageFont.truetype("Arial.ttf", size=max(round(max(im.size) / 40), 12)) - txt_width, txt_height = font.getsize(label) - draw.rectangle([box[0], box[1] - txt_height + 4, box[0] + txt_width, box[1]], fill=color) - draw.text((box[0], box[1] - txt_height + 1), label, fill=(255, 255, 255), font=font) - return np.asarray(im) - - -def plot_wh_methods(): # from utils.plots import *; plot_wh_methods() - # Compares the two methods for width-height anchor multiplication - # https://github.com/ultralytics/yolov3/issues/168 - x = np.arange(-4.0, 4.0, .1) - ya = np.exp(x) - yb = torch.sigmoid(torch.from_numpy(x)).numpy() * 2 - - fig = plt.figure(figsize=(6, 3), tight_layout=True) - plt.plot(x, ya, '.-', label='YOLOv3') - plt.plot(x, yb ** 2, '.-', label='YOLOv5 ^2') - plt.plot(x, yb ** 1.6, '.-', label='YOLOv5 ^1.6') - plt.xlim(left=-4, right=4) - plt.ylim(bottom=0, top=6) - plt.xlabel('input') - plt.ylabel('output') - plt.grid() - plt.legend() - fig.savefig('comparison.png', dpi=200) - - def output_to_target(output): # Convert model output to target format [batch_id, class_id, x, y, w, h, conf] targets = [] @@ -125,82 +179,65 @@ def output_to_target(output): return np.array(targets) -def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max_size=640, max_subplots=16): +def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max_size=1920, max_subplots=16): # Plot image grid with labels - if isinstance(images, torch.Tensor): images = images.cpu().float().numpy() if isinstance(targets, torch.Tensor): targets = targets.cpu().numpy() - - # un-normalise if np.max(images[0]) <= 1: - images *= 255 - - tl = 3 # line thickness - tf = max(tl - 1, 1) # font thickness + images *= 255 # de-normalise (optional) bs, _, h, w = images.shape # batch size, _, height, width bs = min(bs, max_subplots) # limit plot images ns = np.ceil(bs ** 0.5) # number of subplots (square) - # Check if we should resize - scale_factor = max_size / max(h, w) - if scale_factor < 1: - h = math.ceil(scale_factor * h) - w = math.ceil(scale_factor * w) - + # Build Image mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) # init - for i, img in enumerate(images): + for i, im in enumerate(images): if i == max_subplots: # if last batch has fewer images than we expect break - - block_x = int(w * (i // ns)) - block_y = int(h * (i % ns)) - - img = img.transpose(1, 2, 0) - if scale_factor < 1: - img = cv2.resize(img, (w, h)) - - mosaic[block_y:block_y + h, block_x:block_x + w, :] = img + x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin + im = im.transpose(1, 2, 0) + mosaic[y:y + h, x:x + w, :] = im + + # Resize (optional) + scale = max_size / ns / max(h, w) + if scale < 1: + h = math.ceil(scale * h) + w = math.ceil(scale * w) + mosaic = cv2.resize(mosaic, tuple(int(x * ns) for x in (w, h))) + + # Annotate + fs = int((h + w) * ns * 0.01) # font size + annotator = Annotator(mosaic, line_width=round(fs / 10), font_size=fs, pil=True) + for i in range(i + 1): + x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin + annotator.rectangle([x, y, x + w, y + h], None, (255, 255, 255), width=2) # borders + if paths: + annotator.text((x + 5, y + 5 + h), text=Path(paths[i]).name[:40], txt_color=(220, 220, 220)) # filenames if len(targets) > 0: - image_targets = targets[targets[:, 0] == i] - boxes = xywh2xyxy(image_targets[:, 2:6]).T - classes = image_targets[:, 1].astype('int') - labels = image_targets.shape[1] == 6 # labels if no conf column - conf = None if labels else image_targets[:, 6] # check for confidence presence (label vs pred) + ti = targets[targets[:, 0] == i] # image targets + boxes = xywh2xyxy(ti[:, 2:6]).T + classes = ti[:, 1].astype('int') + labels = ti.shape[1] == 6 # labels if no conf column + conf = None if labels else ti[:, 6] # check for confidence presence (label vs pred) if boxes.shape[1]: if boxes.max() <= 1.01: # if normalized with tolerance 0.01 boxes[[0, 2]] *= w # scale to pixels boxes[[1, 3]] *= h - elif scale_factor < 1: # absolute coords need scale if image scales - boxes *= scale_factor - boxes[[0, 2]] += block_x - boxes[[1, 3]] += block_y - for j, box in enumerate(boxes.T): - cls = int(classes[j]) + elif scale < 1: # absolute coords need scale if image scales + boxes *= scale + boxes[[0, 2]] += x + boxes[[1, 3]] += y + for j, box in enumerate(boxes.T.tolist()): + cls = classes[j] color = colors(cls) cls = names[cls] if names else cls if labels or conf[j] > 0.25: # 0.25 conf thresh - label = '%s' % cls if labels else '%s %.1f' % (cls, conf[j]) - plot_one_box(box, mosaic, label=label, color=color, line_thickness=tl) - - # Draw image filename labels - if paths: - label = Path(paths[i]).name[:40] # trim to 40 char - t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] - cv2.putText(mosaic, label, (block_x + 5, block_y + t_size[1] + 5), 0, tl / 3, [220, 220, 220], thickness=tf, - lineType=cv2.LINE_AA) - - # Image border - cv2.rectangle(mosaic, (block_x, block_y), (block_x + w, block_y + h), (255, 255, 255), thickness=3) - - if fname: - r = min(1280. / max(h, w) / ns, 1.0) # ratio to limit image size - mosaic = cv2.resize(mosaic, (int(ns * w * r), int(ns * h * r)), interpolation=cv2.INTER_AREA) - # cv2.imwrite(fname, cv2.cvtColor(mosaic, cv2.COLOR_BGR2RGB)) # cv2 save - Image.fromarray(mosaic).save(fname) # PIL save - return mosaic + label = f'{cls}' if labels else f'{cls} {conf[j]:.1f}' + annotator.box_label(box, label, color=color) + annotator.im.save(fname) # save def plot_lr_scheduler(optimizer, scheduler, epochs=300, save_dir=''): @@ -220,9 +257,9 @@ def plot_lr_scheduler(optimizer, scheduler, epochs=300, save_dir=''): plt.close() -def plot_test_txt(): # from utils.plots import *; plot_test() - # Plot test.txt histograms - x = np.loadtxt('test.txt', dtype=np.float32) +def plot_val_txt(): # from utils.plots import *; plot_val() + # Plot val.txt histograms + x = np.loadtxt('val.txt', dtype=np.float32) box = xyxy2xywh(x[:, :4]) cx, cy = box[:, 0], box[:, 1] @@ -244,29 +281,32 @@ def plot_targets_txt(): # from utils.plots import *; plot_targets_txt() fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) ax = ax.ravel() for i in range(4): - ax[i].hist(x[i], bins=100, label='%.3g +/- %.3g' % (x[i].mean(), x[i].std())) + ax[i].hist(x[i], bins=100, label=f'{x[i].mean():.3g} +/- {x[i].std():.3g}') ax[i].legend() ax[i].set_title(s[i]) plt.savefig('targets.jpg', dpi=200) -def plot_study_txt(path='', x=None): # from utils.plots import *; plot_study_txt() - # Plot study.txt generated by test.py - fig, ax = plt.subplots(2, 4, figsize=(10, 6), tight_layout=True) - # ax = ax.ravel() +def plot_val_study(file='', dir='', x=None): # from utils.plots import *; plot_val_study() + # Plot file=study.txt generated by val.py (or plot all study*.txt in dir) + save_dir = Path(file).parent if file else Path(dir) + plot2 = False # plot additional results + if plot2: + ax = plt.subplots(2, 4, figsize=(10, 6), tight_layout=True)[1].ravel() fig2, ax2 = plt.subplots(1, 1, figsize=(8, 4), tight_layout=True) - # for f in [Path(path) / f'study_coco_{x}.txt' for x in ['yolov3-tiny', 'yolov3', 'yolov3-spp', 'yolov5l']]: - for f in sorted(Path(path).glob('study*.txt')): + # for f in [save_dir / f'study_coco_{x}.txt' for x in ['yolov3', 'yolov3-spp', 'yolov3-tiny']]: + for f in sorted(save_dir.glob('study*.txt')): y = np.loadtxt(f, dtype=np.float32, usecols=[0, 1, 2, 3, 7, 8, 9], ndmin=2).T x = np.arange(y.shape[1]) if x is None else np.array(x) - s = ['P', 'R', 'mAP@.5', 'mAP@.5:.95', 't_inference (ms/img)', 't_NMS (ms/img)', 't_total (ms/img)'] - # for i in range(7): - # ax[i].plot(x, y[i], '.-', linewidth=2, markersize=8) - # ax[i].set_title(s[i]) + if plot2: + s = ['P', 'R', 'mAP@.5', 'mAP@.5:.95', 't_preprocess (ms/img)', 't_inference (ms/img)', 't_NMS (ms/img)'] + for i in range(7): + ax[i].plot(x, y[i], '.-', linewidth=2, markersize=8) + ax[i].set_title(s[i]) j = y[3].argmax() + 1 - ax2.plot(y[6, 1:j], y[3, 1:j] * 1E2, '.-', linewidth=2, markersize=8, + ax2.plot(y[5, 1:j], y[3, 1:j] * 1E2, '.-', linewidth=2, markersize=8, label=f.stem.replace('study_coco_', '').replace('yolo', 'YOLO')) ax2.plot(1E3 / np.array([209, 140, 97, 58, 35, 18]), [34.6, 40.5, 43.0, 47.5, 49.7, 51.5], @@ -275,22 +315,26 @@ def plot_study_txt(path='', x=None): # from utils.plots import *; plot_study_tx ax2.grid(alpha=0.2) ax2.set_yticks(np.arange(20, 60, 5)) ax2.set_xlim(0, 57) - ax2.set_ylim(15, 55) + ax2.set_ylim(25, 55) ax2.set_xlabel('GPU Speed (ms/img)') ax2.set_ylabel('COCO AP val') ax2.legend(loc='lower right') - plt.savefig(str(Path(path).name) + '.png', dpi=300) + f = save_dir / 'study.png' + print(f'Saving {f}...') + plt.savefig(f, dpi=300) -def plot_labels(labels, names=(), save_dir=Path(''), loggers=None): +@try_except # known issue https://github.com/ultralytics/yolov5/issues/5395 +@Timeout(30) # known issue https://github.com/ultralytics/yolov5/issues/5611 +def plot_labels(labels, names=(), save_dir=Path('')): # plot dataset labels - print('Plotting labels... ') + LOGGER.info(f"Plotting labels to {save_dir / 'labels.jpg'}... ") c, b = labels[:, 0], labels[:, 1:].transpose() # classes, boxes nc = int(c.max() + 1) # number of classes x = pd.DataFrame(b.transpose(), columns=['x', 'y', 'width', 'height']) # seaborn correlogram - sns.pairplot(x, corner=True, diag_kind='auto', kind='hist', diag_kws=dict(bins=50), plot_kws=dict(pmax=0.9)) + sn.pairplot(x, corner=True, diag_kind='auto', kind='hist', diag_kws=dict(bins=50), plot_kws=dict(pmax=0.9)) plt.savefig(save_dir / 'labels_correlogram.jpg', dpi=200) plt.close() @@ -298,15 +342,15 @@ def plot_labels(labels, names=(), save_dir=Path(''), loggers=None): matplotlib.use('svg') # faster ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True)[1].ravel() y = ax[0].hist(c, bins=np.linspace(0, nc, nc + 1) - 0.5, rwidth=0.8) - # [y[2].patches[i].set_color([x / 255 for x in colors(i)]) for i in range(nc)] # update colors bug #3195 + # [y[2].patches[i].set_color([x / 255 for x in colors(i)]) for i in range(nc)] # update colors bug #3195 ax[0].set_ylabel('instances') if 0 < len(names) < 30: ax[0].set_xticks(range(len(names))) ax[0].set_xticklabels(names, rotation=90, fontsize=10) else: ax[0].set_xlabel('classes') - sns.histplot(x, x='x', y='y', ax=ax[2], bins=50, pmax=0.9) - sns.histplot(x, x='width', y='height', ax=ax[3], bins=50, pmax=0.9) + sn.histplot(x, x='x', y='y', ax=ax[2], bins=50, pmax=0.9) + sn.histplot(x, x='width', y='height', ax=ax[3], bins=50, pmax=0.9) # rectangles labels[:, 1:3] = 0.5 # center @@ -325,34 +369,57 @@ def plot_labels(labels, names=(), save_dir=Path(''), loggers=None): matplotlib.use('Agg') plt.close() - # loggers - for k, v in loggers.items() or {}: - if k == 'wandb' and v: - v.log({"Labels": [v.Image(str(x), caption=x.name) for x in save_dir.glob('*labels*.jpg')]}, commit=False) - -def plot_evolution(yaml_file='data/hyp.finetune.yaml'): # from utils.plots import *; plot_evolution() - # Plot hyperparameter evolution results in evolve.txt - with open(yaml_file) as f: - hyp = yaml.safe_load(f) - x = np.loadtxt('evolve.txt', ndmin=2) +def plot_evolve(evolve_csv='path/to/evolve.csv'): # from utils.plots import *; plot_evolve() + # Plot evolve.csv hyp evolution results + evolve_csv = Path(evolve_csv) + data = pd.read_csv(evolve_csv) + keys = [x.strip() for x in data.columns] + x = data.values f = fitness(x) - # weights = (f - f.min()) ** 2 # for weighted results + j = np.argmax(f) # max fitness index plt.figure(figsize=(10, 12), tight_layout=True) matplotlib.rc('font', **{'size': 8}) - for i, (k, v) in enumerate(hyp.items()): - y = x[:, i + 7] - # mu = (y * weights).sum() / weights.sum() # best weighted result - mu = y[f.argmax()] # best single result + for i, k in enumerate(keys[7:]): + v = x[:, 7 + i] + mu = v[j] # best single result plt.subplot(6, 5, i + 1) - plt.scatter(y, f, c=hist2d(y, f, 20), cmap='viridis', alpha=.8, edgecolors='none') + plt.scatter(v, f, c=hist2d(v, f, 20), cmap='viridis', alpha=.8, edgecolors='none') plt.plot(mu, f.max(), 'k+', markersize=15) - plt.title('%s = %.3g' % (k, mu), fontdict={'size': 9}) # limit to 40 characters + plt.title(f'{k} = {mu:.3g}', fontdict={'size': 9}) # limit to 40 characters if i % 5 != 0: plt.yticks([]) - print('%15s: %.3g' % (k, mu)) - plt.savefig('evolve.png', dpi=200) - print('\nPlot saved as evolve.png') + print(f'{k:>15}: {mu:.3g}') + f = evolve_csv.with_suffix('.png') # filename + plt.savefig(f, dpi=200) + plt.close() + print(f'Saved {f}') + + +def plot_results(file='path/to/results.csv', dir=''): + # Plot training results.csv. Usage: from utils.plots import *; plot_results('path/to/results.csv') + save_dir = Path(file).parent if file else Path(dir) + fig, ax = plt.subplots(2, 5, figsize=(12, 6), tight_layout=True) + ax = ax.ravel() + files = list(save_dir.glob('results*.csv')) + assert len(files), f'No results.csv files found in {save_dir.resolve()}, nothing to plot.' + for fi, f in enumerate(files): + try: + data = pd.read_csv(f) + s = [x.strip() for x in data.columns] + x = data.values[:, 0] + for i, j in enumerate([1, 2, 3, 4, 5, 8, 9, 10, 6, 7]): + y = data.values[:, j] + # y[y == 0] = np.nan # don't show zero values + ax[i].plot(x, y, marker='.', label=f.stem, linewidth=2, markersize=8) + ax[i].set_title(s[j], fontsize=12) + # if j in [8, 9, 10]: # share train and val loss y axes + # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) + except Exception as e: + print(f'Warning: Plotting error for {f}: {e}') + ax[1].legend() + fig.savefig(save_dir / 'results.png', dpi=200) + plt.close() def profile_idetection(start=0, stop=0, labels=(), save_dir=''): @@ -381,66 +448,22 @@ def profile_idetection(start=0, stop=0, labels=(), save_dir=''): else: a.remove() except Exception as e: - print('Warning: Plotting error for %s; %s' % (f, e)) - + print(f'Warning: Plotting error for {f}; {e}') ax[1].legend() plt.savefig(Path(save_dir) / 'idetection_profile.png', dpi=200) -def plot_results_overlay(start=0, stop=0): # from utils.plots import *; plot_results_overlay() - # Plot training 'results*.txt', overlaying train and val losses - s = ['train', 'train', 'train', 'Precision', 'mAP@0.5', 'val', 'val', 'val', 'Recall', 'mAP@0.5:0.95'] # legends - t = ['Box', 'Objectness', 'Classification', 'P-R', 'mAP-F1'] # titles - for f in sorted(glob.glob('results*.txt') + glob.glob('../../Downloads/results*.txt')): - results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T - n = results.shape[1] # number of rows - x = range(start, min(stop, n) if stop else n) - fig, ax = plt.subplots(1, 5, figsize=(14, 3.5), tight_layout=True) - ax = ax.ravel() - for i in range(5): - for j in [i, i + 5]: - y = results[j, x] - ax[i].plot(x, y, marker='.', label=s[j]) - # y_smooth = butter_lowpass_filtfilt(y) - # ax[i].plot(x, np.gradient(y_smooth), marker='.', label=s[j]) - - ax[i].set_title(t[i]) - ax[i].legend() - ax[i].set_ylabel(f) if i == 0 else None # add filename - fig.savefig(f.replace('.txt', '.png'), dpi=200) - - -def plot_results(start=0, stop=0, bucket='', id=(), labels=(), save_dir=''): - # Plot training 'results*.txt'. from utils.plots import *; plot_results(save_dir='runs/train/exp') - fig, ax = plt.subplots(2, 5, figsize=(12, 6), tight_layout=True) - ax = ax.ravel() - s = ['Box', 'Objectness', 'Classification', 'Precision', 'Recall', - 'val Box', 'val Objectness', 'val Classification', 'mAP@0.5', 'mAP@0.5:0.95'] - if bucket: - # files = ['https://storage.googleapis.com/%s/results%g.txt' % (bucket, x) for x in id] - files = ['results%g.txt' % x for x in id] - c = ('gsutil cp ' + '%s ' * len(files) + '.') % tuple('gs://%s/results%g.txt' % (bucket, x) for x in id) - os.system(c) - else: - files = list(Path(save_dir).glob('results*.txt')) - assert len(files), 'No results.txt files found in %s, nothing to plot.' % os.path.abspath(save_dir) - for fi, f in enumerate(files): - try: - results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T - n = results.shape[1] # number of rows - x = range(start, min(stop, n) if stop else n) - for i in range(10): - y = results[i, x] - if i in [0, 1, 2, 5, 6, 7]: - y[y == 0] = np.nan # don't show zero loss values - # y /= y[0] # normalize - label = labels[fi] if len(labels) else f.stem - ax[i].plot(x, y, marker='.', label=label, linewidth=2, markersize=8) - ax[i].set_title(s[i]) - # if i in [5, 6, 7]: # share train and val loss y axes - # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) - except Exception as e: - print('Warning: Plotting error for %s; %s' % (f, e)) - - ax[1].legend() - fig.savefig(Path(save_dir) / 'results.png', dpi=200) +def save_one_box(xyxy, im, file='image.jpg', gain=1.02, pad=10, square=False, BGR=False, save=True): + # Save image crop as {file} with crop size multiple {gain} and {pad} pixels. Save and/or return crop + xyxy = torch.tensor(xyxy).view(-1, 4) + b = xyxy2xywh(xyxy) # boxes + if square: + b[:, 2:] = b[:, 2:].max(1)[0].unsqueeze(1) # attempt rectangle to square + b[:, 2:] = b[:, 2:] * gain + pad # box wh * gain + pad + xyxy = xywh2xyxy(b).long() + clip_coords(xyxy, im.shape) + crop = im[int(xyxy[0, 1]):int(xyxy[0, 3]), int(xyxy[0, 0]):int(xyxy[0, 2]), ::(1 if BGR else -1)] + if save: + file.parent.mkdir(parents=True, exist_ok=True) # make directory + cv2.imwrite(str(increment_path(file).with_suffix('.jpg')), crop) + return crop diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 9114112a7b..d3692297aa 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -1,7 +1,9 @@ -# YOLOv3 PyTorch utils +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +PyTorch utils +""" import datetime -import logging import math import os import platform @@ -12,16 +14,16 @@ from pathlib import Path import torch -import torch.backends.cudnn as cudnn +import torch.distributed as dist import torch.nn as nn import torch.nn.functional as F -import torchvision + +from utils.general import LOGGER try: - import thop # for FLOPS computation + import thop # for FLOPs computation except ImportError: thop = None -logger = logging.getLogger(__name__) @contextmanager @@ -30,19 +32,10 @@ def torch_distributed_zero_first(local_rank: int): Decorator to make all processes in distributed training wait for each local_master to do something. """ if local_rank not in [-1, 0]: - torch.distributed.barrier() + dist.barrier(device_ids=[local_rank]) yield if local_rank == 0: - torch.distributed.barrier() - - -def init_torch_seeds(seed=0): - # Speed-reproducibility tradeoff https://pytorch.org/docs/stable/notes/randomness.html - torch.manual_seed(seed) - if seed == 0: # slower, more reproducible - cudnn.benchmark, cudnn.deterministic = False, True - else: # faster, less reproducible - cudnn.benchmark, cudnn.deterministic = True, False + dist.barrier(device_ids=[0]) def date_modified(path=__file__): @@ -60,10 +53,11 @@ def git_describe(path=Path(__file__).parent): # path must be a directory return '' # not a git repository -def select_device(device='', batch_size=None): +def select_device(device='', batch_size=None, newline=True): # device = 'cpu' or '0' or '0,1,2,3' s = f'YOLOv3 🚀 {git_describe() or date_modified()} torch {torch.__version__} ' # string - cpu = device.lower() == 'cpu' + device = str(device).strip().lower().replace('cuda:', '') # to string, 'cuda:0' to '0' + cpu = device == 'cpu' if cpu: os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # force torch.cuda.is_available() = False elif device: # non-cpu device requested @@ -72,65 +66,80 @@ def select_device(device='', batch_size=None): cuda = not cpu and torch.cuda.is_available() if cuda: - devices = device.split(',') if device else range(torch.cuda.device_count()) # i.e. 0,1,6,7 + devices = device.split(',') if device else '0' # range(torch.cuda.device_count()) # i.e. 0,1,6,7 n = len(devices) # device count if n > 1 and batch_size: # check batch_size is divisible by device_count assert batch_size % n == 0, f'batch-size {batch_size} not multiple of GPU count {n}' - space = ' ' * len(s) + space = ' ' * (len(s) + 1) for i, d in enumerate(devices): p = torch.cuda.get_device_properties(i) - s += f"{'' if i == 0 else space}CUDA:{d} ({p.name}, {p.total_memory / 1024 ** 2}MB)\n" # bytes to MB + s += f"{'' if i == 0 else space}CUDA:{d} ({p.name}, {p.total_memory / 1024 ** 2:.0f}MiB)\n" # bytes to MB else: s += 'CPU\n' - logger.info(s.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else s) # emoji-safe + if not newline: + s = s.rstrip() + LOGGER.info(s.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else s) # emoji-safe return torch.device('cuda:0' if cuda else 'cpu') -def time_synchronized(): +def time_sync(): # pytorch-accurate time if torch.cuda.is_available(): torch.cuda.synchronize() return time.time() -def profile(x, ops, n=100, device=None): - # profile a pytorch module or list of modules. Example usage: - # x = torch.randn(16, 3, 640, 640) # input +def profile(input, ops, n=10, device=None): + # speed/memory/FLOPs profiler + # + # Usage: + # input = torch.randn(16, 3, 640, 640) # m1 = lambda x: x * torch.sigmoid(x) # m2 = nn.SiLU() - # profile(x, [m1, m2], n=100) # profile speed over 100 iterations - - device = device or torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') - x = x.to(device) - x.requires_grad = True - print(torch.__version__, device.type, torch.cuda.get_device_properties(0) if device.type == 'cuda' else '') - print(f"\n{'Params':>12s}{'GFLOPS':>12s}{'forward (ms)':>16s}{'backward (ms)':>16s}{'input':>24s}{'output':>24s}") - for m in ops if isinstance(ops, list) else [ops]: - m = m.to(device) if hasattr(m, 'to') else m # device - m = m.half() if hasattr(m, 'half') and isinstance(x, torch.Tensor) and x.dtype is torch.float16 else m # type - dtf, dtb, t = 0., 0., [0., 0., 0.] # dt forward, backward - try: - flops = thop.profile(m, inputs=(x,), verbose=False)[0] / 1E9 * 2 # GFLOPS - except: - flops = 0 - - for _ in range(n): - t[0] = time_synchronized() - y = m(x) - t[1] = time_synchronized() + # profile(input, [m1, m2], n=100) # profile over 100 iterations + + results = [] + device = device or select_device() + print(f"{'Params':>12s}{'GFLOPs':>12s}{'GPU_mem (GB)':>14s}{'forward (ms)':>14s}{'backward (ms)':>14s}" + f"{'input':>24s}{'output':>24s}") + + for x in input if isinstance(input, list) else [input]: + x = x.to(device) + x.requires_grad = True + for m in ops if isinstance(ops, list) else [ops]: + m = m.to(device) if hasattr(m, 'to') else m # device + m = m.half() if hasattr(m, 'half') and isinstance(x, torch.Tensor) and x.dtype is torch.float16 else m + tf, tb, t = 0, 0, [0, 0, 0] # dt forward, backward try: - _ = y.sum().backward() - t[2] = time_synchronized() - except: # no backward method - t[2] = float('nan') - dtf += (t[1] - t[0]) * 1000 / n # ms per op forward - dtb += (t[2] - t[1]) * 1000 / n # ms per op backward + flops = thop.profile(m, inputs=(x,), verbose=False)[0] / 1E9 * 2 # GFLOPs + except: + flops = 0 - s_in = tuple(x.shape) if isinstance(x, torch.Tensor) else 'list' - s_out = tuple(y.shape) if isinstance(y, torch.Tensor) else 'list' - p = sum(list(x.numel() for x in m.parameters())) if isinstance(m, nn.Module) else 0 # parameters - print(f'{p:12}{flops:12.4g}{dtf:16.4g}{dtb:16.4g}{str(s_in):>24s}{str(s_out):>24s}') + try: + for _ in range(n): + t[0] = time_sync() + y = m(x) + t[1] = time_sync() + try: + _ = (sum(yi.sum() for yi in y) if isinstance(y, list) else y).sum().backward() + t[2] = time_sync() + except Exception as e: # no backward method + # print(e) # for debug + t[2] = float('nan') + tf += (t[1] - t[0]) * 1000 / n # ms per op forward + tb += (t[2] - t[1]) * 1000 / n # ms per op backward + mem = torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0 # (GB) + s_in = tuple(x.shape) if isinstance(x, torch.Tensor) else 'list' + s_out = tuple(y.shape) if isinstance(y, torch.Tensor) else 'list' + p = sum(list(x.numel() for x in m.parameters())) if isinstance(m, nn.Module) else 0 # parameters + print(f'{p:12}{flops:12.4g}{mem:>14.3f}{tf:14.4g}{tb:14.4g}{str(s_in):>24s}{str(s_out):>24s}') + results.append([p, flops, mem, tf, tb, s_in, s_out]) + except Exception as e: + print(e) + results.append(None) + torch.cuda.empty_cache() + return results def is_parallel(model): @@ -143,11 +152,6 @@ def de_parallel(model): return model.module if is_parallel(model) else model -def intersect_dicts(da, db, exclude=()): - # Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values - return {k: v for k, v in da.items() if k in db and not any(x in k for x in exclude) and v.shape == db[k].shape} - - def initialize_weights(model): for m in model.modules(): t = type(m) @@ -156,7 +160,7 @@ def initialize_weights(model): elif t is nn.BatchNorm2d: m.eps = 1e-3 m.momentum = 0.03 - elif t in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6]: + elif t in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU]: m.inplace = True @@ -167,7 +171,7 @@ def find_modules(model, mclass=nn.Conv2d): def sparsity(model): # Return global model sparsity - a, b = 0., 0. + a, b = 0, 0 for p in model.parameters(): a += p.numel() b += (p == 0).sum() @@ -213,42 +217,23 @@ def model_info(model, verbose=False, img_size=640): n_p = sum(x.numel() for x in model.parameters()) # number parameters n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients if verbose: - print('%5s %40s %9s %12s %20s %10s %10s' % ('layer', 'name', 'gradient', 'parameters', 'shape', 'mu', 'sigma')) + print(f"{'layer':>5} {'name':>40} {'gradient':>9} {'parameters':>12} {'shape':>20} {'mu':>10} {'sigma':>10}") for i, (name, p) in enumerate(model.named_parameters()): name = name.replace('module_list.', '') print('%5g %40s %9s %12g %20s %10.3g %10.3g' % (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) - try: # FLOPS + try: # FLOPs from thop import profile stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32 img = torch.zeros((1, model.yaml.get('ch', 3), stride, stride), device=next(model.parameters()).device) # input - flops = profile(deepcopy(model), inputs=(img,), verbose=False)[0] / 1E9 * 2 # stride GFLOPS + flops = profile(deepcopy(model), inputs=(img,), verbose=False)[0] / 1E9 * 2 # stride GFLOPs img_size = img_size if isinstance(img_size, list) else [img_size, img_size] # expand if int/float - fs = ', %.1f GFLOPS' % (flops * img_size[0] / stride * img_size[1] / stride) # 640x640 GFLOPS + fs = ', %.1f GFLOPs' % (flops * img_size[0] / stride * img_size[1] / stride) # 640x640 GFLOPs except (ImportError, Exception): fs = '' - logger.info(f"Model Summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}") - - -def load_classifier(name='resnet101', n=2): - # Loads a pretrained model reshaped to n-class output - model = torchvision.models.__dict__[name](pretrained=True) - - # ResNet model properties - # input_size = [3, 224, 224] - # input_space = 'RGB' - # input_range = [0, 1] - # mean = [0.485, 0.456, 0.406] - # std = [0.229, 0.224, 0.225] - - # Reshape output to n classes - filters = model.fc.weight.shape[1] - model.fc.bias = nn.Parameter(torch.zeros(n), requires_grad=True) - model.fc.weight = nn.Parameter(torch.zeros(n, filters), requires_grad=True) - model.fc.out_features = n - return model + LOGGER.info(f"Model Summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}") def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416) @@ -260,7 +245,7 @@ def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416) s = (int(h * ratio), int(w * ratio)) # new size img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize if not same_shape: # pad/crop img - h, w = [math.ceil(x * ratio / gs) * gs for x in (h, w)] + h, w = (math.ceil(x * ratio / gs) * gs for x in (h, w)) return F.pad(img, [0, w - s[1], 0, h - s[0]], value=0.447) # value = imagenet mean @@ -273,6 +258,29 @@ def copy_attr(a, b, include=(), exclude=()): setattr(a, k, v) +class EarlyStopping: + # simple early stopper + def __init__(self, patience=30): + self.best_fitness = 0.0 # i.e. mAP + self.best_epoch = 0 + self.patience = patience or float('inf') # epochs to wait after fitness stops improving to stop + self.possible_stop = False # possible stop may occur next epoch + + def __call__(self, epoch, fitness): + if fitness >= self.best_fitness: # >= 0 to allow for early zero-fitness stage of training + self.best_epoch = epoch + self.best_fitness = fitness + delta = epoch - self.best_epoch # epochs without improvement + self.possible_stop = delta >= (self.patience - 1) # possible stop may occur next epoch + stop = delta >= self.patience # stop training if patience exceeded + if stop: + LOGGER.info(f'Stopping training early as no improvement observed in last {self.patience} epochs. ' + f'Best results observed at epoch {self.best_epoch}, best model saved as best.pt.\n' + f'To update EarlyStopping(patience={self.patience}) pass a new patience value, ' + f'i.e. `python train.py --patience 300` or use `--patience 0` to disable EarlyStopping.') + return stop + + class ModelEMA: """ Model Exponential Moving Average from https://github.com/rwightman/pytorch-image-models Keep a moving average of everything in the model state_dict (parameters and buffers). @@ -303,7 +311,7 @@ def update(self, model): for k, v in self.ema.state_dict().items(): if v.dtype.is_floating_point: v *= d - v += (1. - d) * msd[k].detach() + v += (1 - d) * msd[k].detach() def update_attr(self, model, include=(), exclude=('process_group', 'reducer')): # Update EMA attributes diff --git a/utils/wandb_logging/__init__.py b/utils/wandb_logging/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/utils/wandb_logging/wandb_utils.py b/utils/wandb_logging/wandb_utils.py deleted file mode 100644 index 12bd320cc3..0000000000 --- a/utils/wandb_logging/wandb_utils.py +++ /dev/null @@ -1,318 +0,0 @@ -"""Utilities and tools for tracking runs with Weights & Biases.""" -import json -import sys -from pathlib import Path - -import torch -import yaml -from tqdm import tqdm - -sys.path.append(str(Path(__file__).parent.parent.parent)) # add utils/ to path -from utils.datasets import LoadImagesAndLabels -from utils.datasets import img2label_paths -from utils.general import colorstr, xywh2xyxy, check_dataset, check_file - -try: - import wandb - from wandb import init, finish -except ImportError: - wandb = None - -WANDB_ARTIFACT_PREFIX = 'wandb-artifact://' - - -def remove_prefix(from_string, prefix=WANDB_ARTIFACT_PREFIX): - return from_string[len(prefix):] - - -def check_wandb_config_file(data_config_file): - wandb_config = '_wandb.'.join(data_config_file.rsplit('.', 1)) # updated data.yaml path - if Path(wandb_config).is_file(): - return wandb_config - return data_config_file - - -def get_run_info(run_path): - run_path = Path(remove_prefix(run_path, WANDB_ARTIFACT_PREFIX)) - run_id = run_path.stem - project = run_path.parent.stem - entity = run_path.parent.parent.stem - model_artifact_name = 'run_' + run_id + '_model' - return entity, project, run_id, model_artifact_name - - -def check_wandb_resume(opt): - process_wandb_config_ddp_mode(opt) if opt.global_rank not in [-1, 0] else None - if isinstance(opt.resume, str): - if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): - if opt.global_rank not in [-1, 0]: # For resuming DDP runs - entity, project, run_id, model_artifact_name = get_run_info(opt.resume) - api = wandb.Api() - artifact = api.artifact(entity + '/' + project + '/' + model_artifact_name + ':latest') - modeldir = artifact.download() - opt.weights = str(Path(modeldir) / "last.pt") - return True - return None - - -def process_wandb_config_ddp_mode(opt): - with open(check_file(opt.data)) as f: - data_dict = yaml.safe_load(f) # data dict - train_dir, val_dir = None, None - if isinstance(data_dict['train'], str) and data_dict['train'].startswith(WANDB_ARTIFACT_PREFIX): - api = wandb.Api() - train_artifact = api.artifact(remove_prefix(data_dict['train']) + ':' + opt.artifact_alias) - train_dir = train_artifact.download() - train_path = Path(train_dir) / 'data/images/' - data_dict['train'] = str(train_path) - - if isinstance(data_dict['val'], str) and data_dict['val'].startswith(WANDB_ARTIFACT_PREFIX): - api = wandb.Api() - val_artifact = api.artifact(remove_prefix(data_dict['val']) + ':' + opt.artifact_alias) - val_dir = val_artifact.download() - val_path = Path(val_dir) / 'data/images/' - data_dict['val'] = str(val_path) - if train_dir or val_dir: - ddp_data_path = str(Path(val_dir) / 'wandb_local_data.yaml') - with open(ddp_data_path, 'w') as f: - yaml.safe_dump(data_dict, f) - opt.data = ddp_data_path - - -class WandbLogger(): - """Log training runs, datasets, models, and predictions to Weights & Biases. - - This logger sends information to W&B at wandb.ai. By default, this information - includes hyperparameters, system configuration and metrics, model metrics, - and basic data metrics and analyses. - - By providing additional command line arguments to train.py, datasets, - models and predictions can also be logged. - - For more on how this logger is used, see the Weights & Biases documentation: - https://docs.wandb.com/guides/integrations/yolov5 - """ - def __init__(self, opt, name, run_id, data_dict, job_type='Training'): - # Pre-training routine -- - self.job_type = job_type - self.wandb, self.wandb_run, self.data_dict = wandb, None if not wandb else wandb.run, data_dict - # It's more elegant to stick to 1 wandb.init call, but useful config data is overwritten in the WandbLogger's wandb.init call - if isinstance(opt.resume, str): # checks resume from artifact - if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): - entity, project, run_id, model_artifact_name = get_run_info(opt.resume) - model_artifact_name = WANDB_ARTIFACT_PREFIX + model_artifact_name - assert wandb, 'install wandb to resume wandb runs' - # Resume wandb-artifact:// runs here| workaround for not overwriting wandb.config - self.wandb_run = wandb.init(id=run_id, project=project, entity=entity, resume='allow') - opt.resume = model_artifact_name - elif self.wandb: - self.wandb_run = wandb.init(config=opt, - resume="allow", - project='YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem, - entity=opt.entity, - name=name, - job_type=job_type, - id=run_id) if not wandb.run else wandb.run - if self.wandb_run: - if self.job_type == 'Training': - if not opt.resume: - wandb_data_dict = self.check_and_upload_dataset(opt) if opt.upload_dataset else data_dict - # Info useful for resuming from artifacts - self.wandb_run.config.opt = vars(opt) - self.wandb_run.config.data_dict = wandb_data_dict - self.data_dict = self.setup_training(opt, data_dict) - if self.job_type == 'Dataset Creation': - self.data_dict = self.check_and_upload_dataset(opt) - else: - prefix = colorstr('wandb: ') - print(f"{prefix}Install Weights & Biases for YOLOv3 logging with 'pip install wandb' (recommended)") - - def check_and_upload_dataset(self, opt): - assert wandb, 'Install wandb to upload dataset' - check_dataset(self.data_dict) - config_path = self.log_dataset_artifact(check_file(opt.data), - opt.single_cls, - 'YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem) - print("Created dataset config file ", config_path) - with open(config_path) as f: - wandb_data_dict = yaml.safe_load(f) - return wandb_data_dict - - def setup_training(self, opt, data_dict): - self.log_dict, self.current_epoch, self.log_imgs = {}, 0, 16 # Logging Constants - self.bbox_interval = opt.bbox_interval - if isinstance(opt.resume, str): - modeldir, _ = self.download_model_artifact(opt) - if modeldir: - self.weights = Path(modeldir) / "last.pt" - config = self.wandb_run.config - opt.weights, opt.save_period, opt.batch_size, opt.bbox_interval, opt.epochs, opt.hyp = str( - self.weights), config.save_period, config.total_batch_size, config.bbox_interval, config.epochs, \ - config.opt['hyp'] - data_dict = dict(self.wandb_run.config.data_dict) # eliminates the need for config file to resume - if 'val_artifact' not in self.__dict__: # If --upload_dataset is set, use the existing artifact, don't download - self.train_artifact_path, self.train_artifact = self.download_dataset_artifact(data_dict.get('train'), - opt.artifact_alias) - self.val_artifact_path, self.val_artifact = self.download_dataset_artifact(data_dict.get('val'), - opt.artifact_alias) - self.result_artifact, self.result_table, self.val_table, self.weights = None, None, None, None - if self.train_artifact_path is not None: - train_path = Path(self.train_artifact_path) / 'data/images/' - data_dict['train'] = str(train_path) - if self.val_artifact_path is not None: - val_path = Path(self.val_artifact_path) / 'data/images/' - data_dict['val'] = str(val_path) - self.val_table = self.val_artifact.get("val") - self.map_val_table_path() - if self.val_artifact is not None: - self.result_artifact = wandb.Artifact("run_" + wandb.run.id + "_progress", "evaluation") - self.result_table = wandb.Table(["epoch", "id", "prediction", "avg_confidence"]) - if opt.bbox_interval == -1: - self.bbox_interval = opt.bbox_interval = (opt.epochs // 10) if opt.epochs > 10 else 1 - return data_dict - - def download_dataset_artifact(self, path, alias): - if isinstance(path, str) and path.startswith(WANDB_ARTIFACT_PREFIX): - artifact_path = Path(remove_prefix(path, WANDB_ARTIFACT_PREFIX) + ":" + alias) - dataset_artifact = wandb.use_artifact(artifact_path.as_posix()) - assert dataset_artifact is not None, "'Error: W&B dataset artifact doesn\'t exist'" - datadir = dataset_artifact.download() - return datadir, dataset_artifact - return None, None - - def download_model_artifact(self, opt): - if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): - model_artifact = wandb.use_artifact(remove_prefix(opt.resume, WANDB_ARTIFACT_PREFIX) + ":latest") - assert model_artifact is not None, 'Error: W&B model artifact doesn\'t exist' - modeldir = model_artifact.download() - epochs_trained = model_artifact.metadata.get('epochs_trained') - total_epochs = model_artifact.metadata.get('total_epochs') - is_finished = total_epochs is None - assert not is_finished, 'training is finished, can only resume incomplete runs.' - return modeldir, model_artifact - return None, None - - def log_model(self, path, opt, epoch, fitness_score, best_model=False): - model_artifact = wandb.Artifact('run_' + wandb.run.id + '_model', type='model', metadata={ - 'original_url': str(path), - 'epochs_trained': epoch + 1, - 'save period': opt.save_period, - 'project': opt.project, - 'total_epochs': opt.epochs, - 'fitness_score': fitness_score - }) - model_artifact.add_file(str(path / 'last.pt'), name='last.pt') - wandb.log_artifact(model_artifact, - aliases=['latest', 'last', 'epoch ' + str(self.current_epoch), 'best' if best_model else '']) - print("Saving model artifact on epoch ", epoch + 1) - - def log_dataset_artifact(self, data_file, single_cls, project, overwrite_config=False): - with open(data_file) as f: - data = yaml.safe_load(f) # data dict - nc, names = (1, ['item']) if single_cls else (int(data['nc']), data['names']) - names = {k: v for k, v in enumerate(names)} # to index dictionary - self.train_artifact = self.create_dataset_table(LoadImagesAndLabels( - data['train'], rect=True, batch_size=1), names, name='train') if data.get('train') else None - self.val_artifact = self.create_dataset_table(LoadImagesAndLabels( - data['val'], rect=True, batch_size=1), names, name='val') if data.get('val') else None - if data.get('train'): - data['train'] = WANDB_ARTIFACT_PREFIX + str(Path(project) / 'train') - if data.get('val'): - data['val'] = WANDB_ARTIFACT_PREFIX + str(Path(project) / 'val') - path = data_file if overwrite_config else '_wandb.'.join(data_file.rsplit('.', 1)) # updated data.yaml path - data.pop('download', None) - with open(path, 'w') as f: - yaml.safe_dump(data, f) - - if self.job_type == 'Training': # builds correct artifact pipeline graph - self.wandb_run.use_artifact(self.val_artifact) - self.wandb_run.use_artifact(self.train_artifact) - self.val_artifact.wait() - self.val_table = self.val_artifact.get('val') - self.map_val_table_path() - else: - self.wandb_run.log_artifact(self.train_artifact) - self.wandb_run.log_artifact(self.val_artifact) - return path - - def map_val_table_path(self): - self.val_table_map = {} - print("Mapping dataset") - for i, data in enumerate(tqdm(self.val_table.data)): - self.val_table_map[data[3]] = data[0] - - def create_dataset_table(self, dataset, class_to_id, name='dataset'): - # TODO: Explore multiprocessing to slpit this loop parallely| This is essential for speeding up the the logging - artifact = wandb.Artifact(name=name, type="dataset") - img_files = tqdm([dataset.path]) if isinstance(dataset.path, str) and Path(dataset.path).is_dir() else None - img_files = tqdm(dataset.img_files) if not img_files else img_files - for img_file in img_files: - if Path(img_file).is_dir(): - artifact.add_dir(img_file, name='data/images') - labels_path = 'labels'.join(dataset.path.rsplit('images', 1)) - artifact.add_dir(labels_path, name='data/labels') - else: - artifact.add_file(img_file, name='data/images/' + Path(img_file).name) - label_file = Path(img2label_paths([img_file])[0]) - artifact.add_file(str(label_file), - name='data/labels/' + label_file.name) if label_file.exists() else None - table = wandb.Table(columns=["id", "train_image", "Classes", "name"]) - class_set = wandb.Classes([{'id': id, 'name': name} for id, name in class_to_id.items()]) - for si, (img, labels, paths, shapes) in enumerate(tqdm(dataset)): - box_data, img_classes = [], {} - for cls, *xywh in labels[:, 1:].tolist(): - cls = int(cls) - box_data.append({"position": {"middle": [xywh[0], xywh[1]], "width": xywh[2], "height": xywh[3]}, - "class_id": cls, - "box_caption": "%s" % (class_to_id[cls])}) - img_classes[cls] = class_to_id[cls] - boxes = {"ground_truth": {"box_data": box_data, "class_labels": class_to_id}} # inference-space - table.add_data(si, wandb.Image(paths, classes=class_set, boxes=boxes), json.dumps(img_classes), - Path(paths).name) - artifact.add(table, name) - return artifact - - def log_training_progress(self, predn, path, names): - if self.val_table and self.result_table: - class_set = wandb.Classes([{'id': id, 'name': name} for id, name in names.items()]) - box_data = [] - total_conf = 0 - for *xyxy, conf, cls in predn.tolist(): - if conf >= 0.25: - box_data.append( - {"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, - "class_id": int(cls), - "box_caption": "%s %.3f" % (names[cls], conf), - "scores": {"class_score": conf}, - "domain": "pixel"}) - total_conf = total_conf + conf - boxes = {"predictions": {"box_data": box_data, "class_labels": names}} # inference-space - id = self.val_table_map[Path(path).name] - self.result_table.add_data(self.current_epoch, - id, - wandb.Image(self.val_table.data[id][1], boxes=boxes, classes=class_set), - total_conf / max(1, len(box_data)) - ) - - def log(self, log_dict): - if self.wandb_run: - for key, value in log_dict.items(): - self.log_dict[key] = value - - def end_epoch(self, best_result=False): - if self.wandb_run: - wandb.log(self.log_dict) - self.log_dict = {} - if self.result_artifact: - train_results = wandb.JoinedTable(self.val_table, self.result_table, "id") - self.result_artifact.add(train_results, 'result') - wandb.log_artifact(self.result_artifact, aliases=['latest', 'last', 'epoch ' + str(self.current_epoch), - ('best' if best_result else '')]) - self.result_table = wandb.Table(["epoch", "id", "prediction", "avg_confidence"]) - self.result_artifact = wandb.Artifact("run_" + wandb.run.id + "_progress", "evaluation") - - def finish_run(self): - if self.wandb_run: - if self.log_dict: - wandb.log(self.log_dict) - wandb.run.finish() diff --git a/val.py b/val.py new file mode 100644 index 0000000000..24b28ad186 --- /dev/null +++ b/val.py @@ -0,0 +1,367 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Validate a trained model accuracy on a custom dataset + +Usage: + $ python path/to/val.py --data coco128.yaml --weights yolov3.pt --img 640 +""" + +import argparse +import json +import os +import sys +from pathlib import Path +from threading import Thread + +import numpy as np +import torch +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.callbacks import Callbacks +from utils.datasets import create_dataloader +from utils.general import (LOGGER, NCOLS, box_iou, check_dataset, check_img_size, check_requirements, check_yaml, + coco80_to_coco91_class, colorstr, increment_path, non_max_suppression, print_args, + scale_coords, xywh2xyxy, xyxy2xywh) +from utils.metrics import ConfusionMatrix, ap_per_class +from utils.plots import output_to_target, plot_images, plot_val_study +from utils.torch_utils import select_device, time_sync + + +def save_one_txt(predn, save_conf, shape, file): + # Save one txt result + gn = torch.tensor(shape)[[1, 0, 1, 0]] # normalization gain whwh + for *xyxy, conf, cls in predn.tolist(): + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format + with open(file, 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + +def save_one_json(predn, jdict, path, class_map): + # Save one JSON result {"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236} + image_id = int(path.stem) if path.stem.isnumeric() else path.stem + box = xyxy2xywh(predn[:, :4]) # xywh + box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner + for p, b in zip(predn.tolist(), box.tolist()): + jdict.append({'image_id': image_id, + 'category_id': class_map[int(p[5])], + 'bbox': [round(x, 3) for x in b], + 'score': round(p[4], 5)}) + + +def process_batch(detections, labels, iouv): + """ + Return correct predictions matrix. Both sets of boxes are in (x1, y1, x2, y2) format. + Arguments: + detections (Array[N, 6]), x1, y1, x2, y2, conf, class + labels (Array[M, 5]), class, x1, y1, x2, y2 + Returns: + correct (Array[N, 10]), for 10 IoU levels + """ + correct = torch.zeros(detections.shape[0], iouv.shape[0], dtype=torch.bool, device=iouv.device) + iou = box_iou(labels[:, 1:], detections[:, :4]) + x = torch.where((iou >= iouv[0]) & (labels[:, 0:1] == detections[:, 5])) # IoU above threshold and classes match + if x[0].shape[0]: + matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() # [label, detection, iou] + if x[0].shape[0] > 1: + matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 1], return_index=True)[1]] + # matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 0], return_index=True)[1]] + matches = torch.Tensor(matches).to(iouv.device) + correct[matches[:, 1].long()] = matches[:, 2:3] >= iouv + return correct + + +@torch.no_grad() +def run(data, + weights=None, # model.pt path(s) + batch_size=32, # batch size + imgsz=640, # inference size (pixels) + conf_thres=0.001, # confidence threshold + iou_thres=0.6, # NMS IoU threshold + task='val', # train, val, test, speed or study + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + single_cls=False, # treat as single-class dataset + augment=False, # augmented inference + verbose=False, # verbose output + save_txt=False, # save results to *.txt + save_hybrid=False, # save label+prediction hybrid results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_json=False, # save a COCO-JSON results file + project=ROOT / 'runs/val', # save to project/name + name='exp', # save to project/name + exist_ok=False, # existing project/name ok, do not increment + half=True, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + model=None, + dataloader=None, + save_dir=Path(''), + plots=True, + callbacks=Callbacks(), + compute_loss=None, + ): + # Initialize/load model and set device + training = model is not None + if training: # called by train.py + device, pt = next(model.parameters()).device, True # get model device, PyTorch model + + half &= device.type != 'cpu' # half precision only supported on CUDA + model.half() if half else model.float() + else: # called directly + device = select_device(device, batch_size=batch_size) + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + model = DetectMultiBackend(weights, device=device, dnn=dnn) + stride, pt = model.stride, model.pt + imgsz = check_img_size(imgsz, s=stride) # check image size + half &= pt and device.type != 'cpu' # half precision only supported by PyTorch on CUDA + if pt: + model.model.half() if half else model.model.float() + else: + half = False + batch_size = 1 # export.py models default to batch-size 1 + device = torch.device('cpu') + LOGGER.info(f'Forcing --batch-size 1 square inference shape(1,3,{imgsz},{imgsz}) for non-PyTorch backends') + + # Data + data = check_dataset(data) # check + + # Configure + model.eval() + is_coco = isinstance(data.get('val'), str) and data['val'].endswith('coco/val2017.txt') # COCO dataset + nc = 1 if single_cls else int(data['nc']) # number of classes + iouv = torch.linspace(0.5, 0.95, 10).to(device) # iou vector for mAP@0.5:0.95 + niou = iouv.numel() + + # Dataloader + if not training: + if pt and device.type != 'cpu': + model(torch.zeros(1, 3, imgsz, imgsz).to(device).type_as(next(model.model.parameters()))) # warmup + pad = 0.0 if task == 'speed' else 0.5 + task = task if task in ('train', 'val', 'test') else 'val' # path to train/val/test images + dataloader = create_dataloader(data[task], imgsz, batch_size, stride, single_cls, pad=pad, rect=pt, + prefix=colorstr(f'{task}: '))[0] + + seen = 0 + confusion_matrix = ConfusionMatrix(nc=nc) + names = {k: v for k, v in enumerate(model.names if hasattr(model, 'names') else model.module.names)} + class_map = coco80_to_coco91_class() if is_coco else list(range(1000)) + s = ('%20s' + '%11s' * 6) % ('Class', 'Images', 'Labels', 'P', 'R', 'mAP@.5', 'mAP@.5:.95') + dt, p, r, f1, mp, mr, map50, map = [0.0, 0.0, 0.0], 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + loss = torch.zeros(3, device=device) + jdict, stats, ap, ap_class = [], [], [], [] + pbar = tqdm(dataloader, desc=s, ncols=NCOLS, bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}') # progress bar + for batch_i, (im, targets, paths, shapes) in enumerate(pbar): + t1 = time_sync() + if pt: + im = im.to(device, non_blocking=True) + targets = targets.to(device) + im = im.half() if half else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + nb, _, height, width = im.shape # batch size, channels, height, width + t2 = time_sync() + dt[0] += t2 - t1 + + # Inference + out, train_out = model(im) if training else model(im, augment=augment, val=True) # inference, loss outputs + dt[1] += time_sync() - t2 + + # Loss + if compute_loss: + loss += compute_loss([x.float() for x in train_out], targets)[1] # box, obj, cls + + # NMS + targets[:, 2:] *= torch.Tensor([width, height, width, height]).to(device) # to pixels + lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling + t3 = time_sync() + out = non_max_suppression(out, conf_thres, iou_thres, labels=lb, multi_label=True, agnostic=single_cls) + dt[2] += time_sync() - t3 + + # Metrics + for si, pred in enumerate(out): + labels = targets[targets[:, 0] == si, 1:] + nl = len(labels) + tcls = labels[:, 0].tolist() if nl else [] # target class + path, shape = Path(paths[si]), shapes[si][0] + seen += 1 + + if len(pred) == 0: + if nl: + stats.append((torch.zeros(0, niou, dtype=torch.bool), torch.Tensor(), torch.Tensor(), tcls)) + continue + + # Predictions + if single_cls: + pred[:, 5] = 0 + predn = pred.clone() + scale_coords(im[si].shape[1:], predn[:, :4], shape, shapes[si][1]) # native-space pred + + # Evaluate + if nl: + tbox = xywh2xyxy(labels[:, 1:5]) # target boxes + scale_coords(im[si].shape[1:], tbox, shape, shapes[si][1]) # native-space labels + labelsn = torch.cat((labels[:, 0:1], tbox), 1) # native-space labels + correct = process_batch(predn, labelsn, iouv) + if plots: + confusion_matrix.process_batch(predn, labelsn) + else: + correct = torch.zeros(pred.shape[0], niou, dtype=torch.bool) + stats.append((correct.cpu(), pred[:, 4].cpu(), pred[:, 5].cpu(), tcls)) # (correct, conf, pcls, tcls) + + # Save/log + if save_txt: + save_one_txt(predn, save_conf, shape, file=save_dir / 'labels' / (path.stem + '.txt')) + if save_json: + save_one_json(predn, jdict, path, class_map) # append to COCO-JSON dictionary + callbacks.run('on_val_image_end', pred, predn, path, names, im[si]) + + # Plot images + if plots and batch_i < 3: + f = save_dir / f'val_batch{batch_i}_labels.jpg' # labels + Thread(target=plot_images, args=(im, targets, paths, f, names), daemon=True).start() + f = save_dir / f'val_batch{batch_i}_pred.jpg' # predictions + Thread(target=plot_images, args=(im, output_to_target(out), paths, f, names), daemon=True).start() + + # Compute metrics + stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy + if len(stats) and stats[0].any(): + p, r, ap, f1, ap_class = ap_per_class(*stats, plot=plots, save_dir=save_dir, names=names) + ap50, ap = ap[:, 0], ap.mean(1) # AP@0.5, AP@0.5:0.95 + mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean() + nt = np.bincount(stats[3].astype(np.int64), minlength=nc) # number of targets per class + else: + nt = torch.zeros(1) + + # Print results + pf = '%20s' + '%11i' * 2 + '%11.3g' * 4 # print format + LOGGER.info(pf % ('all', seen, nt.sum(), mp, mr, map50, map)) + + # Print results per class + if (verbose or (nc < 50 and not training)) and nc > 1 and len(stats): + for i, c in enumerate(ap_class): + LOGGER.info(pf % (names[c], seen, nt[c], p[i], r[i], ap50[i], ap[i])) + + # Print speeds + t = tuple(x / seen * 1E3 for x in dt) # speeds per image + if not training: + shape = (batch_size, 3, imgsz, imgsz) + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {shape}' % t) + + # Plots + if plots: + confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) + callbacks.run('on_val_end') + + # Save JSON + if save_json and len(jdict): + w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights + anno_json = str(Path(data.get('path', '../coco')) / 'annotations/instances_val2017.json') # annotations json + pred_json = str(save_dir / f"{w}_predictions.json") # predictions json + LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') + with open(pred_json, 'w') as f: + json.dump(jdict, f) + + try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb + check_requirements(['pycocotools']) + from pycocotools.coco import COCO + from pycocotools.cocoeval import COCOeval + + anno = COCO(anno_json) # init annotations api + pred = anno.loadRes(pred_json) # init predictions api + eval = COCOeval(anno, pred, 'bbox') + if is_coco: + eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.img_files] # image IDs to evaluate + eval.evaluate() + eval.accumulate() + eval.summarize() + map, map50 = eval.stats[:2] # update results (mAP@0.5:0.95, mAP@0.5) + except Exception as e: + LOGGER.info(f'pycocotools unable to run: {e}') + + # Return results + model.float() # for training + if not training: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + maps = np.zeros(nc) + map + for i, c in enumerate(ap_class): + maps[c] = ap[i] + return (mp, mr, map50, map, *(loss.cpu() / len(dataloader)).tolist()), maps, t + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov3.pt', help='model.pt path(s)') + parser.add_argument('--batch-size', type=int, default=32, help='batch size') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') + parser.add_argument('--conf-thres', type=float, default=0.001, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.6, help='NMS IoU threshold') + parser.add_argument('--task', default='val', help='train, val, test, speed or study') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--verbose', action='store_true', help='report mAP by class') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-hybrid', action='store_true', help='save label+prediction hybrid results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-json', action='store_true', help='save a COCO-JSON results file') + parser.add_argument('--project', default=ROOT / 'runs/val', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + opt = parser.parse_args() + opt.data = check_yaml(opt.data) # check YAML + opt.save_json |= opt.data.endswith('coco.yaml') + opt.save_txt |= opt.save_hybrid + print_args(FILE.stem, opt) + return opt + + +def main(opt): + check_requirements(requirements=ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + + if opt.task in ('train', 'val', 'test'): # run normally + if opt.conf_thres > 0.001: # https://github.com/ultralytics/yolov5/issues/1466 + LOGGER.info(f'WARNING: confidence threshold {opt.conf_thres} >> 0.001 will produce invalid mAP values.') + run(**vars(opt)) + + else: + weights = opt.weights if isinstance(opt.weights, list) else [opt.weights] + opt.half = True # FP16 for fastest results + if opt.task == 'speed': # speed benchmarks + # python val.py --task speed --data coco.yaml --batch 1 --weights yolov3.pt yolov3-spp.pt... + opt.conf_thres, opt.iou_thres, opt.save_json = 0.25, 0.45, False + for opt.weights in weights: + run(**vars(opt), plots=False) + + elif opt.task == 'study': # speed vs mAP benchmarks + # python val.py --task study --data coco.yaml --iou 0.7 --weights yolov3.pt yolov3-spp.pt... + for opt.weights in weights: + f = f'study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt' # filename to save to + x, y = list(range(256, 1536 + 128, 128)), [] # x axis (image sizes), y axis + for opt.imgsz in x: # img-size + LOGGER.info(f'\nRunning {f} --imgsz {opt.imgsz}...') + r, _, t = run(**vars(opt), plots=False) + y.append(r + t) # results and times + np.savetxt(f, y, fmt='%10.4g') # save + os.system('zip -r study.zip study_*.txt') + plot_val_study(x=x) # plot + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/weights/download_weights.sh b/weights/download_weights.sh deleted file mode 100755 index 6bb58023c9..0000000000 --- a/weights/download_weights.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -# Download latest models from https://github.com/ultralytics/yolov3/releases -# Usage: -# $ bash weights/download_weights.sh - -python - < Date: Sun, 14 Nov 2021 22:33:34 +0100 Subject: [PATCH 0895/1185] Created using Colaboratory --- tutorial.ipynb | 189 ++++++++++++++++++++++++------------------------- 1 file changed, 94 insertions(+), 95 deletions(-) diff --git a/tutorial.ipynb b/tutorial.ipynb index 828e434f6b..4e7049d823 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -368,7 +368,7 @@ "colab_type": "text" }, "source": [ - "\"Open" + "\"Open" ] }, { @@ -402,10 +402,10 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "2e5d0950-2978-4304-856f-3b39f0d6627c" + "outputId": "b15def02-a331-4580-9878-8d06900e296d" }, "source": [ - "!git clone https://github.com/ultralytics/yolov3 -b update/yolov5_v6.0_release # clone\n", + "!git clone https://github.com/ultralytics/yolov3 # clone\n", "%cd yolov3\n", "%pip install -qr requirements.txt # install\n", "\n", @@ -413,13 +413,13 @@ "from yolov3 import utils\n", "display = utils.notebook_init() # checks" ], - "execution_count": 1, + "execution_count": 11, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ - "YOLOv3 🚀 v9.5.0-20-g9d10fe5 torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n" + "YOLOv3 🚀 v9.6.0-0-g7eb23e3 torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n" ] }, { @@ -459,26 +459,26 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "499c53a7-95f7-4fc1-dab8-7a660b813546" + "outputId": "5754dd6d-b5b0-41aa-ce81-7cc7a4c30553" }, "source": [ "!python detect.py --weights yolov3.pt --img 640 --conf 0.25 --source data/images\n", "display.Image(filename='runs/detect/exp/zidane.jpg', width=600)" ], - "execution_count": 3, + "execution_count": 15, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\u001b[34m\u001b[1mdetect: \u001b[0mweights=['yolov3.pt'], source=data/images, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False\n", - "YOLOv3 🚀 v9.5.0-20-g9d10fe5 torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n", + "YOLOv3 🚀 v9.6.0-0-g7eb23e3 torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n", "\n", "Fusing layers... \n", "Model Summary: 261 layers, 61922845 parameters, 0 gradients\n", "image 1/2 /content/yolov3/data/images/bus.jpg: 640x480 4 persons, 1 bus, 1 tie, Done. (0.020s)\n", "image 2/2 /content/yolov3/data/images/zidane.jpg: 384x640 2 persons, 3 ties, Done. (0.020s)\n", - "Speed: 0.5ms pre-process, 19.8ms inference, 1.2ms NMS per image at shape (1, 3, 640, 640)\n", + "Speed: 0.6ms pre-process, 20.0ms inference, 1.2ms NMS per image at shape (1, 3, 640, 640)\n", "Results saved to \u001b[1mruns/detect/exp\u001b[0m\n" ] } @@ -567,43 +567,42 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "0f4cfe4e-364e-4d79-e0af-8884d89eaacd" + "outputId": "fe3159ef-a2e4-49e3-ec0b-2ef434e9a28e" }, "source": [ "# Run YOLOv3 on COCO val\n", "!python val.py --weights yolov3.pt --data coco.yaml --img 640 --iou 0.65 --half" ], - "execution_count": 5, + "execution_count": 13, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\u001b[34m\u001b[1mval: \u001b[0mdata=/content/yolov3/data/coco.yaml, weights=['yolov3.pt'], batch_size=32, imgsz=640, conf_thres=0.001, iou_thres=0.65, task=val, device=, single_cls=False, augment=False, verbose=False, save_txt=False, save_hybrid=False, save_conf=False, save_json=True, project=runs/val, name=exp, exist_ok=False, half=True, dnn=False\n", - "YOLOv3 🚀 v9.5.0-20-g9d10fe5 torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n", + "YOLOv3 🚀 v9.6.0-0-g7eb23e3 torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n", "\n", "Fusing layers... \n", "Model Summary: 261 layers, 61922845 parameters, 0 gradients\n", - "\u001b[34m\u001b[1mval: \u001b[0mScanning '../datasets/coco/val2017' images and labels...4952 found, 48 missing, 0 empty, 0 corrupted: 100% 5000/5000 [00:00<00:00, 12689.82it/s]\n", - "\u001b[34m\u001b[1mval: \u001b[0mNew cache created: ../datasets/coco/val2017.cache\n", - " Class Images Labels P R mAP@.5 mAP@.5:.95: 100% 157/157 [00:42<00:00, 3.70it/s]\n", + "\u001b[34m\u001b[1mval: \u001b[0mScanning '../datasets/coco/val2017.cache' images and labels... 4952 found, 48 missing, 0 empty, 0 corrupted: 100% 5000/5000 [00:00 Date: Sun, 14 Nov 2021 22:43:14 +0100 Subject: [PATCH 0896/1185] Created using Colaboratory --- tutorial.ipynb | 238 ++++++++++++++++++++++++------------------------- 1 file changed, 119 insertions(+), 119 deletions(-) diff --git a/tutorial.ipynb b/tutorial.ipynb index 4e7049d823..3bc0523c43 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -402,7 +402,7 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "b15def02-a331-4580-9878-8d06900e296d" + "outputId": "7efd38e6-c41f-4fe3-9864-ce4fa43fbb5b" }, "source": [ "!git clone https://github.com/ultralytics/yolov3 # clone\n", @@ -413,13 +413,13 @@ "from yolov3 import utils\n", "display = utils.notebook_init() # checks" ], - "execution_count": 11, + "execution_count": 24, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ - "YOLOv3 🚀 v9.6.0-0-g7eb23e3 torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n" + "YOLOv3 🚀 v9.6.0-1-g93a2bcc torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n" ] }, { @@ -459,26 +459,26 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "5754dd6d-b5b0-41aa-ce81-7cc7a4c30553" + "outputId": "486202a4-bae2-454f-da62-2c74676a3058" }, "source": [ "!python detect.py --weights yolov3.pt --img 640 --conf 0.25 --source data/images\n", "display.Image(filename='runs/detect/exp/zidane.jpg', width=600)" ], - "execution_count": 15, + "execution_count": 22, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\u001b[34m\u001b[1mdetect: \u001b[0mweights=['yolov3.pt'], source=data/images, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False\n", - "YOLOv3 🚀 v9.6.0-0-g7eb23e3 torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n", + "YOLOv3 🚀 v9.6.0-1-g93a2bcc torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n", "\n", "Fusing layers... \n", - "Model Summary: 261 layers, 61922845 parameters, 0 gradients\n", - "image 1/2 /content/yolov3/data/images/bus.jpg: 640x480 4 persons, 1 bus, 1 tie, Done. (0.020s)\n", + "Model Summary: 261 layers, 61922845 parameters, 0 gradients, 156.1 GFLOPs\n", + "image 1/2 /content/yolov3/data/images/bus.jpg: 640x480 4 persons, 1 bus, 1 tie, 1 sports ball, Done. (0.020s)\n", "image 2/2 /content/yolov3/data/images/zidane.jpg: 384x640 2 persons, 3 ties, Done. (0.020s)\n", - "Speed: 0.6ms pre-process, 20.0ms inference, 1.2ms NMS per image at shape (1, 3, 640, 640)\n", + "Speed: 0.5ms pre-process, 20.0ms inference, 1.3ms NMS per image at shape (1, 3, 640, 640)\n", "Results saved to \u001b[1mruns/detect/exp\u001b[0m\n" ] } @@ -567,27 +567,27 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "fe3159ef-a2e4-49e3-ec0b-2ef434e9a28e" + "outputId": "15c92efb-05ec-48e0-b9ef-ff34871354c8" }, "source": [ "# Run YOLOv3 on COCO val\n", "!python val.py --weights yolov3.pt --data coco.yaml --img 640 --iou 0.65 --half" ], - "execution_count": 13, + "execution_count": 23, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\u001b[34m\u001b[1mval: \u001b[0mdata=/content/yolov3/data/coco.yaml, weights=['yolov3.pt'], batch_size=32, imgsz=640, conf_thres=0.001, iou_thres=0.65, task=val, device=, single_cls=False, augment=False, verbose=False, save_txt=False, save_hybrid=False, save_conf=False, save_json=True, project=runs/val, name=exp, exist_ok=False, half=True, dnn=False\n", - "YOLOv3 🚀 v9.6.0-0-g7eb23e3 torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n", + "YOLOv3 🚀 v9.6.0-1-g93a2bcc torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n", "\n", "Fusing layers... \n", - "Model Summary: 261 layers, 61922845 parameters, 0 gradients\n", + "Model Summary: 261 layers, 61922845 parameters, 0 gradients, 156.1 GFLOPs\n", "\u001b[34m\u001b[1mval: \u001b[0mScanning '../datasets/coco/val2017.cache' images and labels... 4952 found, 48 missing, 0 empty, 0 corrupted: 100% 5000/5000 [00:00 Date: Sun, 14 Nov 2021 22:48:38 +0100 Subject: [PATCH 0897/1185] Update tutorial.ipynb (#1859) --- tutorial.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorial.ipynb b/tutorial.ipynb index 3bc0523c43..1450682b87 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -1080,4 +1080,4 @@ "outputs": [] } ] -} \ No newline at end of file +} From c35400cffd2abb126db81648d601216f213c2ba7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 12:05:54 +0100 Subject: [PATCH 0898/1185] Bump actions/cache from 2.1.6 to 2.1.7 (#1867) Bumps [actions/cache](https://github.com/actions/cache) from 2.1.6 to 2.1.7. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2.1.6...v2.1.7) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index e777173374..de8e843a85 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -39,7 +39,7 @@ jobs: python -c "from pip._internal.locations import USER_CACHE_DIR; print('::set-output name=dir::' + USER_CACHE_DIR)" - name: Cache pip - uses: actions/cache@v2.1.6 + uses: actions/cache@v2.1.7 with: path: ${{ steps.pip-cache.outputs.dir }} key: ${{ runner.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('requirements.txt') }} From 9d0e1cf29832ab8e79a1c70bd93bf9b72d52831c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 1 Dec 2021 15:37:56 +0100 Subject: [PATCH 0899/1185] Update requirements.txt (#1869) * Update requirements.txt * Add wandb.errors.UsageError * bug fix --- requirements.txt | 2 +- utils/loggers/__init__.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 22b51fc490..e9843e1788 100755 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ tqdm>=4.41.0 # Logging ------------------------------------- tensorboard>=2.4.1 -# wandb +wandb # Plotting ------------------------------------ pandas>=1.1.4 diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index bf55fec860..a234ce2cf0 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -24,7 +24,10 @@ assert hasattr(wandb, '__version__') # verify package import not local dir if pkg.parse_version(wandb.__version__) >= pkg.parse_version('0.12.2') and RANK in [0, -1]: - wandb_login_success = wandb.login(timeout=30) + try: + wandb_login_success = wandb.login(timeout=30) + except wandb.errors.UsageError: # known non-TTY terminal issue + wandb_login_success = False if not wandb_login_success: wandb = None except (ImportError, AssertionError): From 0f80f2f9054dd06d34c51e73ea1bc5ba808fed18 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Jan 2022 10:33:15 -0800 Subject: [PATCH 0900/1185] [pre-commit.ci] pre-commit suggestions (#1883) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.0.1 → v4.1.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.0.1...v4.1.0) - [github.com/asottile/pyupgrade: v2.23.1 → v2.31.0](https://github.com/asottile/pyupgrade/compare/v2.23.1...v2.31.0) - [github.com/PyCQA/isort: 5.9.3 → 5.10.1](https://github.com/PyCQA/isort/compare/5.9.3...5.10.1) - [github.com/PyCQA/flake8: 3.9.2 → 4.0.1](https://github.com/PyCQA/flake8/compare/3.9.2...4.0.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 48e752f448..526a5609fd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ ci: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.1.0 hooks: - id: end-of-file-fixer - id: trailing-whitespace @@ -24,14 +24,14 @@ repos: - id: check-docstring-first - repo: https://github.com/asottile/pyupgrade - rev: v2.23.1 + rev: v2.31.0 hooks: - id: pyupgrade args: [--py36-plus] name: Upgrade code - repo: https://github.com/PyCQA/isort - rev: 5.9.3 + rev: 5.10.1 hooks: - id: isort name: Sort imports @@ -60,7 +60,7 @@ repos: # - id: yesqa - repo: https://github.com/PyCQA/flake8 - rev: 3.9.2 + rev: 4.0.1 hooks: - id: flake8 name: PEP8 From 0519223a629f0dcf63d7dbc1c2560fe2e1a353ea Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 16 Feb 2022 10:14:23 +0100 Subject: [PATCH 0901/1185] Fix yolov3.yaml remove extra bracket (#1902) * Fix yolov3.yaml remove extra bracket Resolves https://github.com/ultralytics/yolov3/issues/1887#issuecomment-1041135181 * Update yolov3.yaml --- models/yolov3.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/yolov3.yaml b/models/yolov3.yaml index 3d041bb393..8656bb95c1 100644 --- a/models/yolov3.yaml +++ b/models/yolov3.yaml @@ -28,7 +28,7 @@ backbone: # YOLOv3 head head: [[-1, 1, Bottleneck, [1024, False]], - [-1, 1, Conv, [512, [1, 1]]], + [-1, 1, Conv, [512, 1, 1]], [-1, 1, Conv, [1024, 3, 1]], [-1, 1, Conv, [512, 1, 1]], [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large) From e6507907f89a934de191619297f1fceaf60a4a56 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Mar 2022 11:42:59 +0100 Subject: [PATCH 0902/1185] Bump actions/setup-python from 2 to 3 (#1911) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 2 to 3. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index de8e843a85..632e24aae6 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -27,7 +27,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} From b6f6b5b96552072fc413753a167c0bbcb6de7459 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Mar 2022 11:43:15 +0100 Subject: [PATCH 0903/1185] Bump actions/checkout from 2 to 3 (#1912) Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-testing.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/rebase.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 632e24aae6..3ff7120d8f 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -25,7 +25,7 @@ jobs: # Timeout: https://stackoverflow.com/a/59076067/4521646 timeout-minutes: 50 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v3 with: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 67f51f0e8b..8bc88e957a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml index a4db1efb29..75c5754616 100644 --- a/.github/workflows/rebase.yml +++ b/.github/workflows/rebase.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the latest code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: token: ${{ secrets.ACTIONS_TOKEN }} fetch-depth: 0 # otherwise, you will fail to push refs to dest repo From 7093a2b54366fce8e20f0d32732d0f9f4d8a68bd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 10 Mar 2022 12:59:47 +0100 Subject: [PATCH 0904/1185] PyTorch 1.11.0 compatibility updates (#1914) * PyTorch 1.11.0 compatibility updates Resolves `AttributeError: 'Upsample' object has no attribute 'recompute_scale_factor'` first raised in https://github.com/ultralytics/yolov5/issues/5499 and observed in all CI runs on just-released PyTorch 1.11.0. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update experimental.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- models/experimental.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/models/experimental.py b/models/experimental.py index 81fc9bb222..ab8266a13a 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -94,21 +94,22 @@ def attempt_load(weights, map_location=None, inplace=True, fuse=True): model = Ensemble() for w in weights if isinstance(weights, list) else [weights]: ckpt = torch.load(attempt_download(w), map_location=map_location) # load - if fuse: - model.append(ckpt['ema' if ckpt.get('ema') else 'model'].float().fuse().eval()) # FP32 model - else: - model.append(ckpt['ema' if ckpt.get('ema') else 'model'].float().eval()) # without layer fuse + ckpt = (ckpt['ema'] or ckpt['model']).float() # FP32 model + model.append(ckpt.fuse().eval() if fuse else ckpt.eval()) # fused or un-fused model in eval mode # Compatibility updates for m in model.modules(): - if type(m) in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Model]: - m.inplace = inplace # pytorch 1.7.0 compatibility - if type(m) is Detect: + t = type(m) + if t in (nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Model): + m.inplace = inplace # torch 1.7.0 compatibility + if t is Detect: if not isinstance(m.anchor_grid, list): # new Detect Layer compatibility delattr(m, 'anchor_grid') setattr(m, 'anchor_grid', [torch.zeros(1)] * m.nl) - elif type(m) is Conv: - m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility + elif t is Conv: + m._non_persistent_buffers_set = set() # torch 1.6.0 compatibility + elif t is nn.Upsample and not hasattr(m, 'recompute_scale_factor'): + m.recompute_scale_factor = None # torch 1.11.0 compatibility if len(model) == 1: return model[-1] # return model From 9f9e650bf89861574d1356ed6929c52384db6f0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Mar 2022 10:37:53 +0200 Subject: [PATCH 0905/1185] Bump actions/cache from 2.1.7 to 3 (#1920) Bumps [actions/cache](https://github.com/actions/cache) from 2.1.7 to 3. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2.1.7...v3) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 3ff7120d8f..10d6795e26 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -39,7 +39,7 @@ jobs: python -c "from pip._internal.locations import USER_CACHE_DIR; print('::set-output name=dir::' + USER_CACHE_DIR)" - name: Cache pip - uses: actions/cache@v2.1.7 + uses: actions/cache@v3 with: path: ${{ steps.pip-cache.outputs.dir }} key: ${{ runner.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('requirements.txt') }} From 8a372c340c486236b8b22351277d247ab5b93f8d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Apr 2022 22:29:34 +0200 Subject: [PATCH 0906/1185] [pre-commit.ci] pre-commit suggestions (#1924) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v2.31.0 → v2.31.1](https://github.com/asottile/pyupgrade/compare/v2.31.0...v2.31.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 526a5609fd..748f9d716d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: - id: check-docstring-first - repo: https://github.com/asottile/pyupgrade - rev: v2.31.0 + rev: v2.31.1 hooks: - id: pyupgrade args: [--py36-plus] From c2c113e5eb49f009cafbaeaeb0e2b5a8b990a38c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 10:25:41 +0200 Subject: [PATCH 0907/1185] Bump actions/stale from 4 to 5 (#1927) Bumps [actions/stale](https://github.com/actions/stale) from 4 to 5. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 330184e879..008ca0fe6d 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -9,7 +9,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v4 + - uses: actions/stale@v5 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: | From ae37b2daa74c599d640a7b9698eeafd64265f999 Mon Sep 17 00:00:00 2001 From: Sahil Chachra <37156032+SahilChachra@users.noreply.github.com> Date: Mon, 11 Apr 2022 16:10:56 +0530 Subject: [PATCH 0908/1185] Fix ONNX inference code (#1928) --- models/common.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/models/common.py b/models/common.py index 82b348aebb..a76fc62826 100644 --- a/models/common.py +++ b/models/common.py @@ -314,9 +314,11 @@ def __init__(self, weights='yolov3.pt', device=None, dnn=True): net = cv2.dnn.readNetFromONNX(w) elif onnx: # ONNX Runtime LOGGER.info(f'Loading {w} for ONNX Runtime inference...') - check_requirements(('onnx', 'onnxruntime-gpu' if torch.has_cuda else 'onnxruntime')) + cuda = torch.cuda.is_available() + check_requirements(('onnx', 'onnxruntime-gpu' if cuda else 'onnxruntime')) import onnxruntime - session = onnxruntime.InferenceSession(w, None) + providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] if cuda else ['CPUExecutionProvider'] + session = onnxruntime.InferenceSession(w, providers=providers) else: # TensorFlow model (TFLite, pb, saved_model) import tensorflow as tf if pb: # https://www.tensorflow.org/guide/migrate#a_graphpb_or_graphpbtxt From f212505c93c5ddd145705dc50e1dc3e872d67b51 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Apr 2022 15:07:16 -0700 Subject: [PATCH 0909/1185] Bump cirrus-actions/rebase from 1.5 to 1.6 (#1929) Bumps [cirrus-actions/rebase](https://github.com/cirrus-actions/rebase) from 1.5 to 1.6. - [Release notes](https://github.com/cirrus-actions/rebase/releases) - [Commits](https://github.com/cirrus-actions/rebase/compare/1.5...1.6) --- updated-dependencies: - dependency-name: cirrus-actions/rebase dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/rebase.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml index 75c5754616..d79d5cfb20 100644 --- a/.github/workflows/rebase.yml +++ b/.github/workflows/rebase.yml @@ -16,6 +16,6 @@ jobs: token: ${{ secrets.ACTIONS_TOKEN }} fetch-depth: 0 # otherwise, you will fail to push refs to dest repo - name: Automatic Rebase - uses: cirrus-actions/rebase@1.5 + uses: cirrus-actions/rebase@1.6 env: GITHUB_TOKEN: ${{ secrets.ACTIONS_TOKEN }} From d58ba5e7a74256c8bd28ed0a06ec8339441f71ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 22:25:22 -0700 Subject: [PATCH 0910/1185] Bump github/codeql-action from 1 to 2 (#1939) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1 to 2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v1...v2) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8bc88e957a..b6f751096d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -26,7 +26,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -37,7 +37,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -51,4 +51,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 From 3508a982f56779d43b5f5d49d5b63766c82d60ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 10:49:39 +0200 Subject: [PATCH 0911/1185] Bump cirrus-actions/rebase from 1.6 to 1.7 (#1944) Bumps [cirrus-actions/rebase](https://github.com/cirrus-actions/rebase) from 1.6 to 1.7. - [Release notes](https://github.com/cirrus-actions/rebase/releases) - [Commits](https://github.com/cirrus-actions/rebase/compare/1.6...1.7) --- updated-dependencies: - dependency-name: cirrus-actions/rebase dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/rebase.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml index d79d5cfb20..a4dc9e5092 100644 --- a/.github/workflows/rebase.yml +++ b/.github/workflows/rebase.yml @@ -16,6 +16,6 @@ jobs: token: ${{ secrets.ACTIONS_TOKEN }} fetch-depth: 0 # otherwise, you will fail to push refs to dest repo - name: Automatic Rebase - uses: cirrus-actions/rebase@1.6 + uses: cirrus-actions/rebase@1.7 env: GITHUB_TOKEN: ${{ secrets.ACTIONS_TOKEN }} From 0aa65efcc0fbb9067cf0b109f1d9f4f7fe14a7ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 11:41:14 +0200 Subject: [PATCH 0912/1185] Bump actions/setup-python from 3 to 4 (#1956) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 3 to 4. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 10d6795e26..80eab59220 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -27,7 +27,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} From 7ec96149612c396b130c7fea5bb1f7603752e55e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Jun 2022 18:07:06 +0200 Subject: [PATCH 0913/1185] Update loss.py (#1959) * Update loss.py * Update metrics.py * Update loss.py --- utils/loss.py | 90 +++++++++++++++++++++++++++--------------------- utils/metrics.py | 44 +++++++++++------------ 2 files changed, 71 insertions(+), 63 deletions(-) diff --git a/utils/loss.py b/utils/loss.py index dfde60adfd..1f38c36217 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -7,7 +7,7 @@ import torch.nn as nn from utils.metrics import bbox_iou -from utils.torch_utils import is_parallel +from utils.torch_utils import de_parallel def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 @@ -89,9 +89,10 @@ def forward(self, pred, true): class ComputeLoss: + sort_obj_iou = False + # Compute losses def __init__(self, model, autobalance=False): - self.sort_obj_iou = False device = next(model.parameters()).device # get model device h = model.hyp # hyperparameters @@ -107,46 +108,53 @@ def __init__(self, model, autobalance=False): if g > 0: BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) - det = model.module.model[-1] if is_parallel(model) else model.model[-1] # Detect() module - self.balance = {3: [4.0, 1.0, 0.4]}.get(det.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 - self.ssi = list(det.stride).index(16) if autobalance else 0 # stride 16 index + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.ssi = list(m.stride).index(16) if autobalance else 0 # stride 16 index self.BCEcls, self.BCEobj, self.gr, self.hyp, self.autobalance = BCEcls, BCEobj, 1.0, h, autobalance - for k in 'na', 'nc', 'nl', 'anchors': - setattr(self, k, getattr(det, k)) - - def __call__(self, p, targets): # predictions, targets, model - device = targets.device - lcls, lbox, lobj = torch.zeros(1, device=device), torch.zeros(1, device=device), torch.zeros(1, device=device) + self.na = m.na # number of anchors + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.anchors = m.anchors + self.device = device + + def __call__(self, p, targets): # predictions, targets + lcls = torch.zeros(1, device=self.device) # class loss + lbox = torch.zeros(1, device=self.device) # box loss + lobj = torch.zeros(1, device=self.device) # object loss tcls, tbox, indices, anchors = self.build_targets(p, targets) # targets # Losses for i, pi in enumerate(p): # layer index, layer predictions b, a, gj, gi = indices[i] # image, anchor, gridy, gridx - tobj = torch.zeros_like(pi[..., 0], device=device) # target obj + tobj = torch.zeros(pi.shape[:4], dtype=pi.dtype, device=self.device) # target obj n = b.shape[0] # number of targets if n: - ps = pi[b, a, gj, gi] # prediction subset corresponding to targets + # pxy, pwh, _, pcls = pi[b, a, gj, gi].tensor_split((2, 4, 5), dim=1) # faster, requires torch 1.8.0 + pxy, pwh, _, pcls = pi[b, a, gj, gi].split((2, 2, 1, self.nc), 1) # target-subset of predictions # Regression - pxy = ps[:, :2].sigmoid() * 2 - 0.5 - pwh = (ps[:, 2:4].sigmoid() * 2) ** 2 * anchors[i] + pxy = pxy.sigmoid() * 2 - 0.5 + pwh = (pwh.sigmoid() * 2) ** 2 * anchors[i] pbox = torch.cat((pxy, pwh), 1) # predicted box - iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, CIoU=True) # iou(prediction, target) + iou = bbox_iou(pbox, tbox[i], CIoU=True).squeeze() # iou(prediction, target) lbox += (1.0 - iou).mean() # iou loss # Objectness - score_iou = iou.detach().clamp(0).type(tobj.dtype) + iou = iou.detach().clamp(0).type(tobj.dtype) if self.sort_obj_iou: - sort_id = torch.argsort(score_iou) - b, a, gj, gi, score_iou = b[sort_id], a[sort_id], gj[sort_id], gi[sort_id], score_iou[sort_id] - tobj[b, a, gj, gi] = (1.0 - self.gr) + self.gr * score_iou # iou ratio + j = iou.argsort() + b, a, gj, gi, iou = b[j], a[j], gj[j], gi[j], iou[j] + if self.gr < 1: + iou = (1.0 - self.gr) + self.gr * iou + tobj[b, a, gj, gi] = iou # iou ratio # Classification if self.nc > 1: # cls loss (only if multiple classes) - t = torch.full_like(ps[:, 5:], self.cn, device=device) # targets + t = torch.full_like(pcls, self.cn, device=self.device) # targets t[range(n), tcls[i]] = self.cp - lcls += self.BCEcls(ps[:, 5:], t) # BCE + lcls += self.BCEcls(pcls, t) # BCE # Append targets to text file # with open('targets.txt', 'a') as file: @@ -170,25 +178,31 @@ def build_targets(self, p, targets): # Build targets for compute_loss(), input targets(image,class,x,y,w,h) na, nt = self.na, targets.shape[0] # number of anchors, targets tcls, tbox, indices, anch = [], [], [], [] - gain = torch.ones(7, device=targets.device) # normalized to gridspace gain - ai = torch.arange(na, device=targets.device).float().view(na, 1).repeat(1, nt) # same as .repeat_interleave(nt) - targets = torch.cat((targets.repeat(na, 1, 1), ai[:, :, None]), 2) # append anchor indices + gain = torch.ones(7, device=self.device) # normalized to gridspace gain + ai = torch.arange(na, device=self.device).float().view(na, 1).repeat(1, nt) # same as .repeat_interleave(nt) + targets = torch.cat((targets.repeat(na, 1, 1), ai[..., None]), 2) # append anchor indices g = 0.5 # bias - off = torch.tensor([[0, 0], - [1, 0], [0, 1], [-1, 0], [0, -1], # j,k,l,m - # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm - ], device=targets.device).float() * g # offsets + off = torch.tensor( + [ + [0, 0], + [1, 0], + [0, 1], + [-1, 0], + [0, -1], # j,k,l,m + # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm + ], + device=self.device).float() * g # offsets for i in range(self.nl): - anchors = self.anchors[i] - gain[2:6] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain + anchors, shape = self.anchors[i], p[i].shape + gain[2:6] = torch.tensor(shape)[[3, 2, 3, 2]] # xyxy gain # Match targets to anchors - t = targets * gain + t = targets * gain # shape(3,n,7) if nt: # Matches - r = t[:, :, 4:6] / anchors[:, None] # wh ratio + r = t[..., 4:6] / anchors[:, None] # wh ratio j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t'] # compare # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2)) t = t[j] # filter @@ -206,15 +220,13 @@ def build_targets(self, p, targets): offsets = 0 # Define - b, c = t[:, :2].long().T # image, class - gxy = t[:, 2:4] # grid xy - gwh = t[:, 4:6] # grid wh + bc, gxy, gwh, a = t.chunk(4, 1) # (image, class), grid xy, grid wh, anchors + a, (b, c) = a.long().view(-1), bc.long().T # anchors, image, class gij = (gxy - offsets).long() - gi, gj = gij.T # grid xy indices + gi, gj = gij.T # grid indices # Append - a = t[:, 6].long() # anchor indices - indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1))) # image, anchor, grid indices + indices.append((b, a, gj.clamp_(0, shape[2] - 1), gi.clamp_(0, shape[3] - 1))) # image, anchor, grid tbox.append(torch.cat((gxy - gij, gwh), 1)) # box anch.append(anchors[a]) # anchors tcls.append(c) # class diff --git a/utils/metrics.py b/utils/metrics.py index c8fcac5f0c..90490955a8 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -189,49 +189,45 @@ def print(self): print(' '.join(map(str, self.matrix[i]))) -def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7): - # Returns the IoU of box1 to box2. box1 is 4, box2 is nx4 - box2 = box2.T +def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7): + # Returns Intersection over Union (IoU) of box1(1,4) to box2(n,4) # Get the coordinates of bounding boxes - if x1y1x2y2: # x1, y1, x2, y2 = box1 - b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3] - b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3] - else: # transform from xywh to xyxy - b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2 - b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2 - b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2 - b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2 + if xywh: # transform from xywh to xyxy + (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, 1), box2.chunk(4, 1) + w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2 + b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_ + b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_ + else: # x1, y1, x2, y2 = box1 + b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, 1) + b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, 1) + w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps + w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps # Intersection area inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \ (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0) # Union Area - w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps - w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps union = w1 * h1 + w2 * h2 - inter + eps + # IoU iou = inter / union - if GIoU or DIoU or CIoU: + if CIoU or DIoU or GIoU: cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1) # convex (smallest enclosing box) width ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1) # convex height if CIoU or DIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1 c2 = cw ** 2 + ch ** 2 + eps # convex diagonal squared - rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + - (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4 # center distance squared - if DIoU: - return iou - rho2 / c2 # DIoU - elif CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47 + rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4 # center dist ** 2 + if CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47 v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2) with torch.no_grad(): alpha = v / (v - iou + (1 + eps)) return iou - (rho2 / c2 + v * alpha) # CIoU - else: # GIoU https://arxiv.org/pdf/1902.09630.pdf - c_area = cw * ch + eps # convex area - return iou - (c_area - union) / c_area # GIoU - else: - return iou # IoU + return iou - rho2 / c2 # DIoU + c_area = cw * ch + eps # convex area + return iou - (c_area - union) / c_area # GIoU https://arxiv.org/pdf/1902.09630.pdf + return iou # IoU def box_iou(box1, box2): From b3244d05cdb1934df47fee53b6f5b99b43fcf99b Mon Sep 17 00:00:00 2001 From: alex-fdias <73295477+alex-fdias@users.noreply.github.com> Date: Wed, 29 Jun 2022 17:18:08 +0100 Subject: [PATCH 0914/1185] Fix downloading file by URL (Windows) (#1958) as_posix() needed so that backslashes are output as forward slashes in the URL string (Windows) Co-authored-by: Glenn Jocher --- utils/general.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/general.py b/utils/general.py index 820e35d945..8331e7dbae 100755 --- a/utils/general.py +++ b/utils/general.py @@ -343,7 +343,7 @@ def check_file(file, suffix=''): if Path(file).is_file() or file == '': # exists return file elif file.startswith(('http:/', 'https:/')): # download - url = str(Path(file)).replace(':/', '://') # Pathlib turns :// -> :/ + url = str(Path(file).as_posix()).replace(':/', '://') # Pathlib turns :// -> :/ file = Path(urllib.parse.unquote(file).split('?')[0]).name # '%2F' to '/', split https://url.com/file.txt?auth if Path(file).is_file(): print(f'Found {url} locally at {file}') # file already exists From 92c3bd7a4e997e215c7b3ec8bd5a3f9337d39776 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 22:09:35 +0200 Subject: [PATCH 0915/1185] [pre-commit.ci] pre-commit suggestions (#1961) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.1.0 → v4.3.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.1.0...v4.3.0) - [github.com/asottile/pyupgrade: v2.31.1 → v2.34.0](https://github.com/asottile/pyupgrade/compare/v2.31.1...v2.34.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 748f9d716d..0f9f939514 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ ci: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 + rev: v4.3.0 hooks: - id: end-of-file-fixer - id: trailing-whitespace @@ -24,7 +24,7 @@ repos: - id: check-docstring-first - repo: https://github.com/asottile/pyupgrade - rev: v2.31.1 + rev: v2.34.0 hooks: - id: pyupgrade args: [--py36-plus] From 0bbd0558ed842afe49472b5e3fe45e7483703584 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 3 Sep 2022 03:22:09 +0200 Subject: [PATCH 0916/1185] Update ci-testing.yml remove macos-latest (#1969) Update ci-testing.yml --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 80eab59220..a7aa35c286 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-latest, macos-latest, windows-latest ] + os: [ ubuntu-latest, windows-latest ] python-version: [ 3.9 ] model: [ 'yolov3-tiny' ] # models to test From 3f855edca51d0fab47badb781fc1029b7448d48d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 24 Sep 2022 13:15:34 +0200 Subject: [PATCH 0917/1185] Update requirements.txt (#1973) --- requirements.txt | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/requirements.txt b/requirements.txt index e9843e1788..7c01cc06a1 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,36 +1,47 @@ -# pip install -r requirements.txt +# YOLOv3 requirements +# Usage: pip install -r requirements.txt # Base ---------------------------------------- matplotlib>=3.2.2 numpy>=1.18.5 -opencv-python>=4.1.2 +opencv-python>=4.1.1 Pillow>=7.1.2 PyYAML>=5.3.1 requests>=2.23.0 scipy>=1.4.1 torch>=1.7.0 torchvision>=0.8.1 -tqdm>=4.41.0 +tqdm>=4.64.0 +# protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 # Logging ------------------------------------- tensorboard>=2.4.1 -wandb +# wandb +# clearml # Plotting ------------------------------------ pandas>=1.1.4 seaborn>=0.11.0 # Export -------------------------------------- -# coremltools>=4.1 # CoreML export +# coremltools>=6.0 # CoreML export # onnx>=1.9.0 # ONNX export -# onnx-simplifier>=0.3.6 # ONNX simplifier -# scikit-learn==0.19.2 # CoreML quantization -# tensorflow>=2.4.1 # TFLite export +# onnx-simplifier>=0.4.1 # ONNX simplifier +# nvidia-pyindex # TensorRT export +# nvidia-tensorrt # TensorRT export +# scikit-learn<=1.1.2 # CoreML quantization +# tensorflow>=2.4.1 # TF exports (-cpu, -aarch64, -macos) # tensorflowjs>=3.9.0 # TF.js export +# openvino-dev # OpenVINO export + +# Deploy -------------------------------------- +# tritonclient[all]~=2.24.0 # Extras -------------------------------------- +ipython # interactive notebook +psutil # system utilization +thop>=0.1.1 # FLOPs computation +# mss # screenshots # albumentations>=1.0.3 -# Cython # for pycocotools https://github.com/cocodataset/cocoapi/issues/172 # pycocotools>=2.0 # COCO mAP # roboflow -thop # FLOPs computation From b0b071dda818dc30265470617554c4c7e790037a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Sep 2022 12:38:40 +0200 Subject: [PATCH 0918/1185] Bump actions/stale from 5 to 6 (#1975) Bumps [actions/stale](https://github.com/actions/stale) from 5 to 6. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 008ca0fe6d..94d649f08a 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -9,7 +9,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v5 + - uses: actions/stale@v6 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: | From 88a803126b1e55e01b295bea887001bd74a0e09b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 16 Oct 2022 11:45:19 +0200 Subject: [PATCH 0919/1185] Update ci-testing.yml --- .github/workflows/ci-testing.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index a7aa35c286..1210400ee8 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -51,7 +51,6 @@ jobs: run: | python -m pip install --upgrade pip pip install -qr requirements.txt -f https://download.pytorch.org/whl/cpu/torch_stable.html - pip install -q onnx tensorflow-cpu keras==2.6.0 # wandb # extras python --version pip --version pip list @@ -83,7 +82,7 @@ jobs: # Export python models/yolo.py --cfg ${{ matrix.model }}.yaml # build PyTorch model # python models/tf.py --weights ${{ matrix.model }}.pt # build TensorFlow model (YOLOv3 not supported) - python export.py --img 64 --batch 1 --weights runs/train/exp/weights/last.pt --include torchscript onnx # export + python export.py --img 64 --batch 1 --weights runs/train/exp/weights/last.pt --include torchscript # export # Python python - < Date: Sun, 16 Oct 2022 11:50:15 +0200 Subject: [PATCH 0920/1185] Update requirements.txt (#1980) --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7c01cc06a1..f78e7ee013 100755 --- a/requirements.txt +++ b/requirements.txt @@ -9,15 +9,15 @@ Pillow>=7.1.2 PyYAML>=5.3.1 requests>=2.23.0 scipy>=1.4.1 -torch>=1.7.0 +torch>=1.7.0 # see https://pytorch.org/get-started/locally/ (recommended) torchvision>=0.8.1 tqdm>=4.64.0 # protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 # Logging ------------------------------------- tensorboard>=2.4.1 -# wandb # clearml +# comet # Plotting ------------------------------------ pandas>=1.1.4 From dd838e25863169d0de4f10631a609350658efb69 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 16 Oct 2022 11:55:23 +0200 Subject: [PATCH 0921/1185] Update ci-testing.yml (#1981) --- .github/workflows/ci-testing.yml | 126 ++++++++++++++++--------------- 1 file changed, 66 insertions(+), 60 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 1210400ee8..b0a6bfd947 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -1,93 +1,99 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 Continuous Integration (CI) GitHub Actions tests -name: CI CPU testing +name: YOLOv3 CI -on: # https://help.github.com/en/actions/reference/events-that-trigger-workflows +on: push: branches: [ master ] pull_request: - # The branches below must be a subset of the branches above branches: [ master ] schedule: - - cron: '0 0 * * *' # Runs at 00:00 UTC every day + - cron: '0 0 * * *' # runs at 00:00 UTC every day jobs: - cpu-tests: - + Tests: + timeout-minutes: 60 runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - os: [ ubuntu-latest, windows-latest ] - python-version: [ 3.9 ] - model: [ 'yolov3-tiny' ] # models to test - - # Timeout: https://stackoverflow.com/a/59076067/4521646 - timeout-minutes: 50 + os: [ ubuntu-latest, windows-latest ] # macos-latest bug https://github.com/ultralytics/yolov5/pull/9049 + python-version: [ '3.10' ] + model: [ yolov3-tiny ] + include: + - os: ubuntu-latest + python-version: '3.7' # '3.6.8' min + model: yolov3-tiny + - os: ubuntu-latest + python-version: '3.8' + model: yolov3-tiny + - os: ubuntu-latest + python-version: '3.9' + model: yolov3-tiny + - os: ubuntu-latest + python-version: '3.8' # torch 1.7.0 requires python >=3.6, <=3.8 + model: yolov3-tiny + torch: '1.7.0' # min torch version CI https://pypi.org/project/torchvision/ steps: - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - # Note: This uses an internal pip API and may not always work - # https://github.com/actions/cache/blob/master/examples.md#multiple-oss-in-a-workflow - - name: Get pip cache + - name: Get cache dir + # https://github.com/actions/cache/blob/master/examples.md#multiple-oss-in-a-workflow id: pip-cache - run: | - python -c "from pip._internal.locations import USER_CACHE_DIR; print('::set-output name=dir::' + USER_CACHE_DIR)" - + run: echo "::set-output name=dir::$(pip cache dir)" - name: Cache pip uses: actions/cache@v3 with: path: ${{ steps.pip-cache.outputs.dir }} key: ${{ runner.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('requirements.txt') }} - restore-keys: | - ${{ runner.os }}-${{ matrix.python-version }}-pip- - - # Known Keras 2.7.0 issue: https://github.com/ultralytics/yolov5/pull/5486 - - name: Install dependencies + restore-keys: ${{ runner.os }}-${{ matrix.python-version }}-pip- + - name: Install requirements + run: | + python -m pip install --upgrade pip wheel + if [ "${{ matrix.torch }}" == "1.7.0" ]; then + pip install -r requirements.txt torch==1.7.0 torchvision==0.8.1 --extra-index-url https://download.pytorch.org/whl/cpu + else + pip install -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cpu + fi + shell: bash # for Windows compatibility + - name: Check environment run: | - python -m pip install --upgrade pip - pip install -qr requirements.txt -f https://download.pytorch.org/whl/cpu/torch_stable.html + python -c "import utils; utils.notebook_init()" + echo "RUNNER_OS is ${{ runner.os }}" + echo "GITHUB_EVENT_NAME is ${{ github.event_name }}" + echo "GITHUB_WORKFLOW is ${{ github.workflow }}" + echo "GITHUB_ACTOR is ${{ github.actor }}" + echo "GITHUB_REPOSITORY is ${{ github.repository }}" + echo "GITHUB_REPOSITORY_OWNER is ${{ github.repository_owner }}" python --version pip --version pip list - shell: bash - - # - name: W&B login - # run: wandb login 345011b3fb26dc8337fd9b20e53857c1d403f2aa - - - name: Download data - run: | - # curl -L -o tmp.zip https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip - # unzip -q tmp.zip -d ../ - # rm tmp.zip - - - name: Tests workflow + - name: Test detection + shell: bash # for Windows compatibility run: | # export PYTHONPATH="$PWD" # to run '$ python *.py' files in subdirectories - di=cpu # device - - # Train - python train.py --img 64 --batch 32 --weights ${{ matrix.model }}.pt --cfg ${{ matrix.model }}.yaml --epochs 1 --device $di - # Val - python val.py --img 64 --batch 32 --weights ${{ matrix.model }}.pt --device $di - python val.py --img 64 --batch 32 --weights runs/train/exp/weights/last.pt --device $di - # Detect - python detect.py --weights ${{ matrix.model }}.pt --device $di - python detect.py --weights runs/train/exp/weights/last.pt --device $di - python hubconf.py # hub - # Export - python models/yolo.py --cfg ${{ matrix.model }}.yaml # build PyTorch model - # python models/tf.py --weights ${{ matrix.model }}.pt # build TensorFlow model (YOLOv3 not supported) - python export.py --img 64 --batch 1 --weights runs/train/exp/weights/last.pt --include torchscript # export - # Python + m=${{ matrix.model }} # official weights + b=runs/train/exp/weights/best # best.pt checkpoint + python train.py --imgsz 64 --batch 32 --weights $m.pt --cfg $m.yaml --epochs 1 --device cpu # train + for d in cpu; do # devices + for w in $m $b; do # weights + python val.py --imgsz 64 --batch 32 --weights $w.pt --device $d # val + python detect.py --imgsz 64 --weights $w.pt --device $d # detect + done + done + python hubconf.py --model $m # hub + # python models/tf.py --weights $m.pt # build TF model + python models/yolo.py --cfg $m.yaml # build PyTorch model + python export.py --weights $m.pt --img 64 --include torchscript # export python - < Date: Mon, 28 Nov 2022 04:43:50 +0330 Subject: [PATCH 0922/1185] fix tflite converter bug for tiny models. (#1990) * fix tflite converter bug for tiny models. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- models/tf.py | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/models/tf.py b/models/tf.py index 4076c9eab5..956ef2bdee 100644 --- a/models/tf.py +++ b/models/tf.py @@ -16,6 +16,8 @@ from copy import deepcopy from pathlib import Path +from packaging import version + FILE = Path(__file__).resolve() ROOT = FILE.parents[1] # root directory if str(ROOT) not in sys.path: @@ -26,6 +28,10 @@ import tensorflow as tf import torch import torch.nn as nn +from keras import backend +from keras.engine.base_layer import Layer +from keras.engine.input_spec import InputSpec +from keras.utils import conv_utils from tensorflow import keras from models.common import C3, SPP, SPPF, Bottleneck, BottleneckCSP, Concat, Conv, DWConv, Focus, autopad @@ -34,6 +40,9 @@ from utils.activations import SiLU from utils.general import LOGGER, make_divisible, print_args +# isort: off +from tensorflow.python.util.tf_export import keras_export + class TFBN(keras.layers.Layer): # TensorFlow BatchNormalization wrapper @@ -50,6 +59,29 @@ def call(self, inputs): return self.bn(inputs) +class TFMaxPool2d(keras.layers.Layer): + # TensorFlow MAX Pooling + def __init__(self, k, s, p, w=None): + super().__init__() + self.pool = keras.layers.MaxPool2D(pool_size=k, strides=s, padding='valid') + + def call(self, inputs): + return self.pool(inputs) + + +class TFZeroPad2d(keras.layers.Layer): + # TensorFlow MAX Pooling + def __init__(self, p, w=None): + super().__init__() + if version.parse(tf.__version__) < version.parse('2.11.0'): + self.zero_pad = ZeroPadding2D(padding=p) + else: + self.zero_pad = keras.layers.ZeroPadding2D(padding=((p[0], p[1]), (p[2], p[3]))) + + def call(self, inputs): + return self.zero_pad(inputs) + + class TFPad(keras.layers.Layer): def __init__(self, pad): super().__init__() @@ -444,6 +476,137 @@ def run(weights=ROOT / 'yolov3.pt', # weights path LOGGER.info('PyTorch, TensorFlow and Keras models successfully verified.\nUse export.py for TF model export.') +@keras_export("keras.layers.ZeroPadding2D") +class ZeroPadding2D(Layer): + """Zero-padding layer for 2D input (e.g. picture). + + This layer can add rows and columns of zeros + at the top, bottom, left and right side of an image tensor. + + Examples: + + >>> input_shape = (1, 1, 2, 2) + >>> x = np.arange(np.prod(input_shape)).reshape(input_shape) + >>> print(x) + [[[[0 1] + [2 3]]]] + >>> y = tf.keras.layers.ZeroPadding2D(padding=1)(x) + >>> print(y) + tf.Tensor( + [[[[0 0] + [0 0] + [0 0] + [0 0]] + [[0 0] + [0 1] + [2 3] + [0 0]] + [[0 0] + [0 0] + [0 0] + [0 0]]]], shape=(1, 3, 4, 2), dtype=int64) + + Args: + padding: Int, or tuple of 2 ints, or tuple of 2 tuples of 2 ints. + - If int: the same symmetric padding + is applied to height and width. + - If tuple of 2 ints: + interpreted as two different + symmetric padding values for height and width: + `(symmetric_height_pad, symmetric_width_pad)`. + - If tuple of 2 tuples of 2 ints: + interpreted as + `((top_pad, bottom_pad), (left_pad, right_pad))` + data_format: A string, + one of `channels_last` (default) or `channels_first`. + The ordering of the dimensions in the inputs. + `channels_last` corresponds to inputs with shape + `(batch_size, height, width, channels)` while `channels_first` + corresponds to inputs with shape + `(batch_size, channels, height, width)`. + It defaults to the `image_data_format` value found in your + Keras config file at `~/.keras/keras.json`. + If you never set it, then it will be "channels_last". + + Input shape: + 4D tensor with shape: + - If `data_format` is `"channels_last"`: + `(batch_size, rows, cols, channels)` + - If `data_format` is `"channels_first"`: + `(batch_size, channels, rows, cols)` + + Output shape: + 4D tensor with shape: + - If `data_format` is `"channels_last"`: + `(batch_size, padded_rows, padded_cols, channels)` + - If `data_format` is `"channels_first"`: + `(batch_size, channels, padded_rows, padded_cols)` + """ + + def __init__(self, padding=(1, 1), data_format=None, **kwargs): + super().__init__(**kwargs) + self.data_format = conv_utils.normalize_data_format(data_format) + if isinstance(padding, int): + self.padding = ((padding, padding), (padding, padding)) + elif hasattr(padding, "__len__"): + if len(padding) == 4: + padding = ((padding[0], padding[1]), (padding[2], padding[3])) + if len(padding) != 2: + raise ValueError( + f"`padding` should have two elements. Received: {padding}." + ) + height_padding = conv_utils.normalize_tuple( + padding[0], 2, "1st entry of padding", allow_zero=True + ) + width_padding = conv_utils.normalize_tuple( + padding[1], 2, "2nd entry of padding", allow_zero=True + ) + self.padding = (height_padding, width_padding) + else: + raise ValueError( + "`padding` should be either an int, " + "a tuple of 2 ints " + "(symmetric_height_pad, symmetric_width_pad), " + "or a tuple of 2 tuples of 2 ints " + "((top_pad, bottom_pad), (left_pad, right_pad)). " + f"Received: {padding}." + ) + self.input_spec = InputSpec(ndim=4) + + def compute_output_shape(self, input_shape): + input_shape = tf.TensorShape(input_shape).as_list() + if self.data_format == "channels_first": + if input_shape[2] is not None: + rows = input_shape[2] + self.padding[0][0] + self.padding[0][1] + else: + rows = None + if input_shape[3] is not None: + cols = input_shape[3] + self.padding[1][0] + self.padding[1][1] + else: + cols = None + return tf.TensorShape([input_shape[0], input_shape[1], rows, cols]) + elif self.data_format == "channels_last": + if input_shape[1] is not None: + rows = input_shape[1] + self.padding[0][0] + self.padding[0][1] + else: + rows = None + if input_shape[2] is not None: + cols = input_shape[2] + self.padding[1][0] + self.padding[1][1] + else: + cols = None + return tf.TensorShape([input_shape[0], rows, cols, input_shape[3]]) + + def call(self, inputs): + return backend.spatial_2d_padding( + inputs, padding=self.padding, data_format=self.data_format + ) + + def get_config(self): + config = {"padding": self.padding, "data_format": self.data_format} + base_config = super().get_config() + return dict(list(base_config.items()) + list(config.items())) + + def parse_opt(): parser = argparse.ArgumentParser() parser.add_argument('--weights', type=str, default=ROOT / 'yolov3.pt', help='weights path') From a441ab15934a42d2155044adc72bf850a4dea914 Mon Sep 17 00:00:00 2001 From: s-mohaghegh97 <74965425+s-mohaghegh97@users.noreply.github.com> Date: Mon, 28 Nov 2022 04:44:27 +0330 Subject: [PATCH 0923/1185] fix half bug. (#1989) Co-authored-by: Glenn Jocher --- export.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/export.py b/export.py index ce23cf5be1..00fb8c0c51 100644 --- a/export.py +++ b/export.py @@ -317,7 +317,7 @@ def run(data=ROOT / 'data/coco128.yaml', # 'dataset.yaml path' if any(tf_exports): pb, tflite, tfjs = tf_exports[1:] assert not (tflite and tfjs), 'TFLite and TF.js models must be exported separately, please pass only one type.' - model = export_saved_model(model, im, file, dynamic, tf_nms=tfjs, agnostic_nms=tfjs, + model = export_saved_model(model.cpu(), im, file, dynamic, tf_nms=tfjs, agnostic_nms=tfjs, topk_per_class=topk_per_class, topk_all=topk_all, conf_thres=conf_thres, iou_thres=iou_thres) # keras model if pb or tfjs: # pb prerequisite to tfjs From 2813de7cc31da84eea392ffef08b51f6b7454291 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 19 Dec 2022 10:57:59 +0100 Subject: [PATCH 0924/1185] Created using Colaboratory --- tutorial.ipynb | 262 ++++++++++++++++++++++--------------------------- 1 file changed, 116 insertions(+), 146 deletions(-) diff --git a/tutorial.ipynb b/tutorial.ipynb index 1450682b87..17a0f62fd8 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -5,7 +5,6 @@ "colab": { "name": "YOLOv3 Tutorial", "provenance": [], - "collapsed_sections": [], "include_colab_link": true }, "kernelspec": { @@ -402,7 +401,7 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "7efd38e6-c41f-4fe3-9864-ce4fa43fbb5b" + "outputId": "141002fc-fe49-48d2-a575-2555bf903413" }, "source": [ "!git clone https://github.com/ultralytics/yolov3 # clone\n", @@ -413,15 +412,8 @@ "from yolov3 import utils\n", "display = utils.notebook_init() # checks" ], - "execution_count": 24, + "execution_count": 1, "outputs": [ - { - "output_type": "stream", - "name": "stderr", - "text": [ - "YOLOv3 🚀 v9.6.0-1-g93a2bcc torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n" - ] - }, { "output_type": "stream", "name": "stdout", @@ -459,27 +451,27 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "486202a4-bae2-454f-da62-2c74676a3058" + "outputId": "c29b082a-8e56-4799-b32a-056425f130d1" }, "source": [ "!python detect.py --weights yolov3.pt --img 640 --conf 0.25 --source data/images\n", - "display.Image(filename='runs/detect/exp/zidane.jpg', width=600)" + "# display.Image(filename='runs/detect/exp/zidane.jpg', width=600)" ], - "execution_count": 22, + "execution_count": 4, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\u001b[34m\u001b[1mdetect: \u001b[0mweights=['yolov3.pt'], source=data/images, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False\n", - "YOLOv3 🚀 v9.6.0-1-g93a2bcc torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n", + "YOLOv3 🚀 v9.6.0-29-ga441ab1 torch 1.13.0+cu116 CUDA:0 (Tesla T4, 15110MiB)\n", "\n", "Fusing layers... \n", - "Model Summary: 261 layers, 61922845 parameters, 0 gradients, 156.1 GFLOPs\n", - "image 1/2 /content/yolov3/data/images/bus.jpg: 640x480 4 persons, 1 bus, 1 tie, 1 sports ball, Done. (0.020s)\n", - "image 2/2 /content/yolov3/data/images/zidane.jpg: 384x640 2 persons, 3 ties, Done. (0.020s)\n", - "Speed: 0.5ms pre-process, 20.0ms inference, 1.3ms NMS per image at shape (1, 3, 640, 640)\n", - "Results saved to \u001b[1mruns/detect/exp\u001b[0m\n" + "Model Summary: 261 layers, 61922845 parameters, 0 gradients\n", + "image 1/2 /content/yolov3/data/images/bus.jpg: 640x480 4 persons, 1 bicycle, 1 bus, Done. (0.050s)\n", + "image 2/2 /content/yolov3/data/images/zidane.jpg: 384x640 2 persons, 2 ties, Done. (0.038s)\n", + "Speed: 0.5ms pre-process, 44.3ms inference, 1.3ms NMS per image at shape (1, 3, 640, 640)\n", + "Results saved to \u001b[1mruns/detect/exp2\u001b[0m\n" ] } ] @@ -542,7 +534,7 @@ "torch.hub.download_url_to_file('https://ultralytics.com/assets/coco2017val.zip', 'tmp.zip')\n", "!unzip -q tmp.zip -d ../datasets && rm tmp.zip" ], - "execution_count": 4, + "execution_count": null, "outputs": [ { "output_type": "display_data", @@ -573,7 +565,7 @@ "# Run YOLOv3 on COCO val\n", "!python val.py --weights yolov3.pt --data coco.yaml --img 640 --iou 0.65 --half" ], - "execution_count": 23, + "execution_count": null, "outputs": [ { "output_type": "stream", @@ -690,20 +682,6 @@ "execution_count": null, "outputs": [] }, - { - "cell_type": "code", - "metadata": { - "id": "2fLAV42oNb7M" - }, - "source": [ - "# Weights & Biases (optional)\n", - "%pip install -q wandb\n", - "import wandb\n", - "wandb.login()" - ], - "execution_count": null, - "outputs": [] - }, { "cell_type": "code", "metadata": { @@ -711,13 +689,13 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "a601aa72-687c-4dda-a16c-c0b2d9073910" + "outputId": "c77013e3-347d-42a4-84de-3ca42ea3aee9" }, "source": [ "# Train YOLOv3 on COCO128 for 3 epochs\n", "!python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov3.pt --cache" ], - "execution_count": 21, + "execution_count": 3, "outputs": [ { "output_type": "stream", @@ -725,12 +703,18 @@ "text": [ "\u001b[34m\u001b[1mtrain: \u001b[0mweights=yolov3.pt, cfg=, data=coco128.yaml, hyp=data/hyps/hyp.scratch.yaml, epochs=3, batch_size=16, imgsz=640, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, evolve=None, bucket=, cache=ram, image_weights=False, device=, multi_scale=False, single_cls=False, adam=False, sync_bn=False, workers=8, project=runs/train, name=exp, exist_ok=False, quad=False, linear_lr=False, label_smoothing=0.0, patience=100, freeze=0, save_period=-1, local_rank=-1, entity=None, upload_dataset=False, bbox_interval=-1, artifact_alias=latest\n", "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov3 ✅\n", - "YOLOv3 🚀 v9.6.0-1-g93a2bcc torch 1.10.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB)\n", + "YOLOv3 🚀 v9.6.0-29-ga441ab1 torch 1.13.0+cu116 CUDA:0 (Tesla T4, 15110MiB)\n", "\n", "\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.1, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0\n", "\u001b[34m\u001b[1mWeights & Biases: \u001b[0mrun 'pip install wandb' to automatically track and visualize YOLOv3 🚀 runs (RECOMMENDED)\n", "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train', view at http://localhost:6006/\n", "\n", + "WARNING: Dataset not found, nonexistent paths: ['/content/datasets/coco128/images/train2017']\n", + "Downloading https://ultralytics.com/assets/coco128.zip to coco128.zip...\n", + "100% 6.66M/6.66M [00:00<00:00, 10.2MB/s]\n", + "Dataset autodownload success, saved to ../datasets\n", + "\n", + "\n", " from n params module arguments \n", " 0 -1 1 928 models.common.Conv [3, 32, 3, 1] \n", " 1 -1 1 18560 models.common.Conv [32, 64, 3, 2] \n", @@ -744,7 +728,7 @@ " 9 -1 1 4720640 models.common.Conv [512, 1024, 3, 2] \n", " 10 -1 4 20983808 models.common.Bottleneck [1024, 1024] \n", " 11 -1 1 5245952 models.common.Bottleneck [1024, 1024, False] \n", - " 12 -1 1 525312 models.common.Conv [1024, 512, [1, 1]] \n", + " 12 -1 1 525312 models.common.Conv [1024, 512, 1, 1] \n", " 13 -1 1 4720640 models.common.Conv [512, 1024, 3, 1] \n", " 14 -1 1 525312 models.common.Conv [1024, 512, 1, 1] \n", " 15 -1 1 4720640 models.common.Conv [512, 1024, 3, 1] \n", @@ -761,119 +745,120 @@ " 26 -1 1 344832 models.common.Bottleneck [384, 256, False] \n", " 27 -1 2 656896 models.common.Bottleneck [256, 256, False] \n", " 28 [27, 22, 15] 1 457725 models.yolo.Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [256, 512, 1024]]\n", - "Model Summary: 333 layers, 61949149 parameters, 61949149 gradients, 156.3 GFLOPs\n", + "Model Summary: 333 layers, 61949149 parameters, 61949149 gradients, 156.6 GFLOPs\n", "\n", "Transferred 439/439 items from yolov3.pt\n", "Scaled weight_decay = 0.0005\n", "\u001b[34m\u001b[1moptimizer:\u001b[0m SGD with parameter groups 72 weight, 75 weight (no decay), 75 bias\n", - "\u001b[34m\u001b[1malbumentations: \u001b[0mversion 1.0.3 required by YOLOv3, but version 0.1.12 is currently installed\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mScanning '../datasets/coco128/labels/train2017.cache' images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100% 128/128 [00:00\"Weights

" - ] - }, { "cell_type": "markdown", "metadata": { @@ -1080,4 +1050,4 @@ "outputs": [] } ] -} +} \ No newline at end of file From 91b040619f42d57e6cbdc632fd0b719a4492ffbd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Dec 2022 13:51:06 +0100 Subject: [PATCH 0925/1185] Bump actions/stale from 6 to 7 (#2000) * Bump actions/stale from 6 to 7 Bumps [actions/stale](https://github.com/actions/stale) from 6 to 7. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/stale.yml | 2 +- tutorial.ipynb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 94d649f08a..819a537950 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -9,7 +9,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v6 + - uses: actions/stale@v7 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: | diff --git a/tutorial.ipynb b/tutorial.ipynb index 17a0f62fd8..635061fbda 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -1050,4 +1050,4 @@ "outputs": [] } ] -} \ No newline at end of file +} From ae460cf4ffd22ac7d5c498aa5a5187e246e34f34 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Jan 2023 21:10:43 +0100 Subject: [PATCH 0926/1185] Bump cirrus-actions/rebase from 1.7 to 1.8 (#1999) Bumps [cirrus-actions/rebase](https://github.com/cirrus-actions/rebase) from 1.7 to 1.8. - [Release notes](https://github.com/cirrus-actions/rebase/releases) - [Commits](https://github.com/cirrus-actions/rebase/compare/1.7...1.8) --- updated-dependencies: - dependency-name: cirrus-actions/rebase dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/rebase.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml index a4dc9e5092..5ec1791d5a 100644 --- a/.github/workflows/rebase.yml +++ b/.github/workflows/rebase.yml @@ -16,6 +16,6 @@ jobs: token: ${{ secrets.ACTIONS_TOKEN }} fetch-depth: 0 # otherwise, you will fail to push refs to dest repo - name: Automatic Rebase - uses: cirrus-actions/rebase@1.7 + uses: cirrus-actions/rebase@1.8 env: GITHUB_TOKEN: ${{ secrets.ACTIONS_TOKEN }} From 05209583a0c987ab4d3c2a9b820850452d6249b6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Feb 2023 02:01:57 +0400 Subject: [PATCH 0927/1185] Update README.md (#2006) --- README.md | 439 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 315 insertions(+), 124 deletions(-) diff --git a/README.md b/README.md index 1d961c3c7a..68a34af8f5 100644 --- a/README.md +++ b/README.md @@ -15,30 +15,27 @@
+ + + + + + + + + + + + + + + + + + + + +

@@ -122,8 +119,6 @@ $ python detect.py --source 0 # webcam

Training - -
@@ -131,143 +126,339 @@ $ python detect.py --source 0 # webcam
Tutorials -* [Train Custom Data](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data)  🚀 RECOMMENDED -* [Tips for Best Training Results](https://github.com/ultralytics/yolov3/wiki/Tips-for-Best-Training-Results)  ☘️ +- [Train Custom Data](https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data)  🚀 RECOMMENDED +- [Tips for Best Training Results](https://github.com/ultralytics/yolov5/wiki/Tips-for-Best-Training-Results)  ☘️ RECOMMENDED -* [Weights & Biases Logging](https://github.com/ultralytics/yolov5/issues/1289)  🌟 NEW -* [Roboflow for Datasets, Labeling, and Active Learning](https://github.com/ultralytics/yolov5/issues/4975)  🌟 NEW -* [Multi-GPU Training](https://github.com/ultralytics/yolov5/issues/475) -* [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36)  ⭐ NEW -* [TorchScript, ONNX, CoreML Export](https://github.com/ultralytics/yolov5/issues/251) 🚀 -* [Test-Time Augmentation (TTA)](https://github.com/ultralytics/yolov5/issues/303) -* [Model Ensembling](https://github.com/ultralytics/yolov5/issues/318) -* [Model Pruning/Sparsity](https://github.com/ultralytics/yolov5/issues/304) -* [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607) -* [Transfer Learning with Frozen Layers](https://github.com/ultralytics/yolov5/issues/1314)  ⭐ NEW -* [TensorRT Deployment](https://github.com/wang-xinyu/tensorrtx) +- [Multi-GPU Training](https://github.com/ultralytics/yolov5/issues/475) +- [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36) 🌟 NEW +- [TFLite, ONNX, CoreML, TensorRT Export](https://github.com/ultralytics/yolov5/issues/251) 🚀 +- [NVIDIA Jetson Nano Deployment](https://github.com/ultralytics/yolov5/issues/9627) 🌟 NEW +- [Test-Time Augmentation (TTA)](https://github.com/ultralytics/yolov5/issues/303) +- [Model Ensembling](https://github.com/ultralytics/yolov5/issues/318) +- [Model Pruning/Sparsity](https://github.com/ultralytics/yolov5/issues/304) +- [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607) +- [Transfer Learning with Frozen Layers](https://github.com/ultralytics/yolov5/issues/1314) +- [Architecture Summary](https://github.com/ultralytics/yolov5/issues/6998) 🌟 NEW +- [Roboflow for Datasets, Labeling, and Active Learning](https://github.com/ultralytics/yolov5/issues/4975)  🌟 NEW +- [ClearML Logging](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml) 🌟 NEW +- [YOLOv5 with Neural Magic's Deepsparse](https://bit.ly/yolov5-neuralmagic) 🌟 NEW +- [Comet Logging](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/comet) 🌟 NEW
-##
Environments
+##
Integrations
-Get started in seconds with our verified environments. Click each icon below for details. +
+ + +
+
-##
Integrations
+| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | +| :--------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | +| Label and export your custom datasets directly to YOLOv5 for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | Automatically track, visualize and even remotely train YOLOv5 using [ClearML](https://cutt.ly/yolov5-readme-clearml) (open-source!) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet2) lets you save YOLOv5 models, resume training, and interactively visualise and debug predictions | Run YOLOv5 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | - +##
Ultralytics HUB
-|Weights and Biases|Roboflow ⭐ NEW| -|:-:|:-:| -|Automatically track and visualize all your YOLOv3 training runs in the cloud with [Weights & Biases](https://wandb.ai/site?utm_campaign=repo_yolo_readme)|Label and export your custom datasets directly to YOLOv3 for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | +[Ultralytics HUB](https://bit.ly/ultralytics_hub) is our ⭐ **NEW** no-code solution to visualize datasets, train YOLOv5 🚀 models, and deploy to the real world in a seamless experience. Get started for **Free** now! + + ##
Why YOLOv5
-

+YOLOv5 has been designed to be super easy to get started and simple to learn. We prioritize real-world results. + +

- YOLOv3-P5 640 Figure (click to expand) + YOLOv5-P5 640 Figure -

+

- Figure Notes (click to expand) + Figure Notes + +- **COCO AP val** denotes mAP@0.5:0.95 metric measured on the 5000-image [COCO val2017](http://cocodataset.org) dataset over various inference sizes from 256 to 1536. +- **GPU Speed** measures average inference time per image on [COCO val2017](http://cocodataset.org) dataset using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) V100 instance at batch-size 32. +- **EfficientDet** data from [google/automl](https://github.com/google/automl) at batch size 8. +- **Reproduce** by `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt` -* **COCO AP val** denotes mAP@0.5:0.95 metric measured on the 5000-image [COCO val2017](http://cocodataset.org) dataset over various inference sizes from 256 to 1536. -* **GPU Speed** measures average inference time per image on [COCO val2017](http://cocodataset.org) dataset using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) V100 instance at batch-size 32. -* **EfficientDet** data from [google/automl](https://github.com/google/automl) at batch size 8. -* **Reproduce** by `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt`
### Pretrained Checkpoints -[assets]: https://github.com/ultralytics/yolov5/releases -[TTA]: https://github.com/ultralytics/yolov5/issues/303 - -|Model |size
(pixels) |mAPval
0.5:0.95 |mAPval
0.5 |Speed
CPU b1
(ms) |Speed
V100 b1
(ms) |Speed
V100 b32
(ms) |params
(M) |FLOPs
@640 (B) -|--- |--- |--- |--- |--- |--- |--- |--- |--- -|[YOLOv5n][assets] |640 |28.4 |46.0 |**45** |**6.3**|**0.6**|**1.9**|**4.5** -|[YOLOv5s][assets] |640 |37.2 |56.0 |98 |6.4 |0.9 |7.2 |16.5 -|[YOLOv5m][assets] |640 |45.2 |63.9 |224 |8.2 |1.7 |21.2 |49.0 -|[YOLOv5l][assets] |640 |48.8 |67.2 |430 |10.1 |2.7 |46.5 |109.1 -|[YOLOv5x][assets] |640 |50.7 |68.9 |766 |12.1 |4.8 |86.7 |205.7 -| | | | | | | | | -|[YOLOv5n6][assets] |1280 |34.0 |50.7 |153 |8.1 |2.1 |3.2 |4.6 -|[YOLOv5s6][assets] |1280 |44.5 |63.0 |385 |8.2 |3.6 |16.8 |12.6 -|[YOLOv5m6][assets] |1280 |51.0 |69.0 |887 |11.1 |6.8 |35.7 |50.0 -|[YOLOv5l6][assets] |1280 |53.6 |71.6 |1784 |15.8 |10.5 |76.8 |111.4 -|[YOLOv5x6][assets]
+ [TTA][TTA]|1280
1536 |54.7
**55.4** |**72.4**
72.3 |3136
- |26.2
- |19.4
- |140.7
- |209.8
- +| Model | size
(pixels) | mAPval
50-95 | mAPval
50 | Speed
CPU b1
(ms) | Speed
V100 b1
(ms) | Speed
V100 b32
(ms) | params
(M) | FLOPs
@640 (B) | +| ----------------------------------------------------------------------------------------------- | --------------------- | -------------------- | ----------------- | ---------------------------- | ----------------------------- | ------------------------------ | ------------------ | ---------------------- | +| [YOLOv5n](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n.pt) | 640 | 28.0 | 45.7 | **45** | **6.3** | **0.6** | **1.9** | **4.5** | +| [YOLOv5s](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt) | 640 | 37.4 | 56.8 | 98 | 6.4 | 0.9 | 7.2 | 16.5 | +| [YOLOv5m](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m.pt) | 640 | 45.4 | 64.1 | 224 | 8.2 | 1.7 | 21.2 | 49.0 | +| [YOLOv5l](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l.pt) | 640 | 49.0 | 67.3 | 430 | 10.1 | 2.7 | 46.5 | 109.1 | +| [YOLOv5x](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x.pt) | 640 | 50.7 | 68.9 | 766 | 12.1 | 4.8 | 86.7 | 205.7 | +| | | | | | | | | | +| [YOLOv5n6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n6.pt) | 1280 | 36.0 | 54.4 | 153 | 8.1 | 2.1 | 3.2 | 4.6 | +| [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | +| [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | +| [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | +| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+ [TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- | + +
+ Table Notes + +- All checkpoints are trained to 300 epochs with default settings. Nano and Small models use [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) hyps, all others use [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml). +- **mAPval** values are for single-model single-scale on [COCO val2017](http://cocodataset.org) dataset.
Reproduce by `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` +- **Speed** averaged over COCO val images using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) instance. NMS times (~1 ms/img) not included.
Reproduce by `python val.py --data coco.yaml --img 640 --task speed --batch 1` +- **TTA** [Test Time Augmentation](https://github.com/ultralytics/yolov5/issues/303) includes reflection and scale augmentations.
Reproduce by `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment` + +
+ +##
Segmentation
+ +Our new YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7.0) instance segmentation models are the fastest and most accurate in the world, beating all current [SOTA benchmarks](https://paperswithcode.com/sota/real-time-instance-segmentation-on-mscoco). We've made them super simple to train, validate and deploy. See full details in our [Release Notes](https://github.com/ultralytics/yolov5/releases/v7.0) and visit our [YOLOv5 Segmentation Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/segment/tutorial.ipynb) for quickstart tutorials. + +
+ Segmentation Checkpoints + +
+ + +
+ +We trained YOLOv5 segmentations models on COCO for 300 epochs at image size 640 using A100 GPUs. We exported all models to ONNX FP32 for CPU speed tests and to TensorRT FP16 for GPU speed tests. We ran all speed tests on Google [Colab Pro](https://colab.research.google.com/signup) notebooks for easy reproducibility. + +| Model | size
(pixels) | mAPbox
50-95 | mAPmask
50-95 | Train time
300 epochs
A100 (hours) | Speed
ONNX CPU
(ms) | Speed
TRT A100
(ms) | params
(M) | FLOPs
@640 (B) | +| ------------------------------------------------------------------------------------------ | --------------------- | -------------------- | --------------------- | --------------------------------------------- | ------------------------------ | ------------------------------ | ------------------ | ---------------------- | +| [YOLOv5n-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-seg.pt) | 640 | 27.6 | 23.4 | 80:17 | **62.7** | **1.2** | **2.0** | **7.1** | +| [YOLOv5s-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt) | 640 | 37.6 | 31.7 | 88:16 | 173.3 | 1.4 | 7.6 | 26.4 | +| [YOLOv5m-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-seg.pt) | 640 | 45.0 | 37.1 | 108:36 | 427.0 | 2.2 | 22.0 | 70.8 | +| [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | +| [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | + +- All checkpoints are trained to 300 epochs with SGD optimizer with `lr0=0.01` and `weight_decay=5e-5` at image size 640 and all default settings.
Runs logged to https://wandb.ai/glenn-jocher/YOLOv5_v70_official +- **Accuracy** values are for single-model single-scale on COCO dataset.
Reproduce by `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt` +- **Speed** averaged over 100 inference images using a [Colab Pro](https://colab.research.google.com/signup) A100 High-RAM instance. Values indicate inference speed only (NMS adds about 1ms per image).
Reproduce by `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt --batch 1` +- **Export** to ONNX at FP32 and TensorRT at FP16 done with `export.py`.
Reproduce by `python export.py --weights yolov5s-seg.pt --include engine --device 0 --half` + +
+ +
+ Segmentation Usage Examples  Open In Colab + +### Train + +YOLOv5 segmentation training supports auto-download COCO128-seg segmentation dataset with `--data coco128-seg.yaml` argument and manual download of COCO-segments dataset with `bash data/scripts/get_coco.sh --train --val --segments` and then `python train.py --data coco.yaml`. + +```bash +# Single-GPU +python segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 + +# Multi-GPU DDP +python -m torch.distributed.run --nproc_per_node 4 --master_port 1 segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 --device 0,1,2,3 +``` + +### Val + +Validate YOLOv5s-seg mask mAP on COCO dataset: + +```bash +bash data/scripts/get_coco.sh --val --segments # download COCO val segments split (780MB, 5000 images) +python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 # validate +``` + +### Predict + +Use pretrained YOLOv5m-seg.pt to predict bus.jpg: + +```bash +python segment/predict.py --weights yolov5m-seg.pt --data data/images/bus.jpg +``` + +```python +model = torch.hub.load( + "ultralytics/yolov5", "custom", "yolov5m-seg.pt" +) # load from PyTorch Hub (WARNING: inference not yet supported) +``` + +| ![zidane](https://user-images.githubusercontent.com/26833433/203113421-decef4c4-183d-4a0a-a6c2-6435b33bc5d3.jpg) | ![bus](https://user-images.githubusercontent.com/26833433/203113416-11fe0025-69f7-4874-a0a6-65d0bfe2999a.jpg) | +| ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | + +### Export + +Export YOLOv5s-seg model to ONNX and TensorRT: + +```bash +python export.py --weights yolov5s-seg.pt --include onnx engine --img 640 --device 0 +``` + +
+ +##
Classification
+ +YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) brings support for classification model training, validation and deployment! See full details in our [Release Notes](https://github.com/ultralytics/yolov5/releases/v6.2) and visit our [YOLOv5 Classification Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/classify/tutorial.ipynb) for quickstart tutorials. + +
+ Classification Checkpoints + +
+ +We trained YOLOv5-cls classification models on ImageNet for 90 epochs using a 4xA100 instance, and we trained ResNet and EfficientNet models alongside with the same default training settings to compare. We exported all models to ONNX FP32 for CPU speed tests and to TensorRT FP16 for GPU speed tests. We ran all speed tests on Google [Colab Pro](https://colab.research.google.com/signup) for easy reproducibility. + +| Model | size
(pixels) | acc
top1 | acc
top5 | Training
90 epochs
4xA100 (hours) | Speed
ONNX CPU
(ms) | Speed
TensorRT V100
(ms) | params
(M) | FLOPs
@224 (B) | +| -------------------------------------------------------------------------------------------------- | --------------------- | ---------------- | ---------------- | -------------------------------------------- | ------------------------------ | ----------------------------------- | ------------------ | ---------------------- | +| [YOLOv5n-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-cls.pt) | 224 | 64.6 | 85.4 | 7:59 | **3.3** | **0.5** | **2.5** | **0.5** | +| [YOLOv5s-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt) | 224 | 71.5 | 90.2 | 8:09 | 6.6 | 0.6 | 5.4 | 1.4 | +| [YOLOv5m-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-cls.pt) | 224 | 75.9 | 92.9 | 10:06 | 15.5 | 0.9 | 12.9 | 3.9 | +| [YOLOv5l-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-cls.pt) | 224 | 78.0 | 94.0 | 11:56 | 26.9 | 1.4 | 26.5 | 8.5 | +| [YOLOv5x-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-cls.pt) | 224 | **79.0** | **94.4** | 15:04 | 54.3 | 1.8 | 48.1 | 15.9 | +| | | | | | | | | | +| [ResNet18](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet18.pt) | 224 | 70.3 | 89.5 | **6:47** | 11.2 | 0.5 | 11.7 | 3.7 | +| [ResNet34](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet34.pt) | 224 | 73.9 | 91.8 | 8:33 | 20.6 | 0.9 | 21.8 | 7.4 | +| [ResNet50](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet50.pt) | 224 | 76.8 | 93.4 | 11:10 | 23.4 | 1.0 | 25.6 | 8.5 | +| [ResNet101](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet101.pt) | 224 | 78.5 | 94.3 | 17:10 | 42.1 | 1.9 | 44.5 | 15.9 | +| | | | | | | | | | +| [EfficientNet_b0](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b0.pt) | 224 | 75.1 | 92.4 | 13:03 | 12.5 | 1.3 | 5.3 | 1.0 | +| [EfficientNet_b1](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b1.pt) | 224 | 76.4 | 93.2 | 17:04 | 14.9 | 1.6 | 7.8 | 1.5 | +| [EfficientNet_b2](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b2.pt) | 224 | 76.6 | 93.4 | 17:10 | 15.9 | 1.6 | 9.1 | 1.7 | +| [EfficientNet_b3](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b3.pt) | 224 | 77.7 | 94.0 | 19:19 | 18.9 | 1.9 | 12.2 | 2.4 |
Table Notes (click to expand) -* All checkpoints are trained to 300 epochs with default settings and hyperparameters. -* **mAPval** values are for single-model single-scale on [COCO val2017](http://cocodataset.org) dataset.
Reproduce by `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` -* **Speed** averaged over COCO val images using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) instance. NMS times (~1 ms/img) not included.
Reproduce by `python val.py --data coco.yaml --img 640 --conf 0.25 --iou 0.45` -* **TTA** [Test Time Augmentation](https://github.com/ultralytics/yolov5/issues/303) includes reflection and scale augmentations.
Reproduce by `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment` +- All checkpoints are trained to 90 epochs with SGD optimizer with `lr0=0.001` and `weight_decay=5e-5` at image size 224 and all default settings.
Runs logged to https://wandb.ai/glenn-jocher/YOLOv5-Classifier-v6-2 +- **Accuracy** values are for single-model single-scale on [ImageNet-1k](https://www.image-net.org/index.php) dataset.
Reproduce by `python classify/val.py --data ../datasets/imagenet --img 224` +- **Speed** averaged over 100 inference images using a Google [Colab Pro](https://colab.research.google.com/signup) V100 High-RAM instance.
Reproduce by `python classify/val.py --data ../datasets/imagenet --img 224 --batch 1` +- **Export** to ONNX at FP32 and TensorRT at FP16 done with `export.py`.
Reproduce by `python export.py --weights yolov5s-cls.pt --include engine onnx --imgsz 224` + +
+
+ +
+ Classification Usage Examples  Open In Colab + +### Train + +YOLOv5 classification training supports auto-download of MNIST, Fashion-MNIST, CIFAR10, CIFAR100, Imagenette, Imagewoof, and ImageNet datasets with the `--data` argument. To start training on MNIST for example use `--data mnist`. + +```bash +# Single-GPU +python classify/train.py --model yolov5s-cls.pt --data cifar100 --epochs 5 --img 224 --batch 128 + +# Multi-GPU DDP +python -m torch.distributed.run --nproc_per_node 4 --master_port 1 classify/train.py --model yolov5s-cls.pt --data imagenet --epochs 5 --img 224 --device 0,1,2,3 +``` + +### Val + +Validate YOLOv5m-cls accuracy on ImageNet-1k dataset: + +```bash +bash data/scripts/get_imagenet.sh --val # download ImageNet val split (6.3G, 50000 images) +python classify/val.py --weights yolov5m-cls.pt --data ../datasets/imagenet --img 224 # validate +``` + +### Predict + +Use pretrained YOLOv5s-cls.pt to predict bus.jpg: + +```bash +python classify/predict.py --weights yolov5s-cls.pt --data data/images/bus.jpg +``` + +```python +model = torch.hub.load( + "ultralytics/yolov5", "custom", "yolov5s-cls.pt" +) # load from PyTorch Hub +``` + +### Export + +Export a group of trained YOLOv5s-cls, ResNet and EfficientNet models to ONNX and TensorRT: + +```bash +python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --include onnx engine --img 224 +```
+##
Environments
+ +Get started in seconds with our verified environments. Click each icon below for details. + +
+ + + + + + + + + + + + + + + + + +
+ ##
Contribute
-We love your input! We want to make contributing to YOLOv3 as easy and transparent as possible. Please see our [Contributing Guide](CONTRIBUTING.md) to get started, and fill out the [YOLOv3 Survey](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to send us feedback on your experiences. Thank you to all our contributors! +We love your input! We want to make contributing to YOLOv5 as easy and transparent as possible. Please see our [Contributing Guide](CONTRIBUTING.md) to get started, and fill out the [YOLOv5 Survey](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to send us feedback on your experiences. Thank you to all our contributors! - + + + +##
License
+ +YOLOv5 is available under two different licenses: + +- **GPL-3.0 License**: See [LICENSE](https://github.com/ultralytics/yolov5/blob/master/LICENSE) file for details. +- **Enterprise License**: Provides greater flexibility for commercial product development without the open-source requirements of GPL-3.0. Typical use cases are embedding Ultralytics software and AI models in commercial products and applications. Request an Enterprise License at [Ultralytics Licensing](https://ultralytics.com/license). ##
Contact
-For YOLOv3 bugs and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues). For business inquiries or -professional support requests please visit [https://ultralytics.com/contact](https://ultralytics.com/contact). +For YOLOv5 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov5/issues) or the [Ultralytics Community Forum](https://community.ultralytics.com/).
-
- - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + +
+ +[tta]: https://github.com/ultralytics/yolov5/issues/303 + From a57a6df95bb9ceb6625e6e23a53a7b1138325361 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Feb 2023 02:02:13 +0400 Subject: [PATCH 0928/1185] Update greetings.yml (#2007) --- .github/workflows/greetings.yml | 60 +++++++++++++++++---------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index aaad2179b5..e01984809d 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -1,8 +1,12 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv5 🚀 by Ultralytics, GPL-3.0 license name: Greetings -on: [pull_request_target, issues] +on: + pull_request_target: + types: [opened] + issues: + types: [opened] jobs: greeting: @@ -12,48 +16,46 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} pr-message: | - 👋 Hello @${{ github.actor }}, thank you for submitting a 🚀 PR! To allow your work to be integrated as seamlessly as possible, we advise you to: - - ✅ Verify your PR is **up-to-date with upstream/master.** If your PR is behind upstream/master an automatic [GitHub actions](https://github.com/ultralytics/yolov3/blob/master/.github/workflows/rebase.yml) rebase may be attempted by including the /rebase command in a comment body, or by running the following code, replacing 'feature' with the name of your local branch: - ```bash - git remote add upstream https://github.com/ultralytics/yolov3.git - git fetch upstream - git checkout feature # <----- replace 'feature' with local branch name - git merge upstream/master - git push -u origin -f - ``` - - ✅ Verify all Continuous Integration (CI) **checks are passing**. - - ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ -Bruce Lee + 👋 Hello @${{ github.actor }}, thank you for submitting a YOLOv3 🚀 PR! To allow your work to be integrated as seamlessly as possible, we advise you to: - issue-message: | - 👋 Hello @${{ github.actor }}, thank you for your interest in YOLOv3 🚀! Please visit our ⭐️ [Tutorials](https://github.com/ultralytics/yolov3/wiki#tutorials) to get started, where you can find quickstart guides for simple tasks like [Custom Data Training](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data) all the way to advanced concepts like [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607). + - ✅ Verify your PR is **up-to-date** with `ultralytics/yolov5` `master` branch. If your PR is behind you can update your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally. + - ✅ Verify all YOLOv3 Continuous Integration (CI) **checks are passing**. + - ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ — Bruce Lee - If this is a 🐛 Bug Report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you. + issue-message: | + 👋 Hello @${{ github.actor }}, thank you for your interest in YOLOv3 🚀! Please visit our ⭐️ [Tutorials](https://github.com/ultralytics/yolov5/wiki#tutorials) to get started, where you can find quickstart guides for simple tasks like [Custom Data Training](https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data) all the way to advanced concepts like [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607). - If this is a custom training ❓ Question, please provide as much information as possible, including dataset images, training logs, screenshots, and a public link to online [W&B logging](https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data#visualize) if available. + If this is a 🐛 Bug Report, please provide a **minimum reproducible example** to help us debug it. - For business inquiries or professional support requests please visit https://ultralytics.com or email Glenn Jocher at glenn.jocher@ultralytics.com. + If this is a custom training ❓ Question, please provide as much information as possible, including dataset image examples and training logs, and verify you are following our [Tips for Best Training Results](https://github.com/ultralytics/yolov5/wiki/Tips-for-Best-Training-Results). ## Requirements - [**Python>=3.6.0**](https://www.python.org/) with all [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) installed including [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). To get started: + [**Python>=3.7.0**](https://www.python.org/) with all [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) installed including [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). To get started: ```bash - $ git clone https://github.com/ultralytics/yolov3 - $ cd yolov3 - $ pip install -r requirements.txt + git clone https://github.com/ultralytics/yolov3 # clone + cd yolov3 + pip install -r requirements.txt # install ``` ## Environments YOLOv3 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): - - **Google Colab and Kaggle** notebooks with free GPU: Open In Colab Open In Kaggle - - **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) - - **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/AWS-Quickstart) - - **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) Docker Pulls - + - **Notebooks** with free GPU: Run on Gradient Open In Colab Open In Kaggle + - **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/GCP-Quickstart) + - **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/AWS-Quickstart) + - **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/Docker-Quickstart) Docker Pulls ## Status - CI CPU testing + YOLOv3 CI - If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 training ([train.py](https://github.com/ultralytics/yolov3/blob/master/train.py)), validation ([val.py](https://github.com/ultralytics/yolov3/blob/master/val.py)), inference ([detect.py](https://github.com/ultralytics/yolov3/blob/master/detect.py)) and export ([export.py](https://github.com/ultralytics/yolov3/blob/master/export.py)) on MacOS, Windows, and Ubuntu every 24 hours and on every commit. + If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 [training](https://github.com/ultralytics/yolov5/blob/master/train.py), [validation](https://github.com/ultralytics/yolov5/blob/master/val.py), [inference](https://github.com/ultralytics/yolov5/blob/master/detect.py), [export](https://github.com/ultralytics/yolov5/blob/master/export.py) and [benchmarks](https://github.com/ultralytics/yolov5/blob/master/benchmarks.py) on MacOS, Windows, and Ubuntu every 24 hours and on every commit. + + ## YOLOv8 + + Ultralytics YOLOv8 🚀 is our new cutting-edge, state-of-the-art (SOTA) model released at [https://github.com/ultralytics/ultralytics](https://github.com/ultralytics/ultralytics). YOLOv8 is designed to be fast, accurate, and easy to use, making it an excellent choice for a wide range of object detection, image segmentation and image classification tasks. See the [YOLOv8 Docs] for details and get started with: + ```bash + pip install ultralytics + ``` From e7b8da649329bc65922eeb68622b88e5472c4daf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Feb 2023 02:08:53 +0400 Subject: [PATCH 0929/1185] Update Dockerfile (#2009) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 1284242289..5b3592b44e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ RUN apt update && apt install -y zip htop screen libgl1-mesa-glx COPY requirements.txt . RUN python -m pip install --upgrade pip RUN pip uninstall -y nvidia-tensorboard nvidia-tensorboard-plugin-dlprof -RUN pip install --no-cache -r requirements.txt coremltools onnx gsutil notebook wandb>=0.12.2 +RUN pip install --no-cache -r requirements.txt coremltools onnx gsutil notebook RUN pip install --no-cache -U torch torchvision numpy Pillow # RUN pip install --no-cache torch==1.10.0+cu113 torchvision==0.11.1+cu113 -f https://download.pytorch.org/whl/cu113/torch_stable.html From 6013704cf575a4fe8661fbcb55b1b3517f7917c3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Feb 2023 02:13:22 +0400 Subject: [PATCH 0930/1185] Updates --- Dockerfile | 58 ++-- utils/loggers/wandb/README.md | 147 -------- utils/loggers/wandb/__init__.py | 0 utils/loggers/wandb/log_dataset.py | 27 -- utils/loggers/wandb/sweep.py | 41 --- utils/loggers/wandb/sweep.yaml | 143 -------- utils/loggers/wandb/wandb_utils.py | 532 ----------------------------- 7 files changed, 36 insertions(+), 912 deletions(-) delete mode 100644 utils/loggers/wandb/README.md delete mode 100644 utils/loggers/wandb/__init__.py delete mode 100644 utils/loggers/wandb/log_dataset.py delete mode 100644 utils/loggers/wandb/sweep.py delete mode 100644 utils/loggers/wandb/sweep.yaml delete mode 100644 utils/loggers/wandb/wandb_utils.py diff --git a/Dockerfile b/Dockerfile index 5b3592b44e..4584b7edf8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,37 +1,51 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# Builds ultralytics/yolov3:latest image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 +# Image is CUDA-optimized for YOLOv3 single/multi-GPU training and inference -# Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch -FROM nvcr.io/nvidia/pytorch:21.10-py3 +# Start FROM NVIDIA PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch +# FROM docker.io/pytorch/pytorch:latest +FROM pytorch/pytorch:latest + +# Downloads to user config dir +ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/ # Install linux packages -RUN apt update && apt install -y zip htop screen libgl1-mesa-glx +ENV DEBIAN_FRONTEND noninteractive +RUN apt update +RUN TZ=Etc/UTC apt install -y tzdata +RUN apt install --no-install-recommends -y gcc git zip curl htop libgl1-mesa-glx libglib2.0-0 libpython3-dev gnupg +# RUN alias python=python3 -# Install python dependencies -COPY requirements.txt . -RUN python -m pip install --upgrade pip -RUN pip uninstall -y nvidia-tensorboard nvidia-tensorboard-plugin-dlprof -RUN pip install --no-cache -r requirements.txt coremltools onnx gsutil notebook -RUN pip install --no-cache -U torch torchvision numpy Pillow -# RUN pip install --no-cache torch==1.10.0+cu113 torchvision==0.11.1+cu113 -f https://download.pytorch.org/whl/cu113/torch_stable.html +# Security updates +# https://security.snyk.io/vuln/SNYK-UBUNTU1804-OPENSSL-3314796 +RUN apt upgrade --no-install-recommends -y openssl # Create working directory -RUN mkdir -p /usr/src/app +RUN rm -rf /usr/src/app && mkdir -p /usr/src/app WORKDIR /usr/src/app # Copy contents -COPY . /usr/src/app +# COPY . /usr/src/app (issues as not a .git directory) +RUN git clone https://github.com/ultralytics/yolov3 /usr/src/app -# Downloads to user config dir -ADD https://ultralytics.com/assets/Arial.ttf /root/.config/Ultralytics/ +# Install pip packages +COPY requirements.txt . +RUN python3 -m pip install --upgrade pip wheel +RUN pip install --no-cache -r requirements.txt albumentations comet gsutil notebook \ + coremltools onnx onnx-simplifier onnxruntime 'openvino-dev>=2022.3' + # tensorflow tensorflowjs \ # Set environment variables -# ENV HOME=/usr/src/app +ENV OMP_NUM_THREADS=1 + +# Cleanup +ENV DEBIAN_FRONTEND teletype # Usage Examples ------------------------------------------------------------------------------------------------------- # Build and Push -# t=ultralytics/yolov3:latest && sudo docker build -t $t . && sudo docker push $t +# t=ultralytics/yolov3:latest && sudo docker build -f utils/docker/Dockerfile -t $t . && sudo docker push $t # Pull and Run # t=ultralytics/yolov3:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all $t @@ -45,17 +59,17 @@ ADD https://ultralytics.com/assets/Arial.ttf /root/.config/Ultralytics/ # Kill all image-based # sudo docker kill $(sudo docker ps -qa --filter ancestor=ultralytics/yolov3:latest) -# Bash into running container -# sudo docker exec -it 5a9b5863d93d bash - -# Bash into stopped container -# id=$(sudo docker ps -qa) && sudo docker start $id && sudo docker exec -it $id bash +# DockerHub tag update +# t=ultralytics/yolov3:latest tnew=ultralytics/yolov3:v6.2 && sudo docker pull $t && sudo docker tag $t $tnew && sudo docker push $tnew # Clean up -# docker system prune -a --volumes +# sudo docker system prune -a --volumes # Update Ubuntu drivers # https://www.maketecheasier.com/install-nvidia-drivers-ubuntu/ # DDP test # python -m torch.distributed.run --nproc_per_node 2 --master_port 1 train.py --epochs 3 + +# GCP VM from Image +# docker.io/ultralytics/yolov3:latest diff --git a/utils/loggers/wandb/README.md b/utils/loggers/wandb/README.md deleted file mode 100644 index bae57bdabf..0000000000 --- a/utils/loggers/wandb/README.md +++ /dev/null @@ -1,147 +0,0 @@ -📚 This guide explains how to use **Weights & Biases** (W&B) with YOLOv3 🚀. UPDATED 29 September 2021. -* [About Weights & Biases](#about-weights-&-biases) -* [First-Time Setup](#first-time-setup) -* [Viewing runs](#viewing-runs) -* [Advanced Usage: Dataset Versioning and Evaluation](#advanced-usage) -* [Reports: Share your work with the world!](#reports) - -## About Weights & Biases -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. - -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: - - * [Debug](https://wandb.ai/wandb/getting-started/reports/Visualize-Debug-Machine-Learning-Models--VmlldzoyNzY5MDk#Free-2) model performance in real time - * [GPU usage](https://wandb.ai/wandb/getting-started/reports/Visualize-Debug-Machine-Learning-Models--VmlldzoyNzY5MDk#System-4) visualized automatically - * [Custom charts](https://wandb.ai/wandb/customizable-charts/reports/Powerful-Custom-Charts-To-Debug-Model-Peformance--VmlldzoyNzY4ODI) for powerful, extensible visualization - * [Share insights](https://wandb.ai/wandb/getting-started/reports/Visualize-Debug-Machine-Learning-Models--VmlldzoyNzY5MDk#Share-8) interactively with collaborators - * [Optimize hyperparameters](https://docs.wandb.com/sweeps) efficiently - * [Track](https://docs.wandb.com/artifacts) datasets, pipelines, and production models - -## First-Time Setup -
- Toggle Details -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. - -W&B will create a cloud **project** (default is 'YOLOv3') 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: - - ```shell - $ python train.py --project ... --name ... - ``` - -YOLOv3 notebook example: Open In Colab Open In Kaggle -Screen Shot 2021-09-29 at 10 23 13 PM - - -
- -## Viewing Runs -
- Toggle Details -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: - - * Training & Validation losses - * Metrics: Precision, Recall, mAP@0.5, mAP@0.5:0.95 - * Learning Rate over time - * A bounding box debugging panel, showing the training progress over time - * GPU: Type, **GPU Utilization**, power, temperature, **CUDA memory usage** - * System: Disk I/0, CPU utilization, RAM memory usage - * Your trained model as W&B Artifact - * Environment: OS and Python types, Git repository and state, **training command** - -

Weights & Biases dashboard

- - -
- -## Advanced Usage -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. -
-

1. Visualize and Version Datasets

- 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. -
- Usage - Code $ python utils/logger/wandb/log_dataset.py --project ... --name ... --data .. - - ![Screenshot (64)](https://user-images.githubusercontent.com/15766192/128486078-d8433890-98a3-4d12-8986-b6c0e3fc64b9.png) -
- -

2: Train and Log Evaluation simultaneousy

- This is an extension of the previous section, but it'll also training after uploading the dataset. This also evaluation Table - Evaluation table compares your predictions and ground truths across the validation set for each epoch. It uses the references to the already uploaded datasets, - so no images will be uploaded from your system more than once. -
- Usage - Code $ python utils/logger/wandb/log_dataset.py --data .. --upload_data - -![Screenshot (72)](https://user-images.githubusercontent.com/15766192/128979739-4cf63aeb-a76f-483f-8861-1c0100b938a5.png) -
- -

3: Train using dataset artifact

- 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 - can be used to train a model directly from the dataset artifact. This also logs evaluation -
- Usage - Code $ python utils/logger/wandb/log_dataset.py --data {data}_wandb.yaml - -![Screenshot (72)](https://user-images.githubusercontent.com/15766192/128979739-4cf63aeb-a76f-483f-8861-1c0100b938a5.png) -
- -

4: Save model checkpoints as artifacts

- To enable saving and versioning checkpoints of your experiment, pass `--save_period n` with the base cammand, where `n` represents checkpoint interval. - You can also log both the dataset and model checkpoints simultaneously. If not passed, only the final model will be logged - -
- Usage - Code $ python train.py --save_period 1 - -![Screenshot (68)](https://user-images.githubusercontent.com/15766192/128726138-ec6c1f60-639d-437d-b4ee-3acd9de47ef3.png) -
- -
- -

5: Resume runs from checkpoint artifacts.

-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. - -
- Usage - Code $ python train.py --resume wandb-artifact://{run_path} - -![Screenshot (70)](https://user-images.githubusercontent.com/15766192/128728988-4e84b355-6c87-41ae-a591-14aecf45343e.png) -
- -

6: Resume runs from dataset artifact & checkpoint artifacts.

- Local dataset or model checkpoints are not required. This can be used to resume runs directly on a different device - 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 - train from _wandb.yaml file and set --save_period - -
- Usage - Code $ python train.py --resume wandb-artifact://{run_path} - -![Screenshot (70)](https://user-images.githubusercontent.com/15766192/128728988-4e84b355-6c87-41ae-a591-14aecf45343e.png) -
- - - - -

Reports

-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 YOLOv5 models ([link](https://wandb.ai/glenn-jocher/yolov5_tutorial/reports/YOLOv5-COCO128-Tutorial-Results--VmlldzozMDI5OTY)). - -Weights & Biases Reports - - -## Environments - -YOLOv3 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): - -- **Google Colab and Kaggle** notebooks with free GPU: Open In Colab Open In Kaggle -- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart) -- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/AWS-Quickstart) -- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) Docker Pulls - - -## Status - -![CI CPU testing](https://github.com/ultralytics/yolov3/workflows/CI%20CPU%20testing/badge.svg) - -If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 training ([train.py](https://github.com/ultralytics/yolov3/blob/master/train.py)), validation ([val.py](https://github.com/ultralytics/yolov3/blob/master/val.py)), inference ([detect.py](https://github.com/ultralytics/yolov3/blob/master/detect.py)) and export ([export.py](https://github.com/ultralytics/yolov3/blob/master/export.py)) on MacOS, Windows, and Ubuntu every 24 hours and on every commit. diff --git a/utils/loggers/wandb/__init__.py b/utils/loggers/wandb/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/utils/loggers/wandb/log_dataset.py b/utils/loggers/wandb/log_dataset.py deleted file mode 100644 index d3c77430ff..0000000000 --- a/utils/loggers/wandb/log_dataset.py +++ /dev/null @@ -1,27 +0,0 @@ -import argparse - -from wandb_utils import WandbLogger - -from utils.general import LOGGER - -WANDB_ARTIFACT_PREFIX = 'wandb-artifact://' - - -def create_dataset_artifact(opt): - logger = WandbLogger(opt, None, job_type='Dataset Creation') # TODO: return value unused - if not logger.wandb: - LOGGER.info("install wandb using `pip install wandb` to log the dataset") - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--data', type=str, default='data/coco128.yaml', help='data.yaml path') - parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') - parser.add_argument('--project', type=str, default='YOLOv3', help='name of W&B Project') - parser.add_argument('--entity', default=None, help='W&B entity') - parser.add_argument('--name', type=str, default='log dataset', help='name of W&B run') - - opt = parser.parse_args() - opt.resume = False # Explicitly disallow resume check for dataset upload job - - create_dataset_artifact(opt) diff --git a/utils/loggers/wandb/sweep.py b/utils/loggers/wandb/sweep.py deleted file mode 100644 index 5e24f96e13..0000000000 --- a/utils/loggers/wandb/sweep.py +++ /dev/null @@ -1,41 +0,0 @@ -import sys -from pathlib import Path - -import wandb - -FILE = Path(__file__).resolve() -ROOT = FILE.parents[3] # root directory -if str(ROOT) not in sys.path: - sys.path.append(str(ROOT)) # add ROOT to PATH - -from train import parse_opt, train -from utils.callbacks import Callbacks -from utils.general import increment_path -from utils.torch_utils import select_device - - -def sweep(): - wandb.init() - # Get hyp dict from sweep agent - hyp_dict = vars(wandb.config).get("_items") - - # Workaround: get necessary opt args - opt = parse_opt(known=True) - opt.batch_size = hyp_dict.get("batch_size") - opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok or opt.evolve)) - opt.epochs = hyp_dict.get("epochs") - opt.nosave = True - opt.data = hyp_dict.get("data") - opt.weights = str(opt.weights) - opt.cfg = str(opt.cfg) - opt.data = str(opt.data) - opt.hyp = str(opt.hyp) - opt.project = str(opt.project) - device = select_device(opt.device, batch_size=opt.batch_size) - - # train - train(hyp_dict, opt, device, callbacks=Callbacks()) - - -if __name__ == "__main__": - sweep() diff --git a/utils/loggers/wandb/sweep.yaml b/utils/loggers/wandb/sweep.yaml deleted file mode 100644 index c7790d75f6..0000000000 --- a/utils/loggers/wandb/sweep.yaml +++ /dev/null @@ -1,143 +0,0 @@ -# Hyperparameters for training -# To set range- -# Provide min and max values as: -# parameter: -# -# min: scalar -# max: scalar -# OR -# -# Set a specific list of search space- -# parameter: -# values: [scalar1, scalar2, scalar3...] -# -# You can use grid, bayesian and hyperopt search strategy -# For more info on configuring sweeps visit - https://docs.wandb.ai/guides/sweeps/configuration - -program: utils/loggers/wandb/sweep.py -method: random -metric: - name: metrics/mAP_0.5 - goal: maximize - -parameters: - # hyperparameters: set either min, max range or values list - data: - value: "data/coco128.yaml" - batch_size: - values: [64] - epochs: - values: [10] - - lr0: - distribution: uniform - min: 1e-5 - max: 1e-1 - lrf: - distribution: uniform - min: 0.01 - max: 1.0 - momentum: - distribution: uniform - min: 0.6 - max: 0.98 - weight_decay: - distribution: uniform - min: 0.0 - max: 0.001 - warmup_epochs: - distribution: uniform - min: 0.0 - max: 5.0 - warmup_momentum: - distribution: uniform - min: 0.0 - max: 0.95 - warmup_bias_lr: - distribution: uniform - min: 0.0 - max: 0.2 - box: - distribution: uniform - min: 0.02 - max: 0.2 - cls: - distribution: uniform - min: 0.2 - max: 4.0 - cls_pw: - distribution: uniform - min: 0.5 - max: 2.0 - obj: - distribution: uniform - min: 0.2 - max: 4.0 - obj_pw: - distribution: uniform - min: 0.5 - max: 2.0 - iou_t: - distribution: uniform - min: 0.1 - max: 0.7 - anchor_t: - distribution: uniform - min: 2.0 - max: 8.0 - fl_gamma: - distribution: uniform - min: 0.0 - max: 0.1 - hsv_h: - distribution: uniform - min: 0.0 - max: 0.1 - hsv_s: - distribution: uniform - min: 0.0 - max: 0.9 - hsv_v: - distribution: uniform - min: 0.0 - max: 0.9 - degrees: - distribution: uniform - min: 0.0 - max: 45.0 - translate: - distribution: uniform - min: 0.0 - max: 0.9 - scale: - distribution: uniform - min: 0.0 - max: 0.9 - shear: - distribution: uniform - min: 0.0 - max: 10.0 - perspective: - distribution: uniform - min: 0.0 - max: 0.001 - flipud: - distribution: uniform - min: 0.0 - max: 1.0 - fliplr: - distribution: uniform - min: 0.0 - max: 1.0 - mosaic: - distribution: uniform - min: 0.0 - max: 1.0 - mixup: - distribution: uniform - min: 0.0 - max: 1.0 - copy_paste: - distribution: uniform - min: 0.0 - max: 1.0 diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py deleted file mode 100644 index 7087e4e95e..0000000000 --- a/utils/loggers/wandb/wandb_utils.py +++ /dev/null @@ -1,532 +0,0 @@ -"""Utilities and tools for tracking runs with Weights & Biases.""" - -import logging -import os -import sys -from contextlib import contextmanager -from pathlib import Path -from typing import Dict - -import pkg_resources as pkg -import yaml -from tqdm import tqdm - -FILE = Path(__file__).resolve() -ROOT = FILE.parents[3] # root directory -if str(ROOT) not in sys.path: - sys.path.append(str(ROOT)) # add ROOT to PATH - -from utils.datasets import LoadImagesAndLabels, img2label_paths -from utils.general import LOGGER, check_dataset, check_file - -try: - import wandb - - assert hasattr(wandb, '__version__') # verify package import not local dir -except (ImportError, AssertionError): - wandb = None - -RANK = int(os.getenv('RANK', -1)) -WANDB_ARTIFACT_PREFIX = 'wandb-artifact://' - - -def remove_prefix(from_string, prefix=WANDB_ARTIFACT_PREFIX): - return from_string[len(prefix):] - - -def check_wandb_config_file(data_config_file): - wandb_config = '_wandb.'.join(data_config_file.rsplit('.', 1)) # updated data.yaml path - if Path(wandb_config).is_file(): - return wandb_config - return data_config_file - - -def check_wandb_dataset(data_file): - is_trainset_wandb_artifact = False - is_valset_wandb_artifact = False - if check_file(data_file) and data_file.endswith('.yaml'): - with open(data_file, errors='ignore') as f: - data_dict = yaml.safe_load(f) - is_trainset_wandb_artifact = (isinstance(data_dict['train'], str) and - data_dict['train'].startswith(WANDB_ARTIFACT_PREFIX)) - is_valset_wandb_artifact = (isinstance(data_dict['val'], str) and - data_dict['val'].startswith(WANDB_ARTIFACT_PREFIX)) - if is_trainset_wandb_artifact or is_valset_wandb_artifact: - return data_dict - else: - return check_dataset(data_file) - - -def get_run_info(run_path): - run_path = Path(remove_prefix(run_path, WANDB_ARTIFACT_PREFIX)) - run_id = run_path.stem - project = run_path.parent.stem - entity = run_path.parent.parent.stem - model_artifact_name = 'run_' + run_id + '_model' - return entity, project, run_id, model_artifact_name - - -def check_wandb_resume(opt): - process_wandb_config_ddp_mode(opt) if RANK not in [-1, 0] else None - if isinstance(opt.resume, str): - if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): - if RANK not in [-1, 0]: # For resuming DDP runs - entity, project, run_id, model_artifact_name = get_run_info(opt.resume) - api = wandb.Api() - artifact = api.artifact(entity + '/' + project + '/' + model_artifact_name + ':latest') - modeldir = artifact.download() - opt.weights = str(Path(modeldir) / "last.pt") - return True - return None - - -def process_wandb_config_ddp_mode(opt): - with open(check_file(opt.data), errors='ignore') as f: - data_dict = yaml.safe_load(f) # data dict - train_dir, val_dir = None, None - if isinstance(data_dict['train'], str) and data_dict['train'].startswith(WANDB_ARTIFACT_PREFIX): - api = wandb.Api() - train_artifact = api.artifact(remove_prefix(data_dict['train']) + ':' + opt.artifact_alias) - train_dir = train_artifact.download() - train_path = Path(train_dir) / 'data/images/' - data_dict['train'] = str(train_path) - - if isinstance(data_dict['val'], str) and data_dict['val'].startswith(WANDB_ARTIFACT_PREFIX): - api = wandb.Api() - val_artifact = api.artifact(remove_prefix(data_dict['val']) + ':' + opt.artifact_alias) - val_dir = val_artifact.download() - val_path = Path(val_dir) / 'data/images/' - data_dict['val'] = str(val_path) - if train_dir or val_dir: - ddp_data_path = str(Path(val_dir) / 'wandb_local_data.yaml') - with open(ddp_data_path, 'w') as f: - yaml.safe_dump(data_dict, f) - opt.data = ddp_data_path - - -class WandbLogger(): - """Log training runs, datasets, models, and predictions to Weights & Biases. - - This logger sends information to W&B at wandb.ai. By default, this information - includes hyperparameters, system configuration and metrics, model metrics, - and basic data metrics and analyses. - - By providing additional command line arguments to train.py, datasets, - models and predictions can also be logged. - - For more on how this logger is used, see the Weights & Biases documentation: - https://docs.wandb.com/guides/integrations/yolov5 - """ - - def __init__(self, opt, run_id=None, job_type='Training'): - """ - - Initialize WandbLogger instance - - Upload dataset if opt.upload_dataset is True - - Setup trainig processes if job_type is 'Training' - - arguments: - opt (namespace) -- Commandline arguments for this run - run_id (str) -- Run ID of W&B run to be resumed - job_type (str) -- To set the job_type for this run - - """ - # Pre-training routine -- - self.job_type = job_type - self.wandb, self.wandb_run = wandb, None if not wandb else wandb.run - self.val_artifact, self.train_artifact = None, None - self.train_artifact_path, self.val_artifact_path = None, None - self.result_artifact = None - self.val_table, self.result_table = None, None - self.bbox_media_panel_images = [] - self.val_table_path_map = None - self.max_imgs_to_log = 16 - self.wandb_artifact_data_dict = None - self.data_dict = None - # It's more elegant to stick to 1 wandb.init call, - # but useful config data is overwritten in the WandbLogger's wandb.init call - if isinstance(opt.resume, str): # checks resume from artifact - if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): - entity, project, run_id, model_artifact_name = get_run_info(opt.resume) - model_artifact_name = WANDB_ARTIFACT_PREFIX + model_artifact_name - assert wandb, 'install wandb to resume wandb runs' - # Resume wandb-artifact:// runs here| workaround for not overwriting wandb.config - self.wandb_run = wandb.init(id=run_id, - project=project, - entity=entity, - resume='allow', - allow_val_change=True) - opt.resume = model_artifact_name - elif self.wandb: - self.wandb_run = wandb.init(config=opt, - resume="allow", - project='YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem, - entity=opt.entity, - name=opt.name if opt.name != 'exp' else None, - job_type=job_type, - id=run_id, - allow_val_change=True) if not wandb.run else wandb.run - if self.wandb_run: - if self.job_type == 'Training': - if opt.upload_dataset: - if not opt.resume: - self.wandb_artifact_data_dict = self.check_and_upload_dataset(opt) - - if opt.resume: - # resume from artifact - if isinstance(opt.resume, str) and opt.resume.startswith(WANDB_ARTIFACT_PREFIX): - self.data_dict = dict(self.wandb_run.config.data_dict) - else: # local resume - self.data_dict = check_wandb_dataset(opt.data) - else: - self.data_dict = check_wandb_dataset(opt.data) - self.wandb_artifact_data_dict = self.wandb_artifact_data_dict or self.data_dict - - # write data_dict to config. useful for resuming from artifacts. Do this only when not resuming. - self.wandb_run.config.update({'data_dict': self.wandb_artifact_data_dict}, - allow_val_change=True) - self.setup_training(opt) - - if self.job_type == 'Dataset Creation': - self.data_dict = self.check_and_upload_dataset(opt) - - def check_and_upload_dataset(self, opt): - """ - Check if the dataset format is compatible and upload it as W&B artifact - - arguments: - opt (namespace)-- Commandline arguments for current run - - returns: - Updated dataset info dictionary where local dataset paths are replaced by WAND_ARFACT_PREFIX links. - """ - assert wandb, 'Install wandb to upload dataset' - config_path = self.log_dataset_artifact(opt.data, - opt.single_cls, - 'YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem) - LOGGER.info(f"Created dataset config file {config_path}") - with open(config_path, errors='ignore') as f: - wandb_data_dict = yaml.safe_load(f) - return wandb_data_dict - - def setup_training(self, opt): - """ - Setup the necessary processes for training YOLO models: - - Attempt to download model checkpoint and dataset artifacts if opt.resume stats with WANDB_ARTIFACT_PREFIX - - Update data_dict, to contain info of previous run if resumed and the paths of dataset artifact if downloaded - - Setup log_dict, initialize bbox_interval - - arguments: - opt (namespace) -- commandline arguments for this run - - """ - self.log_dict, self.current_epoch = {}, 0 - self.bbox_interval = opt.bbox_interval - if isinstance(opt.resume, str): - modeldir, _ = self.download_model_artifact(opt) - if modeldir: - self.weights = Path(modeldir) / "last.pt" - config = self.wandb_run.config - opt.weights, opt.save_period, opt.batch_size, opt.bbox_interval, opt.epochs, opt.hyp = str( - self.weights), config.save_period, config.batch_size, config.bbox_interval, config.epochs, \ - config.hyp - data_dict = self.data_dict - if self.val_artifact is None: # If --upload_dataset is set, use the existing artifact, don't download - self.train_artifact_path, self.train_artifact = self.download_dataset_artifact(data_dict.get('train'), - opt.artifact_alias) - self.val_artifact_path, self.val_artifact = self.download_dataset_artifact(data_dict.get('val'), - opt.artifact_alias) - - if self.train_artifact_path is not None: - train_path = Path(self.train_artifact_path) / 'data/images/' - data_dict['train'] = str(train_path) - if self.val_artifact_path is not None: - val_path = Path(self.val_artifact_path) / 'data/images/' - data_dict['val'] = str(val_path) - - if self.val_artifact is not None: - self.result_artifact = wandb.Artifact("run_" + wandb.run.id + "_progress", "evaluation") - self.result_table = wandb.Table(["epoch", "id", "ground truth", "prediction", "avg_confidence"]) - self.val_table = self.val_artifact.get("val") - if self.val_table_path_map is None: - self.map_val_table_path() - if opt.bbox_interval == -1: - self.bbox_interval = opt.bbox_interval = (opt.epochs // 10) if opt.epochs > 10 else 1 - train_from_artifact = self.train_artifact_path is not None and self.val_artifact_path is not None - # Update the the data_dict to point to local artifacts dir - if train_from_artifact: - self.data_dict = data_dict - - def download_dataset_artifact(self, path, alias): - """ - download the model checkpoint artifact if the path starts with WANDB_ARTIFACT_PREFIX - - arguments: - path -- path of the dataset to be used for training - alias (str)-- alias of the artifact to be download/used for training - - returns: - (str, wandb.Artifact) -- path of the downladed dataset and it's corresponding artifact object if dataset - is found otherwise returns (None, None) - """ - if isinstance(path, str) and path.startswith(WANDB_ARTIFACT_PREFIX): - artifact_path = Path(remove_prefix(path, WANDB_ARTIFACT_PREFIX) + ":" + alias) - dataset_artifact = wandb.use_artifact(artifact_path.as_posix().replace("\\", "/")) - assert dataset_artifact is not None, "'Error: W&B dataset artifact doesn\'t exist'" - datadir = dataset_artifact.download() - return datadir, dataset_artifact - return None, None - - def download_model_artifact(self, opt): - """ - download the model checkpoint artifact if the resume path starts with WANDB_ARTIFACT_PREFIX - - arguments: - opt (namespace) -- Commandline arguments for this run - """ - if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): - model_artifact = wandb.use_artifact(remove_prefix(opt.resume, WANDB_ARTIFACT_PREFIX) + ":latest") - assert model_artifact is not None, 'Error: W&B model artifact doesn\'t exist' - modeldir = model_artifact.download() - epochs_trained = model_artifact.metadata.get('epochs_trained') - total_epochs = model_artifact.metadata.get('total_epochs') - is_finished = total_epochs is None - assert not is_finished, 'training is finished, can only resume incomplete runs.' - return modeldir, model_artifact - return None, None - - def log_model(self, path, opt, epoch, fitness_score, best_model=False): - """ - Log the model checkpoint as W&B artifact - - arguments: - path (Path) -- Path of directory containing the checkpoints - opt (namespace) -- Command line arguments for this run - epoch (int) -- Current epoch number - fitness_score (float) -- fitness score for current epoch - best_model (boolean) -- Boolean representing if the current checkpoint is the best yet. - """ - model_artifact = wandb.Artifact('run_' + wandb.run.id + '_model', type='model', metadata={ - 'original_url': str(path), - 'epochs_trained': epoch + 1, - 'save period': opt.save_period, - 'project': opt.project, - 'total_epochs': opt.epochs, - 'fitness_score': fitness_score - }) - model_artifact.add_file(str(path / 'last.pt'), name='last.pt') - wandb.log_artifact(model_artifact, - aliases=['latest', 'last', 'epoch ' + str(self.current_epoch), 'best' if best_model else '']) - LOGGER.info(f"Saving model artifact on epoch {epoch + 1}") - - def log_dataset_artifact(self, data_file, single_cls, project, overwrite_config=False): - """ - Log the dataset as W&B artifact and return the new data file with W&B links - - arguments: - data_file (str) -- the .yaml file with information about the dataset like - path, classes etc. - single_class (boolean) -- train multi-class data as single-class - project (str) -- project name. Used to construct the artifact path - overwrite_config (boolean) -- overwrites the data.yaml file if set to true otherwise creates a new - file with _wandb postfix. Eg -> data_wandb.yaml - - returns: - the new .yaml file with artifact links. it can be used to start training directly from artifacts - """ - self.data_dict = check_dataset(data_file) # parse and check - data = dict(self.data_dict) - nc, names = (1, ['item']) if single_cls else (int(data['nc']), data['names']) - names = {k: v for k, v in enumerate(names)} # to index dictionary - self.train_artifact = self.create_dataset_table(LoadImagesAndLabels( - data['train'], rect=True, batch_size=1), names, name='train') if data.get('train') else None - self.val_artifact = self.create_dataset_table(LoadImagesAndLabels( - data['val'], rect=True, batch_size=1), names, name='val') if data.get('val') else None - if data.get('train'): - data['train'] = WANDB_ARTIFACT_PREFIX + str(Path(project) / 'train') - if data.get('val'): - data['val'] = WANDB_ARTIFACT_PREFIX + str(Path(project) / 'val') - path = Path(data_file).stem - path = (path if overwrite_config else path + '_wandb') + '.yaml' # updated data.yaml path - data.pop('download', None) - data.pop('path', None) - with open(path, 'w') as f: - yaml.safe_dump(data, f) - - if self.job_type == 'Training': # builds correct artifact pipeline graph - self.wandb_run.use_artifact(self.val_artifact) - self.wandb_run.use_artifact(self.train_artifact) - self.val_artifact.wait() - self.val_table = self.val_artifact.get('val') - self.map_val_table_path() - else: - self.wandb_run.log_artifact(self.train_artifact) - self.wandb_run.log_artifact(self.val_artifact) - return path - - def map_val_table_path(self): - """ - Map the validation dataset Table like name of file -> it's id in the W&B Table. - Useful for - referencing artifacts for evaluation. - """ - self.val_table_path_map = {} - LOGGER.info("Mapping dataset") - for i, data in enumerate(tqdm(self.val_table.data)): - self.val_table_path_map[data[3]] = data[0] - - def create_dataset_table(self, dataset: LoadImagesAndLabels, class_to_id: Dict[int,str], name: str = 'dataset'): - """ - Create and return W&B artifact containing W&B Table of the dataset. - - arguments: - dataset -- instance of LoadImagesAndLabels class used to iterate over the data to build Table - class_to_id -- hash map that maps class ids to labels - name -- name of the artifact - - returns: - dataset artifact to be logged or used - """ - # TODO: Explore multiprocessing to slpit this loop parallely| This is essential for speeding up the the logging - artifact = wandb.Artifact(name=name, type="dataset") - img_files = tqdm([dataset.path]) if isinstance(dataset.path, str) and Path(dataset.path).is_dir() else None - img_files = tqdm(dataset.img_files) if not img_files else img_files - for img_file in img_files: - if Path(img_file).is_dir(): - artifact.add_dir(img_file, name='data/images') - labels_path = 'labels'.join(dataset.path.rsplit('images', 1)) - artifact.add_dir(labels_path, name='data/labels') - else: - artifact.add_file(img_file, name='data/images/' + Path(img_file).name) - label_file = Path(img2label_paths([img_file])[0]) - artifact.add_file(str(label_file), - name='data/labels/' + label_file.name) if label_file.exists() else None - table = wandb.Table(columns=["id", "train_image", "Classes", "name"]) - class_set = wandb.Classes([{'id': id, 'name': name} for id, name in class_to_id.items()]) - for si, (img, labels, paths, shapes) in enumerate(tqdm(dataset)): - box_data, img_classes = [], {} - for cls, *xywh in labels[:, 1:].tolist(): - cls = int(cls) - box_data.append({"position": {"middle": [xywh[0], xywh[1]], "width": xywh[2], "height": xywh[3]}, - "class_id": cls, - "box_caption": "%s" % (class_to_id[cls])}) - img_classes[cls] = class_to_id[cls] - boxes = {"ground_truth": {"box_data": box_data, "class_labels": class_to_id}} # inference-space - table.add_data(si, wandb.Image(paths, classes=class_set, boxes=boxes), list(img_classes.values()), - Path(paths).name) - artifact.add(table, name) - return artifact - - def log_training_progress(self, predn, path, names): - """ - Build evaluation Table. Uses reference from validation dataset table. - - arguments: - predn (list): list of predictions in the native space in the format - [xmin, ymin, xmax, ymax, confidence, class] - path (str): local path of the current evaluation image - names (dict(int, str)): hash map that maps class ids to labels - """ - class_set = wandb.Classes([{'id': id, 'name': name} for id, name in names.items()]) - box_data = [] - total_conf = 0 - for *xyxy, conf, cls in predn.tolist(): - if conf >= 0.25: - box_data.append( - {"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, - "class_id": int(cls), - "box_caption": f"{names[cls]} {conf:.3f}", - "scores": {"class_score": conf}, - "domain": "pixel"}) - total_conf += conf - boxes = {"predictions": {"box_data": box_data, "class_labels": names}} # inference-space - id = self.val_table_path_map[Path(path).name] - self.result_table.add_data(self.current_epoch, - id, - self.val_table.data[id][1], - wandb.Image(self.val_table.data[id][1], boxes=boxes, classes=class_set), - total_conf / max(1, len(box_data)) - ) - - def val_one_image(self, pred, predn, path, names, im): - """ - Log validation data for one image. updates the result Table if validation dataset is uploaded and log bbox media panel - - arguments: - pred (list): list of scaled predictions in the format - [xmin, ymin, xmax, ymax, confidence, class] - predn (list): list of predictions in the native space - [xmin, ymin, xmax, ymax, confidence, class] - path (str): local path of the current evaluation image - """ - if self.val_table and self.result_table: # Log Table if Val dataset is uploaded as artifact - self.log_training_progress(predn, path, names) - - if len(self.bbox_media_panel_images) < self.max_imgs_to_log and self.current_epoch > 0: - if self.current_epoch % self.bbox_interval == 0: - box_data = [{"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, - "class_id": int(cls), - "box_caption": f"{names[cls]} {conf:.3f}", - "scores": {"class_score": conf}, - "domain": "pixel"} for *xyxy, conf, cls in pred.tolist()] - boxes = {"predictions": {"box_data": box_data, "class_labels": names}} # inference-space - self.bbox_media_panel_images.append(wandb.Image(im, boxes=boxes, caption=path.name)) - - def log(self, log_dict): - """ - save the metrics to the logging dictionary - - arguments: - log_dict (Dict) -- metrics/media to be logged in current step - """ - if self.wandb_run: - for key, value in log_dict.items(): - self.log_dict[key] = value - - def end_epoch(self, best_result=False): - """ - commit the log_dict, model artifacts and Tables to W&B and flush the log_dict. - - arguments: - best_result (boolean): Boolean representing if the result of this evaluation is best or not - """ - if self.wandb_run: - with all_logging_disabled(): - if self.bbox_media_panel_images: - self.log_dict["BoundingBoxDebugger"] = self.bbox_media_panel_images - try: - wandb.log(self.log_dict) - except BaseException as e: - LOGGER.info(f"An error occurred in wandb logger. The training will proceed without interruption. More info\n{e}") - self.wandb_run.finish() - self.wandb_run = None - - self.log_dict = {} - self.bbox_media_panel_images = [] - if self.result_artifact: - self.result_artifact.add(self.result_table, 'result') - wandb.log_artifact(self.result_artifact, aliases=['latest', 'last', 'epoch ' + str(self.current_epoch), - ('best' if best_result else '')]) - - wandb.log({"evaluation": self.result_table}) - self.result_table = wandb.Table(["epoch", "id", "ground truth", "prediction", "avg_confidence"]) - self.result_artifact = wandb.Artifact("run_" + wandb.run.id + "_progress", "evaluation") - - def finish_run(self): - """ - Log metrics if any and finish the current W&B run - """ - if self.wandb_run: - if self.log_dict: - with all_logging_disabled(): - wandb.log(self.log_dict) - wandb.run.finish() - - -@contextmanager -def all_logging_disabled(highest_level=logging.CRITICAL): - """ source - https://gist.github.com/simon-weber/7853144 - A context manager that will prevent any logging messages triggered during the body from being processed. - :param highest_level: the maximum logging level in use. - This would only need to be changed if a custom level greater than CRITICAL is defined. - """ - previous_level = logging.root.manager.disable - logging.disable(highest_level) - try: - yield - finally: - logging.disable(previous_level) From 1a2d5c6a5a1269327e1caca46c362821bd186152 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Feb 2023 02:15:51 +0400 Subject: [PATCH 0931/1185] Update Dockerfile (#2010) * Update Dockerfile * Update Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4584b7edf8..ce3c4667b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,7 +45,7 @@ ENV DEBIAN_FRONTEND teletype # Usage Examples ------------------------------------------------------------------------------------------------------- # Build and Push -# t=ultralytics/yolov3:latest && sudo docker build -f utils/docker/Dockerfile -t $t . && sudo docker push $t +# t=ultralytics/yolov3:latest && sudo docker build -f Dockerfile -t $t . && sudo docker push $t # Pull and Run # t=ultralytics/yolov3:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all $t From f50bcfcc3e019aaa1ece410158acf3b28f3a25e5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 11 Feb 2023 15:20:10 +0400 Subject: [PATCH 0932/1185] YOLOv3 general updates, improvements and fixes (#2011) * YOLOv3 updates * Add missing files * Reformat * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Reformat * Reformat * Reformat * Reformat * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .dockerignore | 4 +- .github/FUNDING.yml | 5 - .github/ISSUE_TEMPLATE/bug-report.yml | 8 +- .github/ISSUE_TEMPLATE/config.yml | 6 +- .github/ISSUE_TEMPLATE/feature-request.yml | 8 +- .github/ISSUE_TEMPLATE/question.yml | 4 +- .github/PULL_REQUEST_TEMPLATE.md | 9 + .github/workflows/ci-testing.yml | 47 +- .github/workflows/docker.yml | 57 + .github/workflows/greetings.yml | 16 +- .github/workflows/rebase.yml | 21 - .github/workflows/stale.yml | 18 +- .github/workflows/translate-readme.yml | 26 + .gitignore | 9 +- .pre-commit-config.yaml | 68 +- CITATION.cff | 14 + CONTRIBUTING.md | 51 +- README.md | 260 ++- README.zh-CN.md | 532 ++++++ benchmarks.py | 169 ++ classify/predict.py | 226 +++ classify/train.py | 333 ++++ classify/tutorial.ipynb | 1480 +++++++++++++++++ classify/val.py | 170 ++ data/Argoverse.yaml | 21 +- data/GlobalWheat2020.yaml | 11 +- data/ImageNet.yaml | 1022 ++++++++++++ data/SKU-110K.yaml | 11 +- data/VisDrone.yaml | 21 +- data/coco.yaml | 100 +- data/coco128-seg.yaml | 101 ++ data/coco128.yaml | 97 +- data/hyps/hyp.Objects365.yaml | 34 + data/hyps/hyp.VOC.yaml | 40 + ....scratch.yaml => hyp.no-augmentation.yaml} | 29 +- data/hyps/hyp.scratch-high.yaml | 2 +- data/objects365.yaml | 420 ++++- data/scripts/download_weights.sh | 20 +- data/scripts/get_coco.sh | 47 +- data/scripts/get_coco128.sh | 4 +- data/scripts/get_imagenet.sh | 51 + data/voc.yaml | 48 +- data/xView.yaml | 81 +- detect.py | 157 +- export.py | 840 +++++++--- hubconf.py | 154 +- models/common.py | 724 +++++--- models/experimental.py | 68 +- models/hub/anchors.yaml | 59 + models/hub/yolov5-bifpn.yaml | 48 + models/hub/yolov5-fpn.yaml | 42 + models/hub/yolov5-p2.yaml | 54 + models/hub/yolov5-p34.yaml | 41 + models/hub/yolov5-p6.yaml | 56 + models/hub/yolov5-p7.yaml | 67 + models/hub/yolov5-panet.yaml | 48 + models/hub/yolov5l6.yaml | 60 + models/hub/yolov5m6.yaml | 60 + models/hub/yolov5n6.yaml | 60 + models/hub/yolov5s-LeakyReLU.yaml | 49 + models/hub/yolov5s-ghost.yaml | 48 + models/hub/yolov5s-transformer.yaml | 48 + models/hub/yolov5s6.yaml | 60 + models/hub/yolov5x6.yaml | 60 + models/segment/yolov5l-seg.yaml | 48 + models/segment/yolov5m-seg.yaml | 48 + models/segment/yolov5n-seg.yaml | 48 + models/segment/yolov5s-seg.yaml | 48 + models/segment/yolov5x-seg.yaml | 48 + models/tf.py | 448 +++-- models/yolo.py | 292 ++-- models/yolov5l.yaml | 48 + models/yolov5m.yaml | 48 + models/yolov5n.yaml | 48 + models/yolov5s.yaml | 48 + models/yolov5x.yaml | 48 + requirements.txt | 30 +- segment/predict.py | 284 ++++ segment/train.py | 659 ++++++++ segment/tutorial.ipynb | 594 +++++++ segment/val.py | 473 ++++++ setup.cfg | 45 +- train.py | 490 +++--- tutorial.ipynb | 1183 ++++++------- utils/__init__.py | 74 +- utils/activations.py | 22 +- utils/augmentations.py | 154 +- utils/autoanchor.py | 71 +- utils/autobatch.py | 49 +- utils/aws/__init__.py | 0 utils/aws/mime.sh | 26 + utils/aws/resume.py | 40 + utils/aws/userdata.sh | 27 + utils/callbacks.py | 82 +- utils/dataloaders.py | 1221 ++++++++++++++ utils/datasets.py | 1036 ------------ Dockerfile => utils/docker/Dockerfile | 18 +- utils/docker/Dockerfile-arm64 | 41 + utils/docker/Dockerfile-cpu | 42 + utils/downloads.py | 169 +- utils/flask_rest_api/README.md | 73 + utils/flask_rest_api/example_request.py | 19 + utils/flask_rest_api/restapi.py | 48 + utils/general.py | 958 +++++++---- utils/google_app_engine/Dockerfile | 25 + .../additional_requirements.txt | 4 + utils/google_app_engine/app.yaml | 14 + utils/loggers/__init__.py | 342 +++- utils/loggers/clearml/README.md | 271 +++ utils/loggers/clearml/__init__.py | 0 utils/loggers/clearml/clearml_utils.py | 164 ++ utils/loggers/clearml/hpo.py | 84 + utils/loggers/comet/README.md | 284 ++++ utils/loggers/comet/__init__.py | 508 ++++++ utils/loggers/comet/comet_utils.py | 150 ++ utils/loggers/comet/hpo.py | 118 ++ utils/loggers/comet/optimizer_config.json | 209 +++ utils/loggers/wandb/__init__.py | 0 utils/loggers/wandb/wandb_utils.py | 193 +++ utils/metrics.py | 205 ++- utils/plots.py | 201 ++- utils/segment/__init__.py | 0 utils/segment/augmentations.py | 104 ++ utils/segment/dataloaders.py | 332 ++++ utils/segment/general.py | 160 ++ utils/segment/loss.py | 186 +++ utils/segment/metrics.py | 210 +++ utils/segment/plots.py | 143 ++ utils/torch_utils.py | 294 +++- utils/triton.py | 85 + val.py | 254 +-- 131 files changed, 17914 insertions(+), 4278 deletions(-) delete mode 100644 .github/FUNDING.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/docker.yml delete mode 100644 .github/workflows/rebase.yml create mode 100644 .github/workflows/translate-readme.yml create mode 100644 CITATION.cff create mode 100644 README.zh-CN.md create mode 100644 benchmarks.py create mode 100644 classify/predict.py create mode 100644 classify/train.py create mode 100644 classify/tutorial.ipynb create mode 100644 classify/val.py create mode 100644 data/ImageNet.yaml create mode 100644 data/coco128-seg.yaml create mode 100644 data/hyps/hyp.Objects365.yaml create mode 100644 data/hyps/hyp.VOC.yaml rename data/hyps/{hyp.scratch.yaml => hyp.no-augmentation.yaml} (54%) mode change 100644 => 100755 data/scripts/get_coco128.sh create mode 100755 data/scripts/get_imagenet.sh create mode 100644 models/hub/anchors.yaml create mode 100644 models/hub/yolov5-bifpn.yaml create mode 100644 models/hub/yolov5-fpn.yaml create mode 100644 models/hub/yolov5-p2.yaml create mode 100644 models/hub/yolov5-p34.yaml create mode 100644 models/hub/yolov5-p6.yaml create mode 100644 models/hub/yolov5-p7.yaml create mode 100644 models/hub/yolov5-panet.yaml create mode 100644 models/hub/yolov5l6.yaml create mode 100644 models/hub/yolov5m6.yaml create mode 100644 models/hub/yolov5n6.yaml create mode 100644 models/hub/yolov5s-LeakyReLU.yaml create mode 100644 models/hub/yolov5s-ghost.yaml create mode 100644 models/hub/yolov5s-transformer.yaml create mode 100644 models/hub/yolov5s6.yaml create mode 100644 models/hub/yolov5x6.yaml create mode 100644 models/segment/yolov5l-seg.yaml create mode 100644 models/segment/yolov5m-seg.yaml create mode 100644 models/segment/yolov5n-seg.yaml create mode 100644 models/segment/yolov5s-seg.yaml create mode 100644 models/segment/yolov5x-seg.yaml create mode 100644 models/yolov5l.yaml create mode 100644 models/yolov5m.yaml create mode 100644 models/yolov5n.yaml create mode 100644 models/yolov5s.yaml create mode 100644 models/yolov5x.yaml mode change 100755 => 100644 requirements.txt create mode 100644 segment/predict.py create mode 100644 segment/train.py create mode 100644 segment/tutorial.ipynb create mode 100644 segment/val.py create mode 100644 utils/aws/__init__.py create mode 100644 utils/aws/mime.sh create mode 100644 utils/aws/resume.py create mode 100644 utils/aws/userdata.sh create mode 100644 utils/dataloaders.py delete mode 100755 utils/datasets.py rename Dockerfile => utils/docker/Dockerfile (79%) create mode 100644 utils/docker/Dockerfile-arm64 create mode 100644 utils/docker/Dockerfile-cpu create mode 100644 utils/flask_rest_api/README.md create mode 100644 utils/flask_rest_api/example_request.py create mode 100644 utils/flask_rest_api/restapi.py mode change 100755 => 100644 utils/general.py create mode 100644 utils/google_app_engine/Dockerfile create mode 100644 utils/google_app_engine/additional_requirements.txt create mode 100644 utils/google_app_engine/app.yaml create mode 100644 utils/loggers/clearml/README.md create mode 100644 utils/loggers/clearml/__init__.py create mode 100644 utils/loggers/clearml/clearml_utils.py create mode 100644 utils/loggers/clearml/hpo.py create mode 100644 utils/loggers/comet/README.md create mode 100644 utils/loggers/comet/__init__.py create mode 100644 utils/loggers/comet/comet_utils.py create mode 100644 utils/loggers/comet/hpo.py create mode 100644 utils/loggers/comet/optimizer_config.json create mode 100644 utils/loggers/wandb/__init__.py create mode 100644 utils/loggers/wandb/wandb_utils.py create mode 100644 utils/segment/__init__.py create mode 100644 utils/segment/augmentations.py create mode 100644 utils/segment/dataloaders.py create mode 100644 utils/segment/general.py create mode 100644 utils/segment/loss.py create mode 100644 utils/segment/metrics.py create mode 100644 utils/segment/plots.py create mode 100644 utils/triton.py diff --git a/.dockerignore b/.dockerignore index 6c2f2b9b77..3b669254e7 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,5 @@ # Repo-specific DockerIgnore ------------------------------------------------------------------------------------------- -#.git +.git .cache .idea runs @@ -15,6 +15,7 @@ data/samples/* **/*.pt **/*.pth **/*.onnx +**/*.engine **/*.mlmodel **/*.torchscript **/*.torchscript.pt @@ -23,6 +24,7 @@ data/samples/* **/*.pb *_saved_model/ *_web_model/ +*_openvino_model/ # Below Copied From .gitignore ----------------------------------------------------------------------------------------- # Below Copied From .gitignore ----------------------------------------------------------------------------------------- diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 3da386f7e7..0000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,5 +0,0 @@ -# These are supported funding model platforms - -github: glenn-jocher -patreon: ultralytics -open_collective: ultralytics diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index affe6aae2b..9c11b695ee 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -12,10 +12,10 @@ body: attributes: label: Search before asking description: > - Please search the [issues](https://github.com/ultralytics/yolov3/issues) to see if a similar bug report already exists. + Please search the [issues](https://github.com/ultralytics/yolov5/issues) to see if a similar bug report already exists. options: - label: > - I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov3/issues) and found no similar bug report. + I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov5/issues) and found no similar bug report. required: true - type: dropdown @@ -79,7 +79,7 @@ body: attributes: label: Are you willing to submit a PR? description: > - (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. - See the YOLOv3 [Contributing Guide](https://github.com/ultralytics/yolov3/blob/master/CONTRIBUTING.md) to get started. + (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov5/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. + See the YOLOv3 [Contributing Guide](https://github.com/ultralytics/yolov5/blob/master/CONTRIBUTING.md) to get started. options: - label: Yes I'd like to help by submitting a PR! diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 02be0529fc..e6a8c427cc 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,8 @@ blank_issues_enabled: true contact_links: - - name: Slack - url: https://join.slack.com/t/ultralytics/shared_invite/zt-w29ei8bp-jczz7QYUmDtgo6r6KcMIAg - about: Ask on Ultralytics Slack Forum + - name: 💬 Forum + url: https://community.ultralytics.com/ + about: Ask on Ultralytics Community Forum - name: Stack Overflow url: https://stackoverflow.com/search?q=YOLOv3 about: Ask on Stack Overflow with 'YOLOv3' tag diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index 53cf234475..d67e330126 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -12,10 +12,10 @@ body: attributes: label: Search before asking description: > - Please search the [issues](https://github.com/ultralytics/yolov3/issues) to see if a similar feature request already exists. + Please search the [issues](https://github.com/ultralytics/yolov5/issues) to see if a similar feature request already exists. options: - label: > - I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov3/issues) and found no similar feature requests. + I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov5/issues) and found no similar feature requests. required: true - type: textarea @@ -44,7 +44,7 @@ body: attributes: label: Are you willing to submit a PR? description: > - (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. - See the YOLOv3 [Contributing Guide](https://github.com/ultralytics/yolov3/blob/master/CONTRIBUTING.md) to get started. + (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov5/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. + See the YOLOv3 [Contributing Guide](https://github.com/ultralytics/yolov5/blob/master/CONTRIBUTING.md) to get started. options: - label: Yes I'd like to help by submitting a PR! diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml index decb214859..c056eec8a4 100644 --- a/.github/ISSUE_TEMPLATE/question.yml +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -12,10 +12,10 @@ body: attributes: label: Search before asking description: > - Please search the [issues](https://github.com/ultralytics/yolov3/issues) and [discussions](https://github.com/ultralytics/yolov3/discussions) to see if a similar question already exists. + Please search the [issues](https://github.com/ultralytics/yolov5/issues) and [discussions](https://github.com/ultralytics/yolov5/discussions) to see if a similar question already exists. options: - label: > - I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov3/issues) and [discussions](https://github.com/ultralytics/yolov3/discussions) and found no similar questions. + I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov5/issues) and [discussions](https://github.com/ultralytics/yolov5/discussions) and found no similar questions. required: true - type: textarea diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..f25b017ace --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,9 @@ + diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index b0a6bfd947..6be6236de1 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -5,9 +5,9 @@ name: YOLOv3 CI on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] schedule: - cron: '0 0 * * *' # runs at 00:00 UTC every day @@ -18,22 +18,22 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-latest, windows-latest ] # macos-latest bug https://github.com/ultralytics/yolov5/pull/9049 - python-version: [ '3.10' ] - model: [ yolov3-tiny ] + os: [ubuntu-latest, windows-latest] # macos-latest bug https://github.com/ultralytics/yolov5/pull/9049 + python-version: ['3.10'] + model: [yolov5n] include: - os: ubuntu-latest python-version: '3.7' # '3.6.8' min - model: yolov3-tiny + model: yolov5n - os: ubuntu-latest python-version: '3.8' - model: yolov3-tiny + model: yolov5n - os: ubuntu-latest python-version: '3.9' - model: yolov3-tiny + model: yolov5n - os: ubuntu-latest python-version: '3.8' # torch 1.7.0 requires python >=3.6, <=3.8 - model: yolov3-tiny + model: yolov5n torch: '1.7.0' # min torch version CI https://pypi.org/project/torchvision/ steps: - uses: actions/checkout@v3 @@ -97,3 +97,32 @@ jobs: model(im) # warmup, build grids for trace torch.jit.trace(model, [im]) EOF + - name: Test segmentation + shell: bash # for Windows compatibility + run: | + m=${{ matrix.model }}-seg # official weights + b=runs/train-seg/exp/weights/best # best.pt checkpoint + python segment/train.py --imgsz 64 --batch 32 --weights $m.pt --cfg $m.yaml --epochs 1 --device cpu # train + python segment/train.py --imgsz 64 --batch 32 --weights '' --cfg $m.yaml --epochs 1 --device cpu # train + for d in cpu; do # devices + for w in $m $b; do # weights + python segment/val.py --imgsz 64 --batch 32 --weights $w.pt --device $d # val + python segment/predict.py --imgsz 64 --weights $w.pt --device $d # predict + python export.py --weights $w.pt --img 64 --include torchscript --device $d # export + done + done + - name: Test classification + shell: bash # for Windows compatibility + run: | + m=${{ matrix.model }}-cls.pt # official weights + b=runs/train-cls/exp/weights/best.pt # best.pt checkpoint + python classify/train.py --imgsz 32 --model $m --data mnist160 --epochs 1 # train + python classify/val.py --imgsz 32 --weights $b --data ../datasets/mnist160 # val + python classify/predict.py --imgsz 32 --weights $b --source ../datasets/mnist160/test/7/60.png # predict + python classify/predict.py --imgsz 32 --weights $m --source data/images/bus.jpg # predict + python export.py --weights $b --img 64 --include torchscript # export + python - <=3.7.0**](https://www.python.org/) with all [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) installed including [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). To get started: ```bash - git clone https://github.com/ultralytics/yolov3 # clone - cd yolov3 + git clone https://github.com/ultralytics/yolov5 # clone + cd yolov5 pip install -r requirements.txt # install ``` @@ -45,7 +45,7 @@ jobs: - **Notebooks** with free GPU: Run on Gradient Open In Colab Open In Kaggle - **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/GCP-Quickstart) - **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/AWS-Quickstart) - - **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/Docker-Quickstart) Docker Pulls + - **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/Docker-Quickstart) Docker Pulls ## Status @@ -53,9 +53,13 @@ jobs: If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 [training](https://github.com/ultralytics/yolov5/blob/master/train.py), [validation](https://github.com/ultralytics/yolov5/blob/master/val.py), [inference](https://github.com/ultralytics/yolov5/blob/master/detect.py), [export](https://github.com/ultralytics/yolov5/blob/master/export.py) and [benchmarks](https://github.com/ultralytics/yolov5/blob/master/benchmarks.py) on MacOS, Windows, and Ubuntu every 24 hours and on every commit. - ## YOLOv8 + ## Introducing YOLOv8 🚀 - Ultralytics YOLOv8 🚀 is our new cutting-edge, state-of-the-art (SOTA) model released at [https://github.com/ultralytics/ultralytics](https://github.com/ultralytics/ultralytics). YOLOv8 is designed to be fast, accurate, and easy to use, making it an excellent choice for a wide range of object detection, image segmentation and image classification tasks. See the [YOLOv8 Docs] for details and get started with: + We're excited to announce the launch of our latest state-of-the-art (SOTA) object detection model for 2023 - [YOLOv8](https://github.com/ultralytics/ultralytics) 🚀! + + Designed to be fast, accurate, and easy to use, YOLOv8 is an ideal choice for a wide range of object detection, image segmentation and image classification tasks. With YOLOv8, you'll be able to quickly and accurately detect objects in real-time, streamline your workflows, and achieve new levels of accuracy in your projects. + + Check out our [YOLOv8 Docs](https://docs.ultralytics.com/) for details and get started with: ```bash pip install ultralytics ``` diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml deleted file mode 100644 index 5ec1791d5a..0000000000 --- a/.github/workflows/rebase.yml +++ /dev/null @@ -1,21 +0,0 @@ -# https://github.com/marketplace/actions/automatic-rebase - -name: Automatic Rebase -on: - issue_comment: - types: [created] -jobs: - rebase: - name: Rebase - if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') - runs-on: ubuntu-latest - steps: - - name: Checkout the latest code - uses: actions/checkout@v3 - with: - token: ${{ secrets.ACTIONS_TOKEN }} - fetch-depth: 0 # otherwise, you will fail to push refs to dest repo - - name: Automatic Rebase - uses: cirrus-actions/rebase@1.8 - env: - GITHUB_TOKEN: ${{ secrets.ACTIONS_TOKEN }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 819a537950..5db90eebcf 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -3,7 +3,7 @@ name: Close stale issues on: schedule: - - cron: "0 0 * * *" + - cron: '0 0 * * *' # Runs at 00:00 UTC every day jobs: stale: @@ -15,9 +15,9 @@ jobs: stale-issue-message: | 👋 Hello, this issue has been automatically marked as stale because it has not had recent activity. Please note it will be closed if no further activity occurs. - Access additional [YOLOv3](https://ultralytics.com/yolov3) 🚀 resources: - - **Wiki** – https://github.com/ultralytics/yolov3/wiki - - **Tutorials** – https://github.com/ultralytics/yolov3#tutorials + Access additional [YOLOv3](https://ultralytics.com/yolov5) 🚀 resources: + - **Wiki** – https://github.com/ultralytics/yolov5/wiki + - **Tutorials** – https://github.com/ultralytics/yolov5#tutorials - **Docs** – https://docs.ultralytics.com Access additional [Ultralytics](https://ultralytics.com) ⚡ resources: @@ -32,7 +32,9 @@ jobs: Thank you for your contributions to YOLOv3 🚀 and Vision AI ⭐! stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions YOLOv3 🚀 and Vision AI ⭐.' - days-before-stale: 30 - days-before-close: 5 - exempt-issue-labels: 'documentation,tutorial' - operations-per-run: 100 # The maximum number of operations per run, used to control rate limiting. + days-before-issue-stale: 30 + days-before-issue-close: 10 + days-before-pr-stale: 90 + days-before-pr-close: 30 + exempt-issue-labels: 'documentation,tutorial,TODO' + operations-per-run: 300 # The maximum number of operations per run, used to control rate limiting. diff --git a/.github/workflows/translate-readme.yml b/.github/workflows/translate-readme.yml new file mode 100644 index 0000000000..0efe298dcc --- /dev/null +++ b/.github/workflows/translate-readme.yml @@ -0,0 +1,26 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# README translation action to translate README.md to Chinese as README.zh-CN.md on any change to README.md + +name: Translate README + +on: + push: + branches: + - translate_readme # replace with 'master' to enable action + paths: + - README.md + +jobs: + Translate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 16 + # ISO Language Codes: https://cloud.google.com/translate/docs/languages + - name: Adding README - Chinese Simplified + uses: dephraiim/translate-readme@main + with: + LANG: zh-CN diff --git a/.gitignore b/.gitignore index 5f8cab5500..6bcedfac61 100755 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,11 @@ storage.googleapis.com runs/* data/* -!data/hyps/* +data/images/* +!data/*.yaml +!data/hyps +!data/scripts +!data/images !data/images/zidane.jpg !data/images/bus.jpg !data/*.sh @@ -48,12 +52,15 @@ VOC/ *.pt *.pb *.onnx +*.engine *.mlmodel *.torchscript *.tflite *.h5 *_saved_model/ *_web_model/ +*_openvino_model/ +*_paddle_model/ darknet53.conv.74 yolov3-tiny.conv.15 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0f9f939514..b188048e63 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,18 +4,19 @@ default_language_version: python: python3.8 +exclude: 'docs/' # Define bot property if installed via https://github.com/marketplace/pre-commit-ci ci: autofix_prs: true autoupdate_commit_msg: '[pre-commit.ci] pre-commit suggestions' - autoupdate_schedule: quarterly + autoupdate_schedule: monthly # submodules: true repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.4.0 hooks: - - id: end-of-file-fixer + # - id: end-of-file-fixer - id: trailing-whitespace - id: check-case-conflict - id: check-yaml @@ -24,43 +25,48 @@ repos: - id: check-docstring-first - repo: https://github.com/asottile/pyupgrade - rev: v2.34.0 + rev: v3.3.1 hooks: - id: pyupgrade - args: [--py36-plus] name: Upgrade code + args: [--py37-plus] - - repo: https://github.com/PyCQA/isort - rev: 5.10.1 + # - repo: https://github.com/PyCQA/isort + # rev: 5.11.4 + # hooks: + # - id: isort + # name: Sort imports + + - repo: https://github.com/google/yapf + rev: v0.32.0 hooks: - - id: isort - name: Sort imports + - id: yapf + name: YAPF formatting - # TODO - #- repo: https://github.com/pre-commit/mirrors-yapf - # rev: v0.31.0 - # hooks: - # - id: yapf - # name: formatting + - repo: https://github.com/executablebooks/mdformat + rev: 0.7.16 + hooks: + - id: mdformat + name: MD formatting + additional_dependencies: + - mdformat-gfm + - mdformat-black + # exclude: "README.md|README.zh-CN.md|CONTRIBUTING.md" - # TODO - #- repo: https://github.com/executablebooks/mdformat - # rev: 0.7.7 + - repo: https://github.com/PyCQA/flake8 + rev: 6.0.0 + hooks: + - id: flake8 + name: PEP8 + + #- repo: https://github.com/codespell-project/codespell + # rev: v2.2.2 # hooks: - # - id: mdformat - # additional_dependencies: - # - mdformat-gfm - # - mdformat-black - # - mdformat_frontmatter + # - id: codespell + # args: + # - --ignore-words-list=crate,nd - # TODO #- repo: https://github.com/asottile/yesqa - # rev: v1.2.3 + # rev: v1.4.0 # hooks: # - id: yesqa - - - repo: https://github.com/PyCQA/flake8 - rev: 4.0.1 - hooks: - - id: flake8 - name: PEP8 diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000000..41b1a33709 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,14 @@ +cff-version: 1.2.0 +preferred-citation: + type: software + message: If you use , please cite it as below. + authors: + - family-names: Jocher + given-names: Glenn + orcid: "https://orcid.org/0000-0001-5950-6979" + title: " by Ultralytics" + version: 7.0 + doi: 10.5281/zenodo.3908559 + date-released: 2020-5-29 + license: GPL-3.0 + url: "https://github.com/ultralytics/yolov5" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0ef52f638d..8e83398be6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ ## Contributing to YOLOv3 🚀 -We love your input! We want to make contributing to YOLOv3 as easy and transparent as possible, whether it's: +We love your input! We want to make contributing to as easy and transparent as possible, whether it's: - Reporting a bug - Discussing the current state of the code @@ -8,7 +8,7 @@ We love your input! We want to make contributing to YOLOv3 as easy and transpare - Proposing a new feature - Becoming a maintainer -YOLOv3 works so well due to our combined community effort, and for every small improvement you contribute you will be +works so well due to our combined community effort, and for every small improvement you contribute you will be helping push the frontiers of what's possible in AI 😃! ## Submitting a Pull Request (PR) 🛠️ @@ -18,73 +18,72 @@ Submitting a PR is easy! This example shows how to submit a PR for updating `req ### 1. Select File to Update Select `requirements.txt` to update by clicking on it in GitHub. +

PR_step1

### 2. Click 'Edit this file' -Button is in top-right corner. +The button is in the top-right corner. +

PR_step2

### 3. Make Changes -Change `matplotlib` version from `3.2.2` to `3.3`. +Change the `matplotlib` version from `3.2.2` to `3.3`. +

PR_step3

### 4. Preview Changes and Submit PR Click on the **Preview changes** tab to verify your updates. At the bottom of the screen select 'Create a **new branch** for this commit', assign your branch a descriptive name such as `fix/matplotlib_version` and click the green **Propose -changes** button. All done, your PR is now submitted to YOLOv3 for review and approval 😃! +changes** button. All done, your PR is now submitted to for review and approval 😃! +

PR_step4

### PR recommendations To allow your work to be integrated as seamlessly as possible, we advise you to: -- ✅ Verify your PR is **up-to-date with upstream/master.** If your PR is behind upstream/master an - automatic [GitHub actions](https://github.com/ultralytics/yolov3/blob/master/.github/workflows/rebase.yml) rebase may - be attempted by including the /rebase command in a comment body, or by running the following code, replacing 'feature' - with the name of your local branch: +- ✅ Verify your PR is **up-to-date** with `ultralytics/yolov5` `master` branch. If your PR is behind you can update + your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally. - ```bash - git remote add upstream https://github.com/ultralytics/yolov3.git - git fetch upstream - git checkout feature # <----- replace 'feature' with local branch name - git merge upstream/master - git push -u origin -f - ``` +

Screenshot 2022-08-29 at 22 47 15

- ✅ Verify all Continuous Integration (CI) **checks are passing**. + +

Screenshot 2022-08-29 at 22 47 03

+ - ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ — Bruce Lee ## Submitting a Bug Report 🐛 -If you spot a problem with YOLOv3 please submit a Bug Report! +If you spot a problem with please submit a Bug Report! For us to start investigating a possible problem we need to be able to reproduce it ourselves first. We've created a few -short guidelines below to help users provide what we need in order to get started. +short guidelines below to help users provide what we need to get started. When asking a question, people will be better able to provide help if you provide **code** that they can easily understand and use to **reproduce** the problem. This is referred to by community members as creating a [minimum reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). Your code that reproduces the problem should be: -* ✅ **Minimal** – Use as little code as possible that still produces the same problem -* ✅ **Complete** – Provide **all** parts someone else needs to reproduce your problem in the question itself -* ✅ **Reproducible** – Test the code you're about to provide to make sure it reproduces the problem +- ✅ **Minimal** – Use as little code as possible that still produces the same problem +- ✅ **Complete** – Provide **all** parts someone else needs to reproduce your problem in the question itself +- ✅ **Reproducible** – Test the code you're about to provide to make sure it reproduces the problem In addition to the above requirements, for [Ultralytics](https://ultralytics.com/) to provide assistance your code should be: -* ✅ **Current** – Verify that your code is up-to-date with current - GitHub [master](https://github.com/ultralytics/yolov3/tree/master), and if necessary `git pull` or `git clone` a new +- ✅ **Current** – Verify that your code is up-to-date with the current + GitHub [master](https://github.com/ultralytics/yolov5/tree/master), and if necessary `git pull` or `git clone` a new copy to ensure your problem has not already been resolved by previous commits. -* ✅ **Unmodified** – Your problem must be reproducible without any modifications to the codebase in this +- ✅ **Unmodified** – Your problem must be reproducible without any modifications to the codebase in this repository. [Ultralytics](https://ultralytics.com/) does not provide support for custom code ⚠️. -If you believe your problem meets all of the above criteria, please close this issue and raise a new one using the 🐛 ** -Bug Report** [template](https://github.com/ultralytics/yolov3/issues/new/choose) and providing +If you believe your problem meets all of the above criteria, please close this issue and raise a new one using the 🐛 +**Bug Report** [template](https://github.com/ultralytics/yolov5/issues/new/choose) and provide a [minimum reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) to help us better understand and diagnose your problem. diff --git a/README.md b/README.md index 68a34af8f5..b10c181477 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,30 @@
-

- - -

+

+ + +

+ +[English](README.md) | [简体中文](README.zh-CN.md)
+
- CI CPU testing - YOLOv3 Citation - Docker Pulls -
- Open In Colab - Open In Kaggle - Join Forum -
-
+  CI +  Citation + Docker Pulls +
+ Run on Gradient + Open In Colab + Open In Kaggle +
+
+ +🚀 is the world's most loved vision AI, representing Ultralytics open-source +research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours +of research and development. + +To request an Enterprise License please complete the form at Ultralytics +Licensing. +
@@ -36,56 +47,64 @@
- +
-

-YOLOv3 🚀 is a family of object detection architectures and models pretrained on the COCO dataset, and represents Ultralytics - open-source research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours of research and development. -

- +##
YOLOv8 🚀 NEW
+ +We are thrilled to announce the launch of Ultralytics YOLOv8 🚀, our NEW cutting-edge, state-of-the-art (SOTA) model +released at **[https://github.com/ultralytics/ultralytics](https://github.com/ultralytics/ultralytics)**. +YOLOv8 is designed to be fast, accurate, and easy to use, making it an excellent choice for a wide range of +object detection, image segmentation and image classification tasks. + +See the [YOLOv8 Docs](https://docs.ultralytics.com) for details and get started with: + +```commandline +pip install ultralytics +``` +
+ +
##
Documentation
-See the [YOLOv3 Docs](https://docs.ultralytics.com) for full documentation on training, testing and deployment. - -##
Quick Start Examples
+See the [ Docs](https://docs.ultralytics.com) for full documentation on training, testing and deployment. See below for +quickstart examples.
Install -[**Python>=3.6.0**](https://www.python.org/) is required with all -[requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) installed including -[**PyTorch>=1.7**](https://pytorch.org/get-started/locally/): - +Clone repo and install [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) in a +[**Python>=3.7.0**](https://www.python.org/) environment, including +[**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). ```bash -$ git clone https://github.com/ultralytics/yolov3 -$ cd yolov3 -$ pip install -r requirements.txt +git clone https://github.com/ultralytics/yolov3 # clone +cd yolov3 +pip install -r requirements.txt # install ```
-
+
Inference -Inference with YOLOv3 and [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36). Models automatically download -from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases). +[PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36) +inference. [Models](https://github.com/ultralytics/yolov5/tree/master/models) download automatically from the latest +[release](https://github.com/ultralytics/yolov5/releases). ```python import torch # Model -model = torch.hub.load('ultralytics/yolov3', 'yolov3') # or yolov3-spp, yolov3-tiny, custom +model = torch.hub.load( + "ultralytics/yolov3", "yolov3" +) # or yolov3-spp, yolov3-tiny, custom # Images -img = 'https://ultralytics.com/images/zidane.jpg' # or file, Path, PIL, OpenCV, numpy, list +img = "https://ultralytics.com/images/zidane.jpg" # or file, Path, PIL, OpenCV, numpy, list # Inference results = model(img) @@ -96,22 +115,24 @@ results.print() # or .show(), .save(), .crop(), .pandas(), etc.
- -
Inference with detect.py -`detect.py` runs inference on a variety of sources, downloading models automatically from -the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases) and saving results to `runs/detect`. +`detect.py` runs inference on a variety of sources, +downloading [models](https://github.com/ultralytics/yolov5/tree/master/models) automatically from +the latest [release](https://github.com/ultralytics/yolov5/releases) and saving results to `runs/detect`. ```bash -$ python detect.py --source 0 # webcam - img.jpg # image - vid.mp4 # video - path/ # directory - path/*.jpg # glob - 'https://youtu.be/Zgi9g1ksQHc' # YouTube - 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream +python detect.py --weights yolov5s.pt --source 0 # webcam + img.jpg # image + vid.mp4 # video + screen # screenshot + path/ # directory + list.txt # list of images + list.streams # list of streams + 'path/*.jpg' # glob + 'https://youtu.be/Zgi9g1ksQHc' # YouTube + 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream ```
@@ -119,6 +140,22 @@ $ python detect.py --source 0 # webcam
Training +The commands below reproduce [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) +results. [Models](https://github.com/ultralytics/yolov5/tree/master/models) +and [datasets](https://github.com/ultralytics/yolov5/tree/master/data) download automatically from the latest +[release](https://github.com/ultralytics/yolov5/releases). Training times for YOLOv5n/s/m/l/x are +1/2/4/6/8 days on a V100 GPU ([Multi-GPU](https://github.com/ultralytics/yolov5/issues/475) times faster). Use the +largest `--batch-size` possible, or pass `--batch-size -1` for +[AutoBatch](https://github.com/ultralytics/yolov5/pull/5092). Batch sizes shown for V100-16GB. + +```bash +python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml --batch-size 128 + yolov5s 64 + yolov5m 40 + yolov5l 24 + yolov5x 16 +``` +
@@ -126,8 +163,8 @@ $ python detect.py --source 0 # webcam
Tutorials -- [Train Custom Data](https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data)  🚀 RECOMMENDED -- [Tips for Best Training Results](https://github.com/ultralytics/yolov5/wiki/Tips-for-Best-Training-Results)  ☘️ +- [Train Custom Data](https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data)🚀 RECOMMENDED +- [Tips for Best Training Results](https://github.com/ultralytics/yolov5/wiki/Tips-for-Best-Training-Results)☘️ RECOMMENDED - [Multi-GPU Training](https://github.com/ultralytics/yolov5/issues/475) - [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36) 🌟 NEW @@ -139,9 +176,9 @@ $ python detect.py --source 0 # webcam - [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607) - [Transfer Learning with Frozen Layers](https://github.com/ultralytics/yolov5/issues/1314) - [Architecture Summary](https://github.com/ultralytics/yolov5/issues/6998) 🌟 NEW -- [Roboflow for Datasets, Labeling, and Active Learning](https://github.com/ultralytics/yolov5/issues/4975)  🌟 NEW +- [Roboflow for Datasets, Labeling, and Active Learning](https://github.com/ultralytics/yolov5/issues/4975)🌟 NEW - [ClearML Logging](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml) 🌟 NEW -- [YOLOv5 with Neural Magic's Deepsparse](https://bit.ly/yolov5-neuralmagic) 🌟 NEW +- [ with Neural Magic's Deepsparse](https://bit.ly/yolov5-neuralmagic) 🌟 NEW - [Comet Logging](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/comet) 🌟 NEW
@@ -156,32 +193,33 @@ $ python detect.py --source 0 # webcam -| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | -| :--------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | -| Label and export your custom datasets directly to YOLOv5 for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | Automatically track, visualize and even remotely train YOLOv5 using [ClearML](https://cutt.ly/yolov5-readme-clearml) (open-source!) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet2) lets you save YOLOv5 models, resume training, and interactively visualise and debug predictions | Run YOLOv5 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | +| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | +| :--------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------: | +| Label and export your custom datasets directly to for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | Automatically track, visualize and even remotely train using [ClearML](https://cutt.ly/yolov5-readme-clearml) (open-source!) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet2) lets you save models, resume training, and interactively visualise and debug predictions | Run inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | ##
Ultralytics HUB
-[Ultralytics HUB](https://bit.ly/ultralytics_hub) is our ⭐ **NEW** no-code solution to visualize datasets, train YOLOv5 🚀 models, and deploy to the real world in a seamless experience. Get started for **Free** now! +[Ultralytics HUB](https://bit.ly/ultralytics_hub) is our ⭐ **NEW** no-code solution to visualize datasets, train 🚀 +models, and deploy to the real world in a seamless experience. Get started for **Free** now! -##
Why YOLOv5
+##
Why YOLO
-YOLOv5 has been designed to be super easy to get started and simple to learn. We prioritize real-world results. +has been designed to be super easy to get started and simple to learn. We prioritize real-world results.

@@ -192,10 +230,13 @@ YOLOv5 has been designed to be super easy to get started and simple to learn. We
Figure Notes -- **COCO AP val** denotes mAP@0.5:0.95 metric measured on the 5000-image [COCO val2017](http://cocodataset.org) dataset over various inference sizes from 256 to 1536. -- **GPU Speed** measures average inference time per image on [COCO val2017](http://cocodataset.org) dataset using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) V100 instance at batch-size 32. +- **COCO AP val** denotes mAP@0.5:0.95 metric measured on the 5000-image [COCO val2017](http://cocodataset.org) dataset + over various inference sizes from 256 to 1536. +- **GPU Speed** measures average inference time per image on [COCO val2017](http://cocodataset.org) dataset using + a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) V100 instance at batch-size 32. - **EfficientDet** data from [google/automl](https://github.com/google/automl) at batch size 8. -- **Reproduce** by `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt` +- **Reproduce** + by `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt`
@@ -218,16 +259,28 @@ YOLOv5 has been designed to be super easy to get started and simple to learn. We
Table Notes -- All checkpoints are trained to 300 epochs with default settings. Nano and Small models use [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) hyps, all others use [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml). -- **mAPval** values are for single-model single-scale on [COCO val2017](http://cocodataset.org) dataset.
Reproduce by `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` -- **Speed** averaged over COCO val images using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) instance. NMS times (~1 ms/img) not included.
Reproduce by `python val.py --data coco.yaml --img 640 --task speed --batch 1` -- **TTA** [Test Time Augmentation](https://github.com/ultralytics/yolov5/issues/303) includes reflection and scale augmentations.
Reproduce by `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment` +- All checkpoints are trained to 300 epochs with default settings. Nano and Small models + use [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) hyps, all + others use [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml). +- **mAPval** values are for single-model single-scale on [COCO val2017](http://cocodataset.org) dataset.
+ Reproduce by `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` +- **Speed** averaged over COCO val images using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) + instance. NMS times (~1 ms/img) not included.
Reproduce + by `python val.py --data coco.yaml --img 640 --task speed --batch 1` +- **TTA** [Test Time Augmentation](https://github.com/ultralytics/yolov5/issues/303) includes reflection and scale + augmentations.
Reproduce by `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment`
##
Segmentation
-Our new YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7.0) instance segmentation models are the fastest and most accurate in the world, beating all current [SOTA benchmarks](https://paperswithcode.com/sota/real-time-instance-segmentation-on-mscoco). We've made them super simple to train, validate and deploy. See full details in our [Release Notes](https://github.com/ultralytics/yolov5/releases/v7.0) and visit our [YOLOv5 Segmentation Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/segment/tutorial.ipynb) for quickstart tutorials. +Our new YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7.0) instance segmentation models are the +fastest and most accurate in the world, beating all +current [SOTA benchmarks](https://paperswithcode.com/sota/real-time-instance-segmentation-on-mscoco). We've made them +super simple to train, validate and deploy. See full details in +our [Release Notes](https://github.com/ultralytics/yolov5/releases/v7.0) and visit +our [YOLOv5 Segmentation Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/segment/tutorial.ipynb) for +quickstart tutorials.
Segmentation Checkpoints @@ -237,7 +290,9 @@ Our new YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7. -We trained YOLOv5 segmentations models on COCO for 300 epochs at image size 640 using A100 GPUs. We exported all models to ONNX FP32 for CPU speed tests and to TensorRT FP16 for GPU speed tests. We ran all speed tests on Google [Colab Pro](https://colab.research.google.com/signup) notebooks for easy reproducibility. +We trained YOLOv5 segmentations models on COCO for 300 epochs at image size 640 using A100 GPUs. We exported all models +to ONNX FP32 for CPU speed tests and to TensorRT FP16 for GPU speed tests. We ran all speed tests on +Google [Colab Pro](https://colab.research.google.com/signup) notebooks for easy reproducibility. | Model | size
(pixels) | mAPbox
50-95 | mAPmask
50-95 | Train time
300 epochs
A100 (hours) | Speed
ONNX CPU
(ms) | Speed
TRT A100
(ms) | params
(M) | FLOPs
@640 (B) | | ------------------------------------------------------------------------------------------ | --------------------- | -------------------- | --------------------- | --------------------------------------------- | ------------------------------ | ------------------------------ | ------------------ | ---------------------- | @@ -247,10 +302,15 @@ We trained YOLOv5 segmentations models on COCO for 300 epochs at image size 640 | [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | | [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | -- All checkpoints are trained to 300 epochs with SGD optimizer with `lr0=0.01` and `weight_decay=5e-5` at image size 640 and all default settings.
Runs logged to https://wandb.ai/glenn-jocher/YOLOv5_v70_official -- **Accuracy** values are for single-model single-scale on COCO dataset.
Reproduce by `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt` -- **Speed** averaged over 100 inference images using a [Colab Pro](https://colab.research.google.com/signup) A100 High-RAM instance. Values indicate inference speed only (NMS adds about 1ms per image).
Reproduce by `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt --batch 1` -- **Export** to ONNX at FP32 and TensorRT at FP16 done with `export.py`.
Reproduce by `python export.py --weights yolov5s-seg.pt --include engine --device 0 --half` +- All checkpoints are trained to 300 epochs with SGD optimizer with `lr0=0.01` and `weight_decay=5e-5` at image size 640 + and all default settings.
Runs logged to https://wandb.ai/glenn-jocher/YOLOv5_v70_official +- **Accuracy** values are for single-model single-scale on COCO dataset.
Reproduce + by `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt` +- **Speed** averaged over 100 inference images using a [Colab Pro](https://colab.research.google.com/signup) A100 + High-RAM instance. Values indicate inference speed only (NMS adds about 1ms per image).
Reproduce + by `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt --batch 1` +- **Export** to ONNX at FP32 and TensorRT at FP16 done with `export.py`.
Reproduce + by `python export.py --weights yolov5s-seg.pt --include engine --device 0 --half`
@@ -259,7 +319,9 @@ We trained YOLOv5 segmentations models on COCO for 300 epochs at image size 640 ### Train -YOLOv5 segmentation training supports auto-download COCO128-seg segmentation dataset with `--data coco128-seg.yaml` argument and manual download of COCO-segments dataset with `bash data/scripts/get_coco.sh --train --val --segments` and then `python train.py --data coco.yaml`. +YOLOv5 segmentation training supports auto-download COCO128-seg segmentation dataset with `--data coco128-seg.yaml` +argument and manual download of COCO-segments dataset with `bash data/scripts/get_coco.sh --train --val --segments` and +then `python train.py --data coco.yaml`. ```bash # Single-GPU @@ -307,14 +369,21 @@ python export.py --weights yolov5s-seg.pt --include onnx engine --img 640 --devi ##
Classification
-YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) brings support for classification model training, validation and deployment! See full details in our [Release Notes](https://github.com/ultralytics/yolov5/releases/v6.2) and visit our [YOLOv5 Classification Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/classify/tutorial.ipynb) for quickstart tutorials. +YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) brings support for classification model training, +validation and deployment! See full details in our [Release Notes](https://github.com/ultralytics/yolov5/releases/v6.2) +and visit +our [YOLOv5 Classification Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/classify/tutorial.ipynb) +for quickstart tutorials.
Classification Checkpoints
-We trained YOLOv5-cls classification models on ImageNet for 90 epochs using a 4xA100 instance, and we trained ResNet and EfficientNet models alongside with the same default training settings to compare. We exported all models to ONNX FP32 for CPU speed tests and to TensorRT FP16 for GPU speed tests. We ran all speed tests on Google [Colab Pro](https://colab.research.google.com/signup) for easy reproducibility. +We trained YOLOv5-cls classification models on ImageNet for 90 epochs using a 4xA100 instance, and we trained ResNet and +EfficientNet models alongside with the same default training settings to compare. We exported all models to ONNX FP32 +for CPU speed tests and to TensorRT FP16 for GPU speed tests. We ran all speed tests on +Google [Colab Pro](https://colab.research.google.com/signup) for easy reproducibility. | Model | size
(pixels) | acc
top1 | acc
top5 | Training
90 epochs
4xA100 (hours) | Speed
ONNX CPU
(ms) | Speed
TensorRT V100
(ms) | params
(M) | FLOPs
@224 (B) | | -------------------------------------------------------------------------------------------------- | --------------------- | ---------------- | ---------------- | -------------------------------------------- | ------------------------------ | ----------------------------------- | ------------------ | ---------------------- | @@ -337,10 +406,14 @@ We trained YOLOv5-cls classification models on ImageNet for 90 epochs using a 4x
Table Notes (click to expand) -- All checkpoints are trained to 90 epochs with SGD optimizer with `lr0=0.001` and `weight_decay=5e-5` at image size 224 and all default settings.
Runs logged to https://wandb.ai/glenn-jocher/YOLOv5-Classifier-v6-2 -- **Accuracy** values are for single-model single-scale on [ImageNet-1k](https://www.image-net.org/index.php) dataset.
Reproduce by `python classify/val.py --data ../datasets/imagenet --img 224` -- **Speed** averaged over 100 inference images using a Google [Colab Pro](https://colab.research.google.com/signup) V100 High-RAM instance.
Reproduce by `python classify/val.py --data ../datasets/imagenet --img 224 --batch 1` -- **Export** to ONNX at FP32 and TensorRT at FP16 done with `export.py`.
Reproduce by `python export.py --weights yolov5s-cls.pt --include engine onnx --imgsz 224` +- All checkpoints are trained to 90 epochs with SGD optimizer with `lr0=0.001` and `weight_decay=5e-5` at image size 224 + and all default settings.
Runs logged to https://wandb.ai/glenn-jocher/YOLOv5-Classifier-v6-2 +- **Accuracy** values are for single-model single-scale on [ImageNet-1k](https://www.image-net.org/index.php) + dataset.
Reproduce by `python classify/val.py --data ../datasets/imagenet --img 224` +- **Speed** averaged over 100 inference images using a Google [Colab Pro](https://colab.research.google.com/signup) V100 + High-RAM instance.
Reproduce by `python classify/val.py --data ../datasets/imagenet --img 224 --batch 1` +- **Export** to ONNX at FP32 and TensorRT at FP16 done with `export.py`.
Reproduce + by `python export.py --weights yolov5s-cls.pt --include engine onnx --imgsz 224`
@@ -350,7 +423,8 @@ We trained YOLOv5-cls classification models on ImageNet for 90 epochs using a 4x ### Train -YOLOv5 classification training supports auto-download of MNIST, Fashion-MNIST, CIFAR10, CIFAR100, Imagenette, Imagewoof, and ImageNet datasets with the `--data` argument. To start training on MNIST for example use `--data mnist`. +YOLOv5 classification training supports auto-download of MNIST, Fashion-MNIST, CIFAR10, CIFAR100, Imagenette, Imagewoof, +and ImageNet datasets with the `--data` argument. To start training on MNIST for example use `--data mnist`. ```bash # Single-GPU @@ -407,7 +481,7 @@ Get started in seconds with our verified environments. Click each icon below for - + @@ -419,22 +493,29 @@ Get started in seconds with our verified environments. Click each icon below for ##
Contribute
-We love your input! We want to make contributing to YOLOv5 as easy and transparent as possible. Please see our [Contributing Guide](CONTRIBUTING.md) to get started, and fill out the [YOLOv5 Survey](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to send us feedback on your experiences. Thank you to all our contributors! +We love your input! We want to make contributing to as easy and transparent as possible. Please see +our [Contributing Guide](CONTRIBUTING.md) to get started, and fill out +the [ Survey](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to send us +feedback on your experiences. Thank you to all our contributors! -
+ + ##
License
-YOLOv5 is available under two different licenses: +is available under two different licenses: - **GPL-3.0 License**: See [LICENSE](https://github.com/ultralytics/yolov5/blob/master/LICENSE) file for details. -- **Enterprise License**: Provides greater flexibility for commercial product development without the open-source requirements of GPL-3.0. Typical use cases are embedding Ultralytics software and AI models in commercial products and applications. Request an Enterprise License at [Ultralytics Licensing](https://ultralytics.com/license). +- **Enterprise License**: Provides greater flexibility for commercial product development without the open-source + requirements of GPL-3.0. Typical use cases are embedding Ultralytics software and AI models in commercial products and + applications. Request an Enterprise License at [Ultralytics Licensing](https://ultralytics.com/license). ##
Contact
-For YOLOv5 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov5/issues) or the [Ultralytics Community Forum](https://community.ultralytics.com/). +For bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov5/issues) or +the [Ultralytics Community Forum](https://community.ultralytics.com/).
@@ -461,4 +542,3 @@ For YOLOv5 bug reports and feature requests please visit [GitHub Issues](https:/
[tta]: https://github.com/ultralytics/yolov5/issues/303 - diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 0000000000..f5f91241fe --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,532 @@ +
+

+ + +

+ +[英文](README.md)|[简体中文](README.zh-CN.md)
+ +
+  CI +  Citation + Docker Pulls +
+ Run on Gradient + Open In Colab + Open In Kaggle +
+
+ +🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics 对未来视觉 AI +方法的开源研究,结合在数千小时的研究和开发中积累的经验教训和最佳实践。 + +如果要申请企业许可证,请填写表格Ultralytics 许可. + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ +##
YOLOv8 🚀 NEW
+ +We are thrilled to announce the launch of Ultralytics YOLOv8 🚀, our NEW cutting-edge, state-of-the-art (SOTA) model +released at **[https://github.com/ultralytics/ultralytics](https://github.com/ultralytics/ultralytics)**. +YOLOv8 is designed to be fast, accurate, and easy to use, making it an excellent choice for a wide range of +object detection, image segmentation and image classification tasks. + +See the [YOLOv8 Docs](https://docs.ultralytics.com) for details and get started with: + +```commandline +pip install ultralytics +``` + +
+ + +
+ +##
文档
+ +有关训练、测试和部署的完整文档见[YOLOv5 文档](https://docs.ultralytics.com)。请参阅下面的快速入门示例。 + +
+安装 + +克隆 repo,并要求在 [**Python>=3.7.0**](https://www.python.org/) +环境中安装 [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) ,且要求 [**PyTorch> +=1.7**](https://pytorch.org/get-started/locally/) 。 + +```bash +git clone https://github.com/ultralytics/yolov3 # clone +cd yolov3 +pip install -r requirements.txt # install +``` + +
+ +
+推理 + +使用 YOLOv5 [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36) +推理。最新 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 将自动的从 +YOLOv5 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 + +```python +import torch + +# Model +model = torch.hub.load( + "ultralytics/yolov3", "yolov3" +) # or yolov3-spp, yolov3-tiny, custom + +# Images +img = "https://ultralytics.com/images/zidane.jpg" # or file, Path, PIL, OpenCV, numpy, list + +# Inference +results = model(img) + +# Results +results.print() # or .show(), .save(), .crop(), .pandas(), etc. +``` + +
+ +
+使用 detect.py 推理 + +`detect.py` 在各种来源上运行推理, [模型](https://github.com/ultralytics/yolov5/tree/master/models) 自动从 +最新的YOLOv5 [release](https://github.com/ultralytics/yolov5/releases) 中下载,并将结果保存到 `runs/detect` 。 + +```bash +python detect.py --weights yolov5s.pt --source 0 # webcam + img.jpg # image + vid.mp4 # video + screen # screenshot + path/ # directory + list.txt # list of images + list.streams # list of streams + 'path/*.jpg' # glob + 'https://youtu.be/Zgi9g1ksQHc' # YouTube + 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream +``` + +
+ +
+训练 + +下面的命令重现 YOLOv5 在 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) 数据集上的结果。 +最新的 [模型](https://github.com/ultralytics/yolov5/tree/master/models) +和 [数据集](https://github.com/ultralytics/yolov5/tree/master/data) +将自动的从 YOLOv5 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 +YOLOv5n/s/m/l/x 在 V100 GPU 的训练时间为 1/2/4/6/8 天( [多GPU](https://github.com/ultralytics/yolov5/issues/475) +训练速度更快)。 +尽可能使用更大的 `--batch-size` ,或通过 `--batch-size -1` 实现 +YOLOv5 [自动批处理](https://github.com/ultralytics/yolov5/pull/5092) 。下方显示的 batchsize 适用于 V100-16GB。 + +```bash +python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml --batch-size 128 + yolov5s 64 + yolov5m 40 + yolov5l 24 + yolov5x 16 +``` + + + +
+ +
+教程 + +- [训练自定义数据](https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data)🚀 推荐 +- [获得最佳训练结果的技巧](https://github.com/ultralytics/yolov5/wiki/Tips-for-Best-Training-Results)☘️ 推荐 +- [多 GPU 训练](https://github.com/ultralytics/yolov5/issues/475) +- [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36)🌟 新 +- [TFLite、ONNX、CoreML、TensorRT 导出](https://github.com/ultralytics/yolov5/issues/251)🚀 +- [NVIDIA Jetson Nano 部署](https://github.com/ultralytics/yolov5/issues/9627)🌟 新 +- [测试时数据增强 (TTA)](https://github.com/ultralytics/yolov5/issues/303) +- [模型集成](https://github.com/ultralytics/yolov5/issues/318) +- [模型修剪/稀疏度](https://github.com/ultralytics/yolov5/issues/304) +- [超参数进化](https://github.com/ultralytics/yolov5/issues/607) +- [使用冻结层进行迁移学习](https://github.com/ultralytics/yolov5/issues/1314) +- [架构总结](https://github.com/ultralytics/yolov5/issues/6998)🌟 新 +- [用于数据集、标签和主动学习的 Roboflow](https://github.com/ultralytics/yolov5/issues/4975)🌟 新 +- [ClearML 记录](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml)🌟 新 +- [Deci 平台](https://github.com/ultralytics/yolov5/wiki/Deci-Platform)🌟 新 +- [Comet Logging](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/comet)🌟 新 + +
+ +##
模块集成
+ +
+ + +
+
+ +
+ + + + + + + + + + + +
+ +| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | +| :--------------------------------------------------------------------------------: | :-------------------------------------------------------------------------: | :-------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | +| 将您的自定义数据集进行标注并直接导出到 YOLOv5 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv5 [ClearML](https://cutt.ly/yolov5-readme-clearml)(开源!) | 永远免费,[Comet](https://bit.ly/yolov5-readme-comet)可让您保存 YOLOv5 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv5 推理的速度最高可提高6倍 | + +##
Ultralytics HUB
+ +[Ultralytics HUB](https://bit.ly/ultralytics_hub) 是我们的⭐**新的**用于可视化数据集、训练 YOLOv5 🚀 +模型并以无缝体验部署到现实世界的无代码解决方案。现在开始 **免费** 使用他! + + + + +##
为什么选择 YOLOv5
+ +YOLOv5 超级容易上手,简单易学。我们优先考虑现实世界的结果。 + +

+
+ YOLOv5-P5 640 图 + +

+
+
+ 图表笔记 + +- **COCO AP val** 表示 mAP@0.5:0.95 指标,在 [COCO val2017](http://cocodataset.org) 数据集的 5000 张图像上测得, 图像包含 + 256 到 1536 各种推理大小。 +- **显卡推理速度** 为在 [COCO val2017](http://cocodataset.org) + 数据集上的平均推理时间,使用 [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) V100实例,batchsize 为 32 。 +- **EfficientDet** 数据来自 [google/automl](https://github.com/google/automl) , batchsize 为32。 +- **复现命令** + 为 `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt` + +
+ +### 预训练模型 + +| 模型 | 尺寸
(像素) | mAPval
50-95 | mAPval
50 | 推理速度
CPU b1
(ms) | 推理速度
V100 b1
(ms) | 速度
V100 b32
(ms) | 参数量
(M) | FLOPs
@640 (B) | +| ---------------------------------------------------------------------------------------------- | --------------- | -------------------- | ----------------- | --------------------------- | ---------------------------- | --------------------------- | --------------- | ---------------------- | +| [YOLOv5n](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n.pt) | 640 | 28.0 | 45.7 | **45** | **6.3** | **0.6** | **1.9** | **4.5** | +| [YOLOv5s](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt) | 640 | 37.4 | 56.8 | 98 | 6.4 | 0.9 | 7.2 | 16.5 | +| [YOLOv5m](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m.pt) | 640 | 45.4 | 64.1 | 224 | 8.2 | 1.7 | 21.2 | 49.0 | +| [YOLOv5l](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l.pt) | 640 | 49.0 | 67.3 | 430 | 10.1 | 2.7 | 46.5 | 109.1 | +| [YOLOv5x](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x.pt) | 640 | 50.7 | 68.9 | 766 | 12.1 | 4.8 | 86.7 | 205.7 | +| | | | | | | | | | +| [YOLOv5n6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n6.pt) | 1280 | 36.0 | 54.4 | 153 | 8.1 | 2.1 | 3.2 | 4.6 | +| [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | +| [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | +| [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | +| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+[TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- | + +
+ 笔记 + +- 所有模型都使用默认配置,训练 300 + epochs。n和s模型使用 [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) + ,其他模型都使用 [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml) 。 +- \*\*mAPval\*\*在单模型单尺度上计算,数据集使用 [COCO val2017](http://cocodataset.org) 。
+ 复现命令 `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` +- **推理速度**在 COCO val + 图像总体时间上进行平均得到,测试环境使用[AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/)实例。 NMS 时间 ( + 大约 1 ms/img) 不包括在内。
复现命令 `python val.py --data coco.yaml --img 640 --task speed --batch 1` +- **TTA** [测试时数据增强](https://github.com/ultralytics/yolov5/issues/303) 包括反射和尺度变换。
+ 复现命令 `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment` + +
+ +##
实例分割模型 ⭐ 新
+ +我们新的 YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7.0) +实例分割模型是世界上最快和最准确的模型,击败所有当前 [SOTA 基准](https://paperswithcode.com/sota/real-time-instance-segmentation-on-mscoco) +。我们使它非常易于训练、验证和部署。更多细节请查看 [发行说明](https://github.com/ultralytics/yolov5/releases/v7.0) +或访问我们的 [YOLOv5 分割 Colab 笔记本](https://github.com/ultralytics/yolov5/blob/master/segment/tutorial.ipynb) 以快速入门。 + +
+ 实例分割模型列表 + +
+ +
+ + +
+ +我们使用 A100 GPU 在 COCO 上以 640 图像大小训练了 300 epochs 得到 YOLOv5 分割模型。我们将所有模型导出到 ONNX FP32 以进行 +CPU 速度测试,并导出到 TensorRT FP16 以进行 GPU 速度测试。为了便于再现,我们在 +Google [Colab Pro](https://colab.research.google.com/signup) 上进行了所有速度测试。 + +| 模型 | 尺寸
(像素) | mAPbox
50-95 | mAPmask
50-95 | 训练时长
300 epochs
A100 GPU(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TRT A100
(ms) | 参数量
(M) | FLOPs
@640 (B) | +| ------------------------------------------------------------------------------------------ | --------------- | -------------------- | --------------------- | --------------------------------------- | ----------------------------- | ----------------------------- | --------------- | ---------------------- | +| [YOLOv5n-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-seg.pt) | 640 | 27.6 | 23.4 | 80:17 | **62.7** | **1.2** | **2.0** | **7.1** | +| [YOLOv5s-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt) | 640 | 37.6 | 31.7 | 88:16 | 173.3 | 1.4 | 7.6 | 26.4 | +| [YOLOv5m-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-seg.pt) | 640 | 45.0 | 37.1 | 108:36 | 427.0 | 2.2 | 22.0 | 70.8 | +| [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | +| [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | + +- 所有模型使用 SGD 优化器训练, 都使用 `lr0=0.01` 和 `weight_decay=5e-5` 参数, 图像大小为 640 。
训练 log + 可以查看 https://wandb.ai/glenn-jocher/YOLOv5_v70_official +- **准确性**结果都在 COCO 数据集上,使用单模型单尺度测试得到。
+ 复现命令 `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt` +- **推理速度**是使用 100 张图像推理时间进行平均得到,测试环境使用 [Colab Pro](https://colab.research.google.com/signup) 上 + A100 高 RAM 实例。结果仅表示推理速度(NMS 每张图像增加约 1 毫秒)。
+ 复现命令 `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt --batch 1` +- **模型转换**到 FP32 的 ONNX 和 FP16 的 TensorRT 脚本为 `export.py`.
+ 运行命令 `python export.py --weights yolov5s-seg.pt --include engine --device 0 --half` + +
+ +
+ 分割模型使用示例  Open In Colab + +### 训练 + +YOLOv5分割训练支持自动下载 COCO128-seg 分割数据集,用户仅需在启动指令中包含 `--data coco128-seg.yaml` 参数。 +若要手动下载,使用命令 `bash data/scripts/get_coco.sh --train --val --segments`, +在下载完毕后,使用命令 `python train.py --data coco.yaml` 开启训练。 + +```bash +# 单 GPU +python segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 + +# 多 GPU, DDP 模式 +python -m torch.distributed.run --nproc_per_node 4 --master_port 1 segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 --device 0,1,2,3 +``` + +### 验证 + +在 COCO 数据集上验证 YOLOv5s-seg mask mAP: + +```bash +bash data/scripts/get_coco.sh --val --segments # 下载 COCO val segments 数据集 (780MB, 5000 images) +python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 # 验证 +``` + +### 预测 + +使用预训练的 YOLOv5m-seg.pt 来预测 bus.jpg: + +```bash +python segment/predict.py --weights yolov5m-seg.pt --data data/images/bus.jpg +``` + +```python +model = torch.hub.load( + "ultralytics/yolov5", "custom", "yolov5m-seg.pt" +) # 从load from PyTorch Hub 加载模型 (WARNING: 推理暂未支持) +``` + +| ![zidane](https://user-images.githubusercontent.com/26833433/203113421-decef4c4-183d-4a0a-a6c2-6435b33bc5d3.jpg) | ![bus](https://user-images.githubusercontent.com/26833433/203113416-11fe0025-69f7-4874-a0a6-65d0bfe2999a.jpg) | +| ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | + +### 模型导出 + +将 YOLOv5s-seg 模型导出到 ONNX 和 TensorRT: + +```bash +python export.py --weights yolov5s-seg.pt --include onnx engine --img 640 --device 0 +``` + +
+ +##
分类网络 ⭐ 新
+ +YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) +带来对分类模型训练、验证和部署的支持!详情请查看 [发行说明](https://github.com/ultralytics/yolov5/releases/v6.2) +或访问我们的 [YOLOv5 分类 Colab 笔记本](https://github.com/ultralytics/yolov5/blob/master/classify/tutorial.ipynb) +以快速入门。 + +
+ 分类网络模型 + +
+ +我们使用 4xA100 实例在 ImageNet 上训练了 90 个 epochs 得到 YOLOv5-cls 分类模型,我们训练了 ResNet 和 EfficientNet +模型以及相同的默认训练设置以进行比较。我们将所有模型导出到 ONNX FP32 以进行 CPU 速度测试,并导出到 TensorRT FP16 以进行 +GPU 速度测试。为了便于重现,我们在 Google 上进行了所有速度测试 [Colab Pro](https://colab.research.google.com/signup) 。 + +| 模型 | 尺寸
(像素) | acc
top1 | acc
top5 | 训练时长
90 epochs
4xA100(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TensorRT V100
(ms) | 参数
(M) | FLOPs
@640 (B) | +| -------------------------------------------------------------------------------------------------- | --------------- | ---------------- | ---------------- | ------------------------------------ | ----------------------------- | ---------------------------------- | -------------- | ---------------------- | +| [YOLOv5n-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-cls.pt) | 224 | 64.6 | 85.4 | 7:59 | **3.3** | **0.5** | **2.5** | **0.5** | +| [YOLOv5s-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt) | 224 | 71.5 | 90.2 | 8:09 | 6.6 | 0.6 | 5.4 | 1.4 | +| [YOLOv5m-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-cls.pt) | 224 | 75.9 | 92.9 | 10:06 | 15.5 | 0.9 | 12.9 | 3.9 | +| [YOLOv5l-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-cls.pt) | 224 | 78.0 | 94.0 | 11:56 | 26.9 | 1.4 | 26.5 | 8.5 | +| [YOLOv5x-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-cls.pt) | 224 | **79.0** | **94.4** | 15:04 | 54.3 | 1.8 | 48.1 | 15.9 | +| | | | | | | | | | +| [ResNet18](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet18.pt) | 224 | 70.3 | 89.5 | **6:47** | 11.2 | 0.5 | 11.7 | 3.7 | +| [Resnetzch](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet34.pt) | 224 | 73.9 | 91.8 | 8:33 | 20.6 | 0.9 | 21.8 | 7.4 | +| [ResNet50](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet50.pt) | 224 | 76.8 | 93.4 | 11:10 | 23.4 | 1.0 | 25.6 | 8.5 | +| [ResNet101](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet101.pt) | 224 | 78.5 | 94.3 | 17:10 | 42.1 | 1.9 | 44.5 | 15.9 | +| | | | | | | | | | +| [EfficientNet_b0](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b0.pt) | 224 | 75.1 | 92.4 | 13:03 | 12.5 | 1.3 | 5.3 | 1.0 | +| [EfficientNet_b1](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b1.pt) | 224 | 76.4 | 93.2 | 17:04 | 14.9 | 1.6 | 7.8 | 1.5 | +| [EfficientNet_b2](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b2.pt) | 224 | 76.6 | 93.4 | 17:10 | 15.9 | 1.6 | 9.1 | 1.7 | +| [EfficientNet_b3](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b3.pt) | 224 | 77.7 | 94.0 | 19:19 | 18.9 | 1.9 | 12.2 | 2.4 | + +
+ Table Notes (点击以展开) + +- 所有模型都使用 SGD 优化器训练 90 个 epochs,都使用 `lr0=0.001` 和 `weight_decay=5e-5` 参数, 图像大小为 224 + ,且都使用默认设置。
训练 log 可以查看 https://wandb.ai/glenn-jocher/YOLOv5-Classifier-v6-2 +- **准确性**都在单模型单尺度上计算,数据集使用 [ImageNet-1k](https://www.image-net.org/index.php) 。
+ 复现命令 `python classify/val.py --data ../datasets/imagenet --img 224` +- **推理速度**是使用 100 个推理图像进行平均得到,测试环境使用谷歌 [Colab Pro](https://colab.research.google.com/signup) + V100 高 RAM 实例。
复现命令 `python classify/val.py --data ../datasets/imagenet --img 224 --batch 1` +- **模型导出**到 FP32 的 ONNX 和 FP16 的 TensorRT 使用 `export.py` 。
+ 复现命令 `python export.py --weights yolov5s-cls.pt --include engine onnx --imgsz 224` +
+
+ +
+ 分类训练示例  Open In Colab + +### 训练 + +YOLOv5 分类训练支持自动下载 MNIST、Fashion-MNIST、CIFAR10、CIFAR100、Imagenette、Imagewoof 和 ImageNet +数据集,命令中使用 `--data` 即可。 MNIST 示例 `--data mnist` 。 + +```bash +# 单 GPU +python classify/train.py --model yolov5s-cls.pt --data cifar100 --epochs 5 --img 224 --batch 128 + +# 多 GPU, DDP 模式 +python -m torch.distributed.run --nproc_per_node 4 --master_port 1 classify/train.py --model yolov5s-cls.pt --data imagenet --epochs 5 --img 224 --device 0,1,2,3 +``` + +### 验证 + +在 ImageNet-1k 数据集上验证 YOLOv5m-cls 的准确性: + +```bash +bash data/scripts/get_imagenet.sh --val # download ImageNet val split (6.3G, 50000 images) +python classify/val.py --weights yolov5m-cls.pt --data ../datasets/imagenet --img 224 # validate +``` + +### 预测 + +使用预训练的 YOLOv5s-cls.pt 来预测 bus.jpg: + +```bash +python classify/predict.py --weights yolov5s-cls.pt --data data/images/bus.jpg +``` + +```python +model = torch.hub.load( + "ultralytics/yolov5", "custom", "yolov5s-cls.pt" +) # load from PyTorch Hub +``` + +### 模型导出 + +将一组经过训练的 YOLOv5s-cls、ResNet 和 EfficientNet 模型导出到 ONNX 和 TensorRT: + +```bash +python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --include onnx engine --img 224 +``` + +
+ +##
环境
+ +使用下面我们经过验证的环境,在几秒钟内开始使用 YOLOv5 。单击下面的图标了解详细信息。 + +
+ + + + + + + + + + + + + + + + + +
+ +##
贡献
+ +我们喜欢您的意见或建议!我们希望尽可能简单和透明地为 YOLOv5 做出贡献。请看我们的 [投稿指南](CONTRIBUTING.md) +,并填写 [YOLOv5调查](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) +向我们发送您的体验反馈。感谢我们所有的贡献者! + + + + + + +##
License
+ +YOLOv5 在两种不同的 License 下可用: + +- **GPL-3.0 License**: 查看 [License](https://github.com/ultralytics/yolov5/blob/master/LICENSE) 文件的详细信息。 +- **企业License**:在没有 GPL-3.0 开源要求的情况下为商业产品开发提供更大的灵活性。典型用例是将 Ultralytics 软件和 AI + 模型嵌入到商业产品和应用程序中。在以下位置申请企业许可证 [Ultralytics 许可](https://ultralytics.com/license) 。 + +##
联系我们
+ +请访问 [GitHub Issues](https://github.com/ultralytics/yolov5/issues) +或 [Ultralytics Community Forum](https://community.ultralytis.com) 以报告 YOLOv5 错误和请求功能。 + +
+
+ + + + + + + + + + + + + + + + + + + + +
+ +[tta]: https://github.com/ultralytics/yolov5/issues/303 diff --git a/benchmarks.py b/benchmarks.py new file mode 100644 index 0000000000..b9a4136014 --- /dev/null +++ b/benchmarks.py @@ -0,0 +1,169 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Run benchmarks on all supported export formats + +Format | `export.py --include` | Model +--- | --- | --- +PyTorch | - | yolov5s.pt +TorchScript | `torchscript` | yolov5s.torchscript +ONNX | `onnx` | yolov5s.onnx +OpenVINO | `openvino` | yolov5s_openvino_model/ +TensorRT | `engine` | yolov5s.engine +CoreML | `coreml` | yolov5s.mlmodel +TensorFlow SavedModel | `saved_model` | yolov5s_saved_model/ +TensorFlow GraphDef | `pb` | yolov5s.pb +TensorFlow Lite | `tflite` | yolov5s.tflite +TensorFlow Edge TPU | `edgetpu` | yolov5s_edgetpu.tflite +TensorFlow.js | `tfjs` | yolov5s_web_model/ + +Requirements: + $ pip install -r requirements.txt coremltools onnx onnx-simplifier onnxruntime openvino-dev tensorflow-cpu # CPU + $ pip install -r requirements.txt coremltools onnx onnx-simplifier onnxruntime-gpu openvino-dev tensorflow # GPU + $ pip install -U nvidia-tensorrt --index-url https://pypi.ngc.nvidia.com # TensorRT + +Usage: + $ python benchmarks.py --weights yolov5s.pt --img 640 +""" + +import argparse +import platform +import sys +import time +from pathlib import Path + +import pandas as pd + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +# ROOT = ROOT.relative_to(Path.cwd()) # relative + +import export +from models.experimental import attempt_load +from models.yolo import SegmentationModel +from segment.val import run as val_seg +from utils import notebook_init +from utils.general import LOGGER, check_yaml, file_size, print_args +from utils.torch_utils import select_device +from val import run as val_det + + +def run( + weights=ROOT / 'yolov5s.pt', # weights path + imgsz=640, # inference size (pixels) + batch_size=1, # batch size + data=ROOT / 'data/coco128.yaml', # dataset.yaml path + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + half=False, # use FP16 half-precision inference + test=False, # test exports only + pt_only=False, # test PyTorch only + hard_fail=False, # throw error on benchmark failure +): + y, t = [], time.time() + device = select_device(device) + model_type = type(attempt_load(weights, fuse=False)) # DetectionModel, SegmentationModel, etc. + for i, (name, f, suffix, cpu, gpu) in export.export_formats().iterrows(): # index, (name, file, suffix, CPU, GPU) + try: + assert i not in (9, 10), 'inference not supported' # Edge TPU and TF.js are unsupported + assert i != 5 or platform.system() == 'Darwin', 'inference only supported on macOS>=10.13' # CoreML + if 'cpu' in device.type: + assert cpu, 'inference not supported on CPU' + if 'cuda' in device.type: + assert gpu, 'inference not supported on GPU' + + # Export + if f == '-': + w = weights # PyTorch format + else: + w = export.run(weights=weights, imgsz=[imgsz], include=[f], device=device, half=half)[-1] # all others + assert suffix in str(w), 'export failed' + + # Validate + if model_type == SegmentationModel: + result = val_seg(data, w, batch_size, imgsz, plots=False, device=device, task='speed', half=half) + metric = result[0][7] # (box(p, r, map50, map), mask(p, r, map50, map), *loss(box, obj, cls)) + else: # DetectionModel: + result = val_det(data, w, batch_size, imgsz, plots=False, device=device, task='speed', half=half) + metric = result[0][3] # (p, r, map50, map, *loss(box, obj, cls)) + speed = result[2][1] # times (preprocess, inference, postprocess) + y.append([name, round(file_size(w), 1), round(metric, 4), round(speed, 2)]) # MB, mAP, t_inference + except Exception as e: + if hard_fail: + assert type(e) is AssertionError, f'Benchmark --hard-fail for {name}: {e}' + LOGGER.warning(f'WARNING ⚠️ Benchmark failure for {name}: {e}') + y.append([name, None, None, None]) # mAP, t_inference + if pt_only and i == 0: + break # break after PyTorch + + # Print results + LOGGER.info('\n') + parse_opt() + notebook_init() # print system info + c = ['Format', 'Size (MB)', 'mAP50-95', 'Inference time (ms)'] if map else ['Format', 'Export', '', ''] + py = pd.DataFrame(y, columns=c) + LOGGER.info(f'\nBenchmarks complete ({time.time() - t:.2f}s)') + LOGGER.info(str(py if map else py.iloc[:, :2])) + if hard_fail and isinstance(hard_fail, str): + metrics = py['mAP50-95'].array # values to compare to floor + floor = eval(hard_fail) # minimum metric floor to pass, i.e. = 0.29 mAP for YOLOv5n + assert all(x > floor for x in metrics if pd.notna(x)), f'HARD FAIL: mAP50-95 < floor {floor}' + return py + + +def test( + weights=ROOT / 'yolov5s.pt', # weights path + imgsz=640, # inference size (pixels) + batch_size=1, # batch size + data=ROOT / 'data/coco128.yaml', # dataset.yaml path + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + half=False, # use FP16 half-precision inference + test=False, # test exports only + pt_only=False, # test PyTorch only + hard_fail=False, # throw error on benchmark failure +): + y, t = [], time.time() + device = select_device(device) + for i, (name, f, suffix, gpu) in export.export_formats().iterrows(): # index, (name, file, suffix, gpu-capable) + try: + w = weights if f == '-' else \ + export.run(weights=weights, imgsz=[imgsz], include=[f], device=device, half=half)[-1] # weights + assert suffix in str(w), 'export failed' + y.append([name, True]) + except Exception: + y.append([name, False]) # mAP, t_inference + + # Print results + LOGGER.info('\n') + parse_opt() + notebook_init() # print system info + py = pd.DataFrame(y, columns=['Format', 'Export']) + LOGGER.info(f'\nExports complete ({time.time() - t:.2f}s)') + LOGGER.info(str(py)) + return py + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='weights path') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') + parser.add_argument('--batch-size', type=int, default=1, help='batch size') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--test', action='store_true', help='test exports only') + parser.add_argument('--pt-only', action='store_true', help='test PyTorch only') + parser.add_argument('--hard-fail', nargs='?', const=True, default=False, help='Exception on error or < min metric') + opt = parser.parse_args() + opt.data = check_yaml(opt.data) # check YAML + print_args(vars(opt)) + return opt + + +def main(opt): + test(**vars(opt)) if opt.test else run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/classify/predict.py b/classify/predict.py new file mode 100644 index 0000000000..dc7a3edae7 --- /dev/null +++ b/classify/predict.py @@ -0,0 +1,226 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Run classification inference on images, videos, directories, globs, YouTube, webcam, streams, etc. + +Usage - sources: + $ python classify/predict.py --weights yolov5s-cls.pt --source 0 # webcam + img.jpg # image + vid.mp4 # video + screen # screenshot + path/ # directory + list.txt # list of images + list.streams # list of streams + 'path/*.jpg' # glob + 'https://youtu.be/Zgi9g1ksQHc' # YouTube + 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream + +Usage - formats: + $ python classify/predict.py --weights yolov5s-cls.pt # PyTorch + yolov5s-cls.torchscript # TorchScript + yolov5s-cls.onnx # ONNX Runtime or OpenCV DNN with --dnn + yolov5s-cls_openvino_model # OpenVINO + yolov5s-cls.engine # TensorRT + yolov5s-cls.mlmodel # CoreML (macOS-only) + yolov5s-cls_saved_model # TensorFlow SavedModel + yolov5s-cls.pb # TensorFlow GraphDef + yolov5s-cls.tflite # TensorFlow Lite + yolov5s-cls_edgetpu.tflite # TensorFlow Edge TPU + yolov5s-cls_paddle_model # PaddlePaddle +""" + +import argparse +import os +import platform +import sys +from pathlib import Path + +import torch +import torch.nn.functional as F + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.augmentations import classify_transforms +from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams +from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, + increment_path, print_args, strip_optimizer) +from utils.plots import Annotator +from utils.torch_utils import select_device, smart_inference_mode + + +@smart_inference_mode() +def run( + weights=ROOT / 'yolov5s-cls.pt', # model.pt path(s) + source=ROOT / 'data/images', # file/dir/URL/glob/screen/0(webcam) + data=ROOT / 'data/coco128.yaml', # dataset.yaml path + imgsz=(224, 224), # inference size (height, width) + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + view_img=False, # show results + save_txt=False, # save results to *.txt + nosave=False, # do not save images/videos + augment=False, # augmented inference + visualize=False, # visualize features + update=False, # update all models + project=ROOT / 'runs/predict-cls', # save results to project/name + name='exp', # save results to project/name + exist_ok=False, # existing project/name ok, do not increment + half=False, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + vid_stride=1, # video frame-rate stride +): + source = str(source) + save_img = not nosave and not source.endswith('.txt') # save inference images + is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) + is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://')) + webcam = source.isnumeric() or source.endswith('.streams') or (is_url and not is_file) + screenshot = source.lower().startswith('screen') + if is_url and is_file: + source = check_file(source) # download + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + device = select_device(device) + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, names, pt = model.stride, model.names, model.pt + imgsz = check_img_size(imgsz, s=stride) # check image size + + # Dataloader + bs = 1 # batch_size + if webcam: + view_img = check_imshow(warn=True) + dataset = LoadStreams(source, img_size=imgsz, transforms=classify_transforms(imgsz[0]), vid_stride=vid_stride) + bs = len(dataset) + elif screenshot: + dataset = LoadScreenshots(source, img_size=imgsz, stride=stride, auto=pt) + else: + dataset = LoadImages(source, img_size=imgsz, transforms=classify_transforms(imgsz[0]), vid_stride=vid_stride) + vid_path, vid_writer = [None] * bs, [None] * bs + + # Run inference + model.warmup(imgsz=(1 if pt else bs, 3, *imgsz)) # warmup + seen, windows, dt = 0, [], (Profile(), Profile(), Profile()) + for path, im, im0s, vid_cap, s in dataset: + with dt[0]: + im = torch.Tensor(im).to(model.device) + im = im.half() if model.fp16 else im.float() # uint8 to fp16/32 + if len(im.shape) == 3: + im = im[None] # expand for batch dim + + # Inference + with dt[1]: + results = model(im) + + # Post-process + with dt[2]: + pred = F.softmax(results, dim=1) # probabilities + + # Process predictions + for i, prob in enumerate(pred): # per image + seen += 1 + if webcam: # batch_size >= 1 + p, im0, frame = path[i], im0s[i].copy(), dataset.count + s += f'{i}: ' + else: + p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0) + + p = Path(p) # to Path + save_path = str(save_dir / p.name) # im.jpg + txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # im.txt + + s += '%gx%g ' % im.shape[2:] # print string + annotator = Annotator(im0, example=str(names), pil=True) + + # Print results + top5i = prob.argsort(0, descending=True)[:5].tolist() # top 5 indices + s += f"{', '.join(f'{names[j]} {prob[j]:.2f}' for j in top5i)}, " + + # Write results + text = '\n'.join(f'{prob[j]:.2f} {names[j]}' for j in top5i) + if save_img or view_img: # Add bbox to image + annotator.text((32, 32), text, txt_color=(255, 255, 255)) + if save_txt: # Write to file + with open(f'{txt_path}.txt', 'a') as f: + f.write(text + '\n') + + # Stream results + im0 = annotator.result() + if view_img: + if platform.system() == 'Linux' and p not in windows: + windows.append(p) + cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux) + cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0]) + cv2.imshow(str(p), im0) + cv2.waitKey(1) # 1 millisecond + + # Save results (image with detections) + if save_img: + if dataset.mode == 'image': + cv2.imwrite(save_path, im0) + else: # 'video' or 'stream' + if vid_path[i] != save_path: # new video + vid_path[i] = save_path + if isinstance(vid_writer[i], cv2.VideoWriter): + vid_writer[i].release() # release previous video writer + if vid_cap: # video + fps = vid_cap.get(cv2.CAP_PROP_FPS) + w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + else: # stream + fps, w, h = 30, im0.shape[1], im0.shape[0] + save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos + vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) + vid_writer[i].write(im0) + + # Print time (inference-only) + LOGGER.info(f"{s}{dt[1].dt * 1E3:.1f}ms") + + # Print results + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t) + if save_txt or save_img: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + if update: + strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning) + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s-cls.pt', help='model path(s)') + parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob/screen/0(webcam)') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path') + parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[224], help='inference size h,w') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--view-img', action='store_true', help='show results') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--nosave', action='store_true', help='do not save images/videos') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--visualize', action='store_true', help='visualize features') + parser.add_argument('--update', action='store_true', help='update all models') + parser.add_argument('--project', default=ROOT / 'runs/predict-cls', help='save results to project/name') + parser.add_argument('--name', default='exp', help='save results to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride') + opt = parser.parse_args() + opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand + print_args(vars(opt)) + return opt + + +def main(opt): + check_requirements(exclude=('tensorboard', 'thop')) + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/classify/train.py b/classify/train.py new file mode 100644 index 0000000000..4d62bfc75c --- /dev/null +++ b/classify/train.py @@ -0,0 +1,333 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Train a YOLOv5 classifier model on a classification dataset + +Usage - Single-GPU training: + $ python classify/train.py --model yolov5s-cls.pt --data imagenette160 --epochs 5 --img 224 + +Usage - Multi-GPU DDP training: + $ python -m torch.distributed.run --nproc_per_node 4 --master_port 2022 classify/train.py --model yolov5s-cls.pt --data imagenet --epochs 5 --img 224 --device 0,1,2,3 + +Datasets: --data mnist, fashion-mnist, cifar10, cifar100, imagenette, imagewoof, imagenet, or 'path/to/data' +YOLOv5-cls models: --model yolov5n-cls.pt, yolov5s-cls.pt, yolov5m-cls.pt, yolov5l-cls.pt, yolov5x-cls.pt +Torchvision models: --model resnet50, efficientnet_b0, etc. See https://pytorch.org/vision/stable/models.html +""" + +import argparse +import os +import subprocess +import sys +import time +from copy import deepcopy +from datetime import datetime +from pathlib import Path + +import torch +import torch.distributed as dist +import torch.hub as hub +import torch.optim.lr_scheduler as lr_scheduler +import torchvision +from torch.cuda import amp +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from classify import val as validate +from models.experimental import attempt_load +from models.yolo import ClassificationModel, DetectionModel +from utils.dataloaders import create_classification_dataloader +from utils.general import (DATASETS_DIR, LOGGER, TQDM_BAR_FORMAT, WorkingDirectory, check_git_info, check_git_status, + check_requirements, colorstr, download, increment_path, init_seeds, print_args, yaml_save) +from utils.loggers import GenericLogger +from utils.plots import imshow_cls +from utils.torch_utils import (ModelEMA, model_info, reshape_classifier_output, select_device, smart_DDP, + smart_optimizer, smartCrossEntropyLoss, torch_distributed_zero_first) + +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +GIT_INFO = check_git_info() + + +def train(opt, device): + init_seeds(opt.seed + 1 + RANK, deterministic=True) + save_dir, data, bs, epochs, nw, imgsz, pretrained = \ + opt.save_dir, Path(opt.data), opt.batch_size, opt.epochs, min(os.cpu_count() - 1, opt.workers), \ + opt.imgsz, str(opt.pretrained).lower() == 'true' + cuda = device.type != 'cpu' + + # Directories + wdir = save_dir / 'weights' + wdir.mkdir(parents=True, exist_ok=True) # make dir + last, best = wdir / 'last.pt', wdir / 'best.pt' + + # Save run settings + yaml_save(save_dir / 'opt.yaml', vars(opt)) + + # Logger + logger = GenericLogger(opt=opt, console_logger=LOGGER) if RANK in {-1, 0} else None + + # Download Dataset + with torch_distributed_zero_first(LOCAL_RANK), WorkingDirectory(ROOT): + data_dir = data if data.is_dir() else (DATASETS_DIR / data) + if not data_dir.is_dir(): + LOGGER.info(f'\nDataset not found ⚠️, missing path {data_dir}, attempting download...') + t = time.time() + if str(data) == 'imagenet': + subprocess.run(f"bash {ROOT / 'data/scripts/get_imagenet.sh'}", shell=True, check=True) + else: + url = f'https://github.com/ultralytics/yolov5/releases/download/v1.0/{data}.zip' + download(url, dir=data_dir.parent) + s = f"Dataset download success ✅ ({time.time() - t:.1f}s), saved to {colorstr('bold', data_dir)}\n" + LOGGER.info(s) + + # Dataloaders + nc = len([x for x in (data_dir / 'train').glob('*') if x.is_dir()]) # number of classes + trainloader = create_classification_dataloader(path=data_dir / 'train', + imgsz=imgsz, + batch_size=bs // WORLD_SIZE, + augment=True, + cache=opt.cache, + rank=LOCAL_RANK, + workers=nw) + + test_dir = data_dir / 'test' if (data_dir / 'test').exists() else data_dir / 'val' # data/test or data/val + if RANK in {-1, 0}: + testloader = create_classification_dataloader(path=test_dir, + imgsz=imgsz, + batch_size=bs // WORLD_SIZE * 2, + augment=False, + cache=opt.cache, + rank=-1, + workers=nw) + + # Model + with torch_distributed_zero_first(LOCAL_RANK), WorkingDirectory(ROOT): + if Path(opt.model).is_file() or opt.model.endswith('.pt'): + model = attempt_load(opt.model, device='cpu', fuse=False) + elif opt.model in torchvision.models.__dict__: # TorchVision models i.e. resnet50, efficientnet_b0 + model = torchvision.models.__dict__[opt.model](weights='IMAGENET1K_V1' if pretrained else None) + else: + m = hub.list('ultralytics/yolov5') # + hub.list('pytorch/vision') # models + raise ModuleNotFoundError(f'--model {opt.model} not found. Available models are: \n' + '\n'.join(m)) + if isinstance(model, DetectionModel): + LOGGER.warning("WARNING ⚠️ pass YOLOv5 classifier model with '-cls' suffix, i.e. '--model yolov5s-cls.pt'") + model = ClassificationModel(model=model, nc=nc, cutoff=opt.cutoff or 10) # convert to classification model + reshape_classifier_output(model, nc) # update class count + for m in model.modules(): + if not pretrained and hasattr(m, 'reset_parameters'): + m.reset_parameters() + if isinstance(m, torch.nn.Dropout) and opt.dropout is not None: + m.p = opt.dropout # set dropout + for p in model.parameters(): + p.requires_grad = True # for training + model = model.to(device) + + # Info + if RANK in {-1, 0}: + model.names = trainloader.dataset.classes # attach class names + model.transforms = testloader.dataset.torch_transforms # attach inference transforms + model_info(model) + if opt.verbose: + LOGGER.info(model) + images, labels = next(iter(trainloader)) + file = imshow_cls(images[:25], labels[:25], names=model.names, f=save_dir / 'train_images.jpg') + logger.log_images(file, name='Train Examples') + logger.log_graph(model, imgsz) # log model + + # Optimizer + optimizer = smart_optimizer(model, opt.optimizer, opt.lr0, momentum=0.9, decay=opt.decay) + + # Scheduler + lrf = 0.01 # final lr (fraction of lr0) + # lf = lambda x: ((1 + math.cos(x * math.pi / epochs)) / 2) * (1 - lrf) + lrf # cosine + lf = lambda x: (1 - x / epochs) * (1 - lrf) + lrf # linear + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) + # scheduler = lr_scheduler.OneCycleLR(optimizer, max_lr=lr0, total_steps=epochs, pct_start=0.1, + # final_div_factor=1 / 25 / lrf) + + # EMA + ema = ModelEMA(model) if RANK in {-1, 0} else None + + # DDP mode + if cuda and RANK != -1: + model = smart_DDP(model) + + # Train + t0 = time.time() + criterion = smartCrossEntropyLoss(label_smoothing=opt.label_smoothing) # loss function + best_fitness = 0.0 + scaler = amp.GradScaler(enabled=cuda) + val = test_dir.stem # 'val' or 'test' + LOGGER.info(f'Image sizes {imgsz} train, {imgsz} test\n' + f'Using {nw * WORLD_SIZE} dataloader workers\n' + f"Logging results to {colorstr('bold', save_dir)}\n" + f'Starting {opt.model} training on {data} dataset with {nc} classes for {epochs} epochs...\n\n' + f"{'Epoch':>10}{'GPU_mem':>10}{'train_loss':>12}{f'{val}_loss':>12}{'top1_acc':>12}{'top5_acc':>12}") + for epoch in range(epochs): # loop over the dataset multiple times + tloss, vloss, fitness = 0.0, 0.0, 0.0 # train loss, val loss, fitness + model.train() + if RANK != -1: + trainloader.sampler.set_epoch(epoch) + pbar = enumerate(trainloader) + if RANK in {-1, 0}: + pbar = tqdm(enumerate(trainloader), total=len(trainloader), bar_format=TQDM_BAR_FORMAT) + for i, (images, labels) in pbar: # progress bar + images, labels = images.to(device, non_blocking=True), labels.to(device) + + # Forward + with amp.autocast(enabled=cuda): # stability issues when enabled + loss = criterion(model(images), labels) + + # Backward + scaler.scale(loss).backward() + + # Optimize + scaler.unscale_(optimizer) # unscale gradients + torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=10.0) # clip gradients + scaler.step(optimizer) + scaler.update() + optimizer.zero_grad() + if ema: + ema.update(model) + + if RANK in {-1, 0}: + # Print + tloss = (tloss * i + loss.item()) / (i + 1) # update mean losses + mem = '%.3gG' % (torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0) # (GB) + pbar.desc = f"{f'{epoch + 1}/{epochs}':>10}{mem:>10}{tloss:>12.3g}" + ' ' * 36 + + # Test + if i == len(pbar) - 1: # last batch + top1, top5, vloss = validate.run(model=ema.ema, + dataloader=testloader, + criterion=criterion, + pbar=pbar) # test accuracy, loss + fitness = top1 # define fitness as top1 accuracy + + # Scheduler + scheduler.step() + + # Log metrics + if RANK in {-1, 0}: + # Best fitness + if fitness > best_fitness: + best_fitness = fitness + + # Log + metrics = { + "train/loss": tloss, + f"{val}/loss": vloss, + "metrics/accuracy_top1": top1, + "metrics/accuracy_top5": top5, + "lr/0": optimizer.param_groups[0]['lr']} # learning rate + logger.log_metrics(metrics, epoch) + + # Save model + final_epoch = epoch + 1 == epochs + if (not opt.nosave) or final_epoch: + ckpt = { + 'epoch': epoch, + 'best_fitness': best_fitness, + 'model': deepcopy(ema.ema).half(), # deepcopy(de_parallel(model)).half(), + 'ema': None, # deepcopy(ema.ema).half(), + 'updates': ema.updates, + 'optimizer': None, # optimizer.state_dict(), + 'opt': vars(opt), + 'git': GIT_INFO, # {remote, branch, commit} if a git repo + 'date': datetime.now().isoformat()} + + # Save last, best and delete + torch.save(ckpt, last) + if best_fitness == fitness: + torch.save(ckpt, best) + del ckpt + + # Train complete + if RANK in {-1, 0} and final_epoch: + LOGGER.info(f'\nTraining complete ({(time.time() - t0) / 3600:.3f} hours)' + f"\nResults saved to {colorstr('bold', save_dir)}" + f"\nPredict: python classify/predict.py --weights {best} --source im.jpg" + f"\nValidate: python classify/val.py --weights {best} --data {data_dir}" + f"\nExport: python export.py --weights {best} --include onnx" + f"\nPyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', '{best}')" + f"\nVisualize: https://netron.app\n") + + # Plot examples + images, labels = (x[:25] for x in next(iter(testloader))) # first 25 images and labels + pred = torch.max(ema.ema(images.to(device)), 1)[1] + file = imshow_cls(images, labels, pred, model.names, verbose=False, f=save_dir / 'test_images.jpg') + + # Log results + meta = {"epochs": epochs, "top1_acc": best_fitness, "date": datetime.now().isoformat()} + logger.log_images(file, name='Test Examples (true-predicted)', epoch=epoch) + logger.log_model(best, epochs, metadata=meta) + + +def parse_opt(known=False): + parser = argparse.ArgumentParser() + parser.add_argument('--model', type=str, default='yolov5s-cls.pt', help='initial weights path') + parser.add_argument('--data', type=str, default='imagenette160', help='cifar10, cifar100, mnist, imagenet, ...') + parser.add_argument('--epochs', type=int, default=10, help='total training epochs') + parser.add_argument('--batch-size', type=int, default=64, help='total batch size for all GPUs') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=224, help='train, val image size (pixels)') + parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') + parser.add_argument('--cache', type=str, nargs='?', const='ram', help='--cache images in "ram" (default) or "disk"') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--project', default=ROOT / 'runs/train-cls', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--pretrained', nargs='?', const=True, default=True, help='start from i.e. --pretrained False') + parser.add_argument('--optimizer', choices=['SGD', 'Adam', 'AdamW', 'RMSProp'], default='Adam', help='optimizer') + parser.add_argument('--lr0', type=float, default=0.001, help='initial learning rate') + parser.add_argument('--decay', type=float, default=5e-5, help='weight decay') + parser.add_argument('--label-smoothing', type=float, default=0.1, help='Label smoothing epsilon') + parser.add_argument('--cutoff', type=int, default=None, help='Model layer cutoff index for Classify() head') + parser.add_argument('--dropout', type=float, default=None, help='Dropout (fraction)') + parser.add_argument('--verbose', action='store_true', help='Verbose mode') + parser.add_argument('--seed', type=int, default=0, help='Global training seed') + parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + return parser.parse_known_args()[0] if known else parser.parse_args() + + +def main(opt): + # Checks + if RANK in {-1, 0}: + print_args(vars(opt)) + check_git_status() + check_requirements() + + # DDP mode + device = select_device(opt.device, batch_size=opt.batch_size) + if LOCAL_RANK != -1: + assert opt.batch_size != -1, 'AutoBatch is coming soon for classification, please pass a valid --batch-size' + assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' + assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' + torch.cuda.set_device(LOCAL_RANK) + device = torch.device('cuda', LOCAL_RANK) + dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") + + # Parameters + opt.save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok) # increment run + + # Train + train(opt, device) + + +def run(**kwargs): + # Usage: from yolov5 import classify; classify.train.run(data=mnist, imgsz=320, model='yolov5m') + opt = parse_opt(True) + for k, v in kwargs.items(): + setattr(opt, k, v) + main(opt) + return opt + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/classify/tutorial.ipynb b/classify/tutorial.ipynb new file mode 100644 index 0000000000..e3a60c4ee6 --- /dev/null +++ b/classify/tutorial.ipynb @@ -0,0 +1,1480 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "t6MPjfT5NrKQ" + }, + "source": [ + "
\n", + "\n", + " \n", + " \n", + "\n", + "\n", + "
\n", + " \"Run\n", + " \"Open\n", + " \"Open\n", + "
\n", + "\n", + "This YOLOv3 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7mGmQbAO5pQb" + }, + "source": [ + "# Setup\n", + "\n", + "Clone GitHub [repository](https://github.com/ultralytics/yolov5), install [dependencies](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) and check PyTorch and GPU." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "wbvMlHd_QwMG", + "outputId": "0806e375-610d-4ec0-c867-763dbb518279" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "YOLOv3 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Setup complete ✅ (2 CPUs, 12.7 GB RAM, 22.6/78.2 GB disk)\n" + ] + } + ], + "source": [ + "!git clone https://github.com/ultralytics/yolov5 # clone\n", + "%cd yolov5\n", + "%pip install -qr requirements.txt # install\n", + "\n", + "import torch\n", + "import utils\n", + "display = utils.notebook_init() # checks" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4JnkELT0cIJg" + }, + "source": [ + "# 1. Predict\n", + "\n", + "`classify/predict.py` runs YOLOv5 Classification inference on a variety of sources, downloading models automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases), and saving results to `runs/predict-cls`. Example inference sources are:\n", + "\n", + "```shell\n", + "python classify/predict.py --source 0 # webcam\n", + " img.jpg # image \n", + " vid.mp4 # video\n", + " screen # screenshot\n", + " path/ # directory\n", + " 'path/*.jpg' # glob\n", + " 'https://youtu.be/Zgi9g1ksQHc' # YouTube\n", + " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "zR9ZbuQCH7FX", + "outputId": "50504ef7-aa3e-4281-a4e3-d0c7df3c0ffe" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\u001b[34m\u001b[1mclassify/predict: \u001b[0mweights=['yolov5s-cls.pt'], source=data/images, data=data/coco128.yaml, imgsz=[224, 224], device=, view_img=False, save_txt=False, nosave=False, augment=False, visualize=False, update=False, project=runs/predict-cls, name=exp, exist_ok=False, half=False, dnn=False, vid_stride=1\n", + "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "\n", + "Downloading https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt to yolov5s-cls.pt...\n", + "100% 10.5M/10.5M [00:00<00:00, 12.3MB/s]\n", + "\n", + "Fusing layers... \n", + "Model summary: 117 layers, 5447688 parameters, 0 gradients, 11.4 GFLOPs\n", + "image 1/2 /content/yolov5/data/images/bus.jpg: 224x224 minibus 0.39, police van 0.24, amphibious vehicle 0.05, recreational vehicle 0.04, trolleybus 0.03, 3.9ms\n", + "image 2/2 /content/yolov5/data/images/zidane.jpg: 224x224 suit 0.38, bow tie 0.19, bridegroom 0.18, rugby ball 0.04, stage 0.02, 4.6ms\n", + "Speed: 0.3ms pre-process, 4.3ms inference, 1.5ms NMS per image at shape (1, 3, 224, 224)\n", + "Results saved to \u001b[1mruns/predict-cls/exp\u001b[0m\n" + ] + } + ], + "source": [ + "!python classify/predict.py --weights yolov5s-cls.pt --img 224 --source data/images\n", + "# display.Image(filename='runs/predict-cls/exp/zidane.jpg', width=600)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hkAzDWJ7cWTr" + }, + "source": [ + "        \n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0eq1SMWl6Sfn" + }, + "source": [ + "# 2. Validate\n", + "Validate a model's accuracy on the [Imagenet](https://image-net.org/) dataset's `val` or `test` splits. Models are downloaded automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases). To show results by class use the `--verbose` flag." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "WQPtK1QYVaD_", + "outputId": "20fc0630-141e-4a90-ea06-342cbd7ce496" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "--2022-11-22 19:53:40-- https://image-net.org/data/ILSVRC/2012/ILSVRC2012_img_val.tar\n", + "Resolving image-net.org (image-net.org)... 171.64.68.16\n", + "Connecting to image-net.org (image-net.org)|171.64.68.16|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 6744924160 (6.3G) [application/x-tar]\n", + "Saving to: ‘ILSVRC2012_img_val.tar’\n", + "\n", + "ILSVRC2012_img_val. 100%[===================>] 6.28G 16.1MB/s in 10m 52s \n", + "\n", + "2022-11-22 20:04:32 (9.87 MB/s) - ‘ILSVRC2012_img_val.tar’ saved [6744924160/6744924160]\n", + "\n" + ] + } + ], + "source": [ + "# Download Imagenet val (6.3G, 50000 images)\n", + "!bash data/scripts/get_imagenet.sh --val" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "X58w8JLpMnjH", + "outputId": "41843132-98e2-4c25-d474-4cd7b246fb8e" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\u001b[34m\u001b[1mclassify/val: \u001b[0mdata=../datasets/imagenet, weights=['yolov5s-cls.pt'], batch_size=128, imgsz=224, device=, workers=8, verbose=True, project=runs/val-cls, name=exp, exist_ok=False, half=True, dnn=False\n", + "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "\n", + "Fusing layers... \n", + "Model summary: 117 layers, 5447688 parameters, 0 gradients, 11.4 GFLOPs\n", + "validating: 100% 391/391 [04:57<00:00, 1.31it/s]\n", + " Class Images top1_acc top5_acc\n", + " all 50000 0.715 0.902\n", + " tench 50 0.94 0.98\n", + " goldfish 50 0.88 0.92\n", + " great white shark 50 0.78 0.96\n", + " tiger shark 50 0.68 0.96\n", + " hammerhead shark 50 0.82 0.92\n", + " electric ray 50 0.76 0.9\n", + " stingray 50 0.7 0.9\n", + " cock 50 0.78 0.92\n", + " hen 50 0.84 0.96\n", + " ostrich 50 0.98 1\n", + " brambling 50 0.9 0.96\n", + " goldfinch 50 0.92 0.98\n", + " house finch 50 0.88 0.96\n", + " junco 50 0.94 0.98\n", + " indigo bunting 50 0.86 0.88\n", + " American robin 50 0.9 0.96\n", + " bulbul 50 0.84 0.96\n", + " jay 50 0.9 0.96\n", + " magpie 50 0.84 0.96\n", + " chickadee 50 0.9 1\n", + " American dipper 50 0.82 0.92\n", + " kite 50 0.76 0.94\n", + " bald eagle 50 0.92 1\n", + " vulture 50 0.96 1\n", + " great grey owl 50 0.94 0.98\n", + " fire salamander 50 0.96 0.98\n", + " smooth newt 50 0.58 0.94\n", + " newt 50 0.74 0.9\n", + " spotted salamander 50 0.86 0.94\n", + " axolotl 50 0.86 0.96\n", + " American bullfrog 50 0.78 0.92\n", + " tree frog 50 0.84 0.96\n", + " tailed frog 50 0.48 0.8\n", + " loggerhead sea turtle 50 0.68 0.94\n", + " leatherback sea turtle 50 0.5 0.8\n", + " mud turtle 50 0.64 0.84\n", + " terrapin 50 0.52 0.98\n", + " box turtle 50 0.84 0.98\n", + " banded gecko 50 0.7 0.88\n", + " green iguana 50 0.76 0.94\n", + " Carolina anole 50 0.58 0.96\n", + "desert grassland whiptail lizard 50 0.82 0.94\n", + " agama 50 0.74 0.92\n", + " frilled-necked lizard 50 0.84 0.86\n", + " alligator lizard 50 0.58 0.78\n", + " Gila monster 50 0.72 0.8\n", + " European green lizard 50 0.42 0.9\n", + " chameleon 50 0.76 0.84\n", + " Komodo dragon 50 0.86 0.96\n", + " Nile crocodile 50 0.7 0.84\n", + " American alligator 50 0.76 0.96\n", + " triceratops 50 0.9 0.94\n", + " worm snake 50 0.76 0.88\n", + " ring-necked snake 50 0.8 0.92\n", + " eastern hog-nosed snake 50 0.58 0.88\n", + " smooth green snake 50 0.6 0.94\n", + " kingsnake 50 0.82 0.9\n", + " garter snake 50 0.88 0.94\n", + " water snake 50 0.7 0.94\n", + " vine snake 50 0.66 0.76\n", + " night snake 50 0.34 0.82\n", + " boa constrictor 50 0.8 0.96\n", + " African rock python 50 0.48 0.76\n", + " Indian cobra 50 0.82 0.94\n", + " green mamba 50 0.54 0.86\n", + " sea snake 50 0.62 0.9\n", + " Saharan horned viper 50 0.56 0.86\n", + "eastern diamondback rattlesnake 50 0.6 0.86\n", + " sidewinder 50 0.28 0.86\n", + " trilobite 50 0.98 0.98\n", + " harvestman 50 0.86 0.94\n", + " scorpion 50 0.86 0.94\n", + " yellow garden spider 50 0.92 0.96\n", + " barn spider 50 0.38 0.98\n", + " European garden spider 50 0.62 0.98\n", + " southern black widow 50 0.88 0.94\n", + " tarantula 50 0.94 1\n", + " wolf spider 50 0.82 0.92\n", + " tick 50 0.74 0.84\n", + " centipede 50 0.68 0.82\n", + " black grouse 50 0.88 0.98\n", + " ptarmigan 50 0.78 0.94\n", + " ruffed grouse 50 0.88 1\n", + " prairie grouse 50 0.92 1\n", + " peacock 50 0.88 0.9\n", + " quail 50 0.9 0.94\n", + " partridge 50 0.74 0.96\n", + " grey parrot 50 0.9 0.96\n", + " macaw 50 0.88 0.98\n", + "sulphur-crested cockatoo 50 0.86 0.92\n", + " lorikeet 50 0.96 1\n", + " coucal 50 0.82 0.88\n", + " bee eater 50 0.96 0.98\n", + " hornbill 50 0.9 0.96\n", + " hummingbird 50 0.88 0.96\n", + " jacamar 50 0.92 0.94\n", + " toucan 50 0.84 0.94\n", + " duck 50 0.76 0.94\n", + " red-breasted merganser 50 0.86 0.96\n", + " goose 50 0.74 0.96\n", + " black swan 50 0.94 0.98\n", + " tusker 50 0.54 0.92\n", + " echidna 50 0.98 1\n", + " platypus 50 0.72 0.84\n", + " wallaby 50 0.78 0.88\n", + " koala 50 0.84 0.92\n", + " wombat 50 0.78 0.84\n", + " jellyfish 50 0.88 0.96\n", + " sea anemone 50 0.72 0.9\n", + " brain coral 50 0.88 0.96\n", + " flatworm 50 0.8 0.98\n", + " nematode 50 0.86 0.9\n", + " conch 50 0.74 0.88\n", + " snail 50 0.78 0.88\n", + " slug 50 0.74 0.82\n", + " sea slug 50 0.88 0.98\n", + " chiton 50 0.88 0.98\n", + " chambered nautilus 50 0.88 0.92\n", + " Dungeness crab 50 0.78 0.94\n", + " rock crab 50 0.68 0.86\n", + " fiddler crab 50 0.64 0.86\n", + " red king crab 50 0.76 0.96\n", + " American lobster 50 0.78 0.96\n", + " spiny lobster 50 0.74 0.88\n", + " crayfish 50 0.56 0.86\n", + " hermit crab 50 0.78 0.96\n", + " isopod 50 0.66 0.78\n", + " white stork 50 0.88 0.96\n", + " black stork 50 0.84 0.98\n", + " spoonbill 50 0.96 1\n", + " flamingo 50 0.94 1\n", + " little blue heron 50 0.92 0.98\n", + " great egret 50 0.9 0.96\n", + " bittern 50 0.86 0.94\n", + " crane (bird) 50 0.62 0.9\n", + " limpkin 50 0.98 1\n", + " common gallinule 50 0.92 0.96\n", + " American coot 50 0.9 0.98\n", + " bustard 50 0.92 0.96\n", + " ruddy turnstone 50 0.94 1\n", + " dunlin 50 0.86 0.94\n", + " common redshank 50 0.9 0.96\n", + " dowitcher 50 0.84 0.96\n", + " oystercatcher 50 0.86 0.94\n", + " pelican 50 0.92 0.96\n", + " king penguin 50 0.88 0.96\n", + " albatross 50 0.9 1\n", + " grey whale 50 0.84 0.92\n", + " killer whale 50 0.92 1\n", + " dugong 50 0.84 0.96\n", + " sea lion 50 0.82 0.92\n", + " Chihuahua 50 0.66 0.84\n", + " Japanese Chin 50 0.72 0.98\n", + " Maltese 50 0.76 0.94\n", + " Pekingese 50 0.84 0.94\n", + " Shih Tzu 50 0.74 0.96\n", + " King Charles Spaniel 50 0.88 0.98\n", + " Papillon 50 0.86 0.94\n", + " toy terrier 50 0.48 0.94\n", + " Rhodesian Ridgeback 50 0.76 0.98\n", + " Afghan Hound 50 0.84 1\n", + " Basset Hound 50 0.8 0.92\n", + " Beagle 50 0.82 0.96\n", + " Bloodhound 50 0.48 0.72\n", + " Bluetick Coonhound 50 0.86 0.94\n", + " Black and Tan Coonhound 50 0.54 0.8\n", + "Treeing Walker Coonhound 50 0.66 0.98\n", + " English foxhound 50 0.32 0.84\n", + " Redbone Coonhound 50 0.62 0.94\n", + " borzoi 50 0.92 1\n", + " Irish Wolfhound 50 0.48 0.88\n", + " Italian Greyhound 50 0.76 0.98\n", + " Whippet 50 0.74 0.92\n", + " Ibizan Hound 50 0.6 0.86\n", + " Norwegian Elkhound 50 0.88 0.98\n", + " Otterhound 50 0.62 0.9\n", + " Saluki 50 0.72 0.92\n", + " Scottish Deerhound 50 0.86 0.98\n", + " Weimaraner 50 0.88 0.94\n", + "Staffordshire Bull Terrier 50 0.66 0.98\n", + "American Staffordshire Terrier 50 0.64 0.92\n", + " Bedlington Terrier 50 0.9 0.92\n", + " Border Terrier 50 0.86 0.92\n", + " Kerry Blue Terrier 50 0.78 0.98\n", + " Irish Terrier 50 0.7 0.96\n", + " Norfolk Terrier 50 0.68 0.9\n", + " Norwich Terrier 50 0.72 1\n", + " Yorkshire Terrier 50 0.66 0.9\n", + " Wire Fox Terrier 50 0.64 0.98\n", + " Lakeland Terrier 50 0.74 0.92\n", + " Sealyham Terrier 50 0.76 0.9\n", + " Airedale Terrier 50 0.82 0.92\n", + " Cairn Terrier 50 0.76 0.9\n", + " Australian Terrier 50 0.48 0.84\n", + " Dandie Dinmont Terrier 50 0.82 0.92\n", + " Boston Terrier 50 0.92 1\n", + " Miniature Schnauzer 50 0.68 0.9\n", + " Giant Schnauzer 50 0.72 0.98\n", + " Standard Schnauzer 50 0.74 1\n", + " Scottish Terrier 50 0.76 0.96\n", + " Tibetan Terrier 50 0.48 1\n", + "Australian Silky Terrier 50 0.66 0.96\n", + "Soft-coated Wheaten Terrier 50 0.74 0.96\n", + "West Highland White Terrier 50 0.88 0.96\n", + " Lhasa Apso 50 0.68 0.96\n", + " Flat-Coated Retriever 50 0.72 0.94\n", + " Curly-coated Retriever 50 0.82 0.94\n", + " Golden Retriever 50 0.86 0.94\n", + " Labrador Retriever 50 0.82 0.94\n", + "Chesapeake Bay Retriever 50 0.76 0.96\n", + "German Shorthaired Pointer 50 0.8 0.96\n", + " Vizsla 50 0.68 0.96\n", + " English Setter 50 0.7 1\n", + " Irish Setter 50 0.8 0.9\n", + " Gordon Setter 50 0.84 0.92\n", + " Brittany 50 0.84 0.96\n", + " Clumber Spaniel 50 0.92 0.96\n", + "English Springer Spaniel 50 0.88 1\n", + " Welsh Springer Spaniel 50 0.92 1\n", + " Cocker Spaniels 50 0.7 0.94\n", + " Sussex Spaniel 50 0.72 0.92\n", + " Irish Water Spaniel 50 0.88 0.98\n", + " Kuvasz 50 0.66 0.9\n", + " Schipperke 50 0.9 0.98\n", + " Groenendael 50 0.8 0.94\n", + " Malinois 50 0.86 0.98\n", + " Briard 50 0.52 0.8\n", + " Australian Kelpie 50 0.6 0.88\n", + " Komondor 50 0.88 0.94\n", + " Old English Sheepdog 50 0.94 0.98\n", + " Shetland Sheepdog 50 0.74 0.9\n", + " collie 50 0.6 0.96\n", + " Border Collie 50 0.74 0.96\n", + " Bouvier des Flandres 50 0.78 0.94\n", + " Rottweiler 50 0.88 0.96\n", + " German Shepherd Dog 50 0.8 0.98\n", + " Dobermann 50 0.68 0.96\n", + " Miniature Pinscher 50 0.76 0.88\n", + "Greater Swiss Mountain Dog 50 0.68 0.94\n", + " Bernese Mountain Dog 50 0.96 1\n", + " Appenzeller Sennenhund 50 0.22 1\n", + " Entlebucher Sennenhund 50 0.64 0.98\n", + " Boxer 50 0.7 0.92\n", + " Bullmastiff 50 0.78 0.98\n", + " Tibetan Mastiff 50 0.88 0.96\n", + " French Bulldog 50 0.84 0.94\n", + " Great Dane 50 0.54 0.9\n", + " St. Bernard 50 0.92 1\n", + " husky 50 0.46 0.98\n", + " Alaskan Malamute 50 0.76 0.96\n", + " Siberian Husky 50 0.46 0.98\n", + " Dalmatian 50 0.94 0.98\n", + " Affenpinscher 50 0.78 0.9\n", + " Basenji 50 0.92 0.94\n", + " pug 50 0.94 0.98\n", + " Leonberger 50 1 1\n", + " Newfoundland 50 0.78 0.96\n", + " Pyrenean Mountain Dog 50 0.78 0.96\n", + " Samoyed 50 0.96 1\n", + " Pomeranian 50 0.98 1\n", + " Chow Chow 50 0.9 0.96\n", + " Keeshond 50 0.88 0.94\n", + " Griffon Bruxellois 50 0.84 0.98\n", + " Pembroke Welsh Corgi 50 0.82 0.94\n", + " Cardigan Welsh Corgi 50 0.66 0.98\n", + " Toy Poodle 50 0.52 0.88\n", + " Miniature Poodle 50 0.52 0.92\n", + " Standard Poodle 50 0.8 1\n", + " Mexican hairless dog 50 0.88 0.98\n", + " grey wolf 50 0.82 0.92\n", + " Alaskan tundra wolf 50 0.78 0.98\n", + " red wolf 50 0.48 0.9\n", + " coyote 50 0.64 0.86\n", + " dingo 50 0.76 0.88\n", + " dhole 50 0.9 0.98\n", + " African wild dog 50 0.98 1\n", + " hyena 50 0.88 0.96\n", + " red fox 50 0.54 0.92\n", + " kit fox 50 0.72 0.98\n", + " Arctic fox 50 0.94 1\n", + " grey fox 50 0.7 0.94\n", + " tabby cat 50 0.54 0.92\n", + " tiger cat 50 0.22 0.94\n", + " Persian cat 50 0.9 0.98\n", + " Siamese cat 50 0.96 1\n", + " Egyptian Mau 50 0.54 0.8\n", + " cougar 50 0.9 1\n", + " lynx 50 0.72 0.88\n", + " leopard 50 0.78 0.98\n", + " snow leopard 50 0.9 0.98\n", + " jaguar 50 0.7 0.94\n", + " lion 50 0.9 0.98\n", + " tiger 50 0.92 0.98\n", + " cheetah 50 0.94 0.98\n", + " brown bear 50 0.94 0.98\n", + " American black bear 50 0.8 1\n", + " polar bear 50 0.84 0.96\n", + " sloth bear 50 0.72 0.92\n", + " mongoose 50 0.7 0.92\n", + " meerkat 50 0.82 0.92\n", + " tiger beetle 50 0.92 0.94\n", + " ladybug 50 0.86 0.94\n", + " ground beetle 50 0.64 0.94\n", + " longhorn beetle 50 0.62 0.88\n", + " leaf beetle 50 0.64 0.98\n", + " dung beetle 50 0.86 0.98\n", + " rhinoceros beetle 50 0.86 0.94\n", + " weevil 50 0.9 1\n", + " fly 50 0.78 0.94\n", + " bee 50 0.68 0.94\n", + " ant 50 0.68 0.78\n", + " grasshopper 50 0.5 0.92\n", + " cricket 50 0.64 0.92\n", + " stick insect 50 0.64 0.92\n", + " cockroach 50 0.72 0.8\n", + " mantis 50 0.64 0.86\n", + " cicada 50 0.9 0.96\n", + " leafhopper 50 0.88 0.94\n", + " lacewing 50 0.78 0.92\n", + " dragonfly 50 0.82 0.98\n", + " damselfly 50 0.82 1\n", + " red admiral 50 0.94 0.96\n", + " ringlet 50 0.86 0.98\n", + " monarch butterfly 50 0.9 0.92\n", + " small white 50 0.9 1\n", + " sulphur butterfly 50 0.92 1\n", + "gossamer-winged butterfly 50 0.88 1\n", + " starfish 50 0.88 0.92\n", + " sea urchin 50 0.84 0.94\n", + " sea cucumber 50 0.66 0.84\n", + " cottontail rabbit 50 0.72 0.94\n", + " hare 50 0.84 0.96\n", + " Angora rabbit 50 0.94 0.98\n", + " hamster 50 0.96 1\n", + " porcupine 50 0.88 0.98\n", + " fox squirrel 50 0.76 0.94\n", + " marmot 50 0.92 0.96\n", + " beaver 50 0.78 0.94\n", + " guinea pig 50 0.78 0.94\n", + " common sorrel 50 0.96 0.98\n", + " zebra 50 0.94 0.96\n", + " pig 50 0.5 0.76\n", + " wild boar 50 0.84 0.96\n", + " warthog 50 0.84 0.96\n", + " hippopotamus 50 0.88 0.96\n", + " ox 50 0.48 0.94\n", + " water buffalo 50 0.78 0.94\n", + " bison 50 0.88 0.96\n", + " ram 50 0.58 0.92\n", + " bighorn sheep 50 0.66 1\n", + " Alpine ibex 50 0.92 0.98\n", + " hartebeest 50 0.94 1\n", + " impala 50 0.82 0.96\n", + " gazelle 50 0.7 0.96\n", + " dromedary 50 0.9 1\n", + " llama 50 0.82 0.94\n", + " weasel 50 0.44 0.92\n", + " mink 50 0.78 0.96\n", + " European polecat 50 0.46 0.9\n", + " black-footed ferret 50 0.68 0.96\n", + " otter 50 0.66 0.88\n", + " skunk 50 0.96 0.96\n", + " badger 50 0.86 0.92\n", + " armadillo 50 0.88 0.9\n", + " three-toed sloth 50 0.96 1\n", + " orangutan 50 0.78 0.92\n", + " gorilla 50 0.82 0.94\n", + " chimpanzee 50 0.84 0.94\n", + " gibbon 50 0.76 0.86\n", + " siamang 50 0.68 0.94\n", + " guenon 50 0.8 0.94\n", + " patas monkey 50 0.62 0.82\n", + " baboon 50 0.9 0.98\n", + " macaque 50 0.8 0.86\n", + " langur 50 0.6 0.82\n", + " black-and-white colobus 50 0.86 0.9\n", + " proboscis monkey 50 1 1\n", + " marmoset 50 0.74 0.98\n", + " white-headed capuchin 50 0.72 0.9\n", + " howler monkey 50 0.86 0.94\n", + " titi 50 0.5 0.9\n", + "Geoffroy's spider monkey 50 0.42 0.8\n", + " common squirrel monkey 50 0.76 0.92\n", + " ring-tailed lemur 50 0.72 0.94\n", + " indri 50 0.9 0.96\n", + " Asian elephant 50 0.58 0.92\n", + " African bush elephant 50 0.7 0.98\n", + " red panda 50 0.94 0.94\n", + " giant panda 50 0.94 0.98\n", + " snoek 50 0.74 0.9\n", + " eel 50 0.6 0.84\n", + " coho salmon 50 0.84 0.96\n", + " rock beauty 50 0.88 0.98\n", + " clownfish 50 0.78 0.98\n", + " sturgeon 50 0.68 0.94\n", + " garfish 50 0.62 0.8\n", + " lionfish 50 0.96 0.96\n", + " pufferfish 50 0.88 0.96\n", + " abacus 50 0.74 0.88\n", + " abaya 50 0.84 0.92\n", + " academic gown 50 0.42 0.86\n", + " accordion 50 0.8 0.9\n", + " acoustic guitar 50 0.5 0.76\n", + " aircraft carrier 50 0.8 0.96\n", + " airliner 50 0.92 1\n", + " airship 50 0.76 0.82\n", + " altar 50 0.64 0.98\n", + " ambulance 50 0.88 0.98\n", + " amphibious vehicle 50 0.64 0.94\n", + " analog clock 50 0.52 0.92\n", + " apiary 50 0.82 0.96\n", + " apron 50 0.7 0.84\n", + " waste container 50 0.4 0.8\n", + " assault rifle 50 0.42 0.84\n", + " backpack 50 0.34 0.64\n", + " bakery 50 0.4 0.68\n", + " balance beam 50 0.8 0.98\n", + " balloon 50 0.86 0.96\n", + " ballpoint pen 50 0.52 0.96\n", + " Band-Aid 50 0.7 0.9\n", + " banjo 50 0.84 1\n", + " baluster 50 0.68 0.94\n", + " barbell 50 0.56 0.9\n", + " barber chair 50 0.7 0.92\n", + " barbershop 50 0.54 0.86\n", + " barn 50 0.96 0.96\n", + " barometer 50 0.84 0.98\n", + " barrel 50 0.56 0.88\n", + " wheelbarrow 50 0.66 0.88\n", + " baseball 50 0.74 0.98\n", + " basketball 50 0.88 0.98\n", + " bassinet 50 0.66 0.92\n", + " bassoon 50 0.74 0.98\n", + " swimming cap 50 0.62 0.88\n", + " bath towel 50 0.54 0.78\n", + " bathtub 50 0.4 0.88\n", + " station wagon 50 0.66 0.84\n", + " lighthouse 50 0.78 0.94\n", + " beaker 50 0.52 0.68\n", + " military cap 50 0.84 0.96\n", + " beer bottle 50 0.66 0.88\n", + " beer glass 50 0.6 0.84\n", + " bell-cot 50 0.56 0.96\n", + " bib 50 0.58 0.82\n", + " tandem bicycle 50 0.86 0.96\n", + " bikini 50 0.56 0.88\n", + " ring binder 50 0.64 0.84\n", + " binoculars 50 0.54 0.78\n", + " birdhouse 50 0.86 0.94\n", + " boathouse 50 0.74 0.92\n", + " bobsleigh 50 0.92 0.96\n", + " bolo tie 50 0.8 0.94\n", + " poke bonnet 50 0.64 0.86\n", + " bookcase 50 0.66 0.92\n", + " bookstore 50 0.62 0.88\n", + " bottle cap 50 0.58 0.7\n", + " bow 50 0.72 0.86\n", + " bow tie 50 0.7 0.9\n", + " brass 50 0.92 0.96\n", + " bra 50 0.5 0.7\n", + " breakwater 50 0.62 0.86\n", + " breastplate 50 0.4 0.9\n", + " broom 50 0.6 0.86\n", + " bucket 50 0.66 0.8\n", + " buckle 50 0.5 0.68\n", + " bulletproof vest 50 0.5 0.78\n", + " high-speed train 50 0.94 0.96\n", + " butcher shop 50 0.74 0.94\n", + " taxicab 50 0.64 0.86\n", + " cauldron 50 0.44 0.66\n", + " candle 50 0.48 0.74\n", + " cannon 50 0.88 0.94\n", + " canoe 50 0.94 1\n", + " can opener 50 0.66 0.86\n", + " cardigan 50 0.68 0.8\n", + " car mirror 50 0.94 0.96\n", + " carousel 50 0.94 0.98\n", + " tool kit 50 0.56 0.78\n", + " carton 50 0.42 0.7\n", + " car wheel 50 0.38 0.74\n", + "automated teller machine 50 0.76 0.94\n", + " cassette 50 0.52 0.8\n", + " cassette player 50 0.28 0.9\n", + " castle 50 0.78 0.88\n", + " catamaran 50 0.78 1\n", + " CD player 50 0.52 0.82\n", + " cello 50 0.82 1\n", + " mobile phone 50 0.68 0.86\n", + " chain 50 0.38 0.66\n", + " chain-link fence 50 0.7 0.84\n", + " chain mail 50 0.64 0.9\n", + " chainsaw 50 0.84 0.92\n", + " chest 50 0.68 0.92\n", + " chiffonier 50 0.26 0.64\n", + " chime 50 0.62 0.84\n", + " china cabinet 50 0.82 0.96\n", + " Christmas stocking 50 0.92 0.94\n", + " church 50 0.62 0.9\n", + " movie theater 50 0.58 0.88\n", + " cleaver 50 0.32 0.62\n", + " cliff dwelling 50 0.88 1\n", + " cloak 50 0.32 0.64\n", + " clogs 50 0.58 0.88\n", + " cocktail shaker 50 0.62 0.7\n", + " coffee mug 50 0.44 0.72\n", + " coffeemaker 50 0.64 0.92\n", + " coil 50 0.66 0.84\n", + " combination lock 50 0.64 0.84\n", + " computer keyboard 50 0.7 0.82\n", + " confectionery store 50 0.54 0.86\n", + " container ship 50 0.82 0.98\n", + " convertible 50 0.78 0.98\n", + " corkscrew 50 0.82 0.92\n", + " cornet 50 0.46 0.88\n", + " cowboy boot 50 0.64 0.8\n", + " cowboy hat 50 0.64 0.82\n", + " cradle 50 0.38 0.8\n", + " crane (machine) 50 0.78 0.94\n", + " crash helmet 50 0.92 0.96\n", + " crate 50 0.52 0.82\n", + " infant bed 50 0.74 1\n", + " Crock Pot 50 0.78 0.9\n", + " croquet ball 50 0.9 0.96\n", + " crutch 50 0.46 0.7\n", + " cuirass 50 0.54 0.86\n", + " dam 50 0.74 0.92\n", + " desk 50 0.6 0.86\n", + " desktop computer 50 0.54 0.94\n", + " rotary dial telephone 50 0.88 0.94\n", + " diaper 50 0.68 0.84\n", + " digital clock 50 0.54 0.76\n", + " digital watch 50 0.58 0.86\n", + " dining table 50 0.76 0.9\n", + " dishcloth 50 0.94 1\n", + " dishwasher 50 0.44 0.78\n", + " disc brake 50 0.98 1\n", + " dock 50 0.54 0.94\n", + " dog sled 50 0.84 1\n", + " dome 50 0.72 0.92\n", + " doormat 50 0.56 0.82\n", + " drilling rig 50 0.84 0.96\n", + " drum 50 0.38 0.68\n", + " drumstick 50 0.56 0.72\n", + " dumbbell 50 0.62 0.9\n", + " Dutch oven 50 0.7 0.84\n", + " electric fan 50 0.82 0.86\n", + " electric guitar 50 0.62 0.84\n", + " electric locomotive 50 0.92 0.98\n", + " entertainment center 50 0.9 0.98\n", + " envelope 50 0.44 0.86\n", + " espresso machine 50 0.72 0.94\n", + " face powder 50 0.7 0.92\n", + " feather boa 50 0.7 0.84\n", + " filing cabinet 50 0.88 0.98\n", + " fireboat 50 0.94 0.98\n", + " fire engine 50 0.84 0.9\n", + " fire screen sheet 50 0.62 0.76\n", + " flagpole 50 0.74 0.88\n", + " flute 50 0.36 0.72\n", + " folding chair 50 0.62 0.84\n", + " football helmet 50 0.86 0.94\n", + " forklift 50 0.8 0.92\n", + " fountain 50 0.84 0.94\n", + " fountain pen 50 0.76 0.92\n", + " four-poster bed 50 0.78 0.94\n", + " freight car 50 0.96 1\n", + " French horn 50 0.76 0.92\n", + " frying pan 50 0.36 0.78\n", + " fur coat 50 0.84 0.96\n", + " garbage truck 50 0.9 0.98\n", + " gas mask 50 0.84 0.92\n", + " gas pump 50 0.9 0.98\n", + " goblet 50 0.68 0.82\n", + " go-kart 50 0.9 1\n", + " golf ball 50 0.84 0.9\n", + " golf cart 50 0.78 0.86\n", + " gondola 50 0.98 0.98\n", + " gong 50 0.74 0.92\n", + " gown 50 0.62 0.96\n", + " grand piano 50 0.7 0.96\n", + " greenhouse 50 0.8 0.98\n", + " grille 50 0.72 0.9\n", + " grocery store 50 0.66 0.94\n", + " guillotine 50 0.86 0.92\n", + " barrette 50 0.52 0.66\n", + " hair spray 50 0.5 0.74\n", + " half-track 50 0.78 0.9\n", + " hammer 50 0.56 0.76\n", + " hamper 50 0.64 0.84\n", + " hair dryer 50 0.56 0.74\n", + " hand-held computer 50 0.42 0.86\n", + " handkerchief 50 0.78 0.94\n", + " hard disk drive 50 0.76 0.84\n", + " harmonica 50 0.7 0.88\n", + " harp 50 0.88 0.96\n", + " harvester 50 0.78 1\n", + " hatchet 50 0.54 0.74\n", + " holster 50 0.66 0.84\n", + " home theater 50 0.64 0.94\n", + " honeycomb 50 0.56 0.88\n", + " hook 50 0.3 0.6\n", + " hoop skirt 50 0.64 0.86\n", + " horizontal bar 50 0.68 0.98\n", + " horse-drawn vehicle 50 0.88 0.94\n", + " hourglass 50 0.88 0.96\n", + " iPod 50 0.76 0.94\n", + " clothes iron 50 0.82 0.88\n", + " jack-o'-lantern 50 0.98 0.98\n", + " jeans 50 0.68 0.84\n", + " jeep 50 0.72 0.9\n", + " T-shirt 50 0.72 0.96\n", + " jigsaw puzzle 50 0.84 0.94\n", + " pulled rickshaw 50 0.86 0.94\n", + " joystick 50 0.8 0.9\n", + " kimono 50 0.84 0.96\n", + " knee pad 50 0.62 0.88\n", + " knot 50 0.66 0.8\n", + " lab coat 50 0.8 0.96\n", + " ladle 50 0.36 0.64\n", + " lampshade 50 0.48 0.84\n", + " laptop computer 50 0.26 0.88\n", + " lawn mower 50 0.78 0.96\n", + " lens cap 50 0.46 0.72\n", + " paper knife 50 0.26 0.5\n", + " library 50 0.54 0.9\n", + " lifeboat 50 0.92 0.98\n", + " lighter 50 0.56 0.78\n", + " limousine 50 0.76 0.92\n", + " ocean liner 50 0.88 0.94\n", + " lipstick 50 0.74 0.9\n", + " slip-on shoe 50 0.74 0.92\n", + " lotion 50 0.5 0.86\n", + " speaker 50 0.52 0.68\n", + " loupe 50 0.32 0.52\n", + " sawmill 50 0.72 0.9\n", + " magnetic compass 50 0.52 0.82\n", + " mail bag 50 0.68 0.92\n", + " mailbox 50 0.82 0.92\n", + " tights 50 0.22 0.94\n", + " tank suit 50 0.24 0.9\n", + " manhole cover 50 0.96 0.98\n", + " maraca 50 0.74 0.9\n", + " marimba 50 0.84 0.94\n", + " mask 50 0.44 0.82\n", + " match 50 0.66 0.9\n", + " maypole 50 0.96 1\n", + " maze 50 0.8 0.96\n", + " measuring cup 50 0.54 0.76\n", + " medicine chest 50 0.6 0.84\n", + " megalith 50 0.8 0.92\n", + " microphone 50 0.52 0.7\n", + " microwave oven 50 0.48 0.72\n", + " military uniform 50 0.62 0.84\n", + " milk can 50 0.68 0.82\n", + " minibus 50 0.7 1\n", + " miniskirt 50 0.46 0.76\n", + " minivan 50 0.38 0.8\n", + " missile 50 0.4 0.84\n", + " mitten 50 0.76 0.88\n", + " mixing bowl 50 0.8 0.92\n", + " mobile home 50 0.54 0.78\n", + " Model T 50 0.92 0.96\n", + " modem 50 0.58 0.86\n", + " monastery 50 0.44 0.9\n", + " monitor 50 0.4 0.86\n", + " moped 50 0.56 0.94\n", + " mortar 50 0.68 0.94\n", + " square academic cap 50 0.5 0.84\n", + " mosque 50 0.9 1\n", + " mosquito net 50 0.9 0.98\n", + " scooter 50 0.9 0.98\n", + " mountain bike 50 0.78 0.96\n", + " tent 50 0.88 0.96\n", + " computer mouse 50 0.42 0.82\n", + " mousetrap 50 0.76 0.88\n", + " moving van 50 0.4 0.72\n", + " muzzle 50 0.5 0.72\n", + " nail 50 0.68 0.74\n", + " neck brace 50 0.56 0.68\n", + " necklace 50 0.86 1\n", + " nipple 50 0.7 0.88\n", + " notebook computer 50 0.34 0.84\n", + " obelisk 50 0.8 0.92\n", + " oboe 50 0.6 0.84\n", + " ocarina 50 0.8 0.86\n", + " odometer 50 0.96 1\n", + " oil filter 50 0.58 0.82\n", + " organ 50 0.82 0.9\n", + " oscilloscope 50 0.9 0.96\n", + " overskirt 50 0.2 0.7\n", + " bullock cart 50 0.7 0.94\n", + " oxygen mask 50 0.46 0.84\n", + " packet 50 0.5 0.78\n", + " paddle 50 0.56 0.94\n", + " paddle wheel 50 0.86 0.96\n", + " padlock 50 0.74 0.78\n", + " paintbrush 50 0.62 0.8\n", + " pajamas 50 0.56 0.92\n", + " palace 50 0.64 0.96\n", + " pan flute 50 0.84 0.86\n", + " paper towel 50 0.66 0.84\n", + " parachute 50 0.92 0.94\n", + " parallel bars 50 0.62 0.96\n", + " park bench 50 0.74 0.9\n", + " parking meter 50 0.84 0.92\n", + " passenger car 50 0.5 0.82\n", + " patio 50 0.58 0.84\n", + " payphone 50 0.74 0.92\n", + " pedestal 50 0.52 0.9\n", + " pencil case 50 0.64 0.92\n", + " pencil sharpener 50 0.52 0.78\n", + " perfume 50 0.7 0.9\n", + " Petri dish 50 0.6 0.8\n", + " photocopier 50 0.88 0.98\n", + " plectrum 50 0.7 0.84\n", + " Pickelhaube 50 0.72 0.86\n", + " picket fence 50 0.84 0.94\n", + " pickup truck 50 0.64 0.92\n", + " pier 50 0.52 0.82\n", + " piggy bank 50 0.82 0.94\n", + " pill bottle 50 0.76 0.86\n", + " pillow 50 0.76 0.9\n", + " ping-pong ball 50 0.84 0.88\n", + " pinwheel 50 0.76 0.88\n", + " pirate ship 50 0.76 0.94\n", + " pitcher 50 0.46 0.84\n", + " hand plane 50 0.84 0.94\n", + " planetarium 50 0.88 0.98\n", + " plastic bag 50 0.36 0.62\n", + " plate rack 50 0.52 0.78\n", + " plow 50 0.78 0.88\n", + " plunger 50 0.42 0.7\n", + " Polaroid camera 50 0.84 0.92\n", + " pole 50 0.38 0.74\n", + " police van 50 0.76 0.94\n", + " poncho 50 0.58 0.86\n", + " billiard table 50 0.8 0.88\n", + " soda bottle 50 0.56 0.94\n", + " pot 50 0.78 0.92\n", + " potter's wheel 50 0.9 0.94\n", + " power drill 50 0.42 0.72\n", + " prayer rug 50 0.7 0.86\n", + " printer 50 0.54 0.86\n", + " prison 50 0.7 0.9\n", + " projectile 50 0.28 0.9\n", + " projector 50 0.62 0.84\n", + " hockey puck 50 0.92 0.96\n", + " punching bag 50 0.6 0.68\n", + " purse 50 0.42 0.78\n", + " quill 50 0.68 0.84\n", + " quilt 50 0.64 0.9\n", + " race car 50 0.72 0.92\n", + " racket 50 0.72 0.9\n", + " radiator 50 0.66 0.76\n", + " radio 50 0.64 0.92\n", + " radio telescope 50 0.9 0.96\n", + " rain barrel 50 0.8 0.98\n", + " recreational vehicle 50 0.84 0.94\n", + " reel 50 0.72 0.82\n", + " reflex camera 50 0.72 0.92\n", + " refrigerator 50 0.7 0.9\n", + " remote control 50 0.7 0.88\n", + " restaurant 50 0.5 0.66\n", + " revolver 50 0.82 1\n", + " rifle 50 0.38 0.7\n", + " rocking chair 50 0.62 0.84\n", + " rotisserie 50 0.88 0.92\n", + " eraser 50 0.54 0.76\n", + " rugby ball 50 0.86 0.94\n", + " ruler 50 0.68 0.86\n", + " running shoe 50 0.78 0.94\n", + " safe 50 0.82 0.92\n", + " safety pin 50 0.4 0.62\n", + " salt shaker 50 0.66 0.9\n", + " sandal 50 0.66 0.86\n", + " sarong 50 0.64 0.86\n", + " saxophone 50 0.66 0.88\n", + " scabbard 50 0.76 0.92\n", + " weighing scale 50 0.58 0.78\n", + " school bus 50 0.92 1\n", + " schooner 50 0.84 1\n", + " scoreboard 50 0.9 0.96\n", + " CRT screen 50 0.14 0.7\n", + " screw 50 0.9 0.98\n", + " screwdriver 50 0.3 0.58\n", + " seat belt 50 0.88 0.94\n", + " sewing machine 50 0.76 0.9\n", + " shield 50 0.56 0.82\n", + " shoe store 50 0.78 0.96\n", + " shoji 50 0.8 0.92\n", + " shopping basket 50 0.52 0.88\n", + " shopping cart 50 0.76 0.92\n", + " shovel 50 0.62 0.84\n", + " shower cap 50 0.7 0.84\n", + " shower curtain 50 0.64 0.82\n", + " ski 50 0.74 0.92\n", + " ski mask 50 0.72 0.88\n", + " sleeping bag 50 0.68 0.8\n", + " slide rule 50 0.72 0.88\n", + " sliding door 50 0.44 0.78\n", + " slot machine 50 0.94 0.98\n", + " snorkel 50 0.86 0.98\n", + " snowmobile 50 0.88 1\n", + " snowplow 50 0.84 0.98\n", + " soap dispenser 50 0.56 0.86\n", + " soccer ball 50 0.86 0.96\n", + " sock 50 0.62 0.76\n", + " solar thermal collector 50 0.72 0.96\n", + " sombrero 50 0.6 0.84\n", + " soup bowl 50 0.56 0.94\n", + " space bar 50 0.34 0.88\n", + " space heater 50 0.52 0.74\n", + " space shuttle 50 0.82 0.96\n", + " spatula 50 0.3 0.6\n", + " motorboat 50 0.86 1\n", + " spider web 50 0.7 0.9\n", + " spindle 50 0.86 0.98\n", + " sports car 50 0.6 0.94\n", + " spotlight 50 0.26 0.6\n", + " stage 50 0.68 0.86\n", + " steam locomotive 50 0.94 1\n", + " through arch bridge 50 0.84 0.96\n", + " steel drum 50 0.82 0.9\n", + " stethoscope 50 0.6 0.82\n", + " scarf 50 0.5 0.92\n", + " stone wall 50 0.76 0.9\n", + " stopwatch 50 0.58 0.9\n", + " stove 50 0.46 0.74\n", + " strainer 50 0.64 0.84\n", + " tram 50 0.88 0.96\n", + " stretcher 50 0.6 0.8\n", + " couch 50 0.8 0.96\n", + " stupa 50 0.88 0.88\n", + " submarine 50 0.72 0.92\n", + " suit 50 0.4 0.78\n", + " sundial 50 0.58 0.74\n", + " sunglass 50 0.14 0.58\n", + " sunglasses 50 0.28 0.58\n", + " sunscreen 50 0.32 0.7\n", + " suspension bridge 50 0.6 0.94\n", + " mop 50 0.74 0.92\n", + " sweatshirt 50 0.28 0.66\n", + " swimsuit 50 0.52 0.82\n", + " swing 50 0.76 0.84\n", + " switch 50 0.56 0.76\n", + " syringe 50 0.62 0.82\n", + " table lamp 50 0.6 0.88\n", + " tank 50 0.8 0.96\n", + " tape player 50 0.46 0.76\n", + " teapot 50 0.84 1\n", + " teddy bear 50 0.82 0.94\n", + " television 50 0.6 0.9\n", + " tennis ball 50 0.7 0.94\n", + " thatched roof 50 0.88 0.9\n", + " front curtain 50 0.8 0.92\n", + " thimble 50 0.6 0.8\n", + " threshing machine 50 0.56 0.88\n", + " throne 50 0.72 0.82\n", + " tile roof 50 0.72 0.94\n", + " toaster 50 0.66 0.84\n", + " tobacco shop 50 0.42 0.7\n", + " toilet seat 50 0.62 0.88\n", + " torch 50 0.64 0.84\n", + " totem pole 50 0.92 0.98\n", + " tow truck 50 0.62 0.88\n", + " toy store 50 0.6 0.94\n", + " tractor 50 0.76 0.98\n", + " semi-trailer truck 50 0.78 0.92\n", + " tray 50 0.46 0.64\n", + " trench coat 50 0.54 0.72\n", + " tricycle 50 0.72 0.94\n", + " trimaran 50 0.7 0.98\n", + " tripod 50 0.58 0.86\n", + " triumphal arch 50 0.92 0.98\n", + " trolleybus 50 0.9 1\n", + " trombone 50 0.54 0.88\n", + " tub 50 0.24 0.82\n", + " turnstile 50 0.84 0.94\n", + " typewriter keyboard 50 0.68 0.98\n", + " umbrella 50 0.52 0.7\n", + " unicycle 50 0.74 0.96\n", + " upright piano 50 0.76 0.9\n", + " vacuum cleaner 50 0.62 0.9\n", + " vase 50 0.5 0.78\n", + " vault 50 0.76 0.92\n", + " velvet 50 0.2 0.42\n", + " vending machine 50 0.9 1\n", + " vestment 50 0.54 0.82\n", + " viaduct 50 0.78 0.86\n", + " violin 50 0.68 0.78\n", + " volleyball 50 0.86 1\n", + " waffle iron 50 0.72 0.88\n", + " wall clock 50 0.54 0.88\n", + " wallet 50 0.52 0.9\n", + " wardrobe 50 0.68 0.88\n", + " military aircraft 50 0.9 0.98\n", + " sink 50 0.72 0.96\n", + " washing machine 50 0.78 0.94\n", + " water bottle 50 0.54 0.74\n", + " water jug 50 0.22 0.74\n", + " water tower 50 0.9 0.96\n", + " whiskey jug 50 0.64 0.74\n", + " whistle 50 0.72 0.84\n", + " wig 50 0.84 0.9\n", + " window screen 50 0.68 0.8\n", + " window shade 50 0.52 0.76\n", + " Windsor tie 50 0.22 0.66\n", + " wine bottle 50 0.42 0.82\n", + " wing 50 0.54 0.96\n", + " wok 50 0.46 0.82\n", + " wooden spoon 50 0.58 0.8\n", + " wool 50 0.32 0.82\n", + " split-rail fence 50 0.74 0.9\n", + " shipwreck 50 0.84 0.96\n", + " yawl 50 0.78 0.96\n", + " yurt 50 0.84 1\n", + " website 50 0.98 1\n", + " comic book 50 0.62 0.9\n", + " crossword 50 0.84 0.88\n", + " traffic sign 50 0.78 0.9\n", + " traffic light 50 0.8 0.94\n", + " dust jacket 50 0.72 0.94\n", + " menu 50 0.82 0.96\n", + " plate 50 0.44 0.88\n", + " guacamole 50 0.8 0.92\n", + " consomme 50 0.54 0.88\n", + " hot pot 50 0.86 0.98\n", + " trifle 50 0.92 0.98\n", + " ice cream 50 0.68 0.94\n", + " ice pop 50 0.62 0.84\n", + " baguette 50 0.62 0.88\n", + " bagel 50 0.64 0.92\n", + " pretzel 50 0.72 0.88\n", + " cheeseburger 50 0.9 1\n", + " hot dog 50 0.74 0.94\n", + " mashed potato 50 0.74 0.9\n", + " cabbage 50 0.84 0.96\n", + " broccoli 50 0.9 0.96\n", + " cauliflower 50 0.82 1\n", + " zucchini 50 0.74 0.9\n", + " spaghetti squash 50 0.8 0.96\n", + " acorn squash 50 0.82 0.96\n", + " butternut squash 50 0.7 0.94\n", + " cucumber 50 0.6 0.96\n", + " artichoke 50 0.84 0.94\n", + " bell pepper 50 0.84 0.98\n", + " cardoon 50 0.88 0.94\n", + " mushroom 50 0.38 0.92\n", + " Granny Smith 50 0.9 0.96\n", + " strawberry 50 0.6 0.88\n", + " orange 50 0.7 0.92\n", + " lemon 50 0.78 0.98\n", + " fig 50 0.82 0.96\n", + " pineapple 50 0.86 0.96\n", + " banana 50 0.84 0.96\n", + " jackfruit 50 0.9 0.98\n", + " custard apple 50 0.86 0.96\n", + " pomegranate 50 0.82 0.98\n", + " hay 50 0.8 0.92\n", + " carbonara 50 0.88 0.94\n", + " chocolate syrup 50 0.46 0.84\n", + " dough 50 0.4 0.6\n", + " meatloaf 50 0.58 0.84\n", + " pizza 50 0.84 0.96\n", + " pot pie 50 0.68 0.9\n", + " burrito 50 0.8 0.98\n", + " red wine 50 0.54 0.82\n", + " espresso 50 0.64 0.88\n", + " cup 50 0.38 0.7\n", + " eggnog 50 0.38 0.7\n", + " alp 50 0.54 0.88\n", + " bubble 50 0.8 0.96\n", + " cliff 50 0.64 1\n", + " coral reef 50 0.72 0.96\n", + " geyser 50 0.94 1\n", + " lakeshore 50 0.54 0.88\n", + " promontory 50 0.58 0.94\n", + " shoal 50 0.6 0.96\n", + " seashore 50 0.44 0.78\n", + " valley 50 0.72 0.94\n", + " volcano 50 0.78 0.96\n", + " baseball player 50 0.72 0.94\n", + " bridegroom 50 0.72 0.88\n", + " scuba diver 50 0.8 1\n", + " rapeseed 50 0.94 0.98\n", + " daisy 50 0.96 0.98\n", + " yellow lady's slipper 50 1 1\n", + " corn 50 0.4 0.88\n", + " acorn 50 0.92 0.98\n", + " rose hip 50 0.92 0.98\n", + " horse chestnut seed 50 0.94 0.98\n", + " coral fungus 50 0.96 0.96\n", + " agaric 50 0.82 0.94\n", + " gyromitra 50 0.98 1\n", + " stinkhorn mushroom 50 0.8 0.94\n", + " earth star 50 0.98 1\n", + " hen-of-the-woods 50 0.8 0.96\n", + " bolete 50 0.74 0.94\n", + " ear 50 0.48 0.94\n", + " toilet paper 50 0.36 0.68\n", + "Speed: 0.1ms pre-process, 0.3ms inference, 0.0ms post-process per image at shape (1, 3, 224, 224)\n", + "Results saved to \u001b[1mruns/val-cls/exp\u001b[0m\n" + ] + } + ], + "source": [ + "# Validate YOLOv5s on Imagenet val\n", + "!python classify/val.py --weights yolov5s-cls.pt --data ../datasets/imagenet --img 224 --half" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZY2VXXXu74w5" + }, + "source": [ + "# 3. Train\n", + "\n", + "

\n", + "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", + "

\n", + "\n", + "Train a YOLOv5s Classification model on the [Imagenette](https://image-net.org/) dataset with `--data imagenet`, starting from pretrained `--pretrained yolov5s-cls.pt`.\n", + "\n", + "- **Pretrained [Models](https://github.com/ultralytics/yolov5/tree/master/models)** are downloaded\n", + "automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases)\n", + "- **Training Results** are saved to `runs/train-cls/` with incrementing run directories, i.e. `runs/train-cls/exp2`, `runs/train-cls/exp3` etc.\n", + "

\n", + "\n", + "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic.\n", + "\n", + "## Train on Custom Data with Roboflow 🌟 NEW\n", + "\n", + "[Roboflow](https://roboflow.com/?ref=ultralytics) enables you to easily **organize, label, and prepare** a high quality dataset with your own custom data. Roboflow also makes it easy to establish an active learning pipeline, collaborate with your team on dataset improvement, and integrate directly into your model building workflow with the `roboflow` pip package.\n", + "\n", + "- Custom Training Example: [https://blog.roboflow.com/train-yolov5-classification-custom-data/](https://blog.roboflow.com/train-yolov5-classification-custom-data/?ref=ultralytics)\n", + "- Custom Training Notebook: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1KZiKUAjtARHAfZCXbJRv14-pOnIsBLPV?usp=sharing)\n", + "
\n", + "\n", + "

Label images lightning fast (including with model-assisted labeling)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "i3oKtE4g-aNn" + }, + "outputs": [], + "source": [ + "#@title Select YOLOv5 🚀 logger {run: 'auto'}\n", + "logger = 'TensorBoard' #@param ['TensorBoard', 'Comet', 'ClearML']\n", + "\n", + "if logger == 'TensorBoard':\n", + " %load_ext tensorboard\n", + " %tensorboard --logdir runs/train\n", + "elif logger == 'Comet':\n", + " %pip install -q comet_ml\n", + " import comet_ml; comet_ml.init()\n", + "elif logger == 'ClearML':\n", + " import clearml; clearml.browser_login()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1NcFxRcFdJ_O", + "outputId": "77c8d487-16db-4073-b3ea-06cabf2e7766" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\u001b[34m\u001b[1mclassify/train: \u001b[0mmodel=yolov5s-cls.pt, data=imagenette160, epochs=5, batch_size=64, imgsz=224, nosave=False, cache=ram, device=, workers=8, project=runs/train-cls, name=exp, exist_ok=False, pretrained=True, optimizer=Adam, lr0=0.001, decay=5e-05, label_smoothing=0.1, cutoff=None, dropout=None, verbose=False, seed=0, local_rank=-1\n", + "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", + "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "\n", + "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train-cls', view at http://localhost:6006/\n", + "\n", + "Dataset not found ⚠️, missing path /content/datasets/imagenette160, attempting download...\n", + "Downloading https://github.com/ultralytics/yolov5/releases/download/v1.0/imagenette160.zip to /content/datasets/imagenette160.zip...\n", + "100% 103M/103M [00:00<00:00, 347MB/s] \n", + "Unzipping /content/datasets/imagenette160.zip...\n", + "Dataset download success ✅ (3.3s), saved to \u001b[1m/content/datasets/imagenette160\u001b[0m\n", + "\n", + "\u001b[34m\u001b[1malbumentations: \u001b[0mRandomResizedCrop(p=1.0, height=224, width=224, scale=(0.08, 1.0), ratio=(0.75, 1.3333333333333333), interpolation=1), HorizontalFlip(p=0.5), ColorJitter(p=0.5, brightness=[0.6, 1.4], contrast=[0.6, 1.4], saturation=[0.6, 1.4], hue=[0, 0]), Normalize(p=1.0, mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), max_pixel_value=255.0), ToTensorV2(always_apply=True, p=1.0, transpose_mask=False)\n", + "Model summary: 149 layers, 4185290 parameters, 4185290 gradients, 10.5 GFLOPs\n", + "\u001b[34m\u001b[1moptimizer:\u001b[0m Adam(lr=0.001) with parameter groups 32 weight(decay=0.0), 33 weight(decay=5e-05), 33 bias\n", + "Image sizes 224 train, 224 test\n", + "Using 1 dataloader workers\n", + "Logging results to \u001b[1mruns/train-cls/exp\u001b[0m\n", + "Starting yolov5s-cls.pt training on imagenette160 dataset with 10 classes for 5 epochs...\n", + "\n", + " Epoch GPU_mem train_loss val_loss top1_acc top5_acc\n", + " 1/5 1.47G 1.05 0.974 0.828 0.975: 100% 148/148 [00:38<00:00, 3.82it/s]\n", + " 2/5 1.73G 0.895 0.766 0.911 0.994: 100% 148/148 [00:36<00:00, 4.03it/s]\n", + " 3/5 1.73G 0.82 0.704 0.934 0.996: 100% 148/148 [00:35<00:00, 4.20it/s]\n", + " 4/5 1.73G 0.766 0.664 0.951 0.998: 100% 148/148 [00:36<00:00, 4.05it/s]\n", + " 5/5 1.73G 0.724 0.634 0.959 0.997: 100% 148/148 [00:37<00:00, 3.94it/s]\n", + "\n", + "Training complete (0.052 hours)\n", + "Results saved to \u001b[1mruns/train-cls/exp\u001b[0m\n", + "Predict: python classify/predict.py --weights runs/train-cls/exp/weights/best.pt --source im.jpg\n", + "Validate: python classify/val.py --weights runs/train-cls/exp/weights/best.pt --data /content/datasets/imagenette160\n", + "Export: python export.py --weights runs/train-cls/exp/weights/best.pt --include onnx\n", + "PyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', 'runs/train-cls/exp/weights/best.pt')\n", + "Visualize: https://netron.app\n", + "\n" + ] + } + ], + "source": [ + "# Train YOLOv5s Classification on Imagenette160 for 3 epochs\n", + "!python classify/train.py --model yolov5s-cls.pt --data imagenette160 --epochs 5 --img 224 --cache" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "15glLzbQx5u0" + }, + "source": [ + "# 4. Visualize" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nWOsI5wJR1o3" + }, + "source": [ + "## Comet Logging and Visualization 🌟 NEW\n", + "\n", + "[Comet](https://www.comet.com/site/lp/yolov5-with-comet/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab) is now fully integrated with YOLOv5. Track and visualize model metrics in real time, save your hyperparameters, datasets, and model checkpoints, and visualize your model predictions with [Comet Custom Panels](https://www.comet.com/docs/v2/guides/comet-dashboard/code-panels/about-panels/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab)! Comet makes sure you never lose track of your work and makes it easy to share results and collaborate across teams of all sizes!\n", + "\n", + "Getting started is easy:\n", + "```shell\n", + "pip install comet_ml # 1. install\n", + "export COMET_API_KEY= # 2. paste API key\n", + "python train.py --img 640 --epochs 3 --data coco128.yaml --weights yolov5s.pt # 3. train\n", + "```\n", + "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/comet). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing)\n", + "\n", + "\n", + "\"Comet" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Lay2WsTjNJzP" + }, + "source": [ + "## ClearML Logging and Automation 🌟 NEW\n", + "\n", + "[ClearML](https://cutt.ly/yolov5-notebook-clearml) is completely integrated into YOLOv5 to track your experimentation, manage dataset versions and even remotely execute training runs. To enable ClearML (check cells above):\n", + "\n", + "- `pip install clearml`\n", + "- run `clearml-init` to connect to a ClearML server (**deploy your own [open-source server](https://github.com/allegroai/clearml-server)**, or use our [free hosted server](https://cutt.ly/yolov5-notebook-clearml))\n", + "\n", + "You'll get all the great expected features from an experiment manager: live updates, model upload, experiment comparison etc. but ClearML also tracks uncommitted changes and installed packages for example. Thanks to that ClearML Tasks (which is what we call experiments) are also reproducible on different machines! With only 1 extra line, we can schedule a YOLOv5 training task on a queue to be executed by any number of ClearML Agents (workers).\n", + "\n", + "You can use ClearML Data to version your dataset and then pass it to YOLOv5 simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml) for details!\n", + "\n", + "\n", + "\"ClearML" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-WPvRbS5Swl6" + }, + "source": [ + "## Local Logging\n", + "\n", + "Training results are automatically logged with [Tensorboard](https://www.tensorflow.org/tensorboard) and [CSV](https://github.com/ultralytics/yolov5/pull/4148) loggers to `runs/train`, with a new experiment directory created for each new training as `runs/train/exp2`, `runs/train/exp3`, etc.\n", + "\n", + "This directory contains train and val statistics, mosaics, labels, predictions and augmentated mosaics, as well as metrics and charts including precision-recall (PR) curves and confusion matrices. \n", + "\n", + "\"Local\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Zelyeqbyt3GD" + }, + "source": [ + "# Environments\n", + "\n", + "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):\n", + "\n", + "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", + "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/GCP-Quickstart)\n", + "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/AWS-Quickstart)\n", + "- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/Docker-Quickstart) \"Docker\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6Qu7Iesl0p54" + }, + "source": [ + "# Status\n", + "\n", + "![YOLOv5 CI](https://github.com/ultralytics/yolov3/actions/workflows/ci-testing.yml/badge.svg)\n", + "\n", + "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/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)), testing ([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.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IEijrePND_2I" + }, + "source": [ + "# Appendix\n", + "\n", + "Additional content below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GMusP4OAxFu6" + }, + "outputs": [], + "source": [ + "# YOLOv5 PyTorch HUB Inference (DetectionModels only)\n", + "import torch\n", + "\n", + "model = torch.hub.load('ultralytics/yolov5', 'yolov5s') # yolov5n - yolov5x6 or custom\n", + "im = 'https://ultralytics.com/images/zidane.jpg' # file, Path, PIL.Image, OpenCV, nparray, list\n", + "results = model(im) # inference\n", + "results.print() # or .show(), .save(), .crop(), .pandas(), etc." + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "name": "YOLOv5 Classification Tutorial", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/classify/val.py b/classify/val.py new file mode 100644 index 0000000000..45729609aa --- /dev/null +++ b/classify/val.py @@ -0,0 +1,170 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Validate a trained YOLOv5 classification model on a classification dataset + +Usage: + $ bash data/scripts/get_imagenet.sh --val # download ImageNet val split (6.3G, 50000 images) + $ python classify/val.py --weights yolov5m-cls.pt --data ../datasets/imagenet --img 224 # validate ImageNet + +Usage - formats: + $ python classify/val.py --weights yolov5s-cls.pt # PyTorch + yolov5s-cls.torchscript # TorchScript + yolov5s-cls.onnx # ONNX Runtime or OpenCV DNN with --dnn + yolov5s-cls_openvino_model # OpenVINO + yolov5s-cls.engine # TensorRT + yolov5s-cls.mlmodel # CoreML (macOS-only) + yolov5s-cls_saved_model # TensorFlow SavedModel + yolov5s-cls.pb # TensorFlow GraphDef + yolov5s-cls.tflite # TensorFlow Lite + yolov5s-cls_edgetpu.tflite # TensorFlow Edge TPU + yolov5s-cls_paddle_model # PaddlePaddle +""" + +import argparse +import os +import sys +from pathlib import Path + +import torch +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.dataloaders import create_classification_dataloader +from utils.general import (LOGGER, TQDM_BAR_FORMAT, Profile, check_img_size, check_requirements, colorstr, + increment_path, print_args) +from utils.torch_utils import select_device, smart_inference_mode + + +@smart_inference_mode() +def run( + data=ROOT / '../datasets/mnist', # dataset dir + weights=ROOT / 'yolov5s-cls.pt', # model.pt path(s) + batch_size=128, # batch size + imgsz=224, # inference size (pixels) + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + workers=8, # max dataloader workers (per RANK in DDP mode) + verbose=False, # verbose output + project=ROOT / 'runs/val-cls', # save to project/name + name='exp', # save to project/name + exist_ok=False, # existing project/name ok, do not increment + half=False, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + model=None, + dataloader=None, + criterion=None, + pbar=None, +): + # Initialize/load model and set device + training = model is not None + if training: # called by train.py + device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model + half &= device.type != 'cpu' # half precision only supported on CUDA + model.half() if half else model.float() + else: # called directly + device = select_device(device, batch_size=batch_size) + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + save_dir.mkdir(parents=True, exist_ok=True) # make dir + + # Load model + model = DetectMultiBackend(weights, device=device, dnn=dnn, fp16=half) + stride, pt, jit, engine = model.stride, model.pt, model.jit, model.engine + imgsz = check_img_size(imgsz, s=stride) # check image size + half = model.fp16 # FP16 supported on limited backends with CUDA + if engine: + batch_size = model.batch_size + else: + device = model.device + if not (pt or jit): + batch_size = 1 # export.py models default to batch-size 1 + LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') + + # Dataloader + data = Path(data) + test_dir = data / 'test' if (data / 'test').exists() else data / 'val' # data/test or data/val + dataloader = create_classification_dataloader(path=test_dir, + imgsz=imgsz, + batch_size=batch_size, + augment=False, + rank=-1, + workers=workers) + + model.eval() + pred, targets, loss, dt = [], [], 0, (Profile(), Profile(), Profile()) + n = len(dataloader) # number of batches + action = 'validating' if dataloader.dataset.root.stem == 'val' else 'testing' + desc = f"{pbar.desc[:-36]}{action:>36}" if pbar else f"{action}" + bar = tqdm(dataloader, desc, n, not training, bar_format=TQDM_BAR_FORMAT, position=0) + with torch.cuda.amp.autocast(enabled=device.type != 'cpu'): + for images, labels in bar: + with dt[0]: + images, labels = images.to(device, non_blocking=True), labels.to(device) + + with dt[1]: + y = model(images) + + with dt[2]: + pred.append(y.argsort(1, descending=True)[:, :5]) + targets.append(labels) + if criterion: + loss += criterion(y, labels) + + loss /= n + pred, targets = torch.cat(pred), torch.cat(targets) + correct = (targets[:, None] == pred).float() + acc = torch.stack((correct[:, 0], correct.max(1).values), dim=1) # (top1, top5) accuracy + top1, top5 = acc.mean(0).tolist() + + if pbar: + pbar.desc = f"{pbar.desc[:-36]}{loss:>12.3g}{top1:>12.3g}{top5:>12.3g}" + if verbose: # all classes + LOGGER.info(f"{'Class':>24}{'Images':>12}{'top1_acc':>12}{'top5_acc':>12}") + LOGGER.info(f"{'all':>24}{targets.shape[0]:>12}{top1:>12.3g}{top5:>12.3g}") + for i, c in model.names.items(): + acc_i = acc[targets == i] + top1i, top5i = acc_i.mean(0).tolist() + LOGGER.info(f"{c:>24}{acc_i.shape[0]:>12}{top1i:>12.3g}{top5i:>12.3g}") + + # Print results + t = tuple(x.t / len(dataloader.dataset.samples) * 1E3 for x in dt) # speeds per image + shape = (1, 3, imgsz, imgsz) + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms post-process per image at shape {shape}' % t) + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}") + + return top1, top5, loss + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default=ROOT / '../datasets/mnist', help='dataset path') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s-cls.pt', help='model.pt path(s)') + parser.add_argument('--batch-size', type=int, default=128, help='batch size') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=224, help='inference size (pixels)') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--verbose', nargs='?', const=True, default=True, help='verbose output') + parser.add_argument('--project', default=ROOT / 'runs/val-cls', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + opt = parser.parse_args() + print_args(vars(opt)) + return opt + + +def main(opt): + check_requirements(exclude=('tensorboard', 'thop')) + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/data/Argoverse.yaml b/data/Argoverse.yaml index 9be3ae79a5..a3b4511eb5 100644 --- a/data/Argoverse.yaml +++ b/data/Argoverse.yaml @@ -1,10 +1,10 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license -# Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/ +# Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/ by Argo AI # Example usage: python train.py --data Argoverse.yaml # parent -# ├── yolov3 +# ├── yolov5 # └── datasets -# └── Argoverse ← downloads here +# └── Argoverse ← downloads here (31.3 GB) # 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, ..] @@ -14,8 +14,15 @@ val: Argoverse-1.1/images/val/ # val images (relative to 'path') 15062 images test: Argoverse-1.1/images/test/ # test images (optional) https://eval.ai/web/challenges/challenge-page/800/overview # Classes -nc: 8 # number of classes -names: ['person', 'bicycle', 'car', 'motorcycle', 'bus', 'truck', 'traffic_light', 'stop_sign'] # class names +names: + 0: person + 1: bicycle + 2: car + 3: motorcycle + 4: bus + 5: truck + 6: traffic_light + 7: stop_sign # Download script/URL (optional) --------------------------------------------------------------------------------------- @@ -32,7 +39,7 @@ download: | for annot in tqdm(a['annotations'], desc=f"Converting {set} to YOLOv3 format..."): img_id = annot['image_id'] img_name = a['images'][img_id]['name'] - img_label_name = img_name[:-3] + "txt" + img_label_name = f'{img_name[:-3]}txt' cls = annot['category_id'] # instance class id x_center, y_center, width, height = annot['bbox'] @@ -56,7 +63,7 @@ download: | # Download - dir = Path('../datasets/Argoverse') # dataset root dir + dir = Path(yaml['path']) # dataset root dir urls = ['https://argoverse-hd.s3.us-east-2.amazonaws.com/Argoverse-HD-Full.zip'] download(urls, dir=dir, delete=False) diff --git a/data/GlobalWheat2020.yaml b/data/GlobalWheat2020.yaml index 10a2d3fca8..9df59b84d7 100644 --- a/data/GlobalWheat2020.yaml +++ b/data/GlobalWheat2020.yaml @@ -1,10 +1,10 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license -# Global Wheat 2020 dataset http://www.global-wheat.com/ +# Global Wheat 2020 dataset http://www.global-wheat.com/ by University of Saskatchewan # Example usage: python train.py --data GlobalWheat2020.yaml # parent -# ├── yolov3 +# ├── yolov5 # └── datasets -# └── GlobalWheat2020 ← downloads here +# └── GlobalWheat2020 ← downloads here (7.0 GB) # 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, ..] @@ -26,14 +26,15 @@ test: # test images (optional) 1276 images - images/uq_1 # Classes -nc: 1 # number of classes -names: ['wheat_head'] # class names +names: + 0: wheat_head # Download script/URL (optional) --------------------------------------------------------------------------------------- download: | from utils.general import download, Path + # Download dir = Path(yaml['path']) # dataset root dir urls = ['https://zenodo.org/record/4298502/files/global-wheat-codalab-official.zip', diff --git a/data/ImageNet.yaml b/data/ImageNet.yaml new file mode 100644 index 0000000000..e0af69fe24 --- /dev/null +++ b/data/ImageNet.yaml @@ -0,0 +1,1022 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# ImageNet-1k dataset https://www.image-net.org/index.php by Stanford University +# Simplified class names from https://github.com/anishathalye/imagenet-simple-labels +# Example usage: python classify/train.py --data imagenet +# parent +# ├── yolov5 +# └── datasets +# └── imagenet ← downloads here (144 GB) + + +# 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, ..] +path: ../datasets/imagenet # dataset root dir +train: train # train images (relative to 'path') 1281167 images +val: val # val images (relative to 'path') 50000 images +test: # test images (optional) + +# Classes +names: + 0: tench + 1: goldfish + 2: great white shark + 3: tiger shark + 4: hammerhead shark + 5: electric ray + 6: stingray + 7: cock + 8: hen + 9: ostrich + 10: brambling + 11: goldfinch + 12: house finch + 13: junco + 14: indigo bunting + 15: American robin + 16: bulbul + 17: jay + 18: magpie + 19: chickadee + 20: American dipper + 21: kite + 22: bald eagle + 23: vulture + 24: great grey owl + 25: fire salamander + 26: smooth newt + 27: newt + 28: spotted salamander + 29: axolotl + 30: American bullfrog + 31: tree frog + 32: tailed frog + 33: loggerhead sea turtle + 34: leatherback sea turtle + 35: mud turtle + 36: terrapin + 37: box turtle + 38: banded gecko + 39: green iguana + 40: Carolina anole + 41: desert grassland whiptail lizard + 42: agama + 43: frilled-necked lizard + 44: alligator lizard + 45: Gila monster + 46: European green lizard + 47: chameleon + 48: Komodo dragon + 49: Nile crocodile + 50: American alligator + 51: triceratops + 52: worm snake + 53: ring-necked snake + 54: eastern hog-nosed snake + 55: smooth green snake + 56: kingsnake + 57: garter snake + 58: water snake + 59: vine snake + 60: night snake + 61: boa constrictor + 62: African rock python + 63: Indian cobra + 64: green mamba + 65: sea snake + 66: Saharan horned viper + 67: eastern diamondback rattlesnake + 68: sidewinder + 69: trilobite + 70: harvestman + 71: scorpion + 72: yellow garden spider + 73: barn spider + 74: European garden spider + 75: southern black widow + 76: tarantula + 77: wolf spider + 78: tick + 79: centipede + 80: black grouse + 81: ptarmigan + 82: ruffed grouse + 83: prairie grouse + 84: peacock + 85: quail + 86: partridge + 87: grey parrot + 88: macaw + 89: sulphur-crested cockatoo + 90: lorikeet + 91: coucal + 92: bee eater + 93: hornbill + 94: hummingbird + 95: jacamar + 96: toucan + 97: duck + 98: red-breasted merganser + 99: goose + 100: black swan + 101: tusker + 102: echidna + 103: platypus + 104: wallaby + 105: koala + 106: wombat + 107: jellyfish + 108: sea anemone + 109: brain coral + 110: flatworm + 111: nematode + 112: conch + 113: snail + 114: slug + 115: sea slug + 116: chiton + 117: chambered nautilus + 118: Dungeness crab + 119: rock crab + 120: fiddler crab + 121: red king crab + 122: American lobster + 123: spiny lobster + 124: crayfish + 125: hermit crab + 126: isopod + 127: white stork + 128: black stork + 129: spoonbill + 130: flamingo + 131: little blue heron + 132: great egret + 133: bittern + 134: crane (bird) + 135: limpkin + 136: common gallinule + 137: American coot + 138: bustard + 139: ruddy turnstone + 140: dunlin + 141: common redshank + 142: dowitcher + 143: oystercatcher + 144: pelican + 145: king penguin + 146: albatross + 147: grey whale + 148: killer whale + 149: dugong + 150: sea lion + 151: Chihuahua + 152: Japanese Chin + 153: Maltese + 154: Pekingese + 155: Shih Tzu + 156: King Charles Spaniel + 157: Papillon + 158: toy terrier + 159: Rhodesian Ridgeback + 160: Afghan Hound + 161: Basset Hound + 162: Beagle + 163: Bloodhound + 164: Bluetick Coonhound + 165: Black and Tan Coonhound + 166: Treeing Walker Coonhound + 167: English foxhound + 168: Redbone Coonhound + 169: borzoi + 170: Irish Wolfhound + 171: Italian Greyhound + 172: Whippet + 173: Ibizan Hound + 174: Norwegian Elkhound + 175: Otterhound + 176: Saluki + 177: Scottish Deerhound + 178: Weimaraner + 179: Staffordshire Bull Terrier + 180: American Staffordshire Terrier + 181: Bedlington Terrier + 182: Border Terrier + 183: Kerry Blue Terrier + 184: Irish Terrier + 185: Norfolk Terrier + 186: Norwich Terrier + 187: Yorkshire Terrier + 188: Wire Fox Terrier + 189: Lakeland Terrier + 190: Sealyham Terrier + 191: Airedale Terrier + 192: Cairn Terrier + 193: Australian Terrier + 194: Dandie Dinmont Terrier + 195: Boston Terrier + 196: Miniature Schnauzer + 197: Giant Schnauzer + 198: Standard Schnauzer + 199: Scottish Terrier + 200: Tibetan Terrier + 201: Australian Silky Terrier + 202: Soft-coated Wheaten Terrier + 203: West Highland White Terrier + 204: Lhasa Apso + 205: Flat-Coated Retriever + 206: Curly-coated Retriever + 207: Golden Retriever + 208: Labrador Retriever + 209: Chesapeake Bay Retriever + 210: German Shorthaired Pointer + 211: Vizsla + 212: English Setter + 213: Irish Setter + 214: Gordon Setter + 215: Brittany + 216: Clumber Spaniel + 217: English Springer Spaniel + 218: Welsh Springer Spaniel + 219: Cocker Spaniels + 220: Sussex Spaniel + 221: Irish Water Spaniel + 222: Kuvasz + 223: Schipperke + 224: Groenendael + 225: Malinois + 226: Briard + 227: Australian Kelpie + 228: Komondor + 229: Old English Sheepdog + 230: Shetland Sheepdog + 231: collie + 232: Border Collie + 233: Bouvier des Flandres + 234: Rottweiler + 235: German Shepherd Dog + 236: Dobermann + 237: Miniature Pinscher + 238: Greater Swiss Mountain Dog + 239: Bernese Mountain Dog + 240: Appenzeller Sennenhund + 241: Entlebucher Sennenhund + 242: Boxer + 243: Bullmastiff + 244: Tibetan Mastiff + 245: French Bulldog + 246: Great Dane + 247: St. Bernard + 248: husky + 249: Alaskan Malamute + 250: Siberian Husky + 251: Dalmatian + 252: Affenpinscher + 253: Basenji + 254: pug + 255: Leonberger + 256: Newfoundland + 257: Pyrenean Mountain Dog + 258: Samoyed + 259: Pomeranian + 260: Chow Chow + 261: Keeshond + 262: Griffon Bruxellois + 263: Pembroke Welsh Corgi + 264: Cardigan Welsh Corgi + 265: Toy Poodle + 266: Miniature Poodle + 267: Standard Poodle + 268: Mexican hairless dog + 269: grey wolf + 270: Alaskan tundra wolf + 271: red wolf + 272: coyote + 273: dingo + 274: dhole + 275: African wild dog + 276: hyena + 277: red fox + 278: kit fox + 279: Arctic fox + 280: grey fox + 281: tabby cat + 282: tiger cat + 283: Persian cat + 284: Siamese cat + 285: Egyptian Mau + 286: cougar + 287: lynx + 288: leopard + 289: snow leopard + 290: jaguar + 291: lion + 292: tiger + 293: cheetah + 294: brown bear + 295: American black bear + 296: polar bear + 297: sloth bear + 298: mongoose + 299: meerkat + 300: tiger beetle + 301: ladybug + 302: ground beetle + 303: longhorn beetle + 304: leaf beetle + 305: dung beetle + 306: rhinoceros beetle + 307: weevil + 308: fly + 309: bee + 310: ant + 311: grasshopper + 312: cricket + 313: stick insect + 314: cockroach + 315: mantis + 316: cicada + 317: leafhopper + 318: lacewing + 319: dragonfly + 320: damselfly + 321: red admiral + 322: ringlet + 323: monarch butterfly + 324: small white + 325: sulphur butterfly + 326: gossamer-winged butterfly + 327: starfish + 328: sea urchin + 329: sea cucumber + 330: cottontail rabbit + 331: hare + 332: Angora rabbit + 333: hamster + 334: porcupine + 335: fox squirrel + 336: marmot + 337: beaver + 338: guinea pig + 339: common sorrel + 340: zebra + 341: pig + 342: wild boar + 343: warthog + 344: hippopotamus + 345: ox + 346: water buffalo + 347: bison + 348: ram + 349: bighorn sheep + 350: Alpine ibex + 351: hartebeest + 352: impala + 353: gazelle + 354: dromedary + 355: llama + 356: weasel + 357: mink + 358: European polecat + 359: black-footed ferret + 360: otter + 361: skunk + 362: badger + 363: armadillo + 364: three-toed sloth + 365: orangutan + 366: gorilla + 367: chimpanzee + 368: gibbon + 369: siamang + 370: guenon + 371: patas monkey + 372: baboon + 373: macaque + 374: langur + 375: black-and-white colobus + 376: proboscis monkey + 377: marmoset + 378: white-headed capuchin + 379: howler monkey + 380: titi + 381: Geoffroy's spider monkey + 382: common squirrel monkey + 383: ring-tailed lemur + 384: indri + 385: Asian elephant + 386: African bush elephant + 387: red panda + 388: giant panda + 389: snoek + 390: eel + 391: coho salmon + 392: rock beauty + 393: clownfish + 394: sturgeon + 395: garfish + 396: lionfish + 397: pufferfish + 398: abacus + 399: abaya + 400: academic gown + 401: accordion + 402: acoustic guitar + 403: aircraft carrier + 404: airliner + 405: airship + 406: altar + 407: ambulance + 408: amphibious vehicle + 409: analog clock + 410: apiary + 411: apron + 412: waste container + 413: assault rifle + 414: backpack + 415: bakery + 416: balance beam + 417: balloon + 418: ballpoint pen + 419: Band-Aid + 420: banjo + 421: baluster + 422: barbell + 423: barber chair + 424: barbershop + 425: barn + 426: barometer + 427: barrel + 428: wheelbarrow + 429: baseball + 430: basketball + 431: bassinet + 432: bassoon + 433: swimming cap + 434: bath towel + 435: bathtub + 436: station wagon + 437: lighthouse + 438: beaker + 439: military cap + 440: beer bottle + 441: beer glass + 442: bell-cot + 443: bib + 444: tandem bicycle + 445: bikini + 446: ring binder + 447: binoculars + 448: birdhouse + 449: boathouse + 450: bobsleigh + 451: bolo tie + 452: poke bonnet + 453: bookcase + 454: bookstore + 455: bottle cap + 456: bow + 457: bow tie + 458: brass + 459: bra + 460: breakwater + 461: breastplate + 462: broom + 463: bucket + 464: buckle + 465: bulletproof vest + 466: high-speed train + 467: butcher shop + 468: taxicab + 469: cauldron + 470: candle + 471: cannon + 472: canoe + 473: can opener + 474: cardigan + 475: car mirror + 476: carousel + 477: tool kit + 478: carton + 479: car wheel + 480: automated teller machine + 481: cassette + 482: cassette player + 483: castle + 484: catamaran + 485: CD player + 486: cello + 487: mobile phone + 488: chain + 489: chain-link fence + 490: chain mail + 491: chainsaw + 492: chest + 493: chiffonier + 494: chime + 495: china cabinet + 496: Christmas stocking + 497: church + 498: movie theater + 499: cleaver + 500: cliff dwelling + 501: cloak + 502: clogs + 503: cocktail shaker + 504: coffee mug + 505: coffeemaker + 506: coil + 507: combination lock + 508: computer keyboard + 509: confectionery store + 510: container ship + 511: convertible + 512: corkscrew + 513: cornet + 514: cowboy boot + 515: cowboy hat + 516: cradle + 517: crane (machine) + 518: crash helmet + 519: crate + 520: infant bed + 521: Crock Pot + 522: croquet ball + 523: crutch + 524: cuirass + 525: dam + 526: desk + 527: desktop computer + 528: rotary dial telephone + 529: diaper + 530: digital clock + 531: digital watch + 532: dining table + 533: dishcloth + 534: dishwasher + 535: disc brake + 536: dock + 537: dog sled + 538: dome + 539: doormat + 540: drilling rig + 541: drum + 542: drumstick + 543: dumbbell + 544: Dutch oven + 545: electric fan + 546: electric guitar + 547: electric locomotive + 548: entertainment center + 549: envelope + 550: espresso machine + 551: face powder + 552: feather boa + 553: filing cabinet + 554: fireboat + 555: fire engine + 556: fire screen sheet + 557: flagpole + 558: flute + 559: folding chair + 560: football helmet + 561: forklift + 562: fountain + 563: fountain pen + 564: four-poster bed + 565: freight car + 566: French horn + 567: frying pan + 568: fur coat + 569: garbage truck + 570: gas mask + 571: gas pump + 572: goblet + 573: go-kart + 574: golf ball + 575: golf cart + 576: gondola + 577: gong + 578: gown + 579: grand piano + 580: greenhouse + 581: grille + 582: grocery store + 583: guillotine + 584: barrette + 585: hair spray + 586: half-track + 587: hammer + 588: hamper + 589: hair dryer + 590: hand-held computer + 591: handkerchief + 592: hard disk drive + 593: harmonica + 594: harp + 595: harvester + 596: hatchet + 597: holster + 598: home theater + 599: honeycomb + 600: hook + 601: hoop skirt + 602: horizontal bar + 603: horse-drawn vehicle + 604: hourglass + 605: iPod + 606: clothes iron + 607: jack-o'-lantern + 608: jeans + 609: jeep + 610: T-shirt + 611: jigsaw puzzle + 612: pulled rickshaw + 613: joystick + 614: kimono + 615: knee pad + 616: knot + 617: lab coat + 618: ladle + 619: lampshade + 620: laptop computer + 621: lawn mower + 622: lens cap + 623: paper knife + 624: library + 625: lifeboat + 626: lighter + 627: limousine + 628: ocean liner + 629: lipstick + 630: slip-on shoe + 631: lotion + 632: speaker + 633: loupe + 634: sawmill + 635: magnetic compass + 636: mail bag + 637: mailbox + 638: tights + 639: tank suit + 640: manhole cover + 641: maraca + 642: marimba + 643: mask + 644: match + 645: maypole + 646: maze + 647: measuring cup + 648: medicine chest + 649: megalith + 650: microphone + 651: microwave oven + 652: military uniform + 653: milk can + 654: minibus + 655: miniskirt + 656: minivan + 657: missile + 658: mitten + 659: mixing bowl + 660: mobile home + 661: Model T + 662: modem + 663: monastery + 664: monitor + 665: moped + 666: mortar + 667: square academic cap + 668: mosque + 669: mosquito net + 670: scooter + 671: mountain bike + 672: tent + 673: computer mouse + 674: mousetrap + 675: moving van + 676: muzzle + 677: nail + 678: neck brace + 679: necklace + 680: nipple + 681: notebook computer + 682: obelisk + 683: oboe + 684: ocarina + 685: odometer + 686: oil filter + 687: organ + 688: oscilloscope + 689: overskirt + 690: bullock cart + 691: oxygen mask + 692: packet + 693: paddle + 694: paddle wheel + 695: padlock + 696: paintbrush + 697: pajamas + 698: palace + 699: pan flute + 700: paper towel + 701: parachute + 702: parallel bars + 703: park bench + 704: parking meter + 705: passenger car + 706: patio + 707: payphone + 708: pedestal + 709: pencil case + 710: pencil sharpener + 711: perfume + 712: Petri dish + 713: photocopier + 714: plectrum + 715: Pickelhaube + 716: picket fence + 717: pickup truck + 718: pier + 719: piggy bank + 720: pill bottle + 721: pillow + 722: ping-pong ball + 723: pinwheel + 724: pirate ship + 725: pitcher + 726: hand plane + 727: planetarium + 728: plastic bag + 729: plate rack + 730: plow + 731: plunger + 732: Polaroid camera + 733: pole + 734: police van + 735: poncho + 736: billiard table + 737: soda bottle + 738: pot + 739: potter's wheel + 740: power drill + 741: prayer rug + 742: printer + 743: prison + 744: projectile + 745: projector + 746: hockey puck + 747: punching bag + 748: purse + 749: quill + 750: quilt + 751: race car + 752: racket + 753: radiator + 754: radio + 755: radio telescope + 756: rain barrel + 757: recreational vehicle + 758: reel + 759: reflex camera + 760: refrigerator + 761: remote control + 762: restaurant + 763: revolver + 764: rifle + 765: rocking chair + 766: rotisserie + 767: eraser + 768: rugby ball + 769: ruler + 770: running shoe + 771: safe + 772: safety pin + 773: salt shaker + 774: sandal + 775: sarong + 776: saxophone + 777: scabbard + 778: weighing scale + 779: school bus + 780: schooner + 781: scoreboard + 782: CRT screen + 783: screw + 784: screwdriver + 785: seat belt + 786: sewing machine + 787: shield + 788: shoe store + 789: shoji + 790: shopping basket + 791: shopping cart + 792: shovel + 793: shower cap + 794: shower curtain + 795: ski + 796: ski mask + 797: sleeping bag + 798: slide rule + 799: sliding door + 800: slot machine + 801: snorkel + 802: snowmobile + 803: snowplow + 804: soap dispenser + 805: soccer ball + 806: sock + 807: solar thermal collector + 808: sombrero + 809: soup bowl + 810: space bar + 811: space heater + 812: space shuttle + 813: spatula + 814: motorboat + 815: spider web + 816: spindle + 817: sports car + 818: spotlight + 819: stage + 820: steam locomotive + 821: through arch bridge + 822: steel drum + 823: stethoscope + 824: scarf + 825: stone wall + 826: stopwatch + 827: stove + 828: strainer + 829: tram + 830: stretcher + 831: couch + 832: stupa + 833: submarine + 834: suit + 835: sundial + 836: sunglass + 837: sunglasses + 838: sunscreen + 839: suspension bridge + 840: mop + 841: sweatshirt + 842: swimsuit + 843: swing + 844: switch + 845: syringe + 846: table lamp + 847: tank + 848: tape player + 849: teapot + 850: teddy bear + 851: television + 852: tennis ball + 853: thatched roof + 854: front curtain + 855: thimble + 856: threshing machine + 857: throne + 858: tile roof + 859: toaster + 860: tobacco shop + 861: toilet seat + 862: torch + 863: totem pole + 864: tow truck + 865: toy store + 866: tractor + 867: semi-trailer truck + 868: tray + 869: trench coat + 870: tricycle + 871: trimaran + 872: tripod + 873: triumphal arch + 874: trolleybus + 875: trombone + 876: tub + 877: turnstile + 878: typewriter keyboard + 879: umbrella + 880: unicycle + 881: upright piano + 882: vacuum cleaner + 883: vase + 884: vault + 885: velvet + 886: vending machine + 887: vestment + 888: viaduct + 889: violin + 890: volleyball + 891: waffle iron + 892: wall clock + 893: wallet + 894: wardrobe + 895: military aircraft + 896: sink + 897: washing machine + 898: water bottle + 899: water jug + 900: water tower + 901: whiskey jug + 902: whistle + 903: wig + 904: window screen + 905: window shade + 906: Windsor tie + 907: wine bottle + 908: wing + 909: wok + 910: wooden spoon + 911: wool + 912: split-rail fence + 913: shipwreck + 914: yawl + 915: yurt + 916: website + 917: comic book + 918: crossword + 919: traffic sign + 920: traffic light + 921: dust jacket + 922: menu + 923: plate + 924: guacamole + 925: consomme + 926: hot pot + 927: trifle + 928: ice cream + 929: ice pop + 930: baguette + 931: bagel + 932: pretzel + 933: cheeseburger + 934: hot dog + 935: mashed potato + 936: cabbage + 937: broccoli + 938: cauliflower + 939: zucchini + 940: spaghetti squash + 941: acorn squash + 942: butternut squash + 943: cucumber + 944: artichoke + 945: bell pepper + 946: cardoon + 947: mushroom + 948: Granny Smith + 949: strawberry + 950: orange + 951: lemon + 952: fig + 953: pineapple + 954: banana + 955: jackfruit + 956: custard apple + 957: pomegranate + 958: hay + 959: carbonara + 960: chocolate syrup + 961: dough + 962: meatloaf + 963: pizza + 964: pot pie + 965: burrito + 966: red wine + 967: espresso + 968: cup + 969: eggnog + 970: alp + 971: bubble + 972: cliff + 973: coral reef + 974: geyser + 975: lakeshore + 976: promontory + 977: shoal + 978: seashore + 979: valley + 980: volcano + 981: baseball player + 982: bridegroom + 983: scuba diver + 984: rapeseed + 985: daisy + 986: yellow lady's slipper + 987: corn + 988: acorn + 989: rose hip + 990: horse chestnut seed + 991: coral fungus + 992: agaric + 993: gyromitra + 994: stinkhorn mushroom + 995: earth star + 996: hen-of-the-woods + 997: bolete + 998: ear + 999: toilet paper + + +# Download script/URL (optional) +download: data/scripts/get_imagenet.sh diff --git a/data/SKU-110K.yaml b/data/SKU-110K.yaml index 183d3637b4..9ebbb555a0 100644 --- a/data/SKU-110K.yaml +++ b/data/SKU-110K.yaml @@ -1,10 +1,10 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license -# SKU-110K retail items dataset https://github.com/eg4000/SKU110K_CVPR19 +# SKU-110K retail items dataset https://github.com/eg4000/SKU110K_CVPR19 by Trax Retail # Example usage: python train.py --data SKU-110K.yaml # parent -# ├── yolov3 +# ├── yolov5 # └── datasets -# └── SKU-110K ← downloads here +# └── SKU-110K ← downloads here (13.6 GB) # 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, ..] @@ -14,8 +14,8 @@ val: val.txt # val images (relative to 'path') 588 images test: test.txt # test images (optional) 2936 images # Classes -nc: 1 # number of classes -names: ['object'] # class names +names: + 0: object # Download script/URL (optional) --------------------------------------------------------------------------------------- @@ -24,6 +24,7 @@ download: | from tqdm import tqdm from utils.general import np, pd, Path, download, xyxy2xywh + # Download dir = Path(yaml['path']) # dataset root dir parent = Path(dir.parent) # download dir diff --git a/data/VisDrone.yaml b/data/VisDrone.yaml index 945f05b40f..fae733bba2 100644 --- a/data/VisDrone.yaml +++ b/data/VisDrone.yaml @@ -1,10 +1,10 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license -# VisDrone2019-DET dataset https://github.com/VisDrone/VisDrone-Dataset +# VisDrone2019-DET dataset https://github.com/VisDrone/VisDrone-Dataset by Tianjin University # Example usage: python train.py --data VisDrone.yaml # parent -# ├── yolov3 +# ├── yolov5 # └── datasets -# └── VisDrone ← downloads here +# └── VisDrone ← downloads here (2.3 GB) # 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, ..] @@ -14,8 +14,17 @@ val: VisDrone2019-DET-val/images # val images (relative to 'path') 548 images test: VisDrone2019-DET-test-dev/images # test images (optional) 1610 images # Classes -nc: 10 # number of classes -names: ['pedestrian', 'people', 'bicycle', 'car', 'van', 'truck', 'tricycle', 'awning-tricycle', 'bus', 'motor'] +names: + 0: pedestrian + 1: people + 2: bicycle + 3: car + 4: van + 5: truck + 6: tricycle + 7: awning-tricycle + 8: bus + 9: motor # Download script/URL (optional) --------------------------------------------------------------------------------------- @@ -54,7 +63,7 @@ download: | 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-val.zip', 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-test-dev.zip', 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-test-challenge.zip'] - download(urls, dir=dir) + download(urls, dir=dir, curl=True, threads=4) # Convert for d in 'VisDrone2019-DET-train', 'VisDrone2019-DET-val', 'VisDrone2019-DET-test-dev': diff --git a/data/coco.yaml b/data/coco.yaml index 1d89a3a033..8dd3c7c825 100644 --- a/data/coco.yaml +++ b/data/coco.yaml @@ -1,35 +1,107 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license -# COCO 2017 dataset http://cocodataset.org +# COCO 2017 dataset http://cocodataset.org by Microsoft # Example usage: python train.py --data coco.yaml # parent -# ├── yolov3 +# ├── yolov5 # └── datasets -# └── coco ← downloads here +# └── coco ← downloads here (20.1 GB) # 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, ..] path: ../datasets/coco # dataset root dir train: train2017.txt # train images (relative to 'path') 118287 images -val: val2017.txt # train images (relative to 'path') 5000 images +val: val2017.txt # val images (relative to 'path') 5000 images test: test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794 # Classes -nc: 80 # number of classes -names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', - 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', - 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', - 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', - 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', - 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', - 'hair drier', 'toothbrush'] # class names +names: + 0: person + 1: bicycle + 2: car + 3: motorcycle + 4: airplane + 5: bus + 6: train + 7: truck + 8: boat + 9: traffic light + 10: fire hydrant + 11: stop sign + 12: parking meter + 13: bench + 14: bird + 15: cat + 16: dog + 17: horse + 18: sheep + 19: cow + 20: elephant + 21: bear + 22: zebra + 23: giraffe + 24: backpack + 25: umbrella + 26: handbag + 27: tie + 28: suitcase + 29: frisbee + 30: skis + 31: snowboard + 32: sports ball + 33: kite + 34: baseball bat + 35: baseball glove + 36: skateboard + 37: surfboard + 38: tennis racket + 39: bottle + 40: wine glass + 41: cup + 42: fork + 43: knife + 44: spoon + 45: bowl + 46: banana + 47: apple + 48: sandwich + 49: orange + 50: broccoli + 51: carrot + 52: hot dog + 53: pizza + 54: donut + 55: cake + 56: chair + 57: couch + 58: potted plant + 59: bed + 60: dining table + 61: toilet + 62: tv + 63: laptop + 64: mouse + 65: remote + 66: keyboard + 67: cell phone + 68: microwave + 69: oven + 70: toaster + 71: sink + 72: refrigerator + 73: book + 74: clock + 75: vase + 76: scissors + 77: teddy bear + 78: hair drier + 79: toothbrush # Download script/URL (optional) download: | from utils.general import download, Path + # Download labels segments = False # segment or box labels dir = Path(yaml['path']) # dataset root dir diff --git a/data/coco128-seg.yaml b/data/coco128-seg.yaml new file mode 100644 index 0000000000..6a45758eb9 --- /dev/null +++ b/data/coco128-seg.yaml @@ -0,0 +1,101 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# COCO128-seg dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics +# Example usage: python train.py --data coco128.yaml +# parent +# ├── yolov5 +# └── datasets +# └── coco128-seg ← downloads here (7 MB) + + +# 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, ..] +path: ../datasets/coco128-seg # dataset root dir +train: images/train2017 # train images (relative to 'path') 128 images +val: images/train2017 # val images (relative to 'path') 128 images +test: # test images (optional) + +# Classes +names: + 0: person + 1: bicycle + 2: car + 3: motorcycle + 4: airplane + 5: bus + 6: train + 7: truck + 8: boat + 9: traffic light + 10: fire hydrant + 11: stop sign + 12: parking meter + 13: bench + 14: bird + 15: cat + 16: dog + 17: horse + 18: sheep + 19: cow + 20: elephant + 21: bear + 22: zebra + 23: giraffe + 24: backpack + 25: umbrella + 26: handbag + 27: tie + 28: suitcase + 29: frisbee + 30: skis + 31: snowboard + 32: sports ball + 33: kite + 34: baseball bat + 35: baseball glove + 36: skateboard + 37: surfboard + 38: tennis racket + 39: bottle + 40: wine glass + 41: cup + 42: fork + 43: knife + 44: spoon + 45: bowl + 46: banana + 47: apple + 48: sandwich + 49: orange + 50: broccoli + 51: carrot + 52: hot dog + 53: pizza + 54: donut + 55: cake + 56: chair + 57: couch + 58: potted plant + 59: bed + 60: dining table + 61: toilet + 62: tv + 63: laptop + 64: mouse + 65: remote + 66: keyboard + 67: cell phone + 68: microwave + 69: oven + 70: toaster + 71: sink + 72: refrigerator + 73: book + 74: clock + 75: vase + 76: scissors + 77: teddy bear + 78: hair drier + 79: toothbrush + + +# Download script/URL (optional) +download: https://ultralytics.com/assets/coco128-seg.zip diff --git a/data/coco128.yaml b/data/coco128.yaml index 19e8d8001e..6cb076acdd 100644 --- a/data/coco128.yaml +++ b/data/coco128.yaml @@ -1,10 +1,10 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license -# COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) +# COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics # Example usage: python train.py --data coco128.yaml # parent -# ├── yolov3 +# ├── yolov5 # └── datasets -# └── coco128 ← downloads here +# └── coco128 ← downloads here (7 MB) # 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, ..] @@ -14,16 +14,87 @@ val: images/train2017 # val images (relative to 'path') 128 images test: # test images (optional) # Classes -nc: 80 # number of classes -names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', - 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', - 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', - 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', - 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', - 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', - 'hair drier', 'toothbrush'] # class names +names: + 0: person + 1: bicycle + 2: car + 3: motorcycle + 4: airplane + 5: bus + 6: train + 7: truck + 8: boat + 9: traffic light + 10: fire hydrant + 11: stop sign + 12: parking meter + 13: bench + 14: bird + 15: cat + 16: dog + 17: horse + 18: sheep + 19: cow + 20: elephant + 21: bear + 22: zebra + 23: giraffe + 24: backpack + 25: umbrella + 26: handbag + 27: tie + 28: suitcase + 29: frisbee + 30: skis + 31: snowboard + 32: sports ball + 33: kite + 34: baseball bat + 35: baseball glove + 36: skateboard + 37: surfboard + 38: tennis racket + 39: bottle + 40: wine glass + 41: cup + 42: fork + 43: knife + 44: spoon + 45: bowl + 46: banana + 47: apple + 48: sandwich + 49: orange + 50: broccoli + 51: carrot + 52: hot dog + 53: pizza + 54: donut + 55: cake + 56: chair + 57: couch + 58: potted plant + 59: bed + 60: dining table + 61: toilet + 62: tv + 63: laptop + 64: mouse + 65: remote + 66: keyboard + 67: cell phone + 68: microwave + 69: oven + 70: toaster + 71: sink + 72: refrigerator + 73: book + 74: clock + 75: vase + 76: scissors + 77: teddy bear + 78: hair drier + 79: toothbrush # Download script/URL (optional) diff --git a/data/hyps/hyp.Objects365.yaml b/data/hyps/hyp.Objects365.yaml new file mode 100644 index 0000000000..e3bc19bbc8 --- /dev/null +++ b/data/hyps/hyp.Objects365.yaml @@ -0,0 +1,34 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# Hyperparameters for Objects365 training +# python train.py --weights yolov5m.pt --data Objects365.yaml --evolve +# See Hyperparameter Evolution tutorial for details https://github.com/ultralytics/yolov5#tutorials + +lr0: 0.00258 +lrf: 0.17 +momentum: 0.779 +weight_decay: 0.00058 +warmup_epochs: 1.33 +warmup_momentum: 0.86 +warmup_bias_lr: 0.0711 +box: 0.0539 +cls: 0.299 +cls_pw: 0.825 +obj: 0.632 +obj_pw: 1.0 +iou_t: 0.2 +anchor_t: 3.44 +anchors: 3.2 +fl_gamma: 0.0 +hsv_h: 0.0188 +hsv_s: 0.704 +hsv_v: 0.36 +degrees: 0.0 +translate: 0.0902 +scale: 0.491 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +mosaic: 1.0 +mixup: 0.0 +copy_paste: 0.0 diff --git a/data/hyps/hyp.VOC.yaml b/data/hyps/hyp.VOC.yaml new file mode 100644 index 0000000000..34cf8d1e63 --- /dev/null +++ b/data/hyps/hyp.VOC.yaml @@ -0,0 +1,40 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# Hyperparameters for VOC training +# python train.py --batch 128 --weights yolov5m6.pt --data VOC.yaml --epochs 50 --img 512 --hyp hyp.scratch-med.yaml --evolve +# See Hyperparameter Evolution tutorial for details https://github.com/ultralytics/yolov5#tutorials + +# YOLOv5 Hyperparameter Evolution Results +# Best generation: 467 +# Last generation: 996 +# metrics/precision, metrics/recall, metrics/mAP_0.5, metrics/mAP_0.5:0.95, val/box_loss, val/obj_loss, val/cls_loss +# 0.87729, 0.85125, 0.91286, 0.72664, 0.0076739, 0.0042529, 0.0013865 + +lr0: 0.00334 +lrf: 0.15135 +momentum: 0.74832 +weight_decay: 0.00025 +warmup_epochs: 3.3835 +warmup_momentum: 0.59462 +warmup_bias_lr: 0.18657 +box: 0.02 +cls: 0.21638 +cls_pw: 0.5 +obj: 0.51728 +obj_pw: 0.67198 +iou_t: 0.2 +anchor_t: 3.3744 +fl_gamma: 0.0 +hsv_h: 0.01041 +hsv_s: 0.54703 +hsv_v: 0.27739 +degrees: 0.0 +translate: 0.04591 +scale: 0.75544 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.5 +mosaic: 0.85834 +mixup: 0.04266 +copy_paste: 0.0 +anchors: 3.412 diff --git a/data/hyps/hyp.scratch.yaml b/data/hyps/hyp.no-augmentation.yaml similarity index 54% rename from data/hyps/hyp.scratch.yaml rename to data/hyps/hyp.no-augmentation.yaml index 31f6d142e2..50ee43e699 100644 --- a/data/hyps/hyp.scratch.yaml +++ b/data/hyps/hyp.no-augmentation.yaml @@ -1,7 +1,7 @@ -# YOLOv5 🚀 by Ultralytics, GPL-3.0 license -# Hyperparameters for COCO training from scratch -# python train.py --batch 40 --cfg yolov5m.yaml --weights '' --data coco.yaml --img 640 --epochs 300 -# See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# Hyperparameters when using Albumentations frameworks +# python train.py --hyp hyp.no-augmentation.yaml +# See https://github.com/ultralytics/yolov5/pull/3882 for YOLOv5 + Albumentations Usage examples lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) @@ -11,24 +11,25 @@ warmup_epochs: 3.0 # warmup epochs (fractions ok) warmup_momentum: 0.8 # warmup initial momentum warmup_bias_lr: 0.1 # warmup initial bias lr box: 0.05 # box loss gain -cls: 0.5 # cls loss gain +cls: 0.3 # cls loss gain cls_pw: 1.0 # cls BCELoss positive_weight -obj: 1.0 # obj loss gain (scale with pixels) +obj: 0.7 # obj loss gain (scale with pixels) obj_pw: 1.0 # obj BCELoss positive_weight iou_t: 0.20 # IoU training threshold anchor_t: 4.0 # anchor-multiple threshold # anchors: 3 # anchors per output layer (0 to ignore) +# this parameters are all zero since we want to use albumentation framework fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) -hsv_h: 0.015 # image HSV-Hue augmentation (fraction) -hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) -hsv_v: 0.4 # image HSV-Value augmentation (fraction) +hsv_h: 0 # image HSV-Hue augmentation (fraction) +hsv_s: 00 # image HSV-Saturation augmentation (fraction) +hsv_v: 0 # image HSV-Value augmentation (fraction) degrees: 0.0 # image rotation (+/- deg) -translate: 0.1 # image translation (+/- fraction) -scale: 0.5 # image scale (+/- gain) -shear: 0.0 # image shear (+/- deg) +translate: 0 # image translation (+/- fraction) +scale: 0 # image scale (+/- gain) +shear: 0 # image shear (+/- deg) perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 flipud: 0.0 # image flip up-down (probability) -fliplr: 0.5 # image flip left-right (probability) -mosaic: 1.0 # image mosaic (probability) +fliplr: 0.0 # image flip left-right (probability) +mosaic: 0.0 # image mosaic (probability) mixup: 0.0 # image mixup (probability) copy_paste: 0.0 # segment copy-paste (probability) diff --git a/data/hyps/hyp.scratch-high.yaml b/data/hyps/hyp.scratch-high.yaml index 07ad9fc295..05cd35cb02 100644 --- a/data/hyps/hyp.scratch-high.yaml +++ b/data/hyps/hyp.scratch-high.yaml @@ -4,7 +4,7 @@ # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) -lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf) +lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) momentum: 0.937 # SGD momentum/Adam beta1 weight_decay: 0.0005 # optimizer weight decay 5e-4 warmup_epochs: 3.0 # warmup epochs (fractions ok) diff --git a/data/objects365.yaml b/data/objects365.yaml index 3472f0f6b9..353635a3c6 100644 --- a/data/objects365.yaml +++ b/data/objects365.yaml @@ -1,10 +1,10 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license -# Objects365 dataset https://www.objects365.org/ +# Objects365 dataset https://www.objects365.org/ by Megvii # Example usage: python train.py --data Objects365.yaml # parent -# ├── yolov3 +# ├── yolov5 # └── datasets -# └── Objects365 ← downloads here +# └── Objects365 ← downloads here (712 GB = 367G data + 345G zips) # 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, ..] @@ -14,56 +14,382 @@ val: images/val # val images (relative to 'path') 80000 images test: # test images (optional) # Classes -nc: 365 # number of classes -names: ['Person', 'Sneakers', 'Chair', 'Other Shoes', 'Hat', 'Car', 'Lamp', 'Glasses', 'Bottle', 'Desk', 'Cup', - 'Street Lights', 'Cabinet/shelf', 'Handbag/Satchel', 'Bracelet', 'Plate', 'Picture/Frame', 'Helmet', 'Book', - 'Gloves', 'Storage box', 'Boat', 'Leather Shoes', 'Flower', 'Bench', 'Potted Plant', 'Bowl/Basin', 'Flag', - 'Pillow', 'Boots', 'Vase', 'Microphone', 'Necklace', 'Ring', 'SUV', 'Wine Glass', 'Belt', 'Monitor/TV', - 'Backpack', 'Umbrella', 'Traffic Light', 'Speaker', 'Watch', 'Tie', 'Trash bin Can', 'Slippers', 'Bicycle', - 'Stool', 'Barrel/bucket', 'Van', 'Couch', 'Sandals', 'Basket', 'Drum', 'Pen/Pencil', 'Bus', 'Wild Bird', - 'High Heels', 'Motorcycle', 'Guitar', 'Carpet', 'Cell Phone', 'Bread', 'Camera', 'Canned', 'Truck', - 'Traffic cone', 'Cymbal', 'Lifesaver', 'Towel', 'Stuffed Toy', 'Candle', 'Sailboat', 'Laptop', 'Awning', - 'Bed', 'Faucet', 'Tent', 'Horse', 'Mirror', 'Power outlet', 'Sink', 'Apple', 'Air Conditioner', 'Knife', - 'Hockey Stick', 'Paddle', 'Pickup Truck', 'Fork', 'Traffic Sign', 'Balloon', 'Tripod', 'Dog', 'Spoon', 'Clock', - 'Pot', 'Cow', 'Cake', 'Dinning Table', 'Sheep', 'Hanger', 'Blackboard/Whiteboard', 'Napkin', 'Other Fish', - 'Orange/Tangerine', 'Toiletry', 'Keyboard', 'Tomato', 'Lantern', 'Machinery Vehicle', 'Fan', - 'Green Vegetables', 'Banana', 'Baseball Glove', 'Airplane', 'Mouse', 'Train', 'Pumpkin', 'Soccer', 'Skiboard', - 'Luggage', 'Nightstand', 'Tea pot', 'Telephone', 'Trolley', 'Head Phone', 'Sports Car', 'Stop Sign', - 'Dessert', 'Scooter', 'Stroller', 'Crane', 'Remote', 'Refrigerator', 'Oven', 'Lemon', 'Duck', 'Baseball Bat', - 'Surveillance Camera', 'Cat', 'Jug', 'Broccoli', 'Piano', 'Pizza', 'Elephant', 'Skateboard', 'Surfboard', - 'Gun', 'Skating and Skiing shoes', 'Gas stove', 'Donut', 'Bow Tie', 'Carrot', 'Toilet', 'Kite', 'Strawberry', - 'Other Balls', 'Shovel', 'Pepper', 'Computer Box', 'Toilet Paper', 'Cleaning Products', 'Chopsticks', - 'Microwave', 'Pigeon', 'Baseball', 'Cutting/chopping Board', 'Coffee Table', 'Side Table', 'Scissors', - 'Marker', 'Pie', 'Ladder', 'Snowboard', 'Cookies', 'Radiator', 'Fire Hydrant', 'Basketball', 'Zebra', 'Grape', - 'Giraffe', 'Potato', 'Sausage', 'Tricycle', 'Violin', 'Egg', 'Fire Extinguisher', 'Candy', 'Fire Truck', - 'Billiards', 'Converter', 'Bathtub', 'Wheelchair', 'Golf Club', 'Briefcase', 'Cucumber', 'Cigar/Cigarette', - 'Paint Brush', 'Pear', 'Heavy Truck', 'Hamburger', 'Extractor', 'Extension Cord', 'Tong', 'Tennis Racket', - 'Folder', 'American Football', 'earphone', 'Mask', 'Kettle', 'Tennis', 'Ship', 'Swing', 'Coffee Machine', - 'Slide', 'Carriage', 'Onion', 'Green beans', 'Projector', 'Frisbee', 'Washing Machine/Drying Machine', - 'Chicken', 'Printer', 'Watermelon', 'Saxophone', 'Tissue', 'Toothbrush', 'Ice cream', 'Hot-air balloon', - 'Cello', 'French Fries', 'Scale', 'Trophy', 'Cabbage', 'Hot dog', 'Blender', 'Peach', 'Rice', 'Wallet/Purse', - 'Volleyball', 'Deer', 'Goose', 'Tape', 'Tablet', 'Cosmetics', 'Trumpet', 'Pineapple', 'Golf Ball', - 'Ambulance', 'Parking meter', 'Mango', 'Key', 'Hurdle', 'Fishing Rod', 'Medal', 'Flute', 'Brush', 'Penguin', - 'Megaphone', 'Corn', 'Lettuce', 'Garlic', 'Swan', 'Helicopter', 'Green Onion', 'Sandwich', 'Nuts', - 'Speed Limit Sign', 'Induction Cooker', 'Broom', 'Trombone', 'Plum', 'Rickshaw', 'Goldfish', 'Kiwi fruit', - 'Router/modem', 'Poker Card', 'Toaster', 'Shrimp', 'Sushi', 'Cheese', 'Notepaper', 'Cherry', 'Pliers', 'CD', - 'Pasta', 'Hammer', 'Cue', 'Avocado', 'Hamimelon', 'Flask', 'Mushroom', 'Screwdriver', 'Soap', 'Recorder', - 'Bear', 'Eggplant', 'Board Eraser', 'Coconut', 'Tape Measure/Ruler', 'Pig', 'Showerhead', 'Globe', 'Chips', - 'Steak', 'Crosswalk Sign', 'Stapler', 'Camel', 'Formula 1', 'Pomegranate', 'Dishwasher', 'Crab', - 'Hoverboard', 'Meat ball', 'Rice Cooker', 'Tuba', 'Calculator', 'Papaya', 'Antelope', 'Parrot', 'Seal', - 'Butterfly', 'Dumbbell', 'Donkey', 'Lion', 'Urinal', 'Dolphin', 'Electric Drill', 'Hair Dryer', 'Egg tart', - 'Jellyfish', 'Treadmill', 'Lighter', 'Grapefruit', 'Game board', 'Mop', 'Radish', 'Baozi', 'Target', 'French', - 'Spring Rolls', 'Monkey', 'Rabbit', 'Pencil Case', 'Yak', 'Red Cabbage', 'Binoculars', 'Asparagus', 'Barbell', - 'Scallop', 'Noddles', 'Comb', 'Dumpling', 'Oyster', 'Table Tennis paddle', 'Cosmetics Brush/Eyeliner Pencil', - 'Chainsaw', 'Eraser', 'Lobster', 'Durian', 'Okra', 'Lipstick', 'Cosmetics Mirror', 'Curling', 'Table Tennis'] +names: + 0: Person + 1: Sneakers + 2: Chair + 3: Other Shoes + 4: Hat + 5: Car + 6: Lamp + 7: Glasses + 8: Bottle + 9: Desk + 10: Cup + 11: Street Lights + 12: Cabinet/shelf + 13: Handbag/Satchel + 14: Bracelet + 15: Plate + 16: Picture/Frame + 17: Helmet + 18: Book + 19: Gloves + 20: Storage box + 21: Boat + 22: Leather Shoes + 23: Flower + 24: Bench + 25: Potted Plant + 26: Bowl/Basin + 27: Flag + 28: Pillow + 29: Boots + 30: Vase + 31: Microphone + 32: Necklace + 33: Ring + 34: SUV + 35: Wine Glass + 36: Belt + 37: Monitor/TV + 38: Backpack + 39: Umbrella + 40: Traffic Light + 41: Speaker + 42: Watch + 43: Tie + 44: Trash bin Can + 45: Slippers + 46: Bicycle + 47: Stool + 48: Barrel/bucket + 49: Van + 50: Couch + 51: Sandals + 52: Basket + 53: Drum + 54: Pen/Pencil + 55: Bus + 56: Wild Bird + 57: High Heels + 58: Motorcycle + 59: Guitar + 60: Carpet + 61: Cell Phone + 62: Bread + 63: Camera + 64: Canned + 65: Truck + 66: Traffic cone + 67: Cymbal + 68: Lifesaver + 69: Towel + 70: Stuffed Toy + 71: Candle + 72: Sailboat + 73: Laptop + 74: Awning + 75: Bed + 76: Faucet + 77: Tent + 78: Horse + 79: Mirror + 80: Power outlet + 81: Sink + 82: Apple + 83: Air Conditioner + 84: Knife + 85: Hockey Stick + 86: Paddle + 87: Pickup Truck + 88: Fork + 89: Traffic Sign + 90: Balloon + 91: Tripod + 92: Dog + 93: Spoon + 94: Clock + 95: Pot + 96: Cow + 97: Cake + 98: Dinning Table + 99: Sheep + 100: Hanger + 101: Blackboard/Whiteboard + 102: Napkin + 103: Other Fish + 104: Orange/Tangerine + 105: Toiletry + 106: Keyboard + 107: Tomato + 108: Lantern + 109: Machinery Vehicle + 110: Fan + 111: Green Vegetables + 112: Banana + 113: Baseball Glove + 114: Airplane + 115: Mouse + 116: Train + 117: Pumpkin + 118: Soccer + 119: Skiboard + 120: Luggage + 121: Nightstand + 122: Tea pot + 123: Telephone + 124: Trolley + 125: Head Phone + 126: Sports Car + 127: Stop Sign + 128: Dessert + 129: Scooter + 130: Stroller + 131: Crane + 132: Remote + 133: Refrigerator + 134: Oven + 135: Lemon + 136: Duck + 137: Baseball Bat + 138: Surveillance Camera + 139: Cat + 140: Jug + 141: Broccoli + 142: Piano + 143: Pizza + 144: Elephant + 145: Skateboard + 146: Surfboard + 147: Gun + 148: Skating and Skiing shoes + 149: Gas stove + 150: Donut + 151: Bow Tie + 152: Carrot + 153: Toilet + 154: Kite + 155: Strawberry + 156: Other Balls + 157: Shovel + 158: Pepper + 159: Computer Box + 160: Toilet Paper + 161: Cleaning Products + 162: Chopsticks + 163: Microwave + 164: Pigeon + 165: Baseball + 166: Cutting/chopping Board + 167: Coffee Table + 168: Side Table + 169: Scissors + 170: Marker + 171: Pie + 172: Ladder + 173: Snowboard + 174: Cookies + 175: Radiator + 176: Fire Hydrant + 177: Basketball + 178: Zebra + 179: Grape + 180: Giraffe + 181: Potato + 182: Sausage + 183: Tricycle + 184: Violin + 185: Egg + 186: Fire Extinguisher + 187: Candy + 188: Fire Truck + 189: Billiards + 190: Converter + 191: Bathtub + 192: Wheelchair + 193: Golf Club + 194: Briefcase + 195: Cucumber + 196: Cigar/Cigarette + 197: Paint Brush + 198: Pear + 199: Heavy Truck + 200: Hamburger + 201: Extractor + 202: Extension Cord + 203: Tong + 204: Tennis Racket + 205: Folder + 206: American Football + 207: earphone + 208: Mask + 209: Kettle + 210: Tennis + 211: Ship + 212: Swing + 213: Coffee Machine + 214: Slide + 215: Carriage + 216: Onion + 217: Green beans + 218: Projector + 219: Frisbee + 220: Washing Machine/Drying Machine + 221: Chicken + 222: Printer + 223: Watermelon + 224: Saxophone + 225: Tissue + 226: Toothbrush + 227: Ice cream + 228: Hot-air balloon + 229: Cello + 230: French Fries + 231: Scale + 232: Trophy + 233: Cabbage + 234: Hot dog + 235: Blender + 236: Peach + 237: Rice + 238: Wallet/Purse + 239: Volleyball + 240: Deer + 241: Goose + 242: Tape + 243: Tablet + 244: Cosmetics + 245: Trumpet + 246: Pineapple + 247: Golf Ball + 248: Ambulance + 249: Parking meter + 250: Mango + 251: Key + 252: Hurdle + 253: Fishing Rod + 254: Medal + 255: Flute + 256: Brush + 257: Penguin + 258: Megaphone + 259: Corn + 260: Lettuce + 261: Garlic + 262: Swan + 263: Helicopter + 264: Green Onion + 265: Sandwich + 266: Nuts + 267: Speed Limit Sign + 268: Induction Cooker + 269: Broom + 270: Trombone + 271: Plum + 272: Rickshaw + 273: Goldfish + 274: Kiwi fruit + 275: Router/modem + 276: Poker Card + 277: Toaster + 278: Shrimp + 279: Sushi + 280: Cheese + 281: Notepaper + 282: Cherry + 283: Pliers + 284: CD + 285: Pasta + 286: Hammer + 287: Cue + 288: Avocado + 289: Hamimelon + 290: Flask + 291: Mushroom + 292: Screwdriver + 293: Soap + 294: Recorder + 295: Bear + 296: Eggplant + 297: Board Eraser + 298: Coconut + 299: Tape Measure/Ruler + 300: Pig + 301: Showerhead + 302: Globe + 303: Chips + 304: Steak + 305: Crosswalk Sign + 306: Stapler + 307: Camel + 308: Formula 1 + 309: Pomegranate + 310: Dishwasher + 311: Crab + 312: Hoverboard + 313: Meat ball + 314: Rice Cooker + 315: Tuba + 316: Calculator + 317: Papaya + 318: Antelope + 319: Parrot + 320: Seal + 321: Butterfly + 322: Dumbbell + 323: Donkey + 324: Lion + 325: Urinal + 326: Dolphin + 327: Electric Drill + 328: Hair Dryer + 329: Egg tart + 330: Jellyfish + 331: Treadmill + 332: Lighter + 333: Grapefruit + 334: Game board + 335: Mop + 336: Radish + 337: Baozi + 338: Target + 339: French + 340: Spring Rolls + 341: Monkey + 342: Rabbit + 343: Pencil Case + 344: Yak + 345: Red Cabbage + 346: Binoculars + 347: Asparagus + 348: Barbell + 349: Scallop + 350: Noddles + 351: Comb + 352: Dumpling + 353: Oyster + 354: Table Tennis paddle + 355: Cosmetics Brush/Eyeliner Pencil + 356: Chainsaw + 357: Eraser + 358: Lobster + 359: Durian + 360: Okra + 361: Lipstick + 362: Cosmetics Mirror + 363: Curling + 364: Table Tennis # Download script/URL (optional) --------------------------------------------------------------------------------------- download: | - from pycocotools.coco import COCO from tqdm import tqdm - from utils.general import Path, download, np, xyxy2xywhn + from utils.general import Path, check_requirements, download, np, xyxy2xywhn + + check_requirements(('pycocotools>=2.0',)) + from pycocotools.coco import COCO # Make Directories dir = Path(yaml['path']) # dataset root dir diff --git a/data/scripts/download_weights.sh b/data/scripts/download_weights.sh index 50aec183ab..5e9acc44fa 100755 --- a/data/scripts/download_weights.sh +++ b/data/scripts/download_weights.sh @@ -1,18 +1,22 @@ #!/bin/bash # YOLOv3 🚀 by Ultralytics, GPL-3.0 license -# Download latest models from https://github.com/ultralytics/yolov3/releases -# Example usage: bash path/to/download_weights.sh +# Download latest models from https://github.com/ultralytics/yolov5/releases +# Example usage: bash data/scripts/download_weights.sh # parent -# └── yolov3 -# ├── yolov3.pt ← downloads here -# ├── yolov3-spp.pt +# └── yolov5 +# ├── yolov5s.pt ← downloads here +# ├── yolov5m.pt # └── ... python - < 1)}, " # add to string # Write results @@ -153,22 +164,23 @@ def run(weights=ROOT / 'yolov3.pt', # model.pt path(s) if save_txt: # Write to file xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format - with open(txt_path + '.txt', 'a') as f: + with open(f'{txt_path}.txt', 'a') as f: f.write(('%g ' * len(line)).rstrip() % line + '\n') if save_img or save_crop or view_img: # Add bbox to image c = int(cls) # integer class label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}') annotator.box_label(xyxy, label, color=colors(c, True)) - if save_crop: - save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True) - - # Print time (inference-only) - LOGGER.info(f'{s}Done. ({t3 - t2:.3f}s)') + if save_crop: + save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True) # Stream results im0 = annotator.result() if view_img: + if platform.system() == 'Linux' and p not in windows: + windows.append(p) + cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux) + cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0]) cv2.imshow(str(p), im0) cv2.waitKey(1) # 1 millisecond @@ -187,24 +199,32 @@ def run(weights=ROOT / 'yolov3.pt', # model.pt path(s) h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) else: # stream fps, w, h = 30, im0.shape[1], im0.shape[0] - save_path += '.mp4' + save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) vid_writer[i].write(im0) + # Print time (inference-only) + LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms") + # Print results - t = tuple(x / seen * 1E3 for x in dt) # speeds per image + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t) if save_txt or save_img: s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") if update: - strip_optimizer(weights) # update model (to fix SourceChangeWarning) + strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning) def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov3.pt', help='model path(s)') - parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob, 0 for webcam') + parser.add_argument('--weights', + nargs='+', + type=str, + default=ROOT / 'yolov3-tiny.pt', + help='model path or triton URL') + parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob/screen/0(webcam)') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path') parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold') parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold') @@ -228,9 +248,10 @@ def parse_opt(): parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences') parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride') opt = parser.parse_args() opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand - print_args(FILE.stem, opt) + print_args(vars(opt)) return opt diff --git a/export.py b/export.py index 00fb8c0c51..3d54cbf84c 100644 --- a/export.py +++ b/export.py @@ -1,287 +1,538 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license """ -Export a PyTorch model to TorchScript, ONNX, CoreML, TensorFlow (saved_model, pb, TFLite, TF.js,) formats -TensorFlow exports authored by https://github.com/zldrobit +Export a YOLOv3 PyTorch model to other formats. TensorFlow exports authored by https://github.com/zldrobit + +Format | `export.py --include` | Model +--- | --- | --- +PyTorch | - | yolov5s.pt +TorchScript | `torchscript` | yolov5s.torchscript +ONNX | `onnx` | yolov5s.onnx +OpenVINO | `openvino` | yolov5s_openvino_model/ +TensorRT | `engine` | yolov5s.engine +CoreML | `coreml` | yolov5s.mlmodel +TensorFlow SavedModel | `saved_model` | yolov5s_saved_model/ +TensorFlow GraphDef | `pb` | yolov5s.pb +TensorFlow Lite | `tflite` | yolov5s.tflite +TensorFlow Edge TPU | `edgetpu` | yolov5s_edgetpu.tflite +TensorFlow.js | `tfjs` | yolov5s_web_model/ +PaddlePaddle | `paddle` | yolov5s_paddle_model/ + +Requirements: + $ pip install -r requirements.txt coremltools onnx onnx-simplifier onnxruntime openvino-dev tensorflow-cpu # CPU + $ pip install -r requirements.txt coremltools onnx onnx-simplifier onnxruntime-gpu openvino-dev tensorflow # GPU Usage: - $ python path/to/export.py --weights yolov3.pt --include torchscript onnx coreml saved_model pb tflite tfjs + $ python export.py --weights yolov5s.pt --include torchscript onnx openvino engine coreml tflite ... Inference: - $ python path/to/detect.py --weights yolov3.pt - yolov3.onnx (must export with --dynamic) - yolov3_saved_model - yolov3.pb - yolov3.tflite + $ python detect.py --weights yolov5s.pt # PyTorch + yolov5s.torchscript # TorchScript + yolov5s.onnx # ONNX Runtime or OpenCV DNN with --dnn + yolov5s_openvino_model # OpenVINO + yolov5s.engine # TensorRT + yolov5s.mlmodel # CoreML (macOS-only) + yolov5s_saved_model # TensorFlow SavedModel + yolov5s.pb # TensorFlow GraphDef + yolov5s.tflite # TensorFlow Lite + yolov5s_edgetpu.tflite # TensorFlow Edge TPU + yolov5s_paddle_model # PaddlePaddle TensorFlow.js: $ cd .. && git clone https://github.com/zldrobit/tfjs-yolov5-example.git && cd tfjs-yolov5-example $ npm install - $ ln -s ../../yolov5/yolov3_web_model public/yolov3_web_model + $ ln -s ../../yolov5/yolov5s_web_model public/yolov5s_web_model $ npm start """ import argparse +import contextlib import json import os +import platform +import re import subprocess import sys import time +import warnings from pathlib import Path +import pandas as pd import torch -import torch.nn as nn from torch.utils.mobile_optimizer import optimize_for_mobile FILE = Path(__file__).resolve() -ROOT = FILE.parents[0] # root directory +ROOT = FILE.parents[0] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH -ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative +if platform.system() != 'Windows': + ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative -from models.common import Conv from models.experimental import attempt_load -from models.yolo import Detect -from utils.activations import SiLU -from utils.datasets import LoadImages -from utils.general import (LOGGER, check_dataset, check_img_size, check_requirements, colorstr, file_size, print_args, - url2file) -from utils.torch_utils import select_device - - +from models.yolo import ClassificationModel, Detect, DetectionModel, SegmentationModel +from utils.dataloaders import LoadImages +from utils.general import (LOGGER, Profile, check_dataset, check_img_size, check_requirements, check_version, + check_yaml, colorstr, file_size, get_default_args, print_args, url2file, yaml_save) +from utils.torch_utils import select_device, smart_inference_mode + +MACOS = platform.system() == 'Darwin' # macOS environment + + +def export_formats(): + # YOLOv3 export formats + x = [ + ['PyTorch', '-', '.pt', True, True], + ['TorchScript', 'torchscript', '.torchscript', True, True], + ['ONNX', 'onnx', '.onnx', True, True], + ['OpenVINO', 'openvino', '_openvino_model', True, False], + ['TensorRT', 'engine', '.engine', False, True], + ['CoreML', 'coreml', '.mlmodel', True, False], + ['TensorFlow SavedModel', 'saved_model', '_saved_model', True, True], + ['TensorFlow GraphDef', 'pb', '.pb', True, True], + ['TensorFlow Lite', 'tflite', '.tflite', True, False], + ['TensorFlow Edge TPU', 'edgetpu', '_edgetpu.tflite', False, False], + ['TensorFlow.js', 'tfjs', '_web_model', False, False], + ['PaddlePaddle', 'paddle', '_paddle_model', True, True],] + return pd.DataFrame(x, columns=['Format', 'Argument', 'Suffix', 'CPU', 'GPU']) + + +def try_export(inner_func): + # YOLOv3 export decorator, i..e @try_export + inner_args = get_default_args(inner_func) + + def outer_func(*args, **kwargs): + prefix = inner_args['prefix'] + try: + with Profile() as dt: + f, model = inner_func(*args, **kwargs) + LOGGER.info(f'{prefix} export success ✅ {dt.t:.1f}s, saved as {f} ({file_size(f):.1f} MB)') + return f, model + except Exception as e: + LOGGER.info(f'{prefix} export failure ❌ {dt.t:.1f}s: {e}') + return None, None + + return outer_func + + +@try_export def export_torchscript(model, im, file, optimize, prefix=colorstr('TorchScript:')): - # TorchScript model export - try: - LOGGER.info(f'\n{prefix} starting export with torch {torch.__version__}...') - f = file.with_suffix('.torchscript.pt') - - ts = torch.jit.trace(model, im, strict=False) - d = {"shape": im.shape, "stride": int(max(model.stride)), "names": model.names} - extra_files = {'config.txt': json.dumps(d)} # torch._C.ExtraFilesMap() - (optimize_for_mobile(ts) if optimize else ts).save(f, _extra_files=extra_files) - - LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') - except Exception as e: - LOGGER.info(f'{prefix} export failure: {e}') - - -def export_onnx(model, im, file, opset, train, dynamic, simplify, prefix=colorstr('ONNX:')): - # ONNX export - try: - check_requirements(('onnx',)) - import onnx - - LOGGER.info(f'\n{prefix} starting export with onnx {onnx.__version__}...') - f = file.with_suffix('.onnx') - - torch.onnx.export(model, im, f, verbose=False, opset_version=opset, - training=torch.onnx.TrainingMode.TRAINING if train else torch.onnx.TrainingMode.EVAL, - do_constant_folding=not train, - input_names=['images'], - output_names=['output'], - dynamic_axes={'images': {0: 'batch', 2: 'height', 3: 'width'}, # shape(1,3,640,640) - 'output': {0: 'batch', 1: 'anchors'} # shape(1,25200,85) - } if dynamic else None) - - # Checks - model_onnx = onnx.load(f) # load onnx model - onnx.checker.check_model(model_onnx) # check onnx model - # LOGGER.info(onnx.helper.printable_graph(model_onnx.graph)) # print - - # Simplify - if simplify: - try: - check_requirements(('onnx-simplifier',)) - import onnxsim - - LOGGER.info(f'{prefix} simplifying with onnx-simplifier {onnxsim.__version__}...') - model_onnx, check = onnxsim.simplify( - model_onnx, - dynamic_input_shape=dynamic, - input_shapes={'images': list(im.shape)} if dynamic else None) - assert check, 'assert check failed' - onnx.save(model_onnx, f) - except Exception as e: - LOGGER.info(f'{prefix} simplifier failure: {e}') - LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') - LOGGER.info(f"{prefix} run --dynamic ONNX model inference with: 'python detect.py --weights {f}'") - except Exception as e: - LOGGER.info(f'{prefix} export failure: {e}') - - -def export_coreml(model, im, file, prefix=colorstr('CoreML:')): - # CoreML export - ct_model = None + # YOLOv3 TorchScript model export + LOGGER.info(f'\n{prefix} starting export with torch {torch.__version__}...') + f = file.with_suffix('.torchscript') + + ts = torch.jit.trace(model, im, strict=False) + d = {"shape": im.shape, "stride": int(max(model.stride)), "names": model.names} + extra_files = {'config.txt': json.dumps(d)} # torch._C.ExtraFilesMap() + if optimize: # https://pytorch.org/tutorials/recipes/mobile_interpreter.html + optimize_for_mobile(ts)._save_for_lite_interpreter(str(f), _extra_files=extra_files) + else: + ts.save(str(f), _extra_files=extra_files) + return f, None + + +@try_export +def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr('ONNX:')): + # YOLOv3 ONNX export + check_requirements('onnx>=1.12.0') + import onnx + + LOGGER.info(f'\n{prefix} starting export with onnx {onnx.__version__}...') + f = file.with_suffix('.onnx') + + output_names = ['output0', 'output1'] if isinstance(model, SegmentationModel) else ['output0'] + if dynamic: + dynamic = {'images': {0: 'batch', 2: 'height', 3: 'width'}} # shape(1,3,640,640) + if isinstance(model, SegmentationModel): + dynamic['output0'] = {0: 'batch', 1: 'anchors'} # shape(1,25200,85) + dynamic['output1'] = {0: 'batch', 2: 'mask_height', 3: 'mask_width'} # shape(1,32,160,160) + elif isinstance(model, DetectionModel): + dynamic['output0'] = {0: 'batch', 1: 'anchors'} # shape(1,25200,85) + + torch.onnx.export( + model.cpu() if dynamic else model, # --dynamic only compatible with cpu + im.cpu() if dynamic else im, + f, + verbose=False, + opset_version=opset, + do_constant_folding=True, # WARNING: DNN inference with torch>=1.12 may require do_constant_folding=False + input_names=['images'], + output_names=output_names, + dynamic_axes=dynamic or None) + + # Checks + model_onnx = onnx.load(f) # load onnx model + onnx.checker.check_model(model_onnx) # check onnx model + + # Metadata + d = {'stride': int(max(model.stride)), 'names': model.names} + for k, v in d.items(): + meta = model_onnx.metadata_props.add() + meta.key, meta.value = k, str(v) + onnx.save(model_onnx, f) + + # Simplify + if simplify: + try: + cuda = torch.cuda.is_available() + check_requirements(('onnxruntime-gpu' if cuda else 'onnxruntime', 'onnx-simplifier>=0.4.1')) + import onnxsim + + LOGGER.info(f'{prefix} simplifying with onnx-simplifier {onnxsim.__version__}...') + model_onnx, check = onnxsim.simplify(model_onnx) + assert check, 'assert check failed' + onnx.save(model_onnx, f) + except Exception as e: + LOGGER.info(f'{prefix} simplifier failure: {e}') + return f, model_onnx + + +@try_export +def export_openvino(file, metadata, half, prefix=colorstr('OpenVINO:')): + # YOLOv3 OpenVINO export + check_requirements('openvino-dev') # requires openvino-dev: https://pypi.org/project/openvino-dev/ + import openvino.inference_engine as ie + + LOGGER.info(f'\n{prefix} starting export with openvino {ie.__version__}...') + f = str(file).replace('.pt', f'_openvino_model{os.sep}') + + cmd = f"mo --input_model {file.with_suffix('.onnx')} --output_dir {f} --data_type {'FP16' if half else 'FP32'}" + subprocess.run(cmd.split(), check=True, env=os.environ) # export + yaml_save(Path(f) / file.with_suffix('.yaml').name, metadata) # add metadata.yaml + return f, None + + +@try_export +def export_paddle(model, im, file, metadata, prefix=colorstr('PaddlePaddle:')): + # YOLOv3 Paddle export + check_requirements(('paddlepaddle', 'x2paddle')) + import x2paddle + from x2paddle.convert import pytorch2paddle + + LOGGER.info(f'\n{prefix} starting export with X2Paddle {x2paddle.__version__}...') + f = str(file).replace('.pt', f'_paddle_model{os.sep}') + + pytorch2paddle(module=model, save_dir=f, jit_type='trace', input_examples=[im]) # export + yaml_save(Path(f) / file.with_suffix('.yaml').name, metadata) # add metadata.yaml + return f, None + + +@try_export +def export_coreml(model, im, file, int8, half, prefix=colorstr('CoreML:')): + # YOLOv3 CoreML export + check_requirements('coremltools') + import coremltools as ct + + LOGGER.info(f'\n{prefix} starting export with coremltools {ct.__version__}...') + f = file.with_suffix('.mlmodel') + + ts = torch.jit.trace(model, im, strict=False) # TorchScript model + ct_model = ct.convert(ts, inputs=[ct.ImageType('image', shape=im.shape, scale=1 / 255, bias=[0, 0, 0])]) + bits, mode = (8, 'kmeans_lut') if int8 else (16, 'linear') if half else (32, None) + if bits < 32: + if MACOS: # quantization only supported on macOS + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) # suppress numpy==1.20 float warning + ct_model = ct.models.neural_network.quantization_utils.quantize_weights(ct_model, bits, mode) + else: + print(f'{prefix} quantization only supported on macOS, skipping...') + ct_model.save(f) + return f, ct_model + + +@try_export +def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose=False, prefix=colorstr('TensorRT:')): + # YOLOv3 TensorRT export https://developer.nvidia.com/tensorrt + assert im.device.type != 'cpu', 'export running on CPU but must be on GPU, i.e. `python export.py --device 0`' try: - check_requirements(('coremltools',)) - import coremltools as ct - - LOGGER.info(f'\n{prefix} starting export with coremltools {ct.__version__}...') - f = file.with_suffix('.mlmodel') - - model.train() # CoreML exports should be placed in model.train() mode - ts = torch.jit.trace(model, im, strict=False) # TorchScript model - ct_model = ct.convert(ts, inputs=[ct.ImageType('image', shape=im.shape, scale=1 / 255, bias=[0, 0, 0])]) - ct_model.save(f) - - LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') - except Exception as e: - LOGGER.info(f'\n{prefix} export failure: {e}') - - return ct_model - - -def export_saved_model(model, im, file, dynamic, - tf_nms=False, agnostic_nms=False, topk_per_class=100, topk_all=100, iou_thres=0.45, - conf_thres=0.25, prefix=colorstr('TensorFlow saved_model:')): - # TensorFlow saved_model export - keras_model = None + import tensorrt as trt + except Exception: + if platform.system() == 'Linux': + check_requirements('nvidia-tensorrt', cmds='-U --index-url https://pypi.ngc.nvidia.com') + import tensorrt as trt + + if trt.__version__[0] == '7': # TensorRT 7 handling https://github.com/ultralytics/yolov5/issues/6012 + grid = model.model[-1].anchor_grid + model.model[-1].anchor_grid = [a[..., :1, :1, :] for a in grid] + export_onnx(model, im, file, 12, dynamic, simplify) # opset 12 + model.model[-1].anchor_grid = grid + else: # TensorRT >= 8 + check_version(trt.__version__, '8.0.0', hard=True) # require tensorrt>=8.0.0 + export_onnx(model, im, file, 12, dynamic, simplify) # opset 12 + onnx = file.with_suffix('.onnx') + + LOGGER.info(f'\n{prefix} starting export with TensorRT {trt.__version__}...') + assert onnx.exists(), f'failed to export ONNX file: {onnx}' + f = file.with_suffix('.engine') # TensorRT engine file + logger = trt.Logger(trt.Logger.INFO) + if verbose: + logger.min_severity = trt.Logger.Severity.VERBOSE + + builder = trt.Builder(logger) + config = builder.create_builder_config() + config.max_workspace_size = workspace * 1 << 30 + # config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, workspace << 30) # fix TRT 8.4 deprecation notice + + flag = (1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)) + network = builder.create_network(flag) + parser = trt.OnnxParser(network, logger) + if not parser.parse_from_file(str(onnx)): + raise RuntimeError(f'failed to load ONNX file: {onnx}') + + inputs = [network.get_input(i) for i in range(network.num_inputs)] + outputs = [network.get_output(i) for i in range(network.num_outputs)] + for inp in inputs: + LOGGER.info(f'{prefix} input "{inp.name}" with shape{inp.shape} {inp.dtype}') + for out in outputs: + LOGGER.info(f'{prefix} output "{out.name}" with shape{out.shape} {out.dtype}') + + if dynamic: + if im.shape[0] <= 1: + LOGGER.warning(f"{prefix} WARNING ⚠️ --dynamic model requires maximum --batch-size argument") + profile = builder.create_optimization_profile() + for inp in inputs: + profile.set_shape(inp.name, (1, *im.shape[1:]), (max(1, im.shape[0] // 2), *im.shape[1:]), im.shape) + config.add_optimization_profile(profile) + + LOGGER.info(f'{prefix} building FP{16 if builder.platform_has_fast_fp16 and half else 32} engine as {f}') + if builder.platform_has_fast_fp16 and half: + config.set_flag(trt.BuilderFlag.FP16) + with builder.build_engine(network, config) as engine, open(f, 'wb') as t: + t.write(engine.serialize()) + return f, None + + +@try_export +def export_saved_model(model, + im, + file, + dynamic, + tf_nms=False, + agnostic_nms=False, + topk_per_class=100, + topk_all=100, + iou_thres=0.45, + conf_thres=0.25, + keras=False, + prefix=colorstr('TensorFlow SavedModel:')): + # YOLOv3 TensorFlow SavedModel export try: import tensorflow as tf - from tensorflow import keras - - from models.tf import TFDetect, TFModel - - LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') - f = str(file).replace('.pt', '_saved_model') - batch_size, ch, *imgsz = list(im.shape) # BCHW - - tf_model = TFModel(cfg=model.yaml, model=model, nc=model.nc, imgsz=imgsz) - im = tf.zeros((batch_size, *imgsz, 3)) # BHWC order for TensorFlow - y = tf_model.predict(im, tf_nms, agnostic_nms, topk_per_class, topk_all, iou_thres, conf_thres) - inputs = keras.Input(shape=(*imgsz, 3), batch_size=None if dynamic else batch_size) - outputs = tf_model.predict(inputs, tf_nms, agnostic_nms, topk_per_class, topk_all, iou_thres, conf_thres) - keras_model = keras.Model(inputs=inputs, outputs=outputs) - keras_model.trainable = False - keras_model.summary() - keras_model.save(f, save_format='tf') - - LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') - except Exception as e: - LOGGER.info(f'\n{prefix} export failure: {e}') - - return keras_model - - -def export_pb(keras_model, im, file, prefix=colorstr('TensorFlow GraphDef:')): - # TensorFlow GraphDef *.pb export https://github.com/leimao/Frozen_Graph_TensorFlow - try: + except Exception: + check_requirements(f"tensorflow{'' if torch.cuda.is_available() else '-macos' if MACOS else '-cpu'}") import tensorflow as tf - from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2 - - LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') - f = file.with_suffix('.pb') - + from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2 + + from models.tf import TFModel + + LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') + f = str(file).replace('.pt', '_saved_model') + batch_size, ch, *imgsz = list(im.shape) # BCHW + + tf_model = TFModel(cfg=model.yaml, model=model, nc=model.nc, imgsz=imgsz) + im = tf.zeros((batch_size, *imgsz, ch)) # BHWC order for TensorFlow + _ = tf_model.predict(im, tf_nms, agnostic_nms, topk_per_class, topk_all, iou_thres, conf_thres) + inputs = tf.keras.Input(shape=(*imgsz, ch), batch_size=None if dynamic else batch_size) + outputs = tf_model.predict(inputs, tf_nms, agnostic_nms, topk_per_class, topk_all, iou_thres, conf_thres) + keras_model = tf.keras.Model(inputs=inputs, outputs=outputs) + keras_model.trainable = False + keras_model.summary() + if keras: + keras_model.save(f, save_format='tf') + else: + spec = tf.TensorSpec(keras_model.inputs[0].shape, keras_model.inputs[0].dtype) m = tf.function(lambda x: keras_model(x)) # full model - m = m.get_concrete_function(tf.TensorSpec(keras_model.inputs[0].shape, keras_model.inputs[0].dtype)) + m = m.get_concrete_function(spec) frozen_func = convert_variables_to_constants_v2(m) - frozen_func.graph.as_graph_def() - tf.io.write_graph(graph_or_graph_def=frozen_func.graph, logdir=str(f.parent), name=f.name, as_text=False) - - LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') - except Exception as e: - LOGGER.info(f'\n{prefix} export failure: {e}') - - -def export_tflite(keras_model, im, file, int8, data, ncalib, prefix=colorstr('TensorFlow Lite:')): - # TensorFlow Lite export - try: - import tensorflow as tf - + tfm = tf.Module() + tfm.__call__ = tf.function(lambda x: frozen_func(x)[:4] if tf_nms else frozen_func(x), [spec]) + tfm.__call__(im) + tf.saved_model.save(tfm, + f, + options=tf.saved_model.SaveOptions(experimental_custom_gradients=False) if check_version( + tf.__version__, '2.6') else tf.saved_model.SaveOptions()) + return f, keras_model + + +@try_export +def export_pb(keras_model, file, prefix=colorstr('TensorFlow GraphDef:')): + # YOLOv3 TensorFlow GraphDef *.pb export https://github.com/leimao/Frozen_Graph_TensorFlow + import tensorflow as tf + from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2 + + LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') + f = file.with_suffix('.pb') + + m = tf.function(lambda x: keras_model(x)) # full model + m = m.get_concrete_function(tf.TensorSpec(keras_model.inputs[0].shape, keras_model.inputs[0].dtype)) + frozen_func = convert_variables_to_constants_v2(m) + frozen_func.graph.as_graph_def() + tf.io.write_graph(graph_or_graph_def=frozen_func.graph, logdir=str(f.parent), name=f.name, as_text=False) + return f, None + + +@try_export +def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=colorstr('TensorFlow Lite:')): + # YOLOv3 TensorFlow Lite export + import tensorflow as tf + + LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') + batch_size, ch, *imgsz = list(im.shape) # BCHW + f = str(file).replace('.pt', '-fp16.tflite') + + converter = tf.lite.TFLiteConverter.from_keras_model(keras_model) + converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS] + converter.target_spec.supported_types = [tf.float16] + converter.optimizations = [tf.lite.Optimize.DEFAULT] + if int8: from models.tf import representative_dataset_gen - - LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') - batch_size, ch, *imgsz = list(im.shape) # BCHW - f = str(file).replace('.pt', '-fp16.tflite') - - converter = tf.lite.TFLiteConverter.from_keras_model(keras_model) - converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS] - converter.target_spec.supported_types = [tf.float16] - converter.optimizations = [tf.lite.Optimize.DEFAULT] - if int8: - dataset = LoadImages(check_dataset(data)['train'], img_size=imgsz, auto=False) # representative data - converter.representative_dataset = lambda: representative_dataset_gen(dataset, ncalib) - converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] - converter.target_spec.supported_types = [] - converter.inference_input_type = tf.uint8 # or tf.int8 - converter.inference_output_type = tf.uint8 # or tf.int8 - converter.experimental_new_quantizer = False - f = str(file).replace('.pt', '-int8.tflite') - - tflite_model = converter.convert() - open(f, "wb").write(tflite_model) - LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') - - except Exception as e: - LOGGER.info(f'\n{prefix} export failure: {e}') - - -def export_tfjs(keras_model, im, file, prefix=colorstr('TensorFlow.js:')): - # TensorFlow.js export - try: - check_requirements(('tensorflowjs',)) - import re - - import tensorflowjs as tfjs - - LOGGER.info(f'\n{prefix} starting export with tensorflowjs {tfjs.__version__}...') - f = str(file).replace('.pt', '_web_model') # js dir - f_pb = file.with_suffix('.pb') # *.pb path - f_json = f + '/model.json' # *.json path - - cmd = f"tensorflowjs_converter --input_format=tf_frozen_model " \ - f"--output_node_names='Identity,Identity_1,Identity_2,Identity_3' {f_pb} {f}" - subprocess.run(cmd, shell=True) - - json = open(f_json).read() - with open(f_json, 'w') as j: # sort JSON Identity_* in ascending order - subst = re.sub( - r'{"outputs": {"Identity.?.?": {"name": "Identity.?.?"}, ' - r'"Identity.?.?": {"name": "Identity.?.?"}, ' - r'"Identity.?.?": {"name": "Identity.?.?"}, ' - r'"Identity.?.?": {"name": "Identity.?.?"}}}', - r'{"outputs": {"Identity": {"name": "Identity"}, ' - r'"Identity_1": {"name": "Identity_1"}, ' - r'"Identity_2": {"name": "Identity_2"}, ' - r'"Identity_3": {"name": "Identity_3"}}}', - json) - j.write(subst) - - LOGGER.info(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') - except Exception as e: - LOGGER.info(f'\n{prefix} export failure: {e}') - - -@torch.no_grad() -def run(data=ROOT / 'data/coco128.yaml', # 'dataset.yaml path' - weights=ROOT / 'yolov3.pt', # weights path + dataset = LoadImages(check_dataset(check_yaml(data))['train'], img_size=imgsz, auto=False) + converter.representative_dataset = lambda: representative_dataset_gen(dataset, ncalib=100) + converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] + converter.target_spec.supported_types = [] + converter.inference_input_type = tf.uint8 # or tf.int8 + converter.inference_output_type = tf.uint8 # or tf.int8 + converter.experimental_new_quantizer = True + f = str(file).replace('.pt', '-int8.tflite') + if nms or agnostic_nms: + converter.target_spec.supported_ops.append(tf.lite.OpsSet.SELECT_TF_OPS) + + tflite_model = converter.convert() + open(f, "wb").write(tflite_model) + return f, None + + +@try_export +def export_edgetpu(file, prefix=colorstr('Edge TPU:')): + # YOLOv3 Edge TPU export https://coral.ai/docs/edgetpu/models-intro/ + cmd = 'edgetpu_compiler --version' + help_url = 'https://coral.ai/docs/edgetpu/compiler/' + assert platform.system() == 'Linux', f'export only supported on Linux. See {help_url}' + if subprocess.run(f'{cmd} >/dev/null', shell=True).returncode != 0: + LOGGER.info(f'\n{prefix} export requires Edge TPU compiler. Attempting install from {help_url}') + sudo = subprocess.run('sudo --version >/dev/null', shell=True).returncode == 0 # sudo installed on system + for c in ( + 'curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -', + 'echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list', + 'sudo apt-get update', 'sudo apt-get install edgetpu-compiler'): + subprocess.run(c if sudo else c.replace('sudo ', ''), shell=True, check=True) + ver = subprocess.run(cmd, shell=True, capture_output=True, check=True).stdout.decode().split()[-1] + + LOGGER.info(f'\n{prefix} starting export with Edge TPU compiler {ver}...') + f = str(file).replace('.pt', '-int8_edgetpu.tflite') # Edge TPU model + f_tfl = str(file).replace('.pt', '-int8.tflite') # TFLite model + + cmd = f"edgetpu_compiler -s -d -k 10 --out_dir {file.parent} {f_tfl}" + subprocess.run(cmd.split(), check=True) + return f, None + + +@try_export +def export_tfjs(file, int8, prefix=colorstr('TensorFlow.js:')): + # YOLOv3 TensorFlow.js export + check_requirements('tensorflowjs') + import tensorflowjs as tfjs + + LOGGER.info(f'\n{prefix} starting export with tensorflowjs {tfjs.__version__}...') + f = str(file).replace('.pt', '_web_model') # js dir + f_pb = file.with_suffix('.pb') # *.pb path + f_json = f'{f}/model.json' # *.json path + + int8_export = ' --quantize_uint8 ' if int8 else '' + + cmd = f'tensorflowjs_converter --input_format=tf_frozen_model {int8_export}' \ + f'--output_node_names=Identity,Identity_1,Identity_2,Identity_3 {f_pb} {f}' + subprocess.run(cmd.split()) + + json = Path(f_json).read_text() + with open(f_json, 'w') as j: # sort JSON Identity_* in ascending order + subst = re.sub( + r'{"outputs": {"Identity.?.?": {"name": "Identity.?.?"}, ' + r'"Identity.?.?": {"name": "Identity.?.?"}, ' + r'"Identity.?.?": {"name": "Identity.?.?"}, ' + r'"Identity.?.?": {"name": "Identity.?.?"}}}', r'{"outputs": {"Identity": {"name": "Identity"}, ' + r'"Identity_1": {"name": "Identity_1"}, ' + r'"Identity_2": {"name": "Identity_2"}, ' + r'"Identity_3": {"name": "Identity_3"}}}', json) + j.write(subst) + return f, None + + +def add_tflite_metadata(file, metadata, num_outputs): + # Add metadata to *.tflite models per https://www.tensorflow.org/lite/models/convert/metadata + with contextlib.suppress(ImportError): + # check_requirements('tflite_support') + from tflite_support import flatbuffers + from tflite_support import metadata as _metadata + from tflite_support import metadata_schema_py_generated as _metadata_fb + + tmp_file = Path('/tmp/meta.txt') + with open(tmp_file, 'w') as meta_f: + meta_f.write(str(metadata)) + + model_meta = _metadata_fb.ModelMetadataT() + label_file = _metadata_fb.AssociatedFileT() + label_file.name = tmp_file.name + model_meta.associatedFiles = [label_file] + + subgraph = _metadata_fb.SubGraphMetadataT() + subgraph.inputTensorMetadata = [_metadata_fb.TensorMetadataT()] + subgraph.outputTensorMetadata = [_metadata_fb.TensorMetadataT()] * num_outputs + model_meta.subgraphMetadata = [subgraph] + + b = flatbuffers.Builder(0) + b.Finish(model_meta.Pack(b), _metadata.MetadataPopulator.METADATA_FILE_IDENTIFIER) + metadata_buf = b.Output() + + populator = _metadata.MetadataPopulator.with_model_file(file) + populator.load_metadata_buffer(metadata_buf) + populator.load_associated_files([str(tmp_file)]) + populator.populate() + tmp_file.unlink() + + +@smart_inference_mode() +def run( + data=ROOT / 'data/coco128.yaml', # 'dataset.yaml path' + weights=ROOT / 'yolov5s.pt', # weights path imgsz=(640, 640), # image (height, width) batch_size=1, # batch size device='cpu', # cuda device, i.e. 0 or 0,1,2,3 or cpu - include=('torchscript', 'onnx', 'coreml'), # include formats + include=('torchscript', 'onnx'), # include formats half=False, # FP16 half-precision export - inplace=False, # set Detect() inplace=True - train=False, # model.train() mode + inplace=False, # set YOLOv3 Detect() inplace=True + keras=False, # use Keras optimize=False, # TorchScript: optimize for mobile int8=False, # CoreML/TF INT8 quantization - dynamic=False, # ONNX/TF: dynamic axes + dynamic=False, # ONNX/TF/TensorRT: dynamic axes simplify=False, # ONNX: simplify model opset=12, # ONNX: opset version + verbose=False, # TensorRT: verbose log + workspace=4, # TensorRT: workspace size (GB) + nms=False, # TF: add NMS to model + agnostic_nms=False, # TF: add agnostic NMS to model topk_per_class=100, # TF.js NMS: topk per class to keep topk_all=100, # TF.js NMS: topk for all classes to keep iou_thres=0.45, # TF.js NMS: IoU threshold - conf_thres=0.25 # TF.js NMS: confidence threshold - ): + conf_thres=0.25, # TF.js NMS: confidence threshold +): t = time.time() - include = [x.lower() for x in include] - tf_exports = list(x in include for x in ('saved_model', 'pb', 'tflite', 'tfjs')) # TensorFlow exports - imgsz *= 2 if len(imgsz) == 1 else 1 # expand - file = Path(url2file(weights) if str(weights).startswith(('http:/', 'https:/')) else weights) + include = [x.lower() for x in include] # to lowercase + fmts = tuple(export_formats()['Argument'][1:]) # --include arguments + flags = [x in include for x in fmts] + assert sum(flags) == len(include), f'ERROR: Invalid --include {include}, valid --include arguments are {fmts}' + jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle = flags # export booleans + file = Path(url2file(weights) if str(weights).startswith(('http:/', 'https:/')) else weights) # PyTorch weights # Load PyTorch model device = select_device(device) - assert not (device.type == 'cpu' and half), '--half only compatible with GPU export, i.e. use --device 0' - model = attempt_load(weights, map_location=device, inplace=True, fuse=True) # load FP32 model - nc, names = model.nc, model.names # number of classes, class names + if half: + assert device.type != 'cpu' or coreml, '--half only compatible with GPU export, i.e. use --device 0' + assert not dynamic, '--half not compatible with --dynamic, i.e. use either --half or --dynamic but not both' + model = attempt_load(weights, device=device, inplace=True, fuse=True) # load FP32 model + + # Checks + imgsz *= 2 if len(imgsz) == 1 else 1 # expand + if optimize: + assert device.type == 'cpu', '--optimize not compatible with cuda devices, i.e. use --device cpu' # Input gs = int(max(model.stride)) # grid size (max stride) @@ -289,79 +540,114 @@ def run(data=ROOT / 'data/coco128.yaml', # 'dataset.yaml path' im = torch.zeros(batch_size, 3, *imgsz).to(device) # image size(1,3,320,192) BCHW iDetection # Update model - if half: - im, model = im.half(), model.half() # to FP16 - model.train() if train else model.eval() # training mode = no Detect() layer grid construction + model.eval() for k, m in model.named_modules(): - if isinstance(m, Conv): # assign export-friendly activations - if isinstance(m.act, nn.SiLU): - m.act = SiLU() - elif isinstance(m, Detect): + if isinstance(m, Detect): m.inplace = inplace - m.onnx_dynamic = dynamic - # m.forward = m.forward_export # assign forward (optional) + m.dynamic = dynamic + m.export = True for _ in range(2): y = model(im) # dry runs - LOGGER.info(f"\n{colorstr('PyTorch:')} starting from {file} ({file_size(file):.1f} MB)") + if half and not coreml: + im, model = im.half(), model.half() # to FP16 + shape = tuple((y[0] if isinstance(y, tuple) else y).shape) # model output shape + metadata = {'stride': int(max(model.stride)), 'names': model.names} # model metadata + LOGGER.info(f"\n{colorstr('PyTorch:')} starting from {file} with output shape {shape} ({file_size(file):.1f} MB)") # Exports - if 'torchscript' in include: - export_torchscript(model, im, file, optimize) - if 'onnx' in include: - export_onnx(model, im, file, opset, train, dynamic, simplify) - if 'coreml' in include: - export_coreml(model, im, file) - - # TensorFlow Exports - if any(tf_exports): - pb, tflite, tfjs = tf_exports[1:] - assert not (tflite and tfjs), 'TFLite and TF.js models must be exported separately, please pass only one type.' - model = export_saved_model(model.cpu(), im, file, dynamic, tf_nms=tfjs, agnostic_nms=tfjs, - topk_per_class=topk_per_class, topk_all=topk_all, conf_thres=conf_thres, - iou_thres=iou_thres) # keras model + f = [''] * len(fmts) # exported filenames + warnings.filterwarnings(action='ignore', category=torch.jit.TracerWarning) # suppress TracerWarning + if jit: # TorchScript + f[0], _ = export_torchscript(model, im, file, optimize) + if engine: # TensorRT required before ONNX + f[1], _ = export_engine(model, im, file, half, dynamic, simplify, workspace, verbose) + if onnx or xml: # OpenVINO requires ONNX + f[2], _ = export_onnx(model, im, file, opset, dynamic, simplify) + if xml: # OpenVINO + f[3], _ = export_openvino(file, metadata, half) + if coreml: # CoreML + f[4], _ = export_coreml(model, im, file, int8, half) + if any((saved_model, pb, tflite, edgetpu, tfjs)): # TensorFlow formats + assert not tflite or not tfjs, 'TFLite and TF.js models must be exported separately, please pass only one type.' + assert not isinstance(model, ClassificationModel), 'ClassificationModel export to TF formats not yet supported.' + f[5], s_model = export_saved_model(model.cpu(), + im, + file, + dynamic, + tf_nms=nms or agnostic_nms or tfjs, + agnostic_nms=agnostic_nms or tfjs, + topk_per_class=topk_per_class, + topk_all=topk_all, + iou_thres=iou_thres, + conf_thres=conf_thres, + keras=keras) if pb or tfjs: # pb prerequisite to tfjs - export_pb(model, im, file) - if tflite: - export_tflite(model, im, file, int8=int8, data=data, ncalib=100) + f[6], _ = export_pb(s_model, file) + if tflite or edgetpu: + f[7], _ = export_tflite(s_model, im, file, int8 or edgetpu, data=data, nms=nms, agnostic_nms=agnostic_nms) + if edgetpu: + f[8], _ = export_edgetpu(file) + add_tflite_metadata(f[8] or f[7], metadata, num_outputs=len(s_model.outputs)) if tfjs: - export_tfjs(model, im, file) + f[9], _ = export_tfjs(file, int8) + if paddle: # PaddlePaddle + f[10], _ = export_paddle(model, im, file, metadata) # Finish - LOGGER.info(f'\nExport complete ({time.time() - t:.2f}s)' - f"\nResults saved to {colorstr('bold', file.parent.resolve())}" - f'\nVisualize with https://netron.app') - - -def parse_opt(): + f = [str(x) for x in f if x] # filter out '' and None + if any(f): + cls, det, seg = (isinstance(model, x) for x in (ClassificationModel, DetectionModel, SegmentationModel)) # type + det &= not seg # segmentation models inherit from SegmentationModel(DetectionModel) + dir = Path('segment' if seg else 'classify' if cls else '') + h = '--half' if half else '' # --half FP16 inference arg + s = "# WARNING ⚠️ ClassificationModel not yet supported for PyTorch Hub AutoShape inference" if cls else \ + "# WARNING ⚠️ SegmentationModel not yet supported for PyTorch Hub AutoShape inference" if seg else '' + LOGGER.info(f'\nExport complete ({time.time() - t:.1f}s)' + f"\nResults saved to {colorstr('bold', file.parent.resolve())}" + f"\nDetect: python {dir / ('detect.py' if det else 'predict.py')} --weights {f[-1]} {h}" + f"\nValidate: python {dir / 'val.py'} --weights {f[-1]} {h}" + f"\nPyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', '{f[-1]}') {s}" + f"\nVisualize: https://netron.app") + return f # return list of exported files/dirs + + +def parse_opt(known=False): parser = argparse.ArgumentParser() parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') - parser.add_argument('--weights', type=str, default=ROOT / 'yolov3.pt', help='weights path') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov3-tiny.pt', help='model.pt path(s)') parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640, 640], help='image (h, w)') parser.add_argument('--batch-size', type=int, default=1, help='batch size') parser.add_argument('--device', default='cpu', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--half', action='store_true', help='FP16 half-precision export') - parser.add_argument('--inplace', action='store_true', help='set YOLOv3 Detect() inplace=True') - parser.add_argument('--train', action='store_true', help='model.train() mode') + parser.add_argument('--inplace', action='store_true', help='set Detect() inplace=True') + parser.add_argument('--keras', action='store_true', help='TF: use Keras') parser.add_argument('--optimize', action='store_true', help='TorchScript: optimize for mobile') parser.add_argument('--int8', action='store_true', help='CoreML/TF INT8 quantization') - parser.add_argument('--dynamic', action='store_true', help='ONNX/TF: dynamic axes') + parser.add_argument('--dynamic', action='store_true', help='ONNX/TF/TensorRT: dynamic axes') parser.add_argument('--simplify', action='store_true', help='ONNX: simplify model') - parser.add_argument('--opset', type=int, default=13, help='ONNX: opset version') + parser.add_argument('--opset', type=int, default=17, help='ONNX: opset version') + parser.add_argument('--verbose', action='store_true', help='TensorRT: verbose log') + parser.add_argument('--workspace', type=int, default=4, help='TensorRT: workspace size (GB)') + parser.add_argument('--nms', action='store_true', help='TF: add NMS to model') + parser.add_argument('--agnostic-nms', action='store_true', help='TF: add agnostic NMS to model') parser.add_argument('--topk-per-class', type=int, default=100, help='TF.js NMS: topk per class to keep') parser.add_argument('--topk-all', type=int, default=100, help='TF.js NMS: topk for all classes to keep') parser.add_argument('--iou-thres', type=float, default=0.45, help='TF.js NMS: IoU threshold') parser.add_argument('--conf-thres', type=float, default=0.25, help='TF.js NMS: confidence threshold') - parser.add_argument('--include', nargs='+', - default=['torchscript', 'onnx'], - help='available formats are (torchscript, onnx, coreml, saved_model, pb, tflite, tfjs)') - opt = parser.parse_args() - print_args(FILE.stem, opt) + parser.add_argument( + '--include', + nargs='+', + default=['torchscript'], + help='torchscript, onnx, openvino, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle') + opt = parser.parse_known_args()[0] if known else parser.parse_args() + print_args(vars(opt)) return opt def main(opt): - run(**vars(opt)) + for opt.weights in (opt.weights if isinstance(opt.weights, list) else [opt.weights]): + run(**vars(opt)) if __name__ == "__main__": diff --git a/hubconf.py b/hubconf.py index d610aa3672..b1c45e7b56 100644 --- a/hubconf.py +++ b/hubconf.py @@ -1,52 +1,66 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license """ -PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov5/ +PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov5 Usage: import torch - model = torch.hub.load('ultralytics/yolov3', 'yolov3') + model = torch.hub.load('ultralytics/yolov5', 'yolov5s') # official model + model = torch.hub.load('ultralytics/yolov5:master', 'yolov5s') # from branch + model = torch.hub.load('ultralytics/yolov5', 'custom', 'yolov5s.pt') # custom/local model + model = torch.hub.load('.', 'custom', 'yolov5s.pt', source='local') # local repo """ import torch def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): - """Creates a specified model + """Creates or loads a YOLOv3 model Arguments: - name (str): name of model, i.e. 'yolov3' + name (str): model name 'yolov5s' or path 'path/to/best.pt' pretrained (bool): load pretrained weights into the model channels (int): number of input channels classes (int): number of model classes - autoshape (bool): apply .autoshape() wrapper to model + autoshape (bool): apply YOLOv3 .autoshape() wrapper to model verbose (bool): print all information to screen device (str, torch.device, None): device to use for model parameters Returns: - pytorch model + YOLOv3 model """ from pathlib import Path + from models.common import AutoShape, DetectMultiBackend from models.experimental import attempt_load - from models.yolo import Model + from models.yolo import ClassificationModel, DetectionModel, SegmentationModel from utils.downloads import attempt_download - from utils.general import check_requirements, intersect_dicts, set_logging + from utils.general import LOGGER, check_requirements, intersect_dicts, logging from utils.torch_utils import select_device - file = Path(__file__).resolve() - check_requirements(exclude=('tensorboard', 'thop', 'opencv-python')) - set_logging(verbose=verbose) - - save_dir = Path('') if str(name).endswith('.pt') else file.parent - path = (save_dir / name).with_suffix('.pt') # checkpoint path + if not verbose: + LOGGER.setLevel(logging.WARNING) + check_requirements(exclude=('opencv-python', 'tensorboard', 'thop')) + name = Path(name) + path = name.with_suffix('.pt') if name.suffix == '' and not name.is_dir() else name # checkpoint path try: - device = select_device(('0' if torch.cuda.is_available() else 'cpu') if device is None else device) - + device = select_device(device) if pretrained and channels == 3 and classes == 80: - model = attempt_load(path, map_location=device) # download/load FP32 model + try: + model = DetectMultiBackend(path, device=device, fuse=autoshape) # detection model + if autoshape: + if model.pt and isinstance(model.model, ClassificationModel): + LOGGER.warning('WARNING ⚠️ YOLOv3 ClassificationModel is not yet AutoShape compatible. ' + 'You must pass torch tensors in BCHW to this model, i.e. shape(1,3,224,224).') + elif model.pt and isinstance(model.model, SegmentationModel): + LOGGER.warning('WARNING ⚠️ YOLOv3 SegmentationModel is not yet AutoShape compatible. ' + 'You will not be able to run inference with this model.') + else: + model = AutoShape(model) # for file/URI/PIL/cv2/np inputs and NMS + except Exception: + model = attempt_load(path, device=device, fuse=False) # arbitrary model else: - cfg = list((Path(__file__).parent / 'models').rglob(f'{name}.yaml'))[0] # model.yaml path - model = Model(cfg, channels, classes) # create model + cfg = list((Path(__file__).parent / 'models').rglob(f'{path.stem}.yaml'))[0] # model.yaml path + model = DetectionModel(cfg, channels, classes) # create model if pretrained: ckpt = torch.load(attempt_download(path), map_location=device) # load csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 @@ -54,54 +68,102 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbo model.load_state_dict(csd, strict=False) # load if len(ckpt['model'].names) == classes: model.names = ckpt['model'].names # set class names attribute - if autoshape: - model = model.autoshape() # for file/URI/PIL/cv2/np inputs and NMS + if not verbose: + LOGGER.setLevel(logging.INFO) # reset to default return model.to(device) except Exception as e: help_url = 'https://github.com/ultralytics/yolov5/issues/36' - s = 'Cache may be out of date, try `force_reload=True`. See %s for help.' % help_url + s = f'{e}. Cache may be out of date, try `force_reload=True` or see {help_url} for help.' raise Exception(s) from e -def custom(path='path/to/model.pt', autoshape=True, verbose=True, device=None): - # custom or local model - return _create(path, autoshape=autoshape, verbose=verbose, device=device) +def custom(path='path/to/model.pt', autoshape=True, _verbose=True, device=None): + # YOLOv3 custom or local model + return _create(path, autoshape=autoshape, verbose=_verbose, device=device) -def yolov3(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): - # YOLOv3 model https://github.com/ultralytics/yolov3 - return _create('yolov3', pretrained, channels, classes, autoshape, verbose, device) +def yolov5n(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): + # YOLOv3-nano model https://github.com/ultralytics/yolov5 + return _create('yolov5n', pretrained, channels, classes, autoshape, _verbose, device) -def yolov3_spp(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): - # YOLOv3-SPP model https://github.com/ultralytics/yolov3 - return _create('yolov3-spp', pretrained, channels, classes, autoshape, verbose, device) +def yolov5s(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): + # YOLOv3-small model https://github.com/ultralytics/yolov5 + return _create('yolov5s', pretrained, channels, classes, autoshape, _verbose, device) -def yolov3_tiny(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): - # YOLOv3-tiny model https://github.com/ultralytics/yolov3 - return _create('yolov3-tiny', pretrained, channels, classes, autoshape, verbose, device) +def yolov5m(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): + # YOLOv3-medium model https://github.com/ultralytics/yolov5 + return _create('yolov5m', pretrained, channels, classes, autoshape, _verbose, device) -if __name__ == '__main__': - model = _create(name='yolov3-tiny', pretrained=True, channels=3, classes=80, autoshape=True, verbose=True) # pretrained - # model = custom(path='path/to/model.pt') # custom +def yolov5l(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): + # YOLOv3-large model https://github.com/ultralytics/yolov5 + return _create('yolov5l', pretrained, channels, classes, autoshape, _verbose, device) + + +def yolov5x(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): + # YOLOv3-xlarge model https://github.com/ultralytics/yolov5 + return _create('yolov5x', pretrained, channels, classes, autoshape, _verbose, device) + + +def yolov5n6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): + # YOLOv3-nano-P6 model https://github.com/ultralytics/yolov5 + return _create('yolov5n6', pretrained, channels, classes, autoshape, _verbose, device) + + +def yolov5s6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): + # YOLOv3-small-P6 model https://github.com/ultralytics/yolov5 + return _create('yolov5s6', pretrained, channels, classes, autoshape, _verbose, device) + + +def yolov5m6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): + # YOLOv3-medium-P6 model https://github.com/ultralytics/yolov5 + return _create('yolov5m6', pretrained, channels, classes, autoshape, _verbose, device) - # Verify inference + +def yolov5l6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): + # YOLOv3-large-P6 model https://github.com/ultralytics/yolov5 + return _create('yolov5l6', pretrained, channels, classes, autoshape, _verbose, device) + + +def yolov5x6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): + # YOLOv3-xlarge-P6 model https://github.com/ultralytics/yolov5 + return _create('yolov5x6', pretrained, channels, classes, autoshape, _verbose, device) + + +if __name__ == '__main__': + import argparse from pathlib import Path - import cv2 import numpy as np from PIL import Image - imgs = ['data/images/zidane.jpg', # filename - Path('data/images/zidane.jpg'), # Path - 'https://ultralytics.com/images/zidane.jpg', # URI - cv2.imread('data/images/bus.jpg')[:, :, ::-1], # OpenCV - Image.open('data/images/bus.jpg'), # PIL - np.zeros((320, 640, 3))] # numpy + from utils.general import cv2, print_args + + # Argparser + parser = argparse.ArgumentParser() + parser.add_argument('--model', type=str, default='yolov5s', help='model name') + opt = parser.parse_args() + print_args(vars(opt)) + + # Model + model = _create(name=opt.model, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True) + # model = custom(path='path/to/model.pt') # custom + + # Images + imgs = [ + 'data/images/zidane.jpg', # filename + Path('data/images/zidane.jpg'), # Path + 'https://ultralytics.com/images/zidane.jpg', # URI + cv2.imread('data/images/bus.jpg')[:, :, ::-1], # OpenCV + Image.open('data/images/bus.jpg'), # PIL + np.zeros((320, 640, 3))] # numpy + + # Inference + results = model(imgs, size=320) # batched inference - results = model(imgs) # batched inference + # Results results.print() results.save() diff --git a/models/common.py b/models/common.py index a76fc62826..efb668171a 100644 --- a/models/common.py +++ b/models/common.py @@ -3,12 +3,17 @@ Common modules """ +import ast +import contextlib import json import math import platform import warnings +import zipfile +from collections import OrderedDict, namedtuple from copy import copy from pathlib import Path +from urllib.parse import urlparse import cv2 import numpy as np @@ -16,30 +21,37 @@ import requests import torch import torch.nn as nn +from IPython.display import display from PIL import Image from torch.cuda import amp -from utils.datasets import exif_transpose, letterbox -from utils.general import (LOGGER, check_requirements, check_suffix, colorstr, increment_path, make_divisible, - non_max_suppression, scale_coords, xywh2xyxy, xyxy2xywh) +from utils import TryExcept +from utils.dataloaders import exif_transpose, letterbox +from utils.general import (LOGGER, ROOT, Profile, check_requirements, check_suffix, check_version, colorstr, + increment_path, is_notebook, make_divisible, non_max_suppression, scale_boxes, xywh2xyxy, + xyxy2xywh, yaml_load) from utils.plots import Annotator, colors, save_one_box -from utils.torch_utils import time_sync +from utils.torch_utils import copy_attr, smart_inference_mode -def autopad(k, p=None): # kernel, padding - # Pad to 'same' +def autopad(k, p=None, d=1): # kernel, padding, dilation + # Pad to 'same' shape outputs + if d > 1: + k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k] # actual kernel-size if p is None: p = k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-pad return p class Conv(nn.Module): - # Standard convolution - def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups + # Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation) + default_act = nn.SiLU() # default activation + + def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True): super().__init__() - self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False) + self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False) self.bn = nn.BatchNorm2d(c2) - self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) + self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity() def forward(self, x): return self.act(self.bn(self.conv(x))) @@ -49,9 +61,15 @@ def forward_fuse(self, x): class DWConv(Conv): - # Depth-wise convolution class - def __init__(self, c1, c2, k=1, s=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups - super().__init__(c1, c2, k, s, g=math.gcd(c1, c2), act=act) + # Depth-wise convolution + def __init__(self, c1, c2, k=1, s=1, d=1, act=True): # ch_in, ch_out, kernel, stride, dilation, activation + super().__init__(c1, c2, k, s, g=math.gcd(c1, c2), d=d, act=act) + + +class DWConvTranspose2d(nn.ConvTranspose2d): + # Depth-wise transpose convolution + def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0): # ch_in, ch_out, kernel, stride, padding, padding_out + super().__init__(c1, c2, k, s, p1, p2, groups=math.gcd(c1, c2)) class TransformerLayer(nn.Module): @@ -86,8 +104,8 @@ def forward(self, x): if self.conv is not None: x = self.conv(x) b, _, w, h = x.shape - p = x.flatten(2).unsqueeze(0).transpose(0, 3).squeeze(3) - return self.tr(p + self.linear(p)).unsqueeze(3).transpose(0, 3).reshape(b, self.c2, w, h) + p = x.flatten(2).permute(2, 0, 1) + return self.tr(p + self.linear(p)).permute(1, 2, 0).reshape(b, self.c2, w, h) class Bottleneck(nn.Module): @@ -119,7 +137,21 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, nu def forward(self, x): y1 = self.cv3(self.m(self.cv1(x))) y2 = self.cv2(x) - return self.cv4(self.act(self.bn(torch.cat((y1, y2), dim=1)))) + return self.cv4(self.act(self.bn(torch.cat((y1, y2), 1)))) + + +class CrossConv(nn.Module): + # Cross Convolution Downsample + def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False): + # ch_in, ch_out, kernel, stride, groups, expansion, shortcut + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, (1, k), (1, s)) + self.cv2 = Conv(c_, c2, (k, 1), (s, 1), g=g) + self.add = shortcut and c1 == c2 + + def forward(self, x): + return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) class C3(nn.Module): @@ -129,12 +161,19 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, nu c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, 1, 1) self.cv2 = Conv(c1, c_, 1, 1) - self.cv3 = Conv(2 * c_, c2, 1) # act=FReLU(c2) + self.cv3 = Conv(2 * c_, c2, 1) # optional act=FReLU(c2) self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n))) - # self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)]) def forward(self, x): - return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1)) + return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1)) + + +class C3x(C3): + # C3 module with cross-convolutions + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): + super().__init__(c1, c2, n, shortcut, g, e) + c_ = int(c2 * e) + self.m = nn.Sequential(*(CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n))) class C3TR(C3): @@ -178,7 +217,7 @@ def forward(self, x): class SPPF(nn.Module): - # Spatial Pyramid Pooling - Fast (SPPF) layer for by Glenn Jocher + # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv3 by Glenn Jocher def __init__(self, c1, c2, k=5): # equivalent to SPP(k=(5, 9, 13)) super().__init__() c_ = c1 // 2 # hidden channels @@ -192,18 +231,18 @@ def forward(self, x): warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning y1 = self.m(x) y2 = self.m(y1) - return self.cv2(torch.cat([x, y1, y2, self.m(y2)], 1)) + return self.cv2(torch.cat((x, y1, y2, self.m(y2)), 1)) class Focus(nn.Module): # Focus wh information into c-space def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups super().__init__() - self.conv = Conv(c1 * 4, c2, k, s, p, g, act) + self.conv = Conv(c1 * 4, c2, k, s, p, g, act=act) # self.contract = Contract(gain=2) def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2) - return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1)) + return self.conv(torch.cat((x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]), 1)) # return self.conv(self.contract(x)) @@ -212,12 +251,12 @@ class GhostConv(nn.Module): def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups super().__init__() c_ = c2 // 2 # hidden channels - self.cv1 = Conv(c1, c_, k, s, None, g, act) - self.cv2 = Conv(c_, c_, 5, 1, None, c_, act) + self.cv1 = Conv(c1, c_, k, s, None, g, act=act) + self.cv2 = Conv(c_, c_, 5, 1, None, c_, act=act) def forward(self, x): y = self.cv1(x) - return torch.cat([y, self.cv2(y)], 1) + return torch.cat((y, self.cv2(y)), 1) class GhostBottleneck(nn.Module): @@ -225,11 +264,12 @@ class GhostBottleneck(nn.Module): def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride super().__init__() c_ = c2 // 2 - self.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # pw - DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw - GhostConv(c_, c2, 1, 1, act=False)) # pw-linear - self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False), - Conv(c1, c2, 1, 1, act=False)) if s == 2 else nn.Identity() + self.conv = nn.Sequential( + GhostConv(c1, c_, 1, 1), # pw + DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw + GhostConv(c_, c2, 1, 1, act=False)) # pw-linear + self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False), Conv(c1, c2, 1, 1, + act=False)) if s == 2 else nn.Identity() def forward(self, x): return self.conv(x) + self.shortcut(x) @@ -274,159 +314,350 @@ def forward(self, x): class DetectMultiBackend(nn.Module): - # MultiBackend class for python inference on various backends - def __init__(self, weights='yolov3.pt', device=None, dnn=True): + # YOLOv3 MultiBackend class for python inference on various backends + def __init__(self, weights='yolov5s.pt', device=torch.device('cpu'), dnn=False, data=None, fp16=False, fuse=True): # Usage: - # PyTorch: weights = *.pt - # TorchScript: *.torchscript.pt - # CoreML: *.mlmodel - # TensorFlow: *_saved_model - # TensorFlow: *.pb - # TensorFlow Lite: *.tflite - # ONNX Runtime: *.onnx - # OpenCV DNN: *.onnx with dnn=True + # PyTorch: weights = *.pt + # TorchScript: *.torchscript + # ONNX Runtime: *.onnx + # ONNX OpenCV DNN: *.onnx --dnn + # OpenVINO: *_openvino_model + # CoreML: *.mlmodel + # TensorRT: *.engine + # TensorFlow SavedModel: *_saved_model + # TensorFlow GraphDef: *.pb + # TensorFlow Lite: *.tflite + # TensorFlow Edge TPU: *_edgetpu.tflite + # PaddlePaddle: *_paddle_model + from models.experimental import attempt_download, attempt_load # scoped to avoid circular import + super().__init__() w = str(weights[0] if isinstance(weights, list) else weights) - suffix, suffixes = Path(w).suffix.lower(), ['.pt', '.onnx', '.tflite', '.pb', '', '.mlmodel'] - check_suffix(w, suffixes) # check weights have acceptable suffix - pt, onnx, tflite, pb, saved_model, coreml = (suffix == x for x in suffixes) # backend booleans - jit = pt and 'torchscript' in w.lower() - stride, names = 64, [f'class{i}' for i in range(1000)] # assign defaults - - if jit: # TorchScript + pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle, triton = self._model_type(w) + fp16 &= pt or jit or onnx or engine # FP16 + nhwc = coreml or saved_model or pb or tflite or edgetpu # BHWC formats (vs torch BCWH) + stride = 32 # default stride + cuda = torch.cuda.is_available() and device.type != 'cpu' # use CUDA + if not (pt or triton): + w = attempt_download(w) # download if not local + + if pt: # PyTorch + model = attempt_load(weights if isinstance(weights, list) else w, device=device, inplace=True, fuse=fuse) + stride = max(int(model.stride.max()), 32) # model stride + names = model.module.names if hasattr(model, 'module') else model.names # get class names + model.half() if fp16 else model.float() + self.model = model # explicitly assign for to(), cpu(), cuda(), half() + elif jit: # TorchScript LOGGER.info(f'Loading {w} for TorchScript inference...') extra_files = {'config.txt': ''} # model metadata - model = torch.jit.load(w, _extra_files=extra_files) - if extra_files['config.txt']: - d = json.loads(extra_files['config.txt']) # extra_files dict + model = torch.jit.load(w, _extra_files=extra_files, map_location=device) + model.half() if fp16 else model.float() + if extra_files['config.txt']: # load metadata dict + d = json.loads(extra_files['config.txt'], + object_hook=lambda d: {int(k) if k.isdigit() else k: v + for k, v in d.items()}) stride, names = int(d['stride']), d['names'] - elif pt: # PyTorch - from models.experimental import attempt_load # scoped to avoid circular import - model = torch.jit.load(w) if 'torchscript' in w else attempt_load(weights, map_location=device) - stride = int(model.stride.max()) # model stride - names = model.module.names if hasattr(model, 'module') else model.names # get class names - elif coreml: # CoreML *.mlmodel - import coremltools as ct - model = ct.models.MLModel(w) elif dnn: # ONNX OpenCV DNN LOGGER.info(f'Loading {w} for ONNX OpenCV DNN inference...') - check_requirements(('opencv-python>=4.5.4',)) + check_requirements('opencv-python>=4.5.4') net = cv2.dnn.readNetFromONNX(w) elif onnx: # ONNX Runtime LOGGER.info(f'Loading {w} for ONNX Runtime inference...') - cuda = torch.cuda.is_available() check_requirements(('onnx', 'onnxruntime-gpu' if cuda else 'onnxruntime')) import onnxruntime providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] if cuda else ['CPUExecutionProvider'] session = onnxruntime.InferenceSession(w, providers=providers) - else: # TensorFlow model (TFLite, pb, saved_model) + output_names = [x.name for x in session.get_outputs()] + meta = session.get_modelmeta().custom_metadata_map # metadata + if 'stride' in meta: + stride, names = int(meta['stride']), eval(meta['names']) + elif xml: # OpenVINO + LOGGER.info(f'Loading {w} for OpenVINO inference...') + check_requirements('openvino') # requires openvino-dev: https://pypi.org/project/openvino-dev/ + from openvino.runtime import Core, Layout, get_batch + ie = Core() + if not Path(w).is_file(): # if not *.xml + w = next(Path(w).glob('*.xml')) # get *.xml file from *_openvino_model dir + network = ie.read_model(model=w, weights=Path(w).with_suffix('.bin')) + if network.get_parameters()[0].get_layout().empty: + network.get_parameters()[0].set_layout(Layout("NCHW")) + batch_dim = get_batch(network) + if batch_dim.is_static: + batch_size = batch_dim.get_length() + executable_network = ie.compile_model(network, device_name="CPU") # device_name="MYRIAD" for Intel NCS2 + stride, names = self._load_metadata(Path(w).with_suffix('.yaml')) # load metadata + elif engine: # TensorRT + LOGGER.info(f'Loading {w} for TensorRT inference...') + import tensorrt as trt # https://developer.nvidia.com/nvidia-tensorrt-download + check_version(trt.__version__, '7.0.0', hard=True) # require tensorrt>=7.0.0 + if device.type == 'cpu': + device = torch.device('cuda:0') + Binding = namedtuple('Binding', ('name', 'dtype', 'shape', 'data', 'ptr')) + logger = trt.Logger(trt.Logger.INFO) + with open(w, 'rb') as f, trt.Runtime(logger) as runtime: + model = runtime.deserialize_cuda_engine(f.read()) + context = model.create_execution_context() + bindings = OrderedDict() + output_names = [] + fp16 = False # default updated below + dynamic = False + for i in range(model.num_bindings): + name = model.get_binding_name(i) + dtype = trt.nptype(model.get_binding_dtype(i)) + if model.binding_is_input(i): + if -1 in tuple(model.get_binding_shape(i)): # dynamic + dynamic = True + context.set_binding_shape(i, tuple(model.get_profile_shape(0, i)[2])) + if dtype == np.float16: + fp16 = True + else: # output + output_names.append(name) + shape = tuple(context.get_binding_shape(i)) + im = torch.from_numpy(np.empty(shape, dtype=dtype)).to(device) + bindings[name] = Binding(name, dtype, shape, im, int(im.data_ptr())) + binding_addrs = OrderedDict((n, d.ptr) for n, d in bindings.items()) + batch_size = bindings['images'].shape[0] # if dynamic, this is instead max batch size + elif coreml: # CoreML + LOGGER.info(f'Loading {w} for CoreML inference...') + import coremltools as ct + model = ct.models.MLModel(w) + elif saved_model: # TF SavedModel + LOGGER.info(f'Loading {w} for TensorFlow SavedModel inference...') import tensorflow as tf - if pb: # https://www.tensorflow.org/guide/migrate#a_graphpb_or_graphpbtxt - def wrap_frozen_graph(gd, inputs, outputs): - x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=""), []) # wrapped - return x.prune(tf.nest.map_structure(x.graph.as_graph_element, inputs), - tf.nest.map_structure(x.graph.as_graph_element, outputs)) - - LOGGER.info(f'Loading {w} for TensorFlow *.pb inference...') - graph_def = tf.Graph().as_graph_def() - graph_def.ParseFromString(open(w, 'rb').read()) - frozen_func = wrap_frozen_graph(gd=graph_def, inputs="x:0", outputs="Identity:0") - elif saved_model: - LOGGER.info(f'Loading {w} for TensorFlow saved_model inference...') - model = tf.keras.models.load_model(w) - elif tflite: # https://www.tensorflow.org/lite/guide/python#install_tensorflow_lite_for_python - if 'edgetpu' in w.lower(): - LOGGER.info(f'Loading {w} for TensorFlow Edge TPU inference...') - import tflite_runtime.interpreter as tfli - delegate = {'Linux': 'libedgetpu.so.1', # install https://coral.ai/software/#edgetpu-runtime - 'Darwin': 'libedgetpu.1.dylib', - 'Windows': 'edgetpu.dll'}[platform.system()] - interpreter = tfli.Interpreter(model_path=w, experimental_delegates=[tfli.load_delegate(delegate)]) - else: - LOGGER.info(f'Loading {w} for TensorFlow Lite inference...') - interpreter = tf.lite.Interpreter(model_path=w) # load TFLite model - interpreter.allocate_tensors() # allocate - input_details = interpreter.get_input_details() # inputs - output_details = interpreter.get_output_details() # outputs + keras = False # assume TF1 saved_model + model = tf.keras.models.load_model(w) if keras else tf.saved_model.load(w) + elif pb: # GraphDef https://www.tensorflow.org/guide/migrate#a_graphpb_or_graphpbtxt + LOGGER.info(f'Loading {w} for TensorFlow GraphDef inference...') + import tensorflow as tf + + def wrap_frozen_graph(gd, inputs, outputs): + x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=""), []) # wrapped + ge = x.graph.as_graph_element + return x.prune(tf.nest.map_structure(ge, inputs), tf.nest.map_structure(ge, outputs)) + + def gd_outputs(gd): + name_list, input_list = [], [] + for node in gd.node: # tensorflow.core.framework.node_def_pb2.NodeDef + name_list.append(node.name) + input_list.extend(node.input) + return sorted(f'{x}:0' for x in list(set(name_list) - set(input_list)) if not x.startswith('NoOp')) + + gd = tf.Graph().as_graph_def() # TF GraphDef + with open(w, 'rb') as f: + gd.ParseFromString(f.read()) + frozen_func = wrap_frozen_graph(gd, inputs="x:0", outputs=gd_outputs(gd)) + elif tflite or edgetpu: # https://www.tensorflow.org/lite/guide/python#install_tensorflow_lite_for_python + try: # https://coral.ai/docs/edgetpu/tflite-python/#update-existing-tf-lite-code-for-the-edge-tpu + from tflite_runtime.interpreter import Interpreter, load_delegate + except ImportError: + import tensorflow as tf + Interpreter, load_delegate = tf.lite.Interpreter, tf.lite.experimental.load_delegate, + if edgetpu: # TF Edge TPU https://coral.ai/software/#edgetpu-runtime + LOGGER.info(f'Loading {w} for TensorFlow Lite Edge TPU inference...') + delegate = { + 'Linux': 'libedgetpu.so.1', + 'Darwin': 'libedgetpu.1.dylib', + 'Windows': 'edgetpu.dll'}[platform.system()] + interpreter = Interpreter(model_path=w, experimental_delegates=[load_delegate(delegate)]) + else: # TFLite + LOGGER.info(f'Loading {w} for TensorFlow Lite inference...') + interpreter = Interpreter(model_path=w) # load TFLite model + interpreter.allocate_tensors() # allocate + input_details = interpreter.get_input_details() # inputs + output_details = interpreter.get_output_details() # outputs + # load metadata + with contextlib.suppress(zipfile.BadZipFile): + with zipfile.ZipFile(w, "r") as model: + meta_file = model.namelist()[0] + meta = ast.literal_eval(model.read(meta_file).decode("utf-8")) + stride, names = int(meta['stride']), meta['names'] + elif tfjs: # TF.js + raise NotImplementedError('ERROR: YOLOv3 TF.js inference is not supported') + elif paddle: # PaddlePaddle + LOGGER.info(f'Loading {w} for PaddlePaddle inference...') + check_requirements('paddlepaddle-gpu' if cuda else 'paddlepaddle') + import paddle.inference as pdi + if not Path(w).is_file(): # if not *.pdmodel + w = next(Path(w).rglob('*.pdmodel')) # get *.pdmodel file from *_paddle_model dir + weights = Path(w).with_suffix('.pdiparams') + config = pdi.Config(str(w), str(weights)) + if cuda: + config.enable_use_gpu(memory_pool_init_size_mb=2048, device_id=0) + predictor = pdi.create_predictor(config) + input_handle = predictor.get_input_handle(predictor.get_input_names()[0]) + output_names = predictor.get_output_names() + elif triton: # NVIDIA Triton Inference Server + LOGGER.info(f'Using {w} as Triton Inference Server...') + check_requirements('tritonclient[all]') + from utils.triton import TritonRemoteModel + model = TritonRemoteModel(url=w) + nhwc = model.runtime.startswith("tensorflow") + else: + raise NotImplementedError(f'ERROR: {w} is not a supported format') + + # class names + if 'names' not in locals(): + names = yaml_load(data)['names'] if data else {i: f'class{i}' for i in range(999)} + if names[0] == 'n01440764' and len(names) == 1000: # ImageNet + names = yaml_load(ROOT / 'data/ImageNet.yaml')['names'] # human-readable names + self.__dict__.update(locals()) # assign all variables to self - def forward(self, im, augment=False, visualize=False, val=False): - # MultiBackend inference + def forward(self, im, augment=False, visualize=False): + # YOLOv3 MultiBackend inference b, ch, h, w = im.shape # batch, channel, height, width + if self.fp16 and im.dtype != torch.float16: + im = im.half() # to FP16 + if self.nhwc: + im = im.permute(0, 2, 3, 1) # torch BCHW to numpy BHWC shape(1,320,192,3) + if self.pt: # PyTorch - y = self.model(im) if self.jit else self.model(im, augment=augment, visualize=visualize) - return y if val else y[0] - elif self.coreml: # CoreML *.mlmodel - im = im.permute(0, 2, 3, 1).cpu().numpy() # torch BCHW to numpy BHWC shape(1,320,192,3) + y = self.model(im, augment=augment, visualize=visualize) if augment or visualize else self.model(im) + elif self.jit: # TorchScript + y = self.model(im) + elif self.dnn: # ONNX OpenCV DNN + im = im.cpu().numpy() # torch to numpy + self.net.setInput(im) + y = self.net.forward() + elif self.onnx: # ONNX Runtime + im = im.cpu().numpy() # torch to numpy + y = self.session.run(self.output_names, {self.session.get_inputs()[0].name: im}) + elif self.xml: # OpenVINO + im = im.cpu().numpy() # FP32 + y = list(self.executable_network([im]).values()) + elif self.engine: # TensorRT + if self.dynamic and im.shape != self.bindings['images'].shape: + i = self.model.get_binding_index('images') + self.context.set_binding_shape(i, im.shape) # reshape if dynamic + self.bindings['images'] = self.bindings['images']._replace(shape=im.shape) + for name in self.output_names: + i = self.model.get_binding_index(name) + self.bindings[name].data.resize_(tuple(self.context.get_binding_shape(i))) + s = self.bindings['images'].shape + assert im.shape == s, f"input size {im.shape} {'>' if self.dynamic else 'not equal to'} max model size {s}" + self.binding_addrs['images'] = int(im.data_ptr()) + self.context.execute_v2(list(self.binding_addrs.values())) + y = [self.bindings[x].data for x in sorted(self.output_names)] + elif self.coreml: # CoreML + im = im.cpu().numpy() im = Image.fromarray((im[0] * 255).astype('uint8')) # im = im.resize((192, 320), Image.ANTIALIAS) y = self.model.predict({'image': im}) # coordinates are xywh normalized - box = xywh2xyxy(y['coordinates'] * [[w, h, w, h]]) # xyxy pixels - conf, cls = y['confidence'].max(1), y['confidence'].argmax(1).astype(np.float) - y = np.concatenate((box, conf.reshape(-1, 1), cls.reshape(-1, 1)), 1) - elif self.onnx: # ONNX - im = im.cpu().numpy() # torch to numpy - if self.dnn: # ONNX OpenCV DNN - self.net.setInput(im) - y = self.net.forward() - else: # ONNX Runtime - y = self.session.run([self.session.get_outputs()[0].name], {self.session.get_inputs()[0].name: im})[0] - else: # TensorFlow model (TFLite, pb, saved_model) - im = im.permute(0, 2, 3, 1).cpu().numpy() # torch BCHW to numpy BHWC shape(1,320,192,3) - if self.pb: - y = self.frozen_func(x=self.tf.constant(im)).numpy() - elif self.saved_model: - y = self.model(im, training=False).numpy() - elif self.tflite: - input, output = self.input_details[0], self.output_details[0] + if 'confidence' in y: + box = xywh2xyxy(y['coordinates'] * [[w, h, w, h]]) # xyxy pixels + conf, cls = y['confidence'].max(1), y['confidence'].argmax(1).astype(np.float) + y = np.concatenate((box, conf.reshape(-1, 1), cls.reshape(-1, 1)), 1) + else: + y = list(reversed(y.values())) # reversed for segmentation models (pred, proto) + elif self.paddle: # PaddlePaddle + im = im.cpu().numpy().astype(np.float32) + self.input_handle.copy_from_cpu(im) + self.predictor.run() + y = [self.predictor.get_output_handle(x).copy_to_cpu() for x in self.output_names] + elif self.triton: # NVIDIA Triton Inference Server + y = self.model(im) + else: # TensorFlow (SavedModel, GraphDef, Lite, Edge TPU) + im = im.cpu().numpy() + if self.saved_model: # SavedModel + y = self.model(im, training=False) if self.keras else self.model(im) + elif self.pb: # GraphDef + y = self.frozen_func(x=self.tf.constant(im)) + else: # Lite or Edge TPU + input = self.input_details[0] int8 = input['dtype'] == np.uint8 # is TFLite quantized uint8 model if int8: scale, zero_point = input['quantization'] im = (im / scale + zero_point).astype(np.uint8) # de-scale self.interpreter.set_tensor(input['index'], im) self.interpreter.invoke() - y = self.interpreter.get_tensor(output['index']) - if int8: - scale, zero_point = output['quantization'] - y = (y.astype(np.float32) - zero_point) * scale # re-scale - y[..., 0] *= w # x - y[..., 1] *= h # y - y[..., 2] *= w # w - y[..., 3] *= h # h - y = torch.tensor(y) - return (y, []) if val else y + y = [] + for output in self.output_details: + x = self.interpreter.get_tensor(output['index']) + if int8: + scale, zero_point = output['quantization'] + x = (x.astype(np.float32) - zero_point) * scale # re-scale + y.append(x) + y = [x if isinstance(x, np.ndarray) else x.numpy() for x in y] + y[0][..., :4] *= [w, h, w, h] # xywh normalized to pixels + + if isinstance(y, (list, tuple)): + return self.from_numpy(y[0]) if len(y) == 1 else [self.from_numpy(x) for x in y] + else: + return self.from_numpy(y) + + def from_numpy(self, x): + return torch.from_numpy(x).to(self.device) if isinstance(x, np.ndarray) else x + + def warmup(self, imgsz=(1, 3, 640, 640)): + # Warmup model by running inference once + warmup_types = self.pt, self.jit, self.onnx, self.engine, self.saved_model, self.pb, self.triton + if any(warmup_types) and (self.device.type != 'cpu' or self.triton): + im = torch.empty(*imgsz, dtype=torch.half if self.fp16 else torch.float, device=self.device) # input + for _ in range(2 if self.jit else 1): # + self.forward(im) # warmup + + @staticmethod + def _model_type(p='path/to/model.pt'): + # Return model type from model path, i.e. path='path/to/model.onnx' -> type=onnx + # types = [pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle] + from export import export_formats + from utils.downloads import is_url + sf = list(export_formats().Suffix) # export suffixes + if not is_url(p, check=False): + check_suffix(p, sf) # checks + url = urlparse(p) # if url may be Triton inference server + types = [s in Path(p).name for s in sf] + types[8] &= not types[9] # tflite &= not edgetpu + triton = not any(types) and all([any(s in url.scheme for s in ["http", "grpc"]), url.netloc]) + return types + [triton] + + @staticmethod + def _load_metadata(f=Path('path/to/meta.yaml')): + # Load metadata from meta.yaml if it exists + if f.exists(): + d = yaml_load(f) + return d['stride'], d['names'] # assign stride, names + return None, None class AutoShape(nn.Module): - # input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS + # YOLOv3 input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS conf = 0.25 # NMS confidence threshold iou = 0.45 # NMS IoU threshold - classes = None # (optional list) filter by class, i.e. = [0, 15, 16] for COCO persons, cats and dogs + agnostic = False # NMS class-agnostic multi_label = False # NMS multiple labels per box + classes = None # (optional list) filter by class, i.e. = [0, 15, 16] for COCO persons, cats and dogs max_det = 1000 # maximum number of detections per image + amp = False # Automatic Mixed Precision (AMP) inference - def __init__(self, model): + def __init__(self, model, verbose=True): super().__init__() + if verbose: + LOGGER.info('Adding AutoShape... ') + copy_attr(self, model, include=('yaml', 'nc', 'hyp', 'names', 'stride', 'abc'), exclude=()) # copy attributes + self.dmb = isinstance(model, DetectMultiBackend) # DetectMultiBackend() instance + self.pt = not self.dmb or model.pt # PyTorch model self.model = model.eval() - - def autoshape(self): - LOGGER.info('AutoShape already enabled, skipping... ') # model already converted to model.autoshape() - return self + if self.pt: + m = self.model.model.model[-1] if self.dmb else self.model.model[-1] # Detect() + m.inplace = False # Detect.inplace=False for safe multithread inference + m.export = True # do not output loss values def _apply(self, fn): # Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers self = super()._apply(fn) - m = self.model.model[-1] # Detect() - m.stride = fn(m.stride) - m.grid = list(map(fn, m.grid)) - if isinstance(m.anchor_grid, list): - m.anchor_grid = list(map(fn, m.anchor_grid)) + if self.pt: + m = self.model.model.model[-1] if self.dmb else self.model.model[-1] # Detect() + m.stride = fn(m.stride) + m.grid = list(map(fn, m.grid)) + if isinstance(m.anchor_grid, list): + m.anchor_grid = list(map(fn, m.anchor_grid)) return self - @torch.no_grad() - def forward(self, imgs, size=640, augment=False, profile=False): - # Inference from various sources. For height=640, width=1280, RGB images example inputs are: - # file: imgs = 'data/images/zidane.jpg' # str or PosixPath + @smart_inference_mode() + def forward(self, ims, size=640, augment=False, profile=False): + # Inference from various sources. For size(height=640, width=1280), RGB images example inputs are: + # file: ims = 'data/images/zidane.jpg' # str or PosixPath # URI: = 'https://ultralytics.com/images/zidane.jpg' # OpenCV: = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(640,1280,3) # PIL: = Image.open('image.jpg') or ImageGrab.grab() # HWC x(640,1280,3) @@ -434,129 +665,139 @@ def forward(self, imgs, size=640, augment=False, profile=False): # torch: = torch.zeros(16,3,320,640) # BCHW (scaled to size=640, 0-1 values) # multiple: = [Image.open('image1.jpg'), Image.open('image2.jpg'), ...] # list of images - t = [time_sync()] - p = next(self.model.parameters()) # for device and type - if isinstance(imgs, torch.Tensor): # torch - with amp.autocast(enabled=p.device.type != 'cpu'): - return self.model(imgs.to(p.device).type_as(p), augment, profile) # inference - - # Pre-process - n, imgs = (len(imgs), imgs) if isinstance(imgs, list) else (1, [imgs]) # number of images, list of images - shape0, shape1, files = [], [], [] # image and inference shapes, filenames - for i, im in enumerate(imgs): - f = f'image{i}' # filename - if isinstance(im, (str, Path)): # filename or uri - im, f = Image.open(requests.get(im, stream=True).raw if str(im).startswith('http') else im), im - im = np.asarray(exif_transpose(im)) - elif isinstance(im, Image.Image): # PIL Image - im, f = np.asarray(exif_transpose(im)), getattr(im, 'filename', f) or f - files.append(Path(f).with_suffix('.jpg').name) - if im.shape[0] < 5: # image in CHW - im = im.transpose((1, 2, 0)) # reverse dataloader .transpose(2, 0, 1) - im = im[..., :3] if im.ndim == 3 else np.tile(im[..., None], 3) # enforce 3ch input - s = im.shape[:2] # HWC - shape0.append(s) # image shape - g = (size / max(s)) # gain - shape1.append([y * g for y in s]) - imgs[i] = im if im.data.contiguous else np.ascontiguousarray(im) # update - shape1 = [make_divisible(x, int(self.stride.max())) for x in np.stack(shape1, 0).max(0)] # inference shape - x = [letterbox(im, new_shape=shape1, auto=False)[0] for im in imgs] # pad - x = np.stack(x, 0) if n > 1 else x[0][None] # stack - x = np.ascontiguousarray(x.transpose((0, 3, 1, 2))) # BHWC to BCHW - x = torch.from_numpy(x).to(p.device).type_as(p) / 255 # uint8 to fp16/32 - t.append(time_sync()) - - with amp.autocast(enabled=p.device.type != 'cpu'): + dt = (Profile(), Profile(), Profile()) + with dt[0]: + if isinstance(size, int): # expand + size = (size, size) + p = next(self.model.parameters()) if self.pt else torch.empty(1, device=self.model.device) # param + autocast = self.amp and (p.device.type != 'cpu') # Automatic Mixed Precision (AMP) inference + if isinstance(ims, torch.Tensor): # torch + with amp.autocast(autocast): + return self.model(ims.to(p.device).type_as(p), augment=augment) # inference + + # Pre-process + n, ims = (len(ims), list(ims)) if isinstance(ims, (list, tuple)) else (1, [ims]) # number, list of images + shape0, shape1, files = [], [], [] # image and inference shapes, filenames + for i, im in enumerate(ims): + f = f'image{i}' # filename + if isinstance(im, (str, Path)): # filename or uri + im, f = Image.open(requests.get(im, stream=True).raw if str(im).startswith('http') else im), im + im = np.asarray(exif_transpose(im)) + elif isinstance(im, Image.Image): # PIL Image + im, f = np.asarray(exif_transpose(im)), getattr(im, 'filename', f) or f + files.append(Path(f).with_suffix('.jpg').name) + if im.shape[0] < 5: # image in CHW + im = im.transpose((1, 2, 0)) # reverse dataloader .transpose(2, 0, 1) + im = im[..., :3] if im.ndim == 3 else cv2.cvtColor(im, cv2.COLOR_GRAY2BGR) # enforce 3ch input + s = im.shape[:2] # HWC + shape0.append(s) # image shape + g = max(size) / max(s) # gain + shape1.append([int(y * g) for y in s]) + ims[i] = im if im.data.contiguous else np.ascontiguousarray(im) # update + shape1 = [make_divisible(x, self.stride) for x in np.array(shape1).max(0)] # inf shape + x = [letterbox(im, shape1, auto=False)[0] for im in ims] # pad + x = np.ascontiguousarray(np.array(x).transpose((0, 3, 1, 2))) # stack and BHWC to BCHW + x = torch.from_numpy(x).to(p.device).type_as(p) / 255 # uint8 to fp16/32 + + with amp.autocast(autocast): # Inference - y = self.model(x, augment, profile)[0] # forward - t.append(time_sync()) + with dt[1]: + y = self.model(x, augment=augment) # forward # Post-process - y = non_max_suppression(y, self.conf, iou_thres=self.iou, classes=self.classes, - multi_label=self.multi_label, max_det=self.max_det) # NMS - for i in range(n): - scale_coords(shape1, y[i][:, :4], shape0[i]) + with dt[2]: + y = non_max_suppression(y if self.dmb else y[0], + self.conf, + self.iou, + self.classes, + self.agnostic, + self.multi_label, + max_det=self.max_det) # NMS + for i in range(n): + scale_boxes(shape1, y[i][:, :4], shape0[i]) - t.append(time_sync()) - return Detections(imgs, y, files, t, self.names, x.shape) + return Detections(ims, y, files, dt, self.names, x.shape) class Detections: - # detections class for inference results - def __init__(self, imgs, pred, files, times=None, names=None, shape=None): + # YOLOv3 detections class for inference results + def __init__(self, ims, pred, files, times=(0, 0, 0), names=None, shape=None): super().__init__() d = pred[0].device # device - gn = [torch.tensor([*(im.shape[i] for i in [1, 0, 1, 0]), 1, 1], device=d) for im in imgs] # normalizations - self.imgs = imgs # list of images as numpy arrays + gn = [torch.tensor([*(im.shape[i] for i in [1, 0, 1, 0]), 1, 1], device=d) for im in ims] # normalizations + self.ims = ims # list of images as numpy arrays self.pred = pred # list of tensors pred[0] = (xyxy, conf, cls) self.names = names # class names self.files = files # image filenames + self.times = times # profiling times self.xyxy = pred # xyxy pixels self.xywh = [xyxy2xywh(x) for x in pred] # xywh pixels self.xyxyn = [x / g for x, g in zip(self.xyxy, gn)] # xyxy normalized self.xywhn = [x / g for x, g in zip(self.xywh, gn)] # xywh normalized self.n = len(self.pred) # number of images (batch size) - self.t = tuple((times[i + 1] - times[i]) * 1000 / self.n for i in range(3)) # timestamps (ms) - self.s = shape # inference BCHW shape + self.t = tuple(x.t / self.n * 1E3 for x in times) # timestamps (ms) + self.s = tuple(shape) # inference BCHW shape - def display(self, pprint=False, show=False, save=False, crop=False, render=False, save_dir=Path('')): - crops = [] - for i, (im, pred) in enumerate(zip(self.imgs, self.pred)): - s = f'image {i + 1}/{len(self.pred)}: {im.shape[0]}x{im.shape[1]} ' # string + def _run(self, pprint=False, show=False, save=False, crop=False, render=False, labels=True, save_dir=Path('')): + s, crops = '', [] + for i, (im, pred) in enumerate(zip(self.ims, self.pred)): + s += f'\nimage {i + 1}/{len(self.pred)}: {im.shape[0]}x{im.shape[1]} ' # string if pred.shape[0]: for c in pred[:, -1].unique(): n = (pred[:, -1] == c).sum() # detections per class s += f"{n} {self.names[int(c)]}{'s' * (n > 1)}, " # add to string + s = s.rstrip(', ') if show or save or render or crop: annotator = Annotator(im, example=str(self.names)) for *box, conf, cls in reversed(pred): # xyxy, confidence, class label = f'{self.names[int(cls)]} {conf:.2f}' if crop: file = save_dir / 'crops' / self.names[int(cls)] / self.files[i] if save else None - crops.append({'box': box, 'conf': conf, 'cls': cls, 'label': label, - 'im': save_one_box(box, im, file=file, save=save)}) + crops.append({ + 'box': box, + 'conf': conf, + 'cls': cls, + 'label': label, + 'im': save_one_box(box, im, file=file, save=save)}) else: # all others - annotator.box_label(box, label, color=colors(cls)) + annotator.box_label(box, label if labels else '', color=colors(cls)) im = annotator.im else: s += '(no detections)' im = Image.fromarray(im.astype(np.uint8)) if isinstance(im, np.ndarray) else im # from np - if pprint: - LOGGER.info(s.rstrip(', ')) if show: - im.show(self.files[i]) # show + display(im) if is_notebook() else im.show(self.files[i]) if save: f = self.files[i] im.save(save_dir / f) # save if i == self.n - 1: LOGGER.info(f"Saved {self.n} image{'s' * (self.n > 1)} to {colorstr('bold', save_dir)}") if render: - self.imgs[i] = np.asarray(im) + self.ims[i] = np.asarray(im) + if pprint: + s = s.lstrip('\n') + return f'{s}\nSpeed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {self.s}' % self.t if crop: if save: LOGGER.info(f'Saved results to {save_dir}\n') return crops - def print(self): - self.display(pprint=True) # print results - LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {tuple(self.s)}' % - self.t) - - def show(self): - self.display(show=True) # show results + @TryExcept('Showing images is not supported in this environment') + def show(self, labels=True): + self._run(show=True, labels=labels) # show results - def save(self, save_dir='runs/detect/exp'): - save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/detect/exp', mkdir=True) # increment save_dir - self.display(save=True, save_dir=save_dir) # save results + def save(self, labels=True, save_dir='runs/detect/exp', exist_ok=False): + save_dir = increment_path(save_dir, exist_ok, mkdir=True) # increment save_dir + self._run(save=True, labels=labels, save_dir=save_dir) # save results - def crop(self, save=True, save_dir='runs/detect/exp'): - save_dir = increment_path(save_dir, exist_ok=save_dir != 'runs/detect/exp', mkdir=True) if save else None - return self.display(crop=True, save=save, save_dir=save_dir) # crop results + def crop(self, save=True, save_dir='runs/detect/exp', exist_ok=False): + save_dir = increment_path(save_dir, exist_ok, mkdir=True) if save else None + return self._run(crop=True, save=save, save_dir=save_dir) # crop results - def render(self): - self.display(render=True) # render results - return self.imgs + def render(self, labels=True): + self._run(render=True, labels=labels) # render results + return self.ims def pandas(self): # return detections as pandas DataFrames, i.e. print(results.pandas().xyxy[0]) @@ -570,24 +811,57 @@ def pandas(self): def tolist(self): # return a list of Detections objects, i.e. 'for result in results.tolist():' - x = [Detections([self.imgs[i]], [self.pred[i]], self.names, self.s) for i in range(self.n)] - for d in x: - for k in ['imgs', 'pred', 'xyxy', 'xyxyn', 'xywh', 'xywhn']: - setattr(d, k, getattr(d, k)[0]) # pop out of list + r = range(self.n) # iterable + x = [Detections([self.ims[i]], [self.pred[i]], [self.files[i]], self.times, self.names, self.s) for i in r] + # for d in x: + # for k in ['ims', 'pred', 'xyxy', 'xyxyn', 'xywh', 'xywhn']: + # setattr(d, k, getattr(d, k)[0]) # pop out of list return x - def __len__(self): + def print(self): + LOGGER.info(self.__str__()) + + def __len__(self): # override len(results) return self.n + def __str__(self): # override print(results) + return self._run(pprint=True) # print results + + def __repr__(self): + return f'YOLOv3 {self.__class__} instance\n' + self.__str__() + + +class Proto(nn.Module): + # YOLOv3 mask Proto module for segmentation models + def __init__(self, c1, c_=256, c2=32): # ch_in, number of protos, number of masks + super().__init__() + self.cv1 = Conv(c1, c_, k=3) + self.upsample = nn.Upsample(scale_factor=2, mode='nearest') + self.cv2 = Conv(c_, c_, k=3) + self.cv3 = Conv(c_, c2) + + def forward(self, x): + return self.cv3(self.cv2(self.upsample(self.cv1(x)))) + class Classify(nn.Module): - # Classification head, i.e. x(b,c1,20,20) to x(b,c2) - def __init__(self, c1, c2, k=1, s=1, p=None, g=1): # ch_in, ch_out, kernel, stride, padding, groups + # YOLOv3 classification head, i.e. x(b,c1,20,20) to x(b,c2) + def __init__(self, + c1, + c2, + k=1, + s=1, + p=None, + g=1, + dropout_p=0.0): # ch_in, ch_out, kernel, stride, padding, groups, dropout probability super().__init__() - self.aap = nn.AdaptiveAvgPool2d(1) # to x(b,c1,1,1) - self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g) # to x(b,c2,1,1) - self.flat = nn.Flatten() + c_ = 1280 # efficientnet_b0 size + self.conv = Conv(c1, c_, k, s, autopad(k, p), g) + self.pool = nn.AdaptiveAvgPool2d(1) # to x(b,c_,1,1) + self.drop = nn.Dropout(p=dropout_p, inplace=True) + self.linear = nn.Linear(c_, c2) # to x(b,c2) def forward(self, x): - z = torch.cat([self.aap(y) for y in (x if isinstance(x, list) else [x])], 1) # cat if list - return self.flat(self.conv(z)) # flatten to x(b,c2) + if isinstance(x, list): + x = torch.cat(x, 1) + return self.linear(self.drop(self.pool(self.conv(x)).flatten(1))) diff --git a/models/experimental.py b/models/experimental.py index ab8266a13a..39e3ad9f12 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -8,24 +8,9 @@ import torch import torch.nn as nn -from models.common import Conv from utils.downloads import attempt_download -class CrossConv(nn.Module): - # Cross Convolution Downsample - def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False): - # ch_in, ch_out, kernel, stride, groups, expansion, shortcut - super().__init__() - c_ = int(c2 * e) # hidden channels - self.cv1 = Conv(c1, c_, (1, k), (1, s)) - self.cv2 = Conv(c_, c2, (k, 1), (s, 1), g=g) - self.add = shortcut and c1 == c2 - - def forward(self, x): - return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) - - class Sum(nn.Module): # Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 def __init__(self, n, weight=False): # n: number of inputs @@ -63,8 +48,8 @@ def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): # ch_in, ch_out, kern a[0] = 1 c_ = np.linalg.lstsq(a, b, rcond=None)[0].round() # solve for equal weight indices, ax = b - self.m = nn.ModuleList( - [nn.Conv2d(c1, int(c_), k, s, k // 2, groups=math.gcd(c1, int(c_)), bias=False) for k, c_ in zip(k, c_)]) + self.m = nn.ModuleList([ + nn.Conv2d(c1, int(c_), k, s, k // 2, groups=math.gcd(c1, int(c_)), bias=False) for k, c_ in zip(k, c_)]) self.bn = nn.BatchNorm2d(c2) self.act = nn.SiLU() @@ -78,44 +63,49 @@ def __init__(self): super().__init__() def forward(self, x, augment=False, profile=False, visualize=False): - y = [] - for module in self: - y.append(module(x, augment, profile, visualize)[0]) + y = [module(x, augment, profile, visualize)[0] for module in self] # y = torch.stack(y).max(0)[0] # max ensemble # y = torch.stack(y).mean(0) # mean ensemble y = torch.cat(y, 1) # nms ensemble return y, None # inference, train output -def attempt_load(weights, map_location=None, inplace=True, fuse=True): +def attempt_load(weights, device=None, inplace=True, fuse=True): + # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a from models.yolo import Detect, Model - # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a model = Ensemble() for w in weights if isinstance(weights, list) else [weights]: - ckpt = torch.load(attempt_download(w), map_location=map_location) # load - ckpt = (ckpt['ema'] or ckpt['model']).float() # FP32 model - model.append(ckpt.fuse().eval() if fuse else ckpt.eval()) # fused or un-fused model in eval mode + ckpt = torch.load(attempt_download(w), map_location='cpu') # load + ckpt = (ckpt.get('ema') or ckpt['model']).to(device).float() # FP32 model + + # Model compatibility updates + if not hasattr(ckpt, 'stride'): + ckpt.stride = torch.tensor([32.]) + if hasattr(ckpt, 'names') and isinstance(ckpt.names, (list, tuple)): + ckpt.names = dict(enumerate(ckpt.names)) # convert to dict + + model.append(ckpt.fuse().eval() if fuse and hasattr(ckpt, 'fuse') else ckpt.eval()) # model in eval mode - # Compatibility updates + # Module compatibility updates for m in model.modules(): t = type(m) if t in (nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Model): m.inplace = inplace # torch 1.7.0 compatibility - if t is Detect: - if not isinstance(m.anchor_grid, list): # new Detect Layer compatibility - delattr(m, 'anchor_grid') - setattr(m, 'anchor_grid', [torch.zeros(1)] * m.nl) - elif t is Conv: - m._non_persistent_buffers_set = set() # torch 1.6.0 compatibility + if t is Detect and not isinstance(m.anchor_grid, list): + delattr(m, 'anchor_grid') + setattr(m, 'anchor_grid', [torch.zeros(1)] * m.nl) elif t is nn.Upsample and not hasattr(m, 'recompute_scale_factor'): m.recompute_scale_factor = None # torch 1.11.0 compatibility + # Return model if len(model) == 1: - return model[-1] # return model - else: - print(f'Ensemble created with {weights}\n') - for k in ['names']: - setattr(model, k, getattr(model[-1], k)) - model.stride = model[torch.argmax(torch.tensor([m.stride.max() for m in model])).int()].stride # max stride - return model # return ensemble + return model[-1] + + # Return detection ensemble + print(f'Ensemble created with {weights}\n') + for k in 'names', 'nc', 'yaml': + setattr(model, k, getattr(model[0], k)) + model.stride = model[torch.argmax(torch.tensor([m.stride.max() for m in model])).int()].stride # max stride + assert all(model[0].nc == m.nc for m in model), f'Models have different class counts: {[m.nc for m in model]}' + return model diff --git a/models/hub/anchors.yaml b/models/hub/anchors.yaml new file mode 100644 index 0000000000..fc252c1927 --- /dev/null +++ b/models/hub/anchors.yaml @@ -0,0 +1,59 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# Default anchors for COCO data + + +# P5 ------------------------------------------------------------------------------------------------------------------- +# P5-640: +anchors_p5_640: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + + +# P6 ------------------------------------------------------------------------------------------------------------------- +# P6-640: thr=0.25: 0.9964 BPR, 5.54 anchors past thr, n=12, img_size=640, metric_all=0.281/0.716-mean/best, past_thr=0.469-mean: 9,11, 21,19, 17,41, 43,32, 39,70, 86,64, 65,131, 134,130, 120,265, 282,180, 247,354, 512,387 +anchors_p6_640: + - [9,11, 21,19, 17,41] # P3/8 + - [43,32, 39,70, 86,64] # P4/16 + - [65,131, 134,130, 120,265] # P5/32 + - [282,180, 247,354, 512,387] # P6/64 + +# P6-1280: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1280, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +anchors_p6_1280: + - [19,27, 44,40, 38,94] # P3/8 + - [96,68, 86,152, 180,137] # P4/16 + - [140,301, 303,264, 238,542] # P5/32 + - [436,615, 739,380, 925,792] # P6/64 + +# P6-1920: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1920, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 28,41, 67,59, 57,141, 144,103, 129,227, 270,205, 209,452, 455,396, 358,812, 653,922, 1109,570, 1387,1187 +anchors_p6_1920: + - [28,41, 67,59, 57,141] # P3/8 + - [144,103, 129,227, 270,205] # P4/16 + - [209,452, 455,396, 358,812] # P5/32 + - [653,922, 1109,570, 1387,1187] # P6/64 + + +# P7 ------------------------------------------------------------------------------------------------------------------- +# P7-640: thr=0.25: 0.9962 BPR, 6.76 anchors past thr, n=15, img_size=640, metric_all=0.275/0.733-mean/best, past_thr=0.466-mean: 11,11, 13,30, 29,20, 30,46, 61,38, 39,92, 78,80, 146,66, 79,163, 149,150, 321,143, 157,303, 257,402, 359,290, 524,372 +anchors_p7_640: + - [11,11, 13,30, 29,20] # P3/8 + - [30,46, 61,38, 39,92] # P4/16 + - [78,80, 146,66, 79,163] # P5/32 + - [149,150, 321,143, 157,303] # P6/64 + - [257,402, 359,290, 524,372] # P7/128 + +# P7-1280: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1280, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 19,22, 54,36, 32,77, 70,83, 138,71, 75,173, 165,159, 148,334, 375,151, 334,317, 251,626, 499,474, 750,326, 534,814, 1079,818 +anchors_p7_1280: + - [19,22, 54,36, 32,77] # P3/8 + - [70,83, 138,71, 75,173] # P4/16 + - [165,159, 148,334, 375,151] # P5/32 + - [334,317, 251,626, 499,474] # P6/64 + - [750,326, 534,814, 1079,818] # P7/128 + +# P7-1920: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1920, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 29,34, 81,55, 47,115, 105,124, 207,107, 113,259, 247,238, 222,500, 563,227, 501,476, 376,939, 749,711, 1126,489, 801,1222, 1618,1227 +anchors_p7_1920: + - [29,34, 81,55, 47,115] # P3/8 + - [105,124, 207,107, 113,259] # P4/16 + - [247,238, 222,500, 563,227] # P5/32 + - [501,476, 376,939, 749,711] # P6/64 + - [1126,489, 801,1222, 1618,1227] # P7/128 diff --git a/models/hub/yolov5-bifpn.yaml b/models/hub/yolov5-bifpn.yaml new file mode 100644 index 0000000000..7d17a347c3 --- /dev/null +++ b/models/hub/yolov5-bifpn.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 BiFPN head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14, 6], 1, Concat, [1]], # cat P4 <--- BiFPN change + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/models/hub/yolov5-fpn.yaml b/models/hub/yolov5-fpn.yaml new file mode 100644 index 0000000000..0c91f931c0 --- /dev/null +++ b/models/hub/yolov5-fpn.yaml @@ -0,0 +1,42 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 FPN head +head: + [[-1, 3, C3, [1024, False]], # 10 (P5/32-large) + + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 1, Conv, [512, 1, 1]], + [-1, 3, C3, [512, False]], # 14 (P4/16-medium) + + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 1, Conv, [256, 1, 1]], + [-1, 3, C3, [256, False]], # 18 (P3/8-small) + + [[18, 14, 10], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/models/hub/yolov5-p2.yaml b/models/hub/yolov5-p2.yaml new file mode 100644 index 0000000000..23264db05c --- /dev/null +++ b/models/hub/yolov5-p2.yaml @@ -0,0 +1,54 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: 3 # AutoAnchor evolves 3 anchors per P output layer + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head with (P2, P3, P4, P5) outputs +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 2], 1, Concat, [1]], # cat backbone P2 + [-1, 1, C3, [128, False]], # 21 (P2/4-xsmall) + + [-1, 1, Conv, [128, 3, 2]], + [[-1, 18], 1, Concat, [1]], # cat head P3 + [-1, 3, C3, [256, False]], # 24 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 27 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 30 (P5/32-large) + + [[21, 24, 27, 30], 1, Detect, [nc, anchors]], # Detect(P2, P3, P4, P5) + ] diff --git a/models/hub/yolov5-p34.yaml b/models/hub/yolov5-p34.yaml new file mode 100644 index 0000000000..c7f76e3052 --- /dev/null +++ b/models/hub/yolov5-p34.yaml @@ -0,0 +1,41 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.50 # layer channel multiple +anchors: 3 # AutoAnchor evolves 3 anchors per P output layer + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head with (P3, P4) outputs +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [[17, 20], 1, Detect, [nc, anchors]], # Detect(P3, P4) + ] diff --git a/models/hub/yolov5-p6.yaml b/models/hub/yolov5-p6.yaml new file mode 100644 index 0000000000..a7b79a574d --- /dev/null +++ b/models/hub/yolov5-p6.yaml @@ -0,0 +1,56 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: 3 # AutoAnchor evolves 3 anchors per P output layer + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 11 + ] + +# YOLOv5 v6.0 head with (P3, P4, P5, P6) outputs +head: + [[-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 15 + + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 19 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 23 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 20], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 26 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 16], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 29 (P5/32-large) + + [-1, 1, Conv, [768, 3, 2]], + [[-1, 12], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) + + [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) + ] diff --git a/models/hub/yolov5-p7.yaml b/models/hub/yolov5-p7.yaml new file mode 100644 index 0000000000..3846496bce --- /dev/null +++ b/models/hub/yolov5-p7.yaml @@ -0,0 +1,67 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: 3 # AutoAnchor evolves 3 anchors per P output layer + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, Conv, [1280, 3, 2]], # 11-P7/128 + [-1, 3, C3, [1280]], + [-1, 1, SPPF, [1280, 5]], # 13 + ] + +# YOLOv5 v6.0 head with (P3, P4, P5, P6, P7) outputs +head: + [[-1, 1, Conv, [1024, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 10], 1, Concat, [1]], # cat backbone P6 + [-1, 3, C3, [1024, False]], # 17 + + [-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 21 + + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 25 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 29 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 26], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 32 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 22], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 35 (P5/32-large) + + [-1, 1, Conv, [768, 3, 2]], + [[-1, 18], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 38 (P6/64-xlarge) + + [-1, 1, Conv, [1024, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P7 + [-1, 3, C3, [1280, False]], # 41 (P7/128-xxlarge) + + [[29, 32, 35, 38, 41], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6, P7) + ] diff --git a/models/hub/yolov5-panet.yaml b/models/hub/yolov5-panet.yaml new file mode 100644 index 0000000000..9a9a34dd56 --- /dev/null +++ b/models/hub/yolov5-panet.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 PANet head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/models/hub/yolov5l6.yaml b/models/hub/yolov5l6.yaml new file mode 100644 index 0000000000..e9f03b3494 --- /dev/null +++ b/models/hub/yolov5l6.yaml @@ -0,0 +1,60 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: + - [19,27, 44,40, 38,94] # P3/8 + - [96,68, 86,152, 180,137] # P4/16 + - [140,301, 303,264, 238,542] # P5/32 + - [436,615, 739,380, 925,792] # P6/64 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 11 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 15 + + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 19 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 23 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 20], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 26 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 16], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 29 (P5/32-large) + + [-1, 1, Conv, [768, 3, 2]], + [[-1, 12], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) + + [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) + ] diff --git a/models/hub/yolov5m6.yaml b/models/hub/yolov5m6.yaml new file mode 100644 index 0000000000..7077be1abf --- /dev/null +++ b/models/hub/yolov5m6.yaml @@ -0,0 +1,60 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 0.67 # model depth multiple +width_multiple: 0.75 # layer channel multiple +anchors: + - [19,27, 44,40, 38,94] # P3/8 + - [96,68, 86,152, 180,137] # P4/16 + - [140,301, 303,264, 238,542] # P5/32 + - [436,615, 739,380, 925,792] # P6/64 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 11 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 15 + + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 19 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 23 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 20], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 26 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 16], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 29 (P5/32-large) + + [-1, 1, Conv, [768, 3, 2]], + [[-1, 12], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) + + [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) + ] diff --git a/models/hub/yolov5n6.yaml b/models/hub/yolov5n6.yaml new file mode 100644 index 0000000000..2b4374c805 --- /dev/null +++ b/models/hub/yolov5n6.yaml @@ -0,0 +1,60 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.25 # layer channel multiple +anchors: + - [19,27, 44,40, 38,94] # P3/8 + - [96,68, 86,152, 180,137] # P4/16 + - [140,301, 303,264, 238,542] # P5/32 + - [436,615, 739,380, 925,792] # P6/64 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 11 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 15 + + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 19 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 23 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 20], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 26 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 16], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 29 (P5/32-large) + + [-1, 1, Conv, [768, 3, 2]], + [[-1, 12], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) + + [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) + ] diff --git a/models/hub/yolov5s-LeakyReLU.yaml b/models/hub/yolov5s-LeakyReLU.yaml new file mode 100644 index 0000000000..0d3dbc0dd2 --- /dev/null +++ b/models/hub/yolov5s-LeakyReLU.yaml @@ -0,0 +1,49 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +activation: nn.LeakyReLU(0.1) # <----- Conv() activation used throughout entire YOLOv5 model +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.50 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/models/hub/yolov5s-ghost.yaml b/models/hub/yolov5s-ghost.yaml new file mode 100644 index 0000000000..e8bbcfe3b2 --- /dev/null +++ b/models/hub/yolov5s-ghost.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.50 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, GhostConv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3Ghost, [128]], + [-1, 1, GhostConv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3Ghost, [256]], + [-1, 1, GhostConv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3Ghost, [512]], + [-1, 1, GhostConv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3Ghost, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, GhostConv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3Ghost, [512, False]], # 13 + + [-1, 1, GhostConv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3Ghost, [256, False]], # 17 (P3/8-small) + + [-1, 1, GhostConv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3Ghost, [512, False]], # 20 (P4/16-medium) + + [-1, 1, GhostConv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3Ghost, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/models/hub/yolov5s-transformer.yaml b/models/hub/yolov5s-transformer.yaml new file mode 100644 index 0000000000..a0a3ce8e82 --- /dev/null +++ b/models/hub/yolov5s-transformer.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.50 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3TR, [1024]], # 9 <--- C3TR() Transformer module + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/models/hub/yolov5s6.yaml b/models/hub/yolov5s6.yaml new file mode 100644 index 0000000000..85f3ef5ad1 --- /dev/null +++ b/models/hub/yolov5s6.yaml @@ -0,0 +1,60 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.50 # layer channel multiple +anchors: + - [19,27, 44,40, 38,94] # P3/8 + - [96,68, 86,152, 180,137] # P4/16 + - [140,301, 303,264, 238,542] # P5/32 + - [436,615, 739,380, 925,792] # P6/64 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 11 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 15 + + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 19 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 23 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 20], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 26 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 16], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 29 (P5/32-large) + + [-1, 1, Conv, [768, 3, 2]], + [[-1, 12], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) + + [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) + ] diff --git a/models/hub/yolov5x6.yaml b/models/hub/yolov5x6.yaml new file mode 100644 index 0000000000..290da47dd0 --- /dev/null +++ b/models/hub/yolov5x6.yaml @@ -0,0 +1,60 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.33 # model depth multiple +width_multiple: 1.25 # layer channel multiple +anchors: + - [19,27, 44,40, 38,94] # P3/8 + - [96,68, 86,152, 180,137] # P4/16 + - [140,301, 303,264, 238,542] # P5/32 + - [436,615, 739,380, 925,792] # P6/64 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 11 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 15 + + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 19 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 23 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 20], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 26 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 16], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 29 (P5/32-large) + + [-1, 1, Conv, [768, 3, 2]], + [[-1, 12], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) + + [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) + ] diff --git a/models/segment/yolov5l-seg.yaml b/models/segment/yolov5l-seg.yaml new file mode 100644 index 0000000000..ac06eb8713 --- /dev/null +++ b/models/segment/yolov5l-seg.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) + ] diff --git a/models/segment/yolov5m-seg.yaml b/models/segment/yolov5m-seg.yaml new file mode 100644 index 0000000000..febe93f644 --- /dev/null +++ b/models/segment/yolov5m-seg.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 0.67 # model depth multiple +width_multiple: 0.75 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) + ] \ No newline at end of file diff --git a/models/segment/yolov5n-seg.yaml b/models/segment/yolov5n-seg.yaml new file mode 100644 index 0000000000..21635c3c95 --- /dev/null +++ b/models/segment/yolov5n-seg.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.25 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) + ] diff --git a/models/segment/yolov5s-seg.yaml b/models/segment/yolov5s-seg.yaml new file mode 100644 index 0000000000..3b31ed3a3c --- /dev/null +++ b/models/segment/yolov5s-seg.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.5 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) + ] \ No newline at end of file diff --git a/models/segment/yolov5x-seg.yaml b/models/segment/yolov5x-seg.yaml new file mode 100644 index 0000000000..5a95b92f08 --- /dev/null +++ b/models/segment/yolov5x-seg.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.33 # model depth multiple +width_multiple: 1.25 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) + ] diff --git a/models/tf.py b/models/tf.py index 956ef2bdee..4c40877657 100644 --- a/models/tf.py +++ b/models/tf.py @@ -1,25 +1,22 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license """ -TensorFlow, Keras and TFLite versions of +TensorFlow, Keras and TFLite versions of YOLOv3 Authored by https://github.com/zldrobit in PR https://github.com/ultralytics/yolov5/pull/1127 Usage: - $ python models/tf.py --weights yolov3.pt + $ python models/tf.py --weights yolov5s.pt Export: - $ python path/to/export.py --weights yolov3.pt --include saved_model pb tflite tfjs + $ python export.py --weights yolov5s.pt --include saved_model pb tflite tfjs """ import argparse -import logging import sys from copy import deepcopy from pathlib import Path -from packaging import version - FILE = Path(__file__).resolve() -ROOT = FILE.parents[1] # root directory +ROOT = FILE.parents[1] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH # ROOT = ROOT.relative_to(Path.cwd()) # relative @@ -28,21 +25,15 @@ import tensorflow as tf import torch import torch.nn as nn -from keras import backend -from keras.engine.base_layer import Layer -from keras.engine.input_spec import InputSpec -from keras.utils import conv_utils from tensorflow import keras -from models.common import C3, SPP, SPPF, Bottleneck, BottleneckCSP, Concat, Conv, DWConv, Focus, autopad -from models.experimental import CrossConv, MixConv2d, attempt_load -from models.yolo import Detect +from models.common import (C3, SPP, SPPF, Bottleneck, BottleneckCSP, C3x, Concat, Conv, CrossConv, DWConv, + DWConvTranspose2d, Focus, autopad) +from models.experimental import MixConv2d, attempt_load +from models.yolo import Detect, Segment from utils.activations import SiLU from utils.general import LOGGER, make_divisible, print_args -# isort: off -from tensorflow.python.util.tf_export import keras_export - class TFBN(keras.layers.Layer): # TensorFlow BatchNormalization wrapper @@ -59,33 +50,14 @@ def call(self, inputs): return self.bn(inputs) -class TFMaxPool2d(keras.layers.Layer): - # TensorFlow MAX Pooling - def __init__(self, k, s, p, w=None): - super().__init__() - self.pool = keras.layers.MaxPool2D(pool_size=k, strides=s, padding='valid') - - def call(self, inputs): - return self.pool(inputs) - - -class TFZeroPad2d(keras.layers.Layer): - # TensorFlow MAX Pooling - def __init__(self, p, w=None): - super().__init__() - if version.parse(tf.__version__) < version.parse('2.11.0'): - self.zero_pad = ZeroPadding2D(padding=p) - else: - self.zero_pad = keras.layers.ZeroPadding2D(padding=((p[0], p[1]), (p[2], p[3]))) - - def call(self, inputs): - return self.zero_pad(inputs) - - class TFPad(keras.layers.Layer): + # Pad inputs in spatial dimensions 1 and 2 def __init__(self, pad): super().__init__() - self.pad = tf.constant([[0, 0], [pad, pad], [pad, pad], [0, 0]]) + if isinstance(pad, int): + self.pad = tf.constant([[0, 0], [pad, pad], [pad, pad], [0, 0]]) + else: # tuple/list + self.pad = tf.constant([[0, 0], [pad[0], pad[0]], [pad[1], pad[1]], [0, 0]]) def call(self, inputs): return tf.pad(inputs, self.pad, mode='constant', constant_values=0) @@ -97,31 +69,69 @@ def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None): # ch_in, ch_out, weights, kernel, stride, padding, groups super().__init__() assert g == 1, "TF v2.2 Conv2D does not support 'groups' argument" - assert isinstance(k, int), "Convolution with multiple kernels are not allowed." # TensorFlow convolution padding is inconsistent with PyTorch (e.g. k=3 s=2 'SAME' padding) # see https://stackoverflow.com/questions/52975843/comparing-conv2d-with-padding-between-tensorflow-and-pytorch - conv = keras.layers.Conv2D( - c2, k, s, 'SAME' if s == 1 else 'VALID', use_bias=False if hasattr(w, 'bn') else True, + filters=c2, + kernel_size=k, + strides=s, + padding='SAME' if s == 1 else 'VALID', + use_bias=not hasattr(w, 'bn'), kernel_initializer=keras.initializers.Constant(w.conv.weight.permute(2, 3, 1, 0).numpy()), bias_initializer='zeros' if hasattr(w, 'bn') else keras.initializers.Constant(w.conv.bias.numpy())) self.conv = conv if s == 1 else keras.Sequential([TFPad(autopad(k, p)), conv]) self.bn = TFBN(w.bn) if hasattr(w, 'bn') else tf.identity + self.act = activations(w.act) if act else tf.identity + + def call(self, inputs): + return self.act(self.bn(self.conv(inputs))) - # activations - if isinstance(w.act, nn.LeakyReLU): - self.act = (lambda x: keras.activations.relu(x, alpha=0.1)) if act else tf.identity - elif isinstance(w.act, nn.Hardswish): - self.act = (lambda x: x * tf.nn.relu6(x + 3) * 0.166666667) if act else tf.identity - elif isinstance(w.act, (nn.SiLU, SiLU)): - self.act = (lambda x: keras.activations.swish(x)) if act else tf.identity - else: - raise Exception(f'no matching TensorFlow activation found for {w.act}') + +class TFDWConv(keras.layers.Layer): + # Depthwise convolution + def __init__(self, c1, c2, k=1, s=1, p=None, act=True, w=None): + # ch_in, ch_out, weights, kernel, stride, padding, groups + super().__init__() + assert c2 % c1 == 0, f'TFDWConv() output={c2} must be a multiple of input={c1} channels' + conv = keras.layers.DepthwiseConv2D( + kernel_size=k, + depth_multiplier=c2 // c1, + strides=s, + padding='SAME' if s == 1 else 'VALID', + use_bias=not hasattr(w, 'bn'), + depthwise_initializer=keras.initializers.Constant(w.conv.weight.permute(2, 3, 1, 0).numpy()), + bias_initializer='zeros' if hasattr(w, 'bn') else keras.initializers.Constant(w.conv.bias.numpy())) + self.conv = conv if s == 1 else keras.Sequential([TFPad(autopad(k, p)), conv]) + self.bn = TFBN(w.bn) if hasattr(w, 'bn') else tf.identity + self.act = activations(w.act) if act else tf.identity def call(self, inputs): return self.act(self.bn(self.conv(inputs))) +class TFDWConvTranspose2d(keras.layers.Layer): + # Depthwise ConvTranspose2d + def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0, w=None): + # ch_in, ch_out, weights, kernel, stride, padding, groups + super().__init__() + assert c1 == c2, f'TFDWConv() output={c2} must be equal to input={c1} channels' + assert k == 4 and p1 == 1, 'TFDWConv() only valid for k=4 and p1=1' + weight, bias = w.weight.permute(2, 3, 1, 0).numpy(), w.bias.numpy() + self.c1 = c1 + self.conv = [ + keras.layers.Conv2DTranspose(filters=1, + kernel_size=k, + strides=s, + padding='VALID', + output_padding=p2, + use_bias=True, + kernel_initializer=keras.initializers.Constant(weight[..., i:i + 1]), + bias_initializer=keras.initializers.Constant(bias[i])) for i in range(c1)] + + def call(self, inputs): + return tf.concat([m(x) for m, x in zip(self.conv, tf.split(inputs, self.c1, 3))], 3)[:, 1:-1, 1:-1] + + class TFFocus(keras.layers.Layer): # Focus wh information into c-space def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None): @@ -131,10 +141,8 @@ def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None): def call(self, inputs): # x(b,w,h,c) -> y(b,w/2,h/2,4c) # inputs = inputs / 255 # normalize 0-255 to 0-1 - return self.conv(tf.concat([inputs[:, ::2, ::2, :], - inputs[:, 1::2, ::2, :], - inputs[:, ::2, 1::2, :], - inputs[:, 1::2, 1::2, :]], 3)) + inputs = [inputs[:, ::2, ::2, :], inputs[:, 1::2, ::2, :], inputs[:, ::2, 1::2, :], inputs[:, 1::2, 1::2, :]] + return self.conv(tf.concat(inputs, 3)) class TFBottleneck(keras.layers.Layer): @@ -150,15 +158,32 @@ def call(self, inputs): return inputs + self.cv2(self.cv1(inputs)) if self.add else self.cv2(self.cv1(inputs)) +class TFCrossConv(keras.layers.Layer): + # Cross Convolution + def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False, w=None): + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = TFConv(c1, c_, (1, k), (1, s), w=w.cv1) + self.cv2 = TFConv(c_, c2, (k, 1), (s, 1), g=g, w=w.cv2) + self.add = shortcut and c1 == c2 + + def call(self, inputs): + return inputs + self.cv2(self.cv1(inputs)) if self.add else self.cv2(self.cv1(inputs)) + + class TFConv2d(keras.layers.Layer): # Substitution for PyTorch nn.Conv2D def __init__(self, c1, c2, k, s=1, g=1, bias=True, w=None): super().__init__() assert g == 1, "TF v2.2 Conv2D does not support 'groups' argument" - self.conv = keras.layers.Conv2D( - c2, k, s, 'VALID', use_bias=bias, - kernel_initializer=keras.initializers.Constant(w.weight.permute(2, 3, 1, 0).numpy()), - bias_initializer=keras.initializers.Constant(w.bias.numpy()) if bias else None, ) + self.conv = keras.layers.Conv2D(filters=c2, + kernel_size=k, + strides=s, + padding='VALID', + use_bias=bias, + kernel_initializer=keras.initializers.Constant( + w.weight.permute(2, 3, 1, 0).numpy()), + bias_initializer=keras.initializers.Constant(w.bias.numpy()) if bias else None) def call(self, inputs): return self.conv(inputs) @@ -175,7 +200,7 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): self.cv3 = TFConv2d(c_, c_, 1, 1, bias=False, w=w.cv3) self.cv4 = TFConv(2 * c_, c2, 1, 1, w=w.cv4) self.bn = TFBN(w.bn) - self.act = lambda x: keras.activations.relu(x, alpha=0.1) + self.act = lambda x: keras.activations.swish(x) self.m = keras.Sequential([TFBottleneck(c_, c_, shortcut, g, e=1.0, w=w.m[j]) for j in range(n)]) def call(self, inputs): @@ -199,6 +224,22 @@ def call(self, inputs): return self.cv3(tf.concat((self.m(self.cv1(inputs)), self.cv2(inputs)), axis=3)) +class TFC3x(keras.layers.Layer): + # 3 module with cross-convolutions + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): + # ch_in, ch_out, number, shortcut, groups, expansion + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) + self.cv2 = TFConv(c1, c_, 1, 1, w=w.cv2) + self.cv3 = TFConv(2 * c_, c2, 1, 1, w=w.cv3) + self.m = keras.Sequential([ + TFCrossConv(c_, c_, k=3, s=1, g=g, e=1.0, shortcut=shortcut, w=w.m[j]) for j in range(n)]) + + def call(self, inputs): + return self.cv3(tf.concat((self.m(self.cv1(inputs)), self.cv2(inputs)), axis=3)) + + class TFSPP(keras.layers.Layer): # Spatial pyramid pooling layer used in YOLOv3-SPP def __init__(self, c1, c2, k=(5, 9, 13), w=None): @@ -230,6 +271,7 @@ def call(self, inputs): class TFDetect(keras.layers.Layer): + # TF YOLOv3 Detect layer def __init__(self, nc=80, anchors=(), ch=(), imgsz=(640, 640), w=None): # detection layer super().__init__() self.stride = tf.convert_to_tensor(w.stride.numpy(), dtype=tf.float32) @@ -239,8 +281,7 @@ def __init__(self, nc=80, anchors=(), ch=(), imgsz=(640, 640), w=None): # detec self.na = len(anchors[0]) // 2 # number of anchors self.grid = [tf.zeros(1)] * self.nl # init grid self.anchors = tf.convert_to_tensor(w.anchors.numpy(), dtype=tf.float32) - self.anchor_grid = tf.reshape(self.anchors * tf.reshape(self.stride, [self.nl, 1, 1]), - [self.nl, 1, -1, 1, 2]) + self.anchor_grid = tf.reshape(self.anchors * tf.reshape(self.stride, [self.nl, 1, 1]), [self.nl, 1, -1, 1, 2]) self.m = [TFConv2d(x, self.no * self.na, 1, w=w.m[i]) for i, x in enumerate(ch)] self.training = False # set to False after building model self.imgsz = imgsz @@ -255,19 +296,21 @@ def call(self, inputs): x.append(self.m[i](inputs[i])) # x(bs,20,20,255) to x(bs,3,20,20,85) ny, nx = self.imgsz[0] // self.stride[i], self.imgsz[1] // self.stride[i] - x[i] = tf.transpose(tf.reshape(x[i], [-1, ny * nx, self.na, self.no]), [0, 2, 1, 3]) + x[i] = tf.reshape(x[i], [-1, ny * nx, self.na, self.no]) if not self.training: # inference - y = tf.sigmoid(x[i]) - xy = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i] # xy - wh = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] + y = x[i] + grid = tf.transpose(self.grid[i], [0, 2, 1, 3]) - 0.5 + anchor_grid = tf.transpose(self.anchor_grid[i], [0, 2, 1, 3]) * 4 + xy = (tf.sigmoid(y[..., 0:2]) * 2 + grid) * self.stride[i] # xy + wh = tf.sigmoid(y[..., 2:4]) ** 2 * anchor_grid # Normalize xywh to 0-1 to reduce calibration error xy /= tf.constant([[self.imgsz[1], self.imgsz[0]]], dtype=tf.float32) wh /= tf.constant([[self.imgsz[1], self.imgsz[0]]], dtype=tf.float32) - y = tf.concat([xy, wh, y[..., 4:]], -1) - z.append(tf.reshape(y, [-1, 3 * ny * nx, self.no])) + y = tf.concat([xy, wh, tf.sigmoid(y[..., 4:5 + self.nc]), y[..., 5 + self.nc:]], -1) + z.append(tf.reshape(y, [-1, self.na * ny * nx, self.no])) - return x if self.training else (tf.concat(z, 1), x) + return tf.transpose(x, [0, 2, 1, 3]) if self.training else (tf.concat(z, 1),) @staticmethod def _make_grid(nx=20, ny=20): @@ -277,11 +320,44 @@ def _make_grid(nx=20, ny=20): return tf.cast(tf.reshape(tf.stack([xv, yv], 2), [1, 1, ny * nx, 2]), dtype=tf.float32) +class TFSegment(TFDetect): + # YOLOv3 Segment head for segmentation models + def __init__(self, nc=80, anchors=(), nm=32, npr=256, ch=(), imgsz=(640, 640), w=None): + super().__init__(nc, anchors, ch, imgsz, w) + self.nm = nm # number of masks + self.npr = npr # number of protos + self.no = 5 + nc + self.nm # number of outputs per anchor + self.m = [TFConv2d(x, self.no * self.na, 1, w=w.m[i]) for i, x in enumerate(ch)] # output conv + self.proto = TFProto(ch[0], self.npr, self.nm, w=w.proto) # protos + self.detect = TFDetect.call + + def call(self, x): + p = self.proto(x[0]) + # p = TFUpsample(None, scale_factor=4, mode='nearest')(self.proto(x[0])) # (optional) full-size protos + p = tf.transpose(p, [0, 3, 1, 2]) # from shape(1,160,160,32) to shape(1,32,160,160) + x = self.detect(self, x) + return (x, p) if self.training else (x[0], p) + + +class TFProto(keras.layers.Layer): + + def __init__(self, c1, c_=256, c2=32, w=None): + super().__init__() + self.cv1 = TFConv(c1, c_, k=3, w=w.cv1) + self.upsample = TFUpsample(None, scale_factor=2, mode='nearest') + self.cv2 = TFConv(c_, c_, k=3, w=w.cv2) + self.cv3 = TFConv(c_, c2, w=w.cv3) + + def call(self, inputs): + return self.cv3(self.cv2(self.upsample(self.cv1(inputs)))) + + class TFUpsample(keras.layers.Layer): + # TF version of torch.nn.Upsample() def __init__(self, size, scale_factor, mode, w=None): # warning: all arguments needed including 'w' super().__init__() - assert scale_factor == 2, "scale_factor must be 2" - self.upsample = lambda x: tf.image.resize(x, (x.shape[1] * 2, x.shape[2] * 2), method=mode) + assert scale_factor % 2 == 0, "scale_factor must be multiple of 2" + self.upsample = lambda x: tf.image.resize(x, (x.shape[1] * scale_factor, x.shape[2] * scale_factor), mode) # self.upsample = keras.layers.UpSampling2D(size=scale_factor, interpolation=mode) # with default arguments: align_corners=False, half_pixel_centers=False # self.upsample = lambda x: tf.raw_ops.ResizeNearestNeighbor(images=x, @@ -292,6 +368,7 @@ def call(self, inputs): class TFConcat(keras.layers.Layer): + # TF version of torch.concat() def __init__(self, dimension=1, w=None): super().__init__() assert dimension == 1, "convert only NCHW to NHWC concat" @@ -318,22 +395,26 @@ def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3) pass n = max(round(n * gd), 1) if n > 1 else n # depth gain - if m in [nn.Conv2d, Conv, Bottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv, BottleneckCSP, C3]: + if m in [ + nn.Conv2d, Conv, DWConv, DWConvTranspose2d, Bottleneck, SPP, SPPF, MixConv2d, Focus, CrossConv, + BottleneckCSP, C3, C3x]: c1, c2 = ch[f], args[0] c2 = make_divisible(c2 * gw, 8) if c2 != no else c2 args = [c1, c2, *args[1:]] - if m in [BottleneckCSP, C3]: + if m in [BottleneckCSP, C3, C3x]: args.insert(2, n) n = 1 elif m is nn.BatchNorm2d: args = [ch[f]] elif m is Concat: c2 = sum(ch[-1 if x == -1 else x + 1] for x in f) - elif m is Detect: + elif m in [Detect, Segment]: args.append([ch[x + 1] for x in f]) if isinstance(args[1], int): # number of anchors args[1] = [list(range(args[1] * 2))] * len(f) + if m is Segment: + args[3] = make_divisible(args[3] * gw, 8) args.append(imgsz) else: c2 = ch[f] @@ -354,7 +435,8 @@ def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3) class TFModel: - def __init__(self, cfg='yolov3.yaml', ch=3, nc=None, model=None, imgsz=(640, 640)): # model, channels, classes + # TF YOLOv3 model + def __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, model=None, imgsz=(640, 640)): # model, channels, classes super().__init__() if isinstance(cfg, dict): self.yaml = cfg # model dict @@ -370,11 +452,17 @@ def __init__(self, cfg='yolov3.yaml', ch=3, nc=None, model=None, imgsz=(640, 640 self.yaml['nc'] = nc # override yaml value self.model, self.savelist = parse_model(deepcopy(self.yaml), ch=[ch], model=model, imgsz=imgsz) - def predict(self, inputs, tf_nms=False, agnostic_nms=False, topk_per_class=100, topk_all=100, iou_thres=0.45, + def predict(self, + inputs, + tf_nms=False, + agnostic_nms=False, + topk_per_class=100, + topk_all=100, + iou_thres=0.45, conf_thres=0.25): y = [] # outputs x = inputs - for i, m in enumerate(self.model.layers): + for m in self.model.layers: if m.f != -1: # if not from previous layer x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers @@ -389,15 +477,18 @@ def predict(self, inputs, tf_nms=False, agnostic_nms=False, topk_per_class=100, scores = probs * classes if agnostic_nms: nms = AgnosticNMS()((boxes, classes, scores), topk_all, iou_thres, conf_thres) - return nms, x[1] else: boxes = tf.expand_dims(boxes, 2) - nms = tf.image.combined_non_max_suppression( - boxes, scores, topk_per_class, topk_all, iou_thres, conf_thres, clip_boxes=False) - return nms, x[1] - - return x[0] # output only first tensor [1,6300,85] = [xywh, conf, class0, class1, ...] - # x = x[0][0] # [x(1,6300,85), ...] to x(6300,85) + nms = tf.image.combined_non_max_suppression(boxes, + scores, + topk_per_class, + topk_all, + iou_thres, + conf_thres, + clip_boxes=False) + return (nms,) + return x # output [1,6300,85] = [xywh, conf, class0, class1, ...] + # x = x[0] # [x(1,6300,85), ...] to x(6300,85) # xywh = x[..., :4] # x(6300,4) boxes # conf = x[..., 4:5] # x(6300,1) confidences # cls = tf.reshape(tf.cast(tf.argmax(x[..., 5:], axis=1), tf.float32), (-1, 1)) # x(6300,1) classes @@ -414,7 +505,8 @@ class AgnosticNMS(keras.layers.Layer): # TF Agnostic NMS def call(self, input, topk_all, iou_thres, conf_thres): # wrap map_fn to avoid TypeSpec related error https://stackoverflow.com/a/65809989/3036450 - return tf.map_fn(lambda x: self._nms(x, topk_all, iou_thres, conf_thres), input, + return tf.map_fn(lambda x: self._nms(x, topk_all, iou_thres, conf_thres), + input, fn_output_signature=(tf.float32, tf.float32, tf.float32, tf.int32), name='agnostic_nms') @@ -423,50 +515,69 @@ def _nms(x, topk_all=100, iou_thres=0.45, conf_thres=0.25): # agnostic NMS boxes, classes, scores = x class_inds = tf.cast(tf.argmax(classes, axis=-1), tf.float32) scores_inp = tf.reduce_max(scores, -1) - selected_inds = tf.image.non_max_suppression( - boxes, scores_inp, max_output_size=topk_all, iou_threshold=iou_thres, score_threshold=conf_thres) + selected_inds = tf.image.non_max_suppression(boxes, + scores_inp, + max_output_size=topk_all, + iou_threshold=iou_thres, + score_threshold=conf_thres) selected_boxes = tf.gather(boxes, selected_inds) padded_boxes = tf.pad(selected_boxes, paddings=[[0, topk_all - tf.shape(selected_boxes)[0]], [0, 0]], - mode="CONSTANT", constant_values=0.0) + mode="CONSTANT", + constant_values=0.0) selected_scores = tf.gather(scores_inp, selected_inds) padded_scores = tf.pad(selected_scores, paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]], - mode="CONSTANT", constant_values=-1.0) + mode="CONSTANT", + constant_values=-1.0) selected_classes = tf.gather(class_inds, selected_inds) padded_classes = tf.pad(selected_classes, paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]], - mode="CONSTANT", constant_values=-1.0) + mode="CONSTANT", + constant_values=-1.0) valid_detections = tf.shape(selected_inds)[0] return padded_boxes, padded_scores, padded_classes, valid_detections +def activations(act=nn.SiLU): + # Returns TF activation from input PyTorch activation + if isinstance(act, nn.LeakyReLU): + return lambda x: keras.activations.relu(x, alpha=0.1) + elif isinstance(act, nn.Hardswish): + return lambda x: x * tf.nn.relu6(x + 3) * 0.166666667 + elif isinstance(act, (nn.SiLU, SiLU)): + return lambda x: keras.activations.swish(x) + else: + raise Exception(f'no matching TensorFlow activation found for PyTorch activation {act}') + + def representative_dataset_gen(dataset, ncalib=100): # Representative dataset generator for use with converter.representative_dataset, returns a generator of np arrays for n, (path, img, im0s, vid_cap, string) in enumerate(dataset): - input = np.transpose(img, [1, 2, 0]) - input = np.expand_dims(input, axis=0).astype(np.float32) - input /= 255 - yield [input] + im = np.transpose(img, [1, 2, 0]) + im = np.expand_dims(im, axis=0).astype(np.float32) + im /= 255 + yield [im] if n >= ncalib: break -def run(weights=ROOT / 'yolov3.pt', # weights path +def run( + weights=ROOT / 'yolov5s.pt', # weights path imgsz=(640, 640), # inference size h,w batch_size=1, # batch size dynamic=False, # dynamic batch size - ): +): # PyTorch model im = torch.zeros((batch_size, 3, *imgsz)) # BCHW image - model = attempt_load(weights, map_location=torch.device('cpu'), inplace=True, fuse=False) - y = model(im) # inference + model = attempt_load(weights, device=torch.device('cpu'), inplace=True, fuse=False) + _ = model(im) # inference model.info() # TensorFlow model im = tf.zeros((batch_size, *imgsz, 3)) # BHWC image tf_model = TFModel(cfg=model.yaml, model=model, nc=model.nc, imgsz=imgsz) - y = tf_model.predict(im) # inference + _ = tf_model.predict(im) # inference # Keras model im = keras.Input(shape=(*imgsz, 3), batch_size=None if dynamic else batch_size) @@ -476,146 +587,15 @@ def run(weights=ROOT / 'yolov3.pt', # weights path LOGGER.info('PyTorch, TensorFlow and Keras models successfully verified.\nUse export.py for TF model export.') -@keras_export("keras.layers.ZeroPadding2D") -class ZeroPadding2D(Layer): - """Zero-padding layer for 2D input (e.g. picture). - - This layer can add rows and columns of zeros - at the top, bottom, left and right side of an image tensor. - - Examples: - - >>> input_shape = (1, 1, 2, 2) - >>> x = np.arange(np.prod(input_shape)).reshape(input_shape) - >>> print(x) - [[[[0 1] - [2 3]]]] - >>> y = tf.keras.layers.ZeroPadding2D(padding=1)(x) - >>> print(y) - tf.Tensor( - [[[[0 0] - [0 0] - [0 0] - [0 0]] - [[0 0] - [0 1] - [2 3] - [0 0]] - [[0 0] - [0 0] - [0 0] - [0 0]]]], shape=(1, 3, 4, 2), dtype=int64) - - Args: - padding: Int, or tuple of 2 ints, or tuple of 2 tuples of 2 ints. - - If int: the same symmetric padding - is applied to height and width. - - If tuple of 2 ints: - interpreted as two different - symmetric padding values for height and width: - `(symmetric_height_pad, symmetric_width_pad)`. - - If tuple of 2 tuples of 2 ints: - interpreted as - `((top_pad, bottom_pad), (left_pad, right_pad))` - data_format: A string, - one of `channels_last` (default) or `channels_first`. - The ordering of the dimensions in the inputs. - `channels_last` corresponds to inputs with shape - `(batch_size, height, width, channels)` while `channels_first` - corresponds to inputs with shape - `(batch_size, channels, height, width)`. - It defaults to the `image_data_format` value found in your - Keras config file at `~/.keras/keras.json`. - If you never set it, then it will be "channels_last". - - Input shape: - 4D tensor with shape: - - If `data_format` is `"channels_last"`: - `(batch_size, rows, cols, channels)` - - If `data_format` is `"channels_first"`: - `(batch_size, channels, rows, cols)` - - Output shape: - 4D tensor with shape: - - If `data_format` is `"channels_last"`: - `(batch_size, padded_rows, padded_cols, channels)` - - If `data_format` is `"channels_first"`: - `(batch_size, channels, padded_rows, padded_cols)` - """ - - def __init__(self, padding=(1, 1), data_format=None, **kwargs): - super().__init__(**kwargs) - self.data_format = conv_utils.normalize_data_format(data_format) - if isinstance(padding, int): - self.padding = ((padding, padding), (padding, padding)) - elif hasattr(padding, "__len__"): - if len(padding) == 4: - padding = ((padding[0], padding[1]), (padding[2], padding[3])) - if len(padding) != 2: - raise ValueError( - f"`padding` should have two elements. Received: {padding}." - ) - height_padding = conv_utils.normalize_tuple( - padding[0], 2, "1st entry of padding", allow_zero=True - ) - width_padding = conv_utils.normalize_tuple( - padding[1], 2, "2nd entry of padding", allow_zero=True - ) - self.padding = (height_padding, width_padding) - else: - raise ValueError( - "`padding` should be either an int, " - "a tuple of 2 ints " - "(symmetric_height_pad, symmetric_width_pad), " - "or a tuple of 2 tuples of 2 ints " - "((top_pad, bottom_pad), (left_pad, right_pad)). " - f"Received: {padding}." - ) - self.input_spec = InputSpec(ndim=4) - - def compute_output_shape(self, input_shape): - input_shape = tf.TensorShape(input_shape).as_list() - if self.data_format == "channels_first": - if input_shape[2] is not None: - rows = input_shape[2] + self.padding[0][0] + self.padding[0][1] - else: - rows = None - if input_shape[3] is not None: - cols = input_shape[3] + self.padding[1][0] + self.padding[1][1] - else: - cols = None - return tf.TensorShape([input_shape[0], input_shape[1], rows, cols]) - elif self.data_format == "channels_last": - if input_shape[1] is not None: - rows = input_shape[1] + self.padding[0][0] + self.padding[0][1] - else: - rows = None - if input_shape[2] is not None: - cols = input_shape[2] + self.padding[1][0] + self.padding[1][1] - else: - cols = None - return tf.TensorShape([input_shape[0], rows, cols, input_shape[3]]) - - def call(self, inputs): - return backend.spatial_2d_padding( - inputs, padding=self.padding, data_format=self.data_format - ) - - def get_config(self): - config = {"padding": self.padding, "data_format": self.data_format} - base_config = super().get_config() - return dict(list(base_config.items()) + list(config.items())) - - def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default=ROOT / 'yolov3.pt', help='weights path') + parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='weights path') parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') parser.add_argument('--batch-size', type=int, default=1, help='batch size') parser.add_argument('--dynamic', action='store_true', help='dynamic batch size') opt = parser.parse_args() opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand - print_args(FILE.stem, opt) + print_args(vars(opt)) return opt diff --git a/models/yolo.py b/models/yolo.py index f398d3f971..fbff6da763 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -3,26 +3,29 @@ YOLO-specific modules Usage: - $ python path/to/models/yolo.py --cfg yolov3.yaml + $ python models/yolo.py --cfg yolov5s.yaml """ import argparse +import os +import platform import sys from copy import deepcopy from pathlib import Path FILE = Path(__file__).resolve() -ROOT = FILE.parents[1] # root directory +ROOT = FILE.parents[1] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH -# ROOT = ROOT.relative_to(Path.cwd()) # relative +if platform.system() != 'Windows': + ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative from models.common import * from models.experimental import * from utils.autoanchor import check_anchor_order from utils.general import LOGGER, check_version, check_yaml, make_divisible, print_args from utils.plots import feature_visualization -from utils.torch_utils import (copy_attr, fuse_conv_and_bn, initialize_weights, model_info, scale_img, select_device, +from utils.torch_utils import (fuse_conv_and_bn, initialize_weights, model_info, profile, scale_img, select_device, time_sync) try: @@ -32,8 +35,10 @@ class Detect(nn.Module): + # YOLOv3 Detect head for detection models stride = None # strides computed during build - onnx_dynamic = False # ONNX export parameter + dynamic = False # force grid reconstruction + export = False # export mode def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer super().__init__() @@ -41,11 +46,11 @@ def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer self.no = nc + 5 # number of outputs per anchor self.nl = len(anchors) # number of detection layers self.na = len(anchors[0]) // 2 # number of anchors - self.grid = [torch.zeros(1)] * self.nl # init grid - self.anchor_grid = [torch.zeros(1)] * self.nl # init anchor grid + self.grid = [torch.empty(0) for _ in range(self.nl)] # init grid + self.anchor_grid = [torch.empty(0) for _ in range(self.nl)] # init anchor grid self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2) self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv - self.inplace = inplace # use in-place ops (e.g. slice assignment) + self.inplace = inplace # use inplace ops (e.g. slice assignment) def forward(self, x): z = [] # inference output @@ -55,35 +60,110 @@ def forward(self, x): x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous() if not self.training: # inference - if self.onnx_dynamic or self.grid[i].shape[2:4] != x[i].shape[2:4]: + if self.dynamic or self.grid[i].shape[2:4] != x[i].shape[2:4]: self.grid[i], self.anchor_grid[i] = self._make_grid(nx, ny, i) - y = x[i].sigmoid() - if self.inplace: - y[..., 0:2] = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i] # xy - y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh - else: # for on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953 - xy = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i] # xy - wh = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh - y = torch.cat((xy, wh, y[..., 4:]), -1) - z.append(y.view(bs, -1, self.no)) - - return x if self.training else (torch.cat(z, 1), x) - - def _make_grid(self, nx=20, ny=20, i=0): + if isinstance(self, Segment): # (boxes + masks) + xy, wh, conf, mask = x[i].split((2, 2, self.nc + 1, self.no - self.nc - 5), 4) + xy = (xy.sigmoid() * 2 + self.grid[i]) * self.stride[i] # xy + wh = (wh.sigmoid() * 2) ** 2 * self.anchor_grid[i] # wh + y = torch.cat((xy, wh, conf.sigmoid(), mask), 4) + else: # Detect (boxes only) + xy, wh, conf = x[i].sigmoid().split((2, 2, self.nc + 1), 4) + xy = (xy * 2 + self.grid[i]) * self.stride[i] # xy + wh = (wh * 2) ** 2 * self.anchor_grid[i] # wh + y = torch.cat((xy, wh, conf), 4) + z.append(y.view(bs, self.na * nx * ny, self.no)) + + return x if self.training else (torch.cat(z, 1),) if self.export else (torch.cat(z, 1), x) + + def _make_grid(self, nx=20, ny=20, i=0, torch_1_10=check_version(torch.__version__, '1.10.0')): d = self.anchors[i].device - if check_version(torch.__version__, '1.10.0'): # torch>=1.10.0 meshgrid workaround for torch>=0.7 compatibility - yv, xv = torch.meshgrid([torch.arange(ny).to(d), torch.arange(nx).to(d)], indexing='ij') - else: - yv, xv = torch.meshgrid([torch.arange(ny).to(d), torch.arange(nx).to(d)]) - grid = torch.stack((xv, yv), 2).expand((1, self.na, ny, nx, 2)).float() - anchor_grid = (self.anchors[i].clone() * self.stride[i]) \ - .view((1, self.na, 1, 1, 2)).expand((1, self.na, ny, nx, 2)).float() + t = self.anchors[i].dtype + shape = 1, self.na, ny, nx, 2 # grid shape + y, x = torch.arange(ny, device=d, dtype=t), torch.arange(nx, device=d, dtype=t) + yv, xv = torch.meshgrid(y, x, indexing='ij') if torch_1_10 else torch.meshgrid(y, x) # torch>=0.7 compatibility + grid = torch.stack((xv, yv), 2).expand(shape) - 0.5 # add grid offset, i.e. y = 2.0 * x - 0.5 + anchor_grid = (self.anchors[i] * self.stride[i]).view((1, self.na, 1, 1, 2)).expand(shape) return grid, anchor_grid -class Model(nn.Module): - def __init__(self, cfg='yolov3.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classes +class Segment(Detect): + # YOLOv3 Segment head for segmentation models + def __init__(self, nc=80, anchors=(), nm=32, npr=256, ch=(), inplace=True): + super().__init__(nc, anchors, ch, inplace) + self.nm = nm # number of masks + self.npr = npr # number of protos + self.no = 5 + nc + self.nm # number of outputs per anchor + self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv + self.proto = Proto(ch[0], self.npr, self.nm) # protos + self.detect = Detect.forward + + def forward(self, x): + p = self.proto(x[0]) + x = self.detect(self, x) + return (x, p) if self.training else (x[0], p) if self.export else (x[0], p, x[1]) + + +class BaseModel(nn.Module): + # YOLOv3 base model + def forward(self, x, profile=False, visualize=False): + return self._forward_once(x, profile, visualize) # single-scale inference, train + + def _forward_once(self, x, profile=False, visualize=False): + y, dt = [], [] # outputs + for m in self.model: + if m.f != -1: # if not from previous layer + x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers + if profile: + self._profile_one_layer(m, x, dt) + x = m(x) # run + y.append(x if m.i in self.save else None) # save output + if visualize: + feature_visualization(x, m.type, m.i, save_dir=visualize) + return x + + def _profile_one_layer(self, m, x, dt): + c = m == self.model[-1] # is final layer, copy input as inplace fix + o = thop.profile(m, inputs=(x.copy() if c else x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPs + t = time_sync() + for _ in range(10): + m(x.copy() if c else x) + dt.append((time_sync() - t) * 100) + if m == self.model[0]: + LOGGER.info(f"{'time (ms)':>10s} {'GFLOPs':>10s} {'params':>10s} module") + LOGGER.info(f'{dt[-1]:10.2f} {o:10.2f} {m.np:10.0f} {m.type}') + if c: + LOGGER.info(f"{sum(dt):10.2f} {'-':>10s} {'-':>10s} Total") + + def fuse(self): # fuse model Conv2d() + BatchNorm2d() layers + LOGGER.info('Fusing layers... ') + for m in self.model.modules(): + if isinstance(m, (Conv, DWConv)) and hasattr(m, 'bn'): + m.conv = fuse_conv_and_bn(m.conv, m.bn) # update conv + delattr(m, 'bn') # remove batchnorm + m.forward = m.forward_fuse # update forward + self.info() + return self + + def info(self, verbose=False, img_size=640): # print model information + model_info(self, verbose, img_size) + + def _apply(self, fn): + # Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers + self = super()._apply(fn) + m = self.model[-1] # Detect() + if isinstance(m, (Detect, Segment)): + m.stride = fn(m.stride) + m.grid = list(map(fn, m.grid)) + if isinstance(m.anchor_grid, list): + m.anchor_grid = list(map(fn, m.anchor_grid)) + return self + + +class DetectionModel(BaseModel): + # YOLOv3 detection model + def __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classes super().__init__() if isinstance(cfg, dict): self.yaml = cfg # model dict @@ -107,12 +187,13 @@ def __init__(self, cfg='yolov3.yaml', ch=3, nc=None, anchors=None): # model, in # Build strides, anchors m = self.model[-1] # Detect() - if isinstance(m, Detect): + if isinstance(m, (Detect, Segment)): s = 256 # 2x min stride m.inplace = self.inplace - m.stride = torch.tensor([s / x.shape[-2] for x in self.forward(torch.zeros(1, ch, s, s))]) # forward - m.anchors /= m.stride.view(-1, 1, 1) + forward = lambda x: self.forward(x)[0] if isinstance(m, Segment) else self.forward(x) + m.stride = torch.tensor([s / x.shape[-2] for x in forward(torch.zeros(1, ch, s, s))]) # forward check_anchor_order(m) + m.anchors /= m.stride.view(-1, 1, 1) self.stride = m.stride self._initialize_biases() # only run once @@ -140,19 +221,6 @@ def _forward_augment(self, x): y = self._clip_augmented(y) # clip augmented tails return torch.cat(y, 1), None # augmented inference, train - def _forward_once(self, x, profile=False, visualize=False): - y, dt = [], [] # outputs - for m in self.model: - if m.f != -1: # if not from previous layer - x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers - if profile: - self._profile_one_layer(m, x, dt) - x = m(x) # run - y.append(x if m.i in self.save else None) # save output - if visualize: - feature_visualization(x, m.type, m.i, save_dir=visualize) - return x - def _descale_pred(self, p, flips, scale, img_size): # de-scale predictions following augmented inference (inverse operation) if self.inplace: @@ -181,19 +249,6 @@ def _clip_augmented(self, y): y[-1] = y[-1][:, i:] # small return y - def _profile_one_layer(self, m, x, dt): - c = isinstance(m, Detect) # is final layer, copy input as inplace fix - o = thop.profile(m, inputs=(x.copy() if c else x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPs - t = time_sync() - for _ in range(10): - m(x.copy() if c else x) - dt.append((time_sync() - t) * 100) - if m == self.model[0]: - LOGGER.info(f"{'time (ms)':>10s} {'GFLOPs':>10s} {'params':>10s} {'module'}") - LOGGER.info(f'{dt[-1]:10.2f} {o:10.2f} {m.np:10.0f} {m.type}') - if c: - LOGGER.info(f"{sum(dt):10.2f} {'-':>10s} {'-':>10s} Total") - def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is class frequency # https://arxiv.org/abs/1708.02002 section 3.3 # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1. @@ -201,55 +256,52 @@ def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is for mi, s in zip(m.m, m.stride): # from b = mi.bias.view(m.na, -1) # conv.bias(255) to (3,85) b.data[:, 4] += math.log(8 / (640 / s) ** 2) # obj (8 objects per 640 image) - b.data[:, 5:] += math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum()) # cls + b.data[:, 5:5 + m.nc] += math.log(0.6 / (m.nc - 0.99999)) if cf is None else torch.log(cf / cf.sum()) # cls mi.bias = torch.nn.Parameter(b.view(-1), requires_grad=True) - def _print_biases(self): - m = self.model[-1] # Detect() module - for mi in m.m: # from - b = mi.bias.detach().view(m.na, -1).T # conv.bias(255) to (3,85) - LOGGER.info( - ('%6g Conv2d.bias:' + '%10.3g' * 6) % (mi.weight.shape[1], *b[:5].mean(1).tolist(), b[5:].mean())) - # def _print_weights(self): - # for m in self.model.modules(): - # if type(m) is Bottleneck: - # LOGGER.info('%10.3g' % (m.w.detach().sigmoid() * 2)) # shortcut weights +Model = DetectionModel # retain 'Model' class for backwards compatibility - def fuse(self): # fuse model Conv2d() + BatchNorm2d() layers - LOGGER.info('Fusing layers... ') - for m in self.model.modules(): - if isinstance(m, (Conv, DWConv)) and hasattr(m, 'bn'): - m.conv = fuse_conv_and_bn(m.conv, m.bn) # update conv - delattr(m, 'bn') # remove batchnorm - m.forward = m.forward_fuse # update forward - self.info() - return self - def autoshape(self): # add AutoShape module - LOGGER.info('Adding AutoShape... ') - m = AutoShape(self) # wrap model - copy_attr(m, self, include=('yaml', 'nc', 'hyp', 'names', 'stride'), exclude=()) # copy attributes - return m +class SegmentationModel(DetectionModel): + # segmentation model + def __init__(self, cfg='yolov5s-seg.yaml', ch=3, nc=None, anchors=None): + super().__init__(cfg, ch, nc, anchors) - def info(self, verbose=False, img_size=640): # print model information - model_info(self, verbose, img_size) - def _apply(self, fn): - # Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers - self = super()._apply(fn) - m = self.model[-1] # Detect() - if isinstance(m, Detect): - m.stride = fn(m.stride) - m.grid = list(map(fn, m.grid)) - if isinstance(m.anchor_grid, list): - m.anchor_grid = list(map(fn, m.anchor_grid)) - return self +class ClassificationModel(BaseModel): + # classification model + def __init__(self, cfg=None, model=None, nc=1000, cutoff=10): # yaml, model, number of classes, cutoff index + super().__init__() + self._from_detection_model(model, nc, cutoff) if model is not None else self._from_yaml(cfg) + + def _from_detection_model(self, model, nc=1000, cutoff=10): + # Create a classification model from a detection model + if isinstance(model, DetectMultiBackend): + model = model.model # unwrap DetectMultiBackend + model.model = model.model[:cutoff] # backbone + m = model.model[-1] # last layer + ch = m.conv.in_channels if hasattr(m, 'conv') else m.cv1.conv.in_channels # ch into module + c = Classify(ch, nc) # Classify() + c.i, c.f, c.type = m.i, m.f, 'models.common.Classify' # index, from, type + model.model[-1] = c # replace + self.model = model.model + self.stride = model.stride + self.save = [] + self.nc = nc + + def _from_yaml(self, cfg): + # Create a classification model from a *.yaml file + self.model = None def parse_model(d, ch): # model_dict, input_channels(3) + # Parse a model.yaml dictionary LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}") - anchors, nc, gd, gw = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'] + anchors, nc, gd, gw, act = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'], d.get('activation') + if act: + Conv.default_act = eval(act) # redefine default activation, i.e. Conv.default_act = nn.SiLU() + LOGGER.info(f"{colorstr('activation:')} {act}") # print na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors no = na * (nc + 5) # number of outputs = anchors * (classes + 5) @@ -257,30 +309,32 @@ def parse_model(d, ch): # model_dict, input_channels(3) for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, args m = eval(m) if isinstance(m, str) else m # eval strings for j, a in enumerate(args): - try: + with contextlib.suppress(NameError): args[j] = eval(a) if isinstance(a, str) else a # eval strings - except NameError: - pass n = n_ = max(round(n * gd), 1) if n > 1 else n # depth gain - if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv, - BottleneckCSP, C3, C3TR, C3SPP, C3Ghost]: + if m in { + Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv, + BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x}: c1, c2 = ch[f], args[0] if c2 != no: # if not output c2 = make_divisible(c2 * gw, 8) args = [c1, c2, *args[1:]] - if m in [BottleneckCSP, C3, C3TR, C3Ghost]: + if m in {BottleneckCSP, C3, C3TR, C3Ghost, C3x}: args.insert(2, n) # number of repeats n = 1 elif m is nn.BatchNorm2d: args = [ch[f]] elif m is Concat: c2 = sum(ch[x] for x in f) - elif m is Detect: + # TODO: channel, gw, gd + elif m in {Detect, Segment}: args.append([ch[x] for x in f]) if isinstance(args[1], int): # number of anchors args[1] = [list(range(args[1] * 2))] * len(f) + if m is Segment: + args[3] = make_divisible(args[3] * gw, 8) elif m is Contract: c2 = ch[f] * args[0] ** 2 elif m is Expand: @@ -303,34 +357,34 @@ def parse_model(d, ch): # model_dict, input_channels(3) if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('--cfg', type=str, default='yolov3yaml', help='model.yaml') + parser.add_argument('--cfg', type=str, default='yolov5s.yaml', help='model.yaml') + parser.add_argument('--batch-size', type=int, default=1, help='total batch size for all GPUs') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--profile', action='store_true', help='profile model speed') + parser.add_argument('--line-profile', action='store_true', help='profile model speed layer by layer') parser.add_argument('--test', action='store_true', help='test all yolo*.yaml') opt = parser.parse_args() opt.cfg = check_yaml(opt.cfg) # check YAML - print_args(FILE.stem, opt) + print_args(vars(opt)) device = select_device(opt.device) # Create model + im = torch.rand(opt.batch_size, 3, 640, 640).to(device) model = Model(opt.cfg).to(device) - model.train() - # Profile - if opt.profile: - img = torch.rand(8 if torch.cuda.is_available() else 1, 3, 640, 640).to(device) - y = model(img, profile=True) + # Options + if opt.line_profile: # profile layer by layer + model(im, profile=True) + + elif opt.profile: # profile forward-backward + results = profile(input=im, ops=[model], n=3) - # Test all models - if opt.test: + elif opt.test: # test all models for cfg in Path(ROOT / 'models').rglob('yolo*.yaml'): try: _ = Model(cfg) except Exception as e: print(f'Error in {cfg}: {e}') - # Tensorboard (not working https://github.com/ultralytics/yolov5/issues/2898) - # from torch.utils.tensorboard import SummaryWriter - # tb_writer = SummaryWriter('.') - # LOGGER.info("Run 'tensorboard --logdir=models' to view tensorboard at http://localhost:6006/") - # tb_writer.add_graph(torch.jit.trace(model, img, strict=False), []) # add model graph + else: # report fused model summary + model.fuse() diff --git a/models/yolov5l.yaml b/models/yolov5l.yaml new file mode 100644 index 0000000000..2c3a7c1725 --- /dev/null +++ b/models/yolov5l.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/models/yolov5m.yaml b/models/yolov5m.yaml new file mode 100644 index 0000000000..f0ee2907bd --- /dev/null +++ b/models/yolov5m.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 0.67 # model depth multiple +width_multiple: 0.75 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/models/yolov5n.yaml b/models/yolov5n.yaml new file mode 100644 index 0000000000..a4b7266006 --- /dev/null +++ b/models/yolov5n.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.25 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/models/yolov5s.yaml b/models/yolov5s.yaml new file mode 100644 index 0000000000..b3edebe9d9 --- /dev/null +++ b/models/yolov5s.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.50 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/models/yolov5x.yaml b/models/yolov5x.yaml new file mode 100644 index 0000000000..d8c7dd7881 --- /dev/null +++ b/models/yolov5x.yaml @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.33 # model depth multiple +width_multiple: 1.25 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# YOLOv5 v6.0 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 + ] + +# YOLOv5 v6.0 head +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/requirements.txt b/requirements.txt old mode 100755 new mode 100644 index f78e7ee013..7bfde97bfa --- a/requirements.txt +++ b/requirements.txt @@ -1,31 +1,35 @@ # YOLOv3 requirements # Usage: pip install -r requirements.txt -# Base ---------------------------------------- +# Base ------------------------------------------------------------------------ +gitpython +ipython # interactive notebook matplotlib>=3.2.2 numpy>=1.18.5 opencv-python>=4.1.1 Pillow>=7.1.2 +psutil # system resources PyYAML>=5.3.1 requests>=2.23.0 scipy>=1.4.1 -torch>=1.7.0 # see https://pytorch.org/get-started/locally/ (recommended) +thop>=0.1.1 # FLOPs computation +torch>=1.7.0 # see https://pytorch.org/get-started/locally (recommended) torchvision>=0.8.1 tqdm>=4.64.0 # protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 -# Logging ------------------------------------- +# Logging --------------------------------------------------------------------- tensorboard>=2.4.1 -# clearml +# clearml>=1.2.0 # comet -# Plotting ------------------------------------ +# Plotting -------------------------------------------------------------------- pandas>=1.1.4 seaborn>=0.11.0 -# Export -------------------------------------- +# Export ---------------------------------------------------------------------- # coremltools>=6.0 # CoreML export -# onnx>=1.9.0 # ONNX export +# onnx>=1.12.0 # ONNX export # onnx-simplifier>=0.4.1 # ONNX simplifier # nvidia-pyindex # TensorRT export # nvidia-tensorrt # TensorRT export @@ -34,14 +38,14 @@ seaborn>=0.11.0 # tensorflowjs>=3.9.0 # TF.js export # openvino-dev # OpenVINO export -# Deploy -------------------------------------- +# Deploy ---------------------------------------------------------------------- +setuptools>=65.5.1 # Snyk vulnerability fix +wheel>=0.38.0 # Snyk vulnerability fix # tritonclient[all]~=2.24.0 -# Extras -------------------------------------- -ipython # interactive notebook -psutil # system utilization -thop>=0.1.1 # FLOPs computation +# Extras ---------------------------------------------------------------------- # mss # screenshots # albumentations>=1.0.3 -# pycocotools>=2.0 # COCO mAP +# pycocotools>=2.0.6 # COCO mAP # roboflow +# ultralytics # HUB https://hub.ultralytics.com diff --git a/segment/predict.py b/segment/predict.py new file mode 100644 index 0000000000..ac832bf815 --- /dev/null +++ b/segment/predict.py @@ -0,0 +1,284 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Run segmentation inference on images, videos, directories, streams, etc. + +Usage - sources: + $ python segment/predict.py --weights yolov5s-seg.pt --source 0 # webcam + img.jpg # image + vid.mp4 # video + screen # screenshot + path/ # directory + list.txt # list of images + list.streams # list of streams + 'path/*.jpg' # glob + 'https://youtu.be/Zgi9g1ksQHc' # YouTube + 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream + +Usage - formats: + $ python segment/predict.py --weights yolov5s-seg.pt # PyTorch + yolov5s-seg.torchscript # TorchScript + yolov5s-seg.onnx # ONNX Runtime or OpenCV DNN with --dnn + yolov5s-seg_openvino_model # OpenVINO + yolov5s-seg.engine # TensorRT + yolov5s-seg.mlmodel # CoreML (macOS-only) + yolov5s-seg_saved_model # TensorFlow SavedModel + yolov5s-seg.pb # TensorFlow GraphDef + yolov5s-seg.tflite # TensorFlow Lite + yolov5s-seg_edgetpu.tflite # TensorFlow Edge TPU + yolov5s-seg_paddle_model # PaddlePaddle +""" + +import argparse +import os +import platform +import sys +from pathlib import Path + +import torch + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams +from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, + increment_path, non_max_suppression, print_args, scale_boxes, scale_segments, + strip_optimizer) +from utils.plots import Annotator, colors, save_one_box +from utils.segment.general import masks2segments, process_mask, process_mask_native +from utils.torch_utils import select_device, smart_inference_mode + + +@smart_inference_mode() +def run( + weights=ROOT / 'yolov5s-seg.pt', # model.pt path(s) + source=ROOT / 'data/images', # file/dir/URL/glob/screen/0(webcam) + data=ROOT / 'data/coco128.yaml', # dataset.yaml path + imgsz=(640, 640), # inference size (height, width) + conf_thres=0.25, # confidence threshold + iou_thres=0.45, # NMS IOU threshold + max_det=1000, # maximum detections per image + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + view_img=False, # show results + save_txt=False, # save results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_crop=False, # save cropped prediction boxes + nosave=False, # do not save images/videos + classes=None, # filter by class: --class 0, or --class 0 2 3 + agnostic_nms=False, # class-agnostic NMS + augment=False, # augmented inference + visualize=False, # visualize features + update=False, # update all models + project=ROOT / 'runs/predict-seg', # save results to project/name + name='exp', # save results to project/name + exist_ok=False, # existing project/name ok, do not increment + line_thickness=3, # bounding box thickness (pixels) + hide_labels=False, # hide labels + hide_conf=False, # hide confidences + half=False, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + vid_stride=1, # video frame-rate stride + retina_masks=False, +): + source = str(source) + save_img = not nosave and not source.endswith('.txt') # save inference images + is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) + is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://')) + webcam = source.isnumeric() or source.endswith('.streams') or (is_url and not is_file) + screenshot = source.lower().startswith('screen') + if is_url and is_file: + source = check_file(source) # download + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + device = select_device(device) + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, names, pt = model.stride, model.names, model.pt + imgsz = check_img_size(imgsz, s=stride) # check image size + + # Dataloader + bs = 1 # batch_size + if webcam: + view_img = check_imshow(warn=True) + dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride) + bs = len(dataset) + elif screenshot: + dataset = LoadScreenshots(source, img_size=imgsz, stride=stride, auto=pt) + else: + dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride) + vid_path, vid_writer = [None] * bs, [None] * bs + + # Run inference + model.warmup(imgsz=(1 if pt else bs, 3, *imgsz)) # warmup + seen, windows, dt = 0, [], (Profile(), Profile(), Profile()) + for path, im, im0s, vid_cap, s in dataset: + with dt[0]: + im = torch.from_numpy(im).to(model.device) + im = im.half() if model.fp16 else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + if len(im.shape) == 3: + im = im[None] # expand for batch dim + + # Inference + with dt[1]: + visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False + pred, proto = model(im, augment=augment, visualize=visualize)[:2] + + # NMS + with dt[2]: + pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det, nm=32) + + # Second-stage classifier (optional) + # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s) + + # Process predictions + for i, det in enumerate(pred): # per image + seen += 1 + if webcam: # batch_size >= 1 + p, im0, frame = path[i], im0s[i].copy(), dataset.count + s += f'{i}: ' + else: + p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0) + + p = Path(p) # to Path + save_path = str(save_dir / p.name) # im.jpg + txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # im.txt + s += '%gx%g ' % im.shape[2:] # print string + imc = im0.copy() if save_crop else im0 # for save_crop + annotator = Annotator(im0, line_width=line_thickness, example=str(names)) + if len(det): + if retina_masks: + # scale bbox first the crop masks + det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], im0.shape).round() # rescale boxes to im0 size + masks = process_mask_native(proto[i], det[:, 6:], det[:, :4], im0.shape[:2]) # HWC + else: + masks = process_mask(proto[i], det[:, 6:], det[:, :4], im.shape[2:], upsample=True) # HWC + det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], im0.shape).round() # rescale boxes to im0 size + + # Segments + if save_txt: + segments = [ + scale_segments(im0.shape if retina_masks else im.shape[2:], x, im0.shape, normalize=True) + for x in reversed(masks2segments(masks))] + + # Print results + for c in det[:, 5].unique(): + n = (det[:, 5] == c).sum() # detections per class + s += f"{n} {names[int(c)]}{'s' * (n > 1)}, " # add to string + + # Mask plotting + annotator.masks( + masks, + colors=[colors(x, True) for x in det[:, 5]], + im_gpu=torch.as_tensor(im0, dtype=torch.float16).to(device).permute(2, 0, 1).flip(0).contiguous() / + 255 if retina_masks else im[i]) + + # Write results + for j, (*xyxy, conf, cls) in enumerate(reversed(det[:, :6])): + if save_txt: # Write to file + seg = segments[j].reshape(-1) # (n,2) to (n*2) + line = (cls, *seg, conf) if save_conf else (cls, *seg) # label format + with open(f'{txt_path}.txt', 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + if save_img or save_crop or view_img: # Add bbox to image + c = int(cls) # integer class + label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}') + annotator.box_label(xyxy, label, color=colors(c, True)) + # annotator.draw.polygon(segments[j], outline=colors(c, True), width=3) + if save_crop: + save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True) + + # Stream results + im0 = annotator.result() + if view_img: + if platform.system() == 'Linux' and p not in windows: + windows.append(p) + cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux) + cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0]) + cv2.imshow(str(p), im0) + if cv2.waitKey(1) == ord('q'): # 1 millisecond + exit() + + # Save results (image with detections) + if save_img: + if dataset.mode == 'image': + cv2.imwrite(save_path, im0) + else: # 'video' or 'stream' + if vid_path[i] != save_path: # new video + vid_path[i] = save_path + if isinstance(vid_writer[i], cv2.VideoWriter): + vid_writer[i].release() # release previous video writer + if vid_cap: # video + fps = vid_cap.get(cv2.CAP_PROP_FPS) + w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + else: # stream + fps, w, h = 30, im0.shape[1], im0.shape[0] + save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos + vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) + vid_writer[i].write(im0) + + # Print time (inference-only) + LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms") + + # Print results + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t) + if save_txt or save_img: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + if update: + strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning) + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s-seg.pt', help='model path(s)') + parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob/screen/0(webcam)') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path') + parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') + parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--view-img', action='store_true', help='show results') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes') + parser.add_argument('--nosave', action='store_true', help='do not save images/videos') + parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3') + parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--visualize', action='store_true', help='visualize features') + parser.add_argument('--update', action='store_true', help='update all models') + parser.add_argument('--project', default=ROOT / 'runs/predict-seg', help='save results to project/name') + parser.add_argument('--name', default='exp', help='save results to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)') + parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels') + parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride') + parser.add_argument('--retina-masks', action='store_true', help='whether to plot masks in native resolution') + opt = parser.parse_args() + opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand + print_args(vars(opt)) + return opt + + +def main(opt): + check_requirements(exclude=('tensorboard', 'thop')) + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/segment/train.py b/segment/train.py new file mode 100644 index 0000000000..3efc883be4 --- /dev/null +++ b/segment/train.py @@ -0,0 +1,659 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Train a segment model on a segment dataset +Models and datasets download automatically from the latest release. + +Usage - Single-GPU training: + $ python segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 # from pretrained (recommended) + $ python segment/train.py --data coco128-seg.yaml --weights '' --cfg yolov5s-seg.yaml --img 640 # from scratch + +Usage - Multi-GPU DDP training: + $ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 --device 0,1,2,3 + +Models: https://github.com/ultralytics/yolov5/tree/master/models +Datasets: https://github.com/ultralytics/yolov5/tree/master/data +Tutorial: https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data +""" + +import argparse +import math +import os +import random +import subprocess +import sys +import time +from copy import deepcopy +from datetime import datetime +from pathlib import Path + +import numpy as np +import torch +import torch.distributed as dist +import torch.nn as nn +import yaml +from torch.optim import lr_scheduler +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +import segment.val as validate # for end-of-epoch mAP +from models.experimental import attempt_load +from models.yolo import SegmentationModel +from utils.autoanchor import check_anchors +from utils.autobatch import check_train_batch_size +from utils.callbacks import Callbacks +from utils.downloads import attempt_download, is_url +from utils.general import (LOGGER, TQDM_BAR_FORMAT, check_amp, check_dataset, check_file, check_git_info, + check_git_status, check_img_size, check_requirements, check_suffix, check_yaml, colorstr, + get_latest_run, increment_path, init_seeds, intersect_dicts, labels_to_class_weights, + labels_to_image_weights, one_cycle, print_args, print_mutation, strip_optimizer, yaml_save) +from utils.loggers import GenericLogger +from utils.plots import plot_evolve, plot_labels +from utils.segment.dataloaders import create_dataloader +from utils.segment.loss import ComputeLoss +from utils.segment.metrics import KEYS, fitness +from utils.segment.plots import plot_images_and_masks, plot_results_with_masks +from utils.torch_utils import (EarlyStopping, ModelEMA, de_parallel, select_device, smart_DDP, smart_optimizer, + smart_resume, torch_distributed_zero_first) + +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +GIT_INFO = check_git_info() + + +def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary + save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze, mask_ratio = \ + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze, opt.mask_ratio + # callbacks.run('on_pretrain_routine_start') + + # Directories + w = save_dir / 'weights' # weights dir + (w.parent if evolve else w).mkdir(parents=True, exist_ok=True) # make dir + last, best = w / 'last.pt', w / 'best.pt' + + # Hyperparameters + if isinstance(hyp, str): + with open(hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) + opt.hyp = hyp.copy() # for saving hyps to checkpoints + + # Save run settings + if not evolve: + yaml_save(save_dir / 'hyp.yaml', hyp) + yaml_save(save_dir / 'opt.yaml', vars(opt)) + + # Loggers + data_dict = None + if RANK in {-1, 0}: + logger = GenericLogger(opt=opt, console_logger=LOGGER) + + # Config + plots = not evolve and not opt.noplots # create plots + overlap = not opt.no_overlap + cuda = device.type != 'cpu' + init_seeds(opt.seed + 1 + RANK, deterministic=True) + with torch_distributed_zero_first(LOCAL_RANK): + data_dict = data_dict or check_dataset(data) # check if None + train_path, val_path = data_dict['train'], data_dict['val'] + nc = 1 if single_cls else int(data_dict['nc']) # number of classes + names = {0: 'item'} if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names + is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO dataset + + # Model + check_suffix(weights, '.pt') # check weights + pretrained = weights.endswith('.pt') + if pretrained: + with torch_distributed_zero_first(LOCAL_RANK): + weights = attempt_download(weights) # download if not found locally + ckpt = torch.load(weights, map_location='cpu') # load checkpoint to CPU to avoid CUDA memory leak + model = SegmentationModel(cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) + exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else [] # exclude keys + csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 + csd = intersect_dicts(csd, model.state_dict(), exclude=exclude) # intersect + model.load_state_dict(csd, strict=False) # load + LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}') # report + else: + model = SegmentationModel(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create + amp = check_amp(model) # check AMP + + # Freeze + freeze = [f'model.{x}.' for x in (freeze if len(freeze) > 1 else range(freeze[0]))] # layers to freeze + for k, v in model.named_parameters(): + v.requires_grad = True # train all layers + # v.register_hook(lambda x: torch.nan_to_num(x)) # NaN to 0 (commented for erratic training results) + if any(x in k for x in freeze): + LOGGER.info(f'freezing {k}') + v.requires_grad = False + + # Image size + gs = max(int(model.stride.max()), 32) # grid size (max stride) + imgsz = check_img_size(opt.imgsz, gs, floor=gs * 2) # verify imgsz is gs-multiple + + # Batch size + if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size + batch_size = check_train_batch_size(model, imgsz, amp) + logger.update_params({"batch_size": batch_size}) + # loggers.on_params_update({"batch_size": batch_size}) + + # Optimizer + nbs = 64 # nominal batch size + accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing + hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay + optimizer = smart_optimizer(model, opt.optimizer, hyp['lr0'], hyp['momentum'], hyp['weight_decay']) + + # Scheduler + if opt.cos_lr: + lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] + else: + lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) + + # EMA + ema = ModelEMA(model) if RANK in {-1, 0} else None + + # Resume + best_fitness, start_epoch = 0.0, 0 + if pretrained: + if resume: + best_fitness, start_epoch, epochs = smart_resume(ckpt, optimizer, ema, weights, epochs, resume) + del ckpt, csd + + # DP mode + if cuda and RANK == -1 and torch.cuda.device_count() > 1: + LOGGER.warning('WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n' + 'See Multi-GPU Tutorial at https://github.com/ultralytics/yolov5/issues/475 to get started.') + model = torch.nn.DataParallel(model) + + # SyncBatchNorm + if opt.sync_bn and cuda and RANK != -1: + model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) + LOGGER.info('Using SyncBatchNorm()') + + # Trainloader + train_loader, dataset = create_dataloader( + train_path, + imgsz, + batch_size // WORLD_SIZE, + gs, + single_cls, + hyp=hyp, + augment=True, + cache=None if opt.cache == 'val' else opt.cache, + rect=opt.rect, + rank=LOCAL_RANK, + workers=workers, + image_weights=opt.image_weights, + quad=opt.quad, + prefix=colorstr('train: '), + shuffle=True, + mask_downsample_ratio=mask_ratio, + overlap_mask=overlap, + ) + labels = np.concatenate(dataset.labels, 0) + mlc = int(labels[:, 0].max()) # max label class + assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}' + + # Process 0 + if RANK in {-1, 0}: + val_loader = create_dataloader(val_path, + imgsz, + batch_size // WORLD_SIZE * 2, + gs, + single_cls, + hyp=hyp, + cache=None if noval else opt.cache, + rect=True, + rank=-1, + workers=workers * 2, + pad=0.5, + mask_downsample_ratio=mask_ratio, + overlap_mask=overlap, + prefix=colorstr('val: '))[0] + + if not resume: + if not opt.noautoanchor: + check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) # run AutoAnchor + model.half().float() # pre-reduce anchor precision + + if plots: + plot_labels(labels, names, save_dir) + # callbacks.run('on_pretrain_routine_end', labels, names) + + # DDP mode + if cuda and RANK != -1: + model = smart_DDP(model) + + # Model attributes + nl = de_parallel(model).model[-1].nl # number of detection layers (to scale hyps) + hyp['box'] *= 3 / nl # scale to layers + hyp['cls'] *= nc / 80 * 3 / nl # scale to classes and layers + hyp['obj'] *= (imgsz / 640) ** 2 * 3 / nl # scale to image size and layers + hyp['label_smoothing'] = opt.label_smoothing + model.nc = nc # attach number of classes to model + model.hyp = hyp # attach hyperparameters to model + model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights + model.names = names + + # Start training + t0 = time.time() + nb = len(train_loader) # number of batches + nw = max(round(hyp['warmup_epochs'] * nb), 100) # number of warmup iterations, max(3 epochs, 100 iterations) + # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training + last_opt_step = -1 + maps = np.zeros(nc) # mAP per class + results = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) + scheduler.last_epoch = start_epoch - 1 # do not move + scaler = torch.cuda.amp.GradScaler(enabled=amp) + stopper, stop = EarlyStopping(patience=opt.patience), False + compute_loss = ComputeLoss(model, overlap=overlap) # init loss class + # callbacks.run('on_train_start') + LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n' + f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' + f"Logging results to {colorstr('bold', save_dir)}\n" + f'Starting training for {epochs} epochs...') + for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ + # callbacks.run('on_train_epoch_start') + model.train() + + # Update image weights (optional, single-GPU only) + if opt.image_weights: + cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc # class weights + iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights + dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx + + # Update mosaic border (optional) + # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs) + # dataset.mosaic_border = [b - imgsz, -b] # height, width borders + + mloss = torch.zeros(4, device=device) # mean losses + if RANK != -1: + train_loader.sampler.set_epoch(epoch) + pbar = enumerate(train_loader) + LOGGER.info(('\n' + '%11s' * 8) % + ('Epoch', 'GPU_mem', 'box_loss', 'seg_loss', 'obj_loss', 'cls_loss', 'Instances', 'Size')) + if RANK in {-1, 0}: + pbar = tqdm(pbar, total=nb, bar_format=TQDM_BAR_FORMAT) # progress bar + optimizer.zero_grad() + for i, (imgs, targets, paths, _, masks) in pbar: # batch ------------------------------------------------------ + # callbacks.run('on_train_batch_start') + ni = i + nb * epoch # number integrated batches (since train start) + imgs = imgs.to(device, non_blocking=True).float() / 255 # uint8 to float32, 0-255 to 0.0-1.0 + + # Warmup + if ni <= nw: + xi = [0, nw] # x interp + # compute_loss.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou) + accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round()) + for j, x in enumerate(optimizer.param_groups): + # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 + x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 0 else 0.0, x['initial_lr'] * lf(epoch)]) + if 'momentum' in x: + x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) + + # Multi-scale + if opt.multi_scale: + sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size + sf = sz / max(imgs.shape[2:]) # scale factor + if sf != 1: + ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) + imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) + + # Forward + with torch.cuda.amp.autocast(amp): + pred = model(imgs) # forward + loss, loss_items = compute_loss(pred, targets.to(device), masks=masks.to(device).float()) + if RANK != -1: + loss *= WORLD_SIZE # gradient averaged between devices in DDP mode + if opt.quad: + loss *= 4. + + # Backward + scaler.scale(loss).backward() + + # Optimize - https://pytorch.org/docs/master/notes/amp_examples.html + if ni - last_opt_step >= accumulate: + scaler.unscale_(optimizer) # unscale gradients + torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=10.0) # clip gradients + scaler.step(optimizer) # optimizer.step + scaler.update() + optimizer.zero_grad() + if ema: + ema.update(model) + last_opt_step = ni + + # Log + if RANK in {-1, 0}: + mloss = (mloss * i + loss_items) / (i + 1) # update mean losses + mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G' # (GB) + pbar.set_description(('%11s' * 2 + '%11.4g' * 6) % + (f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])) + # callbacks.run('on_train_batch_end', model, ni, imgs, targets, paths) + # if callbacks.stop_training: + # return + + # Mosaic plots + if plots: + if ni < 3: + plot_images_and_masks(imgs, targets, masks, paths, save_dir / f"train_batch{ni}.jpg") + if ni == 10: + files = sorted(save_dir.glob('train*.jpg')) + logger.log_images(files, "Mosaics", epoch) + # end batch ------------------------------------------------------------------------------------------------ + + # Scheduler + lr = [x['lr'] for x in optimizer.param_groups] # for loggers + scheduler.step() + + if RANK in {-1, 0}: + # mAP + # callbacks.run('on_train_epoch_end', epoch=epoch) + ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights']) + final_epoch = (epoch + 1 == epochs) or stopper.possible_stop + if not noval or final_epoch: # Calculate mAP + results, maps, _ = validate.run(data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + half=amp, + model=ema.ema, + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + plots=False, + callbacks=callbacks, + compute_loss=compute_loss, + mask_downsample_ratio=mask_ratio, + overlap=overlap) + + # Update best mAP + fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + stop = stopper(epoch=epoch, fitness=fi) # early stop check + if fi > best_fitness: + best_fitness = fi + log_vals = list(mloss) + list(results) + lr + # callbacks.run('on_fit_epoch_end', log_vals, epoch, best_fitness, fi) + # Log val metrics and media + metrics_dict = dict(zip(KEYS, log_vals)) + logger.log_metrics(metrics_dict, epoch) + + # Save model + if (not nosave) or (final_epoch and not evolve): # if save + ckpt = { + 'epoch': epoch, + 'best_fitness': best_fitness, + 'model': deepcopy(de_parallel(model)).half(), + 'ema': deepcopy(ema.ema).half(), + 'updates': ema.updates, + 'optimizer': optimizer.state_dict(), + 'opt': vars(opt), + 'git': GIT_INFO, # {remote, branch, commit} if a git repo + 'date': datetime.now().isoformat()} + + # Save last, best and delete + torch.save(ckpt, last) + if best_fitness == fi: + torch.save(ckpt, best) + if opt.save_period > 0 and epoch % opt.save_period == 0: + torch.save(ckpt, w / f'epoch{epoch}.pt') + logger.log_model(w / f'epoch{epoch}.pt') + del ckpt + # callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi) + + # EarlyStopping + if RANK != -1: # if DDP training + broadcast_list = [stop if RANK == 0 else None] + dist.broadcast_object_list(broadcast_list, 0) # broadcast 'stop' to all ranks + if RANK != 0: + stop = broadcast_list[0] + if stop: + break # must break all DDP ranks + + # end epoch ---------------------------------------------------------------------------------------------------- + # end training ----------------------------------------------------------------------------------------------------- + if RANK in {-1, 0}: + LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.') + for f in last, best: + if f.exists(): + strip_optimizer(f) # strip optimizers + if f is best: + LOGGER.info(f'\nValidating {f}...') + results, _, _ = validate.run( + data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + model=attempt_load(f, device).half(), + iou_thres=0.65 if is_coco else 0.60, # best pycocotools at iou 0.65 + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + save_json=is_coco, + verbose=True, + plots=plots, + callbacks=callbacks, + compute_loss=compute_loss, + mask_downsample_ratio=mask_ratio, + overlap=overlap) # val best model with plots + if is_coco: + # callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi) + metrics_dict = dict(zip(KEYS, list(mloss) + list(results) + lr)) + logger.log_metrics(metrics_dict, epoch) + + # callbacks.run('on_train_end', last, best, epoch, results) + # on train end callback using genericLogger + logger.log_metrics(dict(zip(KEYS[4:16], results)), epochs) + if not opt.evolve: + logger.log_model(best, epoch) + if plots: + plot_results_with_masks(file=save_dir / 'results.csv') # save results.png + files = ['results.png', 'confusion_matrix.png', *(f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R'))] + files = [(save_dir / f) for f in files if (save_dir / f).exists()] # filter + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}") + logger.log_images(files, "Results", epoch + 1) + logger.log_images(sorted(save_dir.glob('val*.jpg')), "Validation", epoch + 1) + torch.cuda.empty_cache() + return results + + +def parse_opt(known=False): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s-seg.pt', help='initial weights path') + parser.add_argument('--cfg', type=str, default='', help='model.yaml path') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128-seg.yaml', help='dataset.yaml path') + parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path') + parser.add_argument('--epochs', type=int, default=100, help='total training epochs') + parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') + parser.add_argument('--rect', action='store_true', help='rectangular training') + parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') + parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') + parser.add_argument('--noval', action='store_true', help='only validate final epoch') + parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') + parser.add_argument('--noplots', action='store_true', help='save no plot files') + parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') + parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') + parser.add_argument('--cache', type=str, nargs='?', const='ram', help='image --cache ram/disk') + parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') + parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') + parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer') + parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--project', default=ROOT / 'runs/train-seg', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--quad', action='store_true', help='quad dataloader') + parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') + parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') + parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') + parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') + parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') + parser.add_argument('--seed', type=int, default=0, help='Global training seed') + parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + + # Instance Segmentation Args + parser.add_argument('--mask-ratio', type=int, default=4, help='Downsample the truth masks to saving memory') + parser.add_argument('--no-overlap', action='store_true', help='Overlap masks train faster at slightly less mAP') + + return parser.parse_known_args()[0] if known else parser.parse_args() + + +def main(opt, callbacks=Callbacks()): + # Checks + if RANK in {-1, 0}: + print_args(vars(opt)) + check_git_status() + check_requirements() + + # Resume + if opt.resume and not opt.evolve: # resume from specified or most recent last.pt + last = Path(check_file(opt.resume) if isinstance(opt.resume, str) else get_latest_run()) + opt_yaml = last.parent.parent / 'opt.yaml' # train options yaml + opt_data = opt.data # original dataset + if opt_yaml.is_file(): + with open(opt_yaml, errors='ignore') as f: + d = yaml.safe_load(f) + else: + d = torch.load(last, map_location='cpu')['opt'] + opt = argparse.Namespace(**d) # replace + opt.cfg, opt.weights, opt.resume = '', str(last), True # reinstate + if is_url(opt_data): + opt.data = check_file(opt_data) # avoid HUB resume auth timeout + else: + opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \ + check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks + assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' + if opt.evolve: + if opt.project == str(ROOT / 'runs/train'): # if default project name, rename to runs/evolve + opt.project = str(ROOT / 'runs/evolve') + opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume + if opt.name == 'cfg': + opt.name = Path(opt.cfg).stem # use model.yaml as name + opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) + + # DDP mode + device = select_device(opt.device, batch_size=opt.batch_size) + if LOCAL_RANK != -1: + msg = 'is not compatible with YOLOv5 Multi-GPU DDP training' + assert not opt.image_weights, f'--image-weights {msg}' + assert not opt.evolve, f'--evolve {msg}' + assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size' + assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' + assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' + torch.cuda.set_device(LOCAL_RANK) + device = torch.device('cuda', LOCAL_RANK) + dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") + + # Train + if not opt.evolve: + train(opt.hyp, opt, device, callbacks) + + # Evolve hyperparameters (optional) + else: + # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) + meta = { + 'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) + 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) + 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 + 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay + 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) + 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum + 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr + 'box': (1, 0.02, 0.2), # box loss gain + 'cls': (1, 0.2, 4.0), # cls loss gain + 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight + 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) + 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight + 'iou_t': (0, 0.1, 0.7), # IoU training threshold + 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold + 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) + 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) + 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) + 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) + 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) + 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) + 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) + 'scale': (1, 0.0, 0.9), # image scale (+/- gain) + 'shear': (1, 0.0, 10.0), # image shear (+/- deg) + 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 + 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) + 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) + 'mosaic': (1, 0.0, 1.0), # image mixup (probability) + 'mixup': (1, 0.0, 1.0), # image mixup (probability) + 'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) + + with open(opt.hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + if 'anchors' not in hyp: # anchors commented in hyp.yaml + hyp['anchors'] = 3 + if opt.noautoanchor: + del hyp['anchors'], meta['anchors'] + opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir) # only val/save final epoch + # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices + evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' + if opt.bucket: + subprocess.run( + f'gsutil cp gs://{opt.bucket}/evolve.csv {evolve_csv}'.split()) # download evolve.csv if exists + + for _ in range(opt.evolve): # generations to evolve + if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate + # Select parent(s) + parent = 'single' # parent selection method: 'single' or 'weighted' + x = np.loadtxt(evolve_csv, ndmin=2, delimiter=',', skiprows=1) + n = min(5, len(x)) # number of previous results to consider + x = x[np.argsort(-fitness(x))][:n] # top n mutations + w = fitness(x) - fitness(x).min() + 1E-6 # weights (sum > 0) + if parent == 'single' or len(x) == 1: + # x = x[random.randint(0, n - 1)] # random selection + x = x[random.choices(range(n), weights=w)[0]] # weighted selection + elif parent == 'weighted': + x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination + + # Mutate + mp, s = 0.8, 0.2 # mutation probability, sigma + npr = np.random + npr.seed(int(time.time())) + g = np.array([meta[k][0] for k in hyp.keys()]) # gains 0-1 + ng = len(meta) + v = np.ones(ng) + while all(v == 1): # mutate until a change occurs (prevent duplicates) + v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) + for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) + hyp[k] = float(x[i + 7] * v[i]) # mutate + + # Constrain to limits + for k, v in meta.items(): + hyp[k] = max(hyp[k], v[1]) # lower limit + hyp[k] = min(hyp[k], v[2]) # upper limit + hyp[k] = round(hyp[k], 5) # significant digits + + # Train mutation + results = train(hyp.copy(), opt, device, callbacks) + callbacks = Callbacks() + # Write mutation results + print_mutation(KEYS, results, hyp.copy(), save_dir, opt.bucket) + + # Plot results + plot_evolve(evolve_csv) + LOGGER.info(f'Hyperparameter evolution finished {opt.evolve} generations\n' + f"Results saved to {colorstr('bold', save_dir)}\n" + f'Usage example: $ python train.py --hyp {evolve_yaml}') + + +def run(**kwargs): + # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolov5m.pt') + opt = parse_opt(True) + for k, v in kwargs.items(): + setattr(opt, k, v) + main(opt) + return opt + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/segment/tutorial.ipynb b/segment/tutorial.ipynb new file mode 100644 index 0000000000..be43d6d205 --- /dev/null +++ b/segment/tutorial.ipynb @@ -0,0 +1,594 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "t6MPjfT5NrKQ" + }, + "source": [ + "
\n", + "\n", + " \n", + " \n", + "\n", + "\n", + "
\n", + " \"Run\n", + " \"Open\n", + " \"Open\n", + "
\n", + "\n", + "This 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7mGmQbAO5pQb" + }, + "source": [ + "# Setup\n", + "\n", + "Clone GitHub [repository](https://github.com/ultralytics/yolov5), install [dependencies](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) and check PyTorch and GPU." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "wbvMlHd_QwMG", + "outputId": "171b23f0-71b9-4cbf-b666-6fa2ecef70c8" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + " 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Setup complete ✅ (2 CPUs, 12.7 GB RAM, 22.6/78.2 GB disk)\n" + ] + } + ], + "source": [ + "!git clone https://github.com/ultralytics/yolov5 # clone\n", + "%cd yolov5\n", + "%pip install -qr requirements.txt # install\n", + "\n", + "import torch\n", + "import utils\n", + "display = utils.notebook_init() # checks" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4JnkELT0cIJg" + }, + "source": [ + "# 1. Predict\n", + "\n", + "`segment/predict.py` runs instance segmentation inference on a variety of sources, downloading models automatically from the [latest release](https://github.com/ultralytics/yolov5/releases), and saving results to `runs/predict`. Example inference sources are:\n", + "\n", + "```shell\n", + "python segment/predict.py --source 0 # webcam\n", + " img.jpg # image \n", + " vid.mp4 # video\n", + " screen # screenshot\n", + " path/ # directory\n", + " 'path/*.jpg' # glob\n", + " 'https://youtu.be/Zgi9g1ksQHc' # YouTube\n", + " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "zR9ZbuQCH7FX", + "outputId": "3f67f1c7-f15e-4fa5-d251-967c3b77eaad" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\u001b[34m\u001b[1msegment/predict: \u001b[0mweights=['yolov5s-seg.pt'], source=data/images, data=data/coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/predict-seg, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False, vid_stride=1, retina_masks=False\n", + "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "\n", + "Downloading https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt to yolov5s-seg.pt...\n", + "100% 14.9M/14.9M [00:01<00:00, 12.0MB/s]\n", + "\n", + "Fusing layers... \n", + "YOLOv5s-seg summary: 224 layers, 7611485 parameters, 0 gradients, 26.4 GFLOPs\n", + "image 1/2 /content/yolov5/data/images/bus.jpg: 640x480 4 persons, 1 bus, 18.2ms\n", + "image 2/2 /content/yolov5/data/images/zidane.jpg: 384x640 2 persons, 1 tie, 13.4ms\n", + "Speed: 0.5ms pre-process, 15.8ms inference, 18.5ms NMS per image at shape (1, 3, 640, 640)\n", + "Results saved to \u001b[1mruns/predict-seg/exp\u001b[0m\n" + ] + } + ], + "source": [ + "!python segment/predict.py --weights yolov5s-seg.pt --img 640 --conf 0.25 --source data/images\n", + "#display.Image(filename='runs/predict-seg/exp/zidane.jpg', width=600)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hkAzDWJ7cWTr" + }, + "source": [ + "        \n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0eq1SMWl6Sfn" + }, + "source": [ + "# 2. Validate\n", + "Validate a model's accuracy on the [COCO](https://cocodataset.org/#home) dataset's `val` or `test` splits. Models are downloaded automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases). To show results by class use the `--verbose` flag." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "WQPtK1QYVaD_", + "outputId": "9d751d8c-bee8-4339-cf30-9854ca530449" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading https://github.com/ultralytics/yolov5/releases/download/v1.0/coco2017labels-segments.zip ...\n", + "Downloading http://images.cocodataset.org/zips/val2017.zip ...\n", + "######################################################################## 100.0%\n", + "######################################################################## 100.0%\n" + ] + } + ], + "source": [ + "# Download COCO val\n", + "!bash data/scripts/get_coco.sh --val --segments # download (780M - 5000 images)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "X58w8JLpMnjH", + "outputId": "a140d67a-02da-479e-9ddb-7d54bf9e407a" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\u001b[34m\u001b[1msegment/val: \u001b[0mdata=/content/yolov5/data/coco.yaml, weights=['yolov5s-seg.pt'], batch_size=32, imgsz=640, conf_thres=0.001, iou_thres=0.6, max_det=300, task=val, device=, workers=8, single_cls=False, augment=False, verbose=False, save_txt=False, save_hybrid=False, save_conf=False, save_json=False, project=runs/val-seg, name=exp, exist_ok=False, half=True, dnn=False\n", + "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "\n", + "Fusing layers... \n", + "YOLOv5s-seg summary: 224 layers, 7611485 parameters, 0 gradients, 26.4 GFLOPs\n", + "\u001b[34m\u001b[1mval: \u001b[0mScanning /content/datasets/coco/val2017... 4952 images, 48 backgrounds, 0 corrupt: 100% 5000/5000 [00:03<00:00, 1361.31it/s]\n", + "\u001b[34m\u001b[1mval: \u001b[0mNew cache created: /content/datasets/coco/val2017.cache\n", + " Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100% 157/157 [01:54<00:00, 1.37it/s]\n", + " all 5000 36335 0.673 0.517 0.566 0.373 0.672 0.49 0.532 0.319\n", + "Speed: 0.6ms pre-process, 4.4ms inference, 2.9ms NMS per image at shape (32, 3, 640, 640)\n", + "Results saved to \u001b[1mruns/val-seg/exp\u001b[0m\n" + ] + } + ], + "source": [ + "# Validate YOLOv5s-seg on COCO val\n", + "!python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 --half" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZY2VXXXu74w5" + }, + "source": [ + "# 3. Train\n", + "\n", + "

\n", + "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", + "

\n", + "\n", + "Train a YOLOv5s-seg model on the [COCO128](https://www.kaggle.com/ultralytics/coco128) dataset with `--data coco128-seg.yaml`, starting from pretrained `--weights yolov5s-seg.pt`, or from randomly initialized `--weights '' --cfg yolov5s-seg.yaml`.\n", + "\n", + "- **Pretrained [Models](https://github.com/ultralytics/yolov5/tree/master/models)** are downloaded\n", + "automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases)\n", + "- **[Datasets](https://github.com/ultralytics/yolov5/tree/master/data)** available for autodownload include: [COCO](https://github.com/ultralytics/yolov5/blob/master/data/coco.yaml), [COCO128](https://github.com/ultralytics/yolov5/blob/master/data/coco128.yaml), [VOC](https://github.com/ultralytics/yolov5/blob/master/data/VOC.yaml), [Argoverse](https://github.com/ultralytics/yolov5/blob/master/data/Argoverse.yaml), [VisDrone](https://github.com/ultralytics/yolov5/blob/master/data/VisDrone.yaml), [GlobalWheat](https://github.com/ultralytics/yolov5/blob/master/data/GlobalWheat2020.yaml), [xView](https://github.com/ultralytics/yolov5/blob/master/data/xView.yaml), [Objects365](https://github.com/ultralytics/yolov5/blob/master/data/Objects365.yaml), [SKU-110K](https://github.com/ultralytics/yolov5/blob/master/data/SKU-110K.yaml).\n", + "- **Training Results** are saved to `runs/train-seg/` with incrementing run directories, i.e. `runs/train-seg/exp2`, `runs/train-seg/exp3` etc.\n", + "

\n", + "\n", + "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic.\n", + "\n", + "## Train on Custom Data with Roboflow 🌟 NEW\n", + "\n", + "[Roboflow](https://roboflow.com/?ref=ultralytics) enables you to easily **organize, label, and prepare** a high quality dataset with your own custom data. Roboflow also makes it easy to establish an active learning pipeline, collaborate with your team on dataset improvement, and integrate directly into your model building workflow with the `roboflow` pip package.\n", + "\n", + "- Custom Training Example: [https://blog.roboflow.com/train-yolov5-instance-segmentation-custom-dataset/](https://blog.roboflow.com/train-yolov5-instance-segmentation-custom-dataset/?ref=ultralytics)\n", + "- Custom Training Notebook: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1JTz7kpmHsg-5qwVz2d2IH3AaenI1tv0N?usp=sharing)\n", + "
\n", + "\n", + "

Label images lightning fast (including with model-assisted labeling)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "i3oKtE4g-aNn" + }, + "outputs": [], + "source": [ + "#@title Select YOLOv5 🚀 logger {run: 'auto'}\n", + "logger = 'TensorBoard' #@param ['TensorBoard', 'Comet', 'ClearML']\n", + "\n", + "if logger == 'TensorBoard':\n", + " %load_ext tensorboard\n", + " %tensorboard --logdir runs/train-seg\n", + "elif logger == 'Comet':\n", + " %pip install -q comet_ml\n", + " import comet_ml; comet_ml.init()\n", + "elif logger == 'ClearML':\n", + " import clearml; clearml.browser_login()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1NcFxRcFdJ_O", + "outputId": "3a3e0cf7-e79c-47a5-c8e7-2d26eeeab988" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\u001b[34m\u001b[1msegment/train: \u001b[0mweights=yolov5s-seg.pt, cfg=, data=coco128-seg.yaml, hyp=data/hyps/hyp.scratch-low.yaml, epochs=3, batch_size=16, imgsz=640, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, noplots=False, evolve=None, bucket=, cache=ram, image_weights=False, device=, multi_scale=False, single_cls=False, optimizer=SGD, sync_bn=False, workers=8, project=runs/train-seg, name=exp, exist_ok=False, quad=False, cos_lr=False, label_smoothing=0.0, patience=100, freeze=[0], save_period=-1, seed=0, local_rank=-1, mask_ratio=4, no_overlap=False\n", + "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", + "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "\n", + "\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0\n", + "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train-seg', view at http://localhost:6006/\n", + "\n", + "Dataset not found ⚠️, missing paths ['/content/datasets/coco128-seg/images/train2017']\n", + "Downloading https://ultralytics.com/assets/coco128-seg.zip to coco128-seg.zip...\n", + "100% 6.79M/6.79M [00:01<00:00, 6.73MB/s]\n", + "Dataset download success ✅ (1.9s), saved to \u001b[1m/content/datasets\u001b[0m\n", + "\n", + " from n params module arguments \n", + " 0 -1 1 3520 models.common.Conv [3, 32, 6, 2, 2] \n", + " 1 -1 1 18560 models.common.Conv [32, 64, 3, 2] \n", + " 2 -1 1 18816 models.common.C3 [64, 64, 1] \n", + " 3 -1 1 73984 models.common.Conv [64, 128, 3, 2] \n", + " 4 -1 2 115712 models.common.C3 [128, 128, 2] \n", + " 5 -1 1 295424 models.common.Conv [128, 256, 3, 2] \n", + " 6 -1 3 625152 models.common.C3 [256, 256, 3] \n", + " 7 -1 1 1180672 models.common.Conv [256, 512, 3, 2] \n", + " 8 -1 1 1182720 models.common.C3 [512, 512, 1] \n", + " 9 -1 1 656896 models.common.SPPF [512, 512, 5] \n", + " 10 -1 1 131584 models.common.Conv [512, 256, 1, 1] \n", + " 11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 12 [-1, 6] 1 0 models.common.Concat [1] \n", + " 13 -1 1 361984 models.common.C3 [512, 256, 1, False] \n", + " 14 -1 1 33024 models.common.Conv [256, 128, 1, 1] \n", + " 15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 16 [-1, 4] 1 0 models.common.Concat [1] \n", + " 17 -1 1 90880 models.common.C3 [256, 128, 1, False] \n", + " 18 -1 1 147712 models.common.Conv [128, 128, 3, 2] \n", + " 19 [-1, 14] 1 0 models.common.Concat [1] \n", + " 20 -1 1 296448 models.common.C3 [256, 256, 1, False] \n", + " 21 -1 1 590336 models.common.Conv [256, 256, 3, 2] \n", + " 22 [-1, 10] 1 0 models.common.Concat [1] \n", + " 23 -1 1 1182720 models.common.C3 [512, 512, 1, False] \n", + " 24 [17, 20, 23] 1 615133 models.yolo.Segment [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], 32, 128, [128, 256, 512]]\n", + "Model summary: 225 layers, 7621277 parameters, 7621277 gradients, 26.6 GFLOPs\n", + "\n", + "Transferred 367/367 items from yolov5s-seg.pt\n", + "\u001b[34m\u001b[1mAMP: \u001b[0mchecks passed ✅\n", + "\u001b[34m\u001b[1moptimizer:\u001b[0m SGD(lr=0.01) with parameter groups 60 weight(decay=0.0), 63 weight(decay=0.0005), 63 bias\n", + "\u001b[34m\u001b[1malbumentations: \u001b[0mBlur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01), CLAHE(p=0.01, clip_limit=(1, 4.0), tile_grid_size=(8, 8))\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mScanning /content/datasets/coco128-seg/labels/train2017... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00<00:00, 1389.59it/s]\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mNew cache created: /content/datasets/coco128-seg/labels/train2017.cache\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mCaching images (0.1GB ram): 100% 128/128 [00:00<00:00, 238.86it/s]\n", + "\u001b[34m\u001b[1mval: \u001b[0mScanning /content/datasets/coco128-seg/labels/train2017.cache... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00 # 2. paste API key\n", + "python train.py --img 640 --epochs 3 --data coco128.yaml --weights yolov5s.pt # 3. train\n", + "```\n", + "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/comet). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing)\n", + "\n", + "\n", + "\"Comet" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Lay2WsTjNJzP" + }, + "source": [ + "## ClearML Logging and Automation 🌟 NEW\n", + "\n", + "[ClearML](https://cutt.ly/yolov5-notebook-clearml) is completely integrated into YOLOv5 to track your experimentation, manage dataset versions and even remotely execute training runs. To enable ClearML (check cells above):\n", + "\n", + "- `pip install clearml`\n", + "- run `clearml-init` to connect to a ClearML server (**deploy your own [open-source server](https://github.com/allegroai/clearml-server)**, or use our [free hosted server](https://cutt.ly/yolov5-notebook-clearml))\n", + "\n", + "You'll get all the great expected features from an experiment manager: live updates, model upload, experiment comparison etc. but ClearML also tracks uncommitted changes and installed packages for example. Thanks to that ClearML Tasks (which is what we call experiments) are also reproducible on different machines! With only 1 extra line, we can schedule a YOLOv5 training task on a queue to be executed by any number of ClearML Agents (workers).\n", + "\n", + "You can use ClearML Data to version your dataset and then pass it to YOLOv5 simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml) for details!\n", + "\n", + "\n", + "\"ClearML" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-WPvRbS5Swl6" + }, + "source": [ + "## Local Logging\n", + "\n", + "Training results are automatically logged with [Tensorboard](https://www.tensorflow.org/tensorboard) and [CSV](https://github.com/ultralytics/yolov5/pull/4148) loggers to `runs/train`, with a new experiment directory created for each new training as `runs/train/exp2`, `runs/train/exp3`, etc.\n", + "\n", + "This directory contains train and val statistics, mosaics, labels, predictions and augmentated mosaics, as well as metrics and charts including precision-recall (PR) curves and confusion matrices. \n", + "\n", + "\"Local\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Zelyeqbyt3GD" + }, + "source": [ + "# Environments\n", + "\n", + "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):\n", + "\n", + "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", + "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/GCP-Quickstart)\n", + "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/AWS-Quickstart)\n", + "- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/Docker-Quickstart) \"Docker\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6Qu7Iesl0p54" + }, + "source": [ + "# Status\n", + "\n", + "![YOLOv5 CI](https://github.com/ultralytics/yolov3/actions/workflows/ci-testing.yml/badge.svg)\n", + "\n", + "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/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)), testing ([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.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IEijrePND_2I" + }, + "source": [ + "# Appendix\n", + "\n", + "Additional content below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GMusP4OAxFu6" + }, + "outputs": [], + "source": [ + "# YOLOv5 PyTorch HUB Inference (DetectionModels only)\n", + "import torch\n", + "\n", + "model = torch.hub.load('ultralytics/yolov5', 'yolov5s-seg') # yolov5n - yolov5x6 or custom\n", + "im = 'https://ultralytics.com/images/zidane.jpg' # file, Path, PIL.Image, OpenCV, nparray, list\n", + "results = model(im) # inference\n", + "results.print() # or .show(), .save(), .crop(), .pandas(), etc." + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "name": "YOLOv5 Segmentation Tutorial", + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/segment/val.py b/segment/val.py new file mode 100644 index 0000000000..0e64da288f --- /dev/null +++ b/segment/val.py @@ -0,0 +1,473 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Validate a trained segment model on a segment dataset + +Usage: + $ bash data/scripts/get_coco.sh --val --segments # download COCO-segments val split (1G, 5000 images) + $ python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 # validate COCO-segments + +Usage - formats: + $ python segment/val.py --weights yolov5s-seg.pt # PyTorch + yolov5s-seg.torchscript # TorchScript + yolov5s-seg.onnx # ONNX Runtime or OpenCV DNN with --dnn + yolov5s-seg_openvino_label # OpenVINO + yolov5s-seg.engine # TensorRT + yolov5s-seg.mlmodel # CoreML (macOS-only) + yolov5s-seg_saved_model # TensorFlow SavedModel + yolov5s-seg.pb # TensorFlow GraphDef + yolov5s-seg.tflite # TensorFlow Lite + yolov5s-seg_edgetpu.tflite # TensorFlow Edge TPU + yolov5s-seg_paddle_model # PaddlePaddle +""" + +import argparse +import json +import os +import subprocess +import sys +from multiprocessing.pool import ThreadPool +from pathlib import Path + +import numpy as np +import torch +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +import torch.nn.functional as F + +from models.common import DetectMultiBackend +from models.yolo import SegmentationModel +from utils.callbacks import Callbacks +from utils.general import (LOGGER, NUM_THREADS, TQDM_BAR_FORMAT, Profile, check_dataset, check_img_size, + check_requirements, check_yaml, coco80_to_coco91_class, colorstr, increment_path, + non_max_suppression, print_args, scale_boxes, xywh2xyxy, xyxy2xywh) +from utils.metrics import ConfusionMatrix, box_iou +from utils.plots import output_to_target, plot_val_study +from utils.segment.dataloaders import create_dataloader +from utils.segment.general import mask_iou, process_mask, process_mask_native, scale_image +from utils.segment.metrics import Metrics, ap_per_class_box_and_mask +from utils.segment.plots import plot_images_and_masks +from utils.torch_utils import de_parallel, select_device, smart_inference_mode + + +def save_one_txt(predn, save_conf, shape, file): + # Save one txt result + gn = torch.tensor(shape)[[1, 0, 1, 0]] # normalization gain whwh + for *xyxy, conf, cls in predn.tolist(): + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format + with open(file, 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + +def save_one_json(predn, jdict, path, class_map, pred_masks): + # Save one JSON result {"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236} + from pycocotools.mask import encode + + def single_encode(x): + rle = encode(np.asarray(x[:, :, None], order="F", dtype="uint8"))[0] + rle["counts"] = rle["counts"].decode("utf-8") + return rle + + image_id = int(path.stem) if path.stem.isnumeric() else path.stem + box = xyxy2xywh(predn[:, :4]) # xywh + box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner + pred_masks = np.transpose(pred_masks, (2, 0, 1)) + with ThreadPool(NUM_THREADS) as pool: + rles = pool.map(single_encode, pred_masks) + for i, (p, b) in enumerate(zip(predn.tolist(), box.tolist())): + jdict.append({ + 'image_id': image_id, + 'category_id': class_map[int(p[5])], + 'bbox': [round(x, 3) for x in b], + 'score': round(p[4], 5), + 'segmentation': rles[i]}) + + +def process_batch(detections, labels, iouv, pred_masks=None, gt_masks=None, overlap=False, masks=False): + """ + Return correct prediction matrix + Arguments: + detections (array[N, 6]), x1, y1, x2, y2, conf, class + labels (array[M, 5]), class, x1, y1, x2, y2 + Returns: + correct (array[N, 10]), for 10 IoU levels + """ + if masks: + if overlap: + nl = len(labels) + index = torch.arange(nl, device=gt_masks.device).view(nl, 1, 1) + 1 + gt_masks = gt_masks.repeat(nl, 1, 1) # shape(1,640,640) -> (n,640,640) + gt_masks = torch.where(gt_masks == index, 1.0, 0.0) + if gt_masks.shape[1:] != pred_masks.shape[1:]: + gt_masks = F.interpolate(gt_masks[None], pred_masks.shape[1:], mode="bilinear", align_corners=False)[0] + gt_masks = gt_masks.gt_(0.5) + iou = mask_iou(gt_masks.view(gt_masks.shape[0], -1), pred_masks.view(pred_masks.shape[0], -1)) + else: # boxes + iou = box_iou(labels[:, 1:], detections[:, :4]) + + correct = np.zeros((detections.shape[0], iouv.shape[0])).astype(bool) + correct_class = labels[:, 0:1] == detections[:, 5] + for i in range(len(iouv)): + x = torch.where((iou >= iouv[i]) & correct_class) # IoU > threshold and classes match + if x[0].shape[0]: + matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() # [label, detect, iou] + if x[0].shape[0] > 1: + matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 1], return_index=True)[1]] + # matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 0], return_index=True)[1]] + correct[matches[:, 1].astype(int), i] = True + return torch.tensor(correct, dtype=torch.bool, device=iouv.device) + + +@smart_inference_mode() +def run( + data, + weights=None, # model.pt path(s) + batch_size=32, # batch size + imgsz=640, # inference size (pixels) + conf_thres=0.001, # confidence threshold + iou_thres=0.6, # NMS IoU threshold + max_det=300, # maximum detections per image + task='val', # train, val, test, speed or study + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + workers=8, # max dataloader workers (per RANK in DDP mode) + single_cls=False, # treat as single-class dataset + augment=False, # augmented inference + verbose=False, # verbose output + save_txt=False, # save results to *.txt + save_hybrid=False, # save label+prediction hybrid results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_json=False, # save a COCO-JSON results file + project=ROOT / 'runs/val-seg', # save to project/name + name='exp', # save to project/name + exist_ok=False, # existing project/name ok, do not increment + half=True, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + model=None, + dataloader=None, + save_dir=Path(''), + plots=True, + overlap=False, + mask_downsample_ratio=1, + compute_loss=None, + callbacks=Callbacks(), +): + if save_json: + check_requirements('pycocotools>=2.0.6') + process = process_mask_native # more accurate + else: + process = process_mask # faster + + # Initialize/load model and set device + training = model is not None + if training: # called by train.py + device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model + half &= device.type != 'cpu' # half precision only supported on CUDA + model.half() if half else model.float() + nm = de_parallel(model).model[-1].nm # number of masks + else: # called directly + device = select_device(device, batch_size=batch_size) + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, pt, jit, engine = model.stride, model.pt, model.jit, model.engine + imgsz = check_img_size(imgsz, s=stride) # check image size + half = model.fp16 # FP16 supported on limited backends with CUDA + nm = de_parallel(model).model.model[-1].nm if isinstance(model, SegmentationModel) else 32 # number of masks + if engine: + batch_size = model.batch_size + else: + device = model.device + if not (pt or jit): + batch_size = 1 # export.py models default to batch-size 1 + LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') + + # Data + data = check_dataset(data) # check + + # Configure + model.eval() + cuda = device.type != 'cpu' + is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'coco{os.sep}val2017.txt') # COCO dataset + nc = 1 if single_cls else int(data['nc']) # number of classes + iouv = torch.linspace(0.5, 0.95, 10, device=device) # iou vector for mAP@0.5:0.95 + niou = iouv.numel() + + # Dataloader + if not training: + if pt and not single_cls: # check --weights are trained on --data + ncm = model.model.nc + assert ncm == nc, f'{weights} ({ncm} classes) trained on different --data than what you passed ({nc} ' \ + f'classes). Pass correct combination of --weights and --data that are trained together.' + model.warmup(imgsz=(1 if pt else batch_size, 3, imgsz, imgsz)) # warmup + pad, rect = (0.0, False) if task == 'speed' else (0.5, pt) # square inference for benchmarks + task = task if task in ('train', 'val', 'test') else 'val' # path to train/val/test images + dataloader = create_dataloader(data[task], + imgsz, + batch_size, + stride, + single_cls, + pad=pad, + rect=rect, + workers=workers, + prefix=colorstr(f'{task}: '), + overlap_mask=overlap, + mask_downsample_ratio=mask_downsample_ratio)[0] + + seen = 0 + confusion_matrix = ConfusionMatrix(nc=nc) + names = model.names if hasattr(model, 'names') else model.module.names # get class names + if isinstance(names, (list, tuple)): # old format + names = dict(enumerate(names)) + class_map = coco80_to_coco91_class() if is_coco else list(range(1000)) + s = ('%22s' + '%11s' * 10) % ('Class', 'Images', 'Instances', 'Box(P', "R", "mAP50", "mAP50-95)", "Mask(P", "R", + "mAP50", "mAP50-95)") + dt = Profile(), Profile(), Profile() + metrics = Metrics() + loss = torch.zeros(4, device=device) + jdict, stats = [], [] + # callbacks.run('on_val_start') + pbar = tqdm(dataloader, desc=s, bar_format=TQDM_BAR_FORMAT) # progress bar + for batch_i, (im, targets, paths, shapes, masks) in enumerate(pbar): + # callbacks.run('on_val_batch_start') + with dt[0]: + if cuda: + im = im.to(device, non_blocking=True) + targets = targets.to(device) + masks = masks.to(device) + masks = masks.float() + im = im.half() if half else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + nb, _, height, width = im.shape # batch size, channels, height, width + + # Inference + with dt[1]: + preds, protos, train_out = model(im) if compute_loss else (*model(im, augment=augment)[:2], None) + + # Loss + if compute_loss: + loss += compute_loss((train_out, protos), targets, masks)[1] # box, obj, cls + + # NMS + targets[:, 2:] *= torch.tensor((width, height, width, height), device=device) # to pixels + lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling + with dt[2]: + preds = non_max_suppression(preds, + conf_thres, + iou_thres, + labels=lb, + multi_label=True, + agnostic=single_cls, + max_det=max_det, + nm=nm) + + # Metrics + plot_masks = [] # masks for plotting + for si, (pred, proto) in enumerate(zip(preds, protos)): + labels = targets[targets[:, 0] == si, 1:] + nl, npr = labels.shape[0], pred.shape[0] # number of labels, predictions + path, shape = Path(paths[si]), shapes[si][0] + correct_masks = torch.zeros(npr, niou, dtype=torch.bool, device=device) # init + correct_bboxes = torch.zeros(npr, niou, dtype=torch.bool, device=device) # init + seen += 1 + + if npr == 0: + if nl: + stats.append((correct_masks, correct_bboxes, *torch.zeros((2, 0), device=device), labels[:, 0])) + if plots: + confusion_matrix.process_batch(detections=None, labels=labels[:, 0]) + continue + + # Masks + midx = [si] if overlap else targets[:, 0] == si + gt_masks = masks[midx] + pred_masks = process(proto, pred[:, 6:], pred[:, :4], shape=im[si].shape[1:]) + + # Predictions + if single_cls: + pred[:, 5] = 0 + predn = pred.clone() + scale_boxes(im[si].shape[1:], predn[:, :4], shape, shapes[si][1]) # native-space pred + + # Evaluate + if nl: + tbox = xywh2xyxy(labels[:, 1:5]) # target boxes + scale_boxes(im[si].shape[1:], tbox, shape, shapes[si][1]) # native-space labels + labelsn = torch.cat((labels[:, 0:1], tbox), 1) # native-space labels + correct_bboxes = process_batch(predn, labelsn, iouv) + correct_masks = process_batch(predn, labelsn, iouv, pred_masks, gt_masks, overlap=overlap, masks=True) + if plots: + confusion_matrix.process_batch(predn, labelsn) + stats.append((correct_masks, correct_bboxes, pred[:, 4], pred[:, 5], labels[:, 0])) # (conf, pcls, tcls) + + pred_masks = torch.as_tensor(pred_masks, dtype=torch.uint8) + if plots and batch_i < 3: + plot_masks.append(pred_masks[:15]) # filter top 15 to plot + + # Save/log + if save_txt: + save_one_txt(predn, save_conf, shape, file=save_dir / 'labels' / f'{path.stem}.txt') + if save_json: + pred_masks = scale_image(im[si].shape[1:], + pred_masks.permute(1, 2, 0).contiguous().cpu().numpy(), shape, shapes[si][1]) + save_one_json(predn, jdict, path, class_map, pred_masks) # append to COCO-JSON dictionary + # callbacks.run('on_val_image_end', pred, predn, path, names, im[si]) + + # Plot images + if plots and batch_i < 3: + if len(plot_masks): + plot_masks = torch.cat(plot_masks, dim=0) + plot_images_and_masks(im, targets, masks, paths, save_dir / f'val_batch{batch_i}_labels.jpg', names) + plot_images_and_masks(im, output_to_target(preds, max_det=15), plot_masks, paths, + save_dir / f'val_batch{batch_i}_pred.jpg', names) # pred + + # callbacks.run('on_val_batch_end') + + # Compute metrics + stats = [torch.cat(x, 0).cpu().numpy() for x in zip(*stats)] # to numpy + if len(stats) and stats[0].any(): + results = ap_per_class_box_and_mask(*stats, plot=plots, save_dir=save_dir, names=names) + metrics.update(results) + nt = np.bincount(stats[4].astype(int), minlength=nc) # number of targets per class + + # Print results + pf = '%22s' + '%11i' * 2 + '%11.3g' * 8 # print format + LOGGER.info(pf % ("all", seen, nt.sum(), *metrics.mean_results())) + if nt.sum() == 0: + LOGGER.warning(f'WARNING ⚠️ no labels found in {task} set, can not compute metrics without labels') + + # Print results per class + if (verbose or (nc < 50 and not training)) and nc > 1 and len(stats): + for i, c in enumerate(metrics.ap_class_index): + LOGGER.info(pf % (names[c], seen, nt[c], *metrics.class_result(i))) + + # Print speeds + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + if not training: + shape = (batch_size, 3, imgsz, imgsz) + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {shape}' % t) + + # Plots + if plots: + confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) + # callbacks.run('on_val_end') + + mp_bbox, mr_bbox, map50_bbox, map_bbox, mp_mask, mr_mask, map50_mask, map_mask = metrics.mean_results() + + # Save JSON + if save_json and len(jdict): + w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights + anno_json = str(Path('../datasets/coco/annotations/instances_val2017.json')) # annotations + pred_json = str(save_dir / f"{w}_predictions.json") # predictions + LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') + with open(pred_json, 'w') as f: + json.dump(jdict, f) + + try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb + from pycocotools.coco import COCO + from pycocotools.cocoeval import COCOeval + + anno = COCO(anno_json) # init annotations api + pred = anno.loadRes(pred_json) # init predictions api + results = [] + for eval in COCOeval(anno, pred, 'bbox'), COCOeval(anno, pred, 'segm'): + if is_coco: + eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.im_files] # img ID to evaluate + eval.evaluate() + eval.accumulate() + eval.summarize() + results.extend(eval.stats[:2]) # update results (mAP@0.5:0.95, mAP@0.5) + map_bbox, map50_bbox, map_mask, map50_mask = results + except Exception as e: + LOGGER.info(f'pycocotools unable to run: {e}') + + # Return results + model.float() # for training + if not training: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + final_metric = mp_bbox, mr_bbox, map50_bbox, map_bbox, mp_mask, mr_mask, map50_mask, map_mask + return (*final_metric, *(loss.cpu() / len(dataloader)).tolist()), metrics.get_maps(nc), t + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128-seg.yaml', help='dataset.yaml path') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s-seg.pt', help='model path(s)') + parser.add_argument('--batch-size', type=int, default=32, help='batch size') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') + parser.add_argument('--conf-thres', type=float, default=0.001, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.6, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=300, help='maximum detections per image') + parser.add_argument('--task', default='val', help='train, val, test, speed or study') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--verbose', action='store_true', help='report mAP by class') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-hybrid', action='store_true', help='save label+prediction hybrid results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-json', action='store_true', help='save a COCO-JSON results file') + parser.add_argument('--project', default=ROOT / 'runs/val-seg', help='save results to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + opt = parser.parse_args() + opt.data = check_yaml(opt.data) # check YAML + # opt.save_json |= opt.data.endswith('coco.yaml') + opt.save_txt |= opt.save_hybrid + print_args(vars(opt)) + return opt + + +def main(opt): + check_requirements(requirements=ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + + if opt.task in ('train', 'val', 'test'): # run normally + if opt.conf_thres > 0.001: # https://github.com/ultralytics/yolov5/issues/1466 + LOGGER.warning(f'WARNING ⚠️ confidence threshold {opt.conf_thres} > 0.001 produces invalid results') + if opt.save_hybrid: + LOGGER.warning('WARNING ⚠️ --save-hybrid returns high mAP from hybrid labels, not from predictions alone') + run(**vars(opt)) + + else: + weights = opt.weights if isinstance(opt.weights, list) else [opt.weights] + opt.half = torch.cuda.is_available() and opt.device != 'cpu' # FP16 for fastest results + if opt.task == 'speed': # speed benchmarks + # python val.py --task speed --data coco.yaml --batch 1 --weights yolov5n.pt yolov5s.pt... + opt.conf_thres, opt.iou_thres, opt.save_json = 0.25, 0.45, False + for opt.weights in weights: + run(**vars(opt), plots=False) + + elif opt.task == 'study': # speed vs mAP benchmarks + # python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n.pt yolov5s.pt... + for opt.weights in weights: + f = f'study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt' # filename to save to + x, y = list(range(256, 1536 + 128, 128)), [] # x axis (image sizes), y axis + for opt.imgsz in x: # img-size + LOGGER.info(f'\nRunning {f} --imgsz {opt.imgsz}...') + r, _, t = run(**vars(opt), plots=False) + y.append(r + t) # results and times + np.savetxt(f, y, fmt='%10.4g') # save + subprocess.run('zip -r study.zip study_*.txt'.split()) + plot_val_study(x=x) # plot + else: + raise NotImplementedError(f'--task {opt.task} not in ("train", "val", "test", "speed", "study")') + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/setup.cfg b/setup.cfg index 4ca0f0d7aa..d7c4cb3e1a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,10 +1,10 @@ # Project-wide configuration file, can be used for package metadata and other toll configurations # Example usage: global configuration for PEP8 (via flake8) setting or default pytest arguments +# Local usage: pip install pre-commit, pre-commit run --all-files [metadata] license_file = LICENSE -description-file = README.md - +description_file = README.md [tool:pytest] norecursedirs = @@ -16,7 +16,6 @@ addopts = --durations=25 --color=yes - [flake8] max-line-length = 120 exclude = .tox,*.egg,build,temp @@ -26,26 +25,30 @@ verbose = 2 # https://pep8.readthedocs.io/en/latest/intro.html#error-codes format = pylint # see: https://www.flake8rules.com/ -ignore = - E731 # Do not assign a lambda expression, use a def - F405 - E402 - F841 - E741 - F821 - E722 - F401 - W504 - E127 - W504 - E231 - E501 - F403 - E302 - F541 - +ignore = E731,F405,E402,F401,W504,E127,E231,E501,F403 + # E731: Do not assign a lambda expression, use a def + # F405: name may be undefined, or defined from star imports: module + # E402: module level import not at top of file + # F401: module imported but unused + # W504: line break after binary operator + # E127: continuation line over-indented for visual indent + # E231: missing whitespace after ‘,’, ‘;’, or ‘:’ + # E501: line too long + # F403: ‘from module import *’ used; unable to detect undefined names [isort] # https://pycqa.github.io/isort/docs/configuration/options.html line_length = 120 +# see: https://pycqa.github.io/isort/docs/configuration/multi_line_output_modes.html multi_line_output = 0 + +[yapf] +based_on_style = pep8 +spaces_before_comment = 2 +COLUMN_LIMIT = 120 +COALESCE_BRACKETS = True +SPACES_AROUND_POWER_OPERATOR = True +SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = False +SPLIT_BEFORE_CLOSING_BRACKET = False +SPLIT_BEFORE_FIRST_ARGUMENT = False +# EACH_DICT_ENTRY_ON_SEPARATE_LINE = False diff --git a/train.py b/train.py index 9098b348ce..5ab44562c2 100644 --- a/train.py +++ b/train.py @@ -1,14 +1,25 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license """ -Train a model on a custom dataset +Train a YOLOv3 model on a custom dataset. +Models and datasets download automatically from the latest YOLOv3 release. -Usage: - $ python path/to/train.py --data coco128.yaml --weights yolov3.pt --img 640 +Usage - Single-GPU training: + $ python train.py --data coco128.yaml --weights yolov5s.pt --img 640 # from pretrained (recommended) + $ python train.py --data coco128.yaml --weights '' --cfg yolov5s.yaml --img 640 # from scratch + +Usage - Multi-GPU DDP training: + $ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 train.py --data coco128.yaml --weights yolov5s.pt --img 640 --device 0,1,2,3 + +Models: https://github.com/ultralytics/yolov5/tree/master/models +Datasets: https://github.com/ultralytics/yolov5/tree/master/data +Tutorial: https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data """ + import argparse import math import os import random +import subprocess import sys import time from copy import deepcopy @@ -20,49 +31,46 @@ import torch.distributed as dist import torch.nn as nn import yaml -from torch.cuda import amp -from torch.nn.parallel import DistributedDataParallel as DDP -from torch.optim import SGD, Adam, lr_scheduler +from torch.optim import lr_scheduler from tqdm import tqdm FILE = Path(__file__).resolve() -ROOT = FILE.parents[0] # root directory +ROOT = FILE.parents[0] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative -import val # for end-of-epoch mAP +import val as validate # for end-of-epoch mAP from models.experimental import attempt_load from models.yolo import Model from utils.autoanchor import check_anchors from utils.autobatch import check_train_batch_size from utils.callbacks import Callbacks -from utils.datasets import create_dataloader -from utils.downloads import attempt_download -from utils.general import (LOGGER, NCOLS, check_dataset, check_file, check_git_status, check_img_size, - check_requirements, check_suffix, check_yaml, colorstr, get_latest_run, increment_path, - init_seeds, intersect_dicts, labels_to_class_weights, labels_to_image_weights, methods, - one_cycle, print_args, print_mutation, strip_optimizer) +from utils.dataloaders import create_dataloader +from utils.downloads import attempt_download, is_url +from utils.general import (LOGGER, TQDM_BAR_FORMAT, check_amp, check_dataset, check_file, check_git_info, + check_git_status, check_img_size, check_requirements, check_suffix, check_yaml, colorstr, + get_latest_run, increment_path, init_seeds, intersect_dicts, labels_to_class_weights, + labels_to_image_weights, methods, one_cycle, print_args, print_mutation, strip_optimizer, + yaml_save) from utils.loggers import Loggers -from utils.loggers.wandb.wandb_utils import check_wandb_resume +from utils.loggers.comet.comet_utils import check_comet_resume from utils.loss import ComputeLoss from utils.metrics import fitness -from utils.plots import plot_evolve, plot_labels -from utils.torch_utils import EarlyStopping, ModelEMA, de_parallel, select_device, torch_distributed_zero_first +from utils.plots import plot_evolve +from utils.torch_utils import (EarlyStopping, ModelEMA, de_parallel, select_device, smart_DDP, smart_optimizer, + smart_resume, torch_distributed_zero_first) LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html RANK = int(os.getenv('RANK', -1)) WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +GIT_INFO = check_git_info() -def train(hyp, # path/to/hyp.yaml or hyp dictionary - opt, - device, - callbacks - ): - save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze, = \ - Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ - opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze +def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary + save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = \ + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze + callbacks.run('on_pretrain_routine_start') # Directories w = save_dir / 'weights' # weights dir @@ -74,36 +82,36 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary with open(hyp, errors='ignore') as f: hyp = yaml.safe_load(f) # load hyps dict LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) + opt.hyp = hyp.copy() # for saving hyps to checkpoints # Save run settings - with open(save_dir / 'hyp.yaml', 'w') as f: - yaml.safe_dump(hyp, f, sort_keys=False) - with open(save_dir / 'opt.yaml', 'w') as f: - yaml.safe_dump(vars(opt), f, sort_keys=False) - data_dict = None + if not evolve: + yaml_save(save_dir / 'hyp.yaml', hyp) + yaml_save(save_dir / 'opt.yaml', vars(opt)) # Loggers - if RANK in [-1, 0]: + data_dict = None + if RANK in {-1, 0}: loggers = Loggers(save_dir, weights, opt, hyp, LOGGER) # loggers instance - if loggers.wandb: - data_dict = loggers.wandb.data_dict - if resume: - weights, epochs, hyp = opt.weights, opt.epochs, opt.hyp # Register actions for k in methods(loggers): callbacks.register_action(k, callback=getattr(loggers, k)) + # Process custom dataset artifact link + data_dict = loggers.remote_dataset + if resume: # If resuming runs from remote artifact + weights, epochs, hyp, batch_size = opt.weights, opt.epochs, opt.hyp, opt.batch_size + # Config - plots = not evolve # create plots + plots = not evolve and not opt.noplots # create plots cuda = device.type != 'cpu' - init_seeds(1 + RANK) + init_seeds(opt.seed + 1 + RANK, deterministic=True) with torch_distributed_zero_first(LOCAL_RANK): data_dict = data_dict or check_dataset(data) # check if None train_path, val_path = data_dict['train'], data_dict['val'] nc = 1 if single_cls else int(data_dict['nc']) # number of classes - names = ['item'] if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names - assert len(names) == nc, f'{len(names)} names found for nc={nc} dataset in {data}' # check + names = {0: 'item'} if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO dataset # Model @@ -112,7 +120,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary if pretrained: with torch_distributed_zero_first(LOCAL_RANK): weights = attempt_download(weights) # download if not found locally - ckpt = torch.load(weights, map_location=device) # load checkpoint + ckpt = torch.load(weights, map_location='cpu') # load checkpoint to CPU to avoid CUDA memory leak model = Model(cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else [] # exclude keys csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 @@ -121,11 +129,13 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}') # report else: model = Model(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create + amp = check_amp(model) # check AMP # Freeze - freeze = [f'model.{x}.' for x in range(freeze)] # layers to freeze + freeze = [f'model.{x}.' for x in (freeze if len(freeze) > 1 else range(freeze[0]))] # layers to freeze for k, v in model.named_parameters(): v.requires_grad = True # train all layers + # v.register_hook(lambda x: torch.nan_to_num(x)) # NaN to 0 (commented for erratic training results) if any(x in k for x in freeze): LOGGER.info(f'freezing {k}') v.requires_grad = False @@ -136,70 +146,35 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # Batch size if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size - batch_size = check_train_batch_size(model, imgsz) + batch_size = check_train_batch_size(model, imgsz, amp) + loggers.on_params_update({"batch_size": batch_size}) # Optimizer nbs = 64 # nominal batch size accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay - LOGGER.info(f"Scaled weight_decay = {hyp['weight_decay']}") - - g0, g1, g2 = [], [], [] # optimizer parameter groups - for v in model.modules(): - if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter): # bias - g2.append(v.bias) - if isinstance(v, nn.BatchNorm2d): # weight (no decay) - g0.append(v.weight) - elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter): # weight (with decay) - g1.append(v.weight) - - if opt.adam: - optimizer = Adam(g0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999)) # adjust beta1 to momentum - else: - optimizer = SGD(g0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) - - optimizer.add_param_group({'params': g1, 'weight_decay': hyp['weight_decay']}) # add g1 with weight_decay - optimizer.add_param_group({'params': g2}) # add g2 (biases) - LOGGER.info(f"{colorstr('optimizer:')} {type(optimizer).__name__} with parameter groups " - f"{len(g0)} weight, {len(g1)} weight (no decay), {len(g2)} bias") - del g0, g1, g2 + optimizer = smart_optimizer(model, opt.optimizer, hyp['lr0'], hyp['momentum'], hyp['weight_decay']) # Scheduler - if opt.linear_lr: - lf = lambda x: (1 - x / (epochs - 1)) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear - else: + if opt.cos_lr: lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] + else: + lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) # EMA - ema = ModelEMA(model) if RANK in [-1, 0] else None + ema = ModelEMA(model) if RANK in {-1, 0} else None # Resume - start_epoch, best_fitness = 0, 0.0 + best_fitness, start_epoch = 0.0, 0 if pretrained: - # Optimizer - if ckpt['optimizer'] is not None: - optimizer.load_state_dict(ckpt['optimizer']) - best_fitness = ckpt['best_fitness'] - - # EMA - if ema and ckpt.get('ema'): - ema.ema.load_state_dict(ckpt['ema'].float().state_dict()) - ema.updates = ckpt['updates'] - - # Epochs - start_epoch = ckpt['epoch'] + 1 if resume: - assert start_epoch > 0, f'{weights} training to {epochs} epochs is finished, nothing to resume.' - if epochs < start_epoch: - LOGGER.info(f"{weights} has been trained for {ckpt['epoch']} epochs. Fine-tuning for {epochs} more epochs.") - epochs += ckpt['epoch'] # finetune additional epochs - + best_fitness, start_epoch, epochs = smart_resume(ckpt, optimizer, ema, weights, epochs, resume) del ckpt, csd # DP mode if cuda and RANK == -1 and torch.cuda.device_count() > 1: - LOGGER.warning('WARNING: DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n' + LOGGER.warning('WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n' 'See Multi-GPU Tutorial at https://github.com/ultralytics/yolov5/issues/475 to get started.') model = torch.nn.DataParallel(model) @@ -209,41 +184,53 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary LOGGER.info('Using SyncBatchNorm()') # Trainloader - train_loader, dataset = create_dataloader(train_path, imgsz, batch_size // WORLD_SIZE, gs, single_cls, - hyp=hyp, augment=True, cache=opt.cache, rect=opt.rect, rank=LOCAL_RANK, - workers=workers, image_weights=opt.image_weights, quad=opt.quad, - prefix=colorstr('train: '), shuffle=True) - mlc = int(np.concatenate(dataset.labels, 0)[:, 0].max()) # max label class - nb = len(train_loader) # number of batches + train_loader, dataset = create_dataloader(train_path, + imgsz, + batch_size // WORLD_SIZE, + gs, + single_cls, + hyp=hyp, + augment=True, + cache=None if opt.cache == 'val' else opt.cache, + rect=opt.rect, + rank=LOCAL_RANK, + workers=workers, + image_weights=opt.image_weights, + quad=opt.quad, + prefix=colorstr('train: '), + shuffle=True, + seed=opt.seed) + labels = np.concatenate(dataset.labels, 0) + mlc = int(labels[:, 0].max()) # max label class assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}' # Process 0 - if RANK in [-1, 0]: - val_loader = create_dataloader(val_path, imgsz, batch_size // WORLD_SIZE * 2, gs, single_cls, - hyp=hyp, cache=None if noval else opt.cache, rect=True, rank=-1, - workers=workers, pad=0.5, + if RANK in {-1, 0}: + val_loader = create_dataloader(val_path, + imgsz, + batch_size // WORLD_SIZE * 2, + gs, + single_cls, + hyp=hyp, + cache=None if noval else opt.cache, + rect=True, + rank=-1, + workers=workers * 2, + pad=0.5, prefix=colorstr('val: '))[0] if not resume: - labels = np.concatenate(dataset.labels, 0) - # c = torch.tensor(labels[:, 0]) # classes - # cf = torch.bincount(c.long(), minlength=nc) + 1. # frequency - # model._initialize_biases(cf.to(device)) - if plots: - plot_labels(labels, names, save_dir) - - # Anchors if not opt.noautoanchor: - check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) + check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) # run AutoAnchor model.half().float() # pre-reduce anchor precision - callbacks.run('on_pretrain_routine_end') + callbacks.run('on_pretrain_routine_end', labels, names) # DDP mode if cuda and RANK != -1: - model = DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK) + model = smart_DDP(model) - # Model parameters + # Model attributes nl = de_parallel(model).model[-1].nl # number of detection layers (to scale hyps) hyp['box'] *= 3 / nl # scale to layers hyp['cls'] *= nc / 80 * 3 / nl # scale to classes and layers @@ -256,20 +243,23 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # Start training t0 = time.time() - nw = max(round(hyp['warmup_epochs'] * nb), 1000) # number of warmup iterations, max(3 epochs, 1k iterations) + nb = len(train_loader) # number of batches + nw = max(round(hyp['warmup_epochs'] * nb), 100) # number of warmup iterations, max(3 epochs, 100 iterations) # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training last_opt_step = -1 maps = np.zeros(nc) # mAP per class results = (0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) scheduler.last_epoch = start_epoch - 1 # do not move - scaler = amp.GradScaler(enabled=cuda) - stopper = EarlyStopping(patience=opt.patience) + scaler = torch.cuda.amp.GradScaler(enabled=amp) + stopper, stop = EarlyStopping(patience=opt.patience), False compute_loss = ComputeLoss(model) # init loss class + callbacks.run('on_train_start') LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n' f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' f"Logging results to {colorstr('bold', save_dir)}\n" f'Starting training for {epochs} epochs...') for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ + callbacks.run('on_train_epoch_start') model.train() # Update image weights (optional, single-GPU only) @@ -286,11 +276,12 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary if RANK != -1: train_loader.sampler.set_epoch(epoch) pbar = enumerate(train_loader) - LOGGER.info(('\n' + '%10s' * 7) % ('Epoch', 'gpu_mem', 'box', 'obj', 'cls', 'labels', 'img_size')) - if RANK in [-1, 0]: - pbar = tqdm(pbar, total=nb, ncols=NCOLS, bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}') # progress bar + LOGGER.info(('\n' + '%11s' * 7) % ('Epoch', 'GPU_mem', 'box_loss', 'obj_loss', 'cls_loss', 'Instances', 'Size')) + if RANK in {-1, 0}: + pbar = tqdm(pbar, total=nb, bar_format=TQDM_BAR_FORMAT) # progress bar optimizer.zero_grad() for i, (imgs, targets, paths, _) in pbar: # batch ------------------------------------------------------------- + callbacks.run('on_train_batch_start') ni = i + nb * epoch # number integrated batches (since train start) imgs = imgs.to(device, non_blocking=True).float() / 255 # uint8 to float32, 0-255 to 0.0-1.0 @@ -301,7 +292,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round()) for j, x in enumerate(optimizer.param_groups): # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 - x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 2 else 0.0, x['initial_lr'] * lf(epoch)]) + x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 0 else 0.0, x['initial_lr'] * lf(epoch)]) if 'momentum' in x: x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) @@ -314,7 +305,7 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) # Forward - with amp.autocast(enabled=cuda): + with torch.cuda.amp.autocast(amp): pred = model(imgs) # forward loss, loss_items = compute_loss(pred, targets.to(device)) # loss scaled by batch_size if RANK != -1: @@ -325,8 +316,10 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # Backward scaler.scale(loss).backward() - # Optimize + # Optimize - https://pytorch.org/docs/master/notes/amp_examples.html if ni - last_opt_step >= accumulate: + scaler.unscale_(optimizer) # unscale gradients + torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=10.0) # clip gradients scaler.step(optimizer) # optimizer.step scaler.update() optimizer.zero_grad() @@ -335,37 +328,41 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary last_opt_step = ni # Log - if RANK in [-1, 0]: + if RANK in {-1, 0}: mloss = (mloss * i + loss_items) / (i + 1) # update mean losses mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G' # (GB) - pbar.set_description(('%10s' * 2 + '%10.4g' * 5) % ( - f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])) - callbacks.run('on_train_batch_end', ni, model, imgs, targets, paths, plots, opt.sync_bn) + pbar.set_description(('%11s' * 2 + '%11.4g' * 5) % + (f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])) + callbacks.run('on_train_batch_end', model, ni, imgs, targets, paths, list(mloss)) + if callbacks.stop_training: + return # end batch ------------------------------------------------------------------------------------------------ # Scheduler lr = [x['lr'] for x in optimizer.param_groups] # for loggers scheduler.step() - if RANK in [-1, 0]: + if RANK in {-1, 0}: # mAP callbacks.run('on_train_epoch_end', epoch=epoch) ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights']) final_epoch = (epoch + 1 == epochs) or stopper.possible_stop if not noval or final_epoch: # Calculate mAP - results, maps, _ = val.run(data_dict, - batch_size=batch_size // WORLD_SIZE * 2, - imgsz=imgsz, - model=ema.ema, - single_cls=single_cls, - dataloader=val_loader, - save_dir=save_dir, - plots=False, - callbacks=callbacks, - compute_loss=compute_loss) + results, maps, _ = validate.run(data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + half=amp, + model=ema.ema, + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + plots=False, + callbacks=callbacks, + compute_loss=compute_loss) # Update best mAP fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + stop = stopper(epoch=epoch, fitness=fi) # early stop check if fi > best_fitness: best_fitness = fi log_vals = list(mloss) + list(results) + lr @@ -373,65 +370,62 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary # Save model if (not nosave) or (final_epoch and not evolve): # if save - ckpt = {'epoch': epoch, - 'best_fitness': best_fitness, - 'model': deepcopy(de_parallel(model)).half(), - 'ema': deepcopy(ema.ema).half(), - 'updates': ema.updates, - 'optimizer': optimizer.state_dict(), - 'wandb_id': loggers.wandb.wandb_run.id if loggers.wandb else None, - 'date': datetime.now().isoformat()} + ckpt = { + 'epoch': epoch, + 'best_fitness': best_fitness, + 'model': deepcopy(de_parallel(model)).half(), + 'ema': deepcopy(ema.ema).half(), + 'updates': ema.updates, + 'optimizer': optimizer.state_dict(), + 'opt': vars(opt), + 'git': GIT_INFO, # {remote, branch, commit} if a git repo + 'date': datetime.now().isoformat()} # Save last, best and delete torch.save(ckpt, last) if best_fitness == fi: torch.save(ckpt, best) - if (epoch > 0) and (opt.save_period > 0) and (epoch % opt.save_period == 0): + if opt.save_period > 0 and epoch % opt.save_period == 0: torch.save(ckpt, w / f'epoch{epoch}.pt') del ckpt callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi) - # Stop Single-GPU - if RANK == -1 and stopper(epoch=epoch, fitness=fi): - break - - # Stop DDP TODO: known issues shttps://github.com/ultralytics/yolov5/pull/4576 - # stop = stopper(epoch=epoch, fitness=fi) - # if RANK == 0: - # dist.broadcast_object_list([stop], 0) # broadcast 'stop' to all ranks - - # Stop DPP - # with torch_distributed_zero_first(RANK): - # if stop: - # break # must break all DDP ranks + # EarlyStopping + if RANK != -1: # if DDP training + broadcast_list = [stop if RANK == 0 else None] + dist.broadcast_object_list(broadcast_list, 0) # broadcast 'stop' to all ranks + if RANK != 0: + stop = broadcast_list[0] + if stop: + break # must break all DDP ranks # end epoch ---------------------------------------------------------------------------------------------------- # end training ----------------------------------------------------------------------------------------------------- - if RANK in [-1, 0]: + if RANK in {-1, 0}: LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.') for f in last, best: if f.exists(): strip_optimizer(f) # strip optimizers if f is best: LOGGER.info(f'\nValidating {f}...') - results, _, _ = val.run(data_dict, - batch_size=batch_size // WORLD_SIZE * 2, - imgsz=imgsz, - model=attempt_load(f, device).half(), - iou_thres=0.65 if is_coco else 0.60, # best pycocotools results at 0.65 - single_cls=single_cls, - dataloader=val_loader, - save_dir=save_dir, - save_json=is_coco, - verbose=True, - plots=True, - callbacks=callbacks, - compute_loss=compute_loss) # val best model with plots + results, _, _ = validate.run( + data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + model=attempt_load(f, device).half(), + iou_thres=0.65 if is_coco else 0.60, # best pycocotools at iou 0.65 + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + save_json=is_coco, + verbose=True, + plots=plots, + callbacks=callbacks, + compute_loss=compute_loss) # val best model with plots if is_coco: callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi) - callbacks.run('on_train_end', last, best, plots, epoch, results) - LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}") + callbacks.run('on_train_end', last, best, epoch, results) torch.cuda.empty_cache() return results @@ -439,80 +433,92 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary def parse_opt(known=False): parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default=ROOT / 'yolov3.pt', help='initial weights path') + parser.add_argument('--weights', type=str, default=ROOT / 'yolov3-tiny.pt', help='initial weights path') parser.add_argument('--cfg', type=str, default='', help='model.yaml path') parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') - parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch.yaml', help='hyperparameters path') - parser.add_argument('--epochs', type=int, default=300) + parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path') + parser.add_argument('--epochs', type=int, default=100, help='total training epochs') parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') parser.add_argument('--rect', action='store_true', help='rectangular training') parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') parser.add_argument('--noval', action='store_true', help='only validate final epoch') - parser.add_argument('--noautoanchor', action='store_true', help='disable autoanchor check') + parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') + parser.add_argument('--noplots', action='store_true', help='save no plot files') parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') - parser.add_argument('--cache', type=str, nargs='?', const='ram', help='--cache images in "ram" (default) or "disk"') + parser.add_argument('--cache', type=str, nargs='?', const='ram', help='image --cache ram/disk') parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') - parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer') + parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer') parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name') parser.add_argument('--name', default='exp', help='save to project/name') parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') parser.add_argument('--quad', action='store_true', help='quad dataloader') - parser.add_argument('--linear-lr', action='store_true', help='linear LR') + parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') - parser.add_argument('--freeze', type=int, default=0, help='Number of layers to freeze. backbone=10, all=24') + parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') - parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') + parser.add_argument('--seed', type=int, default=0, help='Global training seed') + parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') - # Weights & Biases arguments - parser.add_argument('--entity', default=None, help='W&B: Entity') - parser.add_argument('--upload_dataset', action='store_true', help='W&B: Upload dataset as artifact table') - parser.add_argument('--bbox_interval', type=int, default=-1, help='W&B: Set bounding-box image logging interval') - parser.add_argument('--artifact_alias', type=str, default='latest', help='W&B: Version of dataset artifact to use') + # Logger arguments + parser.add_argument('--entity', default=None, help='Entity') + parser.add_argument('--upload_dataset', nargs='?', const=True, default=False, help='Upload data, "val" option') + parser.add_argument('--bbox_interval', type=int, default=-1, help='Set bounding-box image logging interval') + parser.add_argument('--artifact_alias', type=str, default='latest', help='Version of dataset artifact to use') - opt = parser.parse_known_args()[0] if known else parser.parse_args() - return opt + return parser.parse_known_args()[0] if known else parser.parse_args() def main(opt, callbacks=Callbacks()): # Checks - if RANK in [-1, 0]: - print_args(FILE.stem, opt) + if RANK in {-1, 0}: + print_args(vars(opt)) check_git_status() - check_requirements(exclude=['thop']) - - # Resume - if opt.resume and not check_wandb_resume(opt) and not opt.evolve: # resume an interrupted run - ckpt = opt.resume if isinstance(opt.resume, str) else get_latest_run() # specified or most recent path - assert os.path.isfile(ckpt), 'ERROR: --resume checkpoint does not exist' - with open(Path(ckpt).parent.parent / 'opt.yaml', errors='ignore') as f: - opt = argparse.Namespace(**yaml.safe_load(f)) # replace - opt.cfg, opt.weights, opt.resume = '', ckpt, True # reinstate - LOGGER.info(f'Resuming training from {ckpt}') + check_requirements() + + # Resume (from specified or most recent last.pt) + if opt.resume and not check_comet_resume(opt) and not opt.evolve: + last = Path(check_file(opt.resume) if isinstance(opt.resume, str) else get_latest_run()) + opt_yaml = last.parent.parent / 'opt.yaml' # train options yaml + opt_data = opt.data # original dataset + if opt_yaml.is_file(): + with open(opt_yaml, errors='ignore') as f: + d = yaml.safe_load(f) + else: + d = torch.load(last, map_location='cpu')['opt'] + opt = argparse.Namespace(**d) # replace + opt.cfg, opt.weights, opt.resume = '', str(last), True # reinstate + if is_url(opt_data): + opt.data = check_file(opt_data) # avoid HUB resume auth timeout else: opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \ check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' if opt.evolve: - opt.project = str(ROOT / 'runs/evolve') + if opt.project == str(ROOT / 'runs/train'): # if default project name, rename to runs/evolve + opt.project = str(ROOT / 'runs/evolve') opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume + if opt.name == 'cfg': + opt.name = Path(opt.cfg).stem # use model.yaml as name opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) # DDP mode device = select_device(opt.device, batch_size=opt.batch_size) if LOCAL_RANK != -1: + msg = 'is not compatible with YOLOv3 Multi-GPU DDP training' + assert not opt.image_weights, f'--image-weights {msg}' + assert not opt.evolve, f'--evolve {msg}' + assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size' + assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' - assert opt.batch_size % WORLD_SIZE == 0, '--batch-size must be multiple of CUDA device count' - assert not opt.image_weights, '--image-weights argument is not compatible with DDP training' - assert not opt.evolve, '--evolve argument is not compatible with DDP training' torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") @@ -520,52 +526,53 @@ def main(opt, callbacks=Callbacks()): # Train if not opt.evolve: train(opt.hyp, opt, device, callbacks) - if WORLD_SIZE > 1 and RANK == 0: - LOGGER.info('Destroying process group... ') - dist.destroy_process_group() # Evolve hyperparameters (optional) else: # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) - meta = {'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) - 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) - 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 - 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay - 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) - 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum - 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr - 'box': (1, 0.02, 0.2), # box loss gain - 'cls': (1, 0.2, 4.0), # cls loss gain - 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight - 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) - 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight - 'iou_t': (0, 0.1, 0.7), # IoU training threshold - 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold - 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) - 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) - 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) - 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) - 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) - 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) - 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) - 'scale': (1, 0.0, 0.9), # image scale (+/- gain) - 'shear': (1, 0.0, 10.0), # image shear (+/- deg) - 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 - 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) - 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) - 'mosaic': (1, 0.0, 1.0), # image mixup (probability) - 'mixup': (1, 0.0, 1.0), # image mixup (probability) - 'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) + meta = { + 'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) + 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) + 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 + 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay + 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) + 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum + 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr + 'box': (1, 0.02, 0.2), # box loss gain + 'cls': (1, 0.2, 4.0), # cls loss gain + 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight + 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) + 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight + 'iou_t': (0, 0.1, 0.7), # IoU training threshold + 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold + 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) + 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) + 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) + 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) + 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) + 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) + 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) + 'scale': (1, 0.0, 0.9), # image scale (+/- gain) + 'shear': (1, 0.0, 10.0), # image shear (+/- deg) + 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 + 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) + 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) + 'mosaic': (1, 0.0, 1.0), # image mixup (probability) + 'mixup': (1, 0.0, 1.0), # image mixup (probability) + 'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) with open(opt.hyp, errors='ignore') as f: hyp = yaml.safe_load(f) # load hyps dict if 'anchors' not in hyp: # anchors commented in hyp.yaml hyp['anchors'] = 3 + if opt.noautoanchor: + del hyp['anchors'], meta['anchors'] opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir) # only val/save final epoch # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' if opt.bucket: - os.system(f'gsutil cp gs://{opt.bucket}/evolve.csv {save_dir}') # download evolve.csv if exists + subprocess.run( + f'gsutil cp gs://{opt.bucket}/evolve.csv {evolve_csv}'.split()) # download evolve.csv if exists for _ in range(opt.evolve): # generations to evolve if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate @@ -601,23 +608,26 @@ def main(opt, callbacks=Callbacks()): # Train mutation results = train(hyp.copy(), opt, device, callbacks) - + callbacks = Callbacks() # Write mutation results - print_mutation(results, hyp.copy(), save_dir, opt.bucket) + keys = ('metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', 'val/box_loss', + 'val/obj_loss', 'val/cls_loss') + print_mutation(keys, results, hyp.copy(), save_dir, opt.bucket) # Plot results plot_evolve(evolve_csv) - LOGGER.info(f'Hyperparameter evolution finished\n' + LOGGER.info(f'Hyperparameter evolution finished {opt.evolve} generations\n' f"Results saved to {colorstr('bold', save_dir)}\n" - f'Use best hyperparameters example: $ python train.py --hyp {evolve_yaml}') + f'Usage example: $ python train.py --hyp {evolve_yaml}') def run(**kwargs): - # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolov3.pt') + # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolov5m.pt') opt = parse_opt(True) for k, v in kwargs.items(): setattr(opt, k, v) main(opt) + return opt if __name__ == "__main__": diff --git a/tutorial.ipynb b/tutorial.ipynb index 635061fbda..63881fb9a6 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -5,7 +5,7 @@ "colab": { "name": "YOLOv3 Tutorial", "provenance": [], - "include_colab_link": true + "toc_visible": true }, "kernelspec": { "name": "python3", @@ -14,373 +14,373 @@ "accelerator": "GPU", "widgets": { "application/vnd.jupyter.widget-state+json": { - "eeda9d6850e8406f9bbc5b06051b3710": { + "1f7df330663048998adcf8a45bc8f69b": { "model_module": "@jupyter-widgets/controls", "model_name": "HBoxModel", "model_module_version": "1.5.0", "state": { - "_view_name": "HBoxView", "_dom_classes": [], - "_model_name": "HBoxModel", - "_view_module": "@jupyter-widgets/controls", + "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", "_view_count": null, + "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", + "_view_name": "HBoxView", "box_style": "", - "layout": "IPY_MODEL_1e823c45174a4216be7234a6cc5cfd99", - "_model_module": "@jupyter-widgets/controls", "children": [ - "IPY_MODEL_cd8efd6c5de94ea8848a7d5b8766a4d6", - "IPY_MODEL_a4ec69c4697c4b0e84e6193be227f63e", - "IPY_MODEL_9a5694c133be46df8d2fe809b77c1c35" - ] - } - }, - "1e823c45174a4216be7234a6cc5cfd99": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "model_module_version": "1.2.0", - "state": { - "_view_name": "LayoutView", - "grid_template_rows": null, - "right": null, - "justify_content": null, - "_view_module": "@jupyter-widgets/base", - "overflow": null, - "_model_module_version": "1.2.0", - "_view_count": null, - "flex_flow": null, - "width": null, - "min_width": null, - "border": null, - "align_items": null, - "bottom": null, - "_model_module": "@jupyter-widgets/base", - "top": null, - "grid_column": null, - "overflow_y": null, - "overflow_x": null, - "grid_auto_flow": null, - "grid_area": null, - "grid_template_columns": null, - "flex": null, - "_model_name": "LayoutModel", - "justify_items": null, - "grid_row": null, - "max_height": null, - "align_content": null, - "visibility": null, - "align_self": null, - "height": null, - "min_height": null, - "padding": null, - "grid_auto_rows": null, - "grid_gap": null, - "max_width": null, - "order": null, - "_view_module_version": "1.2.0", - "grid_template_areas": null, - "object_position": null, - "object_fit": null, - "grid_auto_columns": null, - "margin": null, - "display": null, - "left": null + "IPY_MODEL_e896e6096dd244c59d7955e2035cd729", + "IPY_MODEL_a6ff238c29984b24bf6d0bd175c19430", + "IPY_MODEL_3c085ba3f3fd4c3c8a6bb41b41ce1479" + ], + "layout": "IPY_MODEL_16b0c8aa6e0f427e8a54d3791abb7504" } }, - "cd8efd6c5de94ea8848a7d5b8766a4d6": { + "e896e6096dd244c59d7955e2035cd729": { "model_module": "@jupyter-widgets/controls", "model_name": "HTMLModel", "model_module_version": "1.5.0", "state": { - "_view_name": "HTMLView", - "style": "IPY_MODEL_d584167143f84a0484006dded3fd2620", "_dom_classes": [], - "description": "", - "_model_name": "HTMLModel", - "placeholder": "​", - "_view_module": "@jupyter-widgets/controls", + "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", - "value": "100%", + "_model_name": "HTMLModel", "_view_count": null, + "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", "description_tooltip": null, - "_model_module": "@jupyter-widgets/controls", - "layout": "IPY_MODEL_b9a25c0d425c4fe4b8cd51ae6a301b0d" + "layout": "IPY_MODEL_c7b2dd0f78384cad8e400b282996cdf5", + "placeholder": "​", + "style": "IPY_MODEL_6a27e43b0e434edd82ee63f0a91036ca", + "value": "100%" } }, - "a4ec69c4697c4b0e84e6193be227f63e": { + "a6ff238c29984b24bf6d0bd175c19430": { "model_module": "@jupyter-widgets/controls", "model_name": "FloatProgressModel", "model_module_version": "1.5.0", "state": { - "_view_name": "ProgressView", - "style": "IPY_MODEL_654525fe1ed34d5fbe1c36ed80ae1c1c", "_dom_classes": [], - "description": "", - "_model_name": "FloatProgressModel", - "bar_style": "success", - "max": 818322941, - "_view_module": "@jupyter-widgets/controls", + "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", - "value": 818322941, + "_model_name": "FloatProgressModel", "_view_count": null, + "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", - "orientation": "horizontal", - "min": 0, + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", "description_tooltip": null, - "_model_module": "@jupyter-widgets/controls", - "layout": "IPY_MODEL_09544845070e47baafc5e37d45ff23e9" + "layout": "IPY_MODEL_cce0e6c0c4ec442cb47e65c674e02e92", + "max": 818322941, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_c5b9f38e2f0d4f9aa97fe87265263743", + "value": 818322941 } }, - "9a5694c133be46df8d2fe809b77c1c35": { + "3c085ba3f3fd4c3c8a6bb41b41ce1479": { "model_module": "@jupyter-widgets/controls", "model_name": "HTMLModel", "model_module_version": "1.5.0", "state": { - "_view_name": "HTMLView", - "style": "IPY_MODEL_1066f1d5b6104a3dae19f26269745bd0", "_dom_classes": [], - "description": "", - "_model_name": "HTMLModel", - "placeholder": "​", - "_view_module": "@jupyter-widgets/controls", + "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", - "value": " 780M/780M [00:03<00:00, 200MB/s]", + "_model_name": "HTMLModel", "_view_count": null, + "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", "description_tooltip": null, - "_model_module": "@jupyter-widgets/controls", - "layout": "IPY_MODEL_dd3a70e1ef4547ec8d3463749ce06285" + "layout": "IPY_MODEL_df554fb955c7454696beac5a82889386", + "placeholder": "​", + "style": "IPY_MODEL_74e9112a87a242f4831b7d68c7da6333", + "value": " 780M/780M [00:05<00:00, 126MB/s]" } }, - "d584167143f84a0484006dded3fd2620": { - "model_module": "@jupyter-widgets/controls", - "model_name": "DescriptionStyleModel", - "model_module_version": "1.5.0", + "16b0c8aa6e0f427e8a54d3791abb7504": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", "state": { - "_view_name": "StyleView", - "_model_name": "DescriptionStyleModel", - "description_width": "", - "_view_module": "@jupyter-widgets/base", - "_model_module_version": "1.5.0", + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", "_view_count": null, + "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", - "_model_module": "@jupyter-widgets/controls" + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null } }, - "b9a25c0d425c4fe4b8cd51ae6a301b0d": { + "c7b2dd0f78384cad8e400b282996cdf5": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "model_module_version": "1.2.0", "state": { - "_view_name": "LayoutView", - "grid_template_rows": null, - "right": null, - "justify_content": null, - "_view_module": "@jupyter-widgets/base", - "overflow": null, + "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", "_view_count": null, - "flex_flow": null, - "width": null, - "min_width": null, - "border": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, "align_items": null, + "align_self": null, + "border": null, "bottom": null, - "_model_module": "@jupyter-widgets/base", - "top": null, - "grid_column": null, - "overflow_y": null, - "overflow_x": null, - "grid_auto_flow": null, + "display": null, + "flex": null, + "flex_flow": null, "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, "grid_template_columns": null, - "flex": null, - "_model_name": "LayoutModel", + "grid_template_rows": null, + "height": null, + "justify_content": null, "justify_items": null, - "grid_row": null, + "left": null, + "margin": null, "max_height": null, - "align_content": null, - "visibility": null, - "align_self": null, - "height": null, - "min_height": null, - "padding": null, - "grid_auto_rows": null, - "grid_gap": null, "max_width": null, - "order": null, - "_view_module_version": "1.2.0", - "grid_template_areas": null, - "object_position": null, + "min_height": null, + "min_width": null, "object_fit": null, - "grid_auto_columns": null, - "margin": null, - "display": null, - "left": null + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null } }, - "654525fe1ed34d5fbe1c36ed80ae1c1c": { + "6a27e43b0e434edd82ee63f0a91036ca": { "model_module": "@jupyter-widgets/controls", - "model_name": "ProgressStyleModel", + "model_name": "DescriptionStyleModel", "model_module_version": "1.5.0", "state": { - "_view_name": "StyleView", - "_model_name": "ProgressStyleModel", - "description_width": "", - "_view_module": "@jupyter-widgets/base", + "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", "_view_count": null, + "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", - "bar_color": null, - "_model_module": "@jupyter-widgets/controls" + "_view_name": "StyleView", + "description_width": "" } }, - "09544845070e47baafc5e37d45ff23e9": { + "cce0e6c0c4ec442cb47e65c674e02e92": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "model_module_version": "1.2.0", "state": { - "_view_name": "LayoutView", - "grid_template_rows": null, - "right": null, - "justify_content": null, - "_view_module": "@jupyter-widgets/base", - "overflow": null, + "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", "_view_count": null, - "flex_flow": null, - "width": null, - "min_width": null, - "border": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, "align_items": null, + "align_self": null, + "border": null, "bottom": null, - "_model_module": "@jupyter-widgets/base", - "top": null, - "grid_column": null, - "overflow_y": null, - "overflow_x": null, - "grid_auto_flow": null, - "grid_area": null, - "grid_template_columns": null, + "display": null, "flex": null, - "_model_name": "LayoutModel", - "justify_items": null, - "grid_row": null, - "max_height": null, - "align_content": null, - "visibility": null, - "align_self": null, - "height": null, - "min_height": null, - "padding": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, "grid_auto_rows": null, + "grid_column": null, "grid_gap": null, - "max_width": null, - "order": null, - "_view_module_version": "1.2.0", + "grid_row": null, "grid_template_areas": null, - "object_position": null, - "object_fit": null, - "grid_auto_columns": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, "margin": null, - "display": null, - "left": null + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null } }, - "1066f1d5b6104a3dae19f26269745bd0": { + "c5b9f38e2f0d4f9aa97fe87265263743": { "model_module": "@jupyter-widgets/controls", - "model_name": "DescriptionStyleModel", + "model_name": "ProgressStyleModel", "model_module_version": "1.5.0", "state": { - "_view_name": "StyleView", - "_model_name": "DescriptionStyleModel", - "description_width": "", - "_view_module": "@jupyter-widgets/base", + "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", "_view_count": null, + "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", - "_model_module": "@jupyter-widgets/controls" + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" } }, - "dd3a70e1ef4547ec8d3463749ce06285": { + "df554fb955c7454696beac5a82889386": { "model_module": "@jupyter-widgets/base", "model_name": "LayoutModel", "model_module_version": "1.2.0", "state": { - "_view_name": "LayoutView", - "grid_template_rows": null, - "right": null, - "justify_content": null, - "_view_module": "@jupyter-widgets/base", - "overflow": null, + "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", "_view_count": null, - "flex_flow": null, - "width": null, - "min_width": null, - "border": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, "align_items": null, + "align_self": null, + "border": null, "bottom": null, - "_model_module": "@jupyter-widgets/base", - "top": null, - "grid_column": null, - "overflow_y": null, - "overflow_x": null, - "grid_auto_flow": null, + "display": null, + "flex": null, + "flex_flow": null, "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, "grid_template_columns": null, - "flex": null, - "_model_name": "LayoutModel", + "grid_template_rows": null, + "height": null, + "justify_content": null, "justify_items": null, - "grid_row": null, + "left": null, + "margin": null, "max_height": null, - "align_content": null, - "visibility": null, - "align_self": null, - "height": null, - "min_height": null, - "padding": null, - "grid_auto_rows": null, - "grid_gap": null, "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "74e9112a87a242f4831b7d68c7da6333": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", - "grid_template_areas": null, - "object_position": null, - "object_fit": null, - "grid_auto_columns": null, - "margin": null, - "display": null, - "left": null + "_view_name": "StyleView", + "description_width": "" } } } } }, "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "view-in-github", - "colab_type": "text" - }, - "source": [ - "\"Open" - ] - }, { "cell_type": "markdown", "metadata": { "id": "t6MPjfT5NrKQ" }, "source": [ - "\n", - "\n", + "
\n", + "\n", + " \n", + " \n", + "\n", "\n", - "This is the **official YOLOv3 🚀 notebook** by **Ultralytics**, and is freely available for redistribution under the [GPL-3.0 license](https://choosealicense.com/licenses/gpl-3.0/). \n", - "For more information please visit https://github.com/ultralytics/yolov3 and https://ultralytics.com. Thank you!" + "
\n", + " \"Run\n", + " \"Open\n", + " \"Open\n", + "
\n", + "\n", + "This 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", + "\n", + "
" ] }, { @@ -391,7 +391,7 @@ "source": [ "# Setup\n", "\n", - "Clone repo, install dependencies and check PyTorch and GPU." + "Clone GitHub [repository](https://github.com/ultralytics/yolov5), install [dependencies](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) and check PyTorch and GPU." ] }, { @@ -401,24 +401,31 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "141002fc-fe49-48d2-a575-2555bf903413" + "outputId": "f9f016ad-3dcf-4bd2-e1c3-d5b79efc6f32" }, "source": [ - "!git clone https://github.com/ultralytics/yolov3 # clone\n", - "%cd yolov3\n", + "!git clone https://github.com/ultralytics/yolov5 # clone\n", + "%cd yolov5\n", "%pip install -qr requirements.txt # install\n", "\n", "import torch\n", - "from yolov3 import utils\n", + "import utils\n", "display = utils.notebook_init() # checks" ], - "execution_count": 1, + "execution_count": null, "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + " 🚀 v7.0-1-gb32f67f Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n" + ] + }, { "output_type": "stream", "name": "stdout", "text": [ - "Setup complete ✅\n" + "Setup complete ✅ (2 CPUs, 12.7 GB RAM, 22.6/78.2 GB disk)\n" ] } ] @@ -429,18 +436,19 @@ "id": "4JnkELT0cIJg" }, "source": [ - "# 1. Inference\n", + "# 1. Detect\n", "\n", - "`detect.py` runs YOLOv3 inference on a variety of sources, downloading models automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases), and saving results to `runs/detect`. Example inference sources are:\n", + "`detect.py` runs inference on a variety of sources, downloading models automatically from the [latest release](https://github.com/ultralytics/yolov5/releases), and saving results to `runs/detect`. Example inference sources are:\n", "\n", "```shell\n", "python detect.py --source 0 # webcam\n", " img.jpg # image \n", " vid.mp4 # video\n", + " screen # screenshot\n", " path/ # directory\n", - " path/*.jpg # glob\n", - " 'https://youtu.be/Zgi9g1ksQHc' # YouTube\n", - " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", + " 'path/*.jpg' # glob\n", + " 'https://youtu.be/Zgi9g1ksQHc' # YouTube\n", + " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", "```" ] }, @@ -451,27 +459,30 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "c29b082a-8e56-4799-b32a-056425f130d1" + "outputId": "b4db5c49-f501-4505-cf0d-a1d35236c485" }, "source": [ - "!python detect.py --weights yolov3.pt --img 640 --conf 0.25 --source data/images\n", + "!python detect.py --weights yolov5s.pt --img 640 --conf 0.25 --source data/images\n", "# display.Image(filename='runs/detect/exp/zidane.jpg', width=600)" ], - "execution_count": 4, + "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ - "\u001b[34m\u001b[1mdetect: \u001b[0mweights=['yolov3.pt'], source=data/images, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False\n", - "YOLOv3 🚀 v9.6.0-29-ga441ab1 torch 1.13.0+cu116 CUDA:0 (Tesla T4, 15110MiB)\n", + "\u001b[34m\u001b[1mdetect: \u001b[0mweights=['yolov5s.pt'], source=data/images, data=data/coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False, vid_stride=1\n", + " 🚀 v7.0-1-gb32f67f Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "\n", + "Downloading https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt to yolov5s.pt...\n", + "100% 14.1M/14.1M [00:00<00:00, 116MB/s] \n", "\n", "Fusing layers... \n", - "Model Summary: 261 layers, 61922845 parameters, 0 gradients\n", - "image 1/2 /content/yolov3/data/images/bus.jpg: 640x480 4 persons, 1 bicycle, 1 bus, Done. (0.050s)\n", - "image 2/2 /content/yolov3/data/images/zidane.jpg: 384x640 2 persons, 2 ties, Done. (0.038s)\n", - "Speed: 0.5ms pre-process, 44.3ms inference, 1.3ms NMS per image at shape (1, 3, 640, 640)\n", - "Results saved to \u001b[1mruns/detect/exp2\u001b[0m\n" + "YOLOv5s summary: 213 layers, 7225885 parameters, 0 gradients\n", + "image 1/2 /content/yolov5/data/images/bus.jpg: 640x480 4 persons, 1 bus, 17.0ms\n", + "image 2/2 /content/yolov5/data/images/zidane.jpg: 384x640 2 persons, 2 ties, 14.3ms\n", + "Speed: 0.5ms pre-process, 15.7ms inference, 18.6ms NMS per image at shape (1, 3, 640, 640)\n", + "Results saved to \u001b[1mruns/detect/exp\u001b[0m\n" ] } ] @@ -493,17 +504,7 @@ }, "source": [ "# 2. Validate\n", - "Validate a model's accuracy on [COCO](https://cocodataset.org/#home) val or test-dev datasets. Models are downloaded automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases). To show results by class use the `--verbose` flag. Note that `pycocotools` metrics may be ~1% better than the equivalent repo metrics, as is visible below, due to slight differences in mAP computation." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "eyTZYGgRjnMc" - }, - "source": [ - "## COCO val\n", - "Download [COCO val 2017](https://github.com/ultralytics/yolov3/blob/master/data/coco.yaml) dataset (1GB - 5000 images), and test model accuracy." + "Validate a model's accuracy on the [COCO](https://cocodataset.org/#home) dataset's `val` or `test` splits. Models are downloaded automatically from the [latest release](https://github.com/ultralytics/yolov5/releases). To show results by class use the `--verbose` flag." ] }, { @@ -512,41 +513,41 @@ "id": "WQPtK1QYVaD_", "colab": { "base_uri": "https://localhost:8080/", - "height": 48, + "height": 49, "referenced_widgets": [ - "eeda9d6850e8406f9bbc5b06051b3710", - "1e823c45174a4216be7234a6cc5cfd99", - "cd8efd6c5de94ea8848a7d5b8766a4d6", - "a4ec69c4697c4b0e84e6193be227f63e", - "9a5694c133be46df8d2fe809b77c1c35", - "d584167143f84a0484006dded3fd2620", - "b9a25c0d425c4fe4b8cd51ae6a301b0d", - "654525fe1ed34d5fbe1c36ed80ae1c1c", - "09544845070e47baafc5e37d45ff23e9", - "1066f1d5b6104a3dae19f26269745bd0", - "dd3a70e1ef4547ec8d3463749ce06285" + "1f7df330663048998adcf8a45bc8f69b", + "e896e6096dd244c59d7955e2035cd729", + "a6ff238c29984b24bf6d0bd175c19430", + "3c085ba3f3fd4c3c8a6bb41b41ce1479", + "16b0c8aa6e0f427e8a54d3791abb7504", + "c7b2dd0f78384cad8e400b282996cdf5", + "6a27e43b0e434edd82ee63f0a91036ca", + "cce0e6c0c4ec442cb47e65c674e02e92", + "c5b9f38e2f0d4f9aa97fe87265263743", + "df554fb955c7454696beac5a82889386", + "74e9112a87a242f4831b7d68c7da6333" ] }, - "outputId": "56199bac-5a5e-41eb-8892-bf387a1ec7cb" + "outputId": "c7d0a0d2-abfb-44c3-d60d-f99d0e7aabad" }, "source": [ "# Download COCO val\n", - "torch.hub.download_url_to_file('https://ultralytics.com/assets/coco2017val.zip', 'tmp.zip')\n", - "!unzip -q tmp.zip -d ../datasets && rm tmp.zip" + "torch.hub.download_url_to_file('https://ultralytics.com/assets/coco2017val.zip', 'tmp.zip') # download (780M - 5000 images)\n", + "!unzip -q tmp.zip -d ../datasets && rm tmp.zip # unzip" ], "execution_count": null, "outputs": [ { "output_type": "display_data", "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "eeda9d6850e8406f9bbc5b06051b3710", - "version_minor": 0, - "version_major": 2 - }, "text/plain": [ " 0%| | 0.00/780M [00:00

\n", + "

\n", "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", "

\n", "\n", - "Train a YOLOv3 model on the [COCO128](https://www.kaggle.com/ultralytics/coco128) dataset with `--data coco128.yaml`, starting from pretrained `--weights yolov3.pt`, or from randomly initialized `--weights '' --cfg yolov3yaml`.\n", + "Train a YOLOv5s model on the [COCO128](https://www.kaggle.com/ultralytics/coco128) dataset with `--data coco128.yaml`, starting from pretrained `--weights yolov5s.pt`, or from randomly initialized `--weights '' --cfg yolov5s.yaml`.\n", "\n", - "- **Pretrained [Models](https://github.com/ultralytics/yolov3/tree/master/models)** are downloaded\n", - "automatically from the [latest YOLOv3 release](https://github.com/ultralytics/yolov3/releases)\n", - "- **[Datasets](https://github.com/ultralytics/yolov3/tree/master/data)** available for autodownload include: [COCO](https://github.com/ultralytics/yolov3/blob/master/data/coco.yaml), [COCO128](https://github.com/ultralytics/yolov3/blob/master/data/coco128.yaml), [VOC](https://github.com/ultralytics/yolov3/blob/master/data/VOC.yaml), [Argoverse](https://github.com/ultralytics/yolov3/blob/master/data/Argoverse.yaml), [VisDrone](https://github.com/ultralytics/yolov3/blob/master/data/VisDrone.yaml), [GlobalWheat](https://github.com/ultralytics/yolov3/blob/master/data/GlobalWheat2020.yaml), [xView](https://github.com/ultralytics/yolov3/blob/master/data/xView.yaml), [Objects365](https://github.com/ultralytics/yolov3/blob/master/data/Objects365.yaml), [SKU-110K](https://github.com/ultralytics/yolov3/blob/master/data/SKU-110K.yaml).\n", + "- **Pretrained [Models](https://github.com/ultralytics/yolov5/tree/master/models)** are downloaded\n", + "automatically from the [latest release](https://github.com/ultralytics/yolov5/releases)\n", + "- **[Datasets](https://github.com/ultralytics/yolov5/tree/master/data)** available for autodownload include: [COCO](https://github.com/ultralytics/yolov5/blob/master/data/coco.yaml), [COCO128](https://github.com/ultralytics/yolov5/blob/master/data/coco128.yaml), [VOC](https://github.com/ultralytics/yolov5/blob/master/data/VOC.yaml), [Argoverse](https://github.com/ultralytics/yolov5/blob/master/data/Argoverse.yaml), [VisDrone](https://github.com/ultralytics/yolov5/blob/master/data/VisDrone.yaml), [GlobalWheat](https://github.com/ultralytics/yolov5/blob/master/data/GlobalWheat2020.yaml), [xView](https://github.com/ultralytics/yolov5/blob/master/data/xView.yaml), [Objects365](https://github.com/ultralytics/yolov5/blob/master/data/Objects365.yaml), [SKU-110K](https://github.com/ultralytics/yolov5/blob/master/data/SKU-110K.yaml).\n", "- **Training Results** are saved to `runs/train/` with incrementing run directories, i.e. `runs/train/exp2`, `runs/train/exp3` etc.\n", - "

\n" + "

\n", + "\n", + "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic.\n", + "\n", + "## Train on Custom Data with Roboflow 🌟 NEW\n", + "\n", + "[Roboflow](https://roboflow.com/?ref=ultralytics) enables you to easily **organize, label, and prepare** a high quality dataset with your own custom data. Roboflow also makes it easy to establish an active learning pipeline, collaborate with your team on dataset improvement, and integrate directly into your model building workflow with the `roboflow` pip package.\n", + "\n", + "- Custom Training Example: [https://blog.roboflow.com/how-to-train-yolov5-on-a-custom-dataset/](https://blog.roboflow.com/how-to-train-yolov5-on-a-custom-dataset/?ref=ultralytics)\n", + "- Custom Training Notebook: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow-ai/yolov5-custom-training-tutorial/blob/main/yolov5-custom-training.ipynb)\n", + "
\n", + "\n", + "

Label images lightning fast (including with model-assisted labeling)" ] }, { "cell_type": "code", - "metadata": { - "id": "bOy5KI2ncnWd" - }, "source": [ - "# Tensorboard (optional)\n", - "%load_ext tensorboard\n", - "%tensorboard --logdir runs/train" + "#@title Select 🚀 logger {run: 'auto'}\n", + "logger = 'ClearML' #@param ['ClearML', 'Comet', 'TensorBoard']\n", + "\n", + "if logger == 'ClearML':\n", + " %pip install -q clearml\n", + " import clearml; clearml.browser_login()\n", + "elif logger == 'Comet':\n", + " %pip install -q comet_ml\n", + " import comet_ml; comet_ml.init()\n", + "elif logger == 'TensorBoard':\n", + " %load_ext tensorboard\n", + " %tensorboard --logdir runs/train" ], + "metadata": { + "id": "i3oKtE4g-aNn" + }, "execution_count": null, "outputs": [] }, @@ -689,176 +676,172 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "c77013e3-347d-42a4-84de-3ca42ea3aee9" + "outputId": "721b9028-767f-4a05-c964-692c245f7398" }, "source": [ - "# Train YOLOv3 on COCO128 for 3 epochs\n", - "!python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov3.pt --cache" + "# Train YOLOv5s on COCO128 for 3 epochs\n", + "!python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov5s.pt --cache" ], - "execution_count": 3, + "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ - "\u001b[34m\u001b[1mtrain: \u001b[0mweights=yolov3.pt, cfg=, data=coco128.yaml, hyp=data/hyps/hyp.scratch.yaml, epochs=3, batch_size=16, imgsz=640, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, evolve=None, bucket=, cache=ram, image_weights=False, device=, multi_scale=False, single_cls=False, adam=False, sync_bn=False, workers=8, project=runs/train, name=exp, exist_ok=False, quad=False, linear_lr=False, label_smoothing=0.0, patience=100, freeze=0, save_period=-1, local_rank=-1, entity=None, upload_dataset=False, bbox_interval=-1, artifact_alias=latest\n", - "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov3 ✅\n", - "YOLOv3 🚀 v9.6.0-29-ga441ab1 torch 1.13.0+cu116 CUDA:0 (Tesla T4, 15110MiB)\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mweights=yolov5s.pt, cfg=, data=coco128.yaml, hyp=data/hyps/hyp.scratch-low.yaml, epochs=3, batch_size=16, imgsz=640, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, noplots=False, evolve=None, bucket=, cache=ram, image_weights=False, device=, multi_scale=False, single_cls=False, optimizer=SGD, sync_bn=False, workers=8, project=runs/train, name=exp, exist_ok=False, quad=False, cos_lr=False, label_smoothing=0.0, patience=100, freeze=[0], save_period=-1, seed=0, local_rank=-1, entity=None, upload_dataset=False, bbox_interval=-1, artifact_alias=latest\n", + "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", + " 🚀 v7.0-1-gb32f67f Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", "\n", - "\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.1, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0\n", - "\u001b[34m\u001b[1mWeights & Biases: \u001b[0mrun 'pip install wandb' to automatically track and visualize YOLOv3 🚀 runs (RECOMMENDED)\n", + "\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0\n", + "\u001b[34m\u001b[1mClearML: \u001b[0mrun 'pip install clearml' to automatically track, visualize and remotely train 🚀 in ClearML\n", + "\u001b[34m\u001b[1mComet: \u001b[0mrun 'pip install comet_ml' to automatically track and visualize 🚀 runs in Comet\n", "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train', view at http://localhost:6006/\n", "\n", - "WARNING: Dataset not found, nonexistent paths: ['/content/datasets/coco128/images/train2017']\n", + "Dataset not found ⚠️, missing paths ['/content/datasets/coco128/images/train2017']\n", "Downloading https://ultralytics.com/assets/coco128.zip to coco128.zip...\n", - "100% 6.66M/6.66M [00:00<00:00, 10.2MB/s]\n", - "Dataset autodownload success, saved to ../datasets\n", - "\n", + "100% 6.66M/6.66M [00:00<00:00, 261MB/s]\n", + "Dataset download success ✅ (0.3s), saved to \u001b[1m/content/datasets\u001b[0m\n", "\n", " from n params module arguments \n", - " 0 -1 1 928 models.common.Conv [3, 32, 3, 1] \n", + " 0 -1 1 3520 models.common.Conv [3, 32, 6, 2, 2] \n", " 1 -1 1 18560 models.common.Conv [32, 64, 3, 2] \n", - " 2 -1 1 20672 models.common.Bottleneck [64, 64] \n", + " 2 -1 1 18816 models.common.C3 [64, 64, 1] \n", " 3 -1 1 73984 models.common.Conv [64, 128, 3, 2] \n", - " 4 -1 2 164608 models.common.Bottleneck [128, 128] \n", + " 4 -1 2 115712 models.common.C3 [128, 128, 2] \n", " 5 -1 1 295424 models.common.Conv [128, 256, 3, 2] \n", - " 6 -1 8 2627584 models.common.Bottleneck [256, 256] \n", + " 6 -1 3 625152 models.common.C3 [256, 256, 3] \n", " 7 -1 1 1180672 models.common.Conv [256, 512, 3, 2] \n", - " 8 -1 8 10498048 models.common.Bottleneck [512, 512] \n", - " 9 -1 1 4720640 models.common.Conv [512, 1024, 3, 2] \n", - " 10 -1 4 20983808 models.common.Bottleneck [1024, 1024] \n", - " 11 -1 1 5245952 models.common.Bottleneck [1024, 1024, False] \n", - " 12 -1 1 525312 models.common.Conv [1024, 512, 1, 1] \n", - " 13 -1 1 4720640 models.common.Conv [512, 1024, 3, 1] \n", - " 14 -1 1 525312 models.common.Conv [1024, 512, 1, 1] \n", - " 15 -1 1 4720640 models.common.Conv [512, 1024, 3, 1] \n", - " 16 -2 1 131584 models.common.Conv [512, 256, 1, 1] \n", - " 17 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", - " 18 [-1, 8] 1 0 models.common.Concat [1] \n", - " 19 -1 1 1377792 models.common.Bottleneck [768, 512, False] \n", - " 20 -1 1 1312256 models.common.Bottleneck [512, 512, False] \n", - " 21 -1 1 131584 models.common.Conv [512, 256, 1, 1] \n", - " 22 -1 1 1180672 models.common.Conv [256, 512, 3, 1] \n", - " 23 -2 1 33024 models.common.Conv [256, 128, 1, 1] \n", - " 24 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", - " 25 [-1, 6] 1 0 models.common.Concat [1] \n", - " 26 -1 1 344832 models.common.Bottleneck [384, 256, False] \n", - " 27 -1 2 656896 models.common.Bottleneck [256, 256, False] \n", - " 28 [27, 22, 15] 1 457725 models.yolo.Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [256, 512, 1024]]\n", - "Model Summary: 333 layers, 61949149 parameters, 61949149 gradients, 156.6 GFLOPs\n", + " 8 -1 1 1182720 models.common.C3 [512, 512, 1] \n", + " 9 -1 1 656896 models.common.SPPF [512, 512, 5] \n", + " 10 -1 1 131584 models.common.Conv [512, 256, 1, 1] \n", + " 11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 12 [-1, 6] 1 0 models.common.Concat [1] \n", + " 13 -1 1 361984 models.common.C3 [512, 256, 1, False] \n", + " 14 -1 1 33024 models.common.Conv [256, 128, 1, 1] \n", + " 15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 16 [-1, 4] 1 0 models.common.Concat [1] \n", + " 17 -1 1 90880 models.common.C3 [256, 128, 1, False] \n", + " 18 -1 1 147712 models.common.Conv [128, 128, 3, 2] \n", + " 19 [-1, 14] 1 0 models.common.Concat [1] \n", + " 20 -1 1 296448 models.common.C3 [256, 256, 1, False] \n", + " 21 -1 1 590336 models.common.Conv [256, 256, 3, 2] \n", + " 22 [-1, 10] 1 0 models.common.Concat [1] \n", + " 23 -1 1 1182720 models.common.C3 [512, 512, 1, False] \n", + " 24 [17, 20, 23] 1 229245 models.yolo.Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [128, 256, 512]]\n", + "Model summary: 214 layers, 7235389 parameters, 7235389 gradients, 16.6 GFLOPs\n", "\n", - "Transferred 439/439 items from yolov3.pt\n", - "Scaled weight_decay = 0.0005\n", - "\u001b[34m\u001b[1moptimizer:\u001b[0m SGD with parameter groups 72 weight, 75 weight (no decay), 75 bias\n", - "\u001b[34m\u001b[1malbumentations: \u001b[0mBlur(always_apply=False, p=0.01, blur_limit=(3, 7)), MedianBlur(always_apply=False, p=0.01, blur_limit=(3, 7)), ToGray(always_apply=False, p=0.01), CLAHE(always_apply=False, p=0.01, clip_limit=(1, 4.0), tile_grid_size=(8, 8))\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mScanning '../datasets/coco128/labels/train2017' images and labels...126 found, 2 missing, 0 empty, 0 corrupted: 100% 128/128 [00:00<00:00, 1542.80it/s]\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mNew cache created: ../datasets/coco128/labels/train2017.cache\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mCaching images (0.1GB ram): 100% 128/128 [00:00<00:00, 327.35it/s]\n", - "\u001b[34m\u001b[1mval: \u001b[0mScanning '../datasets/coco128/labels/train2017.cache' images and labels... 126 found, 2 missing, 0 empty, 0 corrupted: 100% 128/128 [00:00 # 2. paste API key\n", + "python train.py --img 640 --epochs 3 --data coco128.yaml --weights yolov5s.pt # 3. train\n", + "```\n", + "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/comet). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing)\n", + "\n", + "\n", + "\"Comet" + ], "metadata": { - "id": "-WPvRbS5Swl6" - }, + "id": "nWOsI5wJR1o3" + } + }, + { + "cell_type": "markdown", "source": [ - "## Local Logging\n", + "## ClearML Logging and Automation 🌟 NEW\n", + "\n", + "[ClearML](https://cutt.ly/yolov5-notebook-clearml) is completely integrated into to track your experimentation, manage dataset versions and even remotely execute training runs. To enable ClearML (check cells above):\n", "\n", - "All results are logged by default to `runs/train`, with a new experiment directory created for each new training as `runs/train/exp2`, `runs/train/exp3`, etc. View train and val jpgs to see mosaics, labels, predictions and augmentation effects. Note an Ultralytics **Mosaic Dataloader** is used for training (shown below), which combines 4 images into 1 mosaic during training.\n", + "- `pip install clearml`\n", + "- run `clearml-init` to connect to a ClearML server (**deploy your own [open-source server](https://github.com/allegroai/clearml-server)**, or use our [free hosted server](https://cutt.ly/yolov5-notebook-clearml))\n", "\n", - "> \n", - "`train_batch0.jpg` shows train batch 0 mosaics and labels\n", + "You'll get all the great expected features from an experiment manager: live updates, model upload, experiment comparison etc. but ClearML also tracks uncommitted changes and installed packages for example. Thanks to that ClearML Tasks (which is what we call experiments) are also reproducible on different machines! With only 1 extra line, we can schedule a training task on a queue to be executed by any number of ClearML Agents (workers).\n", "\n", - "> \n", - "`test_batch0_labels.jpg` shows val batch 0 labels\n", + "You can use ClearML Data to version your dataset and then pass it to simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml) for details!\n", "\n", - "> \n", - "`test_batch0_pred.jpg` shows val batch 0 _predictions_\n", + "\n", + "\"ClearML" + ], + "metadata": { + "id": "Lay2WsTjNJzP" + } + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-WPvRbS5Swl6" + }, + "source": [ + "## Local Logging\n", "\n", - "Training results are automatically logged to [Tensorboard](https://www.tensorflow.org/tensorboard) and [CSV](https://github.com/ultralytics/yolov5/pull/4148) as `results.csv`, which is plotted as `results.png` (below) after training completes. You can also plot any `results.csv` file manually:\n", + "Training results are automatically logged with [Tensorboard](https://www.tensorflow.org/tensorboard) and [CSV](https://github.com/ultralytics/yolov5/pull/4148) loggers to `runs/train`, with a new experiment directory created for each new training as `runs/train/exp2`, `runs/train/exp3`, etc.\n", "\n", - "```python\n", - "from utils.plots import plot_results \n", - "plot_results('path/to/results.csv') # plot 'results.csv' as 'results.png'\n", - "```\n", + "This directory contains train and val statistics, mosaics, labels, predictions and augmentated mosaics, as well as metrics and charts including precision-recall (PR) curves and confusion matrices. \n", "\n", - "\"COCO128" + "\"Local\n" ] }, { @@ -910,12 +923,12 @@ "source": [ "# Environments\n", "\n", - "YOLOv3 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):\n", + " 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):\n", "\n", - "- **Google Colab and Kaggle** notebooks with free GPU: \"Open \"Open\n", - "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/GCP-Quickstart)\n", - "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/AWS-Quickstart)\n", - "- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov3/wiki/Docker-Quickstart) \"Docker\n" + "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", + "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/GCP-Quickstart)\n", + "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/AWS-Quickstart)\n", + "- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/Docker-Quickstart) \"Docker\n" ] }, { @@ -926,9 +939,9 @@ "source": [ "# Status\n", "\n", - "![CI CPU testing](https://github.com/ultralytics/yolov3/workflows/CI%20CPU%20testing/badge.svg)\n", + "![ CI](https://github.com/ultralytics/yolov3/actions/workflows/ci-testing.yml/badge.svg)\n", "\n", - "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 training ([train.py](https://github.com/ultralytics/yolov3/blob/master/train.py)), testing ([val.py](https://github.com/ultralytics/yolov3/blob/master/val.py)), inference ([detect.py](https://github.com/ultralytics/yolov3/blob/master/detect.py)) and export ([export.py](https://github.com/ultralytics/yolov3/blob/master/export.py)) on MacOS, Windows, and Ubuntu every 24 hours and on every commit.\n" + "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of training ([train.py](https://github.com/ultralytics/yolov5/blob/master/train.py)), testing ([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.\n" ] }, { @@ -939,115 +952,25 @@ "source": [ "# Appendix\n", "\n", - "Optional extras below. Unit tests validate repo functionality and should be run on any PRs submitted.\n" + "Additional content below." ] }, - { - "cell_type": "code", - "metadata": { - "id": "mcKoSIK2WSzj" - }, - "source": [ - "# Reproduce\n", - "for x in 'yolov3', 'yolov3-spp', 'yolov3-tiny':\n", - " !python val.py --weights {x}.pt --data coco.yaml --img 640 --task speed # speed\n", - " !python val.py --weights {x}.pt --data coco.yaml --img 640 --conf 0.001 --iou 0.65 # mAP" - ], - "execution_count": null, - "outputs": [] - }, { "cell_type": "code", "metadata": { "id": "GMusP4OAxFu6" }, "source": [ - "# PyTorch Hub\n", + "# PyTorch HUB Inference (DetectionModels only)\n", "import torch\n", "\n", - "# Model\n", - "model = torch.hub.load('ultralytics/yolov3', 'yolov3')\n", - "\n", - "# Images\n", - "dir = 'https://ultralytics.com/images/'\n", - "imgs = [dir + f for f in ('zidane.jpg', 'bus.jpg')] # batch of images\n", - "\n", - "# Inference\n", - "results = model(imgs)\n", - "results.print() # or .show(), .save()" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "FGH0ZjkGjejy" - }, - "source": [ - "# CI Checks\n", - "%%shell\n", - "export PYTHONPATH=\"$PWD\" # to run *.py. files in subdirectories\n", - "rm -rf runs # remove runs/\n", - "for m in yolov3-tiny; do # models\n", - " python train.py --img 64 --batch 32 --weights $m.pt --epochs 1 --device 0 # train pretrained\n", - " python train.py --img 64 --batch 32 --weights '' --cfg $m.yaml --epochs 1 --device 0 # train scratch\n", - " for d in 0 cpu; do # devices\n", - " python val.py --weights $m.pt --device $d # val official\n", - " python val.py --weights runs/train/exp/weights/best.pt --device $d # val custom\n", - " python detect.py --weights $m.pt --device $d # detect official\n", - " python detect.py --weights runs/train/exp/weights/best.pt --device $d # detect custom\n", - " done\n", - " python hubconf.py # hub\n", - " python models/yolo.py --cfg $m.yaml # build PyTorch model\n", - " python models/tf.py --weights $m.pt # build TensorFlow model\n", - " python export.py --img 64 --batch 1 --weights $m.pt --include torchscript onnx # export\n", - "done" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "gogI-kwi3Tye" - }, - "source": [ - "# Profile\n", - "from utils.torch_utils import profile\n", - "\n", - "m1 = lambda x: x * torch.sigmoid(x)\n", - "m2 = torch.nn.SiLU()\n", - "results = profile(input=torch.randn(16, 3, 640, 640), ops=[m1, m2], n=100)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "RVRSOhEvUdb5" - }, - "source": [ - "# Evolve\n", - "!python train.py --img 640 --batch 64 --epochs 100 --data coco128.yaml --weights yolov3.pt --cache --noautoanchor --evolve\n", - "!d=runs/train/evolve && cp evolve.* $d && zip -r evolve.zip $d && gsutil mv evolve.zip gs://bucket # upload results (optional)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "BSgFCAcMbk1R" - }, - "source": [ - "# VOC\n", - "for b, m in zip([24, 24, 64], ['yolov3', 'yolov3-spp', 'yolov3-tiny']): # zip(batch_size, model)\n", - " !python train.py --batch {b} --weights {m}.pt --data VOC.yaml --epochs 50 --cache --img 512 --nosave --hyp hyp.finetune.yaml --project VOC --name {m}" + "model = torch.hub.load('ultralytics/yolov5', 'yolov5s', force_reload=True) # yolov5n - yolov5x6 or custom\n", + "im = 'https://ultralytics.com/images/zidane.jpg' # file, Path, PIL.Image, OpenCV, nparray, list\n", + "results = model(im) # inference\n", + "results.print() # or .show(), .save(), .crop(), .pandas(), etc." ], "execution_count": null, "outputs": [] } ] -} +} \ No newline at end of file diff --git a/utils/__init__.py b/utils/__init__.py index 309830c830..2abd2a795b 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -3,16 +3,78 @@ utils/initialization """ +import contextlib +import platform +import threading -def notebook_init(): - # For notebooks + +def emojis(str=''): + # Return platform-dependent emoji-safe version of string + return str.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else str + + +class TryExcept(contextlib.ContextDecorator): + # YOLOv3 TryExcept class. Usage: @TryExcept() decorator or 'with TryExcept():' context manager + def __init__(self, msg=''): + self.msg = msg + + def __enter__(self): + pass + + def __exit__(self, exc_type, value, traceback): + if value: + print(emojis(f"{self.msg}{': ' if self.msg else ''}{value}")) + return True + + +def threaded(func): + # Multi-threads a target function and returns thread. Usage: @threaded decorator + def wrapper(*args, **kwargs): + thread = threading.Thread(target=func, args=args, kwargs=kwargs, daemon=True) + thread.start() + return thread + + return wrapper + + +def join_threads(verbose=False): + # Join all daemon threads, i.e. atexit.register(lambda: join_threads()) + main_thread = threading.current_thread() + for t in threading.enumerate(): + if t is not main_thread: + if verbose: + print(f'Joining thread {t.name}') + t.join() + + +def notebook_init(verbose=True): + # Check system software and hardware print('Checking setup...') - from IPython import display # to display images and clear console output - from utils.general import emojis + import os + import shutil + + from utils.general import check_font, check_requirements, is_colab from utils.torch_utils import select_device # imports - display.clear_output() + check_font() + + import psutil + from IPython import display # to display images and clear console output + + if is_colab(): + shutil.rmtree('/content/sample_data', ignore_errors=True) # remove colab /sample_data directory + + # System info + if verbose: + gb = 1 << 30 # bytes to GiB (1024 ** 3) + ram = psutil.virtual_memory().total + total, used, free = shutil.disk_usage("/") + display.clear_output() + s = f'({os.cpu_count()} CPUs, {ram / gb:.1f} GB RAM, {(total - free) / gb:.1f}/{total / gb:.1f} GB disk)' + else: + s = '' + select_device(newline=False) - print(emojis('Setup complete ✅')) + print(emojis(f'Setup complete ✅ {s}')) return display diff --git a/utils/activations.py b/utils/activations.py index ae2fef1c8c..0ae0515200 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -8,29 +8,32 @@ import torch.nn.functional as F -# SiLU https://arxiv.org/pdf/1606.08415.pdf ---------------------------------------------------------------------------- -class SiLU(nn.Module): # export-friendly version of nn.SiLU() +class SiLU(nn.Module): + # SiLU activation https://arxiv.org/pdf/1606.08415.pdf @staticmethod def forward(x): return x * torch.sigmoid(x) -class Hardswish(nn.Module): # export-friendly version of nn.Hardswish() +class Hardswish(nn.Module): + # Hard-SiLU activation @staticmethod def forward(x): - # return x * F.hardsigmoid(x) # for torchscript and CoreML - return x * F.hardtanh(x + 3, 0.0, 6.0) / 6.0 # for torchscript, CoreML and ONNX + # return x * F.hardsigmoid(x) # for TorchScript and CoreML + return x * F.hardtanh(x + 3, 0.0, 6.0) / 6.0 # for TorchScript, CoreML and ONNX -# Mish https://github.com/digantamisra98/Mish -------------------------------------------------------------------------- class Mish(nn.Module): + # Mish activation https://github.com/digantamisra98/Mish @staticmethod def forward(x): return x * F.softplus(x).tanh() class MemoryEfficientMish(nn.Module): + # Mish activation memory-efficient class F(torch.autograd.Function): + @staticmethod def forward(ctx, x): ctx.save_for_backward(x) @@ -47,8 +50,8 @@ def forward(self, x): return self.F.apply(x) -# FReLU https://arxiv.org/abs/2007.11824 ------------------------------------------------------------------------------- class FReLU(nn.Module): + # FReLU activation https://arxiv.org/abs/2007.11824 def __init__(self, c1, k=3): # ch_in, kernel super().__init__() self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1, bias=False) @@ -58,9 +61,8 @@ def forward(self, x): return torch.max(x, self.bn(self.conv(x))) -# ACON https://arxiv.org/pdf/2009.04759.pdf ---------------------------------------------------------------------------- class AconC(nn.Module): - r""" ACON activation (activate or not). + r""" ACON activation (activate or not) AconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is a learnable parameter according to "Activate or Not: Learning Customized Activation" . """ @@ -77,7 +79,7 @@ def forward(self, x): class MetaAconC(nn.Module): - r""" ACON activation (activate or not). + r""" ACON activation (activate or not) MetaAconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is generated by a small network according to "Activate or Not: Learning Customized Activation" . """ diff --git a/utils/augmentations.py b/utils/augmentations.py index 16685044ea..85e68d051b 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -8,34 +8,42 @@ import cv2 import numpy as np +import torch +import torchvision.transforms as T +import torchvision.transforms.functional as TF -from utils.general import LOGGER, check_version, colorstr, resample_segments, segment2box +from utils.general import LOGGER, check_version, colorstr, resample_segments, segment2box, xywhn2xyxy from utils.metrics import bbox_ioa +IMAGENET_MEAN = 0.485, 0.456, 0.406 # RGB mean +IMAGENET_STD = 0.229, 0.224, 0.225 # RGB standard deviation + class Albumentations: - # Albumentations class (optional, only used if package is installed) - def __init__(self): + # YOLOv3 Albumentations class (optional, only used if package is installed) + def __init__(self, size=640): self.transform = None + prefix = colorstr('albumentations: ') try: import albumentations as A check_version(A.__version__, '1.0.3', hard=True) # version requirement - self.transform = A.Compose([ + T = [ + A.RandomResizedCrop(height=size, width=size, scale=(0.8, 1.0), ratio=(0.9, 1.11), p=0.0), A.Blur(p=0.01), A.MedianBlur(p=0.01), A.ToGray(p=0.01), A.CLAHE(p=0.01), A.RandomBrightnessContrast(p=0.0), A.RandomGamma(p=0.0), - A.ImageCompression(quality_lower=75, p=0.0)], - bbox_params=A.BboxParams(format='yolo', label_fields=['class_labels'])) + A.ImageCompression(quality_lower=75, p=0.0)] # transforms + self.transform = A.Compose(T, bbox_params=A.BboxParams(format='yolo', label_fields=['class_labels'])) - LOGGER.info(colorstr('albumentations: ') + ', '.join(f'{x}' for x in self.transform.transforms if x.p)) + LOGGER.info(prefix + ', '.join(f'{x}'.replace('always_apply=False, ', '') for x in T if x.p)) except ImportError: # package not installed, skip pass except Exception as e: - LOGGER.info(colorstr('albumentations: ') + f'{e}') + LOGGER.info(f'{prefix}{e}') def __call__(self, im, labels, p=1.0): if self.transform and random.random() < p: @@ -44,6 +52,18 @@ def __call__(self, im, labels, p=1.0): return im, labels +def normalize(x, mean=IMAGENET_MEAN, std=IMAGENET_STD, inplace=False): + # Denormalize RGB images x per ImageNet stats in BCHW format, i.e. = (x - mean) / std + return TF.normalize(x, mean, std, inplace=inplace) + + +def denormalize(x, mean=IMAGENET_MEAN, std=IMAGENET_STD): + # Denormalize RGB images x per ImageNet stats in BCHW format, i.e. = x * std + mean + for i in range(3): + x[:, i] = x[:, i] * std[i] + mean[i] + return x + + def augment_hsv(im, hgain=0.5, sgain=0.5, vgain=0.5): # HSV color-space augmentation if hgain or sgain or vgain: @@ -121,7 +141,14 @@ def letterbox(im, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleF return im, ratio, (dw, dh) -def random_perspective(im, targets=(), segments=(), degrees=10, translate=.1, scale=.1, shear=10, perspective=0.0, +def random_perspective(im, + targets=(), + segments=(), + degrees=10, + translate=.1, + scale=.1, + shear=10, + perspective=0.0, border=(0, 0)): # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(0.1, 0.1), scale=(0.9, 1.1), shear=(-10, 10)) # targets = [cls, xyxy] @@ -174,7 +201,7 @@ def random_perspective(im, targets=(), segments=(), degrees=10, translate=.1, sc # Transform label coordinates n = len(targets) if n: - use_segments = any(x.any() for x in segments) + use_segments = any(x.any() for x in segments) and len(segments) == n new = np.zeros((n, 4)) if use_segments: # warp segments segments = resample_segments(segments) # upsample @@ -223,12 +250,10 @@ def copy_paste(im, labels, segments, p=0.5): if (ioa < 0.30).all(): # allow 30% obscuration of existing labels labels = np.concatenate((labels, [[l[0], *box]]), 0) segments.append(np.concatenate((w - s[:, 0:1], s[:, 1:2]), 1)) - cv2.drawContours(im_new, [segments[j].astype(np.int32)], -1, (255, 255, 255), cv2.FILLED) + cv2.drawContours(im_new, [segments[j].astype(np.int32)], -1, (1, 1, 1), cv2.FILLED) - result = cv2.bitwise_and(src1=im, src2=im_new) - result = cv2.flip(result, 1) # augment segments (flip left-right) - i = result > 0 # pixels to replace - # i[:, :] = result.max(2).reshape(h, w, 1) # act over ch + result = cv2.flip(im, 1) # augment segments (flip left-right) + i = cv2.flip(im_new, 1).astype(bool) im[i] = result[i] # cv2.imwrite('debug.jpg', im) # debug return im, labels, segments @@ -255,7 +280,7 @@ def cutout(im, labels, p=0.5): # return unobscured labels if len(labels) and s > 0.03: box = np.array([xmin, ymin, xmax, ymax], dtype=np.float32) - ioa = bbox_ioa(box, labels[:, 1:5]) # intersection over area + ioa = bbox_ioa(box, xywhn2xyxy(labels[:, 1:5], w, h)) # intersection over area labels = labels[ioa < 0.60] # remove >60% obscured labels return labels @@ -269,9 +294,104 @@ def mixup(im, labels, im2, labels2): return im, labels -def box_candidates(box1, box2, wh_thr=2, ar_thr=20, area_thr=0.1, eps=1e-16): # box1(4,n), box2(4,n) +def box_candidates(box1, box2, wh_thr=2, ar_thr=100, area_thr=0.1, eps=1e-16): # box1(4,n), box2(4,n) # Compute candidate boxes: box1 before augment, box2 after augment, wh_thr (pixels), aspect_ratio_thr, area_ratio w1, h1 = box1[2] - box1[0], box1[3] - box1[1] w2, h2 = box2[2] - box2[0], box2[3] - box2[1] ar = np.maximum(w2 / (h2 + eps), h2 / (w2 + eps)) # aspect ratio return (w2 > wh_thr) & (h2 > wh_thr) & (w2 * h2 / (w1 * h1 + eps) > area_thr) & (ar < ar_thr) # candidates + + +def classify_albumentations( + augment=True, + size=224, + scale=(0.08, 1.0), + ratio=(0.75, 1.0 / 0.75), # 0.75, 1.33 + hflip=0.5, + vflip=0.0, + jitter=0.4, + mean=IMAGENET_MEAN, + std=IMAGENET_STD, + auto_aug=False): + # YOLOv3 classification Albumentations (optional, only used if package is installed) + prefix = colorstr('albumentations: ') + try: + import albumentations as A + from albumentations.pytorch import ToTensorV2 + check_version(A.__version__, '1.0.3', hard=True) # version requirement + if augment: # Resize and crop + T = [A.RandomResizedCrop(height=size, width=size, scale=scale, ratio=ratio)] + if auto_aug: + # TODO: implement AugMix, AutoAug & RandAug in albumentation + LOGGER.info(f'{prefix}auto augmentations are currently not supported') + else: + if hflip > 0: + T += [A.HorizontalFlip(p=hflip)] + if vflip > 0: + T += [A.VerticalFlip(p=vflip)] + if jitter > 0: + color_jitter = (float(jitter),) * 3 # repeat value for brightness, contrast, satuaration, 0 hue + T += [A.ColorJitter(*color_jitter, 0)] + else: # Use fixed crop for eval set (reproducibility) + T = [A.SmallestMaxSize(max_size=size), A.CenterCrop(height=size, width=size)] + T += [A.Normalize(mean=mean, std=std), ToTensorV2()] # Normalize and convert to Tensor + LOGGER.info(prefix + ', '.join(f'{x}'.replace('always_apply=False, ', '') for x in T if x.p)) + return A.Compose(T) + + except ImportError: # package not installed, skip + LOGGER.warning(f'{prefix}⚠️ not found, install with `pip install albumentations` (recommended)') + except Exception as e: + LOGGER.info(f'{prefix}{e}') + + +def classify_transforms(size=224): + # Transforms to apply if albumentations not installed + assert isinstance(size, int), f'ERROR: classify_transforms size {size} must be integer, not (list, tuple)' + # T.Compose([T.ToTensor(), T.Resize(size), T.CenterCrop(size), T.Normalize(IMAGENET_MEAN, IMAGENET_STD)]) + return T.Compose([CenterCrop(size), ToTensor(), T.Normalize(IMAGENET_MEAN, IMAGENET_STD)]) + + +class LetterBox: + # YOLOv3 LetterBox class for image preprocessing, i.e. T.Compose([LetterBox(size), ToTensor()]) + def __init__(self, size=(640, 640), auto=False, stride=32): + super().__init__() + self.h, self.w = (size, size) if isinstance(size, int) else size + self.auto = auto # pass max size integer, automatically solve for short side using stride + self.stride = stride # used with auto + + def __call__(self, im): # im = np.array HWC + imh, imw = im.shape[:2] + r = min(self.h / imh, self.w / imw) # ratio of new/old + h, w = round(imh * r), round(imw * r) # resized image + hs, ws = (math.ceil(x / self.stride) * self.stride for x in (h, w)) if self.auto else self.h, self.w + top, left = round((hs - h) / 2 - 0.1), round((ws - w) / 2 - 0.1) + im_out = np.full((self.h, self.w, 3), 114, dtype=im.dtype) + im_out[top:top + h, left:left + w] = cv2.resize(im, (w, h), interpolation=cv2.INTER_LINEAR) + return im_out + + +class CenterCrop: + # YOLOv3 CenterCrop class for image preprocessing, i.e. T.Compose([CenterCrop(size), ToTensor()]) + def __init__(self, size=640): + super().__init__() + self.h, self.w = (size, size) if isinstance(size, int) else size + + def __call__(self, im): # im = np.array HWC + imh, imw = im.shape[:2] + m = min(imh, imw) # min dimension + top, left = (imh - m) // 2, (imw - m) // 2 + return cv2.resize(im[top:top + m, left:left + m], (self.w, self.h), interpolation=cv2.INTER_LINEAR) + + +class ToTensor: + # YOLOv3 ToTensor class for image preprocessing, i.e. T.Compose([LetterBox(size), ToTensor()]) + def __init__(self, half=False): + super().__init__() + self.half = half + + def __call__(self, im): # im = np.array HWC in BGR order + im = np.ascontiguousarray(im.transpose((2, 0, 1))[::-1]) # HWC to CHW -> BGR to RGB -> contiguous + im = torch.from_numpy(im) # to torch + im = im.half() if self.half else im.float() # uint8 to fp16/32 + im /= 255.0 # 0-255 to 0.0-1.0 + return im diff --git a/utils/autoanchor.py b/utils/autoanchor.py index 0c202c4965..6b11e53396 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license """ -Auto-anchor utils +AutoAnchor utils """ import random @@ -10,21 +10,23 @@ import yaml from tqdm import tqdm -from utils.general import LOGGER, colorstr, emojis +from utils import TryExcept +from utils.general import LOGGER, TQDM_BAR_FORMAT, colorstr PREFIX = colorstr('AutoAnchor: ') def check_anchor_order(m): - # Check anchor order against stride order for Detect() module m, and correct if necessary - a = m.anchors.prod(-1).view(-1) # anchor area + # Check anchor order against stride order for YOLOv3 Detect() module m, and correct if necessary + a = m.anchors.prod(-1).mean(-1).view(-1) # mean anchor area per output layer da = a[-1] - a[0] # delta a ds = m.stride[-1] - m.stride[0] # delta s - if da.sign() != ds.sign(): # same order + if da and (da.sign() != ds.sign()): # same order LOGGER.info(f'{PREFIX}Reversing anchor order') m.anchors[:] = m.anchors.flip(0) +@TryExcept(f'{PREFIX}ERROR') def check_anchors(dataset, model, thr=4.0, imgsz=640): # Check anchor fit to data, recompute if necessary m = model.module.model[-1] if hasattr(model, 'module') else model.model[-1] # Detect() @@ -40,26 +42,26 @@ def metric(k): # compute metric bpr = (best > 1 / thr).float().mean() # best possible recall return bpr, aat - anchors = m.anchors.clone() * m.stride.to(m.anchors.device).view(-1, 1, 1) # current anchors + stride = m.stride.to(m.anchors.device).view(-1, 1, 1) # model strides + anchors = m.anchors.clone() * stride # current anchors bpr, aat = metric(anchors.cpu().view(-1, 2)) s = f'\n{PREFIX}{aat:.2f} anchors/target, {bpr:.3f} Best Possible Recall (BPR). ' if bpr > 0.98: # threshold to recompute - LOGGER.info(emojis(f'{s}Current anchors are a good fit to dataset ✅')) + LOGGER.info(f'{s}Current anchors are a good fit to dataset ✅') else: - LOGGER.info(emojis(f'{s}Anchors are a poor fit to dataset ⚠️, attempting to improve...')) + LOGGER.info(f'{s}Anchors are a poor fit to dataset ⚠️, attempting to improve...') na = m.anchors.numel() // 2 # number of anchors - try: - anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False) - except Exception as e: - LOGGER.info(f'{PREFIX}ERROR: {e}') + anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False) new_bpr = metric(anchors)[0] if new_bpr > bpr: # replace anchors anchors = torch.tensor(anchors, device=m.anchors.device).type_as(m.anchors) - m.anchors[:] = anchors.clone().view_as(m.anchors) / m.stride.to(m.anchors.device).view(-1, 1, 1) # loss - check_anchor_order(m) - LOGGER.info(f'{PREFIX}New anchors saved to model. Update model *.yaml to use these anchors in the future.') + m.anchors[:] = anchors.clone().view_as(m.anchors) + check_anchor_order(m) # must be in pixel-space (not grid-space) + m.anchors /= stride + s = f'{PREFIX}Done ✅ (optional: update model *.yaml to use these anchors in the future)' else: - LOGGER.info(f'{PREFIX}Original anchors better than new anchors. Proceeding with original anchors.') + s = f'{PREFIX}Done ⚠️ (original anchors better than new anchors, proceeding with original anchors)' + LOGGER.info(s) def kmean_anchors(dataset='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=1000, verbose=True): @@ -81,6 +83,7 @@ def kmean_anchors(dataset='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen """ from scipy.cluster.vq import kmeans + npr = np.random thr = 1 / thr def metric(k, wh): # compute metrics @@ -100,7 +103,7 @@ def print_results(k, verbose=True): s = f'{PREFIX}thr={thr:.2f}: {bpr:.4f} best possible recall, {aat:.2f} anchors past thr\n' \ f'{PREFIX}n={n}, img_size={img_size}, metric_all={x.mean():.3f}/{best.mean():.3f}-mean/best, ' \ f'past_thr={x[x > thr].mean():.3f}-mean: ' - for i, x in enumerate(k): + for x in k: s += '%i,%i, ' % (round(x[0]), round(x[1])) if verbose: LOGGER.info(s[:-2]) @@ -109,7 +112,7 @@ def print_results(k, verbose=True): if isinstance(dataset, str): # *.yaml file with open(dataset, errors='ignore') as f: data_dict = yaml.safe_load(f) # model dict - from utils.datasets import LoadImagesAndLabels + from utils.dataloaders import LoadImagesAndLabels dataset = LoadImagesAndLabels(data_dict['train'], augment=True, rect=True) # Get label wh @@ -119,18 +122,21 @@ def print_results(k, verbose=True): # Filter i = (wh0 < 3.0).any(1).sum() if i: - LOGGER.info(f'{PREFIX}WARNING: Extremely small objects found. {i} of {len(wh0)} labels are < 3 pixels in size.') - wh = wh0[(wh0 >= 2.0).any(1)] # filter > 2 pixels - # wh = wh * (np.random.rand(wh.shape[0], 1) * 0.9 + 0.1) # multiply by random scale 0-1 - - # Kmeans calculation - LOGGER.info(f'{PREFIX}Running kmeans for {n} anchors on {len(wh)} points...') - s = wh.std(0) # sigmas for whitening - k, dist = kmeans(wh / s, n, iter=30) # points, mean distance - assert len(k) == n, f'{PREFIX}ERROR: scipy.cluster.vq.kmeans requested {n} points but returned only {len(k)}' - k *= s - wh = torch.tensor(wh, dtype=torch.float32) # filtered - wh0 = torch.tensor(wh0, dtype=torch.float32) # unfiltered + LOGGER.info(f'{PREFIX}WARNING ⚠️ Extremely small objects found: {i} of {len(wh0)} labels are <3 pixels in size') + wh = wh0[(wh0 >= 2.0).any(1)].astype(np.float32) # filter > 2 pixels + # wh = wh * (npr.rand(wh.shape[0], 1) * 0.9 + 0.1) # multiply by random scale 0-1 + + # Kmeans init + try: + LOGGER.info(f'{PREFIX}Running kmeans for {n} anchors on {len(wh)} points...') + assert n <= len(wh) # apply overdetermined constraint + s = wh.std(0) # sigmas for whitening + k = kmeans(wh / s, n, iter=30)[0] * s # points + assert n == len(k) # kmeans may return fewer points than requested if wh is insufficient or too similar + except Exception: + LOGGER.warning(f'{PREFIX}WARNING ⚠️ switching strategies from kmeans to random init') + k = np.sort(npr.rand(n * 2)).reshape(n, 2) * img_size # random init + wh, wh0 = (torch.tensor(x, dtype=torch.float32) for x in (wh, wh0)) k = print_results(k, verbose=False) # Plot @@ -146,9 +152,8 @@ def print_results(k, verbose=True): # fig.savefig('wh.png', dpi=200) # Evolve - npr = np.random f, sh, mp, s = anchor_fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma - pbar = tqdm(range(gen), desc=f'{PREFIX}Evolving anchors with Genetic Algorithm:') # progress bar + pbar = tqdm(range(gen), bar_format=TQDM_BAR_FORMAT) # progress bar for _ in pbar: v = np.ones(sh) while (v == 1).all(): # mutate until a change occurs (prevent duplicates) @@ -161,4 +166,4 @@ def print_results(k, verbose=True): if verbose: print_results(k, verbose) - return print_results(k) + return print_results(k).astype(np.float32) diff --git a/utils/autobatch.py b/utils/autobatch.py index 4fbf32bc9a..de613ca126 100644 --- a/utils/autobatch.py +++ b/utils/autobatch.py @@ -7,51 +7,66 @@ import numpy as np import torch -from torch.cuda import amp from utils.general import LOGGER, colorstr from utils.torch_utils import profile -def check_train_batch_size(model, imgsz=640): - # Check training batch size - with amp.autocast(): +def check_train_batch_size(model, imgsz=640, amp=True): + # Check YOLOv3 training batch size + with torch.cuda.amp.autocast(amp): return autobatch(deepcopy(model).train(), imgsz) # compute optimal batch size -def autobatch(model, imgsz=640, fraction=0.9, batch_size=16): - # Automatically estimate best batch size to use `fraction` of available CUDA memory +def autobatch(model, imgsz=640, fraction=0.8, batch_size=16): + # Automatically estimate best YOLOv3 batch size to use `fraction` of available CUDA memory # Usage: # import torch # from utils.autobatch import autobatch - # model = torch.hub.load('ultralytics/yolov3', 'yolov3', autoshape=False) + # model = torch.hub.load('ultralytics/yolov5', 'yolov5s', autoshape=False) # print(autobatch(model)) + # Check device prefix = colorstr('AutoBatch: ') LOGGER.info(f'{prefix}Computing optimal batch size for --imgsz {imgsz}') device = next(model.parameters()).device # get model device if device.type == 'cpu': LOGGER.info(f'{prefix}CUDA not detected, using default CPU batch-size {batch_size}') return batch_size + if torch.backends.cudnn.benchmark: + LOGGER.info(f'{prefix} ⚠️ Requires torch.backends.cudnn.benchmark=False, using default batch-size {batch_size}') + return batch_size + # Inspect CUDA memory + gb = 1 << 30 # bytes to GiB (1024 ** 3) d = str(device).upper() # 'CUDA:0' properties = torch.cuda.get_device_properties(device) # device properties - t = properties.total_memory / 1024 ** 3 # (GiB) - r = torch.cuda.memory_reserved(device) / 1024 ** 3 # (GiB) - a = torch.cuda.memory_allocated(device) / 1024 ** 3 # (GiB) - f = t - (r + a) # free inside reserved + t = properties.total_memory / gb # GiB total + r = torch.cuda.memory_reserved(device) / gb # GiB reserved + a = torch.cuda.memory_allocated(device) / gb # GiB allocated + f = t - (r + a) # GiB free LOGGER.info(f'{prefix}{d} ({properties.name}) {t:.2f}G total, {r:.2f}G reserved, {a:.2f}G allocated, {f:.2f}G free') + # Profile batch sizes batch_sizes = [1, 2, 4, 8, 16] try: - img = [torch.zeros(b, 3, imgsz, imgsz) for b in batch_sizes] - y = profile(img, model, n=3, device=device) + img = [torch.empty(b, 3, imgsz, imgsz) for b in batch_sizes] + results = profile(img, model, n=3, device=device) except Exception as e: LOGGER.warning(f'{prefix}{e}') - y = [x[2] for x in y if x] # memory [2] - batch_sizes = batch_sizes[:len(y)] - p = np.polyfit(batch_sizes, y, deg=1) # first degree polynomial fit + # Fit a solution + y = [x[2] for x in results if x] # memory [2] + p = np.polyfit(batch_sizes[:len(y)], y, deg=1) # first degree polynomial fit b = int((f * fraction - p[1]) / p[0]) # y intercept (optimal batch size) - LOGGER.info(f'{prefix}Using batch-size {b} for {d} {t * fraction:.2f}G/{t:.2f}G ({fraction * 100:.0f}%)') + if None in results: # some sizes failed + i = results.index(None) # first fail index + if b >= batch_sizes[i]: # y intercept above failure point + b = batch_sizes[max(i - 1, 0)] # select prior safe point + if b < 1 or b > 1024: # b outside of safe range + b = batch_size + LOGGER.warning(f'{prefix}WARNING ⚠️ CUDA anomaly detected, recommend restart environment and retry command.') + + fraction = (np.polyval(p, b) + r + a) / t # actual fraction predicted + LOGGER.info(f'{prefix}Using batch-size {b} for {d} {t * fraction:.2f}G/{t:.2f}G ({fraction * 100:.0f}%) ✅') return b diff --git a/utils/aws/__init__.py b/utils/aws/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/utils/aws/mime.sh b/utils/aws/mime.sh new file mode 100644 index 0000000000..c319a83cfb --- /dev/null +++ b/utils/aws/mime.sh @@ -0,0 +1,26 @@ +# AWS EC2 instance startup 'MIME' script https://aws.amazon.com/premiumsupport/knowledge-center/execute-user-data-ec2/ +# This script will run on every instance restart, not only on first start +# --- DO NOT COPY ABOVE COMMENTS WHEN PASTING INTO USERDATA --- + +Content-Type: multipart/mixed; boundary="//" +MIME-Version: 1.0 + +--// +Content-Type: text/cloud-config; charset="us-ascii" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Content-Disposition: attachment; filename="cloud-config.txt" + +#cloud-config +cloud_final_modules: +- [scripts-user, always] + +--// +Content-Type: text/x-shellscript; charset="us-ascii" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Content-Disposition: attachment; filename="userdata.txt" + +#!/bin/bash +# --- paste contents of userdata.sh here --- +--// diff --git a/utils/aws/resume.py b/utils/aws/resume.py new file mode 100644 index 0000000000..b21731c979 --- /dev/null +++ b/utils/aws/resume.py @@ -0,0 +1,40 @@ +# Resume all interrupted trainings in yolov5/ dir including DDP trainings +# Usage: $ python utils/aws/resume.py + +import os +import sys +from pathlib import Path + +import torch +import yaml + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[2] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH + +port = 0 # --master_port +path = Path('').resolve() +for last in path.rglob('*/**/last.pt'): + ckpt = torch.load(last) + if ckpt['optimizer'] is None: + continue + + # Load opt.yaml + with open(last.parent.parent / 'opt.yaml', errors='ignore') as f: + opt = yaml.safe_load(f) + + # Get device count + d = opt['device'].split(',') # devices + nd = len(d) # number of devices + ddp = nd > 1 or (nd == 0 and torch.cuda.device_count() > 1) # distributed data parallel + + if ddp: # multi-GPU + port += 1 + cmd = f'python -m torch.distributed.run --nproc_per_node {nd} --master_port {port} train.py --resume {last}' + else: # single-GPU + cmd = f'python train.py --resume {last}' + + cmd += ' > /dev/null 2>&1 &' # redirect output to dev/null and run in daemon thread + print(cmd) + os.system(cmd) diff --git a/utils/aws/userdata.sh b/utils/aws/userdata.sh new file mode 100644 index 0000000000..5fc1332ac1 --- /dev/null +++ b/utils/aws/userdata.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# AWS EC2 instance startup script https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html +# This script will run only once on first instance start (for a re-start script see mime.sh) +# /home/ubuntu (ubuntu) or /home/ec2-user (amazon-linux) is working dir +# Use >300 GB SSD + +cd home/ubuntu +if [ ! -d yolov5 ]; then + echo "Running first-time script." # install dependencies, download COCO, pull Docker + git clone https://github.com/ultralytics/yolov5 -b master && sudo chmod -R 777 yolov5 + cd yolov5 + bash data/scripts/get_coco.sh && echo "COCO done." & + sudo docker pull ultralytics/yolov5:latest && echo "Docker done." & + python -m pip install --upgrade pip && pip install -r requirements.txt && python detect.py && echo "Requirements done." & + wait && echo "All tasks done." # finish background tasks +else + echo "Running re-start script." # resume interrupted runs + i=0 + list=$(sudo docker ps -qa) # container list i.e. $'one\ntwo\nthree\nfour' + while IFS= read -r id; do + ((i++)) + echo "restarting container $i: $id" + sudo docker start $id + # sudo docker exec -it $id python train.py --resume # single-GPU + sudo docker exec -d $id python utils/aws/resume.py # multi-scenario + done <<<"$list" +fi diff --git a/utils/callbacks.py b/utils/callbacks.py index 43e81a7c51..7715cf182d 100644 --- a/utils/callbacks.py +++ b/utils/callbacks.py @@ -3,46 +3,46 @@ Callback utils """ +import threading + class Callbacks: """" - Handles all registered callbacks for Hooks + Handles all registered callbacks for YOLOv3 Hooks """ - # Define the available callbacks - _callbacks = { - 'on_pretrain_routine_start': [], - 'on_pretrain_routine_end': [], - - 'on_train_start': [], - 'on_train_epoch_start': [], - 'on_train_batch_start': [], - 'optimizer_step': [], - 'on_before_zero_grad': [], - 'on_train_batch_end': [], - 'on_train_epoch_end': [], - - 'on_val_start': [], - 'on_val_batch_start': [], - 'on_val_image_end': [], - 'on_val_batch_end': [], - 'on_val_end': [], - - 'on_fit_epoch_end': [], # fit = train + val - 'on_model_save': [], - 'on_train_end': [], - - 'teardown': [], - } + def __init__(self): + # Define the available callbacks + self._callbacks = { + 'on_pretrain_routine_start': [], + 'on_pretrain_routine_end': [], + 'on_train_start': [], + 'on_train_epoch_start': [], + 'on_train_batch_start': [], + 'optimizer_step': [], + 'on_before_zero_grad': [], + 'on_train_batch_end': [], + 'on_train_epoch_end': [], + 'on_val_start': [], + 'on_val_batch_start': [], + 'on_val_image_end': [], + 'on_val_batch_end': [], + 'on_val_end': [], + 'on_fit_epoch_end': [], # fit = train + val + 'on_model_save': [], + 'on_train_end': [], + 'on_params_update': [], + 'teardown': [],} + self.stop_training = False # set True to interrupt training def register_action(self, hook, name='', callback=None): """ Register a new action to a callback hook Args: - hook The callback hook name to register the action to - name The name of the action for later reference - callback The callback to fire + hook: The callback hook name to register the action to + name: The name of the action for later reference + callback: The callback to fire """ assert hook in self._callbacks, f"hook '{hook}' not found in callbacks {self._callbacks}" assert callable(callback), f"callback '{callback}' is not callable" @@ -53,24 +53,24 @@ def get_registered_actions(self, hook=None): Returns all the registered actions by callback hook Args: - hook The name of the hook to check, defaults to all + hook: The name of the hook to check, defaults to all """ - if hook: - return self._callbacks[hook] - else: - return self._callbacks + return self._callbacks[hook] if hook else self._callbacks - def run(self, hook, *args, **kwargs): + def run(self, hook, *args, thread=False, **kwargs): """ - Loop through the registered actions and fire all callbacks + Loop through the registered actions and fire all callbacks on main thread Args: - hook The name of the hook to check, defaults to all - args Arguments to receive from - kwargs Keyword Arguments to receive from + hook: The name of the hook to check, defaults to all + args: Arguments to receive from YOLOv3 + thread: (boolean) Run callbacks in daemon thread + kwargs: Keyword Arguments to receive from YOLOv3 """ assert hook in self._callbacks, f"hook '{hook}' not found in callbacks {self._callbacks}" - for logger in self._callbacks[hook]: - logger['callback'](*args, **kwargs) + if thread: + threading.Thread(target=logger['callback'], args=args, kwargs=kwargs, daemon=True).start() + else: + logger['callback'](*args, **kwargs) diff --git a/utils/dataloaders.py b/utils/dataloaders.py new file mode 100644 index 0000000000..ba0317ca91 --- /dev/null +++ b/utils/dataloaders.py @@ -0,0 +1,1221 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Dataloaders and dataset utils +""" + +import contextlib +import glob +import hashlib +import json +import math +import os +import random +import shutil +import time +from itertools import repeat +from multiprocessing.pool import Pool, ThreadPool +from pathlib import Path +from threading import Thread +from urllib.parse import urlparse + +import numpy as np +import psutil +import torch +import torch.nn.functional as F +import torchvision +import yaml +from PIL import ExifTags, Image, ImageOps +from torch.utils.data import DataLoader, Dataset, dataloader, distributed +from tqdm import tqdm + +from utils.augmentations import (Albumentations, augment_hsv, classify_albumentations, classify_transforms, copy_paste, + letterbox, mixup, random_perspective) +from utils.general import (DATASETS_DIR, LOGGER, NUM_THREADS, TQDM_BAR_FORMAT, check_dataset, check_requirements, + check_yaml, clean_str, cv2, is_colab, is_kaggle, segments2boxes, unzip_file, xyn2xy, + xywh2xyxy, xywhn2xyxy, xyxy2xywhn) +from utils.torch_utils import torch_distributed_zero_first + +# Parameters +HELP_URL = 'See https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data' +IMG_FORMATS = 'bmp', 'dng', 'jpeg', 'jpg', 'mpo', 'png', 'tif', 'tiff', 'webp', 'pfm' # include image suffixes +VID_FORMATS = 'asf', 'avi', 'gif', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'ts', 'wmv' # include video suffixes +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +PIN_MEMORY = str(os.getenv('PIN_MEMORY', True)).lower() == 'true' # global pin_memory for dataloaders + +# Get orientation exif tag +for orientation in ExifTags.TAGS.keys(): + if ExifTags.TAGS[orientation] == 'Orientation': + break + + +def get_hash(paths): + # Returns a single hash value of a list of paths (files or dirs) + size = sum(os.path.getsize(p) for p in paths if os.path.exists(p)) # sizes + h = hashlib.sha256(str(size).encode()) # hash sizes + h.update(''.join(paths).encode()) # hash paths + return h.hexdigest() # return hash + + +def exif_size(img): + # Returns exif-corrected PIL size + s = img.size # (width, height) + with contextlib.suppress(Exception): + rotation = dict(img._getexif().items())[orientation] + if rotation in [6, 8]: # rotation 270 or 90 + s = (s[1], s[0]) + return s + + +def exif_transpose(image): + """ + Transpose a PIL image accordingly if it has an EXIF Orientation tag. + Inplace version of https://github.com/python-pillow/Pillow/blob/master/src/PIL/ImageOps.py exif_transpose() + + :param image: The image to transpose. + :return: An image. + """ + exif = image.getexif() + orientation = exif.get(0x0112, 1) # default 1 + if orientation > 1: + method = { + 2: Image.FLIP_LEFT_RIGHT, + 3: Image.ROTATE_180, + 4: Image.FLIP_TOP_BOTTOM, + 5: Image.TRANSPOSE, + 6: Image.ROTATE_270, + 7: Image.TRANSVERSE, + 8: Image.ROTATE_90}.get(orientation) + if method is not None: + image = image.transpose(method) + del exif[0x0112] + image.info["exif"] = exif.tobytes() + return image + + +def seed_worker(worker_id): + # Set dataloader worker seed https://pytorch.org/docs/stable/notes/randomness.html#dataloader + worker_seed = torch.initial_seed() % 2 ** 32 + np.random.seed(worker_seed) + random.seed(worker_seed) + + +def create_dataloader(path, + imgsz, + batch_size, + stride, + single_cls=False, + hyp=None, + augment=False, + cache=False, + pad=0.0, + rect=False, + rank=-1, + workers=8, + image_weights=False, + quad=False, + prefix='', + shuffle=False, + seed=0): + if rect and shuffle: + LOGGER.warning('WARNING ⚠️ --rect is incompatible with DataLoader shuffle, setting shuffle=False') + shuffle = False + with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP + dataset = LoadImagesAndLabels( + path, + imgsz, + batch_size, + augment=augment, # augmentation + hyp=hyp, # hyperparameters + rect=rect, # rectangular batches + cache_images=cache, + single_cls=single_cls, + stride=int(stride), + pad=pad, + image_weights=image_weights, + prefix=prefix) + + batch_size = min(batch_size, len(dataset)) + nd = torch.cuda.device_count() # number of CUDA devices + nw = min([os.cpu_count() // max(nd, 1), batch_size if batch_size > 1 else 0, workers]) # number of workers + sampler = None if rank == -1 else distributed.DistributedSampler(dataset, shuffle=shuffle) + loader = DataLoader if image_weights else InfiniteDataLoader # only DataLoader allows for attribute updates + generator = torch.Generator() + generator.manual_seed(6148914691236517205 + seed + RANK) + return loader(dataset, + batch_size=batch_size, + shuffle=shuffle and sampler is None, + num_workers=nw, + sampler=sampler, + pin_memory=PIN_MEMORY, + collate_fn=LoadImagesAndLabels.collate_fn4 if quad else LoadImagesAndLabels.collate_fn, + worker_init_fn=seed_worker, + generator=generator), dataset + + +class InfiniteDataLoader(dataloader.DataLoader): + """ Dataloader that reuses workers + + Uses same syntax as vanilla DataLoader + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + object.__setattr__(self, 'batch_sampler', _RepeatSampler(self.batch_sampler)) + self.iterator = super().__iter__() + + def __len__(self): + return len(self.batch_sampler.sampler) + + def __iter__(self): + for _ in range(len(self)): + yield next(self.iterator) + + +class _RepeatSampler: + """ Sampler that repeats forever + + Args: + sampler (Sampler) + """ + + def __init__(self, sampler): + self.sampler = sampler + + def __iter__(self): + while True: + yield from iter(self.sampler) + + +class LoadScreenshots: + # YOLOv5 screenshot dataloader, i.e. `python detect.py --source "screen 0 100 100 512 256"` + def __init__(self, source, img_size=640, stride=32, auto=True, transforms=None): + # source = [screen_number left top width height] (pixels) + check_requirements('mss') + import mss + + source, *params = source.split() + self.screen, left, top, width, height = 0, None, None, None, None # default to full screen 0 + if len(params) == 1: + self.screen = int(params[0]) + elif len(params) == 4: + left, top, width, height = (int(x) for x in params) + elif len(params) == 5: + self.screen, left, top, width, height = (int(x) for x in params) + self.img_size = img_size + self.stride = stride + self.transforms = transforms + self.auto = auto + self.mode = 'stream' + self.frame = 0 + self.sct = mss.mss() + + # Parse monitor shape + monitor = self.sct.monitors[self.screen] + self.top = monitor["top"] if top is None else (monitor["top"] + top) + self.left = monitor["left"] if left is None else (monitor["left"] + left) + self.width = width or monitor["width"] + self.height = height or monitor["height"] + self.monitor = {"left": self.left, "top": self.top, "width": self.width, "height": self.height} + + def __iter__(self): + return self + + def __next__(self): + # mss screen capture: get raw pixels from the screen as np array + im0 = np.array(self.sct.grab(self.monitor))[:, :, :3] # [:, :, :3] BGRA to BGR + s = f"screen {self.screen} (LTWH): {self.left},{self.top},{self.width},{self.height}: " + + if self.transforms: + im = self.transforms(im0) # transforms + else: + im = letterbox(im0, self.img_size, stride=self.stride, auto=self.auto)[0] # padded resize + im = im.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB + im = np.ascontiguousarray(im) # contiguous + self.frame += 1 + return str(self.screen), im, im0, None, s # screen, img, original img, im0s, s + + +class LoadImages: + # YOLOv5 image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4` + def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): + if isinstance(path, str) and Path(path).suffix == ".txt": # *.txt file with img/vid/dir on each line + path = Path(path).read_text().rsplit() + files = [] + for p in sorted(path) if isinstance(path, (list, tuple)) else [path]: + p = str(Path(p).resolve()) + if '*' in p: + files.extend(sorted(glob.glob(p, recursive=True))) # glob + elif os.path.isdir(p): + files.extend(sorted(glob.glob(os.path.join(p, '*.*')))) # dir + elif os.path.isfile(p): + files.append(p) # files + else: + raise FileNotFoundError(f'{p} does not exist') + + images = [x for x in files if x.split('.')[-1].lower() in IMG_FORMATS] + videos = [x for x in files if x.split('.')[-1].lower() in VID_FORMATS] + ni, nv = len(images), len(videos) + + self.img_size = img_size + self.stride = stride + self.files = images + videos + self.nf = ni + nv # number of files + self.video_flag = [False] * ni + [True] * nv + self.mode = 'image' + self.auto = auto + self.transforms = transforms # optional + self.vid_stride = vid_stride # video frame-rate stride + if any(videos): + self._new_video(videos[0]) # new video + else: + self.cap = None + assert self.nf > 0, f'No images or videos found in {p}. ' \ + f'Supported formats are:\nimages: {IMG_FORMATS}\nvideos: {VID_FORMATS}' + + def __iter__(self): + self.count = 0 + return self + + def __next__(self): + if self.count == self.nf: + raise StopIteration + path = self.files[self.count] + + if self.video_flag[self.count]: + # Read video + self.mode = 'video' + for _ in range(self.vid_stride): + self.cap.grab() + ret_val, im0 = self.cap.retrieve() + while not ret_val: + self.count += 1 + self.cap.release() + if self.count == self.nf: # last video + raise StopIteration + path = self.files[self.count] + self._new_video(path) + ret_val, im0 = self.cap.read() + + self.frame += 1 + # im0 = self._cv2_rotate(im0) # for use if cv2 autorotation is False + s = f'video {self.count + 1}/{self.nf} ({self.frame}/{self.frames}) {path}: ' + + else: + # Read image + self.count += 1 + im0 = cv2.imread(path) # BGR + assert im0 is not None, f'Image Not Found {path}' + s = f'image {self.count}/{self.nf} {path}: ' + + if self.transforms: + im = self.transforms(im0) # transforms + else: + im = letterbox(im0, self.img_size, stride=self.stride, auto=self.auto)[0] # padded resize + im = im.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB + im = np.ascontiguousarray(im) # contiguous + + return path, im, im0, self.cap, s + + def _new_video(self, path): + # Create a new video capture object + self.frame = 0 + self.cap = cv2.VideoCapture(path) + self.frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT) / self.vid_stride) + self.orientation = int(self.cap.get(cv2.CAP_PROP_ORIENTATION_META)) # rotation degrees + # self.cap.set(cv2.CAP_PROP_ORIENTATION_AUTO, 0) # disable https://github.com/ultralytics/yolov5/issues/8493 + + def _cv2_rotate(self, im): + # Rotate a cv2 video manually + if self.orientation == 0: + return cv2.rotate(im, cv2.ROTATE_90_CLOCKWISE) + elif self.orientation == 180: + return cv2.rotate(im, cv2.ROTATE_90_COUNTERCLOCKWISE) + elif self.orientation == 90: + return cv2.rotate(im, cv2.ROTATE_180) + return im + + def __len__(self): + return self.nf # number of files + + +class LoadStreams: + # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams` + def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): + torch.backends.cudnn.benchmark = True # faster for fixed-size inference + self.mode = 'stream' + self.img_size = img_size + self.stride = stride + self.vid_stride = vid_stride # video frame-rate stride + sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources] + n = len(sources) + self.sources = [clean_str(x) for x in sources] # clean source names for later + self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n + for i, s in enumerate(sources): # index, source + # Start thread to read frames from video stream + st = f'{i + 1}/{n}: {s}... ' + if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video + # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc' + check_requirements(('pafy', 'youtube_dl==2020.12.2')) + import pafy + s = pafy.new(s).getbest(preftype="mp4").url # YouTube URL + s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam + if s == 0: + assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.' + assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.' + cap = cv2.VideoCapture(s) + assert cap.isOpened(), f'{st}Failed to open {s}' + w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + fps = cap.get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan + self.frames[i] = max(int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback + self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback + + _, self.imgs[i] = cap.read() # guarantee first frame + self.threads[i] = Thread(target=self.update, args=([i, cap, s]), daemon=True) + LOGGER.info(f"{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)") + self.threads[i].start() + LOGGER.info('') # newline + + # check for common shapes + s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs]) + self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal + self.auto = auto and self.rect + self.transforms = transforms # optional + if not self.rect: + LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.') + + def update(self, i, cap, stream): + # Read stream `i` frames in daemon thread + n, f = 0, self.frames[i] # frame number, frame array + while cap.isOpened() and n < f: + n += 1 + cap.grab() # .read() = .grab() followed by .retrieve() + if n % self.vid_stride == 0: + success, im = cap.retrieve() + if success: + self.imgs[i] = im + else: + LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.') + self.imgs[i] = np.zeros_like(self.imgs[i]) + cap.open(stream) # re-open stream if signal was lost + time.sleep(0.0) # wait time + + def __iter__(self): + self.count = -1 + return self + + def __next__(self): + self.count += 1 + if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit + cv2.destroyAllWindows() + raise StopIteration + + im0 = self.imgs.copy() + if self.transforms: + im = np.stack([self.transforms(x) for x in im0]) # transforms + else: + im = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0] for x in im0]) # resize + im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW + im = np.ascontiguousarray(im) # contiguous + + return self.sources, im, im0, None, '' + + def __len__(self): + return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years + + +def img2label_paths(img_paths): + # Define label paths as a function of image paths + sa, sb = f'{os.sep}images{os.sep}', f'{os.sep}labels{os.sep}' # /images/, /labels/ substrings + return [sb.join(x.rsplit(sa, 1)).rsplit('.', 1)[0] + '.txt' for x in img_paths] + + +class LoadImagesAndLabels(Dataset): + # YOLOv5 train_loader/val_loader, loads images and labels for training and validation + cache_version = 0.6 # dataset labels *.cache version + rand_interp_methods = [cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_CUBIC, cv2.INTER_AREA, cv2.INTER_LANCZOS4] + + def __init__(self, + path, + img_size=640, + batch_size=16, + augment=False, + hyp=None, + rect=False, + image_weights=False, + cache_images=False, + single_cls=False, + stride=32, + pad=0.0, + min_items=0, + prefix=''): + self.img_size = img_size + self.augment = augment + self.hyp = hyp + self.image_weights = image_weights + self.rect = False if image_weights else rect + self.mosaic = self.augment and not self.rect # load 4 images at a time into a mosaic (only during training) + self.mosaic_border = [-img_size // 2, -img_size // 2] + self.stride = stride + self.path = path + self.albumentations = Albumentations(size=img_size) if augment else None + + try: + f = [] # image files + for p in path if isinstance(path, list) else [path]: + p = Path(p) # os-agnostic + if p.is_dir(): # dir + f += glob.glob(str(p / '**' / '*.*'), recursive=True) + # f = list(p.rglob('*.*')) # pathlib + elif p.is_file(): # file + with open(p) as t: + t = t.read().strip().splitlines() + parent = str(p.parent) + os.sep + f += [x.replace('./', parent, 1) if x.startswith('./') else x for x in t] # to global path + # f += [p.parent / x.lstrip(os.sep) for x in t] # to global path (pathlib) + else: + raise FileNotFoundError(f'{prefix}{p} does not exist') + self.im_files = sorted(x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in IMG_FORMATS) + # self.img_files = sorted([x for x in f if x.suffix[1:].lower() in IMG_FORMATS]) # pathlib + assert self.im_files, f'{prefix}No images found' + except Exception as e: + raise Exception(f'{prefix}Error loading data from {path}: {e}\n{HELP_URL}') from e + + # Check cache + self.label_files = img2label_paths(self.im_files) # labels + cache_path = (p if p.is_file() else Path(self.label_files[0]).parent).with_suffix('.cache') + try: + cache, exists = np.load(cache_path, allow_pickle=True).item(), True # load dict + assert cache['version'] == self.cache_version # matches current version + assert cache['hash'] == get_hash(self.label_files + self.im_files) # identical hash + except Exception: + cache, exists = self.cache_labels(cache_path, prefix), False # run cache ops + + # Display cache + nf, nm, ne, nc, n = cache.pop('results') # found, missing, empty, corrupt, total + if exists and LOCAL_RANK in {-1, 0}: + d = f"Scanning {cache_path}... {nf} images, {nm + ne} backgrounds, {nc} corrupt" + tqdm(None, desc=prefix + d, total=n, initial=n, bar_format=TQDM_BAR_FORMAT) # display cache results + if cache['msgs']: + LOGGER.info('\n'.join(cache['msgs'])) # display warnings + assert nf > 0 or not augment, f'{prefix}No labels found in {cache_path}, can not start training. {HELP_URL}' + + # Read cache + [cache.pop(k) for k in ('hash', 'version', 'msgs')] # remove items + labels, shapes, self.segments = zip(*cache.values()) + nl = len(np.concatenate(labels, 0)) # number of labels + assert nl > 0 or not augment, f'{prefix}All labels empty in {cache_path}, can not start training. {HELP_URL}' + self.labels = list(labels) + self.shapes = np.array(shapes) + self.im_files = list(cache.keys()) # update + self.label_files = img2label_paths(cache.keys()) # update + + # Filter images + if min_items: + include = np.array([len(x) >= min_items for x in self.labels]).nonzero()[0].astype(int) + LOGGER.info(f'{prefix}{n - len(include)}/{n} images filtered from dataset') + self.im_files = [self.im_files[i] for i in include] + self.label_files = [self.label_files[i] for i in include] + self.labels = [self.labels[i] for i in include] + self.segments = [self.segments[i] for i in include] + self.shapes = self.shapes[include] # wh + + # Create indices + n = len(self.shapes) # number of images + bi = np.floor(np.arange(n) / batch_size).astype(int) # batch index + nb = bi[-1] + 1 # number of batches + self.batch = bi # batch index of image + self.n = n + self.indices = range(n) + + # Update labels + include_class = [] # filter labels to include only these classes (optional) + include_class_array = np.array(include_class).reshape(1, -1) + for i, (label, segment) in enumerate(zip(self.labels, self.segments)): + if include_class: + j = (label[:, 0:1] == include_class_array).any(1) + self.labels[i] = label[j] + if segment: + self.segments[i] = segment[j] + if single_cls: # single-class training, merge all classes into 0 + self.labels[i][:, 0] = 0 + + # Rectangular Training + if self.rect: + # Sort by aspect ratio + s = self.shapes # wh + ar = s[:, 1] / s[:, 0] # aspect ratio + irect = ar.argsort() + self.im_files = [self.im_files[i] for i in irect] + self.label_files = [self.label_files[i] for i in irect] + self.labels = [self.labels[i] for i in irect] + self.segments = [self.segments[i] for i in irect] + self.shapes = s[irect] # wh + ar = ar[irect] + + # Set training image shapes + shapes = [[1, 1]] * nb + for i in range(nb): + ari = ar[bi == i] + mini, maxi = ari.min(), ari.max() + if maxi < 1: + shapes[i] = [maxi, 1] + elif mini > 1: + shapes[i] = [1, 1 / mini] + + self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(int) * stride + + # Cache images into RAM/disk for faster training + if cache_images == 'ram' and not self.check_cache_ram(prefix=prefix): + cache_images = False + self.ims = [None] * n + self.npy_files = [Path(f).with_suffix('.npy') for f in self.im_files] + if cache_images: + b, gb = 0, 1 << 30 # bytes of cached images, bytes per gigabytes + self.im_hw0, self.im_hw = [None] * n, [None] * n + fcn = self.cache_images_to_disk if cache_images == 'disk' else self.load_image + results = ThreadPool(NUM_THREADS).imap(fcn, range(n)) + pbar = tqdm(enumerate(results), total=n, bar_format=TQDM_BAR_FORMAT, disable=LOCAL_RANK > 0) + for i, x in pbar: + if cache_images == 'disk': + b += self.npy_files[i].stat().st_size + else: # 'ram' + self.ims[i], self.im_hw0[i], self.im_hw[i] = x # im, hw_orig, hw_resized = load_image(self, i) + b += self.ims[i].nbytes + pbar.desc = f'{prefix}Caching images ({b / gb:.1f}GB {cache_images})' + pbar.close() + + def check_cache_ram(self, safety_margin=0.1, prefix=''): + # Check image caching requirements vs available memory + b, gb = 0, 1 << 30 # bytes of cached images, bytes per gigabytes + n = min(self.n, 30) # extrapolate from 30 random images + for _ in range(n): + im = cv2.imread(random.choice(self.im_files)) # sample image + ratio = self.img_size / max(im.shape[0], im.shape[1]) # max(h, w) # ratio + b += im.nbytes * ratio ** 2 + mem_required = b * self.n / n # GB required to cache dataset into RAM + mem = psutil.virtual_memory() + cache = mem_required * (1 + safety_margin) < mem.available # to cache or not to cache, that is the question + if not cache: + LOGGER.info(f"{prefix}{mem_required / gb:.1f}GB RAM required, " + f"{mem.available / gb:.1f}/{mem.total / gb:.1f}GB available, " + f"{'caching images ✅' if cache else 'not caching images ⚠️'}") + return cache + + def cache_labels(self, path=Path('./labels.cache'), prefix=''): + # Cache dataset labels, check images and read shapes + x = {} # dict + nm, nf, ne, nc, msgs = 0, 0, 0, 0, [] # number missing, found, empty, corrupt, messages + desc = f"{prefix}Scanning {path.parent / path.stem}..." + with Pool(NUM_THREADS) as pool: + pbar = tqdm(pool.imap(verify_image_label, zip(self.im_files, self.label_files, repeat(prefix))), + desc=desc, + total=len(self.im_files), + bar_format=TQDM_BAR_FORMAT) + for im_file, lb, shape, segments, nm_f, nf_f, ne_f, nc_f, msg in pbar: + nm += nm_f + nf += nf_f + ne += ne_f + nc += nc_f + if im_file: + x[im_file] = [lb, shape, segments] + if msg: + msgs.append(msg) + pbar.desc = f"{desc} {nf} images, {nm + ne} backgrounds, {nc} corrupt" + + pbar.close() + if msgs: + LOGGER.info('\n'.join(msgs)) + if nf == 0: + LOGGER.warning(f'{prefix}WARNING ⚠️ No labels found in {path}. {HELP_URL}') + x['hash'] = get_hash(self.label_files + self.im_files) + x['results'] = nf, nm, ne, nc, len(self.im_files) + x['msgs'] = msgs # warnings + x['version'] = self.cache_version # cache version + try: + np.save(path, x) # save cache for next time + path.with_suffix('.cache.npy').rename(path) # remove .npy suffix + LOGGER.info(f'{prefix}New cache created: {path}') + except Exception as e: + LOGGER.warning(f'{prefix}WARNING ⚠️ Cache directory {path.parent} is not writeable: {e}') # not writeable + return x + + def __len__(self): + return len(self.im_files) + + # def __iter__(self): + # self.count = -1 + # print('ran dataset iter') + # #self.shuffled_vector = np.random.permutation(self.nF) if self.augment else np.arange(self.nF) + # return self + + def __getitem__(self, index): + index = self.indices[index] # linear, shuffled, or image_weights + + hyp = self.hyp + mosaic = self.mosaic and random.random() < hyp['mosaic'] + if mosaic: + # Load mosaic + img, labels = self.load_mosaic(index) + shapes = None + + # MixUp augmentation + if random.random() < hyp['mixup']: + img, labels = mixup(img, labels, *self.load_mosaic(random.randint(0, self.n - 1))) + + else: + # Load image + img, (h0, w0), (h, w) = self.load_image(index) + + # Letterbox + shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape + img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment) + shapes = (h0, w0), ((h / h0, w / w0), pad) # for COCO mAP rescaling + + labels = self.labels[index].copy() + if labels.size: # normalized xywh to pixel xyxy format + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], ratio[0] * w, ratio[1] * h, padw=pad[0], padh=pad[1]) + + if self.augment: + img, labels = random_perspective(img, + labels, + degrees=hyp['degrees'], + translate=hyp['translate'], + scale=hyp['scale'], + shear=hyp['shear'], + perspective=hyp['perspective']) + + nl = len(labels) # number of labels + if nl: + labels[:, 1:5] = xyxy2xywhn(labels[:, 1:5], w=img.shape[1], h=img.shape[0], clip=True, eps=1E-3) + + if self.augment: + # Albumentations + img, labels = self.albumentations(img, labels) + nl = len(labels) # update after albumentations + + # HSV color-space + augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) + + # Flip up-down + if random.random() < hyp['flipud']: + img = np.flipud(img) + if nl: + labels[:, 2] = 1 - labels[:, 2] + + # Flip left-right + if random.random() < hyp['fliplr']: + img = np.fliplr(img) + if nl: + labels[:, 1] = 1 - labels[:, 1] + + # Cutouts + # labels = cutout(img, labels, p=0.5) + # nl = len(labels) # update after cutout + + labels_out = torch.zeros((nl, 6)) + if nl: + labels_out[:, 1:] = torch.from_numpy(labels) + + # Convert + img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB + img = np.ascontiguousarray(img) + + return torch.from_numpy(img), labels_out, self.im_files[index], shapes + + def load_image(self, i): + # Loads 1 image from dataset index 'i', returns (im, original hw, resized hw) + im, f, fn = self.ims[i], self.im_files[i], self.npy_files[i], + if im is None: # not cached in RAM + if fn.exists(): # load npy + im = np.load(fn) + else: # read image + im = cv2.imread(f) # BGR + assert im is not None, f'Image Not Found {f}' + h0, w0 = im.shape[:2] # orig hw + r = self.img_size / max(h0, w0) # ratio + if r != 1: # if sizes are not equal + interp = cv2.INTER_LINEAR if (self.augment or r > 1) else cv2.INTER_AREA + im = cv2.resize(im, (math.ceil(w0 * r), math.ceil(h0 * r)), interpolation=interp) + return im, (h0, w0), im.shape[:2] # im, hw_original, hw_resized + return self.ims[i], self.im_hw0[i], self.im_hw[i] # im, hw_original, hw_resized + + def cache_images_to_disk(self, i): + # Saves an image as an *.npy file for faster loading + f = self.npy_files[i] + if not f.exists(): + np.save(f.as_posix(), cv2.imread(self.im_files[i])) + + def load_mosaic(self, index): + # YOLOv5 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic + labels4, segments4 = [], [] + s = self.img_size + yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y + indices = [index] + random.choices(self.indices, k=3) # 3 additional image indices + random.shuffle(indices) + for i, index in enumerate(indices): + # Load image + img, _, (h, w) = self.load_image(index) + + # place img in img4 + if i == 0: # top left + img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles + x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc # xmin, ymin, xmax, ymax (large image) + x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h # xmin, ymin, xmax, ymax (small image) + elif i == 1: # top right + x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc + x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h + elif i == 2: # bottom left + x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h) + x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h) + elif i == 3: # bottom right + x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h) + x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h) + + img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax] + padw = x1a - x1b + padh = y1a - y1b + + # Labels + labels, segments = self.labels[index].copy(), self.segments[index].copy() + if labels.size: + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padw, padh) # normalized xywh to pixel xyxy format + segments = [xyn2xy(x, w, h, padw, padh) for x in segments] + labels4.append(labels) + segments4.extend(segments) + + # Concat/clip labels + labels4 = np.concatenate(labels4, 0) + for x in (labels4[:, 1:], *segments4): + np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective() + # img4, labels4 = replicate(img4, labels4) # replicate + + # Augment + img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp['copy_paste']) + img4, labels4 = random_perspective(img4, + labels4, + segments4, + degrees=self.hyp['degrees'], + translate=self.hyp['translate'], + scale=self.hyp['scale'], + shear=self.hyp['shear'], + perspective=self.hyp['perspective'], + border=self.mosaic_border) # border to remove + + return img4, labels4 + + def load_mosaic9(self, index): + # YOLOv5 9-mosaic loader. Loads 1 image + 8 random images into a 9-image mosaic + labels9, segments9 = [], [] + s = self.img_size + indices = [index] + random.choices(self.indices, k=8) # 8 additional image indices + random.shuffle(indices) + hp, wp = -1, -1 # height, width previous + for i, index in enumerate(indices): + # Load image + img, _, (h, w) = self.load_image(index) + + # place img in img9 + if i == 0: # center + img9 = np.full((s * 3, s * 3, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles + h0, w0 = h, w + c = s, s, s + w, s + h # xmin, ymin, xmax, ymax (base) coordinates + elif i == 1: # top + c = s, s - h, s + w, s + elif i == 2: # top right + c = s + wp, s - h, s + wp + w, s + elif i == 3: # right + c = s + w0, s, s + w0 + w, s + h + elif i == 4: # bottom right + c = s + w0, s + hp, s + w0 + w, s + hp + h + elif i == 5: # bottom + c = s + w0 - w, s + h0, s + w0, s + h0 + h + elif i == 6: # bottom left + c = s + w0 - wp - w, s + h0, s + w0 - wp, s + h0 + h + elif i == 7: # left + c = s - w, s + h0 - h, s, s + h0 + elif i == 8: # top left + c = s - w, s + h0 - hp - h, s, s + h0 - hp + + padx, pady = c[:2] + x1, y1, x2, y2 = (max(x, 0) for x in c) # allocate coords + + # Labels + labels, segments = self.labels[index].copy(), self.segments[index].copy() + if labels.size: + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padx, pady) # normalized xywh to pixel xyxy format + segments = [xyn2xy(x, w, h, padx, pady) for x in segments] + labels9.append(labels) + segments9.extend(segments) + + # Image + img9[y1:y2, x1:x2] = img[y1 - pady:, x1 - padx:] # img9[ymin:ymax, xmin:xmax] + hp, wp = h, w # height, width previous + + # Offset + yc, xc = (int(random.uniform(0, s)) for _ in self.mosaic_border) # mosaic center x, y + img9 = img9[yc:yc + 2 * s, xc:xc + 2 * s] + + # Concat/clip labels + labels9 = np.concatenate(labels9, 0) + labels9[:, [1, 3]] -= xc + labels9[:, [2, 4]] -= yc + c = np.array([xc, yc]) # centers + segments9 = [x - c for x in segments9] + + for x in (labels9[:, 1:], *segments9): + np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective() + # img9, labels9 = replicate(img9, labels9) # replicate + + # Augment + img9, labels9, segments9 = copy_paste(img9, labels9, segments9, p=self.hyp['copy_paste']) + img9, labels9 = random_perspective(img9, + labels9, + segments9, + degrees=self.hyp['degrees'], + translate=self.hyp['translate'], + scale=self.hyp['scale'], + shear=self.hyp['shear'], + perspective=self.hyp['perspective'], + border=self.mosaic_border) # border to remove + + return img9, labels9 + + @staticmethod + def collate_fn(batch): + im, label, path, shapes = zip(*batch) # transposed + for i, lb in enumerate(label): + lb[:, 0] = i # add target image index for build_targets() + return torch.stack(im, 0), torch.cat(label, 0), path, shapes + + @staticmethod + def collate_fn4(batch): + im, label, path, shapes = zip(*batch) # transposed + n = len(shapes) // 4 + im4, label4, path4, shapes4 = [], [], path[:n], shapes[:n] + + ho = torch.tensor([[0.0, 0, 0, 1, 0, 0]]) + wo = torch.tensor([[0.0, 0, 1, 0, 0, 0]]) + s = torch.tensor([[1, 1, 0.5, 0.5, 0.5, 0.5]]) # scale + for i in range(n): # zidane torch.zeros(16,3,720,1280) # BCHW + i *= 4 + if random.random() < 0.5: + im1 = F.interpolate(im[i].unsqueeze(0).float(), scale_factor=2.0, mode='bilinear', + align_corners=False)[0].type(im[i].type()) + lb = label[i] + else: + im1 = torch.cat((torch.cat((im[i], im[i + 1]), 1), torch.cat((im[i + 2], im[i + 3]), 1)), 2) + lb = torch.cat((label[i], label[i + 1] + ho, label[i + 2] + wo, label[i + 3] + ho + wo), 0) * s + im4.append(im1) + label4.append(lb) + + for i, lb in enumerate(label4): + lb[:, 0] = i # add target image index for build_targets() + + return torch.stack(im4, 0), torch.cat(label4, 0), path4, shapes4 + + +# Ancillary functions -------------------------------------------------------------------------------------------------- +def flatten_recursive(path=DATASETS_DIR / 'coco128'): + # Flatten a recursive directory by bringing all files to top level + new_path = Path(f'{str(path)}_flat') + if os.path.exists(new_path): + shutil.rmtree(new_path) # delete output folder + os.makedirs(new_path) # make new output folder + for file in tqdm(glob.glob(f'{str(Path(path))}/**/*.*', recursive=True)): + shutil.copyfile(file, new_path / Path(file).name) + + +def extract_boxes(path=DATASETS_DIR / 'coco128'): # from utils.dataloaders import *; extract_boxes() + # Convert detection dataset into classification dataset, with one directory per class + path = Path(path) # images dir + shutil.rmtree(path / 'classification') if (path / 'classification').is_dir() else None # remove existing + files = list(path.rglob('*.*')) + n = len(files) # number of files + for im_file in tqdm(files, total=n): + if im_file.suffix[1:] in IMG_FORMATS: + # image + im = cv2.imread(str(im_file))[..., ::-1] # BGR to RGB + h, w = im.shape[:2] + + # labels + lb_file = Path(img2label_paths([str(im_file)])[0]) + if Path(lb_file).exists(): + with open(lb_file) as f: + lb = np.array([x.split() for x in f.read().strip().splitlines()], dtype=np.float32) # labels + + for j, x in enumerate(lb): + c = int(x[0]) # class + f = (path / 'classifier') / f'{c}' / f'{path.stem}_{im_file.stem}_{j}.jpg' # new filename + if not f.parent.is_dir(): + f.parent.mkdir(parents=True) + + b = x[1:] * [w, h, w, h] # box + # b[2:] = b[2:].max() # rectangle to square + b[2:] = b[2:] * 1.2 + 3 # pad + b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(int) + + b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image + b[[1, 3]] = np.clip(b[[1, 3]], 0, h) + assert cv2.imwrite(str(f), im[b[1]:b[3], b[0]:b[2]]), f'box failure in {f}' + + +def autosplit(path=DATASETS_DIR / 'coco128/images', weights=(0.9, 0.1, 0.0), annotated_only=False): + """ Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files + Usage: from utils.dataloaders import *; autosplit() + Arguments + path: Path to images directory + weights: Train, val, test weights (list, tuple) + annotated_only: Only use images with an annotated txt file + """ + path = Path(path) # images dir + files = sorted(x for x in path.rglob('*.*') if x.suffix[1:].lower() in IMG_FORMATS) # image files only + n = len(files) # number of files + random.seed(0) # for reproducibility + indices = random.choices([0, 1, 2], weights=weights, k=n) # assign each image to a split + + txt = ['autosplit_train.txt', 'autosplit_val.txt', 'autosplit_test.txt'] # 3 txt files + for x in txt: + if (path.parent / x).exists(): + (path.parent / x).unlink() # remove existing + + print(f'Autosplitting images from {path}' + ', using *.txt labeled images only' * annotated_only) + for i, img in tqdm(zip(indices, files), total=n): + if not annotated_only or Path(img2label_paths([str(img)])[0]).exists(): # check label + with open(path.parent / txt[i], 'a') as f: + f.write(f'./{img.relative_to(path.parent).as_posix()}' + '\n') # add image to txt file + + +def verify_image_label(args): + # Verify one image-label pair + im_file, lb_file, prefix = args + nm, nf, ne, nc, msg, segments = 0, 0, 0, 0, '', [] # number (missing, found, empty, corrupt), message, segments + try: + # verify images + im = Image.open(im_file) + im.verify() # PIL verify + shape = exif_size(im) # image size + assert (shape[0] > 9) & (shape[1] > 9), f'image size {shape} <10 pixels' + assert im.format.lower() in IMG_FORMATS, f'invalid image format {im.format}' + if im.format.lower() in ('jpg', 'jpeg'): + with open(im_file, 'rb') as f: + f.seek(-2, 2) + if f.read() != b'\xff\xd9': # corrupt JPEG + ImageOps.exif_transpose(Image.open(im_file)).save(im_file, 'JPEG', subsampling=0, quality=100) + msg = f'{prefix}WARNING ⚠️ {im_file}: corrupt JPEG restored and saved' + + # verify labels + if os.path.isfile(lb_file): + nf = 1 # label found + with open(lb_file) as f: + lb = [x.split() for x in f.read().strip().splitlines() if len(x)] + if any(len(x) > 6 for x in lb): # is segment + classes = np.array([x[0] for x in lb], dtype=np.float32) + segments = [np.array(x[1:], dtype=np.float32).reshape(-1, 2) for x in lb] # (cls, xy1...) + lb = np.concatenate((classes.reshape(-1, 1), segments2boxes(segments)), 1) # (cls, xywh) + lb = np.array(lb, dtype=np.float32) + nl = len(lb) + if nl: + assert lb.shape[1] == 5, f'labels require 5 columns, {lb.shape[1]} columns detected' + assert (lb >= 0).all(), f'negative label values {lb[lb < 0]}' + assert (lb[:, 1:] <= 1).all(), f'non-normalized or out of bounds coordinates {lb[:, 1:][lb[:, 1:] > 1]}' + _, i = np.unique(lb, axis=0, return_index=True) + if len(i) < nl: # duplicate row check + lb = lb[i] # remove duplicates + if segments: + segments = [segments[x] for x in i] + msg = f'{prefix}WARNING ⚠️ {im_file}: {nl - len(i)} duplicate labels removed' + else: + ne = 1 # label empty + lb = np.zeros((0, 5), dtype=np.float32) + else: + nm = 1 # label missing + lb = np.zeros((0, 5), dtype=np.float32) + return im_file, lb, shape, segments, nm, nf, ne, nc, msg + except Exception as e: + nc = 1 + msg = f'{prefix}WARNING ⚠️ {im_file}: ignoring corrupt image/label: {e}' + return [None, None, None, None, nm, nf, ne, nc, msg] + + +class HUBDatasetStats(): + """ Class for generating HUB dataset JSON and `-hub` dataset directory + + Arguments + path: Path to data.yaml or data.zip (with data.yaml inside data.zip) + autodownload: Attempt to download dataset if not found locally + + Usage + from utils.dataloaders import HUBDatasetStats + stats = HUBDatasetStats('coco128.yaml', autodownload=True) # usage 1 + stats = HUBDatasetStats('path/to/coco128.zip') # usage 2 + stats.get_json(save=False) + stats.process_images() + """ + + def __init__(self, path='coco128.yaml', autodownload=False): + # Initialize class + zipped, data_dir, yaml_path = self._unzip(Path(path)) + try: + with open(check_yaml(yaml_path), errors='ignore') as f: + data = yaml.safe_load(f) # data dict + if zipped: + data['path'] = data_dir + except Exception as e: + raise Exception("error/HUB/dataset_stats/yaml_load") from e + + check_dataset(data, autodownload) # download dataset if missing + self.hub_dir = Path(data['path'] + '-hub') + self.im_dir = self.hub_dir / 'images' + self.im_dir.mkdir(parents=True, exist_ok=True) # makes /images + self.stats = {'nc': data['nc'], 'names': list(data['names'].values())} # statistics dictionary + self.data = data + + @staticmethod + def _find_yaml(dir): + # Return data.yaml file + files = list(dir.glob('*.yaml')) or list(dir.rglob('*.yaml')) # try root level first and then recursive + assert files, f'No *.yaml file found in {dir}' + if len(files) > 1: + files = [f for f in files if f.stem == dir.stem] # prefer *.yaml files that match dir name + assert files, f'Multiple *.yaml files found in {dir}, only 1 *.yaml file allowed' + assert len(files) == 1, f'Multiple *.yaml files found: {files}, only 1 *.yaml file allowed in {dir}' + return files[0] + + def _unzip(self, path): + # Unzip data.zip + if not str(path).endswith('.zip'): # path is data.yaml + return False, None, path + assert Path(path).is_file(), f'Error unzipping {path}, file not found' + unzip_file(path, path=path.parent) + dir = path.with_suffix('') # dataset directory == zip name + assert dir.is_dir(), f'Error unzipping {path}, {dir} not found. path/to/abc.zip MUST unzip to path/to/abc/' + return True, str(dir), self._find_yaml(dir) # zipped, data_dir, yaml_path + + def _hub_ops(self, f, max_dim=1920): + # HUB ops for 1 image 'f': resize and save at reduced quality in /dataset-hub for web/app viewing + f_new = self.im_dir / Path(f).name # dataset-hub image filename + try: # use PIL + im = Image.open(f) + r = max_dim / max(im.height, im.width) # ratio + if r < 1.0: # image too large + im = im.resize((int(im.width * r), int(im.height * r))) + im.save(f_new, 'JPEG', quality=50, optimize=True) # save + except Exception as e: # use OpenCV + LOGGER.info(f'WARNING ⚠️ HUB ops PIL failure {f}: {e}') + im = cv2.imread(f) + im_height, im_width = im.shape[:2] + r = max_dim / max(im_height, im_width) # ratio + if r < 1.0: # image too large + im = cv2.resize(im, (int(im_width * r), int(im_height * r)), interpolation=cv2.INTER_AREA) + cv2.imwrite(str(f_new), im) + + def get_json(self, save=False, verbose=False): + # Return dataset JSON for Ultralytics HUB + def _round(labels): + # Update labels to integer class and 6 decimal place floats + return [[int(c), *(round(x, 4) for x in points)] for c, *points in labels] + + for split in 'train', 'val', 'test': + if self.data.get(split) is None: + self.stats[split] = None # i.e. no test set + continue + dataset = LoadImagesAndLabels(self.data[split]) # load dataset + x = np.array([ + np.bincount(label[:, 0].astype(int), minlength=self.data['nc']) + for label in tqdm(dataset.labels, total=dataset.n, desc='Statistics')]) # shape(128x80) + self.stats[split] = { + 'instance_stats': { + 'total': int(x.sum()), + 'per_class': x.sum(0).tolist()}, + 'image_stats': { + 'total': dataset.n, + 'unlabelled': int(np.all(x == 0, 1).sum()), + 'per_class': (x > 0).sum(0).tolist()}, + 'labels': [{ + str(Path(k).name): _round(v.tolist())} for k, v in zip(dataset.im_files, dataset.labels)]} + + # Save, print and return + if save: + stats_path = self.hub_dir / 'stats.json' + print(f'Saving {stats_path.resolve()}...') + with open(stats_path, 'w') as f: + json.dump(self.stats, f) # save stats.json + if verbose: + print(json.dumps(self.stats, indent=2, sort_keys=False)) + return self.stats + + def process_images(self): + # Compress images for Ultralytics HUB + for split in 'train', 'val', 'test': + if self.data.get(split) is None: + continue + dataset = LoadImagesAndLabels(self.data[split]) # load dataset + desc = f'{split} images' + for _ in tqdm(ThreadPool(NUM_THREADS).imap(self._hub_ops, dataset.im_files), total=dataset.n, desc=desc): + pass + print(f'Done. All images saved to {self.im_dir}') + return self.im_dir + + +# Classification dataloaders ------------------------------------------------------------------------------------------- +class ClassificationDataset(torchvision.datasets.ImageFolder): + """ + YOLOv5 Classification Dataset. + Arguments + root: Dataset path + transform: torchvision transforms, used by default + album_transform: Albumentations transforms, used if installed + """ + + def __init__(self, root, augment, imgsz, cache=False): + super().__init__(root=root) + self.torch_transforms = classify_transforms(imgsz) + self.album_transforms = classify_albumentations(augment, imgsz) if augment else None + self.cache_ram = cache is True or cache == 'ram' + self.cache_disk = cache == 'disk' + self.samples = [list(x) + [Path(x[0]).with_suffix('.npy'), None] for x in self.samples] # file, index, npy, im + + def __getitem__(self, i): + f, j, fn, im = self.samples[i] # filename, index, filename.with_suffix('.npy'), image + if self.cache_ram and im is None: + im = self.samples[i][3] = cv2.imread(f) + elif self.cache_disk: + if not fn.exists(): # load npy + np.save(fn.as_posix(), cv2.imread(f)) + im = np.load(fn) + else: # read image + im = cv2.imread(f) # BGR + if self.album_transforms: + sample = self.album_transforms(image=cv2.cvtColor(im, cv2.COLOR_BGR2RGB))["image"] + else: + sample = self.torch_transforms(im) + return sample, j + + +def create_classification_dataloader(path, + imgsz=224, + batch_size=16, + augment=True, + cache=False, + rank=-1, + workers=8, + shuffle=True): + # Returns Dataloader object to be used with YOLOv5 Classifier + with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP + dataset = ClassificationDataset(root=path, imgsz=imgsz, augment=augment, cache=cache) + batch_size = min(batch_size, len(dataset)) + nd = torch.cuda.device_count() + nw = min([os.cpu_count() // max(nd, 1), batch_size if batch_size > 1 else 0, workers]) + sampler = None if rank == -1 else distributed.DistributedSampler(dataset, shuffle=shuffle) + generator = torch.Generator() + generator.manual_seed(6148914691236517205 + RANK) + return InfiniteDataLoader(dataset, + batch_size=batch_size, + shuffle=shuffle and sampler is None, + num_workers=nw, + sampler=sampler, + pin_memory=PIN_MEMORY, + worker_init_fn=seed_worker, + generator=generator) # or DataLoader(persistent_workers=True) diff --git a/utils/datasets.py b/utils/datasets.py deleted file mode 100755 index 462d561a56..0000000000 --- a/utils/datasets.py +++ /dev/null @@ -1,1036 +0,0 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license -""" -Dataloaders and dataset utils -""" - -import glob -import hashlib -import json -import os -import random -import shutil -import time -from itertools import repeat -from multiprocessing.pool import Pool, ThreadPool -from pathlib import Path -from threading import Thread -from zipfile import ZipFile - -import cv2 -import numpy as np -import torch -import torch.nn.functional as F -import yaml -from PIL import ExifTags, Image, ImageOps -from torch.utils.data import DataLoader, Dataset, dataloader, distributed -from tqdm import tqdm - -from utils.augmentations import Albumentations, augment_hsv, copy_paste, letterbox, mixup, random_perspective -from utils.general import (LOGGER, check_dataset, check_requirements, check_yaml, clean_str, segments2boxes, xyn2xy, - xywh2xyxy, xywhn2xyxy, xyxy2xywhn) -from utils.torch_utils import torch_distributed_zero_first - -# Parameters -HELP_URL = 'https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data' -IMG_FORMATS = ['bmp', 'jpg', 'jpeg', 'png', 'tif', 'tiff', 'dng', 'webp', 'mpo'] # acceptable image suffixes -VID_FORMATS = ['mov', 'avi', 'mp4', 'mpg', 'mpeg', 'm4v', 'wmv', 'mkv'] # acceptable video suffixes -WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) # DPP -NUM_THREADS = min(8, os.cpu_count()) # number of multiprocessing threads - -# Get orientation exif tag -for orientation in ExifTags.TAGS.keys(): - if ExifTags.TAGS[orientation] == 'Orientation': - break - - -def get_hash(paths): - # Returns a single hash value of a list of paths (files or dirs) - size = sum(os.path.getsize(p) for p in paths if os.path.exists(p)) # sizes - h = hashlib.md5(str(size).encode()) # hash sizes - h.update(''.join(paths).encode()) # hash paths - return h.hexdigest() # return hash - - -def exif_size(img): - # Returns exif-corrected PIL size - s = img.size # (width, height) - try: - rotation = dict(img._getexif().items())[orientation] - if rotation == 6: # rotation 270 - s = (s[1], s[0]) - elif rotation == 8: # rotation 90 - s = (s[1], s[0]) - except: - pass - - return s - - -def exif_transpose(image): - """ - Transpose a PIL image accordingly if it has an EXIF Orientation tag. - Inplace version of https://github.com/python-pillow/Pillow/blob/master/src/PIL/ImageOps.py exif_transpose() - - :param image: The image to transpose. - :return: An image. - """ - exif = image.getexif() - orientation = exif.get(0x0112, 1) # default 1 - if orientation > 1: - method = {2: Image.FLIP_LEFT_RIGHT, - 3: Image.ROTATE_180, - 4: Image.FLIP_TOP_BOTTOM, - 5: Image.TRANSPOSE, - 6: Image.ROTATE_270, - 7: Image.TRANSVERSE, - 8: Image.ROTATE_90, - }.get(orientation) - if method is not None: - image = image.transpose(method) - del exif[0x0112] - image.info["exif"] = exif.tobytes() - return image - - -def create_dataloader(path, imgsz, batch_size, stride, single_cls=False, hyp=None, augment=False, cache=False, pad=0.0, - rect=False, rank=-1, workers=8, image_weights=False, quad=False, prefix='', shuffle=False): - if rect and shuffle: - LOGGER.warning('WARNING: --rect is incompatible with DataLoader shuffle, setting shuffle=False') - shuffle = False - with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP - dataset = LoadImagesAndLabels(path, imgsz, batch_size, - augment=augment, # augmentation - hyp=hyp, # hyperparameters - rect=rect, # rectangular batches - cache_images=cache, - single_cls=single_cls, - stride=int(stride), - pad=pad, - image_weights=image_weights, - prefix=prefix) - - batch_size = min(batch_size, len(dataset)) - nw = min([os.cpu_count() // WORLD_SIZE, batch_size if batch_size > 1 else 0, workers]) # number of workers - sampler = None if rank == -1 else distributed.DistributedSampler(dataset, shuffle=shuffle) - loader = DataLoader if image_weights else InfiniteDataLoader # only DataLoader allows for attribute updates - return loader(dataset, - batch_size=batch_size, - shuffle=shuffle and sampler is None, - num_workers=nw, - sampler=sampler, - pin_memory=True, - collate_fn=LoadImagesAndLabels.collate_fn4 if quad else LoadImagesAndLabels.collate_fn), dataset - - -class InfiniteDataLoader(dataloader.DataLoader): - """ Dataloader that reuses workers - - Uses same syntax as vanilla DataLoader - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - object.__setattr__(self, 'batch_sampler', _RepeatSampler(self.batch_sampler)) - self.iterator = super().__iter__() - - def __len__(self): - return len(self.batch_sampler.sampler) - - def __iter__(self): - for i in range(len(self)): - yield next(self.iterator) - - -class _RepeatSampler: - """ Sampler that repeats forever - - Args: - sampler (Sampler) - """ - - def __init__(self, sampler): - self.sampler = sampler - - def __iter__(self): - while True: - yield from iter(self.sampler) - - -class LoadImages: - # image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4` - def __init__(self, path, img_size=640, stride=32, auto=True): - p = str(Path(path).resolve()) # os-agnostic absolute path - if '*' in p: - files = sorted(glob.glob(p, recursive=True)) # glob - elif os.path.isdir(p): - files = sorted(glob.glob(os.path.join(p, '*.*'))) # dir - elif os.path.isfile(p): - files = [p] # files - else: - raise Exception(f'ERROR: {p} does not exist') - - images = [x for x in files if x.split('.')[-1].lower() in IMG_FORMATS] - videos = [x for x in files if x.split('.')[-1].lower() in VID_FORMATS] - ni, nv = len(images), len(videos) - - self.img_size = img_size - self.stride = stride - self.files = images + videos - self.nf = ni + nv # number of files - self.video_flag = [False] * ni + [True] * nv - self.mode = 'image' - self.auto = auto - if any(videos): - self.new_video(videos[0]) # new video - else: - self.cap = None - assert self.nf > 0, f'No images or videos found in {p}. ' \ - f'Supported formats are:\nimages: {IMG_FORMATS}\nvideos: {VID_FORMATS}' - - def __iter__(self): - self.count = 0 - return self - - def __next__(self): - if self.count == self.nf: - raise StopIteration - path = self.files[self.count] - - if self.video_flag[self.count]: - # Read video - self.mode = 'video' - ret_val, img0 = self.cap.read() - if not ret_val: - self.count += 1 - self.cap.release() - if self.count == self.nf: # last video - raise StopIteration - else: - path = self.files[self.count] - self.new_video(path) - ret_val, img0 = self.cap.read() - - self.frame += 1 - s = f'video {self.count + 1}/{self.nf} ({self.frame}/{self.frames}) {path}: ' - - else: - # Read image - self.count += 1 - img0 = cv2.imread(path) # BGR - assert img0 is not None, f'Image Not Found {path}' - s = f'image {self.count}/{self.nf} {path}: ' - - # Padded resize - img = letterbox(img0, self.img_size, stride=self.stride, auto=self.auto)[0] - - # Convert - img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB - img = np.ascontiguousarray(img) - - return path, img, img0, self.cap, s - - def new_video(self, path): - self.frame = 0 - self.cap = cv2.VideoCapture(path) - self.frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT)) - - def __len__(self): - return self.nf # number of files - - -class LoadWebcam: # for inference - # local webcam dataloader, i.e. `python detect.py --source 0` - def __init__(self, pipe='0', img_size=640, stride=32): - self.img_size = img_size - self.stride = stride - self.pipe = eval(pipe) if pipe.isnumeric() else pipe - self.cap = cv2.VideoCapture(self.pipe) # video capture object - self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 3) # set buffer size - - def __iter__(self): - self.count = -1 - return self - - def __next__(self): - self.count += 1 - if cv2.waitKey(1) == ord('q'): # q to quit - self.cap.release() - cv2.destroyAllWindows() - raise StopIteration - - # Read frame - ret_val, img0 = self.cap.read() - img0 = cv2.flip(img0, 1) # flip left-right - - # Print - assert ret_val, f'Camera Error {self.pipe}' - img_path = 'webcam.jpg' - s = f'webcam {self.count}: ' - - # Padded resize - img = letterbox(img0, self.img_size, stride=self.stride)[0] - - # Convert - img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB - img = np.ascontiguousarray(img) - - return img_path, img, img0, None, s - - def __len__(self): - return 0 - - -class LoadStreams: - # streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams` - def __init__(self, sources='streams.txt', img_size=640, stride=32, auto=True): - self.mode = 'stream' - self.img_size = img_size - self.stride = stride - - if os.path.isfile(sources): - with open(sources) as f: - sources = [x.strip() for x in f.read().strip().splitlines() if len(x.strip())] - else: - sources = [sources] - - n = len(sources) - self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n - self.sources = [clean_str(x) for x in sources] # clean source names for later - self.auto = auto - for i, s in enumerate(sources): # index, source - # Start thread to read frames from video stream - st = f'{i + 1}/{n}: {s}... ' - if 'youtube.com/' in s or 'youtu.be/' in s: # if source is YouTube video - check_requirements(('pafy', 'youtube_dl')) - import pafy - s = pafy.new(s).getbest(preftype="mp4").url # YouTube URL - s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam - cap = cv2.VideoCapture(s) - assert cap.isOpened(), f'{st}Failed to open {s}' - w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) - h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) - self.fps[i] = max(cap.get(cv2.CAP_PROP_FPS) % 100, 0) or 30.0 # 30 FPS fallback - self.frames[i] = max(int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback - - _, self.imgs[i] = cap.read() # guarantee first frame - self.threads[i] = Thread(target=self.update, args=([i, cap, s]), daemon=True) - LOGGER.info(f"{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)") - self.threads[i].start() - LOGGER.info('') # newline - - # check for common shapes - s = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0].shape for x in self.imgs]) - self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal - if not self.rect: - LOGGER.warning('WARNING: Stream shapes differ. For optimal performance supply similarly-shaped streams.') - - def update(self, i, cap, stream): - # Read stream `i` frames in daemon thread - n, f, read = 0, self.frames[i], 1 # frame number, frame array, inference every 'read' frame - while cap.isOpened() and n < f: - n += 1 - # _, self.imgs[index] = cap.read() - cap.grab() - if n % read == 0: - success, im = cap.retrieve() - if success: - self.imgs[i] = im - else: - LOGGER.warning('WARNING: Video stream unresponsive, please check your IP camera connection.') - self.imgs[i] *= 0 - cap.open(stream) # re-open stream if signal was lost - time.sleep(1 / self.fps[i]) # wait time - - def __iter__(self): - self.count = -1 - return self - - def __next__(self): - self.count += 1 - if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit - cv2.destroyAllWindows() - raise StopIteration - - # Letterbox - img0 = self.imgs.copy() - img = [letterbox(x, self.img_size, stride=self.stride, auto=self.rect and self.auto)[0] for x in img0] - - # Stack - img = np.stack(img, 0) - - # Convert - img = img[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW - img = np.ascontiguousarray(img) - - return self.sources, img, img0, None, '' - - def __len__(self): - return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years - - -def img2label_paths(img_paths): - # Define label paths as a function of image paths - sa, sb = os.sep + 'images' + os.sep, os.sep + 'labels' + os.sep # /images/, /labels/ substrings - return [sb.join(x.rsplit(sa, 1)).rsplit('.', 1)[0] + '.txt' for x in img_paths] - - -class LoadImagesAndLabels(Dataset): - # train_loader/val_loader, loads images and labels for training and validation - cache_version = 0.6 # dataset labels *.cache version - - def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, - cache_images=False, single_cls=False, stride=32, pad=0.0, prefix=''): - self.img_size = img_size - self.augment = augment - self.hyp = hyp - self.image_weights = image_weights - self.rect = False if image_weights else rect - self.mosaic = self.augment and not self.rect # load 4 images at a time into a mosaic (only during training) - self.mosaic_border = [-img_size // 2, -img_size // 2] - self.stride = stride - self.path = path - self.albumentations = Albumentations() if augment else None - - try: - f = [] # image files - for p in path if isinstance(path, list) else [path]: - p = Path(p) # os-agnostic - if p.is_dir(): # dir - f += glob.glob(str(p / '**' / '*.*'), recursive=True) - # f = list(p.rglob('*.*')) # pathlib - elif p.is_file(): # file - with open(p) as t: - t = t.read().strip().splitlines() - parent = str(p.parent) + os.sep - f += [x.replace('./', parent) if x.startswith('./') else x for x in t] # local to global path - # f += [p.parent / x.lstrip(os.sep) for x in t] # local to global path (pathlib) - else: - raise Exception(f'{prefix}{p} does not exist') - self.img_files = sorted(x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in IMG_FORMATS) - # self.img_files = sorted([x for x in f if x.suffix[1:].lower() in IMG_FORMATS]) # pathlib - assert self.img_files, f'{prefix}No images found' - except Exception as e: - raise Exception(f'{prefix}Error loading data from {path}: {e}\nSee {HELP_URL}') - - # Check cache - self.label_files = img2label_paths(self.img_files) # labels - cache_path = (p if p.is_file() else Path(self.label_files[0]).parent).with_suffix('.cache') - try: - cache, exists = np.load(cache_path, allow_pickle=True).item(), True # load dict - assert cache['version'] == self.cache_version # same version - assert cache['hash'] == get_hash(self.label_files + self.img_files) # same hash - except: - cache, exists = self.cache_labels(cache_path, prefix), False # cache - - # Display cache - nf, nm, ne, nc, n = cache.pop('results') # found, missing, empty, corrupted, total - if exists: - d = f"Scanning '{cache_path}' images and labels... {nf} found, {nm} missing, {ne} empty, {nc} corrupted" - tqdm(None, desc=prefix + d, total=n, initial=n) # display cache results - if cache['msgs']: - LOGGER.info('\n'.join(cache['msgs'])) # display warnings - assert nf > 0 or not augment, f'{prefix}No labels in {cache_path}. Can not train without labels. See {HELP_URL}' - - # Read cache - [cache.pop(k) for k in ('hash', 'version', 'msgs')] # remove items - labels, shapes, self.segments = zip(*cache.values()) - self.labels = list(labels) - self.shapes = np.array(shapes, dtype=np.float64) - self.img_files = list(cache.keys()) # update - self.label_files = img2label_paths(cache.keys()) # update - n = len(shapes) # number of images - bi = np.floor(np.arange(n) / batch_size).astype(np.int) # batch index - nb = bi[-1] + 1 # number of batches - self.batch = bi # batch index of image - self.n = n - self.indices = range(n) - - # Update labels - include_class = [] # filter labels to include only these classes (optional) - include_class_array = np.array(include_class).reshape(1, -1) - for i, (label, segment) in enumerate(zip(self.labels, self.segments)): - if include_class: - j = (label[:, 0:1] == include_class_array).any(1) - self.labels[i] = label[j] - if segment: - self.segments[i] = segment[j] - if single_cls: # single-class training, merge all classes into 0 - self.labels[i][:, 0] = 0 - if segment: - self.segments[i][:, 0] = 0 - - # Rectangular Training - if self.rect: - # Sort by aspect ratio - s = self.shapes # wh - ar = s[:, 1] / s[:, 0] # aspect ratio - irect = ar.argsort() - self.img_files = [self.img_files[i] for i in irect] - self.label_files = [self.label_files[i] for i in irect] - self.labels = [self.labels[i] for i in irect] - self.shapes = s[irect] # wh - ar = ar[irect] - - # Set training image shapes - shapes = [[1, 1]] * nb - for i in range(nb): - ari = ar[bi == i] - mini, maxi = ari.min(), ari.max() - if maxi < 1: - shapes[i] = [maxi, 1] - elif mini > 1: - shapes[i] = [1, 1 / mini] - - self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(np.int) * stride - - # Cache images into memory for faster training (WARNING: large datasets may exceed system RAM) - self.imgs, self.img_npy = [None] * n, [None] * n - if cache_images: - if cache_images == 'disk': - self.im_cache_dir = Path(Path(self.img_files[0]).parent.as_posix() + '_npy') - self.img_npy = [self.im_cache_dir / Path(f).with_suffix('.npy').name for f in self.img_files] - self.im_cache_dir.mkdir(parents=True, exist_ok=True) - gb = 0 # Gigabytes of cached images - self.img_hw0, self.img_hw = [None] * n, [None] * n - results = ThreadPool(NUM_THREADS).imap(lambda x: load_image(*x), zip(repeat(self), range(n))) - pbar = tqdm(enumerate(results), total=n) - for i, x in pbar: - if cache_images == 'disk': - if not self.img_npy[i].exists(): - np.save(self.img_npy[i].as_posix(), x[0]) - gb += self.img_npy[i].stat().st_size - else: - self.imgs[i], self.img_hw0[i], self.img_hw[i] = x # im, hw_orig, hw_resized = load_image(self, i) - gb += self.imgs[i].nbytes - pbar.desc = f'{prefix}Caching images ({gb / 1E9:.1f}GB {cache_images})' - pbar.close() - - def cache_labels(self, path=Path('./labels.cache'), prefix=''): - # Cache dataset labels, check images and read shapes - x = {} # dict - nm, nf, ne, nc, msgs = 0, 0, 0, 0, [] # number missing, found, empty, corrupt, messages - desc = f"{prefix}Scanning '{path.parent / path.stem}' images and labels..." - with Pool(NUM_THREADS) as pool: - pbar = tqdm(pool.imap(verify_image_label, zip(self.img_files, self.label_files, repeat(prefix))), - desc=desc, total=len(self.img_files)) - for im_file, l, shape, segments, nm_f, nf_f, ne_f, nc_f, msg in pbar: - nm += nm_f - nf += nf_f - ne += ne_f - nc += nc_f - if im_file: - x[im_file] = [l, shape, segments] - if msg: - msgs.append(msg) - pbar.desc = f"{desc}{nf} found, {nm} missing, {ne} empty, {nc} corrupted" - - pbar.close() - if msgs: - LOGGER.info('\n'.join(msgs)) - if nf == 0: - LOGGER.warning(f'{prefix}WARNING: No labels found in {path}. See {HELP_URL}') - x['hash'] = get_hash(self.label_files + self.img_files) - x['results'] = nf, nm, ne, nc, len(self.img_files) - x['msgs'] = msgs # warnings - x['version'] = self.cache_version # cache version - try: - np.save(path, x) # save cache for next time - path.with_suffix('.cache.npy').rename(path) # remove .npy suffix - LOGGER.info(f'{prefix}New cache created: {path}') - except Exception as e: - LOGGER.warning(f'{prefix}WARNING: Cache directory {path.parent} is not writeable: {e}') # not writeable - return x - - def __len__(self): - return len(self.img_files) - - # def __iter__(self): - # self.count = -1 - # print('ran dataset iter') - # #self.shuffled_vector = np.random.permutation(self.nF) if self.augment else np.arange(self.nF) - # return self - - def __getitem__(self, index): - index = self.indices[index] # linear, shuffled, or image_weights - - hyp = self.hyp - mosaic = self.mosaic and random.random() < hyp['mosaic'] - if mosaic: - # Load mosaic - img, labels = load_mosaic(self, index) - shapes = None - - # MixUp augmentation - if random.random() < hyp['mixup']: - img, labels = mixup(img, labels, *load_mosaic(self, random.randint(0, self.n - 1))) - - else: - # Load image - img, (h0, w0), (h, w) = load_image(self, index) - - # Letterbox - shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape - img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment) - shapes = (h0, w0), ((h / h0, w / w0), pad) # for COCO mAP rescaling - - labels = self.labels[index].copy() - if labels.size: # normalized xywh to pixel xyxy format - labels[:, 1:] = xywhn2xyxy(labels[:, 1:], ratio[0] * w, ratio[1] * h, padw=pad[0], padh=pad[1]) - - if self.augment: - img, labels = random_perspective(img, labels, - degrees=hyp['degrees'], - translate=hyp['translate'], - scale=hyp['scale'], - shear=hyp['shear'], - perspective=hyp['perspective']) - - nl = len(labels) # number of labels - if nl: - labels[:, 1:5] = xyxy2xywhn(labels[:, 1:5], w=img.shape[1], h=img.shape[0], clip=True, eps=1E-3) - - if self.augment: - # Albumentations - img, labels = self.albumentations(img, labels) - nl = len(labels) # update after albumentations - - # HSV color-space - augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) - - # Flip up-down - if random.random() < hyp['flipud']: - img = np.flipud(img) - if nl: - labels[:, 2] = 1 - labels[:, 2] - - # Flip left-right - if random.random() < hyp['fliplr']: - img = np.fliplr(img) - if nl: - labels[:, 1] = 1 - labels[:, 1] - - # Cutouts - # labels = cutout(img, labels, p=0.5) - - labels_out = torch.zeros((nl, 6)) - if nl: - labels_out[:, 1:] = torch.from_numpy(labels) - - # Convert - img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB - img = np.ascontiguousarray(img) - - return torch.from_numpy(img), labels_out, self.img_files[index], shapes - - @staticmethod - def collate_fn(batch): - img, label, path, shapes = zip(*batch) # transposed - for i, l in enumerate(label): - l[:, 0] = i # add target image index for build_targets() - return torch.stack(img, 0), torch.cat(label, 0), path, shapes - - @staticmethod - def collate_fn4(batch): - img, label, path, shapes = zip(*batch) # transposed - n = len(shapes) // 4 - img4, label4, path4, shapes4 = [], [], path[:n], shapes[:n] - - ho = torch.tensor([[0.0, 0, 0, 1, 0, 0]]) - wo = torch.tensor([[0.0, 0, 1, 0, 0, 0]]) - s = torch.tensor([[1, 1, 0.5, 0.5, 0.5, 0.5]]) # scale - for i in range(n): # zidane torch.zeros(16,3,720,1280) # BCHW - i *= 4 - if random.random() < 0.5: - im = F.interpolate(img[i].unsqueeze(0).float(), scale_factor=2.0, mode='bilinear', align_corners=False)[ - 0].type(img[i].type()) - l = label[i] - else: - im = torch.cat((torch.cat((img[i], img[i + 1]), 1), torch.cat((img[i + 2], img[i + 3]), 1)), 2) - l = torch.cat((label[i], label[i + 1] + ho, label[i + 2] + wo, label[i + 3] + ho + wo), 0) * s - img4.append(im) - label4.append(l) - - for i, l in enumerate(label4): - l[:, 0] = i # add target image index for build_targets() - - return torch.stack(img4, 0), torch.cat(label4, 0), path4, shapes4 - - -# Ancillary functions -------------------------------------------------------------------------------------------------- -def load_image(self, i): - # loads 1 image from dataset index 'i', returns im, original hw, resized hw - im = self.imgs[i] - if im is None: # not cached in ram - npy = self.img_npy[i] - if npy and npy.exists(): # load npy - im = np.load(npy) - else: # read image - path = self.img_files[i] - im = cv2.imread(path) # BGR - assert im is not None, f'Image Not Found {path}' - h0, w0 = im.shape[:2] # orig hw - r = self.img_size / max(h0, w0) # ratio - if r != 1: # if sizes are not equal - im = cv2.resize(im, (int(w0 * r), int(h0 * r)), - interpolation=cv2.INTER_AREA if r < 1 and not self.augment else cv2.INTER_LINEAR) - return im, (h0, w0), im.shape[:2] # im, hw_original, hw_resized - else: - return self.imgs[i], self.img_hw0[i], self.img_hw[i] # im, hw_original, hw_resized - - -def load_mosaic(self, index): - # 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic - labels4, segments4 = [], [] - s = self.img_size - yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y - indices = [index] + random.choices(self.indices, k=3) # 3 additional image indices - random.shuffle(indices) - for i, index in enumerate(indices): - # Load image - img, _, (h, w) = load_image(self, index) - - # place img in img4 - if i == 0: # top left - img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles - x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc # xmin, ymin, xmax, ymax (large image) - x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h # xmin, ymin, xmax, ymax (small image) - elif i == 1: # top right - x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc - x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h - elif i == 2: # bottom left - x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h) - x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h) - elif i == 3: # bottom right - x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h) - x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h) - - img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax] - padw = x1a - x1b - padh = y1a - y1b - - # Labels - labels, segments = self.labels[index].copy(), self.segments[index].copy() - if labels.size: - labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padw, padh) # normalized xywh to pixel xyxy format - segments = [xyn2xy(x, w, h, padw, padh) for x in segments] - labels4.append(labels) - segments4.extend(segments) - - # Concat/clip labels - labels4 = np.concatenate(labels4, 0) - for x in (labels4[:, 1:], *segments4): - np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective() - # img4, labels4 = replicate(img4, labels4) # replicate - - # Augment - img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp['copy_paste']) - img4, labels4 = random_perspective(img4, labels4, segments4, - degrees=self.hyp['degrees'], - translate=self.hyp['translate'], - scale=self.hyp['scale'], - shear=self.hyp['shear'], - perspective=self.hyp['perspective'], - border=self.mosaic_border) # border to remove - - return img4, labels4 - - -def load_mosaic9(self, index): - # 9-mosaic loader. Loads 1 image + 8 random images into a 9-image mosaic - labels9, segments9 = [], [] - s = self.img_size - indices = [index] + random.choices(self.indices, k=8) # 8 additional image indices - random.shuffle(indices) - for i, index in enumerate(indices): - # Load image - img, _, (h, w) = load_image(self, index) - - # place img in img9 - if i == 0: # center - img9 = np.full((s * 3, s * 3, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles - h0, w0 = h, w - c = s, s, s + w, s + h # xmin, ymin, xmax, ymax (base) coordinates - elif i == 1: # top - c = s, s - h, s + w, s - elif i == 2: # top right - c = s + wp, s - h, s + wp + w, s - elif i == 3: # right - c = s + w0, s, s + w0 + w, s + h - elif i == 4: # bottom right - c = s + w0, s + hp, s + w0 + w, s + hp + h - elif i == 5: # bottom - c = s + w0 - w, s + h0, s + w0, s + h0 + h - elif i == 6: # bottom left - c = s + w0 - wp - w, s + h0, s + w0 - wp, s + h0 + h - elif i == 7: # left - c = s - w, s + h0 - h, s, s + h0 - elif i == 8: # top left - c = s - w, s + h0 - hp - h, s, s + h0 - hp - - padx, pady = c[:2] - x1, y1, x2, y2 = (max(x, 0) for x in c) # allocate coords - - # Labels - labels, segments = self.labels[index].copy(), self.segments[index].copy() - if labels.size: - labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padx, pady) # normalized xywh to pixel xyxy format - segments = [xyn2xy(x, w, h, padx, pady) for x in segments] - labels9.append(labels) - segments9.extend(segments) - - # Image - img9[y1:y2, x1:x2] = img[y1 - pady:, x1 - padx:] # img9[ymin:ymax, xmin:xmax] - hp, wp = h, w # height, width previous - - # Offset - yc, xc = (int(random.uniform(0, s)) for _ in self.mosaic_border) # mosaic center x, y - img9 = img9[yc:yc + 2 * s, xc:xc + 2 * s] - - # Concat/clip labels - labels9 = np.concatenate(labels9, 0) - labels9[:, [1, 3]] -= xc - labels9[:, [2, 4]] -= yc - c = np.array([xc, yc]) # centers - segments9 = [x - c for x in segments9] - - for x in (labels9[:, 1:], *segments9): - np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective() - # img9, labels9 = replicate(img9, labels9) # replicate - - # Augment - img9, labels9 = random_perspective(img9, labels9, segments9, - degrees=self.hyp['degrees'], - translate=self.hyp['translate'], - scale=self.hyp['scale'], - shear=self.hyp['shear'], - perspective=self.hyp['perspective'], - border=self.mosaic_border) # border to remove - - return img9, labels9 - - -def create_folder(path='./new'): - # Create folder - if os.path.exists(path): - shutil.rmtree(path) # delete output folder - os.makedirs(path) # make new output folder - - -def flatten_recursive(path='../datasets/coco128'): - # Flatten a recursive directory by bringing all files to top level - new_path = Path(path + '_flat') - create_folder(new_path) - for file in tqdm(glob.glob(str(Path(path)) + '/**/*.*', recursive=True)): - shutil.copyfile(file, new_path / Path(file).name) - - -def extract_boxes(path='../datasets/coco128'): # from utils.datasets import *; extract_boxes() - # Convert detection dataset into classification dataset, with one directory per class - path = Path(path) # images dir - shutil.rmtree(path / 'classifier') if (path / 'classifier').is_dir() else None # remove existing - files = list(path.rglob('*.*')) - n = len(files) # number of files - for im_file in tqdm(files, total=n): - if im_file.suffix[1:] in IMG_FORMATS: - # image - im = cv2.imread(str(im_file))[..., ::-1] # BGR to RGB - h, w = im.shape[:2] - - # labels - lb_file = Path(img2label_paths([str(im_file)])[0]) - if Path(lb_file).exists(): - with open(lb_file) as f: - lb = np.array([x.split() for x in f.read().strip().splitlines()], dtype=np.float32) # labels - - for j, x in enumerate(lb): - c = int(x[0]) # class - f = (path / 'classifier') / f'{c}' / f'{path.stem}_{im_file.stem}_{j}.jpg' # new filename - if not f.parent.is_dir(): - f.parent.mkdir(parents=True) - - b = x[1:] * [w, h, w, h] # box - # b[2:] = b[2:].max() # rectangle to square - b[2:] = b[2:] * 1.2 + 3 # pad - b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(np.int) - - b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image - b[[1, 3]] = np.clip(b[[1, 3]], 0, h) - assert cv2.imwrite(str(f), im[b[1]:b[3], b[0]:b[2]]), f'box failure in {f}' - - -def autosplit(path='../datasets/coco128/images', weights=(0.9, 0.1, 0.0), annotated_only=False): - """ Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files - Usage: from utils.datasets import *; autosplit() - Arguments - path: Path to images directory - weights: Train, val, test weights (list, tuple) - annotated_only: Only use images with an annotated txt file - """ - path = Path(path) # images dir - files = sorted(x for x in path.rglob('*.*') if x.suffix[1:].lower() in IMG_FORMATS) # image files only - n = len(files) # number of files - random.seed(0) # for reproducibility - indices = random.choices([0, 1, 2], weights=weights, k=n) # assign each image to a split - - txt = ['autosplit_train.txt', 'autosplit_val.txt', 'autosplit_test.txt'] # 3 txt files - [(path.parent / x).unlink(missing_ok=True) for x in txt] # remove existing - - print(f'Autosplitting images from {path}' + ', using *.txt labeled images only' * annotated_only) - for i, img in tqdm(zip(indices, files), total=n): - if not annotated_only or Path(img2label_paths([str(img)])[0]).exists(): # check label - with open(path.parent / txt[i], 'a') as f: - f.write('./' + img.relative_to(path.parent).as_posix() + '\n') # add image to txt file - - -def verify_image_label(args): - # Verify one image-label pair - im_file, lb_file, prefix = args - nm, nf, ne, nc, msg, segments = 0, 0, 0, 0, '', [] # number (missing, found, empty, corrupt), message, segments - try: - # verify images - im = Image.open(im_file) - im.verify() # PIL verify - shape = exif_size(im) # image size - assert (shape[0] > 9) & (shape[1] > 9), f'image size {shape} <10 pixels' - assert im.format.lower() in IMG_FORMATS, f'invalid image format {im.format}' - if im.format.lower() in ('jpg', 'jpeg'): - with open(im_file, 'rb') as f: - f.seek(-2, 2) - if f.read() != b'\xff\xd9': # corrupt JPEG - ImageOps.exif_transpose(Image.open(im_file)).save(im_file, 'JPEG', subsampling=0, quality=100) - msg = f'{prefix}WARNING: {im_file}: corrupt JPEG restored and saved' - - # verify labels - if os.path.isfile(lb_file): - nf = 1 # label found - with open(lb_file) as f: - l = [x.split() for x in f.read().strip().splitlines() if len(x)] - if any([len(x) > 8 for x in l]): # is segment - classes = np.array([x[0] for x in l], dtype=np.float32) - segments = [np.array(x[1:], dtype=np.float32).reshape(-1, 2) for x in l] # (cls, xy1...) - l = np.concatenate((classes.reshape(-1, 1), segments2boxes(segments)), 1) # (cls, xywh) - l = np.array(l, dtype=np.float32) - nl = len(l) - if nl: - assert l.shape[1] == 5, f'labels require 5 columns, {l.shape[1]} columns detected' - assert (l >= 0).all(), f'negative label values {l[l < 0]}' - assert (l[:, 1:] <= 1).all(), f'non-normalized or out of bounds coordinates {l[:, 1:][l[:, 1:] > 1]}' - _, i = np.unique(l, axis=0, return_index=True) - if len(i) < nl: # duplicate row check - l = l[i] # remove duplicates - if segments: - segments = segments[i] - msg = f'{prefix}WARNING: {im_file}: {nl - len(i)} duplicate labels removed' - else: - ne = 1 # label empty - l = np.zeros((0, 5), dtype=np.float32) - else: - nm = 1 # label missing - l = np.zeros((0, 5), dtype=np.float32) - return im_file, l, shape, segments, nm, nf, ne, nc, msg - except Exception as e: - nc = 1 - msg = f'{prefix}WARNING: {im_file}: ignoring corrupt image/label: {e}' - return [None, None, None, None, nm, nf, ne, nc, msg] - - -def dataset_stats(path='coco128.yaml', autodownload=False, verbose=False, profile=False, hub=False): - """ Return dataset statistics dictionary with images and instances counts per split per class - To run in parent directory: export PYTHONPATH="$PWD/yolov3" - Usage1: from utils.datasets import *; dataset_stats('coco128.yaml', autodownload=True) - Usage2: from utils.datasets import *; dataset_stats('../datasets/coco128_with_yaml.zip') - Arguments - path: Path to data.yaml or data.zip (with data.yaml inside data.zip) - autodownload: Attempt to download dataset if not found locally - verbose: Print stats dictionary - """ - - def round_labels(labels): - # Update labels to integer class and 6 decimal place floats - return [[int(c), *(round(x, 4) for x in points)] for c, *points in labels] - - def unzip(path): - # Unzip data.zip TODO: CONSTRAINT: path/to/abc.zip MUST unzip to 'path/to/abc/' - if str(path).endswith('.zip'): # path is data.zip - assert Path(path).is_file(), f'Error unzipping {path}, file not found' - ZipFile(path).extractall(path=path.parent) # unzip - dir = path.with_suffix('') # dataset directory == zip name - return True, str(dir), next(dir.rglob('*.yaml')) # zipped, data_dir, yaml_path - else: # path is data.yaml - return False, None, path - - def hub_ops(f, max_dim=1920): - # HUB ops for 1 image 'f': resize and save at reduced quality in /dataset-hub for web/app viewing - f_new = im_dir / Path(f).name # dataset-hub image filename - try: # use PIL - im = Image.open(f) - r = max_dim / max(im.height, im.width) # ratio - if r < 1.0: # image too large - im = im.resize((int(im.width * r), int(im.height * r))) - im.save(f_new, 'JPEG', quality=75, optimize=True) # save - except Exception as e: # use OpenCV - print(f'WARNING: HUB ops PIL failure {f}: {e}') - im = cv2.imread(f) - im_height, im_width = im.shape[:2] - r = max_dim / max(im_height, im_width) # ratio - if r < 1.0: # image too large - im = cv2.resize(im, (int(im_width * r), int(im_height * r)), interpolation=cv2.INTER_LINEAR) - cv2.imwrite(str(f_new), im) - - zipped, data_dir, yaml_path = unzip(Path(path)) - with open(check_yaml(yaml_path), errors='ignore') as f: - data = yaml.safe_load(f) # data dict - if zipped: - data['path'] = data_dir # TODO: should this be dir.resolve()? - check_dataset(data, autodownload) # download dataset if missing - hub_dir = Path(data['path'] + ('-hub' if hub else '')) - stats = {'nc': data['nc'], 'names': data['names']} # statistics dictionary - for split in 'train', 'val', 'test': - if data.get(split) is None: - stats[split] = None # i.e. no test set - continue - x = [] - dataset = LoadImagesAndLabels(data[split]) # load dataset - for label in tqdm(dataset.labels, total=dataset.n, desc='Statistics'): - x.append(np.bincount(label[:, 0].astype(int), minlength=data['nc'])) - x = np.array(x) # shape(128x80) - stats[split] = {'instance_stats': {'total': int(x.sum()), 'per_class': x.sum(0).tolist()}, - 'image_stats': {'total': dataset.n, 'unlabelled': int(np.all(x == 0, 1).sum()), - 'per_class': (x > 0).sum(0).tolist()}, - 'labels': [{str(Path(k).name): round_labels(v.tolist())} for k, v in - zip(dataset.img_files, dataset.labels)]} - - if hub: - im_dir = hub_dir / 'images' - im_dir.mkdir(parents=True, exist_ok=True) - for _ in tqdm(ThreadPool(NUM_THREADS).imap(hub_ops, dataset.img_files), total=dataset.n, desc='HUB Ops'): - pass - - # Profile - stats_path = hub_dir / 'stats.json' - if profile: - for _ in range(1): - file = stats_path.with_suffix('.npy') - t1 = time.time() - np.save(file, stats) - t2 = time.time() - x = np.load(file, allow_pickle=True) - print(f'stats.npy times: {time.time() - t2:.3f}s read, {t2 - t1:.3f}s write') - - file = stats_path.with_suffix('.json') - t1 = time.time() - with open(file, 'w') as f: - json.dump(stats, f) # save stats *.json - t2 = time.time() - with open(file) as f: - x = json.load(f) # load hyps dict - print(f'stats.json times: {time.time() - t2:.3f}s read, {t2 - t1:.3f}s write') - - # Save, print and return - if hub: - print(f'Saving {stats_path.resolve()}...') - with open(stats_path, 'w') as f: - json.dump(stats, f) # save stats.json - if verbose: - print(json.dumps(stats, indent=2, sort_keys=False)) - return stats diff --git a/Dockerfile b/utils/docker/Dockerfile similarity index 79% rename from Dockerfile rename to utils/docker/Dockerfile index ce3c4667b1..a83e664c71 100644 --- a/Dockerfile +++ b/utils/docker/Dockerfile @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license -# Builds ultralytics/yolov3:latest image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 -# Image is CUDA-optimized for YOLOv3 single/multi-GPU training and inference +# Builds ultralytics/yolov5:latest image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 +# Image is CUDA-optimized for YOLOv5 single/multi-GPU training and inference # Start FROM NVIDIA PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch # FROM docker.io/pytorch/pytorch:latest @@ -26,7 +26,7 @@ WORKDIR /usr/src/app # Copy contents # COPY . /usr/src/app (issues as not a .git directory) -RUN git clone https://github.com/ultralytics/yolov3 /usr/src/app +RUN git clone https://github.com/ultralytics/yolov5 /usr/src/app # Install pip packages COPY requirements.txt . @@ -45,22 +45,22 @@ ENV DEBIAN_FRONTEND teletype # Usage Examples ------------------------------------------------------------------------------------------------------- # Build and Push -# t=ultralytics/yolov3:latest && sudo docker build -f Dockerfile -t $t . && sudo docker push $t +# t=ultralytics/yolov5:latest && sudo docker build -f utils/docker/Dockerfile -t $t . && sudo docker push $t # Pull and Run -# t=ultralytics/yolov3:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all $t +# t=ultralytics/yolov5:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all $t # Pull and Run with local directory access -# t=ultralytics/yolov3:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all -v "$(pwd)"/datasets:/usr/src/datasets $t +# t=ultralytics/yolov5:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all -v "$(pwd)"/datasets:/usr/src/datasets $t # Kill all # sudo docker kill $(sudo docker ps -q) # Kill all image-based -# sudo docker kill $(sudo docker ps -qa --filter ancestor=ultralytics/yolov3:latest) +# sudo docker kill $(sudo docker ps -qa --filter ancestor=ultralytics/yolov5:latest) # DockerHub tag update -# t=ultralytics/yolov3:latest tnew=ultralytics/yolov3:v6.2 && sudo docker pull $t && sudo docker tag $t $tnew && sudo docker push $tnew +# t=ultralytics/yolov5:latest tnew=ultralytics/yolov5:v6.2 && sudo docker pull $t && sudo docker tag $t $tnew && sudo docker push $tnew # Clean up # sudo docker system prune -a --volumes @@ -72,4 +72,4 @@ ENV DEBIAN_FRONTEND teletype # python -m torch.distributed.run --nproc_per_node 2 --master_port 1 train.py --epochs 3 # GCP VM from Image -# docker.io/ultralytics/yolov3:latest +# docker.io/ultralytics/yolov5:latest diff --git a/utils/docker/Dockerfile-arm64 b/utils/docker/Dockerfile-arm64 new file mode 100644 index 0000000000..31c2eaf86f --- /dev/null +++ b/utils/docker/Dockerfile-arm64 @@ -0,0 +1,41 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# Builds ultralytics/yolov5:latest-arm64 image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 +# Image is aarch64-compatible for Apple M1 and other ARM architectures i.e. Jetson Nano and Raspberry Pi + +# Start FROM Ubuntu image https://hub.docker.com/_/ubuntu +FROM arm64v8/ubuntu:rolling + +# Downloads to user config dir +ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/ + +# Install linux packages +ENV DEBIAN_FRONTEND noninteractive +RUN apt update +RUN TZ=Etc/UTC apt install -y tzdata +RUN apt install --no-install-recommends -y python3-pip git zip curl htop gcc libgl1-mesa-glx libglib2.0-0 libpython3-dev +# RUN alias python=python3 + +# Install pip packages +COPY requirements.txt . +RUN python3 -m pip install --upgrade pip wheel +RUN pip install --no-cache -r requirements.txt albumentations gsutil notebook \ + coremltools onnx onnxruntime + # tensorflow-aarch64 tensorflowjs \ + +# Create working directory +RUN mkdir -p /usr/src/app +WORKDIR /usr/src/app + +# Copy contents +# COPY . /usr/src/app (issues as not a .git directory) +RUN git clone https://github.com/ultralytics/yolov5 /usr/src/app +ENV DEBIAN_FRONTEND teletype + + +# Usage Examples ------------------------------------------------------------------------------------------------------- + +# Build and Push +# t=ultralytics/yolov5:latest-arm64 && sudo docker build --platform linux/arm64 -f utils/docker/Dockerfile-arm64 -t $t . && sudo docker push $t + +# Pull and Run +# t=ultralytics/yolov5:latest-arm64 && sudo docker pull $t && sudo docker run -it --ipc=host -v "$(pwd)"/datasets:/usr/src/datasets $t diff --git a/utils/docker/Dockerfile-cpu b/utils/docker/Dockerfile-cpu new file mode 100644 index 0000000000..8e27bf61e6 --- /dev/null +++ b/utils/docker/Dockerfile-cpu @@ -0,0 +1,42 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# Builds ultralytics/yolov5:latest-cpu image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 +# Image is CPU-optimized for ONNX, OpenVINO and PyTorch YOLOv5 deployments + +# Start FROM Ubuntu image https://hub.docker.com/_/ubuntu +FROM ubuntu:rolling + +# Downloads to user config dir +ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/ + +# Install linux packages +ENV DEBIAN_FRONTEND noninteractive +RUN apt update +RUN TZ=Etc/UTC apt install -y tzdata +RUN apt install --no-install-recommends -y python3-pip git zip curl htop libgl1-mesa-glx libglib2.0-0 libpython3-dev gnupg +# RUN alias python=python3 + +# Install pip packages +COPY requirements.txt . +RUN python3 -m pip install --upgrade pip wheel +RUN pip install --no-cache -r requirements.txt albumentations gsutil notebook \ + coremltools onnx onnx-simplifier onnxruntime 'openvino-dev>=2022.3' \ + # tensorflow tensorflowjs \ + --extra-index-url https://download.pytorch.org/whl/cpu + +# Create working directory +RUN mkdir -p /usr/src/app +WORKDIR /usr/src/app + +# Copy contents +# COPY . /usr/src/app (issues as not a .git directory) +RUN git clone https://github.com/ultralytics/yolov5 /usr/src/app +ENV DEBIAN_FRONTEND teletype + + +# Usage Examples ------------------------------------------------------------------------------------------------------- + +# Build and Push +# t=ultralytics/yolov5:latest-cpu && sudo docker build -f utils/docker/Dockerfile-cpu -t $t . && sudo docker push $t + +# Pull and Run +# t=ultralytics/yolov5:latest-cpu && sudo docker pull $t && sudo docker run -it --ipc=host -v "$(pwd)"/datasets:/usr/src/datasets $t diff --git a/utils/downloads.py b/utils/downloads.py index cd653078e9..6ca02aaa26 100644 --- a/utils/downloads.py +++ b/utils/downloads.py @@ -3,147 +3,106 @@ Download utils """ -import os -import platform +import logging import subprocess -import time import urllib from pathlib import Path -from zipfile import ZipFile import requests import torch +def is_url(url, check=True): + # Check if string is URL and check if URL exists + try: + url = str(url) + result = urllib.parse.urlparse(url) + assert all([result.scheme, result.netloc]) # check if is url + return (urllib.request.urlopen(url).getcode() == 200) if check else True # check if exists online + except (AssertionError, urllib.request.HTTPError): + return False + + def gsutil_getsize(url=''): # gs://bucket/file size https://cloud.google.com/storage/docs/gsutil/commands/du s = subprocess.check_output(f'gsutil du {url}', shell=True).decode('utf-8') return eval(s.split(' ')[0]) if len(s) else 0 # bytes +def url_getsize(url='https://ultralytics.com/images/bus.jpg'): + # Return downloadable file size in bytes + response = requests.head(url, allow_redirects=True) + return int(response.headers.get('content-length', -1)) + + def safe_download(file, url, url2=None, min_bytes=1E0, error_msg=''): # Attempts to download file from url or url2, checks and removes incomplete downloads < min_bytes + from utils.general import LOGGER + file = Path(file) assert_msg = f"Downloaded file '{file}' does not exist or size is < min_bytes={min_bytes}" try: # url1 - print(f'Downloading {url} to {file}...') - torch.hub.download_url_to_file(url, str(file)) + LOGGER.info(f'Downloading {url} to {file}...') + torch.hub.download_url_to_file(url, str(file), progress=LOGGER.level <= logging.INFO) assert file.exists() and file.stat().st_size > min_bytes, assert_msg # check except Exception as e: # url2 - file.unlink(missing_ok=True) # remove partial downloads - print(f'ERROR: {e}\nRe-attempting {url2 or url} to {file}...') - os.system(f"curl -L '{url2 or url}' -o '{file}' --retry 3 -C -") # curl download, retry and resume on fail + if file.exists(): + file.unlink() # remove partial downloads + LOGGER.info(f'ERROR: {e}\nRe-attempting {url2 or url} to {file}...') + subprocess.run( + f"curl -# -L '{url2 or url}' -o '{file}' --retry 3 -C -".split()) # curl download, retry and resume on fail finally: if not file.exists() or file.stat().st_size < min_bytes: # check - file.unlink(missing_ok=True) # remove partial downloads - print(f"ERROR: {assert_msg}\n{error_msg}") - print('') + if file.exists(): + file.unlink() # remove partial downloads + LOGGER.info(f"ERROR: {assert_msg}\n{error_msg}") + LOGGER.info('') -def attempt_download(file, repo='ultralytics/yolov3'): # from utils.downloads import *; attempt_download() - # Attempt file download if does not exist - file = Path(str(file).strip().replace("'", '')) +def attempt_download(file, repo='ultralytics/yolov5', release='v7.0'): + # Attempt file download from GitHub release assets if not found locally. release = 'latest', 'v7.0', etc. + from utils.general import LOGGER + + def github_assets(repository, version='latest'): + # Return GitHub repo tag (i.e. 'v7.0') and assets (i.e. ['yolov5s.pt', 'yolov5m.pt', ...]) + if version != 'latest': + version = f'tags/{version}' # i.e. tags/v7.0 + response = requests.get(f'https://api.github.com/repos/{repository}/releases/{version}').json() # github api + return response['tag_name'], [x['name'] for x in response['assets']] # tag, assets + file = Path(str(file).strip().replace("'", '')) if not file.exists(): # URL specified name = Path(urllib.parse.unquote(str(file))).name # decode '%2F' to '/' etc. if str(file).startswith(('http:/', 'https:/')): # download url = str(file).replace(':/', '://') # Pathlib turns :// -> :/ - name = name.split('?')[0] # parse authentication https://url.com/file.txt?auth... - safe_download(file=name, url=url, min_bytes=1E5) - return name + file = name.split('?')[0] # parse authentication https://url.com/file.txt?auth... + if Path(file).is_file(): + LOGGER.info(f'Found {url} locally at {file}') # file already exists + else: + safe_download(file=file, url=url, min_bytes=1E5) + return file # GitHub assets - file.parent.mkdir(parents=True, exist_ok=True) # make parent dir (if required) + assets = [f'yolov5{size}{suffix}.pt' for size in 'nsmlx' for suffix in ('', '6', '-cls', '-seg')] # default try: - response = requests.get(f'https://api.github.com/repos/{repo}/releases/latest').json() # github api - assets = [x['name'] for x in response['assets']] # release assets, i.e. ['yolov3.pt'...] - tag = response['tag_name'] # i.e. 'v1.0' - except: # fallback plan - assets = ['yolov3.pt', 'yolov3-spp.pt', 'yolov3-tiny.pt'] + tag, assets = github_assets(repo, release) + except Exception: try: - tag = subprocess.check_output('git tag', shell=True, stderr=subprocess.STDOUT).decode().split()[-1] - except: - tag = 'v9.5.0' # current release + tag, assets = github_assets(repo) # latest release + except Exception: + try: + tag = subprocess.check_output('git tag', shell=True, stderr=subprocess.STDOUT).decode().split()[-1] + except Exception: + tag = release + file.parent.mkdir(parents=True, exist_ok=True) # make parent dir (if required) if name in assets: - safe_download(file, - url=f'https://github.com/{repo}/releases/download/{tag}/{name}', - # url2=f'https://storage.googleapis.com/{repo}/ckpt/{name}', # backup url (optional) - min_bytes=1E5, - error_msg=f'{file} missing, try downloading from https://github.com/{repo}/releases/') + url3 = 'https://drive.google.com/drive/folders/1EFQTEUeXWSFww0luse2jB9M1QNZQGwNl' # backup gdrive mirror + safe_download( + file, + url=f'https://github.com/{repo}/releases/download/{tag}/{name}', + min_bytes=1E5, + error_msg=f'{file} missing, try downloading from https://github.com/{repo}/releases/{tag} or {url3}') return str(file) - - -def gdrive_download(id='16TiPfZj7htmTyhntwcZyEEAejOUxuT6m', file='tmp.zip'): - # Downloads a file from Google Drive. from yolov3.utils.downloads import *; gdrive_download() - t = time.time() - file = Path(file) - cookie = Path('cookie') # gdrive cookie - print(f'Downloading https://drive.google.com/uc?export=download&id={id} as {file}... ', end='') - file.unlink(missing_ok=True) # remove existing file - cookie.unlink(missing_ok=True) # remove existing cookie - - # Attempt file download - out = "NUL" if platform.system() == "Windows" else "/dev/null" - os.system(f'curl -c ./cookie -s -L "drive.google.com/uc?export=download&id={id}" > {out}') - if os.path.exists('cookie'): # large file - s = f'curl -Lb ./cookie "drive.google.com/uc?export=download&confirm={get_token()}&id={id}" -o {file}' - else: # small file - s = f'curl -s -L -o {file} "drive.google.com/uc?export=download&id={id}"' - r = os.system(s) # execute, capture return - cookie.unlink(missing_ok=True) # remove existing cookie - - # Error check - if r != 0: - file.unlink(missing_ok=True) # remove partial - print('Download error ') # raise Exception('Download error') - return r - - # Unzip if archive - if file.suffix == '.zip': - print('unzipping... ', end='') - ZipFile(file).extractall(path=file.parent) # unzip - file.unlink() # remove zip - - print(f'Done ({time.time() - t:.1f}s)') - return r - - -def get_token(cookie="./cookie"): - with open(cookie) as f: - for line in f: - if "download" in line: - return line.split()[-1] - return "" - -# Google utils: https://cloud.google.com/storage/docs/reference/libraries ---------------------------------------------- -# -# -# def upload_blob(bucket_name, source_file_name, destination_blob_name): -# # Uploads a file to a bucket -# # https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-python -# -# storage_client = storage.Client() -# bucket = storage_client.get_bucket(bucket_name) -# blob = bucket.blob(destination_blob_name) -# -# blob.upload_from_filename(source_file_name) -# -# print('File {} uploaded to {}.'.format( -# source_file_name, -# destination_blob_name)) -# -# -# def download_blob(bucket_name, source_blob_name, destination_file_name): -# # Uploads a blob from a bucket -# storage_client = storage.Client() -# bucket = storage_client.get_bucket(bucket_name) -# blob = bucket.blob(source_blob_name) -# -# blob.download_to_filename(destination_file_name) -# -# print('Blob {} downloaded to {}.'.format( -# source_blob_name, -# destination_file_name)) diff --git a/utils/flask_rest_api/README.md b/utils/flask_rest_api/README.md new file mode 100644 index 0000000000..a726acbd92 --- /dev/null +++ b/utils/flask_rest_api/README.md @@ -0,0 +1,73 @@ +# Flask REST API + +[REST](https://en.wikipedia.org/wiki/Representational_state_transfer) [API](https://en.wikipedia.org/wiki/API)s are +commonly used to expose Machine Learning (ML) models to other services. This folder contains an example REST API +created using Flask to expose the YOLOv5s model from [PyTorch Hub](https://pytorch.org/hub/ultralytics_yolov5/). + +## Requirements + +[Flask](https://palletsprojects.com/p/flask/) is required. Install with: + +```shell +$ pip install Flask +``` + +## Run + +After Flask installation run: + +```shell +$ python3 restapi.py --port 5000 +``` + +Then use [curl](https://curl.se/) to perform a request: + +```shell +$ curl -X POST -F image=@zidane.jpg 'http://localhost:5000/v1/object-detection/yolov5s' +``` + +The model inference results are returned as a JSON response: + +```json +[ + { + "class": 0, + "confidence": 0.8900438547, + "height": 0.9318675399, + "name": "person", + "width": 0.3264600933, + "xcenter": 0.7438579798, + "ycenter": 0.5207948685 + }, + { + "class": 0, + "confidence": 0.8440024257, + "height": 0.7155083418, + "name": "person", + "width": 0.6546785235, + "xcenter": 0.427829951, + "ycenter": 0.6334488392 + }, + { + "class": 27, + "confidence": 0.3771208823, + "height": 0.3902671337, + "name": "tie", + "width": 0.0696444362, + "xcenter": 0.3675483763, + "ycenter": 0.7991207838 + }, + { + "class": 27, + "confidence": 0.3527112305, + "height": 0.1540903747, + "name": "tie", + "width": 0.0336618312, + "xcenter": 0.7814827561, + "ycenter": 0.5065554976 + } +] +``` + +An example python script to perform inference using [requests](https://docs.python-requests.org/en/master/) is given +in `example_request.py` diff --git a/utils/flask_rest_api/example_request.py b/utils/flask_rest_api/example_request.py new file mode 100644 index 0000000000..68eec2f32f --- /dev/null +++ b/utils/flask_rest_api/example_request.py @@ -0,0 +1,19 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Perform test request +""" + +import pprint + +import requests + +DETECTION_URL = "http://localhost:5000/v1/object-detection/yolov5s" +IMAGE = "zidane.jpg" + +# Read image +with open(IMAGE, "rb") as f: + image_data = f.read() + +response = requests.post(DETECTION_URL, files={"image": image_data}).json() + +pprint.pprint(response) diff --git a/utils/flask_rest_api/restapi.py b/utils/flask_rest_api/restapi.py new file mode 100644 index 0000000000..290c6d5c88 --- /dev/null +++ b/utils/flask_rest_api/restapi.py @@ -0,0 +1,48 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Run a Flask REST API exposing one or more YOLOv5s models +""" + +import argparse +import io + +import torch +from flask import Flask, request +from PIL import Image + +app = Flask(__name__) +models = {} + +DETECTION_URL = "/v1/object-detection/" + + +@app.route(DETECTION_URL, methods=["POST"]) +def predict(model): + if request.method != "POST": + return + + if request.files.get("image"): + # Method 1 + # with request.files["image"] as f: + # im = Image.open(io.BytesIO(f.read())) + + # Method 2 + im_file = request.files["image"] + im_bytes = im_file.read() + im = Image.open(io.BytesIO(im_bytes)) + + if model in models: + results = models[model](im, size=640) # reduce size=320 for faster inference + return results.pandas().xyxy[0].to_json(orient="records") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Flask API exposing YOLOv5 model") + parser.add_argument("--port", default=5000, type=int, help="port number") + parser.add_argument('--model', nargs='+', default=['yolov5s'], help='model(s) to run, i.e. --model yolov5n yolov5s') + opt = parser.parse_args() + + for m in opt.model: + models[m] = torch.hub.load("ultralytics/yolov5", m, force_reload=True, skip_validation=True) + + app.run(host="0.0.0.0", port=opt.port) # debug=True causes Restarting with stat diff --git a/utils/general.py b/utils/general.py old mode 100755 new mode 100644 index 8331e7dbae..5ec2b5f704 --- a/utils/general.py +++ b/utils/general.py @@ -5,23 +5,31 @@ import contextlib import glob +import inspect import logging +import logging.config import math import os import platform import random import re -import shutil import signal +import subprocess +import sys import time import urllib +from copy import deepcopy +from datetime import datetime from itertools import repeat from multiprocessing.pool import ThreadPool from pathlib import Path from subprocess import check_output -from zipfile import ZipFile +from tarfile import is_tarfile +from typing import Optional +from zipfile import ZipFile, is_zipfile import cv2 +import IPython import numpy as np import pandas as pd import pkg_resources as pkg @@ -29,41 +37,152 @@ import torchvision import yaml +from utils import TryExcept, emojis from utils.downloads import gsutil_getsize from utils.metrics import box_iou, fitness +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLOv3 root directory +RANK = int(os.getenv('RANK', -1)) + # Settings +NUM_THREADS = min(8, max(1, os.cpu_count() - 1)) # number of YOLOv3 multiprocessing threads +DATASETS_DIR = Path(os.getenv('YOLOv5_DATASETS_DIR', ROOT.parent / 'datasets')) # global datasets directory +AUTOINSTALL = str(os.getenv('YOLOv5_AUTOINSTALL', True)).lower() == 'true' # global auto-install mode +VERBOSE = str(os.getenv('YOLOv5_VERBOSE', True)).lower() == 'true' # global verbose mode +TQDM_BAR_FORMAT = '{l_bar}{bar:10}{r_bar}' # tqdm bar format +FONT = 'Arial.ttf' # https://ultralytics.com/assets/Arial.ttf + torch.set_printoptions(linewidth=320, precision=5, profile='long') np.set_printoptions(linewidth=320, formatter={'float_kind': '{:11.5g}'.format}) # format short g, %precision=5 pd.options.display.max_columns = 10 cv2.setNumThreads(0) # prevent OpenCV from multithreading (incompatible with PyTorch DataLoader) -os.environ['NUMEXPR_MAX_THREADS'] = str(min(os.cpu_count(), 8)) # NumExpr max threads +os.environ['NUMEXPR_MAX_THREADS'] = str(NUM_THREADS) # NumExpr max threads +os.environ['OMP_NUM_THREADS'] = '1' if platform.system() == 'darwin' else str(NUM_THREADS) # OpenMP (PyTorch and SciPy) + + +def is_ascii(s=''): + # Is string composed of all ASCII (no UTF) characters? (note str().isascii() introduced in python 3.7) + s = str(s) # convert list, tuple, None, etc. to str + return len(s.encode().decode('ascii', 'ignore')) == len(s) + + +def is_chinese(s='人工智能'): + # Is string composed of any Chinese characters? + return bool(re.search('[\u4e00-\u9fff]', str(s))) + + +def is_colab(): + # Is environment a Google Colab instance? + return 'google.colab' in sys.modules + + +def is_notebook(): + # Is environment a Jupyter notebook? Verified on Colab, Jupyterlab, Kaggle, Paperspace + ipython_type = str(type(IPython.get_ipython())) + return 'colab' in ipython_type or 'zmqshell' in ipython_type + + +def is_kaggle(): + # Is environment a Kaggle Notebook? + return os.environ.get('PWD') == '/kaggle/working' and os.environ.get('KAGGLE_URL_BASE') == 'https://www.kaggle.com' -FILE = Path(__file__).resolve() -ROOT = FILE.parents[1] # root directory +def is_docker() -> bool: + """Check if the process runs inside a docker container.""" + if Path("/.dockerenv").exists(): + return True + try: # check if docker is in control groups + with open("/proc/self/cgroup") as file: + return any("docker" in line for line in file) + except OSError: + return False + + +def is_writeable(dir, test=False): + # Return True if directory has write permissions, test opening a file with write permissions if test=True + if not test: + return os.access(dir, os.W_OK) # possible issues on Windows + file = Path(dir) / 'tmp.txt' + try: + with open(file, 'w'): # open file with write permissions + pass + file.unlink() # remove file + return True + except OSError: + return False -def set_logging(name=None, verbose=True): - # Sets level and returns logger + +LOGGING_NAME = "yolov5" + + +def set_logging(name=LOGGING_NAME, verbose=True): + # sets up logging for the given name rank = int(os.getenv('RANK', -1)) # rank in world for Multi-GPU trainings - logging.basicConfig(format="%(message)s", level=logging.INFO if (verbose and rank in (-1, 0)) else logging.WARNING) - return logging.getLogger(name) + level = logging.INFO if verbose and rank in {-1, 0} else logging.ERROR + logging.config.dictConfig({ + "version": 1, + "disable_existing_loggers": False, + "formatters": { + name: { + "format": "%(message)s"}}, + "handlers": { + name: { + "class": "logging.StreamHandler", + "formatter": name, + "level": level,}}, + "loggers": { + name: { + "level": level, + "handlers": [name], + "propagate": False,}}}) + + +set_logging(LOGGING_NAME) # run before defining LOGGER +LOGGER = logging.getLogger(LOGGING_NAME) # define globally (used in train.py, val.py, detect.py, etc.) +if platform.system() == 'Windows': + for fn in LOGGER.info, LOGGER.warning: + setattr(LOGGER, fn.__name__, lambda x: fn(emojis(x))) # emoji safe logging + + +def user_config_dir(dir='Ultralytics', env_var='YOLOV5_CONFIG_DIR'): + # Return path of user configuration directory. Prefer environment variable if exists. Make dir if required. + env = os.getenv(env_var) + if env: + path = Path(env) # use environment variable + else: + cfg = {'Windows': 'AppData/Roaming', 'Linux': '.config', 'Darwin': 'Library/Application Support'} # 3 OS dirs + path = Path.home() / cfg.get(platform.system(), '') # OS-specific config dir + path = (path if is_writeable(path) else Path('/tmp')) / dir # GCP and AWS lambda fix, only /tmp is writeable + path.mkdir(exist_ok=True) # make if required + return path -LOGGER = set_logging(__name__) # define globally (used in train.py, val.py, detect.py, etc.) +CONFIG_DIR = user_config_dir() # Ultralytics settings dir class Profile(contextlib.ContextDecorator): - # Usage: @Profile() decorator or 'with Profile():' context manager + # YOLOv3 Profile class. Usage: @Profile() decorator or 'with Profile():' context manager + def __init__(self, t=0.0): + self.t = t + self.cuda = torch.cuda.is_available() + def __enter__(self): - self.start = time.time() + self.start = self.time() + return self def __exit__(self, type, value, traceback): - print(f'Profile results: {time.time() - self.start:.5f}s') + self.dt = self.time() - self.start # delta-time + self.t += self.dt # accumulate dt + + def time(self): + if self.cuda: + torch.cuda.synchronize() + return time.time() class Timeout(contextlib.ContextDecorator): - # Usage: @Timeout(seconds) decorator or 'with Timeout(seconds):' context manager + # YOLOv3 Timeout class. Usage: @Timeout(seconds) decorator or 'with Timeout(seconds):' context manager def __init__(self, seconds, *, timeout_msg='', suppress_timeout_errors=True): self.seconds = int(seconds) self.timeout_message = timeout_msg @@ -73,13 +192,15 @@ def _timeout_handler(self, signum, frame): raise TimeoutError(self.timeout_message) def __enter__(self): - signal.signal(signal.SIGALRM, self._timeout_handler) # Set handler for SIGALRM - signal.alarm(self.seconds) # start countdown for SIGALRM to be raised + if platform.system() != 'Windows': # not supported on Windows + signal.signal(signal.SIGALRM, self._timeout_handler) # Set handler for SIGALRM + signal.alarm(self.seconds) # start countdown for SIGALRM to be raised def __exit__(self, exc_type, exc_val, exc_tb): - signal.alarm(0) # Cancel SIGALRM if it's scheduled - if self.suppress and exc_type is TimeoutError: # Suppress TimeoutError - return True + if platform.system() != 'Windows': + signal.alarm(0) # Cancel SIGALRM if it's scheduled + if self.suppress and exc_type is TimeoutError: # Suppress TimeoutError + return True class WorkingDirectory(contextlib.ContextDecorator): @@ -95,40 +216,50 @@ def __exit__(self, exc_type, exc_val, exc_tb): os.chdir(self.cwd) -def try_except(func): - # try-except function. Usage: @try_except decorator - def handler(*args, **kwargs): - try: - func(*args, **kwargs) - except Exception as e: - print(e) - - return handler - - def methods(instance): # Get class/instance methods return [f for f in dir(instance) if callable(getattr(instance, f)) and not f.startswith("__")] -def print_args(name, opt): - # Print argparser arguments - LOGGER.info(colorstr(f'{name}: ') + ', '.join(f'{k}={v}' for k, v in vars(opt).items())) +def print_args(args: Optional[dict] = None, show_file=True, show_func=False): + # Print function arguments (optional args dict) + x = inspect.currentframe().f_back # previous frame + file, _, func, _, _ = inspect.getframeinfo(x) + if args is None: # get args automatically + args, _, _, frm = inspect.getargvalues(x) + args = {k: v for k, v in frm.items() if k in args} + try: + file = Path(file).resolve().relative_to(ROOT).with_suffix('') + except ValueError: + file = Path(file).stem + s = (f'{file}: ' if show_file else '') + (f'{func}: ' if show_func else '') + LOGGER.info(colorstr(s) + ', '.join(f'{k}={v}' for k, v in args.items())) -def init_seeds(seed=0): +def init_seeds(seed=0, deterministic=False): # Initialize random number generator (RNG) seeds https://pytorch.org/docs/stable/notes/randomness.html - # cudnn seed 0 settings are slower and more reproducible, else faster and less reproducible - import torch.backends.cudnn as cudnn random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) - cudnn.benchmark, cudnn.deterministic = (False, True) if seed == 0 else (True, False) + torch.cuda.manual_seed(seed) + torch.cuda.manual_seed_all(seed) # for Multi-GPU, exception safe + # torch.backends.cudnn.benchmark = True # AutoBatch problem https://github.com/ultralytics/yolov5/issues/9287 + if deterministic and check_version(torch.__version__, '1.12.0'): # https://github.com/ultralytics/yolov5/pull/8213 + torch.use_deterministic_algorithms(True) + torch.backends.cudnn.deterministic = True + os.environ['CUBLAS_WORKSPACE_CONFIG'] = ':4096:8' + os.environ['PYTHONHASHSEED'] = str(seed) def intersect_dicts(da, db, exclude=()): # Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values - return {k: v for k, v in da.items() if k in db and not any(x in k for x in exclude) and v.shape == db[k].shape} + return {k: v for k, v in da.items() if k in db and all(x not in k for x in exclude) and v.shape == db[k].shape} + + +def get_default_args(func): + # Get func() default arguments + signature = inspect.signature(func) + return {k: v.default for k, v in signature.parameters.items() if v.default is not inspect.Parameter.empty} def get_latest_run(search_dir='.'): @@ -137,76 +268,26 @@ def get_latest_run(search_dir='.'): return max(last_list, key=os.path.getctime) if last_list else '' -def user_config_dir(dir='Ultralytics', env_var='YOLOV3_CONFIG_DIR'): - # Return path of user configuration directory. Prefer environment variable if exists. Make dir if required. - env = os.getenv(env_var) - if env: - path = Path(env) # use environment variable - else: - cfg = {'Windows': 'AppData/Roaming', 'Linux': '.config', 'Darwin': 'Library/Application Support'} # 3 OS dirs - path = Path.home() / cfg.get(platform.system(), '') # OS-specific config dir - path = (path if is_writeable(path) else Path('/tmp')) / dir # GCP and AWS lambda fix, only /tmp is writeable - path.mkdir(exist_ok=True) # make if required - return path +def file_age(path=__file__): + # Return days since last file update + dt = (datetime.now() - datetime.fromtimestamp(Path(path).stat().st_mtime)) # delta + return dt.days # + dt.seconds / 86400 # fractional days -def is_writeable(dir, test=False): - # Return True if directory has write permissions, test opening a file with write permissions if test=True - if test: # method 1 - file = Path(dir) / 'tmp.txt' - try: - with open(file, 'w'): # open file with write permissions - pass - file.unlink() # remove file - return True - except OSError: - return False - else: # method 2 - return os.access(dir, os.R_OK) # possible issues on Windows - - -def is_docker(): - # Is environment a Docker container? - return Path('/workspace').exists() # or Path('/.dockerenv').exists() - - -def is_colab(): - # Is environment a Google Colab instance? - try: - import google.colab - return True - except ImportError: - return False - - -def is_pip(): - # Is file in a pip package? - return 'site-packages' in Path(__file__).resolve().parts - - -def is_ascii(s=''): - # Is string composed of all ASCII (no UTF) characters? (note str().isascii() introduced in python 3.7) - s = str(s) # convert list, tuple, None, etc. to str - return len(s.encode().decode('ascii', 'ignore')) == len(s) - - -def is_chinese(s='人工智能'): - # Is string composed of any Chinese characters? - return re.search('[\u4e00-\u9fff]', s) - - -def emojis(str=''): - # Return platform-dependent emoji-safe version of string - return str.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else str +def file_date(path=__file__): + # Return human-readable file modification date, i.e. '2021-3-26' + t = datetime.fromtimestamp(Path(path).stat().st_mtime) + return f'{t.year}-{t.month}-{t.day}' def file_size(path): # Return file/dir size (MB) + mb = 1 << 20 # bytes to MiB (1024 ** 2) path = Path(path) if path.is_file(): - return path.stat().st_size / 1E6 + return path.stat().st_size / mb elif path.is_dir(): - return sum(f.stat().st_size for f in path.glob('**/*') if f.is_file()) / 1E6 + return sum(f.stat().st_size for f in path.glob('**/*') if f.is_file()) / mb else: return 0.0 @@ -214,84 +295,123 @@ def file_size(path): def check_online(): # Check internet connectivity import socket + + def run_once(): + # Check once + try: + socket.create_connection(("1.1.1.1", 443), 5) # check host accessibility + return True + except OSError: + return False + + return run_once() or run_once() # check twice to increase robustness to intermittent connectivity issues + + +def git_describe(path=ROOT): # path must be a directory + # Return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe try: - socket.create_connection(("1.1.1.1", 443), 5) # check host accessibility - return True - except OSError: - return False + assert (Path(path) / '.git').is_dir() + return check_output(f'git -C {path} describe --tags --long --always', shell=True).decode()[:-1] + except Exception: + return '' -@try_except +@TryExcept() @WorkingDirectory(ROOT) -def check_git_status(): - # Recommend 'git pull' if code is out of date - msg = ', for updates see https://github.com/ultralytics/yolov3' - print(colorstr('github: '), end='') - assert Path('.git').exists(), 'skipping check (not a git repository)' + msg - assert not is_docker(), 'skipping check (Docker image)' + msg - assert check_online(), 'skipping check (offline)' + msg - - cmd = 'git fetch && git config --get remote.origin.url' - url = check_output(cmd, shell=True, timeout=5).decode().strip().rstrip('.git') # git fetch - branch = check_output('git rev-parse --abbrev-ref HEAD', shell=True).decode().strip() # checked out - n = int(check_output(f'git rev-list {branch}..origin/master --count', shell=True)) # commits behind +def check_git_status(repo='ultralytics/yolov5', branch='master'): + # YOLOv3 status check, recommend 'git pull' if code is out of date + url = f'https://github.com/{repo}' + msg = f', for updates see {url}' + s = colorstr('github: ') # string + assert Path('.git').exists(), s + 'skipping check (not a git repository)' + msg + assert check_online(), s + 'skipping check (offline)' + msg + + splits = re.split(pattern=r'\s', string=check_output('git remote -v', shell=True).decode()) + matches = [repo in s for s in splits] + if any(matches): + remote = splits[matches.index(True) - 1] + else: + remote = 'ultralytics' + check_output(f'git remote add {remote} {url}', shell=True) + check_output(f'git fetch {remote}', shell=True, timeout=5) # git fetch + local_branch = check_output('git rev-parse --abbrev-ref HEAD', shell=True).decode().strip() # checked out + n = int(check_output(f'git rev-list {local_branch}..{remote}/{branch} --count', shell=True)) # commits behind if n > 0: - s = f"⚠️ YOLOv3 is out of date by {n} commit{'s' * (n > 1)}. Use `git pull` or `git clone {url}` to update." + pull = 'git pull' if remote == 'origin' else f'git pull {remote} {branch}' + s += f"⚠️ YOLOv3 is out of date by {n} commit{'s' * (n > 1)}. Use `{pull}` or `git clone {url}` to update." else: - s = f'up to date with {url} ✅' - print(emojis(s)) # emoji-safe + s += f'up to date with {url} ✅' + LOGGER.info(s) -def check_python(minimum='3.6.2'): +@WorkingDirectory(ROOT) +def check_git_info(path='.'): + # YOLOv3 git info check, return {remote, branch, commit} + check_requirements('gitpython') + import git + try: + repo = git.Repo(path) + remote = repo.remotes.origin.url.replace('.git', '') # i.e. 'https://github.com/ultralytics/yolov5' + commit = repo.head.commit.hexsha # i.e. '3134699c73af83aac2a481435550b968d5792c0d' + try: + branch = repo.active_branch.name # i.e. 'main' + except TypeError: # not on any branch + branch = None # i.e. 'detached HEAD' state + return {'remote': remote, 'branch': branch, 'commit': commit} + except git.exc.InvalidGitRepositoryError: # path is not a git dir + return {'remote': None, 'branch': None, 'commit': None} + + +def check_python(minimum='3.7.0'): # Check current python version vs. required python version check_version(platform.python_version(), minimum, name='Python ', hard=True) -def check_version(current='0.0.0', minimum='0.0.0', name='version ', pinned=False, hard=False): +def check_version(current='0.0.0', minimum='0.0.0', name='version ', pinned=False, hard=False, verbose=False): # Check version vs. required version current, minimum = (pkg.parse_version(x) for x in (current, minimum)) result = (current == minimum) if pinned else (current >= minimum) # bool - if hard: # assert min requirements met - assert result, f'{name}{minimum} required by YOLOv3, but {name}{current} is currently installed' - else: - return result + s = f'WARNING ⚠️ {name}{minimum} is required by YOLOv3, but {name}{current} is currently installed' # string + if hard: + assert result, emojis(s) # assert min requirements met + if verbose and not result: + LOGGER.warning(s) + return result -@try_except -def check_requirements(requirements=ROOT / 'requirements.txt', exclude=(), install=True): - # Check installed dependencies meet requirements (pass *.txt file or list of packages) +@TryExcept() +def check_requirements(requirements=ROOT / 'requirements.txt', exclude=(), install=True, cmds=''): + # Check installed dependencies meet YOLOv3 requirements (pass *.txt file or list of packages or single package str) prefix = colorstr('red', 'bold', 'requirements:') check_python() # check python version - if isinstance(requirements, (str, Path)): # requirements.txt file - file = Path(requirements) - assert file.exists(), f"{prefix} {file.resolve()} not found, check failed." + if isinstance(requirements, Path): # requirements.txt file + file = requirements.resolve() + assert file.exists(), f"{prefix} {file} not found, check failed." with file.open() as f: requirements = [f'{x.name}{x.specifier}' for x in pkg.parse_requirements(f) if x.name not in exclude] - else: # list or tuple of packages - requirements = [x for x in requirements if x not in exclude] + elif isinstance(requirements, str): + requirements = [requirements] - n = 0 # number of packages updates + s = '' + n = 0 for r in requirements: try: pkg.require(r) - except Exception as e: # DistributionNotFound or VersionConflict if requirements not met - s = f"{prefix} {r} not found and is required by YOLOv3" - if install: - print(f"{s}, attempting auto-update...") - try: - assert check_online(), f"'pip install {r}' skipped (offline)" - print(check_output(f"pip install '{r}'", shell=True).decode()) - n += 1 - except Exception as e: - print(f'{prefix} {e}') - else: - print(f'{s}. Please install and rerun your command.') + except (pkg.VersionConflict, pkg.DistributionNotFound): # exception if requirements not met + s += f'"{r}" ' + n += 1 - if n: # if packages updated - source = file.resolve() if 'file' in locals() else requirements - s = f"{prefix} {n} package{'s' * (n > 1)} updated per {source}\n" \ - f"{prefix} ⚠️ {colorstr('bold', 'Restart runtime or rerun command for updates to take effect')}\n" - print(emojis(s)) + if s and install and AUTOINSTALL: # check environment variable + LOGGER.info(f"{prefix} YOLOv3 requirement{'s' * (n > 1)} {s}not found, attempting AutoUpdate...") + try: + # assert check_online(), "AutoUpdate skipped (offline)" + LOGGER.info(check_output(f'pip install {s} {cmds}', shell=True).decode()) + source = file if 'file' in locals() else requirements + s = f"{prefix} {n} package{'s' * (n > 1)} updated per {source}\n" \ + f"{prefix} ⚠️ {colorstr('bold', 'Restart runtime or rerun command for updates to take effect')}\n" + LOGGER.info(s) + except Exception as e: + LOGGER.warning(f'{prefix} ❌ {e}') def check_img_size(imgsz, s=32, floor=0): @@ -299,28 +419,30 @@ def check_img_size(imgsz, s=32, floor=0): if isinstance(imgsz, int): # integer i.e. img_size=640 new_size = max(make_divisible(imgsz, int(s)), floor) else: # list i.e. img_size=[640, 480] + imgsz = list(imgsz) # convert to list if tuple new_size = [max(make_divisible(x, int(s)), floor) for x in imgsz] if new_size != imgsz: - print(f'WARNING: --img-size {imgsz} must be multiple of max stride {s}, updating to {new_size}') + LOGGER.warning(f'WARNING ⚠️ --img-size {imgsz} must be multiple of max stride {s}, updating to {new_size}') return new_size -def check_imshow(): +def check_imshow(warn=False): # Check if environment supports image displays try: - assert not is_docker(), 'cv2.imshow() is disabled in Docker environments' - assert not is_colab(), 'cv2.imshow() is disabled in Google Colab environments' + assert not is_notebook() + assert not is_docker() cv2.imshow('test', np.zeros((1, 1, 3))) cv2.waitKey(1) cv2.destroyAllWindows() cv2.waitKey(1) return True except Exception as e: - print(f'WARNING: Environment does not support cv2.imshow() or PIL Image.show() image displays\n{e}') + if warn: + LOGGER.warning(f'WARNING ⚠️ Environment does not support cv2.imshow() or PIL Image.show()\n{e}') return False -def check_suffix(file='yolov3.pt', suffix=('.pt',), msg=''): +def check_suffix(file='yolov5s.pt', suffix=('.pt',), msg=''): # Check file(s) for acceptable suffix if file and suffix: if isinstance(suffix, str): @@ -340,18 +462,21 @@ def check_file(file, suffix=''): # Search/download file (if necessary) and return path check_suffix(file, suffix) # optional file = str(file) # convert to str() - if Path(file).is_file() or file == '': # exists + if os.path.isfile(file) or not file: # exists return file elif file.startswith(('http:/', 'https:/')): # download - url = str(Path(file).as_posix()).replace(':/', '://') # Pathlib turns :// -> :/ + url = file # warning: Pathlib turns :// -> :/ file = Path(urllib.parse.unquote(file).split('?')[0]).name # '%2F' to '/', split https://url.com/file.txt?auth - if Path(file).is_file(): - print(f'Found {url} locally at {file}') # file already exists + if os.path.isfile(file): + LOGGER.info(f'Found {url} locally at {file}') # file already exists else: - print(f'Downloading {url} to {file}...') + LOGGER.info(f'Downloading {url} to {file}...') torch.hub.download_url_to_file(url, file) assert Path(file).exists() and Path(file).stat().st_size > 0, f'File download failed: {url}' # check return file + elif file.startswith('clearml://'): # ClearML Dataset ID + assert 'clearml' in sys.modules, "ClearML is not installed, so cannot use ClearML dataset. Try running 'pip install clearml'." + return file else: # search files = [] for d in 'data', 'models', 'utils': # search directories @@ -361,84 +486,171 @@ def check_file(file, suffix=''): return files[0] # return file +def check_font(font=FONT, progress=False): + # Download font to CONFIG_DIR if necessary + font = Path(font) + file = CONFIG_DIR / font.name + if not font.exists() and not file.exists(): + url = f'https://ultralytics.com/assets/{font.name}' + LOGGER.info(f'Downloading {url} to {file}...') + torch.hub.download_url_to_file(url, str(file), progress=progress) + + def check_dataset(data, autodownload=True): - # Download and/or unzip dataset if not found locally - # Usage: https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128_with_yaml.zip + # Download, check and/or unzip dataset if not found locally # Download (optional) extract_dir = '' - if isinstance(data, (str, Path)) and str(data).endswith('.zip'): # i.e. gs://bucket/dir/coco128.zip - download(data, dir='../datasets', unzip=True, delete=False, curl=False, threads=1) - data = next((Path('../datasets') / Path(data).stem).rglob('*.yaml')) + if isinstance(data, (str, Path)) and (is_zipfile(data) or is_tarfile(data)): + download(data, dir=f'{DATASETS_DIR}/{Path(data).stem}', unzip=True, delete=False, curl=False, threads=1) + data = next((DATASETS_DIR / Path(data).stem).rglob('*.yaml')) extract_dir, autodownload = data.parent, False # Read yaml (optional) if isinstance(data, (str, Path)): - with open(data, errors='ignore') as f: - data = yaml.safe_load(f) # dictionary + data = yaml_load(data) # dictionary - # Parse yaml - path = extract_dir or Path(data.get('path') or '') # optional 'path' default to '.' + # Checks + for k in 'train', 'val', 'names': + assert k in data, emojis(f"data.yaml '{k}:' field missing ❌") + if isinstance(data['names'], (list, tuple)): # old array format + data['names'] = dict(enumerate(data['names'])) # convert to dict + assert all(isinstance(k, int) for k in data['names'].keys()), 'data.yaml names keys must be integers, i.e. 2: car' + data['nc'] = len(data['names']) + + # Resolve paths + path = Path(extract_dir or data.get('path') or '') # optional 'path' default to '.' + if not path.is_absolute(): + path = (ROOT / path).resolve() + data['path'] = path # download scripts for k in 'train', 'val', 'test': if data.get(k): # prepend path - data[k] = str(path / data[k]) if isinstance(data[k], str) else [str(path / x) for x in data[k]] + if isinstance(data[k], str): + x = (path / data[k]).resolve() + if not x.exists() and data[k].startswith('../'): + x = (path / data[k][3:]).resolve() + data[k] = str(x) + else: + data[k] = [str((path / x).resolve()) for x in data[k]] - assert 'nc' in data, "Dataset 'nc' key missing." - if 'names' not in data: - data['names'] = [f'class{i}' for i in range(data['nc'])] # assign class names if missing + # Parse yaml train, val, test, s = (data.get(x) for x in ('train', 'val', 'test', 'download')) if val: val = [Path(x).resolve() for x in (val if isinstance(val, list) else [val])] # val path if not all(x.exists() for x in val): - print('\nWARNING: Dataset not found, nonexistent paths: %s' % [str(x) for x in val if not x.exists()]) - if s and autodownload: # download script - root = path.parent if 'path' in data else '..' # unzip directory i.e. '../' - if s.startswith('http') and s.endswith('.zip'): # URL - f = Path(s).name # filename - print(f'Downloading {s} to {f}...') - torch.hub.download_url_to_file(s, f) - Path(root).mkdir(parents=True, exist_ok=True) # create root - ZipFile(f).extractall(path=root) # unzip - Path(f).unlink() # remove zip - r = None # success - elif s.startswith('bash '): # bash script - print(f'Running {s} ...') - r = os.system(s) - else: # python script - r = exec(s, {'yaml': data}) # return None - print(f"Dataset autodownload {f'success, saved to {root}' if r in (0, None) else 'failure'}\n") - else: - raise Exception('Dataset not found.') - + LOGGER.info('\nDataset not found ⚠️, missing paths %s' % [str(x) for x in val if not x.exists()]) + if not s or not autodownload: + raise Exception('Dataset not found ❌') + t = time.time() + if s.startswith('http') and s.endswith('.zip'): # URL + f = Path(s).name # filename + LOGGER.info(f'Downloading {s} to {f}...') + torch.hub.download_url_to_file(s, f) + Path(DATASETS_DIR).mkdir(parents=True, exist_ok=True) # create root + unzip_file(f, path=DATASETS_DIR) # unzip + Path(f).unlink() # remove zip + r = None # success + elif s.startswith('bash '): # bash script + LOGGER.info(f'Running {s} ...') + r = subprocess.run(s, shell=True) + else: # python script + r = exec(s, {'yaml': data}) # return None + dt = f'({round(time.time() - t, 1)}s)' + s = f"success ✅ {dt}, saved to {colorstr('bold', DATASETS_DIR)}" if r in (0, None) else f"failure {dt} ❌" + LOGGER.info(f"Dataset download {s}") + check_font('Arial.ttf' if is_ascii(data['names']) else 'Arial.Unicode.ttf', progress=True) # download fonts return data # dictionary +def check_amp(model): + # Check PyTorch Automatic Mixed Precision (AMP) functionality. Return True on correct operation + from models.common import AutoShape, DetectMultiBackend + + def amp_allclose(model, im): + # All close FP32 vs AMP results + m = AutoShape(model, verbose=False) # model + a = m(im).xywhn[0] # FP32 inference + m.amp = True + b = m(im).xywhn[0] # AMP inference + return a.shape == b.shape and torch.allclose(a, b, atol=0.1) # close to 10% absolute tolerance + + prefix = colorstr('AMP: ') + device = next(model.parameters()).device # get model device + if device.type in ('cpu', 'mps'): + return False # AMP only used on CUDA devices + f = ROOT / 'data' / 'images' / 'bus.jpg' # image to check + im = f if f.exists() else 'https://ultralytics.com/images/bus.jpg' if check_online() else np.ones((640, 640, 3)) + try: + assert amp_allclose(deepcopy(model), im) or amp_allclose(DetectMultiBackend('yolov5n.pt', device), im) + LOGGER.info(f'{prefix}checks passed ✅') + return True + except Exception: + help_url = 'https://github.com/ultralytics/yolov5/issues/7908' + LOGGER.warning(f'{prefix}checks failed ❌, disabling Automatic Mixed Precision. See {help_url}') + return False + + +def yaml_load(file='data.yaml'): + # Single-line safe yaml loading + with open(file, errors='ignore') as f: + return yaml.safe_load(f) + + +def yaml_save(file='data.yaml', data={}): + # Single-line safe yaml saving + with open(file, 'w') as f: + yaml.safe_dump({k: str(v) if isinstance(v, Path) else v for k, v in data.items()}, f, sort_keys=False) + + +def unzip_file(file, path=None, exclude=('.DS_Store', '__MACOSX')): + # Unzip a *.zip file to path/, excluding files containing strings in exclude list + if path is None: + path = Path(file).parent # default path + with ZipFile(file) as zipObj: + for f in zipObj.namelist(): # list all archived filenames in the zip + if all(x not in f for x in exclude): + zipObj.extract(f, path=path) + + def url2file(url): # Convert URL to filename, i.e. https://url.com/file.txt?auth -> file.txt url = str(Path(url)).replace(':/', '://') # Pathlib turns :// -> :/ - file = Path(urllib.parse.unquote(url)).name.split('?')[0] # '%2F' to '/', split https://url.com/file.txt?auth - return file + return Path(urllib.parse.unquote(url)).name.split('?')[0] # '%2F' to '/', split https://url.com/file.txt?auth -def download(url, dir='.', unzip=True, delete=True, curl=False, threads=1): - # Multi-threaded file download and unzip function, used in data.yaml for autodownload +def download(url, dir='.', unzip=True, delete=True, curl=False, threads=1, retry=3): + # Multithreaded file download and unzip function, used in data.yaml for autodownload def download_one(url, dir): # Download 1 file - f = dir / Path(url).name # filename - if Path(url).is_file(): # exists in current path - Path(url).rename(f) # move to dir - elif not f.exists(): - print(f'Downloading {url} to {f}...') - if curl: - os.system(f"curl -L '{url}' -o '{f}' --retry 9 -C -") # curl download, retry and resume on fail - else: - torch.hub.download_url_to_file(url, f, progress=True) # torch download - if unzip and f.suffix in ('.zip', '.gz'): - print(f'Unzipping {f}...') - if f.suffix == '.zip': - ZipFile(f).extractall(path=dir) # unzip + success = True + if os.path.isfile(url): + f = Path(url) # filename + else: # does not exist + f = dir / Path(url).name + LOGGER.info(f'Downloading {url} to {f}...') + for i in range(retry + 1): + if curl: + s = 'sS' if threads > 1 else '' # silent + r = subprocess.run(f'curl -# -{s}L "{url}" -o "{f}" --retry 9 -C -'.split()) + success = r == 0 + else: + torch.hub.download_url_to_file(url, f, progress=threads == 1) # torch download + success = f.is_file() + if success: + break + elif i < retry: + LOGGER.warning(f'⚠️ Download failure, retrying {i + 1}/{retry} {url}...') + else: + LOGGER.warning(f'❌ Failed to download {url}...') + + if unzip and success and (f.suffix == '.gz' or is_zipfile(f) or is_tarfile(f)): + LOGGER.info(f'Unzipping {f}...') + if is_zipfile(f): + unzip_file(f, dir) # unzip + elif is_tarfile(f): + subprocess.run(['tar', 'xf', f, '--directory', f.parent], check=True) # unzip elif f.suffix == '.gz': - os.system(f'tar xfz {f} --directory {f.parent}') # unzip + subprocess.run(['tar', 'xfz', f, '--directory', f.parent], check=True) # unzip if delete: f.unlink() # remove zip @@ -446,7 +658,7 @@ def download_one(url, dir): dir.mkdir(parents=True, exist_ok=True) # make directory if threads > 1: pool = ThreadPool(threads) - pool.imap(lambda x: download_one(*x), zip(url, repeat(dir))) # multi-threaded + pool.imap(lambda x: download_one(*x), zip(url, repeat(dir))) # multithreaded pool.close() pool.join() else: @@ -455,7 +667,9 @@ def download_one(url, dir): def make_divisible(x, divisor): - # Returns x evenly divisible by divisor + # Returns nearest x divisible by divisor + if isinstance(divisor, torch.Tensor): + divisor = int(divisor.max()) # to int return math.ceil(x / divisor) * divisor @@ -472,25 +686,26 @@ def one_cycle(y1=0.0, y2=1.0, steps=100): def colorstr(*input): # Colors a string https://en.wikipedia.org/wiki/ANSI_escape_code, i.e. colorstr('blue', 'hello world') *args, string = input if len(input) > 1 else ('blue', 'bold', input[0]) # color arguments, string - colors = {'black': '\033[30m', # basic colors - 'red': '\033[31m', - 'green': '\033[32m', - 'yellow': '\033[33m', - 'blue': '\033[34m', - 'magenta': '\033[35m', - 'cyan': '\033[36m', - 'white': '\033[37m', - 'bright_black': '\033[90m', # bright colors - 'bright_red': '\033[91m', - 'bright_green': '\033[92m', - 'bright_yellow': '\033[93m', - 'bright_blue': '\033[94m', - 'bright_magenta': '\033[95m', - 'bright_cyan': '\033[96m', - 'bright_white': '\033[97m', - 'end': '\033[0m', # misc - 'bold': '\033[1m', - 'underline': '\033[4m'} + colors = { + 'black': '\033[30m', # basic colors + 'red': '\033[31m', + 'green': '\033[32m', + 'yellow': '\033[33m', + 'blue': '\033[34m', + 'magenta': '\033[35m', + 'cyan': '\033[36m', + 'white': '\033[37m', + 'bright_black': '\033[90m', # bright colors + 'bright_red': '\033[91m', + 'bright_green': '\033[92m', + 'bright_yellow': '\033[93m', + 'bright_blue': '\033[94m', + 'bright_magenta': '\033[95m', + 'bright_cyan': '\033[96m', + 'bright_white': '\033[97m', + 'end': '\033[0m', # misc + 'bold': '\033[1m', + 'underline': '\033[4m'} return ''.join(colors[x] for x in args) + f'{string}' + colors['end'] @@ -500,7 +715,7 @@ def labels_to_class_weights(labels, nc=80): return torch.Tensor() labels = np.concatenate(labels, 0) # labels.shape = (866643, 5) for COCO - classes = labels[:, 0].astype(np.int) # labels = [class xywh] + classes = labels[:, 0].astype(int) # labels = [class xywh] weights = np.bincount(classes, minlength=nc) # occurrences per class # Prepend gridpoint count (for uCE training) @@ -510,15 +725,14 @@ def labels_to_class_weights(labels, nc=80): weights[weights == 0] = 1 # replace empty bins with 1 weights = 1 / weights # number of targets per class weights /= weights.sum() # normalize - return torch.from_numpy(weights) + return torch.from_numpy(weights).float() def labels_to_image_weights(labels, nc=80, class_weights=np.ones(80)): # Produces image weights based on class_weights and image contents - class_counts = np.array([np.bincount(x[:, 0].astype(np.int), minlength=nc) for x in labels]) - image_weights = (class_weights.reshape(1, nc) * class_counts).sum(1) - # index = random.choices(range(n), weights=image_weights, k=1) # weight image sample - return image_weights + # Usage: index = random.choices(range(n), weights=image_weights, k=1) # weighted image sample + class_counts = np.array([np.bincount(x[:, 0].astype(int), minlength=nc) for x in labels]) + return (class_weights.reshape(1, nc) * class_counts).sum(1) def coco80_to_coco91_class(): # converts 80-index (val2014) to 91-index (paper) @@ -527,59 +741,59 @@ def coco80_to_coco91_class(): # converts 80-index (val2014) to 91-index (paper) # b = np.loadtxt('data/coco_paper.names', dtype='str', delimiter='\n') # x1 = [list(a[i] == b).index(True) + 1 for i in range(80)] # darknet to coco # x2 = [list(b[i] == a).index(True) if any(b[i] == a) else None for i in range(91)] # coco to darknet - x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 67, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] - return x + return [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 67, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] def xyxy2xywh(x): # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] where xy1=top-left, xy2=bottom-right y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) - y[:, 0] = (x[:, 0] + x[:, 2]) / 2 # x center - y[:, 1] = (x[:, 1] + x[:, 3]) / 2 # y center - y[:, 2] = x[:, 2] - x[:, 0] # width - y[:, 3] = x[:, 3] - x[:, 1] # height + y[..., 0] = (x[..., 0] + x[..., 2]) / 2 # x center + y[..., 1] = (x[..., 1] + x[..., 3]) / 2 # y center + y[..., 2] = x[..., 2] - x[..., 0] # width + y[..., 3] = x[..., 3] - x[..., 1] # height return y def xywh2xyxy(x): # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) - y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x - y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y - y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x - y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y + y[..., 0] = x[..., 0] - x[..., 2] / 2 # top left x + y[..., 1] = x[..., 1] - x[..., 3] / 2 # top left y + y[..., 2] = x[..., 0] + x[..., 2] / 2 # bottom right x + y[..., 3] = x[..., 1] + x[..., 3] / 2 # bottom right y return y def xywhn2xyxy(x, w=640, h=640, padw=0, padh=0): # Convert nx4 boxes from [x, y, w, h] normalized to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) - y[:, 0] = w * (x[:, 0] - x[:, 2] / 2) + padw # top left x - y[:, 1] = h * (x[:, 1] - x[:, 3] / 2) + padh # top left y - y[:, 2] = w * (x[:, 0] + x[:, 2] / 2) + padw # bottom right x - y[:, 3] = h * (x[:, 1] + x[:, 3] / 2) + padh # bottom right y + y[..., 0] = w * (x[..., 0] - x[..., 2] / 2) + padw # top left x + y[..., 1] = h * (x[..., 1] - x[..., 3] / 2) + padh # top left y + y[..., 2] = w * (x[..., 0] + x[..., 2] / 2) + padw # bottom right x + y[..., 3] = h * (x[..., 1] + x[..., 3] / 2) + padh # bottom right y return y def xyxy2xywhn(x, w=640, h=640, clip=False, eps=0.0): # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] normalized where xy1=top-left, xy2=bottom-right if clip: - clip_coords(x, (h - eps, w - eps)) # warning: inplace clip + clip_boxes(x, (h - eps, w - eps)) # warning: inplace clip y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) - y[:, 0] = ((x[:, 0] + x[:, 2]) / 2) / w # x center - y[:, 1] = ((x[:, 1] + x[:, 3]) / 2) / h # y center - y[:, 2] = (x[:, 2] - x[:, 0]) / w # width - y[:, 3] = (x[:, 3] - x[:, 1]) / h # height + y[..., 0] = ((x[..., 0] + x[..., 2]) / 2) / w # x center + y[..., 1] = ((x[..., 1] + x[..., 3]) / 2) / h # y center + y[..., 2] = (x[..., 2] - x[..., 0]) / w # width + y[..., 3] = (x[..., 3] - x[..., 1]) / h # height return y def xyn2xy(x, w=640, h=640, padw=0, padh=0): # Convert normalized segments into pixel segments, shape (n,2) y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) - y[:, 0] = w * x[:, 0] + padw # top left x - y[:, 1] = h * x[:, 1] + padh # top left y + y[..., 0] = w * x[..., 0] + padw # top left x + y[..., 1] = h * x[..., 1] + padh # top left y return y @@ -603,13 +817,30 @@ def segments2boxes(segments): def resample_segments(segments, n=1000): # Up-sample an (n,2) segment for i, s in enumerate(segments): + s = np.concatenate((s, s[0:1, :]), axis=0) x = np.linspace(0, len(s) - 1, n) xp = np.arange(len(s)) segments[i] = np.concatenate([np.interp(x, xp, s[:, i]) for i in range(2)]).reshape(2, -1).T # segment xy return segments -def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None): +def scale_boxes(img1_shape, boxes, img0_shape, ratio_pad=None): + # Rescale boxes (xyxy) from img1_shape to img0_shape + if ratio_pad is None: # calculate from img0_shape + gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new + pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding + else: + gain = ratio_pad[0][0] + pad = ratio_pad[1] + + boxes[..., [0, 2]] -= pad[0] # x padding + boxes[..., [1, 3]] -= pad[1] # y padding + boxes[..., :4] /= gain + clip_boxes(boxes, img0_shape) + return boxes + + +def scale_segments(img1_shape, segments, img0_shape, ratio_pad=None, normalize=False): # Rescale coords (xyxy) from img1_shape to img0_shape if ratio_pad is None: # calculate from img0_shape gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new @@ -618,50 +849,81 @@ def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None): gain = ratio_pad[0][0] pad = ratio_pad[1] - coords[:, [0, 2]] -= pad[0] # x padding - coords[:, [1, 3]] -= pad[1] # y padding - coords[:, :4] /= gain - clip_coords(coords, img0_shape) - return coords + segments[:, 0] -= pad[0] # x padding + segments[:, 1] -= pad[1] # y padding + segments /= gain + clip_segments(segments, img0_shape) + if normalize: + segments[:, 0] /= img0_shape[1] # width + segments[:, 1] /= img0_shape[0] # height + return segments -def clip_coords(boxes, shape): - # Clip bounding xyxy bounding boxes to image shape (height, width) +def clip_boxes(boxes, shape): + # Clip boxes (xyxy) to image shape (height, width) if isinstance(boxes, torch.Tensor): # faster individually - boxes[:, 0].clamp_(0, shape[1]) # x1 - boxes[:, 1].clamp_(0, shape[0]) # y1 - boxes[:, 2].clamp_(0, shape[1]) # x2 - boxes[:, 3].clamp_(0, shape[0]) # y2 + boxes[..., 0].clamp_(0, shape[1]) # x1 + boxes[..., 1].clamp_(0, shape[0]) # y1 + boxes[..., 2].clamp_(0, shape[1]) # x2 + boxes[..., 3].clamp_(0, shape[0]) # y2 else: # np.array (faster grouped) - boxes[:, [0, 2]] = boxes[:, [0, 2]].clip(0, shape[1]) # x1, x2 - boxes[:, [1, 3]] = boxes[:, [1, 3]].clip(0, shape[0]) # y1, y2 + boxes[..., [0, 2]] = boxes[..., [0, 2]].clip(0, shape[1]) # x1, x2 + boxes[..., [1, 3]] = boxes[..., [1, 3]].clip(0, shape[0]) # y1, y2 -def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False, multi_label=False, - labels=(), max_det=300): - """Runs Non-Maximum Suppression (NMS) on inference results +def clip_segments(segments, shape): + # Clip segments (xy1,xy2,...) to image shape (height, width) + if isinstance(segments, torch.Tensor): # faster individually + segments[:, 0].clamp_(0, shape[1]) # x + segments[:, 1].clamp_(0, shape[0]) # y + else: # np.array (faster grouped) + segments[:, 0] = segments[:, 0].clip(0, shape[1]) # x + segments[:, 1] = segments[:, 1].clip(0, shape[0]) # y + + +def non_max_suppression( + prediction, + conf_thres=0.25, + iou_thres=0.45, + classes=None, + agnostic=False, + multi_label=False, + labels=(), + max_det=300, + nm=0, # number of masks +): + """Non-Maximum Suppression (NMS) on inference results to reject overlapping detections Returns: list of detections, on (n,6) tensor per image [xyxy, conf, cls] """ - nc = prediction.shape[2] - 5 # number of classes - xc = prediction[..., 4] > conf_thres # candidates - # Checks assert 0 <= conf_thres <= 1, f'Invalid Confidence threshold {conf_thres}, valid values are between 0.0 and 1.0' assert 0 <= iou_thres <= 1, f'Invalid IoU {iou_thres}, valid values are between 0.0 and 1.0' + if isinstance(prediction, (list, tuple)): # YOLOv3 model in validation model, output = (inference_out, loss_out) + prediction = prediction[0] # select only inference output + + device = prediction.device + mps = 'mps' in device.type # Apple MPS + if mps: # MPS not fully supported yet, convert tensors to CPU before NMS + prediction = prediction.cpu() + bs = prediction.shape[0] # batch size + nc = prediction.shape[2] - nm - 5 # number of classes + xc = prediction[..., 4] > conf_thres # candidates # Settings - min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height + # min_wh = 2 # (pixels) minimum box width and height + max_wh = 7680 # (pixels) maximum box width and height max_nms = 30000 # maximum number of boxes into torchvision.ops.nms() - time_limit = 10.0 # seconds to quit after + time_limit = 0.5 + 0.05 * bs # seconds to quit after redundant = True # require redundant detections multi_label &= nc > 1 # multiple labels per box (adds 0.5ms/img) merge = False # use merge-NMS t = time.time() - output = [torch.zeros((0, 6), device=prediction.device)] * prediction.shape[0] + mi = 5 + nc # mask start index + output = [torch.zeros((0, 6 + nm), device=prediction.device)] * bs for xi, x in enumerate(prediction): # image index, image inference # Apply constraints # x[((x[..., 2:4] < min_wh) | (x[..., 2:4] > max_wh)).any(1), 4] = 0 # width-height @@ -669,11 +931,11 @@ def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=Non # Cat apriori labels if autolabelling if labels and len(labels[xi]): - l = labels[xi] - v = torch.zeros((len(l), nc + 5), device=x.device) - v[:, :4] = l[:, 1:5] # box + lb = labels[xi] + v = torch.zeros((len(lb), nc + nm + 5), device=x.device) + v[:, :4] = lb[:, 1:5] # box v[:, 4] = 1.0 # conf - v[range(len(l)), l[:, 0].long() + 5] = 1.0 # cls + v[range(len(lb)), lb[:, 0].long() + 5] = 1.0 # cls x = torch.cat((x, v), 0) # If none remain process next image @@ -683,16 +945,17 @@ def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=Non # Compute conf x[:, 5:] *= x[:, 4:5] # conf = obj_conf * cls_conf - # Box (center x, center y, width, height) to (x1, y1, x2, y2) - box = xywh2xyxy(x[:, :4]) + # Box/Mask + box = xywh2xyxy(x[:, :4]) # center_x, center_y, width, height) to (x1, y1, x2, y2) + mask = x[:, mi:] # zero columns if no masks # Detections matrix nx6 (xyxy, conf, cls) if multi_label: - i, j = (x[:, 5:] > conf_thres).nonzero(as_tuple=False).T - x = torch.cat((box[i], x[i, j + 5, None], j[:, None].float()), 1) + i, j = (x[:, 5:mi] > conf_thres).nonzero(as_tuple=False).T + x = torch.cat((box[i], x[i, 5 + j, None], j[:, None].float(), mask[i]), 1) else: # best class only - conf, j = x[:, 5:].max(1, keepdim=True) - x = torch.cat((box, conf, j.float()), 1)[conf.view(-1) > conf_thres] + conf, j = x[:, 5:mi].max(1, keepdim=True) + x = torch.cat((box, conf, j.float(), mask), 1)[conf.view(-1) > conf_thres] # Filter by class if classes is not None: @@ -706,15 +969,13 @@ def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=Non n = x.shape[0] # number of boxes if not n: # no boxes continue - elif n > max_nms: # excess boxes - x = x[x[:, 4].argsort(descending=True)[:max_nms]] # sort by confidence + x = x[x[:, 4].argsort(descending=True)[:max_nms]] # sort by confidence and remove excess boxes # Batched NMS c = x[:, 5:6] * (0 if agnostic else max_wh) # classes boxes, scores = x[:, :4] + c, x[:, 4] # boxes (offset by class), scores i = torchvision.ops.nms(boxes, scores, iou_thres) # NMS - if i.shape[0] > max_det: # limit detections - i = i[:max_det] + i = i[:max_det] # limit detections if merge and (1 < n < 3E3): # Merge NMS (boxes merged using weighted mean) # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) iou = box_iou(boxes[i], boxes) > iou_thres # iou matrix @@ -724,8 +985,10 @@ def non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=Non i = i[iou.sum(1) > 1] # require redundancy output[xi] = x[i] + if mps: + output[xi] = output[xi].to(device) if (time.time() - t) > time_limit: - print(f'WARNING: NMS time limit {time_limit}s exceeded') + LOGGER.warning(f'WARNING ⚠️ NMS time limit {time_limit:.3f}s exceeded') break # time limit exceeded return output @@ -736,7 +999,7 @@ def strip_optimizer(f='best.pt', s=''): # from utils.general import *; strip_op x = torch.load(f, map_location=torch.device('cpu')) if x.get('ema'): x['model'] = x['ema'] # replace model with ema - for k in 'optimizer', 'training_results', 'wandb_id', 'ema', 'updates': # keys + for k in 'optimizer', 'best_fitness', 'ema', 'updates': # keys x[k] = None x['epoch'] = -1 x['model'].half() # to FP16 @@ -744,13 +1007,13 @@ def strip_optimizer(f='best.pt', s=''): # from utils.general import *; strip_op p.requires_grad = False torch.save(x, s or f) mb = os.path.getsize(s or f) / 1E6 # filesize - print(f"Optimizer stripped from {f},{(' saved as %s,' % s) if s else ''} {mb:.1f}MB") + LOGGER.info(f"Optimizer stripped from {f},{f' saved as {s},' if s else ''} {mb:.1f}MB") -def print_mutation(results, hyp, save_dir, bucket): - evolve_csv, results_csv, evolve_yaml = save_dir / 'evolve.csv', save_dir / 'results.csv', save_dir / 'hyp_evolve.yaml' - keys = ('metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', - 'val/box_loss', 'val/obj_loss', 'val/cls_loss') + tuple(hyp.keys()) # [results + hyps] +def print_mutation(keys, results, hyp, save_dir, bucket, prefix=colorstr('evolve: ')): + evolve_csv = save_dir / 'evolve.csv' + evolve_yaml = save_dir / 'hyp_evolve.yaml' + keys = tuple(keys) + tuple(hyp.keys()) # [results + hyps] keys = tuple(x.strip() for x in keys) vals = results + tuple(hyp.values()) n = len(keys) @@ -758,32 +1021,32 @@ def print_mutation(results, hyp, save_dir, bucket): # Download (optional) if bucket: url = f'gs://{bucket}/evolve.csv' - if gsutil_getsize(url) > (os.path.getsize(evolve_csv) if os.path.exists(evolve_csv) else 0): - os.system(f'gsutil cp {url} {save_dir}') # download evolve.csv if larger than local + if gsutil_getsize(url) > (evolve_csv.stat().st_size if evolve_csv.exists() else 0): + subprocess.run(['gsutil', 'cp', f'{url}', f'{save_dir}']) # download evolve.csv if larger than local # Log to evolve.csv s = '' if evolve_csv.exists() else (('%20s,' * n % keys).rstrip(',') + '\n') # add header with open(evolve_csv, 'a') as f: f.write(s + ('%20.5g,' * n % vals).rstrip(',') + '\n') - # Print to screen - print(colorstr('evolve: ') + ', '.join(f'{x.strip():>20s}' for x in keys)) - print(colorstr('evolve: ') + ', '.join(f'{x:20.5g}' for x in vals), end='\n\n\n') - # Save yaml with open(evolve_yaml, 'w') as f: - data = pd.read_csv(evolve_csv) + data = pd.read_csv(evolve_csv, skipinitialspace=True) data = data.rename(columns=lambda x: x.strip()) # strip keys - i = np.argmax(fitness(data.values[:, :7])) # - f.write('# YOLOv3 Hyperparameter Evolution Results\n' + - f'# Best generation: {i}\n' + - f'# Last generation: {len(data)}\n' + - '# ' + ', '.join(f'{x.strip():>20s}' for x in keys[:7]) + '\n' + - '# ' + ', '.join(f'{x:>20.5g}' for x in data.values[i, :7]) + '\n\n') - yaml.safe_dump(hyp, f, sort_keys=False) + i = np.argmax(fitness(data.values[:, :4])) # + generations = len(data) + f.write('# YOLOv3 Hyperparameter Evolution Results\n' + f'# Best generation: {i}\n' + + f'# Last generation: {generations - 1}\n' + '# ' + ', '.join(f'{x.strip():>20s}' for x in keys[:7]) + + '\n' + '# ' + ', '.join(f'{x:>20.5g}' for x in data.values[i, :7]) + '\n\n') + yaml.safe_dump(data.loc[i][7:].to_dict(), f, sort_keys=False) + + # Print to screen + LOGGER.info(prefix + f'{generations} generations finished, current result:\n' + prefix + + ', '.join(f'{x.strip():>20s}' for x in keys) + '\n' + prefix + ', '.join(f'{x:20.5g}' + for x in vals) + '\n\n') if bucket: - os.system(f'gsutil cp {evolve_csv} {evolve_yaml} gs://{bucket}') # upload + subprocess.run(['gsutil', 'cp', f'{evolve_csv}', f'{evolve_yaml}', f'gs://{bucket}']) # upload def apply_classifier(x, model, img, im0): @@ -801,15 +1064,14 @@ def apply_classifier(x, model, img, im0): d[:, :4] = xywh2xyxy(b).long() # Rescale boxes from img_size to im0 size - scale_coords(img.shape[2:], d[:, :4], im0[i].shape) + scale_boxes(img.shape[2:], d[:, :4], im0[i].shape) # Classes pred_cls1 = d[:, 5].long() ims = [] - for j, a in enumerate(d): # per item + for a in d: cutout = im0[i][int(a[1]):int(a[3]), int(a[0]):int(a[2])] im = cv2.resize(cutout, (224, 224)) # BGR - # cv2.imwrite('example%i.jpg' % j, cutout) im = im[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 im = np.ascontiguousarray(im, dtype=np.float32) # uint8 to float32 @@ -827,15 +1089,47 @@ def increment_path(path, exist_ok=False, sep='', mkdir=False): path = Path(path) # os-agnostic if path.exists() and not exist_ok: path, suffix = (path.with_suffix(''), path.suffix) if path.is_file() else (path, '') - dirs = glob.glob(f"{path}{sep}*") # similar paths - matches = [re.search(rf"%s{sep}(\d+)" % path.stem, d) for d in dirs] - i = [int(m.groups()[0]) for m in matches if m] # indices - n = max(i) + 1 if i else 2 # increment number - path = Path(f"{path}{sep}{n}{suffix}") # increment path + + # Method 1 + for n in range(2, 9999): + p = f'{path}{sep}{n}{suffix}' # increment path + if not os.path.exists(p): # + break + path = Path(p) + + # Method 2 (deprecated) + # dirs = glob.glob(f"{path}{sep}*") # similar paths + # matches = [re.search(rf"{path.stem}{sep}(\d+)", d) for d in dirs] + # i = [int(m.groups()[0]) for m in matches if m] # indices + # n = max(i) + 1 if i else 2 # increment number + # path = Path(f"{path}{sep}{n}{suffix}") # increment path + if mkdir: path.mkdir(parents=True, exist_ok=True) # make directory + return path -# Variables -NCOLS = 0 if is_docker() else shutil.get_terminal_size().columns # terminal window size +# OpenCV Multilanguage-friendly functions ------------------------------------------------------------------------------------ +imshow_ = cv2.imshow # copy to avoid recursion errors + + +def imread(path, flags=cv2.IMREAD_COLOR): + return cv2.imdecode(np.fromfile(path, np.uint8), flags) + + +def imwrite(path, im): + try: + cv2.imencode(Path(path).suffix, im)[1].tofile(path) + return True + except Exception: + return False + + +def imshow(path, im): + imshow_(path.encode('unicode_escape').decode(), im) + + +cv2.imread, cv2.imwrite, cv2.imshow = imread, imwrite, imshow # redefine + +# Variables ------------------------------------------------------------------------------------------------------------ diff --git a/utils/google_app_engine/Dockerfile b/utils/google_app_engine/Dockerfile new file mode 100644 index 0000000000..0155618f47 --- /dev/null +++ b/utils/google_app_engine/Dockerfile @@ -0,0 +1,25 @@ +FROM gcr.io/google-appengine/python + +# Create a virtualenv for dependencies. This isolates these packages from +# system-level packages. +# Use -p python3 or -p python3.7 to select python version. Default is version 2. +RUN virtualenv /env -p python3 + +# Setting these environment variables are the same as running +# source /env/bin/activate. +ENV VIRTUAL_ENV /env +ENV PATH /env/bin:$PATH + +RUN apt-get update && apt-get install -y python-opencv + +# Copy the application's requirements.txt and run pip to install all +# dependencies into the virtualenv. +ADD requirements.txt /app/requirements.txt +RUN pip install -r /app/requirements.txt + +# Add the application source code. +ADD . /app + +# Run a WSGI server to serve the application. gunicorn must be declared as +# a dependency in requirements.txt. +CMD gunicorn -b :$PORT main:app diff --git a/utils/google_app_engine/additional_requirements.txt b/utils/google_app_engine/additional_requirements.txt new file mode 100644 index 0000000000..b6b496feaa --- /dev/null +++ b/utils/google_app_engine/additional_requirements.txt @@ -0,0 +1,4 @@ +# add these requirements in your app on top of the existing ones +pip==21.1 +Flask==1.0.2 +gunicorn==19.10.0 diff --git a/utils/google_app_engine/app.yaml b/utils/google_app_engine/app.yaml new file mode 100644 index 0000000000..5056b7c118 --- /dev/null +++ b/utils/google_app_engine/app.yaml @@ -0,0 +1,14 @@ +runtime: custom +env: flex + +service: yolov5app + +liveness_check: + initial_delay_sec: 600 + +manual_scaling: + instances: 1 +resources: + cpu: 1 + memory_gb: 4 + disk_size_gb: 20 diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index a234ce2cf0..a9a64f0f11 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -5,25 +5,26 @@ import os import warnings -from threading import Thread +from pathlib import Path import pkg_resources as pkg import torch from torch.utils.tensorboard import SummaryWriter -from utils.general import colorstr, emojis +from utils.general import LOGGER, colorstr, cv2 +from utils.loggers.clearml.clearml_utils import ClearmlLogger from utils.loggers.wandb.wandb_utils import WandbLogger -from utils.plots import plot_images, plot_results +from utils.plots import plot_images, plot_labels, plot_results from utils.torch_utils import de_parallel -LOGGERS = ('csv', 'tb', 'wandb') # text-file, TensorBoard, Weights & Biases +LOGGERS = ('csv', 'tb', 'wandb', 'clearml', 'comet') # *.csv, TensorBoard, Weights & Biases, ClearML RANK = int(os.getenv('RANK', -1)) try: import wandb assert hasattr(wandb, '__version__') # verify package import not local dir - if pkg.parse_version(wandb.__version__) >= pkg.parse_version('0.12.2') and RANK in [0, -1]: + if pkg.parse_version(wandb.__version__) >= pkg.parse_version('0.12.2') and RANK in {0, -1}: try: wandb_login_success = wandb.login(timeout=30) except wandb.errors.UsageError: # known non-TTY terminal issue @@ -33,30 +34,64 @@ except (ImportError, AssertionError): wandb = None +try: + import clearml + + assert hasattr(clearml, '__version__') # verify package import not local dir +except (ImportError, AssertionError): + clearml = None + +try: + if RANK not in [0, -1]: + comet_ml = None + else: + import comet_ml + + assert hasattr(comet_ml, '__version__') # verify package import not local dir + from utils.loggers.comet import CometLogger + +except (ModuleNotFoundError, ImportError, AssertionError): + comet_ml = None + class Loggers(): - # Loggers class + # YOLOv3 Loggers class def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, include=LOGGERS): self.save_dir = save_dir self.weights = weights self.opt = opt self.hyp = hyp + self.plots = not opt.noplots # plot results self.logger = logger # for printing results to console self.include = include - self.keys = ['train/box_loss', 'train/obj_loss', 'train/cls_loss', # train loss - 'metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', # metrics - 'val/box_loss', 'val/obj_loss', 'val/cls_loss', # val loss - 'x/lr0', 'x/lr1', 'x/lr2'] # params + self.keys = [ + 'train/box_loss', + 'train/obj_loss', + 'train/cls_loss', # train loss + 'metrics/precision', + 'metrics/recall', + 'metrics/mAP_0.5', + 'metrics/mAP_0.5:0.95', # metrics + 'val/box_loss', + 'val/obj_loss', + 'val/cls_loss', # val loss + 'x/lr0', + 'x/lr1', + 'x/lr2'] # params + self.best_keys = ['best/epoch', 'best/precision', 'best/recall', 'best/mAP_0.5', 'best/mAP_0.5:0.95'] for k in LOGGERS: setattr(self, k, None) # init empty logger dictionary self.csv = True # always log to csv - # Message - if not wandb: - prefix = colorstr('Weights & Biases: ') - s = f"{prefix}run 'pip install wandb' to automatically track and visualize YOLOv3 🚀 runs (RECOMMENDED)" - print(emojis(s)) - + # Messages + if not clearml: + prefix = colorstr('ClearML: ') + s = f"{prefix}run 'pip install clearml' to automatically track, visualize and remotely train YOLOv3 🚀 in ClearML" + self.logger.info(s) + if not comet_ml: + prefix = colorstr('Comet: ') + s = f"{prefix}run 'pip install comet_ml' to automatically track and visualize YOLOv3 🚀 runs in Comet" + self.logger.info(s) # TensorBoard s = self.save_dir if 'tb' in self.include and not self.opt.evolve: @@ -66,53 +101,127 @@ def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, # W&B if wandb and 'wandb' in self.include: - wandb_artifact_resume = isinstance(self.opt.resume, str) and self.opt.resume.startswith('wandb-artifact://') - run_id = torch.load(self.weights).get('wandb_id') if self.opt.resume and not wandb_artifact_resume else None self.opt.hyp = self.hyp # add hyperparameters - self.wandb = WandbLogger(self.opt, run_id) + self.wandb = WandbLogger(self.opt) else: self.wandb = None - def on_pretrain_routine_end(self): - # Callback runs on pre-train routine end - paths = self.save_dir.glob('*labels*.jpg') # training labels + # ClearML + if clearml and 'clearml' in self.include: + try: + self.clearml = ClearmlLogger(self.opt, self.hyp) + except Exception: + self.clearml = None + prefix = colorstr('ClearML: ') + LOGGER.warning(f'{prefix}WARNING ⚠️ ClearML is installed but not configured, skipping ClearML logging.' + f' See https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml#readme') + + else: + self.clearml = None + + # Comet + if comet_ml and 'comet' in self.include: + if isinstance(self.opt.resume, str) and self.opt.resume.startswith("comet://"): + run_id = self.opt.resume.split("/")[-1] + self.comet_logger = CometLogger(self.opt, self.hyp, run_id=run_id) + + else: + self.comet_logger = CometLogger(self.opt, self.hyp) + + else: + self.comet_logger = None + + @property + def remote_dataset(self): + # Get data_dict if custom dataset artifact link is provided + data_dict = None + if self.clearml: + data_dict = self.clearml.data_dict if self.wandb: - self.wandb.log({"Labels": [wandb.Image(str(x), caption=x.name) for x in paths]}) + data_dict = self.wandb.data_dict + if self.comet_logger: + data_dict = self.comet_logger.data_dict + + return data_dict - def on_train_batch_end(self, ni, model, imgs, targets, paths, plots, sync_bn): + def on_train_start(self): + if self.comet_logger: + self.comet_logger.on_train_start() + + def on_pretrain_routine_start(self): + if self.comet_logger: + self.comet_logger.on_pretrain_routine_start() + + def on_pretrain_routine_end(self, labels, names): + # Callback runs on pre-train routine end + if self.plots: + plot_labels(labels, names, self.save_dir) + paths = self.save_dir.glob('*labels*.jpg') # training labels + if self.wandb: + self.wandb.log({"Labels": [wandb.Image(str(x), caption=x.name) for x in paths]}) + # if self.clearml: + # pass # ClearML saves these images automatically using hooks + if self.comet_logger: + self.comet_logger.on_pretrain_routine_end(paths) + + def on_train_batch_end(self, model, ni, imgs, targets, paths, vals): + log_dict = dict(zip(self.keys[:3], vals)) # Callback runs on train batch end - if plots: - if ni == 0: - if not sync_bn: # tb.add_graph() --sync known issue https://github.com/ultralytics/yolov5/issues/3754 - with warnings.catch_warnings(): - warnings.simplefilter('ignore') # suppress jit trace warning - self.tb.add_graph(torch.jit.trace(de_parallel(model), imgs[0:1], strict=False), []) + # ni: number integrated batches (since train start) + if self.plots: if ni < 3: f = self.save_dir / f'train_batch{ni}.jpg' # filename - Thread(target=plot_images, args=(imgs, targets, paths, f), daemon=True).start() - if self.wandb and ni == 10: + plot_images(imgs, targets, paths, f) + if ni == 0 and self.tb and not self.opt.sync_bn: + log_tensorboard_graph(self.tb, model, imgsz=(self.opt.imgsz, self.opt.imgsz)) + if ni == 10 and (self.wandb or self.clearml): files = sorted(self.save_dir.glob('train*.jpg')) - self.wandb.log({'Mosaics': [wandb.Image(str(f), caption=f.name) for f in files if f.exists()]}) + if self.wandb: + self.wandb.log({'Mosaics': [wandb.Image(str(f), caption=f.name) for f in files if f.exists()]}) + if self.clearml: + self.clearml.log_debug_samples(files, title='Mosaics') + + if self.comet_logger: + self.comet_logger.on_train_batch_end(log_dict, step=ni) def on_train_epoch_end(self, epoch): # Callback runs on train epoch end if self.wandb: self.wandb.current_epoch = epoch + 1 + if self.comet_logger: + self.comet_logger.on_train_epoch_end(epoch) + + def on_val_start(self): + if self.comet_logger: + self.comet_logger.on_val_start() + def on_val_image_end(self, pred, predn, path, names, im): # Callback runs on val image end if self.wandb: self.wandb.val_one_image(pred, predn, path, names, im) + if self.clearml: + self.clearml.log_image_with_boxes(path, pred, names, im) - def on_val_end(self): + def on_val_batch_end(self, batch_i, im, targets, paths, shapes, out): + if self.comet_logger: + self.comet_logger.on_val_batch_end(batch_i, im, targets, paths, shapes, out) + + def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix): # Callback runs on val end - if self.wandb: + if self.wandb or self.clearml: files = sorted(self.save_dir.glob('val*.jpg')) + if self.wandb: self.wandb.log({"Validation": [wandb.Image(str(f), caption=f.name) for f in files]}) + if self.clearml: + self.clearml.log_debug_samples(files, title='Validation') + + if self.comet_logger: + self.comet_logger.on_val_end(nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) def on_fit_epoch_end(self, vals, epoch, best_fitness, fi): # Callback runs at the end of each fit (train+val) epoch - x = {k: v for k, v in zip(self.keys, vals)} # dict + x = dict(zip(self.keys, vals)) if self.csv: file = self.save_dir / 'results.csv' n = len(x) + 1 # number of cols @@ -123,37 +232,170 @@ def on_fit_epoch_end(self, vals, epoch, best_fitness, fi): if self.tb: for k, v in x.items(): self.tb.add_scalar(k, v, epoch) + elif self.clearml: # log to ClearML if TensorBoard not used + for k, v in x.items(): + title, series = k.split('/') + self.clearml.task.get_logger().report_scalar(title, series, v, epoch) if self.wandb: + if best_fitness == fi: + best_results = [epoch] + vals[3:7] + for i, name in enumerate(self.best_keys): + self.wandb.wandb_run.summary[name] = best_results[i] # log best results in the summary self.wandb.log(x) - self.wandb.end_epoch(best_result=best_fitness == fi) + self.wandb.end_epoch() + + if self.clearml: + self.clearml.current_epoch_logged_images = set() # reset epoch image limit + self.clearml.current_epoch += 1 + + if self.comet_logger: + self.comet_logger.on_fit_epoch_end(x, epoch=epoch) def on_model_save(self, last, epoch, final_epoch, best_fitness, fi): # Callback runs on model save event - if self.wandb: - if ((epoch + 1) % self.opt.save_period == 0 and not final_epoch) and self.opt.save_period != -1: + if (epoch + 1) % self.opt.save_period == 0 and not final_epoch and self.opt.save_period != -1: + if self.wandb: self.wandb.log_model(last.parent, self.opt, epoch, fi, best_model=best_fitness == fi) + if self.clearml: + self.clearml.task.update_output_model(model_path=str(last), + model_name='Latest Model', + auto_delete_file=False) + + if self.comet_logger: + self.comet_logger.on_model_save(last, epoch, final_epoch, best_fitness, fi) - def on_train_end(self, last, best, plots, epoch, results): - # Callback runs on training end - if plots: + def on_train_end(self, last, best, epoch, results): + # Callback runs on training end, i.e. saving best model + if self.plots: plot_results(file=self.save_dir / 'results.csv') # save results.png files = ['results.png', 'confusion_matrix.png', *(f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R'))] files = [(self.save_dir / f) for f in files if (self.save_dir / f).exists()] # filter + self.logger.info(f"Results saved to {colorstr('bold', self.save_dir)}") - if self.tb: - import cv2 + if self.tb and not self.clearml: # These images are already captured by ClearML by now, we don't want doubles for f in files: self.tb.add_image(f.stem, cv2.imread(str(f))[..., ::-1], epoch, dataformats='HWC') if self.wandb: + self.wandb.log(dict(zip(self.keys[3:10], results))) self.wandb.log({"Results": [wandb.Image(str(f), caption=f.name) for f in files]}) # Calling wandb.log. TODO: Refactor this into WandbLogger.log_model if not self.opt.evolve: - wandb.log_artifact(str(best if best.exists() else last), type='model', - name='run_' + self.wandb.wandb_run.id + '_model', + wandb.log_artifact(str(best if best.exists() else last), + type='model', + name=f'run_{self.wandb.wandb_run.id}_model', aliases=['latest', 'best', 'stripped']) - self.wandb.finish_run() - else: - self.wandb.finish_run() - self.wandb = WandbLogger(self.opt) + self.wandb.finish_run() + + if self.clearml and not self.opt.evolve: + self.clearml.task.update_output_model(model_path=str(best if best.exists() else last), + name='Best Model', + auto_delete_file=False) + + if self.comet_logger: + final_results = dict(zip(self.keys[3:10], results)) + self.comet_logger.on_train_end(files, self.save_dir, last, best, epoch, final_results) + + def on_params_update(self, params: dict): + # Update hyperparams or configs of the experiment + if self.wandb: + self.wandb.wandb_run.config.update(params, allow_val_change=True) + if self.comet_logger: + self.comet_logger.on_params_update(params) + + +class GenericLogger: + """ + YOLOv5 General purpose logger for non-task specific logging + Usage: from utils.loggers import GenericLogger; logger = GenericLogger(...) + Arguments + opt: Run arguments + console_logger: Console logger + include: loggers to include + """ + + def __init__(self, opt, console_logger, include=('tb', 'wandb')): + # init default loggers + self.save_dir = Path(opt.save_dir) + self.include = include + self.console_logger = console_logger + self.csv = self.save_dir / 'results.csv' # CSV logger + if 'tb' in self.include: + prefix = colorstr('TensorBoard: ') + self.console_logger.info( + f"{prefix}Start with 'tensorboard --logdir {self.save_dir.parent}', view at http://localhost:6006/") + self.tb = SummaryWriter(str(self.save_dir)) + + if wandb and 'wandb' in self.include: + self.wandb = wandb.init(project=web_project_name(str(opt.project)), + name=None if opt.name == "exp" else opt.name, + config=opt) + else: + self.wandb = None + + def log_metrics(self, metrics, epoch): + # Log metrics dictionary to all loggers + if self.csv: + keys, vals = list(metrics.keys()), list(metrics.values()) + n = len(metrics) + 1 # number of cols + s = '' if self.csv.exists() else (('%23s,' * n % tuple(['epoch'] + keys)).rstrip(',') + '\n') # header + with open(self.csv, 'a') as f: + f.write(s + ('%23.5g,' * n % tuple([epoch] + vals)).rstrip(',') + '\n') + + if self.tb: + for k, v in metrics.items(): + self.tb.add_scalar(k, v, epoch) + + if self.wandb: + self.wandb.log(metrics, step=epoch) + + def log_images(self, files, name='Images', epoch=0): + # Log images to all loggers + files = [Path(f) for f in (files if isinstance(files, (tuple, list)) else [files])] # to Path + files = [f for f in files if f.exists()] # filter by exists + + if self.tb: + for f in files: + self.tb.add_image(f.stem, cv2.imread(str(f))[..., ::-1], epoch, dataformats='HWC') + + if self.wandb: + self.wandb.log({name: [wandb.Image(str(f), caption=f.name) for f in files]}, step=epoch) + + def log_graph(self, model, imgsz=(640, 640)): + # Log model graph to all loggers + if self.tb: + log_tensorboard_graph(self.tb, model, imgsz) + + def log_model(self, model_path, epoch=0, metadata={}): + # Log model to all loggers + if self.wandb: + art = wandb.Artifact(name=f"run_{wandb.run.id}_model", type="model", metadata=metadata) + art.add_file(str(model_path)) + wandb.log_artifact(art) + + def update_params(self, params): + # Update the paramters logged + if self.wandb: + wandb.run.config.update(params, allow_val_change=True) + + +def log_tensorboard_graph(tb, model, imgsz=(640, 640)): + # Log model graph to TensorBoard + try: + p = next(model.parameters()) # for device, type + imgsz = (imgsz, imgsz) if isinstance(imgsz, int) else imgsz # expand + im = torch.zeros((1, 3, *imgsz)).to(p.device).type_as(p) # input image (WARNING: must be zeros, not empty) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') # suppress jit trace warning + tb.add_graph(torch.jit.trace(de_parallel(model), im, strict=False), []) + except Exception as e: + LOGGER.warning(f'WARNING ⚠️ TensorBoard graph visualization failure {e}') + + +def web_project_name(project): + # Convert local project name to web project name + if not project.startswith('runs/train'): + return project + suffix = '-Classify' if project.endswith('-cls') else '-Segment' if project.endswith('-seg') else '' + return f'YOLOv5{suffix}' diff --git a/utils/loggers/clearml/README.md b/utils/loggers/clearml/README.md new file mode 100644 index 0000000000..2ca610804d --- /dev/null +++ b/utils/loggers/clearml/README.md @@ -0,0 +1,271 @@ +# ClearML Integration + +Clear|MLClear|ML + +## About ClearML + +[ClearML](https://cutt.ly/yolov5-tutorial-clearml) is an [open-source](https://github.com/allegroai/clearml) toolbox +designed to save you time ⏱️. + +🔨 Track every YOLOv5 training run in the experiment manager + +🔧 Version and easily access your custom training data with the integrated ClearML Data Versioning Tool + +🔦 Remotely train and monitor your YOLOv5 training runs using ClearML Agent + +🔬 Get the very best mAP using ClearML Hyperparameter Optimization + +🔭 Turn your newly trained YOLOv5 model into an API with just a few commands using ClearML Serving + +
+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! +
+
+ +![ClearML scalars dashboard](https://github.com/thepycoder/clearml_screenshots/raw/main/experiment_manager_with_compare.gif) + +
+
+ +## 🦾 Setting Things Up + +To keep track of your experiments and/or data, ClearML needs to communicate to a server. You have 2 options to get one: + +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! + +1. Install the `clearml` python package: + + ```bash + pip install clearml + ``` + +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: + + ```bash + clearml-init + ``` + +That's it! You're done 😎 + +
+ +## 🚀 Training YOLOv5 With ClearML + +To enable ClearML experiment tracking, simply install the ClearML pip package. + +```bash +pip install clearml>=1.2.0 +``` + +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`, use the `--project` and `--name` arguments of the `train.py` +script, by default the project will be called `YOLOv5` and the task `Training`. +PLEASE NOTE: ClearML uses `/` as a delimiter for subprojects, so be careful when using `/` in your project name! + +```bash +python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov5s.pt --cache +``` + +or with custom project and task name: + +```bash +python train.py --project my_project --name my_training --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov5s.pt --cache +``` + +This will capture: + +- Source code + uncommitted changes +- Installed packages +- (Hyper)parameters +- Model files (use `--save-period n` to save a checkpoint every n epochs) +- Console output +- Scalars (mAP_0.5, mAP_0.5:0.95, precision, recall, losses, learning rates, ...) +- General info such as machine details, runtime, creation date etc. +- All produced plots such as label correlogram and confusion matrix +- Images with bounding boxes per epoch +- Mosaic per epoch +- Validation images per epoch +- ... + +That's a lot right? 🤯 +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! + +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! + +
+ +## 🔗 Dataset Version Management + +Versioning your data separately from your code is generally a good idea and makes it easy to acquire 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! + +![ClearML Dataset Interface](https://github.com/thepycoder/clearml_screenshots/raw/main/clearml_data.gif) + +### Prepare Your Dataset + +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: + +``` +.. +|_ yolov5 +|_ datasets + |_ coco128 + |_ images + |_ labels + |_ LICENSE + |_ README.txt +``` + +But this can be any dataset you wish. Feel free to use your own, as long as you keep to this folder structure. + +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. + +Basically we need the following keys: `path`, `train`, `test`, `val`, `nc`, `names`. + +``` +.. +|_ yolov5 +|_ datasets + |_ coco128 + |_ images + |_ labels + |_ coco128.yaml # <---- HERE! + |_ LICENSE + |_ README.txt +``` + +### Upload Your Dataset + +To get this dataset into ClearML as a versioned dataset, go to the dataset root folder and run the following command: + +```bash +cd coco128 +clearml-data sync --project YOLOv5 --name coco128 --folder . +``` + +The command `clearml-data sync` is actually a shorthand command. You could also run these commands one after the other: + +```bash +# Optionally add --parent if you want to base +# this version on another dataset version, so no duplicate files are uploaded! +clearml-data create --name coco128 --project YOLOv5 +clearml-data add --files . +clearml-data close +``` + +### Run Training Using A ClearML Dataset + +Now that you have a ClearML dataset, you can very simply use it to train custom YOLOv5 🚀 models! + +```bash +python train.py --img 640 --batch 16 --epochs 3 --data clearml:// --weights yolov5s.pt --cache +``` + +
+ +## 👀 Hyperparameter Optimization + +Now that we have our experiments and data versioned, it's time to take a look at what we can build on top! + +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! + +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. + +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. + +```bash +# To use optuna, install it first, otherwise you can change the optimizer to just be RandomSearch +pip install optuna +python utils/loggers/clearml/hpo.py +``` + +![HPO](https://github.com/thepycoder/clearml_screenshots/raw/main/hpo.png) + +## 🤯 Remote Execution (advanced) + +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. +This is where the ClearML Agent comes into play. Check out what the agent can do here: + +- [YouTube video](https://youtu.be/MX3BrXnaULs) +- [Documentation](https://clear.ml/docs/latest/docs/clearml_agent) + +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. + +You can turn any machine (a cloud VM, a local GPU machine, your own laptop ... ) into a ClearML agent by simply running: + +```bash +clearml-agent daemon --queue [--docker] +``` + +### Cloning, Editing And Enqueuing + +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! + +🪄 Clone the experiment by right-clicking it + +🎯 Edit the hyperparameters to what you wish them to be + +⏳ Enqueue the task to any of the queues by right-clicking it + +![Enqueue a task from the UI](https://github.com/thepycoder/clearml_screenshots/raw/main/enqueue.gif) + +### Executing A Task Remotely + +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! + +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 instantiated: + +```python +# ... +# Loggers +data_dict = None +if RANK in {-1, 0}: + loggers = Loggers(save_dir, weights, opt, hyp, LOGGER) # loggers instance + if loggers.clearml: + loggers.clearml.task.execute_remotely(queue="my_queue") # <------ ADD THIS LINE + # Data_dict is either None is user did not choose for ClearML dataset or is filled in by ClearML + data_dict = loggers.clearml.data_dict +# ... +``` + +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! + +### Autoscaling workers + +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! + +Check out the autoscalers getting started video below. + +[![Watch the video](https://img.youtube.com/vi/j4XVMAaUt3E/0.jpg)](https://youtu.be/j4XVMAaUt3E) diff --git a/utils/loggers/clearml/__init__.py b/utils/loggers/clearml/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py new file mode 100644 index 0000000000..3457727a96 --- /dev/null +++ b/utils/loggers/clearml/clearml_utils.py @@ -0,0 +1,164 @@ +"""Main Logger class for ClearML experiment tracking.""" +import glob +import re +from pathlib import Path + +import numpy as np +import yaml + +from utils.plots import Annotator, colors + +try: + import clearml + from clearml import Dataset, Task + + assert hasattr(clearml, '__version__') # verify package import not local dir +except (ImportError, AssertionError): + clearml = None + + +def construct_dataset(clearml_info_string): + """Load in a clearml dataset and fill the internal data_dict with its contents. + """ + dataset_id = clearml_info_string.replace('clearml://', '') + dataset = Dataset.get(dataset_id=dataset_id) + dataset_root_path = Path(dataset.get_local_copy()) + + # We'll search for the yaml file definition in the dataset + yaml_filenames = list(glob.glob(str(dataset_root_path / "*.yaml")) + glob.glob(str(dataset_root_path / "*.yml"))) + if len(yaml_filenames) > 1: + raise ValueError('More than one yaml file was found in the dataset root, cannot determine which one contains ' + 'the dataset definition this way.') + elif len(yaml_filenames) == 0: + raise ValueError('No yaml definition found in dataset root path, check that there is a correct yaml file ' + 'inside the dataset root path.') + with open(yaml_filenames[0]) as f: + dataset_definition = yaml.safe_load(f) + + assert set(dataset_definition.keys()).issuperset( + {'train', 'test', 'val', 'nc', 'names'} + ), "The right keys were not found in the yaml file, make sure it at least has the following keys: ('train', 'test', 'val', 'nc', 'names')" + + data_dict = dict() + data_dict['train'] = str( + (dataset_root_path / dataset_definition['train']).resolve()) if dataset_definition['train'] else None + data_dict['test'] = str( + (dataset_root_path / dataset_definition['test']).resolve()) if dataset_definition['test'] else None + data_dict['val'] = str( + (dataset_root_path / dataset_definition['val']).resolve()) if dataset_definition['val'] else None + data_dict['nc'] = dataset_definition['nc'] + data_dict['names'] = dataset_definition['names'] + + return data_dict + + +class ClearmlLogger: + """Log training runs, datasets, models, and predictions to ClearML. + + This logger sends information to ClearML at app.clear.ml or to your own hosted server. By default, + this information includes hyperparameters, system configuration and metrics, model metrics, code information and + basic data metrics and analyses. + + By providing additional command line arguments to train.py, datasets, + models and predictions can also be logged. + """ + + def __init__(self, opt, hyp): + """ + - Initialize ClearML Task, this object will capture the experiment + - Upload dataset version to ClearML Data if opt.upload_dataset is True + + arguments: + opt (namespace) -- Commandline arguments for this run + hyp (dict) -- Hyperparameters for this run + + """ + self.current_epoch = 0 + # Keep tracked of amount of logged images to enforce a limit + self.current_epoch_logged_images = set() + # Maximum number of images to log to clearML per epoch + self.max_imgs_to_log_per_epoch = 16 + # Get the interval of epochs when bounding box images should be logged + self.bbox_interval = opt.bbox_interval + self.clearml = clearml + self.task = None + self.data_dict = None + if self.clearml: + self.task = Task.init( + project_name=opt.project if opt.project != 'runs/train' else 'YOLOv5', + task_name=opt.name if opt.name != 'exp' else 'Training', + tags=['YOLOv5'], + output_uri=True, + reuse_last_task_id=opt.exist_ok, + auto_connect_frameworks={'pytorch': False} + # We disconnect pytorch auto-detection, because we added manual model save points in the code + ) + # ClearML's hooks will already grab all general parameters + # Only the hyperparameters coming from the yaml config file + # will have to be added manually! + self.task.connect(hyp, name='Hyperparameters') + self.task.connect(opt, name='Args') + + # Make sure the code is easily remotely runnable by setting the docker image to use by the remote agent + self.task.set_base_docker("ultralytics/yolov5:latest", + docker_arguments='--ipc=host -e="CLEARML_AGENT_SKIP_PYTHON_ENV_INSTALL=1"', + docker_setup_bash_script='pip install clearml') + + # Get ClearML Dataset Version if requested + if opt.data.startswith('clearml://'): + # data_dict should have the following keys: + # names, nc (number of classes), test, train, val (all three relative paths to ../datasets) + self.data_dict = construct_dataset(opt.data) + # Set data to data_dict because wandb will crash without this information and opt is the best way + # to give it to them + opt.data = self.data_dict + + def log_debug_samples(self, files, title='Debug Samples'): + """ + Log files (images) as debug samples in the ClearML task. + + arguments: + files (List(PosixPath)) a list of file paths in PosixPath format + title (str) A title that groups together images with the same values + """ + for f in files: + if f.exists(): + it = re.search(r'_batch(\d+)', f.name) + iteration = int(it.groups()[0]) if it else 0 + self.task.get_logger().report_image(title=title, + series=f.name.replace(it.group(), ''), + local_path=str(f), + iteration=iteration) + + def log_image_with_boxes(self, image_path, boxes, class_names, image, conf_threshold=0.25): + """ + Draw the bounding boxes on a single image and report the result as a ClearML debug sample. + + arguments: + image_path (PosixPath) the path the original image file + boxes (list): list of scaled predictions in the format - [xmin, ymin, xmax, ymax, confidence, class] + class_names (dict): dict containing mapping of class int to class name + image (Tensor): A torch tensor containing the actual image data + """ + if len(self.current_epoch_logged_images) < self.max_imgs_to_log_per_epoch and self.current_epoch >= 0: + # Log every bbox_interval times and deduplicate for any intermittend extra eval runs + if self.current_epoch % self.bbox_interval == 0 and image_path not in self.current_epoch_logged_images: + im = np.ascontiguousarray(np.moveaxis(image.mul(255).clamp(0, 255).byte().cpu().numpy(), 0, 2)) + annotator = Annotator(im=im, pil=True) + for i, (conf, class_nr, box) in enumerate(zip(boxes[:, 4], boxes[:, 5], boxes[:, :4])): + color = colors(i) + + class_name = class_names[int(class_nr)] + confidence_percentage = round(float(conf) * 100, 2) + label = f"{class_name}: {confidence_percentage}%" + + if conf > conf_threshold: + annotator.rectangle(box.cpu().numpy(), outline=color) + annotator.box_label(box.cpu().numpy(), label=label, color=color) + + annotated_image = annotator.result() + self.task.get_logger().report_image(title='Bounding Boxes', + series=image_path.name, + iteration=self.current_epoch, + image=annotated_image) + self.current_epoch_logged_images.add(image_path) diff --git a/utils/loggers/clearml/hpo.py b/utils/loggers/clearml/hpo.py new file mode 100644 index 0000000000..ee518b0fbf --- /dev/null +++ b/utils/loggers/clearml/hpo.py @@ -0,0 +1,84 @@ +from clearml import Task +# Connecting ClearML with the current process, +# from here on everything is logged automatically +from clearml.automation import HyperParameterOptimizer, UniformParameterRange +from clearml.automation.optuna import OptimizerOptuna + +task = Task.init(project_name='Hyper-Parameter Optimization', + task_name='YOLOv5', + task_type=Task.TaskTypes.optimizer, + reuse_last_task_id=False) + +# Example use case: +optimizer = HyperParameterOptimizer( + # This is the experiment we want to optimize + base_task_id='', + # here we define the hyper-parameters to optimize + # Notice: The parameter name should exactly match what you see in the UI: / + # For Example, here we see in the base experiment a section Named: "General" + # under it a parameter named "batch_size", this becomes "General/batch_size" + # If you have `argparse` for example, then arguments will appear under the "Args" section, + # and you should instead pass "Args/batch_size" + hyper_parameters=[ + UniformParameterRange('Hyperparameters/lr0', min_value=1e-5, max_value=1e-1), + UniformParameterRange('Hyperparameters/lrf', min_value=0.01, max_value=1.0), + UniformParameterRange('Hyperparameters/momentum', min_value=0.6, max_value=0.98), + UniformParameterRange('Hyperparameters/weight_decay', min_value=0.0, max_value=0.001), + UniformParameterRange('Hyperparameters/warmup_epochs', min_value=0.0, max_value=5.0), + UniformParameterRange('Hyperparameters/warmup_momentum', min_value=0.0, max_value=0.95), + UniformParameterRange('Hyperparameters/warmup_bias_lr', min_value=0.0, max_value=0.2), + UniformParameterRange('Hyperparameters/box', min_value=0.02, max_value=0.2), + UniformParameterRange('Hyperparameters/cls', min_value=0.2, max_value=4.0), + UniformParameterRange('Hyperparameters/cls_pw', min_value=0.5, max_value=2.0), + UniformParameterRange('Hyperparameters/obj', min_value=0.2, max_value=4.0), + UniformParameterRange('Hyperparameters/obj_pw', min_value=0.5, max_value=2.0), + UniformParameterRange('Hyperparameters/iou_t', min_value=0.1, max_value=0.7), + UniformParameterRange('Hyperparameters/anchor_t', min_value=2.0, max_value=8.0), + UniformParameterRange('Hyperparameters/fl_gamma', min_value=0.0, max_value=4.0), + UniformParameterRange('Hyperparameters/hsv_h', min_value=0.0, max_value=0.1), + UniformParameterRange('Hyperparameters/hsv_s', min_value=0.0, max_value=0.9), + UniformParameterRange('Hyperparameters/hsv_v', min_value=0.0, max_value=0.9), + UniformParameterRange('Hyperparameters/degrees', min_value=0.0, max_value=45.0), + UniformParameterRange('Hyperparameters/translate', min_value=0.0, max_value=0.9), + UniformParameterRange('Hyperparameters/scale', min_value=0.0, max_value=0.9), + UniformParameterRange('Hyperparameters/shear', min_value=0.0, max_value=10.0), + UniformParameterRange('Hyperparameters/perspective', min_value=0.0, max_value=0.001), + UniformParameterRange('Hyperparameters/flipud', min_value=0.0, max_value=1.0), + UniformParameterRange('Hyperparameters/fliplr', min_value=0.0, max_value=1.0), + UniformParameterRange('Hyperparameters/mosaic', min_value=0.0, max_value=1.0), + UniformParameterRange('Hyperparameters/mixup', min_value=0.0, max_value=1.0), + UniformParameterRange('Hyperparameters/copy_paste', min_value=0.0, max_value=1.0)], + # this is the objective metric we want to maximize/minimize + objective_metric_title='metrics', + objective_metric_series='mAP_0.5', + # now we decide if we want to maximize it or minimize it (accuracy we maximize) + objective_metric_sign='max', + # let us limit the number of concurrent experiments, + # this in turn will make sure we do dont bombard the scheduler with experiments. + # if we have an auto-scaler connected, this, by proxy, will limit the number of machine + max_number_of_concurrent_tasks=1, + # this is the optimizer class (actually doing the optimization) + # Currently, we can choose from GridSearch, RandomSearch or OptimizerBOHB (Bayesian optimization Hyper-Band) + optimizer_class=OptimizerOptuna, + # If specified only the top K performing Tasks will be kept, the others will be automatically archived + save_top_k_tasks_only=5, # 5, + compute_time_limit=None, + total_max_jobs=20, + min_iteration_per_job=None, + max_iteration_per_job=None, +) + +# report every 10 seconds, this is way too often, but we are testing here +optimizer.set_report_period(10 / 60) +# You can also use the line below instead to run all the optimizer tasks locally, without using queues or agent +# an_optimizer.start_locally(job_complete_callback=job_complete_callback) +# set the time limit for the optimization process (2 hours) +optimizer.set_time_limit(in_minutes=120.0) +# Start the optimization process in the local environment +optimizer.start_locally() +# wait until process is done (notice we are controlling the optimization process in the background) +optimizer.wait() +# make sure background optimization stopped +optimizer.stop() + +print('We are done, good bye') diff --git a/utils/loggers/comet/README.md b/utils/loggers/comet/README.md new file mode 100644 index 0000000000..4090cf938a --- /dev/null +++ b/utils/loggers/comet/README.md @@ -0,0 +1,284 @@ + + +# YOLOv5 with Comet + +This guide will cover how to use YOLOv5 with [Comet](https://bit.ly/yolov5-readme-comet2) + +# About Comet + +Comet builds tools that help data scientists, engineers, and team leaders accelerate and optimize machine learning and +deep learning models. + +Track and visualize model metrics in real time, save your hyperparameters, datasets, and model checkpoints, and +visualize your model predictions +with [Comet Custom Panels](https://www.comet.com/docs/v2/guides/comet-dashboard/code-panels/about-panels/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github)! +Comet makes sure you never lose track of your work and makes it easy to share results and collaborate across teams of +all sizes! + +# Getting Started + +## Install Comet + +```shell +pip install comet_ml +``` + +## Configure Comet Credentials + +There are two ways to configure Comet with YOLOv5. + +You can either set your credentials through environment variables + +**Environment Variables** + +```shell +export COMET_API_KEY= +export COMET_PROJECT_NAME= # This will default to 'yolov5' +``` + +Or create a `.comet.config` file in your working directory and set your credentials there. + +**Comet Configuration File** + +``` +[comet] +api_key= +project_name= # This will default to 'yolov5' +``` + +## Run the Training Script + +```shell +# Train YOLOv5s on COCO128 for 5 epochs +python train.py --img 640 --batch 16 --epochs 5 --data coco128.yaml --weights yolov5s.pt +``` + +That's it! Comet will automatically log your hyperparameters, command line arguments, training and validation metrics. +You can visualize and analyze your runs in the Comet UI + +yolo-ui + +# Try out an Example! + +Check out an example of +a [completed run here](https://www.comet.com/examples/comet-example-yolov5/a0e29e0e9b984e4a822db2a62d0cb357?experiment-tab=chart&showOutliers=true&smoothing=0&transformY=smoothing&xAxis=step&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) + +Or better yet, try it out yourself in this Colab Notebook + +[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing) + +# Log automatically + +By default, Comet will log the following items + +## Metrics + +- Box Loss, Object Loss, Classification Loss for the training and validation data +- mAP_0.5, mAP_0.5:0.95 metrics for the validation data. +- Precision and Recall for the validation data + +## Parameters + +- Model Hyperparameters +- All parameters passed through the command line options + +## Visualizations + +- Confusion Matrix of the model predictions on the validation data +- Plots for the PR and F1 curves across all classes +- Correlogram of the Class Labels + +# Configure Comet Logging + +Comet can be configured to log additional data either through command line flags passed to the training script +or through environment variables. + +```shell +export COMET_MODE=online # Set whether to run Comet in 'online' or 'offline' mode. Defaults to online +export COMET_MODEL_NAME= #Set the name for the saved model. Defaults to yolov5 +export COMET_LOG_CONFUSION_MATRIX=false # Set to disable logging a Comet Confusion Matrix. Defaults to true +export COMET_MAX_IMAGE_UPLOADS= # Controls how many total image predictions to log to Comet. Defaults to 100. +export COMET_LOG_PER_CLASS_METRICS=true # Set to log evaluation metrics for each detected class at the end of training. Defaults to false +export COMET_DEFAULT_CHECKPOINT_FILENAME= # Set this if you would like to resume training from a different checkpoint. Defaults to 'last.pt' +export COMET_LOG_BATCH_LEVEL_METRICS=true # Set this if you would like to log training metrics at the batch level. Defaults to false. +export COMET_LOG_PREDICTIONS=true # Set this to false to disable logging model predictions +``` + +## Logging Checkpoints with Comet + +Logging Models to Comet is disabled by default. To enable it, pass the `save-period` argument to the training script. +This will save the +logged checkpoints to Comet based on the interval value provided by `save-period` + +```shell +python train.py \ +--img 640 \ +--batch 16 \ +--epochs 5 \ +--data coco128.yaml \ +--weights yolov5s.pt \ +--save-period 1 +``` + +## Logging Model Predictions + +By default, model predictions (images, ground truth labels and bounding boxes) will be logged to Comet. + +You can control the frequency of logged predictions and the associated images by passing the `bbox_interval` command +line argument. Predictions can be visualized using Comet's Object Detection Custom Panel. This frequency corresponds to +every Nth batch of data per epoch. In the example below, we are logging every 2nd batch of data for each epoch. + +**Note:** The YOLOv5 validation dataloader will default to a batch size of 32, so you will have to set the logging +frequency accordingly. + +Here is +an [example project using the Panel](https://www.comet.com/examples/comet-example-yolov5?shareable=YcwMiJaZSXfcEXpGOHDD12vA1&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) + +```shell +python train.py \ +--img 640 \ +--batch 16 \ +--epochs 5 \ +--data coco128.yaml \ +--weights yolov5s.pt \ +--bbox_interval 2 +``` + +### Controlling the number of Prediction Images logged to Comet + +When logging predictions from YOLOv5, Comet will log the images associated with each set of predictions. By default a +maximum of 100 validation images are logged. You can increase or decrease this number using +the `COMET_MAX_IMAGE_UPLOADS` environment variable. + +```shell +env COMET_MAX_IMAGE_UPLOADS=200 python train.py \ +--img 640 \ +--batch 16 \ +--epochs 5 \ +--data coco128.yaml \ +--weights yolov5s.pt \ +--bbox_interval 1 +``` + +### Logging Class Level Metrics + +Use the `COMET_LOG_PER_CLASS_METRICS` environment variable to log mAP, precision, recall, f1 for each class. + +```shell +env COMET_LOG_PER_CLASS_METRICS=true python train.py \ +--img 640 \ +--batch 16 \ +--epochs 5 \ +--data coco128.yaml \ +--weights yolov5s.pt +``` + +## Uploading a Dataset to Comet Artifacts + +If you would like to store your data +using [Comet Artifacts](https://www.comet.com/docs/v2/guides/data-management/using-artifacts/#learn-more?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github), +you can do so using the `upload_dataset` flag. + +The dataset be organized in the way described in +the [YOLOv5 documentation](https://docs.ultralytics.com/tutorials/train-custom-datasets/#3-organize-directories). The +dataset config `yaml` file must follow the same format as that of the `coco128.yaml` file. + +```shell +python train.py \ +--img 640 \ +--batch 16 \ +--epochs 5 \ +--data coco128.yaml \ +--weights yolov5s.pt \ +--upload_dataset +``` + +You can find the uploaded dataset in the Artifacts tab in your Comet Workspace +artifact-1 + +You can preview the data directly in the Comet UI. +artifact-2 + +Artifacts are versioned and also support adding metadata about the dataset. Comet will automatically log the metadata +from your dataset `yaml` file +artifact-3 + +### Using a saved Artifact + +If you would like to use a dataset from Comet Artifacts, set the `path` variable in your dataset `yaml` file to point to +the following Artifact resource URL. + +``` +# contents of artifact.yaml file +path: "comet:///:" +``` + +Then pass this file to your training script in the following way + +```shell +python train.py \ +--img 640 \ +--batch 16 \ +--epochs 5 \ +--data artifact.yaml \ +--weights yolov5s.pt +``` + +Artifacts also allow you to track the lineage of data as it flows through your Experimentation workflow. Here you can +see a graph that shows you all the experiments that have used your uploaded dataset. +artifact-4 + +## Resuming a Training Run + +If your training run is interrupted for any reason, e.g. disrupted internet connection, you can resume the run using +the `resume` flag and the Comet Run Path. + +The Run Path has the following format `comet:////`. + +This will restore the run to its state before the interruption, which includes restoring the model from a checkpoint, +restoring all hyperparameters and training arguments and downloading Comet dataset Artifacts if they were used in the +original run. The resumed run will continue logging to the existing Experiment in the Comet UI + +```shell +python train.py \ +--resume "comet://" +``` + +## Hyperparameter Search with the Comet Optimizer + +YOLOv5 is also integrated with Comet's Optimizer, making is simple to visualize hyperparameter sweeps in the Comet UI. + +### Configuring an Optimizer Sweep + +To configure the Comet Optimizer, you will have to create a JSON file with the information about the sweep. An example +file has been provided in `utils/loggers/comet/optimizer_config.json` + +```shell +python utils/loggers/comet/hpo.py \ + --comet_optimizer_config "utils/loggers/comet/optimizer_config.json" +``` + +The `hpo.py` script accepts the same arguments as `train.py`. If you wish to pass additional arguments to your sweep +simply add them after +the script. + +```shell +python utils/loggers/comet/hpo.py \ + --comet_optimizer_config "utils/loggers/comet/optimizer_config.json" \ + --save-period 1 \ + --bbox_interval 1 +``` + +### Running a Sweep in Parallel + +```shell +comet optimizer -j utils/loggers/comet/hpo.py \ + utils/loggers/comet/optimizer_config.json" +``` + +### Visualizing Results + +Comet provides a number of ways to visualize the results of your sweep. Take a look at +a [project with a completed sweep here](https://www.comet.com/examples/comet-example-yolov5/view/PrlArHGuuhDTKC1UuBmTtOSXD/panels?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) + +hyperparameter-yolo diff --git a/utils/loggers/comet/__init__.py b/utils/loggers/comet/__init__.py new file mode 100644 index 0000000000..b0318f88d6 --- /dev/null +++ b/utils/loggers/comet/__init__.py @@ -0,0 +1,508 @@ +import glob +import json +import logging +import os +import sys +from pathlib import Path + +logger = logging.getLogger(__name__) + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[3] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH + +try: + import comet_ml + + # Project Configuration + config = comet_ml.config.get_config() + COMET_PROJECT_NAME = config.get_string(os.getenv("COMET_PROJECT_NAME"), "comet.project_name", default="yolov5") +except (ModuleNotFoundError, ImportError): + comet_ml = None + COMET_PROJECT_NAME = None + +import PIL +import torch +import torchvision.transforms as T +import yaml + +from utils.dataloaders import img2label_paths +from utils.general import check_dataset, scale_boxes, xywh2xyxy +from utils.metrics import box_iou + +COMET_PREFIX = "comet://" + +COMET_MODE = os.getenv("COMET_MODE", "online") + +# Model Saving Settings +COMET_MODEL_NAME = os.getenv("COMET_MODEL_NAME", "yolov5") + +# Dataset Artifact Settings +COMET_UPLOAD_DATASET = os.getenv("COMET_UPLOAD_DATASET", "false").lower() == "true" + +# Evaluation Settings +COMET_LOG_CONFUSION_MATRIX = os.getenv("COMET_LOG_CONFUSION_MATRIX", "true").lower() == "true" +COMET_LOG_PREDICTIONS = os.getenv("COMET_LOG_PREDICTIONS", "true").lower() == "true" +COMET_MAX_IMAGE_UPLOADS = int(os.getenv("COMET_MAX_IMAGE_UPLOADS", 100)) + +# Confusion Matrix Settings +CONF_THRES = float(os.getenv("CONF_THRES", 0.001)) +IOU_THRES = float(os.getenv("IOU_THRES", 0.6)) + +# Batch Logging Settings +COMET_LOG_BATCH_METRICS = os.getenv("COMET_LOG_BATCH_METRICS", "false").lower() == "true" +COMET_BATCH_LOGGING_INTERVAL = os.getenv("COMET_BATCH_LOGGING_INTERVAL", 1) +COMET_PREDICTION_LOGGING_INTERVAL = os.getenv("COMET_PREDICTION_LOGGING_INTERVAL", 1) +COMET_LOG_PER_CLASS_METRICS = os.getenv("COMET_LOG_PER_CLASS_METRICS", "false").lower() == "true" + +RANK = int(os.getenv("RANK", -1)) + +to_pil = T.ToPILImage() + + +class CometLogger: + """Log metrics, parameters, source code, models and much more + with Comet + """ + + def __init__(self, opt, hyp, run_id=None, job_type="Training", **experiment_kwargs) -> None: + self.job_type = job_type + self.opt = opt + self.hyp = hyp + + # Comet Flags + self.comet_mode = COMET_MODE + + self.save_model = opt.save_period > -1 + self.model_name = COMET_MODEL_NAME + + # Batch Logging Settings + self.log_batch_metrics = COMET_LOG_BATCH_METRICS + self.comet_log_batch_interval = COMET_BATCH_LOGGING_INTERVAL + + # Dataset Artifact Settings + self.upload_dataset = self.opt.upload_dataset if self.opt.upload_dataset else COMET_UPLOAD_DATASET + self.resume = self.opt.resume + + # Default parameters to pass to Experiment objects + self.default_experiment_kwargs = { + "log_code": False, + "log_env_gpu": True, + "log_env_cpu": True, + "project_name": COMET_PROJECT_NAME,} + self.default_experiment_kwargs.update(experiment_kwargs) + self.experiment = self._get_experiment(self.comet_mode, run_id) + + self.data_dict = self.check_dataset(self.opt.data) + self.class_names = self.data_dict["names"] + self.num_classes = self.data_dict["nc"] + + self.logged_images_count = 0 + self.max_images = COMET_MAX_IMAGE_UPLOADS + + if run_id is None: + self.experiment.log_other("Created from", "YOLOv5") + if not isinstance(self.experiment, comet_ml.OfflineExperiment): + workspace, project_name, experiment_id = self.experiment.url.split("/")[-3:] + self.experiment.log_other( + "Run Path", + f"{workspace}/{project_name}/{experiment_id}", + ) + self.log_parameters(vars(opt)) + self.log_parameters(self.opt.hyp) + self.log_asset_data( + self.opt.hyp, + name="hyperparameters.json", + metadata={"type": "hyp-config-file"}, + ) + self.log_asset( + f"{self.opt.save_dir}/opt.yaml", + metadata={"type": "opt-config-file"}, + ) + + self.comet_log_confusion_matrix = COMET_LOG_CONFUSION_MATRIX + + if hasattr(self.opt, "conf_thres"): + self.conf_thres = self.opt.conf_thres + else: + self.conf_thres = CONF_THRES + if hasattr(self.opt, "iou_thres"): + self.iou_thres = self.opt.iou_thres + else: + self.iou_thres = IOU_THRES + + self.log_parameters({"val_iou_threshold": self.iou_thres, "val_conf_threshold": self.conf_thres}) + + self.comet_log_predictions = COMET_LOG_PREDICTIONS + if self.opt.bbox_interval == -1: + self.comet_log_prediction_interval = 1 if self.opt.epochs < 10 else self.opt.epochs // 10 + else: + self.comet_log_prediction_interval = self.opt.bbox_interval + + if self.comet_log_predictions: + self.metadata_dict = {} + self.logged_image_names = [] + + self.comet_log_per_class_metrics = COMET_LOG_PER_CLASS_METRICS + + self.experiment.log_others({ + "comet_mode": COMET_MODE, + "comet_max_image_uploads": COMET_MAX_IMAGE_UPLOADS, + "comet_log_per_class_metrics": COMET_LOG_PER_CLASS_METRICS, + "comet_log_batch_metrics": COMET_LOG_BATCH_METRICS, + "comet_log_confusion_matrix": COMET_LOG_CONFUSION_MATRIX, + "comet_model_name": COMET_MODEL_NAME,}) + + # Check if running the Experiment with the Comet Optimizer + if hasattr(self.opt, "comet_optimizer_id"): + self.experiment.log_other("optimizer_id", self.opt.comet_optimizer_id) + self.experiment.log_other("optimizer_objective", self.opt.comet_optimizer_objective) + self.experiment.log_other("optimizer_metric", self.opt.comet_optimizer_metric) + self.experiment.log_other("optimizer_parameters", json.dumps(self.hyp)) + + def _get_experiment(self, mode, experiment_id=None): + if mode == "offline": + if experiment_id is not None: + return comet_ml.ExistingOfflineExperiment( + previous_experiment=experiment_id, + **self.default_experiment_kwargs, + ) + + return comet_ml.OfflineExperiment(**self.default_experiment_kwargs,) + + else: + try: + if experiment_id is not None: + return comet_ml.ExistingExperiment( + previous_experiment=experiment_id, + **self.default_experiment_kwargs, + ) + + return comet_ml.Experiment(**self.default_experiment_kwargs) + + except ValueError: + logger.warning("COMET WARNING: " + "Comet credentials have not been set. " + "Comet will default to offline logging. " + "Please set your credentials to enable online logging.") + return self._get_experiment("offline", experiment_id) + + return + + def log_metrics(self, log_dict, **kwargs): + self.experiment.log_metrics(log_dict, **kwargs) + + def log_parameters(self, log_dict, **kwargs): + self.experiment.log_parameters(log_dict, **kwargs) + + def log_asset(self, asset_path, **kwargs): + self.experiment.log_asset(asset_path, **kwargs) + + def log_asset_data(self, asset, **kwargs): + self.experiment.log_asset_data(asset, **kwargs) + + def log_image(self, img, **kwargs): + self.experiment.log_image(img, **kwargs) + + def log_model(self, path, opt, epoch, fitness_score, best_model=False): + if not self.save_model: + return + + model_metadata = { + "fitness_score": fitness_score[-1], + "epochs_trained": epoch + 1, + "save_period": opt.save_period, + "total_epochs": opt.epochs,} + + model_files = glob.glob(f"{path}/*.pt") + for model_path in model_files: + name = Path(model_path).name + + self.experiment.log_model( + self.model_name, + file_or_folder=model_path, + file_name=name, + metadata=model_metadata, + overwrite=True, + ) + + def check_dataset(self, data_file): + with open(data_file) as f: + data_config = yaml.safe_load(f) + + if data_config['path'].startswith(COMET_PREFIX): + path = data_config['path'].replace(COMET_PREFIX, "") + data_dict = self.download_dataset_artifact(path) + + return data_dict + + self.log_asset(self.opt.data, metadata={"type": "data-config-file"}) + + return check_dataset(data_file) + + def log_predictions(self, image, labelsn, path, shape, predn): + if self.logged_images_count >= self.max_images: + return + detections = predn[predn[:, 4] > self.conf_thres] + iou = box_iou(labelsn[:, 1:], detections[:, :4]) + mask, _ = torch.where(iou > self.iou_thres) + if len(mask) == 0: + return + + filtered_detections = detections[mask] + filtered_labels = labelsn[mask] + + image_id = path.split("/")[-1].split(".")[0] + image_name = f"{image_id}_curr_epoch_{self.experiment.curr_epoch}" + if image_name not in self.logged_image_names: + native_scale_image = PIL.Image.open(path) + self.log_image(native_scale_image, name=image_name) + self.logged_image_names.append(image_name) + + metadata = [] + for cls, *xyxy in filtered_labels.tolist(): + metadata.append({ + "label": f"{self.class_names[int(cls)]}-gt", + "score": 100, + "box": { + "x": xyxy[0], + "y": xyxy[1], + "x2": xyxy[2], + "y2": xyxy[3]},}) + for *xyxy, conf, cls in filtered_detections.tolist(): + metadata.append({ + "label": f"{self.class_names[int(cls)]}", + "score": conf * 100, + "box": { + "x": xyxy[0], + "y": xyxy[1], + "x2": xyxy[2], + "y2": xyxy[3]},}) + + self.metadata_dict[image_name] = metadata + self.logged_images_count += 1 + + return + + def preprocess_prediction(self, image, labels, shape, pred): + nl, _ = labels.shape[0], pred.shape[0] + + # Predictions + if self.opt.single_cls: + pred[:, 5] = 0 + + predn = pred.clone() + scale_boxes(image.shape[1:], predn[:, :4], shape[0], shape[1]) + + labelsn = None + if nl: + tbox = xywh2xyxy(labels[:, 1:5]) # target boxes + scale_boxes(image.shape[1:], tbox, shape[0], shape[1]) # native-space labels + labelsn = torch.cat((labels[:, 0:1], tbox), 1) # native-space labels + scale_boxes(image.shape[1:], predn[:, :4], shape[0], shape[1]) # native-space pred + + return predn, labelsn + + def add_assets_to_artifact(self, artifact, path, asset_path, split): + img_paths = sorted(glob.glob(f"{asset_path}/*")) + label_paths = img2label_paths(img_paths) + + for image_file, label_file in zip(img_paths, label_paths): + image_logical_path, label_logical_path = map(lambda x: os.path.relpath(x, path), [image_file, label_file]) + + try: + artifact.add(image_file, logical_path=image_logical_path, metadata={"split": split}) + artifact.add(label_file, logical_path=label_logical_path, metadata={"split": split}) + except ValueError as e: + logger.error('COMET ERROR: Error adding file to Artifact. Skipping file.') + logger.error(f"COMET ERROR: {e}") + continue + + return artifact + + def upload_dataset_artifact(self): + dataset_name = self.data_dict.get("dataset_name", "yolov5-dataset") + path = str((ROOT / Path(self.data_dict["path"])).resolve()) + + metadata = self.data_dict.copy() + for key in ["train", "val", "test"]: + split_path = metadata.get(key) + if split_path is not None: + metadata[key] = split_path.replace(path, "") + + artifact = comet_ml.Artifact(name=dataset_name, artifact_type="dataset", metadata=metadata) + for key in metadata.keys(): + if key in ["train", "val", "test"]: + if isinstance(self.upload_dataset, str) and (key != self.upload_dataset): + continue + + asset_path = self.data_dict.get(key) + if asset_path is not None: + artifact = self.add_assets_to_artifact(artifact, path, asset_path, key) + + self.experiment.log_artifact(artifact) + + return + + def download_dataset_artifact(self, artifact_path): + logged_artifact = self.experiment.get_artifact(artifact_path) + artifact_save_dir = str(Path(self.opt.save_dir) / logged_artifact.name) + logged_artifact.download(artifact_save_dir) + + metadata = logged_artifact.metadata + data_dict = metadata.copy() + data_dict["path"] = artifact_save_dir + + metadata_names = metadata.get("names") + if type(metadata_names) == dict: + data_dict["names"] = {int(k): v for k, v in metadata.get("names").items()} + elif type(metadata_names) == list: + data_dict["names"] = {int(k): v for k, v in zip(range(len(metadata_names)), metadata_names)} + else: + raise "Invalid 'names' field in dataset yaml file. Please use a list or dictionary" + + data_dict = self.update_data_paths(data_dict) + return data_dict + + def update_data_paths(self, data_dict): + path = data_dict.get("path", "") + + for split in ["train", "val", "test"]: + if data_dict.get(split): + split_path = data_dict.get(split) + data_dict[split] = (f"{path}/{split_path}" if isinstance(split, str) else [ + f"{path}/{x}" for x in split_path]) + + return data_dict + + def on_pretrain_routine_end(self, paths): + if self.opt.resume: + return + + for path in paths: + self.log_asset(str(path)) + + if self.upload_dataset: + if not self.resume: + self.upload_dataset_artifact() + + return + + def on_train_start(self): + self.log_parameters(self.hyp) + + def on_train_epoch_start(self): + return + + def on_train_epoch_end(self, epoch): + self.experiment.curr_epoch = epoch + + return + + def on_train_batch_start(self): + return + + def on_train_batch_end(self, log_dict, step): + self.experiment.curr_step = step + if self.log_batch_metrics and (step % self.comet_log_batch_interval == 0): + self.log_metrics(log_dict, step=step) + + return + + def on_train_end(self, files, save_dir, last, best, epoch, results): + if self.comet_log_predictions: + curr_epoch = self.experiment.curr_epoch + self.experiment.log_asset_data(self.metadata_dict, "image-metadata.json", epoch=curr_epoch) + + for f in files: + self.log_asset(f, metadata={"epoch": epoch}) + self.log_asset(f"{save_dir}/results.csv", metadata={"epoch": epoch}) + + if not self.opt.evolve: + model_path = str(best if best.exists() else last) + name = Path(model_path).name + if self.save_model: + self.experiment.log_model( + self.model_name, + file_or_folder=model_path, + file_name=name, + overwrite=True, + ) + + # Check if running Experiment with Comet Optimizer + if hasattr(self.opt, 'comet_optimizer_id'): + metric = results.get(self.opt.comet_optimizer_metric) + self.experiment.log_other('optimizer_metric_value', metric) + + self.finish_run() + + def on_val_start(self): + return + + def on_val_batch_start(self): + return + + def on_val_batch_end(self, batch_i, images, targets, paths, shapes, outputs): + if not (self.comet_log_predictions and ((batch_i + 1) % self.comet_log_prediction_interval == 0)): + return + + for si, pred in enumerate(outputs): + if len(pred) == 0: + continue + + image = images[si] + labels = targets[targets[:, 0] == si, 1:] + shape = shapes[si] + path = paths[si] + predn, labelsn = self.preprocess_prediction(image, labels, shape, pred) + if labelsn is not None: + self.log_predictions(image, labelsn, path, shape, predn) + + return + + def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix): + if self.comet_log_per_class_metrics: + if self.num_classes > 1: + for i, c in enumerate(ap_class): + class_name = self.class_names[c] + self.experiment.log_metrics( + { + 'mAP@.5': ap50[i], + 'mAP@.5:.95': ap[i], + 'precision': p[i], + 'recall': r[i], + 'f1': f1[i], + 'true_positives': tp[i], + 'false_positives': fp[i], + 'support': nt[c]}, + prefix=class_name) + + if self.comet_log_confusion_matrix: + epoch = self.experiment.curr_epoch + class_names = list(self.class_names.values()) + class_names.append("background") + num_classes = len(class_names) + + self.experiment.log_confusion_matrix( + matrix=confusion_matrix.matrix, + max_categories=num_classes, + labels=class_names, + epoch=epoch, + column_label='Actual Category', + row_label='Predicted Category', + file_name=f"confusion-matrix-epoch-{epoch}.json", + ) + + def on_fit_epoch_end(self, result, epoch): + self.log_metrics(result, epoch=epoch) + + def on_model_save(self, last, epoch, final_epoch, best_fitness, fi): + if ((epoch + 1) % self.opt.save_period == 0 and not final_epoch) and self.opt.save_period != -1: + self.log_model(last.parent, self.opt, epoch, fi, best_model=best_fitness == fi) + + def on_params_update(self, params): + self.log_parameters(params) + + def finish_run(self): + self.experiment.end() diff --git a/utils/loggers/comet/comet_utils.py b/utils/loggers/comet/comet_utils.py new file mode 100644 index 0000000000..3cbd45156b --- /dev/null +++ b/utils/loggers/comet/comet_utils.py @@ -0,0 +1,150 @@ +import logging +import os +from urllib.parse import urlparse + +try: + import comet_ml +except (ModuleNotFoundError, ImportError): + comet_ml = None + +import yaml + +logger = logging.getLogger(__name__) + +COMET_PREFIX = "comet://" +COMET_MODEL_NAME = os.getenv("COMET_MODEL_NAME", "yolov5") +COMET_DEFAULT_CHECKPOINT_FILENAME = os.getenv("COMET_DEFAULT_CHECKPOINT_FILENAME", "last.pt") + + +def download_model_checkpoint(opt, experiment): + model_dir = f"{opt.project}/{experiment.name}" + os.makedirs(model_dir, exist_ok=True) + + model_name = COMET_MODEL_NAME + model_asset_list = experiment.get_model_asset_list(model_name) + + if len(model_asset_list) == 0: + logger.error(f"COMET ERROR: No checkpoints found for model name : {model_name}") + return + + model_asset_list = sorted( + model_asset_list, + key=lambda x: x["step"], + reverse=True, + ) + logged_checkpoint_map = {asset["fileName"]: asset["assetId"] for asset in model_asset_list} + + resource_url = urlparse(opt.weights) + checkpoint_filename = resource_url.query + + if checkpoint_filename: + asset_id = logged_checkpoint_map.get(checkpoint_filename) + else: + asset_id = logged_checkpoint_map.get(COMET_DEFAULT_CHECKPOINT_FILENAME) + checkpoint_filename = COMET_DEFAULT_CHECKPOINT_FILENAME + + if asset_id is None: + logger.error(f"COMET ERROR: Checkpoint {checkpoint_filename} not found in the given Experiment") + return + + try: + logger.info(f"COMET INFO: Downloading checkpoint {checkpoint_filename}") + asset_filename = checkpoint_filename + + model_binary = experiment.get_asset(asset_id, return_type="binary", stream=False) + model_download_path = f"{model_dir}/{asset_filename}" + with open(model_download_path, "wb") as f: + f.write(model_binary) + + opt.weights = model_download_path + + except Exception as e: + logger.warning("COMET WARNING: Unable to download checkpoint from Comet") + logger.exception(e) + + +def set_opt_parameters(opt, experiment): + """Update the opts Namespace with parameters + from Comet's ExistingExperiment when resuming a run + + Args: + opt (argparse.Namespace): Namespace of command line options + experiment (comet_ml.APIExperiment): Comet API Experiment object + """ + asset_list = experiment.get_asset_list() + resume_string = opt.resume + + for asset in asset_list: + if asset["fileName"] == "opt.yaml": + asset_id = asset["assetId"] + asset_binary = experiment.get_asset(asset_id, return_type="binary", stream=False) + opt_dict = yaml.safe_load(asset_binary) + for key, value in opt_dict.items(): + setattr(opt, key, value) + opt.resume = resume_string + + # Save hyperparameters to YAML file + # Necessary to pass checks in training script + save_dir = f"{opt.project}/{experiment.name}" + os.makedirs(save_dir, exist_ok=True) + + hyp_yaml_path = f"{save_dir}/hyp.yaml" + with open(hyp_yaml_path, "w") as f: + yaml.dump(opt.hyp, f) + opt.hyp = hyp_yaml_path + + +def check_comet_weights(opt): + """Downloads model weights from Comet and updates the + weights path to point to saved weights location + + Args: + opt (argparse.Namespace): Command Line arguments passed + to YOLOv5 training script + + Returns: + None/bool: Return True if weights are successfully downloaded + else return None + """ + if comet_ml is None: + return + + if isinstance(opt.weights, str): + if opt.weights.startswith(COMET_PREFIX): + api = comet_ml.API() + resource = urlparse(opt.weights) + experiment_path = f"{resource.netloc}{resource.path}" + experiment = api.get(experiment_path) + download_model_checkpoint(opt, experiment) + return True + + return None + + +def check_comet_resume(opt): + """Restores run parameters to its original state based on the model checkpoint + and logged Experiment parameters. + + Args: + opt (argparse.Namespace): Command Line arguments passed + to YOLOv5 training script + + Returns: + None/bool: Return True if the run is restored successfully + else return None + """ + if comet_ml is None: + return + + if isinstance(opt.resume, str): + if opt.resume.startswith(COMET_PREFIX): + api = comet_ml.API() + resource = urlparse(opt.resume) + experiment_path = f"{resource.netloc}{resource.path}" + experiment = api.get(experiment_path) + set_opt_parameters(opt, experiment) + download_model_checkpoint(opt, experiment) + + return True + + return None diff --git a/utils/loggers/comet/hpo.py b/utils/loggers/comet/hpo.py new file mode 100644 index 0000000000..7dd5c92e8d --- /dev/null +++ b/utils/loggers/comet/hpo.py @@ -0,0 +1,118 @@ +import argparse +import json +import logging +import os +import sys +from pathlib import Path + +import comet_ml + +logger = logging.getLogger(__name__) + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[3] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH + +from train import train +from utils.callbacks import Callbacks +from utils.general import increment_path +from utils.torch_utils import select_device + +# Project Configuration +config = comet_ml.config.get_config() +COMET_PROJECT_NAME = config.get_string(os.getenv("COMET_PROJECT_NAME"), "comet.project_name", default="yolov5") + + +def get_args(known=False): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='initial weights path') + parser.add_argument('--cfg', type=str, default='', help='model.yaml path') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') + parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path') + parser.add_argument('--epochs', type=int, default=300, help='total training epochs') + parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') + parser.add_argument('--rect', action='store_true', help='rectangular training') + parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') + parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') + parser.add_argument('--noval', action='store_true', help='only validate final epoch') + parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') + parser.add_argument('--noplots', action='store_true', help='save no plot files') + parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') + parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') + parser.add_argument('--cache', type=str, nargs='?', const='ram', help='--cache images in "ram" (default) or "disk"') + parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') + parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') + parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer') + parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--quad', action='store_true', help='quad dataloader') + parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') + parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') + parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') + parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') + parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') + parser.add_argument('--seed', type=int, default=0, help='Global training seed') + parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + + # Weights & Biases arguments + parser.add_argument('--entity', default=None, help='W&B: Entity') + parser.add_argument('--upload_dataset', nargs='?', const=True, default=False, help='W&B: Upload data, "val" option') + parser.add_argument('--bbox_interval', type=int, default=-1, help='W&B: Set bounding-box image logging interval') + parser.add_argument('--artifact_alias', type=str, default='latest', help='W&B: Version of dataset artifact to use') + + # Comet Arguments + parser.add_argument("--comet_optimizer_config", type=str, help="Comet: Path to a Comet Optimizer Config File.") + parser.add_argument("--comet_optimizer_id", type=str, help="Comet: ID of the Comet Optimizer sweep.") + parser.add_argument("--comet_optimizer_objective", type=str, help="Comet: Set to 'minimize' or 'maximize'.") + parser.add_argument("--comet_optimizer_metric", type=str, help="Comet: Metric to Optimize.") + parser.add_argument("--comet_optimizer_workers", + type=int, + default=1, + help="Comet: Number of Parallel Workers to use with the Comet Optimizer.") + + return parser.parse_known_args()[0] if known else parser.parse_args() + + +def run(parameters, opt): + hyp_dict = {k: v for k, v in parameters.items() if k not in ["epochs", "batch_size"]} + + opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok or opt.evolve)) + opt.batch_size = parameters.get("batch_size") + opt.epochs = parameters.get("epochs") + + device = select_device(opt.device, batch_size=opt.batch_size) + train(hyp_dict, opt, device, callbacks=Callbacks()) + + +if __name__ == "__main__": + opt = get_args(known=True) + + opt.weights = str(opt.weights) + opt.cfg = str(opt.cfg) + opt.data = str(opt.data) + opt.project = str(opt.project) + + optimizer_id = os.getenv("COMET_OPTIMIZER_ID") + if optimizer_id is None: + with open(opt.comet_optimizer_config) as f: + optimizer_config = json.load(f) + optimizer = comet_ml.Optimizer(optimizer_config) + else: + optimizer = comet_ml.Optimizer(optimizer_id) + + opt.comet_optimizer_id = optimizer.id + status = optimizer.status() + + opt.comet_optimizer_objective = status["spec"]["objective"] + opt.comet_optimizer_metric = status["spec"]["metric"] + + logger.info("COMET INFO: Starting Hyperparameter Sweep") + for parameter in optimizer.get_parameters(): + run(parameter["parameters"], opt) diff --git a/utils/loggers/comet/optimizer_config.json b/utils/loggers/comet/optimizer_config.json new file mode 100644 index 0000000000..83ddddab6f --- /dev/null +++ b/utils/loggers/comet/optimizer_config.json @@ -0,0 +1,209 @@ +{ + "algorithm": "random", + "parameters": { + "anchor_t": { + "type": "discrete", + "values": [ + 2, + 8 + ] + }, + "batch_size": { + "type": "discrete", + "values": [ + 16, + 32, + 64 + ] + }, + "box": { + "type": "discrete", + "values": [ + 0.02, + 0.2 + ] + }, + "cls": { + "type": "discrete", + "values": [ + 0.2 + ] + }, + "cls_pw": { + "type": "discrete", + "values": [ + 0.5 + ] + }, + "copy_paste": { + "type": "discrete", + "values": [ + 1 + ] + }, + "degrees": { + "type": "discrete", + "values": [ + 0, + 45 + ] + }, + "epochs": { + "type": "discrete", + "values": [ + 5 + ] + }, + "fl_gamma": { + "type": "discrete", + "values": [ + 0 + ] + }, + "fliplr": { + "type": "discrete", + "values": [ + 0 + ] + }, + "flipud": { + "type": "discrete", + "values": [ + 0 + ] + }, + "hsv_h": { + "type": "discrete", + "values": [ + 0 + ] + }, + "hsv_s": { + "type": "discrete", + "values": [ + 0 + ] + }, + "hsv_v": { + "type": "discrete", + "values": [ + 0 + ] + }, + "iou_t": { + "type": "discrete", + "values": [ + 0.7 + ] + }, + "lr0": { + "type": "discrete", + "values": [ + 1e-05, + 0.1 + ] + }, + "lrf": { + "type": "discrete", + "values": [ + 0.01, + 1 + ] + }, + "mixup": { + "type": "discrete", + "values": [ + 1 + ] + }, + "momentum": { + "type": "discrete", + "values": [ + 0.6 + ] + }, + "mosaic": { + "type": "discrete", + "values": [ + 0 + ] + }, + "obj": { + "type": "discrete", + "values": [ + 0.2 + ] + }, + "obj_pw": { + "type": "discrete", + "values": [ + 0.5 + ] + }, + "optimizer": { + "type": "categorical", + "values": [ + "SGD", + "Adam", + "AdamW" + ] + }, + "perspective": { + "type": "discrete", + "values": [ + 0 + ] + }, + "scale": { + "type": "discrete", + "values": [ + 0 + ] + }, + "shear": { + "type": "discrete", + "values": [ + 0 + ] + }, + "translate": { + "type": "discrete", + "values": [ + 0 + ] + }, + "warmup_bias_lr": { + "type": "discrete", + "values": [ + 0, + 0.2 + ] + }, + "warmup_epochs": { + "type": "discrete", + "values": [ + 5 + ] + }, + "warmup_momentum": { + "type": "discrete", + "values": [ + 0, + 0.95 + ] + }, + "weight_decay": { + "type": "discrete", + "values": [ + 0, + 0.001 + ] + } + }, + "spec": { + "maxCombo": 0, + "metric": "metrics/mAP_0.5", + "objective": "maximize" + }, + "trials": 1 +} diff --git a/utils/loggers/wandb/__init__.py b/utils/loggers/wandb/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py new file mode 100644 index 0000000000..97ba31b68f --- /dev/null +++ b/utils/loggers/wandb/wandb_utils.py @@ -0,0 +1,193 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license + +# WARNING ⚠️ wandb is deprecated and will be removed in future release. +# See supported integrations at https://github.com/ultralytics/yolov5#integrations + +import logging +import os +import sys +from contextlib import contextmanager +from pathlib import Path + +from utils.general import LOGGER, colorstr + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[3] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +RANK = int(os.getenv('RANK', -1)) +DEPRECATION_WARNING = f"{colorstr('wandb')}: WARNING ⚠️ wandb is deprecated and will be removed in a future release. " \ + f"See supported integrations at https://github.com/ultralytics/yolov5#integrations." + +try: + import wandb + + assert hasattr(wandb, '__version__') # verify package import not local dir + LOGGER.warning(DEPRECATION_WARNING) +except (ImportError, AssertionError): + wandb = None + + +class WandbLogger(): + """Log training runs, datasets, models, and predictions to Weights & Biases. + + This logger sends information to W&B at wandb.ai. By default, this information + includes hyperparameters, system configuration and metrics, model metrics, + and basic data metrics and analyses. + + By providing additional command line arguments to train.py, datasets, + models and predictions can also be logged. + + For more on how this logger is used, see the Weights & Biases documentation: + https://docs.wandb.com/guides/integrations/yolov5 + """ + + def __init__(self, opt, run_id=None, job_type='Training'): + """ + - Initialize WandbLogger instance + - Upload dataset if opt.upload_dataset is True + - Setup training processes if job_type is 'Training' + + arguments: + opt (namespace) -- Commandline arguments for this run + run_id (str) -- Run ID of W&B run to be resumed + job_type (str) -- To set the job_type for this run + + """ + # Pre-training routine -- + self.job_type = job_type + self.wandb, self.wandb_run = wandb, wandb.run if wandb else None + self.val_artifact, self.train_artifact = None, None + self.train_artifact_path, self.val_artifact_path = None, None + self.result_artifact = None + self.val_table, self.result_table = None, None + self.max_imgs_to_log = 16 + self.data_dict = None + if self.wandb: + self.wandb_run = wandb.init(config=opt, + resume="allow", + project='YOLOv5' if opt.project == 'runs/train' else Path(opt.project).stem, + entity=opt.entity, + name=opt.name if opt.name != 'exp' else None, + job_type=job_type, + id=run_id, + allow_val_change=True) if not wandb.run else wandb.run + + if self.wandb_run: + if self.job_type == 'Training': + if isinstance(opt.data, dict): + # This means another dataset manager has already processed the dataset info (e.g. ClearML) + # and they will have stored the already processed dict in opt.data + self.data_dict = opt.data + self.setup_training(opt) + + def setup_training(self, opt): + """ + Setup the necessary processes for training YOLO models: + - Attempt to download model checkpoint and dataset artifacts if opt.resume stats with WANDB_ARTIFACT_PREFIX + - Update data_dict, to contain info of previous run if resumed and the paths of dataset artifact if downloaded + - Setup log_dict, initialize bbox_interval + + arguments: + opt (namespace) -- commandline arguments for this run + + """ + self.log_dict, self.current_epoch = {}, 0 + self.bbox_interval = opt.bbox_interval + if isinstance(opt.resume, str): + model_dir, _ = self.download_model_artifact(opt) + if model_dir: + self.weights = Path(model_dir) / "last.pt" + config = self.wandb_run.config + opt.weights, opt.save_period, opt.batch_size, opt.bbox_interval, opt.epochs, opt.hyp, opt.imgsz = str( + self.weights), config.save_period, config.batch_size, config.bbox_interval, config.epochs, \ + config.hyp, config.imgsz + + if opt.bbox_interval == -1: + self.bbox_interval = opt.bbox_interval = (opt.epochs // 10) if opt.epochs > 10 else 1 + if opt.evolve or opt.noplots: + self.bbox_interval = opt.bbox_interval = opt.epochs + 1 # disable bbox_interval + + def log_model(self, path, opt, epoch, fitness_score, best_model=False): + """ + Log the model checkpoint as W&B artifact + + arguments: + path (Path) -- Path of directory containing the checkpoints + opt (namespace) -- Command line arguments for this run + epoch (int) -- Current epoch number + fitness_score (float) -- fitness score for current epoch + best_model (boolean) -- Boolean representing if the current checkpoint is the best yet. + """ + model_artifact = wandb.Artifact('run_' + wandb.run.id + '_model', + type='model', + metadata={ + 'original_url': str(path), + 'epochs_trained': epoch + 1, + 'save period': opt.save_period, + 'project': opt.project, + 'total_epochs': opt.epochs, + 'fitness_score': fitness_score}) + model_artifact.add_file(str(path / 'last.pt'), name='last.pt') + wandb.log_artifact(model_artifact, + aliases=['latest', 'last', 'epoch ' + str(self.current_epoch), 'best' if best_model else '']) + LOGGER.info(f"Saving model artifact on epoch {epoch + 1}") + + def val_one_image(self, pred, predn, path, names, im): + pass + + def log(self, log_dict): + """ + save the metrics to the logging dictionary + + arguments: + log_dict (Dict) -- metrics/media to be logged in current step + """ + if self.wandb_run: + for key, value in log_dict.items(): + self.log_dict[key] = value + + def end_epoch(self): + """ + commit the log_dict, model artifacts and Tables to W&B and flush the log_dict. + + arguments: + best_result (boolean): Boolean representing if the result of this evaluation is best or not + """ + if self.wandb_run: + with all_logging_disabled(): + try: + wandb.log(self.log_dict) + except BaseException as e: + LOGGER.info( + f"An error occurred in wandb logger. The training will proceed without interruption. More info\n{e}" + ) + self.wandb_run.finish() + self.wandb_run = None + self.log_dict = {} + + def finish_run(self): + """ + Log metrics if any and finish the current W&B run + """ + if self.wandb_run: + if self.log_dict: + with all_logging_disabled(): + wandb.log(self.log_dict) + wandb.run.finish() + LOGGER.warning(DEPRECATION_WARNING) + + +@contextmanager +def all_logging_disabled(highest_level=logging.CRITICAL): + """ source - https://gist.github.com/simon-weber/7853144 + A context manager that will prevent any logging messages triggered during the body from being processed. + :param highest_level: the maximum logging level in use. + This would only need to be changed if a custom level greater than CRITICAL is defined. + """ + previous_level = logging.root.manager.disable + logging.disable(highest_level) + try: + yield + finally: + logging.disable(previous_level) diff --git a/utils/metrics.py b/utils/metrics.py index 90490955a8..408b613a21 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -11,6 +11,8 @@ import numpy as np import torch +from utils import TryExcept, threaded + def fitness(x): # Model fitness as a weighted combination of metrics @@ -18,7 +20,15 @@ def fitness(x): return (x[:, :4] * w).sum(1) -def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names=()): +def smooth(y, f=0.05): + # Box filter of fraction f + nf = round(len(y) * f * 2) // 2 + 1 # number of filter elements (must be odd) + p = np.ones(nf // 2) # ones padding + yp = np.concatenate((p * y[0], y, p * y[-1]), 0) # y padded + return np.convolve(yp, np.ones(nf) / nf, mode='valid') # y-smoothed + + +def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names=(), eps=1e-16, prefix=""): """ Compute the average precision, given the recall and precision curves. Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. # Arguments @@ -37,7 +47,7 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names tp, conf, pred_cls = tp[i], conf[i], pred_cls[i] # Find unique classes - unique_classes = np.unique(target_cls) + unique_classes, nt = np.unique(target_cls, return_counts=True) nc = unique_classes.shape[0] # number of classes, number of detections # Create Precision-Recall curve and compute AP for each class @@ -45,42 +55,44 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names ap, p, r = np.zeros((nc, tp.shape[1])), np.zeros((nc, 1000)), np.zeros((nc, 1000)) for ci, c in enumerate(unique_classes): i = pred_cls == c - n_l = (target_cls == c).sum() # number of labels + n_l = nt[ci] # number of labels n_p = i.sum() # number of predictions - if n_p == 0 or n_l == 0: continue - else: - # Accumulate FPs and TPs - fpc = (1 - tp[i]).cumsum(0) - tpc = tp[i].cumsum(0) - # Recall - recall = tpc / (n_l + 1e-16) # recall curve - r[ci] = np.interp(-px, -conf[i], recall[:, 0], left=0) # negative x, xp because xp decreases + # Accumulate FPs and TPs + fpc = (1 - tp[i]).cumsum(0) + tpc = tp[i].cumsum(0) + + # Recall + recall = tpc / (n_l + eps) # recall curve + r[ci] = np.interp(-px, -conf[i], recall[:, 0], left=0) # negative x, xp because xp decreases - # Precision - precision = tpc / (tpc + fpc) # precision curve - p[ci] = np.interp(-px, -conf[i], precision[:, 0], left=1) # p at pr_score + # Precision + precision = tpc / (tpc + fpc) # precision curve + p[ci] = np.interp(-px, -conf[i], precision[:, 0], left=1) # p at pr_score - # AP from recall-precision curve - for j in range(tp.shape[1]): - ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j]) - if plot and j == 0: - py.append(np.interp(px, mrec, mpre)) # precision at mAP@0.5 + # AP from recall-precision curve + for j in range(tp.shape[1]): + ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j]) + if plot and j == 0: + py.append(np.interp(px, mrec, mpre)) # precision at mAP@0.5 # Compute F1 (harmonic mean of precision and recall) - f1 = 2 * p * r / (p + r + 1e-16) + f1 = 2 * p * r / (p + r + eps) names = [v for k, v in names.items() if k in unique_classes] # list: only classes that have data - names = {i: v for i, v in enumerate(names)} # to dict + names = dict(enumerate(names)) # to dict if plot: - plot_pr_curve(px, py, ap, Path(save_dir) / 'PR_curve.png', names) - plot_mc_curve(px, f1, Path(save_dir) / 'F1_curve.png', names, ylabel='F1') - plot_mc_curve(px, p, Path(save_dir) / 'P_curve.png', names, ylabel='Precision') - plot_mc_curve(px, r, Path(save_dir) / 'R_curve.png', names, ylabel='Recall') + plot_pr_curve(px, py, ap, Path(save_dir) / f'{prefix}PR_curve.png', names) + plot_mc_curve(px, f1, Path(save_dir) / f'{prefix}F1_curve.png', names, ylabel='F1') + plot_mc_curve(px, p, Path(save_dir) / f'{prefix}P_curve.png', names, ylabel='Precision') + plot_mc_curve(px, r, Path(save_dir) / f'{prefix}R_curve.png', names, ylabel='Recall') - i = f1.mean(0).argmax() # max F1 index - return p[:, i], r[:, i], ap, f1[:, i], unique_classes.astype('int32') + i = smooth(f1.mean(0), 0.1).argmax() # max F1 index + p, r, f1 = p[:, i], r[:, i], f1[:, i] + tp = (r * nt).round() # true positives + fp = (tp / (p + eps) - tp).round() # false positives + return tp, fp, p, r, f1, ap, unique_classes.astype(int) def compute_ap(recall, precision): @@ -129,6 +141,12 @@ def process_batch(self, detections, labels): Returns: None, updates confusion matrix accordingly """ + if detections is None: + gt_classes = labels.int() + for gc in gt_classes: + self.matrix[self.nc, gc] += 1 # background FN + return + detections = detections[detections[:, 4] > self.conf] gt_classes = labels[:, 0].int() detection_classes = detections[:, 5].int() @@ -146,43 +164,55 @@ def process_batch(self, detections, labels): matches = np.zeros((0, 3)) n = matches.shape[0] > 0 - m0, m1, _ = matches.transpose().astype(np.int16) + m0, m1, _ = matches.transpose().astype(int) for i, gc in enumerate(gt_classes): j = m0 == i if n and sum(j) == 1: self.matrix[detection_classes[m1[j]], gc] += 1 # correct else: - self.matrix[self.nc, gc] += 1 # background FP + self.matrix[self.nc, gc] += 1 # true background if n: for i, dc in enumerate(detection_classes): if not any(m1 == i): - self.matrix[dc, self.nc] += 1 # background FN + self.matrix[dc, self.nc] += 1 # predicted background - def matrix(self): - return self.matrix + def tp_fp(self): + tp = self.matrix.diagonal() # true positives + fp = self.matrix.sum(1) - tp # false positives + # fn = self.matrix.sum(0) - tp # false negatives (missed detections) + return tp[:-1], fp[:-1] # remove background class + @TryExcept('WARNING ⚠️ ConfusionMatrix plot failure') def plot(self, normalize=True, save_dir='', names=()): - try: - import seaborn as sn - - array = self.matrix / ((self.matrix.sum(0).reshape(1, -1) + 1E-6) if normalize else 1) # normalize columns - array[array < 0.005] = np.nan # don't annotate (would appear as 0.00) - - fig = plt.figure(figsize=(12, 9), tight_layout=True) - sn.set(font_scale=1.0 if self.nc < 50 else 0.8) # for label size - labels = (0 < len(names) < 99) and len(names) == self.nc # apply names to ticklabels - with warnings.catch_warnings(): - warnings.simplefilter('ignore') # suppress empty matrix RuntimeWarning: All-NaN slice encountered - sn.heatmap(array, annot=self.nc < 30, annot_kws={"size": 8}, cmap='Blues', fmt='.2f', square=True, - xticklabels=names + ['background FP'] if labels else "auto", - yticklabels=names + ['background FN'] if labels else "auto").set_facecolor((1, 1, 1)) - fig.axes[0].set_xlabel('True') - fig.axes[0].set_ylabel('Predicted') - fig.savefig(Path(save_dir) / 'confusion_matrix.png', dpi=250) - plt.close() - except Exception as e: - print(f'WARNING: ConfusionMatrix plot failure: {e}') + import seaborn as sn + + array = self.matrix / ((self.matrix.sum(0).reshape(1, -1) + 1E-9) if normalize else 1) # normalize columns + array[array < 0.005] = np.nan # don't annotate (would appear as 0.00) + + fig, ax = plt.subplots(1, 1, figsize=(12, 9), tight_layout=True) + nc, nn = self.nc, len(names) # number of classes, names + sn.set(font_scale=1.0 if nc < 50 else 0.8) # for label size + labels = (0 < nn < 99) and (nn == nc) # apply names to ticklabels + ticklabels = (names + ['background']) if labels else "auto" + with warnings.catch_warnings(): + warnings.simplefilter('ignore') # suppress empty matrix RuntimeWarning: All-NaN slice encountered + sn.heatmap(array, + ax=ax, + annot=nc < 30, + annot_kws={ + "size": 8}, + cmap='Blues', + fmt='.2f', + square=True, + vmin=0.0, + xticklabels=ticklabels, + yticklabels=ticklabels).set_facecolor((1, 1, 1)) + ax.set_xlabel('True') + ax.set_ylabel('Predicted') + ax.set_title('Confusion Matrix') + fig.savefig(Path(save_dir) / 'confusion_matrix.png', dpi=250) + plt.close(fig) def print(self): for i in range(self.nc + 1): @@ -194,19 +224,19 @@ def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7 # Get the coordinates of bounding boxes if xywh: # transform from xywh to xyxy - (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, 1), box2.chunk(4, 1) + (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1) w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2 b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_ b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_ else: # x1, y1, x2, y2 = box1 - b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, 1) - b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, 1) - w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps - w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps + b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, -1) + b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, -1) + w1, h1 = b1_x2 - b1_x1, (b1_y2 - b1_y1).clamp(eps) + w2, h2 = b2_x2 - b2_x1, (b2_y2 - b2_y1).clamp(eps) # Intersection area - inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \ - (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0) + inter = (b1_x2.minimum(b2_x2) - b1_x1.maximum(b2_x1)).clamp(0) * \ + (b1_y2.minimum(b2_y2) - b1_y1.maximum(b2_y1)).clamp(0) # Union Area union = w1 * h1 + w2 * h2 - inter + eps @@ -214,13 +244,13 @@ def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7 # IoU iou = inter / union if CIoU or DIoU or GIoU: - cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1) # convex (smallest enclosing box) width - ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1) # convex height + cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1) # convex (smallest enclosing box) width + ch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1) # convex height if CIoU or DIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1 c2 = cw ** 2 + ch ** 2 + eps # convex diagonal squared rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4 # center dist ** 2 if CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47 - v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2) + v = (4 / math.pi ** 2) * (torch.atan(w2 / h2) - torch.atan(w1 / h1)).pow(2) with torch.no_grad(): alpha = v / (v - iou + (1 + eps)) return iou - (rho2 / c2 + v * alpha) # CIoU @@ -230,7 +260,7 @@ def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7 return iou # IoU -def box_iou(box1, box2): +def box_iou(box1, box2, eps=1e-7): # https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py """ Return intersection-over-union (Jaccard index) of boxes. @@ -243,30 +273,24 @@ def box_iou(box1, box2): IoU values for every element in boxes1 and boxes2 """ - def box_area(box): - # box = 4xn - return (box[2] - box[0]) * (box[3] - box[1]) - - area1 = box_area(box1.T) - area2 = box_area(box2.T) - # inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2) - inter = (torch.min(box1[:, None, 2:], box2[:, 2:]) - torch.max(box1[:, None, :2], box2[:, :2])).clamp(0).prod(2) - return inter / (area1[:, None] + area2 - inter) # iou = inter / (area1 + area2 - inter) + (a1, a2), (b1, b2) = box1.unsqueeze(1).chunk(2, 2), box2.unsqueeze(0).chunk(2, 2) + inter = (torch.min(a2, b2) - torch.max(a1, b1)).clamp(0).prod(2) + # IoU = inter / (area1 + area2 - inter) + return inter / ((a2 - a1).prod(2) + (b2 - b1).prod(2) - inter + eps) -def bbox_ioa(box1, box2, eps=1E-7): + +def bbox_ioa(box1, box2, eps=1e-7): """ Returns the intersection over box2 area given box1, box2. Boxes are x1y1x2y2 box1: np.array of shape(4) box2: np.array of shape(nx4) returns: np.array of shape(n) """ - box2 = box2.transpose() - # Get the coordinates of bounding boxes - b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3] - b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3] + b1_x1, b1_y1, b1_x2, b1_y2 = box1 + b2_x1, b2_y1, b2_x2, b2_y2 = box2.T # Intersection area inter_area = (np.minimum(b1_x2, b2_x2) - np.maximum(b1_x1, b2_x1)).clip(0) * \ @@ -279,17 +303,19 @@ def bbox_ioa(box1, box2, eps=1E-7): return inter_area / box2_area -def wh_iou(wh1, wh2): +def wh_iou(wh1, wh2, eps=1e-7): # Returns the nxm IoU matrix. wh1 is nx2, wh2 is mx2 wh1 = wh1[:, None] # [N,1,2] wh2 = wh2[None] # [1,M,2] inter = torch.min(wh1, wh2).prod(2) # [N,M] - return inter / (wh1.prod(2) + wh2.prod(2) - inter) # iou = inter / (area1 + area2 - inter) + return inter / (wh1.prod(2) + wh2.prod(2) - inter + eps) # iou = inter / (area1 + area2 - inter) # Plots ---------------------------------------------------------------------------------------------------------------- -def plot_pr_curve(px, py, ap, save_dir='pr_curve.png', names=()): + +@threaded +def plot_pr_curve(px, py, ap, save_dir=Path('pr_curve.png'), names=()): # Precision-recall curve fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True) py = np.stack(py, axis=1) @@ -305,12 +331,14 @@ def plot_pr_curve(px, py, ap, save_dir='pr_curve.png', names=()): ax.set_ylabel('Precision') ax.set_xlim(0, 1) ax.set_ylim(0, 1) - plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left") - fig.savefig(Path(save_dir), dpi=250) - plt.close() + ax.legend(bbox_to_anchor=(1.04, 1), loc="upper left") + ax.set_title('Precision-Recall Curve') + fig.savefig(save_dir, dpi=250) + plt.close(fig) -def plot_mc_curve(px, py, save_dir='mc_curve.png', names=(), xlabel='Confidence', ylabel='Metric'): +@threaded +def plot_mc_curve(px, py, save_dir=Path('mc_curve.png'), names=(), xlabel='Confidence', ylabel='Metric'): # Metric-confidence curve fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True) @@ -320,12 +348,13 @@ def plot_mc_curve(px, py, save_dir='mc_curve.png', names=(), xlabel='Confidence' else: ax.plot(px, py.T, linewidth=1, color='grey') # plot(confidence, metric) - y = py.mean(0) + y = smooth(py.mean(0), 0.05) ax.plot(px, y, linewidth=3, color='blue', label=f'all classes {y.max():.2f} at {px[y.argmax()]:.3f}') ax.set_xlabel(xlabel) ax.set_ylabel(ylabel) ax.set_xlim(0, 1) ax.set_ylim(0, 1) - plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left") - fig.savefig(Path(save_dir), dpi=250) - plt.close() + ax.legend(bbox_to_anchor=(1.04, 1), loc="upper left") + ax.set_title(f'{ylabel}-Confidence Curve') + fig.savefig(save_dir, dpi=250) + plt.close(fig) diff --git a/utils/plots.py b/utils/plots.py index 16ae44a7e1..440e837f3e 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -3,10 +3,12 @@ Plotting utils """ +import contextlib import math import os from copy import copy from pathlib import Path +from urllib.error import URLError import cv2 import matplotlib @@ -17,12 +19,13 @@ import torch from PIL import Image, ImageDraw, ImageFont -from utils.general import (LOGGER, Timeout, check_requirements, clip_coords, increment_path, is_ascii, is_chinese, - try_except, user_config_dir, xywh2xyxy, xyxy2xywh) +from utils import TryExcept, threaded +from utils.general import (CONFIG_DIR, FONT, LOGGER, check_font, check_requirements, clip_boxes, increment_path, + is_ascii, xywh2xyxy, xyxy2xywh) from utils.metrics import fitness +from utils.segment.general import scale_image # Settings -CONFIG_DIR = user_config_dir() # Ultralytics settings dir RANK = int(os.getenv('RANK', -1)) matplotlib.rc('font', **{'size': 11}) matplotlib.use('Agg') # for writing to files only @@ -32,9 +35,9 @@ class Colors: # Ultralytics color palette https://ultralytics.com/ def __init__(self): # hex = matplotlib.colors.TABLEAU_COLORS.values() - hex = ('FF3838', 'FF9D97', 'FF701F', 'FFB21D', 'CFD231', '48F90A', '92CC17', '3DDB86', '1A9334', '00D4BB', - '2C99A8', '00C2FF', '344593', '6473FF', '0018EC', '8438FF', '520085', 'CB38FF', 'FF95C8', 'FF37C7') - self.palette = [self.hex2rgb('#' + c) for c in hex] + hexs = ('FF3838', 'FF9D97', 'FF701F', 'FFB21D', 'CFD231', '48F90A', '92CC17', '3DDB86', '1A9334', '00D4BB', + '2C99A8', '00C2FF', '344593', '6473FF', '0018EC', '8438FF', '520085', 'CB38FF', 'FF95C8', 'FF37C7') + self.palette = [self.hex2rgb(f'#{c}') for c in hexs] self.n = len(self.palette) def __call__(self, i, bgr=False): @@ -49,35 +52,33 @@ def hex2rgb(h): # rgb order (PIL) colors = Colors() # create instance for 'from utils.plots import colors' -def check_font(font='Arial.ttf', size=10): +def check_pil_font(font=FONT, size=10): # Return a PIL TrueType Font, downloading to CONFIG_DIR if necessary font = Path(font) font = font if font.exists() else (CONFIG_DIR / font.name) try: return ImageFont.truetype(str(font) if font.exists() else font.name, size) - except Exception as e: # download if missing - url = "https://ultralytics.com/assets/" + font.name - print(f'Downloading {url} to {font}...') - torch.hub.download_url_to_file(url, str(font), progress=False) + except Exception: # download if missing try: + check_font(font) return ImageFont.truetype(str(font), size) except TypeError: check_requirements('Pillow>=8.4.0') # known issue https://github.com/ultralytics/yolov5/issues/5374 + except URLError: # not online + return ImageFont.load_default() class Annotator: - if RANK in (-1, 0): - check_font() # download TTF if necessary - - # Annotator for train/val mosaics and jpgs and detect/hub inference annotations + # YOLOv3 Annotator for train/val mosaics and jpgs and detect/hub inference annotations def __init__(self, im, line_width=None, font_size=None, font='Arial.ttf', pil=False, example='abc'): assert im.data.contiguous, 'Image not contiguous. Apply np.ascontiguousarray(im) to Annotator() input images.' - self.pil = pil or not is_ascii(example) or is_chinese(example) + non_ascii = not is_ascii(example) # non-latin labels, i.e. asian, arabic, cyrillic + self.pil = pil or non_ascii if self.pil: # use PIL self.im = im if isinstance(im, Image.Image) else Image.fromarray(im) self.draw = ImageDraw.Draw(self.im) - self.font = check_font(font='Arial.Unicode.ttf' if is_chinese(example) else font, - size=font_size or max(round(sum(self.im.size) / 2 * 0.035), 12)) + self.font = check_pil_font(font='Arial.Unicode.ttf' if non_ascii else font, + size=font_size or max(round(sum(self.im.size) / 2 * 0.035), 12)) else: # use cv2 self.im = im self.lw = line_width or max(round(sum(im.shape) / 2 * 0.003), 2) # line width @@ -87,12 +88,14 @@ def box_label(self, box, label='', color=(128, 128, 128), txt_color=(255, 255, 2 if self.pil or not is_ascii(label): self.draw.rectangle(box, width=self.lw, outline=color) # box if label: - w, h = self.font.getsize(label) # text width, height + w, h = self.font.getsize(label) # text width, height (WARNING: deprecated) in 9.2.0 + # _, _, w, h = self.font.getbbox(label) # text width, height (New) outside = box[1] - h >= 0 # label fits outside box - self.draw.rectangle([box[0], - box[1] - h if outside else box[1], - box[0] + w + 1, - box[1] + 1 if outside else box[1] + h + 1], fill=color) + self.draw.rectangle( + (box[0], box[1] - h if outside else box[1], box[0] + w + 1, + box[1] + 1 if outside else box[1] + h + 1), + fill=color, + ) # self.draw.text((box[0], box[1]), label, fill=txt_color, font=self.font, anchor='ls') # for PIL>8.0 self.draw.text((box[0], box[1] - h if outside else box[1]), label, fill=txt_color, font=self.font) else: # cv2 @@ -101,20 +104,62 @@ def box_label(self, box, label='', color=(128, 128, 128), txt_color=(255, 255, 2 if label: tf = max(self.lw - 1, 1) # font thickness w, h = cv2.getTextSize(label, 0, fontScale=self.lw / 3, thickness=tf)[0] # text width, height - outside = p1[1] - h - 3 >= 0 # label fits outside box + outside = p1[1] - h >= 3 p2 = p1[0] + w, p1[1] - h - 3 if outside else p1[1] + h + 3 cv2.rectangle(self.im, p1, p2, color, -1, cv2.LINE_AA) # filled - cv2.putText(self.im, label, (p1[0], p1[1] - 2 if outside else p1[1] + h + 2), 0, self.lw / 3, txt_color, - thickness=tf, lineType=cv2.LINE_AA) + cv2.putText(self.im, + label, (p1[0], p1[1] - 2 if outside else p1[1] + h + 2), + 0, + self.lw / 3, + txt_color, + thickness=tf, + lineType=cv2.LINE_AA) + + def masks(self, masks, colors, im_gpu, alpha=0.5, retina_masks=False): + """Plot masks at once. + Args: + masks (tensor): predicted masks on cuda, shape: [n, h, w] + colors (List[List[Int]]): colors for predicted masks, [[r, g, b] * n] + im_gpu (tensor): img is in cuda, shape: [3, h, w], range: [0, 1] + alpha (float): mask transparency: 0.0 fully transparent, 1.0 opaque + """ + if self.pil: + # convert to numpy first + self.im = np.asarray(self.im).copy() + if len(masks) == 0: + self.im[:] = im_gpu.permute(1, 2, 0).contiguous().cpu().numpy() * 255 + colors = torch.tensor(colors, device=im_gpu.device, dtype=torch.float32) / 255.0 + colors = colors[:, None, None] # shape(n,1,1,3) + masks = masks.unsqueeze(3) # shape(n,h,w,1) + masks_color = masks * (colors * alpha) # shape(n,h,w,3) + + inv_alph_masks = (1 - masks * alpha).cumprod(0) # shape(n,h,w,1) + mcs = (masks_color * inv_alph_masks).sum(0) * 2 # mask color summand shape(n,h,w,3) + + im_gpu = im_gpu.flip(dims=[0]) # flip channel + im_gpu = im_gpu.permute(1, 2, 0).contiguous() # shape(h,w,3) + im_gpu = im_gpu * inv_alph_masks[-1] + mcs + im_mask = (im_gpu * 255).byte().cpu().numpy() + self.im[:] = im_mask if retina_masks else scale_image(im_gpu.shape, im_mask, self.im.shape) + if self.pil: + # convert im back to PIL and update draw + self.fromarray(self.im) def rectangle(self, xy, fill=None, outline=None, width=1): # Add rectangle to image (PIL-only) self.draw.rectangle(xy, fill, outline, width) - def text(self, xy, text, txt_color=(255, 255, 255)): + def text(self, xy, text, txt_color=(255, 255, 255), anchor='top'): # Add text to image (PIL-only) - w, h = self.font.getsize(text) # text width, height - self.draw.text((xy[0], xy[1] - h + 1), text, fill=txt_color, font=self.font) + if anchor == 'bottom': # start y from font bottom + w, h = self.font.getsize(text) # text width, height + xy[1] += 1 - h + self.draw.text(xy, text, fill=txt_color, font=self.font) + + def fromarray(self, im): + # Update self.im from a numpy array + self.im = im if isinstance(im, Image.Image) else Image.fromarray(im) + self.draw = ImageDraw.Draw(self.im) def result(self): # Return annotated image as array @@ -132,7 +177,7 @@ def feature_visualization(x, module_type, stage, n=32, save_dir=Path('runs/detec if 'Detect' not in module_type: batch, channels, height, width = x.shape # batch, channels, height, width if height > 1 and width > 1: - f = f"stage{stage}_{module_type.split('.')[-1]}_features.png" # filename + f = save_dir / f"stage{stage}_{module_type.split('.')[-1]}_features.png" # filename blocks = torch.chunk(x[0].cpu(), channels, dim=0) # select batch index 0, block by channels n = min(n, channels) # number of plots @@ -143,9 +188,10 @@ def feature_visualization(x, module_type, stage, n=32, save_dir=Path('runs/detec ax[i].imshow(blocks[i].squeeze()) # cmap='gray' ax[i].axis('off') - print(f'Saving {save_dir / f}... ({n}/{channels})') - plt.savefig(save_dir / f, dpi=300, bbox_inches='tight') + LOGGER.info(f'Saving {f}... ({n}/{channels})') + plt.savefig(f, dpi=300, bbox_inches='tight') plt.close() + np.save(str(f.with_suffix('.npy')), x[0].cpu().numpy()) # npy save def hist2d(x, y, n=100): @@ -170,26 +216,31 @@ def butter_lowpass(cutoff, fs, order): return filtfilt(b, a, data) # forward-backward filter -def output_to_target(output): - # Convert model output to target format [batch_id, class_id, x, y, w, h, conf] +def output_to_target(output, max_det=300): + # Convert model output to target format [batch_id, class_id, x, y, w, h, conf] for plotting targets = [] for i, o in enumerate(output): - for *box, conf, cls in o.cpu().numpy(): - targets.append([i, cls, *list(*xyxy2xywh(np.array(box)[None])), conf]) - return np.array(targets) + box, conf, cls = o[:max_det, :6].cpu().split((4, 1, 1), 1) + j = torch.full((conf.shape[0], 1), i) + targets.append(torch.cat((j, cls, xyxy2xywh(box), conf), 1)) + return torch.cat(targets, 0).numpy() -def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max_size=1920, max_subplots=16): +@threaded +def plot_images(images, targets, paths=None, fname='images.jpg', names=None): # Plot image grid with labels if isinstance(images, torch.Tensor): images = images.cpu().float().numpy() if isinstance(targets, torch.Tensor): targets = targets.cpu().numpy() - if np.max(images[0]) <= 1: - images *= 255 # de-normalise (optional) + + max_size = 1920 # max image size + max_subplots = 16 # max image subplots, i.e. 4x4 bs, _, h, w = images.shape # batch size, _, height, width bs = min(bs, max_subplots) # limit plot images ns = np.ceil(bs ** 0.5) # number of subplots (square) + if np.max(images[0]) <= 1: + images *= 255 # de-normalise (optional) # Build Image mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) # init @@ -209,12 +260,12 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max # Annotate fs = int((h + w) * ns * 0.01) # font size - annotator = Annotator(mosaic, line_width=round(fs / 10), font_size=fs, pil=True) + annotator = Annotator(mosaic, line_width=round(fs / 10), font_size=fs, pil=True, example=names) for i in range(i + 1): x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin annotator.rectangle([x, y, x + w, y + h], None, (255, 255, 255), width=2) # borders if paths: - annotator.text((x + 5, y + 5 + h), text=Path(paths[i]).name[:40], txt_color=(220, 220, 220)) # filenames + annotator.text((x + 5, y + 5), text=Path(paths[i]).name[:40], txt_color=(220, 220, 220)) # filenames if len(targets) > 0: ti = targets[targets[:, 0] == i] # image targets boxes = xywh2xyxy(ti[:, 2:6]).T @@ -295,7 +346,7 @@ def plot_val_study(file='', dir='', x=None): # from utils.plots import *; plot_ ax = plt.subplots(2, 4, figsize=(10, 6), tight_layout=True)[1].ravel() fig2, ax2 = plt.subplots(1, 1, figsize=(8, 4), tight_layout=True) - # for f in [save_dir / f'study_coco_{x}.txt' for x in ['yolov3', 'yolov3-spp', 'yolov3-tiny']]: + # for f in [save_dir / f'study_coco_{x}.txt' for x in ['yolov5n6', 'yolov5s6', 'yolov5m6', 'yolov5l6', 'yolov5x6']]: for f in sorted(save_dir.glob('study*.txt')): y = np.loadtxt(f, dtype=np.float32, usecols=[0, 1, 2, 3, 7, 8, 9], ndmin=2).T x = np.arange(y.shape[1]) if x is None else np.array(x) @@ -306,11 +357,19 @@ def plot_val_study(file='', dir='', x=None): # from utils.plots import *; plot_ ax[i].set_title(s[i]) j = y[3].argmax() + 1 - ax2.plot(y[5, 1:j], y[3, 1:j] * 1E2, '.-', linewidth=2, markersize=8, + ax2.plot(y[5, 1:j], + y[3, 1:j] * 1E2, + '.-', + linewidth=2, + markersize=8, label=f.stem.replace('study_coco_', '').replace('yolo', 'YOLO')) ax2.plot(1E3 / np.array([209, 140, 97, 58, 35, 18]), [34.6, 40.5, 43.0, 47.5, 49.7, 51.5], - 'k.-', linewidth=2, markersize=8, alpha=.25, label='EfficientDet') + 'k.-', + linewidth=2, + markersize=8, + alpha=.25, + label='EfficientDet') ax2.grid(alpha=0.2) ax2.set_yticks(np.arange(20, 60, 5)) @@ -324,8 +383,7 @@ def plot_val_study(file='', dir='', x=None): # from utils.plots import *; plot_ plt.savefig(f, dpi=300) -@try_except # known issue https://github.com/ultralytics/yolov5/issues/5395 -@Timeout(30) # known issue https://github.com/ultralytics/yolov5/issues/5611 +@TryExcept() # known issue https://github.com/ultralytics/yolov5/issues/5395 def plot_labels(labels, names=(), save_dir=Path('')): # plot dataset labels LOGGER.info(f"Plotting labels to {save_dir / 'labels.jpg'}... ") @@ -342,11 +400,12 @@ def plot_labels(labels, names=(), save_dir=Path('')): matplotlib.use('svg') # faster ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True)[1].ravel() y = ax[0].hist(c, bins=np.linspace(0, nc, nc + 1) - 0.5, rwidth=0.8) - # [y[2].patches[i].set_color([x / 255 for x in colors(i)]) for i in range(nc)] # update colors bug #3195 + with contextlib.suppress(Exception): # color histogram bars by class + [y[2].patches[i].set_color([x / 255 for x in colors(i)]) for i in range(nc)] # known issue #3195 ax[0].set_ylabel('instances') if 0 < len(names) < 30: ax[0].set_xticks(range(len(names))) - ax[0].set_xticklabels(names, rotation=90, fontsize=10) + ax[0].set_xticklabels(list(names.values()), rotation=90, fontsize=10) else: ax[0].set_xlabel('classes') sn.histplot(x, x='x', y='y', ax=ax[2], bins=50, pmax=0.9) @@ -370,6 +429,35 @@ def plot_labels(labels, names=(), save_dir=Path('')): plt.close() +def imshow_cls(im, labels=None, pred=None, names=None, nmax=25, verbose=False, f=Path('images.jpg')): + # Show classification image grid with labels (optional) and predictions (optional) + from utils.augmentations import denormalize + + names = names or [f'class{i}' for i in range(1000)] + blocks = torch.chunk(denormalize(im.clone()).cpu().float(), len(im), + dim=0) # select batch index 0, block by channels + n = min(len(blocks), nmax) # number of plots + m = min(8, round(n ** 0.5)) # 8 x 8 default + fig, ax = plt.subplots(math.ceil(n / m), m) # 8 rows x n/8 cols + ax = ax.ravel() if m > 1 else [ax] + # plt.subplots_adjust(wspace=0.05, hspace=0.05) + for i in range(n): + ax[i].imshow(blocks[i].squeeze().permute((1, 2, 0)).numpy().clip(0.0, 1.0)) + ax[i].axis('off') + if labels is not None: + s = names[labels[i]] + (f'—{names[pred[i]]}' if pred is not None else '') + ax[i].set_title(s, fontsize=8, verticalalignment='top') + plt.savefig(f, dpi=300, bbox_inches='tight') + plt.close() + if verbose: + LOGGER.info(f"Saving {f}") + if labels is not None: + LOGGER.info('True: ' + ' '.join(f'{names[i]:3s}' for i in labels[:nmax])) + if pred is not None: + LOGGER.info('Predicted:' + ' '.join(f'{names[i]:3s}' for i in pred[:nmax])) + return f + + def plot_evolve(evolve_csv='path/to/evolve.csv'): # from utils.plots import *; plot_evolve() # Plot evolve.csv hyp evolution results evolve_csv = Path(evolve_csv) @@ -380,6 +468,7 @@ def plot_evolve(evolve_csv='path/to/evolve.csv'): # from utils.plots import *; j = np.argmax(f) # max fitness index plt.figure(figsize=(10, 12), tight_layout=True) matplotlib.rc('font', **{'size': 8}) + print(f'Best results from row {j} of {evolve_csv}:') for i, k in enumerate(keys[7:]): v = x[:, 7 + i] mu = v[j] # best single result @@ -403,20 +492,20 @@ def plot_results(file='path/to/results.csv', dir=''): ax = ax.ravel() files = list(save_dir.glob('results*.csv')) assert len(files), f'No results.csv files found in {save_dir.resolve()}, nothing to plot.' - for fi, f in enumerate(files): + for f in files: try: data = pd.read_csv(f) s = [x.strip() for x in data.columns] x = data.values[:, 0] for i, j in enumerate([1, 2, 3, 4, 5, 8, 9, 10, 6, 7]): - y = data.values[:, j] + y = data.values[:, j].astype('float') # y[y == 0] = np.nan # don't show zero values ax[i].plot(x, y, marker='.', label=f.stem, linewidth=2, markersize=8) ax[i].set_title(s[j], fontsize=12) # if j in [8, 9, 10]: # share train and val loss y axes # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) except Exception as e: - print(f'Warning: Plotting error for {f}: {e}') + LOGGER.info(f'Warning: Plotting error for {f}: {e}') ax[1].legend() fig.savefig(save_dir / 'results.png', dpi=200) plt.close() @@ -453,7 +542,7 @@ def profile_idetection(start=0, stop=0, labels=(), save_dir=''): plt.savefig(Path(save_dir) / 'idetection_profile.png', dpi=200) -def save_one_box(xyxy, im, file='image.jpg', gain=1.02, pad=10, square=False, BGR=False, save=True): +def save_one_box(xyxy, im, file=Path('im.jpg'), gain=1.02, pad=10, square=False, BGR=False, save=True): # Save image crop as {file} with crop size multiple {gain} and {pad} pixels. Save and/or return crop xyxy = torch.tensor(xyxy).view(-1, 4) b = xyxy2xywh(xyxy) # boxes @@ -461,9 +550,11 @@ def save_one_box(xyxy, im, file='image.jpg', gain=1.02, pad=10, square=False, BG b[:, 2:] = b[:, 2:].max(1)[0].unsqueeze(1) # attempt rectangle to square b[:, 2:] = b[:, 2:] * gain + pad # box wh * gain + pad xyxy = xywh2xyxy(b).long() - clip_coords(xyxy, im.shape) + clip_boxes(xyxy, im.shape) crop = im[int(xyxy[0, 1]):int(xyxy[0, 3]), int(xyxy[0, 0]):int(xyxy[0, 2]), ::(1 if BGR else -1)] if save: file.parent.mkdir(parents=True, exist_ok=True) # make directory - cv2.imwrite(str(increment_path(file).with_suffix('.jpg')), crop) + f = str(increment_path(file).with_suffix('.jpg')) + # cv2.imwrite(f, crop) # save BGR, https://github.com/ultralytics/yolov5/issues/7007 chroma subsampling issue + Image.fromarray(crop[..., ::-1]).save(f, quality=95, subsampling=0) # save RGB return crop diff --git a/utils/segment/__init__.py b/utils/segment/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/utils/segment/augmentations.py b/utils/segment/augmentations.py new file mode 100644 index 0000000000..2897b7f4e2 --- /dev/null +++ b/utils/segment/augmentations.py @@ -0,0 +1,104 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Image augmentation functions +""" + +import math +import random + +import cv2 +import numpy as np + +from ..augmentations import box_candidates +from ..general import resample_segments, segment2box + + +def mixup(im, labels, segments, im2, labels2, segments2): + # Applies MixUp augmentation https://arxiv.org/pdf/1710.09412.pdf + r = np.random.beta(32.0, 32.0) # mixup ratio, alpha=beta=32.0 + im = (im * r + im2 * (1 - r)).astype(np.uint8) + labels = np.concatenate((labels, labels2), 0) + segments = np.concatenate((segments, segments2), 0) + return im, labels, segments + + +def random_perspective(im, + targets=(), + segments=(), + degrees=10, + translate=.1, + scale=.1, + shear=10, + perspective=0.0, + border=(0, 0)): + # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) + # targets = [cls, xyxy] + + height = im.shape[0] + border[0] * 2 # shape(h,w,c) + width = im.shape[1] + border[1] * 2 + + # Center + C = np.eye(3) + C[0, 2] = -im.shape[1] / 2 # x translation (pixels) + C[1, 2] = -im.shape[0] / 2 # y translation (pixels) + + # Perspective + P = np.eye(3) + P[2, 0] = random.uniform(-perspective, perspective) # x perspective (about y) + P[2, 1] = random.uniform(-perspective, perspective) # y perspective (about x) + + # Rotation and Scale + R = np.eye(3) + a = random.uniform(-degrees, degrees) + # a += random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotations + s = random.uniform(1 - scale, 1 + scale) + # s = 2 ** random.uniform(-scale, scale) + R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s) + + # Shear + S = np.eye(3) + S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # x shear (deg) + S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # y shear (deg) + + # Translation + T = np.eye(3) + T[0, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * width) # x translation (pixels) + T[1, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * height) # y translation (pixels) + + # Combined rotation matrix + M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT + if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): # image changed + if perspective: + im = cv2.warpPerspective(im, M, dsize=(width, height), borderValue=(114, 114, 114)) + else: # affine + im = cv2.warpAffine(im, M[:2], dsize=(width, height), borderValue=(114, 114, 114)) + + # Visualize + # import matplotlib.pyplot as plt + # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel() + # ax[0].imshow(im[:, :, ::-1]) # base + # ax[1].imshow(im2[:, :, ::-1]) # warped + + # Transform label coordinates + n = len(targets) + new_segments = [] + if n: + new = np.zeros((n, 4)) + segments = resample_segments(segments) # upsample + for i, segment in enumerate(segments): + xy = np.ones((len(segment), 3)) + xy[:, :2] = segment + xy = xy @ M.T # transform + xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]) # perspective rescale or affine + + # clip + new[i] = segment2box(xy, width, height) + new_segments.append(xy) + + # filter candidates + i = box_candidates(box1=targets[:, 1:5].T * s, box2=new.T, area_thr=0.01) + targets = targets[i] + targets[:, 1:5] = new[i] + new_segments = np.array(new_segments)[i] + + return im, targets, new_segments diff --git a/utils/segment/dataloaders.py b/utils/segment/dataloaders.py new file mode 100644 index 0000000000..2c5cdc2d20 --- /dev/null +++ b/utils/segment/dataloaders.py @@ -0,0 +1,332 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Dataloaders +""" + +import os +import random + +import cv2 +import numpy as np +import torch +from torch.utils.data import DataLoader, distributed + +from ..augmentations import augment_hsv, copy_paste, letterbox +from ..dataloaders import InfiniteDataLoader, LoadImagesAndLabels, seed_worker +from ..general import LOGGER, xyn2xy, xywhn2xyxy, xyxy2xywhn +from ..torch_utils import torch_distributed_zero_first +from .augmentations import mixup, random_perspective + +RANK = int(os.getenv('RANK', -1)) + + +def create_dataloader(path, + imgsz, + batch_size, + stride, + single_cls=False, + hyp=None, + augment=False, + cache=False, + pad=0.0, + rect=False, + rank=-1, + workers=8, + image_weights=False, + quad=False, + prefix='', + shuffle=False, + mask_downsample_ratio=1, + overlap_mask=False, + seed=0): + if rect and shuffle: + LOGGER.warning('WARNING ⚠️ --rect is incompatible with DataLoader shuffle, setting shuffle=False') + shuffle = False + with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP + dataset = LoadImagesAndLabelsAndMasks( + path, + imgsz, + batch_size, + augment=augment, # augmentation + hyp=hyp, # hyperparameters + rect=rect, # rectangular batches + cache_images=cache, + single_cls=single_cls, + stride=int(stride), + pad=pad, + image_weights=image_weights, + prefix=prefix, + downsample_ratio=mask_downsample_ratio, + overlap=overlap_mask) + + batch_size = min(batch_size, len(dataset)) + nd = torch.cuda.device_count() # number of CUDA devices + nw = min([os.cpu_count() // max(nd, 1), batch_size if batch_size > 1 else 0, workers]) # number of workers + sampler = None if rank == -1 else distributed.DistributedSampler(dataset, shuffle=shuffle) + loader = DataLoader if image_weights else InfiniteDataLoader # only DataLoader allows for attribute updates + generator = torch.Generator() + generator.manual_seed(6148914691236517205 + seed + RANK) + return loader( + dataset, + batch_size=batch_size, + shuffle=shuffle and sampler is None, + num_workers=nw, + sampler=sampler, + pin_memory=True, + collate_fn=LoadImagesAndLabelsAndMasks.collate_fn4 if quad else LoadImagesAndLabelsAndMasks.collate_fn, + worker_init_fn=seed_worker, + generator=generator, + ), dataset + + +class LoadImagesAndLabelsAndMasks(LoadImagesAndLabels): # for training/testing + + def __init__( + self, + path, + img_size=640, + batch_size=16, + augment=False, + hyp=None, + rect=False, + image_weights=False, + cache_images=False, + single_cls=False, + stride=32, + pad=0, + min_items=0, + prefix="", + downsample_ratio=1, + overlap=False, + ): + super().__init__(path, img_size, batch_size, augment, hyp, rect, image_weights, cache_images, single_cls, + stride, pad, min_items, prefix) + self.downsample_ratio = downsample_ratio + self.overlap = overlap + + def __getitem__(self, index): + index = self.indices[index] # linear, shuffled, or image_weights + + hyp = self.hyp + mosaic = self.mosaic and random.random() < hyp['mosaic'] + masks = [] + if mosaic: + # Load mosaic + img, labels, segments = self.load_mosaic(index) + shapes = None + + # MixUp augmentation + if random.random() < hyp["mixup"]: + img, labels, segments = mixup(img, labels, segments, *self.load_mosaic(random.randint(0, self.n - 1))) + + else: + # Load image + img, (h0, w0), (h, w) = self.load_image(index) + + # Letterbox + shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape + img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment) + shapes = (h0, w0), ((h / h0, w / w0), pad) # for COCO mAP rescaling + + labels = self.labels[index].copy() + # [array, array, ....], array.shape=(num_points, 2), xyxyxyxy + segments = self.segments[index].copy() + if len(segments): + for i_s in range(len(segments)): + segments[i_s] = xyn2xy( + segments[i_s], + ratio[0] * w, + ratio[1] * h, + padw=pad[0], + padh=pad[1], + ) + if labels.size: # normalized xywh to pixel xyxy format + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], ratio[0] * w, ratio[1] * h, padw=pad[0], padh=pad[1]) + + if self.augment: + img, labels, segments = random_perspective(img, + labels, + segments=segments, + degrees=hyp["degrees"], + translate=hyp["translate"], + scale=hyp["scale"], + shear=hyp["shear"], + perspective=hyp["perspective"]) + + nl = len(labels) # number of labels + if nl: + labels[:, 1:5] = xyxy2xywhn(labels[:, 1:5], w=img.shape[1], h=img.shape[0], clip=True, eps=1e-3) + if self.overlap: + masks, sorted_idx = polygons2masks_overlap(img.shape[:2], + segments, + downsample_ratio=self.downsample_ratio) + masks = masks[None] # (640, 640) -> (1, 640, 640) + labels = labels[sorted_idx] + else: + masks = polygons2masks(img.shape[:2], segments, color=1, downsample_ratio=self.downsample_ratio) + + masks = (torch.from_numpy(masks) if len(masks) else torch.zeros(1 if self.overlap else nl, img.shape[0] // + self.downsample_ratio, img.shape[1] // + self.downsample_ratio)) + # TODO: albumentations support + if self.augment: + # Albumentations + # there are some augmentation that won't change boxes and masks, + # so just be it for now. + img, labels = self.albumentations(img, labels) + nl = len(labels) # update after albumentations + + # HSV color-space + augment_hsv(img, hgain=hyp["hsv_h"], sgain=hyp["hsv_s"], vgain=hyp["hsv_v"]) + + # Flip up-down + if random.random() < hyp["flipud"]: + img = np.flipud(img) + if nl: + labels[:, 2] = 1 - labels[:, 2] + masks = torch.flip(masks, dims=[1]) + + # Flip left-right + if random.random() < hyp["fliplr"]: + img = np.fliplr(img) + if nl: + labels[:, 1] = 1 - labels[:, 1] + masks = torch.flip(masks, dims=[2]) + + # Cutouts # labels = cutout(img, labels, p=0.5) + + labels_out = torch.zeros((nl, 6)) + if nl: + labels_out[:, 1:] = torch.from_numpy(labels) + + # Convert + img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB + img = np.ascontiguousarray(img) + + return (torch.from_numpy(img), labels_out, self.im_files[index], shapes, masks) + + def load_mosaic(self, index): + # YOLOv5 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic + labels4, segments4 = [], [] + s = self.img_size + yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y + + # 3 additional image indices + indices = [index] + random.choices(self.indices, k=3) # 3 additional image indices + for i, index in enumerate(indices): + # Load image + img, _, (h, w) = self.load_image(index) + + # place img in img4 + if i == 0: # top left + img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles + x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc # xmin, ymin, xmax, ymax (large image) + x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h # xmin, ymin, xmax, ymax (small image) + elif i == 1: # top right + x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc + x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h + elif i == 2: # bottom left + x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h) + x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h) + elif i == 3: # bottom right + x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h) + x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h) + + img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax] + padw = x1a - x1b + padh = y1a - y1b + + labels, segments = self.labels[index].copy(), self.segments[index].copy() + + if labels.size: + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padw, padh) # normalized xywh to pixel xyxy format + segments = [xyn2xy(x, w, h, padw, padh) for x in segments] + labels4.append(labels) + segments4.extend(segments) + + # Concat/clip labels + labels4 = np.concatenate(labels4, 0) + for x in (labels4[:, 1:], *segments4): + np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective() + # img4, labels4 = replicate(img4, labels4) # replicate + + # Augment + img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp["copy_paste"]) + img4, labels4, segments4 = random_perspective(img4, + labels4, + segments4, + degrees=self.hyp["degrees"], + translate=self.hyp["translate"], + scale=self.hyp["scale"], + shear=self.hyp["shear"], + perspective=self.hyp["perspective"], + border=self.mosaic_border) # border to remove + return img4, labels4, segments4 + + @staticmethod + def collate_fn(batch): + img, label, path, shapes, masks = zip(*batch) # transposed + batched_masks = torch.cat(masks, 0) + for i, l in enumerate(label): + l[:, 0] = i # add target image index for build_targets() + return torch.stack(img, 0), torch.cat(label, 0), path, shapes, batched_masks + + +def polygon2mask(img_size, polygons, color=1, downsample_ratio=1): + """ + Args: + img_size (tuple): The image size. + polygons (np.ndarray): [N, M], N is the number of polygons, + M is the number of points(Be divided by 2). + """ + mask = np.zeros(img_size, dtype=np.uint8) + polygons = np.asarray(polygons) + polygons = polygons.astype(np.int32) + shape = polygons.shape + polygons = polygons.reshape(shape[0], -1, 2) + cv2.fillPoly(mask, polygons, color=color) + nh, nw = (img_size[0] // downsample_ratio, img_size[1] // downsample_ratio) + # NOTE: fillPoly firstly then resize is trying the keep the same way + # of loss calculation when mask-ratio=1. + mask = cv2.resize(mask, (nw, nh)) + return mask + + +def polygons2masks(img_size, polygons, color, downsample_ratio=1): + """ + Args: + img_size (tuple): The image size. + polygons (list[np.ndarray]): each polygon is [N, M], + N is the number of polygons, + M is the number of points(Be divided by 2). + """ + masks = [] + for si in range(len(polygons)): + mask = polygon2mask(img_size, [polygons[si].reshape(-1)], color, downsample_ratio) + masks.append(mask) + return np.array(masks) + + +def polygons2masks_overlap(img_size, segments, downsample_ratio=1): + """Return a (640, 640) overlap mask.""" + masks = np.zeros((img_size[0] // downsample_ratio, img_size[1] // downsample_ratio), + dtype=np.int32 if len(segments) > 255 else np.uint8) + areas = [] + ms = [] + for si in range(len(segments)): + mask = polygon2mask( + img_size, + [segments[si].reshape(-1)], + downsample_ratio=downsample_ratio, + color=1, + ) + ms.append(mask) + areas.append(mask.sum()) + areas = np.asarray(areas) + index = np.argsort(-areas) + ms = np.array(ms)[index] + for i in range(len(segments)): + mask = ms[i] * (i + 1) + masks = masks + mask + masks = np.clip(masks, a_min=0, a_max=i + 1) + return masks, index diff --git a/utils/segment/general.py b/utils/segment/general.py new file mode 100644 index 0000000000..9da8945386 --- /dev/null +++ b/utils/segment/general.py @@ -0,0 +1,160 @@ +import cv2 +import numpy as np +import torch +import torch.nn.functional as F + + +def crop_mask(masks, boxes): + """ + "Crop" predicted masks by zeroing out everything not in the predicted bbox. + Vectorized by Chong (thanks Chong). + + Args: + - masks should be a size [h, w, n] tensor of masks + - boxes should be a size [n, 4] tensor of bbox coords in relative point form + """ + + n, h, w = masks.shape + x1, y1, x2, y2 = torch.chunk(boxes[:, :, None], 4, 1) # x1 shape(1,1,n) + r = torch.arange(w, device=masks.device, dtype=x1.dtype)[None, None, :] # rows shape(1,w,1) + c = torch.arange(h, device=masks.device, dtype=x1.dtype)[None, :, None] # cols shape(h,1,1) + + return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2)) + + +def process_mask_upsample(protos, masks_in, bboxes, shape): + """ + Crop after upsample. + protos: [mask_dim, mask_h, mask_w] + masks_in: [n, mask_dim], n is number of masks after nms + bboxes: [n, 4], n is number of masks after nms + shape: input_image_size, (h, w) + + return: h, w, n + """ + + c, mh, mw = protos.shape # CHW + masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw) + masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW + masks = crop_mask(masks, bboxes) # CHW + return masks.gt_(0.5) + + +def process_mask(protos, masks_in, bboxes, shape, upsample=False): + """ + Crop before upsample. + proto_out: [mask_dim, mask_h, mask_w] + out_masks: [n, mask_dim], n is number of masks after nms + bboxes: [n, 4], n is number of masks after nms + shape:input_image_size, (h, w) + + return: h, w, n + """ + + c, mh, mw = protos.shape # CHW + ih, iw = shape + masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw) # CHW + + downsampled_bboxes = bboxes.clone() + downsampled_bboxes[:, 0] *= mw / iw + downsampled_bboxes[:, 2] *= mw / iw + downsampled_bboxes[:, 3] *= mh / ih + downsampled_bboxes[:, 1] *= mh / ih + + masks = crop_mask(masks, downsampled_bboxes) # CHW + if upsample: + masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW + return masks.gt_(0.5) + + +def process_mask_native(protos, masks_in, bboxes, shape): + """ + Crop after upsample. + protos: [mask_dim, mask_h, mask_w] + masks_in: [n, mask_dim], n is number of masks after nms + bboxes: [n, 4], n is number of masks after nms + shape: input_image_size, (h, w) + + return: h, w, n + """ + c, mh, mw = protos.shape # CHW + masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw) + gain = min(mh / shape[0], mw / shape[1]) # gain = old / new + pad = (mw - shape[1] * gain) / 2, (mh - shape[0] * gain) / 2 # wh padding + top, left = int(pad[1]), int(pad[0]) # y, x + bottom, right = int(mh - pad[1]), int(mw - pad[0]) + masks = masks[:, top:bottom, left:right] + + masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW + masks = crop_mask(masks, bboxes) # CHW + return masks.gt_(0.5) + + +def scale_image(im1_shape, masks, im0_shape, ratio_pad=None): + """ + img1_shape: model input shape, [h, w] + img0_shape: origin pic shape, [h, w, 3] + masks: [h, w, num] + """ + # Rescale coordinates (xyxy) from im1_shape to im0_shape + if ratio_pad is None: # calculate from im0_shape + gain = min(im1_shape[0] / im0_shape[0], im1_shape[1] / im0_shape[1]) # gain = old / new + pad = (im1_shape[1] - im0_shape[1] * gain) / 2, (im1_shape[0] - im0_shape[0] * gain) / 2 # wh padding + else: + pad = ratio_pad[1] + top, left = int(pad[1]), int(pad[0]) # y, x + bottom, right = int(im1_shape[0] - pad[1]), int(im1_shape[1] - pad[0]) + + if len(masks.shape) < 2: + raise ValueError(f'"len of masks shape" should be 2 or 3, but got {len(masks.shape)}') + masks = masks[top:bottom, left:right] + # masks = masks.permute(2, 0, 1).contiguous() + # masks = F.interpolate(masks[None], im0_shape[:2], mode='bilinear', align_corners=False)[0] + # masks = masks.permute(1, 2, 0).contiguous() + masks = cv2.resize(masks, (im0_shape[1], im0_shape[0])) + + if len(masks.shape) == 2: + masks = masks[:, :, None] + return masks + + +def mask_iou(mask1, mask2, eps=1e-7): + """ + mask1: [N, n] m1 means number of predicted objects + mask2: [M, n] m2 means number of gt objects + Note: n means image_w x image_h + + return: masks iou, [N, M] + """ + intersection = torch.matmul(mask1, mask2.t()).clamp(0) + union = (mask1.sum(1)[:, None] + mask2.sum(1)[None]) - intersection # (area1 + area2) - intersection + return intersection / (union + eps) + + +def masks_iou(mask1, mask2, eps=1e-7): + """ + mask1: [N, n] m1 means number of predicted objects + mask2: [N, n] m2 means number of gt objects + Note: n means image_w x image_h + + return: masks iou, (N, ) + """ + intersection = (mask1 * mask2).sum(1).clamp(0) # (N, ) + union = (mask1.sum(1) + mask2.sum(1))[None] - intersection # (area1 + area2) - intersection + return intersection / (union + eps) + + +def masks2segments(masks, strategy='largest'): + # Convert masks(n,160,160) into segments(n,xy) + segments = [] + for x in masks.int().cpu().numpy().astype('uint8'): + c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0] + if c: + if strategy == 'concat': # concatenate all segments + c = np.concatenate([x.reshape(-1, 2) for x in c]) + elif strategy == 'largest': # select largest segment + c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2) + else: + c = np.zeros((0, 2)) # no segments found + segments.append(c.astype('float32')) + return segments diff --git a/utils/segment/loss.py b/utils/segment/loss.py new file mode 100644 index 0000000000..b45b2c27e0 --- /dev/null +++ b/utils/segment/loss.py @@ -0,0 +1,186 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +from ..general import xywh2xyxy +from ..loss import FocalLoss, smooth_BCE +from ..metrics import bbox_iou +from ..torch_utils import de_parallel +from .general import crop_mask + + +class ComputeLoss: + # Compute losses + def __init__(self, model, autobalance=False, overlap=False): + self.sort_obj_iou = False + self.overlap = overlap + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + self.device = device + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device)) + BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device)) + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get('label_smoothing', 0.0)) # positive, negative BCE targets + + # Focal loss + g = h['fl_gamma'] # focal loss gamma + if g > 0: + BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.ssi = list(m.stride).index(16) if autobalance else 0 # stride 16 index + self.BCEcls, self.BCEobj, self.gr, self.hyp, self.autobalance = BCEcls, BCEobj, 1.0, h, autobalance + self.na = m.na # number of anchors + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.nm = m.nm # number of masks + self.anchors = m.anchors + self.device = device + + def __call__(self, preds, targets, masks): # predictions, targets, model + p, proto = preds + bs, nm, mask_h, mask_w = proto.shape # batch size, number of masks, mask height, mask width + lcls = torch.zeros(1, device=self.device) + lbox = torch.zeros(1, device=self.device) + lobj = torch.zeros(1, device=self.device) + lseg = torch.zeros(1, device=self.device) + tcls, tbox, indices, anchors, tidxs, xywhn = self.build_targets(p, targets) # targets + + # Losses + for i, pi in enumerate(p): # layer index, layer predictions + b, a, gj, gi = indices[i] # image, anchor, gridy, gridx + tobj = torch.zeros(pi.shape[:4], dtype=pi.dtype, device=self.device) # target obj + + n = b.shape[0] # number of targets + if n: + pxy, pwh, _, pcls, pmask = pi[b, a, gj, gi].split((2, 2, 1, self.nc, nm), 1) # subset of predictions + + # Box regression + pxy = pxy.sigmoid() * 2 - 0.5 + pwh = (pwh.sigmoid() * 2) ** 2 * anchors[i] + pbox = torch.cat((pxy, pwh), 1) # predicted box + iou = bbox_iou(pbox, tbox[i], CIoU=True).squeeze() # iou(prediction, target) + lbox += (1.0 - iou).mean() # iou loss + + # Objectness + iou = iou.detach().clamp(0).type(tobj.dtype) + if self.sort_obj_iou: + j = iou.argsort() + b, a, gj, gi, iou = b[j], a[j], gj[j], gi[j], iou[j] + if self.gr < 1: + iou = (1.0 - self.gr) + self.gr * iou + tobj[b, a, gj, gi] = iou # iou ratio + + # Classification + if self.nc > 1: # cls loss (only if multiple classes) + t = torch.full_like(pcls, self.cn, device=self.device) # targets + t[range(n), tcls[i]] = self.cp + lcls += self.BCEcls(pcls, t) # BCE + + # Mask regression + if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample + masks = F.interpolate(masks[None], (mask_h, mask_w), mode="nearest")[0] + marea = xywhn[i][:, 2:].prod(1) # mask width, height normalized + mxyxy = xywh2xyxy(xywhn[i] * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device)) + for bi in b.unique(): + j = b == bi # matching index + if self.overlap: + mask_gti = torch.where(masks[bi][None] == tidxs[i][j].view(-1, 1, 1), 1.0, 0.0) + else: + mask_gti = masks[tidxs[i]][j] + lseg += self.single_mask_loss(mask_gti, pmask[j], proto[bi], mxyxy[j], marea[j]) + + obji = self.BCEobj(pi[..., 4], tobj) + lobj += obji * self.balance[i] # obj loss + if self.autobalance: + self.balance[i] = self.balance[i] * 0.9999 + 0.0001 / obji.detach().item() + + if self.autobalance: + self.balance = [x / self.balance[self.ssi] for x in self.balance] + lbox *= self.hyp["box"] + lobj *= self.hyp["obj"] + lcls *= self.hyp["cls"] + lseg *= self.hyp["box"] / bs + + loss = lbox + lobj + lcls + lseg + return loss * bs, torch.cat((lbox, lseg, lobj, lcls)).detach() + + def single_mask_loss(self, gt_mask, pred, proto, xyxy, area): + # Mask loss for one image + pred_mask = (pred @ proto.view(self.nm, -1)).view(-1, *proto.shape[1:]) # (n,32) @ (32,80,80) -> (n,80,80) + loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction="none") + return (crop_mask(loss, xyxy).mean(dim=(1, 2)) / area).mean() + + def build_targets(self, p, targets): + # Build targets for compute_loss(), input targets(image,class,x,y,w,h) + na, nt = self.na, targets.shape[0] # number of anchors, targets + tcls, tbox, indices, anch, tidxs, xywhn = [], [], [], [], [], [] + gain = torch.ones(8, device=self.device) # normalized to gridspace gain + ai = torch.arange(na, device=self.device).float().view(na, 1).repeat(1, nt) # same as .repeat_interleave(nt) + if self.overlap: + batch = p[0].shape[0] + ti = [] + for i in range(batch): + num = (targets[:, 0] == i).sum() # find number of targets of each image + ti.append(torch.arange(num, device=self.device).float().view(1, num).repeat(na, 1) + 1) # (na, num) + ti = torch.cat(ti, 1) # (na, nt) + else: + ti = torch.arange(nt, device=self.device).float().view(1, nt).repeat(na, 1) + targets = torch.cat((targets.repeat(na, 1, 1), ai[..., None], ti[..., None]), 2) # append anchor indices + + g = 0.5 # bias + off = torch.tensor( + [ + [0, 0], + [1, 0], + [0, 1], + [-1, 0], + [0, -1], # j,k,l,m + # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm + ], + device=self.device).float() * g # offsets + + for i in range(self.nl): + anchors, shape = self.anchors[i], p[i].shape + gain[2:6] = torch.tensor(shape)[[3, 2, 3, 2]] # xyxy gain + + # Match targets to anchors + t = targets * gain # shape(3,n,7) + if nt: + # Matches + r = t[..., 4:6] / anchors[:, None] # wh ratio + j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t'] # compare + # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2)) + t = t[j] # filter + + # Offsets + gxy = t[:, 2:4] # grid xy + gxi = gain[[2, 3]] - gxy # inverse + j, k = ((gxy % 1 < g) & (gxy > 1)).T + l, m = ((gxi % 1 < g) & (gxi > 1)).T + j = torch.stack((torch.ones_like(j), j, k, l, m)) + t = t.repeat((5, 1, 1))[j] + offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j] + else: + t = targets[0] + offsets = 0 + + # Define + bc, gxy, gwh, at = t.chunk(4, 1) # (image, class), grid xy, grid wh, anchors + (a, tidx), (b, c) = at.long().T, bc.long().T # anchors, image, class + gij = (gxy - offsets).long() + gi, gj = gij.T # grid indices + + # Append + indices.append((b, a, gj.clamp_(0, shape[2] - 1), gi.clamp_(0, shape[3] - 1))) # image, anchor, grid + tbox.append(torch.cat((gxy - gij, gwh), 1)) # box + anch.append(anchors[a]) # anchors + tcls.append(c) # class + tidxs.append(tidx) + xywhn.append(torch.cat((gxy, gwh), 1) / gain[2:6]) # xywh normalized + + return tcls, tbox, indices, anch, tidxs, xywhn diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py new file mode 100644 index 0000000000..312e585893 --- /dev/null +++ b/utils/segment/metrics.py @@ -0,0 +1,210 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" +Model validation metrics +""" + +import numpy as np + +from ..metrics import ap_per_class + + +def fitness(x): + # Model fitness as a weighted combination of metrics + w = [0.0, 0.0, 0.1, 0.9, 0.0, 0.0, 0.1, 0.9] + return (x[:, :8] * w).sum(1) + + +def ap_per_class_box_and_mask( + tp_m, + tp_b, + conf, + pred_cls, + target_cls, + plot=False, + save_dir=".", + names=(), +): + """ + Args: + tp_b: tp of boxes. + tp_m: tp of masks. + other arguments see `func: ap_per_class`. + """ + results_boxes = ap_per_class(tp_b, + conf, + pred_cls, + target_cls, + plot=plot, + save_dir=save_dir, + names=names, + prefix="Box")[2:] + results_masks = ap_per_class(tp_m, + conf, + pred_cls, + target_cls, + plot=plot, + save_dir=save_dir, + names=names, + prefix="Mask")[2:] + + results = { + "boxes": { + "p": results_boxes[0], + "r": results_boxes[1], + "ap": results_boxes[3], + "f1": results_boxes[2], + "ap_class": results_boxes[4]}, + "masks": { + "p": results_masks[0], + "r": results_masks[1], + "ap": results_masks[3], + "f1": results_masks[2], + "ap_class": results_masks[4]}} + return results + + +class Metric: + + def __init__(self) -> None: + self.p = [] # (nc, ) + self.r = [] # (nc, ) + self.f1 = [] # (nc, ) + self.all_ap = [] # (nc, 10) + self.ap_class_index = [] # (nc, ) + + @property + def ap50(self): + """AP@0.5 of all classes. + Return: + (nc, ) or []. + """ + return self.all_ap[:, 0] if len(self.all_ap) else [] + + @property + def ap(self): + """AP@0.5:0.95 + Return: + (nc, ) or []. + """ + return self.all_ap.mean(1) if len(self.all_ap) else [] + + @property + def mp(self): + """mean precision of all classes. + Return: + float. + """ + return self.p.mean() if len(self.p) else 0.0 + + @property + def mr(self): + """mean recall of all classes. + Return: + float. + """ + return self.r.mean() if len(self.r) else 0.0 + + @property + def map50(self): + """Mean AP@0.5 of all classes. + Return: + float. + """ + return self.all_ap[:, 0].mean() if len(self.all_ap) else 0.0 + + @property + def map(self): + """Mean AP@0.5:0.95 of all classes. + Return: + float. + """ + return self.all_ap.mean() if len(self.all_ap) else 0.0 + + def mean_results(self): + """Mean of results, return mp, mr, map50, map""" + return (self.mp, self.mr, self.map50, self.map) + + def class_result(self, i): + """class-aware result, return p[i], r[i], ap50[i], ap[i]""" + return (self.p[i], self.r[i], self.ap50[i], self.ap[i]) + + def get_maps(self, nc): + maps = np.zeros(nc) + self.map + for i, c in enumerate(self.ap_class_index): + maps[c] = self.ap[i] + return maps + + def update(self, results): + """ + Args: + results: tuple(p, r, ap, f1, ap_class) + """ + p, r, all_ap, f1, ap_class_index = results + self.p = p + self.r = r + self.all_ap = all_ap + self.f1 = f1 + self.ap_class_index = ap_class_index + + +class Metrics: + """Metric for boxes and masks.""" + + def __init__(self) -> None: + self.metric_box = Metric() + self.metric_mask = Metric() + + def update(self, results): + """ + Args: + results: Dict{'boxes': Dict{}, 'masks': Dict{}} + """ + self.metric_box.update(list(results["boxes"].values())) + self.metric_mask.update(list(results["masks"].values())) + + def mean_results(self): + return self.metric_box.mean_results() + self.metric_mask.mean_results() + + def class_result(self, i): + return self.metric_box.class_result(i) + self.metric_mask.class_result(i) + + def get_maps(self, nc): + return self.metric_box.get_maps(nc) + self.metric_mask.get_maps(nc) + + @property + def ap_class_index(self): + # boxes and masks have the same ap_class_index + return self.metric_box.ap_class_index + + +KEYS = [ + "train/box_loss", + "train/seg_loss", # train loss + "train/obj_loss", + "train/cls_loss", + "metrics/precision(B)", + "metrics/recall(B)", + "metrics/mAP_0.5(B)", + "metrics/mAP_0.5:0.95(B)", # metrics + "metrics/precision(M)", + "metrics/recall(M)", + "metrics/mAP_0.5(M)", + "metrics/mAP_0.5:0.95(M)", # metrics + "val/box_loss", + "val/seg_loss", # val loss + "val/obj_loss", + "val/cls_loss", + "x/lr0", + "x/lr1", + "x/lr2",] + +BEST_KEYS = [ + "best/epoch", + "best/precision(B)", + "best/recall(B)", + "best/mAP_0.5(B)", + "best/mAP_0.5:0.95(B)", + "best/precision(M)", + "best/recall(M)", + "best/mAP_0.5(M)", + "best/mAP_0.5:0.95(M)",] diff --git a/utils/segment/plots.py b/utils/segment/plots.py new file mode 100644 index 0000000000..9b90900b37 --- /dev/null +++ b/utils/segment/plots.py @@ -0,0 +1,143 @@ +import contextlib +import math +from pathlib import Path + +import cv2 +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import torch + +from .. import threaded +from ..general import xywh2xyxy +from ..plots import Annotator, colors + + +@threaded +def plot_images_and_masks(images, targets, masks, paths=None, fname='images.jpg', names=None): + # Plot image grid with labels + if isinstance(images, torch.Tensor): + images = images.cpu().float().numpy() + if isinstance(targets, torch.Tensor): + targets = targets.cpu().numpy() + if isinstance(masks, torch.Tensor): + masks = masks.cpu().numpy().astype(int) + + max_size = 1920 # max image size + max_subplots = 16 # max image subplots, i.e. 4x4 + bs, _, h, w = images.shape # batch size, _, height, width + bs = min(bs, max_subplots) # limit plot images + ns = np.ceil(bs ** 0.5) # number of subplots (square) + if np.max(images[0]) <= 1: + images *= 255 # de-normalise (optional) + + # Build Image + mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) # init + for i, im in enumerate(images): + if i == max_subplots: # if last batch has fewer images than we expect + break + x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin + im = im.transpose(1, 2, 0) + mosaic[y:y + h, x:x + w, :] = im + + # Resize (optional) + scale = max_size / ns / max(h, w) + if scale < 1: + h = math.ceil(scale * h) + w = math.ceil(scale * w) + mosaic = cv2.resize(mosaic, tuple(int(x * ns) for x in (w, h))) + + # Annotate + fs = int((h + w) * ns * 0.01) # font size + annotator = Annotator(mosaic, line_width=round(fs / 10), font_size=fs, pil=True, example=names) + for i in range(i + 1): + x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin + annotator.rectangle([x, y, x + w, y + h], None, (255, 255, 255), width=2) # borders + if paths: + annotator.text((x + 5, y + 5 + h), text=Path(paths[i]).name[:40], txt_color=(220, 220, 220)) # filenames + if len(targets) > 0: + idx = targets[:, 0] == i + ti = targets[idx] # image targets + + boxes = xywh2xyxy(ti[:, 2:6]).T + classes = ti[:, 1].astype('int') + labels = ti.shape[1] == 6 # labels if no conf column + conf = None if labels else ti[:, 6] # check for confidence presence (label vs pred) + + if boxes.shape[1]: + if boxes.max() <= 1.01: # if normalized with tolerance 0.01 + boxes[[0, 2]] *= w # scale to pixels + boxes[[1, 3]] *= h + elif scale < 1: # absolute coords need scale if image scales + boxes *= scale + boxes[[0, 2]] += x + boxes[[1, 3]] += y + for j, box in enumerate(boxes.T.tolist()): + cls = classes[j] + color = colors(cls) + cls = names[cls] if names else cls + if labels or conf[j] > 0.25: # 0.25 conf thresh + label = f'{cls}' if labels else f'{cls} {conf[j]:.1f}' + annotator.box_label(box, label, color=color) + + # Plot masks + if len(masks): + if masks.max() > 1.0: # mean that masks are overlap + image_masks = masks[[i]] # (1, 640, 640) + nl = len(ti) + index = np.arange(nl).reshape(nl, 1, 1) + 1 + image_masks = np.repeat(image_masks, nl, axis=0) + image_masks = np.where(image_masks == index, 1.0, 0.0) + else: + image_masks = masks[idx] + + im = np.asarray(annotator.im).copy() + for j, box in enumerate(boxes.T.tolist()): + if labels or conf[j] > 0.25: # 0.25 conf thresh + color = colors(classes[j]) + mh, mw = image_masks[j].shape + if mh != h or mw != w: + mask = image_masks[j].astype(np.uint8) + mask = cv2.resize(mask, (w, h)) + mask = mask.astype(bool) + else: + mask = image_masks[j].astype(bool) + with contextlib.suppress(Exception): + im[y:y + h, x:x + w, :][mask] = im[y:y + h, x:x + w, :][mask] * 0.4 + np.array(color) * 0.6 + annotator.fromarray(im) + annotator.im.save(fname) # save + + +def plot_results_with_masks(file="path/to/results.csv", dir="", best=True): + # Plot training results.csv. Usage: from utils.plots import *; plot_results('path/to/results.csv') + save_dir = Path(file).parent if file else Path(dir) + fig, ax = plt.subplots(2, 8, figsize=(18, 6), tight_layout=True) + ax = ax.ravel() + files = list(save_dir.glob("results*.csv")) + assert len(files), f"No results.csv files found in {save_dir.resolve()}, nothing to plot." + for f in files: + try: + data = pd.read_csv(f) + index = np.argmax(0.9 * data.values[:, 8] + 0.1 * data.values[:, 7] + 0.9 * data.values[:, 12] + + 0.1 * data.values[:, 11]) + s = [x.strip() for x in data.columns] + x = data.values[:, 0] + for i, j in enumerate([1, 2, 3, 4, 5, 6, 9, 10, 13, 14, 15, 16, 7, 8, 11, 12]): + y = data.values[:, j] + # y[y == 0] = np.nan # don't show zero values + ax[i].plot(x, y, marker=".", label=f.stem, linewidth=2, markersize=2) + if best: + # best + ax[i].scatter(index, y[index], color="r", label=f"best:{index}", marker="*", linewidth=3) + ax[i].set_title(s[j] + f"\n{round(y[index], 5)}") + else: + # last + ax[i].scatter(x[-1], y[-1], color="r", label="last", marker="*", linewidth=3) + ax[i].set_title(s[j] + f"\n{round(y[-1], 5)}") + # if j in [8, 9, 10]: # share train and val loss y axes + # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) + except Exception as e: + print(f"Warning: Plotting error for {f}: {e}") + ax[1].legend() + fig.savefig(save_dir / "results.png", dpi=200) + plt.close() diff --git a/utils/torch_utils.py b/utils/torch_utils.py index d3692297aa..f259be7acb 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -3,12 +3,12 @@ PyTorch utils """ -import datetime import math import os import platform import subprocess import time +import warnings from contextlib import contextmanager from copy import deepcopy from pathlib import Path @@ -17,20 +17,77 @@ import torch.distributed as dist import torch.nn as nn import torch.nn.functional as F +from torch.nn.parallel import DistributedDataParallel as DDP -from utils.general import LOGGER +from utils.general import LOGGER, check_version, colorstr, file_date, git_describe + +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) try: import thop # for FLOPs computation except ImportError: thop = None +# Suppress PyTorch warnings +warnings.filterwarnings('ignore', message='User provided device_type of \'cuda\', but CUDA is not available. Disabling') +warnings.filterwarnings('ignore', category=UserWarning) + + +def smart_inference_mode(torch_1_9=check_version(torch.__version__, '1.9.0')): + # Applies torch.inference_mode() decorator if torch>=1.9.0 else torch.no_grad() decorator + def decorate(fn): + return (torch.inference_mode if torch_1_9 else torch.no_grad)()(fn) + + return decorate + + +def smartCrossEntropyLoss(label_smoothing=0.0): + # Returns nn.CrossEntropyLoss with label smoothing enabled for torch>=1.10.0 + if check_version(torch.__version__, '1.10.0'): + return nn.CrossEntropyLoss(label_smoothing=label_smoothing) + if label_smoothing > 0: + LOGGER.warning(f'WARNING ⚠️ label smoothing {label_smoothing} requires torch>=1.10.0') + return nn.CrossEntropyLoss() + + +def smart_DDP(model): + # Model DDP creation with checks + assert not check_version(torch.__version__, '1.12.0', pinned=True), \ + 'torch==1.12.0 torchvision==0.13.0 DDP training is not supported due to a known issue. ' \ + 'Please upgrade or downgrade torch to use DDP. See https://github.com/ultralytics/yolov5/issues/8395' + if check_version(torch.__version__, '1.11.0'): + return DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK, static_graph=True) + else: + return DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK) + + +def reshape_classifier_output(model, n=1000): + # Update a TorchVision classification model to class count 'n' if required + from models.common import Classify + name, m = list((model.model if hasattr(model, 'model') else model).named_children())[-1] # last module + if isinstance(m, Classify): # YOLOv3 Classify() head + if m.linear.out_features != n: + m.linear = nn.Linear(m.linear.in_features, n) + elif isinstance(m, nn.Linear): # ResNet, EfficientNet + if m.out_features != n: + setattr(model, name, nn.Linear(m.in_features, n)) + elif isinstance(m, nn.Sequential): + types = [type(x) for x in m] + if nn.Linear in types: + i = types.index(nn.Linear) # nn.Linear index + if m[i].out_features != n: + m[i] = nn.Linear(m[i].in_features, n) + elif nn.Conv2d in types: + i = types.index(nn.Conv2d) # nn.Conv2d index + if m[i].out_channels != n: + m[i] = nn.Conv2d(m[i].in_channels, n, m[i].kernel_size, m[i].stride, bias=m[i].bias is not None) + @contextmanager def torch_distributed_zero_first(local_rank: int): - """ - Decorator to make all processes in distributed training wait for each local_master to do something. - """ + # Decorator to make all processes in distributed training wait for each local_master to do something if local_rank not in [-1, 0]: dist.barrier(device_ids=[local_rank]) yield @@ -38,69 +95,70 @@ def torch_distributed_zero_first(local_rank: int): dist.barrier(device_ids=[0]) -def date_modified(path=__file__): - # return human-readable file modification date, i.e. '2021-3-26' - t = datetime.datetime.fromtimestamp(Path(path).stat().st_mtime) - return f'{t.year}-{t.month}-{t.day}' - - -def git_describe(path=Path(__file__).parent): # path must be a directory - # return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe - s = f'git -C {path} describe --tags --long --always' +def device_count(): + # Returns number of CUDA devices available. Safe version of torch.cuda.device_count(). Supports Linux and Windows + assert platform.system() in ('Linux', 'Windows'), 'device_count() only supported on Linux or Windows' try: - return subprocess.check_output(s, shell=True, stderr=subprocess.STDOUT).decode()[:-1] - except subprocess.CalledProcessError as e: - return '' # not a git repository + cmd = 'nvidia-smi -L | wc -l' if platform.system() == 'Linux' else 'nvidia-smi -L | find /c /v ""' # Windows + return int(subprocess.run(cmd, shell=True, capture_output=True, check=True).stdout.decode().split()[-1]) + except Exception: + return 0 -def select_device(device='', batch_size=None, newline=True): - # device = 'cpu' or '0' or '0,1,2,3' - s = f'YOLOv3 🚀 {git_describe() or date_modified()} torch {torch.__version__} ' # string - device = str(device).strip().lower().replace('cuda:', '') # to string, 'cuda:0' to '0' +def select_device(device='', batch_size=0, newline=True): + # device = None or 'cpu' or 0 or '0' or '0,1,2,3' + s = f'YOLOv3 🚀 {git_describe() or file_date()} Python-{platform.python_version()} torch-{torch.__version__} ' + device = str(device).strip().lower().replace('cuda:', '').replace('none', '') # to string, 'cuda:0' to '0' cpu = device == 'cpu' - if cpu: + mps = device == 'mps' # Apple Metal Performance Shaders (MPS) + if cpu or mps: os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # force torch.cuda.is_available() = False elif device: # non-cpu device requested - os.environ['CUDA_VISIBLE_DEVICES'] = device # set environment variable - assert torch.cuda.is_available(), f'CUDA unavailable, invalid device {device} requested' # check availability + os.environ['CUDA_VISIBLE_DEVICES'] = device # set environment variable - must be before assert is_available() + assert torch.cuda.is_available() and torch.cuda.device_count() >= len(device.replace(',', '')), \ + f"Invalid CUDA '--device {device}' requested, use '--device cpu' or pass valid CUDA device(s)" - cuda = not cpu and torch.cuda.is_available() - if cuda: + if not cpu and not mps and torch.cuda.is_available(): # prefer GPU if available devices = device.split(',') if device else '0' # range(torch.cuda.device_count()) # i.e. 0,1,6,7 n = len(devices) # device count - if n > 1 and batch_size: # check batch_size is divisible by device_count + if n > 1 and batch_size > 0: # check batch_size is divisible by device_count assert batch_size % n == 0, f'batch-size {batch_size} not multiple of GPU count {n}' space = ' ' * (len(s) + 1) for i, d in enumerate(devices): p = torch.cuda.get_device_properties(i) - s += f"{'' if i == 0 else space}CUDA:{d} ({p.name}, {p.total_memory / 1024 ** 2:.0f}MiB)\n" # bytes to MB - else: + s += f"{'' if i == 0 else space}CUDA:{d} ({p.name}, {p.total_memory / (1 << 20):.0f}MiB)\n" # bytes to MB + arg = 'cuda:0' + elif mps and getattr(torch, 'has_mps', False) and torch.backends.mps.is_available(): # prefer MPS if available + s += 'MPS\n' + arg = 'mps' + else: # revert to CPU s += 'CPU\n' + arg = 'cpu' if not newline: s = s.rstrip() - LOGGER.info(s.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else s) # emoji-safe - return torch.device('cuda:0' if cuda else 'cpu') + LOGGER.info(s) + return torch.device(arg) def time_sync(): - # pytorch-accurate time + # PyTorch-accurate time if torch.cuda.is_available(): torch.cuda.synchronize() return time.time() def profile(input, ops, n=10, device=None): - # speed/memory/FLOPs profiler - # - # Usage: - # input = torch.randn(16, 3, 640, 640) - # m1 = lambda x: x * torch.sigmoid(x) - # m2 = nn.SiLU() - # profile(input, [m1, m2], n=100) # profile over 100 iterations - + """ YOLOv3 speed/memory/FLOPs profiler + Usage: + input = torch.randn(16, 3, 640, 640) + m1 = lambda x: x * torch.sigmoid(x) + m2 = nn.SiLU() + profile(input, [m1, m2], n=100) # profile over 100 iterations + """ results = [] - device = device or select_device() + if not isinstance(device, torch.device): + device = select_device(device) print(f"{'Params':>12s}{'GFLOPs':>12s}{'GPU_mem (GB)':>14s}{'forward (ms)':>14s}{'backward (ms)':>14s}" f"{'input':>24s}{'output':>24s}") @@ -113,7 +171,7 @@ def profile(input, ops, n=10, device=None): tf, tb, t = 0, 0, [0, 0, 0] # dt forward, backward try: flops = thop.profile(m, inputs=(x,), verbose=False)[0] / 1E9 * 2 # GFLOPs - except: + except Exception: flops = 0 try: @@ -124,15 +182,14 @@ def profile(input, ops, n=10, device=None): try: _ = (sum(yi.sum() for yi in y) if isinstance(y, list) else y).sum().backward() t[2] = time_sync() - except Exception as e: # no backward method + except Exception: # no backward method # print(e) # for debug t[2] = float('nan') tf += (t[1] - t[0]) * 1000 / n # ms per op forward tb += (t[2] - t[1]) * 1000 / n # ms per op backward mem = torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0 # (GB) - s_in = tuple(x.shape) if isinstance(x, torch.Tensor) else 'list' - s_out = tuple(y.shape) if isinstance(y, torch.Tensor) else 'list' - p = sum(list(x.numel() for x in m.parameters())) if isinstance(m, nn.Module) else 0 # parameters + s_in, s_out = (tuple(x.shape) if isinstance(x, torch.Tensor) else 'list' for x in (x, y)) # shapes + p = sum(x.numel() for x in m.parameters()) if isinstance(m, nn.Module) else 0 # parameters print(f'{p:12}{flops:12.4g}{mem:>14.3f}{tf:14.4g}{tb:14.4g}{str(s_in):>24s}{str(s_out):>24s}') results.append([p, flops, mem, tf, tb, s_in, s_out]) except Exception as e: @@ -181,30 +238,30 @@ def sparsity(model): def prune(model, amount=0.3): # Prune model to requested global sparsity import torch.nn.utils.prune as prune - print('Pruning model... ', end='') for name, m in model.named_modules(): if isinstance(m, nn.Conv2d): prune.l1_unstructured(m, name='weight', amount=amount) # prune prune.remove(m, 'weight') # make permanent - print(' %.3g global sparsity' % sparsity(model)) + LOGGER.info(f'Model pruned to {sparsity(model):.3g} global sparsity') def fuse_conv_and_bn(conv, bn): - # Fuse convolution and batchnorm layers https://tehnokv.com/posts/fusing-batchnorm-and-conv/ + # Fuse Conv2d() and BatchNorm2d() layers https://tehnokv.com/posts/fusing-batchnorm-and-conv/ fusedconv = nn.Conv2d(conv.in_channels, conv.out_channels, kernel_size=conv.kernel_size, stride=conv.stride, padding=conv.padding, + dilation=conv.dilation, groups=conv.groups, bias=True).requires_grad_(False).to(conv.weight.device) - # prepare filters + # Prepare filters w_conv = conv.weight.clone().view(conv.out_channels, -1) w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var))) fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.shape)) - # prepare spatial bias + # Prepare spatial bias b_conv = torch.zeros(conv.weight.size(0), device=conv.weight.device) if conv.bias is None else conv.bias b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(torch.sqrt(bn.running_var + bn.eps)) fusedconv.bias.copy_(torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn) @@ -212,7 +269,7 @@ def fuse_conv_and_bn(conv, bn): return fusedconv -def model_info(model, verbose=False, img_size=640): +def model_info(model, verbose=False, imgsz=640): # Model information. img_size may be int or list, i.e. img_size=640 or img_size=[640, 320] n_p = sum(x.numel() for x in model.parameters()) # number parameters n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients @@ -224,29 +281,29 @@ def model_info(model, verbose=False, img_size=640): (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) try: # FLOPs - from thop import profile - stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32 - img = torch.zeros((1, model.yaml.get('ch', 3), stride, stride), device=next(model.parameters()).device) # input - flops = profile(deepcopy(model), inputs=(img,), verbose=False)[0] / 1E9 * 2 # stride GFLOPs - img_size = img_size if isinstance(img_size, list) else [img_size, img_size] # expand if int/float - fs = ', %.1f GFLOPs' % (flops * img_size[0] / stride * img_size[1] / stride) # 640x640 GFLOPs - except (ImportError, Exception): + p = next(model.parameters()) + stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32 # max stride + im = torch.empty((1, p.shape[1], stride, stride), device=p.device) # input image in BCHW format + flops = thop.profile(deepcopy(model), inputs=(im,), verbose=False)[0] / 1E9 * 2 # stride GFLOPs + imgsz = imgsz if isinstance(imgsz, list) else [imgsz, imgsz] # expand if int/float + fs = f', {flops * imgsz[0] / stride * imgsz[1] / stride:.1f} GFLOPs' # 640x640 GFLOPs + except Exception: fs = '' - LOGGER.info(f"Model Summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}") + name = Path(model.yaml_file).stem.replace('yolov5', 'YOLOv3') if hasattr(model, 'yaml_file') else 'Model' + LOGGER.info(f"{name} summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}") def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416) - # scales img(bs,3,y,x) by ratio constrained to gs-multiple + # Scales img(bs,3,y,x) by ratio constrained to gs-multiple if ratio == 1.0: return img - else: - h, w = img.shape[2:] - s = (int(h * ratio), int(w * ratio)) # new size - img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize - if not same_shape: # pad/crop img - h, w = (math.ceil(x * ratio / gs) * gs for x in (h, w)) - return F.pad(img, [0, w - s[1], 0, h - s[0]], value=0.447) # value = imagenet mean + h, w = img.shape[2:] + s = (int(h * ratio), int(w * ratio)) # new size + img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize + if not same_shape: # pad/crop img + h, w = (math.ceil(x * ratio / gs) * gs for x in (h, w)) + return F.pad(img, [0, w - s[1], 0, h - s[0]], value=0.447) # value = imagenet mean def copy_attr(a, b, include=(), exclude=()): @@ -258,8 +315,71 @@ def copy_attr(a, b, include=(), exclude=()): setattr(a, k, v) +def smart_optimizer(model, name='Adam', lr=0.001, momentum=0.9, decay=1e-5): + # YOLOv3 3-param group optimizer: 0) weights with decay, 1) weights no decay, 2) biases no decay + g = [], [], [] # optimizer parameter groups + bn = tuple(v for k, v in nn.__dict__.items() if 'Norm' in k) # normalization layers, i.e. BatchNorm2d() + for v in model.modules(): + for p_name, p in v.named_parameters(recurse=0): + if p_name == 'bias': # bias (no decay) + g[2].append(p) + elif p_name == 'weight' and isinstance(v, bn): # weight (no decay) + g[1].append(p) + else: + g[0].append(p) # weight (with decay) + + if name == 'Adam': + optimizer = torch.optim.Adam(g[2], lr=lr, betas=(momentum, 0.999)) # adjust beta1 to momentum + elif name == 'AdamW': + optimizer = torch.optim.AdamW(g[2], lr=lr, betas=(momentum, 0.999), weight_decay=0.0) + elif name == 'RMSProp': + optimizer = torch.optim.RMSprop(g[2], lr=lr, momentum=momentum) + elif name == 'SGD': + optimizer = torch.optim.SGD(g[2], lr=lr, momentum=momentum, nesterov=True) + else: + raise NotImplementedError(f'Optimizer {name} not implemented.') + + optimizer.add_param_group({'params': g[0], 'weight_decay': decay}) # add g0 with weight_decay + optimizer.add_param_group({'params': g[1], 'weight_decay': 0.0}) # add g1 (BatchNorm2d weights) + LOGGER.info(f"{colorstr('optimizer:')} {type(optimizer).__name__}(lr={lr}) with parameter groups " + f"{len(g[1])} weight(decay=0.0), {len(g[0])} weight(decay={decay}), {len(g[2])} bias") + return optimizer + + +def smart_hub_load(repo='ultralytics/yolov5', model='yolov5s', **kwargs): + # YOLOv3 torch.hub.load() wrapper with smart error/issue handling + if check_version(torch.__version__, '1.9.1'): + kwargs['skip_validation'] = True # validation causes GitHub API rate limit errors + if check_version(torch.__version__, '1.12.0'): + kwargs['trust_repo'] = True # argument required starting in torch 0.12 + try: + return torch.hub.load(repo, model, **kwargs) + except Exception: + return torch.hub.load(repo, model, force_reload=True, **kwargs) + + +def smart_resume(ckpt, optimizer, ema=None, weights='yolov5s.pt', epochs=300, resume=True): + # Resume training from a partially trained checkpoint + best_fitness = 0.0 + start_epoch = ckpt['epoch'] + 1 + if ckpt['optimizer'] is not None: + optimizer.load_state_dict(ckpt['optimizer']) # optimizer + best_fitness = ckpt['best_fitness'] + if ema and ckpt.get('ema'): + ema.ema.load_state_dict(ckpt['ema'].float().state_dict()) # EMA + ema.updates = ckpt['updates'] + if resume: + assert start_epoch > 0, f'{weights} training to {epochs} epochs is finished, nothing to resume.\n' \ + f"Start a new training without --resume, i.e. 'python train.py --weights {weights}'" + LOGGER.info(f'Resuming training from {weights} from epoch {start_epoch} to {epochs} total epochs') + if epochs < start_epoch: + LOGGER.info(f"{weights} has been trained for {ckpt['epoch']} epochs. Fine-tuning for {epochs} more epochs.") + epochs += ckpt['epoch'] # finetune additional epochs + return best_fitness, start_epoch, epochs + + class EarlyStopping: - # simple early stopper + # YOLOv3 simple early stopper def __init__(self, patience=30): self.best_fitness = 0.0 # i.e. mAP self.best_epoch = 0 @@ -282,36 +402,30 @@ def __call__(self, epoch, fitness): class ModelEMA: - """ Model Exponential Moving Average from https://github.com/rwightman/pytorch-image-models - Keep a moving average of everything in the model state_dict (parameters and buffers). - This is intended to allow functionality like - https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage - A smoothed version of the weights is necessary for some training schemes to perform well. - This class is sensitive where it is initialized in the sequence of model init, - GPU assignment and distributed training wrappers. + """ Updated Exponential Moving Average (EMA) from https://github.com/rwightman/pytorch-image-models + Keeps a moving average of everything in the model state_dict (parameters and buffers) + For EMA details see https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage """ - def __init__(self, model, decay=0.9999, updates=0): + def __init__(self, model, decay=0.9999, tau=2000, updates=0): # Create EMA - self.ema = deepcopy(model.module if is_parallel(model) else model).eval() # FP32 EMA - # if next(model.parameters()).device.type != 'cpu': - # self.ema.half() # FP16 EMA + self.ema = deepcopy(de_parallel(model)).eval() # FP32 EMA self.updates = updates # number of EMA updates - self.decay = lambda x: decay * (1 - math.exp(-x / 2000)) # decay exponential ramp (to help early epochs) + self.decay = lambda x: decay * (1 - math.exp(-x / tau)) # decay exponential ramp (to help early epochs) for p in self.ema.parameters(): p.requires_grad_(False) def update(self, model): # Update EMA parameters - with torch.no_grad(): - self.updates += 1 - d = self.decay(self.updates) - - msd = model.module.state_dict() if is_parallel(model) else model.state_dict() # model state_dict - for k, v in self.ema.state_dict().items(): - if v.dtype.is_floating_point: - v *= d - v += (1 - d) * msd[k].detach() + self.updates += 1 + d = self.decay(self.updates) + + msd = de_parallel(model).state_dict() # model state_dict + for k, v in self.ema.state_dict().items(): + if v.dtype.is_floating_point: # true for FP16 and FP32 + v *= d + v += (1 - d) * msd[k].detach() + # assert v.dtype == msd[k].dtype == torch.float32, f'{k}: EMA {v.dtype} and model {msd[k].dtype} must be FP32' def update_attr(self, model, include=(), exclude=('process_group', 'reducer')): # Update EMA attributes diff --git a/utils/triton.py b/utils/triton.py new file mode 100644 index 0000000000..f067eeafaa --- /dev/null +++ b/utils/triton.py @@ -0,0 +1,85 @@ +# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +""" Utils to interact with the Triton Inference Server +""" + +import typing +from urllib.parse import urlparse + +import torch + + +class TritonRemoteModel: + """ A wrapper over a model served by the Triton Inference Server. It can + be configured to communicate over GRPC or HTTP. It accepts Torch Tensors + as input and returns them as outputs. + """ + + def __init__(self, url: str): + """ + Keyword arguments: + url: Fully qualified address of the Triton server - for e.g. grpc://localhost:8000 + """ + + parsed_url = urlparse(url) + if parsed_url.scheme == "grpc": + from tritonclient.grpc import InferenceServerClient, InferInput + + self.client = InferenceServerClient(parsed_url.netloc) # Triton GRPC client + model_repository = self.client.get_model_repository_index() + self.model_name = model_repository.models[0].name + self.metadata = self.client.get_model_metadata(self.model_name, as_json=True) + + def create_input_placeholders() -> typing.List[InferInput]: + return [ + InferInput(i['name'], [int(s) for s in i["shape"]], i['datatype']) for i in self.metadata['inputs']] + + else: + from tritonclient.http import InferenceServerClient, InferInput + + self.client = InferenceServerClient(parsed_url.netloc) # Triton HTTP client + model_repository = self.client.get_model_repository_index() + self.model_name = model_repository[0]['name'] + self.metadata = self.client.get_model_metadata(self.model_name) + + def create_input_placeholders() -> typing.List[InferInput]: + return [ + InferInput(i['name'], [int(s) for s in i["shape"]], i['datatype']) for i in self.metadata['inputs']] + + self._create_input_placeholders_fn = create_input_placeholders + + @property + def runtime(self): + """Returns the model runtime""" + return self.metadata.get("backend", self.metadata.get("platform")) + + def __call__(self, *args, **kwargs) -> typing.Union[torch.Tensor, typing.Tuple[torch.Tensor, ...]]: + """ Invokes the model. Parameters can be provided via args or kwargs. + args, if provided, are assumed to match the order of inputs of the model. + kwargs are matched with the model input names. + """ + inputs = self._create_inputs(*args, **kwargs) + response = self.client.infer(model_name=self.model_name, inputs=inputs) + result = [] + for output in self.metadata['outputs']: + tensor = torch.as_tensor(response.as_numpy(output['name'])) + result.append(tensor) + return result[0] if len(result) == 1 else result + + def _create_inputs(self, *args, **kwargs): + args_len, kwargs_len = len(args), len(kwargs) + if not args_len and not kwargs_len: + raise RuntimeError("No inputs provided.") + if args_len and kwargs_len: + raise RuntimeError("Cannot specify args and kwargs at the same time") + + placeholders = self._create_input_placeholders_fn() + if args_len: + if args_len != len(placeholders): + raise RuntimeError(f"Expected {len(placeholders)} inputs, got {args_len}.") + for input, value in zip(placeholders, args): + input.set_data_from_numpy(value.cpu().numpy()) + else: + for input in placeholders: + value = kwargs[input.name] + input.set_data_from_numpy(value.cpu().numpy()) + return placeholders diff --git a/val.py b/val.py index 24b28ad186..f8868494ef 100644 --- a/val.py +++ b/val.py @@ -1,17 +1,30 @@ # YOLOv3 🚀 by Ultralytics, GPL-3.0 license """ -Validate a trained model accuracy on a custom dataset +Validate a trained YOLOv3 detection model on a detection dataset Usage: - $ python path/to/val.py --data coco128.yaml --weights yolov3.pt --img 640 + $ python val.py --weights yolov5s.pt --data coco128.yaml --img 640 + +Usage - formats: + $ python val.py --weights yolov5s.pt # PyTorch + yolov5s.torchscript # TorchScript + yolov5s.onnx # ONNX Runtime or OpenCV DNN with --dnn + yolov5s_openvino_model # OpenVINO + yolov5s.engine # TensorRT + yolov5s.mlmodel # CoreML (macOS-only) + yolov5s_saved_model # TensorFlow SavedModel + yolov5s.pb # TensorFlow GraphDef + yolov5s.tflite # TensorFlow Lite + yolov5s_edgetpu.tflite # TensorFlow Edge TPU + yolov5s_paddle_model # PaddlePaddle """ import argparse import json import os +import subprocess import sys from pathlib import Path -from threading import Thread import numpy as np import torch @@ -25,13 +38,13 @@ from models.common import DetectMultiBackend from utils.callbacks import Callbacks -from utils.datasets import create_dataloader -from utils.general import (LOGGER, NCOLS, box_iou, check_dataset, check_img_size, check_requirements, check_yaml, - coco80_to_coco91_class, colorstr, increment_path, non_max_suppression, print_args, - scale_coords, xywh2xyxy, xyxy2xywh) -from utils.metrics import ConfusionMatrix, ap_per_class +from utils.dataloaders import create_dataloader +from utils.general import (LOGGER, TQDM_BAR_FORMAT, Profile, check_dataset, check_img_size, check_requirements, + check_yaml, coco80_to_coco91_class, colorstr, increment_path, non_max_suppression, + print_args, scale_boxes, xywh2xyxy, xyxy2xywh) +from utils.metrics import ConfusionMatrix, ap_per_class, box_iou from utils.plots import output_to_target, plot_images, plot_val_study -from utils.torch_utils import select_device, time_sync +from utils.torch_utils import select_device, smart_inference_mode def save_one_txt(predn, save_conf, shape, file): @@ -50,45 +63,50 @@ def save_one_json(predn, jdict, path, class_map): box = xyxy2xywh(predn[:, :4]) # xywh box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner for p, b in zip(predn.tolist(), box.tolist()): - jdict.append({'image_id': image_id, - 'category_id': class_map[int(p[5])], - 'bbox': [round(x, 3) for x in b], - 'score': round(p[4], 5)}) + jdict.append({ + 'image_id': image_id, + 'category_id': class_map[int(p[5])], + 'bbox': [round(x, 3) for x in b], + 'score': round(p[4], 5)}) def process_batch(detections, labels, iouv): """ - Return correct predictions matrix. Both sets of boxes are in (x1, y1, x2, y2) format. + Return correct prediction matrix Arguments: - detections (Array[N, 6]), x1, y1, x2, y2, conf, class - labels (Array[M, 5]), class, x1, y1, x2, y2 + detections (array[N, 6]), x1, y1, x2, y2, conf, class + labels (array[M, 5]), class, x1, y1, x2, y2 Returns: - correct (Array[N, 10]), for 10 IoU levels + correct (array[N, 10]), for 10 IoU levels """ - correct = torch.zeros(detections.shape[0], iouv.shape[0], dtype=torch.bool, device=iouv.device) + correct = np.zeros((detections.shape[0], iouv.shape[0])).astype(bool) iou = box_iou(labels[:, 1:], detections[:, :4]) - x = torch.where((iou >= iouv[0]) & (labels[:, 0:1] == detections[:, 5])) # IoU above threshold and classes match - if x[0].shape[0]: - matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() # [label, detection, iou] - if x[0].shape[0] > 1: - matches = matches[matches[:, 2].argsort()[::-1]] - matches = matches[np.unique(matches[:, 1], return_index=True)[1]] - # matches = matches[matches[:, 2].argsort()[::-1]] - matches = matches[np.unique(matches[:, 0], return_index=True)[1]] - matches = torch.Tensor(matches).to(iouv.device) - correct[matches[:, 1].long()] = matches[:, 2:3] >= iouv - return correct - - -@torch.no_grad() -def run(data, + correct_class = labels[:, 0:1] == detections[:, 5] + for i in range(len(iouv)): + x = torch.where((iou >= iouv[i]) & correct_class) # IoU > threshold and classes match + if x[0].shape[0]: + matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() # [label, detect, iou] + if x[0].shape[0] > 1: + matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 1], return_index=True)[1]] + # matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 0], return_index=True)[1]] + correct[matches[:, 1].astype(int), i] = True + return torch.tensor(correct, dtype=torch.bool, device=iouv.device) + + +@smart_inference_mode() +def run( + data, weights=None, # model.pt path(s) batch_size=32, # batch size imgsz=640, # inference size (pixels) conf_thres=0.001, # confidence threshold iou_thres=0.6, # NMS IoU threshold + max_det=300, # maximum detections per image task='val', # train, val, test, speed or study device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + workers=8, # max dataloader workers (per RANK in DDP mode) single_cls=False, # treat as single-class dataset augment=False, # augmented inference verbose=False, # verbose output @@ -107,12 +125,11 @@ def run(data, plots=True, callbacks=Callbacks(), compute_loss=None, - ): +): # Initialize/load model and set device training = model is not None if training: # called by train.py - device, pt = next(model.parameters()).device, True # get model device, PyTorch model - + device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model half &= device.type != 'cpu' # half precision only supported on CUDA model.half() if half else model.float() else: # called directly @@ -123,130 +140,149 @@ def run(data, (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir # Load model - model = DetectMultiBackend(weights, device=device, dnn=dnn) - stride, pt = model.stride, model.pt + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, pt, jit, engine = model.stride, model.pt, model.jit, model.engine imgsz = check_img_size(imgsz, s=stride) # check image size - half &= pt and device.type != 'cpu' # half precision only supported by PyTorch on CUDA - if pt: - model.model.half() if half else model.model.float() + half = model.fp16 # FP16 supported on limited backends with CUDA + if engine: + batch_size = model.batch_size else: - half = False - batch_size = 1 # export.py models default to batch-size 1 - device = torch.device('cpu') - LOGGER.info(f'Forcing --batch-size 1 square inference shape(1,3,{imgsz},{imgsz}) for non-PyTorch backends') + device = model.device + if not (pt or jit): + batch_size = 1 # export.py models default to batch-size 1 + LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') # Data data = check_dataset(data) # check # Configure model.eval() - is_coco = isinstance(data.get('val'), str) and data['val'].endswith('coco/val2017.txt') # COCO dataset + cuda = device.type != 'cpu' + is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'coco{os.sep}val2017.txt') # COCO dataset nc = 1 if single_cls else int(data['nc']) # number of classes - iouv = torch.linspace(0.5, 0.95, 10).to(device) # iou vector for mAP@0.5:0.95 + iouv = torch.linspace(0.5, 0.95, 10, device=device) # iou vector for mAP@0.5:0.95 niou = iouv.numel() # Dataloader if not training: - if pt and device.type != 'cpu': - model(torch.zeros(1, 3, imgsz, imgsz).to(device).type_as(next(model.model.parameters()))) # warmup - pad = 0.0 if task == 'speed' else 0.5 + if pt and not single_cls: # check --weights are trained on --data + ncm = model.model.nc + assert ncm == nc, f'{weights} ({ncm} classes) trained on different --data than what you passed ({nc} ' \ + f'classes). Pass correct combination of --weights and --data that are trained together.' + model.warmup(imgsz=(1 if pt else batch_size, 3, imgsz, imgsz)) # warmup + pad, rect = (0.0, False) if task == 'speed' else (0.5, pt) # square inference for benchmarks task = task if task in ('train', 'val', 'test') else 'val' # path to train/val/test images - dataloader = create_dataloader(data[task], imgsz, batch_size, stride, single_cls, pad=pad, rect=pt, + dataloader = create_dataloader(data[task], + imgsz, + batch_size, + stride, + single_cls, + pad=pad, + rect=rect, + workers=workers, prefix=colorstr(f'{task}: '))[0] seen = 0 confusion_matrix = ConfusionMatrix(nc=nc) - names = {k: v for k, v in enumerate(model.names if hasattr(model, 'names') else model.module.names)} + names = model.names if hasattr(model, 'names') else model.module.names # get class names + if isinstance(names, (list, tuple)): # old format + names = dict(enumerate(names)) class_map = coco80_to_coco91_class() if is_coco else list(range(1000)) - s = ('%20s' + '%11s' * 6) % ('Class', 'Images', 'Labels', 'P', 'R', 'mAP@.5', 'mAP@.5:.95') - dt, p, r, f1, mp, mr, map50, map = [0.0, 0.0, 0.0], 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + s = ('%22s' + '%11s' * 6) % ('Class', 'Images', 'Instances', 'P', 'R', 'mAP50', 'mAP50-95') + tp, fp, p, r, f1, mp, mr, map50, ap50, map = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + dt = Profile(), Profile(), Profile() # profiling times loss = torch.zeros(3, device=device) jdict, stats, ap, ap_class = [], [], [], [] - pbar = tqdm(dataloader, desc=s, ncols=NCOLS, bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}') # progress bar + callbacks.run('on_val_start') + pbar = tqdm(dataloader, desc=s, bar_format=TQDM_BAR_FORMAT) # progress bar for batch_i, (im, targets, paths, shapes) in enumerate(pbar): - t1 = time_sync() - if pt: - im = im.to(device, non_blocking=True) - targets = targets.to(device) - im = im.half() if half else im.float() # uint8 to fp16/32 - im /= 255 # 0 - 255 to 0.0 - 1.0 - nb, _, height, width = im.shape # batch size, channels, height, width - t2 = time_sync() - dt[0] += t2 - t1 + callbacks.run('on_val_batch_start') + with dt[0]: + if cuda: + im = im.to(device, non_blocking=True) + targets = targets.to(device) + im = im.half() if half else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + nb, _, height, width = im.shape # batch size, channels, height, width # Inference - out, train_out = model(im) if training else model(im, augment=augment, val=True) # inference, loss outputs - dt[1] += time_sync() - t2 + with dt[1]: + preds, train_out = model(im) if compute_loss else (model(im, augment=augment), None) # Loss if compute_loss: - loss += compute_loss([x.float() for x in train_out], targets)[1] # box, obj, cls + loss += compute_loss(train_out, targets)[1] # box, obj, cls # NMS - targets[:, 2:] *= torch.Tensor([width, height, width, height]).to(device) # to pixels + targets[:, 2:] *= torch.tensor((width, height, width, height), device=device) # to pixels lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling - t3 = time_sync() - out = non_max_suppression(out, conf_thres, iou_thres, labels=lb, multi_label=True, agnostic=single_cls) - dt[2] += time_sync() - t3 + with dt[2]: + preds = non_max_suppression(preds, + conf_thres, + iou_thres, + labels=lb, + multi_label=True, + agnostic=single_cls, + max_det=max_det) # Metrics - for si, pred in enumerate(out): + for si, pred in enumerate(preds): labels = targets[targets[:, 0] == si, 1:] - nl = len(labels) - tcls = labels[:, 0].tolist() if nl else [] # target class + nl, npr = labels.shape[0], pred.shape[0] # number of labels, predictions path, shape = Path(paths[si]), shapes[si][0] + correct = torch.zeros(npr, niou, dtype=torch.bool, device=device) # init seen += 1 - if len(pred) == 0: + if npr == 0: if nl: - stats.append((torch.zeros(0, niou, dtype=torch.bool), torch.Tensor(), torch.Tensor(), tcls)) + stats.append((correct, *torch.zeros((2, 0), device=device), labels[:, 0])) + if plots: + confusion_matrix.process_batch(detections=None, labels=labels[:, 0]) continue # Predictions if single_cls: pred[:, 5] = 0 predn = pred.clone() - scale_coords(im[si].shape[1:], predn[:, :4], shape, shapes[si][1]) # native-space pred + scale_boxes(im[si].shape[1:], predn[:, :4], shape, shapes[si][1]) # native-space pred # Evaluate if nl: tbox = xywh2xyxy(labels[:, 1:5]) # target boxes - scale_coords(im[si].shape[1:], tbox, shape, shapes[si][1]) # native-space labels + scale_boxes(im[si].shape[1:], tbox, shape, shapes[si][1]) # native-space labels labelsn = torch.cat((labels[:, 0:1], tbox), 1) # native-space labels correct = process_batch(predn, labelsn, iouv) if plots: confusion_matrix.process_batch(predn, labelsn) - else: - correct = torch.zeros(pred.shape[0], niou, dtype=torch.bool) - stats.append((correct.cpu(), pred[:, 4].cpu(), pred[:, 5].cpu(), tcls)) # (correct, conf, pcls, tcls) + stats.append((correct, pred[:, 4], pred[:, 5], labels[:, 0])) # (correct, conf, pcls, tcls) # Save/log if save_txt: - save_one_txt(predn, save_conf, shape, file=save_dir / 'labels' / (path.stem + '.txt')) + save_one_txt(predn, save_conf, shape, file=save_dir / 'labels' / f'{path.stem}.txt') if save_json: save_one_json(predn, jdict, path, class_map) # append to COCO-JSON dictionary callbacks.run('on_val_image_end', pred, predn, path, names, im[si]) # Plot images if plots and batch_i < 3: - f = save_dir / f'val_batch{batch_i}_labels.jpg' # labels - Thread(target=plot_images, args=(im, targets, paths, f, names), daemon=True).start() - f = save_dir / f'val_batch{batch_i}_pred.jpg' # predictions - Thread(target=plot_images, args=(im, output_to_target(out), paths, f, names), daemon=True).start() + plot_images(im, targets, paths, save_dir / f'val_batch{batch_i}_labels.jpg', names) # labels + plot_images(im, output_to_target(preds), paths, save_dir / f'val_batch{batch_i}_pred.jpg', names) # pred + + callbacks.run('on_val_batch_end', batch_i, im, targets, paths, shapes, preds) # Compute metrics - stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy + stats = [torch.cat(x, 0).cpu().numpy() for x in zip(*stats)] # to numpy if len(stats) and stats[0].any(): - p, r, ap, f1, ap_class = ap_per_class(*stats, plot=plots, save_dir=save_dir, names=names) + tp, fp, p, r, f1, ap, ap_class = ap_per_class(*stats, plot=plots, save_dir=save_dir, names=names) ap50, ap = ap[:, 0], ap.mean(1) # AP@0.5, AP@0.5:0.95 mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean() - nt = np.bincount(stats[3].astype(np.int64), minlength=nc) # number of targets per class - else: - nt = torch.zeros(1) + nt = np.bincount(stats[3].astype(int), minlength=nc) # number of targets per class # Print results - pf = '%20s' + '%11i' * 2 + '%11.3g' * 4 # print format + pf = '%22s' + '%11i' * 2 + '%11.3g' * 4 # print format LOGGER.info(pf % ('all', seen, nt.sum(), mp, mr, map50, map)) + if nt.sum() == 0: + LOGGER.warning(f'WARNING ⚠️ no labels found in {task} set, can not compute metrics without labels') # Print results per class if (verbose or (nc < 50 and not training)) and nc > 1 and len(stats): @@ -254,7 +290,7 @@ def run(data, LOGGER.info(pf % (names[c], seen, nt[c], p[i], r[i], ap50[i], ap[i])) # Print speeds - t = tuple(x / seen * 1E3 for x in dt) # speeds per image + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image if not training: shape = (batch_size, 3, imgsz, imgsz) LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {shape}' % t) @@ -262,19 +298,19 @@ def run(data, # Plots if plots: confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) - callbacks.run('on_val_end') + callbacks.run('on_val_end', nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) # Save JSON if save_json and len(jdict): w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights - anno_json = str(Path(data.get('path', '../coco')) / 'annotations/instances_val2017.json') # annotations json - pred_json = str(save_dir / f"{w}_predictions.json") # predictions json + anno_json = str(Path('../datasets/coco/annotations/instances_val2017.json')) # annotations + pred_json = str(save_dir / f"{w}_predictions.json") # predictions LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') with open(pred_json, 'w') as f: json.dump(jdict, f) try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb - check_requirements(['pycocotools']) + check_requirements('pycocotools>=2.0.6') from pycocotools.coco import COCO from pycocotools.cocoeval import COCOeval @@ -282,7 +318,7 @@ def run(data, pred = anno.loadRes(pred_json) # init predictions api eval = COCOeval(anno, pred, 'bbox') if is_coco: - eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.img_files] # image IDs to evaluate + eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.im_files] # image IDs to evaluate eval.evaluate() eval.accumulate() eval.summarize() @@ -304,13 +340,15 @@ def run(data, def parse_opt(): parser = argparse.ArgumentParser() parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') - parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov3.pt', help='model.pt path(s)') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov3-tiny.pt', help='model path(s)') parser.add_argument('--batch-size', type=int, default=32, help='batch size') parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.001, help='confidence threshold') parser.add_argument('--iou-thres', type=float, default=0.6, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=300, help='maximum detections per image') parser.add_argument('--task', default='val', help='train, val, test, speed or study') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') parser.add_argument('--augment', action='store_true', help='augmented inference') parser.add_argument('--verbose', action='store_true', help='report mAP by class') @@ -327,29 +365,31 @@ def parse_opt(): opt.data = check_yaml(opt.data) # check YAML opt.save_json |= opt.data.endswith('coco.yaml') opt.save_txt |= opt.save_hybrid - print_args(FILE.stem, opt) + print_args(vars(opt)) return opt def main(opt): - check_requirements(requirements=ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + check_requirements(exclude=('tensorboard', 'thop')) if opt.task in ('train', 'val', 'test'): # run normally if opt.conf_thres > 0.001: # https://github.com/ultralytics/yolov5/issues/1466 - LOGGER.info(f'WARNING: confidence threshold {opt.conf_thres} >> 0.001 will produce invalid mAP values.') + LOGGER.info(f'WARNING ⚠️ confidence threshold {opt.conf_thres} > 0.001 produces invalid results') + if opt.save_hybrid: + LOGGER.info('WARNING ⚠️ --save-hybrid will return high mAP from hybrid labels, not from predictions alone') run(**vars(opt)) else: weights = opt.weights if isinstance(opt.weights, list) else [opt.weights] - opt.half = True # FP16 for fastest results + opt.half = torch.cuda.is_available() and opt.device != 'cpu' # FP16 for fastest results if opt.task == 'speed': # speed benchmarks - # python val.py --task speed --data coco.yaml --batch 1 --weights yolov3.pt yolov3-spp.pt... + # python val.py --task speed --data coco.yaml --batch 1 --weights yolov5n.pt yolov5s.pt... opt.conf_thres, opt.iou_thres, opt.save_json = 0.25, 0.45, False for opt.weights in weights: run(**vars(opt), plots=False) elif opt.task == 'study': # speed vs mAP benchmarks - # python val.py --task study --data coco.yaml --iou 0.7 --weights yolov3.pt yolov3-spp.pt... + # python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n.pt yolov5s.pt... for opt.weights in weights: f = f'study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt' # filename to save to x, y = list(range(256, 1536 + 128, 128)), [] # x axis (image sizes), y axis @@ -358,8 +398,10 @@ def main(opt): r, _, t = run(**vars(opt), plots=False) y.append(r + t) # results and times np.savetxt(f, y, fmt='%10.4g') # save - os.system('zip -r study.zip study_*.txt') + subprocess.run('zip -r study.zip study_*.txt'.split()) plot_val_study(x=x) # plot + else: + raise NotImplementedError(f'--task {opt.task} not in ("train", "val", "test", "speed", "study")') if __name__ == "__main__": From 50f78bfd08bf0b0cec297fd9183d47b88dfe5b4c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 13 Feb 2023 01:46:19 +0400 Subject: [PATCH 0933/1185] README link fixes (#2012) Link fixes --- README.md | 4 ++-- README.zh-CN.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b10c181477..b26a29acf0 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ quickstart examples.
Install -Clone repo and install [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) in a +Clone repo and install [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) in a [**Python>=3.7.0**](https://www.python.org/) environment, including [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). @@ -514,7 +514,7 @@ is available under two different licenses: ##
Contact
-For bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov5/issues) or +For bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues) or the [Ultralytics Community Forum](https://community.ultralytics.com/).
diff --git a/README.zh-CN.md b/README.zh-CN.md index f5f91241fe..5bd5a83d48 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -72,7 +72,7 @@ pip install ultralytics 安装 克隆 repo,并要求在 [**Python>=3.7.0**](https://www.python.org/) -环境中安装 [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) ,且要求 [**PyTorch> +环境中安装 [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) ,且要求 [**PyTorch> =1.7**](https://pytorch.org/get-started/locally/) 。 ```bash @@ -502,7 +502,7 @@ YOLOv5 在两种不同的 License 下可用: ##
联系我们
-请访问 [GitHub Issues](https://github.com/ultralytics/yolov5/issues) +请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues) 或 [Ultralytics Community Forum](https://community.ultralytis.com) 以报告 YOLOv5 错误和请求功能。
From 6c8bc4030931fa38415d9b742fb63e52dbb2fee5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 13 Feb 2023 20:28:02 +0400 Subject: [PATCH 0934/1185] Update README (#2013) * Update README * Update README * Update README * Update README.md --- README.md | 161 +++++++++++++++++------------------------------- README.zh-CN.md | 142 +++++++++++++++--------------------------- 2 files changed, 104 insertions(+), 199 deletions(-) diff --git a/README.md b/README.md index b26a29acf0..18d71f0e92 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@

- - + +

[English](README.md) | [简体中文](README.zh-CN.md)
-  CI -  Citation - Docker Pulls + YOLOv3 CI + YOLOv3 Citation + Docker Pulls
Run on Gradient Open In Colab @@ -18,12 +18,9 @@

-🚀 is the world's most loved vision AI, representing Ultralytics open-source -research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours -of research and development. +YOLOv3 🚀 is the world's most loved vision AI, representing Ultralytics open-source research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours of research and development. -To request an Enterprise License please complete the form at Ultralytics -Licensing. +To request an Enterprise License please complete the form at Ultralytics Licensing.
@@ -70,13 +67,12 @@ pip install ultralytics ##
Documentation
-See the [ Docs](https://docs.ultralytics.com) for full documentation on training, testing and deployment. See below for -quickstart examples. +See the [YOLOv3 Docs](https://docs.ultralytics.com) for full documentation on training, testing and deployment. See below for quickstart examples.
Install -Clone repo and install [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) in a +Clone repo and install [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) in a [**Python>=3.7.0**](https://www.python.org/) environment, including [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). @@ -91,17 +87,14 @@ pip install -r requirements.txt # install
Inference -[PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36) -inference. [Models](https://github.com/ultralytics/yolov5/tree/master/models) download automatically from the latest -[release](https://github.com/ultralytics/yolov5/releases). +YOLOv3 [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36) inference. [Models](https://github.com/ultralytics/yolov5/tree/master/models) download automatically from the latest +YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). ```python import torch # Model -model = torch.hub.load( - "ultralytics/yolov3", "yolov3" -) # or yolov3-spp, yolov3-tiny, custom +model = torch.hub.load("ultralytics/yolov3", "yolov3") # or yolov5n - yolov5x6, custom # Images img = "https://ultralytics.com/images/zidane.jpg" # or file, Path, PIL, OpenCV, numpy, list @@ -118,9 +111,8 @@ results.print() # or .show(), .save(), .crop(), .pandas(), etc.
Inference with detect.py -`detect.py` runs inference on a variety of sources, -downloading [models](https://github.com/ultralytics/yolov5/tree/master/models) automatically from -the latest [release](https://github.com/ultralytics/yolov5/releases) and saving results to `runs/detect`. +`detect.py` runs inference on a variety of sources, downloading [models](https://github.com/ultralytics/yolov5/tree/master/models) automatically from +the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) and saving results to `runs/detect`. ```bash python detect.py --weights yolov5s.pt --source 0 # webcam @@ -140,13 +132,13 @@ python detect.py --weights yolov5s.pt --source 0 #
Training -The commands below reproduce [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) +The commands below reproduce YOLOv3 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) results. [Models](https://github.com/ultralytics/yolov5/tree/master/models) and [datasets](https://github.com/ultralytics/yolov5/tree/master/data) download automatically from the latest -[release](https://github.com/ultralytics/yolov5/releases). Training times for YOLOv5n/s/m/l/x are +YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). Training times for YOLOv5n/s/m/l/x are 1/2/4/6/8 days on a V100 GPU ([Multi-GPU](https://github.com/ultralytics/yolov5/issues/475) times faster). Use the largest `--batch-size` possible, or pass `--batch-size -1` for -[AutoBatch](https://github.com/ultralytics/yolov5/pull/5092). Batch sizes shown for V100-16GB. +YOLOv3 [AutoBatch](https://github.com/ultralytics/yolov5/pull/5092). Batch sizes shown for V100-16GB. ```bash python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml --batch-size 128 @@ -163,8 +155,8 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
Tutorials -- [Train Custom Data](https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data)🚀 RECOMMENDED -- [Tips for Best Training Results](https://github.com/ultralytics/yolov5/wiki/Tips-for-Best-Training-Results)☘️ +- [Train Custom Data](https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data)  🚀 RECOMMENDED +- [Tips for Best Training Results](https://github.com/ultralytics/yolov5/wiki/Tips-for-Best-Training-Results)  ☘️ RECOMMENDED - [Multi-GPU Training](https://github.com/ultralytics/yolov5/issues/475) - [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36) 🌟 NEW @@ -176,9 +168,9 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - - [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607) - [Transfer Learning with Frozen Layers](https://github.com/ultralytics/yolov5/issues/1314) - [Architecture Summary](https://github.com/ultralytics/yolov5/issues/6998) 🌟 NEW -- [Roboflow for Datasets, Labeling, and Active Learning](https://github.com/ultralytics/yolov5/issues/4975)🌟 NEW +- [Roboflow for Datasets, Labeling, and Active Learning](https://github.com/ultralytics/yolov5/issues/4975)  🌟 NEW - [ClearML Logging](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml) 🌟 NEW -- [ with Neural Magic's Deepsparse](https://bit.ly/yolov5-neuralmagic) 🌟 NEW +- [YOLOv3 with Neural Magic's Deepsparse](https://bit.ly/yolov5-neuralmagic) 🌟 NEW - [Comet Logging](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/comet) 🌟 NEW
@@ -187,7 +179,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
- +

@@ -205,38 +197,34 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
-| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | -| :--------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------: | -| Label and export your custom datasets directly to for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | Automatically track, visualize and even remotely train using [ClearML](https://cutt.ly/yolov5-readme-clearml) (open-source!) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet2) lets you save models, resume training, and interactively visualise and debug predictions | Run inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | +| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | +| :--------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | +| Label and export your custom datasets directly to YOLOv3 for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | Automatically track, visualize and even remotely train YOLOv3 using [ClearML](https://cutt.ly/yolov5-readme-clearml) (open-source!) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet2) lets you save YOLOv3 models, resume training, and interactively visualise and debug predictions | Run YOLOv3 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | ##
Ultralytics HUB
-[Ultralytics HUB](https://bit.ly/ultralytics_hub) is our ⭐ **NEW** no-code solution to visualize datasets, train 🚀 -models, and deploy to the real world in a seamless experience. Get started for **Free** now! +Experience seamless AI with [Ultralytics HUB](https://bit.ly/ultralytics_hub) ⭐, the all-in-one solution for data visualization, YOLO 🚀 model training and deployment, without any coding. Transform images into actionable insights and bring your AI visions to life with ease using our cutting-edge platform and user-friendly [Ultralytics App](https://ultralytics.com/app_install). Start your journey for **Free** now! -##
Why YOLO
+##
Why YOLOv3
-has been designed to be super easy to get started and simple to learn. We prioritize real-world results. +YOLOv3 has been designed to be super easy to get started and simple to learn. We prioritize real-world results.

- YOLOv5-P5 640 Figure + YOLOv3-P5 640 Figure

Figure Notes -- **COCO AP val** denotes mAP@0.5:0.95 metric measured on the 5000-image [COCO val2017](http://cocodataset.org) dataset - over various inference sizes from 256 to 1536. -- **GPU Speed** measures average inference time per image on [COCO val2017](http://cocodataset.org) dataset using - a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) V100 instance at batch-size 32. +- **COCO AP val** denotes mAP@0.5:0.95 metric measured on the 5000-image [COCO val2017](http://cocodataset.org) dataset over various inference sizes from 256 to 1536. +- **GPU Speed** measures average inference time per image on [COCO val2017](http://cocodataset.org) dataset using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) V100 instance at batch-size 32. - **EfficientDet** data from [google/automl](https://github.com/google/automl) at batch size 8. -- **Reproduce** - by `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt` +- **Reproduce** by `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt`
@@ -259,28 +247,16 @@ has been designed to be super easy to get started and simple to learn. We priori
Table Notes -- All checkpoints are trained to 300 epochs with default settings. Nano and Small models - use [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) hyps, all - others use [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml). -- **mAPval** values are for single-model single-scale on [COCO val2017](http://cocodataset.org) dataset.
- Reproduce by `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` -- **Speed** averaged over COCO val images using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) - instance. NMS times (~1 ms/img) not included.
Reproduce - by `python val.py --data coco.yaml --img 640 --task speed --batch 1` -- **TTA** [Test Time Augmentation](https://github.com/ultralytics/yolov5/issues/303) includes reflection and scale - augmentations.
Reproduce by `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment` +- All checkpoints are trained to 300 epochs with default settings. Nano and Small models use [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) hyps, all others use [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml). +- **mAPval** values are for single-model single-scale on [COCO val2017](http://cocodataset.org) dataset.
Reproduce by `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` +- **Speed** averaged over COCO val images using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) instance. NMS times (~1 ms/img) not included.
Reproduce by `python val.py --data coco.yaml --img 640 --task speed --batch 1` +- **TTA** [Test Time Augmentation](https://github.com/ultralytics/yolov5/issues/303) includes reflection and scale augmentations.
Reproduce by `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment`
##
Segmentation
-Our new YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7.0) instance segmentation models are the -fastest and most accurate in the world, beating all -current [SOTA benchmarks](https://paperswithcode.com/sota/real-time-instance-segmentation-on-mscoco). We've made them -super simple to train, validate and deploy. See full details in -our [Release Notes](https://github.com/ultralytics/yolov5/releases/v7.0) and visit -our [YOLOv5 Segmentation Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/segment/tutorial.ipynb) for -quickstart tutorials. +Our new YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7.0) instance segmentation models are the fastest and most accurate in the world, beating all current [SOTA benchmarks](https://paperswithcode.com/sota/real-time-instance-segmentation-on-mscoco). We've made them super simple to train, validate and deploy. See full details in our [Release Notes](https://github.com/ultralytics/yolov5/releases/v7.0) and visit our [YOLOv5 Segmentation Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/segment/tutorial.ipynb) for quickstart tutorials.
Segmentation Checkpoints @@ -290,9 +266,7 @@ quickstart tutorials.
-We trained YOLOv5 segmentations models on COCO for 300 epochs at image size 640 using A100 GPUs. We exported all models -to ONNX FP32 for CPU speed tests and to TensorRT FP16 for GPU speed tests. We ran all speed tests on -Google [Colab Pro](https://colab.research.google.com/signup) notebooks for easy reproducibility. +We trained YOLOv5 segmentations models on COCO for 300 epochs at image size 640 using A100 GPUs. We exported all models to ONNX FP32 for CPU speed tests and to TensorRT FP16 for GPU speed tests. We ran all speed tests on Google [Colab Pro](https://colab.research.google.com/signup) notebooks for easy reproducibility. | Model | size
(pixels) | mAPbox
50-95 | mAPmask
50-95 | Train time
300 epochs
A100 (hours) | Speed
ONNX CPU
(ms) | Speed
TRT A100
(ms) | params
(M) | FLOPs
@640 (B) | | ------------------------------------------------------------------------------------------ | --------------------- | -------------------- | --------------------- | --------------------------------------------- | ------------------------------ | ------------------------------ | ------------------ | ---------------------- | @@ -302,15 +276,10 @@ Google [Colab Pro](https://colab.research.google.com/signup) notebooks for easy | [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | | [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | -- All checkpoints are trained to 300 epochs with SGD optimizer with `lr0=0.01` and `weight_decay=5e-5` at image size 640 - and all default settings.
Runs logged to https://wandb.ai/glenn-jocher/YOLOv5_v70_official -- **Accuracy** values are for single-model single-scale on COCO dataset.
Reproduce - by `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt` -- **Speed** averaged over 100 inference images using a [Colab Pro](https://colab.research.google.com/signup) A100 - High-RAM instance. Values indicate inference speed only (NMS adds about 1ms per image).
Reproduce - by `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt --batch 1` -- **Export** to ONNX at FP32 and TensorRT at FP16 done with `export.py`.
Reproduce - by `python export.py --weights yolov5s-seg.pt --include engine --device 0 --half` +- All checkpoints are trained to 300 epochs with SGD optimizer with `lr0=0.01` and `weight_decay=5e-5` at image size 640 and all default settings.
Runs logged to https://wandb.ai/glenn-jocher/YOLOv5_v70_official +- **Accuracy** values are for single-model single-scale on COCO dataset.
Reproduce by `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt` +- **Speed** averaged over 100 inference images using a [Colab Pro](https://colab.research.google.com/signup) A100 High-RAM instance. Values indicate inference speed only (NMS adds about 1ms per image).
Reproduce by `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt --batch 1` +- **Export** to ONNX at FP32 and TensorRT at FP16 done with `export.py`.
Reproduce by `python export.py --weights yolov5s-seg.pt --include engine --device 0 --half`
@@ -319,9 +288,7 @@ Google [Colab Pro](https://colab.research.google.com/signup) notebooks for easy ### Train -YOLOv5 segmentation training supports auto-download COCO128-seg segmentation dataset with `--data coco128-seg.yaml` -argument and manual download of COCO-segments dataset with `bash data/scripts/get_coco.sh --train --val --segments` and -then `python train.py --data coco.yaml`. +YOLOv5 segmentation training supports auto-download COCO128-seg segmentation dataset with `--data coco128-seg.yaml` argument and manual download of COCO-segments dataset with `bash data/scripts/get_coco.sh --train --val --segments` and then `python train.py --data coco.yaml`. ```bash # Single-GPU @@ -369,21 +336,14 @@ python export.py --weights yolov5s-seg.pt --include onnx engine --img 640 --devi ##
Classification
-YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) brings support for classification model training, -validation and deployment! See full details in our [Release Notes](https://github.com/ultralytics/yolov5/releases/v6.2) -and visit -our [YOLOv5 Classification Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/classify/tutorial.ipynb) -for quickstart tutorials. +YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) brings support for classification model training, validation and deployment! See full details in our [Release Notes](https://github.com/ultralytics/yolov5/releases/v6.2) and visit our [YOLOv5 Classification Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/classify/tutorial.ipynb) for quickstart tutorials.
Classification Checkpoints
-We trained YOLOv5-cls classification models on ImageNet for 90 epochs using a 4xA100 instance, and we trained ResNet and -EfficientNet models alongside with the same default training settings to compare. We exported all models to ONNX FP32 -for CPU speed tests and to TensorRT FP16 for GPU speed tests. We ran all speed tests on -Google [Colab Pro](https://colab.research.google.com/signup) for easy reproducibility. +We trained YOLOv5-cls classification models on ImageNet for 90 epochs using a 4xA100 instance, and we trained ResNet and EfficientNet models alongside with the same default training settings to compare. We exported all models to ONNX FP32 for CPU speed tests and to TensorRT FP16 for GPU speed tests. We ran all speed tests on Google [Colab Pro](https://colab.research.google.com/signup) for easy reproducibility. | Model | size
(pixels) | acc
top1 | acc
top5 | Training
90 epochs
4xA100 (hours) | Speed
ONNX CPU
(ms) | Speed
TensorRT V100
(ms) | params
(M) | FLOPs
@224 (B) | | -------------------------------------------------------------------------------------------------- | --------------------- | ---------------- | ---------------- | -------------------------------------------- | ------------------------------ | ----------------------------------- | ------------------ | ---------------------- | @@ -406,14 +366,10 @@ Google [Colab Pro](https://colab.research.google.com/signup) for easy reproducib
Table Notes (click to expand) -- All checkpoints are trained to 90 epochs with SGD optimizer with `lr0=0.001` and `weight_decay=5e-5` at image size 224 - and all default settings.
Runs logged to https://wandb.ai/glenn-jocher/YOLOv5-Classifier-v6-2 -- **Accuracy** values are for single-model single-scale on [ImageNet-1k](https://www.image-net.org/index.php) - dataset.
Reproduce by `python classify/val.py --data ../datasets/imagenet --img 224` -- **Speed** averaged over 100 inference images using a Google [Colab Pro](https://colab.research.google.com/signup) V100 - High-RAM instance.
Reproduce by `python classify/val.py --data ../datasets/imagenet --img 224 --batch 1` -- **Export** to ONNX at FP32 and TensorRT at FP16 done with `export.py`.
Reproduce - by `python export.py --weights yolov5s-cls.pt --include engine onnx --imgsz 224` +- All checkpoints are trained to 90 epochs with SGD optimizer with `lr0=0.001` and `weight_decay=5e-5` at image size 224 and all default settings.
Runs logged to https://wandb.ai/glenn-jocher/YOLOv5-Classifier-v6-2 +- **Accuracy** values are for single-model single-scale on [ImageNet-1k](https://www.image-net.org/index.php) dataset.
Reproduce by `python classify/val.py --data ../datasets/imagenet --img 224` +- **Speed** averaged over 100 inference images using a Google [Colab Pro](https://colab.research.google.com/signup) V100 High-RAM instance.
Reproduce by `python classify/val.py --data ../datasets/imagenet --img 224 --batch 1` +- **Export** to ONNX at FP32 and TensorRT at FP16 done with `export.py`.
Reproduce by `python export.py --weights yolov5s-cls.pt --include engine onnx --imgsz 224`
@@ -423,8 +379,7 @@ Google [Colab Pro](https://colab.research.google.com/signup) for easy reproducib ### Train -YOLOv5 classification training supports auto-download of MNIST, Fashion-MNIST, CIFAR10, CIFAR100, Imagenette, Imagewoof, -and ImageNet datasets with the `--data` argument. To start training on MNIST for example use `--data mnist`. +YOLOv5 classification training supports auto-download of MNIST, Fashion-MNIST, CIFAR10, CIFAR100, Imagenette, Imagewoof, and ImageNet datasets with the `--data` argument. To start training on MNIST for example use `--data mnist`. ```bash # Single-GPU @@ -481,7 +436,7 @@ Get started in seconds with our verified environments. Click each icon below for - + @@ -493,10 +448,7 @@ Get started in seconds with our verified environments. Click each icon below for ##
Contribute
-We love your input! We want to make contributing to as easy and transparent as possible. Please see -our [Contributing Guide](CONTRIBUTING.md) to get started, and fill out -the [ Survey](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to send us -feedback on your experiences. Thank you to all our contributors! +We love your input! We want to make contributing to YOLOv3 as easy and transparent as possible. Please see our [Contributing Guide](CONTRIBUTING.md) to get started, and fill out the [YOLOv3 Survey](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to send us feedback on your experiences. Thank you to all our contributors! @@ -505,17 +457,14 @@ feedback on your experiences. Thank you to all our contributors! ##
License
-is available under two different licenses: +YOLOv3 is available under two different licenses: - **GPL-3.0 License**: See [LICENSE](https://github.com/ultralytics/yolov5/blob/master/LICENSE) file for details. -- **Enterprise License**: Provides greater flexibility for commercial product development without the open-source - requirements of GPL-3.0. Typical use cases are embedding Ultralytics software and AI models in commercial products and - applications. Request an Enterprise License at [Ultralytics Licensing](https://ultralytics.com/license). +- **Enterprise License**: Provides greater flexibility for commercial product development without the open-source requirements of GPL-3.0. Typical use cases are embedding Ultralytics software and AI models in commercial products and applications. Request an Enterprise License at [Ultralytics Licensing](https://ultralytics.com/license). ##
Contact
-For bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues) or -the [Ultralytics Community Forum](https://community.ultralytics.com/). +For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov5/issues) or the [Ultralytics Community Forum](https://community.ultralytics.com/).
diff --git a/README.zh-CN.md b/README.zh-CN.md index 5bd5a83d48..6620131cdc 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,15 +1,15 @@

- - + +

[英文](README.md)|[简体中文](README.zh-CN.md)
-  CI -  Citation - Docker Pulls + YOLOv3 CI + YOLOv3 Citation + Docker Pulls
Run on Gradient Open In Colab @@ -17,8 +17,7 @@

-🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics 对未来视觉 AI -方法的开源研究,结合在数千小时的研究和开发中积累的经验教训和最佳实践。 +YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics 对未来视觉 AI 方法的开源研究,结合在数千小时的研究和开发中积累的经验教训和最佳实践。 如果要申请企业许可证,请填写表格Ultralytics 许可. @@ -66,14 +65,12 @@ pip install ultralytics ##
文档
-有关训练、测试和部署的完整文档见[YOLOv5 文档](https://docs.ultralytics.com)。请参阅下面的快速入门示例。 +有关训练、测试和部署的完整文档见[YOLOv3 文档](https://docs.ultralytics.com)。请参阅下面的快速入门示例。
安装 -克隆 repo,并要求在 [**Python>=3.7.0**](https://www.python.org/) -环境中安装 [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) ,且要求 [**PyTorch> -=1.7**](https://pytorch.org/get-started/locally/) 。 +克隆 repo,并要求在 [**Python>=3.7.0**](https://www.python.org/) 环境中安装 [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) ,且要求 [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/) 。 ```bash git clone https://github.com/ultralytics/yolov3 # clone @@ -86,17 +83,14 @@ pip install -r requirements.txt # install
推理 -使用 YOLOv5 [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36) -推理。最新 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 将自动的从 -YOLOv5 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 +使用 YOLOv3 [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36) 推理。最新 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 将自动的从 +YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 ```python import torch # Model -model = torch.hub.load( - "ultralytics/yolov3", "yolov3" -) # or yolov3-spp, yolov3-tiny, custom +model = torch.hub.load("ultralytics/yolov5", "yolov3") # or yolov5n - yolov5x6, custom # Images img = "https://ultralytics.com/images/zidane.jpg" # or file, Path, PIL, OpenCV, numpy, list @@ -134,14 +128,12 @@ python detect.py --weights yolov5s.pt --source 0 #
训练 -下面的命令重现 YOLOv5 在 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) 数据集上的结果。 -最新的 [模型](https://github.com/ultralytics/yolov5/tree/master/models) -和 [数据集](https://github.com/ultralytics/yolov5/tree/master/data) -将自动的从 YOLOv5 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 -YOLOv5n/s/m/l/x 在 V100 GPU 的训练时间为 1/2/4/6/8 天( [多GPU](https://github.com/ultralytics/yolov5/issues/475) -训练速度更快)。 +下面的命令重现 YOLOv3 在 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) 数据集上的结果。 +最新的 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 和 [数据集](https://github.com/ultralytics/yolov5/tree/master/data) +将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 +YOLOv5n/s/m/l/x 在 V100 GPU 的训练时间为 1/2/4/6/8 天( [多GPU](https://github.com/ultralytics/yolov5/issues/475) 训练速度更快)。 尽可能使用更大的 `--batch-size` ,或通过 `--batch-size -1` 实现 -YOLOv5 [自动批处理](https://github.com/ultralytics/yolov5/pull/5092) 。下方显示的 batchsize 适用于 V100-16GB。 +YOLOv3 [自动批处理](https://github.com/ultralytics/yolov5/pull/5092) 。下方显示的 batchsize 适用于 V100-16GB。 ```bash python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml --batch-size 128 @@ -181,7 +173,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
- +

@@ -201,19 +193,18 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - | Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | | :--------------------------------------------------------------------------------: | :-------------------------------------------------------------------------: | :-------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | -| 将您的自定义数据集进行标注并直接导出到 YOLOv5 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv5 [ClearML](https://cutt.ly/yolov5-readme-clearml)(开源!) | 永远免费,[Comet](https://bit.ly/yolov5-readme-comet)可让您保存 YOLOv5 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv5 推理的速度最高可提高6倍 | +| 将您的自定义数据集进行标注并直接导出到 YOLOv3 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv3 [ClearML](https://cutt.ly/yolov5-readme-clearml)(开源!) | 永远免费,[Comet](https://bit.ly/yolov5-readme-comet)可让您保存 YOLOv3 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv3 推理的速度最高可提高6倍 | ##
Ultralytics HUB
-[Ultralytics HUB](https://bit.ly/ultralytics_hub) 是我们的⭐**新的**用于可视化数据集、训练 YOLOv5 🚀 -模型并以无缝体验部署到现实世界的无代码解决方案。现在开始 **免费** 使用他! +[Ultralytics HUB](https://bit.ly/ultralytics_hub) 是我们的⭐**新的**用于可视化数据集、训练 YOLOv3 🚀 模型并以无缝体验部署到现实世界的无代码解决方案。现在开始 **免费** 使用他! -##
为什么选择 YOLOv5
+##
为什么选择 YOLOv3
-YOLOv5 超级容易上手,简单易学。我们优先考虑现实世界的结果。 +YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结果。

@@ -224,13 +215,10 @@ YOLOv5 超级容易上手,简单易学。我们优先考虑现实世界的结
图表笔记 -- **COCO AP val** 表示 mAP@0.5:0.95 指标,在 [COCO val2017](http://cocodataset.org) 数据集的 5000 张图像上测得, 图像包含 - 256 到 1536 各种推理大小。 -- **显卡推理速度** 为在 [COCO val2017](http://cocodataset.org) - 数据集上的平均推理时间,使用 [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) V100实例,batchsize 为 32 。 +- **COCO AP val** 表示 mAP@0.5:0.95 指标,在 [COCO val2017](http://cocodataset.org) 数据集的 5000 张图像上测得, 图像包含 256 到 1536 各种推理大小。 +- **显卡推理速度** 为在 [COCO val2017](http://cocodataset.org) 数据集上的平均推理时间,使用 [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) V100实例,batchsize 为 32 。 - **EfficientDet** 数据来自 [google/automl](https://github.com/google/automl) , batchsize 为32。 -- **复现命令** - 为 `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt` +- **复现命令** 为 `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt`
@@ -253,25 +241,16 @@ YOLOv5 超级容易上手,简单易学。我们优先考虑现实世界的结
笔记 -- 所有模型都使用默认配置,训练 300 - epochs。n和s模型使用 [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) - ,其他模型都使用 [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml) 。 -- \*\*mAPval\*\*在单模型单尺度上计算,数据集使用 [COCO val2017](http://cocodataset.org) 。
- 复现命令 `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` -- **推理速度**在 COCO val - 图像总体时间上进行平均得到,测试环境使用[AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/)实例。 NMS 时间 ( - 大约 1 ms/img) 不包括在内。
复现命令 `python val.py --data coco.yaml --img 640 --task speed --batch 1` -- **TTA** [测试时数据增强](https://github.com/ultralytics/yolov5/issues/303) 包括反射和尺度变换。
- 复现命令 `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment` +- 所有模型都使用默认配置,训练 300 epochs。n和s模型使用 [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) ,其他模型都使用 [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml) 。 +- \*\*mAPval\*\*在单模型单尺度上计算,数据集使用 [COCO val2017](http://cocodataset.org) 。
复现命令 `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` +- **推理速度**在 COCO val 图像总体时间上进行平均得到,测试环境使用[AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/)实例。 NMS 时间 (大约 1 ms/img) 不包括在内。
复现命令 `python val.py --data coco.yaml --img 640 --task speed --batch 1` +- **TTA** [测试时数据增强](https://github.com/ultralytics/yolov5/issues/303) 包括反射和尺度变换。
复现命令 `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment`
-##
实例分割模型 ⭐ 新
+##
实例分割模型 ⭐ 新
-我们新的 YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7.0) -实例分割模型是世界上最快和最准确的模型,击败所有当前 [SOTA 基准](https://paperswithcode.com/sota/real-time-instance-segmentation-on-mscoco) -。我们使它非常易于训练、验证和部署。更多细节请查看 [发行说明](https://github.com/ultralytics/yolov5/releases/v7.0) -或访问我们的 [YOLOv5 分割 Colab 笔记本](https://github.com/ultralytics/yolov5/blob/master/segment/tutorial.ipynb) 以快速入门。 +我们新的 YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7.0) 实例分割模型是世界上最快和最准确的模型,击败所有当前 [SOTA 基准](https://paperswithcode.com/sota/real-time-instance-segmentation-on-mscoco)。我们使它非常易于训练、验证和部署。更多细节请查看 [发行说明](https://github.com/ultralytics/yolov5/releases/v7.0) 或访问我们的 [YOLOv5 分割 Colab 笔记本](https://github.com/ultralytics/yolov5/blob/master/segment/tutorial.ipynb) 以快速入门。
实例分割模型列表 @@ -283,9 +262,7 @@ YOLOv5 超级容易上手,简单易学。我们优先考虑现实世界的结
-我们使用 A100 GPU 在 COCO 上以 640 图像大小训练了 300 epochs 得到 YOLOv5 分割模型。我们将所有模型导出到 ONNX FP32 以进行 -CPU 速度测试,并导出到 TensorRT FP16 以进行 GPU 速度测试。为了便于再现,我们在 -Google [Colab Pro](https://colab.research.google.com/signup) 上进行了所有速度测试。 +我们使用 A100 GPU 在 COCO 上以 640 图像大小训练了 300 epochs 得到 YOLOv5 分割模型。我们将所有模型导出到 ONNX FP32 以进行 CPU 速度测试,并导出到 TensorRT FP16 以进行 GPU 速度测试。为了便于再现,我们在 Google [Colab Pro](https://colab.research.google.com/signup) 上进行了所有速度测试。 | 模型 | 尺寸
(像素) | mAPbox
50-95 | mAPmask
50-95 | 训练时长
300 epochs
A100 GPU(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TRT A100
(ms) | 参数量
(M) | FLOPs
@640 (B) | | ------------------------------------------------------------------------------------------ | --------------- | -------------------- | --------------------- | --------------------------------------- | ----------------------------- | ----------------------------- | --------------- | ---------------------- | @@ -295,15 +272,10 @@ Google [Colab Pro](https://colab.research.google.com/signup) 上进行了所有 | [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | | [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | -- 所有模型使用 SGD 优化器训练, 都使用 `lr0=0.01` 和 `weight_decay=5e-5` 参数, 图像大小为 640 。
训练 log - 可以查看 https://wandb.ai/glenn-jocher/YOLOv5_v70_official -- **准确性**结果都在 COCO 数据集上,使用单模型单尺度测试得到。
- 复现命令 `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt` -- **推理速度**是使用 100 张图像推理时间进行平均得到,测试环境使用 [Colab Pro](https://colab.research.google.com/signup) 上 - A100 高 RAM 实例。结果仅表示推理速度(NMS 每张图像增加约 1 毫秒)。
- 复现命令 `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt --batch 1` -- **模型转换**到 FP32 的 ONNX 和 FP16 的 TensorRT 脚本为 `export.py`.
- 运行命令 `python export.py --weights yolov5s-seg.pt --include engine --device 0 --half` +- 所有模型使用 SGD 优化器训练, 都使用 `lr0=0.01` 和 `weight_decay=5e-5` 参数, 图像大小为 640 。
训练 log 可以查看 https://wandb.ai/glenn-jocher/YOLOv5_v70_official +- **准确性**结果都在 COCO 数据集上,使用单模型单尺度测试得到。
复现命令 `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt` +- **推理速度**是使用 100 张图像推理时间进行平均得到,测试环境使用 [Colab Pro](https://colab.research.google.com/signup) 上 A100 高 RAM 实例。结果仅表示推理速度(NMS 每张图像增加约 1 毫秒)。
复现命令 `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt --batch 1` +- **模型转换**到 FP32 的 ONNX 和 FP16 的 TensorRT 脚本为 `export.py`.
运行命令 `python export.py --weights yolov5s-seg.pt --include engine --device 0 --half`
@@ -312,9 +284,7 @@ Google [Colab Pro](https://colab.research.google.com/signup) 上进行了所有 ### 训练 -YOLOv5分割训练支持自动下载 COCO128-seg 分割数据集,用户仅需在启动指令中包含 `--data coco128-seg.yaml` 参数。 -若要手动下载,使用命令 `bash data/scripts/get_coco.sh --train --val --segments`, -在下载完毕后,使用命令 `python train.py --data coco.yaml` 开启训练。 +YOLOv5分割训练支持自动下载 COCO128-seg 分割数据集,用户仅需在启动指令中包含 `--data coco128-seg.yaml` 参数。 若要手动下载,使用命令 `bash data/scripts/get_coco.sh --train --val --segments`, 在下载完毕后,使用命令 `python train.py --data coco.yaml` 开启训练。 ```bash # 单 GPU @@ -362,19 +332,14 @@ python export.py --weights yolov5s-seg.pt --include onnx engine --img 640 --devi ##
分类网络 ⭐ 新
-YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) -带来对分类模型训练、验证和部署的支持!详情请查看 [发行说明](https://github.com/ultralytics/yolov5/releases/v6.2) -或访问我们的 [YOLOv5 分类 Colab 笔记本](https://github.com/ultralytics/yolov5/blob/master/classify/tutorial.ipynb) -以快速入门。 +YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) 带来对分类模型训练、验证和部署的支持!详情请查看 [发行说明](https://github.com/ultralytics/yolov5/releases/v6.2) 或访问我们的 [YOLOv5 分类 Colab 笔记本](https://github.com/ultralytics/yolov5/blob/master/classify/tutorial.ipynb) 以快速入门。
分类网络模型
-我们使用 4xA100 实例在 ImageNet 上训练了 90 个 epochs 得到 YOLOv5-cls 分类模型,我们训练了 ResNet 和 EfficientNet -模型以及相同的默认训练设置以进行比较。我们将所有模型导出到 ONNX FP32 以进行 CPU 速度测试,并导出到 TensorRT FP16 以进行 -GPU 速度测试。为了便于重现,我们在 Google 上进行了所有速度测试 [Colab Pro](https://colab.research.google.com/signup) 。 +我们使用 4xA100 实例在 ImageNet 上训练了 90 个 epochs 得到 YOLOv5-cls 分类模型,我们训练了 ResNet 和 EfficientNet 模型以及相同的默认训练设置以进行比较。我们将所有模型导出到 ONNX FP32 以进行 CPU 速度测试,并导出到 TensorRT FP16 以进行 GPU 速度测试。为了便于重现,我们在 Google 上进行了所有速度测试 [Colab Pro](https://colab.research.google.com/signup) 。 | 模型 | 尺寸
(像素) | acc
top1 | acc
top5 | 训练时长
90 epochs
4xA100(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TensorRT V100
(ms) | 参数
(M) | FLOPs
@640 (B) | | -------------------------------------------------------------------------------------------------- | --------------- | ---------------- | ---------------- | ------------------------------------ | ----------------------------- | ---------------------------------- | -------------- | ---------------------- | @@ -397,14 +362,10 @@ GPU 速度测试。为了便于重现,我们在 Google 上进行了所有速
Table Notes (点击以展开) -- 所有模型都使用 SGD 优化器训练 90 个 epochs,都使用 `lr0=0.001` 和 `weight_decay=5e-5` 参数, 图像大小为 224 - ,且都使用默认设置。
训练 log 可以查看 https://wandb.ai/glenn-jocher/YOLOv5-Classifier-v6-2 -- **准确性**都在单模型单尺度上计算,数据集使用 [ImageNet-1k](https://www.image-net.org/index.php) 。
- 复现命令 `python classify/val.py --data ../datasets/imagenet --img 224` -- **推理速度**是使用 100 个推理图像进行平均得到,测试环境使用谷歌 [Colab Pro](https://colab.research.google.com/signup) - V100 高 RAM 实例。
复现命令 `python classify/val.py --data ../datasets/imagenet --img 224 --batch 1` -- **模型导出**到 FP32 的 ONNX 和 FP16 的 TensorRT 使用 `export.py` 。
- 复现命令 `python export.py --weights yolov5s-cls.pt --include engine onnx --imgsz 224` +- 所有模型都使用 SGD 优化器训练 90 个 epochs,都使用 `lr0=0.001` 和 `weight_decay=5e-5` 参数, 图像大小为 224 ,且都使用默认设置。
训练 log 可以查看 https://wandb.ai/glenn-jocher/YOLOv5-Classifier-v6-2 +- **准确性**都在单模型单尺度上计算,数据集使用 [ImageNet-1k](https://www.image-net.org/index.php) 。
复现命令 `python classify/val.py --data ../datasets/imagenet --img 224` +- **推理速度**是使用 100 个推理图像进行平均得到,测试环境使用谷歌 [Colab Pro](https://colab.research.google.com/signup) V100 高 RAM 实例。
复现命令 `python classify/val.py --data ../datasets/imagenet --img 224 --batch 1` +- **模型导出**到 FP32 的 ONNX 和 FP16 的 TensorRT 使用 `export.py` 。
复现命令 `python export.py --weights yolov5s-cls.pt --include engine onnx --imgsz 224`
@@ -413,8 +374,7 @@ GPU 速度测试。为了便于重现,我们在 Google 上进行了所有速 ### 训练 -YOLOv5 分类训练支持自动下载 MNIST、Fashion-MNIST、CIFAR10、CIFAR100、Imagenette、Imagewoof 和 ImageNet -数据集,命令中使用 `--data` 即可。 MNIST 示例 `--data mnist` 。 +YOLOv5 分类训练支持自动下载 MNIST、Fashion-MNIST、CIFAR10、CIFAR100、Imagenette、Imagewoof 和 ImageNet 数据集,命令中使用 `--data` 即可。 MNIST 示例 `--data mnist` 。 ```bash # 单 GPU @@ -459,7 +419,7 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu ##
环境
-使用下面我们经过验证的环境,在几秒钟内开始使用 YOLOv5 。单击下面的图标了解详细信息。 +使用下面我们经过验证的环境,在几秒钟内开始使用 YOLOv3 。单击下面的图标了解详细信息。
@@ -471,7 +431,7 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu - + @@ -483,9 +443,7 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu ##
贡献
-我们喜欢您的意见或建议!我们希望尽可能简单和透明地为 YOLOv5 做出贡献。请看我们的 [投稿指南](CONTRIBUTING.md) -,并填写 [YOLOv5调查](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) -向我们发送您的体验反馈。感谢我们所有的贡献者! +我们喜欢您的意见或建议!我们希望尽可能简单和透明地为 YOLOv3 做出贡献。请看我们的 [投稿指南](CONTRIBUTING.md),并填写 [YOLOv5调查](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) 向我们发送您的体验反馈。感谢我们所有的贡献者! @@ -494,16 +452,14 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu ##
License
-YOLOv5 在两种不同的 License 下可用: +YOLOv3 在两种不同的 License 下可用: - **GPL-3.0 License**: 查看 [License](https://github.com/ultralytics/yolov5/blob/master/LICENSE) 文件的详细信息。 -- **企业License**:在没有 GPL-3.0 开源要求的情况下为商业产品开发提供更大的灵活性。典型用例是将 Ultralytics 软件和 AI - 模型嵌入到商业产品和应用程序中。在以下位置申请企业许可证 [Ultralytics 许可](https://ultralytics.com/license) 。 +- **企业License**:在没有 GPL-3.0 开源要求的情况下为商业产品开发提供更大的灵活性。典型用例是将 Ultralytics 软件和 AI 模型嵌入到商业产品和应用程序中。在以下位置申请企业许可证 [Ultralytics 许可](https://ultralytics.com/license) 。 ##
联系我们
-请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues) -或 [Ultralytics Community Forum](https://community.ultralytis.com) 以报告 YOLOv5 错误和请求功能。 +请访问 [GitHub Issues](https://github.com/ultralytics/yolov5/issues) 或 [Ultralytics Community Forum](https://community.ultralytis.com) 以报告 YOLOv3 错误和请求功能。
-| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | -| :--------------------------------------------------------------------------------: | :-------------------------------------------------------------------------: | :-------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | -| 将您的自定义数据集进行标注并直接导出到 YOLOv3 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv3 [ClearML](https://cutt.ly/yolov5-readme-clearml)(开源!) | 永远免费,[Comet](https://bit.ly/yolov5-readme-comet)可让您保存 YOLOv3 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv3 推理的速度最高可提高6倍 | +| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | +| :--------------------------------------------------------------------------------: | :-------------------------------------------------------------------------: |:----------------------------------------------------------------------------------:| :------------------------------------------------------------------------------------: | +| 将您的自定义数据集进行标注并直接导出到 YOLOv3 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv3 [ClearML](https://cutt.ly/yolov5-readme-clearml)(开源!) | 永远免费,[Comet](https://bit.ly/yolov5-readme-comet2)可让您保存 YOLOv3 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv3 推理的速度最高可提高6倍 | ##
Ultralytics HUB
From 21a56e51e57dc21035fbf30400664e605f4824be Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 15 Feb 2023 20:34:42 +0400 Subject: [PATCH 0936/1185] Update README.md (#2016) * Update README.md * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- README.zh-CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.zh-CN.md b/README.zh-CN.md index c17891fa5e..6cbced4997 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -192,7 +192,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | -| :--------------------------------------------------------------------------------: | :-------------------------------------------------------------------------: |:----------------------------------------------------------------------------------:| :------------------------------------------------------------------------------------: | +| :--------------------------------------------------------------------------------: | :-------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | | 将您的自定义数据集进行标注并直接导出到 YOLOv3 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv3 [ClearML](https://cutt.ly/yolov5-readme-clearml)(开源!) | 永远免费,[Comet](https://bit.ly/yolov5-readme-comet2)可让您保存 YOLOv3 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv3 推理的速度最高可提高6倍 | ##
Ultralytics HUB
From a0a40127394c3518b5f2fc12596d40207f84909a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 17 Feb 2023 21:27:34 +0100 Subject: [PATCH 0937/1185] Update downloads.py (#2018) * Update downloads.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- utils/downloads.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/utils/downloads.py b/utils/downloads.py index 6ca02aaa26..63d5be0e07 100644 --- a/utils/downloads.py +++ b/utils/downloads.py @@ -98,11 +98,9 @@ def github_assets(repository, version='latest'): file.parent.mkdir(parents=True, exist_ok=True) # make parent dir (if required) if name in assets: - url3 = 'https://drive.google.com/drive/folders/1EFQTEUeXWSFww0luse2jB9M1QNZQGwNl' # backup gdrive mirror - safe_download( - file, - url=f'https://github.com/{repo}/releases/download/{tag}/{name}', - min_bytes=1E5, - error_msg=f'{file} missing, try downloading from https://github.com/{repo}/releases/{tag} or {url3}') + safe_download(file, + url=f'https://github.com/{repo}/releases/download/{tag}/{name}', + min_bytes=1E5, + error_msg=f'{file} missing, try downloading from https://github.com/{repo}/releases/{tag}') return str(file) From 527ce029166935ddc5e70a187aaee4c480365ae8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 17 Feb 2023 21:52:12 +0100 Subject: [PATCH 0938/1185] Update .pre-commit-config.yaml (#2019) * Update .pre-commit-config.yaml * Update __init__.py * Update .pre-commit-config.yaml * Precommit updates --- .pre-commit-config.yaml | 35 ++--- benchmarks.py | 2 +- classify/predict.py | 4 +- classify/train.py | 24 +-- classify/tutorial.ipynb | 2 +- classify/val.py | 8 +- detect.py | 2 +- export.py | 18 +-- models/common.py | 16 +- models/segment/yolov5m-seg.yaml | 2 +- models/segment/yolov5s-seg.yaml | 2 +- models/tf.py | 12 +- segment/predict.py | 2 +- segment/train.py | 14 +- segment/tutorial.ipynb | 2 +- segment/val.py | 16 +- train.py | 6 +- tutorial.ipynb | 2 +- utils/__init__.py | 2 +- utils/dataloaders.py | 34 ++--- utils/downloads.py | 2 +- utils/flask_rest_api/example_request.py | 8 +- utils/flask_rest_api/restapi.py | 22 +-- utils/general.py | 46 +++--- utils/loggers/__init__.py | 16 +- utils/loggers/clearml/clearml_utils.py | 6 +- utils/loggers/comet/__init__.py | 192 ++++++++++++------------ utils/loggers/comet/comet_utils.py | 42 +++--- utils/loggers/comet/hpo.py | 32 ++-- utils/loggers/wandb/wandb_utils.py | 10 +- utils/metrics.py | 10 +- utils/plots.py | 2 +- utils/segment/dataloaders.py | 32 ++-- utils/segment/loss.py | 12 +- utils/segment/metrics.py | 90 +++++------ utils/segment/plots.py | 20 +-- utils/torch_utils.py | 4 +- utils/triton.py | 14 +- val.py | 4 +- 39 files changed, 383 insertions(+), 386 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b188048e63..c5162378ab 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,8 +1,5 @@ -# Define hooks for code formations -# Will be applied on any updated commit files if a user has installed and linked commit hook - -default_language_version: - python: python3.8 +# Ultralytics YOLO 🚀, GPL-3.0 license +# Pre-commit hooks. For more information see https://github.com/pre-commit/pre-commit-hooks/blob/main/README.md exclude: 'docs/' # Define bot property if installed via https://github.com/marketplace/pre-commit-ci @@ -16,13 +13,13 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - # - id: end-of-file-fixer + - id: end-of-file-fixer - id: trailing-whitespace - id: check-case-conflict - id: check-yaml - - id: check-toml - - id: pretty-format-json - id: check-docstring-first + - id: double-quote-string-fixer + - id: detect-private-key - repo: https://github.com/asottile/pyupgrade rev: v3.3.1 @@ -31,11 +28,11 @@ repos: name: Upgrade code args: [--py37-plus] - # - repo: https://github.com/PyCQA/isort - # rev: 5.11.4 - # hooks: - # - id: isort - # name: Sort imports + - repo: https://github.com/PyCQA/isort + rev: 5.12.0 + hooks: + - id: isort + name: Sort imports - repo: https://github.com/google/yapf rev: v0.32.0 @@ -59,12 +56,12 @@ repos: - id: flake8 name: PEP8 - #- repo: https://github.com/codespell-project/codespell - # rev: v2.2.2 - # hooks: - # - id: codespell - # args: - # - --ignore-words-list=crate,nd + - repo: https://github.com/codespell-project/codespell + rev: v2.2.2 + hooks: + - id: codespell + args: + - --ignore-words-list=crate,nd,strack,dota #- repo: https://github.com/asottile/yesqa # rev: v1.4.0 diff --git a/benchmarks.py b/benchmarks.py index b9a4136014..38fcb0239f 100644 --- a/benchmarks.py +++ b/benchmarks.py @@ -164,6 +164,6 @@ def main(opt): test(**vars(opt)) if opt.test else run(**vars(opt)) -if __name__ == "__main__": +if __name__ == '__main__': opt = parse_opt() main(opt) diff --git a/classify/predict.py b/classify/predict.py index dc7a3edae7..bbb07640dd 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -179,7 +179,7 @@ def run( vid_writer[i].write(im0) # Print time (inference-only) - LOGGER.info(f"{s}{dt[1].dt * 1E3:.1f}ms") + LOGGER.info(f'{s}{dt[1].dt * 1E3:.1f}ms') # Print results t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image @@ -221,6 +221,6 @@ def main(opt): run(**vars(opt)) -if __name__ == "__main__": +if __name__ == '__main__': opt = parse_opt() main(opt) diff --git a/classify/train.py b/classify/train.py index 4d62bfc75c..3db68dc032 100644 --- a/classify/train.py +++ b/classify/train.py @@ -220,11 +220,11 @@ def train(opt, device): # Log metrics = { - "train/loss": tloss, - f"{val}/loss": vloss, - "metrics/accuracy_top1": top1, - "metrics/accuracy_top5": top5, - "lr/0": optimizer.param_groups[0]['lr']} # learning rate + 'train/loss': tloss, + f'{val}/loss': vloss, + 'metrics/accuracy_top1': top1, + 'metrics/accuracy_top5': top5, + 'lr/0': optimizer.param_groups[0]['lr']} # learning rate logger.log_metrics(metrics, epoch) # Save model @@ -251,11 +251,11 @@ def train(opt, device): if RANK in {-1, 0} and final_epoch: LOGGER.info(f'\nTraining complete ({(time.time() - t0) / 3600:.3f} hours)' f"\nResults saved to {colorstr('bold', save_dir)}" - f"\nPredict: python classify/predict.py --weights {best} --source im.jpg" - f"\nValidate: python classify/val.py --weights {best} --data {data_dir}" - f"\nExport: python export.py --weights {best} --include onnx" + f'\nPredict: python classify/predict.py --weights {best} --source im.jpg' + f'\nValidate: python classify/val.py --weights {best} --data {data_dir}' + f'\nExport: python export.py --weights {best} --include onnx' f"\nPyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', '{best}')" - f"\nVisualize: https://netron.app\n") + f'\nVisualize: https://netron.app\n') # Plot examples images, labels = (x[:25] for x in next(iter(testloader))) # first 25 images and labels @@ -263,7 +263,7 @@ def train(opt, device): file = imshow_cls(images, labels, pred, model.names, verbose=False, f=save_dir / 'test_images.jpg') # Log results - meta = {"epochs": epochs, "top1_acc": best_fitness, "date": datetime.now().isoformat()} + meta = {'epochs': epochs, 'top1_acc': best_fitness, 'date': datetime.now().isoformat()} logger.log_images(file, name='Test Examples (true-predicted)', epoch=epoch) logger.log_model(best, epochs, metadata=meta) @@ -310,7 +310,7 @@ def main(opt): assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") + dist.init_process_group(backend='nccl' if dist.is_nccl_available() else 'gloo') # Parameters opt.save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok) # increment run @@ -328,6 +328,6 @@ def run(**kwargs): return opt -if __name__ == "__main__": +if __name__ == '__main__': opt = parse_opt() main(opt) diff --git a/classify/tutorial.ipynb b/classify/tutorial.ipynb index e3a60c4ee6..73c0ea303b 100644 --- a/classify/tutorial.ipynb +++ b/classify/tutorial.ipynb @@ -1477,4 +1477,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} diff --git a/classify/val.py b/classify/val.py index 45729609aa..f0041ea72a 100644 --- a/classify/val.py +++ b/classify/val.py @@ -100,7 +100,7 @@ def run( pred, targets, loss, dt = [], [], 0, (Profile(), Profile(), Profile()) n = len(dataloader) # number of batches action = 'validating' if dataloader.dataset.root.stem == 'val' else 'testing' - desc = f"{pbar.desc[:-36]}{action:>36}" if pbar else f"{action}" + desc = f'{pbar.desc[:-36]}{action:>36}' if pbar else f'{action}' bar = tqdm(dataloader, desc, n, not training, bar_format=TQDM_BAR_FORMAT, position=0) with torch.cuda.amp.autocast(enabled=device.type != 'cpu'): for images, labels in bar: @@ -123,14 +123,14 @@ def run( top1, top5 = acc.mean(0).tolist() if pbar: - pbar.desc = f"{pbar.desc[:-36]}{loss:>12.3g}{top1:>12.3g}{top5:>12.3g}" + pbar.desc = f'{pbar.desc[:-36]}{loss:>12.3g}{top1:>12.3g}{top5:>12.3g}' if verbose: # all classes LOGGER.info(f"{'Class':>24}{'Images':>12}{'top1_acc':>12}{'top5_acc':>12}") LOGGER.info(f"{'all':>24}{targets.shape[0]:>12}{top1:>12.3g}{top5:>12.3g}") for i, c in model.names.items(): acc_i = acc[targets == i] top1i, top5i = acc_i.mean(0).tolist() - LOGGER.info(f"{c:>24}{acc_i.shape[0]:>12}{top1i:>12.3g}{top5i:>12.3g}") + LOGGER.info(f'{c:>24}{acc_i.shape[0]:>12}{top1i:>12.3g}{top5i:>12.3g}') # Print results t = tuple(x.t / len(dataloader.dataset.samples) * 1E3 for x in dt) # speeds per image @@ -165,6 +165,6 @@ def main(opt): run(**vars(opt)) -if __name__ == "__main__": +if __name__ == '__main__': opt = parse_opt() main(opt) diff --git a/detect.py b/detect.py index e8b7674614..d4ab1c8d9d 100644 --- a/detect.py +++ b/detect.py @@ -260,6 +260,6 @@ def main(opt): run(**vars(opt)) -if __name__ == "__main__": +if __name__ == '__main__': opt = parse_opt() main(opt) diff --git a/export.py b/export.py index 3d54cbf84c..fd4720a030 100644 --- a/export.py +++ b/export.py @@ -120,7 +120,7 @@ def export_torchscript(model, im, file, optimize, prefix=colorstr('TorchScript:' f = file.with_suffix('.torchscript') ts = torch.jit.trace(model, im, strict=False) - d = {"shape": im.shape, "stride": int(max(model.stride)), "names": model.names} + d = {'shape': im.shape, 'stride': int(max(model.stride)), 'names': model.names} extra_files = {'config.txt': json.dumps(d)} # torch._C.ExtraFilesMap() if optimize: # https://pytorch.org/tutorials/recipes/mobile_interpreter.html optimize_for_mobile(ts)._save_for_lite_interpreter(str(f), _extra_files=extra_files) @@ -230,7 +230,7 @@ def export_coreml(model, im, file, int8, half, prefix=colorstr('CoreML:')): if bits < 32: if MACOS: # quantization only supported on macOS with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=DeprecationWarning) # suppress numpy==1.20 float warning + warnings.filterwarnings('ignore', category=DeprecationWarning) # suppress numpy==1.20 float warning ct_model = ct.models.neural_network.quantization_utils.quantize_weights(ct_model, bits, mode) else: print(f'{prefix} quantization only supported on macOS, skipping...') @@ -286,7 +286,7 @@ def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose if dynamic: if im.shape[0] <= 1: - LOGGER.warning(f"{prefix} WARNING ⚠️ --dynamic model requires maximum --batch-size argument") + LOGGER.warning(f'{prefix} WARNING ⚠️ --dynamic model requires maximum --batch-size argument') profile = builder.create_optimization_profile() for inp in inputs: profile.set_shape(inp.name, (1, *im.shape[1:]), (max(1, im.shape[0] // 2), *im.shape[1:]), im.shape) @@ -396,7 +396,7 @@ def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=c converter.target_spec.supported_ops.append(tf.lite.OpsSet.SELECT_TF_OPS) tflite_model = converter.convert() - open(f, "wb").write(tflite_model) + open(f, 'wb').write(tflite_model) return f, None @@ -420,7 +420,7 @@ def export_edgetpu(file, prefix=colorstr('Edge TPU:')): f = str(file).replace('.pt', '-int8_edgetpu.tflite') # Edge TPU model f_tfl = str(file).replace('.pt', '-int8.tflite') # TFLite model - cmd = f"edgetpu_compiler -s -d -k 10 --out_dir {file.parent} {f_tfl}" + cmd = f'edgetpu_compiler -s -d -k 10 --out_dir {file.parent} {f_tfl}' subprocess.run(cmd.split(), check=True) return f, None @@ -601,14 +601,14 @@ def run( det &= not seg # segmentation models inherit from SegmentationModel(DetectionModel) dir = Path('segment' if seg else 'classify' if cls else '') h = '--half' if half else '' # --half FP16 inference arg - s = "# WARNING ⚠️ ClassificationModel not yet supported for PyTorch Hub AutoShape inference" if cls else \ - "# WARNING ⚠️ SegmentationModel not yet supported for PyTorch Hub AutoShape inference" if seg else '' + s = '# WARNING ⚠️ ClassificationModel not yet supported for PyTorch Hub AutoShape inference' if cls else \ + '# WARNING ⚠️ SegmentationModel not yet supported for PyTorch Hub AutoShape inference' if seg else '' LOGGER.info(f'\nExport complete ({time.time() - t:.1f}s)' f"\nResults saved to {colorstr('bold', file.parent.resolve())}" f"\nDetect: python {dir / ('detect.py' if det else 'predict.py')} --weights {f[-1]} {h}" f"\nValidate: python {dir / 'val.py'} --weights {f[-1]} {h}" f"\nPyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', '{f[-1]}') {s}" - f"\nVisualize: https://netron.app") + f'\nVisualize: https://netron.app') return f # return list of exported files/dirs @@ -650,6 +650,6 @@ def main(opt): run(**vars(opt)) -if __name__ == "__main__": +if __name__ == '__main__': opt = parse_opt() main(opt) diff --git a/models/common.py b/models/common.py index efb668171a..bc5fc0d356 100644 --- a/models/common.py +++ b/models/common.py @@ -380,11 +380,11 @@ def __init__(self, weights='yolov5s.pt', device=torch.device('cpu'), dnn=False, w = next(Path(w).glob('*.xml')) # get *.xml file from *_openvino_model dir network = ie.read_model(model=w, weights=Path(w).with_suffix('.bin')) if network.get_parameters()[0].get_layout().empty: - network.get_parameters()[0].set_layout(Layout("NCHW")) + network.get_parameters()[0].set_layout(Layout('NCHW')) batch_dim = get_batch(network) if batch_dim.is_static: batch_size = batch_dim.get_length() - executable_network = ie.compile_model(network, device_name="CPU") # device_name="MYRIAD" for Intel NCS2 + executable_network = ie.compile_model(network, device_name='CPU') # device_name="MYRIAD" for Intel NCS2 stride, names = self._load_metadata(Path(w).with_suffix('.yaml')) # load metadata elif engine: # TensorRT LOGGER.info(f'Loading {w} for TensorRT inference...') @@ -431,7 +431,7 @@ def __init__(self, weights='yolov5s.pt', device=torch.device('cpu'), dnn=False, import tensorflow as tf def wrap_frozen_graph(gd, inputs, outputs): - x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=""), []) # wrapped + x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=''), []) # wrapped ge = x.graph.as_graph_element return x.prune(tf.nest.map_structure(ge, inputs), tf.nest.map_structure(ge, outputs)) @@ -445,7 +445,7 @@ def gd_outputs(gd): gd = tf.Graph().as_graph_def() # TF GraphDef with open(w, 'rb') as f: gd.ParseFromString(f.read()) - frozen_func = wrap_frozen_graph(gd, inputs="x:0", outputs=gd_outputs(gd)) + frozen_func = wrap_frozen_graph(gd, inputs='x:0', outputs=gd_outputs(gd)) elif tflite or edgetpu: # https://www.tensorflow.org/lite/guide/python#install_tensorflow_lite_for_python try: # https://coral.ai/docs/edgetpu/tflite-python/#update-existing-tf-lite-code-for-the-edge-tpu from tflite_runtime.interpreter import Interpreter, load_delegate @@ -467,9 +467,9 @@ def gd_outputs(gd): output_details = interpreter.get_output_details() # outputs # load metadata with contextlib.suppress(zipfile.BadZipFile): - with zipfile.ZipFile(w, "r") as model: + with zipfile.ZipFile(w, 'r') as model: meta_file = model.namelist()[0] - meta = ast.literal_eval(model.read(meta_file).decode("utf-8")) + meta = ast.literal_eval(model.read(meta_file).decode('utf-8')) stride, names = int(meta['stride']), meta['names'] elif tfjs: # TF.js raise NotImplementedError('ERROR: YOLOv3 TF.js inference is not supported') @@ -491,7 +491,7 @@ def gd_outputs(gd): check_requirements('tritonclient[all]') from utils.triton import TritonRemoteModel model = TritonRemoteModel(url=w) - nhwc = model.runtime.startswith("tensorflow") + nhwc = model.runtime.startswith('tensorflow') else: raise NotImplementedError(f'ERROR: {w} is not a supported format') @@ -608,7 +608,7 @@ def _model_type(p='path/to/model.pt'): url = urlparse(p) # if url may be Triton inference server types = [s in Path(p).name for s in sf] types[8] &= not types[9] # tflite &= not edgetpu - triton = not any(types) and all([any(s in url.scheme for s in ["http", "grpc"]), url.netloc]) + triton = not any(types) and all([any(s in url.scheme for s in ['http', 'grpc']), url.netloc]) return types + [triton] @staticmethod diff --git a/models/segment/yolov5m-seg.yaml b/models/segment/yolov5m-seg.yaml index febe93f644..cafadcd9cc 100644 --- a/models/segment/yolov5m-seg.yaml +++ b/models/segment/yolov5m-seg.yaml @@ -45,4 +45,4 @@ head: [-1, 3, C3, [1024, False]], # 23 (P5/32-large) [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) - ] \ No newline at end of file + ] diff --git a/models/segment/yolov5s-seg.yaml b/models/segment/yolov5s-seg.yaml index 3b31ed3a3c..6018cdb431 100644 --- a/models/segment/yolov5s-seg.yaml +++ b/models/segment/yolov5s-seg.yaml @@ -45,4 +45,4 @@ head: [-1, 3, C3, [1024, False]], # 23 (P5/32-large) [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) - ] \ No newline at end of file + ] diff --git a/models/tf.py b/models/tf.py index 4c40877657..748a95c9a0 100644 --- a/models/tf.py +++ b/models/tf.py @@ -356,7 +356,7 @@ class TFUpsample(keras.layers.Layer): # TF version of torch.nn.Upsample() def __init__(self, size, scale_factor, mode, w=None): # warning: all arguments needed including 'w' super().__init__() - assert scale_factor % 2 == 0, "scale_factor must be multiple of 2" + assert scale_factor % 2 == 0, 'scale_factor must be multiple of 2' self.upsample = lambda x: tf.image.resize(x, (x.shape[1] * scale_factor, x.shape[2] * scale_factor), mode) # self.upsample = keras.layers.UpSampling2D(size=scale_factor, interpolation=mode) # with default arguments: align_corners=False, half_pixel_centers=False @@ -371,7 +371,7 @@ class TFConcat(keras.layers.Layer): # TF version of torch.concat() def __init__(self, dimension=1, w=None): super().__init__() - assert dimension == 1, "convert only NCHW to NHWC concat" + assert dimension == 1, 'convert only NCHW to NHWC concat' self.d = 3 def call(self, inputs): @@ -523,17 +523,17 @@ def _nms(x, topk_all=100, iou_thres=0.45, conf_thres=0.25): # agnostic NMS selected_boxes = tf.gather(boxes, selected_inds) padded_boxes = tf.pad(selected_boxes, paddings=[[0, topk_all - tf.shape(selected_boxes)[0]], [0, 0]], - mode="CONSTANT", + mode='CONSTANT', constant_values=0.0) selected_scores = tf.gather(scores_inp, selected_inds) padded_scores = tf.pad(selected_scores, paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]], - mode="CONSTANT", + mode='CONSTANT', constant_values=-1.0) selected_classes = tf.gather(class_inds, selected_inds) padded_classes = tf.pad(selected_classes, paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]], - mode="CONSTANT", + mode='CONSTANT', constant_values=-1.0) valid_detections = tf.shape(selected_inds)[0] return padded_boxes, padded_scores, padded_classes, valid_detections @@ -603,6 +603,6 @@ def main(opt): run(**vars(opt)) -if __name__ == "__main__": +if __name__ == '__main__': opt = parse_opt() main(opt) diff --git a/segment/predict.py b/segment/predict.py index ac832bf815..7ec63204dc 100644 --- a/segment/predict.py +++ b/segment/predict.py @@ -279,6 +279,6 @@ def main(opt): run(**vars(opt)) -if __name__ == "__main__": +if __name__ == '__main__': opt = parse_opt() main(opt) diff --git a/segment/train.py b/segment/train.py index 3efc883be4..a9786049e4 100644 --- a/segment/train.py +++ b/segment/train.py @@ -138,7 +138,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Batch size if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size batch_size = check_train_batch_size(model, imgsz, amp) - logger.update_params({"batch_size": batch_size}) + logger.update_params({'batch_size': batch_size}) # loggers.on_params_update({"batch_size": batch_size}) # Optimizer @@ -340,10 +340,10 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Mosaic plots if plots: if ni < 3: - plot_images_and_masks(imgs, targets, masks, paths, save_dir / f"train_batch{ni}.jpg") + plot_images_and_masks(imgs, targets, masks, paths, save_dir / f'train_batch{ni}.jpg') if ni == 10: files = sorted(save_dir.glob('train*.jpg')) - logger.log_images(files, "Mosaics", epoch) + logger.log_images(files, 'Mosaics', epoch) # end batch ------------------------------------------------------------------------------------------------ # Scheduler @@ -453,8 +453,8 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio files = ['results.png', 'confusion_matrix.png', *(f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R'))] files = [(save_dir / f) for f in files if (save_dir / f).exists()] # filter LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}") - logger.log_images(files, "Results", epoch + 1) - logger.log_images(sorted(save_dir.glob('val*.jpg')), "Validation", epoch + 1) + logger.log_images(files, 'Results', epoch + 1) + logger.log_images(sorted(save_dir.glob('val*.jpg')), 'Validation', epoch + 1) torch.cuda.empty_cache() return results @@ -547,7 +547,7 @@ def main(opt, callbacks=Callbacks()): assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") + dist.init_process_group(backend='nccl' if dist.is_nccl_available() else 'gloo') # Train if not opt.evolve: @@ -654,6 +654,6 @@ def run(**kwargs): return opt -if __name__ == "__main__": +if __name__ == '__main__': opt = parse_opt() main(opt) diff --git a/segment/tutorial.ipynb b/segment/tutorial.ipynb index be43d6d205..dc12b23a30 100644 --- a/segment/tutorial.ipynb +++ b/segment/tutorial.ipynb @@ -591,4 +591,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} diff --git a/segment/val.py b/segment/val.py index 0e64da288f..0245652404 100644 --- a/segment/val.py +++ b/segment/val.py @@ -70,8 +70,8 @@ def save_one_json(predn, jdict, path, class_map, pred_masks): from pycocotools.mask import encode def single_encode(x): - rle = encode(np.asarray(x[:, :, None], order="F", dtype="uint8"))[0] - rle["counts"] = rle["counts"].decode("utf-8") + rle = encode(np.asarray(x[:, :, None], order='F', dtype='uint8'))[0] + rle['counts'] = rle['counts'].decode('utf-8') return rle image_id = int(path.stem) if path.stem.isnumeric() else path.stem @@ -105,7 +105,7 @@ def process_batch(detections, labels, iouv, pred_masks=None, gt_masks=None, over gt_masks = gt_masks.repeat(nl, 1, 1) # shape(1,640,640) -> (n,640,640) gt_masks = torch.where(gt_masks == index, 1.0, 0.0) if gt_masks.shape[1:] != pred_masks.shape[1:]: - gt_masks = F.interpolate(gt_masks[None], pred_masks.shape[1:], mode="bilinear", align_corners=False)[0] + gt_masks = F.interpolate(gt_masks[None], pred_masks.shape[1:], mode='bilinear', align_corners=False)[0] gt_masks = gt_masks.gt_(0.5) iou = mask_iou(gt_masks.view(gt_masks.shape[0], -1), pred_masks.view(pred_masks.shape[0], -1)) else: # boxes @@ -231,8 +231,8 @@ def run( if isinstance(names, (list, tuple)): # old format names = dict(enumerate(names)) class_map = coco80_to_coco91_class() if is_coco else list(range(1000)) - s = ('%22s' + '%11s' * 10) % ('Class', 'Images', 'Instances', 'Box(P', "R", "mAP50", "mAP50-95)", "Mask(P", "R", - "mAP50", "mAP50-95)") + s = ('%22s' + '%11s' * 10) % ('Class', 'Images', 'Instances', 'Box(P', 'R', 'mAP50', 'mAP50-95)', 'Mask(P', 'R', + 'mAP50', 'mAP50-95)') dt = Profile(), Profile(), Profile() metrics = Metrics() loss = torch.zeros(4, device=device) @@ -343,7 +343,7 @@ def run( # Print results pf = '%22s' + '%11i' * 2 + '%11.3g' * 8 # print format - LOGGER.info(pf % ("all", seen, nt.sum(), *metrics.mean_results())) + LOGGER.info(pf % ('all', seen, nt.sum(), *metrics.mean_results())) if nt.sum() == 0: LOGGER.warning(f'WARNING ⚠️ no labels found in {task} set, can not compute metrics without labels') @@ -369,7 +369,7 @@ def run( if save_json and len(jdict): w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights anno_json = str(Path('../datasets/coco/annotations/instances_val2017.json')) # annotations - pred_json = str(save_dir / f"{w}_predictions.json") # predictions + pred_json = str(save_dir / f'{w}_predictions.json') # predictions LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') with open(pred_json, 'w') as f: json.dump(jdict, f) @@ -468,6 +468,6 @@ def main(opt): raise NotImplementedError(f'--task {opt.task} not in ("train", "val", "test", "speed", "study")') -if __name__ == "__main__": +if __name__ == '__main__': opt = parse_opt() main(opt) diff --git a/train.py b/train.py index 5ab44562c2..3d5796e0c0 100644 --- a/train.py +++ b/train.py @@ -147,7 +147,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Batch size if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size batch_size = check_train_batch_size(model, imgsz, amp) - loggers.on_params_update({"batch_size": batch_size}) + loggers.on_params_update({'batch_size': batch_size}) # Optimizer nbs = 64 # nominal batch size @@ -521,7 +521,7 @@ def main(opt, callbacks=Callbacks()): assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' torch.cuda.set_device(LOCAL_RANK) device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") + dist.init_process_group(backend='nccl' if dist.is_nccl_available() else 'gloo') # Train if not opt.evolve: @@ -630,6 +630,6 @@ def run(**kwargs): return opt -if __name__ == "__main__": +if __name__ == '__main__': opt = parse_opt() main(opt) diff --git a/tutorial.ipynb b/tutorial.ipynb index 63881fb9a6..5828c40dde 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -973,4 +973,4 @@ "outputs": [] } ] -} \ No newline at end of file +} diff --git a/utils/__init__.py b/utils/__init__.py index 2abd2a795b..8e855a3874 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -69,7 +69,7 @@ def notebook_init(verbose=True): if verbose: gb = 1 << 30 # bytes to GiB (1024 ** 3) ram = psutil.virtual_memory().total - total, used, free = shutil.disk_usage("/") + total, used, free = shutil.disk_usage('/') display.clear_output() s = f'({os.cpu_count()} CPUs, {ram / gb:.1f} GB RAM, {(total - free) / gb:.1f}/{total / gb:.1f} GB disk)' else: diff --git a/utils/dataloaders.py b/utils/dataloaders.py index ba0317ca91..2a038d1a7f 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -89,7 +89,7 @@ def exif_transpose(image): if method is not None: image = image.transpose(method) del exif[0x0112] - image.info["exif"] = exif.tobytes() + image.info['exif'] = exif.tobytes() return image @@ -212,11 +212,11 @@ def __init__(self, source, img_size=640, stride=32, auto=True, transforms=None): # Parse monitor shape monitor = self.sct.monitors[self.screen] - self.top = monitor["top"] if top is None else (monitor["top"] + top) - self.left = monitor["left"] if left is None else (monitor["left"] + left) - self.width = width or monitor["width"] - self.height = height or monitor["height"] - self.monitor = {"left": self.left, "top": self.top, "width": self.width, "height": self.height} + self.top = monitor['top'] if top is None else (monitor['top'] + top) + self.left = monitor['left'] if left is None else (monitor['left'] + left) + self.width = width or monitor['width'] + self.height = height or monitor['height'] + self.monitor = {'left': self.left, 'top': self.top, 'width': self.width, 'height': self.height} def __iter__(self): return self @@ -224,7 +224,7 @@ def __iter__(self): def __next__(self): # mss screen capture: get raw pixels from the screen as np array im0 = np.array(self.sct.grab(self.monitor))[:, :, :3] # [:, :, :3] BGRA to BGR - s = f"screen {self.screen} (LTWH): {self.left},{self.top},{self.width},{self.height}: " + s = f'screen {self.screen} (LTWH): {self.left},{self.top},{self.width},{self.height}: ' if self.transforms: im = self.transforms(im0) # transforms @@ -239,7 +239,7 @@ def __next__(self): class LoadImages: # YOLOv5 image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4` def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): - if isinstance(path, str) and Path(path).suffix == ".txt": # *.txt file with img/vid/dir on each line + if isinstance(path, str) and Path(path).suffix == '.txt': # *.txt file with img/vid/dir on each line path = Path(path).read_text().rsplit() files = [] for p in sorted(path) if isinstance(path, (list, tuple)) else [path]: @@ -358,7 +358,7 @@ def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, t # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc' check_requirements(('pafy', 'youtube_dl==2020.12.2')) import pafy - s = pafy.new(s).getbest(preftype="mp4").url # YouTube URL + s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam if s == 0: assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.' @@ -373,7 +373,7 @@ def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, t _, self.imgs[i] = cap.read() # guarantee first frame self.threads[i] = Thread(target=self.update, args=([i, cap, s]), daemon=True) - LOGGER.info(f"{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)") + LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)') self.threads[i].start() LOGGER.info('') # newline @@ -495,7 +495,7 @@ def __init__(self, # Display cache nf, nm, ne, nc, n = cache.pop('results') # found, missing, empty, corrupt, total if exists and LOCAL_RANK in {-1, 0}: - d = f"Scanning {cache_path}... {nf} images, {nm + ne} backgrounds, {nc} corrupt" + d = f'Scanning {cache_path}... {nf} images, {nm + ne} backgrounds, {nc} corrupt' tqdm(None, desc=prefix + d, total=n, initial=n, bar_format=TQDM_BAR_FORMAT) # display cache results if cache['msgs']: LOGGER.info('\n'.join(cache['msgs'])) # display warnings @@ -598,8 +598,8 @@ def check_cache_ram(self, safety_margin=0.1, prefix=''): mem = psutil.virtual_memory() cache = mem_required * (1 + safety_margin) < mem.available # to cache or not to cache, that is the question if not cache: - LOGGER.info(f"{prefix}{mem_required / gb:.1f}GB RAM required, " - f"{mem.available / gb:.1f}/{mem.total / gb:.1f}GB available, " + LOGGER.info(f'{prefix}{mem_required / gb:.1f}GB RAM required, ' + f'{mem.available / gb:.1f}/{mem.total / gb:.1f}GB available, ' f"{'caching images ✅' if cache else 'not caching images ⚠️'}") return cache @@ -607,7 +607,7 @@ def cache_labels(self, path=Path('./labels.cache'), prefix=''): # Cache dataset labels, check images and read shapes x = {} # dict nm, nf, ne, nc, msgs = 0, 0, 0, 0, [] # number missing, found, empty, corrupt, messages - desc = f"{prefix}Scanning {path.parent / path.stem}..." + desc = f'{prefix}Scanning {path.parent / path.stem}...' with Pool(NUM_THREADS) as pool: pbar = tqdm(pool.imap(verify_image_label, zip(self.im_files, self.label_files, repeat(prefix))), desc=desc, @@ -622,7 +622,7 @@ def cache_labels(self, path=Path('./labels.cache'), prefix=''): x[im_file] = [lb, shape, segments] if msg: msgs.append(msg) - pbar.desc = f"{desc} {nf} images, {nm + ne} backgrounds, {nc} corrupt" + pbar.desc = f'{desc} {nf} images, {nm + ne} backgrounds, {nc} corrupt' pbar.close() if msgs: @@ -1063,7 +1063,7 @@ def __init__(self, path='coco128.yaml', autodownload=False): if zipped: data['path'] = data_dir except Exception as e: - raise Exception("error/HUB/dataset_stats/yaml_load") from e + raise Exception('error/HUB/dataset_stats/yaml_load') from e check_dataset(data, autodownload) # download dataset if missing self.hub_dir = Path(data['path'] + '-hub') @@ -1188,7 +1188,7 @@ def __getitem__(self, i): else: # read image im = cv2.imread(f) # BGR if self.album_transforms: - sample = self.album_transforms(image=cv2.cvtColor(im, cv2.COLOR_BGR2RGB))["image"] + sample = self.album_transforms(image=cv2.cvtColor(im, cv2.COLOR_BGR2RGB))['image'] else: sample = self.torch_transforms(im) return sample, j diff --git a/utils/downloads.py b/utils/downloads.py index 63d5be0e07..cac99afaf9 100644 --- a/utils/downloads.py +++ b/utils/downloads.py @@ -55,7 +55,7 @@ def safe_download(file, url, url2=None, min_bytes=1E0, error_msg=''): if not file.exists() or file.stat().st_size < min_bytes: # check if file.exists(): file.unlink() # remove partial downloads - LOGGER.info(f"ERROR: {assert_msg}\n{error_msg}") + LOGGER.info(f'ERROR: {assert_msg}\n{error_msg}') LOGGER.info('') diff --git a/utils/flask_rest_api/example_request.py b/utils/flask_rest_api/example_request.py index 68eec2f32f..5e6d0c1dfc 100644 --- a/utils/flask_rest_api/example_request.py +++ b/utils/flask_rest_api/example_request.py @@ -7,13 +7,13 @@ import requests -DETECTION_URL = "http://localhost:5000/v1/object-detection/yolov5s" -IMAGE = "zidane.jpg" +DETECTION_URL = 'http://localhost:5000/v1/object-detection/yolov5s' +IMAGE = 'zidane.jpg' # Read image -with open(IMAGE, "rb") as f: +with open(IMAGE, 'rb') as f: image_data = f.read() -response = requests.post(DETECTION_URL, files={"image": image_data}).json() +response = requests.post(DETECTION_URL, files={'image': image_data}).json() pprint.pprint(response) diff --git a/utils/flask_rest_api/restapi.py b/utils/flask_rest_api/restapi.py index 290c6d5c88..5d8f599669 100644 --- a/utils/flask_rest_api/restapi.py +++ b/utils/flask_rest_api/restapi.py @@ -13,36 +13,36 @@ app = Flask(__name__) models = {} -DETECTION_URL = "/v1/object-detection/" +DETECTION_URL = '/v1/object-detection/' -@app.route(DETECTION_URL, methods=["POST"]) +@app.route(DETECTION_URL, methods=['POST']) def predict(model): - if request.method != "POST": + if request.method != 'POST': return - if request.files.get("image"): + if request.files.get('image'): # Method 1 # with request.files["image"] as f: # im = Image.open(io.BytesIO(f.read())) # Method 2 - im_file = request.files["image"] + im_file = request.files['image'] im_bytes = im_file.read() im = Image.open(io.BytesIO(im_bytes)) if model in models: results = models[model](im, size=640) # reduce size=320 for faster inference - return results.pandas().xyxy[0].to_json(orient="records") + return results.pandas().xyxy[0].to_json(orient='records') -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Flask API exposing YOLOv5 model") - parser.add_argument("--port", default=5000, type=int, help="port number") +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Flask API exposing YOLOv5 model') + parser.add_argument('--port', default=5000, type=int, help='port number') parser.add_argument('--model', nargs='+', default=['yolov5s'], help='model(s) to run, i.e. --model yolov5n yolov5s') opt = parser.parse_args() for m in opt.model: - models[m] = torch.hub.load("ultralytics/yolov5", m, force_reload=True, skip_validation=True) + models[m] = torch.hub.load('ultralytics/yolov5', m, force_reload=True, skip_validation=True) - app.run(host="0.0.0.0", port=opt.port) # debug=True causes Restarting with stat + app.run(host='0.0.0.0', port=opt.port) # debug=True causes Restarting with stat diff --git a/utils/general.py b/utils/general.py index 5ec2b5f704..56c94d58e5 100644 --- a/utils/general.py +++ b/utils/general.py @@ -90,11 +90,11 @@ def is_kaggle(): def is_docker() -> bool: """Check if the process runs inside a docker container.""" - if Path("/.dockerenv").exists(): + if Path('/.dockerenv').exists(): return True try: # check if docker is in control groups - with open("/proc/self/cgroup") as file: - return any("docker" in line for line in file) + with open('/proc/self/cgroup') as file: + return any('docker' in line for line in file) except OSError: return False @@ -113,7 +113,7 @@ def is_writeable(dir, test=False): return False -LOGGING_NAME = "yolov5" +LOGGING_NAME = 'yolov5' def set_logging(name=LOGGING_NAME, verbose=True): @@ -121,21 +121,21 @@ def set_logging(name=LOGGING_NAME, verbose=True): rank = int(os.getenv('RANK', -1)) # rank in world for Multi-GPU trainings level = logging.INFO if verbose and rank in {-1, 0} else logging.ERROR logging.config.dictConfig({ - "version": 1, - "disable_existing_loggers": False, - "formatters": { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { name: { - "format": "%(message)s"}}, - "handlers": { + 'format': '%(message)s'}}, + 'handlers': { name: { - "class": "logging.StreamHandler", - "formatter": name, - "level": level,}}, - "loggers": { + 'class': 'logging.StreamHandler', + 'formatter': name, + 'level': level,}}, + 'loggers': { name: { - "level": level, - "handlers": [name], - "propagate": False,}}}) + 'level': level, + 'handlers': [name], + 'propagate': False,}}}) set_logging(LOGGING_NAME) # run before defining LOGGER @@ -218,7 +218,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): def methods(instance): # Get class/instance methods - return [f for f in dir(instance) if callable(getattr(instance, f)) and not f.startswith("__")] + return [f for f in dir(instance) if callable(getattr(instance, f)) and not f.startswith('__')] def print_args(args: Optional[dict] = None, show_file=True, show_func=False): @@ -299,7 +299,7 @@ def check_online(): def run_once(): # Check once try: - socket.create_connection(("1.1.1.1", 443), 5) # check host accessibility + socket.create_connection(('1.1.1.1', 443), 5) # check host accessibility return True except OSError: return False @@ -386,7 +386,7 @@ def check_requirements(requirements=ROOT / 'requirements.txt', exclude=(), insta check_python() # check python version if isinstance(requirements, Path): # requirements.txt file file = requirements.resolve() - assert file.exists(), f"{prefix} {file} not found, check failed." + assert file.exists(), f'{prefix} {file} not found, check failed.' with file.open() as f: requirements = [f'{x.name}{x.specifier}' for x in pkg.parse_requirements(f) if x.name not in exclude] elif isinstance(requirements, str): @@ -450,7 +450,7 @@ def check_suffix(file='yolov5s.pt', suffix=('.pt',), msg=''): for f in file if isinstance(file, (list, tuple)) else [file]: s = Path(f).suffix.lower() # file suffix if len(s): - assert s in suffix, f"{msg}{f} acceptable suffix is {suffix}" + assert s in suffix, f'{msg}{f} acceptable suffix is {suffix}' def check_yaml(file, suffix=('.yaml', '.yml')): @@ -556,8 +556,8 @@ def check_dataset(data, autodownload=True): else: # python script r = exec(s, {'yaml': data}) # return None dt = f'({round(time.time() - t, 1)}s)' - s = f"success ✅ {dt}, saved to {colorstr('bold', DATASETS_DIR)}" if r in (0, None) else f"failure {dt} ❌" - LOGGER.info(f"Dataset download {s}") + s = f"success ✅ {dt}, saved to {colorstr('bold', DATASETS_DIR)}" if r in (0, None) else f'failure {dt} ❌' + LOGGER.info(f'Dataset download {s}') check_font('Arial.ttf' if is_ascii(data['names']) else 'Arial.Unicode.ttf', progress=True) # download fonts return data # dictionary @@ -675,7 +675,7 @@ def make_divisible(x, divisor): def clean_str(s): # Cleans a string by replacing special characters with underscore _ - return re.sub(pattern="[|@#!¡·$€%&()=?¿^*;:,¨´><+]", repl="_", string=s) + return re.sub(pattern='[|@#!¡·$€%&()=?¿^*;:,¨´><+]', repl='_', string=s) def one_cycle(y1=0.0, y2=1.0, steps=100): diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index a9a64f0f11..82e4458aae 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -121,8 +121,8 @@ def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, # Comet if comet_ml and 'comet' in self.include: - if isinstance(self.opt.resume, str) and self.opt.resume.startswith("comet://"): - run_id = self.opt.resume.split("/")[-1] + if isinstance(self.opt.resume, str) and self.opt.resume.startswith('comet://'): + run_id = self.opt.resume.split('/')[-1] self.comet_logger = CometLogger(self.opt, self.hyp, run_id=run_id) else: @@ -158,7 +158,7 @@ def on_pretrain_routine_end(self, labels, names): plot_labels(labels, names, self.save_dir) paths = self.save_dir.glob('*labels*.jpg') # training labels if self.wandb: - self.wandb.log({"Labels": [wandb.Image(str(x), caption=x.name) for x in paths]}) + self.wandb.log({'Labels': [wandb.Image(str(x), caption=x.name) for x in paths]}) # if self.clearml: # pass # ClearML saves these images automatically using hooks if self.comet_logger: @@ -212,7 +212,7 @@ def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) if self.wandb or self.clearml: files = sorted(self.save_dir.glob('val*.jpg')) if self.wandb: - self.wandb.log({"Validation": [wandb.Image(str(f), caption=f.name) for f in files]}) + self.wandb.log({'Validation': [wandb.Image(str(f), caption=f.name) for f in files]}) if self.clearml: self.clearml.log_debug_samples(files, title='Validation') @@ -279,7 +279,7 @@ def on_train_end(self, last, best, epoch, results): if self.wandb: self.wandb.log(dict(zip(self.keys[3:10], results))) - self.wandb.log({"Results": [wandb.Image(str(f), caption=f.name) for f in files]}) + self.wandb.log({'Results': [wandb.Image(str(f), caption=f.name) for f in files]}) # Calling wandb.log. TODO: Refactor this into WandbLogger.log_model if not self.opt.evolve: wandb.log_artifact(str(best if best.exists() else last), @@ -329,7 +329,7 @@ def __init__(self, opt, console_logger, include=('tb', 'wandb')): if wandb and 'wandb' in self.include: self.wandb = wandb.init(project=web_project_name(str(opt.project)), - name=None if opt.name == "exp" else opt.name, + name=None if opt.name == 'exp' else opt.name, config=opt) else: self.wandb = None @@ -370,12 +370,12 @@ def log_graph(self, model, imgsz=(640, 640)): def log_model(self, model_path, epoch=0, metadata={}): # Log model to all loggers if self.wandb: - art = wandb.Artifact(name=f"run_{wandb.run.id}_model", type="model", metadata=metadata) + art = wandb.Artifact(name=f'run_{wandb.run.id}_model', type='model', metadata=metadata) art.add_file(str(model_path)) wandb.log_artifact(art) def update_params(self, params): - # Update the paramters logged + # Update the parameters logged if self.wandb: wandb.run.config.update(params, allow_val_change=True) diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py index 3457727a96..2764abe90d 100644 --- a/utils/loggers/clearml/clearml_utils.py +++ b/utils/loggers/clearml/clearml_utils.py @@ -25,7 +25,7 @@ def construct_dataset(clearml_info_string): dataset_root_path = Path(dataset.get_local_copy()) # We'll search for the yaml file definition in the dataset - yaml_filenames = list(glob.glob(str(dataset_root_path / "*.yaml")) + glob.glob(str(dataset_root_path / "*.yml"))) + yaml_filenames = list(glob.glob(str(dataset_root_path / '*.yaml')) + glob.glob(str(dataset_root_path / '*.yml'))) if len(yaml_filenames) > 1: raise ValueError('More than one yaml file was found in the dataset root, cannot determine which one contains ' 'the dataset definition this way.') @@ -100,7 +100,7 @@ def __init__(self, opt, hyp): self.task.connect(opt, name='Args') # Make sure the code is easily remotely runnable by setting the docker image to use by the remote agent - self.task.set_base_docker("ultralytics/yolov5:latest", + self.task.set_base_docker('ultralytics/yolov5:latest', docker_arguments='--ipc=host -e="CLEARML_AGENT_SKIP_PYTHON_ENV_INSTALL=1"', docker_setup_bash_script='pip install clearml') @@ -150,7 +150,7 @@ def log_image_with_boxes(self, image_path, boxes, class_names, image, conf_thres class_name = class_names[int(class_nr)] confidence_percentage = round(float(conf) * 100, 2) - label = f"{class_name}: {confidence_percentage}%" + label = f'{class_name}: {confidence_percentage}%' if conf > conf_threshold: annotator.rectangle(box.cpu().numpy(), outline=color) diff --git a/utils/loggers/comet/__init__.py b/utils/loggers/comet/__init__.py index b0318f88d6..d4599841c9 100644 --- a/utils/loggers/comet/__init__.py +++ b/utils/loggers/comet/__init__.py @@ -17,7 +17,7 @@ # Project Configuration config = comet_ml.config.get_config() - COMET_PROJECT_NAME = config.get_string(os.getenv("COMET_PROJECT_NAME"), "comet.project_name", default="yolov5") + COMET_PROJECT_NAME = config.get_string(os.getenv('COMET_PROJECT_NAME'), 'comet.project_name', default='yolov5') except (ModuleNotFoundError, ImportError): comet_ml = None COMET_PROJECT_NAME = None @@ -31,32 +31,32 @@ from utils.general import check_dataset, scale_boxes, xywh2xyxy from utils.metrics import box_iou -COMET_PREFIX = "comet://" +COMET_PREFIX = 'comet://' -COMET_MODE = os.getenv("COMET_MODE", "online") +COMET_MODE = os.getenv('COMET_MODE', 'online') # Model Saving Settings -COMET_MODEL_NAME = os.getenv("COMET_MODEL_NAME", "yolov5") +COMET_MODEL_NAME = os.getenv('COMET_MODEL_NAME', 'yolov5') # Dataset Artifact Settings -COMET_UPLOAD_DATASET = os.getenv("COMET_UPLOAD_DATASET", "false").lower() == "true" +COMET_UPLOAD_DATASET = os.getenv('COMET_UPLOAD_DATASET', 'false').lower() == 'true' # Evaluation Settings -COMET_LOG_CONFUSION_MATRIX = os.getenv("COMET_LOG_CONFUSION_MATRIX", "true").lower() == "true" -COMET_LOG_PREDICTIONS = os.getenv("COMET_LOG_PREDICTIONS", "true").lower() == "true" -COMET_MAX_IMAGE_UPLOADS = int(os.getenv("COMET_MAX_IMAGE_UPLOADS", 100)) +COMET_LOG_CONFUSION_MATRIX = os.getenv('COMET_LOG_CONFUSION_MATRIX', 'true').lower() == 'true' +COMET_LOG_PREDICTIONS = os.getenv('COMET_LOG_PREDICTIONS', 'true').lower() == 'true' +COMET_MAX_IMAGE_UPLOADS = int(os.getenv('COMET_MAX_IMAGE_UPLOADS', 100)) # Confusion Matrix Settings -CONF_THRES = float(os.getenv("CONF_THRES", 0.001)) -IOU_THRES = float(os.getenv("IOU_THRES", 0.6)) +CONF_THRES = float(os.getenv('CONF_THRES', 0.001)) +IOU_THRES = float(os.getenv('IOU_THRES', 0.6)) # Batch Logging Settings -COMET_LOG_BATCH_METRICS = os.getenv("COMET_LOG_BATCH_METRICS", "false").lower() == "true" -COMET_BATCH_LOGGING_INTERVAL = os.getenv("COMET_BATCH_LOGGING_INTERVAL", 1) -COMET_PREDICTION_LOGGING_INTERVAL = os.getenv("COMET_PREDICTION_LOGGING_INTERVAL", 1) -COMET_LOG_PER_CLASS_METRICS = os.getenv("COMET_LOG_PER_CLASS_METRICS", "false").lower() == "true" +COMET_LOG_BATCH_METRICS = os.getenv('COMET_LOG_BATCH_METRICS', 'false').lower() == 'true' +COMET_BATCH_LOGGING_INTERVAL = os.getenv('COMET_BATCH_LOGGING_INTERVAL', 1) +COMET_PREDICTION_LOGGING_INTERVAL = os.getenv('COMET_PREDICTION_LOGGING_INTERVAL', 1) +COMET_LOG_PER_CLASS_METRICS = os.getenv('COMET_LOG_PER_CLASS_METRICS', 'false').lower() == 'true' -RANK = int(os.getenv("RANK", -1)) +RANK = int(os.getenv('RANK', -1)) to_pil = T.ToPILImage() @@ -66,7 +66,7 @@ class CometLogger: with Comet """ - def __init__(self, opt, hyp, run_id=None, job_type="Training", **experiment_kwargs) -> None: + def __init__(self, opt, hyp, run_id=None, job_type='Training', **experiment_kwargs) -> None: self.job_type = job_type self.opt = opt self.hyp = hyp @@ -87,52 +87,52 @@ def __init__(self, opt, hyp, run_id=None, job_type="Training", **experiment_kwar # Default parameters to pass to Experiment objects self.default_experiment_kwargs = { - "log_code": False, - "log_env_gpu": True, - "log_env_cpu": True, - "project_name": COMET_PROJECT_NAME,} + 'log_code': False, + 'log_env_gpu': True, + 'log_env_cpu': True, + 'project_name': COMET_PROJECT_NAME,} self.default_experiment_kwargs.update(experiment_kwargs) self.experiment = self._get_experiment(self.comet_mode, run_id) self.data_dict = self.check_dataset(self.opt.data) - self.class_names = self.data_dict["names"] - self.num_classes = self.data_dict["nc"] + self.class_names = self.data_dict['names'] + self.num_classes = self.data_dict['nc'] self.logged_images_count = 0 self.max_images = COMET_MAX_IMAGE_UPLOADS if run_id is None: - self.experiment.log_other("Created from", "YOLOv5") + self.experiment.log_other('Created from', 'YOLOv5') if not isinstance(self.experiment, comet_ml.OfflineExperiment): - workspace, project_name, experiment_id = self.experiment.url.split("/")[-3:] + workspace, project_name, experiment_id = self.experiment.url.split('/')[-3:] self.experiment.log_other( - "Run Path", - f"{workspace}/{project_name}/{experiment_id}", + 'Run Path', + f'{workspace}/{project_name}/{experiment_id}', ) self.log_parameters(vars(opt)) self.log_parameters(self.opt.hyp) self.log_asset_data( self.opt.hyp, - name="hyperparameters.json", - metadata={"type": "hyp-config-file"}, + name='hyperparameters.json', + metadata={'type': 'hyp-config-file'}, ) self.log_asset( - f"{self.opt.save_dir}/opt.yaml", - metadata={"type": "opt-config-file"}, + f'{self.opt.save_dir}/opt.yaml', + metadata={'type': 'opt-config-file'}, ) self.comet_log_confusion_matrix = COMET_LOG_CONFUSION_MATRIX - if hasattr(self.opt, "conf_thres"): + if hasattr(self.opt, 'conf_thres'): self.conf_thres = self.opt.conf_thres else: self.conf_thres = CONF_THRES - if hasattr(self.opt, "iou_thres"): + if hasattr(self.opt, 'iou_thres'): self.iou_thres = self.opt.iou_thres else: self.iou_thres = IOU_THRES - self.log_parameters({"val_iou_threshold": self.iou_thres, "val_conf_threshold": self.conf_thres}) + self.log_parameters({'val_iou_threshold': self.iou_thres, 'val_conf_threshold': self.conf_thres}) self.comet_log_predictions = COMET_LOG_PREDICTIONS if self.opt.bbox_interval == -1: @@ -147,22 +147,22 @@ def __init__(self, opt, hyp, run_id=None, job_type="Training", **experiment_kwar self.comet_log_per_class_metrics = COMET_LOG_PER_CLASS_METRICS self.experiment.log_others({ - "comet_mode": COMET_MODE, - "comet_max_image_uploads": COMET_MAX_IMAGE_UPLOADS, - "comet_log_per_class_metrics": COMET_LOG_PER_CLASS_METRICS, - "comet_log_batch_metrics": COMET_LOG_BATCH_METRICS, - "comet_log_confusion_matrix": COMET_LOG_CONFUSION_MATRIX, - "comet_model_name": COMET_MODEL_NAME,}) + 'comet_mode': COMET_MODE, + 'comet_max_image_uploads': COMET_MAX_IMAGE_UPLOADS, + 'comet_log_per_class_metrics': COMET_LOG_PER_CLASS_METRICS, + 'comet_log_batch_metrics': COMET_LOG_BATCH_METRICS, + 'comet_log_confusion_matrix': COMET_LOG_CONFUSION_MATRIX, + 'comet_model_name': COMET_MODEL_NAME,}) # Check if running the Experiment with the Comet Optimizer - if hasattr(self.opt, "comet_optimizer_id"): - self.experiment.log_other("optimizer_id", self.opt.comet_optimizer_id) - self.experiment.log_other("optimizer_objective", self.opt.comet_optimizer_objective) - self.experiment.log_other("optimizer_metric", self.opt.comet_optimizer_metric) - self.experiment.log_other("optimizer_parameters", json.dumps(self.hyp)) + if hasattr(self.opt, 'comet_optimizer_id'): + self.experiment.log_other('optimizer_id', self.opt.comet_optimizer_id) + self.experiment.log_other('optimizer_objective', self.opt.comet_optimizer_objective) + self.experiment.log_other('optimizer_metric', self.opt.comet_optimizer_metric) + self.experiment.log_other('optimizer_parameters', json.dumps(self.hyp)) def _get_experiment(self, mode, experiment_id=None): - if mode == "offline": + if mode == 'offline': if experiment_id is not None: return comet_ml.ExistingOfflineExperiment( previous_experiment=experiment_id, @@ -182,11 +182,11 @@ def _get_experiment(self, mode, experiment_id=None): return comet_ml.Experiment(**self.default_experiment_kwargs) except ValueError: - logger.warning("COMET WARNING: " - "Comet credentials have not been set. " - "Comet will default to offline logging. " - "Please set your credentials to enable online logging.") - return self._get_experiment("offline", experiment_id) + logger.warning('COMET WARNING: ' + 'Comet credentials have not been set. ' + 'Comet will default to offline logging. ' + 'Please set your credentials to enable online logging.') + return self._get_experiment('offline', experiment_id) return @@ -210,12 +210,12 @@ def log_model(self, path, opt, epoch, fitness_score, best_model=False): return model_metadata = { - "fitness_score": fitness_score[-1], - "epochs_trained": epoch + 1, - "save_period": opt.save_period, - "total_epochs": opt.epochs,} + 'fitness_score': fitness_score[-1], + 'epochs_trained': epoch + 1, + 'save_period': opt.save_period, + 'total_epochs': opt.epochs,} - model_files = glob.glob(f"{path}/*.pt") + model_files = glob.glob(f'{path}/*.pt') for model_path in model_files: name = Path(model_path).name @@ -232,12 +232,12 @@ def check_dataset(self, data_file): data_config = yaml.safe_load(f) if data_config['path'].startswith(COMET_PREFIX): - path = data_config['path'].replace(COMET_PREFIX, "") + path = data_config['path'].replace(COMET_PREFIX, '') data_dict = self.download_dataset_artifact(path) return data_dict - self.log_asset(self.opt.data, metadata={"type": "data-config-file"}) + self.log_asset(self.opt.data, metadata={'type': 'data-config-file'}) return check_dataset(data_file) @@ -253,8 +253,8 @@ def log_predictions(self, image, labelsn, path, shape, predn): filtered_detections = detections[mask] filtered_labels = labelsn[mask] - image_id = path.split("/")[-1].split(".")[0] - image_name = f"{image_id}_curr_epoch_{self.experiment.curr_epoch}" + image_id = path.split('/')[-1].split('.')[0] + image_name = f'{image_id}_curr_epoch_{self.experiment.curr_epoch}' if image_name not in self.logged_image_names: native_scale_image = PIL.Image.open(path) self.log_image(native_scale_image, name=image_name) @@ -263,22 +263,22 @@ def log_predictions(self, image, labelsn, path, shape, predn): metadata = [] for cls, *xyxy in filtered_labels.tolist(): metadata.append({ - "label": f"{self.class_names[int(cls)]}-gt", - "score": 100, - "box": { - "x": xyxy[0], - "y": xyxy[1], - "x2": xyxy[2], - "y2": xyxy[3]},}) + 'label': f'{self.class_names[int(cls)]}-gt', + 'score': 100, + 'box': { + 'x': xyxy[0], + 'y': xyxy[1], + 'x2': xyxy[2], + 'y2': xyxy[3]},}) for *xyxy, conf, cls in filtered_detections.tolist(): metadata.append({ - "label": f"{self.class_names[int(cls)]}", - "score": conf * 100, - "box": { - "x": xyxy[0], - "y": xyxy[1], - "x2": xyxy[2], - "y2": xyxy[3]},}) + 'label': f'{self.class_names[int(cls)]}', + 'score': conf * 100, + 'box': { + 'x': xyxy[0], + 'y': xyxy[1], + 'x2': xyxy[2], + 'y2': xyxy[3]},}) self.metadata_dict[image_name] = metadata self.logged_images_count += 1 @@ -305,35 +305,35 @@ def preprocess_prediction(self, image, labels, shape, pred): return predn, labelsn def add_assets_to_artifact(self, artifact, path, asset_path, split): - img_paths = sorted(glob.glob(f"{asset_path}/*")) + img_paths = sorted(glob.glob(f'{asset_path}/*')) label_paths = img2label_paths(img_paths) for image_file, label_file in zip(img_paths, label_paths): image_logical_path, label_logical_path = map(lambda x: os.path.relpath(x, path), [image_file, label_file]) try: - artifact.add(image_file, logical_path=image_logical_path, metadata={"split": split}) - artifact.add(label_file, logical_path=label_logical_path, metadata={"split": split}) + artifact.add(image_file, logical_path=image_logical_path, metadata={'split': split}) + artifact.add(label_file, logical_path=label_logical_path, metadata={'split': split}) except ValueError as e: logger.error('COMET ERROR: Error adding file to Artifact. Skipping file.') - logger.error(f"COMET ERROR: {e}") + logger.error(f'COMET ERROR: {e}') continue return artifact def upload_dataset_artifact(self): - dataset_name = self.data_dict.get("dataset_name", "yolov5-dataset") - path = str((ROOT / Path(self.data_dict["path"])).resolve()) + dataset_name = self.data_dict.get('dataset_name', 'yolov5-dataset') + path = str((ROOT / Path(self.data_dict['path'])).resolve()) metadata = self.data_dict.copy() - for key in ["train", "val", "test"]: + for key in ['train', 'val', 'test']: split_path = metadata.get(key) if split_path is not None: - metadata[key] = split_path.replace(path, "") + metadata[key] = split_path.replace(path, '') - artifact = comet_ml.Artifact(name=dataset_name, artifact_type="dataset", metadata=metadata) + artifact = comet_ml.Artifact(name=dataset_name, artifact_type='dataset', metadata=metadata) for key in metadata.keys(): - if key in ["train", "val", "test"]: + if key in ['train', 'val', 'test']: if isinstance(self.upload_dataset, str) and (key != self.upload_dataset): continue @@ -352,13 +352,13 @@ def download_dataset_artifact(self, artifact_path): metadata = logged_artifact.metadata data_dict = metadata.copy() - data_dict["path"] = artifact_save_dir + data_dict['path'] = artifact_save_dir - metadata_names = metadata.get("names") + metadata_names = metadata.get('names') if type(metadata_names) == dict: - data_dict["names"] = {int(k): v for k, v in metadata.get("names").items()} + data_dict['names'] = {int(k): v for k, v in metadata.get('names').items()} elif type(metadata_names) == list: - data_dict["names"] = {int(k): v for k, v in zip(range(len(metadata_names)), metadata_names)} + data_dict['names'] = {int(k): v for k, v in zip(range(len(metadata_names)), metadata_names)} else: raise "Invalid 'names' field in dataset yaml file. Please use a list or dictionary" @@ -366,13 +366,13 @@ def download_dataset_artifact(self, artifact_path): return data_dict def update_data_paths(self, data_dict): - path = data_dict.get("path", "") + path = data_dict.get('path', '') - for split in ["train", "val", "test"]: + for split in ['train', 'val', 'test']: if data_dict.get(split): split_path = data_dict.get(split) - data_dict[split] = (f"{path}/{split_path}" if isinstance(split, str) else [ - f"{path}/{x}" for x in split_path]) + data_dict[split] = (f'{path}/{split_path}' if isinstance(split, str) else [ + f'{path}/{x}' for x in split_path]) return data_dict @@ -413,11 +413,11 @@ def on_train_batch_end(self, log_dict, step): def on_train_end(self, files, save_dir, last, best, epoch, results): if self.comet_log_predictions: curr_epoch = self.experiment.curr_epoch - self.experiment.log_asset_data(self.metadata_dict, "image-metadata.json", epoch=curr_epoch) + self.experiment.log_asset_data(self.metadata_dict, 'image-metadata.json', epoch=curr_epoch) for f in files: - self.log_asset(f, metadata={"epoch": epoch}) - self.log_asset(f"{save_dir}/results.csv", metadata={"epoch": epoch}) + self.log_asset(f, metadata={'epoch': epoch}) + self.log_asset(f'{save_dir}/results.csv', metadata={'epoch': epoch}) if not self.opt.evolve: model_path = str(best if best.exists() else last) @@ -481,7 +481,7 @@ def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) if self.comet_log_confusion_matrix: epoch = self.experiment.curr_epoch class_names = list(self.class_names.values()) - class_names.append("background") + class_names.append('background') num_classes = len(class_names) self.experiment.log_confusion_matrix( @@ -491,7 +491,7 @@ def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) epoch=epoch, column_label='Actual Category', row_label='Predicted Category', - file_name=f"confusion-matrix-epoch-{epoch}.json", + file_name=f'confusion-matrix-epoch-{epoch}.json', ) def on_fit_epoch_end(self, result, epoch): diff --git a/utils/loggers/comet/comet_utils.py b/utils/loggers/comet/comet_utils.py index 3cbd45156b..27600761ad 100644 --- a/utils/loggers/comet/comet_utils.py +++ b/utils/loggers/comet/comet_utils.py @@ -11,28 +11,28 @@ logger = logging.getLogger(__name__) -COMET_PREFIX = "comet://" -COMET_MODEL_NAME = os.getenv("COMET_MODEL_NAME", "yolov5") -COMET_DEFAULT_CHECKPOINT_FILENAME = os.getenv("COMET_DEFAULT_CHECKPOINT_FILENAME", "last.pt") +COMET_PREFIX = 'comet://' +COMET_MODEL_NAME = os.getenv('COMET_MODEL_NAME', 'yolov5') +COMET_DEFAULT_CHECKPOINT_FILENAME = os.getenv('COMET_DEFAULT_CHECKPOINT_FILENAME', 'last.pt') def download_model_checkpoint(opt, experiment): - model_dir = f"{opt.project}/{experiment.name}" + model_dir = f'{opt.project}/{experiment.name}' os.makedirs(model_dir, exist_ok=True) model_name = COMET_MODEL_NAME model_asset_list = experiment.get_model_asset_list(model_name) if len(model_asset_list) == 0: - logger.error(f"COMET ERROR: No checkpoints found for model name : {model_name}") + logger.error(f'COMET ERROR: No checkpoints found for model name : {model_name}') return model_asset_list = sorted( model_asset_list, - key=lambda x: x["step"], + key=lambda x: x['step'], reverse=True, ) - logged_checkpoint_map = {asset["fileName"]: asset["assetId"] for asset in model_asset_list} + logged_checkpoint_map = {asset['fileName']: asset['assetId'] for asset in model_asset_list} resource_url = urlparse(opt.weights) checkpoint_filename = resource_url.query @@ -44,22 +44,22 @@ def download_model_checkpoint(opt, experiment): checkpoint_filename = COMET_DEFAULT_CHECKPOINT_FILENAME if asset_id is None: - logger.error(f"COMET ERROR: Checkpoint {checkpoint_filename} not found in the given Experiment") + logger.error(f'COMET ERROR: Checkpoint {checkpoint_filename} not found in the given Experiment') return try: - logger.info(f"COMET INFO: Downloading checkpoint {checkpoint_filename}") + logger.info(f'COMET INFO: Downloading checkpoint {checkpoint_filename}') asset_filename = checkpoint_filename - model_binary = experiment.get_asset(asset_id, return_type="binary", stream=False) - model_download_path = f"{model_dir}/{asset_filename}" - with open(model_download_path, "wb") as f: + model_binary = experiment.get_asset(asset_id, return_type='binary', stream=False) + model_download_path = f'{model_dir}/{asset_filename}' + with open(model_download_path, 'wb') as f: f.write(model_binary) opt.weights = model_download_path except Exception as e: - logger.warning("COMET WARNING: Unable to download checkpoint from Comet") + logger.warning('COMET WARNING: Unable to download checkpoint from Comet') logger.exception(e) @@ -75,9 +75,9 @@ def set_opt_parameters(opt, experiment): resume_string = opt.resume for asset in asset_list: - if asset["fileName"] == "opt.yaml": - asset_id = asset["assetId"] - asset_binary = experiment.get_asset(asset_id, return_type="binary", stream=False) + if asset['fileName'] == 'opt.yaml': + asset_id = asset['assetId'] + asset_binary = experiment.get_asset(asset_id, return_type='binary', stream=False) opt_dict = yaml.safe_load(asset_binary) for key, value in opt_dict.items(): setattr(opt, key, value) @@ -85,11 +85,11 @@ def set_opt_parameters(opt, experiment): # Save hyperparameters to YAML file # Necessary to pass checks in training script - save_dir = f"{opt.project}/{experiment.name}" + save_dir = f'{opt.project}/{experiment.name}' os.makedirs(save_dir, exist_ok=True) - hyp_yaml_path = f"{save_dir}/hyp.yaml" - with open(hyp_yaml_path, "w") as f: + hyp_yaml_path = f'{save_dir}/hyp.yaml' + with open(hyp_yaml_path, 'w') as f: yaml.dump(opt.hyp, f) opt.hyp = hyp_yaml_path @@ -113,7 +113,7 @@ def check_comet_weights(opt): if opt.weights.startswith(COMET_PREFIX): api = comet_ml.API() resource = urlparse(opt.weights) - experiment_path = f"{resource.netloc}{resource.path}" + experiment_path = f'{resource.netloc}{resource.path}' experiment = api.get(experiment_path) download_model_checkpoint(opt, experiment) return True @@ -140,7 +140,7 @@ def check_comet_resume(opt): if opt.resume.startswith(COMET_PREFIX): api = comet_ml.API() resource = urlparse(opt.resume) - experiment_path = f"{resource.netloc}{resource.path}" + experiment_path = f'{resource.netloc}{resource.path}' experiment = api.get(experiment_path) set_opt_parameters(opt, experiment) download_model_checkpoint(opt, experiment) diff --git a/utils/loggers/comet/hpo.py b/utils/loggers/comet/hpo.py index 7dd5c92e8d..fc49115c13 100644 --- a/utils/loggers/comet/hpo.py +++ b/utils/loggers/comet/hpo.py @@ -21,7 +21,7 @@ # Project Configuration config = comet_ml.config.get_config() -COMET_PROJECT_NAME = config.get_string(os.getenv("COMET_PROJECT_NAME"), "comet.project_name", default="yolov5") +COMET_PROJECT_NAME = config.get_string(os.getenv('COMET_PROJECT_NAME'), 'comet.project_name', default='yolov5') def get_args(known=False): @@ -68,30 +68,30 @@ def get_args(known=False): parser.add_argument('--artifact_alias', type=str, default='latest', help='W&B: Version of dataset artifact to use') # Comet Arguments - parser.add_argument("--comet_optimizer_config", type=str, help="Comet: Path to a Comet Optimizer Config File.") - parser.add_argument("--comet_optimizer_id", type=str, help="Comet: ID of the Comet Optimizer sweep.") - parser.add_argument("--comet_optimizer_objective", type=str, help="Comet: Set to 'minimize' or 'maximize'.") - parser.add_argument("--comet_optimizer_metric", type=str, help="Comet: Metric to Optimize.") - parser.add_argument("--comet_optimizer_workers", + parser.add_argument('--comet_optimizer_config', type=str, help='Comet: Path to a Comet Optimizer Config File.') + parser.add_argument('--comet_optimizer_id', type=str, help='Comet: ID of the Comet Optimizer sweep.') + parser.add_argument('--comet_optimizer_objective', type=str, help="Comet: Set to 'minimize' or 'maximize'.") + parser.add_argument('--comet_optimizer_metric', type=str, help='Comet: Metric to Optimize.') + parser.add_argument('--comet_optimizer_workers', type=int, default=1, - help="Comet: Number of Parallel Workers to use with the Comet Optimizer.") + help='Comet: Number of Parallel Workers to use with the Comet Optimizer.') return parser.parse_known_args()[0] if known else parser.parse_args() def run(parameters, opt): - hyp_dict = {k: v for k, v in parameters.items() if k not in ["epochs", "batch_size"]} + hyp_dict = {k: v for k, v in parameters.items() if k not in ['epochs', 'batch_size']} opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok or opt.evolve)) - opt.batch_size = parameters.get("batch_size") - opt.epochs = parameters.get("epochs") + opt.batch_size = parameters.get('batch_size') + opt.epochs = parameters.get('epochs') device = select_device(opt.device, batch_size=opt.batch_size) train(hyp_dict, opt, device, callbacks=Callbacks()) -if __name__ == "__main__": +if __name__ == '__main__': opt = get_args(known=True) opt.weights = str(opt.weights) @@ -99,7 +99,7 @@ def run(parameters, opt): opt.data = str(opt.data) opt.project = str(opt.project) - optimizer_id = os.getenv("COMET_OPTIMIZER_ID") + optimizer_id = os.getenv('COMET_OPTIMIZER_ID') if optimizer_id is None: with open(opt.comet_optimizer_config) as f: optimizer_config = json.load(f) @@ -110,9 +110,9 @@ def run(parameters, opt): opt.comet_optimizer_id = optimizer.id status = optimizer.status() - opt.comet_optimizer_objective = status["spec"]["objective"] - opt.comet_optimizer_metric = status["spec"]["metric"] + opt.comet_optimizer_objective = status['spec']['objective'] + opt.comet_optimizer_metric = status['spec']['metric'] - logger.info("COMET INFO: Starting Hyperparameter Sweep") + logger.info('COMET INFO: Starting Hyperparameter Sweep') for parameter in optimizer.get_parameters(): - run(parameter["parameters"], opt) + run(parameter['parameters'], opt) diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py index 97ba31b68f..adb7840e4a 100644 --- a/utils/loggers/wandb/wandb_utils.py +++ b/utils/loggers/wandb/wandb_utils.py @@ -17,7 +17,7 @@ sys.path.append(str(ROOT)) # add ROOT to PATH RANK = int(os.getenv('RANK', -1)) DEPRECATION_WARNING = f"{colorstr('wandb')}: WARNING ⚠️ wandb is deprecated and will be removed in a future release. " \ - f"See supported integrations at https://github.com/ultralytics/yolov5#integrations." + f'See supported integrations at https://github.com/ultralytics/yolov5#integrations.' try: import wandb @@ -65,7 +65,7 @@ def __init__(self, opt, run_id=None, job_type='Training'): self.data_dict = None if self.wandb: self.wandb_run = wandb.init(config=opt, - resume="allow", + resume='allow', project='YOLOv5' if opt.project == 'runs/train' else Path(opt.project).stem, entity=opt.entity, name=opt.name if opt.name != 'exp' else None, @@ -97,7 +97,7 @@ def setup_training(self, opt): if isinstance(opt.resume, str): model_dir, _ = self.download_model_artifact(opt) if model_dir: - self.weights = Path(model_dir) / "last.pt" + self.weights = Path(model_dir) / 'last.pt' config = self.wandb_run.config opt.weights, opt.save_period, opt.batch_size, opt.bbox_interval, opt.epochs, opt.hyp, opt.imgsz = str( self.weights), config.save_period, config.batch_size, config.bbox_interval, config.epochs, \ @@ -131,7 +131,7 @@ def log_model(self, path, opt, epoch, fitness_score, best_model=False): model_artifact.add_file(str(path / 'last.pt'), name='last.pt') wandb.log_artifact(model_artifact, aliases=['latest', 'last', 'epoch ' + str(self.current_epoch), 'best' if best_model else '']) - LOGGER.info(f"Saving model artifact on epoch {epoch + 1}") + LOGGER.info(f'Saving model artifact on epoch {epoch + 1}') def val_one_image(self, pred, predn, path, names, im): pass @@ -160,7 +160,7 @@ def end_epoch(self): wandb.log(self.log_dict) except BaseException as e: LOGGER.info( - f"An error occurred in wandb logger. The training will proceed without interruption. More info\n{e}" + f'An error occurred in wandb logger. The training will proceed without interruption. More info\n{e}' ) self.wandb_run.finish() self.wandb_run = None diff --git a/utils/metrics.py b/utils/metrics.py index 408b613a21..5dab6130a0 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -28,7 +28,7 @@ def smooth(y, f=0.05): return np.convolve(yp, np.ones(nf) / nf, mode='valid') # y-smoothed -def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names=(), eps=1e-16, prefix=""): +def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names=(), eps=1e-16, prefix=''): """ Compute the average precision, given the recall and precision curves. Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. # Arguments @@ -194,14 +194,14 @@ def plot(self, normalize=True, save_dir='', names=()): nc, nn = self.nc, len(names) # number of classes, names sn.set(font_scale=1.0 if nc < 50 else 0.8) # for label size labels = (0 < nn < 99) and (nn == nc) # apply names to ticklabels - ticklabels = (names + ['background']) if labels else "auto" + ticklabels = (names + ['background']) if labels else 'auto' with warnings.catch_warnings(): warnings.simplefilter('ignore') # suppress empty matrix RuntimeWarning: All-NaN slice encountered sn.heatmap(array, ax=ax, annot=nc < 30, annot_kws={ - "size": 8}, + 'size': 8}, cmap='Blues', fmt='.2f', square=True, @@ -331,7 +331,7 @@ def plot_pr_curve(px, py, ap, save_dir=Path('pr_curve.png'), names=()): ax.set_ylabel('Precision') ax.set_xlim(0, 1) ax.set_ylim(0, 1) - ax.legend(bbox_to_anchor=(1.04, 1), loc="upper left") + ax.legend(bbox_to_anchor=(1.04, 1), loc='upper left') ax.set_title('Precision-Recall Curve') fig.savefig(save_dir, dpi=250) plt.close(fig) @@ -354,7 +354,7 @@ def plot_mc_curve(px, py, save_dir=Path('mc_curve.png'), names=(), xlabel='Confi ax.set_ylabel(ylabel) ax.set_xlim(0, 1) ax.set_ylim(0, 1) - ax.legend(bbox_to_anchor=(1.04, 1), loc="upper left") + ax.legend(bbox_to_anchor=(1.04, 1), loc='upper left') ax.set_title(f'{ylabel}-Confidence Curve') fig.savefig(save_dir, dpi=250) plt.close(fig) diff --git a/utils/plots.py b/utils/plots.py index 440e837f3e..64655a3f0e 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -450,7 +450,7 @@ def imshow_cls(im, labels=None, pred=None, names=None, nmax=25, verbose=False, f plt.savefig(f, dpi=300, bbox_inches='tight') plt.close() if verbose: - LOGGER.info(f"Saving {f}") + LOGGER.info(f'Saving {f}') if labels is not None: LOGGER.info('True: ' + ' '.join(f'{names[i]:3s}' for i in labels[:nmax])) if pred is not None: diff --git a/utils/segment/dataloaders.py b/utils/segment/dataloaders.py index 2c5cdc2d20..d0f59562ed 100644 --- a/utils/segment/dataloaders.py +++ b/utils/segment/dataloaders.py @@ -95,7 +95,7 @@ def __init__( stride=32, pad=0, min_items=0, - prefix="", + prefix='', downsample_ratio=1, overlap=False, ): @@ -116,7 +116,7 @@ def __getitem__(self, index): shapes = None # MixUp augmentation - if random.random() < hyp["mixup"]: + if random.random() < hyp['mixup']: img, labels, segments = mixup(img, labels, segments, *self.load_mosaic(random.randint(0, self.n - 1))) else: @@ -147,11 +147,11 @@ def __getitem__(self, index): img, labels, segments = random_perspective(img, labels, segments=segments, - degrees=hyp["degrees"], - translate=hyp["translate"], - scale=hyp["scale"], - shear=hyp["shear"], - perspective=hyp["perspective"]) + degrees=hyp['degrees'], + translate=hyp['translate'], + scale=hyp['scale'], + shear=hyp['shear'], + perspective=hyp['perspective']) nl = len(labels) # number of labels if nl: @@ -177,17 +177,17 @@ def __getitem__(self, index): nl = len(labels) # update after albumentations # HSV color-space - augment_hsv(img, hgain=hyp["hsv_h"], sgain=hyp["hsv_s"], vgain=hyp["hsv_v"]) + augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) # Flip up-down - if random.random() < hyp["flipud"]: + if random.random() < hyp['flipud']: img = np.flipud(img) if nl: labels[:, 2] = 1 - labels[:, 2] masks = torch.flip(masks, dims=[1]) # Flip left-right - if random.random() < hyp["fliplr"]: + if random.random() < hyp['fliplr']: img = np.fliplr(img) if nl: labels[:, 1] = 1 - labels[:, 1] @@ -251,15 +251,15 @@ def load_mosaic(self, index): # img4, labels4 = replicate(img4, labels4) # replicate # Augment - img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp["copy_paste"]) + img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp['copy_paste']) img4, labels4, segments4 = random_perspective(img4, labels4, segments4, - degrees=self.hyp["degrees"], - translate=self.hyp["translate"], - scale=self.hyp["scale"], - shear=self.hyp["shear"], - perspective=self.hyp["perspective"], + degrees=self.hyp['degrees'], + translate=self.hyp['translate'], + scale=self.hyp['scale'], + shear=self.hyp['shear'], + perspective=self.hyp['perspective'], border=self.mosaic_border) # border to remove return img4, labels4, segments4 diff --git a/utils/segment/loss.py b/utils/segment/loss.py index b45b2c27e0..2a8a4c680f 100644 --- a/utils/segment/loss.py +++ b/utils/segment/loss.py @@ -83,7 +83,7 @@ def __call__(self, preds, targets, masks): # predictions, targets, model # Mask regression if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample - masks = F.interpolate(masks[None], (mask_h, mask_w), mode="nearest")[0] + masks = F.interpolate(masks[None], (mask_h, mask_w), mode='nearest')[0] marea = xywhn[i][:, 2:].prod(1) # mask width, height normalized mxyxy = xywh2xyxy(xywhn[i] * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device)) for bi in b.unique(): @@ -101,10 +101,10 @@ def __call__(self, preds, targets, masks): # predictions, targets, model if self.autobalance: self.balance = [x / self.balance[self.ssi] for x in self.balance] - lbox *= self.hyp["box"] - lobj *= self.hyp["obj"] - lcls *= self.hyp["cls"] - lseg *= self.hyp["box"] / bs + lbox *= self.hyp['box'] + lobj *= self.hyp['obj'] + lcls *= self.hyp['cls'] + lseg *= self.hyp['box'] / bs loss = lbox + lobj + lcls + lseg return loss * bs, torch.cat((lbox, lseg, lobj, lcls)).detach() @@ -112,7 +112,7 @@ def __call__(self, preds, targets, masks): # predictions, targets, model def single_mask_loss(self, gt_mask, pred, proto, xyxy, area): # Mask loss for one image pred_mask = (pred @ proto.view(self.nm, -1)).view(-1, *proto.shape[1:]) # (n,32) @ (32,80,80) -> (n,80,80) - loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction="none") + loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction='none') return (crop_mask(loss, xyxy).mean(dim=(1, 2)) / area).mean() def build_targets(self, p, targets): diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py index 312e585893..6c58dba610 100644 --- a/utils/segment/metrics.py +++ b/utils/segment/metrics.py @@ -21,7 +21,7 @@ def ap_per_class_box_and_mask( pred_cls, target_cls, plot=False, - save_dir=".", + save_dir='.', names=(), ): """ @@ -37,7 +37,7 @@ def ap_per_class_box_and_mask( plot=plot, save_dir=save_dir, names=names, - prefix="Box")[2:] + prefix='Box')[2:] results_masks = ap_per_class(tp_m, conf, pred_cls, @@ -45,21 +45,21 @@ def ap_per_class_box_and_mask( plot=plot, save_dir=save_dir, names=names, - prefix="Mask")[2:] + prefix='Mask')[2:] results = { - "boxes": { - "p": results_boxes[0], - "r": results_boxes[1], - "ap": results_boxes[3], - "f1": results_boxes[2], - "ap_class": results_boxes[4]}, - "masks": { - "p": results_masks[0], - "r": results_masks[1], - "ap": results_masks[3], - "f1": results_masks[2], - "ap_class": results_masks[4]}} + 'boxes': { + 'p': results_boxes[0], + 'r': results_boxes[1], + 'ap': results_boxes[3], + 'f1': results_boxes[2], + 'ap_class': results_boxes[4]}, + 'masks': { + 'p': results_masks[0], + 'r': results_masks[1], + 'ap': results_masks[3], + 'f1': results_masks[2], + 'ap_class': results_masks[4]}} return results @@ -159,8 +159,8 @@ def update(self, results): Args: results: Dict{'boxes': Dict{}, 'masks': Dict{}} """ - self.metric_box.update(list(results["boxes"].values())) - self.metric_mask.update(list(results["masks"].values())) + self.metric_box.update(list(results['boxes'].values())) + self.metric_mask.update(list(results['masks'].values())) def mean_results(self): return self.metric_box.mean_results() + self.metric_mask.mean_results() @@ -178,33 +178,33 @@ def ap_class_index(self): KEYS = [ - "train/box_loss", - "train/seg_loss", # train loss - "train/obj_loss", - "train/cls_loss", - "metrics/precision(B)", - "metrics/recall(B)", - "metrics/mAP_0.5(B)", - "metrics/mAP_0.5:0.95(B)", # metrics - "metrics/precision(M)", - "metrics/recall(M)", - "metrics/mAP_0.5(M)", - "metrics/mAP_0.5:0.95(M)", # metrics - "val/box_loss", - "val/seg_loss", # val loss - "val/obj_loss", - "val/cls_loss", - "x/lr0", - "x/lr1", - "x/lr2",] + 'train/box_loss', + 'train/seg_loss', # train loss + 'train/obj_loss', + 'train/cls_loss', + 'metrics/precision(B)', + 'metrics/recall(B)', + 'metrics/mAP_0.5(B)', + 'metrics/mAP_0.5:0.95(B)', # metrics + 'metrics/precision(M)', + 'metrics/recall(M)', + 'metrics/mAP_0.5(M)', + 'metrics/mAP_0.5:0.95(M)', # metrics + 'val/box_loss', + 'val/seg_loss', # val loss + 'val/obj_loss', + 'val/cls_loss', + 'x/lr0', + 'x/lr1', + 'x/lr2',] BEST_KEYS = [ - "best/epoch", - "best/precision(B)", - "best/recall(B)", - "best/mAP_0.5(B)", - "best/mAP_0.5:0.95(B)", - "best/precision(M)", - "best/recall(M)", - "best/mAP_0.5(M)", - "best/mAP_0.5:0.95(M)",] + 'best/epoch', + 'best/precision(B)', + 'best/recall(B)', + 'best/mAP_0.5(B)', + 'best/mAP_0.5:0.95(B)', + 'best/precision(M)', + 'best/recall(M)', + 'best/mAP_0.5(M)', + 'best/mAP_0.5:0.95(M)',] diff --git a/utils/segment/plots.py b/utils/segment/plots.py index 9b90900b37..3ba097624f 100644 --- a/utils/segment/plots.py +++ b/utils/segment/plots.py @@ -108,13 +108,13 @@ def plot_images_and_masks(images, targets, masks, paths=None, fname='images.jpg' annotator.im.save(fname) # save -def plot_results_with_masks(file="path/to/results.csv", dir="", best=True): +def plot_results_with_masks(file='path/to/results.csv', dir='', best=True): # Plot training results.csv. Usage: from utils.plots import *; plot_results('path/to/results.csv') save_dir = Path(file).parent if file else Path(dir) fig, ax = plt.subplots(2, 8, figsize=(18, 6), tight_layout=True) ax = ax.ravel() - files = list(save_dir.glob("results*.csv")) - assert len(files), f"No results.csv files found in {save_dir.resolve()}, nothing to plot." + files = list(save_dir.glob('results*.csv')) + assert len(files), f'No results.csv files found in {save_dir.resolve()}, nothing to plot.' for f in files: try: data = pd.read_csv(f) @@ -125,19 +125,19 @@ def plot_results_with_masks(file="path/to/results.csv", dir="", best=True): for i, j in enumerate([1, 2, 3, 4, 5, 6, 9, 10, 13, 14, 15, 16, 7, 8, 11, 12]): y = data.values[:, j] # y[y == 0] = np.nan # don't show zero values - ax[i].plot(x, y, marker=".", label=f.stem, linewidth=2, markersize=2) + ax[i].plot(x, y, marker='.', label=f.stem, linewidth=2, markersize=2) if best: # best - ax[i].scatter(index, y[index], color="r", label=f"best:{index}", marker="*", linewidth=3) - ax[i].set_title(s[j] + f"\n{round(y[index], 5)}") + ax[i].scatter(index, y[index], color='r', label=f'best:{index}', marker='*', linewidth=3) + ax[i].set_title(s[j] + f'\n{round(y[index], 5)}') else: # last - ax[i].scatter(x[-1], y[-1], color="r", label="last", marker="*", linewidth=3) - ax[i].set_title(s[j] + f"\n{round(y[-1], 5)}") + ax[i].scatter(x[-1], y[-1], color='r', label='last', marker='*', linewidth=3) + ax[i].set_title(s[j] + f'\n{round(y[-1], 5)}') # if j in [8, 9, 10]: # share train and val loss y axes # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) except Exception as e: - print(f"Warning: Plotting error for {f}: {e}") + print(f'Warning: Plotting error for {f}: {e}') ax[1].legend() - fig.savefig(save_dir / "results.png", dpi=200) + fig.savefig(save_dir / 'results.png', dpi=200) plt.close() diff --git a/utils/torch_utils.py b/utils/torch_utils.py index f259be7acb..073d9bd01f 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -291,7 +291,7 @@ def model_info(model, verbose=False, imgsz=640): fs = '' name = Path(model.yaml_file).stem.replace('yolov5', 'YOLOv3') if hasattr(model, 'yaml_file') else 'Model' - LOGGER.info(f"{name} summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}") + LOGGER.info(f'{name} summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}') def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416) @@ -342,7 +342,7 @@ def smart_optimizer(model, name='Adam', lr=0.001, momentum=0.9, decay=1e-5): optimizer.add_param_group({'params': g[0], 'weight_decay': decay}) # add g0 with weight_decay optimizer.add_param_group({'params': g[1], 'weight_decay': 0.0}) # add g1 (BatchNorm2d weights) LOGGER.info(f"{colorstr('optimizer:')} {type(optimizer).__name__}(lr={lr}) with parameter groups " - f"{len(g[1])} weight(decay=0.0), {len(g[0])} weight(decay={decay}), {len(g[2])} bias") + f'{len(g[1])} weight(decay=0.0), {len(g[0])} weight(decay={decay}), {len(g[2])} bias') return optimizer diff --git a/utils/triton.py b/utils/triton.py index f067eeafaa..87f1fdcdee 100644 --- a/utils/triton.py +++ b/utils/triton.py @@ -21,7 +21,7 @@ def __init__(self, url: str): """ parsed_url = urlparse(url) - if parsed_url.scheme == "grpc": + if parsed_url.scheme == 'grpc': from tritonclient.grpc import InferenceServerClient, InferInput self.client = InferenceServerClient(parsed_url.netloc) # Triton GRPC client @@ -31,7 +31,7 @@ def __init__(self, url: str): def create_input_placeholders() -> typing.List[InferInput]: return [ - InferInput(i['name'], [int(s) for s in i["shape"]], i['datatype']) for i in self.metadata['inputs']] + InferInput(i['name'], [int(s) for s in i['shape']], i['datatype']) for i in self.metadata['inputs']] else: from tritonclient.http import InferenceServerClient, InferInput @@ -43,14 +43,14 @@ def create_input_placeholders() -> typing.List[InferInput]: def create_input_placeholders() -> typing.List[InferInput]: return [ - InferInput(i['name'], [int(s) for s in i["shape"]], i['datatype']) for i in self.metadata['inputs']] + InferInput(i['name'], [int(s) for s in i['shape']], i['datatype']) for i in self.metadata['inputs']] self._create_input_placeholders_fn = create_input_placeholders @property def runtime(self): """Returns the model runtime""" - return self.metadata.get("backend", self.metadata.get("platform")) + return self.metadata.get('backend', self.metadata.get('platform')) def __call__(self, *args, **kwargs) -> typing.Union[torch.Tensor, typing.Tuple[torch.Tensor, ...]]: """ Invokes the model. Parameters can be provided via args or kwargs. @@ -68,14 +68,14 @@ def __call__(self, *args, **kwargs) -> typing.Union[torch.Tensor, typing.Tuple[t def _create_inputs(self, *args, **kwargs): args_len, kwargs_len = len(args), len(kwargs) if not args_len and not kwargs_len: - raise RuntimeError("No inputs provided.") + raise RuntimeError('No inputs provided.') if args_len and kwargs_len: - raise RuntimeError("Cannot specify args and kwargs at the same time") + raise RuntimeError('Cannot specify args and kwargs at the same time') placeholders = self._create_input_placeholders_fn() if args_len: if args_len != len(placeholders): - raise RuntimeError(f"Expected {len(placeholders)} inputs, got {args_len}.") + raise RuntimeError(f'Expected {len(placeholders)} inputs, got {args_len}.') for input, value in zip(placeholders, args): input.set_data_from_numpy(value.cpu().numpy()) else: diff --git a/val.py b/val.py index f8868494ef..f44089fee2 100644 --- a/val.py +++ b/val.py @@ -304,7 +304,7 @@ def run( if save_json and len(jdict): w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights anno_json = str(Path('../datasets/coco/annotations/instances_val2017.json')) # annotations - pred_json = str(save_dir / f"{w}_predictions.json") # predictions + pred_json = str(save_dir / f'{w}_predictions.json') # predictions LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') with open(pred_json, 'w') as f: json.dump(jdict, f) @@ -404,6 +404,6 @@ def main(opt): raise NotImplementedError(f'--task {opt.task} not in ("train", "val", "test", "speed", "study")') -if __name__ == "__main__": +if __name__ == '__main__': opt = parse_opt() main(opt) From 76d848608107780ef92eae7fcbb151b91b6ee368 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 20 Feb 2023 13:52:59 +0100 Subject: [PATCH 0939/1185] Update README.md (#2021) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 209b8bebaa..a42804126f 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@
- YOLOv3 CI + YOLOv3 CI YOLOv3 Citation - Docker Pulls + Docker Pulls
Run on Gradient Open In Colab From ca9a9810fe1009e3aed86ed37951be643e1023f4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 24 Feb 2023 21:32:37 -0800 Subject: [PATCH 0940/1185] Update ci-testing.yml (#2024) * Update ci-testing.yml * Update ci-testing.yml * Update ci-testing.yml --- .github/workflows/ci-testing.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 6be6236de1..60fb348da2 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -40,10 +40,10 @@ jobs: - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - name: Get cache dir - # https://github.com/actions/cache/blob/master/examples.md#multiple-oss-in-a-workflow + - name: Get cache dir # https://github.com/actions/cache/blob/master/examples.md#multiple-oss-in-a-workflow id: pip-cache - run: echo "::set-output name=dir::$(pip cache dir)" + run: echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT + shell: bash # for Windows compatibility - name: Cache pip uses: actions/cache@v3 with: From d94c261af7a4ded87bf992dc1a5994a2f370bfaf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Mar 2023 02:08:47 +0100 Subject: [PATCH 0941/1185] Update ci-testing.yml (#2026) --- .github/workflows/ci-testing.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 60fb348da2..151a564ded 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -40,16 +40,7 @@ jobs: - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - name: Get cache dir # https://github.com/actions/cache/blob/master/examples.md#multiple-oss-in-a-workflow - id: pip-cache - run: echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT - shell: bash # for Windows compatibility - - name: Cache pip - uses: actions/cache@v3 - with: - path: ${{ steps.pip-cache.outputs.dir }} - key: ${{ runner.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('requirements.txt') }} - restore-keys: ${{ runner.os }}-${{ matrix.python-version }}-pip- + cache: 'pip' # caching pip dependencies - name: Install requirements run: | python -m pip install --upgrade pip wheel From a2a17973c56673519330c1cbfc405bcd1dd8c449 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 23 Mar 2023 20:38:35 +0100 Subject: [PATCH 0942/1185] Update social icons, add TikTok and remove Facebook (#2028) * Update README.md * Update README.zh-CN.md --- README.md | 46 ++++++++++++++++++++-------------------------- README.zh-CN.md | 47 +++++++++++++++++++++-------------------------- 2 files changed, 41 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index a42804126f..92dde94964 100644 --- a/README.md +++ b/README.md @@ -23,27 +23,24 @@ YOLOv3 🚀 is the world's most loved vision AI, representing Ultralytics Licensing.
- - - - - - - - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + + + + +

@@ -477,14 +474,11 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/ - - - - - + + diff --git a/README.zh-CN.md b/README.zh-CN.md index 6cbced4997..5338ecaa9b 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -21,28 +21,26 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表Ultralytics 许可. +
- - - - - - - - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + + + + + ##
YOLOv8 🚀 NEW
@@ -472,14 +470,11 @@ YOLOv3 在两种不同的 License 下可用: - - - - - + + From de10db2ee9688d83406411c7e211146c3294c773 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 26 Mar 2023 20:28:50 +0200 Subject: [PATCH 0943/1185] FROM pytorch/pytorch:2.0.0-cuda11.7-cudnn8-runtime (#2030) --- utils/docker/Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/utils/docker/Dockerfile b/utils/docker/Dockerfile index a83e664c71..6607abfb79 100644 --- a/utils/docker/Dockerfile +++ b/utils/docker/Dockerfile @@ -2,9 +2,8 @@ # Builds ultralytics/yolov5:latest image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 # Image is CUDA-optimized for YOLOv5 single/multi-GPU training and inference -# Start FROM NVIDIA PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch -# FROM docker.io/pytorch/pytorch:latest -FROM pytorch/pytorch:latest +# Start FROM PyTorch image https://hub.docker.com/r/pytorch/pytorch +FROM pytorch/pytorch:2.0.0-cuda11.7-cudnn8-runtime # Downloads to user config dir ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/ From 312ca9dccb746c7de3dcdc666112076339ea60c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 13:48:18 +0200 Subject: [PATCH 0944/1185] Bump actions/stale from 7 to 8 (#2031) Bumps [actions/stale](https://github.com/actions/stale) from 7 to 8. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v7...v8) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 5db90eebcf..a93a4d0eff 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -9,7 +9,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v7 + - uses: actions/stale@v8 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: | From 609b93bcfa0fd8a773976319c319cc9d306dff59 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 28 Mar 2023 02:33:14 +0200 Subject: [PATCH 0945/1185] Update README.md (#2032) * Update README.md * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update README.zh-CN.md * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update README.md --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- README.md | 33 ++++++++++++++++----------------- README.zh-CN.md | 32 ++++++++++++++++---------------- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 92dde94964..5996f43f8c 100644 --- a/README.md +++ b/README.md @@ -152,23 +152,22 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
Tutorials -- [Train Custom Data](https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data)  🚀 RECOMMENDED -- [Tips for Best Training Results](https://github.com/ultralytics/yolov5/wiki/Tips-for-Best-Training-Results)  ☘️ - RECOMMENDED -- [Multi-GPU Training](https://github.com/ultralytics/yolov5/issues/475) -- [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36) 🌟 NEW -- [TFLite, ONNX, CoreML, TensorRT Export](https://github.com/ultralytics/yolov5/issues/251) 🚀 -- [NVIDIA Jetson Nano Deployment](https://github.com/ultralytics/yolov5/issues/9627) 🌟 NEW -- [Test-Time Augmentation (TTA)](https://github.com/ultralytics/yolov5/issues/303) -- [Model Ensembling](https://github.com/ultralytics/yolov5/issues/318) -- [Model Pruning/Sparsity](https://github.com/ultralytics/yolov5/issues/304) -- [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607) -- [Transfer Learning with Frozen Layers](https://github.com/ultralytics/yolov5/issues/1314) -- [Architecture Summary](https://github.com/ultralytics/yolov5/issues/6998) 🌟 NEW -- [Roboflow for Datasets, Labeling, and Active Learning](https://github.com/ultralytics/yolov5/issues/4975)  🌟 NEW -- [ClearML Logging](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml) 🌟 NEW -- [YOLOv3 with Neural Magic's Deepsparse](https://bit.ly/yolov5-neuralmagic) 🌟 NEW -- [Comet Logging](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/comet) 🌟 NEW +- [Train Custom Data](https://docs.ultralytics.com/yolov5/train_custom_data) 🚀 RECOMMENDED +- [Tips for Best Training Results](https://docs.ultralytics.com/yolov5/tips_for_best_training_results) ☘️ RECOMMENDED +- [Multi-GPU Training](https://docs.ultralytics.com/yolov5/multi_gpu_training) +- [PyTorch Hub](https://docs.ultralytics.com/yolov5/pytorch_hub) 🌟 NEW +- [TFLite, ONNX, CoreML, TensorRT Export](https://docs.ultralytics.com/yolov5/export) 🚀 +- [NVIDIA Jetson platform Deployment](https://docs.ultralytics.com/yolov5/jetson_nano) 🌟 NEW +- [Test-Time Augmentation (TTA)](https://docs.ultralytics.com/yolov5/tta) +- [Model Ensembling](https://docs.ultralytics.com/yolov5/ensemble) +- [Model Pruning/Sparsity](https://docs.ultralytics.com/yolov5/pruning_sparsity) +- [Hyperparameter Evolution](https://docs.ultralytics.com/yolov5/hyp_evolution) +- [Transfer Learning with Frozen Layers](https://docs.ultralytics.com/yolov5/transfer_learn_frozen) +- [Architecture Summary](https://docs.ultralytics.com/yolov5/architecture) 🌟 NEW +- [Roboflow for Datasets, Labeling, and Active Learning](https://docs.ultralytics.com/yolov5/roboflow) +- [ClearML Logging](https://docs.ultralytics.com/yolov5/clearml) 🌟 NEW +- [YOLOv3 with Neural Magic's Deepsparse](https://docs.ultralytics.com/yolov5/neural_magic) 🌟 NEW +- [Comet Logging](https://docs.ultralytics.com/yolov5/comet) 🌟 NEW
diff --git a/README.zh-CN.md b/README.zh-CN.md index 5338ecaa9b..1842e2a55b 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -148,22 +148,22 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
教程 -- [训练自定义数据](https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data)🚀 推荐 -- [获得最佳训练结果的技巧](https://github.com/ultralytics/yolov5/wiki/Tips-for-Best-Training-Results)☘️ 推荐 -- [多 GPU 训练](https://github.com/ultralytics/yolov5/issues/475) -- [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36)🌟 新 -- [TFLite、ONNX、CoreML、TensorRT 导出](https://github.com/ultralytics/yolov5/issues/251)🚀 -- [NVIDIA Jetson Nano 部署](https://github.com/ultralytics/yolov5/issues/9627)🌟 新 -- [测试时数据增强 (TTA)](https://github.com/ultralytics/yolov5/issues/303) -- [模型集成](https://github.com/ultralytics/yolov5/issues/318) -- [模型修剪/稀疏度](https://github.com/ultralytics/yolov5/issues/304) -- [超参数进化](https://github.com/ultralytics/yolov5/issues/607) -- [使用冻结层进行迁移学习](https://github.com/ultralytics/yolov5/issues/1314) -- [架构总结](https://github.com/ultralytics/yolov5/issues/6998)🌟 新 -- [用于数据集、标签和主动学习的 Roboflow](https://github.com/ultralytics/yolov5/issues/4975)🌟 新 -- [ClearML 记录](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml)🌟 新 -- [Deci 平台](https://github.com/ultralytics/yolov5/wiki/Deci-Platform)🌟 新 -- [Comet Logging](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/comet)🌟 新 +- [训练自定义数据](https://docs.ultralytics.com/yolov5/train_custom_data) 🚀 推荐 +- [获得最佳训练结果的技巧](https://docs.ultralytics.com/yolov5/tips_for_best_training_results) ☘️ 推荐 +- [多 GPU 训练](https://docs.ultralytics.com/yolov5/multi_gpu_training) +- [PyTorch Hub](https://docs.ultralytics.com/yolov5/pytorch_hub) 🌟 新 +- [TFLite, ONNX, CoreML, TensorRT 导出](https://docs.ultralytics.com/yolov5/export) 🚀 +- [NVIDIA Jetson 平台部署](https://docs.ultralytics.com/yolov5/jetson_nano) 🌟 新 +- [测试时增强(TTA)](https://docs.ultralytics.com/yolov5/tta) +- [模型集成](https://docs.ultralytics.com/yolov5/ensemble) +- [模型剪枝/稀疏性](https://docs.ultralytics.com/yolov5/pruning_sparsity) +- [超参数进化](https://docs.ultralytics.com/yolov5/hyp_evolution) +- [冻结层的迁移学习](https://docs.ultralytics.com/yolov5/transfer_learn_frozen) +- [架构概述](https://docs.ultralytics.com/yolov5/architecture) 🌟 新 +- [Roboflow 用于数据集、标签和主动学习](https://docs.ultralytics.com/yolov5/roboflow) +- [ClearML 日志记录](https://docs.ultralytics.com/yolov5/clearml) 🌟 新 +- [YOLOv5 与 Neural Magic 的 Deepsparse](https://docs.ultralytics.com/yolov5/neural_magic) 🌟 新 +- [Comet 日志记录](https://docs.ultralytics.com/yolov5/comet) 🌟 新
From 4c3ff1e5513300ab045ab9b9fc9b53d351281819 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 1 Apr 2023 13:03:29 +0200 Subject: [PATCH 0946/1185] Update greetings.yml (#2033) * Update greeting * Update greeting --- .github/workflows/greetings.yml | 4 ++-- README.md | 2 +- README.zh-CN.md | 2 +- requirements.txt | 1 - 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 7b998b3c24..18d82d04b7 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -18,12 +18,12 @@ jobs: pr-message: | 👋 Hello @${{ github.actor }}, thank you for submitting a YOLOv3 🚀 PR! To allow your work to be integrated as seamlessly as possible, we advise you to: - - ✅ Verify your PR is **up-to-date** with `ultralytics/yolov5` `master` branch. If your PR is behind you can update your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally. + - ✅ Verify your PR is **up-to-date** with `ultralytics/yolov3` `master` branch. If your PR is behind you can update your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally. - ✅ Verify all YOLOv3 Continuous Integration (CI) **checks are passing**. - ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ — Bruce Lee issue-message: | - 👋 Hello @${{ github.actor }}, thank you for your interest in YOLOv3 🚀! Please visit our ⭐️ [Tutorials](https://github.com/ultralytics/yolov5/wiki#tutorials) to get started, where you can find quickstart guides for simple tasks like [Custom Data Training](https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data) all the way to advanced concepts like [Hyperparameter Evolution](https://github.com/ultralytics/yolov5/issues/607). + 👋 Hello @${{ github.actor }}, thank you for your interest in YOLOv3 🚀! Please visit our ⭐️ [Tutorials](https://docs.ultralytics.com/yolov5/) to get started, where you can find quickstart guides for simple tasks like [Custom Data Training](https://docs.ultralytics.com/yolov5/train_custom_data/) all the way to advanced concepts like [Hyperparameter Evolution](https://docs.ultralytics.com/yolov5/hyp_evolution/). If this is a 🐛 Bug Report, please provide a **minimum reproducible example** to help us debug it. diff --git a/README.md b/README.md index 5996f43f8c..bc72d3037a 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - - [Hyperparameter Evolution](https://docs.ultralytics.com/yolov5/hyp_evolution) - [Transfer Learning with Frozen Layers](https://docs.ultralytics.com/yolov5/transfer_learn_frozen) - [Architecture Summary](https://docs.ultralytics.com/yolov5/architecture) 🌟 NEW -- [Roboflow for Datasets, Labeling, and Active Learning](https://docs.ultralytics.com/yolov5/roboflow) +- [Roboflow for Datasets](https://docs.ultralytics.com/yolov5/roboflow) - [ClearML Logging](https://docs.ultralytics.com/yolov5/clearml) 🌟 NEW - [YOLOv3 with Neural Magic's Deepsparse](https://docs.ultralytics.com/yolov5/neural_magic) 🌟 NEW - [Comet Logging](https://docs.ultralytics.com/yolov5/comet) 🌟 NEW diff --git a/README.zh-CN.md b/README.zh-CN.md index 1842e2a55b..c2d372754b 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -160,7 +160,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - - [超参数进化](https://docs.ultralytics.com/yolov5/hyp_evolution) - [冻结层的迁移学习](https://docs.ultralytics.com/yolov5/transfer_learn_frozen) - [架构概述](https://docs.ultralytics.com/yolov5/architecture) 🌟 新 -- [Roboflow 用于数据集、标签和主动学习](https://docs.ultralytics.com/yolov5/roboflow) +- [Roboflow](https://docs.ultralytics.com/yolov5/roboflow) - [ClearML 日志记录](https://docs.ultralytics.com/yolov5/clearml) 🌟 新 - [YOLOv5 与 Neural Magic 的 Deepsparse](https://docs.ultralytics.com/yolov5/neural_magic) 🌟 新 - [Comet 日志记录](https://docs.ultralytics.com/yolov5/comet) 🌟 新 diff --git a/requirements.txt b/requirements.txt index 7bfde97bfa..97ecf13898 100644 --- a/requirements.txt +++ b/requirements.txt @@ -47,5 +47,4 @@ wheel>=0.38.0 # Snyk vulnerability fix # mss # screenshots # albumentations>=1.0.3 # pycocotools>=2.0.6 # COCO mAP -# roboflow # ultralytics # HUB https://hub.ultralytics.com From a31b8663b4c0b0c3917995f3000bd4c10e8044dd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 13:00:52 +0200 Subject: [PATCH 0947/1185] [pre-commit.ci] pre-commit suggestions (#2034) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/codespell-project/codespell: v2.2.2 → v2.2.4](https://github.com/codespell-project/codespell/compare/v2.2.2...v2.2.4) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c5162378ab..750ced6905 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -57,7 +57,7 @@ repos: name: PEP8 - repo: https://github.com/codespell-project/codespell - rev: v2.2.2 + rev: v2.2.4 hooks: - id: codespell args: From d020053a3f5ab6a04fdd44a14f1761db8cdbcaa5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 9 Apr 2023 13:34:42 +0200 Subject: [PATCH 0948/1185] Update issue YAMLs (#2038) --- .github/ISSUE_TEMPLATE/bug-report.yml | 8 ++++---- .github/ISSUE_TEMPLATE/config.yml | 9 ++++++--- .github/ISSUE_TEMPLATE/feature-request.yml | 8 ++++---- .github/ISSUE_TEMPLATE/question.yml | 4 ++-- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 9c11b695ee..affe6aae2b 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -12,10 +12,10 @@ body: attributes: label: Search before asking description: > - Please search the [issues](https://github.com/ultralytics/yolov5/issues) to see if a similar bug report already exists. + Please search the [issues](https://github.com/ultralytics/yolov3/issues) to see if a similar bug report already exists. options: - label: > - I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov5/issues) and found no similar bug report. + I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov3/issues) and found no similar bug report. required: true - type: dropdown @@ -79,7 +79,7 @@ body: attributes: label: Are you willing to submit a PR? description: > - (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov5/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. - See the YOLOv3 [Contributing Guide](https://github.com/ultralytics/yolov5/blob/master/CONTRIBUTING.md) to get started. + (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. + See the YOLOv3 [Contributing Guide](https://github.com/ultralytics/yolov3/blob/master/CONTRIBUTING.md) to get started. options: - label: Yes I'd like to help by submitting a PR! diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index e6a8c427cc..b071ccae73 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,11 @@ blank_issues_enabled: true contact_links: + - name: 📄 Docs + url: https://docs.ultralytics.com/ + about: View Ultralytics YOLOv3 Docs - name: 💬 Forum url: https://community.ultralytics.com/ about: Ask on Ultralytics Community Forum - - name: Stack Overflow - url: https://stackoverflow.com/search?q=YOLOv3 - about: Ask on Stack Overflow with 'YOLOv3' tag + - name: 🎧 Discord + url: https://discord.gg/n6cFeSPZdD + about: Ask on Ultralytics Discord diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index d67e330126..53cf234475 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -12,10 +12,10 @@ body: attributes: label: Search before asking description: > - Please search the [issues](https://github.com/ultralytics/yolov5/issues) to see if a similar feature request already exists. + Please search the [issues](https://github.com/ultralytics/yolov3/issues) to see if a similar feature request already exists. options: - label: > - I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov5/issues) and found no similar feature requests. + I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov3/issues) and found no similar feature requests. required: true - type: textarea @@ -44,7 +44,7 @@ body: attributes: label: Are you willing to submit a PR? description: > - (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov5/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. - See the YOLOv3 [Contributing Guide](https://github.com/ultralytics/yolov5/blob/master/CONTRIBUTING.md) to get started. + (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. + See the YOLOv3 [Contributing Guide](https://github.com/ultralytics/yolov3/blob/master/CONTRIBUTING.md) to get started. options: - label: Yes I'd like to help by submitting a PR! diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml index c056eec8a4..decb214859 100644 --- a/.github/ISSUE_TEMPLATE/question.yml +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -12,10 +12,10 @@ body: attributes: label: Search before asking description: > - Please search the [issues](https://github.com/ultralytics/yolov5/issues) and [discussions](https://github.com/ultralytics/yolov5/discussions) to see if a similar question already exists. + Please search the [issues](https://github.com/ultralytics/yolov3/issues) and [discussions](https://github.com/ultralytics/yolov3/discussions) to see if a similar question already exists. options: - label: > - I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov5/issues) and [discussions](https://github.com/ultralytics/yolov5/discussions) and found no similar questions. + I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov3/issues) and [discussions](https://github.com/ultralytics/yolov3/discussions) and found no similar questions. required: true - type: textarea From 5d5452d74661567c908179a4d4c18882c4d6f343 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 9 Apr 2023 18:16:18 +0200 Subject: [PATCH 0949/1185] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f25b017ace..51f9803a57 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,4 +6,8 @@ Thank you for submitting a YOLOv5 🚀 Pull Request! We want to make contributin - Provide before and after profiling/inference/training results to help us quantify the improvement your PR provides (if applicable). Please see our ✅ [Contributing Guide](https://github.com/ultralytics/yolov5/blob/master/CONTRIBUTING.md) for more details. + +Note that Copilot will summarize this PR below, do not modify the 'copilot:all' line. --> + +copilot:all From cf85b67a5485e88f8ce0dc42e885da6b8b10e4e8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 14 Apr 2023 14:42:30 +0200 Subject: [PATCH 0950/1185] Update LICENSE to AGPL-3.0 (#2039) * Update LICENSE to AGPL-3.0 This pull request updates the license of the YOLOv3 project from GNU General Public License v3.0 (GPL-3.0) to GNU Affero General Public License v3.0 (AGPL-3.0). We at Ultralytics have decided to make this change in order to better protect our intellectual property and ensure that any modifications made to the YOLOv3 source code will be shared back with the community when used over a network. AGPL-3.0 is very similar to GPL-3.0, but with an additional clause to address the use of software over a network. This change ensures that if someone modifies YOLOv3 and provides it as a service over a network (e.g., through a web application or API), they must also make the source code of their modified version available to users of the service. This update includes the following changes: Replace the LICENSE file with the AGPL-3.0 license text Update the license reference in the README.md file Update the license headers in source code files We believe that this change will promote a more collaborative environment and help drive further innovation within the YOLOv3 community. * Update headers --- .github/workflows/ci-testing.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/greetings.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/translate-readme.yml | 2 +- .pre-commit-config.yaml | 2 +- CITATION.cff | 2 +- CONTRIBUTING.md | 2 +- LICENSE | 153 +++++++++++------------- README.md | 4 +- README.zh-CN.md | 4 +- benchmarks.py | 2 +- classify/predict.py | 2 +- classify/train.py | 2 +- classify/val.py | 2 +- data/Argoverse.yaml | 2 +- data/GlobalWheat2020.yaml | 2 +- data/ImageNet.yaml | 2 +- data/SKU-110K.yaml | 2 +- data/VisDrone.yaml | 2 +- data/coco.yaml | 2 +- data/coco128-seg.yaml | 2 +- data/coco128.yaml | 2 +- data/hyps/hyp.Objects365.yaml | 2 +- data/hyps/hyp.VOC.yaml | 2 +- data/hyps/hyp.no-augmentation.yaml | 2 +- data/hyps/hyp.scratch-high.yaml | 2 +- data/hyps/hyp.scratch-low.yaml | 2 +- data/hyps/hyp.scratch-med.yaml | 2 +- data/objects365.yaml | 2 +- data/scripts/download_weights.sh | 2 +- data/scripts/get_coco.sh | 2 +- data/scripts/get_coco128.sh | 2 +- data/scripts/get_imagenet.sh | 2 +- data/voc.yaml | 2 +- data/xView.yaml | 2 +- detect.py | 2 +- export.py | 2 +- hubconf.py | 2 +- models/common.py | 2 +- models/experimental.py | 2 +- models/hub/anchors.yaml | 2 +- models/hub/yolov5-bifpn.yaml | 2 +- models/hub/yolov5-fpn.yaml | 2 +- models/hub/yolov5-p2.yaml | 2 +- models/hub/yolov5-p34.yaml | 2 +- models/hub/yolov5-p6.yaml | 2 +- models/hub/yolov5-p7.yaml | 2 +- models/hub/yolov5-panet.yaml | 2 +- models/hub/yolov5l6.yaml | 2 +- models/hub/yolov5m6.yaml | 2 +- models/hub/yolov5n6.yaml | 2 +- models/hub/yolov5s-LeakyReLU.yaml | 2 +- models/hub/yolov5s-ghost.yaml | 2 +- models/hub/yolov5s-transformer.yaml | 2 +- models/hub/yolov5s6.yaml | 2 +- models/hub/yolov5x6.yaml | 2 +- models/segment/yolov5l-seg.yaml | 2 +- models/segment/yolov5m-seg.yaml | 2 +- models/segment/yolov5n-seg.yaml | 2 +- models/segment/yolov5s-seg.yaml | 2 +- models/segment/yolov5x-seg.yaml | 2 +- models/tf.py | 2 +- models/yolo.py | 2 +- models/yolov3-spp.yaml | 2 +- models/yolov3-tiny.yaml | 2 +- models/yolov3.yaml | 2 +- models/yolov5l.yaml | 2 +- models/yolov5m.yaml | 2 +- models/yolov5n.yaml | 2 +- models/yolov5s.yaml | 2 +- models/yolov5x.yaml | 2 +- segment/predict.py | 2 +- segment/train.py | 2 +- segment/val.py | 2 +- train.py | 2 +- utils/__init__.py | 2 +- utils/activations.py | 2 +- utils/augmentations.py | 2 +- utils/autoanchor.py | 2 +- utils/autobatch.py | 2 +- utils/callbacks.py | 2 +- utils/dataloaders.py | 2 +- utils/docker/Dockerfile | 2 +- utils/docker/Dockerfile-arm64 | 2 +- utils/docker/Dockerfile-cpu | 2 +- utils/downloads.py | 2 +- utils/flask_rest_api/example_request.py | 2 +- utils/flask_rest_api/restapi.py | 2 +- utils/general.py | 2 +- utils/loggers/__init__.py | 2 +- utils/loggers/wandb/wandb_utils.py | 2 +- utils/loss.py | 2 +- utils/metrics.py | 2 +- utils/plots.py | 2 +- utils/segment/augmentations.py | 2 +- utils/segment/dataloaders.py | 2 +- utils/segment/metrics.py | 2 +- utils/torch_utils.py | 2 +- utils/triton.py | 2 +- val.py | 2 +- 101 files changed, 172 insertions(+), 185 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 151a564ded..06597e89b7 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # YOLOv3 Continuous Integration (CI) GitHub Actions tests name: YOLOv3 CI diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c849665656..db9a4cc9e1 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Builds ultralytics/yolov5:latest images on DockerHub https://hub.docker.com/r/ultralytics/yolov3 name: Publish Docker Images diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 18d82d04b7..b412eecc87 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license name: Greetings diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index a93a4d0eff..c020ed0cd1 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license name: Close stale issues on: diff --git a/.github/workflows/translate-readme.yml b/.github/workflows/translate-readme.yml index 0efe298dcc..5632b62aed 100644 --- a/.github/workflows/translate-readme.yml +++ b/.github/workflows/translate-readme.yml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # README translation action to translate README.md to Chinese as README.zh-CN.md on any change to README.md name: Translate README diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 750ced6905..8bd40484c5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLO 🚀, GPL-3.0 license +# Ultralytics YOLO 🚀, AGPL-3.0 license # Pre-commit hooks. For more information see https://github.com/pre-commit/pre-commit-hooks/blob/main/README.md exclude: 'docs/' diff --git a/CITATION.cff b/CITATION.cff index 41b1a33709..f371d61015 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -10,5 +10,5 @@ preferred-citation: version: 7.0 doi: 10.5281/zenodo.3908559 date-released: 2020-5-29 - license: GPL-3.0 + license: AGPL-3.0 url: "https://github.com/ultralytics/yolov5" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8e83398be6..68db594f51 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -90,4 +90,4 @@ understand and diagnose your problem. ## License By contributing, you agree that your contributions will be licensed under -the [GPL-3.0 license](https://choosealicense.com/licenses/gpl-3.0/) +the [AGPL-3.0 license](https://choosealicense.com/licenses/agpl-3.0/) diff --git a/LICENSE b/LICENSE index 92b370f0e0..be3f7b28e5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,23 +1,21 @@ -GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble - The GNU General Public License is a free, copyleft license for -software and other kinds of works. + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to +our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. +software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you @@ -26,44 +24,34 @@ them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. The precise terms and conditions for copying, distribution and modification follow. @@ -72,7 +60,7 @@ modification follow. 0. Definitions. - "This License" refers to version 3 of the GNU General Public License. + "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. @@ -549,35 +537,45 @@ to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - 13. Use with the GNU Affero General Public License. + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single +under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General +Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published +GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's +versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. @@ -635,40 +633,29 @@ the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by + it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Affero General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md index bc72d3037a..65fbb486b7 100644 --- a/README.md +++ b/README.md @@ -455,8 +455,8 @@ We love your input! We want to make contributing to YOLOv3 as easy and transpare YOLOv3 is available under two different licenses: -- **GPL-3.0 License**: See [LICENSE](https://github.com/ultralytics/yolov5/blob/master/LICENSE) file for details. -- **Enterprise License**: Provides greater flexibility for commercial product development without the open-source requirements of GPL-3.0. Typical use cases are embedding Ultralytics software and AI models in commercial products and applications. Request an Enterprise License at [Ultralytics Licensing](https://ultralytics.com/license). +- **AGPL-3.0 License**: See [LICENSE](https://github.com/ultralytics/yolov5/blob/master/LICENSE) file for details. +- **Enterprise License**: Provides greater flexibility for commercial product development without the open-source requirements of AGPL-3.0. Typical use cases are embedding Ultralytics software and AI models in commercial products and applications. Request an Enterprise License at [Ultralytics Licensing](https://ultralytics.com/license). ##
Contact
diff --git a/README.zh-CN.md b/README.zh-CN.md index c2d372754b..fbc194e1e9 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -452,8 +452,8 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu YOLOv3 在两种不同的 License 下可用: -- **GPL-3.0 License**: 查看 [License](https://github.com/ultralytics/yolov5/blob/master/LICENSE) 文件的详细信息。 -- **企业License**:在没有 GPL-3.0 开源要求的情况下为商业产品开发提供更大的灵活性。典型用例是将 Ultralytics 软件和 AI 模型嵌入到商业产品和应用程序中。在以下位置申请企业许可证 [Ultralytics 许可](https://ultralytics.com/license) 。 +- **AGPL-3.0 License**: 查看 [License](https://github.com/ultralytics/yolov5/blob/master/LICENSE) 文件的详细信息。 +- **企业License**:在没有 AGPL-3.0 开源要求的情况下为商业产品开发提供更大的灵活性。典型用例是将 Ultralytics 软件和 AI 模型嵌入到商业产品和应用程序中。在以下位置申请企业许可证 [Ultralytics 许可](https://ultralytics.com/license) 。 ##
联系我们
diff --git a/benchmarks.py b/benchmarks.py index 38fcb0239f..d4c57e9b00 100644 --- a/benchmarks.py +++ b/benchmarks.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Run benchmarks on all supported export formats diff --git a/classify/predict.py b/classify/predict.py index bbb07640dd..c123f64439 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Run classification inference on images, videos, directories, globs, YouTube, webcam, streams, etc. diff --git a/classify/train.py b/classify/train.py index 3db68dc032..46518a9a3e 100644 --- a/classify/train.py +++ b/classify/train.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Train a YOLOv5 classifier model on a classification dataset diff --git a/classify/val.py b/classify/val.py index f0041ea72a..c2e468d08f 100644 --- a/classify/val.py +++ b/classify/val.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Validate a trained YOLOv5 classification model on a classification dataset diff --git a/data/Argoverse.yaml b/data/Argoverse.yaml index a3b4511eb5..794718a4c0 100644 --- a/data/Argoverse.yaml +++ b/data/Argoverse.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/ by Argo AI # Example usage: python train.py --data Argoverse.yaml # parent diff --git a/data/GlobalWheat2020.yaml b/data/GlobalWheat2020.yaml index 9df59b84d7..68d86b5ebc 100644 --- a/data/GlobalWheat2020.yaml +++ b/data/GlobalWheat2020.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Global Wheat 2020 dataset http://www.global-wheat.com/ by University of Saskatchewan # Example usage: python train.py --data GlobalWheat2020.yaml # parent diff --git a/data/ImageNet.yaml b/data/ImageNet.yaml index e0af69fe24..cf0218006a 100644 --- a/data/ImageNet.yaml +++ b/data/ImageNet.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # ImageNet-1k dataset https://www.image-net.org/index.php by Stanford University # Simplified class names from https://github.com/anishathalye/imagenet-simple-labels # Example usage: python classify/train.py --data imagenet diff --git a/data/SKU-110K.yaml b/data/SKU-110K.yaml index 9ebbb555a0..0e014d3d3b 100644 --- a/data/SKU-110K.yaml +++ b/data/SKU-110K.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # SKU-110K retail items dataset https://github.com/eg4000/SKU110K_CVPR19 by Trax Retail # Example usage: python train.py --data SKU-110K.yaml # parent diff --git a/data/VisDrone.yaml b/data/VisDrone.yaml index fae733bba2..3c70269618 100644 --- a/data/VisDrone.yaml +++ b/data/VisDrone.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # VisDrone2019-DET dataset https://github.com/VisDrone/VisDrone-Dataset by Tianjin University # Example usage: python train.py --data VisDrone.yaml # parent diff --git a/data/coco.yaml b/data/coco.yaml index 8dd3c7c825..48da613504 100644 --- a/data/coco.yaml +++ b/data/coco.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # COCO 2017 dataset http://cocodataset.org by Microsoft # Example usage: python train.py --data coco.yaml # parent diff --git a/data/coco128-seg.yaml b/data/coco128-seg.yaml index 6a45758eb9..124eca12cb 100644 --- a/data/coco128-seg.yaml +++ b/data/coco128-seg.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # COCO128-seg dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics # Example usage: python train.py --data coco128.yaml # parent diff --git a/data/coco128.yaml b/data/coco128.yaml index 6cb076acdd..2317921c9e 100644 --- a/data/coco128.yaml +++ b/data/coco128.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics # Example usage: python train.py --data coco128.yaml # parent diff --git a/data/hyps/hyp.Objects365.yaml b/data/hyps/hyp.Objects365.yaml index e3bc19bbc8..e96e9ac307 100644 --- a/data/hyps/hyp.Objects365.yaml +++ b/data/hyps/hyp.Objects365.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Hyperparameters for Objects365 training # python train.py --weights yolov5m.pt --data Objects365.yaml --evolve # See Hyperparameter Evolution tutorial for details https://github.com/ultralytics/yolov5#tutorials diff --git a/data/hyps/hyp.VOC.yaml b/data/hyps/hyp.VOC.yaml index 34cf8d1e63..45d82370a6 100644 --- a/data/hyps/hyp.VOC.yaml +++ b/data/hyps/hyp.VOC.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Hyperparameters for VOC training # python train.py --batch 128 --weights yolov5m6.pt --data VOC.yaml --epochs 50 --img 512 --hyp hyp.scratch-med.yaml --evolve # See Hyperparameter Evolution tutorial for details https://github.com/ultralytics/yolov5#tutorials diff --git a/data/hyps/hyp.no-augmentation.yaml b/data/hyps/hyp.no-augmentation.yaml index 50ee43e699..76c01e9cc0 100644 --- a/data/hyps/hyp.no-augmentation.yaml +++ b/data/hyps/hyp.no-augmentation.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Hyperparameters when using Albumentations frameworks # python train.py --hyp hyp.no-augmentation.yaml # See https://github.com/ultralytics/yolov5/pull/3882 for YOLOv5 + Albumentations Usage examples diff --git a/data/hyps/hyp.scratch-high.yaml b/data/hyps/hyp.scratch-high.yaml index 05cd35cb02..370e6542f1 100644 --- a/data/hyps/hyp.scratch-high.yaml +++ b/data/hyps/hyp.scratch-high.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Hyperparameters for high-augmentation COCO training from scratch # python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300 # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials diff --git a/data/hyps/hyp.scratch-low.yaml b/data/hyps/hyp.scratch-low.yaml index 3f9849c9fa..23d99f0709 100644 --- a/data/hyps/hyp.scratch-low.yaml +++ b/data/hyps/hyp.scratch-low.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Hyperparameters for low-augmentation COCO training from scratch # python train.py --batch 64 --cfg yolov5n6.yaml --weights '' --data coco.yaml --img 640 --epochs 300 --linear # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials diff --git a/data/hyps/hyp.scratch-med.yaml b/data/hyps/hyp.scratch-med.yaml index d1f480bcb2..022cc51167 100644 --- a/data/hyps/hyp.scratch-med.yaml +++ b/data/hyps/hyp.scratch-med.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Hyperparameters for medium-augmentation COCO training from scratch # python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300 # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials diff --git a/data/objects365.yaml b/data/objects365.yaml index 353635a3c6..fc32203981 100644 --- a/data/objects365.yaml +++ b/data/objects365.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Objects365 dataset https://www.objects365.org/ by Megvii # Example usage: python train.py --data Objects365.yaml # parent diff --git a/data/scripts/download_weights.sh b/data/scripts/download_weights.sh index 5e9acc44fa..16b14b9616 100755 --- a/data/scripts/download_weights.sh +++ b/data/scripts/download_weights.sh @@ -1,5 +1,5 @@ #!/bin/bash -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Download latest models from https://github.com/ultralytics/yolov5/releases # Example usage: bash data/scripts/download_weights.sh # parent diff --git a/data/scripts/get_coco.sh b/data/scripts/get_coco.sh index 040bad554e..6a5cbffb25 100755 --- a/data/scripts/get_coco.sh +++ b/data/scripts/get_coco.sh @@ -1,5 +1,5 @@ #!/bin/bash -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Download COCO 2017 dataset http://cocodataset.org # Example usage: bash data/scripts/get_coco.sh # parent diff --git a/data/scripts/get_coco128.sh b/data/scripts/get_coco128.sh index 515d1ad50c..99f5f4d68f 100755 --- a/data/scripts/get_coco128.sh +++ b/data/scripts/get_coco128.sh @@ -1,5 +1,5 @@ #!/bin/bash -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Download COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) # Example usage: bash data/scripts/get_coco128.sh # parent diff --git a/data/scripts/get_imagenet.sh b/data/scripts/get_imagenet.sh index ef5e3eb406..2f2f8db3b2 100755 --- a/data/scripts/get_imagenet.sh +++ b/data/scripts/get_imagenet.sh @@ -1,5 +1,5 @@ #!/bin/bash -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Download ILSVRC2012 ImageNet dataset https://image-net.org # Example usage: bash data/scripts/get_imagenet.sh # parent diff --git a/data/voc.yaml b/data/voc.yaml index 7b1e947185..555ae0d7bb 100644 --- a/data/voc.yaml +++ b/data/voc.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # PASCAL VOC dataset http://host.robots.ox.ac.uk/pascal/VOC by University of Oxford # Example usage: python train.py --data VOC.yaml # parent diff --git a/data/xView.yaml b/data/xView.yaml index 0b247aad33..54a623ea28 100644 --- a/data/xView.yaml +++ b/data/xView.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # DIUx xView 2018 Challenge https://challenge.xviewdataset.org by U.S. National Geospatial-Intelligence Agency (NGA) # -------- DOWNLOAD DATA MANUALLY and jar xf val_images.zip to 'datasets/xView' before running train command! -------- # Example usage: python train.py --data xView.yaml diff --git a/detect.py b/detect.py index d4ab1c8d9d..c4acb976c2 100644 --- a/detect.py +++ b/detect.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Run YOLOv3 detection inference on images, videos, directories, globs, YouTube, webcam, streams, etc. diff --git a/export.py b/export.py index fd4720a030..6e460210bb 100644 --- a/export.py +++ b/export.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Export a YOLOv3 PyTorch model to other formats. TensorFlow exports authored by https://github.com/zldrobit diff --git a/hubconf.py b/hubconf.py index b1c45e7b56..0515dae648 100644 --- a/hubconf.py +++ b/hubconf.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov5 diff --git a/models/common.py b/models/common.py index bc5fc0d356..cc147b7384 100644 --- a/models/common.py +++ b/models/common.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Common modules """ diff --git a/models/experimental.py b/models/experimental.py index 39e3ad9f12..dd41155a8d 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Experimental modules """ diff --git a/models/hub/anchors.yaml b/models/hub/anchors.yaml index fc252c1927..b1306c7f48 100644 --- a/models/hub/anchors.yaml +++ b/models/hub/anchors.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Default anchors for COCO data diff --git a/models/hub/yolov5-bifpn.yaml b/models/hub/yolov5-bifpn.yaml index 7d17a347c3..8afcc45219 100644 --- a/models/hub/yolov5-bifpn.yaml +++ b/models/hub/yolov5-bifpn.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-fpn.yaml b/models/hub/yolov5-fpn.yaml index 0c91f931c0..172135ae57 100644 --- a/models/hub/yolov5-fpn.yaml +++ b/models/hub/yolov5-fpn.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-p2.yaml b/models/hub/yolov5-p2.yaml index 23264db05c..ee86296a0c 100644 --- a/models/hub/yolov5-p2.yaml +++ b/models/hub/yolov5-p2.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-p34.yaml b/models/hub/yolov5-p34.yaml index c7f76e3052..b477f2fee5 100644 --- a/models/hub/yolov5-p34.yaml +++ b/models/hub/yolov5-p34.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-p6.yaml b/models/hub/yolov5-p6.yaml index a7b79a574d..7a94d0cc0a 100644 --- a/models/hub/yolov5-p6.yaml +++ b/models/hub/yolov5-p6.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-p7.yaml b/models/hub/yolov5-p7.yaml index 3846496bce..a0dcced7b8 100644 --- a/models/hub/yolov5-p7.yaml +++ b/models/hub/yolov5-p7.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-panet.yaml b/models/hub/yolov5-panet.yaml index 9a9a34dd56..352cce45af 100644 --- a/models/hub/yolov5-panet.yaml +++ b/models/hub/yolov5-panet.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5l6.yaml b/models/hub/yolov5l6.yaml index e9f03b3494..0eba5de427 100644 --- a/models/hub/yolov5l6.yaml +++ b/models/hub/yolov5l6.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5m6.yaml b/models/hub/yolov5m6.yaml index 7077be1abf..75bd2c1f29 100644 --- a/models/hub/yolov5m6.yaml +++ b/models/hub/yolov5m6.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5n6.yaml b/models/hub/yolov5n6.yaml index 2b4374c805..79deec1f97 100644 --- a/models/hub/yolov5n6.yaml +++ b/models/hub/yolov5n6.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5s-LeakyReLU.yaml b/models/hub/yolov5s-LeakyReLU.yaml index 0d3dbc0dd2..638f6ec892 100644 --- a/models/hub/yolov5s-LeakyReLU.yaml +++ b/models/hub/yolov5s-LeakyReLU.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5s-ghost.yaml b/models/hub/yolov5s-ghost.yaml index e8bbcfe3b2..993fcd6fcb 100644 --- a/models/hub/yolov5s-ghost.yaml +++ b/models/hub/yolov5s-ghost.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5s-transformer.yaml b/models/hub/yolov5s-transformer.yaml index a0a3ce8e82..9525ee0f2d 100644 --- a/models/hub/yolov5s-transformer.yaml +++ b/models/hub/yolov5s-transformer.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5s6.yaml b/models/hub/yolov5s6.yaml index 85f3ef5ad1..8443a7f329 100644 --- a/models/hub/yolov5s6.yaml +++ b/models/hub/yolov5s6.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5x6.yaml b/models/hub/yolov5x6.yaml index 290da47dd0..48415b8a8c 100644 --- a/models/hub/yolov5x6.yaml +++ b/models/hub/yolov5x6.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5l-seg.yaml b/models/segment/yolov5l-seg.yaml index ac06eb8713..0da593db07 100644 --- a/models/segment/yolov5l-seg.yaml +++ b/models/segment/yolov5l-seg.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5m-seg.yaml b/models/segment/yolov5m-seg.yaml index cafadcd9cc..59cf47e94e 100644 --- a/models/segment/yolov5m-seg.yaml +++ b/models/segment/yolov5m-seg.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5n-seg.yaml b/models/segment/yolov5n-seg.yaml index 21635c3c95..8d749007f1 100644 --- a/models/segment/yolov5n-seg.yaml +++ b/models/segment/yolov5n-seg.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5s-seg.yaml b/models/segment/yolov5s-seg.yaml index 6018cdb431..05ce94bbe8 100644 --- a/models/segment/yolov5s-seg.yaml +++ b/models/segment/yolov5s-seg.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5x-seg.yaml b/models/segment/yolov5x-seg.yaml index 5a95b92f08..8e926612c4 100644 --- a/models/segment/yolov5x-seg.yaml +++ b/models/segment/yolov5x-seg.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/tf.py b/models/tf.py index 748a95c9a0..ca6fc9ec0b 100644 --- a/models/tf.py +++ b/models/tf.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ TensorFlow, Keras and TFLite versions of YOLOv3 Authored by https://github.com/zldrobit in PR https://github.com/ultralytics/yolov5/pull/1127 diff --git a/models/yolo.py b/models/yolo.py index fbff6da763..22da67f78c 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ YOLO-specific modules diff --git a/models/yolov3-spp.yaml b/models/yolov3-spp.yaml index 04593a47d2..2598a9b6c8 100644 --- a/models/yolov3-spp.yaml +++ b/models/yolov3-spp.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov3-tiny.yaml b/models/yolov3-tiny.yaml index 04f9b446a6..6d1c65dd1c 100644 --- a/models/yolov3-tiny.yaml +++ b/models/yolov3-tiny.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov3.yaml b/models/yolov3.yaml index 8656bb95c1..19874a0f15 100644 --- a/models/yolov3.yaml +++ b/models/yolov3.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov5l.yaml b/models/yolov5l.yaml index 2c3a7c1725..01a3dc78ae 100644 --- a/models/yolov5l.yaml +++ b/models/yolov5l.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov5m.yaml b/models/yolov5m.yaml index f0ee2907bd..2d1d180861 100644 --- a/models/yolov5m.yaml +++ b/models/yolov5m.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov5n.yaml b/models/yolov5n.yaml index a4b7266006..3c295ee130 100644 --- a/models/yolov5n.yaml +++ b/models/yolov5n.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov5s.yaml b/models/yolov5s.yaml index b3edebe9d9..07b171671d 100644 --- a/models/yolov5s.yaml +++ b/models/yolov5s.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov5x.yaml b/models/yolov5x.yaml index d8c7dd7881..f046b2c677 100644 --- a/models/yolov5x.yaml +++ b/models/yolov5x.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/segment/predict.py b/segment/predict.py index 7ec63204dc..3a376a1680 100644 --- a/segment/predict.py +++ b/segment/predict.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Run segmentation inference on images, videos, directories, streams, etc. diff --git a/segment/train.py b/segment/train.py index a9786049e4..efb9a5de42 100644 --- a/segment/train.py +++ b/segment/train.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Train a segment model on a segment dataset Models and datasets download automatically from the latest release. diff --git a/segment/val.py b/segment/val.py index 0245652404..8759249341 100644 --- a/segment/val.py +++ b/segment/val.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Validate a trained segment model on a segment dataset diff --git a/train.py b/train.py index 3d5796e0c0..58a8182557 100644 --- a/train.py +++ b/train.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Train a YOLOv3 model on a custom dataset. Models and datasets download automatically from the latest YOLOv3 release. diff --git a/utils/__init__.py b/utils/__init__.py index 8e855a3874..77f9ff835b 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ utils/initialization """ diff --git a/utils/activations.py b/utils/activations.py index 0ae0515200..f4435ad6db 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Activation functions """ diff --git a/utils/augmentations.py b/utils/augmentations.py index 85e68d051b..f5e0cebf00 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Image augmentation functions """ diff --git a/utils/autoanchor.py b/utils/autoanchor.py index 6b11e53396..b7f902695d 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ AutoAnchor utils """ diff --git a/utils/autobatch.py b/utils/autobatch.py index de613ca126..71faf8783f 100644 --- a/utils/autobatch.py +++ b/utils/autobatch.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Auto-batch utils """ diff --git a/utils/callbacks.py b/utils/callbacks.py index 7715cf182d..b444a2ba39 100644 --- a/utils/callbacks.py +++ b/utils/callbacks.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Callback utils """ diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 2a038d1a7f..1d32d4ad61 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Dataloaders and dataset utils """ diff --git a/utils/docker/Dockerfile b/utils/docker/Dockerfile index 6607abfb79..6bc8eccf11 100644 --- a/utils/docker/Dockerfile +++ b/utils/docker/Dockerfile @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Builds ultralytics/yolov5:latest image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 # Image is CUDA-optimized for YOLOv5 single/multi-GPU training and inference diff --git a/utils/docker/Dockerfile-arm64 b/utils/docker/Dockerfile-arm64 index 31c2eaf86f..75a8c9bcca 100644 --- a/utils/docker/Dockerfile-arm64 +++ b/utils/docker/Dockerfile-arm64 @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Builds ultralytics/yolov5:latest-arm64 image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 # Image is aarch64-compatible for Apple M1 and other ARM architectures i.e. Jetson Nano and Raspberry Pi diff --git a/utils/docker/Dockerfile-cpu b/utils/docker/Dockerfile-cpu index 8e27bf61e6..c626ddc015 100644 --- a/utils/docker/Dockerfile-cpu +++ b/utils/docker/Dockerfile-cpu @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Builds ultralytics/yolov5:latest-cpu image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 # Image is CPU-optimized for ONNX, OpenVINO and PyTorch YOLOv5 deployments diff --git a/utils/downloads.py b/utils/downloads.py index cac99afaf9..e55c639929 100644 --- a/utils/downloads.py +++ b/utils/downloads.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Download utils """ diff --git a/utils/flask_rest_api/example_request.py b/utils/flask_rest_api/example_request.py index 5e6d0c1dfc..7dac472e88 100644 --- a/utils/flask_rest_api/example_request.py +++ b/utils/flask_rest_api/example_request.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Perform test request """ diff --git a/utils/flask_rest_api/restapi.py b/utils/flask_rest_api/restapi.py index 5d8f599669..c8ddc9a938 100644 --- a/utils/flask_rest_api/restapi.py +++ b/utils/flask_rest_api/restapi.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Run a Flask REST API exposing one or more YOLOv5s models """ diff --git a/utils/general.py b/utils/general.py index 56c94d58e5..40a0aa9371 100644 --- a/utils/general.py +++ b/utils/general.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ General utils """ diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index 82e4458aae..9cb86165ef 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Logging utils """ diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py index adb7840e4a..c714088283 100644 --- a/utils/loggers/wandb/wandb_utils.py +++ b/utils/loggers/wandb/wandb_utils.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # WARNING ⚠️ wandb is deprecated and will be removed in future release. # See supported integrations at https://github.com/ultralytics/yolov5#integrations diff --git a/utils/loss.py b/utils/loss.py index 1f38c36217..7fe6ae445b 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Loss functions """ diff --git a/utils/metrics.py b/utils/metrics.py index 5dab6130a0..56a15f45f7 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Model validation metrics """ diff --git a/utils/plots.py b/utils/plots.py index 64655a3f0e..770fca6237 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Plotting utils """ diff --git a/utils/segment/augmentations.py b/utils/segment/augmentations.py index 2897b7f4e2..085ef3a314 100644 --- a/utils/segment/augmentations.py +++ b/utils/segment/augmentations.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Image augmentation functions """ diff --git a/utils/segment/dataloaders.py b/utils/segment/dataloaders.py index d0f59562ed..c796ede565 100644 --- a/utils/segment/dataloaders.py +++ b/utils/segment/dataloaders.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Dataloaders """ diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py index 6c58dba610..d1de86e0d2 100644 --- a/utils/segment/metrics.py +++ b/utils/segment/metrics.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Model validation metrics """ diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 073d9bd01f..3aa764a8f6 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ PyTorch utils """ diff --git a/utils/triton.py b/utils/triton.py index 87f1fdcdee..c57ee676e6 100644 --- a/utils/triton.py +++ b/utils/triton.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Utils to interact with the Triton Inference Server """ diff --git a/val.py b/val.py index f44089fee2..17c0bc2e43 100644 --- a/val.py +++ b/val.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, GPL-3.0 license +# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ Validate a trained YOLOv3 detection model on a detection dataset From 843d31af579b83c6e1276aa8c1e3a4a177d4e377 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 14 Apr 2023 14:45:53 +0200 Subject: [PATCH 0951/1185] Update check_requirements() (#2040) * Update check_requirements.py * Update general.py --- utils/general.py | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/utils/general.py b/utils/general.py index 40a0aa9371..567f913ad4 100644 --- a/utils/general.py +++ b/utils/general.py @@ -380,10 +380,23 @@ def check_version(current='0.0.0', minimum='0.0.0', name='version ', pinned=Fals @TryExcept() -def check_requirements(requirements=ROOT / 'requirements.txt', exclude=(), install=True, cmds=''): - # Check installed dependencies meet YOLOv3 requirements (pass *.txt file or list of packages or single package str) +def check_requirements(requirements=ROOT.parent / 'requirements.txt', exclude=(), install=True, cmds=''): + """ + Check if installed dependencies meet YOLOv3 requirements and attempt to auto-update if needed. + + Args: + requirements (Union[Path, str, List[str]]): Path to a requirements.txt file, a single package requirement as a + string, or a list of package requirements as strings. + exclude (Tuple[str]): Tuple of package names to exclude from checking. + install (bool): If True, attempt to auto-update packages that don't meet requirements. + cmds (str): Additional commands to pass to the pip install command when auto-updating. + + Returns: + None + """ prefix = colorstr('red', 'bold', 'requirements:') check_python() # check python version + file = None if isinstance(requirements, Path): # requirements.txt file file = requirements.resolve() assert file.exists(), f'{prefix} {file} not found, check failed.' @@ -392,22 +405,25 @@ def check_requirements(requirements=ROOT / 'requirements.txt', exclude=(), insta elif isinstance(requirements, str): requirements = [requirements] - s = '' - n = 0 + s = '' # console string + n = 0 # number of packages updates for r in requirements: try: pkg.require(r) except (pkg.VersionConflict, pkg.DistributionNotFound): # exception if requirements not met - s += f'"{r}" ' - n += 1 + try: # attempt to import (slower but more accurate) + import importlib + importlib.import_module(next(pkg.parse_requirements(r)).name) + except ImportError: + s += f'"{r}" ' + n += 1 if s and install and AUTOINSTALL: # check environment variable LOGGER.info(f"{prefix} YOLOv3 requirement{'s' * (n > 1)} {s}not found, attempting AutoUpdate...") try: - # assert check_online(), "AutoUpdate skipped (offline)" - LOGGER.info(check_output(f'pip install {s} {cmds}', shell=True).decode()) - source = file if 'file' in locals() else requirements - s = f"{prefix} {n} package{'s' * (n > 1)} updated per {source}\n" \ + assert check_online(), 'AutoUpdate skipped (offline)' + LOGGER.info(subprocess.check_output(f'pip install {s} {cmds}', shell=True).decode()) + s = f"{prefix} {n} package{'s' * (n > 1)} updated per {file or requirements}\n" \ f"{prefix} ⚠️ {colorstr('bold', 'Restart runtime or rerun command for updates to take effect')}\n" LOGGER.info(s) except Exception as e: From 97b892644c57824430065846f05f32e09dcc7b07 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 21 Apr 2023 13:55:09 +0200 Subject: [PATCH 0952/1185] Docs update for new YOLOv3 URLs (#2041) * Update Docs * Update Docs * Update Docs * Update Docs * Update Docs * Update Docs * Update Docs * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/greetings.yml | 16 +++++++------- .github/workflows/links.yml | 38 +++++++++++++++++++++++++++++++++ .github/workflows/stale.yml | 33 +++++++++++++++++----------- README.md | 36 +++++++++++++++---------------- README.zh-CN.md | 38 ++++++++++++++++----------------- utils/loggers/comet/README.md | 2 +- 6 files changed, 104 insertions(+), 59 deletions(-) create mode 100644 .github/workflows/links.yml diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index b412eecc87..184be28680 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -18,16 +18,16 @@ jobs: pr-message: | 👋 Hello @${{ github.actor }}, thank you for submitting a YOLOv3 🚀 PR! To allow your work to be integrated as seamlessly as possible, we advise you to: - - ✅ Verify your PR is **up-to-date** with `ultralytics/yolov3` `master` branch. If your PR is behind you can update your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally. + - ✅ Verify your PR is **up-to-date** with `ultralytics/yolov5` `master` branch. If your PR is behind you can update your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally. - ✅ Verify all YOLOv3 Continuous Integration (CI) **checks are passing**. - ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ — Bruce Lee issue-message: | - 👋 Hello @${{ github.actor }}, thank you for your interest in YOLOv3 🚀! Please visit our ⭐️ [Tutorials](https://docs.ultralytics.com/yolov5/) to get started, where you can find quickstart guides for simple tasks like [Custom Data Training](https://docs.ultralytics.com/yolov5/train_custom_data/) all the way to advanced concepts like [Hyperparameter Evolution](https://docs.ultralytics.com/yolov5/hyp_evolution/). + 👋 Hello @${{ github.actor }}, thank you for your interest in YOLOv3 🚀! Please visit our ⭐️ [Tutorials](https://docs.ultralytics.com/yolov5/) to get started, where you can find quickstart guides for simple tasks like [Custom Data Training](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/) all the way to advanced concepts like [Hyperparameter Evolution](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution/). If this is a 🐛 Bug Report, please provide a **minimum reproducible example** to help us debug it. - If this is a custom training ❓ Question, please provide as much information as possible, including dataset image examples and training logs, and verify you are following our [Tips for Best Training Results](https://github.com/ultralytics/yolov5/wiki/Tips-for-Best-Training-Results). + If this is a custom training ❓ Question, please provide as much information as possible, including dataset image examples and training logs, and verify you are following our [Tips for Best Training Results](https://docs.ultralytics.com/yolov5/tutorials/tips_for_best_training_results/). ## Requirements @@ -43,15 +43,15 @@ jobs: YOLOv3 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): - **Notebooks** with free GPU: Run on Gradient Open In Colab Open In Kaggle - - **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/GCP-Quickstart) - - **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/AWS-Quickstart) - - **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/Docker-Quickstart) Docker Pulls + - **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/) + - **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/aws_quickstart_tutorial/) + - **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) Docker Pulls ## Status - YOLOv3 CI + YOLOv3 CI - If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 [training](https://github.com/ultralytics/yolov5/blob/master/train.py), [validation](https://github.com/ultralytics/yolov5/blob/master/val.py), [inference](https://github.com/ultralytics/yolov5/blob/master/detect.py), [export](https://github.com/ultralytics/yolov5/blob/master/export.py) and [benchmarks](https://github.com/ultralytics/yolov5/blob/master/benchmarks.py) on MacOS, Windows, and Ubuntu every 24 hours and on every commit. + If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov5/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 [training](https://github.com/ultralytics/yolov5/blob/master/train.py), [validation](https://github.com/ultralytics/yolov5/blob/master/val.py), [inference](https://github.com/ultralytics/yolov5/blob/master/detect.py), [export](https://github.com/ultralytics/yolov5/blob/master/export.py) and [benchmarks](https://github.com/ultralytics/yolov5/blob/master/benchmarks.py) on macOS, Windows, and Ubuntu every 24 hours and on every commit. ## Introducing YOLOv8 🚀 diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml new file mode 100644 index 0000000000..b3e82df349 --- /dev/null +++ b/.github/workflows/links.yml @@ -0,0 +1,38 @@ +# Ultralytics YOLO 🚀, AGPL-3.0 license +# YOLO Continuous Integration (CI) GitHub Actions tests + +name: Check Broken links + +on: + push: + branches: [master] + pull_request: + branches: [master] + workflow_dispatch: + schedule: + - cron: '0 0 * * *' # runs at 00:00 UTC every day + +jobs: + Links: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Test Markdown and HTML links + uses: lycheeverse/lychee-action@v1.6.1 + with: + fail: true + # accept 429(Instagram, 'too many requests'), 999(LinkedIn, 'unknown status code'), Timeout(Twitter) + args: --accept 429,999 --exclude-loopback --exclude twitter.com --exclude-mail './**/*.md' './**/*.html' + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + + - name: Test Markdown, HTML, YAML, Python and Notebook links + if: github.event_name == 'workflow_dispatch' + uses: lycheeverse/lychee-action@v1.6.1 + with: + fail: true + # accept 429(Instagram, 'too many requests'), 999(LinkedIn, 'unknown status code'), Timeout(Twitter) + args: --accept 429,999 --exclude-loopback --exclude twitter.com,url.com --exclude-mail './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index c020ed0cd1..8a9871ae67 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -12,26 +12,33 @@ jobs: - uses: actions/stale@v8 with: repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: | - 👋 Hello, this issue has been automatically marked as stale because it has not had recent activity. Please note it will be closed if no further activity occurs. + 👋 Hello there! We wanted to give you a friendly reminder that this issue has not had any recent activity and may be closed soon, but don't worry - you can always reopen it if needed. If you still have any questions or concerns, please feel free to let us know how we can help. - Access additional [YOLOv3](https://ultralytics.com/yolov5) 🚀 resources: - - **Wiki** – https://github.com/ultralytics/yolov5/wiki - - **Tutorials** – https://github.com/ultralytics/yolov5#tutorials - - **Docs** – https://docs.ultralytics.com + For additional resources and information, please see the links below: - Access additional [Ultralytics](https://ultralytics.com) ⚡ resources: - - **Ultralytics HUB** – https://ultralytics.com/hub - - **Vision API** – https://ultralytics.com/yolov5 - - **About Us** – https://ultralytics.com/about - - **Join Our Team** – https://ultralytics.com/work - - **Contact Us** – https://ultralytics.com/contact + - **Docs**: https://docs.ultralytics.com + - **HUB**: https://hub.ultralytics.com + - **Community**: https://community.ultralytics.com Feel free to inform us of any other **issues** you discover or **feature requests** that come to mind in the future. Pull Requests (PRs) are also always welcomed! - Thank you for your contributions to YOLOv3 🚀 and Vision AI ⭐! + Thank you for your contributions to YOLO 🚀 and Vision AI ⭐ + + stale-pr-message: | + 👋 Hello there! We wanted to let you know that we've decided to close this pull request due to inactivity. We appreciate the effort you put into contributing to our project, but unfortunately, not all contributions are suitable or aligned with our product roadmap. + + We hope you understand our decision, and please don't let it discourage you from contributing to open source projects in the future. We value all of our community members and their contributions, and we encourage you to keep exploring new projects and ways to get involved. + + For additional resources and information, please see the links below: + + - **Docs**: https://docs.ultralytics.com + - **HUB**: https://hub.ultralytics.com + - **Community**: https://community.ultralytics.com + + Thank you for your contributions to YOLO 🚀 and Vision AI ⭐ - stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions YOLOv3 🚀 and Vision AI ⭐.' days-before-issue-stale: 30 days-before-issue-close: 10 days-before-pr-stale: 90 diff --git a/README.md b/README.md index 65fbb486b7..e11eca94f5 100644 --- a/README.md +++ b/README.md @@ -152,22 +152,22 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
Tutorials -- [Train Custom Data](https://docs.ultralytics.com/yolov5/train_custom_data) 🚀 RECOMMENDED -- [Tips for Best Training Results](https://docs.ultralytics.com/yolov5/tips_for_best_training_results) ☘️ RECOMMENDED -- [Multi-GPU Training](https://docs.ultralytics.com/yolov5/multi_gpu_training) -- [PyTorch Hub](https://docs.ultralytics.com/yolov5/pytorch_hub) 🌟 NEW -- [TFLite, ONNX, CoreML, TensorRT Export](https://docs.ultralytics.com/yolov5/export) 🚀 -- [NVIDIA Jetson platform Deployment](https://docs.ultralytics.com/yolov5/jetson_nano) 🌟 NEW -- [Test-Time Augmentation (TTA)](https://docs.ultralytics.com/yolov5/tta) -- [Model Ensembling](https://docs.ultralytics.com/yolov5/ensemble) -- [Model Pruning/Sparsity](https://docs.ultralytics.com/yolov5/pruning_sparsity) -- [Hyperparameter Evolution](https://docs.ultralytics.com/yolov5/hyp_evolution) -- [Transfer Learning with Frozen Layers](https://docs.ultralytics.com/yolov5/transfer_learn_frozen) -- [Architecture Summary](https://docs.ultralytics.com/yolov5/architecture) 🌟 NEW -- [Roboflow for Datasets](https://docs.ultralytics.com/yolov5/roboflow) -- [ClearML Logging](https://docs.ultralytics.com/yolov5/clearml) 🌟 NEW -- [YOLOv3 with Neural Magic's Deepsparse](https://docs.ultralytics.com/yolov5/neural_magic) 🌟 NEW -- [Comet Logging](https://docs.ultralytics.com/yolov5/comet) 🌟 NEW +- [Train Custom Data](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data) 🚀 RECOMMENDED +- [Tips for Best Training Results](https://docs.ultralytics.com/yolov5/tutorials/tips_for_best_training_results) ☘️ +- [Multi-GPU Training](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) +- [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) 🌟 NEW +- [TFLite, ONNX, CoreML, TensorRT Export](https://docs.ultralytics.com/yolov5/tutorials/model_export) 🚀 +- [NVIDIA Jetson platform Deployment](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano) 🌟 NEW +- [Test-Time Augmentation (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation) +- [Model Ensembling](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling) +- [Model Pruning/Sparsity](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity) +- [Hyperparameter Evolution](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution) +- [Transfer Learning with Frozen Layers](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers) +- [Architecture Summary](https://docs.ultralytics.com/yolov5/tutorials/architecture_description) 🌟 NEW +- [Roboflow for Datasets, Labeling, and Active Learning](https://docs.ultralytics.com/yolov5/tutorials/roboflow_datasets_integration) +- [ClearML Logging](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration) 🌟 NEW +- [YOLOv5 with Neural Magic's Deepsparse](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization) 🌟 NEW +- [Comet Logging](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration) 🌟 NEW
@@ -435,10 +435,10 @@ Get started in seconds with our verified environments. Click each icon below for - + - + diff --git a/README.zh-CN.md b/README.zh-CN.md index fbc194e1e9..70aa9ec23f 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -148,22 +148,22 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
教程 -- [训练自定义数据](https://docs.ultralytics.com/yolov5/train_custom_data) 🚀 推荐 -- [获得最佳训练结果的技巧](https://docs.ultralytics.com/yolov5/tips_for_best_training_results) ☘️ 推荐 -- [多 GPU 训练](https://docs.ultralytics.com/yolov5/multi_gpu_training) -- [PyTorch Hub](https://docs.ultralytics.com/yolov5/pytorch_hub) 🌟 新 -- [TFLite, ONNX, CoreML, TensorRT 导出](https://docs.ultralytics.com/yolov5/export) 🚀 -- [NVIDIA Jetson 平台部署](https://docs.ultralytics.com/yolov5/jetson_nano) 🌟 新 -- [测试时增强(TTA)](https://docs.ultralytics.com/yolov5/tta) -- [模型集成](https://docs.ultralytics.com/yolov5/ensemble) -- [模型剪枝/稀疏性](https://docs.ultralytics.com/yolov5/pruning_sparsity) -- [超参数进化](https://docs.ultralytics.com/yolov5/hyp_evolution) -- [冻结层的迁移学习](https://docs.ultralytics.com/yolov5/transfer_learn_frozen) -- [架构概述](https://docs.ultralytics.com/yolov5/architecture) 🌟 新 -- [Roboflow](https://docs.ultralytics.com/yolov5/roboflow) -- [ClearML 日志记录](https://docs.ultralytics.com/yolov5/clearml) 🌟 新 -- [YOLOv5 与 Neural Magic 的 Deepsparse](https://docs.ultralytics.com/yolov5/neural_magic) 🌟 新 -- [Comet 日志记录](https://docs.ultralytics.com/yolov5/comet) 🌟 新 +- [训练自定义数据](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data) 🚀 推荐 +- [获得最佳训练结果的技巧](https://docs.ultralytics.com/yolov5/tutorials/tips_for_best_training_results) ☘️ +- [多GPU训练](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) +- [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) 🌟 新 +- [TFLite,ONNX,CoreML,TensorRT导出](https://docs.ultralytics.com/yolov5/tutorials/model_export) 🚀 +- [NVIDIA Jetson平台部署](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano) 🌟 新 +- [测试时增强 (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation) +- [模型集成](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling) +- [模型剪枝/稀疏](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity) +- [超参数进化](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution) +- [冻结层的迁移学习](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers) +- [架构概述](https://docs.ultralytics.com/yolov5/tutorials/architecture_description) 🌟 新 +- [Roboflow用于数据集、标注和主动学习](https://docs.ultralytics.com/yolov5/tutorials/roboflow_datasets_integration) +- [ClearML日志记录](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration) 🌟 新 +- [使用Neural Magic的Deepsparse的YOLOv5](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization) 🌟 新 +- [Comet日志记录](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration) 🌟 新
@@ -432,10 +432,10 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu - + - + @@ -457,7 +457,7 @@ YOLOv3 在两种不同的 License 下可用: ##
联系我们
-请访问 [GitHub Issues](https://github.com/ultralytics/yolov5/issues) 或 [Ultralytics Community Forum](https://community.ultralytis.com) 以报告 YOLOv3 错误和请求功能。 +请访问 [GitHub Issues](https://github.com/ultralytics/yolov5/issues) 或 [Ultralytics Community Forum](https://community.ultralytics.com) 以报告 YOLOv3 错误和请求功能。
diff --git a/utils/loggers/comet/README.md b/utils/loggers/comet/README.md index 4090cf938a..6e918db803 100644 --- a/utils/loggers/comet/README.md +++ b/utils/loggers/comet/README.md @@ -180,7 +180,7 @@ using [Comet Artifacts](https://www.comet.com/docs/v2/guides/data-management/usi you can do so using the `upload_dataset` flag. The dataset be organized in the way described in -the [YOLOv5 documentation](https://docs.ultralytics.com/tutorials/train-custom-datasets/#3-organize-directories). The +the [YOLOv5 documentation](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/). The dataset config `yaml` file must follow the same format as that of the `coco128.yaml` file. ```shell From f1260cb94d7a3f37c776b023ce26f481b24b09df Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 21 Apr 2023 22:11:42 +0200 Subject: [PATCH 0953/1185] Update greetings.yml (#2042) --- .github/workflows/greetings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 184be28680..c996efc3a8 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -44,7 +44,7 @@ jobs: - **Notebooks** with free GPU: Run on Gradient Open In Colab Open In Kaggle - **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/) - - **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/aws_quickstart_tutorial/) + - **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/) - **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) Docker Pulls ## Status From 95325d8b1dc7a9c319884908acd5eb85bf2d26d5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 21 Apr 2023 23:41:50 +0200 Subject: [PATCH 0954/1185] Update links to https://docs.ultralytics.com (#2043) * Update links to Docs * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- README.md | 8 ++++---- README.zh-CN.md | 8 ++++---- classify/tutorial.ipynb | 10 +++++----- hubconf.py | 2 +- segment/train.py | 8 +++++--- segment/tutorial.ipynb | 10 +++++----- train.py | 8 +++++--- tutorial.ipynb | 10 +++++----- utils/dataloaders.py | 2 +- utils/loggers/__init__.py | 2 +- 10 files changed, 36 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index e11eca94f5..c45afe2a54 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ pip install -r requirements.txt # install
Inference -YOLOv3 [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36) inference. [Models](https://github.com/ultralytics/yolov5/tree/master/models) download automatically from the latest +YOLOv3 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) inference. [Models](https://github.com/ultralytics/yolov5/tree/master/models) download automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). ```python @@ -133,7 +133,7 @@ The commands below reproduce YOLOv3 [COCO](https://github.com/ultralytics/yolov5 results. [Models](https://github.com/ultralytics/yolov5/tree/master/models) and [datasets](https://github.com/ultralytics/yolov5/tree/master/data) download automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). Training times for YOLOv5n/s/m/l/x are -1/2/4/6/8 days on a V100 GPU ([Multi-GPU](https://github.com/ultralytics/yolov5/issues/475) times faster). Use the +1/2/4/6/8 days on a V100 GPU ([Multi-GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) times faster). Use the largest `--batch-size` possible, or pass `--batch-size -1` for YOLOv3 [AutoBatch](https://github.com/ultralytics/yolov5/pull/5092). Batch sizes shown for V100-16GB. @@ -246,7 +246,7 @@ YOLOv3 has been designed to be super easy to get started and simple to learn. We - All checkpoints are trained to 300 epochs with default settings. Nano and Small models use [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) hyps, all others use [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml). - **mAPval** values are for single-model single-scale on [COCO val2017](http://cocodataset.org) dataset.
Reproduce by `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` - **Speed** averaged over COCO val images using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) instance. NMS times (~1 ms/img) not included.
Reproduce by `python val.py --data coco.yaml --img 640 --task speed --batch 1` -- **TTA** [Test Time Augmentation](https://github.com/ultralytics/yolov5/issues/303) includes reflection and scale augmentations.
Reproduce by `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment` +- **TTA** [Test Time Augmentation](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation) includes reflection and scale augmentations.
Reproduce by `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment`
@@ -483,4 +483,4 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/
-[tta]: https://github.com/ultralytics/yolov5/issues/303 +[tta]: https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation diff --git a/README.zh-CN.md b/README.zh-CN.md index 70aa9ec23f..20e0135adb 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -81,7 +81,7 @@ pip install -r requirements.txt # install
推理 -使用 YOLOv3 [PyTorch Hub](https://github.com/ultralytics/yolov5/issues/36) 推理。最新 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 将自动的从 +使用 YOLOv3 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) 推理。最新 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 ```python @@ -129,7 +129,7 @@ python detect.py --weights yolov5s.pt --source 0 # 下面的命令重现 YOLOv3 在 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) 数据集上的结果。 最新的 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 和 [数据集](https://github.com/ultralytics/yolov5/tree/master/data) 将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 -YOLOv5n/s/m/l/x 在 V100 GPU 的训练时间为 1/2/4/6/8 天( [多GPU](https://github.com/ultralytics/yolov5/issues/475) 训练速度更快)。 +YOLOv5n/s/m/l/x 在 V100 GPU 的训练时间为 1/2/4/6/8 天( [多GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) 训练速度更快)。 尽可能使用更大的 `--batch-size` ,或通过 `--batch-size -1` 实现 YOLOv3 [自动批处理](https://github.com/ultralytics/yolov5/pull/5092) 。下方显示的 batchsize 适用于 V100-16GB。 @@ -242,7 +242,7 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结 - 所有模型都使用默认配置,训练 300 epochs。n和s模型使用 [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) ,其他模型都使用 [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml) 。 - \*\*mAPval\*\*在单模型单尺度上计算,数据集使用 [COCO val2017](http://cocodataset.org) 。
复现命令 `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` - **推理速度**在 COCO val 图像总体时间上进行平均得到,测试环境使用[AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/)实例。 NMS 时间 (大约 1 ms/img) 不包括在内。
复现命令 `python val.py --data coco.yaml --img 640 --task speed --batch 1` -- **TTA** [测试时数据增强](https://github.com/ultralytics/yolov5/issues/303) 包括反射和尺度变换。
复现命令 `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment` +- **TTA** [测试时数据增强](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation) 包括反射和尺度变换。
复现命令 `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment`
@@ -480,4 +480,4 @@ YOLOv3 在两种不同的 License 下可用: -[tta]: https://github.com/ultralytics/yolov5/issues/303 +[tta]: https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation diff --git a/classify/tutorial.ipynb b/classify/tutorial.ipynb index 73c0ea303b..42ef67b450 100644 --- a/classify/tutorial.ipynb +++ b/classify/tutorial.ipynb @@ -1350,7 +1350,7 @@ "export COMET_API_KEY= # 2. paste API key\n", "python train.py --img 640 --epochs 3 --data coco128.yaml --weights yolov5s.pt # 3. train\n", "```\n", - "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/comet). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", + "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing)\n", "\n", "\n", @@ -1372,7 +1372,7 @@ "\n", "You'll get all the great expected features from an experiment manager: live updates, model upload, experiment comparison etc. but ClearML also tracks uncommitted changes and installed packages for example. Thanks to that ClearML Tasks (which is what we call experiments) are also reproducible on different machines! With only 1 extra line, we can schedule a YOLOv5 training task on a queue to be executed by any number of ClearML Agents (workers).\n", "\n", - "You can use ClearML Data to version your dataset and then pass it to YOLOv5 simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml) for details!\n", + "You can use ClearML Data to version your dataset and then pass it to YOLOv5 simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration) for details!\n", "\n", "\n", "\"ClearML" @@ -1404,9 +1404,9 @@ "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):\n", "\n", "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", - "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/GCP-Quickstart)\n", - "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/AWS-Quickstart)\n", - "- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/Docker-Quickstart) \"Docker\n" + "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)\n", + "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)\n", + "- **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) \"Docker\n" ] }, { diff --git a/hubconf.py b/hubconf.py index 0515dae648..7b87835bb6 100644 --- a/hubconf.py +++ b/hubconf.py @@ -73,7 +73,7 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbo return model.to(device) except Exception as e: - help_url = 'https://github.com/ultralytics/yolov5/issues/36' + help_url = 'https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading' s = f'{e}. Cache may be out of date, try `force_reload=True` or see {help_url} for help.' raise Exception(s) from e diff --git a/segment/train.py b/segment/train.py index efb9a5de42..4113eb6112 100644 --- a/segment/train.py +++ b/segment/train.py @@ -12,7 +12,7 @@ Models: https://github.com/ultralytics/yolov5/tree/master/models Datasets: https://github.com/ultralytics/yolov5/tree/master/data -Tutorial: https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data +Tutorial: https://docs.ultralytics.com/yolov5/tutorials/train_custom_data """ import argparse @@ -166,8 +166,10 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # DP mode if cuda and RANK == -1 and torch.cuda.device_count() > 1: - LOGGER.warning('WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n' - 'See Multi-GPU Tutorial at https://github.com/ultralytics/yolov5/issues/475 to get started.') + LOGGER.warning( + 'WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n' + 'See Multi-GPU Tutorial at https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training to get started.' + ) model = torch.nn.DataParallel(model) # SyncBatchNorm diff --git a/segment/tutorial.ipynb b/segment/tutorial.ipynb index dc12b23a30..7a641c718e 100644 --- a/segment/tutorial.ipynb +++ b/segment/tutorial.ipynb @@ -463,7 +463,7 @@ "export COMET_API_KEY= # 2. paste API key\n", "python train.py --img 640 --epochs 3 --data coco128.yaml --weights yolov5s.pt # 3. train\n", "```\n", - "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/comet). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", + "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing)\n", "\n", "\n", @@ -485,7 +485,7 @@ "\n", "You'll get all the great expected features from an experiment manager: live updates, model upload, experiment comparison etc. but ClearML also tracks uncommitted changes and installed packages for example. Thanks to that ClearML Tasks (which is what we call experiments) are also reproducible on different machines! With only 1 extra line, we can schedule a YOLOv5 training task on a queue to be executed by any number of ClearML Agents (workers).\n", "\n", - "You can use ClearML Data to version your dataset and then pass it to YOLOv5 simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml) for details!\n", + "You can use ClearML Data to version your dataset and then pass it to YOLOv5 simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration) for details!\n", "\n", "\n", "\"ClearML" @@ -517,9 +517,9 @@ "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):\n", "\n", "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", - "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/GCP-Quickstart)\n", - "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/AWS-Quickstart)\n", - "- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/Docker-Quickstart) \"Docker\n" + "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)\n", + "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)\n", + "- **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) \"Docker\n" ] }, { diff --git a/train.py b/train.py index 58a8182557..65c8cd3ef6 100644 --- a/train.py +++ b/train.py @@ -12,7 +12,7 @@ Models: https://github.com/ultralytics/yolov5/tree/master/models Datasets: https://github.com/ultralytics/yolov5/tree/master/data -Tutorial: https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data +Tutorial: https://docs.ultralytics.com/yolov5/tutorials/train_custom_data """ import argparse @@ -174,8 +174,10 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # DP mode if cuda and RANK == -1 and torch.cuda.device_count() > 1: - LOGGER.warning('WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n' - 'See Multi-GPU Tutorial at https://github.com/ultralytics/yolov5/issues/475 to get started.') + LOGGER.warning( + 'WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n' + 'See Multi-GPU Tutorial at https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training to get started.' + ) model = torch.nn.DataParallel(model) # SyncBatchNorm diff --git a/tutorial.ipynb b/tutorial.ipynb index 5828c40dde..a5aa2d23ba 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -869,7 +869,7 @@ "export COMET_API_KEY= # 2. paste API key\n", "python train.py --img 640 --epochs 3 --data coco128.yaml --weights yolov5s.pt # 3. train\n", "```\n", - "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/comet). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", + "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing)\n", "\n", "\n", @@ -891,7 +891,7 @@ "\n", "You'll get all the great expected features from an experiment manager: live updates, model upload, experiment comparison etc. but ClearML also tracks uncommitted changes and installed packages for example. Thanks to that ClearML Tasks (which is what we call experiments) are also reproducible on different machines! With only 1 extra line, we can schedule a training task on a queue to be executed by any number of ClearML Agents (workers).\n", "\n", - "You can use ClearML Data to version your dataset and then pass it to simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml) for details!\n", + "You can use ClearML Data to version your dataset and then pass it to simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration) for details!\n", "\n", "\n", "\"ClearML" @@ -926,9 +926,9 @@ " 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):\n", "\n", "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", - "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/GCP-Quickstart)\n", - "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/AWS-Quickstart)\n", - "- **Docker Image**. See [Docker Quickstart Guide](https://github.com/ultralytics/yolov5/wiki/Docker-Quickstart) \"Docker\n" + "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)\n", + "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)\n", + "- **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) \"Docker\n" ] }, { diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 1d32d4ad61..348e4ce424 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -36,7 +36,7 @@ from utils.torch_utils import torch_distributed_zero_first # Parameters -HELP_URL = 'See https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data' +HELP_URL = 'See https://docs.ultralytics.com/yolov5/tutorials/train_custom_data' IMG_FORMATS = 'bmp', 'dng', 'jpeg', 'jpg', 'mpo', 'png', 'tif', 'tiff', 'webp', 'pfm' # include image suffixes VID_FORMATS = 'asf', 'avi', 'gif', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'ts', 'wmv' # include video suffixes LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index 9cb86165ef..6e6b41ccf1 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -114,7 +114,7 @@ def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, self.clearml = None prefix = colorstr('ClearML: ') LOGGER.warning(f'{prefix}WARNING ⚠️ ClearML is installed but not configured, skipping ClearML logging.' - f' See https://github.com/ultralytics/yolov5/tree/master/utils/loggers/clearml#readme') + f' See https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration#readme') else: self.clearml = None From 22f0d3ea5ce6d77984ebcc8fdc1a9a0c526eca96 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 23 Apr 2023 18:38:00 +0200 Subject: [PATCH 0955/1185] Add Slack notification of CI errors (#2044) * Update links.yml * Update * Update * Update --- .github/workflows/ci-testing.yml | 8 ++++++++ .github/workflows/links.yml | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 06597e89b7..521a417e84 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -117,3 +117,11 @@ jobs: for path in '$m', '$b': model = torch.hub.load('.', 'custom', path=path, source='local') EOF + - name: Notify on failure + if: failure() && github.repository == 'ultralytics/yolov3' && (github.event_name == 'schedule' || github.event_name == 'push') + uses: slackapi/slack-github-action@v1.23.0 + with: + payload: | + {"text": " GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n*Job Status:* ${{ job.status }}\n"} + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }} diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index b3e82df349..f640372016 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -23,7 +23,7 @@ jobs: with: fail: true # accept 429(Instagram, 'too many requests'), 999(LinkedIn, 'unknown status code'), Timeout(Twitter) - args: --accept 429,999 --exclude-loopback --exclude twitter.com --exclude-mail './**/*.md' './**/*.html' + args: --accept 429,999 --exclude-loopback --exclude twitter.com --exclude-path '**/ci-testing.yaml' --exclude-mail './**/*.md' './**/*.html' env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} @@ -33,6 +33,6 @@ jobs: with: fail: true # accept 429(Instagram, 'too many requests'), 999(LinkedIn, 'unknown status code'), Timeout(Twitter) - args: --accept 429,999 --exclude-loopback --exclude twitter.com,url.com --exclude-mail './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' + args: --accept 429,999 --exclude-loopback --exclude twitter.com,url.com --exclude-path '**/ci-testing.yaml' --exclude-mail './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} From f28872894628bf84ae6b9fb43d6a79bddb50c41d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 17:14:42 +0200 Subject: [PATCH 0956/1185] Bump lycheeverse/lychee-action from 1.6.1 to 1.7.0 (#2045) Bumps [lycheeverse/lychee-action](https://github.com/lycheeverse/lychee-action) from 1.6.1 to 1.7.0. - [Release notes](https://github.com/lycheeverse/lychee-action/releases) - [Commits](https://github.com/lycheeverse/lychee-action/compare/v1.6.1...v1.7.0) --- updated-dependencies: - dependency-name: lycheeverse/lychee-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/links.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index f640372016..a541331803 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@v3 - name: Test Markdown and HTML links - uses: lycheeverse/lychee-action@v1.6.1 + uses: lycheeverse/lychee-action@v1.7.0 with: fail: true # accept 429(Instagram, 'too many requests'), 999(LinkedIn, 'unknown status code'), Timeout(Twitter) @@ -29,7 +29,7 @@ jobs: - name: Test Markdown, HTML, YAML, Python and Notebook links if: github.event_name == 'workflow_dispatch' - uses: lycheeverse/lychee-action@v1.6.1 + uses: lycheeverse/lychee-action@v1.7.0 with: fail: true # accept 429(Instagram, 'too many requests'), 999(LinkedIn, 'unknown status code'), Timeout(Twitter) From 83bedce03dc0effa4f23df4a29f235c20f23cfa1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 29 Apr 2023 13:51:08 +0200 Subject: [PATCH 0957/1185] Improve Slack notification (#2046) * Update * Update * Update * Update * Update --- .github/workflows/ci-testing.yml | 12 +++++++++--- .github/workflows/codeql-analysis.yml | 1 + .github/workflows/docker.yml | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 521a417e84..d9c7e8db33 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -117,11 +117,17 @@ jobs: for path in '$m', '$b': model = torch.hub.load('.', 'custom', path=path, source='local') EOF - - name: Notify on failure - if: failure() && github.repository == 'ultralytics/yolov3' && (github.event_name == 'schedule' || github.event_name == 'push') + + Summary: + runs-on: ubuntu-latest + needs: [Tests] # Add job names that you want to check for failure + if: always() # This ensures the job runs even if previous jobs fail + steps: + - name: Check for failure and notify + if: ${{ needs.Tests.result == 'failure' }} # Check if any of the jobs failed uses: slackapi/slack-github-action@v1.23.0 with: payload: | - {"text": " GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n*Job Status:* ${{ job.status }}\n"} + {"text": " GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n"} env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b6f751096d..05db12dabd 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -6,6 +6,7 @@ name: "CodeQL" on: schedule: - cron: '0 0 1 * *' # Runs at 00:00 UTC on the 1st of every month + workflow_dispatch: jobs: analyze: diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index db9a4cc9e1..e7db8a5554 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -6,6 +6,7 @@ name: Publish Docker Images on: push: branches: [none] # use DockerHub AutoBuild + workflow_dispatch: jobs: docker: From 0abfd9437e30d61a7a0f9600f234aa9a939e2540 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 29 Apr 2023 17:50:17 +0200 Subject: [PATCH 0958/1185] Add Discord links (#2047) * Add Discord links * Add Discord links * Add Discord links * Update README.md --- README.md | 12 ++++++++++-- README.zh-CN.md | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c45afe2a54..060e3da91b 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,9 @@ YOLOv3 🚀 is the world's most loved vision AI, representing Ultralytics open-source research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours of research and development. -To request an Enterprise License please complete the form at Ultralytics Licensing. +We hope that the resources here will help you get the most out of YOLOv3. Please browse the YOLOv3 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions! + +To request an Enterprise License please complete the form at [Ultralytics Licensing](https://ultralytics.com/license).
@@ -460,7 +465,7 @@ YOLOv3 is available under two different licenses: ##
Contact
-For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov5/issues) or the [Ultralytics Community Forum](https://community.ultralytics.com/). +For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues), and join our [Discord](https://discord.gg/n6cFeSPZdD) community for questions and discussions!
@@ -481,6 +486,9 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/ + + +
[tta]: https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation diff --git a/README.zh-CN.md b/README.zh-CN.md index 20e0135adb..b650e75de2 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -19,7 +19,9 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics 对未来视觉 AI 方法的开源研究,结合在数千小时的研究和开发中积累的经验教训和最佳实践。 -如果要申请企业许可证,请填写表格Ultralytics 许可. +我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 YOLOv3 文档 了解详细信息,在 GitHub 上提交问题以获得支持,并加入我们的 Discord 社区进行问题和讨论! + +如需申请企业许可,请在 [Ultralytics Licensing](https://ultralytics.com/license) 处填写表格
@@ -40,6 +42,9 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 + + +
@@ -457,7 +462,7 @@ YOLOv3 在两种不同的 License 下可用: ##
联系我们
-请访问 [GitHub Issues](https://github.com/ultralytics/yolov5/issues) 或 [Ultralytics Community Forum](https://community.ultralytics.com) 以报告 YOLOv3 错误和请求功能。 +对于 YOLOv8 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://discord.gg/n6cFeSPZdD) 社区进行问题和讨论!
@@ -478,6 +483,9 @@ YOLOv3 在两种不同的 License 下可用: + + +
[tta]: https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation From 7a6304311ca712bd04d65867cb4cd55640d755af Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 29 Apr 2023 20:46:27 +0200 Subject: [PATCH 0959/1185] Contribute at https://docs.ultralytics.com/help/contributing (#2048) Contribute link https://docs.ultralytics.com/help/contributing --- .github/ISSUE_TEMPLATE/bug-report.yml | 2 +- .github/ISSUE_TEMPLATE/feature-request.yml | 2 +- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index affe6aae2b..569ee93be1 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -80,6 +80,6 @@ body: label: Are you willing to submit a PR? description: > (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. - See the YOLOv3 [Contributing Guide](https://github.com/ultralytics/yolov3/blob/master/CONTRIBUTING.md) to get started. + See the YOLOv3 [Contributing Guide](https://docs.ultralytics.com/help/contributing) to get started. options: - label: Yes I'd like to help by submitting a PR! diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index 53cf234475..3cc2a96bcd 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -45,6 +45,6 @@ body: label: Are you willing to submit a PR? description: > (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. - See the YOLOv3 [Contributing Guide](https://github.com/ultralytics/yolov3/blob/master/CONTRIBUTING.md) to get started. + See the YOLOv3 [Contributing Guide](https://docs.ultralytics.com/help/contributing) to get started. options: - label: Yes I'd like to help by submitting a PR! diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 51f9803a57..d96d5afd28 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,7 +5,7 @@ Thank you for submitting a YOLOv5 🚀 Pull Request! We want to make contributin - Link this PR to a YOLOv5 [issue](https://github.com/ultralytics/yolov5/issues) to help us understand what bug fix or feature is being implemented. - Provide before and after profiling/inference/training results to help us quantify the improvement your PR provides (if applicable). -Please see our ✅ [Contributing Guide](https://github.com/ultralytics/yolov5/blob/master/CONTRIBUTING.md) for more details. +Please see our ✅ [Contributing Guide](https://docs.ultralytics.com/help/contributing) for more details. Note that Copilot will summarize this PR below, do not modify the 'copilot:all' line. --> From 44f08190976f81a01f3ab56c5351b84300c0d4a3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 29 Apr 2023 20:50:39 +0200 Subject: [PATCH 0960/1185] Add https://docs.ultralytics.com/help/contributing (#2049) Contribute link https://docs.ultralytics.com/help/contributing --- README.md | 2 +- README.zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 060e3da91b..e7c41131fc 100644 --- a/README.md +++ b/README.md @@ -449,7 +449,7 @@ Get started in seconds with our verified environments. Click each icon below for ##
Contribute
-We love your input! We want to make contributing to YOLOv3 as easy and transparent as possible. Please see our [Contributing Guide](CONTRIBUTING.md) to get started, and fill out the [YOLOv3 Survey](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to send us feedback on your experiences. Thank you to all our contributors! +We love your input! We want to make contributing to YOLOv3 as easy and transparent as possible. Please see our [Contributing Guide](https://docs.ultralytics.com/help/contributing/) to get started, and fill out the [YOLOv3 Survey](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to send us feedback on your experiences. Thank you to all our contributors! diff --git a/README.zh-CN.md b/README.zh-CN.md index b650e75de2..b9e88d2b64 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -446,7 +446,7 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu ##
贡献
-我们喜欢您的意见或建议!我们希望尽可能简单和透明地为 YOLOv3 做出贡献。请看我们的 [投稿指南](CONTRIBUTING.md),并填写 [YOLOv5调查](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) 向我们发送您的体验反馈。感谢我们所有的贡献者! +我们喜欢您的意见或建议!我们希望尽可能简单和透明地为 YOLOv3 做出贡献。请看我们的 [投稿指南](https://docs.ultralytics.com/help/contributing/),并填写 [YOLOv5调查](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) 向我们发送您的体验反馈。感谢我们所有的贡献者! From a8b2e9f50252d01837a27e9be08eee0935ea620e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 1 May 2023 10:43:54 +0200 Subject: [PATCH 0961/1185] Add links to https://docs.ultralytics.com/help/ (#2051) Contribute link https://docs.ultralytics.com/help/ --- .github/ISSUE_TEMPLATE/bug-report.yml | 2 +- CONTRIBUTING.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 569ee93be1..f74a3b871d 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -62,7 +62,7 @@ body: label: Minimal Reproducible Example description: > When asking a question, people will be better able to provide help if you provide code that they can easily understand and use to **reproduce** the problem. - This is referred to by community members as creating a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). + This is referred to by community members as creating a [minimal reproducible example](https://docs.ultralytics.com/help/minimum_reproducible_example/). placeholder: | ``` # Code to reproduce your issue here diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 68db594f51..16b1ecef09 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -66,7 +66,7 @@ short guidelines below to help users provide what we need to get started. When asking a question, people will be better able to provide help if you provide **code** that they can easily understand and use to **reproduce** the problem. This is referred to by community members as creating -a [minimum reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). Your code that reproduces +a [minimum reproducible example](https://docs.ultralytics.com/help/minimum_reproducible_example/). Your code that reproduces the problem should be: - ✅ **Minimal** – Use as little code as possible that still produces the same problem @@ -84,7 +84,7 @@ should be: If you believe your problem meets all of the above criteria, please close this issue and raise a new one using the 🐛 **Bug Report** [template](https://github.com/ultralytics/yolov5/issues/new/choose) and provide -a [minimum reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) to help us better +a [minimum reproducible example](https://docs.ultralytics.com/help/minimum_reproducible_example/) to help us better understand and diagnose your problem. ## License From c8a6fa327452face69742aaddc2cb1eb658a7237 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 1 May 2023 12:07:38 +0200 Subject: [PATCH 0962/1185] Update links.yml (#2052) * Update links.yml * Update links.yml --- .github/workflows/links.yml | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index a541331803..8845a87c05 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -1,5 +1,6 @@ # Ultralytics YOLO 🚀, AGPL-3.0 license -# YOLO Continuous Integration (CI) GitHub Actions tests +# YOLO Continuous Integration (CI) GitHub Actions tests broken link checker +# Accept 429(Instagram, 'too many requests'), 999(LinkedIn, 'unknown status code'), Timeout(Twitter) name: Check Broken links @@ -18,21 +19,26 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Test Markdown and HTML links - uses: lycheeverse/lychee-action@v1.7.0 + - name: Download and install lychee + run: | + LYCHEE_URL=$(curl -s https://api.github.com/repos/lycheeverse/lychee/releases/latest | grep "browser_download_url" | grep "x86_64-unknown-linux-gnu.tar.gz" | cut -d '"' -f 4) + curl -L $LYCHEE_URL -o lychee.tar.gz + tar xzf lychee.tar.gz + sudo mv lychee /usr/local/bin + + - name: Test Markdown and HTML links with retry + uses: nick-invision/retry@v2 with: - fail: true - # accept 429(Instagram, 'too many requests'), 999(LinkedIn, 'unknown status code'), Timeout(Twitter) - args: --accept 429,999 --exclude-loopback --exclude twitter.com --exclude-path '**/ci-testing.yaml' --exclude-mail './**/*.md' './**/*.html' - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + timeout_minutes: 5 + delay_seconds: 30 + max_attempts: 3 + command: lychee --accept 429,999 --exclude-loopback --exclude twitter.com --exclude-path '**/ci.yaml' --exclude-mail './**/*.md' './**/*.html' - - name: Test Markdown, HTML, YAML, Python and Notebook links + - name: Test Markdown, HTML, YAML, Python and Notebook links with retry if: github.event_name == 'workflow_dispatch' - uses: lycheeverse/lychee-action@v1.7.0 + uses: nick-invision/retry@v2 with: - fail: true - # accept 429(Instagram, 'too many requests'), 999(LinkedIn, 'unknown status code'), Timeout(Twitter) - args: --accept 429,999 --exclude-loopback --exclude twitter.com,url.com --exclude-path '**/ci-testing.yaml' --exclude-mail './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + timeout_minutes: 5 + delay_seconds: 30 + max_attempts: 3 + command: lychee --accept 429,999 --exclude-loopback --exclude twitter.com,url.com --exclude-path '**/ci.yaml' --exclude-mail './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' From 48aad6c24bb26b41e0625420bddd4e59ca0e827d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 1 May 2023 14:37:25 +0200 Subject: [PATCH 0963/1185] Update ci-testing.yml (#2053) * Update ci-testing.yml * Update ci-testing.yml * Update links.yml * Update links.yml * Update ci-testing.yml * Update --- .github/workflows/ci-testing.yml | 2 +- .github/workflows/links.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index d9c7e8db33..fc8449026b 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -124,7 +124,7 @@ jobs: if: always() # This ensures the job runs even if previous jobs fail steps: - name: Check for failure and notify - if: ${{ needs.Tests.result == 'failure' }} # Check if any of the jobs failed + if: needs.Tests.result == 'failure' && github.repository == 'ultralytics/yolov3' && (github.event_name == 'schedule' || github.event_name == 'push') uses: slackapi/slack-github-action@v1.23.0 with: payload: | diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 8845a87c05..306689f465 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -30,15 +30,15 @@ jobs: uses: nick-invision/retry@v2 with: timeout_minutes: 5 - delay_seconds: 30 + retry_wait_seconds: 60 max_attempts: 3 - command: lychee --accept 429,999 --exclude-loopback --exclude twitter.com --exclude-path '**/ci.yaml' --exclude-mail './**/*.md' './**/*.html' + command: lychee --accept 429,999 --exclude-loopback --exclude twitter.com --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' - name: Test Markdown, HTML, YAML, Python and Notebook links with retry if: github.event_name == 'workflow_dispatch' uses: nick-invision/retry@v2 with: timeout_minutes: 5 - delay_seconds: 30 + retry_wait_seconds: 60 max_attempts: 3 - command: lychee --accept 429,999 --exclude-loopback --exclude twitter.com,url.com --exclude-path '**/ci.yaml' --exclude-mail './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' + command: lychee --accept 429,999 --exclude-loopback --exclude twitter.com,url.com --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' From 2f7ef58e81d40d8cde37dbf0a112db45e2ccebdf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 22:13:43 +0200 Subject: [PATCH 0964/1185] [pre-commit.ci] pre-commit suggestions (#2056) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit suggestions updates: - [github.com/asottile/pyupgrade: v3.3.1 → v3.3.2](https://github.com/asottile/pyupgrade/compare/v3.3.1...v3.3.2) - [github.com/google/yapf: v0.32.0 → v0.33.0](https://github.com/google/yapf/compare/v0.32.0...v0.33.0) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- models/common.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8bd40484c5..defb137262 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: - id: detect-private-key - repo: https://github.com/asottile/pyupgrade - rev: v3.3.1 + rev: v3.3.2 hooks: - id: pyupgrade name: Upgrade code @@ -35,7 +35,7 @@ repos: name: Sort imports - repo: https://github.com/google/yapf - rev: v0.32.0 + rev: v0.33.0 hooks: - id: yapf name: YAPF formatting diff --git a/models/common.py b/models/common.py index cc147b7384..1bb3ac2b8b 100644 --- a/models/common.py +++ b/models/common.py @@ -354,8 +354,9 @@ def __init__(self, weights='yolov5s.pt', device=torch.device('cpu'), dnn=False, model.half() if fp16 else model.float() if extra_files['config.txt']: # load metadata dict d = json.loads(extra_files['config.txt'], - object_hook=lambda d: {int(k) if k.isdigit() else k: v - for k, v in d.items()}) + object_hook=lambda d: { + int(k) if k.isdigit() else k: v + for k, v in d.items()}) stride, names = int(d['stride']), d['names'] elif dnn: # ONNX OpenCV DNN LOGGER.info(f'Loading {w} for ONNX OpenCV DNN inference...') From 89088c9e8a4870ecab2539556601b2cc229edfc8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 22:13:58 +0200 Subject: [PATCH 0965/1185] Bump flask from 1.0.2 to 2.3.2 in /utils/google_app_engine (#2055) Bumps [flask](https://github.com/pallets/flask) from 1.0.2 to 2.3.2. - [Release notes](https://github.com/pallets/flask/releases) - [Changelog](https://github.com/pallets/flask/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/flask/compare/1.0.2...2.3.2) --- updated-dependencies: - dependency-name: flask dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- utils/google_app_engine/additional_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/google_app_engine/additional_requirements.txt b/utils/google_app_engine/additional_requirements.txt index b6b496feaa..5ac5c71a3c 100644 --- a/utils/google_app_engine/additional_requirements.txt +++ b/utils/google_app_engine/additional_requirements.txt @@ -1,4 +1,4 @@ # add these requirements in your app on top of the existing ones pip==21.1 -Flask==1.0.2 +Flask==2.3.2 gunicorn==19.10.0 From deb68511bbce7c76c641cc129ee03fd48046b996 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 14 May 2023 02:35:38 +0200 Subject: [PATCH 0966/1185] Update links.yml with 301,302 (#2058) * Update links.yml with 301,302 * Update links.yml --- .github/workflows/links.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 306689f465..cd65b961f7 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -5,10 +5,6 @@ name: Check Broken links on: - push: - branches: [master] - pull_request: - branches: [master] workflow_dispatch: schedule: - cron: '0 0 * * *' # runs at 00:00 UTC every day @@ -32,7 +28,7 @@ jobs: timeout_minutes: 5 retry_wait_seconds: 60 max_attempts: 3 - command: lychee --accept 429,999 --exclude-loopback --exclude twitter.com --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' + command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(twitter\.com|instagram\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' - name: Test Markdown, HTML, YAML, Python and Notebook links with retry if: github.event_name == 'workflow_dispatch' @@ -41,4 +37,4 @@ jobs: timeout_minutes: 5 retry_wait_seconds: 60 max_attempts: 3 - command: lychee --accept 429,999 --exclude-loopback --exclude twitter.com,url.com --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' + command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(twitter\.com|instagram\.com|url\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' From 19beec81264ec6caddf439e7ad409e7850f3e9e8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 14 May 2023 21:44:22 +0200 Subject: [PATCH 0967/1185] Add `ultralytics` pip package (#2059) * Add `ultralytics` pip package * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update requirements.txt * Update requirements.txt * Update requirements.txt --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- classify/train.py | 2 +- requirements.txt | 12 +++++------ segment/train.py | 2 +- train.py | 2 +- utils/general.py | 52 +---------------------------------------------- 5 files changed, 10 insertions(+), 60 deletions(-) diff --git a/classify/train.py b/classify/train.py index 46518a9a3e..4750da9cb1 100644 --- a/classify/train.py +++ b/classify/train.py @@ -300,7 +300,7 @@ def main(opt): if RANK in {-1, 0}: print_args(vars(opt)) check_git_status() - check_requirements() + check_requirements(ROOT / 'requirements.txt') # DDP mode device = select_device(opt.device, batch_size=opt.batch_size) diff --git a/requirements.txt b/requirements.txt index 97ecf13898..bea59ace3c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,9 +2,9 @@ # Usage: pip install -r requirements.txt # Base ------------------------------------------------------------------------ -gitpython +gitpython>=3.1.30 ipython # interactive notebook -matplotlib>=3.2.2 +matplotlib>=3.3 numpy>=1.18.5 opencv-python>=4.1.1 Pillow>=7.1.2 @@ -16,6 +16,7 @@ thop>=0.1.1 # FLOPs computation torch>=1.7.0 # see https://pytorch.org/get-started/locally (recommended) torchvision>=0.8.1 tqdm>=4.64.0 +ultralytics>=8.0.100 # protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 # Logging --------------------------------------------------------------------- @@ -29,22 +30,21 @@ seaborn>=0.11.0 # Export ---------------------------------------------------------------------- # coremltools>=6.0 # CoreML export -# onnx>=1.12.0 # ONNX export +# onnx>=1.10.0 # ONNX export # onnx-simplifier>=0.4.1 # ONNX simplifier # nvidia-pyindex # TensorRT export # nvidia-tensorrt # TensorRT export # scikit-learn<=1.1.2 # CoreML quantization -# tensorflow>=2.4.1 # TF exports (-cpu, -aarch64, -macos) +# tensorflow>=2.4.0 # TF exports (-cpu, -aarch64, -macos) # tensorflowjs>=3.9.0 # TF.js export # openvino-dev # OpenVINO export # Deploy ---------------------------------------------------------------------- setuptools>=65.5.1 # Snyk vulnerability fix -wheel>=0.38.0 # Snyk vulnerability fix # tritonclient[all]~=2.24.0 # Extras ---------------------------------------------------------------------- +# ipython # interactive notebook # mss # screenshots # albumentations>=1.0.3 # pycocotools>=2.0.6 # COCO mAP -# ultralytics # HUB https://hub.ultralytics.com diff --git a/segment/train.py b/segment/train.py index 4113eb6112..b7f8c1c723 100644 --- a/segment/train.py +++ b/segment/train.py @@ -510,7 +510,7 @@ def main(opt, callbacks=Callbacks()): if RANK in {-1, 0}: print_args(vars(opt)) check_git_status() - check_requirements() + check_requirements(ROOT / 'requirements.txt') # Resume if opt.resume and not opt.evolve: # resume from specified or most recent last.pt diff --git a/train.py b/train.py index 65c8cd3ef6..acfb8402ce 100644 --- a/train.py +++ b/train.py @@ -484,7 +484,7 @@ def main(opt, callbacks=Callbacks()): if RANK in {-1, 0}: print_args(vars(opt)) check_git_status() - check_requirements() + check_requirements(ROOT / 'requirements.txt') # Resume (from specified or most recent last.pt) if opt.resume and not check_comet_resume(opt) and not opt.evolve: diff --git a/utils/general.py b/utils/general.py index 567f913ad4..38e7439b78 100644 --- a/utils/general.py +++ b/utils/general.py @@ -36,6 +36,7 @@ import torch import torchvision import yaml +from ultralytics.yolo.utils.checks import check_requirements from utils import TryExcept, emojis from utils.downloads import gsutil_getsize @@ -379,57 +380,6 @@ def check_version(current='0.0.0', minimum='0.0.0', name='version ', pinned=Fals return result -@TryExcept() -def check_requirements(requirements=ROOT.parent / 'requirements.txt', exclude=(), install=True, cmds=''): - """ - Check if installed dependencies meet YOLOv3 requirements and attempt to auto-update if needed. - - Args: - requirements (Union[Path, str, List[str]]): Path to a requirements.txt file, a single package requirement as a - string, or a list of package requirements as strings. - exclude (Tuple[str]): Tuple of package names to exclude from checking. - install (bool): If True, attempt to auto-update packages that don't meet requirements. - cmds (str): Additional commands to pass to the pip install command when auto-updating. - - Returns: - None - """ - prefix = colorstr('red', 'bold', 'requirements:') - check_python() # check python version - file = None - if isinstance(requirements, Path): # requirements.txt file - file = requirements.resolve() - assert file.exists(), f'{prefix} {file} not found, check failed.' - with file.open() as f: - requirements = [f'{x.name}{x.specifier}' for x in pkg.parse_requirements(f) if x.name not in exclude] - elif isinstance(requirements, str): - requirements = [requirements] - - s = '' # console string - n = 0 # number of packages updates - for r in requirements: - try: - pkg.require(r) - except (pkg.VersionConflict, pkg.DistributionNotFound): # exception if requirements not met - try: # attempt to import (slower but more accurate) - import importlib - importlib.import_module(next(pkg.parse_requirements(r)).name) - except ImportError: - s += f'"{r}" ' - n += 1 - - if s and install and AUTOINSTALL: # check environment variable - LOGGER.info(f"{prefix} YOLOv3 requirement{'s' * (n > 1)} {s}not found, attempting AutoUpdate...") - try: - assert check_online(), 'AutoUpdate skipped (offline)' - LOGGER.info(subprocess.check_output(f'pip install {s} {cmds}', shell=True).decode()) - s = f"{prefix} {n} package{'s' * (n > 1)} updated per {file or requirements}\n" \ - f"{prefix} ⚠️ {colorstr('bold', 'Restart runtime or rerun command for updates to take effect')}\n" - LOGGER.info(s) - except Exception as e: - LOGGER.warning(f'{prefix} ❌ {e}') - - def check_img_size(imgsz, s=32, floor=0): # Verify image size is a multiple of stride s in each dimension if isinstance(imgsz, int): # integer i.e. img_size=640 From 66d18ce5dd6c04b0898c9e6e939bb8b640c5f7df Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 15 May 2023 01:16:37 +0200 Subject: [PATCH 0968/1185] Update docker.yml (#2060) --- .github/workflows/docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index e7db8a5554..84f4475eef 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,11 +1,11 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -# Builds ultralytics/yolov5:latest images on DockerHub https://hub.docker.com/r/ultralytics/yolov3 +# Builds ultralytics/yolov3:latest images on DockerHub https://hub.docker.com/r/ultralytics/yolov3 name: Publish Docker Images on: push: - branches: [none] # use DockerHub AutoBuild + branches: [ master ] workflow_dispatch: jobs: From 65d88b1e87f106f289b46a98ead7a3451591cea9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 15 May 2023 01:28:06 +0200 Subject: [PATCH 0969/1185] Update Dockerfiles to Ubuntu 22.10 (#2061) Update Dockerfiles --- utils/docker/Dockerfile-arm64 | 2 +- utils/docker/Dockerfile-cpu | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/docker/Dockerfile-arm64 b/utils/docker/Dockerfile-arm64 index 75a8c9bcca..6bd30a2325 100644 --- a/utils/docker/Dockerfile-arm64 +++ b/utils/docker/Dockerfile-arm64 @@ -3,7 +3,7 @@ # Image is aarch64-compatible for Apple M1 and other ARM architectures i.e. Jetson Nano and Raspberry Pi # Start FROM Ubuntu image https://hub.docker.com/_/ubuntu -FROM arm64v8/ubuntu:rolling +FROM arm64v8/ubuntu:22.10 # Downloads to user config dir ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/ diff --git a/utils/docker/Dockerfile-cpu b/utils/docker/Dockerfile-cpu index c626ddc015..f1543b2efe 100644 --- a/utils/docker/Dockerfile-cpu +++ b/utils/docker/Dockerfile-cpu @@ -3,7 +3,7 @@ # Image is CPU-optimized for ONNX, OpenVINO and PyTorch YOLOv5 deployments # Start FROM Ubuntu image https://hub.docker.com/_/ubuntu -FROM ubuntu:rolling +FROM ubuntu:22.10 # Downloads to user config dir ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/ From 4d7e424bcf1ae53a726f144e5bcfece99c5c7a44 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 21 May 2023 00:42:29 +0200 Subject: [PATCH 0970/1185] Update check_requirements() ROOT (#2062) --- classify/predict.py | 2 +- classify/val.py | 2 +- data/objects365.yaml | 2 +- detect.py | 2 +- hubconf.py | 4 ++-- segment/predict.py | 2 +- segment/val.py | 2 +- val.py | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/classify/predict.py b/classify/predict.py index c123f64439..0f48d93ea4 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -217,7 +217,7 @@ def parse_opt(): def main(opt): - check_requirements(exclude=('tensorboard', 'thop')) + check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) run(**vars(opt)) diff --git a/classify/val.py b/classify/val.py index c2e468d08f..827b626217 100644 --- a/classify/val.py +++ b/classify/val.py @@ -161,7 +161,7 @@ def parse_opt(): def main(opt): - check_requirements(exclude=('tensorboard', 'thop')) + check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) run(**vars(opt)) diff --git a/data/objects365.yaml b/data/objects365.yaml index fc32203981..38372be380 100644 --- a/data/objects365.yaml +++ b/data/objects365.yaml @@ -388,7 +388,7 @@ download: | from utils.general import Path, check_requirements, download, np, xyxy2xywhn - check_requirements(('pycocotools>=2.0',)) + check_requirements('pycocotools>=2.0') from pycocotools.coco import COCO # Make Directories diff --git a/detect.py b/detect.py index c4acb976c2..37cbfb4043 100644 --- a/detect.py +++ b/detect.py @@ -256,7 +256,7 @@ def parse_opt(): def main(opt): - check_requirements(exclude=('tensorboard', 'thop')) + check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) run(**vars(opt)) diff --git a/hubconf.py b/hubconf.py index 7b87835bb6..89fa522200 100644 --- a/hubconf.py +++ b/hubconf.py @@ -34,12 +34,12 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbo from models.experimental import attempt_load from models.yolo import ClassificationModel, DetectionModel, SegmentationModel from utils.downloads import attempt_download - from utils.general import LOGGER, check_requirements, intersect_dicts, logging + from utils.general import LOGGER, ROOT, check_requirements, intersect_dicts, logging from utils.torch_utils import select_device if not verbose: LOGGER.setLevel(logging.WARNING) - check_requirements(exclude=('opencv-python', 'tensorboard', 'thop')) + check_requirements(ROOT / 'requirements.txt', exclude=('opencv-python', 'tensorboard', 'thop')) name = Path(name) path = name.with_suffix('.pt') if name.suffix == '' and not name.is_dir() else name # checkpoint path try: diff --git a/segment/predict.py b/segment/predict.py index 3a376a1680..184502c5ee 100644 --- a/segment/predict.py +++ b/segment/predict.py @@ -275,7 +275,7 @@ def parse_opt(): def main(opt): - check_requirements(exclude=('tensorboard', 'thop')) + check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) run(**vars(opt)) diff --git a/segment/val.py b/segment/val.py index 8759249341..321af8090f 100644 --- a/segment/val.py +++ b/segment/val.py @@ -434,7 +434,7 @@ def parse_opt(): def main(opt): - check_requirements(requirements=ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) if opt.task in ('train', 'val', 'test'): # run normally if opt.conf_thres > 0.001: # https://github.com/ultralytics/yolov5/issues/1466 diff --git a/val.py b/val.py index 17c0bc2e43..fe1bc66d1d 100644 --- a/val.py +++ b/val.py @@ -370,7 +370,7 @@ def parse_opt(): def main(opt): - check_requirements(exclude=('tensorboard', 'thop')) + check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) if opt.task in ('train', 'val', 'test'): # run normally if opt.conf_thres > 0.001: # https://github.com/ultralytics/yolov5/issues/1466 From a4d844cd84052f6145ede17888d3eabea937a2d1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 23 May 2023 10:53:53 +0200 Subject: [PATCH 0971/1185] Update LinkedIn URL (#2065) --- README.md | 4 ++-- README.zh-CN.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e7c41131fc..1c16b3df63 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ To request an Enterprise License please complete the form at [Ultralytics Licens - + @@ -472,7 +472,7 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/ - + diff --git a/README.zh-CN.md b/README.zh-CN.md index b9e88d2b64..4d0510a248 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -28,7 +28,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 - + @@ -469,7 +469,7 @@ YOLOv3 在两种不同的 License 下可用: - + From 4d6393c1f02d135356a6da1e7f37649d53e4d4fe Mon Sep 17 00:00:00 2001 From: Peter van Lunteren Date: Tue, 23 May 2023 12:12:18 +0200 Subject: [PATCH 0972/1185] add smoothing line to results.png to improve readability (#2064) * add smoothing line to results.png to improve readability PR for YOLOv5 already merged (https://github.com/ultralytics/yolov5/pull/11536). Now same PR for YOLOv3 to keep consistent. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- utils/plots.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils/plots.py b/utils/plots.py index 770fca6237..1ac207821d 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -18,6 +18,7 @@ import seaborn as sn import torch from PIL import Image, ImageDraw, ImageFont +from scipy.ndimage.filters import gaussian_filter1d from utils import TryExcept, threaded from utils.general import (CONFIG_DIR, FONT, LOGGER, check_font, check_requirements, clip_boxes, increment_path, @@ -500,7 +501,8 @@ def plot_results(file='path/to/results.csv', dir=''): for i, j in enumerate([1, 2, 3, 4, 5, 8, 9, 10, 6, 7]): y = data.values[:, j].astype('float') # y[y == 0] = np.nan # don't show zero values - ax[i].plot(x, y, marker='.', label=f.stem, linewidth=2, markersize=8) + ax[i].plot(x, y, marker='.', label=f.stem, linewidth=2, markersize=8) # actual results + ax[i].plot(x, gaussian_filter1d(y, sigma=3), ':', label='smooth', linewidth=2) # smoothing line ax[i].set_title(s[j], fontsize=12) # if j in [8, 9, 10]: # share train and val loss y axes # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) From 5a5bfae27fb61d725c7e15cc662c372d389d2734 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 28 May 2023 16:32:28 +0200 Subject: [PATCH 0973/1185] Update Dockerfile with `nvidia-tensorrt` (#2067) --- utils/docker/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/docker/Dockerfile b/utils/docker/Dockerfile index 6bc8eccf11..5cd49868cc 100644 --- a/utils/docker/Dockerfile +++ b/utils/docker/Dockerfile @@ -31,7 +31,8 @@ RUN git clone https://github.com/ultralytics/yolov5 /usr/src/app COPY requirements.txt . RUN python3 -m pip install --upgrade pip wheel RUN pip install --no-cache -r requirements.txt albumentations comet gsutil notebook \ - coremltools onnx onnx-simplifier onnxruntime 'openvino-dev>=2022.3' + coremltools onnx onnx-simplifier onnxruntime 'openvino-dev>=2022.3' \ + nvidia-tensorrt --index-url https://pypi.ngc.nvidia.com # tensorflow tensorflowjs \ # Set environment variables From 35d17798d81f9981dc39be6912cd71c8d31d53a0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 28 May 2023 16:48:31 +0200 Subject: [PATCH 0974/1185] Fix Dockerfile `nvidia-tensorrt` install (#2068) --- utils/docker/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/docker/Dockerfile b/utils/docker/Dockerfile index 5cd49868cc..ceb3d0c6be 100644 --- a/utils/docker/Dockerfile +++ b/utils/docker/Dockerfile @@ -30,10 +30,10 @@ RUN git clone https://github.com/ultralytics/yolov5 /usr/src/app # Install pip packages COPY requirements.txt . RUN python3 -m pip install --upgrade pip wheel +RUN pip install --nocache nvidia-tensorrt --index-url https://pypi.ngc.nvidia.com RUN pip install --no-cache -r requirements.txt albumentations comet gsutil notebook \ - coremltools onnx onnx-simplifier onnxruntime 'openvino-dev>=2022.3' \ - nvidia-tensorrt --index-url https://pypi.ngc.nvidia.com - # tensorflow tensorflowjs \ + coremltools onnx onnx-simplifier onnxruntime 'openvino-dev>=2022.3' + # tensorflow tensorflowjs # Set environment variables ENV OMP_NUM_THREADS=1 From e4e32f5fab515a22ff02ba2c534e7308bd6db55f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 28 May 2023 17:24:48 +0200 Subject: [PATCH 0975/1185] Update Dockerfile with `nvidia-tensorrt` `--no-cache` (#2069) --- utils/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/docker/Dockerfile b/utils/docker/Dockerfile index ceb3d0c6be..b2797f3c18 100644 --- a/utils/docker/Dockerfile +++ b/utils/docker/Dockerfile @@ -30,7 +30,7 @@ RUN git clone https://github.com/ultralytics/yolov5 /usr/src/app # Install pip packages COPY requirements.txt . RUN python3 -m pip install --upgrade pip wheel -RUN pip install --nocache nvidia-tensorrt --index-url https://pypi.ngc.nvidia.com +RUN pip install --no-cache nvidia-tensorrt --index-url https://pypi.ngc.nvidia.com RUN pip install --no-cache -r requirements.txt albumentations comet gsutil notebook \ coremltools onnx onnx-simplifier onnxruntime 'openvino-dev>=2022.3' # tensorflow tensorflowjs From 11ebd48e9d5fc22c8944e898c4490d62e12b84af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 May 2023 17:46:50 +0200 Subject: [PATCH 0976/1185] Bump slackapi/slack-github-action from 1.23.0 to 1.24.0 (#2063) Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 1.23.0 to 1.24.0. - [Release notes](https://github.com/slackapi/slack-github-action/releases) - [Commits](https://github.com/slackapi/slack-github-action/compare/v1.23.0...v1.24.0) --- updated-dependencies: - dependency-name: slackapi/slack-github-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index fc8449026b..70944746bc 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -125,7 +125,7 @@ jobs: steps: - name: Check for failure and notify if: needs.Tests.result == 'failure' && github.repository == 'ultralytics/yolov3' && (github.event_name == 'schedule' || github.event_name == 'push') - uses: slackapi/slack-github-action@v1.23.0 + uses: slackapi/slack-github-action@v1.24.0 with: payload: | {"text": " GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n"} From 69c73e32b737dccf7ab7b4719c5c0d789f279b1c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 31 May 2023 12:25:31 +0200 Subject: [PATCH 0977/1185] Update requirements.txt `ultralytics>=8.0.111` (#2070) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index bea59ace3c..04c7415ff3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,7 +16,7 @@ thop>=0.1.1 # FLOPs computation torch>=1.7.0 # see https://pytorch.org/get-started/locally (recommended) torchvision>=0.8.1 tqdm>=4.64.0 -ultralytics>=8.0.100 +ultralytics>=8.0.111 # protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 # Logging --------------------------------------------------------------------- From 081dd56fd03e031f4249faf395dd8edd78150f87 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 1 Jun 2023 13:06:04 +0200 Subject: [PATCH 0978/1185] Update ci-testing.yml (#2071) --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 70944746bc..2d71707d00 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -124,7 +124,7 @@ jobs: if: always() # This ensures the job runs even if previous jobs fail steps: - name: Check for failure and notify - if: needs.Tests.result == 'failure' && github.repository == 'ultralytics/yolov3' && (github.event_name == 'schedule' || github.event_name == 'push') + if: (needs.Tests.result == 'failure' || needs.Tests.result == 'cancelled') && github.repository == 'ultralytics/yolov3' && (github.event_name == 'schedule' || github.event_name == 'push') uses: slackapi/slack-github-action@v1.24.0 with: payload: | From 56b0e208501a51c5934cf89b35db4ea7c1769cbd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Jun 2023 00:29:46 +0200 Subject: [PATCH 0979/1185] [pre-commit.ci] pre-commit suggestions (#2072) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.3.2 → v3.4.0](https://github.com/asottile/pyupgrade/compare/v3.3.2...v3.4.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index defb137262..c6fd997676 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: - id: detect-private-key - repo: https://github.com/asottile/pyupgrade - rev: v3.3.2 + rev: v3.4.0 hooks: - id: pyupgrade name: Upgrade code From 9a05787d4a60ff0ad4d3821f504d385e207960cf Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 6 Jun 2023 14:48:56 +0200 Subject: [PATCH 0980/1185] Fix OpenVINO export (#2073) * Fix OpenVINO export * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update export.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- export.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/export.py b/export.py index 6e460210bb..68bc8ba95f 100644 --- a/export.py +++ b/export.py @@ -188,14 +188,18 @@ def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr('ONNX @try_export def export_openvino(file, metadata, half, prefix=colorstr('OpenVINO:')): # YOLOv3 OpenVINO export - check_requirements('openvino-dev') # requires openvino-dev: https://pypi.org/project/openvino-dev/ - import openvino.inference_engine as ie + check_requirements('openvino-dev>=2022.3') # requires openvino-dev: https://pypi.org/project/openvino-dev/ + import openvino.runtime as ov # noqa + from openvino.tools import mo # noqa - LOGGER.info(f'\n{prefix} starting export with openvino {ie.__version__}...') - f = str(file).replace('.pt', f'_openvino_model{os.sep}') + LOGGER.info(f'\n{prefix} starting export with openvino {ov.__version__}...') + f = str(file).replace(file.suffix, f'_openvino_model{os.sep}') + f_onnx = file.with_suffix('.onnx') + f_ov = str(Path(f) / file.with_suffix('.xml').name) - cmd = f"mo --input_model {file.with_suffix('.onnx')} --output_dir {f} --data_type {'FP16' if half else 'FP32'}" - subprocess.run(cmd.split(), check=True, env=os.environ) # export + ov_model = mo.convert_model(f_onnx, model_name=file.stem, framework='onnx', compress_to_fp16=half) # export + + ov.serialize(ov_model, f_ov) # save yaml_save(Path(f) / file.with_suffix('.yaml').name, metadata) # add metadata.yaml return f, None From 715fecd25cb0dcd7968f8f0acefb203a3f6730f9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 15 Jun 2023 13:53:02 +0200 Subject: [PATCH 0981/1185] Update ci-testing.yml (#2077) --- .github/workflows/ci-testing.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 2d71707d00..727e83fe3f 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -23,10 +23,7 @@ jobs: model: [yolov5n] include: - os: ubuntu-latest - python-version: '3.7' # '3.6.8' min - model: yolov5n - - os: ubuntu-latest - python-version: '3.8' + python-version: '3.8' # '3.6.8' min model: yolov5n - os: ubuntu-latest python-version: '3.9' From 518104947f6f6ed5dc625e88564dd07e97f65cc6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 15 Jun 2023 21:14:13 +0200 Subject: [PATCH 0982/1185] Update Discord invite URLs (#2078) --- .github/ISSUE_TEMPLATE/config.yml | 2 +- README.md | 8 ++++---- README.zh-CN.md | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index b071ccae73..43d9c7f8dc 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -7,5 +7,5 @@ contact_links: url: https://community.ultralytics.com/ about: Ask on Ultralytics Community Forum - name: 🎧 Discord - url: https://discord.gg/n6cFeSPZdD + url: https://discord.gg/7aegy5d8 about: Ask on Ultralytics Discord diff --git a/README.md b/README.md index 1c16b3df63..b95846c70c 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ YOLOv3 🚀 is the world's most loved vision AI, representing Ultralytics open-source research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours of research and development. -We hope that the resources here will help you get the most out of YOLOv3. Please browse the YOLOv3 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions! +We hope that the resources here will help you get the most out of YOLOv3. Please browse the YOLOv3 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions! To request an Enterprise License please complete the form at [Ultralytics Licensing](https://ultralytics.com/license). @@ -43,7 +43,7 @@ To request an Enterprise License please complete the form at [Ultralytics Licens - + @@ -465,7 +465,7 @@ YOLOv3 is available under two different licenses: ##
Contact
-For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues), and join our [Discord](https://discord.gg/n6cFeSPZdD) community for questions and discussions! +For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues), and join our [Discord](https://discord.gg/7aegy5d8) community for questions and discussions!
@@ -487,7 +487,7 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/ - +
diff --git a/README.zh-CN.md b/README.zh-CN.md index 4d0510a248..a95e6c6c88 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -19,7 +19,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics 对未来视觉 AI 方法的开源研究,结合在数千小时的研究和开发中积累的经验教训和最佳实践。 -我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 YOLOv3 文档 了解详细信息,在 GitHub 上提交问题以获得支持,并加入我们的 Discord 社区进行问题和讨论! +我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 YOLOv3 文档 了解详细信息,在 GitHub 上提交问题以获得支持,并加入我们的 Discord 社区进行问题和讨论! 如需申请企业许可,请在 [Ultralytics Licensing](https://ultralytics.com/license) 处填写表格 @@ -43,7 +43,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 - + @@ -462,7 +462,7 @@ YOLOv3 在两种不同的 License 下可用: ##
联系我们
-对于 YOLOv8 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://discord.gg/n6cFeSPZdD) 社区进行问题和讨论! +对于 YOLOv8 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://discord.gg/7aegy5d8) 社区进行问题和讨论!
@@ -484,7 +484,7 @@ YOLOv3 在两种不同的 License 下可用: - +
From 7de40c623a3576df2311061c3a1a631411864aae Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 18 Jun 2023 16:09:33 +0200 Subject: [PATCH 0983/1185] Uninstall `wandb` from notebook environments (#2079) * Uninstall `wandb` from notebook environments Due to unwanted behavior in https://www.kaggle.com/code/ultralytics/yolov8/comments#2306977 * Update __init__.py * Update __init__.py --- utils/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/__init__.py b/utils/__init__.py index 77f9ff835b..0969bbd5a4 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -62,6 +62,8 @@ def notebook_init(verbose=True): import psutil from IPython import display # to display images and clear console output + if check_requirements('wandb', install=False): + os.system('pip uninstall -y wandb') # eliminate unexpected account creation prompt with infinite hang if is_colab(): shutil.rmtree('/content/sample_data', ignore_errors=True) # remove colab /sample_data directory From d3ced6a054a17010980198e8042f578f61f30e41 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 25 Jun 2023 18:05:40 +0200 Subject: [PATCH 0984/1185] Add PyPI badges to README (#2080) * Update README.zh-CN.md * Update README.md * Update README.zh-CN.md --- README.md | 4 +++- README.zh-CN.md | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b95846c70c..b51d545ccd 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,9 @@ object detection, image segmentation and image classification tasks. See the [YOLOv8 Docs](https://docs.ultralytics.com) for details and get started with: -```commandline +[![PyPI version](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![Downloads](https://static.pepy.tech/badge/ultralytics)](https://pepy.tech/project/ultralytics) + +```bash pip install ultralytics ``` diff --git a/README.zh-CN.md b/README.zh-CN.md index a95e6c6c88..17e4c0e706 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -48,14 +48,14 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表YOLOv8 🚀 NEW +##
YOLOv8 🚀 新品
-We are thrilled to announce the launch of Ultralytics YOLOv8 🚀, our NEW cutting-edge, state-of-the-art (SOTA) model -released at **[https://github.com/ultralytics/ultralytics](https://github.com/ultralytics/ultralytics)**. -YOLOv8 is designed to be fast, accurate, and easy to use, making it an excellent choice for a wide range of -object detection, image segmentation and image classification tasks. +我们很高兴宣布 Ultralytics YOLOv8 🚀 的发布,这是我们新推出的领先水平、最先进的(SOTA)模型,发布于 **[https://github.com/ultralytics/ultralytics](https://github.com/ultralytics/ultralytics)**。 +YOLOv8 旨在快速、准确且易于使用,使其成为广泛的物体检测、图像分割和图像分类任务的极佳选择。 -See the [YOLOv8 Docs](https://docs.ultralytics.com) for details and get started with: +请查看 [YOLOv8 文档](https://docs.ultralytics.com)了解详细信息,并开始使用: + +[![PyPI 版本](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![下载量](https://static.pepy.tech/badge/ultralytics)](https://pepy.tech/project/ultralytics) ```commandline pip install ultralytics From 79ead18451bb55d32d02531b515e3255fd6d057f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 26 Jun 2023 19:13:25 +0200 Subject: [PATCH 0985/1185] Update Discord invite URLs (#2081) --- .github/ISSUE_TEMPLATE/config.yml | 2 +- README.md | 8 ++++---- README.zh-CN.md | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 43d9c7f8dc..c1f9a4efd8 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -7,5 +7,5 @@ contact_links: url: https://community.ultralytics.com/ about: Ask on Ultralytics Community Forum - name: 🎧 Discord - url: https://discord.gg/7aegy5d8 + url: https://discord.gg/bNc8wwx7Qy about: Ask on Ultralytics Discord diff --git a/README.md b/README.md index b51d545ccd..c42b1d0fee 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ YOLOv3 🚀 is the world's most loved vision AI, representing
Ultralytics open-source research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours of research and development. -We hope that the resources here will help you get the most out of YOLOv3. Please browse the YOLOv3 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions! +We hope that the resources here will help you get the most out of YOLOv3. Please browse the YOLOv3 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions! To request an Enterprise License please complete the form at [Ultralytics Licensing](https://ultralytics.com/license). @@ -43,7 +43,7 @@ To request an Enterprise License please complete the form at [Ultralytics Licens - + @@ -467,7 +467,7 @@ YOLOv3 is available under two different licenses: ##
Contact
-For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues), and join our [Discord](https://discord.gg/7aegy5d8) community for questions and discussions! +For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues), and join our [Discord](https://discord.gg/bNc8wwx7Qy) community for questions and discussions!
@@ -489,7 +489,7 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/ - +
diff --git a/README.zh-CN.md b/README.zh-CN.md index 17e4c0e706..7b093f5c4c 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -19,7 +19,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics 对未来视觉 AI 方法的开源研究,结合在数千小时的研究和开发中积累的经验教训和最佳实践。 -我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 YOLOv3 文档 了解详细信息,在 GitHub 上提交问题以获得支持,并加入我们的 Discord 社区进行问题和讨论! +我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 YOLOv3 文档 了解详细信息,在 GitHub 上提交问题以获得支持,并加入我们的 Discord 社区进行问题和讨论! 如需申请企业许可,请在 [Ultralytics Licensing](https://ultralytics.com/license) 处填写表格 @@ -43,7 +43,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 - + @@ -462,7 +462,7 @@ YOLOv3 在两种不同的 License 下可用: ##
联系我们
-对于 YOLOv8 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://discord.gg/7aegy5d8) 社区进行问题和讨论! +对于 YOLOv8 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://discord.gg/bNc8wwx7Qy) 社区进行问题和讨论!
@@ -484,7 +484,7 @@ YOLOv3 在两种不同的 License 下可用: - +
From 8f9de236d4e477b7ca6266534e12eb1211476480 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 3 Jul 2023 02:37:44 +0200 Subject: [PATCH 0986/1185] Fix PIL.ANTIALIAS deprecation (#2084) * Fix PIL.ANTIALIAS deprecation * Update requirements.txt * Update loggers * Update notebook init * Update notebook init * Update notebook init * Update general.py --- models/common.py | 13 ++++++++----- requirements.txt | 3 +-- utils/__init__.py | 10 +++++++--- utils/downloads.py | 32 +++++++++++++++++++++++++++----- utils/general.py | 37 ++++++++++++++++++++++--------------- utils/loggers/__init__.py | 18 +++++++++--------- 6 files changed, 74 insertions(+), 39 deletions(-) diff --git a/models/common.py b/models/common.py index 1bb3ac2b8b..6ad05380e9 100644 --- a/models/common.py +++ b/models/common.py @@ -21,14 +21,13 @@ import requests import torch import torch.nn as nn -from IPython.display import display from PIL import Image from torch.cuda import amp from utils import TryExcept from utils.dataloaders import exif_transpose, letterbox from utils.general import (LOGGER, ROOT, Profile, check_requirements, check_suffix, check_version, colorstr, - increment_path, is_notebook, make_divisible, non_max_suppression, scale_boxes, xywh2xyxy, + increment_path, is_jupyter, make_divisible, non_max_suppression, scale_boxes, xywh2xyxy, xyxy2xywh, yaml_load) from utils.plots import Annotator, colors, save_one_box from utils.torch_utils import copy_attr, smart_inference_mode @@ -334,7 +333,7 @@ def __init__(self, weights='yolov5s.pt', device=torch.device('cpu'), dnn=False, super().__init__() w = str(weights[0] if isinstance(weights, list) else weights) pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle, triton = self._model_type(w) - fp16 &= pt or jit or onnx or engine # FP16 + fp16 &= pt or jit or onnx or engine or triton # FP16 nhwc = coreml or saved_model or pb or tflite or edgetpu # BHWC formats (vs torch BCWH) stride = 32 # default stride cuda = torch.cuda.is_available() and device.type != 'cpu' # use CUDA @@ -542,7 +541,7 @@ def forward(self, im, augment=False, visualize=False): elif self.coreml: # CoreML im = im.cpu().numpy() im = Image.fromarray((im[0] * 255).astype('uint8')) - # im = im.resize((192, 320), Image.ANTIALIAS) + # im = im.resize((192, 320), Image.BILINEAR) y = self.model.predict({'image': im}) # coordinates are xywh normalized if 'confidence' in y: box = xywh2xyxy(y['coordinates'] * [[w, h, w, h]]) # xyxy pixels @@ -768,7 +767,11 @@ def _run(self, pprint=False, show=False, save=False, crop=False, render=False, l im = Image.fromarray(im.astype(np.uint8)) if isinstance(im, np.ndarray) else im # from np if show: - display(im) if is_notebook() else im.show(self.files[i]) + if is_jupyter(): + from IPython.display import display + display(im) + else: + im.show(self.files[i]) if save: f = self.files[i] im.save(save_dir / f) # save diff --git a/requirements.txt b/requirements.txt index 04c7415ff3..2857407f3c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,6 @@ # Base ------------------------------------------------------------------------ gitpython>=3.1.30 -ipython # interactive notebook matplotlib>=3.3 numpy>=1.18.5 opencv-python>=4.1.1 @@ -20,7 +19,7 @@ ultralytics>=8.0.111 # protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 # Logging --------------------------------------------------------------------- -tensorboard>=2.4.1 +# tensorboard>=2.4.1 # clearml>=1.2.0 # comet diff --git a/utils/__init__.py b/utils/__init__.py index 0969bbd5a4..7e74073321 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -54,13 +54,14 @@ def notebook_init(verbose=True): import os import shutil - from utils.general import check_font, check_requirements, is_colab + from ultralytics.yolo.utils.checks import check_requirements + + from utils.general import check_font, is_colab from utils.torch_utils import select_device # imports check_font() import psutil - from IPython import display # to display images and clear console output if check_requirements('wandb', install=False): os.system('pip uninstall -y wandb') # eliminate unexpected account creation prompt with infinite hang @@ -68,11 +69,14 @@ def notebook_init(verbose=True): shutil.rmtree('/content/sample_data', ignore_errors=True) # remove colab /sample_data directory # System info + display = None if verbose: gb = 1 << 30 # bytes to GiB (1024 ** 3) ram = psutil.virtual_memory().total total, used, free = shutil.disk_usage('/') - display.clear_output() + with contextlib.suppress(Exception): # clear display if ipython is installed + from IPython import display + display.clear_output() s = f'({os.cpu_count()} CPUs, {ram / gb:.1f} GB RAM, {(total - free) / gb:.1f}/{total / gb:.1f} GB disk)' else: s = '' diff --git a/utils/downloads.py b/utils/downloads.py index e55c639929..4c2533625d 100644 --- a/utils/downloads.py +++ b/utils/downloads.py @@ -4,6 +4,7 @@ """ import logging +import os import subprocess import urllib from pathlib import Path @@ -25,8 +26,10 @@ def is_url(url, check=True): def gsutil_getsize(url=''): # gs://bucket/file size https://cloud.google.com/storage/docs/gsutil/commands/du - s = subprocess.check_output(f'gsutil du {url}', shell=True).decode('utf-8') - return eval(s.split(' ')[0]) if len(s) else 0 # bytes + output = subprocess.check_output(['gsutil', 'du', url], shell=True, encoding='utf-8') + if output: + return int(output.split()[0]) + return 0 def url_getsize(url='https://ultralytics.com/images/bus.jpg'): @@ -35,6 +38,25 @@ def url_getsize(url='https://ultralytics.com/images/bus.jpg'): return int(response.headers.get('content-length', -1)) +def curl_download(url, filename, *, silent: bool = False) -> bool: + """ + Download a file from a url to a filename using curl. + """ + silent_option = 'sS' if silent else '' # silent + proc = subprocess.run([ + 'curl', + '-#', + f'-{silent_option}L', + url, + '--output', + filename, + '--retry', + '9', + '-C', + '-',]) + return proc.returncode == 0 + + def safe_download(file, url, url2=None, min_bytes=1E0, error_msg=''): # Attempts to download file from url or url2, checks and removes incomplete downloads < min_bytes from utils.general import LOGGER @@ -49,8 +71,8 @@ def safe_download(file, url, url2=None, min_bytes=1E0, error_msg=''): if file.exists(): file.unlink() # remove partial downloads LOGGER.info(f'ERROR: {e}\nRe-attempting {url2 or url} to {file}...') - subprocess.run( - f"curl -# -L '{url2 or url}' -o '{file}' --retry 3 -C -".split()) # curl download, retry and resume on fail + # curl download, retry and resume on fail + curl_download(url2 or url, file) finally: if not file.exists() or file.stat().st_size < min_bytes: # check if file.exists(): @@ -96,8 +118,8 @@ def github_assets(repository, version='latest'): except Exception: tag = release - file.parent.mkdir(parents=True, exist_ok=True) # make parent dir (if required) if name in assets: + file.parent.mkdir(parents=True, exist_ok=True) # make parent dir (if required) safe_download(file, url=f'https://github.com/{repo}/releases/download/{tag}/{name}', min_bytes=1E5, diff --git a/utils/general.py b/utils/general.py index 38e7439b78..cf3fc10db1 100644 --- a/utils/general.py +++ b/utils/general.py @@ -29,7 +29,6 @@ from zipfile import ZipFile, is_zipfile import cv2 -import IPython import numpy as np import pandas as pd import pkg_resources as pkg @@ -39,7 +38,7 @@ from ultralytics.yolo.utils.checks import check_requirements from utils import TryExcept, emojis -from utils.downloads import gsutil_getsize +from utils.downloads import curl_download, gsutil_getsize from utils.metrics import box_iou, fitness FILE = Path(__file__).resolve() @@ -60,6 +59,7 @@ cv2.setNumThreads(0) # prevent OpenCV from multithreading (incompatible with PyTorch DataLoader) os.environ['NUMEXPR_MAX_THREADS'] = str(NUM_THREADS) # NumExpr max threads os.environ['OMP_NUM_THREADS'] = '1' if platform.system() == 'darwin' else str(NUM_THREADS) # OpenMP (PyTorch and SciPy) +os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # suppress verbose TF compiler warnings in Colab def is_ascii(s=''): @@ -78,10 +78,18 @@ def is_colab(): return 'google.colab' in sys.modules -def is_notebook(): - # Is environment a Jupyter notebook? Verified on Colab, Jupyterlab, Kaggle, Paperspace - ipython_type = str(type(IPython.get_ipython())) - return 'colab' in ipython_type or 'zmqshell' in ipython_type +def is_jupyter(): + """ + Check if the current script is running inside a Jupyter Notebook. + Verified on Colab, Jupyterlab, Kaggle, Paperspace. + + Returns: + bool: True if running inside a Jupyter Notebook, False otherwise. + """ + with contextlib.suppress(Exception): + from IPython import get_ipython + return get_ipython() is not None + return False def is_kaggle(): @@ -395,7 +403,7 @@ def check_img_size(imgsz, s=32, floor=0): def check_imshow(warn=False): # Check if environment supports image displays try: - assert not is_notebook() + assert not is_jupyter() assert not is_docker() cv2.imshow('test', np.zeros((1, 1, 3))) cv2.waitKey(1) @@ -596,9 +604,7 @@ def download_one(url, dir): LOGGER.info(f'Downloading {url} to {f}...') for i in range(retry + 1): if curl: - s = 'sS' if threads > 1 else '' # silent - r = subprocess.run(f'curl -# -{s}L "{url}" -o "{f}" --retry 9 -C -'.split()) - success = r == 0 + success = curl_download(url, f, silent=(threads > 1)) else: torch.hub.download_url_to_file(url, f, progress=threads == 1) # torch download success = f.is_file() @@ -1080,13 +1086,13 @@ def increment_path(path, exist_ok=False, sep='', mkdir=False): imshow_ = cv2.imshow # copy to avoid recursion errors -def imread(path, flags=cv2.IMREAD_COLOR): - return cv2.imdecode(np.fromfile(path, np.uint8), flags) +def imread(filename, flags=cv2.IMREAD_COLOR): + return cv2.imdecode(np.fromfile(filename, np.uint8), flags) -def imwrite(path, im): +def imwrite(filename, img): try: - cv2.imencode(Path(path).suffix, im)[1].tofile(path) + cv2.imencode(Path(filename).suffix, img)[1].tofile(filename) return True except Exception: return False @@ -1096,6 +1102,7 @@ def imshow(path, im): imshow_(path.encode('unicode_escape').decode(), im) -cv2.imread, cv2.imwrite, cv2.imshow = imread, imwrite, imshow # redefine +if Path(inspect.stack()[0].filename).parent.parent.as_posix() in inspect.stack()[-1].filename: + cv2.imread, cv2.imwrite, cv2.imshow = imread, imwrite, imshow # redefine # Variables ------------------------------------------------------------------------------------------------------------ diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index 6e6b41ccf1..edd6cf2c60 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -9,7 +9,6 @@ import pkg_resources as pkg import torch -from torch.utils.tensorboard import SummaryWriter from utils.general import LOGGER, colorstr, cv2 from utils.loggers.clearml.clearml_utils import ClearmlLogger @@ -20,6 +19,11 @@ LOGGERS = ('csv', 'tb', 'wandb', 'clearml', 'comet') # *.csv, TensorBoard, Weights & Biases, ClearML RANK = int(os.getenv('RANK', -1)) +try: + from torch.utils.tensorboard import SummaryWriter +except ImportError: + SummaryWriter = lambda *args: None # None = SummaryWriter(str) + try: import wandb @@ -42,15 +46,15 @@ clearml = None try: - if RANK not in [0, -1]: - comet_ml = None - else: + if RANK in {0, -1}: import comet_ml assert hasattr(comet_ml, '__version__') # verify package import not local dir from utils.loggers.comet import CometLogger -except (ModuleNotFoundError, ImportError, AssertionError): + else: + comet_ml = None +except (ImportError, AssertionError): comet_ml = None @@ -84,10 +88,6 @@ def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, self.csv = True # always log to csv # Messages - if not clearml: - prefix = colorstr('ClearML: ') - s = f"{prefix}run 'pip install clearml' to automatically track, visualize and remotely train YOLOv3 🚀 in ClearML" - self.logger.info(s) if not comet_ml: prefix = colorstr('Comet: ') s = f"{prefix}run 'pip install comet_ml' to automatically track and visualize YOLOv3 🚀 runs in Comet" From 937e4618843e73e4b1b9e5c41320f80515c46005 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 4 Jul 2023 01:55:49 +0200 Subject: [PATCH 0987/1185] [pre-commit.ci] pre-commit suggestions (#2086) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.4.0 → v3.8.0](https://github.com/asottile/pyupgrade/compare/v3.4.0...v3.8.0) - [github.com/google/yapf: v0.33.0 → v0.40.0](https://github.com/google/yapf/compare/v0.33.0...v0.40.0) - [github.com/codespell-project/codespell: v2.2.4 → v2.2.5](https://github.com/codespell-project/codespell/compare/v2.2.4...v2.2.5) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c6fd997676..3c5081e709 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: - id: detect-private-key - repo: https://github.com/asottile/pyupgrade - rev: v3.4.0 + rev: v3.8.0 hooks: - id: pyupgrade name: Upgrade code @@ -35,7 +35,7 @@ repos: name: Sort imports - repo: https://github.com/google/yapf - rev: v0.33.0 + rev: v0.40.0 hooks: - id: yapf name: YAPF formatting @@ -57,7 +57,7 @@ repos: name: PEP8 - repo: https://github.com/codespell-project/codespell - rev: v2.2.4 + rev: v2.2.5 hooks: - id: codespell args: From bbc3f292371588f71c4104e830f2fec72df65e57 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 4 Jul 2023 22:41:21 +0200 Subject: [PATCH 0988/1185] Update Discord links (#2087) --- .github/ISSUE_TEMPLATE/config.yml | 2 +- README.md | 8 ++++---- README.zh-CN.md | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index c1f9a4efd8..d676dd9d02 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -7,5 +7,5 @@ contact_links: url: https://community.ultralytics.com/ about: Ask on Ultralytics Community Forum - name: 🎧 Discord - url: https://discord.gg/bNc8wwx7Qy + url: https://discord.gg/2wNGbc6g9X about: Ask on Ultralytics Discord diff --git a/README.md b/README.md index c42b1d0fee..0768a5b696 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ YOLOv3 🚀 is the world's most loved vision AI, representing Ultralytics open-source research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours of research and development. -We hope that the resources here will help you get the most out of YOLOv3. Please browse the YOLOv3 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions! +We hope that the resources here will help you get the most out of YOLOv3. Please browse the YOLOv3 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions! To request an Enterprise License please complete the form at [Ultralytics Licensing](https://ultralytics.com/license). @@ -43,7 +43,7 @@ To request an Enterprise License please complete the form at [Ultralytics Licens - + @@ -467,7 +467,7 @@ YOLOv3 is available under two different licenses: ##
Contact
-For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues), and join our [Discord](https://discord.gg/bNc8wwx7Qy) community for questions and discussions! +For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues), and join our [Discord](https://discord.gg/2wNGbc6g9X) community for questions and discussions!
@@ -489,7 +489,7 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/ - +
diff --git a/README.zh-CN.md b/README.zh-CN.md index 7b093f5c4c..e22c7926b7 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -19,7 +19,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics 对未来视觉 AI 方法的开源研究,结合在数千小时的研究和开发中积累的经验教训和最佳实践。 -我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 YOLOv3 文档 了解详细信息,在 GitHub 上提交问题以获得支持,并加入我们的 Discord 社区进行问题和讨论! +我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 YOLOv3 文档 了解详细信息,在 GitHub 上提交问题以获得支持,并加入我们的 Discord 社区进行问题和讨论! 如需申请企业许可,请在 [Ultralytics Licensing](https://ultralytics.com/license) 处填写表格 @@ -43,7 +43,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 - + @@ -462,7 +462,7 @@ YOLOv3 在两种不同的 License 下可用: ##
联系我们
-对于 YOLOv8 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://discord.gg/bNc8wwx7Qy) 社区进行问题和讨论! +对于 YOLOv8 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://discord.gg/2wNGbc6g9X) 社区进行问题和讨论!
@@ -484,7 +484,7 @@ YOLOv3 在两种不同的 License 下可用: - +
From eb99ba8e05e07bfbe96101a35a6cfd67c88207a2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 5 Jul 2023 00:50:53 +0200 Subject: [PATCH 0989/1185] Update setup.cfg (#2088) * Update setup.cfg * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update .pre-commit-config.yaml * Update downloads.py * Update yolo.py * Update train.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 16 ++++++++++------ classify/train.py | 8 ++++---- export.py | 2 +- models/tf.py | 4 ++-- models/yolo.py | 8 ++++---- setup.cfg | 14 ++++++++------ utils/augmentations.py | 2 +- utils/callbacks.py | 2 +- utils/downloads.py | 3 +-- utils/general.py | 6 +++--- utils/loggers/comet/__init__.py | 12 ++++++------ utils/segment/metrics.py | 4 ++-- utils/torch_utils.py | 4 ++-- 13 files changed, 45 insertions(+), 40 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3c5081e709..192a0ff3cb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - id: check-case-conflict - - id: check-yaml + # - id: check-yaml - id: check-docstring-first - id: double-quote-string-fixer - id: detect-private-key @@ -26,7 +26,6 @@ repos: hooks: - id: pyupgrade name: Upgrade code - args: [--py37-plus] - repo: https://github.com/PyCQA/isort rev: 5.12.0 @@ -63,7 +62,12 @@ repos: args: - --ignore-words-list=crate,nd,strack,dota - #- repo: https://github.com/asottile/yesqa - # rev: v1.4.0 - # hooks: - # - id: yesqa +# - repo: https://github.com/asottile/yesqa +# rev: v1.4.0 +# hooks: +# - id: yesqa + +# - repo: https://github.com/asottile/dead +# rev: v1.5.0 +# hooks: +# - id: dead diff --git a/classify/train.py b/classify/train.py index 4750da9cb1..9da4e3c445 100644 --- a/classify/train.py +++ b/classify/train.py @@ -44,7 +44,7 @@ check_requirements, colorstr, download, increment_path, init_seeds, print_args, yaml_save) from utils.loggers import GenericLogger from utils.plots import imshow_cls -from utils.torch_utils import (ModelEMA, model_info, reshape_classifier_output, select_device, smart_DDP, +from utils.torch_utils import (ModelEMA, de_parallel, model_info, reshape_classifier_output, select_device, smart_DDP, smart_optimizer, smartCrossEntropyLoss, torch_distributed_zero_first) LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html @@ -57,7 +57,7 @@ def train(opt, device): init_seeds(opt.seed + 1 + RANK, deterministic=True) save_dir, data, bs, epochs, nw, imgsz, pretrained = \ opt.save_dir, Path(opt.data), opt.batch_size, opt.epochs, min(os.cpu_count() - 1, opt.workers), \ - opt.imgsz, str(opt.pretrained).lower() == 'true' + opt.imgsz, str(opt.pretrained).lower() == 'true' cuda = device.type != 'cpu' # Directories @@ -78,7 +78,7 @@ def train(opt, device): LOGGER.info(f'\nDataset not found ⚠️, missing path {data_dir}, attempting download...') t = time.time() if str(data) == 'imagenet': - subprocess.run(f"bash {ROOT / 'data/scripts/get_imagenet.sh'}", shell=True, check=True) + subprocess.run(['bash', str(ROOT / 'data/scripts/get_imagenet.sh')], shell=True, check=True) else: url = f'https://github.com/ultralytics/yolov5/releases/download/v1.0/{data}.zip' download(url, dir=data_dir.parent) @@ -260,7 +260,7 @@ def train(opt, device): # Plot examples images, labels = (x[:25] for x in next(iter(testloader))) # first 25 images and labels pred = torch.max(ema.ema(images.to(device)), 1)[1] - file = imshow_cls(images, labels, pred, model.names, verbose=False, f=save_dir / 'test_images.jpg') + file = imshow_cls(images, labels, pred, de_parallel(model).names, verbose=False, f=save_dir / 'test_images.jpg') # Log results meta = {'epochs': epochs, 'top1_acc': best_fitness, 'date': datetime.now().isoformat()} diff --git a/export.py b/export.py index 68bc8ba95f..fc2c800411 100644 --- a/export.py +++ b/export.py @@ -91,7 +91,7 @@ def export_formats(): ['TensorFlow Lite', 'tflite', '.tflite', True, False], ['TensorFlow Edge TPU', 'edgetpu', '_edgetpu.tflite', False, False], ['TensorFlow.js', 'tfjs', '_web_model', False, False], - ['PaddlePaddle', 'paddle', '_paddle_model', True, True],] + ['PaddlePaddle', 'paddle', '_paddle_model', True, True], ] return pd.DataFrame(x, columns=['Format', 'Argument', 'Suffix', 'CPU', 'GPU']) diff --git a/models/tf.py b/models/tf.py index ca6fc9ec0b..d9ce958d45 100644 --- a/models/tf.py +++ b/models/tf.py @@ -310,7 +310,7 @@ def call(self, inputs): y = tf.concat([xy, wh, tf.sigmoid(y[..., 4:5 + self.nc]), y[..., 5 + self.nc:]], -1) z.append(tf.reshape(y, [-1, self.na * ny * nx, self.no])) - return tf.transpose(x, [0, 2, 1, 3]) if self.training else (tf.concat(z, 1),) + return tf.transpose(x, [0, 2, 1, 3]) if self.training else (tf.concat(z, 1), ) @staticmethod def _make_grid(nx=20, ny=20): @@ -486,7 +486,7 @@ def predict(self, iou_thres, conf_thres, clip_boxes=False) - return (nms,) + return (nms, ) return x # output [1,6300,85] = [xywh, conf, class0, class1, ...] # x = x[0] # [x(1,6300,85), ...] to x(6300,85) # xywh = x[..., :4] # x(6300,4) boxes diff --git a/models/yolo.py b/models/yolo.py index 22da67f78c..ac7fa95ee9 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -20,8 +20,8 @@ if platform.system() != 'Windows': ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative -from models.common import * -from models.experimental import * +from models.common import * # noqa +from models.experimental import * # noqa from utils.autoanchor import check_anchor_order from utils.general import LOGGER, check_version, check_yaml, make_divisible, print_args from utils.plots import feature_visualization @@ -75,7 +75,7 @@ def forward(self, x): y = torch.cat((xy, wh, conf), 4) z.append(y.view(bs, self.na * nx * ny, self.no)) - return x if self.training else (torch.cat(z, 1),) if self.export else (torch.cat(z, 1), x) + return x if self.training else (torch.cat(z, 1), ) if self.export else (torch.cat(z, 1), x) def _make_grid(self, nx=20, ny=20, i=0, torch_1_10=check_version(torch.__version__, '1.10.0')): d = self.anchors[i].device @@ -125,7 +125,7 @@ def _forward_once(self, x, profile=False, visualize=False): def _profile_one_layer(self, m, x, dt): c = m == self.model[-1] # is final layer, copy input as inplace fix - o = thop.profile(m, inputs=(x.copy() if c else x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPs + o = thop.profile(m, inputs=(x.copy() if c else x, ), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPs t = time_sync() for _ in range(10): m(x.copy() if c else x) diff --git a/setup.cfg b/setup.cfg index d7c4cb3e1a..2cde6a4948 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,7 +3,7 @@ # Local usage: pip install pre-commit, pre-commit run --all-files [metadata] -license_file = LICENSE +license_files = LICENSE description_file = README.md [tool:pytest] @@ -25,17 +25,19 @@ verbose = 2 # https://pep8.readthedocs.io/en/latest/intro.html#error-codes format = pylint # see: https://www.flake8rules.com/ -ignore = E731,F405,E402,F401,W504,E127,E231,E501,F403 +ignore = E731,F405,E402,W504,E501 # E731: Do not assign a lambda expression, use a def # F405: name may be undefined, or defined from star imports: module # E402: module level import not at top of file - # F401: module imported but unused # W504: line break after binary operator - # E127: continuation line over-indented for visual indent - # E231: missing whitespace after ‘,’, ‘;’, or ‘:’ # E501: line too long + # removed: + # F401: module imported but unused + # E231: missing whitespace after ‘,’, ‘;’, or ‘:’ + # E127: continuation line over-indented for visual indent # F403: ‘from module import *’ used; unable to detect undefined names + [isort] # https://pycqa.github.io/isort/docs/configuration/options.html line_length = 120 @@ -48,7 +50,7 @@ spaces_before_comment = 2 COLUMN_LIMIT = 120 COALESCE_BRACKETS = True SPACES_AROUND_POWER_OPERATOR = True -SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = False +SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = True SPLIT_BEFORE_CLOSING_BRACKET = False SPLIT_BEFORE_FIRST_ARGUMENT = False # EACH_DICT_ENTRY_ON_SEPARATE_LINE = False diff --git a/utils/augmentations.py b/utils/augmentations.py index f5e0cebf00..64bd7a50a8 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -330,7 +330,7 @@ def classify_albumentations( if vflip > 0: T += [A.VerticalFlip(p=vflip)] if jitter > 0: - color_jitter = (float(jitter),) * 3 # repeat value for brightness, contrast, satuaration, 0 hue + color_jitter = (float(jitter), ) * 3 # repeat value for brightness, contrast, satuaration, 0 hue T += [A.ColorJitter(*color_jitter, 0)] else: # Use fixed crop for eval set (reproducibility) T = [A.SmallestMaxSize(max_size=size), A.CenterCrop(height=size, width=size)] diff --git a/utils/callbacks.py b/utils/callbacks.py index b444a2ba39..fff6b0356e 100644 --- a/utils/callbacks.py +++ b/utils/callbacks.py @@ -32,7 +32,7 @@ def __init__(self): 'on_model_save': [], 'on_train_end': [], 'on_params_update': [], - 'teardown': [],} + 'teardown': [], } self.stop_training = False # set True to interrupt training def register_action(self, hook, name='', callback=None): diff --git a/utils/downloads.py b/utils/downloads.py index 4c2533625d..27a879e2c6 100644 --- a/utils/downloads.py +++ b/utils/downloads.py @@ -4,7 +4,6 @@ """ import logging -import os import subprocess import urllib from pathlib import Path @@ -53,7 +52,7 @@ def curl_download(url, filename, *, silent: bool = False) -> bool: '--retry', '9', '-C', - '-',]) + '-', ]) return proc.returncode == 0 diff --git a/utils/general.py b/utils/general.py index cf3fc10db1..f49f181985 100644 --- a/utils/general.py +++ b/utils/general.py @@ -139,12 +139,12 @@ def set_logging(name=LOGGING_NAME, verbose=True): name: { 'class': 'logging.StreamHandler', 'formatter': name, - 'level': level,}}, + 'level': level, }}, 'loggers': { name: { 'level': level, 'handlers': [name], - 'propagate': False,}}}) + 'propagate': False, }}}) set_logging(LOGGING_NAME) # run before defining LOGGER @@ -416,7 +416,7 @@ def check_imshow(warn=False): return False -def check_suffix(file='yolov5s.pt', suffix=('.pt',), msg=''): +def check_suffix(file='yolov5s.pt', suffix=('.pt', ), msg=''): # Check file(s) for acceptable suffix if file and suffix: if isinstance(suffix, str): diff --git a/utils/loggers/comet/__init__.py b/utils/loggers/comet/__init__.py index d4599841c9..78d37651f6 100644 --- a/utils/loggers/comet/__init__.py +++ b/utils/loggers/comet/__init__.py @@ -90,7 +90,7 @@ def __init__(self, opt, hyp, run_id=None, job_type='Training', **experiment_kwar 'log_code': False, 'log_env_gpu': True, 'log_env_cpu': True, - 'project_name': COMET_PROJECT_NAME,} + 'project_name': COMET_PROJECT_NAME, } self.default_experiment_kwargs.update(experiment_kwargs) self.experiment = self._get_experiment(self.comet_mode, run_id) @@ -152,7 +152,7 @@ def __init__(self, opt, hyp, run_id=None, job_type='Training', **experiment_kwar 'comet_log_per_class_metrics': COMET_LOG_PER_CLASS_METRICS, 'comet_log_batch_metrics': COMET_LOG_BATCH_METRICS, 'comet_log_confusion_matrix': COMET_LOG_CONFUSION_MATRIX, - 'comet_model_name': COMET_MODEL_NAME,}) + 'comet_model_name': COMET_MODEL_NAME, }) # Check if running the Experiment with the Comet Optimizer if hasattr(self.opt, 'comet_optimizer_id'): @@ -169,7 +169,7 @@ def _get_experiment(self, mode, experiment_id=None): **self.default_experiment_kwargs, ) - return comet_ml.OfflineExperiment(**self.default_experiment_kwargs,) + return comet_ml.OfflineExperiment(**self.default_experiment_kwargs, ) else: try: @@ -213,7 +213,7 @@ def log_model(self, path, opt, epoch, fitness_score, best_model=False): 'fitness_score': fitness_score[-1], 'epochs_trained': epoch + 1, 'save_period': opt.save_period, - 'total_epochs': opt.epochs,} + 'total_epochs': opt.epochs, } model_files = glob.glob(f'{path}/*.pt') for model_path in model_files: @@ -269,7 +269,7 @@ def log_predictions(self, image, labelsn, path, shape, predn): 'x': xyxy[0], 'y': xyxy[1], 'x2': xyxy[2], - 'y2': xyxy[3]},}) + 'y2': xyxy[3]}, }) for *xyxy, conf, cls in filtered_detections.tolist(): metadata.append({ 'label': f'{self.class_names[int(cls)]}', @@ -278,7 +278,7 @@ def log_predictions(self, image, labelsn, path, shape, predn): 'x': xyxy[0], 'y': xyxy[1], 'x2': xyxy[2], - 'y2': xyxy[3]},}) + 'y2': xyxy[3]}, }) self.metadata_dict[image_name] = metadata self.logged_images_count += 1 diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py index d1de86e0d2..f9abf3dff1 100644 --- a/utils/segment/metrics.py +++ b/utils/segment/metrics.py @@ -196,7 +196,7 @@ def ap_class_index(self): 'val/cls_loss', 'x/lr0', 'x/lr1', - 'x/lr2',] + 'x/lr2', ] BEST_KEYS = [ 'best/epoch', @@ -207,4 +207,4 @@ def ap_class_index(self): 'best/precision(M)', 'best/recall(M)', 'best/mAP_0.5(M)', - 'best/mAP_0.5:0.95(M)',] + 'best/mAP_0.5:0.95(M)', ] diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 3aa764a8f6..940c5ba9e6 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -170,7 +170,7 @@ def profile(input, ops, n=10, device=None): m = m.half() if hasattr(m, 'half') and isinstance(x, torch.Tensor) and x.dtype is torch.float16 else m tf, tb, t = 0, 0, [0, 0, 0] # dt forward, backward try: - flops = thop.profile(m, inputs=(x,), verbose=False)[0] / 1E9 * 2 # GFLOPs + flops = thop.profile(m, inputs=(x, ), verbose=False)[0] / 1E9 * 2 # GFLOPs except Exception: flops = 0 @@ -284,7 +284,7 @@ def model_info(model, verbose=False, imgsz=640): p = next(model.parameters()) stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32 # max stride im = torch.empty((1, p.shape[1], stride, stride), device=p.device) # input image in BCHW format - flops = thop.profile(deepcopy(model), inputs=(im,), verbose=False)[0] / 1E9 * 2 # stride GFLOPs + flops = thop.profile(deepcopy(model), inputs=(im, ), verbose=False)[0] / 1E9 * 2 # stride GFLOPs imgsz = imgsz if isinstance(imgsz, list) else [imgsz, imgsz] # expand if int/float fs = f', {flops * imgsz[0] / stride * imgsz[1] / stride:.1f} GFLOPs' # 640x640 GFLOPs except Exception: From 5373026e7c3ffc90969f1e74f1fed33060b47e41 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 23 Jul 2023 03:50:39 +0200 Subject: [PATCH 0990/1185] Update README License and Contact sections (#2093) * Update README.md * Update README.zh-CN.md * Update README.zh-CN.md --- README.md | 6 +++--- README.zh-CN.md | 13 ++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0768a5b696..64527c5e08 100644 --- a/README.md +++ b/README.md @@ -460,10 +460,10 @@ We love your input! We want to make contributing to YOLOv3 as easy and transpare ##
License
-YOLOv3 is available under two different licenses: +Ultralytics offers two licensing options to accommodate diverse use cases: -- **AGPL-3.0 License**: See [LICENSE](https://github.com/ultralytics/yolov5/blob/master/LICENSE) file for details. -- **Enterprise License**: Provides greater flexibility for commercial product development without the open-source requirements of AGPL-3.0. Typical use cases are embedding Ultralytics software and AI models in commercial products and applications. Request an Enterprise License at [Ultralytics Licensing](https://ultralytics.com/license). +- **AGPL-3.0 License**: This [OSI-approved](https://opensource.org/licenses/) open-source license is ideal for students and enthusiasts, promoting open collaboration and knowledge sharing. See the [LICENSE](https://github.com/ultralytics/ultralytics/blob/main/LICENSE) file for more details. +- **Enterprise License**: Designed for commercial use, this license permits seamless integration of Ultralytics software and AI models into commercial goods and services, bypassing the open-source requirements of AGPL-3.0. If your scenario involves embedding our solutions into a commercial offering, reach out through [Ultralytics Licensing](https://ultralytics.com/license). ##
Contact
diff --git a/README.zh-CN.md b/README.zh-CN.md index e22c7926b7..d1a5b46831 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -453,16 +453,16 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu -##
License
+##
许可证
-YOLOv3 在两种不同的 License 下可用: +Ultralytics 提供两种许可证选项以适应各种使用场景: -- **AGPL-3.0 License**: 查看 [License](https://github.com/ultralytics/yolov5/blob/master/LICENSE) 文件的详细信息。 -- **企业License**:在没有 AGPL-3.0 开源要求的情况下为商业产品开发提供更大的灵活性。典型用例是将 Ultralytics 软件和 AI 模型嵌入到商业产品和应用程序中。在以下位置申请企业许可证 [Ultralytics 许可](https://ultralytics.com/license) 。 +- **AGPL-3.0 许可证**:这个[OSI 批准](https://opensource.org/licenses/)的开源许可证非常适合学生和爱好者,可以推动开放的协作和知识分享。请查看[LICENSE](https://github.com/ultralytics/ultralytics/blob/main/LICENSE) 文件以了解更多细节。 +- **企业许可证**:专为商业用途设计,该许可证允许将 Ultralytics 的软件和 AI 模型无缝集成到商业产品和服务中,从而绕过 AGPL-3.0 的开源要求。如果您的场景涉及将我们的解决方案嵌入到商业产品中,请通过 [Ultralytics Licensing](https://ultralytics.com/license)与我们联系。 -##
联系我们
+##
联系方式
-对于 YOLOv8 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://discord.gg/2wNGbc6g9X) 社区进行问题和讨论! +对于 Ultralytics 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://discord.gg/2wNGbc6g9X) 社区进行问题和讨论!
@@ -483,7 +483,6 @@ YOLOv3 在两种不同的 License 下可用: -
From 193b397b097fdf99a856d36444135ae10c9852ac Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 23 Jul 2023 03:58:19 +0200 Subject: [PATCH 0991/1185] Update README.zh-CN.md (#2094) * Update README.zh-CN.md * Update README.zh-CN.md * Update README.md * Update README.md --- README.md | 2 +- README.zh-CN.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 64527c5e08..384a305900 100644 --- a/README.md +++ b/README.md @@ -462,7 +462,7 @@ We love your input! We want to make contributing to YOLOv3 as easy and transpare Ultralytics offers two licensing options to accommodate diverse use cases: -- **AGPL-3.0 License**: This [OSI-approved](https://opensource.org/licenses/) open-source license is ideal for students and enthusiasts, promoting open collaboration and knowledge sharing. See the [LICENSE](https://github.com/ultralytics/ultralytics/blob/main/LICENSE) file for more details. +- **AGPL-3.0 License**: This [OSI-approved](https://opensource.org/licenses/) open-source license is ideal for students and enthusiasts, promoting open collaboration and knowledge sharing. See the [LICENSE](https://github.com/ultralytics/yolov3/blob/master/LICENSE) file for more details. - **Enterprise License**: Designed for commercial use, this license permits seamless integration of Ultralytics software and AI models into commercial goods and services, bypassing the open-source requirements of AGPL-3.0. If your scenario involves embedding our solutions into a commercial offering, reach out through [Ultralytics Licensing](https://ultralytics.com/license). ##
Contact
diff --git a/README.zh-CN.md b/README.zh-CN.md index d1a5b46831..f3996936b0 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -457,7 +457,7 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu Ultralytics 提供两种许可证选项以适应各种使用场景: -- **AGPL-3.0 许可证**:这个[OSI 批准](https://opensource.org/licenses/)的开源许可证非常适合学生和爱好者,可以推动开放的协作和知识分享。请查看[LICENSE](https://github.com/ultralytics/ultralytics/blob/main/LICENSE) 文件以了解更多细节。 +- **AGPL-3.0 许可证**:这个[OSI 批准](https://opensource.org/licenses/)的开源许可证非常适合学生和爱好者,可以推动开放的协作和知识分享。请查看[LICENSE](https://github.com/ultralytics/yolov3/blob/master/LICENSE) 文件以了解更多细节。 - **企业许可证**:专为商业用途设计,该许可证允许将 Ultralytics 的软件和 AI 模型无缝集成到商业产品和服务中,从而绕过 AGPL-3.0 的开源要求。如果您的场景涉及将我们的解决方案嵌入到商业产品中,请通过 [Ultralytics Licensing](https://ultralytics.com/license)与我们联系。 ##
联系方式
@@ -483,6 +483,7 @@ Ultralytics 提供两种许可证选项以适应各种使用场景: + From 98130dd617d97488190e62fa393a1355c1213229 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 24 Jul 2023 16:34:07 +0200 Subject: [PATCH 0992/1185] Update Discord invite to https://ultralytics.com/discord (#2096) --- .github/ISSUE_TEMPLATE/config.yml | 2 +- README.md | 8 ++++---- README.zh-CN.md | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index d676dd9d02..43b61e3beb 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -7,5 +7,5 @@ contact_links: url: https://community.ultralytics.com/ about: Ask on Ultralytics Community Forum - name: 🎧 Discord - url: https://discord.gg/2wNGbc6g9X + url: https://ultralytics.com/discord about: Ask on Ultralytics Discord diff --git a/README.md b/README.md index 384a305900..992a91c5b5 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ YOLOv3 🚀 is the world's most loved vision AI, representing Ultralytics open-source research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours of research and development. -We hope that the resources here will help you get the most out of YOLOv3. Please browse the YOLOv3 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions! +We hope that the resources here will help you get the most out of YOLOv3. Please browse the YOLOv3 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions! To request an Enterprise License please complete the form at [Ultralytics Licensing](https://ultralytics.com/license). @@ -43,7 +43,7 @@ To request an Enterprise License please complete the form at [Ultralytics Licens - + @@ -467,7 +467,7 @@ Ultralytics offers two licensing options to accommodate diverse use cases: ##
Contact
-For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues), and join our [Discord](https://discord.gg/2wNGbc6g9X) community for questions and discussions! +For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues), and join our [Discord](https://ultralytics.com/discord) community for questions and discussions!
@@ -489,7 +489,7 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/ - +
diff --git a/README.zh-CN.md b/README.zh-CN.md index f3996936b0..8f74e3df37 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -19,7 +19,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics 对未来视觉 AI 方法的开源研究,结合在数千小时的研究和开发中积累的经验教训和最佳实践。 -我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 YOLOv3 文档 了解详细信息,在 GitHub 上提交问题以获得支持,并加入我们的 Discord 社区进行问题和讨论! +我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 YOLOv3 文档 了解详细信息,在 GitHub 上提交问题以获得支持,并加入我们的 Discord 社区进行问题和讨论! 如需申请企业许可,请在 [Ultralytics Licensing](https://ultralytics.com/license) 处填写表格 @@ -43,7 +43,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 - + @@ -462,7 +462,7 @@ Ultralytics 提供两种许可证选项以适应各种使用场景: ##
联系方式
-对于 Ultralytics 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://discord.gg/2wNGbc6g9X) 社区进行问题和讨论! +对于 Ultralytics 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://ultralytics.com/discord) 社区进行问题和讨论!
@@ -484,7 +484,7 @@ Ultralytics 提供两种许可证选项以适应各种使用场景: - +
From 6dfdc279b6ad02c46eb698cad2da4cd3afaa549a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 30 Jul 2023 13:58:49 +0200 Subject: [PATCH 0993/1185] Update requirements.txt to `ultralytics 8.0.145` (#2098) Update to `ultralytics 8.0.145` --- requirements.txt | 2 +- utils/__init__.py | 2 +- utils/general.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index 2857407f3c..1cb9608543 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ thop>=0.1.1 # FLOPs computation torch>=1.7.0 # see https://pytorch.org/get-started/locally (recommended) torchvision>=0.8.1 tqdm>=4.64.0 -ultralytics>=8.0.111 +ultralytics>=8.0.145 # protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 # Logging --------------------------------------------------------------------- diff --git a/utils/__init__.py b/utils/__init__.py index 7e74073321..1c05ec0d54 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -54,7 +54,7 @@ def notebook_init(verbose=True): import os import shutil - from ultralytics.yolo.utils.checks import check_requirements + from ultralytics.utils.checks import check_requirements from utils.general import check_font, is_colab from utils.torch_utils import select_device # imports diff --git a/utils/general.py b/utils/general.py index f49f181985..65db2fdc3e 100644 --- a/utils/general.py +++ b/utils/general.py @@ -35,7 +35,7 @@ import torch import torchvision import yaml -from ultralytics.yolo.utils.checks import check_requirements +from ultralytics.utils.checks import check_requirements from utils import TryExcept, emojis from utils.downloads import curl_download, gsutil_getsize From 3d866f05124751d540203e9bc7773969107ff4b2 Mon Sep 17 00:00:00 2001 From: Adrian Boguszewski Date: Sun, 30 Jul 2023 14:20:29 +0200 Subject: [PATCH 0994/1185] Bringing OpenVINO updates from YOLOv8 to YOLOv3 (#2097) Bringing OpenVINO updates from yolov8 to volov3 Co-authored-by: Glenn Jocher --- export.py | 2 +- models/common.py | 16 ++++++++-------- requirements.txt | 2 +- utils/docker/Dockerfile | 2 +- utils/docker/Dockerfile-cpu | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/export.py b/export.py index fc2c800411..be376472d6 100644 --- a/export.py +++ b/export.py @@ -188,7 +188,7 @@ def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr('ONNX @try_export def export_openvino(file, metadata, half, prefix=colorstr('OpenVINO:')): # YOLOv3 OpenVINO export - check_requirements('openvino-dev>=2022.3') # requires openvino-dev: https://pypi.org/project/openvino-dev/ + check_requirements('openvino-dev>=2023.0') # requires openvino-dev: https://pypi.org/project/openvino-dev/ import openvino.runtime as ov # noqa from openvino.tools import mo # noqa diff --git a/models/common.py b/models/common.py index 6ad05380e9..d8f0a0d8ff 100644 --- a/models/common.py +++ b/models/common.py @@ -373,18 +373,18 @@ def __init__(self, weights='yolov5s.pt', device=torch.device('cpu'), dnn=False, stride, names = int(meta['stride']), eval(meta['names']) elif xml: # OpenVINO LOGGER.info(f'Loading {w} for OpenVINO inference...') - check_requirements('openvino') # requires openvino-dev: https://pypi.org/project/openvino-dev/ + check_requirements('openvino>=2023.0') # requires openvino-dev: https://pypi.org/project/openvino-dev/ from openvino.runtime import Core, Layout, get_batch - ie = Core() + core = Core() if not Path(w).is_file(): # if not *.xml w = next(Path(w).glob('*.xml')) # get *.xml file from *_openvino_model dir - network = ie.read_model(model=w, weights=Path(w).with_suffix('.bin')) - if network.get_parameters()[0].get_layout().empty: - network.get_parameters()[0].set_layout(Layout('NCHW')) - batch_dim = get_batch(network) + ov_model = core.read_model(model=w, weights=Path(w).with_suffix('.bin')) + if ov_model.get_parameters()[0].get_layout().empty: + ov_model.get_parameters()[0].set_layout(Layout('NCHW')) + batch_dim = get_batch(ov_model) if batch_dim.is_static: batch_size = batch_dim.get_length() - executable_network = ie.compile_model(network, device_name='CPU') # device_name="MYRIAD" for Intel NCS2 + ov_compiled_model = core.compile_model(ov_model, device_name='AUTO') # AUTO selects best available device stride, names = self._load_metadata(Path(w).with_suffix('.yaml')) # load metadata elif engine: # TensorRT LOGGER.info(f'Loading {w} for TensorRT inference...') @@ -524,7 +524,7 @@ def forward(self, im, augment=False, visualize=False): y = self.session.run(self.output_names, {self.session.get_inputs()[0].name: im}) elif self.xml: # OpenVINO im = im.cpu().numpy() # FP32 - y = list(self.executable_network([im]).values()) + y = list(self.ov_compiled_model(im).values()) elif self.engine: # TensorRT if self.dynamic and im.shape != self.bindings['images'].shape: i = self.model.get_binding_index('images') diff --git a/requirements.txt b/requirements.txt index 1cb9608543..1f74ef3ee6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -36,7 +36,7 @@ seaborn>=0.11.0 # scikit-learn<=1.1.2 # CoreML quantization # tensorflow>=2.4.0 # TF exports (-cpu, -aarch64, -macos) # tensorflowjs>=3.9.0 # TF.js export -# openvino-dev # OpenVINO export +# openvino-dev>=2023.0 # OpenVINO export # Deploy ---------------------------------------------------------------------- setuptools>=65.5.1 # Snyk vulnerability fix diff --git a/utils/docker/Dockerfile b/utils/docker/Dockerfile index b2797f3c18..23a5067223 100644 --- a/utils/docker/Dockerfile +++ b/utils/docker/Dockerfile @@ -32,7 +32,7 @@ COPY requirements.txt . RUN python3 -m pip install --upgrade pip wheel RUN pip install --no-cache nvidia-tensorrt --index-url https://pypi.ngc.nvidia.com RUN pip install --no-cache -r requirements.txt albumentations comet gsutil notebook \ - coremltools onnx onnx-simplifier onnxruntime 'openvino-dev>=2022.3' + coremltools onnx onnx-simplifier onnxruntime 'openvino-dev>=2023.0' # tensorflow tensorflowjs # Set environment variables diff --git a/utils/docker/Dockerfile-cpu b/utils/docker/Dockerfile-cpu index f1543b2efe..a9c782abb0 100644 --- a/utils/docker/Dockerfile-cpu +++ b/utils/docker/Dockerfile-cpu @@ -19,7 +19,7 @@ RUN apt install --no-install-recommends -y python3-pip git zip curl htop libgl1- COPY requirements.txt . RUN python3 -m pip install --upgrade pip wheel RUN pip install --no-cache -r requirements.txt albumentations gsutil notebook \ - coremltools onnx onnx-simplifier onnxruntime 'openvino-dev>=2022.3' \ + coremltools onnx onnx-simplifier onnxruntime 'openvino-dev>=2023.0' \ # tensorflow tensorflowjs \ --extra-index-url https://download.pytorch.org/whl/cpu From 4437181f8da70c7ad6371b0e9c7284b545b021c5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 1 Aug 2023 18:52:16 +0200 Subject: [PATCH 0995/1185] [Snyk] Security upgrade numpy from 1.21.3 to 1.22.2 (#2099) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321964 - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321966 - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321970 Co-authored-by: snyk-bot --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1f74ef3ee6..3dda1b4e68 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ # Base ------------------------------------------------------------------------ gitpython>=3.1.30 matplotlib>=3.3 -numpy>=1.18.5 +numpy>=1.22.2 opencv-python>=4.1.1 Pillow>=7.1.2 psutil # system resources From 251ea948e4d7aa9cefcbafdda4d22089336bdaf6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 1 Aug 2023 22:17:57 +0200 Subject: [PATCH 0996/1185] YOLOv3 downstream updates from YOLOv5 (#2100) * YOLOv3 downstream updates from YOLOv5 * Update val.py * Update train.py * YOLOv3 downstream updates from YOLOv5 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * YOLOv3 downstream updates from YOLOv5 * YOLOv3 downstream updates from YOLOv5 * Update greetings.yml --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/greetings.yml | 14 +- CITATION.cff | 4 +- CONTRIBUTING.md | 10 +- README.md | 2 +- README.zh-CN.md | 6 +- benchmarks.py | 13 +- classify/predict.py | 9 +- classify/train.py | 8 +- classify/tutorial.ipynb | 17 +- classify/val.py | 4 +- data/Argoverse.yaml | 2 +- data/hyps/hyp.VOC.yaml | 2 +- data/hyps/hyp.no-augmentation.yaml | 4 +- data/objects365.yaml | 4 +- data/voc.yaml | 2 +- detect.py | 3 +- export.py | 236 +++++- models/common.py | 2 +- models/tf.py | 2 +- models/yolo.py | 15 +- requirements.txt | 2 +- segment/predict.py | 7 +- segment/train.py | 29 +- segment/tutorial.ipynb | 21 +- segment/val.py | 6 +- train.py | 18 +- tutorial.ipynb | 675 ++++-------------- utils/aws/resume.py | 2 +- utils/dataloaders.py | 19 +- utils/docker/Dockerfile | 5 +- utils/docker/Dockerfile-arm64 | 2 +- utils/docker/Dockerfile-cpu | 15 +- utils/flask_rest_api/restapi.py | 2 +- utils/general.py | 2 +- .../additional_requirements.txt | 1 + utils/loggers/__init__.py | 4 +- utils/loggers/clearml/README.md | 78 +- utils/loggers/clearml/clearml_utils.py | 7 +- utils/loggers/clearml/hpo.py | 2 +- utils/loggers/comet/README.md | 68 +- utils/loggers/comet/__init__.py | 37 +- utils/loggers/comet/comet_utils.py | 4 +- utils/loggers/comet/hpo.py | 4 +- utils/loggers/wandb/wandb_utils.py | 4 +- utils/plots.py | 124 +--- utils/segment/dataloaders.py | 2 +- utils/segment/general.py | 2 +- utils/segment/loss.py | 1 - utils/segment/plots.py | 2 +- val.py | 6 +- 50 files changed, 603 insertions(+), 907 deletions(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index c996efc3a8..8efe82d643 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -18,7 +18,7 @@ jobs: pr-message: | 👋 Hello @${{ github.actor }}, thank you for submitting a YOLOv3 🚀 PR! To allow your work to be integrated as seamlessly as possible, we advise you to: - - ✅ Verify your PR is **up-to-date** with `ultralytics/yolov5` `master` branch. If your PR is behind you can update your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally. + - ✅ Verify your PR is **up-to-date** with `ultralytics/yolov3` `master` branch. If your PR is behind you can update your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally. - ✅ Verify all YOLOv3 Continuous Integration (CI) **checks are passing**. - ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ — Bruce Lee @@ -31,10 +31,10 @@ jobs: ## Requirements - [**Python>=3.7.0**](https://www.python.org/) with all [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) installed including [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). To get started: + [**Python>=3.7.0**](https://www.python.org/) with all [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) installed including [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). To get started: ```bash - git clone https://github.com/ultralytics/yolov5 # clone - cd yolov5 + git clone https://github.com/ultralytics/yolov3 # clone + cd yolov3 pip install -r requirements.txt # install ``` @@ -45,13 +45,13 @@ jobs: - **Notebooks** with free GPU: Run on Gradient Open In Colab Open In Kaggle - **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/) - **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/) - - **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) Docker Pulls + - **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) Docker Pulls ## Status - YOLOv3 CI + YOLOv3 CI - If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov5/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 [training](https://github.com/ultralytics/yolov5/blob/master/train.py), [validation](https://github.com/ultralytics/yolov5/blob/master/val.py), [inference](https://github.com/ultralytics/yolov5/blob/master/detect.py), [export](https://github.com/ultralytics/yolov5/blob/master/export.py) and [benchmarks](https://github.com/ultralytics/yolov5/blob/master/benchmarks.py) on macOS, Windows, and Ubuntu every 24 hours and on every commit. + If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 [training](https://github.com/ultralytics/yolov5/blob/master/train.py), [validation](https://github.com/ultralytics/yolov5/blob/master/val.py), [inference](https://github.com/ultralytics/yolov5/blob/master/detect.py), [export](https://github.com/ultralytics/yolov5/blob/master/export.py) and [benchmarks](https://github.com/ultralytics/yolov5/blob/master/benchmarks.py) on macOS, Windows, and Ubuntu every 24 hours and on every commit. ## Introducing YOLOv8 🚀 diff --git a/CITATION.cff b/CITATION.cff index f371d61015..c277230d92 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,12 +1,12 @@ cff-version: 1.2.0 preferred-citation: type: software - message: If you use , please cite it as below. + message: If you use YOLOv5, please cite it as below. authors: - family-names: Jocher given-names: Glenn orcid: "https://orcid.org/0000-0001-5950-6979" - title: " by Ultralytics" + title: "YOLOv5 by Ultralytics" version: 7.0 doi: 10.5281/zenodo.3908559 date-released: 2020-5-29 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 16b1ecef09..7995069f88 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ ## Contributing to YOLOv3 🚀 -We love your input! We want to make contributing to as easy and transparent as possible, whether it's: +We love your input! We want to make contributing to YOLOv5 as easy and transparent as possible, whether it's: - Reporting a bug - Discussing the current state of the code @@ -8,7 +8,7 @@ We love your input! We want to make contributing to as easy and transparent as p - Proposing a new feature - Becoming a maintainer -works so well due to our combined community effort, and for every small improvement you contribute you will be +YOLOv5 works so well due to our combined community effort, and for every small improvement you contribute you will be helping push the frontiers of what's possible in AI 😃! ## Submitting a Pull Request (PR) 🛠️ @@ -37,7 +37,7 @@ Change the `matplotlib` version from `3.2.2` to `3.3`. Click on the **Preview changes** tab to verify your updates. At the bottom of the screen select 'Create a **new branch** for this commit', assign your branch a descriptive name such as `fix/matplotlib_version` and click the green **Propose -changes** button. All done, your PR is now submitted to for review and approval 😃! +changes** button. All done, your PR is now submitted to YOLOv5 for review and approval 😃!

PR_step4

@@ -50,7 +50,7 @@ To allow your work to be integrated as seamlessly as possible, we advise you to:

Screenshot 2022-08-29 at 22 47 15

-- ✅ Verify all Continuous Integration (CI) **checks are passing**. +- ✅ Verify all YOLOv5 Continuous Integration (CI) **checks are passing**.

Screenshot 2022-08-29 at 22 47 03

@@ -59,7 +59,7 @@ To allow your work to be integrated as seamlessly as possible, we advise you to: ## Submitting a Bug Report 🐛 -If you spot a problem with please submit a Bug Report! +If you spot a problem with YOLOv5 please submit a Bug Report! For us to start investigating a possible problem we need to be able to reproduce it ourselves first. We've created a few short guidelines below to help users provide what we need to get started. diff --git a/README.md b/README.md index 992a91c5b5..1cb8fc29eb 100644 --- a/README.md +++ b/README.md @@ -439,7 +439,7 @@ Get started in seconds with our verified environments. Click each icon below for - + diff --git a/README.zh-CN.md b/README.zh-CN.md index 8f74e3df37..7340f43d09 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -7,9 +7,9 @@ [英文](README.md)|[简体中文](README.zh-CN.md)
- YOLOv3 CI + YOLOv3 CI YOLOv3 Citation - Docker Pulls + Docker Pulls
Run on Gradient Open In Colab @@ -434,7 +434,7 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu - + diff --git a/benchmarks.py b/benchmarks.py index d4c57e9b00..cbc5b20499 100644 --- a/benchmarks.py +++ b/benchmarks.py @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Run benchmarks on all supported export formats +Run YOLOv3 benchmarks on all supported export formats Format | `export.py --include` | Model --- | --- | --- @@ -34,7 +34,7 @@ import pandas as pd FILE = Path(__file__).resolve() -ROOT = FILE.parents[0] # root directory +ROOT = FILE.parents[0] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH # ROOT = ROOT.relative_to(Path.cwd()) # relative @@ -76,7 +76,12 @@ def run( if f == '-': w = weights # PyTorch format else: - w = export.run(weights=weights, imgsz=[imgsz], include=[f], device=device, half=half)[-1] # all others + w = export.run(weights=weights, + imgsz=[imgsz], + include=[f], + batch_size=batch_size, + device=device, + half=half)[-1] # all others assert suffix in str(w), 'export failed' # Validate @@ -145,7 +150,7 @@ def test( def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='weights path') + parser.add_argument('--weights', type=str, default=ROOT / 'yolov3-tiny.pt', help='weights path') parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') parser.add_argument('--batch-size', type=int, default=1, help='batch size') parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') diff --git a/classify/predict.py b/classify/predict.py index 0f48d93ea4..5ebbfe9aae 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Run classification inference on images, videos, directories, globs, YouTube, webcam, streams, etc. +Run YOLOv3 classification inference on images, videos, directories, globs, YouTube, webcam, streams, etc. Usage - sources: $ python classify/predict.py --weights yolov5s-cls.pt --source 0 # webcam @@ -38,17 +38,18 @@ import torch.nn.functional as F FILE = Path(__file__).resolve() -ROOT = FILE.parents[1] # root directory +ROOT = FILE.parents[1] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative +from ultralytics.utils.plotting import Annotator + from models.common import DetectMultiBackend from utils.augmentations import classify_transforms from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, increment_path, print_args, strip_optimizer) -from utils.plots import Annotator from utils.torch_utils import select_device, smart_inference_mode @@ -144,7 +145,7 @@ def run( # Write results text = '\n'.join(f'{prob[j]:.2f} {names[j]}' for j in top5i) if save_img or view_img: # Add bbox to image - annotator.text((32, 32), text, txt_color=(255, 255, 255)) + annotator.text([32, 32], text, txt_color=(255, 255, 255)) if save_txt: # Write to file with open(f'{txt_path}.txt', 'a') as f: f.write(text + '\n') diff --git a/classify/train.py b/classify/train.py index 9da4e3c445..1a3e0511f4 100644 --- a/classify/train.py +++ b/classify/train.py @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Train a YOLOv5 classifier model on a classification dataset +Train a YOLOv3 classifier model on a classification dataset Usage - Single-GPU training: $ python classify/train.py --model yolov5s-cls.pt --data imagenette160 --epochs 5 --img 224 @@ -9,7 +9,7 @@ $ python -m torch.distributed.run --nproc_per_node 4 --master_port 2022 classify/train.py --model yolov5s-cls.pt --data imagenet --epochs 5 --img 224 --device 0,1,2,3 Datasets: --data mnist, fashion-mnist, cifar10, cifar100, imagenette, imagewoof, imagenet, or 'path/to/data' -YOLOv5-cls models: --model yolov5n-cls.pt, yolov5s-cls.pt, yolov5m-cls.pt, yolov5l-cls.pt, yolov5x-cls.pt +YOLOv3-cls models: --model yolov5n-cls.pt, yolov5s-cls.pt, yolov5m-cls.pt, yolov5l-cls.pt, yolov5x-cls.pt Torchvision models: --model resnet50, efficientnet_b0, etc. See https://pytorch.org/vision/stable/models.html """ @@ -31,7 +31,7 @@ from tqdm import tqdm FILE = Path(__file__).resolve() -ROOT = FILE.parents[1] # YOLOv5 root directory +ROOT = FILE.parents[1] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative @@ -115,7 +115,7 @@ def train(opt, device): m = hub.list('ultralytics/yolov5') # + hub.list('pytorch/vision') # models raise ModuleNotFoundError(f'--model {opt.model} not found. Available models are: \n' + '\n'.join(m)) if isinstance(model, DetectionModel): - LOGGER.warning("WARNING ⚠️ pass YOLOv5 classifier model with '-cls' suffix, i.e. '--model yolov5s-cls.pt'") + LOGGER.warning("WARNING ⚠️ pass YOLOv3 classifier model with '-cls' suffix, i.e. '--model yolov5s-cls.pt'") model = ClassificationModel(model=model, nc=nc, cutoff=opt.cutoff or 10) # convert to classification model reshape_classifier_output(model, nc) # update class count for m in model.modules(): diff --git a/classify/tutorial.ipynb b/classify/tutorial.ipynb index 42ef67b450..5aa7237161 100644 --- a/classify/tutorial.ipynb +++ b/classify/tutorial.ipynb @@ -18,7 +18,7 @@ " \"Open\n", "
\n", "\n", - "This YOLOv3 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", + "This YOLOv5 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", "\n", "
" ] @@ -49,7 +49,7 @@ "output_type": "stream", "name": "stderr", "text": [ - "YOLOv3 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n" + "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n" ] }, { @@ -1255,16 +1255,17 @@ "outputs": [], "source": [ "#@title Select YOLOv5 🚀 logger {run: 'auto'}\n", - "logger = 'TensorBoard' #@param ['TensorBoard', 'Comet', 'ClearML']\n", + "logger = 'Comet' #@param ['Comet', 'ClearML', 'TensorBoard']\n", "\n", - "if logger == 'TensorBoard':\n", - " %load_ext tensorboard\n", - " %tensorboard --logdir runs/train\n", - "elif logger == 'Comet':\n", + "if logger == 'Comet':\n", " %pip install -q comet_ml\n", " import comet_ml; comet_ml.init()\n", "elif logger == 'ClearML':\n", - " import clearml; clearml.browser_login()" + " %pip install -q clearml\n", + " import clearml; clearml.browser_login()\n", + "elif logger == 'TensorBoard':\n", + " %load_ext tensorboard\n", + " %tensorboard --logdir runs/train" ] }, { diff --git a/classify/val.py b/classify/val.py index 827b626217..6e2deca78e 100644 --- a/classify/val.py +++ b/classify/val.py @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Validate a trained YOLOv5 classification model on a classification dataset +Validate a trained YOLOv3 classification model on a classification dataset Usage: $ bash data/scripts/get_imagenet.sh --val # download ImageNet val split (6.3G, 50000 images) @@ -29,7 +29,7 @@ from tqdm import tqdm FILE = Path(__file__).resolve() -ROOT = FILE.parents[1] # root directory +ROOT = FILE.parents[1] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative diff --git a/data/Argoverse.yaml b/data/Argoverse.yaml index 794718a4c0..a7dc0c6927 100644 --- a/data/Argoverse.yaml +++ b/data/Argoverse.yaml @@ -36,7 +36,7 @@ download: | def argoverse2yolo(set): labels = {} a = json.load(open(set, "rb")) - for annot in tqdm(a['annotations'], desc=f"Converting {set} to YOLOv3 format..."): + for annot in tqdm(a['annotations'], desc=f"Converting {set} to YOLOv5 format..."): img_id = annot['image_id'] img_name = a['images'][img_id]['name'] img_label_name = f'{img_name[:-3]}txt' diff --git a/data/hyps/hyp.VOC.yaml b/data/hyps/hyp.VOC.yaml index 45d82370a6..9831eb0fab 100644 --- a/data/hyps/hyp.VOC.yaml +++ b/data/hyps/hyp.VOC.yaml @@ -3,7 +3,7 @@ # python train.py --batch 128 --weights yolov5m6.pt --data VOC.yaml --epochs 50 --img 512 --hyp hyp.scratch-med.yaml --evolve # See Hyperparameter Evolution tutorial for details https://github.com/ultralytics/yolov5#tutorials -# YOLOv5 Hyperparameter Evolution Results +# YOLOv3 Hyperparameter Evolution Results # Best generation: 467 # Last generation: 996 # metrics/precision, metrics/recall, metrics/mAP_0.5, metrics/mAP_0.5:0.95, val/box_loss, val/obj_loss, val/cls_loss diff --git a/data/hyps/hyp.no-augmentation.yaml b/data/hyps/hyp.no-augmentation.yaml index 76c01e9cc0..6206d039fb 100644 --- a/data/hyps/hyp.no-augmentation.yaml +++ b/data/hyps/hyp.no-augmentation.yaml @@ -1,7 +1,7 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Hyperparameters when using Albumentations frameworks # python train.py --hyp hyp.no-augmentation.yaml -# See https://github.com/ultralytics/yolov5/pull/3882 for YOLOv5 + Albumentations Usage examples +# See https://github.com/ultralytics/yolov5/pull/3882 for YOLOv3 + Albumentations Usage examples lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) @@ -21,7 +21,7 @@ anchor_t: 4.0 # anchor-multiple threshold # this parameters are all zero since we want to use albumentation framework fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) hsv_h: 0 # image HSV-Hue augmentation (fraction) -hsv_s: 00 # image HSV-Saturation augmentation (fraction) +hsv_s: 0 # image HSV-Saturation augmentation (fraction) hsv_v: 0 # image HSV-Value augmentation (fraction) degrees: 0.0 # image rotation (+/- deg) translate: 0 # image translation (+/- fraction) diff --git a/data/objects365.yaml b/data/objects365.yaml index 38372be380..d4045e2f85 100644 --- a/data/objects365.yaml +++ b/data/objects365.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license # Objects365 dataset https://www.objects365.org/ by Megvii # Example usage: python train.py --data Objects365.yaml # parent @@ -428,7 +428,7 @@ download: | path = Path(im["file_name"]) # image filename try: with open(labels / path.with_suffix('.txt').name, 'a') as file: - annIds = coco.getAnnIds(imgIds=im["id"], catIds=catIds, iscrowd=None) + annIds = coco.getAnnIds(imgIds=im["id"], catIds=catIds, iscrowd=False) for a in coco.loadAnns(annIds): x, y, w, h = a['bbox'] # bounding box in xywh (xy top-left corner) xyxy = np.array([x, y, x + w, y + h])[None] # pixels(1,4) diff --git a/data/voc.yaml b/data/voc.yaml index 555ae0d7bb..104856f0c9 100644 --- a/data/voc.yaml +++ b/data/voc.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license # PASCAL VOC dataset http://host.robots.ox.ac.uk/pascal/VOC by University of Oxford # Example usage: python train.py --data VOC.yaml # parent diff --git a/detect.py b/detect.py index 37cbfb4043..0f3898487e 100644 --- a/detect.py +++ b/detect.py @@ -42,11 +42,12 @@ sys.path.append(str(ROOT)) # add ROOT to PATH ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative +from ultralytics.utils.plotting import Annotator, colors, save_one_box + from models.common import DetectMultiBackend from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, increment_path, non_max_suppression, print_args, scale_boxes, strip_optimizer, xyxy2xywh) -from utils.plots import Annotator, colors, save_one_box from utils.torch_utils import select_device, smart_inference_mode diff --git a/export.py b/export.py index be376472d6..93f2b888e5 100644 --- a/export.py +++ b/export.py @@ -77,6 +77,25 @@ MACOS = platform.system() == 'Darwin' # macOS environment +class iOSModel(torch.nn.Module): + + def __init__(self, model, im): + super().__init__() + b, c, h, w = im.shape # batch, channel, height, width + self.model = model + self.nc = model.nc # number of classes + if w == h: + self.normalize = 1. / w + else: + self.normalize = torch.tensor([1. / w, 1. / h, 1. / w, 1. / h]) # broadcast (slower, smaller) + # np = model(im)[0].shape[1] # number of points + # self.normalize = torch.tensor([1. / w, 1. / h, 1. / w, 1. / h]).expand(np, 4) # explicit (faster, larger) + + def forward(self, x): + xywh, conf, cls = self.model(x)[0].squeeze().split((4, 1, self.nc), 1) + return cls * conf, xywh * self.normalize # confidence (3780, 80), coordinates (3780, 4) + + def export_formats(): # YOLOv3 export formats x = [ @@ -186,7 +205,7 @@ def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr('ONNX @try_export -def export_openvino(file, metadata, half, prefix=colorstr('OpenVINO:')): +def export_openvino(file, metadata, half, int8, data, prefix=colorstr('OpenVINO:')): # YOLOv3 OpenVINO export check_requirements('openvino-dev>=2023.0') # requires openvino-dev: https://pypi.org/project/openvino-dev/ import openvino.runtime as ov # noqa @@ -196,8 +215,56 @@ def export_openvino(file, metadata, half, prefix=colorstr('OpenVINO:')): f = str(file).replace(file.suffix, f'_openvino_model{os.sep}') f_onnx = file.with_suffix('.onnx') f_ov = str(Path(f) / file.with_suffix('.xml').name) - - ov_model = mo.convert_model(f_onnx, model_name=file.stem, framework='onnx', compress_to_fp16=half) # export + if int8: + check_requirements('nncf>=2.4.0') # requires at least version 2.4.0 to use the post-training quantization + import nncf + import numpy as np + from openvino.runtime import Core + + from utils.dataloaders import create_dataloader + core = Core() + onnx_model = core.read_model(f_onnx) # export + + def prepare_input_tensor(image: np.ndarray): + input_tensor = image.astype(np.float32) # uint8 to fp16/32 + input_tensor /= 255.0 # 0 - 255 to 0.0 - 1.0 + + if input_tensor.ndim == 3: + input_tensor = np.expand_dims(input_tensor, 0) + return input_tensor + + def gen_dataloader(yaml_path, task='train', imgsz=640, workers=4): + data_yaml = check_yaml(yaml_path) + data = check_dataset(data_yaml) + dataloader = create_dataloader(data[task], + imgsz=imgsz, + batch_size=1, + stride=32, + pad=0.5, + single_cls=False, + rect=False, + workers=workers)[0] + return dataloader + + # noqa: F811 + + def transform_fn(data_item): + """ + Quantization transform function. Extracts and preprocess input data from dataloader item for quantization. + Parameters: + data_item: Tuple with data item produced by DataLoader during iteration + Returns: + input_tensor: Input data for quantization + """ + img = data_item[0].numpy() + input_tensor = prepare_input_tensor(img) + return input_tensor + + ds = gen_dataloader(data) + quantization_dataset = nncf.Dataset(ds, transform_fn) + ov_model = nncf.quantize(onnx_model, quantization_dataset, preset=nncf.QuantizationPreset.MIXED) + else: + ov_model = mo.convert_model(f_onnx, model_name=file.stem, framework='onnx', compress_to_fp16=half) # export ov.serialize(ov_model, f_ov) # save yaml_save(Path(f) / file.with_suffix('.yaml').name, metadata) # add metadata.yaml @@ -220,7 +287,7 @@ def export_paddle(model, im, file, metadata, prefix=colorstr('PaddlePaddle:')): @try_export -def export_coreml(model, im, file, int8, half, prefix=colorstr('CoreML:')): +def export_coreml(model, im, file, int8, half, nms, prefix=colorstr('CoreML:')): # YOLOv3 CoreML export check_requirements('coremltools') import coremltools as ct @@ -228,6 +295,8 @@ def export_coreml(model, im, file, int8, half, prefix=colorstr('CoreML:')): LOGGER.info(f'\n{prefix} starting export with coremltools {ct.__version__}...') f = file.with_suffix('.mlmodel') + if nms: + model = iOSModel(model, im) ts = torch.jit.trace(model, im, strict=False) # TorchScript model ct_model = ct.convert(ts, inputs=[ct.ImageType('image', shape=im.shape, scale=1 / 255, bias=[0, 0, 0])]) bits, mode = (8, 'kmeans_lut') if int8 else (16, 'linear') if half else (32, None) @@ -410,7 +479,7 @@ def export_edgetpu(file, prefix=colorstr('Edge TPU:')): cmd = 'edgetpu_compiler --version' help_url = 'https://coral.ai/docs/edgetpu/compiler/' assert platform.system() == 'Linux', f'export only supported on Linux. See {help_url}' - if subprocess.run(f'{cmd} >/dev/null', shell=True).returncode != 0: + if subprocess.run(f'{cmd} > /dev/null 2>&1', shell=True).returncode != 0: LOGGER.info(f'\n{prefix} export requires Edge TPU compiler. Attempting install from {help_url}') sudo = subprocess.run('sudo --version >/dev/null', shell=True).returncode == 0 # sudo installed on system for c in ( @@ -424,8 +493,15 @@ def export_edgetpu(file, prefix=colorstr('Edge TPU:')): f = str(file).replace('.pt', '-int8_edgetpu.tflite') # Edge TPU model f_tfl = str(file).replace('.pt', '-int8.tflite') # TFLite model - cmd = f'edgetpu_compiler -s -d -k 10 --out_dir {file.parent} {f_tfl}' - subprocess.run(cmd.split(), check=True) + subprocess.run([ + 'edgetpu_compiler', + '-s', + '-d', + '-k', + '10', + '--out_dir', + str(file.parent), + f_tfl, ], check=True) return f, None @@ -440,11 +516,14 @@ def export_tfjs(file, int8, prefix=colorstr('TensorFlow.js:')): f_pb = file.with_suffix('.pb') # *.pb path f_json = f'{f}/model.json' # *.json path - int8_export = ' --quantize_uint8 ' if int8 else '' - - cmd = f'tensorflowjs_converter --input_format=tf_frozen_model {int8_export}' \ - f'--output_node_names=Identity,Identity_1,Identity_2,Identity_3 {f_pb} {f}' - subprocess.run(cmd.split()) + args = [ + 'tensorflowjs_converter', + '--input_format=tf_frozen_model', + '--quantize_uint8' if int8 else '', + '--output_node_names=Identity,Identity_1,Identity_2,Identity_3', + str(f_pb), + str(f), ] + subprocess.run([arg for arg in args if arg], check=True) json = Path(f_json).read_text() with open(f_json, 'w') as j: # sort JSON Identity_* in ascending order @@ -493,6 +572,129 @@ def add_tflite_metadata(file, metadata, num_outputs): tmp_file.unlink() +def pipeline_coreml(model, im, file, names, y, prefix=colorstr('CoreML Pipeline:')): + # YOLOv3 CoreML pipeline + import coremltools as ct + from PIL import Image + + print(f'{prefix} starting pipeline with coremltools {ct.__version__}...') + batch_size, ch, h, w = list(im.shape) # BCHW + t = time.time() + + # YOLOv3 Output shapes + spec = model.get_spec() + out0, out1 = iter(spec.description.output) + if platform.system() == 'Darwin': + img = Image.new('RGB', (w, h)) # img(192 width, 320 height) + # img = torch.zeros((*opt.img_size, 3)).numpy() # img size(320,192,3) iDetection + out = model.predict({'image': img}) + out0_shape, out1_shape = out[out0.name].shape, out[out1.name].shape + else: # linux and windows can not run model.predict(), get sizes from pytorch output y + s = tuple(y[0].shape) + out0_shape, out1_shape = (s[1], s[2] - 5), (s[1], 4) # (3780, 80), (3780, 4) + + # Checks + nx, ny = spec.description.input[0].type.imageType.width, spec.description.input[0].type.imageType.height + na, nc = out0_shape + # na, nc = out0.type.multiArrayType.shape # number anchors, classes + assert len(names) == nc, f'{len(names)} names found for nc={nc}' # check + + # Define output shapes (missing) + out0.type.multiArrayType.shape[:] = out0_shape # (3780, 80) + out1.type.multiArrayType.shape[:] = out1_shape # (3780, 4) + # spec.neuralNetwork.preprocessing[0].featureName = '0' + + # Flexible input shapes + # from coremltools.models.neural_network import flexible_shape_utils + # s = [] # shapes + # s.append(flexible_shape_utils.NeuralNetworkImageSize(320, 192)) + # s.append(flexible_shape_utils.NeuralNetworkImageSize(640, 384)) # (height, width) + # flexible_shape_utils.add_enumerated_image_sizes(spec, feature_name='image', sizes=s) + # r = flexible_shape_utils.NeuralNetworkImageSizeRange() # shape ranges + # r.add_height_range((192, 640)) + # r.add_width_range((192, 640)) + # flexible_shape_utils.update_image_size_range(spec, feature_name='image', size_range=r) + + # Print + print(spec.description) + + # Model from spec + model = ct.models.MLModel(spec) + + # 3. Create NMS protobuf + nms_spec = ct.proto.Model_pb2.Model() + nms_spec.specificationVersion = 5 + for i in range(2): + decoder_output = model._spec.description.output[i].SerializeToString() + nms_spec.description.input.add() + nms_spec.description.input[i].ParseFromString(decoder_output) + nms_spec.description.output.add() + nms_spec.description.output[i].ParseFromString(decoder_output) + + nms_spec.description.output[0].name = 'confidence' + nms_spec.description.output[1].name = 'coordinates' + + output_sizes = [nc, 4] + for i in range(2): + ma_type = nms_spec.description.output[i].type.multiArrayType + ma_type.shapeRange.sizeRanges.add() + ma_type.shapeRange.sizeRanges[0].lowerBound = 0 + ma_type.shapeRange.sizeRanges[0].upperBound = -1 + ma_type.shapeRange.sizeRanges.add() + ma_type.shapeRange.sizeRanges[1].lowerBound = output_sizes[i] + ma_type.shapeRange.sizeRanges[1].upperBound = output_sizes[i] + del ma_type.shape[:] + + nms = nms_spec.nonMaximumSuppression + nms.confidenceInputFeatureName = out0.name # 1x507x80 + nms.coordinatesInputFeatureName = out1.name # 1x507x4 + nms.confidenceOutputFeatureName = 'confidence' + nms.coordinatesOutputFeatureName = 'coordinates' + nms.iouThresholdInputFeatureName = 'iouThreshold' + nms.confidenceThresholdInputFeatureName = 'confidenceThreshold' + nms.iouThreshold = 0.45 + nms.confidenceThreshold = 0.25 + nms.pickTop.perClass = True + nms.stringClassLabels.vector.extend(names.values()) + nms_model = ct.models.MLModel(nms_spec) + + # 4. Pipeline models together + pipeline = ct.models.pipeline.Pipeline(input_features=[('image', ct.models.datatypes.Array(3, ny, nx)), + ('iouThreshold', ct.models.datatypes.Double()), + ('confidenceThreshold', ct.models.datatypes.Double())], + output_features=['confidence', 'coordinates']) + pipeline.add_model(model) + pipeline.add_model(nms_model) + + # Correct datatypes + pipeline.spec.description.input[0].ParseFromString(model._spec.description.input[0].SerializeToString()) + pipeline.spec.description.output[0].ParseFromString(nms_model._spec.description.output[0].SerializeToString()) + pipeline.spec.description.output[1].ParseFromString(nms_model._spec.description.output[1].SerializeToString()) + + # Update metadata + pipeline.spec.specificationVersion = 5 + pipeline.spec.description.metadata.versionString = 'https://github.com/ultralytics/yolov5' + pipeline.spec.description.metadata.shortDescription = 'https://github.com/ultralytics/yolov5' + pipeline.spec.description.metadata.author = 'glenn.jocher@ultralytics.com' + pipeline.spec.description.metadata.license = 'https://github.com/ultralytics/yolov5/blob/master/LICENSE' + pipeline.spec.description.metadata.userDefined.update({ + 'classes': ','.join(names.values()), + 'iou_threshold': str(nms.iouThreshold), + 'confidence_threshold': str(nms.confidenceThreshold)}) + + # Save the model + f = file.with_suffix('.mlmodel') # filename + model = ct.models.MLModel(pipeline.spec) + model.input_description['image'] = 'Input image' + model.input_description['iouThreshold'] = f'(optional) IOU Threshold override (default: {nms.iouThreshold})' + model.input_description['confidenceThreshold'] = \ + f'(optional) Confidence Threshold override (default: {nms.confidenceThreshold})' + model.output_description['confidence'] = 'Boxes × Class confidence (see user-defined metadata "classes")' + model.output_description['coordinates'] = 'Boxes × [x, y, width, height] (relative to image size)' + model.save(f) # pipelined + print(f'{prefix} pipeline success ({time.time() - t:.2f}s), saved as {f} ({file_size(f):.1f} MB)') + + @smart_inference_mode() def run( data=ROOT / 'data/coco128.yaml', # 'dataset.yaml path' @@ -569,9 +771,11 @@ def run( if onnx or xml: # OpenVINO requires ONNX f[2], _ = export_onnx(model, im, file, opset, dynamic, simplify) if xml: # OpenVINO - f[3], _ = export_openvino(file, metadata, half) + f[3], _ = export_openvino(file, metadata, half, int8, data) if coreml: # CoreML - f[4], _ = export_coreml(model, im, file, int8, half) + f[4], ct_model = export_coreml(model, im, file, int8, half, nms) + if nms: + pipeline_coreml(ct_model, im, file, model.names, y) if any((saved_model, pb, tflite, edgetpu, tfjs)): # TensorFlow formats assert not tflite or not tfjs, 'TFLite and TF.js models must be exported separately, please pass only one type.' assert not isinstance(model, ClassificationModel), 'ClassificationModel export to TF formats not yet supported.' @@ -624,10 +828,10 @@ def parse_opt(known=False): parser.add_argument('--batch-size', type=int, default=1, help='batch size') parser.add_argument('--device', default='cpu', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--half', action='store_true', help='FP16 half-precision export') - parser.add_argument('--inplace', action='store_true', help='set Detect() inplace=True') + parser.add_argument('--inplace', action='store_true', help='set YOLOv3 Detect() inplace=True') parser.add_argument('--keras', action='store_true', help='TF: use Keras') parser.add_argument('--optimize', action='store_true', help='TorchScript: optimize for mobile') - parser.add_argument('--int8', action='store_true', help='CoreML/TF INT8 quantization') + parser.add_argument('--int8', action='store_true', help='CoreML/TF/OpenVINO INT8 quantization') parser.add_argument('--dynamic', action='store_true', help='ONNX/TF/TensorRT: dynamic axes') parser.add_argument('--simplify', action='store_true', help='ONNX: simplify model') parser.add_argument('--opset', type=int, default=17, help='ONNX: opset version') diff --git a/models/common.py b/models/common.py index d8f0a0d8ff..152b861f60 100644 --- a/models/common.py +++ b/models/common.py @@ -23,13 +23,13 @@ import torch.nn as nn from PIL import Image from torch.cuda import amp +from ultralytics.utils.plotting import Annotator, colors, save_one_box from utils import TryExcept from utils.dataloaders import exif_transpose, letterbox from utils.general import (LOGGER, ROOT, Profile, check_requirements, check_suffix, check_version, colorstr, increment_path, is_jupyter, make_divisible, non_max_suppression, scale_boxes, xywh2xyxy, xyxy2xywh, yaml_load) -from utils.plots import Annotator, colors, save_one_box from utils.torch_utils import copy_attr, smart_inference_mode diff --git a/models/tf.py b/models/tf.py index d9ce958d45..a933918e14 100644 --- a/models/tf.py +++ b/models/tf.py @@ -589,7 +589,7 @@ def run( def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='weights path') + parser.add_argument('--weights', type=str, default=ROOT / 'yolov3-tiny.pt', help='weights path') parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') parser.add_argument('--batch-size', type=int, default=1, help='batch size') parser.add_argument('--dynamic', action='store_true', help='dynamic batch size') diff --git a/models/yolo.py b/models/yolo.py index ac7fa95ee9..0cc5dfc1ba 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -7,6 +7,7 @@ """ import argparse +import contextlib import os import platform import sys @@ -239,7 +240,7 @@ def _descale_pred(self, p, flips, scale, img_size): return p def _clip_augmented(self, y): - # Clip augmented inference tails + # Clip YOLOv3 augmented inference tails nl = self.model[-1].nl # number of detection layers (P3-P5) g = sum(4 ** x for x in range(nl)) # grid points e = 1 # exclude layer count @@ -260,23 +261,23 @@ def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is mi.bias = torch.nn.Parameter(b.view(-1), requires_grad=True) -Model = DetectionModel # retain 'Model' class for backwards compatibility +Model = DetectionModel # retain YOLOv3 'Model' class for backwards compatibility class SegmentationModel(DetectionModel): - # segmentation model + # YOLOv3 segmentation model def __init__(self, cfg='yolov5s-seg.yaml', ch=3, nc=None, anchors=None): super().__init__(cfg, ch, nc, anchors) class ClassificationModel(BaseModel): - # classification model + # YOLOv3 classification model def __init__(self, cfg=None, model=None, nc=1000, cutoff=10): # yaml, model, number of classes, cutoff index super().__init__() self._from_detection_model(model, nc, cutoff) if model is not None else self._from_yaml(cfg) def _from_detection_model(self, model, nc=1000, cutoff=10): - # Create a classification model from a detection model + # Create a YOLOv3 classification model from a YOLOv3 detection model if isinstance(model, DetectMultiBackend): model = model.model # unwrap DetectMultiBackend model.model = model.model[:cutoff] # backbone @@ -291,12 +292,12 @@ def _from_detection_model(self, model, nc=1000, cutoff=10): self.nc = nc def _from_yaml(self, cfg): - # Create a classification model from a *.yaml file + # Create a YOLOv3 classification model from a *.yaml file self.model = None def parse_model(d, ch): # model_dict, input_channels(3) - # Parse a model.yaml dictionary + # Parse a YOLOv3 model.yaml dictionary LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}") anchors, nc, gd, gw, act = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'], d.get('activation') if act: diff --git a/requirements.txt b/requirements.txt index 3dda1b4e68..e00ba300e5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ thop>=0.1.1 # FLOPs computation torch>=1.7.0 # see https://pytorch.org/get-started/locally (recommended) torchvision>=0.8.1 tqdm>=4.64.0 -ultralytics>=8.0.145 +ultralytics>=8.0.146 # protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 # Logging --------------------------------------------------------------------- diff --git a/segment/predict.py b/segment/predict.py index 184502c5ee..694b47a763 100644 --- a/segment/predict.py +++ b/segment/predict.py @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Run segmentation inference on images, videos, directories, streams, etc. +Run YOLOv3 segmentation inference on images, videos, directories, streams, etc. Usage - sources: $ python segment/predict.py --weights yolov5s-seg.pt --source 0 # webcam @@ -37,17 +37,18 @@ import torch FILE = Path(__file__).resolve() -ROOT = FILE.parents[1] # root directory +ROOT = FILE.parents[1] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative +from ultralytics.utils.plotting import Annotator, colors, save_one_box + from models.common import DetectMultiBackend from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, increment_path, non_max_suppression, print_args, scale_boxes, scale_segments, strip_optimizer) -from utils.plots import Annotator, colors, save_one_box from utils.segment.general import masks2segments, process_mask, process_mask_native from utils.torch_utils import select_device, smart_inference_mode diff --git a/segment/train.py b/segment/train.py index b7f8c1c723..ea7e7bf99b 100644 --- a/segment/train.py +++ b/segment/train.py @@ -1,7 +1,7 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Train a segment model on a segment dataset -Models and datasets download automatically from the latest release. +Train a YOLOv3 segment model on a segment dataset +Models and datasets download automatically from the latest YOLOv3 release. Usage - Single-GPU training: $ python segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 # from pretrained (recommended) @@ -35,7 +35,7 @@ from tqdm import tqdm FILE = Path(__file__).resolve() -ROOT = FILE.parents[1] # root directory +ROOT = FILE.parents[1] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative @@ -68,7 +68,8 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze, mask_ratio = \ - Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze, opt.mask_ratio + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ + opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze, opt.mask_ratio # callbacks.run('on_pretrain_routine_start') # Directories @@ -300,7 +301,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Multi-scale if opt.multi_scale: - sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size + sz = random.randrange(int(imgsz * 0.5), int(imgsz * 1.5) + gs) // gs * gs # size sf = sz / max(imgs.shape[2:]) # scale factor if sf != 1: ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) @@ -531,8 +532,8 @@ def main(opt, callbacks=Callbacks()): check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' if opt.evolve: - if opt.project == str(ROOT / 'runs/train'): # if default project name, rename to runs/evolve - opt.project = str(ROOT / 'runs/evolve') + if opt.project == str(ROOT / 'runs/train-seg'): # if default project name, rename to runs/evolve-seg + opt.project = str(ROOT / 'runs/evolve-seg') opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume if opt.name == 'cfg': opt.name = Path(opt.cfg).stem # use model.yaml as name @@ -541,7 +542,7 @@ def main(opt, callbacks=Callbacks()): # DDP mode device = select_device(opt.device, batch_size=opt.batch_size) if LOCAL_RANK != -1: - msg = 'is not compatible with YOLOv5 Multi-GPU DDP training' + msg = 'is not compatible with YOLOv3 Multi-GPU DDP training' assert not opt.image_weights, f'--image-weights {msg}' assert not opt.evolve, f'--evolve {msg}' assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size' @@ -599,8 +600,12 @@ def main(opt, callbacks=Callbacks()): # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' if opt.bucket: - subprocess.run( - f'gsutil cp gs://{opt.bucket}/evolve.csv {evolve_csv}'.split()) # download evolve.csv if exists + # download evolve.csv if exists + subprocess.run([ + 'gsutil', + 'cp', + f'gs://{opt.bucket}/evolve.csv', + str(evolve_csv), ]) for _ in range(opt.evolve): # generations to evolve if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate @@ -626,7 +631,7 @@ def main(opt, callbacks=Callbacks()): while all(v == 1): # mutate until a change occurs (prevent duplicates) v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) - hyp[k] = float(x[i + 7] * v[i]) # mutate + hyp[k] = float(x[i + 12] * v[i]) # mutate # Constrain to limits for k, v in meta.items(): @@ -638,7 +643,7 @@ def main(opt, callbacks=Callbacks()): results = train(hyp.copy(), opt, device, callbacks) callbacks = Callbacks() # Write mutation results - print_mutation(KEYS, results, hyp.copy(), save_dir, opt.bucket) + print_mutation(KEYS[4:16], results, hyp.copy(), save_dir, opt.bucket) # Plot results plot_evolve(evolve_csv) diff --git a/segment/tutorial.ipynb b/segment/tutorial.ipynb index 7a641c718e..b87658e106 100644 --- a/segment/tutorial.ipynb +++ b/segment/tutorial.ipynb @@ -18,7 +18,7 @@ " \"Open\n", "
\n", "\n", - "This 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", + "This YOLOv5 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", "\n", "" ] @@ -49,7 +49,7 @@ "output_type": "stream", "name": "stderr", "text": [ - " 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n" + "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n" ] }, { @@ -63,7 +63,7 @@ "source": [ "!git clone https://github.com/ultralytics/yolov5 # clone\n", "%cd yolov5\n", - "%pip install -qr requirements.txt # install\n", + "%pip install -qr requirements.txt comet_ml # install\n", "\n", "import torch\n", "import utils\n", @@ -78,7 +78,7 @@ "source": [ "# 1. Predict\n", "\n", - "`segment/predict.py` runs instance segmentation inference on a variety of sources, downloading models automatically from the [latest release](https://github.com/ultralytics/yolov5/releases), and saving results to `runs/predict`. Example inference sources are:\n", + "`segment/predict.py` runs YOLOv5 instance segmentation inference on a variety of sources, downloading models automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases), and saving results to `runs/predict`. Example inference sources are:\n", "\n", "```shell\n", "python segment/predict.py --source 0 # webcam\n", @@ -250,16 +250,17 @@ "outputs": [], "source": [ "#@title Select YOLOv5 🚀 logger {run: 'auto'}\n", - "logger = 'TensorBoard' #@param ['TensorBoard', 'Comet', 'ClearML']\n", + "logger = 'Comet' #@param ['Comet', 'ClearML', 'TensorBoard']\n", "\n", - "if logger == 'TensorBoard':\n", - " %load_ext tensorboard\n", - " %tensorboard --logdir runs/train-seg\n", - "elif logger == 'Comet':\n", + "if logger == 'Comet':\n", " %pip install -q comet_ml\n", " import comet_ml; comet_ml.init()\n", "elif logger == 'ClearML':\n", - " import clearml; clearml.browser_login()" + " %pip install -q clearml\n", + " import clearml; clearml.browser_login()\n", + "elif logger == 'TensorBoard':\n", + " %load_ext tensorboard\n", + " %tensorboard --logdir runs/train" ] }, { diff --git a/segment/val.py b/segment/val.py index 321af8090f..87d6ca791c 100644 --- a/segment/val.py +++ b/segment/val.py @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Validate a trained segment model on a segment dataset +Validate a trained YOLOv3 segment model on a segment dataset Usage: $ bash data/scripts/get_coco.sh --val --segments # download COCO-segments val split (1G, 5000 images) @@ -33,7 +33,7 @@ from tqdm import tqdm FILE = Path(__file__).resolve() -ROOT = FILE.parents[1] # root directory +ROOT = FILE.parents[1] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative @@ -462,7 +462,7 @@ def main(opt): r, _, t = run(**vars(opt), plots=False) y.append(r + t) # results and times np.savetxt(f, y, fmt='%10.4g') # save - subprocess.run('zip -r study.zip study_*.txt'.split()) + subprocess.run(['zip', '-r', 'study.zip', 'study_*.txt']) plot_val_study(x=x) # plot else: raise NotImplementedError(f'--task {opt.task} not in ("train", "val", "test", "speed", "study")') diff --git a/train.py b/train.py index acfb8402ce..fa9bae5ad8 100644 --- a/train.py +++ b/train.py @@ -26,6 +26,11 @@ from datetime import datetime from pathlib import Path +try: + import comet_ml # must be imported before torch (if installed) +except ImportError: + comet_ml = None + import numpy as np import torch import torch.distributed as dist @@ -69,7 +74,8 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = \ - Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ + opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze callbacks.run('on_pretrain_routine_start') # Directories @@ -300,7 +306,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Multi-scale if opt.multi_scale: - sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size + sz = random.randrange(int(imgsz * 0.5), int(imgsz * 1.5) + gs) // gs * gs # size sf = sz / max(imgs.shape[2:]) # scale factor if sf != 1: ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) @@ -573,8 +579,12 @@ def main(opt, callbacks=Callbacks()): # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' if opt.bucket: - subprocess.run( - f'gsutil cp gs://{opt.bucket}/evolve.csv {evolve_csv}'.split()) # download evolve.csv if exists + # download evolve.csv if exists + subprocess.run([ + 'gsutil', + 'cp', + f'gs://{opt.bucket}/evolve.csv', + str(evolve_csv), ]) for _ in range(opt.evolve): # generations to evolve if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate diff --git a/tutorial.ipynb b/tutorial.ipynb index a5aa2d23ba..c6b527c802 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -3,361 +3,14 @@ "nbformat_minor": 0, "metadata": { "colab": { - "name": "YOLOv3 Tutorial", - "provenance": [], - "toc_visible": true + "name": "YOLOv5 Tutorial", + "provenance": [] }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, - "accelerator": "GPU", - "widgets": { - "application/vnd.jupyter.widget-state+json": { - "1f7df330663048998adcf8a45bc8f69b": { - "model_module": "@jupyter-widgets/controls", - "model_name": "HBoxModel", - "model_module_version": "1.5.0", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HBoxModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HBoxView", - "box_style": "", - "children": [ - "IPY_MODEL_e896e6096dd244c59d7955e2035cd729", - "IPY_MODEL_a6ff238c29984b24bf6d0bd175c19430", - "IPY_MODEL_3c085ba3f3fd4c3c8a6bb41b41ce1479" - ], - "layout": "IPY_MODEL_16b0c8aa6e0f427e8a54d3791abb7504" - } - }, - "e896e6096dd244c59d7955e2035cd729": { - "model_module": "@jupyter-widgets/controls", - "model_name": "HTMLModel", - "model_module_version": "1.5.0", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_c7b2dd0f78384cad8e400b282996cdf5", - "placeholder": "​", - "style": "IPY_MODEL_6a27e43b0e434edd82ee63f0a91036ca", - "value": "100%" - } - }, - "a6ff238c29984b24bf6d0bd175c19430": { - "model_module": "@jupyter-widgets/controls", - "model_name": "FloatProgressModel", - "model_module_version": "1.5.0", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "FloatProgressModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "ProgressView", - "bar_style": "success", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_cce0e6c0c4ec442cb47e65c674e02e92", - "max": 818322941, - "min": 0, - "orientation": "horizontal", - "style": "IPY_MODEL_c5b9f38e2f0d4f9aa97fe87265263743", - "value": 818322941 - } - }, - "3c085ba3f3fd4c3c8a6bb41b41ce1479": { - "model_module": "@jupyter-widgets/controls", - "model_name": "HTMLModel", - "model_module_version": "1.5.0", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_df554fb955c7454696beac5a82889386", - "placeholder": "​", - "style": "IPY_MODEL_74e9112a87a242f4831b7d68c7da6333", - "value": " 780M/780M [00:05<00:00, 126MB/s]" - } - }, - "16b0c8aa6e0f427e8a54d3791abb7504": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "model_module_version": "1.2.0", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "c7b2dd0f78384cad8e400b282996cdf5": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "model_module_version": "1.2.0", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "6a27e43b0e434edd82ee63f0a91036ca": { - "model_module": "@jupyter-widgets/controls", - "model_name": "DescriptionStyleModel", - "model_module_version": "1.5.0", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "cce0e6c0c4ec442cb47e65c674e02e92": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "model_module_version": "1.2.0", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "c5b9f38e2f0d4f9aa97fe87265263743": { - "model_module": "@jupyter-widgets/controls", - "model_name": "ProgressStyleModel", - "model_module_version": "1.5.0", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "ProgressStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "bar_color": null, - "description_width": "" - } - }, - "df554fb955c7454696beac5a82889386": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "model_module_version": "1.2.0", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "74e9112a87a242f4831b7d68c7da6333": { - "model_module": "@jupyter-widgets/controls", - "model_name": "DescriptionStyleModel", - "model_module_version": "1.5.0", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - } - } - } + "accelerator": "GPU" }, "cells": [ { @@ -378,7 +31,7 @@ " \"Open\n", "
\n", "\n", - "This 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", + "This YOLOv5 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
We hope that the resources in this notebook will help you get the most out of YOLOv5. Please browse the YOLOv5 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions!\n", "\n", "" ] @@ -401,31 +54,31 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "f9f016ad-3dcf-4bd2-e1c3-d5b79efc6f32" + "outputId": "e8225db4-e61d-4640-8b1f-8bfce3331cea" }, "source": [ "!git clone https://github.com/ultralytics/yolov5 # clone\n", "%cd yolov5\n", - "%pip install -qr requirements.txt # install\n", + "%pip install -qr requirements.txt comet_ml # install\n", "\n", "import torch\n", "import utils\n", "display = utils.notebook_init() # checks" ], - "execution_count": null, + "execution_count": 1, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ - " 🚀 v7.0-1-gb32f67f Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n" + "YOLOv5 🚀 v7.0-136-g71244ae Python-3.9.16 torch-2.0.0+cu118 CUDA:0 (Tesla T4, 15102MiB)\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ - "Setup complete ✅ (2 CPUs, 12.7 GB RAM, 22.6/78.2 GB disk)\n" + "Setup complete ✅ (2 CPUs, 12.7 GB RAM, 23.3/166.8 GB disk)\n" ] } ] @@ -438,7 +91,7 @@ "source": [ "# 1. Detect\n", "\n", - "`detect.py` runs inference on a variety of sources, downloading models automatically from the [latest release](https://github.com/ultralytics/yolov5/releases), and saving results to `runs/detect`. Example inference sources are:\n", + "`detect.py` runs YOLOv5 inference on a variety of sources, downloading models automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases), and saving results to `runs/detect`. Example inference sources are:\n", "\n", "```shell\n", "python detect.py --source 0 # webcam\n", @@ -459,29 +112,29 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "b4db5c49-f501-4505-cf0d-a1d35236c485" + "outputId": "284ef04b-1596-412f-88f6-948828dd2b49" }, "source": [ "!python detect.py --weights yolov5s.pt --img 640 --conf 0.25 --source data/images\n", "# display.Image(filename='runs/detect/exp/zidane.jpg', width=600)" ], - "execution_count": null, + "execution_count": 13, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\u001b[34m\u001b[1mdetect: \u001b[0mweights=['yolov5s.pt'], source=data/images, data=data/coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False, vid_stride=1\n", - " 🚀 v7.0-1-gb32f67f Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "YOLOv5 🚀 v7.0-136-g71244ae Python-3.9.16 torch-2.0.0+cu118 CUDA:0 (Tesla T4, 15102MiB)\n", "\n", "Downloading https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt to yolov5s.pt...\n", - "100% 14.1M/14.1M [00:00<00:00, 116MB/s] \n", + "100% 14.1M/14.1M [00:00<00:00, 24.5MB/s]\n", "\n", "Fusing layers... \n", "YOLOv5s summary: 213 layers, 7225885 parameters, 0 gradients\n", - "image 1/2 /content/yolov5/data/images/bus.jpg: 640x480 4 persons, 1 bus, 17.0ms\n", - "image 2/2 /content/yolov5/data/images/zidane.jpg: 384x640 2 persons, 2 ties, 14.3ms\n", - "Speed: 0.5ms pre-process, 15.7ms inference, 18.6ms NMS per image at shape (1, 3, 640, 640)\n", + "image 1/2 /content/yolov5/data/images/bus.jpg: 640x480 4 persons, 1 bus, 41.5ms\n", + "image 2/2 /content/yolov5/data/images/zidane.jpg: 384x640 2 persons, 2 ties, 60.0ms\n", + "Speed: 0.5ms pre-process, 50.8ms inference, 37.7ms NMS per image at shape (1, 3, 640, 640)\n", "Results saved to \u001b[1mruns/detect/exp\u001b[0m\n" ] } @@ -504,7 +157,7 @@ }, "source": [ "# 2. Validate\n", - "Validate a model's accuracy on the [COCO](https://cocodataset.org/#home) dataset's `val` or `test` splits. Models are downloaded automatically from the [latest release](https://github.com/ultralytics/yolov5/releases). To show results by class use the `--verbose` flag." + "Validate a model's accuracy on the [COCO](https://cocodataset.org/#home) dataset's `val` or `test` splits. Models are downloaded automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases). To show results by class use the `--verbose` flag." ] }, { @@ -512,44 +165,23 @@ "metadata": { "id": "WQPtK1QYVaD_", "colab": { - "base_uri": "https://localhost:8080/", - "height": 49, - "referenced_widgets": [ - "1f7df330663048998adcf8a45bc8f69b", - "e896e6096dd244c59d7955e2035cd729", - "a6ff238c29984b24bf6d0bd175c19430", - "3c085ba3f3fd4c3c8a6bb41b41ce1479", - "16b0c8aa6e0f427e8a54d3791abb7504", - "c7b2dd0f78384cad8e400b282996cdf5", - "6a27e43b0e434edd82ee63f0a91036ca", - "cce0e6c0c4ec442cb47e65c674e02e92", - "c5b9f38e2f0d4f9aa97fe87265263743", - "df554fb955c7454696beac5a82889386", - "74e9112a87a242f4831b7d68c7da6333" - ] + "base_uri": "https://localhost:8080/" }, - "outputId": "c7d0a0d2-abfb-44c3-d60d-f99d0e7aabad" + "outputId": "cf7d52f0-281c-4c96-a488-79f5908f8426" }, "source": [ "# Download COCO val\n", "torch.hub.download_url_to_file('https://ultralytics.com/assets/coco2017val.zip', 'tmp.zip') # download (780M - 5000 images)\n", "!unzip -q tmp.zip -d ../datasets && rm tmp.zip # unzip" ], - "execution_count": null, + "execution_count": 3, "outputs": [ { - "output_type": "display_data", - "data": { - "text/plain": [ - " 0%| | 0.00/780M [00:00

\n", + "

\n", "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", "

\n", "\n", "Train a YOLOv5s model on the [COCO128](https://www.kaggle.com/ultralytics/coco128) dataset with `--data coco128.yaml`, starting from pretrained `--weights yolov5s.pt`, or from randomly initialized `--weights '' --cfg yolov5s.yaml`.\n", "\n", "- **Pretrained [Models](https://github.com/ultralytics/yolov5/tree/master/models)** are downloaded\n", - "automatically from the [latest release](https://github.com/ultralytics/yolov5/releases)\n", + "automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases)\n", "- **[Datasets](https://github.com/ultralytics/yolov5/tree/master/data)** available for autodownload include: [COCO](https://github.com/ultralytics/yolov5/blob/master/data/coco.yaml), [COCO128](https://github.com/ultralytics/yolov5/blob/master/data/coco128.yaml), [VOC](https://github.com/ultralytics/yolov5/blob/master/data/VOC.yaml), [Argoverse](https://github.com/ultralytics/yolov5/blob/master/data/Argoverse.yaml), [VisDrone](https://github.com/ultralytics/yolov5/blob/master/data/VisDrone.yaml), [GlobalWheat](https://github.com/ultralytics/yolov5/blob/master/data/GlobalWheat2020.yaml), [xView](https://github.com/ultralytics/yolov5/blob/master/data/xView.yaml), [Objects365](https://github.com/ultralytics/yolov5/blob/master/data/Objects365.yaml), [SKU-110K](https://github.com/ultralytics/yolov5/blob/master/data/SKU-110K.yaml).\n", "- **Training Results** are saved to `runs/train/` with incrementing run directories, i.e. `runs/train/exp2`, `runs/train/exp3` etc.\n", - "

\n", + "
\n", "\n", "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic.\n", "\n", - "## Train on Custom Data with Roboflow 🌟 NEW\n", + "## Label a dataset on Roboflow (optional)\n", "\n", - "[Roboflow](https://roboflow.com/?ref=ultralytics) enables you to easily **organize, label, and prepare** a high quality dataset with your own custom data. Roboflow also makes it easy to establish an active learning pipeline, collaborate with your team on dataset improvement, and integrate directly into your model building workflow with the `roboflow` pip package.\n", - "\n", - "- Custom Training Example: [https://blog.roboflow.com/how-to-train-yolov5-on-a-custom-dataset/](https://blog.roboflow.com/how-to-train-yolov5-on-a-custom-dataset/?ref=ultralytics)\n", - "- Custom Training Notebook: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow-ai/yolov5-custom-training-tutorial/blob/main/yolov5-custom-training.ipynb)\n", - "
\n", - "\n", - "

Label images lightning fast (including with model-assisted labeling)" + "[Roboflow](https://roboflow.com/?ref=ultralytics) enables you to easily **organize, label, and prepare** a high quality dataset with your own custom data. Roboflow also makes it easy to establish an active learning pipeline, collaborate with your team on dataset improvement, and integrate directly into your model building workflow with the `roboflow` pip package." ] }, { "cell_type": "code", "source": [ - "#@title Select 🚀 logger {run: 'auto'}\n", - "logger = 'ClearML' #@param ['ClearML', 'Comet', 'TensorBoard']\n", + "#@title Select YOLOv5 🚀 logger {run: 'auto'}\n", + "logger = 'Comet' #@param ['Comet', 'ClearML', 'TensorBoard']\n", "\n", - "if logger == 'ClearML':\n", - " %pip install -q clearml\n", - " import clearml; clearml.browser_login()\n", - "elif logger == 'Comet':\n", + "if logger == 'Comet':\n", " %pip install -q comet_ml\n", " import comet_ml; comet_ml.init()\n", + "elif logger == 'ClearML':\n", + " %pip install -q clearml\n", + " import clearml; clearml.browser_login()\n", "elif logger == 'TensorBoard':\n", " %load_ext tensorboard\n", " %tensorboard --logdir runs/train" @@ -676,31 +302,34 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "721b9028-767f-4a05-c964-692c245f7398" + "outputId": "bbeeea2b-04fc-4185-aa64-258690495b5a" }, "source": [ "# Train YOLOv5s on COCO128 for 3 epochs\n", "!python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov5s.pt --cache" ], - "execution_count": null, + "execution_count": 5, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ + "2023-04-09 14:11:38.063605: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX512F FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2023-04-09 14:11:39.026661: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n", "\u001b[34m\u001b[1mtrain: \u001b[0mweights=yolov5s.pt, cfg=, data=coco128.yaml, hyp=data/hyps/hyp.scratch-low.yaml, epochs=3, batch_size=16, imgsz=640, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, noplots=False, evolve=None, bucket=, cache=ram, image_weights=False, device=, multi_scale=False, single_cls=False, optimizer=SGD, sync_bn=False, workers=8, project=runs/train, name=exp, exist_ok=False, quad=False, cos_lr=False, label_smoothing=0.0, patience=100, freeze=[0], save_period=-1, seed=0, local_rank=-1, entity=None, upload_dataset=False, bbox_interval=-1, artifact_alias=latest\n", "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", - " 🚀 v7.0-1-gb32f67f Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "YOLOv5 🚀 v7.0-136-g71244ae Python-3.9.16 torch-2.0.0+cu118 CUDA:0 (Tesla T4, 15102MiB)\n", "\n", "\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0\n", - "\u001b[34m\u001b[1mClearML: \u001b[0mrun 'pip install clearml' to automatically track, visualize and remotely train 🚀 in ClearML\n", - "\u001b[34m\u001b[1mComet: \u001b[0mrun 'pip install comet_ml' to automatically track and visualize 🚀 runs in Comet\n", + "\u001b[34m\u001b[1mClearML: \u001b[0mrun 'pip install clearml' to automatically track, visualize and remotely train YOLOv5 🚀 in ClearML\n", + "\u001b[34m\u001b[1mComet: \u001b[0mrun 'pip install comet_ml' to automatically track and visualize YOLOv5 🚀 runs in Comet\n", "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train', view at http://localhost:6006/\n", "\n", "Dataset not found ⚠️, missing paths ['/content/datasets/coco128/images/train2017']\n", "Downloading https://ultralytics.com/assets/coco128.zip to coco128.zip...\n", - "100% 6.66M/6.66M [00:00<00:00, 261MB/s]\n", - "Dataset download success ✅ (0.3s), saved to \u001b[1m/content/datasets\u001b[0m\n", + "100% 6.66M/6.66M [00:00<00:00, 75.6MB/s]\n", + "Dataset download success ✅ (0.6s), saved to \u001b[1m/content/datasets\u001b[0m\n", "\n", " from n params module arguments \n", " 0 -1 1 3520 models.common.Conv [3, 32, 6, 2, 2] \n", @@ -734,11 +363,11 @@ "\u001b[34m\u001b[1mAMP: \u001b[0mchecks passed ✅\n", "\u001b[34m\u001b[1moptimizer:\u001b[0m SGD(lr=0.01) with parameter groups 57 weight(decay=0.0), 60 weight(decay=0.0005), 60 bias\n", "\u001b[34m\u001b[1malbumentations: \u001b[0mBlur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01), CLAHE(p=0.01, clip_limit=(1, 4.0), tile_grid_size=(8, 8))\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mScanning /content/datasets/coco128/labels/train2017... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00<00:00, 1911.57it/s]\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mScanning /content/datasets/coco128/labels/train2017... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00<00:00, 1709.36it/s]\n", "\u001b[34m\u001b[1mtrain: \u001b[0mNew cache created: /content/datasets/coco128/labels/train2017.cache\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mCaching images (0.1GB ram): 100% 128/128 [00:00<00:00, 229.69it/s]\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mCaching images (0.1GB ram): 100% 128/128 [00:00<00:00, 264.35it/s]\n", "\u001b[34m\u001b[1mval: \u001b[0mScanning /content/datasets/coco128/labels/train2017.cache... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00\n", "\"ClearML" @@ -923,7 +552,7 @@ "source": [ "# Environments\n", "\n", - " 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):\n", + "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):\n", "\n", "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)\n", @@ -939,9 +568,9 @@ "source": [ "# Status\n", "\n", - "![ CI](https://github.com/ultralytics/yolov3/actions/workflows/ci-testing.yml/badge.svg)\n", + "![YOLOv5 CI](https://github.com/ultralytics/yolov3/actions/workflows/ci-testing.yml/badge.svg)\n", "\n", - "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of training ([train.py](https://github.com/ultralytics/yolov5/blob/master/train.py)), testing ([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.\n" + "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/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)), testing ([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.\n" ] }, { @@ -961,7 +590,7 @@ "id": "GMusP4OAxFu6" }, "source": [ - "# PyTorch HUB Inference (DetectionModels only)\n", + "# YOLOv5 PyTorch HUB Inference (DetectionModels only)\n", "import torch\n", "\n", "model = torch.hub.load('ultralytics/yolov5', 'yolov5s', force_reload=True) # yolov5n - yolov5x6 or custom\n", diff --git a/utils/aws/resume.py b/utils/aws/resume.py index b21731c979..e34bc2d72c 100644 --- a/utils/aws/resume.py +++ b/utils/aws/resume.py @@ -9,7 +9,7 @@ import yaml FILE = Path(__file__).resolve() -ROOT = FILE.parents[2] # YOLOv5 root directory +ROOT = FILE.parents[2] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 348e4ce424..0ed126899c 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -188,7 +188,7 @@ def __iter__(self): class LoadScreenshots: - # YOLOv5 screenshot dataloader, i.e. `python detect.py --source "screen 0 100 100 512 256"` + # YOLOv3 screenshot dataloader, i.e. `python detect.py --source "screen 0 100 100 512 256"` def __init__(self, source, img_size=640, stride=32, auto=True, transforms=None): # source = [screen_number left top width height] (pixels) check_requirements('mss') @@ -237,7 +237,7 @@ def __next__(self): class LoadImages: - # YOLOv5 image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4` + # YOLOv3 image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4` def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): if isinstance(path, str) and Path(path).suffix == '.txt': # *.txt file with img/vid/dir on each line path = Path(path).read_text().rsplit() @@ -340,7 +340,7 @@ def __len__(self): class LoadStreams: - # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams` + # YOLOv3 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams` def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): torch.backends.cudnn.benchmark = True # faster for fixed-size inference self.mode = 'stream' @@ -432,7 +432,7 @@ def img2label_paths(img_paths): class LoadImagesAndLabels(Dataset): - # YOLOv5 train_loader/val_loader, loads images and labels for training and validation + # YOLOv3 train_loader/val_loader, loads images and labels for training and validation cache_version = 0.6 # dataset labels *.cache version rand_interp_methods = [cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_CUBIC, cv2.INTER_AREA, cv2.INTER_LANCZOS4] @@ -531,13 +531,14 @@ def __init__(self, # Update labels include_class = [] # filter labels to include only these classes (optional) + self.segments = list(self.segments) include_class_array = np.array(include_class).reshape(1, -1) for i, (label, segment) in enumerate(zip(self.labels, self.segments)): if include_class: j = (label[:, 0:1] == include_class_array).any(1) self.labels[i] = label[j] if segment: - self.segments[i] = segment[j] + self.segments[i] = [segment[idx] for idx, elem in enumerate(j) if elem] if single_cls: # single-class training, merge all classes into 0 self.labels[i][:, 0] = 0 @@ -748,7 +749,7 @@ def cache_images_to_disk(self, i): np.save(f.as_posix(), cv2.imread(self.im_files[i])) def load_mosaic(self, index): - # YOLOv5 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic + # YOLOv3 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic labels4, segments4 = [], [] s = self.img_size yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y @@ -806,7 +807,7 @@ def load_mosaic(self, index): return img4, labels4 def load_mosaic9(self, index): - # YOLOv5 9-mosaic loader. Loads 1 image + 8 random images into a 9-image mosaic + # YOLOv3 9-mosaic loader. Loads 1 image + 8 random images into a 9-image mosaic labels9, segments9 = [], [] s = self.img_size indices = [index] + random.choices(self.indices, k=8) # 8 additional image indices @@ -1162,7 +1163,7 @@ def process_images(self): # Classification dataloaders ------------------------------------------------------------------------------------------- class ClassificationDataset(torchvision.datasets.ImageFolder): """ - YOLOv5 Classification Dataset. + YOLOv3 Classification Dataset. Arguments root: Dataset path transform: torchvision transforms, used by default @@ -1202,7 +1203,7 @@ def create_classification_dataloader(path, rank=-1, workers=8, shuffle=True): - # Returns Dataloader object to be used with YOLOv5 Classifier + # Returns Dataloader object to be used with YOLOv3 Classifier with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP dataset = ClassificationDataset(root=path, imgsz=imgsz, augment=augment, cache=cache) batch_size = min(batch_size, len(dataset)) diff --git a/utils/docker/Dockerfile b/utils/docker/Dockerfile index 23a5067223..fbffdbbe0c 100644 --- a/utils/docker/Dockerfile +++ b/utils/docker/Dockerfile @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license # Builds ultralytics/yolov5:latest image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 # Image is CUDA-optimized for YOLOv5 single/multi-GPU training and inference @@ -30,10 +30,9 @@ RUN git clone https://github.com/ultralytics/yolov5 /usr/src/app # Install pip packages COPY requirements.txt . RUN python3 -m pip install --upgrade pip wheel -RUN pip install --no-cache nvidia-tensorrt --index-url https://pypi.ngc.nvidia.com RUN pip install --no-cache -r requirements.txt albumentations comet gsutil notebook \ coremltools onnx onnx-simplifier onnxruntime 'openvino-dev>=2023.0' - # tensorflow tensorflowjs + # tensorflow tensorflowjs \ # Set environment variables ENV OMP_NUM_THREADS=1 diff --git a/utils/docker/Dockerfile-arm64 b/utils/docker/Dockerfile-arm64 index 6bd30a2325..9a9f1a69d9 100644 --- a/utils/docker/Dockerfile-arm64 +++ b/utils/docker/Dockerfile-arm64 @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license # Builds ultralytics/yolov5:latest-arm64 image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 # Image is aarch64-compatible for Apple M1 and other ARM architectures i.e. Jetson Nano and Raspberry Pi diff --git a/utils/docker/Dockerfile-cpu b/utils/docker/Dockerfile-cpu index a9c782abb0..d79e3839a6 100644 --- a/utils/docker/Dockerfile-cpu +++ b/utils/docker/Dockerfile-cpu @@ -1,20 +1,22 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license # Builds ultralytics/yolov5:latest-cpu image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 # Image is CPU-optimized for ONNX, OpenVINO and PyTorch YOLOv5 deployments # Start FROM Ubuntu image https://hub.docker.com/_/ubuntu -FROM ubuntu:22.10 +FROM ubuntu:lunar-20230615 # Downloads to user config dir ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/ # Install linux packages -ENV DEBIAN_FRONTEND noninteractive -RUN apt update -RUN TZ=Etc/UTC apt install -y tzdata -RUN apt install --no-install-recommends -y python3-pip git zip curl htop libgl1-mesa-glx libglib2.0-0 libpython3-dev gnupg +# g++ required to build 'tflite_support' and 'lap' packages, libusb-1.0-0 required for 'tflite_support' package +RUN apt update \ + && apt install --no-install-recommends -y python3-pip git zip curl htop libgl1-mesa-glx libglib2.0-0 libpython3-dev gnupg g++ libusb-1.0-0 # RUN alias python=python3 +# Remove python3.11/EXTERNALLY-MANAGED or use 'pip install --break-system-packages' avoid 'externally-managed-environment' Ubuntu nightly error +RUN rm -rf /usr/lib/python3.11/EXTERNALLY-MANAGED + # Install pip packages COPY requirements.txt . RUN python3 -m pip install --upgrade pip wheel @@ -30,7 +32,6 @@ WORKDIR /usr/src/app # Copy contents # COPY . /usr/src/app (issues as not a .git directory) RUN git clone https://github.com/ultralytics/yolov5 /usr/src/app -ENV DEBIAN_FRONTEND teletype # Usage Examples ------------------------------------------------------------------------------------------------------- diff --git a/utils/flask_rest_api/restapi.py b/utils/flask_rest_api/restapi.py index c8ddc9a938..b04c295874 100644 --- a/utils/flask_rest_api/restapi.py +++ b/utils/flask_rest_api/restapi.py @@ -37,7 +37,7 @@ def predict(model): if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Flask API exposing YOLOv5 model') + parser = argparse.ArgumentParser(description='Flask API exposing YOLOv3 model') parser.add_argument('--port', default=5000, type=int, help='port number') parser.add_argument('--model', nargs='+', default=['yolov5s'], help='model(s) to run, i.e. --model yolov5n yolov5s') opt = parser.parse_args() diff --git a/utils/general.py b/utils/general.py index 65db2fdc3e..6b51d5b48c 100644 --- a/utils/general.py +++ b/utils/general.py @@ -347,7 +347,7 @@ def check_git_status(repo='ultralytics/yolov5', branch='master'): n = int(check_output(f'git rev-list {local_branch}..{remote}/{branch} --count', shell=True)) # commits behind if n > 0: pull = 'git pull' if remote == 'origin' else f'git pull {remote} {branch}' - s += f"⚠️ YOLOv3 is out of date by {n} commit{'s' * (n > 1)}. Use `{pull}` or `git clone {url}` to update." + s += f"⚠️ YOLOv3 is out of date by {n} commit{'s' * (n > 1)}. Use '{pull}' or 'git clone {url}' to update." else: s += f'up to date with {url} ✅' LOGGER.info(s) diff --git a/utils/google_app_engine/additional_requirements.txt b/utils/google_app_engine/additional_requirements.txt index 5ac5c71a3c..fce1511588 100644 --- a/utils/google_app_engine/additional_requirements.txt +++ b/utils/google_app_engine/additional_requirements.txt @@ -2,3 +2,4 @@ pip==21.1 Flask==2.3.2 gunicorn==19.10.0 +werkzeug>=2.2.3 # not directly required, pinned by Snyk to avoid a vulnerability diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index edd6cf2c60..f78d6b5c01 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -307,7 +307,7 @@ def on_params_update(self, params: dict): class GenericLogger: """ - YOLOv5 General purpose logger for non-task specific logging + YOLOv3 General purpose logger for non-task specific logging Usage: from utils.loggers import GenericLogger; logger = GenericLogger(...) Arguments opt: Run arguments @@ -398,4 +398,4 @@ def web_project_name(project): if not project.startswith('runs/train'): return project suffix = '-Classify' if project.endswith('-cls') else '-Segment' if project.endswith('-seg') else '' - return f'YOLOv5{suffix}' + return f'YOLOv3{suffix}' diff --git a/utils/loggers/clearml/README.md b/utils/loggers/clearml/README.md index 2ca610804d..7dbf6e4263 100644 --- a/utils/loggers/clearml/README.md +++ b/utils/loggers/clearml/README.md @@ -4,8 +4,7 @@ ## About ClearML -[ClearML](https://cutt.ly/yolov5-tutorial-clearml) is an [open-source](https://github.com/allegroai/clearml) toolbox -designed to save you time ⏱️. +[ClearML](https://cutt.ly/yolov5-tutorial-clearml) is an [open-source](https://github.com/allegroai/clearml) toolbox designed to save you time ⏱️. 🔨 Track every YOLOv5 training run in the experiment manager @@ -31,9 +30,7 @@ And so much more. It's up to you how many of these tools you want to use, you ca To keep track of your experiments and/or data, ClearML needs to communicate to a server. You have 2 options to get one: -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! +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! 1. Install the `clearml` python package: @@ -41,9 +38,7 @@ open-source, so even if you're dealing with sensitive data, you should be good t pip install clearml ``` -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: +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: ```bash clearml-init @@ -61,11 +56,9 @@ To enable ClearML experiment tracking, simply install the ClearML pip package. pip install clearml>=1.2.0 ``` -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. +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`, use the `--project` and `--name` arguments of the `train.py` -script, by default the project will be called `YOLOv5` and the task `Training`. +If you want to change the `project_name` or `task_name`, use the `--project` and `--name` arguments of the `train.py` script, by default the project will be called `YOLOv5` and the task `Training`. PLEASE NOTE: ClearML uses `/` as a delimiter for subprojects, so be careful when using `/` in your project name! ```bash @@ -94,30 +87,21 @@ This will capture: - ... That's a lot right? 🤯 -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! +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! -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! +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!
## 🔗 Dataset Version Management -Versioning your data separately from your code is generally a good idea and makes it easy to acquire 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! +Versioning your data separately from your code is generally a good idea and makes it easy to acquire 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! ![ClearML Dataset Interface](https://github.com/thepycoder/clearml_screenshots/raw/main/clearml_data.gif) ### Prepare Your Dataset -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: +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: ``` .. @@ -132,9 +116,7 @@ structure: But this can be any dataset you wish. Feel free to use your own, as long as you keep to this folder structure. -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. +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. Basically we need the following keys: `path`, `train`, `test`, `val`, `nc`, `names`. @@ -156,7 +138,7 @@ To get this dataset into ClearML as a versioned dataset, go to the dataset root ```bash cd coco128 -clearml-data sync --project YOLOv5 --name coco128 --folder . +clearml-data sync --project YOLOv3 --name coco128 --folder . ``` The command `clearml-data sync` is actually a shorthand command. You could also run these commands one after the other: @@ -164,7 +146,7 @@ The command `clearml-data sync` is actually a shorthand command. You could also ```bash # Optionally add --parent if you want to base # this version on another dataset version, so no duplicate files are uploaded! -clearml-data create --name coco128 --project YOLOv5 +clearml-data create --name coco128 --project YOLOv3 clearml-data add --files . clearml-data close ``` @@ -183,17 +165,11 @@ python train.py --img 640 --batch 16 --epochs 3 --data clearml:// [--docker] ### Cloning, Editing And Enqueuing -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! +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! 🪄 Clone the experiment by right-clicking it @@ -238,11 +209,9 @@ hyperparameters? We can do that from the interface too! ### Executing A Task Remotely -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! +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! -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 instantiated: +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 instantiated: ```python # ... @@ -257,14 +226,11 @@ if RANK in {-1, 0}: # ... ``` -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! +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! ### Autoscaling workers -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! +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! Check out the autoscalers getting started video below. diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py index 2764abe90d..0c7ddeed31 100644 --- a/utils/loggers/clearml/clearml_utils.py +++ b/utils/loggers/clearml/clearml_utils.py @@ -5,8 +5,7 @@ import numpy as np import yaml - -from utils.plots import Annotator, colors +from ultralytics.utils.plotting import Annotator, colors try: import clearml @@ -85,9 +84,9 @@ def __init__(self, opt, hyp): self.data_dict = None if self.clearml: self.task = Task.init( - project_name=opt.project if opt.project != 'runs/train' else 'YOLOv5', + project_name=opt.project if opt.project != 'runs/train' else 'YOLOv3', task_name=opt.name if opt.name != 'exp' else 'Training', - tags=['YOLOv5'], + tags=['YOLOv3'], output_uri=True, reuse_last_task_id=opt.exist_ok, auto_connect_frameworks={'pytorch': False} diff --git a/utils/loggers/clearml/hpo.py b/utils/loggers/clearml/hpo.py index ee518b0fbf..8cccaa23b6 100644 --- a/utils/loggers/clearml/hpo.py +++ b/utils/loggers/clearml/hpo.py @@ -5,7 +5,7 @@ from clearml.automation.optuna import OptimizerOptuna task = Task.init(project_name='Hyper-Parameter Optimization', - task_name='YOLOv5', + task_name='YOLOv3', task_type=Task.TaskTypes.optimizer, reuse_last_task_id=False) diff --git a/utils/loggers/comet/README.md b/utils/loggers/comet/README.md index 6e918db803..3ad52b01b4 100644 --- a/utils/loggers/comet/README.md +++ b/utils/loggers/comet/README.md @@ -6,14 +6,10 @@ This guide will cover how to use YOLOv5 with [Comet](https://bit.ly/yolov5-readm # About Comet -Comet builds tools that help data scientists, engineers, and team leaders accelerate and optimize machine learning and -deep learning models. +Comet builds tools that help data scientists, engineers, and team leaders accelerate and optimize machine learning and deep learning models. -Track and visualize model metrics in real time, save your hyperparameters, datasets, and model checkpoints, and -visualize your model predictions -with [Comet Custom Panels](https://www.comet.com/docs/v2/guides/comet-dashboard/code-panels/about-panels/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github)! -Comet makes sure you never lose track of your work and makes it easy to share results and collaborate across teams of -all sizes! +Track and visualize model metrics in real time, save your hyperparameters, datasets, and model checkpoints, and visualize your model predictions with [Comet Custom Panels](https://www.comet.com/docs/v2/guides/comet-dashboard/code-panels/about-panels/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github)! +Comet makes sure you never lose track of your work and makes it easy to share results and collaborate across teams of all sizes! # Getting Started @@ -53,19 +49,17 @@ project_name= # This will default to 'yolov5' python train.py --img 640 --batch 16 --epochs 5 --data coco128.yaml --weights yolov5s.pt ``` -That's it! Comet will automatically log your hyperparameters, command line arguments, training and validation metrics. -You can visualize and analyze your runs in the Comet UI +That's it! Comet will automatically log your hyperparameters, command line arguments, training and validation metrics. You can visualize and analyze your runs in the Comet UI yolo-ui # Try out an Example! -Check out an example of -a [completed run here](https://www.comet.com/examples/comet-example-yolov5/a0e29e0e9b984e4a822db2a62d0cb357?experiment-tab=chart&showOutliers=true&smoothing=0&transformY=smoothing&xAxis=step&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) +Check out an example of a [completed run here](https://www.comet.com/examples/comet-example-yolov5/a0e29e0e9b984e4a822db2a62d0cb357?experiment-tab=chart&showOutliers=true&smoothing=0&transformY=smoothing&xAxis=step&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) Or better yet, try it out yourself in this Colab Notebook -[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing) +[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/comet-ml/comet-examples/blob/master/integrations/model-training/yolov5/notebooks/Comet_and_YOLOv5.ipynb) # Log automatically @@ -106,8 +100,7 @@ export COMET_LOG_PREDICTIONS=true # Set this to false to disable logging model p ## Logging Checkpoints with Comet -Logging Models to Comet is disabled by default. To enable it, pass the `save-period` argument to the training script. -This will save the +Logging Models to Comet is disabled by default. To enable it, pass the `save-period` argument to the training script. This will save the logged checkpoints to Comet based on the interval value provided by `save-period` ```shell @@ -124,15 +117,11 @@ python train.py \ By default, model predictions (images, ground truth labels and bounding boxes) will be logged to Comet. -You can control the frequency of logged predictions and the associated images by passing the `bbox_interval` command -line argument. Predictions can be visualized using Comet's Object Detection Custom Panel. This frequency corresponds to -every Nth batch of data per epoch. In the example below, we are logging every 2nd batch of data for each epoch. +You can control the frequency of logged predictions and the associated images by passing the `bbox_interval` command line argument. Predictions can be visualized using Comet's Object Detection Custom Panel. This frequency corresponds to every Nth batch of data per epoch. In the example below, we are logging every 2nd batch of data for each epoch. -**Note:** The YOLOv5 validation dataloader will default to a batch size of 32, so you will have to set the logging -frequency accordingly. +**Note:** The YOLOv5 validation dataloader will default to a batch size of 32, so you will have to set the logging frequency accordingly. -Here is -an [example project using the Panel](https://www.comet.com/examples/comet-example-yolov5?shareable=YcwMiJaZSXfcEXpGOHDD12vA1&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) +Here is an [example project using the Panel](https://www.comet.com/examples/comet-example-yolov5?shareable=YcwMiJaZSXfcEXpGOHDD12vA1&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) ```shell python train.py \ @@ -146,9 +135,7 @@ python train.py \ ### Controlling the number of Prediction Images logged to Comet -When logging predictions from YOLOv5, Comet will log the images associated with each set of predictions. By default a -maximum of 100 validation images are logged. You can increase or decrease this number using -the `COMET_MAX_IMAGE_UPLOADS` environment variable. +When logging predictions from YOLOv5, Comet will log the images associated with each set of predictions. By default a maximum of 100 validation images are logged. You can increase or decrease this number using the `COMET_MAX_IMAGE_UPLOADS` environment variable. ```shell env COMET_MAX_IMAGE_UPLOADS=200 python train.py \ @@ -175,13 +162,9 @@ env COMET_LOG_PER_CLASS_METRICS=true python train.py \ ## Uploading a Dataset to Comet Artifacts -If you would like to store your data -using [Comet Artifacts](https://www.comet.com/docs/v2/guides/data-management/using-artifacts/#learn-more?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github), -you can do so using the `upload_dataset` flag. +If you would like to store your data using [Comet Artifacts](https://www.comet.com/docs/v2/guides/data-management/using-artifacts/#learn-more?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github), you can do so using the `upload_dataset` flag. -The dataset be organized in the way described in -the [YOLOv5 documentation](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/). The -dataset config `yaml` file must follow the same format as that of the `coco128.yaml` file. +The dataset be organized in the way described in the [YOLOv5 documentation](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/). The dataset config `yaml` file must follow the same format as that of the `coco128.yaml` file. ```shell python train.py \ @@ -199,14 +182,12 @@ You can find the uploaded dataset in the Artifacts tab in your Comet Workspace You can preview the data directly in the Comet UI. artifact-2 -Artifacts are versioned and also support adding metadata about the dataset. Comet will automatically log the metadata -from your dataset `yaml` file +Artifacts are versioned and also support adding metadata about the dataset. Comet will automatically log the metadata from your dataset `yaml` file artifact-3 ### Using a saved Artifact -If you would like to use a dataset from Comet Artifacts, set the `path` variable in your dataset `yaml` file to point to -the following Artifact resource URL. +If you would like to use a dataset from Comet Artifacts, set the `path` variable in your dataset `yaml` file to point to the following Artifact resource URL. ``` # contents of artifact.yaml file @@ -224,20 +205,16 @@ python train.py \ --weights yolov5s.pt ``` -Artifacts also allow you to track the lineage of data as it flows through your Experimentation workflow. Here you can -see a graph that shows you all the experiments that have used your uploaded dataset. +Artifacts also allow you to track the lineage of data as it flows through your Experimentation workflow. Here you can see a graph that shows you all the experiments that have used your uploaded dataset. artifact-4 ## Resuming a Training Run -If your training run is interrupted for any reason, e.g. disrupted internet connection, you can resume the run using -the `resume` flag and the Comet Run Path. +If your training run is interrupted for any reason, e.g. disrupted internet connection, you can resume the run using the `resume` flag and the Comet Run Path. The Run Path has the following format `comet:////`. -This will restore the run to its state before the interruption, which includes restoring the model from a checkpoint, -restoring all hyperparameters and training arguments and downloading Comet dataset Artifacts if they were used in the -original run. The resumed run will continue logging to the existing Experiment in the Comet UI +This will restore the run to its state before the interruption, which includes restoring the model from a checkpoint, restoring all hyperparameters and training arguments and downloading Comet dataset Artifacts if they were used in the original run. The resumed run will continue logging to the existing Experiment in the Comet UI ```shell python train.py \ @@ -250,16 +227,14 @@ YOLOv5 is also integrated with Comet's Optimizer, making is simple to visualize ### Configuring an Optimizer Sweep -To configure the Comet Optimizer, you will have to create a JSON file with the information about the sweep. An example -file has been provided in `utils/loggers/comet/optimizer_config.json` +To configure the Comet Optimizer, you will have to create a JSON file with the information about the sweep. An example file has been provided in `utils/loggers/comet/optimizer_config.json` ```shell python utils/loggers/comet/hpo.py \ --comet_optimizer_config "utils/loggers/comet/optimizer_config.json" ``` -The `hpo.py` script accepts the same arguments as `train.py`. If you wish to pass additional arguments to your sweep -simply add them after +The `hpo.py` script accepts the same arguments as `train.py`. If you wish to pass additional arguments to your sweep simply add them after the script. ```shell @@ -278,7 +253,6 @@ comet optimizer -j utils/loggers/comet/hpo.py \ ### Visualizing Results -Comet provides a number of ways to visualize the results of your sweep. Take a look at -a [project with a completed sweep here](https://www.comet.com/examples/comet-example-yolov5/view/PrlArHGuuhDTKC1UuBmTtOSXD/panels?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) +Comet provides a number of ways to visualize the results of your sweep. Take a look at a [project with a completed sweep here](https://www.comet.com/examples/comet-example-yolov5/view/PrlArHGuuhDTKC1UuBmTtOSXD/panels?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) hyperparameter-yolo diff --git a/utils/loggers/comet/__init__.py b/utils/loggers/comet/__init__.py index 78d37651f6..e17704a462 100644 --- a/utils/loggers/comet/__init__.py +++ b/utils/loggers/comet/__init__.py @@ -8,7 +8,7 @@ logger = logging.getLogger(__name__) FILE = Path(__file__).resolve() -ROOT = FILE.parents[3] # YOLOv5 root directory +ROOT = FILE.parents[3] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH @@ -18,7 +18,7 @@ # Project Configuration config = comet_ml.config.get_config() COMET_PROJECT_NAME = config.get_string(os.getenv('COMET_PROJECT_NAME'), 'comet.project_name', default='yolov5') -except (ModuleNotFoundError, ImportError): +except ImportError: comet_ml = None COMET_PROJECT_NAME = None @@ -42,7 +42,7 @@ COMET_UPLOAD_DATASET = os.getenv('COMET_UPLOAD_DATASET', 'false').lower() == 'true' # Evaluation Settings -COMET_LOG_CONFUSION_MATRIX = os.getenv('COMET_LOG_CONFUSION_MATRIX', 'true').lower() == 'true' +COMET_LOG_CONFUSION_MATRIX = (os.getenv('COMET_LOG_CONFUSION_MATRIX', 'true').lower() == 'true') COMET_LOG_PREDICTIONS = os.getenv('COMET_LOG_PREDICTIONS', 'true').lower() == 'true' COMET_MAX_IMAGE_UPLOADS = int(os.getenv('COMET_MAX_IMAGE_UPLOADS', 100)) @@ -51,10 +51,10 @@ IOU_THRES = float(os.getenv('IOU_THRES', 0.6)) # Batch Logging Settings -COMET_LOG_BATCH_METRICS = os.getenv('COMET_LOG_BATCH_METRICS', 'false').lower() == 'true' +COMET_LOG_BATCH_METRICS = (os.getenv('COMET_LOG_BATCH_METRICS', 'false').lower() == 'true') COMET_BATCH_LOGGING_INTERVAL = os.getenv('COMET_BATCH_LOGGING_INTERVAL', 1) COMET_PREDICTION_LOGGING_INTERVAL = os.getenv('COMET_PREDICTION_LOGGING_INTERVAL', 1) -COMET_LOG_PER_CLASS_METRICS = os.getenv('COMET_LOG_PER_CLASS_METRICS', 'false').lower() == 'true' +COMET_LOG_PER_CLASS_METRICS = (os.getenv('COMET_LOG_PER_CLASS_METRICS', 'false').lower() == 'true') RANK = int(os.getenv('RANK', -1)) @@ -82,7 +82,7 @@ def __init__(self, opt, hyp, run_id=None, job_type='Training', **experiment_kwar self.comet_log_batch_interval = COMET_BATCH_LOGGING_INTERVAL # Dataset Artifact Settings - self.upload_dataset = self.opt.upload_dataset if self.opt.upload_dataset else COMET_UPLOAD_DATASET + self.upload_dataset = self.opt.upload_dataset or COMET_UPLOAD_DATASET self.resume = self.opt.resume # Default parameters to pass to Experiment objects @@ -93,6 +93,7 @@ def __init__(self, opt, hyp, run_id=None, job_type='Training', **experiment_kwar 'project_name': COMET_PROJECT_NAME, } self.default_experiment_kwargs.update(experiment_kwargs) self.experiment = self._get_experiment(self.comet_mode, run_id) + self.experiment.set_name(self.opt.name) self.data_dict = self.check_dataset(self.opt.data) self.class_names = self.data_dict['names'] @@ -102,7 +103,7 @@ def __init__(self, opt, hyp, run_id=None, job_type='Training', **experiment_kwar self.max_images = COMET_MAX_IMAGE_UPLOADS if run_id is None: - self.experiment.log_other('Created from', 'YOLOv5') + self.experiment.log_other('Created from', 'YOLOv3') if not isinstance(self.experiment, comet_ml.OfflineExperiment): workspace, project_name, experiment_id = self.experiment.url.split('/')[-3:] self.experiment.log_other( @@ -136,7 +137,7 @@ def __init__(self, opt, hyp, run_id=None, job_type='Training', **experiment_kwar self.comet_log_predictions = COMET_LOG_PREDICTIONS if self.opt.bbox_interval == -1: - self.comet_log_prediction_interval = 1 if self.opt.epochs < 10 else self.opt.epochs // 10 + self.comet_log_prediction_interval = (1 if self.opt.epochs < 10 else self.opt.epochs // 10) else: self.comet_log_prediction_interval = self.opt.bbox_interval @@ -231,7 +232,8 @@ def check_dataset(self, data_file): with open(data_file) as f: data_config = yaml.safe_load(f) - if data_config['path'].startswith(COMET_PREFIX): + path = data_config.get('path') + if path and path.startswith(COMET_PREFIX): path = data_config['path'].replace(COMET_PREFIX, '') data_dict = self.download_dataset_artifact(path) @@ -312,8 +314,16 @@ def add_assets_to_artifact(self, artifact, path, asset_path, split): image_logical_path, label_logical_path = map(lambda x: os.path.relpath(x, path), [image_file, label_file]) try: - artifact.add(image_file, logical_path=image_logical_path, metadata={'split': split}) - artifact.add(label_file, logical_path=label_logical_path, metadata={'split': split}) + artifact.add( + image_file, + logical_path=image_logical_path, + metadata={'split': split}, + ) + artifact.add( + label_file, + logical_path=label_logical_path, + metadata={'split': split}, + ) except ValueError as e: logger.error('COMET ERROR: Error adding file to Artifact. Skipping file.') logger.error(f'COMET ERROR: {e}') @@ -475,8 +485,9 @@ def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) 'f1': f1[i], 'true_positives': tp[i], 'false_positives': fp[i], - 'support': nt[c]}, - prefix=class_name) + 'support': nt[c], }, + prefix=class_name, + ) if self.comet_log_confusion_matrix: epoch = self.experiment.curr_epoch diff --git a/utils/loggers/comet/comet_utils.py b/utils/loggers/comet/comet_utils.py index 27600761ad..dbe7539675 100644 --- a/utils/loggers/comet/comet_utils.py +++ b/utils/loggers/comet/comet_utils.py @@ -100,7 +100,7 @@ def check_comet_weights(opt): Args: opt (argparse.Namespace): Command Line arguments passed - to YOLOv5 training script + to YOLOv3 training script Returns: None/bool: Return True if weights are successfully downloaded @@ -127,7 +127,7 @@ def check_comet_resume(opt): Args: opt (argparse.Namespace): Command Line arguments passed - to YOLOv5 training script + to YOLOv3 training script Returns: None/bool: Return True if the run is restored successfully diff --git a/utils/loggers/comet/hpo.py b/utils/loggers/comet/hpo.py index fc49115c13..daf21bc5e2 100644 --- a/utils/loggers/comet/hpo.py +++ b/utils/loggers/comet/hpo.py @@ -10,7 +10,7 @@ logger = logging.getLogger(__name__) FILE = Path(__file__).resolve() -ROOT = FILE.parents[3] # YOLOv5 root directory +ROOT = FILE.parents[3] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH @@ -26,7 +26,7 @@ def get_args(known=False): parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='initial weights path') + parser.add_argument('--weights', type=str, default=ROOT / 'yolov3-tiny.pt', help='initial weights path') parser.add_argument('--cfg', type=str, default='', help='model.yaml path') parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path') diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py index c714088283..c69e8f3ae7 100644 --- a/utils/loggers/wandb/wandb_utils.py +++ b/utils/loggers/wandb/wandb_utils.py @@ -12,7 +12,7 @@ from utils.general import LOGGER, colorstr FILE = Path(__file__).resolve() -ROOT = FILE.parents[3] # YOLOv5 root directory +ROOT = FILE.parents[3] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH RANK = int(os.getenv('RANK', -1)) @@ -66,7 +66,7 @@ def __init__(self, opt, run_id=None, job_type='Training'): if self.wandb: self.wandb_run = wandb.init(config=opt, resume='allow', - project='YOLOv5' if opt.project == 'runs/train' else Path(opt.project).stem, + project='YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem, entity=opt.entity, name=opt.name if opt.name != 'exp' else None, job_type=job_type, diff --git a/utils/plots.py b/utils/plots.py index 1ac207821d..039c0cdafd 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -8,7 +8,6 @@ import os from copy import copy from pathlib import Path -from urllib.error import URLError import cv2 import matplotlib @@ -17,14 +16,13 @@ import pandas as pd import seaborn as sn import torch -from PIL import Image, ImageDraw, ImageFont +from PIL import Image, ImageDraw from scipy.ndimage.filters import gaussian_filter1d +from ultralytics.utils.plotting import Annotator from utils import TryExcept, threaded -from utils.general import (CONFIG_DIR, FONT, LOGGER, check_font, check_requirements, clip_boxes, increment_path, - is_ascii, xywh2xyxy, xyxy2xywh) +from utils.general import LOGGER, clip_boxes, increment_path, xywh2xyxy, xyxy2xywh from utils.metrics import fitness -from utils.segment.general import scale_image # Settings RANK = int(os.getenv('RANK', -1)) @@ -53,120 +51,6 @@ def hex2rgb(h): # rgb order (PIL) colors = Colors() # create instance for 'from utils.plots import colors' -def check_pil_font(font=FONT, size=10): - # Return a PIL TrueType Font, downloading to CONFIG_DIR if necessary - font = Path(font) - font = font if font.exists() else (CONFIG_DIR / font.name) - try: - return ImageFont.truetype(str(font) if font.exists() else font.name, size) - except Exception: # download if missing - try: - check_font(font) - return ImageFont.truetype(str(font), size) - except TypeError: - check_requirements('Pillow>=8.4.0') # known issue https://github.com/ultralytics/yolov5/issues/5374 - except URLError: # not online - return ImageFont.load_default() - - -class Annotator: - # YOLOv3 Annotator for train/val mosaics and jpgs and detect/hub inference annotations - def __init__(self, im, line_width=None, font_size=None, font='Arial.ttf', pil=False, example='abc'): - assert im.data.contiguous, 'Image not contiguous. Apply np.ascontiguousarray(im) to Annotator() input images.' - non_ascii = not is_ascii(example) # non-latin labels, i.e. asian, arabic, cyrillic - self.pil = pil or non_ascii - if self.pil: # use PIL - self.im = im if isinstance(im, Image.Image) else Image.fromarray(im) - self.draw = ImageDraw.Draw(self.im) - self.font = check_pil_font(font='Arial.Unicode.ttf' if non_ascii else font, - size=font_size or max(round(sum(self.im.size) / 2 * 0.035), 12)) - else: # use cv2 - self.im = im - self.lw = line_width or max(round(sum(im.shape) / 2 * 0.003), 2) # line width - - def box_label(self, box, label='', color=(128, 128, 128), txt_color=(255, 255, 255)): - # Add one xyxy box to image with label - if self.pil or not is_ascii(label): - self.draw.rectangle(box, width=self.lw, outline=color) # box - if label: - w, h = self.font.getsize(label) # text width, height (WARNING: deprecated) in 9.2.0 - # _, _, w, h = self.font.getbbox(label) # text width, height (New) - outside = box[1] - h >= 0 # label fits outside box - self.draw.rectangle( - (box[0], box[1] - h if outside else box[1], box[0] + w + 1, - box[1] + 1 if outside else box[1] + h + 1), - fill=color, - ) - # self.draw.text((box[0], box[1]), label, fill=txt_color, font=self.font, anchor='ls') # for PIL>8.0 - self.draw.text((box[0], box[1] - h if outside else box[1]), label, fill=txt_color, font=self.font) - else: # cv2 - p1, p2 = (int(box[0]), int(box[1])), (int(box[2]), int(box[3])) - cv2.rectangle(self.im, p1, p2, color, thickness=self.lw, lineType=cv2.LINE_AA) - if label: - tf = max(self.lw - 1, 1) # font thickness - w, h = cv2.getTextSize(label, 0, fontScale=self.lw / 3, thickness=tf)[0] # text width, height - outside = p1[1] - h >= 3 - p2 = p1[0] + w, p1[1] - h - 3 if outside else p1[1] + h + 3 - cv2.rectangle(self.im, p1, p2, color, -1, cv2.LINE_AA) # filled - cv2.putText(self.im, - label, (p1[0], p1[1] - 2 if outside else p1[1] + h + 2), - 0, - self.lw / 3, - txt_color, - thickness=tf, - lineType=cv2.LINE_AA) - - def masks(self, masks, colors, im_gpu, alpha=0.5, retina_masks=False): - """Plot masks at once. - Args: - masks (tensor): predicted masks on cuda, shape: [n, h, w] - colors (List[List[Int]]): colors for predicted masks, [[r, g, b] * n] - im_gpu (tensor): img is in cuda, shape: [3, h, w], range: [0, 1] - alpha (float): mask transparency: 0.0 fully transparent, 1.0 opaque - """ - if self.pil: - # convert to numpy first - self.im = np.asarray(self.im).copy() - if len(masks) == 0: - self.im[:] = im_gpu.permute(1, 2, 0).contiguous().cpu().numpy() * 255 - colors = torch.tensor(colors, device=im_gpu.device, dtype=torch.float32) / 255.0 - colors = colors[:, None, None] # shape(n,1,1,3) - masks = masks.unsqueeze(3) # shape(n,h,w,1) - masks_color = masks * (colors * alpha) # shape(n,h,w,3) - - inv_alph_masks = (1 - masks * alpha).cumprod(0) # shape(n,h,w,1) - mcs = (masks_color * inv_alph_masks).sum(0) * 2 # mask color summand shape(n,h,w,3) - - im_gpu = im_gpu.flip(dims=[0]) # flip channel - im_gpu = im_gpu.permute(1, 2, 0).contiguous() # shape(h,w,3) - im_gpu = im_gpu * inv_alph_masks[-1] + mcs - im_mask = (im_gpu * 255).byte().cpu().numpy() - self.im[:] = im_mask if retina_masks else scale_image(im_gpu.shape, im_mask, self.im.shape) - if self.pil: - # convert im back to PIL and update draw - self.fromarray(self.im) - - def rectangle(self, xy, fill=None, outline=None, width=1): - # Add rectangle to image (PIL-only) - self.draw.rectangle(xy, fill, outline, width) - - def text(self, xy, text, txt_color=(255, 255, 255), anchor='top'): - # Add text to image (PIL-only) - if anchor == 'bottom': # start y from font bottom - w, h = self.font.getsize(text) # text width, height - xy[1] += 1 - h - self.draw.text(xy, text, fill=txt_color, font=self.font) - - def fromarray(self, im): - # Update self.im from a numpy array - self.im = im if isinstance(im, Image.Image) else Image.fromarray(im) - self.draw = ImageDraw.Draw(self.im) - - def result(self): - # Return annotated image as array - return np.asarray(self.im) - - def feature_visualization(x, module_type, stage, n=32, save_dir=Path('runs/detect/exp')): """ x: Features to be visualized @@ -266,7 +150,7 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None): x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin annotator.rectangle([x, y, x + w, y + h], None, (255, 255, 255), width=2) # borders if paths: - annotator.text((x + 5, y + 5), text=Path(paths[i]).name[:40], txt_color=(220, 220, 220)) # filenames + annotator.text([x + 5, y + 5], text=Path(paths[i]).name[:40], txt_color=(220, 220, 220)) # filenames if len(targets) > 0: ti = targets[targets[:, 0] == i] # image targets boxes = xywh2xyxy(ti[:, 2:6]).T diff --git a/utils/segment/dataloaders.py b/utils/segment/dataloaders.py index c796ede565..b6daef2c7b 100644 --- a/utils/segment/dataloaders.py +++ b/utils/segment/dataloaders.py @@ -206,7 +206,7 @@ def __getitem__(self, index): return (torch.from_numpy(img), labels_out, self.im_files[index], shapes, masks) def load_mosaic(self, index): - # YOLOv5 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic + # YOLOv3 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic labels4, segments4 = [], [] s = self.img_size yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y diff --git a/utils/segment/general.py b/utils/segment/general.py index 9da8945386..f1b2f1dd12 100644 --- a/utils/segment/general.py +++ b/utils/segment/general.py @@ -10,7 +10,7 @@ def crop_mask(masks, boxes): Vectorized by Chong (thanks Chong). Args: - - masks should be a size [h, w, n] tensor of masks + - masks should be a size [n, h, w] tensor of masks - boxes should be a size [n, 4] tensor of bbox coords in relative point form """ diff --git a/utils/segment/loss.py b/utils/segment/loss.py index 2a8a4c680f..caeff3cad5 100644 --- a/utils/segment/loss.py +++ b/utils/segment/loss.py @@ -16,7 +16,6 @@ def __init__(self, model, autobalance=False, overlap=False): self.overlap = overlap device = next(model.parameters()).device # get model device h = model.hyp # hyperparameters - self.device = device # Define criteria BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device)) diff --git a/utils/segment/plots.py b/utils/segment/plots.py index 3ba097624f..f9938cd1b0 100644 --- a/utils/segment/plots.py +++ b/utils/segment/plots.py @@ -54,7 +54,7 @@ def plot_images_and_masks(images, targets, masks, paths=None, fname='images.jpg' x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin annotator.rectangle([x, y, x + w, y + h], None, (255, 255, 255), width=2) # borders if paths: - annotator.text((x + 5, y + 5 + h), text=Path(paths[i]).name[:40], txt_color=(220, 220, 220)) # filenames + annotator.text([x + 5, y + 5], text=Path(paths[i]).name[:40], txt_color=(220, 220, 220)) # filenames if len(targets) > 0: idx = targets[:, 0] == i ti = targets[idx] # image targets diff --git a/val.py b/val.py index fe1bc66d1d..8a82108567 100644 --- a/val.py +++ b/val.py @@ -31,7 +31,7 @@ from tqdm import tqdm FILE = Path(__file__).resolve() -ROOT = FILE.parents[0] # root directory +ROOT = FILE.parents[0] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative @@ -304,6 +304,8 @@ def run( if save_json and len(jdict): w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights anno_json = str(Path('../datasets/coco/annotations/instances_val2017.json')) # annotations + if not os.path.exists(anno_json): + anno_json = os.path.join(data['path'], 'annotations', 'instances_val2017.json') pred_json = str(save_dir / f'{w}_predictions.json') # predictions LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') with open(pred_json, 'w') as f: @@ -398,7 +400,7 @@ def main(opt): r, _, t = run(**vars(opt), plots=False) y.append(r + t) # results and times np.savetxt(f, y, fmt='%10.4g') # save - subprocess.run('zip -r study.zip study_*.txt'.split()) + subprocess.run(['zip', '-r', 'study.zip', 'study_*.txt']) plot_val_study(x=x) # plot else: raise NotImplementedError(f'--task {opt.task} not in ("train", "val", "test", "speed", "study")') From 8767b2209ddb2fbc37f201911676c5bec221368f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 1 Aug 2023 22:32:30 +0200 Subject: [PATCH 0997/1185] [Snyk] Security upgrade numpy from 1.21.3 to 1.22.2 (#2101) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321964 - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321966 - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321970 Co-authored-by: snyk-bot From b9c40f333229b85ddb1c38b39fb79ad50e540822 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 3 Aug 2023 01:52:37 +0200 Subject: [PATCH 0998/1185] Update requirements.txt to `ultralytics>=8.0.147` (#2103) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e00ba300e5..1e25bffb4d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ thop>=0.1.1 # FLOPs computation torch>=1.7.0 # see https://pytorch.org/get-started/locally (recommended) torchvision>=0.8.1 tqdm>=4.64.0 -ultralytics>=8.0.146 +ultralytics>=8.0.147 # protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 # Logging --------------------------------------------------------------------- From 44cb63f69feb2c7f3d0c0428c2d3c03f3f8ab630 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 01:53:31 +0200 Subject: [PATCH 0999/1185] Replace `type(1) == int` with `isinstance(1, int)` (#2104) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit suggestions updates: - [github.com/asottile/pyupgrade: v3.8.0 → v3.10.1](https://github.com/asottile/pyupgrade/compare/v3.8.0...v3.10.1) - [github.com/PyCQA/flake8: 6.0.0 → 6.1.0](https://github.com/PyCQA/flake8/compare/6.0.0...6.1.0) * Update __init__.py * Update __init__.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- .pre-commit-config.yaml | 4 ++-- utils/loggers/comet/__init__.py | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 192a0ff3cb..b8099b9789 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: - id: detect-private-key - repo: https://github.com/asottile/pyupgrade - rev: v3.8.0 + rev: v3.10.1 hooks: - id: pyupgrade name: Upgrade code @@ -50,7 +50,7 @@ repos: # exclude: "README.md|README.zh-CN.md|CONTRIBUTING.md" - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 + rev: 6.1.0 hooks: - id: flake8 name: PEP8 diff --git a/utils/loggers/comet/__init__.py b/utils/loggers/comet/__init__.py index e17704a462..c3e999d81e 100644 --- a/utils/loggers/comet/__init__.py +++ b/utils/loggers/comet/__init__.py @@ -365,15 +365,14 @@ def download_dataset_artifact(self, artifact_path): data_dict['path'] = artifact_save_dir metadata_names = metadata.get('names') - if type(metadata_names) == dict: + if isinstance(metadata_names, dict): data_dict['names'] = {int(k): v for k, v in metadata.get('names').items()} - elif type(metadata_names) == list: + elif isinstance(metadata_names, list): data_dict['names'] = {int(k): v for k, v in zip(range(len(metadata_names)), metadata_names)} else: raise "Invalid 'names' field in dataset yaml file. Please use a list or dictionary" - data_dict = self.update_data_paths(data_dict) - return data_dict + return self.update_data_paths(data_dict) def update_data_paths(self, data_dict): path = data_dict.get('path', '') From 316c2e371c51500cb1a03762386a4ccf74dd09c5 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 23 Aug 2023 20:56:15 +0200 Subject: [PATCH 1000/1185] Update links.yml to exclude Kaggle (#2106) --- .github/workflows/links.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index cd65b961f7..4bee94534b 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -28,7 +28,7 @@ jobs: timeout_minutes: 5 retry_wait_seconds: 60 max_attempts: 3 - command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(twitter\.com|instagram\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' + command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' - name: Test Markdown, HTML, YAML, Python and Notebook links with retry if: github.event_name == 'workflow_dispatch' @@ -37,4 +37,4 @@ jobs: timeout_minutes: 5 retry_wait_seconds: 60 max_attempts: 3 - command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(twitter\.com|instagram\.com|url\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' + command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|url\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' From 5edcae0d3c2cf4ee85a598c45595aac8dd6fa1cb Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 5 Sep 2023 01:11:07 +0200 Subject: [PATCH 1001/1185] Update requirements.txt `torch>1.8.0` (#2110) * Update requirements.txt `torch>1.8.0` * Update ci-testing.yml --- .github/workflows/ci-testing.yml | 8 ++++---- requirements.txt | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 727e83fe3f..a05d44db52 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -29,9 +29,9 @@ jobs: python-version: '3.9' model: yolov5n - os: ubuntu-latest - python-version: '3.8' # torch 1.7.0 requires python >=3.6, <=3.8 + python-version: '3.8' # torch 1.8.0 requires python >=3.6, <=3.8 model: yolov5n - torch: '1.7.0' # min torch version CI https://pypi.org/project/torchvision/ + torch: '1.8.0' # min torch version CI https://pypi.org/project/torchvision/ steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 @@ -41,8 +41,8 @@ jobs: - name: Install requirements run: | python -m pip install --upgrade pip wheel - if [ "${{ matrix.torch }}" == "1.7.0" ]; then - pip install -r requirements.txt torch==1.7.0 torchvision==0.8.1 --extra-index-url https://download.pytorch.org/whl/cpu + if [ "${{ matrix.torch }}" == "1.8.0" ]; then + pip install -r requirements.txt torch==1.8.0 torchvision==0.9.0 --extra-index-url https://download.pytorch.org/whl/cpu else pip install -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cpu fi diff --git a/requirements.txt b/requirements.txt index 1e25bffb4d..e4cd0e2d7e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,8 +12,8 @@ PyYAML>=5.3.1 requests>=2.23.0 scipy>=1.4.1 thop>=0.1.1 # FLOPs computation -torch>=1.7.0 # see https://pytorch.org/get-started/locally (recommended) -torchvision>=0.8.1 +torch>=1.8.0 # see https://pytorch.org/get-started/locally (recommended) +torchvision>=0.9.0 tqdm>=4.64.0 ultralytics>=8.0.147 # protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 From 9d7cb763f2252cb02a4f03d73148d30eb7ae6364 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 21:30:50 +0200 Subject: [PATCH 1002/1185] [pre-commit.ci] pre-commit suggestions (#2111) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/executablebooks/mdformat: 0.7.16 → 0.7.17](https://github.com/executablebooks/mdformat/compare/0.7.16...0.7.17) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b8099b9789..ff21906143 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,7 +40,7 @@ repos: name: YAPF formatting - repo: https://github.com/executablebooks/mdformat - rev: 0.7.16 + rev: 0.7.17 hooks: - id: mdformat name: MD formatting From 738ff94166684ca8f54d5916902d434aa6b7c14c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 10 Sep 2023 04:59:06 +0200 Subject: [PATCH 1003/1185] Update YouTube URL https://youtu.be/LNwODJXcvt4 (#2112) Update example YouTube URL --- README.md | 2 +- README.zh-CN.md | 2 +- classify/predict.py | 2 +- classify/tutorial.ipynb | 2 +- detect.py | 2 +- segment/predict.py | 2 +- segment/tutorial.ipynb | 2 +- tutorial.ipynb | 2 +- utils/dataloaders.py | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1cb8fc29eb..d9a4ae6844 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ python detect.py --weights yolov5s.pt --source 0 # list.txt # list of images list.streams # list of streams 'path/*.jpg' # glob - 'https://youtu.be/Zgi9g1ksQHc' # YouTube + 'https://youtu.be/LNwODJXcvt4' # YouTube 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream ``` diff --git a/README.zh-CN.md b/README.zh-CN.md index 7340f43d09..a05dd93383 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -122,7 +122,7 @@ python detect.py --weights yolov5s.pt --source 0 # list.txt # list of images list.streams # list of streams 'path/*.jpg' # glob - 'https://youtu.be/Zgi9g1ksQHc' # YouTube + 'https://youtu.be/LNwODJXcvt4' # YouTube 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream ``` diff --git a/classify/predict.py b/classify/predict.py index 5ebbfe9aae..692cd607b8 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -11,7 +11,7 @@ list.txt # list of images list.streams # list of streams 'path/*.jpg' # glob - 'https://youtu.be/Zgi9g1ksQHc' # YouTube + 'https://youtu.be/LNwODJXcvt4' # YouTube 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream Usage - formats: diff --git a/classify/tutorial.ipynb b/classify/tutorial.ipynb index 5aa7237161..d9e1d69137 100644 --- a/classify/tutorial.ipynb +++ b/classify/tutorial.ipynb @@ -87,7 +87,7 @@ " screen # screenshot\n", " path/ # directory\n", " 'path/*.jpg' # glob\n", - " 'https://youtu.be/Zgi9g1ksQHc' # YouTube\n", + " 'https://youtu.be/LNwODJXcvt4' # YouTube\n", " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", "```" ] diff --git a/detect.py b/detect.py index 0f3898487e..8ef95761f0 100644 --- a/detect.py +++ b/detect.py @@ -11,7 +11,7 @@ list.txt # list of images list.streams # list of streams 'path/*.jpg' # glob - 'https://youtu.be/Zgi9g1ksQHc' # YouTube + 'https://youtu.be/LNwODJXcvt4' # YouTube 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream Usage - formats: diff --git a/segment/predict.py b/segment/predict.py index 694b47a763..ae3f5d960f 100644 --- a/segment/predict.py +++ b/segment/predict.py @@ -11,7 +11,7 @@ list.txt # list of images list.streams # list of streams 'path/*.jpg' # glob - 'https://youtu.be/Zgi9g1ksQHc' # YouTube + 'https://youtu.be/LNwODJXcvt4' # YouTube 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream Usage - formats: diff --git a/segment/tutorial.ipynb b/segment/tutorial.ipynb index b87658e106..5b4b46303a 100644 --- a/segment/tutorial.ipynb +++ b/segment/tutorial.ipynb @@ -87,7 +87,7 @@ " screen # screenshot\n", " path/ # directory\n", " 'path/*.jpg' # glob\n", - " 'https://youtu.be/Zgi9g1ksQHc' # YouTube\n", + " 'https://youtu.be/LNwODJXcvt4' # YouTube\n", " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", "```" ] diff --git a/tutorial.ipynb b/tutorial.ipynb index c6b527c802..a44d85ddad 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -100,7 +100,7 @@ " screen # screenshot\n", " path/ # directory\n", " 'path/*.jpg' # glob\n", - " 'https://youtu.be/Zgi9g1ksQHc' # YouTube\n", + " 'https://youtu.be/LNwODJXcvt4' # YouTube\n", " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", "```" ] diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 0ed126899c..5d119c2e77 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -355,7 +355,7 @@ def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, t # Start thread to read frames from video stream st = f'{i + 1}/{n}: {s}... ' if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video - # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc' + # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/LNwODJXcvt4' check_requirements(('pafy', 'youtube_dl==2020.12.2')) import pafy s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL From 58eca445e05b3874bcfc5481bd59db61d5ce0809 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 20:47:47 +0200 Subject: [PATCH 1004/1185] Bump actions/checkout from 3 to 4 (#2113) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-testing.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/links.yml | 2 +- .github/workflows/translate-readme.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index a05d44db52..84fed0c0d7 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -33,7 +33,7 @@ jobs: model: yolov5n torch: '1.8.0' # min torch version CI https://pypi.org/project/torchvision/ steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 05db12dabd..53af304ee9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 84f4475eef..1a2dcf9c4d 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v2 diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 4bee94534b..c2665fd3f2 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -13,7 +13,7 @@ jobs: Links: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Download and install lychee run: | diff --git a/.github/workflows/translate-readme.yml b/.github/workflows/translate-readme.yml index 5632b62aed..ba07066e65 100644 --- a/.github/workflows/translate-readme.yml +++ b/.github/workflows/translate-readme.yml @@ -14,7 +14,7 @@ jobs: Translate: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v3 with: From 5c5be115c9065fcc4475279586ae9392faeaf410 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 14:26:48 +0200 Subject: [PATCH 1005/1185] Bump docker/setup-qemu-action from 2 to 3 (#2118) Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2 to 3. - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 1a2dcf9c4d..80d3251447 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 From b99099b1fb633f350aa0227970a685a63c543dda Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 14:27:08 +0200 Subject: [PATCH 1006/1185] Bump docker/setup-buildx-action from 2 to 3 (#2116) Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2 to 3. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 80d3251447..749d9b3967 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -21,7 +21,7 @@ jobs: uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub uses: docker/login-action@v2 From 0b950875d9856f4c5e6c5d7b61e9b92e53a076b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 14:28:35 +0200 Subject: [PATCH 1007/1185] Bump docker/build-push-action from 4 to 5 (#2117) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 4 to 5. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v4...v5) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 749d9b3967..336be1d39c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -30,7 +30,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push arm64 image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 continue-on-error: true with: context: . @@ -40,7 +40,7 @@ jobs: tags: ultralytics/yolov3:latest-arm64 - name: Build and push CPU image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 continue-on-error: true with: context: . @@ -49,7 +49,7 @@ jobs: tags: ultralytics/yolov3:latest-cpu - name: Build and push GPU image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 continue-on-error: true with: context: . From ecd5112dfb59b49cbb16876c7d99f0e4a8973877 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 14:31:49 +0200 Subject: [PATCH 1008/1185] Bump docker/login-action from 2 to 3 (#2115) Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/login-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 336be1d39c..46d263f596 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -24,7 +24,7 @@ jobs: uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} From 814fd8d5460e80578788dfdef2fcc2d1f2801a6d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 15:47:14 +0200 Subject: [PATCH 1009/1185] [pre-commit.ci] pre-commit suggestions (#2120) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.10.1 → v3.14.0](https://github.com/asottile/pyupgrade/compare/v3.10.1...v3.14.0) - [github.com/google/yapf: v0.40.0 → v0.40.2](https://github.com/google/yapf/compare/v0.40.0...v0.40.2) - [github.com/codespell-project/codespell: v2.2.5 → v2.2.6](https://github.com/codespell-project/codespell/compare/v2.2.5...v2.2.6) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ff21906143..39ab266f70 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: - id: detect-private-key - repo: https://github.com/asottile/pyupgrade - rev: v3.10.1 + rev: v3.14.0 hooks: - id: pyupgrade name: Upgrade code @@ -34,7 +34,7 @@ repos: name: Sort imports - repo: https://github.com/google/yapf - rev: v0.40.0 + rev: v0.40.2 hooks: - id: yapf name: YAPF formatting @@ -56,7 +56,7 @@ repos: name: PEP8 - repo: https://github.com/codespell-project/codespell - rev: v2.2.5 + rev: v2.2.6 hooks: - id: codespell args: From 0252becdb82d185b13a582882d52d62b22a6cee0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 14 Oct 2023 19:18:32 +0200 Subject: [PATCH 1010/1185] Update Dockerfile-cpu `FROM ubuntu:23.04` (#2121) --- utils/docker/Dockerfile-cpu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/docker/Dockerfile-cpu b/utils/docker/Dockerfile-cpu index d79e3839a6..35ee8d01f2 100644 --- a/utils/docker/Dockerfile-cpu +++ b/utils/docker/Dockerfile-cpu @@ -3,7 +3,7 @@ # Image is CPU-optimized for ONNX, OpenVINO and PyTorch YOLOv5 deployments # Start FROM Ubuntu image https://hub.docker.com/_/ubuntu -FROM ubuntu:lunar-20230615 +FROM ubuntu:23.04 # Downloads to user config dir ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/ From 47c6f2fabe3cdcb42c5ddb465a332e1308a07a24 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 21 Oct 2023 18:08:02 +0200 Subject: [PATCH 1011/1185] Exclude url.com and gstatic.com from links.yml (#2126) * Exclude url.com and gstatic.com from links.yml * Update links.yml --- .github/workflows/links.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index c2665fd3f2..5d897da3c1 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -28,7 +28,7 @@ jobs: timeout_minutes: 5 retry_wait_seconds: 60 max_attempts: 3 - command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' + command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' - name: Test Markdown, HTML, YAML, Python and Notebook links with retry if: github.event_name == 'workflow_dispatch' @@ -37,4 +37,4 @@ jobs: timeout_minutes: 5 retry_wait_seconds: 60 max_attempts: 3 - command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|url\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' + command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|url\.com|fonts\.gstatic\.com|url\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' From f85ba8e2e9366b8d71af022effadf1805a4603e6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Oct 2023 18:57:35 +0200 Subject: [PATCH 1012/1185] Fix discord social image URL (#2128) --- README.md | 4 ++-- README.zh-CN.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d9a4ae6844..6df5f25c29 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ To request an Enterprise License please complete the form at [Ultralytics Licens - +
@@ -490,7 +490,7 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/ - + [tta]: https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation diff --git a/README.zh-CN.md b/README.zh-CN.md index a05dd93383..668119fa70 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -44,7 +44,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 - + @@ -485,7 +485,7 @@ Ultralytics 提供两种许可证选项以适应各种使用场景: - + [tta]: https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation From 969129bc2dc97f7dcaed81aaa73eaa24383e7423 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 26 Oct 2023 19:28:07 +0200 Subject: [PATCH 1013/1185] Update social media links (#2129) * Update social media links * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- README.md | 83 +++++++++++++++++------------------------------ README.zh-CN.md | 85 +++++++++++++++++++------------------------------ 2 files changed, 62 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index 6df5f25c29..7087b54f28 100644 --- a/README.md +++ b/README.md @@ -25,36 +25,26 @@ We hope that the resources here will help you get the most out of YOLOv3. Please To request an Enterprise License please complete the form at [Ultralytics Licensing](https://ultralytics.com/license).
- - - - - - - - - - - - - - - - - - - - + Ultralytics GitHub + + Ultralytics LinkedIn + + Ultralytics Twitter + + Ultralytics YouTube + + Ultralytics TikTok + + Ultralytics Instagram + + Ultralytics Discord

##
YOLOv8 🚀 NEW
-We are thrilled to announce the launch of Ultralytics YOLOv8 🚀, our NEW cutting-edge, state-of-the-art (SOTA) model -released at **[https://github.com/ultralytics/ultralytics](https://github.com/ultralytics/ultralytics)**. -YOLOv8 is designed to be fast, accurate, and easy to use, making it an excellent choice for a wide range of -object detection, image segmentation and image classification tasks. +We are thrilled to announce the launch of Ultralytics YOLOv8 🚀, our NEW cutting-edge, state-of-the-art (SOTA) model released at **[https://github.com/ultralytics/ultralytics](https://github.com/ultralytics/ultralytics)**. YOLOv8 is designed to be fast, accurate, and easy to use, making it an excellent choice for a wide range of object detection, image segmentation and image classification tasks. See the [YOLOv8 Docs](https://docs.ultralytics.com) for details and get started with: @@ -91,8 +81,7 @@ pip install -r requirements.txt # install
Inference -YOLOv3 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) inference. [Models](https://github.com/ultralytics/yolov5/tree/master/models) download automatically from the latest -YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). +YOLOv3 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) inference. [Models](https://github.com/ultralytics/yolov5/tree/master/models) download automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). ```python import torch @@ -115,8 +104,7 @@ results.print() # or .show(), .save(), .crop(), .pandas(), etc.
Inference with detect.py -`detect.py` runs inference on a variety of sources, downloading [models](https://github.com/ultralytics/yolov5/tree/master/models) automatically from -the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) and saving results to `runs/detect`. +`detect.py` runs inference on a variety of sources, downloading [models](https://github.com/ultralytics/yolov5/tree/master/models) automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) and saving results to `runs/detect`. ```bash python detect.py --weights yolov5s.pt --source 0 # webcam @@ -138,11 +126,7 @@ python detect.py --weights yolov5s.pt --source 0 # The commands below reproduce YOLOv3 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) results. [Models](https://github.com/ultralytics/yolov5/tree/master/models) -and [datasets](https://github.com/ultralytics/yolov5/tree/master/data) download automatically from the latest -YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). Training times for YOLOv5n/s/m/l/x are -1/2/4/6/8 days on a V100 GPU ([Multi-GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) times faster). Use the -largest `--batch-size` possible, or pass `--batch-size -1` for -YOLOv3 [AutoBatch](https://github.com/ultralytics/yolov5/pull/5092). Batch sizes shown for V100-16GB. +and [datasets](https://github.com/ultralytics/yolov5/tree/master/data) download automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). Training times for YOLOv5n/s/m/l/x are 1/2/4/6/8 days on a V100 GPU ([Multi-GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) times faster). Use the largest `--batch-size` possible, or pass `--batch-size -1` for YOLOv3 [AutoBatch](https://github.com/ultralytics/yolov5/pull/5092). Batch sizes shown for V100-16GB. ```bash python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml --batch-size 128 @@ -471,26 +455,19 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/
- - - - - - - - - - - - - - - - - - - - + Ultralytics GitHub + + Ultralytics LinkedIn + + Ultralytics Twitter + + Ultralytics YouTube + + Ultralytics TikTok + + Ultralytics Instagram + + Ultralytics Discord
[tta]: https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation diff --git a/README.zh-CN.md b/README.zh-CN.md index 668119fa70..f1e6b78291 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -25,33 +25,25 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 - - - - - - - - - - - - - - - - - - - - + Ultralytics GitHub + + Ultralytics LinkedIn + + Ultralytics Twitter + + Ultralytics YouTube + + Ultralytics TikTok + + Ultralytics Instagram + + Ultralytics Discord ##
YOLOv8 🚀 新品
-我们很高兴宣布 Ultralytics YOLOv8 🚀 的发布,这是我们新推出的领先水平、最先进的(SOTA)模型,发布于 **[https://github.com/ultralytics/ultralytics](https://github.com/ultralytics/ultralytics)**。 -YOLOv8 旨在快速、准确且易于使用,使其成为广泛的物体检测、图像分割和图像分类任务的极佳选择。 +我们很高兴宣布 Ultralytics YOLOv8 🚀 的发布,这是我们新推出的领先水平、最先进的(SOTA)模型,发布于 **[https://github.com/ultralytics/ultralytics](https://github.com/ultralytics/ultralytics)**。 YOLOv8 旨在快速、准确且易于使用,使其成为广泛的物体检测、图像分割和图像分类任务的极佳选择。 请查看 [YOLOv8 文档](https://docs.ultralytics.com)了解详细信息,并开始使用: @@ -86,8 +78,7 @@ pip install -r requirements.txt # install
推理 -使用 YOLOv3 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) 推理。最新 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 将自动的从 -YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 +使用 YOLOv3 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) 推理。最新 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 ```python import torch @@ -110,8 +101,7 @@ results.print() # or .show(), .save(), .crop(), .pandas(), etc.
使用 detect.py 推理 -`detect.py` 在各种来源上运行推理, [模型](https://github.com/ultralytics/yolov5/tree/master/models) 自动从 -最新的YOLOv5 [release](https://github.com/ultralytics/yolov5/releases) 中下载,并将结果保存到 `runs/detect` 。 +`detect.py` 在各种来源上运行推理, [模型](https://github.com/ultralytics/yolov5/tree/master/models) 自动从 最新的YOLOv5 [release](https://github.com/ultralytics/yolov5/releases) 中下载,并将结果保存到 `runs/detect` 。 ```bash python detect.py --weights yolov5s.pt --source 0 # webcam @@ -131,12 +121,8 @@ python detect.py --weights yolov5s.pt --source 0 #
训练 -下面的命令重现 YOLOv3 在 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) 数据集上的结果。 -最新的 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 和 [数据集](https://github.com/ultralytics/yolov5/tree/master/data) -将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 -YOLOv5n/s/m/l/x 在 V100 GPU 的训练时间为 1/2/4/6/8 天( [多GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) 训练速度更快)。 -尽可能使用更大的 `--batch-size` ,或通过 `--batch-size -1` 实现 -YOLOv3 [自动批处理](https://github.com/ultralytics/yolov5/pull/5092) 。下方显示的 batchsize 适用于 V100-16GB。 +下面的命令重现 YOLOv3 在 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) 数据集上的结果。 最新的 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 和 [数据集](https://github.com/ultralytics/yolov5/tree/master/data) +将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 YOLOv5n/s/m/l/x 在 V100 GPU 的训练时间为 1/2/4/6/8 天( [多GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) 训练速度更快)。 尽可能使用更大的 `--batch-size` ,或通过 `--batch-size -1` 实现 YOLOv3 [自动批处理](https://github.com/ultralytics/yolov5/pull/5092) 。下方显示的 batchsize 适用于 V100-16GB。 ```bash python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml --batch-size 128 @@ -251,7 +237,7 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结
-##
实例分割模型 ⭐ 新
+##
实例分割模型 ⭐ 新
我们新的 YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7.0) 实例分割模型是世界上最快和最准确的模型,击败所有当前 [SOTA 基准](https://paperswithcode.com/sota/real-time-instance-segmentation-on-mscoco)。我们使它非常易于训练、验证和部署。更多细节请查看 [发行说明](https://github.com/ultralytics/yolov5/releases/v7.0) 或访问我们的 [YOLOv5 分割 Colab 笔记本](https://github.com/ultralytics/yolov5/blob/master/segment/tutorial.ipynb) 以快速入门。 @@ -466,26 +452,19 @@ Ultralytics 提供两种许可证选项以适应各种使用场景:
- - - - - - - - - - - - - - - - - - - - + Ultralytics GitHub + + Ultralytics LinkedIn + + Ultralytics Twitter + + Ultralytics YouTube + + Ultralytics TikTok + + Ultralytics Instagram + + Ultralytics Discord
[tta]: https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation From 109527edf2c45dc25983455fbf2d9f76623543c9 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 29 Oct 2023 20:07:57 +0100 Subject: [PATCH 1014/1185] [Snyk] Security upgrade werkzeug from 2.2.3 to 3.0.1 (#2130) fix: utils/google_app_engine/additional_requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-WERKZEUG-6035177 Co-authored-by: snyk-bot --- utils/google_app_engine/additional_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/google_app_engine/additional_requirements.txt b/utils/google_app_engine/additional_requirements.txt index fce1511588..a29141a633 100644 --- a/utils/google_app_engine/additional_requirements.txt +++ b/utils/google_app_engine/additional_requirements.txt @@ -2,4 +2,4 @@ pip==21.1 Flask==2.3.2 gunicorn==19.10.0 -werkzeug>=2.2.3 # not directly required, pinned by Snyk to avoid a vulnerability +werkzeug>=3.0.1 # not directly required, pinned by Snyk to avoid a vulnerability From 71b264cef07e1470bc35a25e46e6dd925fb03376 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Nov 2023 11:00:21 +0100 Subject: [PATCH 1015/1185] Bump actions/setup-node from 3 to 4 (#2131) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/translate-readme.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/translate-readme.yml b/.github/workflows/translate-readme.yml index ba07066e65..4a404539b9 100644 --- a/.github/workflows/translate-readme.yml +++ b/.github/workflows/translate-readme.yml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 16 # ISO Language Codes: https://cloud.google.com/translate/docs/languages From 0e86f37797f8e7c8027a7acaff62a73f74267563 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 3 Nov 2023 16:01:41 +0100 Subject: [PATCH 1016/1185] Update links.yml (#2134) * Update links.yml * Update links.yml --- .github/workflows/links.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 5d897da3c1..05408fd622 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -1,6 +1,11 @@ # Ultralytics YOLO 🚀, AGPL-3.0 license -# YOLO Continuous Integration (CI) GitHub Actions tests broken link checker -# Accept 429(Instagram, 'too many requests'), 999(LinkedIn, 'unknown status code'), Timeout(Twitter) +# Continuous Integration (CI) GitHub Actions tests broken link checker using https://github.com/lycheeverse/lychee +# Ignores the following status codes to reduce false positives: +# - 403(OpenVINO, 'forbidden') +# - 429(Instagram, 'too many requests') +# - 500(Zenodo, 'cached') +# - 502(Zenodo, 'bad gateway') +# - 999(LinkedIn, 'unknown status code') name: Check Broken links @@ -28,7 +33,7 @@ jobs: timeout_minutes: 5 retry_wait_seconds: 60 max_attempts: 3 - command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' + command: lychee --accept 403,429,500,502,999 --exclude-loopback --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' - name: Test Markdown, HTML, YAML, Python and Notebook links with retry if: github.event_name == 'workflow_dispatch' @@ -37,4 +42,4 @@ jobs: timeout_minutes: 5 retry_wait_seconds: 60 max_attempts: 3 - command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|url\.com|fonts\.gstatic\.com|url\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' + command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' From 4fb31ba86178c5689dc2a850e20b585f6dedbe52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 16:01:53 +0100 Subject: [PATCH 1017/1185] Bump pip from 21.1 to 23.3 in /utils/google_app_engine (#2133) Bumps [pip](https://github.com/pypa/pip) from 21.1 to 23.3. - [Changelog](https://github.com/pypa/pip/blob/main/NEWS.rst) - [Commits](https://github.com/pypa/pip/compare/21.1...23.3) --- updated-dependencies: - dependency-name: pip dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- utils/google_app_engine/additional_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/google_app_engine/additional_requirements.txt b/utils/google_app_engine/additional_requirements.txt index a29141a633..c1a2af2c11 100644 --- a/utils/google_app_engine/additional_requirements.txt +++ b/utils/google_app_engine/additional_requirements.txt @@ -1,5 +1,5 @@ # add these requirements in your app on top of the existing ones -pip==21.1 +pip==23.3 Flask==2.3.2 gunicorn==19.10.0 werkzeug>=3.0.1 # not directly required, pinned by Snyk to avoid a vulnerability From 472d647a2b65deb170385e3df491d582c62eb13e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 3 Nov 2023 18:59:25 +0100 Subject: [PATCH 1018/1185] [Snyk] Security upgrade ubuntu from 23.04 to mantic-20231011 (#2132) * fix: utils/docker/Dockerfile-cpu to reduce vulnerabilities The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-UBUNTU2304-GLIBC-5919743 - https://snyk.io/vuln/SNYK-UBUNTU2304-GLIBC-5919743 - https://snyk.io/vuln/SNYK-UBUNTU2304-PROCPS-5816666 - https://snyk.io/vuln/SNYK-UBUNTU2304-PROCPS-5816666 - https://snyk.io/vuln/SNYK-UBUNTU2304-XZUTILS-5854648 * Update apt install libgl1-mesa-glx to libgl1 --------- Co-authored-by: snyk-bot --- utils/docker/Dockerfile | 2 +- utils/docker/Dockerfile-arm64 | 2 +- utils/docker/Dockerfile-cpu | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/docker/Dockerfile b/utils/docker/Dockerfile index fbffdbbe0c..8ccb7c2090 100644 --- a/utils/docker/Dockerfile +++ b/utils/docker/Dockerfile @@ -12,7 +12,7 @@ ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Aria ENV DEBIAN_FRONTEND noninteractive RUN apt update RUN TZ=Etc/UTC apt install -y tzdata -RUN apt install --no-install-recommends -y gcc git zip curl htop libgl1-mesa-glx libglib2.0-0 libpython3-dev gnupg +RUN apt install --no-install-recommends -y gcc git zip curl htop libgl1 libglib2.0-0 libpython3-dev gnupg # RUN alias python=python3 # Security updates diff --git a/utils/docker/Dockerfile-arm64 b/utils/docker/Dockerfile-arm64 index 9a9f1a69d9..574e1e9154 100644 --- a/utils/docker/Dockerfile-arm64 +++ b/utils/docker/Dockerfile-arm64 @@ -12,7 +12,7 @@ ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Aria ENV DEBIAN_FRONTEND noninteractive RUN apt update RUN TZ=Etc/UTC apt install -y tzdata -RUN apt install --no-install-recommends -y python3-pip git zip curl htop gcc libgl1-mesa-glx libglib2.0-0 libpython3-dev +RUN apt install --no-install-recommends -y python3-pip git zip curl htop gcc libgl1 libglib2.0-0 libpython3-dev # RUN alias python=python3 # Install pip packages diff --git a/utils/docker/Dockerfile-cpu b/utils/docker/Dockerfile-cpu index 35ee8d01f2..acebf09951 100644 --- a/utils/docker/Dockerfile-cpu +++ b/utils/docker/Dockerfile-cpu @@ -3,7 +3,7 @@ # Image is CPU-optimized for ONNX, OpenVINO and PyTorch YOLOv5 deployments # Start FROM Ubuntu image https://hub.docker.com/_/ubuntu -FROM ubuntu:23.04 +FROM ubuntu:mantic-20231011 # Downloads to user config dir ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/ @@ -11,7 +11,7 @@ ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Aria # Install linux packages # g++ required to build 'tflite_support' and 'lap' packages, libusb-1.0-0 required for 'tflite_support' package RUN apt update \ - && apt install --no-install-recommends -y python3-pip git zip curl htop libgl1-mesa-glx libglib2.0-0 libpython3-dev gnupg g++ libusb-1.0-0 + && apt install --no-install-recommends -y python3-pip git zip curl htop libgl1 libglib2.0-0 libpython3-dev gnupg g++ libusb-1.0-0 # RUN alias python=python3 # Remove python3.11/EXTERNALLY-MANAGED or use 'pip install --break-system-packages' avoid 'externally-managed-environment' Ubuntu nightly error From 6282b662be67c53ac5db67aef009d398ab269970 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 4 Nov 2023 19:36:04 +0100 Subject: [PATCH 1019/1185] [Snyk] Security upgrade pillow from 9.5.0 to 10.0.1 (#2119) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-5918878 Co-authored-by: snyk-bot --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e4cd0e2d7e..cb1927dd7a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ gitpython>=3.1.30 matplotlib>=3.3 numpy>=1.22.2 opencv-python>=4.1.1 -Pillow>=7.1.2 +Pillow>=10.0.1 psutil # system resources PyYAML>=5.3.1 requests>=2.23.0 From fcf9579891480052360cd768e016e5683bd227e2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 4 Nov 2023 19:36:40 +0100 Subject: [PATCH 1020/1185] [Snyk] Security upgrade pillow from 9.5.0 to 10.0.0 (#2135) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-6043904 Co-authored-by: snyk-bot --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index cb1927dd7a..ff7434f743 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ gitpython>=3.1.30 matplotlib>=3.3 numpy>=1.22.2 opencv-python>=4.1.1 -Pillow>=10.0.1 +Pillow>=10.0.0 psutil # system resources PyYAML>=5.3.1 requests>=2.23.0 From 2391854aab4a8c26926d240a6826f2e36f145a0d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 4 Nov 2023 20:13:15 +0100 Subject: [PATCH 1021/1185] [Snyk] Fix for 5 vulnerabilities (#2136) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321964 - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321966 - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321970 - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-5918878 - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-6043904 Co-authored-by: snyk-bot --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ff7434f743..cb1927dd7a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ gitpython>=3.1.30 matplotlib>=3.3 numpy>=1.22.2 opencv-python>=4.1.1 -Pillow>=10.0.0 +Pillow>=10.0.1 psutil # system resources PyYAML>=5.3.1 requests>=2.23.0 From cbccadd718eea2ac0d4730a7dddccfe55530122d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 5 Nov 2023 15:49:18 +0100 Subject: [PATCH 1022/1185] [Snyk] Fix for 5 vulnerabilities (#2137) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321964 - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321966 - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321970 - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-5918878 - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-6043904 Co-authored-by: snyk-bot From d608de4964e7da0074dc6231ac6e2e38d3a6777f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 6 Nov 2023 13:56:12 +0100 Subject: [PATCH 1023/1185] [Snyk] Security upgrade pillow from 9.5.0 to 10.0.1 (#2138) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-5918878 Co-authored-by: snyk-bot From baac29adb0b5bc6a4b0c1aff1384296ef7f3f94a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 23:56:10 +0100 Subject: [PATCH 1024/1185] [pre-commit.ci] pre-commit suggestions (#2139) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.4.0 → v4.5.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.4.0...v4.5.0) - [github.com/asottile/pyupgrade: v3.14.0 → v3.15.0](https://github.com/asottile/pyupgrade/compare/v3.14.0...v3.15.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 39ab266f70..ab272b2a14 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ ci: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: end-of-file-fixer - id: trailing-whitespace @@ -22,7 +22,7 @@ repos: - id: detect-private-key - repo: https://github.com/asottile/pyupgrade - rev: v3.14.0 + rev: v3.15.0 hooks: - id: pyupgrade name: Upgrade code From 02fb2b12aaac1cfd4466a176aed786e1fabd7247 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 16 Nov 2023 21:13:48 +0100 Subject: [PATCH 1025/1185] [Snyk] Security upgrade pillow from 9.5.0 to 10.0.1 (#2140) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-5918878 Co-authored-by: snyk-bot From d568b633a301d050118a388608c01574d49db9b7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 16 Nov 2023 21:23:29 +0100 Subject: [PATCH 1026/1185] [Snyk] Fix for 5 vulnerabilities (#2141) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321964 - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321966 - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321970 - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-5918878 - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-6043904 Co-authored-by: snyk-bot From 1f87d7aa8172cd0b418280441c694c4fcff631f3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 19 Nov 2023 00:52:16 +0100 Subject: [PATCH 1027/1185] =?UTF-8?q?Add=20Hindi=20=E0=A4=B9=E0=A4=BF?= =?UTF-8?q?=E0=A4=A8=E0=A5=8D=E0=A4=A6=E0=A5=80=20and=20Arabic=20=D8=A7?= =?UTF-8?q?=D9=84=D8=B9=D8=B1=D8=A8=D9=8A=D8=A9=20Docs=20translations=20(#?= =?UTF-8?q?2143)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update README.md * Update README.zh-CN.md * Update README.zh-CN.md * Update README.zh-CN.md * Update README.md --- README.md | 3 +-- README.zh-CN.md | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7087b54f28..87577ded1d 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@

-[English](README.md) | [简体中文](README.zh-CN.md) -
+[中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [हिन्दी](https://docs.ultralytics.com/hi/) | [العربية](https://docs.ultralytics.com/ar/)
YOLOv3 CI diff --git a/README.zh-CN.md b/README.zh-CN.md index f1e6b78291..355173bf98 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -4,7 +4,7 @@

-[英文](README.md)|[简体中文](README.zh-CN.md)
+[中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [हिन्दी](https://docs.ultralytics.com/hi/) | [العربية](https://docs.ultralytics.com/ar/)
YOLOv3 CI @@ -14,8 +14,8 @@ Run on Gradient Open In Colab Open In Kaggle -
-
+
+
YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics 对未来视觉 AI 方法的开源研究,结合在数千小时的研究和开发中积累的经验教训和最佳实践。 From 0e52e9d5db8df6574290b1c6891d10d560c84763 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 20 Nov 2023 01:58:40 +0100 Subject: [PATCH 1028/1185] Update dependabot.yml (#2144) * Update dependabot.yml * Update dependabot.yml --- .github/dependabot.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c1b3d5d514..2d4ae31873 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,3 +1,7 @@ +# Ultralytics YOLO 🚀, AGPL-3.0 license +# Dependabot for package version updates +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + version: 2 updates: - package-ecosystem: pip @@ -12,7 +16,7 @@ updates: - dependencies - package-ecosystem: github-actions - directory: "/" + directory: "/.github/workflows" schedule: interval: weekly time: "04:00" From e6f32b405af405e0e26d003a5f2e88373d4794e0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 20 Nov 2023 17:45:25 +0100 Subject: [PATCH 1029/1185] Delete .github/workflows/translate-readme.yml (#2145) --- .github/workflows/translate-readme.yml | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 .github/workflows/translate-readme.yml diff --git a/.github/workflows/translate-readme.yml b/.github/workflows/translate-readme.yml deleted file mode 100644 index 4a404539b9..0000000000 --- a/.github/workflows/translate-readme.yml +++ /dev/null @@ -1,26 +0,0 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -# README translation action to translate README.md to Chinese as README.zh-CN.md on any change to README.md - -name: Translate README - -on: - push: - branches: - - translate_readme # replace with 'master' to enable action - paths: - - README.md - -jobs: - Translate: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 16 - # ISO Language Codes: https://cloud.google.com/translate/docs/languages - - name: Adding README - Chinese Simplified - uses: dephraiim/translate-readme@main - with: - LANG: zh-CN From 64f9f9696394739bf386c53f7eb563eb0840fc3d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 23 Nov 2023 13:25:15 +0100 Subject: [PATCH 1030/1185] Update ci-testing.yml (#2146) --- .github/workflows/ci-testing.yml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 84fed0c0d7..3b2788dbae 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -19,7 +19,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] # macos-latest bug https://github.com/ultralytics/yolov5/pull/9049 - python-version: ['3.10'] + python-version: ['3.11'] model: [yolov5n] include: - os: ubuntu-latest @@ -49,15 +49,7 @@ jobs: shell: bash # for Windows compatibility - name: Check environment run: | - python -c "import utils; utils.notebook_init()" - echo "RUNNER_OS is ${{ runner.os }}" - echo "GITHUB_EVENT_NAME is ${{ github.event_name }}" - echo "GITHUB_WORKFLOW is ${{ github.workflow }}" - echo "GITHUB_ACTOR is ${{ github.actor }}" - echo "GITHUB_REPOSITORY is ${{ github.repository }}" - echo "GITHUB_REPOSITORY_OWNER is ${{ github.repository_owner }}" - python --version - pip --version + yolo checks pip list - name: Test detection shell: bash # for Windows compatibility From c6acbdda5679a4443c2b5b7aa9f9673a53d939ac Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 23 Nov 2023 13:31:30 +0100 Subject: [PATCH 1031/1185] [Snyk] Security upgrade pillow from 9.5.0 to 10.0.1 (#2142) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-5918878 Co-authored-by: snyk-bot From 7f08eaf75be2a2118be03eec4a9955f45f94c839 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 13:43:36 +0100 Subject: [PATCH 1032/1185] Bump actions/stale from 8 to 9 in /.github/workflows (#2153) Bumps [actions/stale](https://github.com/actions/stale) from 8 to 9. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v8...v9) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 8a9871ae67..c0b1f405c7 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -9,7 +9,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v8 + - uses: actions/stale@v9 with: repo-token: ${{ secrets.GITHUB_TOKEN }} From 624c2e06241358bcace814b1693db3abf3c596dc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 11 Dec 2023 13:44:22 +0100 Subject: [PATCH 1033/1185] [Snyk] Security upgrade ubuntu from mantic-20231011 to 23.10 (#2149) fix: utils/docker/Dockerfile-cpu to reduce vulnerabilities The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-UBUNTU2310-GNUTLS28-6069047 - https://snyk.io/vuln/SNYK-UBUNTU2310-PERL-6085371 - https://snyk.io/vuln/SNYK-UBUNTU2310-PROCPS-5972730 - https://snyk.io/vuln/SNYK-UBUNTU2310-PROCPS-5972730 - https://snyk.io/vuln/SNYK-UBUNTU2310-TAR-6096092 Co-authored-by: snyk-bot --- utils/docker/Dockerfile-cpu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/docker/Dockerfile-cpu b/utils/docker/Dockerfile-cpu index acebf09951..cdb55f63bf 100644 --- a/utils/docker/Dockerfile-cpu +++ b/utils/docker/Dockerfile-cpu @@ -3,7 +3,7 @@ # Image is CPU-optimized for ONNX, OpenVINO and PyTorch YOLOv5 deployments # Start FROM Ubuntu image https://hub.docker.com/_/ubuntu -FROM ubuntu:mantic-20231011 +FROM ubuntu:23.10 # Downloads to user config dir ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/ From 37d3a42fb1dee782f417f57556d597cfa5f6696f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 13:44:33 +0100 Subject: [PATCH 1034/1185] Bump actions/setup-python from 4 to 5 in /.github/workflows (#2152) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 3b2788dbae..e6ab9b7d57 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -34,7 +34,7 @@ jobs: torch: '1.8.0' # min torch version CI https://pypi.org/project/torchvision/ steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: 'pip' # caching pip dependencies From f99d525046d56e08584544f611da8ef7559fcac6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 16:30:36 +0100 Subject: [PATCH 1035/1185] Bump github/codeql-action from 2 to 3 in /.github/workflows (#2154) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v2...v3) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 53af304ee9..11db0dceca 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -27,7 +27,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -38,7 +38,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -52,4 +52,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 From 5490f5617927041b44912a05b9db6b6e6c07ef1c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 23 Dec 2023 20:26:44 +0100 Subject: [PATCH 1036/1185] [Snyk] Security upgrade fonttools from 4.38.0 to 4.43.0 (#2155) * fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-FONTTOOLS-6133203 * Update requirements.txt --------- Co-authored-by: snyk-bot From 44c8733b3ecf29aab173809418f299ba04336427 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 1 Jan 2024 15:50:35 +0100 Subject: [PATCH 1037/1185] Update requirements.txt to `ultralytics 8.0.232` (#2160) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index cb1927dd7a..5bbe3509e2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ thop>=0.1.1 # FLOPs computation torch>=1.8.0 # see https://pytorch.org/get-started/locally (recommended) torchvision>=0.9.0 tqdm>=4.64.0 -ultralytics>=8.0.147 +ultralytics>=8.0.232 # protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 # Logging --------------------------------------------------------------------- From 2f7b807ae30e43d0a36008203ab018f52ccec50e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 1 Jan 2024 22:23:06 +0100 Subject: [PATCH 1038/1185] Delete .github/PULL_REQUEST_TEMPLATE.md (#2159) --- .github/PULL_REQUEST_TEMPLATE.md | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index d96d5afd28..0000000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,13 +0,0 @@ - - -copilot:all From 8cb64ab1f65187ba1bcb6705fafd39d8cafa4017 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 2 Jan 2024 14:02:50 +0100 Subject: [PATCH 1039/1185] Delete setup.cfg --- setup.cfg | 56 ------------------------------------------------------- 1 file changed, 56 deletions(-) delete mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 2cde6a4948..0000000000 --- a/setup.cfg +++ /dev/null @@ -1,56 +0,0 @@ -# Project-wide configuration file, can be used for package metadata and other toll configurations -# Example usage: global configuration for PEP8 (via flake8) setting or default pytest arguments -# Local usage: pip install pre-commit, pre-commit run --all-files - -[metadata] -license_files = LICENSE -description_file = README.md - -[tool:pytest] -norecursedirs = - .git - dist - build -addopts = - --doctest-modules - --durations=25 - --color=yes - -[flake8] -max-line-length = 120 -exclude = .tox,*.egg,build,temp -select = E,W,F -doctests = True -verbose = 2 -# https://pep8.readthedocs.io/en/latest/intro.html#error-codes -format = pylint -# see: https://www.flake8rules.com/ -ignore = E731,F405,E402,W504,E501 - # E731: Do not assign a lambda expression, use a def - # F405: name may be undefined, or defined from star imports: module - # E402: module level import not at top of file - # W504: line break after binary operator - # E501: line too long - # removed: - # F401: module imported but unused - # E231: missing whitespace after ‘,’, ‘;’, or ‘:’ - # E127: continuation line over-indented for visual indent - # F403: ‘from module import *’ used; unable to detect undefined names - - -[isort] -# https://pycqa.github.io/isort/docs/configuration/options.html -line_length = 120 -# see: https://pycqa.github.io/isort/docs/configuration/multi_line_output_modes.html -multi_line_output = 0 - -[yapf] -based_on_style = pep8 -spaces_before_comment = 2 -COLUMN_LIMIT = 120 -COALESCE_BRACKETS = True -SPACES_AROUND_POWER_OPERATOR = True -SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = True -SPLIT_BEFORE_CLOSING_BRACKET = False -SPLIT_BEFORE_FIRST_ARGUMENT = False -# EACH_DICT_ENTRY_ON_SEPARATE_LINE = False From 10301b24820d0fc23c28d55ab799ec80b63d6dc2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 2 Jan 2024 16:37:48 +0100 Subject: [PATCH 1040/1185] Delete .pre-commit-config.yaml (#2163) --- .pre-commit-config.yaml | 73 ----------------------------------------- 1 file changed, 73 deletions(-) delete mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index ab272b2a14..0000000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,73 +0,0 @@ -# Ultralytics YOLO 🚀, AGPL-3.0 license -# Pre-commit hooks. For more information see https://github.com/pre-commit/pre-commit-hooks/blob/main/README.md - -exclude: 'docs/' -# Define bot property if installed via https://github.com/marketplace/pre-commit-ci -ci: - autofix_prs: true - autoupdate_commit_msg: '[pre-commit.ci] pre-commit suggestions' - autoupdate_schedule: monthly - # submodules: true - -repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 - hooks: - - id: end-of-file-fixer - - id: trailing-whitespace - - id: check-case-conflict - # - id: check-yaml - - id: check-docstring-first - - id: double-quote-string-fixer - - id: detect-private-key - - - repo: https://github.com/asottile/pyupgrade - rev: v3.15.0 - hooks: - - id: pyupgrade - name: Upgrade code - - - repo: https://github.com/PyCQA/isort - rev: 5.12.0 - hooks: - - id: isort - name: Sort imports - - - repo: https://github.com/google/yapf - rev: v0.40.2 - hooks: - - id: yapf - name: YAPF formatting - - - repo: https://github.com/executablebooks/mdformat - rev: 0.7.17 - hooks: - - id: mdformat - name: MD formatting - additional_dependencies: - - mdformat-gfm - - mdformat-black - # exclude: "README.md|README.zh-CN.md|CONTRIBUTING.md" - - - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 - hooks: - - id: flake8 - name: PEP8 - - - repo: https://github.com/codespell-project/codespell - rev: v2.2.6 - hooks: - - id: codespell - args: - - --ignore-words-list=crate,nd,strack,dota - -# - repo: https://github.com/asottile/yesqa -# rev: v1.4.0 -# hooks: -# - id: yesqa - -# - repo: https://github.com/asottile/dead -# rev: v1.5.0 -# hooks: -# - id: dead From d4f6ebd6c39408a204ff955e87c13b2537b7c00a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 2 Jan 2024 16:50:00 +0100 Subject: [PATCH 1041/1185] Create pyproject.toml (#2164) --- pyproject.toml | 164 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..ec3c5723f5 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,164 @@ +# Ultralytics YOLO 🚀, AGPL-3.0 license +# +# Overview: +# This pyproject.toml file manages the build, packaging, and distribution of the Ultralytics library. +# It defines essential project metadata, dependencies, and settings used to develop and deploy the library. + +# Key Sections: +# - [build-system]: Specifies the build requirements and backend (e.g., setuptools, wheel). +# - [project]: Includes details like name, version, description, authors, dependencies and more. +# - [project.optional-dependencies]: Provides additional, optional packages for extended features. +# - [tool.*]: Configures settings for various tools (pytest, yapf, etc.) used in the project. + +# Installation: +# The Ultralytics library can be installed using the command: 'pip install ultralytics' +# For development purposes, you can install the package in editable mode with: 'pip install -e .' +# This approach allows for real-time code modifications without the need for re-installation. + +# Documentation: +# For comprehensive documentation and usage instructions, visit: https://docs.ultralytics.com + +[build-system] +requires = ["setuptools>=43.0.0", "wheel"] +build-backend = "setuptools.build_meta" + +# Project settings ----------------------------------------------------------------------------------------------------- +[project] +name = "ultralytics" +dynamic = ["version"] +description = "Ultralytics YOLOv8 for SOTA object detection, multi-object tracking, instance segmentation, pose estimation and image classification." +readme = "README.md" +requires-python = ">=3.8" +license = { "text" = "AGPL-3.0" } +keywords = ["machine-learning", "deep-learning", "computer-vision", "ML", "DL", "AI", "YOLO", "YOLOv3", "YOLOv5", "YOLOv8", "HUB", "Ultralytics"] +authors = [ + { name = "Glenn Jocher" }, + { name = "Ayush Chaurasia" }, + { name = "Jing Qiu" } +] +maintainers = [ + { name = "Glenn Jocher" }, + { name = "Ayush Chaurasia" }, + { name = "Jing Qiu" } +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Intended Audience :: Education", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Topic :: Software Development", + "Topic :: Scientific/Engineering", + "Topic :: Scientific/Engineering :: Artificial Intelligence", + "Topic :: Scientific/Engineering :: Image Recognition", + "Operating System :: POSIX :: Linux", + "Operating System :: MacOS", + "Operating System :: Microsoft :: Windows", +] + +# Required dependencies ------------------------------------------------------------------------------------------------ +dependencies = [ + "matplotlib>=3.3.0", + "numpy>=1.22.2", + "opencv-python>=4.6.0", + "pillow>=7.1.2", + "pyyaml>=5.3.1", + "requests>=2.23.0", + "scipy>=1.4.1", + "torch>=1.8.0", + "torchvision>=0.9.0", + "tqdm>=4.64.0", # progress bars + "psutil", # system utilization + "py-cpuinfo", # display CPU info + "thop>=0.1.1", # FLOPs computation + "pandas>=1.1.4", + "seaborn>=0.11.0", # plotting +] + +# Optional dependencies ------------------------------------------------------------------------------------------------ +[project.optional-dependencies] +dev = [ + "ipython", + "check-manifest", + "pre-commit", + "pytest", + "pytest-cov", + "coverage[toml]", + "mkdocs-material", + "mkdocstrings[python]", + "mkdocs-redirects", # for 301 redirects + "mkdocs-ultralytics-plugin>=0.0.34", # for meta descriptions and images, dates and authors +] +export = [ + "onnx>=1.12.0", # ONNX export + "coremltools>=7.0", # CoreML export + "openvino-dev>=2023.0", # OpenVINO export + "tensorflow<=2.13.1", # TF bug https://github.com/ultralytics/ultralytics/issues/5161 + "jax<=0.4.21", # tensorflowjs bug https://github.com/google/jax/issues/18978 + "jaxlib<=0.4.21", # tensorflowjs bug https://github.com/google/jax/issues/18978 + "tensorflowjs>=3.9.0", # TF.js export, automatically installs tensorflow +] +# tensorflow>=2.4.1,<=2.13.1 # TF exports (-cpu, -aarch64, -macos) +# tflite-support # for TFLite model metadata +# scikit-learn==0.19.2 # CoreML quantization +# nvidia-pyindex # TensorRT export +# nvidia-tensorrt # TensorRT export +logging = [ + "comet", # https://docs.ultralytics.com/integrations/comet/ + "tensorboard>=2.13.0", + "dvclive>=2.12.0", +] +extra = [ + "ipython", # interactive notebook + "albumentations>=1.0.3", # training augmentations + "pycocotools>=2.0.6", # COCO mAP +] + +[project.urls] +"Bug Reports" = "https://github.com/ultralytics/ultralytics/issues" +"Funding" = "https://ultralytics.com" +"Source" = "https://github.com/ultralytics/ultralytics/" + +[project.scripts] +yolo = "ultralytics.cfg:entrypoint" +ultralytics = "ultralytics.cfg:entrypoint" + +# Tools settings ------------------------------------------------------------------------------------------------------- +[tool.setuptools] # configuration specific to the `setuptools` build backend. +packages = { find = { where = ["."], include = ["ultralytics", "ultralytics.*"] } } +package-data = { "ultralytics" = ["**/*.yaml"], "ultralytics.assets" = ["*.jpg"] } + +[tool.setuptools.dynamic] +version = { attr = "ultralytics.__version__" } + +[tool.pytest] +norecursedirs = [".git", "dist", "build"] +addopts = "--doctest-modules --durations=30 --color=yes" + +[tool.coverage.run] +source = ["ultralytics/"] +data_file = "tests/.coverage" +omit = ["ultralytics/utils/callbacks/*"] + +[tool.isort] +line_length = 120 +multi_line_output = 0 + +[tool.ruff] +line-length = 120 + +[tool.docformatter] +wrap-summaries = 120 +wrap-descriptions = 120 +in-place = true +pre-summary-newline = true +close-quotes-on-newline = true + +[tool.codespell] +ignore-words-list = "crate,nd,strack,dota,ane,segway,fo,gool,winn,commend" +skip = '*.csv,*venv*,docs/??/,docs/mkdocs_??.yml' From dcbbf2af5f7e642cff6155f9cb7f651ef53c9163 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 2 Jan 2024 17:47:54 +0100 Subject: [PATCH 1042/1185] Update pyproject.toml (#2166) * Update pyproject.toml * Update README.md * Update README.md --- pyproject.toml | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ec3c5723f5..80bb50a4cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ # Ultralytics YOLO 🚀, AGPL-3.0 license -# + # Overview: # This pyproject.toml file manages the build, packaging, and distribution of the Ultralytics library. # It defines essential project metadata, dependencies, and settings used to develop and deploy the library. @@ -24,9 +24,8 @@ build-backend = "setuptools.build_meta" # Project settings ----------------------------------------------------------------------------------------------------- [project] -name = "ultralytics" -dynamic = ["version"] -description = "Ultralytics YOLOv8 for SOTA object detection, multi-object tracking, instance segmentation, pose estimation and image classification." +name = "YOLOv3" +description = "Ultralytics YOLOv3 for object detection." readme = "README.md" requires-python = ">=3.8" license = { "text" = "AGPL-3.0" } @@ -78,6 +77,7 @@ dependencies = [ "thop>=0.1.1", # FLOPs computation "pandas>=1.1.4", "seaborn>=0.11.0", # plotting + "ultralytics>=8.0.232" ] # Optional dependencies ------------------------------------------------------------------------------------------------ @@ -120,31 +120,15 @@ extra = [ ] [project.urls] -"Bug Reports" = "https://github.com/ultralytics/ultralytics/issues" +"Bug Reports" = "https://github.com/ultralytics/yolov3/issues" "Funding" = "https://ultralytics.com" -"Source" = "https://github.com/ultralytics/ultralytics/" - -[project.scripts] -yolo = "ultralytics.cfg:entrypoint" -ultralytics = "ultralytics.cfg:entrypoint" +"Source" = "https://github.com/ultralytics/yolov3/" # Tools settings ------------------------------------------------------------------------------------------------------- -[tool.setuptools] # configuration specific to the `setuptools` build backend. -packages = { find = { where = ["."], include = ["ultralytics", "ultralytics.*"] } } -package-data = { "ultralytics" = ["**/*.yaml"], "ultralytics.assets" = ["*.jpg"] } - -[tool.setuptools.dynamic] -version = { attr = "ultralytics.__version__" } - [tool.pytest] norecursedirs = [".git", "dist", "build"] addopts = "--doctest-modules --durations=30 --color=yes" -[tool.coverage.run] -source = ["ultralytics/"] -data_file = "tests/.coverage" -omit = ["ultralytics/utils/callbacks/*"] - [tool.isort] line_length = 120 multi_line_output = 0 From cac7189c3e11de563056e2db08012c2c12b30789 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 3 Jan 2024 08:04:47 +0100 Subject: [PATCH 1043/1185] Create format.yml (#2165) * Create format.yml * Auto-format by Ultralytics actions * Update metrics.py * Auto-format by Ultralytics actions * Update pyproject.toml * Update CONTRIBUTING.md * Auto-format by Ultralytics actions --- .github/workflows/format.yml | 23 + CONTRIBUTING.md | 39 +- README.md | 8 +- README.zh-CN.md | 3 +- benchmarks.py | 116 ++--- classify/predict.py | 127 ++--- classify/train.py | 255 +++++----- classify/val.py | 81 ++-- detect.py | 176 +++---- export.py | 592 ++++++++++++----------- hubconf.py | 72 +-- models/common.py | 312 +++++++------ models/experimental.py | 35 +- models/tf.py | 245 ++++++---- models/yolo.py | 115 +++-- segment/predict.py | 143 +++--- segment/train.py | 522 ++++++++++++--------- segment/val.py | 297 ++++++------ train.py | 546 ++++++++++++---------- utils/__init__.py | 29 +- utils/activations.py | 9 +- utils/augmentations.py | 76 ++- utils/autoanchor.py | 72 +-- utils/autobatch.py | 24 +- utils/aws/resume.py | 16 +- utils/callbacks.py | 63 ++- utils/dataloaders.py | 593 +++++++++++++----------- utils/downloads.py | 91 ++-- utils/flask_rest_api/README.md | 7 +- utils/flask_rest_api/example_request.py | 12 +- utils/flask_rest_api/restapi.py | 28 +- utils/general.py | 568 ++++++++++++++--------- utils/loggers/__init__.py | 170 +++---- utils/loggers/clearml/README.md | 11 +- utils/loggers/clearml/clearml_utils.py | 100 ++-- utils/loggers/clearml/hpo.py | 78 ++-- utils/loggers/comet/README.md | 26 +- utils/loggers/comet/__init__.py | 243 +++++----- utils/loggers/comet/comet_utils.py | 54 +-- utils/loggers/comet/hpo.py | 114 ++--- utils/loggers/wandb/wandb_utils.py | 109 +++-- utils/loss.py | 58 +-- utils/metrics.py | 118 ++--- utils/plots.py | 250 +++++----- utils/segment/augmentations.py | 22 +- utils/segment/dataloaders.py | 147 +++--- utils/segment/general.py | 19 +- utils/segment/loss.py | 46 +- utils/segment/metrics.py | 156 ++++--- utils/segment/plots.py | 39 +- utils/torch_utils.py | 230 ++++----- utils/triton.py | 43 +- val.py | 267 ++++++----- 53 files changed, 4136 insertions(+), 3459 deletions(-) create mode 100644 .github/workflows/format.yml diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 0000000000..27b2c7d890 --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,23 @@ +# Ultralytics 🚀 - AGPL-3.0 license +# Ultralytics Actions https://github.com/ultralytics/actions +# This workflow automatically formats code and documentation in PRs to official Ultralytics standards + +name: Ultralytics Actions + +on: + push: + branches: [main,master] + pull_request: + branches: [main,master] + +jobs: + format: + runs-on: ubuntu-latest + steps: + - name: Run Ultralytics Formatting + uses: ultralytics/actions@main + with: + python: true + docstrings: true + markdown: true + spelling: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7995069f88..0dbea33b38 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,8 +8,7 @@ We love your input! We want to make contributing to YOLOv5 as easy and transpare - Proposing a new feature - Becoming a maintainer -YOLOv5 works so well due to our combined community effort, and for every small improvement you contribute you will be -helping push the frontiers of what's possible in AI 😃! +YOLOv5 works so well due to our combined community effort, and for every small improvement you contribute you will be helping push the frontiers of what's possible in AI 😃! ## Submitting a Pull Request (PR) 🛠️ @@ -35,9 +34,7 @@ Change the `matplotlib` version from `3.2.2` to `3.3`. ### 4. Preview Changes and Submit PR -Click on the **Preview changes** tab to verify your updates. At the bottom of the screen select 'Create a **new branch** -for this commit', assign your branch a descriptive name such as `fix/matplotlib_version` and click the green **Propose -changes** button. All done, your PR is now submitted to YOLOv5 for review and approval 😃! +Click on the **Preview changes** tab to verify your updates. At the bottom of the screen select 'Create a **new branch** for this commit', assign your branch a descriptive name such as `fix/matplotlib_version` and click the green **Propose changes** button. All done, your PR is now submitted to YOLOv5 for review and approval 😃!

PR_step4

@@ -45,8 +42,7 @@ changes** button. All done, your PR is now submitted to YOLOv5 for review and ap To allow your work to be integrated as seamlessly as possible, we advise you to: -- ✅ Verify your PR is **up-to-date** with `ultralytics/yolov5` `master` branch. If your PR is behind you can update - your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally. +- ✅ Verify your PR is **up-to-date** with `ultralytics/yolov5` `master` branch. If your PR is behind you can update your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally.

Screenshot 2022-08-29 at 22 47 15

@@ -54,40 +50,27 @@ To allow your work to be integrated as seamlessly as possible, we advise you to:

Screenshot 2022-08-29 at 22 47 03

-- ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase - but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ — Bruce Lee +- ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ — Bruce Lee ## Submitting a Bug Report 🐛 If you spot a problem with YOLOv5 please submit a Bug Report! -For us to start investigating a possible problem we need to be able to reproduce it ourselves first. We've created a few -short guidelines below to help users provide what we need to get started. +For us to start investigating a possible problem we need to be able to reproduce it ourselves first. We've created a few short guidelines below to help users provide what we need to get started. -When asking a question, people will be better able to provide help if you provide **code** that they can easily -understand and use to **reproduce** the problem. This is referred to by community members as creating -a [minimum reproducible example](https://docs.ultralytics.com/help/minimum_reproducible_example/). Your code that reproduces -the problem should be: +When asking a question, people will be better able to provide help if you provide **code** that they can easily understand and use to **reproduce** the problem. This is referred to by community members as creating a [minimum reproducible example](https://docs.ultralytics.com/help/minimum_reproducible_example/). Your code that reproduces the problem should be: - ✅ **Minimal** – Use as little code as possible that still produces the same problem - ✅ **Complete** – Provide **all** parts someone else needs to reproduce your problem in the question itself - ✅ **Reproducible** – Test the code you're about to provide to make sure it reproduces the problem -In addition to the above requirements, for [Ultralytics](https://ultralytics.com/) to provide assistance your code -should be: +In addition to the above requirements, for [Ultralytics](https://ultralytics.com/) to provide assistance your code should be: -- ✅ **Current** – Verify that your code is up-to-date with the current - GitHub [master](https://github.com/ultralytics/yolov5/tree/master), and if necessary `git pull` or `git clone` a new - copy to ensure your problem has not already been resolved by previous commits. -- ✅ **Unmodified** – Your problem must be reproducible without any modifications to the codebase in this - repository. [Ultralytics](https://ultralytics.com/) does not provide support for custom code ⚠️. +- ✅ **Current** – Verify that your code is up-to-date with the current GitHub [master](https://github.com/ultralytics/yolov5/tree/master), and if necessary `git pull` or `git clone` a new copy to ensure your problem has not already been resolved by previous commits. +- ✅ **Unmodified** – Your problem must be reproducible without any modifications to the codebase in this repository. [Ultralytics](https://ultralytics.com/) does not provide support for custom code ⚠️. -If you believe your problem meets all of the above criteria, please close this issue and raise a new one using the 🐛 -**Bug Report** [template](https://github.com/ultralytics/yolov5/issues/new/choose) and provide -a [minimum reproducible example](https://docs.ultralytics.com/help/minimum_reproducible_example/) to help us better -understand and diagnose your problem. +If you believe your problem meets all of the above criteria, please close this issue and raise a new one using the 🐛 **Bug Report** [template](https://github.com/ultralytics/yolov5/issues/new/choose) and provide a [minimum reproducible example](https://docs.ultralytics.com/help/minimum_reproducible_example/) to help us better understand and diagnose your problem. ## License -By contributing, you agree that your contributions will be licensed under -the [AGPL-3.0 license](https://choosealicense.com/licenses/agpl-3.0/) +By contributing, you agree that your contributions will be licensed under the [AGPL-3.0 license](https://choosealicense.com/licenses/agpl-3.0/) diff --git a/README.md b/README.md index 87577ded1d..00cc1abf22 100644 --- a/README.md +++ b/README.md @@ -65,9 +65,7 @@ See the [YOLOv3 Docs](https://docs.ultralytics.com) for full documentation on tr
Install -Clone repo and install [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) in a -[**Python>=3.7.0**](https://www.python.org/) environment, including -[**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). +Clone repo and install [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) in a [**Python>=3.7.0**](https://www.python.org/) environment, including [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). ```bash git clone https://github.com/ultralytics/yolov3 # clone @@ -123,9 +121,7 @@ python detect.py --weights yolov5s.pt --source 0 #
Training -The commands below reproduce YOLOv3 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) -results. [Models](https://github.com/ultralytics/yolov5/tree/master/models) -and [datasets](https://github.com/ultralytics/yolov5/tree/master/data) download automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). Training times for YOLOv5n/s/m/l/x are 1/2/4/6/8 days on a V100 GPU ([Multi-GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) times faster). Use the largest `--batch-size` possible, or pass `--batch-size -1` for YOLOv3 [AutoBatch](https://github.com/ultralytics/yolov5/pull/5092). Batch sizes shown for V100-16GB. +The commands below reproduce YOLOv3 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) results. [Models](https://github.com/ultralytics/yolov5/tree/master/models) and [datasets](https://github.com/ultralytics/yolov5/tree/master/data) download automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). Training times for YOLOv5n/s/m/l/x are 1/2/4/6/8 days on a V100 GPU ([Multi-GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) times faster). Use the largest `--batch-size` possible, or pass `--batch-size -1` for YOLOv3 [AutoBatch](https://github.com/ultralytics/yolov5/pull/5092). Batch sizes shown for V100-16GB. ```bash python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml --batch-size 128 diff --git a/README.zh-CN.md b/README.zh-CN.md index 355173bf98..e9defd022e 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -121,8 +121,7 @@ python detect.py --weights yolov5s.pt --source 0 #
训练 -下面的命令重现 YOLOv3 在 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) 数据集上的结果。 最新的 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 和 [数据集](https://github.com/ultralytics/yolov5/tree/master/data) -将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 YOLOv5n/s/m/l/x 在 V100 GPU 的训练时间为 1/2/4/6/8 天( [多GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) 训练速度更快)。 尽可能使用更大的 `--batch-size` ,或通过 `--batch-size -1` 实现 YOLOv3 [自动批处理](https://github.com/ultralytics/yolov5/pull/5092) 。下方显示的 batchsize 适用于 V100-16GB。 +下面的命令重现 YOLOv3 在 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) 数据集上的结果。 最新的 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 和 [数据集](https://github.com/ultralytics/yolov5/tree/master/data) 将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 YOLOv5n/s/m/l/x 在 V100 GPU 的训练时间为 1/2/4/6/8 天( [多GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) 训练速度更快)。 尽可能使用更大的 `--batch-size` ,或通过 `--batch-size -1` 实现 YOLOv3 [自动批处理](https://github.com/ultralytics/yolov5/pull/5092) 。下方显示的 batchsize 适用于 V100-16GB。 ```bash python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml --batch-size 128 diff --git a/benchmarks.py b/benchmarks.py index cbc5b20499..2f7d58bd3a 100644 --- a/benchmarks.py +++ b/benchmarks.py @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Run YOLOv3 benchmarks on all supported export formats +Run YOLOv3 benchmarks on all supported export formats. Format | `export.py --include` | Model --- | --- | --- @@ -50,115 +50,115 @@ def run( - weights=ROOT / 'yolov5s.pt', # weights path - imgsz=640, # inference size (pixels) - batch_size=1, # batch size - data=ROOT / 'data/coco128.yaml', # dataset.yaml path - device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu - half=False, # use FP16 half-precision inference - test=False, # test exports only - pt_only=False, # test PyTorch only - hard_fail=False, # throw error on benchmark failure + weights=ROOT / "yolov5s.pt", # weights path + imgsz=640, # inference size (pixels) + batch_size=1, # batch size + data=ROOT / "data/coco128.yaml", # dataset.yaml path + device="", # cuda device, i.e. 0 or 0,1,2,3 or cpu + half=False, # use FP16 half-precision inference + test=False, # test exports only + pt_only=False, # test PyTorch only + hard_fail=False, # throw error on benchmark failure ): y, t = [], time.time() device = select_device(device) model_type = type(attempt_load(weights, fuse=False)) # DetectionModel, SegmentationModel, etc. for i, (name, f, suffix, cpu, gpu) in export.export_formats().iterrows(): # index, (name, file, suffix, CPU, GPU) try: - assert i not in (9, 10), 'inference not supported' # Edge TPU and TF.js are unsupported - assert i != 5 or platform.system() == 'Darwin', 'inference only supported on macOS>=10.13' # CoreML - if 'cpu' in device.type: - assert cpu, 'inference not supported on CPU' - if 'cuda' in device.type: - assert gpu, 'inference not supported on GPU' + assert i not in (9, 10), "inference not supported" # Edge TPU and TF.js are unsupported + assert i != 5 or platform.system() == "Darwin", "inference only supported on macOS>=10.13" # CoreML + if "cpu" in device.type: + assert cpu, "inference not supported on CPU" + if "cuda" in device.type: + assert gpu, "inference not supported on GPU" # Export - if f == '-': + if f == "-": w = weights # PyTorch format else: - w = export.run(weights=weights, - imgsz=[imgsz], - include=[f], - batch_size=batch_size, - device=device, - half=half)[-1] # all others - assert suffix in str(w), 'export failed' + w = export.run( + weights=weights, imgsz=[imgsz], include=[f], batch_size=batch_size, device=device, half=half + )[-1] # all others + assert suffix in str(w), "export failed" # Validate if model_type == SegmentationModel: - result = val_seg(data, w, batch_size, imgsz, plots=False, device=device, task='speed', half=half) + result = val_seg(data, w, batch_size, imgsz, plots=False, device=device, task="speed", half=half) metric = result[0][7] # (box(p, r, map50, map), mask(p, r, map50, map), *loss(box, obj, cls)) else: # DetectionModel: - result = val_det(data, w, batch_size, imgsz, plots=False, device=device, task='speed', half=half) + result = val_det(data, w, batch_size, imgsz, plots=False, device=device, task="speed", half=half) metric = result[0][3] # (p, r, map50, map, *loss(box, obj, cls)) speed = result[2][1] # times (preprocess, inference, postprocess) y.append([name, round(file_size(w), 1), round(metric, 4), round(speed, 2)]) # MB, mAP, t_inference except Exception as e: if hard_fail: - assert type(e) is AssertionError, f'Benchmark --hard-fail for {name}: {e}' - LOGGER.warning(f'WARNING ⚠️ Benchmark failure for {name}: {e}') + assert type(e) is AssertionError, f"Benchmark --hard-fail for {name}: {e}" + LOGGER.warning(f"WARNING ⚠️ Benchmark failure for {name}: {e}") y.append([name, None, None, None]) # mAP, t_inference if pt_only and i == 0: break # break after PyTorch # Print results - LOGGER.info('\n') + LOGGER.info("\n") parse_opt() notebook_init() # print system info - c = ['Format', 'Size (MB)', 'mAP50-95', 'Inference time (ms)'] if map else ['Format', 'Export', '', ''] + c = ["Format", "Size (MB)", "mAP50-95", "Inference time (ms)"] if map else ["Format", "Export", "", ""] py = pd.DataFrame(y, columns=c) - LOGGER.info(f'\nBenchmarks complete ({time.time() - t:.2f}s)') + LOGGER.info(f"\nBenchmarks complete ({time.time() - t:.2f}s)") LOGGER.info(str(py if map else py.iloc[:, :2])) if hard_fail and isinstance(hard_fail, str): - metrics = py['mAP50-95'].array # values to compare to floor + metrics = py["mAP50-95"].array # values to compare to floor floor = eval(hard_fail) # minimum metric floor to pass, i.e. = 0.29 mAP for YOLOv5n - assert all(x > floor for x in metrics if pd.notna(x)), f'HARD FAIL: mAP50-95 < floor {floor}' + assert all(x > floor for x in metrics if pd.notna(x)), f"HARD FAIL: mAP50-95 < floor {floor}" return py def test( - weights=ROOT / 'yolov5s.pt', # weights path - imgsz=640, # inference size (pixels) - batch_size=1, # batch size - data=ROOT / 'data/coco128.yaml', # dataset.yaml path - device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu - half=False, # use FP16 half-precision inference - test=False, # test exports only - pt_only=False, # test PyTorch only - hard_fail=False, # throw error on benchmark failure + weights=ROOT / "yolov5s.pt", # weights path + imgsz=640, # inference size (pixels) + batch_size=1, # batch size + data=ROOT / "data/coco128.yaml", # dataset.yaml path + device="", # cuda device, i.e. 0 or 0,1,2,3 or cpu + half=False, # use FP16 half-precision inference + test=False, # test exports only + pt_only=False, # test PyTorch only + hard_fail=False, # throw error on benchmark failure ): y, t = [], time.time() device = select_device(device) for i, (name, f, suffix, gpu) in export.export_formats().iterrows(): # index, (name, file, suffix, gpu-capable) try: - w = weights if f == '-' else \ - export.run(weights=weights, imgsz=[imgsz], include=[f], device=device, half=half)[-1] # weights - assert suffix in str(w), 'export failed' + w = ( + weights + if f == "-" + else export.run(weights=weights, imgsz=[imgsz], include=[f], device=device, half=half)[-1] + ) # weights + assert suffix in str(w), "export failed" y.append([name, True]) except Exception: y.append([name, False]) # mAP, t_inference # Print results - LOGGER.info('\n') + LOGGER.info("\n") parse_opt() notebook_init() # print system info - py = pd.DataFrame(y, columns=['Format', 'Export']) - LOGGER.info(f'\nExports complete ({time.time() - t:.2f}s)') + py = pd.DataFrame(y, columns=["Format", "Export"]) + LOGGER.info(f"\nExports complete ({time.time() - t:.2f}s)") LOGGER.info(str(py)) return py def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default=ROOT / 'yolov3-tiny.pt', help='weights path') - parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') - parser.add_argument('--batch-size', type=int, default=1, help='batch size') - parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') - parser.add_argument('--test', action='store_true', help='test exports only') - parser.add_argument('--pt-only', action='store_true', help='test PyTorch only') - parser.add_argument('--hard-fail', nargs='?', const=True, default=False, help='Exception on error or < min metric') + parser.add_argument("--weights", type=str, default=ROOT / "yolov3-tiny.pt", help="weights path") + parser.add_argument("--imgsz", "--img", "--img-size", type=int, default=640, help="inference size (pixels)") + parser.add_argument("--batch-size", type=int, default=1, help="batch size") + parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="dataset.yaml path") + parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu") + parser.add_argument("--half", action="store_true", help="use FP16 half-precision inference") + parser.add_argument("--test", action="store_true", help="test exports only") + parser.add_argument("--pt-only", action="store_true", help="test PyTorch only") + parser.add_argument("--hard-fail", nargs="?", const=True, default=False, help="Exception on error or < min metric") opt = parser.parse_args() opt.data = check_yaml(opt.data) # check YAML print_args(vars(opt)) @@ -169,6 +169,6 @@ def main(opt): test(**vars(opt)) if opt.test else run(**vars(opt)) -if __name__ == '__main__': +if __name__ == "__main__": opt = parse_opt() main(opt) diff --git a/classify/predict.py b/classify/predict.py index 692cd607b8..17dce7cd16 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -48,43 +48,54 @@ from models.common import DetectMultiBackend from utils.augmentations import classify_transforms from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams -from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, - increment_path, print_args, strip_optimizer) +from utils.general import ( + LOGGER, + Profile, + check_file, + check_img_size, + check_imshow, + check_requirements, + colorstr, + cv2, + increment_path, + print_args, + strip_optimizer, +) from utils.torch_utils import select_device, smart_inference_mode @smart_inference_mode() def run( - weights=ROOT / 'yolov5s-cls.pt', # model.pt path(s) - source=ROOT / 'data/images', # file/dir/URL/glob/screen/0(webcam) - data=ROOT / 'data/coco128.yaml', # dataset.yaml path - imgsz=(224, 224), # inference size (height, width) - device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu - view_img=False, # show results - save_txt=False, # save results to *.txt - nosave=False, # do not save images/videos - augment=False, # augmented inference - visualize=False, # visualize features - update=False, # update all models - project=ROOT / 'runs/predict-cls', # save results to project/name - name='exp', # save results to project/name - exist_ok=False, # existing project/name ok, do not increment - half=False, # use FP16 half-precision inference - dnn=False, # use OpenCV DNN for ONNX inference - vid_stride=1, # video frame-rate stride + weights=ROOT / "yolov5s-cls.pt", # model.pt path(s) + source=ROOT / "data/images", # file/dir/URL/glob/screen/0(webcam) + data=ROOT / "data/coco128.yaml", # dataset.yaml path + imgsz=(224, 224), # inference size (height, width) + device="", # cuda device, i.e. 0 or 0,1,2,3 or cpu + view_img=False, # show results + save_txt=False, # save results to *.txt + nosave=False, # do not save images/videos + augment=False, # augmented inference + visualize=False, # visualize features + update=False, # update all models + project=ROOT / "runs/predict-cls", # save results to project/name + name="exp", # save results to project/name + exist_ok=False, # existing project/name ok, do not increment + half=False, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + vid_stride=1, # video frame-rate stride ): source = str(source) - save_img = not nosave and not source.endswith('.txt') # save inference images + save_img = not nosave and not source.endswith(".txt") # save inference images is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) - is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://')) - webcam = source.isnumeric() or source.endswith('.streams') or (is_url and not is_file) - screenshot = source.lower().startswith('screen') + is_url = source.lower().startswith(("rtsp://", "rtmp://", "http://", "https://")) + webcam = source.isnumeric() or source.endswith(".streams") or (is_url and not is_file) + screenshot = source.lower().startswith("screen") if is_url and is_file: source = check_file(source) # download # Directories save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run - (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + (save_dir / "labels" if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir # Load model device = select_device(device) @@ -127,15 +138,15 @@ def run( seen += 1 if webcam: # batch_size >= 1 p, im0, frame = path[i], im0s[i].copy(), dataset.count - s += f'{i}: ' + s += f"{i}: " else: - p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0) + p, im0, frame = path, im0s.copy(), getattr(dataset, "frame", 0) p = Path(p) # to Path save_path = str(save_dir / p.name) # im.jpg - txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # im.txt + txt_path = str(save_dir / "labels" / p.stem) + ("" if dataset.mode == "image" else f"_{frame}") # im.txt - s += '%gx%g ' % im.shape[2:] # print string + s += "%gx%g " % im.shape[2:] # print string annotator = Annotator(im0, example=str(names), pil=True) # Print results @@ -143,17 +154,17 @@ def run( s += f"{', '.join(f'{names[j]} {prob[j]:.2f}' for j in top5i)}, " # Write results - text = '\n'.join(f'{prob[j]:.2f} {names[j]}' for j in top5i) + text = "\n".join(f"{prob[j]:.2f} {names[j]}" for j in top5i) if save_img or view_img: # Add bbox to image annotator.text([32, 32], text, txt_color=(255, 255, 255)) if save_txt: # Write to file - with open(f'{txt_path}.txt', 'a') as f: - f.write(text + '\n') + with open(f"{txt_path}.txt", "a") as f: + f.write(text + "\n") # Stream results im0 = annotator.result() if view_img: - if platform.system() == 'Linux' and p not in windows: + if platform.system() == "Linux" and p not in windows: windows.append(p) cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux) cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0]) @@ -162,7 +173,7 @@ def run( # Save results (image with detections) if save_img: - if dataset.mode == 'image': + if dataset.mode == "image": cv2.imwrite(save_path, im0) else: # 'video' or 'stream' if vid_path[i] != save_path: # new video @@ -175,18 +186,18 @@ def run( h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) else: # stream fps, w, h = 30, im0.shape[1], im0.shape[0] - save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos - vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) + save_path = str(Path(save_path).with_suffix(".mp4")) # force *.mp4 suffix on results videos + vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h)) vid_writer[i].write(im0) # Print time (inference-only) - LOGGER.info(f'{s}{dt[1].dt * 1E3:.1f}ms') + LOGGER.info(f"{s}{dt[1].dt * 1E3:.1f}ms") # Print results - t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image - LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t) + t = tuple(x.t / seen * 1e3 for x in dt) # speeds per image + LOGGER.info(f"Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}" % t) if save_txt or save_img: - s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else "" LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") if update: strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning) @@ -194,23 +205,23 @@ def run( def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s-cls.pt', help='model path(s)') - parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob/screen/0(webcam)') - parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path') - parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[224], help='inference size h,w') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--view-img', action='store_true', help='show results') - parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') - parser.add_argument('--nosave', action='store_true', help='do not save images/videos') - parser.add_argument('--augment', action='store_true', help='augmented inference') - parser.add_argument('--visualize', action='store_true', help='visualize features') - parser.add_argument('--update', action='store_true', help='update all models') - parser.add_argument('--project', default=ROOT / 'runs/predict-cls', help='save results to project/name') - parser.add_argument('--name', default='exp', help='save results to project/name') - parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') - parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') - parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') - parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride') + parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov5s-cls.pt", help="model path(s)") + parser.add_argument("--source", type=str, default=ROOT / "data/images", help="file/dir/URL/glob/screen/0(webcam)") + parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="(optional) dataset.yaml path") + parser.add_argument("--imgsz", "--img", "--img-size", nargs="+", type=int, default=[224], help="inference size h,w") + parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu") + parser.add_argument("--view-img", action="store_true", help="show results") + parser.add_argument("--save-txt", action="store_true", help="save results to *.txt") + parser.add_argument("--nosave", action="store_true", help="do not save images/videos") + parser.add_argument("--augment", action="store_true", help="augmented inference") + parser.add_argument("--visualize", action="store_true", help="visualize features") + parser.add_argument("--update", action="store_true", help="update all models") + parser.add_argument("--project", default=ROOT / "runs/predict-cls", help="save results to project/name") + parser.add_argument("--name", default="exp", help="save results to project/name") + parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment") + parser.add_argument("--half", action="store_true", help="use FP16 half-precision inference") + parser.add_argument("--dnn", action="store_true", help="use OpenCV DNN for ONNX inference") + parser.add_argument("--vid-stride", type=int, default=1, help="video frame-rate stride") opt = parser.parse_args() opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand print_args(vars(opt)) @@ -218,10 +229,10 @@ def parse_opt(): def main(opt): - check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) run(**vars(opt)) -if __name__ == '__main__': +if __name__ == "__main__": opt = parse_opt() main(opt) diff --git a/classify/train.py b/classify/train.py index 1a3e0511f4..9b6aed86a8 100644 --- a/classify/train.py +++ b/classify/train.py @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Train a YOLOv3 classifier model on a classification dataset +Train a YOLOv3 classifier model on a classification dataset. Usage - Single-GPU training: $ python classify/train.py --model yolov5s-cls.pt --data imagenette160 --epochs 5 --img 224 @@ -40,33 +40,61 @@ from models.experimental import attempt_load from models.yolo import ClassificationModel, DetectionModel from utils.dataloaders import create_classification_dataloader -from utils.general import (DATASETS_DIR, LOGGER, TQDM_BAR_FORMAT, WorkingDirectory, check_git_info, check_git_status, - check_requirements, colorstr, download, increment_path, init_seeds, print_args, yaml_save) +from utils.general import ( + DATASETS_DIR, + LOGGER, + TQDM_BAR_FORMAT, + WorkingDirectory, + check_git_info, + check_git_status, + check_requirements, + colorstr, + download, + increment_path, + init_seeds, + print_args, + yaml_save, +) from utils.loggers import GenericLogger from utils.plots import imshow_cls -from utils.torch_utils import (ModelEMA, de_parallel, model_info, reshape_classifier_output, select_device, smart_DDP, - smart_optimizer, smartCrossEntropyLoss, torch_distributed_zero_first) - -LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html -RANK = int(os.getenv('RANK', -1)) -WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +from utils.torch_utils import ( + ModelEMA, + de_parallel, + model_info, + reshape_classifier_output, + select_device, + smart_DDP, + smart_optimizer, + smartCrossEntropyLoss, + torch_distributed_zero_first, +) + +LOCAL_RANK = int(os.getenv("LOCAL_RANK", -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv("RANK", -1)) +WORLD_SIZE = int(os.getenv("WORLD_SIZE", 1)) GIT_INFO = check_git_info() def train(opt, device): init_seeds(opt.seed + 1 + RANK, deterministic=True) - save_dir, data, bs, epochs, nw, imgsz, pretrained = \ - opt.save_dir, Path(opt.data), opt.batch_size, opt.epochs, min(os.cpu_count() - 1, opt.workers), \ - opt.imgsz, str(opt.pretrained).lower() == 'true' - cuda = device.type != 'cpu' + save_dir, data, bs, epochs, nw, imgsz, pretrained = ( + opt.save_dir, + Path(opt.data), + opt.batch_size, + opt.epochs, + min(os.cpu_count() - 1, opt.workers), + opt.imgsz, + str(opt.pretrained).lower() == "true", + ) + cuda = device.type != "cpu" # Directories - wdir = save_dir / 'weights' + wdir = save_dir / "weights" wdir.mkdir(parents=True, exist_ok=True) # make dir - last, best = wdir / 'last.pt', wdir / 'best.pt' + last, best = wdir / "last.pt", wdir / "best.pt" # Save run settings - yaml_save(save_dir / 'opt.yaml', vars(opt)) + yaml_save(save_dir / "opt.yaml", vars(opt)) # Logger logger = GenericLogger(opt=opt, console_logger=LOGGER) if RANK in {-1, 0} else None @@ -75,51 +103,55 @@ def train(opt, device): with torch_distributed_zero_first(LOCAL_RANK), WorkingDirectory(ROOT): data_dir = data if data.is_dir() else (DATASETS_DIR / data) if not data_dir.is_dir(): - LOGGER.info(f'\nDataset not found ⚠️, missing path {data_dir}, attempting download...') + LOGGER.info(f"\nDataset not found ⚠️, missing path {data_dir}, attempting download...") t = time.time() - if str(data) == 'imagenet': - subprocess.run(['bash', str(ROOT / 'data/scripts/get_imagenet.sh')], shell=True, check=True) + if str(data) == "imagenet": + subprocess.run(["bash", str(ROOT / "data/scripts/get_imagenet.sh")], shell=True, check=True) else: - url = f'https://github.com/ultralytics/yolov5/releases/download/v1.0/{data}.zip' + url = f"https://github.com/ultralytics/yolov5/releases/download/v1.0/{data}.zip" download(url, dir=data_dir.parent) s = f"Dataset download success ✅ ({time.time() - t:.1f}s), saved to {colorstr('bold', data_dir)}\n" LOGGER.info(s) # Dataloaders - nc = len([x for x in (data_dir / 'train').glob('*') if x.is_dir()]) # number of classes - trainloader = create_classification_dataloader(path=data_dir / 'train', - imgsz=imgsz, - batch_size=bs // WORLD_SIZE, - augment=True, - cache=opt.cache, - rank=LOCAL_RANK, - workers=nw) - - test_dir = data_dir / 'test' if (data_dir / 'test').exists() else data_dir / 'val' # data/test or data/val + nc = len([x for x in (data_dir / "train").glob("*") if x.is_dir()]) # number of classes + trainloader = create_classification_dataloader( + path=data_dir / "train", + imgsz=imgsz, + batch_size=bs // WORLD_SIZE, + augment=True, + cache=opt.cache, + rank=LOCAL_RANK, + workers=nw, + ) + + test_dir = data_dir / "test" if (data_dir / "test").exists() else data_dir / "val" # data/test or data/val if RANK in {-1, 0}: - testloader = create_classification_dataloader(path=test_dir, - imgsz=imgsz, - batch_size=bs // WORLD_SIZE * 2, - augment=False, - cache=opt.cache, - rank=-1, - workers=nw) + testloader = create_classification_dataloader( + path=test_dir, + imgsz=imgsz, + batch_size=bs // WORLD_SIZE * 2, + augment=False, + cache=opt.cache, + rank=-1, + workers=nw, + ) # Model with torch_distributed_zero_first(LOCAL_RANK), WorkingDirectory(ROOT): - if Path(opt.model).is_file() or opt.model.endswith('.pt'): - model = attempt_load(opt.model, device='cpu', fuse=False) + if Path(opt.model).is_file() or opt.model.endswith(".pt"): + model = attempt_load(opt.model, device="cpu", fuse=False) elif opt.model in torchvision.models.__dict__: # TorchVision models i.e. resnet50, efficientnet_b0 - model = torchvision.models.__dict__[opt.model](weights='IMAGENET1K_V1' if pretrained else None) + model = torchvision.models.__dict__[opt.model](weights="IMAGENET1K_V1" if pretrained else None) else: - m = hub.list('ultralytics/yolov5') # + hub.list('pytorch/vision') # models - raise ModuleNotFoundError(f'--model {opt.model} not found. Available models are: \n' + '\n'.join(m)) + m = hub.list("ultralytics/yolov5") # + hub.list('pytorch/vision') # models + raise ModuleNotFoundError(f"--model {opt.model} not found. Available models are: \n" + "\n".join(m)) if isinstance(model, DetectionModel): LOGGER.warning("WARNING ⚠️ pass YOLOv3 classifier model with '-cls' suffix, i.e. '--model yolov5s-cls.pt'") model = ClassificationModel(model=model, nc=nc, cutoff=opt.cutoff or 10) # convert to classification model reshape_classifier_output(model, nc) # update class count for m in model.modules(): - if not pretrained and hasattr(m, 'reset_parameters'): + if not pretrained and hasattr(m, "reset_parameters"): m.reset_parameters() if isinstance(m, torch.nn.Dropout) and opt.dropout is not None: m.p = opt.dropout # set dropout @@ -135,8 +167,8 @@ def train(opt, device): if opt.verbose: LOGGER.info(model) images, labels = next(iter(trainloader)) - file = imshow_cls(images[:25], labels[:25], names=model.names, f=save_dir / 'train_images.jpg') - logger.log_images(file, name='Train Examples') + file = imshow_cls(images[:25], labels[:25], names=model.names, f=save_dir / "train_images.jpg") + logger.log_images(file, name="Train Examples") logger.log_graph(model, imgsz) # log model # Optimizer @@ -163,11 +195,13 @@ def train(opt, device): best_fitness = 0.0 scaler = amp.GradScaler(enabled=cuda) val = test_dir.stem # 'val' or 'test' - LOGGER.info(f'Image sizes {imgsz} train, {imgsz} test\n' - f'Using {nw * WORLD_SIZE} dataloader workers\n' - f"Logging results to {colorstr('bold', save_dir)}\n" - f'Starting {opt.model} training on {data} dataset with {nc} classes for {epochs} epochs...\n\n' - f"{'Epoch':>10}{'GPU_mem':>10}{'train_loss':>12}{f'{val}_loss':>12}{'top1_acc':>12}{'top5_acc':>12}") + LOGGER.info( + f'Image sizes {imgsz} train, {imgsz} test\n' + f'Using {nw * WORLD_SIZE} dataloader workers\n' + f"Logging results to {colorstr('bold', save_dir)}\n" + f'Starting {opt.model} training on {data} dataset with {nc} classes for {epochs} epochs...\n\n' + f"{'Epoch':>10}{'GPU_mem':>10}{'train_loss':>12}{f'{val}_loss':>12}{'top1_acc':>12}{'top5_acc':>12}" + ) for epoch in range(epochs): # loop over the dataset multiple times tloss, vloss, fitness = 0.0, 0.0, 0.0 # train loss, val loss, fitness model.train() @@ -198,15 +232,14 @@ def train(opt, device): if RANK in {-1, 0}: # Print tloss = (tloss * i + loss.item()) / (i + 1) # update mean losses - mem = '%.3gG' % (torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0) # (GB) - pbar.desc = f"{f'{epoch + 1}/{epochs}':>10}{mem:>10}{tloss:>12.3g}" + ' ' * 36 + mem = "%.3gG" % (torch.cuda.memory_reserved() / 1e9 if torch.cuda.is_available() else 0) # (GB) + pbar.desc = f"{f'{epoch + 1}/{epochs}':>10}{mem:>10}{tloss:>12.3g}" + " " * 36 # Test if i == len(pbar) - 1: # last batch - top1, top5, vloss = validate.run(model=ema.ema, - dataloader=testloader, - criterion=criterion, - pbar=pbar) # test accuracy, loss + top1, top5, vloss = validate.run( + model=ema.ema, dataloader=testloader, criterion=criterion, pbar=pbar + ) # test accuracy, loss fitness = top1 # define fitness as top1 accuracy # Scheduler @@ -220,26 +253,28 @@ def train(opt, device): # Log metrics = { - 'train/loss': tloss, - f'{val}/loss': vloss, - 'metrics/accuracy_top1': top1, - 'metrics/accuracy_top5': top5, - 'lr/0': optimizer.param_groups[0]['lr']} # learning rate + "train/loss": tloss, + f"{val}/loss": vloss, + "metrics/accuracy_top1": top1, + "metrics/accuracy_top5": top5, + "lr/0": optimizer.param_groups[0]["lr"], + } # learning rate logger.log_metrics(metrics, epoch) # Save model final_epoch = epoch + 1 == epochs if (not opt.nosave) or final_epoch: ckpt = { - 'epoch': epoch, - 'best_fitness': best_fitness, - 'model': deepcopy(ema.ema).half(), # deepcopy(de_parallel(model)).half(), - 'ema': None, # deepcopy(ema.ema).half(), - 'updates': ema.updates, - 'optimizer': None, # optimizer.state_dict(), - 'opt': vars(opt), - 'git': GIT_INFO, # {remote, branch, commit} if a git repo - 'date': datetime.now().isoformat()} + "epoch": epoch, + "best_fitness": best_fitness, + "model": deepcopy(ema.ema).half(), # deepcopy(de_parallel(model)).half(), + "ema": None, # deepcopy(ema.ema).half(), + "updates": ema.updates, + "optimizer": None, # optimizer.state_dict(), + "opt": vars(opt), + "git": GIT_INFO, # {remote, branch, commit} if a git repo + "date": datetime.now().isoformat(), + } # Save last, best and delete torch.save(ckpt, last) @@ -249,49 +284,51 @@ def train(opt, device): # Train complete if RANK in {-1, 0} and final_epoch: - LOGGER.info(f'\nTraining complete ({(time.time() - t0) / 3600:.3f} hours)' - f"\nResults saved to {colorstr('bold', save_dir)}" - f'\nPredict: python classify/predict.py --weights {best} --source im.jpg' - f'\nValidate: python classify/val.py --weights {best} --data {data_dir}' - f'\nExport: python export.py --weights {best} --include onnx' - f"\nPyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', '{best}')" - f'\nVisualize: https://netron.app\n') + LOGGER.info( + f'\nTraining complete ({(time.time() - t0) / 3600:.3f} hours)' + f"\nResults saved to {colorstr('bold', save_dir)}" + f'\nPredict: python classify/predict.py --weights {best} --source im.jpg' + f'\nValidate: python classify/val.py --weights {best} --data {data_dir}' + f'\nExport: python export.py --weights {best} --include onnx' + f"\nPyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', '{best}')" + f'\nVisualize: https://netron.app\n' + ) # Plot examples images, labels = (x[:25] for x in next(iter(testloader))) # first 25 images and labels pred = torch.max(ema.ema(images.to(device)), 1)[1] - file = imshow_cls(images, labels, pred, de_parallel(model).names, verbose=False, f=save_dir / 'test_images.jpg') + file = imshow_cls(images, labels, pred, de_parallel(model).names, verbose=False, f=save_dir / "test_images.jpg") # Log results - meta = {'epochs': epochs, 'top1_acc': best_fitness, 'date': datetime.now().isoformat()} - logger.log_images(file, name='Test Examples (true-predicted)', epoch=epoch) + meta = {"epochs": epochs, "top1_acc": best_fitness, "date": datetime.now().isoformat()} + logger.log_images(file, name="Test Examples (true-predicted)", epoch=epoch) logger.log_model(best, epochs, metadata=meta) def parse_opt(known=False): parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default='yolov5s-cls.pt', help='initial weights path') - parser.add_argument('--data', type=str, default='imagenette160', help='cifar10, cifar100, mnist, imagenet, ...') - parser.add_argument('--epochs', type=int, default=10, help='total training epochs') - parser.add_argument('--batch-size', type=int, default=64, help='total batch size for all GPUs') - parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=224, help='train, val image size (pixels)') - parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') - parser.add_argument('--cache', type=str, nargs='?', const='ram', help='--cache images in "ram" (default) or "disk"') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') - parser.add_argument('--project', default=ROOT / 'runs/train-cls', help='save to project/name') - parser.add_argument('--name', default='exp', help='save to project/name') - parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') - parser.add_argument('--pretrained', nargs='?', const=True, default=True, help='start from i.e. --pretrained False') - parser.add_argument('--optimizer', choices=['SGD', 'Adam', 'AdamW', 'RMSProp'], default='Adam', help='optimizer') - parser.add_argument('--lr0', type=float, default=0.001, help='initial learning rate') - parser.add_argument('--decay', type=float, default=5e-5, help='weight decay') - parser.add_argument('--label-smoothing', type=float, default=0.1, help='Label smoothing epsilon') - parser.add_argument('--cutoff', type=int, default=None, help='Model layer cutoff index for Classify() head') - parser.add_argument('--dropout', type=float, default=None, help='Dropout (fraction)') - parser.add_argument('--verbose', action='store_true', help='Verbose mode') - parser.add_argument('--seed', type=int, default=0, help='Global training seed') - parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + parser.add_argument("--model", type=str, default="yolov5s-cls.pt", help="initial weights path") + parser.add_argument("--data", type=str, default="imagenette160", help="cifar10, cifar100, mnist, imagenet, ...") + parser.add_argument("--epochs", type=int, default=10, help="total training epochs") + parser.add_argument("--batch-size", type=int, default=64, help="total batch size for all GPUs") + parser.add_argument("--imgsz", "--img", "--img-size", type=int, default=224, help="train, val image size (pixels)") + parser.add_argument("--nosave", action="store_true", help="only save final checkpoint") + parser.add_argument("--cache", type=str, nargs="?", const="ram", help='--cache images in "ram" (default) or "disk"') + parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu") + parser.add_argument("--workers", type=int, default=8, help="max dataloader workers (per RANK in DDP mode)") + parser.add_argument("--project", default=ROOT / "runs/train-cls", help="save to project/name") + parser.add_argument("--name", default="exp", help="save to project/name") + parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment") + parser.add_argument("--pretrained", nargs="?", const=True, default=True, help="start from i.e. --pretrained False") + parser.add_argument("--optimizer", choices=["SGD", "Adam", "AdamW", "RMSProp"], default="Adam", help="optimizer") + parser.add_argument("--lr0", type=float, default=0.001, help="initial learning rate") + parser.add_argument("--decay", type=float, default=5e-5, help="weight decay") + parser.add_argument("--label-smoothing", type=float, default=0.1, help="Label smoothing epsilon") + parser.add_argument("--cutoff", type=int, default=None, help="Model layer cutoff index for Classify() head") + parser.add_argument("--dropout", type=float, default=None, help="Dropout (fraction)") + parser.add_argument("--verbose", action="store_true", help="Verbose mode") + parser.add_argument("--seed", type=int, default=0, help="Global training seed") + parser.add_argument("--local_rank", type=int, default=-1, help="Automatic DDP Multi-GPU argument, do not modify") return parser.parse_known_args()[0] if known else parser.parse_args() @@ -300,17 +337,17 @@ def main(opt): if RANK in {-1, 0}: print_args(vars(opt)) check_git_status() - check_requirements(ROOT / 'requirements.txt') + check_requirements(ROOT / "requirements.txt") # DDP mode device = select_device(opt.device, batch_size=opt.batch_size) if LOCAL_RANK != -1: - assert opt.batch_size != -1, 'AutoBatch is coming soon for classification, please pass a valid --batch-size' - assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' - assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' + assert opt.batch_size != -1, "AutoBatch is coming soon for classification, please pass a valid --batch-size" + assert opt.batch_size % WORLD_SIZE == 0, f"--batch-size {opt.batch_size} must be multiple of WORLD_SIZE" + assert torch.cuda.device_count() > LOCAL_RANK, "insufficient CUDA devices for DDP command" torch.cuda.set_device(LOCAL_RANK) - device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend='nccl' if dist.is_nccl_available() else 'gloo') + device = torch.device("cuda", LOCAL_RANK) + dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") # Parameters opt.save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok) # increment run @@ -328,6 +365,6 @@ def run(**kwargs): return opt -if __name__ == '__main__': +if __name__ == "__main__": opt = parse_opt() main(opt) diff --git a/classify/val.py b/classify/val.py index 6e2deca78e..3875001e85 100644 --- a/classify/val.py +++ b/classify/val.py @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Validate a trained YOLOv3 classification model on a classification dataset +Validate a trained YOLOv3 classification model on a classification dataset. Usage: $ bash data/scripts/get_imagenet.sh --val # download ImageNet val split (6.3G, 50000 images) @@ -36,22 +36,30 @@ from models.common import DetectMultiBackend from utils.dataloaders import create_classification_dataloader -from utils.general import (LOGGER, TQDM_BAR_FORMAT, Profile, check_img_size, check_requirements, colorstr, - increment_path, print_args) +from utils.general import ( + LOGGER, + TQDM_BAR_FORMAT, + Profile, + check_img_size, + check_requirements, + colorstr, + increment_path, + print_args, +) from utils.torch_utils import select_device, smart_inference_mode @smart_inference_mode() def run( - data=ROOT / '../datasets/mnist', # dataset dir - weights=ROOT / 'yolov5s-cls.pt', # model.pt path(s) + data=ROOT / "../datasets/mnist", # dataset dir + weights=ROOT / "yolov5s-cls.pt", # model.pt path(s) batch_size=128, # batch size imgsz=224, # inference size (pixels) - device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + device="", # cuda device, i.e. 0 or 0,1,2,3 or cpu workers=8, # max dataloader workers (per RANK in DDP mode) verbose=False, # verbose output - project=ROOT / 'runs/val-cls', # save to project/name - name='exp', # save to project/name + project=ROOT / "runs/val-cls", # save to project/name + name="exp", # save to project/name exist_ok=False, # existing project/name ok, do not increment half=False, # use FP16 half-precision inference dnn=False, # use OpenCV DNN for ONNX inference @@ -64,7 +72,7 @@ def run( training = model is not None if training: # called by train.py device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model - half &= device.type != 'cpu' # half precision only supported on CUDA + half &= device.type != "cpu" # half precision only supported on CUDA model.half() if half else model.float() else: # called directly device = select_device(device, batch_size=batch_size) @@ -84,25 +92,22 @@ def run( device = model.device if not (pt or jit): batch_size = 1 # export.py models default to batch-size 1 - LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') + LOGGER.info(f"Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models") # Dataloader data = Path(data) - test_dir = data / 'test' if (data / 'test').exists() else data / 'val' # data/test or data/val - dataloader = create_classification_dataloader(path=test_dir, - imgsz=imgsz, - batch_size=batch_size, - augment=False, - rank=-1, - workers=workers) + test_dir = data / "test" if (data / "test").exists() else data / "val" # data/test or data/val + dataloader = create_classification_dataloader( + path=test_dir, imgsz=imgsz, batch_size=batch_size, augment=False, rank=-1, workers=workers + ) model.eval() pred, targets, loss, dt = [], [], 0, (Profile(), Profile(), Profile()) n = len(dataloader) # number of batches - action = 'validating' if dataloader.dataset.root.stem == 'val' else 'testing' - desc = f'{pbar.desc[:-36]}{action:>36}' if pbar else f'{action}' + action = "validating" if dataloader.dataset.root.stem == "val" else "testing" + desc = f"{pbar.desc[:-36]}{action:>36}" if pbar else f"{action}" bar = tqdm(dataloader, desc, n, not training, bar_format=TQDM_BAR_FORMAT, position=0) - with torch.cuda.amp.autocast(enabled=device.type != 'cpu'): + with torch.cuda.amp.autocast(enabled=device.type != "cpu"): for images, labels in bar: with dt[0]: images, labels = images.to(device, non_blocking=True), labels.to(device) @@ -123,19 +128,19 @@ def run( top1, top5 = acc.mean(0).tolist() if pbar: - pbar.desc = f'{pbar.desc[:-36]}{loss:>12.3g}{top1:>12.3g}{top5:>12.3g}' + pbar.desc = f"{pbar.desc[:-36]}{loss:>12.3g}{top1:>12.3g}{top5:>12.3g}" if verbose: # all classes LOGGER.info(f"{'Class':>24}{'Images':>12}{'top1_acc':>12}{'top5_acc':>12}") LOGGER.info(f"{'all':>24}{targets.shape[0]:>12}{top1:>12.3g}{top5:>12.3g}") for i, c in model.names.items(): acc_i = acc[targets == i] top1i, top5i = acc_i.mean(0).tolist() - LOGGER.info(f'{c:>24}{acc_i.shape[0]:>12}{top1i:>12.3g}{top5i:>12.3g}') + LOGGER.info(f"{c:>24}{acc_i.shape[0]:>12}{top1i:>12.3g}{top5i:>12.3g}") # Print results - t = tuple(x.t / len(dataloader.dataset.samples) * 1E3 for x in dt) # speeds per image + t = tuple(x.t / len(dataloader.dataset.samples) * 1e3 for x in dt) # speeds per image shape = (1, 3, imgsz, imgsz) - LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms post-process per image at shape {shape}' % t) + LOGGER.info(f"Speed: %.1fms pre-process, %.1fms inference, %.1fms post-process per image at shape {shape}" % t) LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}") return top1, top5, loss @@ -143,28 +148,28 @@ def run( def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--data', type=str, default=ROOT / '../datasets/mnist', help='dataset path') - parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s-cls.pt', help='model.pt path(s)') - parser.add_argument('--batch-size', type=int, default=128, help='batch size') - parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=224, help='inference size (pixels)') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') - parser.add_argument('--verbose', nargs='?', const=True, default=True, help='verbose output') - parser.add_argument('--project', default=ROOT / 'runs/val-cls', help='save to project/name') - parser.add_argument('--name', default='exp', help='save to project/name') - parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') - parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') - parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument("--data", type=str, default=ROOT / "../datasets/mnist", help="dataset path") + parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov5s-cls.pt", help="model.pt path(s)") + parser.add_argument("--batch-size", type=int, default=128, help="batch size") + parser.add_argument("--imgsz", "--img", "--img-size", type=int, default=224, help="inference size (pixels)") + parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu") + parser.add_argument("--workers", type=int, default=8, help="max dataloader workers (per RANK in DDP mode)") + parser.add_argument("--verbose", nargs="?", const=True, default=True, help="verbose output") + parser.add_argument("--project", default=ROOT / "runs/val-cls", help="save to project/name") + parser.add_argument("--name", default="exp", help="save to project/name") + parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment") + parser.add_argument("--half", action="store_true", help="use FP16 half-precision inference") + parser.add_argument("--dnn", action="store_true", help="use OpenCV DNN for ONNX inference") opt = parser.parse_args() print_args(vars(opt)) return opt def main(opt): - check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) run(**vars(opt)) -if __name__ == '__main__': +if __name__ == "__main__": opt = parse_opt() main(opt) diff --git a/detect.py b/detect.py index 8ef95761f0..4502e5fc35 100644 --- a/detect.py +++ b/detect.py @@ -46,53 +46,67 @@ from models.common import DetectMultiBackend from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams -from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, - increment_path, non_max_suppression, print_args, scale_boxes, strip_optimizer, xyxy2xywh) +from utils.general import ( + LOGGER, + Profile, + check_file, + check_img_size, + check_imshow, + check_requirements, + colorstr, + cv2, + increment_path, + non_max_suppression, + print_args, + scale_boxes, + strip_optimizer, + xyxy2xywh, +) from utils.torch_utils import select_device, smart_inference_mode @smart_inference_mode() def run( - weights=ROOT / 'yolov5s.pt', # model path or triton URL - source=ROOT / 'data/images', # file/dir/URL/glob/screen/0(webcam) - data=ROOT / 'data/coco128.yaml', # dataset.yaml path - imgsz=(640, 640), # inference size (height, width) - conf_thres=0.25, # confidence threshold - iou_thres=0.45, # NMS IOU threshold - max_det=1000, # maximum detections per image - device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu - view_img=False, # show results - save_txt=False, # save results to *.txt - save_conf=False, # save confidences in --save-txt labels - save_crop=False, # save cropped prediction boxes - nosave=False, # do not save images/videos - classes=None, # filter by class: --class 0, or --class 0 2 3 - agnostic_nms=False, # class-agnostic NMS - augment=False, # augmented inference - visualize=False, # visualize features - update=False, # update all models - project=ROOT / 'runs/detect', # save results to project/name - name='exp', # save results to project/name - exist_ok=False, # existing project/name ok, do not increment - line_thickness=3, # bounding box thickness (pixels) - hide_labels=False, # hide labels - hide_conf=False, # hide confidences - half=False, # use FP16 half-precision inference - dnn=False, # use OpenCV DNN for ONNX inference - vid_stride=1, # video frame-rate stride + weights=ROOT / "yolov5s.pt", # model path or triton URL + source=ROOT / "data/images", # file/dir/URL/glob/screen/0(webcam) + data=ROOT / "data/coco128.yaml", # dataset.yaml path + imgsz=(640, 640), # inference size (height, width) + conf_thres=0.25, # confidence threshold + iou_thres=0.45, # NMS IOU threshold + max_det=1000, # maximum detections per image + device="", # cuda device, i.e. 0 or 0,1,2,3 or cpu + view_img=False, # show results + save_txt=False, # save results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_crop=False, # save cropped prediction boxes + nosave=False, # do not save images/videos + classes=None, # filter by class: --class 0, or --class 0 2 3 + agnostic_nms=False, # class-agnostic NMS + augment=False, # augmented inference + visualize=False, # visualize features + update=False, # update all models + project=ROOT / "runs/detect", # save results to project/name + name="exp", # save results to project/name + exist_ok=False, # existing project/name ok, do not increment + line_thickness=3, # bounding box thickness (pixels) + hide_labels=False, # hide labels + hide_conf=False, # hide confidences + half=False, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + vid_stride=1, # video frame-rate stride ): source = str(source) - save_img = not nosave and not source.endswith('.txt') # save inference images + save_img = not nosave and not source.endswith(".txt") # save inference images is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) - is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://')) - webcam = source.isnumeric() or source.endswith('.streams') or (is_url and not is_file) - screenshot = source.lower().startswith('screen') + is_url = source.lower().startswith(("rtsp://", "rtmp://", "http://", "https://")) + webcam = source.isnumeric() or source.endswith(".streams") or (is_url and not is_file) + screenshot = source.lower().startswith("screen") if is_url and is_file: source = check_file(source) # download # Directories save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run - (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + (save_dir / "labels" if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir # Load model device = select_device(device) @@ -140,14 +154,14 @@ def run( seen += 1 if webcam: # batch_size >= 1 p, im0, frame = path[i], im0s[i].copy(), dataset.count - s += f'{i}: ' + s += f"{i}: " else: - p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0) + p, im0, frame = path, im0s.copy(), getattr(dataset, "frame", 0) p = Path(p) # to Path save_path = str(save_dir / p.name) # im.jpg - txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # im.txt - s += '%gx%g ' % im.shape[2:] # print string + txt_path = str(save_dir / "labels" / p.stem) + ("" if dataset.mode == "image" else f"_{frame}") # im.txt + s += "%gx%g " % im.shape[2:] # print string gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh imc = im0.copy() if save_crop else im0 # for save_crop annotator = Annotator(im0, line_width=line_thickness, example=str(names)) @@ -165,20 +179,20 @@ def run( if save_txt: # Write to file xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format - with open(f'{txt_path}.txt', 'a') as f: - f.write(('%g ' * len(line)).rstrip() % line + '\n') + with open(f"{txt_path}.txt", "a") as f: + f.write(("%g " * len(line)).rstrip() % line + "\n") if save_img or save_crop or view_img: # Add bbox to image c = int(cls) # integer class - label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}') + label = None if hide_labels else (names[c] if hide_conf else f"{names[c]} {conf:.2f}") annotator.box_label(xyxy, label, color=colors(c, True)) if save_crop: - save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True) + save_one_box(xyxy, imc, file=save_dir / "crops" / names[c] / f"{p.stem}.jpg", BGR=True) # Stream results im0 = annotator.result() if view_img: - if platform.system() == 'Linux' and p not in windows: + if platform.system() == "Linux" and p not in windows: windows.append(p) cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux) cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0]) @@ -187,7 +201,7 @@ def run( # Save results (image with detections) if save_img: - if dataset.mode == 'image': + if dataset.mode == "image": cv2.imwrite(save_path, im0) else: # 'video' or 'stream' if vid_path[i] != save_path: # new video @@ -200,18 +214,18 @@ def run( h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) else: # stream fps, w, h = 30, im0.shape[1], im0.shape[0] - save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos - vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) + save_path = str(Path(save_path).with_suffix(".mp4")) # force *.mp4 suffix on results videos + vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h)) vid_writer[i].write(im0) # Print time (inference-only) LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms") # Print results - t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image - LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t) + t = tuple(x.t / seen * 1e3 for x in dt) # speeds per image + LOGGER.info(f"Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}" % t) if save_txt or save_img: - s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else "" LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") if update: strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning) @@ -219,37 +233,35 @@ def run( def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--weights', - nargs='+', - type=str, - default=ROOT / 'yolov3-tiny.pt', - help='model path or triton URL') - parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob/screen/0(webcam)') - parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path') - parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') - parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold') - parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold') - parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--view-img', action='store_true', help='show results') - parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') - parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') - parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes') - parser.add_argument('--nosave', action='store_true', help='do not save images/videos') - parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3') - parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') - parser.add_argument('--augment', action='store_true', help='augmented inference') - parser.add_argument('--visualize', action='store_true', help='visualize features') - parser.add_argument('--update', action='store_true', help='update all models') - parser.add_argument('--project', default=ROOT / 'runs/detect', help='save results to project/name') - parser.add_argument('--name', default='exp', help='save results to project/name') - parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') - parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)') - parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels') - parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences') - parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') - parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') - parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride') + parser.add_argument( + "--weights", nargs="+", type=str, default=ROOT / "yolov3-tiny.pt", help="model path or triton URL" + ) + parser.add_argument("--source", type=str, default=ROOT / "data/images", help="file/dir/URL/glob/screen/0(webcam)") + parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="(optional) dataset.yaml path") + parser.add_argument("--imgsz", "--img", "--img-size", nargs="+", type=int, default=[640], help="inference size h,w") + parser.add_argument("--conf-thres", type=float, default=0.25, help="confidence threshold") + parser.add_argument("--iou-thres", type=float, default=0.45, help="NMS IoU threshold") + parser.add_argument("--max-det", type=int, default=1000, help="maximum detections per image") + parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu") + parser.add_argument("--view-img", action="store_true", help="show results") + parser.add_argument("--save-txt", action="store_true", help="save results to *.txt") + parser.add_argument("--save-conf", action="store_true", help="save confidences in --save-txt labels") + parser.add_argument("--save-crop", action="store_true", help="save cropped prediction boxes") + parser.add_argument("--nosave", action="store_true", help="do not save images/videos") + parser.add_argument("--classes", nargs="+", type=int, help="filter by class: --classes 0, or --classes 0 2 3") + parser.add_argument("--agnostic-nms", action="store_true", help="class-agnostic NMS") + parser.add_argument("--augment", action="store_true", help="augmented inference") + parser.add_argument("--visualize", action="store_true", help="visualize features") + parser.add_argument("--update", action="store_true", help="update all models") + parser.add_argument("--project", default=ROOT / "runs/detect", help="save results to project/name") + parser.add_argument("--name", default="exp", help="save results to project/name") + parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment") + parser.add_argument("--line-thickness", default=3, type=int, help="bounding box thickness (pixels)") + parser.add_argument("--hide-labels", default=False, action="store_true", help="hide labels") + parser.add_argument("--hide-conf", default=False, action="store_true", help="hide confidences") + parser.add_argument("--half", action="store_true", help="use FP16 half-precision inference") + parser.add_argument("--dnn", action="store_true", help="use OpenCV DNN for ONNX inference") + parser.add_argument("--vid-stride", type=int, default=1, help="video frame-rate stride") opt = parser.parse_args() opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand print_args(vars(opt)) @@ -257,10 +269,10 @@ def parse_opt(): def main(opt): - check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) run(**vars(opt)) -if __name__ == '__main__': +if __name__ == "__main__": opt = parse_opt() main(opt) diff --git a/export.py b/export.py index 93f2b888e5..8cacd97201 100644 --- a/export.py +++ b/export.py @@ -64,30 +64,42 @@ ROOT = FILE.parents[0] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH -if platform.system() != 'Windows': +if platform.system() != "Windows": ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative from models.experimental import attempt_load from models.yolo import ClassificationModel, Detect, DetectionModel, SegmentationModel from utils.dataloaders import LoadImages -from utils.general import (LOGGER, Profile, check_dataset, check_img_size, check_requirements, check_version, - check_yaml, colorstr, file_size, get_default_args, print_args, url2file, yaml_save) +from utils.general import ( + LOGGER, + Profile, + check_dataset, + check_img_size, + check_requirements, + check_version, + check_yaml, + colorstr, + file_size, + get_default_args, + print_args, + url2file, + yaml_save, +) from utils.torch_utils import select_device, smart_inference_mode -MACOS = platform.system() == 'Darwin' # macOS environment +MACOS = platform.system() == "Darwin" # macOS environment class iOSModel(torch.nn.Module): - def __init__(self, model, im): super().__init__() b, c, h, w = im.shape # batch, channel, height, width self.model = model self.nc = model.nc # number of classes if w == h: - self.normalize = 1. / w + self.normalize = 1.0 / w else: - self.normalize = torch.tensor([1. / w, 1. / h, 1. / w, 1. / h]) # broadcast (slower, smaller) + self.normalize = torch.tensor([1.0 / w, 1.0 / h, 1.0 / w, 1.0 / h]) # broadcast (slower, smaller) # np = model(im)[0].shape[1] # number of points # self.normalize = torch.tensor([1. / w, 1. / h, 1. / w, 1. / h]).expand(np, 4) # explicit (faster, larger) @@ -99,19 +111,20 @@ def forward(self, x): def export_formats(): # YOLOv3 export formats x = [ - ['PyTorch', '-', '.pt', True, True], - ['TorchScript', 'torchscript', '.torchscript', True, True], - ['ONNX', 'onnx', '.onnx', True, True], - ['OpenVINO', 'openvino', '_openvino_model', True, False], - ['TensorRT', 'engine', '.engine', False, True], - ['CoreML', 'coreml', '.mlmodel', True, False], - ['TensorFlow SavedModel', 'saved_model', '_saved_model', True, True], - ['TensorFlow GraphDef', 'pb', '.pb', True, True], - ['TensorFlow Lite', 'tflite', '.tflite', True, False], - ['TensorFlow Edge TPU', 'edgetpu', '_edgetpu.tflite', False, False], - ['TensorFlow.js', 'tfjs', '_web_model', False, False], - ['PaddlePaddle', 'paddle', '_paddle_model', True, True], ] - return pd.DataFrame(x, columns=['Format', 'Argument', 'Suffix', 'CPU', 'GPU']) + ["PyTorch", "-", ".pt", True, True], + ["TorchScript", "torchscript", ".torchscript", True, True], + ["ONNX", "onnx", ".onnx", True, True], + ["OpenVINO", "openvino", "_openvino_model", True, False], + ["TensorRT", "engine", ".engine", False, True], + ["CoreML", "coreml", ".mlmodel", True, False], + ["TensorFlow SavedModel", "saved_model", "_saved_model", True, True], + ["TensorFlow GraphDef", "pb", ".pb", True, True], + ["TensorFlow Lite", "tflite", ".tflite", True, False], + ["TensorFlow Edge TPU", "edgetpu", "_edgetpu.tflite", False, False], + ["TensorFlow.js", "tfjs", "_web_model", False, False], + ["PaddlePaddle", "paddle", "_paddle_model", True, True], + ] + return pd.DataFrame(x, columns=["Format", "Argument", "Suffix", "CPU", "GPU"]) def try_export(inner_func): @@ -119,28 +132,28 @@ def try_export(inner_func): inner_args = get_default_args(inner_func) def outer_func(*args, **kwargs): - prefix = inner_args['prefix'] + prefix = inner_args["prefix"] try: with Profile() as dt: f, model = inner_func(*args, **kwargs) - LOGGER.info(f'{prefix} export success ✅ {dt.t:.1f}s, saved as {f} ({file_size(f):.1f} MB)') + LOGGER.info(f"{prefix} export success ✅ {dt.t:.1f}s, saved as {f} ({file_size(f):.1f} MB)") return f, model except Exception as e: - LOGGER.info(f'{prefix} export failure ❌ {dt.t:.1f}s: {e}') + LOGGER.info(f"{prefix} export failure ❌ {dt.t:.1f}s: {e}") return None, None return outer_func @try_export -def export_torchscript(model, im, file, optimize, prefix=colorstr('TorchScript:')): +def export_torchscript(model, im, file, optimize, prefix=colorstr("TorchScript:")): # YOLOv3 TorchScript model export - LOGGER.info(f'\n{prefix} starting export with torch {torch.__version__}...') - f = file.with_suffix('.torchscript') + LOGGER.info(f"\n{prefix} starting export with torch {torch.__version__}...") + f = file.with_suffix(".torchscript") ts = torch.jit.trace(model, im, strict=False) - d = {'shape': im.shape, 'stride': int(max(model.stride)), 'names': model.names} - extra_files = {'config.txt': json.dumps(d)} # torch._C.ExtraFilesMap() + d = {"shape": im.shape, "stride": int(max(model.stride)), "names": model.names} + extra_files = {"config.txt": json.dumps(d)} # torch._C.ExtraFilesMap() if optimize: # https://pytorch.org/tutorials/recipes/mobile_interpreter.html optimize_for_mobile(ts)._save_for_lite_interpreter(str(f), _extra_files=extra_files) else: @@ -149,22 +162,22 @@ def export_torchscript(model, im, file, optimize, prefix=colorstr('TorchScript:' @try_export -def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr('ONNX:')): +def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr("ONNX:")): # YOLOv3 ONNX export - check_requirements('onnx>=1.12.0') + check_requirements("onnx>=1.12.0") import onnx - LOGGER.info(f'\n{prefix} starting export with onnx {onnx.__version__}...') - f = file.with_suffix('.onnx') + LOGGER.info(f"\n{prefix} starting export with onnx {onnx.__version__}...") + f = file.with_suffix(".onnx") - output_names = ['output0', 'output1'] if isinstance(model, SegmentationModel) else ['output0'] + output_names = ["output0", "output1"] if isinstance(model, SegmentationModel) else ["output0"] if dynamic: - dynamic = {'images': {0: 'batch', 2: 'height', 3: 'width'}} # shape(1,3,640,640) + dynamic = {"images": {0: "batch", 2: "height", 3: "width"}} # shape(1,3,640,640) if isinstance(model, SegmentationModel): - dynamic['output0'] = {0: 'batch', 1: 'anchors'} # shape(1,25200,85) - dynamic['output1'] = {0: 'batch', 2: 'mask_height', 3: 'mask_width'} # shape(1,32,160,160) + dynamic["output0"] = {0: "batch", 1: "anchors"} # shape(1,25200,85) + dynamic["output1"] = {0: "batch", 2: "mask_height", 3: "mask_width"} # shape(1,32,160,160) elif isinstance(model, DetectionModel): - dynamic['output0'] = {0: 'batch', 1: 'anchors'} # shape(1,25200,85) + dynamic["output0"] = {0: "batch", 1: "anchors"} # shape(1,25200,85) torch.onnx.export( model.cpu() if dynamic else model, # --dynamic only compatible with cpu @@ -173,16 +186,17 @@ def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr('ONNX verbose=False, opset_version=opset, do_constant_folding=True, # WARNING: DNN inference with torch>=1.12 may require do_constant_folding=False - input_names=['images'], + input_names=["images"], output_names=output_names, - dynamic_axes=dynamic or None) + dynamic_axes=dynamic or None, + ) # Checks model_onnx = onnx.load(f) # load onnx model onnx.checker.check_model(model_onnx) # check onnx model # Metadata - d = {'stride': int(max(model.stride)), 'names': model.names} + d = {"stride": int(max(model.stride)), "names": model.names} for k, v in d.items(): meta = model_onnx.metadata_props.add() meta.key, meta.value = k, str(v) @@ -192,36 +206,37 @@ def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr('ONNX if simplify: try: cuda = torch.cuda.is_available() - check_requirements(('onnxruntime-gpu' if cuda else 'onnxruntime', 'onnx-simplifier>=0.4.1')) + check_requirements(("onnxruntime-gpu" if cuda else "onnxruntime", "onnx-simplifier>=0.4.1")) import onnxsim - LOGGER.info(f'{prefix} simplifying with onnx-simplifier {onnxsim.__version__}...') + LOGGER.info(f"{prefix} simplifying with onnx-simplifier {onnxsim.__version__}...") model_onnx, check = onnxsim.simplify(model_onnx) - assert check, 'assert check failed' + assert check, "assert check failed" onnx.save(model_onnx, f) except Exception as e: - LOGGER.info(f'{prefix} simplifier failure: {e}') + LOGGER.info(f"{prefix} simplifier failure: {e}") return f, model_onnx @try_export -def export_openvino(file, metadata, half, int8, data, prefix=colorstr('OpenVINO:')): +def export_openvino(file, metadata, half, int8, data, prefix=colorstr("OpenVINO:")): # YOLOv3 OpenVINO export - check_requirements('openvino-dev>=2023.0') # requires openvino-dev: https://pypi.org/project/openvino-dev/ + check_requirements("openvino-dev>=2023.0") # requires openvino-dev: https://pypi.org/project/openvino-dev/ import openvino.runtime as ov # noqa from openvino.tools import mo # noqa - LOGGER.info(f'\n{prefix} starting export with openvino {ov.__version__}...') - f = str(file).replace(file.suffix, f'_openvino_model{os.sep}') - f_onnx = file.with_suffix('.onnx') - f_ov = str(Path(f) / file.with_suffix('.xml').name) + LOGGER.info(f"\n{prefix} starting export with openvino {ov.__version__}...") + f = str(file).replace(file.suffix, f"_openvino_model{os.sep}") + f_onnx = file.with_suffix(".onnx") + f_ov = str(Path(f) / file.with_suffix(".xml").name) if int8: - check_requirements('nncf>=2.4.0') # requires at least version 2.4.0 to use the post-training quantization + check_requirements("nncf>=2.4.0") # requires at least version 2.4.0 to use the post-training quantization import nncf import numpy as np from openvino.runtime import Core from utils.dataloaders import create_dataloader + core = Core() onnx_model = core.read_model(f_onnx) # export @@ -233,24 +248,21 @@ def prepare_input_tensor(image: np.ndarray): input_tensor = np.expand_dims(input_tensor, 0) return input_tensor - def gen_dataloader(yaml_path, task='train', imgsz=640, workers=4): + def gen_dataloader(yaml_path, task="train", imgsz=640, workers=4): data_yaml = check_yaml(yaml_path) data = check_dataset(data_yaml) - dataloader = create_dataloader(data[task], - imgsz=imgsz, - batch_size=1, - stride=32, - pad=0.5, - single_cls=False, - rect=False, - workers=workers)[0] + dataloader = create_dataloader( + data[task], imgsz=imgsz, batch_size=1, stride=32, pad=0.5, single_cls=False, rect=False, workers=workers + )[0] return dataloader # noqa: F811 def transform_fn(data_item): """ - Quantization transform function. Extracts and preprocess input data from dataloader item for quantization. + Quantization transform function. + + Extracts and preprocess input data from dataloader item for quantization. Parameters: data_item: Tuple with data item produced by DataLoader during iteration Returns: @@ -264,77 +276,77 @@ def transform_fn(data_item): quantization_dataset = nncf.Dataset(ds, transform_fn) ov_model = nncf.quantize(onnx_model, quantization_dataset, preset=nncf.QuantizationPreset.MIXED) else: - ov_model = mo.convert_model(f_onnx, model_name=file.stem, framework='onnx', compress_to_fp16=half) # export + ov_model = mo.convert_model(f_onnx, model_name=file.stem, framework="onnx", compress_to_fp16=half) # export ov.serialize(ov_model, f_ov) # save - yaml_save(Path(f) / file.with_suffix('.yaml').name, metadata) # add metadata.yaml + yaml_save(Path(f) / file.with_suffix(".yaml").name, metadata) # add metadata.yaml return f, None @try_export -def export_paddle(model, im, file, metadata, prefix=colorstr('PaddlePaddle:')): +def export_paddle(model, im, file, metadata, prefix=colorstr("PaddlePaddle:")): # YOLOv3 Paddle export - check_requirements(('paddlepaddle', 'x2paddle')) + check_requirements(("paddlepaddle", "x2paddle")) import x2paddle from x2paddle.convert import pytorch2paddle - LOGGER.info(f'\n{prefix} starting export with X2Paddle {x2paddle.__version__}...') - f = str(file).replace('.pt', f'_paddle_model{os.sep}') + LOGGER.info(f"\n{prefix} starting export with X2Paddle {x2paddle.__version__}...") + f = str(file).replace(".pt", f"_paddle_model{os.sep}") - pytorch2paddle(module=model, save_dir=f, jit_type='trace', input_examples=[im]) # export - yaml_save(Path(f) / file.with_suffix('.yaml').name, metadata) # add metadata.yaml + pytorch2paddle(module=model, save_dir=f, jit_type="trace", input_examples=[im]) # export + yaml_save(Path(f) / file.with_suffix(".yaml").name, metadata) # add metadata.yaml return f, None @try_export -def export_coreml(model, im, file, int8, half, nms, prefix=colorstr('CoreML:')): +def export_coreml(model, im, file, int8, half, nms, prefix=colorstr("CoreML:")): # YOLOv3 CoreML export - check_requirements('coremltools') + check_requirements("coremltools") import coremltools as ct - LOGGER.info(f'\n{prefix} starting export with coremltools {ct.__version__}...') - f = file.with_suffix('.mlmodel') + LOGGER.info(f"\n{prefix} starting export with coremltools {ct.__version__}...") + f = file.with_suffix(".mlmodel") if nms: model = iOSModel(model, im) ts = torch.jit.trace(model, im, strict=False) # TorchScript model - ct_model = ct.convert(ts, inputs=[ct.ImageType('image', shape=im.shape, scale=1 / 255, bias=[0, 0, 0])]) - bits, mode = (8, 'kmeans_lut') if int8 else (16, 'linear') if half else (32, None) + ct_model = ct.convert(ts, inputs=[ct.ImageType("image", shape=im.shape, scale=1 / 255, bias=[0, 0, 0])]) + bits, mode = (8, "kmeans_lut") if int8 else (16, "linear") if half else (32, None) if bits < 32: if MACOS: # quantization only supported on macOS with warnings.catch_warnings(): - warnings.filterwarnings('ignore', category=DeprecationWarning) # suppress numpy==1.20 float warning + warnings.filterwarnings("ignore", category=DeprecationWarning) # suppress numpy==1.20 float warning ct_model = ct.models.neural_network.quantization_utils.quantize_weights(ct_model, bits, mode) else: - print(f'{prefix} quantization only supported on macOS, skipping...') + print(f"{prefix} quantization only supported on macOS, skipping...") ct_model.save(f) return f, ct_model @try_export -def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose=False, prefix=colorstr('TensorRT:')): +def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose=False, prefix=colorstr("TensorRT:")): # YOLOv3 TensorRT export https://developer.nvidia.com/tensorrt - assert im.device.type != 'cpu', 'export running on CPU but must be on GPU, i.e. `python export.py --device 0`' + assert im.device.type != "cpu", "export running on CPU but must be on GPU, i.e. `python export.py --device 0`" try: import tensorrt as trt except Exception: - if platform.system() == 'Linux': - check_requirements('nvidia-tensorrt', cmds='-U --index-url https://pypi.ngc.nvidia.com') + if platform.system() == "Linux": + check_requirements("nvidia-tensorrt", cmds="-U --index-url https://pypi.ngc.nvidia.com") import tensorrt as trt - if trt.__version__[0] == '7': # TensorRT 7 handling https://github.com/ultralytics/yolov5/issues/6012 + if trt.__version__[0] == "7": # TensorRT 7 handling https://github.com/ultralytics/yolov5/issues/6012 grid = model.model[-1].anchor_grid model.model[-1].anchor_grid = [a[..., :1, :1, :] for a in grid] export_onnx(model, im, file, 12, dynamic, simplify) # opset 12 model.model[-1].anchor_grid = grid else: # TensorRT >= 8 - check_version(trt.__version__, '8.0.0', hard=True) # require tensorrt>=8.0.0 + check_version(trt.__version__, "8.0.0", hard=True) # require tensorrt>=8.0.0 export_onnx(model, im, file, 12, dynamic, simplify) # opset 12 - onnx = file.with_suffix('.onnx') + onnx = file.with_suffix(".onnx") - LOGGER.info(f'\n{prefix} starting export with TensorRT {trt.__version__}...') - assert onnx.exists(), f'failed to export ONNX file: {onnx}' - f = file.with_suffix('.engine') # TensorRT engine file + LOGGER.info(f"\n{prefix} starting export with TensorRT {trt.__version__}...") + assert onnx.exists(), f"failed to export ONNX file: {onnx}" + f = file.with_suffix(".engine") # TensorRT engine file logger = trt.Logger(trt.Logger.INFO) if verbose: logger.min_severity = trt.Logger.Severity.VERBOSE @@ -344,11 +356,11 @@ def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose config.max_workspace_size = workspace * 1 << 30 # config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, workspace << 30) # fix TRT 8.4 deprecation notice - flag = (1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)) + flag = 1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH) network = builder.create_network(flag) parser = trt.OnnxParser(network, logger) if not parser.parse_from_file(str(onnx)): - raise RuntimeError(f'failed to load ONNX file: {onnx}') + raise RuntimeError(f"failed to load ONNX file: {onnx}") inputs = [network.get_input(i) for i in range(network.num_inputs)] outputs = [network.get_output(i) for i in range(network.num_outputs)] @@ -359,33 +371,35 @@ def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose if dynamic: if im.shape[0] <= 1: - LOGGER.warning(f'{prefix} WARNING ⚠️ --dynamic model requires maximum --batch-size argument') + LOGGER.warning(f"{prefix} WARNING ⚠️ --dynamic model requires maximum --batch-size argument") profile = builder.create_optimization_profile() for inp in inputs: profile.set_shape(inp.name, (1, *im.shape[1:]), (max(1, im.shape[0] // 2), *im.shape[1:]), im.shape) config.add_optimization_profile(profile) - LOGGER.info(f'{prefix} building FP{16 if builder.platform_has_fast_fp16 and half else 32} engine as {f}') + LOGGER.info(f"{prefix} building FP{16 if builder.platform_has_fast_fp16 and half else 32} engine as {f}") if builder.platform_has_fast_fp16 and half: config.set_flag(trt.BuilderFlag.FP16) - with builder.build_engine(network, config) as engine, open(f, 'wb') as t: + with builder.build_engine(network, config) as engine, open(f, "wb") as t: t.write(engine.serialize()) return f, None @try_export -def export_saved_model(model, - im, - file, - dynamic, - tf_nms=False, - agnostic_nms=False, - topk_per_class=100, - topk_all=100, - iou_thres=0.45, - conf_thres=0.25, - keras=False, - prefix=colorstr('TensorFlow SavedModel:')): +def export_saved_model( + model, + im, + file, + dynamic, + tf_nms=False, + agnostic_nms=False, + topk_per_class=100, + topk_all=100, + iou_thres=0.45, + conf_thres=0.25, + keras=False, + prefix=colorstr("TensorFlow SavedModel:"), +): # YOLOv3 TensorFlow SavedModel export try: import tensorflow as tf @@ -396,8 +410,8 @@ def export_saved_model(model, from models.tf import TFModel - LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') - f = str(file).replace('.pt', '_saved_model') + LOGGER.info(f"\n{prefix} starting export with tensorflow {tf.__version__}...") + f = str(file).replace(".pt", "_saved_model") batch_size, ch, *imgsz = list(im.shape) # BCHW tf_model = TFModel(cfg=model.yaml, model=model, nc=model.nc, imgsz=imgsz) @@ -409,7 +423,7 @@ def export_saved_model(model, keras_model.trainable = False keras_model.summary() if keras: - keras_model.save(f, save_format='tf') + keras_model.save(f, save_format="tf") else: spec = tf.TensorSpec(keras_model.inputs[0].shape, keras_model.inputs[0].dtype) m = tf.function(lambda x: keras_model(x)) # full model @@ -418,21 +432,24 @@ def export_saved_model(model, tfm = tf.Module() tfm.__call__ = tf.function(lambda x: frozen_func(x)[:4] if tf_nms else frozen_func(x), [spec]) tfm.__call__(im) - tf.saved_model.save(tfm, - f, - options=tf.saved_model.SaveOptions(experimental_custom_gradients=False) if check_version( - tf.__version__, '2.6') else tf.saved_model.SaveOptions()) + tf.saved_model.save( + tfm, + f, + options=tf.saved_model.SaveOptions(experimental_custom_gradients=False) + if check_version(tf.__version__, "2.6") + else tf.saved_model.SaveOptions(), + ) return f, keras_model @try_export -def export_pb(keras_model, file, prefix=colorstr('TensorFlow GraphDef:')): +def export_pb(keras_model, file, prefix=colorstr("TensorFlow GraphDef:")): # YOLOv3 TensorFlow GraphDef *.pb export https://github.com/leimao/Frozen_Graph_TensorFlow import tensorflow as tf from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2 - LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') - f = file.with_suffix('.pb') + LOGGER.info(f"\n{prefix} starting export with tensorflow {tf.__version__}...") + f = file.with_suffix(".pb") m = tf.function(lambda x: keras_model(x)) # full model m = m.get_concrete_function(tf.TensorSpec(keras_model.inputs[0].shape, keras_model.inputs[0].dtype)) @@ -443,13 +460,13 @@ def export_pb(keras_model, file, prefix=colorstr('TensorFlow GraphDef:')): @try_export -def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=colorstr('TensorFlow Lite:')): +def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=colorstr("TensorFlow Lite:")): # YOLOv3 TensorFlow Lite export import tensorflow as tf - LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') + LOGGER.info(f"\n{prefix} starting export with tensorflow {tf.__version__}...") batch_size, ch, *imgsz = list(im.shape) # BCHW - f = str(file).replace('.pt', '-fp16.tflite') + f = str(file).replace(".pt", "-fp16.tflite") converter = tf.lite.TFLiteConverter.from_keras_model(keras_model) converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS] @@ -457,84 +474,95 @@ def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=c converter.optimizations = [tf.lite.Optimize.DEFAULT] if int8: from models.tf import representative_dataset_gen - dataset = LoadImages(check_dataset(check_yaml(data))['train'], img_size=imgsz, auto=False) + + dataset = LoadImages(check_dataset(check_yaml(data))["train"], img_size=imgsz, auto=False) converter.representative_dataset = lambda: representative_dataset_gen(dataset, ncalib=100) converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] converter.target_spec.supported_types = [] converter.inference_input_type = tf.uint8 # or tf.int8 converter.inference_output_type = tf.uint8 # or tf.int8 converter.experimental_new_quantizer = True - f = str(file).replace('.pt', '-int8.tflite') + f = str(file).replace(".pt", "-int8.tflite") if nms or agnostic_nms: converter.target_spec.supported_ops.append(tf.lite.OpsSet.SELECT_TF_OPS) tflite_model = converter.convert() - open(f, 'wb').write(tflite_model) + open(f, "wb").write(tflite_model) return f, None @try_export -def export_edgetpu(file, prefix=colorstr('Edge TPU:')): +def export_edgetpu(file, prefix=colorstr("Edge TPU:")): # YOLOv3 Edge TPU export https://coral.ai/docs/edgetpu/models-intro/ - cmd = 'edgetpu_compiler --version' - help_url = 'https://coral.ai/docs/edgetpu/compiler/' - assert platform.system() == 'Linux', f'export only supported on Linux. See {help_url}' - if subprocess.run(f'{cmd} > /dev/null 2>&1', shell=True).returncode != 0: - LOGGER.info(f'\n{prefix} export requires Edge TPU compiler. Attempting install from {help_url}') - sudo = subprocess.run('sudo --version >/dev/null', shell=True).returncode == 0 # sudo installed on system + cmd = "edgetpu_compiler --version" + help_url = "https://coral.ai/docs/edgetpu/compiler/" + assert platform.system() == "Linux", f"export only supported on Linux. See {help_url}" + if subprocess.run(f"{cmd} > /dev/null 2>&1", shell=True).returncode != 0: + LOGGER.info(f"\n{prefix} export requires Edge TPU compiler. Attempting install from {help_url}") + sudo = subprocess.run("sudo --version >/dev/null", shell=True).returncode == 0 # sudo installed on system for c in ( - 'curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -', - 'echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list', - 'sudo apt-get update', 'sudo apt-get install edgetpu-compiler'): - subprocess.run(c if sudo else c.replace('sudo ', ''), shell=True, check=True) + "curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -", + 'echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list', + "sudo apt-get update", + "sudo apt-get install edgetpu-compiler", + ): + subprocess.run(c if sudo else c.replace("sudo ", ""), shell=True, check=True) ver = subprocess.run(cmd, shell=True, capture_output=True, check=True).stdout.decode().split()[-1] - LOGGER.info(f'\n{prefix} starting export with Edge TPU compiler {ver}...') - f = str(file).replace('.pt', '-int8_edgetpu.tflite') # Edge TPU model - f_tfl = str(file).replace('.pt', '-int8.tflite') # TFLite model - - subprocess.run([ - 'edgetpu_compiler', - '-s', - '-d', - '-k', - '10', - '--out_dir', - str(file.parent), - f_tfl, ], check=True) + LOGGER.info(f"\n{prefix} starting export with Edge TPU compiler {ver}...") + f = str(file).replace(".pt", "-int8_edgetpu.tflite") # Edge TPU model + f_tfl = str(file).replace(".pt", "-int8.tflite") # TFLite model + + subprocess.run( + [ + "edgetpu_compiler", + "-s", + "-d", + "-k", + "10", + "--out_dir", + str(file.parent), + f_tfl, + ], + check=True, + ) return f, None @try_export -def export_tfjs(file, int8, prefix=colorstr('TensorFlow.js:')): +def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): # YOLOv3 TensorFlow.js export - check_requirements('tensorflowjs') + check_requirements("tensorflowjs") import tensorflowjs as tfjs - LOGGER.info(f'\n{prefix} starting export with tensorflowjs {tfjs.__version__}...') - f = str(file).replace('.pt', '_web_model') # js dir - f_pb = file.with_suffix('.pb') # *.pb path - f_json = f'{f}/model.json' # *.json path + LOGGER.info(f"\n{prefix} starting export with tensorflowjs {tfjs.__version__}...") + f = str(file).replace(".pt", "_web_model") # js dir + f_pb = file.with_suffix(".pb") # *.pb path + f_json = f"{f}/model.json" # *.json path args = [ - 'tensorflowjs_converter', - '--input_format=tf_frozen_model', - '--quantize_uint8' if int8 else '', - '--output_node_names=Identity,Identity_1,Identity_2,Identity_3', + "tensorflowjs_converter", + "--input_format=tf_frozen_model", + "--quantize_uint8" if int8 else "", + "--output_node_names=Identity,Identity_1,Identity_2,Identity_3", str(f_pb), - str(f), ] + str(f), + ] subprocess.run([arg for arg in args if arg], check=True) json = Path(f_json).read_text() - with open(f_json, 'w') as j: # sort JSON Identity_* in ascending order + with open(f_json, "w") as j: # sort JSON Identity_* in ascending order subst = re.sub( r'{"outputs": {"Identity.?.?": {"name": "Identity.?.?"}, ' r'"Identity.?.?": {"name": "Identity.?.?"}, ' r'"Identity.?.?": {"name": "Identity.?.?"}, ' - r'"Identity.?.?": {"name": "Identity.?.?"}}}', r'{"outputs": {"Identity": {"name": "Identity"}, ' + r'"Identity.?.?": {"name": "Identity.?.?"}}}', + r'{"outputs": {"Identity": {"name": "Identity"}, ' r'"Identity_1": {"name": "Identity_1"}, ' r'"Identity_2": {"name": "Identity_2"}, ' - r'"Identity_3": {"name": "Identity_3"}}}', json) + r'"Identity_3": {"name": "Identity_3"}}}', + json, + ) j.write(subst) return f, None @@ -547,8 +575,8 @@ def add_tflite_metadata(file, metadata, num_outputs): from tflite_support import metadata as _metadata from tflite_support import metadata_schema_py_generated as _metadata_fb - tmp_file = Path('/tmp/meta.txt') - with open(tmp_file, 'w') as meta_f: + tmp_file = Path("/tmp/meta.txt") + with open(tmp_file, "w") as meta_f: meta_f.write(str(metadata)) model_meta = _metadata_fb.ModelMetadataT() @@ -572,22 +600,22 @@ def add_tflite_metadata(file, metadata, num_outputs): tmp_file.unlink() -def pipeline_coreml(model, im, file, names, y, prefix=colorstr('CoreML Pipeline:')): +def pipeline_coreml(model, im, file, names, y, prefix=colorstr("CoreML Pipeline:")): # YOLOv3 CoreML pipeline import coremltools as ct from PIL import Image - print(f'{prefix} starting pipeline with coremltools {ct.__version__}...') + print(f"{prefix} starting pipeline with coremltools {ct.__version__}...") batch_size, ch, h, w = list(im.shape) # BCHW t = time.time() # YOLOv3 Output shapes spec = model.get_spec() out0, out1 = iter(spec.description.output) - if platform.system() == 'Darwin': - img = Image.new('RGB', (w, h)) # img(192 width, 320 height) + if platform.system() == "Darwin": + img = Image.new("RGB", (w, h)) # img(192 width, 320 height) # img = torch.zeros((*opt.img_size, 3)).numpy() # img size(320,192,3) iDetection - out = model.predict({'image': img}) + out = model.predict({"image": img}) out0_shape, out1_shape = out[out0.name].shape, out[out1.name].shape else: # linux and windows can not run model.predict(), get sizes from pytorch output y s = tuple(y[0].shape) @@ -597,7 +625,7 @@ def pipeline_coreml(model, im, file, names, y, prefix=colorstr('CoreML Pipeline: nx, ny = spec.description.input[0].type.imageType.width, spec.description.input[0].type.imageType.height na, nc = out0_shape # na, nc = out0.type.multiArrayType.shape # number anchors, classes - assert len(names) == nc, f'{len(names)} names found for nc={nc}' # check + assert len(names) == nc, f"{len(names)} names found for nc={nc}" # check # Define output shapes (missing) out0.type.multiArrayType.shape[:] = out0_shape # (3780, 80) @@ -631,8 +659,8 @@ def pipeline_coreml(model, im, file, names, y, prefix=colorstr('CoreML Pipeline: nms_spec.description.output.add() nms_spec.description.output[i].ParseFromString(decoder_output) - nms_spec.description.output[0].name = 'confidence' - nms_spec.description.output[1].name = 'coordinates' + nms_spec.description.output[0].name = "confidence" + nms_spec.description.output[1].name = "coordinates" output_sizes = [nc, 4] for i in range(2): @@ -648,10 +676,10 @@ def pipeline_coreml(model, im, file, names, y, prefix=colorstr('CoreML Pipeline: nms = nms_spec.nonMaximumSuppression nms.confidenceInputFeatureName = out0.name # 1x507x80 nms.coordinatesInputFeatureName = out1.name # 1x507x4 - nms.confidenceOutputFeatureName = 'confidence' - nms.coordinatesOutputFeatureName = 'coordinates' - nms.iouThresholdInputFeatureName = 'iouThreshold' - nms.confidenceThresholdInputFeatureName = 'confidenceThreshold' + nms.confidenceOutputFeatureName = "confidence" + nms.coordinatesOutputFeatureName = "coordinates" + nms.iouThresholdInputFeatureName = "iouThreshold" + nms.confidenceThresholdInputFeatureName = "confidenceThreshold" nms.iouThreshold = 0.45 nms.confidenceThreshold = 0.25 nms.pickTop.perClass = True @@ -659,10 +687,14 @@ def pipeline_coreml(model, im, file, names, y, prefix=colorstr('CoreML Pipeline: nms_model = ct.models.MLModel(nms_spec) # 4. Pipeline models together - pipeline = ct.models.pipeline.Pipeline(input_features=[('image', ct.models.datatypes.Array(3, ny, nx)), - ('iouThreshold', ct.models.datatypes.Double()), - ('confidenceThreshold', ct.models.datatypes.Double())], - output_features=['confidence', 'coordinates']) + pipeline = ct.models.pipeline.Pipeline( + input_features=[ + ("image", ct.models.datatypes.Array(3, ny, nx)), + ("iouThreshold", ct.models.datatypes.Double()), + ("confidenceThreshold", ct.models.datatypes.Double()), + ], + output_features=["confidence", "coordinates"], + ) pipeline.add_model(model) pipeline.add_model(nms_model) @@ -673,72 +705,76 @@ def pipeline_coreml(model, im, file, names, y, prefix=colorstr('CoreML Pipeline: # Update metadata pipeline.spec.specificationVersion = 5 - pipeline.spec.description.metadata.versionString = 'https://github.com/ultralytics/yolov5' - pipeline.spec.description.metadata.shortDescription = 'https://github.com/ultralytics/yolov5' - pipeline.spec.description.metadata.author = 'glenn.jocher@ultralytics.com' - pipeline.spec.description.metadata.license = 'https://github.com/ultralytics/yolov5/blob/master/LICENSE' - pipeline.spec.description.metadata.userDefined.update({ - 'classes': ','.join(names.values()), - 'iou_threshold': str(nms.iouThreshold), - 'confidence_threshold': str(nms.confidenceThreshold)}) + pipeline.spec.description.metadata.versionString = "https://github.com/ultralytics/yolov5" + pipeline.spec.description.metadata.shortDescription = "https://github.com/ultralytics/yolov5" + pipeline.spec.description.metadata.author = "glenn.jocher@ultralytics.com" + pipeline.spec.description.metadata.license = "https://github.com/ultralytics/yolov5/blob/master/LICENSE" + pipeline.spec.description.metadata.userDefined.update( + { + "classes": ",".join(names.values()), + "iou_threshold": str(nms.iouThreshold), + "confidence_threshold": str(nms.confidenceThreshold), + } + ) # Save the model - f = file.with_suffix('.mlmodel') # filename + f = file.with_suffix(".mlmodel") # filename model = ct.models.MLModel(pipeline.spec) - model.input_description['image'] = 'Input image' - model.input_description['iouThreshold'] = f'(optional) IOU Threshold override (default: {nms.iouThreshold})' - model.input_description['confidenceThreshold'] = \ - f'(optional) Confidence Threshold override (default: {nms.confidenceThreshold})' - model.output_description['confidence'] = 'Boxes × Class confidence (see user-defined metadata "classes")' - model.output_description['coordinates'] = 'Boxes × [x, y, width, height] (relative to image size)' + model.input_description["image"] = "Input image" + model.input_description["iouThreshold"] = f"(optional) IOU Threshold override (default: {nms.iouThreshold})" + model.input_description[ + "confidenceThreshold" + ] = f"(optional) Confidence Threshold override (default: {nms.confidenceThreshold})" + model.output_description["confidence"] = 'Boxes × Class confidence (see user-defined metadata "classes")' + model.output_description["coordinates"] = "Boxes × [x, y, width, height] (relative to image size)" model.save(f) # pipelined - print(f'{prefix} pipeline success ({time.time() - t:.2f}s), saved as {f} ({file_size(f):.1f} MB)') + print(f"{prefix} pipeline success ({time.time() - t:.2f}s), saved as {f} ({file_size(f):.1f} MB)") @smart_inference_mode() def run( - data=ROOT / 'data/coco128.yaml', # 'dataset.yaml path' - weights=ROOT / 'yolov5s.pt', # weights path - imgsz=(640, 640), # image (height, width) - batch_size=1, # batch size - device='cpu', # cuda device, i.e. 0 or 0,1,2,3 or cpu - include=('torchscript', 'onnx'), # include formats - half=False, # FP16 half-precision export - inplace=False, # set YOLOv3 Detect() inplace=True - keras=False, # use Keras - optimize=False, # TorchScript: optimize for mobile - int8=False, # CoreML/TF INT8 quantization - dynamic=False, # ONNX/TF/TensorRT: dynamic axes - simplify=False, # ONNX: simplify model - opset=12, # ONNX: opset version - verbose=False, # TensorRT: verbose log - workspace=4, # TensorRT: workspace size (GB) - nms=False, # TF: add NMS to model - agnostic_nms=False, # TF: add agnostic NMS to model - topk_per_class=100, # TF.js NMS: topk per class to keep - topk_all=100, # TF.js NMS: topk for all classes to keep - iou_thres=0.45, # TF.js NMS: IoU threshold - conf_thres=0.25, # TF.js NMS: confidence threshold + data=ROOT / "data/coco128.yaml", # 'dataset.yaml path' + weights=ROOT / "yolov5s.pt", # weights path + imgsz=(640, 640), # image (height, width) + batch_size=1, # batch size + device="cpu", # cuda device, i.e. 0 or 0,1,2,3 or cpu + include=("torchscript", "onnx"), # include formats + half=False, # FP16 half-precision export + inplace=False, # set YOLOv3 Detect() inplace=True + keras=False, # use Keras + optimize=False, # TorchScript: optimize for mobile + int8=False, # CoreML/TF INT8 quantization + dynamic=False, # ONNX/TF/TensorRT: dynamic axes + simplify=False, # ONNX: simplify model + opset=12, # ONNX: opset version + verbose=False, # TensorRT: verbose log + workspace=4, # TensorRT: workspace size (GB) + nms=False, # TF: add NMS to model + agnostic_nms=False, # TF: add agnostic NMS to model + topk_per_class=100, # TF.js NMS: topk per class to keep + topk_all=100, # TF.js NMS: topk for all classes to keep + iou_thres=0.45, # TF.js NMS: IoU threshold + conf_thres=0.25, # TF.js NMS: confidence threshold ): t = time.time() include = [x.lower() for x in include] # to lowercase - fmts = tuple(export_formats()['Argument'][1:]) # --include arguments + fmts = tuple(export_formats()["Argument"][1:]) # --include arguments flags = [x in include for x in fmts] - assert sum(flags) == len(include), f'ERROR: Invalid --include {include}, valid --include arguments are {fmts}' + assert sum(flags) == len(include), f"ERROR: Invalid --include {include}, valid --include arguments are {fmts}" jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle = flags # export booleans - file = Path(url2file(weights) if str(weights).startswith(('http:/', 'https:/')) else weights) # PyTorch weights + file = Path(url2file(weights) if str(weights).startswith(("http:/", "https:/")) else weights) # PyTorch weights # Load PyTorch model device = select_device(device) if half: - assert device.type != 'cpu' or coreml, '--half only compatible with GPU export, i.e. use --device 0' - assert not dynamic, '--half not compatible with --dynamic, i.e. use either --half or --dynamic but not both' + assert device.type != "cpu" or coreml, "--half only compatible with GPU export, i.e. use --device 0" + assert not dynamic, "--half not compatible with --dynamic, i.e. use either --half or --dynamic but not both" model = attempt_load(weights, device=device, inplace=True, fuse=True) # load FP32 model # Checks imgsz *= 2 if len(imgsz) == 1 else 1 # expand if optimize: - assert device.type == 'cpu', '--optimize not compatible with cuda devices, i.e. use --device cpu' + assert device.type == "cpu", "--optimize not compatible with cuda devices, i.e. use --device cpu" # Input gs = int(max(model.stride)) # grid size (max stride) @@ -758,12 +794,12 @@ def run( if half and not coreml: im, model = im.half(), model.half() # to FP16 shape = tuple((y[0] if isinstance(y, tuple) else y).shape) # model output shape - metadata = {'stride': int(max(model.stride)), 'names': model.names} # model metadata + metadata = {"stride": int(max(model.stride)), "names": model.names} # model metadata LOGGER.info(f"\n{colorstr('PyTorch:')} starting from {file} with output shape {shape} ({file_size(file):.1f} MB)") # Exports - f = [''] * len(fmts) # exported filenames - warnings.filterwarnings(action='ignore', category=torch.jit.TracerWarning) # suppress TracerWarning + f = [""] * len(fmts) # exported filenames + warnings.filterwarnings(action="ignore", category=torch.jit.TracerWarning) # suppress TracerWarning if jit: # TorchScript f[0], _ = export_torchscript(model, im, file, optimize) if engine: # TensorRT required before ONNX @@ -777,19 +813,21 @@ def run( if nms: pipeline_coreml(ct_model, im, file, model.names, y) if any((saved_model, pb, tflite, edgetpu, tfjs)): # TensorFlow formats - assert not tflite or not tfjs, 'TFLite and TF.js models must be exported separately, please pass only one type.' - assert not isinstance(model, ClassificationModel), 'ClassificationModel export to TF formats not yet supported.' - f[5], s_model = export_saved_model(model.cpu(), - im, - file, - dynamic, - tf_nms=nms or agnostic_nms or tfjs, - agnostic_nms=agnostic_nms or tfjs, - topk_per_class=topk_per_class, - topk_all=topk_all, - iou_thres=iou_thres, - conf_thres=conf_thres, - keras=keras) + assert not tflite or not tfjs, "TFLite and TF.js models must be exported separately, please pass only one type." + assert not isinstance(model, ClassificationModel), "ClassificationModel export to TF formats not yet supported." + f[5], s_model = export_saved_model( + model.cpu(), + im, + file, + dynamic, + tf_nms=nms or agnostic_nms or tfjs, + agnostic_nms=agnostic_nms or tfjs, + topk_per_class=topk_per_class, + topk_all=topk_all, + iou_thres=iou_thres, + conf_thres=conf_thres, + keras=keras, + ) if pb or tfjs: # pb prerequisite to tfjs f[6], _ = export_pb(s_model, file) if tflite or edgetpu: @@ -807,57 +845,65 @@ def run( if any(f): cls, det, seg = (isinstance(model, x) for x in (ClassificationModel, DetectionModel, SegmentationModel)) # type det &= not seg # segmentation models inherit from SegmentationModel(DetectionModel) - dir = Path('segment' if seg else 'classify' if cls else '') - h = '--half' if half else '' # --half FP16 inference arg - s = '# WARNING ⚠️ ClassificationModel not yet supported for PyTorch Hub AutoShape inference' if cls else \ - '# WARNING ⚠️ SegmentationModel not yet supported for PyTorch Hub AutoShape inference' if seg else '' - LOGGER.info(f'\nExport complete ({time.time() - t:.1f}s)' - f"\nResults saved to {colorstr('bold', file.parent.resolve())}" - f"\nDetect: python {dir / ('detect.py' if det else 'predict.py')} --weights {f[-1]} {h}" - f"\nValidate: python {dir / 'val.py'} --weights {f[-1]} {h}" - f"\nPyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', '{f[-1]}') {s}" - f'\nVisualize: https://netron.app') + dir = Path("segment" if seg else "classify" if cls else "") + h = "--half" if half else "" # --half FP16 inference arg + s = ( + "# WARNING ⚠️ ClassificationModel not yet supported for PyTorch Hub AutoShape inference" + if cls + else "# WARNING ⚠️ SegmentationModel not yet supported for PyTorch Hub AutoShape inference" + if seg + else "" + ) + LOGGER.info( + f'\nExport complete ({time.time() - t:.1f}s)' + f"\nResults saved to {colorstr('bold', file.parent.resolve())}" + f"\nDetect: python {dir / ('detect.py' if det else 'predict.py')} --weights {f[-1]} {h}" + f"\nValidate: python {dir / 'val.py'} --weights {f[-1]} {h}" + f"\nPyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', '{f[-1]}') {s}" + f'\nVisualize: https://netron.app' + ) return f # return list of exported files/dirs def parse_opt(known=False): parser = argparse.ArgumentParser() - parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') - parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov3-tiny.pt', help='model.pt path(s)') - parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640, 640], help='image (h, w)') - parser.add_argument('--batch-size', type=int, default=1, help='batch size') - parser.add_argument('--device', default='cpu', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--half', action='store_true', help='FP16 half-precision export') - parser.add_argument('--inplace', action='store_true', help='set YOLOv3 Detect() inplace=True') - parser.add_argument('--keras', action='store_true', help='TF: use Keras') - parser.add_argument('--optimize', action='store_true', help='TorchScript: optimize for mobile') - parser.add_argument('--int8', action='store_true', help='CoreML/TF/OpenVINO INT8 quantization') - parser.add_argument('--dynamic', action='store_true', help='ONNX/TF/TensorRT: dynamic axes') - parser.add_argument('--simplify', action='store_true', help='ONNX: simplify model') - parser.add_argument('--opset', type=int, default=17, help='ONNX: opset version') - parser.add_argument('--verbose', action='store_true', help='TensorRT: verbose log') - parser.add_argument('--workspace', type=int, default=4, help='TensorRT: workspace size (GB)') - parser.add_argument('--nms', action='store_true', help='TF: add NMS to model') - parser.add_argument('--agnostic-nms', action='store_true', help='TF: add agnostic NMS to model') - parser.add_argument('--topk-per-class', type=int, default=100, help='TF.js NMS: topk per class to keep') - parser.add_argument('--topk-all', type=int, default=100, help='TF.js NMS: topk for all classes to keep') - parser.add_argument('--iou-thres', type=float, default=0.45, help='TF.js NMS: IoU threshold') - parser.add_argument('--conf-thres', type=float, default=0.25, help='TF.js NMS: confidence threshold') + parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="dataset.yaml path") + parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov3-tiny.pt", help="model.pt path(s)") + parser.add_argument("--imgsz", "--img", "--img-size", nargs="+", type=int, default=[640, 640], help="image (h, w)") + parser.add_argument("--batch-size", type=int, default=1, help="batch size") + parser.add_argument("--device", default="cpu", help="cuda device, i.e. 0 or 0,1,2,3 or cpu") + parser.add_argument("--half", action="store_true", help="FP16 half-precision export") + parser.add_argument("--inplace", action="store_true", help="set YOLOv3 Detect() inplace=True") + parser.add_argument("--keras", action="store_true", help="TF: use Keras") + parser.add_argument("--optimize", action="store_true", help="TorchScript: optimize for mobile") + parser.add_argument("--int8", action="store_true", help="CoreML/TF/OpenVINO INT8 quantization") + parser.add_argument("--dynamic", action="store_true", help="ONNX/TF/TensorRT: dynamic axes") + parser.add_argument("--simplify", action="store_true", help="ONNX: simplify model") + parser.add_argument("--opset", type=int, default=17, help="ONNX: opset version") + parser.add_argument("--verbose", action="store_true", help="TensorRT: verbose log") + parser.add_argument("--workspace", type=int, default=4, help="TensorRT: workspace size (GB)") + parser.add_argument("--nms", action="store_true", help="TF: add NMS to model") + parser.add_argument("--agnostic-nms", action="store_true", help="TF: add agnostic NMS to model") + parser.add_argument("--topk-per-class", type=int, default=100, help="TF.js NMS: topk per class to keep") + parser.add_argument("--topk-all", type=int, default=100, help="TF.js NMS: topk for all classes to keep") + parser.add_argument("--iou-thres", type=float, default=0.45, help="TF.js NMS: IoU threshold") + parser.add_argument("--conf-thres", type=float, default=0.25, help="TF.js NMS: confidence threshold") parser.add_argument( - '--include', - nargs='+', - default=['torchscript'], - help='torchscript, onnx, openvino, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle') + "--include", + nargs="+", + default=["torchscript"], + help="torchscript, onnx, openvino, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle", + ) opt = parser.parse_known_args()[0] if known else parser.parse_args() print_args(vars(opt)) return opt def main(opt): - for opt.weights in (opt.weights if isinstance(opt.weights, list) else [opt.weights]): + for opt.weights in opt.weights if isinstance(opt.weights, list) else [opt.weights]: run(**vars(opt)) -if __name__ == '__main__': +if __name__ == "__main__": opt = parse_opt() main(opt) diff --git a/hubconf.py b/hubconf.py index 89fa522200..729eed0600 100644 --- a/hubconf.py +++ b/hubconf.py @@ -14,7 +14,8 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): - """Creates or loads a YOLOv3 model + """ + Creates or loads a YOLOv3 model. Arguments: name (str): model name 'yolov5s' or path 'path/to/best.pt' @@ -39,9 +40,9 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbo if not verbose: LOGGER.setLevel(logging.WARNING) - check_requirements(ROOT / 'requirements.txt', exclude=('opencv-python', 'tensorboard', 'thop')) + check_requirements(ROOT / "requirements.txt", exclude=("opencv-python", "tensorboard", "thop")) name = Path(name) - path = name.with_suffix('.pt') if name.suffix == '' and not name.is_dir() else name # checkpoint path + path = name.with_suffix(".pt") if name.suffix == "" and not name.is_dir() else name # checkpoint path try: device = select_device(device) if pretrained and channels == 3 and classes == 80: @@ -49,91 +50,95 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbo model = DetectMultiBackend(path, device=device, fuse=autoshape) # detection model if autoshape: if model.pt and isinstance(model.model, ClassificationModel): - LOGGER.warning('WARNING ⚠️ YOLOv3 ClassificationModel is not yet AutoShape compatible. ' - 'You must pass torch tensors in BCHW to this model, i.e. shape(1,3,224,224).') + LOGGER.warning( + "WARNING ⚠️ YOLOv3 ClassificationModel is not yet AutoShape compatible. " + "You must pass torch tensors in BCHW to this model, i.e. shape(1,3,224,224)." + ) elif model.pt and isinstance(model.model, SegmentationModel): - LOGGER.warning('WARNING ⚠️ YOLOv3 SegmentationModel is not yet AutoShape compatible. ' - 'You will not be able to run inference with this model.') + LOGGER.warning( + "WARNING ⚠️ YOLOv3 SegmentationModel is not yet AutoShape compatible. " + "You will not be able to run inference with this model." + ) else: model = AutoShape(model) # for file/URI/PIL/cv2/np inputs and NMS except Exception: model = attempt_load(path, device=device, fuse=False) # arbitrary model else: - cfg = list((Path(__file__).parent / 'models').rglob(f'{path.stem}.yaml'))[0] # model.yaml path + cfg = list((Path(__file__).parent / "models").rglob(f"{path.stem}.yaml"))[0] # model.yaml path model = DetectionModel(cfg, channels, classes) # create model if pretrained: ckpt = torch.load(attempt_download(path), map_location=device) # load - csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 - csd = intersect_dicts(csd, model.state_dict(), exclude=['anchors']) # intersect + csd = ckpt["model"].float().state_dict() # checkpoint state_dict as FP32 + csd = intersect_dicts(csd, model.state_dict(), exclude=["anchors"]) # intersect model.load_state_dict(csd, strict=False) # load - if len(ckpt['model'].names) == classes: - model.names = ckpt['model'].names # set class names attribute + if len(ckpt["model"].names) == classes: + model.names = ckpt["model"].names # set class names attribute if not verbose: LOGGER.setLevel(logging.INFO) # reset to default return model.to(device) except Exception as e: - help_url = 'https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading' - s = f'{e}. Cache may be out of date, try `force_reload=True` or see {help_url} for help.' + help_url = "https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading" + s = f"{e}. Cache may be out of date, try `force_reload=True` or see {help_url} for help." raise Exception(s) from e -def custom(path='path/to/model.pt', autoshape=True, _verbose=True, device=None): +def custom(path="path/to/model.pt", autoshape=True, _verbose=True, device=None): # YOLOv3 custom or local model return _create(path, autoshape=autoshape, verbose=_verbose, device=device) def yolov5n(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): # YOLOv3-nano model https://github.com/ultralytics/yolov5 - return _create('yolov5n', pretrained, channels, classes, autoshape, _verbose, device) + return _create("yolov5n", pretrained, channels, classes, autoshape, _verbose, device) def yolov5s(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): # YOLOv3-small model https://github.com/ultralytics/yolov5 - return _create('yolov5s', pretrained, channels, classes, autoshape, _verbose, device) + return _create("yolov5s", pretrained, channels, classes, autoshape, _verbose, device) def yolov5m(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): # YOLOv3-medium model https://github.com/ultralytics/yolov5 - return _create('yolov5m', pretrained, channels, classes, autoshape, _verbose, device) + return _create("yolov5m", pretrained, channels, classes, autoshape, _verbose, device) def yolov5l(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): # YOLOv3-large model https://github.com/ultralytics/yolov5 - return _create('yolov5l', pretrained, channels, classes, autoshape, _verbose, device) + return _create("yolov5l", pretrained, channels, classes, autoshape, _verbose, device) def yolov5x(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): # YOLOv3-xlarge model https://github.com/ultralytics/yolov5 - return _create('yolov5x', pretrained, channels, classes, autoshape, _verbose, device) + return _create("yolov5x", pretrained, channels, classes, autoshape, _verbose, device) def yolov5n6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): # YOLOv3-nano-P6 model https://github.com/ultralytics/yolov5 - return _create('yolov5n6', pretrained, channels, classes, autoshape, _verbose, device) + return _create("yolov5n6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5s6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): # YOLOv3-small-P6 model https://github.com/ultralytics/yolov5 - return _create('yolov5s6', pretrained, channels, classes, autoshape, _verbose, device) + return _create("yolov5s6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5m6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): # YOLOv3-medium-P6 model https://github.com/ultralytics/yolov5 - return _create('yolov5m6', pretrained, channels, classes, autoshape, _verbose, device) + return _create("yolov5m6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5l6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): # YOLOv3-large-P6 model https://github.com/ultralytics/yolov5 - return _create('yolov5l6', pretrained, channels, classes, autoshape, _verbose, device) + return _create("yolov5l6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5x6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): # YOLOv3-xlarge-P6 model https://github.com/ultralytics/yolov5 - return _create('yolov5x6', pretrained, channels, classes, autoshape, _verbose, device) + return _create("yolov5x6", pretrained, channels, classes, autoshape, _verbose, device) -if __name__ == '__main__': +if __name__ == "__main__": import argparse from pathlib import Path @@ -144,7 +149,7 @@ def yolov5x6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=T # Argparser parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default='yolov5s', help='model name') + parser.add_argument("--model", type=str, default="yolov5s", help="model name") opt = parser.parse_args() print_args(vars(opt)) @@ -154,12 +159,13 @@ def yolov5x6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=T # Images imgs = [ - 'data/images/zidane.jpg', # filename - Path('data/images/zidane.jpg'), # Path - 'https://ultralytics.com/images/zidane.jpg', # URI - cv2.imread('data/images/bus.jpg')[:, :, ::-1], # OpenCV - Image.open('data/images/bus.jpg'), # PIL - np.zeros((320, 640, 3))] # numpy + "data/images/zidane.jpg", # filename + Path("data/images/zidane.jpg"), # Path + "https://ultralytics.com/images/zidane.jpg", # URI + cv2.imread("data/images/bus.jpg")[:, :, ::-1], # OpenCV + Image.open("data/images/bus.jpg"), # PIL + np.zeros((320, 640, 3)), + ] # numpy # Inference results = model(imgs, size=320) # batched inference diff --git a/models/common.py b/models/common.py index 152b861f60..d45b99cfd9 100644 --- a/models/common.py +++ b/models/common.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Common modules -""" +"""Common modules.""" import ast import contextlib @@ -27,9 +25,23 @@ from utils import TryExcept from utils.dataloaders import exif_transpose, letterbox -from utils.general import (LOGGER, ROOT, Profile, check_requirements, check_suffix, check_version, colorstr, - increment_path, is_jupyter, make_divisible, non_max_suppression, scale_boxes, xywh2xyxy, - xyxy2xywh, yaml_load) +from utils.general import ( + LOGGER, + ROOT, + Profile, + check_requirements, + check_suffix, + check_version, + colorstr, + increment_path, + is_jupyter, + make_divisible, + non_max_suppression, + scale_boxes, + xywh2xyxy, + xyxy2xywh, + yaml_load, +) from utils.torch_utils import copy_attr, smart_inference_mode @@ -211,7 +223,7 @@ def __init__(self, c1, c2, k=(5, 9, 13)): def forward(self, x): x = self.cv1(x) with warnings.catch_warnings(): - warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning + warnings.simplefilter("ignore") # suppress torch 1.9.0 max_pool2d() warning return self.cv2(torch.cat([x] + [m(x) for m in self.m], 1)) @@ -227,7 +239,7 @@ def __init__(self, c1, c2, k=5): # equivalent to SPP(k=(5, 9, 13)) def forward(self, x): x = self.cv1(x) with warnings.catch_warnings(): - warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning + warnings.simplefilter("ignore") # suppress torch 1.9.0 max_pool2d() warning y1 = self.m(x) y2 = self.m(y1) return self.cv2(torch.cat((x, y1, y2, self.m(y2)), 1)) @@ -266,9 +278,11 @@ def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride self.conv = nn.Sequential( GhostConv(c1, c_, 1, 1), # pw DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw - GhostConv(c_, c2, 1, 1, act=False)) # pw-linear - self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False), Conv(c1, c2, 1, 1, - act=False)) if s == 2 else nn.Identity() + GhostConv(c_, c2, 1, 1, act=False), + ) # pw-linear + self.shortcut = ( + nn.Sequential(DWConv(c1, c1, k, s, act=False), Conv(c1, c2, 1, 1, act=False)) if s == 2 else nn.Identity() + ) def forward(self, x): return self.conv(x) + self.shortcut(x) @@ -297,9 +311,9 @@ def __init__(self, gain=2): def forward(self, x): b, c, h, w = x.size() # assert C / s ** 2 == 0, 'Indivisible gain' s = self.gain - x = x.view(b, s, s, c // s ** 2, h, w) # x(1,2,2,16,80,80) + x = x.view(b, s, s, c // s**2, h, w) # x(1,2,2,16,80,80) x = x.permute(0, 3, 4, 1, 5, 2).contiguous() # x(1,16,80,2,80,2) - return x.view(b, c // s ** 2, h * s, w * s) # x(1,16,160,160) + return x.view(b, c // s**2, h * s, w * s) # x(1,16,160,160) class Concat(nn.Module): @@ -314,7 +328,7 @@ def forward(self, x): class DetectMultiBackend(nn.Module): # YOLOv3 MultiBackend class for python inference on various backends - def __init__(self, weights='yolov5s.pt', device=torch.device('cpu'), dnn=False, data=None, fp16=False, fuse=True): + def __init__(self, weights="yolov5s.pt", device=torch.device("cpu"), dnn=False, data=None, fp16=False, fuse=True): # Usage: # PyTorch: weights = *.pt # TorchScript: *.torchscript @@ -336,65 +350,68 @@ def __init__(self, weights='yolov5s.pt', device=torch.device('cpu'), dnn=False, fp16 &= pt or jit or onnx or engine or triton # FP16 nhwc = coreml or saved_model or pb or tflite or edgetpu # BHWC formats (vs torch BCWH) stride = 32 # default stride - cuda = torch.cuda.is_available() and device.type != 'cpu' # use CUDA + cuda = torch.cuda.is_available() and device.type != "cpu" # use CUDA if not (pt or triton): w = attempt_download(w) # download if not local if pt: # PyTorch model = attempt_load(weights if isinstance(weights, list) else w, device=device, inplace=True, fuse=fuse) stride = max(int(model.stride.max()), 32) # model stride - names = model.module.names if hasattr(model, 'module') else model.names # get class names + names = model.module.names if hasattr(model, "module") else model.names # get class names model.half() if fp16 else model.float() self.model = model # explicitly assign for to(), cpu(), cuda(), half() elif jit: # TorchScript - LOGGER.info(f'Loading {w} for TorchScript inference...') - extra_files = {'config.txt': ''} # model metadata + LOGGER.info(f"Loading {w} for TorchScript inference...") + extra_files = {"config.txt": ""} # model metadata model = torch.jit.load(w, _extra_files=extra_files, map_location=device) model.half() if fp16 else model.float() - if extra_files['config.txt']: # load metadata dict - d = json.loads(extra_files['config.txt'], - object_hook=lambda d: { - int(k) if k.isdigit() else k: v - for k, v in d.items()}) - stride, names = int(d['stride']), d['names'] + if extra_files["config.txt"]: # load metadata dict + d = json.loads( + extra_files["config.txt"], + object_hook=lambda d: {int(k) if k.isdigit() else k: v for k, v in d.items()}, + ) + stride, names = int(d["stride"]), d["names"] elif dnn: # ONNX OpenCV DNN - LOGGER.info(f'Loading {w} for ONNX OpenCV DNN inference...') - check_requirements('opencv-python>=4.5.4') + LOGGER.info(f"Loading {w} for ONNX OpenCV DNN inference...") + check_requirements("opencv-python>=4.5.4") net = cv2.dnn.readNetFromONNX(w) elif onnx: # ONNX Runtime - LOGGER.info(f'Loading {w} for ONNX Runtime inference...') - check_requirements(('onnx', 'onnxruntime-gpu' if cuda else 'onnxruntime')) + LOGGER.info(f"Loading {w} for ONNX Runtime inference...") + check_requirements(("onnx", "onnxruntime-gpu" if cuda else "onnxruntime")) import onnxruntime - providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] if cuda else ['CPUExecutionProvider'] + + providers = ["CUDAExecutionProvider", "CPUExecutionProvider"] if cuda else ["CPUExecutionProvider"] session = onnxruntime.InferenceSession(w, providers=providers) output_names = [x.name for x in session.get_outputs()] meta = session.get_modelmeta().custom_metadata_map # metadata - if 'stride' in meta: - stride, names = int(meta['stride']), eval(meta['names']) + if "stride" in meta: + stride, names = int(meta["stride"]), eval(meta["names"]) elif xml: # OpenVINO - LOGGER.info(f'Loading {w} for OpenVINO inference...') - check_requirements('openvino>=2023.0') # requires openvino-dev: https://pypi.org/project/openvino-dev/ + LOGGER.info(f"Loading {w} for OpenVINO inference...") + check_requirements("openvino>=2023.0") # requires openvino-dev: https://pypi.org/project/openvino-dev/ from openvino.runtime import Core, Layout, get_batch + core = Core() if not Path(w).is_file(): # if not *.xml - w = next(Path(w).glob('*.xml')) # get *.xml file from *_openvino_model dir - ov_model = core.read_model(model=w, weights=Path(w).with_suffix('.bin')) + w = next(Path(w).glob("*.xml")) # get *.xml file from *_openvino_model dir + ov_model = core.read_model(model=w, weights=Path(w).with_suffix(".bin")) if ov_model.get_parameters()[0].get_layout().empty: - ov_model.get_parameters()[0].set_layout(Layout('NCHW')) + ov_model.get_parameters()[0].set_layout(Layout("NCHW")) batch_dim = get_batch(ov_model) if batch_dim.is_static: batch_size = batch_dim.get_length() - ov_compiled_model = core.compile_model(ov_model, device_name='AUTO') # AUTO selects best available device - stride, names = self._load_metadata(Path(w).with_suffix('.yaml')) # load metadata + ov_compiled_model = core.compile_model(ov_model, device_name="AUTO") # AUTO selects best available device + stride, names = self._load_metadata(Path(w).with_suffix(".yaml")) # load metadata elif engine: # TensorRT - LOGGER.info(f'Loading {w} for TensorRT inference...') + LOGGER.info(f"Loading {w} for TensorRT inference...") import tensorrt as trt # https://developer.nvidia.com/nvidia-tensorrt-download - check_version(trt.__version__, '7.0.0', hard=True) # require tensorrt>=7.0.0 - if device.type == 'cpu': - device = torch.device('cuda:0') - Binding = namedtuple('Binding', ('name', 'dtype', 'shape', 'data', 'ptr')) + + check_version(trt.__version__, "7.0.0", hard=True) # require tensorrt>=7.0.0 + if device.type == "cpu": + device = torch.device("cuda:0") + Binding = namedtuple("Binding", ("name", "dtype", "shape", "data", "ptr")) logger = trt.Logger(trt.Logger.INFO) - with open(w, 'rb') as f, trt.Runtime(logger) as runtime: + with open(w, "rb") as f, trt.Runtime(logger) as runtime: model = runtime.deserialize_cuda_engine(f.read()) context = model.create_execution_context() bindings = OrderedDict() @@ -416,22 +433,24 @@ def __init__(self, weights='yolov5s.pt', device=torch.device('cpu'), dnn=False, im = torch.from_numpy(np.empty(shape, dtype=dtype)).to(device) bindings[name] = Binding(name, dtype, shape, im, int(im.data_ptr())) binding_addrs = OrderedDict((n, d.ptr) for n, d in bindings.items()) - batch_size = bindings['images'].shape[0] # if dynamic, this is instead max batch size + batch_size = bindings["images"].shape[0] # if dynamic, this is instead max batch size elif coreml: # CoreML - LOGGER.info(f'Loading {w} for CoreML inference...') + LOGGER.info(f"Loading {w} for CoreML inference...") import coremltools as ct + model = ct.models.MLModel(w) elif saved_model: # TF SavedModel - LOGGER.info(f'Loading {w} for TensorFlow SavedModel inference...') + LOGGER.info(f"Loading {w} for TensorFlow SavedModel inference...") import tensorflow as tf + keras = False # assume TF1 saved_model model = tf.keras.models.load_model(w) if keras else tf.saved_model.load(w) elif pb: # GraphDef https://www.tensorflow.org/guide/migrate#a_graphpb_or_graphpbtxt - LOGGER.info(f'Loading {w} for TensorFlow GraphDef inference...') + LOGGER.info(f"Loading {w} for TensorFlow GraphDef inference...") import tensorflow as tf def wrap_frozen_graph(gd, inputs, outputs): - x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=''), []) # wrapped + x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=""), []) # wrapped ge = x.graph.as_graph_element return x.prune(tf.nest.map_structure(ge, inputs), tf.nest.map_structure(ge, outputs)) @@ -440,46 +459,50 @@ def gd_outputs(gd): for node in gd.node: # tensorflow.core.framework.node_def_pb2.NodeDef name_list.append(node.name) input_list.extend(node.input) - return sorted(f'{x}:0' for x in list(set(name_list) - set(input_list)) if not x.startswith('NoOp')) + return sorted(f"{x}:0" for x in list(set(name_list) - set(input_list)) if not x.startswith("NoOp")) gd = tf.Graph().as_graph_def() # TF GraphDef - with open(w, 'rb') as f: + with open(w, "rb") as f: gd.ParseFromString(f.read()) - frozen_func = wrap_frozen_graph(gd, inputs='x:0', outputs=gd_outputs(gd)) + frozen_func = wrap_frozen_graph(gd, inputs="x:0", outputs=gd_outputs(gd)) elif tflite or edgetpu: # https://www.tensorflow.org/lite/guide/python#install_tensorflow_lite_for_python try: # https://coral.ai/docs/edgetpu/tflite-python/#update-existing-tf-lite-code-for-the-edge-tpu from tflite_runtime.interpreter import Interpreter, load_delegate except ImportError: import tensorflow as tf - Interpreter, load_delegate = tf.lite.Interpreter, tf.lite.experimental.load_delegate, + + Interpreter, load_delegate = ( + tf.lite.Interpreter, + tf.lite.experimental.load_delegate, + ) if edgetpu: # TF Edge TPU https://coral.ai/software/#edgetpu-runtime - LOGGER.info(f'Loading {w} for TensorFlow Lite Edge TPU inference...') - delegate = { - 'Linux': 'libedgetpu.so.1', - 'Darwin': 'libedgetpu.1.dylib', - 'Windows': 'edgetpu.dll'}[platform.system()] + LOGGER.info(f"Loading {w} for TensorFlow Lite Edge TPU inference...") + delegate = {"Linux": "libedgetpu.so.1", "Darwin": "libedgetpu.1.dylib", "Windows": "edgetpu.dll"}[ + platform.system() + ] interpreter = Interpreter(model_path=w, experimental_delegates=[load_delegate(delegate)]) else: # TFLite - LOGGER.info(f'Loading {w} for TensorFlow Lite inference...') + LOGGER.info(f"Loading {w} for TensorFlow Lite inference...") interpreter = Interpreter(model_path=w) # load TFLite model interpreter.allocate_tensors() # allocate input_details = interpreter.get_input_details() # inputs output_details = interpreter.get_output_details() # outputs # load metadata with contextlib.suppress(zipfile.BadZipFile): - with zipfile.ZipFile(w, 'r') as model: + with zipfile.ZipFile(w, "r") as model: meta_file = model.namelist()[0] - meta = ast.literal_eval(model.read(meta_file).decode('utf-8')) - stride, names = int(meta['stride']), meta['names'] + meta = ast.literal_eval(model.read(meta_file).decode("utf-8")) + stride, names = int(meta["stride"]), meta["names"] elif tfjs: # TF.js - raise NotImplementedError('ERROR: YOLOv3 TF.js inference is not supported') + raise NotImplementedError("ERROR: YOLOv3 TF.js inference is not supported") elif paddle: # PaddlePaddle - LOGGER.info(f'Loading {w} for PaddlePaddle inference...') - check_requirements('paddlepaddle-gpu' if cuda else 'paddlepaddle') + LOGGER.info(f"Loading {w} for PaddlePaddle inference...") + check_requirements("paddlepaddle-gpu" if cuda else "paddlepaddle") import paddle.inference as pdi + if not Path(w).is_file(): # if not *.pdmodel - w = next(Path(w).rglob('*.pdmodel')) # get *.pdmodel file from *_paddle_model dir - weights = Path(w).with_suffix('.pdiparams') + w = next(Path(w).rglob("*.pdmodel")) # get *.pdmodel file from *_paddle_model dir + weights = Path(w).with_suffix(".pdiparams") config = pdi.Config(str(w), str(weights)) if cuda: config.enable_use_gpu(memory_pool_init_size_mb=2048, device_id=0) @@ -487,19 +510,20 @@ def gd_outputs(gd): input_handle = predictor.get_input_handle(predictor.get_input_names()[0]) output_names = predictor.get_output_names() elif triton: # NVIDIA Triton Inference Server - LOGGER.info(f'Using {w} as Triton Inference Server...') - check_requirements('tritonclient[all]') + LOGGER.info(f"Using {w} as Triton Inference Server...") + check_requirements("tritonclient[all]") from utils.triton import TritonRemoteModel + model = TritonRemoteModel(url=w) - nhwc = model.runtime.startswith('tensorflow') + nhwc = model.runtime.startswith("tensorflow") else: - raise NotImplementedError(f'ERROR: {w} is not a supported format') + raise NotImplementedError(f"ERROR: {w} is not a supported format") # class names - if 'names' not in locals(): - names = yaml_load(data)['names'] if data else {i: f'class{i}' for i in range(999)} - if names[0] == 'n01440764' and len(names) == 1000: # ImageNet - names = yaml_load(ROOT / 'data/ImageNet.yaml')['names'] # human-readable names + if "names" not in locals(): + names = yaml_load(data)["names"] if data else {i: f"class{i}" for i in range(999)} + if names[0] == "n01440764" and len(names) == 1000: # ImageNet + names = yaml_load(ROOT / "data/ImageNet.yaml")["names"] # human-readable names self.__dict__.update(locals()) # assign all variables to self @@ -526,26 +550,26 @@ def forward(self, im, augment=False, visualize=False): im = im.cpu().numpy() # FP32 y = list(self.ov_compiled_model(im).values()) elif self.engine: # TensorRT - if self.dynamic and im.shape != self.bindings['images'].shape: - i = self.model.get_binding_index('images') + if self.dynamic and im.shape != self.bindings["images"].shape: + i = self.model.get_binding_index("images") self.context.set_binding_shape(i, im.shape) # reshape if dynamic - self.bindings['images'] = self.bindings['images']._replace(shape=im.shape) + self.bindings["images"] = self.bindings["images"]._replace(shape=im.shape) for name in self.output_names: i = self.model.get_binding_index(name) self.bindings[name].data.resize_(tuple(self.context.get_binding_shape(i))) - s = self.bindings['images'].shape + s = self.bindings["images"].shape assert im.shape == s, f"input size {im.shape} {'>' if self.dynamic else 'not equal to'} max model size {s}" - self.binding_addrs['images'] = int(im.data_ptr()) + self.binding_addrs["images"] = int(im.data_ptr()) self.context.execute_v2(list(self.binding_addrs.values())) y = [self.bindings[x].data for x in sorted(self.output_names)] elif self.coreml: # CoreML im = im.cpu().numpy() - im = Image.fromarray((im[0] * 255).astype('uint8')) + im = Image.fromarray((im[0] * 255).astype("uint8")) # im = im.resize((192, 320), Image.BILINEAR) - y = self.model.predict({'image': im}) # coordinates are xywh normalized - if 'confidence' in y: - box = xywh2xyxy(y['coordinates'] * [[w, h, w, h]]) # xyxy pixels - conf, cls = y['confidence'].max(1), y['confidence'].argmax(1).astype(np.float) + y = self.model.predict({"image": im}) # coordinates are xywh normalized + if "confidence" in y: + box = xywh2xyxy(y["coordinates"] * [[w, h, w, h]]) # xyxy pixels + conf, cls = y["confidence"].max(1), y["confidence"].argmax(1).astype(np.float) y = np.concatenate((box, conf.reshape(-1, 1), cls.reshape(-1, 1)), 1) else: y = list(reversed(y.values())) # reversed for segmentation models (pred, proto) @@ -564,17 +588,17 @@ def forward(self, im, augment=False, visualize=False): y = self.frozen_func(x=self.tf.constant(im)) else: # Lite or Edge TPU input = self.input_details[0] - int8 = input['dtype'] == np.uint8 # is TFLite quantized uint8 model + int8 = input["dtype"] == np.uint8 # is TFLite quantized uint8 model if int8: - scale, zero_point = input['quantization'] + scale, zero_point = input["quantization"] im = (im / scale + zero_point).astype(np.uint8) # de-scale - self.interpreter.set_tensor(input['index'], im) + self.interpreter.set_tensor(input["index"], im) self.interpreter.invoke() y = [] for output in self.output_details: - x = self.interpreter.get_tensor(output['index']) + x = self.interpreter.get_tensor(output["index"]) if int8: - scale, zero_point = output['quantization'] + scale, zero_point = output["quantization"] x = (x.astype(np.float32) - zero_point) * scale # re-scale y.append(x) y = [x if isinstance(x, np.ndarray) else x.numpy() for x in y] @@ -591,32 +615,33 @@ def from_numpy(self, x): def warmup(self, imgsz=(1, 3, 640, 640)): # Warmup model by running inference once warmup_types = self.pt, self.jit, self.onnx, self.engine, self.saved_model, self.pb, self.triton - if any(warmup_types) and (self.device.type != 'cpu' or self.triton): + if any(warmup_types) and (self.device.type != "cpu" or self.triton): im = torch.empty(*imgsz, dtype=torch.half if self.fp16 else torch.float, device=self.device) # input for _ in range(2 if self.jit else 1): # self.forward(im) # warmup @staticmethod - def _model_type(p='path/to/model.pt'): + def _model_type(p="path/to/model.pt"): # Return model type from model path, i.e. path='path/to/model.onnx' -> type=onnx # types = [pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle] from export import export_formats from utils.downloads import is_url + sf = list(export_formats().Suffix) # export suffixes if not is_url(p, check=False): check_suffix(p, sf) # checks url = urlparse(p) # if url may be Triton inference server types = [s in Path(p).name for s in sf] types[8] &= not types[9] # tflite &= not edgetpu - triton = not any(types) and all([any(s in url.scheme for s in ['http', 'grpc']), url.netloc]) + triton = not any(types) and all([any(s in url.scheme for s in ["http", "grpc"]), url.netloc]) return types + [triton] @staticmethod - def _load_metadata(f=Path('path/to/meta.yaml')): + def _load_metadata(f=Path("path/to/meta.yaml")): # Load metadata from meta.yaml if it exists if f.exists(): d = yaml_load(f) - return d['stride'], d['names'] # assign stride, names + return d["stride"], d["names"] # assign stride, names return None, None @@ -633,8 +658,8 @@ class AutoShape(nn.Module): def __init__(self, model, verbose=True): super().__init__() if verbose: - LOGGER.info('Adding AutoShape... ') - copy_attr(self, model, include=('yaml', 'nc', 'hyp', 'names', 'stride', 'abc'), exclude=()) # copy attributes + LOGGER.info("Adding AutoShape... ") + copy_attr(self, model, include=("yaml", "nc", "hyp", "names", "stride", "abc"), exclude=()) # copy attributes self.dmb = isinstance(model, DetectMultiBackend) # DetectMultiBackend() instance self.pt = not self.dmb or model.pt # PyTorch model self.model = model.eval() @@ -670,7 +695,7 @@ def forward(self, ims, size=640, augment=False, profile=False): if isinstance(size, int): # expand size = (size, size) p = next(self.model.parameters()) if self.pt else torch.empty(1, device=self.model.device) # param - autocast = self.amp and (p.device.type != 'cpu') # Automatic Mixed Precision (AMP) inference + autocast = self.amp and (p.device.type != "cpu") # Automatic Mixed Precision (AMP) inference if isinstance(ims, torch.Tensor): # torch with amp.autocast(autocast): return self.model(ims.to(p.device).type_as(p), augment=augment) # inference @@ -679,13 +704,13 @@ def forward(self, ims, size=640, augment=False, profile=False): n, ims = (len(ims), list(ims)) if isinstance(ims, (list, tuple)) else (1, [ims]) # number, list of images shape0, shape1, files = [], [], [] # image and inference shapes, filenames for i, im in enumerate(ims): - f = f'image{i}' # filename + f = f"image{i}" # filename if isinstance(im, (str, Path)): # filename or uri - im, f = Image.open(requests.get(im, stream=True).raw if str(im).startswith('http') else im), im + im, f = Image.open(requests.get(im, stream=True).raw if str(im).startswith("http") else im), im im = np.asarray(exif_transpose(im)) elif isinstance(im, Image.Image): # PIL Image - im, f = np.asarray(exif_transpose(im)), getattr(im, 'filename', f) or f - files.append(Path(f).with_suffix('.jpg').name) + im, f = np.asarray(exif_transpose(im)), getattr(im, "filename", f) or f + files.append(Path(f).with_suffix(".jpg").name) if im.shape[0] < 5: # image in CHW im = im.transpose((1, 2, 0)) # reverse dataloader .transpose(2, 0, 1) im = im[..., :3] if im.ndim == 3 else cv2.cvtColor(im, cv2.COLOR_GRAY2BGR) # enforce 3ch input @@ -706,13 +731,15 @@ def forward(self, ims, size=640, augment=False, profile=False): # Post-process with dt[2]: - y = non_max_suppression(y if self.dmb else y[0], - self.conf, - self.iou, - self.classes, - self.agnostic, - self.multi_label, - max_det=self.max_det) # NMS + y = non_max_suppression( + y if self.dmb else y[0], + self.conf, + self.iou, + self.classes, + self.agnostic, + self.multi_label, + max_det=self.max_det, + ) # NMS for i in range(n): scale_boxes(shape1, y[i][:, :4], shape0[i]) @@ -735,40 +762,44 @@ def __init__(self, ims, pred, files, times=(0, 0, 0), names=None, shape=None): self.xyxyn = [x / g for x, g in zip(self.xyxy, gn)] # xyxy normalized self.xywhn = [x / g for x, g in zip(self.xywh, gn)] # xywh normalized self.n = len(self.pred) # number of images (batch size) - self.t = tuple(x.t / self.n * 1E3 for x in times) # timestamps (ms) + self.t = tuple(x.t / self.n * 1e3 for x in times) # timestamps (ms) self.s = tuple(shape) # inference BCHW shape - def _run(self, pprint=False, show=False, save=False, crop=False, render=False, labels=True, save_dir=Path('')): - s, crops = '', [] + def _run(self, pprint=False, show=False, save=False, crop=False, render=False, labels=True, save_dir=Path("")): + s, crops = "", [] for i, (im, pred) in enumerate(zip(self.ims, self.pred)): - s += f'\nimage {i + 1}/{len(self.pred)}: {im.shape[0]}x{im.shape[1]} ' # string + s += f"\nimage {i + 1}/{len(self.pred)}: {im.shape[0]}x{im.shape[1]} " # string if pred.shape[0]: for c in pred[:, -1].unique(): n = (pred[:, -1] == c).sum() # detections per class s += f"{n} {self.names[int(c)]}{'s' * (n > 1)}, " # add to string - s = s.rstrip(', ') + s = s.rstrip(", ") if show or save or render or crop: annotator = Annotator(im, example=str(self.names)) for *box, conf, cls in reversed(pred): # xyxy, confidence, class - label = f'{self.names[int(cls)]} {conf:.2f}' + label = f"{self.names[int(cls)]} {conf:.2f}" if crop: - file = save_dir / 'crops' / self.names[int(cls)] / self.files[i] if save else None - crops.append({ - 'box': box, - 'conf': conf, - 'cls': cls, - 'label': label, - 'im': save_one_box(box, im, file=file, save=save)}) + file = save_dir / "crops" / self.names[int(cls)] / self.files[i] if save else None + crops.append( + { + "box": box, + "conf": conf, + "cls": cls, + "label": label, + "im": save_one_box(box, im, file=file, save=save), + } + ) else: # all others - annotator.box_label(box, label if labels else '', color=colors(cls)) + annotator.box_label(box, label if labels else "", color=colors(cls)) im = annotator.im else: - s += '(no detections)' + s += "(no detections)" im = Image.fromarray(im.astype(np.uint8)) if isinstance(im, np.ndarray) else im # from np if show: if is_jupyter(): from IPython.display import display + display(im) else: im.show(self.files[i]) @@ -780,22 +811,22 @@ def _run(self, pprint=False, show=False, save=False, crop=False, render=False, l if render: self.ims[i] = np.asarray(im) if pprint: - s = s.lstrip('\n') - return f'{s}\nSpeed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {self.s}' % self.t + s = s.lstrip("\n") + return f"{s}\nSpeed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {self.s}" % self.t if crop: if save: - LOGGER.info(f'Saved results to {save_dir}\n') + LOGGER.info(f"Saved results to {save_dir}\n") return crops - @TryExcept('Showing images is not supported in this environment') + @TryExcept("Showing images is not supported in this environment") def show(self, labels=True): self._run(show=True, labels=labels) # show results - def save(self, labels=True, save_dir='runs/detect/exp', exist_ok=False): + def save(self, labels=True, save_dir="runs/detect/exp", exist_ok=False): save_dir = increment_path(save_dir, exist_ok, mkdir=True) # increment save_dir self._run(save=True, labels=labels, save_dir=save_dir) # save results - def crop(self, save=True, save_dir='runs/detect/exp', exist_ok=False): + def crop(self, save=True, save_dir="runs/detect/exp", exist_ok=False): save_dir = increment_path(save_dir, exist_ok, mkdir=True) if save else None return self._run(crop=True, save=save, save_dir=save_dir) # crop results @@ -806,9 +837,9 @@ def render(self, labels=True): def pandas(self): # return detections as pandas DataFrames, i.e. print(results.pandas().xyxy[0]) new = copy(self) # return copy - ca = 'xmin', 'ymin', 'xmax', 'ymax', 'confidence', 'class', 'name' # xyxy columns - cb = 'xcenter', 'ycenter', 'width', 'height', 'confidence', 'class', 'name' # xywh columns - for k, c in zip(['xyxy', 'xyxyn', 'xywh', 'xywhn'], [ca, ca, cb, cb]): + ca = "xmin", "ymin", "xmax", "ymax", "confidence", "class", "name" # xyxy columns + cb = "xcenter", "ycenter", "width", "height", "confidence", "class", "name" # xywh columns + for k, c in zip(["xyxy", "xyxyn", "xywh", "xywhn"], [ca, ca, cb, cb]): a = [[x[:5] + [int(x[5]), self.names[int(x[5])]] for x in x.tolist()] for x in getattr(self, k)] # update setattr(new, k, [pd.DataFrame(x, columns=c) for x in a]) return new @@ -832,7 +863,7 @@ def __str__(self): # override print(results) return self._run(pprint=True) # print results def __repr__(self): - return f'YOLOv3 {self.__class__} instance\n' + self.__str__() + return f"YOLOv3 {self.__class__} instance\n" + self.__str__() class Proto(nn.Module): @@ -840,7 +871,7 @@ class Proto(nn.Module): def __init__(self, c1, c_=256, c2=32): # ch_in, number of protos, number of masks super().__init__() self.cv1 = Conv(c1, c_, k=3) - self.upsample = nn.Upsample(scale_factor=2, mode='nearest') + self.upsample = nn.Upsample(scale_factor=2, mode="nearest") self.cv2 = Conv(c_, c_, k=3) self.cv3 = Conv(c_, c2) @@ -850,14 +881,9 @@ def forward(self, x): class Classify(nn.Module): # YOLOv3 classification head, i.e. x(b,c1,20,20) to x(b,c2) - def __init__(self, - c1, - c2, - k=1, - s=1, - p=None, - g=1, - dropout_p=0.0): # ch_in, ch_out, kernel, stride, padding, groups, dropout probability + def __init__( + self, c1, c2, k=1, s=1, p=None, g=1, dropout_p=0.0 + ): # ch_in, ch_out, kernel, stride, padding, groups, dropout probability super().__init__() c_ = 1280 # efficientnet_b0 size self.conv = Conv(c1, c_, k, s, autopad(k, p), g) diff --git a/models/experimental.py b/models/experimental.py index dd41155a8d..37b5940d65 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Experimental modules -""" +"""Experimental modules.""" import math import numpy as np @@ -38,7 +36,7 @@ def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): # ch_in, ch_out, kern super().__init__() n = len(k) # number of convolutions if equal_ch: # equal c_ per group - i = torch.linspace(0, n - 1E-6, c2).floor() # c2 indices + i = torch.linspace(0, n - 1e-6, c2).floor() # c2 indices c_ = [(i == g).sum() for g in range(n)] # intermediate channels else: # equal weight.numel() per group b = [c2] + [0] * n @@ -48,8 +46,9 @@ def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): # ch_in, ch_out, kern a[0] = 1 c_ = np.linalg.lstsq(a, b, rcond=None)[0].round() # solve for equal weight indices, ax = b - self.m = nn.ModuleList([ - nn.Conv2d(c1, int(c_), k, s, k // 2, groups=math.gcd(c1, int(c_)), bias=False) for k, c_ in zip(k, c_)]) + self.m = nn.ModuleList( + [nn.Conv2d(c1, int(c_), k, s, k // 2, groups=math.gcd(c1, int(c_)), bias=False) for k, c_ in zip(k, c_)] + ) self.bn = nn.BatchNorm2d(c2) self.act = nn.SiLU() @@ -76,16 +75,16 @@ def attempt_load(weights, device=None, inplace=True, fuse=True): model = Ensemble() for w in weights if isinstance(weights, list) else [weights]: - ckpt = torch.load(attempt_download(w), map_location='cpu') # load - ckpt = (ckpt.get('ema') or ckpt['model']).to(device).float() # FP32 model + ckpt = torch.load(attempt_download(w), map_location="cpu") # load + ckpt = (ckpt.get("ema") or ckpt["model"]).to(device).float() # FP32 model # Model compatibility updates - if not hasattr(ckpt, 'stride'): - ckpt.stride = torch.tensor([32.]) - if hasattr(ckpt, 'names') and isinstance(ckpt.names, (list, tuple)): + if not hasattr(ckpt, "stride"): + ckpt.stride = torch.tensor([32.0]) + if hasattr(ckpt, "names") and isinstance(ckpt.names, (list, tuple)): ckpt.names = dict(enumerate(ckpt.names)) # convert to dict - model.append(ckpt.fuse().eval() if fuse and hasattr(ckpt, 'fuse') else ckpt.eval()) # model in eval mode + model.append(ckpt.fuse().eval() if fuse and hasattr(ckpt, "fuse") else ckpt.eval()) # model in eval mode # Module compatibility updates for m in model.modules(): @@ -93,9 +92,9 @@ def attempt_load(weights, device=None, inplace=True, fuse=True): if t in (nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Model): m.inplace = inplace # torch 1.7.0 compatibility if t is Detect and not isinstance(m.anchor_grid, list): - delattr(m, 'anchor_grid') - setattr(m, 'anchor_grid', [torch.zeros(1)] * m.nl) - elif t is nn.Upsample and not hasattr(m, 'recompute_scale_factor'): + delattr(m, "anchor_grid") + setattr(m, "anchor_grid", [torch.zeros(1)] * m.nl) + elif t is nn.Upsample and not hasattr(m, "recompute_scale_factor"): m.recompute_scale_factor = None # torch 1.11.0 compatibility # Return model @@ -103,9 +102,9 @@ def attempt_load(weights, device=None, inplace=True, fuse=True): return model[-1] # Return detection ensemble - print(f'Ensemble created with {weights}\n') - for k in 'names', 'nc', 'yaml': + print(f"Ensemble created with {weights}\n") + for k in "names", "nc", "yaml": setattr(model, k, getattr(model[0], k)) model.stride = model[torch.argmax(torch.tensor([m.stride.max() for m in model])).int()].stride # max stride - assert all(model[0].nc == m.nc for m in model), f'Models have different class counts: {[m.nc for m in model]}' + assert all(model[0].nc == m.nc for m in model), f"Models have different class counts: {[m.nc for m in model]}" return model diff --git a/models/tf.py b/models/tf.py index a933918e14..e59b00055a 100644 --- a/models/tf.py +++ b/models/tf.py @@ -27,8 +27,21 @@ import torch.nn as nn from tensorflow import keras -from models.common import (C3, SPP, SPPF, Bottleneck, BottleneckCSP, C3x, Concat, Conv, CrossConv, DWConv, - DWConvTranspose2d, Focus, autopad) +from models.common import ( + C3, + SPP, + SPPF, + Bottleneck, + BottleneckCSP, + C3x, + Concat, + Conv, + CrossConv, + DWConv, + DWConvTranspose2d, + Focus, + autopad, +) from models.experimental import MixConv2d, attempt_load from models.yolo import Detect, Segment from utils.activations import SiLU @@ -44,7 +57,8 @@ def __init__(self, w=None): gamma_initializer=keras.initializers.Constant(w.weight.numpy()), moving_mean_initializer=keras.initializers.Constant(w.running_mean.numpy()), moving_variance_initializer=keras.initializers.Constant(w.running_var.numpy()), - epsilon=w.eps) + epsilon=w.eps, + ) def call(self, inputs): return self.bn(inputs) @@ -60,7 +74,7 @@ def __init__(self, pad): self.pad = tf.constant([[0, 0], [pad[0], pad[0]], [pad[1], pad[1]], [0, 0]]) def call(self, inputs): - return tf.pad(inputs, self.pad, mode='constant', constant_values=0) + return tf.pad(inputs, self.pad, mode="constant", constant_values=0) class TFConv(keras.layers.Layer): @@ -75,12 +89,13 @@ def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None): filters=c2, kernel_size=k, strides=s, - padding='SAME' if s == 1 else 'VALID', - use_bias=not hasattr(w, 'bn'), + padding="SAME" if s == 1 else "VALID", + use_bias=not hasattr(w, "bn"), kernel_initializer=keras.initializers.Constant(w.conv.weight.permute(2, 3, 1, 0).numpy()), - bias_initializer='zeros' if hasattr(w, 'bn') else keras.initializers.Constant(w.conv.bias.numpy())) + bias_initializer="zeros" if hasattr(w, "bn") else keras.initializers.Constant(w.conv.bias.numpy()), + ) self.conv = conv if s == 1 else keras.Sequential([TFPad(autopad(k, p)), conv]) - self.bn = TFBN(w.bn) if hasattr(w, 'bn') else tf.identity + self.bn = TFBN(w.bn) if hasattr(w, "bn") else tf.identity self.act = activations(w.act) if act else tf.identity def call(self, inputs): @@ -92,17 +107,18 @@ class TFDWConv(keras.layers.Layer): def __init__(self, c1, c2, k=1, s=1, p=None, act=True, w=None): # ch_in, ch_out, weights, kernel, stride, padding, groups super().__init__() - assert c2 % c1 == 0, f'TFDWConv() output={c2} must be a multiple of input={c1} channels' + assert c2 % c1 == 0, f"TFDWConv() output={c2} must be a multiple of input={c1} channels" conv = keras.layers.DepthwiseConv2D( kernel_size=k, depth_multiplier=c2 // c1, strides=s, - padding='SAME' if s == 1 else 'VALID', - use_bias=not hasattr(w, 'bn'), + padding="SAME" if s == 1 else "VALID", + use_bias=not hasattr(w, "bn"), depthwise_initializer=keras.initializers.Constant(w.conv.weight.permute(2, 3, 1, 0).numpy()), - bias_initializer='zeros' if hasattr(w, 'bn') else keras.initializers.Constant(w.conv.bias.numpy())) + bias_initializer="zeros" if hasattr(w, "bn") else keras.initializers.Constant(w.conv.bias.numpy()), + ) self.conv = conv if s == 1 else keras.Sequential([TFPad(autopad(k, p)), conv]) - self.bn = TFBN(w.bn) if hasattr(w, 'bn') else tf.identity + self.bn = TFBN(w.bn) if hasattr(w, "bn") else tf.identity self.act = activations(w.act) if act else tf.identity def call(self, inputs): @@ -114,19 +130,23 @@ class TFDWConvTranspose2d(keras.layers.Layer): def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0, w=None): # ch_in, ch_out, weights, kernel, stride, padding, groups super().__init__() - assert c1 == c2, f'TFDWConv() output={c2} must be equal to input={c1} channels' - assert k == 4 and p1 == 1, 'TFDWConv() only valid for k=4 and p1=1' + assert c1 == c2, f"TFDWConv() output={c2} must be equal to input={c1} channels" + assert k == 4 and p1 == 1, "TFDWConv() only valid for k=4 and p1=1" weight, bias = w.weight.permute(2, 3, 1, 0).numpy(), w.bias.numpy() self.c1 = c1 self.conv = [ - keras.layers.Conv2DTranspose(filters=1, - kernel_size=k, - strides=s, - padding='VALID', - output_padding=p2, - use_bias=True, - kernel_initializer=keras.initializers.Constant(weight[..., i:i + 1]), - bias_initializer=keras.initializers.Constant(bias[i])) for i in range(c1)] + keras.layers.Conv2DTranspose( + filters=1, + kernel_size=k, + strides=s, + padding="VALID", + output_padding=p2, + use_bias=True, + kernel_initializer=keras.initializers.Constant(weight[..., i : i + 1]), + bias_initializer=keras.initializers.Constant(bias[i]), + ) + for i in range(c1) + ] def call(self, inputs): return tf.concat([m(x) for m, x in zip(self.conv, tf.split(inputs, self.c1, 3))], 3)[:, 1:-1, 1:-1] @@ -176,14 +196,15 @@ class TFConv2d(keras.layers.Layer): def __init__(self, c1, c2, k, s=1, g=1, bias=True, w=None): super().__init__() assert g == 1, "TF v2.2 Conv2D does not support 'groups' argument" - self.conv = keras.layers.Conv2D(filters=c2, - kernel_size=k, - strides=s, - padding='VALID', - use_bias=bias, - kernel_initializer=keras.initializers.Constant( - w.weight.permute(2, 3, 1, 0).numpy()), - bias_initializer=keras.initializers.Constant(w.bias.numpy()) if bias else None) + self.conv = keras.layers.Conv2D( + filters=c2, + kernel_size=k, + strides=s, + padding="VALID", + use_bias=bias, + kernel_initializer=keras.initializers.Constant(w.weight.permute(2, 3, 1, 0).numpy()), + bias_initializer=keras.initializers.Constant(w.bias.numpy()) if bias else None, + ) def call(self, inputs): return self.conv(inputs) @@ -233,8 +254,9 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) self.cv2 = TFConv(c1, c_, 1, 1, w=w.cv2) self.cv3 = TFConv(2 * c_, c2, 1, 1, w=w.cv3) - self.m = keras.Sequential([ - TFCrossConv(c_, c_, k=3, s=1, g=g, e=1.0, shortcut=shortcut, w=w.m[j]) for j in range(n)]) + self.m = keras.Sequential( + [TFCrossConv(c_, c_, k=3, s=1, g=g, e=1.0, shortcut=shortcut, w=w.m[j]) for j in range(n)] + ) def call(self, inputs): return self.cv3(tf.concat((self.m(self.cv1(inputs)), self.cv2(inputs)), axis=3)) @@ -247,7 +269,7 @@ def __init__(self, c1, c2, k=(5, 9, 13), w=None): c_ = c1 // 2 # hidden channels self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) self.cv2 = TFConv(c_ * (len(k) + 1), c2, 1, 1, w=w.cv2) - self.m = [keras.layers.MaxPool2D(pool_size=x, strides=1, padding='SAME') for x in k] + self.m = [keras.layers.MaxPool2D(pool_size=x, strides=1, padding="SAME") for x in k] def call(self, inputs): x = self.cv1(inputs) @@ -261,7 +283,7 @@ def __init__(self, c1, c2, k=5, w=None): c_ = c1 // 2 # hidden channels self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) self.cv2 = TFConv(c_ * 4, c2, 1, 1, w=w.cv2) - self.m = keras.layers.MaxPool2D(pool_size=k, strides=1, padding='SAME') + self.m = keras.layers.MaxPool2D(pool_size=k, strides=1, padding="SAME") def call(self, inputs): x = self.cv1(inputs) @@ -307,10 +329,10 @@ def call(self, inputs): # Normalize xywh to 0-1 to reduce calibration error xy /= tf.constant([[self.imgsz[1], self.imgsz[0]]], dtype=tf.float32) wh /= tf.constant([[self.imgsz[1], self.imgsz[0]]], dtype=tf.float32) - y = tf.concat([xy, wh, tf.sigmoid(y[..., 4:5 + self.nc]), y[..., 5 + self.nc:]], -1) + y = tf.concat([xy, wh, tf.sigmoid(y[..., 4 : 5 + self.nc]), y[..., 5 + self.nc :]], -1) z.append(tf.reshape(y, [-1, self.na * ny * nx, self.no])) - return tf.transpose(x, [0, 2, 1, 3]) if self.training else (tf.concat(z, 1), ) + return tf.transpose(x, [0, 2, 1, 3]) if self.training else (tf.concat(z, 1),) @staticmethod def _make_grid(nx=20, ny=20): @@ -340,11 +362,10 @@ def call(self, x): class TFProto(keras.layers.Layer): - def __init__(self, c1, c_=256, c2=32, w=None): super().__init__() self.cv1 = TFConv(c1, c_, k=3, w=w.cv1) - self.upsample = TFUpsample(None, scale_factor=2, mode='nearest') + self.upsample = TFUpsample(None, scale_factor=2, mode="nearest") self.cv2 = TFConv(c_, c_, k=3, w=w.cv2) self.cv3 = TFConv(c_, c2, w=w.cv3) @@ -356,7 +377,7 @@ class TFUpsample(keras.layers.Layer): # TF version of torch.nn.Upsample() def __init__(self, size, scale_factor, mode, w=None): # warning: all arguments needed including 'w' super().__init__() - assert scale_factor % 2 == 0, 'scale_factor must be multiple of 2' + assert scale_factor % 2 == 0, "scale_factor must be multiple of 2" self.upsample = lambda x: tf.image.resize(x, (x.shape[1] * scale_factor, x.shape[2] * scale_factor), mode) # self.upsample = keras.layers.UpSampling2D(size=scale_factor, interpolation=mode) # with default arguments: align_corners=False, half_pixel_centers=False @@ -371,7 +392,7 @@ class TFConcat(keras.layers.Layer): # TF version of torch.concat() def __init__(self, dimension=1, w=None): super().__init__() - assert dimension == 1, 'convert only NCHW to NHWC concat' + assert dimension == 1, "convert only NCHW to NHWC concat" self.d = 3 def call(self, inputs): @@ -380,12 +401,12 @@ def call(self, inputs): def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3) LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}") - anchors, nc, gd, gw = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'] + anchors, nc, gd, gw = d["anchors"], d["nc"], d["depth_multiple"], d["width_multiple"] na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors no = na * (nc + 5) # number of outputs = anchors * (classes + 5) layers, save, c2 = [], [], ch[-1] # layers, savelist, ch out - for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, args + for i, (f, n, m, args) in enumerate(d["backbone"] + d["head"]): # from, number, module, args m_str = m m = eval(m) if isinstance(m, str) else m # eval strings for j, a in enumerate(args): @@ -396,8 +417,20 @@ def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3) n = max(round(n * gd), 1) if n > 1 else n # depth gain if m in [ - nn.Conv2d, Conv, DWConv, DWConvTranspose2d, Bottleneck, SPP, SPPF, MixConv2d, Focus, CrossConv, - BottleneckCSP, C3, C3x]: + nn.Conv2d, + Conv, + DWConv, + DWConvTranspose2d, + Bottleneck, + SPP, + SPPF, + MixConv2d, + Focus, + CrossConv, + BottleneckCSP, + C3, + C3x, + ]: c1, c2 = ch[f], args[0] c2 = make_divisible(c2 * gw, 8) if c2 != no else c2 @@ -419,15 +452,18 @@ def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3) else: c2 = ch[f] - tf_m = eval('TF' + m_str.replace('nn.', '')) - m_ = keras.Sequential([tf_m(*args, w=model.model[i][j]) for j in range(n)]) if n > 1 \ - else tf_m(*args, w=model.model[i]) # module + tf_m = eval("TF" + m_str.replace("nn.", "")) + m_ = ( + keras.Sequential([tf_m(*args, w=model.model[i][j]) for j in range(n)]) + if n > 1 + else tf_m(*args, w=model.model[i]) + ) # module torch_m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # module - t = str(m)[8:-2].replace('__main__.', '') # module type + t = str(m)[8:-2].replace("__main__.", "") # module type np = sum(x.numel() for x in torch_m_.parameters()) # number params m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params - LOGGER.info(f'{i:>3}{str(f):>18}{str(n):>3}{np:>10} {t:<40}{str(args):<30}') # print + LOGGER.info(f"{i:>3}{str(f):>18}{str(n):>3}{np:>10} {t:<40}{str(args):<30}") # print save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist layers.append(m_) ch.append(c2) @@ -436,30 +472,33 @@ def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3) class TFModel: # TF YOLOv3 model - def __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, model=None, imgsz=(640, 640)): # model, channels, classes + def __init__(self, cfg="yolov5s.yaml", ch=3, nc=None, model=None, imgsz=(640, 640)): # model, channels, classes super().__init__() if isinstance(cfg, dict): self.yaml = cfg # model dict else: # is *.yaml import yaml # for torch hub + self.yaml_file = Path(cfg).name with open(cfg) as f: self.yaml = yaml.load(f, Loader=yaml.FullLoader) # model dict # Define model - if nc and nc != self.yaml['nc']: + if nc and nc != self.yaml["nc"]: LOGGER.info(f"Overriding {cfg} nc={self.yaml['nc']} with nc={nc}") - self.yaml['nc'] = nc # override yaml value + self.yaml["nc"] = nc # override yaml value self.model, self.savelist = parse_model(deepcopy(self.yaml), ch=[ch], model=model, imgsz=imgsz) - def predict(self, - inputs, - tf_nms=False, - agnostic_nms=False, - topk_per_class=100, - topk_all=100, - iou_thres=0.45, - conf_thres=0.25): + def predict( + self, + inputs, + tf_nms=False, + agnostic_nms=False, + topk_per_class=100, + topk_all=100, + iou_thres=0.45, + conf_thres=0.25, + ): y = [] # outputs x = inputs for m in self.model.layers: @@ -479,14 +518,10 @@ def predict(self, nms = AgnosticNMS()((boxes, classes, scores), topk_all, iou_thres, conf_thres) else: boxes = tf.expand_dims(boxes, 2) - nms = tf.image.combined_non_max_suppression(boxes, - scores, - topk_per_class, - topk_all, - iou_thres, - conf_thres, - clip_boxes=False) - return (nms, ) + nms = tf.image.combined_non_max_suppression( + boxes, scores, topk_per_class, topk_all, iou_thres, conf_thres, clip_boxes=False + ) + return (nms,) return x # output [1,6300,85] = [xywh, conf, class0, class1, ...] # x = x[0] # [x(1,6300,85), ...] to x(6300,85) # xywh = x[..., :4] # x(6300,4) boxes @@ -505,36 +540,42 @@ class AgnosticNMS(keras.layers.Layer): # TF Agnostic NMS def call(self, input, topk_all, iou_thres, conf_thres): # wrap map_fn to avoid TypeSpec related error https://stackoverflow.com/a/65809989/3036450 - return tf.map_fn(lambda x: self._nms(x, topk_all, iou_thres, conf_thres), - input, - fn_output_signature=(tf.float32, tf.float32, tf.float32, tf.int32), - name='agnostic_nms') + return tf.map_fn( + lambda x: self._nms(x, topk_all, iou_thres, conf_thres), + input, + fn_output_signature=(tf.float32, tf.float32, tf.float32, tf.int32), + name="agnostic_nms", + ) @staticmethod def _nms(x, topk_all=100, iou_thres=0.45, conf_thres=0.25): # agnostic NMS boxes, classes, scores = x class_inds = tf.cast(tf.argmax(classes, axis=-1), tf.float32) scores_inp = tf.reduce_max(scores, -1) - selected_inds = tf.image.non_max_suppression(boxes, - scores_inp, - max_output_size=topk_all, - iou_threshold=iou_thres, - score_threshold=conf_thres) + selected_inds = tf.image.non_max_suppression( + boxes, scores_inp, max_output_size=topk_all, iou_threshold=iou_thres, score_threshold=conf_thres + ) selected_boxes = tf.gather(boxes, selected_inds) - padded_boxes = tf.pad(selected_boxes, - paddings=[[0, topk_all - tf.shape(selected_boxes)[0]], [0, 0]], - mode='CONSTANT', - constant_values=0.0) + padded_boxes = tf.pad( + selected_boxes, + paddings=[[0, topk_all - tf.shape(selected_boxes)[0]], [0, 0]], + mode="CONSTANT", + constant_values=0.0, + ) selected_scores = tf.gather(scores_inp, selected_inds) - padded_scores = tf.pad(selected_scores, - paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]], - mode='CONSTANT', - constant_values=-1.0) + padded_scores = tf.pad( + selected_scores, + paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]], + mode="CONSTANT", + constant_values=-1.0, + ) selected_classes = tf.gather(class_inds, selected_inds) - padded_classes = tf.pad(selected_classes, - paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]], - mode='CONSTANT', - constant_values=-1.0) + padded_classes = tf.pad( + selected_classes, + paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]], + mode="CONSTANT", + constant_values=-1.0, + ) valid_detections = tf.shape(selected_inds)[0] return padded_boxes, padded_scores, padded_classes, valid_detections @@ -548,7 +589,7 @@ def activations(act=nn.SiLU): elif isinstance(act, (nn.SiLU, SiLU)): return lambda x: keras.activations.swish(x) else: - raise Exception(f'no matching TensorFlow activation found for PyTorch activation {act}') + raise Exception(f"no matching TensorFlow activation found for PyTorch activation {act}") def representative_dataset_gen(dataset, ncalib=100): @@ -563,14 +604,14 @@ def representative_dataset_gen(dataset, ncalib=100): def run( - weights=ROOT / 'yolov5s.pt', # weights path - imgsz=(640, 640), # inference size h,w - batch_size=1, # batch size - dynamic=False, # dynamic batch size + weights=ROOT / "yolov5s.pt", # weights path + imgsz=(640, 640), # inference size h,w + batch_size=1, # batch size + dynamic=False, # dynamic batch size ): # PyTorch model im = torch.zeros((batch_size, 3, *imgsz)) # BCHW image - model = attempt_load(weights, device=torch.device('cpu'), inplace=True, fuse=False) + model = attempt_load(weights, device=torch.device("cpu"), inplace=True, fuse=False) _ = model(im) # inference model.info() @@ -584,15 +625,15 @@ def run( keras_model = keras.Model(inputs=im, outputs=tf_model.predict(im)) keras_model.summary() - LOGGER.info('PyTorch, TensorFlow and Keras models successfully verified.\nUse export.py for TF model export.') + LOGGER.info("PyTorch, TensorFlow and Keras models successfully verified.\nUse export.py for TF model export.") def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default=ROOT / 'yolov3-tiny.pt', help='weights path') - parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') - parser.add_argument('--batch-size', type=int, default=1, help='batch size') - parser.add_argument('--dynamic', action='store_true', help='dynamic batch size') + parser.add_argument("--weights", type=str, default=ROOT / "yolov3-tiny.pt", help="weights path") + parser.add_argument("--imgsz", "--img", "--img-size", nargs="+", type=int, default=[640], help="inference size h,w") + parser.add_argument("--batch-size", type=int, default=1, help="batch size") + parser.add_argument("--dynamic", action="store_true", help="dynamic batch size") opt = parser.parse_args() opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand print_args(vars(opt)) @@ -603,6 +644,6 @@ def main(opt): run(**vars(opt)) -if __name__ == '__main__': +if __name__ == "__main__": opt = parse_opt() main(opt) diff --git a/models/yolo.py b/models/yolo.py index 0cc5dfc1ba..9c9962e682 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -YOLO-specific modules +YOLO-specific modules. Usage: $ python models/yolo.py --cfg yolov5s.yaml @@ -18,7 +18,7 @@ ROOT = FILE.parents[1] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH -if platform.system() != 'Windows': +if platform.system() != "Windows": ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative from models.common import * # noqa @@ -26,8 +26,15 @@ from utils.autoanchor import check_anchor_order from utils.general import LOGGER, check_version, check_yaml, make_divisible, print_args from utils.plots import feature_visualization -from utils.torch_utils import (fuse_conv_and_bn, initialize_weights, model_info, profile, scale_img, select_device, - time_sync) +from utils.torch_utils import ( + fuse_conv_and_bn, + initialize_weights, + model_info, + profile, + scale_img, + select_device, + time_sync, +) try: import thop # for FLOPs computation @@ -49,7 +56,7 @@ def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer self.na = len(anchors[0]) // 2 # number of anchors self.grid = [torch.empty(0) for _ in range(self.nl)] # init grid self.anchor_grid = [torch.empty(0) for _ in range(self.nl)] # init anchor grid - self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2) + self.register_buffer("anchors", torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2) self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv self.inplace = inplace # use inplace ops (e.g. slice assignment) @@ -76,14 +83,14 @@ def forward(self, x): y = torch.cat((xy, wh, conf), 4) z.append(y.view(bs, self.na * nx * ny, self.no)) - return x if self.training else (torch.cat(z, 1), ) if self.export else (torch.cat(z, 1), x) + return x if self.training else (torch.cat(z, 1),) if self.export else (torch.cat(z, 1), x) - def _make_grid(self, nx=20, ny=20, i=0, torch_1_10=check_version(torch.__version__, '1.10.0')): + def _make_grid(self, nx=20, ny=20, i=0, torch_1_10=check_version(torch.__version__, "1.10.0")): d = self.anchors[i].device t = self.anchors[i].dtype shape = 1, self.na, ny, nx, 2 # grid shape y, x = torch.arange(ny, device=d, dtype=t), torch.arange(nx, device=d, dtype=t) - yv, xv = torch.meshgrid(y, x, indexing='ij') if torch_1_10 else torch.meshgrid(y, x) # torch>=0.7 compatibility + yv, xv = torch.meshgrid(y, x, indexing="ij") if torch_1_10 else torch.meshgrid(y, x) # torch>=0.7 compatibility grid = torch.stack((xv, yv), 2).expand(shape) - 0.5 # add grid offset, i.e. y = 2.0 * x - 0.5 anchor_grid = (self.anchors[i] * self.stride[i]).view((1, self.na, 1, 1, 2)).expand(shape) return grid, anchor_grid @@ -126,23 +133,23 @@ def _forward_once(self, x, profile=False, visualize=False): def _profile_one_layer(self, m, x, dt): c = m == self.model[-1] # is final layer, copy input as inplace fix - o = thop.profile(m, inputs=(x.copy() if c else x, ), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPs + o = thop.profile(m, inputs=(x.copy() if c else x,), verbose=False)[0] / 1e9 * 2 if thop else 0 # FLOPs t = time_sync() for _ in range(10): m(x.copy() if c else x) dt.append((time_sync() - t) * 100) if m == self.model[0]: LOGGER.info(f"{'time (ms)':>10s} {'GFLOPs':>10s} {'params':>10s} module") - LOGGER.info(f'{dt[-1]:10.2f} {o:10.2f} {m.np:10.0f} {m.type}') + LOGGER.info(f"{dt[-1]:10.2f} {o:10.2f} {m.np:10.0f} {m.type}") if c: LOGGER.info(f"{sum(dt):10.2f} {'-':>10s} {'-':>10s} Total") def fuse(self): # fuse model Conv2d() + BatchNorm2d() layers - LOGGER.info('Fusing layers... ') + LOGGER.info("Fusing layers... ") for m in self.model.modules(): - if isinstance(m, (Conv, DWConv)) and hasattr(m, 'bn'): + if isinstance(m, (Conv, DWConv)) and hasattr(m, "bn"): m.conv = fuse_conv_and_bn(m.conv, m.bn) # update conv - delattr(m, 'bn') # remove batchnorm + delattr(m, "bn") # remove batchnorm m.forward = m.forward_fuse # update forward self.info() return self @@ -164,27 +171,28 @@ def _apply(self, fn): class DetectionModel(BaseModel): # YOLOv3 detection model - def __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classes + def __init__(self, cfg="yolov5s.yaml", ch=3, nc=None, anchors=None): # model, input channels, number of classes super().__init__() if isinstance(cfg, dict): self.yaml = cfg # model dict else: # is *.yaml import yaml # for torch hub + self.yaml_file = Path(cfg).name - with open(cfg, encoding='ascii', errors='ignore') as f: + with open(cfg, encoding="ascii", errors="ignore") as f: self.yaml = yaml.safe_load(f) # model dict # Define model - ch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channels - if nc and nc != self.yaml['nc']: + ch = self.yaml["ch"] = self.yaml.get("ch", ch) # input channels + if nc and nc != self.yaml["nc"]: LOGGER.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}") - self.yaml['nc'] = nc # override yaml value + self.yaml["nc"] = nc # override yaml value if anchors: - LOGGER.info(f'Overriding model.yaml anchors with anchors={anchors}') - self.yaml['anchors'] = round(anchors) # override yaml value + LOGGER.info(f"Overriding model.yaml anchors with anchors={anchors}") + self.yaml["anchors"] = round(anchors) # override yaml value self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelist - self.names = [str(i) for i in range(self.yaml['nc'])] # default names - self.inplace = self.yaml.get('inplace', True) + self.names = [str(i) for i in range(self.yaml["nc"])] # default names + self.inplace = self.yaml.get("inplace", True) # Build strides, anchors m = self.model[-1] # Detect() @@ -201,7 +209,7 @@ def __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, anchors=None): # model, i # Init weights, biases initialize_weights(self) self.info() - LOGGER.info('') + LOGGER.info("") def forward(self, x, augment=False, profile=False, visualize=False): if augment: @@ -242,9 +250,9 @@ def _descale_pred(self, p, flips, scale, img_size): def _clip_augmented(self, y): # Clip YOLOv3 augmented inference tails nl = self.model[-1].nl # number of detection layers (P3-P5) - g = sum(4 ** x for x in range(nl)) # grid points + g = sum(4**x for x in range(nl)) # grid points e = 1 # exclude layer count - i = (y[0].shape[1] // g) * sum(4 ** x for x in range(e)) # indices + i = (y[0].shape[1] // g) * sum(4**x for x in range(e)) # indices y[0] = y[0][:, :-i] # large i = (y[-1].shape[1] // g) * sum(4 ** (nl - 1 - x) for x in range(e)) # indices y[-1] = y[-1][:, i:] # small @@ -257,7 +265,9 @@ def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is for mi, s in zip(m.m, m.stride): # from b = mi.bias.view(m.na, -1) # conv.bias(255) to (3,85) b.data[:, 4] += math.log(8 / (640 / s) ** 2) # obj (8 objects per 640 image) - b.data[:, 5:5 + m.nc] += math.log(0.6 / (m.nc - 0.99999)) if cf is None else torch.log(cf / cf.sum()) # cls + b.data[:, 5 : 5 + m.nc] += ( + math.log(0.6 / (m.nc - 0.99999)) if cf is None else torch.log(cf / cf.sum()) + ) # cls mi.bias = torch.nn.Parameter(b.view(-1), requires_grad=True) @@ -266,7 +276,7 @@ def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is class SegmentationModel(DetectionModel): # YOLOv3 segmentation model - def __init__(self, cfg='yolov5s-seg.yaml', ch=3, nc=None, anchors=None): + def __init__(self, cfg="yolov5s-seg.yaml", ch=3, nc=None, anchors=None): super().__init__(cfg, ch, nc, anchors) @@ -282,9 +292,9 @@ def _from_detection_model(self, model, nc=1000, cutoff=10): model = model.model # unwrap DetectMultiBackend model.model = model.model[:cutoff] # backbone m = model.model[-1] # last layer - ch = m.conv.in_channels if hasattr(m, 'conv') else m.cv1.conv.in_channels # ch into module + ch = m.conv.in_channels if hasattr(m, "conv") else m.cv1.conv.in_channels # ch into module c = Classify(ch, nc) # Classify() - c.i, c.f, c.type = m.i, m.f, 'models.common.Classify' # index, from, type + c.i, c.f, c.type = m.i, m.f, "models.common.Classify" # index, from, type model.model[-1] = c # replace self.model = model.model self.stride = model.stride @@ -299,7 +309,7 @@ def _from_yaml(self, cfg): def parse_model(d, ch): # model_dict, input_channels(3) # Parse a YOLOv3 model.yaml dictionary LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}") - anchors, nc, gd, gw, act = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'], d.get('activation') + anchors, nc, gd, gw, act = d["anchors"], d["nc"], d["depth_multiple"], d["width_multiple"], d.get("activation") if act: Conv.default_act = eval(act) # redefine default activation, i.e. Conv.default_act = nn.SiLU() LOGGER.info(f"{colorstr('activation:')} {act}") # print @@ -307,7 +317,7 @@ def parse_model(d, ch): # model_dict, input_channels(3) no = na * (nc + 5) # number of outputs = anchors * (classes + 5) layers, save, c2 = [], [], ch[-1] # layers, savelist, ch out - for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, args + for i, (f, n, m, args) in enumerate(d["backbone"] + d["head"]): # from, number, module, args m = eval(m) if isinstance(m, str) else m # eval strings for j, a in enumerate(args): with contextlib.suppress(NameError): @@ -315,8 +325,25 @@ def parse_model(d, ch): # model_dict, input_channels(3) n = n_ = max(round(n * gd), 1) if n > 1 else n # depth gain if m in { - Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv, - BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x}: + Conv, + GhostConv, + Bottleneck, + GhostBottleneck, + SPP, + SPPF, + DWConv, + MixConv2d, + Focus, + CrossConv, + BottleneckCSP, + C3, + C3TR, + C3SPP, + C3Ghost, + nn.ConvTranspose2d, + DWConvTranspose2d, + C3x, + }: c1, c2 = ch[f], args[0] if c2 != no: # if not output c2 = make_divisible(c2 * gw, 8) @@ -344,10 +371,10 @@ def parse_model(d, ch): # model_dict, input_channels(3) c2 = ch[f] m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # module - t = str(m)[8:-2].replace('__main__.', '') # module type + t = str(m)[8:-2].replace("__main__.", "") # module type np = sum(x.numel() for x in m_.parameters()) # number params m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params - LOGGER.info(f'{i:>3}{str(f):>18}{n_:>3}{np:10.0f} {t:<40}{str(args):<30}') # print + LOGGER.info(f"{i:>3}{str(f):>18}{n_:>3}{np:10.0f} {t:<40}{str(args):<30}") # print save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist layers.append(m_) if i == 0: @@ -356,14 +383,14 @@ def parse_model(d, ch): # model_dict, input_channels(3) return nn.Sequential(*layers), sorted(save) -if __name__ == '__main__': +if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument('--cfg', type=str, default='yolov5s.yaml', help='model.yaml') - parser.add_argument('--batch-size', type=int, default=1, help='total batch size for all GPUs') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--profile', action='store_true', help='profile model speed') - parser.add_argument('--line-profile', action='store_true', help='profile model speed layer by layer') - parser.add_argument('--test', action='store_true', help='test all yolo*.yaml') + parser.add_argument("--cfg", type=str, default="yolov5s.yaml", help="model.yaml") + parser.add_argument("--batch-size", type=int, default=1, help="total batch size for all GPUs") + parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu") + parser.add_argument("--profile", action="store_true", help="profile model speed") + parser.add_argument("--line-profile", action="store_true", help="profile model speed layer by layer") + parser.add_argument("--test", action="store_true", help="test all yolo*.yaml") opt = parser.parse_args() opt.cfg = check_yaml(opt.cfg) # check YAML print_args(vars(opt)) @@ -381,11 +408,11 @@ def parse_model(d, ch): # model_dict, input_channels(3) results = profile(input=im, ops=[model], n=3) elif opt.test: # test all models - for cfg in Path(ROOT / 'models').rglob('yolo*.yaml'): + for cfg in Path(ROOT / "models").rglob("yolo*.yaml"): try: _ = Model(cfg) except Exception as e: - print(f'Error in {cfg}: {e}') + print(f"Error in {cfg}: {e}") else: # report fused model summary model.fuse() diff --git a/segment/predict.py b/segment/predict.py index ae3f5d960f..cbd79be552 100644 --- a/segment/predict.py +++ b/segment/predict.py @@ -46,23 +46,36 @@ from models.common import DetectMultiBackend from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams -from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, - increment_path, non_max_suppression, print_args, scale_boxes, scale_segments, - strip_optimizer) +from utils.general import ( + LOGGER, + Profile, + check_file, + check_img_size, + check_imshow, + check_requirements, + colorstr, + cv2, + increment_path, + non_max_suppression, + print_args, + scale_boxes, + scale_segments, + strip_optimizer, +) from utils.segment.general import masks2segments, process_mask, process_mask_native from utils.torch_utils import select_device, smart_inference_mode @smart_inference_mode() def run( - weights=ROOT / 'yolov5s-seg.pt', # model.pt path(s) - source=ROOT / 'data/images', # file/dir/URL/glob/screen/0(webcam) - data=ROOT / 'data/coco128.yaml', # dataset.yaml path + weights=ROOT / "yolov5s-seg.pt", # model.pt path(s) + source=ROOT / "data/images", # file/dir/URL/glob/screen/0(webcam) + data=ROOT / "data/coco128.yaml", # dataset.yaml path imgsz=(640, 640), # inference size (height, width) conf_thres=0.25, # confidence threshold iou_thres=0.45, # NMS IOU threshold max_det=1000, # maximum detections per image - device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + device="", # cuda device, i.e. 0 or 0,1,2,3 or cpu view_img=False, # show results save_txt=False, # save results to *.txt save_conf=False, # save confidences in --save-txt labels @@ -73,8 +86,8 @@ def run( augment=False, # augmented inference visualize=False, # visualize features update=False, # update all models - project=ROOT / 'runs/predict-seg', # save results to project/name - name='exp', # save results to project/name + project=ROOT / "runs/predict-seg", # save results to project/name + name="exp", # save results to project/name exist_ok=False, # existing project/name ok, do not increment line_thickness=3, # bounding box thickness (pixels) hide_labels=False, # hide labels @@ -85,17 +98,17 @@ def run( retina_masks=False, ): source = str(source) - save_img = not nosave and not source.endswith('.txt') # save inference images + save_img = not nosave and not source.endswith(".txt") # save inference images is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) - is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://')) - webcam = source.isnumeric() or source.endswith('.streams') or (is_url and not is_file) - screenshot = source.lower().startswith('screen') + is_url = source.lower().startswith(("rtsp://", "rtmp://", "http://", "https://")) + webcam = source.isnumeric() or source.endswith(".streams") or (is_url and not is_file) + screenshot = source.lower().startswith("screen") if is_url and is_file: source = check_file(source) # download # Directories save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run - (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + (save_dir / "labels" if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir # Load model device = select_device(device) @@ -143,14 +156,14 @@ def run( seen += 1 if webcam: # batch_size >= 1 p, im0, frame = path[i], im0s[i].copy(), dataset.count - s += f'{i}: ' + s += f"{i}: " else: - p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0) + p, im0, frame = path, im0s.copy(), getattr(dataset, "frame", 0) p = Path(p) # to Path save_path = str(save_dir / p.name) # im.jpg - txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # im.txt - s += '%gx%g ' % im.shape[2:] # print string + txt_path = str(save_dir / "labels" / p.stem) + ("" if dataset.mode == "image" else f"_{frame}") # im.txt + s += "%gx%g " % im.shape[2:] # print string imc = im0.copy() if save_crop else im0 # for save_crop annotator = Annotator(im0, line_width=line_thickness, example=str(names)) if len(det): @@ -166,7 +179,8 @@ def run( if save_txt: segments = [ scale_segments(im0.shape if retina_masks else im.shape[2:], x, im0.shape, normalize=True) - for x in reversed(masks2segments(masks))] + for x in reversed(masks2segments(masks)) + ] # Print results for c in det[:, 5].unique(): @@ -177,39 +191,42 @@ def run( annotator.masks( masks, colors=[colors(x, True) for x in det[:, 5]], - im_gpu=torch.as_tensor(im0, dtype=torch.float16).to(device).permute(2, 0, 1).flip(0).contiguous() / - 255 if retina_masks else im[i]) + im_gpu=torch.as_tensor(im0, dtype=torch.float16).to(device).permute(2, 0, 1).flip(0).contiguous() + / 255 + if retina_masks + else im[i], + ) # Write results for j, (*xyxy, conf, cls) in enumerate(reversed(det[:, :6])): if save_txt: # Write to file seg = segments[j].reshape(-1) # (n,2) to (n*2) line = (cls, *seg, conf) if save_conf else (cls, *seg) # label format - with open(f'{txt_path}.txt', 'a') as f: - f.write(('%g ' * len(line)).rstrip() % line + '\n') + with open(f"{txt_path}.txt", "a") as f: + f.write(("%g " * len(line)).rstrip() % line + "\n") if save_img or save_crop or view_img: # Add bbox to image c = int(cls) # integer class - label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}') + label = None if hide_labels else (names[c] if hide_conf else f"{names[c]} {conf:.2f}") annotator.box_label(xyxy, label, color=colors(c, True)) # annotator.draw.polygon(segments[j], outline=colors(c, True), width=3) if save_crop: - save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True) + save_one_box(xyxy, imc, file=save_dir / "crops" / names[c] / f"{p.stem}.jpg", BGR=True) # Stream results im0 = annotator.result() if view_img: - if platform.system() == 'Linux' and p not in windows: + if platform.system() == "Linux" and p not in windows: windows.append(p) cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux) cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0]) cv2.imshow(str(p), im0) - if cv2.waitKey(1) == ord('q'): # 1 millisecond + if cv2.waitKey(1) == ord("q"): # 1 millisecond exit() # Save results (image with detections) if save_img: - if dataset.mode == 'image': + if dataset.mode == "image": cv2.imwrite(save_path, im0) else: # 'video' or 'stream' if vid_path[i] != save_path: # new video @@ -222,18 +239,18 @@ def run( h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) else: # stream fps, w, h = 30, im0.shape[1], im0.shape[0] - save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos - vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) + save_path = str(Path(save_path).with_suffix(".mp4")) # force *.mp4 suffix on results videos + vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h)) vid_writer[i].write(im0) # Print time (inference-only) LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms") # Print results - t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image - LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t) + t = tuple(x.t / seen * 1e3 for x in dt) # speeds per image + LOGGER.info(f"Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}" % t) if save_txt or save_img: - s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else "" LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") if update: strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning) @@ -241,34 +258,34 @@ def run( def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s-seg.pt', help='model path(s)') - parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob/screen/0(webcam)') - parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path') - parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') - parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold') - parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold') - parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--view-img', action='store_true', help='show results') - parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') - parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') - parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes') - parser.add_argument('--nosave', action='store_true', help='do not save images/videos') - parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3') - parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') - parser.add_argument('--augment', action='store_true', help='augmented inference') - parser.add_argument('--visualize', action='store_true', help='visualize features') - parser.add_argument('--update', action='store_true', help='update all models') - parser.add_argument('--project', default=ROOT / 'runs/predict-seg', help='save results to project/name') - parser.add_argument('--name', default='exp', help='save results to project/name') - parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') - parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)') - parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels') - parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences') - parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') - parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') - parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride') - parser.add_argument('--retina-masks', action='store_true', help='whether to plot masks in native resolution') + parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov5s-seg.pt", help="model path(s)") + parser.add_argument("--source", type=str, default=ROOT / "data/images", help="file/dir/URL/glob/screen/0(webcam)") + parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="(optional) dataset.yaml path") + parser.add_argument("--imgsz", "--img", "--img-size", nargs="+", type=int, default=[640], help="inference size h,w") + parser.add_argument("--conf-thres", type=float, default=0.25, help="confidence threshold") + parser.add_argument("--iou-thres", type=float, default=0.45, help="NMS IoU threshold") + parser.add_argument("--max-det", type=int, default=1000, help="maximum detections per image") + parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu") + parser.add_argument("--view-img", action="store_true", help="show results") + parser.add_argument("--save-txt", action="store_true", help="save results to *.txt") + parser.add_argument("--save-conf", action="store_true", help="save confidences in --save-txt labels") + parser.add_argument("--save-crop", action="store_true", help="save cropped prediction boxes") + parser.add_argument("--nosave", action="store_true", help="do not save images/videos") + parser.add_argument("--classes", nargs="+", type=int, help="filter by class: --classes 0, or --classes 0 2 3") + parser.add_argument("--agnostic-nms", action="store_true", help="class-agnostic NMS") + parser.add_argument("--augment", action="store_true", help="augmented inference") + parser.add_argument("--visualize", action="store_true", help="visualize features") + parser.add_argument("--update", action="store_true", help="update all models") + parser.add_argument("--project", default=ROOT / "runs/predict-seg", help="save results to project/name") + parser.add_argument("--name", default="exp", help="save results to project/name") + parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment") + parser.add_argument("--line-thickness", default=3, type=int, help="bounding box thickness (pixels)") + parser.add_argument("--hide-labels", default=False, action="store_true", help="hide labels") + parser.add_argument("--hide-conf", default=False, action="store_true", help="hide confidences") + parser.add_argument("--half", action="store_true", help="use FP16 half-precision inference") + parser.add_argument("--dnn", action="store_true", help="use OpenCV DNN for ONNX inference") + parser.add_argument("--vid-stride", type=int, default=1, help="video frame-rate stride") + parser.add_argument("--retina-masks", action="store_true", help="whether to plot masks in native resolution") opt = parser.parse_args() opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand print_args(vars(opt)) @@ -276,10 +293,10 @@ def parse_opt(): def main(opt): - check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) run(**vars(opt)) -if __name__ == '__main__': +if __name__ == "__main__": opt = parse_opt() main(opt) diff --git a/segment/train.py b/segment/train.py index ea7e7bf99b..3535d5bcb7 100644 --- a/segment/train.py +++ b/segment/train.py @@ -1,7 +1,7 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Train a YOLOv3 segment model on a segment dataset -Models and datasets download automatically from the latest YOLOv3 release. +Train a YOLOv3 segment model on a segment dataset Models and datasets download automatically from the latest YOLOv3 +release. Usage - Single-GPU training: $ python segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 # from pretrained (recommended) @@ -47,47 +47,104 @@ from utils.autobatch import check_train_batch_size from utils.callbacks import Callbacks from utils.downloads import attempt_download, is_url -from utils.general import (LOGGER, TQDM_BAR_FORMAT, check_amp, check_dataset, check_file, check_git_info, - check_git_status, check_img_size, check_requirements, check_suffix, check_yaml, colorstr, - get_latest_run, increment_path, init_seeds, intersect_dicts, labels_to_class_weights, - labels_to_image_weights, one_cycle, print_args, print_mutation, strip_optimizer, yaml_save) +from utils.general import ( + LOGGER, + TQDM_BAR_FORMAT, + check_amp, + check_dataset, + check_file, + check_git_info, + check_git_status, + check_img_size, + check_requirements, + check_suffix, + check_yaml, + colorstr, + get_latest_run, + increment_path, + init_seeds, + intersect_dicts, + labels_to_class_weights, + labels_to_image_weights, + one_cycle, + print_args, + print_mutation, + strip_optimizer, + yaml_save, +) from utils.loggers import GenericLogger from utils.plots import plot_evolve, plot_labels from utils.segment.dataloaders import create_dataloader from utils.segment.loss import ComputeLoss from utils.segment.metrics import KEYS, fitness from utils.segment.plots import plot_images_and_masks, plot_results_with_masks -from utils.torch_utils import (EarlyStopping, ModelEMA, de_parallel, select_device, smart_DDP, smart_optimizer, - smart_resume, torch_distributed_zero_first) - -LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html -RANK = int(os.getenv('RANK', -1)) -WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +from utils.torch_utils import ( + EarlyStopping, + ModelEMA, + de_parallel, + select_device, + smart_DDP, + smart_optimizer, + smart_resume, + torch_distributed_zero_first, +) + +LOCAL_RANK = int(os.getenv("LOCAL_RANK", -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv("RANK", -1)) +WORLD_SIZE = int(os.getenv("WORLD_SIZE", 1)) GIT_INFO = check_git_info() def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary - save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze, mask_ratio = \ - Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ - opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze, opt.mask_ratio + ( + save_dir, + epochs, + batch_size, + weights, + single_cls, + evolve, + data, + cfg, + resume, + noval, + nosave, + workers, + freeze, + mask_ratio, + ) = ( + Path(opt.save_dir), + opt.epochs, + opt.batch_size, + opt.weights, + opt.single_cls, + opt.evolve, + opt.data, + opt.cfg, + opt.resume, + opt.noval, + opt.nosave, + opt.workers, + opt.freeze, + opt.mask_ratio, + ) # callbacks.run('on_pretrain_routine_start') # Directories - w = save_dir / 'weights' # weights dir + w = save_dir / "weights" # weights dir (w.parent if evolve else w).mkdir(parents=True, exist_ok=True) # make dir - last, best = w / 'last.pt', w / 'best.pt' + last, best = w / "last.pt", w / "best.pt" # Hyperparameters if isinstance(hyp, str): - with open(hyp, errors='ignore') as f: + with open(hyp, errors="ignore") as f: hyp = yaml.safe_load(f) # load hyps dict - LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) + LOGGER.info(colorstr("hyperparameters: ") + ", ".join(f"{k}={v}" for k, v in hyp.items())) opt.hyp = hyp.copy() # for saving hyps to checkpoints # Save run settings if not evolve: - yaml_save(save_dir / 'hyp.yaml', hyp) - yaml_save(save_dir / 'opt.yaml', vars(opt)) + yaml_save(save_dir / "hyp.yaml", hyp) + yaml_save(save_dir / "opt.yaml", vars(opt)) # Loggers data_dict = None @@ -97,39 +154,39 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Config plots = not evolve and not opt.noplots # create plots overlap = not opt.no_overlap - cuda = device.type != 'cpu' + cuda = device.type != "cpu" init_seeds(opt.seed + 1 + RANK, deterministic=True) with torch_distributed_zero_first(LOCAL_RANK): data_dict = data_dict or check_dataset(data) # check if None - train_path, val_path = data_dict['train'], data_dict['val'] - nc = 1 if single_cls else int(data_dict['nc']) # number of classes - names = {0: 'item'} if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names - is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO dataset + train_path, val_path = data_dict["train"], data_dict["val"] + nc = 1 if single_cls else int(data_dict["nc"]) # number of classes + names = {0: "item"} if single_cls and len(data_dict["names"]) != 1 else data_dict["names"] # class names + is_coco = isinstance(val_path, str) and val_path.endswith("coco/val2017.txt") # COCO dataset # Model - check_suffix(weights, '.pt') # check weights - pretrained = weights.endswith('.pt') + check_suffix(weights, ".pt") # check weights + pretrained = weights.endswith(".pt") if pretrained: with torch_distributed_zero_first(LOCAL_RANK): weights = attempt_download(weights) # download if not found locally - ckpt = torch.load(weights, map_location='cpu') # load checkpoint to CPU to avoid CUDA memory leak - model = SegmentationModel(cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) - exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else [] # exclude keys - csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 + ckpt = torch.load(weights, map_location="cpu") # load checkpoint to CPU to avoid CUDA memory leak + model = SegmentationModel(cfg or ckpt["model"].yaml, ch=3, nc=nc, anchors=hyp.get("anchors")).to(device) + exclude = ["anchor"] if (cfg or hyp.get("anchors")) and not resume else [] # exclude keys + csd = ckpt["model"].float().state_dict() # checkpoint state_dict as FP32 csd = intersect_dicts(csd, model.state_dict(), exclude=exclude) # intersect model.load_state_dict(csd, strict=False) # load - LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}') # report + LOGGER.info(f"Transferred {len(csd)}/{len(model.state_dict())} items from {weights}") # report else: - model = SegmentationModel(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create + model = SegmentationModel(cfg, ch=3, nc=nc, anchors=hyp.get("anchors")).to(device) # create amp = check_amp(model) # check AMP # Freeze - freeze = [f'model.{x}.' for x in (freeze if len(freeze) > 1 else range(freeze[0]))] # layers to freeze + freeze = [f"model.{x}." for x in (freeze if len(freeze) > 1 else range(freeze[0]))] # layers to freeze for k, v in model.named_parameters(): v.requires_grad = True # train all layers # v.register_hook(lambda x: torch.nan_to_num(x)) # NaN to 0 (commented for erratic training results) if any(x in k for x in freeze): - LOGGER.info(f'freezing {k}') + LOGGER.info(f"freezing {k}") v.requires_grad = False # Image size @@ -139,20 +196,20 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Batch size if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size batch_size = check_train_batch_size(model, imgsz, amp) - logger.update_params({'batch_size': batch_size}) + logger.update_params({"batch_size": batch_size}) # loggers.on_params_update({"batch_size": batch_size}) # Optimizer nbs = 64 # nominal batch size accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing - hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay - optimizer = smart_optimizer(model, opt.optimizer, hyp['lr0'], hyp['momentum'], hyp['weight_decay']) + hyp["weight_decay"] *= batch_size * accumulate / nbs # scale weight_decay + optimizer = smart_optimizer(model, opt.optimizer, hyp["lr0"], hyp["momentum"], hyp["weight_decay"]) # Scheduler if opt.cos_lr: - lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] + lf = one_cycle(1, hyp["lrf"], epochs) # cosine 1->hyp['lrf'] else: - lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear + lf = lambda x: (1 - x / epochs) * (1.0 - hyp["lrf"]) + hyp["lrf"] # linear scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) # EMA @@ -168,15 +225,15 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # DP mode if cuda and RANK == -1 and torch.cuda.device_count() > 1: LOGGER.warning( - 'WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n' - 'See Multi-GPU Tutorial at https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training to get started.' + "WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n" + "See Multi-GPU Tutorial at https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training to get started." ) model = torch.nn.DataParallel(model) # SyncBatchNorm if opt.sync_bn and cuda and RANK != -1: model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) - LOGGER.info('Using SyncBatchNorm()') + LOGGER.info("Using SyncBatchNorm()") # Trainloader train_loader, dataset = create_dataloader( @@ -187,41 +244,43 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio single_cls, hyp=hyp, augment=True, - cache=None if opt.cache == 'val' else opt.cache, + cache=None if opt.cache == "val" else opt.cache, rect=opt.rect, rank=LOCAL_RANK, workers=workers, image_weights=opt.image_weights, quad=opt.quad, - prefix=colorstr('train: '), + prefix=colorstr("train: "), shuffle=True, mask_downsample_ratio=mask_ratio, overlap_mask=overlap, ) labels = np.concatenate(dataset.labels, 0) mlc = int(labels[:, 0].max()) # max label class - assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}' + assert mlc < nc, f"Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}" # Process 0 if RANK in {-1, 0}: - val_loader = create_dataloader(val_path, - imgsz, - batch_size // WORLD_SIZE * 2, - gs, - single_cls, - hyp=hyp, - cache=None if noval else opt.cache, - rect=True, - rank=-1, - workers=workers * 2, - pad=0.5, - mask_downsample_ratio=mask_ratio, - overlap_mask=overlap, - prefix=colorstr('val: '))[0] + val_loader = create_dataloader( + val_path, + imgsz, + batch_size // WORLD_SIZE * 2, + gs, + single_cls, + hyp=hyp, + cache=None if noval else opt.cache, + rect=True, + rank=-1, + workers=workers * 2, + pad=0.5, + mask_downsample_ratio=mask_ratio, + overlap_mask=overlap, + prefix=colorstr("val: "), + )[0] if not resume: if not opt.noautoanchor: - check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) # run AutoAnchor + check_anchors(dataset, model=model, thr=hyp["anchor_t"], imgsz=imgsz) # run AutoAnchor model.half().float() # pre-reduce anchor precision if plots: @@ -234,10 +293,10 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Model attributes nl = de_parallel(model).model[-1].nl # number of detection layers (to scale hyps) - hyp['box'] *= 3 / nl # scale to layers - hyp['cls'] *= nc / 80 * 3 / nl # scale to classes and layers - hyp['obj'] *= (imgsz / 640) ** 2 * 3 / nl # scale to image size and layers - hyp['label_smoothing'] = opt.label_smoothing + hyp["box"] *= 3 / nl # scale to layers + hyp["cls"] *= nc / 80 * 3 / nl # scale to classes and layers + hyp["obj"] *= (imgsz / 640) ** 2 * 3 / nl # scale to image size and layers + hyp["label_smoothing"] = opt.label_smoothing model.nc = nc # attach number of classes to model model.hyp = hyp # attach hyperparameters to model model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights @@ -246,7 +305,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Start training t0 = time.time() nb = len(train_loader) # number of batches - nw = max(round(hyp['warmup_epochs'] * nb), 100) # number of warmup iterations, max(3 epochs, 100 iterations) + nw = max(round(hyp["warmup_epochs"] * nb), 100) # number of warmup iterations, max(3 epochs, 100 iterations) # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training last_opt_step = -1 maps = np.zeros(nc) # mAP per class @@ -256,10 +315,12 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio stopper, stop = EarlyStopping(patience=opt.patience), False compute_loss = ComputeLoss(model, overlap=overlap) # init loss class # callbacks.run('on_train_start') - LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n' - f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' - f"Logging results to {colorstr('bold', save_dir)}\n" - f'Starting training for {epochs} epochs...') + LOGGER.info( + f'Image sizes {imgsz} train, {imgsz} val\n' + f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' + f"Logging results to {colorstr('bold', save_dir)}\n" + f'Starting training for {epochs} epochs...' + ) for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ # callbacks.run('on_train_epoch_start') model.train() @@ -278,8 +339,10 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio if RANK != -1: train_loader.sampler.set_epoch(epoch) pbar = enumerate(train_loader) - LOGGER.info(('\n' + '%11s' * 8) % - ('Epoch', 'GPU_mem', 'box_loss', 'seg_loss', 'obj_loss', 'cls_loss', 'Instances', 'Size')) + LOGGER.info( + ("\n" + "%11s" * 8) + % ("Epoch", "GPU_mem", "box_loss", "seg_loss", "obj_loss", "cls_loss", "Instances", "Size") + ) if RANK in {-1, 0}: pbar = tqdm(pbar, total=nb, bar_format=TQDM_BAR_FORMAT) # progress bar optimizer.zero_grad() @@ -295,9 +358,9 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round()) for j, x in enumerate(optimizer.param_groups): # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 - x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 0 else 0.0, x['initial_lr'] * lf(epoch)]) - if 'momentum' in x: - x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) + x["lr"] = np.interp(ni, xi, [hyp["warmup_bias_lr"] if j == 0 else 0.0, x["initial_lr"] * lf(epoch)]) + if "momentum" in x: + x["momentum"] = np.interp(ni, xi, [hyp["warmup_momentum"], hyp["momentum"]]) # Multi-scale if opt.multi_scale: @@ -305,7 +368,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio sf = sz / max(imgs.shape[2:]) # scale factor if sf != 1: ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) - imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) + imgs = nn.functional.interpolate(imgs, size=ns, mode="bilinear", align_corners=False) # Forward with torch.cuda.amp.autocast(amp): @@ -314,7 +377,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio if RANK != -1: loss *= WORLD_SIZE # gradient averaged between devices in DDP mode if opt.quad: - loss *= 4. + loss *= 4.0 # Backward scaler.scale(loss).backward() @@ -333,9 +396,11 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Log if RANK in {-1, 0}: mloss = (mloss * i + loss_items) / (i + 1) # update mean losses - mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G' # (GB) - pbar.set_description(('%11s' * 2 + '%11.4g' * 6) % - (f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])) + mem = f"{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G" # (GB) + pbar.set_description( + ("%11s" * 2 + "%11.4g" * 6) + % (f"{epoch}/{epochs - 1}", mem, *mloss, targets.shape[0], imgs.shape[-1]) + ) # callbacks.run('on_train_batch_end', model, ni, imgs, targets, paths) # if callbacks.stop_training: # return @@ -343,35 +408,37 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Mosaic plots if plots: if ni < 3: - plot_images_and_masks(imgs, targets, masks, paths, save_dir / f'train_batch{ni}.jpg') + plot_images_and_masks(imgs, targets, masks, paths, save_dir / f"train_batch{ni}.jpg") if ni == 10: - files = sorted(save_dir.glob('train*.jpg')) - logger.log_images(files, 'Mosaics', epoch) + files = sorted(save_dir.glob("train*.jpg")) + logger.log_images(files, "Mosaics", epoch) # end batch ------------------------------------------------------------------------------------------------ # Scheduler - lr = [x['lr'] for x in optimizer.param_groups] # for loggers + lr = [x["lr"] for x in optimizer.param_groups] # for loggers scheduler.step() if RANK in {-1, 0}: # mAP # callbacks.run('on_train_epoch_end', epoch=epoch) - ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights']) + ema.update_attr(model, include=["yaml", "nc", "hyp", "names", "stride", "class_weights"]) final_epoch = (epoch + 1 == epochs) or stopper.possible_stop if not noval or final_epoch: # Calculate mAP - results, maps, _ = validate.run(data_dict, - batch_size=batch_size // WORLD_SIZE * 2, - imgsz=imgsz, - half=amp, - model=ema.ema, - single_cls=single_cls, - dataloader=val_loader, - save_dir=save_dir, - plots=False, - callbacks=callbacks, - compute_loss=compute_loss, - mask_downsample_ratio=mask_ratio, - overlap=overlap) + results, maps, _ = validate.run( + data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + half=amp, + model=ema.ema, + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + plots=False, + callbacks=callbacks, + compute_loss=compute_loss, + mask_downsample_ratio=mask_ratio, + overlap=overlap, + ) # Update best mAP fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] @@ -387,23 +454,24 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Save model if (not nosave) or (final_epoch and not evolve): # if save ckpt = { - 'epoch': epoch, - 'best_fitness': best_fitness, - 'model': deepcopy(de_parallel(model)).half(), - 'ema': deepcopy(ema.ema).half(), - 'updates': ema.updates, - 'optimizer': optimizer.state_dict(), - 'opt': vars(opt), - 'git': GIT_INFO, # {remote, branch, commit} if a git repo - 'date': datetime.now().isoformat()} + "epoch": epoch, + "best_fitness": best_fitness, + "model": deepcopy(de_parallel(model)).half(), + "ema": deepcopy(ema.ema).half(), + "updates": ema.updates, + "optimizer": optimizer.state_dict(), + "opt": vars(opt), + "git": GIT_INFO, # {remote, branch, commit} if a git repo + "date": datetime.now().isoformat(), + } # Save last, best and delete torch.save(ckpt, last) if best_fitness == fi: torch.save(ckpt, best) if opt.save_period > 0 and epoch % opt.save_period == 0: - torch.save(ckpt, w / f'epoch{epoch}.pt') - logger.log_model(w / f'epoch{epoch}.pt') + torch.save(ckpt, w / f"epoch{epoch}.pt") + logger.log_model(w / f"epoch{epoch}.pt") del ckpt # callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi) @@ -419,12 +487,12 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # end epoch ---------------------------------------------------------------------------------------------------- # end training ----------------------------------------------------------------------------------------------------- if RANK in {-1, 0}: - LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.') + LOGGER.info(f"\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.") for f in last, best: if f.exists(): strip_optimizer(f) # strip optimizers if f is best: - LOGGER.info(f'\nValidating {f}...') + LOGGER.info(f"\nValidating {f}...") results, _, _ = validate.run( data_dict, batch_size=batch_size // WORLD_SIZE * 2, @@ -440,7 +508,8 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio callbacks=callbacks, compute_loss=compute_loss, mask_downsample_ratio=mask_ratio, - overlap=overlap) # val best model with plots + overlap=overlap, + ) # val best model with plots if is_coco: # callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi) metrics_dict = dict(zip(KEYS, list(mloss) + list(results) + lr)) @@ -452,56 +521,56 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio if not opt.evolve: logger.log_model(best, epoch) if plots: - plot_results_with_masks(file=save_dir / 'results.csv') # save results.png - files = ['results.png', 'confusion_matrix.png', *(f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R'))] + plot_results_with_masks(file=save_dir / "results.csv") # save results.png + files = ["results.png", "confusion_matrix.png", *(f"{x}_curve.png" for x in ("F1", "PR", "P", "R"))] files = [(save_dir / f) for f in files if (save_dir / f).exists()] # filter LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}") - logger.log_images(files, 'Results', epoch + 1) - logger.log_images(sorted(save_dir.glob('val*.jpg')), 'Validation', epoch + 1) + logger.log_images(files, "Results", epoch + 1) + logger.log_images(sorted(save_dir.glob("val*.jpg")), "Validation", epoch + 1) torch.cuda.empty_cache() return results def parse_opt(known=False): parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s-seg.pt', help='initial weights path') - parser.add_argument('--cfg', type=str, default='', help='model.yaml path') - parser.add_argument('--data', type=str, default=ROOT / 'data/coco128-seg.yaml', help='dataset.yaml path') - parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path') - parser.add_argument('--epochs', type=int, default=100, help='total training epochs') - parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') - parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') - parser.add_argument('--rect', action='store_true', help='rectangular training') - parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') - parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') - parser.add_argument('--noval', action='store_true', help='only validate final epoch') - parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') - parser.add_argument('--noplots', action='store_true', help='save no plot files') - parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') - parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') - parser.add_argument('--cache', type=str, nargs='?', const='ram', help='image --cache ram/disk') - parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') - parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') - parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer') - parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') - parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') - parser.add_argument('--project', default=ROOT / 'runs/train-seg', help='save to project/name') - parser.add_argument('--name', default='exp', help='save to project/name') - parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') - parser.add_argument('--quad', action='store_true', help='quad dataloader') - parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') - parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') - parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') - parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') - parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') - parser.add_argument('--seed', type=int, default=0, help='Global training seed') - parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + parser.add_argument("--weights", type=str, default=ROOT / "yolov5s-seg.pt", help="initial weights path") + parser.add_argument("--cfg", type=str, default="", help="model.yaml path") + parser.add_argument("--data", type=str, default=ROOT / "data/coco128-seg.yaml", help="dataset.yaml path") + parser.add_argument("--hyp", type=str, default=ROOT / "data/hyps/hyp.scratch-low.yaml", help="hyperparameters path") + parser.add_argument("--epochs", type=int, default=100, help="total training epochs") + parser.add_argument("--batch-size", type=int, default=16, help="total batch size for all GPUs, -1 for autobatch") + parser.add_argument("--imgsz", "--img", "--img-size", type=int, default=640, help="train, val image size (pixels)") + parser.add_argument("--rect", action="store_true", help="rectangular training") + parser.add_argument("--resume", nargs="?", const=True, default=False, help="resume most recent training") + parser.add_argument("--nosave", action="store_true", help="only save final checkpoint") + parser.add_argument("--noval", action="store_true", help="only validate final epoch") + parser.add_argument("--noautoanchor", action="store_true", help="disable AutoAnchor") + parser.add_argument("--noplots", action="store_true", help="save no plot files") + parser.add_argument("--evolve", type=int, nargs="?", const=300, help="evolve hyperparameters for x generations") + parser.add_argument("--bucket", type=str, default="", help="gsutil bucket") + parser.add_argument("--cache", type=str, nargs="?", const="ram", help="image --cache ram/disk") + parser.add_argument("--image-weights", action="store_true", help="use weighted image selection for training") + parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu") + parser.add_argument("--multi-scale", action="store_true", help="vary img-size +/- 50%%") + parser.add_argument("--single-cls", action="store_true", help="train multi-class data as single-class") + parser.add_argument("--optimizer", type=str, choices=["SGD", "Adam", "AdamW"], default="SGD", help="optimizer") + parser.add_argument("--sync-bn", action="store_true", help="use SyncBatchNorm, only available in DDP mode") + parser.add_argument("--workers", type=int, default=8, help="max dataloader workers (per RANK in DDP mode)") + parser.add_argument("--project", default=ROOT / "runs/train-seg", help="save to project/name") + parser.add_argument("--name", default="exp", help="save to project/name") + parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment") + parser.add_argument("--quad", action="store_true", help="quad dataloader") + parser.add_argument("--cos-lr", action="store_true", help="cosine LR scheduler") + parser.add_argument("--label-smoothing", type=float, default=0.0, help="Label smoothing epsilon") + parser.add_argument("--patience", type=int, default=100, help="EarlyStopping patience (epochs without improvement)") + parser.add_argument("--freeze", nargs="+", type=int, default=[0], help="Freeze layers: backbone=10, first3=0 1 2") + parser.add_argument("--save-period", type=int, default=-1, help="Save checkpoint every x epochs (disabled if < 1)") + parser.add_argument("--seed", type=int, default=0, help="Global training seed") + parser.add_argument("--local_rank", type=int, default=-1, help="Automatic DDP Multi-GPU argument, do not modify") # Instance Segmentation Args - parser.add_argument('--mask-ratio', type=int, default=4, help='Downsample the truth masks to saving memory') - parser.add_argument('--no-overlap', action='store_true', help='Overlap masks train faster at slightly less mAP') + parser.add_argument("--mask-ratio", type=int, default=4, help="Downsample the truth masks to saving memory") + parser.add_argument("--no-overlap", action="store_true", help="Overlap masks train faster at slightly less mAP") return parser.parse_known_args()[0] if known else parser.parse_args() @@ -511,46 +580,51 @@ def main(opt, callbacks=Callbacks()): if RANK in {-1, 0}: print_args(vars(opt)) check_git_status() - check_requirements(ROOT / 'requirements.txt') + check_requirements(ROOT / "requirements.txt") # Resume if opt.resume and not opt.evolve: # resume from specified or most recent last.pt last = Path(check_file(opt.resume) if isinstance(opt.resume, str) else get_latest_run()) - opt_yaml = last.parent.parent / 'opt.yaml' # train options yaml + opt_yaml = last.parent.parent / "opt.yaml" # train options yaml opt_data = opt.data # original dataset if opt_yaml.is_file(): - with open(opt_yaml, errors='ignore') as f: + with open(opt_yaml, errors="ignore") as f: d = yaml.safe_load(f) else: - d = torch.load(last, map_location='cpu')['opt'] + d = torch.load(last, map_location="cpu")["opt"] opt = argparse.Namespace(**d) # replace - opt.cfg, opt.weights, opt.resume = '', str(last), True # reinstate + opt.cfg, opt.weights, opt.resume = "", str(last), True # reinstate if is_url(opt_data): opt.data = check_file(opt_data) # avoid HUB resume auth timeout else: - opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \ - check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks - assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' + opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = ( + check_file(opt.data), + check_yaml(opt.cfg), + check_yaml(opt.hyp), + str(opt.weights), + str(opt.project), + ) # checks + assert len(opt.cfg) or len(opt.weights), "either --cfg or --weights must be specified" if opt.evolve: - if opt.project == str(ROOT / 'runs/train-seg'): # if default project name, rename to runs/evolve-seg - opt.project = str(ROOT / 'runs/evolve-seg') + if opt.project == str(ROOT / "runs/train-seg"): # if default project name, rename to runs/evolve-seg + opt.project = str(ROOT / "runs/evolve-seg") opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume - if opt.name == 'cfg': + if opt.name == "cfg": opt.name = Path(opt.cfg).stem # use model.yaml as name opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) # DDP mode device = select_device(opt.device, batch_size=opt.batch_size) if LOCAL_RANK != -1: - msg = 'is not compatible with YOLOv3 Multi-GPU DDP training' - assert not opt.image_weights, f'--image-weights {msg}' - assert not opt.evolve, f'--evolve {msg}' - assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size' - assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' - assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' + msg = "is not compatible with YOLOv3 Multi-GPU DDP training" + assert not opt.image_weights, f"--image-weights {msg}" + assert not opt.evolve, f"--evolve {msg}" + assert opt.batch_size != -1, f"AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size" + assert opt.batch_size % WORLD_SIZE == 0, f"--batch-size {opt.batch_size} must be multiple of WORLD_SIZE" + assert torch.cuda.device_count() > LOCAL_RANK, "insufficient CUDA devices for DDP command" torch.cuda.set_device(LOCAL_RANK) - device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend='nccl' if dist.is_nccl_available() else 'gloo') + device = torch.device("cuda", LOCAL_RANK) + dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") # Train if not opt.evolve: @@ -560,65 +634,69 @@ def main(opt, callbacks=Callbacks()): else: # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) meta = { - 'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) - 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) - 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 - 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay - 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) - 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum - 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr - 'box': (1, 0.02, 0.2), # box loss gain - 'cls': (1, 0.2, 4.0), # cls loss gain - 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight - 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) - 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight - 'iou_t': (0, 0.1, 0.7), # IoU training threshold - 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold - 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) - 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) - 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) - 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) - 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) - 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) - 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) - 'scale': (1, 0.0, 0.9), # image scale (+/- gain) - 'shear': (1, 0.0, 10.0), # image shear (+/- deg) - 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 - 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) - 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) - 'mosaic': (1, 0.0, 1.0), # image mixup (probability) - 'mixup': (1, 0.0, 1.0), # image mixup (probability) - 'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) - - with open(opt.hyp, errors='ignore') as f: + "lr0": (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) + "lrf": (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) + "momentum": (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 + "weight_decay": (1, 0.0, 0.001), # optimizer weight decay + "warmup_epochs": (1, 0.0, 5.0), # warmup epochs (fractions ok) + "warmup_momentum": (1, 0.0, 0.95), # warmup initial momentum + "warmup_bias_lr": (1, 0.0, 0.2), # warmup initial bias lr + "box": (1, 0.02, 0.2), # box loss gain + "cls": (1, 0.2, 4.0), # cls loss gain + "cls_pw": (1, 0.5, 2.0), # cls BCELoss positive_weight + "obj": (1, 0.2, 4.0), # obj loss gain (scale with pixels) + "obj_pw": (1, 0.5, 2.0), # obj BCELoss positive_weight + "iou_t": (0, 0.1, 0.7), # IoU training threshold + "anchor_t": (1, 2.0, 8.0), # anchor-multiple threshold + "anchors": (2, 2.0, 10.0), # anchors per output grid (0 to ignore) + "fl_gamma": (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) + "hsv_h": (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) + "hsv_s": (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) + "hsv_v": (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) + "degrees": (1, 0.0, 45.0), # image rotation (+/- deg) + "translate": (1, 0.0, 0.9), # image translation (+/- fraction) + "scale": (1, 0.0, 0.9), # image scale (+/- gain) + "shear": (1, 0.0, 10.0), # image shear (+/- deg) + "perspective": (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 + "flipud": (1, 0.0, 1.0), # image flip up-down (probability) + "fliplr": (0, 0.0, 1.0), # image flip left-right (probability) + "mosaic": (1, 0.0, 1.0), # image mixup (probability) + "mixup": (1, 0.0, 1.0), # image mixup (probability) + "copy_paste": (1, 0.0, 1.0), + } # segment copy-paste (probability) + + with open(opt.hyp, errors="ignore") as f: hyp = yaml.safe_load(f) # load hyps dict - if 'anchors' not in hyp: # anchors commented in hyp.yaml - hyp['anchors'] = 3 + if "anchors" not in hyp: # anchors commented in hyp.yaml + hyp["anchors"] = 3 if opt.noautoanchor: - del hyp['anchors'], meta['anchors'] + del hyp["anchors"], meta["anchors"] opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir) # only val/save final epoch # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices - evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' + evolve_yaml, evolve_csv = save_dir / "hyp_evolve.yaml", save_dir / "evolve.csv" if opt.bucket: # download evolve.csv if exists - subprocess.run([ - 'gsutil', - 'cp', - f'gs://{opt.bucket}/evolve.csv', - str(evolve_csv), ]) + subprocess.run( + [ + "gsutil", + "cp", + f"gs://{opt.bucket}/evolve.csv", + str(evolve_csv), + ] + ) for _ in range(opt.evolve): # generations to evolve if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate # Select parent(s) - parent = 'single' # parent selection method: 'single' or 'weighted' - x = np.loadtxt(evolve_csv, ndmin=2, delimiter=',', skiprows=1) + parent = "single" # parent selection method: 'single' or 'weighted' + x = np.loadtxt(evolve_csv, ndmin=2, delimiter=",", skiprows=1) n = min(5, len(x)) # number of previous results to consider x = x[np.argsort(-fitness(x))][:n] # top n mutations - w = fitness(x) - fitness(x).min() + 1E-6 # weights (sum > 0) - if parent == 'single' or len(x) == 1: + w = fitness(x) - fitness(x).min() + 1e-6 # weights (sum > 0) + if parent == "single" or len(x) == 1: # x = x[random.randint(0, n - 1)] # random selection x = x[random.choices(range(n), weights=w)[0]] # weighted selection - elif parent == 'weighted': + elif parent == "weighted": x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination # Mutate @@ -647,9 +725,11 @@ def main(opt, callbacks=Callbacks()): # Plot results plot_evolve(evolve_csv) - LOGGER.info(f'Hyperparameter evolution finished {opt.evolve} generations\n' - f"Results saved to {colorstr('bold', save_dir)}\n" - f'Usage example: $ python train.py --hyp {evolve_yaml}') + LOGGER.info( + f'Hyperparameter evolution finished {opt.evolve} generations\n' + f"Results saved to {colorstr('bold', save_dir)}\n" + f'Usage example: $ python train.py --hyp {evolve_yaml}' + ) def run(**kwargs): @@ -661,6 +741,6 @@ def run(**kwargs): return opt -if __name__ == '__main__': +if __name__ == "__main__": opt = parse_opt() main(opt) diff --git a/segment/val.py b/segment/val.py index 87d6ca791c..28f7e5125e 100644 --- a/segment/val.py +++ b/segment/val.py @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Validate a trained YOLOv3 segment model on a segment dataset +Validate a trained YOLOv3 segment model on a segment dataset. Usage: $ bash data/scripts/get_coco.sh --val --segments # download COCO-segments val split (1G, 5000 images) @@ -43,9 +43,24 @@ from models.common import DetectMultiBackend from models.yolo import SegmentationModel from utils.callbacks import Callbacks -from utils.general import (LOGGER, NUM_THREADS, TQDM_BAR_FORMAT, Profile, check_dataset, check_img_size, - check_requirements, check_yaml, coco80_to_coco91_class, colorstr, increment_path, - non_max_suppression, print_args, scale_boxes, xywh2xyxy, xyxy2xywh) +from utils.general import ( + LOGGER, + NUM_THREADS, + TQDM_BAR_FORMAT, + Profile, + check_dataset, + check_img_size, + check_requirements, + check_yaml, + coco80_to_coco91_class, + colorstr, + increment_path, + non_max_suppression, + print_args, + scale_boxes, + xywh2xyxy, + xyxy2xywh, +) from utils.metrics import ConfusionMatrix, box_iou from utils.plots import output_to_target, plot_val_study from utils.segment.dataloaders import create_dataloader @@ -61,8 +76,8 @@ def save_one_txt(predn, save_conf, shape, file): for *xyxy, conf, cls in predn.tolist(): xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format - with open(file, 'a') as f: - f.write(('%g ' * len(line)).rstrip() % line + '\n') + with open(file, "a") as f: + f.write(("%g " * len(line)).rstrip() % line + "\n") def save_one_json(predn, jdict, path, class_map, pred_masks): @@ -70,8 +85,8 @@ def save_one_json(predn, jdict, path, class_map, pred_masks): from pycocotools.mask import encode def single_encode(x): - rle = encode(np.asarray(x[:, :, None], order='F', dtype='uint8'))[0] - rle['counts'] = rle['counts'].decode('utf-8') + rle = encode(np.asarray(x[:, :, None], order="F", dtype="uint8"))[0] + rle["counts"] = rle["counts"].decode("utf-8") return rle image_id = int(path.stem) if path.stem.isnumeric() else path.stem @@ -81,12 +96,15 @@ def single_encode(x): with ThreadPool(NUM_THREADS) as pool: rles = pool.map(single_encode, pred_masks) for i, (p, b) in enumerate(zip(predn.tolist(), box.tolist())): - jdict.append({ - 'image_id': image_id, - 'category_id': class_map[int(p[5])], - 'bbox': [round(x, 3) for x in b], - 'score': round(p[4], 5), - 'segmentation': rles[i]}) + jdict.append( + { + "image_id": image_id, + "category_id": class_map[int(p[5])], + "bbox": [round(x, 3) for x in b], + "score": round(p[4], 5), + "segmentation": rles[i], + } + ) def process_batch(detections, labels, iouv, pred_masks=None, gt_masks=None, overlap=False, masks=False): @@ -105,7 +123,7 @@ def process_batch(detections, labels, iouv, pred_masks=None, gt_masks=None, over gt_masks = gt_masks.repeat(nl, 1, 1) # shape(1,640,640) -> (n,640,640) gt_masks = torch.where(gt_masks == index, 1.0, 0.0) if gt_masks.shape[1:] != pred_masks.shape[1:]: - gt_masks = F.interpolate(gt_masks[None], pred_masks.shape[1:], mode='bilinear', align_corners=False)[0] + gt_masks = F.interpolate(gt_masks[None], pred_masks.shape[1:], mode="bilinear", align_corners=False)[0] gt_masks = gt_masks.gt_(0.5) iou = mask_iou(gt_masks.view(gt_masks.shape[0], -1), pred_masks.view(pred_masks.shape[0], -1)) else: # boxes @@ -128,39 +146,39 @@ def process_batch(detections, labels, iouv, pred_masks=None, gt_masks=None, over @smart_inference_mode() def run( - data, - weights=None, # model.pt path(s) - batch_size=32, # batch size - imgsz=640, # inference size (pixels) - conf_thres=0.001, # confidence threshold - iou_thres=0.6, # NMS IoU threshold - max_det=300, # maximum detections per image - task='val', # train, val, test, speed or study - device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu - workers=8, # max dataloader workers (per RANK in DDP mode) - single_cls=False, # treat as single-class dataset - augment=False, # augmented inference - verbose=False, # verbose output - save_txt=False, # save results to *.txt - save_hybrid=False, # save label+prediction hybrid results to *.txt - save_conf=False, # save confidences in --save-txt labels - save_json=False, # save a COCO-JSON results file - project=ROOT / 'runs/val-seg', # save to project/name - name='exp', # save to project/name - exist_ok=False, # existing project/name ok, do not increment - half=True, # use FP16 half-precision inference - dnn=False, # use OpenCV DNN for ONNX inference - model=None, - dataloader=None, - save_dir=Path(''), - plots=True, - overlap=False, - mask_downsample_ratio=1, - compute_loss=None, - callbacks=Callbacks(), + data, + weights=None, # model.pt path(s) + batch_size=32, # batch size + imgsz=640, # inference size (pixels) + conf_thres=0.001, # confidence threshold + iou_thres=0.6, # NMS IoU threshold + max_det=300, # maximum detections per image + task="val", # train, val, test, speed or study + device="", # cuda device, i.e. 0 or 0,1,2,3 or cpu + workers=8, # max dataloader workers (per RANK in DDP mode) + single_cls=False, # treat as single-class dataset + augment=False, # augmented inference + verbose=False, # verbose output + save_txt=False, # save results to *.txt + save_hybrid=False, # save label+prediction hybrid results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_json=False, # save a COCO-JSON results file + project=ROOT / "runs/val-seg", # save to project/name + name="exp", # save to project/name + exist_ok=False, # existing project/name ok, do not increment + half=True, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + model=None, + dataloader=None, + save_dir=Path(""), + plots=True, + overlap=False, + mask_downsample_ratio=1, + compute_loss=None, + callbacks=Callbacks(), ): if save_json: - check_requirements('pycocotools>=2.0.6') + check_requirements("pycocotools>=2.0.6") process = process_mask_native # more accurate else: process = process_mask # faster @@ -169,7 +187,7 @@ def run( training = model is not None if training: # called by train.py device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model - half &= device.type != 'cpu' # half precision only supported on CUDA + half &= device.type != "cpu" # half precision only supported on CUDA model.half() if half else model.float() nm = de_parallel(model).model[-1].nm # number of masks else: # called directly @@ -177,7 +195,7 @@ def run( # Directories save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run - (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + (save_dir / "labels" if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir # Load model model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) @@ -191,16 +209,16 @@ def run( device = model.device if not (pt or jit): batch_size = 1 # export.py models default to batch-size 1 - LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') + LOGGER.info(f"Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models") # Data data = check_dataset(data) # check # Configure model.eval() - cuda = device.type != 'cpu' - is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'coco{os.sep}val2017.txt') # COCO dataset - nc = 1 if single_cls else int(data['nc']) # number of classes + cuda = device.type != "cpu" + is_coco = isinstance(data.get("val"), str) and data["val"].endswith(f"coco{os.sep}val2017.txt") # COCO dataset + nc = 1 if single_cls else int(data["nc"]) # number of classes iouv = torch.linspace(0.5, 0.95, 10, device=device) # iou vector for mAP@0.5:0.95 niou = iouv.numel() @@ -208,31 +226,46 @@ def run( if not training: if pt and not single_cls: # check --weights are trained on --data ncm = model.model.nc - assert ncm == nc, f'{weights} ({ncm} classes) trained on different --data than what you passed ({nc} ' \ - f'classes). Pass correct combination of --weights and --data that are trained together.' + assert ncm == nc, ( + f"{weights} ({ncm} classes) trained on different --data than what you passed ({nc} " + f"classes). Pass correct combination of --weights and --data that are trained together." + ) model.warmup(imgsz=(1 if pt else batch_size, 3, imgsz, imgsz)) # warmup - pad, rect = (0.0, False) if task == 'speed' else (0.5, pt) # square inference for benchmarks - task = task if task in ('train', 'val', 'test') else 'val' # path to train/val/test images - dataloader = create_dataloader(data[task], - imgsz, - batch_size, - stride, - single_cls, - pad=pad, - rect=rect, - workers=workers, - prefix=colorstr(f'{task}: '), - overlap_mask=overlap, - mask_downsample_ratio=mask_downsample_ratio)[0] + pad, rect = (0.0, False) if task == "speed" else (0.5, pt) # square inference for benchmarks + task = task if task in ("train", "val", "test") else "val" # path to train/val/test images + dataloader = create_dataloader( + data[task], + imgsz, + batch_size, + stride, + single_cls, + pad=pad, + rect=rect, + workers=workers, + prefix=colorstr(f"{task}: "), + overlap_mask=overlap, + mask_downsample_ratio=mask_downsample_ratio, + )[0] seen = 0 confusion_matrix = ConfusionMatrix(nc=nc) - names = model.names if hasattr(model, 'names') else model.module.names # get class names + names = model.names if hasattr(model, "names") else model.module.names # get class names if isinstance(names, (list, tuple)): # old format names = dict(enumerate(names)) class_map = coco80_to_coco91_class() if is_coco else list(range(1000)) - s = ('%22s' + '%11s' * 10) % ('Class', 'Images', 'Instances', 'Box(P', 'R', 'mAP50', 'mAP50-95)', 'Mask(P', 'R', - 'mAP50', 'mAP50-95)') + s = ("%22s" + "%11s" * 10) % ( + "Class", + "Images", + "Instances", + "Box(P", + "R", + "mAP50", + "mAP50-95)", + "Mask(P", + "R", + "mAP50", + "mAP50-95)", + ) dt = Profile(), Profile(), Profile() metrics = Metrics() loss = torch.zeros(4, device=device) @@ -263,14 +296,9 @@ def run( targets[:, 2:] *= torch.tensor((width, height, width, height), device=device) # to pixels lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling with dt[2]: - preds = non_max_suppression(preds, - conf_thres, - iou_thres, - labels=lb, - multi_label=True, - agnostic=single_cls, - max_det=max_det, - nm=nm) + preds = non_max_suppression( + preds, conf_thres, iou_thres, labels=lb, multi_label=True, agnostic=single_cls, max_det=max_det, nm=nm + ) # Metrics plot_masks = [] # masks for plotting @@ -317,10 +345,11 @@ def run( # Save/log if save_txt: - save_one_txt(predn, save_conf, shape, file=save_dir / 'labels' / f'{path.stem}.txt') + save_one_txt(predn, save_conf, shape, file=save_dir / "labels" / f"{path.stem}.txt") if save_json: - pred_masks = scale_image(im[si].shape[1:], - pred_masks.permute(1, 2, 0).contiguous().cpu().numpy(), shape, shapes[si][1]) + pred_masks = scale_image( + im[si].shape[1:], pred_masks.permute(1, 2, 0).contiguous().cpu().numpy(), shape, shapes[si][1] + ) save_one_json(predn, jdict, path, class_map, pred_masks) # append to COCO-JSON dictionary # callbacks.run('on_val_image_end', pred, predn, path, names, im[si]) @@ -328,9 +357,15 @@ def run( if plots and batch_i < 3: if len(plot_masks): plot_masks = torch.cat(plot_masks, dim=0) - plot_images_and_masks(im, targets, masks, paths, save_dir / f'val_batch{batch_i}_labels.jpg', names) - plot_images_and_masks(im, output_to_target(preds, max_det=15), plot_masks, paths, - save_dir / f'val_batch{batch_i}_pred.jpg', names) # pred + plot_images_and_masks(im, targets, masks, paths, save_dir / f"val_batch{batch_i}_labels.jpg", names) + plot_images_and_masks( + im, + output_to_target(preds, max_det=15), + plot_masks, + paths, + save_dir / f"val_batch{batch_i}_pred.jpg", + names, + ) # pred # callbacks.run('on_val_batch_end') @@ -342,10 +377,10 @@ def run( nt = np.bincount(stats[4].astype(int), minlength=nc) # number of targets per class # Print results - pf = '%22s' + '%11i' * 2 + '%11.3g' * 8 # print format - LOGGER.info(pf % ('all', seen, nt.sum(), *metrics.mean_results())) + pf = "%22s" + "%11i" * 2 + "%11.3g" * 8 # print format + LOGGER.info(pf % ("all", seen, nt.sum(), *metrics.mean_results())) if nt.sum() == 0: - LOGGER.warning(f'WARNING ⚠️ no labels found in {task} set, can not compute metrics without labels') + LOGGER.warning(f"WARNING ⚠️ no labels found in {task} set, can not compute metrics without labels") # Print results per class if (verbose or (nc < 50 and not training)) and nc > 1 and len(stats): @@ -353,10 +388,10 @@ def run( LOGGER.info(pf % (names[c], seen, nt[c], *metrics.class_result(i))) # Print speeds - t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + t = tuple(x.t / seen * 1e3 for x in dt) # speeds per image if not training: shape = (batch_size, 3, imgsz, imgsz) - LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {shape}' % t) + LOGGER.info(f"Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {shape}" % t) # Plots if plots: @@ -367,11 +402,11 @@ def run( # Save JSON if save_json and len(jdict): - w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights - anno_json = str(Path('../datasets/coco/annotations/instances_val2017.json')) # annotations - pred_json = str(save_dir / f'{w}_predictions.json') # predictions - LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') - with open(pred_json, 'w') as f: + w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else "" # weights + anno_json = str(Path("../datasets/coco/annotations/instances_val2017.json")) # annotations + pred_json = str(save_dir / f"{w}_predictions.json") # predictions + LOGGER.info(f"\nEvaluating pycocotools mAP... saving {pred_json}...") + with open(pred_json, "w") as f: json.dump(jdict, f) try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb @@ -381,7 +416,7 @@ def run( anno = COCO(anno_json) # init annotations api pred = anno.loadRes(pred_json) # init predictions api results = [] - for eval in COCOeval(anno, pred, 'bbox'), COCOeval(anno, pred, 'segm'): + for eval in COCOeval(anno, pred, "bbox"), COCOeval(anno, pred, "segm"): if is_coco: eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.im_files] # img ID to evaluate eval.evaluate() @@ -390,12 +425,12 @@ def run( results.extend(eval.stats[:2]) # update results (mAP@0.5:0.95, mAP@0.5) map_bbox, map50_bbox, map_mask, map50_mask = results except Exception as e: - LOGGER.info(f'pycocotools unable to run: {e}') + LOGGER.info(f"pycocotools unable to run: {e}") # Return results model.float() # for training if not training: - s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else "" LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") final_metric = mp_bbox, mr_bbox, map50_bbox, map_bbox, mp_mask, mr_mask, map50_mask, map_mask return (*final_metric, *(loss.cpu() / len(dataloader)).tolist()), metrics.get_maps(nc), t @@ -403,28 +438,28 @@ def run( def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--data', type=str, default=ROOT / 'data/coco128-seg.yaml', help='dataset.yaml path') - parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s-seg.pt', help='model path(s)') - parser.add_argument('--batch-size', type=int, default=32, help='batch size') - parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') - parser.add_argument('--conf-thres', type=float, default=0.001, help='confidence threshold') - parser.add_argument('--iou-thres', type=float, default=0.6, help='NMS IoU threshold') - parser.add_argument('--max-det', type=int, default=300, help='maximum detections per image') - parser.add_argument('--task', default='val', help='train, val, test, speed or study') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') - parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') - parser.add_argument('--augment', action='store_true', help='augmented inference') - parser.add_argument('--verbose', action='store_true', help='report mAP by class') - parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') - parser.add_argument('--save-hybrid', action='store_true', help='save label+prediction hybrid results to *.txt') - parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') - parser.add_argument('--save-json', action='store_true', help='save a COCO-JSON results file') - parser.add_argument('--project', default=ROOT / 'runs/val-seg', help='save results to project/name') - parser.add_argument('--name', default='exp', help='save to project/name') - parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') - parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') - parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument("--data", type=str, default=ROOT / "data/coco128-seg.yaml", help="dataset.yaml path") + parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov5s-seg.pt", help="model path(s)") + parser.add_argument("--batch-size", type=int, default=32, help="batch size") + parser.add_argument("--imgsz", "--img", "--img-size", type=int, default=640, help="inference size (pixels)") + parser.add_argument("--conf-thres", type=float, default=0.001, help="confidence threshold") + parser.add_argument("--iou-thres", type=float, default=0.6, help="NMS IoU threshold") + parser.add_argument("--max-det", type=int, default=300, help="maximum detections per image") + parser.add_argument("--task", default="val", help="train, val, test, speed or study") + parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu") + parser.add_argument("--workers", type=int, default=8, help="max dataloader workers (per RANK in DDP mode)") + parser.add_argument("--single-cls", action="store_true", help="treat as single-class dataset") + parser.add_argument("--augment", action="store_true", help="augmented inference") + parser.add_argument("--verbose", action="store_true", help="report mAP by class") + parser.add_argument("--save-txt", action="store_true", help="save results to *.txt") + parser.add_argument("--save-hybrid", action="store_true", help="save label+prediction hybrid results to *.txt") + parser.add_argument("--save-conf", action="store_true", help="save confidences in --save-txt labels") + parser.add_argument("--save-json", action="store_true", help="save a COCO-JSON results file") + parser.add_argument("--project", default=ROOT / "runs/val-seg", help="save results to project/name") + parser.add_argument("--name", default="exp", help="save to project/name") + parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment") + parser.add_argument("--half", action="store_true", help="use FP16 half-precision inference") + parser.add_argument("--dnn", action="store_true", help="use OpenCV DNN for ONNX inference") opt = parser.parse_args() opt.data = check_yaml(opt.data) # check YAML # opt.save_json |= opt.data.endswith('coco.yaml') @@ -434,40 +469,40 @@ def parse_opt(): def main(opt): - check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) - if opt.task in ('train', 'val', 'test'): # run normally + if opt.task in ("train", "val", "test"): # run normally if opt.conf_thres > 0.001: # https://github.com/ultralytics/yolov5/issues/1466 - LOGGER.warning(f'WARNING ⚠️ confidence threshold {opt.conf_thres} > 0.001 produces invalid results') + LOGGER.warning(f"WARNING ⚠️ confidence threshold {opt.conf_thres} > 0.001 produces invalid results") if opt.save_hybrid: - LOGGER.warning('WARNING ⚠️ --save-hybrid returns high mAP from hybrid labels, not from predictions alone') + LOGGER.warning("WARNING ⚠️ --save-hybrid returns high mAP from hybrid labels, not from predictions alone") run(**vars(opt)) else: weights = opt.weights if isinstance(opt.weights, list) else [opt.weights] - opt.half = torch.cuda.is_available() and opt.device != 'cpu' # FP16 for fastest results - if opt.task == 'speed': # speed benchmarks + opt.half = torch.cuda.is_available() and opt.device != "cpu" # FP16 for fastest results + if opt.task == "speed": # speed benchmarks # python val.py --task speed --data coco.yaml --batch 1 --weights yolov5n.pt yolov5s.pt... opt.conf_thres, opt.iou_thres, opt.save_json = 0.25, 0.45, False for opt.weights in weights: run(**vars(opt), plots=False) - elif opt.task == 'study': # speed vs mAP benchmarks + elif opt.task == "study": # speed vs mAP benchmarks # python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n.pt yolov5s.pt... for opt.weights in weights: - f = f'study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt' # filename to save to + f = f"study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt" # filename to save to x, y = list(range(256, 1536 + 128, 128)), [] # x axis (image sizes), y axis for opt.imgsz in x: # img-size - LOGGER.info(f'\nRunning {f} --imgsz {opt.imgsz}...') + LOGGER.info(f"\nRunning {f} --imgsz {opt.imgsz}...") r, _, t = run(**vars(opt), plots=False) y.append(r + t) # results and times - np.savetxt(f, y, fmt='%10.4g') # save - subprocess.run(['zip', '-r', 'study.zip', 'study_*.txt']) + np.savetxt(f, y, fmt="%10.4g") # save + subprocess.run(["zip", "-r", "study.zip", "study_*.txt"]) plot_val_study(x=x) # plot else: raise NotImplementedError(f'--task {opt.task} not in ("train", "val", "test", "speed", "study")') -if __name__ == '__main__': +if __name__ == "__main__": opt = parse_opt() main(opt) diff --git a/train.py b/train.py index fa9bae5ad8..146c5cc8a7 100644 --- a/train.py +++ b/train.py @@ -1,7 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Train a YOLOv3 model on a custom dataset. -Models and datasets download automatically from the latest YOLOv3 release. +Train a YOLOv3 model on a custom dataset. Models and datasets download automatically from the latest YOLOv3 release. Usage - Single-GPU training: $ python train.py --data coco128.yaml --weights yolov5s.pt --img 640 # from pretrained (recommended) @@ -53,47 +52,88 @@ from utils.callbacks import Callbacks from utils.dataloaders import create_dataloader from utils.downloads import attempt_download, is_url -from utils.general import (LOGGER, TQDM_BAR_FORMAT, check_amp, check_dataset, check_file, check_git_info, - check_git_status, check_img_size, check_requirements, check_suffix, check_yaml, colorstr, - get_latest_run, increment_path, init_seeds, intersect_dicts, labels_to_class_weights, - labels_to_image_weights, methods, one_cycle, print_args, print_mutation, strip_optimizer, - yaml_save) +from utils.general import ( + LOGGER, + TQDM_BAR_FORMAT, + check_amp, + check_dataset, + check_file, + check_git_info, + check_git_status, + check_img_size, + check_requirements, + check_suffix, + check_yaml, + colorstr, + get_latest_run, + increment_path, + init_seeds, + intersect_dicts, + labels_to_class_weights, + labels_to_image_weights, + methods, + one_cycle, + print_args, + print_mutation, + strip_optimizer, + yaml_save, +) from utils.loggers import Loggers from utils.loggers.comet.comet_utils import check_comet_resume from utils.loss import ComputeLoss from utils.metrics import fitness from utils.plots import plot_evolve -from utils.torch_utils import (EarlyStopping, ModelEMA, de_parallel, select_device, smart_DDP, smart_optimizer, - smart_resume, torch_distributed_zero_first) - -LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html -RANK = int(os.getenv('RANK', -1)) -WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +from utils.torch_utils import ( + EarlyStopping, + ModelEMA, + de_parallel, + select_device, + smart_DDP, + smart_optimizer, + smart_resume, + torch_distributed_zero_first, +) + +LOCAL_RANK = int(os.getenv("LOCAL_RANK", -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv("RANK", -1)) +WORLD_SIZE = int(os.getenv("WORLD_SIZE", 1)) GIT_INFO = check_git_info() def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary - save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = \ - Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ - opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze - callbacks.run('on_pretrain_routine_start') + save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = ( + Path(opt.save_dir), + opt.epochs, + opt.batch_size, + opt.weights, + opt.single_cls, + opt.evolve, + opt.data, + opt.cfg, + opt.resume, + opt.noval, + opt.nosave, + opt.workers, + opt.freeze, + ) + callbacks.run("on_pretrain_routine_start") # Directories - w = save_dir / 'weights' # weights dir + w = save_dir / "weights" # weights dir (w.parent if evolve else w).mkdir(parents=True, exist_ok=True) # make dir - last, best = w / 'last.pt', w / 'best.pt' + last, best = w / "last.pt", w / "best.pt" # Hyperparameters if isinstance(hyp, str): - with open(hyp, errors='ignore') as f: + with open(hyp, errors="ignore") as f: hyp = yaml.safe_load(f) # load hyps dict - LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) + LOGGER.info(colorstr("hyperparameters: ") + ", ".join(f"{k}={v}" for k, v in hyp.items())) opt.hyp = hyp.copy() # for saving hyps to checkpoints # Save run settings if not evolve: - yaml_save(save_dir / 'hyp.yaml', hyp) - yaml_save(save_dir / 'opt.yaml', vars(opt)) + yaml_save(save_dir / "hyp.yaml", hyp) + yaml_save(save_dir / "opt.yaml", vars(opt)) # Loggers data_dict = None @@ -111,39 +151,39 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Config plots = not evolve and not opt.noplots # create plots - cuda = device.type != 'cpu' + cuda = device.type != "cpu" init_seeds(opt.seed + 1 + RANK, deterministic=True) with torch_distributed_zero_first(LOCAL_RANK): data_dict = data_dict or check_dataset(data) # check if None - train_path, val_path = data_dict['train'], data_dict['val'] - nc = 1 if single_cls else int(data_dict['nc']) # number of classes - names = {0: 'item'} if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names - is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO dataset + train_path, val_path = data_dict["train"], data_dict["val"] + nc = 1 if single_cls else int(data_dict["nc"]) # number of classes + names = {0: "item"} if single_cls and len(data_dict["names"]) != 1 else data_dict["names"] # class names + is_coco = isinstance(val_path, str) and val_path.endswith("coco/val2017.txt") # COCO dataset # Model - check_suffix(weights, '.pt') # check weights - pretrained = weights.endswith('.pt') + check_suffix(weights, ".pt") # check weights + pretrained = weights.endswith(".pt") if pretrained: with torch_distributed_zero_first(LOCAL_RANK): weights = attempt_download(weights) # download if not found locally - ckpt = torch.load(weights, map_location='cpu') # load checkpoint to CPU to avoid CUDA memory leak - model = Model(cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create - exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else [] # exclude keys - csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 + ckpt = torch.load(weights, map_location="cpu") # load checkpoint to CPU to avoid CUDA memory leak + model = Model(cfg or ckpt["model"].yaml, ch=3, nc=nc, anchors=hyp.get("anchors")).to(device) # create + exclude = ["anchor"] if (cfg or hyp.get("anchors")) and not resume else [] # exclude keys + csd = ckpt["model"].float().state_dict() # checkpoint state_dict as FP32 csd = intersect_dicts(csd, model.state_dict(), exclude=exclude) # intersect model.load_state_dict(csd, strict=False) # load - LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}') # report + LOGGER.info(f"Transferred {len(csd)}/{len(model.state_dict())} items from {weights}") # report else: - model = Model(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create + model = Model(cfg, ch=3, nc=nc, anchors=hyp.get("anchors")).to(device) # create amp = check_amp(model) # check AMP # Freeze - freeze = [f'model.{x}.' for x in (freeze if len(freeze) > 1 else range(freeze[0]))] # layers to freeze + freeze = [f"model.{x}." for x in (freeze if len(freeze) > 1 else range(freeze[0]))] # layers to freeze for k, v in model.named_parameters(): v.requires_grad = True # train all layers # v.register_hook(lambda x: torch.nan_to_num(x)) # NaN to 0 (commented for erratic training results) if any(x in k for x in freeze): - LOGGER.info(f'freezing {k}') + LOGGER.info(f"freezing {k}") v.requires_grad = False # Image size @@ -153,19 +193,19 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Batch size if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size batch_size = check_train_batch_size(model, imgsz, amp) - loggers.on_params_update({'batch_size': batch_size}) + loggers.on_params_update({"batch_size": batch_size}) # Optimizer nbs = 64 # nominal batch size accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing - hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay - optimizer = smart_optimizer(model, opt.optimizer, hyp['lr0'], hyp['momentum'], hyp['weight_decay']) + hyp["weight_decay"] *= batch_size * accumulate / nbs # scale weight_decay + optimizer = smart_optimizer(model, opt.optimizer, hyp["lr0"], hyp["momentum"], hyp["weight_decay"]) # Scheduler if opt.cos_lr: - lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] + lf = one_cycle(1, hyp["lrf"], epochs) # cosine 1->hyp['lrf'] else: - lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear + lf = lambda x: (1 - x / epochs) * (1.0 - hyp["lrf"]) + hyp["lrf"] # linear scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) # EMA @@ -181,58 +221,62 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # DP mode if cuda and RANK == -1 and torch.cuda.device_count() > 1: LOGGER.warning( - 'WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n' - 'See Multi-GPU Tutorial at https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training to get started.' + "WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.\n" + "See Multi-GPU Tutorial at https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training to get started." ) model = torch.nn.DataParallel(model) # SyncBatchNorm if opt.sync_bn and cuda and RANK != -1: model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) - LOGGER.info('Using SyncBatchNorm()') + LOGGER.info("Using SyncBatchNorm()") # Trainloader - train_loader, dataset = create_dataloader(train_path, - imgsz, - batch_size // WORLD_SIZE, - gs, - single_cls, - hyp=hyp, - augment=True, - cache=None if opt.cache == 'val' else opt.cache, - rect=opt.rect, - rank=LOCAL_RANK, - workers=workers, - image_weights=opt.image_weights, - quad=opt.quad, - prefix=colorstr('train: '), - shuffle=True, - seed=opt.seed) + train_loader, dataset = create_dataloader( + train_path, + imgsz, + batch_size // WORLD_SIZE, + gs, + single_cls, + hyp=hyp, + augment=True, + cache=None if opt.cache == "val" else opt.cache, + rect=opt.rect, + rank=LOCAL_RANK, + workers=workers, + image_weights=opt.image_weights, + quad=opt.quad, + prefix=colorstr("train: "), + shuffle=True, + seed=opt.seed, + ) labels = np.concatenate(dataset.labels, 0) mlc = int(labels[:, 0].max()) # max label class - assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}' + assert mlc < nc, f"Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}" # Process 0 if RANK in {-1, 0}: - val_loader = create_dataloader(val_path, - imgsz, - batch_size // WORLD_SIZE * 2, - gs, - single_cls, - hyp=hyp, - cache=None if noval else opt.cache, - rect=True, - rank=-1, - workers=workers * 2, - pad=0.5, - prefix=colorstr('val: '))[0] + val_loader = create_dataloader( + val_path, + imgsz, + batch_size // WORLD_SIZE * 2, + gs, + single_cls, + hyp=hyp, + cache=None if noval else opt.cache, + rect=True, + rank=-1, + workers=workers * 2, + pad=0.5, + prefix=colorstr("val: "), + )[0] if not resume: if not opt.noautoanchor: - check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) # run AutoAnchor + check_anchors(dataset, model=model, thr=hyp["anchor_t"], imgsz=imgsz) # run AutoAnchor model.half().float() # pre-reduce anchor precision - callbacks.run('on_pretrain_routine_end', labels, names) + callbacks.run("on_pretrain_routine_end", labels, names) # DDP mode if cuda and RANK != -1: @@ -240,10 +284,10 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Model attributes nl = de_parallel(model).model[-1].nl # number of detection layers (to scale hyps) - hyp['box'] *= 3 / nl # scale to layers - hyp['cls'] *= nc / 80 * 3 / nl # scale to classes and layers - hyp['obj'] *= (imgsz / 640) ** 2 * 3 / nl # scale to image size and layers - hyp['label_smoothing'] = opt.label_smoothing + hyp["box"] *= 3 / nl # scale to layers + hyp["cls"] *= nc / 80 * 3 / nl # scale to classes and layers + hyp["obj"] *= (imgsz / 640) ** 2 * 3 / nl # scale to image size and layers + hyp["label_smoothing"] = opt.label_smoothing model.nc = nc # attach number of classes to model model.hyp = hyp # attach hyperparameters to model model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights @@ -252,7 +296,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Start training t0 = time.time() nb = len(train_loader) # number of batches - nw = max(round(hyp['warmup_epochs'] * nb), 100) # number of warmup iterations, max(3 epochs, 100 iterations) + nw = max(round(hyp["warmup_epochs"] * nb), 100) # number of warmup iterations, max(3 epochs, 100 iterations) # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training last_opt_step = -1 maps = np.zeros(nc) # mAP per class @@ -261,13 +305,15 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio scaler = torch.cuda.amp.GradScaler(enabled=amp) stopper, stop = EarlyStopping(patience=opt.patience), False compute_loss = ComputeLoss(model) # init loss class - callbacks.run('on_train_start') - LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n' - f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' - f"Logging results to {colorstr('bold', save_dir)}\n" - f'Starting training for {epochs} epochs...') + callbacks.run("on_train_start") + LOGGER.info( + f'Image sizes {imgsz} train, {imgsz} val\n' + f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' + f"Logging results to {colorstr('bold', save_dir)}\n" + f'Starting training for {epochs} epochs...' + ) for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ - callbacks.run('on_train_epoch_start') + callbacks.run("on_train_epoch_start") model.train() # Update image weights (optional, single-GPU only) @@ -284,12 +330,12 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio if RANK != -1: train_loader.sampler.set_epoch(epoch) pbar = enumerate(train_loader) - LOGGER.info(('\n' + '%11s' * 7) % ('Epoch', 'GPU_mem', 'box_loss', 'obj_loss', 'cls_loss', 'Instances', 'Size')) + LOGGER.info(("\n" + "%11s" * 7) % ("Epoch", "GPU_mem", "box_loss", "obj_loss", "cls_loss", "Instances", "Size")) if RANK in {-1, 0}: pbar = tqdm(pbar, total=nb, bar_format=TQDM_BAR_FORMAT) # progress bar optimizer.zero_grad() for i, (imgs, targets, paths, _) in pbar: # batch ------------------------------------------------------------- - callbacks.run('on_train_batch_start') + callbacks.run("on_train_batch_start") ni = i + nb * epoch # number integrated batches (since train start) imgs = imgs.to(device, non_blocking=True).float() / 255 # uint8 to float32, 0-255 to 0.0-1.0 @@ -300,9 +346,9 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round()) for j, x in enumerate(optimizer.param_groups): # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 - x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 0 else 0.0, x['initial_lr'] * lf(epoch)]) - if 'momentum' in x: - x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) + x["lr"] = np.interp(ni, xi, [hyp["warmup_bias_lr"] if j == 0 else 0.0, x["initial_lr"] * lf(epoch)]) + if "momentum" in x: + x["momentum"] = np.interp(ni, xi, [hyp["warmup_momentum"], hyp["momentum"]]) # Multi-scale if opt.multi_scale: @@ -310,7 +356,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio sf = sz / max(imgs.shape[2:]) # scale factor if sf != 1: ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) - imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) + imgs = nn.functional.interpolate(imgs, size=ns, mode="bilinear", align_corners=False) # Forward with torch.cuda.amp.autocast(amp): @@ -319,7 +365,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio if RANK != -1: loss *= WORLD_SIZE # gradient averaged between devices in DDP mode if opt.quad: - loss *= 4. + loss *= 4.0 # Backward scaler.scale(loss).backward() @@ -338,35 +384,39 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # Log if RANK in {-1, 0}: mloss = (mloss * i + loss_items) / (i + 1) # update mean losses - mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G' # (GB) - pbar.set_description(('%11s' * 2 + '%11.4g' * 5) % - (f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])) - callbacks.run('on_train_batch_end', model, ni, imgs, targets, paths, list(mloss)) + mem = f"{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G" # (GB) + pbar.set_description( + ("%11s" * 2 + "%11.4g" * 5) + % (f"{epoch}/{epochs - 1}", mem, *mloss, targets.shape[0], imgs.shape[-1]) + ) + callbacks.run("on_train_batch_end", model, ni, imgs, targets, paths, list(mloss)) if callbacks.stop_training: return # end batch ------------------------------------------------------------------------------------------------ # Scheduler - lr = [x['lr'] for x in optimizer.param_groups] # for loggers + lr = [x["lr"] for x in optimizer.param_groups] # for loggers scheduler.step() if RANK in {-1, 0}: # mAP - callbacks.run('on_train_epoch_end', epoch=epoch) - ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights']) + callbacks.run("on_train_epoch_end", epoch=epoch) + ema.update_attr(model, include=["yaml", "nc", "hyp", "names", "stride", "class_weights"]) final_epoch = (epoch + 1 == epochs) or stopper.possible_stop if not noval or final_epoch: # Calculate mAP - results, maps, _ = validate.run(data_dict, - batch_size=batch_size // WORLD_SIZE * 2, - imgsz=imgsz, - half=amp, - model=ema.ema, - single_cls=single_cls, - dataloader=val_loader, - save_dir=save_dir, - plots=False, - callbacks=callbacks, - compute_loss=compute_loss) + results, maps, _ = validate.run( + data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + half=amp, + model=ema.ema, + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + plots=False, + callbacks=callbacks, + compute_loss=compute_loss, + ) # Update best mAP fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] @@ -374,29 +424,30 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio if fi > best_fitness: best_fitness = fi log_vals = list(mloss) + list(results) + lr - callbacks.run('on_fit_epoch_end', log_vals, epoch, best_fitness, fi) + callbacks.run("on_fit_epoch_end", log_vals, epoch, best_fitness, fi) # Save model if (not nosave) or (final_epoch and not evolve): # if save ckpt = { - 'epoch': epoch, - 'best_fitness': best_fitness, - 'model': deepcopy(de_parallel(model)).half(), - 'ema': deepcopy(ema.ema).half(), - 'updates': ema.updates, - 'optimizer': optimizer.state_dict(), - 'opt': vars(opt), - 'git': GIT_INFO, # {remote, branch, commit} if a git repo - 'date': datetime.now().isoformat()} + "epoch": epoch, + "best_fitness": best_fitness, + "model": deepcopy(de_parallel(model)).half(), + "ema": deepcopy(ema.ema).half(), + "updates": ema.updates, + "optimizer": optimizer.state_dict(), + "opt": vars(opt), + "git": GIT_INFO, # {remote, branch, commit} if a git repo + "date": datetime.now().isoformat(), + } # Save last, best and delete torch.save(ckpt, last) if best_fitness == fi: torch.save(ckpt, best) if opt.save_period > 0 and epoch % opt.save_period == 0: - torch.save(ckpt, w / f'epoch{epoch}.pt') + torch.save(ckpt, w / f"epoch{epoch}.pt") del ckpt - callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi) + callbacks.run("on_model_save", last, epoch, final_epoch, best_fitness, fi) # EarlyStopping if RANK != -1: # if DDP training @@ -410,12 +461,12 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio # end epoch ---------------------------------------------------------------------------------------------------- # end training ----------------------------------------------------------------------------------------------------- if RANK in {-1, 0}: - LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.') + LOGGER.info(f"\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.") for f in last, best: if f.exists(): strip_optimizer(f) # strip optimizers if f is best: - LOGGER.info(f'\nValidating {f}...') + LOGGER.info(f"\nValidating {f}...") results, _, _ = validate.run( data_dict, batch_size=batch_size // WORLD_SIZE * 2, @@ -429,11 +480,12 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio verbose=True, plots=plots, callbacks=callbacks, - compute_loss=compute_loss) # val best model with plots + compute_loss=compute_loss, + ) # val best model with plots if is_coco: - callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi) + callbacks.run("on_fit_epoch_end", list(mloss) + list(results) + lr, epoch, best_fitness, fi) - callbacks.run('on_train_end', last, best, epoch, results) + callbacks.run("on_train_end", last, best, epoch, results) torch.cuda.empty_cache() return results @@ -441,46 +493,46 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio def parse_opt(known=False): parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default=ROOT / 'yolov3-tiny.pt', help='initial weights path') - parser.add_argument('--cfg', type=str, default='', help='model.yaml path') - parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') - parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path') - parser.add_argument('--epochs', type=int, default=100, help='total training epochs') - parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') - parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') - parser.add_argument('--rect', action='store_true', help='rectangular training') - parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') - parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') - parser.add_argument('--noval', action='store_true', help='only validate final epoch') - parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') - parser.add_argument('--noplots', action='store_true', help='save no plot files') - parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') - parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') - parser.add_argument('--cache', type=str, nargs='?', const='ram', help='image --cache ram/disk') - parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') - parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') - parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer') - parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') - parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') - parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name') - parser.add_argument('--name', default='exp', help='save to project/name') - parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') - parser.add_argument('--quad', action='store_true', help='quad dataloader') - parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') - parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') - parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') - parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') - parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') - parser.add_argument('--seed', type=int, default=0, help='Global training seed') - parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + parser.add_argument("--weights", type=str, default=ROOT / "yolov3-tiny.pt", help="initial weights path") + parser.add_argument("--cfg", type=str, default="", help="model.yaml path") + parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="dataset.yaml path") + parser.add_argument("--hyp", type=str, default=ROOT / "data/hyps/hyp.scratch-low.yaml", help="hyperparameters path") + parser.add_argument("--epochs", type=int, default=100, help="total training epochs") + parser.add_argument("--batch-size", type=int, default=16, help="total batch size for all GPUs, -1 for autobatch") + parser.add_argument("--imgsz", "--img", "--img-size", type=int, default=640, help="train, val image size (pixels)") + parser.add_argument("--rect", action="store_true", help="rectangular training") + parser.add_argument("--resume", nargs="?", const=True, default=False, help="resume most recent training") + parser.add_argument("--nosave", action="store_true", help="only save final checkpoint") + parser.add_argument("--noval", action="store_true", help="only validate final epoch") + parser.add_argument("--noautoanchor", action="store_true", help="disable AutoAnchor") + parser.add_argument("--noplots", action="store_true", help="save no plot files") + parser.add_argument("--evolve", type=int, nargs="?", const=300, help="evolve hyperparameters for x generations") + parser.add_argument("--bucket", type=str, default="", help="gsutil bucket") + parser.add_argument("--cache", type=str, nargs="?", const="ram", help="image --cache ram/disk") + parser.add_argument("--image-weights", action="store_true", help="use weighted image selection for training") + parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu") + parser.add_argument("--multi-scale", action="store_true", help="vary img-size +/- 50%%") + parser.add_argument("--single-cls", action="store_true", help="train multi-class data as single-class") + parser.add_argument("--optimizer", type=str, choices=["SGD", "Adam", "AdamW"], default="SGD", help="optimizer") + parser.add_argument("--sync-bn", action="store_true", help="use SyncBatchNorm, only available in DDP mode") + parser.add_argument("--workers", type=int, default=8, help="max dataloader workers (per RANK in DDP mode)") + parser.add_argument("--project", default=ROOT / "runs/train", help="save to project/name") + parser.add_argument("--name", default="exp", help="save to project/name") + parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment") + parser.add_argument("--quad", action="store_true", help="quad dataloader") + parser.add_argument("--cos-lr", action="store_true", help="cosine LR scheduler") + parser.add_argument("--label-smoothing", type=float, default=0.0, help="Label smoothing epsilon") + parser.add_argument("--patience", type=int, default=100, help="EarlyStopping patience (epochs without improvement)") + parser.add_argument("--freeze", nargs="+", type=int, default=[0], help="Freeze layers: backbone=10, first3=0 1 2") + parser.add_argument("--save-period", type=int, default=-1, help="Save checkpoint every x epochs (disabled if < 1)") + parser.add_argument("--seed", type=int, default=0, help="Global training seed") + parser.add_argument("--local_rank", type=int, default=-1, help="Automatic DDP Multi-GPU argument, do not modify") # Logger arguments - parser.add_argument('--entity', default=None, help='Entity') - parser.add_argument('--upload_dataset', nargs='?', const=True, default=False, help='Upload data, "val" option') - parser.add_argument('--bbox_interval', type=int, default=-1, help='Set bounding-box image logging interval') - parser.add_argument('--artifact_alias', type=str, default='latest', help='Version of dataset artifact to use') + parser.add_argument("--entity", default=None, help="Entity") + parser.add_argument("--upload_dataset", nargs="?", const=True, default=False, help='Upload data, "val" option') + parser.add_argument("--bbox_interval", type=int, default=-1, help="Set bounding-box image logging interval") + parser.add_argument("--artifact_alias", type=str, default="latest", help="Version of dataset artifact to use") return parser.parse_known_args()[0] if known else parser.parse_args() @@ -490,46 +542,51 @@ def main(opt, callbacks=Callbacks()): if RANK in {-1, 0}: print_args(vars(opt)) check_git_status() - check_requirements(ROOT / 'requirements.txt') + check_requirements(ROOT / "requirements.txt") # Resume (from specified or most recent last.pt) if opt.resume and not check_comet_resume(opt) and not opt.evolve: last = Path(check_file(opt.resume) if isinstance(opt.resume, str) else get_latest_run()) - opt_yaml = last.parent.parent / 'opt.yaml' # train options yaml + opt_yaml = last.parent.parent / "opt.yaml" # train options yaml opt_data = opt.data # original dataset if opt_yaml.is_file(): - with open(opt_yaml, errors='ignore') as f: + with open(opt_yaml, errors="ignore") as f: d = yaml.safe_load(f) else: - d = torch.load(last, map_location='cpu')['opt'] + d = torch.load(last, map_location="cpu")["opt"] opt = argparse.Namespace(**d) # replace - opt.cfg, opt.weights, opt.resume = '', str(last), True # reinstate + opt.cfg, opt.weights, opt.resume = "", str(last), True # reinstate if is_url(opt_data): opt.data = check_file(opt_data) # avoid HUB resume auth timeout else: - opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \ - check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks - assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' + opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = ( + check_file(opt.data), + check_yaml(opt.cfg), + check_yaml(opt.hyp), + str(opt.weights), + str(opt.project), + ) # checks + assert len(opt.cfg) or len(opt.weights), "either --cfg or --weights must be specified" if opt.evolve: - if opt.project == str(ROOT / 'runs/train'): # if default project name, rename to runs/evolve - opt.project = str(ROOT / 'runs/evolve') + if opt.project == str(ROOT / "runs/train"): # if default project name, rename to runs/evolve + opt.project = str(ROOT / "runs/evolve") opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume - if opt.name == 'cfg': + if opt.name == "cfg": opt.name = Path(opt.cfg).stem # use model.yaml as name opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) # DDP mode device = select_device(opt.device, batch_size=opt.batch_size) if LOCAL_RANK != -1: - msg = 'is not compatible with YOLOv3 Multi-GPU DDP training' - assert not opt.image_weights, f'--image-weights {msg}' - assert not opt.evolve, f'--evolve {msg}' - assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size' - assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' - assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' + msg = "is not compatible with YOLOv3 Multi-GPU DDP training" + assert not opt.image_weights, f"--image-weights {msg}" + assert not opt.evolve, f"--evolve {msg}" + assert opt.batch_size != -1, f"AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size" + assert opt.batch_size % WORLD_SIZE == 0, f"--batch-size {opt.batch_size} must be multiple of WORLD_SIZE" + assert torch.cuda.device_count() > LOCAL_RANK, "insufficient CUDA devices for DDP command" torch.cuda.set_device(LOCAL_RANK) - device = torch.device('cuda', LOCAL_RANK) - dist.init_process_group(backend='nccl' if dist.is_nccl_available() else 'gloo') + device = torch.device("cuda", LOCAL_RANK) + dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") # Train if not opt.evolve: @@ -539,65 +596,69 @@ def main(opt, callbacks=Callbacks()): else: # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) meta = { - 'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) - 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) - 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 - 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay - 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) - 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum - 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr - 'box': (1, 0.02, 0.2), # box loss gain - 'cls': (1, 0.2, 4.0), # cls loss gain - 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight - 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) - 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight - 'iou_t': (0, 0.1, 0.7), # IoU training threshold - 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold - 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) - 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) - 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) - 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) - 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) - 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) - 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) - 'scale': (1, 0.0, 0.9), # image scale (+/- gain) - 'shear': (1, 0.0, 10.0), # image shear (+/- deg) - 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 - 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) - 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) - 'mosaic': (1, 0.0, 1.0), # image mixup (probability) - 'mixup': (1, 0.0, 1.0), # image mixup (probability) - 'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) - - with open(opt.hyp, errors='ignore') as f: + "lr0": (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) + "lrf": (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) + "momentum": (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 + "weight_decay": (1, 0.0, 0.001), # optimizer weight decay + "warmup_epochs": (1, 0.0, 5.0), # warmup epochs (fractions ok) + "warmup_momentum": (1, 0.0, 0.95), # warmup initial momentum + "warmup_bias_lr": (1, 0.0, 0.2), # warmup initial bias lr + "box": (1, 0.02, 0.2), # box loss gain + "cls": (1, 0.2, 4.0), # cls loss gain + "cls_pw": (1, 0.5, 2.0), # cls BCELoss positive_weight + "obj": (1, 0.2, 4.0), # obj loss gain (scale with pixels) + "obj_pw": (1, 0.5, 2.0), # obj BCELoss positive_weight + "iou_t": (0, 0.1, 0.7), # IoU training threshold + "anchor_t": (1, 2.0, 8.0), # anchor-multiple threshold + "anchors": (2, 2.0, 10.0), # anchors per output grid (0 to ignore) + "fl_gamma": (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) + "hsv_h": (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) + "hsv_s": (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) + "hsv_v": (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) + "degrees": (1, 0.0, 45.0), # image rotation (+/- deg) + "translate": (1, 0.0, 0.9), # image translation (+/- fraction) + "scale": (1, 0.0, 0.9), # image scale (+/- gain) + "shear": (1, 0.0, 10.0), # image shear (+/- deg) + "perspective": (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 + "flipud": (1, 0.0, 1.0), # image flip up-down (probability) + "fliplr": (0, 0.0, 1.0), # image flip left-right (probability) + "mosaic": (1, 0.0, 1.0), # image mixup (probability) + "mixup": (1, 0.0, 1.0), # image mixup (probability) + "copy_paste": (1, 0.0, 1.0), + } # segment copy-paste (probability) + + with open(opt.hyp, errors="ignore") as f: hyp = yaml.safe_load(f) # load hyps dict - if 'anchors' not in hyp: # anchors commented in hyp.yaml - hyp['anchors'] = 3 + if "anchors" not in hyp: # anchors commented in hyp.yaml + hyp["anchors"] = 3 if opt.noautoanchor: - del hyp['anchors'], meta['anchors'] + del hyp["anchors"], meta["anchors"] opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir) # only val/save final epoch # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices - evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' + evolve_yaml, evolve_csv = save_dir / "hyp_evolve.yaml", save_dir / "evolve.csv" if opt.bucket: # download evolve.csv if exists - subprocess.run([ - 'gsutil', - 'cp', - f'gs://{opt.bucket}/evolve.csv', - str(evolve_csv), ]) + subprocess.run( + [ + "gsutil", + "cp", + f"gs://{opt.bucket}/evolve.csv", + str(evolve_csv), + ] + ) for _ in range(opt.evolve): # generations to evolve if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate # Select parent(s) - parent = 'single' # parent selection method: 'single' or 'weighted' - x = np.loadtxt(evolve_csv, ndmin=2, delimiter=',', skiprows=1) + parent = "single" # parent selection method: 'single' or 'weighted' + x = np.loadtxt(evolve_csv, ndmin=2, delimiter=",", skiprows=1) n = min(5, len(x)) # number of previous results to consider x = x[np.argsort(-fitness(x))][:n] # top n mutations - w = fitness(x) - fitness(x).min() + 1E-6 # weights (sum > 0) - if parent == 'single' or len(x) == 1: + w = fitness(x) - fitness(x).min() + 1e-6 # weights (sum > 0) + if parent == "single" or len(x) == 1: # x = x[random.randint(0, n - 1)] # random selection x = x[random.choices(range(n), weights=w)[0]] # weighted selection - elif parent == 'weighted': + elif parent == "weighted": x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination # Mutate @@ -622,15 +683,24 @@ def main(opt, callbacks=Callbacks()): results = train(hyp.copy(), opt, device, callbacks) callbacks = Callbacks() # Write mutation results - keys = ('metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', 'val/box_loss', - 'val/obj_loss', 'val/cls_loss') + keys = ( + "metrics/precision", + "metrics/recall", + "metrics/mAP_0.5", + "metrics/mAP_0.5:0.95", + "val/box_loss", + "val/obj_loss", + "val/cls_loss", + ) print_mutation(keys, results, hyp.copy(), save_dir, opt.bucket) # Plot results plot_evolve(evolve_csv) - LOGGER.info(f'Hyperparameter evolution finished {opt.evolve} generations\n' - f"Results saved to {colorstr('bold', save_dir)}\n" - f'Usage example: $ python train.py --hyp {evolve_yaml}') + LOGGER.info( + f'Hyperparameter evolution finished {opt.evolve} generations\n' + f"Results saved to {colorstr('bold', save_dir)}\n" + f'Usage example: $ python train.py --hyp {evolve_yaml}' + ) def run(**kwargs): @@ -642,6 +712,6 @@ def run(**kwargs): return opt -if __name__ == '__main__': +if __name__ == "__main__": opt = parse_opt() main(opt) diff --git a/utils/__init__.py b/utils/__init__.py index 1c05ec0d54..8966abbc30 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -1,21 +1,19 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -utils/initialization -""" +"""utils/initialization.""" import contextlib import platform import threading -def emojis(str=''): +def emojis(str=""): # Return platform-dependent emoji-safe version of string - return str.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else str + return str.encode().decode("ascii", "ignore") if platform.system() == "Windows" else str class TryExcept(contextlib.ContextDecorator): # YOLOv3 TryExcept class. Usage: @TryExcept() decorator or 'with TryExcept():' context manager - def __init__(self, msg=''): + def __init__(self, msg=""): self.msg = msg def __enter__(self): @@ -43,13 +41,13 @@ def join_threads(verbose=False): for t in threading.enumerate(): if t is not main_thread: if verbose: - print(f'Joining thread {t.name}') + print(f"Joining thread {t.name}") t.join() def notebook_init(verbose=True): # Check system software and hardware - print('Checking setup...') + print("Checking setup...") import os import shutil @@ -63,24 +61,25 @@ def notebook_init(verbose=True): import psutil - if check_requirements('wandb', install=False): - os.system('pip uninstall -y wandb') # eliminate unexpected account creation prompt with infinite hang + if check_requirements("wandb", install=False): + os.system("pip uninstall -y wandb") # eliminate unexpected account creation prompt with infinite hang if is_colab(): - shutil.rmtree('/content/sample_data', ignore_errors=True) # remove colab /sample_data directory + shutil.rmtree("/content/sample_data", ignore_errors=True) # remove colab /sample_data directory # System info display = None if verbose: gb = 1 << 30 # bytes to GiB (1024 ** 3) ram = psutil.virtual_memory().total - total, used, free = shutil.disk_usage('/') + total, used, free = shutil.disk_usage("/") with contextlib.suppress(Exception): # clear display if ipython is installed from IPython import display + display.clear_output() - s = f'({os.cpu_count()} CPUs, {ram / gb:.1f} GB RAM, {(total - free) / gb:.1f}/{total / gb:.1f} GB disk)' + s = f"({os.cpu_count()} CPUs, {ram / gb:.1f} GB RAM, {(total - free) / gb:.1f}/{total / gb:.1f} GB disk)" else: - s = '' + s = "" select_device(newline=False) - print(emojis(f'Setup complete ✅ {s}')) + print(emojis(f"Setup complete ✅ {s}")) return display diff --git a/utils/activations.py b/utils/activations.py index f4435ad6db..cb193862ff 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Activation functions -""" +"""Activation functions.""" import torch import torch.nn as nn @@ -33,7 +31,6 @@ def forward(x): class MemoryEfficientMish(nn.Module): # Mish activation memory-efficient class F(torch.autograd.Function): - @staticmethod def forward(ctx, x): ctx.save_for_backward(x) @@ -62,7 +59,7 @@ def forward(self, x): class AconC(nn.Module): - r""" ACON activation (activate or not) + r"""ACON activation (activate or not) AconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is a learnable parameter according to "Activate or Not: Learning Customized Activation" . """ @@ -79,7 +76,7 @@ def forward(self, x): class MetaAconC(nn.Module): - r""" ACON activation (activate or not) + r"""ACON activation (activate or not) MetaAconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is generated by a small network according to "Activate or Not: Learning Customized Activation" . """ diff --git a/utils/augmentations.py b/utils/augmentations.py index 64bd7a50a8..d91c84272a 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Image augmentation functions -""" +"""Image augmentation functions.""" import math import random @@ -23,10 +21,11 @@ class Albumentations: # YOLOv3 Albumentations class (optional, only used if package is installed) def __init__(self, size=640): self.transform = None - prefix = colorstr('albumentations: ') + prefix = colorstr("albumentations: ") try: import albumentations as A - check_version(A.__version__, '1.0.3', hard=True) # version requirement + + check_version(A.__version__, "1.0.3", hard=True) # version requirement T = [ A.RandomResizedCrop(height=size, width=size, scale=(0.8, 1.0), ratio=(0.9, 1.11), p=0.0), @@ -36,19 +35,20 @@ def __init__(self, size=640): A.CLAHE(p=0.01), A.RandomBrightnessContrast(p=0.0), A.RandomGamma(p=0.0), - A.ImageCompression(quality_lower=75, p=0.0)] # transforms - self.transform = A.Compose(T, bbox_params=A.BboxParams(format='yolo', label_fields=['class_labels'])) + A.ImageCompression(quality_lower=75, p=0.0), + ] # transforms + self.transform = A.Compose(T, bbox_params=A.BboxParams(format="yolo", label_fields=["class_labels"])) - LOGGER.info(prefix + ', '.join(f'{x}'.replace('always_apply=False, ', '') for x in T if x.p)) + LOGGER.info(prefix + ", ".join(f"{x}".replace("always_apply=False, ", "") for x in T if x.p)) except ImportError: # package not installed, skip pass except Exception as e: - LOGGER.info(f'{prefix}{e}') + LOGGER.info(f"{prefix}{e}") def __call__(self, im, labels, p=1.0): if self.transform and random.random() < p: new = self.transform(image=im, bboxes=labels[:, 1:], class_labels=labels[:, 0]) # transformed - im, labels = new['image'], np.array([[c, *b] for c, b in zip(new['class_labels'], new['bboxes'])]) + im, labels = new["image"], np.array([[c, *b] for c, b in zip(new["class_labels"], new["bboxes"])]) return im, labels @@ -97,7 +97,7 @@ def replicate(im, labels): boxes = labels[:, 1:].astype(int) x1, y1, x2, y2 = boxes.T s = ((x2 - x1) + (y2 - y1)) / 2 # side length (pixels) - for i in s.argsort()[:round(s.size * 0.5)]: # smallest indices + for i in s.argsort()[: round(s.size * 0.5)]: # smallest indices x1b, y1b, x2b, y2b = boxes[i] bh, bw = y2b - y1b, x2b - x1b yc, xc = int(random.uniform(0, h - bh)), int(random.uniform(0, w - bw)) # offset x, y @@ -141,15 +141,9 @@ def letterbox(im, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleF return im, ratio, (dw, dh) -def random_perspective(im, - targets=(), - segments=(), - degrees=10, - translate=.1, - scale=.1, - shear=10, - perspective=0.0, - border=(0, 0)): +def random_perspective( + im, targets=(), segments=(), degrees=10, translate=0.1, scale=0.1, shear=10, perspective=0.0, border=(0, 0) +): # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(0.1, 0.1), scale=(0.9, 1.1), shear=(-10, 10)) # targets = [cls, xyxy] @@ -303,50 +297,52 @@ def box_candidates(box1, box2, wh_thr=2, ar_thr=100, area_thr=0.1, eps=1e-16): def classify_albumentations( - augment=True, - size=224, - scale=(0.08, 1.0), - ratio=(0.75, 1.0 / 0.75), # 0.75, 1.33 - hflip=0.5, - vflip=0.0, - jitter=0.4, - mean=IMAGENET_MEAN, - std=IMAGENET_STD, - auto_aug=False): + augment=True, + size=224, + scale=(0.08, 1.0), + ratio=(0.75, 1.0 / 0.75), # 0.75, 1.33 + hflip=0.5, + vflip=0.0, + jitter=0.4, + mean=IMAGENET_MEAN, + std=IMAGENET_STD, + auto_aug=False, +): # YOLOv3 classification Albumentations (optional, only used if package is installed) - prefix = colorstr('albumentations: ') + prefix = colorstr("albumentations: ") try: import albumentations as A from albumentations.pytorch import ToTensorV2 - check_version(A.__version__, '1.0.3', hard=True) # version requirement + + check_version(A.__version__, "1.0.3", hard=True) # version requirement if augment: # Resize and crop T = [A.RandomResizedCrop(height=size, width=size, scale=scale, ratio=ratio)] if auto_aug: # TODO: implement AugMix, AutoAug & RandAug in albumentation - LOGGER.info(f'{prefix}auto augmentations are currently not supported') + LOGGER.info(f"{prefix}auto augmentations are currently not supported") else: if hflip > 0: T += [A.HorizontalFlip(p=hflip)] if vflip > 0: T += [A.VerticalFlip(p=vflip)] if jitter > 0: - color_jitter = (float(jitter), ) * 3 # repeat value for brightness, contrast, satuaration, 0 hue + color_jitter = (float(jitter),) * 3 # repeat value for brightness, contrast, satuaration, 0 hue T += [A.ColorJitter(*color_jitter, 0)] else: # Use fixed crop for eval set (reproducibility) T = [A.SmallestMaxSize(max_size=size), A.CenterCrop(height=size, width=size)] T += [A.Normalize(mean=mean, std=std), ToTensorV2()] # Normalize and convert to Tensor - LOGGER.info(prefix + ', '.join(f'{x}'.replace('always_apply=False, ', '') for x in T if x.p)) + LOGGER.info(prefix + ", ".join(f"{x}".replace("always_apply=False, ", "") for x in T if x.p)) return A.Compose(T) except ImportError: # package not installed, skip - LOGGER.warning(f'{prefix}⚠️ not found, install with `pip install albumentations` (recommended)') + LOGGER.warning(f"{prefix}⚠️ not found, install with `pip install albumentations` (recommended)") except Exception as e: - LOGGER.info(f'{prefix}{e}') + LOGGER.info(f"{prefix}{e}") def classify_transforms(size=224): # Transforms to apply if albumentations not installed - assert isinstance(size, int), f'ERROR: classify_transforms size {size} must be integer, not (list, tuple)' + assert isinstance(size, int), f"ERROR: classify_transforms size {size} must be integer, not (list, tuple)" # T.Compose([T.ToTensor(), T.Resize(size), T.CenterCrop(size), T.Normalize(IMAGENET_MEAN, IMAGENET_STD)]) return T.Compose([CenterCrop(size), ToTensor(), T.Normalize(IMAGENET_MEAN, IMAGENET_STD)]) @@ -366,7 +362,7 @@ def __call__(self, im): # im = np.array HWC hs, ws = (math.ceil(x / self.stride) * self.stride for x in (h, w)) if self.auto else self.h, self.w top, left = round((hs - h) / 2 - 0.1), round((ws - w) / 2 - 0.1) im_out = np.full((self.h, self.w, 3), 114, dtype=im.dtype) - im_out[top:top + h, left:left + w] = cv2.resize(im, (w, h), interpolation=cv2.INTER_LINEAR) + im_out[top : top + h, left : left + w] = cv2.resize(im, (w, h), interpolation=cv2.INTER_LINEAR) return im_out @@ -380,7 +376,7 @@ def __call__(self, im): # im = np.array HWC imh, imw = im.shape[:2] m = min(imh, imw) # min dimension top, left = (imh - m) // 2, (imw - m) // 2 - return cv2.resize(im[top:top + m, left:left + m], (self.w, self.h), interpolation=cv2.INTER_LINEAR) + return cv2.resize(im[top : top + m, left : left + m], (self.w, self.h), interpolation=cv2.INTER_LINEAR) class ToTensor: diff --git a/utils/autoanchor.py b/utils/autoanchor.py index b7f902695d..381259ecfb 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -AutoAnchor utils -""" +"""AutoAnchor utils.""" import random @@ -13,7 +11,7 @@ from utils import TryExcept from utils.general import LOGGER, TQDM_BAR_FORMAT, colorstr -PREFIX = colorstr('AutoAnchor: ') +PREFIX = colorstr("AutoAnchor: ") def check_anchor_order(m): @@ -22,14 +20,14 @@ def check_anchor_order(m): da = a[-1] - a[0] # delta a ds = m.stride[-1] - m.stride[0] # delta s if da and (da.sign() != ds.sign()): # same order - LOGGER.info(f'{PREFIX}Reversing anchor order') + LOGGER.info(f"{PREFIX}Reversing anchor order") m.anchors[:] = m.anchors.flip(0) -@TryExcept(f'{PREFIX}ERROR') +@TryExcept(f"{PREFIX}ERROR") def check_anchors(dataset, model, thr=4.0, imgsz=640): # Check anchor fit to data, recompute if necessary - m = model.module.model[-1] if hasattr(model, 'module') else model.model[-1] # Detect() + m = model.module.model[-1] if hasattr(model, "module") else model.model[-1] # Detect() shapes = imgsz * dataset.shapes / dataset.shapes.max(1, keepdims=True) scale = np.random.uniform(0.9, 1.1, size=(shapes.shape[0], 1)) # augment scale wh = torch.tensor(np.concatenate([l[:, 3:5] * s for s, l in zip(shapes * scale, dataset.labels)])).float() # wh @@ -45,11 +43,11 @@ def metric(k): # compute metric stride = m.stride.to(m.anchors.device).view(-1, 1, 1) # model strides anchors = m.anchors.clone() * stride # current anchors bpr, aat = metric(anchors.cpu().view(-1, 2)) - s = f'\n{PREFIX}{aat:.2f} anchors/target, {bpr:.3f} Best Possible Recall (BPR). ' + s = f"\n{PREFIX}{aat:.2f} anchors/target, {bpr:.3f} Best Possible Recall (BPR). " if bpr > 0.98: # threshold to recompute - LOGGER.info(f'{s}Current anchors are a good fit to dataset ✅') + LOGGER.info(f"{s}Current anchors are a good fit to dataset ✅") else: - LOGGER.info(f'{s}Anchors are a poor fit to dataset ⚠️, attempting to improve...') + LOGGER.info(f"{s}Anchors are a poor fit to dataset ⚠️, attempting to improve...") na = m.anchors.numel() // 2 # number of anchors anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False) new_bpr = metric(anchors)[0] @@ -58,28 +56,29 @@ def metric(k): # compute metric m.anchors[:] = anchors.clone().view_as(m.anchors) check_anchor_order(m) # must be in pixel-space (not grid-space) m.anchors /= stride - s = f'{PREFIX}Done ✅ (optional: update model *.yaml to use these anchors in the future)' + s = f"{PREFIX}Done ✅ (optional: update model *.yaml to use these anchors in the future)" else: - s = f'{PREFIX}Done ⚠️ (original anchors better than new anchors, proceeding with original anchors)' + s = f"{PREFIX}Done ⚠️ (original anchors better than new anchors, proceeding with original anchors)" LOGGER.info(s) -def kmean_anchors(dataset='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=1000, verbose=True): - """ Creates kmeans-evolved anchors from training dataset +def kmean_anchors(dataset="./data/coco128.yaml", n=9, img_size=640, thr=4.0, gen=1000, verbose=True): + """ + Creates kmeans-evolved anchors from training dataset. - Arguments: - dataset: path to data.yaml, or a loaded dataset - n: number of anchors - img_size: image size used for training - thr: anchor-label wh ratio threshold hyperparameter hyp['anchor_t'] used for training, default=4.0 - gen: generations to evolve anchors using genetic algorithm - verbose: print all results + Arguments: + dataset: path to data.yaml, or a loaded dataset + n: number of anchors + img_size: image size used for training + thr: anchor-label wh ratio threshold hyperparameter hyp['anchor_t'] used for training, default=4.0 + gen: generations to evolve anchors using genetic algorithm + verbose: print all results - Return: - k: kmeans evolved anchors + Return: + k: kmeans evolved anchors - Usage: - from utils.autoanchor import *; _ = kmean_anchors() + Usage: + from utils.autoanchor import *; _ = kmean_anchors() """ from scipy.cluster.vq import kmeans @@ -100,20 +99,23 @@ def print_results(k, verbose=True): k = k[np.argsort(k.prod(1))] # sort small to large x, best = metric(k, wh0) bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr - s = f'{PREFIX}thr={thr:.2f}: {bpr:.4f} best possible recall, {aat:.2f} anchors past thr\n' \ - f'{PREFIX}n={n}, img_size={img_size}, metric_all={x.mean():.3f}/{best.mean():.3f}-mean/best, ' \ - f'past_thr={x[x > thr].mean():.3f}-mean: ' + s = ( + f"{PREFIX}thr={thr:.2f}: {bpr:.4f} best possible recall, {aat:.2f} anchors past thr\n" + f"{PREFIX}n={n}, img_size={img_size}, metric_all={x.mean():.3f}/{best.mean():.3f}-mean/best, " + f"past_thr={x[x > thr].mean():.3f}-mean: " + ) for x in k: - s += '%i,%i, ' % (round(x[0]), round(x[1])) + s += "%i,%i, " % (round(x[0]), round(x[1])) if verbose: LOGGER.info(s[:-2]) return k if isinstance(dataset, str): # *.yaml file - with open(dataset, errors='ignore') as f: + with open(dataset, errors="ignore") as f: data_dict = yaml.safe_load(f) # model dict from utils.dataloaders import LoadImagesAndLabels - dataset = LoadImagesAndLabels(data_dict['train'], augment=True, rect=True) + + dataset = LoadImagesAndLabels(data_dict["train"], augment=True, rect=True) # Get label wh shapes = img_size * dataset.shapes / dataset.shapes.max(1, keepdims=True) @@ -122,19 +124,19 @@ def print_results(k, verbose=True): # Filter i = (wh0 < 3.0).any(1).sum() if i: - LOGGER.info(f'{PREFIX}WARNING ⚠️ Extremely small objects found: {i} of {len(wh0)} labels are <3 pixels in size') + LOGGER.info(f"{PREFIX}WARNING ⚠️ Extremely small objects found: {i} of {len(wh0)} labels are <3 pixels in size") wh = wh0[(wh0 >= 2.0).any(1)].astype(np.float32) # filter > 2 pixels # wh = wh * (npr.rand(wh.shape[0], 1) * 0.9 + 0.1) # multiply by random scale 0-1 # Kmeans init try: - LOGGER.info(f'{PREFIX}Running kmeans for {n} anchors on {len(wh)} points...') + LOGGER.info(f"{PREFIX}Running kmeans for {n} anchors on {len(wh)} points...") assert n <= len(wh) # apply overdetermined constraint s = wh.std(0) # sigmas for whitening k = kmeans(wh / s, n, iter=30)[0] * s # points assert n == len(k) # kmeans may return fewer points than requested if wh is insufficient or too similar except Exception: - LOGGER.warning(f'{PREFIX}WARNING ⚠️ switching strategies from kmeans to random init') + LOGGER.warning(f"{PREFIX}WARNING ⚠️ switching strategies from kmeans to random init") k = np.sort(npr.rand(n * 2)).reshape(n, 2) * img_size # random init wh, wh0 = (torch.tensor(x, dtype=torch.float32) for x in (wh, wh0)) k = print_results(k, verbose=False) @@ -162,7 +164,7 @@ def print_results(k, verbose=True): fg = anchor_fitness(kg) if fg > f: f, k = fg, kg.copy() - pbar.desc = f'{PREFIX}Evolving anchors with Genetic Algorithm: fitness = {f:.4f}' + pbar.desc = f"{PREFIX}Evolving anchors with Genetic Algorithm: fitness = {f:.4f}" if verbose: print_results(k, verbose) diff --git a/utils/autobatch.py b/utils/autobatch.py index 71faf8783f..4eaf153cb9 100644 --- a/utils/autobatch.py +++ b/utils/autobatch.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Auto-batch utils -""" +"""Auto-batch utils.""" from copy import deepcopy @@ -27,14 +25,14 @@ def autobatch(model, imgsz=640, fraction=0.8, batch_size=16): # print(autobatch(model)) # Check device - prefix = colorstr('AutoBatch: ') - LOGGER.info(f'{prefix}Computing optimal batch size for --imgsz {imgsz}') + prefix = colorstr("AutoBatch: ") + LOGGER.info(f"{prefix}Computing optimal batch size for --imgsz {imgsz}") device = next(model.parameters()).device # get model device - if device.type == 'cpu': - LOGGER.info(f'{prefix}CUDA not detected, using default CPU batch-size {batch_size}') + if device.type == "cpu": + LOGGER.info(f"{prefix}CUDA not detected, using default CPU batch-size {batch_size}") return batch_size if torch.backends.cudnn.benchmark: - LOGGER.info(f'{prefix} ⚠️ Requires torch.backends.cudnn.benchmark=False, using default batch-size {batch_size}') + LOGGER.info(f"{prefix} ⚠️ Requires torch.backends.cudnn.benchmark=False, using default batch-size {batch_size}") return batch_size # Inspect CUDA memory @@ -45,7 +43,7 @@ def autobatch(model, imgsz=640, fraction=0.8, batch_size=16): r = torch.cuda.memory_reserved(device) / gb # GiB reserved a = torch.cuda.memory_allocated(device) / gb # GiB allocated f = t - (r + a) # GiB free - LOGGER.info(f'{prefix}{d} ({properties.name}) {t:.2f}G total, {r:.2f}G reserved, {a:.2f}G allocated, {f:.2f}G free') + LOGGER.info(f"{prefix}{d} ({properties.name}) {t:.2f}G total, {r:.2f}G reserved, {a:.2f}G allocated, {f:.2f}G free") # Profile batch sizes batch_sizes = [1, 2, 4, 8, 16] @@ -53,11 +51,11 @@ def autobatch(model, imgsz=640, fraction=0.8, batch_size=16): img = [torch.empty(b, 3, imgsz, imgsz) for b in batch_sizes] results = profile(img, model, n=3, device=device) except Exception as e: - LOGGER.warning(f'{prefix}{e}') + LOGGER.warning(f"{prefix}{e}") # Fit a solution y = [x[2] for x in results if x] # memory [2] - p = np.polyfit(batch_sizes[:len(y)], y, deg=1) # first degree polynomial fit + p = np.polyfit(batch_sizes[: len(y)], y, deg=1) # first degree polynomial fit b = int((f * fraction - p[1]) / p[0]) # y intercept (optimal batch size) if None in results: # some sizes failed i = results.index(None) # first fail index @@ -65,8 +63,8 @@ def autobatch(model, imgsz=640, fraction=0.8, batch_size=16): b = batch_sizes[max(i - 1, 0)] # select prior safe point if b < 1 or b > 1024: # b outside of safe range b = batch_size - LOGGER.warning(f'{prefix}WARNING ⚠️ CUDA anomaly detected, recommend restart environment and retry command.') + LOGGER.warning(f"{prefix}WARNING ⚠️ CUDA anomaly detected, recommend restart environment and retry command.") fraction = (np.polyval(p, b) + r + a) / t # actual fraction predicted - LOGGER.info(f'{prefix}Using batch-size {b} for {d} {t * fraction:.2f}G/{t:.2f}G ({fraction * 100:.0f}%) ✅') + LOGGER.info(f"{prefix}Using batch-size {b} for {d} {t * fraction:.2f}G/{t:.2f}G ({fraction * 100:.0f}%) ✅") return b diff --git a/utils/aws/resume.py b/utils/aws/resume.py index e34bc2d72c..91643e2c40 100644 --- a/utils/aws/resume.py +++ b/utils/aws/resume.py @@ -14,27 +14,27 @@ sys.path.append(str(ROOT)) # add ROOT to PATH port = 0 # --master_port -path = Path('').resolve() -for last in path.rglob('*/**/last.pt'): +path = Path("").resolve() +for last in path.rglob("*/**/last.pt"): ckpt = torch.load(last) - if ckpt['optimizer'] is None: + if ckpt["optimizer"] is None: continue # Load opt.yaml - with open(last.parent.parent / 'opt.yaml', errors='ignore') as f: + with open(last.parent.parent / "opt.yaml", errors="ignore") as f: opt = yaml.safe_load(f) # Get device count - d = opt['device'].split(',') # devices + d = opt["device"].split(",") # devices nd = len(d) # number of devices ddp = nd > 1 or (nd == 0 and torch.cuda.device_count() > 1) # distributed data parallel if ddp: # multi-GPU port += 1 - cmd = f'python -m torch.distributed.run --nproc_per_node {nd} --master_port {port} train.py --resume {last}' + cmd = f"python -m torch.distributed.run --nproc_per_node {nd} --master_port {port} train.py --resume {last}" else: # single-GPU - cmd = f'python train.py --resume {last}' + cmd = f"python train.py --resume {last}" - cmd += ' > /dev/null 2>&1 &' # redirect output to dev/null and run in daemon thread + cmd += " > /dev/null 2>&1 &" # redirect output to dev/null and run in daemon thread print(cmd) os.system(cmd) diff --git a/utils/callbacks.py b/utils/callbacks.py index fff6b0356e..6b5321f1f3 100644 --- a/utils/callbacks.py +++ b/utils/callbacks.py @@ -1,43 +1,40 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Callback utils -""" +"""Callback utils.""" import threading class Callbacks: - """" - Handles all registered callbacks for YOLOv3 Hooks - """ + """" Handles all registered callbacks for YOLOv3 Hooks.""" def __init__(self): # Define the available callbacks self._callbacks = { - 'on_pretrain_routine_start': [], - 'on_pretrain_routine_end': [], - 'on_train_start': [], - 'on_train_epoch_start': [], - 'on_train_batch_start': [], - 'optimizer_step': [], - 'on_before_zero_grad': [], - 'on_train_batch_end': [], - 'on_train_epoch_end': [], - 'on_val_start': [], - 'on_val_batch_start': [], - 'on_val_image_end': [], - 'on_val_batch_end': [], - 'on_val_end': [], - 'on_fit_epoch_end': [], # fit = train + val - 'on_model_save': [], - 'on_train_end': [], - 'on_params_update': [], - 'teardown': [], } + "on_pretrain_routine_start": [], + "on_pretrain_routine_end": [], + "on_train_start": [], + "on_train_epoch_start": [], + "on_train_batch_start": [], + "optimizer_step": [], + "on_before_zero_grad": [], + "on_train_batch_end": [], + "on_train_epoch_end": [], + "on_val_start": [], + "on_val_batch_start": [], + "on_val_image_end": [], + "on_val_batch_end": [], + "on_val_end": [], + "on_fit_epoch_end": [], # fit = train + val + "on_model_save": [], + "on_train_end": [], + "on_params_update": [], + "teardown": [], + } self.stop_training = False # set True to interrupt training - def register_action(self, hook, name='', callback=None): + def register_action(self, hook, name="", callback=None): """ - Register a new action to a callback hook + Register a new action to a callback hook. Args: hook: The callback hook name to register the action to @@ -46,11 +43,11 @@ def register_action(self, hook, name='', callback=None): """ assert hook in self._callbacks, f"hook '{hook}' not found in callbacks {self._callbacks}" assert callable(callback), f"callback '{callback}' is not callable" - self._callbacks[hook].append({'name': name, 'callback': callback}) + self._callbacks[hook].append({"name": name, "callback": callback}) def get_registered_actions(self, hook=None): - """" - Returns all the registered actions by callback hook + """ + " Returns all the registered actions by callback hook. Args: hook: The name of the hook to check, defaults to all @@ -59,7 +56,7 @@ def get_registered_actions(self, hook=None): def run(self, hook, *args, thread=False, **kwargs): """ - Loop through the registered actions and fire all callbacks on main thread + Loop through the registered actions and fire all callbacks on main thread. Args: hook: The name of the hook to check, defaults to all @@ -71,6 +68,6 @@ def run(self, hook, *args, thread=False, **kwargs): assert hook in self._callbacks, f"hook '{hook}' not found in callbacks {self._callbacks}" for logger in self._callbacks[hook]: if thread: - threading.Thread(target=logger['callback'], args=args, kwargs=kwargs, daemon=True).start() + threading.Thread(target=logger["callback"], args=args, kwargs=kwargs, daemon=True).start() else: - logger['callback'](*args, **kwargs) + logger["callback"](*args, **kwargs) diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 5d119c2e77..a290111de8 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Dataloaders and dataset utils -""" +"""Dataloaders and dataset utils.""" import contextlib import glob @@ -28,24 +26,48 @@ from torch.utils.data import DataLoader, Dataset, dataloader, distributed from tqdm import tqdm -from utils.augmentations import (Albumentations, augment_hsv, classify_albumentations, classify_transforms, copy_paste, - letterbox, mixup, random_perspective) -from utils.general import (DATASETS_DIR, LOGGER, NUM_THREADS, TQDM_BAR_FORMAT, check_dataset, check_requirements, - check_yaml, clean_str, cv2, is_colab, is_kaggle, segments2boxes, unzip_file, xyn2xy, - xywh2xyxy, xywhn2xyxy, xyxy2xywhn) +from utils.augmentations import ( + Albumentations, + augment_hsv, + classify_albumentations, + classify_transforms, + copy_paste, + letterbox, + mixup, + random_perspective, +) +from utils.general import ( + DATASETS_DIR, + LOGGER, + NUM_THREADS, + TQDM_BAR_FORMAT, + check_dataset, + check_requirements, + check_yaml, + clean_str, + cv2, + is_colab, + is_kaggle, + segments2boxes, + unzip_file, + xyn2xy, + xywh2xyxy, + xywhn2xyxy, + xyxy2xywhn, +) from utils.torch_utils import torch_distributed_zero_first # Parameters -HELP_URL = 'See https://docs.ultralytics.com/yolov5/tutorials/train_custom_data' -IMG_FORMATS = 'bmp', 'dng', 'jpeg', 'jpg', 'mpo', 'png', 'tif', 'tiff', 'webp', 'pfm' # include image suffixes -VID_FORMATS = 'asf', 'avi', 'gif', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'ts', 'wmv' # include video suffixes -LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html -RANK = int(os.getenv('RANK', -1)) -PIN_MEMORY = str(os.getenv('PIN_MEMORY', True)).lower() == 'true' # global pin_memory for dataloaders +HELP_URL = "See https://docs.ultralytics.com/yolov5/tutorials/train_custom_data" +IMG_FORMATS = "bmp", "dng", "jpeg", "jpg", "mpo", "png", "tif", "tiff", "webp", "pfm" # include image suffixes +VID_FORMATS = "asf", "avi", "gif", "m4v", "mkv", "mov", "mp4", "mpeg", "mpg", "ts", "wmv" # include video suffixes +LOCAL_RANK = int(os.getenv("LOCAL_RANK", -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv("RANK", -1)) +PIN_MEMORY = str(os.getenv("PIN_MEMORY", True)).lower() == "true" # global pin_memory for dataloaders # Get orientation exif tag for orientation in ExifTags.TAGS.keys(): - if ExifTags.TAGS[orientation] == 'Orientation': + if ExifTags.TAGS[orientation] == "Orientation": break @@ -53,7 +75,7 @@ def get_hash(paths): # Returns a single hash value of a list of paths (files or dirs) size = sum(os.path.getsize(p) for p in paths if os.path.exists(p)) # sizes h = hashlib.sha256(str(size).encode()) # hash sizes - h.update(''.join(paths).encode()) # hash paths + h.update("".join(paths).encode()) # hash paths return h.hexdigest() # return hash @@ -85,40 +107,43 @@ def exif_transpose(image): 5: Image.TRANSPOSE, 6: Image.ROTATE_270, 7: Image.TRANSVERSE, - 8: Image.ROTATE_90}.get(orientation) + 8: Image.ROTATE_90, + }.get(orientation) if method is not None: image = image.transpose(method) del exif[0x0112] - image.info['exif'] = exif.tobytes() + image.info["exif"] = exif.tobytes() return image def seed_worker(worker_id): # Set dataloader worker seed https://pytorch.org/docs/stable/notes/randomness.html#dataloader - worker_seed = torch.initial_seed() % 2 ** 32 + worker_seed = torch.initial_seed() % 2**32 np.random.seed(worker_seed) random.seed(worker_seed) -def create_dataloader(path, - imgsz, - batch_size, - stride, - single_cls=False, - hyp=None, - augment=False, - cache=False, - pad=0.0, - rect=False, - rank=-1, - workers=8, - image_weights=False, - quad=False, - prefix='', - shuffle=False, - seed=0): +def create_dataloader( + path, + imgsz, + batch_size, + stride, + single_cls=False, + hyp=None, + augment=False, + cache=False, + pad=0.0, + rect=False, + rank=-1, + workers=8, + image_weights=False, + quad=False, + prefix="", + shuffle=False, + seed=0, +): if rect and shuffle: - LOGGER.warning('WARNING ⚠️ --rect is incompatible with DataLoader shuffle, setting shuffle=False') + LOGGER.warning("WARNING ⚠️ --rect is incompatible with DataLoader shuffle, setting shuffle=False") shuffle = False with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP dataset = LoadImagesAndLabels( @@ -133,7 +158,8 @@ def create_dataloader(path, stride=int(stride), pad=pad, image_weights=image_weights, - prefix=prefix) + prefix=prefix, + ) batch_size = min(batch_size, len(dataset)) nd = torch.cuda.device_count() # number of CUDA devices @@ -142,26 +168,29 @@ def create_dataloader(path, loader = DataLoader if image_weights else InfiniteDataLoader # only DataLoader allows for attribute updates generator = torch.Generator() generator.manual_seed(6148914691236517205 + seed + RANK) - return loader(dataset, - batch_size=batch_size, - shuffle=shuffle and sampler is None, - num_workers=nw, - sampler=sampler, - pin_memory=PIN_MEMORY, - collate_fn=LoadImagesAndLabels.collate_fn4 if quad else LoadImagesAndLabels.collate_fn, - worker_init_fn=seed_worker, - generator=generator), dataset + return loader( + dataset, + batch_size=batch_size, + shuffle=shuffle and sampler is None, + num_workers=nw, + sampler=sampler, + pin_memory=PIN_MEMORY, + collate_fn=LoadImagesAndLabels.collate_fn4 if quad else LoadImagesAndLabels.collate_fn, + worker_init_fn=seed_worker, + generator=generator, + ), dataset class InfiniteDataLoader(dataloader.DataLoader): - """ Dataloader that reuses workers + """ + Dataloader that reuses workers. Uses same syntax as vanilla DataLoader """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - object.__setattr__(self, 'batch_sampler', _RepeatSampler(self.batch_sampler)) + object.__setattr__(self, "batch_sampler", _RepeatSampler(self.batch_sampler)) self.iterator = super().__iter__() def __len__(self): @@ -173,7 +202,8 @@ def __iter__(self): class _RepeatSampler: - """ Sampler that repeats forever + """ + Sampler that repeats forever. Args: sampler (Sampler) @@ -191,7 +221,7 @@ class LoadScreenshots: # YOLOv3 screenshot dataloader, i.e. `python detect.py --source "screen 0 100 100 512 256"` def __init__(self, source, img_size=640, stride=32, auto=True, transforms=None): # source = [screen_number left top width height] (pixels) - check_requirements('mss') + check_requirements("mss") import mss source, *params = source.split() @@ -206,17 +236,17 @@ def __init__(self, source, img_size=640, stride=32, auto=True, transforms=None): self.stride = stride self.transforms = transforms self.auto = auto - self.mode = 'stream' + self.mode = "stream" self.frame = 0 self.sct = mss.mss() # Parse monitor shape monitor = self.sct.monitors[self.screen] - self.top = monitor['top'] if top is None else (monitor['top'] + top) - self.left = monitor['left'] if left is None else (monitor['left'] + left) - self.width = width or monitor['width'] - self.height = height or monitor['height'] - self.monitor = {'left': self.left, 'top': self.top, 'width': self.width, 'height': self.height} + self.top = monitor["top"] if top is None else (monitor["top"] + top) + self.left = monitor["left"] if left is None else (monitor["left"] + left) + self.width = width or monitor["width"] + self.height = height or monitor["height"] + self.monitor = {"left": self.left, "top": self.top, "width": self.width, "height": self.height} def __iter__(self): return self @@ -224,7 +254,7 @@ def __iter__(self): def __next__(self): # mss screen capture: get raw pixels from the screen as np array im0 = np.array(self.sct.grab(self.monitor))[:, :, :3] # [:, :, :3] BGRA to BGR - s = f'screen {self.screen} (LTWH): {self.left},{self.top},{self.width},{self.height}: ' + s = f"screen {self.screen} (LTWH): {self.left},{self.top},{self.width},{self.height}: " if self.transforms: im = self.transforms(im0) # transforms @@ -239,22 +269,22 @@ def __next__(self): class LoadImages: # YOLOv3 image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4` def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): - if isinstance(path, str) and Path(path).suffix == '.txt': # *.txt file with img/vid/dir on each line + if isinstance(path, str) and Path(path).suffix == ".txt": # *.txt file with img/vid/dir on each line path = Path(path).read_text().rsplit() files = [] for p in sorted(path) if isinstance(path, (list, tuple)) else [path]: p = str(Path(p).resolve()) - if '*' in p: + if "*" in p: files.extend(sorted(glob.glob(p, recursive=True))) # glob elif os.path.isdir(p): - files.extend(sorted(glob.glob(os.path.join(p, '*.*')))) # dir + files.extend(sorted(glob.glob(os.path.join(p, "*.*")))) # dir elif os.path.isfile(p): files.append(p) # files else: - raise FileNotFoundError(f'{p} does not exist') + raise FileNotFoundError(f"{p} does not exist") - images = [x for x in files if x.split('.')[-1].lower() in IMG_FORMATS] - videos = [x for x in files if x.split('.')[-1].lower() in VID_FORMATS] + images = [x for x in files if x.split(".")[-1].lower() in IMG_FORMATS] + videos = [x for x in files if x.split(".")[-1].lower() in VID_FORMATS] ni, nv = len(images), len(videos) self.img_size = img_size @@ -262,7 +292,7 @@ def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vi self.files = images + videos self.nf = ni + nv # number of files self.video_flag = [False] * ni + [True] * nv - self.mode = 'image' + self.mode = "image" self.auto = auto self.transforms = transforms # optional self.vid_stride = vid_stride # video frame-rate stride @@ -270,8 +300,10 @@ def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vi self._new_video(videos[0]) # new video else: self.cap = None - assert self.nf > 0, f'No images or videos found in {p}. ' \ - f'Supported formats are:\nimages: {IMG_FORMATS}\nvideos: {VID_FORMATS}' + assert self.nf > 0, ( + f"No images or videos found in {p}. " + f"Supported formats are:\nimages: {IMG_FORMATS}\nvideos: {VID_FORMATS}" + ) def __iter__(self): self.count = 0 @@ -284,7 +316,7 @@ def __next__(self): if self.video_flag[self.count]: # Read video - self.mode = 'video' + self.mode = "video" for _ in range(self.vid_stride): self.cap.grab() ret_val, im0 = self.cap.retrieve() @@ -299,14 +331,14 @@ def __next__(self): self.frame += 1 # im0 = self._cv2_rotate(im0) # for use if cv2 autorotation is False - s = f'video {self.count + 1}/{self.nf} ({self.frame}/{self.frames}) {path}: ' + s = f"video {self.count + 1}/{self.nf} ({self.frame}/{self.frames}) {path}: " else: # Read image self.count += 1 im0 = cv2.imread(path) # BGR - assert im0 is not None, f'Image Not Found {path}' - s = f'image {self.count}/{self.nf} {path}: ' + assert im0 is not None, f"Image Not Found {path}" + s = f"image {self.count}/{self.nf} {path}: " if self.transforms: im = self.transforms(im0) # transforms @@ -341,9 +373,9 @@ def __len__(self): class LoadStreams: # YOLOv3 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams` - def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): + def __init__(self, sources="file.streams", img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): torch.backends.cudnn.benchmark = True # faster for fixed-size inference - self.mode = 'stream' + self.mode = "stream" self.img_size = img_size self.stride = stride self.vid_stride = vid_stride # video frame-rate stride @@ -353,29 +385,30 @@ def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, t self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n for i, s in enumerate(sources): # index, source # Start thread to read frames from video stream - st = f'{i + 1}/{n}: {s}... ' - if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video + st = f"{i + 1}/{n}: {s}... " + if urlparse(s).hostname in ("www.youtube.com", "youtube.com", "youtu.be"): # if source is YouTube video # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/LNwODJXcvt4' - check_requirements(('pafy', 'youtube_dl==2020.12.2')) + check_requirements(("pafy", "youtube_dl==2020.12.2")) import pafy - s = pafy.new(s).getbest(preftype='mp4').url # YouTube URL + + s = pafy.new(s).getbest(preftype="mp4").url # YouTube URL s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam if s == 0: - assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.' - assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.' + assert not is_colab(), "--source 0 webcam unsupported on Colab. Rerun command in a local environment." + assert not is_kaggle(), "--source 0 webcam unsupported on Kaggle. Rerun command in a local environment." cap = cv2.VideoCapture(s) - assert cap.isOpened(), f'{st}Failed to open {s}' + assert cap.isOpened(), f"{st}Failed to open {s}" w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps = cap.get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan - self.frames[i] = max(int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback + self.frames[i] = max(int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float("inf") # infinite stream fallback self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback _, self.imgs[i] = cap.read() # guarantee first frame self.threads[i] = Thread(target=self.update, args=([i, cap, s]), daemon=True) - LOGGER.info(f'{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)') + LOGGER.info(f"{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)") self.threads[i].start() - LOGGER.info('') # newline + LOGGER.info("") # newline # check for common shapes s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs]) @@ -383,7 +416,7 @@ def __init__(self, sources='file.streams', img_size=640, stride=32, auto=True, t self.auto = auto and self.rect self.transforms = transforms # optional if not self.rect: - LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.') + LOGGER.warning("WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.") def update(self, i, cap, stream): # Read stream `i` frames in daemon thread @@ -396,7 +429,7 @@ def update(self, i, cap, stream): if success: self.imgs[i] = im else: - LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.') + LOGGER.warning("WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.") self.imgs[i] = np.zeros_like(self.imgs[i]) cap.open(stream) # re-open stream if signal was lost time.sleep(0.0) # wait time @@ -407,7 +440,7 @@ def __iter__(self): def __next__(self): self.count += 1 - if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit + if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord("q"): # q to quit cv2.destroyAllWindows() raise StopIteration @@ -419,7 +452,7 @@ def __next__(self): im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW im = np.ascontiguousarray(im) # contiguous - return self.sources, im, im0, None, '' + return self.sources, im, im0, None, "" def __len__(self): return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years @@ -427,8 +460,8 @@ def __len__(self): def img2label_paths(img_paths): # Define label paths as a function of image paths - sa, sb = f'{os.sep}images{os.sep}', f'{os.sep}labels{os.sep}' # /images/, /labels/ substrings - return [sb.join(x.rsplit(sa, 1)).rsplit('.', 1)[0] + '.txt' for x in img_paths] + sa, sb = f"{os.sep}images{os.sep}", f"{os.sep}labels{os.sep}" # /images/, /labels/ substrings + return [sb.join(x.rsplit(sa, 1)).rsplit(".", 1)[0] + ".txt" for x in img_paths] class LoadImagesAndLabels(Dataset): @@ -436,20 +469,22 @@ class LoadImagesAndLabels(Dataset): cache_version = 0.6 # dataset labels *.cache version rand_interp_methods = [cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_CUBIC, cv2.INTER_AREA, cv2.INTER_LANCZOS4] - def __init__(self, - path, - img_size=640, - batch_size=16, - augment=False, - hyp=None, - rect=False, - image_weights=False, - cache_images=False, - single_cls=False, - stride=32, - pad=0.0, - min_items=0, - prefix=''): + def __init__( + self, + path, + img_size=640, + batch_size=16, + augment=False, + hyp=None, + rect=False, + image_weights=False, + cache_images=False, + single_cls=False, + stride=32, + pad=0.0, + min_items=0, + prefix="", + ): self.img_size = img_size self.augment = augment self.hyp = hyp @@ -466,46 +501,46 @@ def __init__(self, for p in path if isinstance(path, list) else [path]: p = Path(p) # os-agnostic if p.is_dir(): # dir - f += glob.glob(str(p / '**' / '*.*'), recursive=True) + f += glob.glob(str(p / "**" / "*.*"), recursive=True) # f = list(p.rglob('*.*')) # pathlib elif p.is_file(): # file with open(p) as t: t = t.read().strip().splitlines() parent = str(p.parent) + os.sep - f += [x.replace('./', parent, 1) if x.startswith('./') else x for x in t] # to global path + f += [x.replace("./", parent, 1) if x.startswith("./") else x for x in t] # to global path # f += [p.parent / x.lstrip(os.sep) for x in t] # to global path (pathlib) else: - raise FileNotFoundError(f'{prefix}{p} does not exist') - self.im_files = sorted(x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in IMG_FORMATS) + raise FileNotFoundError(f"{prefix}{p} does not exist") + self.im_files = sorted(x.replace("/", os.sep) for x in f if x.split(".")[-1].lower() in IMG_FORMATS) # self.img_files = sorted([x for x in f if x.suffix[1:].lower() in IMG_FORMATS]) # pathlib - assert self.im_files, f'{prefix}No images found' + assert self.im_files, f"{prefix}No images found" except Exception as e: - raise Exception(f'{prefix}Error loading data from {path}: {e}\n{HELP_URL}') from e + raise Exception(f"{prefix}Error loading data from {path}: {e}\n{HELP_URL}") from e # Check cache self.label_files = img2label_paths(self.im_files) # labels - cache_path = (p if p.is_file() else Path(self.label_files[0]).parent).with_suffix('.cache') + cache_path = (p if p.is_file() else Path(self.label_files[0]).parent).with_suffix(".cache") try: cache, exists = np.load(cache_path, allow_pickle=True).item(), True # load dict - assert cache['version'] == self.cache_version # matches current version - assert cache['hash'] == get_hash(self.label_files + self.im_files) # identical hash + assert cache["version"] == self.cache_version # matches current version + assert cache["hash"] == get_hash(self.label_files + self.im_files) # identical hash except Exception: cache, exists = self.cache_labels(cache_path, prefix), False # run cache ops # Display cache - nf, nm, ne, nc, n = cache.pop('results') # found, missing, empty, corrupt, total + nf, nm, ne, nc, n = cache.pop("results") # found, missing, empty, corrupt, total if exists and LOCAL_RANK in {-1, 0}: - d = f'Scanning {cache_path}... {nf} images, {nm + ne} backgrounds, {nc} corrupt' + d = f"Scanning {cache_path}... {nf} images, {nm + ne} backgrounds, {nc} corrupt" tqdm(None, desc=prefix + d, total=n, initial=n, bar_format=TQDM_BAR_FORMAT) # display cache results - if cache['msgs']: - LOGGER.info('\n'.join(cache['msgs'])) # display warnings - assert nf > 0 or not augment, f'{prefix}No labels found in {cache_path}, can not start training. {HELP_URL}' + if cache["msgs"]: + LOGGER.info("\n".join(cache["msgs"])) # display warnings + assert nf > 0 or not augment, f"{prefix}No labels found in {cache_path}, can not start training. {HELP_URL}" # Read cache - [cache.pop(k) for k in ('hash', 'version', 'msgs')] # remove items + [cache.pop(k) for k in ("hash", "version", "msgs")] # remove items labels, shapes, self.segments = zip(*cache.values()) nl = len(np.concatenate(labels, 0)) # number of labels - assert nl > 0 or not augment, f'{prefix}All labels empty in {cache_path}, can not start training. {HELP_URL}' + assert nl > 0 or not augment, f"{prefix}All labels empty in {cache_path}, can not start training. {HELP_URL}" self.labels = list(labels) self.shapes = np.array(shapes) self.im_files = list(cache.keys()) # update @@ -514,7 +549,7 @@ def __init__(self, # Filter images if min_items: include = np.array([len(x) >= min_items for x in self.labels]).nonzero()[0].astype(int) - LOGGER.info(f'{prefix}{n - len(include)}/{n} images filtered from dataset') + LOGGER.info(f"{prefix}{n - len(include)}/{n} images filtered from dataset") self.im_files = [self.im_files[i] for i in include] self.label_files = [self.label_files[i] for i in include] self.labels = [self.labels[i] for i in include] @@ -568,52 +603,56 @@ def __init__(self, self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(int) * stride # Cache images into RAM/disk for faster training - if cache_images == 'ram' and not self.check_cache_ram(prefix=prefix): + if cache_images == "ram" and not self.check_cache_ram(prefix=prefix): cache_images = False self.ims = [None] * n - self.npy_files = [Path(f).with_suffix('.npy') for f in self.im_files] + self.npy_files = [Path(f).with_suffix(".npy") for f in self.im_files] if cache_images: b, gb = 0, 1 << 30 # bytes of cached images, bytes per gigabytes self.im_hw0, self.im_hw = [None] * n, [None] * n - fcn = self.cache_images_to_disk if cache_images == 'disk' else self.load_image + fcn = self.cache_images_to_disk if cache_images == "disk" else self.load_image results = ThreadPool(NUM_THREADS).imap(fcn, range(n)) pbar = tqdm(enumerate(results), total=n, bar_format=TQDM_BAR_FORMAT, disable=LOCAL_RANK > 0) for i, x in pbar: - if cache_images == 'disk': + if cache_images == "disk": b += self.npy_files[i].stat().st_size else: # 'ram' self.ims[i], self.im_hw0[i], self.im_hw[i] = x # im, hw_orig, hw_resized = load_image(self, i) b += self.ims[i].nbytes - pbar.desc = f'{prefix}Caching images ({b / gb:.1f}GB {cache_images})' + pbar.desc = f"{prefix}Caching images ({b / gb:.1f}GB {cache_images})" pbar.close() - def check_cache_ram(self, safety_margin=0.1, prefix=''): + def check_cache_ram(self, safety_margin=0.1, prefix=""): # Check image caching requirements vs available memory b, gb = 0, 1 << 30 # bytes of cached images, bytes per gigabytes n = min(self.n, 30) # extrapolate from 30 random images for _ in range(n): im = cv2.imread(random.choice(self.im_files)) # sample image ratio = self.img_size / max(im.shape[0], im.shape[1]) # max(h, w) # ratio - b += im.nbytes * ratio ** 2 + b += im.nbytes * ratio**2 mem_required = b * self.n / n # GB required to cache dataset into RAM mem = psutil.virtual_memory() cache = mem_required * (1 + safety_margin) < mem.available # to cache or not to cache, that is the question if not cache: - LOGGER.info(f'{prefix}{mem_required / gb:.1f}GB RAM required, ' - f'{mem.available / gb:.1f}/{mem.total / gb:.1f}GB available, ' - f"{'caching images ✅' if cache else 'not caching images ⚠️'}") + LOGGER.info( + f'{prefix}{mem_required / gb:.1f}GB RAM required, ' + f'{mem.available / gb:.1f}/{mem.total / gb:.1f}GB available, ' + f"{'caching images ✅' if cache else 'not caching images ⚠️'}" + ) return cache - def cache_labels(self, path=Path('./labels.cache'), prefix=''): + def cache_labels(self, path=Path("./labels.cache"), prefix=""): # Cache dataset labels, check images and read shapes x = {} # dict nm, nf, ne, nc, msgs = 0, 0, 0, 0, [] # number missing, found, empty, corrupt, messages - desc = f'{prefix}Scanning {path.parent / path.stem}...' + desc = f"{prefix}Scanning {path.parent / path.stem}..." with Pool(NUM_THREADS) as pool: - pbar = tqdm(pool.imap(verify_image_label, zip(self.im_files, self.label_files, repeat(prefix))), - desc=desc, - total=len(self.im_files), - bar_format=TQDM_BAR_FORMAT) + pbar = tqdm( + pool.imap(verify_image_label, zip(self.im_files, self.label_files, repeat(prefix))), + desc=desc, + total=len(self.im_files), + bar_format=TQDM_BAR_FORMAT, + ) for im_file, lb, shape, segments, nm_f, nf_f, ne_f, nc_f, msg in pbar: nm += nm_f nf += nf_f @@ -623,23 +662,23 @@ def cache_labels(self, path=Path('./labels.cache'), prefix=''): x[im_file] = [lb, shape, segments] if msg: msgs.append(msg) - pbar.desc = f'{desc} {nf} images, {nm + ne} backgrounds, {nc} corrupt' + pbar.desc = f"{desc} {nf} images, {nm + ne} backgrounds, {nc} corrupt" pbar.close() if msgs: - LOGGER.info('\n'.join(msgs)) + LOGGER.info("\n".join(msgs)) if nf == 0: - LOGGER.warning(f'{prefix}WARNING ⚠️ No labels found in {path}. {HELP_URL}') - x['hash'] = get_hash(self.label_files + self.im_files) - x['results'] = nf, nm, ne, nc, len(self.im_files) - x['msgs'] = msgs # warnings - x['version'] = self.cache_version # cache version + LOGGER.warning(f"{prefix}WARNING ⚠️ No labels found in {path}. {HELP_URL}") + x["hash"] = get_hash(self.label_files + self.im_files) + x["results"] = nf, nm, ne, nc, len(self.im_files) + x["msgs"] = msgs # warnings + x["version"] = self.cache_version # cache version try: np.save(path, x) # save cache for next time - path.with_suffix('.cache.npy').rename(path) # remove .npy suffix - LOGGER.info(f'{prefix}New cache created: {path}') + path.with_suffix(".cache.npy").rename(path) # remove .npy suffix + LOGGER.info(f"{prefix}New cache created: {path}") except Exception as e: - LOGGER.warning(f'{prefix}WARNING ⚠️ Cache directory {path.parent} is not writeable: {e}') # not writeable + LOGGER.warning(f"{prefix}WARNING ⚠️ Cache directory {path.parent} is not writeable: {e}") # not writeable return x def __len__(self): @@ -655,14 +694,14 @@ def __getitem__(self, index): index = self.indices[index] # linear, shuffled, or image_weights hyp = self.hyp - mosaic = self.mosaic and random.random() < hyp['mosaic'] + mosaic = self.mosaic and random.random() < hyp["mosaic"] if mosaic: # Load mosaic img, labels = self.load_mosaic(index) shapes = None # MixUp augmentation - if random.random() < hyp['mixup']: + if random.random() < hyp["mixup"]: img, labels = mixup(img, labels, *self.load_mosaic(random.randint(0, self.n - 1))) else: @@ -679,17 +718,19 @@ def __getitem__(self, index): labels[:, 1:] = xywhn2xyxy(labels[:, 1:], ratio[0] * w, ratio[1] * h, padw=pad[0], padh=pad[1]) if self.augment: - img, labels = random_perspective(img, - labels, - degrees=hyp['degrees'], - translate=hyp['translate'], - scale=hyp['scale'], - shear=hyp['shear'], - perspective=hyp['perspective']) + img, labels = random_perspective( + img, + labels, + degrees=hyp["degrees"], + translate=hyp["translate"], + scale=hyp["scale"], + shear=hyp["shear"], + perspective=hyp["perspective"], + ) nl = len(labels) # number of labels if nl: - labels[:, 1:5] = xyxy2xywhn(labels[:, 1:5], w=img.shape[1], h=img.shape[0], clip=True, eps=1E-3) + labels[:, 1:5] = xyxy2xywhn(labels[:, 1:5], w=img.shape[1], h=img.shape[0], clip=True, eps=1e-3) if self.augment: # Albumentations @@ -697,16 +738,16 @@ def __getitem__(self, index): nl = len(labels) # update after albumentations # HSV color-space - augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) + augment_hsv(img, hgain=hyp["hsv_h"], sgain=hyp["hsv_s"], vgain=hyp["hsv_v"]) # Flip up-down - if random.random() < hyp['flipud']: + if random.random() < hyp["flipud"]: img = np.flipud(img) if nl: labels[:, 2] = 1 - labels[:, 2] # Flip left-right - if random.random() < hyp['fliplr']: + if random.random() < hyp["fliplr"]: img = np.fliplr(img) if nl: labels[:, 1] = 1 - labels[:, 1] @@ -727,13 +768,17 @@ def __getitem__(self, index): def load_image(self, i): # Loads 1 image from dataset index 'i', returns (im, original hw, resized hw) - im, f, fn = self.ims[i], self.im_files[i], self.npy_files[i], + im, f, fn = ( + self.ims[i], + self.im_files[i], + self.npy_files[i], + ) if im is None: # not cached in RAM if fn.exists(): # load npy im = np.load(fn) else: # read image im = cv2.imread(f) # BGR - assert im is not None, f'Image Not Found {f}' + assert im is not None, f"Image Not Found {f}" h0, w0 = im.shape[:2] # orig hw r = self.img_size / max(h0, w0) # ratio if r != 1: # if sizes are not equal @@ -793,16 +838,18 @@ def load_mosaic(self, index): # img4, labels4 = replicate(img4, labels4) # replicate # Augment - img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp['copy_paste']) - img4, labels4 = random_perspective(img4, - labels4, - segments4, - degrees=self.hyp['degrees'], - translate=self.hyp['translate'], - scale=self.hyp['scale'], - shear=self.hyp['shear'], - perspective=self.hyp['perspective'], - border=self.mosaic_border) # border to remove + img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp["copy_paste"]) + img4, labels4 = random_perspective( + img4, + labels4, + segments4, + degrees=self.hyp["degrees"], + translate=self.hyp["translate"], + scale=self.hyp["scale"], + shear=self.hyp["shear"], + perspective=self.hyp["perspective"], + border=self.mosaic_border, + ) # border to remove return img4, labels4 @@ -851,12 +898,12 @@ def load_mosaic9(self, index): segments9.extend(segments) # Image - img9[y1:y2, x1:x2] = img[y1 - pady:, x1 - padx:] # img9[ymin:ymax, xmin:xmax] + img9[y1:y2, x1:x2] = img[y1 - pady :, x1 - padx :] # img9[ymin:ymax, xmin:xmax] hp, wp = h, w # height, width previous # Offset yc, xc = (int(random.uniform(0, s)) for _ in self.mosaic_border) # mosaic center x, y - img9 = img9[yc:yc + 2 * s, xc:xc + 2 * s] + img9 = img9[yc : yc + 2 * s, xc : xc + 2 * s] # Concat/clip labels labels9 = np.concatenate(labels9, 0) @@ -870,16 +917,18 @@ def load_mosaic9(self, index): # img9, labels9 = replicate(img9, labels9) # replicate # Augment - img9, labels9, segments9 = copy_paste(img9, labels9, segments9, p=self.hyp['copy_paste']) - img9, labels9 = random_perspective(img9, - labels9, - segments9, - degrees=self.hyp['degrees'], - translate=self.hyp['translate'], - scale=self.hyp['scale'], - shear=self.hyp['shear'], - perspective=self.hyp['perspective'], - border=self.mosaic_border) # border to remove + img9, labels9, segments9 = copy_paste(img9, labels9, segments9, p=self.hyp["copy_paste"]) + img9, labels9 = random_perspective( + img9, + labels9, + segments9, + degrees=self.hyp["degrees"], + translate=self.hyp["translate"], + scale=self.hyp["scale"], + shear=self.hyp["shear"], + perspective=self.hyp["perspective"], + border=self.mosaic_border, + ) # border to remove return img9, labels9 @@ -902,8 +951,9 @@ def collate_fn4(batch): for i in range(n): # zidane torch.zeros(16,3,720,1280) # BCHW i *= 4 if random.random() < 0.5: - im1 = F.interpolate(im[i].unsqueeze(0).float(), scale_factor=2.0, mode='bilinear', - align_corners=False)[0].type(im[i].type()) + im1 = F.interpolate(im[i].unsqueeze(0).float(), scale_factor=2.0, mode="bilinear", align_corners=False)[ + 0 + ].type(im[i].type()) lb = label[i] else: im1 = torch.cat((torch.cat((im[i], im[i + 1]), 1), torch.cat((im[i + 2], im[i + 3]), 1)), 2) @@ -918,21 +968,21 @@ def collate_fn4(batch): # Ancillary functions -------------------------------------------------------------------------------------------------- -def flatten_recursive(path=DATASETS_DIR / 'coco128'): +def flatten_recursive(path=DATASETS_DIR / "coco128"): # Flatten a recursive directory by bringing all files to top level - new_path = Path(f'{str(path)}_flat') + new_path = Path(f"{str(path)}_flat") if os.path.exists(new_path): shutil.rmtree(new_path) # delete output folder os.makedirs(new_path) # make new output folder - for file in tqdm(glob.glob(f'{str(Path(path))}/**/*.*', recursive=True)): + for file in tqdm(glob.glob(f"{str(Path(path))}/**/*.*", recursive=True)): shutil.copyfile(file, new_path / Path(file).name) -def extract_boxes(path=DATASETS_DIR / 'coco128'): # from utils.dataloaders import *; extract_boxes() +def extract_boxes(path=DATASETS_DIR / "coco128"): # from utils.dataloaders import *; extract_boxes() # Convert detection dataset into classification dataset, with one directory per class path = Path(path) # images dir - shutil.rmtree(path / 'classification') if (path / 'classification').is_dir() else None # remove existing - files = list(path.rglob('*.*')) + shutil.rmtree(path / "classification") if (path / "classification").is_dir() else None # remove existing + files = list(path.rglob("*.*")) n = len(files) # number of files for im_file in tqdm(files, total=n): if im_file.suffix[1:] in IMG_FORMATS: @@ -948,7 +998,7 @@ def extract_boxes(path=DATASETS_DIR / 'coco128'): # from utils.dataloaders impo for j, x in enumerate(lb): c = int(x[0]) # class - f = (path / 'classifier') / f'{c}' / f'{path.stem}_{im_file.stem}_{j}.jpg' # new filename + f = (path / "classifier") / f"{c}" / f"{path.stem}_{im_file.stem}_{j}.jpg" # new filename if not f.parent.is_dir(): f.parent.mkdir(parents=True) @@ -959,11 +1009,11 @@ def extract_boxes(path=DATASETS_DIR / 'coco128'): # from utils.dataloaders impo b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image b[[1, 3]] = np.clip(b[[1, 3]], 0, h) - assert cv2.imwrite(str(f), im[b[1]:b[3], b[0]:b[2]]), f'box failure in {f}' + assert cv2.imwrite(str(f), im[b[1] : b[3], b[0] : b[2]]), f"box failure in {f}" -def autosplit(path=DATASETS_DIR / 'coco128/images', weights=(0.9, 0.1, 0.0), annotated_only=False): - """ Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files +def autosplit(path=DATASETS_DIR / "coco128/images", weights=(0.9, 0.1, 0.0), annotated_only=False): + """Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files Usage: from utils.dataloaders import *; autosplit() Arguments path: Path to images directory @@ -971,40 +1021,40 @@ def autosplit(path=DATASETS_DIR / 'coco128/images', weights=(0.9, 0.1, 0.0), ann annotated_only: Only use images with an annotated txt file """ path = Path(path) # images dir - files = sorted(x for x in path.rglob('*.*') if x.suffix[1:].lower() in IMG_FORMATS) # image files only + files = sorted(x for x in path.rglob("*.*") if x.suffix[1:].lower() in IMG_FORMATS) # image files only n = len(files) # number of files random.seed(0) # for reproducibility indices = random.choices([0, 1, 2], weights=weights, k=n) # assign each image to a split - txt = ['autosplit_train.txt', 'autosplit_val.txt', 'autosplit_test.txt'] # 3 txt files + txt = ["autosplit_train.txt", "autosplit_val.txt", "autosplit_test.txt"] # 3 txt files for x in txt: if (path.parent / x).exists(): (path.parent / x).unlink() # remove existing - print(f'Autosplitting images from {path}' + ', using *.txt labeled images only' * annotated_only) + print(f"Autosplitting images from {path}" + ", using *.txt labeled images only" * annotated_only) for i, img in tqdm(zip(indices, files), total=n): if not annotated_only or Path(img2label_paths([str(img)])[0]).exists(): # check label - with open(path.parent / txt[i], 'a') as f: - f.write(f'./{img.relative_to(path.parent).as_posix()}' + '\n') # add image to txt file + with open(path.parent / txt[i], "a") as f: + f.write(f"./{img.relative_to(path.parent).as_posix()}" + "\n") # add image to txt file def verify_image_label(args): # Verify one image-label pair im_file, lb_file, prefix = args - nm, nf, ne, nc, msg, segments = 0, 0, 0, 0, '', [] # number (missing, found, empty, corrupt), message, segments + nm, nf, ne, nc, msg, segments = 0, 0, 0, 0, "", [] # number (missing, found, empty, corrupt), message, segments try: # verify images im = Image.open(im_file) im.verify() # PIL verify shape = exif_size(im) # image size - assert (shape[0] > 9) & (shape[1] > 9), f'image size {shape} <10 pixels' - assert im.format.lower() in IMG_FORMATS, f'invalid image format {im.format}' - if im.format.lower() in ('jpg', 'jpeg'): - with open(im_file, 'rb') as f: + assert (shape[0] > 9) & (shape[1] > 9), f"image size {shape} <10 pixels" + assert im.format.lower() in IMG_FORMATS, f"invalid image format {im.format}" + if im.format.lower() in ("jpg", "jpeg"): + with open(im_file, "rb") as f: f.seek(-2, 2) - if f.read() != b'\xff\xd9': # corrupt JPEG - ImageOps.exif_transpose(Image.open(im_file)).save(im_file, 'JPEG', subsampling=0, quality=100) - msg = f'{prefix}WARNING ⚠️ {im_file}: corrupt JPEG restored and saved' + if f.read() != b"\xff\xd9": # corrupt JPEG + ImageOps.exif_transpose(Image.open(im_file)).save(im_file, "JPEG", subsampling=0, quality=100) + msg = f"{prefix}WARNING ⚠️ {im_file}: corrupt JPEG restored and saved" # verify labels if os.path.isfile(lb_file): @@ -1018,15 +1068,15 @@ def verify_image_label(args): lb = np.array(lb, dtype=np.float32) nl = len(lb) if nl: - assert lb.shape[1] == 5, f'labels require 5 columns, {lb.shape[1]} columns detected' - assert (lb >= 0).all(), f'negative label values {lb[lb < 0]}' - assert (lb[:, 1:] <= 1).all(), f'non-normalized or out of bounds coordinates {lb[:, 1:][lb[:, 1:] > 1]}' + assert lb.shape[1] == 5, f"labels require 5 columns, {lb.shape[1]} columns detected" + assert (lb >= 0).all(), f"negative label values {lb[lb < 0]}" + assert (lb[:, 1:] <= 1).all(), f"non-normalized or out of bounds coordinates {lb[:, 1:][lb[:, 1:] > 1]}" _, i = np.unique(lb, axis=0, return_index=True) if len(i) < nl: # duplicate row check lb = lb[i] # remove duplicates if segments: segments = [segments[x] for x in i] - msg = f'{prefix}WARNING ⚠️ {im_file}: {nl - len(i)} duplicate labels removed' + msg = f"{prefix}WARNING ⚠️ {im_file}: {nl - len(i)} duplicate labels removed" else: ne = 1 # label empty lb = np.zeros((0, 5), dtype=np.float32) @@ -1036,12 +1086,13 @@ def verify_image_label(args): return im_file, lb, shape, segments, nm, nf, ne, nc, msg except Exception as e: nc = 1 - msg = f'{prefix}WARNING ⚠️ {im_file}: ignoring corrupt image/label: {e}' + msg = f"{prefix}WARNING ⚠️ {im_file}: ignoring corrupt image/label: {e}" return [None, None, None, None, nm, nf, ne, nc, msg] -class HUBDatasetStats(): - """ Class for generating HUB dataset JSON and `-hub` dataset directory +class HUBDatasetStats: + """ + Class for generating HUB dataset JSON and `-hub` dataset directory. Arguments path: Path to data.yaml or data.zip (with data.yaml inside data.zip) @@ -1055,43 +1106,43 @@ class HUBDatasetStats(): stats.process_images() """ - def __init__(self, path='coco128.yaml', autodownload=False): + def __init__(self, path="coco128.yaml", autodownload=False): # Initialize class zipped, data_dir, yaml_path = self._unzip(Path(path)) try: - with open(check_yaml(yaml_path), errors='ignore') as f: + with open(check_yaml(yaml_path), errors="ignore") as f: data = yaml.safe_load(f) # data dict if zipped: - data['path'] = data_dir + data["path"] = data_dir except Exception as e: - raise Exception('error/HUB/dataset_stats/yaml_load') from e + raise Exception("error/HUB/dataset_stats/yaml_load") from e check_dataset(data, autodownload) # download dataset if missing - self.hub_dir = Path(data['path'] + '-hub') - self.im_dir = self.hub_dir / 'images' + self.hub_dir = Path(data["path"] + "-hub") + self.im_dir = self.hub_dir / "images" self.im_dir.mkdir(parents=True, exist_ok=True) # makes /images - self.stats = {'nc': data['nc'], 'names': list(data['names'].values())} # statistics dictionary + self.stats = {"nc": data["nc"], "names": list(data["names"].values())} # statistics dictionary self.data = data @staticmethod def _find_yaml(dir): # Return data.yaml file - files = list(dir.glob('*.yaml')) or list(dir.rglob('*.yaml')) # try root level first and then recursive - assert files, f'No *.yaml file found in {dir}' + files = list(dir.glob("*.yaml")) or list(dir.rglob("*.yaml")) # try root level first and then recursive + assert files, f"No *.yaml file found in {dir}" if len(files) > 1: files = [f for f in files if f.stem == dir.stem] # prefer *.yaml files that match dir name - assert files, f'Multiple *.yaml files found in {dir}, only 1 *.yaml file allowed' - assert len(files) == 1, f'Multiple *.yaml files found: {files}, only 1 *.yaml file allowed in {dir}' + assert files, f"Multiple *.yaml files found in {dir}, only 1 *.yaml file allowed" + assert len(files) == 1, f"Multiple *.yaml files found: {files}, only 1 *.yaml file allowed in {dir}" return files[0] def _unzip(self, path): # Unzip data.zip - if not str(path).endswith('.zip'): # path is data.yaml + if not str(path).endswith(".zip"): # path is data.yaml return False, None, path - assert Path(path).is_file(), f'Error unzipping {path}, file not found' + assert Path(path).is_file(), f"Error unzipping {path}, file not found" unzip_file(path, path=path.parent) - dir = path.with_suffix('') # dataset directory == zip name - assert dir.is_dir(), f'Error unzipping {path}, {dir} not found. path/to/abc.zip MUST unzip to path/to/abc/' + dir = path.with_suffix("") # dataset directory == zip name + assert dir.is_dir(), f"Error unzipping {path}, {dir} not found. path/to/abc.zip MUST unzip to path/to/abc/" return True, str(dir), self._find_yaml(dir) # zipped, data_dir, yaml_path def _hub_ops(self, f, max_dim=1920): @@ -1102,9 +1153,9 @@ def _hub_ops(self, f, max_dim=1920): r = max_dim / max(im.height, im.width) # ratio if r < 1.0: # image too large im = im.resize((int(im.width * r), int(im.height * r))) - im.save(f_new, 'JPEG', quality=50, optimize=True) # save + im.save(f_new, "JPEG", quality=50, optimize=True) # save except Exception as e: # use OpenCV - LOGGER.info(f'WARNING ⚠️ HUB ops PIL failure {f}: {e}') + LOGGER.info(f"WARNING ⚠️ HUB ops PIL failure {f}: {e}") im = cv2.imread(f) im_height, im_width = im.shape[:2] r = max_dim / max(im_height, im_width) # ratio @@ -1118,30 +1169,32 @@ def _round(labels): # Update labels to integer class and 6 decimal place floats return [[int(c), *(round(x, 4) for x in points)] for c, *points in labels] - for split in 'train', 'val', 'test': + for split in "train", "val", "test": if self.data.get(split) is None: self.stats[split] = None # i.e. no test set continue dataset = LoadImagesAndLabels(self.data[split]) # load dataset - x = np.array([ - np.bincount(label[:, 0].astype(int), minlength=self.data['nc']) - for label in tqdm(dataset.labels, total=dataset.n, desc='Statistics')]) # shape(128x80) + x = np.array( + [ + np.bincount(label[:, 0].astype(int), minlength=self.data["nc"]) + for label in tqdm(dataset.labels, total=dataset.n, desc="Statistics") + ] + ) # shape(128x80) self.stats[split] = { - 'instance_stats': { - 'total': int(x.sum()), - 'per_class': x.sum(0).tolist()}, - 'image_stats': { - 'total': dataset.n, - 'unlabelled': int(np.all(x == 0, 1).sum()), - 'per_class': (x > 0).sum(0).tolist()}, - 'labels': [{ - str(Path(k).name): _round(v.tolist())} for k, v in zip(dataset.im_files, dataset.labels)]} + "instance_stats": {"total": int(x.sum()), "per_class": x.sum(0).tolist()}, + "image_stats": { + "total": dataset.n, + "unlabelled": int(np.all(x == 0, 1).sum()), + "per_class": (x > 0).sum(0).tolist(), + }, + "labels": [{str(Path(k).name): _round(v.tolist())} for k, v in zip(dataset.im_files, dataset.labels)], + } # Save, print and return if save: - stats_path = self.hub_dir / 'stats.json' - print(f'Saving {stats_path.resolve()}...') - with open(stats_path, 'w') as f: + stats_path = self.hub_dir / "stats.json" + print(f"Saving {stats_path.resolve()}...") + with open(stats_path, "w") as f: json.dump(self.stats, f) # save stats.json if verbose: print(json.dumps(self.stats, indent=2, sort_keys=False)) @@ -1149,14 +1202,14 @@ def _round(labels): def process_images(self): # Compress images for Ultralytics HUB - for split in 'train', 'val', 'test': + for split in "train", "val", "test": if self.data.get(split) is None: continue dataset = LoadImagesAndLabels(self.data[split]) # load dataset - desc = f'{split} images' + desc = f"{split} images" for _ in tqdm(ThreadPool(NUM_THREADS).imap(self._hub_ops, dataset.im_files), total=dataset.n, desc=desc): pass - print(f'Done. All images saved to {self.im_dir}') + print(f"Done. All images saved to {self.im_dir}") return self.im_dir @@ -1164,6 +1217,7 @@ def process_images(self): class ClassificationDataset(torchvision.datasets.ImageFolder): """ YOLOv3 Classification Dataset. + Arguments root: Dataset path transform: torchvision transforms, used by default @@ -1174,9 +1228,9 @@ def __init__(self, root, augment, imgsz, cache=False): super().__init__(root=root) self.torch_transforms = classify_transforms(imgsz) self.album_transforms = classify_albumentations(augment, imgsz) if augment else None - self.cache_ram = cache is True or cache == 'ram' - self.cache_disk = cache == 'disk' - self.samples = [list(x) + [Path(x[0]).with_suffix('.npy'), None] for x in self.samples] # file, index, npy, im + self.cache_ram = cache is True or cache == "ram" + self.cache_disk = cache == "disk" + self.samples = [list(x) + [Path(x[0]).with_suffix(".npy"), None] for x in self.samples] # file, index, npy, im def __getitem__(self, i): f, j, fn, im = self.samples[i] # filename, index, filename.with_suffix('.npy'), image @@ -1189,20 +1243,15 @@ def __getitem__(self, i): else: # read image im = cv2.imread(f) # BGR if self.album_transforms: - sample = self.album_transforms(image=cv2.cvtColor(im, cv2.COLOR_BGR2RGB))['image'] + sample = self.album_transforms(image=cv2.cvtColor(im, cv2.COLOR_BGR2RGB))["image"] else: sample = self.torch_transforms(im) return sample, j -def create_classification_dataloader(path, - imgsz=224, - batch_size=16, - augment=True, - cache=False, - rank=-1, - workers=8, - shuffle=True): +def create_classification_dataloader( + path, imgsz=224, batch_size=16, augment=True, cache=False, rank=-1, workers=8, shuffle=True +): # Returns Dataloader object to be used with YOLOv3 Classifier with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP dataset = ClassificationDataset(root=path, imgsz=imgsz, augment=augment, cache=cache) @@ -1212,11 +1261,13 @@ def create_classification_dataloader(path, sampler = None if rank == -1 else distributed.DistributedSampler(dataset, shuffle=shuffle) generator = torch.Generator() generator.manual_seed(6148914691236517205 + RANK) - return InfiniteDataLoader(dataset, - batch_size=batch_size, - shuffle=shuffle and sampler is None, - num_workers=nw, - sampler=sampler, - pin_memory=PIN_MEMORY, - worker_init_fn=seed_worker, - generator=generator) # or DataLoader(persistent_workers=True) + return InfiniteDataLoader( + dataset, + batch_size=batch_size, + shuffle=shuffle and sampler is None, + num_workers=nw, + sampler=sampler, + pin_memory=PIN_MEMORY, + worker_init_fn=seed_worker, + generator=generator, + ) # or DataLoader(persistent_workers=True) diff --git a/utils/downloads.py b/utils/downloads.py index 27a879e2c6..59e9325a7e 100644 --- a/utils/downloads.py +++ b/utils/downloads.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Download utils -""" +"""Download utils.""" import logging import subprocess @@ -23,89 +21,90 @@ def is_url(url, check=True): return False -def gsutil_getsize(url=''): +def gsutil_getsize(url=""): # gs://bucket/file size https://cloud.google.com/storage/docs/gsutil/commands/du - output = subprocess.check_output(['gsutil', 'du', url], shell=True, encoding='utf-8') + output = subprocess.check_output(["gsutil", "du", url], shell=True, encoding="utf-8") if output: return int(output.split()[0]) return 0 -def url_getsize(url='https://ultralytics.com/images/bus.jpg'): +def url_getsize(url="https://ultralytics.com/images/bus.jpg"): # Return downloadable file size in bytes response = requests.head(url, allow_redirects=True) - return int(response.headers.get('content-length', -1)) + return int(response.headers.get("content-length", -1)) def curl_download(url, filename, *, silent: bool = False) -> bool: - """ - Download a file from a url to a filename using curl. - """ - silent_option = 'sS' if silent else '' # silent - proc = subprocess.run([ - 'curl', - '-#', - f'-{silent_option}L', - url, - '--output', - filename, - '--retry', - '9', - '-C', - '-', ]) + """Download a file from a url to a filename using curl.""" + silent_option = "sS" if silent else "" # silent + proc = subprocess.run( + [ + "curl", + "-#", + f"-{silent_option}L", + url, + "--output", + filename, + "--retry", + "9", + "-C", + "-", + ] + ) return proc.returncode == 0 -def safe_download(file, url, url2=None, min_bytes=1E0, error_msg=''): +def safe_download(file, url, url2=None, min_bytes=1e0, error_msg=""): # Attempts to download file from url or url2, checks and removes incomplete downloads < min_bytes from utils.general import LOGGER file = Path(file) assert_msg = f"Downloaded file '{file}' does not exist or size is < min_bytes={min_bytes}" try: # url1 - LOGGER.info(f'Downloading {url} to {file}...') + LOGGER.info(f"Downloading {url} to {file}...") torch.hub.download_url_to_file(url, str(file), progress=LOGGER.level <= logging.INFO) assert file.exists() and file.stat().st_size > min_bytes, assert_msg # check except Exception as e: # url2 if file.exists(): file.unlink() # remove partial downloads - LOGGER.info(f'ERROR: {e}\nRe-attempting {url2 or url} to {file}...') + LOGGER.info(f"ERROR: {e}\nRe-attempting {url2 or url} to {file}...") # curl download, retry and resume on fail curl_download(url2 or url, file) finally: if not file.exists() or file.stat().st_size < min_bytes: # check if file.exists(): file.unlink() # remove partial downloads - LOGGER.info(f'ERROR: {assert_msg}\n{error_msg}') - LOGGER.info('') + LOGGER.info(f"ERROR: {assert_msg}\n{error_msg}") + LOGGER.info("") -def attempt_download(file, repo='ultralytics/yolov5', release='v7.0'): +def attempt_download(file, repo="ultralytics/yolov5", release="v7.0"): # Attempt file download from GitHub release assets if not found locally. release = 'latest', 'v7.0', etc. from utils.general import LOGGER - def github_assets(repository, version='latest'): + def github_assets(repository, version="latest"): # Return GitHub repo tag (i.e. 'v7.0') and assets (i.e. ['yolov5s.pt', 'yolov5m.pt', ...]) - if version != 'latest': - version = f'tags/{version}' # i.e. tags/v7.0 - response = requests.get(f'https://api.github.com/repos/{repository}/releases/{version}').json() # github api - return response['tag_name'], [x['name'] for x in response['assets']] # tag, assets + if version != "latest": + version = f"tags/{version}" # i.e. tags/v7.0 + response = requests.get(f"https://api.github.com/repos/{repository}/releases/{version}").json() # github api + return response["tag_name"], [x["name"] for x in response["assets"]] # tag, assets - file = Path(str(file).strip().replace("'", '')) + file = Path(str(file).strip().replace("'", "")) if not file.exists(): # URL specified name = Path(urllib.parse.unquote(str(file))).name # decode '%2F' to '/' etc. - if str(file).startswith(('http:/', 'https:/')): # download - url = str(file).replace(':/', '://') # Pathlib turns :// -> :/ - file = name.split('?')[0] # parse authentication https://url.com/file.txt?auth... + if str(file).startswith(("http:/", "https:/")): # download + url = str(file).replace(":/", "://") # Pathlib turns :// -> :/ + file = name.split("?")[0] # parse authentication https://url.com/file.txt?auth... if Path(file).is_file(): - LOGGER.info(f'Found {url} locally at {file}') # file already exists + LOGGER.info(f"Found {url} locally at {file}") # file already exists else: - safe_download(file=file, url=url, min_bytes=1E5) + safe_download(file=file, url=url, min_bytes=1e5) return file # GitHub assets - assets = [f'yolov5{size}{suffix}.pt' for size in 'nsmlx' for suffix in ('', '6', '-cls', '-seg')] # default + assets = [f"yolov5{size}{suffix}.pt" for size in "nsmlx" for suffix in ("", "6", "-cls", "-seg")] # default try: tag, assets = github_assets(repo, release) except Exception: @@ -113,15 +112,17 @@ def github_assets(repository, version='latest'): tag, assets = github_assets(repo) # latest release except Exception: try: - tag = subprocess.check_output('git tag', shell=True, stderr=subprocess.STDOUT).decode().split()[-1] + tag = subprocess.check_output("git tag", shell=True, stderr=subprocess.STDOUT).decode().split()[-1] except Exception: tag = release if name in assets: file.parent.mkdir(parents=True, exist_ok=True) # make parent dir (if required) - safe_download(file, - url=f'https://github.com/{repo}/releases/download/{tag}/{name}', - min_bytes=1E5, - error_msg=f'{file} missing, try downloading from https://github.com/{repo}/releases/{tag}') + safe_download( + file, + url=f"https://github.com/{repo}/releases/download/{tag}/{name}", + min_bytes=1e5, + error_msg=f"{file} missing, try downloading from https://github.com/{repo}/releases/{tag}", + ) return str(file) diff --git a/utils/flask_rest_api/README.md b/utils/flask_rest_api/README.md index a726acbd92..b18a3011cf 100644 --- a/utils/flask_rest_api/README.md +++ b/utils/flask_rest_api/README.md @@ -1,8 +1,6 @@ # Flask REST API -[REST](https://en.wikipedia.org/wiki/Representational_state_transfer) [API](https://en.wikipedia.org/wiki/API)s are -commonly used to expose Machine Learning (ML) models to other services. This folder contains an example REST API -created using Flask to expose the YOLOv5s model from [PyTorch Hub](https://pytorch.org/hub/ultralytics_yolov5/). +[REST](https://en.wikipedia.org/wiki/Representational_state_transfer) [API](https://en.wikipedia.org/wiki/API)s are commonly used to expose Machine Learning (ML) models to other services. This folder contains an example REST API created using Flask to expose the YOLOv5s model from [PyTorch Hub](https://pytorch.org/hub/ultralytics_yolov5/). ## Requirements @@ -69,5 +67,4 @@ The model inference results are returned as a JSON response: ] ``` -An example python script to perform inference using [requests](https://docs.python-requests.org/en/master/) is given -in `example_request.py` +An example python script to perform inference using [requests](https://docs.python-requests.org/en/master/) is given in `example_request.py` diff --git a/utils/flask_rest_api/example_request.py b/utils/flask_rest_api/example_request.py index 7dac472e88..55fca5e964 100644 --- a/utils/flask_rest_api/example_request.py +++ b/utils/flask_rest_api/example_request.py @@ -1,19 +1,17 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Perform test request -""" +"""Perform test request.""" import pprint import requests -DETECTION_URL = 'http://localhost:5000/v1/object-detection/yolov5s' -IMAGE = 'zidane.jpg' +DETECTION_URL = "http://localhost:5000/v1/object-detection/yolov5s" +IMAGE = "zidane.jpg" # Read image -with open(IMAGE, 'rb') as f: +with open(IMAGE, "rb") as f: image_data = f.read() -response = requests.post(DETECTION_URL, files={'image': image_data}).json() +response = requests.post(DETECTION_URL, files={"image": image_data}).json() pprint.pprint(response) diff --git a/utils/flask_rest_api/restapi.py b/utils/flask_rest_api/restapi.py index b04c295874..62698d848e 100644 --- a/utils/flask_rest_api/restapi.py +++ b/utils/flask_rest_api/restapi.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Run a Flask REST API exposing one or more YOLOv5s models -""" +"""Run a Flask REST API exposing one or more YOLOv5s models.""" import argparse import io @@ -13,36 +11,36 @@ app = Flask(__name__) models = {} -DETECTION_URL = '/v1/object-detection/' +DETECTION_URL = "/v1/object-detection/" -@app.route(DETECTION_URL, methods=['POST']) +@app.route(DETECTION_URL, methods=["POST"]) def predict(model): - if request.method != 'POST': + if request.method != "POST": return - if request.files.get('image'): + if request.files.get("image"): # Method 1 # with request.files["image"] as f: # im = Image.open(io.BytesIO(f.read())) # Method 2 - im_file = request.files['image'] + im_file = request.files["image"] im_bytes = im_file.read() im = Image.open(io.BytesIO(im_bytes)) if model in models: results = models[model](im, size=640) # reduce size=320 for faster inference - return results.pandas().xyxy[0].to_json(orient='records') + return results.pandas().xyxy[0].to_json(orient="records") -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Flask API exposing YOLOv3 model') - parser.add_argument('--port', default=5000, type=int, help='port number') - parser.add_argument('--model', nargs='+', default=['yolov5s'], help='model(s) to run, i.e. --model yolov5n yolov5s') +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Flask API exposing YOLOv3 model") + parser.add_argument("--port", default=5000, type=int, help="port number") + parser.add_argument("--model", nargs="+", default=["yolov5s"], help="model(s) to run, i.e. --model yolov5n yolov5s") opt = parser.parse_args() for m in opt.model: - models[m] = torch.hub.load('ultralytics/yolov5', m, force_reload=True, skip_validation=True) + models[m] = torch.hub.load("ultralytics/yolov5", m, force_reload=True, skip_validation=True) - app.run(host='0.0.0.0', port=opt.port) # debug=True causes Restarting with stat + app.run(host="0.0.0.0", port=opt.port) # debug=True causes Restarting with stat diff --git a/utils/general.py b/utils/general.py index 6b51d5b48c..ce5e3db069 100644 --- a/utils/general.py +++ b/utils/general.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -General utils -""" +"""General utils.""" import contextlib import glob @@ -43,67 +41,67 @@ FILE = Path(__file__).resolve() ROOT = FILE.parents[1] # YOLOv3 root directory -RANK = int(os.getenv('RANK', -1)) +RANK = int(os.getenv("RANK", -1)) # Settings NUM_THREADS = min(8, max(1, os.cpu_count() - 1)) # number of YOLOv3 multiprocessing threads -DATASETS_DIR = Path(os.getenv('YOLOv5_DATASETS_DIR', ROOT.parent / 'datasets')) # global datasets directory -AUTOINSTALL = str(os.getenv('YOLOv5_AUTOINSTALL', True)).lower() == 'true' # global auto-install mode -VERBOSE = str(os.getenv('YOLOv5_VERBOSE', True)).lower() == 'true' # global verbose mode -TQDM_BAR_FORMAT = '{l_bar}{bar:10}{r_bar}' # tqdm bar format -FONT = 'Arial.ttf' # https://ultralytics.com/assets/Arial.ttf - -torch.set_printoptions(linewidth=320, precision=5, profile='long') -np.set_printoptions(linewidth=320, formatter={'float_kind': '{:11.5g}'.format}) # format short g, %precision=5 +DATASETS_DIR = Path(os.getenv("YOLOv5_DATASETS_DIR", ROOT.parent / "datasets")) # global datasets directory +AUTOINSTALL = str(os.getenv("YOLOv5_AUTOINSTALL", True)).lower() == "true" # global auto-install mode +VERBOSE = str(os.getenv("YOLOv5_VERBOSE", True)).lower() == "true" # global verbose mode +TQDM_BAR_FORMAT = "{l_bar}{bar:10}{r_bar}" # tqdm bar format +FONT = "Arial.ttf" # https://ultralytics.com/assets/Arial.ttf + +torch.set_printoptions(linewidth=320, precision=5, profile="long") +np.set_printoptions(linewidth=320, formatter={"float_kind": "{:11.5g}".format}) # format short g, %precision=5 pd.options.display.max_columns = 10 cv2.setNumThreads(0) # prevent OpenCV from multithreading (incompatible with PyTorch DataLoader) -os.environ['NUMEXPR_MAX_THREADS'] = str(NUM_THREADS) # NumExpr max threads -os.environ['OMP_NUM_THREADS'] = '1' if platform.system() == 'darwin' else str(NUM_THREADS) # OpenMP (PyTorch and SciPy) -os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # suppress verbose TF compiler warnings in Colab +os.environ["NUMEXPR_MAX_THREADS"] = str(NUM_THREADS) # NumExpr max threads +os.environ["OMP_NUM_THREADS"] = "1" if platform.system() == "darwin" else str(NUM_THREADS) # OpenMP (PyTorch and SciPy) +os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" # suppress verbose TF compiler warnings in Colab -def is_ascii(s=''): +def is_ascii(s=""): # Is string composed of all ASCII (no UTF) characters? (note str().isascii() introduced in python 3.7) s = str(s) # convert list, tuple, None, etc. to str - return len(s.encode().decode('ascii', 'ignore')) == len(s) + return len(s.encode().decode("ascii", "ignore")) == len(s) -def is_chinese(s='人工智能'): +def is_chinese(s="人工智能"): # Is string composed of any Chinese characters? - return bool(re.search('[\u4e00-\u9fff]', str(s))) + return bool(re.search("[\u4e00-\u9fff]", str(s))) def is_colab(): # Is environment a Google Colab instance? - return 'google.colab' in sys.modules + return "google.colab" in sys.modules def is_jupyter(): """ - Check if the current script is running inside a Jupyter Notebook. - Verified on Colab, Jupyterlab, Kaggle, Paperspace. + Check if the current script is running inside a Jupyter Notebook. Verified on Colab, Jupyterlab, Kaggle, Paperspace. Returns: bool: True if running inside a Jupyter Notebook, False otherwise. """ with contextlib.suppress(Exception): from IPython import get_ipython + return get_ipython() is not None return False def is_kaggle(): # Is environment a Kaggle Notebook? - return os.environ.get('PWD') == '/kaggle/working' and os.environ.get('KAGGLE_URL_BASE') == 'https://www.kaggle.com' + return os.environ.get("PWD") == "/kaggle/working" and os.environ.get("KAGGLE_URL_BASE") == "https://www.kaggle.com" def is_docker() -> bool: """Check if the process runs inside a docker container.""" - if Path('/.dockerenv').exists(): + if Path("/.dockerenv").exists(): return True try: # check if docker is in control groups - with open('/proc/self/cgroup') as file: - return any('docker' in line for line in file) + with open("/proc/self/cgroup") as file: + return any("docker" in line for line in file) except OSError: return False @@ -112,9 +110,9 @@ def is_writeable(dir, test=False): # Return True if directory has write permissions, test opening a file with write permissions if test=True if not test: return os.access(dir, os.W_OK) # possible issues on Windows - file = Path(dir) / 'tmp.txt' + file = Path(dir) / "tmp.txt" try: - with open(file, 'w'): # open file with write permissions + with open(file, "w"): # open file with write permissions pass file.unlink() # remove file return True @@ -122,47 +120,52 @@ def is_writeable(dir, test=False): return False -LOGGING_NAME = 'yolov5' +LOGGING_NAME = "yolov5" def set_logging(name=LOGGING_NAME, verbose=True): # sets up logging for the given name - rank = int(os.getenv('RANK', -1)) # rank in world for Multi-GPU trainings + rank = int(os.getenv("RANK", -1)) # rank in world for Multi-GPU trainings level = logging.INFO if verbose and rank in {-1, 0} else logging.ERROR - logging.config.dictConfig({ - 'version': 1, - 'disable_existing_loggers': False, - 'formatters': { - name: { - 'format': '%(message)s'}}, - 'handlers': { - name: { - 'class': 'logging.StreamHandler', - 'formatter': name, - 'level': level, }}, - 'loggers': { - name: { - 'level': level, - 'handlers': [name], - 'propagate': False, }}}) + logging.config.dictConfig( + { + "version": 1, + "disable_existing_loggers": False, + "formatters": {name: {"format": "%(message)s"}}, + "handlers": { + name: { + "class": "logging.StreamHandler", + "formatter": name, + "level": level, + } + }, + "loggers": { + name: { + "level": level, + "handlers": [name], + "propagate": False, + } + }, + } + ) set_logging(LOGGING_NAME) # run before defining LOGGER LOGGER = logging.getLogger(LOGGING_NAME) # define globally (used in train.py, val.py, detect.py, etc.) -if platform.system() == 'Windows': +if platform.system() == "Windows": for fn in LOGGER.info, LOGGER.warning: setattr(LOGGER, fn.__name__, lambda x: fn(emojis(x))) # emoji safe logging -def user_config_dir(dir='Ultralytics', env_var='YOLOV5_CONFIG_DIR'): +def user_config_dir(dir="Ultralytics", env_var="YOLOV5_CONFIG_DIR"): # Return path of user configuration directory. Prefer environment variable if exists. Make dir if required. env = os.getenv(env_var) if env: path = Path(env) # use environment variable else: - cfg = {'Windows': 'AppData/Roaming', 'Linux': '.config', 'Darwin': 'Library/Application Support'} # 3 OS dirs - path = Path.home() / cfg.get(platform.system(), '') # OS-specific config dir - path = (path if is_writeable(path) else Path('/tmp')) / dir # GCP and AWS lambda fix, only /tmp is writeable + cfg = {"Windows": "AppData/Roaming", "Linux": ".config", "Darwin": "Library/Application Support"} # 3 OS dirs + path = Path.home() / cfg.get(platform.system(), "") # OS-specific config dir + path = (path if is_writeable(path) else Path("/tmp")) / dir # GCP and AWS lambda fix, only /tmp is writeable path.mkdir(exist_ok=True) # make if required return path @@ -192,7 +195,7 @@ def time(self): class Timeout(contextlib.ContextDecorator): # YOLOv3 Timeout class. Usage: @Timeout(seconds) decorator or 'with Timeout(seconds):' context manager - def __init__(self, seconds, *, timeout_msg='', suppress_timeout_errors=True): + def __init__(self, seconds, *, timeout_msg="", suppress_timeout_errors=True): self.seconds = int(seconds) self.timeout_message = timeout_msg self.suppress = bool(suppress_timeout_errors) @@ -201,12 +204,12 @@ def _timeout_handler(self, signum, frame): raise TimeoutError(self.timeout_message) def __enter__(self): - if platform.system() != 'Windows': # not supported on Windows + if platform.system() != "Windows": # not supported on Windows signal.signal(signal.SIGALRM, self._timeout_handler) # Set handler for SIGALRM signal.alarm(self.seconds) # start countdown for SIGALRM to be raised def __exit__(self, exc_type, exc_val, exc_tb): - if platform.system() != 'Windows': + if platform.system() != "Windows": signal.alarm(0) # Cancel SIGALRM if it's scheduled if self.suppress and exc_type is TimeoutError: # Suppress TimeoutError return True @@ -227,7 +230,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): def methods(instance): # Get class/instance methods - return [f for f in dir(instance) if callable(getattr(instance, f)) and not f.startswith('__')] + return [f for f in dir(instance) if callable(getattr(instance, f)) and not f.startswith("__")] def print_args(args: Optional[dict] = None, show_file=True, show_func=False): @@ -238,11 +241,11 @@ def print_args(args: Optional[dict] = None, show_file=True, show_func=False): args, _, _, frm = inspect.getargvalues(x) args = {k: v for k, v in frm.items() if k in args} try: - file = Path(file).resolve().relative_to(ROOT).with_suffix('') + file = Path(file).resolve().relative_to(ROOT).with_suffix("") except ValueError: file = Path(file).stem - s = (f'{file}: ' if show_file else '') + (f'{func}: ' if show_func else '') - LOGGER.info(colorstr(s) + ', '.join(f'{k}={v}' for k, v in args.items())) + s = (f"{file}: " if show_file else "") + (f"{func}: " if show_func else "") + LOGGER.info(colorstr(s) + ", ".join(f"{k}={v}" for k, v in args.items())) def init_seeds(seed=0, deterministic=False): @@ -253,11 +256,11 @@ def init_seeds(seed=0, deterministic=False): torch.cuda.manual_seed(seed) torch.cuda.manual_seed_all(seed) # for Multi-GPU, exception safe # torch.backends.cudnn.benchmark = True # AutoBatch problem https://github.com/ultralytics/yolov5/issues/9287 - if deterministic and check_version(torch.__version__, '1.12.0'): # https://github.com/ultralytics/yolov5/pull/8213 + if deterministic and check_version(torch.__version__, "1.12.0"): # https://github.com/ultralytics/yolov5/pull/8213 torch.use_deterministic_algorithms(True) torch.backends.cudnn.deterministic = True - os.environ['CUBLAS_WORKSPACE_CONFIG'] = ':4096:8' - os.environ['PYTHONHASHSEED'] = str(seed) + os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8" + os.environ["PYTHONHASHSEED"] = str(seed) def intersect_dicts(da, db, exclude=()): @@ -271,22 +274,22 @@ def get_default_args(func): return {k: v.default for k, v in signature.parameters.items() if v.default is not inspect.Parameter.empty} -def get_latest_run(search_dir='.'): +def get_latest_run(search_dir="."): # Return path to most recent 'last.pt' in /runs (i.e. to --resume from) - last_list = glob.glob(f'{search_dir}/**/last*.pt', recursive=True) - return max(last_list, key=os.path.getctime) if last_list else '' + last_list = glob.glob(f"{search_dir}/**/last*.pt", recursive=True) + return max(last_list, key=os.path.getctime) if last_list else "" def file_age(path=__file__): # Return days since last file update - dt = (datetime.now() - datetime.fromtimestamp(Path(path).stat().st_mtime)) # delta + dt = datetime.now() - datetime.fromtimestamp(Path(path).stat().st_mtime) # delta return dt.days # + dt.seconds / 86400 # fractional days def file_date(path=__file__): # Return human-readable file modification date, i.e. '2021-3-26' t = datetime.fromtimestamp(Path(path).stat().st_mtime) - return f'{t.year}-{t.month}-{t.day}' + return f"{t.year}-{t.month}-{t.day}" def file_size(path): @@ -296,7 +299,7 @@ def file_size(path): if path.is_file(): return path.stat().st_size / mb elif path.is_dir(): - return sum(f.stat().st_size for f in path.glob('**/*') if f.is_file()) / mb + return sum(f.stat().st_size for f in path.glob("**/*") if f.is_file()) / mb else: return 0.0 @@ -308,7 +311,7 @@ def check_online(): def run_once(): # Check once try: - socket.create_connection(('1.1.1.1', 443), 5) # check host accessibility + socket.create_connection(("1.1.1.1", 443), 5) # check host accessibility return True except OSError: return False @@ -319,68 +322,69 @@ def run_once(): def git_describe(path=ROOT): # path must be a directory # Return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe try: - assert (Path(path) / '.git').is_dir() - return check_output(f'git -C {path} describe --tags --long --always', shell=True).decode()[:-1] + assert (Path(path) / ".git").is_dir() + return check_output(f"git -C {path} describe --tags --long --always", shell=True).decode()[:-1] except Exception: - return '' + return "" @TryExcept() @WorkingDirectory(ROOT) -def check_git_status(repo='ultralytics/yolov5', branch='master'): +def check_git_status(repo="ultralytics/yolov5", branch="master"): # YOLOv3 status check, recommend 'git pull' if code is out of date - url = f'https://github.com/{repo}' - msg = f', for updates see {url}' - s = colorstr('github: ') # string - assert Path('.git').exists(), s + 'skipping check (not a git repository)' + msg - assert check_online(), s + 'skipping check (offline)' + msg + url = f"https://github.com/{repo}" + msg = f", for updates see {url}" + s = colorstr("github: ") # string + assert Path(".git").exists(), s + "skipping check (not a git repository)" + msg + assert check_online(), s + "skipping check (offline)" + msg - splits = re.split(pattern=r'\s', string=check_output('git remote -v', shell=True).decode()) + splits = re.split(pattern=r"\s", string=check_output("git remote -v", shell=True).decode()) matches = [repo in s for s in splits] if any(matches): remote = splits[matches.index(True) - 1] else: - remote = 'ultralytics' - check_output(f'git remote add {remote} {url}', shell=True) - check_output(f'git fetch {remote}', shell=True, timeout=5) # git fetch - local_branch = check_output('git rev-parse --abbrev-ref HEAD', shell=True).decode().strip() # checked out - n = int(check_output(f'git rev-list {local_branch}..{remote}/{branch} --count', shell=True)) # commits behind + remote = "ultralytics" + check_output(f"git remote add {remote} {url}", shell=True) + check_output(f"git fetch {remote}", shell=True, timeout=5) # git fetch + local_branch = check_output("git rev-parse --abbrev-ref HEAD", shell=True).decode().strip() # checked out + n = int(check_output(f"git rev-list {local_branch}..{remote}/{branch} --count", shell=True)) # commits behind if n > 0: - pull = 'git pull' if remote == 'origin' else f'git pull {remote} {branch}' + pull = "git pull" if remote == "origin" else f"git pull {remote} {branch}" s += f"⚠️ YOLOv3 is out of date by {n} commit{'s' * (n > 1)}. Use '{pull}' or 'git clone {url}' to update." else: - s += f'up to date with {url} ✅' + s += f"up to date with {url} ✅" LOGGER.info(s) @WorkingDirectory(ROOT) -def check_git_info(path='.'): +def check_git_info(path="."): # YOLOv3 git info check, return {remote, branch, commit} - check_requirements('gitpython') + check_requirements("gitpython") import git + try: repo = git.Repo(path) - remote = repo.remotes.origin.url.replace('.git', '') # i.e. 'https://github.com/ultralytics/yolov5' + remote = repo.remotes.origin.url.replace(".git", "") # i.e. 'https://github.com/ultralytics/yolov5' commit = repo.head.commit.hexsha # i.e. '3134699c73af83aac2a481435550b968d5792c0d' try: branch = repo.active_branch.name # i.e. 'main' except TypeError: # not on any branch branch = None # i.e. 'detached HEAD' state - return {'remote': remote, 'branch': branch, 'commit': commit} + return {"remote": remote, "branch": branch, "commit": commit} except git.exc.InvalidGitRepositoryError: # path is not a git dir - return {'remote': None, 'branch': None, 'commit': None} + return {"remote": None, "branch": None, "commit": None} -def check_python(minimum='3.7.0'): +def check_python(minimum="3.7.0"): # Check current python version vs. required python version - check_version(platform.python_version(), minimum, name='Python ', hard=True) + check_version(platform.python_version(), minimum, name="Python ", hard=True) -def check_version(current='0.0.0', minimum='0.0.0', name='version ', pinned=False, hard=False, verbose=False): +def check_version(current="0.0.0", minimum="0.0.0", name="version ", pinned=False, hard=False, verbose=False): # Check version vs. required version current, minimum = (pkg.parse_version(x) for x in (current, minimum)) result = (current == minimum) if pinned else (current >= minimum) # bool - s = f'WARNING ⚠️ {name}{minimum} is required by YOLOv3, but {name}{current} is currently installed' # string + s = f"WARNING ⚠️ {name}{minimum} is required by YOLOv3, but {name}{current} is currently installed" # string if hard: assert result, emojis(s) # assert min requirements met if verbose and not result: @@ -396,7 +400,7 @@ def check_img_size(imgsz, s=32, floor=0): imgsz = list(imgsz) # convert to list if tuple new_size = [max(make_divisible(x, int(s)), floor) for x in imgsz] if new_size != imgsz: - LOGGER.warning(f'WARNING ⚠️ --img-size {imgsz} must be multiple of max stride {s}, updating to {new_size}') + LOGGER.warning(f"WARNING ⚠️ --img-size {imgsz} must be multiple of max stride {s}, updating to {new_size}") return new_size @@ -405,18 +409,18 @@ def check_imshow(warn=False): try: assert not is_jupyter() assert not is_docker() - cv2.imshow('test', np.zeros((1, 1, 3))) + cv2.imshow("test", np.zeros((1, 1, 3))) cv2.waitKey(1) cv2.destroyAllWindows() cv2.waitKey(1) return True except Exception as e: if warn: - LOGGER.warning(f'WARNING ⚠️ Environment does not support cv2.imshow() or PIL Image.show()\n{e}') + LOGGER.warning(f"WARNING ⚠️ Environment does not support cv2.imshow() or PIL Image.show()\n{e}") return False -def check_suffix(file='yolov5s.pt', suffix=('.pt', ), msg=''): +def check_suffix(file="yolov5s.pt", suffix=(".pt",), msg=""): # Check file(s) for acceptable suffix if file and suffix: if isinstance(suffix, str): @@ -424,38 +428,40 @@ def check_suffix(file='yolov5s.pt', suffix=('.pt', ), msg=''): for f in file if isinstance(file, (list, tuple)) else [file]: s = Path(f).suffix.lower() # file suffix if len(s): - assert s in suffix, f'{msg}{f} acceptable suffix is {suffix}' + assert s in suffix, f"{msg}{f} acceptable suffix is {suffix}" -def check_yaml(file, suffix=('.yaml', '.yml')): +def check_yaml(file, suffix=(".yaml", ".yml")): # Search/download YAML file (if necessary) and return path, checking suffix return check_file(file, suffix) -def check_file(file, suffix=''): +def check_file(file, suffix=""): # Search/download file (if necessary) and return path check_suffix(file, suffix) # optional file = str(file) # convert to str() if os.path.isfile(file) or not file: # exists return file - elif file.startswith(('http:/', 'https:/')): # download + elif file.startswith(("http:/", "https:/")): # download url = file # warning: Pathlib turns :// -> :/ - file = Path(urllib.parse.unquote(file).split('?')[0]).name # '%2F' to '/', split https://url.com/file.txt?auth + file = Path(urllib.parse.unquote(file).split("?")[0]).name # '%2F' to '/', split https://url.com/file.txt?auth if os.path.isfile(file): - LOGGER.info(f'Found {url} locally at {file}') # file already exists + LOGGER.info(f"Found {url} locally at {file}") # file already exists else: - LOGGER.info(f'Downloading {url} to {file}...') + LOGGER.info(f"Downloading {url} to {file}...") torch.hub.download_url_to_file(url, file) - assert Path(file).exists() and Path(file).stat().st_size > 0, f'File download failed: {url}' # check + assert Path(file).exists() and Path(file).stat().st_size > 0, f"File download failed: {url}" # check return file - elif file.startswith('clearml://'): # ClearML Dataset ID - assert 'clearml' in sys.modules, "ClearML is not installed, so cannot use ClearML dataset. Try running 'pip install clearml'." + elif file.startswith("clearml://"): # ClearML Dataset ID + assert ( + "clearml" in sys.modules + ), "ClearML is not installed, so cannot use ClearML dataset. Try running 'pip install clearml'." return file else: # search files = [] - for d in 'data', 'models', 'utils': # search directories - files.extend(glob.glob(str(ROOT / d / '**' / file), recursive=True)) # find file - assert len(files), f'File not found: {file}' # assert file was found + for d in "data", "models", "utils": # search directories + files.extend(glob.glob(str(ROOT / d / "**" / file), recursive=True)) # find file + assert len(files), f"File not found: {file}" # assert file was found assert len(files) == 1, f"Multiple files match '{file}', specify exact path: {files}" # assert unique return files[0] # return file @@ -465,8 +471,8 @@ def check_font(font=FONT, progress=False): font = Path(font) file = CONFIG_DIR / font.name if not font.exists() and not file.exists(): - url = f'https://ultralytics.com/assets/{font.name}' - LOGGER.info(f'Downloading {url} to {file}...') + url = f"https://ultralytics.com/assets/{font.name}" + LOGGER.info(f"Downloading {url} to {file}...") torch.hub.download_url_to_file(url, str(file), progress=progress) @@ -474,10 +480,10 @@ def check_dataset(data, autodownload=True): # Download, check and/or unzip dataset if not found locally # Download (optional) - extract_dir = '' + extract_dir = "" if isinstance(data, (str, Path)) and (is_zipfile(data) or is_tarfile(data)): - download(data, dir=f'{DATASETS_DIR}/{Path(data).stem}', unzip=True, delete=False, curl=False, threads=1) - data = next((DATASETS_DIR / Path(data).stem).rglob('*.yaml')) + download(data, dir=f"{DATASETS_DIR}/{Path(data).stem}", unzip=True, delete=False, curl=False, threads=1) + data = next((DATASETS_DIR / Path(data).stem).rglob("*.yaml")) extract_dir, autodownload = data.parent, False # Read yaml (optional) @@ -485,54 +491,54 @@ def check_dataset(data, autodownload=True): data = yaml_load(data) # dictionary # Checks - for k in 'train', 'val', 'names': + for k in "train", "val", "names": assert k in data, emojis(f"data.yaml '{k}:' field missing ❌") - if isinstance(data['names'], (list, tuple)): # old array format - data['names'] = dict(enumerate(data['names'])) # convert to dict - assert all(isinstance(k, int) for k in data['names'].keys()), 'data.yaml names keys must be integers, i.e. 2: car' - data['nc'] = len(data['names']) + if isinstance(data["names"], (list, tuple)): # old array format + data["names"] = dict(enumerate(data["names"])) # convert to dict + assert all(isinstance(k, int) for k in data["names"].keys()), "data.yaml names keys must be integers, i.e. 2: car" + data["nc"] = len(data["names"]) # Resolve paths - path = Path(extract_dir or data.get('path') or '') # optional 'path' default to '.' + path = Path(extract_dir or data.get("path") or "") # optional 'path' default to '.' if not path.is_absolute(): path = (ROOT / path).resolve() - data['path'] = path # download scripts - for k in 'train', 'val', 'test': + data["path"] = path # download scripts + for k in "train", "val", "test": if data.get(k): # prepend path if isinstance(data[k], str): x = (path / data[k]).resolve() - if not x.exists() and data[k].startswith('../'): + if not x.exists() and data[k].startswith("../"): x = (path / data[k][3:]).resolve() data[k] = str(x) else: data[k] = [str((path / x).resolve()) for x in data[k]] # Parse yaml - train, val, test, s = (data.get(x) for x in ('train', 'val', 'test', 'download')) + train, val, test, s = (data.get(x) for x in ("train", "val", "test", "download")) if val: val = [Path(x).resolve() for x in (val if isinstance(val, list) else [val])] # val path if not all(x.exists() for x in val): - LOGGER.info('\nDataset not found ⚠️, missing paths %s' % [str(x) for x in val if not x.exists()]) + LOGGER.info("\nDataset not found ⚠️, missing paths %s" % [str(x) for x in val if not x.exists()]) if not s or not autodownload: - raise Exception('Dataset not found ❌') + raise Exception("Dataset not found ❌") t = time.time() - if s.startswith('http') and s.endswith('.zip'): # URL + if s.startswith("http") and s.endswith(".zip"): # URL f = Path(s).name # filename - LOGGER.info(f'Downloading {s} to {f}...') + LOGGER.info(f"Downloading {s} to {f}...") torch.hub.download_url_to_file(s, f) Path(DATASETS_DIR).mkdir(parents=True, exist_ok=True) # create root unzip_file(f, path=DATASETS_DIR) # unzip Path(f).unlink() # remove zip r = None # success - elif s.startswith('bash '): # bash script - LOGGER.info(f'Running {s} ...') + elif s.startswith("bash "): # bash script + LOGGER.info(f"Running {s} ...") r = subprocess.run(s, shell=True) else: # python script - r = exec(s, {'yaml': data}) # return None - dt = f'({round(time.time() - t, 1)}s)' - s = f"success ✅ {dt}, saved to {colorstr('bold', DATASETS_DIR)}" if r in (0, None) else f'failure {dt} ❌' - LOGGER.info(f'Dataset download {s}') - check_font('Arial.ttf' if is_ascii(data['names']) else 'Arial.Unicode.ttf', progress=True) # download fonts + r = exec(s, {"yaml": data}) # return None + dt = f"({round(time.time() - t, 1)}s)" + s = f"success ✅ {dt}, saved to {colorstr('bold', DATASETS_DIR)}" if r in (0, None) else f"failure {dt} ❌" + LOGGER.info(f"Dataset download {s}") + check_font("Arial.ttf" if is_ascii(data["names"]) else "Arial.Unicode.ttf", progress=True) # download fonts return data # dictionary @@ -548,35 +554,35 @@ def amp_allclose(model, im): b = m(im).xywhn[0] # AMP inference return a.shape == b.shape and torch.allclose(a, b, atol=0.1) # close to 10% absolute tolerance - prefix = colorstr('AMP: ') + prefix = colorstr("AMP: ") device = next(model.parameters()).device # get model device - if device.type in ('cpu', 'mps'): + if device.type in ("cpu", "mps"): return False # AMP only used on CUDA devices - f = ROOT / 'data' / 'images' / 'bus.jpg' # image to check - im = f if f.exists() else 'https://ultralytics.com/images/bus.jpg' if check_online() else np.ones((640, 640, 3)) + f = ROOT / "data" / "images" / "bus.jpg" # image to check + im = f if f.exists() else "https://ultralytics.com/images/bus.jpg" if check_online() else np.ones((640, 640, 3)) try: - assert amp_allclose(deepcopy(model), im) or amp_allclose(DetectMultiBackend('yolov5n.pt', device), im) - LOGGER.info(f'{prefix}checks passed ✅') + assert amp_allclose(deepcopy(model), im) or amp_allclose(DetectMultiBackend("yolov5n.pt", device), im) + LOGGER.info(f"{prefix}checks passed ✅") return True except Exception: - help_url = 'https://github.com/ultralytics/yolov5/issues/7908' - LOGGER.warning(f'{prefix}checks failed ❌, disabling Automatic Mixed Precision. See {help_url}') + help_url = "https://github.com/ultralytics/yolov5/issues/7908" + LOGGER.warning(f"{prefix}checks failed ❌, disabling Automatic Mixed Precision. See {help_url}") return False -def yaml_load(file='data.yaml'): +def yaml_load(file="data.yaml"): # Single-line safe yaml loading - with open(file, errors='ignore') as f: + with open(file, errors="ignore") as f: return yaml.safe_load(f) -def yaml_save(file='data.yaml', data={}): +def yaml_save(file="data.yaml", data={}): # Single-line safe yaml saving - with open(file, 'w') as f: + with open(file, "w") as f: yaml.safe_dump({k: str(v) if isinstance(v, Path) else v for k, v in data.items()}, f, sort_keys=False) -def unzip_file(file, path=None, exclude=('.DS_Store', '__MACOSX')): +def unzip_file(file, path=None, exclude=(".DS_Store", "__MACOSX")): # Unzip a *.zip file to path/, excluding files containing strings in exclude list if path is None: path = Path(file).parent # default path @@ -588,11 +594,11 @@ def unzip_file(file, path=None, exclude=('.DS_Store', '__MACOSX')): def url2file(url): # Convert URL to filename, i.e. https://url.com/file.txt?auth -> file.txt - url = str(Path(url)).replace(':/', '://') # Pathlib turns :// -> :/ - return Path(urllib.parse.unquote(url)).name.split('?')[0] # '%2F' to '/', split https://url.com/file.txt?auth + url = str(Path(url)).replace(":/", "://") # Pathlib turns :// -> :/ + return Path(urllib.parse.unquote(url)).name.split("?")[0] # '%2F' to '/', split https://url.com/file.txt?auth -def download(url, dir='.', unzip=True, delete=True, curl=False, threads=1, retry=3): +def download(url, dir=".", unzip=True, delete=True, curl=False, threads=1, retry=3): # Multithreaded file download and unzip function, used in data.yaml for autodownload def download_one(url, dir): # Download 1 file @@ -601,7 +607,7 @@ def download_one(url, dir): f = Path(url) # filename else: # does not exist f = dir / Path(url).name - LOGGER.info(f'Downloading {url} to {f}...') + LOGGER.info(f"Downloading {url} to {f}...") for i in range(retry + 1): if curl: success = curl_download(url, f, silent=(threads > 1)) @@ -611,18 +617,18 @@ def download_one(url, dir): if success: break elif i < retry: - LOGGER.warning(f'⚠️ Download failure, retrying {i + 1}/{retry} {url}...') + LOGGER.warning(f"⚠️ Download failure, retrying {i + 1}/{retry} {url}...") else: - LOGGER.warning(f'❌ Failed to download {url}...') + LOGGER.warning(f"❌ Failed to download {url}...") - if unzip and success and (f.suffix == '.gz' or is_zipfile(f) or is_tarfile(f)): - LOGGER.info(f'Unzipping {f}...') + if unzip and success and (f.suffix == ".gz" or is_zipfile(f) or is_tarfile(f)): + LOGGER.info(f"Unzipping {f}...") if is_zipfile(f): unzip_file(f, dir) # unzip elif is_tarfile(f): - subprocess.run(['tar', 'xf', f, '--directory', f.parent], check=True) # unzip - elif f.suffix == '.gz': - subprocess.run(['tar', 'xfz', f, '--directory', f.parent], check=True) # unzip + subprocess.run(["tar", "xf", f, "--directory", f.parent], check=True) # unzip + elif f.suffix == ".gz": + subprocess.run(["tar", "xfz", f, "--directory", f.parent], check=True) # unzip if delete: f.unlink() # remove zip @@ -647,7 +653,7 @@ def make_divisible(x, divisor): def clean_str(s): # Cleans a string by replacing special characters with underscore _ - return re.sub(pattern='[|@#!¡·$€%&()=?¿^*;:,¨´><+]', repl='_', string=s) + return re.sub(pattern="[|@#!¡·$€%&()=?¿^*;:,¨´><+]", repl="_", string=s) def one_cycle(y1=0.0, y2=1.0, steps=100): @@ -657,28 +663,29 @@ def one_cycle(y1=0.0, y2=1.0, steps=100): def colorstr(*input): # Colors a string https://en.wikipedia.org/wiki/ANSI_escape_code, i.e. colorstr('blue', 'hello world') - *args, string = input if len(input) > 1 else ('blue', 'bold', input[0]) # color arguments, string + *args, string = input if len(input) > 1 else ("blue", "bold", input[0]) # color arguments, string colors = { - 'black': '\033[30m', # basic colors - 'red': '\033[31m', - 'green': '\033[32m', - 'yellow': '\033[33m', - 'blue': '\033[34m', - 'magenta': '\033[35m', - 'cyan': '\033[36m', - 'white': '\033[37m', - 'bright_black': '\033[90m', # bright colors - 'bright_red': '\033[91m', - 'bright_green': '\033[92m', - 'bright_yellow': '\033[93m', - 'bright_blue': '\033[94m', - 'bright_magenta': '\033[95m', - 'bright_cyan': '\033[96m', - 'bright_white': '\033[97m', - 'end': '\033[0m', # misc - 'bold': '\033[1m', - 'underline': '\033[4m'} - return ''.join(colors[x] for x in args) + f'{string}' + colors['end'] + "black": "\033[30m", # basic colors + "red": "\033[31m", + "green": "\033[32m", + "yellow": "\033[33m", + "blue": "\033[34m", + "magenta": "\033[35m", + "cyan": "\033[36m", + "white": "\033[37m", + "bright_black": "\033[90m", # bright colors + "bright_red": "\033[91m", + "bright_green": "\033[92m", + "bright_yellow": "\033[93m", + "bright_blue": "\033[94m", + "bright_magenta": "\033[95m", + "bright_cyan": "\033[96m", + "bright_white": "\033[97m", + "end": "\033[0m", # misc + "bold": "\033[1m", + "underline": "\033[4m", + } + return "".join(colors[x] for x in args) + f"{string}" + colors["end"] def labels_to_class_weights(labels, nc=80): @@ -714,9 +721,87 @@ def coco80_to_coco91_class(): # converts 80-index (val2014) to 91-index (paper) # x1 = [list(a[i] == b).index(True) + 1 for i in range(80)] # darknet to coco # x2 = [list(b[i] == a).index(True) if any(b[i] == a) else None for i in range(91)] # coco to darknet return [ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 67, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 27, + 28, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 67, + 70, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + ] def xyxy2xywh(x): @@ -773,7 +858,10 @@ def segment2box(segment, width=640, height=640): # Convert 1 segment label to 1 box label, applying inside-image constraint, i.e. (xy1, xy2, ...) to (xyxy) x, y = segment.T # segment xy inside = (x >= 0) & (y >= 0) & (x <= width) & (y <= height) - x, y, = x[inside], y[inside] + ( + x, + y, + ) = x[inside], y[inside] return np.array([x.min(), y.min(), x.max(), y.max()]) if any(x) else np.zeros((1, 4)) # xyxy @@ -854,30 +942,31 @@ def clip_segments(segments, shape): def non_max_suppression( - prediction, - conf_thres=0.25, - iou_thres=0.45, - classes=None, - agnostic=False, - multi_label=False, - labels=(), - max_det=300, - nm=0, # number of masks + prediction, + conf_thres=0.25, + iou_thres=0.45, + classes=None, + agnostic=False, + multi_label=False, + labels=(), + max_det=300, + nm=0, # number of masks ): - """Non-Maximum Suppression (NMS) on inference results to reject overlapping detections + """ + Non-Maximum Suppression (NMS) on inference results to reject overlapping detections. Returns: list of detections, on (n,6) tensor per image [xyxy, conf, cls] """ # Checks - assert 0 <= conf_thres <= 1, f'Invalid Confidence threshold {conf_thres}, valid values are between 0.0 and 1.0' - assert 0 <= iou_thres <= 1, f'Invalid IoU {iou_thres}, valid values are between 0.0 and 1.0' + assert 0 <= conf_thres <= 1, f"Invalid Confidence threshold {conf_thres}, valid values are between 0.0 and 1.0" + assert 0 <= iou_thres <= 1, f"Invalid IoU {iou_thres}, valid values are between 0.0 and 1.0" if isinstance(prediction, (list, tuple)): # YOLOv3 model in validation model, output = (inference_out, loss_out) prediction = prediction[0] # select only inference output device = prediction.device - mps = 'mps' in device.type # Apple MPS + mps = "mps" in device.type # Apple MPS if mps: # MPS not fully supported yet, convert tensors to CPU before NMS prediction = prediction.cpu() bs = prediction.shape[0] # batch size @@ -948,7 +1037,7 @@ def non_max_suppression( boxes, scores = x[:, :4] + c, x[:, 4] # boxes (offset by class), scores i = torchvision.ops.nms(boxes, scores, iou_thres) # NMS i = i[:max_det] # limit detections - if merge and (1 < n < 3E3): # Merge NMS (boxes merged using weighted mean) + if merge and (1 < n < 3e3): # Merge NMS (boxes merged using weighted mean) # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) iou = box_iou(boxes[i], boxes) > iou_thres # iou matrix weights = iou * scores[None] # box weights @@ -960,31 +1049,31 @@ def non_max_suppression( if mps: output[xi] = output[xi].to(device) if (time.time() - t) > time_limit: - LOGGER.warning(f'WARNING ⚠️ NMS time limit {time_limit:.3f}s exceeded') + LOGGER.warning(f"WARNING ⚠️ NMS time limit {time_limit:.3f}s exceeded") break # time limit exceeded return output -def strip_optimizer(f='best.pt', s=''): # from utils.general import *; strip_optimizer() +def strip_optimizer(f="best.pt", s=""): # from utils.general import *; strip_optimizer() # Strip optimizer from 'f' to finalize training, optionally save as 's' - x = torch.load(f, map_location=torch.device('cpu')) - if x.get('ema'): - x['model'] = x['ema'] # replace model with ema - for k in 'optimizer', 'best_fitness', 'ema', 'updates': # keys + x = torch.load(f, map_location=torch.device("cpu")) + if x.get("ema"): + x["model"] = x["ema"] # replace model with ema + for k in "optimizer", "best_fitness", "ema", "updates": # keys x[k] = None - x['epoch'] = -1 - x['model'].half() # to FP16 - for p in x['model'].parameters(): + x["epoch"] = -1 + x["model"].half() # to FP16 + for p in x["model"].parameters(): p.requires_grad = False torch.save(x, s or f) - mb = os.path.getsize(s or f) / 1E6 # filesize + mb = os.path.getsize(s or f) / 1e6 # filesize LOGGER.info(f"Optimizer stripped from {f},{f' saved as {s},' if s else ''} {mb:.1f}MB") -def print_mutation(keys, results, hyp, save_dir, bucket, prefix=colorstr('evolve: ')): - evolve_csv = save_dir / 'evolve.csv' - evolve_yaml = save_dir / 'hyp_evolve.yaml' +def print_mutation(keys, results, hyp, save_dir, bucket, prefix=colorstr("evolve: ")): + evolve_csv = save_dir / "evolve.csv" + evolve_yaml = save_dir / "hyp_evolve.yaml" keys = tuple(keys) + tuple(hyp.keys()) # [results + hyps] keys = tuple(x.strip() for x in keys) vals = results + tuple(hyp.values()) @@ -992,33 +1081,48 @@ def print_mutation(keys, results, hyp, save_dir, bucket, prefix=colorstr('evolve # Download (optional) if bucket: - url = f'gs://{bucket}/evolve.csv' + url = f"gs://{bucket}/evolve.csv" if gsutil_getsize(url) > (evolve_csv.stat().st_size if evolve_csv.exists() else 0): - subprocess.run(['gsutil', 'cp', f'{url}', f'{save_dir}']) # download evolve.csv if larger than local + subprocess.run(["gsutil", "cp", f"{url}", f"{save_dir}"]) # download evolve.csv if larger than local # Log to evolve.csv - s = '' if evolve_csv.exists() else (('%20s,' * n % keys).rstrip(',') + '\n') # add header - with open(evolve_csv, 'a') as f: - f.write(s + ('%20.5g,' * n % vals).rstrip(',') + '\n') + s = "" if evolve_csv.exists() else (("%20s," * n % keys).rstrip(",") + "\n") # add header + with open(evolve_csv, "a") as f: + f.write(s + ("%20.5g," * n % vals).rstrip(",") + "\n") # Save yaml - with open(evolve_yaml, 'w') as f: + with open(evolve_yaml, "w") as f: data = pd.read_csv(evolve_csv, skipinitialspace=True) data = data.rename(columns=lambda x: x.strip()) # strip keys i = np.argmax(fitness(data.values[:, :4])) # generations = len(data) - f.write('# YOLOv3 Hyperparameter Evolution Results\n' + f'# Best generation: {i}\n' + - f'# Last generation: {generations - 1}\n' + '# ' + ', '.join(f'{x.strip():>20s}' for x in keys[:7]) + - '\n' + '# ' + ', '.join(f'{x:>20.5g}' for x in data.values[i, :7]) + '\n\n') + f.write( + "# YOLOv3 Hyperparameter Evolution Results\n" + + f"# Best generation: {i}\n" + + f"# Last generation: {generations - 1}\n" + + "# " + + ", ".join(f"{x.strip():>20s}" for x in keys[:7]) + + "\n" + + "# " + + ", ".join(f"{x:>20.5g}" for x in data.values[i, :7]) + + "\n\n" + ) yaml.safe_dump(data.loc[i][7:].to_dict(), f, sort_keys=False) # Print to screen - LOGGER.info(prefix + f'{generations} generations finished, current result:\n' + prefix + - ', '.join(f'{x.strip():>20s}' for x in keys) + '\n' + prefix + ', '.join(f'{x:20.5g}' - for x in vals) + '\n\n') + LOGGER.info( + prefix + + f"{generations} generations finished, current result:\n" + + prefix + + ", ".join(f"{x.strip():>20s}" for x in keys) + + "\n" + + prefix + + ", ".join(f"{x:20.5g}" for x in vals) + + "\n\n" + ) if bucket: - subprocess.run(['gsutil', 'cp', f'{evolve_csv}', f'{evolve_yaml}', f'gs://{bucket}']) # upload + subprocess.run(["gsutil", "cp", f"{evolve_csv}", f"{evolve_yaml}", f"gs://{bucket}"]) # upload def apply_classifier(x, model, img, im0): @@ -1042,7 +1146,7 @@ def apply_classifier(x, model, img, im0): pred_cls1 = d[:, 5].long() ims = [] for a in d: - cutout = im0[i][int(a[1]):int(a[3]), int(a[0]):int(a[2])] + cutout = im0[i][int(a[1]) : int(a[3]), int(a[0]) : int(a[2])] im = cv2.resize(cutout, (224, 224)) # BGR im = im[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 @@ -1056,15 +1160,15 @@ def apply_classifier(x, model, img, im0): return x -def increment_path(path, exist_ok=False, sep='', mkdir=False): +def increment_path(path, exist_ok=False, sep="", mkdir=False): # Increment file or directory path, i.e. runs/exp --> runs/exp{sep}2, runs/exp{sep}3, ... etc. path = Path(path) # os-agnostic if path.exists() and not exist_ok: - path, suffix = (path.with_suffix(''), path.suffix) if path.is_file() else (path, '') + path, suffix = (path.with_suffix(""), path.suffix) if path.is_file() else (path, "") # Method 1 for n in range(2, 9999): - p = f'{path}{sep}{n}{suffix}' # increment path + p = f"{path}{sep}{n}{suffix}" # increment path if not os.path.exists(p): # break path = Path(p) @@ -1099,7 +1203,7 @@ def imwrite(filename, img): def imshow(path, im): - imshow_(path.encode('unicode_escape').decode(), im) + imshow_(path.encode("unicode_escape").decode(), im) if Path(inspect.stack()[0].filename).parent.parent.as_posix() in inspect.stack()[-1].filename: diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index f78d6b5c01..4d4c4fccfd 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Logging utils -""" +"""Logging utils.""" import os import warnings @@ -16,8 +14,8 @@ from utils.plots import plot_images, plot_labels, plot_results from utils.torch_utils import de_parallel -LOGGERS = ('csv', 'tb', 'wandb', 'clearml', 'comet') # *.csv, TensorBoard, Weights & Biases, ClearML -RANK = int(os.getenv('RANK', -1)) +LOGGERS = ("csv", "tb", "wandb", "clearml", "comet") # *.csv, TensorBoard, Weights & Biases, ClearML +RANK = int(os.getenv("RANK", -1)) try: from torch.utils.tensorboard import SummaryWriter @@ -27,8 +25,8 @@ try: import wandb - assert hasattr(wandb, '__version__') # verify package import not local dir - if pkg.parse_version(wandb.__version__) >= pkg.parse_version('0.12.2') and RANK in {0, -1}: + assert hasattr(wandb, "__version__") # verify package import not local dir + if pkg.parse_version(wandb.__version__) >= pkg.parse_version("0.12.2") and RANK in {0, -1}: try: wandb_login_success = wandb.login(timeout=30) except wandb.errors.UsageError: # known non-TTY terminal issue @@ -41,7 +39,7 @@ try: import clearml - assert hasattr(clearml, '__version__') # verify package import not local dir + assert hasattr(clearml, "__version__") # verify package import not local dir except (ImportError, AssertionError): clearml = None @@ -49,7 +47,7 @@ if RANK in {0, -1}: import comet_ml - assert hasattr(comet_ml, '__version__') # verify package import not local dir + assert hasattr(comet_ml, "__version__") # verify package import not local dir from utils.loggers.comet import CometLogger else: @@ -58,7 +56,7 @@ comet_ml = None -class Loggers(): +class Loggers: # YOLOv3 Loggers class def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, include=LOGGERS): self.save_dir = save_dir @@ -69,60 +67,63 @@ def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, self.logger = logger # for printing results to console self.include = include self.keys = [ - 'train/box_loss', - 'train/obj_loss', - 'train/cls_loss', # train loss - 'metrics/precision', - 'metrics/recall', - 'metrics/mAP_0.5', - 'metrics/mAP_0.5:0.95', # metrics - 'val/box_loss', - 'val/obj_loss', - 'val/cls_loss', # val loss - 'x/lr0', - 'x/lr1', - 'x/lr2'] # params - self.best_keys = ['best/epoch', 'best/precision', 'best/recall', 'best/mAP_0.5', 'best/mAP_0.5:0.95'] + "train/box_loss", + "train/obj_loss", + "train/cls_loss", # train loss + "metrics/precision", + "metrics/recall", + "metrics/mAP_0.5", + "metrics/mAP_0.5:0.95", # metrics + "val/box_loss", + "val/obj_loss", + "val/cls_loss", # val loss + "x/lr0", + "x/lr1", + "x/lr2", + ] # params + self.best_keys = ["best/epoch", "best/precision", "best/recall", "best/mAP_0.5", "best/mAP_0.5:0.95"] for k in LOGGERS: setattr(self, k, None) # init empty logger dictionary self.csv = True # always log to csv # Messages if not comet_ml: - prefix = colorstr('Comet: ') + prefix = colorstr("Comet: ") s = f"{prefix}run 'pip install comet_ml' to automatically track and visualize YOLOv3 🚀 runs in Comet" self.logger.info(s) # TensorBoard s = self.save_dir - if 'tb' in self.include and not self.opt.evolve: - prefix = colorstr('TensorBoard: ') + if "tb" in self.include and not self.opt.evolve: + prefix = colorstr("TensorBoard: ") self.logger.info(f"{prefix}Start with 'tensorboard --logdir {s.parent}', view at http://localhost:6006/") self.tb = SummaryWriter(str(s)) # W&B - if wandb and 'wandb' in self.include: + if wandb and "wandb" in self.include: self.opt.hyp = self.hyp # add hyperparameters self.wandb = WandbLogger(self.opt) else: self.wandb = None # ClearML - if clearml and 'clearml' in self.include: + if clearml and "clearml" in self.include: try: self.clearml = ClearmlLogger(self.opt, self.hyp) except Exception: self.clearml = None - prefix = colorstr('ClearML: ') - LOGGER.warning(f'{prefix}WARNING ⚠️ ClearML is installed but not configured, skipping ClearML logging.' - f' See https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration#readme') + prefix = colorstr("ClearML: ") + LOGGER.warning( + f"{prefix}WARNING ⚠️ ClearML is installed but not configured, skipping ClearML logging." + f" See https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration#readme" + ) else: self.clearml = None # Comet - if comet_ml and 'comet' in self.include: - if isinstance(self.opt.resume, str) and self.opt.resume.startswith('comet://'): - run_id = self.opt.resume.split('/')[-1] + if comet_ml and "comet" in self.include: + if isinstance(self.opt.resume, str) and self.opt.resume.startswith("comet://"): + run_id = self.opt.resume.split("/")[-1] self.comet_logger = CometLogger(self.opt, self.hyp, run_id=run_id) else: @@ -156,9 +157,9 @@ def on_pretrain_routine_end(self, labels, names): # Callback runs on pre-train routine end if self.plots: plot_labels(labels, names, self.save_dir) - paths = self.save_dir.glob('*labels*.jpg') # training labels + paths = self.save_dir.glob("*labels*.jpg") # training labels if self.wandb: - self.wandb.log({'Labels': [wandb.Image(str(x), caption=x.name) for x in paths]}) + self.wandb.log({"Labels": [wandb.Image(str(x), caption=x.name) for x in paths]}) # if self.clearml: # pass # ClearML saves these images automatically using hooks if self.comet_logger: @@ -170,16 +171,16 @@ def on_train_batch_end(self, model, ni, imgs, targets, paths, vals): # ni: number integrated batches (since train start) if self.plots: if ni < 3: - f = self.save_dir / f'train_batch{ni}.jpg' # filename + f = self.save_dir / f"train_batch{ni}.jpg" # filename plot_images(imgs, targets, paths, f) if ni == 0 and self.tb and not self.opt.sync_bn: log_tensorboard_graph(self.tb, model, imgsz=(self.opt.imgsz, self.opt.imgsz)) if ni == 10 and (self.wandb or self.clearml): - files = sorted(self.save_dir.glob('train*.jpg')) + files = sorted(self.save_dir.glob("train*.jpg")) if self.wandb: - self.wandb.log({'Mosaics': [wandb.Image(str(f), caption=f.name) for f in files if f.exists()]}) + self.wandb.log({"Mosaics": [wandb.Image(str(f), caption=f.name) for f in files if f.exists()]}) if self.clearml: - self.clearml.log_debug_samples(files, title='Mosaics') + self.clearml.log_debug_samples(files, title="Mosaics") if self.comet_logger: self.comet_logger.on_train_batch_end(log_dict, step=ni) @@ -210,11 +211,11 @@ def on_val_batch_end(self, batch_i, im, targets, paths, shapes, out): def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix): # Callback runs on val end if self.wandb or self.clearml: - files = sorted(self.save_dir.glob('val*.jpg')) + files = sorted(self.save_dir.glob("val*.jpg")) if self.wandb: - self.wandb.log({'Validation': [wandb.Image(str(f), caption=f.name) for f in files]}) + self.wandb.log({"Validation": [wandb.Image(str(f), caption=f.name) for f in files]}) if self.clearml: - self.clearml.log_debug_samples(files, title='Validation') + self.clearml.log_debug_samples(files, title="Validation") if self.comet_logger: self.comet_logger.on_val_end(nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) @@ -223,18 +224,18 @@ def on_fit_epoch_end(self, vals, epoch, best_fitness, fi): # Callback runs at the end of each fit (train+val) epoch x = dict(zip(self.keys, vals)) if self.csv: - file = self.save_dir / 'results.csv' + file = self.save_dir / "results.csv" n = len(x) + 1 # number of cols - s = '' if file.exists() else (('%20s,' * n % tuple(['epoch'] + self.keys)).rstrip(',') + '\n') # add header - with open(file, 'a') as f: - f.write(s + ('%20.5g,' * n % tuple([epoch] + vals)).rstrip(',') + '\n') + s = "" if file.exists() else (("%20s," * n % tuple(["epoch"] + self.keys)).rstrip(",") + "\n") # add header + with open(file, "a") as f: + f.write(s + ("%20.5g," * n % tuple([epoch] + vals)).rstrip(",") + "\n") if self.tb: for k, v in x.items(): self.tb.add_scalar(k, v, epoch) elif self.clearml: # log to ClearML if TensorBoard not used for k, v in x.items(): - title, series = k.split('/') + title, series = k.split("/") self.clearml.task.get_logger().report_scalar(title, series, v, epoch) if self.wandb: @@ -258,9 +259,9 @@ def on_model_save(self, last, epoch, final_epoch, best_fitness, fi): if self.wandb: self.wandb.log_model(last.parent, self.opt, epoch, fi, best_model=best_fitness == fi) if self.clearml: - self.clearml.task.update_output_model(model_path=str(last), - model_name='Latest Model', - auto_delete_file=False) + self.clearml.task.update_output_model( + model_path=str(last), model_name="Latest Model", auto_delete_file=False + ) if self.comet_logger: self.comet_logger.on_model_save(last, epoch, final_epoch, best_fitness, fi) @@ -268,30 +269,32 @@ def on_model_save(self, last, epoch, final_epoch, best_fitness, fi): def on_train_end(self, last, best, epoch, results): # Callback runs on training end, i.e. saving best model if self.plots: - plot_results(file=self.save_dir / 'results.csv') # save results.png - files = ['results.png', 'confusion_matrix.png', *(f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R'))] + plot_results(file=self.save_dir / "results.csv") # save results.png + files = ["results.png", "confusion_matrix.png", *(f"{x}_curve.png" for x in ("F1", "PR", "P", "R"))] files = [(self.save_dir / f) for f in files if (self.save_dir / f).exists()] # filter self.logger.info(f"Results saved to {colorstr('bold', self.save_dir)}") if self.tb and not self.clearml: # These images are already captured by ClearML by now, we don't want doubles for f in files: - self.tb.add_image(f.stem, cv2.imread(str(f))[..., ::-1], epoch, dataformats='HWC') + self.tb.add_image(f.stem, cv2.imread(str(f))[..., ::-1], epoch, dataformats="HWC") if self.wandb: self.wandb.log(dict(zip(self.keys[3:10], results))) - self.wandb.log({'Results': [wandb.Image(str(f), caption=f.name) for f in files]}) + self.wandb.log({"Results": [wandb.Image(str(f), caption=f.name) for f in files]}) # Calling wandb.log. TODO: Refactor this into WandbLogger.log_model if not self.opt.evolve: - wandb.log_artifact(str(best if best.exists() else last), - type='model', - name=f'run_{self.wandb.wandb_run.id}_model', - aliases=['latest', 'best', 'stripped']) + wandb.log_artifact( + str(best if best.exists() else last), + type="model", + name=f"run_{self.wandb.wandb_run.id}_model", + aliases=["latest", "best", "stripped"], + ) self.wandb.finish_run() if self.clearml and not self.opt.evolve: - self.clearml.task.update_output_model(model_path=str(best if best.exists() else last), - name='Best Model', - auto_delete_file=False) + self.clearml.task.update_output_model( + model_path=str(best if best.exists() else last), name="Best Model", auto_delete_file=False + ) if self.comet_logger: final_results = dict(zip(self.keys[3:10], results)) @@ -315,22 +318,23 @@ class GenericLogger: include: loggers to include """ - def __init__(self, opt, console_logger, include=('tb', 'wandb')): + def __init__(self, opt, console_logger, include=("tb", "wandb")): # init default loggers self.save_dir = Path(opt.save_dir) self.include = include self.console_logger = console_logger - self.csv = self.save_dir / 'results.csv' # CSV logger - if 'tb' in self.include: - prefix = colorstr('TensorBoard: ') + self.csv = self.save_dir / "results.csv" # CSV logger + if "tb" in self.include: + prefix = colorstr("TensorBoard: ") self.console_logger.info( - f"{prefix}Start with 'tensorboard --logdir {self.save_dir.parent}', view at http://localhost:6006/") + f"{prefix}Start with 'tensorboard --logdir {self.save_dir.parent}', view at http://localhost:6006/" + ) self.tb = SummaryWriter(str(self.save_dir)) - if wandb and 'wandb' in self.include: - self.wandb = wandb.init(project=web_project_name(str(opt.project)), - name=None if opt.name == 'exp' else opt.name, - config=opt) + if wandb and "wandb" in self.include: + self.wandb = wandb.init( + project=web_project_name(str(opt.project)), name=None if opt.name == "exp" else opt.name, config=opt + ) else: self.wandb = None @@ -339,9 +343,9 @@ def log_metrics(self, metrics, epoch): if self.csv: keys, vals = list(metrics.keys()), list(metrics.values()) n = len(metrics) + 1 # number of cols - s = '' if self.csv.exists() else (('%23s,' * n % tuple(['epoch'] + keys)).rstrip(',') + '\n') # header - with open(self.csv, 'a') as f: - f.write(s + ('%23.5g,' * n % tuple([epoch] + vals)).rstrip(',') + '\n') + s = "" if self.csv.exists() else (("%23s," * n % tuple(["epoch"] + keys)).rstrip(",") + "\n") # header + with open(self.csv, "a") as f: + f.write(s + ("%23.5g," * n % tuple([epoch] + vals)).rstrip(",") + "\n") if self.tb: for k, v in metrics.items(): @@ -350,14 +354,14 @@ def log_metrics(self, metrics, epoch): if self.wandb: self.wandb.log(metrics, step=epoch) - def log_images(self, files, name='Images', epoch=0): + def log_images(self, files, name="Images", epoch=0): # Log images to all loggers files = [Path(f) for f in (files if isinstance(files, (tuple, list)) else [files])] # to Path files = [f for f in files if f.exists()] # filter by exists if self.tb: for f in files: - self.tb.add_image(f.stem, cv2.imread(str(f))[..., ::-1], epoch, dataformats='HWC') + self.tb.add_image(f.stem, cv2.imread(str(f))[..., ::-1], epoch, dataformats="HWC") if self.wandb: self.wandb.log({name: [wandb.Image(str(f), caption=f.name) for f in files]}, step=epoch) @@ -370,7 +374,7 @@ def log_graph(self, model, imgsz=(640, 640)): def log_model(self, model_path, epoch=0, metadata={}): # Log model to all loggers if self.wandb: - art = wandb.Artifact(name=f'run_{wandb.run.id}_model', type='model', metadata=metadata) + art = wandb.Artifact(name=f"run_{wandb.run.id}_model", type="model", metadata=metadata) art.add_file(str(model_path)) wandb.log_artifact(art) @@ -387,15 +391,15 @@ def log_tensorboard_graph(tb, model, imgsz=(640, 640)): imgsz = (imgsz, imgsz) if isinstance(imgsz, int) else imgsz # expand im = torch.zeros((1, 3, *imgsz)).to(p.device).type_as(p) # input image (WARNING: must be zeros, not empty) with warnings.catch_warnings(): - warnings.simplefilter('ignore') # suppress jit trace warning + warnings.simplefilter("ignore") # suppress jit trace warning tb.add_graph(torch.jit.trace(de_parallel(model), im, strict=False), []) except Exception as e: - LOGGER.warning(f'WARNING ⚠️ TensorBoard graph visualization failure {e}') + LOGGER.warning(f"WARNING ⚠️ TensorBoard graph visualization failure {e}") def web_project_name(project): # Convert local project name to web project name - if not project.startswith('runs/train'): + if not project.startswith("runs/train"): return project - suffix = '-Classify' if project.endswith('-cls') else '-Segment' if project.endswith('-seg') else '' - return f'YOLOv3{suffix}' + suffix = "-Classify" if project.endswith("-cls") else "-Segment" if project.endswith("-seg") else "" + return f"YOLOv3{suffix}" diff --git a/utils/loggers/clearml/README.md b/utils/loggers/clearml/README.md index 7dbf6e4263..d228ebfde3 100644 --- a/utils/loggers/clearml/README.md +++ b/utils/loggers/clearml/README.md @@ -38,7 +38,7 @@ Either sign up for free to the [ClearML Hosted Service](https://cutt.ly/yolov5-t pip install clearml ``` -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: +2. 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: ```bash clearml-init @@ -58,8 +58,7 @@ pip install clearml>=1.2.0 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`, use the `--project` and `--name` arguments of the `train.py` script, by default the project will be called `YOLOv5` and the task `Training`. -PLEASE NOTE: ClearML uses `/` as a delimiter for subprojects, so be careful when using `/` in your project name! +If you want to change the `project_name` or `task_name`, use the `--project` and `--name` arguments of the `train.py` script, by default the project will be called `YOLOv5` and the task `Training`. PLEASE NOTE: ClearML uses `/` as a delimiter for subprojects, so be careful when using `/` in your project name! ```bash python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov5s.pt --cache @@ -86,8 +85,7 @@ This will capture: - Validation images per epoch - ... -That's a lot right? 🤯 -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! +That's a lot right? 🤯 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! 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! @@ -181,8 +179,7 @@ python utils/loggers/clearml/hpo.py ## 🤯 Remote Execution (advanced) -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. -This is where the ClearML Agent comes into play. Check out what the agent can do here: +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. This is where the ClearML Agent comes into play. Check out what the agent can do here: - [YouTube video](https://youtu.be/MX3BrXnaULs) - [Documentation](https://clear.ml/docs/latest/docs/clearml_agent) diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py index 0c7ddeed31..df4c945202 100644 --- a/utils/loggers/clearml/clearml_utils.py +++ b/utils/loggers/clearml/clearml_utils.py @@ -11,55 +11,63 @@ import clearml from clearml import Dataset, Task - assert hasattr(clearml, '__version__') # verify package import not local dir + assert hasattr(clearml, "__version__") # verify package import not local dir except (ImportError, AssertionError): clearml = None def construct_dataset(clearml_info_string): - """Load in a clearml dataset and fill the internal data_dict with its contents. - """ - dataset_id = clearml_info_string.replace('clearml://', '') + """Load in a clearml dataset and fill the internal data_dict with its contents.""" + dataset_id = clearml_info_string.replace("clearml://", "") dataset = Dataset.get(dataset_id=dataset_id) dataset_root_path = Path(dataset.get_local_copy()) # We'll search for the yaml file definition in the dataset - yaml_filenames = list(glob.glob(str(dataset_root_path / '*.yaml')) + glob.glob(str(dataset_root_path / '*.yml'))) + yaml_filenames = list(glob.glob(str(dataset_root_path / "*.yaml")) + glob.glob(str(dataset_root_path / "*.yml"))) if len(yaml_filenames) > 1: - raise ValueError('More than one yaml file was found in the dataset root, cannot determine which one contains ' - 'the dataset definition this way.') + raise ValueError( + "More than one yaml file was found in the dataset root, cannot determine which one contains " + "the dataset definition this way." + ) elif len(yaml_filenames) == 0: - raise ValueError('No yaml definition found in dataset root path, check that there is a correct yaml file ' - 'inside the dataset root path.') + raise ValueError( + "No yaml definition found in dataset root path, check that there is a correct yaml file " + "inside the dataset root path." + ) with open(yaml_filenames[0]) as f: dataset_definition = yaml.safe_load(f) - assert set(dataset_definition.keys()).issuperset( - {'train', 'test', 'val', 'nc', 'names'} + assert set( + dataset_definition.keys() + ).issuperset( + {"train", "test", "val", "nc", "names"} ), "The right keys were not found in the yaml file, make sure it at least has the following keys: ('train', 'test', 'val', 'nc', 'names')" data_dict = dict() - data_dict['train'] = str( - (dataset_root_path / dataset_definition['train']).resolve()) if dataset_definition['train'] else None - data_dict['test'] = str( - (dataset_root_path / dataset_definition['test']).resolve()) if dataset_definition['test'] else None - data_dict['val'] = str( - (dataset_root_path / dataset_definition['val']).resolve()) if dataset_definition['val'] else None - data_dict['nc'] = dataset_definition['nc'] - data_dict['names'] = dataset_definition['names'] + data_dict["train"] = ( + str((dataset_root_path / dataset_definition["train"]).resolve()) if dataset_definition["train"] else None + ) + data_dict["test"] = ( + str((dataset_root_path / dataset_definition["test"]).resolve()) if dataset_definition["test"] else None + ) + data_dict["val"] = ( + str((dataset_root_path / dataset_definition["val"]).resolve()) if dataset_definition["val"] else None + ) + data_dict["nc"] = dataset_definition["nc"] + data_dict["names"] = dataset_definition["names"] return data_dict class ClearmlLogger: - """Log training runs, datasets, models, and predictions to ClearML. + """ + Log training runs, datasets, models, and predictions to ClearML. - This logger sends information to ClearML at app.clear.ml or to your own hosted server. By default, - this information includes hyperparameters, system configuration and metrics, model metrics, code information and - basic data metrics and analyses. + This logger sends information to ClearML at app.clear.ml or to your own hosted server. By default, this information + includes hyperparameters, system configuration and metrics, model metrics, code information and basic data metrics + and analyses. - By providing additional command line arguments to train.py, datasets, - models and predictions can also be logged. + By providing additional command line arguments to train.py, datasets, models and predictions can also be logged. """ def __init__(self, opt, hyp): @@ -84,27 +92,29 @@ def __init__(self, opt, hyp): self.data_dict = None if self.clearml: self.task = Task.init( - project_name=opt.project if opt.project != 'runs/train' else 'YOLOv3', - task_name=opt.name if opt.name != 'exp' else 'Training', - tags=['YOLOv3'], + project_name=opt.project if opt.project != "runs/train" else "YOLOv3", + task_name=opt.name if opt.name != "exp" else "Training", + tags=["YOLOv3"], output_uri=True, reuse_last_task_id=opt.exist_ok, - auto_connect_frameworks={'pytorch': False} + auto_connect_frameworks={"pytorch": False}, # We disconnect pytorch auto-detection, because we added manual model save points in the code ) # ClearML's hooks will already grab all general parameters # Only the hyperparameters coming from the yaml config file # will have to be added manually! - self.task.connect(hyp, name='Hyperparameters') - self.task.connect(opt, name='Args') + self.task.connect(hyp, name="Hyperparameters") + self.task.connect(opt, name="Args") # Make sure the code is easily remotely runnable by setting the docker image to use by the remote agent - self.task.set_base_docker('ultralytics/yolov5:latest', - docker_arguments='--ipc=host -e="CLEARML_AGENT_SKIP_PYTHON_ENV_INSTALL=1"', - docker_setup_bash_script='pip install clearml') + self.task.set_base_docker( + "ultralytics/yolov5:latest", + docker_arguments='--ipc=host -e="CLEARML_AGENT_SKIP_PYTHON_ENV_INSTALL=1"', + docker_setup_bash_script="pip install clearml", + ) # Get ClearML Dataset Version if requested - if opt.data.startswith('clearml://'): + if opt.data.startswith("clearml://"): # data_dict should have the following keys: # names, nc (number of classes), test, train, val (all three relative paths to ../datasets) self.data_dict = construct_dataset(opt.data) @@ -112,7 +122,7 @@ def __init__(self, opt, hyp): # to give it to them opt.data = self.data_dict - def log_debug_samples(self, files, title='Debug Samples'): + def log_debug_samples(self, files, title="Debug Samples"): """ Log files (images) as debug samples in the ClearML task. @@ -122,12 +132,11 @@ def log_debug_samples(self, files, title='Debug Samples'): """ for f in files: if f.exists(): - it = re.search(r'_batch(\d+)', f.name) + it = re.search(r"_batch(\d+)", f.name) iteration = int(it.groups()[0]) if it else 0 - self.task.get_logger().report_image(title=title, - series=f.name.replace(it.group(), ''), - local_path=str(f), - iteration=iteration) + self.task.get_logger().report_image( + title=title, series=f.name.replace(it.group(), ""), local_path=str(f), iteration=iteration + ) def log_image_with_boxes(self, image_path, boxes, class_names, image, conf_threshold=0.25): """ @@ -149,15 +158,14 @@ def log_image_with_boxes(self, image_path, boxes, class_names, image, conf_thres class_name = class_names[int(class_nr)] confidence_percentage = round(float(conf) * 100, 2) - label = f'{class_name}: {confidence_percentage}%' + label = f"{class_name}: {confidence_percentage}%" if conf > conf_threshold: annotator.rectangle(box.cpu().numpy(), outline=color) annotator.box_label(box.cpu().numpy(), label=label, color=color) annotated_image = annotator.result() - self.task.get_logger().report_image(title='Bounding Boxes', - series=image_path.name, - iteration=self.current_epoch, - image=annotated_image) + self.task.get_logger().report_image( + title="Bounding Boxes", series=image_path.name, iteration=self.current_epoch, image=annotated_image + ) self.current_epoch_logged_images.add(image_path) diff --git a/utils/loggers/clearml/hpo.py b/utils/loggers/clearml/hpo.py index 8cccaa23b6..fcbd6770f6 100644 --- a/utils/loggers/clearml/hpo.py +++ b/utils/loggers/clearml/hpo.py @@ -1,18 +1,21 @@ from clearml import Task + # Connecting ClearML with the current process, # from here on everything is logged automatically from clearml.automation import HyperParameterOptimizer, UniformParameterRange from clearml.automation.optuna import OptimizerOptuna -task = Task.init(project_name='Hyper-Parameter Optimization', - task_name='YOLOv3', - task_type=Task.TaskTypes.optimizer, - reuse_last_task_id=False) +task = Task.init( + project_name="Hyper-Parameter Optimization", + task_name="YOLOv3", + task_type=Task.TaskTypes.optimizer, + reuse_last_task_id=False, +) # Example use case: optimizer = HyperParameterOptimizer( # This is the experiment we want to optimize - base_task_id='', + base_task_id="", # here we define the hyper-parameters to optimize # Notice: The parameter name should exactly match what you see in the UI: / # For Example, here we see in the base experiment a section Named: "General" @@ -20,39 +23,40 @@ # If you have `argparse` for example, then arguments will appear under the "Args" section, # and you should instead pass "Args/batch_size" hyper_parameters=[ - UniformParameterRange('Hyperparameters/lr0', min_value=1e-5, max_value=1e-1), - UniformParameterRange('Hyperparameters/lrf', min_value=0.01, max_value=1.0), - UniformParameterRange('Hyperparameters/momentum', min_value=0.6, max_value=0.98), - UniformParameterRange('Hyperparameters/weight_decay', min_value=0.0, max_value=0.001), - UniformParameterRange('Hyperparameters/warmup_epochs', min_value=0.0, max_value=5.0), - UniformParameterRange('Hyperparameters/warmup_momentum', min_value=0.0, max_value=0.95), - UniformParameterRange('Hyperparameters/warmup_bias_lr', min_value=0.0, max_value=0.2), - UniformParameterRange('Hyperparameters/box', min_value=0.02, max_value=0.2), - UniformParameterRange('Hyperparameters/cls', min_value=0.2, max_value=4.0), - UniformParameterRange('Hyperparameters/cls_pw', min_value=0.5, max_value=2.0), - UniformParameterRange('Hyperparameters/obj', min_value=0.2, max_value=4.0), - UniformParameterRange('Hyperparameters/obj_pw', min_value=0.5, max_value=2.0), - UniformParameterRange('Hyperparameters/iou_t', min_value=0.1, max_value=0.7), - UniformParameterRange('Hyperparameters/anchor_t', min_value=2.0, max_value=8.0), - UniformParameterRange('Hyperparameters/fl_gamma', min_value=0.0, max_value=4.0), - UniformParameterRange('Hyperparameters/hsv_h', min_value=0.0, max_value=0.1), - UniformParameterRange('Hyperparameters/hsv_s', min_value=0.0, max_value=0.9), - UniformParameterRange('Hyperparameters/hsv_v', min_value=0.0, max_value=0.9), - UniformParameterRange('Hyperparameters/degrees', min_value=0.0, max_value=45.0), - UniformParameterRange('Hyperparameters/translate', min_value=0.0, max_value=0.9), - UniformParameterRange('Hyperparameters/scale', min_value=0.0, max_value=0.9), - UniformParameterRange('Hyperparameters/shear', min_value=0.0, max_value=10.0), - UniformParameterRange('Hyperparameters/perspective', min_value=0.0, max_value=0.001), - UniformParameterRange('Hyperparameters/flipud', min_value=0.0, max_value=1.0), - UniformParameterRange('Hyperparameters/fliplr', min_value=0.0, max_value=1.0), - UniformParameterRange('Hyperparameters/mosaic', min_value=0.0, max_value=1.0), - UniformParameterRange('Hyperparameters/mixup', min_value=0.0, max_value=1.0), - UniformParameterRange('Hyperparameters/copy_paste', min_value=0.0, max_value=1.0)], + UniformParameterRange("Hyperparameters/lr0", min_value=1e-5, max_value=1e-1), + UniformParameterRange("Hyperparameters/lrf", min_value=0.01, max_value=1.0), + UniformParameterRange("Hyperparameters/momentum", min_value=0.6, max_value=0.98), + UniformParameterRange("Hyperparameters/weight_decay", min_value=0.0, max_value=0.001), + UniformParameterRange("Hyperparameters/warmup_epochs", min_value=0.0, max_value=5.0), + UniformParameterRange("Hyperparameters/warmup_momentum", min_value=0.0, max_value=0.95), + UniformParameterRange("Hyperparameters/warmup_bias_lr", min_value=0.0, max_value=0.2), + UniformParameterRange("Hyperparameters/box", min_value=0.02, max_value=0.2), + UniformParameterRange("Hyperparameters/cls", min_value=0.2, max_value=4.0), + UniformParameterRange("Hyperparameters/cls_pw", min_value=0.5, max_value=2.0), + UniformParameterRange("Hyperparameters/obj", min_value=0.2, max_value=4.0), + UniformParameterRange("Hyperparameters/obj_pw", min_value=0.5, max_value=2.0), + UniformParameterRange("Hyperparameters/iou_t", min_value=0.1, max_value=0.7), + UniformParameterRange("Hyperparameters/anchor_t", min_value=2.0, max_value=8.0), + UniformParameterRange("Hyperparameters/fl_gamma", min_value=0.0, max_value=4.0), + UniformParameterRange("Hyperparameters/hsv_h", min_value=0.0, max_value=0.1), + UniformParameterRange("Hyperparameters/hsv_s", min_value=0.0, max_value=0.9), + UniformParameterRange("Hyperparameters/hsv_v", min_value=0.0, max_value=0.9), + UniformParameterRange("Hyperparameters/degrees", min_value=0.0, max_value=45.0), + UniformParameterRange("Hyperparameters/translate", min_value=0.0, max_value=0.9), + UniformParameterRange("Hyperparameters/scale", min_value=0.0, max_value=0.9), + UniformParameterRange("Hyperparameters/shear", min_value=0.0, max_value=10.0), + UniformParameterRange("Hyperparameters/perspective", min_value=0.0, max_value=0.001), + UniformParameterRange("Hyperparameters/flipud", min_value=0.0, max_value=1.0), + UniformParameterRange("Hyperparameters/fliplr", min_value=0.0, max_value=1.0), + UniformParameterRange("Hyperparameters/mosaic", min_value=0.0, max_value=1.0), + UniformParameterRange("Hyperparameters/mixup", min_value=0.0, max_value=1.0), + UniformParameterRange("Hyperparameters/copy_paste", min_value=0.0, max_value=1.0), + ], # this is the objective metric we want to maximize/minimize - objective_metric_title='metrics', - objective_metric_series='mAP_0.5', + objective_metric_title="metrics", + objective_metric_series="mAP_0.5", # now we decide if we want to maximize it or minimize it (accuracy we maximize) - objective_metric_sign='max', + objective_metric_sign="max", # let us limit the number of concurrent experiments, # this in turn will make sure we do dont bombard the scheduler with experiments. # if we have an auto-scaler connected, this, by proxy, will limit the number of machine @@ -81,4 +85,4 @@ # make sure background optimization stopped optimizer.stop() -print('We are done, good bye') +print("We are done, good bye") diff --git a/utils/loggers/comet/README.md b/utils/loggers/comet/README.md index 3ad52b01b4..52f344dba6 100644 --- a/utils/loggers/comet/README.md +++ b/utils/loggers/comet/README.md @@ -8,8 +8,7 @@ This guide will cover how to use YOLOv5 with [Comet](https://bit.ly/yolov5-readm Comet builds tools that help data scientists, engineers, and team leaders accelerate and optimize machine learning and deep learning models. -Track and visualize model metrics in real time, save your hyperparameters, datasets, and model checkpoints, and visualize your model predictions with [Comet Custom Panels](https://www.comet.com/docs/v2/guides/comet-dashboard/code-panels/about-panels/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github)! -Comet makes sure you never lose track of your work and makes it easy to share results and collaborate across teams of all sizes! +Track and visualize model metrics in real time, save your hyperparameters, datasets, and model checkpoints, and visualize your model predictions with [Comet Custom Panels](https://www.comet.com/docs/v2/guides/comet-dashboard/code-panels/about-panels/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github)! Comet makes sure you never lose track of your work and makes it easy to share results and collaborate across teams of all sizes! # Getting Started @@ -84,8 +83,7 @@ By default, Comet will log the following items # Configure Comet Logging -Comet can be configured to log additional data either through command line flags passed to the training script -or through environment variables. +Comet can be configured to log additional data either through command line flags passed to the training script or through environment variables. ```shell export COMET_MODE=online # Set whether to run Comet in 'online' or 'offline' mode. Defaults to online @@ -100,8 +98,7 @@ export COMET_LOG_PREDICTIONS=true # Set this to false to disable logging model p ## Logging Checkpoints with Comet -Logging Models to Comet is disabled by default. To enable it, pass the `save-period` argument to the training script. This will save the -logged checkpoints to Comet based on the interval value provided by `save-period` +Logging Models to Comet is disabled by default. To enable it, pass the `save-period` argument to the training script. This will save the logged checkpoints to Comet based on the interval value provided by `save-period` ```shell python train.py \ @@ -176,14 +173,11 @@ python train.py \ --upload_dataset ``` -You can find the uploaded dataset in the Artifacts tab in your Comet Workspace -artifact-1 +You can find the uploaded dataset in the Artifacts tab in your Comet Workspace artifact-1 -You can preview the data directly in the Comet UI. -artifact-2 +You can preview the data directly in the Comet UI. artifact-2 -Artifacts are versioned and also support adding metadata about the dataset. Comet will automatically log the metadata from your dataset `yaml` file -artifact-3 +Artifacts are versioned and also support adding metadata about the dataset. Comet will automatically log the metadata from your dataset `yaml` file artifact-3 ### Using a saved Artifact @@ -205,8 +199,7 @@ python train.py \ --weights yolov5s.pt ``` -Artifacts also allow you to track the lineage of data as it flows through your Experimentation workflow. Here you can see a graph that shows you all the experiments that have used your uploaded dataset. -artifact-4 +Artifacts also allow you to track the lineage of data as it flows through your Experimentation workflow. Here you can see a graph that shows you all the experiments that have used your uploaded dataset. artifact-4 ## Resuming a Training Run @@ -214,7 +207,7 @@ If your training run is interrupted for any reason, e.g. disrupted internet conn The Run Path has the following format `comet:////`. -This will restore the run to its state before the interruption, which includes restoring the model from a checkpoint, restoring all hyperparameters and training arguments and downloading Comet dataset Artifacts if they were used in the original run. The resumed run will continue logging to the existing Experiment in the Comet UI +This will restore the run to its state before the interruption, which includes restoring the model from a checkpoint, restoring all hyperparameters and training arguments and downloading Comet dataset Artifacts if they were used in the original run. The resumed run will continue logging to the existing Experiment in the Comet UI ```shell python train.py \ @@ -234,8 +227,7 @@ python utils/loggers/comet/hpo.py \ --comet_optimizer_config "utils/loggers/comet/optimizer_config.json" ``` -The `hpo.py` script accepts the same arguments as `train.py`. If you wish to pass additional arguments to your sweep simply add them after -the script. +The `hpo.py` script accepts the same arguments as `train.py`. If you wish to pass additional arguments to your sweep simply add them after the script. ```shell python utils/loggers/comet/hpo.py \ diff --git a/utils/loggers/comet/__init__.py b/utils/loggers/comet/__init__.py index c3e999d81e..36eed15a2c 100644 --- a/utils/loggers/comet/__init__.py +++ b/utils/loggers/comet/__init__.py @@ -17,7 +17,7 @@ # Project Configuration config = comet_ml.config.get_config() - COMET_PROJECT_NAME = config.get_string(os.getenv('COMET_PROJECT_NAME'), 'comet.project_name', default='yolov5') + COMET_PROJECT_NAME = config.get_string(os.getenv("COMET_PROJECT_NAME"), "comet.project_name", default="yolov5") except ImportError: comet_ml = None COMET_PROJECT_NAME = None @@ -31,42 +31,40 @@ from utils.general import check_dataset, scale_boxes, xywh2xyxy from utils.metrics import box_iou -COMET_PREFIX = 'comet://' +COMET_PREFIX = "comet://" -COMET_MODE = os.getenv('COMET_MODE', 'online') +COMET_MODE = os.getenv("COMET_MODE", "online") # Model Saving Settings -COMET_MODEL_NAME = os.getenv('COMET_MODEL_NAME', 'yolov5') +COMET_MODEL_NAME = os.getenv("COMET_MODEL_NAME", "yolov5") # Dataset Artifact Settings -COMET_UPLOAD_DATASET = os.getenv('COMET_UPLOAD_DATASET', 'false').lower() == 'true' +COMET_UPLOAD_DATASET = os.getenv("COMET_UPLOAD_DATASET", "false").lower() == "true" # Evaluation Settings -COMET_LOG_CONFUSION_MATRIX = (os.getenv('COMET_LOG_CONFUSION_MATRIX', 'true').lower() == 'true') -COMET_LOG_PREDICTIONS = os.getenv('COMET_LOG_PREDICTIONS', 'true').lower() == 'true' -COMET_MAX_IMAGE_UPLOADS = int(os.getenv('COMET_MAX_IMAGE_UPLOADS', 100)) +COMET_LOG_CONFUSION_MATRIX = os.getenv("COMET_LOG_CONFUSION_MATRIX", "true").lower() == "true" +COMET_LOG_PREDICTIONS = os.getenv("COMET_LOG_PREDICTIONS", "true").lower() == "true" +COMET_MAX_IMAGE_UPLOADS = int(os.getenv("COMET_MAX_IMAGE_UPLOADS", 100)) # Confusion Matrix Settings -CONF_THRES = float(os.getenv('CONF_THRES', 0.001)) -IOU_THRES = float(os.getenv('IOU_THRES', 0.6)) +CONF_THRES = float(os.getenv("CONF_THRES", 0.001)) +IOU_THRES = float(os.getenv("IOU_THRES", 0.6)) # Batch Logging Settings -COMET_LOG_BATCH_METRICS = (os.getenv('COMET_LOG_BATCH_METRICS', 'false').lower() == 'true') -COMET_BATCH_LOGGING_INTERVAL = os.getenv('COMET_BATCH_LOGGING_INTERVAL', 1) -COMET_PREDICTION_LOGGING_INTERVAL = os.getenv('COMET_PREDICTION_LOGGING_INTERVAL', 1) -COMET_LOG_PER_CLASS_METRICS = (os.getenv('COMET_LOG_PER_CLASS_METRICS', 'false').lower() == 'true') +COMET_LOG_BATCH_METRICS = os.getenv("COMET_LOG_BATCH_METRICS", "false").lower() == "true" +COMET_BATCH_LOGGING_INTERVAL = os.getenv("COMET_BATCH_LOGGING_INTERVAL", 1) +COMET_PREDICTION_LOGGING_INTERVAL = os.getenv("COMET_PREDICTION_LOGGING_INTERVAL", 1) +COMET_LOG_PER_CLASS_METRICS = os.getenv("COMET_LOG_PER_CLASS_METRICS", "false").lower() == "true" -RANK = int(os.getenv('RANK', -1)) +RANK = int(os.getenv("RANK", -1)) to_pil = T.ToPILImage() class CometLogger: - """Log metrics, parameters, source code, models and much more - with Comet - """ + """Log metrics, parameters, source code, models and much more with Comet.""" - def __init__(self, opt, hyp, run_id=None, job_type='Training', **experiment_kwargs) -> None: + def __init__(self, opt, hyp, run_id=None, job_type="Training", **experiment_kwargs) -> None: self.job_type = job_type self.opt = opt self.hyp = hyp @@ -87,57 +85,58 @@ def __init__(self, opt, hyp, run_id=None, job_type='Training', **experiment_kwar # Default parameters to pass to Experiment objects self.default_experiment_kwargs = { - 'log_code': False, - 'log_env_gpu': True, - 'log_env_cpu': True, - 'project_name': COMET_PROJECT_NAME, } + "log_code": False, + "log_env_gpu": True, + "log_env_cpu": True, + "project_name": COMET_PROJECT_NAME, + } self.default_experiment_kwargs.update(experiment_kwargs) self.experiment = self._get_experiment(self.comet_mode, run_id) self.experiment.set_name(self.opt.name) self.data_dict = self.check_dataset(self.opt.data) - self.class_names = self.data_dict['names'] - self.num_classes = self.data_dict['nc'] + self.class_names = self.data_dict["names"] + self.num_classes = self.data_dict["nc"] self.logged_images_count = 0 self.max_images = COMET_MAX_IMAGE_UPLOADS if run_id is None: - self.experiment.log_other('Created from', 'YOLOv3') + self.experiment.log_other("Created from", "YOLOv3") if not isinstance(self.experiment, comet_ml.OfflineExperiment): - workspace, project_name, experiment_id = self.experiment.url.split('/')[-3:] + workspace, project_name, experiment_id = self.experiment.url.split("/")[-3:] self.experiment.log_other( - 'Run Path', - f'{workspace}/{project_name}/{experiment_id}', + "Run Path", + f"{workspace}/{project_name}/{experiment_id}", ) self.log_parameters(vars(opt)) self.log_parameters(self.opt.hyp) self.log_asset_data( self.opt.hyp, - name='hyperparameters.json', - metadata={'type': 'hyp-config-file'}, + name="hyperparameters.json", + metadata={"type": "hyp-config-file"}, ) self.log_asset( - f'{self.opt.save_dir}/opt.yaml', - metadata={'type': 'opt-config-file'}, + f"{self.opt.save_dir}/opt.yaml", + metadata={"type": "opt-config-file"}, ) self.comet_log_confusion_matrix = COMET_LOG_CONFUSION_MATRIX - if hasattr(self.opt, 'conf_thres'): + if hasattr(self.opt, "conf_thres"): self.conf_thres = self.opt.conf_thres else: self.conf_thres = CONF_THRES - if hasattr(self.opt, 'iou_thres'): + if hasattr(self.opt, "iou_thres"): self.iou_thres = self.opt.iou_thres else: self.iou_thres = IOU_THRES - self.log_parameters({'val_iou_threshold': self.iou_thres, 'val_conf_threshold': self.conf_thres}) + self.log_parameters({"val_iou_threshold": self.iou_thres, "val_conf_threshold": self.conf_thres}) self.comet_log_predictions = COMET_LOG_PREDICTIONS if self.opt.bbox_interval == -1: - self.comet_log_prediction_interval = (1 if self.opt.epochs < 10 else self.opt.epochs // 10) + self.comet_log_prediction_interval = 1 if self.opt.epochs < 10 else self.opt.epochs // 10 else: self.comet_log_prediction_interval = self.opt.bbox_interval @@ -147,30 +146,35 @@ def __init__(self, opt, hyp, run_id=None, job_type='Training', **experiment_kwar self.comet_log_per_class_metrics = COMET_LOG_PER_CLASS_METRICS - self.experiment.log_others({ - 'comet_mode': COMET_MODE, - 'comet_max_image_uploads': COMET_MAX_IMAGE_UPLOADS, - 'comet_log_per_class_metrics': COMET_LOG_PER_CLASS_METRICS, - 'comet_log_batch_metrics': COMET_LOG_BATCH_METRICS, - 'comet_log_confusion_matrix': COMET_LOG_CONFUSION_MATRIX, - 'comet_model_name': COMET_MODEL_NAME, }) + self.experiment.log_others( + { + "comet_mode": COMET_MODE, + "comet_max_image_uploads": COMET_MAX_IMAGE_UPLOADS, + "comet_log_per_class_metrics": COMET_LOG_PER_CLASS_METRICS, + "comet_log_batch_metrics": COMET_LOG_BATCH_METRICS, + "comet_log_confusion_matrix": COMET_LOG_CONFUSION_MATRIX, + "comet_model_name": COMET_MODEL_NAME, + } + ) # Check if running the Experiment with the Comet Optimizer - if hasattr(self.opt, 'comet_optimizer_id'): - self.experiment.log_other('optimizer_id', self.opt.comet_optimizer_id) - self.experiment.log_other('optimizer_objective', self.opt.comet_optimizer_objective) - self.experiment.log_other('optimizer_metric', self.opt.comet_optimizer_metric) - self.experiment.log_other('optimizer_parameters', json.dumps(self.hyp)) + if hasattr(self.opt, "comet_optimizer_id"): + self.experiment.log_other("optimizer_id", self.opt.comet_optimizer_id) + self.experiment.log_other("optimizer_objective", self.opt.comet_optimizer_objective) + self.experiment.log_other("optimizer_metric", self.opt.comet_optimizer_metric) + self.experiment.log_other("optimizer_parameters", json.dumps(self.hyp)) def _get_experiment(self, mode, experiment_id=None): - if mode == 'offline': + if mode == "offline": if experiment_id is not None: return comet_ml.ExistingOfflineExperiment( previous_experiment=experiment_id, **self.default_experiment_kwargs, ) - return comet_ml.OfflineExperiment(**self.default_experiment_kwargs, ) + return comet_ml.OfflineExperiment( + **self.default_experiment_kwargs, + ) else: try: @@ -183,11 +187,13 @@ def _get_experiment(self, mode, experiment_id=None): return comet_ml.Experiment(**self.default_experiment_kwargs) except ValueError: - logger.warning('COMET WARNING: ' - 'Comet credentials have not been set. ' - 'Comet will default to offline logging. ' - 'Please set your credentials to enable online logging.') - return self._get_experiment('offline', experiment_id) + logger.warning( + "COMET WARNING: " + "Comet credentials have not been set. " + "Comet will default to offline logging. " + "Please set your credentials to enable online logging." + ) + return self._get_experiment("offline", experiment_id) return @@ -211,12 +217,13 @@ def log_model(self, path, opt, epoch, fitness_score, best_model=False): return model_metadata = { - 'fitness_score': fitness_score[-1], - 'epochs_trained': epoch + 1, - 'save_period': opt.save_period, - 'total_epochs': opt.epochs, } + "fitness_score": fitness_score[-1], + "epochs_trained": epoch + 1, + "save_period": opt.save_period, + "total_epochs": opt.epochs, + } - model_files = glob.glob(f'{path}/*.pt') + model_files = glob.glob(f"{path}/*.pt") for model_path in model_files: name = Path(model_path).name @@ -232,14 +239,14 @@ def check_dataset(self, data_file): with open(data_file) as f: data_config = yaml.safe_load(f) - path = data_config.get('path') + path = data_config.get("path") if path and path.startswith(COMET_PREFIX): - path = data_config['path'].replace(COMET_PREFIX, '') + path = data_config["path"].replace(COMET_PREFIX, "") data_dict = self.download_dataset_artifact(path) return data_dict - self.log_asset(self.opt.data, metadata={'type': 'data-config-file'}) + self.log_asset(self.opt.data, metadata={"type": "data-config-file"}) return check_dataset(data_file) @@ -255,8 +262,8 @@ def log_predictions(self, image, labelsn, path, shape, predn): filtered_detections = detections[mask] filtered_labels = labelsn[mask] - image_id = path.split('/')[-1].split('.')[0] - image_name = f'{image_id}_curr_epoch_{self.experiment.curr_epoch}' + image_id = path.split("/")[-1].split(".")[0] + image_name = f"{image_id}_curr_epoch_{self.experiment.curr_epoch}" if image_name not in self.logged_image_names: native_scale_image = PIL.Image.open(path) self.log_image(native_scale_image, name=image_name) @@ -264,23 +271,21 @@ def log_predictions(self, image, labelsn, path, shape, predn): metadata = [] for cls, *xyxy in filtered_labels.tolist(): - metadata.append({ - 'label': f'{self.class_names[int(cls)]}-gt', - 'score': 100, - 'box': { - 'x': xyxy[0], - 'y': xyxy[1], - 'x2': xyxy[2], - 'y2': xyxy[3]}, }) + metadata.append( + { + "label": f"{self.class_names[int(cls)]}-gt", + "score": 100, + "box": {"x": xyxy[0], "y": xyxy[1], "x2": xyxy[2], "y2": xyxy[3]}, + } + ) for *xyxy, conf, cls in filtered_detections.tolist(): - metadata.append({ - 'label': f'{self.class_names[int(cls)]}', - 'score': conf * 100, - 'box': { - 'x': xyxy[0], - 'y': xyxy[1], - 'x2': xyxy[2], - 'y2': xyxy[3]}, }) + metadata.append( + { + "label": f"{self.class_names[int(cls)]}", + "score": conf * 100, + "box": {"x": xyxy[0], "y": xyxy[1], "x2": xyxy[2], "y2": xyxy[3]}, + } + ) self.metadata_dict[image_name] = metadata self.logged_images_count += 1 @@ -307,7 +312,7 @@ def preprocess_prediction(self, image, labels, shape, pred): return predn, labelsn def add_assets_to_artifact(self, artifact, path, asset_path, split): - img_paths = sorted(glob.glob(f'{asset_path}/*')) + img_paths = sorted(glob.glob(f"{asset_path}/*")) label_paths = img2label_paths(img_paths) for image_file, label_file in zip(img_paths, label_paths): @@ -317,33 +322,33 @@ def add_assets_to_artifact(self, artifact, path, asset_path, split): artifact.add( image_file, logical_path=image_logical_path, - metadata={'split': split}, + metadata={"split": split}, ) artifact.add( label_file, logical_path=label_logical_path, - metadata={'split': split}, + metadata={"split": split}, ) except ValueError as e: - logger.error('COMET ERROR: Error adding file to Artifact. Skipping file.') - logger.error(f'COMET ERROR: {e}') + logger.error("COMET ERROR: Error adding file to Artifact. Skipping file.") + logger.error(f"COMET ERROR: {e}") continue return artifact def upload_dataset_artifact(self): - dataset_name = self.data_dict.get('dataset_name', 'yolov5-dataset') - path = str((ROOT / Path(self.data_dict['path'])).resolve()) + dataset_name = self.data_dict.get("dataset_name", "yolov5-dataset") + path = str((ROOT / Path(self.data_dict["path"])).resolve()) metadata = self.data_dict.copy() - for key in ['train', 'val', 'test']: + for key in ["train", "val", "test"]: split_path = metadata.get(key) if split_path is not None: - metadata[key] = split_path.replace(path, '') + metadata[key] = split_path.replace(path, "") - artifact = comet_ml.Artifact(name=dataset_name, artifact_type='dataset', metadata=metadata) + artifact = comet_ml.Artifact(name=dataset_name, artifact_type="dataset", metadata=metadata) for key in metadata.keys(): - if key in ['train', 'val', 'test']: + if key in ["train", "val", "test"]: if isinstance(self.upload_dataset, str) and (key != self.upload_dataset): continue @@ -362,26 +367,27 @@ def download_dataset_artifact(self, artifact_path): metadata = logged_artifact.metadata data_dict = metadata.copy() - data_dict['path'] = artifact_save_dir + data_dict["path"] = artifact_save_dir - metadata_names = metadata.get('names') + metadata_names = metadata.get("names") if isinstance(metadata_names, dict): - data_dict['names'] = {int(k): v for k, v in metadata.get('names').items()} + data_dict["names"] = {int(k): v for k, v in metadata.get("names").items()} elif isinstance(metadata_names, list): - data_dict['names'] = {int(k): v for k, v in zip(range(len(metadata_names)), metadata_names)} + data_dict["names"] = {int(k): v for k, v in zip(range(len(metadata_names)), metadata_names)} else: raise "Invalid 'names' field in dataset yaml file. Please use a list or dictionary" return self.update_data_paths(data_dict) def update_data_paths(self, data_dict): - path = data_dict.get('path', '') + path = data_dict.get("path", "") - for split in ['train', 'val', 'test']: + for split in ["train", "val", "test"]: if data_dict.get(split): split_path = data_dict.get(split) - data_dict[split] = (f'{path}/{split_path}' if isinstance(split, str) else [ - f'{path}/{x}' for x in split_path]) + data_dict[split] = ( + f"{path}/{split_path}" if isinstance(split, str) else [f"{path}/{x}" for x in split_path] + ) return data_dict @@ -422,11 +428,11 @@ def on_train_batch_end(self, log_dict, step): def on_train_end(self, files, save_dir, last, best, epoch, results): if self.comet_log_predictions: curr_epoch = self.experiment.curr_epoch - self.experiment.log_asset_data(self.metadata_dict, 'image-metadata.json', epoch=curr_epoch) + self.experiment.log_asset_data(self.metadata_dict, "image-metadata.json", epoch=curr_epoch) for f in files: - self.log_asset(f, metadata={'epoch': epoch}) - self.log_asset(f'{save_dir}/results.csv', metadata={'epoch': epoch}) + self.log_asset(f, metadata={"epoch": epoch}) + self.log_asset(f"{save_dir}/results.csv", metadata={"epoch": epoch}) if not self.opt.evolve: model_path = str(best if best.exists() else last) @@ -440,9 +446,9 @@ def on_train_end(self, files, save_dir, last, best, epoch, results): ) # Check if running Experiment with Comet Optimizer - if hasattr(self.opt, 'comet_optimizer_id'): + if hasattr(self.opt, "comet_optimizer_id"): metric = results.get(self.opt.comet_optimizer_metric) - self.experiment.log_other('optimizer_metric_value', metric) + self.experiment.log_other("optimizer_metric_value", metric) self.finish_run() @@ -477,21 +483,22 @@ def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) class_name = self.class_names[c] self.experiment.log_metrics( { - 'mAP@.5': ap50[i], - 'mAP@.5:.95': ap[i], - 'precision': p[i], - 'recall': r[i], - 'f1': f1[i], - 'true_positives': tp[i], - 'false_positives': fp[i], - 'support': nt[c], }, + "mAP@.5": ap50[i], + "mAP@.5:.95": ap[i], + "precision": p[i], + "recall": r[i], + "f1": f1[i], + "true_positives": tp[i], + "false_positives": fp[i], + "support": nt[c], + }, prefix=class_name, ) if self.comet_log_confusion_matrix: epoch = self.experiment.curr_epoch class_names = list(self.class_names.values()) - class_names.append('background') + class_names.append("background") num_classes = len(class_names) self.experiment.log_confusion_matrix( @@ -499,9 +506,9 @@ def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) max_categories=num_classes, labels=class_names, epoch=epoch, - column_label='Actual Category', - row_label='Predicted Category', - file_name=f'confusion-matrix-epoch-{epoch}.json', + column_label="Actual Category", + row_label="Predicted Category", + file_name=f"confusion-matrix-epoch-{epoch}.json", ) def on_fit_epoch_end(self, result, epoch): diff --git a/utils/loggers/comet/comet_utils.py b/utils/loggers/comet/comet_utils.py index dbe7539675..99477f85d9 100644 --- a/utils/loggers/comet/comet_utils.py +++ b/utils/loggers/comet/comet_utils.py @@ -11,28 +11,28 @@ logger = logging.getLogger(__name__) -COMET_PREFIX = 'comet://' -COMET_MODEL_NAME = os.getenv('COMET_MODEL_NAME', 'yolov5') -COMET_DEFAULT_CHECKPOINT_FILENAME = os.getenv('COMET_DEFAULT_CHECKPOINT_FILENAME', 'last.pt') +COMET_PREFIX = "comet://" +COMET_MODEL_NAME = os.getenv("COMET_MODEL_NAME", "yolov5") +COMET_DEFAULT_CHECKPOINT_FILENAME = os.getenv("COMET_DEFAULT_CHECKPOINT_FILENAME", "last.pt") def download_model_checkpoint(opt, experiment): - model_dir = f'{opt.project}/{experiment.name}' + model_dir = f"{opt.project}/{experiment.name}" os.makedirs(model_dir, exist_ok=True) model_name = COMET_MODEL_NAME model_asset_list = experiment.get_model_asset_list(model_name) if len(model_asset_list) == 0: - logger.error(f'COMET ERROR: No checkpoints found for model name : {model_name}') + logger.error(f"COMET ERROR: No checkpoints found for model name : {model_name}") return model_asset_list = sorted( model_asset_list, - key=lambda x: x['step'], + key=lambda x: x["step"], reverse=True, ) - logged_checkpoint_map = {asset['fileName']: asset['assetId'] for asset in model_asset_list} + logged_checkpoint_map = {asset["fileName"]: asset["assetId"] for asset in model_asset_list} resource_url = urlparse(opt.weights) checkpoint_filename = resource_url.query @@ -44,28 +44,28 @@ def download_model_checkpoint(opt, experiment): checkpoint_filename = COMET_DEFAULT_CHECKPOINT_FILENAME if asset_id is None: - logger.error(f'COMET ERROR: Checkpoint {checkpoint_filename} not found in the given Experiment') + logger.error(f"COMET ERROR: Checkpoint {checkpoint_filename} not found in the given Experiment") return try: - logger.info(f'COMET INFO: Downloading checkpoint {checkpoint_filename}') + logger.info(f"COMET INFO: Downloading checkpoint {checkpoint_filename}") asset_filename = checkpoint_filename - model_binary = experiment.get_asset(asset_id, return_type='binary', stream=False) - model_download_path = f'{model_dir}/{asset_filename}' - with open(model_download_path, 'wb') as f: + model_binary = experiment.get_asset(asset_id, return_type="binary", stream=False) + model_download_path = f"{model_dir}/{asset_filename}" + with open(model_download_path, "wb") as f: f.write(model_binary) opt.weights = model_download_path except Exception as e: - logger.warning('COMET WARNING: Unable to download checkpoint from Comet') + logger.warning("COMET WARNING: Unable to download checkpoint from Comet") logger.exception(e) def set_opt_parameters(opt, experiment): - """Update the opts Namespace with parameters - from Comet's ExistingExperiment when resuming a run + """ + Update the opts Namespace with parameters from Comet's ExistingExperiment when resuming a run. Args: opt (argparse.Namespace): Namespace of command line options @@ -75,9 +75,9 @@ def set_opt_parameters(opt, experiment): resume_string = opt.resume for asset in asset_list: - if asset['fileName'] == 'opt.yaml': - asset_id = asset['assetId'] - asset_binary = experiment.get_asset(asset_id, return_type='binary', stream=False) + if asset["fileName"] == "opt.yaml": + asset_id = asset["assetId"] + asset_binary = experiment.get_asset(asset_id, return_type="binary", stream=False) opt_dict = yaml.safe_load(asset_binary) for key, value in opt_dict.items(): setattr(opt, key, value) @@ -85,18 +85,18 @@ def set_opt_parameters(opt, experiment): # Save hyperparameters to YAML file # Necessary to pass checks in training script - save_dir = f'{opt.project}/{experiment.name}' + save_dir = f"{opt.project}/{experiment.name}" os.makedirs(save_dir, exist_ok=True) - hyp_yaml_path = f'{save_dir}/hyp.yaml' - with open(hyp_yaml_path, 'w') as f: + hyp_yaml_path = f"{save_dir}/hyp.yaml" + with open(hyp_yaml_path, "w") as f: yaml.dump(opt.hyp, f) opt.hyp = hyp_yaml_path def check_comet_weights(opt): - """Downloads model weights from Comet and updates the - weights path to point to saved weights location + """ + Downloads model weights from Comet and updates the weights path to point to saved weights location. Args: opt (argparse.Namespace): Command Line arguments passed @@ -113,7 +113,7 @@ def check_comet_weights(opt): if opt.weights.startswith(COMET_PREFIX): api = comet_ml.API() resource = urlparse(opt.weights) - experiment_path = f'{resource.netloc}{resource.path}' + experiment_path = f"{resource.netloc}{resource.path}" experiment = api.get(experiment_path) download_model_checkpoint(opt, experiment) return True @@ -122,8 +122,8 @@ def check_comet_weights(opt): def check_comet_resume(opt): - """Restores run parameters to its original state based on the model checkpoint - and logged Experiment parameters. + """ + Restores run parameters to its original state based on the model checkpoint and logged Experiment parameters. Args: opt (argparse.Namespace): Command Line arguments passed @@ -140,7 +140,7 @@ def check_comet_resume(opt): if opt.resume.startswith(COMET_PREFIX): api = comet_ml.API() resource = urlparse(opt.resume) - experiment_path = f'{resource.netloc}{resource.path}' + experiment_path = f"{resource.netloc}{resource.path}" experiment = api.get(experiment_path) set_opt_parameters(opt, experiment) download_model_checkpoint(opt, experiment) diff --git a/utils/loggers/comet/hpo.py b/utils/loggers/comet/hpo.py index daf21bc5e2..943bd47e00 100644 --- a/utils/loggers/comet/hpo.py +++ b/utils/loggers/comet/hpo.py @@ -21,77 +21,79 @@ # Project Configuration config = comet_ml.config.get_config() -COMET_PROJECT_NAME = config.get_string(os.getenv('COMET_PROJECT_NAME'), 'comet.project_name', default='yolov5') +COMET_PROJECT_NAME = config.get_string(os.getenv("COMET_PROJECT_NAME"), "comet.project_name", default="yolov5") def get_args(known=False): parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default=ROOT / 'yolov3-tiny.pt', help='initial weights path') - parser.add_argument('--cfg', type=str, default='', help='model.yaml path') - parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') - parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path') - parser.add_argument('--epochs', type=int, default=300, help='total training epochs') - parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') - parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') - parser.add_argument('--rect', action='store_true', help='rectangular training') - parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') - parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') - parser.add_argument('--noval', action='store_true', help='only validate final epoch') - parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') - parser.add_argument('--noplots', action='store_true', help='save no plot files') - parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') - parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') - parser.add_argument('--cache', type=str, nargs='?', const='ram', help='--cache images in "ram" (default) or "disk"') - parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') - parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') - parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer') - parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') - parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') - parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name') - parser.add_argument('--name', default='exp', help='save to project/name') - parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') - parser.add_argument('--quad', action='store_true', help='quad dataloader') - parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') - parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') - parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') - parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') - parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') - parser.add_argument('--seed', type=int, default=0, help='Global training seed') - parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + parser.add_argument("--weights", type=str, default=ROOT / "yolov3-tiny.pt", help="initial weights path") + parser.add_argument("--cfg", type=str, default="", help="model.yaml path") + parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="dataset.yaml path") + parser.add_argument("--hyp", type=str, default=ROOT / "data/hyps/hyp.scratch-low.yaml", help="hyperparameters path") + parser.add_argument("--epochs", type=int, default=300, help="total training epochs") + parser.add_argument("--batch-size", type=int, default=16, help="total batch size for all GPUs, -1 for autobatch") + parser.add_argument("--imgsz", "--img", "--img-size", type=int, default=640, help="train, val image size (pixels)") + parser.add_argument("--rect", action="store_true", help="rectangular training") + parser.add_argument("--resume", nargs="?", const=True, default=False, help="resume most recent training") + parser.add_argument("--nosave", action="store_true", help="only save final checkpoint") + parser.add_argument("--noval", action="store_true", help="only validate final epoch") + parser.add_argument("--noautoanchor", action="store_true", help="disable AutoAnchor") + parser.add_argument("--noplots", action="store_true", help="save no plot files") + parser.add_argument("--evolve", type=int, nargs="?", const=300, help="evolve hyperparameters for x generations") + parser.add_argument("--bucket", type=str, default="", help="gsutil bucket") + parser.add_argument("--cache", type=str, nargs="?", const="ram", help='--cache images in "ram" (default) or "disk"') + parser.add_argument("--image-weights", action="store_true", help="use weighted image selection for training") + parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu") + parser.add_argument("--multi-scale", action="store_true", help="vary img-size +/- 50%%") + parser.add_argument("--single-cls", action="store_true", help="train multi-class data as single-class") + parser.add_argument("--optimizer", type=str, choices=["SGD", "Adam", "AdamW"], default="SGD", help="optimizer") + parser.add_argument("--sync-bn", action="store_true", help="use SyncBatchNorm, only available in DDP mode") + parser.add_argument("--workers", type=int, default=8, help="max dataloader workers (per RANK in DDP mode)") + parser.add_argument("--project", default=ROOT / "runs/train", help="save to project/name") + parser.add_argument("--name", default="exp", help="save to project/name") + parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment") + parser.add_argument("--quad", action="store_true", help="quad dataloader") + parser.add_argument("--cos-lr", action="store_true", help="cosine LR scheduler") + parser.add_argument("--label-smoothing", type=float, default=0.0, help="Label smoothing epsilon") + parser.add_argument("--patience", type=int, default=100, help="EarlyStopping patience (epochs without improvement)") + parser.add_argument("--freeze", nargs="+", type=int, default=[0], help="Freeze layers: backbone=10, first3=0 1 2") + parser.add_argument("--save-period", type=int, default=-1, help="Save checkpoint every x epochs (disabled if < 1)") + parser.add_argument("--seed", type=int, default=0, help="Global training seed") + parser.add_argument("--local_rank", type=int, default=-1, help="Automatic DDP Multi-GPU argument, do not modify") # Weights & Biases arguments - parser.add_argument('--entity', default=None, help='W&B: Entity') - parser.add_argument('--upload_dataset', nargs='?', const=True, default=False, help='W&B: Upload data, "val" option') - parser.add_argument('--bbox_interval', type=int, default=-1, help='W&B: Set bounding-box image logging interval') - parser.add_argument('--artifact_alias', type=str, default='latest', help='W&B: Version of dataset artifact to use') + parser.add_argument("--entity", default=None, help="W&B: Entity") + parser.add_argument("--upload_dataset", nargs="?", const=True, default=False, help='W&B: Upload data, "val" option') + parser.add_argument("--bbox_interval", type=int, default=-1, help="W&B: Set bounding-box image logging interval") + parser.add_argument("--artifact_alias", type=str, default="latest", help="W&B: Version of dataset artifact to use") # Comet Arguments - parser.add_argument('--comet_optimizer_config', type=str, help='Comet: Path to a Comet Optimizer Config File.') - parser.add_argument('--comet_optimizer_id', type=str, help='Comet: ID of the Comet Optimizer sweep.') - parser.add_argument('--comet_optimizer_objective', type=str, help="Comet: Set to 'minimize' or 'maximize'.") - parser.add_argument('--comet_optimizer_metric', type=str, help='Comet: Metric to Optimize.') - parser.add_argument('--comet_optimizer_workers', - type=int, - default=1, - help='Comet: Number of Parallel Workers to use with the Comet Optimizer.') + parser.add_argument("--comet_optimizer_config", type=str, help="Comet: Path to a Comet Optimizer Config File.") + parser.add_argument("--comet_optimizer_id", type=str, help="Comet: ID of the Comet Optimizer sweep.") + parser.add_argument("--comet_optimizer_objective", type=str, help="Comet: Set to 'minimize' or 'maximize'.") + parser.add_argument("--comet_optimizer_metric", type=str, help="Comet: Metric to Optimize.") + parser.add_argument( + "--comet_optimizer_workers", + type=int, + default=1, + help="Comet: Number of Parallel Workers to use with the Comet Optimizer.", + ) return parser.parse_known_args()[0] if known else parser.parse_args() def run(parameters, opt): - hyp_dict = {k: v for k, v in parameters.items() if k not in ['epochs', 'batch_size']} + hyp_dict = {k: v for k, v in parameters.items() if k not in ["epochs", "batch_size"]} opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok or opt.evolve)) - opt.batch_size = parameters.get('batch_size') - opt.epochs = parameters.get('epochs') + opt.batch_size = parameters.get("batch_size") + opt.epochs = parameters.get("epochs") device = select_device(opt.device, batch_size=opt.batch_size) train(hyp_dict, opt, device, callbacks=Callbacks()) -if __name__ == '__main__': +if __name__ == "__main__": opt = get_args(known=True) opt.weights = str(opt.weights) @@ -99,7 +101,7 @@ def run(parameters, opt): opt.data = str(opt.data) opt.project = str(opt.project) - optimizer_id = os.getenv('COMET_OPTIMIZER_ID') + optimizer_id = os.getenv("COMET_OPTIMIZER_ID") if optimizer_id is None: with open(opt.comet_optimizer_config) as f: optimizer_config = json.load(f) @@ -110,9 +112,9 @@ def run(parameters, opt): opt.comet_optimizer_id = optimizer.id status = optimizer.status() - opt.comet_optimizer_objective = status['spec']['objective'] - opt.comet_optimizer_metric = status['spec']['metric'] + opt.comet_optimizer_objective = status["spec"]["objective"] + opt.comet_optimizer_metric = status["spec"]["metric"] - logger.info('COMET INFO: Starting Hyperparameter Sweep') + logger.info("COMET INFO: Starting Hyperparameter Sweep") for parameter in optimizer.get_parameters(): - run(parameter['parameters'], opt) + run(parameter["parameters"], opt) diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py index c69e8f3ae7..edbb0b5e2b 100644 --- a/utils/loggers/wandb/wandb_utils.py +++ b/utils/loggers/wandb/wandb_utils.py @@ -15,34 +15,35 @@ ROOT = FILE.parents[3] # YOLOv3 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH -RANK = int(os.getenv('RANK', -1)) -DEPRECATION_WARNING = f"{colorstr('wandb')}: WARNING ⚠️ wandb is deprecated and will be removed in a future release. " \ - f'See supported integrations at https://github.com/ultralytics/yolov5#integrations.' +RANK = int(os.getenv("RANK", -1)) +DEPRECATION_WARNING = ( + f"{colorstr('wandb')}: WARNING ⚠️ wandb is deprecated and will be removed in a future release. " + f'See supported integrations at https://github.com/ultralytics/yolov5#integrations.' +) try: import wandb - assert hasattr(wandb, '__version__') # verify package import not local dir + assert hasattr(wandb, "__version__") # verify package import not local dir LOGGER.warning(DEPRECATION_WARNING) except (ImportError, AssertionError): wandb = None -class WandbLogger(): - """Log training runs, datasets, models, and predictions to Weights & Biases. +class WandbLogger: + """ + Log training runs, datasets, models, and predictions to Weights & Biases. - This logger sends information to W&B at wandb.ai. By default, this information - includes hyperparameters, system configuration and metrics, model metrics, - and basic data metrics and analyses. + This logger sends information to W&B at wandb.ai. By default, this information includes hyperparameters, system + configuration and metrics, model metrics, and basic data metrics and analyses. - By providing additional command line arguments to train.py, datasets, - models and predictions can also be logged. + By providing additional command line arguments to train.py, datasets, models and predictions can also be logged. For more on how this logger is used, see the Weights & Biases documentation: https://docs.wandb.com/guides/integrations/yolov5 """ - def __init__(self, opt, run_id=None, job_type='Training'): + def __init__(self, opt, run_id=None, job_type="Training"): """ - Initialize WandbLogger instance - Upload dataset if opt.upload_dataset is True @@ -53,7 +54,7 @@ def __init__(self, opt, run_id=None, job_type='Training'): run_id (str) -- Run ID of W&B run to be resumed job_type (str) -- To set the job_type for this run - """ + """ # Pre-training routine -- self.job_type = job_type self.wandb, self.wandb_run = wandb, wandb.run if wandb else None @@ -64,17 +65,23 @@ def __init__(self, opt, run_id=None, job_type='Training'): self.max_imgs_to_log = 16 self.data_dict = None if self.wandb: - self.wandb_run = wandb.init(config=opt, - resume='allow', - project='YOLOv3' if opt.project == 'runs/train' else Path(opt.project).stem, - entity=opt.entity, - name=opt.name if opt.name != 'exp' else None, - job_type=job_type, - id=run_id, - allow_val_change=True) if not wandb.run else wandb.run + self.wandb_run = ( + wandb.init( + config=opt, + resume="allow", + project="YOLOv3" if opt.project == "runs/train" else Path(opt.project).stem, + entity=opt.entity, + name=opt.name if opt.name != "exp" else None, + job_type=job_type, + id=run_id, + allow_val_change=True, + ) + if not wandb.run + else wandb.run + ) if self.wandb_run: - if self.job_type == 'Training': + if self.job_type == "Training": if isinstance(opt.data, dict): # This means another dataset manager has already processed the dataset info (e.g. ClearML) # and they will have stored the already processed dict in opt.data @@ -97,11 +104,17 @@ def setup_training(self, opt): if isinstance(opt.resume, str): model_dir, _ = self.download_model_artifact(opt) if model_dir: - self.weights = Path(model_dir) / 'last.pt' + self.weights = Path(model_dir) / "last.pt" config = self.wandb_run.config - opt.weights, opt.save_period, opt.batch_size, opt.bbox_interval, opt.epochs, opt.hyp, opt.imgsz = str( - self.weights), config.save_period, config.batch_size, config.bbox_interval, config.epochs, \ - config.hyp, config.imgsz + opt.weights, opt.save_period, opt.batch_size, opt.bbox_interval, opt.epochs, opt.hyp, opt.imgsz = ( + str(self.weights), + config.save_period, + config.batch_size, + config.bbox_interval, + config.epochs, + config.hyp, + config.imgsz, + ) if opt.bbox_interval == -1: self.bbox_interval = opt.bbox_interval = (opt.epochs // 10) if opt.epochs > 10 else 1 @@ -110,7 +123,7 @@ def setup_training(self, opt): def log_model(self, path, opt, epoch, fitness_score, best_model=False): """ - Log the model checkpoint as W&B artifact + Log the model checkpoint as W&B artifact. arguments: path (Path) -- Path of directory containing the checkpoints @@ -119,26 +132,30 @@ def log_model(self, path, opt, epoch, fitness_score, best_model=False): fitness_score (float) -- fitness score for current epoch best_model (boolean) -- Boolean representing if the current checkpoint is the best yet. """ - model_artifact = wandb.Artifact('run_' + wandb.run.id + '_model', - type='model', - metadata={ - 'original_url': str(path), - 'epochs_trained': epoch + 1, - 'save period': opt.save_period, - 'project': opt.project, - 'total_epochs': opt.epochs, - 'fitness_score': fitness_score}) - model_artifact.add_file(str(path / 'last.pt'), name='last.pt') - wandb.log_artifact(model_artifact, - aliases=['latest', 'last', 'epoch ' + str(self.current_epoch), 'best' if best_model else '']) - LOGGER.info(f'Saving model artifact on epoch {epoch + 1}') + model_artifact = wandb.Artifact( + "run_" + wandb.run.id + "_model", + type="model", + metadata={ + "original_url": str(path), + "epochs_trained": epoch + 1, + "save period": opt.save_period, + "project": opt.project, + "total_epochs": opt.epochs, + "fitness_score": fitness_score, + }, + ) + model_artifact.add_file(str(path / "last.pt"), name="last.pt") + wandb.log_artifact( + model_artifact, aliases=["latest", "last", "epoch " + str(self.current_epoch), "best" if best_model else ""] + ) + LOGGER.info(f"Saving model artifact on epoch {epoch + 1}") def val_one_image(self, pred, predn, path, names, im): pass def log(self, log_dict): """ - save the metrics to the logging dictionary + Save the metrics to the logging dictionary. arguments: log_dict (Dict) -- metrics/media to be logged in current step @@ -149,7 +166,7 @@ def log(self, log_dict): def end_epoch(self): """ - commit the log_dict, model artifacts and Tables to W&B and flush the log_dict. + Commit the log_dict, model artifacts and Tables to W&B and flush the log_dict. arguments: best_result (boolean): Boolean representing if the result of this evaluation is best or not @@ -160,16 +177,14 @@ def end_epoch(self): wandb.log(self.log_dict) except BaseException as e: LOGGER.info( - f'An error occurred in wandb logger. The training will proceed without interruption. More info\n{e}' + f"An error occurred in wandb logger. The training will proceed without interruption. More info\n{e}" ) self.wandb_run.finish() self.wandb_run = None self.log_dict = {} def finish_run(self): - """ - Log metrics if any and finish the current W&B run - """ + """Log metrics if any and finish the current W&B run.""" if self.wandb_run: if self.log_dict: with all_logging_disabled(): @@ -180,7 +195,7 @@ def finish_run(self): @contextmanager def all_logging_disabled(highest_level=logging.CRITICAL): - """ source - https://gist.github.com/simon-weber/7853144 + """source - https://gist.github.com/simon-weber/7853144 A context manager that will prevent any logging messages triggered during the body from being processed. :param highest_level: the maximum logging level in use. This would only need to be changed if a custom level greater than CRITICAL is defined. diff --git a/utils/loss.py b/utils/loss.py index 7fe6ae445b..d533246e60 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Loss functions -""" +"""Loss functions.""" import torch import torch.nn as nn @@ -19,7 +17,7 @@ class BCEBlurWithLogitsLoss(nn.Module): # BCEwithLogitLoss() with reduced missing label effects. def __init__(self, alpha=0.05): super().__init__() - self.loss_fcn = nn.BCEWithLogitsLoss(reduction='none') # must be nn.BCEWithLogitsLoss() + self.loss_fcn = nn.BCEWithLogitsLoss(reduction="none") # must be nn.BCEWithLogitsLoss() self.alpha = alpha def forward(self, pred, true): @@ -40,7 +38,7 @@ def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): self.gamma = gamma self.alpha = alpha self.reduction = loss_fcn.reduction - self.loss_fcn.reduction = 'none' # required to apply FL to each element + self.loss_fcn.reduction = "none" # required to apply FL to each element def forward(self, pred, true): loss = self.loss_fcn(pred, true) @@ -54,9 +52,9 @@ def forward(self, pred, true): modulating_factor = (1.0 - p_t) ** self.gamma loss *= alpha_factor * modulating_factor - if self.reduction == 'mean': + if self.reduction == "mean": return loss.mean() - elif self.reduction == 'sum': + elif self.reduction == "sum": return loss.sum() else: # 'none' return loss @@ -70,7 +68,7 @@ def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): self.gamma = gamma self.alpha = alpha self.reduction = loss_fcn.reduction - self.loss_fcn.reduction = 'none' # required to apply FL to each element + self.loss_fcn.reduction = "none" # required to apply FL to each element def forward(self, pred, true): loss = self.loss_fcn(pred, true) @@ -80,9 +78,9 @@ def forward(self, pred, true): modulating_factor = torch.abs(true - pred_prob) ** self.gamma loss *= alpha_factor * modulating_factor - if self.reduction == 'mean': + if self.reduction == "mean": return loss.mean() - elif self.reduction == 'sum': + elif self.reduction == "sum": return loss.sum() else: # 'none' return loss @@ -97,14 +95,14 @@ def __init__(self, model, autobalance=False): h = model.hyp # hyperparameters # Define criteria - BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device)) - BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device)) + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h["cls_pw"]], device=device)) + BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h["obj_pw"]], device=device)) # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 - self.cp, self.cn = smooth_BCE(eps=h.get('label_smoothing', 0.0)) # positive, negative BCE targets + self.cp, self.cn = smooth_BCE(eps=h.get("label_smoothing", 0.0)) # positive, negative BCE targets # Focal loss - g = h['fl_gamma'] # focal loss gamma + g = h["fl_gamma"] # focal loss gamma if g > 0: BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) @@ -167,9 +165,9 @@ def __call__(self, p, targets): # predictions, targets if self.autobalance: self.balance = [x / self.balance[self.ssi] for x in self.balance] - lbox *= self.hyp['box'] - lobj *= self.hyp['obj'] - lcls *= self.hyp['cls'] + lbox *= self.hyp["box"] + lobj *= self.hyp["obj"] + lcls *= self.hyp["cls"] bs = tobj.shape[0] # batch size return (lbox + lobj + lcls) * bs, torch.cat((lbox, lobj, lcls)).detach() @@ -183,16 +181,20 @@ def build_targets(self, p, targets): targets = torch.cat((targets.repeat(na, 1, 1), ai[..., None]), 2) # append anchor indices g = 0.5 # bias - off = torch.tensor( - [ - [0, 0], - [1, 0], - [0, 1], - [-1, 0], - [0, -1], # j,k,l,m - # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm - ], - device=self.device).float() * g # offsets + off = ( + torch.tensor( + [ + [0, 0], + [1, 0], + [0, 1], + [-1, 0], + [0, -1], # j,k,l,m + # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm + ], + device=self.device, + ).float() + * g + ) # offsets for i in range(self.nl): anchors, shape = self.anchors[i], p[i].shape @@ -203,7 +205,7 @@ def build_targets(self, p, targets): if nt: # Matches r = t[..., 4:6] / anchors[:, None] # wh ratio - j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t'] # compare + j = torch.max(r, 1 / r).max(2)[0] < self.hyp["anchor_t"] # compare # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2)) t = t[j] # filter diff --git a/utils/metrics.py b/utils/metrics.py index 56a15f45f7..626c290186 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Model validation metrics -""" +"""Model validation metrics.""" import math import warnings @@ -25,11 +23,13 @@ def smooth(y, f=0.05): nf = round(len(y) * f * 2) // 2 + 1 # number of filter elements (must be odd) p = np.ones(nf // 2) # ones padding yp = np.concatenate((p * y[0], y, p * y[-1]), 0) # y padded - return np.convolve(yp, np.ones(nf) / nf, mode='valid') # y-smoothed + return np.convolve(yp, np.ones(nf) / nf, mode="valid") # y-smoothed -def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names=(), eps=1e-16, prefix=''): - """ Compute the average precision, given the recall and precision curves. +def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir=".", names=(), eps=1e-16, prefix=""): + """ + Compute the average precision, given the recall and precision curves. + Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. # Arguments tp: True positives (nparray, nx1 or nx10). @@ -83,10 +83,10 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names names = [v for k, v in names.items() if k in unique_classes] # list: only classes that have data names = dict(enumerate(names)) # to dict if plot: - plot_pr_curve(px, py, ap, Path(save_dir) / f'{prefix}PR_curve.png', names) - plot_mc_curve(px, f1, Path(save_dir) / f'{prefix}F1_curve.png', names, ylabel='F1') - plot_mc_curve(px, p, Path(save_dir) / f'{prefix}P_curve.png', names, ylabel='Precision') - plot_mc_curve(px, r, Path(save_dir) / f'{prefix}R_curve.png', names, ylabel='Recall') + plot_pr_curve(px, py, ap, Path(save_dir) / f"{prefix}PR_curve.png", names) + plot_mc_curve(px, f1, Path(save_dir) / f"{prefix}F1_curve.png", names, ylabel="F1") + plot_mc_curve(px, p, Path(save_dir) / f"{prefix}P_curve.png", names, ylabel="Precision") + plot_mc_curve(px, r, Path(save_dir) / f"{prefix}R_curve.png", names, ylabel="Recall") i = smooth(f1.mean(0), 0.1).argmax() # max F1 index p, r, f1 = p[:, i], r[:, i], f1[:, i] @@ -96,7 +96,7 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names def compute_ap(recall, precision): - """ Compute the average precision, given the recall and precision curves + """Compute the average precision, given the recall and precision curves # Arguments recall: The recall curve (list) precision: The precision curve (list) @@ -112,8 +112,8 @@ def compute_ap(recall, precision): mpre = np.flip(np.maximum.accumulate(np.flip(mpre))) # Integrate area under curve - method = 'interp' # methods: 'continuous', 'interp' - if method == 'interp': + method = "interp" # methods: 'continuous', 'interp' + if method == "interp": x = np.linspace(0, 1, 101) # 101-point interp (COCO) ap = np.trapz(np.interp(x, mrec, mpre), x) # integrate else: # 'continuous' @@ -134,6 +134,7 @@ def __init__(self, nc, conf=0.25, iou_thres=0.45): def process_batch(self, detections, labels): """ Return intersection-over-union (Jaccard index) of boxes. + Both sets of boxes are expected to be in (x1, y1, x2, y2) format. Arguments: detections (Array[N, 6]), x1, y1, x2, y2, conf, class @@ -183,40 +184,41 @@ def tp_fp(self): # fn = self.matrix.sum(0) - tp # false negatives (missed detections) return tp[:-1], fp[:-1] # remove background class - @TryExcept('WARNING ⚠️ ConfusionMatrix plot failure') - def plot(self, normalize=True, save_dir='', names=()): + @TryExcept("WARNING ⚠️ ConfusionMatrix plot failure") + def plot(self, normalize=True, save_dir="", names=()): import seaborn as sn - array = self.matrix / ((self.matrix.sum(0).reshape(1, -1) + 1E-9) if normalize else 1) # normalize columns + array = self.matrix / ((self.matrix.sum(0).reshape(1, -1) + 1e-9) if normalize else 1) # normalize columns array[array < 0.005] = np.nan # don't annotate (would appear as 0.00) fig, ax = plt.subplots(1, 1, figsize=(12, 9), tight_layout=True) nc, nn = self.nc, len(names) # number of classes, names sn.set(font_scale=1.0 if nc < 50 else 0.8) # for label size labels = (0 < nn < 99) and (nn == nc) # apply names to ticklabels - ticklabels = (names + ['background']) if labels else 'auto' + ticklabels = (names + ["background"]) if labels else "auto" with warnings.catch_warnings(): - warnings.simplefilter('ignore') # suppress empty matrix RuntimeWarning: All-NaN slice encountered - sn.heatmap(array, - ax=ax, - annot=nc < 30, - annot_kws={ - 'size': 8}, - cmap='Blues', - fmt='.2f', - square=True, - vmin=0.0, - xticklabels=ticklabels, - yticklabels=ticklabels).set_facecolor((1, 1, 1)) - ax.set_xlabel('True') - ax.set_ylabel('Predicted') - ax.set_title('Confusion Matrix') - fig.savefig(Path(save_dir) / 'confusion_matrix.png', dpi=250) + warnings.simplefilter("ignore") # suppress empty matrix RuntimeWarning: All-NaN slice encountered + sn.heatmap( + array, + ax=ax, + annot=nc < 30, + annot_kws={"size": 8}, + cmap="Blues", + fmt=".2f", + square=True, + vmin=0.0, + xticklabels=ticklabels, + yticklabels=ticklabels, + ).set_facecolor((1, 1, 1)) + ax.set_xlabel("True") + ax.set_ylabel("Predicted") + ax.set_title("Confusion Matrix") + fig.savefig(Path(save_dir) / "confusion_matrix.png", dpi=250) plt.close(fig) def print(self): for i in range(self.nc + 1): - print(' '.join(map(str, self.matrix[i]))) + print(" ".join(map(str, self.matrix[i]))) def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7): @@ -235,8 +237,9 @@ def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7 w2, h2 = b2_x2 - b2_x1, (b2_y2 - b2_y1).clamp(eps) # Intersection area - inter = (b1_x2.minimum(b2_x2) - b1_x1.maximum(b2_x1)).clamp(0) * \ - (b1_y2.minimum(b2_y2) - b1_y1.maximum(b2_y1)).clamp(0) + inter = (b1_x2.minimum(b2_x2) - b1_x1.maximum(b2_x1)).clamp(0) * ( + b1_y2.minimum(b2_y2) - b1_y1.maximum(b2_y1) + ).clamp(0) # Union Area union = w1 * h1 + w2 * h2 - inter + eps @@ -247,10 +250,10 @@ def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7 cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1) # convex (smallest enclosing box) width ch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1) # convex height if CIoU or DIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1 - c2 = cw ** 2 + ch ** 2 + eps # convex diagonal squared + c2 = cw**2 + ch**2 + eps # convex diagonal squared rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4 # center dist ** 2 if CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47 - v = (4 / math.pi ** 2) * (torch.atan(w2 / h2) - torch.atan(w1 / h1)).pow(2) + v = (4 / math.pi**2) * (torch.atan(w2 / h2) - torch.atan(w1 / h1)).pow(2) with torch.no_grad(): alpha = v / (v - iou + (1 + eps)) return iou - (rho2 / c2 + v * alpha) # CIoU @@ -264,6 +267,7 @@ def box_iou(box1, box2, eps=1e-7): # https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py """ Return intersection-over-union (Jaccard index) of boxes. + Both sets of boxes are expected to be in (x1, y1, x2, y2) format. Arguments: box1 (Tensor[N, 4]) @@ -282,7 +286,10 @@ def box_iou(box1, box2, eps=1e-7): def bbox_ioa(box1, box2, eps=1e-7): - """ Returns the intersection over box2 area given box1, box2. Boxes are x1y1x2y2 + """ + Returns the intersection over box2 area given box1, box2. + + Boxes are x1y1x2y2 box1: np.array of shape(4) box2: np.array of shape(nx4) returns: np.array of shape(n) @@ -293,8 +300,9 @@ def bbox_ioa(box1, box2, eps=1e-7): b2_x1, b2_y1, b2_x2, b2_y2 = box2.T # Intersection area - inter_area = (np.minimum(b1_x2, b2_x2) - np.maximum(b1_x1, b2_x1)).clip(0) * \ - (np.minimum(b1_y2, b2_y2) - np.maximum(b1_y1, b2_y1)).clip(0) + inter_area = (np.minimum(b1_x2, b2_x2) - np.maximum(b1_x1, b2_x1)).clip(0) * ( + np.minimum(b1_y2, b2_y2) - np.maximum(b1_y1, b2_y1) + ).clip(0) # box2 area box2_area = (b2_x2 - b2_x1) * (b2_y2 - b2_y1) + eps @@ -315,46 +323,46 @@ def wh_iou(wh1, wh2, eps=1e-7): @threaded -def plot_pr_curve(px, py, ap, save_dir=Path('pr_curve.png'), names=()): +def plot_pr_curve(px, py, ap, save_dir=Path("pr_curve.png"), names=()): # Precision-recall curve fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True) py = np.stack(py, axis=1) if 0 < len(names) < 21: # display per-class legend if < 21 classes for i, y in enumerate(py.T): - ax.plot(px, y, linewidth=1, label=f'{names[i]} {ap[i, 0]:.3f}') # plot(recall, precision) + ax.plot(px, y, linewidth=1, label=f"{names[i]} {ap[i, 0]:.3f}") # plot(recall, precision) else: - ax.plot(px, py, linewidth=1, color='grey') # plot(recall, precision) + ax.plot(px, py, linewidth=1, color="grey") # plot(recall, precision) - ax.plot(px, py.mean(1), linewidth=3, color='blue', label='all classes %.3f mAP@0.5' % ap[:, 0].mean()) - ax.set_xlabel('Recall') - ax.set_ylabel('Precision') + ax.plot(px, py.mean(1), linewidth=3, color="blue", label="all classes %.3f mAP@0.5" % ap[:, 0].mean()) + ax.set_xlabel("Recall") + ax.set_ylabel("Precision") ax.set_xlim(0, 1) ax.set_ylim(0, 1) - ax.legend(bbox_to_anchor=(1.04, 1), loc='upper left') - ax.set_title('Precision-Recall Curve') + ax.legend(bbox_to_anchor=(1.04, 1), loc="upper left") + ax.set_title("Precision-Recall Curve") fig.savefig(save_dir, dpi=250) plt.close(fig) @threaded -def plot_mc_curve(px, py, save_dir=Path('mc_curve.png'), names=(), xlabel='Confidence', ylabel='Metric'): +def plot_mc_curve(px, py, save_dir=Path("mc_curve.png"), names=(), xlabel="Confidence", ylabel="Metric"): # Metric-confidence curve fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True) if 0 < len(names) < 21: # display per-class legend if < 21 classes for i, y in enumerate(py): - ax.plot(px, y, linewidth=1, label=f'{names[i]}') # plot(confidence, metric) + ax.plot(px, y, linewidth=1, label=f"{names[i]}") # plot(confidence, metric) else: - ax.plot(px, py.T, linewidth=1, color='grey') # plot(confidence, metric) + ax.plot(px, py.T, linewidth=1, color="grey") # plot(confidence, metric) y = smooth(py.mean(0), 0.05) - ax.plot(px, y, linewidth=3, color='blue', label=f'all classes {y.max():.2f} at {px[y.argmax()]:.3f}') + ax.plot(px, y, linewidth=3, color="blue", label=f"all classes {y.max():.2f} at {px[y.argmax()]:.3f}") ax.set_xlabel(xlabel) ax.set_ylabel(ylabel) ax.set_xlim(0, 1) ax.set_ylim(0, 1) - ax.legend(bbox_to_anchor=(1.04, 1), loc='upper left') - ax.set_title(f'{ylabel}-Confidence Curve') + ax.legend(bbox_to_anchor=(1.04, 1), loc="upper left") + ax.set_title(f"{ylabel}-Confidence Curve") fig.savefig(save_dir, dpi=250) plt.close(fig) diff --git a/utils/plots.py b/utils/plots.py index 039c0cdafd..a089a8d6d6 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Plotting utils -""" +"""Plotting utils.""" import contextlib import math @@ -25,18 +23,38 @@ from utils.metrics import fitness # Settings -RANK = int(os.getenv('RANK', -1)) -matplotlib.rc('font', **{'size': 11}) -matplotlib.use('Agg') # for writing to files only +RANK = int(os.getenv("RANK", -1)) +matplotlib.rc("font", **{"size": 11}) +matplotlib.use("Agg") # for writing to files only class Colors: # Ultralytics color palette https://ultralytics.com/ def __init__(self): # hex = matplotlib.colors.TABLEAU_COLORS.values() - hexs = ('FF3838', 'FF9D97', 'FF701F', 'FFB21D', 'CFD231', '48F90A', '92CC17', '3DDB86', '1A9334', '00D4BB', - '2C99A8', '00C2FF', '344593', '6473FF', '0018EC', '8438FF', '520085', 'CB38FF', 'FF95C8', 'FF37C7') - self.palette = [self.hex2rgb(f'#{c}') for c in hexs] + hexs = ( + "FF3838", + "FF9D97", + "FF701F", + "FFB21D", + "CFD231", + "48F90A", + "92CC17", + "3DDB86", + "1A9334", + "00D4BB", + "2C99A8", + "00C2FF", + "344593", + "6473FF", + "0018EC", + "8438FF", + "520085", + "CB38FF", + "FF95C8", + "FF37C7", + ) + self.palette = [self.hex2rgb(f"#{c}") for c in hexs] self.n = len(self.palette) def __call__(self, i, bgr=False): @@ -45,13 +63,13 @@ def __call__(self, i, bgr=False): @staticmethod def hex2rgb(h): # rgb order (PIL) - return tuple(int(h[1 + i:1 + i + 2], 16) for i in (0, 2, 4)) + return tuple(int(h[1 + i : 1 + i + 2], 16) for i in (0, 2, 4)) colors = Colors() # create instance for 'from utils.plots import colors' -def feature_visualization(x, module_type, stage, n=32, save_dir=Path('runs/detect/exp')): +def feature_visualization(x, module_type, stage, n=32, save_dir=Path("runs/detect/exp")): """ x: Features to be visualized module_type: Module type @@ -59,7 +77,7 @@ def feature_visualization(x, module_type, stage, n=32, save_dir=Path('runs/detec n: Maximum number of feature maps to plot save_dir: Directory to save results """ - if 'Detect' not in module_type: + if "Detect" not in module_type: batch, channels, height, width = x.shape # batch, channels, height, width if height > 1 and width > 1: f = save_dir / f"stage{stage}_{module_type.split('.')[-1]}_features.png" # filename @@ -71,12 +89,12 @@ def feature_visualization(x, module_type, stage, n=32, save_dir=Path('runs/detec plt.subplots_adjust(wspace=0.05, hspace=0.05) for i in range(n): ax[i].imshow(blocks[i].squeeze()) # cmap='gray' - ax[i].axis('off') + ax[i].axis("off") - LOGGER.info(f'Saving {f}... ({n}/{channels})') - plt.savefig(f, dpi=300, bbox_inches='tight') + LOGGER.info(f"Saving {f}... ({n}/{channels})") + plt.savefig(f, dpi=300, bbox_inches="tight") plt.close() - np.save(str(f.with_suffix('.npy')), x[0].cpu().numpy()) # npy save + np.save(str(f.with_suffix(".npy")), x[0].cpu().numpy()) # npy save def hist2d(x, y, n=100): @@ -95,7 +113,7 @@ def butter_lowpass_filtfilt(data, cutoff=1500, fs=50000, order=5): def butter_lowpass(cutoff, fs, order): nyq = 0.5 * fs normal_cutoff = cutoff / nyq - return butter(order, normal_cutoff, btype='low', analog=False) + return butter(order, normal_cutoff, btype="low", analog=False) b, a = butter_lowpass(cutoff, fs, order=order) return filtfilt(b, a, data) # forward-backward filter @@ -112,7 +130,7 @@ def output_to_target(output, max_det=300): @threaded -def plot_images(images, targets, paths=None, fname='images.jpg', names=None): +def plot_images(images, targets, paths=None, fname="images.jpg", names=None): # Plot image grid with labels if isinstance(images, torch.Tensor): images = images.cpu().float().numpy() @@ -123,7 +141,7 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None): max_subplots = 16 # max image subplots, i.e. 4x4 bs, _, h, w = images.shape # batch size, _, height, width bs = min(bs, max_subplots) # limit plot images - ns = np.ceil(bs ** 0.5) # number of subplots (square) + ns = np.ceil(bs**0.5) # number of subplots (square) if np.max(images[0]) <= 1: images *= 255 # de-normalise (optional) @@ -134,7 +152,7 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None): break x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin im = im.transpose(1, 2, 0) - mosaic[y:y + h, x:x + w, :] = im + mosaic[y : y + h, x : x + w, :] = im # Resize (optional) scale = max_size / ns / max(h, w) @@ -154,7 +172,7 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None): if len(targets) > 0: ti = targets[targets[:, 0] == i] # image targets boxes = xywh2xyxy(ti[:, 2:6]).T - classes = ti[:, 1].astype('int') + classes = ti[:, 1].astype("int") labels = ti.shape[1] == 6 # labels if no conf column conf = None if labels else ti[:, 6] # check for confidence presence (label vs pred) @@ -171,59 +189,59 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None): color = colors(cls) cls = names[cls] if names else cls if labels or conf[j] > 0.25: # 0.25 conf thresh - label = f'{cls}' if labels else f'{cls} {conf[j]:.1f}' + label = f"{cls}" if labels else f"{cls} {conf[j]:.1f}" annotator.box_label(box, label, color=color) annotator.im.save(fname) # save -def plot_lr_scheduler(optimizer, scheduler, epochs=300, save_dir=''): +def plot_lr_scheduler(optimizer, scheduler, epochs=300, save_dir=""): # Plot LR simulating training for full epochs optimizer, scheduler = copy(optimizer), copy(scheduler) # do not modify originals y = [] for _ in range(epochs): scheduler.step() - y.append(optimizer.param_groups[0]['lr']) - plt.plot(y, '.-', label='LR') - plt.xlabel('epoch') - plt.ylabel('LR') + y.append(optimizer.param_groups[0]["lr"]) + plt.plot(y, ".-", label="LR") + plt.xlabel("epoch") + plt.ylabel("LR") plt.grid() plt.xlim(0, epochs) plt.ylim(0) - plt.savefig(Path(save_dir) / 'LR.png', dpi=200) + plt.savefig(Path(save_dir) / "LR.png", dpi=200) plt.close() def plot_val_txt(): # from utils.plots import *; plot_val() # Plot val.txt histograms - x = np.loadtxt('val.txt', dtype=np.float32) + x = np.loadtxt("val.txt", dtype=np.float32) box = xyxy2xywh(x[:, :4]) cx, cy = box[:, 0], box[:, 1] fig, ax = plt.subplots(1, 1, figsize=(6, 6), tight_layout=True) ax.hist2d(cx, cy, bins=600, cmax=10, cmin=0) - ax.set_aspect('equal') - plt.savefig('hist2d.png', dpi=300) + ax.set_aspect("equal") + plt.savefig("hist2d.png", dpi=300) fig, ax = plt.subplots(1, 2, figsize=(12, 6), tight_layout=True) ax[0].hist(cx, bins=600) ax[1].hist(cy, bins=600) - plt.savefig('hist1d.png', dpi=200) + plt.savefig("hist1d.png", dpi=200) def plot_targets_txt(): # from utils.plots import *; plot_targets_txt() # Plot targets.txt histograms - x = np.loadtxt('targets.txt', dtype=np.float32).T - s = ['x targets', 'y targets', 'width targets', 'height targets'] + x = np.loadtxt("targets.txt", dtype=np.float32).T + s = ["x targets", "y targets", "width targets", "height targets"] fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) ax = ax.ravel() for i in range(4): - ax[i].hist(x[i], bins=100, label=f'{x[i].mean():.3g} +/- {x[i].std():.3g}') + ax[i].hist(x[i], bins=100, label=f"{x[i].mean():.3g} +/- {x[i].std():.3g}") ax[i].legend() ax[i].set_title(s[i]) - plt.savefig('targets.jpg', dpi=200) + plt.savefig("targets.jpg", dpi=200) -def plot_val_study(file='', dir='', x=None): # from utils.plots import *; plot_val_study() +def plot_val_study(file="", dir="", x=None): # from utils.plots import *; plot_val_study() # Plot file=study.txt generated by val.py (or plot all study*.txt in dir) save_dir = Path(file).parent if file else Path(dir) plot2 = False # plot additional results @@ -232,69 +250,74 @@ def plot_val_study(file='', dir='', x=None): # from utils.plots import *; plot_ fig2, ax2 = plt.subplots(1, 1, figsize=(8, 4), tight_layout=True) # for f in [save_dir / f'study_coco_{x}.txt' for x in ['yolov5n6', 'yolov5s6', 'yolov5m6', 'yolov5l6', 'yolov5x6']]: - for f in sorted(save_dir.glob('study*.txt')): + for f in sorted(save_dir.glob("study*.txt")): y = np.loadtxt(f, dtype=np.float32, usecols=[0, 1, 2, 3, 7, 8, 9], ndmin=2).T x = np.arange(y.shape[1]) if x is None else np.array(x) if plot2: - s = ['P', 'R', 'mAP@.5', 'mAP@.5:.95', 't_preprocess (ms/img)', 't_inference (ms/img)', 't_NMS (ms/img)'] + s = ["P", "R", "mAP@.5", "mAP@.5:.95", "t_preprocess (ms/img)", "t_inference (ms/img)", "t_NMS (ms/img)"] for i in range(7): - ax[i].plot(x, y[i], '.-', linewidth=2, markersize=8) + ax[i].plot(x, y[i], ".-", linewidth=2, markersize=8) ax[i].set_title(s[i]) j = y[3].argmax() + 1 - ax2.plot(y[5, 1:j], - y[3, 1:j] * 1E2, - '.-', - linewidth=2, - markersize=8, - label=f.stem.replace('study_coco_', '').replace('yolo', 'YOLO')) - - ax2.plot(1E3 / np.array([209, 140, 97, 58, 35, 18]), [34.6, 40.5, 43.0, 47.5, 49.7, 51.5], - 'k.-', - linewidth=2, - markersize=8, - alpha=.25, - label='EfficientDet') + ax2.plot( + y[5, 1:j], + y[3, 1:j] * 1e2, + ".-", + linewidth=2, + markersize=8, + label=f.stem.replace("study_coco_", "").replace("yolo", "YOLO"), + ) + + ax2.plot( + 1e3 / np.array([209, 140, 97, 58, 35, 18]), + [34.6, 40.5, 43.0, 47.5, 49.7, 51.5], + "k.-", + linewidth=2, + markersize=8, + alpha=0.25, + label="EfficientDet", + ) ax2.grid(alpha=0.2) ax2.set_yticks(np.arange(20, 60, 5)) ax2.set_xlim(0, 57) ax2.set_ylim(25, 55) - ax2.set_xlabel('GPU Speed (ms/img)') - ax2.set_ylabel('COCO AP val') - ax2.legend(loc='lower right') - f = save_dir / 'study.png' - print(f'Saving {f}...') + ax2.set_xlabel("GPU Speed (ms/img)") + ax2.set_ylabel("COCO AP val") + ax2.legend(loc="lower right") + f = save_dir / "study.png" + print(f"Saving {f}...") plt.savefig(f, dpi=300) @TryExcept() # known issue https://github.com/ultralytics/yolov5/issues/5395 -def plot_labels(labels, names=(), save_dir=Path('')): +def plot_labels(labels, names=(), save_dir=Path("")): # plot dataset labels LOGGER.info(f"Plotting labels to {save_dir / 'labels.jpg'}... ") c, b = labels[:, 0], labels[:, 1:].transpose() # classes, boxes nc = int(c.max() + 1) # number of classes - x = pd.DataFrame(b.transpose(), columns=['x', 'y', 'width', 'height']) + x = pd.DataFrame(b.transpose(), columns=["x", "y", "width", "height"]) # seaborn correlogram - sn.pairplot(x, corner=True, diag_kind='auto', kind='hist', diag_kws=dict(bins=50), plot_kws=dict(pmax=0.9)) - plt.savefig(save_dir / 'labels_correlogram.jpg', dpi=200) + sn.pairplot(x, corner=True, diag_kind="auto", kind="hist", diag_kws=dict(bins=50), plot_kws=dict(pmax=0.9)) + plt.savefig(save_dir / "labels_correlogram.jpg", dpi=200) plt.close() # matplotlib labels - matplotlib.use('svg') # faster + matplotlib.use("svg") # faster ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True)[1].ravel() y = ax[0].hist(c, bins=np.linspace(0, nc, nc + 1) - 0.5, rwidth=0.8) with contextlib.suppress(Exception): # color histogram bars by class [y[2].patches[i].set_color([x / 255 for x in colors(i)]) for i in range(nc)] # known issue #3195 - ax[0].set_ylabel('instances') + ax[0].set_ylabel("instances") if 0 < len(names) < 30: ax[0].set_xticks(range(len(names))) ax[0].set_xticklabels(list(names.values()), rotation=90, fontsize=10) else: - ax[0].set_xlabel('classes') - sn.histplot(x, x='x', y='y', ax=ax[2], bins=50, pmax=0.9) - sn.histplot(x, x='width', y='height', ax=ax[3], bins=50, pmax=0.9) + ax[0].set_xlabel("classes") + sn.histplot(x, x="x", y="y", ax=ax[2], bins=50, pmax=0.9) + sn.histplot(x, x="width", y="height", ax=ax[3], bins=50, pmax=0.9) # rectangles labels[:, 1:3] = 0.5 # center @@ -303,47 +326,48 @@ def plot_labels(labels, names=(), save_dir=Path('')): for cls, *box in labels[:1000]: ImageDraw.Draw(img).rectangle(box, width=1, outline=colors(cls)) # plot ax[1].imshow(img) - ax[1].axis('off') + ax[1].axis("off") for a in [0, 1, 2, 3]: - for s in ['top', 'right', 'left', 'bottom']: + for s in ["top", "right", "left", "bottom"]: ax[a].spines[s].set_visible(False) - plt.savefig(save_dir / 'labels.jpg', dpi=200) - matplotlib.use('Agg') + plt.savefig(save_dir / "labels.jpg", dpi=200) + matplotlib.use("Agg") plt.close() -def imshow_cls(im, labels=None, pred=None, names=None, nmax=25, verbose=False, f=Path('images.jpg')): +def imshow_cls(im, labels=None, pred=None, names=None, nmax=25, verbose=False, f=Path("images.jpg")): # Show classification image grid with labels (optional) and predictions (optional) from utils.augmentations import denormalize - names = names or [f'class{i}' for i in range(1000)] - blocks = torch.chunk(denormalize(im.clone()).cpu().float(), len(im), - dim=0) # select batch index 0, block by channels + names = names or [f"class{i}" for i in range(1000)] + blocks = torch.chunk( + denormalize(im.clone()).cpu().float(), len(im), dim=0 + ) # select batch index 0, block by channels n = min(len(blocks), nmax) # number of plots - m = min(8, round(n ** 0.5)) # 8 x 8 default + m = min(8, round(n**0.5)) # 8 x 8 default fig, ax = plt.subplots(math.ceil(n / m), m) # 8 rows x n/8 cols ax = ax.ravel() if m > 1 else [ax] # plt.subplots_adjust(wspace=0.05, hspace=0.05) for i in range(n): ax[i].imshow(blocks[i].squeeze().permute((1, 2, 0)).numpy().clip(0.0, 1.0)) - ax[i].axis('off') + ax[i].axis("off") if labels is not None: - s = names[labels[i]] + (f'—{names[pred[i]]}' if pred is not None else '') - ax[i].set_title(s, fontsize=8, verticalalignment='top') - plt.savefig(f, dpi=300, bbox_inches='tight') + s = names[labels[i]] + (f"—{names[pred[i]]}" if pred is not None else "") + ax[i].set_title(s, fontsize=8, verticalalignment="top") + plt.savefig(f, dpi=300, bbox_inches="tight") plt.close() if verbose: - LOGGER.info(f'Saving {f}') + LOGGER.info(f"Saving {f}") if labels is not None: - LOGGER.info('True: ' + ' '.join(f'{names[i]:3s}' for i in labels[:nmax])) + LOGGER.info("True: " + " ".join(f"{names[i]:3s}" for i in labels[:nmax])) if pred is not None: - LOGGER.info('Predicted:' + ' '.join(f'{names[i]:3s}' for i in pred[:nmax])) + LOGGER.info("Predicted:" + " ".join(f"{names[i]:3s}" for i in pred[:nmax])) return f -def plot_evolve(evolve_csv='path/to/evolve.csv'): # from utils.plots import *; plot_evolve() +def plot_evolve(evolve_csv="path/to/evolve.csv"): # from utils.plots import *; plot_evolve() # Plot evolve.csv hyp evolution results evolve_csv = Path(evolve_csv) data = pd.read_csv(evolve_csv) @@ -352,83 +376,83 @@ def plot_evolve(evolve_csv='path/to/evolve.csv'): # from utils.plots import *; f = fitness(x) j = np.argmax(f) # max fitness index plt.figure(figsize=(10, 12), tight_layout=True) - matplotlib.rc('font', **{'size': 8}) - print(f'Best results from row {j} of {evolve_csv}:') + matplotlib.rc("font", **{"size": 8}) + print(f"Best results from row {j} of {evolve_csv}:") for i, k in enumerate(keys[7:]): v = x[:, 7 + i] mu = v[j] # best single result plt.subplot(6, 5, i + 1) - plt.scatter(v, f, c=hist2d(v, f, 20), cmap='viridis', alpha=.8, edgecolors='none') - plt.plot(mu, f.max(), 'k+', markersize=15) - plt.title(f'{k} = {mu:.3g}', fontdict={'size': 9}) # limit to 40 characters + plt.scatter(v, f, c=hist2d(v, f, 20), cmap="viridis", alpha=0.8, edgecolors="none") + plt.plot(mu, f.max(), "k+", markersize=15) + plt.title(f"{k} = {mu:.3g}", fontdict={"size": 9}) # limit to 40 characters if i % 5 != 0: plt.yticks([]) - print(f'{k:>15}: {mu:.3g}') - f = evolve_csv.with_suffix('.png') # filename + print(f"{k:>15}: {mu:.3g}") + f = evolve_csv.with_suffix(".png") # filename plt.savefig(f, dpi=200) plt.close() - print(f'Saved {f}') + print(f"Saved {f}") -def plot_results(file='path/to/results.csv', dir=''): +def plot_results(file="path/to/results.csv", dir=""): # Plot training results.csv. Usage: from utils.plots import *; plot_results('path/to/results.csv') save_dir = Path(file).parent if file else Path(dir) fig, ax = plt.subplots(2, 5, figsize=(12, 6), tight_layout=True) ax = ax.ravel() - files = list(save_dir.glob('results*.csv')) - assert len(files), f'No results.csv files found in {save_dir.resolve()}, nothing to plot.' + files = list(save_dir.glob("results*.csv")) + assert len(files), f"No results.csv files found in {save_dir.resolve()}, nothing to plot." for f in files: try: data = pd.read_csv(f) s = [x.strip() for x in data.columns] x = data.values[:, 0] for i, j in enumerate([1, 2, 3, 4, 5, 8, 9, 10, 6, 7]): - y = data.values[:, j].astype('float') + y = data.values[:, j].astype("float") # y[y == 0] = np.nan # don't show zero values - ax[i].plot(x, y, marker='.', label=f.stem, linewidth=2, markersize=8) # actual results - ax[i].plot(x, gaussian_filter1d(y, sigma=3), ':', label='smooth', linewidth=2) # smoothing line + ax[i].plot(x, y, marker=".", label=f.stem, linewidth=2, markersize=8) # actual results + ax[i].plot(x, gaussian_filter1d(y, sigma=3), ":", label="smooth", linewidth=2) # smoothing line ax[i].set_title(s[j], fontsize=12) # if j in [8, 9, 10]: # share train and val loss y axes # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) except Exception as e: - LOGGER.info(f'Warning: Plotting error for {f}: {e}') + LOGGER.info(f"Warning: Plotting error for {f}: {e}") ax[1].legend() - fig.savefig(save_dir / 'results.png', dpi=200) + fig.savefig(save_dir / "results.png", dpi=200) plt.close() -def profile_idetection(start=0, stop=0, labels=(), save_dir=''): +def profile_idetection(start=0, stop=0, labels=(), save_dir=""): # Plot iDetection '*.txt' per-image logs. from utils.plots import *; profile_idetection() ax = plt.subplots(2, 4, figsize=(12, 6), tight_layout=True)[1].ravel() - s = ['Images', 'Free Storage (GB)', 'RAM Usage (GB)', 'Battery', 'dt_raw (ms)', 'dt_smooth (ms)', 'real-world FPS'] - files = list(Path(save_dir).glob('frames*.txt')) + s = ["Images", "Free Storage (GB)", "RAM Usage (GB)", "Battery", "dt_raw (ms)", "dt_smooth (ms)", "real-world FPS"] + files = list(Path(save_dir).glob("frames*.txt")) for fi, f in enumerate(files): try: results = np.loadtxt(f, ndmin=2).T[:, 90:-30] # clip first and last rows n = results.shape[1] # number of rows x = np.arange(start, min(stop, n) if stop else n) results = results[:, x] - t = (results[0] - results[0].min()) # set t0=0s + t = results[0] - results[0].min() # set t0=0s results[0] = x for i, a in enumerate(ax): if i < len(results): - label = labels[fi] if len(labels) else f.stem.replace('frames_', '') - a.plot(t, results[i], marker='.', label=label, linewidth=1, markersize=5) + label = labels[fi] if len(labels) else f.stem.replace("frames_", "") + a.plot(t, results[i], marker=".", label=label, linewidth=1, markersize=5) a.set_title(s[i]) - a.set_xlabel('time (s)') + a.set_xlabel("time (s)") # if fi == len(files) - 1: # a.set_ylim(bottom=0) - for side in ['top', 'right']: + for side in ["top", "right"]: a.spines[side].set_visible(False) else: a.remove() except Exception as e: - print(f'Warning: Plotting error for {f}; {e}') + print(f"Warning: Plotting error for {f}; {e}") ax[1].legend() - plt.savefig(Path(save_dir) / 'idetection_profile.png', dpi=200) + plt.savefig(Path(save_dir) / "idetection_profile.png", dpi=200) -def save_one_box(xyxy, im, file=Path('im.jpg'), gain=1.02, pad=10, square=False, BGR=False, save=True): +def save_one_box(xyxy, im, file=Path("im.jpg"), gain=1.02, pad=10, square=False, BGR=False, save=True): # Save image crop as {file} with crop size multiple {gain} and {pad} pixels. Save and/or return crop xyxy = torch.tensor(xyxy).view(-1, 4) b = xyxy2xywh(xyxy) # boxes @@ -437,10 +461,10 @@ def save_one_box(xyxy, im, file=Path('im.jpg'), gain=1.02, pad=10, square=False, b[:, 2:] = b[:, 2:] * gain + pad # box wh * gain + pad xyxy = xywh2xyxy(b).long() clip_boxes(xyxy, im.shape) - crop = im[int(xyxy[0, 1]):int(xyxy[0, 3]), int(xyxy[0, 0]):int(xyxy[0, 2]), ::(1 if BGR else -1)] + crop = im[int(xyxy[0, 1]) : int(xyxy[0, 3]), int(xyxy[0, 0]) : int(xyxy[0, 2]), :: (1 if BGR else -1)] if save: file.parent.mkdir(parents=True, exist_ok=True) # make directory - f = str(increment_path(file).with_suffix('.jpg')) + f = str(increment_path(file).with_suffix(".jpg")) # cv2.imwrite(f, crop) # save BGR, https://github.com/ultralytics/yolov5/issues/7007 chroma subsampling issue Image.fromarray(crop[..., ::-1]).save(f, quality=95, subsampling=0) # save RGB return crop diff --git a/utils/segment/augmentations.py b/utils/segment/augmentations.py index 085ef3a314..f3074d1cdd 100644 --- a/utils/segment/augmentations.py +++ b/utils/segment/augmentations.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Image augmentation functions -""" +"""Image augmentation functions.""" import math import random @@ -22,15 +20,9 @@ def mixup(im, labels, segments, im2, labels2, segments2): return im, labels, segments -def random_perspective(im, - targets=(), - segments=(), - degrees=10, - translate=.1, - scale=.1, - shear=10, - perspective=0.0, - border=(0, 0)): +def random_perspective( + im, targets=(), segments=(), degrees=10, translate=0.1, scale=0.1, shear=10, perspective=0.0, border=(0, 0) +): # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) # targets = [cls, xyxy] @@ -62,8 +54,8 @@ def random_perspective(im, # Translation T = np.eye(3) - T[0, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * width) # x translation (pixels) - T[1, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * height) # y translation (pixels) + T[0, 2] = random.uniform(0.5 - translate, 0.5 + translate) * width # x translation (pixels) + T[1, 2] = random.uniform(0.5 - translate, 0.5 + translate) * height # y translation (pixels) # Combined rotation matrix M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT @@ -89,7 +81,7 @@ def random_perspective(im, xy = np.ones((len(segment), 3)) xy[:, :2] = segment xy = xy @ M.T # transform - xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]) # perspective rescale or affine + xy = xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2] # perspective rescale or affine # clip new[i] = segment2box(xy, width, height) diff --git a/utils/segment/dataloaders.py b/utils/segment/dataloaders.py index b6daef2c7b..2fa37be554 100644 --- a/utils/segment/dataloaders.py +++ b/utils/segment/dataloaders.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Dataloaders -""" +"""Dataloaders.""" import os import random @@ -17,30 +15,32 @@ from ..torch_utils import torch_distributed_zero_first from .augmentations import mixup, random_perspective -RANK = int(os.getenv('RANK', -1)) - - -def create_dataloader(path, - imgsz, - batch_size, - stride, - single_cls=False, - hyp=None, - augment=False, - cache=False, - pad=0.0, - rect=False, - rank=-1, - workers=8, - image_weights=False, - quad=False, - prefix='', - shuffle=False, - mask_downsample_ratio=1, - overlap_mask=False, - seed=0): +RANK = int(os.getenv("RANK", -1)) + + +def create_dataloader( + path, + imgsz, + batch_size, + stride, + single_cls=False, + hyp=None, + augment=False, + cache=False, + pad=0.0, + rect=False, + rank=-1, + workers=8, + image_weights=False, + quad=False, + prefix="", + shuffle=False, + mask_downsample_ratio=1, + overlap_mask=False, + seed=0, +): if rect and shuffle: - LOGGER.warning('WARNING ⚠️ --rect is incompatible with DataLoader shuffle, setting shuffle=False') + LOGGER.warning("WARNING ⚠️ --rect is incompatible with DataLoader shuffle, setting shuffle=False") shuffle = False with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP dataset = LoadImagesAndLabelsAndMasks( @@ -57,7 +57,8 @@ def create_dataloader(path, image_weights=image_weights, prefix=prefix, downsample_ratio=mask_downsample_ratio, - overlap=overlap_mask) + overlap=overlap_mask, + ) batch_size = min(batch_size, len(dataset)) nd = torch.cuda.device_count() # number of CUDA devices @@ -80,7 +81,6 @@ def create_dataloader(path, class LoadImagesAndLabelsAndMasks(LoadImagesAndLabels): # for training/testing - def __init__( self, path, @@ -95,12 +95,25 @@ def __init__( stride=32, pad=0, min_items=0, - prefix='', + prefix="", downsample_ratio=1, overlap=False, ): - super().__init__(path, img_size, batch_size, augment, hyp, rect, image_weights, cache_images, single_cls, - stride, pad, min_items, prefix) + super().__init__( + path, + img_size, + batch_size, + augment, + hyp, + rect, + image_weights, + cache_images, + single_cls, + stride, + pad, + min_items, + prefix, + ) self.downsample_ratio = downsample_ratio self.overlap = overlap @@ -108,7 +121,7 @@ def __getitem__(self, index): index = self.indices[index] # linear, shuffled, or image_weights hyp = self.hyp - mosaic = self.mosaic and random.random() < hyp['mosaic'] + mosaic = self.mosaic and random.random() < hyp["mosaic"] masks = [] if mosaic: # Load mosaic @@ -116,7 +129,7 @@ def __getitem__(self, index): shapes = None # MixUp augmentation - if random.random() < hyp['mixup']: + if random.random() < hyp["mixup"]: img, labels, segments = mixup(img, labels, segments, *self.load_mosaic(random.randint(0, self.n - 1))) else: @@ -144,30 +157,36 @@ def __getitem__(self, index): labels[:, 1:] = xywhn2xyxy(labels[:, 1:], ratio[0] * w, ratio[1] * h, padw=pad[0], padh=pad[1]) if self.augment: - img, labels, segments = random_perspective(img, - labels, - segments=segments, - degrees=hyp['degrees'], - translate=hyp['translate'], - scale=hyp['scale'], - shear=hyp['shear'], - perspective=hyp['perspective']) + img, labels, segments = random_perspective( + img, + labels, + segments=segments, + degrees=hyp["degrees"], + translate=hyp["translate"], + scale=hyp["scale"], + shear=hyp["shear"], + perspective=hyp["perspective"], + ) nl = len(labels) # number of labels if nl: labels[:, 1:5] = xyxy2xywhn(labels[:, 1:5], w=img.shape[1], h=img.shape[0], clip=True, eps=1e-3) if self.overlap: - masks, sorted_idx = polygons2masks_overlap(img.shape[:2], - segments, - downsample_ratio=self.downsample_ratio) + masks, sorted_idx = polygons2masks_overlap( + img.shape[:2], segments, downsample_ratio=self.downsample_ratio + ) masks = masks[None] # (640, 640) -> (1, 640, 640) labels = labels[sorted_idx] else: masks = polygons2masks(img.shape[:2], segments, color=1, downsample_ratio=self.downsample_ratio) - masks = (torch.from_numpy(masks) if len(masks) else torch.zeros(1 if self.overlap else nl, img.shape[0] // - self.downsample_ratio, img.shape[1] // - self.downsample_ratio)) + masks = ( + torch.from_numpy(masks) + if len(masks) + else torch.zeros( + 1 if self.overlap else nl, img.shape[0] // self.downsample_ratio, img.shape[1] // self.downsample_ratio + ) + ) # TODO: albumentations support if self.augment: # Albumentations @@ -177,17 +196,17 @@ def __getitem__(self, index): nl = len(labels) # update after albumentations # HSV color-space - augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) + augment_hsv(img, hgain=hyp["hsv_h"], sgain=hyp["hsv_s"], vgain=hyp["hsv_v"]) # Flip up-down - if random.random() < hyp['flipud']: + if random.random() < hyp["flipud"]: img = np.flipud(img) if nl: labels[:, 2] = 1 - labels[:, 2] masks = torch.flip(masks, dims=[1]) # Flip left-right - if random.random() < hyp['fliplr']: + if random.random() < hyp["fliplr"]: img = np.fliplr(img) if nl: labels[:, 1] = 1 - labels[:, 1] @@ -251,16 +270,18 @@ def load_mosaic(self, index): # img4, labels4 = replicate(img4, labels4) # replicate # Augment - img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp['copy_paste']) - img4, labels4, segments4 = random_perspective(img4, - labels4, - segments4, - degrees=self.hyp['degrees'], - translate=self.hyp['translate'], - scale=self.hyp['scale'], - shear=self.hyp['shear'], - perspective=self.hyp['perspective'], - border=self.mosaic_border) # border to remove + img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp["copy_paste"]) + img4, labels4, segments4 = random_perspective( + img4, + labels4, + segments4, + degrees=self.hyp["degrees"], + translate=self.hyp["translate"], + scale=self.hyp["scale"], + shear=self.hyp["shear"], + perspective=self.hyp["perspective"], + border=self.mosaic_border, + ) # border to remove return img4, labels4, segments4 @staticmethod @@ -309,8 +330,10 @@ def polygons2masks(img_size, polygons, color, downsample_ratio=1): def polygons2masks_overlap(img_size, segments, downsample_ratio=1): """Return a (640, 640) overlap mask.""" - masks = np.zeros((img_size[0] // downsample_ratio, img_size[1] // downsample_ratio), - dtype=np.int32 if len(segments) > 255 else np.uint8) + masks = np.zeros( + (img_size[0] // downsample_ratio, img_size[1] // downsample_ratio), + dtype=np.int32 if len(segments) > 255 else np.uint8, + ) areas = [] ms = [] for si in range(len(segments)): diff --git a/utils/segment/general.py b/utils/segment/general.py index f1b2f1dd12..8cbc745b4a 100644 --- a/utils/segment/general.py +++ b/utils/segment/general.py @@ -6,8 +6,7 @@ def crop_mask(masks, boxes): """ - "Crop" predicted masks by zeroing out everything not in the predicted bbox. - Vectorized by Chong (thanks Chong). + "Crop" predicted masks by zeroing out everything not in the predicted bbox. Vectorized by Chong (thanks Chong). Args: - masks should be a size [n, h, w] tensor of masks @@ -35,7 +34,7 @@ def process_mask_upsample(protos, masks_in, bboxes, shape): c, mh, mw = protos.shape # CHW masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw) - masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW + masks = F.interpolate(masks[None], shape, mode="bilinear", align_corners=False)[0] # CHW masks = crop_mask(masks, bboxes) # CHW return masks.gt_(0.5) @@ -63,7 +62,7 @@ def process_mask(protos, masks_in, bboxes, shape, upsample=False): masks = crop_mask(masks, downsampled_bboxes) # CHW if upsample: - masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW + masks = F.interpolate(masks[None], shape, mode="bilinear", align_corners=False)[0] # CHW return masks.gt_(0.5) @@ -85,7 +84,7 @@ def process_mask_native(protos, masks_in, bboxes, shape): bottom, right = int(mh - pad[1]), int(mw - pad[0]) masks = masks[:, top:bottom, left:right] - masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW + masks = F.interpolate(masks[None], shape, mode="bilinear", align_corners=False)[0] # CHW masks = crop_mask(masks, bboxes) # CHW return masks.gt_(0.5) @@ -144,17 +143,17 @@ def masks_iou(mask1, mask2, eps=1e-7): return intersection / (union + eps) -def masks2segments(masks, strategy='largest'): +def masks2segments(masks, strategy="largest"): # Convert masks(n,160,160) into segments(n,xy) segments = [] - for x in masks.int().cpu().numpy().astype('uint8'): + for x in masks.int().cpu().numpy().astype("uint8"): c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0] if c: - if strategy == 'concat': # concatenate all segments + if strategy == "concat": # concatenate all segments c = np.concatenate([x.reshape(-1, 2) for x in c]) - elif strategy == 'largest': # select largest segment + elif strategy == "largest": # select largest segment c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2) else: c = np.zeros((0, 2)) # no segments found - segments.append(c.astype('float32')) + segments.append(c.astype("float32")) return segments diff --git a/utils/segment/loss.py b/utils/segment/loss.py index caeff3cad5..1e007271fa 100644 --- a/utils/segment/loss.py +++ b/utils/segment/loss.py @@ -18,14 +18,14 @@ def __init__(self, model, autobalance=False, overlap=False): h = model.hyp # hyperparameters # Define criteria - BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device)) - BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device)) + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h["cls_pw"]], device=device)) + BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h["obj_pw"]], device=device)) # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 - self.cp, self.cn = smooth_BCE(eps=h.get('label_smoothing', 0.0)) # positive, negative BCE targets + self.cp, self.cn = smooth_BCE(eps=h.get("label_smoothing", 0.0)) # positive, negative BCE targets # Focal loss - g = h['fl_gamma'] # focal loss gamma + g = h["fl_gamma"] # focal loss gamma if g > 0: BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) @@ -82,7 +82,7 @@ def __call__(self, preds, targets, masks): # predictions, targets, model # Mask regression if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample - masks = F.interpolate(masks[None], (mask_h, mask_w), mode='nearest')[0] + masks = F.interpolate(masks[None], (mask_h, mask_w), mode="nearest")[0] marea = xywhn[i][:, 2:].prod(1) # mask width, height normalized mxyxy = xywh2xyxy(xywhn[i] * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device)) for bi in b.unique(): @@ -100,10 +100,10 @@ def __call__(self, preds, targets, masks): # predictions, targets, model if self.autobalance: self.balance = [x / self.balance[self.ssi] for x in self.balance] - lbox *= self.hyp['box'] - lobj *= self.hyp['obj'] - lcls *= self.hyp['cls'] - lseg *= self.hyp['box'] / bs + lbox *= self.hyp["box"] + lobj *= self.hyp["obj"] + lcls *= self.hyp["cls"] + lseg *= self.hyp["box"] / bs loss = lbox + lobj + lcls + lseg return loss * bs, torch.cat((lbox, lseg, lobj, lcls)).detach() @@ -111,7 +111,7 @@ def __call__(self, preds, targets, masks): # predictions, targets, model def single_mask_loss(self, gt_mask, pred, proto, xyxy, area): # Mask loss for one image pred_mask = (pred @ proto.view(self.nm, -1)).view(-1, *proto.shape[1:]) # (n,32) @ (32,80,80) -> (n,80,80) - loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction='none') + loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction="none") return (crop_mask(loss, xyxy).mean(dim=(1, 2)) / area).mean() def build_targets(self, p, targets): @@ -132,16 +132,20 @@ def build_targets(self, p, targets): targets = torch.cat((targets.repeat(na, 1, 1), ai[..., None], ti[..., None]), 2) # append anchor indices g = 0.5 # bias - off = torch.tensor( - [ - [0, 0], - [1, 0], - [0, 1], - [-1, 0], - [0, -1], # j,k,l,m - # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm - ], - device=self.device).float() * g # offsets + off = ( + torch.tensor( + [ + [0, 0], + [1, 0], + [0, 1], + [-1, 0], + [0, -1], # j,k,l,m + # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm + ], + device=self.device, + ).float() + * g + ) # offsets for i in range(self.nl): anchors, shape = self.anchors[i], p[i].shape @@ -152,7 +156,7 @@ def build_targets(self, p, targets): if nt: # Matches r = t[..., 4:6] / anchors[:, None] # wh ratio - j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t'] # compare + j = torch.max(r, 1 / r).max(2)[0] < self.hyp["anchor_t"] # compare # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2)) t = t[j] # filter diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py index f9abf3dff1..978017bd31 100644 --- a/utils/segment/metrics.py +++ b/utils/segment/metrics.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -Model validation metrics -""" +"""Model validation metrics.""" import numpy as np @@ -15,14 +13,14 @@ def fitness(x): def ap_per_class_box_and_mask( - tp_m, - tp_b, - conf, - pred_cls, - target_cls, - plot=False, - save_dir='.', - names=(), + tp_m, + tp_b, + conf, + pred_cls, + target_cls, + plot=False, + save_dir=".", + names=(), ): """ Args: @@ -30,41 +28,33 @@ def ap_per_class_box_and_mask( tp_m: tp of masks. other arguments see `func: ap_per_class`. """ - results_boxes = ap_per_class(tp_b, - conf, - pred_cls, - target_cls, - plot=plot, - save_dir=save_dir, - names=names, - prefix='Box')[2:] - results_masks = ap_per_class(tp_m, - conf, - pred_cls, - target_cls, - plot=plot, - save_dir=save_dir, - names=names, - prefix='Mask')[2:] + results_boxes = ap_per_class( + tp_b, conf, pred_cls, target_cls, plot=plot, save_dir=save_dir, names=names, prefix="Box" + )[2:] + results_masks = ap_per_class( + tp_m, conf, pred_cls, target_cls, plot=plot, save_dir=save_dir, names=names, prefix="Mask" + )[2:] results = { - 'boxes': { - 'p': results_boxes[0], - 'r': results_boxes[1], - 'ap': results_boxes[3], - 'f1': results_boxes[2], - 'ap_class': results_boxes[4]}, - 'masks': { - 'p': results_masks[0], - 'r': results_masks[1], - 'ap': results_masks[3], - 'f1': results_masks[2], - 'ap_class': results_masks[4]}} + "boxes": { + "p": results_boxes[0], + "r": results_boxes[1], + "ap": results_boxes[3], + "f1": results_boxes[2], + "ap_class": results_boxes[4], + }, + "masks": { + "p": results_masks[0], + "r": results_masks[1], + "ap": results_masks[3], + "f1": results_masks[2], + "ap_class": results_masks[4], + }, + } return results class Metric: - def __init__(self) -> None: self.p = [] # (nc, ) self.r = [] # (nc, ) @@ -74,7 +64,9 @@ def __init__(self) -> None: @property def ap50(self): - """AP@0.5 of all classes. + """ + AP@0.5 of all classes. + Return: (nc, ) or []. """ @@ -90,7 +82,9 @@ def ap(self): @property def mp(self): - """mean precision of all classes. + """ + Mean precision of all classes. + Return: float. """ @@ -98,7 +92,9 @@ def mp(self): @property def mr(self): - """mean recall of all classes. + """ + Mean recall of all classes. + Return: float. """ @@ -106,7 +102,9 @@ def mr(self): @property def map50(self): - """Mean AP@0.5 of all classes. + """ + Mean AP@0.5 of all classes. + Return: float. """ @@ -114,18 +112,20 @@ def map50(self): @property def map(self): - """Mean AP@0.5:0.95 of all classes. + """ + Mean AP@0.5:0.95 of all classes. + Return: float. """ return self.all_ap.mean() if len(self.all_ap) else 0.0 def mean_results(self): - """Mean of results, return mp, mr, map50, map""" + """Mean of results, return mp, mr, map50, map.""" return (self.mp, self.mr, self.map50, self.map) def class_result(self, i): - """class-aware result, return p[i], r[i], ap50[i], ap[i]""" + """Class-aware result, return p[i], r[i], ap50[i], ap[i]""" return (self.p[i], self.r[i], self.ap50[i], self.ap[i]) def get_maps(self, nc): @@ -159,8 +159,8 @@ def update(self, results): Args: results: Dict{'boxes': Dict{}, 'masks': Dict{}} """ - self.metric_box.update(list(results['boxes'].values())) - self.metric_mask.update(list(results['masks'].values())) + self.metric_box.update(list(results["boxes"].values())) + self.metric_mask.update(list(results["masks"].values())) def mean_results(self): return self.metric_box.mean_results() + self.metric_mask.mean_results() @@ -178,33 +178,35 @@ def ap_class_index(self): KEYS = [ - 'train/box_loss', - 'train/seg_loss', # train loss - 'train/obj_loss', - 'train/cls_loss', - 'metrics/precision(B)', - 'metrics/recall(B)', - 'metrics/mAP_0.5(B)', - 'metrics/mAP_0.5:0.95(B)', # metrics - 'metrics/precision(M)', - 'metrics/recall(M)', - 'metrics/mAP_0.5(M)', - 'metrics/mAP_0.5:0.95(M)', # metrics - 'val/box_loss', - 'val/seg_loss', # val loss - 'val/obj_loss', - 'val/cls_loss', - 'x/lr0', - 'x/lr1', - 'x/lr2', ] + "train/box_loss", + "train/seg_loss", # train loss + "train/obj_loss", + "train/cls_loss", + "metrics/precision(B)", + "metrics/recall(B)", + "metrics/mAP_0.5(B)", + "metrics/mAP_0.5:0.95(B)", # metrics + "metrics/precision(M)", + "metrics/recall(M)", + "metrics/mAP_0.5(M)", + "metrics/mAP_0.5:0.95(M)", # metrics + "val/box_loss", + "val/seg_loss", # val loss + "val/obj_loss", + "val/cls_loss", + "x/lr0", + "x/lr1", + "x/lr2", +] BEST_KEYS = [ - 'best/epoch', - 'best/precision(B)', - 'best/recall(B)', - 'best/mAP_0.5(B)', - 'best/mAP_0.5:0.95(B)', - 'best/precision(M)', - 'best/recall(M)', - 'best/mAP_0.5(M)', - 'best/mAP_0.5:0.95(M)', ] + "best/epoch", + "best/precision(B)", + "best/recall(B)", + "best/mAP_0.5(B)", + "best/mAP_0.5:0.95(B)", + "best/precision(M)", + "best/recall(M)", + "best/mAP_0.5(M)", + "best/mAP_0.5:0.95(M)", +] diff --git a/utils/segment/plots.py b/utils/segment/plots.py index f9938cd1b0..0e30c61be6 100644 --- a/utils/segment/plots.py +++ b/utils/segment/plots.py @@ -14,7 +14,7 @@ @threaded -def plot_images_and_masks(images, targets, masks, paths=None, fname='images.jpg', names=None): +def plot_images_and_masks(images, targets, masks, paths=None, fname="images.jpg", names=None): # Plot image grid with labels if isinstance(images, torch.Tensor): images = images.cpu().float().numpy() @@ -27,7 +27,7 @@ def plot_images_and_masks(images, targets, masks, paths=None, fname='images.jpg' max_subplots = 16 # max image subplots, i.e. 4x4 bs, _, h, w = images.shape # batch size, _, height, width bs = min(bs, max_subplots) # limit plot images - ns = np.ceil(bs ** 0.5) # number of subplots (square) + ns = np.ceil(bs**0.5) # number of subplots (square) if np.max(images[0]) <= 1: images *= 255 # de-normalise (optional) @@ -38,7 +38,7 @@ def plot_images_and_masks(images, targets, masks, paths=None, fname='images.jpg' break x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin im = im.transpose(1, 2, 0) - mosaic[y:y + h, x:x + w, :] = im + mosaic[y : y + h, x : x + w, :] = im # Resize (optional) scale = max_size / ns / max(h, w) @@ -60,7 +60,7 @@ def plot_images_and_masks(images, targets, masks, paths=None, fname='images.jpg' ti = targets[idx] # image targets boxes = xywh2xyxy(ti[:, 2:6]).T - classes = ti[:, 1].astype('int') + classes = ti[:, 1].astype("int") labels = ti.shape[1] == 6 # labels if no conf column conf = None if labels else ti[:, 6] # check for confidence presence (label vs pred) @@ -77,7 +77,7 @@ def plot_images_and_masks(images, targets, masks, paths=None, fname='images.jpg' color = colors(cls) cls = names[cls] if names else cls if labels or conf[j] > 0.25: # 0.25 conf thresh - label = f'{cls}' if labels else f'{cls} {conf[j]:.1f}' + label = f"{cls}" if labels else f"{cls} {conf[j]:.1f}" annotator.box_label(box, label, color=color) # Plot masks @@ -103,41 +103,44 @@ def plot_images_and_masks(images, targets, masks, paths=None, fname='images.jpg' else: mask = image_masks[j].astype(bool) with contextlib.suppress(Exception): - im[y:y + h, x:x + w, :][mask] = im[y:y + h, x:x + w, :][mask] * 0.4 + np.array(color) * 0.6 + im[y : y + h, x : x + w, :][mask] = ( + im[y : y + h, x : x + w, :][mask] * 0.4 + np.array(color) * 0.6 + ) annotator.fromarray(im) annotator.im.save(fname) # save -def plot_results_with_masks(file='path/to/results.csv', dir='', best=True): +def plot_results_with_masks(file="path/to/results.csv", dir="", best=True): # Plot training results.csv. Usage: from utils.plots import *; plot_results('path/to/results.csv') save_dir = Path(file).parent if file else Path(dir) fig, ax = plt.subplots(2, 8, figsize=(18, 6), tight_layout=True) ax = ax.ravel() - files = list(save_dir.glob('results*.csv')) - assert len(files), f'No results.csv files found in {save_dir.resolve()}, nothing to plot.' + files = list(save_dir.glob("results*.csv")) + assert len(files), f"No results.csv files found in {save_dir.resolve()}, nothing to plot." for f in files: try: data = pd.read_csv(f) - index = np.argmax(0.9 * data.values[:, 8] + 0.1 * data.values[:, 7] + 0.9 * data.values[:, 12] + - 0.1 * data.values[:, 11]) + index = np.argmax( + 0.9 * data.values[:, 8] + 0.1 * data.values[:, 7] + 0.9 * data.values[:, 12] + 0.1 * data.values[:, 11] + ) s = [x.strip() for x in data.columns] x = data.values[:, 0] for i, j in enumerate([1, 2, 3, 4, 5, 6, 9, 10, 13, 14, 15, 16, 7, 8, 11, 12]): y = data.values[:, j] # y[y == 0] = np.nan # don't show zero values - ax[i].plot(x, y, marker='.', label=f.stem, linewidth=2, markersize=2) + ax[i].plot(x, y, marker=".", label=f.stem, linewidth=2, markersize=2) if best: # best - ax[i].scatter(index, y[index], color='r', label=f'best:{index}', marker='*', linewidth=3) - ax[i].set_title(s[j] + f'\n{round(y[index], 5)}') + ax[i].scatter(index, y[index], color="r", label=f"best:{index}", marker="*", linewidth=3) + ax[i].set_title(s[j] + f"\n{round(y[index], 5)}") else: # last - ax[i].scatter(x[-1], y[-1], color='r', label='last', marker='*', linewidth=3) - ax[i].set_title(s[j] + f'\n{round(y[-1], 5)}') + ax[i].scatter(x[-1], y[-1], color="r", label="last", marker="*", linewidth=3) + ax[i].set_title(s[j] + f"\n{round(y[-1], 5)}") # if j in [8, 9, 10]: # share train and val loss y axes # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) except Exception as e: - print(f'Warning: Plotting error for {f}: {e}') + print(f"Warning: Plotting error for {f}: {e}") ax[1].legend() - fig.savefig(save_dir / 'results.png', dpi=200) + fig.savefig(save_dir / "results.png", dpi=200) plt.close() diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 940c5ba9e6..000b77b37c 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -1,7 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" -PyTorch utils -""" +"""PyTorch utils.""" import math import os @@ -21,9 +19,9 @@ from utils.general import LOGGER, check_version, colorstr, file_date, git_describe -LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html -RANK = int(os.getenv('RANK', -1)) -WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +LOCAL_RANK = int(os.getenv("LOCAL_RANK", -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv("RANK", -1)) +WORLD_SIZE = int(os.getenv("WORLD_SIZE", 1)) try: import thop # for FLOPs computation @@ -31,11 +29,11 @@ thop = None # Suppress PyTorch warnings -warnings.filterwarnings('ignore', message='User provided device_type of \'cuda\', but CUDA is not available. Disabling') -warnings.filterwarnings('ignore', category=UserWarning) +warnings.filterwarnings("ignore", message="User provided device_type of 'cuda', but CUDA is not available. Disabling") +warnings.filterwarnings("ignore", category=UserWarning) -def smart_inference_mode(torch_1_9=check_version(torch.__version__, '1.9.0')): +def smart_inference_mode(torch_1_9=check_version(torch.__version__, "1.9.0")): # Applies torch.inference_mode() decorator if torch>=1.9.0 else torch.no_grad() decorator def decorate(fn): return (torch.inference_mode if torch_1_9 else torch.no_grad)()(fn) @@ -45,19 +43,20 @@ def decorate(fn): def smartCrossEntropyLoss(label_smoothing=0.0): # Returns nn.CrossEntropyLoss with label smoothing enabled for torch>=1.10.0 - if check_version(torch.__version__, '1.10.0'): + if check_version(torch.__version__, "1.10.0"): return nn.CrossEntropyLoss(label_smoothing=label_smoothing) if label_smoothing > 0: - LOGGER.warning(f'WARNING ⚠️ label smoothing {label_smoothing} requires torch>=1.10.0') + LOGGER.warning(f"WARNING ⚠️ label smoothing {label_smoothing} requires torch>=1.10.0") return nn.CrossEntropyLoss() def smart_DDP(model): # Model DDP creation with checks - assert not check_version(torch.__version__, '1.12.0', pinned=True), \ - 'torch==1.12.0 torchvision==0.13.0 DDP training is not supported due to a known issue. ' \ - 'Please upgrade or downgrade torch to use DDP. See https://github.com/ultralytics/yolov5/issues/8395' - if check_version(torch.__version__, '1.11.0'): + assert not check_version(torch.__version__, "1.12.0", pinned=True), ( + "torch==1.12.0 torchvision==0.13.0 DDP training is not supported due to a known issue. " + "Please upgrade or downgrade torch to use DDP. See https://github.com/ultralytics/yolov5/issues/8395" + ) + if check_version(torch.__version__, "1.11.0"): return DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK, static_graph=True) else: return DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK) @@ -66,7 +65,8 @@ def smart_DDP(model): def reshape_classifier_output(model, n=1000): # Update a TorchVision classification model to class count 'n' if required from models.common import Classify - name, m = list((model.model if hasattr(model, 'model') else model).named_children())[-1] # last module + + name, m = list((model.model if hasattr(model, "model") else model).named_children())[-1] # last module if isinstance(m, Classify): # YOLOv3 Classify() head if m.linear.out_features != n: m.linear = nn.Linear(m.linear.in_features, n) @@ -97,43 +97,44 @@ def torch_distributed_zero_first(local_rank: int): def device_count(): # Returns number of CUDA devices available. Safe version of torch.cuda.device_count(). Supports Linux and Windows - assert platform.system() in ('Linux', 'Windows'), 'device_count() only supported on Linux or Windows' + assert platform.system() in ("Linux", "Windows"), "device_count() only supported on Linux or Windows" try: - cmd = 'nvidia-smi -L | wc -l' if platform.system() == 'Linux' else 'nvidia-smi -L | find /c /v ""' # Windows + cmd = "nvidia-smi -L | wc -l" if platform.system() == "Linux" else 'nvidia-smi -L | find /c /v ""' # Windows return int(subprocess.run(cmd, shell=True, capture_output=True, check=True).stdout.decode().split()[-1]) except Exception: return 0 -def select_device(device='', batch_size=0, newline=True): +def select_device(device="", batch_size=0, newline=True): # device = None or 'cpu' or 0 or '0' or '0,1,2,3' - s = f'YOLOv3 🚀 {git_describe() or file_date()} Python-{platform.python_version()} torch-{torch.__version__} ' - device = str(device).strip().lower().replace('cuda:', '').replace('none', '') # to string, 'cuda:0' to '0' - cpu = device == 'cpu' - mps = device == 'mps' # Apple Metal Performance Shaders (MPS) + s = f"YOLOv3 🚀 {git_describe() or file_date()} Python-{platform.python_version()} torch-{torch.__version__} " + device = str(device).strip().lower().replace("cuda:", "").replace("none", "") # to string, 'cuda:0' to '0' + cpu = device == "cpu" + mps = device == "mps" # Apple Metal Performance Shaders (MPS) if cpu or mps: - os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # force torch.cuda.is_available() = False + os.environ["CUDA_VISIBLE_DEVICES"] = "-1" # force torch.cuda.is_available() = False elif device: # non-cpu device requested - os.environ['CUDA_VISIBLE_DEVICES'] = device # set environment variable - must be before assert is_available() - assert torch.cuda.is_available() and torch.cuda.device_count() >= len(device.replace(',', '')), \ - f"Invalid CUDA '--device {device}' requested, use '--device cpu' or pass valid CUDA device(s)" + os.environ["CUDA_VISIBLE_DEVICES"] = device # set environment variable - must be before assert is_available() + assert torch.cuda.is_available() and torch.cuda.device_count() >= len( + device.replace(",", "") + ), f"Invalid CUDA '--device {device}' requested, use '--device cpu' or pass valid CUDA device(s)" if not cpu and not mps and torch.cuda.is_available(): # prefer GPU if available - devices = device.split(',') if device else '0' # range(torch.cuda.device_count()) # i.e. 0,1,6,7 + devices = device.split(",") if device else "0" # range(torch.cuda.device_count()) # i.e. 0,1,6,7 n = len(devices) # device count if n > 1 and batch_size > 0: # check batch_size is divisible by device_count - assert batch_size % n == 0, f'batch-size {batch_size} not multiple of GPU count {n}' - space = ' ' * (len(s) + 1) + assert batch_size % n == 0, f"batch-size {batch_size} not multiple of GPU count {n}" + space = " " * (len(s) + 1) for i, d in enumerate(devices): p = torch.cuda.get_device_properties(i) s += f"{'' if i == 0 else space}CUDA:{d} ({p.name}, {p.total_memory / (1 << 20):.0f}MiB)\n" # bytes to MB - arg = 'cuda:0' - elif mps and getattr(torch, 'has_mps', False) and torch.backends.mps.is_available(): # prefer MPS if available - s += 'MPS\n' - arg = 'mps' + arg = "cuda:0" + elif mps and getattr(torch, "has_mps", False) and torch.backends.mps.is_available(): # prefer MPS if available + s += "MPS\n" + arg = "mps" else: # revert to CPU - s += 'CPU\n' - arg = 'cpu' + s += "CPU\n" + arg = "cpu" if not newline: s = s.rstrip() @@ -149,7 +150,7 @@ def time_sync(): def profile(input, ops, n=10, device=None): - """ YOLOv3 speed/memory/FLOPs profiler + """YOLOv3 speed/memory/FLOPs profiler Usage: input = torch.randn(16, 3, 640, 640) m1 = lambda x: x * torch.sigmoid(x) @@ -159,18 +160,20 @@ def profile(input, ops, n=10, device=None): results = [] if not isinstance(device, torch.device): device = select_device(device) - print(f"{'Params':>12s}{'GFLOPs':>12s}{'GPU_mem (GB)':>14s}{'forward (ms)':>14s}{'backward (ms)':>14s}" - f"{'input':>24s}{'output':>24s}") + print( + f"{'Params':>12s}{'GFLOPs':>12s}{'GPU_mem (GB)':>14s}{'forward (ms)':>14s}{'backward (ms)':>14s}" + f"{'input':>24s}{'output':>24s}" + ) for x in input if isinstance(input, list) else [input]: x = x.to(device) x.requires_grad = True for m in ops if isinstance(ops, list) else [ops]: - m = m.to(device) if hasattr(m, 'to') else m # device - m = m.half() if hasattr(m, 'half') and isinstance(x, torch.Tensor) and x.dtype is torch.float16 else m + m = m.to(device) if hasattr(m, "to") else m # device + m = m.half() if hasattr(m, "half") and isinstance(x, torch.Tensor) and x.dtype is torch.float16 else m tf, tb, t = 0, 0, [0, 0, 0] # dt forward, backward try: - flops = thop.profile(m, inputs=(x, ), verbose=False)[0] / 1E9 * 2 # GFLOPs + flops = thop.profile(m, inputs=(x,), verbose=False)[0] / 1e9 * 2 # GFLOPs except Exception: flops = 0 @@ -184,13 +187,13 @@ def profile(input, ops, n=10, device=None): t[2] = time_sync() except Exception: # no backward method # print(e) # for debug - t[2] = float('nan') + t[2] = float("nan") tf += (t[1] - t[0]) * 1000 / n # ms per op forward tb += (t[2] - t[1]) * 1000 / n # ms per op backward - mem = torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0 # (GB) - s_in, s_out = (tuple(x.shape) if isinstance(x, torch.Tensor) else 'list' for x in (x, y)) # shapes + mem = torch.cuda.memory_reserved() / 1e9 if torch.cuda.is_available() else 0 # (GB) + s_in, s_out = (tuple(x.shape) if isinstance(x, torch.Tensor) else "list" for x in (x, y)) # shapes p = sum(x.numel() for x in m.parameters()) if isinstance(m, nn.Module) else 0 # parameters - print(f'{p:12}{flops:12.4g}{mem:>14.3f}{tf:14.4g}{tb:14.4g}{str(s_in):>24s}{str(s_out):>24s}') + print(f"{p:12}{flops:12.4g}{mem:>14.3f}{tf:14.4g}{tb:14.4g}{str(s_in):>24s}{str(s_out):>24s}") results.append([p, flops, mem, tf, tb, s_in, s_out]) except Exception as e: print(e) @@ -238,23 +241,30 @@ def sparsity(model): def prune(model, amount=0.3): # Prune model to requested global sparsity import torch.nn.utils.prune as prune + for name, m in model.named_modules(): if isinstance(m, nn.Conv2d): - prune.l1_unstructured(m, name='weight', amount=amount) # prune - prune.remove(m, 'weight') # make permanent - LOGGER.info(f'Model pruned to {sparsity(model):.3g} global sparsity') + prune.l1_unstructured(m, name="weight", amount=amount) # prune + prune.remove(m, "weight") # make permanent + LOGGER.info(f"Model pruned to {sparsity(model):.3g} global sparsity") def fuse_conv_and_bn(conv, bn): # Fuse Conv2d() and BatchNorm2d() layers https://tehnokv.com/posts/fusing-batchnorm-and-conv/ - fusedconv = nn.Conv2d(conv.in_channels, - conv.out_channels, - kernel_size=conv.kernel_size, - stride=conv.stride, - padding=conv.padding, - dilation=conv.dilation, - groups=conv.groups, - bias=True).requires_grad_(False).to(conv.weight.device) + fusedconv = ( + nn.Conv2d( + conv.in_channels, + conv.out_channels, + kernel_size=conv.kernel_size, + stride=conv.stride, + padding=conv.padding, + dilation=conv.dilation, + groups=conv.groups, + bias=True, + ) + .requires_grad_(False) + .to(conv.weight.device) + ) # Prepare filters w_conv = conv.weight.clone().view(conv.out_channels, -1) @@ -276,22 +286,24 @@ def model_info(model, verbose=False, imgsz=640): if verbose: print(f"{'layer':>5} {'name':>40} {'gradient':>9} {'parameters':>12} {'shape':>20} {'mu':>10} {'sigma':>10}") for i, (name, p) in enumerate(model.named_parameters()): - name = name.replace('module_list.', '') - print('%5g %40s %9s %12g %20s %10.3g %10.3g' % - (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) + name = name.replace("module_list.", "") + print( + "%5g %40s %9s %12g %20s %10.3g %10.3g" + % (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std()) + ) try: # FLOPs p = next(model.parameters()) - stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32 # max stride + stride = max(int(model.stride.max()), 32) if hasattr(model, "stride") else 32 # max stride im = torch.empty((1, p.shape[1], stride, stride), device=p.device) # input image in BCHW format - flops = thop.profile(deepcopy(model), inputs=(im, ), verbose=False)[0] / 1E9 * 2 # stride GFLOPs + flops = thop.profile(deepcopy(model), inputs=(im,), verbose=False)[0] / 1e9 * 2 # stride GFLOPs imgsz = imgsz if isinstance(imgsz, list) else [imgsz, imgsz] # expand if int/float - fs = f', {flops * imgsz[0] / stride * imgsz[1] / stride:.1f} GFLOPs' # 640x640 GFLOPs + fs = f", {flops * imgsz[0] / stride * imgsz[1] / stride:.1f} GFLOPs" # 640x640 GFLOPs except Exception: - fs = '' + fs = "" - name = Path(model.yaml_file).stem.replace('yolov5', 'YOLOv3') if hasattr(model, 'yaml_file') else 'Model' - LOGGER.info(f'{name} summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}') + name = Path(model.yaml_file).stem.replace("yolov5", "YOLOv3") if hasattr(model, "yaml_file") else "Model" + LOGGER.info(f"{name} summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}") def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416) @@ -300,7 +312,7 @@ def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416) return img h, w = img.shape[2:] s = (int(h * ratio), int(w * ratio)) # new size - img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize + img = F.interpolate(img, size=s, mode="bilinear", align_corners=False) # resize if not same_shape: # pad/crop img h, w = (math.ceil(x * ratio / gs) * gs for x in (h, w)) return F.pad(img, [0, w - s[1], 0, h - s[0]], value=0.447) # value = imagenet mean @@ -309,72 +321,76 @@ def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416) def copy_attr(a, b, include=(), exclude=()): # Copy attributes from b to a, options to only include [...] and to exclude [...] for k, v in b.__dict__.items(): - if (len(include) and k not in include) or k.startswith('_') or k in exclude: + if (len(include) and k not in include) or k.startswith("_") or k in exclude: continue else: setattr(a, k, v) -def smart_optimizer(model, name='Adam', lr=0.001, momentum=0.9, decay=1e-5): +def smart_optimizer(model, name="Adam", lr=0.001, momentum=0.9, decay=1e-5): # YOLOv3 3-param group optimizer: 0) weights with decay, 1) weights no decay, 2) biases no decay g = [], [], [] # optimizer parameter groups - bn = tuple(v for k, v in nn.__dict__.items() if 'Norm' in k) # normalization layers, i.e. BatchNorm2d() + bn = tuple(v for k, v in nn.__dict__.items() if "Norm" in k) # normalization layers, i.e. BatchNorm2d() for v in model.modules(): for p_name, p in v.named_parameters(recurse=0): - if p_name == 'bias': # bias (no decay) + if p_name == "bias": # bias (no decay) g[2].append(p) - elif p_name == 'weight' and isinstance(v, bn): # weight (no decay) + elif p_name == "weight" and isinstance(v, bn): # weight (no decay) g[1].append(p) else: g[0].append(p) # weight (with decay) - if name == 'Adam': + if name == "Adam": optimizer = torch.optim.Adam(g[2], lr=lr, betas=(momentum, 0.999)) # adjust beta1 to momentum - elif name == 'AdamW': + elif name == "AdamW": optimizer = torch.optim.AdamW(g[2], lr=lr, betas=(momentum, 0.999), weight_decay=0.0) - elif name == 'RMSProp': + elif name == "RMSProp": optimizer = torch.optim.RMSprop(g[2], lr=lr, momentum=momentum) - elif name == 'SGD': + elif name == "SGD": optimizer = torch.optim.SGD(g[2], lr=lr, momentum=momentum, nesterov=True) else: - raise NotImplementedError(f'Optimizer {name} not implemented.') - - optimizer.add_param_group({'params': g[0], 'weight_decay': decay}) # add g0 with weight_decay - optimizer.add_param_group({'params': g[1], 'weight_decay': 0.0}) # add g1 (BatchNorm2d weights) - LOGGER.info(f"{colorstr('optimizer:')} {type(optimizer).__name__}(lr={lr}) with parameter groups " - f'{len(g[1])} weight(decay=0.0), {len(g[0])} weight(decay={decay}), {len(g[2])} bias') + raise NotImplementedError(f"Optimizer {name} not implemented.") + + optimizer.add_param_group({"params": g[0], "weight_decay": decay}) # add g0 with weight_decay + optimizer.add_param_group({"params": g[1], "weight_decay": 0.0}) # add g1 (BatchNorm2d weights) + LOGGER.info( + f"{colorstr('optimizer:')} {type(optimizer).__name__}(lr={lr}) with parameter groups " + f'{len(g[1])} weight(decay=0.0), {len(g[0])} weight(decay={decay}), {len(g[2])} bias' + ) return optimizer -def smart_hub_load(repo='ultralytics/yolov5', model='yolov5s', **kwargs): +def smart_hub_load(repo="ultralytics/yolov5", model="yolov5s", **kwargs): # YOLOv3 torch.hub.load() wrapper with smart error/issue handling - if check_version(torch.__version__, '1.9.1'): - kwargs['skip_validation'] = True # validation causes GitHub API rate limit errors - if check_version(torch.__version__, '1.12.0'): - kwargs['trust_repo'] = True # argument required starting in torch 0.12 + if check_version(torch.__version__, "1.9.1"): + kwargs["skip_validation"] = True # validation causes GitHub API rate limit errors + if check_version(torch.__version__, "1.12.0"): + kwargs["trust_repo"] = True # argument required starting in torch 0.12 try: return torch.hub.load(repo, model, **kwargs) except Exception: return torch.hub.load(repo, model, force_reload=True, **kwargs) -def smart_resume(ckpt, optimizer, ema=None, weights='yolov5s.pt', epochs=300, resume=True): +def smart_resume(ckpt, optimizer, ema=None, weights="yolov5s.pt", epochs=300, resume=True): # Resume training from a partially trained checkpoint best_fitness = 0.0 - start_epoch = ckpt['epoch'] + 1 - if ckpt['optimizer'] is not None: - optimizer.load_state_dict(ckpt['optimizer']) # optimizer - best_fitness = ckpt['best_fitness'] - if ema and ckpt.get('ema'): - ema.ema.load_state_dict(ckpt['ema'].float().state_dict()) # EMA - ema.updates = ckpt['updates'] + start_epoch = ckpt["epoch"] + 1 + if ckpt["optimizer"] is not None: + optimizer.load_state_dict(ckpt["optimizer"]) # optimizer + best_fitness = ckpt["best_fitness"] + if ema and ckpt.get("ema"): + ema.ema.load_state_dict(ckpt["ema"].float().state_dict()) # EMA + ema.updates = ckpt["updates"] if resume: - assert start_epoch > 0, f'{weights} training to {epochs} epochs is finished, nothing to resume.\n' \ - f"Start a new training without --resume, i.e. 'python train.py --weights {weights}'" - LOGGER.info(f'Resuming training from {weights} from epoch {start_epoch} to {epochs} total epochs') + assert start_epoch > 0, ( + f"{weights} training to {epochs} epochs is finished, nothing to resume.\n" + f"Start a new training without --resume, i.e. 'python train.py --weights {weights}'" + ) + LOGGER.info(f"Resuming training from {weights} from epoch {start_epoch} to {epochs} total epochs") if epochs < start_epoch: LOGGER.info(f"{weights} has been trained for {ckpt['epoch']} epochs. Fine-tuning for {epochs} more epochs.") - epochs += ckpt['epoch'] # finetune additional epochs + epochs += ckpt["epoch"] # finetune additional epochs return best_fitness, start_epoch, epochs @@ -383,7 +399,7 @@ class EarlyStopping: def __init__(self, patience=30): self.best_fitness = 0.0 # i.e. mAP self.best_epoch = 0 - self.patience = patience or float('inf') # epochs to wait after fitness stops improving to stop + self.patience = patience or float("inf") # epochs to wait after fitness stops improving to stop self.possible_stop = False # possible stop may occur next epoch def __call__(self, epoch, fitness): @@ -394,15 +410,17 @@ def __call__(self, epoch, fitness): self.possible_stop = delta >= (self.patience - 1) # possible stop may occur next epoch stop = delta >= self.patience # stop training if patience exceeded if stop: - LOGGER.info(f'Stopping training early as no improvement observed in last {self.patience} epochs. ' - f'Best results observed at epoch {self.best_epoch}, best model saved as best.pt.\n' - f'To update EarlyStopping(patience={self.patience}) pass a new patience value, ' - f'i.e. `python train.py --patience 300` or use `--patience 0` to disable EarlyStopping.') + LOGGER.info( + f"Stopping training early as no improvement observed in last {self.patience} epochs. " + f"Best results observed at epoch {self.best_epoch}, best model saved as best.pt.\n" + f"To update EarlyStopping(patience={self.patience}) pass a new patience value, " + f"i.e. `python train.py --patience 300` or use `--patience 0` to disable EarlyStopping." + ) return stop class ModelEMA: - """ Updated Exponential Moving Average (EMA) from https://github.com/rwightman/pytorch-image-models + """Updated Exponential Moving Average (EMA) from https://github.com/rwightman/pytorch-image-models Keeps a moving average of everything in the model state_dict (parameters and buffers) For EMA details see https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage """ @@ -427,6 +445,6 @@ def update(self, model): v += (1 - d) * msd[k].detach() # assert v.dtype == msd[k].dtype == torch.float32, f'{k}: EMA {v.dtype} and model {msd[k].dtype} must be FP32' - def update_attr(self, model, include=(), exclude=('process_group', 'reducer')): + def update_attr(self, model, include=(), exclude=("process_group", "reducer")): # Update EMA attributes copy_attr(self.ema, model, include, exclude) diff --git a/utils/triton.py b/utils/triton.py index c57ee676e6..f34ec0f323 100644 --- a/utils/triton.py +++ b/utils/triton.py @@ -1,6 +1,5 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license -""" Utils to interact with the Triton Inference Server -""" +"""Utils to interact with the Triton Inference Server.""" import typing from urllib.parse import urlparse @@ -9,9 +8,11 @@ class TritonRemoteModel: - """ A wrapper over a model served by the Triton Inference Server. It can - be configured to communicate over GRPC or HTTP. It accepts Torch Tensors - as input and returns them as outputs. + """ + A wrapper over a model served by the Triton Inference Server. + + It can be configured to communicate over GRPC or HTTP. It accepts Torch Tensors as input and returns them as + outputs. """ def __init__(self, url: str): @@ -21,7 +22,7 @@ def __init__(self, url: str): """ parsed_url = urlparse(url) - if parsed_url.scheme == 'grpc': + if parsed_url.scheme == "grpc": from tritonclient.grpc import InferenceServerClient, InferInput self.client = InferenceServerClient(parsed_url.netloc) # Triton GRPC client @@ -31,51 +32,55 @@ def __init__(self, url: str): def create_input_placeholders() -> typing.List[InferInput]: return [ - InferInput(i['name'], [int(s) for s in i['shape']], i['datatype']) for i in self.metadata['inputs']] + InferInput(i["name"], [int(s) for s in i["shape"]], i["datatype"]) for i in self.metadata["inputs"] + ] else: from tritonclient.http import InferenceServerClient, InferInput self.client = InferenceServerClient(parsed_url.netloc) # Triton HTTP client model_repository = self.client.get_model_repository_index() - self.model_name = model_repository[0]['name'] + self.model_name = model_repository[0]["name"] self.metadata = self.client.get_model_metadata(self.model_name) def create_input_placeholders() -> typing.List[InferInput]: return [ - InferInput(i['name'], [int(s) for s in i['shape']], i['datatype']) for i in self.metadata['inputs']] + InferInput(i["name"], [int(s) for s in i["shape"]], i["datatype"]) for i in self.metadata["inputs"] + ] self._create_input_placeholders_fn = create_input_placeholders @property def runtime(self): - """Returns the model runtime""" - return self.metadata.get('backend', self.metadata.get('platform')) + """Returns the model runtime.""" + return self.metadata.get("backend", self.metadata.get("platform")) def __call__(self, *args, **kwargs) -> typing.Union[torch.Tensor, typing.Tuple[torch.Tensor, ...]]: - """ Invokes the model. Parameters can be provided via args or kwargs. - args, if provided, are assumed to match the order of inputs of the model. - kwargs are matched with the model input names. + """ + Invokes the model. + + Parameters can be provided via args or kwargs. args, if provided, are assumed to match the order of inputs of + the model. kwargs are matched with the model input names. """ inputs = self._create_inputs(*args, **kwargs) response = self.client.infer(model_name=self.model_name, inputs=inputs) result = [] - for output in self.metadata['outputs']: - tensor = torch.as_tensor(response.as_numpy(output['name'])) + for output in self.metadata["outputs"]: + tensor = torch.as_tensor(response.as_numpy(output["name"])) result.append(tensor) return result[0] if len(result) == 1 else result def _create_inputs(self, *args, **kwargs): args_len, kwargs_len = len(args), len(kwargs) if not args_len and not kwargs_len: - raise RuntimeError('No inputs provided.') + raise RuntimeError("No inputs provided.") if args_len and kwargs_len: - raise RuntimeError('Cannot specify args and kwargs at the same time') + raise RuntimeError("Cannot specify args and kwargs at the same time") placeholders = self._create_input_placeholders_fn() if args_len: if args_len != len(placeholders): - raise RuntimeError(f'Expected {len(placeholders)} inputs, got {args_len}.') + raise RuntimeError(f"Expected {len(placeholders)} inputs, got {args_len}.") for input, value in zip(placeholders, args): input.set_data_from_numpy(value.cpu().numpy()) else: diff --git a/val.py b/val.py index 8a82108567..a0a740700b 100644 --- a/val.py +++ b/val.py @@ -1,6 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """ -Validate a trained YOLOv3 detection model on a detection dataset +Validate a trained YOLOv3 detection model on a detection dataset. Usage: $ python val.py --weights yolov5s.pt --data coco128.yaml --img 640 @@ -39,9 +39,23 @@ from models.common import DetectMultiBackend from utils.callbacks import Callbacks from utils.dataloaders import create_dataloader -from utils.general import (LOGGER, TQDM_BAR_FORMAT, Profile, check_dataset, check_img_size, check_requirements, - check_yaml, coco80_to_coco91_class, colorstr, increment_path, non_max_suppression, - print_args, scale_boxes, xywh2xyxy, xyxy2xywh) +from utils.general import ( + LOGGER, + TQDM_BAR_FORMAT, + Profile, + check_dataset, + check_img_size, + check_requirements, + check_yaml, + coco80_to_coco91_class, + colorstr, + increment_path, + non_max_suppression, + print_args, + scale_boxes, + xywh2xyxy, + xyxy2xywh, +) from utils.metrics import ConfusionMatrix, ap_per_class, box_iou from utils.plots import output_to_target, plot_images, plot_val_study from utils.torch_utils import select_device, smart_inference_mode @@ -53,8 +67,8 @@ def save_one_txt(predn, save_conf, shape, file): for *xyxy, conf, cls in predn.tolist(): xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format - with open(file, 'a') as f: - f.write(('%g ' * len(line)).rstrip() % line + '\n') + with open(file, "a") as f: + f.write(("%g " * len(line)).rstrip() % line + "\n") def save_one_json(predn, jdict, path, class_map): @@ -63,11 +77,14 @@ def save_one_json(predn, jdict, path, class_map): box = xyxy2xywh(predn[:, :4]) # xywh box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner for p, b in zip(predn.tolist(), box.tolist()): - jdict.append({ - 'image_id': image_id, - 'category_id': class_map[int(p[5])], - 'bbox': [round(x, 3) for x in b], - 'score': round(p[4], 5)}) + jdict.append( + { + "image_id": image_id, + "category_id": class_map[int(p[5])], + "bbox": [round(x, 3) for x in b], + "score": round(p[4], 5), + } + ) def process_batch(detections, labels, iouv): @@ -97,47 +114,47 @@ def process_batch(detections, labels, iouv): @smart_inference_mode() def run( - data, - weights=None, # model.pt path(s) - batch_size=32, # batch size - imgsz=640, # inference size (pixels) - conf_thres=0.001, # confidence threshold - iou_thres=0.6, # NMS IoU threshold - max_det=300, # maximum detections per image - task='val', # train, val, test, speed or study - device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu - workers=8, # max dataloader workers (per RANK in DDP mode) - single_cls=False, # treat as single-class dataset - augment=False, # augmented inference - verbose=False, # verbose output - save_txt=False, # save results to *.txt - save_hybrid=False, # save label+prediction hybrid results to *.txt - save_conf=False, # save confidences in --save-txt labels - save_json=False, # save a COCO-JSON results file - project=ROOT / 'runs/val', # save to project/name - name='exp', # save to project/name - exist_ok=False, # existing project/name ok, do not increment - half=True, # use FP16 half-precision inference - dnn=False, # use OpenCV DNN for ONNX inference - model=None, - dataloader=None, - save_dir=Path(''), - plots=True, - callbacks=Callbacks(), - compute_loss=None, + data, + weights=None, # model.pt path(s) + batch_size=32, # batch size + imgsz=640, # inference size (pixels) + conf_thres=0.001, # confidence threshold + iou_thres=0.6, # NMS IoU threshold + max_det=300, # maximum detections per image + task="val", # train, val, test, speed or study + device="", # cuda device, i.e. 0 or 0,1,2,3 or cpu + workers=8, # max dataloader workers (per RANK in DDP mode) + single_cls=False, # treat as single-class dataset + augment=False, # augmented inference + verbose=False, # verbose output + save_txt=False, # save results to *.txt + save_hybrid=False, # save label+prediction hybrid results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_json=False, # save a COCO-JSON results file + project=ROOT / "runs/val", # save to project/name + name="exp", # save to project/name + exist_ok=False, # existing project/name ok, do not increment + half=True, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + model=None, + dataloader=None, + save_dir=Path(""), + plots=True, + callbacks=Callbacks(), + compute_loss=None, ): # Initialize/load model and set device training = model is not None if training: # called by train.py device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model - half &= device.type != 'cpu' # half precision only supported on CUDA + half &= device.type != "cpu" # half precision only supported on CUDA model.half() if half else model.float() else: # called directly device = select_device(device, batch_size=batch_size) # Directories save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run - (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + (save_dir / "labels" if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir # Load model model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) @@ -150,16 +167,16 @@ def run( device = model.device if not (pt or jit): batch_size = 1 # export.py models default to batch-size 1 - LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') + LOGGER.info(f"Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models") # Data data = check_dataset(data) # check # Configure model.eval() - cuda = device.type != 'cpu' - is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'coco{os.sep}val2017.txt') # COCO dataset - nc = 1 if single_cls else int(data['nc']) # number of classes + cuda = device.type != "cpu" + is_coco = isinstance(data.get("val"), str) and data["val"].endswith(f"coco{os.sep}val2017.txt") # COCO dataset + nc = 1 if single_cls else int(data["nc"]) # number of classes iouv = torch.linspace(0.5, 0.95, 10, device=device) # iou vector for mAP@0.5:0.95 niou = iouv.numel() @@ -167,36 +184,40 @@ def run( if not training: if pt and not single_cls: # check --weights are trained on --data ncm = model.model.nc - assert ncm == nc, f'{weights} ({ncm} classes) trained on different --data than what you passed ({nc} ' \ - f'classes). Pass correct combination of --weights and --data that are trained together.' + assert ncm == nc, ( + f"{weights} ({ncm} classes) trained on different --data than what you passed ({nc} " + f"classes). Pass correct combination of --weights and --data that are trained together." + ) model.warmup(imgsz=(1 if pt else batch_size, 3, imgsz, imgsz)) # warmup - pad, rect = (0.0, False) if task == 'speed' else (0.5, pt) # square inference for benchmarks - task = task if task in ('train', 'val', 'test') else 'val' # path to train/val/test images - dataloader = create_dataloader(data[task], - imgsz, - batch_size, - stride, - single_cls, - pad=pad, - rect=rect, - workers=workers, - prefix=colorstr(f'{task}: '))[0] + pad, rect = (0.0, False) if task == "speed" else (0.5, pt) # square inference for benchmarks + task = task if task in ("train", "val", "test") else "val" # path to train/val/test images + dataloader = create_dataloader( + data[task], + imgsz, + batch_size, + stride, + single_cls, + pad=pad, + rect=rect, + workers=workers, + prefix=colorstr(f"{task}: "), + )[0] seen = 0 confusion_matrix = ConfusionMatrix(nc=nc) - names = model.names if hasattr(model, 'names') else model.module.names # get class names + names = model.names if hasattr(model, "names") else model.module.names # get class names if isinstance(names, (list, tuple)): # old format names = dict(enumerate(names)) class_map = coco80_to_coco91_class() if is_coco else list(range(1000)) - s = ('%22s' + '%11s' * 6) % ('Class', 'Images', 'Instances', 'P', 'R', 'mAP50', 'mAP50-95') + s = ("%22s" + "%11s" * 6) % ("Class", "Images", "Instances", "P", "R", "mAP50", "mAP50-95") tp, fp, p, r, f1, mp, mr, map50, ap50, map = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 dt = Profile(), Profile(), Profile() # profiling times loss = torch.zeros(3, device=device) jdict, stats, ap, ap_class = [], [], [], [] - callbacks.run('on_val_start') + callbacks.run("on_val_start") pbar = tqdm(dataloader, desc=s, bar_format=TQDM_BAR_FORMAT) # progress bar for batch_i, (im, targets, paths, shapes) in enumerate(pbar): - callbacks.run('on_val_batch_start') + callbacks.run("on_val_batch_start") with dt[0]: if cuda: im = im.to(device, non_blocking=True) @@ -217,13 +238,9 @@ def run( targets[:, 2:] *= torch.tensor((width, height, width, height), device=device) # to pixels lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling with dt[2]: - preds = non_max_suppression(preds, - conf_thres, - iou_thres, - labels=lb, - multi_label=True, - agnostic=single_cls, - max_det=max_det) + preds = non_max_suppression( + preds, conf_thres, iou_thres, labels=lb, multi_label=True, agnostic=single_cls, max_det=max_det + ) # Metrics for si, pred in enumerate(preds): @@ -258,17 +275,17 @@ def run( # Save/log if save_txt: - save_one_txt(predn, save_conf, shape, file=save_dir / 'labels' / f'{path.stem}.txt') + save_one_txt(predn, save_conf, shape, file=save_dir / "labels" / f"{path.stem}.txt") if save_json: save_one_json(predn, jdict, path, class_map) # append to COCO-JSON dictionary - callbacks.run('on_val_image_end', pred, predn, path, names, im[si]) + callbacks.run("on_val_image_end", pred, predn, path, names, im[si]) # Plot images if plots and batch_i < 3: - plot_images(im, targets, paths, save_dir / f'val_batch{batch_i}_labels.jpg', names) # labels - plot_images(im, output_to_target(preds), paths, save_dir / f'val_batch{batch_i}_pred.jpg', names) # pred + plot_images(im, targets, paths, save_dir / f"val_batch{batch_i}_labels.jpg", names) # labels + plot_images(im, output_to_target(preds), paths, save_dir / f"val_batch{batch_i}_pred.jpg", names) # pred - callbacks.run('on_val_batch_end', batch_i, im, targets, paths, shapes, preds) + callbacks.run("on_val_batch_end", batch_i, im, targets, paths, shapes, preds) # Compute metrics stats = [torch.cat(x, 0).cpu().numpy() for x in zip(*stats)] # to numpy @@ -279,10 +296,10 @@ def run( nt = np.bincount(stats[3].astype(int), minlength=nc) # number of targets per class # Print results - pf = '%22s' + '%11i' * 2 + '%11.3g' * 4 # print format - LOGGER.info(pf % ('all', seen, nt.sum(), mp, mr, map50, map)) + pf = "%22s" + "%11i" * 2 + "%11.3g" * 4 # print format + LOGGER.info(pf % ("all", seen, nt.sum(), mp, mr, map50, map)) if nt.sum() == 0: - LOGGER.warning(f'WARNING ⚠️ no labels found in {task} set, can not compute metrics without labels') + LOGGER.warning(f"WARNING ⚠️ no labels found in {task} set, can not compute metrics without labels") # Print results per class if (verbose or (nc < 50 and not training)) and nc > 1 and len(stats): @@ -290,35 +307,35 @@ def run( LOGGER.info(pf % (names[c], seen, nt[c], p[i], r[i], ap50[i], ap[i])) # Print speeds - t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + t = tuple(x.t / seen * 1e3 for x in dt) # speeds per image if not training: shape = (batch_size, 3, imgsz, imgsz) - LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {shape}' % t) + LOGGER.info(f"Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {shape}" % t) # Plots if plots: confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) - callbacks.run('on_val_end', nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) + callbacks.run("on_val_end", nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) # Save JSON if save_json and len(jdict): - w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights - anno_json = str(Path('../datasets/coco/annotations/instances_val2017.json')) # annotations + w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else "" # weights + anno_json = str(Path("../datasets/coco/annotations/instances_val2017.json")) # annotations if not os.path.exists(anno_json): - anno_json = os.path.join(data['path'], 'annotations', 'instances_val2017.json') - pred_json = str(save_dir / f'{w}_predictions.json') # predictions - LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') - with open(pred_json, 'w') as f: + anno_json = os.path.join(data["path"], "annotations", "instances_val2017.json") + pred_json = str(save_dir / f"{w}_predictions.json") # predictions + LOGGER.info(f"\nEvaluating pycocotools mAP... saving {pred_json}...") + with open(pred_json, "w") as f: json.dump(jdict, f) try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb - check_requirements('pycocotools>=2.0.6') + check_requirements("pycocotools>=2.0.6") from pycocotools.coco import COCO from pycocotools.cocoeval import COCOeval anno = COCO(anno_json) # init annotations api pred = anno.loadRes(pred_json) # init predictions api - eval = COCOeval(anno, pred, 'bbox') + eval = COCOeval(anno, pred, "bbox") if is_coco: eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.im_files] # image IDs to evaluate eval.evaluate() @@ -326,12 +343,12 @@ def run( eval.summarize() map, map50 = eval.stats[:2] # update results (mAP@0.5:0.95, mAP@0.5) except Exception as e: - LOGGER.info(f'pycocotools unable to run: {e}') + LOGGER.info(f"pycocotools unable to run: {e}") # Return results model.float() # for training if not training: - s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else "" LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") maps = np.zeros(nc) + map for i, c in enumerate(ap_class): @@ -341,71 +358,71 @@ def run( def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') - parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov3-tiny.pt', help='model path(s)') - parser.add_argument('--batch-size', type=int, default=32, help='batch size') - parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') - parser.add_argument('--conf-thres', type=float, default=0.001, help='confidence threshold') - parser.add_argument('--iou-thres', type=float, default=0.6, help='NMS IoU threshold') - parser.add_argument('--max-det', type=int, default=300, help='maximum detections per image') - parser.add_argument('--task', default='val', help='train, val, test, speed or study') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') - parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') - parser.add_argument('--augment', action='store_true', help='augmented inference') - parser.add_argument('--verbose', action='store_true', help='report mAP by class') - parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') - parser.add_argument('--save-hybrid', action='store_true', help='save label+prediction hybrid results to *.txt') - parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') - parser.add_argument('--save-json', action='store_true', help='save a COCO-JSON results file') - parser.add_argument('--project', default=ROOT / 'runs/val', help='save to project/name') - parser.add_argument('--name', default='exp', help='save to project/name') - parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') - parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') - parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="dataset.yaml path") + parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov3-tiny.pt", help="model path(s)") + parser.add_argument("--batch-size", type=int, default=32, help="batch size") + parser.add_argument("--imgsz", "--img", "--img-size", type=int, default=640, help="inference size (pixels)") + parser.add_argument("--conf-thres", type=float, default=0.001, help="confidence threshold") + parser.add_argument("--iou-thres", type=float, default=0.6, help="NMS IoU threshold") + parser.add_argument("--max-det", type=int, default=300, help="maximum detections per image") + parser.add_argument("--task", default="val", help="train, val, test, speed or study") + parser.add_argument("--device", default="", help="cuda device, i.e. 0 or 0,1,2,3 or cpu") + parser.add_argument("--workers", type=int, default=8, help="max dataloader workers (per RANK in DDP mode)") + parser.add_argument("--single-cls", action="store_true", help="treat as single-class dataset") + parser.add_argument("--augment", action="store_true", help="augmented inference") + parser.add_argument("--verbose", action="store_true", help="report mAP by class") + parser.add_argument("--save-txt", action="store_true", help="save results to *.txt") + parser.add_argument("--save-hybrid", action="store_true", help="save label+prediction hybrid results to *.txt") + parser.add_argument("--save-conf", action="store_true", help="save confidences in --save-txt labels") + parser.add_argument("--save-json", action="store_true", help="save a COCO-JSON results file") + parser.add_argument("--project", default=ROOT / "runs/val", help="save to project/name") + parser.add_argument("--name", default="exp", help="save to project/name") + parser.add_argument("--exist-ok", action="store_true", help="existing project/name ok, do not increment") + parser.add_argument("--half", action="store_true", help="use FP16 half-precision inference") + parser.add_argument("--dnn", action="store_true", help="use OpenCV DNN for ONNX inference") opt = parser.parse_args() opt.data = check_yaml(opt.data) # check YAML - opt.save_json |= opt.data.endswith('coco.yaml') + opt.save_json |= opt.data.endswith("coco.yaml") opt.save_txt |= opt.save_hybrid print_args(vars(opt)) return opt def main(opt): - check_requirements(ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) - if opt.task in ('train', 'val', 'test'): # run normally + if opt.task in ("train", "val", "test"): # run normally if opt.conf_thres > 0.001: # https://github.com/ultralytics/yolov5/issues/1466 - LOGGER.info(f'WARNING ⚠️ confidence threshold {opt.conf_thres} > 0.001 produces invalid results') + LOGGER.info(f"WARNING ⚠️ confidence threshold {opt.conf_thres} > 0.001 produces invalid results") if opt.save_hybrid: - LOGGER.info('WARNING ⚠️ --save-hybrid will return high mAP from hybrid labels, not from predictions alone') + LOGGER.info("WARNING ⚠️ --save-hybrid will return high mAP from hybrid labels, not from predictions alone") run(**vars(opt)) else: weights = opt.weights if isinstance(opt.weights, list) else [opt.weights] - opt.half = torch.cuda.is_available() and opt.device != 'cpu' # FP16 for fastest results - if opt.task == 'speed': # speed benchmarks + opt.half = torch.cuda.is_available() and opt.device != "cpu" # FP16 for fastest results + if opt.task == "speed": # speed benchmarks # python val.py --task speed --data coco.yaml --batch 1 --weights yolov5n.pt yolov5s.pt... opt.conf_thres, opt.iou_thres, opt.save_json = 0.25, 0.45, False for opt.weights in weights: run(**vars(opt), plots=False) - elif opt.task == 'study': # speed vs mAP benchmarks + elif opt.task == "study": # speed vs mAP benchmarks # python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n.pt yolov5s.pt... for opt.weights in weights: - f = f'study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt' # filename to save to + f = f"study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt" # filename to save to x, y = list(range(256, 1536 + 128, 128)), [] # x axis (image sizes), y axis for opt.imgsz in x: # img-size - LOGGER.info(f'\nRunning {f} --imgsz {opt.imgsz}...') + LOGGER.info(f"\nRunning {f} --imgsz {opt.imgsz}...") r, _, t = run(**vars(opt), plots=False) y.append(r + t) # results and times - np.savetxt(f, y, fmt='%10.4g') # save - subprocess.run(['zip', '-r', 'study.zip', 'study_*.txt']) + np.savetxt(f, y, fmt="%10.4g") # save + subprocess.run(["zip", "-r", "study.zip", "study_*.txt"]) plot_val_study(x=x) # plot else: raise NotImplementedError(f'--task {opt.task} not in ("train", "val", "test", "speed", "study")') -if __name__ == '__main__': +if __name__ == "__main__": opt = parse_opt() main(opt) From 9ec21264844dfd1c4446a8d1b70b59c5fcf09131 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 7 Jan 2024 01:42:53 +0100 Subject: [PATCH 1044/1185] Update links.yml (#2167) * Update links.yml * Update links.yml --- .github/workflows/links.yml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 05408fd622..1c7b28257d 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -33,7 +33,15 @@ jobs: timeout_minutes: 5 retry_wait_seconds: 60 max_attempts: 3 - command: lychee --accept 403,429,500,502,999 --exclude-loopback --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' + command: | + lychee + --accept 403,429,500,502,999 + --exclude-loopback + --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' + --exclude-path '**/ci.yaml' + --github-token ${{ secrets.GITHUB_TOKEN }} + './**/*.md' + './**/*.html' - name: Test Markdown, HTML, YAML, Python and Notebook links with retry if: github.event_name == 'workflow_dispatch' @@ -42,4 +50,16 @@ jobs: timeout_minutes: 5 retry_wait_seconds: 60 max_attempts: 3 - command: lychee --accept 429,999 --exclude-loopback --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' --exclude-path '**/ci.yaml' --exclude-mail --github-token ${{ secrets.GITHUB_TOKEN }} './**/*.md' './**/*.html' './**/*.yml' './**/*.yaml' './**/*.py' './**/*.ipynb' + command: | + lychee + --accept 429,999 + --exclude-loopback + --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' + --exclude-path '**/ci.yaml' + --github-token ${{ secrets.GITHUB_TOKEN }} + './**/*.md' + './**/*.html' + './**/*.yml' + './**/*.yaml' + './**/*.py' + './**/*.ipynb' From a39950b57cb605697f0c1dde5affeb3fb8850abc Mon Sep 17 00:00:00 2001 From: Paula Derrenger <107626595+pderrenger@users.noreply.github.com> Date: Mon, 8 Jan 2024 01:26:28 +0100 Subject: [PATCH 1045/1185] Update Actions with Lychee and GitHub Token (#2168) * Update Ultralytics Actions * Update format.yml --------- Co-authored-by: Glenn Jocher --- .github/workflows/format.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 27b2c7d890..8d623f4f6e 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -7,7 +7,7 @@ name: Ultralytics Actions on: push: branches: [main,master] - pull_request: + pull_request_target: branches: [main,master] jobs: @@ -17,7 +17,9 @@ jobs: - name: Run Ultralytics Formatting uses: ultralytics/actions@main with: + token: ${{ secrets.GITHUB_TOKEN }} # automatically generated python: true docstrings: true markdown: true spelling: true + links: true From e567c797686e1798e1d4713083950b3642d7732b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 8 Jan 2024 18:52:40 +0100 Subject: [PATCH 1046/1185] Update links.yml (#2173) --- .github/workflows/links.yml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 1c7b28257d..cb0ad264cc 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -34,13 +34,13 @@ jobs: retry_wait_seconds: 60 max_attempts: 3 command: | - lychee - --accept 403,429,500,502,999 - --exclude-loopback - --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' - --exclude-path '**/ci.yaml' - --github-token ${{ secrets.GITHUB_TOKEN }} - './**/*.md' + lychee \ + --accept 403,429,500,502,999 \ + --exclude-loopback \ + --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ + --exclude-path '**/ci.yaml' \ + --github-token ${{ secrets.GITHUB_TOKEN }} \ + './**/*.md' \ './**/*.html' - name: Test Markdown, HTML, YAML, Python and Notebook links with retry @@ -51,15 +51,15 @@ jobs: retry_wait_seconds: 60 max_attempts: 3 command: | - lychee - --accept 429,999 - --exclude-loopback - --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' - --exclude-path '**/ci.yaml' - --github-token ${{ secrets.GITHUB_TOKEN }} - './**/*.md' - './**/*.html' - './**/*.yml' - './**/*.yaml' - './**/*.py' + lychee \ + --accept 429,999 \ + --exclude-loopback \ + --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ + --exclude-path '**/ci.yaml' \ + --github-token ${{ secrets.GITHUB_TOKEN }} \ + './**/*.md' \ + './**/*.html' \ + './**/*.yml' \ + './**/*.yaml' \ + './**/*.py' \ './**/*.ipynb' From 2960a2dab213cfc5e7581172001ce971065bba07 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 13 Jan 2024 22:13:19 +0100 Subject: [PATCH 1047/1185] Python refactor and simplification (#2174) * Python code cleanup * Auto-format by Ultralytics actions --------- Co-authored-by: UltralyticsAssistant --- export.py | 2 +- models/common.py | 16 ++-- utils/downloads.py | 4 +- utils/loggers/clearml/README.md | 12 +-- utils/loggers/clearml/clearml_utils.py | 48 +++++----- utils/loggers/comet/__init__.py | 120 ++++++++++++------------- utils/loggers/comet/comet_utils.py | 34 ++++--- utils/loggers/wandb/wandb_utils.py | 45 +++++----- utils/segment/metrics.py | 3 +- 9 files changed, 140 insertions(+), 144 deletions(-) diff --git a/export.py b/export.py index 8cacd97201..dd45e5ebc1 100644 --- a/export.py +++ b/export.py @@ -546,7 +546,7 @@ def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): "--quantize_uint8" if int8 else "", "--output_node_names=Identity,Identity_1,Identity_2,Identity_3", str(f_pb), - str(f), + f, ] subprocess.run([arg for arg in args if arg], check=True) diff --git a/models/common.py b/models/common.py index d45b99cfd9..6e533b56ec 100644 --- a/models/common.py +++ b/models/common.py @@ -847,11 +847,17 @@ def pandas(self): def tolist(self): # return a list of Detections objects, i.e. 'for result in results.tolist():' r = range(self.n) # iterable - x = [Detections([self.ims[i]], [self.pred[i]], [self.files[i]], self.times, self.names, self.s) for i in r] - # for d in x: - # for k in ['ims', 'pred', 'xyxy', 'xyxyn', 'xywh', 'xywhn']: - # setattr(d, k, getattr(d, k)[0]) # pop out of list - return x + return [ + Detections( + [self.ims[i]], + [self.pred[i]], + [self.files[i]], + self.times, + self.names, + self.s, + ) + for i in r + ] def print(self): LOGGER.info(self.__str__()) diff --git a/utils/downloads.py b/utils/downloads.py index 59e9325a7e..e35922d159 100644 --- a/utils/downloads.py +++ b/utils/downloads.py @@ -24,9 +24,7 @@ def is_url(url, check=True): def gsutil_getsize(url=""): # gs://bucket/file size https://cloud.google.com/storage/docs/gsutil/commands/du output = subprocess.check_output(["gsutil", "du", url], shell=True, encoding="utf-8") - if output: - return int(output.split()[0]) - return 0 + return int(output.split()[0]) if output else 0 def url_getsize(url="https://ultralytics.com/images/bus.jpg"): diff --git a/utils/loggers/clearml/README.md b/utils/loggers/clearml/README.md index d228ebfde3..e5eca05c24 100644 --- a/utils/loggers/clearml/README.md +++ b/utils/loggers/clearml/README.md @@ -34,15 +34,15 @@ Either sign up for free to the [ClearML Hosted Service](https://cutt.ly/yolov5-t 1. Install the `clearml` python package: - ```bash - pip install clearml - ``` + ```bash + pip install clearml + ``` 2. 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: - ```bash - clearml-init - ``` + ```bash + clearml-init + ``` That's it! You're done 😎 diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py index df4c945202..7e69fc6567 100644 --- a/utils/loggers/clearml/clearml_utils.py +++ b/utils/loggers/clearml/clearml_utils.py @@ -29,7 +29,7 @@ def construct_dataset(clearml_info_string): "More than one yaml file was found in the dataset root, cannot determine which one contains " "the dataset definition this way." ) - elif len(yaml_filenames) == 0: + elif not yaml_filenames: raise ValueError( "No yaml definition found in dataset root path, check that there is a correct yaml file " "inside the dataset root path." @@ -43,7 +43,7 @@ def construct_dataset(clearml_info_string): {"train", "test", "val", "nc", "names"} ), "The right keys were not found in the yaml file, make sure it at least has the following keys: ('train', 'test', 'val', 'nc', 'names')" - data_dict = dict() + data_dict = {} data_dict["train"] = ( str((dataset_root_path / dataset_definition["train"]).resolve()) if dataset_definition["train"] else None ) @@ -148,24 +148,26 @@ def log_image_with_boxes(self, image_path, boxes, class_names, image, conf_thres class_names (dict): dict containing mapping of class int to class name image (Tensor): A torch tensor containing the actual image data """ - if len(self.current_epoch_logged_images) < self.max_imgs_to_log_per_epoch and self.current_epoch >= 0: - # Log every bbox_interval times and deduplicate for any intermittend extra eval runs - if self.current_epoch % self.bbox_interval == 0 and image_path not in self.current_epoch_logged_images: - im = np.ascontiguousarray(np.moveaxis(image.mul(255).clamp(0, 255).byte().cpu().numpy(), 0, 2)) - annotator = Annotator(im=im, pil=True) - for i, (conf, class_nr, box) in enumerate(zip(boxes[:, 4], boxes[:, 5], boxes[:, :4])): - color = colors(i) - - class_name = class_names[int(class_nr)] - confidence_percentage = round(float(conf) * 100, 2) - label = f"{class_name}: {confidence_percentage}%" - - if conf > conf_threshold: - annotator.rectangle(box.cpu().numpy(), outline=color) - annotator.box_label(box.cpu().numpy(), label=label, color=color) - - annotated_image = annotator.result() - self.task.get_logger().report_image( - title="Bounding Boxes", series=image_path.name, iteration=self.current_epoch, image=annotated_image - ) - self.current_epoch_logged_images.add(image_path) + if ( + len(self.current_epoch_logged_images) < self.max_imgs_to_log_per_epoch + and self.current_epoch >= 0 + and (self.current_epoch % self.bbox_interval == 0 and image_path not in self.current_epoch_logged_images) + ): + im = np.ascontiguousarray(np.moveaxis(image.mul(255).clamp(0, 255).byte().cpu().numpy(), 0, 2)) + annotator = Annotator(im=im, pil=True) + for i, (conf, class_nr, box) in enumerate(zip(boxes[:, 4], boxes[:, 5], boxes[:, :4])): + color = colors(i) + + class_name = class_names[int(class_nr)] + confidence_percentage = round(float(conf) * 100, 2) + label = f"{class_name}: {confidence_percentage}%" + + if conf > conf_threshold: + annotator.rectangle(box.cpu().numpy(), outline=color) + annotator.box_label(box.cpu().numpy(), label=label, color=color) + + annotated_image = annotator.result() + self.task.get_logger().report_image( + title="Bounding Boxes", series=image_path.name, iteration=self.current_epoch, image=annotated_image + ) + self.current_epoch_logged_images.add(image_path) diff --git a/utils/loggers/comet/__init__.py b/utils/loggers/comet/__init__.py index 36eed15a2c..f1d355d290 100644 --- a/utils/loggers/comet/__init__.py +++ b/utils/loggers/comet/__init__.py @@ -166,34 +166,33 @@ def __init__(self, opt, hyp, run_id=None, job_type="Training", **experiment_kwar def _get_experiment(self, mode, experiment_id=None): if mode == "offline": + return ( + comet_ml.ExistingOfflineExperiment( + previous_experiment=experiment_id, + **self.default_experiment_kwargs, + ) + if experiment_id is not None + else comet_ml.OfflineExperiment( + **self.default_experiment_kwargs, + ) + ) + try: if experiment_id is not None: - return comet_ml.ExistingOfflineExperiment( + return comet_ml.ExistingExperiment( previous_experiment=experiment_id, **self.default_experiment_kwargs, ) - return comet_ml.OfflineExperiment( - **self.default_experiment_kwargs, - ) + return comet_ml.Experiment(**self.default_experiment_kwargs) - else: - try: - if experiment_id is not None: - return comet_ml.ExistingExperiment( - previous_experiment=experiment_id, - **self.default_experiment_kwargs, - ) - - return comet_ml.Experiment(**self.default_experiment_kwargs) - - except ValueError: - logger.warning( - "COMET WARNING: " - "Comet credentials have not been set. " - "Comet will default to offline logging. " - "Please set your credentials to enable online logging." - ) - return self._get_experiment("offline", experiment_id) + except ValueError: + logger.warning( + "COMET WARNING: " + "Comet credentials have not been set. " + "Comet will default to offline logging. " + "Please set your credentials to enable online logging." + ) + return self._get_experiment("offline", experiment_id) return @@ -242,10 +241,7 @@ def check_dataset(self, data_file): path = data_config.get("path") if path and path.startswith(COMET_PREFIX): path = data_config["path"].replace(COMET_PREFIX, "") - data_dict = self.download_dataset_artifact(path) - - return data_dict - + return self.download_dataset_artifact(path) self.log_asset(self.opt.data, metadata={"type": "data-config-file"}) return check_dataset(data_file) @@ -269,24 +265,22 @@ def log_predictions(self, image, labelsn, path, shape, predn): self.log_image(native_scale_image, name=image_name) self.logged_image_names.append(image_name) - metadata = [] - for cls, *xyxy in filtered_labels.tolist(): - metadata.append( - { - "label": f"{self.class_names[int(cls)]}-gt", - "score": 100, - "box": {"x": xyxy[0], "y": xyxy[1], "x2": xyxy[2], "y2": xyxy[3]}, - } - ) - for *xyxy, conf, cls in filtered_detections.tolist(): - metadata.append( - { - "label": f"{self.class_names[int(cls)]}", - "score": conf * 100, - "box": {"x": xyxy[0], "y": xyxy[1], "x2": xyxy[2], "y2": xyxy[3]}, - } - ) - + metadata = [ + { + "label": f"{self.class_names[int(cls)]}-gt", + "score": 100, + "box": {"x": xyxy[0], "y": xyxy[1], "x2": xyxy[2], "y2": xyxy[3]}, + } + for cls, *xyxy in filtered_labels.tolist() + ] + metadata.extend( + { + "label": f"{self.class_names[int(cls)]}", + "score": conf * 100, + "box": {"x": xyxy[0], "y": xyxy[1], "x2": xyxy[2], "y2": xyxy[3]}, + } + for *xyxy, conf, cls in filtered_detections.tolist() + ) self.metadata_dict[image_name] = metadata self.logged_images_count += 1 @@ -398,9 +392,8 @@ def on_pretrain_routine_end(self, paths): for path in paths: self.log_asset(str(path)) - if self.upload_dataset: - if not self.resume: - self.upload_dataset_artifact() + if self.upload_dataset and not self.resume: + self.upload_dataset_artifact() return @@ -477,23 +470,22 @@ def on_val_batch_end(self, batch_i, images, targets, paths, shapes, outputs): return def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix): - if self.comet_log_per_class_metrics: - if self.num_classes > 1: - for i, c in enumerate(ap_class): - class_name = self.class_names[c] - self.experiment.log_metrics( - { - "mAP@.5": ap50[i], - "mAP@.5:.95": ap[i], - "precision": p[i], - "recall": r[i], - "f1": f1[i], - "true_positives": tp[i], - "false_positives": fp[i], - "support": nt[c], - }, - prefix=class_name, - ) + if self.comet_log_per_class_metrics and self.num_classes > 1: + for i, c in enumerate(ap_class): + class_name = self.class_names[c] + self.experiment.log_metrics( + { + "mAP@.5": ap50[i], + "mAP@.5:.95": ap[i], + "precision": p[i], + "recall": r[i], + "f1": f1[i], + "true_positives": tp[i], + "false_positives": fp[i], + "support": nt[c], + }, + prefix=class_name, + ) if self.comet_log_confusion_matrix: epoch = self.experiment.curr_epoch diff --git a/utils/loggers/comet/comet_utils.py b/utils/loggers/comet/comet_utils.py index 99477f85d9..afa5964645 100644 --- a/utils/loggers/comet/comet_utils.py +++ b/utils/loggers/comet/comet_utils.py @@ -4,7 +4,7 @@ try: import comet_ml -except (ModuleNotFoundError, ImportError): +except ImportError: comet_ml = None import yaml @@ -109,14 +109,13 @@ def check_comet_weights(opt): if comet_ml is None: return - if isinstance(opt.weights, str): - if opt.weights.startswith(COMET_PREFIX): - api = comet_ml.API() - resource = urlparse(opt.weights) - experiment_path = f"{resource.netloc}{resource.path}" - experiment = api.get(experiment_path) - download_model_checkpoint(opt, experiment) - return True + if isinstance(opt.weights, str) and opt.weights.startswith(COMET_PREFIX): + api = comet_ml.API() + resource = urlparse(opt.weights) + experiment_path = f"{resource.netloc}{resource.path}" + experiment = api.get(experiment_path) + download_model_checkpoint(opt, experiment) + return True return None @@ -136,15 +135,14 @@ def check_comet_resume(opt): if comet_ml is None: return - if isinstance(opt.resume, str): - if opt.resume.startswith(COMET_PREFIX): - api = comet_ml.API() - resource = urlparse(opt.resume) - experiment_path = f"{resource.netloc}{resource.path}" - experiment = api.get(experiment_path) - set_opt_parameters(opt, experiment) - download_model_checkpoint(opt, experiment) + if isinstance(opt.resume, str) and opt.resume.startswith(COMET_PREFIX): + api = comet_ml.API() + resource = urlparse(opt.resume) + experiment_path = f"{resource.netloc}{resource.path}" + experiment = api.get(experiment_path) + set_opt_parameters(opt, experiment) + download_model_checkpoint(opt, experiment) - return True + return True return None diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py index edbb0b5e2b..04f19ef8e6 100644 --- a/utils/loggers/wandb/wandb_utils.py +++ b/utils/loggers/wandb/wandb_utils.py @@ -65,28 +65,23 @@ def __init__(self, opt, run_id=None, job_type="Training"): self.max_imgs_to_log = 16 self.data_dict = None if self.wandb: - self.wandb_run = ( - wandb.init( - config=opt, - resume="allow", - project="YOLOv3" if opt.project == "runs/train" else Path(opt.project).stem, - entity=opt.entity, - name=opt.name if opt.name != "exp" else None, - job_type=job_type, - id=run_id, - allow_val_change=True, - ) - if not wandb.run - else wandb.run + self.wandb_run = wandb.run or wandb.init( + config=opt, + resume="allow", + project="YOLOv3" if opt.project == "runs/train" else Path(opt.project).stem, + entity=opt.entity, + name=opt.name if opt.name != "exp" else None, + job_type=job_type, + id=run_id, + allow_val_change=True, ) - if self.wandb_run: - if self.job_type == "Training": - if isinstance(opt.data, dict): - # This means another dataset manager has already processed the dataset info (e.g. ClearML) - # and they will have stored the already processed dict in opt.data - self.data_dict = opt.data - self.setup_training(opt) + if self.wandb_run and self.job_type == "Training": + if isinstance(opt.data, dict): + # This means another dataset manager has already processed the dataset info (e.g. ClearML) + # and they will have stored the already processed dict in opt.data + self.data_dict = opt.data + self.setup_training(opt) def setup_training(self, opt): """ @@ -133,7 +128,7 @@ def log_model(self, path, opt, epoch, fitness_score, best_model=False): best_model (boolean) -- Boolean representing if the current checkpoint is the best yet. """ model_artifact = wandb.Artifact( - "run_" + wandb.run.id + "_model", + f"run_{wandb.run.id}_model", type="model", metadata={ "original_url": str(path), @@ -146,7 +141,13 @@ def log_model(self, path, opt, epoch, fitness_score, best_model=False): ) model_artifact.add_file(str(path / "last.pt"), name="last.pt") wandb.log_artifact( - model_artifact, aliases=["latest", "last", "epoch " + str(self.current_epoch), "best" if best_model else ""] + model_artifact, + aliases=[ + "latest", + "last", + f"epoch {str(self.current_epoch)}", + "best" if best_model else "", + ], ) LOGGER.info(f"Saving model artifact on epoch {epoch + 1}") diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py index 978017bd31..f85baebacd 100644 --- a/utils/segment/metrics.py +++ b/utils/segment/metrics.py @@ -35,7 +35,7 @@ def ap_per_class_box_and_mask( tp_m, conf, pred_cls, target_cls, plot=plot, save_dir=save_dir, names=names, prefix="Mask" )[2:] - results = { + return { "boxes": { "p": results_boxes[0], "r": results_boxes[1], @@ -51,7 +51,6 @@ def ap_per_class_box_and_mask( "ap_class": results_masks[4], }, } - return results class Metric: From 0a7ed1131ae0a6dd51b9671babf88bf85fcada99 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 13 Jan 2024 22:42:28 +0100 Subject: [PATCH 1048/1185] Update links.yml to --scheme 'https' (#2175) --- .github/workflows/links.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index cb0ad264cc..d00cb61fe1 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -35,6 +35,7 @@ jobs: max_attempts: 3 command: | lychee \ + --scheme 'https' \ --accept 403,429,500,502,999 \ --exclude-loopback \ --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ @@ -52,6 +53,7 @@ jobs: max_attempts: 3 command: | lychee \ + --scheme 'https' \ --accept 429,999 \ --exclude-loopback \ --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ From 8fc7ecc7425400c45a38e892a57ae7f9a321fea8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 00:03:33 +0100 Subject: [PATCH 1049/1185] Update jax requirement from <=0.4.21 to <=0.4.23 (#2171) Updates the requirements on [jax](https://github.com/google/jax) to permit the latest version. - [Release notes](https://github.com/google/jax/releases) - [Changelog](https://github.com/google/jax/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/jax/compare/jaxlib-v0.1.32...jax-v0.4.23) --- updated-dependencies: - dependency-name: jax dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 80bb50a4cc..7834eb63b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,7 +99,7 @@ export = [ "coremltools>=7.0", # CoreML export "openvino-dev>=2023.0", # OpenVINO export "tensorflow<=2.13.1", # TF bug https://github.com/ultralytics/ultralytics/issues/5161 - "jax<=0.4.21", # tensorflowjs bug https://github.com/google/jax/issues/18978 + "jax<=0.4.23", # tensorflowjs bug https://github.com/google/jax/issues/18978 "jaxlib<=0.4.21", # tensorflowjs bug https://github.com/google/jax/issues/18978 "tensorflowjs>=3.9.0", # TF.js export, automatically installs tensorflow ] From 2ea3b1755e25c291841047a1285c85371f85750f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 00:04:17 +0100 Subject: [PATCH 1050/1185] Update jaxlib requirement from <=0.4.21 to <=0.4.23 (#2170) * Update jaxlib requirement from <=0.4.21 to <=0.4.23 Updates the requirements on [jaxlib](https://github.com/google/jax) to permit the latest version. - [Release notes](https://github.com/google/jax/releases) - [Changelog](https://github.com/google/jax/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/jax/compare/jaxlib-v0.1.32...jaxlib-v0.4.23) --- updated-dependencies: - dependency-name: jaxlib dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Update pyproject.toml --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- pyproject.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7834eb63b1..9abc3093fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,11 +96,9 @@ dev = [ ] export = [ "onnx>=1.12.0", # ONNX export - "coremltools>=7.0", # CoreML export + "coremltools>=7.0; platform_system != 'Windows'", # CoreML only supported on macOS and Linux "openvino-dev>=2023.0", # OpenVINO export "tensorflow<=2.13.1", # TF bug https://github.com/ultralytics/ultralytics/issues/5161 - "jax<=0.4.23", # tensorflowjs bug https://github.com/google/jax/issues/18978 - "jaxlib<=0.4.21", # tensorflowjs bug https://github.com/google/jax/issues/18978 "tensorflowjs>=3.9.0", # TF.js export, automatically installs tensorflow ] # tensorflow>=2.4.1,<=2.13.1 # TF exports (-cpu, -aarch64, -macos) From 8c1d74ddee674b9dfe6b8e5715e7735d4fe53d67 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 17 Jan 2024 00:05:50 +0100 Subject: [PATCH 1051/1185] Delete .gitattributes (#2176) --- .gitattributes | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index dad4239eba..0000000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# this drop notebooks from GitHub language stats -*.ipynb linguist-vendored From 25e5c6a470938e2072798049db95a875c27b2cc4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 17 Jan 2024 01:19:11 +0100 Subject: [PATCH 1052/1185] Update requirements.txt to `numpy>=1.23.5` (#2177) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5bbe3509e2..59020cce86 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ # Base ------------------------------------------------------------------------ gitpython>=3.1.30 matplotlib>=3.3 -numpy>=1.22.2 +numpy>=1.23.5 opencv-python>=4.1.1 Pillow>=10.0.1 psutil # system resources From a11f1d5cd4445117ed6879dca57e77f2efa19317 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:37:41 +0100 Subject: [PATCH 1053/1185] Update PR from base branch master Updates the requirements on [tensorflow](https://github.com/tensorflow/tensorflow) to permit the latest version. - [Release notes](https://github.com/tensorflow/tensorflow/releases) - [Changelog](https://github.com/tensorflow/tensorflow/blob/master/RELEASE.md) - [Commits](https://github.com/tensorflow/tensorflow/commits) --- updated-dependencies: - dependency-name: tensorflow dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9abc3093fd..2fcc344d66 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,7 @@ export = [ "onnx>=1.12.0", # ONNX export "coremltools>=7.0; platform_system != 'Windows'", # CoreML only supported on macOS and Linux "openvino-dev>=2023.0", # OpenVINO export - "tensorflow<=2.13.1", # TF bug https://github.com/ultralytics/ultralytics/issues/5161 + "tensorflow<=2.15.0.post1", # TF bug https://github.com/ultralytics/ultralytics/issues/5161 "tensorflowjs>=3.9.0", # TF.js export, automatically installs tensorflow ] # tensorflow>=2.4.1,<=2.13.1 # TF exports (-cpu, -aarch64, -macos) From de1d5fd98485d0a240550b533b4dfd9a1133cc54 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 17 Jan 2024 11:42:54 +0100 Subject: [PATCH 1054/1185] Update pyproject.toml (#2178) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2fcc344d66..9abc3093fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,7 @@ export = [ "onnx>=1.12.0", # ONNX export "coremltools>=7.0; platform_system != 'Windows'", # CoreML only supported on macOS and Linux "openvino-dev>=2023.0", # OpenVINO export - "tensorflow<=2.15.0.post1", # TF bug https://github.com/ultralytics/ultralytics/issues/5161 + "tensorflow<=2.13.1", # TF bug https://github.com/ultralytics/ultralytics/issues/5161 "tensorflowjs>=3.9.0", # TF.js export, automatically installs tensorflow ] # tensorflow>=2.4.1,<=2.13.1 # TF exports (-cpu, -aarch64, -macos) From d5717e791c07601a5b439669a130eb51522cf011 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 18 Jan 2024 17:53:03 +0100 Subject: [PATCH 1055/1185] YAML reformat (#2180) * YAML reformat * Auto-format by Ultralytics actions --------- Co-authored-by: UltralyticsAssistant --- .github/workflows/ci-testing.yml | 24 ++-- .github/workflows/codeql-analysis.yml | 4 +- .github/workflows/docker.yml | 2 +- .github/workflows/format.yml | 6 +- .github/workflows/links.yml | 2 +- .github/workflows/stale.yml | 6 +- README.md | 2 +- README.zh-CN.md | 78 ++++++------- data/Argoverse.yaml | 10 +- data/GlobalWheat2020.yaml | 4 +- data/ImageNet.yaml | 10 +- data/SKU-110K.yaml | 10 +- data/VisDrone.yaml | 10 +- data/coco.yaml | 10 +- data/coco128-seg.yaml | 10 +- data/coco128.yaml | 10 +- data/hyps/hyp.no-augmentation.yaml | 56 ++++----- data/hyps/hyp.scratch-high.yaml | 56 ++++----- data/hyps/hyp.scratch-low.yaml | 56 ++++----- data/hyps/hyp.scratch-med.yaml | 56 ++++----- data/objects365.yaml | 8 +- data/voc.yaml | 2 - data/xView.yaml | 8 +- models/hub/anchors.yaml | 63 +++++----- models/hub/yolov5-bifpn.yaml | 65 ++++++----- models/hub/yolov5-fpn.yaml | 55 ++++----- models/hub/yolov5-p2.yaml | 87 +++++++------- models/hub/yolov5-p34.yaml | 55 ++++----- models/hub/yolov5-p6.yaml | 91 ++++++++------- models/hub/yolov5-p7.yaml | 97 +++++++-------- models/hub/yolov5-panet.yaml | 65 ++++++----- models/hub/yolov5l6.yaml | 97 +++++++-------- models/hub/yolov5m6.yaml | 97 +++++++-------- models/hub/yolov5n6.yaml | 97 +++++++-------- models/hub/yolov5s-LeakyReLU.yaml | 67 +++++------ models/hub/yolov5s-ghost.yaml | 65 ++++++----- models/hub/yolov5s-transformer.yaml | 65 ++++++----- models/hub/yolov5s6.yaml | 97 +++++++-------- models/hub/yolov5x6.yaml | 97 +++++++-------- models/segment/yolov5l-seg.yaml | 65 ++++++----- models/segment/yolov5m-seg.yaml | 65 ++++++----- models/segment/yolov5n-seg.yaml | 65 ++++++----- models/segment/yolov5s-seg.yaml | 65 ++++++----- models/segment/yolov5x-seg.yaml | 65 ++++++----- models/yolov3-spp.yaml | 73 ++++++------ models/yolov3-tiny.yaml | 55 ++++----- models/yolov3.yaml | 73 ++++++------ models/yolov5l.yaml | 65 ++++++----- models/yolov5m.yaml | 65 ++++++----- models/yolov5n.yaml | 65 ++++++----- models/yolov5s.yaml | 65 ++++++----- models/yolov5x.yaml | 65 ++++++----- utils/loggers/comet/optimizer_config.json | 136 +++++----------------- 53 files changed, 1308 insertions(+), 1379 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index e6ab9b7d57..fbab5a29d8 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -9,7 +9,7 @@ on: pull_request: branches: [master] schedule: - - cron: '0 0 * * *' # runs at 00:00 UTC every day + - cron: "0 0 * * *" # runs at 00:00 UTC every day jobs: Tests: @@ -18,26 +18,26 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest] # macos-latest bug https://github.com/ultralytics/yolov5/pull/9049 - python-version: ['3.11'] + os: [ubuntu-latest, windows-latest] # macos-latest bug https://github.com/ultralytics/yolov5/pull/9049 + python-version: ["3.11"] model: [yolov5n] include: - os: ubuntu-latest - python-version: '3.8' # '3.6.8' min + python-version: "3.8" # '3.6.8' min model: yolov5n - os: ubuntu-latest - python-version: '3.9' + python-version: "3.9" model: yolov5n - os: ubuntu-latest - python-version: '3.8' # torch 1.8.0 requires python >=3.6, <=3.8 + python-version: "3.8" # torch 1.8.0 requires python >=3.6, <=3.8 model: yolov5n - torch: '1.8.0' # min torch version CI https://pypi.org/project/torchvision/ + torch: "1.8.0" # min torch version CI https://pypi.org/project/torchvision/ steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - cache: 'pip' # caching pip dependencies + cache: "pip" # caching pip dependencies - name: Install requirements run: | python -m pip install --upgrade pip wheel @@ -46,13 +46,13 @@ jobs: else pip install -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cpu fi - shell: bash # for Windows compatibility + shell: bash # for Windows compatibility - name: Check environment run: | yolo checks pip list - name: Test detection - shell: bash # for Windows compatibility + shell: bash # for Windows compatibility run: | # export PYTHONPATH="$PWD" # to run '$ python *.py' files in subdirectories m=${{ matrix.model }} # official weights @@ -78,7 +78,7 @@ jobs: torch.jit.trace(model, [im]) EOF - name: Test segmentation - shell: bash # for Windows compatibility + shell: bash # for Windows compatibility run: | m=${{ matrix.model }}-seg # official weights b=runs/train-seg/exp/weights/best # best.pt checkpoint @@ -92,7 +92,7 @@ jobs: done done - name: Test classification - shell: bash # for Windows compatibility + shell: bash # for Windows compatibility run: | m=${{ matrix.model }}-cls.pt # official weights b=runs/train-cls/exp/weights/best.pt # best.pt checkpoint diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 11db0dceca..2897fd0b45 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -5,7 +5,7 @@ name: "CodeQL" on: schedule: - - cron: '0 0 1 * *' # Runs at 00:00 UTC on the 1st of every month + - cron: "0 0 1 * *" # Runs at 00:00 UTC on the 1st of every month workflow_dispatch: jobs: @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - language: ['python'] + language: ["python"] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more: # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 46d263f596..c3939ab633 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -5,7 +5,7 @@ name: Publish Docker Images on: push: - branches: [ master ] + branches: [master] workflow_dispatch: jobs: diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 8d623f4f6e..3caff1624e 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -6,9 +6,9 @@ name: Ultralytics Actions on: push: - branches: [main,master] + branches: [main, master] pull_request_target: - branches: [main,master] + branches: [main, master] jobs: format: @@ -17,7 +17,7 @@ jobs: - name: Run Ultralytics Formatting uses: ultralytics/actions@main with: - token: ${{ secrets.GITHUB_TOKEN }} # automatically generated + token: ${{ secrets.GITHUB_TOKEN }} # automatically generated python: true docstrings: true markdown: true diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index d00cb61fe1..8259160a87 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -12,7 +12,7 @@ name: Check Broken links on: workflow_dispatch: schedule: - - cron: '0 0 * * *' # runs at 00:00 UTC every day + - cron: "0 0 * * *" # runs at 00:00 UTC every day jobs: Links: diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index c0b1f405c7..cda1acda0c 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -3,7 +3,7 @@ name: Close stale issues on: schedule: - - cron: '0 0 * * *' # Runs at 00:00 UTC every day + - cron: "0 0 * * *" # Runs at 00:00 UTC every day jobs: stale: @@ -43,5 +43,5 @@ jobs: days-before-issue-close: 10 days-before-pr-stale: 90 days-before-pr-close: 30 - exempt-issue-labels: 'documentation,tutorial,TODO' - operations-per-run: 300 # The maximum number of operations per run, used to control rate limiting. + exempt-issue-labels: "documentation,tutorial,TODO" + operations-per-run: 300 # The maximum number of operations per run, used to control rate limiting. diff --git a/README.md b/README.md index 00cc1abf22..a6401ae529 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - -| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | +| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | | :--------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | | Label and export your custom datasets directly to YOLOv3 for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | Automatically track, visualize and even remotely train YOLOv3 using [ClearML](https://cutt.ly/yolov5-readme-clearml) (open-source!) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet2) lets you save YOLOv3 models, resume training, and interactively visualise and debug predictions | Run YOLOv3 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | diff --git a/README.zh-CN.md b/README.zh-CN.md index e9defd022e..22b4374654 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -179,8 +179,8 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - -| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | -| :--------------------------------------------------------------------------------: | :-------------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | +| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | +| :--------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | | 将您的自定义数据集进行标注并直接导出到 YOLOv3 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv3 [ClearML](https://cutt.ly/yolov5-readme-clearml)(开源!) | 永远免费,[Comet](https://bit.ly/yolov5-readme-comet2)可让您保存 YOLOv3 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv3 推理的速度最高可提高6倍 | ##
Ultralytics HUB
@@ -212,19 +212,19 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结 ### 预训练模型 -| 模型 | 尺寸
(像素) | mAPval
50-95 | mAPval
50 | 推理速度
CPU b1
(ms) | 推理速度
V100 b1
(ms) | 速度
V100 b32
(ms) | 参数量
(M) | FLOPs
@640 (B) | -| ---------------------------------------------------------------------------------------------- | --------------- | -------------------- | ----------------- | --------------------------- | ---------------------------- | --------------------------- | --------------- | ---------------------- | -| [YOLOv5n](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n.pt) | 640 | 28.0 | 45.7 | **45** | **6.3** | **0.6** | **1.9** | **4.5** | -| [YOLOv5s](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt) | 640 | 37.4 | 56.8 | 98 | 6.4 | 0.9 | 7.2 | 16.5 | -| [YOLOv5m](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m.pt) | 640 | 45.4 | 64.1 | 224 | 8.2 | 1.7 | 21.2 | 49.0 | -| [YOLOv5l](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l.pt) | 640 | 49.0 | 67.3 | 430 | 10.1 | 2.7 | 46.5 | 109.1 | -| [YOLOv5x](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x.pt) | 640 | 50.7 | 68.9 | 766 | 12.1 | 4.8 | 86.7 | 205.7 | -| | | | | | | | | | -| [YOLOv5n6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n6.pt) | 1280 | 36.0 | 54.4 | 153 | 8.1 | 2.1 | 3.2 | 4.6 | -| [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | -| [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | -| [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | -| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+[TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- | +| 模型 | 尺寸
(像素) | mAPval
50-95 | mAPval
50 | 推理速度
CPU b1
(ms) | 推理速度
V100 b1
(ms) | 速度
V100 b32
(ms) | 参数量
(M) | FLOPs
@640 (B) | +| ---------------------------------------------------------------------------------------------- | --------------------- | -------------------- | ----------------- | --------------------------------- | ---------------------------------- | ------------------------------- | ------------------ | ---------------------- | +| [YOLOv5n](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n.pt) | 640 | 28.0 | 45.7 | **45** | **6.3** | **0.6** | **1.9** | **4.5** | +| [YOLOv5s](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt) | 640 | 37.4 | 56.8 | 98 | 6.4 | 0.9 | 7.2 | 16.5 | +| [YOLOv5m](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m.pt) | 640 | 45.4 | 64.1 | 224 | 8.2 | 1.7 | 21.2 | 49.0 | +| [YOLOv5l](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l.pt) | 640 | 49.0 | 67.3 | 430 | 10.1 | 2.7 | 46.5 | 109.1 | +| [YOLOv5x](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x.pt) | 640 | 50.7 | 68.9 | 766 | 12.1 | 4.8 | 86.7 | 205.7 | +| | | | | | | | | | +| [YOLOv5n6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n6.pt) | 1280 | 36.0 | 54.4 | 153 | 8.1 | 2.1 | 3.2 | 4.6 | +| [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | +| [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | +| [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | +| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+[TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- |
笔记 @@ -252,13 +252,13 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结 我们使用 A100 GPU 在 COCO 上以 640 图像大小训练了 300 epochs 得到 YOLOv5 分割模型。我们将所有模型导出到 ONNX FP32 以进行 CPU 速度测试,并导出到 TensorRT FP16 以进行 GPU 速度测试。为了便于再现,我们在 Google [Colab Pro](https://colab.research.google.com/signup) 上进行了所有速度测试。 -| 模型 | 尺寸
(像素) | mAPbox
50-95 | mAPmask
50-95 | 训练时长
300 epochs
A100 GPU(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TRT A100
(ms) | 参数量
(M) | FLOPs
@640 (B) | -| ------------------------------------------------------------------------------------------ | --------------- | -------------------- | --------------------- | --------------------------------------- | ----------------------------- | ----------------------------- | --------------- | ---------------------- | -| [YOLOv5n-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-seg.pt) | 640 | 27.6 | 23.4 | 80:17 | **62.7** | **1.2** | **2.0** | **7.1** | -| [YOLOv5s-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt) | 640 | 37.6 | 31.7 | 88:16 | 173.3 | 1.4 | 7.6 | 26.4 | -| [YOLOv5m-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-seg.pt) | 640 | 45.0 | 37.1 | 108:36 | 427.0 | 2.2 | 22.0 | 70.8 | -| [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | -| [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | +| 模型 | 尺寸
(像素) | mAPbox
50-95 | mAPmask
50-95 | 训练时长
300 epochs
A100 GPU(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TRT A100
(ms) | 参数量
(M) | FLOPs
@640 (B) | +| ------------------------------------------------------------------------------------------ | --------------------- | -------------------- | --------------------- | ----------------------------------------------- | ----------------------------------- | ----------------------------------- | ------------------ | ---------------------- | +| [YOLOv5n-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-seg.pt) | 640 | 27.6 | 23.4 | 80:17 | **62.7** | **1.2** | **2.0** | **7.1** | +| [YOLOv5s-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt) | 640 | 37.6 | 31.7 | 88:16 | 173.3 | 1.4 | 7.6 | 26.4 | +| [YOLOv5m-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-seg.pt) | 640 | 45.0 | 37.1 | 108:36 | 427.0 | 2.2 | 22.0 | 70.8 | +| [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | +| [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | - 所有模型使用 SGD 优化器训练, 都使用 `lr0=0.01` 和 `weight_decay=5e-5` 参数, 图像大小为 640 。
训练 log 可以查看 https://wandb.ai/glenn-jocher/YOLOv5_v70_official - **准确性**结果都在 COCO 数据集上,使用单模型单尺度测试得到。
复现命令 `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt` @@ -329,23 +329,23 @@ YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) 带来对 我们使用 4xA100 实例在 ImageNet 上训练了 90 个 epochs 得到 YOLOv5-cls 分类模型,我们训练了 ResNet 和 EfficientNet 模型以及相同的默认训练设置以进行比较。我们将所有模型导出到 ONNX FP32 以进行 CPU 速度测试,并导出到 TensorRT FP16 以进行 GPU 速度测试。为了便于重现,我们在 Google 上进行了所有速度测试 [Colab Pro](https://colab.research.google.com/signup) 。 -| 模型 | 尺寸
(像素) | acc
top1 | acc
top5 | 训练时长
90 epochs
4xA100(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TensorRT V100
(ms) | 参数
(M) | FLOPs
@640 (B) | -| -------------------------------------------------------------------------------------------------- | --------------- | ---------------- | ---------------- | ------------------------------------ | ----------------------------- | ---------------------------------- | -------------- | ---------------------- | -| [YOLOv5n-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-cls.pt) | 224 | 64.6 | 85.4 | 7:59 | **3.3** | **0.5** | **2.5** | **0.5** | -| [YOLOv5s-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt) | 224 | 71.5 | 90.2 | 8:09 | 6.6 | 0.6 | 5.4 | 1.4 | -| [YOLOv5m-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-cls.pt) | 224 | 75.9 | 92.9 | 10:06 | 15.5 | 0.9 | 12.9 | 3.9 | -| [YOLOv5l-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-cls.pt) | 224 | 78.0 | 94.0 | 11:56 | 26.9 | 1.4 | 26.5 | 8.5 | -| [YOLOv5x-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-cls.pt) | 224 | **79.0** | **94.4** | 15:04 | 54.3 | 1.8 | 48.1 | 15.9 | -| | | | | | | | | | -| [ResNet18](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet18.pt) | 224 | 70.3 | 89.5 | **6:47** | 11.2 | 0.5 | 11.7 | 3.7 | -| [Resnetzch](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet34.pt) | 224 | 73.9 | 91.8 | 8:33 | 20.6 | 0.9 | 21.8 | 7.4 | -| [ResNet50](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet50.pt) | 224 | 76.8 | 93.4 | 11:10 | 23.4 | 1.0 | 25.6 | 8.5 | -| [ResNet101](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet101.pt) | 224 | 78.5 | 94.3 | 17:10 | 42.1 | 1.9 | 44.5 | 15.9 | -| | | | | | | | | | -| [EfficientNet_b0](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b0.pt) | 224 | 75.1 | 92.4 | 13:03 | 12.5 | 1.3 | 5.3 | 1.0 | -| [EfficientNet_b1](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b1.pt) | 224 | 76.4 | 93.2 | 17:04 | 14.9 | 1.6 | 7.8 | 1.5 | -| [EfficientNet_b2](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b2.pt) | 224 | 76.6 | 93.4 | 17:10 | 15.9 | 1.6 | 9.1 | 1.7 | -| [EfficientNet_b3](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b3.pt) | 224 | 77.7 | 94.0 | 19:19 | 18.9 | 1.9 | 12.2 | 2.4 | +| 模型 | 尺寸
(像素) | acc
top1 | acc
top5 | 训练时长
90 epochs
4xA100(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TensorRT V100
(ms) | 参数
(M) | FLOPs
@640 (B) | +| -------------------------------------------------------------------------------------------------- | --------------------- | ---------------- | ---------------- | -------------------------------------------- | ----------------------------------- | ---------------------------------------- | ---------------- | ---------------------- | +| [YOLOv5n-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-cls.pt) | 224 | 64.6 | 85.4 | 7:59 | **3.3** | **0.5** | **2.5** | **0.5** | +| [YOLOv5s-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt) | 224 | 71.5 | 90.2 | 8:09 | 6.6 | 0.6 | 5.4 | 1.4 | +| [YOLOv5m-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-cls.pt) | 224 | 75.9 | 92.9 | 10:06 | 15.5 | 0.9 | 12.9 | 3.9 | +| [YOLOv5l-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-cls.pt) | 224 | 78.0 | 94.0 | 11:56 | 26.9 | 1.4 | 26.5 | 8.5 | +| [YOLOv5x-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-cls.pt) | 224 | **79.0** | **94.4** | 15:04 | 54.3 | 1.8 | 48.1 | 15.9 | +| | | | | | | | | | +| [ResNet18](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet18.pt) | 224 | 70.3 | 89.5 | **6:47** | 11.2 | 0.5 | 11.7 | 3.7 | +| [Resnetzch](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet34.pt) | 224 | 73.9 | 91.8 | 8:33 | 20.6 | 0.9 | 21.8 | 7.4 | +| [ResNet50](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet50.pt) | 224 | 76.8 | 93.4 | 11:10 | 23.4 | 1.0 | 25.6 | 8.5 | +| [ResNet101](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet101.pt) | 224 | 78.5 | 94.3 | 17:10 | 42.1 | 1.9 | 44.5 | 15.9 | +| | | | | | | | | | +| [EfficientNet_b0](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b0.pt) | 224 | 75.1 | 92.4 | 13:03 | 12.5 | 1.3 | 5.3 | 1.0 | +| [EfficientNet_b1](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b1.pt) | 224 | 76.4 | 93.2 | 17:04 | 14.9 | 1.6 | 7.8 | 1.5 | +| [EfficientNet_b2](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b2.pt) | 224 | 76.6 | 93.4 | 17:10 | 15.9 | 1.6 | 9.1 | 1.7 | +| [EfficientNet_b3](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b3.pt) | 224 | 77.7 | 94.0 | 19:19 | 18.9 | 1.9 | 12.2 | 2.4 |
Table Notes (点击以展开) diff --git a/data/Argoverse.yaml b/data/Argoverse.yaml index a7dc0c6927..e11f4b8bb0 100644 --- a/data/Argoverse.yaml +++ b/data/Argoverse.yaml @@ -6,12 +6,11 @@ # └── datasets # └── Argoverse ← downloads here (31.3 GB) - # 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, ..] -path: ../datasets/Argoverse # dataset root dir -train: Argoverse-1.1/images/train/ # train images (relative to 'path') 39384 images -val: Argoverse-1.1/images/val/ # val images (relative to 'path') 15062 images -test: Argoverse-1.1/images/test/ # test images (optional) https://eval.ai/web/challenges/challenge-page/800/overview +path: ../datasets/Argoverse # dataset root dir +train: Argoverse-1.1/images/train/ # train images (relative to 'path') 39384 images +val: Argoverse-1.1/images/val/ # val images (relative to 'path') 15062 images +test: Argoverse-1.1/images/test/ # test images (optional) https://eval.ai/web/challenges/challenge-page/800/overview # Classes names: @@ -24,7 +23,6 @@ names: 6: traffic_light 7: stop_sign - # Download script/URL (optional) --------------------------------------------------------------------------------------- download: | import json diff --git a/data/GlobalWheat2020.yaml b/data/GlobalWheat2020.yaml index 68d86b5ebc..8c4cd3397c 100644 --- a/data/GlobalWheat2020.yaml +++ b/data/GlobalWheat2020.yaml @@ -6,9 +6,8 @@ # └── datasets # └── GlobalWheat2020 ← downloads here (7.0 GB) - # 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, ..] -path: ../datasets/GlobalWheat2020 # dataset root dir +path: ../datasets/GlobalWheat2020 # dataset root dir train: # train images (relative to 'path') 3422 images - images/arvalis_1 - images/arvalis_2 @@ -29,7 +28,6 @@ test: # test images (optional) 1276 images names: 0: wheat_head - # Download script/URL (optional) --------------------------------------------------------------------------------------- download: | from utils.general import download, Path diff --git a/data/ImageNet.yaml b/data/ImageNet.yaml index cf0218006a..71270dde49 100644 --- a/data/ImageNet.yaml +++ b/data/ImageNet.yaml @@ -7,12 +7,11 @@ # └── datasets # └── imagenet ← downloads here (144 GB) - # 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, ..] -path: ../datasets/imagenet # dataset root dir -train: train # train images (relative to 'path') 1281167 images -val: val # val images (relative to 'path') 50000 images -test: # test images (optional) +path: ../datasets/imagenet # dataset root dir +train: train # train images (relative to 'path') 1281167 images +val: val # val images (relative to 'path') 50000 images +test: # test images (optional) # Classes names: @@ -1017,6 +1016,5 @@ names: 998: ear 999: toilet paper - # Download script/URL (optional) download: data/scripts/get_imagenet.sh diff --git a/data/SKU-110K.yaml b/data/SKU-110K.yaml index 0e014d3d3b..d2c216bd1a 100644 --- a/data/SKU-110K.yaml +++ b/data/SKU-110K.yaml @@ -6,18 +6,16 @@ # └── datasets # └── SKU-110K ← downloads here (13.6 GB) - # 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, ..] -path: ../datasets/SKU-110K # dataset root dir -train: train.txt # train images (relative to 'path') 8219 images -val: val.txt # val images (relative to 'path') 588 images -test: test.txt # test images (optional) 2936 images +path: ../datasets/SKU-110K # dataset root dir +train: train.txt # train images (relative to 'path') 8219 images +val: val.txt # val images (relative to 'path') 588 images +test: test.txt # test images (optional) 2936 images # Classes names: 0: object - # Download script/URL (optional) --------------------------------------------------------------------------------------- download: | import shutil diff --git a/data/VisDrone.yaml b/data/VisDrone.yaml index 3c70269618..e816989cc8 100644 --- a/data/VisDrone.yaml +++ b/data/VisDrone.yaml @@ -6,12 +6,11 @@ # └── datasets # └── VisDrone ← downloads here (2.3 GB) - # 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, ..] -path: ../datasets/VisDrone # dataset root dir -train: VisDrone2019-DET-train/images # train images (relative to 'path') 6471 images -val: VisDrone2019-DET-val/images # val images (relative to 'path') 548 images -test: VisDrone2019-DET-test-dev/images # test images (optional) 1610 images +path: ../datasets/VisDrone # dataset root dir +train: VisDrone2019-DET-train/images # train images (relative to 'path') 6471 images +val: VisDrone2019-DET-val/images # val images (relative to 'path') 548 images +test: VisDrone2019-DET-test-dev/images # test images (optional) 1610 images # Classes names: @@ -26,7 +25,6 @@ names: 8: bus 9: motor - # Download script/URL (optional) --------------------------------------------------------------------------------------- download: | from utils.general import download, os, Path diff --git a/data/coco.yaml b/data/coco.yaml index 48da613504..314a4db001 100644 --- a/data/coco.yaml +++ b/data/coco.yaml @@ -6,12 +6,11 @@ # └── datasets # └── coco ← downloads here (20.1 GB) - # 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, ..] -path: ../datasets/coco # dataset root dir -train: train2017.txt # train images (relative to 'path') 118287 images -val: val2017.txt # val images (relative to 'path') 5000 images -test: test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794 +path: ../datasets/coco # dataset root dir +train: train2017.txt # train images (relative to 'path') 118287 images +val: val2017.txt # val images (relative to 'path') 5000 images +test: test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794 # Classes names: @@ -96,7 +95,6 @@ names: 78: hair drier 79: toothbrush - # Download script/URL (optional) download: | from utils.general import download, Path diff --git a/data/coco128-seg.yaml b/data/coco128-seg.yaml index 124eca12cb..36eb047f5b 100644 --- a/data/coco128-seg.yaml +++ b/data/coco128-seg.yaml @@ -6,12 +6,11 @@ # └── datasets # └── coco128-seg ← downloads here (7 MB) - # 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, ..] -path: ../datasets/coco128-seg # dataset root dir -train: images/train2017 # train images (relative to 'path') 128 images -val: images/train2017 # val images (relative to 'path') 128 images -test: # test images (optional) +path: ../datasets/coco128-seg # dataset root dir +train: images/train2017 # train images (relative to 'path') 128 images +val: images/train2017 # val images (relative to 'path') 128 images +test: # test images (optional) # Classes names: @@ -96,6 +95,5 @@ names: 78: hair drier 79: toothbrush - # Download script/URL (optional) download: https://ultralytics.com/assets/coco128-seg.zip diff --git a/data/coco128.yaml b/data/coco128.yaml index 2317921c9e..5509d3ceea 100644 --- a/data/coco128.yaml +++ b/data/coco128.yaml @@ -6,12 +6,11 @@ # └── datasets # └── coco128 ← downloads here (7 MB) - # 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, ..] -path: ../datasets/coco128 # dataset root dir -train: images/train2017 # train images (relative to 'path') 128 images -val: images/train2017 # val images (relative to 'path') 128 images -test: # test images (optional) +path: ../datasets/coco128 # dataset root dir +train: images/train2017 # train images (relative to 'path') 128 images +val: images/train2017 # val images (relative to 'path') 128 images +test: # test images (optional) # Classes names: @@ -96,6 +95,5 @@ names: 78: hair drier 79: toothbrush - # Download script/URL (optional) download: https://ultralytics.com/assets/coco128.zip diff --git a/data/hyps/hyp.no-augmentation.yaml b/data/hyps/hyp.no-augmentation.yaml index 6206d039fb..494f023068 100644 --- a/data/hyps/hyp.no-augmentation.yaml +++ b/data/hyps/hyp.no-augmentation.yaml @@ -3,33 +3,33 @@ # python train.py --hyp hyp.no-augmentation.yaml # See https://github.com/ultralytics/yolov5/pull/3882 for YOLOv3 + Albumentations Usage examples -lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) -lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) -momentum: 0.937 # SGD momentum/Adam beta1 -weight_decay: 0.0005 # optimizer weight decay 5e-4 -warmup_epochs: 3.0 # warmup epochs (fractions ok) -warmup_momentum: 0.8 # warmup initial momentum -warmup_bias_lr: 0.1 # warmup initial bias lr -box: 0.05 # box loss gain -cls: 0.3 # cls loss gain -cls_pw: 1.0 # cls BCELoss positive_weight -obj: 0.7 # obj loss gain (scale with pixels) -obj_pw: 1.0 # obj BCELoss positive_weight -iou_t: 0.20 # IoU training threshold -anchor_t: 4.0 # anchor-multiple threshold +lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) +lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) +momentum: 0.937 # SGD momentum/Adam beta1 +weight_decay: 0.0005 # optimizer weight decay 5e-4 +warmup_epochs: 3.0 # warmup epochs (fractions ok) +warmup_momentum: 0.8 # warmup initial momentum +warmup_bias_lr: 0.1 # warmup initial bias lr +box: 0.05 # box loss gain +cls: 0.3 # cls loss gain +cls_pw: 1.0 # cls BCELoss positive_weight +obj: 0.7 # obj loss gain (scale with pixels) +obj_pw: 1.0 # obj BCELoss positive_weight +iou_t: 0.20 # IoU training threshold +anchor_t: 4.0 # anchor-multiple threshold # anchors: 3 # anchors per output layer (0 to ignore) # this parameters are all zero since we want to use albumentation framework -fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) -hsv_h: 0 # image HSV-Hue augmentation (fraction) -hsv_s: 0 # image HSV-Saturation augmentation (fraction) -hsv_v: 0 # image HSV-Value augmentation (fraction) -degrees: 0.0 # image rotation (+/- deg) -translate: 0 # image translation (+/- fraction) -scale: 0 # image scale (+/- gain) -shear: 0 # image shear (+/- deg) -perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 -flipud: 0.0 # image flip up-down (probability) -fliplr: 0.0 # image flip left-right (probability) -mosaic: 0.0 # image mosaic (probability) -mixup: 0.0 # image mixup (probability) -copy_paste: 0.0 # segment copy-paste (probability) +fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) +hsv_h: 0 # image HSV-Hue augmentation (fraction) +hsv_s: 0 # image HSV-Saturation augmentation (fraction) +hsv_v: 0 # image HSV-Value augmentation (fraction) +degrees: 0.0 # image rotation (+/- deg) +translate: 0 # image translation (+/- fraction) +scale: 0 # image scale (+/- gain) +shear: 0 # image shear (+/- deg) +perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 +flipud: 0.0 # image flip up-down (probability) +fliplr: 0.0 # image flip left-right (probability) +mosaic: 0.0 # image mosaic (probability) +mixup: 0.0 # image mixup (probability) +copy_paste: 0.0 # segment copy-paste (probability) diff --git a/data/hyps/hyp.scratch-high.yaml b/data/hyps/hyp.scratch-high.yaml index 370e6542f1..6e89cc0d5d 100644 --- a/data/hyps/hyp.scratch-high.yaml +++ b/data/hyps/hyp.scratch-high.yaml @@ -3,32 +3,32 @@ # python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300 # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials -lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) -lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) -momentum: 0.937 # SGD momentum/Adam beta1 -weight_decay: 0.0005 # optimizer weight decay 5e-4 -warmup_epochs: 3.0 # warmup epochs (fractions ok) -warmup_momentum: 0.8 # warmup initial momentum -warmup_bias_lr: 0.1 # warmup initial bias lr -box: 0.05 # box loss gain -cls: 0.3 # cls loss gain -cls_pw: 1.0 # cls BCELoss positive_weight -obj: 0.7 # obj loss gain (scale with pixels) -obj_pw: 1.0 # obj BCELoss positive_weight -iou_t: 0.20 # IoU training threshold -anchor_t: 4.0 # anchor-multiple threshold +lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) +lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) +momentum: 0.937 # SGD momentum/Adam beta1 +weight_decay: 0.0005 # optimizer weight decay 5e-4 +warmup_epochs: 3.0 # warmup epochs (fractions ok) +warmup_momentum: 0.8 # warmup initial momentum +warmup_bias_lr: 0.1 # warmup initial bias lr +box: 0.05 # box loss gain +cls: 0.3 # cls loss gain +cls_pw: 1.0 # cls BCELoss positive_weight +obj: 0.7 # obj loss gain (scale with pixels) +obj_pw: 1.0 # obj BCELoss positive_weight +iou_t: 0.20 # IoU training threshold +anchor_t: 4.0 # anchor-multiple threshold # anchors: 3 # anchors per output layer (0 to ignore) -fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) -hsv_h: 0.015 # image HSV-Hue augmentation (fraction) -hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) -hsv_v: 0.4 # image HSV-Value augmentation (fraction) -degrees: 0.0 # image rotation (+/- deg) -translate: 0.1 # image translation (+/- fraction) -scale: 0.9 # image scale (+/- gain) -shear: 0.0 # image shear (+/- deg) -perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 -flipud: 0.0 # image flip up-down (probability) -fliplr: 0.5 # image flip left-right (probability) -mosaic: 1.0 # image mosaic (probability) -mixup: 0.1 # image mixup (probability) -copy_paste: 0.1 # segment copy-paste (probability) +fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) +hsv_h: 0.015 # image HSV-Hue augmentation (fraction) +hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) +hsv_v: 0.4 # image HSV-Value augmentation (fraction) +degrees: 0.0 # image rotation (+/- deg) +translate: 0.1 # image translation (+/- fraction) +scale: 0.9 # image scale (+/- gain) +shear: 0.0 # image shear (+/- deg) +perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 +flipud: 0.0 # image flip up-down (probability) +fliplr: 0.5 # image flip left-right (probability) +mosaic: 1.0 # image mosaic (probability) +mixup: 0.1 # image mixup (probability) +copy_paste: 0.1 # segment copy-paste (probability) diff --git a/data/hyps/hyp.scratch-low.yaml b/data/hyps/hyp.scratch-low.yaml index 23d99f0709..52a3a4e8b8 100644 --- a/data/hyps/hyp.scratch-low.yaml +++ b/data/hyps/hyp.scratch-low.yaml @@ -3,32 +3,32 @@ # python train.py --batch 64 --cfg yolov5n6.yaml --weights '' --data coco.yaml --img 640 --epochs 300 --linear # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials -lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) -lrf: 0.01 # final OneCycleLR learning rate (lr0 * lrf) -momentum: 0.937 # SGD momentum/Adam beta1 -weight_decay: 0.0005 # optimizer weight decay 5e-4 -warmup_epochs: 3.0 # warmup epochs (fractions ok) -warmup_momentum: 0.8 # warmup initial momentum -warmup_bias_lr: 0.1 # warmup initial bias lr -box: 0.05 # box loss gain -cls: 0.5 # cls loss gain -cls_pw: 1.0 # cls BCELoss positive_weight -obj: 1.0 # obj loss gain (scale with pixels) -obj_pw: 1.0 # obj BCELoss positive_weight -iou_t: 0.20 # IoU training threshold -anchor_t: 4.0 # anchor-multiple threshold +lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) +lrf: 0.01 # final OneCycleLR learning rate (lr0 * lrf) +momentum: 0.937 # SGD momentum/Adam beta1 +weight_decay: 0.0005 # optimizer weight decay 5e-4 +warmup_epochs: 3.0 # warmup epochs (fractions ok) +warmup_momentum: 0.8 # warmup initial momentum +warmup_bias_lr: 0.1 # warmup initial bias lr +box: 0.05 # box loss gain +cls: 0.5 # cls loss gain +cls_pw: 1.0 # cls BCELoss positive_weight +obj: 1.0 # obj loss gain (scale with pixels) +obj_pw: 1.0 # obj BCELoss positive_weight +iou_t: 0.20 # IoU training threshold +anchor_t: 4.0 # anchor-multiple threshold # anchors: 3 # anchors per output layer (0 to ignore) -fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) -hsv_h: 0.015 # image HSV-Hue augmentation (fraction) -hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) -hsv_v: 0.4 # image HSV-Value augmentation (fraction) -degrees: 0.0 # image rotation (+/- deg) -translate: 0.1 # image translation (+/- fraction) -scale: 0.5 # image scale (+/- gain) -shear: 0.0 # image shear (+/- deg) -perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 -flipud: 0.0 # image flip up-down (probability) -fliplr: 0.5 # image flip left-right (probability) -mosaic: 1.0 # image mosaic (probability) -mixup: 0.0 # image mixup (probability) -copy_paste: 0.0 # segment copy-paste (probability) +fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) +hsv_h: 0.015 # image HSV-Hue augmentation (fraction) +hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) +hsv_v: 0.4 # image HSV-Value augmentation (fraction) +degrees: 0.0 # image rotation (+/- deg) +translate: 0.1 # image translation (+/- fraction) +scale: 0.5 # image scale (+/- gain) +shear: 0.0 # image shear (+/- deg) +perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 +flipud: 0.0 # image flip up-down (probability) +fliplr: 0.5 # image flip left-right (probability) +mosaic: 1.0 # image mosaic (probability) +mixup: 0.0 # image mixup (probability) +copy_paste: 0.0 # segment copy-paste (probability) diff --git a/data/hyps/hyp.scratch-med.yaml b/data/hyps/hyp.scratch-med.yaml index 022cc51167..ce7d5d7cb9 100644 --- a/data/hyps/hyp.scratch-med.yaml +++ b/data/hyps/hyp.scratch-med.yaml @@ -3,32 +3,32 @@ # python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300 # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials -lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) -lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) -momentum: 0.937 # SGD momentum/Adam beta1 -weight_decay: 0.0005 # optimizer weight decay 5e-4 -warmup_epochs: 3.0 # warmup epochs (fractions ok) -warmup_momentum: 0.8 # warmup initial momentum -warmup_bias_lr: 0.1 # warmup initial bias lr -box: 0.05 # box loss gain -cls: 0.3 # cls loss gain -cls_pw: 1.0 # cls BCELoss positive_weight -obj: 0.7 # obj loss gain (scale with pixels) -obj_pw: 1.0 # obj BCELoss positive_weight -iou_t: 0.20 # IoU training threshold -anchor_t: 4.0 # anchor-multiple threshold +lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) +lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) +momentum: 0.937 # SGD momentum/Adam beta1 +weight_decay: 0.0005 # optimizer weight decay 5e-4 +warmup_epochs: 3.0 # warmup epochs (fractions ok) +warmup_momentum: 0.8 # warmup initial momentum +warmup_bias_lr: 0.1 # warmup initial bias lr +box: 0.05 # box loss gain +cls: 0.3 # cls loss gain +cls_pw: 1.0 # cls BCELoss positive_weight +obj: 0.7 # obj loss gain (scale with pixels) +obj_pw: 1.0 # obj BCELoss positive_weight +iou_t: 0.20 # IoU training threshold +anchor_t: 4.0 # anchor-multiple threshold # anchors: 3 # anchors per output layer (0 to ignore) -fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) -hsv_h: 0.015 # image HSV-Hue augmentation (fraction) -hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) -hsv_v: 0.4 # image HSV-Value augmentation (fraction) -degrees: 0.0 # image rotation (+/- deg) -translate: 0.1 # image translation (+/- fraction) -scale: 0.9 # image scale (+/- gain) -shear: 0.0 # image shear (+/- deg) -perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 -flipud: 0.0 # image flip up-down (probability) -fliplr: 0.5 # image flip left-right (probability) -mosaic: 1.0 # image mosaic (probability) -mixup: 0.1 # image mixup (probability) -copy_paste: 0.0 # segment copy-paste (probability) +fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) +hsv_h: 0.015 # image HSV-Hue augmentation (fraction) +hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) +hsv_v: 0.4 # image HSV-Value augmentation (fraction) +degrees: 0.0 # image rotation (+/- deg) +translate: 0.1 # image translation (+/- fraction) +scale: 0.9 # image scale (+/- gain) +shear: 0.0 # image shear (+/- deg) +perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 +flipud: 0.0 # image flip up-down (probability) +fliplr: 0.5 # image flip left-right (probability) +mosaic: 1.0 # image mosaic (probability) +mixup: 0.1 # image mixup (probability) +copy_paste: 0.0 # segment copy-paste (probability) diff --git a/data/objects365.yaml b/data/objects365.yaml index d4045e2f85..2a4fef135f 100644 --- a/data/objects365.yaml +++ b/data/objects365.yaml @@ -6,12 +6,11 @@ # └── datasets # └── Objects365 ← downloads here (712 GB = 367G data + 345G zips) - # 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, ..] -path: ../datasets/Objects365 # dataset root dir -train: images/train # train images (relative to 'path') 1742289 images +path: ../datasets/Objects365 # dataset root dir +train: images/train # train images (relative to 'path') 1742289 images val: images/val # val images (relative to 'path') 80000 images -test: # test images (optional) +test: # test images (optional) # Classes names: @@ -381,7 +380,6 @@ names: 363: Curling 364: Table Tennis - # Download script/URL (optional) --------------------------------------------------------------------------------------- download: | from tqdm import tqdm diff --git a/data/voc.yaml b/data/voc.yaml index 104856f0c9..27fa80bcca 100644 --- a/data/voc.yaml +++ b/data/voc.yaml @@ -6,7 +6,6 @@ # └── datasets # └── VOC ← downloads here (2.8 GB) - # 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, ..] path: ../datasets/VOC train: # train images (relative to 'path') 16551 images @@ -42,7 +41,6 @@ names: 18: train 19: tvmonitor - # Download script/URL (optional) --------------------------------------------------------------------------------------- download: | import xml.etree.ElementTree as ET diff --git a/data/xView.yaml b/data/xView.yaml index 54a623ea28..04ec46d3e0 100644 --- a/data/xView.yaml +++ b/data/xView.yaml @@ -7,11 +7,10 @@ # └── datasets # └── xView ← downloads here (20.7 GB) - # 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, ..] -path: ../datasets/xView # dataset root dir -train: images/autosplit_train.txt # train images (relative to 'path') 90% of 847 train images -val: images/autosplit_val.txt # train images (relative to 'path') 10% of 847 train images +path: ../datasets/xView # dataset root dir +train: images/autosplit_train.txt # train images (relative to 'path') 90% of 847 train images +val: images/autosplit_val.txt # train images (relative to 'path') 10% of 847 train images # Classes names: @@ -76,7 +75,6 @@ names: 58: Pylon 59: Tower - # Download script/URL (optional) --------------------------------------------------------------------------------------- download: | import json diff --git a/models/hub/anchors.yaml b/models/hub/anchors.yaml index b1306c7f48..fb85f14fb3 100644 --- a/models/hub/anchors.yaml +++ b/models/hub/anchors.yaml @@ -1,59 +1,56 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Default anchors for COCO data - # P5 ------------------------------------------------------------------------------------------------------------------- # P5-640: anchors_p5_640: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 - + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # P6 ------------------------------------------------------------------------------------------------------------------- # P6-640: thr=0.25: 0.9964 BPR, 5.54 anchors past thr, n=12, img_size=640, metric_all=0.281/0.716-mean/best, past_thr=0.469-mean: 9,11, 21,19, 17,41, 43,32, 39,70, 86,64, 65,131, 134,130, 120,265, 282,180, 247,354, 512,387 anchors_p6_640: - - [9,11, 21,19, 17,41] # P3/8 - - [43,32, 39,70, 86,64] # P4/16 - - [65,131, 134,130, 120,265] # P5/32 - - [282,180, 247,354, 512,387] # P6/64 + - [9, 11, 21, 19, 17, 41] # P3/8 + - [43, 32, 39, 70, 86, 64] # P4/16 + - [65, 131, 134, 130, 120, 265] # P5/32 + - [282, 180, 247, 354, 512, 387] # P6/64 # P6-1280: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1280, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 anchors_p6_1280: - - [19,27, 44,40, 38,94] # P3/8 - - [96,68, 86,152, 180,137] # P4/16 - - [140,301, 303,264, 238,542] # P5/32 - - [436,615, 739,380, 925,792] # P6/64 + - [19, 27, 44, 40, 38, 94] # P3/8 + - [96, 68, 86, 152, 180, 137] # P4/16 + - [140, 301, 303, 264, 238, 542] # P5/32 + - [436, 615, 739, 380, 925, 792] # P6/64 # P6-1920: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1920, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 28,41, 67,59, 57,141, 144,103, 129,227, 270,205, 209,452, 455,396, 358,812, 653,922, 1109,570, 1387,1187 anchors_p6_1920: - - [28,41, 67,59, 57,141] # P3/8 - - [144,103, 129,227, 270,205] # P4/16 - - [209,452, 455,396, 358,812] # P5/32 - - [653,922, 1109,570, 1387,1187] # P6/64 - + - [28, 41, 67, 59, 57, 141] # P3/8 + - [144, 103, 129, 227, 270, 205] # P4/16 + - [209, 452, 455, 396, 358, 812] # P5/32 + - [653, 922, 1109, 570, 1387, 1187] # P6/64 # P7 ------------------------------------------------------------------------------------------------------------------- # P7-640: thr=0.25: 0.9962 BPR, 6.76 anchors past thr, n=15, img_size=640, metric_all=0.275/0.733-mean/best, past_thr=0.466-mean: 11,11, 13,30, 29,20, 30,46, 61,38, 39,92, 78,80, 146,66, 79,163, 149,150, 321,143, 157,303, 257,402, 359,290, 524,372 anchors_p7_640: - - [11,11, 13,30, 29,20] # P3/8 - - [30,46, 61,38, 39,92] # P4/16 - - [78,80, 146,66, 79,163] # P5/32 - - [149,150, 321,143, 157,303] # P6/64 - - [257,402, 359,290, 524,372] # P7/128 + - [11, 11, 13, 30, 29, 20] # P3/8 + - [30, 46, 61, 38, 39, 92] # P4/16 + - [78, 80, 146, 66, 79, 163] # P5/32 + - [149, 150, 321, 143, 157, 303] # P6/64 + - [257, 402, 359, 290, 524, 372] # P7/128 # P7-1280: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1280, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 19,22, 54,36, 32,77, 70,83, 138,71, 75,173, 165,159, 148,334, 375,151, 334,317, 251,626, 499,474, 750,326, 534,814, 1079,818 anchors_p7_1280: - - [19,22, 54,36, 32,77] # P3/8 - - [70,83, 138,71, 75,173] # P4/16 - - [165,159, 148,334, 375,151] # P5/32 - - [334,317, 251,626, 499,474] # P6/64 - - [750,326, 534,814, 1079,818] # P7/128 + - [19, 22, 54, 36, 32, 77] # P3/8 + - [70, 83, 138, 71, 75, 173] # P4/16 + - [165, 159, 148, 334, 375, 151] # P5/32 + - [334, 317, 251, 626, 499, 474] # P6/64 + - [750, 326, 534, 814, 1079, 818] # P7/128 # P7-1920: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1920, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 29,34, 81,55, 47,115, 105,124, 207,107, 113,259, 247,238, 222,500, 563,227, 501,476, 376,939, 749,711, 1126,489, 801,1222, 1618,1227 anchors_p7_1920: - - [29,34, 81,55, 47,115] # P3/8 - - [105,124, 207,107, 113,259] # P4/16 - - [247,238, 222,500, 563,227] # P5/32 - - [501,476, 376,939, 749,711] # P6/64 - - [1126,489, 801,1222, 1618,1227] # P7/128 + - [29, 34, 81, 55, 47, 115] # P3/8 + - [105, 124, 207, 107, 113, 259] # P4/16 + - [247, 238, 222, 500, 563, 227] # P5/32 + - [501, 476, 376, 939, 749, 711] # P6/64 + - [1126, 489, 801, 1222, 1618, 1227] # P7/128 diff --git a/models/hub/yolov5-bifpn.yaml b/models/hub/yolov5-bifpn.yaml index 8afcc45219..4ea8370473 100644 --- a/models/hub/yolov5-bifpn.yaml +++ b/models/hub/yolov5-bifpn.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.0 # model depth multiple -width_multiple: 1.0 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 BiFPN head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14, 6], 1, Concat, [1]], # cat P4 <--- BiFPN change - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14, 6], 1, Concat, [1]], # cat P4 <--- BiFPN change + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/models/hub/yolov5-fpn.yaml b/models/hub/yolov5-fpn.yaml index 172135ae57..ea587cec55 100644 --- a/models/hub/yolov5-fpn.yaml +++ b/models/hub/yolov5-fpn.yaml @@ -1,42 +1,43 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.0 # model depth multiple -width_multiple: 1.0 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 FPN head -head: - [[-1, 3, C3, [1024, False]], # 10 (P5/32-large) +head: [ + [-1, 3, C3, [1024, False]], # 10 (P5/32-large) - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 1, Conv, [512, 1, 1]], - [-1, 3, C3, [512, False]], # 14 (P4/16-medium) + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 1, Conv, [512, 1, 1]], + [-1, 3, C3, [512, False]], # 14 (P4/16-medium) - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 1, Conv, [256, 1, 1]], - [-1, 3, C3, [256, False]], # 18 (P3/8-small) + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 1, Conv, [256, 1, 1]], + [-1, 3, C3, [256, False]], # 18 (P3/8-small) - [[18, 14, 10], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + [[18, 14, 10], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/models/hub/yolov5-p2.yaml b/models/hub/yolov5-p2.yaml index ee86296a0c..8d2dd9bddb 100644 --- a/models/hub/yolov5-p2.yaml +++ b/models/hub/yolov5-p2.yaml @@ -1,54 +1,55 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.0 # model depth multiple -width_multiple: 1.0 # layer channel multiple -anchors: 3 # AutoAnchor evolves 3 anchors per P output layer +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: 3 # AutoAnchor evolves 3 anchors per P output layer # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head with (P2, P3, P4, P5) outputs -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 - - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) - - [-1, 1, Conv, [128, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 2], 1, Concat, [1]], # cat backbone P2 - [-1, 1, C3, [128, False]], # 21 (P2/4-xsmall) - - [-1, 1, Conv, [128, 3, 2]], - [[-1, 18], 1, Concat, [1]], # cat head P3 - [-1, 3, C3, [256, False]], # 24 (P3/8-small) - - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 27 (P4/16-medium) - - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 30 (P5/32-large) - - [[21, 24, 27, 30], 1, Detect, [nc, anchors]], # Detect(P2, P3, P4, P5) +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) + + [-1, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 2], 1, Concat, [1]], # cat backbone P2 + [-1, 1, C3, [128, False]], # 21 (P2/4-xsmall) + + [-1, 1, Conv, [128, 3, 2]], + [[-1, 18], 1, Concat, [1]], # cat head P3 + [-1, 3, C3, [256, False]], # 24 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 27 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 30 (P5/32-large) + + [[21, 24, 27, 30], 1, Detect, [nc, anchors]], # Detect(P2, P3, P4, P5) ] diff --git a/models/hub/yolov5-p34.yaml b/models/hub/yolov5-p34.yaml index b477f2fee5..77ebfe3b77 100644 --- a/models/hub/yolov5-p34.yaml +++ b/models/hub/yolov5-p34.yaml @@ -1,41 +1,42 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 0.33 # model depth multiple -width_multiple: 0.50 # layer channel multiple -anchors: 3 # AutoAnchor evolves 3 anchors per P output layer +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.50 # layer channel multiple +anchors: 3 # AutoAnchor evolves 3 anchors per P output layer # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head with (P3, P4) outputs -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [[17, 20], 1, Detect, [nc, anchors]], # Detect(P3, P4) + [[17, 20], 1, Detect, [nc, anchors]], # Detect(P3, P4) ] diff --git a/models/hub/yolov5-p6.yaml b/models/hub/yolov5-p6.yaml index 7a94d0cc0a..f27a28cc2b 100644 --- a/models/hub/yolov5-p6.yaml +++ b/models/hub/yolov5-p6.yaml @@ -1,56 +1,57 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.0 # model depth multiple -width_multiple: 1.0 # layer channel multiple -anchors: 3 # AutoAnchor evolves 3 anchors per P output layer +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: 3 # AutoAnchor evolves 3 anchors per P output layer # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 - [-1, 3, C3, [768]], - [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 11 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 11 ] # YOLOv5 v6.0 head with (P3, P4, P5, P6) outputs -head: - [[-1, 1, Conv, [768, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 8], 1, Concat, [1]], # cat backbone P5 - [-1, 3, C3, [768, False]], # 15 - - [-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 19 - - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 23 (P3/8-small) - - [-1, 1, Conv, [256, 3, 2]], - [[-1, 20], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 26 (P4/16-medium) - - [-1, 1, Conv, [512, 3, 2]], - [[-1, 16], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [768, False]], # 29 (P5/32-large) - - [-1, 1, Conv, [768, 3, 2]], - [[-1, 12], 1, Concat, [1]], # cat head P6 - [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) - - [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) +head: [ + [-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 15 + + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 19 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 23 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 20], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 26 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 16], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 29 (P5/32-large) + + [-1, 1, Conv, [768, 3, 2]], + [[-1, 12], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) + + [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) ] diff --git a/models/hub/yolov5-p7.yaml b/models/hub/yolov5-p7.yaml index a0dcced7b8..899e83b74c 100644 --- a/models/hub/yolov5-p7.yaml +++ b/models/hub/yolov5-p7.yaml @@ -1,67 +1,68 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.0 # model depth multiple -width_multiple: 1.0 # layer channel multiple -anchors: 3 # AutoAnchor evolves 3 anchors per P output layer +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: 3 # AutoAnchor evolves 3 anchors per P output layer # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 - [-1, 3, C3, [768]], - [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 - [-1, 3, C3, [1024]], - [-1, 1, Conv, [1280, 3, 2]], # 11-P7/128 - [-1, 3, C3, [1280]], - [-1, 1, SPPF, [1280, 5]], # 13 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, Conv, [1280, 3, 2]], # 11-P7/128 + [-1, 3, C3, [1280]], + [-1, 1, SPPF, [1280, 5]], # 13 ] # YOLOv5 v6.0 head with (P3, P4, P5, P6, P7) outputs -head: - [[-1, 1, Conv, [1024, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 10], 1, Concat, [1]], # cat backbone P6 - [-1, 3, C3, [1024, False]], # 17 +head: [ + [-1, 1, Conv, [1024, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 10], 1, Concat, [1]], # cat backbone P6 + [-1, 3, C3, [1024, False]], # 17 - [-1, 1, Conv, [768, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 8], 1, Concat, [1]], # cat backbone P5 - [-1, 3, C3, [768, False]], # 21 + [-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 21 - [-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 25 + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 25 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 29 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 29 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 26], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 32 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 26], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 32 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 22], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [768, False]], # 35 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 22], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 35 (P5/32-large) - [-1, 1, Conv, [768, 3, 2]], - [[-1, 18], 1, Concat, [1]], # cat head P6 - [-1, 3, C3, [1024, False]], # 38 (P6/64-xlarge) + [-1, 1, Conv, [768, 3, 2]], + [[-1, 18], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 38 (P6/64-xlarge) - [-1, 1, Conv, [1024, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P7 - [-1, 3, C3, [1280, False]], # 41 (P7/128-xxlarge) + [-1, 1, Conv, [1024, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P7 + [-1, 3, C3, [1280, False]], # 41 (P7/128-xxlarge) - [[29, 32, 35, 38, 41], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6, P7) + [[29, 32, 35, 38, 41], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6, P7) ] diff --git a/models/hub/yolov5-panet.yaml b/models/hub/yolov5-panet.yaml index 352cce45af..0b8478751e 100644 --- a/models/hub/yolov5-panet.yaml +++ b/models/hub/yolov5-panet.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.0 # model depth multiple -width_multiple: 1.0 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 PANet head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/models/hub/yolov5l6.yaml b/models/hub/yolov5l6.yaml index 0eba5de427..b208cf5307 100644 --- a/models/hub/yolov5l6.yaml +++ b/models/hub/yolov5l6.yaml @@ -1,60 +1,61 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.0 # model depth multiple -width_multiple: 1.0 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple anchors: - - [19,27, 44,40, 38,94] # P3/8 - - [96,68, 86,152, 180,137] # P4/16 - - [140,301, 303,264, 238,542] # P5/32 - - [436,615, 739,380, 925,792] # P6/64 + - [19, 27, 44, 40, 38, 94] # P3/8 + - [96, 68, 86, 152, 180, 137] # P4/16 + - [140, 301, 303, 264, 238, 542] # P5/32 + - [436, 615, 739, 380, 925, 792] # P6/64 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 - [-1, 3, C3, [768]], - [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 11 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 11 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [768, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 8], 1, Concat, [1]], # cat backbone P5 - [-1, 3, C3, [768, False]], # 15 - - [-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 19 - - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 23 (P3/8-small) - - [-1, 1, Conv, [256, 3, 2]], - [[-1, 20], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 26 (P4/16-medium) - - [-1, 1, Conv, [512, 3, 2]], - [[-1, 16], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [768, False]], # 29 (P5/32-large) - - [-1, 1, Conv, [768, 3, 2]], - [[-1, 12], 1, Concat, [1]], # cat head P6 - [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) - - [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) +head: [ + [-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 15 + + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 19 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 23 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 20], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 26 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 16], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 29 (P5/32-large) + + [-1, 1, Conv, [768, 3, 2]], + [[-1, 12], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) + + [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) ] diff --git a/models/hub/yolov5m6.yaml b/models/hub/yolov5m6.yaml index 75bd2c1f29..d9da4d0750 100644 --- a/models/hub/yolov5m6.yaml +++ b/models/hub/yolov5m6.yaml @@ -1,60 +1,61 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 0.67 # model depth multiple -width_multiple: 0.75 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 0.67 # model depth multiple +width_multiple: 0.75 # layer channel multiple anchors: - - [19,27, 44,40, 38,94] # P3/8 - - [96,68, 86,152, 180,137] # P4/16 - - [140,301, 303,264, 238,542] # P5/32 - - [436,615, 739,380, 925,792] # P6/64 + - [19, 27, 44, 40, 38, 94] # P3/8 + - [96, 68, 86, 152, 180, 137] # P4/16 + - [140, 301, 303, 264, 238, 542] # P5/32 + - [436, 615, 739, 380, 925, 792] # P6/64 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 - [-1, 3, C3, [768]], - [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 11 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 11 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [768, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 8], 1, Concat, [1]], # cat backbone P5 - [-1, 3, C3, [768, False]], # 15 - - [-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 19 - - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 23 (P3/8-small) - - [-1, 1, Conv, [256, 3, 2]], - [[-1, 20], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 26 (P4/16-medium) - - [-1, 1, Conv, [512, 3, 2]], - [[-1, 16], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [768, False]], # 29 (P5/32-large) - - [-1, 1, Conv, [768, 3, 2]], - [[-1, 12], 1, Concat, [1]], # cat head P6 - [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) - - [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) +head: [ + [-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 15 + + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 19 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 23 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 20], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 26 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 16], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 29 (P5/32-large) + + [-1, 1, Conv, [768, 3, 2]], + [[-1, 12], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) + + [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) ] diff --git a/models/hub/yolov5n6.yaml b/models/hub/yolov5n6.yaml index 79deec1f97..a49ecf12c4 100644 --- a/models/hub/yolov5n6.yaml +++ b/models/hub/yolov5n6.yaml @@ -1,60 +1,61 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 0.33 # model depth multiple -width_multiple: 0.25 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.25 # layer channel multiple anchors: - - [19,27, 44,40, 38,94] # P3/8 - - [96,68, 86,152, 180,137] # P4/16 - - [140,301, 303,264, 238,542] # P5/32 - - [436,615, 739,380, 925,792] # P6/64 + - [19, 27, 44, 40, 38, 94] # P3/8 + - [96, 68, 86, 152, 180, 137] # P4/16 + - [140, 301, 303, 264, 238, 542] # P5/32 + - [436, 615, 739, 380, 925, 792] # P6/64 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 - [-1, 3, C3, [768]], - [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 11 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 11 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [768, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 8], 1, Concat, [1]], # cat backbone P5 - [-1, 3, C3, [768, False]], # 15 - - [-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 19 - - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 23 (P3/8-small) - - [-1, 1, Conv, [256, 3, 2]], - [[-1, 20], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 26 (P4/16-medium) - - [-1, 1, Conv, [512, 3, 2]], - [[-1, 16], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [768, False]], # 29 (P5/32-large) - - [-1, 1, Conv, [768, 3, 2]], - [[-1, 12], 1, Concat, [1]], # cat head P6 - [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) - - [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) +head: [ + [-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 15 + + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 19 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 23 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 20], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 26 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 16], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 29 (P5/32-large) + + [-1, 1, Conv, [768, 3, 2]], + [[-1, 12], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) + + [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) ] diff --git a/models/hub/yolov5s-LeakyReLU.yaml b/models/hub/yolov5s-LeakyReLU.yaml index 638f6ec892..08cb5d91cc 100644 --- a/models/hub/yolov5s-LeakyReLU.yaml +++ b/models/hub/yolov5s-LeakyReLU.yaml @@ -1,49 +1,50 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -activation: nn.LeakyReLU(0.1) # <----- Conv() activation used throughout entire YOLOv5 model -depth_multiple: 0.33 # model depth multiple -width_multiple: 0.50 # layer channel multiple +nc: 80 # number of classes +activation: nn.LeakyReLU(0.1) # <----- Conv() activation used throughout entire YOLOv5 model +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.50 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/models/hub/yolov5s-ghost.yaml b/models/hub/yolov5s-ghost.yaml index 993fcd6fcb..ed4f7b8ae6 100644 --- a/models/hub/yolov5s-ghost.yaml +++ b/models/hub/yolov5s-ghost.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 0.33 # model depth multiple -width_multiple: 0.50 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.50 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, GhostConv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3Ghost, [128]], - [-1, 1, GhostConv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3Ghost, [256]], - [-1, 1, GhostConv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3Ghost, [512]], - [-1, 1, GhostConv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3Ghost, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, GhostConv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3Ghost, [128]], + [-1, 1, GhostConv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3Ghost, [256]], + [-1, 1, GhostConv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3Ghost, [512]], + [-1, 1, GhostConv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3Ghost, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head -head: - [[-1, 1, GhostConv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3Ghost, [512, False]], # 13 +head: [ + [-1, 1, GhostConv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3Ghost, [512, False]], # 13 - [-1, 1, GhostConv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3Ghost, [256, False]], # 17 (P3/8-small) + [-1, 1, GhostConv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3Ghost, [256, False]], # 17 (P3/8-small) - [-1, 1, GhostConv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3Ghost, [512, False]], # 20 (P4/16-medium) + [-1, 1, GhostConv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3Ghost, [512, False]], # 20 (P4/16-medium) - [-1, 1, GhostConv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3Ghost, [1024, False]], # 23 (P5/32-large) + [-1, 1, GhostConv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3Ghost, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/models/hub/yolov5s-transformer.yaml b/models/hub/yolov5s-transformer.yaml index 9525ee0f2d..12c7992f93 100644 --- a/models/hub/yolov5s-transformer.yaml +++ b/models/hub/yolov5s-transformer.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 0.33 # model depth multiple -width_multiple: 0.50 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.50 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3TR, [1024]], # 9 <--- C3TR() Transformer module - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3TR, [1024]], # 9 <--- C3TR() Transformer module + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/models/hub/yolov5s6.yaml b/models/hub/yolov5s6.yaml index 8443a7f329..5b37de477c 100644 --- a/models/hub/yolov5s6.yaml +++ b/models/hub/yolov5s6.yaml @@ -1,60 +1,61 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 0.33 # model depth multiple -width_multiple: 0.50 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.50 # layer channel multiple anchors: - - [19,27, 44,40, 38,94] # P3/8 - - [96,68, 86,152, 180,137] # P4/16 - - [140,301, 303,264, 238,542] # P5/32 - - [436,615, 739,380, 925,792] # P6/64 + - [19, 27, 44, 40, 38, 94] # P3/8 + - [96, 68, 86, 152, 180, 137] # P4/16 + - [140, 301, 303, 264, 238, 542] # P5/32 + - [436, 615, 739, 380, 925, 792] # P6/64 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 - [-1, 3, C3, [768]], - [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 11 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 11 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [768, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 8], 1, Concat, [1]], # cat backbone P5 - [-1, 3, C3, [768, False]], # 15 - - [-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 19 - - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 23 (P3/8-small) - - [-1, 1, Conv, [256, 3, 2]], - [[-1, 20], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 26 (P4/16-medium) - - [-1, 1, Conv, [512, 3, 2]], - [[-1, 16], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [768, False]], # 29 (P5/32-large) - - [-1, 1, Conv, [768, 3, 2]], - [[-1, 12], 1, Concat, [1]], # cat head P6 - [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) - - [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) +head: [ + [-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 15 + + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 19 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 23 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 20], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 26 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 16], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 29 (P5/32-large) + + [-1, 1, Conv, [768, 3, 2]], + [[-1, 12], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) + + [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) ] diff --git a/models/hub/yolov5x6.yaml b/models/hub/yolov5x6.yaml index 48415b8a8c..5446399de2 100644 --- a/models/hub/yolov5x6.yaml +++ b/models/hub/yolov5x6.yaml @@ -1,60 +1,61 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.33 # model depth multiple -width_multiple: 1.25 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 1.33 # model depth multiple +width_multiple: 1.25 # layer channel multiple anchors: - - [19,27, 44,40, 38,94] # P3/8 - - [96,68, 86,152, 180,137] # P4/16 - - [140,301, 303,264, 238,542] # P5/32 - - [436,615, 739,380, 925,792] # P6/64 + - [19, 27, 44, 40, 38, 94] # P3/8 + - [96, 68, 86, 152, 180, 137] # P4/16 + - [140, 301, 303, 264, 238, 542] # P5/32 + - [436, 615, 739, 380, 925, 792] # P6/64 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 - [-1, 3, C3, [768]], - [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 11 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [768, 3, 2]], # 7-P5/32 + [-1, 3, C3, [768]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P6/64 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 11 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [768, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 8], 1, Concat, [1]], # cat backbone P5 - [-1, 3, C3, [768, False]], # 15 - - [-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 19 - - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 23 (P3/8-small) - - [-1, 1, Conv, [256, 3, 2]], - [[-1, 20], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 26 (P4/16-medium) - - [-1, 1, Conv, [512, 3, 2]], - [[-1, 16], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [768, False]], # 29 (P5/32-large) - - [-1, 1, Conv, [768, 3, 2]], - [[-1, 12], 1, Concat, [1]], # cat head P6 - [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) - - [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) +head: [ + [-1, 1, Conv, [768, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 8], 1, Concat, [1]], # cat backbone P5 + [-1, 3, C3, [768, False]], # 15 + + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 19 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 23 (P3/8-small) + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 20], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 26 (P4/16-medium) + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 16], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [768, False]], # 29 (P5/32-large) + + [-1, 1, Conv, [768, 3, 2]], + [[-1, 12], 1, Concat, [1]], # cat head P6 + [-1, 3, C3, [1024, False]], # 32 (P6/64-xlarge) + + [[23, 26, 29, 32], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5, P6) ] diff --git a/models/segment/yolov5l-seg.yaml b/models/segment/yolov5l-seg.yaml index 0da593db07..83021f2d1f 100644 --- a/models/segment/yolov5l-seg.yaml +++ b/models/segment/yolov5l-seg.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.0 # model depth multiple -width_multiple: 1.0 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) ] diff --git a/models/segment/yolov5m-seg.yaml b/models/segment/yolov5m-seg.yaml index 59cf47e94e..81279469f1 100644 --- a/models/segment/yolov5m-seg.yaml +++ b/models/segment/yolov5m-seg.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 0.67 # model depth multiple -width_multiple: 0.75 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 0.67 # model depth multiple +width_multiple: 0.75 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) ] diff --git a/models/segment/yolov5n-seg.yaml b/models/segment/yolov5n-seg.yaml index 8d749007f1..a4d44cd8e8 100644 --- a/models/segment/yolov5n-seg.yaml +++ b/models/segment/yolov5n-seg.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 0.33 # model depth multiple -width_multiple: 0.25 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.25 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) ] diff --git a/models/segment/yolov5s-seg.yaml b/models/segment/yolov5s-seg.yaml index 05ce94bbe8..caef266d35 100644 --- a/models/segment/yolov5s-seg.yaml +++ b/models/segment/yolov5s-seg.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 0.33 # model depth multiple -width_multiple: 0.5 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.5 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) ] diff --git a/models/segment/yolov5x-seg.yaml b/models/segment/yolov5x-seg.yaml index 8e926612c4..10e3e5f562 100644 --- a/models/segment/yolov5x-seg.yaml +++ b/models/segment/yolov5x-seg.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.33 # model depth multiple -width_multiple: 1.25 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 1.33 # model depth multiple +width_multiple: 1.25 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5) ] diff --git a/models/yolov3-spp.yaml b/models/yolov3-spp.yaml index 2598a9b6c8..810f517556 100644 --- a/models/yolov3-spp.yaml +++ b/models/yolov3-spp.yaml @@ -1,51 +1,52 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.0 # model depth multiple -width_multiple: 1.0 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # darknet53 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [32, 3, 1]], # 0 - [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 - [-1, 1, Bottleneck, [64]], - [-1, 1, Conv, [128, 3, 2]], # 3-P2/4 - [-1, 2, Bottleneck, [128]], - [-1, 1, Conv, [256, 3, 2]], # 5-P3/8 - [-1, 8, Bottleneck, [256]], - [-1, 1, Conv, [512, 3, 2]], # 7-P4/16 - [-1, 8, Bottleneck, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 9-P5/32 - [-1, 4, Bottleneck, [1024]], # 10 + [ + [-1, 1, Conv, [32, 3, 1]], # 0 + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + [-1, 1, Bottleneck, [64]], + [-1, 1, Conv, [128, 3, 2]], # 3-P2/4 + [-1, 2, Bottleneck, [128]], + [-1, 1, Conv, [256, 3, 2]], # 5-P3/8 + [-1, 8, Bottleneck, [256]], + [-1, 1, Conv, [512, 3, 2]], # 7-P4/16 + [-1, 8, Bottleneck, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P5/32 + [-1, 4, Bottleneck, [1024]], # 10 ] # YOLOv3-SPP head -head: - [[-1, 1, Bottleneck, [1024, False]], - [-1, 1, SPP, [512, [5, 9, 13]]], - [-1, 1, Conv, [1024, 3, 1]], - [-1, 1, Conv, [512, 1, 1]], - [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large) +head: [ + [-1, 1, Bottleneck, [1024, False]], + [-1, 1, SPP, [512, [5, 9, 13]]], + [-1, 1, Conv, [1024, 3, 1]], + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large) - [-2, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 8], 1, Concat, [1]], # cat backbone P4 - [-1, 1, Bottleneck, [512, False]], - [-1, 1, Bottleneck, [512, False]], - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium) + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 8], 1, Concat, [1]], # cat backbone P4 + [-1, 1, Bottleneck, [512, False]], + [-1, 1, Bottleneck, [512, False]], + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium) - [-2, 1, Conv, [128, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P3 - [-1, 1, Bottleneck, [256, False]], - [-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small) + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P3 + [-1, 1, Bottleneck, [256, False]], + [-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small) - [[27, 22, 15], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + [[27, 22, 15], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/models/yolov3-tiny.yaml b/models/yolov3-tiny.yaml index 6d1c65dd1c..8707f1db1e 100644 --- a/models/yolov3-tiny.yaml +++ b/models/yolov3-tiny.yaml @@ -1,41 +1,42 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.0 # model depth multiple -width_multiple: 1.0 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple anchors: - - [10,14, 23,27, 37,58] # P4/16 - - [81,82, 135,169, 344,319] # P5/32 + - [10, 14, 23, 27, 37, 58] # P4/16 + - [81, 82, 135, 169, 344, 319] # P5/32 # YOLOv3-tiny backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [16, 3, 1]], # 0 - [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 1-P1/2 - [-1, 1, Conv, [32, 3, 1]], - [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 3-P2/4 - [-1, 1, Conv, [64, 3, 1]], - [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 5-P3/8 - [-1, 1, Conv, [128, 3, 1]], - [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 7-P4/16 - [-1, 1, Conv, [256, 3, 1]], - [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 9-P5/32 - [-1, 1, Conv, [512, 3, 1]], - [-1, 1, nn.ZeroPad2d, [[0, 1, 0, 1]]], # 11 - [-1, 1, nn.MaxPool2d, [2, 1, 0]], # 12 + [ + [-1, 1, Conv, [16, 3, 1]], # 0 + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 1-P1/2 + [-1, 1, Conv, [32, 3, 1]], + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 3-P2/4 + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 5-P3/8 + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 7-P4/16 + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 9-P5/32 + [-1, 1, Conv, [512, 3, 1]], + [-1, 1, nn.ZeroPad2d, [[0, 1, 0, 1]]], # 11 + [-1, 1, nn.MaxPool2d, [2, 1, 0]], # 12 ] # YOLOv3-tiny head -head: - [[-1, 1, Conv, [1024, 3, 1]], - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, Conv, [512, 3, 1]], # 15 (P5/32-large) +head: [ + [-1, 1, Conv, [1024, 3, 1]], + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [512, 3, 1]], # 15 (P5/32-large) - [-2, 1, Conv, [128, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 8], 1, Concat, [1]], # cat backbone P4 - [-1, 1, Conv, [256, 3, 1]], # 19 (P4/16-medium) + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 8], 1, Concat, [1]], # cat backbone P4 + [-1, 1, Conv, [256, 3, 1]], # 19 (P4/16-medium) - [[19, 15], 1, Detect, [nc, anchors]], # Detect(P4, P5) + [[19, 15], 1, Detect, [nc, anchors]], # Detect(P4, P5) ] diff --git a/models/yolov3.yaml b/models/yolov3.yaml index 19874a0f15..8a6680e1c5 100644 --- a/models/yolov3.yaml +++ b/models/yolov3.yaml @@ -1,51 +1,52 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.0 # model depth multiple -width_multiple: 1.0 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # darknet53 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [32, 3, 1]], # 0 - [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 - [-1, 1, Bottleneck, [64]], - [-1, 1, Conv, [128, 3, 2]], # 3-P2/4 - [-1, 2, Bottleneck, [128]], - [-1, 1, Conv, [256, 3, 2]], # 5-P3/8 - [-1, 8, Bottleneck, [256]], - [-1, 1, Conv, [512, 3, 2]], # 7-P4/16 - [-1, 8, Bottleneck, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 9-P5/32 - [-1, 4, Bottleneck, [1024]], # 10 + [ + [-1, 1, Conv, [32, 3, 1]], # 0 + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + [-1, 1, Bottleneck, [64]], + [-1, 1, Conv, [128, 3, 2]], # 3-P2/4 + [-1, 2, Bottleneck, [128]], + [-1, 1, Conv, [256, 3, 2]], # 5-P3/8 + [-1, 8, Bottleneck, [256]], + [-1, 1, Conv, [512, 3, 2]], # 7-P4/16 + [-1, 8, Bottleneck, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P5/32 + [-1, 4, Bottleneck, [1024]], # 10 ] # YOLOv3 head -head: - [[-1, 1, Bottleneck, [1024, False]], - [-1, 1, Conv, [512, 1, 1]], - [-1, 1, Conv, [1024, 3, 1]], - [-1, 1, Conv, [512, 1, 1]], - [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large) +head: [ + [-1, 1, Bottleneck, [1024, False]], + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [1024, 3, 1]], + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large) - [-2, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 8], 1, Concat, [1]], # cat backbone P4 - [-1, 1, Bottleneck, [512, False]], - [-1, 1, Bottleneck, [512, False]], - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium) + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 8], 1, Concat, [1]], # cat backbone P4 + [-1, 1, Bottleneck, [512, False]], + [-1, 1, Bottleneck, [512, False]], + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium) - [-2, 1, Conv, [128, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P3 - [-1, 1, Bottleneck, [256, False]], - [-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small) + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P3 + [-1, 1, Bottleneck, [256, False]], + [-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small) - [[27, 22, 15], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + [[27, 22, 15], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/models/yolov5l.yaml b/models/yolov5l.yaml index 01a3dc78ae..18a8106e2d 100644 --- a/models/yolov5l.yaml +++ b/models/yolov5l.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.0 # model depth multiple -width_multiple: 1.0 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/models/yolov5m.yaml b/models/yolov5m.yaml index 2d1d180861..1637421528 100644 --- a/models/yolov5m.yaml +++ b/models/yolov5m.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 0.67 # model depth multiple -width_multiple: 0.75 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 0.67 # model depth multiple +width_multiple: 0.75 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/models/yolov5n.yaml b/models/yolov5n.yaml index 3c295ee130..19cb10a84b 100644 --- a/models/yolov5n.yaml +++ b/models/yolov5n.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 0.33 # model depth multiple -width_multiple: 0.25 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.25 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/models/yolov5s.yaml b/models/yolov5s.yaml index 07b171671d..3cd30e8ca5 100644 --- a/models/yolov5s.yaml +++ b/models/yolov5s.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 0.33 # model depth multiple -width_multiple: 0.50 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 0.33 # model depth multiple +width_multiple: 0.50 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/models/yolov5x.yaml b/models/yolov5x.yaml index f046b2c677..be0f90b8a1 100644 --- a/models/yolov5x.yaml +++ b/models/yolov5x.yaml @@ -1,48 +1,49 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license # Parameters -nc: 80 # number of classes -depth_multiple: 1.33 # model depth multiple -width_multiple: 1.25 # layer channel multiple +nc: 80 # number of classes +depth_multiple: 1.33 # model depth multiple +width_multiple: 1.25 # layer channel multiple anchors: - - [10,13, 16,30, 33,23] # P3/8 - - [30,61, 62,45, 59,119] # P4/16 - - [116,90, 156,198, 373,326] # P5/32 + - [10, 13, 16, 30, 33, 23] # P3/8 + - [30, 61, 62, 45, 59, 119] # P4/16 + - [116, 90, 156, 198, 373, 326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 - [-1, 3, C3, [128]], - [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 - [-1, 6, C3, [256]], - [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 - [-1, 9, C3, [512]], - [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 - [-1, 3, C3, [1024]], - [-1, 1, SPPF, [1024, 5]], # 9 + [ + [-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], # cat backbone P4 - [-1, 3, C3, [512, False]], # 13 +head: [ + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], # cat backbone P3 - [-1, 3, C3, [256, False]], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, "nearest"]], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], # cat head P4 - [-1, 3, C3, [512, False]], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], # cat head P5 - [-1, 3, C3, [1024, False]], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/utils/loggers/comet/optimizer_config.json b/utils/loggers/comet/optimizer_config.json index 83ddddab6f..0218f162d9 100644 --- a/utils/loggers/comet/optimizer_config.json +++ b/utils/loggers/comet/optimizer_config.json @@ -3,201 +3,127 @@ "parameters": { "anchor_t": { "type": "discrete", - "values": [ - 2, - 8 - ] + "values": [2, 8] }, "batch_size": { "type": "discrete", - "values": [ - 16, - 32, - 64 - ] + "values": [16, 32, 64] }, "box": { "type": "discrete", - "values": [ - 0.02, - 0.2 - ] + "values": [0.02, 0.2] }, "cls": { "type": "discrete", - "values": [ - 0.2 - ] + "values": [0.2] }, "cls_pw": { "type": "discrete", - "values": [ - 0.5 - ] + "values": [0.5] }, "copy_paste": { "type": "discrete", - "values": [ - 1 - ] + "values": [1] }, "degrees": { "type": "discrete", - "values": [ - 0, - 45 - ] + "values": [0, 45] }, "epochs": { "type": "discrete", - "values": [ - 5 - ] + "values": [5] }, "fl_gamma": { "type": "discrete", - "values": [ - 0 - ] + "values": [0] }, "fliplr": { "type": "discrete", - "values": [ - 0 - ] + "values": [0] }, "flipud": { "type": "discrete", - "values": [ - 0 - ] + "values": [0] }, "hsv_h": { "type": "discrete", - "values": [ - 0 - ] + "values": [0] }, "hsv_s": { "type": "discrete", - "values": [ - 0 - ] + "values": [0] }, "hsv_v": { "type": "discrete", - "values": [ - 0 - ] + "values": [0] }, "iou_t": { "type": "discrete", - "values": [ - 0.7 - ] + "values": [0.7] }, "lr0": { "type": "discrete", - "values": [ - 1e-05, - 0.1 - ] + "values": [1e-5, 0.1] }, "lrf": { "type": "discrete", - "values": [ - 0.01, - 1 - ] + "values": [0.01, 1] }, "mixup": { "type": "discrete", - "values": [ - 1 - ] + "values": [1] }, "momentum": { "type": "discrete", - "values": [ - 0.6 - ] + "values": [0.6] }, "mosaic": { "type": "discrete", - "values": [ - 0 - ] + "values": [0] }, "obj": { "type": "discrete", - "values": [ - 0.2 - ] + "values": [0.2] }, "obj_pw": { "type": "discrete", - "values": [ - 0.5 - ] + "values": [0.5] }, "optimizer": { "type": "categorical", - "values": [ - "SGD", - "Adam", - "AdamW" - ] + "values": ["SGD", "Adam", "AdamW"] }, "perspective": { "type": "discrete", - "values": [ - 0 - ] + "values": [0] }, "scale": { "type": "discrete", - "values": [ - 0 - ] + "values": [0] }, "shear": { "type": "discrete", - "values": [ - 0 - ] + "values": [0] }, "translate": { "type": "discrete", - "values": [ - 0 - ] + "values": [0] }, "warmup_bias_lr": { "type": "discrete", - "values": [ - 0, - 0.2 - ] + "values": [0, 0.2] }, "warmup_epochs": { "type": "discrete", - "values": [ - 5 - ] + "values": [5] }, "warmup_momentum": { "type": "discrete", - "values": [ - 0, - 0.95 - ] + "values": [0, 0.95] }, "weight_decay": { "type": "discrete", - "values": [ - 0, - 0.001 - ] + "values": [0, 0.001] } }, "spec": { From d4ed6400d73e6a02070cfe927e509256a685c822 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 27 Jan 2024 18:49:29 +0100 Subject: [PATCH 1056/1185] Link checks SSL insecure robustness (#2186) --- .github/workflows/links.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 8259160a87..69a3444613 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -36,8 +36,10 @@ jobs: command: | lychee \ --scheme 'https' \ + --timeout 60 \ + --insecure \ --accept 403,429,500,502,999 \ - --exclude-loopback \ + --exclude-all-private \ --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ --exclude-path '**/ci.yaml' \ --github-token ${{ secrets.GITHUB_TOKEN }} \ @@ -54,8 +56,10 @@ jobs: command: | lychee \ --scheme 'https' \ + --timeout 60 \ + --insecure \ --accept 429,999 \ - --exclude-loopback \ + --exclude-all-private \ --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ --exclude-path '**/ci.yaml' \ --github-token ${{ secrets.GITHUB_TOKEN }} \ From a046b1b483706b8f8298861a14b3035280d5269d Mon Sep 17 00:00:00 2001 From: Paula Derrenger <107626595+pderrenger@users.noreply.github.com> Date: Sun, 28 Jan 2024 23:40:36 +0100 Subject: [PATCH 1057/1185] Ultralytics Actions with OpenAI GPT-4 PR Summary (#2187) Update Ultralytics Actions --- .github/workflows/format.yml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 3caff1624e..81e10187dd 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -6,9 +6,9 @@ name: Ultralytics Actions on: push: - branches: [main, master] - pull_request_target: - branches: [main, master] + branches: [main,master] + pull_request: + branches: [main,master] jobs: format: @@ -17,9 +17,11 @@ jobs: - name: Run Ultralytics Formatting uses: ultralytics/actions@main with: - token: ${{ secrets.GITHUB_TOKEN }} # automatically generated - python: true - docstrings: true - markdown: true - spelling: true - links: true + token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, do not modify + python: true # format Python code and docstrings + markdown: true # format Markdown and YAML + spelling: true # check spelling + links: true # check broken links + summary: true # print PR summary with GPT4 (requires 'openai_api_key' or 'openai_azure_api_key' and 'openai_azure_endpoint') + openai_azure_api_key: ${{ secrets.OPENAI_AZURE_API_KEY }} + openai_azure_endpoint: ${{ secrets.OPENAI_AZURE_ENDPOINT }} From 5b57a8d83007b77d5a3005bc40fb906ac719e594 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 29 Jan 2024 11:53:55 +0100 Subject: [PATCH 1058/1185] Update format.yml (#2189) --- .github/workflows/format.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 81e10187dd..048fd81114 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -6,9 +6,9 @@ name: Ultralytics Actions on: push: - branches: [main,master] - pull_request: - branches: [main,master] + branches: [main, master] + pull_request_target: + branches: [main, master] jobs: format: From 2d6d601b686e7991a96cad4f20e8cde3b6cbccde Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jan 2024 13:08:52 +0100 Subject: [PATCH 1059/1185] Bump slackapi/slack-github-action from 1.24.0 to 1.25.0 in /.github/workflows (#2188) Bump slackapi/slack-github-action in /.github/workflows Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 1.24.0 to 1.25.0. - [Release notes](https://github.com/slackapi/slack-github-action/releases) - [Commits](https://github.com/slackapi/slack-github-action/compare/v1.24.0...v1.25.0) --- updated-dependencies: - dependency-name: slackapi/slack-github-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index fbab5a29d8..1f9b59332b 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -114,7 +114,7 @@ jobs: steps: - name: Check for failure and notify if: (needs.Tests.result == 'failure' || needs.Tests.result == 'cancelled') && github.repository == 'ultralytics/yolov3' && (github.event_name == 'schedule' || github.event_name == 'push') - uses: slackapi/slack-github-action@v1.24.0 + uses: slackapi/slack-github-action@v1.25.0 with: payload: | {"text": " GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n"} From 8b0abddfeed13c6523708c69aa373a22a1c25871 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Feb 2024 19:46:52 +0100 Subject: [PATCH 1060/1185] Bump nick-invision/retry from 2 to 3 in /.github/workflows (#2192) * Bump nick-invision/retry from 2 to 3 in /.github/workflows Bumps [nick-invision/retry](https://github.com/nick-invision/retry) from 2 to 3. - [Release notes](https://github.com/nick-invision/retry/releases) - [Changelog](https://github.com/nick-fields/retry/blob/master/.releaserc.js) - [Commits](https://github.com/nick-invision/retry/compare/v2...v3) --- updated-dependencies: - dependency-name: nick-invision/retry dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Auto-format by https://ultralytics.com/actions --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: UltralyticsAssistant --- .github/workflows/links.yml | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 69a3444613..3acae3ec2d 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -28,7 +28,7 @@ jobs: sudo mv lychee /usr/local/bin - name: Test Markdown and HTML links with retry - uses: nick-invision/retry@v2 + uses: nick-invision/retry@v3 with: timeout_minutes: 5 retry_wait_seconds: 60 @@ -48,7 +48,7 @@ jobs: - name: Test Markdown, HTML, YAML, Python and Notebook links with retry if: github.event_name == 'workflow_dispatch' - uses: nick-invision/retry@v2 + uses: nick-invision/retry@v3 with: timeout_minutes: 5 retry_wait_seconds: 60 diff --git a/README.md b/README.md index a6401ae529..00cc1abf22 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - -| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | +| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | | :--------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | | Label and export your custom datasets directly to YOLOv3 for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | Automatically track, visualize and even remotely train YOLOv3 using [ClearML](https://cutt.ly/yolov5-readme-clearml) (open-source!) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet2) lets you save YOLOv3 models, resume training, and interactively visualise and debug predictions | Run YOLOv3 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | From 0b2c5f97f49a920f18b11953b2ab2c59b2688e60 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 4 Mar 2024 21:13:31 +0100 Subject: [PATCH 1061/1185] Add Discord badge (#2196) * Add Discord badge * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: UltralyticsAssistant --- README.md | 1 + export.py | 6 +++--- models/experimental.py | 1 + utils/loggers/clearml/clearml_utils.py | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 00cc1abf22..6a1d168ce4 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ YOLOv3 CI YOLOv3 Citation Docker Pulls + Discord
Run on Gradient Open In Colab diff --git a/export.py b/export.py index dd45e5ebc1..311c4cae81 100644 --- a/export.py +++ b/export.py @@ -722,9 +722,9 @@ def pipeline_coreml(model, im, file, names, y, prefix=colorstr("CoreML Pipeline: model = ct.models.MLModel(pipeline.spec) model.input_description["image"] = "Input image" model.input_description["iouThreshold"] = f"(optional) IOU Threshold override (default: {nms.iouThreshold})" - model.input_description[ - "confidenceThreshold" - ] = f"(optional) Confidence Threshold override (default: {nms.confidenceThreshold})" + model.input_description["confidenceThreshold"] = ( + f"(optional) Confidence Threshold override (default: {nms.confidenceThreshold})" + ) model.output_description["confidence"] = 'Boxes × Class confidence (see user-defined metadata "classes")' model.output_description["coordinates"] = "Boxes × [x, y, width, height] (relative to image size)" model.save(f) # pipelined diff --git a/models/experimental.py b/models/experimental.py index 37b5940d65..bba3c2be89 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -1,5 +1,6 @@ # YOLOv3 🚀 by Ultralytics, AGPL-3.0 license """Experimental modules.""" + import math import numpy as np diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py index 7e69fc6567..ff417e1581 100644 --- a/utils/loggers/clearml/clearml_utils.py +++ b/utils/loggers/clearml/clearml_utils.py @@ -1,4 +1,5 @@ """Main Logger class for ClearML experiment tracking.""" + import glob import re from pathlib import Path From cff02836976652a1491eebb4319edea81685d582 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 24 Mar 2024 18:17:28 +0100 Subject: [PATCH 1062/1185] [Snyk] Security upgrade pillow from 9.5.0 to 10.2.0 (#2190) * fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-6219984 - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-6219986 * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: snyk-bot Co-authored-by: UltralyticsAssistant --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 59020cce86..a6e2f09822 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ gitpython>=3.1.30 matplotlib>=3.3 numpy>=1.23.5 opencv-python>=4.1.1 -Pillow>=10.0.1 +Pillow>=10.2.0 psutil # system resources PyYAML>=5.3.1 requests>=2.23.0 From 2acf78bf48ce60e03246770888519976366fc51a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 7 Apr 2024 00:44:02 +0200 Subject: [PATCH 1063/1185] [Snyk] Security upgrade wheel from 0.32.2 to 0.38.0 (#2197) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-WHEEL-3180413 Co-authored-by: snyk-bot --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index a6e2f09822..803ee6ebd3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -47,3 +47,4 @@ setuptools>=65.5.1 # Snyk vulnerability fix # mss # screenshots # albumentations>=1.0.3 # pycocotools>=2.0.6 # COCO mAP +wheel>=0.38.0 # not directly required, pinned by Snyk to avoid a vulnerability From 541ba28c30bebb02272a408c6f501e2bc026188c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 7 Apr 2024 00:44:15 +0200 Subject: [PATCH 1064/1185] [Snyk] Security upgrade pillow from 9.5.0 to 10.3.0 (#2199) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-6514866 Co-authored-by: snyk-bot --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 803ee6ebd3..fee7d74c9a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ gitpython>=3.1.30 matplotlib>=3.3 numpy>=1.23.5 opencv-python>=4.1.1 -Pillow>=10.2.0 +Pillow>=10.3.0 psutil # system resources PyYAML>=5.3.1 requests>=2.23.0 From 4bcaa4e5f3a9e24aa83dd95295ffdbc8d4e57979 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 13 Apr 2024 17:20:42 +0200 Subject: [PATCH 1065/1185] Sort imports with Ruff and iSort (#2201) * Sort imports with Ruff and iSort * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: UltralyticsAssistant From 4b859a765ed227154812ade718393f8782999067 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Apr 2024 20:42:48 -0700 Subject: [PATCH 1066/1185] Bump gunicorn from 19.10.0 to 22.0.0 in /utils/google_app_engine (#2203) * Bump gunicorn from 19.10.0 to 22.0.0 in /utils/google_app_engine Bumps [gunicorn](https://github.com/benoitc/gunicorn) from 19.10.0 to 22.0.0. - [Release notes](https://github.com/benoitc/gunicorn/releases) - [Commits](https://github.com/benoitc/gunicorn/compare/19.10.0...22.0.0) --- updated-dependencies: - dependency-name: gunicorn dependency-type: direct:production ... Signed-off-by: dependabot[bot] * [Snyk] Security upgrade gunicorn from 19.10.0 to 22.0.0 (#2204) fix: utils/google_app_engine/additional_requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-GUNICORN-6615672 Co-authored-by: snyk-bot --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher Co-authored-by: snyk-bot --- utils/google_app_engine/additional_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/google_app_engine/additional_requirements.txt b/utils/google_app_engine/additional_requirements.txt index c1a2af2c11..821c3caf3c 100644 --- a/utils/google_app_engine/additional_requirements.txt +++ b/utils/google_app_engine/additional_requirements.txt @@ -1,5 +1,5 @@ # add these requirements in your app on top of the existing ones pip==23.3 Flask==2.3.2 -gunicorn==19.10.0 +gunicorn==22.0.0 werkzeug>=3.0.1 # not directly required, pinned by Snyk to avoid a vulnerability From 949f6aff2aba721390ddc19b7f30d87f2ee58d6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 27 Apr 2024 13:19:17 +0200 Subject: [PATCH 1067/1185] Bump slackapi/slack-github-action from 1.25.0 to 1.26.0 in /.github/workflows (#2206) Bump slackapi/slack-github-action in /.github/workflows Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 1.25.0 to 1.26.0. - [Release notes](https://github.com/slackapi/slack-github-action/releases) - [Commits](https://github.com/slackapi/slack-github-action/compare/v1.25.0...v1.26.0) --- updated-dependencies: - dependency-name: slackapi/slack-github-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 1f9b59332b..425ab487d2 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -114,7 +114,7 @@ jobs: steps: - name: Check for failure and notify if: (needs.Tests.result == 'failure' || needs.Tests.result == 'cancelled') && github.repository == 'ultralytics/yolov3' && (github.event_name == 'schedule' || github.event_name == 'push') - uses: slackapi/slack-github-action@v1.25.0 + uses: slackapi/slack-github-action@v1.26.0 with: payload: | {"text": " GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n"} From 54028975f176fd4ce53eccfbf52d43c156d97840 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 28 Apr 2024 17:19:17 +0200 Subject: [PATCH 1068/1185] Add Python docstrings (#2209) * Add Python docstrings * Auto-format by https://ultralytics.com/actions * Reformat * Auto-format by https://ultralytics.com/actions * Reformat * Reformat --------- Co-authored-by: UltralyticsAssistant --- CITATION.cff | 6 +- README.zh-CN.md | 80 ++++++------- benchmarks.py | 4 + classify/predict.py | 2 + classify/train.py | 8 +- classify/val.py | 4 + detect.py | 2 + export.py | 52 ++++++-- hubconf.py | 36 ++++-- models/common.py | 160 +++++++++++++++++++++++-- models/experimental.py | 19 ++- models/tf.py | 103 ++++++++++++++-- models/yolo.py | 42 +++++-- segment/predict.py | 2 + segment/train.py | 12 +- segment/val.py | 8 +- train.py | 10 +- utils/__init__.py | 22 +++- utils/activations.py | 29 ++++- utils/augmentations.py | 48 ++++++-- utils/autoanchor.py | 4 +- utils/autobatch.py | 6 +- utils/callbacks.py | 2 +- utils/dataloaders.py | 97 +++++++++++---- utils/downloads.py | 12 +- utils/flask_rest_api/restapi.py | 3 + utils/general.py | 186 ++++++++++++++++++++--------- utils/loggers/__init__.py | 58 ++++++--- utils/loggers/comet/__init__.py | 37 ++++++ utils/loggers/comet/comet_utils.py | 1 + utils/loggers/comet/hpo.py | 4 + utils/loggers/wandb/wandb_utils.py | 3 +- utils/loss.py | 24 +++- utils/metrics.py | 20 +++- utils/plots.py | 41 ++++--- utils/segment/augmentations.py | 3 +- utils/segment/dataloaders.py | 6 +- utils/segment/general.py | 4 +- utils/segment/loss.py | 14 ++- utils/segment/metrics.py | 10 +- utils/segment/plots.py | 6 +- utils/torch_utils.py | 78 ++++++++---- utils/triton.py | 3 + val.py | 8 +- 44 files changed, 989 insertions(+), 290 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index c277230d92..117c3a552b 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -3,9 +3,9 @@ preferred-citation: type: software message: If you use YOLOv5, please cite it as below. authors: - - family-names: Jocher - given-names: Glenn - orcid: "https://orcid.org/0000-0001-5950-6979" + - family-names: Jocher + given-names: Glenn + orcid: "https://orcid.org/0000-0001-5950-6979" title: "YOLOv5 by Ultralytics" version: 7.0 doi: 10.5281/zenodo.3908559 diff --git a/README.zh-CN.md b/README.zh-CN.md index 22b4374654..0467d0c7c0 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -179,8 +179,8 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - -| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | -| :--------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | +| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | +|:----------------------------------------------------------------------------------:|:---------------------------------------------------------------------------:|:----------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------:| | 将您的自定义数据集进行标注并直接导出到 YOLOv3 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv3 [ClearML](https://cutt.ly/yolov5-readme-clearml)(开源!) | 永远免费,[Comet](https://bit.ly/yolov5-readme-comet2)可让您保存 YOLOv3 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv3 推理的速度最高可提高6倍 | ##
Ultralytics HUB
@@ -212,19 +212,19 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结 ### 预训练模型 -| 模型 | 尺寸
(像素) | mAPval
50-95 | mAPval
50 | 推理速度
CPU b1
(ms) | 推理速度
V100 b1
(ms) | 速度
V100 b32
(ms) | 参数量
(M) | FLOPs
@640 (B) | -| ---------------------------------------------------------------------------------------------- | --------------------- | -------------------- | ----------------- | --------------------------------- | ---------------------------------- | ------------------------------- | ------------------ | ---------------------- | -| [YOLOv5n](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n.pt) | 640 | 28.0 | 45.7 | **45** | **6.3** | **0.6** | **1.9** | **4.5** | -| [YOLOv5s](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt) | 640 | 37.4 | 56.8 | 98 | 6.4 | 0.9 | 7.2 | 16.5 | -| [YOLOv5m](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m.pt) | 640 | 45.4 | 64.1 | 224 | 8.2 | 1.7 | 21.2 | 49.0 | -| [YOLOv5l](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l.pt) | 640 | 49.0 | 67.3 | 430 | 10.1 | 2.7 | 46.5 | 109.1 | -| [YOLOv5x](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x.pt) | 640 | 50.7 | 68.9 | 766 | 12.1 | 4.8 | 86.7 | 205.7 | -| | | | | | | | | | -| [YOLOv5n6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n6.pt) | 1280 | 36.0 | 54.4 | 153 | 8.1 | 2.1 | 3.2 | 4.6 | -| [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | -| [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | -| [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | -| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+[TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- | +| 模型 | 尺寸
(像素) | mAPval
50-95 | mAPval
50 | 推理速度
CPU b1
(ms) | 推理速度
V100 b1
(ms) | 速度
V100 b32
(ms) | 参数量
(M) | FLOPs
@640 (B) | +|------------------------------------------------------------------------------------------------|-----------------|----------------------|-------------------|-----------------------------|------------------------------|-----------------------------|-----------------|------------------------| +| [YOLOv5n](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n.pt) | 640 | 28.0 | 45.7 | **45** | **6.3** | **0.6** | **1.9** | **4.5** | +| [YOLOv5s](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt) | 640 | 37.4 | 56.8 | 98 | 6.4 | 0.9 | 7.2 | 16.5 | +| [YOLOv5m](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m.pt) | 640 | 45.4 | 64.1 | 224 | 8.2 | 1.7 | 21.2 | 49.0 | +| [YOLOv5l](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l.pt) | 640 | 49.0 | 67.3 | 430 | 10.1 | 2.7 | 46.5 | 109.1 | +| [YOLOv5x](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x.pt) | 640 | 50.7 | 68.9 | 766 | 12.1 | 4.8 | 86.7 | 205.7 | +| | | | | | | | | | +| [YOLOv5n6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n6.pt) | 1280 | 36.0 | 54.4 | 153 | 8.1 | 2.1 | 3.2 | 4.6 | +| [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | +| [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | +| [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | +| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+[TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- |
笔记 @@ -252,13 +252,13 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结 我们使用 A100 GPU 在 COCO 上以 640 图像大小训练了 300 epochs 得到 YOLOv5 分割模型。我们将所有模型导出到 ONNX FP32 以进行 CPU 速度测试,并导出到 TensorRT FP16 以进行 GPU 速度测试。为了便于再现,我们在 Google [Colab Pro](https://colab.research.google.com/signup) 上进行了所有速度测试。 -| 模型 | 尺寸
(像素) | mAPbox
50-95 | mAPmask
50-95 | 训练时长
300 epochs
A100 GPU(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TRT A100
(ms) | 参数量
(M) | FLOPs
@640 (B) | -| ------------------------------------------------------------------------------------------ | --------------------- | -------------------- | --------------------- | ----------------------------------------------- | ----------------------------------- | ----------------------------------- | ------------------ | ---------------------- | -| [YOLOv5n-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-seg.pt) | 640 | 27.6 | 23.4 | 80:17 | **62.7** | **1.2** | **2.0** | **7.1** | -| [YOLOv5s-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt) | 640 | 37.6 | 31.7 | 88:16 | 173.3 | 1.4 | 7.6 | 26.4 | -| [YOLOv5m-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-seg.pt) | 640 | 45.0 | 37.1 | 108:36 | 427.0 | 2.2 | 22.0 | 70.8 | -| [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | -| [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | +| 模型 | 尺寸
(像素) | mAPbox
50-95 | mAPmask
50-95 | 训练时长
300 epochs
A100 GPU(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TRT A100
(ms) | 参数量
(M) | FLOPs
@640 (B) | +|--------------------------------------------------------------------------------------------|-----------------|----------------------|-----------------------|-----------------------------------------|-------------------------------|-------------------------------|-----------------|------------------------| +| [YOLOv5n-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-seg.pt) | 640 | 27.6 | 23.4 | 80:17 | **62.7** | **1.2** | **2.0** | **7.1** | +| [YOLOv5s-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt) | 640 | 37.6 | 31.7 | 88:16 | 173.3 | 1.4 | 7.6 | 26.4 | +| [YOLOv5m-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-seg.pt) | 640 | 45.0 | 37.1 | 108:36 | 427.0 | 2.2 | 22.0 | 70.8 | +| [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | +| [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | - 所有模型使用 SGD 优化器训练, 都使用 `lr0=0.01` 和 `weight_decay=5e-5` 参数, 图像大小为 640 。
训练 log 可以查看 https://wandb.ai/glenn-jocher/YOLOv5_v70_official - **准确性**结果都在 COCO 数据集上,使用单模型单尺度测试得到。
复现命令 `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt` @@ -306,7 +306,7 @@ model = torch.hub.load( ``` | ![zidane](https://user-images.githubusercontent.com/26833433/203113421-decef4c4-183d-4a0a-a6c2-6435b33bc5d3.jpg) | ![bus](https://user-images.githubusercontent.com/26833433/203113416-11fe0025-69f7-4874-a0a6-65d0bfe2999a.jpg) | -| ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | +|------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------| ### 模型导出 @@ -329,23 +329,23 @@ YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) 带来对 我们使用 4xA100 实例在 ImageNet 上训练了 90 个 epochs 得到 YOLOv5-cls 分类模型,我们训练了 ResNet 和 EfficientNet 模型以及相同的默认训练设置以进行比较。我们将所有模型导出到 ONNX FP32 以进行 CPU 速度测试,并导出到 TensorRT FP16 以进行 GPU 速度测试。为了便于重现,我们在 Google 上进行了所有速度测试 [Colab Pro](https://colab.research.google.com/signup) 。 -| 模型 | 尺寸
(像素) | acc
top1 | acc
top5 | 训练时长
90 epochs
4xA100(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TensorRT V100
(ms) | 参数
(M) | FLOPs
@640 (B) | -| -------------------------------------------------------------------------------------------------- | --------------------- | ---------------- | ---------------- | -------------------------------------------- | ----------------------------------- | ---------------------------------------- | ---------------- | ---------------------- | -| [YOLOv5n-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-cls.pt) | 224 | 64.6 | 85.4 | 7:59 | **3.3** | **0.5** | **2.5** | **0.5** | -| [YOLOv5s-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt) | 224 | 71.5 | 90.2 | 8:09 | 6.6 | 0.6 | 5.4 | 1.4 | -| [YOLOv5m-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-cls.pt) | 224 | 75.9 | 92.9 | 10:06 | 15.5 | 0.9 | 12.9 | 3.9 | -| [YOLOv5l-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-cls.pt) | 224 | 78.0 | 94.0 | 11:56 | 26.9 | 1.4 | 26.5 | 8.5 | -| [YOLOv5x-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-cls.pt) | 224 | **79.0** | **94.4** | 15:04 | 54.3 | 1.8 | 48.1 | 15.9 | -| | | | | | | | | | -| [ResNet18](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet18.pt) | 224 | 70.3 | 89.5 | **6:47** | 11.2 | 0.5 | 11.7 | 3.7 | -| [Resnetzch](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet34.pt) | 224 | 73.9 | 91.8 | 8:33 | 20.6 | 0.9 | 21.8 | 7.4 | -| [ResNet50](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet50.pt) | 224 | 76.8 | 93.4 | 11:10 | 23.4 | 1.0 | 25.6 | 8.5 | -| [ResNet101](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet101.pt) | 224 | 78.5 | 94.3 | 17:10 | 42.1 | 1.9 | 44.5 | 15.9 | -| | | | | | | | | | -| [EfficientNet_b0](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b0.pt) | 224 | 75.1 | 92.4 | 13:03 | 12.5 | 1.3 | 5.3 | 1.0 | -| [EfficientNet_b1](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b1.pt) | 224 | 76.4 | 93.2 | 17:04 | 14.9 | 1.6 | 7.8 | 1.5 | -| [EfficientNet_b2](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b2.pt) | 224 | 76.6 | 93.4 | 17:10 | 15.9 | 1.6 | 9.1 | 1.7 | -| [EfficientNet_b3](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b3.pt) | 224 | 77.7 | 94.0 | 19:19 | 18.9 | 1.9 | 12.2 | 2.4 | +| 模型 | 尺寸
(像素) | acc
top1 | acc
top5 | 训练时长
90 epochs
4xA100(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TensorRT V100
(ms) | 参数
(M) | FLOPs
@640 (B) | +|----------------------------------------------------------------------------------------------------|-----------------|------------------|------------------|--------------------------------------|-------------------------------|------------------------------------|----------------|------------------------| +| [YOLOv5n-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-cls.pt) | 224 | 64.6 | 85.4 | 7:59 | **3.3** | **0.5** | **2.5** | **0.5** | +| [YOLOv5s-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt) | 224 | 71.5 | 90.2 | 8:09 | 6.6 | 0.6 | 5.4 | 1.4 | +| [YOLOv5m-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-cls.pt) | 224 | 75.9 | 92.9 | 10:06 | 15.5 | 0.9 | 12.9 | 3.9 | +| [YOLOv5l-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-cls.pt) | 224 | 78.0 | 94.0 | 11:56 | 26.9 | 1.4 | 26.5 | 8.5 | +| [YOLOv5x-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-cls.pt) | 224 | **79.0** | **94.4** | 15:04 | 54.3 | 1.8 | 48.1 | 15.9 | +| | | | | | | | | | +| [ResNet18](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet18.pt) | 224 | 70.3 | 89.5 | **6:47** | 11.2 | 0.5 | 11.7 | 3.7 | +| [Resnetzch](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet34.pt) | 224 | 73.9 | 91.8 | 8:33 | 20.6 | 0.9 | 21.8 | 7.4 | +| [ResNet50](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet50.pt) | 224 | 76.8 | 93.4 | 11:10 | 23.4 | 1.0 | 25.6 | 8.5 | +| [ResNet101](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet101.pt) | 224 | 78.5 | 94.3 | 17:10 | 42.1 | 1.9 | 44.5 | 15.9 | +| | | | | | | | | | +| [EfficientNet_b0](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b0.pt) | 224 | 75.1 | 92.4 | 13:03 | 12.5 | 1.3 | 5.3 | 1.0 | +| [EfficientNet_b1](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b1.pt) | 224 | 76.4 | 93.2 | 17:04 | 14.9 | 1.6 | 7.8 | 1.5 | +| [EfficientNet_b2](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b2.pt) | 224 | 76.6 | 93.4 | 17:10 | 15.9 | 1.6 | 9.1 | 1.7 | +| [EfficientNet_b3](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b3.pt) | 224 | 77.7 | 94.0 | 19:19 | 18.9 | 1.9 | 12.2 | 2.4 |
Table Notes (点击以展开) diff --git a/benchmarks.py b/benchmarks.py index 2f7d58bd3a..e91f204d92 100644 --- a/benchmarks.py +++ b/benchmarks.py @@ -149,6 +149,9 @@ def test( def parse_opt(): + """Parses command line arguments for model inference configurations, including weights, image size, and device + options. + """ parser = argparse.ArgumentParser() parser.add_argument("--weights", type=str, default=ROOT / "yolov3-tiny.pt", help="weights path") parser.add_argument("--imgsz", "--img", "--img-size", type=int, default=640, help="inference size (pixels)") @@ -166,6 +169,7 @@ def parse_opt(): def main(opt): + """Executes tests or main pipeline on provided options, determining behavior based on `opt.test`.""" test(**vars(opt)) if opt.test else run(**vars(opt)) diff --git a/classify/predict.py b/classify/predict.py index 17dce7cd16..23d608ed32 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -204,6 +204,7 @@ def run( def parse_opt(): + """Parses command line arguments for model inference settings, returns a Namespace of options.""" parser = argparse.ArgumentParser() parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov5s-cls.pt", help="model path(s)") parser.add_argument("--source", type=str, default=ROOT / "data/images", help="file/dir/URL/glob/screen/0(webcam)") @@ -229,6 +230,7 @@ def parse_opt(): def main(opt): + """Entry point for running the model; checks requirements and calls `run` with options parsed from CLI.""" check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) run(**vars(opt)) diff --git a/classify/train.py b/classify/train.py index 9b6aed86a8..bfcf36fd04 100644 --- a/classify/train.py +++ b/classify/train.py @@ -76,6 +76,9 @@ def train(opt, device): + """Trains a model on a given dataset using specified options and device, handling data loading, model optimization, + and logging. + """ init_seeds(opt.seed + 1 + RANK, deterministic=True) save_dir, data, bs, epochs, nw, imgsz, pretrained = ( opt.save_dir, @@ -306,6 +309,7 @@ def train(opt, device): def parse_opt(known=False): + """Parses command line arguments for model configuration and training options.""" parser = argparse.ArgumentParser() parser.add_argument("--model", type=str, default="yolov5s-cls.pt", help="initial weights path") parser.add_argument("--data", type=str, default="imagenette160", help="cifar10, cifar100, mnist, imagenet, ...") @@ -333,7 +337,7 @@ def parse_opt(known=False): def main(opt): - # Checks + """Initializes training environment, checks, DDP mode setup, and starts training with given options.""" if RANK in {-1, 0}: print_args(vars(opt)) check_git_status() @@ -357,7 +361,7 @@ def main(opt): def run(**kwargs): - # Usage: from yolov5 import classify; classify.train.run(data=mnist, imgsz=320, model='yolov5m') + """Executes YOLOv5 model training with dynamic options, e.g., `run(data='mnist', imgsz=320, model='yolov5m')`.""" opt = parse_opt(True) for k, v in kwargs.items(): setattr(opt, k, v) diff --git a/classify/val.py b/classify/val.py index 3875001e85..bf786379f6 100644 --- a/classify/val.py +++ b/classify/val.py @@ -147,6 +147,7 @@ def run( def parse_opt(): + """Parses command-line options for model configuration and returns an argparse.Namespace of options.""" parser = argparse.ArgumentParser() parser.add_argument("--data", type=str, default=ROOT / "../datasets/mnist", help="dataset path") parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov5s-cls.pt", help="model.pt path(s)") @@ -166,6 +167,9 @@ def parse_opt(): def main(opt): + """Executes the main pipeline, checks and installs requirements, then runs inference or training based on provided + options. + """ check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) run(**vars(opt)) diff --git a/detect.py b/detect.py index 4502e5fc35..daca7fac14 100644 --- a/detect.py +++ b/detect.py @@ -232,6 +232,7 @@ def run( def parse_opt(): + """Parses and returns command-line options for model inference configurations.""" parser = argparse.ArgumentParser() parser.add_argument( "--weights", nargs="+", type=str, default=ROOT / "yolov3-tiny.pt", help="model path or triton URL" @@ -269,6 +270,7 @@ def parse_opt(): def main(opt): + """Entry point for running the model; checks requirements and calls `run` with parsed options.""" check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) run(**vars(opt)) diff --git a/export.py b/export.py index 311c4cae81..70f5045a39 100644 --- a/export.py +++ b/export.py @@ -92,6 +92,7 @@ class iOSModel(torch.nn.Module): def __init__(self, model, im): + """Initializes an iOSModel with normalized input dimensions and number of classes from a torch model.""" super().__init__() b, c, h, w = im.shape # batch, channel, height, width self.model = model @@ -104,12 +105,13 @@ def __init__(self, model, im): # self.normalize = torch.tensor([1. / w, 1. / h, 1. / w, 1. / h]).expand(np, 4) # explicit (faster, larger) def forward(self, x): + """Performs forward pass, returns scaled confidences and normalized coordinates given input tensor `x`.""" xywh, conf, cls = self.model(x)[0].squeeze().split((4, 1, self.nc), 1) return cls * conf, xywh * self.normalize # confidence (3780, 80), coordinates (3780, 4) def export_formats(): - # YOLOv3 export formats + """Lists supported YOLOv3 model export formats including file suffixes and CPU/GPU compatibility.""" x = [ ["PyTorch", "-", ".pt", True, True], ["TorchScript", "torchscript", ".torchscript", True, True], @@ -128,7 +130,7 @@ def export_formats(): def try_export(inner_func): - # YOLOv3 export decorator, i..e @try_export + """Decorator to profile and log the export process of YOLOv3 models, handling successes and failures.""" inner_args = get_default_args(inner_func) def outer_func(*args, **kwargs): @@ -147,7 +149,11 @@ def outer_func(*args, **kwargs): @try_export def export_torchscript(model, im, file, optimize, prefix=colorstr("TorchScript:")): - # YOLOv3 TorchScript model export + """ + Exports a YOLOv3 model to TorchScript format, optionally optimizing for mobile. + + Args: model, im (input image), file (path), optimize (bool). + """ LOGGER.info(f"\n{prefix} starting export with torch {torch.__version__}...") f = file.with_suffix(".torchscript") @@ -163,7 +169,7 @@ def export_torchscript(model, im, file, optimize, prefix=colorstr("TorchScript:" @try_export def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr("ONNX:")): - # YOLOv3 ONNX export + """Exports a YOLOv3 model to ONNX format with dynamic shapes and simplification options.""" check_requirements("onnx>=1.12.0") import onnx @@ -285,7 +291,9 @@ def transform_fn(data_item): @try_export def export_paddle(model, im, file, metadata, prefix=colorstr("PaddlePaddle:")): - # YOLOv3 Paddle export + """Exports a YOLOv3 model to PaddlePaddle format using X2Paddle, saving to `file` directory with metadata in + yaml. + """ check_requirements(("paddlepaddle", "x2paddle")) import x2paddle from x2paddle.convert import pytorch2paddle @@ -300,7 +308,7 @@ def export_paddle(model, im, file, metadata, prefix=colorstr("PaddlePaddle:")): @try_export def export_coreml(model, im, file, int8, half, nms, prefix=colorstr("CoreML:")): - # YOLOv3 CoreML export + """Exports YOLOv3 model to CoreML format with optional quantization and NMS; requires 'coremltools'.""" check_requirements("coremltools") import coremltools as ct @@ -325,7 +333,11 @@ def export_coreml(model, im, file, int8, half, nms, prefix=colorstr("CoreML:")): @try_export def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose=False, prefix=colorstr("TensorRT:")): - # YOLOv3 TensorRT export https://developer.nvidia.com/tensorrt + """ + Exports a YOLOv3 model to TensorRT engine format. + + Nvidia TensorRT: https://developer.nvidia.com/tensorrt + """ assert im.device.type != "cpu", "export running on CPU but must be on GPU, i.e. `python export.py --device 0`" try: import tensorrt as trt @@ -444,7 +456,11 @@ def export_saved_model( @try_export def export_pb(keras_model, file, prefix=colorstr("TensorFlow GraphDef:")): - # YOLOv3 TensorFlow GraphDef *.pb export https://github.com/leimao/Frozen_Graph_TensorFlow + """ + Exports Keras model as TensorFlow GraphDef *.pb file, compatible with YOLOv3. + + See https://github.com/leimao/Frozen_Graph_TensorFlow for details. + """ import tensorflow as tf from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2 @@ -461,7 +477,7 @@ def export_pb(keras_model, file, prefix=colorstr("TensorFlow GraphDef:")): @try_export def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=colorstr("TensorFlow Lite:")): - # YOLOv3 TensorFlow Lite export + """Exports a YOLOv3 model to TensorFlow Lite format, supports fp16/int8, NMS options, and custom data.""" import tensorflow as tf LOGGER.info(f"\n{prefix} starting export with tensorflow {tf.__version__}...") @@ -493,7 +509,11 @@ def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=c @try_export def export_edgetpu(file, prefix=colorstr("Edge TPU:")): - # YOLOv3 Edge TPU export https://coral.ai/docs/edgetpu/models-intro/ + """ + Exports YOLOv3 model to Edge TPU compatible format; requires Linux and Edge TPU compiler. + + https://coral.ai/docs/edgetpu/compiler/ + """ cmd = "edgetpu_compiler --version" help_url = "https://coral.ai/docs/edgetpu/compiler/" assert platform.system() == "Linux", f"export only supported on Linux. See {help_url}" @@ -531,7 +551,7 @@ def export_edgetpu(file, prefix=colorstr("Edge TPU:")): @try_export def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): - # YOLOv3 TensorFlow.js export + """Exports a YOLOv3 model to TensorFlow.js format, optionally quantizing to uint8.""" check_requirements("tensorflowjs") import tensorflowjs as tfjs @@ -568,7 +588,7 @@ def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): def add_tflite_metadata(file, metadata, num_outputs): - # Add metadata to *.tflite models per https://www.tensorflow.org/lite/models/convert/metadata + """Adds TFLite model metadata for enhanced model understanding and processing; requires `tflite_support`.""" with contextlib.suppress(ImportError): # check_requirements('tflite_support') from tflite_support import flatbuffers @@ -601,7 +621,9 @@ def add_tflite_metadata(file, metadata, num_outputs): def pipeline_coreml(model, im, file, names, y, prefix=colorstr("CoreML Pipeline:")): - # YOLOv3 CoreML pipeline + """Executes YOLOv3 CoreML pipeline, handling image preprocessing, prediction, and NMS, saving the model with + metadata. + """ import coremltools as ct from PIL import Image @@ -866,6 +888,9 @@ def run( def parse_opt(known=False): + """Parses command line arguments for model export configuration, including data paths, weights, and export + options. + """ parser = argparse.ArgumentParser() parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="dataset.yaml path") parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov3-tiny.pt", help="model.pt path(s)") @@ -900,6 +925,7 @@ def parse_opt(known=False): def main(opt): + """Executes model inference, supporting various export formats based on specified weights and options.""" for opt.weights in opt.weights if isinstance(opt.weights, list) else [opt.weights]: run(**vars(opt)) diff --git a/hubconf.py b/hubconf.py index 729eed0600..a950909be1 100644 --- a/hubconf.py +++ b/hubconf.py @@ -84,57 +84,71 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbo def custom(path="path/to/model.pt", autoshape=True, _verbose=True, device=None): - # YOLOv3 custom or local model + """Loads a custom or local YOLOv3 model from a specified path, with options for autoshaping and device + assignment. + """ return _create(path, autoshape=autoshape, verbose=_verbose, device=device) def yolov5n(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - # YOLOv3-nano model https://github.com/ultralytics/yolov5 + """Instantiates YOLOv5n model; optional pretrained weights, class/channel count, autoshaping, device selection.""" return _create("yolov5n", pretrained, channels, classes, autoshape, _verbose, device) def yolov5s(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - # YOLOv3-small model https://github.com/ultralytics/yolov5 + """Loads YOLOv5s model, with options for pretrained weights, channel/class customization, autoshaping, and device + choice. + """ return _create("yolov5s", pretrained, channels, classes, autoshape, _verbose, device) def yolov5m(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - # YOLOv3-medium model https://github.com/ultralytics/yolov5 + """Loads YOLOv5m model with optional pretrained weights, channel/class customization, autoshaping, device + selection. + """ return _create("yolov5m", pretrained, channels, classes, autoshape, _verbose, device) def yolov5l(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - # YOLOv3-large model https://github.com/ultralytics/yolov5 + """Loads YOLOv5l model with options for pretrained weights, channel/class customization, autoshaping, and device + selection. + """ return _create("yolov5l", pretrained, channels, classes, autoshape, _verbose, device) def yolov5x(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - # YOLOv3-xlarge model https://github.com/ultralytics/yolov5 + """Loads YOLOv5x model with customization options for weights, channels, classes, autoshaping, and device + selection. + """ return _create("yolov5x", pretrained, channels, classes, autoshape, _verbose, device) def yolov5n6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - # YOLOv3-nano-P6 model https://github.com/ultralytics/yolov5 + """Loads the YOLOv5n6 model with options for weights, channels, classes, shaping, and device.""" return _create("yolov5n6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5s6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - # YOLOv3-small-P6 model https://github.com/ultralytics/yolov5 + """Loads the YOLOv5s6 model; see options for weights, channels, classes, + at https://github.com/ultralytics/yolov5.""" return _create("yolov5s6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5m6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - # YOLOv3-medium-P6 model https://github.com/ultralytics/yolov5 + """Loads YOLOv5m6 model; options for weights, channels, classes documented at + https://github.com/ultralytics/yolov5.""" return _create("yolov5m6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5l6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - # YOLOv3-large-P6 model https://github.com/ultralytics/yolov5 + """Loads YOLOv5l6 model with customization for pretraining, channels, classes; details at + https://github.com/ultralytics/yolov5.""" return _create("yolov5l6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5x6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - # YOLOv3-xlarge-P6 model https://github.com/ultralytics/yolov5 + """Loads the YOLOv5x6 model, allowing customization for channels and classes; more at + https://github.com/ultralytics/yolov5.""" return _create("yolov5x6", pretrained, channels, classes, autoshape, _verbose, device) diff --git a/models/common.py b/models/common.py index 6e533b56ec..a2b89164e1 100644 --- a/models/common.py +++ b/models/common.py @@ -46,7 +46,7 @@ def autopad(k, p=None, d=1): # kernel, padding, dilation - # Pad to 'same' shape outputs + """Automatically calculates same shape padding for convolutional layers, optionally adjusts for dilation.""" if d > 1: k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k] # actual kernel-size if p is None: @@ -59,33 +59,50 @@ class Conv(nn.Module): default_act = nn.SiLU() # default activation def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True): + """Initializes a standard Conv2D layer with batch normalization and optional activation; args are channel_in, + channel_out, kernel_size, stride, padding, groups, dilation, and activation. + """ super().__init__() self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False) self.bn = nn.BatchNorm2d(c2) self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity() def forward(self, x): + """Applies convolution, batch normalization, and activation to input `x`; `x` shape: [N, C_in, H, W] -> [N, + C_out, H_out, W_out]. + """ return self.act(self.bn(self.conv(x))) def forward_fuse(self, x): + """Applies fused convolution and activation to input `x`; input shape: [N, C_in, H, W] -> [N, C_out, H_out, + W_out]. + """ return self.act(self.conv(x)) class DWConv(Conv): # Depth-wise convolution def __init__(self, c1, c2, k=1, s=1, d=1, act=True): # ch_in, ch_out, kernel, stride, dilation, activation + """Initializes depth-wise convolution with optional activation; parameters are channel in/out, kernel, stride, + dilation. + """ super().__init__(c1, c2, k, s, g=math.gcd(c1, c2), d=d, act=act) class DWConvTranspose2d(nn.ConvTranspose2d): # Depth-wise transpose convolution def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0): # ch_in, ch_out, kernel, stride, padding, padding_out + """Initializes a depth-wise or transpose convolution layer with specified in/out channels, kernel size, stride, + and padding. + """ super().__init__(c1, c2, k, s, p1, p2, groups=math.gcd(c1, c2)) class TransformerLayer(nn.Module): # Transformer layer https://arxiv.org/abs/2010.11929 (LayerNorm layers removed for better performance) def __init__(self, c, num_heads): + """Initializes a Transformer layer as per https://arxiv.org/abs/2010.11929, sans LayerNorm, with specified + embedding dimension and number of heads.""" super().__init__() self.q = nn.Linear(c, c, bias=False) self.k = nn.Linear(c, c, bias=False) @@ -95,6 +112,9 @@ def __init__(self, c, num_heads): self.fc2 = nn.Linear(c, c, bias=False) def forward(self, x): + """Performs forward pass with multi-head attention and residual connections on input tensor 'x' [batch, seq_len, + features]. + """ x = self.ma(self.q(x), self.k(x), self.v(x))[0] + x x = self.fc2(self.fc1(x)) + x return x @@ -103,6 +123,7 @@ def forward(self, x): class TransformerBlock(nn.Module): # Vision Transformer https://arxiv.org/abs/2010.11929 def __init__(self, c1, c2, num_heads, num_layers): + """Initializes a Transformer block with optional convolution, linear, and transformer layers.""" super().__init__() self.conv = None if c1 != c2: @@ -112,6 +133,7 @@ def __init__(self, c1, c2, num_heads, num_layers): self.c2 = c2 def forward(self, x): + """Applies an optional convolution, transforms features, and reshapes output matching input dimensions.""" if self.conv is not None: x = self.conv(x) b, _, w, h = x.shape @@ -122,6 +144,9 @@ def forward(self, x): class Bottleneck(nn.Module): # Standard bottleneck def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion + """Initializes a standard bottleneck layer with optional shortcut; args: input channels (c1), output channels + (c2), shortcut (bool), groups (g), expansion factor (e). + """ super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, 1, 1) @@ -129,12 +154,17 @@ def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcu self.add = shortcut and c1 == c2 def forward(self, x): + """Executes forward pass, performing convolutional ops and optional shortcut addition; expects input tensor + x. + """ return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) class BottleneckCSP(nn.Module): # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion + """Initializes CSP Bottleneck with channel in/out, optional shortcut, groups, expansion; see + https://github.com/WongKinYiu/CrossStagePartialNetworks.""" super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, 1, 1) @@ -146,6 +176,9 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, nu self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n))) def forward(self, x): + """Processes input through layers, combining outputs with activation and normalization for feature + extraction. + """ y1 = self.cv3(self.m(self.cv1(x))) y2 = self.cv2(x) return self.cv4(self.act(self.bn(torch.cat((y1, y2), 1)))) @@ -154,7 +187,9 @@ def forward(self, x): class CrossConv(nn.Module): # Cross Convolution Downsample def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False): - # ch_in, ch_out, kernel, stride, groups, expansion, shortcut + """Initializes CrossConv with downsample options, combining 1D and 2D convolutions, optional shortcut if + input/output channels match. + """ super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, (1, k), (1, s)) @@ -162,12 +197,16 @@ def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False): self.add = shortcut and c1 == c2 def forward(self, x): + """Performs forward pass using sequential 1D and 2D convolutions with optional shortcut addition.""" return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) class C3(nn.Module): # CSP Bottleneck with 3 convolutions def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion + """Initializes CSP Bottleneck with 3 convolutions, optional shortcuts, group convolutions, and expansion + factor. + """ super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, 1, 1) @@ -176,12 +215,14 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, nu self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n))) def forward(self, x): + """Processes input tensor `x` through convolutions and bottlenecks, returning the concatenated output tensor.""" return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1)) class C3x(C3): # C3 module with cross-convolutions def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): + """Initializes a C3x module with cross-convolutions, extending the C3 module with customizable parameters.""" super().__init__(c1, c2, n, shortcut, g, e) c_ = int(c2 * e) self.m = nn.Sequential(*(CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n))) @@ -190,6 +231,7 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): class C3TR(C3): # C3 module with TransformerBlock() def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): + """Initializes a C3 module with TransformerBlock, extending C3 for attention mechanisms.""" super().__init__(c1, c2, n, shortcut, g, e) c_ = int(c2 * e) self.m = TransformerBlock(c_, c_, 4, n) @@ -198,6 +240,7 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): class C3SPP(C3): # C3 module with SPP() def __init__(self, c1, c2, k=(5, 9, 13), n=1, shortcut=True, g=1, e=0.5): + """Initializes C3SPP module, extending C3 with Spatial Pyramid Pooling for enhanced feature extraction.""" super().__init__(c1, c2, n, shortcut, g, e) c_ = int(c2 * e) self.m = SPP(c_, c_, k) @@ -206,6 +249,7 @@ def __init__(self, c1, c2, k=(5, 9, 13), n=1, shortcut=True, g=1, e=0.5): class C3Ghost(C3): # C3 module with GhostBottleneck() def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): + """Initializes C3Ghost module with Ghost Bottlenecks for efficient feature extraction.""" super().__init__(c1, c2, n, shortcut, g, e) c_ = int(c2 * e) # hidden channels self.m = nn.Sequential(*(GhostBottleneck(c_, c_) for _ in range(n))) @@ -214,6 +258,11 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): class SPP(nn.Module): # Spatial Pyramid Pooling (SPP) layer https://arxiv.org/abs/1406.4729 def __init__(self, c1, c2, k=(5, 9, 13)): + """ + Initializes SPP layer with specified channels and kernels. + + More at https://arxiv.org/abs/1406.4729 + """ super().__init__() c_ = c1 // 2 # hidden channels self.cv1 = Conv(c1, c_, 1, 1) @@ -221,6 +270,11 @@ def __init__(self, c1, c2, k=(5, 9, 13)): self.m = nn.ModuleList([nn.MaxPool2d(kernel_size=x, stride=1, padding=x // 2) for x in k]) def forward(self, x): + """ + Applies convolution and max pooling layers to the input tensor `x`, concatenates results for feature extraction. + + `x` is a tensor of shape [N, C, H, W]. See https://arxiv.org/abs/1406.4729 for more details. + """ x = self.cv1(x) with warnings.catch_warnings(): warnings.simplefilter("ignore") # suppress torch 1.9.0 max_pool2d() warning @@ -230,6 +284,7 @@ def forward(self, x): class SPPF(nn.Module): # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv3 by Glenn Jocher def __init__(self, c1, c2, k=5): # equivalent to SPP(k=(5, 9, 13)) + """Initializes the SPPF layer with specified input/output channels and kernel size for YOLOv3.""" super().__init__() c_ = c1 // 2 # hidden channels self.cv1 = Conv(c1, c_, 1, 1) @@ -237,6 +292,9 @@ def __init__(self, c1, c2, k=5): # equivalent to SPP(k=(5, 9, 13)) self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2) def forward(self, x): + """Performs forward pass combining convolutions and max pooling on input `x` of shape [N, C, H, W] to produce + feature map. + """ x = self.cv1(x) with warnings.catch_warnings(): warnings.simplefilter("ignore") # suppress torch 1.9.0 max_pool2d() warning @@ -248,11 +306,15 @@ def forward(self, x): class Focus(nn.Module): # Focus wh information into c-space def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups + """Initializes Focus module to focus width and height information into channel space with configurable + convolution parameters. + """ super().__init__() self.conv = Conv(c1 * 4, c2, k, s, p, g, act=act) # self.contract = Contract(gain=2) def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2) + """Applies focused downsampling to input tensor, returning a convolved output with increased channel depth.""" return self.conv(torch.cat((x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]), 1)) # return self.conv(self.contract(x)) @@ -260,12 +322,15 @@ def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2) class GhostConv(nn.Module): # Ghost Convolution https://github.com/huawei-noah/ghostnet def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups + """Initializes GhostConv with in/out channels, kernel size, stride, groups; see + https://github.com/huawei-noah/ghostnet.""" super().__init__() c_ = c2 // 2 # hidden channels self.cv1 = Conv(c1, c_, k, s, None, g, act=act) self.cv2 = Conv(c_, c_, 5, 1, None, c_, act=act) def forward(self, x): + """Executes forward pass, applying convolutions and concatenating results; input `x` is a tensor.""" y = self.cv1(x) return torch.cat((y, self.cv2(y)), 1) @@ -273,6 +338,8 @@ def forward(self, x): class GhostBottleneck(nn.Module): # Ghost Bottleneck https://github.com/huawei-noah/ghostnet def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride + """Initializes GhostBottleneck module with in/out channels, kernel size, and stride; see + https://github.com/huawei-noah/ghostnet.""" super().__init__() c_ = c2 // 2 self.conv = nn.Sequential( @@ -285,16 +352,23 @@ def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride ) def forward(self, x): + """Performs a forward pass through the network, returning the sum of convolution and shortcut outputs.""" return self.conv(x) + self.shortcut(x) class Contract(nn.Module): # Contract width-height into channels, i.e. x(1,64,80,80) to x(1,256,40,40) def __init__(self, gain=2): + """Initializes Contract module to refine input dimensions, e.g., from (1,64,80,80) to (1,256,40,40) with a + default gain of 2. + """ super().__init__() self.gain = gain def forward(self, x): + """Processes input tensor (b,c,h,w) to contracted shape (b,c*s^2,h/s,w/s) with default gain s=2, e.g., + (1,64,80,80) to (1,256,40,40). + """ b, c, h, w = x.size() # assert (h / s == 0) and (W / s == 0), 'Indivisible gain' s = self.gain x = x.view(b, c, h // s, s, w // s, s) # x(1,64,40,2,40,2) @@ -305,10 +379,16 @@ def forward(self, x): class Expand(nn.Module): # Expand channels into width-height, i.e. x(1,64,80,80) to x(1,16,160,160) def __init__(self, gain=2): + """Initializes Expand module to increase spatial dimensions by factor `gain` while reducing channels + correspondingly. + """ super().__init__() self.gain = gain def forward(self, x): + """Expands spatial dimensions of input tensor `x` by factor `gain` while reducing channels, transforming shape + `(B,C,H,W)` to `(B,C/gain^2,H*gain,W*gain)`. + """ b, c, h, w = x.size() # assert C / s ** 2 == 0, 'Indivisible gain' s = self.gain x = x.view(b, s, s, c // s**2, h, w) # x(1,2,2,16,80,80) @@ -319,17 +399,23 @@ def forward(self, x): class Concat(nn.Module): # Concatenate a list of tensors along dimension def __init__(self, dimension=1): + """Initializes a module to concatenate tensors along a specified dimension.""" super().__init__() self.d = dimension def forward(self, x): + """Concatenates a list of tensors along a specified dimension; x is a list of tensors to concatenate, dimension + defaults to 1. + """ return torch.cat(x, self.d) class DetectMultiBackend(nn.Module): # YOLOv3 MultiBackend class for python inference on various backends def __init__(self, weights="yolov5s.pt", device=torch.device("cpu"), dnn=False, data=None, fp16=False, fuse=True): - # Usage: + """Initializes multi-backend detection with options for various frameworks and devices, also handles model + download. + """ # PyTorch: weights = *.pt # TorchScript: *.torchscript # ONNX Runtime: *.onnx @@ -450,11 +536,17 @@ def __init__(self, weights="yolov5s.pt", device=torch.device("cpu"), dnn=False, import tensorflow as tf def wrap_frozen_graph(gd, inputs, outputs): + """Wraps a frozen TensorFlow GraphDef for inference, returning a pruned function for specified inputs + and outputs. + """ x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=""), []) # wrapped ge = x.graph.as_graph_element return x.prune(tf.nest.map_structure(ge, inputs), tf.nest.map_structure(ge, outputs)) def gd_outputs(gd): + """Extracts and sorts non-input (output) tensor names from a TensorFlow GraphDef, excluding 'NoOp' + prefixed tensors. + """ name_list, input_list = [], [] for node in gd.node: # tensorflow.core.framework.node_def_pb2.NodeDef name_list.append(node.name) @@ -528,7 +620,7 @@ def gd_outputs(gd): self.__dict__.update(locals()) # assign all variables to self def forward(self, im, augment=False, visualize=False): - # YOLOv3 MultiBackend inference + """Performs YOLOv3 inference on an input image tensor, optionally with augmentation and visualization.""" b, ch, h, w = im.shape # batch, channel, height, width if self.fp16 and im.dtype != torch.float16: im = im.half() # to FP16 @@ -610,10 +702,13 @@ def forward(self, im, augment=False, visualize=False): return self.from_numpy(y) def from_numpy(self, x): + """Converts a Numpy array to a PyTorch tensor on the specified device, else returns the input if not a Numpy + array. + """ return torch.from_numpy(x).to(self.device) if isinstance(x, np.ndarray) else x def warmup(self, imgsz=(1, 3, 640, 640)): - # Warmup model by running inference once + """Warms up the model by running inference once with a dummy input of shape imgsz.""" warmup_types = self.pt, self.jit, self.onnx, self.engine, self.saved_model, self.pb, self.triton if any(warmup_types) and (self.device.type != "cpu" or self.triton): im = torch.empty(*imgsz, dtype=torch.half if self.fp16 else torch.float, device=self.device) # input @@ -622,7 +717,11 @@ def warmup(self, imgsz=(1, 3, 640, 640)): @staticmethod def _model_type(p="path/to/model.pt"): - # Return model type from model path, i.e. path='path/to/model.onnx' -> type=onnx + """ + Determines model type from filepath or URL, supports various formats including ONNX, PT, JIT. + + See `export_formats` for all. + """ # types = [pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle] from export import export_formats from utils.downloads import is_url @@ -638,7 +737,7 @@ def _model_type(p="path/to/model.pt"): @staticmethod def _load_metadata(f=Path("path/to/meta.yaml")): - # Load metadata from meta.yaml if it exists + """Loads metadata from a YAML file, returning 'stride' and 'names' if the file exists, else 'None'.""" if f.exists(): d = yaml_load(f) return d["stride"], d["names"] # assign stride, names @@ -656,6 +755,9 @@ class AutoShape(nn.Module): amp = False # Automatic Mixed Precision (AMP) inference def __init__(self, model, verbose=True): + """Initializes the model for inference, setting attributes, and preparing for multithreaded execution with + optional verbose logging. + """ super().__init__() if verbose: LOGGER.info("Adding AutoShape... ") @@ -669,7 +771,9 @@ def __init__(self, model, verbose=True): m.export = True # do not output loss values def _apply(self, fn): - # Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers + """Applies given function `fn` to model tensors excluding parameters or registered buffers, adjusting strides + and grids. + """ self = super()._apply(fn) if self.pt: m = self.model.model.model[-1] if self.dmb else self.model.model[-1] # Detect() @@ -681,7 +785,8 @@ def _apply(self, fn): @smart_inference_mode() def forward(self, ims, size=640, augment=False, profile=False): - # Inference from various sources. For size(height=640, width=1280), RGB images example inputs are: + """Performs inference on various input sources with optional augmentation and profiling; see + `https://ultralytics.com`.""" # file: ims = 'data/images/zidane.jpg' # str or PosixPath # URI: = 'https://ultralytics.com/images/zidane.jpg' # OpenCV: = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(640,1280,3) @@ -749,6 +854,9 @@ def forward(self, ims, size=640, augment=False, profile=False): class Detections: # YOLOv3 detections class for inference results def __init__(self, ims, pred, files, times=(0, 0, 0), names=None, shape=None): + """Initializes YOLOv3 detections with image data, predictions, filenames, profiling times, class names, and + shapes. + """ super().__init__() d = pred[0].device # device gn = [torch.tensor([*(im.shape[i] for i in [1, 0, 1, 0]), 1, 1], device=d) for im in ims] # normalizations @@ -766,6 +874,7 @@ def __init__(self, ims, pred, files, times=(0, 0, 0), names=None, shape=None): self.s = tuple(shape) # inference BCHW shape def _run(self, pprint=False, show=False, save=False, crop=False, render=False, labels=True, save_dir=Path("")): + """Executes inference on images, annotates detections, and can optionally show, save, or crop output images.""" s, crops = "", [] for i, (im, pred) in enumerate(zip(self.ims, self.pred)): s += f"\nimage {i + 1}/{len(self.pred)}: {im.shape[0]}x{im.shape[1]} " # string @@ -820,22 +929,42 @@ def _run(self, pprint=False, show=False, save=False, crop=False, render=False, l @TryExcept("Showing images is not supported in this environment") def show(self, labels=True): + """ + Displays image results with optional labels. + + Usage: `show(labels=True)` + """ self._run(show=True, labels=labels) # show results def save(self, labels=True, save_dir="runs/detect/exp", exist_ok=False): + """ + Saves image results with optional labels to a specified directory. + + Usage: `save(labels=True, save_dir='runs/detect/exp', exist_ok=False)` + """ save_dir = increment_path(save_dir, exist_ok, mkdir=True) # increment save_dir self._run(save=True, labels=labels, save_dir=save_dir) # save results def crop(self, save=True, save_dir="runs/detect/exp", exist_ok=False): + """ + Crops detection results; can save to `save_dir`. + + Usage: `crop(save=True, save_dir='runs/detect/exp')`. + """ save_dir = increment_path(save_dir, exist_ok, mkdir=True) if save else None return self._run(crop=True, save=save, save_dir=save_dir) # crop results def render(self, labels=True): + """ + Renders detection results, optionally displaying labels. + + Usage: `render(labels=True)`. + """ self._run(render=True, labels=labels) # render results return self.ims def pandas(self): - # return detections as pandas DataFrames, i.e. print(results.pandas().xyxy[0]) + """Returns a copy of the detection results as pandas DataFrames for various bounding box formats.""" new = copy(self) # return copy ca = "xmin", "ymin", "xmax", "ymax", "confidence", "class", "name" # xyxy columns cb = "xcenter", "ycenter", "width", "height", "confidence", "class", "name" # xywh columns @@ -845,7 +974,7 @@ def pandas(self): return new def tolist(self): - # return a list of Detections objects, i.e. 'for result in results.tolist():' + """Converts Detections object to a list of individual Detection objects for iteration.""" r = range(self.n) # iterable return [ Detections( @@ -860,21 +989,26 @@ def tolist(self): ] def print(self): + """Logs the string representation of the current object state to the LOGGER.""" LOGGER.info(self.__str__()) def __len__(self): # override len(results) + """Returns the number of results stored in the instance.""" return self.n def __str__(self): # override print(results) + """Returns a string representation of the current object state, printing the results.""" return self._run(pprint=True) # print results def __repr__(self): + """Returns a string representation for debugging, including class info and current object state.""" return f"YOLOv3 {self.__class__} instance\n" + self.__str__() class Proto(nn.Module): # YOLOv3 mask Proto module for segmentation models def __init__(self, c1, c_=256, c2=32): # ch_in, number of protos, number of masks + """Initializes the Proto module for YOLOv3 segmentation, setting up convolutional layers and upsampling.""" super().__init__() self.cv1 = Conv(c1, c_, k=3) self.upsample = nn.Upsample(scale_factor=2, mode="nearest") @@ -882,6 +1016,7 @@ def __init__(self, c1, c_=256, c2=32): # ch_in, number of protos, number of mas self.cv3 = Conv(c_, c2) def forward(self, x): + """Performs forward pass, upsampling and applying convolutions for YOLOv3 segmentation.""" return self.cv3(self.cv2(self.upsample(self.cv1(x)))) @@ -898,6 +1033,9 @@ def __init__( self.linear = nn.Linear(c_, c2) # to x(b,c2) def forward(self, x): + """Processes input tensor `x` through convolutions and pooling, optionally concatenating lists of tensors, and + returns linear output. + """ if isinstance(x, list): x = torch.cat(x, 1) return self.linear(self.drop(self.pool(self.conv(x)).flatten(1))) diff --git a/models/experimental.py b/models/experimental.py index bba3c2be89..5a3af681dc 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -13,6 +13,11 @@ class Sum(nn.Module): # Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 def __init__(self, n, weight=False): # n: number of inputs + """ + Initializes a module to compute weighted/unweighted sum of n inputs, with optional learning weights. + + https://arxiv.org/abs/1911.09070 + """ super().__init__() self.weight = weight # apply weights boolean self.iter = range(n - 1) # iter object @@ -20,6 +25,11 @@ def __init__(self, n, weight=False): # n: number of inputs self.w = nn.Parameter(-torch.arange(1.0, n) / 2, requires_grad=True) # layer weights def forward(self, x): + """ + Performs forward pass, blending `x` elements with optional learnable weights. + + See https://arxiv.org/abs/1911.09070 for more. + """ y = x[0] # no weight if self.weight: w = torch.sigmoid(self.w) * 2 @@ -34,6 +44,8 @@ def forward(self, x): class MixConv2d(nn.Module): # Mixed Depth-wise Conv https://arxiv.org/abs/1907.09595 def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): # ch_in, ch_out, kernel, stride, ch_strategy + """Initializes MixConv2d with mixed depth-wise convolution layers; details at + https://arxiv.org/abs/1907.09595.""" super().__init__() n = len(k) # number of convolutions if equal_ch: # equal c_ per group @@ -54,15 +66,20 @@ def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): # ch_in, ch_out, kern self.act = nn.SiLU() def forward(self, x): + """Applies a series of convolutions, batch normalization, and SiLU activation to input tensor `x`.""" return self.act(self.bn(torch.cat([m(x) for m in self.m], 1))) class Ensemble(nn.ModuleList): # Ensemble of models def __init__(self): + """Initializes an ensemble of models to combine their outputs.""" super().__init__() def forward(self, x, augment=False, profile=False, visualize=False): + """Applies ensemble of models on input `x`, with options for augmentation, profiling, and visualization, + returning inference outputs. + """ y = [module(x, augment, profile, visualize)[0] for module in self] # y = torch.stack(y).max(0)[0] # max ensemble # y = torch.stack(y).mean(0) # mean ensemble @@ -71,7 +88,7 @@ def forward(self, x, augment=False, profile=False, visualize=False): def attempt_load(weights, device=None, inplace=True, fuse=True): - # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a + """Loads an ensemble or single model weights, supports device placement and model fusion.""" from models.yolo import Detect, Model model = Ensemble() diff --git a/models/tf.py b/models/tf.py index e59b00055a..e988ff0bb5 100644 --- a/models/tf.py +++ b/models/tf.py @@ -51,6 +51,7 @@ class TFBN(keras.layers.Layer): # TensorFlow BatchNormalization wrapper def __init__(self, w=None): + """Initializes TFBN with weights, wrapping TensorFlow's BatchNormalization layer with specific initializers.""" super().__init__() self.bn = keras.layers.BatchNormalization( beta_initializer=keras.initializers.Constant(w.bias.numpy()), @@ -61,12 +62,14 @@ def __init__(self, w=None): ) def call(self, inputs): + """Applies batch normalization on inputs using initialized parameters.""" return self.bn(inputs) class TFPad(keras.layers.Layer): # Pad inputs in spatial dimensions 1 and 2 def __init__(self, pad): + """Initializes a padding layer for spatial dimensions 1 and 2, with `pad` as int or (int, int) tuple/list.""" super().__init__() if isinstance(pad, int): self.pad = tf.constant([[0, 0], [pad, pad], [pad, pad], [0, 0]]) @@ -74,13 +77,18 @@ def __init__(self, pad): self.pad = tf.constant([[0, 0], [pad[0], pad[0]], [pad[1], pad[1]], [0, 0]]) def call(self, inputs): + """Applies constant padding to inputs with `pad` specifying padding width; `pad` can be an int or (int, int) + tuple/list. + """ return tf.pad(inputs, self.pad, mode="constant", constant_values=0) class TFConv(keras.layers.Layer): # Standard convolution def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None): - # ch_in, ch_out, weights, kernel, stride, padding, groups + """Initializes a convolutional layer with customizable filters, kernel size, stride, padding, groups, and + activation. + """ super().__init__() assert g == 1, "TF v2.2 Conv2D does not support 'groups' argument" # TensorFlow convolution padding is inconsistent with PyTorch (e.g. k=3 s=2 'SAME' padding) @@ -99,13 +107,14 @@ def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None): self.act = activations(w.act) if act else tf.identity def call(self, inputs): + """Executes the convolution, batch normalization, and activation on the input data.""" return self.act(self.bn(self.conv(inputs))) class TFDWConv(keras.layers.Layer): # Depthwise convolution def __init__(self, c1, c2, k=1, s=1, p=None, act=True, w=None): - # ch_in, ch_out, weights, kernel, stride, padding, groups + """Initializes a depthwise convolutional layer with optional batch normalization and activation.""" super().__init__() assert c2 % c1 == 0, f"TFDWConv() output={c2} must be a multiple of input={c1} channels" conv = keras.layers.DepthwiseConv2D( @@ -122,13 +131,14 @@ def __init__(self, c1, c2, k=1, s=1, p=None, act=True, w=None): self.act = activations(w.act) if act else tf.identity def call(self, inputs): + """Applies convolution, batch normalization, and activation to the input tensor.""" return self.act(self.bn(self.conv(inputs))) class TFDWConvTranspose2d(keras.layers.Layer): # Depthwise ConvTranspose2d def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0, w=None): - # ch_in, ch_out, weights, kernel, stride, padding, groups + """Initializes TFDWConvTranspose2d with ch_in=c1=ch_out, k=4, p1=1; sets up depthwise Conv2DTranspose layers.""" super().__init__() assert c1 == c2, f"TFDWConv() output={c2} must be equal to input={c1} channels" assert k == 4 and p1 == 1, "TFDWConv() only valid for k=4 and p1=1" @@ -149,18 +159,25 @@ def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0, w=None): ] def call(self, inputs): + """Performs a forward pass by applying parallel convolutions to split input tensors and concatenates the + results. + """ return tf.concat([m(x) for m, x in zip(self.conv, tf.split(inputs, self.c1, 3))], 3)[:, 1:-1, 1:-1] class TFFocus(keras.layers.Layer): # Focus wh information into c-space def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None): - # ch_in, ch_out, kernel, stride, padding, groups + """Initializes TFFocus layer for efficient information focusing into channel-space with customizable convolution + parameters. + """ super().__init__() self.conv = TFConv(c1 * 4, c2, k, s, p, g, act, w.conv) def call(self, inputs): # x(b,w,h,c) -> y(b,w/2,h/2,4c) - # inputs = inputs / 255 # normalize 0-255 to 0-1 + """Executes TFFocus layer operation, reducing spatial dimensions by 2 and quadrupling channels, input shape + (b,w,h,c). + """ inputs = [inputs[:, ::2, ::2, :], inputs[:, 1::2, ::2, :], inputs[:, ::2, 1::2, :], inputs[:, 1::2, 1::2, :]] return self.conv(tf.concat(inputs, 3)) @@ -168,6 +185,7 @@ def call(self, inputs): # x(b,w,h,c) -> y(b,w/2,h/2,4c) class TFBottleneck(keras.layers.Layer): # Standard bottleneck def __init__(self, c1, c2, shortcut=True, g=1, e=0.5, w=None): # ch_in, ch_out, shortcut, groups, expansion + """Initializes a standard bottleneck layer with optional shortcut, channel expansion, and group convolutions.""" super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) @@ -175,12 +193,18 @@ def __init__(self, c1, c2, shortcut=True, g=1, e=0.5, w=None): # ch_in, ch_out, self.add = shortcut and c1 == c2 def call(self, inputs): + """Executes a bottleneck layer with optional shortcut; returns either input + convoluted input or just + convoluted input. + """ return inputs + self.cv2(self.cv1(inputs)) if self.add else self.cv2(self.cv1(inputs)) class TFCrossConv(keras.layers.Layer): # Cross Convolution def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False, w=None): + """Initializes cross convolutional layer with parameters for channel sizes, kernel size, stride, groups, + expansion factor, shortcut option, and weights. + """ super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = TFConv(c1, c_, (1, k), (1, s), w=w.cv1) @@ -188,12 +212,16 @@ def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False, w=None): self.add = shortcut and c1 == c2 def call(self, inputs): + """Executes the function, optionally adding input to output if shapes match; inputs: tensor [B, C, H, W].""" return inputs + self.cv2(self.cv1(inputs)) if self.add else self.cv2(self.cv1(inputs)) class TFConv2d(keras.layers.Layer): # Substitution for PyTorch nn.Conv2D def __init__(self, c1, c2, k, s=1, g=1, bias=True, w=None): + """Initializes TFConv2d layer for TensorFlow 2.2+, substituting PyTorch Conv2D; c1, c2: channels, k: kernel + size, s: stride. + """ super().__init__() assert g == 1, "TF v2.2 Conv2D does not support 'groups' argument" self.conv = keras.layers.Conv2D( @@ -207,13 +235,16 @@ def __init__(self, c1, c2, k, s=1, g=1, bias=True, w=None): ) def call(self, inputs): + """Applies convolution to the inputs using initialized weights and biases, returning the convolved output.""" return self.conv(inputs) class TFBottleneckCSP(keras.layers.Layer): # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): - # ch_in, ch_out, number, shortcut, groups, expansion + """Initializes CSP Bottleneck layer with channel configurations and optional shortcut, groups, expansion, and + weights. + """ super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) @@ -225,6 +256,7 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): self.m = keras.Sequential([TFBottleneck(c_, c_, shortcut, g, e=1.0, w=w.m[j]) for j in range(n)]) def call(self, inputs): + """Executes the forward pass by combining features through convolutions, activation, and batch normalization.""" y1 = self.cv3(self.m(self.cv1(inputs))) y2 = self.cv2(inputs) return self.cv4(self.act(self.bn(tf.concat((y1, y2), axis=3)))) @@ -233,7 +265,7 @@ def call(self, inputs): class TFC3(keras.layers.Layer): # CSP Bottleneck with 3 convolutions def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): - # ch_in, ch_out, number, shortcut, groups, expansion + """Initializes a CSP Bottleneck layer with 3 convolutions for channel manipulation and feature integration.""" super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) @@ -242,13 +274,18 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): self.m = keras.Sequential([TFBottleneck(c_, c_, shortcut, g, e=1.0, w=w.m[j]) for j in range(n)]) def call(self, inputs): + """Executes model forwarding, combining features using TF layers and concatenation, returning the resulting + tensor. + """ return self.cv3(tf.concat((self.m(self.cv1(inputs)), self.cv2(inputs)), axis=3)) class TFC3x(keras.layers.Layer): # 3 module with cross-convolutions def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): - # ch_in, ch_out, number, shortcut, groups, expansion + """Initializes a TFC3x layer with cross-convolutions, expanding and concatenating features for given channel + inputs and outputs. + """ super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) @@ -259,12 +296,16 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): ) def call(self, inputs): + """Executes model forwarding, combining features through conv layers and concatenation.""" return self.cv3(tf.concat((self.m(self.cv1(inputs)), self.cv2(inputs)), axis=3)) class TFSPP(keras.layers.Layer): # Spatial pyramid pooling layer used in YOLOv3-SPP def __init__(self, c1, c2, k=(5, 9, 13), w=None): + """Initializes a Spatial Pyramid Pooling layer for YOLOv3-SPP with configurable in/out channels and kernel + sizes. + """ super().__init__() c_ = c1 // 2 # hidden channels self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) @@ -272,6 +313,7 @@ def __init__(self, c1, c2, k=(5, 9, 13), w=None): self.m = [keras.layers.MaxPool2D(pool_size=x, strides=1, padding="SAME") for x in k] def call(self, inputs): + """Applies transformations and concatenates feature maps from multiple kernel-sized max-poolings.""" x = self.cv1(inputs) return self.cv2(tf.concat([x] + [m(x) for m in self.m], 3)) @@ -279,6 +321,9 @@ def call(self, inputs): class TFSPPF(keras.layers.Layer): # Spatial pyramid pooling-Fast layer def __init__(self, c1, c2, k=5, w=None): + """Initializes a Spatial Pyramid Pooling-Fast layer with specified channels, kernel size, and optional + weights. + """ super().__init__() c_ = c1 // 2 # hidden channels self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) @@ -286,6 +331,7 @@ def __init__(self, c1, c2, k=5, w=None): self.m = keras.layers.MaxPool2D(pool_size=k, strides=1, padding="SAME") def call(self, inputs): + """Applies two TFConvs and max pooling with concatenation, returning the processed tensor.""" x = self.cv1(inputs) y1 = self.m(x) y2 = self.m(y1) @@ -295,6 +341,7 @@ def call(self, inputs): class TFDetect(keras.layers.Layer): # TF YOLOv3 Detect layer def __init__(self, nc=80, anchors=(), ch=(), imgsz=(640, 640), w=None): # detection layer + """Initializes a YOLOv3 detection layer with specified classes, anchors, channels, image size, and weights.""" super().__init__() self.stride = tf.convert_to_tensor(w.stride.numpy(), dtype=tf.float32) self.nc = nc # number of classes @@ -312,6 +359,9 @@ def __init__(self, nc=80, anchors=(), ch=(), imgsz=(640, 640), w=None): # detec self.grid[i] = self._make_grid(nx, ny) def call(self, inputs): + """Performs inference on inputs, transforming shape to (batch_size, ny*nx, num_anchors, num_outputs) for each + layer. + """ z = [] # inference output x = [] for i in range(self.nl): @@ -336,7 +386,7 @@ def call(self, inputs): @staticmethod def _make_grid(nx=20, ny=20): - # yv, xv = torch.meshgrid([torch.arange(ny), torch.arange(nx)]) + """Generates a grid of shape [1, 1, ny * nx, 2] with ranges [0, nx) and [0, ny) for object detection.""" # return torch.stack((xv, yv), 2).view((1, 1, ny, nx, 2)).float() xv, yv = tf.meshgrid(tf.range(nx), tf.range(ny)) return tf.cast(tf.reshape(tf.stack([xv, yv], 2), [1, 1, ny * nx, 2]), dtype=tf.float32) @@ -345,6 +395,7 @@ def _make_grid(nx=20, ny=20): class TFSegment(TFDetect): # YOLOv3 Segment head for segmentation models def __init__(self, nc=80, anchors=(), nm=32, npr=256, ch=(), imgsz=(640, 640), w=None): + """Initializes a YOLOv3 Segment head with customizable parameters for segmentation models.""" super().__init__(nc, anchors, ch, imgsz, w) self.nm = nm # number of masks self.npr = npr # number of protos @@ -354,6 +405,7 @@ def __init__(self, nc=80, anchors=(), nm=32, npr=256, ch=(), imgsz=(640, 640), w self.detect = TFDetect.call def call(self, x): + """Executes model's forward pass, returning predictions and optionally full-size protos if training.""" p = self.proto(x[0]) # p = TFUpsample(None, scale_factor=4, mode='nearest')(self.proto(x[0])) # (optional) full-size protos p = tf.transpose(p, [0, 3, 1, 2]) # from shape(1,160,160,32) to shape(1,32,160,160) @@ -363,6 +415,7 @@ def call(self, x): class TFProto(keras.layers.Layer): def __init__(self, c1, c_=256, c2=32, w=None): + """Initializes a TFProto layer with convolution and upsample operations for feature processing.""" super().__init__() self.cv1 = TFConv(c1, c_, k=3, w=w.cv1) self.upsample = TFUpsample(None, scale_factor=2, mode="nearest") @@ -370,12 +423,16 @@ def __init__(self, c1, c_=256, c2=32, w=None): self.cv3 = TFConv(c_, c2, w=w.cv3) def call(self, inputs): + """Performs convolution and upsample operations on input features, returning processed features.""" return self.cv3(self.cv2(self.upsample(self.cv1(inputs)))) class TFUpsample(keras.layers.Layer): # TF version of torch.nn.Upsample() def __init__(self, size, scale_factor, mode, w=None): # warning: all arguments needed including 'w' + """Initializes an upsample layer with specific size, doubling scale factor (>0, even), interpolation mode, and + optional weights. + """ super().__init__() assert scale_factor % 2 == 0, "scale_factor must be multiple of 2" self.upsample = lambda x: tf.image.resize(x, (x.shape[1] * scale_factor, x.shape[2] * scale_factor), mode) @@ -385,21 +442,27 @@ def __init__(self, size, scale_factor, mode, w=None): # warning: all arguments # size=(x.shape[1] * 2, x.shape[2] * 2)) def call(self, inputs): + """Applies upsample lambda function to the input tensor, returning the upsampled tensor.""" return self.upsample(inputs) class TFConcat(keras.layers.Layer): # TF version of torch.concat() def __init__(self, dimension=1, w=None): + """Initializes a TensorFlow layer to concatenate tensors along the NHWC dimension, requiring dimension=1.""" super().__init__() assert dimension == 1, "convert only NCHW to NHWC concat" self.d = 3 def call(self, inputs): + """Concatenates tensors along NHWC dimension (3rd axis); `inputs` is a list of tensors.""" return tf.concat(inputs, self.d) def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3) + """Parses model configuration and constructs Keras model with layer connectivity, returning the model and save + list. + """ LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}") anchors, nc, gd, gw = d["anchors"], d["nc"], d["depth_multiple"], d["width_multiple"] na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors @@ -473,6 +536,9 @@ def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3) class TFModel: # TF YOLOv3 model def __init__(self, cfg="yolov5s.yaml", ch=3, nc=None, model=None, imgsz=(640, 640)): # model, channels, classes + """Initializes TF YOLOv3 model with config, channels, classes, optional pre-loaded model, and input image + size. + """ super().__init__() if isinstance(cfg, dict): self.yaml = cfg # model dict @@ -531,7 +597,9 @@ def predict( @staticmethod def _xywh2xyxy(xywh): - # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + """Converts bounding boxes from [x, y, w, h] format to [x1, y1, x2, y2], where xy1=top-left, xy2=bottom- + right. + """ x, y, w, h = tf.split(xywh, num_or_size_splits=4, axis=-1) return tf.concat([x - w / 2, y - h / 2, x + w / 2, y + h / 2], axis=-1) @@ -539,7 +607,7 @@ def _xywh2xyxy(xywh): class AgnosticNMS(keras.layers.Layer): # TF Agnostic NMS def call(self, input, topk_all, iou_thres, conf_thres): - # wrap map_fn to avoid TypeSpec related error https://stackoverflow.com/a/65809989/3036450 + """Applies non-maximum suppression (NMS) to filter detections based on IoU, confidence thresholds, and top-K.""" return tf.map_fn( lambda x: self._nms(x, topk_all, iou_thres, conf_thres), input, @@ -549,6 +617,9 @@ def call(self, input, topk_all, iou_thres, conf_thres): @staticmethod def _nms(x, topk_all=100, iou_thres=0.45, conf_thres=0.25): # agnostic NMS + """Performs non-max suppression on bounding boxes with class, IoU, and confidence thresholds; returns processed + boxes, scores, classes, and count. + """ boxes, classes, scores = x class_inds = tf.cast(tf.argmax(classes, axis=-1), tf.float32) scores_inp = tf.reduce_max(scores, -1) @@ -581,7 +652,7 @@ def _nms(x, topk_all=100, iou_thres=0.45, conf_thres=0.25): # agnostic NMS def activations(act=nn.SiLU): - # Returns TF activation from input PyTorch activation + """Converts PyTorch activation functions (LeakyReLU, Hardswish, SiLU) to their TensorFlow counterparts.""" if isinstance(act, nn.LeakyReLU): return lambda x: keras.activations.relu(x, alpha=0.1) elif isinstance(act, nn.Hardswish): @@ -593,7 +664,9 @@ def activations(act=nn.SiLU): def representative_dataset_gen(dataset, ncalib=100): - # Representative dataset generator for use with converter.representative_dataset, returns a generator of np arrays + """Generates a representative dataset for TFLite conversion; yields normalized np arrays from input dataset up to + `ncalib` samples. + """ for n, (path, img, im0s, vid_cap, string) in enumerate(dataset): im = np.transpose(img, [1, 2, 0]) im = np.expand_dims(im, axis=0).astype(np.float32) @@ -629,6 +702,9 @@ def run( def parse_opt(): + """Parses command line arguments for model configuration including weights path, image size, batch size, and dynamic + batching. + """ parser = argparse.ArgumentParser() parser.add_argument("--weights", type=str, default=ROOT / "yolov3-tiny.pt", help="weights path") parser.add_argument("--imgsz", "--img", "--img-size", nargs="+", type=int, default=[640], help="inference size h,w") @@ -641,6 +717,7 @@ def parse_opt(): def main(opt): + """Executes the model run function with parsed CLI arguments on batch size and dynamic batching option.""" run(**vars(opt)) diff --git a/models/yolo.py b/models/yolo.py index 9c9962e682..8602c1697b 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -7,7 +7,6 @@ """ import argparse -import contextlib import os import platform import sys @@ -49,6 +48,7 @@ class Detect(nn.Module): export = False # export mode def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer + """Initializes YOLOv3 detection layer with class count, anchors, channels, and operation modes.""" super().__init__() self.nc = nc # number of classes self.no = nc + 5 # number of outputs per anchor @@ -61,6 +61,11 @@ def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer self.inplace = inplace # use inplace ops (e.g. slice assignment) def forward(self, x): + """ + Processes input through convolutional layers, reshaping output for detection. + + Expects x as list of tensors with shape(bs, C, H, W). + """ z = [] # inference output for i in range(self.nl): x[i] = self.m[i](x[i]) # conv @@ -86,6 +91,9 @@ def forward(self, x): return x if self.training else (torch.cat(z, 1),) if self.export else (torch.cat(z, 1), x) def _make_grid(self, nx=20, ny=20, i=0, torch_1_10=check_version(torch.__version__, "1.10.0")): + """Generates a grid and corresponding anchor grid with shape `(1, num_anchors, ny, nx, 2)` for indexing + anchors. + """ d = self.anchors[i].device t = self.anchors[i].dtype shape = 1, self.na, ny, nx, 2 # grid shape @@ -99,6 +107,9 @@ def _make_grid(self, nx=20, ny=20, i=0, torch_1_10=check_version(torch.__version class Segment(Detect): # YOLOv3 Segment head for segmentation models def __init__(self, nc=80, anchors=(), nm=32, npr=256, ch=(), inplace=True): + """Initializes the YOLOv3 segment head with customizable class count, anchors, masks, protos, channels, and + inplace option. + """ super().__init__(nc, anchors, ch, inplace) self.nm = nm # number of masks self.npr = npr # number of protos @@ -108,6 +119,9 @@ def __init__(self, nc=80, anchors=(), nm=32, npr=256, ch=(), inplace=True): self.detect = Detect.forward def forward(self, x): + """Executes forward pass, returning predictions and protos, with different outputs based on training and export + states. + """ p = self.proto(x[0]) x = self.detect(self, x) return (x, p) if self.training else (x[0], p) if self.export else (x[0], p, x[1]) @@ -116,9 +130,13 @@ def forward(self, x): class BaseModel(nn.Module): # YOLOv3 base model def forward(self, x, profile=False, visualize=False): + """Performs a single-scale inference or training step on input `x`, with options for profiling and + visualization. + """ return self._forward_once(x, profile, visualize) # single-scale inference, train def _forward_once(self, x, profile=False, visualize=False): + """Executes a single inference or training step, offering profiling and visualization options for input `x`.""" y, dt = [], [] # outputs for m in self.model: if m.f != -1: # if not from previous layer @@ -132,6 +150,7 @@ def _forward_once(self, x, profile=False, visualize=False): return x def _profile_one_layer(self, m, x, dt): + """Profiles a single layer of the model by measuring its execution time and computational cost.""" c = m == self.model[-1] # is final layer, copy input as inplace fix o = thop.profile(m, inputs=(x.copy() if c else x,), verbose=False)[0] / 1e9 * 2 if thop else 0 # FLOPs t = time_sync() @@ -145,6 +164,7 @@ def _profile_one_layer(self, m, x, dt): LOGGER.info(f"{sum(dt):10.2f} {'-':>10s} {'-':>10s} Total") def fuse(self): # fuse model Conv2d() + BatchNorm2d() layers + """Fuses Conv2d() and BatchNorm2d() layers in the model to optimize inference speed.""" LOGGER.info("Fusing layers... ") for m in self.model.modules(): if isinstance(m, (Conv, DWConv)) and hasattr(m, "bn"): @@ -155,10 +175,11 @@ def fuse(self): # fuse model Conv2d() + BatchNorm2d() layers return self def info(self, verbose=False, img_size=640): # print model information + """Prints model information; `verbose` for detailed, `img_size` for input image size (default 640).""" model_info(self, verbose, img_size) def _apply(self, fn): - # Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers + """Applies `to()`, `cpu()`, `cuda()`, `half()` to model tensors, excluding parameters or registered buffers.""" self = super()._apply(fn) m = self.model[-1] # Detect() if isinstance(m, (Detect, Segment)): @@ -172,6 +193,7 @@ def _apply(self, fn): class DetectionModel(BaseModel): # YOLOv3 detection model def __init__(self, cfg="yolov5s.yaml", ch=3, nc=None, anchors=None): # model, input channels, number of classes + """Initializes YOLOv3 detection model with configurable YAML, input channels, classes, and anchors.""" super().__init__() if isinstance(cfg, dict): self.yaml = cfg # model dict @@ -212,11 +234,13 @@ def __init__(self, cfg="yolov5s.yaml", ch=3, nc=None, anchors=None): # model, i LOGGER.info("") def forward(self, x, augment=False, profile=False, visualize=False): + """Processes input through the model, with options for augmentation, profiling, and visualization.""" if augment: return self._forward_augment(x) # augmented inference, None return self._forward_once(x, profile, visualize) # single-scale inference, train def _forward_augment(self, x): + """Performs augmented inference by scaling and flipping input images, returning concatenated predictions.""" img_size = x.shape[-2:] # height, width s = [1, 0.83, 0.67] # scales f = [None, 3, None] # flips (2-ud, 3-lr) @@ -231,7 +255,7 @@ def _forward_augment(self, x): return torch.cat(y, 1), None # augmented inference, train def _descale_pred(self, p, flips, scale, img_size): - # de-scale predictions following augmented inference (inverse operation) + """Rescales predictions after augmentation by adjusting scales and flips based on image dimensions.""" if self.inplace: p[..., :4] /= scale # de-scale if flips == 2: @@ -248,7 +272,7 @@ def _descale_pred(self, p, flips, scale, img_size): return p def _clip_augmented(self, y): - # Clip YOLOv3 augmented inference tails + """Clips augmented inference tails from YOLOv3 predictions, affecting the first and last detection layers.""" nl = self.model[-1].nl # number of detection layers (P3-P5) g = sum(4**x for x in range(nl)) # grid points e = 1 # exclude layer count @@ -259,7 +283,7 @@ def _clip_augmented(self, y): return y def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is class frequency - # https://arxiv.org/abs/1708.02002 section 3.3 + """Initializes biases for objectness and classes in Detect() module; optionally uses class frequency `cf`.""" # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1. m = self.model[-1] # Detect() module for mi, s in zip(m.m, m.stride): # from @@ -277,17 +301,19 @@ def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is class SegmentationModel(DetectionModel): # YOLOv3 segmentation model def __init__(self, cfg="yolov5s-seg.yaml", ch=3, nc=None, anchors=None): + """Initializes a SegmentationModel with optional configuration, channel, class count, and anchors parameters.""" super().__init__(cfg, ch, nc, anchors) class ClassificationModel(BaseModel): # YOLOv3 classification model def __init__(self, cfg=None, model=None, nc=1000, cutoff=10): # yaml, model, number of classes, cutoff index + """Initializes a ClassificationModel from a detection model or YAML, with configurable classes and cutoff.""" super().__init__() self._from_detection_model(model, nc, cutoff) if model is not None else self._from_yaml(cfg) def _from_detection_model(self, model, nc=1000, cutoff=10): - # Create a YOLOv3 classification model from a YOLOv3 detection model + """Initializes a classification model from a YOLOv3 detection model, configuring classes and cutoff.""" if isinstance(model, DetectMultiBackend): model = model.model # unwrap DetectMultiBackend model.model = model.model[:cutoff] # backbone @@ -302,12 +328,12 @@ def _from_detection_model(self, model, nc=1000, cutoff=10): self.nc = nc def _from_yaml(self, cfg): - # Create a YOLOv3 classification model from a *.yaml file + """Creates a YOLOv3 classification model from a YAML file configuration.""" self.model = None def parse_model(d, ch): # model_dict, input_channels(3) - # Parse a YOLOv3 model.yaml dictionary + """Parses a YOLOv3 model configuration from a dictionary and constructs the model.""" LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}") anchors, nc, gd, gw, act = d["anchors"], d["nc"], d["depth_multiple"], d["width_multiple"], d.get("activation") if act: diff --git a/segment/predict.py b/segment/predict.py index cbd79be552..de20b9dff1 100644 --- a/segment/predict.py +++ b/segment/predict.py @@ -257,6 +257,7 @@ def run( def parse_opt(): + """Parses command-line options for YOLOv5 including model paths, source, inference size, and saving options.""" parser = argparse.ArgumentParser() parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov5s-seg.pt", help="model path(s)") parser.add_argument("--source", type=str, default=ROOT / "data/images", help="file/dir/URL/glob/screen/0(webcam)") @@ -293,6 +294,7 @@ def parse_opt(): def main(opt): + """Executes model inference based on parsed options, checking requirements and excluding specified packages.""" check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) run(**vars(opt)) diff --git a/segment/train.py b/segment/train.py index 3535d5bcb7..97c5b2f371 100644 --- a/segment/train.py +++ b/segment/train.py @@ -96,6 +96,9 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary + """Trains a segmentation model using the provided hyperparameters, options, and callbacks, handling multi-GPU + setups, data loading, logging, and validation. + """ ( save_dir, epochs, @@ -532,6 +535,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio def parse_opt(known=False): + """Parses command line arguments for training configurations, supporting optional known args parsing.""" parser = argparse.ArgumentParser() parser.add_argument("--weights", type=str, default=ROOT / "yolov5s-seg.pt", help="initial weights path") parser.add_argument("--cfg", type=str, default="", help="model.yaml path") @@ -576,7 +580,9 @@ def parse_opt(known=False): def main(opt, callbacks=Callbacks()): - # Checks + """Initializes training or evolution of models with given options and callbacks, handling device setup and data + preparation. + """ if RANK in {-1, 0}: print_args(vars(opt)) check_git_status() @@ -733,7 +739,9 @@ def main(opt, callbacks=Callbacks()): def run(**kwargs): - # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolov5m.pt') + """Executes model training with specified configurations; see example: `train.run(data='coco128.yaml', imgsz=320, + weights='yolov5m.pt')`. + """ opt = parse_opt(True) for k, v in kwargs.items(): setattr(opt, k, v) diff --git a/segment/val.py b/segment/val.py index 28f7e5125e..6179ab87f7 100644 --- a/segment/val.py +++ b/segment/val.py @@ -71,7 +71,7 @@ def save_one_txt(predn, save_conf, shape, file): - # Save one txt result + """Saves detection results in normalized xywh format (with optional confidence) to a txt file.""" gn = torch.tensor(shape)[[1, 0, 1, 0]] # normalization gain whwh for *xyxy, conf, cls in predn.tolist(): xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh @@ -81,7 +81,7 @@ def save_one_txt(predn, save_conf, shape, file): def save_one_json(predn, jdict, path, class_map, pred_masks): - # Save one JSON result {"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236} + """Saves detection results in COCO JSON format, including bbox, category_id and segmentation if available.""" from pycocotools.mask import encode def single_encode(x): @@ -437,6 +437,7 @@ def run( def parse_opt(): + """Parses and validates command-line arguments for configuring model training or inference.""" parser = argparse.ArgumentParser() parser.add_argument("--data", type=str, default=ROOT / "data/coco128-seg.yaml", help="dataset.yaml path") parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov5s-seg.pt", help="model path(s)") @@ -469,6 +470,9 @@ def parse_opt(): def main(opt): + """Executes the primary function based on task, including training, validation, testing, speed, and study + benchmarks. + """ check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) if opt.task in ("train", "val", "test"): # run normally diff --git a/train.py b/train.py index 146c5cc8a7..ac5235599a 100644 --- a/train.py +++ b/train.py @@ -101,6 +101,9 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary + """Trains a model with given hyperparameters, options, device, and callbacks, saving results and weights as + specified. + """ save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = ( Path(opt.save_dir), opt.epochs, @@ -492,6 +495,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio def parse_opt(known=False): + """Parses command line arguments for training configurations, with facilities for known arg parsing.""" parser = argparse.ArgumentParser() parser.add_argument("--weights", type=str, default=ROOT / "yolov3-tiny.pt", help="initial weights path") parser.add_argument("--cfg", type=str, default="", help="model.yaml path") @@ -538,7 +542,7 @@ def parse_opt(known=False): def main(opt, callbacks=Callbacks()): - # Checks + """Main training/evolution script handling model checks, DDP setup, training, and hyperparameter evolution.""" if RANK in {-1, 0}: print_args(vars(opt)) check_git_status() @@ -704,7 +708,9 @@ def main(opt, callbacks=Callbacks()): def run(**kwargs): - # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolov5m.pt') + """Executes model training with specified configurations; see example: import train; train.run(data='coco128.yaml', + imgsz=320, weights='yolov5m.pt'). + """ opt = parse_opt(True) for k, v in kwargs.items(): setattr(opt, k, v) diff --git a/utils/__init__.py b/utils/__init__.py index 8966abbc30..3a3524b05a 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -7,26 +7,40 @@ def emojis(str=""): - # Return platform-dependent emoji-safe version of string + """Returns platform-dependent emoji-safe version of str; ignores emojis on Windows, else returns original str.""" return str.encode().decode("ascii", "ignore") if platform.system() == "Windows" else str class TryExcept(contextlib.ContextDecorator): # YOLOv3 TryExcept class. Usage: @TryExcept() decorator or 'with TryExcept():' context manager def __init__(self, msg=""): + """Initializes TryExcept with optional custom message, used as decorator or context manager for exception + handling. + """ self.msg = msg def __enter__(self): + """Begin exception-handling block, optionally customizing exception message when used with TryExcept context + manager. + """ pass def __exit__(self, exc_type, value, traceback): + """Ends exception-handling block, optionally prints custom message with exception, suppressing exceptions within + context. + """ if value: print(emojis(f"{self.msg}{': ' if self.msg else ''}{value}")) return True def threaded(func): - # Multi-threads a target function and returns thread. Usage: @threaded decorator + """ + Decorates a function to run in a separate thread, returning the thread object. + + Usage: @threaded. + """ + def wrapper(*args, **kwargs): thread = threading.Thread(target=func, args=args, kwargs=kwargs, daemon=True) thread.start() @@ -36,7 +50,7 @@ def wrapper(*args, **kwargs): def join_threads(verbose=False): - # Join all daemon threads, i.e. atexit.register(lambda: join_threads()) + """Joins all daemon threads, excluding the main thread, with an optional verbose flag for logging.""" main_thread = threading.current_thread() for t in threading.enumerate(): if t is not main_thread: @@ -46,7 +60,7 @@ def join_threads(verbose=False): def notebook_init(verbose=True): - # Check system software and hardware + """Initializes notebook environment by checking hardware, software requirements, and cleaning up if in Colab.""" print("Checking setup...") import os diff --git a/utils/activations.py b/utils/activations.py index cb193862ff..5986a0d08d 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -10,6 +10,8 @@ class SiLU(nn.Module): # SiLU activation https://arxiv.org/pdf/1606.08415.pdf @staticmethod def forward(x): + """Applies the SiLU activation function, as detailed in https://arxiv.org/pdf/1606.08415.pdf, on input tensor + `x`.""" return x * torch.sigmoid(x) @@ -17,7 +19,9 @@ class Hardswish(nn.Module): # Hard-SiLU activation @staticmethod def forward(x): - # return x * F.hardsigmoid(x) # for TorchScript and CoreML + """Applies Hardswish activation, suitable for TorchScript, CoreML, ONNX, modifying input `x` as per Hard-SiLU + definition. + """ return x * F.hardtanh(x + 3, 0.0, 6.0) / 6.0 # for TorchScript, CoreML and ONNX @@ -25,6 +29,11 @@ class Mish(nn.Module): # Mish activation https://github.com/digantamisra98/Mish @staticmethod def forward(x): + """ + Applies the Mish activation function, enhancing model performance and convergence. + + Reference: https://github.com/digantamisra98/Mish + """ return x * F.softplus(x).tanh() @@ -33,28 +42,38 @@ class MemoryEfficientMish(nn.Module): class F(torch.autograd.Function): @staticmethod def forward(ctx, x): + """Applies the Mish activation function in a memory-efficient manner, useful for enhancing model + performance. + """ ctx.save_for_backward(x) return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x))) @staticmethod def backward(ctx, grad_output): + """Computes gradient of the Mish activation function for backpropagation, returning the derivative with + respect to the input. + """ x = ctx.saved_tensors[0] sx = torch.sigmoid(x) fx = F.softplus(x).tanh() return grad_output * (fx + x * sx * (1 - fx * fx)) def forward(self, x): + """Applies Mish activation function, useful in neural networks for nonlinear transformation of inputs.""" return self.F.apply(x) class FReLU(nn.Module): # FReLU activation https://arxiv.org/abs/2007.11824 def __init__(self, c1, k=3): # ch_in, kernel + """Initializes FReLU with specified channel size and kernel, implementing activation from + https://arxiv.org/abs/2007.11824.""" super().__init__() self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1, bias=False) self.bn = nn.BatchNorm2d(c1) def forward(self, x): + """Performs FReLU activation on input, returning the max of input and its 2D convolution.""" return torch.max(x, self.bn(self.conv(x))) @@ -65,12 +84,16 @@ class AconC(nn.Module): """ def __init__(self, c1): + """Initializes ACON activation with learnable parameters p1, p2, and beta as per + https://arxiv.org/pdf/2009.04759.pdf.""" super().__init__() self.p1 = nn.Parameter(torch.randn(1, c1, 1, 1)) self.p2 = nn.Parameter(torch.randn(1, c1, 1, 1)) self.beta = nn.Parameter(torch.ones(1, c1, 1, 1)) def forward(self, x): + """Applies a parametric activation function to tensor x; see https://arxiv.org/pdf/2009.04759.pdf for + details.""" dpx = (self.p1 - self.p2) * x return dpx * torch.sigmoid(self.beta * dpx) + self.p2 * x @@ -82,6 +105,9 @@ class MetaAconC(nn.Module): """ def __init__(self, c1, k=1, s=1, r=16): # ch_in, kernel, stride, r + """Initializes MetaAconC activation with params c1, optional k (kernel=1), s (stride=1), r (16), defining + activation dynamics. + """ super().__init__() c2 = max(r, c1 // r) self.p1 = nn.Parameter(torch.randn(1, c1, 1, 1)) @@ -92,6 +118,7 @@ def __init__(self, c1, k=1, s=1, r=16): # ch_in, kernel, stride, r # self.bn2 = nn.BatchNorm2d(c1) def forward(self, x): + """Applies a forward pass transforming input `x` using parametric operations and returns the modified tensor.""" y = x.mean(dim=2, keepdims=True).mean(dim=3, keepdims=True) # batch-size 1 bug/instabilities https://github.com/ultralytics/yolov5/issues/2891 # beta = torch.sigmoid(self.bn2(self.fc2(self.bn1(self.fc1(y))))) # bug/unstable diff --git a/utils/augmentations.py b/utils/augmentations.py index d91c84272a..5bb36404f1 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -20,6 +20,7 @@ class Albumentations: # YOLOv3 Albumentations class (optional, only used if package is installed) def __init__(self, size=640): + """Initializes Albumentations class for optional YOLOv3 data augmentation with default size 640.""" self.transform = None prefix = colorstr("albumentations: ") try: @@ -46,6 +47,7 @@ def __init__(self, size=640): LOGGER.info(f"{prefix}{e}") def __call__(self, im, labels, p=1.0): + """Applies transformations to an image and its bounding boxes with a probability `p`.""" if self.transform and random.random() < p: new = self.transform(image=im, bboxes=labels[:, 1:], class_labels=labels[:, 0]) # transformed im, labels = new["image"], np.array([[c, *b] for c, b in zip(new["class_labels"], new["bboxes"])]) @@ -53,19 +55,27 @@ def __call__(self, im, labels, p=1.0): def normalize(x, mean=IMAGENET_MEAN, std=IMAGENET_STD, inplace=False): - # Denormalize RGB images x per ImageNet stats in BCHW format, i.e. = (x - mean) / std + """Normalizes RGB images in BCHW format using ImageNet stats; use `inplace=True` for in-place normalization.""" return TF.normalize(x, mean, std, inplace=inplace) def denormalize(x, mean=IMAGENET_MEAN, std=IMAGENET_STD): - # Denormalize RGB images x per ImageNet stats in BCHW format, i.e. = x * std + mean + """ + Converts normalized images back to original form using ImageNet stats; inputs in BCHW format. + + Example: `denormalize(tensor)`. + """ for i in range(3): x[:, i] = x[:, i] * std[i] + mean[i] return x def augment_hsv(im, hgain=0.5, sgain=0.5, vgain=0.5): - # HSV color-space augmentation + """ + Applies HSV color-space augmentation with optional gains; expects BGR image input. + + Example: `augment_hsv(image)`. + """ if hgain or sgain or vgain: r = np.random.uniform(-1, 1, 3) * [hgain, sgain, vgain] + 1 # random gains hue, sat, val = cv2.split(cv2.cvtColor(im, cv2.COLOR_BGR2HSV)) @@ -81,7 +91,7 @@ def augment_hsv(im, hgain=0.5, sgain=0.5, vgain=0.5): def hist_equalize(im, clahe=True, bgr=False): - # Equalize histogram on BGR image 'im' with im.shape(n,m,3) and range 0-255 + """Equalizes histogram of BGR/RGB image `im` with shape (n,m,3), optionally using CLAHE; returns equalized image.""" yuv = cv2.cvtColor(im, cv2.COLOR_BGR2YUV if bgr else cv2.COLOR_RGB2YUV) if clahe: c = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) @@ -92,7 +102,7 @@ def hist_equalize(im, clahe=True, bgr=False): def replicate(im, labels): - # Replicate labels + """Duplicates half of the smallest bounding boxes in an image to augment dataset; update labels accordingly.""" h, w = im.shape[:2] boxes = labels[:, 1:].astype(int) x1, y1, x2, y2 = boxes.T @@ -109,7 +119,7 @@ def replicate(im, labels): def letterbox(im, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32): - # Resize and pad image while meeting stride-multiple constraints + """Resizes and pads an image to a new shape with optional scaling, filling, and stride-multiple constraints.""" shape = im.shape[:2] # current shape [height, width] if isinstance(new_shape, int): new_shape = (new_shape, new_shape) @@ -232,7 +242,8 @@ def random_perspective( def copy_paste(im, labels, segments, p=0.5): - # Implement Copy-Paste augmentation https://arxiv.org/abs/2012.07177, labels as nx5 np.array(cls, xyxy) + """Applies Copy-Paste augmentation (https://arxiv.org/abs/2012.07177) on image, labels (nx5 np.array(cls, xyxy)), + and segments.""" n = len(segments) if p and n: h, w, c = im.shape # height, width, channels @@ -254,7 +265,7 @@ def copy_paste(im, labels, segments, p=0.5): def cutout(im, labels, p=0.5): - # Applies image cutout augmentation https://arxiv.org/abs/1708.04552 + """Applies cutout augmentation, potentially removing >60% obscured labels; see https://arxiv.org/abs/1708.04552.""" if random.random() < p: h, w = im.shape[:2] scales = [0.5] * 1 + [0.25] * 2 + [0.125] * 4 + [0.0625] * 8 + [0.03125] * 16 # image size fraction @@ -281,7 +292,8 @@ def cutout(im, labels, p=0.5): def mixup(im, labels, im2, labels2): - # Applies MixUp augmentation https://arxiv.org/pdf/1710.09412.pdf + """Applies MixUp augmentation by blending images and labels; see https://arxiv.org/pdf/1710.09412.pdf for + details.""" r = np.random.beta(32.0, 32.0) # mixup ratio, alpha=beta=32.0 im = (im * r + im2 * (1 - r)).astype(np.uint8) labels = np.concatenate((labels, labels2), 0) @@ -289,7 +301,7 @@ def mixup(im, labels, im2, labels2): def box_candidates(box1, box2, wh_thr=2, ar_thr=100, area_thr=0.1, eps=1e-16): # box1(4,n), box2(4,n) - # Compute candidate boxes: box1 before augment, box2 after augment, wh_thr (pixels), aspect_ratio_thr, area_ratio + """Evaluates candidate boxes based on width, height, aspect ratio, and area thresholds.""" w1, h1 = box1[2] - box1[0], box1[3] - box1[1] w2, h2 = box2[2] - box2[0], box2[3] - box2[1] ar = np.maximum(w2 / (h2 + eps), h2 / (w2 + eps)) # aspect ratio @@ -341,7 +353,7 @@ def classify_albumentations( def classify_transforms(size=224): - # Transforms to apply if albumentations not installed + """Applies classification transforms including center cropping, tensor conversion, and normalization.""" assert isinstance(size, int), f"ERROR: classify_transforms size {size} must be integer, not (list, tuple)" # T.Compose([T.ToTensor(), T.Resize(size), T.CenterCrop(size), T.Normalize(IMAGENET_MEAN, IMAGENET_STD)]) return T.Compose([CenterCrop(size), ToTensor(), T.Normalize(IMAGENET_MEAN, IMAGENET_STD)]) @@ -350,12 +362,18 @@ def classify_transforms(size=224): class LetterBox: # YOLOv3 LetterBox class for image preprocessing, i.e. T.Compose([LetterBox(size), ToTensor()]) def __init__(self, size=(640, 640), auto=False, stride=32): + """Initializes LetterBox for YOLOv3 image preprocessing with optional auto-sizing and stride; `size` can be int + or tuple. + """ super().__init__() self.h, self.w = (size, size) if isinstance(size, int) else size self.auto = auto # pass max size integer, automatically solve for short side using stride self.stride = stride # used with auto def __call__(self, im): # im = np.array HWC + """Resizes and pads image `im` (np.array HWC) to specified `size` and `stride`, possibly autosizing for the + short side. + """ imh, imw = im.shape[:2] r = min(self.h / imh, self.w / imw) # ratio of new/old h, w = round(imh * r), round(imw * r) # resized image @@ -369,10 +387,12 @@ def __call__(self, im): # im = np.array HWC class CenterCrop: # YOLOv3 CenterCrop class for image preprocessing, i.e. T.Compose([CenterCrop(size), ToTensor()]) def __init__(self, size=640): + """Initializes a CenterCrop object for YOLOv3, to crop images to a specified size, with default 640x640.""" super().__init__() self.h, self.w = (size, size) if isinstance(size, int) else size def __call__(self, im): # im = np.array HWC + """Crops and resizes an image to specified dimensions, defaulting to 640x640, maintaining aspect ratio.""" imh, imw = im.shape[:2] m = min(imh, imw) # min dimension top, left = (imh - m) // 2, (imw - m) // 2 @@ -382,10 +402,16 @@ def __call__(self, im): # im = np.array HWC class ToTensor: # YOLOv3 ToTensor class for image preprocessing, i.e. T.Compose([LetterBox(size), ToTensor()]) def __init__(self, half=False): + """Initializes ToTensor class for YOLOv3 image preprocessing to convert images to PyTorch tensors, optionally in + half precision. + """ super().__init__() self.half = half def __call__(self, im): # im = np.array HWC in BGR order + """Converts a BGR image in numpy format to a PyTorch tensor in RGB format, with options for half precision and + normalization. + """ im = np.ascontiguousarray(im.transpose((2, 0, 1))[::-1]) # HWC to CHW -> BGR to RGB -> contiguous im = torch.from_numpy(im) # to torch im = im.half() if self.half else im.float() # uint8 to fp16/32 diff --git a/utils/autoanchor.py b/utils/autoanchor.py index 381259ecfb..dda1dce7d9 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -15,7 +15,7 @@ def check_anchor_order(m): - # Check anchor order against stride order for YOLOv3 Detect() module m, and correct if necessary + """Checks and corrects anchor order in YOLOv3's Detect() module if mismatched with stride order.""" a = m.anchors.prod(-1).mean(-1).view(-1) # mean anchor area per output layer da = a[-1] - a[0] # delta a ds = m.stride[-1] - m.stride[0] # delta s @@ -26,7 +26,7 @@ def check_anchor_order(m): @TryExcept(f"{PREFIX}ERROR") def check_anchors(dataset, model, thr=4.0, imgsz=640): - # Check anchor fit to data, recompute if necessary + """Evaluates anchor fit to dataset and recomputes if below a threshold, enhancing model performance.""" m = model.module.model[-1] if hasattr(model, "module") else model.model[-1] # Detect() shapes = imgsz * dataset.shapes / dataset.shapes.max(1, keepdims=True) scale = np.random.uniform(0.9, 1.1, size=(shapes.shape[0], 1)) # augment scale diff --git a/utils/autobatch.py b/utils/autobatch.py index 4eaf153cb9..c2ba75ce07 100644 --- a/utils/autobatch.py +++ b/utils/autobatch.py @@ -11,13 +11,15 @@ def check_train_batch_size(model, imgsz=640, amp=True): - # Check YOLOv3 training batch size + """Checks and computes the optimal training batch size for YOLOv3, given model and image size.""" with torch.cuda.amp.autocast(amp): return autobatch(deepcopy(model).train(), imgsz) # compute optimal batch size def autobatch(model, imgsz=640, fraction=0.8, batch_size=16): - # Automatically estimate best YOLOv3 batch size to use `fraction` of available CUDA memory + """Estimates optimal YOLOv3 batch size using available CUDA memory; imgsz:int=640, fraction:float=0.8, + batch_size:int=16. + """ # Usage: # import torch # from utils.autobatch import autobatch diff --git a/utils/callbacks.py b/utils/callbacks.py index 6b5321f1f3..7ee41642b0 100644 --- a/utils/callbacks.py +++ b/utils/callbacks.py @@ -8,7 +8,7 @@ class Callbacks: """" Handles all registered callbacks for YOLOv3 Hooks.""" def __init__(self): - # Define the available callbacks + """Initializes a Callbacks object to manage YOLOv3 training hooks with various event triggers.""" self._callbacks = { "on_pretrain_routine_start": [], "on_pretrain_routine_end": [], diff --git a/utils/dataloaders.py b/utils/dataloaders.py index a290111de8..6bbdf880fe 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -72,7 +72,7 @@ def get_hash(paths): - # Returns a single hash value of a list of paths (files or dirs) + """Calculates a SHA256 hash for a list of file or directory paths, combining their total size and path strings.""" size = sum(os.path.getsize(p) for p in paths if os.path.exists(p)) # sizes h = hashlib.sha256(str(size).encode()) # hash sizes h.update("".join(paths).encode()) # hash paths @@ -80,7 +80,7 @@ def get_hash(paths): def exif_size(img): - # Returns exif-corrected PIL size + """Returns corrected image size (width, height) considering EXIF rotation metadata.""" s = img.size # (width, height) with contextlib.suppress(Exception): rotation = dict(img._getexif().items())[orientation] @@ -117,7 +117,7 @@ def exif_transpose(image): def seed_worker(worker_id): - # Set dataloader worker seed https://pytorch.org/docs/stable/notes/randomness.html#dataloader + """Sets the seed for a DataLoader worker to ensure reproducibility.""" worker_seed = torch.initial_seed() % 2**32 np.random.seed(worker_seed) random.seed(worker_seed) @@ -189,14 +189,19 @@ class InfiniteDataLoader(dataloader.DataLoader): """ def __init__(self, *args, **kwargs): + """Initializes an InfiniteDataLoader that reuses workers with standard DataLoader syntax and a repeating + sampler. + """ super().__init__(*args, **kwargs) object.__setattr__(self, "batch_sampler", _RepeatSampler(self.batch_sampler)) self.iterator = super().__iter__() def __len__(self): + """Returns the length of the batch sampler's sampler.""" return len(self.batch_sampler.sampler) def __iter__(self): + """Iterates over the dataset indefinitely, yielding batches from the batch_sampler.""" for _ in range(len(self)): yield next(self.iterator) @@ -210,9 +215,11 @@ class _RepeatSampler: """ def __init__(self, sampler): + """Initializes an infinitely repeating sampler with a provided `sampler` object.""" self.sampler = sampler def __iter__(self): + """Provides an iterator that infinitely repeats over a given `sampler` object.""" while True: yield from iter(self.sampler) @@ -220,7 +227,9 @@ def __iter__(self): class LoadScreenshots: # YOLOv3 screenshot dataloader, i.e. `python detect.py --source "screen 0 100 100 512 256"` def __init__(self, source, img_size=640, stride=32, auto=True, transforms=None): - # source = [screen_number left top width height] (pixels) + """Initializes a screenshot dataloader for YOLOv3; source format: [screen_number left top width height], default + img_size=640, stride=32. + """ check_requirements("mss") import mss @@ -249,10 +258,11 @@ def __init__(self, source, img_size=640, stride=32, auto=True, transforms=None): self.monitor = {"left": self.left, "top": self.top, "width": self.width, "height": self.height} def __iter__(self): + """Iterates over itself, effectively making the object its own iterator.""" return self def __next__(self): - # mss screen capture: get raw pixels from the screen as np array + """Captures and returns the next screen image as a NumPy array in BGR format, excluding alpha channel.""" im0 = np.array(self.sct.grab(self.monitor))[:, :, :3] # [:, :, :3] BGRA to BGR s = f"screen {self.screen} (LTWH): {self.left},{self.top},{self.width},{self.height}: " @@ -269,6 +279,9 @@ def __next__(self): class LoadImages: # YOLOv3 image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4` def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): + """Initializes the data loader for YOLOv3, supporting image, video, directory, and '*.txt' path lists with + customizable image sizing. + """ if isinstance(path, str) and Path(path).suffix == ".txt": # *.txt file with img/vid/dir on each line path = Path(path).read_text().rsplit() files = [] @@ -306,10 +319,12 @@ def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vi ) def __iter__(self): + """Initializes the iterator by resetting count to zero and returning the iterator instance itself.""" self.count = 0 return self def __next__(self): + """Advances to the next file in the dataset, raising StopIteration when all files are processed.""" if self.count == self.nf: raise StopIteration path = self.files[self.count] @@ -350,7 +365,7 @@ def __next__(self): return path, im, im0, self.cap, s def _new_video(self, path): - # Create a new video capture object + """Initializes a video capture object with frame counting and orientation from a given path.""" self.frame = 0 self.cap = cv2.VideoCapture(path) self.frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT) / self.vid_stride) @@ -358,7 +373,7 @@ def _new_video(self, path): # self.cap.set(cv2.CAP_PROP_ORIENTATION_AUTO, 0) # disable https://github.com/ultralytics/yolov5/issues/8493 def _cv2_rotate(self, im): - # Rotate a cv2 video manually + """Rotates a cv2 image based on the video's metadata orientation; returns the rotated image.""" if self.orientation == 0: return cv2.rotate(im, cv2.ROTATE_90_CLOCKWISE) elif self.orientation == 180: @@ -368,12 +383,16 @@ def _cv2_rotate(self, im): return im def __len__(self): + """Returns the number of files in the dataset.""" return self.nf # number of files class LoadStreams: # YOLOv3 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams` def __init__(self, sources="file.streams", img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): + """Initializes a stream loader for YOLOv3, handling video sources or files with customizable frame sizes and + intervals. + """ torch.backends.cudnn.benchmark = True # faster for fixed-size inference self.mode = "stream" self.img_size = img_size @@ -419,7 +438,9 @@ def __init__(self, sources="file.streams", img_size=640, stride=32, auto=True, t LOGGER.warning("WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.") def update(self, i, cap, stream): - # Read stream `i` frames in daemon thread + """Reads frames from stream `i` into `self.imgs` at intervals defined by `self.vid_stride`, handling + reconnection if needed. + """ n, f = 0, self.frames[i] # frame number, frame array while cap.isOpened() and n < f: n += 1 @@ -435,10 +456,12 @@ def update(self, i, cap, stream): time.sleep(0.0) # wait time def __iter__(self): + """Resets and returns an iterator of the current object for iterating through video frames or images.""" self.count = -1 return self def __next__(self): + """Iterates video frames or images; halts if all threads are dead or 'q' is pressed.""" self.count += 1 if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord("q"): # q to quit cv2.destroyAllWindows() @@ -455,11 +478,14 @@ def __next__(self): return self.sources, im, im0, None, "" def __len__(self): + """Returns the number of sources in the dataset, supporting up to 1E12 frames across streams and scenarios.""" return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years def img2label_paths(img_paths): - # Define label paths as a function of image paths + """Converts image paths to corresponding label paths by replacing `/images/` with `/labels/` and `.jpg` with + `.txt`. + """ sa, sb = f"{os.sep}images{os.sep}", f"{os.sep}labels{os.sep}" # /images/, /labels/ substrings return [sb.join(x.rsplit(sa, 1)).rsplit(".", 1)[0] + ".txt" for x in img_paths] @@ -623,7 +649,7 @@ def __init__( pbar.close() def check_cache_ram(self, safety_margin=0.1, prefix=""): - # Check image caching requirements vs available memory + """Evaluates if there's enough RAM to cache dataset images, considering a safety margin.""" b, gb = 0, 1 << 30 # bytes of cached images, bytes per gigabytes n = min(self.n, 30) # extrapolate from 30 random images for _ in range(n): @@ -642,7 +668,7 @@ def check_cache_ram(self, safety_margin=0.1, prefix=""): return cache def cache_labels(self, path=Path("./labels.cache"), prefix=""): - # Cache dataset labels, check images and read shapes + """Caches dataset labels, checks image existence and readability, and records image shapes and segments.""" x = {} # dict nm, nf, ne, nc, msgs = 0, 0, 0, 0, [] # number missing, found, empty, corrupt, messages desc = f"{prefix}Scanning {path.parent / path.stem}..." @@ -682,6 +708,7 @@ def cache_labels(self, path=Path("./labels.cache"), prefix=""): return x def __len__(self): + """Returns the number of image files in the dataset.""" return len(self.im_files) # def __iter__(self): @@ -691,6 +718,9 @@ def __len__(self): # return self def __getitem__(self, index): + """Fetches dataset item at `index` after applying indexing via `self.indices`, supporting + linear/shuffled/image_weights modes. + """ index = self.indices[index] # linear, shuffled, or image_weights hyp = self.hyp @@ -767,7 +797,7 @@ def __getitem__(self, index): return torch.from_numpy(img), labels_out, self.im_files[index], shapes def load_image(self, i): - # Loads 1 image from dataset index 'i', returns (im, original hw, resized hw) + """Loads a single image by index, returning the image, its original dimensions, and resized dimensions.""" im, f, fn = ( self.ims[i], self.im_files[i], @@ -788,13 +818,15 @@ def load_image(self, i): return self.ims[i], self.im_hw0[i], self.im_hw[i] # im, hw_original, hw_resized def cache_images_to_disk(self, i): - # Saves an image as an *.npy file for faster loading + """Saves an image to disk as an *.npy file for faster future loading.""" f = self.npy_files[i] if not f.exists(): np.save(f.as_posix(), cv2.imread(self.im_files[i])) def load_mosaic(self, index): - # YOLOv3 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic + """Loads 4 images into a mosaic for YOLOv3 training, enhancing detection capabilities through data + augmentation. + """ labels4, segments4 = [], [] s = self.img_size yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y @@ -854,7 +886,7 @@ def load_mosaic(self, index): return img4, labels4 def load_mosaic9(self, index): - # YOLOv3 9-mosaic loader. Loads 1 image + 8 random images into a 9-image mosaic + """Loads 1 image + 8 random images into a 9-image mosaic for YOLOv3, returning combined image and labels.""" labels9, segments9 = [], [] s = self.img_size indices = [index] + random.choices(self.indices, k=8) # 8 additional image indices @@ -934,6 +966,7 @@ def load_mosaic9(self, index): @staticmethod def collate_fn(batch): + """Collates batch of images, labels, paths, and shapes, indexing labels for target image identification.""" im, label, path, shapes = zip(*batch) # transposed for i, lb in enumerate(label): lb[:, 0] = i # add target image index for build_targets() @@ -941,6 +974,7 @@ def collate_fn(batch): @staticmethod def collate_fn4(batch): + """Batches images, labels, paths, and shapes by grouping every 4 items for dataset loading.""" im, label, path, shapes = zip(*batch) # transposed n = len(shapes) // 4 im4, label4, path4, shapes4 = [], [], path[:n], shapes[:n] @@ -969,7 +1003,7 @@ def collate_fn4(batch): # Ancillary functions -------------------------------------------------------------------------------------------------- def flatten_recursive(path=DATASETS_DIR / "coco128"): - # Flatten a recursive directory by bringing all files to top level + """Flattens a directory recursively by copying all files to a new top-level directory, given an input path.""" new_path = Path(f"{str(path)}_flat") if os.path.exists(new_path): shutil.rmtree(new_path) # delete output folder @@ -979,7 +1013,9 @@ def flatten_recursive(path=DATASETS_DIR / "coco128"): def extract_boxes(path=DATASETS_DIR / "coco128"): # from utils.dataloaders import *; extract_boxes() - # Convert detection dataset into classification dataset, with one directory per class + """Converts detection dataset to classification dataset, creating one directory per class with images cropped to + bounding boxes. + """ path = Path(path) # images dir shutil.rmtree(path / "classification") if (path / "classification").is_dir() else None # remove existing files = list(path.rglob("*.*")) @@ -1039,7 +1075,7 @@ def autosplit(path=DATASETS_DIR / "coco128/images", weights=(0.9, 0.1, 0.0), ann def verify_image_label(args): - # Verify one image-label pair + """Checks and verifies one image-label pair, fixing common issues and reporting anomalies.""" im_file, lb_file, prefix = args nm, nf, ne, nc, msg, segments = 0, 0, 0, 0, "", [] # number (missing, found, empty, corrupt), message, segments try: @@ -1107,7 +1143,7 @@ class HUBDatasetStats: """ def __init__(self, path="coco128.yaml", autodownload=False): - # Initialize class + """Initializes HUBDatasetStats with dataset path, optionally autodownloads; supports .yaml or .zip formats.""" zipped, data_dir, yaml_path = self._unzip(Path(path)) try: with open(check_yaml(yaml_path), errors="ignore") as f: @@ -1126,7 +1162,7 @@ def __init__(self, path="coco128.yaml", autodownload=False): @staticmethod def _find_yaml(dir): - # Return data.yaml file + """Finds a single `data.yaml` file within specified directory, preferring matches to directory name.""" files = list(dir.glob("*.yaml")) or list(dir.rglob("*.yaml")) # try root level first and then recursive assert files, f"No *.yaml file found in {dir}" if len(files) > 1: @@ -1136,7 +1172,9 @@ def _find_yaml(dir): return files[0] def _unzip(self, path): - # Unzip data.zip + """Unzips a .zip file, verifying its integrity and locating the associated YAML file within the unzipped + directory. + """ if not str(path).endswith(".zip"): # path is data.yaml return False, None, path assert Path(path).is_file(), f"Error unzipping {path}, file not found" @@ -1146,7 +1184,9 @@ def _unzip(self, path): return True, str(dir), self._find_yaml(dir) # zipped, data_dir, yaml_path def _hub_ops(self, f, max_dim=1920): - # HUB ops for 1 image 'f': resize and save at reduced quality in /dataset-hub for web/app viewing + """Resizes and saves an image at reduced quality for web/app viewing; `f`: path to image, `max_dim`=1920 maximum + dimension. + """ f_new = self.im_dir / Path(f).name # dataset-hub image filename try: # use PIL im = Image.open(f) @@ -1164,7 +1204,10 @@ def _hub_ops(self, f, max_dim=1920): cv2.imwrite(str(f_new), im) def get_json(self, save=False, verbose=False): - # Return dataset JSON for Ultralytics HUB + """Generates dataset JSON for Ultralytics HUB, with optional saving and verbosity; rounds labels to int class + and 6 decimal floats. + """ + def _round(labels): # Update labels to integer class and 6 decimal place floats return [[int(c), *(round(x, 4) for x in points)] for c, *points in labels] @@ -1201,7 +1244,9 @@ def _round(labels): return self.stats def process_images(self): - # Compress images for Ultralytics HUB + """Compresses images for Ultralytics HUB, saving them to specified directory; supports 'train', 'val', 'test' + splits. + """ for split in "train", "val", "test": if self.data.get(split) is None: continue @@ -1225,6 +1270,9 @@ class ClassificationDataset(torchvision.datasets.ImageFolder): """ def __init__(self, root, augment, imgsz, cache=False): + """Initializes classification dataset with optional augmentation, image resizing, caching, inheriting from + ImageFolder. + """ super().__init__(root=root) self.torch_transforms = classify_transforms(imgsz) self.album_transforms = classify_albumentations(augment, imgsz) if augment else None @@ -1233,6 +1281,7 @@ def __init__(self, root, augment, imgsz, cache=False): self.samples = [list(x) + [Path(x[0]).with_suffix(".npy"), None] for x in self.samples] # file, index, npy, im def __getitem__(self, i): + """Fetches the item at index `i`, applies caching and transformations, and returns image-sample and index.""" f, j, fn, im = self.samples[i] # filename, index, filename.with_suffix('.npy'), image if self.cache_ram and im is None: im = self.samples[i][3] = cv2.imread(f) diff --git a/utils/downloads.py b/utils/downloads.py index e35922d159..5203dd14b8 100644 --- a/utils/downloads.py +++ b/utils/downloads.py @@ -11,7 +11,7 @@ def is_url(url, check=True): - # Check if string is URL and check if URL exists + """Determines if a string is a valid URL and optionally checks its existence online.""" try: url = str(url) result = urllib.parse.urlparse(url) @@ -22,13 +22,13 @@ def is_url(url, check=True): def gsutil_getsize(url=""): - # gs://bucket/file size https://cloud.google.com/storage/docs/gsutil/commands/du + """Returns the size of a file at a 'gs://' URL using gsutil du command; 0 if file not found or command fails.""" output = subprocess.check_output(["gsutil", "du", url], shell=True, encoding="utf-8") return int(output.split()[0]) if output else 0 def url_getsize(url="https://ultralytics.com/images/bus.jpg"): - # Return downloadable file size in bytes + """Fetches file size in bytes from a URL using an HTTP HEAD request; defaults to -1 if not found.""" response = requests.head(url, allow_redirects=True) return int(response.headers.get("content-length", -1)) @@ -54,7 +54,7 @@ def curl_download(url, filename, *, silent: bool = False) -> bool: def safe_download(file, url, url2=None, min_bytes=1e0, error_msg=""): - # Attempts to download file from url or url2, checks and removes incomplete downloads < min_bytes + """Downloads a file from 'url' or 'url2' to 'file', ensuring size > 'min_bytes'; removes incomplete downloads.""" from utils.general import LOGGER file = Path(file) @@ -78,7 +78,9 @@ def safe_download(file, url, url2=None, min_bytes=1e0, error_msg=""): def attempt_download(file, repo="ultralytics/yolov5", release="v7.0"): - # Attempt file download from GitHub release assets if not found locally. release = 'latest', 'v7.0', etc. + """Attempts to download a file from a specified URL or GitHub release, ensuring file integrity with a minimum size + check. + """ from utils.general import LOGGER def github_assets(repository, version="latest"): diff --git a/utils/flask_rest_api/restapi.py b/utils/flask_rest_api/restapi.py index 62698d848e..015316e5b6 100644 --- a/utils/flask_rest_api/restapi.py +++ b/utils/flask_rest_api/restapi.py @@ -16,6 +16,9 @@ @app.route(DETECTION_URL, methods=["POST"]) def predict(model): + """Predicts objects in an image using YOLOv5s models exposed via Flask REST API; expects 'image' file in POST + request. + """ if request.method != "POST": return diff --git a/utils/general.py b/utils/general.py index ce5e3db069..6309a22c01 100644 --- a/utils/general.py +++ b/utils/general.py @@ -61,18 +61,18 @@ def is_ascii(s=""): - # Is string composed of all ASCII (no UTF) characters? (note str().isascii() introduced in python 3.7) + """Checks if input string `s` is composed solely of ASCII characters; compatible with pre-Python 3.7 versions.""" s = str(s) # convert list, tuple, None, etc. to str return len(s.encode().decode("ascii", "ignore")) == len(s) def is_chinese(s="人工智能"): - # Is string composed of any Chinese characters? + """Determines if a string `s` contains any Chinese characters; returns a boolean.""" return bool(re.search("[\u4e00-\u9fff]", str(s))) def is_colab(): - # Is environment a Google Colab instance? + """Checks if the current environment is a Google Colab instance; returns a boolean.""" return "google.colab" in sys.modules @@ -91,7 +91,7 @@ def is_jupyter(): def is_kaggle(): - # Is environment a Kaggle Notebook? + """Determines if the environment is a Kaggle Notebook by checking environment variables.""" return os.environ.get("PWD") == "/kaggle/working" and os.environ.get("KAGGLE_URL_BASE") == "https://www.kaggle.com" @@ -107,7 +107,7 @@ def is_docker() -> bool: def is_writeable(dir, test=False): - # Return True if directory has write permissions, test opening a file with write permissions if test=True + """Determines if a directory is writeable, optionally tests by writing a file if `test=True`.""" if not test: return os.access(dir, os.W_OK) # possible issues on Windows file = Path(dir) / "tmp.txt" @@ -124,7 +124,7 @@ def is_writeable(dir, test=False): def set_logging(name=LOGGING_NAME, verbose=True): - # sets up logging for the given name + """Configures logging with specified verbosity; 'name' sets logger identity, 'verbose' toggles logging level.""" rank = int(os.getenv("RANK", -1)) # rank in world for Multi-GPU trainings level = logging.INFO if verbose and rank in {-1, 0} else logging.ERROR logging.config.dictConfig( @@ -158,7 +158,9 @@ def set_logging(name=LOGGING_NAME, verbose=True): def user_config_dir(dir="Ultralytics", env_var="YOLOV5_CONFIG_DIR"): - # Return path of user configuration directory. Prefer environment variable if exists. Make dir if required. + """Returns user configuration directory path, prefers `env_var` if set, else uses OS-specific path, creates + directory if needed. + """ env = os.getenv(env_var) if env: path = Path(env) # use environment variable @@ -176,18 +178,26 @@ def user_config_dir(dir="Ultralytics", env_var="YOLOV5_CONFIG_DIR"): class Profile(contextlib.ContextDecorator): # YOLOv3 Profile class. Usage: @Profile() decorator or 'with Profile():' context manager def __init__(self, t=0.0): + """Initializes a profiling context for YOLOv3 with optional timing threshold `t` and checks CUDA + availability. + """ self.t = t self.cuda = torch.cuda.is_available() def __enter__(self): + """Starts the profiling timer, returning the profile instance for use with @Profile() decorator or 'with + Profile():' context. + """ self.start = self.time() return self def __exit__(self, type, value, traceback): + """Ends profiling, calculating time delta and updating total time, for use within 'with Profile():' context.""" self.dt = self.time() - self.start # delta-time self.t += self.dt # accumulate dt def time(self): + """Returns current time, ensuring CUDA operations are synchronized if on GPU.""" if self.cuda: torch.cuda.synchronize() return time.time() @@ -196,19 +206,25 @@ def time(self): class Timeout(contextlib.ContextDecorator): # YOLOv3 Timeout class. Usage: @Timeout(seconds) decorator or 'with Timeout(seconds):' context manager def __init__(self, seconds, *, timeout_msg="", suppress_timeout_errors=True): + """Initializes a timeout context/decorator with specified duration, custom message, and error handling + option. + """ self.seconds = int(seconds) self.timeout_message = timeout_msg self.suppress = bool(suppress_timeout_errors) def _timeout_handler(self, signum, frame): + """Raises a TimeoutError with a custom message upon timeout signal reception.""" raise TimeoutError(self.timeout_message) def __enter__(self): + """Starts a countdown for a signal alarm; not supported on Windows.""" if platform.system() != "Windows": # not supported on Windows signal.signal(signal.SIGALRM, self._timeout_handler) # Set handler for SIGALRM signal.alarm(self.seconds) # start countdown for SIGALRM to be raised def __exit__(self, exc_type, exc_val, exc_tb): + """Cancels any scheduled SIGALRM on non-Windows platforms, optionally suppressing TimeoutError.""" if platform.system() != "Windows": signal.alarm(0) # Cancel SIGALRM if it's scheduled if self.suppress and exc_type is TimeoutError: # Suppress TimeoutError @@ -218,23 +234,26 @@ def __exit__(self, exc_type, exc_val, exc_tb): class WorkingDirectory(contextlib.ContextDecorator): # Usage: @WorkingDirectory(dir) decorator or 'with WorkingDirectory(dir):' context manager def __init__(self, new_dir): + """Initializes context manager to temporarily change working directory, reverting on exit.""" self.dir = new_dir # new dir self.cwd = Path.cwd().resolve() # current dir def __enter__(self): + """Temporarily changes the current working directory to `new_dir`, reverting to the original on exit.""" os.chdir(self.dir) def __exit__(self, exc_type, exc_val, exc_tb): + """Reverts to the original working directory upon exiting the context manager.""" os.chdir(self.cwd) def methods(instance): - # Get class/instance methods + """Returns a list of callable class/instance methods, excluding magic methods.""" return [f for f in dir(instance) if callable(getattr(instance, f)) and not f.startswith("__")] def print_args(args: Optional[dict] = None, show_file=True, show_func=False): - # Print function arguments (optional args dict) + """Prints function arguments; optionally specify args dict, show file and/or function name.""" x = inspect.currentframe().f_back # previous frame file, _, func, _, _ = inspect.getframeinfo(x) if args is None: # get args automatically @@ -249,7 +268,9 @@ def print_args(args: Optional[dict] = None, show_file=True, show_func=False): def init_seeds(seed=0, deterministic=False): - # Initialize random number generator (RNG) seeds https://pytorch.org/docs/stable/notes/randomness.html + """Initializes RNG seeds for reproducibility; `seed`: RNG seed, `deterministic`: enforces deterministic behavior if + True. + """ random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) @@ -264,36 +285,40 @@ def init_seeds(seed=0, deterministic=False): def intersect_dicts(da, db, exclude=()): - # Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values + """Intersects two dicts by matching keys and shapes, excluding specified keys, and retains values from the first + dict. + """ return {k: v for k, v in da.items() if k in db and all(x not in k for x in exclude) and v.shape == db[k].shape} def get_default_args(func): - # Get func() default arguments + """Returns a dict of `func`'s default arguments using inspection.""" signature = inspect.signature(func) return {k: v.default for k, v in signature.parameters.items() if v.default is not inspect.Parameter.empty} def get_latest_run(search_dir="."): - # Return path to most recent 'last.pt' in /runs (i.e. to --resume from) + """Returns path to the most recent 'last.pt' file within 'search_dir' for resuming, or an empty string if not + found. + """ last_list = glob.glob(f"{search_dir}/**/last*.pt", recursive=True) return max(last_list, key=os.path.getctime) if last_list else "" def file_age(path=__file__): - # Return days since last file update + """Returns the number of days since the last update of the file specified by 'path'.""" dt = datetime.now() - datetime.fromtimestamp(Path(path).stat().st_mtime) # delta return dt.days # + dt.seconds / 86400 # fractional days def file_date(path=__file__): - # Return human-readable file modification date, i.e. '2021-3-26' + """Returns file modification date in 'YYYY-M-D' format for the file at 'path'.""" t = datetime.fromtimestamp(Path(path).stat().st_mtime) return f"{t.year}-{t.month}-{t.day}" def file_size(path): - # Return file/dir size (MB) + """Returns the size of a file or total size of files in a directory at 'path' in MB.""" mb = 1 << 20 # bytes to MiB (1024 ** 2) path = Path(path) if path.is_file(): @@ -305,7 +330,9 @@ def file_size(path): def check_online(): - # Check internet connectivity + """Checks internet connectivity by attempting to connect to "1.1.1.1" on port 443 twice; returns True if + successful. + """ import socket def run_once(): @@ -320,7 +347,7 @@ def run_once(): def git_describe(path=ROOT): # path must be a directory - # Return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe + """Returns human-readable git description of a directory if it's a git repository, otherwise an empty string.""" try: assert (Path(path) / ".git").is_dir() return check_output(f"git -C {path} describe --tags --long --always", shell=True).decode()[:-1] @@ -331,7 +358,9 @@ def git_describe(path=ROOT): # path must be a directory @TryExcept() @WorkingDirectory(ROOT) def check_git_status(repo="ultralytics/yolov5", branch="master"): - # YOLOv3 status check, recommend 'git pull' if code is out of date + """Checks YOLOv3 code update status against remote, suggests 'git pull' if outdated; requires internet and git + repository. + """ url = f"https://github.com/{repo}" msg = f", for updates see {url}" s = colorstr("github: ") # string @@ -358,7 +387,11 @@ def check_git_status(repo="ultralytics/yolov5", branch="master"): @WorkingDirectory(ROOT) def check_git_info(path="."): - # YOLOv3 git info check, return {remote, branch, commit} + """ + Checks YOLOv3 git info (remote, branch, commit) in path, requires 'gitpython'. + + Returns dict. + """ check_requirements("gitpython") import git @@ -376,12 +409,12 @@ def check_git_info(path="."): def check_python(minimum="3.7.0"): - # Check current python version vs. required python version + """Checks if current Python version meets the specified minimum requirement, raising error if not.""" check_version(platform.python_version(), minimum, name="Python ", hard=True) def check_version(current="0.0.0", minimum="0.0.0", name="version ", pinned=False, hard=False, verbose=False): - # Check version vs. required version + """Compares current and minimum version requirements, optionally enforcing minimum version and logging warnings.""" current, minimum = (pkg.parse_version(x) for x in (current, minimum)) result = (current == minimum) if pinned else (current >= minimum) # bool s = f"WARNING ⚠️ {name}{minimum} is required by YOLOv3, but {name}{current} is currently installed" # string @@ -393,7 +426,9 @@ def check_version(current="0.0.0", minimum="0.0.0", name="version ", pinned=Fals def check_img_size(imgsz, s=32, floor=0): - # Verify image size is a multiple of stride s in each dimension + """Adjusts image size to be divisible by `s`, ensuring it's above `floor`; returns int for single dim or list for + dims. + """ if isinstance(imgsz, int): # integer i.e. img_size=640 new_size = max(make_divisible(imgsz, int(s)), floor) else: # list i.e. img_size=[640, 480] @@ -405,7 +440,7 @@ def check_img_size(imgsz, s=32, floor=0): def check_imshow(warn=False): - # Check if environment supports image displays + """Checks if the environment supports image display; warns if `warn=True` and display is unsupported.""" try: assert not is_jupyter() assert not is_docker() @@ -421,7 +456,7 @@ def check_imshow(warn=False): def check_suffix(file="yolov5s.pt", suffix=(".pt",), msg=""): - # Check file(s) for acceptable suffix + """Checks for acceptable file suffixes, supports batch checking for lists or tuples of filenames.""" if file and suffix: if isinstance(suffix, str): suffix = [suffix] @@ -432,12 +467,14 @@ def check_suffix(file="yolov5s.pt", suffix=(".pt",), msg=""): def check_yaml(file, suffix=(".yaml", ".yml")): - # Search/download YAML file (if necessary) and return path, checking suffix + """Searches/downloads a YAML file and returns its path, ensuring it has a .yaml or .yml suffix.""" return check_file(file, suffix) def check_file(file, suffix=""): - # Search/download file (if necessary) and return path + """Checks for file's existence locally, downloads if a URL, supports ClearML dataset IDs, and enforces optional + suffix. + """ check_suffix(file, suffix) # optional file = str(file) # convert to str() if os.path.isfile(file) or not file: # exists @@ -467,7 +504,7 @@ def check_file(file, suffix=""): def check_font(font=FONT, progress=False): - # Download font to CONFIG_DIR if necessary + """Checks and downloads the specified font to CONFIG_DIR if not present, with optional download progress.""" font = Path(font) file = CONFIG_DIR / font.name if not font.exists() and not file.exists(): @@ -477,7 +514,7 @@ def check_font(font=FONT, progress=False): def check_dataset(data, autodownload=True): - # Download, check and/or unzip dataset if not found locally + """Verifies and prepares dataset by downloading if absent, checking, and unzipping; supports auto-downloading.""" # Download (optional) extract_dir = "" @@ -543,7 +580,7 @@ def check_dataset(data, autodownload=True): def check_amp(model): - # Check PyTorch Automatic Mixed Precision (AMP) functionality. Return True on correct operation + """Checks PyTorch AMP functionality with model and sample image, returning True if AMP operates correctly.""" from models.common import AutoShape, DetectMultiBackend def amp_allclose(model, im): @@ -571,19 +608,21 @@ def amp_allclose(model, im): def yaml_load(file="data.yaml"): - # Single-line safe yaml loading + """Safely loads a YAML file, ignoring file errors; default file is 'data.yaml'.""" with open(file, errors="ignore") as f: return yaml.safe_load(f) def yaml_save(file="data.yaml", data={}): - # Single-line safe yaml saving + """Safely saves data to a YAML file, converting `Path` objects to strings; defaults to 'data.yaml'.""" with open(file, "w") as f: yaml.safe_dump({k: str(v) if isinstance(v, Path) else v for k, v in data.items()}, f, sort_keys=False) def unzip_file(file, path=None, exclude=(".DS_Store", "__MACOSX")): - # Unzip a *.zip file to path/, excluding files containing strings in exclude list + """Unzips '*.zip' to `path` (default: file's parent), excluding files matching `exclude` (`('.DS_Store', + '__MACOSX')`). + """ if path is None: path = Path(file).parent # default path with ZipFile(file) as zipObj: @@ -593,13 +632,16 @@ def unzip_file(file, path=None, exclude=(".DS_Store", "__MACOSX")): def url2file(url): - # Convert URL to filename, i.e. https://url.com/file.txt?auth -> file.txt + """Converts a URL to a filename by extracting the last path segment and removing query parameters.""" url = str(Path(url)).replace(":/", "://") # Pathlib turns :// -> :/ return Path(urllib.parse.unquote(url)).name.split("?")[0] # '%2F' to '/', split https://url.com/file.txt?auth def download(url, dir=".", unzip=True, delete=True, curl=False, threads=1, retry=3): - # Multithreaded file download and unzip function, used in data.yaml for autodownload + """Downloads files from URLs into a specified directory, optionally unzips, and supports multithreading and + retries. + """ + def download_one(url, dir): # Download 1 file success = True @@ -645,24 +687,29 @@ def download_one(url, dir): def make_divisible(x, divisor): - # Returns nearest x divisible by divisor + """Adjusts `x` to be nearest and greater than or equal to value divisible by `divisor`.""" if isinstance(divisor, torch.Tensor): divisor = int(divisor.max()) # to int return math.ceil(x / divisor) * divisor def clean_str(s): - # Cleans a string by replacing special characters with underscore _ + """Cleans a string by replacing special characters with underscores, e.g., 'test@string!' to 'test_string_'.""" return re.sub(pattern="[|@#!¡·$€%&()=?¿^*;:,¨´><+]", repl="_", string=s) def one_cycle(y1=0.0, y2=1.0, steps=100): - # lambda function for sinusoidal ramp from y1 to y2 https://arxiv.org/pdf/1812.01187.pdf + """Generates a lambda for a sinusoidal ramp from y1 to y2 over 'steps'; usage: `lambda x: ((1 - math.cos(x * + math.pi / steps)) / 2) * (y2 - y1) + y1`.""" return lambda x: ((1 - math.cos(x * math.pi / steps)) / 2) * (y2 - y1) + y1 def colorstr(*input): - # Colors a string https://en.wikipedia.org/wiki/ANSI_escape_code, i.e. colorstr('blue', 'hello world') + """ + Colors strings using ANSI escape codes; see usage example `colorstr('blue', 'hello world')`. + + [https://en.wikipedia.org/wiki/ANSI_escape_code] + """ *args, string = input if len(input) > 1 else ("blue", "bold", input[0]) # color arguments, string colors = { "black": "\033[30m", # basic colors @@ -689,7 +736,9 @@ def colorstr(*input): def labels_to_class_weights(labels, nc=80): - # Get class weights (inverse frequency) from training labels + """Calculates class weights from labels to counteract dataset imbalance; `labels` is a list of numpy arrays with + shape `(n, 5)`. + """ if labels[0] is None: # no labels loaded return torch.Tensor() @@ -708,14 +757,18 @@ def labels_to_class_weights(labels, nc=80): def labels_to_image_weights(labels, nc=80, class_weights=np.ones(80)): - # Produces image weights based on class_weights and image contents + """Calculates image weights from labels using class weights, for balanced sampling.""" # Usage: index = random.choices(range(n), weights=image_weights, k=1) # weighted image sample class_counts = np.array([np.bincount(x[:, 0].astype(int), minlength=nc) for x in labels]) return (class_weights.reshape(1, nc) * class_counts).sum(1) def coco80_to_coco91_class(): # converts 80-index (val2014) to 91-index (paper) - # https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/ + """ + Converts COCO 80-class index to COCO 91-class index. + + Reference: https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/ + """ # a = np.loadtxt('data/coco.names', dtype='str', delimiter='\n') # b = np.loadtxt('data/coco_paper.names', dtype='str', delimiter='\n') # x1 = [list(a[i] == b).index(True) + 1 for i in range(80)] # darknet to coco @@ -805,7 +858,7 @@ def coco80_to_coco91_class(): # converts 80-index (val2014) to 91-index (paper) def xyxy2xywh(x): - # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] where xy1=top-left, xy2=bottom-right + """Converts nx4 bounding boxes from corners [x1, y1, x2, y2] to center format [x, y, w, h].""" y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) y[..., 0] = (x[..., 0] + x[..., 2]) / 2 # x center y[..., 1] = (x[..., 1] + x[..., 3]) / 2 # y center @@ -815,7 +868,7 @@ def xyxy2xywh(x): def xywh2xyxy(x): - # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + """Converts bbox format from [x, y, w, h] to [x1, y1, x2, y2], supporting torch.Tensor and np.ndarray.""" y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) y[..., 0] = x[..., 0] - x[..., 2] / 2 # top left x y[..., 1] = x[..., 1] - x[..., 3] / 2 # top left y @@ -825,7 +878,7 @@ def xywh2xyxy(x): def xywhn2xyxy(x, w=640, h=640, padw=0, padh=0): - # Convert nx4 boxes from [x, y, w, h] normalized to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + """Converts boxes from normalized [x, y, w, h] to [x1, y1, x2, y2] format, applies padding.""" y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) y[..., 0] = w * (x[..., 0] - x[..., 2] / 2) + padw # top left x y[..., 1] = h * (x[..., 1] - x[..., 3] / 2) + padh # top left y @@ -835,7 +888,7 @@ def xywhn2xyxy(x, w=640, h=640, padw=0, padh=0): def xyxy2xywhn(x, w=640, h=640, clip=False, eps=0.0): - # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] normalized where xy1=top-left, xy2=bottom-right + """Converts bounding boxes from [x1, y1, x2, y2] format to normalized [x, y, w, h] format.""" if clip: clip_boxes(x, (h - eps, w - eps)) # warning: inplace clip y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) @@ -847,7 +900,7 @@ def xyxy2xywhn(x, w=640, h=640, clip=False, eps=0.0): def xyn2xy(x, w=640, h=640, padw=0, padh=0): - # Convert normalized segments into pixel segments, shape (n,2) + """Converts normalized segments to pixel segments, shape (n,2), adjusting for width `w`, height `h`, and padding.""" y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) y[..., 0] = w * x[..., 0] + padw # top left x y[..., 1] = h * x[..., 1] + padh # top left y @@ -855,7 +908,9 @@ def xyn2xy(x, w=640, h=640, padw=0, padh=0): def segment2box(segment, width=640, height=640): - # Convert 1 segment label to 1 box label, applying inside-image constraint, i.e. (xy1, xy2, ...) to (xyxy) + """Converts a single segment to a bounding box using image dimensions, output shape (4,), ensuring coordinates stay + within image boundaries. + """ x, y = segment.T # segment xy inside = (x >= 0) & (y >= 0) & (x <= width) & (y <= height) ( @@ -866,7 +921,7 @@ def segment2box(segment, width=640, height=640): def segments2boxes(segments): - # Convert segment labels to box labels, i.e. (cls, xy1, xy2, ...) to (cls, xywh) + """Converts segmentation labels to bounding box labels in format (cls, xywh) from (cls, xy1, xy2, ...).""" boxes = [] for s in segments: x, y = s.T # segment xy @@ -875,7 +930,7 @@ def segments2boxes(segments): def resample_segments(segments, n=1000): - # Up-sample an (n,2) segment + """Resamples segments to a fixed number of points (n), returning up-sampled (n,2) segment arrays.""" for i, s in enumerate(segments): s = np.concatenate((s, s[0:1, :]), axis=0) x = np.linspace(0, len(s) - 1, n) @@ -885,7 +940,7 @@ def resample_segments(segments, n=1000): def scale_boxes(img1_shape, boxes, img0_shape, ratio_pad=None): - # Rescale boxes (xyxy) from img1_shape to img0_shape + """Rescales bounding boxes from one image shape to another, optionally with ratio and padding adjustments.""" if ratio_pad is None: # calculate from img0_shape gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding @@ -901,7 +956,9 @@ def scale_boxes(img1_shape, boxes, img0_shape, ratio_pad=None): def scale_segments(img1_shape, segments, img0_shape, ratio_pad=None, normalize=False): - # Rescale coords (xyxy) from img1_shape to img0_shape + """Rescales segment coordinates from img1_shape to img0_shape, optionally normalizing, with support for padding + adjustments. + """ if ratio_pad is None: # calculate from img0_shape gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding @@ -920,7 +977,7 @@ def scale_segments(img1_shape, segments, img0_shape, ratio_pad=None, normalize=F def clip_boxes(boxes, shape): - # Clip boxes (xyxy) to image shape (height, width) + """Clips bounding boxes to within the specified image shape; supports both torch.Tensor and np.array.""" if isinstance(boxes, torch.Tensor): # faster individually boxes[..., 0].clamp_(0, shape[1]) # x1 boxes[..., 1].clamp_(0, shape[0]) # y1 @@ -932,7 +989,7 @@ def clip_boxes(boxes, shape): def clip_segments(segments, shape): - # Clip segments (xy1,xy2,...) to image shape (height, width) + """Clips segments to within image shape (height, width), supporting torch.Tensor and np.array inputs.""" if isinstance(segments, torch.Tensor): # faster individually segments[:, 0].clamp_(0, shape[1]) # x segments[:, 1].clamp_(0, shape[0]) # y @@ -1056,7 +1113,7 @@ def non_max_suppression( def strip_optimizer(f="best.pt", s=""): # from utils.general import *; strip_optimizer() - # Strip optimizer from 'f' to finalize training, optionally save as 's' + """Strips optimizer from a checkpoint file 'f', optionally saving as 's', to finalize training.""" x = torch.load(f, map_location=torch.device("cpu")) if x.get("ema"): x["model"] = x["ema"] # replace model with ema @@ -1072,6 +1129,7 @@ def strip_optimizer(f="best.pt", s=""): # from utils.general import *; strip_op def print_mutation(keys, results, hyp, save_dir, bucket, prefix=colorstr("evolve: ")): + """Logs mutation results, updates evolve CSV/YAML, optionally syncs with cloud storage.""" evolve_csv = save_dir / "evolve.csv" evolve_yaml = save_dir / "hyp_evolve.yaml" keys = tuple(keys) + tuple(hyp.keys()) # [results + hyps] @@ -1126,7 +1184,7 @@ def print_mutation(keys, results, hyp, save_dir, bucket, prefix=colorstr("evolve def apply_classifier(x, model, img, im0): - # Apply a second stage classifier to YOLO outputs + """Applies a second stage classifier to YOLO outputs, adjusting box shapes and filtering class matches.""" # Example model = torchvision.models.__dict__['efficientnet_b0'](pretrained=True).to(device).eval() im0 = [im0] if isinstance(im0, np.ndarray) else im0 for i, d in enumerate(x): # per image @@ -1161,7 +1219,11 @@ def apply_classifier(x, model, img, im0): def increment_path(path, exist_ok=False, sep="", mkdir=False): - # Increment file or directory path, i.e. runs/exp --> runs/exp{sep}2, runs/exp{sep}3, ... etc. + """ + Increments file or directory path, optionally creating the directory, not thread-safe. + + Args: path (str/Path), exist_ok (bool), sep (str), mkdir (bool). + """ path = Path(path) # os-agnostic if path.exists() and not exist_ok: path, suffix = (path.with_suffix(""), path.suffix) if path.is_file() else (path, "") @@ -1186,15 +1248,22 @@ def increment_path(path, exist_ok=False, sep="", mkdir=False): return path -# OpenCV Multilanguage-friendly functions ------------------------------------------------------------------------------------ +# OpenCV Multilanguage-friendly functions +# ------------------------------------------------------------------------------------ imshow_ = cv2.imshow # copy to avoid recursion errors def imread(filename, flags=cv2.IMREAD_COLOR): + """Reads an image from a file, supporting multilanguage paths, and returns it in the specified color scheme.""" return cv2.imdecode(np.fromfile(filename, np.uint8), flags) def imwrite(filename, img): + """ + Writes an image to a file; returns True on success, False on failure. + + Args: filename (str), img (ndarray). + """ try: cv2.imencode(Path(filename).suffix, img)[1].tofile(filename) return True @@ -1203,6 +1272,7 @@ def imwrite(filename, img): def imshow(path, im): + """Displays an image; accepts a path (str) and image data (ndarray) as arguments.""" imshow_(path.encode("unicode_escape").decode(), im) diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index 4d4c4fccfd..1d84536f06 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -59,6 +59,9 @@ class Loggers: # YOLOv3 Loggers class def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, include=LOGGERS): + """Initializes YOLOv3 logging with directory, weights, options, hyperparameters, and includes specified + loggers. + """ self.save_dir = save_dir self.weights = weights self.opt = opt @@ -134,7 +137,7 @@ def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, @property def remote_dataset(self): - # Get data_dict if custom dataset artifact link is provided + """Fetches dataset dictionary from ClearML, W&B, or Comet ML based on the logger instantiated.""" data_dict = None if self.clearml: data_dict = self.clearml.data_dict @@ -146,15 +149,21 @@ def remote_dataset(self): return data_dict def on_train_start(self): + """Calls `on_train_start` method on comet_logger if it's available.""" if self.comet_logger: self.comet_logger.on_train_start() def on_pretrain_routine_start(self): + """Initiates pretraining routine on comet_logger if available.""" if self.comet_logger: self.comet_logger.on_pretrain_routine_start() def on_pretrain_routine_end(self, labels, names): - # Callback runs on pre-train routine end + """ + Logs pretrain routine end, plots labels if enabled, updates WandB/Comet with images. + + Takes `labels` (List of int), `names` (List of str). + """ if self.plots: plot_labels(labels, names, self.save_dir) paths = self.save_dir.glob("*labels*.jpg") # training labels @@ -166,6 +175,7 @@ def on_pretrain_routine_end(self, labels, names): self.comet_logger.on_pretrain_routine_end(paths) def on_train_batch_end(self, model, ni, imgs, targets, paths, vals): + """Logs training batch details, plots initial batches, logs Tensorboard and WandB/ClearML if enabled.""" log_dict = dict(zip(self.keys[:3], vals)) # Callback runs on train batch end # ni: number integrated batches (since train start) @@ -186,7 +196,7 @@ def on_train_batch_end(self, model, ni, imgs, targets, paths, vals): self.comet_logger.on_train_batch_end(log_dict, step=ni) def on_train_epoch_end(self, epoch): - # Callback runs on train epoch end + """Callback that updates the current epoch in wandb at the end of each training epoch.""" if self.wandb: self.wandb.current_epoch = epoch + 1 @@ -194,22 +204,30 @@ def on_train_epoch_end(self, epoch): self.comet_logger.on_train_epoch_end(epoch) def on_val_start(self): + """Callback that notifies the comet logger at the start of each validation phase.""" if self.comet_logger: self.comet_logger.on_val_start() def on_val_image_end(self, pred, predn, path, names, im): - # Callback runs on val image end + """Callback for logging a single validation image and its predictions to WandB or ClearML at the end of + validation. + """ if self.wandb: self.wandb.val_one_image(pred, predn, path, names, im) if self.clearml: self.clearml.log_image_with_boxes(path, pred, names, im) def on_val_batch_end(self, batch_i, im, targets, paths, shapes, out): + """ + Logs a single validation batch for Comet ML analytics (batch_i: int, im: tensor, targets: tensor, paths: + + list, shapes: list, out: tensor). + """ if self.comet_logger: self.comet_logger.on_val_batch_end(batch_i, im, targets, paths, shapes, out) def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix): - # Callback runs on val end + """Logs validation results and images on validation end for visual analytics.""" if self.wandb or self.clearml: files = sorted(self.save_dir.glob("val*.jpg")) if self.wandb: @@ -221,7 +239,7 @@ def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) self.comet_logger.on_val_end(nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) def on_fit_epoch_end(self, vals, epoch, best_fitness, fi): - # Callback runs at the end of each fit (train+val) epoch + """Logs epoch results to CSV if enabled, updating with vals, best_fitness, and fi.""" x = dict(zip(self.keys, vals)) if self.csv: file = self.save_dir / "results.csv" @@ -254,7 +272,9 @@ def on_fit_epoch_end(self, vals, epoch, best_fitness, fi): self.comet_logger.on_fit_epoch_end(x, epoch=epoch) def on_model_save(self, last, epoch, final_epoch, best_fitness, fi): - # Callback runs on model save event + """Logs model to WandB/ClearML, considering save_period and if not final_epoch, also notes if best model so + far. + """ if (epoch + 1) % self.opt.save_period == 0 and not final_epoch and self.opt.save_period != -1: if self.wandb: self.wandb.log_model(last.parent, self.opt, epoch, fi, best_model=best_fitness == fi) @@ -267,7 +287,9 @@ def on_model_save(self, last, epoch, final_epoch, best_fitness, fi): self.comet_logger.on_model_save(last, epoch, final_epoch, best_fitness, fi) def on_train_end(self, last, best, epoch, results): - # Callback runs on training end, i.e. saving best model + """Callback to execute at training end, saving plots of results and relevant metrics to the specified save + directory. + """ if self.plots: plot_results(file=self.save_dir / "results.csv") # save results.png files = ["results.png", "confusion_matrix.png", *(f"{x}_curve.png" for x in ("F1", "PR", "P", "R"))] @@ -301,7 +323,7 @@ def on_train_end(self, last, best, epoch, results): self.comet_logger.on_train_end(files, self.save_dir, last, best, epoch, final_results) def on_params_update(self, params: dict): - # Update hyperparams or configs of the experiment + """Updates experiment hyperparameters or configs in WandB and Comet logger with provided params dictionary.""" if self.wandb: self.wandb.wandb_run.config.update(params, allow_val_change=True) if self.comet_logger: @@ -319,7 +341,7 @@ class GenericLogger: """ def __init__(self, opt, console_logger, include=("tb", "wandb")): - # init default loggers + """Initializes a generic logger for YOLOv3, including options for TensorBoard and wandb logging.""" self.save_dir = Path(opt.save_dir) self.include = include self.console_logger = console_logger @@ -339,7 +361,7 @@ def __init__(self, opt, console_logger, include=("tb", "wandb")): self.wandb = None def log_metrics(self, metrics, epoch): - # Log metrics dictionary to all loggers + """Logs metric dictionary to all loggers, including CSV with keys, values, and epoch.""" if self.csv: keys, vals = list(metrics.keys()), list(metrics.values()) n = len(metrics) + 1 # number of cols @@ -355,7 +377,7 @@ def log_metrics(self, metrics, epoch): self.wandb.log(metrics, step=epoch) def log_images(self, files, name="Images", epoch=0): - # Log images to all loggers + """Logs images to TensorBoard and Weights & Biases, ensuring file existence and supporting various formats.""" files = [Path(f) for f in (files if isinstance(files, (tuple, list)) else [files])] # to Path files = [f for f in files if f.exists()] # filter by exists @@ -367,25 +389,25 @@ def log_images(self, files, name="Images", epoch=0): self.wandb.log({name: [wandb.Image(str(f), caption=f.name) for f in files]}, step=epoch) def log_graph(self, model, imgsz=(640, 640)): - # Log model graph to all loggers + """Logs model graph to all loggers, accepts `model` and `imgsz` (default (640, 640)) as inputs.""" if self.tb: log_tensorboard_graph(self.tb, model, imgsz) def log_model(self, model_path, epoch=0, metadata={}): - # Log model to all loggers + """Logs model to all loggers with `model_path`, optional `epoch` (default 0), and `metadata` dictionary.""" if self.wandb: art = wandb.Artifact(name=f"run_{wandb.run.id}_model", type="model", metadata=metadata) art.add_file(str(model_path)) wandb.log_artifact(art) def update_params(self, params): - # Update the parameters logged + """Updates logged parameters in wandb; `params`: dictionary to update, requires `wandb` to be initialized.""" if self.wandb: wandb.run.config.update(params, allow_val_change=True) def log_tensorboard_graph(tb, model, imgsz=(640, 640)): - # Log model graph to TensorBoard + """Logs a model graph to TensorBoard using an all-zero input image of shape `(1, 3, imgsz, imgsz)`.""" try: p = next(model.parameters()) # for device, type imgsz = (imgsz, imgsz) if isinstance(imgsz, int) else imgsz # expand @@ -398,7 +420,9 @@ def log_tensorboard_graph(tb, model, imgsz=(640, 640)): def web_project_name(project): - # Convert local project name to web project name + """Converts local project name to a web-friendly format by adding a suffix based on its type (classify or + segment). + """ if not project.startswith("runs/train"): return project suffix = "-Classify" if project.endswith("-cls") else "-Segment" if project.endswith("-seg") else "" diff --git a/utils/loggers/comet/__init__.py b/utils/loggers/comet/__init__.py index f1d355d290..74f763a7dc 100644 --- a/utils/loggers/comet/__init__.py +++ b/utils/loggers/comet/__init__.py @@ -165,6 +165,9 @@ def __init__(self, opt, hyp, run_id=None, job_type="Training", **experiment_kwar self.experiment.log_other("optimizer_parameters", json.dumps(self.hyp)) def _get_experiment(self, mode, experiment_id=None): + """Returns a comet_ml Experiment object, either online or offline, existing or new, based on mode and + experiment_id. + """ if mode == "offline": return ( comet_ml.ExistingOfflineExperiment( @@ -197,21 +200,29 @@ def _get_experiment(self, mode, experiment_id=None): return def log_metrics(self, log_dict, **kwargs): + """Logs metrics to the current experiment using a dictionary of metric names and values.""" self.experiment.log_metrics(log_dict, **kwargs) def log_parameters(self, log_dict, **kwargs): + """Logs parameters to the current experiment using a dictionary of parameter names and values.""" self.experiment.log_parameters(log_dict, **kwargs) def log_asset(self, asset_path, **kwargs): + """Logs a file or directory at `asset_path` to the current experiment, supporting additional `kwargs`.""" self.experiment.log_asset(asset_path, **kwargs) def log_asset_data(self, asset, **kwargs): + """Logs binary asset data to the current experiment, supporting additional `kwargs`.""" self.experiment.log_asset_data(asset, **kwargs) def log_image(self, img, **kwargs): + """Logs an image to the current experiment with optional `kwargs` for additional parameters.""" self.experiment.log_image(img, **kwargs) def log_model(self, path, opt, epoch, fitness_score, best_model=False): + """Logs a model's state at a given epoch, fitness, and optionality as best, requiring path, options, epoch, and + fitness score. + """ if not self.save_model: return @@ -235,6 +246,7 @@ def log_model(self, path, opt, epoch, fitness_score, best_model=False): ) def check_dataset(self, data_file): + """Loads and validates the dataset configuration from a YAML file.""" with open(data_file) as f: data_config = yaml.safe_load(f) @@ -247,6 +259,7 @@ def check_dataset(self, data_file): return check_dataset(data_file) def log_predictions(self, image, labelsn, path, shape, predn): + """Logs filtered predictions with IoU above a threshold, discarding if max image log count reached.""" if self.logged_images_count >= self.max_images: return detections = predn[predn[:, 4] > self.conf_thres] @@ -287,6 +300,9 @@ def log_predictions(self, image, labelsn, path, shape, predn): return def preprocess_prediction(self, image, labels, shape, pred): + """Preprocesses predictions by adjusting label and prediction shapes; `image`: input image, `labels`: true + labels, `shape`: image shape, `pred`: model predictions. + """ nl, _ = labels.shape[0], pred.shape[0] # Predictions @@ -306,6 +322,7 @@ def preprocess_prediction(self, image, labels, shape, pred): return predn, labelsn def add_assets_to_artifact(self, artifact, path, asset_path, split): + """Adds asset images and labels from `asset_path` to `artifact` by `split`, ensuring paths are sorted.""" img_paths = sorted(glob.glob(f"{asset_path}/*")) label_paths = img2label_paths(img_paths) @@ -331,6 +348,7 @@ def add_assets_to_artifact(self, artifact, path, asset_path, split): return artifact def upload_dataset_artifact(self): + """Uploads dataset to Comet as an artifact with optional custom dataset name, defaulting to 'yolov5-dataset'.""" dataset_name = self.data_dict.get("dataset_name", "yolov5-dataset") path = str((ROOT / Path(self.data_dict["path"])).resolve()) @@ -355,6 +373,7 @@ def upload_dataset_artifact(self): return def download_dataset_artifact(self, artifact_path): + """Downloads a dataset artifact to a specified directory, given its path.""" logged_artifact = self.experiment.get_artifact(artifact_path) artifact_save_dir = str(Path(self.opt.save_dir) / logged_artifact.name) logged_artifact.download(artifact_save_dir) @@ -374,6 +393,7 @@ def download_dataset_artifact(self, artifact_path): return self.update_data_paths(data_dict) def update_data_paths(self, data_dict): + """Updates 'path' in data_dict with provided path, returning modified data_dict.""" path = data_dict.get("path", "") for split in ["train", "val", "test"]: @@ -386,6 +406,7 @@ def update_data_paths(self, data_dict): return data_dict def on_pretrain_routine_end(self, paths): + """Called at the end of the pretraining routine to handle paths modification if `opt.resume` is False.""" if self.opt.resume: return @@ -398,20 +419,25 @@ def on_pretrain_routine_end(self, paths): return def on_train_start(self): + """Logs hyperparameter settings at the start of training.""" self.log_parameters(self.hyp) def on_train_epoch_start(self): + """Callback function executed at the start of each training epoch.""" return def on_train_epoch_end(self, epoch): + """Callback function executed at the end of each training epoch, updates current epoch in experiment.""" self.experiment.curr_epoch = epoch return def on_train_batch_start(self): + """Callback executed at the start of each training batch without inputs or modifications.""" return def on_train_batch_end(self, log_dict, step): + """Callback after training batch ends; updates step and logs metrics if conditions met.""" self.experiment.curr_step = step if self.log_batch_metrics and (step % self.comet_log_batch_interval == 0): self.log_metrics(log_dict, step=step) @@ -419,6 +445,7 @@ def on_train_batch_end(self, log_dict, step): return def on_train_end(self, files, save_dir, last, best, epoch, results): + """Callback at training end; logs image metadata to Comet if comet_log_predictions is True.""" if self.comet_log_predictions: curr_epoch = self.experiment.curr_epoch self.experiment.log_asset_data(self.metadata_dict, "image-metadata.json", epoch=curr_epoch) @@ -446,12 +473,15 @@ def on_train_end(self, files, save_dir, last, best, epoch, results): self.finish_run() def on_val_start(self): + """Prepares environment for validation phase.""" return def on_val_batch_start(self): + """Called at the start of each validation batch to prepare the batch environment.""" return def on_val_batch_end(self, batch_i, images, targets, paths, shapes, outputs): + """Handles end of validation batch, optionally logs predictions to Comet.ml if conditions met.""" if not (self.comet_log_predictions and ((batch_i + 1) % self.comet_log_prediction_interval == 0)): return @@ -470,6 +500,9 @@ def on_val_batch_end(self, batch_i, images, targets, paths, shapes, outputs): return def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix): + """Logs per-class metric stats to Comet.ml at validation end; requires class-wise tp, fp, nt, p, r, f1, ap, + ap50, ap_class, confusion_matrix. + """ if self.comet_log_per_class_metrics and self.num_classes > 1: for i, c in enumerate(ap_class): class_name = self.class_names[c] @@ -504,14 +537,18 @@ def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) ) def on_fit_epoch_end(self, result, epoch): + """Logs metrics at the end of each training epoch with provided result and epoch number.""" self.log_metrics(result, epoch=epoch) def on_model_save(self, last, epoch, final_epoch, best_fitness, fi): + """Logs and saves model periodically if conditions met, excluding final epoch unless best fitness achieved.""" if ((epoch + 1) % self.opt.save_period == 0 and not final_epoch) and self.opt.save_period != -1: self.log_model(last.parent, self.opt, epoch, fi, best_model=best_fitness == fi) def on_params_update(self, params): + """Updates and logs model parameters.""" self.log_parameters(params) def finish_run(self): + """Terminates the current experiment and performs necessary cleanup operations.""" self.experiment.end() diff --git a/utils/loggers/comet/comet_utils.py b/utils/loggers/comet/comet_utils.py index afa5964645..f78c397c1e 100644 --- a/utils/loggers/comet/comet_utils.py +++ b/utils/loggers/comet/comet_utils.py @@ -17,6 +17,7 @@ def download_model_checkpoint(opt, experiment): + """Downloads the model checkpoint from Comet ML; updates `opt.weights` with the downloaded file path.""" model_dir = f"{opt.project}/{experiment.name}" os.makedirs(model_dir, exist_ok=True) diff --git a/utils/loggers/comet/hpo.py b/utils/loggers/comet/hpo.py index 943bd47e00..afcafa8df5 100644 --- a/utils/loggers/comet/hpo.py +++ b/utils/loggers/comet/hpo.py @@ -25,6 +25,7 @@ def get_args(known=False): + """Parses command line arguments for configuring training options, supporting Comet and W&B integrations.""" parser = argparse.ArgumentParser() parser.add_argument("--weights", type=str, default=ROOT / "yolov3-tiny.pt", help="initial weights path") parser.add_argument("--cfg", type=str, default="", help="model.yaml path") @@ -83,6 +84,9 @@ def get_args(known=False): def run(parameters, opt): + """Executes training process with given hyperparameters and options, handling device selection and callback + initialization. + """ hyp_dict = {k: v for k, v in parameters.items() if k not in ["epochs", "batch_size"]} opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok or opt.evolve)) diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py index 04f19ef8e6..b24d797016 100644 --- a/utils/loggers/wandb/wandb_utils.py +++ b/utils/loggers/wandb/wandb_utils.py @@ -152,6 +152,7 @@ def log_model(self, path, opt, epoch, fitness_score, best_model=False): LOGGER.info(f"Saving model artifact on epoch {epoch + 1}") def val_one_image(self, pred, predn, path, names, im): + """Evaluates model's prediction for a single image, updating metrics based on comparison with ground truth.""" pass def log(self, log_dict): @@ -178,7 +179,7 @@ def end_epoch(self): wandb.log(self.log_dict) except BaseException as e: LOGGER.info( - f"An error occurred in wandb logger. The training will proceed without interruption. More info\n{e}" + f"An error occurred in wandb. The training will proceed without interruption. More info\n{e}" ) self.wandb_run.finish() self.wandb_run = None diff --git a/utils/loss.py b/utils/loss.py index d533246e60..c805e7a2bd 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -9,18 +9,22 @@ def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 - # return positive, negative label smoothing BCE targets + """Applies label smoothing to BCE targets, returning smoothed positive/negative labels; eps default is 0.1.""" return 1.0 - 0.5 * eps, 0.5 * eps class BCEBlurWithLogitsLoss(nn.Module): # BCEwithLogitLoss() with reduced missing label effects. def __init__(self, alpha=0.05): + """Initializes BCEBlurWithLogitsLoss with alpha to reduce missing label effects; default alpha is 0.05.""" super().__init__() self.loss_fcn = nn.BCEWithLogitsLoss(reduction="none") # must be nn.BCEWithLogitsLoss() self.alpha = alpha def forward(self, pred, true): + """Calculates modified BCEWithLogitsLoss factoring in missing labels, taking `pred` logits and `true` labels as + inputs. + """ loss = self.loss_fcn(pred, true) pred = torch.sigmoid(pred) # prob from logits dx = pred - true # reduce only missing label effects @@ -33,6 +37,9 @@ def forward(self, pred, true): class FocalLoss(nn.Module): # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): + """Initializes FocalLoss with specified loss function, gamma, and alpha for enhanced training on imbalanced + datasets. + """ super().__init__() self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() self.gamma = gamma @@ -41,6 +48,9 @@ def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): self.loss_fcn.reduction = "none" # required to apply FL to each element def forward(self, pred, true): + """Computes the focal loss between `pred` and `true` using specific alpha and gamma, not applying the modulating + factor. + """ loss = self.loss_fcn(pred, true) # p_t = torch.exp(-loss) # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability @@ -63,6 +73,9 @@ def forward(self, pred, true): class QFocalLoss(nn.Module): # Wraps Quality focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): + """Initializes QFocalLoss with specified loss function, gamma, and alpha for element-wise focal loss + application. + """ super().__init__() self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() self.gamma = gamma @@ -71,6 +84,9 @@ def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): self.loss_fcn.reduction = "none" # required to apply FL to each element def forward(self, pred, true): + """Computes focal loss between predictions and true labels using configured loss function, `gamma`, and + `alpha`. + """ loss = self.loss_fcn(pred, true) pred_prob = torch.sigmoid(pred) # prob from logits @@ -91,6 +107,7 @@ class ComputeLoss: # Compute losses def __init__(self, model, autobalance=False): + """Initializes ComputeLoss with model's device and hyperparameters, and sets autobalance.""" device = next(model.parameters()).device # get model device h = model.hyp # hyperparameters @@ -117,6 +134,7 @@ def __init__(self, model, autobalance=False): self.device = device def __call__(self, p, targets): # predictions, targets + """Computes loss given predictions and targets, returning class, box, and object loss as tensors.""" lcls = torch.zeros(1, device=self.device) # class loss lbox = torch.zeros(1, device=self.device) # box loss lobj = torch.zeros(1, device=self.device) # object loss @@ -173,7 +191,9 @@ def __call__(self, p, targets): # predictions, targets return (lbox + lobj + lcls) * bs, torch.cat((lbox, lobj, lcls)).detach() def build_targets(self, p, targets): - # Build targets for compute_loss(), input targets(image,class,x,y,w,h) + """Generates matching anchor targets for compute_loss() from given images and labels in format + (image,class,x,y,w,h). + """ na, nt = self.na, targets.shape[0] # number of anchors, targets tcls, tbox, indices, anch = [], [], [], [] gain = torch.ones(7, device=self.device) # normalized to gridspace gain diff --git a/utils/metrics.py b/utils/metrics.py index 626c290186..540ad2c969 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -13,13 +13,13 @@ def fitness(x): - # Model fitness as a weighted combination of metrics + """Calculates model fitness as a weighted sum of metrics [P, R, mAP@0.5, mAP@0.5:0.95] with respective weights.""" w = [0.0, 0.0, 0.1, 0.9] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] return (x[:, :4] * w).sum(1) def smooth(y, f=0.05): - # Box filter of fraction f + """Smooths array `y` using a box filter with fractional size `f`, returning the smoothed array.""" nf = round(len(y) * f * 2) // 2 + 1 # number of filter elements (must be odd) p = np.ones(nf // 2) # ones padding yp = np.concatenate((p * y[0], y, p * y[-1]), 0) # y padded @@ -126,6 +126,7 @@ def compute_ap(recall, precision): class ConfusionMatrix: # Updated version of https://github.com/kaanakan/object_detection_confusion_matrix def __init__(self, nc, conf=0.25, iou_thres=0.45): + """Initializes confusion matrix for object detection with adjustable confidence and IoU thresholds.""" self.matrix = np.zeros((nc + 1, nc + 1)) self.nc = nc # number of classes self.conf = conf @@ -179,6 +180,7 @@ def process_batch(self, detections, labels): self.matrix[dc, self.nc] += 1 # predicted background def tp_fp(self): + """Computes true positives and false positives, excluding the background class, from a confusion matrix.""" tp = self.matrix.diagonal() # true positives fp = self.matrix.sum(1) - tp # false positives # fn = self.matrix.sum(0) - tp # false negatives (missed detections) @@ -186,6 +188,7 @@ def tp_fp(self): @TryExcept("WARNING ⚠️ ConfusionMatrix plot failure") def plot(self, normalize=True, save_dir="", names=()): + """Plots confusion matrix as a heatmap; args: normalize(bool), save_dir(str), names(iterable of str).""" import seaborn as sn array = self.matrix / ((self.matrix.sum(0).reshape(1, -1) + 1e-9) if normalize else 1) # normalize columns @@ -217,12 +220,13 @@ def plot(self, normalize=True, save_dir="", names=()): plt.close(fig) def print(self): + """Prints each row of the confusion matrix, where matrix elements are separated by spaces.""" for i in range(self.nc + 1): print(" ".join(map(str, self.matrix[i]))) def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7): - # Returns Intersection over Union (IoU) of box1(1,4) to box2(n,4) + """Calculates IoU, GIoU, DIoU, CIoU between two bounding boxes, supporting `xywh` and `xyxy` formats.""" # Get the coordinates of bounding boxes if xywh: # transform from xywh to xyxy @@ -312,7 +316,7 @@ def bbox_ioa(box1, box2, eps=1e-7): def wh_iou(wh1, wh2, eps=1e-7): - # Returns the nxm IoU matrix. wh1 is nx2, wh2 is mx2 + """Calculates the IoU of width-height pairs, wh1[n,2] and wh2[m,2], returning an nxm IoU matrix.""" wh1 = wh1[:, None] # [N,1,2] wh2 = wh2[None] # [1,M,2] inter = torch.min(wh1, wh2).prod(2) # [N,M] @@ -324,7 +328,9 @@ def wh_iou(wh1, wh2, eps=1e-7): @threaded def plot_pr_curve(px, py, ap, save_dir=Path("pr_curve.png"), names=()): - # Precision-recall curve + """Plots precision-recall curve, supports per-class curves if < 21 classes; args: px (recall), py (precision list), + ap (APs), save_dir, names. + """ fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True) py = np.stack(py, axis=1) @@ -347,7 +353,9 @@ def plot_pr_curve(px, py, ap, save_dir=Path("pr_curve.png"), names=()): @threaded def plot_mc_curve(px, py, save_dir=Path("mc_curve.png"), names=(), xlabel="Confidence", ylabel="Metric"): - # Metric-confidence curve + """Plots metric-confidence curve for given classes; px, py shapes (N,), (C, N); save_dir: str or Path; names: tuple + of class names. + """ fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True) if 0 < len(names) < 21: # display per-class legend if < 21 classes diff --git a/utils/plots.py b/utils/plots.py index a089a8d6d6..6c4af5b3b8 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -31,7 +31,7 @@ class Colors: # Ultralytics color palette https://ultralytics.com/ def __init__(self): - # hex = matplotlib.colors.TABLEAU_COLORS.values() + """Initializes the Colors class with a palette from the Ultralytics color palette.""" hexs = ( "FF3838", "FF9D97", @@ -58,11 +58,13 @@ def __init__(self): self.n = len(self.palette) def __call__(self, i, bgr=False): + """Converts index `i` to a color from predefined palette, returning in BGR format if `bgr` is True, else RGB.""" c = self.palette[int(i) % self.n] return (c[2], c[1], c[0]) if bgr else c @staticmethod def hex2rgb(h): # rgb order (PIL) + """Converts hexadecimal color `h` to RGB tuple; `h` format should be '#RRGGBB'.""" return tuple(int(h[1 + i : 1 + i + 2], 16) for i in (0, 2, 4)) @@ -98,7 +100,7 @@ def feature_visualization(x, module_type, stage, n=32, save_dir=Path("runs/detec def hist2d(x, y, n=100): - # 2d histogram used in labels.png and evolve.png + """Generates a 2D log-scaled histogram from input arrays `x` and `y`, with `n` bins for each axis.""" xedges, yedges = np.linspace(x.min(), x.max(), n), np.linspace(y.min(), y.max(), n) hist, xedges, yedges = np.histogram2d(x, y, (xedges, yedges)) xidx = np.clip(np.digitize(x, xedges) - 1, 0, hist.shape[0] - 1) @@ -107,6 +109,11 @@ def hist2d(x, y, n=100): def butter_lowpass_filtfilt(data, cutoff=1500, fs=50000, order=5): + """ + Applies a low-pass Butterworth filter using forward-backward method. + + See: https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy + """ from scipy.signal import butter, filtfilt # https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy @@ -120,7 +127,9 @@ def butter_lowpass(cutoff, fs, order): def output_to_target(output, max_det=300): - # Convert model output to target format [batch_id, class_id, x, y, w, h, conf] for plotting + """Converts model output to [batch_id, class_id, x, y, w, h, conf] format for plotting, handling up to `max_det` + detections. + """ targets = [] for i, o in enumerate(output): box, conf, cls = o[:max_det, :6].cpu().split((4, 1, 1), 1) @@ -131,7 +140,7 @@ def output_to_target(output, max_det=300): @threaded def plot_images(images, targets, paths=None, fname="images.jpg", names=None): - # Plot image grid with labels + """Plots a grid of images with labels, optionally resizing and annotating with target boxes and names.""" if isinstance(images, torch.Tensor): images = images.cpu().float().numpy() if isinstance(targets, torch.Tensor): @@ -195,7 +204,7 @@ def plot_images(images, targets, paths=None, fname="images.jpg", names=None): def plot_lr_scheduler(optimizer, scheduler, epochs=300, save_dir=""): - # Plot LR simulating training for full epochs + """Simulates and plots LR schedule over epochs, saving figure to `save_dir`.""" optimizer, scheduler = copy(optimizer), copy(scheduler) # do not modify originals y = [] for _ in range(epochs): @@ -212,7 +221,7 @@ def plot_lr_scheduler(optimizer, scheduler, epochs=300, save_dir=""): def plot_val_txt(): # from utils.plots import *; plot_val() - # Plot val.txt histograms + """Plots 2D and 1D histograms of object center locations from 'val.txt', saving as 'hist2d.png' and 'hist1d.png'.""" x = np.loadtxt("val.txt", dtype=np.float32) box = xyxy2xywh(x[:, :4]) cx, cy = box[:, 0], box[:, 1] @@ -229,7 +238,7 @@ def plot_val_txt(): # from utils.plots import *; plot_val() def plot_targets_txt(): # from utils.plots import *; plot_targets_txt() - # Plot targets.txt histograms + """Plots histograms for target attributes from 'targets.txt' and saves as 'targets.jpg'.""" x = np.loadtxt("targets.txt", dtype=np.float32).T s = ["x targets", "y targets", "width targets", "height targets"] fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) @@ -242,7 +251,7 @@ def plot_targets_txt(): # from utils.plots import *; plot_targets_txt() def plot_val_study(file="", dir="", x=None): # from utils.plots import *; plot_val_study() - # Plot file=study.txt generated by val.py (or plot all study*.txt in dir) + """Plots validation study results from 'study*.txt' files, comparing model performance and speed.""" save_dir = Path(file).parent if file else Path(dir) plot2 = False # plot additional results if plot2: @@ -293,7 +302,7 @@ def plot_val_study(file="", dir="", x=None): # from utils.plots import *; plot_ @TryExcept() # known issue https://github.com/ultralytics/yolov5/issues/5395 def plot_labels(labels, names=(), save_dir=Path("")): - # plot dataset labels + """Plots dataset labels correlogram, class distribution, and label geometry; saves to `save_dir`.""" LOGGER.info(f"Plotting labels to {save_dir / 'labels.jpg'}... ") c, b = labels[:, 0], labels[:, 1:].transpose() # classes, boxes nc = int(c.max() + 1) # number of classes @@ -338,7 +347,7 @@ def plot_labels(labels, names=(), save_dir=Path("")): def imshow_cls(im, labels=None, pred=None, names=None, nmax=25, verbose=False, f=Path("images.jpg")): - # Show classification image grid with labels (optional) and predictions (optional) + """Displays a grid of classification images with optional labels and predictions, saving to file.""" from utils.augmentations import denormalize names = names or [f"class{i}" for i in range(1000)] @@ -368,7 +377,7 @@ def imshow_cls(im, labels=None, pred=None, names=None, nmax=25, verbose=False, f def plot_evolve(evolve_csv="path/to/evolve.csv"): # from utils.plots import *; plot_evolve() - # Plot evolve.csv hyp evolution results + """Plots evolution of hyperparameters from a CSV file, highlighting best results.""" evolve_csv = Path(evolve_csv) data = pd.read_csv(evolve_csv) keys = [x.strip() for x in data.columns] @@ -395,7 +404,7 @@ def plot_evolve(evolve_csv="path/to/evolve.csv"): # from utils.plots import *; def plot_results(file="path/to/results.csv", dir=""): - # Plot training results.csv. Usage: from utils.plots import *; plot_results('path/to/results.csv') + """Plots training results from 'results.csv'; usage: `plot_results('path/to/results.csv')`.""" save_dir = Path(file).parent if file else Path(dir) fig, ax = plt.subplots(2, 5, figsize=(12, 6), tight_layout=True) ax = ax.ravel() @@ -422,7 +431,9 @@ def plot_results(file="path/to/results.csv", dir=""): def profile_idetection(start=0, stop=0, labels=(), save_dir=""): - # Plot iDetection '*.txt' per-image logs. from utils.plots import *; profile_idetection() + """Plots iDetection per-image logs from '*.txt', including metrics like storage and FPS; pass start, stop times, + labels, and save_dir. + """ ax = plt.subplots(2, 4, figsize=(12, 6), tight_layout=True)[1].ravel() s = ["Images", "Free Storage (GB)", "RAM Usage (GB)", "Battery", "dt_raw (ms)", "dt_smooth (ms)", "real-world FPS"] files = list(Path(save_dir).glob("frames*.txt")) @@ -453,7 +464,9 @@ def profile_idetection(start=0, stop=0, labels=(), save_dir=""): def save_one_box(xyxy, im, file=Path("im.jpg"), gain=1.02, pad=10, square=False, BGR=False, save=True): - # Save image crop as {file} with crop size multiple {gain} and {pad} pixels. Save and/or return crop + """Saves/enhances a crop from `im` defined by `xyxy` to `file` or returns it; customizable with `gain`, `pad`, + `square`, `BGR`. + """ xyxy = torch.tensor(xyxy).view(-1, 4) b = xyxy2xywh(xyxy) # boxes if square: diff --git a/utils/segment/augmentations.py b/utils/segment/augmentations.py index f3074d1cdd..96047663d7 100644 --- a/utils/segment/augmentations.py +++ b/utils/segment/augmentations.py @@ -12,7 +12,8 @@ def mixup(im, labels, segments, im2, labels2, segments2): - # Applies MixUp augmentation https://arxiv.org/pdf/1710.09412.pdf + """Applies MixUp augmentation by blending pairs of images, labels, and segments; see + https://arxiv.org/pdf/1710.09412.pdf.""" r = np.random.beta(32.0, 32.0) # mixup ratio, alpha=beta=32.0 im = (im * r + im2 * (1 - r)).astype(np.uint8) labels = np.concatenate((labels, labels2), 0) diff --git a/utils/segment/dataloaders.py b/utils/segment/dataloaders.py index 2fa37be554..6cdf6ad982 100644 --- a/utils/segment/dataloaders.py +++ b/utils/segment/dataloaders.py @@ -118,6 +118,7 @@ def __init__( self.overlap = overlap def __getitem__(self, index): + """Fetches the dataset item at a given index, handling linear, shuffled, or image-weighted indexing.""" index = self.indices[index] # linear, shuffled, or image_weights hyp = self.hyp @@ -225,7 +226,9 @@ def __getitem__(self, index): return (torch.from_numpy(img), labels_out, self.im_files[index], shapes, masks) def load_mosaic(self, index): - # YOLOv3 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic + """Loads 4-image mosaic for YOLOv3 training, combining 1 target image with 3 random images within specified + border constraints. + """ labels4, segments4 = [], [] s = self.img_size yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y @@ -286,6 +289,7 @@ def load_mosaic(self, index): @staticmethod def collate_fn(batch): + """Batches images, labels, paths, shapes, and masks; modifies label indices for target image association.""" img, label, path, shapes, masks = zip(*batch) # transposed batched_masks = torch.cat(masks, 0) for i, l in enumerate(label): diff --git a/utils/segment/general.py b/utils/segment/general.py index 8cbc745b4a..14ef9e7132 100644 --- a/utils/segment/general.py +++ b/utils/segment/general.py @@ -144,7 +144,9 @@ def masks_iou(mask1, mask2, eps=1e-7): def masks2segments(masks, strategy="largest"): - # Convert masks(n,160,160) into segments(n,xy) + """Converts binary masks to polygon segments with 'largest' or 'concat' strategies, returning lists of (n,xy) + coordinates. + """ segments = [] for x in masks.int().cpu().numpy().astype("uint8"): c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0] diff --git a/utils/segment/loss.py b/utils/segment/loss.py index 1e007271fa..f9533813eb 100644 --- a/utils/segment/loss.py +++ b/utils/segment/loss.py @@ -12,6 +12,7 @@ class ComputeLoss: # Compute losses def __init__(self, model, autobalance=False, overlap=False): + """Initializes ComputeLoss with model settings, optional autobalancing, and overlap handling.""" self.sort_obj_iou = False self.overlap = overlap device = next(model.parameters()).device # get model device @@ -41,6 +42,9 @@ def __init__(self, model, autobalance=False, overlap=False): self.device = device def __call__(self, preds, targets, masks): # predictions, targets, model + """Computes losses given predictions, targets, and masks; returns tuple of class, box, object, and segmentation + losses. + """ p, proto = preds bs, nm, mask_h, mask_w = proto.shape # batch size, number of masks, mask height, mask width lcls = torch.zeros(1, device=self.device) @@ -109,13 +113,19 @@ def __call__(self, preds, targets, masks): # predictions, targets, model return loss * bs, torch.cat((lbox, lseg, lobj, lcls)).detach() def single_mask_loss(self, gt_mask, pred, proto, xyxy, area): - # Mask loss for one image + """ + Computes single image mask loss using BCE, cropping based on bbox. + + Args: gt_mask[n,h,w], pred[n,nm], proto[nm,h,w], xyxy[n,4], area[n]. + """ pred_mask = (pred @ proto.view(self.nm, -1)).view(-1, *proto.shape[1:]) # (n,32) @ (32,80,80) -> (n,80,80) loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction="none") return (crop_mask(loss, xyxy).mean(dim=(1, 2)) / area).mean() def build_targets(self, p, targets): - # Build targets for compute_loss(), input targets(image,class,x,y,w,h) + """Prepares targets for loss computation by appending anchor indices; supports optional target overlap + handling. + """ na, nt = self.na, targets.shape[0] # number of anchors, targets tcls, tbox, indices, anch, tidxs, xywhn = [], [], [], [], [], [] gain = torch.ones(8, device=self.device) # normalized to gridspace gain diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py index f85baebacd..cb74f5cb07 100644 --- a/utils/segment/metrics.py +++ b/utils/segment/metrics.py @@ -7,7 +7,7 @@ def fitness(x): - # Model fitness as a weighted combination of metrics + """Calculates model fitness as a weighted sum of 8 metrics, where `x` is an array of shape [N, 8].""" w = [0.0, 0.0, 0.1, 0.9, 0.0, 0.0, 0.1, 0.9] return (x[:, :8] * w).sum(1) @@ -128,6 +128,9 @@ def class_result(self, i): return (self.p[i], self.r[i], self.ap50[i], self.ap[i]) def get_maps(self, nc): + """Calculates mean average precisions (mAPs) for each class; `nc`: num of classes; returns array of mAPs per + class. + """ maps = np.zeros(nc) + self.map for i, c in enumerate(self.ap_class_index): maps[c] = self.ap[i] @@ -162,17 +165,20 @@ def update(self, results): self.metric_mask.update(list(results["masks"].values())) def mean_results(self): + """Calculates and returns the sum of mean results from 'metric_box' and 'metric_mask'.""" return self.metric_box.mean_results() + self.metric_mask.mean_results() def class_result(self, i): + """Combines and returns class-specific results from 'metric_box' and 'metric_mask' for class index 'i'.""" return self.metric_box.class_result(i) + self.metric_mask.class_result(i) def get_maps(self, nc): + """Returns combined mean Average Precision (mAP) scores for bounding boxes and masks for `nc` classes.""" return self.metric_box.get_maps(nc) + self.metric_mask.get_maps(nc) @property def ap_class_index(self): - # boxes and masks have the same ap_class_index + """Returns the AP class index, identical for both boxes and masks.""" return self.metric_box.ap_class_index diff --git a/utils/segment/plots.py b/utils/segment/plots.py index 0e30c61be6..b0c8bee6be 100644 --- a/utils/segment/plots.py +++ b/utils/segment/plots.py @@ -15,7 +15,7 @@ @threaded def plot_images_and_masks(images, targets, masks, paths=None, fname="images.jpg", names=None): - # Plot image grid with labels + """Plots a grid of images with annotations and masks, optionally resizing and saving the result.""" if isinstance(images, torch.Tensor): images = images.cpu().float().numpy() if isinstance(targets, torch.Tensor): @@ -111,7 +111,9 @@ def plot_images_and_masks(images, targets, masks, paths=None, fname="images.jpg" def plot_results_with_masks(file="path/to/results.csv", dir="", best=True): - # Plot training results.csv. Usage: from utils.plots import *; plot_results('path/to/results.csv') + """Plots training results from CSV, highlighting best/last metrics; supports custom file paths and directory + saving. + """ save_dir = Path(file).parent if file else Path(dir) fig, ax = plt.subplots(2, 8, figsize=(18, 6), tight_layout=True) ax = ax.ravel() diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 000b77b37c..a41327f0bf 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -34,7 +34,8 @@ def smart_inference_mode(torch_1_9=check_version(torch.__version__, "1.9.0")): - # Applies torch.inference_mode() decorator if torch>=1.9.0 else torch.no_grad() decorator + """Applies torch.inference_mode() if torch>=1.9.0 or torch.no_grad() otherwise as a decorator to functions.""" + def decorate(fn): return (torch.inference_mode if torch_1_9 else torch.no_grad)()(fn) @@ -42,7 +43,9 @@ def decorate(fn): def smartCrossEntropyLoss(label_smoothing=0.0): - # Returns nn.CrossEntropyLoss with label smoothing enabled for torch>=1.10.0 + """Returns CrossEntropyLoss with optional label smoothing for torch>=1.10.0; warns if label smoothing used with + older versions. + """ if check_version(torch.__version__, "1.10.0"): return nn.CrossEntropyLoss(label_smoothing=label_smoothing) if label_smoothing > 0: @@ -51,7 +54,11 @@ def smartCrossEntropyLoss(label_smoothing=0.0): def smart_DDP(model): - # Model DDP creation with checks + """ + Initializes DDP for a model with version checks; fails for torch==1.12.0 due to known issues. + + See https://github.com/ultralytics/yolov5/issues/8395. + """ assert not check_version(torch.__version__, "1.12.0", pinned=True), ( "torch==1.12.0 torchvision==0.13.0 DDP training is not supported due to a known issue. " "Please upgrade or downgrade torch to use DDP. See https://github.com/ultralytics/yolov5/issues/8395" @@ -63,7 +70,9 @@ def smart_DDP(model): def reshape_classifier_output(model, n=1000): - # Update a TorchVision classification model to class count 'n' if required + """Reshapes the last layer of a model to have 'n' outputs; supports YOLOv3, ResNet, EfficientNet, adjusting Linear + and Conv2d layers. + """ from models.common import Classify name, m = list((model.model if hasattr(model, "model") else model).named_children())[-1] # last module @@ -87,7 +96,7 @@ def reshape_classifier_output(model, n=1000): @contextmanager def torch_distributed_zero_first(local_rank: int): - # Decorator to make all processes in distributed training wait for each local_master to do something + """Context manager ensuring ordered execution in distributed training by synchronizing local masters first.""" if local_rank not in [-1, 0]: dist.barrier(device_ids=[local_rank]) yield @@ -96,7 +105,7 @@ def torch_distributed_zero_first(local_rank: int): def device_count(): - # Returns number of CUDA devices available. Safe version of torch.cuda.device_count(). Supports Linux and Windows + """Returns the count of available CUDA devices; supports Linux and Windows, using nvidia-smi.""" assert platform.system() in ("Linux", "Windows"), "device_count() only supported on Linux or Windows" try: cmd = "nvidia-smi -L | wc -l" if platform.system() == "Linux" else 'nvidia-smi -L | find /c /v ""' # Windows @@ -106,7 +115,7 @@ def device_count(): def select_device(device="", batch_size=0, newline=True): - # device = None or 'cpu' or 0 or '0' or '0,1,2,3' + """Selects the device for running models, handling CPU, GPU, and MPS with optional batch size divisibility check.""" s = f"YOLOv3 🚀 {git_describe() or file_date()} Python-{platform.python_version()} torch-{torch.__version__} " device = str(device).strip().lower().replace("cuda:", "").replace("none", "") # to string, 'cuda:0' to '0' cpu = device == "cpu" @@ -143,7 +152,7 @@ def select_device(device="", batch_size=0, newline=True): def time_sync(): - # PyTorch-accurate time + """Synchronizes PyTorch across available CUDA devices and returns current time in seconds.""" if torch.cuda.is_available(): torch.cuda.synchronize() return time.time() @@ -203,16 +212,19 @@ def profile(input, ops, n=10, device=None): def is_parallel(model): - # Returns True if model is of type DP or DDP + """Checks if a model is using DataParallel (DP) or DistributedDataParallel (DDP).""" return type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) def de_parallel(model): - # De-parallelize a model: returns single-GPU model if model is of type DP or DDP + """Returns a single-GPU model if input model is using DataParallel (DP) or DistributedDataParallel (DDP).""" return model.module if is_parallel(model) else model def initialize_weights(model): + """Initializes weights for Conv2D, BatchNorm2d, and activation layers (Hardswish, LeakyReLU, ReLU, ReLU6, SiLU) in a + model. + """ for m in model.modules(): t = type(m) if t is nn.Conv2d: @@ -225,12 +237,14 @@ def initialize_weights(model): def find_modules(model, mclass=nn.Conv2d): - # Finds layer indices matching module class 'mclass' + """Finds indices of layers in 'model' matching 'mclass'; default searches for 'nn.Conv2d'.""" return [i for i, m in enumerate(model.module_list) if isinstance(m, mclass)] def sparsity(model): - # Return global model sparsity + """Calculates and returns the global sparsity of a model as the ratio of zero-valued parameters to total + parameters. + """ a, b = 0, 0 for p in model.parameters(): a += p.numel() @@ -239,7 +253,7 @@ def sparsity(model): def prune(model, amount=0.3): - # Prune model to requested global sparsity + """Prunes Conv2d layers in a model to a specified global sparsity using l1 unstructured pruning.""" import torch.nn.utils.prune as prune for name, m in model.named_modules(): @@ -250,7 +264,7 @@ def prune(model, amount=0.3): def fuse_conv_and_bn(conv, bn): - # Fuse Conv2d() and BatchNorm2d() layers https://tehnokv.com/posts/fusing-batchnorm-and-conv/ + """Fuses Conv2d and BatchNorm2d layers for efficiency; see https://tehnokv.com/posts/fusing-batchnorm-and-conv/.""" fusedconv = ( nn.Conv2d( conv.in_channels, @@ -280,7 +294,11 @@ def fuse_conv_and_bn(conv, bn): def model_info(model, verbose=False, imgsz=640): - # Model information. img_size may be int or list, i.e. img_size=640 or img_size=[640, 320] + """ + Prints model layers, parameters, gradients, and GFLOPs if verbose; handles various `imgsz`. + + Usage: model_info(model). + """ n_p = sum(x.numel() for x in model.parameters()) # number parameters n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients if verbose: @@ -307,7 +325,9 @@ def model_info(model, verbose=False, imgsz=640): def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416) - # Scales img(bs,3,y,x) by ratio constrained to gs-multiple + """Scales and optionally pads an image tensor to a specified ratio, maintaining its aspect ratio constrained by + `gs`. + """ if ratio == 1.0: return img h, w = img.shape[2:] @@ -319,7 +339,7 @@ def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416) def copy_attr(a, b, include=(), exclude=()): - # Copy attributes from b to a, options to only include [...] and to exclude [...] + """Copies attributes from object b to a, with options to include or exclude specific attributes.""" for k, v in b.__dict__.items(): if (len(include) and k not in include) or k.startswith("_") or k in exclude: continue @@ -328,7 +348,7 @@ def copy_attr(a, b, include=(), exclude=()): def smart_optimizer(model, name="Adam", lr=0.001, momentum=0.9, decay=1e-5): - # YOLOv3 3-param group optimizer: 0) weights with decay, 1) weights no decay, 2) biases no decay + """Initializes a smart optimizer for YOLOv3 with custom parameter groups for different weight decays and biases.""" g = [], [], [] # optimizer parameter groups bn = tuple(v for k, v in nn.__dict__.items() if "Norm" in k) # normalization layers, i.e. BatchNorm2d() for v in model.modules(): @@ -361,7 +381,11 @@ def smart_optimizer(model, name="Adam", lr=0.001, momentum=0.9, decay=1e-5): def smart_hub_load(repo="ultralytics/yolov5", model="yolov5s", **kwargs): - # YOLOv3 torch.hub.load() wrapper with smart error/issue handling + """ + Loads YOLO model from Ultralytics repo with smart error handling, supports `force_reload` on failure. + + See https://github.com/ultralytics/yolov5 + """ if check_version(torch.__version__, "1.9.1"): kwargs["skip_validation"] = True # validation causes GitHub API rate limit errors if check_version(torch.__version__, "1.12.0"): @@ -373,7 +397,9 @@ def smart_hub_load(repo="ultralytics/yolov5", model="yolov5s", **kwargs): def smart_resume(ckpt, optimizer, ema=None, weights="yolov5s.pt", epochs=300, resume=True): - # Resume training from a partially trained checkpoint + """Resumes or fine-tunes training from a checkpoint with optimizer and EMA support; updates epochs based on + progress. + """ best_fitness = 0.0 start_epoch = ckpt["epoch"] + 1 if ckpt["optimizer"] is not None: @@ -397,12 +423,16 @@ def smart_resume(ckpt, optimizer, ema=None, weights="yolov5s.pt", epochs=300, re class EarlyStopping: # YOLOv3 simple early stopper def __init__(self, patience=30): + """Initializes EarlyStopping to monitor training, halting if no improvement in 'patience' epochs, defaulting to + 30. + """ self.best_fitness = 0.0 # i.e. mAP self.best_epoch = 0 self.patience = patience or float("inf") # epochs to wait after fitness stops improving to stop self.possible_stop = False # possible stop may occur next epoch def __call__(self, epoch, fitness): + """Updates stopping criteria based on fitness; returns True to stop if no improvement in 'patience' epochs.""" if fitness >= self.best_fitness: # >= 0 to allow for early zero-fitness stage of training self.best_epoch = epoch self.best_fitness = fitness @@ -426,7 +456,9 @@ class ModelEMA: """ def __init__(self, model, decay=0.9999, tau=2000, updates=0): - # Create EMA + """Initializes EMA with model, optional decay (default 0.9999), tau (2000), and updates count, setting model to + eval mode. + """ self.ema = deepcopy(de_parallel(model)).eval() # FP32 EMA self.updates = updates # number of EMA updates self.decay = lambda x: decay * (1 - math.exp(-x / tau)) # decay exponential ramp (to help early epochs) @@ -434,7 +466,7 @@ def __init__(self, model, decay=0.9999, tau=2000, updates=0): p.requires_grad_(False) def update(self, model): - # Update EMA parameters + """Updates EMA parameters based on model weights, decay factor, and increment update count.""" self.updates += 1 d = self.decay(self.updates) @@ -446,5 +478,5 @@ def update(self, model): # assert v.dtype == msd[k].dtype == torch.float32, f'{k}: EMA {v.dtype} and model {msd[k].dtype} must be FP32' def update_attr(self, model, include=(), exclude=("process_group", "reducer")): - # Update EMA attributes + """Updates EMA attributes by copying from model, excluding 'process_group' and 'reducer' by default.""" copy_attr(self.ema, model, include, exclude) diff --git a/utils/triton.py b/utils/triton.py index f34ec0f323..3cb0cce869 100644 --- a/utils/triton.py +++ b/utils/triton.py @@ -71,6 +71,9 @@ def __call__(self, *args, **kwargs) -> typing.Union[torch.Tensor, typing.Tuple[t return result[0] if len(result) == 1 else result def _create_inputs(self, *args, **kwargs): + """Generates model inputs from args or kwargs, not allowing both; raises error if neither or both are + provided. + """ args_len, kwargs_len = len(args), len(kwargs) if not args_len and not kwargs_len: raise RuntimeError("No inputs provided.") diff --git a/val.py b/val.py index a0a740700b..39eaf56145 100644 --- a/val.py +++ b/val.py @@ -62,7 +62,9 @@ def save_one_txt(predn, save_conf, shape, file): - # Save one txt result + """Saves detection results in txt format; includes labels and optionally confidence scores if `save_conf` is + True. + """ gn = torch.tensor(shape)[[1, 0, 1, 0]] # normalization gain whwh for *xyxy, conf, cls in predn.tolist(): xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh @@ -72,7 +74,7 @@ def save_one_txt(predn, save_conf, shape, file): def save_one_json(predn, jdict, path, class_map): - # Save one JSON result {"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236} + """Saves detection results in JSON format containing image_id, category_id, bbox, and score per detection.""" image_id = int(path.stem) if path.stem.isnumeric() else path.stem box = xyxy2xywh(predn[:, :4]) # xywh box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner @@ -357,6 +359,7 @@ def run( def parse_opt(): + """Parses and returns command-line options for dataset paths, model parameters, and inference settings.""" parser = argparse.ArgumentParser() parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="dataset.yaml path") parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov3-tiny.pt", help="model path(s)") @@ -389,6 +392,7 @@ def parse_opt(): def main(opt): + """Executes model tasks including training, validation, and speed or study benchmarks based on specified options.""" check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) if opt.task in ("train", "val", "test"): # run normally From 283a2d5e9ba616088aa79412ae0b417bdd944681 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 28 Apr 2024 17:21:08 +0200 Subject: [PATCH 1069/1185] =?UTF-8?q?T=C3=BCrk=C3=A7e=20(Turkish)=20and=20?= =?UTF-8?q?Ti=E1=BA=BFng=20Vi=E1=BB=87t=20(Vietnamese)=20Docs=20(#2210)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Turkish and Vietnamese Docs * Update README.zh-CN.md --- README.md | 2 +- README.zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6a1d168ce4..4692d31af3 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

-[中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [हिन्दी](https://docs.ultralytics.com/hi/) | [العربية](https://docs.ultralytics.com/ar/) +[中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [Türkçe](https://docs.ultralytics.com/tr/) | [Tiếng Việt](https://docs.ultralytics.com/vi/) | [हिन्दी](https://docs.ultralytics.com/hi/) | [العربية](https://docs.ultralytics.com/ar/)
YOLOv3 CI diff --git a/README.zh-CN.md b/README.zh-CN.md index 0467d0c7c0..8605283e48 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -4,7 +4,7 @@

-[中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [हिन्दी](https://docs.ultralytics.com/hi/) | [العربية](https://docs.ultralytics.com/ar/) +[中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [Türkçe](https://docs.ultralytics.com/tr/) | [Tiếng Việt](https://docs.ultralytics.com/vi/) | [हिन्दी](https://docs.ultralytics.com/hi/) | [العربية](https://docs.ultralytics.com/ar/)
YOLOv3 CI From b35d59bb6b07d281c58cb9f70bbe2c99822d0377 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 09:34:06 +0200 Subject: [PATCH 1070/1185] Update tensorflow requirement from <=2.13.1 to <=2.16.1 (#2198) Updates the requirements on [tensorflow](https://github.com/tensorflow/tensorflow) to permit the latest version. - [Release notes](https://github.com/tensorflow/tensorflow/releases) - [Changelog](https://github.com/tensorflow/tensorflow/blob/v2.16.1/RELEASE.md) - [Commits](https://github.com/tensorflow/tensorflow/compare/tflite-v0.1.7...v2.16.1) --- updated-dependencies: - dependency-name: tensorflow dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9abc3093fd..4d5d3ad172 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,7 @@ export = [ "onnx>=1.12.0", # ONNX export "coremltools>=7.0; platform_system != 'Windows'", # CoreML only supported on macOS and Linux "openvino-dev>=2023.0", # OpenVINO export - "tensorflow<=2.13.1", # TF bug https://github.com/ultralytics/ultralytics/issues/5161 + "tensorflow<=2.16.1", # TF bug https://github.com/ultralytics/ultralytics/issues/5161 "tensorflowjs>=3.9.0", # TF.js export, automatically installs tensorflow ] # tensorflow>=2.4.1,<=2.13.1 # TF exports (-cpu, -aarch64, -macos) From 42c38a5d1f5de584c9c02b5cc558f114efc13532 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 May 2024 18:25:29 +0200 Subject: [PATCH 1071/1185] Add `pip install --retries 3` to CI to resolve transients (#2212) --- .github/workflows/ci-testing.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 425ab487d2..4ce7b0dcc9 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -41,11 +41,11 @@ jobs: - name: Install requirements run: | python -m pip install --upgrade pip wheel + torch="" if [ "${{ matrix.torch }}" == "1.8.0" ]; then - pip install -r requirements.txt torch==1.8.0 torchvision==0.9.0 --extra-index-url https://download.pytorch.org/whl/cpu - else - pip install -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cpu + torch="torch==1.8.0 torchvision==0.9.0" fi + pip install --retries 3 -r requirements.txt $torch --extra-index-url https://download.pytorch.org/whl/cpu shell: bash # for Windows compatibility - name: Check environment run: | From 77352d2028e80bd64ddecf43a7fcf90c86f4b593 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 May 2024 18:48:06 +0200 Subject: [PATCH 1072/1185] Revert CI pip install retries to default (#2213) --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 4ce7b0dcc9..2de64ab9e9 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -45,7 +45,7 @@ jobs: if [ "${{ matrix.torch }}" == "1.8.0" ]; then torch="torch==1.8.0 torchvision==0.9.0" fi - pip install --retries 3 -r requirements.txt $torch --extra-index-url https://download.pytorch.org/whl/cpu + pip install -r requirements.txt $torch --extra-index-url https://download.pytorch.org/whl/cpu shell: bash # for Windows compatibility - name: Check environment run: | From fd9179654d2130594bdd886a1bc9d34d7b5db6eb Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 18 May 2024 18:18:51 +0200 Subject: [PATCH 1073/1185] Reformat Markdown code blocks (#2214) --- README.md | 4 +--- README.zh-CN.md | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4692d31af3..615f271269 100644 --- a/README.md +++ b/README.md @@ -390,9 +390,7 @@ python classify/predict.py --weights yolov5s-cls.pt --data data/images/bus.jpg ``` ```python -model = torch.hub.load( - "ultralytics/yolov5", "custom", "yolov5s-cls.pt" -) # load from PyTorch Hub +model = torch.hub.load("ultralytics/yolov5", "custom", "yolov5s-cls.pt") # load from PyTorch Hub ``` ### Export diff --git a/README.zh-CN.md b/README.zh-CN.md index 8605283e48..3a7f8f2f68 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -390,9 +390,7 @@ python classify/predict.py --weights yolov5s-cls.pt --data data/images/bus.jpg ``` ```python -model = torch.hub.load( - "ultralytics/yolov5", "custom", "yolov5s-cls.pt" -) # load from PyTorch Hub +model = torch.hub.load("ultralytics/yolov5", "custom", "yolov5s-cls.pt") # load from PyTorch Hub ``` ### 模型导出 From 6b4831ccb7fd3bbb87df3c8694f6398decf28a4c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 24 May 2024 07:49:53 +0200 Subject: [PATCH 1074/1185] [Snyk] Security upgrade requests from 2.31.0 to 2.32.0 (#2215) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-REQUESTS-6928867 Co-authored-by: snyk-bot --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index fee7d74c9a..a14a3a262e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ opencv-python>=4.1.1 Pillow>=10.3.0 psutil # system resources PyYAML>=5.3.1 -requests>=2.23.0 +requests>=2.32.0 scipy>=1.4.1 thop>=0.1.1 # FLOPs computation torch>=1.8.0 # see https://pytorch.org/get-started/locally (recommended) From e9fc3780ab226469f5c6d9a0f3159742358dea54 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 28 May 2024 16:56:02 +0200 Subject: [PATCH 1075/1185] Update Ultralytics YouTube URL (#2216) * Update Ultralytics YouTube URL * Update README.zh-CN.md * Update README.zh-CN.md --- README.md | 4 ++-- README.zh-CN.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 615f271269..1b420e9aba 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ To request an Enterprise License please complete the form at [Ultralytics Licens Ultralytics Twitter - Ultralytics YouTube + Ultralytics YouTube Ultralytics TikTok @@ -455,7 +455,7 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/ Ultralytics Twitter - Ultralytics YouTube + Ultralytics YouTube Ultralytics TikTok diff --git a/README.zh-CN.md b/README.zh-CN.md index 3a7f8f2f68..8992ddd8ae 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -31,7 +31,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics Twitter - Ultralytics YouTube + Ultralytics YouTube Ultralytics TikTok @@ -455,7 +455,7 @@ Ultralytics 提供两种许可证选项以适应各种使用场景: Ultralytics Twitter - Ultralytics YouTube + Ultralytics YouTube Ultralytics TikTok From 0d2eccfbd2286052c1635d62ea6d0f22054fc8b1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 8 Jun 2024 21:45:02 +0200 Subject: [PATCH 1076/1185] Add Prettier for YAML formatting to Ultralytics Actions (#2217) * Add Prettier for YAML formatting to Ultralytics Actions * Update format.yml --- .github/workflows/format.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 048fd81114..34b277afda 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -19,7 +19,8 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, do not modify python: true # format Python code and docstrings - markdown: true # format Markdown and YAML + markdown: true # format Markdown + prettier: true # format YAML spelling: true # check spelling links: true # check broken links summary: true # print PR summary with GPT4 (requires 'openai_api_key' or 'openai_azure_api_key' and 'openai_azure_endpoint') From d4c06a8b9cc8258b299c7c4c2823e8e0b6874373 Mon Sep 17 00:00:00 2001 From: Ultralytics Assistant <135830346+UltralyticsAssistant@users.noreply.github.com> Date: Sat, 8 Jun 2024 22:22:35 +0200 Subject: [PATCH 1077/1185] Update license line in Python files (#2220) * Add license line to .github/ISSUE_TEMPLATE/bug-report.yml * Add license line to .github/ISSUE_TEMPLATE/config.yml * Add license line to .github/ISSUE_TEMPLATE/feature-request.yml * Add license line to .github/ISSUE_TEMPLATE/question.yml * Add license line to .github/dependabot.yml * Add license line to .github/workflows/ci-testing.yml * Add license line to .github/workflows/codeql-analysis.yml * Add license line to .github/workflows/docker.yml * Add license line to .github/workflows/format.yml * Add license line to .github/workflows/greetings.yml * Add license line to .github/workflows/links.yml * Add license line to .github/workflows/stale.yml * Add license line to benchmarks.py * Add license line to classify/predict.py * Add license line to classify/train.py * Add license line to classify/val.py * Add license line to data/Argoverse.yaml * Add license line to data/GlobalWheat2020.yaml * Add license line to data/ImageNet.yaml * Add license line to data/SKU-110K.yaml * Add license line to data/VisDrone.yaml * Add license line to data/coco.yaml * Add license line to data/coco128-seg.yaml * Add license line to data/coco128.yaml * Add license line to data/hyps/hyp.Objects365.yaml * Add license line to data/hyps/hyp.VOC.yaml * Add license line to data/hyps/hyp.no-augmentation.yaml * Add license line to data/hyps/hyp.scratch-high.yaml * Add license line to data/hyps/hyp.scratch-low.yaml * Add license line to data/hyps/hyp.scratch-med.yaml * Add license line to data/objects365.yaml * Add license line to data/voc.yaml * Add license line to data/xView.yaml * Add license line to detect.py * Add license line to export.py * Add license line to hubconf.py * Add license line to models/common.py * Add license line to models/experimental.py * Add license line to models/hub/anchors.yaml * Add license line to models/hub/yolov5-bifpn.yaml * Add license line to models/hub/yolov5-fpn.yaml * Add license line to models/hub/yolov5-p2.yaml * Add license line to models/hub/yolov5-p34.yaml * Add license line to models/hub/yolov5-p6.yaml * Add license line to models/hub/yolov5-p7.yaml * Add license line to models/hub/yolov5-panet.yaml * Add license line to models/hub/yolov5l6.yaml * Add license line to models/hub/yolov5m6.yaml * Add license line to models/hub/yolov5n6.yaml * Add license line to models/hub/yolov5s-LeakyReLU.yaml * Add license line to models/hub/yolov5s-ghost.yaml * Add license line to models/hub/yolov5s-transformer.yaml * Add license line to models/hub/yolov5s6.yaml * Add license line to models/hub/yolov5x6.yaml * Add license line to models/segment/yolov5l-seg.yaml * Add license line to models/segment/yolov5m-seg.yaml * Add license line to models/segment/yolov5n-seg.yaml * Add license line to models/segment/yolov5s-seg.yaml * Add license line to models/segment/yolov5x-seg.yaml * Add license line to models/tf.py * Add license line to models/yolo.py * Add license line to models/yolov3-spp.yaml * Add license line to models/yolov3-tiny.yaml * Add license line to models/yolov3.yaml * Add license line to models/yolov5l.yaml * Add license line to models/yolov5m.yaml * Add license line to models/yolov5n.yaml * Add license line to models/yolov5s.yaml * Add license line to models/yolov5x.yaml * Add license line to pyproject.toml * Add license line to segment/predict.py * Add license line to segment/train.py * Add license line to segment/val.py * Add license line to train.py * Add license line to utils/__init__.py * Add license line to utils/activations.py * Add license line to utils/augmentations.py * Add license line to utils/autoanchor.py * Add license line to utils/autobatch.py * Add license line to utils/aws/resume.py * Add license line to utils/callbacks.py * Add license line to utils/dataloaders.py * Add license line to utils/downloads.py * Add license line to utils/flask_rest_api/example_request.py * Add license line to utils/flask_rest_api/restapi.py * Add license line to utils/general.py * Add license line to utils/google_app_engine/app.yaml * Add license line to utils/loggers/__init__.py * Add license line to utils/loggers/clearml/clearml_utils.py * Add license line to utils/loggers/clearml/hpo.py * Add license line to utils/loggers/comet/__init__.py * Add license line to utils/loggers/comet/comet_utils.py * Add license line to utils/loggers/comet/hpo.py * Add license line to utils/loggers/wandb/wandb_utils.py * Add license line to utils/loss.py * Add license line to utils/metrics.py * Add license line to utils/plots.py * Add license line to utils/segment/augmentations.py * Add license line to utils/segment/dataloaders.py * Add license line to utils/segment/general.py * Add license line to utils/segment/loss.py * Add license line to utils/segment/metrics.py * Add license line to utils/segment/plots.py * Add license line to utils/torch_utils.py * Add license line to utils/triton.py * Add license line to val.py * Auto-format by https://ultralytics.com/actions * Update train.py * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: Glenn Jocher --- .github/ISSUE_TEMPLATE/bug-report.yml | 2 ++ .github/ISSUE_TEMPLATE/config.yml | 2 ++ .github/ISSUE_TEMPLATE/feature-request.yml | 2 ++ .github/ISSUE_TEMPLATE/question.yml | 2 ++ .github/dependabot.yml | 2 +- .github/workflows/ci-testing.yml | 2 +- .github/workflows/codeql-analysis.yml | 1 + .github/workflows/docker.yml | 2 +- .github/workflows/format.yml | 2 +- .github/workflows/greetings.yml | 2 +- .github/workflows/links.yml | 2 +- .github/workflows/stale.yml | 2 +- benchmarks.py | 2 +- classify/predict.py | 2 +- classify/train.py | 2 +- classify/val.py | 2 +- data/Argoverse.yaml | 2 +- data/GlobalWheat2020.yaml | 2 +- data/ImageNet.yaml | 2 +- data/SKU-110K.yaml | 2 +- data/VisDrone.yaml | 2 +- data/coco.yaml | 2 +- data/coco128-seg.yaml | 2 +- data/coco128.yaml | 2 +- data/hyps/hyp.Objects365.yaml | 2 +- data/hyps/hyp.VOC.yaml | 2 +- data/hyps/hyp.no-augmentation.yaml | 2 +- data/hyps/hyp.scratch-high.yaml | 2 +- data/hyps/hyp.scratch-low.yaml | 2 +- data/hyps/hyp.scratch-med.yaml | 2 +- data/objects365.yaml | 2 +- data/voc.yaml | 2 +- data/xView.yaml | 2 +- detect.py | 2 +- export.py | 2 +- hubconf.py | 2 +- models/common.py | 2 +- models/experimental.py | 2 +- models/hub/anchors.yaml | 2 +- models/hub/yolov5-bifpn.yaml | 2 +- models/hub/yolov5-fpn.yaml | 2 +- models/hub/yolov5-p2.yaml | 2 +- models/hub/yolov5-p34.yaml | 2 +- models/hub/yolov5-p6.yaml | 2 +- models/hub/yolov5-p7.yaml | 2 +- models/hub/yolov5-panet.yaml | 2 +- models/hub/yolov5l6.yaml | 2 +- models/hub/yolov5m6.yaml | 2 +- models/hub/yolov5n6.yaml | 2 +- models/hub/yolov5s-LeakyReLU.yaml | 2 +- models/hub/yolov5s-ghost.yaml | 2 +- models/hub/yolov5s-transformer.yaml | 2 +- models/hub/yolov5s6.yaml | 2 +- models/hub/yolov5x6.yaml | 2 +- models/segment/yolov5l-seg.yaml | 2 +- models/segment/yolov5m-seg.yaml | 2 +- models/segment/yolov5n-seg.yaml | 2 +- models/segment/yolov5s-seg.yaml | 2 +- models/segment/yolov5x-seg.yaml | 2 +- models/tf.py | 2 +- models/yolo.py | 2 +- models/yolov3-spp.yaml | 2 +- models/yolov3-tiny.yaml | 2 +- models/yolov3.yaml | 2 +- models/yolov5l.yaml | 2 +- models/yolov5m.yaml | 2 +- models/yolov5n.yaml | 2 +- models/yolov5s.yaml | 2 +- models/yolov5x.yaml | 2 +- pyproject.toml | 2 +- segment/predict.py | 2 +- segment/train.py | 2 +- segment/val.py | 2 +- train.py | 2 +- utils/__init__.py | 2 +- utils/activations.py | 2 +- utils/augmentations.py | 2 +- utils/autoanchor.py | 2 +- utils/autobatch.py | 2 +- utils/aws/resume.py | 1 + utils/callbacks.py | 2 +- utils/dataloaders.py | 2 +- utils/downloads.py | 2 +- utils/flask_rest_api/example_request.py | 2 +- utils/flask_rest_api/restapi.py | 2 +- utils/general.py | 2 +- utils/google_app_engine/app.yaml | 2 ++ utils/loggers/__init__.py | 2 +- utils/loggers/clearml/clearml_utils.py | 1 + utils/loggers/clearml/hpo.py | 2 ++ utils/loggers/comet/__init__.py | 2 ++ utils/loggers/comet/comet_utils.py | 2 ++ utils/loggers/comet/hpo.py | 2 ++ utils/loggers/wandb/wandb_utils.py | 2 +- utils/loss.py | 2 +- utils/metrics.py | 2 +- utils/plots.py | 2 +- utils/segment/augmentations.py | 2 +- utils/segment/dataloaders.py | 2 +- utils/segment/general.py | 2 ++ utils/segment/loss.py | 2 ++ utils/segment/metrics.py | 2 +- utils/segment/plots.py | 2 ++ utils/torch_utils.py | 2 +- utils/triton.py | 2 +- val.py | 2 +- 106 files changed, 118 insertions(+), 91 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index f74a3b871d..dbdb9d72b6 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -1,3 +1,5 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license + name: 🐛 Bug Report # title: " " description: Problems with YOLOv3 diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 43b61e3beb..5c80f143ad 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,3 +1,5 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license + blank_issues_enabled: true contact_links: - name: 📄 Docs diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index 3cc2a96bcd..cb28b4aa9b 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -1,3 +1,5 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license + name: 🚀 Feature Request description: Suggest a YOLOv3 idea # title: " " diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml index decb214859..edf0efee9c 100644 --- a/.github/ISSUE_TEMPLATE/question.yml +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -1,3 +1,5 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license + name: ❓ Question description: Ask a YOLOv3 question # title: " " diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2d4ae31873..34985ad6d9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,4 +1,4 @@ -# Ultralytics YOLO 🚀, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Dependabot for package version updates # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 2de64ab9e9..88719b913c 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # YOLOv3 Continuous Integration (CI) GitHub Actions tests name: YOLOv3 CI diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 2897fd0b45..cece81c8c3 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,3 +1,4 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # This action runs GitHub's industry-leading static analysis engine, CodeQL, against a repository's source code to find security vulnerabilities. # https://github.com/github/codeql-action diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c3939ab633..3f44df8f68 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Builds ultralytics/yolov3:latest images on DockerHub https://hub.docker.com/r/ultralytics/yolov3 name: Publish Docker Images diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 34b277afda..1ed49314ff 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -1,4 +1,4 @@ -# Ultralytics 🚀 - AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Ultralytics Actions https://github.com/ultralytics/actions # This workflow automatically formats code and documentation in PRs to official Ultralytics standards diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 8efe82d643..5f311cb48e 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license name: Greetings diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 3acae3ec2d..a90e2c20fb 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -1,4 +1,4 @@ -# Ultralytics YOLO 🚀, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Continuous Integration (CI) GitHub Actions tests broken link checker using https://github.com/lycheeverse/lychee # Ignores the following status codes to reduce false positives: # - 403(OpenVINO, 'forbidden') diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index cda1acda0c..b4ed8bd6aa 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license name: Close stale issues on: diff --git a/benchmarks.py b/benchmarks.py index e91f204d92..1ce0d65cbd 100644 --- a/benchmarks.py +++ b/benchmarks.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ Run YOLOv3 benchmarks on all supported export formats. diff --git a/classify/predict.py b/classify/predict.py index 23d608ed32..7737f18ddb 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ Run YOLOv3 classification inference on images, videos, directories, globs, YouTube, webcam, streams, etc. diff --git a/classify/train.py b/classify/train.py index bfcf36fd04..95291edb10 100644 --- a/classify/train.py +++ b/classify/train.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ Train a YOLOv3 classifier model on a classification dataset. diff --git a/classify/val.py b/classify/val.py index bf786379f6..58575fbb70 100644 --- a/classify/val.py +++ b/classify/val.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ Validate a trained YOLOv3 classification model on a classification dataset. diff --git a/data/Argoverse.yaml b/data/Argoverse.yaml index e11f4b8bb0..e6a07ef3e5 100644 --- a/data/Argoverse.yaml +++ b/data/Argoverse.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/ by Argo AI # Example usage: python train.py --data Argoverse.yaml # parent diff --git a/data/GlobalWheat2020.yaml b/data/GlobalWheat2020.yaml index 8c4cd3397c..52e07a658a 100644 --- a/data/GlobalWheat2020.yaml +++ b/data/GlobalWheat2020.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Global Wheat 2020 dataset http://www.global-wheat.com/ by University of Saskatchewan # Example usage: python train.py --data GlobalWheat2020.yaml # parent diff --git a/data/ImageNet.yaml b/data/ImageNet.yaml index 71270dde49..62e8cb5ff5 100644 --- a/data/ImageNet.yaml +++ b/data/ImageNet.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # ImageNet-1k dataset https://www.image-net.org/index.php by Stanford University # Simplified class names from https://github.com/anishathalye/imagenet-simple-labels # Example usage: python classify/train.py --data imagenet diff --git a/data/SKU-110K.yaml b/data/SKU-110K.yaml index d2c216bd1a..272cdea4e9 100644 --- a/data/SKU-110K.yaml +++ b/data/SKU-110K.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # SKU-110K retail items dataset https://github.com/eg4000/SKU110K_CVPR19 by Trax Retail # Example usage: python train.py --data SKU-110K.yaml # parent diff --git a/data/VisDrone.yaml b/data/VisDrone.yaml index e816989cc8..2934e01f1c 100644 --- a/data/VisDrone.yaml +++ b/data/VisDrone.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # VisDrone2019-DET dataset https://github.com/VisDrone/VisDrone-Dataset by Tianjin University # Example usage: python train.py --data VisDrone.yaml # parent diff --git a/data/coco.yaml b/data/coco.yaml index 314a4db001..f7ddc80705 100644 --- a/data/coco.yaml +++ b/data/coco.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # COCO 2017 dataset http://cocodataset.org by Microsoft # Example usage: python train.py --data coco.yaml # parent diff --git a/data/coco128-seg.yaml b/data/coco128-seg.yaml index 36eb047f5b..a3798158bf 100644 --- a/data/coco128-seg.yaml +++ b/data/coco128-seg.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # COCO128-seg dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics # Example usage: python train.py --data coco128.yaml # parent diff --git a/data/coco128.yaml b/data/coco128.yaml index 5509d3ceea..3a58985aaf 100644 --- a/data/coco128.yaml +++ b/data/coco128.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics # Example usage: python train.py --data coco128.yaml # parent diff --git a/data/hyps/hyp.Objects365.yaml b/data/hyps/hyp.Objects365.yaml index e96e9ac307..77a06577f7 100644 --- a/data/hyps/hyp.Objects365.yaml +++ b/data/hyps/hyp.Objects365.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Hyperparameters for Objects365 training # python train.py --weights yolov5m.pt --data Objects365.yaml --evolve # See Hyperparameter Evolution tutorial for details https://github.com/ultralytics/yolov5#tutorials diff --git a/data/hyps/hyp.VOC.yaml b/data/hyps/hyp.VOC.yaml index 9831eb0fab..88a418ed59 100644 --- a/data/hyps/hyp.VOC.yaml +++ b/data/hyps/hyp.VOC.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Hyperparameters for VOC training # python train.py --batch 128 --weights yolov5m6.pt --data VOC.yaml --epochs 50 --img 512 --hyp hyp.scratch-med.yaml --evolve # See Hyperparameter Evolution tutorial for details https://github.com/ultralytics/yolov5#tutorials diff --git a/data/hyps/hyp.no-augmentation.yaml b/data/hyps/hyp.no-augmentation.yaml index 494f023068..2937714df6 100644 --- a/data/hyps/hyp.no-augmentation.yaml +++ b/data/hyps/hyp.no-augmentation.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Hyperparameters when using Albumentations frameworks # python train.py --hyp hyp.no-augmentation.yaml # See https://github.com/ultralytics/yolov5/pull/3882 for YOLOv3 + Albumentations Usage examples diff --git a/data/hyps/hyp.scratch-high.yaml b/data/hyps/hyp.scratch-high.yaml index 6e89cc0d5d..4acf2f8da8 100644 --- a/data/hyps/hyp.scratch-high.yaml +++ b/data/hyps/hyp.scratch-high.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Hyperparameters for high-augmentation COCO training from scratch # python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300 # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials diff --git a/data/hyps/hyp.scratch-low.yaml b/data/hyps/hyp.scratch-low.yaml index 52a3a4e8b8..7f15609f00 100644 --- a/data/hyps/hyp.scratch-low.yaml +++ b/data/hyps/hyp.scratch-low.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Hyperparameters for low-augmentation COCO training from scratch # python train.py --batch 64 --cfg yolov5n6.yaml --weights '' --data coco.yaml --img 640 --epochs 300 --linear # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials diff --git a/data/hyps/hyp.scratch-med.yaml b/data/hyps/hyp.scratch-med.yaml index ce7d5d7cb9..18c1b0e963 100644 --- a/data/hyps/hyp.scratch-med.yaml +++ b/data/hyps/hyp.scratch-med.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Hyperparameters for medium-augmentation COCO training from scratch # python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300 # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials diff --git a/data/objects365.yaml b/data/objects365.yaml index 2a4fef135f..9e0e199431 100644 --- a/data/objects365.yaml +++ b/data/objects365.yaml @@ -1,4 +1,4 @@ -# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Objects365 dataset https://www.objects365.org/ by Megvii # Example usage: python train.py --data Objects365.yaml # parent diff --git a/data/voc.yaml b/data/voc.yaml index 27fa80bcca..b7f25e7235 100644 --- a/data/voc.yaml +++ b/data/voc.yaml @@ -1,4 +1,4 @@ -# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # PASCAL VOC dataset http://host.robots.ox.ac.uk/pascal/VOC by University of Oxford # Example usage: python train.py --data VOC.yaml # parent diff --git a/data/xView.yaml b/data/xView.yaml index 04ec46d3e0..cadc7f31fd 100644 --- a/data/xView.yaml +++ b/data/xView.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # DIUx xView 2018 Challenge https://challenge.xviewdataset.org by U.S. National Geospatial-Intelligence Agency (NGA) # -------- DOWNLOAD DATA MANUALLY and jar xf val_images.zip to 'datasets/xView' before running train command! -------- # Example usage: python train.py --data xView.yaml diff --git a/detect.py b/detect.py index daca7fac14..0a5396537a 100644 --- a/detect.py +++ b/detect.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ Run YOLOv3 detection inference on images, videos, directories, globs, YouTube, webcam, streams, etc. diff --git a/export.py b/export.py index 70f5045a39..dcfd51debf 100644 --- a/export.py +++ b/export.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ Export a YOLOv3 PyTorch model to other formats. TensorFlow exports authored by https://github.com/zldrobit diff --git a/hubconf.py b/hubconf.py index a950909be1..89c47a0721 100644 --- a/hubconf.py +++ b/hubconf.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov5 diff --git a/models/common.py b/models/common.py index a2b89164e1..b2ce877465 100644 --- a/models/common.py +++ b/models/common.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Common modules.""" import ast diff --git a/models/experimental.py b/models/experimental.py index 5a3af681dc..fba1ed3239 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Experimental modules.""" import math diff --git a/models/hub/anchors.yaml b/models/hub/anchors.yaml index fb85f14fb3..a2cb271235 100644 --- a/models/hub/anchors.yaml +++ b/models/hub/anchors.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Default anchors for COCO data # P5 ------------------------------------------------------------------------------------------------------------------- diff --git a/models/hub/yolov5-bifpn.yaml b/models/hub/yolov5-bifpn.yaml index 4ea8370473..ec36c165c7 100644 --- a/models/hub/yolov5-bifpn.yaml +++ b/models/hub/yolov5-bifpn.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-fpn.yaml b/models/hub/yolov5-fpn.yaml index ea587cec55..a55b4db137 100644 --- a/models/hub/yolov5-fpn.yaml +++ b/models/hub/yolov5-fpn.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-p2.yaml b/models/hub/yolov5-p2.yaml index 8d2dd9bddb..5841b7fe83 100644 --- a/models/hub/yolov5-p2.yaml +++ b/models/hub/yolov5-p2.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-p34.yaml b/models/hub/yolov5-p34.yaml index 77ebfe3b77..101f08abfb 100644 --- a/models/hub/yolov5-p34.yaml +++ b/models/hub/yolov5-p34.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-p6.yaml b/models/hub/yolov5-p6.yaml index f27a28cc2b..7e68d33107 100644 --- a/models/hub/yolov5-p6.yaml +++ b/models/hub/yolov5-p6.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-p7.yaml b/models/hub/yolov5-p7.yaml index 899e83b74c..238fbf0f85 100644 --- a/models/hub/yolov5-p7.yaml +++ b/models/hub/yolov5-p7.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-panet.yaml b/models/hub/yolov5-panet.yaml index 0b8478751e..b7fa4ffe50 100644 --- a/models/hub/yolov5-panet.yaml +++ b/models/hub/yolov5-panet.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5l6.yaml b/models/hub/yolov5l6.yaml index b208cf5307..274419beb7 100644 --- a/models/hub/yolov5l6.yaml +++ b/models/hub/yolov5l6.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5m6.yaml b/models/hub/yolov5m6.yaml index d9da4d0750..0ff59e48ba 100644 --- a/models/hub/yolov5m6.yaml +++ b/models/hub/yolov5m6.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5n6.yaml b/models/hub/yolov5n6.yaml index a49ecf12c4..abd1fb03dc 100644 --- a/models/hub/yolov5n6.yaml +++ b/models/hub/yolov5n6.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5s-LeakyReLU.yaml b/models/hub/yolov5s-LeakyReLU.yaml index 08cb5d91cc..76726a16e0 100644 --- a/models/hub/yolov5s-LeakyReLU.yaml +++ b/models/hub/yolov5s-LeakyReLU.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5s-ghost.yaml b/models/hub/yolov5s-ghost.yaml index ed4f7b8ae6..2ce0ef2353 100644 --- a/models/hub/yolov5s-ghost.yaml +++ b/models/hub/yolov5s-ghost.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5s-transformer.yaml b/models/hub/yolov5s-transformer.yaml index 12c7992f93..142d7cff07 100644 --- a/models/hub/yolov5s-transformer.yaml +++ b/models/hub/yolov5s-transformer.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5s6.yaml b/models/hub/yolov5s6.yaml index 5b37de477c..2f02f2329f 100644 --- a/models/hub/yolov5s6.yaml +++ b/models/hub/yolov5s6.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5x6.yaml b/models/hub/yolov5x6.yaml index 5446399de2..acbbddba81 100644 --- a/models/hub/yolov5x6.yaml +++ b/models/hub/yolov5x6.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5l-seg.yaml b/models/segment/yolov5l-seg.yaml index 83021f2d1f..9e99301f1a 100644 --- a/models/segment/yolov5l-seg.yaml +++ b/models/segment/yolov5l-seg.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5m-seg.yaml b/models/segment/yolov5m-seg.yaml index 81279469f1..2437a90dd6 100644 --- a/models/segment/yolov5m-seg.yaml +++ b/models/segment/yolov5m-seg.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5n-seg.yaml b/models/segment/yolov5n-seg.yaml index a4d44cd8e8..3ffc4fd8c1 100644 --- a/models/segment/yolov5n-seg.yaml +++ b/models/segment/yolov5n-seg.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5s-seg.yaml b/models/segment/yolov5s-seg.yaml index caef266d35..e1a2641da8 100644 --- a/models/segment/yolov5s-seg.yaml +++ b/models/segment/yolov5s-seg.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5x-seg.yaml b/models/segment/yolov5x-seg.yaml index 10e3e5f562..0a8312136c 100644 --- a/models/segment/yolov5x-seg.yaml +++ b/models/segment/yolov5x-seg.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/tf.py b/models/tf.py index e988ff0bb5..913445de08 100644 --- a/models/tf.py +++ b/models/tf.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ TensorFlow, Keras and TFLite versions of YOLOv3 Authored by https://github.com/zldrobit in PR https://github.com/ultralytics/yolov5/pull/1127 diff --git a/models/yolo.py b/models/yolo.py index 8602c1697b..b65f6cdcc9 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ YOLO-specific modules. diff --git a/models/yolov3-spp.yaml b/models/yolov3-spp.yaml index 810f517556..9cb9b93a2a 100644 --- a/models/yolov3-spp.yaml +++ b/models/yolov3-spp.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov3-tiny.yaml b/models/yolov3-tiny.yaml index 8707f1db1e..e531e34b2e 100644 --- a/models/yolov3-tiny.yaml +++ b/models/yolov3-tiny.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov3.yaml b/models/yolov3.yaml index 8a6680e1c5..f181e12bcc 100644 --- a/models/yolov3.yaml +++ b/models/yolov3.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov5l.yaml b/models/yolov5l.yaml index 18a8106e2d..69bfe9cd66 100644 --- a/models/yolov5l.yaml +++ b/models/yolov5l.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov5m.yaml b/models/yolov5m.yaml index 1637421528..2aac70af11 100644 --- a/models/yolov5m.yaml +++ b/models/yolov5m.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov5n.yaml b/models/yolov5n.yaml index 19cb10a84b..ad1cd770da 100644 --- a/models/yolov5n.yaml +++ b/models/yolov5n.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov5s.yaml b/models/yolov5s.yaml index 3cd30e8ca5..e2dda5de68 100644 --- a/models/yolov5s.yaml +++ b/models/yolov5s.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/models/yolov5x.yaml b/models/yolov5x.yaml index be0f90b8a1..51082e6527 100644 --- a/models/yolov5x.yaml +++ b/models/yolov5x.yaml @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Parameters nc: 80 # number of classes diff --git a/pyproject.toml b/pyproject.toml index 4d5d3ad172..12ccf70950 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,4 +1,4 @@ -# Ultralytics YOLO 🚀, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Overview: # This pyproject.toml file manages the build, packaging, and distribution of the Ultralytics library. diff --git a/segment/predict.py b/segment/predict.py index de20b9dff1..597060bde7 100644 --- a/segment/predict.py +++ b/segment/predict.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ Run YOLOv3 segmentation inference on images, videos, directories, streams, etc. diff --git a/segment/train.py b/segment/train.py index 97c5b2f371..8b83abf7fd 100644 --- a/segment/train.py +++ b/segment/train.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ Train a YOLOv3 segment model on a segment dataset Models and datasets download automatically from the latest YOLOv3 release. diff --git a/segment/val.py b/segment/val.py index 6179ab87f7..47de1db58b 100644 --- a/segment/val.py +++ b/segment/val.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ Validate a trained YOLOv3 segment model on a segment dataset. diff --git a/train.py b/train.py index ac5235599a..3b688cd004 100644 --- a/train.py +++ b/train.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ Train a YOLOv3 model on a custom dataset. Models and datasets download automatically from the latest YOLOv3 release. diff --git a/utils/__init__.py b/utils/__init__.py index 3a3524b05a..0d5bf73ec0 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """utils/initialization.""" import contextlib diff --git a/utils/activations.py b/utils/activations.py index 5986a0d08d..457de4ab54 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Activation functions.""" import torch diff --git a/utils/augmentations.py b/utils/augmentations.py index 5bb36404f1..1468a90ef7 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Image augmentation functions.""" import math diff --git a/utils/autoanchor.py b/utils/autoanchor.py index dda1dce7d9..af5cea1e92 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """AutoAnchor utils.""" import random diff --git a/utils/autobatch.py b/utils/autobatch.py index c2ba75ce07..1e8d8b0775 100644 --- a/utils/autobatch.py +++ b/utils/autobatch.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Auto-batch utils.""" from copy import deepcopy diff --git a/utils/aws/resume.py b/utils/aws/resume.py index 91643e2c40..37c6ffd42c 100644 --- a/utils/aws/resume.py +++ b/utils/aws/resume.py @@ -1,3 +1,4 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # Resume all interrupted trainings in yolov5/ dir including DDP trainings # Usage: $ python utils/aws/resume.py diff --git a/utils/callbacks.py b/utils/callbacks.py index 7ee41642b0..4545d3f64f 100644 --- a/utils/callbacks.py +++ b/utils/callbacks.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Callback utils.""" import threading diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 6bbdf880fe..59a051b0f7 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Dataloaders and dataset utils.""" import contextlib diff --git a/utils/downloads.py b/utils/downloads.py index 5203dd14b8..c9eb36a1fb 100644 --- a/utils/downloads.py +++ b/utils/downloads.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Download utils.""" import logging diff --git a/utils/flask_rest_api/example_request.py b/utils/flask_rest_api/example_request.py index 55fca5e964..7a411fce7d 100644 --- a/utils/flask_rest_api/example_request.py +++ b/utils/flask_rest_api/example_request.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Perform test request.""" import pprint diff --git a/utils/flask_rest_api/restapi.py b/utils/flask_rest_api/restapi.py index 015316e5b6..67521c02da 100644 --- a/utils/flask_rest_api/restapi.py +++ b/utils/flask_rest_api/restapi.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Run a Flask REST API exposing one or more YOLOv5s models.""" import argparse diff --git a/utils/general.py b/utils/general.py index 6309a22c01..2ea6380623 100644 --- a/utils/general.py +++ b/utils/general.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """General utils.""" import contextlib diff --git a/utils/google_app_engine/app.yaml b/utils/google_app_engine/app.yaml index 5056b7c118..e30c673e52 100644 --- a/utils/google_app_engine/app.yaml +++ b/utils/google_app_engine/app.yaml @@ -1,3 +1,5 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license + runtime: custom env: flex diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index 1d84536f06..6f04d32ddb 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Logging utils.""" import os diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py index ff417e1581..9ef352fd19 100644 --- a/utils/loggers/clearml/clearml_utils.py +++ b/utils/loggers/clearml/clearml_utils.py @@ -1,3 +1,4 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Main Logger class for ClearML experiment tracking.""" import glob diff --git a/utils/loggers/clearml/hpo.py b/utils/loggers/clearml/hpo.py index fcbd6770f6..180dcc5b5f 100644 --- a/utils/loggers/clearml/hpo.py +++ b/utils/loggers/clearml/hpo.py @@ -1,3 +1,5 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license + from clearml import Task # Connecting ClearML with the current process, diff --git a/utils/loggers/comet/__init__.py b/utils/loggers/comet/__init__.py index 74f763a7dc..00667214cc 100644 --- a/utils/loggers/comet/__init__.py +++ b/utils/loggers/comet/__init__.py @@ -1,3 +1,5 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license + import glob import json import logging diff --git a/utils/loggers/comet/comet_utils.py b/utils/loggers/comet/comet_utils.py index f78c397c1e..f6ba90dc50 100644 --- a/utils/loggers/comet/comet_utils.py +++ b/utils/loggers/comet/comet_utils.py @@ -1,3 +1,5 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license + import logging import os from urllib.parse import urlparse diff --git a/utils/loggers/comet/hpo.py b/utils/loggers/comet/hpo.py index afcafa8df5..e5fcdfe260 100644 --- a/utils/loggers/comet/hpo.py +++ b/utils/loggers/comet/hpo.py @@ -1,3 +1,5 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license + import argparse import json import logging diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py index b24d797016..a3450d5f1f 100644 --- a/utils/loggers/wandb/wandb_utils.py +++ b/utils/loggers/wandb/wandb_utils.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license # WARNING ⚠️ wandb is deprecated and will be removed in future release. # See supported integrations at https://github.com/ultralytics/yolov5#integrations diff --git a/utils/loss.py b/utils/loss.py index c805e7a2bd..148f5118e5 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Loss functions.""" import torch diff --git a/utils/metrics.py b/utils/metrics.py index 540ad2c969..6d78c5784f 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Model validation metrics.""" import math diff --git a/utils/plots.py b/utils/plots.py index 6c4af5b3b8..431c0f30f6 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Plotting utils.""" import contextlib diff --git a/utils/segment/augmentations.py b/utils/segment/augmentations.py index 96047663d7..f37b5e9226 100644 --- a/utils/segment/augmentations.py +++ b/utils/segment/augmentations.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Image augmentation functions.""" import math diff --git a/utils/segment/dataloaders.py b/utils/segment/dataloaders.py index 6cdf6ad982..8f670241dc 100644 --- a/utils/segment/dataloaders.py +++ b/utils/segment/dataloaders.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Dataloaders.""" import os diff --git a/utils/segment/general.py b/utils/segment/general.py index 14ef9e7132..c112df13ff 100644 --- a/utils/segment/general.py +++ b/utils/segment/general.py @@ -1,3 +1,5 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license + import cv2 import numpy as np import torch diff --git a/utils/segment/loss.py b/utils/segment/loss.py index f9533813eb..1871d5662e 100644 --- a/utils/segment/loss.py +++ b/utils/segment/loss.py @@ -1,3 +1,5 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license + import torch import torch.nn as nn import torch.nn.functional as F diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py index cb74f5cb07..189fded575 100644 --- a/utils/segment/metrics.py +++ b/utils/segment/metrics.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Model validation metrics.""" import numpy as np diff --git a/utils/segment/plots.py b/utils/segment/plots.py index b0c8bee6be..8c4f3d2b9f 100644 --- a/utils/segment/plots.py +++ b/utils/segment/plots.py @@ -1,3 +1,5 @@ +# Ultralytics YOLOv3 🚀, AGPL-3.0 license + import contextlib import math from pathlib import Path diff --git a/utils/torch_utils.py b/utils/torch_utils.py index a41327f0bf..665beda8a2 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """PyTorch utils.""" import math diff --git a/utils/triton.py b/utils/triton.py index 3cb0cce869..529f99743d 100644 --- a/utils/triton.py +++ b/utils/triton.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """Utils to interact with the Triton Inference Server.""" import typing diff --git a/val.py b/val.py index 39eaf56145..ca7be53f09 100644 --- a/val.py +++ b/val.py @@ -1,4 +1,4 @@ -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics YOLOv3 🚀, AGPL-3.0 license """ Validate a trained YOLOv3 detection model on a detection dataset. From cdc585761308635709b01c6781957a4ee03e4b98 Mon Sep 17 00:00:00 2001 From: Paula Derrenger <107626595+pderrenger@users.noreply.github.com> Date: Sun, 9 Jun 2024 04:13:30 +0200 Subject: [PATCH 1078/1185] Code Refactor for Speed and Readability (#2221) Refactor code for speed and clarity Co-authored-by: Glenn Jocher --- utils/general.py | 4 +++- utils/loggers/__init__.py | 4 +++- utils/loggers/clearml/clearml_utils.py | 9 +++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/utils/general.py b/utils/general.py index 2ea6380623..14fdb91275 100644 --- a/utils/general.py +++ b/utils/general.py @@ -613,8 +613,10 @@ def yaml_load(file="data.yaml"): return yaml.safe_load(f) -def yaml_save(file="data.yaml", data={}): +def yaml_save(file="data.yaml", data=None): """Safely saves data to a YAML file, converting `Path` objects to strings; defaults to 'data.yaml'.""" + if data is None: + data = {} with open(file, "w") as f: yaml.safe_dump({k: str(v) if isinstance(v, Path) else v for k, v in data.items()}, f, sort_keys=False) diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index 6f04d32ddb..ff9d304fec 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -393,8 +393,10 @@ def log_graph(self, model, imgsz=(640, 640)): if self.tb: log_tensorboard_graph(self.tb, model, imgsz) - def log_model(self, model_path, epoch=0, metadata={}): + def log_model(self, model_path, epoch=0, metadata=None): """Logs model to all loggers with `model_path`, optional `epoch` (default 0), and `metadata` dictionary.""" + if metadata is None: + metadata = {} if self.wandb: art = wandb.Artifact(name=f"run_{wandb.run.id}_model", type="model", metadata=metadata) art.add_file(str(model_path)) diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py index 9ef352fd19..6d69a74558 100644 --- a/utils/loggers/clearml/clearml_utils.py +++ b/utils/loggers/clearml/clearml_utils.py @@ -45,10 +45,11 @@ def construct_dataset(clearml_info_string): {"train", "test", "val", "nc", "names"} ), "The right keys were not found in the yaml file, make sure it at least has the following keys: ('train', 'test', 'val', 'nc', 'names')" - data_dict = {} - data_dict["train"] = ( - str((dataset_root_path / dataset_definition["train"]).resolve()) if dataset_definition["train"] else None - ) + data_dict = { + "train": ( + str((dataset_root_path / dataset_definition["train"]).resolve()) if dataset_definition["train"] else None + ) + } data_dict["test"] = ( str((dataset_root_path / dataset_definition["test"]).resolve()) if dataset_definition["test"] else None ) From c9bd9e880ce22e500fe52a0dea49a1c3535c7a19 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 16 Jun 2024 22:08:31 +0200 Subject: [PATCH 1079/1185] Update ci-testing.yml (#2223) * Update ci-testing.yml * Update requirements.txt --- .github/workflows/ci-testing.yml | 1 + requirements.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 88719b913c..aadb8b4d69 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -10,6 +10,7 @@ on: branches: [master] schedule: - cron: "0 0 * * *" # runs at 00:00 UTC every day + workflow_dispatch: jobs: Tests: diff --git a/requirements.txt b/requirements.txt index a14a3a262e..94b5e7019a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ thop>=0.1.1 # FLOPs computation torch>=1.8.0 # see https://pytorch.org/get-started/locally (recommended) torchvision>=0.9.0 tqdm>=4.64.0 -ultralytics>=8.0.232 +ultralytics>=8.2.32 # https://ultralytics.com # protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 # Logging --------------------------------------------------------------------- From 7c031b8e4b59d9f25a74e438eadbb8408c7ef3af Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 16 Jun 2024 22:39:20 +0200 Subject: [PATCH 1080/1185] Code Refactor `ruff check --fix --extend-select I` (#2222) * Refactor code for speed and clarity * Auto-format by https://ultralytics.com/actions * Update README.md * Update train.py --------- Co-authored-by: UltralyticsAssistant --- README.zh-CN.md | 80 ++++++++++++++++----------------- classify/train.py | 4 +- models/yolo.py | 5 ++- segment/train.py | 5 ++- train.py | 5 ++- utils/loggers/__init__.py | 5 ++- utils/loggers/clearml/README.md | 12 ----- 7 files changed, 59 insertions(+), 57 deletions(-) diff --git a/README.zh-CN.md b/README.zh-CN.md index 8992ddd8ae..1771c9942e 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -179,8 +179,8 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
-| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | -|:----------------------------------------------------------------------------------:|:---------------------------------------------------------------------------:|:----------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------:| +| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | +| :--------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | | 将您的自定义数据集进行标注并直接导出到 YOLOv3 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv3 [ClearML](https://cutt.ly/yolov5-readme-clearml)(开源!) | 永远免费,[Comet](https://bit.ly/yolov5-readme-comet2)可让您保存 YOLOv3 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv3 推理的速度最高可提高6倍 | ##
Ultralytics HUB
@@ -212,19 +212,19 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结 ### 预训练模型 -| 模型 | 尺寸
(像素) | mAPval
50-95 | mAPval
50 | 推理速度
CPU b1
(ms) | 推理速度
V100 b1
(ms) | 速度
V100 b32
(ms) | 参数量
(M) | FLOPs
@640 (B) | -|------------------------------------------------------------------------------------------------|-----------------|----------------------|-------------------|-----------------------------|------------------------------|-----------------------------|-----------------|------------------------| -| [YOLOv5n](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n.pt) | 640 | 28.0 | 45.7 | **45** | **6.3** | **0.6** | **1.9** | **4.5** | -| [YOLOv5s](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt) | 640 | 37.4 | 56.8 | 98 | 6.4 | 0.9 | 7.2 | 16.5 | -| [YOLOv5m](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m.pt) | 640 | 45.4 | 64.1 | 224 | 8.2 | 1.7 | 21.2 | 49.0 | -| [YOLOv5l](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l.pt) | 640 | 49.0 | 67.3 | 430 | 10.1 | 2.7 | 46.5 | 109.1 | -| [YOLOv5x](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x.pt) | 640 | 50.7 | 68.9 | 766 | 12.1 | 4.8 | 86.7 | 205.7 | -| | | | | | | | | | -| [YOLOv5n6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n6.pt) | 1280 | 36.0 | 54.4 | 153 | 8.1 | 2.1 | 3.2 | 4.6 | -| [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | -| [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | -| [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | -| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+[TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- | +| 模型 | 尺寸
(像素) | mAPval
50-95 | mAPval
50 | 推理速度
CPU b1
(ms) | 推理速度
V100 b1
(ms) | 速度
V100 b32
(ms) | 参数量
(M) | FLOPs
@640 (B) | +| ---------------------------------------------------------------------------------------------- | --------------------- | -------------------- | ----------------- | --------------------------------- | ---------------------------------- | ------------------------------- | ------------------ | ---------------------- | +| [YOLOv5n](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n.pt) | 640 | 28.0 | 45.7 | **45** | **6.3** | **0.6** | **1.9** | **4.5** | +| [YOLOv5s](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt) | 640 | 37.4 | 56.8 | 98 | 6.4 | 0.9 | 7.2 | 16.5 | +| [YOLOv5m](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m.pt) | 640 | 45.4 | 64.1 | 224 | 8.2 | 1.7 | 21.2 | 49.0 | +| [YOLOv5l](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l.pt) | 640 | 49.0 | 67.3 | 430 | 10.1 | 2.7 | 46.5 | 109.1 | +| [YOLOv5x](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x.pt) | 640 | 50.7 | 68.9 | 766 | 12.1 | 4.8 | 86.7 | 205.7 | +| | | | | | | | | | +| [YOLOv5n6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n6.pt) | 1280 | 36.0 | 54.4 | 153 | 8.1 | 2.1 | 3.2 | 4.6 | +| [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | +| [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | +| [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | +| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+[TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- |
笔记 @@ -252,13 +252,13 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结 我们使用 A100 GPU 在 COCO 上以 640 图像大小训练了 300 epochs 得到 YOLOv5 分割模型。我们将所有模型导出到 ONNX FP32 以进行 CPU 速度测试,并导出到 TensorRT FP16 以进行 GPU 速度测试。为了便于再现,我们在 Google [Colab Pro](https://colab.research.google.com/signup) 上进行了所有速度测试。 -| 模型 | 尺寸
(像素) | mAPbox
50-95 | mAPmask
50-95 | 训练时长
300 epochs
A100 GPU(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TRT A100
(ms) | 参数量
(M) | FLOPs
@640 (B) | -|--------------------------------------------------------------------------------------------|-----------------|----------------------|-----------------------|-----------------------------------------|-------------------------------|-------------------------------|-----------------|------------------------| -| [YOLOv5n-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-seg.pt) | 640 | 27.6 | 23.4 | 80:17 | **62.7** | **1.2** | **2.0** | **7.1** | -| [YOLOv5s-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt) | 640 | 37.6 | 31.7 | 88:16 | 173.3 | 1.4 | 7.6 | 26.4 | -| [YOLOv5m-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-seg.pt) | 640 | 45.0 | 37.1 | 108:36 | 427.0 | 2.2 | 22.0 | 70.8 | -| [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | -| [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | +| 模型 | 尺寸
(像素) | mAPbox
50-95 | mAPmask
50-95 | 训练时长
300 epochs
A100 GPU(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TRT A100
(ms) | 参数量
(M) | FLOPs
@640 (B) | +| ------------------------------------------------------------------------------------------ | --------------------- | -------------------- | --------------------- | ----------------------------------------------- | ----------------------------------- | ----------------------------------- | ------------------ | ---------------------- | +| [YOLOv5n-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-seg.pt) | 640 | 27.6 | 23.4 | 80:17 | **62.7** | **1.2** | **2.0** | **7.1** | +| [YOLOv5s-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt) | 640 | 37.6 | 31.7 | 88:16 | 173.3 | 1.4 | 7.6 | 26.4 | +| [YOLOv5m-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-seg.pt) | 640 | 45.0 | 37.1 | 108:36 | 427.0 | 2.2 | 22.0 | 70.8 | +| [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | +| [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | - 所有模型使用 SGD 优化器训练, 都使用 `lr0=0.01` 和 `weight_decay=5e-5` 参数, 图像大小为 640 。
训练 log 可以查看 https://wandb.ai/glenn-jocher/YOLOv5_v70_official - **准确性**结果都在 COCO 数据集上,使用单模型单尺度测试得到。
复现命令 `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt` @@ -306,7 +306,7 @@ model = torch.hub.load( ``` | ![zidane](https://user-images.githubusercontent.com/26833433/203113421-decef4c4-183d-4a0a-a6c2-6435b33bc5d3.jpg) | ![bus](https://user-images.githubusercontent.com/26833433/203113416-11fe0025-69f7-4874-a0a6-65d0bfe2999a.jpg) | -|------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------| +| ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ### 模型导出 @@ -329,23 +329,23 @@ YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) 带来对 我们使用 4xA100 实例在 ImageNet 上训练了 90 个 epochs 得到 YOLOv5-cls 分类模型,我们训练了 ResNet 和 EfficientNet 模型以及相同的默认训练设置以进行比较。我们将所有模型导出到 ONNX FP32 以进行 CPU 速度测试,并导出到 TensorRT FP16 以进行 GPU 速度测试。为了便于重现,我们在 Google 上进行了所有速度测试 [Colab Pro](https://colab.research.google.com/signup) 。 -| 模型 | 尺寸
(像素) | acc
top1 | acc
top5 | 训练时长
90 epochs
4xA100(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TensorRT V100
(ms) | 参数
(M) | FLOPs
@640 (B) | -|----------------------------------------------------------------------------------------------------|-----------------|------------------|------------------|--------------------------------------|-------------------------------|------------------------------------|----------------|------------------------| -| [YOLOv5n-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-cls.pt) | 224 | 64.6 | 85.4 | 7:59 | **3.3** | **0.5** | **2.5** | **0.5** | -| [YOLOv5s-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt) | 224 | 71.5 | 90.2 | 8:09 | 6.6 | 0.6 | 5.4 | 1.4 | -| [YOLOv5m-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-cls.pt) | 224 | 75.9 | 92.9 | 10:06 | 15.5 | 0.9 | 12.9 | 3.9 | -| [YOLOv5l-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-cls.pt) | 224 | 78.0 | 94.0 | 11:56 | 26.9 | 1.4 | 26.5 | 8.5 | -| [YOLOv5x-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-cls.pt) | 224 | **79.0** | **94.4** | 15:04 | 54.3 | 1.8 | 48.1 | 15.9 | -| | | | | | | | | | -| [ResNet18](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet18.pt) | 224 | 70.3 | 89.5 | **6:47** | 11.2 | 0.5 | 11.7 | 3.7 | -| [Resnetzch](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet34.pt) | 224 | 73.9 | 91.8 | 8:33 | 20.6 | 0.9 | 21.8 | 7.4 | -| [ResNet50](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet50.pt) | 224 | 76.8 | 93.4 | 11:10 | 23.4 | 1.0 | 25.6 | 8.5 | -| [ResNet101](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet101.pt) | 224 | 78.5 | 94.3 | 17:10 | 42.1 | 1.9 | 44.5 | 15.9 | -| | | | | | | | | | -| [EfficientNet_b0](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b0.pt) | 224 | 75.1 | 92.4 | 13:03 | 12.5 | 1.3 | 5.3 | 1.0 | -| [EfficientNet_b1](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b1.pt) | 224 | 76.4 | 93.2 | 17:04 | 14.9 | 1.6 | 7.8 | 1.5 | -| [EfficientNet_b2](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b2.pt) | 224 | 76.6 | 93.4 | 17:10 | 15.9 | 1.6 | 9.1 | 1.7 | -| [EfficientNet_b3](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b3.pt) | 224 | 77.7 | 94.0 | 19:19 | 18.9 | 1.9 | 12.2 | 2.4 | +| 模型 | 尺寸
(像素) | acc
top1 | acc
top5 | 训练时长
90 epochs
4xA100(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TensorRT V100
(ms) | 参数
(M) | FLOPs
@640 (B) | +| -------------------------------------------------------------------------------------------------- | --------------------- | ---------------- | ---------------- | -------------------------------------------- | ----------------------------------- | ---------------------------------------- | ---------------- | ---------------------- | +| [YOLOv5n-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-cls.pt) | 224 | 64.6 | 85.4 | 7:59 | **3.3** | **0.5** | **2.5** | **0.5** | +| [YOLOv5s-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt) | 224 | 71.5 | 90.2 | 8:09 | 6.6 | 0.6 | 5.4 | 1.4 | +| [YOLOv5m-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-cls.pt) | 224 | 75.9 | 92.9 | 10:06 | 15.5 | 0.9 | 12.9 | 3.9 | +| [YOLOv5l-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-cls.pt) | 224 | 78.0 | 94.0 | 11:56 | 26.9 | 1.4 | 26.5 | 8.5 | +| [YOLOv5x-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-cls.pt) | 224 | **79.0** | **94.4** | 15:04 | 54.3 | 1.8 | 48.1 | 15.9 | +| | | | | | | | | | +| [ResNet18](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet18.pt) | 224 | 70.3 | 89.5 | **6:47** | 11.2 | 0.5 | 11.7 | 3.7 | +| [Resnetzch](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet34.pt) | 224 | 73.9 | 91.8 | 8:33 | 20.6 | 0.9 | 21.8 | 7.4 | +| [ResNet50](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet50.pt) | 224 | 76.8 | 93.4 | 11:10 | 23.4 | 1.0 | 25.6 | 8.5 | +| [ResNet101](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet101.pt) | 224 | 78.5 | 94.3 | 17:10 | 42.1 | 1.9 | 44.5 | 15.9 | +| | | | | | | | | | +| [EfficientNet_b0](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b0.pt) | 224 | 75.1 | 92.4 | 13:03 | 12.5 | 1.3 | 5.3 | 1.0 | +| [EfficientNet_b1](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b1.pt) | 224 | 76.4 | 93.2 | 17:04 | 14.9 | 1.6 | 7.8 | 1.5 | +| [EfficientNet_b2](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b2.pt) | 224 | 76.6 | 93.4 | 17:10 | 15.9 | 1.6 | 9.1 | 1.7 | +| [EfficientNet_b3](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b3.pt) | 224 | 77.7 | 94.0 | 19:19 | 18.9 | 1.9 | 12.2 | 2.4 |
Table Notes (点击以展开) diff --git a/classify/train.py b/classify/train.py index 95291edb10..d90b3c28c3 100644 --- a/classify/train.py +++ b/classify/train.py @@ -180,7 +180,9 @@ def train(opt, device): # Scheduler lrf = 0.01 # final lr (fraction of lr0) # lf = lambda x: ((1 + math.cos(x * math.pi / epochs)) / 2) * (1 - lrf) + lrf # cosine - lf = lambda x: (1 - x / epochs) * (1 - lrf) + lrf # linear + def lf(x): + return (1 - x / epochs) * (1 - lrf) + lrf # linear + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # scheduler = lr_scheduler.OneCycleLR(optimizer, max_lr=lr0, total_steps=epochs, pct_start=0.1, # final_div_factor=1 / 25 / lrf) diff --git a/models/yolo.py b/models/yolo.py index b65f6cdcc9..ddc2aad13b 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -221,7 +221,10 @@ def __init__(self, cfg="yolov5s.yaml", ch=3, nc=None, anchors=None): # model, i if isinstance(m, (Detect, Segment)): s = 256 # 2x min stride m.inplace = self.inplace - forward = lambda x: self.forward(x)[0] if isinstance(m, Segment) else self.forward(x) + + def forward(x): + return self.forward(x)[0] if isinstance(m, Segment) else self.forward(x) + m.stride = torch.tensor([s / x.shape[-2] for x in forward(torch.zeros(1, ch, s, s))]) # forward check_anchor_order(m) m.anchors /= m.stride.view(-1, 1, 1) diff --git a/segment/train.py b/segment/train.py index 8b83abf7fd..50c964ba40 100644 --- a/segment/train.py +++ b/segment/train.py @@ -212,7 +212,10 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio if opt.cos_lr: lf = one_cycle(1, hyp["lrf"], epochs) # cosine 1->hyp['lrf'] else: - lf = lambda x: (1 - x / epochs) * (1.0 - hyp["lrf"]) + hyp["lrf"] # linear + + def lf(x): + return (1 - x / epochs) * (1.0 - hyp["lrf"]) + hyp["lrf"] # linear + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) # EMA diff --git a/train.py b/train.py index 3b688cd004..2c642482f3 100644 --- a/train.py +++ b/train.py @@ -208,7 +208,10 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio if opt.cos_lr: lf = one_cycle(1, hyp["lrf"], epochs) # cosine 1->hyp['lrf'] else: - lf = lambda x: (1 - x / epochs) * (1.0 - hyp["lrf"]) + hyp["lrf"] # linear + + def lf(x): + return (1 - x / epochs) * (1.0 - hyp["lrf"]) + hyp["lrf"] # linear + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) # EMA diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index ff9d304fec..88b7c212c7 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -20,7 +20,10 @@ try: from torch.utils.tensorboard import SummaryWriter except ImportError: - SummaryWriter = lambda *args: None # None = SummaryWriter(str) + + def SummaryWriter(*args): + return None # None = SummaryWriter(str) + try: import wandb diff --git a/utils/loggers/clearml/README.md b/utils/loggers/clearml/README.md index e5eca05c24..e3710cd42f 100644 --- a/utils/loggers/clearml/README.md +++ b/utils/loggers/clearml/README.md @@ -16,16 +16,10 @@ 🔭 Turn your newly trained YOLOv5 model into an API with just a few commands using ClearML Serving -
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! -
-
![ClearML scalars dashboard](https://github.com/thepycoder/clearml_screenshots/raw/main/experiment_manager_with_compare.gif) -
-
- ## 🦾 Setting Things Up To keep track of your experiments and/or data, ClearML needs to communicate to a server. You have 2 options to get one: @@ -46,8 +40,6 @@ Either sign up for free to the [ClearML Hosted Service](https://cutt.ly/yolov5-t That's it! You're done 😎 -
- ## 🚀 Training YOLOv5 With ClearML To enable ClearML experiment tracking, simply install the ClearML pip package. @@ -89,8 +81,6 @@ That's a lot right? 🤯 Now, we can visualize all of this information in the Cl 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! -
- ## 🔗 Dataset Version Management Versioning your data separately from your code is generally a good idea and makes it easy to acquire 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! @@ -157,8 +147,6 @@ Now that you have a ClearML dataset, you can very simply use it to train custom python train.py --img 640 --batch 16 --epochs 3 --data clearml:// --weights yolov5s.pt --cache ``` -
- ## 👀 Hyperparameter Optimization Now that we have our experiments and data versioned, it's time to take a look at what we can build on top! From 661e058519657665d63a1b32488c534a27cdcfad Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 17 Jun 2024 02:05:33 +0200 Subject: [PATCH 1081/1185] Update requirements.txt to `ultralytics>=8.2.34` (#2224) Update requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 94b5e7019a..298ae7aee3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ thop>=0.1.1 # FLOPs computation torch>=1.8.0 # see https://pytorch.org/get-started/locally (recommended) torchvision>=0.9.0 tqdm>=4.64.0 -ultralytics>=8.2.32 # https://ultralytics.com +ultralytics>=8.2.34 # https://ultralytics.com # protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 # Logging --------------------------------------------------------------------- From 94a0799bb00bdd5cf3ef5e8da017b059cf5dfca3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 19 Jun 2024 02:21:37 +0200 Subject: [PATCH 1082/1185] [Snyk] Security upgrade urllib3 from 2.0.7 to 2.2.2 (#2226) * fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-URLLIB3-7267250 * Update requirements.txt * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: snyk-bot Co-authored-by: UltralyticsAssistant --- classify/train.py | 1 + requirements.txt | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/classify/train.py b/classify/train.py index d90b3c28c3..62c5c7a1dc 100644 --- a/classify/train.py +++ b/classify/train.py @@ -179,6 +179,7 @@ def train(opt, device): # Scheduler lrf = 0.01 # final lr (fraction of lr0) + # lf = lambda x: ((1 + math.cos(x * math.pi / epochs)) / 2) * (1 - lrf) + lrf # cosine def lf(x): return (1 - x / epochs) * (1 - lrf) + lrf # linear diff --git a/requirements.txt b/requirements.txt index 298ae7aee3..ace47e72fd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -47,4 +47,3 @@ setuptools>=65.5.1 # Snyk vulnerability fix # mss # screenshots # albumentations>=1.0.3 # pycocotools>=2.0.6 # COCO mAP -wheel>=0.38.0 # not directly required, pinned by Snyk to avoid a vulnerability From 65ab707c11e053b83cd38c893701e82f99f3487a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 19 Jun 2024 02:27:37 +0200 Subject: [PATCH 1083/1185] Add missing Python function docstrings (#2227) * Add missing Python function docstrings * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: UltralyticsAssistant --- models/yolo.py | 1 + utils/dataloaders.py | 2 +- utils/loggers/__init__.py | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/models/yolo.py b/models/yolo.py index ddc2aad13b..8c77f04a66 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -223,6 +223,7 @@ def __init__(self, cfg="yolov5s.yaml", ch=3, nc=None, anchors=None): # model, i m.inplace = self.inplace def forward(x): + """Passes the input 'x' through the model and returns the processed output.""" return self.forward(x)[0] if isinstance(m, Segment) else self.forward(x) m.stride = torch.tensor([s / x.shape[-2] for x in forward(torch.zeros(1, ch, s, s))]) # forward diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 59a051b0f7..35e9b32058 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -1209,7 +1209,7 @@ def get_json(self, save=False, verbose=False): """ def _round(labels): - # Update labels to integer class and 6 decimal place floats + """Update labels to integer class and 6 decimal place floats.""" return [[int(c), *(round(x, 4) for x in points)] for c, *points in labels] for split in "train", "val", "test": diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index 88b7c212c7..debc3238e0 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -22,6 +22,9 @@ except ImportError: def SummaryWriter(*args): + """Imports TensorBoard's SummaryWriter for logging, with a fallback returning None if TensorBoard is not + installed. + """ return None # None = SummaryWriter(str) From 8e5b2dd761063c67bea0597a4c7002cb9f541cbb Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 20 Jun 2024 14:58:22 +0200 Subject: [PATCH 1084/1185] Create CLA Action (#2228) Create cla.yml --- .github/workflows/cla.yml | 44 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/cla.yml diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml new file mode 100644 index 0000000000..fa89a80897 --- /dev/null +++ b/.github/workflows/cla.yml @@ -0,0 +1,44 @@ +# Ultralytics YOLO 🚀, AGPL-3.0 license +# Ultralytics Contributor License Agreement (CLA) action https://docs.ultralytics.com/help/CLA +# This workflow automatically requests Pull Requests (PR) authors to sign the Ultralytics CLA before PRs can be merged + +name: CLA Assistant +on: + issue_comment: + types: + - created + pull_request_target: + types: + - reopened + - opened + - synchronize + +permissions: + actions: write + contents: write + pull-requests: write + statuses: write + +jobs: + CLA: + if: github.repository == 'ultralytics/yolov3' + runs-on: ubuntu-latest + steps: + - name: CLA Assistant + if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I sign the CLA') || github.event_name == 'pull_request_target' + uses: contributor-assistant/github-action@v2.4.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Must be repository secret PAT + PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + with: + path-to-signatures: "signatures/version1/cla.json" + path-to-document: "https://docs.ultralytics.com/help/CLA" # CLA document + # Branch must not be protected + branch: cla-signatures + allowlist: dependabot[bot],github-actions,[pre-commit*,pre-commit*,bot* + + remote-organization-name: ultralytics + remote-repository-name: cla + custom-pr-sign-comment: "I have read the CLA Document and I sign the CLA" + custom-allsigned-prcomment: All Contributors have signed the CLA. ✅ From 5d4db5de2ddf04b1ef80781bc799060321a9c744 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 20 Jun 2024 15:06:10 +0200 Subject: [PATCH 1085/1185] Update format.yml (#2229) --- .github/workflows/format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 1ed49314ff..bce585bdba 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -22,7 +22,7 @@ jobs: markdown: true # format Markdown prettier: true # format YAML spelling: true # check spelling - links: true # check broken links + links: false # check broken links summary: true # print PR summary with GPT4 (requires 'openai_api_key' or 'openai_azure_api_key' and 'openai_azure_endpoint') openai_azure_api_key: ${{ secrets.OPENAI_AZURE_API_KEY }} openai_azure_endpoint: ${{ secrets.OPENAI_AZURE_ENDPOINT }} From 7d623a69877e6bdcf4f97a5d42096f12842789bc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 20 Jun 2024 18:51:29 +0200 Subject: [PATCH 1086/1185] Update README.md (#2230) * Update README.md * Auto-format by https://ultralytics.com/actions * Update README.zh-CN.md * Update README.zh-CN.md * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: UltralyticsAssistant --- README.md | 4 +- README.zh-CN.md | 6 +-- utils/flask_rest_api/README.md | 72 +++++++++++++++++----------------- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 1b420e9aba..78af1282d0 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
-| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | +| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | | :--------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | | Label and export your custom datasets directly to YOLOv3 for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | Automatically track, visualize and even remotely train YOLOv3 using [ClearML](https://cutt.ly/yolov5-readme-clearml) (open-source!) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet2) lets you save YOLOv3 models, resume training, and interactively visualise and debug predictions | Run YOLOv3 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | @@ -225,7 +225,7 @@ YOLOv3 has been designed to be super easy to get started and simple to learn. We | [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | | [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | | [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | -| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+ [TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- | +| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+ [TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- |
Table Notes diff --git a/README.zh-CN.md b/README.zh-CN.md index 1771c9942e..1cb5d1029e 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -224,7 +224,7 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结 | [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | | [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | | [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | -| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+[TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- | +| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+[TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- |
笔记 @@ -354,8 +354,8 @@ YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) 带来对 - **准确性**都在单模型单尺度上计算,数据集使用 [ImageNet-1k](https://www.image-net.org/index.php) 。
复现命令 `python classify/val.py --data ../datasets/imagenet --img 224` - **推理速度**是使用 100 个推理图像进行平均得到,测试环境使用谷歌 [Colab Pro](https://colab.research.google.com/signup) V100 高 RAM 实例。
复现命令 `python classify/val.py --data ../datasets/imagenet --img 224 --batch 1` - **模型导出**到 FP32 的 ONNX 和 FP16 的 TensorRT 使用 `export.py` 。
复现命令 `python export.py --weights yolov5s-cls.pt --include engine onnx --imgsz 224` -
-
+
+
分类训练示例  Open In Colab diff --git a/utils/flask_rest_api/README.md b/utils/flask_rest_api/README.md index b18a3011cf..47ad8fa795 100644 --- a/utils/flask_rest_api/README.md +++ b/utils/flask_rest_api/README.md @@ -28,42 +28,42 @@ The model inference results are returned as a JSON response: ```json [ - { - "class": 0, - "confidence": 0.8900438547, - "height": 0.9318675399, - "name": "person", - "width": 0.3264600933, - "xcenter": 0.7438579798, - "ycenter": 0.5207948685 - }, - { - "class": 0, - "confidence": 0.8440024257, - "height": 0.7155083418, - "name": "person", - "width": 0.6546785235, - "xcenter": 0.427829951, - "ycenter": 0.6334488392 - }, - { - "class": 27, - "confidence": 0.3771208823, - "height": 0.3902671337, - "name": "tie", - "width": 0.0696444362, - "xcenter": 0.3675483763, - "ycenter": 0.7991207838 - }, - { - "class": 27, - "confidence": 0.3527112305, - "height": 0.1540903747, - "name": "tie", - "width": 0.0336618312, - "xcenter": 0.7814827561, - "ycenter": 0.5065554976 - } + { + "class": 0, + "confidence": 0.8900438547, + "height": 0.9318675399, + "name": "person", + "width": 0.3264600933, + "xcenter": 0.7438579798, + "ycenter": 0.5207948685 + }, + { + "class": 0, + "confidence": 0.8440024257, + "height": 0.7155083418, + "name": "person", + "width": 0.6546785235, + "xcenter": 0.427829951, + "ycenter": 0.6334488392 + }, + { + "class": 27, + "confidence": 0.3771208823, + "height": 0.3902671337, + "name": "tie", + "width": 0.0696444362, + "xcenter": 0.3675483763, + "ycenter": 0.7991207838 + }, + { + "class": 27, + "confidence": 0.3527112305, + "height": 0.1540903747, + "name": "tie", + "width": 0.0336618312, + "xcenter": 0.7814827561, + "ycenter": 0.5065554976 + } ] ``` From 7ab9c7238694ec72c1b16bd990b0f5eb33e0e7c6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 20 Jun 2024 19:04:55 +0200 Subject: [PATCH 1087/1185] Update README.md (#2231) * Update README.md * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: UltralyticsAssistant --- README.md | 2 +- README.zh-CN.md | 2 +- utils/flask_rest_api/README.md | 72 ++++++++++++++++----------------- utils/loggers/clearml/README.md | 12 +++--- 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 78af1282d0..f7fbc62129 100644 --- a/README.md +++ b/README.md @@ -225,7 +225,7 @@ YOLOv3 has been designed to be super easy to get started and simple to learn. We | [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | | [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | | [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | -| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+ [TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- | +| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+ [TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- |
Table Notes diff --git a/README.zh-CN.md b/README.zh-CN.md index 1cb5d1029e..003a581a64 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -224,7 +224,7 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结 | [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | | [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | | [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | -| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+[TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- | +| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+[TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- |
笔记 diff --git a/utils/flask_rest_api/README.md b/utils/flask_rest_api/README.md index 47ad8fa795..b18a3011cf 100644 --- a/utils/flask_rest_api/README.md +++ b/utils/flask_rest_api/README.md @@ -28,42 +28,42 @@ The model inference results are returned as a JSON response: ```json [ - { - "class": 0, - "confidence": 0.8900438547, - "height": 0.9318675399, - "name": "person", - "width": 0.3264600933, - "xcenter": 0.7438579798, - "ycenter": 0.5207948685 - }, - { - "class": 0, - "confidence": 0.8440024257, - "height": 0.7155083418, - "name": "person", - "width": 0.6546785235, - "xcenter": 0.427829951, - "ycenter": 0.6334488392 - }, - { - "class": 27, - "confidence": 0.3771208823, - "height": 0.3902671337, - "name": "tie", - "width": 0.0696444362, - "xcenter": 0.3675483763, - "ycenter": 0.7991207838 - }, - { - "class": 27, - "confidence": 0.3527112305, - "height": 0.1540903747, - "name": "tie", - "width": 0.0336618312, - "xcenter": 0.7814827561, - "ycenter": 0.5065554976 - } + { + "class": 0, + "confidence": 0.8900438547, + "height": 0.9318675399, + "name": "person", + "width": 0.3264600933, + "xcenter": 0.7438579798, + "ycenter": 0.5207948685 + }, + { + "class": 0, + "confidence": 0.8440024257, + "height": 0.7155083418, + "name": "person", + "width": 0.6546785235, + "xcenter": 0.427829951, + "ycenter": 0.6334488392 + }, + { + "class": 27, + "confidence": 0.3771208823, + "height": 0.3902671337, + "name": "tie", + "width": 0.0696444362, + "xcenter": 0.3675483763, + "ycenter": 0.7991207838 + }, + { + "class": 27, + "confidence": 0.3527112305, + "height": 0.1540903747, + "name": "tie", + "width": 0.0336618312, + "xcenter": 0.7814827561, + "ycenter": 0.5065554976 + } ] ``` diff --git a/utils/loggers/clearml/README.md b/utils/loggers/clearml/README.md index e3710cd42f..aff95d11a1 100644 --- a/utils/loggers/clearml/README.md +++ b/utils/loggers/clearml/README.md @@ -28,15 +28,15 @@ Either sign up for free to the [ClearML Hosted Service](https://cutt.ly/yolov5-t 1. Install the `clearml` python package: - ```bash - pip install clearml - ``` + ```bash + pip install clearml + ``` 2. 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: - ```bash - clearml-init - ``` + ```bash + clearml-init + ``` That's it! You're done 😎 From 9701460d06ea39c8a1e3eb09cfe11cf26b8b19d4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 20 Jun 2024 22:28:12 +0200 Subject: [PATCH 1088/1185] Ultralytics Refactor https://ultralytics.com/actions (#2232) Refactor code for speed and clarity --- README.md | 4 ++-- README.zh-CN.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f7fbc62129..c51b9211e4 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ To request an Enterprise License please complete the form at [Ultralytics Licens Ultralytics TikTok - Ultralytics Instagram + Ultralytics Instagram Ultralytics Discord @@ -459,7 +459,7 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/ Ultralytics TikTok - Ultralytics Instagram + Ultralytics Instagram Ultralytics Discord diff --git a/README.zh-CN.md b/README.zh-CN.md index 003a581a64..ccf64d5d80 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -35,7 +35,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics TikTok - Ultralytics Instagram + Ultralytics Instagram Ultralytics Discord @@ -459,7 +459,7 @@ Ultralytics 提供两种许可证选项以适应各种使用场景: Ultralytics TikTok - Ultralytics Instagram + Ultralytics Instagram Ultralytics Discord From aece7ad49b744e733de1826d8a54f461fccd53d8 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 22 Jun 2024 13:17:37 +0200 Subject: [PATCH 1089/1185] Fix HUB link https://ultralytics.com/hub (#2233) Refactor code for speed and clarity --- README.md | 10 +++++----- README.zh-CN.md | 10 +++++----- tutorial.ipynb | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c51b9211e4..dcbb64cae7 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ To request an Enterprise License please complete the form at [Ultralytics Licens Ultralytics TikTok - Ultralytics Instagram + Ultralytics BiliBili Ultralytics Discord @@ -161,7 +161,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - ##
Integrations

- +

@@ -186,9 +186,9 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - ##
Ultralytics HUB
-Experience seamless AI with [Ultralytics HUB](https://bit.ly/ultralytics_hub) ⭐, the all-in-one solution for data visualization, YOLO 🚀 model training and deployment, without any coding. Transform images into actionable insights and bring your AI visions to life with ease using our cutting-edge platform and user-friendly [Ultralytics App](https://ultralytics.com/app_install). Start your journey for **Free** now! +Experience seamless AI with [Ultralytics HUB](https://ultralytics.com/hub) ⭐, the all-in-one solution for data visualization, YOLO 🚀 model training and deployment, without any coding. Transform images into actionable insights and bring your AI visions to life with ease using our cutting-edge platform and user-friendly [Ultralytics App](https://ultralytics.com/app_install). Start your journey for **Free** now! - + ##
Why YOLOv3
@@ -459,7 +459,7 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/ Ultralytics TikTok - Ultralytics Instagram + Ultralytics BiliBili Ultralytics Discord diff --git a/README.zh-CN.md b/README.zh-CN.md index ccf64d5d80..1402cdcec8 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -35,7 +35,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics TikTok - Ultralytics Instagram + Ultralytics BiliBili Ultralytics Discord @@ -160,7 +160,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - ##
模块集成

- +

@@ -185,9 +185,9 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - ##
Ultralytics HUB
-[Ultralytics HUB](https://bit.ly/ultralytics_hub) 是我们的⭐**新的**用于可视化数据集、训练 YOLOv3 🚀 模型并以无缝体验部署到现实世界的无代码解决方案。现在开始 **免费** 使用他! +[Ultralytics HUB](https://ultralytics.com/hub) 是我们的⭐**新的**用于可视化数据集、训练 YOLOv3 🚀 模型并以无缝体验部署到现实世界的无代码解决方案。现在开始 **免费** 使用他! - + ##
为什么选择 YOLOv3
@@ -459,7 +459,7 @@ Ultralytics 提供两种许可证选项以适应各种使用场景: Ultralytics TikTok - Ultralytics Instagram + Ultralytics BiliBili Ultralytics Discord diff --git a/tutorial.ipynb b/tutorial.ipynb index a44d85ddad..93949e4866 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -254,7 +254,7 @@ "source": [ "# 3. Train\n", "\n", - "

\n", + "

\n", "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", "

\n", "\n", From a6e437cb58698fd22ba485e932fe9cfe86f6f7c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 30 Jun 2024 03:20:25 +0200 Subject: [PATCH 1090/1185] Bump docker/build-push-action from 5 to 6 in /.github/workflows (#2234) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v5...v6) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 3f44df8f68..056b1151d8 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -30,7 +30,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push arm64 image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 continue-on-error: true with: context: . @@ -40,7 +40,7 @@ jobs: tags: ultralytics/yolov3:latest-arm64 - name: Build and push CPU image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 continue-on-error: true with: context: . @@ -49,7 +49,7 @@ jobs: tags: ultralytics/yolov3:latest-cpu - name: Build and push GPU image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 continue-on-error: true with: context: . From b93ce5858da5c23808dd9c2696376ecc8b671261 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 30 Jun 2024 11:58:00 +0200 Subject: [PATCH 1091/1185] Ultralytics Code Refactor https://ultralytics.com/actions (#2235) Refactor code for speed and clarity --- classify/train.py | 1 + export.py | 5 ++++- segment/train.py | 1 + segment/val.py | 1 + train.py | 1 + utils/__init__.py | 5 +++++ utils/autoanchor.py | 6 ++++++ utils/downloads.py | 2 +- utils/general.py | 8 +++++--- utils/loggers/comet/__init__.py | 1 + utils/plots.py | 1 + utils/segment/metrics.py | 2 ++ utils/torch_utils.py | 1 + 13 files changed, 30 insertions(+), 5 deletions(-) diff --git a/classify/train.py b/classify/train.py index 62c5c7a1dc..9fb30fa2b5 100644 --- a/classify/train.py +++ b/classify/train.py @@ -182,6 +182,7 @@ def train(opt, device): # lf = lambda x: ((1 + math.cos(x * math.pi / epochs)) / 2) * (1 - lrf) + lrf # cosine def lf(x): + """Linear learning rate scheduler function, scaling learning rate from initial value to `lrf` over `epochs`.""" return (1 - x / epochs) * (1 - lrf) + lrf # linear scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) diff --git a/export.py b/export.py index dcfd51debf..2e5f95e298 100644 --- a/export.py +++ b/export.py @@ -134,6 +134,7 @@ def try_export(inner_func): inner_args = get_default_args(inner_func) def outer_func(*args, **kwargs): + """Profiles and logs the export process of YOLOv3 models, capturing success or failure details.""" prefix = inner_args["prefix"] try: with Profile() as dt: @@ -226,7 +227,7 @@ def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr("ONNX @try_export def export_openvino(file, metadata, half, int8, data, prefix=colorstr("OpenVINO:")): - # YOLOv3 OpenVINO export + """Exports a YOLOv3 model to OpenVINO format, with optional INT8 quantization and inference metadata.""" check_requirements("openvino-dev>=2023.0") # requires openvino-dev: https://pypi.org/project/openvino-dev/ import openvino.runtime as ov # noqa from openvino.tools import mo # noqa @@ -247,6 +248,7 @@ def export_openvino(file, metadata, half, int8, data, prefix=colorstr("OpenVINO: onnx_model = core.read_model(f_onnx) # export def prepare_input_tensor(image: np.ndarray): + """Prepares the input tensor by normalizing pixel values and converting the datatype to float32.""" input_tensor = image.astype(np.float32) # uint8 to fp16/32 input_tensor /= 255.0 # 0 - 255 to 0.0 - 1.0 @@ -255,6 +257,7 @@ def prepare_input_tensor(image: np.ndarray): return input_tensor def gen_dataloader(yaml_path, task="train", imgsz=640, workers=4): + """Generates a PyTorch dataloader for the specified task using dataset configurations from a YAML file.""" data_yaml = check_yaml(yaml_path) data = check_dataset(data_yaml) dataloader = create_dataloader( diff --git a/segment/train.py b/segment/train.py index 50c964ba40..63f133d258 100644 --- a/segment/train.py +++ b/segment/train.py @@ -214,6 +214,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio else: def lf(x): + """Linear learning rate scheduler decreasing from 1 to hyp['lrf'] over the course of given epochs.""" return (1 - x / epochs) * (1.0 - hyp["lrf"]) + hyp["lrf"] # linear scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) diff --git a/segment/val.py b/segment/val.py index 47de1db58b..afb170ce28 100644 --- a/segment/val.py +++ b/segment/val.py @@ -85,6 +85,7 @@ def save_one_json(predn, jdict, path, class_map, pred_masks): from pycocotools.mask import encode def single_encode(x): + """Encodes a binary mask to COCO RLE format, converting counts to a UTF-8 string for JSON serialization.""" rle = encode(np.asarray(x[:, :, None], order="F", dtype="uint8"))[0] rle["counts"] = rle["counts"].decode("utf-8") return rle diff --git a/train.py b/train.py index 2c642482f3..708fc9670b 100644 --- a/train.py +++ b/train.py @@ -210,6 +210,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio else: def lf(x): + """Linear learning rate scheduler function with decay calculated by epoch proportion.""" return (1 - x / epochs) * (1.0 - hyp["lrf"]) + hyp["lrf"] # linear scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) diff --git a/utils/__init__.py b/utils/__init__.py index 0d5bf73ec0..a34a38abef 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -42,6 +42,11 @@ def threaded(func): """ def wrapper(*args, **kwargs): + """ + Runs the decorated function in a separate thread and returns the thread object. + + Usage: @threaded. + """ thread = threading.Thread(target=func, args=args, kwargs=kwargs, daemon=True) thread.start() return thread diff --git a/utils/autoanchor.py b/utils/autoanchor.py index af5cea1e92..b8c40dc553 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -33,6 +33,9 @@ def check_anchors(dataset, model, thr=4.0, imgsz=640): wh = torch.tensor(np.concatenate([l[:, 3:5] * s for s, l in zip(shapes * scale, dataset.labels)])).float() # wh def metric(k): # compute metric + """Computes and returns best possible recall (bpr) and anchors above threshold (aat) metrics for given + anchors. + """ r = wh[:, None] / k[None] x = torch.min(r, 1 / r).min(2)[0] # ratio metric best = x.max(1)[0] # best_x @@ -86,16 +89,19 @@ def kmean_anchors(dataset="./data/coco128.yaml", n=9, img_size=640, thr=4.0, gen thr = 1 / thr def metric(k, wh): # compute metrics + """Computes best possible recall (BPR) and anchors above threshold (AAT) metrics for given anchor boxes.""" r = wh[:, None] / k[None] x = torch.min(r, 1 / r).min(2)[0] # ratio metric # x = wh_iou(wh, torch.tensor(k)) # iou metric return x, x.max(1)[0] # x, best_x def anchor_fitness(k): # mutation fitness + """Evaluates the fitness of anchor boxes by computing mean recall weighted by an activation threshold.""" _, best = metric(torch.tensor(k, dtype=torch.float32), wh) return (best * (best > thr).float()).mean() # fitness def print_results(k, verbose=True): + """Displays sorted anchors and their metrics including best possible recall and anchors above threshold.""" k = k[np.argsort(k.prod(1))] # sort small to large x, best = metric(k, wh0) bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr diff --git a/utils/downloads.py b/utils/downloads.py index c9eb36a1fb..d95d76d9cd 100644 --- a/utils/downloads.py +++ b/utils/downloads.py @@ -84,7 +84,7 @@ def attempt_download(file, repo="ultralytics/yolov5", release="v7.0"): from utils.general import LOGGER def github_assets(repository, version="latest"): - # Return GitHub repo tag (i.e. 'v7.0') and assets (i.e. ['yolov5s.pt', 'yolov5m.pt', ...]) + """Returns GitHub tag and assets for a given repository and version from the GitHub API.""" if version != "latest": version = f"tags/{version}" # i.e. tags/v7.0 response = requests.get(f"https://api.github.com/repos/{repository}/releases/{version}").json() # github api diff --git a/utils/general.py b/utils/general.py index 14fdb91275..117ab059fd 100644 --- a/utils/general.py +++ b/utils/general.py @@ -336,7 +336,7 @@ def check_online(): import socket def run_once(): - # Check once + """Attempts a single internet connectivity check to '1.1.1.1' on port 443 and returns True if successful.""" try: socket.create_connection(("1.1.1.1", 443), 5) # check host accessibility return True @@ -584,7 +584,7 @@ def check_amp(model): from models.common import AutoShape, DetectMultiBackend def amp_allclose(model, im): - # All close FP32 vs AMP results + """Compares FP32 and AMP inference results for a model and image, ensuring outputs are within 10% tolerance.""" m = AutoShape(model, verbose=False) # model a = m(im).xywhn[0] # FP32 inference m.amp = True @@ -645,7 +645,9 @@ def download(url, dir=".", unzip=True, delete=True, curl=False, threads=1, retry """ def download_one(url, dir): - # Download 1 file + """Downloads a file from a URL into the specified directory, supporting retries and using curl or torch + methods. + """ success = True if os.path.isfile(url): f = Path(url) # filename diff --git a/utils/loggers/comet/__init__.py b/utils/loggers/comet/__init__.py index 00667214cc..b6c6846747 100644 --- a/utils/loggers/comet/__init__.py +++ b/utils/loggers/comet/__init__.py @@ -67,6 +67,7 @@ class CometLogger: """Log metrics, parameters, source code, models and much more with Comet.""" def __init__(self, opt, hyp, run_id=None, job_type="Training", **experiment_kwargs) -> None: + """Initialize the CometLogger instance with experiment configurations and hyperparameters for logging.""" self.job_type = job_type self.opt = opt self.hyp = hyp diff --git a/utils/plots.py b/utils/plots.py index 431c0f30f6..2919133e02 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -118,6 +118,7 @@ def butter_lowpass_filtfilt(data, cutoff=1500, fs=50000, order=5): # https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy def butter_lowpass(cutoff, fs, order): + """Applies a low-pass Butterworth filter to input data using forward-backward method; see https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy.""" nyq = 0.5 * fs normal_cutoff = cutoff / nyq return butter(order, normal_cutoff, btype="low", analog=False) diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py index 189fded575..519604db05 100644 --- a/utils/segment/metrics.py +++ b/utils/segment/metrics.py @@ -55,6 +55,7 @@ def ap_per_class_box_and_mask( class Metric: def __init__(self) -> None: + """Initializes Metric class attributes for precision, recall, F1 score, AP values, and AP class indices.""" self.p = [] # (nc, ) self.r = [] # (nc, ) self.f1 = [] # (nc, ) @@ -153,6 +154,7 @@ class Metrics: """Metric for boxes and masks.""" def __init__(self) -> None: + """Initializes the Metrics class with separate Metric instances for boxes and masks.""" self.metric_box = Metric() self.metric_mask = Metric() diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 665beda8a2..115e4d9f89 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -37,6 +37,7 @@ def smart_inference_mode(torch_1_9=check_version(torch.__version__, "1.9.0")): """Applies torch.inference_mode() if torch>=1.9.0 or torch.no_grad() otherwise as a decorator to functions.""" def decorate(fn): + """Applies torch.inference_mode() if torch>=1.9.0, otherwise torch.no_grad(), as a decorator to functions.""" return (torch.inference_mode if torch_1_9 else torch.no_grad)()(fn) return decorate From 8ed1e65ce75ceba61d702055edee8b338b91b2b7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 1 Jul 2024 00:17:39 +0200 Subject: [PATCH 1092/1185] Ultralytics Code Refactor https://ultralytics.com/actions (#2236) * Refactor code for speed and clarity * Auto-format by https://ultralytics.com/actions * Update export.py * Auto-format by https://ultralytics.com/actions * Update dataloaders.py --------- Co-authored-by: UltralyticsAssistant --- benchmarks.py | 2 ++ classify/predict.py | 1 + classify/val.py | 1 + detect.py | 1 + export.py | 2 ++ models/common.py | 3 +++ models/tf.py | 2 ++ segment/predict.py | 1 + segment/val.py | 1 + utils/augmentations.py | 2 ++ utils/dataloaders.py | 5 +++++ utils/segment/augmentations.py | 1 + utils/segment/dataloaders.py | 2 ++ val.py | 1 + 14 files changed, 25 insertions(+) diff --git a/benchmarks.py b/benchmarks.py index 1ce0d65cbd..f01dc9b52d 100644 --- a/benchmarks.py +++ b/benchmarks.py @@ -60,6 +60,7 @@ def run( pt_only=False, # test PyTorch only hard_fail=False, # throw error on benchmark failure ): + """Run YOLOv3 benchmarks on multiple export formats and validate performance metrics.""" y, t = [], time.time() device = select_device(device) model_type = type(attempt_load(weights, fuse=False)) # DetectionModel, SegmentationModel, etc. @@ -124,6 +125,7 @@ def test( pt_only=False, # test PyTorch only hard_fail=False, # throw error on benchmark failure ): + """Run YOLOv3 export tests for various formats and log the results, including export success status.""" y, t = [], time.time() device = select_device(device) for i, (name, f, suffix, gpu) in export.export_formats().iterrows(): # index, (name, file, suffix, gpu-capable) diff --git a/classify/predict.py b/classify/predict.py index 7737f18ddb..2f7eda383a 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -84,6 +84,7 @@ def run( dnn=False, # use OpenCV DNN for ONNX inference vid_stride=1, # video frame-rate stride ): + """Performs YOLOv3 classification inference on various input sources and saves or displays results.""" source = str(source) save_img = not nosave and not source.endswith(".txt") # save inference images is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) diff --git a/classify/val.py b/classify/val.py index 58575fbb70..7735533120 100644 --- a/classify/val.py +++ b/classify/val.py @@ -68,6 +68,7 @@ def run( criterion=None, pbar=None, ): + """Evaluate a YOLOv3 classification model on the specified dataset, providing accuracy metrics.""" # Initialize/load model and set device training = model is not None if training: # called by train.py diff --git a/detect.py b/detect.py index 0a5396537a..ba11935c76 100644 --- a/detect.py +++ b/detect.py @@ -95,6 +95,7 @@ def run( dnn=False, # use OpenCV DNN for ONNX inference vid_stride=1, # video frame-rate stride ): + """Performs YOLOv3 detection on various input sources including images, videos, streams, and YouTube URLs.""" source = str(source) save_img = not nosave and not source.endswith(".txt") # save inference images is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) diff --git a/export.py b/export.py index 2e5f95e298..22ac1d5198 100644 --- a/export.py +++ b/export.py @@ -415,6 +415,7 @@ def export_saved_model( keras=False, prefix=colorstr("TensorFlow SavedModel:"), ): + """Exports YOLOv3 model to TensorFlow SavedModel format; includes NMS and configuration options.""" # YOLOv3 TensorFlow SavedModel export try: import tensorflow as tf @@ -781,6 +782,7 @@ def run( iou_thres=0.45, # TF.js NMS: IoU threshold conf_thres=0.25, # TF.js NMS: confidence threshold ): + """Exports a PyTorch model to specified formats like ONNX, CoreML, TensorRT.""" t = time.time() include = [x.lower() for x in include] # to lowercase fmts = tuple(export_formats()["Argument"][1:]) # --include arguments diff --git a/models/common.py b/models/common.py index b2ce877465..74c7b0c9c9 100644 --- a/models/common.py +++ b/models/common.py @@ -1025,6 +1025,9 @@ class Classify(nn.Module): def __init__( self, c1, c2, k=1, s=1, p=None, g=1, dropout_p=0.0 ): # ch_in, ch_out, kernel, stride, padding, groups, dropout probability + """Initializes YOLOv3 classification head with convolution, pooling and dropout layers for feature extraction + and classification. + """ super().__init__() c_ = 1280 # efficientnet_b0 size self.conv = Conv(c1, c_, k, s, autopad(k, p), g) diff --git a/models/tf.py b/models/tf.py index 913445de08..1731e76a6f 100644 --- a/models/tf.py +++ b/models/tf.py @@ -565,6 +565,7 @@ def predict( iou_thres=0.45, conf_thres=0.25, ): + """Performs inference on input data using a YOLOv3 model, including optional TensorFlow NMS.""" y = [] # outputs x = inputs for m in self.model.layers: @@ -683,6 +684,7 @@ def run( dynamic=False, # dynamic batch size ): # PyTorch model + """Exports and summarizes both PyTorch and TensorFlow models for YOLOv5-based object detection.""" im = torch.zeros((batch_size, 3, *imgsz)) # BCHW image model = attempt_load(weights, device=torch.device("cpu"), inplace=True, fuse=False) _ = model(im) # inference diff --git a/segment/predict.py b/segment/predict.py index 597060bde7..67b435e7fa 100644 --- a/segment/predict.py +++ b/segment/predict.py @@ -97,6 +97,7 @@ def run( vid_stride=1, # video frame-rate stride retina_masks=False, ): + """Performs YOLOv3 segmentation inference on various sources such as images, videos, and streams.""" source = str(source) save_img = not nosave and not source.endswith(".txt") # save inference images is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) diff --git a/segment/val.py b/segment/val.py index afb170ce28..619bcc1951 100644 --- a/segment/val.py +++ b/segment/val.py @@ -178,6 +178,7 @@ def run( compute_loss=None, callbacks=Callbacks(), ): + """Validates a trained YOLOv3 segmentation model using a specified dataset and evaluation metrics.""" if save_json: check_requirements("pycocotools>=2.0.6") process = process_mask_native # more accurate diff --git a/utils/augmentations.py b/utils/augmentations.py index 1468a90ef7..d65f2ea204 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -157,6 +157,7 @@ def random_perspective( # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(0.1, 0.1), scale=(0.9, 1.1), shear=(-10, 10)) # targets = [cls, xyxy] + """Applies a random perspective transformation to an image and its bounding boxes for data augmentation.""" height = im.shape[0] + border[0] * 2 # shape(h,w,c) width = im.shape[1] + border[1] * 2 @@ -321,6 +322,7 @@ def classify_albumentations( auto_aug=False, ): # YOLOv3 classification Albumentations (optional, only used if package is installed) + """Generates an Albumentations transform pipeline for image classification with optional augmentations.""" prefix = colorstr("albumentations: ") try: import albumentations as A diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 35e9b32058..28cf40774e 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -142,6 +142,7 @@ def create_dataloader( shuffle=False, seed=0, ): + """Creates a DataLoader for training, with options for augmentation, caching, and parallelization.""" if rect and shuffle: LOGGER.warning("WARNING ⚠️ --rect is incompatible with DataLoader shuffle, setting shuffle=False") shuffle = False @@ -511,6 +512,7 @@ def __init__( min_items=0, prefix="", ): + """Initializes a dataset with images and labels for YOLOv3 training and validation.""" self.img_size = img_size self.augment = augment self.hyp = hyp @@ -1302,6 +1304,9 @@ def create_classification_dataloader( path, imgsz=224, batch_size=16, augment=True, cache=False, rank=-1, workers=8, shuffle=True ): # Returns Dataloader object to be used with YOLOv3 Classifier + """Creates a DataLoader for image classification tasks with options for augmentation, caching, and distributed + training. + """ with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP dataset = ClassificationDataset(root=path, imgsz=imgsz, augment=augment, cache=cache) batch_size = min(batch_size, len(dataset)) diff --git a/utils/segment/augmentations.py b/utils/segment/augmentations.py index f37b5e9226..ced82d723d 100644 --- a/utils/segment/augmentations.py +++ b/utils/segment/augmentations.py @@ -27,6 +27,7 @@ def random_perspective( # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) # targets = [cls, xyxy] + """Applies random perspective augmentation including rotation, translation, scale, and shear transformations.""" height = im.shape[0] + border[0] * 2 # shape(h,w,c) width = im.shape[1] + border[1] * 2 diff --git a/utils/segment/dataloaders.py b/utils/segment/dataloaders.py index 8f670241dc..0343291d68 100644 --- a/utils/segment/dataloaders.py +++ b/utils/segment/dataloaders.py @@ -39,6 +39,7 @@ def create_dataloader( overlap_mask=False, seed=0, ): + """Creates a DataLoader for images and labels with optional augmentations and distributed sampling.""" if rect and shuffle: LOGGER.warning("WARNING ⚠️ --rect is incompatible with DataLoader shuffle, setting shuffle=False") shuffle = False @@ -99,6 +100,7 @@ def __init__( downsample_ratio=1, overlap=False, ): + """Initializes image, label, and mask loading for training/testing with optional augmentations.""" super().__init__( path, img_size, diff --git a/val.py b/val.py index ca7be53f09..8d6c06aa68 100644 --- a/val.py +++ b/val.py @@ -145,6 +145,7 @@ def run( callbacks=Callbacks(), compute_loss=None, ): + """Validates a trained YOLO model on a dataset and saves detection results in specified formats.""" # Initialize/load model and set device training = model is not None if training: # called by train.py From a8540fc8b5a6dd63cd4b306799c95d085dd64c3c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 5 Jul 2024 14:24:20 +0200 Subject: [PATCH 1093/1185] Add Discourse at https://community.ultralytics.com (#2244) Refactor code for speed and clarity --- .github/workflows/greetings.yml | 2 +- README.md | 4 ++-- README.zh-CN.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index 5f311cb48e..6a4dd47701 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -27,7 +27,7 @@ jobs: If this is a 🐛 Bug Report, please provide a **minimum reproducible example** to help us debug it. - If this is a custom training ❓ Question, please provide as much information as possible, including dataset image examples and training logs, and verify you are following our [Tips for Best Training Results](https://docs.ultralytics.com/yolov5/tutorials/tips_for_best_training_results/). + If this is a custom training ❓ Question, please provide as much information as possible, including dataset image examples and training logs, and verify you are following our [Tips for Best Training Results](https://docs.ultralytics.com/guides/model-training-tips//). ## Requirements diff --git a/README.md b/README.md index dcbb64cae7..89bea96cf8 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ YOLOv3 CI YOLOv3 Citation Docker Pulls - Discord + Discord Ultralytics Forums
Run on Gradient Open In Colab @@ -140,7 +140,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - Tutorials - [Train Custom Data](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data) 🚀 RECOMMENDED -- [Tips for Best Training Results](https://docs.ultralytics.com/yolov5/tutorials/tips_for_best_training_results) ☘️ +- [Tips for Best Training Results](https://docs.ultralytics.com/guides/model-training-tips/) ☘️ - [Multi-GPU Training](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) - [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) 🌟 NEW - [TFLite, ONNX, CoreML, TensorRT Export](https://docs.ultralytics.com/yolov5/tutorials/model_export) 🚀 diff --git a/README.zh-CN.md b/README.zh-CN.md index 1402cdcec8..0a367b1b7d 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -139,7 +139,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - 教程 - [训练自定义数据](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data) 🚀 推荐 -- [获得最佳训练结果的技巧](https://docs.ultralytics.com/yolov5/tutorials/tips_for_best_training_results) ☘️ +- [获得最佳训练结果的技巧](https://docs.ultralytics.com/guides/model-training-tips/) ☘️ - [多GPU训练](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) - [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) 🌟 新 - [TFLite,ONNX,CoreML,TensorRT导出](https://docs.ultralytics.com/yolov5/tutorials/model_export) 🚀 From 2af2504aa2373e2118474152fa84360e9ac57b66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 19:41:31 +0200 Subject: [PATCH 1094/1185] Update tensorflow requirement from <=2.16.1 to <=2.16.2 (#2237) * Update tensorflow requirement from <=2.16.1 to <=2.16.2 Updates the requirements on [tensorflow](https://github.com/tensorflow/tensorflow) to permit the latest version. - [Release notes](https://github.com/tensorflow/tensorflow/releases) - [Changelog](https://github.com/tensorflow/tensorflow/blob/v2.16.2/RELEASE.md) - [Commits](https://github.com/tensorflow/tensorflow/compare/tflite-v0.1.7...v2.16.2) --- updated-dependencies: - dependency-name: tensorflow dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Update pyproject.toml --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 12ccf70950..faa679f7a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,7 @@ export = [ "onnx>=1.12.0", # ONNX export "coremltools>=7.0; platform_system != 'Windows'", # CoreML only supported on macOS and Linux "openvino-dev>=2023.0", # OpenVINO export - "tensorflow<=2.16.1", # TF bug https://github.com/ultralytics/ultralytics/issues/5161 + "tensorflow>=2.0.0", # TF bug https://github.com/ultralytics/ultralytics/issues/5161 "tensorflowjs>=3.9.0", # TF.js export, automatically installs tensorflow ] # tensorflow>=2.4.1,<=2.13.1 # TF exports (-cpu, -aarch64, -macos) From b5b53bab0dbb04a30bf396aba2d15ecb6c5aa2c0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 8 Jul 2024 23:56:23 +0200 Subject: [PATCH 1095/1185] Ultralytics Code Refactor https://ultralytics.com/actions (#2246) * Refactor code for speed and clarity * Update export.py * Update hubconf.py --- benchmarks.py | 138 +++++++++++- detect.py | 139 +++++++++++- export.py | 611 +++++++++++++++++++++++++++++++++++++++++++++++--- hubconf.py | 326 ++++++++++++++++++++++++--- train.py | 142 +++++++++++- val.py | 199 +++++++++++++++- 6 files changed, 1470 insertions(+), 85 deletions(-) diff --git a/benchmarks.py b/benchmarks.py index f01dc9b52d..06bde1e380 100644 --- a/benchmarks.py +++ b/benchmarks.py @@ -60,7 +60,40 @@ def run( pt_only=False, # test PyTorch only hard_fail=False, # throw error on benchmark failure ): - """Run YOLOv3 benchmarks on multiple export formats and validate performance metrics.""" + """ + Run YOLOv3 benchmarks on multiple export formats and validate performance metrics. + + Args: + weights (str | Path): Path to the weights file. Defaults to 'yolov5s.pt'. + imgsz (int): Inference image size in pixels. Defaults to 640. + batch_size (int): Batch size for inference. Defaults to 1. + data (str | Path): Path to the dataset configuration file (dataset.yaml). Defaults to 'data/coco128.yaml'. + device (str): Device to be used for inference, e.g., '0' or '0,1,2,3' for GPU or 'cpu' for CPU. Defaults to ''. + half (bool): Use FP16 half-precision for inference. Defaults to False. + test (bool): Test exports only without running benchmarks. Defaults to False. + pt_only (bool): Run benchmarks only for PyTorch format. Defaults to False. + hard_fail (bool): Raise an error if any benchmark test fails. Defaults to False. + + Returns: + None + + Notes: + This function iterates over multiple export formats, performs the export, and then validates the model's + performance using appropriate validation functions for detection and segmentation models. The results are logged, + and optionally, benchmarks can be configured to raise errors on failures using the `hard_fail` argument. + + Examples: + ```python + # Run benchmarks on the default 'yolov5s.pt' model with an image size of 640 pixels + run() + + # Run benchmarks on a specific model with GPU and half-precision enabled + run(weights='custom_model.pt', device='0', half=True) + + # Test only PyTorch export + run(pt_only=True) + ``` + """ y, t = [], time.time() device = select_device(device) model_type = type(attempt_load(weights, fuse=False)) # DetectionModel, SegmentationModel, etc. @@ -125,7 +158,45 @@ def test( pt_only=False, # test PyTorch only hard_fail=False, # throw error on benchmark failure ): - """Run YOLOv3 export tests for various formats and log the results, including export success status.""" + """ + Run YOLOv3 export tests for various formats and log the results, including export success status. + + Args: + weights (str | Path): Path to the weights file. Defaults to ROOT / "yolov5s.pt". + imgsz (int): Inference size in pixels. Defaults to 640. + batch_size (int): Number of images per batch. Defaults to 1. + data (str | Path): Path to the dataset yaml file. Defaults to ROOT / "data/coco128.yaml". + device (str): Device for inference. Accepts cuda device (e.g., "0" or "0,1,2,3") or "cpu". Defaults to "". + half (bool): Use FP16 half-precision inference. Defaults to False. + test (bool): Run export tests only, no inference. Defaults to False. + pt_only (bool): Run tests on PyTorch format only. Defaults to False. + hard_fail (bool): Raise an error on benchmark failure. Defaults to False. + + Returns: + pd.DataFrame: A DataFrame containing the export formats and their success status. (pd.DataFrame) + + Examples: + ```python + from ultralytics import test + + results = test( + weights="path/to/yolov5s.pt", + imgsz=640, + batch_size=1, + data="path/to/coco128.yaml", + device="0", + half=False, + test=True, + pt_only=False, + hard_fail=True, + ) + print(results) + ``` + + Notes: + Ensure all required packages are installed as specified in the Ultralytics YOLOv3 documentation: + https://github.com/ultralytics/ultralytics + """ y, t = [], time.time() device = select_device(device) for i, (name, f, suffix, gpu) in export.export_formats().iterrows(): # index, (name, file, suffix, gpu-capable) @@ -151,8 +222,38 @@ def test( def parse_opt(): - """Parses command line arguments for model inference configurations, including weights, image size, and device - options. + """ + Parses command line arguments for YOLOv3 inference and export configuration. + + Args: + --weights (str): Path to the weights file. Default is 'ROOT / "yolov3-tiny.pt"'. + --imgsz | --img | --img-size (int): Inference image size in pixels. Default is 640. + --batch-size (int): Batch size for inference. Default is 1. + --data (str): Path to the dataset configuration file (dataset.yaml). Default is 'ROOT / "data/coco128.yaml"'. + --device (str): CUDA device identifier, e.g., '0' for single GPU, '0,1,2,3' for multiple GPUs, or 'cpu' for CPU + inference. Default is "". + --half (bool): If set, use FP16 half-precision inference. Default is False. + --test (bool): If set, only test exports without running inference. Default is False. + --pt-only (bool): If set, test only the PyTorch model without exporting to other formats. Default is False. + --hard-fail (str | bool): If set, raise an exception on benchmark failure. Can also be a string representing + the minimum metric floor for success. Default is False. + + Returns: + argparse.Namespace: The parsed arguments as a namespace object. + + Example: + To run inference on the YOLOv3-tiny model with a different image size: + + ```python + $ python benchmarks.py --weights yolov3-tiny.pt --imgsz 512 --device 0 + ``` + + Notes: + The `--hard-fail` argument can be a boolean or a string. If a string is provided, it should be an expression that + represents the minimum acceptable metric value, such as '0.29' for mAP (mean Average Precision). + + Links: + https://github.com/ultralytics/ultralytics """ parser = argparse.ArgumentParser() parser.add_argument("--weights", type=str, default=ROOT / "yolov3-tiny.pt", help="weights path") @@ -171,7 +272,34 @@ def parse_opt(): def main(opt): - """Executes tests or main pipeline on provided options, determining behavior based on `opt.test`.""" + """ + Executes the export and benchmarking pipeline for YOLOv3 models, testing multiple export formats and validating + performance metrics. + + Args: + opt (argparse.Namespace): Parsed command line arguments, including options for weights, image size, batch size, + dataset path, device, half-precision inference, test mode, PyTorch-only testing, and hard fail conditions. + + Returns: + pd.DataFrame: A DataFrame containing benchmarking results with columns: + - Format: Name of the export format + - Size (MB): File size of the exported model + - mAP50-95: Mean Average Precision for the model + - Inference time (ms): Time taken for inference + + Notes: + The function runs the main pipeline by exporting the YOLOv3 model to various formats and running benchmarks to + evaluate performance. If `opt.test` is set to True, it only tests the export process and logs the results. + + Example: + Running the function from command line with required arguments: + + ```python + $ python benchmarks.py --weights yolov5s.pt --img 640 + ``` + + For more details, visit the Ultralytics YOLOv3 repository on [GitHub](https://github.com/ultralytics/ultralytics). + """ test(**vars(opt)) if opt.test else run(**vars(opt)) diff --git a/detect.py b/detect.py index ba11935c76..efe3f1d6e5 100644 --- a/detect.py +++ b/detect.py @@ -95,7 +95,60 @@ def run( dnn=False, # use OpenCV DNN for ONNX inference vid_stride=1, # video frame-rate stride ): - """Performs YOLOv3 detection on various input sources including images, videos, streams, and YouTube URLs.""" + """ + Performs YOLOv3 detection on various input sources including images, videos, streams, and YouTube URLs. + + Args: + weights (str | Path): Path to the model weights file or a Triton URL (default: 'yolov5s.pt'). + source (str | Path): Source of input data such as a file, directory, URL, glob pattern, or device identifier + (default: 'data/images'). + data (str | Path): Path to the dataset YAML file (default: 'data/coco128.yaml'). + imgsz (tuple[int, int]): Inference size as a tuple (height, width) (default: (640, 640)). + conf_thres (float): Confidence threshold for detection (default: 0.25). + iou_thres (float): Intersection Over Union (IOU) threshold for Non-Max Suppression (NMS) (default: 0.45). + max_det (int): Maximum number of detections per image (default: 1000). + device (str): CUDA device identifier, e.g., '0', '0,1,2,3', or 'cpu' (default: ''). + view_img (bool): Whether to display results during inference (default: False). + save_txt (bool): Whether to save detection results to text files (default: False). + save_conf (bool): Whether to save detection confidences in the text labels (default: False). + save_crop (bool): Whether to save cropped detection boxes (default: False). + nosave (bool): Whether to prevent saving images or videos with detections (default: False). + classes (list[int] | None): List of class indices to filter, e.g., [0, 2, 3] (default: None). + agnostic_nms (bool): Whether to perform class-agnostic NMS (default: False). + augment (bool): Whether to apply augmented inference (default: False). + visualize (bool): Whether to visualize feature maps (default: False). + update (bool): Whether to update all models (default: False). + project (str | Path): Path to the project directory where results will be saved (default: 'runs/detect'). + name (str): Name for the specific run within the project directory (default: 'exp'). + exist_ok (bool): Whether to allow existing project/name directory without incrementing run index (default: False). + line_thickness (int): Thickness of bounding box lines in pixels (default: 3). + hide_labels (bool): Whether to hide labels in the results (default: False). + hide_conf (bool): Whether to hide confidences in the results (default: False). + half (bool): Whether to use half-precision (FP16) for inference (default: False). + dnn (bool): Whether to use OpenCV DNN for ONNX inference (default: False). + vid_stride (int): Stride for video frame rate (default: 1). + + Returns: + None + + Notes: + This function supports a variety of input sources such as image files, video files, directories, URL patterns, + webcam streams, and YouTube links. It also supports multiple model formats including PyTorch, ONNX, OpenVINO, + TensorRT, CoreML, TensorFlow, PaddlePaddle, and others. The results can be visualized in real-time or saved to + specified directories. Use command-line arguments to modify the behavior of the function. + + Examples: + ```python + # Run YOLOv3 inference on an image + run(weights='yolov5s.pt', source='data/images/bus.jpg') + + # Run YOLOv3 inference on a video + run(weights='yolov5s.pt', source='data/videos/video.mp4', view_img=True) + + # Run YOLOv3 inference on a webcam + run(weights='yolov5s.pt', source='0', view_img=True) + ``` + """ source = str(source) save_img = not nosave and not source.endswith(".txt") # save inference images is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) @@ -233,7 +286,41 @@ def run( def parse_opt(): - """Parses and returns command-line options for model inference configurations.""" + """ + Parses and returns command-line options for model inference configurations. + + Args: + --weights (list[str]): Model path or triton URL. Default: `ROOT / "yolov3-tiny.pt"`. + --source (str): File/directory/URL/glob/screen/0(webcam) for input data. Default: `ROOT / "data/images"`. + --data (str): (Optional) Path to dataset.yaml. Default: `ROOT / "data/coco128.yaml"`. + --imgsz (list[int]): Inference size as height, width. Accepts multiple values. Default: `[640]`. + --conf-thres (float): Confidence threshold for predictions. Default: `0.25`. + --iou-thres (float): IoU threshold for Non-Maximum Suppression (NMS). Default: `0.45`. + --max-det (int): Maximum number of detections per image. Default: `1000`. + --device (str): CUDA device to run the model on, e.g., `0` or `0,1,2,3` or `cpu`. Default: `""`. + --view-img (bool): Display results on the screen. Default: `False`. + --save-txt (bool): Save results to text files. Default: `False`. + --save-conf (bool): Save confidence scores in text labels. Default: `False`. + --save-crop (bool): Save cropped prediction boxes. Default: `False`. + --nosave (bool): Do not save images/videos. Default: `False`. + --classes (list[int]): Filter results by class, e.g., `--classes 0` or `--classes 0 2 3`. Default: `None`. + --agnostic-nms (bool): Perform class-agnostic NMS. Default: `False`. + --augment (bool): Perform augmented inference. Default: `False`. + --visualize (bool): Visualize features. Default: `False`. + --update (bool): Update all models. Default: `False`. + --project (str): Directory to save results, saved as "project/name". Default: `ROOT / "runs/detect"`. + --name (str): Directory name for saving results, e.g., "exp" in "project/name". Default: `"exp"`. + --exist-ok (bool): Allow results to be saved in an existing directory without incrementing. Default: `False`. + --line-thickness (int): Thickness of bounding box lines (in pixels). Default: `3`. + --hide-labels (bool): Hide labels on detected objects. Default: `False`. + --hide-conf (bool): Hide confidence scores on labels. Default: `False`. + --half (bool): Use FP16 half-precision inference. Default: `False`. + --dnn (bool): Use OpenCV DNN backend for ONNX inference. Default: `False`. + --vid-stride (int): Frame-rate stride for video input. Default: `1`. + + Returns: + argparse.Namespace: Parsed command-line arguments for inference configurations. + """ parser = argparse.ArgumentParser() parser.add_argument( "--weights", nargs="+", type=str, default=ROOT / "yolov3-tiny.pt", help="model path or triton URL" @@ -271,7 +358,53 @@ def parse_opt(): def main(opt): - """Entry point for running the model; checks requirements and calls `run` with parsed options.""" + """ + Entry point for running the model; checks requirements and calls `run` with parsed options. + + Args: + opt (argparse.Namespace): Parsed command-line options, which include: + - weights (str | list of str): Path to the model weights or Triton server URL. + - source (str): Input source, can be a file, directory, URL, glob, screen, or webcam index. + - data (str): Path to the dataset configuration file (.yaml). + - imgsz (tuple of int): Inference image size as (height, width). + - conf_thres (float): Confidence threshold for detections. + - iou_thres (float): Intersection over Union (IoU) threshold for Non-Maximum Suppression (NMS). + - max_det (int): Maximum number of detections per image. + - device (str): Device to run inference on; options are CUDA device id(s) or 'cpu' + - view_img (bool): Flag to display inference results. + - save_txt (bool): Save detection results in .txt format. + - save_conf (bool): Save detection confidences in .txt labels. + - save_crop (bool): Save cropped bounding box predictions. + - nosave (bool): Do not save images/videos with detections. + - classes (list of int): Filter results by class, e.g., --class 0 2 3. + - agnostic_nms (bool): Use class-agnostic NMS. + - augment (bool): Enable augmented inference. + - visualize (bool): Visualize feature maps. + - update (bool): Update the model during inference. + - project (str): Directory to save results. + - name (str): Name for the results directory. + - exist_ok (bool): Allow existing project/name directories without incrementing. + - line_thickness (int): Thickness of bounding box lines. + - hide_labels (bool): Hide class labels on bounding boxes. + - hide_conf (bool): Hide confidence scores on bounding boxes. + - half (bool): Use FP16 half-precision inference. + - dnn (bool): Use OpenCV DNN backend for ONNX inference. + - vid_stride (int): Video frame-rate stride. + + Returns: + None + + Example: + ```python + if __name__ == "__main__": + opt = parse_opt() + main(opt) + ``` + Notes: + Run this function as the entry point for using YOLOv3 for object detection on a variety of input sources such + as images, videos, directories, webcams, streams, etc. This function ensures all requirements are checked and + subsequently initiates the detection process by calling the `run` function with appropriate options. + """ check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) run(**vars(opt)) diff --git a/export.py b/export.py index 22ac1d5198..e30c4f0e7b 100644 --- a/export.py +++ b/export.py @@ -92,7 +92,25 @@ class iOSModel(torch.nn.Module): def __init__(self, model, im): - """Initializes an iOSModel with normalized input dimensions and number of classes from a torch model.""" + """ + Initializes an iOSModel with normalized input dimensions and number of classes from a PyTorch model. + + Args: + model (torch.nn.Module): The PyTorch model from which to initialize the iOS model. This should include + attributes like `nc` (number of classes) which will be used to configure the iOS model. + im (torch.Tensor): A Tensor representing a sample input image. The shape of this tensor should be (batch_size, + channels, height, width). This is used to extract dimensions for input normalization. + + Returns: + None + + Notes: + - This class is specifically designed for use in exporting a PyTorch model for deployment on iOS platforms, + optimizing input dimensions and class configurations to suit mobile requirements. + - Normalization factor is derived from the input image dimensions, which impacts the model's performance + during inference on iOS devices. + - Ensure the sample input image `im` provided has correct dimensions and shape for accurate model configuration. + """ super().__init__() b, c, h, w = im.shape # batch, channel, height, width self.model = model @@ -105,13 +123,61 @@ def __init__(self, model, im): # self.normalize = torch.tensor([1. / w, 1. / h, 1. / w, 1. / h]).expand(np, 4) # explicit (faster, larger) def forward(self, x): - """Performs forward pass, returns scaled confidences and normalized coordinates given input tensor `x`.""" + """ + Performs a forward pass, returning scaled confidences and normalized coordinates given an input tensor. + + Args: + x (torch.Tensor): Input tensor representing a batch of images, with dimensions [batch_size, channels, height, width]. + + Returns: + tuple[torch.Tensor, torch.Tensor, torch.Tensor]: A tuple containing three elements: + - xywh (torch.Tensor): Tensor of shape [batch_size, num_detections, 4] containing normalized x, y, width, + and height coordinates. + - conf (torch.Tensor): Tensor of shape [batch_size, num_detections, 1] containing confidence scores for each detection. + - cls (torch.Tensor): Tensor of shape [batch_size, num_detections, num_classes] containing class probabilities. + + Notes: + The dimensions of `x` should match the input dimensions used during the model's initialization to ensure proper + scaling and normalization. + + Examples: + ```python + model = iOSModel(trained_model, input_image_tensor) + detection_results = model.forward(input_tensor) + xywh, conf, cls = detection_results + ``` + + Further reading on exporting models to different formats: + https://github.com/ultralytics/ultralytics + + See Also: + `export.py` for exporting a YOLOv3 PyTorch model to various formats. + https://github.com/zldrobit for TensorFlow export scripts. + """ xywh, conf, cls = self.model(x)[0].squeeze().split((4, 1, self.nc), 1) return cls * conf, xywh * self.normalize # confidence (3780, 80), coordinates (3780, 4) def export_formats(): - """Lists supported YOLOv3 model export formats including file suffixes and CPU/GPU compatibility.""" + """ + Lists supported YOLOv3 model export formats including file suffixes and CPU/GPU compatibility. + + Returns: + list: A list of lists where each sublist contains information about a specific export format. + Each sublist includes the following elements: + - str: The name of the format. + - str: The command-line argument for including this format. + - str: The file suffix used for this format. + - bool: Indicates if the format is compatible with CPU. + - bool: Indicates if the format is compatible with GPU. + + Examples: + ```python + formats = export_formats() + for format in formats: + print(f"Format: {format[0]}, Suffix: {format[2]}, CPU Compatible: {format[3]}, GPU Compatible: {format[4]}") + ``` + """ x = [ ["PyTorch", "-", ".pt", True, True], ["TorchScript", "torchscript", ".torchscript", True, True], @@ -130,7 +196,28 @@ def export_formats(): def try_export(inner_func): - """Decorator to profile and log the export process of YOLOv3 models, handling successes and failures.""" + """ + Profiles and logs the export process of YOLOv3 models, capturing success or failure details. + + Args: + inner_func (Callable): The function that performs the actual export process and returns the model file path + and the exported model. + + Returns: + Callable: A wrapped function that profiles and logs the export process, handling successes and failures. + + Usage example: + + ```python + @try_export + def export_onnx(py_model_path: str, output_path: str): + # Export logic here + return output_path, model + ``` + + After applying this decorator, `export_onnx` will log the export results, including export success or failure along + with associated time and file size details. + """ inner_args = get_default_args(inner_func) def outer_func(*args, **kwargs): @@ -151,9 +238,40 @@ def outer_func(*args, **kwargs): @try_export def export_torchscript(model, im, file, optimize, prefix=colorstr("TorchScript:")): """ - Exports a YOLOv3 model to TorchScript format, optionally optimizing for mobile. + Exports a YOLOv3 model to TorchScript format, with optional optimization for mobile deployment. + + Args: + model (torch.nn.Module): The YOLOv3 model to be exported. + im (torch.Tensor): A tensor representing the input image for the model. + file (pathlib.Path): The file path where the TorchScript model will be saved. + optimize (bool): A boolean flag indicating whether to optimize the model for mobile. + prefix (str): A prefix for logging messages. Defaults to `colorstr("TorchScript:")`. + + Returns: + (pathlib.Path | None, torch.nn.Module | None): Tuple containing the path to the saved TorchScript model and the + model itself. Returns `(None, None)` if the export fails. + + Raises: + Exception: If there is an error during export, it logs the error and returns `(None, None)`. + + Notes: + The function uses torch.jit.trace to trace the model with the input image tensor (`im`). Required metadata such as + input shape, stride, and class names are saved in an extra file included in the TorchScript model. + + Examples: + ```python + from pathlib import Path + import torch - Args: model, im (input image), file (path), optimize (bool). + model = ... # Assume model is loaded or created + im = torch.randn(1, 3, 640, 640) # A sample input tensor + file = Path("model.torchscript") + optimize = True + + export_torchscript(model, im, file, optimize) + ``` + + For more information, visit: https://ultralytics.com/. """ LOGGER.info(f"\n{prefix} starting export with torch {torch.__version__}...") f = file.with_suffix(".torchscript") @@ -170,7 +288,21 @@ def export_torchscript(model, im, file, optimize, prefix=colorstr("TorchScript:" @try_export def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr("ONNX:")): - """Exports a YOLOv3 model to ONNX format with dynamic shapes and simplification options.""" + """ + Exports a YOLOv3 model to ONNX format with dynamic shape and simplification options. + + Args: + model (torch.nn.Module): The YOLOv3 model to be exported. + im (torch.Tensor): A sample input tensor for tracing the model. + file (pathlib.Path): The file path where the ONNX model will be saved. + opset (int): The ONNX opset version to use for the export. + dynamic (bool): If `True`, enables dynamic shape support. + simplify (bool): If `True`, simplifies the ONNX model using onnx-simplifier. + prefix (str): A prefix for logging messages. + + Returns: + tuple[pathlib.Path, None]: The path to the saved ONNX model, None as the second tuple element (kept for consistency). + """ check_requirements("onnx>=1.12.0") import onnx @@ -227,7 +359,31 @@ def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr("ONNX @try_export def export_openvino(file, metadata, half, int8, data, prefix=colorstr("OpenVINO:")): - """Exports a YOLOv3 model to OpenVINO format, with optional INT8 quantization and inference metadata.""" + """ + Exports a YOLOv3 model to OpenVINO format with optional INT8 quantization and inference metadata. + + Args: + file (Path): Path to the output file. + metadata (dict): Inference metadata to include in the exported model. + half (bool): Indicates if FP16 precision should be used. + int8 (bool): Indicates if INT8 quantization should be applied. + data (str): Path to the dataset file (.yaml) for post-training quantization. + + Returns: + tuple[Path | None, openvino.runtime.Model | None]: Tuple containing the path to the exported model and + the OpenVINO model object, or None if the export failed. + + Notes: + - Requires the `openvino-dev>=2023.0` and optional `nncf>=2.4.0` package for INT8 quantization. + - Refer to OpenVINO documentation for further details: https://docs.openvino.ai/latest/index.html. + + Examples: + ```python + model_file = Path('/path/to/model.onnx') + metadata = {'names': ['class1', 'class2'], 'stride': 32} + export_openvino(model_file, metadata, half=True, int8=False, data='/path/to/dataset.yaml') + ``` + """ check_requirements("openvino-dev>=2023.0") # requires openvino-dev: https://pypi.org/project/openvino-dev/ import openvino.runtime as ov # noqa from openvino.tools import mo # noqa @@ -294,8 +450,42 @@ def transform_fn(data_item): @try_export def export_paddle(model, im, file, metadata, prefix=colorstr("PaddlePaddle:")): - """Exports a YOLOv3 model to PaddlePaddle format using X2Paddle, saving to `file` directory with metadata in - yaml. + """ + Exports a YOLOv3 model to PaddlePaddle format using X2Paddle, saving to a specified directory and including model + metadata. + + Args: + model (torch.nn.Module): The YOLOv3 model to be exported. + im (torch.Tensor): A sample input tensor used for tracing the model. + file (pathlib.Path): Destination file path for the exported model, with `.pt` suffix. + metadata (dict): Additional metadata to be saved in YAML format alongside the exported model. + prefix (str, optional): Log message prefix. Defaults to a colored "PaddlePaddle:" string. + + Returns: + tuple: A tuple containing the directory path (str) where the PaddlePaddle model is saved, and `None`. + + Requirements: + - paddlepaddle: Install via `pip install paddlepaddle`. + - x2paddle: Install via `pip install x2paddle`. + + Notes: + The function first checks for required packages `paddlepaddle` and `x2paddle`. It then uses X2Paddle to trace + the model and export it to a PaddlePaddle format, saving the resulting files in the specified directory + with included metadata in a YAML file. + + Example: + ```python + from pathlib import Path + import torch + from models.yolo import DetectionModel + + model = DetectionModel() # Example model initialization + im = torch.rand(1, 3, 640, 640) # Example input tensor + file = Path("path/to/save/model.pt") + metadata = {"nc": 80, "names": ["class1", "class2", ...]} # Example metadata + + export_paddle(model, im, file, metadata) + ``` """ check_requirements(("paddlepaddle", "x2paddle")) import x2paddle @@ -311,7 +501,21 @@ def export_paddle(model, im, file, metadata, prefix=colorstr("PaddlePaddle:")): @try_export def export_coreml(model, im, file, int8, half, nms, prefix=colorstr("CoreML:")): - """Exports YOLOv3 model to CoreML format with optional quantization and NMS; requires 'coremltools'.""" + """ + Exports a YOLOv3 model to CoreML format with optional quantization and Non-Maximum Suppression (NMS). + + Args: + model (torch.nn.Module): The YOLOv3 model to be exported. + im (torch.Tensor): Input tensor used for tracing the model. + file (pathlib.Path): Destination file path where the CoreML model will be saved. + int8 (bool): Whether to use INT8 quantization or not. + half (bool): Whether to use FP16 quantization or not. + nms (bool): Whether to include Non-Maximum Suppression in the CoreML model or not. + prefix (str): Prefix string to add context to log messages. + + Returns: + str: Path to the saved CoreML model file (.mlmodel). + """ check_requirements("coremltools") import coremltools as ct @@ -337,9 +541,41 @@ def export_coreml(model, im, file, int8, half, nms, prefix=colorstr("CoreML:")): @try_export def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose=False, prefix=colorstr("TensorRT:")): """ - Exports a YOLOv3 model to TensorRT engine format. - - Nvidia TensorRT: https://developer.nvidia.com/tensorrt + Exports a YOLOv3 model to TensorRT engine format, optimizing it for GPU inference. + + Args: + model (torch.nn.Module): The YOLOv3 model to be exported. + im (torch.Tensor): Sample input tensor used for tracing the model. + file (Path): File path where the exported TensorRT engine will be saved. + half (bool): Whether to use FP16 precision. Requires a supported GPU. + dynamic (bool): Whether to use dynamic input shapes. + simplify (bool): Whether to simplify the model during the ONNX export. + workspace (int): The maximum workspace size in GB. Default is 4. + verbose (bool): Whether to print detailed export logs. + prefix (str): Prefix string for log messages. Default is "TensorRT:". + + Returns: + tuple: A tuple containing the output file path (Path) and None. + + Raises: + AssertionError: If the model is running on CPU instead of GPU. + RuntimeError: If the ONNX file failed to load. + + Notes: + Nvidia TensorRT: https://developer.nvidia.com/tensorrt + + Example: + ```python + from pathlib import Path + import torch + + # Initialize model and dummy input + model = YOLOv3(...) # or another correct initialization + im = torch.randn(1, 3, 640, 640) + + # Export the model + export_engine(model, im, Path("yolov3.engine"), half=True, dynamic=True, simplify=True) + ``` """ assert im.device.type != "cpu", "export running on CPU but must be on GPU, i.e. `python export.py --device 0`" try: @@ -415,7 +651,48 @@ def export_saved_model( keras=False, prefix=colorstr("TensorFlow SavedModel:"), ): - """Exports YOLOv3 model to TensorFlow SavedModel format; includes NMS and configuration options.""" + """ + Exports a YOLOv3 model to TensorFlow SavedModel format. The function includes options for post-processing like Non- + Max Suppression (NMS) and others. + + Args: + model (torch.nn.Module): The PyTorch model to be exported. + im (torch.Tensor): Input tensor with sample data to trace the model. + file (Path): Path to save the exported model. + dynamic (bool): Whether to export the model with dynamic shapes. + tf_nms (bool, optional): Whether to include TensorFlow NMS in the exported model. Defaults to False. + agnostic_nms (bool, optional): Whether to use class-agnostic NMS. Defaults to False. + topk_per_class (int, optional): Number of top-K predictions to keep per class after NMS. Defaults to 100. + topk_all (int, optional): Number of top-K predictions to keep overall after NMS. Defaults to 100. + iou_thres (float, optional): IoU threshold for NMS. Defaults to 0.45. + conf_thres (float, optional): Confidence threshold for NMS. Defaults to 0.25. + keras (bool, optional): Whether to save as a Keras model, retaining the original graph. Defaults to False. + prefix (str, optional): String prefix for log messages, formatted with color. Defaults to "TensorFlow SavedModel:". + + Returns: + Tuple[str, None]: Path to the saved model and None (to maintain consistency with other export functions). + + Raises: + ImportError: If the necessary TensorFlow libraries are not installed. + + Note: + - Ensure required libraries are installed: + `pip install tensorflow` or `tensorflow-cpu` or `tensorflow-macos` depending on your environment. + - Refer to https://github.com/ultralytics/yolov5 for more details and usage examples. + + Example: + ```python + from pathlib import Path + from models.common import DetectMultiBackend + import torch + + model = DetectMultiBackend(weights='yolov5s.pt') + im = torch.zeros(1, 3, 640, 640) + file = Path("output/saved_model") + + export_saved_model(model, im, file, dynamic=True) + ``` + """ # YOLOv3 TensorFlow SavedModel export try: import tensorflow as tf @@ -461,9 +738,30 @@ def export_saved_model( @try_export def export_pb(keras_model, file, prefix=colorstr("TensorFlow GraphDef:")): """ - Exports Keras model as TensorFlow GraphDef *.pb file, compatible with YOLOv3. - - See https://github.com/leimao/Frozen_Graph_TensorFlow for details. + Exports a Keras model to TensorFlow GraphDef (*.pb) format, which is compatible with YOLOv3. + + Args: + keras_model (tf.keras.Model): The trained Keras model to be exported. + file (pathlib.Path): The target file path for saving the exported model. + prefix (str, optional): Prefix string for logging. Defaults to colorstr("TensorFlow GraphDef:"). + + Returns: + tuple[pathlib.Path, None]: The file path where the model is saved and None. + + Example: + ```python + from tensorflow.keras.models import load_model + from pathlib import Path + export_pb(load_model('model.h5'), Path('model.pb')) + ``` + + See Also: + For more details on TensorFlow GraphDef, visit + https://github.com/leimao/Frozen_Graph_TensorFlow. + + Notes: + Ensure TensorFlow is properly installed in your environment as it is required for this function to execute. + TensorFlow's version should be compatible with the version used to train your model to avoid any compatibility issues. """ import tensorflow as tf from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2 @@ -481,7 +779,47 @@ def export_pb(keras_model, file, prefix=colorstr("TensorFlow GraphDef:")): @try_export def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=colorstr("TensorFlow Lite:")): - """Exports a YOLOv3 model to TensorFlow Lite format, supports fp16/int8, NMS options, and custom data.""" + """ + Export a YOLOv3 model to TensorFlow Lite format, supporting fp16/int8, NMS options, and custom data. + + Args: + keras_model (tf.keras.Model): The Keras model to be exported. + im (torch.Tensor): The input tensor used for model tracing. + file (Path): The file path where the exported model will be saved. + int8 (bool): Flag to enable INT8 quantization for the model. + data (str): Path to the dataset YAML file for representative data generation. + nms (bool): Flag to include Non-Max Suppression (NMS) in the exported model. + agnostic_nms (bool): Flag to apply class-agnostic NMS. + prefix (str, optional): Prefix string for logging. Defaults to colorstr("TensorFlow Lite:"). + + Returns: + (str, NoneType): The file path of the saved TensorFlow Lite model and None. + + Notes: + - TensorFlow dependency is required for model export. + - INT8 quantization requires a representative dataset for calibration. + - Non-Max Suppression (NMS) can be optionally included in the exported model. + + Examples: + ```python + import torch + from pathlib import Path + from models.experimental import attempt_load + + # Load and prepare model + model = attempt_load('yolov5s.pt', map_location='cpu') + im = torch.zeros(1, 3, 640, 640) # Dummy input tensor + + # Export model + export_tflite(model, im, Path('yolov5s'), int8=False, data=None, nms=True, agnostic_nms=False) + ``` + + TensorFlow Lite Developer Guide: + https://www.tensorflow.org/lite/guide + + Model Conversion Reference: + https://github.com/leimao/Frozen_Graph_TensorFlow + """ import tensorflow as tf LOGGER.info(f"\n{prefix} starting export with tensorflow {tf.__version__}...") @@ -514,9 +852,35 @@ def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=c @try_export def export_edgetpu(file, prefix=colorstr("Edge TPU:")): """ - Exports YOLOv3 model to Edge TPU compatible format; requires Linux and Edge TPU compiler. - - https://coral.ai/docs/edgetpu/compiler/ + Exports YOLOv3 model to Edge TPU compatible format. + + Args: + file (Path): The file path for the model to be exported, with a `.pt` suffix. + prefix (str): A prefix used for logging, default is 'Edge TPU:'. + + Returns: + Tuple[Path | None, None]: The tuple contains the file path of the exported model with `-int8_edgetpu.tflite` suffix + if successful, otherwise returns `None`. + + Raises: + AssertionError: If the export is not executed on a Linux system. + subprocess.CalledProcessError: If there are issues with subprocess execution, particularly around Edge TPU compiler + installation or execution. + + Notes: + This function requires Linux and the Edge TPU compiler. If the compiler is not installed, it attempts to install it. + For more details, refer to the Edge TPU compiler documentation: + https://coral.ai/docs/edgetpu/compiler/ + + Example: + ```python + from pathlib import Path + from ultralytics import export_edgetpu + + model_file = Path('yolov5s.pt') + exported_model, _ = export_edgetpu(model_file) + print(f"Model exported to {exported_model}") + ``` """ cmd = "edgetpu_compiler --version" help_url = "https://coral.ai/docs/edgetpu/compiler/" @@ -555,7 +919,48 @@ def export_edgetpu(file, prefix=colorstr("Edge TPU:")): @try_export def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): - """Exports a YOLOv3 model to TensorFlow.js format, optionally quantizing to uint8.""" + """ + Exports a YOLOv3 model to TensorFlow.js format, with an optional quantization to uint8. + + Args: + file (Path): The path to the model file to be exported. + int8 (bool): Boolean flag to determine if the model should be quantized to uint8. + prefix (str): String prefix for logging, by default "TensorFlow.js". + + Returns: + tuple: + str: Directory path where the TensorFlow.js files are saved. + None: Placeholder to match the expected return type from 'try_export' decorator. + + Raises: + ImportError: If the required 'tensorflowjs' package is not installed. + + Requirements: + - tensorflowjs: Install with `pip install tensorflowjs` + + Example: + ```python + from pathlib import Path + export_tfjs(file=Path("yolov5s.pt"), int8=False) + ``` + + Note: + Ensure that you have TensorFlow.js installed in your environment. For more details, visit the official + TensorFlow.js documentation at https://www.tensorflow.org/js. + + Usage: + The converted model can be used directly in JavaScript environments using the TensorFlow.js library. + + For usage in web applications: + - Clone the example repository: + $ cd .. && git clone https://github.com/zldrobit/tfjs-yolov5-example.git && cd tfjs-yolov5-example + - Install dependencies: + $ npm install + - Create a symbolic link to the exported web model: + $ ln -s ../../yolov5/yolov5s_web_model public/yolov5s_web_model + - Start the example application: + $ npm star + """ check_requirements("tensorflowjs") import tensorflowjs as tfjs @@ -592,7 +997,32 @@ def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): def add_tflite_metadata(file, metadata, num_outputs): - """Adds TFLite model metadata for enhanced model understanding and processing; requires `tflite_support`.""" + """ + Adds metadata to a TensorFlow Lite model to enhance model understanding and processing using `tflite_support`. + + Args: + file (str): The path to the TensorFlow Lite model file. + metadata (dict): A dictionary containing metadata information such as labels, input/output descriptions, etc. + num_outputs (int): The number of output tensors in the model. + + Returns: + None. + + Raises: + ImportError: If the `tflite_support` library is not available. + + Note: + This function uses the `tflite_support` library to add the metadata. The library must be installed separately. + + Example: + ```python + metadata = { + "input": {"description": "Input image tensor"}, + "output": [{"name": "scores", "description": "Detection scores"}], + } + add_tflite_metadata("/path/to/model.tflite", metadata, num_outputs=1) + ``` + """ with contextlib.suppress(ImportError): # check_requirements('tflite_support') from tflite_support import flatbuffers @@ -625,8 +1055,34 @@ def add_tflite_metadata(file, metadata, num_outputs): def pipeline_coreml(model, im, file, names, y, prefix=colorstr("CoreML Pipeline:")): - """Executes YOLOv3 CoreML pipeline, handling image preprocessing, prediction, and NMS, saving the model with - metadata. + """ + Executes YOLOv3 CoreML pipeline, handling image preprocessing, prediction, and NMS, saving the model with metadata. + + Args: + model (coremltools.models.MLModel): The CoreML model to be used for the prediction. + im (torch.Tensor): Input tensor in BCHW (Batch, Channel, Height, Width) format. + file (pathlib.Path): The file path where the exported CoreML model will be saved. + names (dict): Dictionary mapping class indices to class names. + y (torch.Tensor): YOLO model output tensor. + prefix (str): Optional prefix for logging messages; default is 'CoreML Pipeline:'. + + Returns: + (pathlib.Path | None): The file path of the saved CoreML model if successful; None otherwise. + + Example: + ```python + from pathlib import Path + import torch + from coremltools.models import MLModel + + model = MLModel('path/to/pretrained/model.mlmodel') + im = torch.randn(1, 3, 640, 640) # Example input tensor + file = Path('path/to/save/model.mlmodel') + names = {0: 'class0', 1: 'class1'} + y = torch.randn(1, 25200, 85) # Example output tensor + + pipeline_coreml(model, im, file, names, y) + ``` """ import coremltools as ct from PIL import Image @@ -782,7 +1238,55 @@ def run( iou_thres=0.45, # TF.js NMS: IoU threshold conf_thres=0.25, # TF.js NMS: confidence threshold ): - """Exports a PyTorch model to specified formats like ONNX, CoreML, TensorRT.""" + """ + Export a PyTorch model to various formats like ONNX, CoreML, and TensorRT. + + Args: + data (str | Path): Path to dataset configuration file. + weights (str | Path): Path to model weights file in PyTorch format. + imgsz (tuple[int, int]): Tuple specifying image height and width for input dimensions. + batch_size (int): Batch size for model inference. + device (str): Device to use for inference (e.g., '0', '0,1,2,3', 'cpu'). + include (tuple[str]): Formats to include for model export (e.g., 'torchscript', 'onnx', etc.). + half (bool): Whether to export model with FP16 precision. + inplace (bool): Set YOLOv3 Detect module inplace option to True. + keras (bool): Save Keras model when exporting TensorFlow SavedModel format. + optimize (bool): Optimize the TorchScript model for mobile inference. + int8 (bool): Apply INT8 quantization for CoreML/TF models. + dynamic (bool): Enable dynamic axes for ONNX/TF/TensorRT models. + simplify (bool): Simplify the ONNX model after export. + opset (int): ONNX opset version. + verbose (bool): Enable verbose logging for TensorRT engine export. + workspace (int): Workspace size in GB for TensorRT engine. + nms (bool): Enable Non-Maximum Suppression (NMS) in TensorFlow models. + agnostic_nms (bool): Enable class-agnostic NMS in TensorFlow models. + topk_per_class (int): Top-K per class to keep in TensorFlow JSON model. + topk_all (int): Top-K for all classes to keep in TensorFlow JSON model. + iou_thres (float): IOU threshold for TensorFlow JSON model. + conf_thres (float): Confidence threshold for TensorFlow JSON model. + + Returns: + None + + Notes: + - Requires various packages installed for different export formats, e.g., `onnx`, `coremltools`, etc. + - Some formats have additional dependencies (e.g., TensorFlow, TensorRT, etc.) + + Examples: + ```python + run( + data='data/coco128.yaml', + weights='yolov5s.pt', + imgsz=(640, 640), + batch_size=1, + device='cpu', + include=('torchscript', 'onnx'), + half=False, + dynamic=True, + opset=12 + ) + ``` + """ t = time.time() include = [x.lower() for x in include] # to lowercase fmts = tuple(export_formats()["Argument"][1:]) # --include arguments @@ -893,8 +1397,19 @@ def run( def parse_opt(known=False): - """Parses command line arguments for model export configuration, including data paths, weights, and export - options. + """ + Parses command line arguments for model export configuration, allowing users to specify various export options. + + Args: + known (bool): If True, parse only known arguments and ignore others. Default is False. + + Returns: + argparse.Namespace: An object containing all the configured arguments and their values. + + Notes: + This function uses `argparse` to define and process command line arguments. It supports multiple model export formats + including TorchScript, ONNX, OpenVINO, TensorRT, and others. Users can set various options like image size, batch size, + device, and thresholds for NMS. """ parser = argparse.ArgumentParser() parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="dataset.yaml path") @@ -930,7 +1445,43 @@ def parse_opt(known=False): def main(opt): - """Executes model inference, supporting various export formats based on specified weights and options.""" + """ + Main function for exporting a YOLOv3 PyTorch model to various formats. + + This function parses command line arguments to configure export options and then proceeds to export + the YOLOv3 model to specified formats such as TorchScript, ONNX, CoreML, TensorRT, and more. + + Args: + opt (argparse.Namespace): Parsed command line arguments containing export configurations such as: + data (str): Path to dataset YAML file. + weights (int | str): Path(s) to model weights file(s). + imgsz (tuple[int, int]): Image dimensions (height, width). + batch_size (int): Batch size for export. + device (str): Device to use for export, e.g., 'cpu' or '0' for GPU. + include (list[int | str]): List of formats to export, e.g., ['torchscript', 'onnx']. + half (bool): If True, export model in FP16 half-precision. + inplace (bool): If True, set YOLOv3 Detect() inplace=True. + keras (bool): If True, use Keras for TensorFlow SavedModel export. + optimize (bool): If True, optimize TorchScript model for mobile. + int8 (bool): If True, enable INT8 quantization for CoreML and TensorFlow. + dynamic (bool): If True, enable dynamic axes for ONNX, TensorRT, and TensorFlow. + simplify (bool): If True, simplify ONNX model using onnx-simplifier. + opset (int): ONNX opset version to use. + verbose (bool): If True, enable verbose logging for TensorRT export. + workspace (int): Workspace size in GB for TensorRT export. + nms (bool): If True, add Non-Max Suppression (NMS) to TensorFlow model. + agnostic_nms (bool): If True, add class-agnostic NMS to TensorFlow model. + topk_per_class (int): Top-k per class to keep for TensorFlow.js NMS. + topk_all (int): Top-k for all classes to keep for TensorFlow.js NMS. + iou_thres (float): IoU threshold for TensorFlow.js NMS. + conf_thres (float): Confidence threshold for TensorFlow.js NMS. + + Returns: + list[str]: List of paths to the exported model(s). + + Example: + $ python export.py --weights yolov5s.pt --include torchscript onnx openvino engine coreml tflite ... + """ for opt.weights in opt.weights if isinstance(opt.weights, list) else [opt.weights]: run(**vars(opt)) diff --git a/hubconf.py b/hubconf.py index 89c47a0721..d701c2d4c7 100644 --- a/hubconf.py +++ b/hubconf.py @@ -15,19 +15,31 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): """ - Creates or loads a YOLOv3 model. - - Arguments: - name (str): model name 'yolov5s' or path 'path/to/best.pt' - pretrained (bool): load pretrained weights into the model - channels (int): number of input channels - classes (int): number of model classes - autoshape (bool): apply YOLOv3 .autoshape() wrapper to model - verbose (bool): print all information to screen - device (str, torch.device, None): device to use for model parameters + Creates or loads a YOLOv3 model with specified configurations and optional pretrained weights. + + Args: + name (str): Model name such as 'yolov5s' or a path to a model checkpoint file, e.g., 'path/to/best.pt'. + pretrained (bool): Whether to load pretrained weights into the model. Default is True. + channels (int): Number of input channels. Default is 3. + classes (int): Number of model classes. Default is 80. + autoshape (bool): Whether to apply the YOLOv3 .autoshape() wrapper to the model for handling multiple input types. + Default is True. + verbose (bool): If True, print all information to the screen. Default is True. + device (str | torch.device | None): Device to use for model parameters ('cpu', 'cuda', etc.). If None, defaults to + the best available device. Returns: - YOLOv3 model + torch.nn.Module: YOLOv3 model loaded with or without pretrained weights. + + Example: + ```python + import torch + model = _create('yolov5s') + ``` + + Raises: + Exception: If an error occurs while loading the model, returns an error message with a helpful URL: + "https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading". """ from pathlib import Path @@ -84,71 +96,325 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbo def custom(path="path/to/model.pt", autoshape=True, _verbose=True, device=None): - """Loads a custom or local YOLOv3 model from a specified path, with options for autoshaping and device - assignment. + """ + Loads a custom or local YOLOv3 model from a specified path, with options for autoshaping and device assignment. + + Args: + path (str): Path to the model file. Supports both local and URL paths. + autoshape (bool): If True, applies the YOLOv3 `.autoshape()` wrapper to allow for various input formats. + _verbose (bool): If True, outputs detailed information. Otherwise, limits verbosity. + device (str | torch.device | None): Device to load the model on. Default is None, which uses the available GPU if + possible. + + Returns: + torch.nn.Module: The loaded YOLOv3 model, either with or without autoshaping applied. + + Raises: + Exception: If the model loading fails due to invalid path or incompatible model state, with helpful suggestions + including a reference to the troubleshooting page: + https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading + + Examples: + ```python + import torch + model = torch.hub.load('ultralytics/yolov5', 'custom', 'path/to/best.pt') + model = torch.hub.load('ultralytics/yolov5', 'custom', 'path/to/best.pt', autoshape=False, device='cpu') + ``` """ return _create(path, autoshape=autoshape, verbose=_verbose, device=device) def yolov5n(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """Instantiates YOLOv5n model; optional pretrained weights, class/channel count, autoshaping, device selection.""" + """ + Instantiates a YOLOv5n model with optional pretrained weights, configurable input channels, classes, autoshaping, + and device selection. + + Args: + pretrained (bool): If True, loads pretrained weights into the model. Defaults to True. + channels (int): Number of input channels. Defaults to 3. + classes (int): Number of detection classes. Defaults to 80. + autoshape (bool): If True, applies YOLOv5 .autoshape() wrapper to the model for various formats (file/URI/PIL/cv2/np) + and non-maximum suppression (NMS). Defaults to True. + _verbose (bool): If True, prints detailed information to the screen. Defaults to True. + device (str | torch.device | None): Device to use for model computations (e.g., 'cpu', 'cuda'). If None, the best + available device is automatically selected. Defaults to None. + + Returns: + torch.nn.Module: The instantiated YOLOv5n model. + + Example: + ```python + import torch + model = torch.hub.load('ultralytics/yolov5', 'yolov5n') # using official model + model = torch.hub.load('ultralytics/yolov5:master', 'yolov5n') # from specific branch + model = torch.hub.load('ultralytics/yolov5', 'custom', 'yolov5n.pt') # using custom/local model + model = torch.hub.load('.', 'custom', 'yolov5n.pt', source='local') # from local repository + ``` + """ return _create("yolov5n", pretrained, channels, classes, autoshape, _verbose, device) def yolov5s(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """Loads YOLOv5s model, with options for pretrained weights, channel/class customization, autoshaping, and device - choice. + """ + Loads the YOLOv5s model with customizable options for pretrained weights, input channels, number of classes, + autoshape functionality, and device selection. + + Args: + pretrained (bool, optional): If True, loads model with pretrained weights. Default is True. + channels (int, optional): Specifies the number of input channels. Default is 3. + classes (int, optional): Defines the number of model classes. Default is 80. + autoshape (bool, optional): Applies YOLOv5 .autoshape() wrapper to the model for enhanced usability. Default is + True. + _verbose (bool, optional): If True, prints detailed information during model loading. Default is True. + device (str | torch.device | None, optional): Specifies the device to load the model on. Accepts 'cpu', 'cuda', or + torch.device. Default is None, which automatically selects the best available option. + + Returns: + torch.nn.Module: The initialized YOLOv5s model loaded with the specified options. + + Example: + ```python + import torch + model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True) + ``` + + For more information, refer to [PyTorch Hub models](https://pytorch.org/hub/ultralytics_yolov5). """ return _create("yolov5s", pretrained, channels, classes, autoshape, _verbose, device) def yolov5m(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """Loads YOLOv5m model with optional pretrained weights, channel/class customization, autoshaping, device + """ + Loads YOLOv5m model with options for pretrained weights, channel/class customization, autoshaping, and device selection. + + Args: + pretrained (bool, optional): If True, loads pretrained weights into the model. Default is True. + channels (int, optional): Number of input channels for the model. Default is 3. + classes (int, optional): Number of classes for the model. Default is 80. + autoshape (bool, optional): If True, applies the YOLOv3 .autoshape() wrapper to the model for convenient input + handling. Default is True. + _verbose (bool, optional): If True, prints all information to the screen. Default is True. + device (str | torch.device | None, optional): Device to use for model parameters. Default is None, which + automatically selects the available device. + + Returns: + torch.nn.Module: YOLOv5m model instance. + + Example: + ```python + import torch + model = yolov5m(pretrained=True, channels=3, classes=80, autoshape=True, device='cuda:0') + ``` """ return _create("yolov5m", pretrained, channels, classes, autoshape, _verbose, device) def yolov5l(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """Loads YOLOv5l model with options for pretrained weights, channel/class customization, autoshaping, and device - selection. + """ + Loads the YOLOv5l model with options for pretrained weights, channel and class customization, autoshaping, and + device selection. + + Args: + pretrained (bool, optional): If True, loads the model with pretrained weights. Defaults to True. + channels (int, optional): Number of input channels. Defaults to 3. + classes (int, optional): Number of model classes. Defaults to 80. + autoshape (bool, optional): If True, applies YOLOv5's .autoshape() wrapper to the model. Defaults to True. + _verbose (bool, optional): If True, prints detailed information during model loading. Defaults to True. + device (str | torch.device | None, optional): Device to use for model parameters, e.g., 'cpu', 'cuda:0', + or torch.device object. If None, automatically selects the appropriate device. Defaults to None. + + Returns: + torch.nn.Module: The initialized YOLOv5l model. + + Example: + ```python + import torch + model = torch.hub.load('ultralytics/yolov5', 'yolov5l', pretrained=True) + ``` """ return _create("yolov5l", pretrained, channels, classes, autoshape, _verbose, device) def yolov5x(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """Loads YOLOv5x model with customization options for weights, channels, classes, autoshaping, and device - selection. + """ + Loads YOLOv5x model with customization options for weights, channels, classes, autoshaping, and device selection. + + Args: + pretrained (bool, optional): Whether to load pretrained weights. Defaults to True. + channels (int, optional): Number of input channels. Defaults to 3. + classes (int, optional): Number of model classes. Defaults to 80. + autoshape (bool, optional): Whether to apply YOLOv3 .autoshape() wrapper to the model. Defaults to True. + _verbose (bool, optional): Whether to print all information to the screen. Defaults to True. + device (str | torch.device | None, optional): Device to use for model parameters, e.g., 'cpu', 'cuda', or + torch.device(). If None, default device will be selected. Defaults to None. + + Returns: + torch.nn.Module: The YOLOv5x model. + + Examples: + ```python + import torch + + # Load YOLOv5x model with default settings + model = torch.hub.load('ultralytics/yolov5', 'yolov5x') + + # Load YOLOv5x model with custom device + model = torch.hub.load('ultralytics/yolov5', 'yolov5x', device='cuda:0') + ``` """ return _create("yolov5x", pretrained, channels, classes, autoshape, _verbose, device) def yolov5n6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """Loads the YOLOv5n6 model with options for weights, channels, classes, shaping, and device.""" + """ + Loads the YOLOv5n6 model with options for pretrained weights, input channels, classes, autoshaping, verbosity, and + device assignment. + + Args: + pretrained (bool, optional): If True, loads pretrained weights into the model. Default is True. + channels (int, optional): Number of input channels. Default is 3. + classes (int, optional): Number of model classes. Default is 80. + autoshape (bool, optional): If True, applies the YOLOv3 .autoshape() wrapper to the model. Default is True. + _verbose (bool, optional): If True, prints all information to the screen. Default is True. + device (str | torch.device | None, optional): Device to use for model parameters, e.g., 'cpu', '0', or torch.device. + Default is None. + + Returns: + torch.nn.Module: YOLOv5n6 model loaded on the specified device and configured as per the provided options. + + Notes: + For more information on PyTorch Hub models, refer to: https://pytorch.org/hub/ultralytics_yolov5 + + Example: + ```python + model = yolov5n6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device='cuda') + ``` + """ return _create("yolov5n6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5s6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """Loads the YOLOv5s6 model; see options for weights, channels, classes, - at https://github.com/ultralytics/yolov5.""" + """ + Loads the YOLOv5s6 model with options for weights, channels, classes, autoshaping, and device selection. + + Args: + pretrained (bool, optional): If True, loads pretrained weights into the model. Defaults to True. + channels (int, optional): Number of input channels. Defaults to 3. + classes (int, optional): Number of model classes. Defaults to 80. + autoshape (bool, optional): Apply YOLOv5 .autoshape() wrapper to model. Defaults to True. + _verbose (bool, optional): If True, prints detailed information to the screen. Defaults to True. + device (str | torch.device | None, optional): Device to use for model parameters, e.g., 'cpu', 'cuda:0'. + If None, it will select the appropriate device automatically. Defaults to None. + + Returns: + torch.nn.Module: The YOLOv5s6 model, ready for inference or further training. + + Example: + ```python + import torch + model = torch.hub.load('ultralytics/yolov5', 'yolov5s6', pretrained=True, channels=3, classes=80) + model.eval() # Set the model to evaluation mode + ``` + + For more details, see the official documentation at: + https://github.com/ultralytics/yolov5 + """ return _create("yolov5s6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5m6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """Loads YOLOv5m6 model; options for weights, channels, classes documented at - https://github.com/ultralytics/yolov5.""" + """ + Loads YOLOv5m6 model with options for pretrained weights, input channels, number of classes, autoshaping, and device + selection. + + Args: + pretrained (bool): Whether to load pretrained weights into the model. Default is True. + channels (int): Number of input channels. Default is 3. + classes (int): Number of model classes. Default is 80. + autoshape (bool): Whether to apply YOLOv3 .autoshape() wrapper to the model. Default is True. + _verbose (bool): Whether to print all information to the screen. Default is True. + device (str | torch.device | None): Device to use for model parameters, e.g., 'cpu', 'cuda', 'mps', or torch device. + Default is None. + + Returns: + YOLOv5m6 model (torch.nn.Module): The instantiated YOLOv5m6 model with specified options. + + Example: + ```python + import torch + model = torch.hub.load('ultralytics/yolov5', 'yolov5m6') + # Load custom YOLOv5m6 model from a local path with specific options + model = torch.hub.load('.', 'yolov5m6', pretrained=False, channels=1, classes=10, device='cuda') + ``` + + Notes: + For more detailed documentation, visit https://github.com/ultralytics/yolov5 + """ return _create("yolov5m6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5l6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """Loads YOLOv5l6 model with customization for pretraining, channels, classes; details at - https://github.com/ultralytics/yolov5.""" + """ + Loads the YOLOv5l6 model with options for pretrained weights, input channels, the number of classes, autoshaping, + and device selection. + + Args: + pretrained (bool, optional): If True, loads pretrained weights into the model. Default is True. + channels (int, optional): Number of input channels. Default is 3. + classes (int, optional): Number of model classes. Default is 80. + autoshape (bool, optional): If True, applies the YOLOv5 .autoshape() wrapper to the model for automatic shape + inference. Default is True. + _verbose (bool, optional): If True, prints all information to the screen. Default is True. + device (str | torch.device | None, optional): Device to use for the model parameters, e.g., 'cpu', 'cuda', or + a specific GPU like 'cuda:0'. Default is None, which means the best available device will be selected + automatically. + + Returns: + yolov5.models.yolo.DetectionModel: YOLOv5l6 model initialized with defined custom configurations. + + Examples: + ```python + import torch + model = torch.hub.load('ultralytics/yolov5', 'yolov5l6') # Load YOLOv5l6 model + ``` + + Note: + For more details, visit the [Ultralytics YOLOv5 GitHub repository](https://github.com/ultralytics/yolov5). + """ return _create("yolov5l6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5x6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """Loads the YOLOv5x6 model, allowing customization for channels and classes; more at - https://github.com/ultralytics/yolov5.""" + """ + Loads the YOLOv5x6 model, allowing customization for pretrained weights, input channels, and model classes. + + Args: + pretrained (bool): If True, loads the model with pretrained weights. Default is True. + channels (int): Number of input channels. Default is 3. + classes (int): Number of output classes for the model. Default is 80. + autoshape (bool): If True, applies the .autoshape() wrapper for inference on diverse input formats. Default is True. + _verbose (bool): If True, prints detailed information during model loading. Default is True. + device (str | torch.device | None): Specifies the device to load the model on ('cpu', 'cuda', etc.). Default is None, + which uses the best available device. + + Returns: + torch.nn.Module: The YOLOv5x6 model with the specified configurations. + + Example: + ```python + from ultralytics import yolov5x6 + + # Load the model with default settings + model = yolov5x6() + + # Load the model with custom configurations + model = yolov5x6(pretrained=False, channels=1, classes=10, autoshape=False, device='cuda') + ``` + + Notes: + For more information, refer to the YOLOv5 repository: https://github.com/ultralytics/yolov5 + """ return _create("yolov5x6", pretrained, channels, classes, autoshape, _verbose, device) diff --git a/train.py b/train.py index 708fc9670b..cbdce77f6f 100644 --- a/train.py +++ b/train.py @@ -101,8 +101,52 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary - """Trains a model with given hyperparameters, options, device, and callbacks, saving results and weights as - specified. + """ + Train a YOLOv3 model on a custom dataset and manage the training process. + + Args: + hyp (str | dict): Path to hyperparameters yaml file or hyperparameters dictionary. + opt (argparse.Namespace): Parsed command line arguments containing training options. + device (torch.device): Device to load and train the model on. + callbacks (Callbacks): Callbacks to handle various stages of the training lifecycle. + + Returns: + None + + Usage - Single-GPU training: + $ python train.py --data coco128.yaml --weights yolov5s.pt --img 640 # from pretrained (recommended) + $ python train.py --data coco128.yaml --weights '' --cfg yolov5s.yaml --img 640 # from scratch + + Usage - Multi-GPU DDP training: + $ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 train.py --data coco128.yaml --weights yolov5s.pt --img 640 --device 0,1,2,3 + + Models: https://github.com/ultralytics/yolov5/tree/master/models + Datasets: https://github.com/ultralytics/yolov5/tree/master/data + Tutorial: https://docs.ultralytics.com/yolov5/tutorials/train_custom_data + + Examples: + ```python + from ultralytics import train + import argparse + import torch + from utils.callbacks import Callbacks + + # Example usage + args = argparse.Namespace( + data='coco128.yaml', + weights='yolov5s.pt', + cfg='yolov5s.yaml', + img_size=640, + epochs=50, + batch_size=16, + device='0' + ) + + device = torch.device(f'cuda:{args.device}' if torch.cuda.is_available() else 'cpu') + callbacks = Callbacks() + + train(hyp='hyp.scratch.yaml', opt=args, device=device, callbacks=callbacks) + ``` """ save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = ( Path(opt.save_dir), @@ -499,7 +543,30 @@ def lf(x): def parse_opt(known=False): - """Parses command line arguments for training configurations, with facilities for known arg parsing.""" + """ + Parses command line arguments for configuring the training of a YOLO model. + + Args: + known (bool): Flag to parse known arguments only, defaults to False. + + Returns: + argparse.Namespace: Parsed command line arguments. + + Examples: + ```python + options = parse_opt() + print(options.weights) + ``` + + Notes: + * The default weights path is 'yolov3-tiny.pt'. + * Set `known` to True for parsing only the known arguments, useful for partial arguments. + + References: + * Models: https://github.com/ultralytics/yolov5/tree/master/models + * Datasets: https://github.com/ultralytics/yolov5/tree/master/data + * Training Tutorial: https://docs.ultralytics.com/yolov5/tutorials/train_custom_data + """ parser = argparse.ArgumentParser() parser.add_argument("--weights", type=str, default=ROOT / "yolov3-tiny.pt", help="initial weights path") parser.add_argument("--cfg", type=str, default="", help="model.yaml path") @@ -546,7 +613,39 @@ def parse_opt(known=False): def main(opt, callbacks=Callbacks()): - """Main training/evolution script handling model checks, DDP setup, training, and hyperparameter evolution.""" + """ + Main training/evolution script handling model checks, DDP setup, training, and hyperparameter evolution. + + Args: + opt (argparse.Namespace): Parsed command-line options. + callbacks (Callbacks, optional): Callback object for handling training events. Defaults to Callbacks(). + + Returns: + None + + Raises: + AssertionError: If certain constraints are violated (e.g., when specific options are incompatible with DDP training). + + Notes: + - For tutorial on using Multi-GPU with DDP: https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training + + Example: + Single-GPU training: + ```python + $ python train.py --data coco128.yaml --weights yolov5s.pt --img 640 # from pretrained (recommended) + $ python train.py --data coco128.yaml --weights '' --cfg yolov5s.yaml --img 640 # from scratch + ``` + + Multi-GPU DDP training: + ```python + $ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 train.py --data coco128.yaml \ + --weights yolov5s.pt --img 640 --device 0,1,2,3 + ``` + + Models: https://github.com/ultralytics/yolov5/tree/master/models + Datasets: https://github.com/ultralytics/yolov5/tree/master/data + Tutorial: https://docs.ultralytics.com/yolov5/tutorials/train_custom_data + """ if RANK in {-1, 0}: print_args(vars(opt)) check_git_status() @@ -712,8 +811,39 @@ def main(opt, callbacks=Callbacks()): def run(**kwargs): - """Executes model training with specified configurations; see example: import train; train.run(data='coco128.yaml', - imgsz=320, weights='yolov5m.pt'). + """ + Executes model training with specified configurations. + + Args: + kwargs (dict): Configuration parameters for the training process. Supported parameters include but are not limited to: + - data (str): Path to the dataset YAML file. + - weights (str): Path to initial weights file. + - imgsz (int): Image size for training and validation. + - epochs (int): Number of training epochs. + - batch_size (int): Total batch size for all GPUs. + + Returns: + None + + Notes: + - Ensure that the provided dataset YAML file and the initial weights path are accessible. + - For multi-GPU training, use appropriate distributed training settings. + - Example usage: + ```python + run(data='coco128.yaml', imgsz=320, weights='yolov5m.pt') + ``` + + Example: + To execute model training with custom configurations: + ```python + from train import run + run(data='coco128.yaml', imgsz=320, weights='yolov5m.pt') + ``` + + References: + - Models: https://github.com/ultralytics/yolov5/tree/master/models + - Datasets: https://github.com/ultralytics/yolov5/tree/master/data + - Tutorial: https://docs.ultralytics.com/yolov5/tutorials/train_custom_data """ opt = parse_opt(True) for k, v in kwargs.items(): diff --git a/val.py b/val.py index 8d6c06aa68..775282d50d 100644 --- a/val.py +++ b/val.py @@ -62,8 +62,38 @@ def save_one_txt(predn, save_conf, shape, file): - """Saves detection results in txt format; includes labels and optionally confidence scores if `save_conf` is - True. + """ + Saves detection results in a text format, including labels and optionally confidence scores. + + Args: + predn (torch.Tensor): A tensor containing normalized prediction results in the format (x1, y1, x2, y2, conf, cls). + save_conf (bool): A flag indicating whether to save confidence scores. + shape (tuple[int, int]): Original image shape in the format (height, width). + file (str | Path): Path to the file where the results will be saved. + + Returns: + None + + Example: + ```python + from pathlib import Path + import torch + + predn = torch.tensor([ + [10, 20, 100, 200, 0.9, 1], + [30, 40, 150, 250, 0.8, 0], + ]) + save_conf = True + shape = (416, 416) + file = Path("results.txt") + + save_one_txt(predn, save_conf, shape, file) + ``` + + Notes: + - The function normalizes bounding box coordinates before saving. + - Each line in the output file will contain class, x-center, y-center, width, height and optionally confidence score. + - The format is compatible with YOLO training dataset format. """ gn = torch.tensor(shape)[[1, 0, 1, 0]] # normalization gain whwh for *xyxy, conf, cls in predn.tolist(): @@ -74,7 +104,28 @@ def save_one_txt(predn, save_conf, shape, file): def save_one_json(predn, jdict, path, class_map): - """Saves detection results in JSON format containing image_id, category_id, bbox, and score per detection.""" + """ + Saves detection results in JSON format containing image_id, category_id, bbox, and score per detection. + + Args: + predn (torch.Tensor): Normalized prediction tensor of shape (N, 6) where N is the number of detections. + Each detection should contain (x1, y1, x2, y2, confidence, class). + jdict (list): List to store the JSON serializable detections. + path (Path): Path object representing the image file path. + class_map (dict[int, int]): Dictionary mapping class indices to their respective category IDs. + + Returns: + None + + Example: + ```python + predn = torch.tensor([[50, 30, 200, 150, 0.9, 0], [30, 20, 180, 150, 0.8, 1]]) + jdict = [] + path = Path('images/000001.jpg') + class_map = {0: 1, 1: 2} + save_one_json(predn, jdict, path, class_map) + ``` + """ image_id = int(path.stem) if path.stem.isnumeric() else path.stem box = xyxy2xywh(predn[:, :4]) # xywh box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner @@ -91,12 +142,31 @@ def save_one_json(predn, jdict, path, class_map): def process_batch(detections, labels, iouv): """ - Return correct prediction matrix - Arguments: - detections (array[N, 6]), x1, y1, x2, y2, conf, class - labels (array[M, 5]), class, x1, y1, x2, y2 + Computes correct prediction matrix for detections against ground truth labels at various IoU thresholds. + + Args: + detections (np.ndarray): Array of detections with shape (N, 6), where each detection contains [x1, y1, x2, y2, + confidence, class]. + labels (np.ndarray): Array of ground truth labels with shape (M, 5), where each label contains [class, x1, y1, x2, y2]. + iouv (np.ndarray): Array of IoU thresholds to use for evaluation. + Returns: - correct (array[N, 10]), for 10 IoU levels + np.ndarray: Boolean array of shape (N, len(iouv)), indicating correct predictions at each IoU threshold. + + Notes: + - This function compares detections and ground truth labels to establish matches based on IoU and class. + - It supports multiple IoU thresholds to evaluate prediction accuracy flexibly. + + Example: + ```python + detections = np.array([[50, 50, 150, 150, 0.8, 0], + [30, 30, 120, 120, 0.7, 1]]) + labels = np.array([[0, 50, 50, 150, 150], + [1, 30, 30, 120, 120]]) + iouv = np.array([0.5, 0.6, 0.7]) + + correct = process_batch(detections, labels, iouv) + ``` """ correct = np.zeros((detections.shape[0], iouv.shape[0])).astype(bool) iou = box_iou(labels[:, 1:], detections[:, :4]) @@ -145,7 +215,45 @@ def run( callbacks=Callbacks(), compute_loss=None, ): - """Validates a trained YOLO model on a dataset and saves detection results in specified formats.""" + """ + Validates a trained YOLO model on a dataset and saves detection results in specified formats. + + Parameters: + data (str | dict): Path to the dataset configuration file (.yaml) or a dictionary containing the dataset paths. + weights (str | list, optional): Path to the trained model weights file(s). Default is None. + batch_size (int, optional): Batch size for inference. Default is 32. + imgsz (int, optional): Input image size for inference in pixels. Default is 640. + conf_thres (float, optional): Confidence threshold for object detection. Default is 0.001. + iou_thres (float, optional): IoU threshold for Non-Maximum Suppression (NMS). Default is 0.6. + max_det (int, optional): Maximum number of detections per image. Default is 300. + task (str, optional): Task type, can be 'train', 'val', 'test', 'speed', or 'study'. Default is 'val'. + device (str, optional): Device for computation, e.g., '0' for GPU or 'cpu' for CPU. Default is "". + workers (int, optional): Number of dataloader workers. Default is 8. + single_cls (bool, optional): Whether to treat the dataset as a single-class dataset. Default is False. + augment (bool, optional): Whether to apply augmented inference. Default is False. + verbose (bool, optional): Whether to output verbose information. Default is False. + save_txt (bool, optional): Whether to save detection results in text format (*.txt). Default is False. + save_hybrid (bool, optional): Whether to save hybrid results (labels+predictions) in text format (*.txt). Default is False. + save_conf (bool, optional): Whether to save confidence scores in text format labels. Default is False. + save_json (bool, optional): Whether to save detection results in COCO JSON format. Default is False. + project (str | Path, optional): Directory path to save validation results. Default is ROOT / 'runs/val'. + name (str, optional): Directory name to save validation results. Default is 'exp'. + exist_ok (bool, optional): Whether to overwrite existing project/name directory. Default is False. + half (bool, optional): Whether to use half-precision (FP16) for inference. Default is True. + dnn (bool, optional): Whether to use OpenCV DNN for ONNX inference. Default is False. + model (nn.Module, optional): Existing model instance. Default is None. + dataloader (DataLoader, optional): Existing dataloader instance. Default is None. + save_dir (Path, optional): Path to directory to save results. Default is Path(""). + plots (bool, optional): Whether to generate plots for visual results. Default is True. + callbacks (Callbacks, optional): Callbacks instance for event handling. Default is Callbacks(). + compute_loss (Callable, optional): Loss function for computing training loss. Default is None. + + Returns: + Tuple[torch.Tensor, dict, dict, torch.Tensor]: + - metrics: Dictionary containing metrics such as precision, recall, mAP, F1 score, etc. + - time: Dictionary containing times for different parts of the pipeline (e.g., preprocessing, inference, NMS) + - samples: Torch tensor containing validation samples. + """ # Initialize/load model and set device training = model is not None if training: # called by train.py @@ -360,7 +468,47 @@ def run( def parse_opt(): - """Parses and returns command-line options for dataset paths, model parameters, and inference settings.""" + """ + Parses and returns command-line options for dataset paths, model parameters, and inference settings. + + Args: + --data (str): Path to the dataset YAML file. Default is 'data/coco128.yaml'. + --weights (list[str]): Paths to one or more model files. Default is 'yolov3-tiny.pt'. + --batch-size (int): Number of images per batch during inference. Default is 32. + --imgsz (int): Inference size (pixels). Default is 640. + --conf-thres (float): Confidence threshold for object detection. Default is 0.001. + --iou-thres (float): IoU threshold for non-max suppression (NMS). Default is 0.6. + --max-det (int): Maximum number of detections per image. Default is 300. + --task (str): Task to perform: 'train', 'val', 'test', 'speed', or 'study'. Default is 'val'. + --device (str): CUDA device identifier (e.g., '0' or '0,1,2,3') or 'cpu' for using CPU. Default is "". + --workers (int): Maximum number of dataloader workers (per RANK in DDP mode). Default is 8. + --single-cls (bool): Treat the dataset as a single-class dataset. Default is False. + --augment (bool): Apply test-time augmentation during inference. Default is False. + --verbose (bool): Print mAP by class. Default is False. + --save-txt (bool): Save detection results in '.txt' format. Default is False. + --save-hybrid (bool): Save hybrid results containing both label and prediction in '.txt' format. Default is False. + --save-conf (bool): Save confidence scores in the '--save-txt' labels. Default is False. + --save-json (bool): Save detection results in COCO JSON format. Default is False. + --project (str): Project directory to save results. Default is 'runs/val'. + --name (str): Name of the experiment to save results. Default is 'exp'. + --exist-ok (bool): Whether to overwrite existing project/name without incrementing. Default is False. + --half (bool): Use FP16 half-precision during inference. Default is False. + --dnn (bool): Use OpenCV DNN backend for ONNX inference. Default is False. + + Returns: + opt (argparse.Namespace): Parsed command-line options. + + Notes: + - The function uses `argparse` to handle command-line options. + - It also modifies some options based on specific conditions, such as appending additional flags for saving in + JSON format and checking for the `coco.yaml` dataset. + + Example: + Use the following command to run validation with custom settings: + ```python + $ python val.py --weights yolov5s.pt --data coco128.yaml --img 640 + ``` + """ parser = argparse.ArgumentParser() parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="dataset.yaml path") parser.add_argument("--weights", nargs="+", type=str, default=ROOT / "yolov3-tiny.pt", help="model path(s)") @@ -393,7 +541,36 @@ def parse_opt(): def main(opt): - """Executes model tasks including training, validation, and speed or study benchmarks based on specified options.""" + """ + Executes model tasks including training, validation, and speed or study benchmarks based on specified options. + + Args: + opt (argparse.Namespace): Parsed command-line options for dataset paths, model parameters, and inference settings. + + Returns: + None + + Note: + This function orchestrates different tasks based on the user input provided through command-line arguments. It + supports tasks like `train`, `val`, `test`, `speed`, and `study`. Depending on the task, it validates the model on a + dataset, performs speed benchmarks, or runs mAP benchmarks. + + Examples: + To validate a trained YOLOv3 model: + + ```bash + $ python val.py --weights yolov3.pt --data coco.yaml --img 640 --task val + ``` + + For running speed benchmarks: + + ```bash + $ python val.py --task speed --data coco.yaml --weights yolov3.pt --batch-size 1 + ``` + + Links: + For more information, visit the official repository: https://github.com/ultralytics/ultralytics + """ check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) if opt.task in ("train", "val", "test"): # run normally From fa450096e2b78f6573cb87d639fe3c66f8580951 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 10 Jul 2024 20:44:30 +0200 Subject: [PATCH 1096/1185] Ultralytics Asset URL Update (#2248) Refactor code for speed and clarity --- README.md | 12 ++++++------ README.zh-CN.md | 12 ++++++------ classify/train.py | 2 +- classify/tutorial.ipynb | 2 +- data/GlobalWheat2020.yaml | 2 +- data/VisDrone.yaml | 8 ++++---- data/coco.yaml | 2 +- data/coco128-seg.yaml | 2 +- data/coco128.yaml | 2 +- data/voc.yaml | 2 +- segment/tutorial.ipynb | 4 ++-- tutorial.ipynb | 4 ++-- utils/general.py | 4 ++-- 13 files changed, 29 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 89bea96cf8..6a50e7f476 100644 --- a/README.md +++ b/README.md @@ -409,22 +409,22 @@ Get started in seconds with our verified environments. Click each icon below for ##
Contribute
diff --git a/README.zh-CN.md b/README.zh-CN.md index 0a367b1b7d..a63eabb4fb 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -409,22 +409,22 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu ##
贡献
diff --git a/classify/train.py b/classify/train.py index 9fb30fa2b5..9321a60bad 100644 --- a/classify/train.py +++ b/classify/train.py @@ -111,7 +111,7 @@ def train(opt, device): if str(data) == "imagenet": subprocess.run(["bash", str(ROOT / "data/scripts/get_imagenet.sh")], shell=True, check=True) else: - url = f"https://github.com/ultralytics/yolov5/releases/download/v1.0/{data}.zip" + url = f"https://github.com/ultralytics/assets/releases/download/v0.0.0/{data}.zip" download(url, dir=data_dir.parent) s = f"Dataset download success ✅ ({time.time() - t:.1f}s), saved to {colorstr('bold', data_dir)}\n" LOGGER.info(s) diff --git a/classify/tutorial.ipynb b/classify/tutorial.ipynb index d9e1d69137..34eaca9553 100644 --- a/classify/tutorial.ipynb +++ b/classify/tutorial.ipynb @@ -1290,7 +1290,7 @@ "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train-cls', view at http://localhost:6006/\n", "\n", "Dataset not found ⚠️, missing path /content/datasets/imagenette160, attempting download...\n", - "Downloading https://github.com/ultralytics/yolov5/releases/download/v1.0/imagenette160.zip to /content/datasets/imagenette160.zip...\n", + "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/imagenette160.zip to /content/datasets/imagenette160.zip...\n", "100% 103M/103M [00:00<00:00, 347MB/s] \n", "Unzipping /content/datasets/imagenette160.zip...\n", "Dataset download success ✅ (3.3s), saved to \u001b[1m/content/datasets/imagenette160\u001b[0m\n", diff --git a/data/GlobalWheat2020.yaml b/data/GlobalWheat2020.yaml index 52e07a658a..007e4f0953 100644 --- a/data/GlobalWheat2020.yaml +++ b/data/GlobalWheat2020.yaml @@ -36,7 +36,7 @@ download: | # Download dir = Path(yaml['path']) # dataset root dir urls = ['https://zenodo.org/record/4298502/files/global-wheat-codalab-official.zip', - 'https://github.com/ultralytics/yolov5/releases/download/v1.0/GlobalWheat2020_labels.zip'] + 'https://github.com/ultralytics/assets/releases/download/v0.0.0/GlobalWheat2020_labels.zip'] download(urls, dir=dir) # Make Directories diff --git a/data/VisDrone.yaml b/data/VisDrone.yaml index 2934e01f1c..de42f7a384 100644 --- a/data/VisDrone.yaml +++ b/data/VisDrone.yaml @@ -57,10 +57,10 @@ download: | # Download dir = Path(yaml['path']) # dataset root dir - urls = ['https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-train.zip', - 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-val.zip', - 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-test-dev.zip', - 'https://github.com/ultralytics/yolov5/releases/download/v1.0/VisDrone2019-DET-test-challenge.zip'] + urls = ['https://github.com/ultralytics/assets/releases/download/v0.0.0/VisDrone2019-DET-train.zip', + 'https://github.com/ultralytics/assets/releases/download/v0.0.0/VisDrone2019-DET-val.zip', + 'https://github.com/ultralytics/assets/releases/download/v0.0.0/VisDrone2019-DET-test-dev.zip', + 'https://github.com/ultralytics/assets/releases/download/v0.0.0/VisDrone2019-DET-test-challenge.zip'] download(urls, dir=dir, curl=True, threads=4) # Convert diff --git a/data/coco.yaml b/data/coco.yaml index f7ddc80705..65224a06fd 100644 --- a/data/coco.yaml +++ b/data/coco.yaml @@ -103,7 +103,7 @@ download: | # Download labels segments = False # segment or box labels dir = Path(yaml['path']) # dataset root dir - url = 'https://github.com/ultralytics/yolov5/releases/download/v1.0/' + url = 'https://github.com/ultralytics/assets/releases/download/v0.0.0/' urls = [url + ('coco2017labels-segments.zip' if segments else 'coco2017labels.zip')] # labels download(urls, dir=dir.parent) diff --git a/data/coco128-seg.yaml b/data/coco128-seg.yaml index a3798158bf..363ced868a 100644 --- a/data/coco128-seg.yaml +++ b/data/coco128-seg.yaml @@ -96,4 +96,4 @@ names: 79: toothbrush # Download script/URL (optional) -download: https://ultralytics.com/assets/coco128-seg.zip +download: https://github.com/ultralytics/assets/releases/download/v0.0.0/coco128-seg.zip diff --git a/data/coco128.yaml b/data/coco128.yaml index 3a58985aaf..4bfbf3a2eb 100644 --- a/data/coco128.yaml +++ b/data/coco128.yaml @@ -96,4 +96,4 @@ names: 79: toothbrush # Download script/URL (optional) -download: https://ultralytics.com/assets/coco128.zip +download: https://github.com/ultralytics/assets/releases/download/v0.0.0/coco128.zip diff --git a/data/voc.yaml b/data/voc.yaml index b7f25e7235..732c96345f 100644 --- a/data/voc.yaml +++ b/data/voc.yaml @@ -75,7 +75,7 @@ download: | # Download dir = Path(yaml['path']) # dataset root dir - url = 'https://github.com/ultralytics/yolov5/releases/download/v1.0/' + url = 'https://github.com/ultralytics/assets/releases/download/v0.0.0/' urls = [f'{url}VOCtrainval_06-Nov-2007.zip', # 446MB, 5012 images f'{url}VOCtest_06-Nov-2007.zip', # 438MB, 4953 images f'{url}VOCtrainval_11-May-2012.zip'] # 1.95GB, 17126 images diff --git a/segment/tutorial.ipynb b/segment/tutorial.ipynb index 5b4b46303a..346dd2e961 100644 --- a/segment/tutorial.ipynb +++ b/segment/tutorial.ipynb @@ -162,7 +162,7 @@ "output_type": "stream", "name": "stdout", "text": [ - "Downloading https://github.com/ultralytics/yolov5/releases/download/v1.0/coco2017labels-segments.zip ...\n", + "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/coco2017labels-segments.zip ...\n", "Downloading http://images.cocodataset.org/zips/val2017.zip ...\n", "######################################################################## 100.0%\n", "######################################################################## 100.0%\n" @@ -286,7 +286,7 @@ "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train-seg', view at http://localhost:6006/\n", "\n", "Dataset not found ⚠️, missing paths ['/content/datasets/coco128-seg/images/train2017']\n", - "Downloading https://ultralytics.com/assets/coco128-seg.zip to coco128-seg.zip...\n", + "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/coco128-seg.zip to coco128-seg.zip...\n", "100% 6.79M/6.79M [00:01<00:00, 6.73MB/s]\n", "Dataset download success ✅ (1.9s), saved to \u001b[1m/content/datasets\u001b[0m\n", "\n", diff --git a/tutorial.ipynb b/tutorial.ipynb index 93949e4866..783c5ef718 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -171,7 +171,7 @@ }, "source": [ "# Download COCO val\n", - "torch.hub.download_url_to_file('https://ultralytics.com/assets/coco2017val.zip', 'tmp.zip') # download (780M - 5000 images)\n", + "torch.hub.download_url_to_file('https://github.com/ultralytics/assets/releases/download/v0.0.0/coco2017val.zip', 'tmp.zip') # download (780M - 5000 images)\n", "!unzip -q tmp.zip -d ../datasets && rm tmp.zip # unzip" ], "execution_count": 3, @@ -327,7 +327,7 @@ "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train', view at http://localhost:6006/\n", "\n", "Dataset not found ⚠️, missing paths ['/content/datasets/coco128/images/train2017']\n", - "Downloading https://ultralytics.com/assets/coco128.zip to coco128.zip...\n", + "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/coco128.zip to coco128.zip...\n", "100% 6.66M/6.66M [00:00<00:00, 75.6MB/s]\n", "Dataset download success ✅ (0.6s), saved to \u001b[1m/content/datasets\u001b[0m\n", "\n", diff --git a/utils/general.py b/utils/general.py index 117ab059fd..209350eb26 100644 --- a/utils/general.py +++ b/utils/general.py @@ -49,7 +49,7 @@ AUTOINSTALL = str(os.getenv("YOLOv5_AUTOINSTALL", True)).lower() == "true" # global auto-install mode VERBOSE = str(os.getenv("YOLOv5_VERBOSE", True)).lower() == "true" # global verbose mode TQDM_BAR_FORMAT = "{l_bar}{bar:10}{r_bar}" # tqdm bar format -FONT = "Arial.ttf" # https://ultralytics.com/assets/Arial.ttf +FONT = "Arial.ttf" # https://github.com/ultralytics/assets/releases/download/v0.0.0/Arial.ttf torch.set_printoptions(linewidth=320, precision=5, profile="long") np.set_printoptions(linewidth=320, formatter={"float_kind": "{:11.5g}".format}) # format short g, %precision=5 @@ -508,7 +508,7 @@ def check_font(font=FONT, progress=False): font = Path(font) file = CONFIG_DIR / font.name if not font.exists() and not file.exists(): - url = f"https://ultralytics.com/assets/{font.name}" + url = f"https://github.com/ultralytics/assets/releases/download/v0.0.0/{font.name}" LOGGER.info(f"Downloading {url} to {file}...") torch.hub.download_url_to_file(url, str(file), progress=progress) From af561498051bbd08ae41f7e23c81b2423e5b4ff6 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 16 Jul 2024 01:03:43 +0200 Subject: [PATCH 1097/1185] Ultralytics Code Refactor https://ultralytics.com/actions (#2251) * Refactor code for speed and clarity * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: UltralyticsAssistant --- benchmarks.py | 16 +- detect.py | 73 +++++---- export.py | 442 +++++++++++++++++++++++++++++--------------------- hubconf.py | 102 +++++++----- train.py | 72 +++++--- val.py | 46 ++++-- 6 files changed, 445 insertions(+), 306 deletions(-) diff --git a/benchmarks.py b/benchmarks.py index 06bde1e380..127fecf4fb 100644 --- a/benchmarks.py +++ b/benchmarks.py @@ -78,9 +78,9 @@ def run( None Notes: - This function iterates over multiple export formats, performs the export, and then validates the model's - performance using appropriate validation functions for detection and segmentation models. The results are logged, - and optionally, benchmarks can be configured to raise errors on failures using the `hard_fail` argument. + This function iterates over multiple export formats, performs the export, and then validates the model's performance + using appropriate validation functions for detection and segmentation models. The results are logged, and optionally, + benchmarks can be configured to raise errors on failures using the `hard_fail` argument. Examples: ```python @@ -173,7 +173,7 @@ def test( hard_fail (bool): Raise an error on benchmark failure. Defaults to False. Returns: - pd.DataFrame: A DataFrame containing the export formats and their success status. (pd.DataFrame) + pd.DataFrame: A DataFrame containing the export formats and their success status. Examples: ```python @@ -223,7 +223,7 @@ def test( def parse_opt(): """ - Parses command line arguments for YOLOv3 inference and export configuration. + Parses command line arguments for YOLOv3 inference and export configurations. Args: --weights (str): Path to the weights file. Default is 'ROOT / "yolov3-tiny.pt"'. @@ -233,10 +233,10 @@ def parse_opt(): --device (str): CUDA device identifier, e.g., '0' for single GPU, '0,1,2,3' for multiple GPUs, or 'cpu' for CPU inference. Default is "". --half (bool): If set, use FP16 half-precision inference. Default is False. - --test (bool): If set, only test exports without running inference. Default is False. + --test (bool): If set, test only exports without running inference. Default is False. --pt-only (bool): If set, test only the PyTorch model without exporting to other formats. Default is False. - --hard-fail (str | bool): If set, raise an exception on benchmark failure. Can also be a string representing - the minimum metric floor for success. Default is False. + --hard-fail (str | bool): If set, raise an exception on benchmark failure. Can also be a string representing the + minimum metric floor for success. Default is False. Returns: argparse.Namespace: The parsed arguments as a namespace object. diff --git a/detect.py b/detect.py index efe3f1d6e5..1b26714bf2 100644 --- a/detect.py +++ b/detect.py @@ -96,7 +96,7 @@ def run( vid_stride=1, # video frame-rate stride ): """ - Performs YOLOv3 detection on various input sources including images, videos, streams, and YouTube URLs. + Run YOLOv3 detection inference on various input sources such as images, videos, streams, and YouTube URLs. Args: weights (str | Path): Path to the model weights file or a Triton URL (default: 'yolov5s.pt'). @@ -287,39 +287,45 @@ def run( def parse_opt(): """ - Parses and returns command-line options for model inference configurations. + Parses and returns command-line options for running YOLOv3 model detection. Args: - --weights (list[str]): Model path or triton URL. Default: `ROOT / "yolov3-tiny.pt"`. - --source (str): File/directory/URL/glob/screen/0(webcam) for input data. Default: `ROOT / "data/images"`. - --data (str): (Optional) Path to dataset.yaml. Default: `ROOT / "data/coco128.yaml"`. - --imgsz (list[int]): Inference size as height, width. Accepts multiple values. Default: `[640]`. - --conf-thres (float): Confidence threshold for predictions. Default: `0.25`. - --iou-thres (float): IoU threshold for Non-Maximum Suppression (NMS). Default: `0.45`. - --max-det (int): Maximum number of detections per image. Default: `1000`. - --device (str): CUDA device to run the model on, e.g., `0` or `0,1,2,3` or `cpu`. Default: `""`. - --view-img (bool): Display results on the screen. Default: `False`. - --save-txt (bool): Save results to text files. Default: `False`. - --save-conf (bool): Save confidence scores in text labels. Default: `False`. - --save-crop (bool): Save cropped prediction boxes. Default: `False`. - --nosave (bool): Do not save images/videos. Default: `False`. - --classes (list[int]): Filter results by class, e.g., `--classes 0` or `--classes 0 2 3`. Default: `None`. - --agnostic-nms (bool): Perform class-agnostic NMS. Default: `False`. - --augment (bool): Perform augmented inference. Default: `False`. - --visualize (bool): Visualize features. Default: `False`. - --update (bool): Update all models. Default: `False`. - --project (str): Directory to save results, saved as "project/name". Default: `ROOT / "runs/detect"`. - --name (str): Directory name for saving results, e.g., "exp" in "project/name". Default: `"exp"`. - --exist-ok (bool): Allow results to be saved in an existing directory without incrementing. Default: `False`. - --line-thickness (int): Thickness of bounding box lines (in pixels). Default: `3`. - --hide-labels (bool): Hide labels on detected objects. Default: `False`. - --hide-conf (bool): Hide confidence scores on labels. Default: `False`. - --half (bool): Use FP16 half-precision inference. Default: `False`. - --dnn (bool): Use OpenCV DNN backend for ONNX inference. Default: `False`. - --vid-stride (int): Frame-rate stride for video input. Default: `1`. + --weights (list[str]): Model path or Triton URL. Default: ROOT / "yolov3-tiny.pt". + --source (str): Input data source like file/dir/URL/glob/screen/0(webcam). Default: ROOT / "data/images". + --data (str): Optional path to dataset.yaml. Default: ROOT / "data/coco128.yaml". + --imgsz (list[int]): Inference size as height, width. Accepts multiple values. Default: [640]. + --conf-thres (float): Confidence threshold for predictions. Default: 0.25. + --iou-thres (float): IoU threshold for Non-Maximum Suppression (NMS). Default: 0.45. + --max-det (int): Maximum number of detections per image. Default: 1000. + --device (str): CUDA device identifier, e.g. "0" or "0,1,2,3" or "cpu". Default: "" (auto-select). + --view-img (bool): Display results. Default: False. + --save-txt (bool): Save results to *.txt files. Default: False. + --save-conf (bool): Save confidence scores in text labels. Default: False. + --save-crop (bool): Save cropped prediction boxes. Default: False. + --nosave (bool): Do not save images/videos. Default: False. + --classes (list[int] | None): Filter results by class, e.g. [0, 2, 3]. Default: None. + --agnostic-nms (bool): Perform class-agnostic NMS. Default: False. + --augment (bool): Apply augmented inference. Default: False. + --visualize (bool): Visualize feature maps. Default: False. + --update (bool): Update all models. Default: False. + --project (str): Directory to save results; results saved to "project/name". Default: ROOT / "runs/detect". + --name (str): Name of the specific run; results saved to "project/name". Default: "exp". + --exist-ok (bool): Allow results to be saved in an existing directory without incrementing. Default: False. + --line-thickness (int): Bounding box line thickness in pixels. Default: 3. + --hide-labels (bool): Hide labels on detections. Default: False. + --hide-conf (bool): Hide confidence scores on labels. Default: False. + --half (bool): Use FP16 half-precision inference. Default: False. + --dnn (bool): Use OpenCV DNN backend for ONNX inference. Default: False. + --vid-stride (int): Frame-rate stride for video input. Default: 1. Returns: - argparse.Namespace: Parsed command-line arguments for inference configurations. + argparse.Namespace: Parsed command-line arguments for YOLOv3 inference configurations. + + Example: + ```python + options = parse_opt() + run(**vars(options)) + ``` """ parser = argparse.ArgumentParser() parser.add_argument( @@ -359,7 +365,7 @@ def parse_opt(): def main(opt): """ - Entry point for running the model; checks requirements and calls `run` with parsed options. + Entry point for running the YOLO model; checks requirements and calls `run` with parsed options. Args: opt (argparse.Namespace): Parsed command-line options, which include: @@ -400,9 +406,10 @@ def main(opt): opt = parse_opt() main(opt) ``` + Notes: - Run this function as the entry point for using YOLOv3 for object detection on a variety of input sources such - as images, videos, directories, webcams, streams, etc. This function ensures all requirements are checked and + Run this function as the entry point for using YOLO for object detection on a variety of input sources such as + images, videos, directories, webcams, streams, etc. This function ensures all requirements are checked and subsequently initiates the detection process by calling the `run` function with appropriate options. """ check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) diff --git a/export.py b/export.py index e30c4f0e7b..5584601559 100644 --- a/export.py +++ b/export.py @@ -96,19 +96,19 @@ def __init__(self, model, im): Initializes an iOSModel with normalized input dimensions and number of classes from a PyTorch model. Args: - model (torch.nn.Module): The PyTorch model from which to initialize the iOS model. This should include - attributes like `nc` (number of classes) which will be used to configure the iOS model. - im (torch.Tensor): A Tensor representing a sample input image. The shape of this tensor should be (batch_size, - channels, height, width). This is used to extract dimensions for input normalization. + model (torch.nn.Module): The PyTorch model from which to initialize the iOS model. This should include attributes + like `nc` (number of classes) which will be used to configure the iOS model. + im (torch.Tensor): A Tensor representing a sample input image. The shape of this tensor should be + (batch_size, channels, height, width). This is used to extract dimensions for input normalization. Returns: None Notes: - - This class is specifically designed for use in exporting a PyTorch model for deployment on iOS platforms, - optimizing input dimensions and class configurations to suit mobile requirements. - - Normalization factor is derived from the input image dimensions, which impacts the model's performance - during inference on iOS devices. + - This class is specifically designed for use in exporting a PyTorch model for deployment on iOS platforms, optimizing + input dimensions and class configurations to suit mobile requirements. + - Normalization factor is derived from the input image dimensions, which impacts the model's performance during + inference on iOS devices. - Ensure the sample input image `im` provided has correct dimensions and shape for accurate model configuration. """ super().__init__() @@ -127,18 +127,21 @@ def forward(self, x): Performs a forward pass, returning scaled confidences and normalized coordinates given an input tensor. Args: - x (torch.Tensor): Input tensor representing a batch of images, with dimensions [batch_size, channels, height, width]. + x (torch.Tensor): Input tensor representing a batch of images, with dimensions [batch_size, channels, + height, width]. Returns: tuple[torch.Tensor, torch.Tensor, torch.Tensor]: A tuple containing three elements: - xywh (torch.Tensor): Tensor of shape [batch_size, num_detections, 4] containing normalized x, y, width, and height coordinates. - - conf (torch.Tensor): Tensor of shape [batch_size, num_detections, 1] containing confidence scores for each detection. - - cls (torch.Tensor): Tensor of shape [batch_size, num_detections, num_classes] containing class probabilities. + - conf (torch.Tensor): Tensor of shape [batch_size, num_detections, 1] containing confidence scores for + each detection. + - cls (torch.Tensor): Tensor of shape [batch_size, num_detections, num_classes] containing class + probabilities. Notes: - The dimensions of `x` should match the input dimensions used during the model's initialization to ensure proper - scaling and normalization. + The dimensions of `x` should match the input dimensions used during the model's initialization to ensure + proper scaling and normalization. Examples: ```python @@ -163,8 +166,8 @@ def export_formats(): Lists supported YOLOv3 model export formats including file suffixes and CPU/GPU compatibility. Returns: - list: A list of lists where each sublist contains information about a specific export format. - Each sublist includes the following elements: + list: A list of lists where each sublist contains information about a specific export format. Each sublist includes + the following elements: - str: The name of the format. - str: The command-line argument for including this format. - str: The file suffix used for this format. @@ -206,17 +209,17 @@ def try_export(inner_func): Returns: Callable: A wrapped function that profiles and logs the export process, handling successes and failures. - Usage example: - - ```python - @try_export - def export_onnx(py_model_path: str, output_path: str): - # Export logic here - return output_path, model - ``` + Examples: + ```python + @try_export + def export_onnx(py_model_path: str, output_path: str): + # Export logic here + return output_path, model + ``` - After applying this decorator, `export_onnx` will log the export results, including export success or failure along - with associated time and file size details. + Notes: + Applying this decorator to an export function will log the export results, including export success or failure, + along with associated time and file size details. """ inner_args = get_default_args(inner_func) @@ -238,13 +241,13 @@ def outer_func(*args, **kwargs): @try_export def export_torchscript(model, im, file, optimize, prefix=colorstr("TorchScript:")): """ - Exports a YOLOv3 model to TorchScript format, with optional optimization for mobile deployment. + Export a YOLOv3 model to TorchScript format, with optional optimization for mobile deployment. Args: model (torch.nn.Module): The YOLOv3 model to be exported. - im (torch.Tensor): A tensor representing the input image for the model. + im (torch.Tensor): A tensor representing the input image for the model, typically with shape (N, 3, H, W). file (pathlib.Path): The file path where the TorchScript model will be saved. - optimize (bool): A boolean flag indicating whether to optimize the model for mobile. + optimize (bool): A boolean flag indicating whether to optimize the model for mobile devices. prefix (str): A prefix for logging messages. Defaults to `colorstr("TorchScript:")`. Returns: @@ -255,8 +258,8 @@ def export_torchscript(model, im, file, optimize, prefix=colorstr("TorchScript:" Exception: If there is an error during export, it logs the error and returns `(None, None)`. Notes: - The function uses torch.jit.trace to trace the model with the input image tensor (`im`). Required metadata such as - input shape, stride, and class names are saved in an extra file included in the TorchScript model. + The function uses `torch.jit.trace` to trace the model with the input image tensor (`im`). Required metadata such as + input shape, stride, and class names are stored in an extra file included in the TorchScript model. Examples: ```python @@ -289,7 +292,7 @@ def export_torchscript(model, im, file, optimize, prefix=colorstr("TorchScript:" @try_export def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr("ONNX:")): """ - Exports a YOLOv3 model to ONNX format with dynamic shape and simplification options. + Export a YOLOv3 model to ONNX format with dynamic shape and simplification options. Args: model (torch.nn.Module): The YOLOv3 model to be exported. @@ -302,6 +305,31 @@ def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr("ONNX Returns: tuple[pathlib.Path, None]: The path to the saved ONNX model, None as the second tuple element (kept for consistency). + + Example: + ```python + from pathlib import Path + import torch + + model = ... # Assume model is loaded or created + im = torch.randn(1, 3, 640, 640) # A sample input tensor + file = Path("model.onnx") + opset = 12 + dynamic = True + simplify = True + + export_onnx(model, im, file, opset, dynamic, simplify) + ``` + + Notes: + Ensure `onnx`, `onnx-simplifier`, and suitable runtime packages are installed. + This function uses `torch.onnx.export` to create the ONNX model, followed by optional simplification using + `onnx-simplifier`. If `dynamic` is enabled, dynamic axes mappings are added to support variable input shapes. + Relevant YOLO model metadata like `stride` and `names` are included as part of the ONNX model's metadata. + + For more details on exporting and running inferences, visit: + - https://github.com/ultralytics/ultralytics + - https://github.com/zldrobit for TensorFlow export scripts. """ check_requirements("onnx>=1.12.0") import onnx @@ -360,7 +388,7 @@ def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr("ONNX @try_export def export_openvino(file, metadata, half, int8, data, prefix=colorstr("OpenVINO:")): """ - Exports a YOLOv3 model to OpenVINO format with optional INT8 quantization and inference metadata. + Export a YOLOv3 model to OpenVINO format with optional INT8 quantization and inference metadata. Args: file (Path): Path to the output file. @@ -370,8 +398,8 @@ def export_openvino(file, metadata, half, int8, data, prefix=colorstr("OpenVINO: data (str): Path to the dataset file (.yaml) for post-training quantization. Returns: - tuple[Path | None, openvino.runtime.Model | None]: Tuple containing the path to the exported model and - the OpenVINO model object, or None if the export failed. + tuple[Path | None, openvino.runtime.Model | None]: Tuple containing the path to the exported model and the OpenVINO + model object, or None if the export failed. Notes: - Requires the `openvino-dev>=2023.0` and optional `nncf>=2.4.0` package for INT8 quantization. @@ -451,7 +479,7 @@ def transform_fn(data_item): @try_export def export_paddle(model, im, file, metadata, prefix=colorstr("PaddlePaddle:")): """ - Exports a YOLOv3 model to PaddlePaddle format using X2Paddle, saving to a specified directory and including model + Export a YOLOv3 model to PaddlePaddle format using X2Paddle, saving to a specified directory and including model metadata. Args: @@ -470,8 +498,8 @@ def export_paddle(model, im, file, metadata, prefix=colorstr("PaddlePaddle:")): Notes: The function first checks for required packages `paddlepaddle` and `x2paddle`. It then uses X2Paddle to trace - the model and export it to a PaddlePaddle format, saving the resulting files in the specified directory - with included metadata in a YAML file. + the model and export it to a PaddlePaddle format, saving the resulting files in the specified directory with + included metadata in a YAML file. Example: ```python @@ -502,19 +530,39 @@ def export_paddle(model, im, file, metadata, prefix=colorstr("PaddlePaddle:")): @try_export def export_coreml(model, im, file, int8, half, nms, prefix=colorstr("CoreML:")): """ - Exports a YOLOv3 model to CoreML format with optional quantization and Non-Maximum Suppression (NMS). + Export a YOLOv3 model to CoreML format with optional quantization and Non-Maximum Suppression (NMS). Args: model (torch.nn.Module): The YOLOv3 model to be exported. - im (torch.Tensor): Input tensor used for tracing the model. + im (torch.Tensor): Input tensor used for tracing the model. Shape should be (batch_size, channels, height, width). file (pathlib.Path): Destination file path where the CoreML model will be saved. - int8 (bool): Whether to use INT8 quantization or not. - half (bool): Whether to use FP16 quantization or not. - nms (bool): Whether to include Non-Maximum Suppression in the CoreML model or not. - prefix (str): Prefix string to add context to log messages. + int8 (bool): Whether to use INT8 quantization. If True, quantizes the model to 8-bit integers. + half (bool): Whether to use FP16 quantization. If True, converts the model to 16-bit floating point numbers. + nms (bool): Whether to include Non-Maximum Suppression in the CoreML model. + prefix (str): Prefix string for logging purposes. Default is colorstr("CoreML:"). Returns: - str: Path to the saved CoreML model file (.mlmodel). + str: Path to the saved CoreML model (.mlmodel). + + Raises: + Exception: If there is an error during export, logs the error and stops the process. + + Notes: + - This function requires `coremltools` to be installed. + - If `nms` is enabled, the model is wrapped with `iOSModel` to include NMS. + - Quantization only works on macOS. + + Example: + ```python + from ultralytics.utils import export_coreml + from pathlib import Path + import torch + + model = ... # Assume model is loaded or created + im = torch.randn(1, 3, 640, 640) # A sample input tensor + file = Path("model.mlmodel") + export_coreml(model, im, file, int8=False, half=True, nms=True) + ``` """ check_requirements("coremltools") import coremltools as ct @@ -541,7 +589,7 @@ def export_coreml(model, im, file, int8, half, nms, prefix=colorstr("CoreML:")): @try_export def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose=False, prefix=colorstr("TensorRT:")): """ - Exports a YOLOv3 model to TensorRT engine format, optimizing it for GPU inference. + Export a YOLOv3 model to TensorRT engine format, optimizing it for GPU inference. Args: model (torch.nn.Module): The YOLOv3 model to be exported. @@ -555,14 +603,14 @@ def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose prefix (str): Prefix string for log messages. Default is "TensorRT:". Returns: - tuple: A tuple containing the output file path (Path) and None. + tuple[Path, None]: The output file path (Path) and None. Raises: AssertionError: If the model is running on CPU instead of GPU. RuntimeError: If the ONNX file failed to load. Notes: - Nvidia TensorRT: https://developer.nvidia.com/tensorrt + Requires TensorRT installation to execute. Nvidia TensorRT: https://developer.nvidia.com/tensorrt Example: ```python @@ -652,46 +700,44 @@ def export_saved_model( prefix=colorstr("TensorFlow SavedModel:"), ): """ - Exports a YOLOv3 model to TensorFlow SavedModel format. The function includes options for post-processing like Non- - Max Suppression (NMS) and others. + Exports a YOLOv3 model to TensorFlow SavedModel format, including optional settings for Non-Max Suppression (NMS). Args: - model (torch.nn.Module): The PyTorch model to be exported. - im (torch.Tensor): Input tensor with sample data to trace the model. - file (Path): Path to save the exported model. - dynamic (bool): Whether to export the model with dynamic shapes. - tf_nms (bool, optional): Whether to include TensorFlow NMS in the exported model. Defaults to False. - agnostic_nms (bool, optional): Whether to use class-agnostic NMS. Defaults to False. - topk_per_class (int, optional): Number of top-K predictions to keep per class after NMS. Defaults to 100. - topk_all (int, optional): Number of top-K predictions to keep overall after NMS. Defaults to 100. - iou_thres (float, optional): IoU threshold for NMS. Defaults to 0.45. - conf_thres (float, optional): Confidence threshold for NMS. Defaults to 0.25. - keras (bool, optional): Whether to save as a Keras model, retaining the original graph. Defaults to False. - prefix (str, optional): String prefix for log messages, formatted with color. Defaults to "TensorFlow SavedModel:". + model (torch.nn.Module): The YOLOv3 PyTorch model to be exported. + im (torch.Tensor): Tensor of sample input data used for tracing the model. + file (pathlib.Path): File path where the exported TensorFlow SavedModel will be saved. + dynamic (bool): If `True`, supports dynamic input shapes. + tf_nms (bool, optional): If `True`, includes TensorFlow NMS in the exported model. Defaults to `False`. + agnostic_nms (bool, optional): If `True`, uses class-agnostic NMS. Defaults to `False`. + topk_per_class (int, optional): Number of top-K predictions to keep per class after NMS. Defaults to `100`. + topk_all (int, optional): Number of top-K predictions to keep overall after NMS. Defaults to `100`. + iou_thres (float, optional): Intersection over Union (IoU) threshold for NMS. Defaults to `0.45`. + conf_thres (float, optional): Confidence threshold for NMS. Defaults to `0.25`. + keras (bool, optional): If `True`, saves the model in Keras format. Defaults to `False`. + prefix (str, optional): Prefix for logging messages. Defaults to `colorstr("TensorFlow SavedModel:")`. Returns: - Tuple[str, None]: Path to the saved model and None (to maintain consistency with other export functions). + (str, None): Path to the saved TensorFlow model as a string and `None` (kept for interface consistency). Raises: - ImportError: If the necessary TensorFlow libraries are not installed. + ImportError: If the required TensorFlow libraries are not installed. - Note: - - Ensure required libraries are installed: - `pip install tensorflow` or `tensorflow-cpu` or `tensorflow-macos` depending on your environment. - - Refer to https://github.com/ultralytics/yolov5 for more details and usage examples. - - Example: + Examples: ```python from pathlib import Path from models.common import DetectMultiBackend import torch model = DetectMultiBackend(weights='yolov5s.pt') - im = torch.zeros(1, 3, 640, 640) + im = torch.zeros(1, 3, 640, 640) # Sample input tensor file = Path("output/saved_model") export_saved_model(model, im, file, dynamic=True) ``` + + Notes: + - Ensure that required TensorFlow libraries are installed (e.g., `pip install tensorflow`). + - For more information, visit https://github.com/ultralytics/yolov5. """ # YOLOv3 TensorFlow SavedModel export try: @@ -738,7 +784,7 @@ def export_saved_model( @try_export def export_pb(keras_model, file, prefix=colorstr("TensorFlow GraphDef:")): """ - Exports a Keras model to TensorFlow GraphDef (*.pb) format, which is compatible with YOLOv3. + Export a Keras model to TensorFlow GraphDef (*.pb) format, which is compatible with YOLOv3. Args: keras_model (tf.keras.Model): The trained Keras model to be exported. @@ -761,7 +807,8 @@ def export_pb(keras_model, file, prefix=colorstr("TensorFlow GraphDef:")): Notes: Ensure TensorFlow is properly installed in your environment as it is required for this function to execute. - TensorFlow's version should be compatible with the version used to train your model to avoid any compatibility issues. + TensorFlow's version should be compatible with the version used to train your model to avoid any compatibility + issues. """ import tensorflow as tf from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2 @@ -780,27 +827,27 @@ def export_pb(keras_model, file, prefix=colorstr("TensorFlow GraphDef:")): @try_export def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=colorstr("TensorFlow Lite:")): """ - Export a YOLOv3 model to TensorFlow Lite format, supporting fp16/int8, NMS options, and custom data. + Export a YOLOv3 PyTorch model to TensorFlow Lite (TFLite) format. Args: - keras_model (tf.keras.Model): The Keras model to be exported. - im (torch.Tensor): The input tensor used for model tracing. - file (Path): The file path where the exported model will be saved. - int8 (bool): Flag to enable INT8 quantization for the model. - data (str): Path to the dataset YAML file for representative data generation. - nms (bool): Flag to include Non-Max Suppression (NMS) in the exported model. - agnostic_nms (bool): Flag to apply class-agnostic NMS. - prefix (str, optional): Prefix string for logging. Defaults to colorstr("TensorFlow Lite:"). + keras_model (tf.keras.Model): The Keras model obtained after converting the PyTorch model. + im (torch.Tensor): Sample input tensor to determine model input size. + file (pathlib.Path): Desired file path for saving the exported TFLite model. + int8 (bool): Flag to enable INT8 quantization for the TFLite model. + data (str): Path to dataset YAML file for representative data generation used in quantization. + nms (bool): Flag to include Non-Maximum Suppression (NMS) in the exported TFLite model. + agnostic_nms (bool): Flag to apply class-agnostic NMS during inference. + prefix (str, optional): Prefix for logging messages. Defaults to colorstr("TensorFlow Lite:"). Returns: - (str, NoneType): The file path of the saved TensorFlow Lite model and None. + (str | None): File path of the saved TensorFlow Lite model file or None if export fails. Notes: - - TensorFlow dependency is required for model export. - - INT8 quantization requires a representative dataset for calibration. - - Non-Max Suppression (NMS) can be optionally included in the exported model. + - Ensure TensorFlow is installed to perform the export. + - INT8 quantization requires a representative dataset to provide accurate calibration for the model. + - Including Non-Max Suppression (NMS) modifies the exported model to handle post-processing. - Examples: + Example: ```python import torch from pathlib import Path @@ -814,11 +861,9 @@ def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=c export_tflite(model, im, Path('yolov5s'), int8=False, data=None, nms=True, agnostic_nms=False) ``` - TensorFlow Lite Developer Guide: - https://www.tensorflow.org/lite/guide - - Model Conversion Reference: - https://github.com/leimao/Frozen_Graph_TensorFlow + For more details, refer to: + TensorFlow Lite Developer Guide: https://www.tensorflow.org/lite/guide + Model Conversion Reference: https://github.com/leimao/Frozen_Graph_TensorFlow """ import tensorflow as tf @@ -852,25 +897,24 @@ def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=c @try_export def export_edgetpu(file, prefix=colorstr("Edge TPU:")): """ - Exports YOLOv3 model to Edge TPU compatible format. + Export a YOLOv5 model to TensorFlow Edge TPU format with INT8 quantization. Args: - file (Path): The file path for the model to be exported, with a `.pt` suffix. - prefix (str): A prefix used for logging, default is 'Edge TPU:'. + file (Path): The file path for the PyTorch model to be exported, with a `.pt` suffix. + prefix (str): A prefix to be used for logging output. Defaults to "Edge TPU:" Returns: - Tuple[Path | None, None]: The tuple contains the file path of the exported model with `-int8_edgetpu.tflite` suffix - if successful, otherwise returns `None`. + Tuple[Path | None, None]: A tuple containing the file path of the exported model with the `-int8_edgetpu.tflite` + suffix and `None`, if successful. If unsuccessful, returns `(None, None)`. Raises: AssertionError: If the export is not executed on a Linux system. subprocess.CalledProcessError: If there are issues with subprocess execution, particularly around Edge TPU compiler - installation or execution. + installation or model conversion. Notes: - This function requires Linux and the Edge TPU compiler. If the compiler is not installed, it attempts to install it. - For more details, refer to the Edge TPU compiler documentation: - https://coral.ai/docs/edgetpu/compiler/ + This function is designed to work exclusively on Linux systems and requires the Edge TPU compiler to be installed. + If the compiler is not found, the function attempts to install it. Example: ```python @@ -881,6 +925,9 @@ def export_edgetpu(file, prefix=colorstr("Edge TPU:")): exported_model, _ = export_edgetpu(model_file) print(f"Model exported to {exported_model}") ``` + + For additional details, visit the Edge TPU compiler documentation: + https://coral.ai/docs/edgetpu/compiler/ """ cmd = "edgetpu_compiler --version" help_url = "https://coral.ai/docs/edgetpu/compiler/" @@ -920,7 +967,7 @@ def export_edgetpu(file, prefix=colorstr("Edge TPU:")): @try_export def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): """ - Exports a YOLOv3 model to TensorFlow.js format, with an optional quantization to uint8. + Export a YOLOv3 model to TensorFlow.js format, with an optional quantization to uint8. Args: file (Path): The path to the model file to be exported. @@ -928,16 +975,12 @@ def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): prefix (str): String prefix for logging, by default "TensorFlow.js". Returns: - tuple: - str: Directory path where the TensorFlow.js files are saved. - None: Placeholder to match the expected return type from 'try_export' decorator. + (tuple[str, None]): The directory path where the TensorFlow.js model files are saved and `None` placeholder to match + the expected return type from 'try_export' decorator. Raises: ImportError: If the required 'tensorflowjs' package is not installed. - Requirements: - - tensorflowjs: Install with `pip install tensorflowjs` - Example: ```python from pathlib import Path @@ -945,21 +988,34 @@ def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): ``` Note: - Ensure that you have TensorFlow.js installed in your environment. For more details, visit the official - TensorFlow.js documentation at https://www.tensorflow.org/js. + Ensure that you have TensorFlow.js installed in your environment. Install the package via: + ```bash + pip install tensorflowjs + ``` + + For more details on using the converted model: + Refer to the official TensorFlow.js documentation: https://www.tensorflow.org/js. Usage: The converted model can be used directly in JavaScript environments using the TensorFlow.js library. - For usage in web applications: - - Clone the example repository: - $ cd .. && git clone https://github.com/zldrobit/tfjs-yolov5-example.git && cd tfjs-yolov5-example - - Install dependencies: - $ npm install - - Create a symbolic link to the exported web model: - $ ln -s ../../yolov5/yolov5s_web_model public/yolov5s_web_model - - Start the example application: - $ npm star + For usage in web applications: + - Clone the example repository: + ```bash + cd .. && git clone https://github.com/zldrobit/tfjs-yolov5-example.git && cd tfjs-yolov5-example + ``` + - Install dependencies: + ```bash + npm install + ``` + - Create a symbolic link to the exported web model: + ```bash + ln -s ../../yolov5/yolov5s_web_model public/yolov5s_web_model + ``` + - Start the example application: + ```bash + npm start + ``` """ check_requirements("tensorflowjs") import tensorflowjs as tfjs @@ -998,21 +1054,15 @@ def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): def add_tflite_metadata(file, metadata, num_outputs): """ - Adds metadata to a TensorFlow Lite model to enhance model understanding and processing using `tflite_support`. + Adds metadata to a TensorFlow Lite model to enhance its usability with `tflite_support`. Args: - file (str): The path to the TensorFlow Lite model file. - metadata (dict): A dictionary containing metadata information such as labels, input/output descriptions, etc. - num_outputs (int): The number of output tensors in the model. + file (str): Path to the TensorFlow Lite model file. + metadata (dict): Dictionary of metadata to add, including descriptions of inputs, outputs, and other relevant info. + num_outputs (int): Number of output tensors in the model. Returns: - None. - - Raises: - ImportError: If the `tflite_support` library is not available. - - Note: - This function uses the `tflite_support` library to add the metadata. The library must be installed separately. + None Example: ```python @@ -1022,6 +1072,43 @@ def add_tflite_metadata(file, metadata, num_outputs): } add_tflite_metadata("/path/to/model.tflite", metadata, num_outputs=1) ``` + + Note: + Requires the `tflite_support` library for adding metadata to the TensorFlow Lite model. + Installation: `pip install tflite-support` + + ```python + from tflite_support import flatbuffers + from tflite_support import metadata as _metadata + from tflite_support import metadata_schema_py_generated as _metadata_fb + + tmp_file = Path("/tmp/meta.txt") + with open(tmp_file, "w") as meta_f: + meta_f.write(str(metadata)) + + model_meta = _metadata_fb.ModelMetadataT() + label_file = _metadata_fb.AssociatedFileT() + label_file.name = tmp_file.name + model_meta.associatedFiles = [label_file] + + subgraph = _metadata_fb.SubGraphMetadataT() + subgraph.inputTensorMetadata = [_metadata_fb.TensorMetadataT()] + subgraph.outputTensorMetadata = [_metadata_fb.TensorMetadataT()] * num_outputs + model_meta.subgraphMetadata = [subgraph] + + b = flatbuffers.Builder(0) + b.Finish(model_meta.Pack(b), _metadata.MetadataPopulator.METADATA_FILE_IDENTIFIER) + metadata_buf = b.Output() + + populator = _metadata.MetadataPopulator.with_model_file(file) + populator.load_metadata_buffer(metadata_buf) + populator.load_associated_files([str(tmp_file)]) + populator.populate() + ``` + + This function is a helper to add metadata to a TFLite model, making it easier to interpret and process for tasks like + object detection or classification. It leverages `tflite_support` to load and attach the metadata directly to the + model file. """ with contextlib.suppress(ImportError): # check_requirements('tflite_support') @@ -1056,18 +1143,19 @@ def add_tflite_metadata(file, metadata, num_outputs): def pipeline_coreml(model, im, file, names, y, prefix=colorstr("CoreML Pipeline:")): """ - Executes YOLOv3 CoreML pipeline, handling image preprocessing, prediction, and NMS, saving the model with metadata. + Processes and exports a YOLOv3 model into the CoreML model format, applying metadata and non-maximum suppression + (NMS). Args: - model (coremltools.models.MLModel): The CoreML model to be used for the prediction. - im (torch.Tensor): Input tensor in BCHW (Batch, Channel, Height, Width) format. - file (pathlib.Path): The file path where the exported CoreML model will be saved. - names (dict): Dictionary mapping class indices to class names. - y (torch.Tensor): YOLO model output tensor. - prefix (str): Optional prefix for logging messages; default is 'CoreML Pipeline:'. + model (coremltools.models.MLModel): The pre-trained YOLOv3 CoreML model to be used for the pipeline. + im (torch.Tensor): Input image tensor in BCHW (Batch, Channel, Height, Width) format with a shape (B, 3, H, W). + file (pathlib.Path): Destination file path where the CoreML model will be saved. + names (dict): A dictionary that maps class indices to class names. + y (torch.Tensor): Output detection tensor from the YOLO model, containing predictions. + prefix (str): Prefix for logging messages, default is "CoreML Pipeline:". Returns: - (pathlib.Path | None): The file path of the saved CoreML model if successful; None otherwise. + pathlib.Path | None: The path to the saved CoreML model if successful, otherwise None. Example: ```python @@ -1075,14 +1163,35 @@ def pipeline_coreml(model, im, file, names, y, prefix=colorstr("CoreML Pipeline: import torch from coremltools.models import MLModel + # Load example CoreML model model = MLModel('path/to/pretrained/model.mlmodel') - im = torch.randn(1, 3, 640, 640) # Example input tensor + + # Create example input tensor: B, C, H, W format + im = torch.randn(1, 3, 640, 640) + + # Define where the CoreML model will be saved file = Path('path/to/save/model.mlmodel') + + # Define example class names names = {0: 'class0', 1: 'class1'} - y = torch.randn(1, 25200, 85) # Example output tensor + # Dummy YOLO model output prediction having similar dimensions to y + y = torch.randn(1, 25200, 85) + + # Execute CoreML pipeline pipeline_coreml(model, im, file, names, y) ``` + + Notes: + - The function adds NMS to the CoreML model, supporting dynamic thresholds for IoU and confidence. + - Metadata fields are updated to include class names, thresholds, and additional information. + - The pipeline exports the final enhanced model into the specified file path in CoreML (`.mlmodel`) format. + - Ensure that `coremltools` is installed and properly configured in your environment. + - This function is designed to work primarily on macOS systems as CoreML is macOS-specific. + + References: + - `coremltools`: https://github.com/apple/coremltools + - YOLOv3: https://github.com/ultralytics/yolov5 """ import coremltools as ct from PIL import Image @@ -1398,18 +1507,25 @@ def run( def parse_opt(known=False): """ - Parses command line arguments for model export configuration, allowing users to specify various export options. + Parse command-line arguments for model export configuration. Args: known (bool): If True, parse only known arguments and ignore others. Default is False. Returns: - argparse.Namespace: An object containing all the configured arguments and their values. + argparse.Namespace: Namespace object containing export configuration parameters. + + Example: + ```python + from ultralytics.export import parse_opt + + options = parse_opt(known=True) + print(options) + ``` Notes: - This function uses `argparse` to define and process command line arguments. It supports multiple model export formats - including TorchScript, ONNX, OpenVINO, TensorRT, and others. Users can set various options like image size, batch size, - device, and thresholds for NMS. + This function leverages `argparse` to handle command-line arguments for various model export configurations, allowing + users to specify export formats, model parameters, and optimization settings. """ parser = argparse.ArgumentParser() parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="dataset.yaml path") @@ -1445,43 +1561,7 @@ def parse_opt(known=False): def main(opt): - """ - Main function for exporting a YOLOv3 PyTorch model to various formats. - - This function parses command line arguments to configure export options and then proceeds to export - the YOLOv3 model to specified formats such as TorchScript, ONNX, CoreML, TensorRT, and more. - - Args: - opt (argparse.Namespace): Parsed command line arguments containing export configurations such as: - data (str): Path to dataset YAML file. - weights (int | str): Path(s) to model weights file(s). - imgsz (tuple[int, int]): Image dimensions (height, width). - batch_size (int): Batch size for export. - device (str): Device to use for export, e.g., 'cpu' or '0' for GPU. - include (list[int | str]): List of formats to export, e.g., ['torchscript', 'onnx']. - half (bool): If True, export model in FP16 half-precision. - inplace (bool): If True, set YOLOv3 Detect() inplace=True. - keras (bool): If True, use Keras for TensorFlow SavedModel export. - optimize (bool): If True, optimize TorchScript model for mobile. - int8 (bool): If True, enable INT8 quantization for CoreML and TensorFlow. - dynamic (bool): If True, enable dynamic axes for ONNX, TensorRT, and TensorFlow. - simplify (bool): If True, simplify ONNX model using onnx-simplifier. - opset (int): ONNX opset version to use. - verbose (bool): If True, enable verbose logging for TensorRT export. - workspace (int): Workspace size in GB for TensorRT export. - nms (bool): If True, add Non-Max Suppression (NMS) to TensorFlow model. - agnostic_nms (bool): If True, add class-agnostic NMS to TensorFlow model. - topk_per_class (int): Top-k per class to keep for TensorFlow.js NMS. - topk_all (int): Top-k for all classes to keep for TensorFlow.js NMS. - iou_thres (float): IoU threshold for TensorFlow.js NMS. - conf_thres (float): Confidence threshold for TensorFlow.js NMS. - - Returns: - list[str]: List of paths to the exported model(s). - - Example: - $ python export.py --weights yolov5s.pt --include torchscript onnx openvino engine coreml tflite ... - """ + """Run(**vars(opt))""" for opt.weights in opt.weights if isinstance(opt.weights, list) else [opt.weights]: run(**vars(opt)) diff --git a/hubconf.py b/hubconf.py index d701c2d4c7..a3e8eef583 100644 --- a/hubconf.py +++ b/hubconf.py @@ -22,11 +22,11 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbo pretrained (bool): Whether to load pretrained weights into the model. Default is True. channels (int): Number of input channels. Default is 3. classes (int): Number of model classes. Default is 80. - autoshape (bool): Whether to apply the YOLOv3 .autoshape() wrapper to the model for handling multiple input types. - Default is True. + autoshape (bool): Whether to apply the YOLOv3 .autoshape() wrapper to the model for handling multiple input + types. Default is True. verbose (bool): If True, print all information to the screen. Default is True. - device (str | torch.device | None): Device to use for model parameters ('cpu', 'cuda', etc.). If None, defaults to - the best available device. + device (str | torch.device | None): Device to use for model parameters ('cpu', 'cuda', etc.). If None, defaults + to the best available device. Returns: torch.nn.Module: YOLOv3 model loaded with or without pretrained weights. @@ -101,13 +101,13 @@ def custom(path="path/to/model.pt", autoshape=True, _verbose=True, device=None): Args: path (str): Path to the model file. Supports both local and URL paths. - autoshape (bool): If True, applies the YOLOv3 `.autoshape()` wrapper to allow for various input formats. - _verbose (bool): If True, outputs detailed information. Otherwise, limits verbosity. + autoshape (bool): If True, applies the YOLOv3 `.autoshape()` wrapper to allow for various input formats. Default is True. + _verbose (bool): If True, outputs detailed information. Otherwise, limits verbosity. Default is True. device (str | torch.device | None): Device to load the model on. Default is None, which uses the available GPU if possible. Returns: - torch.nn.Module: The loaded YOLOv3 model, either with or without autoshaping applied. + (torch.nn.Module): The loaded YOLOv3 model, either with or without autoshaping applied. Raises: Exception: If the model loading fails due to invalid path or incompatible model state, with helpful suggestions @@ -126,15 +126,15 @@ def custom(path="path/to/model.pt", autoshape=True, _verbose=True, device=None): def yolov5n(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): """ - Instantiates a YOLOv5n model with optional pretrained weights, configurable input channels, classes, autoshaping, - and device selection. + Instantiates a YOLOv5n model with optional pretrained weights, configurable input channels, number of classes, + autoshaping, and device selection. Args: pretrained (bool): If True, loads pretrained weights into the model. Defaults to True. channels (int): Number of input channels. Defaults to 3. classes (int): Number of detection classes. Defaults to 80. - autoshape (bool): If True, applies YOLOv5 .autoshape() wrapper to the model for various formats (file/URI/PIL/cv2/np) - and non-maximum suppression (NMS). Defaults to True. + autoshape (bool): If True, applies YOLOv5 .autoshape() wrapper to the model for various input formats like file/URI/PIL/cv2/np + and adds non-maximum suppression (NMS). Defaults to True. _verbose (bool): If True, prints detailed information to the screen. Defaults to True. device (str | torch.device | None): Device to use for model computations (e.g., 'cpu', 'cuda'). If None, the best available device is automatically selected. Defaults to None. @@ -150,21 +150,23 @@ def yolov5n(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr model = torch.hub.load('ultralytics/yolov5', 'custom', 'yolov5n.pt') # using custom/local model model = torch.hub.load('.', 'custom', 'yolov5n.pt', source='local') # from local repository ``` + + Note: + PyTorch Hub models can be explored at https://pytorch.org/hub/ultralytics_yolov5. This allows easy model loading and usage. """ return _create("yolov5n", pretrained, channels, classes, autoshape, _verbose, device) def yolov5s(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): """ - Loads the YOLOv5s model with customizable options for pretrained weights, input channels, number of classes, + Load the YOLOv5s model with customizable options for pretrained weights, input channels, number of classes, autoshape functionality, and device selection. Args: pretrained (bool, optional): If True, loads model with pretrained weights. Default is True. channels (int, optional): Specifies the number of input channels. Default is 3. classes (int, optional): Defines the number of model classes. Default is 80. - autoshape (bool, optional): Applies YOLOv5 .autoshape() wrapper to the model for enhanced usability. Default is - True. + autoshape (bool, optional): Applies YOLOv5 .autoshape() wrapper to the model for enhanced usability. Default is True. _verbose (bool, optional): If True, prints detailed information during model loading. Default is True. device (str | torch.device | None, optional): Specifies the device to load the model on. Accepts 'cpu', 'cuda', or torch.device. Default is None, which automatically selects the best available option. @@ -185,26 +187,26 @@ def yolov5s(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr def yolov5m(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): """ - Loads YOLOv5m model with options for pretrained weights, channel/class customization, autoshaping, and device - selection. + Loads the YOLOv5m model with options for pretrained weights, input channels, number of classes, autoshape + functionality, and device selection. Args: pretrained (bool, optional): If True, loads pretrained weights into the model. Default is True. channels (int, optional): Number of input channels for the model. Default is 3. - classes (int, optional): Number of classes for the model. Default is 80. - autoshape (bool, optional): If True, applies the YOLOv3 .autoshape() wrapper to the model for convenient input - handling. Default is True. - _verbose (bool, optional): If True, prints all information to the screen. Default is True. - device (str | torch.device | None, optional): Device to use for model parameters. Default is None, which - automatically selects the available device. + classes (int, optional): Number of model classes. Default is 80. + autoshape (bool, optional): If True, applies the YOLOv5 .autoshape() wrapper for handling multiple input types and NMS. + Default is True. + _verbose (bool, optional): If True, prints detailed information during model loading. Default is True. + device (str | torch.device | None, optional): Device for model computations (e.g., 'cpu', 'cuda'). Automatically + selects the best available device if None. Default is None. Returns: - torch.nn.Module: YOLOv5m model instance. + torch.nn.Module: The instantiated YOLOv5m model. Example: ```python import torch - model = yolov5m(pretrained=True, channels=3, classes=80, autoshape=True, device='cuda:0') + model = torch.hub.load('ultralytics/yolov5', 'yolov5m', pretrained=True) ``` """ return _create("yolov5m", pretrained, channels, classes, autoshape, _verbose, device) @@ -212,45 +214,50 @@ def yolov5m(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr def yolov5l(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): """ - Loads the YOLOv5l model with options for pretrained weights, channel and class customization, autoshaping, and - device selection. + Load the YOLOv5l model with customizable options for pretrained weights, input channels, number of classes, + autoshape functionality, and device selection. Args: - pretrained (bool, optional): If True, loads the model with pretrained weights. Defaults to True. - channels (int, optional): Number of input channels. Defaults to 3. - classes (int, optional): Number of model classes. Defaults to 80. - autoshape (bool, optional): If True, applies YOLOv5's .autoshape() wrapper to the model. Defaults to True. - _verbose (bool, optional): If True, prints detailed information during model loading. Defaults to True. - device (str | torch.device | None, optional): Device to use for model parameters, e.g., 'cpu', 'cuda:0', - or torch.device object. If None, automatically selects the appropriate device. Defaults to None. + pretrained (bool, optional): If True, load model with pretrained weights. Default is True. + channels (int, optional): Specifies the number of input channels. Default is 3. + classes (int, optional): Defines the number of model classes. Default is 80. + autoshape (bool, optional): Applies the YOLOv5 .autoshape() wrapper to the model for enhanced usability. Default is + True. + _verbose (bool, optional): If True, prints detailed information during model loading. Default is True. + device (str | torch.device | None, optional): Specifies the device to load the model on. Accepts 'cpu', 'cuda', or + torch.device. Default is None, which automatically selects the best available option. Returns: - torch.nn.Module: The initialized YOLOv5l model. + torch.nn.Module: The initialized YOLOv5l model loaded with the specified options. Example: ```python import torch model = torch.hub.load('ultralytics/yolov5', 'yolov5l', pretrained=True) ``` + + For more information, refer to [PyTorch Hub models](https://pytorch.org/hub/ultralytics_yolov5). """ return _create("yolov5l", pretrained, channels, classes, autoshape, _verbose, device) def yolov5x(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): """ - Loads YOLOv5x model with customization options for weights, channels, classes, autoshaping, and device selection. + Load the YOLOv5x model with options for pretrained weights, number of input channels, classes, autoshaping, and + device selection. Args: - pretrained (bool, optional): Whether to load pretrained weights. Defaults to True. + pretrained (bool, optional): If True, loads the model with pretrained weights. Defaults to True. channels (int, optional): Number of input channels. Defaults to 3. - classes (int, optional): Number of model classes. Defaults to 80. - autoshape (bool, optional): Whether to apply YOLOv3 .autoshape() wrapper to the model. Defaults to True. - _verbose (bool, optional): Whether to print all information to the screen. Defaults to True. - device (str | torch.device | None, optional): Device to use for model parameters, e.g., 'cpu', 'cuda', or - torch.device(). If None, default device will be selected. Defaults to None. + classes (int, optional): Number of detection classes. Defaults to 80. + autoshape (bool, optional): If True, applies the YOLOv5 .autoshape() wrapper, enabling various input formats and + non-maximum suppression (NMS). Defaults to True. + _verbose (bool, optional): If True, prints detailed information during model loading. Defaults to True. + device (str | torch.device | None, optional): Device to use for model parameters (e.g., 'cpu', 'cuda'). Defaults to + None, selecting the best available device automatically. Returns: - torch.nn.Module: The YOLOv5x model. + torch.nn.Module: The YOLOv5x model loaded with the specified configuration. Examples: ```python @@ -262,6 +269,8 @@ def yolov5x(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr # Load YOLOv5x model with custom device model = torch.hub.load('ultralytics/yolov5', 'yolov5x', device='cuda:0') ``` + + For more details, refer to [PyTorch Hub models](https://pytorch.org/hub/ultralytics_yolov5). """ return _create("yolov5x", pretrained, channels, classes, autoshape, _verbose, device) @@ -302,7 +311,7 @@ def yolov5s6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=T pretrained (bool, optional): If True, loads pretrained weights into the model. Defaults to True. channels (int, optional): Number of input channels. Defaults to 3. classes (int, optional): Number of model classes. Defaults to 80. - autoshape (bool, optional): Apply YOLOv5 .autoshape() wrapper to model. Defaults to True. + autoshape (bool, optional): Apply YOLOv5 .autoshape() wrapper to the model. Defaults to True. _verbose (bool, optional): If True, prints detailed information to the screen. Defaults to True. device (str | torch.device | None, optional): Device to use for model parameters, e.g., 'cpu', 'cuda:0'. If None, it will select the appropriate device automatically. Defaults to None. @@ -332,7 +341,7 @@ def yolov5m6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=T pretrained (bool): Whether to load pretrained weights into the model. Default is True. channels (int): Number of input channels. Default is 3. classes (int): Number of model classes. Default is 80. - autoshape (bool): Whether to apply YOLOv3 .autoshape() wrapper to the model. Default is True. + autoshape (bool): Whether to apply YOLOv5 .autoshape() wrapper to the model. Default is True. _verbose (bool): Whether to print all information to the screen. Default is True. device (str | torch.device | None): Device to use for model parameters, e.g., 'cpu', 'cuda', 'mps', or torch device. Default is None. @@ -343,13 +352,16 @@ def yolov5m6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=T Example: ```python import torch + + # Load YOLOv5m6 model with default settings model = torch.hub.load('ultralytics/yolov5', 'yolov5m6') + # Load custom YOLOv5m6 model from a local path with specific options model = torch.hub.load('.', 'yolov5m6', pretrained=False, channels=1, classes=10, device='cuda') ``` Notes: - For more detailed documentation, visit https://github.com/ultralytics/yolov5 + For more detailed documentation, visit https://github.com/ultralytics/yolov5 """ return _create("yolov5m6", pretrained, channels, classes, autoshape, _verbose, device) diff --git a/train.py b/train.py index cbdce77f6f..4ea84a5667 100644 --- a/train.py +++ b/train.py @@ -118,7 +118,8 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio $ python train.py --data coco128.yaml --weights '' --cfg yolov5s.yaml --img 640 # from scratch Usage - Multi-GPU DDP training: - $ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 train.py --data coco128.yaml --weights yolov5s.pt --img 640 --device 0,1,2,3 + $ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 train.py --data coco128.yaml --weights + yolov5s.pt --img 640 --device 0,1,2,3 Models: https://github.com/ultralytics/yolov5/tree/master/models Datasets: https://github.com/ultralytics/yolov5/tree/master/data @@ -544,13 +545,13 @@ def lf(x): def parse_opt(known=False): """ - Parses command line arguments for configuring the training of a YOLO model. + Parse command line arguments for configuring the training of a YOLO model. Args: known (bool): Flag to parse known arguments only, defaults to False. Returns: - argparse.Namespace: Parsed command line arguments. + (argparse.Namespace): Parsed command line arguments. Examples: ```python @@ -627,7 +628,7 @@ def main(opt, callbacks=Callbacks()): AssertionError: If certain constraints are violated (e.g., when specific options are incompatible with DDP training). Notes: - - For tutorial on using Multi-GPU with DDP: https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training + - For a tutorial on using Multi-GPU with DDP: https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training Example: Single-GPU training: @@ -812,38 +813,57 @@ def main(opt, callbacks=Callbacks()): def run(**kwargs): """ - Executes model training with specified configurations. + Run the training process for a YOLOv3 model with the specified configurations. Args: - kwargs (dict): Configuration parameters for the training process. Supported parameters include but are not limited to: - - data (str): Path to the dataset YAML file. - - weights (str): Path to initial weights file. - - imgsz (int): Image size for training and validation. - - epochs (int): Number of training epochs. - - batch_size (int): Total batch size for all GPUs. + data (str): Path to the dataset YAML file. + weights (str): Path to the pre-trained weights file or '' to train from scratch. + cfg (str): Path to the model configuration file. + hyp (str): Path to the hyperparameters YAML file. + epochs (int): Total number of training epochs. + batch_size (int): Total batch size across all GPUs. + imgsz (int): Image size for training and validation (in pixels). + rect (bool): Use rectangular training for better aspect ratio preservation. + resume (bool | str): Resume most recent training if True, or resume training from a specific checkpoint if a string. + nosave (bool): Only save the final checkpoint and not the intermediate ones. + noval (bool): Only validate model performance in the final epoch. + noautoanchor (bool): Disable automatic anchor generation. + noplots (bool): Do not save any plots. + evolve (int): Number of generations for hyperparameters evolution. + bucket (str): Google Cloud Storage bucket name for saving run artifacts. + cache (str | None): Cache images for faster training ('ram' or 'disk'). + image_weights (bool): Use weighted image selection for training. + device (str): Device to use for training, e.g., '0' for first GPU or 'cpu' for CPU. + multi_scale (bool): Use multi-scale training. + single_cls (bool): Train a multi-class dataset as a single-class. + optimizer (str): Optimizer to use ('SGD', 'Adam', or 'AdamW'). + sync_bn (bool): Use synchronized batch normalization (only in DDP mode). + workers (int): Maximum number of dataloader workers (per rank in DDP mode). + project (str): Location of the output directory. + name (str): Unique name for the run. + exist_ok (bool): Allow existing output directory. + quad (bool): Use quad dataloader. + cos_lr (bool): Use cosine learning rate scheduler. + label_smoothing (float): Label smoothing epsilon. + patience (int): EarlyStopping patience (epochs without improvement). + freeze (list[int]): List of layers to freeze, e.g., [0] to freeze only the first layer. + save_period (int): Save checkpoint every 'save_period' epochs (disabled if less than 1). + seed (int): Global training seed for reproducibility. + local_rank (int): For automatic DDP Multi-GPU argument parsing, do not modify. Returns: None - Notes: - - Ensure that the provided dataset YAML file and the initial weights path are accessible. - - For multi-GPU training, use appropriate distributed training settings. - - Example usage: - ```python - run(data='coco128.yaml', imgsz=320, weights='yolov5m.pt') - ``` - Example: - To execute model training with custom configurations: ```python - from train import run - run(data='coco128.yaml', imgsz=320, weights='yolov5m.pt') + from ultralytics import run + run(data='coco128.yaml', weights='yolov5m.pt', imgsz=320, epochs=100, batch_size=16) ``` - References: - - Models: https://github.com/ultralytics/yolov5/tree/master/models - - Datasets: https://github.com/ultralytics/yolov5/tree/master/data - - Tutorial: https://docs.ultralytics.com/yolov5/tutorials/train_custom_data + Notes: + - Ensure the dataset YAML file and initial weights are accessible. + - Refer to the [Ultralytics YOLOv5 repository](https://github.com/ultralytics/yolov5) for model and data configurations. + - Use the [Training Tutorial](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data) for custom dataset training. """ opt = parse_opt(True) for k, v in kwargs.items(): diff --git a/val.py b/val.py index 775282d50d..6c7a88ccbb 100644 --- a/val.py +++ b/val.py @@ -105,7 +105,7 @@ def save_one_txt(predn, save_conf, shape, file): def save_one_json(predn, jdict, path, class_map): """ - Saves detection results in JSON format containing image_id, category_id, bbox, and score per detection. + Save detection results in JSON format containing image_id, category_id, bbox, and score per detection. Args: predn (torch.Tensor): Normalized prediction tensor of shape (N, 6) where N is the number of detections. @@ -125,6 +125,11 @@ def save_one_json(predn, jdict, path, class_map): class_map = {0: 1, 1: 2} save_one_json(predn, jdict, path, class_map) ``` + + Notes: + - The image_id is extracted from the image file path. + - Bounding boxes are converted from xyxy format to xywh format. + - The JSON output format is compatible with COCO dataset evaluation. """ image_id = int(path.stem) if path.stem.isnumeric() else path.stem box = xyxy2xywh(predn[:, :4]) # xywh @@ -218,7 +223,7 @@ def run( """ Validates a trained YOLO model on a dataset and saves detection results in specified formats. - Parameters: + Args: data (str | dict): Path to the dataset configuration file (.yaml) or a dictionary containing the dataset paths. weights (str | list, optional): Path to the trained model weights file(s). Default is None. batch_size (int, optional): Batch size for inference. Default is 32. @@ -241,18 +246,33 @@ def run( exist_ok (bool, optional): Whether to overwrite existing project/name directory. Default is False. half (bool, optional): Whether to use half-precision (FP16) for inference. Default is True. dnn (bool, optional): Whether to use OpenCV DNN for ONNX inference. Default is False. - model (nn.Module, optional): Existing model instance. Default is None. - dataloader (DataLoader, optional): Existing dataloader instance. Default is None. + model (torch.nn.Module, optional): Existing model instance. Default is None. + dataloader (torch.utils.data.DataLoader, optional): Existing dataloader instance. Default is None. save_dir (Path, optional): Path to directory to save results. Default is Path(""). plots (bool, optional): Whether to generate plots for visual results. Default is True. callbacks (Callbacks, optional): Callbacks instance for event handling. Default is Callbacks(). compute_loss (Callable, optional): Loss function for computing training loss. Default is None. Returns: - Tuple[torch.Tensor, dict, dict, torch.Tensor]: - - metrics: Dictionary containing metrics such as precision, recall, mAP, F1 score, etc. - - time: Dictionary containing times for different parts of the pipeline (e.g., preprocessing, inference, NMS) - - samples: Torch tensor containing validation samples. + (tuple): A tuple containing: + - metrics (torch.Tensor): Dictionary containing metrics such as precision, recall, mAP, F1 score, etc. + - times (dict): Dictionary containing times for different parts of the pipeline (e.g., preprocessing, inference, NMS). + - samples (torch.Tensor): Torch tensor containing validation samples. + + Example: + ```python + metrics, times, samples = run( + data='data/coco.yaml', + weights='yolov5s.pt', + batch_size=32, + imgsz=640, + conf_thres=0.001, + iou_thres=0.6, + max_det=300, + task='val', + device='cpu' + ) + ``` """ # Initialize/load model and set device training = model is not None @@ -500,8 +520,8 @@ def parse_opt(): Notes: - The function uses `argparse` to handle command-line options. - - It also modifies some options based on specific conditions, such as appending additional flags for saving in - JSON format and checking for the `coco.yaml` dataset. + - It also modifies some options based on specific conditions, such as appending additional flags for saving + in JSON format and checking for the `coco.yaml` dataset. Example: Use the following command to run validation with custom settings: @@ -551,9 +571,9 @@ def main(opt): None Note: - This function orchestrates different tasks based on the user input provided through command-line arguments. It - supports tasks like `train`, `val`, `test`, `speed`, and `study`. Depending on the task, it validates the model on a - dataset, performs speed benchmarks, or runs mAP benchmarks. + This function orchestrates different tasks based on the user input provided through command-line arguments. It supports tasks + like `train`, `val`, `test`, `speed`, and `study`. Depending on the task, it validates the model on a dataset, performs speed + benchmarks, or runs mAP benchmarks. Examples: To validate a trained YOLOv3 model: From 9b684c92a6c3cf25abce36cd5daf853ceb362085 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 22 Jul 2024 03:05:00 +0200 Subject: [PATCH 1098/1185] [Snyk] Security upgrade setuptools from 68.0.0 to 70.0.0 (#2252) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-SETUPTOOLS-7448482 Co-authored-by: snyk-bot --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ace47e72fd..3f39dd7bd2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -39,7 +39,7 @@ seaborn>=0.11.0 # openvino-dev>=2023.0 # OpenVINO export # Deploy ---------------------------------------------------------------------- -setuptools>=65.5.1 # Snyk vulnerability fix +setuptools>=70.0.0 # Snyk vulnerability fix # tritonclient[all]~=2.24.0 # Extras ---------------------------------------------------------------------- From b021bac935d8b64dfbfb2c5c5635ffddd00b581c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 22 Jul 2024 23:36:53 +0200 Subject: [PATCH 1099/1185] Update format.yml (#2257) --- .github/workflows/format.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index bce585bdba..00d7d78cb0 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -5,8 +5,8 @@ name: Ultralytics Actions on: - push: - branches: [main, master] + issues: + types: [opened, edited] pull_request_target: branches: [main, master] @@ -17,7 +17,8 @@ jobs: - name: Run Ultralytics Formatting uses: ultralytics/actions@main with: - token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, do not modify + token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} # or secrets.GITHUB_TOKEN for automatically generated + labels: true # autolabel issues and PRs python: true # format Python code and docstrings markdown: true # format Markdown prettier: true # format YAML From f763c50710c7e7a6b7d85bed773d5db90feceb25 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 22 Jul 2024 23:41:33 +0200 Subject: [PATCH 1100/1185] Update format.yml (#2258) --- .github/workflows/format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 00d7d78cb0..b809830d50 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -17,7 +17,7 @@ jobs: - name: Run Ultralytics Formatting uses: ultralytics/actions@main with: - token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} # or secrets.GITHUB_TOKEN for automatically generated + token: ${{ secrets.PERSONAL_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} # note GITHUB_TOKEN automatically generated labels: true # autolabel issues and PRs python: true # format Python code and docstrings markdown: true # format Markdown From 1222df95a807298dcb604b2ae1a48e1a5b19e0dc Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 22 Jul 2024 23:48:32 +0200 Subject: [PATCH 1101/1185] [Snyk] Security upgrade zipp from 3.15.0 to 3.19.1 (#2256) fix: utils/google_app_engine/additional_requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-ZIPP-7430899 Co-authored-by: snyk-bot --- utils/google_app_engine/additional_requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/google_app_engine/additional_requirements.txt b/utils/google_app_engine/additional_requirements.txt index 821c3caf3c..08c276f7b4 100644 --- a/utils/google_app_engine/additional_requirements.txt +++ b/utils/google_app_engine/additional_requirements.txt @@ -3,3 +3,4 @@ pip==23.3 Flask==2.3.2 gunicorn==22.0.0 werkzeug>=3.0.1 # not directly required, pinned by Snyk to avoid a vulnerability +zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability From 5c7ef49a6c7eb699631251ffa0ef79fe4baabf5e Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 25 Jul 2024 14:00:40 +0200 Subject: [PATCH 1102/1185] Update links.yml (#2255) --- .github/workflows/links.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index a90e2c20fb..b928aa6682 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -43,6 +43,7 @@ jobs: --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ --exclude-path '**/ci.yaml' \ --github-token ${{ secrets.GITHUB_TOKEN }} \ + --header "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \ './**/*.md' \ './**/*.html' @@ -63,6 +64,7 @@ jobs: --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ --exclude-path '**/ci.yaml' \ --github-token ${{ secrets.GITHUB_TOKEN }} \ + --header "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \ './**/*.md' \ './**/*.html' \ './**/*.yml' \ From e6b3a931f51ef36fa936730566502a9f77765869 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 29 Jul 2024 02:10:36 +0200 Subject: [PATCH 1103/1185] [Snyk] Security upgrade setuptools from 40.5.0 to 70.0.0 (#2263) fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-SETUPTOOLS-7448482 Co-authored-by: snyk-bot From 3a9231af38391c3f879b85bcc61ab813058c096c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 29 Jul 2024 02:10:45 +0200 Subject: [PATCH 1104/1185] [Snyk] Security upgrade zipp from 3.15.0 to 3.19.1 (#2262) fix: utils/google_app_engine/additional_requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-ZIPP-7430899 Co-authored-by: snyk-bot From 55eaec541a15bbc8a20a4269b20df0ba30c1327d Mon Sep 17 00:00:00 2001 From: Ultralytics Assistant <135830346+UltralyticsAssistant@users.noreply.github.com> Date: Wed, 14 Aug 2024 20:50:04 +0200 Subject: [PATCH 1105/1185] Ultralytics Actions JSON, CSS and autolabel support (#2267) * Update Ultralytics Actions * Update format.yml --------- Co-authored-by: Glenn Jocher --- .github/workflows/format.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index b809830d50..7ba7e5822a 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 - AGPL-3.0 License https://ultralytics.com/license # Ultralytics Actions https://github.com/ultralytics/actions # This workflow automatically formats code and documentation in PRs to official Ultralytics standards @@ -6,9 +6,10 @@ name: Ultralytics Actions on: issues: - types: [opened, edited] + types: [opened] pull_request_target: - branches: [main, master] + branches: [main,master] + types: [opened, closed, synchronize, review_requested] jobs: format: @@ -20,10 +21,9 @@ jobs: token: ${{ secrets.PERSONAL_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} # note GITHUB_TOKEN automatically generated labels: true # autolabel issues and PRs python: true # format Python code and docstrings - markdown: true # format Markdown - prettier: true # format YAML + prettier: true # format YAML, JSON, Markdown and CSS spelling: true # check spelling links: false # check broken links - summary: true # print PR summary with GPT4 (requires 'openai_api_key' or 'openai_azure_api_key' and 'openai_azure_endpoint') + summary: true # print PR summary with GPT4o (requires 'openai_api_key') openai_azure_api_key: ${{ secrets.OPENAI_AZURE_API_KEY }} openai_azure_endpoint: ${{ secrets.OPENAI_AZURE_ENDPOINT }} From d785a80f5c3d59d5d894e79c4dc616ece6bb1d37 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 20 Aug 2024 05:02:19 +0800 Subject: [PATCH 1106/1185] Ultralytics Code Refactor https://ultralytics.com/actions (#2271) * Refactor code for speed and clarity * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: UltralyticsAssistant --- .github/workflows/format.yml | 2 +- README.md | 2 +- README.zh-CN.md | 2 +- classify/tutorial.ipynb | 2933 +++++++++++++++++----------------- segment/tutorial.ipynb | 1161 +++++++------- 5 files changed, 2055 insertions(+), 2045 deletions(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 7ba7e5822a..b326e778da 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -8,7 +8,7 @@ on: issues: types: [opened] pull_request_target: - branches: [main,master] + branches: [main, master] types: [opened, closed, synchronize, review_requested] jobs: diff --git a/README.md b/README.md index 6a50e7f476..e4314803be 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

-[中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [Türkçe](https://docs.ultralytics.com/tr/) | [Tiếng Việt](https://docs.ultralytics.com/vi/) | [हिन्दी](https://docs.ultralytics.com/hi/) | [العربية](https://docs.ultralytics.com/ar/) +[中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [Türkçe](https://docs.ultralytics.com/tr/) | [Tiếng Việt](https://docs.ultralytics.com/vi/) | [العربية](https://docs.ultralytics.com/ar/)
YOLOv3 CI diff --git a/README.zh-CN.md b/README.zh-CN.md index a63eabb4fb..6a483a1164 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -4,7 +4,7 @@

-[中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [Türkçe](https://docs.ultralytics.com/tr/) | [Tiếng Việt](https://docs.ultralytics.com/vi/) | [हिन्दी](https://docs.ultralytics.com/hi/) | [العربية](https://docs.ultralytics.com/ar/) +[中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [Türkçe](https://docs.ultralytics.com/tr/) | [Tiếng Việt](https://docs.ultralytics.com/vi/) | [العربية](https://docs.ultralytics.com/ar/)
YOLOv3 CI diff --git a/classify/tutorial.ipynb b/classify/tutorial.ipynb index 34eaca9553..3252daf718 100644 --- a/classify/tutorial.ipynb +++ b/classify/tutorial.ipynb @@ -1,1481 +1,1486 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "t6MPjfT5NrKQ" - }, - "source": [ - "
\n", - "\n", - " \n", - " \n", - "\n", - "\n", - "
\n", - " \"Run\n", - " \"Open\n", - " \"Open\n", - "
\n", - "\n", - "This YOLOv5 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", - "\n", - "
" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "7mGmQbAO5pQb" - }, - "source": [ - "# Setup\n", - "\n", - "Clone GitHub [repository](https://github.com/ultralytics/yolov5), install [dependencies](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) and check PyTorch and GPU." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "wbvMlHd_QwMG", - "outputId": "0806e375-610d-4ec0-c867-763dbb518279" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stderr", - "text": [ - "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n" - ] - }, - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Setup complete ✅ (2 CPUs, 12.7 GB RAM, 22.6/78.2 GB disk)\n" - ] - } - ], - "source": [ - "!git clone https://github.com/ultralytics/yolov5 # clone\n", - "%cd yolov5\n", - "%pip install -qr requirements.txt # install\n", - "\n", - "import torch\n", - "import utils\n", - "display = utils.notebook_init() # checks" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "4JnkELT0cIJg" - }, - "source": [ - "# 1. Predict\n", - "\n", - "`classify/predict.py` runs YOLOv5 Classification inference on a variety of sources, downloading models automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases), and saving results to `runs/predict-cls`. Example inference sources are:\n", - "\n", - "```shell\n", - "python classify/predict.py --source 0 # webcam\n", - " img.jpg # image \n", - " vid.mp4 # video\n", - " screen # screenshot\n", - " path/ # directory\n", - " 'path/*.jpg' # glob\n", - " 'https://youtu.be/LNwODJXcvt4' # YouTube\n", - " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "zR9ZbuQCH7FX", - "outputId": "50504ef7-aa3e-4281-a4e3-d0c7df3c0ffe" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "\u001b[34m\u001b[1mclassify/predict: \u001b[0mweights=['yolov5s-cls.pt'], source=data/images, data=data/coco128.yaml, imgsz=[224, 224], device=, view_img=False, save_txt=False, nosave=False, augment=False, visualize=False, update=False, project=runs/predict-cls, name=exp, exist_ok=False, half=False, dnn=False, vid_stride=1\n", - "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", - "\n", - "Downloading https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt to yolov5s-cls.pt...\n", - "100% 10.5M/10.5M [00:00<00:00, 12.3MB/s]\n", - "\n", - "Fusing layers... \n", - "Model summary: 117 layers, 5447688 parameters, 0 gradients, 11.4 GFLOPs\n", - "image 1/2 /content/yolov5/data/images/bus.jpg: 224x224 minibus 0.39, police van 0.24, amphibious vehicle 0.05, recreational vehicle 0.04, trolleybus 0.03, 3.9ms\n", - "image 2/2 /content/yolov5/data/images/zidane.jpg: 224x224 suit 0.38, bow tie 0.19, bridegroom 0.18, rugby ball 0.04, stage 0.02, 4.6ms\n", - "Speed: 0.3ms pre-process, 4.3ms inference, 1.5ms NMS per image at shape (1, 3, 224, 224)\n", - "Results saved to \u001b[1mruns/predict-cls/exp\u001b[0m\n" - ] - } - ], - "source": [ - "!python classify/predict.py --weights yolov5s-cls.pt --img 224 --source data/images\n", - "# display.Image(filename='runs/predict-cls/exp/zidane.jpg', width=600)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "hkAzDWJ7cWTr" - }, - "source": [ - "        \n", - "" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "0eq1SMWl6Sfn" - }, - "source": [ - "# 2. Validate\n", - "Validate a model's accuracy on the [Imagenet](https://image-net.org/) dataset's `val` or `test` splits. Models are downloaded automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases). To show results by class use the `--verbose` flag." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "WQPtK1QYVaD_", - "outputId": "20fc0630-141e-4a90-ea06-342cbd7ce496" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "--2022-11-22 19:53:40-- https://image-net.org/data/ILSVRC/2012/ILSVRC2012_img_val.tar\n", - "Resolving image-net.org (image-net.org)... 171.64.68.16\n", - "Connecting to image-net.org (image-net.org)|171.64.68.16|:443... connected.\n", - "HTTP request sent, awaiting response... 200 OK\n", - "Length: 6744924160 (6.3G) [application/x-tar]\n", - "Saving to: ‘ILSVRC2012_img_val.tar’\n", - "\n", - "ILSVRC2012_img_val. 100%[===================>] 6.28G 16.1MB/s in 10m 52s \n", - "\n", - "2022-11-22 20:04:32 (9.87 MB/s) - ‘ILSVRC2012_img_val.tar’ saved [6744924160/6744924160]\n", - "\n" - ] - } - ], - "source": [ - "# Download Imagenet val (6.3G, 50000 images)\n", - "!bash data/scripts/get_imagenet.sh --val" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "X58w8JLpMnjH", - "outputId": "41843132-98e2-4c25-d474-4cd7b246fb8e" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "\u001b[34m\u001b[1mclassify/val: \u001b[0mdata=../datasets/imagenet, weights=['yolov5s-cls.pt'], batch_size=128, imgsz=224, device=, workers=8, verbose=True, project=runs/val-cls, name=exp, exist_ok=False, half=True, dnn=False\n", - "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", - "\n", - "Fusing layers... \n", - "Model summary: 117 layers, 5447688 parameters, 0 gradients, 11.4 GFLOPs\n", - "validating: 100% 391/391 [04:57<00:00, 1.31it/s]\n", - " Class Images top1_acc top5_acc\n", - " all 50000 0.715 0.902\n", - " tench 50 0.94 0.98\n", - " goldfish 50 0.88 0.92\n", - " great white shark 50 0.78 0.96\n", - " tiger shark 50 0.68 0.96\n", - " hammerhead shark 50 0.82 0.92\n", - " electric ray 50 0.76 0.9\n", - " stingray 50 0.7 0.9\n", - " cock 50 0.78 0.92\n", - " hen 50 0.84 0.96\n", - " ostrich 50 0.98 1\n", - " brambling 50 0.9 0.96\n", - " goldfinch 50 0.92 0.98\n", - " house finch 50 0.88 0.96\n", - " junco 50 0.94 0.98\n", - " indigo bunting 50 0.86 0.88\n", - " American robin 50 0.9 0.96\n", - " bulbul 50 0.84 0.96\n", - " jay 50 0.9 0.96\n", - " magpie 50 0.84 0.96\n", - " chickadee 50 0.9 1\n", - " American dipper 50 0.82 0.92\n", - " kite 50 0.76 0.94\n", - " bald eagle 50 0.92 1\n", - " vulture 50 0.96 1\n", - " great grey owl 50 0.94 0.98\n", - " fire salamander 50 0.96 0.98\n", - " smooth newt 50 0.58 0.94\n", - " newt 50 0.74 0.9\n", - " spotted salamander 50 0.86 0.94\n", - " axolotl 50 0.86 0.96\n", - " American bullfrog 50 0.78 0.92\n", - " tree frog 50 0.84 0.96\n", - " tailed frog 50 0.48 0.8\n", - " loggerhead sea turtle 50 0.68 0.94\n", - " leatherback sea turtle 50 0.5 0.8\n", - " mud turtle 50 0.64 0.84\n", - " terrapin 50 0.52 0.98\n", - " box turtle 50 0.84 0.98\n", - " banded gecko 50 0.7 0.88\n", - " green iguana 50 0.76 0.94\n", - " Carolina anole 50 0.58 0.96\n", - "desert grassland whiptail lizard 50 0.82 0.94\n", - " agama 50 0.74 0.92\n", - " frilled-necked lizard 50 0.84 0.86\n", - " alligator lizard 50 0.58 0.78\n", - " Gila monster 50 0.72 0.8\n", - " European green lizard 50 0.42 0.9\n", - " chameleon 50 0.76 0.84\n", - " Komodo dragon 50 0.86 0.96\n", - " Nile crocodile 50 0.7 0.84\n", - " American alligator 50 0.76 0.96\n", - " triceratops 50 0.9 0.94\n", - " worm snake 50 0.76 0.88\n", - " ring-necked snake 50 0.8 0.92\n", - " eastern hog-nosed snake 50 0.58 0.88\n", - " smooth green snake 50 0.6 0.94\n", - " kingsnake 50 0.82 0.9\n", - " garter snake 50 0.88 0.94\n", - " water snake 50 0.7 0.94\n", - " vine snake 50 0.66 0.76\n", - " night snake 50 0.34 0.82\n", - " boa constrictor 50 0.8 0.96\n", - " African rock python 50 0.48 0.76\n", - " Indian cobra 50 0.82 0.94\n", - " green mamba 50 0.54 0.86\n", - " sea snake 50 0.62 0.9\n", - " Saharan horned viper 50 0.56 0.86\n", - "eastern diamondback rattlesnake 50 0.6 0.86\n", - " sidewinder 50 0.28 0.86\n", - " trilobite 50 0.98 0.98\n", - " harvestman 50 0.86 0.94\n", - " scorpion 50 0.86 0.94\n", - " yellow garden spider 50 0.92 0.96\n", - " barn spider 50 0.38 0.98\n", - " European garden spider 50 0.62 0.98\n", - " southern black widow 50 0.88 0.94\n", - " tarantula 50 0.94 1\n", - " wolf spider 50 0.82 0.92\n", - " tick 50 0.74 0.84\n", - " centipede 50 0.68 0.82\n", - " black grouse 50 0.88 0.98\n", - " ptarmigan 50 0.78 0.94\n", - " ruffed grouse 50 0.88 1\n", - " prairie grouse 50 0.92 1\n", - " peacock 50 0.88 0.9\n", - " quail 50 0.9 0.94\n", - " partridge 50 0.74 0.96\n", - " grey parrot 50 0.9 0.96\n", - " macaw 50 0.88 0.98\n", - "sulphur-crested cockatoo 50 0.86 0.92\n", - " lorikeet 50 0.96 1\n", - " coucal 50 0.82 0.88\n", - " bee eater 50 0.96 0.98\n", - " hornbill 50 0.9 0.96\n", - " hummingbird 50 0.88 0.96\n", - " jacamar 50 0.92 0.94\n", - " toucan 50 0.84 0.94\n", - " duck 50 0.76 0.94\n", - " red-breasted merganser 50 0.86 0.96\n", - " goose 50 0.74 0.96\n", - " black swan 50 0.94 0.98\n", - " tusker 50 0.54 0.92\n", - " echidna 50 0.98 1\n", - " platypus 50 0.72 0.84\n", - " wallaby 50 0.78 0.88\n", - " koala 50 0.84 0.92\n", - " wombat 50 0.78 0.84\n", - " jellyfish 50 0.88 0.96\n", - " sea anemone 50 0.72 0.9\n", - " brain coral 50 0.88 0.96\n", - " flatworm 50 0.8 0.98\n", - " nematode 50 0.86 0.9\n", - " conch 50 0.74 0.88\n", - " snail 50 0.78 0.88\n", - " slug 50 0.74 0.82\n", - " sea slug 50 0.88 0.98\n", - " chiton 50 0.88 0.98\n", - " chambered nautilus 50 0.88 0.92\n", - " Dungeness crab 50 0.78 0.94\n", - " rock crab 50 0.68 0.86\n", - " fiddler crab 50 0.64 0.86\n", - " red king crab 50 0.76 0.96\n", - " American lobster 50 0.78 0.96\n", - " spiny lobster 50 0.74 0.88\n", - " crayfish 50 0.56 0.86\n", - " hermit crab 50 0.78 0.96\n", - " isopod 50 0.66 0.78\n", - " white stork 50 0.88 0.96\n", - " black stork 50 0.84 0.98\n", - " spoonbill 50 0.96 1\n", - " flamingo 50 0.94 1\n", - " little blue heron 50 0.92 0.98\n", - " great egret 50 0.9 0.96\n", - " bittern 50 0.86 0.94\n", - " crane (bird) 50 0.62 0.9\n", - " limpkin 50 0.98 1\n", - " common gallinule 50 0.92 0.96\n", - " American coot 50 0.9 0.98\n", - " bustard 50 0.92 0.96\n", - " ruddy turnstone 50 0.94 1\n", - " dunlin 50 0.86 0.94\n", - " common redshank 50 0.9 0.96\n", - " dowitcher 50 0.84 0.96\n", - " oystercatcher 50 0.86 0.94\n", - " pelican 50 0.92 0.96\n", - " king penguin 50 0.88 0.96\n", - " albatross 50 0.9 1\n", - " grey whale 50 0.84 0.92\n", - " killer whale 50 0.92 1\n", - " dugong 50 0.84 0.96\n", - " sea lion 50 0.82 0.92\n", - " Chihuahua 50 0.66 0.84\n", - " Japanese Chin 50 0.72 0.98\n", - " Maltese 50 0.76 0.94\n", - " Pekingese 50 0.84 0.94\n", - " Shih Tzu 50 0.74 0.96\n", - " King Charles Spaniel 50 0.88 0.98\n", - " Papillon 50 0.86 0.94\n", - " toy terrier 50 0.48 0.94\n", - " Rhodesian Ridgeback 50 0.76 0.98\n", - " Afghan Hound 50 0.84 1\n", - " Basset Hound 50 0.8 0.92\n", - " Beagle 50 0.82 0.96\n", - " Bloodhound 50 0.48 0.72\n", - " Bluetick Coonhound 50 0.86 0.94\n", - " Black and Tan Coonhound 50 0.54 0.8\n", - "Treeing Walker Coonhound 50 0.66 0.98\n", - " English foxhound 50 0.32 0.84\n", - " Redbone Coonhound 50 0.62 0.94\n", - " borzoi 50 0.92 1\n", - " Irish Wolfhound 50 0.48 0.88\n", - " Italian Greyhound 50 0.76 0.98\n", - " Whippet 50 0.74 0.92\n", - " Ibizan Hound 50 0.6 0.86\n", - " Norwegian Elkhound 50 0.88 0.98\n", - " Otterhound 50 0.62 0.9\n", - " Saluki 50 0.72 0.92\n", - " Scottish Deerhound 50 0.86 0.98\n", - " Weimaraner 50 0.88 0.94\n", - "Staffordshire Bull Terrier 50 0.66 0.98\n", - "American Staffordshire Terrier 50 0.64 0.92\n", - " Bedlington Terrier 50 0.9 0.92\n", - " Border Terrier 50 0.86 0.92\n", - " Kerry Blue Terrier 50 0.78 0.98\n", - " Irish Terrier 50 0.7 0.96\n", - " Norfolk Terrier 50 0.68 0.9\n", - " Norwich Terrier 50 0.72 1\n", - " Yorkshire Terrier 50 0.66 0.9\n", - " Wire Fox Terrier 50 0.64 0.98\n", - " Lakeland Terrier 50 0.74 0.92\n", - " Sealyham Terrier 50 0.76 0.9\n", - " Airedale Terrier 50 0.82 0.92\n", - " Cairn Terrier 50 0.76 0.9\n", - " Australian Terrier 50 0.48 0.84\n", - " Dandie Dinmont Terrier 50 0.82 0.92\n", - " Boston Terrier 50 0.92 1\n", - " Miniature Schnauzer 50 0.68 0.9\n", - " Giant Schnauzer 50 0.72 0.98\n", - " Standard Schnauzer 50 0.74 1\n", - " Scottish Terrier 50 0.76 0.96\n", - " Tibetan Terrier 50 0.48 1\n", - "Australian Silky Terrier 50 0.66 0.96\n", - "Soft-coated Wheaten Terrier 50 0.74 0.96\n", - "West Highland White Terrier 50 0.88 0.96\n", - " Lhasa Apso 50 0.68 0.96\n", - " Flat-Coated Retriever 50 0.72 0.94\n", - " Curly-coated Retriever 50 0.82 0.94\n", - " Golden Retriever 50 0.86 0.94\n", - " Labrador Retriever 50 0.82 0.94\n", - "Chesapeake Bay Retriever 50 0.76 0.96\n", - "German Shorthaired Pointer 50 0.8 0.96\n", - " Vizsla 50 0.68 0.96\n", - " English Setter 50 0.7 1\n", - " Irish Setter 50 0.8 0.9\n", - " Gordon Setter 50 0.84 0.92\n", - " Brittany 50 0.84 0.96\n", - " Clumber Spaniel 50 0.92 0.96\n", - "English Springer Spaniel 50 0.88 1\n", - " Welsh Springer Spaniel 50 0.92 1\n", - " Cocker Spaniels 50 0.7 0.94\n", - " Sussex Spaniel 50 0.72 0.92\n", - " Irish Water Spaniel 50 0.88 0.98\n", - " Kuvasz 50 0.66 0.9\n", - " Schipperke 50 0.9 0.98\n", - " Groenendael 50 0.8 0.94\n", - " Malinois 50 0.86 0.98\n", - " Briard 50 0.52 0.8\n", - " Australian Kelpie 50 0.6 0.88\n", - " Komondor 50 0.88 0.94\n", - " Old English Sheepdog 50 0.94 0.98\n", - " Shetland Sheepdog 50 0.74 0.9\n", - " collie 50 0.6 0.96\n", - " Border Collie 50 0.74 0.96\n", - " Bouvier des Flandres 50 0.78 0.94\n", - " Rottweiler 50 0.88 0.96\n", - " German Shepherd Dog 50 0.8 0.98\n", - " Dobermann 50 0.68 0.96\n", - " Miniature Pinscher 50 0.76 0.88\n", - "Greater Swiss Mountain Dog 50 0.68 0.94\n", - " Bernese Mountain Dog 50 0.96 1\n", - " Appenzeller Sennenhund 50 0.22 1\n", - " Entlebucher Sennenhund 50 0.64 0.98\n", - " Boxer 50 0.7 0.92\n", - " Bullmastiff 50 0.78 0.98\n", - " Tibetan Mastiff 50 0.88 0.96\n", - " French Bulldog 50 0.84 0.94\n", - " Great Dane 50 0.54 0.9\n", - " St. Bernard 50 0.92 1\n", - " husky 50 0.46 0.98\n", - " Alaskan Malamute 50 0.76 0.96\n", - " Siberian Husky 50 0.46 0.98\n", - " Dalmatian 50 0.94 0.98\n", - " Affenpinscher 50 0.78 0.9\n", - " Basenji 50 0.92 0.94\n", - " pug 50 0.94 0.98\n", - " Leonberger 50 1 1\n", - " Newfoundland 50 0.78 0.96\n", - " Pyrenean Mountain Dog 50 0.78 0.96\n", - " Samoyed 50 0.96 1\n", - " Pomeranian 50 0.98 1\n", - " Chow Chow 50 0.9 0.96\n", - " Keeshond 50 0.88 0.94\n", - " Griffon Bruxellois 50 0.84 0.98\n", - " Pembroke Welsh Corgi 50 0.82 0.94\n", - " Cardigan Welsh Corgi 50 0.66 0.98\n", - " Toy Poodle 50 0.52 0.88\n", - " Miniature Poodle 50 0.52 0.92\n", - " Standard Poodle 50 0.8 1\n", - " Mexican hairless dog 50 0.88 0.98\n", - " grey wolf 50 0.82 0.92\n", - " Alaskan tundra wolf 50 0.78 0.98\n", - " red wolf 50 0.48 0.9\n", - " coyote 50 0.64 0.86\n", - " dingo 50 0.76 0.88\n", - " dhole 50 0.9 0.98\n", - " African wild dog 50 0.98 1\n", - " hyena 50 0.88 0.96\n", - " red fox 50 0.54 0.92\n", - " kit fox 50 0.72 0.98\n", - " Arctic fox 50 0.94 1\n", - " grey fox 50 0.7 0.94\n", - " tabby cat 50 0.54 0.92\n", - " tiger cat 50 0.22 0.94\n", - " Persian cat 50 0.9 0.98\n", - " Siamese cat 50 0.96 1\n", - " Egyptian Mau 50 0.54 0.8\n", - " cougar 50 0.9 1\n", - " lynx 50 0.72 0.88\n", - " leopard 50 0.78 0.98\n", - " snow leopard 50 0.9 0.98\n", - " jaguar 50 0.7 0.94\n", - " lion 50 0.9 0.98\n", - " tiger 50 0.92 0.98\n", - " cheetah 50 0.94 0.98\n", - " brown bear 50 0.94 0.98\n", - " American black bear 50 0.8 1\n", - " polar bear 50 0.84 0.96\n", - " sloth bear 50 0.72 0.92\n", - " mongoose 50 0.7 0.92\n", - " meerkat 50 0.82 0.92\n", - " tiger beetle 50 0.92 0.94\n", - " ladybug 50 0.86 0.94\n", - " ground beetle 50 0.64 0.94\n", - " longhorn beetle 50 0.62 0.88\n", - " leaf beetle 50 0.64 0.98\n", - " dung beetle 50 0.86 0.98\n", - " rhinoceros beetle 50 0.86 0.94\n", - " weevil 50 0.9 1\n", - " fly 50 0.78 0.94\n", - " bee 50 0.68 0.94\n", - " ant 50 0.68 0.78\n", - " grasshopper 50 0.5 0.92\n", - " cricket 50 0.64 0.92\n", - " stick insect 50 0.64 0.92\n", - " cockroach 50 0.72 0.8\n", - " mantis 50 0.64 0.86\n", - " cicada 50 0.9 0.96\n", - " leafhopper 50 0.88 0.94\n", - " lacewing 50 0.78 0.92\n", - " dragonfly 50 0.82 0.98\n", - " damselfly 50 0.82 1\n", - " red admiral 50 0.94 0.96\n", - " ringlet 50 0.86 0.98\n", - " monarch butterfly 50 0.9 0.92\n", - " small white 50 0.9 1\n", - " sulphur butterfly 50 0.92 1\n", - "gossamer-winged butterfly 50 0.88 1\n", - " starfish 50 0.88 0.92\n", - " sea urchin 50 0.84 0.94\n", - " sea cucumber 50 0.66 0.84\n", - " cottontail rabbit 50 0.72 0.94\n", - " hare 50 0.84 0.96\n", - " Angora rabbit 50 0.94 0.98\n", - " hamster 50 0.96 1\n", - " porcupine 50 0.88 0.98\n", - " fox squirrel 50 0.76 0.94\n", - " marmot 50 0.92 0.96\n", - " beaver 50 0.78 0.94\n", - " guinea pig 50 0.78 0.94\n", - " common sorrel 50 0.96 0.98\n", - " zebra 50 0.94 0.96\n", - " pig 50 0.5 0.76\n", - " wild boar 50 0.84 0.96\n", - " warthog 50 0.84 0.96\n", - " hippopotamus 50 0.88 0.96\n", - " ox 50 0.48 0.94\n", - " water buffalo 50 0.78 0.94\n", - " bison 50 0.88 0.96\n", - " ram 50 0.58 0.92\n", - " bighorn sheep 50 0.66 1\n", - " Alpine ibex 50 0.92 0.98\n", - " hartebeest 50 0.94 1\n", - " impala 50 0.82 0.96\n", - " gazelle 50 0.7 0.96\n", - " dromedary 50 0.9 1\n", - " llama 50 0.82 0.94\n", - " weasel 50 0.44 0.92\n", - " mink 50 0.78 0.96\n", - " European polecat 50 0.46 0.9\n", - " black-footed ferret 50 0.68 0.96\n", - " otter 50 0.66 0.88\n", - " skunk 50 0.96 0.96\n", - " badger 50 0.86 0.92\n", - " armadillo 50 0.88 0.9\n", - " three-toed sloth 50 0.96 1\n", - " orangutan 50 0.78 0.92\n", - " gorilla 50 0.82 0.94\n", - " chimpanzee 50 0.84 0.94\n", - " gibbon 50 0.76 0.86\n", - " siamang 50 0.68 0.94\n", - " guenon 50 0.8 0.94\n", - " patas monkey 50 0.62 0.82\n", - " baboon 50 0.9 0.98\n", - " macaque 50 0.8 0.86\n", - " langur 50 0.6 0.82\n", - " black-and-white colobus 50 0.86 0.9\n", - " proboscis monkey 50 1 1\n", - " marmoset 50 0.74 0.98\n", - " white-headed capuchin 50 0.72 0.9\n", - " howler monkey 50 0.86 0.94\n", - " titi 50 0.5 0.9\n", - "Geoffroy's spider monkey 50 0.42 0.8\n", - " common squirrel monkey 50 0.76 0.92\n", - " ring-tailed lemur 50 0.72 0.94\n", - " indri 50 0.9 0.96\n", - " Asian elephant 50 0.58 0.92\n", - " African bush elephant 50 0.7 0.98\n", - " red panda 50 0.94 0.94\n", - " giant panda 50 0.94 0.98\n", - " snoek 50 0.74 0.9\n", - " eel 50 0.6 0.84\n", - " coho salmon 50 0.84 0.96\n", - " rock beauty 50 0.88 0.98\n", - " clownfish 50 0.78 0.98\n", - " sturgeon 50 0.68 0.94\n", - " garfish 50 0.62 0.8\n", - " lionfish 50 0.96 0.96\n", - " pufferfish 50 0.88 0.96\n", - " abacus 50 0.74 0.88\n", - " abaya 50 0.84 0.92\n", - " academic gown 50 0.42 0.86\n", - " accordion 50 0.8 0.9\n", - " acoustic guitar 50 0.5 0.76\n", - " aircraft carrier 50 0.8 0.96\n", - " airliner 50 0.92 1\n", - " airship 50 0.76 0.82\n", - " altar 50 0.64 0.98\n", - " ambulance 50 0.88 0.98\n", - " amphibious vehicle 50 0.64 0.94\n", - " analog clock 50 0.52 0.92\n", - " apiary 50 0.82 0.96\n", - " apron 50 0.7 0.84\n", - " waste container 50 0.4 0.8\n", - " assault rifle 50 0.42 0.84\n", - " backpack 50 0.34 0.64\n", - " bakery 50 0.4 0.68\n", - " balance beam 50 0.8 0.98\n", - " balloon 50 0.86 0.96\n", - " ballpoint pen 50 0.52 0.96\n", - " Band-Aid 50 0.7 0.9\n", - " banjo 50 0.84 1\n", - " baluster 50 0.68 0.94\n", - " barbell 50 0.56 0.9\n", - " barber chair 50 0.7 0.92\n", - " barbershop 50 0.54 0.86\n", - " barn 50 0.96 0.96\n", - " barometer 50 0.84 0.98\n", - " barrel 50 0.56 0.88\n", - " wheelbarrow 50 0.66 0.88\n", - " baseball 50 0.74 0.98\n", - " basketball 50 0.88 0.98\n", - " bassinet 50 0.66 0.92\n", - " bassoon 50 0.74 0.98\n", - " swimming cap 50 0.62 0.88\n", - " bath towel 50 0.54 0.78\n", - " bathtub 50 0.4 0.88\n", - " station wagon 50 0.66 0.84\n", - " lighthouse 50 0.78 0.94\n", - " beaker 50 0.52 0.68\n", - " military cap 50 0.84 0.96\n", - " beer bottle 50 0.66 0.88\n", - " beer glass 50 0.6 0.84\n", - " bell-cot 50 0.56 0.96\n", - " bib 50 0.58 0.82\n", - " tandem bicycle 50 0.86 0.96\n", - " bikini 50 0.56 0.88\n", - " ring binder 50 0.64 0.84\n", - " binoculars 50 0.54 0.78\n", - " birdhouse 50 0.86 0.94\n", - " boathouse 50 0.74 0.92\n", - " bobsleigh 50 0.92 0.96\n", - " bolo tie 50 0.8 0.94\n", - " poke bonnet 50 0.64 0.86\n", - " bookcase 50 0.66 0.92\n", - " bookstore 50 0.62 0.88\n", - " bottle cap 50 0.58 0.7\n", - " bow 50 0.72 0.86\n", - " bow tie 50 0.7 0.9\n", - " brass 50 0.92 0.96\n", - " bra 50 0.5 0.7\n", - " breakwater 50 0.62 0.86\n", - " breastplate 50 0.4 0.9\n", - " broom 50 0.6 0.86\n", - " bucket 50 0.66 0.8\n", - " buckle 50 0.5 0.68\n", - " bulletproof vest 50 0.5 0.78\n", - " high-speed train 50 0.94 0.96\n", - " butcher shop 50 0.74 0.94\n", - " taxicab 50 0.64 0.86\n", - " cauldron 50 0.44 0.66\n", - " candle 50 0.48 0.74\n", - " cannon 50 0.88 0.94\n", - " canoe 50 0.94 1\n", - " can opener 50 0.66 0.86\n", - " cardigan 50 0.68 0.8\n", - " car mirror 50 0.94 0.96\n", - " carousel 50 0.94 0.98\n", - " tool kit 50 0.56 0.78\n", - " carton 50 0.42 0.7\n", - " car wheel 50 0.38 0.74\n", - "automated teller machine 50 0.76 0.94\n", - " cassette 50 0.52 0.8\n", - " cassette player 50 0.28 0.9\n", - " castle 50 0.78 0.88\n", - " catamaran 50 0.78 1\n", - " CD player 50 0.52 0.82\n", - " cello 50 0.82 1\n", - " mobile phone 50 0.68 0.86\n", - " chain 50 0.38 0.66\n", - " chain-link fence 50 0.7 0.84\n", - " chain mail 50 0.64 0.9\n", - " chainsaw 50 0.84 0.92\n", - " chest 50 0.68 0.92\n", - " chiffonier 50 0.26 0.64\n", - " chime 50 0.62 0.84\n", - " china cabinet 50 0.82 0.96\n", - " Christmas stocking 50 0.92 0.94\n", - " church 50 0.62 0.9\n", - " movie theater 50 0.58 0.88\n", - " cleaver 50 0.32 0.62\n", - " cliff dwelling 50 0.88 1\n", - " cloak 50 0.32 0.64\n", - " clogs 50 0.58 0.88\n", - " cocktail shaker 50 0.62 0.7\n", - " coffee mug 50 0.44 0.72\n", - " coffeemaker 50 0.64 0.92\n", - " coil 50 0.66 0.84\n", - " combination lock 50 0.64 0.84\n", - " computer keyboard 50 0.7 0.82\n", - " confectionery store 50 0.54 0.86\n", - " container ship 50 0.82 0.98\n", - " convertible 50 0.78 0.98\n", - " corkscrew 50 0.82 0.92\n", - " cornet 50 0.46 0.88\n", - " cowboy boot 50 0.64 0.8\n", - " cowboy hat 50 0.64 0.82\n", - " cradle 50 0.38 0.8\n", - " crane (machine) 50 0.78 0.94\n", - " crash helmet 50 0.92 0.96\n", - " crate 50 0.52 0.82\n", - " infant bed 50 0.74 1\n", - " Crock Pot 50 0.78 0.9\n", - " croquet ball 50 0.9 0.96\n", - " crutch 50 0.46 0.7\n", - " cuirass 50 0.54 0.86\n", - " dam 50 0.74 0.92\n", - " desk 50 0.6 0.86\n", - " desktop computer 50 0.54 0.94\n", - " rotary dial telephone 50 0.88 0.94\n", - " diaper 50 0.68 0.84\n", - " digital clock 50 0.54 0.76\n", - " digital watch 50 0.58 0.86\n", - " dining table 50 0.76 0.9\n", - " dishcloth 50 0.94 1\n", - " dishwasher 50 0.44 0.78\n", - " disc brake 50 0.98 1\n", - " dock 50 0.54 0.94\n", - " dog sled 50 0.84 1\n", - " dome 50 0.72 0.92\n", - " doormat 50 0.56 0.82\n", - " drilling rig 50 0.84 0.96\n", - " drum 50 0.38 0.68\n", - " drumstick 50 0.56 0.72\n", - " dumbbell 50 0.62 0.9\n", - " Dutch oven 50 0.7 0.84\n", - " electric fan 50 0.82 0.86\n", - " electric guitar 50 0.62 0.84\n", - " electric locomotive 50 0.92 0.98\n", - " entertainment center 50 0.9 0.98\n", - " envelope 50 0.44 0.86\n", - " espresso machine 50 0.72 0.94\n", - " face powder 50 0.7 0.92\n", - " feather boa 50 0.7 0.84\n", - " filing cabinet 50 0.88 0.98\n", - " fireboat 50 0.94 0.98\n", - " fire engine 50 0.84 0.9\n", - " fire screen sheet 50 0.62 0.76\n", - " flagpole 50 0.74 0.88\n", - " flute 50 0.36 0.72\n", - " folding chair 50 0.62 0.84\n", - " football helmet 50 0.86 0.94\n", - " forklift 50 0.8 0.92\n", - " fountain 50 0.84 0.94\n", - " fountain pen 50 0.76 0.92\n", - " four-poster bed 50 0.78 0.94\n", - " freight car 50 0.96 1\n", - " French horn 50 0.76 0.92\n", - " frying pan 50 0.36 0.78\n", - " fur coat 50 0.84 0.96\n", - " garbage truck 50 0.9 0.98\n", - " gas mask 50 0.84 0.92\n", - " gas pump 50 0.9 0.98\n", - " goblet 50 0.68 0.82\n", - " go-kart 50 0.9 1\n", - " golf ball 50 0.84 0.9\n", - " golf cart 50 0.78 0.86\n", - " gondola 50 0.98 0.98\n", - " gong 50 0.74 0.92\n", - " gown 50 0.62 0.96\n", - " grand piano 50 0.7 0.96\n", - " greenhouse 50 0.8 0.98\n", - " grille 50 0.72 0.9\n", - " grocery store 50 0.66 0.94\n", - " guillotine 50 0.86 0.92\n", - " barrette 50 0.52 0.66\n", - " hair spray 50 0.5 0.74\n", - " half-track 50 0.78 0.9\n", - " hammer 50 0.56 0.76\n", - " hamper 50 0.64 0.84\n", - " hair dryer 50 0.56 0.74\n", - " hand-held computer 50 0.42 0.86\n", - " handkerchief 50 0.78 0.94\n", - " hard disk drive 50 0.76 0.84\n", - " harmonica 50 0.7 0.88\n", - " harp 50 0.88 0.96\n", - " harvester 50 0.78 1\n", - " hatchet 50 0.54 0.74\n", - " holster 50 0.66 0.84\n", - " home theater 50 0.64 0.94\n", - " honeycomb 50 0.56 0.88\n", - " hook 50 0.3 0.6\n", - " hoop skirt 50 0.64 0.86\n", - " horizontal bar 50 0.68 0.98\n", - " horse-drawn vehicle 50 0.88 0.94\n", - " hourglass 50 0.88 0.96\n", - " iPod 50 0.76 0.94\n", - " clothes iron 50 0.82 0.88\n", - " jack-o'-lantern 50 0.98 0.98\n", - " jeans 50 0.68 0.84\n", - " jeep 50 0.72 0.9\n", - " T-shirt 50 0.72 0.96\n", - " jigsaw puzzle 50 0.84 0.94\n", - " pulled rickshaw 50 0.86 0.94\n", - " joystick 50 0.8 0.9\n", - " kimono 50 0.84 0.96\n", - " knee pad 50 0.62 0.88\n", - " knot 50 0.66 0.8\n", - " lab coat 50 0.8 0.96\n", - " ladle 50 0.36 0.64\n", - " lampshade 50 0.48 0.84\n", - " laptop computer 50 0.26 0.88\n", - " lawn mower 50 0.78 0.96\n", - " lens cap 50 0.46 0.72\n", - " paper knife 50 0.26 0.5\n", - " library 50 0.54 0.9\n", - " lifeboat 50 0.92 0.98\n", - " lighter 50 0.56 0.78\n", - " limousine 50 0.76 0.92\n", - " ocean liner 50 0.88 0.94\n", - " lipstick 50 0.74 0.9\n", - " slip-on shoe 50 0.74 0.92\n", - " lotion 50 0.5 0.86\n", - " speaker 50 0.52 0.68\n", - " loupe 50 0.32 0.52\n", - " sawmill 50 0.72 0.9\n", - " magnetic compass 50 0.52 0.82\n", - " mail bag 50 0.68 0.92\n", - " mailbox 50 0.82 0.92\n", - " tights 50 0.22 0.94\n", - " tank suit 50 0.24 0.9\n", - " manhole cover 50 0.96 0.98\n", - " maraca 50 0.74 0.9\n", - " marimba 50 0.84 0.94\n", - " mask 50 0.44 0.82\n", - " match 50 0.66 0.9\n", - " maypole 50 0.96 1\n", - " maze 50 0.8 0.96\n", - " measuring cup 50 0.54 0.76\n", - " medicine chest 50 0.6 0.84\n", - " megalith 50 0.8 0.92\n", - " microphone 50 0.52 0.7\n", - " microwave oven 50 0.48 0.72\n", - " military uniform 50 0.62 0.84\n", - " milk can 50 0.68 0.82\n", - " minibus 50 0.7 1\n", - " miniskirt 50 0.46 0.76\n", - " minivan 50 0.38 0.8\n", - " missile 50 0.4 0.84\n", - " mitten 50 0.76 0.88\n", - " mixing bowl 50 0.8 0.92\n", - " mobile home 50 0.54 0.78\n", - " Model T 50 0.92 0.96\n", - " modem 50 0.58 0.86\n", - " monastery 50 0.44 0.9\n", - " monitor 50 0.4 0.86\n", - " moped 50 0.56 0.94\n", - " mortar 50 0.68 0.94\n", - " square academic cap 50 0.5 0.84\n", - " mosque 50 0.9 1\n", - " mosquito net 50 0.9 0.98\n", - " scooter 50 0.9 0.98\n", - " mountain bike 50 0.78 0.96\n", - " tent 50 0.88 0.96\n", - " computer mouse 50 0.42 0.82\n", - " mousetrap 50 0.76 0.88\n", - " moving van 50 0.4 0.72\n", - " muzzle 50 0.5 0.72\n", - " nail 50 0.68 0.74\n", - " neck brace 50 0.56 0.68\n", - " necklace 50 0.86 1\n", - " nipple 50 0.7 0.88\n", - " notebook computer 50 0.34 0.84\n", - " obelisk 50 0.8 0.92\n", - " oboe 50 0.6 0.84\n", - " ocarina 50 0.8 0.86\n", - " odometer 50 0.96 1\n", - " oil filter 50 0.58 0.82\n", - " organ 50 0.82 0.9\n", - " oscilloscope 50 0.9 0.96\n", - " overskirt 50 0.2 0.7\n", - " bullock cart 50 0.7 0.94\n", - " oxygen mask 50 0.46 0.84\n", - " packet 50 0.5 0.78\n", - " paddle 50 0.56 0.94\n", - " paddle wheel 50 0.86 0.96\n", - " padlock 50 0.74 0.78\n", - " paintbrush 50 0.62 0.8\n", - " pajamas 50 0.56 0.92\n", - " palace 50 0.64 0.96\n", - " pan flute 50 0.84 0.86\n", - " paper towel 50 0.66 0.84\n", - " parachute 50 0.92 0.94\n", - " parallel bars 50 0.62 0.96\n", - " park bench 50 0.74 0.9\n", - " parking meter 50 0.84 0.92\n", - " passenger car 50 0.5 0.82\n", - " patio 50 0.58 0.84\n", - " payphone 50 0.74 0.92\n", - " pedestal 50 0.52 0.9\n", - " pencil case 50 0.64 0.92\n", - " pencil sharpener 50 0.52 0.78\n", - " perfume 50 0.7 0.9\n", - " Petri dish 50 0.6 0.8\n", - " photocopier 50 0.88 0.98\n", - " plectrum 50 0.7 0.84\n", - " Pickelhaube 50 0.72 0.86\n", - " picket fence 50 0.84 0.94\n", - " pickup truck 50 0.64 0.92\n", - " pier 50 0.52 0.82\n", - " piggy bank 50 0.82 0.94\n", - " pill bottle 50 0.76 0.86\n", - " pillow 50 0.76 0.9\n", - " ping-pong ball 50 0.84 0.88\n", - " pinwheel 50 0.76 0.88\n", - " pirate ship 50 0.76 0.94\n", - " pitcher 50 0.46 0.84\n", - " hand plane 50 0.84 0.94\n", - " planetarium 50 0.88 0.98\n", - " plastic bag 50 0.36 0.62\n", - " plate rack 50 0.52 0.78\n", - " plow 50 0.78 0.88\n", - " plunger 50 0.42 0.7\n", - " Polaroid camera 50 0.84 0.92\n", - " pole 50 0.38 0.74\n", - " police van 50 0.76 0.94\n", - " poncho 50 0.58 0.86\n", - " billiard table 50 0.8 0.88\n", - " soda bottle 50 0.56 0.94\n", - " pot 50 0.78 0.92\n", - " potter's wheel 50 0.9 0.94\n", - " power drill 50 0.42 0.72\n", - " prayer rug 50 0.7 0.86\n", - " printer 50 0.54 0.86\n", - " prison 50 0.7 0.9\n", - " projectile 50 0.28 0.9\n", - " projector 50 0.62 0.84\n", - " hockey puck 50 0.92 0.96\n", - " punching bag 50 0.6 0.68\n", - " purse 50 0.42 0.78\n", - " quill 50 0.68 0.84\n", - " quilt 50 0.64 0.9\n", - " race car 50 0.72 0.92\n", - " racket 50 0.72 0.9\n", - " radiator 50 0.66 0.76\n", - " radio 50 0.64 0.92\n", - " radio telescope 50 0.9 0.96\n", - " rain barrel 50 0.8 0.98\n", - " recreational vehicle 50 0.84 0.94\n", - " reel 50 0.72 0.82\n", - " reflex camera 50 0.72 0.92\n", - " refrigerator 50 0.7 0.9\n", - " remote control 50 0.7 0.88\n", - " restaurant 50 0.5 0.66\n", - " revolver 50 0.82 1\n", - " rifle 50 0.38 0.7\n", - " rocking chair 50 0.62 0.84\n", - " rotisserie 50 0.88 0.92\n", - " eraser 50 0.54 0.76\n", - " rugby ball 50 0.86 0.94\n", - " ruler 50 0.68 0.86\n", - " running shoe 50 0.78 0.94\n", - " safe 50 0.82 0.92\n", - " safety pin 50 0.4 0.62\n", - " salt shaker 50 0.66 0.9\n", - " sandal 50 0.66 0.86\n", - " sarong 50 0.64 0.86\n", - " saxophone 50 0.66 0.88\n", - " scabbard 50 0.76 0.92\n", - " weighing scale 50 0.58 0.78\n", - " school bus 50 0.92 1\n", - " schooner 50 0.84 1\n", - " scoreboard 50 0.9 0.96\n", - " CRT screen 50 0.14 0.7\n", - " screw 50 0.9 0.98\n", - " screwdriver 50 0.3 0.58\n", - " seat belt 50 0.88 0.94\n", - " sewing machine 50 0.76 0.9\n", - " shield 50 0.56 0.82\n", - " shoe store 50 0.78 0.96\n", - " shoji 50 0.8 0.92\n", - " shopping basket 50 0.52 0.88\n", - " shopping cart 50 0.76 0.92\n", - " shovel 50 0.62 0.84\n", - " shower cap 50 0.7 0.84\n", - " shower curtain 50 0.64 0.82\n", - " ski 50 0.74 0.92\n", - " ski mask 50 0.72 0.88\n", - " sleeping bag 50 0.68 0.8\n", - " slide rule 50 0.72 0.88\n", - " sliding door 50 0.44 0.78\n", - " slot machine 50 0.94 0.98\n", - " snorkel 50 0.86 0.98\n", - " snowmobile 50 0.88 1\n", - " snowplow 50 0.84 0.98\n", - " soap dispenser 50 0.56 0.86\n", - " soccer ball 50 0.86 0.96\n", - " sock 50 0.62 0.76\n", - " solar thermal collector 50 0.72 0.96\n", - " sombrero 50 0.6 0.84\n", - " soup bowl 50 0.56 0.94\n", - " space bar 50 0.34 0.88\n", - " space heater 50 0.52 0.74\n", - " space shuttle 50 0.82 0.96\n", - " spatula 50 0.3 0.6\n", - " motorboat 50 0.86 1\n", - " spider web 50 0.7 0.9\n", - " spindle 50 0.86 0.98\n", - " sports car 50 0.6 0.94\n", - " spotlight 50 0.26 0.6\n", - " stage 50 0.68 0.86\n", - " steam locomotive 50 0.94 1\n", - " through arch bridge 50 0.84 0.96\n", - " steel drum 50 0.82 0.9\n", - " stethoscope 50 0.6 0.82\n", - " scarf 50 0.5 0.92\n", - " stone wall 50 0.76 0.9\n", - " stopwatch 50 0.58 0.9\n", - " stove 50 0.46 0.74\n", - " strainer 50 0.64 0.84\n", - " tram 50 0.88 0.96\n", - " stretcher 50 0.6 0.8\n", - " couch 50 0.8 0.96\n", - " stupa 50 0.88 0.88\n", - " submarine 50 0.72 0.92\n", - " suit 50 0.4 0.78\n", - " sundial 50 0.58 0.74\n", - " sunglass 50 0.14 0.58\n", - " sunglasses 50 0.28 0.58\n", - " sunscreen 50 0.32 0.7\n", - " suspension bridge 50 0.6 0.94\n", - " mop 50 0.74 0.92\n", - " sweatshirt 50 0.28 0.66\n", - " swimsuit 50 0.52 0.82\n", - " swing 50 0.76 0.84\n", - " switch 50 0.56 0.76\n", - " syringe 50 0.62 0.82\n", - " table lamp 50 0.6 0.88\n", - " tank 50 0.8 0.96\n", - " tape player 50 0.46 0.76\n", - " teapot 50 0.84 1\n", - " teddy bear 50 0.82 0.94\n", - " television 50 0.6 0.9\n", - " tennis ball 50 0.7 0.94\n", - " thatched roof 50 0.88 0.9\n", - " front curtain 50 0.8 0.92\n", - " thimble 50 0.6 0.8\n", - " threshing machine 50 0.56 0.88\n", - " throne 50 0.72 0.82\n", - " tile roof 50 0.72 0.94\n", - " toaster 50 0.66 0.84\n", - " tobacco shop 50 0.42 0.7\n", - " toilet seat 50 0.62 0.88\n", - " torch 50 0.64 0.84\n", - " totem pole 50 0.92 0.98\n", - " tow truck 50 0.62 0.88\n", - " toy store 50 0.6 0.94\n", - " tractor 50 0.76 0.98\n", - " semi-trailer truck 50 0.78 0.92\n", - " tray 50 0.46 0.64\n", - " trench coat 50 0.54 0.72\n", - " tricycle 50 0.72 0.94\n", - " trimaran 50 0.7 0.98\n", - " tripod 50 0.58 0.86\n", - " triumphal arch 50 0.92 0.98\n", - " trolleybus 50 0.9 1\n", - " trombone 50 0.54 0.88\n", - " tub 50 0.24 0.82\n", - " turnstile 50 0.84 0.94\n", - " typewriter keyboard 50 0.68 0.98\n", - " umbrella 50 0.52 0.7\n", - " unicycle 50 0.74 0.96\n", - " upright piano 50 0.76 0.9\n", - " vacuum cleaner 50 0.62 0.9\n", - " vase 50 0.5 0.78\n", - " vault 50 0.76 0.92\n", - " velvet 50 0.2 0.42\n", - " vending machine 50 0.9 1\n", - " vestment 50 0.54 0.82\n", - " viaduct 50 0.78 0.86\n", - " violin 50 0.68 0.78\n", - " volleyball 50 0.86 1\n", - " waffle iron 50 0.72 0.88\n", - " wall clock 50 0.54 0.88\n", - " wallet 50 0.52 0.9\n", - " wardrobe 50 0.68 0.88\n", - " military aircraft 50 0.9 0.98\n", - " sink 50 0.72 0.96\n", - " washing machine 50 0.78 0.94\n", - " water bottle 50 0.54 0.74\n", - " water jug 50 0.22 0.74\n", - " water tower 50 0.9 0.96\n", - " whiskey jug 50 0.64 0.74\n", - " whistle 50 0.72 0.84\n", - " wig 50 0.84 0.9\n", - " window screen 50 0.68 0.8\n", - " window shade 50 0.52 0.76\n", - " Windsor tie 50 0.22 0.66\n", - " wine bottle 50 0.42 0.82\n", - " wing 50 0.54 0.96\n", - " wok 50 0.46 0.82\n", - " wooden spoon 50 0.58 0.8\n", - " wool 50 0.32 0.82\n", - " split-rail fence 50 0.74 0.9\n", - " shipwreck 50 0.84 0.96\n", - " yawl 50 0.78 0.96\n", - " yurt 50 0.84 1\n", - " website 50 0.98 1\n", - " comic book 50 0.62 0.9\n", - " crossword 50 0.84 0.88\n", - " traffic sign 50 0.78 0.9\n", - " traffic light 50 0.8 0.94\n", - " dust jacket 50 0.72 0.94\n", - " menu 50 0.82 0.96\n", - " plate 50 0.44 0.88\n", - " guacamole 50 0.8 0.92\n", - " consomme 50 0.54 0.88\n", - " hot pot 50 0.86 0.98\n", - " trifle 50 0.92 0.98\n", - " ice cream 50 0.68 0.94\n", - " ice pop 50 0.62 0.84\n", - " baguette 50 0.62 0.88\n", - " bagel 50 0.64 0.92\n", - " pretzel 50 0.72 0.88\n", - " cheeseburger 50 0.9 1\n", - " hot dog 50 0.74 0.94\n", - " mashed potato 50 0.74 0.9\n", - " cabbage 50 0.84 0.96\n", - " broccoli 50 0.9 0.96\n", - " cauliflower 50 0.82 1\n", - " zucchini 50 0.74 0.9\n", - " spaghetti squash 50 0.8 0.96\n", - " acorn squash 50 0.82 0.96\n", - " butternut squash 50 0.7 0.94\n", - " cucumber 50 0.6 0.96\n", - " artichoke 50 0.84 0.94\n", - " bell pepper 50 0.84 0.98\n", - " cardoon 50 0.88 0.94\n", - " mushroom 50 0.38 0.92\n", - " Granny Smith 50 0.9 0.96\n", - " strawberry 50 0.6 0.88\n", - " orange 50 0.7 0.92\n", - " lemon 50 0.78 0.98\n", - " fig 50 0.82 0.96\n", - " pineapple 50 0.86 0.96\n", - " banana 50 0.84 0.96\n", - " jackfruit 50 0.9 0.98\n", - " custard apple 50 0.86 0.96\n", - " pomegranate 50 0.82 0.98\n", - " hay 50 0.8 0.92\n", - " carbonara 50 0.88 0.94\n", - " chocolate syrup 50 0.46 0.84\n", - " dough 50 0.4 0.6\n", - " meatloaf 50 0.58 0.84\n", - " pizza 50 0.84 0.96\n", - " pot pie 50 0.68 0.9\n", - " burrito 50 0.8 0.98\n", - " red wine 50 0.54 0.82\n", - " espresso 50 0.64 0.88\n", - " cup 50 0.38 0.7\n", - " eggnog 50 0.38 0.7\n", - " alp 50 0.54 0.88\n", - " bubble 50 0.8 0.96\n", - " cliff 50 0.64 1\n", - " coral reef 50 0.72 0.96\n", - " geyser 50 0.94 1\n", - " lakeshore 50 0.54 0.88\n", - " promontory 50 0.58 0.94\n", - " shoal 50 0.6 0.96\n", - " seashore 50 0.44 0.78\n", - " valley 50 0.72 0.94\n", - " volcano 50 0.78 0.96\n", - " baseball player 50 0.72 0.94\n", - " bridegroom 50 0.72 0.88\n", - " scuba diver 50 0.8 1\n", - " rapeseed 50 0.94 0.98\n", - " daisy 50 0.96 0.98\n", - " yellow lady's slipper 50 1 1\n", - " corn 50 0.4 0.88\n", - " acorn 50 0.92 0.98\n", - " rose hip 50 0.92 0.98\n", - " horse chestnut seed 50 0.94 0.98\n", - " coral fungus 50 0.96 0.96\n", - " agaric 50 0.82 0.94\n", - " gyromitra 50 0.98 1\n", - " stinkhorn mushroom 50 0.8 0.94\n", - " earth star 50 0.98 1\n", - " hen-of-the-woods 50 0.8 0.96\n", - " bolete 50 0.74 0.94\n", - " ear 50 0.48 0.94\n", - " toilet paper 50 0.36 0.68\n", - "Speed: 0.1ms pre-process, 0.3ms inference, 0.0ms post-process per image at shape (1, 3, 224, 224)\n", - "Results saved to \u001b[1mruns/val-cls/exp\u001b[0m\n" - ] - } - ], - "source": [ - "# Validate YOLOv5s on Imagenet val\n", - "!python classify/val.py --weights yolov5s-cls.pt --data ../datasets/imagenet --img 224 --half" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "ZY2VXXXu74w5" - }, - "source": [ - "# 3. Train\n", - "\n", - "

\n", - "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", - "

\n", - "\n", - "Train a YOLOv5s Classification model on the [Imagenette](https://image-net.org/) dataset with `--data imagenet`, starting from pretrained `--pretrained yolov5s-cls.pt`.\n", - "\n", - "- **Pretrained [Models](https://github.com/ultralytics/yolov5/tree/master/models)** are downloaded\n", - "automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases)\n", - "- **Training Results** are saved to `runs/train-cls/` with incrementing run directories, i.e. `runs/train-cls/exp2`, `runs/train-cls/exp3` etc.\n", - "

\n", - "\n", - "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic.\n", - "\n", - "## Train on Custom Data with Roboflow 🌟 NEW\n", - "\n", - "[Roboflow](https://roboflow.com/?ref=ultralytics) enables you to easily **organize, label, and prepare** a high quality dataset with your own custom data. Roboflow also makes it easy to establish an active learning pipeline, collaborate with your team on dataset improvement, and integrate directly into your model building workflow with the `roboflow` pip package.\n", - "\n", - "- Custom Training Example: [https://blog.roboflow.com/train-yolov5-classification-custom-data/](https://blog.roboflow.com/train-yolov5-classification-custom-data/?ref=ultralytics)\n", - "- Custom Training Notebook: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1KZiKUAjtARHAfZCXbJRv14-pOnIsBLPV?usp=sharing)\n", - "
\n", - "\n", - "

Label images lightning fast (including with model-assisted labeling)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "i3oKtE4g-aNn" - }, - "outputs": [], - "source": [ - "#@title Select YOLOv5 🚀 logger {run: 'auto'}\n", - "logger = 'Comet' #@param ['Comet', 'ClearML', 'TensorBoard']\n", - "\n", - "if logger == 'Comet':\n", - " %pip install -q comet_ml\n", - " import comet_ml; comet_ml.init()\n", - "elif logger == 'ClearML':\n", - " %pip install -q clearml\n", - " import clearml; clearml.browser_login()\n", - "elif logger == 'TensorBoard':\n", - " %load_ext tensorboard\n", - " %tensorboard --logdir runs/train" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "1NcFxRcFdJ_O", - "outputId": "77c8d487-16db-4073-b3ea-06cabf2e7766" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "\u001b[34m\u001b[1mclassify/train: \u001b[0mmodel=yolov5s-cls.pt, data=imagenette160, epochs=5, batch_size=64, imgsz=224, nosave=False, cache=ram, device=, workers=8, project=runs/train-cls, name=exp, exist_ok=False, pretrained=True, optimizer=Adam, lr0=0.001, decay=5e-05, label_smoothing=0.1, cutoff=None, dropout=None, verbose=False, seed=0, local_rank=-1\n", - "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", - "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", - "\n", - "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train-cls', view at http://localhost:6006/\n", - "\n", - "Dataset not found ⚠️, missing path /content/datasets/imagenette160, attempting download...\n", - "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/imagenette160.zip to /content/datasets/imagenette160.zip...\n", - "100% 103M/103M [00:00<00:00, 347MB/s] \n", - "Unzipping /content/datasets/imagenette160.zip...\n", - "Dataset download success ✅ (3.3s), saved to \u001b[1m/content/datasets/imagenette160\u001b[0m\n", - "\n", - "\u001b[34m\u001b[1malbumentations: \u001b[0mRandomResizedCrop(p=1.0, height=224, width=224, scale=(0.08, 1.0), ratio=(0.75, 1.3333333333333333), interpolation=1), HorizontalFlip(p=0.5), ColorJitter(p=0.5, brightness=[0.6, 1.4], contrast=[0.6, 1.4], saturation=[0.6, 1.4], hue=[0, 0]), Normalize(p=1.0, mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), max_pixel_value=255.0), ToTensorV2(always_apply=True, p=1.0, transpose_mask=False)\n", - "Model summary: 149 layers, 4185290 parameters, 4185290 gradients, 10.5 GFLOPs\n", - "\u001b[34m\u001b[1moptimizer:\u001b[0m Adam(lr=0.001) with parameter groups 32 weight(decay=0.0), 33 weight(decay=5e-05), 33 bias\n", - "Image sizes 224 train, 224 test\n", - "Using 1 dataloader workers\n", - "Logging results to \u001b[1mruns/train-cls/exp\u001b[0m\n", - "Starting yolov5s-cls.pt training on imagenette160 dataset with 10 classes for 5 epochs...\n", - "\n", - " Epoch GPU_mem train_loss val_loss top1_acc top5_acc\n", - " 1/5 1.47G 1.05 0.974 0.828 0.975: 100% 148/148 [00:38<00:00, 3.82it/s]\n", - " 2/5 1.73G 0.895 0.766 0.911 0.994: 100% 148/148 [00:36<00:00, 4.03it/s]\n", - " 3/5 1.73G 0.82 0.704 0.934 0.996: 100% 148/148 [00:35<00:00, 4.20it/s]\n", - " 4/5 1.73G 0.766 0.664 0.951 0.998: 100% 148/148 [00:36<00:00, 4.05it/s]\n", - " 5/5 1.73G 0.724 0.634 0.959 0.997: 100% 148/148 [00:37<00:00, 3.94it/s]\n", - "\n", - "Training complete (0.052 hours)\n", - "Results saved to \u001b[1mruns/train-cls/exp\u001b[0m\n", - "Predict: python classify/predict.py --weights runs/train-cls/exp/weights/best.pt --source im.jpg\n", - "Validate: python classify/val.py --weights runs/train-cls/exp/weights/best.pt --data /content/datasets/imagenette160\n", - "Export: python export.py --weights runs/train-cls/exp/weights/best.pt --include onnx\n", - "PyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', 'runs/train-cls/exp/weights/best.pt')\n", - "Visualize: https://netron.app\n", - "\n" - ] - } - ], - "source": [ - "# Train YOLOv5s Classification on Imagenette160 for 3 epochs\n", - "!python classify/train.py --model yolov5s-cls.pt --data imagenette160 --epochs 5 --img 224 --cache" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "15glLzbQx5u0" - }, - "source": [ - "# 4. Visualize" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "nWOsI5wJR1o3" - }, - "source": [ - "## Comet Logging and Visualization 🌟 NEW\n", - "\n", - "[Comet](https://www.comet.com/site/lp/yolov5-with-comet/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab) is now fully integrated with YOLOv5. Track and visualize model metrics in real time, save your hyperparameters, datasets, and model checkpoints, and visualize your model predictions with [Comet Custom Panels](https://www.comet.com/docs/v2/guides/comet-dashboard/code-panels/about-panels/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab)! Comet makes sure you never lose track of your work and makes it easy to share results and collaborate across teams of all sizes!\n", - "\n", - "Getting started is easy:\n", - "```shell\n", - "pip install comet_ml # 1. install\n", - "export COMET_API_KEY= # 2. paste API key\n", - "python train.py --img 640 --epochs 3 --data coco128.yaml --weights yolov5s.pt # 3. train\n", - "```\n", - "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", - "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing)\n", - "\n", - "\n", - "\"Comet" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Lay2WsTjNJzP" - }, - "source": [ - "## ClearML Logging and Automation 🌟 NEW\n", - "\n", - "[ClearML](https://cutt.ly/yolov5-notebook-clearml) is completely integrated into YOLOv5 to track your experimentation, manage dataset versions and even remotely execute training runs. To enable ClearML (check cells above):\n", - "\n", - "- `pip install clearml`\n", - "- run `clearml-init` to connect to a ClearML server (**deploy your own [open-source server](https://github.com/allegroai/clearml-server)**, or use our [free hosted server](https://cutt.ly/yolov5-notebook-clearml))\n", - "\n", - "You'll get all the great expected features from an experiment manager: live updates, model upload, experiment comparison etc. but ClearML also tracks uncommitted changes and installed packages for example. Thanks to that ClearML Tasks (which is what we call experiments) are also reproducible on different machines! With only 1 extra line, we can schedule a YOLOv5 training task on a queue to be executed by any number of ClearML Agents (workers).\n", - "\n", - "You can use ClearML Data to version your dataset and then pass it to YOLOv5 simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration) for details!\n", - "\n", - "\n", - "\"ClearML" - ] + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "t6MPjfT5NrKQ" + }, + "source": [ + "
\n", + "\n", + " \n", + " \n", + "\n", + "\n", + "
\n", + " \"Run\n", + " \"Open\n", + " \"Open\n", + "
\n", + "\n", + "This YOLOv5 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7mGmQbAO5pQb" + }, + "source": [ + "# Setup\n", + "\n", + "Clone GitHub [repository](https://github.com/ultralytics/yolov5), install [dependencies](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) and check PyTorch and GPU." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "wbvMlHd_QwMG", + "outputId": "0806e375-610d-4ec0-c867-763dbb518279" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "-WPvRbS5Swl6" - }, - "source": [ - "## Local Logging\n", - "\n", - "Training results are automatically logged with [Tensorboard](https://www.tensorflow.org/tensorboard) and [CSV](https://github.com/ultralytics/yolov5/pull/4148) loggers to `runs/train`, with a new experiment directory created for each new training as `runs/train/exp2`, `runs/train/exp3`, etc.\n", - "\n", - "This directory contains train and val statistics, mosaics, labels, predictions and augmentated mosaics, as well as metrics and charts including precision-recall (PR) curves and confusion matrices. \n", - "\n", - "\"Local\n" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n" + ] }, { - "cell_type": "markdown", - "metadata": { - "id": "Zelyeqbyt3GD" - }, - "source": [ - "# Environments\n", - "\n", - "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):\n", - "\n", - "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", - "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)\n", - "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)\n", - "- **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) \"Docker\n" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Setup complete ✅ (2 CPUs, 12.7 GB RAM, 22.6/78.2 GB disk)\n" + ] + } + ], + "source": [ + "!git clone https://github.com/ultralytics/yolov5 # clone\n", + "%cd yolov5\n", + "%pip install -qr requirements.txt # install\n", + "\n", + "import torch\n", + "\n", + "import utils\n", + "\n", + "display = utils.notebook_init() # checks" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4JnkELT0cIJg" + }, + "source": [ + "# 1. Predict\n", + "\n", + "`classify/predict.py` runs YOLOv5 Classification inference on a variety of sources, downloading models automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases), and saving results to `runs/predict-cls`. Example inference sources are:\n", + "\n", + "```shell\n", + "python classify/predict.py --source 0 # webcam\n", + " img.jpg # image \n", + " vid.mp4 # video\n", + " screen # screenshot\n", + " path/ # directory\n", + " 'path/*.jpg' # glob\n", + " 'https://youtu.be/LNwODJXcvt4' # YouTube\n", + " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "zR9ZbuQCH7FX", + "outputId": "50504ef7-aa3e-4281-a4e3-d0c7df3c0ffe" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "6Qu7Iesl0p54" - }, - "source": [ - "# Status\n", - "\n", - "![YOLOv5 CI](https://github.com/ultralytics/yolov3/actions/workflows/ci-testing.yml/badge.svg)\n", - "\n", - "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/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)), testing ([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.\n" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[34m\u001b[1mclassify/predict: \u001b[0mweights=['yolov5s-cls.pt'], source=data/images, data=data/coco128.yaml, imgsz=[224, 224], device=, view_img=False, save_txt=False, nosave=False, augment=False, visualize=False, update=False, project=runs/predict-cls, name=exp, exist_ok=False, half=False, dnn=False, vid_stride=1\n", + "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "\n", + "Downloading https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt to yolov5s-cls.pt...\n", + "100% 10.5M/10.5M [00:00<00:00, 12.3MB/s]\n", + "\n", + "Fusing layers... \n", + "Model summary: 117 layers, 5447688 parameters, 0 gradients, 11.4 GFLOPs\n", + "image 1/2 /content/yolov5/data/images/bus.jpg: 224x224 minibus 0.39, police van 0.24, amphibious vehicle 0.05, recreational vehicle 0.04, trolleybus 0.03, 3.9ms\n", + "image 2/2 /content/yolov5/data/images/zidane.jpg: 224x224 suit 0.38, bow tie 0.19, bridegroom 0.18, rugby ball 0.04, stage 0.02, 4.6ms\n", + "Speed: 0.3ms pre-process, 4.3ms inference, 1.5ms NMS per image at shape (1, 3, 224, 224)\n", + "Results saved to \u001b[1mruns/predict-cls/exp\u001b[0m\n" + ] + } + ], + "source": [ + "!python classify/predict.py --weights yolov5s-cls.pt --img 224 --source data/images\n", + "# display.Image(filename='runs/predict-cls/exp/zidane.jpg', width=600)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hkAzDWJ7cWTr" + }, + "source": [ + "        \n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0eq1SMWl6Sfn" + }, + "source": [ + "# 2. Validate\n", + "Validate a model's accuracy on the [Imagenet](https://image-net.org/) dataset's `val` or `test` splits. Models are downloaded automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases). To show results by class use the `--verbose` flag." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "WQPtK1QYVaD_", + "outputId": "20fc0630-141e-4a90-ea06-342cbd7ce496" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "IEijrePND_2I" - }, - "source": [ - "# Appendix\n", - "\n", - "Additional content below." - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "--2022-11-22 19:53:40-- https://image-net.org/data/ILSVRC/2012/ILSVRC2012_img_val.tar\n", + "Resolving image-net.org (image-net.org)... 171.64.68.16\n", + "Connecting to image-net.org (image-net.org)|171.64.68.16|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 6744924160 (6.3G) [application/x-tar]\n", + "Saving to: ‘ILSVRC2012_img_val.tar’\n", + "\n", + "ILSVRC2012_img_val. 100%[===================>] 6.28G 16.1MB/s in 10m 52s \n", + "\n", + "2022-11-22 20:04:32 (9.87 MB/s) - ‘ILSVRC2012_img_val.tar’ saved [6744924160/6744924160]\n", + "\n" + ] + } + ], + "source": [ + "# Download Imagenet val (6.3G, 50000 images)\n", + "!bash data/scripts/get_imagenet.sh --val" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "X58w8JLpMnjH", + "outputId": "41843132-98e2-4c25-d474-4cd7b246fb8e" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "GMusP4OAxFu6" - }, - "outputs": [], - "source": [ - "# YOLOv5 PyTorch HUB Inference (DetectionModels only)\n", - "import torch\n", - "\n", - "model = torch.hub.load('ultralytics/yolov5', 'yolov5s') # yolov5n - yolov5x6 or custom\n", - "im = 'https://ultralytics.com/images/zidane.jpg' # file, Path, PIL.Image, OpenCV, nparray, list\n", - "results = model(im) # inference\n", - "results.print() # or .show(), .save(), .crop(), .pandas(), etc." - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[34m\u001b[1mclassify/val: \u001b[0mdata=../datasets/imagenet, weights=['yolov5s-cls.pt'], batch_size=128, imgsz=224, device=, workers=8, verbose=True, project=runs/val-cls, name=exp, exist_ok=False, half=True, dnn=False\n", + "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "\n", + "Fusing layers... \n", + "Model summary: 117 layers, 5447688 parameters, 0 gradients, 11.4 GFLOPs\n", + "validating: 100% 391/391 [04:57<00:00, 1.31it/s]\n", + " Class Images top1_acc top5_acc\n", + " all 50000 0.715 0.902\n", + " tench 50 0.94 0.98\n", + " goldfish 50 0.88 0.92\n", + " great white shark 50 0.78 0.96\n", + " tiger shark 50 0.68 0.96\n", + " hammerhead shark 50 0.82 0.92\n", + " electric ray 50 0.76 0.9\n", + " stingray 50 0.7 0.9\n", + " cock 50 0.78 0.92\n", + " hen 50 0.84 0.96\n", + " ostrich 50 0.98 1\n", + " brambling 50 0.9 0.96\n", + " goldfinch 50 0.92 0.98\n", + " house finch 50 0.88 0.96\n", + " junco 50 0.94 0.98\n", + " indigo bunting 50 0.86 0.88\n", + " American robin 50 0.9 0.96\n", + " bulbul 50 0.84 0.96\n", + " jay 50 0.9 0.96\n", + " magpie 50 0.84 0.96\n", + " chickadee 50 0.9 1\n", + " American dipper 50 0.82 0.92\n", + " kite 50 0.76 0.94\n", + " bald eagle 50 0.92 1\n", + " vulture 50 0.96 1\n", + " great grey owl 50 0.94 0.98\n", + " fire salamander 50 0.96 0.98\n", + " smooth newt 50 0.58 0.94\n", + " newt 50 0.74 0.9\n", + " spotted salamander 50 0.86 0.94\n", + " axolotl 50 0.86 0.96\n", + " American bullfrog 50 0.78 0.92\n", + " tree frog 50 0.84 0.96\n", + " tailed frog 50 0.48 0.8\n", + " loggerhead sea turtle 50 0.68 0.94\n", + " leatherback sea turtle 50 0.5 0.8\n", + " mud turtle 50 0.64 0.84\n", + " terrapin 50 0.52 0.98\n", + " box turtle 50 0.84 0.98\n", + " banded gecko 50 0.7 0.88\n", + " green iguana 50 0.76 0.94\n", + " Carolina anole 50 0.58 0.96\n", + "desert grassland whiptail lizard 50 0.82 0.94\n", + " agama 50 0.74 0.92\n", + " frilled-necked lizard 50 0.84 0.86\n", + " alligator lizard 50 0.58 0.78\n", + " Gila monster 50 0.72 0.8\n", + " European green lizard 50 0.42 0.9\n", + " chameleon 50 0.76 0.84\n", + " Komodo dragon 50 0.86 0.96\n", + " Nile crocodile 50 0.7 0.84\n", + " American alligator 50 0.76 0.96\n", + " triceratops 50 0.9 0.94\n", + " worm snake 50 0.76 0.88\n", + " ring-necked snake 50 0.8 0.92\n", + " eastern hog-nosed snake 50 0.58 0.88\n", + " smooth green snake 50 0.6 0.94\n", + " kingsnake 50 0.82 0.9\n", + " garter snake 50 0.88 0.94\n", + " water snake 50 0.7 0.94\n", + " vine snake 50 0.66 0.76\n", + " night snake 50 0.34 0.82\n", + " boa constrictor 50 0.8 0.96\n", + " African rock python 50 0.48 0.76\n", + " Indian cobra 50 0.82 0.94\n", + " green mamba 50 0.54 0.86\n", + " sea snake 50 0.62 0.9\n", + " Saharan horned viper 50 0.56 0.86\n", + "eastern diamondback rattlesnake 50 0.6 0.86\n", + " sidewinder 50 0.28 0.86\n", + " trilobite 50 0.98 0.98\n", + " harvestman 50 0.86 0.94\n", + " scorpion 50 0.86 0.94\n", + " yellow garden spider 50 0.92 0.96\n", + " barn spider 50 0.38 0.98\n", + " European garden spider 50 0.62 0.98\n", + " southern black widow 50 0.88 0.94\n", + " tarantula 50 0.94 1\n", + " wolf spider 50 0.82 0.92\n", + " tick 50 0.74 0.84\n", + " centipede 50 0.68 0.82\n", + " black grouse 50 0.88 0.98\n", + " ptarmigan 50 0.78 0.94\n", + " ruffed grouse 50 0.88 1\n", + " prairie grouse 50 0.92 1\n", + " peacock 50 0.88 0.9\n", + " quail 50 0.9 0.94\n", + " partridge 50 0.74 0.96\n", + " grey parrot 50 0.9 0.96\n", + " macaw 50 0.88 0.98\n", + "sulphur-crested cockatoo 50 0.86 0.92\n", + " lorikeet 50 0.96 1\n", + " coucal 50 0.82 0.88\n", + " bee eater 50 0.96 0.98\n", + " hornbill 50 0.9 0.96\n", + " hummingbird 50 0.88 0.96\n", + " jacamar 50 0.92 0.94\n", + " toucan 50 0.84 0.94\n", + " duck 50 0.76 0.94\n", + " red-breasted merganser 50 0.86 0.96\n", + " goose 50 0.74 0.96\n", + " black swan 50 0.94 0.98\n", + " tusker 50 0.54 0.92\n", + " echidna 50 0.98 1\n", + " platypus 50 0.72 0.84\n", + " wallaby 50 0.78 0.88\n", + " koala 50 0.84 0.92\n", + " wombat 50 0.78 0.84\n", + " jellyfish 50 0.88 0.96\n", + " sea anemone 50 0.72 0.9\n", + " brain coral 50 0.88 0.96\n", + " flatworm 50 0.8 0.98\n", + " nematode 50 0.86 0.9\n", + " conch 50 0.74 0.88\n", + " snail 50 0.78 0.88\n", + " slug 50 0.74 0.82\n", + " sea slug 50 0.88 0.98\n", + " chiton 50 0.88 0.98\n", + " chambered nautilus 50 0.88 0.92\n", + " Dungeness crab 50 0.78 0.94\n", + " rock crab 50 0.68 0.86\n", + " fiddler crab 50 0.64 0.86\n", + " red king crab 50 0.76 0.96\n", + " American lobster 50 0.78 0.96\n", + " spiny lobster 50 0.74 0.88\n", + " crayfish 50 0.56 0.86\n", + " hermit crab 50 0.78 0.96\n", + " isopod 50 0.66 0.78\n", + " white stork 50 0.88 0.96\n", + " black stork 50 0.84 0.98\n", + " spoonbill 50 0.96 1\n", + " flamingo 50 0.94 1\n", + " little blue heron 50 0.92 0.98\n", + " great egret 50 0.9 0.96\n", + " bittern 50 0.86 0.94\n", + " crane (bird) 50 0.62 0.9\n", + " limpkin 50 0.98 1\n", + " common gallinule 50 0.92 0.96\n", + " American coot 50 0.9 0.98\n", + " bustard 50 0.92 0.96\n", + " ruddy turnstone 50 0.94 1\n", + " dunlin 50 0.86 0.94\n", + " common redshank 50 0.9 0.96\n", + " dowitcher 50 0.84 0.96\n", + " oystercatcher 50 0.86 0.94\n", + " pelican 50 0.92 0.96\n", + " king penguin 50 0.88 0.96\n", + " albatross 50 0.9 1\n", + " grey whale 50 0.84 0.92\n", + " killer whale 50 0.92 1\n", + " dugong 50 0.84 0.96\n", + " sea lion 50 0.82 0.92\n", + " Chihuahua 50 0.66 0.84\n", + " Japanese Chin 50 0.72 0.98\n", + " Maltese 50 0.76 0.94\n", + " Pekingese 50 0.84 0.94\n", + " Shih Tzu 50 0.74 0.96\n", + " King Charles Spaniel 50 0.88 0.98\n", + " Papillon 50 0.86 0.94\n", + " toy terrier 50 0.48 0.94\n", + " Rhodesian Ridgeback 50 0.76 0.98\n", + " Afghan Hound 50 0.84 1\n", + " Basset Hound 50 0.8 0.92\n", + " Beagle 50 0.82 0.96\n", + " Bloodhound 50 0.48 0.72\n", + " Bluetick Coonhound 50 0.86 0.94\n", + " Black and Tan Coonhound 50 0.54 0.8\n", + "Treeing Walker Coonhound 50 0.66 0.98\n", + " English foxhound 50 0.32 0.84\n", + " Redbone Coonhound 50 0.62 0.94\n", + " borzoi 50 0.92 1\n", + " Irish Wolfhound 50 0.48 0.88\n", + " Italian Greyhound 50 0.76 0.98\n", + " Whippet 50 0.74 0.92\n", + " Ibizan Hound 50 0.6 0.86\n", + " Norwegian Elkhound 50 0.88 0.98\n", + " Otterhound 50 0.62 0.9\n", + " Saluki 50 0.72 0.92\n", + " Scottish Deerhound 50 0.86 0.98\n", + " Weimaraner 50 0.88 0.94\n", + "Staffordshire Bull Terrier 50 0.66 0.98\n", + "American Staffordshire Terrier 50 0.64 0.92\n", + " Bedlington Terrier 50 0.9 0.92\n", + " Border Terrier 50 0.86 0.92\n", + " Kerry Blue Terrier 50 0.78 0.98\n", + " Irish Terrier 50 0.7 0.96\n", + " Norfolk Terrier 50 0.68 0.9\n", + " Norwich Terrier 50 0.72 1\n", + " Yorkshire Terrier 50 0.66 0.9\n", + " Wire Fox Terrier 50 0.64 0.98\n", + " Lakeland Terrier 50 0.74 0.92\n", + " Sealyham Terrier 50 0.76 0.9\n", + " Airedale Terrier 50 0.82 0.92\n", + " Cairn Terrier 50 0.76 0.9\n", + " Australian Terrier 50 0.48 0.84\n", + " Dandie Dinmont Terrier 50 0.82 0.92\n", + " Boston Terrier 50 0.92 1\n", + " Miniature Schnauzer 50 0.68 0.9\n", + " Giant Schnauzer 50 0.72 0.98\n", + " Standard Schnauzer 50 0.74 1\n", + " Scottish Terrier 50 0.76 0.96\n", + " Tibetan Terrier 50 0.48 1\n", + "Australian Silky Terrier 50 0.66 0.96\n", + "Soft-coated Wheaten Terrier 50 0.74 0.96\n", + "West Highland White Terrier 50 0.88 0.96\n", + " Lhasa Apso 50 0.68 0.96\n", + " Flat-Coated Retriever 50 0.72 0.94\n", + " Curly-coated Retriever 50 0.82 0.94\n", + " Golden Retriever 50 0.86 0.94\n", + " Labrador Retriever 50 0.82 0.94\n", + "Chesapeake Bay Retriever 50 0.76 0.96\n", + "German Shorthaired Pointer 50 0.8 0.96\n", + " Vizsla 50 0.68 0.96\n", + " English Setter 50 0.7 1\n", + " Irish Setter 50 0.8 0.9\n", + " Gordon Setter 50 0.84 0.92\n", + " Brittany 50 0.84 0.96\n", + " Clumber Spaniel 50 0.92 0.96\n", + "English Springer Spaniel 50 0.88 1\n", + " Welsh Springer Spaniel 50 0.92 1\n", + " Cocker Spaniels 50 0.7 0.94\n", + " Sussex Spaniel 50 0.72 0.92\n", + " Irish Water Spaniel 50 0.88 0.98\n", + " Kuvasz 50 0.66 0.9\n", + " Schipperke 50 0.9 0.98\n", + " Groenendael 50 0.8 0.94\n", + " Malinois 50 0.86 0.98\n", + " Briard 50 0.52 0.8\n", + " Australian Kelpie 50 0.6 0.88\n", + " Komondor 50 0.88 0.94\n", + " Old English Sheepdog 50 0.94 0.98\n", + " Shetland Sheepdog 50 0.74 0.9\n", + " collie 50 0.6 0.96\n", + " Border Collie 50 0.74 0.96\n", + " Bouvier des Flandres 50 0.78 0.94\n", + " Rottweiler 50 0.88 0.96\n", + " German Shepherd Dog 50 0.8 0.98\n", + " Dobermann 50 0.68 0.96\n", + " Miniature Pinscher 50 0.76 0.88\n", + "Greater Swiss Mountain Dog 50 0.68 0.94\n", + " Bernese Mountain Dog 50 0.96 1\n", + " Appenzeller Sennenhund 50 0.22 1\n", + " Entlebucher Sennenhund 50 0.64 0.98\n", + " Boxer 50 0.7 0.92\n", + " Bullmastiff 50 0.78 0.98\n", + " Tibetan Mastiff 50 0.88 0.96\n", + " French Bulldog 50 0.84 0.94\n", + " Great Dane 50 0.54 0.9\n", + " St. Bernard 50 0.92 1\n", + " husky 50 0.46 0.98\n", + " Alaskan Malamute 50 0.76 0.96\n", + " Siberian Husky 50 0.46 0.98\n", + " Dalmatian 50 0.94 0.98\n", + " Affenpinscher 50 0.78 0.9\n", + " Basenji 50 0.92 0.94\n", + " pug 50 0.94 0.98\n", + " Leonberger 50 1 1\n", + " Newfoundland 50 0.78 0.96\n", + " Pyrenean Mountain Dog 50 0.78 0.96\n", + " Samoyed 50 0.96 1\n", + " Pomeranian 50 0.98 1\n", + " Chow Chow 50 0.9 0.96\n", + " Keeshond 50 0.88 0.94\n", + " Griffon Bruxellois 50 0.84 0.98\n", + " Pembroke Welsh Corgi 50 0.82 0.94\n", + " Cardigan Welsh Corgi 50 0.66 0.98\n", + " Toy Poodle 50 0.52 0.88\n", + " Miniature Poodle 50 0.52 0.92\n", + " Standard Poodle 50 0.8 1\n", + " Mexican hairless dog 50 0.88 0.98\n", + " grey wolf 50 0.82 0.92\n", + " Alaskan tundra wolf 50 0.78 0.98\n", + " red wolf 50 0.48 0.9\n", + " coyote 50 0.64 0.86\n", + " dingo 50 0.76 0.88\n", + " dhole 50 0.9 0.98\n", + " African wild dog 50 0.98 1\n", + " hyena 50 0.88 0.96\n", + " red fox 50 0.54 0.92\n", + " kit fox 50 0.72 0.98\n", + " Arctic fox 50 0.94 1\n", + " grey fox 50 0.7 0.94\n", + " tabby cat 50 0.54 0.92\n", + " tiger cat 50 0.22 0.94\n", + " Persian cat 50 0.9 0.98\n", + " Siamese cat 50 0.96 1\n", + " Egyptian Mau 50 0.54 0.8\n", + " cougar 50 0.9 1\n", + " lynx 50 0.72 0.88\n", + " leopard 50 0.78 0.98\n", + " snow leopard 50 0.9 0.98\n", + " jaguar 50 0.7 0.94\n", + " lion 50 0.9 0.98\n", + " tiger 50 0.92 0.98\n", + " cheetah 50 0.94 0.98\n", + " brown bear 50 0.94 0.98\n", + " American black bear 50 0.8 1\n", + " polar bear 50 0.84 0.96\n", + " sloth bear 50 0.72 0.92\n", + " mongoose 50 0.7 0.92\n", + " meerkat 50 0.82 0.92\n", + " tiger beetle 50 0.92 0.94\n", + " ladybug 50 0.86 0.94\n", + " ground beetle 50 0.64 0.94\n", + " longhorn beetle 50 0.62 0.88\n", + " leaf beetle 50 0.64 0.98\n", + " dung beetle 50 0.86 0.98\n", + " rhinoceros beetle 50 0.86 0.94\n", + " weevil 50 0.9 1\n", + " fly 50 0.78 0.94\n", + " bee 50 0.68 0.94\n", + " ant 50 0.68 0.78\n", + " grasshopper 50 0.5 0.92\n", + " cricket 50 0.64 0.92\n", + " stick insect 50 0.64 0.92\n", + " cockroach 50 0.72 0.8\n", + " mantis 50 0.64 0.86\n", + " cicada 50 0.9 0.96\n", + " leafhopper 50 0.88 0.94\n", + " lacewing 50 0.78 0.92\n", + " dragonfly 50 0.82 0.98\n", + " damselfly 50 0.82 1\n", + " red admiral 50 0.94 0.96\n", + " ringlet 50 0.86 0.98\n", + " monarch butterfly 50 0.9 0.92\n", + " small white 50 0.9 1\n", + " sulphur butterfly 50 0.92 1\n", + "gossamer-winged butterfly 50 0.88 1\n", + " starfish 50 0.88 0.92\n", + " sea urchin 50 0.84 0.94\n", + " sea cucumber 50 0.66 0.84\n", + " cottontail rabbit 50 0.72 0.94\n", + " hare 50 0.84 0.96\n", + " Angora rabbit 50 0.94 0.98\n", + " hamster 50 0.96 1\n", + " porcupine 50 0.88 0.98\n", + " fox squirrel 50 0.76 0.94\n", + " marmot 50 0.92 0.96\n", + " beaver 50 0.78 0.94\n", + " guinea pig 50 0.78 0.94\n", + " common sorrel 50 0.96 0.98\n", + " zebra 50 0.94 0.96\n", + " pig 50 0.5 0.76\n", + " wild boar 50 0.84 0.96\n", + " warthog 50 0.84 0.96\n", + " hippopotamus 50 0.88 0.96\n", + " ox 50 0.48 0.94\n", + " water buffalo 50 0.78 0.94\n", + " bison 50 0.88 0.96\n", + " ram 50 0.58 0.92\n", + " bighorn sheep 50 0.66 1\n", + " Alpine ibex 50 0.92 0.98\n", + " hartebeest 50 0.94 1\n", + " impala 50 0.82 0.96\n", + " gazelle 50 0.7 0.96\n", + " dromedary 50 0.9 1\n", + " llama 50 0.82 0.94\n", + " weasel 50 0.44 0.92\n", + " mink 50 0.78 0.96\n", + " European polecat 50 0.46 0.9\n", + " black-footed ferret 50 0.68 0.96\n", + " otter 50 0.66 0.88\n", + " skunk 50 0.96 0.96\n", + " badger 50 0.86 0.92\n", + " armadillo 50 0.88 0.9\n", + " three-toed sloth 50 0.96 1\n", + " orangutan 50 0.78 0.92\n", + " gorilla 50 0.82 0.94\n", + " chimpanzee 50 0.84 0.94\n", + " gibbon 50 0.76 0.86\n", + " siamang 50 0.68 0.94\n", + " guenon 50 0.8 0.94\n", + " patas monkey 50 0.62 0.82\n", + " baboon 50 0.9 0.98\n", + " macaque 50 0.8 0.86\n", + " langur 50 0.6 0.82\n", + " black-and-white colobus 50 0.86 0.9\n", + " proboscis monkey 50 1 1\n", + " marmoset 50 0.74 0.98\n", + " white-headed capuchin 50 0.72 0.9\n", + " howler monkey 50 0.86 0.94\n", + " titi 50 0.5 0.9\n", + "Geoffroy's spider monkey 50 0.42 0.8\n", + " common squirrel monkey 50 0.76 0.92\n", + " ring-tailed lemur 50 0.72 0.94\n", + " indri 50 0.9 0.96\n", + " Asian elephant 50 0.58 0.92\n", + " African bush elephant 50 0.7 0.98\n", + " red panda 50 0.94 0.94\n", + " giant panda 50 0.94 0.98\n", + " snoek 50 0.74 0.9\n", + " eel 50 0.6 0.84\n", + " coho salmon 50 0.84 0.96\n", + " rock beauty 50 0.88 0.98\n", + " clownfish 50 0.78 0.98\n", + " sturgeon 50 0.68 0.94\n", + " garfish 50 0.62 0.8\n", + " lionfish 50 0.96 0.96\n", + " pufferfish 50 0.88 0.96\n", + " abacus 50 0.74 0.88\n", + " abaya 50 0.84 0.92\n", + " academic gown 50 0.42 0.86\n", + " accordion 50 0.8 0.9\n", + " acoustic guitar 50 0.5 0.76\n", + " aircraft carrier 50 0.8 0.96\n", + " airliner 50 0.92 1\n", + " airship 50 0.76 0.82\n", + " altar 50 0.64 0.98\n", + " ambulance 50 0.88 0.98\n", + " amphibious vehicle 50 0.64 0.94\n", + " analog clock 50 0.52 0.92\n", + " apiary 50 0.82 0.96\n", + " apron 50 0.7 0.84\n", + " waste container 50 0.4 0.8\n", + " assault rifle 50 0.42 0.84\n", + " backpack 50 0.34 0.64\n", + " bakery 50 0.4 0.68\n", + " balance beam 50 0.8 0.98\n", + " balloon 50 0.86 0.96\n", + " ballpoint pen 50 0.52 0.96\n", + " Band-Aid 50 0.7 0.9\n", + " banjo 50 0.84 1\n", + " baluster 50 0.68 0.94\n", + " barbell 50 0.56 0.9\n", + " barber chair 50 0.7 0.92\n", + " barbershop 50 0.54 0.86\n", + " barn 50 0.96 0.96\n", + " barometer 50 0.84 0.98\n", + " barrel 50 0.56 0.88\n", + " wheelbarrow 50 0.66 0.88\n", + " baseball 50 0.74 0.98\n", + " basketball 50 0.88 0.98\n", + " bassinet 50 0.66 0.92\n", + " bassoon 50 0.74 0.98\n", + " swimming cap 50 0.62 0.88\n", + " bath towel 50 0.54 0.78\n", + " bathtub 50 0.4 0.88\n", + " station wagon 50 0.66 0.84\n", + " lighthouse 50 0.78 0.94\n", + " beaker 50 0.52 0.68\n", + " military cap 50 0.84 0.96\n", + " beer bottle 50 0.66 0.88\n", + " beer glass 50 0.6 0.84\n", + " bell-cot 50 0.56 0.96\n", + " bib 50 0.58 0.82\n", + " tandem bicycle 50 0.86 0.96\n", + " bikini 50 0.56 0.88\n", + " ring binder 50 0.64 0.84\n", + " binoculars 50 0.54 0.78\n", + " birdhouse 50 0.86 0.94\n", + " boathouse 50 0.74 0.92\n", + " bobsleigh 50 0.92 0.96\n", + " bolo tie 50 0.8 0.94\n", + " poke bonnet 50 0.64 0.86\n", + " bookcase 50 0.66 0.92\n", + " bookstore 50 0.62 0.88\n", + " bottle cap 50 0.58 0.7\n", + " bow 50 0.72 0.86\n", + " bow tie 50 0.7 0.9\n", + " brass 50 0.92 0.96\n", + " bra 50 0.5 0.7\n", + " breakwater 50 0.62 0.86\n", + " breastplate 50 0.4 0.9\n", + " broom 50 0.6 0.86\n", + " bucket 50 0.66 0.8\n", + " buckle 50 0.5 0.68\n", + " bulletproof vest 50 0.5 0.78\n", + " high-speed train 50 0.94 0.96\n", + " butcher shop 50 0.74 0.94\n", + " taxicab 50 0.64 0.86\n", + " cauldron 50 0.44 0.66\n", + " candle 50 0.48 0.74\n", + " cannon 50 0.88 0.94\n", + " canoe 50 0.94 1\n", + " can opener 50 0.66 0.86\n", + " cardigan 50 0.68 0.8\n", + " car mirror 50 0.94 0.96\n", + " carousel 50 0.94 0.98\n", + " tool kit 50 0.56 0.78\n", + " carton 50 0.42 0.7\n", + " car wheel 50 0.38 0.74\n", + "automated teller machine 50 0.76 0.94\n", + " cassette 50 0.52 0.8\n", + " cassette player 50 0.28 0.9\n", + " castle 50 0.78 0.88\n", + " catamaran 50 0.78 1\n", + " CD player 50 0.52 0.82\n", + " cello 50 0.82 1\n", + " mobile phone 50 0.68 0.86\n", + " chain 50 0.38 0.66\n", + " chain-link fence 50 0.7 0.84\n", + " chain mail 50 0.64 0.9\n", + " chainsaw 50 0.84 0.92\n", + " chest 50 0.68 0.92\n", + " chiffonier 50 0.26 0.64\n", + " chime 50 0.62 0.84\n", + " china cabinet 50 0.82 0.96\n", + " Christmas stocking 50 0.92 0.94\n", + " church 50 0.62 0.9\n", + " movie theater 50 0.58 0.88\n", + " cleaver 50 0.32 0.62\n", + " cliff dwelling 50 0.88 1\n", + " cloak 50 0.32 0.64\n", + " clogs 50 0.58 0.88\n", + " cocktail shaker 50 0.62 0.7\n", + " coffee mug 50 0.44 0.72\n", + " coffeemaker 50 0.64 0.92\n", + " coil 50 0.66 0.84\n", + " combination lock 50 0.64 0.84\n", + " computer keyboard 50 0.7 0.82\n", + " confectionery store 50 0.54 0.86\n", + " container ship 50 0.82 0.98\n", + " convertible 50 0.78 0.98\n", + " corkscrew 50 0.82 0.92\n", + " cornet 50 0.46 0.88\n", + " cowboy boot 50 0.64 0.8\n", + " cowboy hat 50 0.64 0.82\n", + " cradle 50 0.38 0.8\n", + " crane (machine) 50 0.78 0.94\n", + " crash helmet 50 0.92 0.96\n", + " crate 50 0.52 0.82\n", + " infant bed 50 0.74 1\n", + " Crock Pot 50 0.78 0.9\n", + " croquet ball 50 0.9 0.96\n", + " crutch 50 0.46 0.7\n", + " cuirass 50 0.54 0.86\n", + " dam 50 0.74 0.92\n", + " desk 50 0.6 0.86\n", + " desktop computer 50 0.54 0.94\n", + " rotary dial telephone 50 0.88 0.94\n", + " diaper 50 0.68 0.84\n", + " digital clock 50 0.54 0.76\n", + " digital watch 50 0.58 0.86\n", + " dining table 50 0.76 0.9\n", + " dishcloth 50 0.94 1\n", + " dishwasher 50 0.44 0.78\n", + " disc brake 50 0.98 1\n", + " dock 50 0.54 0.94\n", + " dog sled 50 0.84 1\n", + " dome 50 0.72 0.92\n", + " doormat 50 0.56 0.82\n", + " drilling rig 50 0.84 0.96\n", + " drum 50 0.38 0.68\n", + " drumstick 50 0.56 0.72\n", + " dumbbell 50 0.62 0.9\n", + " Dutch oven 50 0.7 0.84\n", + " electric fan 50 0.82 0.86\n", + " electric guitar 50 0.62 0.84\n", + " electric locomotive 50 0.92 0.98\n", + " entertainment center 50 0.9 0.98\n", + " envelope 50 0.44 0.86\n", + " espresso machine 50 0.72 0.94\n", + " face powder 50 0.7 0.92\n", + " feather boa 50 0.7 0.84\n", + " filing cabinet 50 0.88 0.98\n", + " fireboat 50 0.94 0.98\n", + " fire engine 50 0.84 0.9\n", + " fire screen sheet 50 0.62 0.76\n", + " flagpole 50 0.74 0.88\n", + " flute 50 0.36 0.72\n", + " folding chair 50 0.62 0.84\n", + " football helmet 50 0.86 0.94\n", + " forklift 50 0.8 0.92\n", + " fountain 50 0.84 0.94\n", + " fountain pen 50 0.76 0.92\n", + " four-poster bed 50 0.78 0.94\n", + " freight car 50 0.96 1\n", + " French horn 50 0.76 0.92\n", + " frying pan 50 0.36 0.78\n", + " fur coat 50 0.84 0.96\n", + " garbage truck 50 0.9 0.98\n", + " gas mask 50 0.84 0.92\n", + " gas pump 50 0.9 0.98\n", + " goblet 50 0.68 0.82\n", + " go-kart 50 0.9 1\n", + " golf ball 50 0.84 0.9\n", + " golf cart 50 0.78 0.86\n", + " gondola 50 0.98 0.98\n", + " gong 50 0.74 0.92\n", + " gown 50 0.62 0.96\n", + " grand piano 50 0.7 0.96\n", + " greenhouse 50 0.8 0.98\n", + " grille 50 0.72 0.9\n", + " grocery store 50 0.66 0.94\n", + " guillotine 50 0.86 0.92\n", + " barrette 50 0.52 0.66\n", + " hair spray 50 0.5 0.74\n", + " half-track 50 0.78 0.9\n", + " hammer 50 0.56 0.76\n", + " hamper 50 0.64 0.84\n", + " hair dryer 50 0.56 0.74\n", + " hand-held computer 50 0.42 0.86\n", + " handkerchief 50 0.78 0.94\n", + " hard disk drive 50 0.76 0.84\n", + " harmonica 50 0.7 0.88\n", + " harp 50 0.88 0.96\n", + " harvester 50 0.78 1\n", + " hatchet 50 0.54 0.74\n", + " holster 50 0.66 0.84\n", + " home theater 50 0.64 0.94\n", + " honeycomb 50 0.56 0.88\n", + " hook 50 0.3 0.6\n", + " hoop skirt 50 0.64 0.86\n", + " horizontal bar 50 0.68 0.98\n", + " horse-drawn vehicle 50 0.88 0.94\n", + " hourglass 50 0.88 0.96\n", + " iPod 50 0.76 0.94\n", + " clothes iron 50 0.82 0.88\n", + " jack-o'-lantern 50 0.98 0.98\n", + " jeans 50 0.68 0.84\n", + " jeep 50 0.72 0.9\n", + " T-shirt 50 0.72 0.96\n", + " jigsaw puzzle 50 0.84 0.94\n", + " pulled rickshaw 50 0.86 0.94\n", + " joystick 50 0.8 0.9\n", + " kimono 50 0.84 0.96\n", + " knee pad 50 0.62 0.88\n", + " knot 50 0.66 0.8\n", + " lab coat 50 0.8 0.96\n", + " ladle 50 0.36 0.64\n", + " lampshade 50 0.48 0.84\n", + " laptop computer 50 0.26 0.88\n", + " lawn mower 50 0.78 0.96\n", + " lens cap 50 0.46 0.72\n", + " paper knife 50 0.26 0.5\n", + " library 50 0.54 0.9\n", + " lifeboat 50 0.92 0.98\n", + " lighter 50 0.56 0.78\n", + " limousine 50 0.76 0.92\n", + " ocean liner 50 0.88 0.94\n", + " lipstick 50 0.74 0.9\n", + " slip-on shoe 50 0.74 0.92\n", + " lotion 50 0.5 0.86\n", + " speaker 50 0.52 0.68\n", + " loupe 50 0.32 0.52\n", + " sawmill 50 0.72 0.9\n", + " magnetic compass 50 0.52 0.82\n", + " mail bag 50 0.68 0.92\n", + " mailbox 50 0.82 0.92\n", + " tights 50 0.22 0.94\n", + " tank suit 50 0.24 0.9\n", + " manhole cover 50 0.96 0.98\n", + " maraca 50 0.74 0.9\n", + " marimba 50 0.84 0.94\n", + " mask 50 0.44 0.82\n", + " match 50 0.66 0.9\n", + " maypole 50 0.96 1\n", + " maze 50 0.8 0.96\n", + " measuring cup 50 0.54 0.76\n", + " medicine chest 50 0.6 0.84\n", + " megalith 50 0.8 0.92\n", + " microphone 50 0.52 0.7\n", + " microwave oven 50 0.48 0.72\n", + " military uniform 50 0.62 0.84\n", + " milk can 50 0.68 0.82\n", + " minibus 50 0.7 1\n", + " miniskirt 50 0.46 0.76\n", + " minivan 50 0.38 0.8\n", + " missile 50 0.4 0.84\n", + " mitten 50 0.76 0.88\n", + " mixing bowl 50 0.8 0.92\n", + " mobile home 50 0.54 0.78\n", + " Model T 50 0.92 0.96\n", + " modem 50 0.58 0.86\n", + " monastery 50 0.44 0.9\n", + " monitor 50 0.4 0.86\n", + " moped 50 0.56 0.94\n", + " mortar 50 0.68 0.94\n", + " square academic cap 50 0.5 0.84\n", + " mosque 50 0.9 1\n", + " mosquito net 50 0.9 0.98\n", + " scooter 50 0.9 0.98\n", + " mountain bike 50 0.78 0.96\n", + " tent 50 0.88 0.96\n", + " computer mouse 50 0.42 0.82\n", + " mousetrap 50 0.76 0.88\n", + " moving van 50 0.4 0.72\n", + " muzzle 50 0.5 0.72\n", + " nail 50 0.68 0.74\n", + " neck brace 50 0.56 0.68\n", + " necklace 50 0.86 1\n", + " nipple 50 0.7 0.88\n", + " notebook computer 50 0.34 0.84\n", + " obelisk 50 0.8 0.92\n", + " oboe 50 0.6 0.84\n", + " ocarina 50 0.8 0.86\n", + " odometer 50 0.96 1\n", + " oil filter 50 0.58 0.82\n", + " organ 50 0.82 0.9\n", + " oscilloscope 50 0.9 0.96\n", + " overskirt 50 0.2 0.7\n", + " bullock cart 50 0.7 0.94\n", + " oxygen mask 50 0.46 0.84\n", + " packet 50 0.5 0.78\n", + " paddle 50 0.56 0.94\n", + " paddle wheel 50 0.86 0.96\n", + " padlock 50 0.74 0.78\n", + " paintbrush 50 0.62 0.8\n", + " pajamas 50 0.56 0.92\n", + " palace 50 0.64 0.96\n", + " pan flute 50 0.84 0.86\n", + " paper towel 50 0.66 0.84\n", + " parachute 50 0.92 0.94\n", + " parallel bars 50 0.62 0.96\n", + " park bench 50 0.74 0.9\n", + " parking meter 50 0.84 0.92\n", + " passenger car 50 0.5 0.82\n", + " patio 50 0.58 0.84\n", + " payphone 50 0.74 0.92\n", + " pedestal 50 0.52 0.9\n", + " pencil case 50 0.64 0.92\n", + " pencil sharpener 50 0.52 0.78\n", + " perfume 50 0.7 0.9\n", + " Petri dish 50 0.6 0.8\n", + " photocopier 50 0.88 0.98\n", + " plectrum 50 0.7 0.84\n", + " Pickelhaube 50 0.72 0.86\n", + " picket fence 50 0.84 0.94\n", + " pickup truck 50 0.64 0.92\n", + " pier 50 0.52 0.82\n", + " piggy bank 50 0.82 0.94\n", + " pill bottle 50 0.76 0.86\n", + " pillow 50 0.76 0.9\n", + " ping-pong ball 50 0.84 0.88\n", + " pinwheel 50 0.76 0.88\n", + " pirate ship 50 0.76 0.94\n", + " pitcher 50 0.46 0.84\n", + " hand plane 50 0.84 0.94\n", + " planetarium 50 0.88 0.98\n", + " plastic bag 50 0.36 0.62\n", + " plate rack 50 0.52 0.78\n", + " plow 50 0.78 0.88\n", + " plunger 50 0.42 0.7\n", + " Polaroid camera 50 0.84 0.92\n", + " pole 50 0.38 0.74\n", + " police van 50 0.76 0.94\n", + " poncho 50 0.58 0.86\n", + " billiard table 50 0.8 0.88\n", + " soda bottle 50 0.56 0.94\n", + " pot 50 0.78 0.92\n", + " potter's wheel 50 0.9 0.94\n", + " power drill 50 0.42 0.72\n", + " prayer rug 50 0.7 0.86\n", + " printer 50 0.54 0.86\n", + " prison 50 0.7 0.9\n", + " projectile 50 0.28 0.9\n", + " projector 50 0.62 0.84\n", + " hockey puck 50 0.92 0.96\n", + " punching bag 50 0.6 0.68\n", + " purse 50 0.42 0.78\n", + " quill 50 0.68 0.84\n", + " quilt 50 0.64 0.9\n", + " race car 50 0.72 0.92\n", + " racket 50 0.72 0.9\n", + " radiator 50 0.66 0.76\n", + " radio 50 0.64 0.92\n", + " radio telescope 50 0.9 0.96\n", + " rain barrel 50 0.8 0.98\n", + " recreational vehicle 50 0.84 0.94\n", + " reel 50 0.72 0.82\n", + " reflex camera 50 0.72 0.92\n", + " refrigerator 50 0.7 0.9\n", + " remote control 50 0.7 0.88\n", + " restaurant 50 0.5 0.66\n", + " revolver 50 0.82 1\n", + " rifle 50 0.38 0.7\n", + " rocking chair 50 0.62 0.84\n", + " rotisserie 50 0.88 0.92\n", + " eraser 50 0.54 0.76\n", + " rugby ball 50 0.86 0.94\n", + " ruler 50 0.68 0.86\n", + " running shoe 50 0.78 0.94\n", + " safe 50 0.82 0.92\n", + " safety pin 50 0.4 0.62\n", + " salt shaker 50 0.66 0.9\n", + " sandal 50 0.66 0.86\n", + " sarong 50 0.64 0.86\n", + " saxophone 50 0.66 0.88\n", + " scabbard 50 0.76 0.92\n", + " weighing scale 50 0.58 0.78\n", + " school bus 50 0.92 1\n", + " schooner 50 0.84 1\n", + " scoreboard 50 0.9 0.96\n", + " CRT screen 50 0.14 0.7\n", + " screw 50 0.9 0.98\n", + " screwdriver 50 0.3 0.58\n", + " seat belt 50 0.88 0.94\n", + " sewing machine 50 0.76 0.9\n", + " shield 50 0.56 0.82\n", + " shoe store 50 0.78 0.96\n", + " shoji 50 0.8 0.92\n", + " shopping basket 50 0.52 0.88\n", + " shopping cart 50 0.76 0.92\n", + " shovel 50 0.62 0.84\n", + " shower cap 50 0.7 0.84\n", + " shower curtain 50 0.64 0.82\n", + " ski 50 0.74 0.92\n", + " ski mask 50 0.72 0.88\n", + " sleeping bag 50 0.68 0.8\n", + " slide rule 50 0.72 0.88\n", + " sliding door 50 0.44 0.78\n", + " slot machine 50 0.94 0.98\n", + " snorkel 50 0.86 0.98\n", + " snowmobile 50 0.88 1\n", + " snowplow 50 0.84 0.98\n", + " soap dispenser 50 0.56 0.86\n", + " soccer ball 50 0.86 0.96\n", + " sock 50 0.62 0.76\n", + " solar thermal collector 50 0.72 0.96\n", + " sombrero 50 0.6 0.84\n", + " soup bowl 50 0.56 0.94\n", + " space bar 50 0.34 0.88\n", + " space heater 50 0.52 0.74\n", + " space shuttle 50 0.82 0.96\n", + " spatula 50 0.3 0.6\n", + " motorboat 50 0.86 1\n", + " spider web 50 0.7 0.9\n", + " spindle 50 0.86 0.98\n", + " sports car 50 0.6 0.94\n", + " spotlight 50 0.26 0.6\n", + " stage 50 0.68 0.86\n", + " steam locomotive 50 0.94 1\n", + " through arch bridge 50 0.84 0.96\n", + " steel drum 50 0.82 0.9\n", + " stethoscope 50 0.6 0.82\n", + " scarf 50 0.5 0.92\n", + " stone wall 50 0.76 0.9\n", + " stopwatch 50 0.58 0.9\n", + " stove 50 0.46 0.74\n", + " strainer 50 0.64 0.84\n", + " tram 50 0.88 0.96\n", + " stretcher 50 0.6 0.8\n", + " couch 50 0.8 0.96\n", + " stupa 50 0.88 0.88\n", + " submarine 50 0.72 0.92\n", + " suit 50 0.4 0.78\n", + " sundial 50 0.58 0.74\n", + " sunglass 50 0.14 0.58\n", + " sunglasses 50 0.28 0.58\n", + " sunscreen 50 0.32 0.7\n", + " suspension bridge 50 0.6 0.94\n", + " mop 50 0.74 0.92\n", + " sweatshirt 50 0.28 0.66\n", + " swimsuit 50 0.52 0.82\n", + " swing 50 0.76 0.84\n", + " switch 50 0.56 0.76\n", + " syringe 50 0.62 0.82\n", + " table lamp 50 0.6 0.88\n", + " tank 50 0.8 0.96\n", + " tape player 50 0.46 0.76\n", + " teapot 50 0.84 1\n", + " teddy bear 50 0.82 0.94\n", + " television 50 0.6 0.9\n", + " tennis ball 50 0.7 0.94\n", + " thatched roof 50 0.88 0.9\n", + " front curtain 50 0.8 0.92\n", + " thimble 50 0.6 0.8\n", + " threshing machine 50 0.56 0.88\n", + " throne 50 0.72 0.82\n", + " tile roof 50 0.72 0.94\n", + " toaster 50 0.66 0.84\n", + " tobacco shop 50 0.42 0.7\n", + " toilet seat 50 0.62 0.88\n", + " torch 50 0.64 0.84\n", + " totem pole 50 0.92 0.98\n", + " tow truck 50 0.62 0.88\n", + " toy store 50 0.6 0.94\n", + " tractor 50 0.76 0.98\n", + " semi-trailer truck 50 0.78 0.92\n", + " tray 50 0.46 0.64\n", + " trench coat 50 0.54 0.72\n", + " tricycle 50 0.72 0.94\n", + " trimaran 50 0.7 0.98\n", + " tripod 50 0.58 0.86\n", + " triumphal arch 50 0.92 0.98\n", + " trolleybus 50 0.9 1\n", + " trombone 50 0.54 0.88\n", + " tub 50 0.24 0.82\n", + " turnstile 50 0.84 0.94\n", + " typewriter keyboard 50 0.68 0.98\n", + " umbrella 50 0.52 0.7\n", + " unicycle 50 0.74 0.96\n", + " upright piano 50 0.76 0.9\n", + " vacuum cleaner 50 0.62 0.9\n", + " vase 50 0.5 0.78\n", + " vault 50 0.76 0.92\n", + " velvet 50 0.2 0.42\n", + " vending machine 50 0.9 1\n", + " vestment 50 0.54 0.82\n", + " viaduct 50 0.78 0.86\n", + " violin 50 0.68 0.78\n", + " volleyball 50 0.86 1\n", + " waffle iron 50 0.72 0.88\n", + " wall clock 50 0.54 0.88\n", + " wallet 50 0.52 0.9\n", + " wardrobe 50 0.68 0.88\n", + " military aircraft 50 0.9 0.98\n", + " sink 50 0.72 0.96\n", + " washing machine 50 0.78 0.94\n", + " water bottle 50 0.54 0.74\n", + " water jug 50 0.22 0.74\n", + " water tower 50 0.9 0.96\n", + " whiskey jug 50 0.64 0.74\n", + " whistle 50 0.72 0.84\n", + " wig 50 0.84 0.9\n", + " window screen 50 0.68 0.8\n", + " window shade 50 0.52 0.76\n", + " Windsor tie 50 0.22 0.66\n", + " wine bottle 50 0.42 0.82\n", + " wing 50 0.54 0.96\n", + " wok 50 0.46 0.82\n", + " wooden spoon 50 0.58 0.8\n", + " wool 50 0.32 0.82\n", + " split-rail fence 50 0.74 0.9\n", + " shipwreck 50 0.84 0.96\n", + " yawl 50 0.78 0.96\n", + " yurt 50 0.84 1\n", + " website 50 0.98 1\n", + " comic book 50 0.62 0.9\n", + " crossword 50 0.84 0.88\n", + " traffic sign 50 0.78 0.9\n", + " traffic light 50 0.8 0.94\n", + " dust jacket 50 0.72 0.94\n", + " menu 50 0.82 0.96\n", + " plate 50 0.44 0.88\n", + " guacamole 50 0.8 0.92\n", + " consomme 50 0.54 0.88\n", + " hot pot 50 0.86 0.98\n", + " trifle 50 0.92 0.98\n", + " ice cream 50 0.68 0.94\n", + " ice pop 50 0.62 0.84\n", + " baguette 50 0.62 0.88\n", + " bagel 50 0.64 0.92\n", + " pretzel 50 0.72 0.88\n", + " cheeseburger 50 0.9 1\n", + " hot dog 50 0.74 0.94\n", + " mashed potato 50 0.74 0.9\n", + " cabbage 50 0.84 0.96\n", + " broccoli 50 0.9 0.96\n", + " cauliflower 50 0.82 1\n", + " zucchini 50 0.74 0.9\n", + " spaghetti squash 50 0.8 0.96\n", + " acorn squash 50 0.82 0.96\n", + " butternut squash 50 0.7 0.94\n", + " cucumber 50 0.6 0.96\n", + " artichoke 50 0.84 0.94\n", + " bell pepper 50 0.84 0.98\n", + " cardoon 50 0.88 0.94\n", + " mushroom 50 0.38 0.92\n", + " Granny Smith 50 0.9 0.96\n", + " strawberry 50 0.6 0.88\n", + " orange 50 0.7 0.92\n", + " lemon 50 0.78 0.98\n", + " fig 50 0.82 0.96\n", + " pineapple 50 0.86 0.96\n", + " banana 50 0.84 0.96\n", + " jackfruit 50 0.9 0.98\n", + " custard apple 50 0.86 0.96\n", + " pomegranate 50 0.82 0.98\n", + " hay 50 0.8 0.92\n", + " carbonara 50 0.88 0.94\n", + " chocolate syrup 50 0.46 0.84\n", + " dough 50 0.4 0.6\n", + " meatloaf 50 0.58 0.84\n", + " pizza 50 0.84 0.96\n", + " pot pie 50 0.68 0.9\n", + " burrito 50 0.8 0.98\n", + " red wine 50 0.54 0.82\n", + " espresso 50 0.64 0.88\n", + " cup 50 0.38 0.7\n", + " eggnog 50 0.38 0.7\n", + " alp 50 0.54 0.88\n", + " bubble 50 0.8 0.96\n", + " cliff 50 0.64 1\n", + " coral reef 50 0.72 0.96\n", + " geyser 50 0.94 1\n", + " lakeshore 50 0.54 0.88\n", + " promontory 50 0.58 0.94\n", + " shoal 50 0.6 0.96\n", + " seashore 50 0.44 0.78\n", + " valley 50 0.72 0.94\n", + " volcano 50 0.78 0.96\n", + " baseball player 50 0.72 0.94\n", + " bridegroom 50 0.72 0.88\n", + " scuba diver 50 0.8 1\n", + " rapeseed 50 0.94 0.98\n", + " daisy 50 0.96 0.98\n", + " yellow lady's slipper 50 1 1\n", + " corn 50 0.4 0.88\n", + " acorn 50 0.92 0.98\n", + " rose hip 50 0.92 0.98\n", + " horse chestnut seed 50 0.94 0.98\n", + " coral fungus 50 0.96 0.96\n", + " agaric 50 0.82 0.94\n", + " gyromitra 50 0.98 1\n", + " stinkhorn mushroom 50 0.8 0.94\n", + " earth star 50 0.98 1\n", + " hen-of-the-woods 50 0.8 0.96\n", + " bolete 50 0.74 0.94\n", + " ear 50 0.48 0.94\n", + " toilet paper 50 0.36 0.68\n", + "Speed: 0.1ms pre-process, 0.3ms inference, 0.0ms post-process per image at shape (1, 3, 224, 224)\n", + "Results saved to \u001b[1mruns/val-cls/exp\u001b[0m\n" + ] } - ], - "metadata": { - "accelerator": "GPU", + ], + "source": [ + "# Validate YOLOv5s on Imagenet val\n", + "!python classify/val.py --weights yolov5s-cls.pt --data ../datasets/imagenet --img 224 --half" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZY2VXXXu74w5" + }, + "source": [ + "# 3. Train\n", + "\n", + "

\n", + "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", + "

\n", + "\n", + "Train a YOLOv5s Classification model on the [Imagenette](https://image-net.org/) dataset with `--data imagenet`, starting from pretrained `--pretrained yolov5s-cls.pt`.\n", + "\n", + "- **Pretrained [Models](https://github.com/ultralytics/yolov5/tree/master/models)** are downloaded\n", + "automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases)\n", + "- **Training Results** are saved to `runs/train-cls/` with incrementing run directories, i.e. `runs/train-cls/exp2`, `runs/train-cls/exp3` etc.\n", + "

\n", + "\n", + "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic.\n", + "\n", + "## Train on Custom Data with Roboflow 🌟 NEW\n", + "\n", + "[Roboflow](https://roboflow.com/?ref=ultralytics) enables you to easily **organize, label, and prepare** a high quality dataset with your own custom data. Roboflow also makes it easy to establish an active learning pipeline, collaborate with your team on dataset improvement, and integrate directly into your model building workflow with the `roboflow` pip package.\n", + "\n", + "- Custom Training Example: [https://blog.roboflow.com/train-yolov5-classification-custom-data/](https://blog.roboflow.com/train-yolov5-classification-custom-data/?ref=ultralytics)\n", + "- Custom Training Notebook: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1KZiKUAjtARHAfZCXbJRv14-pOnIsBLPV?usp=sharing)\n", + "
\n", + "\n", + "

Label images lightning fast (including with model-assisted labeling)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "i3oKtE4g-aNn" + }, + "outputs": [], + "source": [ + "# @title Select YOLOv5 🚀 logger {run: 'auto'}\n", + "logger = \"Comet\" # @param ['Comet', 'ClearML', 'TensorBoard']\n", + "\n", + "if logger == \"Comet\":\n", + " %pip install -q comet_ml\n", + " import comet_ml\n", + "\n", + " comet_ml.init()\n", + "elif logger == \"ClearML\":\n", + " %pip install -q clearml\n", + " import clearml\n", + "\n", + " clearml.browser_login()\n", + "elif logger == \"TensorBoard\":\n", + " %load_ext tensorboard\n", + " %tensorboard --logdir runs/train" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { "colab": { - "name": "YOLOv5 Classification Tutorial", - "provenance": [] - }, - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" + "base_uri": "https://localhost:8080/" }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.12" + "id": "1NcFxRcFdJ_O", + "outputId": "77c8d487-16db-4073-b3ea-06cabf2e7766" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[34m\u001b[1mclassify/train: \u001b[0mmodel=yolov5s-cls.pt, data=imagenette160, epochs=5, batch_size=64, imgsz=224, nosave=False, cache=ram, device=, workers=8, project=runs/train-cls, name=exp, exist_ok=False, pretrained=True, optimizer=Adam, lr0=0.001, decay=5e-05, label_smoothing=0.1, cutoff=None, dropout=None, verbose=False, seed=0, local_rank=-1\n", + "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", + "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "\n", + "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train-cls', view at http://localhost:6006/\n", + "\n", + "Dataset not found ⚠️, missing path /content/datasets/imagenette160, attempting download...\n", + "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/imagenette160.zip to /content/datasets/imagenette160.zip...\n", + "100% 103M/103M [00:00<00:00, 347MB/s] \n", + "Unzipping /content/datasets/imagenette160.zip...\n", + "Dataset download success ✅ (3.3s), saved to \u001b[1m/content/datasets/imagenette160\u001b[0m\n", + "\n", + "\u001b[34m\u001b[1malbumentations: \u001b[0mRandomResizedCrop(p=1.0, height=224, width=224, scale=(0.08, 1.0), ratio=(0.75, 1.3333333333333333), interpolation=1), HorizontalFlip(p=0.5), ColorJitter(p=0.5, brightness=[0.6, 1.4], contrast=[0.6, 1.4], saturation=[0.6, 1.4], hue=[0, 0]), Normalize(p=1.0, mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), max_pixel_value=255.0), ToTensorV2(always_apply=True, p=1.0, transpose_mask=False)\n", + "Model summary: 149 layers, 4185290 parameters, 4185290 gradients, 10.5 GFLOPs\n", + "\u001b[34m\u001b[1moptimizer:\u001b[0m Adam(lr=0.001) with parameter groups 32 weight(decay=0.0), 33 weight(decay=5e-05), 33 bias\n", + "Image sizes 224 train, 224 test\n", + "Using 1 dataloader workers\n", + "Logging results to \u001b[1mruns/train-cls/exp\u001b[0m\n", + "Starting yolov5s-cls.pt training on imagenette160 dataset with 10 classes for 5 epochs...\n", + "\n", + " Epoch GPU_mem train_loss val_loss top1_acc top5_acc\n", + " 1/5 1.47G 1.05 0.974 0.828 0.975: 100% 148/148 [00:38<00:00, 3.82it/s]\n", + " 2/5 1.73G 0.895 0.766 0.911 0.994: 100% 148/148 [00:36<00:00, 4.03it/s]\n", + " 3/5 1.73G 0.82 0.704 0.934 0.996: 100% 148/148 [00:35<00:00, 4.20it/s]\n", + " 4/5 1.73G 0.766 0.664 0.951 0.998: 100% 148/148 [00:36<00:00, 4.05it/s]\n", + " 5/5 1.73G 0.724 0.634 0.959 0.997: 100% 148/148 [00:37<00:00, 3.94it/s]\n", + "\n", + "Training complete (0.052 hours)\n", + "Results saved to \u001b[1mruns/train-cls/exp\u001b[0m\n", + "Predict: python classify/predict.py --weights runs/train-cls/exp/weights/best.pt --source im.jpg\n", + "Validate: python classify/val.py --weights runs/train-cls/exp/weights/best.pt --data /content/datasets/imagenette160\n", + "Export: python export.py --weights runs/train-cls/exp/weights/best.pt --include onnx\n", + "PyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', 'runs/train-cls/exp/weights/best.pt')\n", + "Visualize: https://netron.app\n", + "\n" + ] } + ], + "source": [ + "# Train YOLOv5s Classification on Imagenette160 for 3 epochs\n", + "!python classify/train.py --model yolov5s-cls.pt --data imagenette160 --epochs 5 --img 224 --cache" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "15glLzbQx5u0" + }, + "source": [ + "# 4. Visualize" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nWOsI5wJR1o3" + }, + "source": [ + "## Comet Logging and Visualization 🌟 NEW\n", + "\n", + "[Comet](https://www.comet.com/site/lp/yolov5-with-comet/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab) is now fully integrated with YOLOv5. Track and visualize model metrics in real time, save your hyperparameters, datasets, and model checkpoints, and visualize your model predictions with [Comet Custom Panels](https://www.comet.com/docs/v2/guides/comet-dashboard/code-panels/about-panels/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab)! Comet makes sure you never lose track of your work and makes it easy to share results and collaborate across teams of all sizes!\n", + "\n", + "Getting started is easy:\n", + "```shell\n", + "pip install comet_ml # 1. install\n", + "export COMET_API_KEY= # 2. paste API key\n", + "python train.py --img 640 --epochs 3 --data coco128.yaml --weights yolov5s.pt # 3. train\n", + "```\n", + "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing)\n", + "\n", + "\n", + "\"Comet" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Lay2WsTjNJzP" + }, + "source": [ + "## ClearML Logging and Automation 🌟 NEW\n", + "\n", + "[ClearML](https://cutt.ly/yolov5-notebook-clearml) is completely integrated into YOLOv5 to track your experimentation, manage dataset versions and even remotely execute training runs. To enable ClearML (check cells above):\n", + "\n", + "- `pip install clearml`\n", + "- run `clearml-init` to connect to a ClearML server (**deploy your own [open-source server](https://github.com/allegroai/clearml-server)**, or use our [free hosted server](https://cutt.ly/yolov5-notebook-clearml))\n", + "\n", + "You'll get all the great expected features from an experiment manager: live updates, model upload, experiment comparison etc. but ClearML also tracks uncommitted changes and installed packages for example. Thanks to that ClearML Tasks (which is what we call experiments) are also reproducible on different machines! With only 1 extra line, we can schedule a YOLOv5 training task on a queue to be executed by any number of ClearML Agents (workers).\n", + "\n", + "You can use ClearML Data to version your dataset and then pass it to YOLOv5 simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration) for details!\n", + "\n", + "\n", + "\"ClearML" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-WPvRbS5Swl6" + }, + "source": [ + "## Local Logging\n", + "\n", + "Training results are automatically logged with [Tensorboard](https://www.tensorflow.org/tensorboard) and [CSV](https://github.com/ultralytics/yolov5/pull/4148) loggers to `runs/train`, with a new experiment directory created for each new training as `runs/train/exp2`, `runs/train/exp3`, etc.\n", + "\n", + "This directory contains train and val statistics, mosaics, labels, predictions and augmentated mosaics, as well as metrics and charts including precision-recall (PR) curves and confusion matrices. \n", + "\n", + "\"Local\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Zelyeqbyt3GD" + }, + "source": [ + "# Environments\n", + "\n", + "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):\n", + "\n", + "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", + "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)\n", + "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)\n", + "- **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) \"Docker\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6Qu7Iesl0p54" + }, + "source": [ + "# Status\n", + "\n", + "![YOLOv5 CI](https://github.com/ultralytics/yolov3/actions/workflows/ci-testing.yml/badge.svg)\n", + "\n", + "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/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)), testing ([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.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IEijrePND_2I" + }, + "source": [ + "# Appendix\n", + "\n", + "Additional content below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GMusP4OAxFu6" + }, + "outputs": [], + "source": [ + "# YOLOv5 PyTorch HUB Inference (DetectionModels only)\n", + "\n", + "model = torch.hub.load(\"ultralytics/yolov5\", \"yolov5s\") # yolov5n - yolov5x6 or custom\n", + "im = \"https://ultralytics.com/images/zidane.jpg\" # file, Path, PIL.Image, OpenCV, nparray, list\n", + "results = model(im) # inference\n", + "results.print() # or .show(), .save(), .crop(), .pandas(), etc." + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "name": "YOLOv5 Classification Tutorial", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 0 + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 0 } diff --git a/segment/tutorial.ipynb b/segment/tutorial.ipynb index 346dd2e961..55eaa254a1 100644 --- a/segment/tutorial.ipynb +++ b/segment/tutorial.ipynb @@ -1,595 +1,600 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "t6MPjfT5NrKQ" - }, - "source": [ - "
\n", - "\n", - " \n", - " \n", - "\n", - "\n", - "
\n", - " \"Run\n", - " \"Open\n", - " \"Open\n", - "
\n", - "\n", - "This YOLOv5 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", - "\n", - "
" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "7mGmQbAO5pQb" - }, - "source": [ - "# Setup\n", - "\n", - "Clone GitHub [repository](https://github.com/ultralytics/yolov5), install [dependencies](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) and check PyTorch and GPU." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "wbvMlHd_QwMG", - "outputId": "171b23f0-71b9-4cbf-b666-6fa2ecef70c8" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stderr", - "text": [ - "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n" - ] - }, - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Setup complete ✅ (2 CPUs, 12.7 GB RAM, 22.6/78.2 GB disk)\n" - ] - } - ], - "source": [ - "!git clone https://github.com/ultralytics/yolov5 # clone\n", - "%cd yolov5\n", - "%pip install -qr requirements.txt comet_ml # install\n", - "\n", - "import torch\n", - "import utils\n", - "display = utils.notebook_init() # checks" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "4JnkELT0cIJg" - }, - "source": [ - "# 1. Predict\n", - "\n", - "`segment/predict.py` runs YOLOv5 instance segmentation inference on a variety of sources, downloading models automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases), and saving results to `runs/predict`. Example inference sources are:\n", - "\n", - "```shell\n", - "python segment/predict.py --source 0 # webcam\n", - " img.jpg # image \n", - " vid.mp4 # video\n", - " screen # screenshot\n", - " path/ # directory\n", - " 'path/*.jpg' # glob\n", - " 'https://youtu.be/LNwODJXcvt4' # YouTube\n", - " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "zR9ZbuQCH7FX", - "outputId": "3f67f1c7-f15e-4fa5-d251-967c3b77eaad" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "\u001b[34m\u001b[1msegment/predict: \u001b[0mweights=['yolov5s-seg.pt'], source=data/images, data=data/coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/predict-seg, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False, vid_stride=1, retina_masks=False\n", - "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", - "\n", - "Downloading https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt to yolov5s-seg.pt...\n", - "100% 14.9M/14.9M [00:01<00:00, 12.0MB/s]\n", - "\n", - "Fusing layers... \n", - "YOLOv5s-seg summary: 224 layers, 7611485 parameters, 0 gradients, 26.4 GFLOPs\n", - "image 1/2 /content/yolov5/data/images/bus.jpg: 640x480 4 persons, 1 bus, 18.2ms\n", - "image 2/2 /content/yolov5/data/images/zidane.jpg: 384x640 2 persons, 1 tie, 13.4ms\n", - "Speed: 0.5ms pre-process, 15.8ms inference, 18.5ms NMS per image at shape (1, 3, 640, 640)\n", - "Results saved to \u001b[1mruns/predict-seg/exp\u001b[0m\n" - ] - } - ], - "source": [ - "!python segment/predict.py --weights yolov5s-seg.pt --img 640 --conf 0.25 --source data/images\n", - "#display.Image(filename='runs/predict-seg/exp/zidane.jpg', width=600)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "hkAzDWJ7cWTr" - }, - "source": [ - "        \n", - "" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "0eq1SMWl6Sfn" - }, - "source": [ - "# 2. Validate\n", - "Validate a model's accuracy on the [COCO](https://cocodataset.org/#home) dataset's `val` or `test` splits. Models are downloaded automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases). To show results by class use the `--verbose` flag." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "WQPtK1QYVaD_", - "outputId": "9d751d8c-bee8-4339-cf30-9854ca530449" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/coco2017labels-segments.zip ...\n", - "Downloading http://images.cocodataset.org/zips/val2017.zip ...\n", - "######################################################################## 100.0%\n", - "######################################################################## 100.0%\n" - ] - } - ], - "source": [ - "# Download COCO val\n", - "!bash data/scripts/get_coco.sh --val --segments # download (780M - 5000 images)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "X58w8JLpMnjH", - "outputId": "a140d67a-02da-479e-9ddb-7d54bf9e407a" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "\u001b[34m\u001b[1msegment/val: \u001b[0mdata=/content/yolov5/data/coco.yaml, weights=['yolov5s-seg.pt'], batch_size=32, imgsz=640, conf_thres=0.001, iou_thres=0.6, max_det=300, task=val, device=, workers=8, single_cls=False, augment=False, verbose=False, save_txt=False, save_hybrid=False, save_conf=False, save_json=False, project=runs/val-seg, name=exp, exist_ok=False, half=True, dnn=False\n", - "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", - "\n", - "Fusing layers... \n", - "YOLOv5s-seg summary: 224 layers, 7611485 parameters, 0 gradients, 26.4 GFLOPs\n", - "\u001b[34m\u001b[1mval: \u001b[0mScanning /content/datasets/coco/val2017... 4952 images, 48 backgrounds, 0 corrupt: 100% 5000/5000 [00:03<00:00, 1361.31it/s]\n", - "\u001b[34m\u001b[1mval: \u001b[0mNew cache created: /content/datasets/coco/val2017.cache\n", - " Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100% 157/157 [01:54<00:00, 1.37it/s]\n", - " all 5000 36335 0.673 0.517 0.566 0.373 0.672 0.49 0.532 0.319\n", - "Speed: 0.6ms pre-process, 4.4ms inference, 2.9ms NMS per image at shape (32, 3, 640, 640)\n", - "Results saved to \u001b[1mruns/val-seg/exp\u001b[0m\n" - ] - } - ], - "source": [ - "# Validate YOLOv5s-seg on COCO val\n", - "!python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 --half" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "ZY2VXXXu74w5" - }, - "source": [ - "# 3. Train\n", - "\n", - "

\n", - "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", - "

\n", - "\n", - "Train a YOLOv5s-seg model on the [COCO128](https://www.kaggle.com/ultralytics/coco128) dataset with `--data coco128-seg.yaml`, starting from pretrained `--weights yolov5s-seg.pt`, or from randomly initialized `--weights '' --cfg yolov5s-seg.yaml`.\n", - "\n", - "- **Pretrained [Models](https://github.com/ultralytics/yolov5/tree/master/models)** are downloaded\n", - "automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases)\n", - "- **[Datasets](https://github.com/ultralytics/yolov5/tree/master/data)** available for autodownload include: [COCO](https://github.com/ultralytics/yolov5/blob/master/data/coco.yaml), [COCO128](https://github.com/ultralytics/yolov5/blob/master/data/coco128.yaml), [VOC](https://github.com/ultralytics/yolov5/blob/master/data/VOC.yaml), [Argoverse](https://github.com/ultralytics/yolov5/blob/master/data/Argoverse.yaml), [VisDrone](https://github.com/ultralytics/yolov5/blob/master/data/VisDrone.yaml), [GlobalWheat](https://github.com/ultralytics/yolov5/blob/master/data/GlobalWheat2020.yaml), [xView](https://github.com/ultralytics/yolov5/blob/master/data/xView.yaml), [Objects365](https://github.com/ultralytics/yolov5/blob/master/data/Objects365.yaml), [SKU-110K](https://github.com/ultralytics/yolov5/blob/master/data/SKU-110K.yaml).\n", - "- **Training Results** are saved to `runs/train-seg/` with incrementing run directories, i.e. `runs/train-seg/exp2`, `runs/train-seg/exp3` etc.\n", - "

\n", - "\n", - "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic.\n", - "\n", - "## Train on Custom Data with Roboflow 🌟 NEW\n", - "\n", - "[Roboflow](https://roboflow.com/?ref=ultralytics) enables you to easily **organize, label, and prepare** a high quality dataset with your own custom data. Roboflow also makes it easy to establish an active learning pipeline, collaborate with your team on dataset improvement, and integrate directly into your model building workflow with the `roboflow` pip package.\n", - "\n", - "- Custom Training Example: [https://blog.roboflow.com/train-yolov5-instance-segmentation-custom-dataset/](https://blog.roboflow.com/train-yolov5-instance-segmentation-custom-dataset/?ref=ultralytics)\n", - "- Custom Training Notebook: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1JTz7kpmHsg-5qwVz2d2IH3AaenI1tv0N?usp=sharing)\n", - "
\n", - "\n", - "

Label images lightning fast (including with model-assisted labeling)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "i3oKtE4g-aNn" - }, - "outputs": [], - "source": [ - "#@title Select YOLOv5 🚀 logger {run: 'auto'}\n", - "logger = 'Comet' #@param ['Comet', 'ClearML', 'TensorBoard']\n", - "\n", - "if logger == 'Comet':\n", - " %pip install -q comet_ml\n", - " import comet_ml; comet_ml.init()\n", - "elif logger == 'ClearML':\n", - " %pip install -q clearml\n", - " import clearml; clearml.browser_login()\n", - "elif logger == 'TensorBoard':\n", - " %load_ext tensorboard\n", - " %tensorboard --logdir runs/train" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "1NcFxRcFdJ_O", - "outputId": "3a3e0cf7-e79c-47a5-c8e7-2d26eeeab988" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "\u001b[34m\u001b[1msegment/train: \u001b[0mweights=yolov5s-seg.pt, cfg=, data=coco128-seg.yaml, hyp=data/hyps/hyp.scratch-low.yaml, epochs=3, batch_size=16, imgsz=640, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, noplots=False, evolve=None, bucket=, cache=ram, image_weights=False, device=, multi_scale=False, single_cls=False, optimizer=SGD, sync_bn=False, workers=8, project=runs/train-seg, name=exp, exist_ok=False, quad=False, cos_lr=False, label_smoothing=0.0, patience=100, freeze=[0], save_period=-1, seed=0, local_rank=-1, mask_ratio=4, no_overlap=False\n", - "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", - "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", - "\n", - "\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0\n", - "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train-seg', view at http://localhost:6006/\n", - "\n", - "Dataset not found ⚠️, missing paths ['/content/datasets/coco128-seg/images/train2017']\n", - "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/coco128-seg.zip to coco128-seg.zip...\n", - "100% 6.79M/6.79M [00:01<00:00, 6.73MB/s]\n", - "Dataset download success ✅ (1.9s), saved to \u001b[1m/content/datasets\u001b[0m\n", - "\n", - " from n params module arguments \n", - " 0 -1 1 3520 models.common.Conv [3, 32, 6, 2, 2] \n", - " 1 -1 1 18560 models.common.Conv [32, 64, 3, 2] \n", - " 2 -1 1 18816 models.common.C3 [64, 64, 1] \n", - " 3 -1 1 73984 models.common.Conv [64, 128, 3, 2] \n", - " 4 -1 2 115712 models.common.C3 [128, 128, 2] \n", - " 5 -1 1 295424 models.common.Conv [128, 256, 3, 2] \n", - " 6 -1 3 625152 models.common.C3 [256, 256, 3] \n", - " 7 -1 1 1180672 models.common.Conv [256, 512, 3, 2] \n", - " 8 -1 1 1182720 models.common.C3 [512, 512, 1] \n", - " 9 -1 1 656896 models.common.SPPF [512, 512, 5] \n", - " 10 -1 1 131584 models.common.Conv [512, 256, 1, 1] \n", - " 11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", - " 12 [-1, 6] 1 0 models.common.Concat [1] \n", - " 13 -1 1 361984 models.common.C3 [512, 256, 1, False] \n", - " 14 -1 1 33024 models.common.Conv [256, 128, 1, 1] \n", - " 15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", - " 16 [-1, 4] 1 0 models.common.Concat [1] \n", - " 17 -1 1 90880 models.common.C3 [256, 128, 1, False] \n", - " 18 -1 1 147712 models.common.Conv [128, 128, 3, 2] \n", - " 19 [-1, 14] 1 0 models.common.Concat [1] \n", - " 20 -1 1 296448 models.common.C3 [256, 256, 1, False] \n", - " 21 -1 1 590336 models.common.Conv [256, 256, 3, 2] \n", - " 22 [-1, 10] 1 0 models.common.Concat [1] \n", - " 23 -1 1 1182720 models.common.C3 [512, 512, 1, False] \n", - " 24 [17, 20, 23] 1 615133 models.yolo.Segment [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], 32, 128, [128, 256, 512]]\n", - "Model summary: 225 layers, 7621277 parameters, 7621277 gradients, 26.6 GFLOPs\n", - "\n", - "Transferred 367/367 items from yolov5s-seg.pt\n", - "\u001b[34m\u001b[1mAMP: \u001b[0mchecks passed ✅\n", - "\u001b[34m\u001b[1moptimizer:\u001b[0m SGD(lr=0.01) with parameter groups 60 weight(decay=0.0), 63 weight(decay=0.0005), 63 bias\n", - "\u001b[34m\u001b[1malbumentations: \u001b[0mBlur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01), CLAHE(p=0.01, clip_limit=(1, 4.0), tile_grid_size=(8, 8))\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mScanning /content/datasets/coco128-seg/labels/train2017... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00<00:00, 1389.59it/s]\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mNew cache created: /content/datasets/coco128-seg/labels/train2017.cache\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mCaching images (0.1GB ram): 100% 128/128 [00:00<00:00, 238.86it/s]\n", - "\u001b[34m\u001b[1mval: \u001b[0mScanning /content/datasets/coco128-seg/labels/train2017.cache... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00 # 2. paste API key\n", - "python train.py --img 640 --epochs 3 --data coco128.yaml --weights yolov5s.pt # 3. train\n", - "```\n", - "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", - "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing)\n", - "\n", - "\n", - "\"Comet" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Lay2WsTjNJzP" - }, - "source": [ - "## ClearML Logging and Automation 🌟 NEW\n", - "\n", - "[ClearML](https://cutt.ly/yolov5-notebook-clearml) is completely integrated into YOLOv5 to track your experimentation, manage dataset versions and even remotely execute training runs. To enable ClearML (check cells above):\n", - "\n", - "- `pip install clearml`\n", - "- run `clearml-init` to connect to a ClearML server (**deploy your own [open-source server](https://github.com/allegroai/clearml-server)**, or use our [free hosted server](https://cutt.ly/yolov5-notebook-clearml))\n", - "\n", - "You'll get all the great expected features from an experiment manager: live updates, model upload, experiment comparison etc. but ClearML also tracks uncommitted changes and installed packages for example. Thanks to that ClearML Tasks (which is what we call experiments) are also reproducible on different machines! With only 1 extra line, we can schedule a YOLOv5 training task on a queue to be executed by any number of ClearML Agents (workers).\n", - "\n", - "You can use ClearML Data to version your dataset and then pass it to YOLOv5 simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration) for details!\n", - "\n", - "\n", - "\"ClearML" - ] + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "t6MPjfT5NrKQ" + }, + "source": [ + "
\n", + "\n", + " \n", + " \n", + "\n", + "\n", + "
\n", + " \"Run\n", + " \"Open\n", + " \"Open\n", + "
\n", + "\n", + "This YOLOv5 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7mGmQbAO5pQb" + }, + "source": [ + "# Setup\n", + "\n", + "Clone GitHub [repository](https://github.com/ultralytics/yolov5), install [dependencies](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) and check PyTorch and GPU." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "wbvMlHd_QwMG", + "outputId": "171b23f0-71b9-4cbf-b666-6fa2ecef70c8" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "-WPvRbS5Swl6" - }, - "source": [ - "## Local Logging\n", - "\n", - "Training results are automatically logged with [Tensorboard](https://www.tensorflow.org/tensorboard) and [CSV](https://github.com/ultralytics/yolov5/pull/4148) loggers to `runs/train`, with a new experiment directory created for each new training as `runs/train/exp2`, `runs/train/exp3`, etc.\n", - "\n", - "This directory contains train and val statistics, mosaics, labels, predictions and augmentated mosaics, as well as metrics and charts including precision-recall (PR) curves and confusion matrices. \n", - "\n", - "\"Local\n" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n" + ] }, { - "cell_type": "markdown", - "metadata": { - "id": "Zelyeqbyt3GD" - }, - "source": [ - "# Environments\n", - "\n", - "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):\n", - "\n", - "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", - "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)\n", - "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)\n", - "- **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) \"Docker\n" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Setup complete ✅ (2 CPUs, 12.7 GB RAM, 22.6/78.2 GB disk)\n" + ] + } + ], + "source": [ + "!git clone https://github.com/ultralytics/yolov5 # clone\n", + "%cd yolov5\n", + "%pip install -qr requirements.txt comet_ml # install\n", + "\n", + "import torch\n", + "\n", + "import utils\n", + "\n", + "display = utils.notebook_init() # checks" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4JnkELT0cIJg" + }, + "source": [ + "# 1. Predict\n", + "\n", + "`segment/predict.py` runs YOLOv5 instance segmentation inference on a variety of sources, downloading models automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases), and saving results to `runs/predict`. Example inference sources are:\n", + "\n", + "```shell\n", + "python segment/predict.py --source 0 # webcam\n", + " img.jpg # image \n", + " vid.mp4 # video\n", + " screen # screenshot\n", + " path/ # directory\n", + " 'path/*.jpg' # glob\n", + " 'https://youtu.be/LNwODJXcvt4' # YouTube\n", + " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "zR9ZbuQCH7FX", + "outputId": "3f67f1c7-f15e-4fa5-d251-967c3b77eaad" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "6Qu7Iesl0p54" - }, - "source": [ - "# Status\n", - "\n", - "![YOLOv5 CI](https://github.com/ultralytics/yolov3/actions/workflows/ci-testing.yml/badge.svg)\n", - "\n", - "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/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)), testing ([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.\n" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[34m\u001b[1msegment/predict: \u001b[0mweights=['yolov5s-seg.pt'], source=data/images, data=data/coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/predict-seg, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False, vid_stride=1, retina_masks=False\n", + "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "\n", + "Downloading https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt to yolov5s-seg.pt...\n", + "100% 14.9M/14.9M [00:01<00:00, 12.0MB/s]\n", + "\n", + "Fusing layers... \n", + "YOLOv5s-seg summary: 224 layers, 7611485 parameters, 0 gradients, 26.4 GFLOPs\n", + "image 1/2 /content/yolov5/data/images/bus.jpg: 640x480 4 persons, 1 bus, 18.2ms\n", + "image 2/2 /content/yolov5/data/images/zidane.jpg: 384x640 2 persons, 1 tie, 13.4ms\n", + "Speed: 0.5ms pre-process, 15.8ms inference, 18.5ms NMS per image at shape (1, 3, 640, 640)\n", + "Results saved to \u001b[1mruns/predict-seg/exp\u001b[0m\n" + ] + } + ], + "source": [ + "!python segment/predict.py --weights yolov5s-seg.pt --img 640 --conf 0.25 --source data/images\n", + "# display.Image(filename='runs/predict-seg/exp/zidane.jpg', width=600)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hkAzDWJ7cWTr" + }, + "source": [ + "        \n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0eq1SMWl6Sfn" + }, + "source": [ + "# 2. Validate\n", + "Validate a model's accuracy on the [COCO](https://cocodataset.org/#home) dataset's `val` or `test` splits. Models are downloaded automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases). To show results by class use the `--verbose` flag." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "WQPtK1QYVaD_", + "outputId": "9d751d8c-bee8-4339-cf30-9854ca530449" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "IEijrePND_2I" - }, - "source": [ - "# Appendix\n", - "\n", - "Additional content below." - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/coco2017labels-segments.zip ...\n", + "Downloading http://images.cocodataset.org/zips/val2017.zip ...\n", + "######################################################################## 100.0%\n", + "######################################################################## 100.0%\n" + ] + } + ], + "source": [ + "# Download COCO val\n", + "!bash data/scripts/get_coco.sh --val --segments # download (780M - 5000 images)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "X58w8JLpMnjH", + "outputId": "a140d67a-02da-479e-9ddb-7d54bf9e407a" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "GMusP4OAxFu6" - }, - "outputs": [], - "source": [ - "# YOLOv5 PyTorch HUB Inference (DetectionModels only)\n", - "import torch\n", - "\n", - "model = torch.hub.load('ultralytics/yolov5', 'yolov5s-seg') # yolov5n - yolov5x6 or custom\n", - "im = 'https://ultralytics.com/images/zidane.jpg' # file, Path, PIL.Image, OpenCV, nparray, list\n", - "results = model(im) # inference\n", - "results.print() # or .show(), .save(), .crop(), .pandas(), etc." - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[34m\u001b[1msegment/val: \u001b[0mdata=/content/yolov5/data/coco.yaml, weights=['yolov5s-seg.pt'], batch_size=32, imgsz=640, conf_thres=0.001, iou_thres=0.6, max_det=300, task=val, device=, workers=8, single_cls=False, augment=False, verbose=False, save_txt=False, save_hybrid=False, save_conf=False, save_json=False, project=runs/val-seg, name=exp, exist_ok=False, half=True, dnn=False\n", + "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "\n", + "Fusing layers... \n", + "YOLOv5s-seg summary: 224 layers, 7611485 parameters, 0 gradients, 26.4 GFLOPs\n", + "\u001b[34m\u001b[1mval: \u001b[0mScanning /content/datasets/coco/val2017... 4952 images, 48 backgrounds, 0 corrupt: 100% 5000/5000 [00:03<00:00, 1361.31it/s]\n", + "\u001b[34m\u001b[1mval: \u001b[0mNew cache created: /content/datasets/coco/val2017.cache\n", + " Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100% 157/157 [01:54<00:00, 1.37it/s]\n", + " all 5000 36335 0.673 0.517 0.566 0.373 0.672 0.49 0.532 0.319\n", + "Speed: 0.6ms pre-process, 4.4ms inference, 2.9ms NMS per image at shape (32, 3, 640, 640)\n", + "Results saved to \u001b[1mruns/val-seg/exp\u001b[0m\n" + ] } - ], - "metadata": { - "accelerator": "GPU", + ], + "source": [ + "# Validate YOLOv5s-seg on COCO val\n", + "!python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 --half" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZY2VXXXu74w5" + }, + "source": [ + "# 3. Train\n", + "\n", + "

\n", + "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", + "

\n", + "\n", + "Train a YOLOv5s-seg model on the [COCO128](https://www.kaggle.com/ultralytics/coco128) dataset with `--data coco128-seg.yaml`, starting from pretrained `--weights yolov5s-seg.pt`, or from randomly initialized `--weights '' --cfg yolov5s-seg.yaml`.\n", + "\n", + "- **Pretrained [Models](https://github.com/ultralytics/yolov5/tree/master/models)** are downloaded\n", + "automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases)\n", + "- **[Datasets](https://github.com/ultralytics/yolov5/tree/master/data)** available for autodownload include: [COCO](https://github.com/ultralytics/yolov5/blob/master/data/coco.yaml), [COCO128](https://github.com/ultralytics/yolov5/blob/master/data/coco128.yaml), [VOC](https://github.com/ultralytics/yolov5/blob/master/data/VOC.yaml), [Argoverse](https://github.com/ultralytics/yolov5/blob/master/data/Argoverse.yaml), [VisDrone](https://github.com/ultralytics/yolov5/blob/master/data/VisDrone.yaml), [GlobalWheat](https://github.com/ultralytics/yolov5/blob/master/data/GlobalWheat2020.yaml), [xView](https://github.com/ultralytics/yolov5/blob/master/data/xView.yaml), [Objects365](https://github.com/ultralytics/yolov5/blob/master/data/Objects365.yaml), [SKU-110K](https://github.com/ultralytics/yolov5/blob/master/data/SKU-110K.yaml).\n", + "- **Training Results** are saved to `runs/train-seg/` with incrementing run directories, i.e. `runs/train-seg/exp2`, `runs/train-seg/exp3` etc.\n", + "

\n", + "\n", + "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic.\n", + "\n", + "## Train on Custom Data with Roboflow 🌟 NEW\n", + "\n", + "[Roboflow](https://roboflow.com/?ref=ultralytics) enables you to easily **organize, label, and prepare** a high quality dataset with your own custom data. Roboflow also makes it easy to establish an active learning pipeline, collaborate with your team on dataset improvement, and integrate directly into your model building workflow with the `roboflow` pip package.\n", + "\n", + "- Custom Training Example: [https://blog.roboflow.com/train-yolov5-instance-segmentation-custom-dataset/](https://blog.roboflow.com/train-yolov5-instance-segmentation-custom-dataset/?ref=ultralytics)\n", + "- Custom Training Notebook: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1JTz7kpmHsg-5qwVz2d2IH3AaenI1tv0N?usp=sharing)\n", + "
\n", + "\n", + "

Label images lightning fast (including with model-assisted labeling)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "i3oKtE4g-aNn" + }, + "outputs": [], + "source": [ + "# @title Select YOLOv5 🚀 logger {run: 'auto'}\n", + "logger = \"Comet\" # @param ['Comet', 'ClearML', 'TensorBoard']\n", + "\n", + "if logger == \"Comet\":\n", + " %pip install -q comet_ml\n", + " import comet_ml\n", + "\n", + " comet_ml.init()\n", + "elif logger == \"ClearML\":\n", + " %pip install -q clearml\n", + " import clearml\n", + "\n", + " clearml.browser_login()\n", + "elif logger == \"TensorBoard\":\n", + " %load_ext tensorboard\n", + " %tensorboard --logdir runs/train" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { "colab": { - "name": "YOLOv5 Segmentation Tutorial", - "provenance": [], - "toc_visible": true - }, - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" + "base_uri": "https://localhost:8080/" }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.12" + "id": "1NcFxRcFdJ_O", + "outputId": "3a3e0cf7-e79c-47a5-c8e7-2d26eeeab988" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[34m\u001b[1msegment/train: \u001b[0mweights=yolov5s-seg.pt, cfg=, data=coco128-seg.yaml, hyp=data/hyps/hyp.scratch-low.yaml, epochs=3, batch_size=16, imgsz=640, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, noplots=False, evolve=None, bucket=, cache=ram, image_weights=False, device=, multi_scale=False, single_cls=False, optimizer=SGD, sync_bn=False, workers=8, project=runs/train-seg, name=exp, exist_ok=False, quad=False, cos_lr=False, label_smoothing=0.0, patience=100, freeze=[0], save_period=-1, seed=0, local_rank=-1, mask_ratio=4, no_overlap=False\n", + "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", + "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", + "\n", + "\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0\n", + "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train-seg', view at http://localhost:6006/\n", + "\n", + "Dataset not found ⚠️, missing paths ['/content/datasets/coco128-seg/images/train2017']\n", + "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/coco128-seg.zip to coco128-seg.zip...\n", + "100% 6.79M/6.79M [00:01<00:00, 6.73MB/s]\n", + "Dataset download success ✅ (1.9s), saved to \u001b[1m/content/datasets\u001b[0m\n", + "\n", + " from n params module arguments \n", + " 0 -1 1 3520 models.common.Conv [3, 32, 6, 2, 2] \n", + " 1 -1 1 18560 models.common.Conv [32, 64, 3, 2] \n", + " 2 -1 1 18816 models.common.C3 [64, 64, 1] \n", + " 3 -1 1 73984 models.common.Conv [64, 128, 3, 2] \n", + " 4 -1 2 115712 models.common.C3 [128, 128, 2] \n", + " 5 -1 1 295424 models.common.Conv [128, 256, 3, 2] \n", + " 6 -1 3 625152 models.common.C3 [256, 256, 3] \n", + " 7 -1 1 1180672 models.common.Conv [256, 512, 3, 2] \n", + " 8 -1 1 1182720 models.common.C3 [512, 512, 1] \n", + " 9 -1 1 656896 models.common.SPPF [512, 512, 5] \n", + " 10 -1 1 131584 models.common.Conv [512, 256, 1, 1] \n", + " 11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 12 [-1, 6] 1 0 models.common.Concat [1] \n", + " 13 -1 1 361984 models.common.C3 [512, 256, 1, False] \n", + " 14 -1 1 33024 models.common.Conv [256, 128, 1, 1] \n", + " 15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 16 [-1, 4] 1 0 models.common.Concat [1] \n", + " 17 -1 1 90880 models.common.C3 [256, 128, 1, False] \n", + " 18 -1 1 147712 models.common.Conv [128, 128, 3, 2] \n", + " 19 [-1, 14] 1 0 models.common.Concat [1] \n", + " 20 -1 1 296448 models.common.C3 [256, 256, 1, False] \n", + " 21 -1 1 590336 models.common.Conv [256, 256, 3, 2] \n", + " 22 [-1, 10] 1 0 models.common.Concat [1] \n", + " 23 -1 1 1182720 models.common.C3 [512, 512, 1, False] \n", + " 24 [17, 20, 23] 1 615133 models.yolo.Segment [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], 32, 128, [128, 256, 512]]\n", + "Model summary: 225 layers, 7621277 parameters, 7621277 gradients, 26.6 GFLOPs\n", + "\n", + "Transferred 367/367 items from yolov5s-seg.pt\n", + "\u001b[34m\u001b[1mAMP: \u001b[0mchecks passed ✅\n", + "\u001b[34m\u001b[1moptimizer:\u001b[0m SGD(lr=0.01) with parameter groups 60 weight(decay=0.0), 63 weight(decay=0.0005), 63 bias\n", + "\u001b[34m\u001b[1malbumentations: \u001b[0mBlur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01), CLAHE(p=0.01, clip_limit=(1, 4.0), tile_grid_size=(8, 8))\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mScanning /content/datasets/coco128-seg/labels/train2017... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00<00:00, 1389.59it/s]\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mNew cache created: /content/datasets/coco128-seg/labels/train2017.cache\n", + "\u001b[34m\u001b[1mtrain: \u001b[0mCaching images (0.1GB ram): 100% 128/128 [00:00<00:00, 238.86it/s]\n", + "\u001b[34m\u001b[1mval: \u001b[0mScanning /content/datasets/coco128-seg/labels/train2017.cache... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00 # 2. paste API key\n", + "python train.py --img 640 --epochs 3 --data coco128.yaml --weights yolov5s.pt # 3. train\n", + "```\n", + "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing)\n", + "\n", + "\n", + "\"Comet" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Lay2WsTjNJzP" + }, + "source": [ + "## ClearML Logging and Automation 🌟 NEW\n", + "\n", + "[ClearML](https://cutt.ly/yolov5-notebook-clearml) is completely integrated into YOLOv5 to track your experimentation, manage dataset versions and even remotely execute training runs. To enable ClearML (check cells above):\n", + "\n", + "- `pip install clearml`\n", + "- run `clearml-init` to connect to a ClearML server (**deploy your own [open-source server](https://github.com/allegroai/clearml-server)**, or use our [free hosted server](https://cutt.ly/yolov5-notebook-clearml))\n", + "\n", + "You'll get all the great expected features from an experiment manager: live updates, model upload, experiment comparison etc. but ClearML also tracks uncommitted changes and installed packages for example. Thanks to that ClearML Tasks (which is what we call experiments) are also reproducible on different machines! With only 1 extra line, we can schedule a YOLOv5 training task on a queue to be executed by any number of ClearML Agents (workers).\n", + "\n", + "You can use ClearML Data to version your dataset and then pass it to YOLOv5 simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration) for details!\n", + "\n", + "\n", + "\"ClearML" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-WPvRbS5Swl6" + }, + "source": [ + "## Local Logging\n", + "\n", + "Training results are automatically logged with [Tensorboard](https://www.tensorflow.org/tensorboard) and [CSV](https://github.com/ultralytics/yolov5/pull/4148) loggers to `runs/train`, with a new experiment directory created for each new training as `runs/train/exp2`, `runs/train/exp3`, etc.\n", + "\n", + "This directory contains train and val statistics, mosaics, labels, predictions and augmentated mosaics, as well as metrics and charts including precision-recall (PR) curves and confusion matrices. \n", + "\n", + "\"Local\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Zelyeqbyt3GD" + }, + "source": [ + "# Environments\n", + "\n", + "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):\n", + "\n", + "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", + "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)\n", + "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)\n", + "- **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) \"Docker\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6Qu7Iesl0p54" + }, + "source": [ + "# Status\n", + "\n", + "![YOLOv5 CI](https://github.com/ultralytics/yolov3/actions/workflows/ci-testing.yml/badge.svg)\n", + "\n", + "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/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)), testing ([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.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IEijrePND_2I" + }, + "source": [ + "# Appendix\n", + "\n", + "Additional content below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GMusP4OAxFu6" + }, + "outputs": [], + "source": [ + "# YOLOv5 PyTorch HUB Inference (DetectionModels only)\n", + "\n", + "model = torch.hub.load(\"ultralytics/yolov5\", \"yolov5s-seg\") # yolov5n - yolov5x6 or custom\n", + "im = \"https://ultralytics.com/images/zidane.jpg\" # file, Path, PIL.Image, OpenCV, nparray, list\n", + "results = model(im) # inference\n", + "results.print() # or .show(), .save(), .crop(), .pandas(), etc." + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "name": "YOLOv5 Segmentation Tutorial", + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 0 + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 0 } From 79b3c95066ba88e8e58d98e40e2839395ff5ad51 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 20 Aug 2024 16:36:27 +0800 Subject: [PATCH 1107/1185] YOLO Vision 2024 updates https://ultralytics.com/events/yolovision (#2268) Refactor code for speed and clarity From f3309e790c4d1bbac28bb1312dfa447483c5ecf3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Aug 2024 16:36:41 +0800 Subject: [PATCH 1108/1185] Bump contributor-assistant/github-action from 2.4.0 to 2.5.1 in /.github/workflows (#2269) * Bump contributor-assistant/github-action in /.github/workflows Bumps [contributor-assistant/github-action](https://github.com/contributor-assistant/github-action) from 2.4.0 to 2.5.1. - [Release notes](https://github.com/contributor-assistant/github-action/releases) - [Commits](https://github.com/contributor-assistant/github-action/compare/v2.4.0...v2.5.1) --- updated-dependencies: - dependency-name: contributor-assistant/github-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Auto-format by https://ultralytics.com/actions --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: UltralyticsAssistant --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index fa89a80897..53fbf400ef 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -26,7 +26,7 @@ jobs: steps: - name: CLA Assistant if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I sign the CLA') || github.event_name == 'pull_request_target' - uses: contributor-assistant/github-action@v2.4.0 + uses: contributor-assistant/github-action@v2.5.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Must be repository secret PAT From 89fe25978de16b124d68b48a2a4ce9025ab0f4ac Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 25 Aug 2024 05:45:19 +0800 Subject: [PATCH 1109/1185] Apply Ruff Docstring reformat (#2273) * Apply Ruff Docstring reformat * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: UltralyticsAssistant --- export.py | 1 + models/common.py | 15 ++++++++++----- models/experimental.py | 3 ++- utils/activations.py | 12 ++++++++---- utils/augmentations.py | 7 ++++--- utils/callbacks.py | 1 - utils/dataloaders.py | 7 ++++--- utils/general.py | 5 ++--- utils/loggers/__init__.py | 3 ++- utils/loggers/clearml/clearml_utils.py | 6 +++--- utils/loggers/wandb/wandb_utils.py | 12 ++++++------ utils/metrics.py | 8 +++----- utils/segment/augmentations.py | 4 ++-- utils/segment/general.py | 3 --- utils/triton.py | 3 +-- 15 files changed, 48 insertions(+), 42 deletions(-) diff --git a/export.py b/export.py index 5584601559..182f544c69 100644 --- a/export.py +++ b/export.py @@ -456,6 +456,7 @@ def transform_fn(data_item): Quantization transform function. Extracts and preprocess input data from dataloader item for quantization. + Parameters: data_item: Tuple with data item produced by DataLoader during iteration Returns: diff --git a/models/common.py b/models/common.py index 74c7b0c9c9..295a04d933 100644 --- a/models/common.py +++ b/models/common.py @@ -102,7 +102,8 @@ class TransformerLayer(nn.Module): # Transformer layer https://arxiv.org/abs/2010.11929 (LayerNorm layers removed for better performance) def __init__(self, c, num_heads): """Initializes a Transformer layer as per https://arxiv.org/abs/2010.11929, sans LayerNorm, with specified - embedding dimension and number of heads.""" + embedding dimension and number of heads. + """ super().__init__() self.q = nn.Linear(c, c, bias=False) self.k = nn.Linear(c, c, bias=False) @@ -164,7 +165,8 @@ class BottleneckCSP(nn.Module): # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion """Initializes CSP Bottleneck with channel in/out, optional shortcut, groups, expansion; see - https://github.com/WongKinYiu/CrossStagePartialNetworks.""" + https://github.com/WongKinYiu/CrossStagePartialNetworks. + """ super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, 1, 1) @@ -323,7 +325,8 @@ class GhostConv(nn.Module): # Ghost Convolution https://github.com/huawei-noah/ghostnet def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups """Initializes GhostConv with in/out channels, kernel size, stride, groups; see - https://github.com/huawei-noah/ghostnet.""" + https://github.com/huawei-noah/ghostnet. + """ super().__init__() c_ = c2 // 2 # hidden channels self.cv1 = Conv(c1, c_, k, s, None, g, act=act) @@ -339,7 +342,8 @@ class GhostBottleneck(nn.Module): # Ghost Bottleneck https://github.com/huawei-noah/ghostnet def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride """Initializes GhostBottleneck module with in/out channels, kernel size, and stride; see - https://github.com/huawei-noah/ghostnet.""" + https://github.com/huawei-noah/ghostnet. + """ super().__init__() c_ = c2 // 2 self.conv = nn.Sequential( @@ -786,7 +790,8 @@ def _apply(self, fn): @smart_inference_mode() def forward(self, ims, size=640, augment=False, profile=False): """Performs inference on various input sources with optional augmentation and profiling; see - `https://ultralytics.com`.""" + `https://ultralytics.com`. + """ # file: ims = 'data/images/zidane.jpg' # str or PosixPath # URI: = 'https://ultralytics.com/images/zidane.jpg' # OpenCV: = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(640,1280,3) diff --git a/models/experimental.py b/models/experimental.py index fba1ed3239..305434ec87 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -45,7 +45,8 @@ class MixConv2d(nn.Module): # Mixed Depth-wise Conv https://arxiv.org/abs/1907.09595 def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): # ch_in, ch_out, kernel, stride, ch_strategy """Initializes MixConv2d with mixed depth-wise convolution layers; details at - https://arxiv.org/abs/1907.09595.""" + https://arxiv.org/abs/1907.09595. + """ super().__init__() n = len(k) # number of convolutions if equal_ch: # equal c_ per group diff --git a/utils/activations.py b/utils/activations.py index 457de4ab54..95661bf1dd 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -11,7 +11,8 @@ class SiLU(nn.Module): @staticmethod def forward(x): """Applies the SiLU activation function, as detailed in https://arxiv.org/pdf/1606.08415.pdf, on input tensor - `x`.""" + `x`. + """ return x * torch.sigmoid(x) @@ -67,7 +68,8 @@ class FReLU(nn.Module): # FReLU activation https://arxiv.org/abs/2007.11824 def __init__(self, c1, k=3): # ch_in, kernel """Initializes FReLU with specified channel size and kernel, implementing activation from - https://arxiv.org/abs/2007.11824.""" + https://arxiv.org/abs/2007.11824. + """ super().__init__() self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1, bias=False) self.bn = nn.BatchNorm2d(c1) @@ -85,7 +87,8 @@ class AconC(nn.Module): def __init__(self, c1): """Initializes ACON activation with learnable parameters p1, p2, and beta as per - https://arxiv.org/pdf/2009.04759.pdf.""" + https://arxiv.org/pdf/2009.04759.pdf. + """ super().__init__() self.p1 = nn.Parameter(torch.randn(1, c1, 1, 1)) self.p2 = nn.Parameter(torch.randn(1, c1, 1, 1)) @@ -93,7 +96,8 @@ def __init__(self, c1): def forward(self, x): """Applies a parametric activation function to tensor x; see https://arxiv.org/pdf/2009.04759.pdf for - details.""" + details. + """ dpx = (self.p1 - self.p2) * x return dpx * torch.sigmoid(self.beta * dpx) + self.p2 * x diff --git a/utils/augmentations.py b/utils/augmentations.py index d65f2ea204..539b55304a 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -156,7 +156,6 @@ def random_perspective( ): # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(0.1, 0.1), scale=(0.9, 1.1), shear=(-10, 10)) # targets = [cls, xyxy] - """Applies a random perspective transformation to an image and its bounding boxes for data augmentation.""" height = im.shape[0] + border[0] * 2 # shape(h,w,c) width = im.shape[1] + border[1] * 2 @@ -244,7 +243,8 @@ def random_perspective( def copy_paste(im, labels, segments, p=0.5): """Applies Copy-Paste augmentation (https://arxiv.org/abs/2012.07177) on image, labels (nx5 np.array(cls, xyxy)), - and segments.""" + and segments. + """ n = len(segments) if p and n: h, w, c = im.shape # height, width, channels @@ -294,7 +294,8 @@ def cutout(im, labels, p=0.5): def mixup(im, labels, im2, labels2): """Applies MixUp augmentation by blending images and labels; see https://arxiv.org/pdf/1710.09412.pdf for - details.""" + details. + """ r = np.random.beta(32.0, 32.0) # mixup ratio, alpha=beta=32.0 im = (im * r + im2 * (1 - r)).astype(np.uint8) labels = np.concatenate((labels, labels2), 0) diff --git a/utils/callbacks.py b/utils/callbacks.py index 4545d3f64f..e4b62c2f25 100644 --- a/utils/callbacks.py +++ b/utils/callbacks.py @@ -64,7 +64,6 @@ def run(self, hook, *args, thread=False, **kwargs): thread: (boolean) Run callbacks in daemon thread kwargs: Keyword Arguments to receive from YOLOv3 """ - assert hook in self._callbacks, f"hook '{hook}' not found in callbacks {self._callbacks}" for logger in self._callbacks[hook]: if thread: diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 28cf40774e..96fe83c15e 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -1053,7 +1053,8 @@ def extract_boxes(path=DATASETS_DIR / "coco128"): # from utils.dataloaders impo def autosplit(path=DATASETS_DIR / "coco128/images", weights=(0.9, 0.1, 0.0), annotated_only=False): """Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files Usage: from utils.dataloaders import *; autosplit() - Arguments + + Arguments: path: Path to images directory weights: Train, val, test weights (list, tuple) annotated_only: Only use images with an annotated txt file @@ -1132,7 +1133,7 @@ class HUBDatasetStats: """ Class for generating HUB dataset JSON and `-hub` dataset directory. - Arguments + Arguments: path: Path to data.yaml or data.zip (with data.yaml inside data.zip) autodownload: Attempt to download dataset if not found locally @@ -1265,7 +1266,7 @@ class ClassificationDataset(torchvision.datasets.ImageFolder): """ YOLOv3 Classification Dataset. - Arguments + Arguments: root: Dataset path transform: torchvision transforms, used by default album_transform: Albumentations transforms, used if installed diff --git a/utils/general.py b/utils/general.py index 209350eb26..afee396906 100644 --- a/utils/general.py +++ b/utils/general.py @@ -515,7 +515,6 @@ def check_font(font=FONT, progress=False): def check_dataset(data, autodownload=True): """Verifies and prepares dataset by downloading if absent, checking, and unzipping; supports auto-downloading.""" - # Download (optional) extract_dir = "" if isinstance(data, (str, Path)) and (is_zipfile(data) or is_tarfile(data)): @@ -704,7 +703,8 @@ def clean_str(s): def one_cycle(y1=0.0, y2=1.0, steps=100): """Generates a lambda for a sinusoidal ramp from y1 to y2 over 'steps'; usage: `lambda x: ((1 - math.cos(x * - math.pi / steps)) / 2) * (y2 - y1) + y1`.""" + math.pi / steps)) / 2) * (y2 - y1) + y1`. + """ return lambda x: ((1 - math.cos(x * math.pi / steps)) / 2) * (y2 - y1) + y1 @@ -1019,7 +1019,6 @@ def non_max_suppression( Returns: list of detections, on (n,6) tensor per image [xyxy, conf, cls] """ - # Checks assert 0 <= conf_thres <= 1, f"Invalid Confidence threshold {conf_thres}, valid values are between 0.0 and 1.0" assert 0 <= iou_thres <= 1, f"Invalid IoU {iou_thres}, valid values are between 0.0 and 1.0" diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index debc3238e0..fd9f704a88 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -340,7 +340,8 @@ class GenericLogger: """ YOLOv3 General purpose logger for non-task specific logging Usage: from utils.loggers import GenericLogger; logger = GenericLogger(...) - Arguments + + Arguments: opt: Run arguments console_logger: Console logger include: loggers to include diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py index 6d69a74558..f4841f0376 100644 --- a/utils/loggers/clearml/clearml_utils.py +++ b/utils/loggers/clearml/clearml_utils.py @@ -78,7 +78,7 @@ def __init__(self, opt, hyp): - Initialize ClearML Task, this object will capture the experiment - Upload dataset version to ClearML Data if opt.upload_dataset is True - arguments: + Arguments: opt (namespace) -- Commandline arguments for this run hyp (dict) -- Hyperparameters for this run @@ -129,7 +129,7 @@ def log_debug_samples(self, files, title="Debug Samples"): """ Log files (images) as debug samples in the ClearML task. - arguments: + Arguments: files (List(PosixPath)) a list of file paths in PosixPath format title (str) A title that groups together images with the same values """ @@ -145,7 +145,7 @@ def log_image_with_boxes(self, image_path, boxes, class_names, image, conf_thres """ Draw the bounding boxes on a single image and report the result as a ClearML debug sample. - arguments: + Arguments: image_path (PosixPath) the path the original image file boxes (list): list of scaled predictions in the format - [xmin, ymin, xmax, ymax, confidence, class] class_names (dict): dict containing mapping of class int to class name diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py index a3450d5f1f..059c0a7ef6 100644 --- a/utils/loggers/wandb/wandb_utils.py +++ b/utils/loggers/wandb/wandb_utils.py @@ -49,7 +49,7 @@ def __init__(self, opt, run_id=None, job_type="Training"): - Upload dataset if opt.upload_dataset is True - Setup training processes if job_type is 'Training' - arguments: + Arguments: opt (namespace) -- Commandline arguments for this run run_id (str) -- Run ID of W&B run to be resumed job_type (str) -- To set the job_type for this run @@ -90,7 +90,7 @@ def setup_training(self, opt): - Update data_dict, to contain info of previous run if resumed and the paths of dataset artifact if downloaded - Setup log_dict, initialize bbox_interval - arguments: + Arguments: opt (namespace) -- commandline arguments for this run """ @@ -120,7 +120,7 @@ def log_model(self, path, opt, epoch, fitness_score, best_model=False): """ Log the model checkpoint as W&B artifact. - arguments: + Arguments: path (Path) -- Path of directory containing the checkpoints opt (namespace) -- Command line arguments for this run epoch (int) -- Current epoch number @@ -159,7 +159,7 @@ def log(self, log_dict): """ Save the metrics to the logging dictionary. - arguments: + Arguments: log_dict (Dict) -- metrics/media to be logged in current step """ if self.wandb_run: @@ -170,7 +170,7 @@ def end_epoch(self): """ Commit the log_dict, model artifacts and Tables to W&B and flush the log_dict. - arguments: + Arguments: best_result (boolean): Boolean representing if the result of this evaluation is best or not """ if self.wandb_run: @@ -197,7 +197,7 @@ def finish_run(self): @contextmanager def all_logging_disabled(highest_level=logging.CRITICAL): - """source - https://gist.github.com/simon-weber/7853144 + """Source - https://gist.github.com/simon-weber/7853144 A context manager that will prevent any logging messages triggered during the body from being processed. :param highest_level: the maximum logging level in use. This would only need to be changed if a custom level greater than CRITICAL is defined. diff --git a/utils/metrics.py b/utils/metrics.py index 6d78c5784f..0323398ce5 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -41,7 +41,6 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir=".", names # Returns The average precision as computed in py-faster-rcnn. """ - # Sort by objectness i = np.argsort(-conf) tp, conf, pred_cls = tp[i], conf[i], pred_cls[i] @@ -103,7 +102,6 @@ def compute_ap(recall, precision): # Returns Average precision, precision curve, recall curve """ - # Append sentinel values to beginning and end mrec = np.concatenate(([0.0], recall, [1.0])) mpre = np.concatenate(([1.0], precision, [0.0])) @@ -137,6 +135,7 @@ def process_batch(self, detections, labels): Return intersection-over-union (Jaccard index) of boxes. Both sets of boxes are expected to be in (x1, y1, x2, y2) format. + Arguments: detections (Array[N, 6]), x1, y1, x2, y2, conf, class labels (Array[M, 5]), class, x1, y1, x2, y2 @@ -227,7 +226,6 @@ def print(self): def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7): """Calculates IoU, GIoU, DIoU, CIoU between two bounding boxes, supporting `xywh` and `xyxy` formats.""" - # Get the coordinates of bounding boxes if xywh: # transform from xywh to xyxy (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1) @@ -273,14 +271,15 @@ def box_iou(box1, box2, eps=1e-7): Return intersection-over-union (Jaccard index) of boxes. Both sets of boxes are expected to be in (x1, y1, x2, y2) format. + Arguments: box1 (Tensor[N, 4]) box2 (Tensor[M, 4]) + Returns: iou (Tensor[N, M]): the NxM matrix containing the pairwise IoU values for every element in boxes1 and boxes2 """ - # inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2) (a1, a2), (b1, b2) = box1.unsqueeze(1).chunk(2, 2), box2.unsqueeze(0).chunk(2, 2) inter = (torch.min(a2, b2) - torch.max(a1, b1)).clamp(0).prod(2) @@ -298,7 +297,6 @@ def bbox_ioa(box1, box2, eps=1e-7): box2: np.array of shape(nx4) returns: np.array of shape(n) """ - # Get the coordinates of bounding boxes b1_x1, b1_y1, b1_x2, b1_y2 = box1 b2_x1, b2_y1, b2_x2, b2_y2 = box2.T diff --git a/utils/segment/augmentations.py b/utils/segment/augmentations.py index ced82d723d..74e1653925 100644 --- a/utils/segment/augmentations.py +++ b/utils/segment/augmentations.py @@ -13,7 +13,8 @@ def mixup(im, labels, segments, im2, labels2, segments2): """Applies MixUp augmentation by blending pairs of images, labels, and segments; see - https://arxiv.org/pdf/1710.09412.pdf.""" + https://arxiv.org/pdf/1710.09412.pdf. + """ r = np.random.beta(32.0, 32.0) # mixup ratio, alpha=beta=32.0 im = (im * r + im2 * (1 - r)).astype(np.uint8) labels = np.concatenate((labels, labels2), 0) @@ -26,7 +27,6 @@ def random_perspective( ): # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) # targets = [cls, xyxy] - """Applies random perspective augmentation including rotation, translation, scale, and shear transformations.""" height = im.shape[0] + border[0] * 2 # shape(h,w,c) width = im.shape[1] + border[1] * 2 diff --git a/utils/segment/general.py b/utils/segment/general.py index c112df13ff..9226065bb5 100644 --- a/utils/segment/general.py +++ b/utils/segment/general.py @@ -14,7 +14,6 @@ def crop_mask(masks, boxes): - masks should be a size [n, h, w] tensor of masks - boxes should be a size [n, 4] tensor of bbox coords in relative point form """ - n, h, w = masks.shape x1, y1, x2, y2 = torch.chunk(boxes[:, :, None], 4, 1) # x1 shape(1,1,n) r = torch.arange(w, device=masks.device, dtype=x1.dtype)[None, None, :] # rows shape(1,w,1) @@ -33,7 +32,6 @@ def process_mask_upsample(protos, masks_in, bboxes, shape): return: h, w, n """ - c, mh, mw = protos.shape # CHW masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw) masks = F.interpolate(masks[None], shape, mode="bilinear", align_corners=False)[0] # CHW @@ -51,7 +49,6 @@ def process_mask(protos, masks_in, bboxes, shape, upsample=False): return: h, w, n """ - c, mh, mw = protos.shape # CHW ih, iw = shape masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw) # CHW diff --git a/utils/triton.py b/utils/triton.py index 529f99743d..9902dcbf47 100644 --- a/utils/triton.py +++ b/utils/triton.py @@ -17,10 +17,9 @@ class TritonRemoteModel: def __init__(self, url: str): """ - Keyword arguments: + Keyword Arguments: url: Fully qualified address of the Triton server - for e.g. grpc://localhost:8000 """ - parsed_url = urlparse(url) if parsed_url.scheme == "grpc": from tritonclient.grpc import InferenceServerClient, InferInput From 8dd7e31c300ec36a25bdb7d772eb814e66535081 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 26 Aug 2024 01:20:41 +0800 Subject: [PATCH 1110/1185] Create merge-main-into-prs.yml (#2274) * Create merge-main-into-prs.yml * Update merge-main-into-prs.yml --- .github/workflows/merge-main-into-prs.yml | 74 +++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 .github/workflows/merge-main-into-prs.yml diff --git a/.github/workflows/merge-main-into-prs.yml b/.github/workflows/merge-main-into-prs.yml new file mode 100644 index 0000000000..c0c13896d0 --- /dev/null +++ b/.github/workflows/merge-main-into-prs.yml @@ -0,0 +1,74 @@ +# Ultralytics YOLO 🚀, AGPL-3.0 license +# Automatically merges repository 'main' branch into all open PRs to keep them up-to-date +# Action runs on updates to main branch so when one PR merges to main all others update + +name: Merge main into PRs + +on: + workflow_dispatch: + # push: + # branches: + # - ${{ github.event.repository.default_branch }} + +jobs: + Merge: + if: github.repository == 'ultralytics/yolov3' + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-python@v5 + with: + python-version: "3.x" + cache: "pip" + - name: Install requirements + run: | + pip install pygithub + - name: Merge default branch into PRs + shell: python + run: | + from github import Github + import os + + g = Github(os.getenv('GITHUB_TOKEN')) + repo = g.get_repo(os.getenv('GITHUB_REPOSITORY')) + + # Fetch the default branch name + default_branch_name = repo.default_branch + default_branch = repo.get_branch(default_branch_name) + + print(f"Default branch for this repository is: {default_branch_name}") + + open_pulls = repo.get_pulls(state='open', sort='created') + for pr in open_pulls: + try: + # Get full names for repositories and branches + base_repo_name = repo.full_name + head_repo_name = pr.head.repo.full_name + base_branch_name = pr.base.ref + head_branch_name = pr.head.ref + + # Check if PR is behind the default branch + comparison = repo.compare(default_branch.commit.sha, pr.head.sha) + + if comparison.behind_by > 0: + print(f"PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}) is behind {default_branch_name} by {comparison.behind_by} commit(s).") + + # Attempt to update the branch + try: + success = pr.update_branch() + assert success, "Branch update failed" + print(f"Successfully merged '{default_branch_name}' into PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}).") + except Exception as update_error: + print(f"Could not update PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}): {update_error}") + print("This might be due to branch protection rules or insufficient permissions.") + else: + print(f"PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}) is up to date with {default_branch_name}.") + except Exception as e: + print(f"Could not process PR #{pr.number}: {e}") + + env: + GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} From d02dedf87d0e50221e8afa1202d7024527ea866b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 26 Aug 2024 01:28:17 +0800 Subject: [PATCH 1111/1185] Update merge-main-into-prs.yml (#2275) * Update merge-main-into-prs.yml * Update merge-main-into-prs.yml * Update merge-main-into-prs.yml * Update merge-main-into-prs.yml --- .github/workflows/merge-main-into-prs.yml | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/.github/workflows/merge-main-into-prs.yml b/.github/workflows/merge-main-into-prs.yml index c0c13896d0..db6a180295 100644 --- a/.github/workflows/merge-main-into-prs.yml +++ b/.github/workflows/merge-main-into-prs.yml @@ -39,10 +39,7 @@ jobs: default_branch_name = repo.default_branch default_branch = repo.get_branch(default_branch_name) - print(f"Default branch for this repository is: {default_branch_name}") - - open_pulls = repo.get_pulls(state='open', sort='created') - for pr in open_pulls: + for pr in repo.get_pulls(state='open', sort='created'): try: # Get full names for repositories and branches base_repo_name = repo.full_name @@ -54,21 +51,21 @@ jobs: comparison = repo.compare(default_branch.commit.sha, pr.head.sha) if comparison.behind_by > 0: - print(f"PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}) is behind {default_branch_name} by {comparison.behind_by} commit(s).") + print(f"⚠️ PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}) is behind {default_branch_name} by {comparison.behind_by} commit(s).") # Attempt to update the branch try: success = pr.update_branch() assert success, "Branch update failed" - print(f"Successfully merged '{default_branch_name}' into PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}).") + print(f"✅ Successfully merged '{default_branch_name}' into PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}).") except Exception as update_error: - print(f"Could not update PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}): {update_error}") - print("This might be due to branch protection rules or insufficient permissions.") + print(f"❌ Could not update PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}): {update_error}") + print(" This might be due to branch protection rules or insufficient permissions.") else: - print(f"PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}) is up to date with {default_branch_name}.") + print(f"✅ PR #{pr.number} ({head_repo_name}:{head_branch_name} -> {base_repo_name}:{base_branch_name}) is up to date with {default_branch_name}.") except Exception as e: - print(f"Could not process PR #{pr.number}: {e}") + print(f"❌ Could not process PR #{pr.number}: {e}") env: - GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} From 06525f969db5754a14f18131428fd642a4fbce60 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 26 Aug 2024 08:21:22 +0800 Subject: [PATCH 1112/1185] Update README.md (#2276) * Update README.md * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: UltralyticsAssistant --- export.py | 4 ++-- hubconf.py | 2 +- models/tf.py | 2 +- segment/val.py | 2 +- utils/dataloaders.py | 4 ++-- utils/loggers/__init__.py | 2 +- utils/loggers/clearml/clearml_utils.py | 2 +- utils/loggers/wandb/wandb_utils.py | 4 ++-- utils/metrics.py | 2 +- utils/plots.py | 2 +- utils/segment/general.py | 12 ++++++------ utils/segment/metrics.py | 6 +++--- utils/torch_utils.py | 4 ++-- utils/triton.py | 2 +- 14 files changed, 25 insertions(+), 25 deletions(-) diff --git a/export.py b/export.py index 182f544c69..fad82dbac6 100644 --- a/export.py +++ b/export.py @@ -1,6 +1,6 @@ # Ultralytics YOLOv3 🚀, AGPL-3.0 license """ -Export a YOLOv3 PyTorch model to other formats. TensorFlow exports authored by https://github.com/zldrobit +Export a YOLOv3 PyTorch model to other formats. TensorFlow exports authored by https://github.com/zldrobit. Format | `export.py --include` | Model --- | --- | --- @@ -1562,7 +1562,7 @@ def parse_opt(known=False): def main(opt): - """Run(**vars(opt))""" + """Run(**vars(opt)).""" for opt.weights in opt.weights if isinstance(opt.weights, list) else [opt.weights]: run(**vars(opt)) diff --git a/hubconf.py b/hubconf.py index a3e8eef583..7e34f06adc 100644 --- a/hubconf.py +++ b/hubconf.py @@ -1,6 +1,6 @@ # Ultralytics YOLOv3 🚀, AGPL-3.0 license """ -PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov5 +PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov5. Usage: import torch diff --git a/models/tf.py b/models/tf.py index 1731e76a6f..13edcdcfca 100644 --- a/models/tf.py +++ b/models/tf.py @@ -1,7 +1,7 @@ # Ultralytics YOLOv3 🚀, AGPL-3.0 license """ TensorFlow, Keras and TFLite versions of YOLOv3 -Authored by https://github.com/zldrobit in PR https://github.com/ultralytics/yolov5/pull/1127 +Authored by https://github.com/zldrobit in PR https://github.com/ultralytics/yolov5/pull/1127. Usage: $ python models/tf.py --weights yolov5s.pt diff --git a/segment/val.py b/segment/val.py index 619bcc1951..52cf7137ea 100644 --- a/segment/val.py +++ b/segment/val.py @@ -115,7 +115,7 @@ def process_batch(detections, labels, iouv, pred_masks=None, gt_masks=None, over detections (array[N, 6]), x1, y1, x2, y2, conf, class labels (array[M, 5]), class, x1, y1, x2, y2 Returns: - correct (array[N, 10]), for 10 IoU levels + correct (array[N, 10]), for 10 IoU levels. """ if masks: if overlap: diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 96fe83c15e..dc9ff22f3c 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -92,7 +92,7 @@ def exif_size(img): def exif_transpose(image): """ Transpose a PIL image accordingly if it has an EXIF Orientation tag. - Inplace version of https://github.com/python-pillow/Pillow/blob/master/src/PIL/ImageOps.py exif_transpose() + Inplace version of https://github.com/python-pillow/Pillow/blob/master/src/PIL/ImageOps.py exif_transpose(). :param image: The image to transpose. :return: An image. @@ -1052,7 +1052,7 @@ def extract_boxes(path=DATASETS_DIR / "coco128"): # from utils.dataloaders impo def autosplit(path=DATASETS_DIR / "coco128/images", weights=(0.9, 0.1, 0.0), annotated_only=False): """Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files - Usage: from utils.dataloaders import *; autosplit() + Usage: from utils.dataloaders import *; autosplit(). Arguments: path: Path to images directory diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index fd9f704a88..0a15554cfa 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -339,7 +339,7 @@ def on_params_update(self, params: dict): class GenericLogger: """ YOLOv3 General purpose logger for non-task specific logging - Usage: from utils.loggers import GenericLogger; logger = GenericLogger(...) + Usage: from utils.loggers import GenericLogger; logger = GenericLogger(...). Arguments: opt: Run arguments diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py index f4841f0376..e9cec6be97 100644 --- a/utils/loggers/clearml/clearml_utils.py +++ b/utils/loggers/clearml/clearml_utils.py @@ -76,7 +76,7 @@ class ClearmlLogger: def __init__(self, opt, hyp): """ - Initialize ClearML Task, this object will capture the experiment - - Upload dataset version to ClearML Data if opt.upload_dataset is True + - Upload dataset version to ClearML Data if opt.upload_dataset is True. Arguments: opt (namespace) -- Commandline arguments for this run diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py index 059c0a7ef6..0481339dd6 100644 --- a/utils/loggers/wandb/wandb_utils.py +++ b/utils/loggers/wandb/wandb_utils.py @@ -47,7 +47,7 @@ def __init__(self, opt, run_id=None, job_type="Training"): """ - Initialize WandbLogger instance - Upload dataset if opt.upload_dataset is True - - Setup training processes if job_type is 'Training' + - Setup training processes if job_type is 'Training'. Arguments: opt (namespace) -- Commandline arguments for this run @@ -88,7 +88,7 @@ def setup_training(self, opt): Setup the necessary processes for training YOLO models: - Attempt to download model checkpoint and dataset artifacts if opt.resume stats with WANDB_ARTIFACT_PREFIX - Update data_dict, to contain info of previous run if resumed and the paths of dataset artifact if downloaded - - Setup log_dict, initialize bbox_interval + - Setup log_dict, initialize bbox_interval. Arguments: opt (namespace) -- commandline arguments for this run diff --git a/utils/metrics.py b/utils/metrics.py index 0323398ce5..20d9928359 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -100,7 +100,7 @@ def compute_ap(recall, precision): recall: The recall curve (list) precision: The precision curve (list) # Returns - Average precision, precision curve, recall curve + Average precision, precision curve, recall curve. """ # Append sentinel values to beginning and end mrec = np.concatenate(([0.0], recall, [1.0])) diff --git a/utils/plots.py b/utils/plots.py index 2919133e02..9bb865dcd3 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -77,7 +77,7 @@ def feature_visualization(x, module_type, stage, n=32, save_dir=Path("runs/detec module_type: Module type stage: Module stage within model n: Maximum number of feature maps to plot - save_dir: Directory to save results + save_dir: Directory to save results. """ if "Detect" not in module_type: batch, channels, height, width = x.shape # batch, channels, height, width diff --git a/utils/segment/general.py b/utils/segment/general.py index 9226065bb5..7ddca4656b 100644 --- a/utils/segment/general.py +++ b/utils/segment/general.py @@ -28,7 +28,7 @@ def process_mask_upsample(protos, masks_in, bboxes, shape): protos: [mask_dim, mask_h, mask_w] masks_in: [n, mask_dim], n is number of masks after nms bboxes: [n, 4], n is number of masks after nms - shape: input_image_size, (h, w) + shape: input_image_size, (h, w). return: h, w, n """ @@ -45,7 +45,7 @@ def process_mask(protos, masks_in, bboxes, shape, upsample=False): proto_out: [mask_dim, mask_h, mask_w] out_masks: [n, mask_dim], n is number of masks after nms bboxes: [n, 4], n is number of masks after nms - shape:input_image_size, (h, w) + shape:input_image_size, (h, w). return: h, w, n """ @@ -71,7 +71,7 @@ def process_mask_native(protos, masks_in, bboxes, shape): protos: [mask_dim, mask_h, mask_w] masks_in: [n, mask_dim], n is number of masks after nms bboxes: [n, 4], n is number of masks after nms - shape: input_image_size, (h, w) + shape: input_image_size, (h, w). return: h, w, n """ @@ -92,7 +92,7 @@ def scale_image(im1_shape, masks, im0_shape, ratio_pad=None): """ img1_shape: model input shape, [h, w] img0_shape: origin pic shape, [h, w, 3] - masks: [h, w, num] + masks: [h, w, num]. """ # Rescale coordinates (xyxy) from im1_shape to im0_shape if ratio_pad is None: # calculate from im0_shape @@ -120,7 +120,7 @@ def mask_iou(mask1, mask2, eps=1e-7): """ mask1: [N, n] m1 means number of predicted objects mask2: [M, n] m2 means number of gt objects - Note: n means image_w x image_h + Note: n means image_w x image_h. return: masks iou, [N, M] """ @@ -133,7 +133,7 @@ def masks_iou(mask1, mask2, eps=1e-7): """ mask1: [N, n] m1 means number of predicted objects mask2: [N, n] m2 means number of gt objects - Note: n means image_w x image_h + Note: n means image_w x image_h. return: masks iou, (N, ) """ diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py index 519604db05..d4689ca015 100644 --- a/utils/segment/metrics.py +++ b/utils/segment/metrics.py @@ -125,7 +125,7 @@ def mean_results(self): return (self.mp, self.mr, self.map50, self.map) def class_result(self, i): - """Class-aware result, return p[i], r[i], ap50[i], ap[i]""" + """Class-aware result, return p[i], r[i], ap50[i], ap[i].""" return (self.p[i], self.r[i], self.ap50[i], self.ap[i]) def get_maps(self, nc): @@ -140,7 +140,7 @@ def get_maps(self, nc): def update(self, results): """ Args: - results: tuple(p, r, ap, f1, ap_class) + results: tuple(p, r, ap, f1, ap_class). """ p, r, all_ap, f1, ap_class_index = results self.p = p @@ -161,7 +161,7 @@ def __init__(self) -> None: def update(self, results): """ Args: - results: Dict{'boxes': Dict{}, 'masks': Dict{}} + results: Dict{'boxes': Dict{}, 'masks': Dict{}}. """ self.metric_box.update(list(results["boxes"].values())) self.metric_mask.update(list(results["masks"].values())) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 115e4d9f89..b3eb9871e9 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -165,7 +165,7 @@ def profile(input, ops, n=10, device=None): input = torch.randn(16, 3, 640, 640) m1 = lambda x: x * torch.sigmoid(x) m2 = nn.SiLU() - profile(input, [m1, m2], n=100) # profile over 100 iterations + profile(input, [m1, m2], n=100) # profile over 100 iterations. """ results = [] if not isinstance(device, torch.device): @@ -453,7 +453,7 @@ def __call__(self, epoch, fitness): class ModelEMA: """Updated Exponential Moving Average (EMA) from https://github.com/rwightman/pytorch-image-models Keeps a moving average of everything in the model state_dict (parameters and buffers) - For EMA details see https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage + For EMA details see https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage. """ def __init__(self, model, decay=0.9999, tau=2000, updates=0): diff --git a/utils/triton.py b/utils/triton.py index 9902dcbf47..dad9dcd472 100644 --- a/utils/triton.py +++ b/utils/triton.py @@ -18,7 +18,7 @@ class TritonRemoteModel: def __init__(self, url: str): """ Keyword Arguments: - url: Fully qualified address of the Triton server - for e.g. grpc://localhost:8000 + url: Fully qualified address of the Triton server - for e.g. grpc://localhost:8000. """ parsed_url = urlparse(url) if parsed_url.scheme == "grpc": From 2423cdd4e0f6f9c28049d0335490cdce5cb78572 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 26 Aug 2024 15:43:22 +0200 Subject: [PATCH 1113/1185] Add https://www.reddit.com/r/Ultralytics/ badge (#2277) Refactor code for speed and clarity Co-authored-by: UltralyticsAssistant --- .github/workflows/merge-main-into-prs.yml | 4 +- README.md | 2 +- export.py | 2 + models/common.py | 78 +++++++++++++++-------- models/experimental.py | 9 ++- models/tf.py | 62 ++++++++++++------ models/yolo.py | 18 ++++-- utils/__init__.py | 3 +- utils/activations.py | 17 +++-- utils/augmentations.py | 12 ++-- utils/dataloaders.py | 12 ++-- utils/general.py | 9 ++- utils/loggers/__init__.py | 3 +- utils/loss.py | 11 +++- utils/metrics.py | 3 +- utils/plots.py | 3 +- utils/segment/dataloaders.py | 2 + utils/segment/loss.py | 3 +- utils/segment/metrics.py | 2 + utils/torch_utils.py | 3 +- 20 files changed, 175 insertions(+), 83 deletions(-) diff --git a/.github/workflows/merge-main-into-prs.yml b/.github/workflows/merge-main-into-prs.yml index db6a180295..372d888241 100644 --- a/.github/workflows/merge-main-into-prs.yml +++ b/.github/workflows/merge-main-into-prs.yml @@ -34,11 +34,11 @@ jobs: g = Github(os.getenv('GITHUB_TOKEN')) repo = g.get_repo(os.getenv('GITHUB_REPOSITORY')) - + # Fetch the default branch name default_branch_name = repo.default_branch default_branch = repo.get_branch(default_branch_name) - + for pr in repo.get_pulls(state='open', sort='created'): try: # Get full names for repositories and branches diff --git a/README.md b/README.md index e4314803be..14bc041938 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ YOLOv3 CI YOLOv3 Citation Docker Pulls - Discord Ultralytics Forums + Discord Ultralytics Forums Ultralytics Reddit
Run on Gradient Open In Colab diff --git a/export.py b/export.py index fad82dbac6..9c9a0d9a77 100644 --- a/export.py +++ b/export.py @@ -91,6 +91,8 @@ class iOSModel(torch.nn.Module): + """Exports a PyTorch model to an iOS-compatible format with normalized input dimensions and class configurations.""" + def __init__(self, model, im): """ Initializes an iOSModel with normalized input dimensions and number of classes from a PyTorch model. diff --git a/models/common.py b/models/common.py index 295a04d933..9d0818d62f 100644 --- a/models/common.py +++ b/models/common.py @@ -55,7 +55,8 @@ def autopad(k, p=None, d=1): # kernel, padding, dilation class Conv(nn.Module): - # Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation) + """A standard Conv2D layer with batch normalization and optional activation for neural networks.""" + default_act = nn.SiLU() # default activation def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True): @@ -81,7 +82,8 @@ def forward_fuse(self, x): class DWConv(Conv): - # Depth-wise convolution + """Implements depth-wise convolution for efficient spatial feature extraction in neural networks.""" + def __init__(self, c1, c2, k=1, s=1, d=1, act=True): # ch_in, ch_out, kernel, stride, dilation, activation """Initializes depth-wise convolution with optional activation; parameters are channel in/out, kernel, stride, dilation. @@ -90,7 +92,8 @@ def __init__(self, c1, c2, k=1, s=1, d=1, act=True): # ch_in, ch_out, kernel, s class DWConvTranspose2d(nn.ConvTranspose2d): - # Depth-wise transpose convolution + """Implements a depth-wise transpose convolution layer with specified channels, kernel size, stride, and padding.""" + def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0): # ch_in, ch_out, kernel, stride, padding, padding_out """Initializes a depth-wise or transpose convolution layer with specified in/out channels, kernel size, stride, and padding. @@ -99,7 +102,8 @@ def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0): # ch_in, ch_out, kernel, stri class TransformerLayer(nn.Module): - # Transformer layer https://arxiv.org/abs/2010.11929 (LayerNorm layers removed for better performance) + """Transformer layer with multi-head attention and feed-forward network, optimized by removing LayerNorm.""" + def __init__(self, c, num_heads): """Initializes a Transformer layer as per https://arxiv.org/abs/2010.11929, sans LayerNorm, with specified embedding dimension and number of heads. @@ -122,7 +126,8 @@ def forward(self, x): class TransformerBlock(nn.Module): - # Vision Transformer https://arxiv.org/abs/2010.11929 + """Implements a Vision Transformer block with transformer layers; https://arxiv.org/abs/2010.11929.""" + def __init__(self, c1, c2, num_heads, num_layers): """Initializes a Transformer block with optional convolution, linear, and transformer layers.""" super().__init__() @@ -143,7 +148,8 @@ def forward(self, x): class Bottleneck(nn.Module): - # Standard bottleneck + """Implements a bottleneck layer with optional shortcut for efficient feature extraction in neural networks.""" + def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion """Initializes a standard bottleneck layer with optional shortcut; args: input channels (c1), output channels (c2), shortcut (bool), groups (g), expansion factor (e). @@ -162,7 +168,8 @@ def forward(self, x): class BottleneckCSP(nn.Module): - # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks + """Implements a CSP Bottleneck layer for feature extraction.""" + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion """Initializes CSP Bottleneck with channel in/out, optional shortcut, groups, expansion; see https://github.com/WongKinYiu/CrossStagePartialNetworks. @@ -187,7 +194,8 @@ def forward(self, x): class CrossConv(nn.Module): - # Cross Convolution Downsample + """Implements Cross Convolution Downsample with 1D and 2D convolutions and optional shortcut.""" + def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False): """Initializes CrossConv with downsample options, combining 1D and 2D convolutions, optional shortcut if input/output channels match. @@ -204,7 +212,8 @@ def forward(self, x): class C3(nn.Module): - # CSP Bottleneck with 3 convolutions + """Implements a CSP Bottleneck with 3 convolutions, optional shortcuts, group convolutions, and expansion factor.""" + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion """Initializes CSP Bottleneck with 3 convolutions, optional shortcuts, group convolutions, and expansion factor. @@ -222,7 +231,8 @@ def forward(self, x): class C3x(C3): - # C3 module with cross-convolutions + """Extends the C3 module with cross-convolutions for enhanced feature extraction and flexibility.""" + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): """Initializes a C3x module with cross-convolutions, extending the C3 module with customizable parameters.""" super().__init__(c1, c2, n, shortcut, g, e) @@ -231,7 +241,8 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): class C3TR(C3): - # C3 module with TransformerBlock() + """C3 module with TransformerBlock for integrating attention mechanisms in CNNs.""" + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): """Initializes a C3 module with TransformerBlock, extending C3 for attention mechanisms.""" super().__init__(c1, c2, n, shortcut, g, e) @@ -240,7 +251,8 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): class C3SPP(C3): - # C3 module with SPP() + """Extends C3 with Spatial Pyramid Pooling (SPP) for enhanced feature extraction in CNNs.""" + def __init__(self, c1, c2, k=(5, 9, 13), n=1, shortcut=True, g=1, e=0.5): """Initializes C3SPP module, extending C3 with Spatial Pyramid Pooling for enhanced feature extraction.""" super().__init__(c1, c2, n, shortcut, g, e) @@ -249,7 +261,8 @@ def __init__(self, c1, c2, k=(5, 9, 13), n=1, shortcut=True, g=1, e=0.5): class C3Ghost(C3): - # C3 module with GhostBottleneck() + """Implements a C3 module with Ghost Bottlenecks for efficient feature extraction in neural networks.""" + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): """Initializes C3Ghost module with Ghost Bottlenecks for efficient feature extraction.""" super().__init__(c1, c2, n, shortcut, g, e) @@ -258,7 +271,8 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): class SPP(nn.Module): - # Spatial Pyramid Pooling (SPP) layer https://arxiv.org/abs/1406.4729 + """Implements Spatial Pyramid Pooling (SPP) for enhanced feature extraction; see https://arxiv.org/abs/1406.4729.""" + def __init__(self, c1, c2, k=(5, 9, 13)): """ Initializes SPP layer with specified channels and kernels. @@ -284,7 +298,8 @@ def forward(self, x): class SPPF(nn.Module): - # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv3 by Glenn Jocher + """Implements a fast Spatial Pyramid Pooling (SPPF) layer for efficient feature extraction in YOLOv3 models.""" + def __init__(self, c1, c2, k=5): # equivalent to SPP(k=(5, 9, 13)) """Initializes the SPPF layer with specified input/output channels and kernel size for YOLOv3.""" super().__init__() @@ -306,7 +321,8 @@ def forward(self, x): class Focus(nn.Module): - # Focus wh information into c-space + """Focuses spatial information into channel space using configurable convolution.""" + def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups """Initializes Focus module to focus width and height information into channel space with configurable convolution parameters. @@ -322,7 +338,8 @@ def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2) class GhostConv(nn.Module): - # Ghost Convolution https://github.com/huawei-noah/ghostnet + """Implements Ghost Convolution for efficient feature extraction; see github.com/huawei-noah/ghostnet.""" + def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups """Initializes GhostConv with in/out channels, kernel size, stride, groups; see https://github.com/huawei-noah/ghostnet. @@ -339,7 +356,8 @@ def forward(self, x): class GhostBottleneck(nn.Module): - # Ghost Bottleneck https://github.com/huawei-noah/ghostnet + """Implements a Ghost Bottleneck layer for efficient feature extraction from GhostNet.""" + def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride """Initializes GhostBottleneck module with in/out channels, kernel size, and stride; see https://github.com/huawei-noah/ghostnet. @@ -361,7 +379,8 @@ def forward(self, x): class Contract(nn.Module): - # Contract width-height into channels, i.e. x(1,64,80,80) to x(1,256,40,40) + """Contracts spatial dimensions into channels, e.g., (1,64,80,80) to (1,256,40,40) with a specified gain.""" + def __init__(self, gain=2): """Initializes Contract module to refine input dimensions, e.g., from (1,64,80,80) to (1,256,40,40) with a default gain of 2. @@ -381,7 +400,8 @@ def forward(self, x): class Expand(nn.Module): - # Expand channels into width-height, i.e. x(1,64,80,80) to x(1,16,160,160) + """Expands spatial dimensions of input tensor by a factor while reducing channels correspondingly.""" + def __init__(self, gain=2): """Initializes Expand module to increase spatial dimensions by factor `gain` while reducing channels correspondingly. @@ -401,7 +421,8 @@ def forward(self, x): class Concat(nn.Module): - # Concatenate a list of tensors along dimension + """Concatenates a list of tensors along a specified dimension for efficient feature aggregation.""" + def __init__(self, dimension=1): """Initializes a module to concatenate tensors along a specified dimension.""" super().__init__() @@ -415,7 +436,8 @@ def forward(self, x): class DetectMultiBackend(nn.Module): - # YOLOv3 MultiBackend class for python inference on various backends + """YOLOv3 multi-backend class for inference on frameworks like PyTorch, ONNX, TensorRT, and more.""" + def __init__(self, weights="yolov5s.pt", device=torch.device("cpu"), dnn=False, data=None, fp16=False, fuse=True): """Initializes multi-backend detection with options for various frameworks and devices, also handles model download. @@ -749,7 +771,8 @@ def _load_metadata(f=Path("path/to/meta.yaml")): class AutoShape(nn.Module): - # YOLOv3 input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS + """A wrapper for YOLOv3 models to handle diverse input types with preprocessing, inference, and NMS.""" + conf = 0.25 # NMS confidence threshold iou = 0.45 # NMS IoU threshold agnostic = False # NMS class-agnostic @@ -857,7 +880,8 @@ def forward(self, ims, size=640, augment=False, profile=False): class Detections: - # YOLOv3 detections class for inference results + """Handles YOLOv3 detection results with methods for visualization, saving, cropping, and format conversion.""" + def __init__(self, ims, pred, files, times=(0, 0, 0), names=None, shape=None): """Initializes YOLOv3 detections with image data, predictions, filenames, profiling times, class names, and shapes. @@ -1011,7 +1035,8 @@ def __repr__(self): class Proto(nn.Module): - # YOLOv3 mask Proto module for segmentation models + """Implements the YOLOv3 mask Proto module for segmentation, including convolutional layers and upsampling.""" + def __init__(self, c1, c_=256, c2=32): # ch_in, number of protos, number of masks """Initializes the Proto module for YOLOv3 segmentation, setting up convolutional layers and upsampling.""" super().__init__() @@ -1026,7 +1051,8 @@ def forward(self, x): class Classify(nn.Module): - # YOLOv3 classification head, i.e. x(b,c1,20,20) to x(b,c2) + """Performs image classification using YOLOv3-based architecture with convolutional, pooling, and dropout layers.""" + def __init__( self, c1, c2, k=1, s=1, p=None, g=1, dropout_p=0.0 ): # ch_in, ch_out, kernel, stride, padding, groups, dropout probability diff --git a/models/experimental.py b/models/experimental.py index 305434ec87..7c1ed58608 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -11,7 +11,8 @@ class Sum(nn.Module): - # Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + """Computes the weighted or unweighted sum of multiple input layers per https://arxiv.org/abs/1911.09070.""" + def __init__(self, n, weight=False): # n: number of inputs """ Initializes a module to compute weighted/unweighted sum of n inputs, with optional learning weights. @@ -42,7 +43,8 @@ def forward(self, x): class MixConv2d(nn.Module): - # Mixed Depth-wise Conv https://arxiv.org/abs/1907.09595 + """Implements mixed depth-wise convolutions for efficient neural networks; see https://arxiv.org/abs/1907.09595.""" + def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): # ch_in, ch_out, kernel, stride, ch_strategy """Initializes MixConv2d with mixed depth-wise convolution layers; details at https://arxiv.org/abs/1907.09595. @@ -72,7 +74,8 @@ def forward(self, x): class Ensemble(nn.ModuleList): - # Ensemble of models + """Combines outputs from multiple models to improve inference results.""" + def __init__(self): """Initializes an ensemble of models to combine their outputs.""" super().__init__() diff --git a/models/tf.py b/models/tf.py index 13edcdcfca..b4c47e8e73 100644 --- a/models/tf.py +++ b/models/tf.py @@ -49,7 +49,8 @@ class TFBN(keras.layers.Layer): - # TensorFlow BatchNormalization wrapper + """A TensorFlow BatchNormalization wrapper layer initialized with specific weights for YOLOv3 models.""" + def __init__(self, w=None): """Initializes TFBN with weights, wrapping TensorFlow's BatchNormalization layer with specific initializers.""" super().__init__() @@ -67,7 +68,8 @@ def call(self, inputs): class TFPad(keras.layers.Layer): - # Pad inputs in spatial dimensions 1 and 2 + """Pads inputs in spatial dimensions 1 and 2 using specified padding width as an int or (int, int) tuple/list.""" + def __init__(self, pad): """Initializes a padding layer for spatial dimensions 1 and 2, with `pad` as int or (int, int) tuple/list.""" super().__init__() @@ -84,7 +86,8 @@ def call(self, inputs): class TFConv(keras.layers.Layer): - # Standard convolution + """Implements a standard convolutional layer with optional batch normalization and activation for TensorFlow.""" + def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None): """Initializes a convolutional layer with customizable filters, kernel size, stride, padding, groups, and activation. @@ -112,7 +115,8 @@ def call(self, inputs): class TFDWConv(keras.layers.Layer): - # Depthwise convolution + """Implements a depthwise convolutional layer with optional batch normalization and activation for TensorFlow.""" + def __init__(self, c1, c2, k=1, s=1, p=None, act=True, w=None): """Initializes a depthwise convolutional layer with optional batch normalization and activation.""" super().__init__() @@ -136,7 +140,8 @@ def call(self, inputs): class TFDWConvTranspose2d(keras.layers.Layer): - # Depthwise ConvTranspose2d + """Implements a depthwise transposed convolutional layer for TensorFlow with equal input and output channels.""" + def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0, w=None): """Initializes TFDWConvTranspose2d with ch_in=c1=ch_out, k=4, p1=1; sets up depthwise Conv2DTranspose layers.""" super().__init__() @@ -166,7 +171,8 @@ def call(self, inputs): class TFFocus(keras.layers.Layer): - # Focus wh information into c-space + """Focuses spatial information into channel space using a convolutional layer for efficient feature extraction.""" + def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None): """Initializes TFFocus layer for efficient information focusing into channel-space with customizable convolution parameters. @@ -183,7 +189,8 @@ def call(self, inputs): # x(b,w,h,c) -> y(b,w/2,h/2,4c) class TFBottleneck(keras.layers.Layer): - # Standard bottleneck + """A TensorFlow bottleneck layer with optional shortcut connections, channel expansion, and group convolutions.""" + def __init__(self, c1, c2, shortcut=True, g=1, e=0.5, w=None): # ch_in, ch_out, shortcut, groups, expansion """Initializes a standard bottleneck layer with optional shortcut, channel expansion, and group convolutions.""" super().__init__() @@ -200,7 +207,8 @@ def call(self, inputs): class TFCrossConv(keras.layers.Layer): - # Cross Convolution + """Implements a cross convolutional layer with customizable channels, kernel size, stride, groups, and shortcut.""" + def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False, w=None): """Initializes cross convolutional layer with parameters for channel sizes, kernel size, stride, groups, expansion factor, shortcut option, and weights. @@ -217,7 +225,8 @@ def call(self, inputs): class TFConv2d(keras.layers.Layer): - # Substitution for PyTorch nn.Conv2D + """Implements a TensorFlow 2.2+ Conv2D layer as a substitute for PyTorch's Conv2D with customizable parameters.""" + def __init__(self, c1, c2, k, s=1, g=1, bias=True, w=None): """Initializes TFConv2d layer for TensorFlow 2.2+, substituting PyTorch Conv2D; c1, c2: channels, k: kernel size, s: stride. @@ -240,7 +249,8 @@ def call(self, inputs): class TFBottleneckCSP(keras.layers.Layer): - # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks + """Implements a Cross Stage Partial (CSP) Bottleneck layer for efficient feature extraction in neural networks.""" + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): """Initializes CSP Bottleneck layer with channel configurations and optional shortcut, groups, expansion, and weights. @@ -263,7 +273,8 @@ def call(self, inputs): class TFC3(keras.layers.Layer): - # CSP Bottleneck with 3 convolutions + """CSP Bottleneck layer with 3 convolutions for enhanced feature extraction and integration in TensorFlow models.""" + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): """Initializes a CSP Bottleneck layer with 3 convolutions for channel manipulation and feature integration.""" super().__init__() @@ -281,7 +292,8 @@ def call(self, inputs): class TFC3x(keras.layers.Layer): - # 3 module with cross-convolutions + """Implements a CSP Bottleneck layer with cross-convolutions for enhanced feature extraction in YOLOv3 models.""" + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): """Initializes a TFC3x layer with cross-convolutions, expanding and concatenating features for given channel inputs and outputs. @@ -301,7 +313,8 @@ def call(self, inputs): class TFSPP(keras.layers.Layer): - # Spatial pyramid pooling layer used in YOLOv3-SPP + """Implements Spatial Pyramid Pooling (SPP) for YOLOv3-SPP with configurable channels and kernel sizes.""" + def __init__(self, c1, c2, k=(5, 9, 13), w=None): """Initializes a Spatial Pyramid Pooling layer for YOLOv3-SPP with configurable in/out channels and kernel sizes. @@ -319,7 +332,8 @@ def call(self, inputs): class TFSPPF(keras.layers.Layer): - # Spatial pyramid pooling-Fast layer + """Implements a fast spatial pyramid pooling layer for efficient multi-scale feature extraction in YOLOv3 models.""" + def __init__(self, c1, c2, k=5, w=None): """Initializes a Spatial Pyramid Pooling-Fast layer with specified channels, kernel size, and optional weights. @@ -339,7 +353,8 @@ def call(self, inputs): class TFDetect(keras.layers.Layer): - # TF YOLOv3 Detect layer + """Implements YOLOv3 detection layer in TensorFlow for object detection with configurable classes and anchors.""" + def __init__(self, nc=80, anchors=(), ch=(), imgsz=(640, 640), w=None): # detection layer """Initializes a YOLOv3 detection layer with specified classes, anchors, channels, image size, and weights.""" super().__init__() @@ -393,7 +408,8 @@ def _make_grid(nx=20, ny=20): class TFSegment(TFDetect): - # YOLOv3 Segment head for segmentation models + """Implements YOLOv3 segmentation head for object detection and segmentation tasks using TensorFlow.""" + def __init__(self, nc=80, anchors=(), nm=32, npr=256, ch=(), imgsz=(640, 640), w=None): """Initializes a YOLOv3 Segment head with customizable parameters for segmentation models.""" super().__init__(nc, anchors, ch, imgsz, w) @@ -414,6 +430,8 @@ def call(self, x): class TFProto(keras.layers.Layer): + """Implements a TensorFlow layer for feature processing with convolution and upsample operations.""" + def __init__(self, c1, c_=256, c2=32, w=None): """Initializes a TFProto layer with convolution and upsample operations for feature processing.""" super().__init__() @@ -428,7 +446,8 @@ def call(self, inputs): class TFUpsample(keras.layers.Layer): - # TF version of torch.nn.Upsample() + """Implements an upsample layer using TensorFlow with specified size, scale factor, and interpolation mode.""" + def __init__(self, size, scale_factor, mode, w=None): # warning: all arguments needed including 'w' """Initializes an upsample layer with specific size, doubling scale factor (>0, even), interpolation mode, and optional weights. @@ -447,7 +466,8 @@ def call(self, inputs): class TFConcat(keras.layers.Layer): - # TF version of torch.concat() + """Concatenates input tensors along the specified dimension (NHWC format) using TensorFlow.""" + def __init__(self, dimension=1, w=None): """Initializes a TensorFlow layer to concatenate tensors along the NHWC dimension, requiring dimension=1.""" super().__init__() @@ -534,7 +554,8 @@ def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3) class TFModel: - # TF YOLOv3 model + """TensorFlow implementation of YOLOv3 for object detection, supporting Keras and TFLite models.""" + def __init__(self, cfg="yolov5s.yaml", ch=3, nc=None, model=None, imgsz=(640, 640)): # model, channels, classes """Initializes TF YOLOv3 model with config, channels, classes, optional pre-loaded model, and input image size. @@ -606,7 +627,8 @@ def _xywh2xyxy(xywh): class AgnosticNMS(keras.layers.Layer): - # TF Agnostic NMS + """Applies class-agnostic non-maximum suppression (NMS) to filter detections by IoU and confidence thresholds.""" + def call(self, input, topk_all, iou_thres, conf_thres): """Applies non-maximum suppression (NMS) to filter detections based on IoU, confidence thresholds, and top-K.""" return tf.map_fn( diff --git a/models/yolo.py b/models/yolo.py index 8c77f04a66..49cd9c74fc 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -42,7 +42,8 @@ class Detect(nn.Module): - # YOLOv3 Detect head for detection models + """YOLOv3 Detect head for processing detection model outputs, including grid and anchor grid generation.""" + stride = None # strides computed during build dynamic = False # force grid reconstruction export = False # export mode @@ -105,7 +106,8 @@ def _make_grid(self, nx=20, ny=20, i=0, torch_1_10=check_version(torch.__version class Segment(Detect): - # YOLOv3 Segment head for segmentation models + """YOLOv3 Segment head for segmentation models, adding mask prediction and prototyping to detection.""" + def __init__(self, nc=80, anchors=(), nm=32, npr=256, ch=(), inplace=True): """Initializes the YOLOv3 segment head with customizable class count, anchors, masks, protos, channels, and inplace option. @@ -128,7 +130,8 @@ def forward(self, x): class BaseModel(nn.Module): - # YOLOv3 base model + """Implements the base YOLOv3 model architecture for object detection tasks.""" + def forward(self, x, profile=False, visualize=False): """Performs a single-scale inference or training step on input `x`, with options for profiling and visualization. @@ -191,7 +194,8 @@ def _apply(self, fn): class DetectionModel(BaseModel): - # YOLOv3 detection model + """YOLOv3 detection model class for initializing and processing detection models with configurable parameters.""" + def __init__(self, cfg="yolov5s.yaml", ch=3, nc=None, anchors=None): # model, input channels, number of classes """Initializes YOLOv3 detection model with configurable YAML, input channels, classes, and anchors.""" super().__init__() @@ -303,14 +307,16 @@ def _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is class SegmentationModel(DetectionModel): - # YOLOv3 segmentation model + """Implements a YOLOv3-based segmentation model with customizable configuration, channels, classes, and anchors.""" + def __init__(self, cfg="yolov5s-seg.yaml", ch=3, nc=None, anchors=None): """Initializes a SegmentationModel with optional configuration, channel, class count, and anchors parameters.""" super().__init__(cfg, ch, nc, anchors) class ClassificationModel(BaseModel): - # YOLOv3 classification model + """Implements a YOLOv3-based image classification model with configurable architecture and class count.""" + def __init__(self, cfg=None, model=None, nc=1000, cutoff=10): # yaml, model, number of classes, cutoff index """Initializes a ClassificationModel from a detection model or YAML, with configurable classes and cutoff.""" super().__init__() diff --git a/utils/__init__.py b/utils/__init__.py index a34a38abef..918856178c 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -12,7 +12,8 @@ def emojis(str=""): class TryExcept(contextlib.ContextDecorator): - # YOLOv3 TryExcept class. Usage: @TryExcept() decorator or 'with TryExcept():' context manager + """A context manager and decorator for handling exceptions with optional custom messages.""" + def __init__(self, msg=""): """Initializes TryExcept with optional custom message, used as decorator or context manager for exception handling. diff --git a/utils/activations.py b/utils/activations.py index 95661bf1dd..a4ff9e48f7 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -7,7 +7,8 @@ class SiLU(nn.Module): - # SiLU activation https://arxiv.org/pdf/1606.08415.pdf + """Applies the SiLU activation function to the input tensor as described in https://arxiv.org/pdf/1606.08415.pdf.""" + @staticmethod def forward(x): """Applies the SiLU activation function, as detailed in https://arxiv.org/pdf/1606.08415.pdf, on input tensor @@ -17,7 +18,8 @@ def forward(x): class Hardswish(nn.Module): - # Hard-SiLU activation + """Applies the Hardswish activation function to the input tensor `x`.""" + @staticmethod def forward(x): """Applies Hardswish activation, suitable for TorchScript, CoreML, ONNX, modifying input `x` as per Hard-SiLU @@ -27,7 +29,8 @@ def forward(x): class Mish(nn.Module): - # Mish activation https://github.com/digantamisra98/Mish + """Applies the Mish activation function to improve model performance; see https://github.com/digantamisra98/Mish.""" + @staticmethod def forward(x): """ @@ -39,8 +42,11 @@ def forward(x): class MemoryEfficientMish(nn.Module): - # Mish activation memory-efficient + """Applies the memory-efficient Mish activation function for improved model performance and reduced memory usage.""" + class F(torch.autograd.Function): + """Memory-efficient implementation of the Mish activation function for enhanced model performance.""" + @staticmethod def forward(ctx, x): """Applies the Mish activation function in a memory-efficient manner, useful for enhancing model @@ -65,7 +71,8 @@ def forward(self, x): class FReLU(nn.Module): - # FReLU activation https://arxiv.org/abs/2007.11824 + """Implements the FReLU activation, combining ReLU and convolution from https://arxiv.org/abs/2007.11824.""" + def __init__(self, c1, k=3): # ch_in, kernel """Initializes FReLU with specified channel size and kernel, implementing activation from https://arxiv.org/abs/2007.11824. diff --git a/utils/augmentations.py b/utils/augmentations.py index 539b55304a..cf11b0c525 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -18,7 +18,8 @@ class Albumentations: - # YOLOv3 Albumentations class (optional, only used if package is installed) + """Provides optional image augmentation for YOLOv3 using the Albumentations library if installed.""" + def __init__(self, size=640): """Initializes Albumentations class for optional YOLOv3 data augmentation with default size 640.""" self.transform = None @@ -363,7 +364,8 @@ def classify_transforms(size=224): class LetterBox: - # YOLOv3 LetterBox class for image preprocessing, i.e. T.Compose([LetterBox(size), ToTensor()]) + """Resizes and pads images to a specified size while maintaining aspect ratio.""" + def __init__(self, size=(640, 640), auto=False, stride=32): """Initializes LetterBox for YOLOv3 image preprocessing with optional auto-sizing and stride; `size` can be int or tuple. @@ -388,7 +390,8 @@ def __call__(self, im): # im = np.array HWC class CenterCrop: - # YOLOv3 CenterCrop class for image preprocessing, i.e. T.Compose([CenterCrop(size), ToTensor()]) + """Crops the center of an image to a specified size, maintaining aspect ratio.""" + def __init__(self, size=640): """Initializes a CenterCrop object for YOLOv3, to crop images to a specified size, with default 640x640.""" super().__init__() @@ -403,7 +406,8 @@ def __call__(self, im): # im = np.array HWC class ToTensor: - # YOLOv3 ToTensor class for image preprocessing, i.e. T.Compose([LetterBox(size), ToTensor()]) + """Converts a BGR image in numpy format to a PyTorch tensor in RGB format, with optional half precision.""" + def __init__(self, half=False): """Initializes ToTensor class for YOLOv3 image preprocessing to convert images to PyTorch tensors, optionally in half precision. diff --git a/utils/dataloaders.py b/utils/dataloaders.py index dc9ff22f3c..4fef716250 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -226,7 +226,8 @@ def __iter__(self): class LoadScreenshots: - # YOLOv3 screenshot dataloader, i.e. `python detect.py --source "screen 0 100 100 512 256"` + """Loads screenshots as input data for YOLOv3, capturing screen regions specified by coordinates and dimensions.""" + def __init__(self, source, img_size=640, stride=32, auto=True, transforms=None): """Initializes a screenshot dataloader for YOLOv3; source format: [screen_number left top width height], default img_size=640, stride=32. @@ -278,7 +279,8 @@ def __next__(self): class LoadImages: - # YOLOv3 image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4` + """Loads images and videos for YOLOv3 from various sources, including directories and '*.txt' path lists.""" + def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): """Initializes the data loader for YOLOv3, supporting image, video, directory, and '*.txt' path lists with customizable image sizing. @@ -389,7 +391,8 @@ def __len__(self): class LoadStreams: - # YOLOv3 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams` + """Loads video streams for YOLOv3 inference, supporting multiple sources and customizable frame sizes.""" + def __init__(self, sources="file.streams", img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): """Initializes a stream loader for YOLOv3, handling video sources or files with customizable frame sizes and intervals. @@ -492,7 +495,8 @@ def img2label_paths(img_paths): class LoadImagesAndLabels(Dataset): - # YOLOv3 train_loader/val_loader, loads images and labels for training and validation + """Loads images and labels for YOLOv3 training and validation with support for augmentations and caching.""" + cache_version = 0.6 # dataset labels *.cache version rand_interp_methods = [cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_CUBIC, cv2.INTER_AREA, cv2.INTER_LANCZOS4] diff --git a/utils/general.py b/utils/general.py index afee396906..812720b7bc 100644 --- a/utils/general.py +++ b/utils/general.py @@ -176,7 +176,8 @@ def user_config_dir(dir="Ultralytics", env_var="YOLOV5_CONFIG_DIR"): class Profile(contextlib.ContextDecorator): - # YOLOv3 Profile class. Usage: @Profile() decorator or 'with Profile():' context manager + """Profiles code execution time, usable as a context manager or decorator for performance monitoring.""" + def __init__(self, t=0.0): """Initializes a profiling context for YOLOv3 with optional timing threshold `t` and checks CUDA availability. @@ -204,7 +205,8 @@ def time(self): class Timeout(contextlib.ContextDecorator): - # YOLOv3 Timeout class. Usage: @Timeout(seconds) decorator or 'with Timeout(seconds):' context manager + """Enforces a timeout on code execution, raising TimeoutError on expiry.""" + def __init__(self, seconds, *, timeout_msg="", suppress_timeout_errors=True): """Initializes a timeout context/decorator with specified duration, custom message, and error handling option. @@ -232,7 +234,8 @@ def __exit__(self, exc_type, exc_val, exc_tb): class WorkingDirectory(contextlib.ContextDecorator): - # Usage: @WorkingDirectory(dir) decorator or 'with WorkingDirectory(dir):' context manager + """Context manager to temporarily change the working directory, reverting to the original on exit.""" + def __init__(self, new_dir): """Initializes context manager to temporarily change working directory, reverting on exit.""" self.dir = new_dir # new dir diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index 0a15554cfa..35fa66ad89 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -63,7 +63,8 @@ def SummaryWriter(*args): class Loggers: - # YOLOv3 Loggers class + """Manages logging for training and validation using TensorBoard, Weights & Biases, ClearML, and Comet ML.""" + def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, include=LOGGERS): """Initializes YOLOv3 logging with directory, weights, options, hyperparameters, and includes specified loggers. diff --git a/utils/loss.py b/utils/loss.py index 148f5118e5..3d3e1208b3 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -14,7 +14,8 @@ def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#iss class BCEBlurWithLogitsLoss(nn.Module): - # BCEwithLogitLoss() with reduced missing label effects. + """Implements BCEWithLogitsLoss with adjustments to mitigate missing label effects using an alpha parameter.""" + def __init__(self, alpha=0.05): """Initializes BCEBlurWithLogitsLoss with alpha to reduce missing label effects; default alpha is 0.05.""" super().__init__() @@ -35,7 +36,8 @@ def forward(self, pred, true): class FocalLoss(nn.Module): - # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) + """Implements Focal Loss to address class imbalance by modulating the loss based on prediction confidence.""" + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): """Initializes FocalLoss with specified loss function, gamma, and alpha for enhanced training on imbalanced datasets. @@ -71,7 +73,8 @@ def forward(self, pred, true): class QFocalLoss(nn.Module): - # Wraps Quality focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) + """Implements Quality Focal Loss to handle class imbalance with a modulating factor and alpha.""" + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): """Initializes QFocalLoss with specified loss function, gamma, and alpha for element-wise focal loss application. @@ -103,6 +106,8 @@ def forward(self, pred, true): class ComputeLoss: + """Computes the total loss for YOLO models by aggregating classification, box regression, and objectness losses.""" + sort_obj_iou = False # Compute losses diff --git a/utils/metrics.py b/utils/metrics.py index 20d9928359..f79bdfbdc4 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -122,7 +122,8 @@ def compute_ap(recall, precision): class ConfusionMatrix: - # Updated version of https://github.com/kaanakan/object_detection_confusion_matrix + """Computes and visualizes a confusion matrix for object detection tasks with configurable thresholds.""" + def __init__(self, nc, conf=0.25, iou_thres=0.45): """Initializes confusion matrix for object detection with adjustable confidence and IoU thresholds.""" self.matrix = np.zeros((nc + 1, nc + 1)) diff --git a/utils/plots.py b/utils/plots.py index 9bb865dcd3..ad5f4ea6d3 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -29,7 +29,8 @@ class Colors: - # Ultralytics color palette https://ultralytics.com/ + """Provides a color palette and methods to convert indices to RGB or BGR color tuples.""" + def __init__(self): """Initializes the Colors class with a palette from the Ultralytics color palette.""" hexs = ( diff --git a/utils/segment/dataloaders.py b/utils/segment/dataloaders.py index 0343291d68..4b1fba08bf 100644 --- a/utils/segment/dataloaders.py +++ b/utils/segment/dataloaders.py @@ -82,6 +82,8 @@ def create_dataloader( class LoadImagesAndLabelsAndMasks(LoadImagesAndLabels): # for training/testing + """Loads images, labels, and masks for training/testing with optional augmentations including mosaic and mixup.""" + def __init__( self, path, diff --git a/utils/segment/loss.py b/utils/segment/loss.py index 1871d5662e..4e204a42c8 100644 --- a/utils/segment/loss.py +++ b/utils/segment/loss.py @@ -12,7 +12,8 @@ class ComputeLoss: - # Compute losses + """Computes classification, box regression, objectness, and segmentation losses for YOLOv3 model predictions.""" + def __init__(self, model, autobalance=False, overlap=False): """Initializes ComputeLoss with model settings, optional autobalancing, and overlap handling.""" self.sort_obj_iou = False diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py index d4689ca015..9451cc9324 100644 --- a/utils/segment/metrics.py +++ b/utils/segment/metrics.py @@ -54,6 +54,8 @@ def ap_per_class_box_and_mask( class Metric: + """Represents model evaluation metrics including precision, recall, F1 score, and average precision (AP) values.""" + def __init__(self) -> None: """Initializes Metric class attributes for precision, recall, F1 score, AP values, and AP class indices.""" self.p = [] # (nc, ) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index b3eb9871e9..0b1d69a9ab 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -422,7 +422,8 @@ def smart_resume(ckpt, optimizer, ema=None, weights="yolov5s.pt", epochs=300, re class EarlyStopping: - # YOLOv3 simple early stopper + """Monitors training to halt if no improvement in fitness metric is observed for a specified number of epochs.""" + def __init__(self, patience=30): """Initializes EarlyStopping to monitor training, halting if no improvement in 'patience' epochs, defaulting to 30. From fc83ab9eccf991b0814845cfc8a2d852b2deadff Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 26 Aug 2024 15:47:54 +0200 Subject: [PATCH 1114/1185] Update README.zh-CN.md (#2278) --- README.zh-CN.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.zh-CN.md b/README.zh-CN.md index 6a483a1164..1fbd24a74c 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -10,12 +10,13 @@ YOLOv3 CI YOLOv3 Citation Docker Pulls + Discord Ultralytics Forums Ultralytics Reddit
Run on Gradient Open In Colab Open In Kaggle -
-
+
+
YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics 对未来视觉 AI 方法的开源研究,结合在数千小时的研究和开发中积累的经验教训和最佳实践。 From ae4cd98a3cc78891f78fc9f97bd574e4de072ae3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 1 Sep 2024 17:33:22 +0200 Subject: [PATCH 1115/1185] PyUpgrade 3.8 updates (#2279) * PyUpgrade 3.8 updates * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: UltralyticsAssistant --- classify/predict.py | 2 +- detect.py | 2 +- segment/predict.py | 2 +- utils/metrics.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/classify/predict.py b/classify/predict.py index 2f7eda383a..f0f8aadbad 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -147,7 +147,7 @@ def run( save_path = str(save_dir / p.name) # im.jpg txt_path = str(save_dir / "labels" / p.stem) + ("" if dataset.mode == "image" else f"_{frame}") # im.txt - s += "%gx%g " % im.shape[2:] # print string + s += "{:g}x{:g} ".format(*im.shape[2:]) # print string annotator = Annotator(im0, example=str(names), pil=True) # Print results diff --git a/detect.py b/detect.py index 1b26714bf2..71b5dab7f8 100644 --- a/detect.py +++ b/detect.py @@ -215,7 +215,7 @@ def run( p = Path(p) # to Path save_path = str(save_dir / p.name) # im.jpg txt_path = str(save_dir / "labels" / p.stem) + ("" if dataset.mode == "image" else f"_{frame}") # im.txt - s += "%gx%g " % im.shape[2:] # print string + s += "{:g}x{:g} ".format(*im.shape[2:]) # print string gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh imc = im0.copy() if save_crop else im0 # for save_crop annotator = Annotator(im0, line_width=line_thickness, example=str(names)) diff --git a/segment/predict.py b/segment/predict.py index 67b435e7fa..aa4d9a7f5c 100644 --- a/segment/predict.py +++ b/segment/predict.py @@ -164,7 +164,7 @@ def run( p = Path(p) # to Path save_path = str(save_dir / p.name) # im.jpg txt_path = str(save_dir / "labels" / p.stem) + ("" if dataset.mode == "image" else f"_{frame}") # im.txt - s += "%gx%g " % im.shape[2:] # print string + s += "{:g}x{:g} ".format(*im.shape[2:]) # print string imc = im0.copy() if save_crop else im0 # for save_crop annotator = Annotator(im0, line_width=line_thickness, example=str(names)) if len(det): diff --git a/utils/metrics.py b/utils/metrics.py index f79bdfbdc4..6324b76992 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -339,7 +339,7 @@ def plot_pr_curve(px, py, ap, save_dir=Path("pr_curve.png"), names=()): else: ax.plot(px, py, linewidth=1, color="grey") # plot(recall, precision) - ax.plot(px, py.mean(1), linewidth=3, color="blue", label="all classes %.3f mAP@0.5" % ap[:, 0].mean()) + ax.plot(px, py.mean(1), linewidth=3, color="blue", label=f"all classes {ap[:, 0].mean():.3f} mAP@0.5") ax.set_xlabel("Recall") ax.set_ylabel("Precision") ax.set_xlim(0, 1) From 9cab5d446b859fd5732252e766191ddc8784e1fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 11:11:38 +0200 Subject: [PATCH 1116/1185] Bump slackapi/slack-github-action from 1.26.0 to 1.27.0 in /.github/workflows (#2280) Bump slackapi/slack-github-action in /.github/workflows Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 1.26.0 to 1.27.0. - [Release notes](https://github.com/slackapi/slack-github-action/releases) - [Commits](https://github.com/slackapi/slack-github-action/compare/v1.26.0...v1.27.0) --- updated-dependencies: - dependency-name: slackapi/slack-github-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index aadb8b4d69..a0a477d698 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -115,7 +115,7 @@ jobs: steps: - name: Check for failure and notify if: (needs.Tests.result == 'failure' || needs.Tests.result == 'cancelled') && github.repository == 'ultralytics/yolov3' && (github.event_name == 'schedule' || github.event_name == 'push') - uses: slackapi/slack-github-action@v1.26.0 + uses: slackapi/slack-github-action@v1.27.0 with: payload: | {"text": " GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n"} From 3ca8abedaa683f002ca3c1954eaef6418c865a95 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Sep 2024 20:55:06 +0200 Subject: [PATCH 1117/1185] [Snyk] Fix for 2 vulnerabilities (#2281) * fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-TQDM-6807582 - https://snyk.io/vuln/SNYK-PYTHON-ZIPP-7430899 * Update requirements.txt --------- Co-authored-by: snyk-bot --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3f39dd7bd2..f1643aabfb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ scipy>=1.4.1 thop>=0.1.1 # FLOPs computation torch>=1.8.0 # see https://pytorch.org/get-started/locally (recommended) torchvision>=0.9.0 -tqdm>=4.64.0 +tqdm>=4.66.3 ultralytics>=8.2.34 # https://ultralytics.com # protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 From 58a62c2a13b372f6ab05a3717cdbaac61c40efec Mon Sep 17 00:00:00 2001 From: Ultralytics Assistant <135830346+UltralyticsAssistant@users.noreply.github.com> Date: Fri, 6 Sep 2024 03:53:39 +0800 Subject: [PATCH 1118/1185] Ultralytics Code Refactor https://ultralytics.com/actions (#2284) * Refactor code for speed and clarity * Auto-format by https://ultralytics.com/actions * Update README.md * Update README.zh-CN.md * Auto-format by https://ultralytics.com/actions * Auto-format by https://ultralytics.com/actions * Update README.md --------- Co-authored-by: Glenn Jocher --- CONTRIBUTING.md | 4 ++-- README.md | 20 ++++++++++---------- README.zh-CN.md | 20 ++++++++++---------- utils/flask_rest_api/README.md | 2 +- utils/loggers/clearml/README.md | 14 +++++++------- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0dbea33b38..ba0e248f12 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,10 +64,10 @@ When asking a question, people will be better able to provide help if you provid - ✅ **Complete** – Provide **all** parts someone else needs to reproduce your problem in the question itself - ✅ **Reproducible** – Test the code you're about to provide to make sure it reproduces the problem -In addition to the above requirements, for [Ultralytics](https://ultralytics.com/) to provide assistance your code should be: +In addition to the above requirements, for [Ultralytics](https://www.ultralytics.com/) to provide assistance your code should be: - ✅ **Current** – Verify that your code is up-to-date with the current GitHub [master](https://github.com/ultralytics/yolov5/tree/master), and if necessary `git pull` or `git clone` a new copy to ensure your problem has not already been resolved by previous commits. -- ✅ **Unmodified** – Your problem must be reproducible without any modifications to the codebase in this repository. [Ultralytics](https://ultralytics.com/) does not provide support for custom code ⚠️. +- ✅ **Unmodified** – Your problem must be reproducible without any modifications to the codebase in this repository. [Ultralytics](https://www.ultralytics.com/) does not provide support for custom code ⚠️. If you believe your problem meets all of the above criteria, please close this issue and raise a new one using the 🐛 **Bug Report** [template](https://github.com/ultralytics/yolov5/issues/new/choose) and provide a [minimum reproducible example](https://docs.ultralytics.com/help/minimum_reproducible_example/) to help us better understand and diagnose your problem. diff --git a/README.md b/README.md index 14bc041938..01bd24d056 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

-[中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [Türkçe](https://docs.ultralytics.com/tr/) | [Tiếng Việt](https://docs.ultralytics.com/vi/) | [العربية](https://docs.ultralytics.com/ar/) +[中文](https://docs.ultralytics.com/zh) | [한국어](https://docs.ultralytics.com/ko) | [日本語](https://docs.ultralytics.com/ja) | [Русский](https://docs.ultralytics.com/ru) | [Deutsch](https://docs.ultralytics.com/de) | [Français](https://docs.ultralytics.com/fr) | [Español](https://docs.ultralytics.com/es) | [Português](https://docs.ultralytics.com/pt) | [Türkçe](https://docs.ultralytics.com/tr) | [Tiếng Việt](https://docs.ultralytics.com/vi) | [العربية](https://docs.ultralytics.com/ar)
YOLOv3 CI @@ -22,7 +22,7 @@ YOLOv3 🚀 is the world's most loved vision AI, representing Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions! -To request an Enterprise License please complete the form at [Ultralytics Licensing](https://ultralytics.com/license). +To request an Enterprise License please complete the form at [Ultralytics Licensing](https://www.ultralytics.com/license).
Ultralytics GitHub @@ -180,13 +180,13 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
-| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | -| :--------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | -| Label and export your custom datasets directly to YOLOv3 for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | Automatically track, visualize and even remotely train YOLOv3 using [ClearML](https://cutt.ly/yolov5-readme-clearml) (open-source!) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet2) lets you save YOLOv3 models, resume training, and interactively visualise and debug predictions | Run YOLOv3 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | +| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | +| :--------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | +| Label and export your custom datasets directly to YOLOv3 for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | Automatically track, visualize and even remotely train YOLOv3 using [ClearML](https://clear.ml/) (open-source!) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet2) lets you save YOLOv3 models, resume training, and interactively visualise and debug predictions | Run YOLOv3 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | ##
Ultralytics HUB
-Experience seamless AI with [Ultralytics HUB](https://ultralytics.com/hub) ⭐, the all-in-one solution for data visualization, YOLO 🚀 model training and deployment, without any coding. Transform images into actionable insights and bring your AI visions to life with ease using our cutting-edge platform and user-friendly [Ultralytics App](https://ultralytics.com/app_install). Start your journey for **Free** now! +Experience seamless AI with [Ultralytics HUB](https://www.ultralytics.com/hub) ⭐, the all-in-one solution for data visualization, YOLO 🚀 model training and deployment, without any coding. Transform images into actionable insights and bring your AI visions to life with ease using our cutting-edge platform and user-friendly [Ultralytics App](https://www.ultralytics.com/app-install). Start your journey for **Free** now! @@ -429,7 +429,7 @@ Get started in seconds with our verified environments. Click each icon below for ##
Contribute
-We love your input! We want to make contributing to YOLOv3 as easy and transparent as possible. Please see our [Contributing Guide](https://docs.ultralytics.com/help/contributing/) to get started, and fill out the [YOLOv3 Survey](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to send us feedback on your experiences. Thank you to all our contributors! +We love your input! We want to make contributing to YOLOv3 as easy and transparent as possible. Please see our [Contributing Guide](https://docs.ultralytics.com/help/contributing/) to get started, and fill out the [YOLOv3 Survey](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to send us feedback on your experiences. Thank you to all our contributors! @@ -440,12 +440,12 @@ We love your input! We want to make contributing to YOLOv3 as easy and transpare Ultralytics offers two licensing options to accommodate diverse use cases: -- **AGPL-3.0 License**: This [OSI-approved](https://opensource.org/licenses/) open-source license is ideal for students and enthusiasts, promoting open collaboration and knowledge sharing. See the [LICENSE](https://github.com/ultralytics/yolov3/blob/master/LICENSE) file for more details. -- **Enterprise License**: Designed for commercial use, this license permits seamless integration of Ultralytics software and AI models into commercial goods and services, bypassing the open-source requirements of AGPL-3.0. If your scenario involves embedding our solutions into a commercial offering, reach out through [Ultralytics Licensing](https://ultralytics.com/license). +- **AGPL-3.0 License**: This [OSI-approved](https://opensource.org/license) open-source license is ideal for students and enthusiasts, promoting open collaboration and knowledge sharing. See the [LICENSE](https://github.com/ultralytics/yolov3/blob/master/LICENSE) file for more details. +- **Enterprise License**: Designed for commercial use, this license permits seamless integration of Ultralytics software and AI models into commercial goods and services, bypassing the open-source requirements of AGPL-3.0. If your scenario involves embedding our solutions into a commercial offering, reach out through [Ultralytics Licensing](https://www.ultralytics.com/license). ##
Contact
-For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues), and join our [Discord](https://ultralytics.com/discord) community for questions and discussions! +For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues), and join our [Discord](https://discord.com/invite/ultralytics) community for questions and discussions!
diff --git a/README.zh-CN.md b/README.zh-CN.md index 1fbd24a74c..f8121080ec 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -4,7 +4,7 @@

-[中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [Türkçe](https://docs.ultralytics.com/tr/) | [Tiếng Việt](https://docs.ultralytics.com/vi/) | [العربية](https://docs.ultralytics.com/ar/) +[中文](https://docs.ultralytics.com/zh) | [한국어](https://docs.ultralytics.com/ko) | [日本語](https://docs.ultralytics.com/ja) | [Русский](https://docs.ultralytics.com/ru) | [Deutsch](https://docs.ultralytics.com/de) | [Français](https://docs.ultralytics.com/fr) | [Español](https://docs.ultralytics.com/es) | [Português](https://docs.ultralytics.com/pt) | [Türkçe](https://docs.ultralytics.com/tr) | [Tiếng Việt](https://docs.ultralytics.com/vi) | [العربية](https://docs.ultralytics.com/ar)
YOLOv3 CI @@ -22,7 +22,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表文档 了解详细信息,在 GitHub 上提交问题以获得支持,并加入我们的 Discord 社区进行问题和讨论! -如需申请企业许可,请在 [Ultralytics Licensing](https://ultralytics.com/license) 处填写表格 +如需申请企业许可,请在 [Ultralytics Licensing](https://www.ultralytics.com/license) 处填写表格
@@ -180,13 +180,13 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
-| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | -| :--------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | -| 将您的自定义数据集进行标注并直接导出到 YOLOv3 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv3 [ClearML](https://cutt.ly/yolov5-readme-clearml)(开源!) | 永远免费,[Comet](https://bit.ly/yolov5-readme-comet2)可让您保存 YOLOv3 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv3 推理的速度最高可提高6倍 | +| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | +| :--------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | +| 将您的自定义数据集进行标注并直接导出到 YOLOv3 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv3 [ClearML](https://clear.ml/)(开源!) | 永远免费,[Comet](https://bit.ly/yolov5-readme-comet2)可让您保存 YOLOv3 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv3 推理的速度最高可提高6倍 | ##
Ultralytics HUB
-[Ultralytics HUB](https://ultralytics.com/hub) 是我们的⭐**新的**用于可视化数据集、训练 YOLOv3 🚀 模型并以无缝体验部署到现实世界的无代码解决方案。现在开始 **免费** 使用他! +[Ultralytics HUB](https://www.ultralytics.com/hub) 是我们的⭐**新的**用于可视化数据集、训练 YOLOv3 🚀 模型并以无缝体验部署到现实世界的无代码解决方案。现在开始 **免费** 使用他! @@ -430,7 +430,7 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu ##
贡献
-我们喜欢您的意见或建议!我们希望尽可能简单和透明地为 YOLOv3 做出贡献。请看我们的 [投稿指南](https://docs.ultralytics.com/help/contributing/),并填写 [YOLOv5调查](https://ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) 向我们发送您的体验反馈。感谢我们所有的贡献者! +我们喜欢您的意见或建议!我们希望尽可能简单和透明地为 YOLOv3 做出贡献。请看我们的 [投稿指南](https://docs.ultralytics.com/help/contributing/),并填写 [YOLOv5调查](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) 向我们发送您的体验反馈。感谢我们所有的贡献者! @@ -441,12 +441,12 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu Ultralytics 提供两种许可证选项以适应各种使用场景: -- **AGPL-3.0 许可证**:这个[OSI 批准](https://opensource.org/licenses/)的开源许可证非常适合学生和爱好者,可以推动开放的协作和知识分享。请查看[LICENSE](https://github.com/ultralytics/yolov3/blob/master/LICENSE) 文件以了解更多细节。 -- **企业许可证**:专为商业用途设计,该许可证允许将 Ultralytics 的软件和 AI 模型无缝集成到商业产品和服务中,从而绕过 AGPL-3.0 的开源要求。如果您的场景涉及将我们的解决方案嵌入到商业产品中,请通过 [Ultralytics Licensing](https://ultralytics.com/license)与我们联系。 +- **AGPL-3.0 许可证**:这个[OSI 批准](https://opensource.org/license)的开源许可证非常适合学生和爱好者,可以推动开放的协作和知识分享。请查看[LICENSE](https://github.com/ultralytics/yolov3/blob/master/LICENSE) 文件以了解更多细节。 +- **企业许可证**:专为商业用途设计,该许可证允许将 Ultralytics 的软件和 AI 模型无缝集成到商业产品和服务中,从而绕过 AGPL-3.0 的开源要求。如果您的场景涉及将我们的解决方案嵌入到商业产品中,请通过 [Ultralytics Licensing](https://www.ultralytics.com/license)与我们联系。 ##
联系方式
-对于 Ultralytics 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://ultralytics.com/discord) 社区进行问题和讨论! +对于 Ultralytics 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://discord.com/invite/ultralytics) 社区进行问题和讨论!
diff --git a/utils/flask_rest_api/README.md b/utils/flask_rest_api/README.md index b18a3011cf..d3ffaa2069 100644 --- a/utils/flask_rest_api/README.md +++ b/utils/flask_rest_api/README.md @@ -4,7 +4,7 @@ ## Requirements -[Flask](https://palletsprojects.com/p/flask/) is required. Install with: +[Flask](https://palletsprojects.com/projects/flask/) is required. Install with: ```shell $ pip install Flask diff --git a/utils/loggers/clearml/README.md b/utils/loggers/clearml/README.md index aff95d11a1..9ec33a39c6 100644 --- a/utils/loggers/clearml/README.md +++ b/utils/loggers/clearml/README.md @@ -4,7 +4,7 @@ ## About ClearML -[ClearML](https://cutt.ly/yolov5-tutorial-clearml) is an [open-source](https://github.com/allegroai/clearml) toolbox designed to save you time ⏱️. +[ClearML](https://clear.ml/) is an [open-source](https://github.com/allegroai/clearml) toolbox designed to save you time ⏱️. 🔨 Track every YOLOv5 training run in the experiment manager @@ -18,13 +18,13 @@ 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! -![ClearML scalars dashboard](https://github.com/thepycoder/clearml_screenshots/raw/main/experiment_manager_with_compare.gif) +![ClearML scalars dashboard](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/experiment_manager_with_compare.gif) ## 🦾 Setting Things Up To keep track of your experiments and/or data, ClearML needs to communicate to a server. You have 2 options to get one: -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! +Either sign up for free to the [ClearML Hosted Service](https://clear.ml/) 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! 1. Install the `clearml` python package: @@ -85,7 +85,7 @@ There even more we can do with all of this information, like hyperparameter opti Versioning your data separately from your code is generally a good idea and makes it easy to acquire 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! -![ClearML Dataset Interface](https://github.com/thepycoder/clearml_screenshots/raw/main/clearml_data.gif) +![ClearML Dataset Interface](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/clearml_data.gif) ### Prepare Your Dataset @@ -163,13 +163,13 @@ pip install optuna python utils/loggers/clearml/hpo.py ``` -![HPO](https://github.com/thepycoder/clearml_screenshots/raw/main/hpo.png) +![HPO](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/hpo.png) ## 🤯 Remote Execution (advanced) 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. This is where the ClearML Agent comes into play. Check out what the agent can do here: -- [YouTube video](https://youtu.be/MX3BrXnaULs) +- [YouTube video](https://www.youtube.com/watch?v=MX3BrXnaULs&feature=youtu.be) - [Documentation](https://clear.ml/docs/latest/docs/clearml_agent) 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. @@ -190,7 +190,7 @@ With our agent running, we can give it some work. Remember from the HPO section ⏳ Enqueue the task to any of the queues by right-clicking it -![Enqueue a task from the UI](https://github.com/thepycoder/clearml_screenshots/raw/main/enqueue.gif) +![Enqueue a task from the UI](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/enqueue.gif) ### Executing A Task Remotely From 854394ceec5b2e649e5d793c10461d77d6cd1fdb Mon Sep 17 00:00:00 2001 From: Ultralytics Assistant <135830346+UltralyticsAssistant@users.noreply.github.com> Date: Thu, 12 Sep 2024 19:41:21 +0200 Subject: [PATCH 1119/1185] Delete .github/workflows/greetings.yml (#2286) Delete greetings.yml --- .github/workflows/greetings.yml | 65 --------------------------------- 1 file changed, 65 deletions(-) delete mode 100644 .github/workflows/greetings.yml diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml deleted file mode 100644 index 6a4dd47701..0000000000 --- a/.github/workflows/greetings.yml +++ /dev/null @@ -1,65 +0,0 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license - -name: Greetings - -on: - pull_request_target: - types: [opened] - issues: - types: [opened] - -jobs: - greeting: - runs-on: ubuntu-latest - steps: - - uses: actions/first-interaction@v1 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - pr-message: | - 👋 Hello @${{ github.actor }}, thank you for submitting a YOLOv3 🚀 PR! To allow your work to be integrated as seamlessly as possible, we advise you to: - - - ✅ Verify your PR is **up-to-date** with `ultralytics/yolov3` `master` branch. If your PR is behind you can update your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally. - - ✅ Verify all YOLOv3 Continuous Integration (CI) **checks are passing**. - - ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ — Bruce Lee - - issue-message: | - 👋 Hello @${{ github.actor }}, thank you for your interest in YOLOv3 🚀! Please visit our ⭐️ [Tutorials](https://docs.ultralytics.com/yolov5/) to get started, where you can find quickstart guides for simple tasks like [Custom Data Training](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/) all the way to advanced concepts like [Hyperparameter Evolution](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution/). - - If this is a 🐛 Bug Report, please provide a **minimum reproducible example** to help us debug it. - - If this is a custom training ❓ Question, please provide as much information as possible, including dataset image examples and training logs, and verify you are following our [Tips for Best Training Results](https://docs.ultralytics.com/guides/model-training-tips//). - - ## Requirements - - [**Python>=3.7.0**](https://www.python.org/) with all [requirements.txt](https://github.com/ultralytics/yolov3/blob/master/requirements.txt) installed including [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). To get started: - ```bash - git clone https://github.com/ultralytics/yolov3 # clone - cd yolov3 - pip install -r requirements.txt # install - ``` - - ## Environments - - YOLOv3 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): - - - **Notebooks** with free GPU: Run on Gradient Open In Colab Open In Kaggle - - **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/) - - **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/) - - **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) Docker Pulls - - ## Status - - YOLOv3 CI - - If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/actions) Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv3 [training](https://github.com/ultralytics/yolov5/blob/master/train.py), [validation](https://github.com/ultralytics/yolov5/blob/master/val.py), [inference](https://github.com/ultralytics/yolov5/blob/master/detect.py), [export](https://github.com/ultralytics/yolov5/blob/master/export.py) and [benchmarks](https://github.com/ultralytics/yolov5/blob/master/benchmarks.py) on macOS, Windows, and Ubuntu every 24 hours and on every commit. - - ## Introducing YOLOv8 🚀 - - We're excited to announce the launch of our latest state-of-the-art (SOTA) object detection model for 2023 - [YOLOv8](https://github.com/ultralytics/ultralytics) 🚀! - - Designed to be fast, accurate, and easy to use, YOLOv8 is an ideal choice for a wide range of object detection, image segmentation and image classification tasks. With YOLOv8, you'll be able to quickly and accurately detect objects in real-time, streamline your workflows, and achieve new levels of accuracy in your projects. - - Check out our [YOLOv8 Docs](https://docs.ultralytics.com/) for details and get started with: - ```bash - pip install ultralytics - ``` From fe663f72a9944018e6775e75583f349595780ee2 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 16 Sep 2024 16:58:00 +0200 Subject: [PATCH 1120/1185] [Snyk] Fix for 17 vulnerabilities (#2283) * fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-FONTTOOLS-6133203 - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321964 - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321966 - https://snyk.io/vuln/SNYK-PYTHON-NUMPY-2321970 - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-5918878 - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-6043904 - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-6182918 - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-6219984 - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-6219986 - https://snyk.io/vuln/SNYK-PYTHON-PILLOW-6514866 - https://snyk.io/vuln/SNYK-PYTHON-REQUESTS-6928867 - https://snyk.io/vuln/SNYK-PYTHON-SETUPTOOLS-3180412 - https://snyk.io/vuln/SNYK-PYTHON-SETUPTOOLS-7448482 - https://snyk.io/vuln/SNYK-PYTHON-TORCH-6619806 - https://snyk.io/vuln/SNYK-PYTHON-TORCH-6649934 - https://snyk.io/vuln/SNYK-PYTHON-URLLIB3-7267250 - https://snyk.io/vuln/SNYK-PYTHON-WHEEL-3180413 * Update requirements.txt --------- Co-authored-by: snyk-bot --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f1643aabfb..c2dc8a08bf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ opencv-python>=4.1.1 Pillow>=10.3.0 psutil # system resources PyYAML>=5.3.1 -requests>=2.32.0 +requests>=2.32.2 scipy>=1.4.1 thop>=0.1.1 # FLOPs computation torch>=1.8.0 # see https://pytorch.org/get-started/locally (recommended) From 8882dca3295d241f1a758d344b204cd65327ca31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 12:17:13 +0200 Subject: [PATCH 1121/1185] Bump contributor-assistant/github-action from 2.5.1 to 2.5.2 in /.github/workflows (#2287) Bump contributor-assistant/github-action in /.github/workflows Bumps [contributor-assistant/github-action](https://github.com/contributor-assistant/github-action) from 2.5.1 to 2.5.2. - [Release notes](https://github.com/contributor-assistant/github-action/releases) - [Commits](https://github.com/contributor-assistant/github-action/compare/v2.5.1...v2.5.2) --- updated-dependencies: - dependency-name: contributor-assistant/github-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 53fbf400ef..e90494a0e8 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -26,7 +26,7 @@ jobs: steps: - name: CLA Assistant if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I sign the CLA') || github.event_name == 'pull_request_target' - uses: contributor-assistant/github-action@v2.5.1 + uses: contributor-assistant/github-action@v2.5.2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Must be repository secret PAT From e7310e705b259113127752871bb1ccbf42d14001 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:52:25 +0200 Subject: [PATCH 1122/1185] Bump contributor-assistant/github-action from 2.5.2 to 2.6.1 in /.github/workflows (#2288) Bump contributor-assistant/github-action in /.github/workflows Bumps [contributor-assistant/github-action](https://github.com/contributor-assistant/github-action) from 2.5.2 to 2.6.1. - [Release notes](https://github.com/contributor-assistant/github-action/releases) - [Commits](https://github.com/contributor-assistant/github-action/compare/v2.5.2...v2.6.1) --- updated-dependencies: - dependency-name: contributor-assistant/github-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index e90494a0e8..352e09efe5 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -26,7 +26,7 @@ jobs: steps: - name: CLA Assistant if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I sign the CLA') || github.event_name == 'pull_request_target' - uses: contributor-assistant/github-action@v2.5.2 + uses: contributor-assistant/github-action@v2.6.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Must be repository secret PAT From 7c2031969a946a49960e166934dfbf48fa1f3dfa Mon Sep 17 00:00:00 2001 From: Ultralytics Assistant <135830346+UltralyticsAssistant@users.noreply.github.com> Date: Sat, 5 Oct 2024 14:10:25 +0200 Subject: [PATCH 1123/1185] Ultralytics Code Refactor https://ultralytics.com/actions (#2289) Refactor code for speed and clarity --- README.md | 40 ++++++++++++++++++++-------------------- README.zh-CN.md | 40 ++++++++++++++++++++-------------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 01bd24d056..f197aba42c 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ To request an Enterprise License please complete the form at [Ultralytics Licens We are thrilled to announce the launch of Ultralytics YOLOv8 🚀, our NEW cutting-edge, state-of-the-art (SOTA) model released at **[https://github.com/ultralytics/ultralytics](https://github.com/ultralytics/ultralytics)**. YOLOv8 is designed to be fast, accurate, and easy to use, making it an excellent choice for a wide range of object detection, image segmentation and image classification tasks. -See the [YOLOv8 Docs](https://docs.ultralytics.com) for details and get started with: +See the [YOLOv8 Docs](https://docs.ultralytics.com/) for details and get started with: [![PyPI version](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![Downloads](https://static.pepy.tech/badge/ultralytics)](https://pepy.tech/project/ultralytics) @@ -61,7 +61,7 @@ pip install ultralytics ##
Documentation
-See the [YOLOv3 Docs](https://docs.ultralytics.com) for full documentation on training, testing and deployment. See below for quickstart examples. +See the [YOLOv3 Docs](https://docs.ultralytics.com/) for full documentation on training, testing and deployment. See below for quickstart examples.
Install @@ -79,7 +79,7 @@ pip install -r requirements.txt # install
Inference -YOLOv3 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) inference. [Models](https://github.com/ultralytics/yolov5/tree/master/models) download automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). +YOLOv3 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/) inference. [Models](https://github.com/ultralytics/yolov5/tree/master/models) download automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). ```python import torch @@ -122,7 +122,7 @@ python detect.py --weights yolov5s.pt --source 0 #
Training -The commands below reproduce YOLOv3 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) results. [Models](https://github.com/ultralytics/yolov5/tree/master/models) and [datasets](https://github.com/ultralytics/yolov5/tree/master/data) download automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). Training times for YOLOv5n/s/m/l/x are 1/2/4/6/8 days on a V100 GPU ([Multi-GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) times faster). Use the largest `--batch-size` possible, or pass `--batch-size -1` for YOLOv3 [AutoBatch](https://github.com/ultralytics/yolov5/pull/5092). Batch sizes shown for V100-16GB. +The commands below reproduce YOLOv3 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) results. [Models](https://github.com/ultralytics/yolov5/tree/master/models) and [datasets](https://github.com/ultralytics/yolov5/tree/master/data) download automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). Training times for YOLOv5n/s/m/l/x are 1/2/4/6/8 days on a V100 GPU ([Multi-GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/) times faster). Use the largest `--batch-size` possible, or pass `--batch-size -1` for YOLOv3 [AutoBatch](https://github.com/ultralytics/yolov5/pull/5092). Batch sizes shown for V100-16GB. ```bash python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml --batch-size 128 @@ -139,22 +139,22 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
Tutorials -- [Train Custom Data](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data) 🚀 RECOMMENDED +- [Train Custom Data](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/) 🚀 RECOMMENDED - [Tips for Best Training Results](https://docs.ultralytics.com/guides/model-training-tips/) ☘️ -- [Multi-GPU Training](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) -- [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) 🌟 NEW -- [TFLite, ONNX, CoreML, TensorRT Export](https://docs.ultralytics.com/yolov5/tutorials/model_export) 🚀 -- [NVIDIA Jetson platform Deployment](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano) 🌟 NEW -- [Test-Time Augmentation (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation) -- [Model Ensembling](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling) -- [Model Pruning/Sparsity](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity) -- [Hyperparameter Evolution](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution) -- [Transfer Learning with Frozen Layers](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers) -- [Architecture Summary](https://docs.ultralytics.com/yolov5/tutorials/architecture_description) 🌟 NEW -- [Roboflow for Datasets, Labeling, and Active Learning](https://docs.ultralytics.com/yolov5/tutorials/roboflow_datasets_integration) -- [ClearML Logging](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration) 🌟 NEW -- [YOLOv5 with Neural Magic's Deepsparse](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization) 🌟 NEW -- [Comet Logging](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration) 🌟 NEW +- [Multi-GPU Training](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/) +- [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/) 🌟 NEW +- [TFLite, ONNX, CoreML, TensorRT Export](https://docs.ultralytics.com/yolov5/tutorials/model_export/) 🚀 +- [NVIDIA Jetson platform Deployment](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano/) 🌟 NEW +- [Test-Time Augmentation (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/) +- [Model Ensembling](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling/) +- [Model Pruning/Sparsity](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity/) +- [Hyperparameter Evolution](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution/) +- [Transfer Learning with Frozen Layers](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers/) +- [Architecture Summary](https://docs.ultralytics.com/yolov5/tutorials/architecture_description/) 🌟 NEW +- [Roboflow for Datasets, Labeling, and Active Learning](https://docs.ultralytics.com/yolov5/tutorials/roboflow_datasets_integration/) +- [ClearML Logging](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration/) 🌟 NEW +- [YOLOv5 with Neural Magic's Deepsparse](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization/) 🌟 NEW +- [Comet Logging](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration/) 🌟 NEW
@@ -233,7 +233,7 @@ YOLOv3 has been designed to be super easy to get started and simple to learn. We - All checkpoints are trained to 300 epochs with default settings. Nano and Small models use [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) hyps, all others use [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml). - **mAPval** values are for single-model single-scale on [COCO val2017](http://cocodataset.org) dataset.
Reproduce by `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` - **Speed** averaged over COCO val images using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) instance. NMS times (~1 ms/img) not included.
Reproduce by `python val.py --data coco.yaml --img 640 --task speed --batch 1` -- **TTA** [Test Time Augmentation](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation) includes reflection and scale augmentations.
Reproduce by `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment` +- **TTA** [Test Time Augmentation](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/) includes reflection and scale augmentations.
Reproduce by `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment`
diff --git a/README.zh-CN.md b/README.zh-CN.md index f8121080ec..04c5d9b99d 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -46,7 +46,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表文档
-有关训练、测试和部署的完整文档见[YOLOv3 文档](https://docs.ultralytics.com)。请参阅下面的快速入门示例。 +有关训练、测试和部署的完整文档见[YOLOv3 文档](https://docs.ultralytics.com/)。请参阅下面的快速入门示例。
安装 @@ -79,7 +79,7 @@ pip install -r requirements.txt # install
推理 -使用 YOLOv3 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) 推理。最新 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 +使用 YOLOv3 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/) 推理。最新 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 ```python import torch @@ -122,7 +122,7 @@ python detect.py --weights yolov5s.pt --source 0 #
训练 -下面的命令重现 YOLOv3 在 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) 数据集上的结果。 最新的 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 和 [数据集](https://github.com/ultralytics/yolov5/tree/master/data) 将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 YOLOv5n/s/m/l/x 在 V100 GPU 的训练时间为 1/2/4/6/8 天( [多GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) 训练速度更快)。 尽可能使用更大的 `--batch-size` ,或通过 `--batch-size -1` 实现 YOLOv3 [自动批处理](https://github.com/ultralytics/yolov5/pull/5092) 。下方显示的 batchsize 适用于 V100-16GB。 +下面的命令重现 YOLOv3 在 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) 数据集上的结果。 最新的 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 和 [数据集](https://github.com/ultralytics/yolov5/tree/master/data) 将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 YOLOv5n/s/m/l/x 在 V100 GPU 的训练时间为 1/2/4/6/8 天( [多GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/) 训练速度更快)。 尽可能使用更大的 `--batch-size` ,或通过 `--batch-size -1` 实现 YOLOv3 [自动批处理](https://github.com/ultralytics/yolov5/pull/5092) 。下方显示的 batchsize 适用于 V100-16GB。 ```bash python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml --batch-size 128 @@ -139,22 +139,22 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
教程 -- [训练自定义数据](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data) 🚀 推荐 +- [训练自定义数据](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/) 🚀 推荐 - [获得最佳训练结果的技巧](https://docs.ultralytics.com/guides/model-training-tips/) ☘️ -- [多GPU训练](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training) -- [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading) 🌟 新 -- [TFLite,ONNX,CoreML,TensorRT导出](https://docs.ultralytics.com/yolov5/tutorials/model_export) 🚀 -- [NVIDIA Jetson平台部署](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano) 🌟 新 -- [测试时增强 (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation) -- [模型集成](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling) -- [模型剪枝/稀疏](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity) -- [超参数进化](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution) -- [冻结层的迁移学习](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers) -- [架构概述](https://docs.ultralytics.com/yolov5/tutorials/architecture_description) 🌟 新 -- [Roboflow用于数据集、标注和主动学习](https://docs.ultralytics.com/yolov5/tutorials/roboflow_datasets_integration) -- [ClearML日志记录](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration) 🌟 新 -- [使用Neural Magic的Deepsparse的YOLOv5](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization) 🌟 新 -- [Comet日志记录](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration) 🌟 新 +- [多GPU训练](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/) +- [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/) 🌟 新 +- [TFLite,ONNX,CoreML,TensorRT导出](https://docs.ultralytics.com/yolov5/tutorials/model_export/) 🚀 +- [NVIDIA Jetson平台部署](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano/) 🌟 新 +- [测试时增强 (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/) +- [模型集成](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling/) +- [模型剪枝/稀疏](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity/) +- [超参数进化](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution/) +- [冻结层的迁移学习](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers/) +- [架构概述](https://docs.ultralytics.com/yolov5/tutorials/architecture_description/) 🌟 新 +- [Roboflow用于数据集、标注和主动学习](https://docs.ultralytics.com/yolov5/tutorials/roboflow_datasets_integration/) +- [ClearML日志记录](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration/) 🌟 新 +- [使用Neural Magic的Deepsparse的YOLOv5](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization/) 🌟 新 +- [Comet日志记录](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration/) 🌟 新
@@ -233,7 +233,7 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结 - 所有模型都使用默认配置,训练 300 epochs。n和s模型使用 [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) ,其他模型都使用 [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml) 。 - \*\*mAPval\*\*在单模型单尺度上计算,数据集使用 [COCO val2017](http://cocodataset.org) 。
复现命令 `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` - **推理速度**在 COCO val 图像总体时间上进行平均得到,测试环境使用[AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/)实例。 NMS 时间 (大约 1 ms/img) 不包括在内。
复现命令 `python val.py --data coco.yaml --img 640 --task speed --batch 1` -- **TTA** [测试时数据增强](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation) 包括反射和尺度变换。
复现命令 `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment` +- **TTA** [测试时数据增强](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/) 包括反射和尺度变换。
复现命令 `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment`
From 95971f472293fb16079f63bd8a67d85cbcb29c43 Mon Sep 17 00:00:00 2001 From: Ultralytics Assistant <135830346+UltralyticsAssistant@users.noreply.github.com> Date: Sat, 5 Oct 2024 14:27:48 +0200 Subject: [PATCH 1124/1185] Ultralytics Code Refactor https://ultralytics.com/actions (#2290) Refactor code for speed and clarity --- README.md | 22 +++++++++++----------- README.zh-CN.md | 22 +++++++++++----------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index f197aba42c..d5f8b3d43e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- +

@@ -10,7 +10,7 @@ YOLOv3 CI YOLOv3 Citation Docker Pulls - Discord Ultralytics Forums Ultralytics Reddit + Discord Ultralytics Forums Ultralytics Reddit
Run on Gradient Open In Colab @@ -18,9 +18,9 @@

-YOLOv3 🚀 is the world's most loved vision AI, representing Ultralytics open-source research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours of research and development. +YOLOv3 🚀 is the world's most loved vision AI, representing Ultralytics open-source research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours of research and development. -We hope that the resources here will help you get the most out of YOLOv3. Please browse the YOLOv3 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions! +We hope that the resources here will help you get the most out of YOLOv3. Please browse the YOLOv3 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions! To request an Enterprise License please complete the form at [Ultralytics Licensing](https://www.ultralytics.com/license). @@ -37,7 +37,7 @@ To request an Enterprise License please complete the form at [Ultralytics Licens Ultralytics BiliBili - Ultralytics Discord + Ultralytics Discord

@@ -55,7 +55,7 @@ pip install ultralytics ``` @@ -161,7 +161,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - ##
Integrations

- +

@@ -170,7 +170,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - - + @@ -188,7 +188,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - Experience seamless AI with [Ultralytics HUB](https://www.ultralytics.com/hub) ⭐, the all-in-one solution for data visualization, YOLO 🚀 model training and deployment, without any coding. Transform images into actionable insights and bring your AI visions to life with ease using our cutting-edge platform and user-friendly [Ultralytics App](https://www.ultralytics.com/app-install). Start your journey for **Free** now! - + ##
Why YOLOv3
@@ -245,7 +245,7 @@ Our new YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7. Segmentation Checkpoints
- +
@@ -461,7 +461,7 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/ Ultralytics BiliBili - Ultralytics Discord + Ultralytics Discord
[tta]: https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation diff --git a/README.zh-CN.md b/README.zh-CN.md index 04c5d9b99d..d2bd6e0473 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,6 +1,6 @@

- +

@@ -10,7 +10,7 @@ YOLOv3 CI YOLOv3 Citation Docker Pulls - Discord Ultralytics Forums Ultralytics Reddit + Discord Ultralytics Forums Ultralytics Reddit
Run on Gradient Open In Colab @@ -18,9 +18,9 @@

-YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics 对未来视觉 AI 方法的开源研究,结合在数千小时的研究和开发中积累的经验教训和最佳实践。 +YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics 对未来视觉 AI 方法的开源研究,结合在数千小时的研究和开发中积累的经验教训和最佳实践。 -我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 YOLOv3 文档 了解详细信息,在 GitHub 上提交问题以获得支持,并加入我们的 Discord 社区进行问题和讨论! +我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 YOLOv3 文档 了解详细信息,在 GitHub 上提交问题以获得支持,并加入我们的 Discord 社区进行问题和讨论! 如需申请企业许可,请在 [Ultralytics Licensing](https://www.ultralytics.com/license) 处填写表格 @@ -38,7 +38,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics BiliBili - Ultralytics Discord + Ultralytics Discord @@ -55,7 +55,7 @@ pip install ultralytics ``` @@ -161,7 +161,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - ##
模块集成

- +

@@ -170,7 +170,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - - + @@ -188,7 +188,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - [Ultralytics HUB](https://www.ultralytics.com/hub) 是我们的⭐**新的**用于可视化数据集、训练 YOLOv3 🚀 模型并以无缝体验部署到现实世界的无代码解决方案。现在开始 **免费** 使用他! - + ##
为什么选择 YOLOv3
@@ -247,7 +247,7 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结
- +
@@ -462,7 +462,7 @@ Ultralytics 提供两种许可证选项以适应各种使用场景: Ultralytics BiliBili - Ultralytics Discord + Ultralytics Discord [tta]: https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation From 9cb2d1f4cd048b8c00462ab9efbbfe9b858cd63c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 11 Oct 2024 15:06:51 +0200 Subject: [PATCH 1125/1185] Update codeql-analysis.yml (#2291) --- .github/workflows/codeql-analysis.yml | 36 ++++++++------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index cece81c8c3..e6e3e85d3c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,26 +1,26 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license -# This action runs GitHub's industry-leading static analysis engine, CodeQL, against a repository's source code to find security vulnerabilities. -# https://github.com/github/codeql-action +# Ultralytics YOLO 🚀, AGPL-3.0 license name: "CodeQL" on: schedule: - - cron: "0 0 1 * *" # Runs at 00:00 UTC on the 1st of every month + - cron: "0 0 1 * *" workflow_dispatch: jobs: analyze: name: Analyze - runs-on: ubuntu-latest + runs-on: ${{ 'ubuntu-latest' }} + permissions: + actions: read + contents: read + security-events: write strategy: fail-fast: false matrix: language: ["python"] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] steps: - name: Checkout repository @@ -34,23 +34,9 @@ jobs: # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v3 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release + # queries: security-extended,security-and-quality - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" From b2abc0afa3da5caac92e2b8c83081e9c38598f82 Mon Sep 17 00:00:00 2001 From: Ultralytics Assistant <135830346+UltralyticsAssistant@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:03:05 +0200 Subject: [PATCH 1126/1185] Ultralytics Code Refactor https://ultralytics.com/actions (#2292) Refactor code for speed and clarity --- .github/workflows/cla.yml | 2 +- .github/workflows/format.yml | 5 ++--- .github/workflows/merge-main-into-prs.yml | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 352e09efe5..b122d5f722 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -30,7 +30,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Must be repository secret PAT - PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + PERSONAL_ACCESS_TOKEN: ${{ secrets._GITHUB_TOKEN }} with: path-to-signatures: "signatures/version1/cla.json" path-to-document: "https://docs.ultralytics.com/help/CLA" # CLA document diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index b326e778da..bcc9609092 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -18,12 +18,11 @@ jobs: - name: Run Ultralytics Formatting uses: ultralytics/actions@main with: - token: ${{ secrets.PERSONAL_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} # note GITHUB_TOKEN automatically generated + token: ${{ secrets._GITHUB_TOKEN }} # note GITHUB_TOKEN automatically generated labels: true # autolabel issues and PRs python: true # format Python code and docstrings prettier: true # format YAML, JSON, Markdown and CSS spelling: true # check spelling links: false # check broken links summary: true # print PR summary with GPT4o (requires 'openai_api_key') - openai_azure_api_key: ${{ secrets.OPENAI_AZURE_API_KEY }} - openai_azure_endpoint: ${{ secrets.OPENAI_AZURE_ENDPOINT }} + openai_api_key: ${{ secrets.OPENAI_API_KEY }} diff --git a/.github/workflows/merge-main-into-prs.yml b/.github/workflows/merge-main-into-prs.yml index 372d888241..82f113c548 100644 --- a/.github/workflows/merge-main-into-prs.yml +++ b/.github/workflows/merge-main-into-prs.yml @@ -67,5 +67,5 @@ jobs: print(f"❌ Could not process PR #{pr.number}: {e}") env: - GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} From 8ce945291a0ab95184e4e0078c32fb37ab1d157a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 17 Oct 2024 19:17:56 +0200 Subject: [PATCH 1127/1185] Update Integrations table (#2293) * Update README.md * Update README.zh-CN.md * Auto-format by https://ultralytics.com/actions * Auto-format by https://ultralytics.com/actions * Update README.zh-CN.md --------- Co-authored-by: UltralyticsAssistant --- README.md | 32 +++++++++++++++++--------------- README.zh-CN.md | 34 ++++++++++++++++++---------------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index d5f8b3d43e..1b994effbb 100644 --- a/README.md +++ b/README.md @@ -160,29 +160,31 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - ##
Integrations
+Our key integrations with leading AI platforms extend the functionality of Ultralytics' offerings, enhancing tasks like dataset labeling, training, visualization, and model management. Discover how Ultralytics, in collaboration with [W&B](https://docs.wandb.ai/guides/integrations/ultralytics/), [Comet](https://bit.ly/yolov8-readme-comet), [Roboflow](https://roboflow.com/?ref=ultralytics) and [OpenVINO](https://docs.ultralytics.com/integrations/openvino/), can optimize your AI workflow. +
- - + +Ultralytics active learning integrations

- - - - - - - - - + + Ultralytics HUB logo + space + + ClearML logo + space + + Comet ML logo + space - + NeuralMagic logo
-| Roboflow | ClearML ⭐ NEW | Comet ⭐ NEW | Neural Magic ⭐ NEW | -| :--------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | -| Label and export your custom datasets directly to YOLOv3 for training with [Roboflow](https://roboflow.com/?ref=ultralytics) | Automatically track, visualize and even remotely train YOLOv3 using [ClearML](https://clear.ml/) (open-source!) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet2) lets you save YOLOv3 models, resume training, and interactively visualise and debug predictions | Run YOLOv3 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | +| Ultralytics HUB 🚀 | W&B | Comet ⭐ NEW | Neural Magic | +| :----------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | +| Streamline YOLO workflows: Label, train, and deploy effortlessly with [Ultralytics HUB](https://ultralytics.com/hub). Try now! | Track experiments, hyperparameters, and results with [Weights & Biases](https://docs.wandb.ai/guides/integrations/ultralytics/) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet) lets you save YOLO models, resume training, and interactively visualize and debug predictions | Run YOLO11 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | ##
Ultralytics HUB
diff --git a/README.zh-CN.md b/README.zh-CN.md index d2bd6e0473..ef7cd7abcd 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -158,31 +158,33 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
-##
模块集成
+##
集成
+ +我们与领先的 AI 平台的关键集成扩展了 Ultralytics 产品的功能,提升了数据集标注、训练、可视化和模型管理等任务。探索 Ultralytics 如何通过与 [W&B](https://docs.wandb.ai/guides/integrations/ultralytics/)、[Comet](https://bit.ly/yolov8-readme-comet)、[Roboflow](https://roboflow.com/?ref=ultralytics) 和 [OpenVINO](https://docs.ultralytics.com/integrations/openvino/) 的合作,优化您的 AI 工作流程。
- - + +Ultralytics active learning integrations

- - - - - - - - - + + Ultralytics HUB logo + space + + W&B logo + space + + Comet ML logo + space - + NeuralMagic logo
-| Roboflow | ClearML ⭐ 新 | Comet ⭐ 新 | Neural Magic ⭐ 新 | -| :--------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | -| 将您的自定义数据集进行标注并直接导出到 YOLOv3 以进行训练 [Roboflow](https://roboflow.com/?ref=ultralytics) | 自动跟踪、可视化甚至远程训练 YOLOv3 [ClearML](https://clear.ml/)(开源!) | 永远免费,[Comet](https://bit.ly/yolov5-readme-comet2)可让您保存 YOLOv3 模型、恢复训练以及交互式可视化和调试预测 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic),运行 YOLOv3 推理的速度最高可提高6倍 | +| Ultralytics HUB 🚀 | W&B | Comet ⭐ 全新 | Neural Magic | +| :------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------: | +| 简化 YOLO 工作流程:通过 [Ultralytics HUB](https://ultralytics.com/hub) 轻松标注、训练和部署。立即试用! | 使用 [Weights & Biases](https://docs.wandb.ai/guides/integrations/ultralytics/) 跟踪实验、超参数和结果 | 永久免费,[Comet](https://bit.ly/yolov5-readme-comet) 允许您保存 YOLO11 模型、恢复训练,并交互式地可视化和调试预测结果 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) 运行 YOLO11 推理,速度提升至 6 倍 | ##
Ultralytics HUB
From 6de8aa6d2c799c2fec03a56c1fb0e2f6df394d29 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 17 Oct 2024 19:35:22 +0200 Subject: [PATCH 1128/1185] Update README.md (#2294) * Update README.md * Update README.zh-CN.md * Update ci-testing.yml --- .github/workflows/ci-testing.yml | 6 +++--- README.md | 2 +- README.zh-CN.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index a0a477d698..ba6cee9723 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -23,9 +23,9 @@ jobs: python-version: ["3.11"] model: [yolov5n] include: - - os: ubuntu-latest - python-version: "3.8" # '3.6.8' min - model: yolov5n + # - os: ubuntu-latest + # python-version: "3.8" # '3.6.8' min (warning, this test is failing) + # model: yolov5n - os: ubuntu-latest python-version: "3.9" model: yolov5n diff --git a/README.md b/README.md index 1b994effbb..fc5b50ffb1 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ Our key integrations with leading AI platforms extend the functionality of Ultra Ultralytics HUB logo space - + ClearML logo space diff --git a/README.zh-CN.md b/README.zh-CN.md index ef7cd7abcd..91aa2f4bb8 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -172,7 +172,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - Ultralytics HUB logo space - + W&B logo space From 94e72a299c578962261faac4e50b4f64e11bef7e Mon Sep 17 00:00:00 2001 From: Ultralytics Assistant <135830346+UltralyticsAssistant@users.noreply.github.com> Date: Sat, 19 Oct 2024 17:45:48 +0200 Subject: [PATCH 1129/1185] Ultralytics Refactor https://ultralytics.com/actions (#2295) * Refactor code for speed and clarity * Auto-format by https://ultralytics.com/actions --- README.md | 10 +++++----- README.zh-CN.md | 10 +++++----- classify/tutorial.ipynb | 4 ++-- data/coco128-seg.yaml | 2 +- data/coco128.yaml | 2 +- segment/tutorial.ipynb | 6 +++--- tutorial.ipynb | 6 +++--- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index fc5b50ffb1..68a54593b1 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@
Run on Gradient Open In Colab - Open In Kaggle + Open In Kaggle
@@ -182,9 +182,9 @@ Our key integrations with leading AI platforms extend the functionality of Ultra NeuralMagic logo -| Ultralytics HUB 🚀 | W&B | Comet ⭐ NEW | Neural Magic | -| :----------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | -| Streamline YOLO workflows: Label, train, and deploy effortlessly with [Ultralytics HUB](https://ultralytics.com/hub). Try now! | Track experiments, hyperparameters, and results with [Weights & Biases](https://docs.wandb.ai/guides/integrations/ultralytics/) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet) lets you save YOLO models, resume training, and interactively visualize and debug predictions | Run YOLO11 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | +| Ultralytics HUB 🚀 | W&B | Comet ⭐ NEW | Neural Magic | +| :--------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | +| Streamline YOLO workflows: Label, train, and deploy effortlessly with [Ultralytics HUB](https://www.ultralytics.com/hub). Try now! | Track experiments, hyperparameters, and results with [Weights & Biases](https://docs.wandb.ai/guides/integrations/ultralytics/) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet) lets you save YOLO models, resume training, and interactively visualize and debug predictions | Run YOLO11 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | ##
Ultralytics HUB
@@ -416,7 +416,7 @@ Get started in seconds with our verified environments. Click each icon below for - + diff --git a/README.zh-CN.md b/README.zh-CN.md index 91aa2f4bb8..d763a30a65 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -14,7 +14,7 @@
Run on Gradient Open In Colab - Open In Kaggle + Open In Kaggle
@@ -182,9 +182,9 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - NeuralMagic logo -| Ultralytics HUB 🚀 | W&B | Comet ⭐ 全新 | Neural Magic | -| :------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------: | -| 简化 YOLO 工作流程:通过 [Ultralytics HUB](https://ultralytics.com/hub) 轻松标注、训练和部署。立即试用! | 使用 [Weights & Biases](https://docs.wandb.ai/guides/integrations/ultralytics/) 跟踪实验、超参数和结果 | 永久免费,[Comet](https://bit.ly/yolov5-readme-comet) 允许您保存 YOLO11 模型、恢复训练,并交互式地可视化和调试预测结果 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) 运行 YOLO11 推理,速度提升至 6 倍 | +| Ultralytics HUB 🚀 | W&B | Comet ⭐ 全新 | Neural Magic | +| :----------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------: | +| 简化 YOLO 工作流程:通过 [Ultralytics HUB](https://www.ultralytics.com/hub) 轻松标注、训练和部署。立即试用! | 使用 [Weights & Biases](https://docs.wandb.ai/guides/integrations/ultralytics/) 跟踪实验、超参数和结果 | 永久免费,[Comet](https://bit.ly/yolov5-readme-comet) 允许您保存 YOLO11 模型、恢复训练,并交互式地可视化和调试预测结果 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) 运行 YOLO11 推理,速度提升至 6 倍 | ##
Ultralytics HUB
@@ -417,7 +417,7 @@ python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --inclu - + diff --git a/classify/tutorial.ipynb b/classify/tutorial.ipynb index 3252daf718..8b819639a7 100644 --- a/classify/tutorial.ipynb +++ b/classify/tutorial.ipynb @@ -15,7 +15,7 @@ "
\n", "
\"Run\n", " \"Open\n", - " \"Open\n", + " \"Open\n", "
\n", "\n", "This YOLOv5 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", @@ -1410,7 +1410,7 @@ "\n", "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):\n", "\n", - "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", + "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)\n", "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)\n", "- **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) \"Docker\n" diff --git a/data/coco128-seg.yaml b/data/coco128-seg.yaml index 363ced868a..6509214555 100644 --- a/data/coco128-seg.yaml +++ b/data/coco128-seg.yaml @@ -1,5 +1,5 @@ # Ultralytics YOLOv3 🚀, AGPL-3.0 license -# COCO128-seg dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics +# COCO128-seg dataset https://www.kaggle.com/datasets/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics # Example usage: python train.py --data coco128.yaml # parent # ├── yolov5 diff --git a/data/coco128.yaml b/data/coco128.yaml index 4bfbf3a2eb..78d1545c10 100644 --- a/data/coco128.yaml +++ b/data/coco128.yaml @@ -1,5 +1,5 @@ # Ultralytics YOLOv3 🚀, AGPL-3.0 license -# COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics +# COCO128 dataset https://www.kaggle.com/datasets/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics # Example usage: python train.py --data coco128.yaml # parent # ├── yolov5 diff --git a/segment/tutorial.ipynb b/segment/tutorial.ipynb index 55eaa254a1..1c364d6abe 100644 --- a/segment/tutorial.ipynb +++ b/segment/tutorial.ipynb @@ -15,7 +15,7 @@ "
\n", " \"Run\n", " \"Open\n", - " \"Open\n", + " \"Open\n", "
\n", "\n", "This YOLOv5 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", @@ -222,7 +222,7 @@ "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", "

\n", "\n", - "Train a YOLOv5s-seg model on the [COCO128](https://www.kaggle.com/ultralytics/coco128) dataset with `--data coco128-seg.yaml`, starting from pretrained `--weights yolov5s-seg.pt`, or from randomly initialized `--weights '' --cfg yolov5s-seg.yaml`.\n", + "Train a YOLOv5s-seg model on the [COCO128](https://www.kaggle.com/datasets/ultralytics/coco128) dataset with `--data coco128-seg.yaml`, starting from pretrained `--weights yolov5s-seg.pt`, or from randomly initialized `--weights '' --cfg yolov5s-seg.yaml`.\n", "\n", "- **Pretrained [Models](https://github.com/ultralytics/yolov5/tree/master/models)** are downloaded\n", "automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases)\n", @@ -523,7 +523,7 @@ "\n", "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):\n", "\n", - "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", + "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)\n", "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)\n", "- **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) \"Docker\n" diff --git a/tutorial.ipynb b/tutorial.ipynb index 783c5ef718..9e688bfe76 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -28,7 +28,7 @@ "
\n", " \"Run\n", " \"Open\n", - " \"Open\n", + " \"Open\n", "
\n", "\n", "This YOLOv5 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
We hope that the resources in this notebook will help you get the most out of YOLOv5. Please browse the YOLOv5 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions!\n", @@ -258,7 +258,7 @@ "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", "

\n", "\n", - "Train a YOLOv5s model on the [COCO128](https://www.kaggle.com/ultralytics/coco128) dataset with `--data coco128.yaml`, starting from pretrained `--weights yolov5s.pt`, or from randomly initialized `--weights '' --cfg yolov5s.yaml`.\n", + "Train a YOLOv5s model on the [COCO128](https://www.kaggle.com/datasets/ultralytics/coco128) dataset with `--data coco128.yaml`, starting from pretrained `--weights yolov5s.pt`, or from randomly initialized `--weights '' --cfg yolov5s.yaml`.\n", "\n", "- **Pretrained [Models](https://github.com/ultralytics/yolov5/tree/master/models)** are downloaded\n", "automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases)\n", @@ -554,7 +554,7 @@ "\n", "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):\n", "\n", - "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", + "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)\n", "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)\n", "- **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) \"Docker\n" From 0d26f5c2f5976d11f4e8eec64ef9eac58f7c7682 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 22 Oct 2024 19:23:44 +0200 Subject: [PATCH 1130/1185] Update README.md with YOLO11 section (#2296) * Update README.md * Remove Hindi links * Auto-format by https://ultralytics.com/actions * Update YOLO11 --------- Co-authored-by: UltralyticsAssistant --- README.md | 14 +++++++------- README.zh-CN.md | 32 ++++++++++++++++---------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 68a54593b1..fb71f0fbdf 100644 --- a/README.md +++ b/README.md @@ -42,11 +42,11 @@ To request an Enterprise License please complete the form at [Ultralytics Licens
-##
YOLOv8 🚀 NEW
+##
YOLO11 🚀 NEW
-We are thrilled to announce the launch of Ultralytics YOLOv8 🚀, our NEW cutting-edge, state-of-the-art (SOTA) model released at **[https://github.com/ultralytics/ultralytics](https://github.com/ultralytics/ultralytics)**. YOLOv8 is designed to be fast, accurate, and easy to use, making it an excellent choice for a wide range of object detection, image segmentation and image classification tasks. +We are excited to unveil the launch of Ultralytics YOLO11 🚀, the latest advancement in our state-of-the-art (SOTA) vision models! Available now at **[GitHub](https://github.com/ultralytics/ultralytics)**, YOLO11 builds on our legacy of speed, precision, and ease of use. Whether you're tackling object detection, image segmentation, or image classification, YOLO11 delivers the performance and versatility needed to excel in diverse applications. -See the [YOLOv8 Docs](https://docs.ultralytics.com/) for details and get started with: +Get started today and unlock the full potential of YOLO11! Visit the [Ultralytics Docs](https://docs.ultralytics.com/) for comprehensive guides and resources: [![PyPI version](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![Downloads](https://static.pepy.tech/badge/ultralytics)](https://pepy.tech/project/ultralytics) @@ -56,7 +56,7 @@ pip install ultralytics
- +
##
Documentation
@@ -151,9 +151,9 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml - - [Hyperparameter Evolution](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution/) - [Transfer Learning with Frozen Layers](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers/) - [Architecture Summary](https://docs.ultralytics.com/yolov5/tutorials/architecture_description/) 🌟 NEW -- [Roboflow for Datasets, Labeling, and Active Learning](https://docs.ultralytics.com/yolov5/tutorials/roboflow_datasets_integration/) -- [ClearML Logging](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration/) 🌟 NEW -- [YOLOv5 with Neural Magic's Deepsparse](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization/) 🌟 NEW +- [Ultralytics HUB to train and deploy YOLO](https://www.ultralytics.com/hub) 🚀 RECOMMENDED +- [ClearML Logging](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration/) +- [YOLOv5 with Neural Magic's Deepsparse](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization/) - [Comet Logging](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration/) 🌟 NEW
diff --git a/README.zh-CN.md b/README.zh-CN.md index d763a30a65..041bf83bd1 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -42,21 +42,21 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表YOLOv8 🚀 新品 +##
YOLO11 🚀 全新发布
-我们很高兴宣布 Ultralytics YOLOv8 🚀 的发布,这是我们新推出的领先水平、最先进的(SOTA)模型,发布于 **[https://github.com/ultralytics/ultralytics](https://github.com/ultralytics/ultralytics)**。 YOLOv8 旨在快速、准确且易于使用,使其成为广泛的物体检测、图像分割和图像分类任务的极佳选择。 +我们很高兴宣布推出 Ultralytics YOLO11 🚀,这是我们最先进视觉模型的最新进展!现已在 **[GitHub](https://github.com/ultralytics/ultralytics)** 上发布。YOLO11 在速度、精度和易用性方面进一步提升,无论是处理目标检测、图像分割还是图像分类任务,YOLO11 都具备出色的性能和多功能性,助您在各种应用中脱颖而出。 -请查看 [YOLOv8 文档](https://docs.ultralytics.com/)了解详细信息,并开始使用: +立即开始,解锁 YOLO11 的全部潜力!访问 [Ultralytics 文档](https://docs.ultralytics.com/) 获取全面的指南和资源: [![PyPI 版本](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![下载量](https://static.pepy.tech/badge/ultralytics)](https://pepy.tech/project/ultralytics) -```commandline +```bash pip install ultralytics ```
##
文档
@@ -139,22 +139,22 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml -
教程 -- [训练自定义数据](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/) 🚀 推荐 -- [获得最佳训练结果的技巧](https://docs.ultralytics.com/guides/model-training-tips/) ☘️ +- [自定义数据训练](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/) 🚀 **推荐** +- [最佳训练效果的提示](https://docs.ultralytics.com/guides/model-training-tips/) ☘️ - [多GPU训练](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/) -- [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/) 🌟 新 -- [TFLite,ONNX,CoreML,TensorRT导出](https://docs.ultralytics.com/yolov5/tutorials/model_export/) 🚀 -- [NVIDIA Jetson平台部署](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano/) 🌟 新 +- [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/) 🌟 **全新** +- [TFLite, ONNX, CoreML, TensorRT 导出](https://docs.ultralytics.com/yolov5/tutorials/model_export/) 🚀 +- [NVIDIA Jetson 平台部署](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano/) 🌟 **全新** - [测试时增强 (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/) - [模型集成](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling/) -- [模型剪枝/稀疏](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity/) +- [模型剪枝/稀疏化](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity/) - [超参数进化](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution/) - [冻结层的迁移学习](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers/) -- [架构概述](https://docs.ultralytics.com/yolov5/tutorials/architecture_description/) 🌟 新 -- [Roboflow用于数据集、标注和主动学习](https://docs.ultralytics.com/yolov5/tutorials/roboflow_datasets_integration/) -- [ClearML日志记录](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration/) 🌟 新 -- [使用Neural Magic的Deepsparse的YOLOv5](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization/) 🌟 新 -- [Comet日志记录](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration/) 🌟 新 +- [架构概述](https://docs.ultralytics.com/yolov5/tutorials/architecture_description/) 🌟 **全新** +- [使用 Ultralytics HUB 进行 YOLO 训练和部署](https://www.ultralytics.com/hub) 🚀 **推荐** +- [ClearML 日志记录](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration/) +- [与 Neural Magic 的 Deepsparse 集成的 YOLOv5](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization/) +- [Comet 日志记录](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration/) 🌟 **全新**
From 033c5a95eb4ef3d9800f75b04bdf21988331c728 Mon Sep 17 00:00:00 2001 From: Paula Derrenger <107626595+pderrenger@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:19:11 +0100 Subject: [PATCH 1131/1185] Fix PyPI downloads links (#2298) Refactor code for speed and clarity Co-authored-by: UltralyticsAssistant --- README.md | 2 +- README.zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fb71f0fbdf..5e9aff2f68 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ We are excited to unveil the launch of Ultralytics YOLO11 🚀, the latest advan Get started today and unlock the full potential of YOLO11! Visit the [Ultralytics Docs](https://docs.ultralytics.com/) for comprehensive guides and resources: -[![PyPI version](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![Downloads](https://static.pepy.tech/badge/ultralytics)](https://pepy.tech/project/ultralytics) +[![PyPI version](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![Downloads](https://static.pepy.tech/badge/ultralytics)](https://www.pepy.tech/projects/ultralytics) ```bash pip install ultralytics diff --git a/README.zh-CN.md b/README.zh-CN.md index 041bf83bd1..edf06a51ec 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -48,7 +48,7 @@ YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Date: Tue, 19 Nov 2024 10:50:28 +0100 Subject: [PATCH 1134/1185] Bump slackapi/slack-github-action from 1.27.0 to 2.0.0 in /.github/workflows (#2302) Bump slackapi/slack-github-action in /.github/workflows Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 1.27.0 to 2.0.0. - [Release notes](https://github.com/slackapi/slack-github-action/releases) - [Commits](https://github.com/slackapi/slack-github-action/compare/v1.27.0...v2.0.0) --- updated-dependencies: - dependency-name: slackapi/slack-github-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index ba6cee9723..fc4a449dc2 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -115,7 +115,7 @@ jobs: steps: - name: Check for failure and notify if: (needs.Tests.result == 'failure' || needs.Tests.result == 'cancelled') && github.repository == 'ultralytics/yolov3' && (github.event_name == 'schedule' || github.event_name == 'push') - uses: slackapi/slack-github-action@v1.27.0 + uses: slackapi/slack-github-action@v2.0.0 with: payload: | {"text": " GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n"} From 47a65e30e5b37c16906a9b77ca19daf0b3c1fc6f Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 19 Nov 2024 10:52:49 +0100 Subject: [PATCH 1135/1185] Update ci-testing.yml (#2303) --- .github/workflows/ci-testing.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index fc4a449dc2..0b6f55b659 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -110,14 +110,14 @@ jobs: Summary: runs-on: ubuntu-latest - needs: [Tests] # Add job names that you want to check for failure - if: always() # This ensures the job runs even if previous jobs fail + needs: [Tests] + if: always() steps: - name: Check for failure and notify if: (needs.Tests.result == 'failure' || needs.Tests.result == 'cancelled') && github.repository == 'ultralytics/yolov3' && (github.event_name == 'schedule' || github.event_name == 'push') uses: slackapi/slack-github-action@v2.0.0 with: + webhook-type: incoming-webhook + webhook: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }} payload: | - {"text": " GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n"} - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }} + text: " GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n" From 44ad81cf43513a2e10a9b655c1ed6a856ea102b7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 25 Nov 2024 11:52:23 +0100 Subject: [PATCH 1136/1185] Delete .github/dependabot.yml (#2306) --- .github/dependabot.yml | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 34985ad6d9..0000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,27 +0,0 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license -# Dependabot for package version updates -# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - package-ecosystem: pip - directory: "/" - schedule: - interval: weekly - time: "04:00" - open-pull-requests-limit: 10 - reviewers: - - glenn-jocher - labels: - - dependencies - - - package-ecosystem: github-actions - directory: "/.github/workflows" - schedule: - interval: weekly - time: "04:00" - open-pull-requests-limit: 5 - reviewers: - - glenn-jocher - labels: - - dependencies From 300aa8433df719fbffe87900fa47d95d759abe72 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 25 Nov 2024 11:53:45 +0100 Subject: [PATCH 1137/1185] Delete .github/workflows/codeql-analysis.yml (#2307) --- .github/workflows/codeql-analysis.yml | 42 --------------------------- 1 file changed, 42 deletions(-) delete mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index e6e3e85d3c..0000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,42 +0,0 @@ -# Ultralytics YOLO 🚀, AGPL-3.0 license - -name: "CodeQL" - -on: - schedule: - - cron: "0 0 1 * *" - workflow_dispatch: - -jobs: - analyze: - name: Analyze - runs-on: ${{ 'ubuntu-latest' }} - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: ["python"] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: security-extended,security-and-quality - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:${{matrix.language}}" From 549240bf157693235dcb503537655bf0e712963a Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 7 Dec 2024 22:59:27 +0100 Subject: [PATCH 1138/1185] Update format.yml (#2308) Signed-off-by: Glenn Jocher --- .github/workflows/format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index bcc9609092..6c7981b71b 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -7,7 +7,7 @@ name: Ultralytics Actions on: issues: types: [opened] - pull_request_target: + pull_request: branches: [main, master] types: [opened, closed, synchronize, review_requested] From 08239577e859d37c9589ab6d1eba5e0d8bb66bb0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 25 Dec 2024 20:44:22 +0100 Subject: [PATCH 1139/1185] Update links.yml (#2310) * Update links.yml Signed-off-by: Glenn Jocher * Update links.yml Signed-off-by: Glenn Jocher --------- Signed-off-by: Glenn Jocher --- .github/workflows/links.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index fe8b5a6777..4ef9c55340 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -23,9 +23,7 @@ jobs: - name: Download and install lychee run: | LYCHEE_URL=$(curl -s https://api.github.com/repos/lycheeverse/lychee/releases/latest | grep "browser_download_url" | grep "x86_64-unknown-linux-gnu.tar.gz" | cut -d '"' -f 4) - curl -L $LYCHEE_URL -o lychee.tar.gz - tar xzf lychee.tar.gz - sudo mv lychee /usr/local/bin + curl -L $LYCHEE_URL | tar xz -C /usr/local/bin - name: Test Markdown and HTML links with retry uses: ultralytics/actions/retry@main From 39b54d3445755a6a4f2dfa78cf56d1ee72e04ea7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 6 Jan 2025 20:46:03 +0100 Subject: [PATCH 1140/1185] Update format.yml (#2311) Signed-off-by: Glenn Jocher --- .github/workflows/format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 6c7981b71b..d524d23fa1 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -18,7 +18,7 @@ jobs: - name: Run Ultralytics Formatting uses: ultralytics/actions@main with: - token: ${{ secrets._GITHUB_TOKEN }} # note GITHUB_TOKEN automatically generated + token: ${{ secrets._GITHUB_TOKEN || secrets.GITHUB_TOKEN}} labels: true # autolabel issues and PRs python: true # format Python code and docstrings prettier: true # format YAML, JSON, Markdown and CSS From 607097da6dde07fd3efbe7cdca6864e254cb833b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 6 Jan 2025 21:24:54 +0100 Subject: [PATCH 1141/1185] Ultralytics Refactor https://ultralytics.com/actions (#2312) Refactor code for speed and clarity Co-authored-by: UltralyticsAssistant --- .github/workflows/format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index d524d23fa1..790fa19527 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -18,7 +18,7 @@ jobs: - name: Run Ultralytics Formatting uses: ultralytics/actions@main with: - token: ${{ secrets._GITHUB_TOKEN || secrets.GITHUB_TOKEN}} + token: ${{ secrets._GITHUB_TOKEN || secrets.GITHUB_TOKEN }} labels: true # autolabel issues and PRs python: true # format Python code and docstrings prettier: true # format YAML, JSON, Markdown and CSS From a62c0f2b1b330632432ddc6aac9386b748aa1044 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Jan 2025 01:28:18 +0100 Subject: [PATCH 1142/1185] Apply `ruff==0.9.0` formatting (#2313) * Refactor code for speed and clarity * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: UltralyticsAssistant --- README.md | 4 ++-- README.zh-CN.md | 4 ++-- classify/predict.py | 2 +- classify/train.py | 16 ++++++++-------- detect.py | 2 +- export.py | 4 ++-- segment/predict.py | 2 +- segment/train.py | 12 ++++++------ train.py | 12 ++++++------ utils/augmentations.py | 10 +--------- utils/dataloaders.py | 13 +++++-------- utils/general.py | 9 ++++----- utils/loggers/clearml/clearml_utils.py | 8 +++----- utils/loggers/comet/__init__.py | 4 +--- utils/loggers/wandb/wandb_utils.py | 2 +- utils/loss.py | 7 +------ utils/segment/augmentations.py | 10 +--------- utils/segment/dataloaders.py | 5 ++--- utils/segment/loss.py | 3 +-- utils/torch_utils.py | 8 ++++---- 20 files changed, 53 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index 5e9aff2f68..6883ca2bab 100644 --- a/README.md +++ b/README.md @@ -207,7 +207,7 @@ YOLOv3 has been designed to be super easy to get started and simple to learn. We Figure Notes - **COCO AP val** denotes mAP@0.5:0.95 metric measured on the 5000-image [COCO val2017](http://cocodataset.org) dataset over various inference sizes from 256 to 1536. -- **GPU Speed** measures average inference time per image on [COCO val2017](http://cocodataset.org) dataset using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) V100 instance at batch-size 32. +- **GPU Speed** measures average inference time per image on [COCO val2017](http://cocodataset.org) dataset using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p4/) V100 instance at batch-size 32. - **EfficientDet** data from [google/automl](https://github.com/google/automl) at batch size 8. - **Reproduce** by `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt` @@ -234,7 +234,7 @@ YOLOv3 has been designed to be super easy to get started and simple to learn. We - All checkpoints are trained to 300 epochs with default settings. Nano and Small models use [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) hyps, all others use [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml). - **mAPval** values are for single-model single-scale on [COCO val2017](http://cocodataset.org) dataset.
Reproduce by `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` -- **Speed** averaged over COCO val images using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) instance. NMS times (~1 ms/img) not included.
Reproduce by `python val.py --data coco.yaml --img 640 --task speed --batch 1` +- **Speed** averaged over COCO val images using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p4/) instance. NMS times (~1 ms/img) not included.
Reproduce by `python val.py --data coco.yaml --img 640 --task speed --batch 1` - **TTA** [Test Time Augmentation](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/) includes reflection and scale augmentations.
Reproduce by `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment`
diff --git a/README.zh-CN.md b/README.zh-CN.md index edf06a51ec..33193409e3 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -207,7 +207,7 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结 图表笔记 - **COCO AP val** 表示 mAP@0.5:0.95 指标,在 [COCO val2017](http://cocodataset.org) 数据集的 5000 张图像上测得, 图像包含 256 到 1536 各种推理大小。 -- **显卡推理速度** 为在 [COCO val2017](http://cocodataset.org) 数据集上的平均推理时间,使用 [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/) V100实例,batchsize 为 32 。 +- **显卡推理速度** 为在 [COCO val2017](http://cocodataset.org) 数据集上的平均推理时间,使用 [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p4/) V100实例,batchsize 为 32 。 - **EfficientDet** 数据来自 [google/automl](https://github.com/google/automl) , batchsize 为32。 - **复现命令** 为 `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt` @@ -234,7 +234,7 @@ YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结 - 所有模型都使用默认配置,训练 300 epochs。n和s模型使用 [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) ,其他模型都使用 [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml) 。 - \*\*mAPval\*\*在单模型单尺度上计算,数据集使用 [COCO val2017](http://cocodataset.org) 。
复现命令 `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` -- **推理速度**在 COCO val 图像总体时间上进行平均得到,测试环境使用[AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p3/)实例。 NMS 时间 (大约 1 ms/img) 不包括在内。
复现命令 `python val.py --data coco.yaml --img 640 --task speed --batch 1` +- **推理速度**在 COCO val 图像总体时间上进行平均得到,测试环境使用[AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p4/)实例。 NMS 时间 (大约 1 ms/img) 不包括在内。
复现命令 `python val.py --data coco.yaml --img 640 --task speed --batch 1` - **TTA** [测试时数据增强](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/) 包括反射和尺度变换。
复现命令 `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment`
diff --git a/classify/predict.py b/classify/predict.py index f0f8aadbad..e3ab6f4da8 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -192,7 +192,7 @@ def run( vid_writer[i].write(im0) # Print time (inference-only) - LOGGER.info(f"{s}{dt[1].dt * 1E3:.1f}ms") + LOGGER.info(f"{s}{dt[1].dt * 1e3:.1f}ms") # Print results t = tuple(x.t / seen * 1e3 for x in dt) # speeds per image diff --git a/classify/train.py b/classify/train.py index 9321a60bad..1ba22a58ed 100644 --- a/classify/train.py +++ b/classify/train.py @@ -203,10 +203,10 @@ def lf(x): scaler = amp.GradScaler(enabled=cuda) val = test_dir.stem # 'val' or 'test' LOGGER.info( - f'Image sizes {imgsz} train, {imgsz} test\n' - f'Using {nw * WORLD_SIZE} dataloader workers\n' + f"Image sizes {imgsz} train, {imgsz} test\n" + f"Using {nw * WORLD_SIZE} dataloader workers\n" f"Logging results to {colorstr('bold', save_dir)}\n" - f'Starting {opt.model} training on {data} dataset with {nc} classes for {epochs} epochs...\n\n' + f"Starting {opt.model} training on {data} dataset with {nc} classes for {epochs} epochs...\n\n" f"{'Epoch':>10}{'GPU_mem':>10}{'train_loss':>12}{f'{val}_loss':>12}{'top1_acc':>12}{'top5_acc':>12}" ) for epoch in range(epochs): # loop over the dataset multiple times @@ -292,13 +292,13 @@ def lf(x): # Train complete if RANK in {-1, 0} and final_epoch: LOGGER.info( - f'\nTraining complete ({(time.time() - t0) / 3600:.3f} hours)' + f"\nTraining complete ({(time.time() - t0) / 3600:.3f} hours)" f"\nResults saved to {colorstr('bold', save_dir)}" - f'\nPredict: python classify/predict.py --weights {best} --source im.jpg' - f'\nValidate: python classify/val.py --weights {best} --data {data_dir}' - f'\nExport: python export.py --weights {best} --include onnx' + f"\nPredict: python classify/predict.py --weights {best} --source im.jpg" + f"\nValidate: python classify/val.py --weights {best} --data {data_dir}" + f"\nExport: python export.py --weights {best} --include onnx" f"\nPyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', '{best}')" - f'\nVisualize: https://netron.app\n' + f"\nVisualize: https://netron.app\n" ) # Plot examples diff --git a/detect.py b/detect.py index 71b5dab7f8..ee789d34c8 100644 --- a/detect.py +++ b/detect.py @@ -273,7 +273,7 @@ def run( vid_writer[i].write(im0) # Print time (inference-only) - LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms") + LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1e3:.1f}ms") # Print results t = tuple(x.t / seen * 1e3 for x in dt) # speeds per image diff --git a/export.py b/export.py index 9c9a0d9a77..8d3802b348 100644 --- a/export.py +++ b/export.py @@ -1498,12 +1498,12 @@ def run( else "" ) LOGGER.info( - f'\nExport complete ({time.time() - t:.1f}s)' + f"\nExport complete ({time.time() - t:.1f}s)" f"\nResults saved to {colorstr('bold', file.parent.resolve())}" f"\nDetect: python {dir / ('detect.py' if det else 'predict.py')} --weights {f[-1]} {h}" f"\nValidate: python {dir / 'val.py'} --weights {f[-1]} {h}" f"\nPyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', '{f[-1]}') {s}" - f'\nVisualize: https://netron.app' + f"\nVisualize: https://netron.app" ) return f # return list of exported files/dirs diff --git a/segment/predict.py b/segment/predict.py index aa4d9a7f5c..60078b9691 100644 --- a/segment/predict.py +++ b/segment/predict.py @@ -245,7 +245,7 @@ def run( vid_writer[i].write(im0) # Print time (inference-only) - LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms") + LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1e3:.1f}ms") # Print results t = tuple(x.t / seen * 1e3 for x in dt) # speeds per image diff --git a/segment/train.py b/segment/train.py index 63f133d258..05e69285b9 100644 --- a/segment/train.py +++ b/segment/train.py @@ -323,10 +323,10 @@ def lf(x): compute_loss = ComputeLoss(model, overlap=overlap) # init loss class # callbacks.run('on_train_start') LOGGER.info( - f'Image sizes {imgsz} train, {imgsz} val\n' - f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' + f"Image sizes {imgsz} train, {imgsz} val\n" + f"Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n" f"Logging results to {colorstr('bold', save_dir)}\n" - f'Starting training for {epochs} epochs...' + f"Starting training for {epochs} epochs..." ) for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ # callbacks.run('on_train_epoch_start') @@ -403,7 +403,7 @@ def lf(x): # Log if RANK in {-1, 0}: mloss = (mloss * i + loss_items) / (i + 1) # update mean losses - mem = f"{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G" # (GB) + mem = f"{torch.cuda.memory_reserved() / 1e9 if torch.cuda.is_available() else 0:.3g}G" # (GB) pbar.set_description( ("%11s" * 2 + "%11.4g" * 6) % (f"{epoch}/{epochs - 1}", mem, *mloss, targets.shape[0], imgs.shape[-1]) @@ -736,9 +736,9 @@ def main(opt, callbacks=Callbacks()): # Plot results plot_evolve(evolve_csv) LOGGER.info( - f'Hyperparameter evolution finished {opt.evolve} generations\n' + f"Hyperparameter evolution finished {opt.evolve} generations\n" f"Results saved to {colorstr('bold', save_dir)}\n" - f'Usage example: $ python train.py --hyp {evolve_yaml}' + f"Usage example: $ python train.py --hyp {evolve_yaml}" ) diff --git a/train.py b/train.py index 4ea84a5667..e484b069a8 100644 --- a/train.py +++ b/train.py @@ -359,10 +359,10 @@ def lf(x): compute_loss = ComputeLoss(model) # init loss class callbacks.run("on_train_start") LOGGER.info( - f'Image sizes {imgsz} train, {imgsz} val\n' - f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' + f"Image sizes {imgsz} train, {imgsz} val\n" + f"Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n" f"Logging results to {colorstr('bold', save_dir)}\n" - f'Starting training for {epochs} epochs...' + f"Starting training for {epochs} epochs..." ) for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ callbacks.run("on_train_epoch_start") @@ -436,7 +436,7 @@ def lf(x): # Log if RANK in {-1, 0}: mloss = (mloss * i + loss_items) / (i + 1) # update mean losses - mem = f"{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G" # (GB) + mem = f"{torch.cuda.memory_reserved() / 1e9 if torch.cuda.is_available() else 0:.3g}G" # (GB) pbar.set_description( ("%11s" * 2 + "%11.4g" * 5) % (f"{epoch}/{epochs - 1}", mem, *mloss, targets.shape[0], imgs.shape[-1]) @@ -805,9 +805,9 @@ def main(opt, callbacks=Callbacks()): # Plot results plot_evolve(evolve_csv) LOGGER.info( - f'Hyperparameter evolution finished {opt.evolve} generations\n' + f"Hyperparameter evolution finished {opt.evolve} generations\n" f"Results saved to {colorstr('bold', save_dir)}\n" - f'Usage example: $ python train.py --hyp {evolve_yaml}' + f"Usage example: $ python train.py --hyp {evolve_yaml}" ) diff --git a/utils/augmentations.py b/utils/augmentations.py index cf11b0c525..662360d5c6 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -197,15 +197,7 @@ def random_perspective( else: # affine im = cv2.warpAffine(im, M[:2], dsize=(width, height), borderValue=(114, 114, 114)) - # Visualize - # import matplotlib.pyplot as plt - # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel() - # ax[0].imshow(im[:, :, ::-1]) # base - # ax[1].imshow(im2[:, :, ::-1]) # warped - - # Transform label coordinates - n = len(targets) - if n: + if n := len(targets): use_segments = any(x.any() for x in segments) and len(segments) == n new = np.zeros((n, 4)) if use_segments: # warp segments diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 4fef716250..7bebfdad36 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -317,8 +317,7 @@ def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vi else: self.cap = None assert self.nf > 0, ( - f"No images or videos found in {p}. " - f"Supported formats are:\nimages: {IMG_FORMATS}\nvideos: {VID_FORMATS}" + f"No images or videos found in {p}. Supported formats are:\nimages: {IMG_FORMATS}\nvideos: {VID_FORMATS}" ) def __iter__(self): @@ -667,8 +666,8 @@ def check_cache_ram(self, safety_margin=0.1, prefix=""): cache = mem_required * (1 + safety_margin) < mem.available # to cache or not to cache, that is the question if not cache: LOGGER.info( - f'{prefix}{mem_required / gb:.1f}GB RAM required, ' - f'{mem.available / gb:.1f}/{mem.total / gb:.1f}GB available, ' + f"{prefix}{mem_required / gb:.1f}GB RAM required, " + f"{mem.available / gb:.1f}/{mem.total / gb:.1f}GB available, " f"{'caching images ✅' if cache else 'not caching images ⚠️'}" ) return cache @@ -730,8 +729,7 @@ def __getitem__(self, index): index = self.indices[index] # linear, shuffled, or image_weights hyp = self.hyp - mosaic = self.mosaic and random.random() < hyp["mosaic"] - if mosaic: + if mosaic := self.mosaic and random.random() < hyp["mosaic"]: # Load mosaic img, labels = self.load_mosaic(index) shapes = None @@ -1109,8 +1107,7 @@ def verify_image_label(args): segments = [np.array(x[1:], dtype=np.float32).reshape(-1, 2) for x in lb] # (cls, xy1...) lb = np.concatenate((classes.reshape(-1, 1), segments2boxes(segments)), 1) # (cls, xywh) lb = np.array(lb, dtype=np.float32) - nl = len(lb) - if nl: + if nl := len(lb): assert lb.shape[1] == 5, f"labels require 5 columns, {lb.shape[1]} columns detected" assert (lb >= 0).all(), f"negative label values {lb[lb < 0]}" assert (lb[:, 1:] <= 1).all(), f"non-normalized or out of bounds coordinates {lb[:, 1:][lb[:, 1:] > 1]}" diff --git a/utils/general.py b/utils/general.py index 812720b7bc..ffd65738ae 100644 --- a/utils/general.py +++ b/utils/general.py @@ -161,8 +161,7 @@ def user_config_dir(dir="Ultralytics", env_var="YOLOV5_CONFIG_DIR"): """Returns user configuration directory path, prefers `env_var` if set, else uses OS-specific path, creates directory if needed. """ - env = os.getenv(env_var) - if env: + if env := os.getenv(env_var): path = Path(env) # use environment variable else: cfg = {"Windows": "AppData/Roaming", "Linux": ".config", "Darwin": "Library/Application Support"} # 3 OS dirs @@ -493,9 +492,9 @@ def check_file(file, suffix=""): assert Path(file).exists() and Path(file).stat().st_size > 0, f"File download failed: {url}" # check return file elif file.startswith("clearml://"): # ClearML Dataset ID - assert ( - "clearml" in sys.modules - ), "ClearML is not installed, so cannot use ClearML dataset. Try running 'pip install clearml'." + assert "clearml" in sys.modules, ( + "ClearML is not installed, so cannot use ClearML dataset. Try running 'pip install clearml'." + ) return file else: # search files = [] diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py index e9cec6be97..0fb9d8a24c 100644 --- a/utils/loggers/clearml/clearml_utils.py +++ b/utils/loggers/clearml/clearml_utils.py @@ -39,11 +39,9 @@ def construct_dataset(clearml_info_string): with open(yaml_filenames[0]) as f: dataset_definition = yaml.safe_load(f) - assert set( - dataset_definition.keys() - ).issuperset( - {"train", "test", "val", "nc", "names"} - ), "The right keys were not found in the yaml file, make sure it at least has the following keys: ('train', 'test', 'val', 'nc', 'names')" + assert set(dataset_definition.keys()).issuperset({"train", "test", "val", "nc", "names"}), ( + "The right keys were not found in the yaml file, make sure it at least has the following keys: ('train', 'test', 'val', 'nc', 'names')" + ) data_dict = { "train": ( diff --git a/utils/loggers/comet/__init__.py b/utils/loggers/comet/__init__.py index b6c6846747..1c9483c029 100644 --- a/utils/loggers/comet/__init__.py +++ b/utils/loggers/comet/__init__.py @@ -86,14 +86,12 @@ def __init__(self, opt, hyp, run_id=None, job_type="Training", **experiment_kwar self.upload_dataset = self.opt.upload_dataset or COMET_UPLOAD_DATASET self.resume = self.opt.resume - # Default parameters to pass to Experiment objects self.default_experiment_kwargs = { "log_code": False, "log_env_gpu": True, "log_env_cpu": True, "project_name": COMET_PROJECT_NAME, - } - self.default_experiment_kwargs.update(experiment_kwargs) + } | experiment_kwargs self.experiment = self._get_experiment(self.comet_mode, run_id) self.experiment.set_name(self.opt.name) diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py index 0481339dd6..0813616516 100644 --- a/utils/loggers/wandb/wandb_utils.py +++ b/utils/loggers/wandb/wandb_utils.py @@ -18,7 +18,7 @@ RANK = int(os.getenv("RANK", -1)) DEPRECATION_WARNING = ( f"{colorstr('wandb')}: WARNING ⚠️ wandb is deprecated and will be removed in a future release. " - f'See supported integrations at https://github.com/ultralytics/yolov5#integrations.' + f"See supported integrations at https://github.com/ultralytics/yolov5#integrations." ) try: diff --git a/utils/loss.py b/utils/loss.py index 3d3e1208b3..fa33136e3b 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -150,8 +150,7 @@ def __call__(self, p, targets): # predictions, targets b, a, gj, gi = indices[i] # image, anchor, gridy, gridx tobj = torch.zeros(pi.shape[:4], dtype=pi.dtype, device=self.device) # target obj - n = b.shape[0] # number of targets - if n: + if n := b.shape[0]: # pxy, pwh, _, pcls = pi[b, a, gj, gi].tensor_split((2, 4, 5), dim=1) # faster, requires torch 1.8.0 pxy, pwh, _, pcls = pi[b, a, gj, gi].split((2, 2, 1, self.nc), 1) # target-subset of predictions @@ -177,10 +176,6 @@ def __call__(self, p, targets): # predictions, targets t[range(n), tcls[i]] = self.cp lcls += self.BCEcls(pcls, t) # BCE - # Append targets to text file - # with open('targets.txt', 'a') as file: - # [file.write('%11.5g ' * 4 % tuple(x) + '\n') for x in torch.cat((txy[i], twh[i]), 1)] - obji = self.BCEobj(pi[..., 4], tobj) lobj += obji * self.balance[i] # obj loss if self.autobalance: diff --git a/utils/segment/augmentations.py b/utils/segment/augmentations.py index 74e1653925..a9830b2d92 100644 --- a/utils/segment/augmentations.py +++ b/utils/segment/augmentations.py @@ -67,16 +67,8 @@ def random_perspective( else: # affine im = cv2.warpAffine(im, M[:2], dsize=(width, height), borderValue=(114, 114, 114)) - # Visualize - # import matplotlib.pyplot as plt - # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel() - # ax[0].imshow(im[:, :, ::-1]) # base - # ax[1].imshow(im2[:, :, ::-1]) # warped - - # Transform label coordinates - n = len(targets) new_segments = [] - if n: + if n := len(targets): new = np.zeros((n, 4)) segments = resample_segments(segments) # upsample for i, segment in enumerate(segments): diff --git a/utils/segment/dataloaders.py b/utils/segment/dataloaders.py index 4b1fba08bf..fbf936862d 100644 --- a/utils/segment/dataloaders.py +++ b/utils/segment/dataloaders.py @@ -126,9 +126,7 @@ def __getitem__(self, index): index = self.indices[index] # linear, shuffled, or image_weights hyp = self.hyp - mosaic = self.mosaic and random.random() < hyp["mosaic"] - masks = [] - if mosaic: + if mosaic := self.mosaic and random.random() < hyp["mosaic"]: # Load mosaic img, labels, segments = self.load_mosaic(index) shapes = None @@ -174,6 +172,7 @@ def __getitem__(self, index): ) nl = len(labels) # number of labels + masks = [] if nl: labels[:, 1:5] = xyxy2xywhn(labels[:, 1:5], w=img.shape[1], h=img.shape[0], clip=True, eps=1e-3) if self.overlap: diff --git a/utils/segment/loss.py b/utils/segment/loss.py index 4e204a42c8..714eb6f47d 100644 --- a/utils/segment/loss.py +++ b/utils/segment/loss.py @@ -61,8 +61,7 @@ def __call__(self, preds, targets, masks): # predictions, targets, model b, a, gj, gi = indices[i] # image, anchor, gridy, gridx tobj = torch.zeros(pi.shape[:4], dtype=pi.dtype, device=self.device) # target obj - n = b.shape[0] # number of targets - if n: + if n := b.shape[0]: pxy, pwh, _, pcls, pmask = pi[b, a, gj, gi].split((2, 2, 1, self.nc, nm), 1) # subset of predictions # Box regression diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 0b1d69a9ab..519c227cd1 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -125,9 +125,9 @@ def select_device(device="", batch_size=0, newline=True): os.environ["CUDA_VISIBLE_DEVICES"] = "-1" # force torch.cuda.is_available() = False elif device: # non-cpu device requested os.environ["CUDA_VISIBLE_DEVICES"] = device # set environment variable - must be before assert is_available() - assert torch.cuda.is_available() and torch.cuda.device_count() >= len( - device.replace(",", "") - ), f"Invalid CUDA '--device {device}' requested, use '--device cpu' or pass valid CUDA device(s)" + assert torch.cuda.is_available() and torch.cuda.device_count() >= len(device.replace(",", "")), ( + f"Invalid CUDA '--device {device}' requested, use '--device cpu' or pass valid CUDA device(s)" + ) if not cpu and not mps and torch.cuda.is_available(): # prefer GPU if available devices = device.split(",") if device else "0" # range(torch.cuda.device_count()) # i.e. 0,1,6,7 @@ -376,7 +376,7 @@ def smart_optimizer(model, name="Adam", lr=0.001, momentum=0.9, decay=1e-5): optimizer.add_param_group({"params": g[1], "weight_decay": 0.0}) # add g1 (BatchNorm2d weights) LOGGER.info( f"{colorstr('optimizer:')} {type(optimizer).__name__}(lr={lr}) with parameter groups " - f'{len(g[1])} weight(decay=0.0), {len(g[0])} weight(decay={decay}), {len(g[2])} bias' + f"{len(g[1])} weight(decay=0.0), {len(g[0])} weight(decay={decay}), {len(g[2])} bias" ) return optimizer From 7beeb1f14522aa5794a5ccd2fefa9e61762dc808 Mon Sep 17 00:00:00 2001 From: Paula Derrenger <107626595+pderrenger@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:25:19 +0100 Subject: [PATCH 1143/1185] Standardize license headers in Python files (#2314) * Refactor code for speed and clarity * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: Glenn Jocher Co-authored-by: UltralyticsAssistant --- benchmarks.py | 2 +- classify/predict.py | 2 +- classify/train.py | 2 +- classify/val.py | 2 +- detect.py | 2 +- export.py | 2 +- hubconf.py | 2 +- models/__init__.py | 1 + models/common.py | 2 +- models/experimental.py | 2 +- models/tf.py | 2 +- models/yolo.py | 2 +- segment/predict.py | 2 +- segment/train.py | 2 +- segment/val.py | 2 +- train.py | 2 +- utils/__init__.py | 2 +- utils/activations.py | 2 +- utils/augmentations.py | 2 +- utils/autoanchor.py | 2 +- utils/autobatch.py | 2 +- utils/aws/__init__.py | 1 + utils/aws/resume.py | 3 ++- utils/callbacks.py | 2 +- utils/dataloaders.py | 2 +- utils/downloads.py | 2 +- utils/flask_rest_api/example_request.py | 2 +- utils/flask_rest_api/restapi.py | 2 +- utils/general.py | 2 +- utils/loggers/__init__.py | 2 +- utils/loggers/clearml/README.md | 2 +- utils/loggers/clearml/__init__.py | 1 + utils/loggers/clearml/clearml_utils.py | 2 +- utils/loggers/clearml/hpo.py | 2 +- utils/loggers/comet/__init__.py | 2 +- utils/loggers/comet/comet_utils.py | 2 +- utils/loggers/comet/hpo.py | 2 +- utils/loggers/wandb/__init__.py | 1 + utils/loggers/wandb/wandb_utils.py | 2 +- utils/loss.py | 2 +- utils/metrics.py | 2 +- utils/plots.py | 2 +- utils/segment/__init__.py | 1 + utils/segment/augmentations.py | 2 +- utils/segment/dataloaders.py | 2 +- utils/segment/general.py | 2 +- utils/segment/loss.py | 2 +- utils/segment/metrics.py | 2 +- utils/segment/plots.py | 2 +- utils/torch_utils.py | 2 +- utils/triton.py | 2 +- val.py | 2 +- 52 files changed, 53 insertions(+), 47 deletions(-) diff --git a/benchmarks.py b/benchmarks.py index 127fecf4fb..7c215dede6 100644 --- a/benchmarks.py +++ b/benchmarks.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ Run YOLOv3 benchmarks on all supported export formats. diff --git a/classify/predict.py b/classify/predict.py index e3ab6f4da8..9e191933e9 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ Run YOLOv3 classification inference on images, videos, directories, globs, YouTube, webcam, streams, etc. diff --git a/classify/train.py b/classify/train.py index 1ba22a58ed..9eef8e0715 100644 --- a/classify/train.py +++ b/classify/train.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ Train a YOLOv3 classifier model on a classification dataset. diff --git a/classify/val.py b/classify/val.py index 7735533120..f8079941cc 100644 --- a/classify/val.py +++ b/classify/val.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ Validate a trained YOLOv3 classification model on a classification dataset. diff --git a/detect.py b/detect.py index ee789d34c8..6668a504e3 100644 --- a/detect.py +++ b/detect.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ Run YOLOv3 detection inference on images, videos, directories, globs, YouTube, webcam, streams, etc. diff --git a/export.py b/export.py index 8d3802b348..56ab25b3c8 100644 --- a/export.py +++ b/export.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ Export a YOLOv3 PyTorch model to other formats. TensorFlow exports authored by https://github.com/zldrobit. diff --git a/hubconf.py b/hubconf.py index 7e34f06adc..16dcb68477 100644 --- a/hubconf.py +++ b/hubconf.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov5. diff --git a/models/__init__.py b/models/__init__.py index e69de29bb2..77a19dcf0f 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -0,0 +1 @@ +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license diff --git a/models/common.py b/models/common.py index 9d0818d62f..9372150e86 100644 --- a/models/common.py +++ b/models/common.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Common modules.""" import ast diff --git a/models/experimental.py b/models/experimental.py index 7c1ed58608..50d1cd0d4a 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Experimental modules.""" import math diff --git a/models/tf.py b/models/tf.py index b4c47e8e73..5f6f2a6374 100644 --- a/models/tf.py +++ b/models/tf.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ TensorFlow, Keras and TFLite versions of YOLOv3 Authored by https://github.com/zldrobit in PR https://github.com/ultralytics/yolov5/pull/1127. diff --git a/models/yolo.py b/models/yolo.py index 49cd9c74fc..7b00e7ef67 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ YOLO-specific modules. diff --git a/segment/predict.py b/segment/predict.py index 60078b9691..529332c12c 100644 --- a/segment/predict.py +++ b/segment/predict.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ Run YOLOv3 segmentation inference on images, videos, directories, streams, etc. diff --git a/segment/train.py b/segment/train.py index 05e69285b9..78ade178da 100644 --- a/segment/train.py +++ b/segment/train.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ Train a YOLOv3 segment model on a segment dataset Models and datasets download automatically from the latest YOLOv3 release. diff --git a/segment/val.py b/segment/val.py index 52cf7137ea..2da9a7e1ac 100644 --- a/segment/val.py +++ b/segment/val.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ Validate a trained YOLOv3 segment model on a segment dataset. diff --git a/train.py b/train.py index e484b069a8..878f1e614f 100644 --- a/train.py +++ b/train.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ Train a YOLOv3 model on a custom dataset. Models and datasets download automatically from the latest YOLOv3 release. diff --git a/utils/__init__.py b/utils/__init__.py index 918856178c..a7b86410d0 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """utils/initialization.""" import contextlib diff --git a/utils/activations.py b/utils/activations.py index a4ff9e48f7..0a1a79766a 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Activation functions.""" import torch diff --git a/utils/augmentations.py b/utils/augmentations.py index 662360d5c6..65a0435758 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Image augmentation functions.""" import math diff --git a/utils/autoanchor.py b/utils/autoanchor.py index b8c40dc553..3599d66865 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """AutoAnchor utils.""" import random diff --git a/utils/autobatch.py b/utils/autobatch.py index 1e8d8b0775..915ba35575 100644 --- a/utils/autobatch.py +++ b/utils/autobatch.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Auto-batch utils.""" from copy import deepcopy diff --git a/utils/aws/__init__.py b/utils/aws/__init__.py index e69de29bb2..77a19dcf0f 100644 --- a/utils/aws/__init__.py +++ b/utils/aws/__init__.py @@ -0,0 +1 @@ +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license diff --git a/utils/aws/resume.py b/utils/aws/resume.py index 37c6ffd42c..1924ea845e 100644 --- a/utils/aws/resume.py +++ b/utils/aws/resume.py @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Resume all interrupted trainings in yolov5/ dir including DDP trainings # Usage: $ python utils/aws/resume.py diff --git a/utils/callbacks.py b/utils/callbacks.py index e4b62c2f25..279741b5d7 100644 --- a/utils/callbacks.py +++ b/utils/callbacks.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Callback utils.""" import threading diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 7bebfdad36..e3227e8470 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Dataloaders and dataset utils.""" import contextlib diff --git a/utils/downloads.py b/utils/downloads.py index d95d76d9cd..54d02dcaee 100644 --- a/utils/downloads.py +++ b/utils/downloads.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Download utils.""" import logging diff --git a/utils/flask_rest_api/example_request.py b/utils/flask_rest_api/example_request.py index 7a411fce7d..db88e80407 100644 --- a/utils/flask_rest_api/example_request.py +++ b/utils/flask_rest_api/example_request.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Perform test request.""" import pprint diff --git a/utils/flask_rest_api/restapi.py b/utils/flask_rest_api/restapi.py index 67521c02da..fa8af4833c 100644 --- a/utils/flask_rest_api/restapi.py +++ b/utils/flask_rest_api/restapi.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Run a Flask REST API exposing one or more YOLOv5s models.""" import argparse diff --git a/utils/general.py b/utils/general.py index ffd65738ae..e8572419cd 100644 --- a/utils/general.py +++ b/utils/general.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """General utils.""" import contextlib diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index 35fa66ad89..8aaafd1c52 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Logging utils.""" import os diff --git a/utils/loggers/clearml/README.md b/utils/loggers/clearml/README.md index 9ec33a39c6..c565ee089d 100644 --- a/utils/loggers/clearml/README.md +++ b/utils/loggers/clearml/README.md @@ -4,7 +4,7 @@ ## About ClearML -[ClearML](https://clear.ml/) is an [open-source](https://github.com/allegroai/clearml) toolbox designed to save you time ⏱️. +[ClearML](https://clear.ml/) is an [open-source](https://github.com/clearml/clearml) toolbox designed to save you time ⏱️. 🔨 Track every YOLOv5 training run in the experiment manager diff --git a/utils/loggers/clearml/__init__.py b/utils/loggers/clearml/__init__.py index e69de29bb2..77a19dcf0f 100644 --- a/utils/loggers/clearml/__init__.py +++ b/utils/loggers/clearml/__init__.py @@ -0,0 +1 @@ +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py index 0fb9d8a24c..215c830cb0 100644 --- a/utils/loggers/clearml/clearml_utils.py +++ b/utils/loggers/clearml/clearml_utils.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Main Logger class for ClearML experiment tracking.""" import glob diff --git a/utils/loggers/clearml/hpo.py b/utils/loggers/clearml/hpo.py index 180dcc5b5f..7ab3d80557 100644 --- a/utils/loggers/clearml/hpo.py +++ b/utils/loggers/clearml/hpo.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license from clearml import Task diff --git a/utils/loggers/comet/__init__.py b/utils/loggers/comet/__init__.py index 1c9483c029..b89cf02eea 100644 --- a/utils/loggers/comet/__init__.py +++ b/utils/loggers/comet/__init__.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license import glob import json diff --git a/utils/loggers/comet/comet_utils.py b/utils/loggers/comet/comet_utils.py index f6ba90dc50..841e200e04 100644 --- a/utils/loggers/comet/comet_utils.py +++ b/utils/loggers/comet/comet_utils.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license import logging import os diff --git a/utils/loggers/comet/hpo.py b/utils/loggers/comet/hpo.py index e5fcdfe260..ffc14997f1 100644 --- a/utils/loggers/comet/hpo.py +++ b/utils/loggers/comet/hpo.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license import argparse import json diff --git a/utils/loggers/wandb/__init__.py b/utils/loggers/wandb/__init__.py index e69de29bb2..77a19dcf0f 100644 --- a/utils/loggers/wandb/__init__.py +++ b/utils/loggers/wandb/__init__.py @@ -0,0 +1 @@ +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py index 0813616516..af7c1d502f 100644 --- a/utils/loggers/wandb/wandb_utils.py +++ b/utils/loggers/wandb/wandb_utils.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # WARNING ⚠️ wandb is deprecated and will be removed in future release. # See supported integrations at https://github.com/ultralytics/yolov5#integrations diff --git a/utils/loss.py b/utils/loss.py index fa33136e3b..b3fa859838 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Loss functions.""" import torch diff --git a/utils/metrics.py b/utils/metrics.py index 6324b76992..205136547e 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Model validation metrics.""" import math diff --git a/utils/plots.py b/utils/plots.py index ad5f4ea6d3..a8fa09c882 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Plotting utils.""" import contextlib diff --git a/utils/segment/__init__.py b/utils/segment/__init__.py index e69de29bb2..77a19dcf0f 100644 --- a/utils/segment/__init__.py +++ b/utils/segment/__init__.py @@ -0,0 +1 @@ +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license diff --git a/utils/segment/augmentations.py b/utils/segment/augmentations.py index a9830b2d92..cdec000e33 100644 --- a/utils/segment/augmentations.py +++ b/utils/segment/augmentations.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Image augmentation functions.""" import math diff --git a/utils/segment/dataloaders.py b/utils/segment/dataloaders.py index fbf936862d..ee4ed6c49f 100644 --- a/utils/segment/dataloaders.py +++ b/utils/segment/dataloaders.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Dataloaders.""" import os diff --git a/utils/segment/general.py b/utils/segment/general.py index 7ddca4656b..ecb3111f9d 100644 --- a/utils/segment/general.py +++ b/utils/segment/general.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license import cv2 import numpy as np diff --git a/utils/segment/loss.py b/utils/segment/loss.py index 714eb6f47d..3bb4a6f48c 100644 --- a/utils/segment/loss.py +++ b/utils/segment/loss.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license import torch import torch.nn as nn diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py index 9451cc9324..3ff6c6a58c 100644 --- a/utils/segment/metrics.py +++ b/utils/segment/metrics.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Model validation metrics.""" import numpy as np diff --git a/utils/segment/plots.py b/utils/segment/plots.py index 8c4f3d2b9f..d2e4928f96 100644 --- a/utils/segment/plots.py +++ b/utils/segment/plots.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license import contextlib import math diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 519c227cd1..9b0f81d76a 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """PyTorch utils.""" import math diff --git a/utils/triton.py b/utils/triton.py index dad9dcd472..630292e6eb 100644 --- a/utils/triton.py +++ b/utils/triton.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Utils to interact with the Triton Inference Server.""" import typing diff --git a/val.py b/val.py index 6c7a88ccbb..e33a65816f 100644 --- a/val.py +++ b/val.py @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """ Validate a trained YOLOv3 detection model on a detection dataset. From 239aaafa5c02f8606bf71813feadf90ddd98270d Mon Sep 17 00:00:00 2001 From: Paula Derrenger <107626595+pderrenger@users.noreply.github.com> Date: Wed, 15 Jan 2025 17:52:34 +0100 Subject: [PATCH 1144/1185] Standardize license headers in TOML/YAML files (#2315) Refactor code for speed and clarity Co-authored-by: Glenn Jocher --- .github/ISSUE_TEMPLATE/bug-report.yml | 2 +- .github/ISSUE_TEMPLATE/config.yml | 2 +- .github/ISSUE_TEMPLATE/feature-request.yml | 2 +- .github/ISSUE_TEMPLATE/question.yml | 2 +- .github/workflows/ci-testing.yml | 3 ++- .github/workflows/cla.yml | 3 ++- .github/workflows/docker.yml | 3 ++- .github/workflows/format.yml | 3 ++- .github/workflows/links.yml | 3 ++- .github/workflows/merge-main-into-prs.yml | 3 ++- .github/workflows/stale.yml | 2 +- data/Argoverse.yaml | 3 ++- data/GlobalWheat2020.yaml | 3 ++- data/ImageNet.yaml | 3 ++- data/SKU-110K.yaml | 3 ++- data/VisDrone.yaml | 3 ++- data/coco.yaml | 3 ++- data/coco128-seg.yaml | 3 ++- data/coco128.yaml | 3 ++- data/hyps/hyp.Objects365.yaml | 3 ++- data/hyps/hyp.VOC.yaml | 3 ++- data/hyps/hyp.no-augmentation.yaml | 3 ++- data/hyps/hyp.scratch-high.yaml | 3 ++- data/hyps/hyp.scratch-low.yaml | 3 ++- data/hyps/hyp.scratch-med.yaml | 3 ++- data/objects365.yaml | 3 ++- data/voc.yaml | 3 ++- data/xView.yaml | 3 ++- models/hub/anchors.yaml | 3 ++- models/hub/yolov5-bifpn.yaml | 2 +- models/hub/yolov5-fpn.yaml | 2 +- models/hub/yolov5-p2.yaml | 2 +- models/hub/yolov5-p34.yaml | 2 +- models/hub/yolov5-p6.yaml | 2 +- models/hub/yolov5-p7.yaml | 2 +- models/hub/yolov5-panet.yaml | 2 +- models/hub/yolov5l6.yaml | 2 +- models/hub/yolov5m6.yaml | 2 +- models/hub/yolov5n6.yaml | 2 +- models/hub/yolov5s-LeakyReLU.yaml | 2 +- models/hub/yolov5s-ghost.yaml | 2 +- models/hub/yolov5s-transformer.yaml | 2 +- models/hub/yolov5s6.yaml | 2 +- models/hub/yolov5x6.yaml | 2 +- models/segment/yolov5l-seg.yaml | 2 +- models/segment/yolov5m-seg.yaml | 2 +- models/segment/yolov5n-seg.yaml | 2 +- models/segment/yolov5s-seg.yaml | 2 +- models/segment/yolov5x-seg.yaml | 2 +- models/yolov3-spp.yaml | 2 +- models/yolov3-tiny.yaml | 2 +- models/yolov3.yaml | 2 +- models/yolov5l.yaml | 2 +- models/yolov5m.yaml | 2 +- models/yolov5n.yaml | 2 +- models/yolov5s.yaml | 2 +- models/yolov5x.yaml | 2 +- pyproject.toml | 2 +- utils/google_app_engine/app.yaml | 2 +- 59 files changed, 83 insertions(+), 59 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index dbdb9d72b6..b55f34f14f 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license name: 🐛 Bug Report # title: " " diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 5c80f143ad..7d8d1fa5f4 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license blank_issues_enabled: true contact_links: diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index cb28b4aa9b..befa9d55c7 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license name: 🚀 Feature Request description: Suggest a YOLOv3 idea diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml index edf0efee9c..2cccf8c4c1 100644 --- a/.github/ISSUE_TEMPLATE/question.yml +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license name: ❓ Question description: Ask a YOLOv3 question diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 0b6f55b659..3912e9940e 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # YOLOv3 Continuous Integration (CI) GitHub Actions tests name: YOLOv3 CI diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index b122d5f722..3721c14a6d 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -1,4 +1,5 @@ -# Ultralytics YOLO 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Ultralytics Contributor License Agreement (CLA) action https://docs.ultralytics.com/help/CLA # This workflow automatically requests Pull Requests (PR) authors to sign the Ultralytics CLA before PRs can be merged diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 056b1151d8..8ca4f3662c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Builds ultralytics/yolov3:latest images on DockerHub https://hub.docker.com/r/ultralytics/yolov3 name: Publish Docker Images diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 790fa19527..687bc31582 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -1,4 +1,5 @@ -# Ultralytics 🚀 - AGPL-3.0 License https://ultralytics.com/license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Ultralytics Actions https://github.com/ultralytics/actions # This workflow automatically formats code and documentation in PRs to official Ultralytics standards diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 4ef9c55340..07bf6db74e 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Continuous Integration (CI) GitHub Actions tests broken link checker using https://github.com/lycheeverse/lychee # Ignores the following status codes to reduce false positives: # - 403(OpenVINO, 'forbidden') diff --git a/.github/workflows/merge-main-into-prs.yml b/.github/workflows/merge-main-into-prs.yml index 82f113c548..0cae77e268 100644 --- a/.github/workflows/merge-main-into-prs.yml +++ b/.github/workflows/merge-main-into-prs.yml @@ -1,4 +1,5 @@ -# Ultralytics YOLO 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Automatically merges repository 'main' branch into all open PRs to keep them up-to-date # Action runs on updates to main branch so when one PR merges to main all others update diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index b4ed8bd6aa..fda092a442 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license name: Close stale issues on: diff --git a/data/Argoverse.yaml b/data/Argoverse.yaml index e6a07ef3e5..651b6431bb 100644 --- a/data/Argoverse.yaml +++ b/data/Argoverse.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/ by Argo AI # Example usage: python train.py --data Argoverse.yaml # parent diff --git a/data/GlobalWheat2020.yaml b/data/GlobalWheat2020.yaml index 007e4f0953..eb25871c65 100644 --- a/data/GlobalWheat2020.yaml +++ b/data/GlobalWheat2020.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Global Wheat 2020 dataset http://www.global-wheat.com/ by University of Saskatchewan # Example usage: python train.py --data GlobalWheat2020.yaml # parent diff --git a/data/ImageNet.yaml b/data/ImageNet.yaml index 62e8cb5ff5..a3cf694bc5 100644 --- a/data/ImageNet.yaml +++ b/data/ImageNet.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # ImageNet-1k dataset https://www.image-net.org/index.php by Stanford University # Simplified class names from https://github.com/anishathalye/imagenet-simple-labels # Example usage: python classify/train.py --data imagenet diff --git a/data/SKU-110K.yaml b/data/SKU-110K.yaml index 272cdea4e9..695b89cd43 100644 --- a/data/SKU-110K.yaml +++ b/data/SKU-110K.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # SKU-110K retail items dataset https://github.com/eg4000/SKU110K_CVPR19 by Trax Retail # Example usage: python train.py --data SKU-110K.yaml # parent diff --git a/data/VisDrone.yaml b/data/VisDrone.yaml index de42f7a384..637433b509 100644 --- a/data/VisDrone.yaml +++ b/data/VisDrone.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # VisDrone2019-DET dataset https://github.com/VisDrone/VisDrone-Dataset by Tianjin University # Example usage: python train.py --data VisDrone.yaml # parent diff --git a/data/coco.yaml b/data/coco.yaml index 65224a06fd..7f872e8ca6 100644 --- a/data/coco.yaml +++ b/data/coco.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # COCO 2017 dataset http://cocodataset.org by Microsoft # Example usage: python train.py --data coco.yaml # parent diff --git a/data/coco128-seg.yaml b/data/coco128-seg.yaml index 6509214555..fa618d87e7 100644 --- a/data/coco128-seg.yaml +++ b/data/coco128-seg.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # COCO128-seg dataset https://www.kaggle.com/datasets/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics # Example usage: python train.py --data coco128.yaml # parent diff --git a/data/coco128.yaml b/data/coco128.yaml index 78d1545c10..e81fb1ff4b 100644 --- a/data/coco128.yaml +++ b/data/coco128.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # COCO128 dataset https://www.kaggle.com/datasets/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics # Example usage: python train.py --data coco128.yaml # parent diff --git a/data/hyps/hyp.Objects365.yaml b/data/hyps/hyp.Objects365.yaml index 77a06577f7..7b26a053bb 100644 --- a/data/hyps/hyp.Objects365.yaml +++ b/data/hyps/hyp.Objects365.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Hyperparameters for Objects365 training # python train.py --weights yolov5m.pt --data Objects365.yaml --evolve # See Hyperparameter Evolution tutorial for details https://github.com/ultralytics/yolov5#tutorials diff --git a/data/hyps/hyp.VOC.yaml b/data/hyps/hyp.VOC.yaml index 88a418ed59..472da47ff5 100644 --- a/data/hyps/hyp.VOC.yaml +++ b/data/hyps/hyp.VOC.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Hyperparameters for VOC training # python train.py --batch 128 --weights yolov5m6.pt --data VOC.yaml --epochs 50 --img 512 --hyp hyp.scratch-med.yaml --evolve # See Hyperparameter Evolution tutorial for details https://github.com/ultralytics/yolov5#tutorials diff --git a/data/hyps/hyp.no-augmentation.yaml b/data/hyps/hyp.no-augmentation.yaml index 2937714df6..a612518c2b 100644 --- a/data/hyps/hyp.no-augmentation.yaml +++ b/data/hyps/hyp.no-augmentation.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Hyperparameters when using Albumentations frameworks # python train.py --hyp hyp.no-augmentation.yaml # See https://github.com/ultralytics/yolov5/pull/3882 for YOLOv3 + Albumentations Usage examples diff --git a/data/hyps/hyp.scratch-high.yaml b/data/hyps/hyp.scratch-high.yaml index 4acf2f8da8..74536c2973 100644 --- a/data/hyps/hyp.scratch-high.yaml +++ b/data/hyps/hyp.scratch-high.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Hyperparameters for high-augmentation COCO training from scratch # python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300 # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials diff --git a/data/hyps/hyp.scratch-low.yaml b/data/hyps/hyp.scratch-low.yaml index 7f15609f00..e89b3ba4e7 100644 --- a/data/hyps/hyp.scratch-low.yaml +++ b/data/hyps/hyp.scratch-low.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Hyperparameters for low-augmentation COCO training from scratch # python train.py --batch 64 --cfg yolov5n6.yaml --weights '' --data coco.yaml --img 640 --epochs 300 --linear # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials diff --git a/data/hyps/hyp.scratch-med.yaml b/data/hyps/hyp.scratch-med.yaml index 18c1b0e963..7dfd2f3060 100644 --- a/data/hyps/hyp.scratch-med.yaml +++ b/data/hyps/hyp.scratch-med.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Hyperparameters for medium-augmentation COCO training from scratch # python train.py --batch 32 --cfg yolov5m6.yaml --weights '' --data coco.yaml --img 1280 --epochs 300 # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials diff --git a/data/objects365.yaml b/data/objects365.yaml index 9e0e199431..248b6c7750 100644 --- a/data/objects365.yaml +++ b/data/objects365.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Objects365 dataset https://www.objects365.org/ by Megvii # Example usage: python train.py --data Objects365.yaml # parent diff --git a/data/voc.yaml b/data/voc.yaml index 732c96345f..9dad47777a 100644 --- a/data/voc.yaml +++ b/data/voc.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # PASCAL VOC dataset http://host.robots.ox.ac.uk/pascal/VOC by University of Oxford # Example usage: python train.py --data VOC.yaml # parent diff --git a/data/xView.yaml b/data/xView.yaml index cadc7f31fd..6bea7637e8 100644 --- a/data/xView.yaml +++ b/data/xView.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # DIUx xView 2018 Challenge https://challenge.xviewdataset.org by U.S. National Geospatial-Intelligence Agency (NGA) # -------- DOWNLOAD DATA MANUALLY and jar xf val_images.zip to 'datasets/xView' before running train command! -------- # Example usage: python train.py --data xView.yaml diff --git a/models/hub/anchors.yaml b/models/hub/anchors.yaml index a2cb271235..0f3e288e16 100644 --- a/models/hub/anchors.yaml +++ b/models/hub/anchors.yaml @@ -1,4 +1,5 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Default anchors for COCO data # P5 ------------------------------------------------------------------------------------------------------------------- diff --git a/models/hub/yolov5-bifpn.yaml b/models/hub/yolov5-bifpn.yaml index ec36c165c7..fba3fe5f7d 100644 --- a/models/hub/yolov5-bifpn.yaml +++ b/models/hub/yolov5-bifpn.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-fpn.yaml b/models/hub/yolov5-fpn.yaml index a55b4db137..4411d1cc03 100644 --- a/models/hub/yolov5-fpn.yaml +++ b/models/hub/yolov5-fpn.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-p2.yaml b/models/hub/yolov5-p2.yaml index 5841b7fe83..e47d39e4eb 100644 --- a/models/hub/yolov5-p2.yaml +++ b/models/hub/yolov5-p2.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-p34.yaml b/models/hub/yolov5-p34.yaml index 101f08abfb..17e46f7bdc 100644 --- a/models/hub/yolov5-p34.yaml +++ b/models/hub/yolov5-p34.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-p6.yaml b/models/hub/yolov5-p6.yaml index 7e68d33107..dbc1ae4d0b 100644 --- a/models/hub/yolov5-p6.yaml +++ b/models/hub/yolov5-p6.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-p7.yaml b/models/hub/yolov5-p7.yaml index 238fbf0f85..2c1706992e 100644 --- a/models/hub/yolov5-p7.yaml +++ b/models/hub/yolov5-p7.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5-panet.yaml b/models/hub/yolov5-panet.yaml index b7fa4ffe50..68a7175661 100644 --- a/models/hub/yolov5-panet.yaml +++ b/models/hub/yolov5-panet.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5l6.yaml b/models/hub/yolov5l6.yaml index 274419beb7..223f681bf7 100644 --- a/models/hub/yolov5l6.yaml +++ b/models/hub/yolov5l6.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5m6.yaml b/models/hub/yolov5m6.yaml index 0ff59e48ba..6878d89960 100644 --- a/models/hub/yolov5m6.yaml +++ b/models/hub/yolov5m6.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5n6.yaml b/models/hub/yolov5n6.yaml index abd1fb03dc..0d454c9ca3 100644 --- a/models/hub/yolov5n6.yaml +++ b/models/hub/yolov5n6.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5s-LeakyReLU.yaml b/models/hub/yolov5s-LeakyReLU.yaml index 76726a16e0..61d6d33176 100644 --- a/models/hub/yolov5s-LeakyReLU.yaml +++ b/models/hub/yolov5s-LeakyReLU.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5s-ghost.yaml b/models/hub/yolov5s-ghost.yaml index 2ce0ef2353..53695ae48a 100644 --- a/models/hub/yolov5s-ghost.yaml +++ b/models/hub/yolov5s-ghost.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5s-transformer.yaml b/models/hub/yolov5s-transformer.yaml index 142d7cff07..213e4dac13 100644 --- a/models/hub/yolov5s-transformer.yaml +++ b/models/hub/yolov5s-transformer.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5s6.yaml b/models/hub/yolov5s6.yaml index 2f02f2329f..6e69964a95 100644 --- a/models/hub/yolov5s6.yaml +++ b/models/hub/yolov5s6.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/hub/yolov5x6.yaml b/models/hub/yolov5x6.yaml index acbbddba81..33a8525f10 100644 --- a/models/hub/yolov5x6.yaml +++ b/models/hub/yolov5x6.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5l-seg.yaml b/models/segment/yolov5l-seg.yaml index 9e99301f1a..824e8aec22 100644 --- a/models/segment/yolov5l-seg.yaml +++ b/models/segment/yolov5l-seg.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5m-seg.yaml b/models/segment/yolov5m-seg.yaml index 2437a90dd6..c3c1e668af 100644 --- a/models/segment/yolov5m-seg.yaml +++ b/models/segment/yolov5m-seg.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5n-seg.yaml b/models/segment/yolov5n-seg.yaml index 3ffc4fd8c1..2461e4160f 100644 --- a/models/segment/yolov5n-seg.yaml +++ b/models/segment/yolov5n-seg.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5s-seg.yaml b/models/segment/yolov5s-seg.yaml index e1a2641da8..fac7664a35 100644 --- a/models/segment/yolov5s-seg.yaml +++ b/models/segment/yolov5s-seg.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/segment/yolov5x-seg.yaml b/models/segment/yolov5x-seg.yaml index 0a8312136c..d3c457a6db 100644 --- a/models/segment/yolov5x-seg.yaml +++ b/models/segment/yolov5x-seg.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/yolov3-spp.yaml b/models/yolov3-spp.yaml index 9cb9b93a2a..34c2d517c6 100644 --- a/models/yolov3-spp.yaml +++ b/models/yolov3-spp.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/yolov3-tiny.yaml b/models/yolov3-tiny.yaml index e531e34b2e..f1861012ea 100644 --- a/models/yolov3-tiny.yaml +++ b/models/yolov3-tiny.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/yolov3.yaml b/models/yolov3.yaml index f181e12bcc..15cb68a83c 100644 --- a/models/yolov3.yaml +++ b/models/yolov3.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/yolov5l.yaml b/models/yolov5l.yaml index 69bfe9cd66..c6c878a10e 100644 --- a/models/yolov5l.yaml +++ b/models/yolov5l.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/yolov5m.yaml b/models/yolov5m.yaml index 2aac70af11..41d9c223a2 100644 --- a/models/yolov5m.yaml +++ b/models/yolov5m.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/yolov5n.yaml b/models/yolov5n.yaml index ad1cd770da..588674923d 100644 --- a/models/yolov5n.yaml +++ b/models/yolov5n.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/yolov5s.yaml b/models/yolov5s.yaml index e2dda5de68..11ff790018 100644 --- a/models/yolov5s.yaml +++ b/models/yolov5s.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/models/yolov5x.yaml b/models/yolov5x.yaml index 51082e6527..817b4f9118 100644 --- a/models/yolov5x.yaml +++ b/models/yolov5x.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Parameters nc: 80 # number of classes diff --git a/pyproject.toml b/pyproject.toml index faa679f7a8..146694a176 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Overview: # This pyproject.toml file manages the build, packaging, and distribution of the Ultralytics library. diff --git a/utils/google_app_engine/app.yaml b/utils/google_app_engine/app.yaml index e30c673e52..6fb9d5f9db 100644 --- a/utils/google_app_engine/app.yaml +++ b/utils/google_app_engine/app.yaml @@ -1,4 +1,4 @@ -# Ultralytics YOLOv3 🚀, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license runtime: custom env: flex From 17013985fe9411a6b05b83ee7015649da63080db Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 30 Jan 2025 17:42:43 +0100 Subject: [PATCH 1145/1185] Update links.yml (#2316) Signed-off-by: Glenn Jocher --- .github/workflows/links.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 07bf6db74e..2da3c066f3 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -44,7 +44,7 @@ jobs: --github-token ${{ secrets.GITHUB_TOKEN }} \ --header "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \ './**/*.md' \ - './**/*.html' + './**/*.html' | tee -a $GITHUB_STEP_SUMMARY - name: Test Markdown, HTML, YAML, Python and Notebook links with retry if: github.event_name == 'workflow_dispatch' @@ -69,4 +69,4 @@ jobs: './**/*.yml' \ './**/*.yaml' \ './**/*.py' \ - './**/*.ipynb' + './**/*.ipynb' | tee -a $GITHUB_STEP_SUMMARY From 5c0148128c77c13610b355766c3c8f6766eb1c32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 23 Mar 2025 14:13:52 +0100 Subject: [PATCH 1146/1185] Bump gunicorn from 22.0.0 to 23.0.0 in /utils/google_app_engine (#2319) Bumps [gunicorn](https://github.com/benoitc/gunicorn) from 22.0.0 to 23.0.0. - [Release notes](https://github.com/benoitc/gunicorn/releases) - [Commits](https://github.com/benoitc/gunicorn/compare/22.0.0...23.0.0) --- updated-dependencies: - dependency-name: gunicorn dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- utils/google_app_engine/additional_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/google_app_engine/additional_requirements.txt b/utils/google_app_engine/additional_requirements.txt index 08c276f7b4..bf7cf8868e 100644 --- a/utils/google_app_engine/additional_requirements.txt +++ b/utils/google_app_engine/additional_requirements.txt @@ -1,6 +1,6 @@ # add these requirements in your app on top of the existing ones pip==23.3 Flask==2.3.2 -gunicorn==22.0.0 +gunicorn==23.0.0 werkzeug>=3.0.1 # not directly required, pinned by Snyk to avoid a vulnerability zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability From 750b2c06d5fa8d27b087e7d0422950f3c7818e09 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 23 Mar 2025 21:19:00 +0100 Subject: [PATCH 1147/1185] Bash code blocks reformat (#2320) * Bash code blocks reformat Signed-off-by: Glenn Jocher * Auto-format by https://ultralytics.com/actions * Update README.md Signed-off-by: Glenn Jocher * Update README.zh-CN.md Signed-off-by: Glenn Jocher --------- Signed-off-by: Glenn Jocher Co-authored-by: UltralyticsAssistant --- README.md | 38 ++++++++---------- README.zh-CN.md | 38 ++++++++---------- utils/loggers/clearml/README.md | 6 +-- utils/loggers/comet/README.md | 70 ++++++++++++++++----------------- 4 files changed, 72 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index 6883ca2bab..67c13313ff 100644 --- a/README.md +++ b/README.md @@ -69,9 +69,9 @@ See the [YOLOv3 Docs](https://docs.ultralytics.com/) for full documentation on t Clone repo and install [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) in a [**Python>=3.7.0**](https://www.python.org/) environment, including [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). ```bash -git clone https://github.com/ultralytics/yolov3 # clone +git clone https://github.com/ultralytics/yolov3 # clone cd yolov3 -pip install -r requirements.txt # install +pip install -r requirements.txt # install ```
@@ -105,16 +105,16 @@ results.print() # or .show(), .save(), .crop(), .pandas(), etc. `detect.py` runs inference on a variety of sources, downloading [models](https://github.com/ultralytics/yolov5/tree/master/models) automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) and saving results to `runs/detect`. ```bash -python detect.py --weights yolov5s.pt --source 0 # webcam - img.jpg # image - vid.mp4 # video - screen # screenshot - path/ # directory - list.txt # list of images - list.streams # list of streams - 'path/*.jpg' # glob - 'https://youtu.be/LNwODJXcvt4' # YouTube - 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream +python detect.py --weights yolov3.pt --source 0 # webcam +python detect.py --weights yolov3.pt --source img.jpg # image +python detect.py --weights yolov3.pt --source vid.mp4 # video +python detect.py --weights yolov3.pt --source screen # screenshot +python detect.py --weights yolov3.pt --source path/ # directory +python detect.py --weights yolov3.pt --source list.txt # list of images +python detect.py --weights yolov3.pt --source list.streams # list of streams +python detect.py --weights yolov3.pt --source 'path/*.jpg' # glob +python detect.py --weights yolov3.pt --source 'https://youtu.be/LNwODJXcvt4' # YouTube +python detect.py --weights yolov3.pt --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream ```
@@ -125,11 +125,7 @@ python detect.py --weights yolov5s.pt --source 0 # The commands below reproduce YOLOv3 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) results. [Models](https://github.com/ultralytics/yolov5/tree/master/models) and [datasets](https://github.com/ultralytics/yolov5/tree/master/data) download automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). Training times for YOLOv5n/s/m/l/x are 1/2/4/6/8 days on a V100 GPU ([Multi-GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/) times faster). Use the largest `--batch-size` possible, or pass `--batch-size -1` for YOLOv3 [AutoBatch](https://github.com/ultralytics/yolov5/pull/5092). Batch sizes shown for V100-16GB. ```bash -python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml --batch-size 128 - yolov5s 64 - yolov5m 40 - yolov5l 24 - yolov5x 16 +python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3.yaml --batch-size 128 ``` @@ -288,8 +284,8 @@ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 segment/train Validate YOLOv5s-seg mask mAP on COCO dataset: ```bash -bash data/scripts/get_coco.sh --val --segments # download COCO val segments split (780MB, 5000 images) -python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 # validate +bash data/scripts/get_coco.sh --val --segments # download COCO val segments split (780MB, 5000 images) +python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 # validate ``` ### Predict @@ -379,8 +375,8 @@ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 classify/trai Validate YOLOv5m-cls accuracy on ImageNet-1k dataset: ```bash -bash data/scripts/get_imagenet.sh --val # download ImageNet val split (6.3G, 50000 images) -python classify/val.py --weights yolov5m-cls.pt --data ../datasets/imagenet --img 224 # validate +bash data/scripts/get_imagenet.sh --val # download ImageNet val split (6.3G, 50000 images) +python classify/val.py --weights yolov5m-cls.pt --data ../datasets/imagenet --img 224 # validate ``` ### Predict diff --git a/README.zh-CN.md b/README.zh-CN.md index 33193409e3..ecd0b5db7e 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -69,9 +69,9 @@ pip install ultralytics 克隆 repo,并要求在 [**Python>=3.7.0**](https://www.python.org/) 环境中安装 [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) ,且要求 [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/) 。 ```bash -git clone https://github.com/ultralytics/yolov3 # clone +git clone https://github.com/ultralytics/yolov3 # clone cd yolov3 -pip install -r requirements.txt # install +pip install -r requirements.txt # install ```
@@ -105,16 +105,16 @@ results.print() # or .show(), .save(), .crop(), .pandas(), etc. `detect.py` 在各种来源上运行推理, [模型](https://github.com/ultralytics/yolov5/tree/master/models) 自动从 最新的YOLOv5 [release](https://github.com/ultralytics/yolov5/releases) 中下载,并将结果保存到 `runs/detect` 。 ```bash -python detect.py --weights yolov5s.pt --source 0 # webcam - img.jpg # image - vid.mp4 # video - screen # screenshot - path/ # directory - list.txt # list of images - list.streams # list of streams - 'path/*.jpg' # glob - 'https://youtu.be/LNwODJXcvt4' # YouTube - 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream +python detect.py --weights yolov3.pt --source 0 # 摄像头 +python detect.py --weights yolov3.pt --source img.jpg # 图片 +python detect.py --weights yolov3.pt --source vid.mp4 # 视频 +python detect.py --weights yolov3.pt --source screen # 截图 +python detect.py --weights yolov3.pt --source path/ # 目录 +python detect.py --weights yolov3.pt --source list.txt # 图片列表 +python detect.py --weights yolov3.pt --source list.streams # 流列表 +python detect.py --weights yolov3.pt --source 'path/*.jpg' # glob 通配符 +python detect.py --weights yolov3.pt --source 'https://youtu.be/LNwODJXcvt4' # YouTube +python detect.py --weights yolov3.pt --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP 流 ```
@@ -125,11 +125,7 @@ python detect.py --weights yolov5s.pt --source 0 # 下面的命令重现 YOLOv3 在 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) 数据集上的结果。 最新的 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 和 [数据集](https://github.com/ultralytics/yolov5/tree/master/data) 将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 YOLOv5n/s/m/l/x 在 V100 GPU 的训练时间为 1/2/4/6/8 天( [多GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/) 训练速度更快)。 尽可能使用更大的 `--batch-size` ,或通过 `--batch-size -1` 实现 YOLOv3 [自动批处理](https://github.com/ultralytics/yolov5/pull/5092) 。下方显示的 batchsize 适用于 V100-16GB。 ```bash -python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov5n.yaml --batch-size 128 - yolov5s 64 - yolov5m 40 - yolov5l 24 - yolov5x 16 +python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3.yaml --batch-size 128 ``` @@ -290,8 +286,8 @@ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 segment/train 在 COCO 数据集上验证 YOLOv5s-seg mask mAP: ```bash -bash data/scripts/get_coco.sh --val --segments # 下载 COCO val segments 数据集 (780MB, 5000 images) -python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 # 验证 +bash data/scripts/get_coco.sh --val --segments # 下载 COCO val segments 数据集 (780MB, 5000 images) +python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 # 验证 ``` ### 预测 @@ -380,8 +376,8 @@ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 classify/trai 在 ImageNet-1k 数据集上验证 YOLOv5m-cls 的准确性: ```bash -bash data/scripts/get_imagenet.sh --val # download ImageNet val split (6.3G, 50000 images) -python classify/val.py --weights yolov5m-cls.pt --data ../datasets/imagenet --img 224 # validate +bash data/scripts/get_imagenet.sh --val # download ImageNet val split (6.3G, 50000 images) +python classify/val.py --weights yolov5m-cls.pt --data ../datasets/imagenet --img 224 # validate ``` ### 预测 diff --git a/utils/loggers/clearml/README.md b/utils/loggers/clearml/README.md index c565ee089d..f81f48e8c1 100644 --- a/utils/loggers/clearml/README.md +++ b/utils/loggers/clearml/README.md @@ -45,7 +45,7 @@ That's it! You're done 😎 To enable ClearML experiment tracking, simply install the ClearML pip package. ```bash -pip install clearml>=1.2.0 +pip install clearml > =1.2.0 ``` 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. @@ -144,7 +144,7 @@ clearml-data close Now that you have a ClearML dataset, you can very simply use it to train custom YOLOv5 🚀 models! ```bash -python train.py --img 640 --batch 16 --epochs 3 --data clearml:// --weights yolov5s.pt --cache +python train.py --img 640 --batch 16 --epochs 3 --data clearml:// yolov5s.pt --cache < your_dataset_id > --weights ``` ## 👀 Hyperparameter Optimization @@ -177,7 +177,7 @@ In short: every experiment tracked by the experiment manager contains enough inf You can turn any machine (a cloud VM, a local GPU machine, your own laptop ... ) into a ClearML agent by simply running: ```bash -clearml-agent daemon --queue [--docker] +clearml-agent daemon --queue < queues_to_listen_to > [--docker] ``` ### Cloning, Editing And Enqueuing diff --git a/utils/loggers/comet/README.md b/utils/loggers/comet/README.md index 52f344dba6..353698dd4d 100644 --- a/utils/loggers/comet/README.md +++ b/utils/loggers/comet/README.md @@ -102,12 +102,12 @@ Logging Models to Comet is disabled by default. To enable it, pass the `save-per ```shell python train.py \ ---img 640 \ ---batch 16 \ ---epochs 5 \ ---data coco128.yaml \ ---weights yolov5s.pt \ ---save-period 1 + --img 640 \ + --batch 16 \ + --epochs 5 \ + --data coco128.yaml \ + --weights yolov5s.pt \ + --save-period 1 ``` ## Logging Model Predictions @@ -122,12 +122,12 @@ Here is an [example project using the Panel](https://www.comet.com/examples/come ```shell python train.py \ ---img 640 \ ---batch 16 \ ---epochs 5 \ ---data coco128.yaml \ ---weights yolov5s.pt \ ---bbox_interval 2 + --img 640 \ + --batch 16 \ + --epochs 5 \ + --data coco128.yaml \ + --weights yolov5s.pt \ + --bbox_interval 2 ``` ### Controlling the number of Prediction Images logged to Comet @@ -136,12 +136,12 @@ When logging predictions from YOLOv5, Comet will log the images associated with ```shell env COMET_MAX_IMAGE_UPLOADS=200 python train.py \ ---img 640 \ ---batch 16 \ ---epochs 5 \ ---data coco128.yaml \ ---weights yolov5s.pt \ ---bbox_interval 1 + --img 640 \ + --batch 16 \ + --epochs 5 \ + --data coco128.yaml \ + --weights yolov5s.pt \ + --bbox_interval 1 ``` ### Logging Class Level Metrics @@ -150,11 +150,11 @@ Use the `COMET_LOG_PER_CLASS_METRICS` environment variable to log mAP, precision ```shell env COMET_LOG_PER_CLASS_METRICS=true python train.py \ ---img 640 \ ---batch 16 \ ---epochs 5 \ ---data coco128.yaml \ ---weights yolov5s.pt + --img 640 \ + --batch 16 \ + --epochs 5 \ + --data coco128.yaml \ + --weights yolov5s.pt ``` ## Uploading a Dataset to Comet Artifacts @@ -165,12 +165,12 @@ The dataset be organized in the way described in the [YOLOv5 documentation](http ```shell python train.py \ ---img 640 \ ---batch 16 \ ---epochs 5 \ ---data coco128.yaml \ ---weights yolov5s.pt \ ---upload_dataset + --img 640 \ + --batch 16 \ + --epochs 5 \ + --data coco128.yaml \ + --weights yolov5s.pt \ + --upload_dataset ``` You can find the uploaded dataset in the Artifacts tab in your Comet Workspace artifact-1 @@ -192,11 +192,11 @@ Then pass this file to your training script in the following way ```shell python train.py \ ---img 640 \ ---batch 16 \ ---epochs 5 \ ---data artifact.yaml \ ---weights yolov5s.pt + --img 640 \ + --batch 16 \ + --epochs 5 \ + --data artifact.yaml \ + --weights yolov5s.pt ``` Artifacts also allow you to track the lineage of data as it flows through your Experimentation workflow. Here you can see a graph that shows you all the experiments that have used your uploaded dataset. artifact-4 @@ -211,7 +211,7 @@ This will restore the run to its state before the interruption, which includes r ```shell python train.py \ ---resume "comet://" + --resume "comet://" ``` ## Hyperparameter Search with the Comet Optimizer From 1107102d04e0b1f9a9d98cca0baa3caf26e14a9c Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 23 Mar 2025 21:20:17 +0100 Subject: [PATCH 1148/1185] Update Dockerfile headers (#2322) * Update Dockerfile headers * Auto-format by https://ultralytics.com/actions --------- Signed-off-by: Glenn Jocher Co-authored-by: UltralyticsAssistant --- utils/docker/Dockerfile | 3 ++- utils/docker/Dockerfile-arm64 | 3 ++- utils/docker/Dockerfile-cpu | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/utils/docker/Dockerfile b/utils/docker/Dockerfile index 8ccb7c2090..9cba96cee2 100644 --- a/utils/docker/Dockerfile +++ b/utils/docker/Dockerfile @@ -1,4 +1,5 @@ -# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Builds ultralytics/yolov5:latest image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 # Image is CUDA-optimized for YOLOv5 single/multi-GPU training and inference diff --git a/utils/docker/Dockerfile-arm64 b/utils/docker/Dockerfile-arm64 index 574e1e9154..7aaae00e70 100644 --- a/utils/docker/Dockerfile-arm64 +++ b/utils/docker/Dockerfile-arm64 @@ -1,4 +1,5 @@ -# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Builds ultralytics/yolov5:latest-arm64 image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 # Image is aarch64-compatible for Apple M1 and other ARM architectures i.e. Jetson Nano and Raspberry Pi diff --git a/utils/docker/Dockerfile-cpu b/utils/docker/Dockerfile-cpu index cdb55f63bf..c7f8cbe7b2 100644 --- a/utils/docker/Dockerfile-cpu +++ b/utils/docker/Dockerfile-cpu @@ -1,4 +1,5 @@ -# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Builds ultralytics/yolov5:latest-cpu image on DockerHub https://hub.docker.com/r/ultralytics/yolov3 # Image is CPU-optimized for ONNX, OpenVINO and PyTorch YOLOv5 deployments From f6b0263ef3f81a8cbd5477d96a8970910f49c0e6 Mon Sep 17 00:00:00 2001 From: Paula Derrenger <107626595+pderrenger@users.noreply.github.com> Date: Fri, 28 Mar 2025 03:46:05 +0100 Subject: [PATCH 1149/1185] Ultralytics Refactor https://ultralytics.com/actions (#2323) * Refactor code for speed and clarity * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: Glenn Jocher Co-authored-by: UltralyticsAssistant --- README.md | 305 +++++++++++++++++-------------- data/scripts/download_weights.sh | 3 +- data/scripts/get_coco.sh | 3 +- data/scripts/get_coco128.sh | 3 +- data/scripts/get_imagenet.sh | 3 +- utils/aws/mime.sh | 2 + utils/aws/userdata.sh | 2 + utils/flask_rest_api/README.md | 50 +++-- utils/loggers/clearml/README.md | 245 ++++++++++++------------- utils/loggers/comet/README.md | 202 +++++++++++--------- 10 files changed, 452 insertions(+), 366 deletions(-) diff --git a/README.md b/README.md index 67c13313ff..f9aa65ed15 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +Ultralytics logo +

@@ -10,7 +12,9 @@ YOLOv3 CI YOLOv3 Citation Docker Pulls - Discord Ultralytics Forums Ultralytics Reddit + Discord + Ultralytics Forums + Ultralytics Reddit
Run on Gradient Open In Colab @@ -18,11 +22,11 @@


-YOLOv3 🚀 is the world's most loved vision AI, representing Ultralytics open-source research into future vision AI methods, incorporating lessons learned and best practices evolved over thousands of hours of research and development. +Ultralytics YOLOv3 🚀 is a significant iteration in the YOLO (You Only Look Once) family of real-time [object detection](https://docs.ultralytics.com/tasks/detect/) models. Originally developed by Joseph Redmon, YOLOv3 improved upon its predecessors by enhancing accuracy, particularly for smaller objects, through techniques like multi-scale predictions and a more complex backbone network (Darknet-53). This repository represents [Ultralytics'](https://www.ultralytics.com/) implementation, building upon the foundational work and incorporating best practices learned through extensive research in [computer vision](https://www.ultralytics.com/glossary/computer-vision-cv) and [deep learning](https://www.ultralytics.com/glossary/deep-learning-dl). -We hope that the resources here will help you get the most out of YOLOv3. Please browse the YOLOv3 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions! +We hope the resources here help you leverage YOLOv3 effectively. Explore the [Ultralytics YOLOv3 Docs](https://docs.ultralytics.com/models/yolov3/) for detailed guides, raise issues on [GitHub](https://github.com/ultralytics/yolov3/issues/new/choose) for support, and join our vibrant [Discord community](https://discord.com/invite/ultralytics) for questions and discussions! -To request an Enterprise License please complete the form at [Ultralytics Licensing](https://www.ultralytics.com/license). +To request an Enterprise License for commercial use, please complete the form at [Ultralytics Licensing](https://www.ultralytics.com/license).
Ultralytics GitHub @@ -42,11 +46,11 @@ To request an Enterprise License please complete the form at [Ultralytics Licens

-##
YOLO11 🚀 NEW
+##
🚀 Ultralytics YOLO11 is Here!
-We are excited to unveil the launch of Ultralytics YOLO11 🚀, the latest advancement in our state-of-the-art (SOTA) vision models! Available now at **[GitHub](https://github.com/ultralytics/ultralytics)**, YOLO11 builds on our legacy of speed, precision, and ease of use. Whether you're tackling object detection, image segmentation, or image classification, YOLO11 delivers the performance and versatility needed to excel in diverse applications. +We are thrilled to announce the release of Ultralytics YOLO11 🚀, the next generation in state-of-the-art (SOTA) vision models! Now available at the main **[Ultralytics repository](https://github.com/ultralytics/ultralytics)**, YOLO11 continues our commitment to speed, [accuracy](https://www.ultralytics.com/glossary/accuracy), and user-friendliness. Whether your focus is [object detection](https://docs.ultralytics.com/tasks/detect/), [image segmentation](https://docs.ultralytics.com/tasks/segment/), or [image classification](https://docs.ultralytics.com/tasks/classify/), YOLO11 offers unparalleled performance and versatility for a wide range of applications. -Get started today and unlock the full potential of YOLO11! Visit the [Ultralytics Docs](https://docs.ultralytics.com/) for comprehensive guides and resources: +Start exploring YOLO11 today! Visit the [Ultralytics Docs](https://docs.ultralytics.com/) for comprehensive guides and resources. [![PyPI version](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![Downloads](https://static.pepy.tech/badge/ultralytics)](https://www.pepy.tech/projects/ultralytics) @@ -59,19 +63,19 @@ pip install ultralytics -##
Documentation
+##
📚 Documentation
-See the [YOLOv3 Docs](https://docs.ultralytics.com/) for full documentation on training, testing and deployment. See below for quickstart examples. +See the [Ultralytics YOLOv3 Docs](https://docs.ultralytics.com/models/yolov3/) for full documentation on training, validation, inference, and deployment. Quickstart examples are provided below.
Install -Clone repo and install [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) in a [**Python>=3.7.0**](https://www.python.org/) environment, including [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/). +Clone the repository and install dependencies using `requirements.txt` in a **Python>=3.7.0** environment. Ensure you have **PyTorch>=1.7**. ```bash -git clone https://github.com/ultralytics/yolov3 # clone +git clone https://github.com/ultralytics/yolov3 # clone repository cd yolov3 -pip install -r requirements.txt # install +pip install -r requirements.txt # install dependencies ```
@@ -79,22 +83,26 @@ pip install -r requirements.txt # install
Inference -YOLOv3 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/) inference. [Models](https://github.com/ultralytics/yolov5/tree/master/models) download automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). +Perform inference using YOLOv3 models loaded via [PyTorch Hub](https://pytorch.org/hub/). Models are automatically downloaded from the latest YOLOv3 release. ```python import torch -# Model -model = torch.hub.load("ultralytics/yolov3", "yolov3") # or yolov5n - yolov5x6, custom +# Load a YOLOv3 model (e.g., yolov3, yolov3-spp) +model = torch.hub.load("ultralytics/yolov3", "yolov3", pretrained=True) # specify 'yolov3' or other variants -# Images -img = "https://ultralytics.com/images/zidane.jpg" # or file, Path, PIL, OpenCV, numpy, list +# Define image source (URL, file path, PIL image, OpenCV image, numpy array, list of images) +img_source = "https://ultralytics.com/images/zidane.jpg" -# Inference -results = model(img) +# Perform inference +results = model(img_source) -# Results -results.print() # or .show(), .save(), .crop(), .pandas(), etc. +# Process and display results +results.print() # Print results to console +# results.show() # Display results in a window +# results.save() # Save results to runs/detect/exp +# results.crop() # Save cropped detections +# results.pandas().xyxy[0] # Access results as pandas DataFrame ```
@@ -102,19 +110,20 @@ results.print() # or .show(), .save(), .crop(), .pandas(), etc.
Inference with detect.py -`detect.py` runs inference on a variety of sources, downloading [models](https://github.com/ultralytics/yolov5/tree/master/models) automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) and saving results to `runs/detect`. +The `detect.py` script runs inference on various sources. It automatically downloads required [models](https://github.com/ultralytics/yolov5/tree/master/models) from the latest YOLOv3 release and saves the output to `runs/detect`. ```bash -python detect.py --weights yolov3.pt --source 0 # webcam -python detect.py --weights yolov3.pt --source img.jpg # image -python detect.py --weights yolov3.pt --source vid.mp4 # video -python detect.py --weights yolov3.pt --source screen # screenshot -python detect.py --weights yolov3.pt --source path/ # directory -python detect.py --weights yolov3.pt --source list.txt # list of images -python detect.py --weights yolov3.pt --source list.streams # list of streams -python detect.py --weights yolov3.pt --source 'path/*.jpg' # glob -python detect.py --weights yolov3.pt --source 'https://youtu.be/LNwODJXcvt4' # YouTube -python detect.py --weights yolov3.pt --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream +# Run inference using detect.py with different sources +python detect.py --weights yolov3.pt --source 0 # Webcam +python detect.py --weights yolov3.pt --source image.jpg # Single image +python detect.py --weights yolov3.pt --source video.mp4 # Video file +python detect.py --weights yolov3.pt --source screen # Screen capture +python detect.py --weights yolov3.pt --source path/ # Directory of images/videos +python detect.py --weights yolov3.pt --source list.txt # Text file with image paths +python detect.py --weights yolov3.pt --source list.streams # Text file with stream URLs +python detect.py --weights yolov3.pt --source 'path/*.jpg' # Glob pattern for images +python detect.py --weights yolov3.pt --source 'https://youtu.be/LNwODJXcvt4' # YouTube video URL +python detect.py --weights yolov3.pt --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream URL ```
@@ -122,9 +131,10 @@ python detect.py --weights yolov3.pt --source 'rtsp://example.com/media.mp4' # R
Training -The commands below reproduce YOLOv3 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) results. [Models](https://github.com/ultralytics/yolov5/tree/master/models) and [datasets](https://github.com/ultralytics/yolov5/tree/master/data) download automatically from the latest YOLOv3 [release](https://github.com/ultralytics/yolov5/releases). Training times for YOLOv5n/s/m/l/x are 1/2/4/6/8 days on a V100 GPU ([Multi-GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/) times faster). Use the largest `--batch-size` possible, or pass `--batch-size -1` for YOLOv3 [AutoBatch](https://github.com/ultralytics/yolov5/pull/5092). Batch sizes shown for V100-16GB. +The following command demonstrates training YOLOv3 on the [COCO dataset](https://docs.ultralytics.com/datasets/detect/coco/). Models and datasets are automatically downloaded from the latest YOLOv3 release. Training times vary depending on the model size and hardware; for instance, YOLOv5 variants (often used as a reference) take 1-8 days on a V100 GPU. Use the largest possible `--batch-size` or utilize `--batch-size -1` for YOLOv3 [AutoBatch](https://docs.ultralytics.com/reference/utils/autobatch/). Batch sizes shown are indicative for a V100-16GB GPU. ```bash +# Train YOLOv3 on COCO dataset for 300 epochs python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3.yaml --batch-size 128 ``` @@ -133,30 +143,30 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3.yaml --b
-Tutorials - -- [Train Custom Data](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/) 🚀 RECOMMENDED -- [Tips for Best Training Results](https://docs.ultralytics.com/guides/model-training-tips/) ☘️ -- [Multi-GPU Training](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/) -- [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/) 🌟 NEW -- [TFLite, ONNX, CoreML, TensorRT Export](https://docs.ultralytics.com/yolov5/tutorials/model_export/) 🚀 -- [NVIDIA Jetson platform Deployment](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano/) 🌟 NEW -- [Test-Time Augmentation (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/) -- [Model Ensembling](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling/) -- [Model Pruning/Sparsity](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity/) -- [Hyperparameter Evolution](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution/) -- [Transfer Learning with Frozen Layers](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers/) -- [Architecture Summary](https://docs.ultralytics.com/yolov5/tutorials/architecture_description/) 🌟 NEW -- [Ultralytics HUB to train and deploy YOLO](https://www.ultralytics.com/hub) 🚀 RECOMMENDED -- [ClearML Logging](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration/) -- [YOLOv5 with Neural Magic's Deepsparse](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization/) -- [Comet Logging](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration/) 🌟 NEW +📚 Tutorials + +- [Train Custom Data](https://docs.ultralytics.com/datasets/detect/) 🚀 **RECOMMENDED**: Learn how to train YOLO models on your own datasets. +- [Tips for Best Training Results](https://docs.ultralytics.com/guides/model-training-tips/) ☘️: Improve your model's performance with expert tips. +- [Multi-GPU Training](https://docs.ultralytics.com/usage/cli/#multi-gpu-training): Scale your training across multiple GPUs. +- [PyTorch Hub Integration](https://docs.ultralytics.com/integrations/pytorch-hub/): Load models easily using PyTorch Hub. 🌟 **NEW** +- [Model Export](https://docs.ultralytics.com/modes/export/): Export models to various formats like TFLite, ONNX, CoreML, TensorRT. 🚀 +- [NVIDIA Jetson Deployment](https://docs.ultralytics.com/guides/nvidia-jetson/): Deploy models on NVIDIA Jetson devices. 🌟 **NEW** +- [Test-Time Augmentation (TTA)](https://docs.ultralytics.com/modes/val/#inference-augmentation): Enhance prediction accuracy using TTA. +- [Model Ensembling](https://docs.ultralytics.com/reference/engine/model/#ultralytics.engine.model.Model.ensemble): Combine multiple models for better robustness. +- [Model Pruning/Sparsity](https://docs.ultralytics.com/integrations/neural-magic/): Optimize models for size and speed. +- [Hyperparameter Evolution](https://docs.ultralytics.com/guides/hyperparameter-tuning/): Automatically tune hyperparameters for optimal performance. +- [Transfer Learning](https://docs.ultralytics.com/guides/transfer-learning/): Fine-tune pretrained models on your custom data. +- [Architecture Summary](https://docs.ultralytics.com/models/yolov5/#architecture): Understand the underlying model architecture. 🌟 **NEW** +- [Ultralytics HUB Training](https://docs.ultralytics.com/hub/cloud-training/) 🚀 **RECOMMENDED**: Train and deploy YOLO models easily using Ultralytics HUB. +- [ClearML Logging](https://docs.ultralytics.com/integrations/clearml/): Integrate experiment tracking with ClearML. +- [Neural Magic DeepSparse Integration](https://docs.ultralytics.com/integrations/neural-magic/): Accelerate inference with DeepSparse. +- [Comet Logging](https://docs.ultralytics.com/integrations/comet/): Log and visualize experiments using Comet. 🌟 **NEW**
-##
Integrations
+##
🤝 Integrations
-Our key integrations with leading AI platforms extend the functionality of Ultralytics' offerings, enhancing tasks like dataset labeling, training, visualization, and model management. Discover how Ultralytics, in collaboration with [W&B](https://docs.wandb.ai/guides/integrations/ultralytics/), [Comet](https://bit.ly/yolov8-readme-comet), [Roboflow](https://roboflow.com/?ref=ultralytics) and [OpenVINO](https://docs.ultralytics.com/integrations/openvino/), can optimize your AI workflow. +Our key integrations with leading AI platforms extend Ultralytics' capabilities, enhancing tasks like dataset labeling, training, visualization, and model management. Explore how Ultralytics works with [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/), [Comet ML](https://docs.ultralytics.com/integrations/comet/), [Roboflow](https://docs.ultralytics.com/integrations/roboflow/), and [Intel OpenVINO](https://docs.ultralytics.com/integrations/openvino/) to streamline your AI workflow.
@@ -168,30 +178,36 @@ Our key integrations with leading AI platforms extend the functionality of Ultra Ultralytics HUB logo space - - ClearML logo + + Weights & Biases logo space - + Comet ML logo space - + NeuralMagic logo -| Ultralytics HUB 🚀 | W&B | Comet ⭐ NEW | Neural Magic | -| :--------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | -| Streamline YOLO workflows: Label, train, and deploy effortlessly with [Ultralytics HUB](https://www.ultralytics.com/hub). Try now! | Track experiments, hyperparameters, and results with [Weights & Biases](https://docs.wandb.ai/guides/integrations/ultralytics/) | Free forever, [Comet](https://bit.ly/yolov5-readme-comet) lets you save YOLO models, resume training, and interactively visualize and debug predictions | Run YOLO11 inference up to 6x faster with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) | +| Ultralytics HUB 🚀 | W&B | Comet ⭐ NEW | Neural Magic | +| :-----------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------: | +| Streamline YOLO workflows: Label, train, and deploy effortlessly with [Ultralytics HUB](https://hub.ultralytics.com/). Try now! | Track experiments, hyperparameters, and results with [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/). | Free forever, [Comet](https://docs.ultralytics.com/integrations/comet/) lets you save YOLO models, resume training, and interactively visualize and debug predictions. | Run YOLO inference up to 6x faster with [Neural Magic DeepSparse](https://docs.ultralytics.com/integrations/neural-magic/). | -##
Ultralytics HUB
+##
☁️ Ultralytics HUB
-Experience seamless AI with [Ultralytics HUB](https://www.ultralytics.com/hub) ⭐, the all-in-one solution for data visualization, YOLO 🚀 model training and deployment, without any coding. Transform images into actionable insights and bring your AI visions to life with ease using our cutting-edge platform and user-friendly [Ultralytics App](https://www.ultralytics.com/app-install). Start your journey for **Free** now! +Experience seamless AI development with [Ultralytics HUB](https://hub.ultralytics.com/) ⭐, your all-in-one platform for data visualization, YOLO 🚀 model training, and deployment—no coding required. Convert images into actionable insights and realize your AI projects effortlessly using our advanced platform and intuitive [Ultralytics App](https://www.ultralytics.com/app-install). Begin your journey for **Free** today! - + -##
Why YOLOv3
+##
💡 Why YOLOv3?
+ +YOLOv3 marked a significant step in the evolution of real-time object detectors. Its key contributions include: + +- **Multi-Scale Predictions:** Detecting objects at three different scales using feature pyramids, improving accuracy for objects of varying sizes, especially small ones. +- **Improved Backbone:** Utilizing Darknet-53, a deeper and more complex network than its predecessor (Darknet-19), enhancing feature extraction capabilities. +- **Class Prediction:** Using logistic classifiers instead of softmax for class predictions, allowing for multi-label classification where an object can belong to multiple categories. -YOLOv3 has been designed to be super easy to get started and simple to learn. We prioritize real-world results. +While newer models like [YOLOv5](https://docs.ultralytics.com/models/yolov5/) and [YOLOv8](https://docs.ultralytics.com/models/yolov8/) offer further improvements in speed and accuracy, YOLOv3 remains a foundational model in the field and is still widely used and studied. The table below shows comparisons with later YOLOv5 models for context.

@@ -202,14 +218,16 @@ YOLOv3 has been designed to be super easy to get started and simple to learn. We
Figure Notes -- **COCO AP val** denotes mAP@0.5:0.95 metric measured on the 5000-image [COCO val2017](http://cocodataset.org) dataset over various inference sizes from 256 to 1536. -- **GPU Speed** measures average inference time per image on [COCO val2017](http://cocodataset.org) dataset using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p4/) V100 instance at batch-size 32. -- **EfficientDet** data from [google/automl](https://github.com/google/automl) at batch size 8. -- **Reproduce** by `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt` +- **COCO AP val** denotes [mAP@0.5:0.95](https://www.ultralytics.com/glossary/mean-average-precision-map) metric measured on the 5000-image COCO val2017 dataset over various inference sizes from 256 to 1536. See [COCO dataset](https://docs.ultralytics.com/datasets/detect/coco/). +- **GPU Speed** measures average inference time per image on the COCO val2017 dataset using an [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p4/) V100 instance at batch-size 32. +- **EfficientDet** data from [google/automl](https://github.com/google/automl) repository at batch size 8. +- **Reproduce** benchmark results using `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt`
-### Pretrained Checkpoints +### Pretrained Checkpoints (YOLOv5 Comparison) + +This table shows YOLOv5 models trained on the COCO dataset, often used as benchmarks. | Model | size
(pixels) | mAPval
50-95 | mAPval
50 | Speed
CPU b1
(ms) | Speed
V100 b1
(ms) | Speed
V100 b32
(ms) | params
(M) | FLOPs
@640 (B) | | ----------------------------------------------------------------------------------------------- | --------------------- | -------------------- | ----------------- | ---------------------------- | ----------------------------- | ------------------------------ | ------------------ | ---------------------- | @@ -228,26 +246,26 @@ YOLOv3 has been designed to be super easy to get started and simple to learn. We
Table Notes -- All checkpoints are trained to 300 epochs with default settings. Nano and Small models use [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) hyps, all others use [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml). -- **mAPval** values are for single-model single-scale on [COCO val2017](http://cocodataset.org) dataset.
Reproduce by `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` -- **Speed** averaged over COCO val images using a [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p4/) instance. NMS times (~1 ms/img) not included.
Reproduce by `python val.py --data coco.yaml --img 640 --task speed --batch 1` -- **TTA** [Test Time Augmentation](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/) includes reflection and scale augmentations.
Reproduce by `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment` +- All YOLOv5 checkpoints shown are trained to 300 epochs with default settings. Nano and Small models use `hyp.scratch-low.yaml` hyperparameters, others use `hyp.scratch-high.yaml`. See [Hyperparameter Tuning Guide](https://docs.ultralytics.com/guides/hyperparameter-tuning/). +- **mAPval** values are for single-model single-scale evaluation on the [COCO val2017 dataset](https://docs.ultralytics.com/datasets/detect/coco/).
Reproduce using `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65`. +- **Speed** metrics averaged over COCO val images using an [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p4/) instance. NMS times (~1 ms/img) are not included.
Reproduce using `python val.py --data coco.yaml --img 640 --task speed --batch 1`. +- **TTA** ([Test Time Augmentation](https://docs.ultralytics.com/modes/val/#inference-augmentation)) includes reflection and scale augmentations.
Reproduce using `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment`.
-##
Segmentation
+##
🖼️ Segmentation
-Our new YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7.0) instance segmentation models are the fastest and most accurate in the world, beating all current [SOTA benchmarks](https://paperswithcode.com/sota/real-time-instance-segmentation-on-mscoco). We've made them super simple to train, validate and deploy. See full details in our [Release Notes](https://github.com/ultralytics/yolov5/releases/v7.0) and visit our [YOLOv5 Segmentation Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/segment/tutorial.ipynb) for quickstart tutorials. +While YOLOv3 primarily focused on object detection, later Ultralytics models like YOLOv5 introduced instance segmentation capabilities. The YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7.0) included segmentation models that achieved state-of-the-art performance. These models are easy to train, validate, and deploy. See the [YOLOv5 Release Notes](https://github.com/ultralytics/yolov5/releases/v7.0) and the [YOLOv5 Segmentation Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/segment/tutorial.ipynb) for more details and tutorials.
- Segmentation Checkpoints + Segmentation Checkpoints (YOLOv5) -We trained YOLOv5 segmentations models on COCO for 300 epochs at image size 640 using A100 GPUs. We exported all models to ONNX FP32 for CPU speed tests and to TensorRT FP16 for GPU speed tests. We ran all speed tests on Google [Colab Pro](https://colab.research.google.com/signup) notebooks for easy reproducibility. +YOLOv5 segmentation models were trained on the [COCO-segments dataset](https://docs.ultralytics.com/datasets/segment/coco/) for 300 epochs at an image size of 640 using A100 GPUs. Models were exported to ONNX FP32 for CPU speed tests and TensorRT FP16 for GPU speed tests on Google [Colab Pro](https://colab.research.google.com/signup). | Model | size
(pixels) | mAPbox
50-95 | mAPmask
50-95 | Train time
300 epochs
A100 (hours) | Speed
ONNX CPU
(ms) | Speed
TRT A100
(ms) | params
(M) | FLOPs
@640 (B) | | ------------------------------------------------------------------------------------------ | --------------------- | -------------------- | --------------------- | --------------------------------------------- | ------------------------------ | ------------------------------ | ------------------ | ---------------------- | @@ -257,74 +275,77 @@ We trained YOLOv5 segmentations models on COCO for 300 epochs at image size 640 | [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | | [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | -- All checkpoints are trained to 300 epochs with SGD optimizer with `lr0=0.01` and `weight_decay=5e-5` at image size 640 and all default settings.
Runs logged to https://wandb.ai/glenn-jocher/YOLOv5_v70_official -- **Accuracy** values are for single-model single-scale on COCO dataset.
Reproduce by `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt` -- **Speed** averaged over 100 inference images using a [Colab Pro](https://colab.research.google.com/signup) A100 High-RAM instance. Values indicate inference speed only (NMS adds about 1ms per image).
Reproduce by `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt --batch 1` -- **Export** to ONNX at FP32 and TensorRT at FP16 done with `export.py`.
Reproduce by `python export.py --weights yolov5s-seg.pt --include engine --device 0 --half` +- All checkpoints trained for 300 epochs with SGD optimizer (`lr0=0.01`, `weight_decay=5e-5`) at image size 640 using default settings. Runs logged at [W&B YOLOv5_v70_official](https://wandb.ai/glenn-jocher/YOLOv5_v70_official). +- **Accuracy** values are for single-model, single-scale on the COCO dataset.
Reproduce with `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt`. +- **Speed** averaged over 100 inference images on a [Colab Pro](https://colab.research.google.com/signup) A100 High-RAM instance (inference only, NMS adds ~1ms/image).
Reproduce with `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt --batch 1`. +- **Export** to ONNX (FP32) and TensorRT (FP16) using `export.py`.
Reproduce with `python export.py --weights yolov5s-seg.pt --include engine --device 0 --half`.
- Segmentation Usage Examples  Open In Colab + Segmentation Usage Examples (YOLOv5)  Open In Colab ### Train -YOLOv5 segmentation training supports auto-download COCO128-seg segmentation dataset with `--data coco128-seg.yaml` argument and manual download of COCO-segments dataset with `bash data/scripts/get_coco.sh --train --val --segments` and then `python train.py --data coco.yaml`. +Train YOLOv5 segmentation models. Use `--data coco128-seg.yaml` for auto-download or manually download COCO-segments with `bash data/scripts/get_coco.sh --train --val --segments` then use `--data coco.yaml`. ```bash -# Single-GPU +# Single-GPU Training python segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 -# Multi-GPU DDP +# Multi-GPU DDP Training python -m torch.distributed.run --nproc_per_node 4 --master_port 1 segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 --device 0,1,2,3 ``` ### Val -Validate YOLOv5s-seg mask mAP on COCO dataset: +Validate YOLOv5s-seg mask mAP on the COCO dataset: ```bash -bash data/scripts/get_coco.sh --val --segments # download COCO val segments split (780MB, 5000 images) -python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 # validate +# Download COCO val segments split (780MB, 5000 images) +bash data/scripts/get_coco.sh --val --segments +# Validate performance +python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 ``` ### Predict -Use pretrained YOLOv5m-seg.pt to predict bus.jpg: +Use a pretrained YOLOv5m-seg model for prediction: ```bash +# Predict objects and masks in an image python segment/predict.py --weights yolov5m-seg.pt --data data/images/bus.jpg ``` ```python -model = torch.hub.load( - "ultralytics/yolov5", "custom", "yolov5m-seg.pt" -) # load from PyTorch Hub (WARNING: inference not yet supported) +# Load model via PyTorch Hub (Note: Segmentation inference might require specific handling) +# model = torch.hub.load("ultralytics/yolov5", "custom", "yolov5m-seg.pt") ``` -| ![zidane](https://user-images.githubusercontent.com/26833433/203113421-decef4c4-183d-4a0a-a6c2-6435b33bc5d3.jpg) | ![bus](https://user-images.githubusercontent.com/26833433/203113416-11fe0025-69f7-4874-a0a6-65d0bfe2999a.jpg) | -| ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | +| ![Zidane Segmentation Example](https://user-images.githubusercontent.com/26833433/203113421-decef4c4-183d-4a0a-a6c2-6435b33bc5d3.jpg) | ![Bus Segmentation Example](https://user-images.githubusercontent.com/26833433/203113416-11fe0025-69f7-4874-a0a6-65d0bfe2999a.jpg) | +| ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ### Export -Export YOLOv5s-seg model to ONNX and TensorRT: +Export a YOLOv5s-seg model to ONNX and TensorRT formats: ```bash +# Export model for deployment python export.py --weights yolov5s-seg.pt --include onnx engine --img 640 --device 0 ```
-##
Classification
+##
🏷️ Classification
-YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) brings support for classification model training, validation and deployment! See full details in our [Release Notes](https://github.com/ultralytics/yolov5/releases/v6.2) and visit our [YOLOv5 Classification Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/classify/tutorial.ipynb) for quickstart tutorials. +Similar to segmentation, image classification capabilities were formally introduced in later Ultralytics YOLO versions, specifically YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases/v6.2). These models allow for training, validation, and deployment for classification tasks. Check the [YOLOv5 Release Notes](https://github.com/ultralytics/yolov5/releases/v6.2) and the [YOLOv5 Classification Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/classify/tutorial.ipynb) for detailed information and examples.
- Classification Checkpoints + Classification Checkpoints (YOLOv5 & Others)
-We trained YOLOv5-cls classification models on ImageNet for 90 epochs using a 4xA100 instance, and we trained ResNet and EfficientNet models alongside with the same default training settings to compare. We exported all models to ONNX FP32 for CPU speed tests and to TensorRT FP16 for GPU speed tests. We ran all speed tests on Google [Colab Pro](https://colab.research.google.com/signup) for easy reproducibility. +YOLOv5-cls models were trained on [ImageNet](https://docs.ultralytics.com/datasets/classify/imagenet/) for 90 epochs using a 4xA100 instance. ResNet and EfficientNet models were trained alongside for comparison using the same settings. Models were exported to ONNX FP32 (CPU speed) and TensorRT FP16 (GPU speed) and tested on Google [Colab Pro](https://colab.research.google.com/signup). | Model | size
(pixels) | acc
top1 | acc
top5 | Training
90 epochs
4xA100 (hours) | Speed
ONNX CPU
(ms) | Speed
TensorRT V100
(ms) | params
(M) | FLOPs
@224 (B) | | -------------------------------------------------------------------------------------------------- | --------------------- | ---------------- | ---------------- | -------------------------------------------- | ------------------------------ | ----------------------------------- | ------------------ | ---------------------- | @@ -347,103 +368,105 @@ We trained YOLOv5-cls classification models on ImageNet for 90 epochs using a 4x
Table Notes (click to expand) -- All checkpoints are trained to 90 epochs with SGD optimizer with `lr0=0.001` and `weight_decay=5e-5` at image size 224 and all default settings.
Runs logged to https://wandb.ai/glenn-jocher/YOLOv5-Classifier-v6-2 -- **Accuracy** values are for single-model single-scale on [ImageNet-1k](https://www.image-net.org/index.php) dataset.
Reproduce by `python classify/val.py --data ../datasets/imagenet --img 224` -- **Speed** averaged over 100 inference images using a Google [Colab Pro](https://colab.research.google.com/signup) V100 High-RAM instance.
Reproduce by `python classify/val.py --data ../datasets/imagenet --img 224 --batch 1` -- **Export** to ONNX at FP32 and TensorRT at FP16 done with `export.py`.
Reproduce by `python export.py --weights yolov5s-cls.pt --include engine onnx --imgsz 224` +- All checkpoints trained for 90 epochs with SGD optimizer (`lr0=0.001`, `weight_decay=5e-5`) at image size 224 using default settings. Runs logged at [W&B YOLOv5-Classifier-v6-2](https://wandb.ai/glenn-jocher/YOLOv5-Classifier-v6-2). +- **Accuracy** values are for single-model, single-scale on the [ImageNet-1k dataset](https://www.image-net.org/index.php).
Reproduce with `python classify/val.py --data ../datasets/imagenet --img 224`. +- **Speed** averaged over 100 inference images using a Google [Colab Pro](https://colab.research.google.com/signup) V100 High-RAM instance.
Reproduce with `python classify/val.py --data ../datasets/imagenet --img 224 --batch 1`. +- **Export** to ONNX (FP32) and TensorRT (FP16) using `export.py`.
Reproduce with `python export.py --weights yolov5s-cls.pt --include engine onnx --imgsz 224`.
- Classification Usage Examples  Open In Colab + Classification Usage Examples (YOLOv5)  Open In Colab ### Train -YOLOv5 classification training supports auto-download of MNIST, Fashion-MNIST, CIFAR10, CIFAR100, Imagenette, Imagewoof, and ImageNet datasets with the `--data` argument. To start training on MNIST for example use `--data mnist`. +Train YOLOv5 classification models. Datasets like [MNIST](https://docs.ultralytics.com/datasets/classify/mnist/), [Fashion-MNIST](https://docs.ultralytics.com/datasets/classify/fashion-mnist/), [CIFAR10](https://docs.ultralytics.com/datasets/classify/cifar10/), [CIFAR100](https://docs.ultralytics.com/datasets/classify/cifar100/), [Imagenette](https://docs.ultralytics.com/datasets/classify/imagenette/), [Imagewoof](https://docs.ultralytics.com/datasets/classify/imagewoof/), and [ImageNet](https://docs.ultralytics.com/datasets/classify/imagenet/) can be auto-downloaded using the `--data` argument (e.g., `--data mnist`). ```bash -# Single-GPU +# Single-GPU Training on CIFAR-100 python classify/train.py --model yolov5s-cls.pt --data cifar100 --epochs 5 --img 224 --batch 128 -# Multi-GPU DDP +# Multi-GPU DDP Training on ImageNet python -m torch.distributed.run --nproc_per_node 4 --master_port 1 classify/train.py --model yolov5s-cls.pt --data imagenet --epochs 5 --img 224 --device 0,1,2,3 ``` ### Val -Validate YOLOv5m-cls accuracy on ImageNet-1k dataset: +Validate YOLOv5m-cls accuracy on the ImageNet-1k validation set: ```bash -bash data/scripts/get_imagenet.sh --val # download ImageNet val split (6.3G, 50000 images) -python classify/val.py --weights yolov5m-cls.pt --data ../datasets/imagenet --img 224 # validate +# Download ImageNet validation split (6.3G, 50000 images) +bash data/scripts/get_imagenet.sh --val +# Validate model accuracy +python classify/val.py --weights yolov5m-cls.pt --data ../datasets/imagenet --img 224 ``` ### Predict -Use pretrained YOLOv5s-cls.pt to predict bus.jpg: +Use a pretrained YOLOv5s-cls model to classify an image: ```bash +# Classify an image python classify/predict.py --weights yolov5s-cls.pt --data data/images/bus.jpg ``` ```python -model = torch.hub.load("ultralytics/yolov5", "custom", "yolov5s-cls.pt") # load from PyTorch Hub +# Load model via PyTorch Hub +# model = torch.hub.load("ultralytics/yolov5", "custom", "yolov5s-cls.pt") ``` ### Export -Export a group of trained YOLOv5s-cls, ResNet and EfficientNet models to ONNX and TensorRT: +Export trained classification models (YOLOv5s-cls, ResNet50, EfficientNet-B0) to ONNX and TensorRT formats: ```bash +# Export models for deployment python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --include onnx engine --img 224 ```
-##
Environments
+##
🌎 Environments
-Get started in seconds with our verified environments. Click each icon below for details. +Get started quickly with our verified environments. Click the icons below for setup details. -##
Contribute
- -We love your input! We want to make contributing to YOLOv3 as easy and transparent as possible. Please see our [Contributing Guide](https://docs.ultralytics.com/help/contributing/) to get started, and fill out the [YOLOv3 Survey](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to send us feedback on your experiences. Thank you to all our contributors! +##
💖 Contribute
- +We welcome your contributions! Making contributions to YOLOv3 should be easy and transparent. Please refer to our [Contributing Guide](https://docs.ultralytics.com/help/contributing/) for instructions on getting started. We also encourage you to fill out the [Ultralytics Survey](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to share your feedback. A huge thank you to all our contributors! - - +[![Ultralytics open-source contributors](https://raw.githubusercontent.com/ultralytics/assets/main/im/image-contributors.png)](https://github.com/ultralytics/ultralytics/graphs/contributors) -##
License
+##
📜 License
-Ultralytics offers two licensing options to accommodate diverse use cases: +Ultralytics provides two licensing options to suit different needs: -- **AGPL-3.0 License**: This [OSI-approved](https://opensource.org/license) open-source license is ideal for students and enthusiasts, promoting open collaboration and knowledge sharing. See the [LICENSE](https://github.com/ultralytics/yolov3/blob/master/LICENSE) file for more details. -- **Enterprise License**: Designed for commercial use, this license permits seamless integration of Ultralytics software and AI models into commercial goods and services, bypassing the open-source requirements of AGPL-3.0. If your scenario involves embedding our solutions into a commercial offering, reach out through [Ultralytics Licensing](https://www.ultralytics.com/license). +- **AGPL-3.0 License**: Ideal for students, researchers, and enthusiasts, this [OSI-approved](https://opensource.org/license/agpl-v3) open-source license encourages open collaboration and knowledge sharing. See the [LICENSE](https://github.com/ultralytics/yolov3/blob/master/LICENSE) file for details. +- **Enterprise License**: Tailored for commercial applications, this license allows the integration of Ultralytics software and AI models into commercial products and services, bypassing the open-source requirements of AGPL-3.0. For commercial use cases, please contact us via [Ultralytics Licensing](https://www.ultralytics.com/license). -##
Contact
+##
📞 Contact
-For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues), and join our [Discord](https://discord.com/invite/ultralytics) community for questions and discussions! +For bug reports and feature requests related to YOLOv3, please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues). For general questions, discussions, and community interaction, join our [Discord server](https://discord.com/invite/ultralytics)!
@@ -461,5 +484,3 @@ For YOLOv3 bug reports and feature requests please visit [GitHub Issues](https:/ Ultralytics Discord
- -[tta]: https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation diff --git a/data/scripts/download_weights.sh b/data/scripts/download_weights.sh index 16b14b9616..7726a9bd18 100755 --- a/data/scripts/download_weights.sh +++ b/data/scripts/download_weights.sh @@ -1,5 +1,6 @@ #!/bin/bash -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Download latest models from https://github.com/ultralytics/yolov5/releases # Example usage: bash data/scripts/download_weights.sh # parent diff --git a/data/scripts/get_coco.sh b/data/scripts/get_coco.sh index 6a5cbffb25..e8ea16944d 100755 --- a/data/scripts/get_coco.sh +++ b/data/scripts/get_coco.sh @@ -1,5 +1,6 @@ #!/bin/bash -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Download COCO 2017 dataset http://cocodataset.org # Example usage: bash data/scripts/get_coco.sh # parent diff --git a/data/scripts/get_coco128.sh b/data/scripts/get_coco128.sh index 99f5f4d68f..a44eb84524 100755 --- a/data/scripts/get_coco128.sh +++ b/data/scripts/get_coco128.sh @@ -1,5 +1,6 @@ #!/bin/bash -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Download COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) # Example usage: bash data/scripts/get_coco128.sh # parent diff --git a/data/scripts/get_imagenet.sh b/data/scripts/get_imagenet.sh index 2f2f8db3b2..359cded855 100755 --- a/data/scripts/get_imagenet.sh +++ b/data/scripts/get_imagenet.sh @@ -1,5 +1,6 @@ #!/bin/bash -# YOLOv3 🚀 by Ultralytics, AGPL-3.0 license +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # Download ILSVRC2012 ImageNet dataset https://image-net.org # Example usage: bash data/scripts/get_imagenet.sh # parent diff --git a/utils/aws/mime.sh b/utils/aws/mime.sh index c319a83cfb..f69cab0a84 100644 --- a/utils/aws/mime.sh +++ b/utils/aws/mime.sh @@ -1,3 +1,5 @@ +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # AWS EC2 instance startup 'MIME' script https://aws.amazon.com/premiumsupport/knowledge-center/execute-user-data-ec2/ # This script will run on every instance restart, not only on first start # --- DO NOT COPY ABOVE COMMENTS WHEN PASTING INTO USERDATA --- diff --git a/utils/aws/userdata.sh b/utils/aws/userdata.sh index 5fc1332ac1..4e5dfadec4 100644 --- a/utils/aws/userdata.sh +++ b/utils/aws/userdata.sh @@ -1,4 +1,6 @@ #!/bin/bash +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + # AWS EC2 instance startup script https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html # This script will run only once on first instance start (for a re-start script see mime.sh) # /home/ubuntu (ubuntu) or /home/ec2-user (amazon-linux) is working dir diff --git a/utils/flask_rest_api/README.md b/utils/flask_rest_api/README.md index d3ffaa2069..b7a2b1aa06 100644 --- a/utils/flask_rest_api/README.md +++ b/utils/flask_rest_api/README.md @@ -1,30 +1,52 @@ -# Flask REST API +Ultralytics logo -[REST](https://en.wikipedia.org/wiki/Representational_state_transfer) [API](https://en.wikipedia.org/wiki/API)s are commonly used to expose Machine Learning (ML) models to other services. This folder contains an example REST API created using Flask to expose the YOLOv5s model from [PyTorch Hub](https://pytorch.org/hub/ultralytics_yolov5/). +# Flask REST API Example for YOLO Models -## Requirements +[Representational State Transfer (REST)](https://en.wikipedia.org/wiki/Representational_state_transfer) [Application Programming Interfaces (APIs)](https://developer.mozilla.org/en-US/docs/Web/API) are a standard way to expose [Machine Learning (ML)](https://www.ultralytics.com/glossary/machine-learning-ml) models, allowing other services or applications to interact with them over a network. This directory provides an example REST API built using the [Flask](https://palletsprojects.com/projects/flask/) microframework to serve predictions from an [Ultralytics YOLOv5s](https://docs.ultralytics.com/models/yolov5/) model loaded via [PyTorch Hub](https://pytorch.org/hub/ultralytics_yolov5/). -[Flask](https://palletsprojects.com/projects/flask/) is required. Install with: +Deploying models via APIs is a crucial step in [MLOps](https://www.ultralytics.com/glossary/machine-learning-operations-mlops) and enables integration into larger systems. You can explore various [model deployment options](https://docs.ultralytics.com/guides/model-deployment-options/) for different scenarios. + +## 🔧 Requirements + +Ensure you have the necessary Python packages installed. The primary requirement is Flask. + +Install Flask using pip: ```shell -$ pip install Flask +pip install Flask torch torchvision ``` -## Run +_Note: `torch` and `torchvision` are required by the YOLOv5 model from PyTorch Hub._ + +## ▶️ Run the API -After Flask installation run: +Once Flask and dependencies are installed, you can start the API server. + +Execute the Python script: ```shell -$ python3 restapi.py --port 5000 +python restapi.py --port 5000 ``` -Then use [curl](https://curl.se/) to perform a request: +The API server will start listening on the specified port (default is 5000). + +## 🚀 Make a Prediction Request + +You can send prediction requests to the running API using tools like [`curl`](https://curl.se/) or scripting languages. + +Send a POST request with an image file (`zidane.jpg` in this example) to the `/v1/object-detection/yolov5s` endpoint: ```shell -$ curl -X POST -F image=@zidane.jpg 'http://localhost:5000/v1/object-detection/yolov5s' +curl -X POST -F image=@zidane.jpg 'http://localhost:5000/v1/object-detection/yolov5s' ``` -The model inference results are returned as a JSON response: +_Ensure `zidane.jpg` (or your test image) is present in the directory where you run the `curl` command._ + +## 📄 Understand the Response + +The API processes the image and returns the [object detection](https://www.ultralytics.com/glossary/object-detection) results in [JSON](https://www.ultralytics.com/glossary/json) format. Each object detected includes its class ID, confidence score, bounding box coordinates (normalized), and class name. + +Example JSON response: ```json [ @@ -67,4 +89,8 @@ The model inference results are returned as a JSON response: ] ``` -An example python script to perform inference using [requests](https://docs.python-requests.org/en/master/) is given in `example_request.py` +An example Python script (`example_request.py`) demonstrating how to send requests using the popular [requests](https://requests.readthedocs.io/en/latest/) library is also included in this directory. + +## 🤝 Contributing + +Contributions to enhance this example or add support for other Ultralytics models are welcome! Please see the main Ultralytics [CONTRIBUTING](https://docs.ultralytics.com/help/contributing/) guide for more information on how to get involved. diff --git a/utils/loggers/clearml/README.md b/utils/loggers/clearml/README.md index f81f48e8c1..56af5898cf 100644 --- a/utils/loggers/clearml/README.md +++ b/utils/loggers/clearml/README.md @@ -1,222 +1,223 @@ -# ClearML Integration +Ultralytics logo -Clear|MLClear|ML - -## About ClearML +# ClearML Integration for Ultralytics YOLO -[ClearML](https://clear.ml/) is an [open-source](https://github.com/clearml/clearml) toolbox designed to save you time ⏱️. +This guide explains how to integrate [ClearML](https://clear.ml/), an open-source MLOps platform, with your Ultralytics YOLOv5 projects. ClearML helps streamline your machine learning workflow from experiment tracking to deployment. -🔨 Track every YOLOv5 training run in the experiment manager - -🔧 Version and easily access your custom training data with the integrated ClearML Data Versioning Tool +Clear|MLClear|ML -🔦 Remotely train and monitor your YOLOv5 training runs using ClearML Agent +## ✨ About ClearML -🔬 Get the very best mAP using ClearML Hyperparameter Optimization +[ClearML](https://clear.ml/) is an [open-source](https://github.com/clearml/clearml) suite of tools designed to manage, automate, and orchestrate machine learning workflows, significantly saving development time ⏱️. Integrating ClearML with Ultralytics YOLOv5 provides several benefits: -🔭 Turn your newly trained YOLOv5 model into an API with just a few commands using ClearML Serving +- **Experiment Management**: Automatically track every YOLOv5 training run, including code versions, configurations, metrics, and outputs in a centralized dashboard. Learn more about [Ultralytics experiment tracking integrations](https://docs.ultralytics.com/integrations/). +- **Data Versioning**: Use the ClearML Data Versioning Tool to manage and easily access your custom training datasets. See how Ultralytics handles [datasets](https://docs.ultralytics.com/datasets/). +- **Remote Execution**: Remotely train and monitor your YOLOv5 models using ClearML Agent on different machines or cloud instances. Explore [model deployment options](https://docs.ultralytics.com/guides/model-deployment-options/). +- **Hyperparameter Optimization**: Leverage ClearML Hyperparameter Optimization to find the best model configurations and improve [Mean Average Precision (mAP)](https://www.ultralytics.com/glossary/mean-average-precision-map). Check out the Ultralytics [Hyperparameter Tuning guide](https://docs.ultralytics.com/guides/hyperparameter-tuning/). +- **Model Deployment**: Turn your trained YOLOv5 models into scalable APIs using ClearML Serving with just a few commands. -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! +You can choose to use any combination of these tools to fit your project needs. ![ClearML scalars dashboard](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/experiment_manager_with_compare.gif) ## 🦾 Setting Things Up -To keep track of your experiments and/or data, ClearML needs to communicate to a server. You have 2 options to get one: +To start using ClearML, you need to connect the SDK to a ClearML Server instance. You have two main options: -Either sign up for free to the [ClearML Hosted Service](https://clear.ml/) 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! +1. **ClearML Hosted Service**: Sign up for a free account at the [ClearML Hosted Service](https://app.clear.ml/). +2. **Self-Hosted Server**: Set up your own [ClearML Server](https://clear.ml/docs/latest/docs/deploying_clearml/clearml_server). The server is also open-source, providing flexibility for data privacy concerns. -1. Install the `clearml` python package: +Follow these steps to get started: - ```bash - pip install clearml - ``` +1. Install the `clearml` Python package using pip: -2. 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: + ```bash + pip install clearml + ``` - ```bash - clearml-init - ``` +2. Connect the ClearML SDK to your server. Generate credentials through the ClearML Web UI (Settings -> Workspace -> Create new credentials) and run the following command in your terminal, following the prompts: + ```bash + clearml-init + ``` -That's it! You're done 😎 +Once configured, ClearML is ready to integrate with your YOLOv5 workflows! 😎 ## 🚀 Training YOLOv5 With ClearML -To enable ClearML experiment tracking, simply install the ClearML pip package. +Enabling ClearML experiment tracking for YOLOv5 is straightforward. Simply ensure the `clearml` package is installed: ```bash pip install clearml > =1.2.0 ``` -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. +With the package installed, ClearML automatically captures details for every YOLOv5 [training run](https://docs.ultralytics.com/modes/train/). -If you want to change the `project_name` or `task_name`, use the `--project` and `--name` arguments of the `train.py` script, by default the project will be called `YOLOv5` and the task `Training`. PLEASE NOTE: ClearML uses `/` as a delimiter for subprojects, so be careful when using `/` in your project name! +By default, experiments are logged under the `YOLOv5` project with the task name `Training`. You can customize these using the `--project` and `--name` arguments in your training command. Note that ClearML uses `/` as a delimiter for subprojects. + +**Example Training Command:** ```bash +# Train with default project/task names python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov5s.pt --cache ``` -or with custom project and task name: +**Example with Custom Names:** ```bash -python train.py --project my_project --name my_training --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov5s.pt --cache +# Train with custom project and task names +python train.py --project my_yolo_project --name experiment_001 --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov5s.pt --cache ``` -This will capture: - -- Source code + uncommitted changes -- Installed packages -- (Hyper)parameters -- Model files (use `--save-period n` to save a checkpoint every n epochs) -- Console output -- Scalars (mAP_0.5, mAP_0.5:0.95, precision, recall, losses, learning rates, ...) -- General info such as machine details, runtime, creation date etc. -- All produced plots such as label correlogram and confusion matrix -- Images with bounding boxes per epoch -- Mosaic per epoch -- Validation images per epoch -- ... +ClearML will automatically capture: -That's a lot right? 🤯 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! +- Git repository details (URL, commit ID, entry point) and local code changes. +- Installed Python packages and versions. +- [Hyperparameters](https://www.ultralytics.com/glossary/hyperparameter-tuning) and script arguments. +- [Model checkpoints](https://www.ultralytics.com/glossary/model-weights) (use `--save-period n` to save every `n` epochs). +- Console output (stdout and stderr). +- Performance [metrics/scalars](https://docs.ultralytics.com/guides/yolo-performance-metrics/) like mAP_0.5, mAP_0.5:0.95, precision, recall, losses, and learning rates. +- Machine details, runtime, and creation date. +- Generated plots like label correlograms and [confusion matrices](https://www.ultralytics.com/glossary/confusion-matrix). +- Debug samples: images with bounding boxes, mosaic visualizations, and validation images per epoch. -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! +This comprehensive tracking allows you to visualize progress in the ClearML UI, compare experiments, and easily identify the best-performing models by sorting based on metrics like [mAP](https://www.ultralytics.com/glossary/mean-average-precision-map). ## 🔗 Dataset Version Management -Versioning your data separately from your code is generally a good idea and makes it easy to acquire 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! +Versioning datasets is crucial for reproducibility and collaboration in [machine learning](https://www.ultralytics.com/glossary/machine-learning-ml) projects. ClearML Data helps manage datasets efficiently. YOLOv5 supports using ClearML dataset IDs directly in the training command. ![ClearML Dataset Interface](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/clearml_data.gif) ### Prepare Your Dataset -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: +YOLOv5 uses YAML files to define dataset configurations. Datasets are typically expected in a specific structure, often downloaded to a `../datasets` directory relative to your repository root. For example, the [COCO128 dataset](https://docs.ultralytics.com/datasets/detect/coco128/) structure looks like this: ``` -.. -|_ yolov5 -|_ datasets - |_ coco128 - |_ images - |_ labels - |_ LICENSE - |_ README.txt +../ +├── yolov5/ # Your repository +└── datasets/ + └── coco128/ # Dataset root folder + ├── images/ + ├── labels/ + ├── coco128.yaml # Dataset configuration file <--- IMPORTANT + ├── LICENSE + └── README.txt ``` -But this can be any dataset you wish. Feel free to use your own, as long as you keep to this folder structure. - -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. +Ensure your custom dataset follows a similar structure. -Basically we need the following keys: `path`, `train`, `test`, `val`, `nc`, `names`. - -``` -.. -|_ yolov5 -|_ datasets - |_ coco128 - |_ images - |_ labels - |_ coco128.yaml # <---- HERE! - |_ LICENSE - |_ README.txt -``` +⚠️ **Important**: Copy the corresponding dataset `.yaml` configuration file into the **root directory** of your dataset folder (e.g., `datasets/coco128/coco128.yaml`). This YAML file must contain keys like `path`, `train`, `val`, `test`, `nc` (number of classes), and `names` (class names list) for ClearML integration to work correctly. ### Upload Your Dataset -To get this dataset into ClearML as a versioned dataset, go to the dataset root folder and run the following command: +Navigate to your dataset's root folder in the terminal and use the `clearml-data` CLI tool to upload and version it: ```bash -cd coco128 -clearml-data sync --project YOLOv3 --name coco128 --folder . +# Navigate to the dataset directory +cd ../datasets/coco128 + +# Sync the dataset with ClearML (creates a versioned dataset) +clearml-data sync --project "YOLOv5 Datasets" --name coco128 --folder . ``` -The command `clearml-data sync` is actually a shorthand command. You could also run these commands one after the other: +This command creates a new ClearML dataset (or a new version if it exists) named `coco128` within the `YOLOv5 Datasets` project. + +Alternatively, you can use granular commands: ```bash -# Optionally add --parent if you want to base -# this version on another dataset version, so no duplicate files are uploaded! -clearml-data create --name coco128 --project YOLOv3 +# Create a new dataset task +clearml-data create --project "YOLOv5 Datasets" --name coco128 + +# Add files to the dataset (use '.' for current folder) clearml-data add --files . + +# Finalize and upload the dataset version clearml-data close ``` -### Run Training Using A ClearML Dataset +### Run Training Using a ClearML Dataset -Now that you have a ClearML dataset, you can very simply use it to train custom YOLOv5 🚀 models! +Once your dataset is versioned in ClearML, you can reference it directly in your YOLOv5 training command using its unique ID. ClearML will automatically download the dataset if it's not present locally. ```bash +# Replace with the actual ID from ClearML python train.py --img 640 --batch 16 --epochs 3 --data clearml:// yolov5s.pt --cache < your_dataset_id > --weights ``` -## 👀 Hyperparameter Optimization +The dataset ID used will be logged as a parameter in your ClearML experiment, ensuring full traceability. -Now that we have our experiments and data versioned, it's time to take a look at what we can build on top! +## 👀 Hyperparameter Optimization -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! +ClearML's experiment tracking captures all necessary information (code, environment, parameters) to reproduce a run. This reproducibility is the foundation for effective [Hyperparameter Optimization (HPO)](https://docs.ultralytics.com/guides/hyperparameter-tuning/). ClearML allows you to clone experiments, modify hyperparameters, and automatically rerun them. -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. +To run HPO locally, Ultralytics provides a sample script. You'll need the ID of a previously executed training task (the "template task") to use as a base. -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. +1. Locate the HPO script at `utils/loggers/clearml/hpo.py`. +2. Edit the script to include the `template task` ID. +3. Optionally, install [Optuna](https://optuna.org/) (`pip install optuna`) for advanced optimization strategies, or use the default `RandomSearch`. +4. Run the script: + ```bash + python utils/loggers/clearml/hpo.py + ``` -```bash -# To use optuna, install it first, otherwise you can change the optimizer to just be RandomSearch -pip install optuna -python utils/loggers/clearml/hpo.py -``` +This script clones the template task, applies new hyperparameters suggested by the optimizer, and executes the modified task locally (`task.execute_locally()`). To run HPO remotely, change this to `task.execute()` to enqueue the tasks for a ClearML Agent. -![HPO](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/hpo.png) +![HPO in ClearML UI](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/hpo.png) -## 🤯 Remote Execution (advanced) +## 🤯 Remote Execution (Advanced) -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. This is where the ClearML Agent comes into play. Check out what the agent can do here: +ClearML Agent enables running experiments on remote machines (e.g., powerful on-premises servers or cloud GPUs). The agent fetches tasks from a queue, replicates the original environment (code, packages, uncommitted changes), executes the task, and reports results back to the ClearML Server. -- [YouTube video](https://www.youtube.com/watch?v=MX3BrXnaULs&feature=youtu.be) -- [Documentation](https://clear.ml/docs/latest/docs/clearml_agent) +- **Learn More**: Watch the [ClearML Agent Introduction](https://www.youtube.com/watch?v=MX3BrXnaULs) or read the [documentation](https://clear.ml/docs/latest/docs/clearml_agent). -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. - -You can turn any machine (a cloud VM, a local GPU machine, your own laptop ... ) into a ClearML agent by simply running: +Turn any machine into a ClearML Agent by running the following command: ```bash -clearml-agent daemon --queue < queues_to_listen_to > [--docker] +# Replace with the name(s) of your queue(s) +clearml-agent daemon --queue < queues_to_listen_to > [--docker] # Use --docker to run in a Docker container ``` -### Cloning, Editing And Enqueuing - -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! - -🪄 Clone the experiment by right-clicking it +### Cloning, Editing, and Enqueuing Tasks -🎯 Edit the hyperparameters to what you wish them to be +You can manage remote execution tasks through the ClearML Web UI: -⏳ Enqueue the task to any of the queues by right-clicking it +1. **Clone**: Right-click an existing experiment to clone it. +2. **Edit**: Modify hyperparameters or other configurations in the cloned task. +3. **Enqueue**: Right-click the modified task and select "Enqueue" to assign it to a specific queue monitored by your agents. -![Enqueue a task from the UI](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/enqueue.gif) +![Enqueue a task from the ClearML UI](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/enqueue.gif) -### Executing A Task Remotely +### Executing a Task Remotely via Code -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! - -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 instantiated: +Alternatively, you can modify your training script to automatically enqueue the task for remote execution. Add `task.execute_remotely()` after the ClearML logger is initialized in `train.py`: ```python -# ... -# Loggers -data_dict = None +# ... inside train.py ... + +# Loggers setup if RANK in {-1, 0}: - loggers = Loggers(save_dir, weights, opt, hyp, LOGGER) # loggers instance + # Initialize loggers, including ClearML + loggers = Loggers(save_dir, weights, opt, hyp, LOGGER) + if loggers.clearml: - loggers.clearml.task.execute_remotely(queue="my_queue") # <------ ADD THIS LINE - # Data_dict is either None is user did not choose for ClearML dataset or is filled in by ClearML + # Add this line to send the task to a queue for remote execution + loggers.clearml.task.execute_remotely(queue_name="my_default_queue") + + # Get dataset dictionary if using ClearML datasets data_dict = loggers.clearml.data_dict -# ... +# ... rest of the script ... ``` -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! +When you run the modified `train.py`, the script execution will pause, package the code and environment, and send the task to the specified queue (`my_default_queue` in this example). A ClearML Agent listening to that queue will then pick it up and run it. + +### Autoscaling Agents + +ClearML also provides **Autoscalers** that automatically provision and manage cloud instances (AWS, GCP, Azure) as ClearML Agents based on queue load. They spin up machines when tasks are pending and shut them down when idle, optimizing resource usage and cost. -### Autoscaling workers +Learn how to set up autoscalers: -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! +[![Watch the Autoscaler setup video](https://img.youtube.com/vi/j4XVMAaUt3E/0.jpg)](https://youtu.be/j4XVMAaUt3E) -Check out the autoscalers getting started video below. +## 👋 Contribute -[![Watch the video](https://img.youtube.com/vi/j4XVMAaUt3E/0.jpg)](https://youtu.be/j4XVMAaUt3E) +Contributions are welcome! If you'd like to improve this integration or suggest features, please see the Ultralytics [Contributing Guide](https://docs.ultralytics.com/help/contributing/) and submit a Pull Request. Thank you to all our contributors! diff --git a/utils/loggers/comet/README.md b/utils/loggers/comet/README.md index 353698dd4d..1b39260f72 100644 --- a/utils/loggers/comet/README.md +++ b/utils/loggers/comet/README.md @@ -1,104 +1,107 @@ +Ultralytics logo + -# YOLOv5 with Comet +# YOLOv5 Integration with Comet -This guide will cover how to use YOLOv5 with [Comet](https://bit.ly/yolov5-readme-comet2) +This guide details how to effectively use YOLOv5 with [Comet](https://bit.ly/yolov5-readme-comet2) for experiment tracking and model optimization. # About Comet -Comet builds tools that help data scientists, engineers, and team leaders accelerate and optimize machine learning and deep learning models. +[Comet](https://www.comet.com/site/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) provides tools designed to help data scientists, engineers, and team leaders accelerate and optimize machine learning and deep learning models. -Track and visualize model metrics in real time, save your hyperparameters, datasets, and model checkpoints, and visualize your model predictions with [Comet Custom Panels](https://www.comet.com/docs/v2/guides/comet-dashboard/code-panels/about-panels/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github)! Comet makes sure you never lose track of your work and makes it easy to share results and collaborate across teams of all sizes! +With Comet, you can track and visualize model metrics in real-time, save hyperparameters, datasets, and model checkpoints, and visualize model predictions using [Comet Custom Panels](https://www.comet.com/docs/v2/guides/comet-dashboard/code-panels/about-panels/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). Comet ensures your work is never lost and simplifies sharing results and collaboration across teams of any size. -# Getting Started +# 🚀 Getting Started ## Install Comet +Install the necessary package using pip: + ```shell pip install comet_ml ``` ## Configure Comet Credentials -There are two ways to configure Comet with YOLOv5. - -You can either set your credentials through environment variables +You can configure Comet credentials for YOLOv5 in two ways: -**Environment Variables** - -```shell -export COMET_API_KEY= -export COMET_PROJECT_NAME= # This will default to 'yolov5' -``` +1. **Environment Variables**: Set your credentials directly in your environment. -Or create a `.comet.config` file in your working directory and set your credentials there. + ```shell + export COMET_API_KEY= + export COMET_PROJECT_NAME= # Defaults to 'yolov5' if not set + ``` -**Comet Configuration File** +2. **Comet Configuration File**: Create a `.comet.config` file in your working directory and add your credentials there. -``` -[comet] -api_key= -project_name= # This will default to 'yolov5' -``` + ``` + [comet] + api_key= + project_name= # Defaults to 'yolov5' if not set + ``` ## Run the Training Script +Execute the [Ultralytics training script](https://docs.ultralytics.com/modes/train/) as you normally would. Comet automatically integrates with YOLOv5. + ```shell # Train YOLOv5s on COCO128 for 5 epochs python train.py --img 640 --batch 16 --epochs 5 --data coco128.yaml --weights yolov5s.pt ``` -That's it! Comet will automatically log your hyperparameters, command line arguments, training and validation metrics. You can visualize and analyze your runs in the Comet UI +That's it! Comet will automatically log your hyperparameters, command-line arguments, training metrics, and validation metrics. You can visualize and analyze your runs in the Comet UI. For more details on metrics like mAP and Recall, see the [YOLO Performance Metrics guide](https://docs.ultralytics.com/guides/yolo-performance-metrics/). -yolo-ui +Comet UI showing YOLOv5 training run -# Try out an Example! +# ✨ Try an Example! -Check out an example of a [completed run here](https://www.comet.com/examples/comet-example-yolov5/a0e29e0e9b984e4a822db2a62d0cb357?experiment-tab=chart&showOutliers=true&smoothing=0&transformY=smoothing&xAxis=step&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) +Explore an example of a [completed run in the Comet UI](https://www.comet.com/examples/comet-example-yolov5/a0e29e0e9b984e4a822db2a62d0cb357?experiment-tab=chart&showOutliers=true&smoothing=0&transformY=smoothing&xAxis=step&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). -Or better yet, try it out yourself in this Colab Notebook +Or, try it yourself using this Colab Notebook: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/comet-ml/comet-examples/blob/master/integrations/model-training/yolov5/notebooks/Comet_and_YOLOv5.ipynb) -# Log automatically +# 📊 Automatic Logging -By default, Comet will log the following items +By default, Comet automatically logs the following: ## Metrics -- Box Loss, Object Loss, Classification Loss for the training and validation data -- mAP_0.5, mAP_0.5:0.95 metrics for the validation data. -- Precision and Recall for the validation data +- Box Loss, Object Loss, Classification Loss (Training and Validation) +- mAP_0.5, mAP_0.5:0.95 (Validation) +- Precision and Recall (Validation) ## Parameters - Model Hyperparameters -- All parameters passed through the command line options +- All command-line options passed during training ## Visualizations -- Confusion Matrix of the model predictions on the validation data -- Plots for the PR and F1 curves across all classes -- Correlogram of the Class Labels +- Confusion Matrix of model predictions on validation data +- Plots for PR and F1 curves across all classes +- Correlogram of Class Labels -# Configure Comet Logging +# ⚙️ Configure Comet Logging -Comet can be configured to log additional data either through command line flags passed to the training script or through environment variables. +You can configure Comet to log additional data using command-line flags or environment variables. ```shell -export COMET_MODE=online # Set whether to run Comet in 'online' or 'offline' mode. Defaults to online -export COMET_MODEL_NAME= #Set the name for the saved model. Defaults to yolov5 -export COMET_LOG_CONFUSION_MATRIX=false # Set to disable logging a Comet Confusion Matrix. Defaults to true -export COMET_MAX_IMAGE_UPLOADS= # Controls how many total image predictions to log to Comet. Defaults to 100. -export COMET_LOG_PER_CLASS_METRICS=true # Set to log evaluation metrics for each detected class at the end of training. Defaults to false -export COMET_DEFAULT_CHECKPOINT_FILENAME= # Set this if you would like to resume training from a different checkpoint. Defaults to 'last.pt' -export COMET_LOG_BATCH_LEVEL_METRICS=true # Set this if you would like to log training metrics at the batch level. Defaults to false. -export COMET_LOG_PREDICTIONS=true # Set this to false to disable logging model predictions +# Environment Variables for Comet Configuration +export COMET_MODE=online # 'online' or 'offline'. Defaults to online. +export COMET_MODEL_NAME= # Name for the saved model. Defaults to yolov5. +export COMET_LOG_CONFUSION_MATRIX=false # Disable logging Confusion Matrix. Defaults to true. +export COMET_MAX_IMAGE_UPLOADS= # Max prediction images to log. Defaults to 100. +export COMET_LOG_PER_CLASS_METRICS=true # Log evaluation metrics per class. Defaults to false. +export COMET_DEFAULT_CHECKPOINT_FILENAME= # Checkpoint for resuming. Defaults to 'last.pt'. +export COMET_LOG_BATCH_LEVEL_METRICS=true # Log training metrics per batch. Defaults to false. +export COMET_LOG_PREDICTIONS=true # Set to false to disable logging model predictions. Defaults to true. ``` ## Logging Checkpoints with Comet -Logging Models to Comet is disabled by default. To enable it, pass the `save-period` argument to the training script. This will save the logged checkpoints to Comet based on the interval value provided by `save-period` +Logging [model checkpoints](https://docs.ultralytics.com/guides/model-training-tips/#checkpoints) to Comet is disabled by default. Enable it by passing the `save-period` argument to the training script. Checkpoints will be saved to Comet at the specified interval. ```shell python train.py \ @@ -107,18 +110,16 @@ python train.py \ --epochs 5 \ --data coco128.yaml \ --weights yolov5s.pt \ - --save-period 1 + --save-period 1 # Saves checkpoints every epoch ``` ## Logging Model Predictions -By default, model predictions (images, ground truth labels and bounding boxes) will be logged to Comet. - -You can control the frequency of logged predictions and the associated images by passing the `bbox_interval` command line argument. Predictions can be visualized using Comet's Object Detection Custom Panel. This frequency corresponds to every Nth batch of data per epoch. In the example below, we are logging every 2nd batch of data for each epoch. +Model predictions (images, ground truth labels, bounding boxes) are logged to Comet by default. Control the frequency using the `bbox_interval` argument. This value corresponds to logging every Nth batch per epoch. Predictions can be visualized using Comet's Object Detection Custom Panel. -**Note:** The YOLOv5 validation dataloader will default to a batch size of 32, so you will have to set the logging frequency accordingly. +**Note:** The YOLOv5 validation dataloader defaults to a batch size of 32. Adjust the logging frequency accordingly. -Here is an [example project using the Panel](https://www.comet.com/examples/comet-example-yolov5?shareable=YcwMiJaZSXfcEXpGOHDD12vA1&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) +See an [example project using the Panel here](https://www.comet.com/examples/comet-example-yolov5?shareable=YcwMiJaZSXfcEXpGOHDD12vA1&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). ```shell python train.py \ @@ -127,12 +128,12 @@ python train.py \ --epochs 5 \ --data coco128.yaml \ --weights yolov5s.pt \ - --bbox_interval 2 + --bbox_interval 2 # Logs predictions every 2nd batch per epoch ``` -### Controlling the number of Prediction Images logged to Comet +### Controlling the Number of Prediction Images Logged -When logging predictions from YOLOv5, Comet will log the images associated with each set of predictions. By default a maximum of 100 validation images are logged. You can increase or decrease this number using the `COMET_MAX_IMAGE_UPLOADS` environment variable. +Comet logs images associated with predictions. The default maximum is 100 validation images. Adjust this using the `COMET_MAX_IMAGE_UPLOADS` environment variable. ```shell env COMET_MAX_IMAGE_UPLOADS=200 python train.py \ @@ -146,7 +147,7 @@ env COMET_MAX_IMAGE_UPLOADS=200 python train.py \ ### Logging Class Level Metrics -Use the `COMET_LOG_PER_CLASS_METRICS` environment variable to log mAP, precision, recall, f1 for each class. +Use the `COMET_LOG_PER_CLASS_METRICS` environment variable to log mAP, precision, recall, and F1-score for each class. ```shell env COMET_LOG_PER_CLASS_METRICS=true python train.py \ @@ -157,11 +158,9 @@ env COMET_LOG_PER_CLASS_METRICS=true python train.py \ --weights yolov5s.pt ``` -## Uploading a Dataset to Comet Artifacts +## 💾 Uploading a Dataset to Comet Artifacts -If you would like to store your data using [Comet Artifacts](https://www.comet.com/docs/v2/guides/data-management/using-artifacts/#learn-more?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github), you can do so using the `upload_dataset` flag. - -The dataset be organized in the way described in the [YOLOv5 documentation](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/). The dataset config `yaml` file must follow the same format as that of the `coco128.yaml` file. +Store your [datasets](https://docs.ultralytics.com/datasets/) using [Comet Artifacts](https://www.comet.com/docs/v2/guides/data-management/using-artifacts/#learn-more?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) by using the `upload_dataset` flag. Ensure your dataset follows the structure described in the [Ultralytics dataset guide](https://docs.ultralytics.com/datasets/). The dataset config `yaml` file must match the format of `coco128.yaml`. ```shell python train.py \ @@ -170,25 +169,31 @@ python train.py \ --epochs 5 \ --data coco128.yaml \ --weights yolov5s.pt \ - --upload_dataset + --upload_dataset # Uploads the dataset specified in coco128.yaml ``` -You can find the uploaded dataset in the Artifacts tab in your Comet Workspace artifact-1 +Find the uploaded dataset in the Artifacts tab in your Comet Workspace. +Comet Artifacts tab showing uploaded dataset -You can preview the data directly in the Comet UI. artifact-2 +Preview the data directly in the Comet UI. +Comet UI previewing dataset artifact -Artifacts are versioned and also support adding metadata about the dataset. Comet will automatically log the metadata from your dataset `yaml` file artifact-3 +Artifacts are versioned and support metadata. Comet automatically logs metadata from your dataset `yaml` file. +Comet Artifact metadata view -### Using a saved Artifact +### Using a Saved Artifact -If you would like to use a dataset from Comet Artifacts, set the `path` variable in your dataset `yaml` file to point to the following Artifact resource URL. +To use a dataset stored in Comet Artifacts, update the `path` variable in your dataset `yaml` file to the Artifact resource URL: -``` +```yaml # contents of artifact.yaml file path: "comet:///:" +train: images/train # train images (relative to 'path') +val: images/val # val images (relative to 'path') +# ... other dataset configurations ``` -Then pass this file to your training script in the following way +Then, pass this configuration file to your training script: ```shell python train.py \ @@ -199,52 +204,77 @@ python train.py \ --weights yolov5s.pt ``` -Artifacts also allow you to track the lineage of data as it flows through your Experimentation workflow. Here you can see a graph that shows you all the experiments that have used your uploaded dataset. artifact-4 - -## Resuming a Training Run +Artifacts also enable tracking data lineage throughout your experimentation workflow. The graph below shows experiments that used the uploaded dataset. +Comet Artifact lineage graph -If your training run is interrupted for any reason, e.g. disrupted internet connection, you can resume the run using the `resume` flag and the Comet Run Path. +## ▶️ Resuming a Training Run -The Run Path has the following format `comet:////`. - -This will restore the run to its state before the interruption, which includes restoring the model from a checkpoint, restoring all hyperparameters and training arguments and downloading Comet dataset Artifacts if they were used in the original run. The resumed run will continue logging to the existing Experiment in the Comet UI +If a training run is interrupted, resume it using the `--resume` flag with the Comet Run Path (`comet:////`). This restores the model state, hyperparameters, training arguments, and downloads necessary Comet Artifacts. Logging continues to the existing Comet Experiment. ```shell python train.py \ - --resume "comet://" + --resume "comet:////" ``` -## Hyperparameter Search with the Comet Optimizer +## 🔍 Hyperparameter Search with the Comet Optimizer -YOLOv5 is also integrated with Comet's Optimizer, making is simple to visualize hyperparameter sweeps in the Comet UI. +YOLOv5 integrates with Comet's Optimizer for easy [hyperparameter tuning](https://docs.ultralytics.com/guides/hyperparameter-tuning/) and visualization. ### Configuring an Optimizer Sweep -To configure the Comet Optimizer, you will have to create a JSON file with the information about the sweep. An example file has been provided in `utils/loggers/comet/optimizer_config.json` +Create a JSON configuration file for the sweep (e.g., `utils/loggers/comet/optimizer_config.json`). + +```json +// Example optimizer_config.json +{ + "spec": { + "maxCombo": 10, // Max number of experiments to run + "objective": "minimize", // "minimize" or "maximize" + "metric": "metrics/mAP_0.5", // Metric to optimize + "algorithm": "bayes", // Optimization algorithm + "parameters": { + // Hyperparameters to tune + "lr0": { "type": "float", "min": 0.001, "max": 0.01 }, + "momentum": { "type": "float", "min": 0.85, "max": 0.95 } + // Add other hyperparameters from train.py args + } + }, + "name": "YOLOv5 Hyperparameter Sweep", // Name of the sweep + "trials": 1 // Number of trials per experiment combination +} +``` + +Run the sweep using the `hpo.py` script: ```shell python utils/loggers/comet/hpo.py \ - --comet_optimizer_config "utils/loggers/comet/optimizer_config.json" + --comet_optimizer_config utils/loggers/comet/optimizer_config.json ``` -The `hpo.py` script accepts the same arguments as `train.py`. If you wish to pass additional arguments to your sweep simply add them after the script. +The `hpo.py` script accepts the same arguments as `train.py`. Add any additional arguments needed for the sweep: ```shell python utils/loggers/comet/hpo.py \ - --comet_optimizer_config "utils/loggers/comet/optimizer_config.json" \ + --comet_optimizer_config utils/loggers/comet/optimizer_config.json \ --save-period 1 \ --bbox_interval 1 ``` ### Running a Sweep in Parallel +Use the `comet optimizer` command to run the sweep with multiple workers: + ```shell -comet optimizer -j utils/loggers/comet/hpo.py \ - utils/loggers/comet/optimizer_config.json" +comet optimizer -j \ + utils/loggers/comet/optimizer_config.json < number_of_workers > utils/loggers/comet/hpo.py ``` ### Visualizing Results -Comet provides a number of ways to visualize the results of your sweep. Take a look at a [project with a completed sweep here](https://www.comet.com/examples/comet-example-yolov5/view/PrlArHGuuhDTKC1UuBmTtOSXD/panels?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) +Comet offers various visualizations for sweep results. Explore a [project with a completed sweep here](https://www.comet.com/examples/comet-example-yolov5/view/PrlArHGuuhDTKC1UuBmTtOSXD/panels?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). + +Comet UI showing hyperparameter optimization results + +# 🤝 Contributing -hyperparameter-yolo +Contributions to enhance this integration are welcome! Please see the [Ultralytics Contributing Guide](https://docs.ultralytics.com/help/contributing/) for more information on how to get involved. Thank you for helping improve the Ultralytics ecosystem! From 133f31dfb0565d1a9440a927e8dc5e3975da504d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 28 Mar 2025 21:39:19 +0100 Subject: [PATCH 1150/1185] Update Dockerfile headers --- utils/flask_rest_api/README.md | 8 ++-- utils/loggers/clearml/README.md | 40 +++++++++--------- utils/loggers/comet/README.md | 74 ++++++++++++++++----------------- 3 files changed, 62 insertions(+), 60 deletions(-) diff --git a/utils/flask_rest_api/README.md b/utils/flask_rest_api/README.md index b7a2b1aa06..cad02d7677 100644 --- a/utils/flask_rest_api/README.md +++ b/utils/flask_rest_api/README.md @@ -2,7 +2,7 @@ # Flask REST API Example for YOLO Models -[Representational State Transfer (REST)](https://en.wikipedia.org/wiki/Representational_state_transfer) [Application Programming Interfaces (APIs)](https://developer.mozilla.org/en-US/docs/Web/API) are a standard way to expose [Machine Learning (ML)](https://www.ultralytics.com/glossary/machine-learning-ml) models, allowing other services or applications to interact with them over a network. This directory provides an example REST API built using the [Flask](https://palletsprojects.com/projects/flask/) microframework to serve predictions from an [Ultralytics YOLOv5s](https://docs.ultralytics.com/models/yolov5/) model loaded via [PyTorch Hub](https://pytorch.org/hub/ultralytics_yolov5/). +[Representational State Transfer (REST)](https://en.wikipedia.org/wiki/Representational_state_transfer) [Application Programming Interfaces (APIs)](https://developer.mozilla.org/en-US/docs/Web/API) are a standard way to expose [Machine Learning (ML)](https://www.ultralytics.com/glossary/machine-learning-ml) models, allowing other services or applications to interact with them over a network. This directory provides an example REST API built using the [Flask](https://palletsprojects.com/projects/flask/) microframework to serve predictions from an [Ultralytics YOLOv3](https://docs.ultralytics.com/models/yolov3/) model, potentially loaded via [PyTorch Hub](https://pytorch.org/hub/) or other standard PyTorch methods. Deploying models via APIs is a crucial step in [MLOps](https://www.ultralytics.com/glossary/machine-learning-operations-mlops) and enables integration into larger systems. You can explore various [model deployment options](https://docs.ultralytics.com/guides/model-deployment-options/) for different scenarios. @@ -16,7 +16,7 @@ Install Flask using pip: pip install Flask torch torchvision ``` -_Note: `torch` and `torchvision` are required by the YOLOv5 model from PyTorch Hub._ +_Note: `torch` and `torchvision` are required for loading and running PyTorch-based models like YOLOv3._ ## ▶️ Run the API @@ -34,10 +34,10 @@ The API server will start listening on the specified port (default is 5000). You can send prediction requests to the running API using tools like [`curl`](https://curl.se/) or scripting languages. -Send a POST request with an image file (`zidane.jpg` in this example) to the `/v1/object-detection/yolov5s` endpoint: +Send a POST request with an image file (`zidane.jpg` in this example) to the `/v1/object-detection/yolov3` endpoint: ```shell -curl -X POST -F image=@zidane.jpg 'http://localhost:5000/v1/object-detection/yolov5s' +curl -X POST -F image=@zidane.jpg 'http://localhost:5000/v1/object-detection/yolov3' ``` _Ensure `zidane.jpg` (or your test image) is present in the directory where you run the `curl` command._ diff --git a/utils/loggers/clearml/README.md b/utils/loggers/clearml/README.md index 56af5898cf..e012f80e44 100644 --- a/utils/loggers/clearml/README.md +++ b/utils/loggers/clearml/README.md @@ -2,19 +2,19 @@ # ClearML Integration for Ultralytics YOLO -This guide explains how to integrate [ClearML](https://clear.ml/), an open-source MLOps platform, with your Ultralytics YOLOv5 projects. ClearML helps streamline your machine learning workflow from experiment tracking to deployment. +This guide explains how to integrate [ClearML](https://clear.ml/), an open-source MLOps platform, with your Ultralytics YOLOv3 projects. ClearML helps streamline your machine learning workflow from experiment tracking to deployment. Clear|MLClear|ML ## ✨ About ClearML -[ClearML](https://clear.ml/) is an [open-source](https://github.com/clearml/clearml) suite of tools designed to manage, automate, and orchestrate machine learning workflows, significantly saving development time ⏱️. Integrating ClearML with Ultralytics YOLOv5 provides several benefits: +[ClearML](https://clear.ml/) is an [open-source](https://github.com/clearml/clearml) suite of tools designed to manage, automate, and orchestrate machine learning workflows, significantly saving development time ⏱️. Integrating ClearML with Ultralytics YOLOv3 provides several benefits: -- **Experiment Management**: Automatically track every YOLOv5 training run, including code versions, configurations, metrics, and outputs in a centralized dashboard. Learn more about [Ultralytics experiment tracking integrations](https://docs.ultralytics.com/integrations/). +- **Experiment Management**: Automatically track every YOLOv3 training run, including code versions, configurations, metrics, and outputs in a centralized dashboard. Learn more about [Ultralytics experiment tracking integrations](https://docs.ultralytics.com/integrations/). - **Data Versioning**: Use the ClearML Data Versioning Tool to manage and easily access your custom training datasets. See how Ultralytics handles [datasets](https://docs.ultralytics.com/datasets/). -- **Remote Execution**: Remotely train and monitor your YOLOv5 models using ClearML Agent on different machines or cloud instances. Explore [model deployment options](https://docs.ultralytics.com/guides/model-deployment-options/). +- **Remote Execution**: Remotely train and monitor your YOLOv3 models using ClearML Agent on different machines or cloud instances. Explore [model deployment options](https://docs.ultralytics.com/guides/model-deployment-options/). - **Hyperparameter Optimization**: Leverage ClearML Hyperparameter Optimization to find the best model configurations and improve [Mean Average Precision (mAP)](https://www.ultralytics.com/glossary/mean-average-precision-map). Check out the Ultralytics [Hyperparameter Tuning guide](https://docs.ultralytics.com/guides/hyperparameter-tuning/). -- **Model Deployment**: Turn your trained YOLOv5 models into scalable APIs using ClearML Serving with just a few commands. +- **Model Deployment**: Turn your trained YOLOv3 models into scalable APIs using ClearML Serving with just a few commands. You can choose to use any combination of these tools to fit your project needs. @@ -40,19 +40,19 @@ Follow these steps to get started: clearml-init ``` -Once configured, ClearML is ready to integrate with your YOLOv5 workflows! 😎 +Once configured, ClearML is ready to integrate with your YOLOv3 workflows! 😎 -## 🚀 Training YOLOv5 With ClearML +## 🚀 Training YOLOv3 With ClearML -Enabling ClearML experiment tracking for YOLOv5 is straightforward. Simply ensure the `clearml` package is installed: +Enabling ClearML experiment tracking for YOLOv3 is straightforward. Simply ensure the `clearml` package is installed: ```bash pip install clearml > =1.2.0 ``` -With the package installed, ClearML automatically captures details for every YOLOv5 [training run](https://docs.ultralytics.com/modes/train/). +With the package installed, ClearML automatically captures details for every YOLOv3 [training run](https://docs.ultralytics.com/modes/train/). -By default, experiments are logged under the `YOLOv5` project with the task name `Training`. You can customize these using the `--project` and `--name` arguments in your training command. Note that ClearML uses `/` as a delimiter for subprojects. +By default, experiments are logged under the `YOLOv3` project with the task name `Training`. You can customize these using the `--project` and `--name` arguments in your training command. Note that ClearML uses `/` as a delimiter for subprojects. **Example Training Command:** @@ -84,17 +84,17 @@ This comprehensive tracking allows you to visualize progress in the ClearML UI, ## 🔗 Dataset Version Management -Versioning datasets is crucial for reproducibility and collaboration in [machine learning](https://www.ultralytics.com/glossary/machine-learning-ml) projects. ClearML Data helps manage datasets efficiently. YOLOv5 supports using ClearML dataset IDs directly in the training command. +Versioning datasets is crucial for reproducibility and collaboration in [machine learning](https://www.ultralytics.com/glossary/machine-learning-ml) projects. ClearML Data helps manage datasets efficiently. YOLOv3 supports using ClearML dataset IDs directly in the training command. ![ClearML Dataset Interface](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/clearml_data.gif) ### Prepare Your Dataset -YOLOv5 uses YAML files to define dataset configurations. Datasets are typically expected in a specific structure, often downloaded to a `../datasets` directory relative to your repository root. For example, the [COCO128 dataset](https://docs.ultralytics.com/datasets/detect/coco128/) structure looks like this: +YOLOv3 uses YAML files to define dataset configurations. Datasets are typically expected in a specific structure, often downloaded to a `../datasets` directory relative to your repository root. For example, the [COCO128 dataset](https://docs.ultralytics.com/datasets/detect/coco128/) structure looks like this: ``` ../ -├── yolov5/ # Your repository +├── yolov3/ # Your repository └── datasets/ └── coco128/ # Dataset root folder ├── images/ @@ -117,16 +117,16 @@ Navigate to your dataset's root folder in the terminal and use the `clearml-data cd ../datasets/coco128 # Sync the dataset with ClearML (creates a versioned dataset) -clearml-data sync --project "YOLOv5 Datasets" --name coco128 --folder . +clearml-data sync --project "YOLOv3 Datasets" --name coco128 --folder . ``` -This command creates a new ClearML dataset (or a new version if it exists) named `coco128` within the `YOLOv5 Datasets` project. +This command creates a new ClearML dataset (or a new version if it exists) named `coco128` within the `YOLOv3 Datasets` project. Alternatively, you can use granular commands: ```bash # Create a new dataset task -clearml-data create --project "YOLOv5 Datasets" --name coco128 +clearml-data create --project "YOLOv3 Datasets" --name coco128 # Add files to the dataset (use '.' for current folder) clearml-data add --files . @@ -137,11 +137,11 @@ clearml-data close ### Run Training Using a ClearML Dataset -Once your dataset is versioned in ClearML, you can reference it directly in your YOLOv5 training command using its unique ID. ClearML will automatically download the dataset if it's not present locally. +Once your dataset is versioned in ClearML, you can reference it directly in your YOLOv3 training command using its unique ID. ClearML will automatically download the dataset if it's not present locally. ```bash # Replace with the actual ID from ClearML -python train.py --img 640 --batch 16 --epochs 3 --data clearml:// yolov5s.pt --cache < your_dataset_id > --weights +python train.py --img 640 --batch 16 --epochs 3 --data clearml:// --weights yolov5s.pt --cache ``` The dataset ID used will be logged as a parameter in your ClearML experiment, ensuring full traceability. @@ -174,7 +174,7 @@ Turn any machine into a ClearML Agent by running the following command: ```bash # Replace with the name(s) of your queue(s) -clearml-agent daemon --queue < queues_to_listen_to > [--docker] # Use --docker to run in a Docker container +clearml-agent daemon --queue [--docker] # Use --docker to run in a Docker container ``` ### Cloning, Editing, and Enqueuing Tasks @@ -221,3 +221,5 @@ Learn how to set up autoscalers: ## 👋 Contribute Contributions are welcome! If you'd like to improve this integration or suggest features, please see the Ultralytics [Contributing Guide](https://docs.ultralytics.com/help/contributing/) and submit a Pull Request. Thank you to all our contributors! + +[![Ultralytics open-source contributors](https://raw.githubusercontent.com/ultralytics/assets/main/im/image-contributors.png)](https://github.com/ultralytics/ultralytics/graphs/contributors) diff --git a/utils/loggers/comet/README.md b/utils/loggers/comet/README.md index 1b39260f72..7eeaef5270 100644 --- a/utils/loggers/comet/README.md +++ b/utils/loggers/comet/README.md @@ -2,19 +2,19 @@ -# YOLOv5 Integration with Comet +# YOLOv3 Integration with Comet -This guide details how to effectively use YOLOv5 with [Comet](https://bit.ly/yolov5-readme-comet2) for experiment tracking and model optimization. +This guide details how to effectively use YOLOv3 with [Comet](https://bit.ly/yolov5-readme-comet2) for experiment tracking and model optimization. -# About Comet +## ℹ️ About Comet [Comet](https://www.comet.com/site/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) provides tools designed to help data scientists, engineers, and team leaders accelerate and optimize machine learning and deep learning models. With Comet, you can track and visualize model metrics in real-time, save hyperparameters, datasets, and model checkpoints, and visualize model predictions using [Comet Custom Panels](https://www.comet.com/docs/v2/guides/comet-dashboard/code-panels/about-panels/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). Comet ensures your work is never lost and simplifies sharing results and collaboration across teams of any size. -# 🚀 Getting Started +## 🚀 Getting Started -## Install Comet +### Install Comet Install the necessary package using pip: @@ -22,15 +22,15 @@ Install the necessary package using pip: pip install comet_ml ``` -## Configure Comet Credentials +### Configure Comet Credentials -You can configure Comet credentials for YOLOv5 in two ways: +You can configure Comet credentials for YOLOv3 in two ways: 1. **Environment Variables**: Set your credentials directly in your environment. ```shell export COMET_API_KEY= - export COMET_PROJECT_NAME= # Defaults to 'yolov5' if not set + export COMET_PROJECT_NAME= # Defaults to 'yolov3' if not set ``` 2. **Comet Configuration File**: Create a `.comet.config` file in your working directory and add your credentials there. @@ -38,23 +38,23 @@ You can configure Comet credentials for YOLOv5 in two ways: ``` [comet] api_key= - project_name= # Defaults to 'yolov5' if not set + project_name= # Defaults to 'yolov3' if not set ``` -## Run the Training Script +### Run the Training Script -Execute the [Ultralytics training script](https://docs.ultralytics.com/modes/train/) as you normally would. Comet automatically integrates with YOLOv5. +Execute the [Ultralytics training script](https://docs.ultralytics.com/modes/train/) as you normally would. Comet automatically integrates with YOLOv3. ```shell -# Train YOLOv5s on COCO128 for 5 epochs -python train.py --img 640 --batch 16 --epochs 5 --data coco128.yaml --weights yolov5s.pt +# Train YOLOv3 on COCO128 for 5 epochs +python train.py --img 640 --batch 16 --epochs 5 --data coco128.yaml --weights yolov3.pt ``` That's it! Comet will automatically log your hyperparameters, command-line arguments, training metrics, and validation metrics. You can visualize and analyze your runs in the Comet UI. For more details on metrics like mAP and Recall, see the [YOLO Performance Metrics guide](https://docs.ultralytics.com/guides/yolo-performance-metrics/). -Comet UI showing YOLOv5 training run +Comet UI showing YOLO training run -# ✨ Try an Example! +## ✨ Try an Example! Explore an example of a [completed run in the Comet UI](https://www.comet.com/examples/comet-example-yolov5/a0e29e0e9b984e4a822db2a62d0cb357?experiment-tab=chart&showOutliers=true&smoothing=0&transformY=smoothing&xAxis=step&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). @@ -62,35 +62,35 @@ Or, try it yourself using this Colab Notebook: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/comet-ml/comet-examples/blob/master/integrations/model-training/yolov5/notebooks/Comet_and_YOLOv5.ipynb) -# 📊 Automatic Logging +## 📊 Automatic Logging By default, Comet automatically logs the following: -## Metrics +### Metrics - Box Loss, Object Loss, Classification Loss (Training and Validation) - mAP_0.5, mAP_0.5:0.95 (Validation) - Precision and Recall (Validation) -## Parameters +### Parameters - Model Hyperparameters - All command-line options passed during training -## Visualizations +### Visualizations - Confusion Matrix of model predictions on validation data - Plots for PR and F1 curves across all classes - Correlogram of Class Labels -# ⚙️ Configure Comet Logging +## ⚙️ Configure Comet Logging You can configure Comet to log additional data using command-line flags or environment variables. ```shell # Environment Variables for Comet Configuration export COMET_MODE=online # 'online' or 'offline'. Defaults to online. -export COMET_MODEL_NAME= # Name for the saved model. Defaults to yolov5. +export COMET_MODEL_NAME= # Name for the saved model. Defaults to yolov3. export COMET_LOG_CONFUSION_MATRIX=false # Disable logging Confusion Matrix. Defaults to true. export COMET_MAX_IMAGE_UPLOADS= # Max prediction images to log. Defaults to 100. export COMET_LOG_PER_CLASS_METRICS=true # Log evaluation metrics per class. Defaults to false. @@ -99,7 +99,7 @@ export COMET_LOG_BATCH_LEVEL_METRICS=true # Log training metrics per batch. Defa export COMET_LOG_PREDICTIONS=true # Set to false to disable logging model predictions. Defaults to true. ``` -## Logging Checkpoints with Comet +### Logging Checkpoints with Comet Logging [model checkpoints](https://docs.ultralytics.com/guides/model-training-tips/#checkpoints) to Comet is disabled by default. Enable it by passing the `save-period` argument to the training script. Checkpoints will be saved to Comet at the specified interval. @@ -109,15 +109,15 @@ python train.py \ --batch 16 \ --epochs 5 \ --data coco128.yaml \ - --weights yolov5s.pt \ + --weights yolov3.pt \ --save-period 1 # Saves checkpoints every epoch ``` -## Logging Model Predictions +### Logging Model Predictions Model predictions (images, ground truth labels, bounding boxes) are logged to Comet by default. Control the frequency using the `bbox_interval` argument. This value corresponds to logging every Nth batch per epoch. Predictions can be visualized using Comet's Object Detection Custom Panel. -**Note:** The YOLOv5 validation dataloader defaults to a batch size of 32. Adjust the logging frequency accordingly. +**Note:** The YOLOv3 validation dataloader defaults to a batch size of 32. Adjust the logging frequency accordingly. See an [example project using the Panel here](https://www.comet.com/examples/comet-example-yolov5?shareable=YcwMiJaZSXfcEXpGOHDD12vA1&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). @@ -127,11 +127,11 @@ python train.py \ --batch 16 \ --epochs 5 \ --data coco128.yaml \ - --weights yolov5s.pt \ + --weights yolov3.pt \ --bbox_interval 2 # Logs predictions every 2nd batch per epoch ``` -### Controlling the Number of Prediction Images Logged +#### Controlling the Number of Prediction Images Logged Comet logs images associated with predictions. The default maximum is 100 validation images. Adjust this using the `COMET_MAX_IMAGE_UPLOADS` environment variable. @@ -141,11 +141,11 @@ env COMET_MAX_IMAGE_UPLOADS=200 python train.py \ --batch 16 \ --epochs 5 \ --data coco128.yaml \ - --weights yolov5s.pt \ + --weights yolov3.pt \ --bbox_interval 1 ``` -### Logging Class Level Metrics +#### Logging Class Level Metrics Use the `COMET_LOG_PER_CLASS_METRICS` environment variable to log mAP, precision, recall, and F1-score for each class. @@ -155,7 +155,7 @@ env COMET_LOG_PER_CLASS_METRICS=true python train.py \ --batch 16 \ --epochs 5 \ --data coco128.yaml \ - --weights yolov5s.pt + --weights yolov3.pt ``` ## 💾 Uploading a Dataset to Comet Artifacts @@ -168,7 +168,7 @@ python train.py \ --batch 16 \ --epochs 5 \ --data coco128.yaml \ - --weights yolov5s.pt \ + --weights yolov3.pt \ --upload_dataset # Uploads the dataset specified in coco128.yaml ``` @@ -201,7 +201,7 @@ python train.py \ --batch 16 \ --epochs 5 \ --data artifact.yaml \ - --weights yolov5s.pt + --weights yolov3.pt ``` Artifacts also enable tracking data lineage throughout your experimentation workflow. The graph below shows experiments that used the uploaded dataset. @@ -218,7 +218,7 @@ python train.py \ ## 🔍 Hyperparameter Search with the Comet Optimizer -YOLOv5 integrates with Comet's Optimizer for easy [hyperparameter tuning](https://docs.ultralytics.com/guides/hyperparameter-tuning/) and visualization. +YOLOv3 integrates with Comet's Optimizer for easy [hyperparameter tuning](https://docs.ultralytics.com/guides/hyperparameter-tuning/) and visualization. ### Configuring an Optimizer Sweep @@ -239,7 +239,7 @@ Create a JSON configuration file for the sweep (e.g., `utils/loggers/comet/optim // Add other hyperparameters from train.py args } }, - "name": "YOLOv5 Hyperparameter Sweep", // Name of the sweep + "name": "YOLOv3 Hyperparameter Sweep", // Name of the sweep "trials": 1 // Number of trials per experiment combination } ``` @@ -265,8 +265,8 @@ python utils/loggers/comet/hpo.py \ Use the `comet optimizer` command to run the sweep with multiple workers: ```shell -comet optimizer -j \ - utils/loggers/comet/optimizer_config.json < number_of_workers > utils/loggers/comet/hpo.py +comet optimizer -j < number_of_workers > \ + utils/loggers/comet/optimizer_config.json utils/loggers/comet/hpo.py ``` ### Visualizing Results @@ -275,6 +275,6 @@ Comet offers various visualizations for sweep results. Explore a [project with a Comet UI showing hyperparameter optimization results -# 🤝 Contributing +## 🤝 Contributing Contributions to enhance this integration are welcome! Please see the [Ultralytics Contributing Guide](https://docs.ultralytics.com/help/contributing/) for more information on how to get involved. Thank you for helping improve the Ultralytics ecosystem! From e53e797bd772e34cee5a1d36286505d9452c1fef Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 28 Mar 2025 21:45:27 +0100 Subject: [PATCH 1151/1185] Update Dockerfile headers --- README.md | 438 ++++++++++++++++-------------------------------------- 1 file changed, 124 insertions(+), 314 deletions(-) diff --git a/README.md b/README.md index f9aa65ed15..0cc3763068 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,7 @@ -Ultralytics logo -

- - + + Ultralytics YOLOv3 banner

[中文](https://docs.ultralytics.com/zh) | [한국어](https://docs.ultralytics.com/ko) | [日本語](https://docs.ultralytics.com/ja) | [Русский](https://docs.ultralytics.com/ru) | [Deutsch](https://docs.ultralytics.com/de) | [Français](https://docs.ultralytics.com/fr) | [Español](https://docs.ultralytics.com/es) | [Português](https://docs.ultralytics.com/pt) | [Türkçe](https://docs.ultralytics.com/tr) | [Tiếng Việt](https://docs.ultralytics.com/vi) | [العربية](https://docs.ultralytics.com/ar) @@ -22,11 +20,11 @@

-Ultralytics YOLOv3 🚀 is a significant iteration in the YOLO (You Only Look Once) family of real-time [object detection](https://docs.ultralytics.com/tasks/detect/) models. Originally developed by Joseph Redmon, YOLOv3 improved upon its predecessors by enhancing accuracy, particularly for smaller objects, through techniques like multi-scale predictions and a more complex backbone network (Darknet-53). This repository represents [Ultralytics'](https://www.ultralytics.com/) implementation, building upon the foundational work and incorporating best practices learned through extensive research in [computer vision](https://www.ultralytics.com/glossary/computer-vision-cv) and [deep learning](https://www.ultralytics.com/glossary/deep-learning-dl). +Ultralytics YOLOv3 is a robust and efficient [computer vision](https://www.ultralytics.com/glossary/computer-vision-cv) model developed by [Ultralytics](https://www.ultralytics.com/). Based on the [PyTorch](https://pytorch.org/) framework, this implementation builds upon the original YOLOv3 architecture, known for its significant improvements in [object detection](https://www.ultralytics.com/glossary/object-detection) speed and accuracy compared to its predecessors. It incorporates insights and best practices from extensive research and development, making it a reliable choice for various vision AI tasks. -We hope the resources here help you leverage YOLOv3 effectively. Explore the [Ultralytics YOLOv3 Docs](https://docs.ultralytics.com/models/yolov3/) for detailed guides, raise issues on [GitHub](https://github.com/ultralytics/yolov3/issues/new/choose) for support, and join our vibrant [Discord community](https://discord.com/invite/ultralytics) for questions and discussions! +We hope the resources here help you get the most out of YOLOv3. Please browse the [Ultralytics Docs](https://docs.ultralytics.com/) for detailed information (note: specific YOLOv3 docs may be limited, refer to general YOLO principles), raise an issue on [GitHub](https://github.com/ultralytics/yolov5/issues/new/choose) for support, and join our [Discord community](https://discord.com/invite/ultralytics) for questions and discussions! -To request an Enterprise License for commercial use, please complete the form at [Ultralytics Licensing](https://www.ultralytics.com/license). +To request an Enterprise License, please complete the form at [Ultralytics Licensing](https://www.ultralytics.com/license).
Ultralytics GitHub @@ -43,47 +41,54 @@ To request an Enterprise License for commercial use, please complete the form at Ultralytics Discord
+
-##
🚀 Ultralytics YOLO11 is Here!
+## 🚀 YOLO11: The Next Evolution -We are thrilled to announce the release of Ultralytics YOLO11 🚀, the next generation in state-of-the-art (SOTA) vision models! Now available at the main **[Ultralytics repository](https://github.com/ultralytics/ultralytics)**, YOLO11 continues our commitment to speed, [accuracy](https://www.ultralytics.com/glossary/accuracy), and user-friendliness. Whether your focus is [object detection](https://docs.ultralytics.com/tasks/detect/), [image segmentation](https://docs.ultralytics.com/tasks/segment/), or [image classification](https://docs.ultralytics.com/tasks/classify/), YOLO11 offers unparalleled performance and versatility for a wide range of applications. +We are excited to announce the launch of **Ultralytics YOLO11** 🚀, the latest advancement in our state-of-the-art (SOTA) vision models! Available now at the [Ultralytics YOLO GitHub repository](https://github.com/ultralytics/ultralytics), YOLO11 builds on our legacy of speed, precision, and ease of use. Whether you're tackling [object detection](https://docs.ultralytics.com/tasks/detect/), [instance segmentation](https://docs.ultralytics.com/tasks/segment/), [pose estimation](https://docs.ultralytics.com/tasks/pose/), [image classification](https://docs.ultralytics.com/tasks/classify/), or [oriented object detection (OBB)](https://docs.ultralytics.com/tasks/obb/), YOLO11 delivers the performance and versatility needed to excel in diverse applications. -Start exploring YOLO11 today! Visit the [Ultralytics Docs](https://docs.ultralytics.com/) for comprehensive guides and resources. +Get started today and unlock the full potential of YOLO11! Visit the [Ultralytics Docs](https://docs.ultralytics.com/) for comprehensive guides and resources: [![PyPI version](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![Downloads](https://static.pepy.tech/badge/ultralytics)](https://www.pepy.tech/projects/ultralytics) ```bash +# Install the ultralytics package pip install ultralytics ```
- + Ultralytics YOLO Performance Comparison
-##
📚 Documentation
+## 📚 Documentation -See the [Ultralytics YOLOv3 Docs](https://docs.ultralytics.com/models/yolov3/) for full documentation on training, validation, inference, and deployment. Quickstart examples are provided below. +See the [Ultralytics Docs](https://docs.ultralytics.com/models/yolov3/) for full documentation on training, testing, and deployment using the Ultralytics framework. While specific YOLOv3 documentation might be limited, the general principles apply. See below for quickstart examples adapted for YOLOv3 concepts.
Install -Clone the repository and install dependencies using `requirements.txt` in a **Python>=3.7.0** environment. Ensure you have **PyTorch>=1.7**. +Clone the repository and install dependencies from [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) in a [**Python>=3.8.0**](https://www.python.org/) environment. Ensure you have [**PyTorch>=1.8**](https://pytorch.org/get-started/locally/) installed. (Note: This repo is originally YOLOv5, dependencies should be compatible but tailored testing for YOLOv3 is recommended). ```bash -git clone https://github.com/ultralytics/yolov3 # clone repository +# Clone the YOLOv3 repository +git clone https://github.com/ultralytics/yolov3 + +# Navigate to the cloned directory cd yolov3 -pip install -r requirements.txt # install dependencies + +# Install required packages +pip install -r requirements.txt ```
-
-Inference +
+Inference with PyTorch Hub -Perform inference using YOLOv3 models loaded via [PyTorch Hub](https://pytorch.org/hub/). Models are automatically downloaded from the latest YOLOv3 release. +Use YOLOv3 via [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/) for inference. [Models](https://github.com/ultralytics/yolov5/tree/master/models) like `yolov3.pt`, `yolov3-spp.pt`, `yolov3-tiny.pt` can be loaded. ```python import torch @@ -91,18 +96,16 @@ import torch # Load a YOLOv3 model (e.g., yolov3, yolov3-spp) model = torch.hub.load("ultralytics/yolov3", "yolov3", pretrained=True) # specify 'yolov3' or other variants -# Define image source (URL, file path, PIL image, OpenCV image, numpy array, list of images) -img_source = "https://ultralytics.com/images/zidane.jpg" +# Define the input image source (URL, local file, PIL image, OpenCV frame, numpy array, or list) +img = "https://ultralytics.com/images/zidane.jpg" # Example image # Perform inference -results = model(img_source) +results = model(img) -# Process and display results +# Process the results (options: .print(), .show(), .save(), .crop(), .pandas()) results.print() # Print results to console -# results.show() # Display results in a window -# results.save() # Save results to runs/detect/exp -# results.crop() # Save cropped detections -# results.pandas().xyxy[0] # Access results as pandas DataFrame +results.show() # Display results in a window +results.save() # Save results to runs/detect/exp ```
@@ -110,20 +113,38 @@ results.print() # Print results to console
Inference with detect.py -The `detect.py` script runs inference on various sources. It automatically downloads required [models](https://github.com/ultralytics/yolov5/tree/master/models) from the latest YOLOv3 release and saves the output to `runs/detect`. +The `detect.py` script runs inference on various sources. Use `--weights yolov3.pt` or other YOLOv3 variants. It automatically downloads models and saves results to `runs/detect`. ```bash -# Run inference using detect.py with different sources -python detect.py --weights yolov3.pt --source 0 # Webcam -python detect.py --weights yolov3.pt --source image.jpg # Single image -python detect.py --weights yolov3.pt --source video.mp4 # Video file -python detect.py --weights yolov3.pt --source screen # Screen capture -python detect.py --weights yolov3.pt --source path/ # Directory of images/videos -python detect.py --weights yolov3.pt --source list.txt # Text file with image paths -python detect.py --weights yolov3.pt --source list.streams # Text file with stream URLs -python detect.py --weights yolov3.pt --source 'path/*.jpg' # Glob pattern for images -python detect.py --weights yolov3.pt --source 'https://youtu.be/LNwODJXcvt4' # YouTube video URL -python detect.py --weights yolov3.pt --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream URL +# Run inference using a webcam with yolov3-tiny +python detect.py --weights yolov3-tiny.pt --source 0 + +# Run inference on a local image file with yolov3 +python detect.py --weights yolov3.pt --source img.jpg + +# Run inference on a local video file with yolov3-spp +python detect.py --weights yolov3-spp.pt --source vid.mp4 + +# Run inference on a screen capture +python detect.py --weights yolov3.pt --source screen + +# Run inference on a directory of images +python detect.py --weights yolov3.pt --source path/to/images/ + +# Run inference on a text file listing image paths +python detect.py --weights yolov3.pt --source list.txt + +# Run inference on a text file listing stream URLs +python detect.py --weights yolov3.pt --source list.streams + +# Run inference using a glob pattern for images +python detect.py --weights yolov3.pt --source 'path/to/*.jpg' + +# Run inference on a YouTube video URL +python detect.py --weights yolov3.pt --source 'https://youtu.be/LNwODJXcvt4' + +# Run inference on an RTSP, RTMP, or HTTP stream +python detect.py --weights yolov3.pt --source 'rtsp://example.com/media.mp4' ```
@@ -131,46 +152,52 @@ python detect.py --weights yolov3.pt --source 'rtsp://example.com/media.mp4' # R
Training -The following command demonstrates training YOLOv3 on the [COCO dataset](https://docs.ultralytics.com/datasets/detect/coco/). Models and datasets are automatically downloaded from the latest YOLOv3 release. Training times vary depending on the model size and hardware; for instance, YOLOv5 variants (often used as a reference) take 1-8 days on a V100 GPU. Use the largest possible `--batch-size` or utilize `--batch-size -1` for YOLOv3 [AutoBatch](https://docs.ultralytics.com/reference/utils/autobatch/). Batch sizes shown are indicative for a V100-16GB GPU. +The commands below show how to train YOLOv3 models on the [COCO dataset](https://docs.ultralytics.com/datasets/detect/coco/). Models and datasets are downloaded automatically. Use the largest `--batch-size` your hardware allows. ```bash -# Train YOLOv3 on COCO dataset for 300 epochs -python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3.yaml --batch-size 128 -``` +# Train YOLOv3-tiny on COCO for 300 epochs (example settings) +python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3-tiny.yaml --batch-size 64 + +# Train YOLOv3 on COCO for 300 epochs (example settings) +python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3.yaml --batch-size 32 - +# Train YOLOv3-SPP on COCO for 300 epochs (example settings) +python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3-spp.yaml --batch-size 16 +```
-📚 Tutorials - -- [Train Custom Data](https://docs.ultralytics.com/datasets/detect/) 🚀 **RECOMMENDED**: Learn how to train YOLO models on your own datasets. -- [Tips for Best Training Results](https://docs.ultralytics.com/guides/model-training-tips/) ☘️: Improve your model's performance with expert tips. -- [Multi-GPU Training](https://docs.ultralytics.com/usage/cli/#multi-gpu-training): Scale your training across multiple GPUs. -- [PyTorch Hub Integration](https://docs.ultralytics.com/integrations/pytorch-hub/): Load models easily using PyTorch Hub. 🌟 **NEW** -- [Model Export](https://docs.ultralytics.com/modes/export/): Export models to various formats like TFLite, ONNX, CoreML, TensorRT. 🚀 -- [NVIDIA Jetson Deployment](https://docs.ultralytics.com/guides/nvidia-jetson/): Deploy models on NVIDIA Jetson devices. 🌟 **NEW** -- [Test-Time Augmentation (TTA)](https://docs.ultralytics.com/modes/val/#inference-augmentation): Enhance prediction accuracy using TTA. -- [Model Ensembling](https://docs.ultralytics.com/reference/engine/model/#ultralytics.engine.model.Model.ensemble): Combine multiple models for better robustness. -- [Model Pruning/Sparsity](https://docs.ultralytics.com/integrations/neural-magic/): Optimize models for size and speed. -- [Hyperparameter Evolution](https://docs.ultralytics.com/guides/hyperparameter-tuning/): Automatically tune hyperparameters for optimal performance. -- [Transfer Learning](https://docs.ultralytics.com/guides/transfer-learning/): Fine-tune pretrained models on your custom data. -- [Architecture Summary](https://docs.ultralytics.com/models/yolov5/#architecture): Understand the underlying model architecture. 🌟 **NEW** -- [Ultralytics HUB Training](https://docs.ultralytics.com/hub/cloud-training/) 🚀 **RECOMMENDED**: Train and deploy YOLO models easily using Ultralytics HUB. -- [ClearML Logging](https://docs.ultralytics.com/integrations/clearml/): Integrate experiment tracking with ClearML. -- [Neural Magic DeepSparse Integration](https://docs.ultralytics.com/integrations/neural-magic/): Accelerate inference with DeepSparse. -- [Comet Logging](https://docs.ultralytics.com/integrations/comet/): Log and visualize experiments using Comet. 🌟 **NEW** +Tutorials + +Note: These tutorials primarily use YOLOv5 examples but the principles often apply to YOLOv3 within the Ultralytics framework. + +- **[Train Custom Data](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/)** 🚀 **RECOMMENDED**: Learn how to train models on your own datasets. +- **[Tips for Best Training Results](https://docs.ultralytics.com/guides/model-training-tips/)** ☘️: Improve your model's performance with expert tips. +- **[Multi-GPU Training](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/)**: Speed up training using multiple GPUs. +- **[PyTorch Hub Integration](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/)** 🌟 **NEW**: Easily load models using PyTorch Hub. +- **[Model Export (TFLite, ONNX, CoreML, TensorRT)](https://docs.ultralytics.com/yolov5/tutorials/model_export/)** 🚀: Convert your models to various deployment formats. +- **[NVIDIA Jetson Deployment](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano/)** 🌟 **NEW**: Deploy models on NVIDIA Jetson devices. +- **[Test-Time Augmentation (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/)**: Enhance prediction accuracy with TTA. +- **[Model Ensembling](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling/)**: Combine multiple models for better performance. +- **[Model Pruning/Sparsity](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity/)**: Optimize models for size and speed. +- **[Hyperparameter Evolution](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution/)**: Automatically find the best training hyperparameters. +- **[Transfer Learning with Frozen Layers](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers/)**: Adapt pretrained models to new tasks efficiently. +- **[Architecture Summary](https://docs.ultralytics.com/yolov5/tutorials/architecture_description/)** 🌟 **NEW**: Understand the model architecture (focus on YOLOv3 principles). +- **[Ultralytics HUB Training](https://www.ultralytics.com/hub)** 🚀 **RECOMMENDED**: Train and deploy YOLO models using Ultralytics HUB. +- **[ClearML Logging](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration/)**: Integrate with ClearML for experiment tracking. +- **[Neural Magic DeepSparse Integration](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization/)**: Accelerate inference with DeepSparse. +- **[Comet Logging](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration/)** 🌟 **NEW**: Log experiments using Comet ML.
-##
🤝 Integrations
+## 🛠️ Integrations -Our key integrations with leading AI platforms extend Ultralytics' capabilities, enhancing tasks like dataset labeling, training, visualization, and model management. Explore how Ultralytics works with [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/), [Comet ML](https://docs.ultralytics.com/integrations/comet/), [Roboflow](https://docs.ultralytics.com/integrations/roboflow/), and [Intel OpenVINO](https://docs.ultralytics.com/integrations/openvino/) to streamline your AI workflow. +Explore Ultralytics' key integrations with leading AI platforms. These collaborations enhance capabilities for dataset labeling, training, visualization, and model management. Discover how Ultralytics works with [Weights & Biases (W&B)](https://docs.wandb.ai/guides/integrations/ultralytics/), [Comet ML](https://bit.ly/yolov5-readme-comet), [Roboflow](https://roboflow.com/?ref=ultralytics), and [Intel OpenVINO](https://docs.ultralytics.com/integrations/openvino/) to optimize your AI workflows.
-Ultralytics active learning integrations +Ultralytics Active Learning Integrations Banner

@@ -185,251 +212,34 @@ Our key integrations with leading AI platforms extend Ultralytics' capabilities, Comet ML logo space - NeuralMagic logo - - -| Ultralytics HUB 🚀 | W&B | Comet ⭐ NEW | Neural Magic | -| :-----------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------: | -| Streamline YOLO workflows: Label, train, and deploy effortlessly with [Ultralytics HUB](https://hub.ultralytics.com/). Try now! | Track experiments, hyperparameters, and results with [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/). | Free forever, [Comet](https://docs.ultralytics.com/integrations/comet/) lets you save YOLO models, resume training, and interactively visualize and debug predictions. | Run YOLO inference up to 6x faster with [Neural Magic DeepSparse](https://docs.ultralytics.com/integrations/neural-magic/). | - -##
☁️ Ultralytics HUB
- -Experience seamless AI development with [Ultralytics HUB](https://hub.ultralytics.com/) ⭐, your all-in-one platform for data visualization, YOLO 🚀 model training, and deployment—no coding required. Convert images into actionable insights and realize your AI projects effortlessly using our advanced platform and intuitive [Ultralytics App](https://www.ultralytics.com/app-install). Begin your journey for **Free** today! - - - - -##
💡 Why YOLOv3?
- -YOLOv3 marked a significant step in the evolution of real-time object detectors. Its key contributions include: - -- **Multi-Scale Predictions:** Detecting objects at three different scales using feature pyramids, improving accuracy for objects of varying sizes, especially small ones. -- **Improved Backbone:** Utilizing Darknet-53, a deeper and more complex network than its predecessor (Darknet-19), enhancing feature extraction capabilities. -- **Class Prediction:** Using logistic classifiers instead of softmax for class predictions, allowing for multi-label classification where an object can belong to multiple categories. - -While newer models like [YOLOv5](https://docs.ultralytics.com/models/yolov5/) and [YOLOv8](https://docs.ultralytics.com/models/yolov8/) offer further improvements in speed and accuracy, YOLOv3 remains a foundational model in the field and is still widely used and studied. The table below shows comparisons with later YOLOv5 models for context. - -

-
- YOLOv3-P5 640 Figure - -

-
-
- Figure Notes - -- **COCO AP val** denotes [mAP@0.5:0.95](https://www.ultralytics.com/glossary/mean-average-precision-map) metric measured on the 5000-image COCO val2017 dataset over various inference sizes from 256 to 1536. See [COCO dataset](https://docs.ultralytics.com/datasets/detect/coco/). -- **GPU Speed** measures average inference time per image on the COCO val2017 dataset using an [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p4/) V100 instance at batch-size 32. -- **EfficientDet** data from [google/automl](https://github.com/google/automl) repository at batch size 8. -- **Reproduce** benchmark results using `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt` - -
- -### Pretrained Checkpoints (YOLOv5 Comparison) - -This table shows YOLOv5 models trained on the COCO dataset, often used as benchmarks. - -| Model | size
(pixels) | mAPval
50-95 | mAPval
50 | Speed
CPU b1
(ms) | Speed
V100 b1
(ms) | Speed
V100 b32
(ms) | params
(M) | FLOPs
@640 (B) | -| ----------------------------------------------------------------------------------------------- | --------------------- | -------------------- | ----------------- | ---------------------------- | ----------------------------- | ------------------------------ | ------------------ | ---------------------- | -| [YOLOv5n](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n.pt) | 640 | 28.0 | 45.7 | **45** | **6.3** | **0.6** | **1.9** | **4.5** | -| [YOLOv5s](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt) | 640 | 37.4 | 56.8 | 98 | 6.4 | 0.9 | 7.2 | 16.5 | -| [YOLOv5m](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m.pt) | 640 | 45.4 | 64.1 | 224 | 8.2 | 1.7 | 21.2 | 49.0 | -| [YOLOv5l](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l.pt) | 640 | 49.0 | 67.3 | 430 | 10.1 | 2.7 | 46.5 | 109.1 | -| [YOLOv5x](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x.pt) | 640 | 50.7 | 68.9 | 766 | 12.1 | 4.8 | 86.7 | 205.7 | -| | | | | | | | | | -| [YOLOv5n6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n6.pt) | 1280 | 36.0 | 54.4 | 153 | 8.1 | 2.1 | 3.2 | 4.6 | -| [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | -| [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | -| [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | -| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+ [TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- | - -
- Table Notes - -- All YOLOv5 checkpoints shown are trained to 300 epochs with default settings. Nano and Small models use `hyp.scratch-low.yaml` hyperparameters, others use `hyp.scratch-high.yaml`. See [Hyperparameter Tuning Guide](https://docs.ultralytics.com/guides/hyperparameter-tuning/). -- **mAPval** values are for single-model single-scale evaluation on the [COCO val2017 dataset](https://docs.ultralytics.com/datasets/detect/coco/).
Reproduce using `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65`. -- **Speed** metrics averaged over COCO val images using an [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p4/) instance. NMS times (~1 ms/img) are not included.
Reproduce using `python val.py --data coco.yaml --img 640 --task speed --batch 1`. -- **TTA** ([Test Time Augmentation](https://docs.ultralytics.com/modes/val/#inference-augmentation)) includes reflection and scale augmentations.
Reproduce using `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment`. - -
- -##
🖼️ Segmentation
- -While YOLOv3 primarily focused on object detection, later Ultralytics models like YOLOv5 introduced instance segmentation capabilities. The YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7.0) included segmentation models that achieved state-of-the-art performance. These models are easy to train, validate, and deploy. See the [YOLOv5 Release Notes](https://github.com/ultralytics/yolov5/releases/v7.0) and the [YOLOv5 Segmentation Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/segment/tutorial.ipynb) for more details and tutorials. - -
- Segmentation Checkpoints (YOLOv5) - -
- - + Neural Magic logo
-YOLOv5 segmentation models were trained on the [COCO-segments dataset](https://docs.ultralytics.com/datasets/segment/coco/) for 300 epochs at an image size of 640 using A100 GPUs. Models were exported to ONNX FP32 for CPU speed tests and TensorRT FP16 for GPU speed tests on Google [Colab Pro](https://colab.research.google.com/signup). - -| Model | size
(pixels) | mAPbox
50-95 | mAPmask
50-95 | Train time
300 epochs
A100 (hours) | Speed
ONNX CPU
(ms) | Speed
TRT A100
(ms) | params
(M) | FLOPs
@640 (B) | -| ------------------------------------------------------------------------------------------ | --------------------- | -------------------- | --------------------- | --------------------------------------------- | ------------------------------ | ------------------------------ | ------------------ | ---------------------- | -| [YOLOv5n-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-seg.pt) | 640 | 27.6 | 23.4 | 80:17 | **62.7** | **1.2** | **2.0** | **7.1** | -| [YOLOv5s-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt) | 640 | 37.6 | 31.7 | 88:16 | 173.3 | 1.4 | 7.6 | 26.4 | -| [YOLOv5m-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-seg.pt) | 640 | 45.0 | 37.1 | 108:36 | 427.0 | 2.2 | 22.0 | 70.8 | -| [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | -| [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | - -- All checkpoints trained for 300 epochs with SGD optimizer (`lr0=0.01`, `weight_decay=5e-5`) at image size 640 using default settings. Runs logged at [W&B YOLOv5_v70_official](https://wandb.ai/glenn-jocher/YOLOv5_v70_official). -- **Accuracy** values are for single-model, single-scale on the COCO dataset.
Reproduce with `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt`. -- **Speed** averaged over 100 inference images on a [Colab Pro](https://colab.research.google.com/signup) A100 High-RAM instance (inference only, NMS adds ~1ms/image).
Reproduce with `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt --batch 1`. -- **Export** to ONNX (FP32) and TensorRT (FP16) using `export.py`.
Reproduce with `python export.py --weights yolov5s-seg.pt --include engine --device 0 --half`. - -
- -
- Segmentation Usage Examples (YOLOv5)  Open In Colab - -### Train - -Train YOLOv5 segmentation models. Use `--data coco128-seg.yaml` for auto-download or manually download COCO-segments with `bash data/scripts/get_coco.sh --train --val --segments` then use `--data coco.yaml`. - -```bash -# Single-GPU Training -python segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 - -# Multi-GPU DDP Training -python -m torch.distributed.run --nproc_per_node 4 --master_port 1 segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 --device 0,1,2,3 -``` - -### Val - -Validate YOLOv5s-seg mask mAP on the COCO dataset: - -```bash -# Download COCO val segments split (780MB, 5000 images) -bash data/scripts/get_coco.sh --val --segments -# Validate performance -python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 -``` - -### Predict - -Use a pretrained YOLOv5m-seg model for prediction: - -```bash -# Predict objects and masks in an image -python segment/predict.py --weights yolov5m-seg.pt --data data/images/bus.jpg -``` - -```python -# Load model via PyTorch Hub (Note: Segmentation inference might require specific handling) -# model = torch.hub.load("ultralytics/yolov5", "custom", "yolov5m-seg.pt") -``` - -| ![Zidane Segmentation Example](https://user-images.githubusercontent.com/26833433/203113421-decef4c4-183d-4a0a-a6c2-6435b33bc5d3.jpg) | ![Bus Segmentation Example](https://user-images.githubusercontent.com/26833433/203113416-11fe0025-69f7-4874-a0a6-65d0bfe2999a.jpg) | -| ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | - -### Export - -Export a YOLOv5s-seg model to ONNX and TensorRT formats: - -```bash -# Export model for deployment -python export.py --weights yolov5s-seg.pt --include onnx engine --img 640 --device 0 -``` - -
- -##
🏷️ Classification
- -Similar to segmentation, image classification capabilities were formally introduced in later Ultralytics YOLO versions, specifically YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases/v6.2). These models allow for training, validation, and deployment for classification tasks. Check the [YOLOv5 Release Notes](https://github.com/ultralytics/yolov5/releases/v6.2) and the [YOLOv5 Classification Colab Notebook](https://github.com/ultralytics/yolov5/blob/master/classify/tutorial.ipynb) for detailed information and examples. - -
- Classification Checkpoints (YOLOv5 & Others) - -
- -YOLOv5-cls models were trained on [ImageNet](https://docs.ultralytics.com/datasets/classify/imagenet/) for 90 epochs using a 4xA100 instance. ResNet and EfficientNet models were trained alongside for comparison using the same settings. Models were exported to ONNX FP32 (CPU speed) and TensorRT FP16 (GPU speed) and tested on Google [Colab Pro](https://colab.research.google.com/signup). - -| Model | size
(pixels) | acc
top1 | acc
top5 | Training
90 epochs
4xA100 (hours) | Speed
ONNX CPU
(ms) | Speed
TensorRT V100
(ms) | params
(M) | FLOPs
@224 (B) | -| -------------------------------------------------------------------------------------------------- | --------------------- | ---------------- | ---------------- | -------------------------------------------- | ------------------------------ | ----------------------------------- | ------------------ | ---------------------- | -| [YOLOv5n-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-cls.pt) | 224 | 64.6 | 85.4 | 7:59 | **3.3** | **0.5** | **2.5** | **0.5** | -| [YOLOv5s-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt) | 224 | 71.5 | 90.2 | 8:09 | 6.6 | 0.6 | 5.4 | 1.4 | -| [YOLOv5m-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-cls.pt) | 224 | 75.9 | 92.9 | 10:06 | 15.5 | 0.9 | 12.9 | 3.9 | -| [YOLOv5l-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-cls.pt) | 224 | 78.0 | 94.0 | 11:56 | 26.9 | 1.4 | 26.5 | 8.5 | -| [YOLOv5x-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-cls.pt) | 224 | **79.0** | **94.4** | 15:04 | 54.3 | 1.8 | 48.1 | 15.9 | -| | | | | | | | | | -| [ResNet18](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet18.pt) | 224 | 70.3 | 89.5 | **6:47** | 11.2 | 0.5 | 11.7 | 3.7 | -| [ResNet34](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet34.pt) | 224 | 73.9 | 91.8 | 8:33 | 20.6 | 0.9 | 21.8 | 7.4 | -| [ResNet50](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet50.pt) | 224 | 76.8 | 93.4 | 11:10 | 23.4 | 1.0 | 25.6 | 8.5 | -| [ResNet101](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet101.pt) | 224 | 78.5 | 94.3 | 17:10 | 42.1 | 1.9 | 44.5 | 15.9 | -| | | | | | | | | | -| [EfficientNet_b0](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b0.pt) | 224 | 75.1 | 92.4 | 13:03 | 12.5 | 1.3 | 5.3 | 1.0 | -| [EfficientNet_b1](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b1.pt) | 224 | 76.4 | 93.2 | 17:04 | 14.9 | 1.6 | 7.8 | 1.5 | -| [EfficientNet_b2](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b2.pt) | 224 | 76.6 | 93.4 | 17:10 | 15.9 | 1.6 | 9.1 | 1.7 | -| [EfficientNet_b3](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b3.pt) | 224 | 77.7 | 94.0 | 19:19 | 18.9 | 1.9 | 12.2 | 2.4 | - -
- Table Notes (click to expand) +| Ultralytics HUB 🚀 | W&B | Comet ⭐ NEW | Neural Magic | +| :--------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------: | +| Streamline YOLO workflows: Label, train, and deploy effortlessly with [Ultralytics HUB](https://www.ultralytics.com/hub). Try now! | Track experiments, hyperparameters, and results seamlessly with [Weights & Biases](https://docs.wandb.ai/guides/integrations/ultralytics/). | Free forever, [Comet](https://bit.ly/yolov5-readme-comet) lets you save YOLO models, resume training, and interactively visualize and debug predictions. | Run YOLO inference up to 6x faster on CPUs with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic). | -- All checkpoints trained for 90 epochs with SGD optimizer (`lr0=0.001`, `weight_decay=5e-5`) at image size 224 using default settings. Runs logged at [W&B YOLOv5-Classifier-v6-2](https://wandb.ai/glenn-jocher/YOLOv5-Classifier-v6-2). -- **Accuracy** values are for single-model, single-scale on the [ImageNet-1k dataset](https://www.image-net.org/index.php).
Reproduce with `python classify/val.py --data ../datasets/imagenet --img 224`. -- **Speed** averaged over 100 inference images using a Google [Colab Pro](https://colab.research.google.com/signup) V100 High-RAM instance.
Reproduce with `python classify/val.py --data ../datasets/imagenet --img 224 --batch 1`. -- **Export** to ONNX (FP32) and TensorRT (FP16) using `export.py`.
Reproduce with `python export.py --weights yolov5s-cls.pt --include engine onnx --imgsz 224`. +## ⭐ Ultralytics HUB -
-
+Experience seamless AI development with [Ultralytics HUB](https://www.ultralytics.com/hub) ⭐, the ultimate platform for building, training, and deploying computer vision models. Visualize datasets, train YOLOv3, YOLOv5 and YOLOv8 🚀 models, and deploy them to real-world applications without writing any code. Transform images into actionable insights using our cutting-edge tools and user-friendly [Ultralytics App](https://www.ultralytics.com/app-install). Start your journey for **Free** today! -
- Classification Usage Examples (YOLOv5)  Open In Colab + +Ultralytics HUB Platform Screenshot -### Train +## 🤔 Why YOLOv3? -Train YOLOv5 classification models. Datasets like [MNIST](https://docs.ultralytics.com/datasets/classify/mnist/), [Fashion-MNIST](https://docs.ultralytics.com/datasets/classify/fashion-mnist/), [CIFAR10](https://docs.ultralytics.com/datasets/classify/cifar10/), [CIFAR100](https://docs.ultralytics.com/datasets/classify/cifar100/), [Imagenette](https://docs.ultralytics.com/datasets/classify/imagenette/), [Imagewoof](https://docs.ultralytics.com/datasets/classify/imagewoof/), and [ImageNet](https://docs.ultralytics.com/datasets/classify/imagenet/) can be auto-downloaded using the `--data` argument (e.g., `--data mnist`). +YOLOv3 represented a significant step forward in real-time object detection upon its release. Key advantages include: -```bash -# Single-GPU Training on CIFAR-100 -python classify/train.py --model yolov5s-cls.pt --data cifar100 --epochs 5 --img 224 --batch 128 - -# Multi-GPU DDP Training on ImageNet -python -m torch.distributed.run --nproc_per_node 4 --master_port 1 classify/train.py --model yolov5s-cls.pt --data imagenet --epochs 5 --img 224 --device 0,1,2,3 -``` - -### Val - -Validate YOLOv5m-cls accuracy on the ImageNet-1k validation set: - -```bash -# Download ImageNet validation split (6.3G, 50000 images) -bash data/scripts/get_imagenet.sh --val -# Validate model accuracy -python classify/val.py --weights yolov5m-cls.pt --data ../datasets/imagenet --img 224 -``` +- **Improved Accuracy:** Better detection of small objects compared to YOLOv2. +- **Multi-Scale Predictions:** Detects objects at three different scales, enhancing performance across various object sizes. +- **Class Prediction:** Uses logistic classifiers for predicting object classes instead of softmax, allowing for multi-label classification. +- **Feature Extractor:** Utilizes a deeper network (Darknet-53) compared to Darknet-19 used in YOLOv2. -### Predict - -Use a pretrained YOLOv5s-cls model to classify an image: - -```bash -# Classify an image -python classify/predict.py --weights yolov5s-cls.pt --data data/images/bus.jpg -``` - -```python -# Load model via PyTorch Hub -# model = torch.hub.load("ultralytics/yolov5", "custom", "yolov5s-cls.pt") -``` - -### Export - -Export trained classification models (YOLOv5s-cls, ResNet50, EfficientNet-B0) to ONNX and TensorRT formats: - -```bash -# Export models for deployment -python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --include onnx engine --img 224 -``` - -
+While newer models like YOLOv5 and YOLO11 offer further improvements, YOLOv3 remains a solid and widely understood baseline implemented efficiently in PyTorch by Ultralytics. -##
🌎 Environments
+## ☁️ Environments -Get started quickly with our verified environments. Click the icons below for setup details. +Get started quickly with our pre-configured environments. Click the icons below for setup details. -##
💖 Contribute
+## 🤝 Contribute -We welcome your contributions! Making contributions to YOLOv3 should be easy and transparent. Please refer to our [Contributing Guide](https://docs.ultralytics.com/help/contributing/) for instructions on getting started. We also encourage you to fill out the [Ultralytics Survey](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) to share your feedback. A huge thank you to all our contributors! +We welcome your contributions! Making YOLO models accessible and effective is a community effort. Please see our [Contributing Guide](https://docs.ultralytics.com/help/contributing/) to get started. Share your feedback through the [Ultralytics Survey](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey). Thank you to all our contributors for making Ultralytics YOLO better! -[![Ultralytics open-source contributors](https://raw.githubusercontent.com/ultralytics/assets/main/im/image-contributors.png)](https://github.com/ultralytics/ultralytics/graphs/contributors) +[![Ultralytics open-source contributors](https://raw.githubusercontent.com/ultralytics/assets/main/im/image-contributors.png)](https://github.com/ultralytics/yolov5/graphs/contributors) -##
📜 License
+## 📜 License -Ultralytics provides two licensing options to suit different needs: +Ultralytics provides two licensing options to meet different needs: -- **AGPL-3.0 License**: Ideal for students, researchers, and enthusiasts, this [OSI-approved](https://opensource.org/license/agpl-v3) open-source license encourages open collaboration and knowledge sharing. See the [LICENSE](https://github.com/ultralytics/yolov3/blob/master/LICENSE) file for details. -- **Enterprise License**: Tailored for commercial applications, this license allows the integration of Ultralytics software and AI models into commercial products and services, bypassing the open-source requirements of AGPL-3.0. For commercial use cases, please contact us via [Ultralytics Licensing](https://www.ultralytics.com/license). +- **AGPL-3.0 License**: An [OSI-approved](https://opensource.org/license/agpl-v3) open-source license ideal for academic research, personal projects, and testing. It promotes open collaboration and knowledge sharing. See the [LICENSE](https://github.com/ultralytics/yolov5/blob/master/LICENSE) file for details. +- **Enterprise License**: Tailored for commercial applications, this license allows seamless integration of Ultralytics software and AI models into commercial products and services, bypassing the open-source requirements of AGPL-3.0. For commercial use cases, please contact us via [Ultralytics Licensing](https://www.ultralytics.com/license). -##
📞 Contact
+## 📧 Contact -For bug reports and feature requests related to YOLOv3, please visit [GitHub Issues](https://github.com/ultralytics/yolov3/issues). For general questions, discussions, and community interaction, join our [Discord server](https://discord.com/invite/ultralytics)! +For bug reports and feature requests related to Ultralytics YOLO implementations, please visit [GitHub Issues](https://github.com/ultralytics/yolov5/issues). For general questions, discussions, and community support, join our [Discord server](https://discord.com/invite/ultralytics)!
Ultralytics GitHub - + space Ultralytics LinkedIn - + space Ultralytics Twitter - + space Ultralytics YouTube - + space Ultralytics TikTok - + space Ultralytics BiliBili - + space Ultralytics Discord
From 5ba4be1d56e4cdcdb1ef17da9463354f1e6c9b40 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 28 Mar 2025 21:57:27 +0100 Subject: [PATCH 1152/1185] Update YOLOv3 READMEs (#2325) * Update YOLOv3 READMEs * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: UltralyticsAssistant --- README.md | 17 +- README.zh-CN.md | 475 ++++++++++---------------------- utils/loggers/clearml/README.md | 4 +- utils/loggers/comet/README.md | 4 +- 4 files changed, 164 insertions(+), 336 deletions(-) diff --git a/README.md b/README.md index 0cc3763068..88a5633386 100644 --- a/README.md +++ b/README.md @@ -28,20 +28,19 @@ To request an Enterprise License, please complete the form at [Ultralytics Licen
Ultralytics GitHub - + space Ultralytics LinkedIn - + space Ultralytics Twitter - + space Ultralytics YouTube - + space Ultralytics TikTok - + space Ultralytics BiliBili - + space Ultralytics Discord
-
@@ -215,8 +214,8 @@ Explore Ultralytics' key integrations with leading AI platforms. These collabora Neural Magic logo -| Ultralytics HUB 🚀 | W&B | Comet ⭐ NEW | Neural Magic | -| :--------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------: | +| Ultralytics HUB 🚀 | W&B | Comet ⭐ NEW | Neural Magic | +| :--------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------: | | Streamline YOLO workflows: Label, train, and deploy effortlessly with [Ultralytics HUB](https://www.ultralytics.com/hub). Try now! | Track experiments, hyperparameters, and results seamlessly with [Weights & Biases](https://docs.wandb.ai/guides/integrations/ultralytics/). | Free forever, [Comet](https://bit.ly/yolov5-readme-comet) lets you save YOLO models, resume training, and interactively visualize and debug predictions. | Run YOLO inference up to 6x faster on CPUs with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic). | ## ⭐ Ultralytics HUB diff --git a/README.zh-CN.md b/README.zh-CN.md index ecd0b5db7e..4e20e7b9ec 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,16 +1,18 @@

- - + + Ultralytics YOLOv3 banner

-[中文](https://docs.ultralytics.com/zh) | [한국어](https://docs.ultralytics.com/ko) | [日本語](https://docs.ultralytics.com/ja) | [Русский](https://docs.ultralytics.com/ru) | [Deutsch](https://docs.ultralytics.com/de) | [Français](https://docs.ultralytics.com/fr) | [Español](https://docs.ultralytics.com/es) | [Português](https://docs.ultralytics.com/pt) | [Türkçe](https://docs.ultralytics.com/tr) | [Tiếng Việt](https://docs.ultralytics.com/vi) | [العربية](https://docs.ultralytics.com/ar) +[English](https://docs.ultralytics.com/en) | [한국어](https://docs.ultralytics.com/ko) | [日本語](https://docs.ultralytics.com/ja) | [Русский](https://docs.ultralytics.com/ru) | [Deutsch](https://docs.ultralytics.com/de) | [Français](https://docs.ultralytics.com/fr) | [Español](https://docs.ultralytics.com/es) | [Português](https://docs.ultralytics.com/pt) | [Türkçe](https://docs.ultralytics.com/tr) | [Tiếng Việt](https://docs.ultralytics.com/vi) | [العربية](https://docs.ultralytics.com/ar)
YOLOv3 CI YOLOv3 Citation Docker Pulls - Discord Ultralytics Forums Ultralytics Reddit + Discord + Ultralytics Forums + Ultralytics Reddit
Run on Gradient Open In Colab @@ -18,103 +20,130 @@

-YOLOv3 🚀 是世界上最受欢迎的视觉 AI,代表 Ultralytics 对未来视觉 AI 方法的开源研究,结合在数千小时的研究和开发中积累的经验教训和最佳实践。 +Ultralytics YOLOv3 是由 [Ultralytics](https://www.ultralytics.com/) 开发的一款强大而高效的[计算机视觉](https://www.ultralytics.com/glossary/computer-vision-cv)模型。该实现基于 [PyTorch](https://pytorch.org/) 框架,构建在原始 YOLOv3 架构之上,该架构以其相比前代在[目标检测](https://www.ultralytics.com/glossary/object-detection)速度和准确性方面的显著改进而闻名。它融合了广泛研究和开发的见解与最佳实践,使其成为各种视觉 AI 任务的可靠选择。 -我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 YOLOv3 文档 了解详细信息,在 GitHub 上提交问题以获得支持,并加入我们的 Discord 社区进行问题和讨论! +我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 [Ultralytics 文档](https://docs.ultralytics.com/)获取详细信息(注意:特定的 YOLOv3 文档可能有限,请参考通用的 YOLO 原则),在 [GitHub](https://github.com/ultralytics/yolov5/issues/new/choose) 上提出问题以获得支持,并加入我们的 [Discord 社区](https://discord.com/invite/ultralytics)进行提问和讨论! -如需申请企业许可,请在 [Ultralytics Licensing](https://www.ultralytics.com/license) 处填写表格 +如需申请企业许可证,请填写 [Ultralytics 许可](https://www.ultralytics.com/license)表格。 -
Ultralytics GitHub - + space Ultralytics LinkedIn - + space Ultralytics Twitter - + space Ultralytics YouTube - + space Ultralytics TikTok - + space Ultralytics BiliBili - + space Ultralytics Discord
+
-##
YOLO11 🚀 全新发布
+## 🚀 YOLO11:下一代进化 -我们很高兴宣布推出 Ultralytics YOLO11 🚀,这是我们最先进视觉模型的最新进展!现已在 **[GitHub](https://github.com/ultralytics/ultralytics)** 上发布。YOLO11 在速度、精度和易用性方面进一步提升,无论是处理目标检测、图像分割还是图像分类任务,YOLO11 都具备出色的性能和多功能性,助您在各种应用中脱颖而出。 +我们激动地宣布推出 **Ultralytics YOLO11** 🚀,这是我们最先进(SOTA)视觉模型的最新进展!YOLO11 现已在 [Ultralytics YOLO GitHub 仓库](https://github.com/ultralytics/ultralytics)发布,它继承了我们速度、精度和易用性的传统。无论您是处理[目标检测](https://docs.ultralytics.com/tasks/detect/)、[实例分割](https://docs.ultralytics.com/tasks/segment/)、[姿态估计](https://docs.ultralytics.com/tasks/pose/)、[图像分类](https://docs.ultralytics.com/tasks/classify/),还是[旋转目标检测 (OBB)](https://docs.ultralytics.com/tasks/obb/),YOLO11 都能提供在各种应用中脱颖而出所需的性能和多功能性。 -立即开始,解锁 YOLO11 的全部潜力!访问 [Ultralytics 文档](https://docs.ultralytics.com/) 获取全面的指南和资源: +立即开始,释放 YOLO11 的全部潜力!访问 [Ultralytics 文档](https://docs.ultralytics.com/)获取全面的指南和资源: -[![PyPI 版本](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![下载量](https://static.pepy.tech/badge/ultralytics)](https://www.pepy.tech/projects/ultralytics) +[![PyPI version](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![Downloads](https://static.pepy.tech/badge/ultralytics)](https://www.pepy.tech/projects/ultralytics) ```bash +# 安装 ultralytics 包 pip install ultralytics ```
- + Ultralytics YOLO Performance Comparison
-##
文档
+## 📚 文档 -有关训练、测试和部署的完整文档见[YOLOv3 文档](https://docs.ultralytics.com/)。请参阅下面的快速入门示例。 +请参阅 [Ultralytics 文档](https://docs.ultralytics.com/models/yolov3/),了解使用 Ultralytics 框架进行训练、测试和部署的完整文档。虽然特定的 YOLOv3 文档可能有限,但通用原则仍然适用。请参阅下方为 YOLOv3 概念调整的快速入门示例。
安装 -克隆 repo,并要求在 [**Python>=3.7.0**](https://www.python.org/) 环境中安装 [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) ,且要求 [**PyTorch>=1.7**](https://pytorch.org/get-started/locally/) 。 +克隆仓库并在 [**Python>=3.8.0**](https://www.python.org/) 环境中从 [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) 安装依赖项。确保您已安装 [**PyTorch>=1.8**](https://pytorch.org/get-started/locally/)。(注意:此仓库最初是 YOLOv5 的,依赖项应兼容,但建议针对 YOLOv3 进行专门测试)。 ```bash -git clone https://github.com/ultralytics/yolov3 # clone +# 克隆 YOLOv3 仓库 +git clone https://github.com/ultralytics/yolov3 + +# 导航到克隆的目录 cd yolov3 -pip install -r requirements.txt # install + +# 安装所需的包 +pip install -r requirements.txt ```
-
-推理 +
+使用 PyTorch Hub 进行推理 -使用 YOLOv3 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/) 推理。最新 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 +通过 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/) 使用 YOLOv3 进行推理。[模型](https://github.com/ultralytics/yolov5/tree/master/models)如 `yolov3.pt`、`yolov3-spp.pt`、`yolov3-tiny.pt` 可以被加载。 ```python import torch -# Model -model = torch.hub.load("ultralytics/yolov5", "yolov3") # or yolov5n - yolov5x6, custom +# 加载 YOLOv3 模型(例如,yolov3, yolov3-spp) +model = torch.hub.load("ultralytics/yolov3", "yolov3", pretrained=True) # 指定 'yolov3' 或其他变体 -# Images -img = "https://ultralytics.com/images/zidane.jpg" # or file, Path, PIL, OpenCV, numpy, list +# 定义输入图像源(URL、本地文件、PIL 图像、OpenCV 帧、numpy 数组或列表) +img = "https://ultralytics.com/images/zidane.jpg" # 示例图像 -# Inference +# 执行推理 results = model(img) -# Results -results.print() # or .show(), .save(), .crop(), .pandas(), etc. +# 处理结果(选项:.print(), .show(), .save(), .crop(), .pandas()) +results.print() # 将结果打印到控制台 +results.show() # 在窗口中显示结果 +results.save() # 将结果保存到 runs/detect/exp ```
-使用 detect.py 推理 +使用 detect.py 进行推理 -`detect.py` 在各种来源上运行推理, [模型](https://github.com/ultralytics/yolov5/tree/master/models) 自动从 最新的YOLOv5 [release](https://github.com/ultralytics/yolov5/releases) 中下载,并将结果保存到 `runs/detect` 。 +`detect.py` 脚本在各种来源上运行推理。使用 `--weights yolov3.pt` 或其他 YOLOv3 变体。它会自动下载模型并将结果保存到 `runs/detect`。 ```bash -python detect.py --weights yolov3.pt --source 0 # 摄像头 -python detect.py --weights yolov3.pt --source img.jpg # 图片 -python detect.py --weights yolov3.pt --source vid.mp4 # 视频 -python detect.py --weights yolov3.pt --source screen # 截图 -python detect.py --weights yolov3.pt --source path/ # 目录 -python detect.py --weights yolov3.pt --source list.txt # 图片列表 -python detect.py --weights yolov3.pt --source list.streams # 流列表 -python detect.py --weights yolov3.pt --source 'path/*.jpg' # glob 通配符 -python detect.py --weights yolov3.pt --source 'https://youtu.be/LNwODJXcvt4' # YouTube -python detect.py --weights yolov3.pt --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP 流 +# 使用 yolov3-tiny 通过网络摄像头运行推理 +python detect.py --weights yolov3-tiny.pt --source 0 + +# 使用 yolov3 在本地图像文件上运行推理 +python detect.py --weights yolov3.pt --source img.jpg + +# 使用 yolov3-spp 在本地视频文件上运行推理 +python detect.py --weights yolov3-spp.pt --source vid.mp4 + +# 在屏幕截图上运行推理 +python detect.py --weights yolov3.pt --source screen + +# 在图像目录上运行推理 +python detect.py --weights yolov3.pt --source path/to/images/ + +# 在列出图像路径的文本文件上运行推理 +python detect.py --weights yolov3.pt --source list.txt + +# 在列出流 URL 的文本文件上运行推理 +python detect.py --weights yolov3.pt --source list.streams + +# 使用 glob 模式对图像运行推理 +python detect.py --weights yolov3.pt --source 'path/to/*.jpg' + +# 在 YouTube 视频 URL 上运行推理 +python detect.py --weights yolov3.pt --source 'https://youtu.be/LNwODJXcvt4' + +# 在 RTSP、RTMP 或 HTTP 流上运行推理 +python detect.py --weights yolov3.pt --source 'rtsp://example.com/media.mp4' ```
@@ -122,45 +151,52 @@ python detect.py --weights yolov3.pt --source 'rtsp://example.com/media.mp4' # R
训练 -下面的命令重现 YOLOv3 在 [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) 数据集上的结果。 最新的 [模型](https://github.com/ultralytics/yolov5/tree/master/models) 和 [数据集](https://github.com/ultralytics/yolov5/tree/master/data) 将自动的从 YOLOv3 [release](https://github.com/ultralytics/yolov5/releases) 中下载。 YOLOv5n/s/m/l/x 在 V100 GPU 的训练时间为 1/2/4/6/8 天( [多GPU](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/) 训练速度更快)。 尽可能使用更大的 `--batch-size` ,或通过 `--batch-size -1` 实现 YOLOv3 [自动批处理](https://github.com/ultralytics/yolov5/pull/5092) 。下方显示的 batchsize 适用于 V100-16GB。 +以下命令展示了如何在 [COCO 数据集](https://docs.ultralytics.com/datasets/detect/coco/)上训练 YOLOv3 模型。模型和数据集会自动下载。请使用您硬件允许的最大 `--batch-size`。 ```bash -python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3.yaml --batch-size 128 -``` +# 在 COCO 上训练 YOLOv3-tiny 300 个周期(示例设置) +python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3-tiny.yaml --batch-size 64 + +# 在 COCO 上训练 YOLOv3 300 个周期(示例设置) +python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3.yaml --batch-size 32 - +# 在 COCO 上训练 YOLOv3-SPP 300 个周期(示例设置) +python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3-spp.yaml --batch-size 16 +```
教程 -- [自定义数据训练](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/) 🚀 **推荐** -- [最佳训练效果的提示](https://docs.ultralytics.com/guides/model-training-tips/) ☘️ -- [多GPU训练](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/) -- [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/) 🌟 **全新** -- [TFLite, ONNX, CoreML, TensorRT 导出](https://docs.ultralytics.com/yolov5/tutorials/model_export/) 🚀 -- [NVIDIA Jetson 平台部署](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano/) 🌟 **全新** -- [测试时增强 (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/) -- [模型集成](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling/) -- [模型剪枝/稀疏化](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity/) -- [超参数进化](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution/) -- [冻结层的迁移学习](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers/) -- [架构概述](https://docs.ultralytics.com/yolov5/tutorials/architecture_description/) 🌟 **全新** -- [使用 Ultralytics HUB 进行 YOLO 训练和部署](https://www.ultralytics.com/hub) 🚀 **推荐** -- [ClearML 日志记录](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration/) -- [与 Neural Magic 的 Deepsparse 集成的 YOLOv5](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization/) -- [Comet 日志记录](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration/) 🌟 **全新** +注意:这些教程主要使用 YOLOv5 示例,但其原则通常适用于 Ultralytics 框架内的 YOLOv3。 + +- **[训练自定义数据](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/)** 🚀 **推荐**:学习如何在您自己的数据集上训练模型。 +- **[获得最佳训练结果的技巧](https://docs.ultralytics.com/guides/model-training-tips/)** ☘️:通过专家技巧提高模型性能。 +- **[多 GPU 训练](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/)**:使用多个 GPU 加速训练。 +- **[PyTorch Hub 集成](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/)** 🌟 **新增**:使用 PyTorch Hub 轻松加载模型。 +- **[模型导出 (TFLite, ONNX, CoreML, TensorRT)](https://docs.ultralytics.com/yolov5/tutorials/model_export/)** 🚀:将您的模型转换为各种部署格式。 +- **[NVIDIA Jetson 部署](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano/)** 🌟 **新增**:在 NVIDIA Jetson 设备上部署模型。 +- **[测试时增强 (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/)**:使用 TTA 提高预测准确性。 +- **[模型集成](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling/)**:组合多个模型以获得更好的性能。 +- **[模型剪枝/稀疏化](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity/)**:优化模型的大小和速度。 +- **[超参数进化](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution/)**:自动找到最佳训练超参数。 +- **[使用冻结层的迁移学习](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers/)**:高效地将预训练模型应用于新任务。 +- **[架构总结](https://docs.ultralytics.com/yolov5/tutorials/architecture_description/)** 🌟 **新增**:理解模型架构(侧重于 YOLOv3 原则)。 +- **[Ultralytics HUB 训练](https://www.ultralytics.com/hub)** 🚀 **推荐**:使用 Ultralytics HUB 训练和部署 YOLO 模型。 +- **[ClearML 日志记录](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration/)**:与 ClearML 集成以进行实验跟踪。 +- **[Neural Magic DeepSparse 集成](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization/)**:使用 DeepSparse 加速推理。 +- **[Comet 日志记录](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration/)** 🌟 **新增**:使用 Comet ML 记录实验。
-##
集成
+## 🛠️ 集成 -我们与领先的 AI 平台的关键集成扩展了 Ultralytics 产品的功能,提升了数据集标注、训练、可视化和模型管理等任务。探索 Ultralytics 如何通过与 [W&B](https://docs.wandb.ai/guides/integrations/ultralytics/)、[Comet](https://bit.ly/yolov8-readme-comet)、[Roboflow](https://roboflow.com/?ref=ultralytics) 和 [OpenVINO](https://docs.ultralytics.com/integrations/openvino/) 的合作,优化您的 AI 工作流程。 +探索 Ultralytics 与领先 AI 平台的关键集成。这些合作为数据集标注、训练、可视化和模型管理提供了增强的功能。了解 Ultralytics 如何与 [Weights & Biases (W&B)](https://docs.wandb.ai/guides/integrations/ultralytics/)、[Comet ML](https://bit.ly/yolov5-readme-comet)、[Roboflow](https://roboflow.com/?ref=ultralytics) 和 [Intel OpenVINO](https://docs.ultralytics.com/integrations/openvino/) 合作以优化您的 AI 工作流程。
-Ultralytics active learning integrations +Ultralytics Active Learning Integrations Banner

@@ -168,299 +204,92 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3.yaml --b Ultralytics HUB logo space - - W&B logo + + Weights & Biases logo space - + Comet ML logo space - - NeuralMagic logo + + Neural Magic logo -| Ultralytics HUB 🚀 | W&B | Comet ⭐ 全新 | Neural Magic | -| :----------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------: | -| 简化 YOLO 工作流程:通过 [Ultralytics HUB](https://www.ultralytics.com/hub) 轻松标注、训练和部署。立即试用! | 使用 [Weights & Biases](https://docs.wandb.ai/guides/integrations/ultralytics/) 跟踪实验、超参数和结果 | 永久免费,[Comet](https://bit.ly/yolov5-readme-comet) 允许您保存 YOLO11 模型、恢复训练,并交互式地可视化和调试预测结果 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) 运行 YOLO11 推理,速度提升至 6 倍 | +| Ultralytics HUB 🚀 | W&B | Comet ⭐ 新增 | Neural Magic | +| :----------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------: | +| 简化 YOLO 工作流程:使用 [Ultralytics HUB](https://www.ultralytics.com/hub) 轻松标注、训练和部署。立即试用! | 使用 [Weights & Biases](https://docs.wandb.ai/guides/integrations/ultralytics/) 无缝跟踪实验、超参数和结果。 | 永久免费的 [Comet](https://bit.ly/yolov5-readme-comet) 让您能够保存 YOLO 模型、恢复训练,并交互式地可视化和调试预测。 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) 在 CPU 上将 YOLO 推理速度提高达 6 倍。 | -##
Ultralytics HUB
+## ⭐ Ultralytics HUB -[Ultralytics HUB](https://www.ultralytics.com/hub) 是我们的⭐**新的**用于可视化数据集、训练 YOLOv3 🚀 模型并以无缝体验部署到现实世界的无代码解决方案。现在开始 **免费** 使用他! +通过 [Ultralytics HUB](https://www.ultralytics.com/hub) ⭐ 体验无缝的 AI 开发,这是构建、训练和部署计算机视觉模型的终极平台。无需编写任何代码即可可视化数据集、训练 YOLOv3、YOLOv5 和 YOLOv8 🚀 模型,并将它们部署到实际应用中。使用我们尖端的工具和用户友好的 [Ultralytics App](https://www.ultralytics.com/app-install) 将图像转化为可操作的见解。立即开始您的**免费**之旅! - - -##
为什么选择 YOLOv3
- -YOLOv3 超级容易上手,简单易学。我们优先考虑现实世界的结果。 - -

-
- YOLOv5-P5 640 图 - -

-
-
- 图表笔记 - -- **COCO AP val** 表示 mAP@0.5:0.95 指标,在 [COCO val2017](http://cocodataset.org) 数据集的 5000 张图像上测得, 图像包含 256 到 1536 各种推理大小。 -- **显卡推理速度** 为在 [COCO val2017](http://cocodataset.org) 数据集上的平均推理时间,使用 [AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p4/) V100实例,batchsize 为 32 。 -- **EfficientDet** 数据来自 [google/automl](https://github.com/google/automl) , batchsize 为32。 -- **复现命令** 为 `python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n6.pt yolov5s6.pt yolov5m6.pt yolov5l6.pt yolov5x6.pt` - -
- -### 预训练模型 - -| 模型 | 尺寸
(像素) | mAPval
50-95 | mAPval
50 | 推理速度
CPU b1
(ms) | 推理速度
V100 b1
(ms) | 速度
V100 b32
(ms) | 参数量
(M) | FLOPs
@640 (B) | -| ---------------------------------------------------------------------------------------------- | --------------------- | -------------------- | ----------------- | --------------------------------- | ---------------------------------- | ------------------------------- | ------------------ | ---------------------- | -| [YOLOv5n](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n.pt) | 640 | 28.0 | 45.7 | **45** | **6.3** | **0.6** | **1.9** | **4.5** | -| [YOLOv5s](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt) | 640 | 37.4 | 56.8 | 98 | 6.4 | 0.9 | 7.2 | 16.5 | -| [YOLOv5m](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m.pt) | 640 | 45.4 | 64.1 | 224 | 8.2 | 1.7 | 21.2 | 49.0 | -| [YOLOv5l](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l.pt) | 640 | 49.0 | 67.3 | 430 | 10.1 | 2.7 | 46.5 | 109.1 | -| [YOLOv5x](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x.pt) | 640 | 50.7 | 68.9 | 766 | 12.1 | 4.8 | 86.7 | 205.7 | -| | | | | | | | | | -| [YOLOv5n6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n6.pt) | 1280 | 36.0 | 54.4 | 153 | 8.1 | 2.1 | 3.2 | 4.6 | -| [YOLOv5s6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s6.pt) | 1280 | 44.8 | 63.7 | 385 | 8.2 | 3.6 | 12.6 | 16.8 | -| [YOLOv5m6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m6.pt) | 1280 | 51.3 | 69.3 | 887 | 11.1 | 6.8 | 35.7 | 50.0 | -| [YOLOv5l6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l6.pt) | 1280 | 53.7 | 71.3 | 1784 | 15.8 | 10.5 | 76.8 | 111.4 | -| [YOLOv5x6](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x6.pt)
+[TTA] | 1280
1536 | 55.0
**55.8** | 72.7
**72.7** | 3136
- | 26.2
- | 19.4
- | 140.7
- | 209.8
- | +Ultralytics HUB Platform Screenshot -
- 笔记 - -- 所有模型都使用默认配置,训练 300 epochs。n和s模型使用 [hyp.scratch-low.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-low.yaml) ,其他模型都使用 [hyp.scratch-high.yaml](https://github.com/ultralytics/yolov5/blob/master/data/hyps/hyp.scratch-high.yaml) 。 -- \*\*mAPval\*\*在单模型单尺度上计算,数据集使用 [COCO val2017](http://cocodataset.org) 。
复现命令 `python val.py --data coco.yaml --img 640 --conf 0.001 --iou 0.65` -- **推理速度**在 COCO val 图像总体时间上进行平均得到,测试环境使用[AWS p3.2xlarge](https://aws.amazon.com/ec2/instance-types/p4/)实例。 NMS 时间 (大约 1 ms/img) 不包括在内。
复现命令 `python val.py --data coco.yaml --img 640 --task speed --batch 1` -- **TTA** [测试时数据增强](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/) 包括反射和尺度变换。
复现命令 `python val.py --data coco.yaml --img 1536 --iou 0.7 --augment` +## 🤔 为什么选择 YOLOv3? -
+YOLOv3 在发布时代表了实时目标检测领域的一个重要进步。其主要优势包括: -##
实例分割模型 ⭐ 新
+- **更高的准确性:** 与 YOLOv2 相比,对小目标的检测效果更好。 +- **多尺度预测:** 在三个不同的尺度上检测目标,提高了对各种尺寸目标的性能。 +- **类别预测:** 使用逻辑分类器而不是 softmax 来预测目标类别,允许进行多标签分类。 +- **特征提取器:** 与 YOLOv2 中使用的 Darknet-19 相比,使用了更深的网络(Darknet-53)。 -我们新的 YOLOv5 [release v7.0](https://github.com/ultralytics/yolov5/releases/v7.0) 实例分割模型是世界上最快和最准确的模型,击败所有当前 [SOTA 基准](https://paperswithcode.com/sota/real-time-instance-segmentation-on-mscoco)。我们使它非常易于训练、验证和部署。更多细节请查看 [发行说明](https://github.com/ultralytics/yolov5/releases/v7.0) 或访问我们的 [YOLOv5 分割 Colab 笔记本](https://github.com/ultralytics/yolov5/blob/master/segment/tutorial.ipynb) 以快速入门。 +虽然像 YOLOv5 和 YOLO11 这样的更新模型提供了进一步的改进,但 YOLOv3 仍然是一个坚实且被广泛理解的基准,由 Ultralytics 在 PyTorch 中高效实现。 -
- 实例分割模型列表 +## ☁️ 环境 -
+使用我们预配置的环境快速开始。点击下面的图标查看设置详情。
- - -
- -我们使用 A100 GPU 在 COCO 上以 640 图像大小训练了 300 epochs 得到 YOLOv5 分割模型。我们将所有模型导出到 ONNX FP32 以进行 CPU 速度测试,并导出到 TensorRT FP16 以进行 GPU 速度测试。为了便于再现,我们在 Google [Colab Pro](https://colab.research.google.com/signup) 上进行了所有速度测试。 - -| 模型 | 尺寸
(像素) | mAPbox
50-95 | mAPmask
50-95 | 训练时长
300 epochs
A100 GPU(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TRT A100
(ms) | 参数量
(M) | FLOPs
@640 (B) | -| ------------------------------------------------------------------------------------------ | --------------------- | -------------------- | --------------------- | ----------------------------------------------- | ----------------------------------- | ----------------------------------- | ------------------ | ---------------------- | -| [YOLOv5n-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-seg.pt) | 640 | 27.6 | 23.4 | 80:17 | **62.7** | **1.2** | **2.0** | **7.1** | -| [YOLOv5s-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt) | 640 | 37.6 | 31.7 | 88:16 | 173.3 | 1.4 | 7.6 | 26.4 | -| [YOLOv5m-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-seg.pt) | 640 | 45.0 | 37.1 | 108:36 | 427.0 | 2.2 | 22.0 | 70.8 | -| [YOLOv5l-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-seg.pt) | 640 | 49.0 | 39.9 | 66:43 (2x) | 857.4 | 2.9 | 47.9 | 147.7 | -| [YOLOv5x-seg](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-seg.pt) | 640 | **50.7** | **41.4** | 62:56 (3x) | 1579.2 | 4.5 | 88.8 | 265.7 | - -- 所有模型使用 SGD 优化器训练, 都使用 `lr0=0.01` 和 `weight_decay=5e-5` 参数, 图像大小为 640 。
训练 log 可以查看 https://wandb.ai/glenn-jocher/YOLOv5_v70_official -- **准确性**结果都在 COCO 数据集上,使用单模型单尺度测试得到。
复现命令 `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt` -- **推理速度**是使用 100 张图像推理时间进行平均得到,测试环境使用 [Colab Pro](https://colab.research.google.com/signup) 上 A100 高 RAM 实例。结果仅表示推理速度(NMS 每张图像增加约 1 毫秒)。
复现命令 `python segment/val.py --data coco.yaml --weights yolov5s-seg.pt --batch 1` -- **模型转换**到 FP32 的 ONNX 和 FP16 的 TensorRT 脚本为 `export.py`.
运行命令 `python export.py --weights yolov5s-seg.pt --include engine --device 0 --half` - -
- -
- 分割模型使用示例  Open In Colab - -### 训练 - -YOLOv5分割训练支持自动下载 COCO128-seg 分割数据集,用户仅需在启动指令中包含 `--data coco128-seg.yaml` 参数。 若要手动下载,使用命令 `bash data/scripts/get_coco.sh --train --val --segments`, 在下载完毕后,使用命令 `python train.py --data coco.yaml` 开启训练。 - -```bash -# 单 GPU -python segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 - -# 多 GPU, DDP 模式 -python -m torch.distributed.run --nproc_per_node 4 --master_port 1 segment/train.py --data coco128-seg.yaml --weights yolov5s-seg.pt --img 640 --device 0,1,2,3 -``` - -### 验证 - -在 COCO 数据集上验证 YOLOv5s-seg mask mAP: - -```bash -bash data/scripts/get_coco.sh --val --segments # 下载 COCO val segments 数据集 (780MB, 5000 images) -python segment/val.py --weights yolov5s-seg.pt --data coco.yaml --img 640 # 验证 -``` - -### 预测 - -使用预训练的 YOLOv5m-seg.pt 来预测 bus.jpg: - -```bash -python segment/predict.py --weights yolov5m-seg.pt --data data/images/bus.jpg -``` - -```python -model = torch.hub.load( - "ultralytics/yolov5", "custom", "yolov5m-seg.pt" -) # 从load from PyTorch Hub 加载模型 (WARNING: 推理暂未支持) -``` - -| ![zidane](https://user-images.githubusercontent.com/26833433/203113421-decef4c4-183d-4a0a-a6c2-6435b33bc5d3.jpg) | ![bus](https://user-images.githubusercontent.com/26833433/203113416-11fe0025-69f7-4874-a0a6-65d0bfe2999a.jpg) | -| ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | - -### 模型导出 - -将 YOLOv5s-seg 模型导出到 ONNX 和 TensorRT: - -```bash -python export.py --weights yolov5s-seg.pt --include onnx engine --img 640 --device 0 -``` - -
- -##
分类网络 ⭐ 新
- -YOLOv5 [release v6.2](https://github.com/ultralytics/yolov5/releases) 带来对分类模型训练、验证和部署的支持!详情请查看 [发行说明](https://github.com/ultralytics/yolov5/releases/v6.2) 或访问我们的 [YOLOv5 分类 Colab 笔记本](https://github.com/ultralytics/yolov5/blob/master/classify/tutorial.ipynb) 以快速入门。 - -
- 分类网络模型 - -
- -我们使用 4xA100 实例在 ImageNet 上训练了 90 个 epochs 得到 YOLOv5-cls 分类模型,我们训练了 ResNet 和 EfficientNet 模型以及相同的默认训练设置以进行比较。我们将所有模型导出到 ONNX FP32 以进行 CPU 速度测试,并导出到 TensorRT FP16 以进行 GPU 速度测试。为了便于重现,我们在 Google 上进行了所有速度测试 [Colab Pro](https://colab.research.google.com/signup) 。 - -| 模型 | 尺寸
(像素) | acc
top1 | acc
top5 | 训练时长
90 epochs
4xA100(小时) | 推理速度
ONNX CPU
(ms) | 推理速度
TensorRT V100
(ms) | 参数
(M) | FLOPs
@640 (B) | -| -------------------------------------------------------------------------------------------------- | --------------------- | ---------------- | ---------------- | -------------------------------------------- | ----------------------------------- | ---------------------------------------- | ---------------- | ---------------------- | -| [YOLOv5n-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5n-cls.pt) | 224 | 64.6 | 85.4 | 7:59 | **3.3** | **0.5** | **2.5** | **0.5** | -| [YOLOv5s-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt) | 224 | 71.5 | 90.2 | 8:09 | 6.6 | 0.6 | 5.4 | 1.4 | -| [YOLOv5m-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5m-cls.pt) | 224 | 75.9 | 92.9 | 10:06 | 15.5 | 0.9 | 12.9 | 3.9 | -| [YOLOv5l-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5l-cls.pt) | 224 | 78.0 | 94.0 | 11:56 | 26.9 | 1.4 | 26.5 | 8.5 | -| [YOLOv5x-cls](https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5x-cls.pt) | 224 | **79.0** | **94.4** | 15:04 | 54.3 | 1.8 | 48.1 | 15.9 | -| | | | | | | | | | -| [ResNet18](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet18.pt) | 224 | 70.3 | 89.5 | **6:47** | 11.2 | 0.5 | 11.7 | 3.7 | -| [Resnetzch](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet34.pt) | 224 | 73.9 | 91.8 | 8:33 | 20.6 | 0.9 | 21.8 | 7.4 | -| [ResNet50](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet50.pt) | 224 | 76.8 | 93.4 | 11:10 | 23.4 | 1.0 | 25.6 | 8.5 | -| [ResNet101](https://github.com/ultralytics/yolov5/releases/download/v7.0/resnet101.pt) | 224 | 78.5 | 94.3 | 17:10 | 42.1 | 1.9 | 44.5 | 15.9 | -| | | | | | | | | | -| [EfficientNet_b0](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b0.pt) | 224 | 75.1 | 92.4 | 13:03 | 12.5 | 1.3 | 5.3 | 1.0 | -| [EfficientNet_b1](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b1.pt) | 224 | 76.4 | 93.2 | 17:04 | 14.9 | 1.6 | 7.8 | 1.5 | -| [EfficientNet_b2](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b2.pt) | 224 | 76.6 | 93.4 | 17:10 | 15.9 | 1.6 | 9.1 | 1.7 | -| [EfficientNet_b3](https://github.com/ultralytics/yolov5/releases/download/v7.0/efficientnet_b3.pt) | 224 | 77.7 | 94.0 | 19:19 | 18.9 | 1.9 | 12.2 | 2.4 | - -
- Table Notes (点击以展开) - -- 所有模型都使用 SGD 优化器训练 90 个 epochs,都使用 `lr0=0.001` 和 `weight_decay=5e-5` 参数, 图像大小为 224 ,且都使用默认设置。
训练 log 可以查看 https://wandb.ai/glenn-jocher/YOLOv5-Classifier-v6-2 -- **准确性**都在单模型单尺度上计算,数据集使用 [ImageNet-1k](https://www.image-net.org/index.php) 。
复现命令 `python classify/val.py --data ../datasets/imagenet --img 224` -- **推理速度**是使用 100 个推理图像进行平均得到,测试环境使用谷歌 [Colab Pro](https://colab.research.google.com/signup) V100 高 RAM 实例。
复现命令 `python classify/val.py --data ../datasets/imagenet --img 224 --batch 1` -- **模型导出**到 FP32 的 ONNX 和 FP16 的 TensorRT 使用 `export.py` 。
复现命令 `python export.py --weights yolov5s-cls.pt --include engine onnx --imgsz 224` -
-
- -
- 分类训练示例  Open In Colab - -### 训练 - -YOLOv5 分类训练支持自动下载 MNIST、Fashion-MNIST、CIFAR10、CIFAR100、Imagenette、Imagewoof 和 ImageNet 数据集,命令中使用 `--data` 即可。 MNIST 示例 `--data mnist` 。 - -```bash -# 单 GPU -python classify/train.py --model yolov5s-cls.pt --data cifar100 --epochs 5 --img 224 --batch 128 - -# 多 GPU, DDP 模式 -python -m torch.distributed.run --nproc_per_node 4 --master_port 1 classify/train.py --model yolov5s-cls.pt --data imagenet --epochs 5 --img 224 --device 0,1,2,3 -``` - -### 验证 - -在 ImageNet-1k 数据集上验证 YOLOv5m-cls 的准确性: - -```bash -bash data/scripts/get_imagenet.sh --val # download ImageNet val split (6.3G, 50000 images) -python classify/val.py --weights yolov5m-cls.pt --data ../datasets/imagenet --img 224 # validate -``` - -### 预测 - -使用预训练的 YOLOv5s-cls.pt 来预测 bus.jpg: - -```bash -python classify/predict.py --weights yolov5s-cls.pt --data data/images/bus.jpg -``` - -```python -model = torch.hub.load("ultralytics/yolov5", "custom", "yolov5s-cls.pt") # load from PyTorch Hub -``` - -### 模型导出 - -将一组经过训练的 YOLOv5s-cls、ResNet 和 EfficientNet 模型导出到 ONNX 和 TensorRT: - -```bash -python export.py --weights yolov5s-cls.pt resnet50.pt efficientnet_b0.pt --include onnx engine --img 224 -``` - -
- -##
环境
- -使用下面我们经过验证的环境,在几秒钟内开始使用 YOLOv3 。单击下面的图标了解详细信息。 - - -##
贡献
- -我们喜欢您的意见或建议!我们希望尽可能简单和透明地为 YOLOv3 做出贡献。请看我们的 [投稿指南](https://docs.ultralytics.com/help/contributing/),并填写 [YOLOv5调查](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) 向我们发送您的体验反馈。感谢我们所有的贡献者! +## 🤝 贡献 - +我们欢迎您的贡献!让 YOLO 模型易于访问和有效是社区共同努力的结果。请参阅我们的[贡献指南](https://docs.ultralytics.com/help/contributing/)开始。通过 [Ultralytics 调查](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey)分享您的反馈。感谢所有为使 Ultralytics YOLO 变得更好而做出贡献的人! - - +[![Ultralytics open-source contributors](https://raw.githubusercontent.com/ultralytics/assets/main/im/image-contributors.png)](https://github.com/ultralytics/yolov5/graphs/contributors) -##
许可证
+## 📜 许可证 -Ultralytics 提供两种许可证选项以适应各种使用场景: +Ultralytics 提供两种许可选项以满足不同需求: -- **AGPL-3.0 许可证**:这个[OSI 批准](https://opensource.org/license)的开源许可证非常适合学生和爱好者,可以推动开放的协作和知识分享。请查看[LICENSE](https://github.com/ultralytics/yolov3/blob/master/LICENSE) 文件以了解更多细节。 -- **企业许可证**:专为商业用途设计,该许可证允许将 Ultralytics 的软件和 AI 模型无缝集成到商业产品和服务中,从而绕过 AGPL-3.0 的开源要求。如果您的场景涉及将我们的解决方案嵌入到商业产品中,请通过 [Ultralytics Licensing](https://www.ultralytics.com/license)与我们联系。 +- **AGPL-3.0 许可证**:一种 [OSI 批准](https://opensource.org/license/agpl-v3)的开源许可证,非常适合学术研究、个人项目和测试。它促进开放合作和知识共享。详情请参阅 [LICENSE](https://github.com/ultralytics/yolov5/blob/master/LICENSE) 文件。 +- **企业许可证**:专为商业应用量身定制,此许可证允许将 Ultralytics 软件和 AI 模型无缝集成到商业产品和服务中,绕过 AGPL-3.0 的开源要求。对于商业用途,请通过 [Ultralytics 许可](https://www.ultralytics.com/license)联系我们。 -##
联系方式
+## 📧 联系 -对于 Ultralytics 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov3/issues),并加入我们的 [Discord](https://discord.com/invite/ultralytics) 社区进行问题和讨论! +有关 Ultralytics YOLO 实现的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov5/issues)。有关一般问题、讨论和社区支持,请加入我们的 [Discord 服务器](https://discord.com/invite/ultralytics)!
Ultralytics GitHub - + space Ultralytics LinkedIn - + space Ultralytics Twitter - + space Ultralytics YouTube - + space Ultralytics TikTok - + space Ultralytics BiliBili - + space Ultralytics Discord
- -[tta]: https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation diff --git a/utils/loggers/clearml/README.md b/utils/loggers/clearml/README.md index e012f80e44..55e26b2660 100644 --- a/utils/loggers/clearml/README.md +++ b/utils/loggers/clearml/README.md @@ -141,7 +141,7 @@ Once your dataset is versioned in ClearML, you can reference it directly in your ```bash # Replace with the actual ID from ClearML -python train.py --img 640 --batch 16 --epochs 3 --data clearml:// --weights yolov5s.pt --cache +python train.py --img 640 --batch 16 --epochs 3 --data clearml:// yolov5s.pt --cache < your_dataset_id > --weights ``` The dataset ID used will be logged as a parameter in your ClearML experiment, ensuring full traceability. @@ -174,7 +174,7 @@ Turn any machine into a ClearML Agent by running the following command: ```bash # Replace with the name(s) of your queue(s) -clearml-agent daemon --queue [--docker] # Use --docker to run in a Docker container +clearml-agent daemon --queue < queues_to_listen_to > [--docker] # Use --docker to run in a Docker container ``` ### Cloning, Editing, and Enqueuing Tasks diff --git a/utils/loggers/comet/README.md b/utils/loggers/comet/README.md index 7eeaef5270..c702cd1d38 100644 --- a/utils/loggers/comet/README.md +++ b/utils/loggers/comet/README.md @@ -265,8 +265,8 @@ python utils/loggers/comet/hpo.py \ Use the `comet optimizer` command to run the sweep with multiple workers: ```shell -comet optimizer -j < number_of_workers > \ - utils/loggers/comet/optimizer_config.json utils/loggers/comet/hpo.py +comet optimizer -j \ + utils/loggers/comet/hpo.py < number_of_workers > utils/loggers/comet/optimizer_config.json ``` ### Visualizing Results From 2919399fa5fa39f0b5cfb3f4dd11053de7ae9894 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 29 Mar 2025 01:52:36 +0100 Subject: [PATCH 1153/1185] Update README.md (#2326) * Update README.md Signed-off-by: Glenn Jocher * Update YOLOv3 READMEs * Auto-format by https://ultralytics.com/actions --------- Signed-off-by: Glenn Jocher Co-authored-by: UltralyticsAssistant --- README.md | 16 ++++++++-------- README.zh-CN.md | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 88a5633386..b098ea1a3f 100644 --- a/README.md +++ b/README.md @@ -190,13 +190,13 @@ Note: These tutorials primarily use YOLOv5 examples but the principles often app
-## 🛠️ Integrations +## 🧩 Integrations -Explore Ultralytics' key integrations with leading AI platforms. These collaborations enhance capabilities for dataset labeling, training, visualization, and model management. Discover how Ultralytics works with [Weights & Biases (W&B)](https://docs.wandb.ai/guides/integrations/ultralytics/), [Comet ML](https://bit.ly/yolov5-readme-comet), [Roboflow](https://roboflow.com/?ref=ultralytics), and [Intel OpenVINO](https://docs.ultralytics.com/integrations/openvino/) to optimize your AI workflows. +Our key integrations with leading AI platforms extend the functionality of Ultralytics' offerings, enhancing tasks like dataset labeling, training, visualization, and model management. Discover how Ultralytics, in collaboration with partners like [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/), [Comet ML](https://docs.ultralytics.com/integrations/comet/), [Roboflow](https://docs.ultralytics.com/integrations/roboflow/), and [Intel OpenVINO](https://docs.ultralytics.com/integrations/openvino/), can optimize your AI workflow. Explore more at [Ultralytics Integrations](https://docs.ultralytics.com/integrations/). -
- -Ultralytics Active Learning Integrations Banner + + Ultralytics active learning integrations +

@@ -214,9 +214,9 @@ Explore Ultralytics' key integrations with leading AI platforms. These collabora Neural Magic logo -| Ultralytics HUB 🚀 | W&B | Comet ⭐ NEW | Neural Magic | -| :--------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------: | -| Streamline YOLO workflows: Label, train, and deploy effortlessly with [Ultralytics HUB](https://www.ultralytics.com/hub). Try now! | Track experiments, hyperparameters, and results seamlessly with [Weights & Biases](https://docs.wandb.ai/guides/integrations/ultralytics/). | Free forever, [Comet](https://bit.ly/yolov5-readme-comet) lets you save YOLO models, resume training, and interactively visualize and debug predictions. | Run YOLO inference up to 6x faster on CPUs with [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic). | +| Ultralytics HUB 🌟 | Weights & Biases | Comet | Neural Magic | +| :----------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------: | +| Streamline YOLO workflows: Label, train, and deploy effortlessly with [Ultralytics HUB](https://hub.ultralytics.com). Try now! | Track experiments, hyperparameters, and results with [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/). | Free forever, [Comet ML](https://docs.ultralytics.com/integrations/comet/) lets you save YOLO models, resume training, and interactively visualize predictions. | Run YOLO inference up to 6x faster with [Neural Magic DeepSparse](https://docs.ultralytics.com/integrations/neural-magic/). | ## ⭐ Ultralytics HUB diff --git a/README.zh-CN.md b/README.zh-CN.md index 4e20e7b9ec..4755536110 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -20,7 +20,7 @@
-Ultralytics YOLOv3 是由 [Ultralytics](https://www.ultralytics.com/) 开发的一款强大而高效的[计算机视觉](https://www.ultralytics.com/glossary/computer-vision-cv)模型。该实现基于 [PyTorch](https://pytorch.org/) 框架,构建在原始 YOLOv3 架构之上,该架构以其相比前代在[目标检测](https://www.ultralytics.com/glossary/object-detection)速度和准确性方面的显著改进而闻名。它融合了广泛研究和开发的见解与最佳实践,使其成为各种视觉 AI 任务的可靠选择。 +Ultralytics YOLOv3 是由 [Ultralytics](https://www.ultralytics.com/) 开发的一款强大而高效的[计算机视觉](https://www.ultralytics.com/glossary/computer-vision-cv)模型。该实现基于 [PyTorch](https://pytorch.org/) 框架,建立在原始 YOLOv3 架构之上。与之前的版本相比,YOLOv3 以其在[目标检测](https://www.ultralytics.com/glossary/object-detection)速度和准确性方面的显著改进而闻名。它融合了广泛研究和开发的见解与最佳实践,使其成为各种视觉 AI 任务的可靠选择。 我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 [Ultralytics 文档](https://docs.ultralytics.com/)获取详细信息(注意:特定的 YOLOv3 文档可能有限,请参考通用的 YOLO 原则),在 [GitHub](https://github.com/ultralytics/yolov5/issues/new/choose) 上提出问题以获得支持,并加入我们的 [Discord 社区](https://discord.com/invite/ultralytics)进行提问和讨论! @@ -46,7 +46,7 @@ Ultralytics YOLOv3 是由 [Ultralytics](https://www.ultralytics.com/) 开发的 ## 🚀 YOLO11:下一代进化 -我们激动地宣布推出 **Ultralytics YOLO11** 🚀,这是我们最先进(SOTA)视觉模型的最新进展!YOLO11 现已在 [Ultralytics YOLO GitHub 仓库](https://github.com/ultralytics/ultralytics)发布,它继承了我们速度、精度和易用性的传统。无论您是处理[目标检测](https://docs.ultralytics.com/tasks/detect/)、[实例分割](https://docs.ultralytics.com/tasks/segment/)、[姿态估计](https://docs.ultralytics.com/tasks/pose/)、[图像分类](https://docs.ultralytics.com/tasks/classify/),还是[旋转目标检测 (OBB)](https://docs.ultralytics.com/tasks/obb/),YOLO11 都能提供在各种应用中脱颖而出所需的性能和多功能性。 +我们激动地宣布推出 **Ultralytics YOLO11** 🚀,这是我们最先进(SOTA)视觉模型的最新进展!YOLO11 现已在 [Ultralytics YOLO GitHub 仓库](https://github.com/ultralytics/ultralytics)发布,它继承了我们在速度、精度和易用性方面的传统。无论您是处理[目标检测](https://docs.ultralytics.com/tasks/detect/)、[实例分割](https://docs.ultralytics.com/tasks/segment/)、[姿态估计](https://docs.ultralytics.com/tasks/pose/)、[图像分类](https://docs.ultralytics.com/tasks/classify/)还是[旋转目标检测 (OBB)](https://docs.ultralytics.com/tasks/obb/),YOLO11 都能提供在各种应用中脱颖而出所需的性能和多功能性。 立即开始,释放 YOLO11 的全部潜力!访问 [Ultralytics 文档](https://docs.ultralytics.com/)获取全面的指南和资源: @@ -64,7 +64,7 @@ pip install ultralytics ## 📚 文档 -请参阅 [Ultralytics 文档](https://docs.ultralytics.com/models/yolov3/),了解使用 Ultralytics 框架进行训练、测试和部署的完整文档。虽然特定的 YOLOv3 文档可能有限,但通用原则仍然适用。请参阅下方为 YOLOv3 概念调整的快速入门示例。 +请参阅 [Ultralytics 文档](https://docs.ultralytics.com/models/yolov3/),了解使用 Ultralytics 框架进行训练、测试和部署的完整文档。虽然特定的 YOLOv3 文档可能有限,但通用原则仍然适用。请参阅下方为 YOLOv3 概念改编的快速入门示例。
安装 @@ -115,7 +115,7 @@ results.save() # 将结果保存到 runs/detect/exp `detect.py` 脚本在各种来源上运行推理。使用 `--weights yolov3.pt` 或其他 YOLOv3 变体。它会自动下载模型并将结果保存到 `runs/detect`。 ```bash -# 使用 yolov3-tiny 通过网络摄像头运行推理 +# 使用 yolov3-tiny 和网络摄像头运行推理 python detect.py --weights yolov3-tiny.pt --source 0 # 使用 yolov3 在本地图像文件上运行推理 @@ -169,10 +169,10 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3-spp.yaml
教程 -注意:这些教程主要使用 YOLOv5 示例,但其原则通常适用于 Ultralytics 框架内的 YOLOv3。 +注意:这些教程主要使用 YOLOv5 示例,但其原理通常适用于 Ultralytics 框架内的 YOLOv3。 - **[训练自定义数据](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/)** 🚀 **推荐**:学习如何在您自己的数据集上训练模型。 -- **[获得最佳训练结果的技巧](https://docs.ultralytics.com/guides/model-training-tips/)** ☘️:通过专家技巧提高模型性能。 +- **[获得最佳训练结果的技巧](https://docs.ultralytics.com/guides/model-training-tips/)** ☘️:利用专家技巧提高模型性能。 - **[多 GPU 训练](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/)**:使用多个 GPU 加速训练。 - **[PyTorch Hub 集成](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/)** 🌟 **新增**:使用 PyTorch Hub 轻松加载模型。 - **[模型导出 (TFLite, ONNX, CoreML, TensorRT)](https://docs.ultralytics.com/yolov5/tutorials/model_export/)** 🚀:将您的模型转换为各种部署格式。 @@ -182,7 +182,7 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3-spp.yaml - **[模型剪枝/稀疏化](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity/)**:优化模型的大小和速度。 - **[超参数进化](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution/)**:自动找到最佳训练超参数。 - **[使用冻结层的迁移学习](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers/)**:高效地将预训练模型应用于新任务。 -- **[架构总结](https://docs.ultralytics.com/yolov5/tutorials/architecture_description/)** 🌟 **新增**:理解模型架构(侧重于 YOLOv3 原则)。 +- **[架构总结](https://docs.ultralytics.com/yolov5/tutorials/architecture_description/)** 🌟 **新增**:理解模型架构(侧重于 YOLOv3 原理)。 - **[Ultralytics HUB 训练](https://www.ultralytics.com/hub)** 🚀 **推荐**:使用 Ultralytics HUB 训练和部署 YOLO 模型。 - **[ClearML 日志记录](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration/)**:与 ClearML 集成以进行实验跟踪。 - **[Neural Magic DeepSparse 集成](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization/)**:使用 DeepSparse 加速推理。 @@ -190,13 +190,13 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3-spp.yaml
-## 🛠️ 集成 +## 🧩 集成 -探索 Ultralytics 与领先 AI 平台的关键集成。这些合作为数据集标注、训练、可视化和模型管理提供了增强的功能。了解 Ultralytics 如何与 [Weights & Biases (W&B)](https://docs.wandb.ai/guides/integrations/ultralytics/)、[Comet ML](https://bit.ly/yolov5-readme-comet)、[Roboflow](https://roboflow.com/?ref=ultralytics) 和 [Intel OpenVINO](https://docs.ultralytics.com/integrations/openvino/) 合作以优化您的 AI 工作流程。 +我们与领先 AI 平台的关键集成扩展了 Ultralytics 产品的功能,增强了诸如数据集标注、训练、可视化和模型管理等任务。了解 Ultralytics 如何与 [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/)、[Comet ML](https://docs.ultralytics.com/integrations/comet/)、[Roboflow](https://docs.ultralytics.com/integrations/roboflow/) 和 [Intel OpenVINO](https://docs.ultralytics.com/integrations/openvino/) 等合作伙伴协作,优化您的 AI 工作流程。在 [Ultralytics 集成](https://docs.ultralytics.com/integrations/) 探索更多信息。 -
- -Ultralytics Active Learning Integrations Banner + + Ultralytics active learning integrations +

@@ -214,24 +214,24 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3-spp.yaml Neural Magic logo -| Ultralytics HUB 🚀 | W&B | Comet ⭐ 新增 | Neural Magic | -| :----------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------: | -| 简化 YOLO 工作流程:使用 [Ultralytics HUB](https://www.ultralytics.com/hub) 轻松标注、训练和部署。立即试用! | 使用 [Weights & Biases](https://docs.wandb.ai/guides/integrations/ultralytics/) 无缝跟踪实验、超参数和结果。 | 永久免费的 [Comet](https://bit.ly/yolov5-readme-comet) 让您能够保存 YOLO 模型、恢复训练,并交互式地可视化和调试预测。 | 使用 [Neural Magic DeepSparse](https://bit.ly/yolov5-neuralmagic) 在 CPU 上将 YOLO 推理速度提高达 6 倍。 | +| Ultralytics HUB 🌟 | Weights & Biases | Comet | Neural Magic | +| :------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------: | +| 简化 YOLO 工作流程:使用 [Ultralytics HUB](https://hub.ultralytics.com) 轻松标注、训练和部署。立即试用! | 使用 [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/) 跟踪实验、超参数和结果。 | 永久免费,[Comet ML](https://docs.ultralytics.com/integrations/comet/) 让您保存 YOLO 模型、恢复训练并交互式地可视化预测。 | 使用 [Neural Magic DeepSparse](https://docs.ultralytics.com/integrations/neural-magic/) 将 YOLO 推理速度提高多达 6 倍。 | ## ⭐ Ultralytics HUB -通过 [Ultralytics HUB](https://www.ultralytics.com/hub) ⭐ 体验无缝的 AI 开发,这是构建、训练和部署计算机视觉模型的终极平台。无需编写任何代码即可可视化数据集、训练 YOLOv3、YOLOv5 和 YOLOv8 🚀 模型,并将它们部署到实际应用中。使用我们尖端的工具和用户友好的 [Ultralytics App](https://www.ultralytics.com/app-install) 将图像转化为可操作的见解。立即开始您的**免费**之旅! +通过 [Ultralytics HUB](https://www.ultralytics.com/hub) ⭐ 体验无缝的 AI 开发,这是构建、训练和部署计算机视觉模型的终极平台。无需编写任何代码,即可可视化数据集、训练 YOLOv3、YOLOv5 和 YOLOv8 🚀 模型,并将它们部署到实际应用中。使用我们尖端的工具和用户友好的 [Ultralytics App](https://www.ultralytics.com/app-install),将图像转化为可操作的见解。立即开始您的**免费**旅程! Ultralytics HUB Platform Screenshot -## 🤔 为什么选择 YOLOv3? +## 🤔 为何选择 YOLOv3? -YOLOv3 在发布时代表了实时目标检测领域的一个重要进步。其主要优势包括: +YOLOv3 在发布时代表了实时目标检测领域的一大进步。其主要优势包括: -- **更高的准确性:** 与 YOLOv2 相比,对小目标的检测效果更好。 -- **多尺度预测:** 在三个不同的尺度上检测目标,提高了对各种尺寸目标的性能。 -- **类别预测:** 使用逻辑分类器而不是 softmax 来预测目标类别,允许进行多标签分类。 +- **提高准确性:** 与 YOLOv2 相比,对小目标的检测效果更好。 +- **多尺度预测:** 在三个不同尺度上检测目标,提高了对各种尺寸目标的性能。 +- **类别预测:** 使用逻辑分类器预测目标类别,而不是 softmax,允许进行多标签分类。 - **特征提取器:** 与 YOLOv2 中使用的 Darknet-19 相比,使用了更深的网络(Darknet-53)。 虽然像 YOLOv5 和 YOLO11 这样的更新模型提供了进一步的改进,但 YOLOv3 仍然是一个坚实且被广泛理解的基准,由 Ultralytics 在 PyTorch 中高效实现。 @@ -262,7 +262,7 @@ YOLOv3 在发布时代表了实时目标检测领域的一个重要进步。其 ## 🤝 贡献 -我们欢迎您的贡献!让 YOLO 模型易于访问和有效是社区共同努力的结果。请参阅我们的[贡献指南](https://docs.ultralytics.com/help/contributing/)开始。通过 [Ultralytics 调查](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey)分享您的反馈。感谢所有为使 Ultralytics YOLO 变得更好而做出贡献的人! +我们欢迎您的贡献!让 YOLO 模型易于使用且高效是社区共同努力的目标。请参阅我们的[贡献指南](https://docs.ultralytics.com/help/contributing/)开始。通过 [Ultralytics 调查](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey)分享您的反馈。感谢所有为使 Ultralytics YOLO 变得更好而做出贡献的人! [![Ultralytics open-source contributors](https://raw.githubusercontent.com/ultralytics/assets/main/im/image-contributors.png)](https://github.com/ultralytics/yolov5/graphs/contributors) @@ -270,8 +270,8 @@ YOLOv3 在发布时代表了实时目标检测领域的一个重要进步。其 Ultralytics 提供两种许可选项以满足不同需求: -- **AGPL-3.0 许可证**:一种 [OSI 批准](https://opensource.org/license/agpl-v3)的开源许可证,非常适合学术研究、个人项目和测试。它促进开放合作和知识共享。详情请参阅 [LICENSE](https://github.com/ultralytics/yolov5/blob/master/LICENSE) 文件。 -- **企业许可证**:专为商业应用量身定制,此许可证允许将 Ultralytics 软件和 AI 模型无缝集成到商业产品和服务中,绕过 AGPL-3.0 的开源要求。对于商业用途,请通过 [Ultralytics 许可](https://www.ultralytics.com/license)联系我们。 +- **AGPL-3.0 许可证**:一种经 [OSI 批准](https://opensource.org/license/agpl-v3)的开源许可证,非常适合学术研究、个人项目和测试。它促进开放合作和知识共享。详情请参阅 [LICENSE](https://github.com/ultralytics/yolov5/blob/master/LICENSE) 文件。 +- **企业许可证**:专为商业应用量身定制,此许可证允许将 Ultralytics 软件和 AI 模型无缝集成到商业产品和服务中,绕过 AGPL-3.0 的开源要求。对于商业用途,请通过 [Ultralytics 许可](https://www.ultralytics.com/license)与我们联系。 ## 📧 联系 From 4664e8f1bb5bbf061cfc9ef9a168d558ae9bad40 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 15 Apr 2025 22:42:26 +0200 Subject: [PATCH 1154/1185] Update YOLOv3<>Comet ML READMEs (#2327) * Update links.yml Signed-off-by: Glenn Jocher * Update YOLOv3 READMEs * Auto-format by https://ultralytics.com/actions * Update YOLOv3 READMEs * Auto-format by https://ultralytics.com/actions * Update links.yml Signed-off-by: Glenn Jocher * Update YOLOv3 READMEs * Auto-format by https://ultralytics.com/actions * Update YOLOv3 READMEs * Update YOLOv3 READMEs * Update YOLOv3 READMEs * Auto-format by https://ultralytics.com/actions --------- Signed-off-by: Glenn Jocher Co-authored-by: UltralyticsAssistant --- .github/workflows/links.yml | 6 +- CONTRIBUTING.md | 67 +++++++------- README.md | 42 ++++----- README.zh-CN.md | 146 +++++++++++++++--------------- hubconf.py | 6 +- train.py | 2 +- utils/loggers/clearml/README.md | 126 +++++++++++++------------- utils/loggers/comet/README.md | 152 ++++++++++++++++---------------- 8 files changed, 281 insertions(+), 266 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 2da3c066f3..2235c00004 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -33,13 +33,14 @@ jobs: retry_delay_seconds: 60 retries: 2 run: | + set -o pipefail # preserve exit code from lychee command in pipeline lychee \ --scheme 'https' \ --timeout 60 \ --insecure \ --accept 403,429,500,502,999 \ --exclude-all-private \ - --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ + --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|x\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ --exclude-path '**/ci.yaml' \ --github-token ${{ secrets.GITHUB_TOKEN }} \ --header "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \ @@ -54,13 +55,14 @@ jobs: retry_delay_seconds: 60 retries: 2 run: | + set -o pipefail # preserve exit code from lychee command in pipeline lychee \ --scheme 'https' \ --timeout 60 \ --insecure \ --accept 429,999 \ --exclude-all-private \ - --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ + --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|x\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ --exclude-path '**/ci.yaml' \ --github-token ${{ secrets.GITHUB_TOKEN }} \ --header "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ba0e248f12..b324957cf6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,76 +1,79 @@ -## Contributing to YOLOv3 🚀 +# Contributing To YOLOv3 🚀 -We love your input! We want to make contributing to YOLOv5 as easy and transparent as possible, whether it's: +We value your input and welcome your contributions to Ultralytics YOLOv3! Whether you're interested in: - Reporting a bug -- Discussing the current state of the code +- Discussing the current state of the codebase - Submitting a fix - Proposing a new feature - Becoming a maintainer -YOLOv5 works so well due to our combined community effort, and for every small improvement you contribute you will be helping push the frontiers of what's possible in AI 😃! +Ultralytics YOLO models are successful thanks to the collective efforts of our community. Every improvement you contribute helps advance the possibilities of AI and computer vision! 😃 -## Submitting a Pull Request (PR) 🛠️ +## Submitting A Pull Request (PR) 🛠️ -Submitting a PR is easy! This example shows how to submit a PR for updating `requirements.txt` in 4 steps: +Contributing a PR is straightforward! Here’s a step-by-step example for updating `requirements.txt`: -### 1. Select File to Update +### 1. Select The File To Update -Select `requirements.txt` to update by clicking on it in GitHub. +Click on `requirements.txt` in the GitHub repository to open it.

PR_step1

-### 2. Click 'Edit this file' +### 2. Click 'Edit This File' -The button is in the top-right corner. +Use the pencil icon in the top-right corner to begin editing.

PR_step2

-### 3. Make Changes +### 3. Make Your Changes -Change the `matplotlib` version from `3.2.2` to `3.3`. +For example, update the `matplotlib` version from `3.2.2` to `3.3`.

PR_step3

-### 4. Preview Changes and Submit PR +### 4. Preview And Submit Your PR -Click on the **Preview changes** tab to verify your updates. At the bottom of the screen select 'Create a **new branch** for this commit', assign your branch a descriptive name such as `fix/matplotlib_version` and click the green **Propose changes** button. All done, your PR is now submitted to YOLOv5 for review and approval 😃! +Switch to the **Preview changes** tab to review your edits. At the bottom, select 'Create a new branch for this commit', give your branch a descriptive name like `fix/matplotlib_version`, and click the green **Propose changes** button. Your PR is now submitted for review! 😃

PR_step4

-### PR recommendations +### PR Best Practices -To allow your work to be integrated as seamlessly as possible, we advise you to: +To ensure your contribution is integrated smoothly, please: -- ✅ Verify your PR is **up-to-date** with `ultralytics/yolov5` `master` branch. If your PR is behind you can update your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally. +- ✅ Ensure your PR is **up-to-date** with the `ultralytics/yolov3` `master` branch. If your PR is behind, update your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally.

Screenshot 2022-08-29 at 22 47 15

-- ✅ Verify all YOLOv5 Continuous Integration (CI) **checks are passing**. +- ✅ Confirm that all Continuous Integration (CI) **checks are passing**.

Screenshot 2022-08-29 at 22 47 03

-- ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ — Bruce Lee +- ✅ Limit your changes to the **minimum required** for your bug fix or feature. + _"It is not daily increase but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ — Bruce Lee -## Submitting a Bug Report 🐛 +## Submitting A Bug Report 🐛 -If you spot a problem with YOLOv5 please submit a Bug Report! +If you encounter an issue with Ultralytics YOLOv3, please submit a bug report! -For us to start investigating a possible problem we need to be able to reproduce it ourselves first. We've created a few short guidelines below to help users provide what we need to get started. +To help us investigate, please provide a [minimum reproducible example](https://docs.ultralytics.com/help/minimum-reproducible-example/). Your code should be: -When asking a question, people will be better able to provide help if you provide **code** that they can easily understand and use to **reproduce** the problem. This is referred to by community members as creating a [minimum reproducible example](https://docs.ultralytics.com/help/minimum_reproducible_example/). Your code that reproduces the problem should be: +- ✅ **Minimal** – Use as little code as possible that still produces the issue. +- ✅ **Complete** – Include all parts needed for someone else to reproduce the problem. +- ✅ **Reproducible** – Test your code to ensure it reliably triggers the issue. -- ✅ **Minimal** – Use as little code as possible that still produces the same problem -- ✅ **Complete** – Provide **all** parts someone else needs to reproduce your problem in the question itself -- ✅ **Reproducible** – Test the code you're about to provide to make sure it reproduces the problem +Additionally, for [Ultralytics](https://www.ultralytics.com/) to assist, your code should be: -In addition to the above requirements, for [Ultralytics](https://www.ultralytics.com/) to provide assistance your code should be: +- ✅ **Current** – Ensure your code is up-to-date with the latest [master branch](https://github.com/ultralytics/yolov3/tree/master). Use `git pull` or `git clone` to get the latest version. +- ✅ **Unmodified** – The problem must be reproducible without custom modifications to the repository. [Ultralytics](https://www.ultralytics.com/) does not provide support for custom code. -- ✅ **Current** – Verify that your code is up-to-date with the current GitHub [master](https://github.com/ultralytics/yolov5/tree/master), and if necessary `git pull` or `git clone` a new copy to ensure your problem has not already been resolved by previous commits. -- ✅ **Unmodified** – Your problem must be reproducible without any modifications to the codebase in this repository. [Ultralytics](https://www.ultralytics.com/) does not provide support for custom code ⚠️. - -If you believe your problem meets all of the above criteria, please close this issue and raise a new one using the 🐛 **Bug Report** [template](https://github.com/ultralytics/yolov5/issues/new/choose) and provide a [minimum reproducible example](https://docs.ultralytics.com/help/minimum_reproducible_example/) to help us better understand and diagnose your problem. +If your issue meets these criteria, please close your current issue and open a new one using the 🐛 **Bug Report** [template](https://github.com/ultralytics/yolov3/issues/new/choose), including your [minimum reproducible example](https://docs.ultralytics.com/help/minimum-reproducible-example/) to help us diagnose and resolve your problem. ## License -By contributing, you agree that your contributions will be licensed under the [AGPL-3.0 license](https://choosealicense.com/licenses/agpl-3.0/) +By contributing, you agree that your submissions will be licensed under the [AGPL-3.0 license](https://choosealicense.com/licenses/agpl-3.0/). + +--- + +Thank you for helping improve Ultralytics YOLOv3! Your contributions make a difference. For more on open-source best practices, check out the [Ultralytics open-source community](https://www.ultralytics.com/blog/tips-to-start-contributing-to-ultralytics-open-source-projects) and [GitHub's open source guides](https://opensource.guide/how-to-contribute/). diff --git a/README.md b/README.md index b098ea1a3f..d6b6724817 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Docker Pulls Discord Ultralytics Forums - Ultralytics Reddit + Ultralytics Reddit
Run on Gradient Open In Colab @@ -20,11 +20,11 @@
-Ultralytics YOLOv3 is a robust and efficient [computer vision](https://www.ultralytics.com/glossary/computer-vision-cv) model developed by [Ultralytics](https://www.ultralytics.com/). Based on the [PyTorch](https://pytorch.org/) framework, this implementation builds upon the original YOLOv3 architecture, known for its significant improvements in [object detection](https://www.ultralytics.com/glossary/object-detection) speed and accuracy compared to its predecessors. It incorporates insights and best practices from extensive research and development, making it a reliable choice for various vision AI tasks. +Ultralytics YOLOv3 is a robust and efficient [computer vision](https://www.ultralytics.com/glossary/computer-vision-cv) model developed by [Ultralytics](https://www.ultralytics.com/). Built on the [PyTorch](https://pytorch.org/) framework, this implementation extends the original YOLOv3 architecture, renowned for its improvements in [object detection](https://www.ultralytics.com/glossary/object-detection) speed and accuracy over earlier versions. It incorporates best practices and insights from extensive research, making it a reliable choice for a wide range of vision AI applications. -We hope the resources here help you get the most out of YOLOv3. Please browse the [Ultralytics Docs](https://docs.ultralytics.com/) for detailed information (note: specific YOLOv3 docs may be limited, refer to general YOLO principles), raise an issue on [GitHub](https://github.com/ultralytics/yolov5/issues/new/choose) for support, and join our [Discord community](https://discord.com/invite/ultralytics) for questions and discussions! +Explore the [Ultralytics Docs](https://docs.ultralytics.com/) for in-depth guidance (YOLOv3-specific docs may be limited, but general YOLO principles apply), open an issue on [GitHub](https://github.com/ultralytics/yolov5/issues/new/choose) for support, and join our [Discord community](https://discord.com/invite/ultralytics) for questions and discussions! -To request an Enterprise License, please complete the form at [Ultralytics Licensing](https://www.ultralytics.com/license). +For Enterprise License requests, please complete the form at [Ultralytics Licensing](https://www.ultralytics.com/license).
Ultralytics GitHub @@ -46,11 +46,11 @@ To request an Enterprise License, please complete the form at [Ultralytics Licen ## 🚀 YOLO11: The Next Evolution -We are excited to announce the launch of **Ultralytics YOLO11** 🚀, the latest advancement in our state-of-the-art (SOTA) vision models! Available now at the [Ultralytics YOLO GitHub repository](https://github.com/ultralytics/ultralytics), YOLO11 builds on our legacy of speed, precision, and ease of use. Whether you're tackling [object detection](https://docs.ultralytics.com/tasks/detect/), [instance segmentation](https://docs.ultralytics.com/tasks/segment/), [pose estimation](https://docs.ultralytics.com/tasks/pose/), [image classification](https://docs.ultralytics.com/tasks/classify/), or [oriented object detection (OBB)](https://docs.ultralytics.com/tasks/obb/), YOLO11 delivers the performance and versatility needed to excel in diverse applications. +We are thrilled to introduce **Ultralytics YOLO11** 🚀, the latest advancement in our state-of-the-art vision models! Available now at the [Ultralytics YOLO GitHub repository](https://github.com/ultralytics/ultralytics), YOLO11 continues our legacy of speed, precision, and user-friendly design. Whether you're working on [object detection](https://docs.ultralytics.com/tasks/detect/), [instance segmentation](https://docs.ultralytics.com/tasks/segment/), [pose estimation](https://docs.ultralytics.com/tasks/pose/), [image classification](https://docs.ultralytics.com/tasks/classify/), or [oriented object detection (OBB)](https://docs.ultralytics.com/tasks/obb/), YOLO11 delivers the performance and flexibility needed for modern computer vision tasks. Get started today and unlock the full potential of YOLO11! Visit the [Ultralytics Docs](https://docs.ultralytics.com/) for comprehensive guides and resources: -[![PyPI version](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![Downloads](https://static.pepy.tech/badge/ultralytics)](https://www.pepy.tech/projects/ultralytics) +[![PyPI version](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![Downloads](https://static.pepy.tech/badge/ultralytics)](https://pepy.tech/projects/ultralytics) ```bash # Install the ultralytics package @@ -64,12 +64,12 @@ pip install ultralytics ## 📚 Documentation -See the [Ultralytics Docs](https://docs.ultralytics.com/models/yolov3/) for full documentation on training, testing, and deployment using the Ultralytics framework. While specific YOLOv3 documentation might be limited, the general principles apply. See below for quickstart examples adapted for YOLOv3 concepts. +See the [Ultralytics Docs for YOLOv3](https://docs.ultralytics.com/models/yolov3/) for full documentation on training, testing, and deployment using the Ultralytics framework. While YOLOv3-specific documentation may be limited, the general YOLO principles apply. Below are quickstart examples adapted for YOLOv3 concepts.
Install -Clone the repository and install dependencies from [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) in a [**Python>=3.8.0**](https://www.python.org/) environment. Ensure you have [**PyTorch>=1.8**](https://pytorch.org/get-started/locally/) installed. (Note: This repo is originally YOLOv5, dependencies should be compatible but tailored testing for YOLOv3 is recommended). +Clone the repository and install dependencies from `requirements.txt` in a [**Python>=3.8.0**](https://www.python.org/) environment. Ensure you have [**PyTorch>=1.8**](https://pytorch.org/get-started/locally/) installed. (Note: This repo is originally YOLOv5, dependencies should be compatible but tailored testing for YOLOv3 is recommended). ```bash # Clone the YOLOv3 repository @@ -176,7 +176,7 @@ Note: These tutorials primarily use YOLOv5 examples but the principles often app - **[Multi-GPU Training](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/)**: Speed up training using multiple GPUs. - **[PyTorch Hub Integration](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/)** 🌟 **NEW**: Easily load models using PyTorch Hub. - **[Model Export (TFLite, ONNX, CoreML, TensorRT)](https://docs.ultralytics.com/yolov5/tutorials/model_export/)** 🚀: Convert your models to various deployment formats. -- **[NVIDIA Jetson Deployment](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano/)** 🌟 **NEW**: Deploy models on NVIDIA Jetson devices. +- **[NVIDIA Jetson Deployment](https://docs.ultralytics.com/guides/nvidia-jetson/)** 🌟 **NEW**: Deploy models on NVIDIA Jetson devices. - **[Test-Time Augmentation (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/)**: Enhance prediction accuracy with TTA. - **[Model Ensembling](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling/)**: Combine multiple models for better performance. - **[Model Pruning/Sparsity](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity/)**: Optimize models for size and speed. @@ -192,7 +192,7 @@ Note: These tutorials primarily use YOLOv5 examples but the principles often app ## 🧩 Integrations -Our key integrations with leading AI platforms extend the functionality of Ultralytics' offerings, enhancing tasks like dataset labeling, training, visualization, and model management. Discover how Ultralytics, in collaboration with partners like [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/), [Comet ML](https://docs.ultralytics.com/integrations/comet/), [Roboflow](https://docs.ultralytics.com/integrations/roboflow/), and [Intel OpenVINO](https://docs.ultralytics.com/integrations/openvino/), can optimize your AI workflow. Explore more at [Ultralytics Integrations](https://docs.ultralytics.com/integrations/). +Ultralytics offers robust integrations with leading AI platforms to enhance your workflow, including dataset labeling, training, visualization, and model management. Discover how Ultralytics, in collaboration with partners like [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/), [Comet ML](https://docs.ultralytics.com/integrations/comet/), [Roboflow](https://docs.ultralytics.com/integrations/roboflow/), and [Intel OpenVINO](https://docs.ultralytics.com/integrations/openvino/), can optimize your AI projects. Explore more at [Ultralytics Integrations](https://docs.ultralytics.com/integrations/). Ultralytics active learning integrations @@ -214,27 +214,27 @@ Our key integrations with leading AI platforms extend the functionality of Ultra Neural Magic logo
-| Ultralytics HUB 🌟 | Weights & Biases | Comet | Neural Magic | -| :----------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------: | -| Streamline YOLO workflows: Label, train, and deploy effortlessly with [Ultralytics HUB](https://hub.ultralytics.com). Try now! | Track experiments, hyperparameters, and results with [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/). | Free forever, [Comet ML](https://docs.ultralytics.com/integrations/comet/) lets you save YOLO models, resume training, and interactively visualize predictions. | Run YOLO inference up to 6x faster with [Neural Magic DeepSparse](https://docs.ultralytics.com/integrations/neural-magic/). | +| Ultralytics HUB 🌟 | Weights & Biases | Comet | Neural Magic | +| :-----------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------: | +| Streamline YOLO workflows: Label, train, and deploy effortlessly with [Ultralytics HUB](https://hub.ultralytics.com/). Try now! | Track experiments, hyperparameters, and results with [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/). | Free forever, [Comet ML](https://docs.ultralytics.com/integrations/comet/) lets you save YOLO models, resume training, and interactively visualize predictions. | Run YOLO inference up to 6x faster with [Neural Magic DeepSparse](https://docs.ultralytics.com/integrations/neural-magic/). | ## ⭐ Ultralytics HUB -Experience seamless AI development with [Ultralytics HUB](https://www.ultralytics.com/hub) ⭐, the ultimate platform for building, training, and deploying computer vision models. Visualize datasets, train YOLOv3, YOLOv5 and YOLOv8 🚀 models, and deploy them to real-world applications without writing any code. Transform images into actionable insights using our cutting-edge tools and user-friendly [Ultralytics App](https://www.ultralytics.com/app-install). Start your journey for **Free** today! +Experience seamless AI development with [Ultralytics HUB](https://www.ultralytics.com/hub) ⭐, the ultimate platform for building, training, and deploying computer vision models. Visualize datasets, train YOLOv3, YOLOv5, and YOLOv8 🚀 models, and deploy them to real-world applications without writing any code. Transform images into actionable insights using our advanced tools and user-friendly [Ultralytics App](https://www.ultralytics.com/app-install). Start your journey for **Free** today! Ultralytics HUB Platform Screenshot ## 🤔 Why YOLOv3? -YOLOv3 represented a significant step forward in real-time object detection upon its release. Key advantages include: +YOLOv3 marked a major leap forward in real-time object detection at its release. Key advantages include: -- **Improved Accuracy:** Better detection of small objects compared to YOLOv2. -- **Multi-Scale Predictions:** Detects objects at three different scales, enhancing performance across various object sizes. -- **Class Prediction:** Uses logistic classifiers for predicting object classes instead of softmax, allowing for multi-label classification. -- **Feature Extractor:** Utilizes a deeper network (Darknet-53) compared to Darknet-19 used in YOLOv2. +- **Improved Accuracy:** Enhanced detection of small objects compared to YOLOv2. +- **Multi-Scale Predictions:** Detects objects at three different scales, boosting performance across varied object sizes. +- **Class Prediction:** Uses logistic classifiers for object classes, enabling multi-label classification. +- **Feature Extractor:** Employs a deeper network (Darknet-53) versus the Darknet-19 used in YOLOv2. -While newer models like YOLOv5 and YOLO11 offer further improvements, YOLOv3 remains a solid and widely understood baseline implemented efficiently in PyTorch by Ultralytics. +While newer models like YOLOv5 and YOLO11 offer further advancements, YOLOv3 remains a reliable and widely adopted baseline, efficiently implemented in PyTorch by Ultralytics. ## ☁️ Environments @@ -256,7 +256,7 @@ Get started quickly with our pre-configured environments. Click the icons below AWS Marketplace - + GCP Quickstart diff --git a/README.zh-CN.md b/README.zh-CN.md index 4755536110..72e7a0bdf8 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,10 +1,12 @@ +Ultralytics logo +

Ultralytics YOLOv3 banner

-[English](https://docs.ultralytics.com/en) | [한국어](https://docs.ultralytics.com/ko) | [日本語](https://docs.ultralytics.com/ja) | [Русский](https://docs.ultralytics.com/ru) | [Deutsch](https://docs.ultralytics.com/de) | [Français](https://docs.ultralytics.com/fr) | [Español](https://docs.ultralytics.com/es) | [Português](https://docs.ultralytics.com/pt) | [Türkçe](https://docs.ultralytics.com/tr) | [Tiếng Việt](https://docs.ultralytics.com/vi) | [العربية](https://docs.ultralytics.com/ar) +[English](https://docs.ultralytics.com/) | [한국어](https://docs.ultralytics.com/ko) | [日本語](https://docs.ultralytics.com/ja) | [Русский](https://docs.ultralytics.com/ru) | [Deutsch](https://docs.ultralytics.com/de) | [Français](https://docs.ultralytics.com/fr) | [Español](https://docs.ultralytics.com/es) | [Português](https://docs.ultralytics.com/pt) | [Türkçe](https://docs.ultralytics.com/tr) | [Tiếng Việt](https://docs.ultralytics.com/vi) | [العربية](https://docs.ultralytics.com/ar)
YOLOv3 CI @@ -12,7 +14,7 @@ Docker Pulls Discord Ultralytics Forums - Ultralytics Reddit + Ultralytics Reddit
Run on Gradient Open In Colab @@ -20,11 +22,11 @@

-Ultralytics YOLOv3 是由 [Ultralytics](https://www.ultralytics.com/) 开发的一款强大而高效的[计算机视觉](https://www.ultralytics.com/glossary/computer-vision-cv)模型。该实现基于 [PyTorch](https://pytorch.org/) 框架,建立在原始 YOLOv3 架构之上。与之前的版本相比,YOLOv3 以其在[目标检测](https://www.ultralytics.com/glossary/object-detection)速度和准确性方面的显著改进而闻名。它融合了广泛研究和开发的见解与最佳实践,使其成为各种视觉 AI 任务的可靠选择。 +Ultralytics YOLOv3 是由 [Ultralytics](https://www.ultralytics.com/) 开发的高效、强大的[计算机视觉](https://www.ultralytics.com/glossary/computer-vision-cv)模型。该实现基于 [PyTorch](https://pytorch.org/) 框架,构建于原始 YOLOv3 架构之上。与早期版本相比,YOLOv3 在[目标检测](https://www.ultralytics.com/glossary/object-detection)速度与准确性方面表现卓越,融合了前沿研究和最佳实践,成为多种视觉 AI 任务的可靠选择。 -我们希望这里的资源能帮助您充分利用 YOLOv3。请浏览 [Ultralytics 文档](https://docs.ultralytics.com/)获取详细信息(注意:特定的 YOLOv3 文档可能有限,请参考通用的 YOLO 原则),在 [GitHub](https://github.com/ultralytics/yolov5/issues/new/choose) 上提出问题以获得支持,并加入我们的 [Discord 社区](https://discord.com/invite/ultralytics)进行提问和讨论! +欢迎您充分利用本项目资源!请访问 [Ultralytics 文档](https://docs.ultralytics.com/)获取详细指南(注意:YOLOv3 专属文档有限,建议参考通用 YOLO 原则),在 [GitHub Issues](https://github.com/ultralytics/yolov5/issues/new/choose) 提问获取支持,并加入 [Discord 社区](https://discord.com/invite/ultralytics)参与讨论! -如需申请企业许可证,请填写 [Ultralytics 许可](https://www.ultralytics.com/license)表格。 +如需企业许可证,请填写 [Ultralytics 许可申请](https://www.ultralytics.com/license)。
Ultralytics GitHub @@ -46,11 +48,11 @@ Ultralytics YOLOv3 是由 [Ultralytics](https://www.ultralytics.com/) 开发的 ## 🚀 YOLO11:下一代进化 -我们激动地宣布推出 **Ultralytics YOLO11** 🚀,这是我们最先进(SOTA)视觉模型的最新进展!YOLO11 现已在 [Ultralytics YOLO GitHub 仓库](https://github.com/ultralytics/ultralytics)发布,它继承了我们在速度、精度和易用性方面的传统。无论您是处理[目标检测](https://docs.ultralytics.com/tasks/detect/)、[实例分割](https://docs.ultralytics.com/tasks/segment/)、[姿态估计](https://docs.ultralytics.com/tasks/pose/)、[图像分类](https://docs.ultralytics.com/tasks/classify/)还是[旋转目标检测 (OBB)](https://docs.ultralytics.com/tasks/obb/),YOLO11 都能提供在各种应用中脱颖而出所需的性能和多功能性。 +我们隆重推出 **Ultralytics YOLO11** 🚀,这是我们最新的 SOTA 视觉模型!YOLO11 已在 [Ultralytics YOLO GitHub 仓库](https://github.com/ultralytics/ultralytics)发布,延续了速度、精度与易用性的卓越传统。无论您在进行[目标检测](https://docs.ultralytics.com/tasks/detect/)、[实例分割](https://docs.ultralytics.com/tasks/segment/)、[姿态估计](https://docs.ultralytics.com/tasks/pose/)、[图像分类](https://docs.ultralytics.com/tasks/classify/)还是[旋转目标检测 (OBB)](https://docs.ultralytics.com/tasks/obb/),YOLO11 都能为您的应用带来卓越性能和多功能性。 -立即开始,释放 YOLO11 的全部潜力!访问 [Ultralytics 文档](https://docs.ultralytics.com/)获取全面的指南和资源: +立即体验,释放 YOLO11 的全部潜能!访问 [Ultralytics 文档](https://docs.ultralytics.com/)获取全面指南和资源: -[![PyPI version](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![Downloads](https://static.pepy.tech/badge/ultralytics)](https://www.pepy.tech/projects/ultralytics) +[![PyPI version](https://badge.fury.io/py/ultralytics.svg)](https://badge.fury.io/py/ultralytics) [![Downloads](https://static.pepy.tech/badge/ultralytics)](https://pepy.tech/projects/ultralytics) ```bash # 安装 ultralytics 包 @@ -64,21 +66,21 @@ pip install ultralytics ## 📚 文档 -请参阅 [Ultralytics 文档](https://docs.ultralytics.com/models/yolov3/),了解使用 Ultralytics 框架进行训练、测试和部署的完整文档。虽然特定的 YOLOv3 文档可能有限,但通用原则仍然适用。请参阅下方为 YOLOv3 概念改编的快速入门示例。 +请参阅 [Ultralytics YOLOv3 文档](https://docs.ultralytics.com/models/yolov3/),了解如何使用 Ultralytics 框架进行训练、测试和部署。虽然 YOLOv3 专属文档有限,但通用 YOLO 原则同样适用。以下为 YOLOv3 快速入门示例。
安装 -克隆仓库并在 [**Python>=3.8.0**](https://www.python.org/) 环境中从 [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) 安装依赖项。确保您已安装 [**PyTorch>=1.8**](https://pytorch.org/get-started/locally/)。(注意:此仓库最初是 YOLOv5 的,依赖项应兼容,但建议针对 YOLOv3 进行专门测试)。 +克隆仓库并在 [**Python>=3.8.0**](https://www.python.org/) 环境下,从 [requirements.txt](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) 安装依赖。确保已安装 [**PyTorch>=1.8**](https://pytorch.org/get-started/locally/)。建议针对 YOLOv3 进行专门测试以确保兼容性。 ```bash # 克隆 YOLOv3 仓库 git clone https://github.com/ultralytics/yolov3 -# 导航到克隆的目录 +# 进入目录 cd yolov3 -# 安装所需的包 +# 安装依赖 pip install -r requirements.txt ``` @@ -87,24 +89,24 @@ pip install -r requirements.txt
使用 PyTorch Hub 进行推理 -通过 [PyTorch Hub](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/) 使用 YOLOv3 进行推理。[模型](https://github.com/ultralytics/yolov5/tree/master/models)如 `yolov3.pt`、`yolov3-spp.pt`、`yolov3-tiny.pt` 可以被加载。 +通过 [PyTorch Hub](https://docs.ultralytics.com/integrations/jupyterlab/) 可便捷加载 YOLOv3 进行推理。[模型权重](https://github.com/ultralytics/yolov5/tree/master/models)如 `yolov3.pt`、`yolov3-spp.pt`、`yolov3-tiny.pt` 均可直接使用。 ```python import torch -# 加载 YOLOv3 模型(例如,yolov3, yolov3-spp) -model = torch.hub.load("ultralytics/yolov3", "yolov3", pretrained=True) # 指定 'yolov3' 或其他变体 +# 加载 YOLOv3 模型(如 yolov3, yolov3-spp) +model = torch.hub.load("ultralytics/yolov3", "yolov3", pretrained=True) -# 定义输入图像源(URL、本地文件、PIL 图像、OpenCV 帧、numpy 数组或列表) -img = "https://ultralytics.com/images/zidane.jpg" # 示例图像 +# 输入图像(支持 URL、本地文件、PIL、OpenCV、numpy 数组或列表) +img = "https://ultralytics.com/images/zidane.jpg" -# 执行推理 +# 推理 results = model(img) -# 处理结果(选项:.print(), .show(), .save(), .crop(), .pandas()) -results.print() # 将结果打印到控制台 -results.show() # 在窗口中显示结果 -results.save() # 将结果保存到 runs/detect/exp +# 结果处理(.print(), .show(), .save(), .crop(), .pandas()) +results.print() +results.show() +results.save() ```
@@ -112,37 +114,37 @@ results.save() # 将结果保存到 runs/detect/exp
使用 detect.py 进行推理 -`detect.py` 脚本在各种来源上运行推理。使用 `--weights yolov3.pt` 或其他 YOLOv3 变体。它会自动下载模型并将结果保存到 `runs/detect`。 +`detect.py` 脚本支持多种输入源推理。使用 `--weights yolov3.pt` 或其他变体,模型会自动下载,结果保存至 `runs/detect`。 ```bash -# 使用 yolov3-tiny 和网络摄像头运行推理 +# 使用 yolov3-tiny 和摄像头推理 python detect.py --weights yolov3-tiny.pt --source 0 -# 使用 yolov3 在本地图像文件上运行推理 +# 使用 yolov3 推理本地图像 python detect.py --weights yolov3.pt --source img.jpg -# 使用 yolov3-spp 在本地视频文件上运行推理 +# 使用 yolov3-spp 推理本地视频 python detect.py --weights yolov3-spp.pt --source vid.mp4 -# 在屏幕截图上运行推理 +# 推理屏幕截图 python detect.py --weights yolov3.pt --source screen -# 在图像目录上运行推理 +# 推理图像目录 python detect.py --weights yolov3.pt --source path/to/images/ -# 在列出图像路径的文本文件上运行推理 +# 推理图像路径列表文件 python detect.py --weights yolov3.pt --source list.txt -# 在列出流 URL 的文本文件上运行推理 +# 推理流 URL 列表文件 python detect.py --weights yolov3.pt --source list.streams -# 使用 glob 模式对图像运行推理 +# 使用 glob 模式推理 python detect.py --weights yolov3.pt --source 'path/to/*.jpg' -# 在 YouTube 视频 URL 上运行推理 +# 推理 YouTube 视频 python detect.py --weights yolov3.pt --source 'https://youtu.be/LNwODJXcvt4' -# 在 RTSP、RTMP 或 HTTP 流上运行推理 +# 推理 RTSP、RTMP 或 HTTP 流 python detect.py --weights yolov3.pt --source 'rtsp://example.com/media.mp4' ``` @@ -151,16 +153,16 @@ python detect.py --weights yolov3.pt --source 'rtsp://example.com/media.mp4'
训练 -以下命令展示了如何在 [COCO 数据集](https://docs.ultralytics.com/datasets/detect/coco/)上训练 YOLOv3 模型。模型和数据集会自动下载。请使用您硬件允许的最大 `--batch-size`。 +以下命令展示如何在 [COCO 数据集](https://docs.ultralytics.com/datasets/detect/coco/)上训练 YOLOv3。模型和数据集会自动下载。请根据硬件选择合适的 `--batch-size`。 ```bash -# 在 COCO 上训练 YOLOv3-tiny 300 个周期(示例设置) +# 在 COCO 上训练 YOLOv3-tiny 300 轮 python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3-tiny.yaml --batch-size 64 -# 在 COCO 上训练 YOLOv3 300 个周期(示例设置) +# 在 COCO 上训练 YOLOv3 300 轮 python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3.yaml --batch-size 32 -# 在 COCO 上训练 YOLOv3-SPP 300 个周期(示例设置) +# 在 COCO 上训练 YOLOv3-SPP 300 轮 python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3-spp.yaml --batch-size 16 ``` @@ -169,30 +171,30 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3-spp.yaml
教程 -注意:这些教程主要使用 YOLOv5 示例,但其原理通常适用于 Ultralytics 框架内的 YOLOv3。 - -- **[训练自定义数据](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/)** 🚀 **推荐**:学习如何在您自己的数据集上训练模型。 -- **[获得最佳训练结果的技巧](https://docs.ultralytics.com/guides/model-training-tips/)** ☘️:利用专家技巧提高模型性能。 -- **[多 GPU 训练](https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training/)**:使用多个 GPU 加速训练。 -- **[PyTorch Hub 集成](https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading/)** 🌟 **新增**:使用 PyTorch Hub 轻松加载模型。 -- **[模型导出 (TFLite, ONNX, CoreML, TensorRT)](https://docs.ultralytics.com/yolov5/tutorials/model_export/)** 🚀:将您的模型转换为各种部署格式。 -- **[NVIDIA Jetson 部署](https://docs.ultralytics.com/yolov5/tutorials/running_on_jetson_nano/)** 🌟 **新增**:在 NVIDIA Jetson 设备上部署模型。 -- **[测试时增强 (TTA)](https://docs.ultralytics.com/yolov5/tutorials/test_time_augmentation/)**:使用 TTA 提高预测准确性。 -- **[模型集成](https://docs.ultralytics.com/yolov5/tutorials/model_ensembling/)**:组合多个模型以获得更好的性能。 -- **[模型剪枝/稀疏化](https://docs.ultralytics.com/yolov5/tutorials/model_pruning_and_sparsity/)**:优化模型的大小和速度。 -- **[超参数进化](https://docs.ultralytics.com/yolov5/tutorials/hyperparameter_evolution/)**:自动找到最佳训练超参数。 -- **[使用冻结层的迁移学习](https://docs.ultralytics.com/yolov5/tutorials/transfer_learning_with_frozen_layers/)**:高效地将预训练模型应用于新任务。 -- **[架构总结](https://docs.ultralytics.com/yolov5/tutorials/architecture_description/)** 🌟 **新增**:理解模型架构(侧重于 YOLOv3 原理)。 -- **[Ultralytics HUB 训练](https://www.ultralytics.com/hub)** 🚀 **推荐**:使用 Ultralytics HUB 训练和部署 YOLO 模型。 -- **[ClearML 日志记录](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration/)**:与 ClearML 集成以进行实验跟踪。 -- **[Neural Magic DeepSparse 集成](https://docs.ultralytics.com/yolov5/tutorials/neural_magic_pruning_quantization/)**:使用 DeepSparse 加速推理。 -- **[Comet 日志记录](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration/)** 🌟 **新增**:使用 Comet ML 记录实验。 +注意:这些教程多以 YOLOv5 为例,但原理同样适用于 YOLOv3。 + +- **[训练自定义数据](https://docs.ultralytics.com/guides/data-collection-and-annotation/)** 🚀 **推荐**:学习如何在自有数据集上训练模型。 +- **[最佳训练技巧](https://docs.ultralytics.com/guides/model-training-tips/)** ☘️:提升模型性能的专家建议。 +- **[多 GPU 训练](https://docs.ultralytics.com/guides/model-training-tips/)**:加速大规模训练。 +- **[PyTorch Hub 集成](https://docs.ultralytics.com/integrations/jupyterlab/)** 🌟 **新增**:一键加载模型。 +- **[模型导出 (TFLite, ONNX, CoreML, TensorRT)](https://docs.ultralytics.com/modes/export/)** 🚀:多格式部署支持。 +- **[NVIDIA Jetson 部署](https://docs.ultralytics.com/guides/nvidia-jetson/)** 🌟 **新增**:边缘设备推理。 +- **[测试时增强 (TTA)](https://docs.ultralytics.com/guides/model-evaluation-insights/)**:提升预测准确率。 +- **[模型集成](https://docs.ultralytics.com/guides/model-deployment-options/)**:多模型融合提升表现。 +- **[模型剪枝/稀疏化](https://docs.ultralytics.com/guides/model-deployment-practices/)**:优化模型体积与速度。 +- **[超参数进化](https://docs.ultralytics.com/guides/hyperparameter-tuning/)**:自动优化训练参数。 +- **[迁移学习与冻结层](https://docs.ultralytics.com/guides/model-training-tips/)**:高效迁移预训练模型。 +- **[架构总结](https://docs.ultralytics.com/models/yolov3/)** 🌟 **新增**:理解 YOLOv3 设计原理。 +- **[Ultralytics HUB 训练](https://www.ultralytics.com/hub)** 🚀 **推荐**:无代码训练与部署。 +- **[ClearML 日志集成](https://docs.ultralytics.com/integrations/clearml/)**:实验可追溯。 +- **[Neural Magic DeepSparse 集成](https://docs.ultralytics.com/integrations/neural-magic/)**:极致推理加速。 +- **[Comet 日志集成](https://docs.ultralytics.com/integrations/comet/)** 🌟 **新增**:实验可视化与管理。
## 🧩 集成 -我们与领先 AI 平台的关键集成扩展了 Ultralytics 产品的功能,增强了诸如数据集标注、训练、可视化和模型管理等任务。了解 Ultralytics 如何与 [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/)、[Comet ML](https://docs.ultralytics.com/integrations/comet/)、[Roboflow](https://docs.ultralytics.com/integrations/roboflow/) 和 [Intel OpenVINO](https://docs.ultralytics.com/integrations/openvino/) 等合作伙伴协作,优化您的 AI 工作流程。在 [Ultralytics 集成](https://docs.ultralytics.com/integrations/) 探索更多信息。 +Ultralytics 与领先 AI 平台深度集成,扩展了数据集标注、训练、可视化和模型管理等能力。了解如何通过 [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/)、[Comet ML](https://docs.ultralytics.com/integrations/comet/)、[Roboflow](https://docs.ultralytics.com/integrations/roboflow/) 和 [Intel OpenVINO](https://docs.ultralytics.com/integrations/openvino/) 等合作伙伴优化您的 AI 工作流。探索 [Ultralytics 集成](https://docs.ultralytics.com/integrations/) 了解更多。 Ultralytics active learning integrations @@ -214,31 +216,31 @@ python train.py --data coco.yaml --epochs 300 --weights '' --cfg yolov3-spp.yaml Neural Magic logo
-| Ultralytics HUB 🌟 | Weights & Biases | Comet | Neural Magic | -| :------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------: | -| 简化 YOLO 工作流程:使用 [Ultralytics HUB](https://hub.ultralytics.com) 轻松标注、训练和部署。立即试用! | 使用 [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/) 跟踪实验、超参数和结果。 | 永久免费,[Comet ML](https://docs.ultralytics.com/integrations/comet/) 让您保存 YOLO 模型、恢复训练并交互式地可视化预测。 | 使用 [Neural Magic DeepSparse](https://docs.ultralytics.com/integrations/neural-magic/) 将 YOLO 推理速度提高多达 6 倍。 | +| Ultralytics HUB 🌟 | Weights & Biases | Comet | Neural Magic | +| :-----------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------: | +| 简化 YOLO 工作流:使用 [Ultralytics HUB](https://hub.ultralytics.com/) 轻松标注、训练和部署。立即体验! | 使用 [Weights & Biases](https://docs.ultralytics.com/integrations/weights-biases/) 跟踪实验与超参数。 | [Comet ML](https://docs.ultralytics.com/integrations/comet/) 永久免费,支持模型保存、训练恢复与预测可视化。 | [Neural Magic DeepSparse](https://docs.ultralytics.com/integrations/neural-magic/) 可将 YOLO 推理速度提升至 6 倍。 | ## ⭐ Ultralytics HUB -通过 [Ultralytics HUB](https://www.ultralytics.com/hub) ⭐ 体验无缝的 AI 开发,这是构建、训练和部署计算机视觉模型的终极平台。无需编写任何代码,即可可视化数据集、训练 YOLOv3、YOLOv5 和 YOLOv8 🚀 模型,并将它们部署到实际应用中。使用我们尖端的工具和用户友好的 [Ultralytics App](https://www.ultralytics.com/app-install),将图像转化为可操作的见解。立即开始您的**免费**旅程! +通过 [Ultralytics HUB](https://www.ultralytics.com/hub) ⭐ 体验无缝 AI 开发,轻松构建、训练和部署计算机视觉模型。无需代码,即可可视化数据集、训练 YOLOv3、YOLOv5 和 YOLOv8 🚀,并将模型部署到实际场景。借助 [Ultralytics App](https://www.ultralytics.com/app-install) 和创新工具,将图像转化为可操作见解。立即开启您的**免费** AI 之旅! Ultralytics HUB Platform Screenshot ## 🤔 为何选择 YOLOv3? -YOLOv3 在发布时代表了实时目标检测领域的一大进步。其主要优势包括: +YOLOv3 发布时推动了实时目标检测的进步。其核心优势包括: -- **提高准确性:** 与 YOLOv2 相比,对小目标的检测效果更好。 -- **多尺度预测:** 在三个不同尺度上检测目标,提高了对各种尺寸目标的性能。 -- **类别预测:** 使用逻辑分类器预测目标类别,而不是 softmax,允许进行多标签分类。 -- **特征提取器:** 与 YOLOv2 中使用的 Darknet-19 相比,使用了更深的网络(Darknet-53)。 +- **更高准确率:** 对小目标检测表现优异。 +- **多尺度预测:** 支持三种不同尺度,提升多尺寸目标检测能力。 +- **多标签分类:** 采用逻辑分类器而非 softmax,支持多标签输出。 +- **强大特征提取器:** 使用更深的 Darknet-53 网络替代 YOLOv2 的 Darknet-19。 -虽然像 YOLOv5 和 YOLO11 这样的更新模型提供了进一步的改进,但 YOLOv3 仍然是一个坚实且被广泛理解的基准,由 Ultralytics 在 PyTorch 中高效实现。 +尽管后续如 YOLOv5 和 YOLO11 等模型带来更多创新,YOLOv3 依然是坚实且广泛理解的基准,Ultralytics 在 PyTorch 中实现高效。 ## ☁️ 环境 -使用我们预配置的环境快速开始。点击下面的图标查看设置详情。 +使用预配置环境快速上手。点击下方图标了解各平台设置详情。 ## 🤝 贡献 -我们欢迎您的贡献!让 YOLO 模型易于使用且高效是社区共同努力的目标。请参阅我们的[贡献指南](https://docs.ultralytics.com/help/contributing/)开始。通过 [Ultralytics 调查](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey)分享您的反馈。感谢所有为使 Ultralytics YOLO 变得更好而做出贡献的人! +欢迎您的贡献!Ultralytics 致力于让 YOLO 模型更易用、更高效。请参阅[贡献指南](https://docs.ultralytics.com/help/contributing/)开始参与。通过 [Ultralytics 调查](https://www.ultralytics.com/survey?utm_source=github&utm_medium=social&utm_campaign=Survey) 分享您的反馈。感谢所有为 Ultralytics YOLO 发展做出贡献的朋友! [![Ultralytics open-source contributors](https://raw.githubusercontent.com/ultralytics/assets/main/im/image-contributors.png)](https://github.com/ultralytics/yolov5/graphs/contributors) @@ -270,12 +272,12 @@ YOLOv3 在发布时代表了实时目标检测领域的一大进步。其主要 Ultralytics 提供两种许可选项以满足不同需求: -- **AGPL-3.0 许可证**:一种经 [OSI 批准](https://opensource.org/license/agpl-v3)的开源许可证,非常适合学术研究、个人项目和测试。它促进开放合作和知识共享。详情请参阅 [LICENSE](https://github.com/ultralytics/yolov5/blob/master/LICENSE) 文件。 -- **企业许可证**:专为商业应用量身定制,此许可证允许将 Ultralytics 软件和 AI 模型无缝集成到商业产品和服务中,绕过 AGPL-3.0 的开源要求。对于商业用途,请通过 [Ultralytics 许可](https://www.ultralytics.com/license)与我们联系。 +- **AGPL-3.0 许可证**:经 [OSI 批准](https://opensource.org/license/agpl-v3)的开源协议,适合学术、个人项目和测试,促进开放合作。详情见 [LICENSE](https://github.com/ultralytics/yolov5/blob/master/LICENSE)。 +- **企业许可证**:专为商业应用设计,允许将 Ultralytics 软件和模型集成到商业产品和服务,无需遵守 AGPL-3.0 的开源要求。请通过 [Ultralytics 许可](https://www.ultralytics.com/license) 联系我们。 ## 📧 联系 -有关 Ultralytics YOLO 实现的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov5/issues)。有关一般问题、讨论和社区支持,请加入我们的 [Discord 服务器](https://discord.com/invite/ultralytics)! +如需报告 Ultralytics YOLO 实现的 bug 或功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/yolov5/issues)。如有一般问题、讨论或社区支持,欢迎加入 [Discord 服务器](https://discord.com/invite/ultralytics)!
diff --git a/hubconf.py b/hubconf.py index 16dcb68477..53fe1cfcbb 100644 --- a/hubconf.py +++ b/hubconf.py @@ -180,7 +180,7 @@ def yolov5s(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True) ``` - For more information, refer to [PyTorch Hub models](https://pytorch.org/hub/ultralytics_yolov5). + For more information, refer to [PyTorch Hub models](https://pytorch.org/hub/ultralytics_yolov5/). """ return _create("yolov5s", pretrained, channels, classes, autoshape, _verbose, device) @@ -236,7 +236,7 @@ def yolov5l(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr model = torch.hub.load('ultralytics/yolov5', 'yolov5l', pretrained=True) ``` - For more information, refer to [PyTorch Hub models](https://pytorch.org/hub/ultralytics_yolov5). + For more information, refer to [PyTorch Hub models](https://pytorch.org/hub/ultralytics_yolov5/). """ return _create("yolov5l", pretrained, channels, classes, autoshape, _verbose, device) @@ -270,7 +270,7 @@ def yolov5x(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr model = torch.hub.load('ultralytics/yolov5', 'yolov5x', device='cuda:0') ``` - For more details, refer to [PyTorch Hub models](https://pytorch.org/hub/ultralytics_yolov5). + For more details, refer to [PyTorch Hub models](https://pytorch.org/hub/ultralytics_yolov5/). """ return _create("yolov5x", pretrained, channels, classes, autoshape, _verbose, device) diff --git a/train.py b/train.py index 878f1e614f..ba4784ee90 100644 --- a/train.py +++ b/train.py @@ -863,7 +863,7 @@ def run(**kwargs): Notes: - Ensure the dataset YAML file and initial weights are accessible. - Refer to the [Ultralytics YOLOv5 repository](https://github.com/ultralytics/yolov5) for model and data configurations. - - Use the [Training Tutorial](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data) for custom dataset training. + - Use the [Training Tutorial](https://docs.ultralytics.com/yolov5/tutorials/train_custom_data/) for custom dataset training. """ opt = parse_opt(True) for k, v in kwargs.items(): diff --git a/utils/loggers/clearml/README.md b/utils/loggers/clearml/README.md index 55e26b2660..56dfcf143b 100644 --- a/utils/loggers/clearml/README.md +++ b/utils/loggers/clearml/README.md @@ -2,57 +2,60 @@ # ClearML Integration for Ultralytics YOLO -This guide explains how to integrate [ClearML](https://clear.ml/), an open-source MLOps platform, with your Ultralytics YOLOv3 projects. ClearML helps streamline your machine learning workflow from experiment tracking to deployment. +This guide details how to integrate [ClearML](https://clear.ml/), a leading open-source MLOps platform, with your Ultralytics YOLO projects. ClearML streamlines the entire machine learning lifecycle—from experiment tracking to deployment—making it easier to manage and scale your computer vision workflows. Clear|MLClear|ML ## ✨ About ClearML -[ClearML](https://clear.ml/) is an [open-source](https://github.com/clearml/clearml) suite of tools designed to manage, automate, and orchestrate machine learning workflows, significantly saving development time ⏱️. Integrating ClearML with Ultralytics YOLOv3 provides several benefits: +[ClearML](https://clear.ml/) is an [open-source MLOps suite](https://github.com/clearml/clearml) that enables you to manage, automate, and orchestrate machine learning workflows efficiently. Integrating ClearML with Ultralytics YOLO unlocks several advantages: -- **Experiment Management**: Automatically track every YOLOv3 training run, including code versions, configurations, metrics, and outputs in a centralized dashboard. Learn more about [Ultralytics experiment tracking integrations](https://docs.ultralytics.com/integrations/). -- **Data Versioning**: Use the ClearML Data Versioning Tool to manage and easily access your custom training datasets. See how Ultralytics handles [datasets](https://docs.ultralytics.com/datasets/). -- **Remote Execution**: Remotely train and monitor your YOLOv3 models using ClearML Agent on different machines or cloud instances. Explore [model deployment options](https://docs.ultralytics.com/guides/model-deployment-options/). -- **Hyperparameter Optimization**: Leverage ClearML Hyperparameter Optimization to find the best model configurations and improve [Mean Average Precision (mAP)](https://www.ultralytics.com/glossary/mean-average-precision-map). Check out the Ultralytics [Hyperparameter Tuning guide](https://docs.ultralytics.com/guides/hyperparameter-tuning/). -- **Model Deployment**: Turn your trained YOLOv3 models into scalable APIs using ClearML Serving with just a few commands. +- **Experiment Management**: Automatically track every YOLO training run, including code versions, configurations, metrics, and outputs in a centralized dashboard. Explore more about [Ultralytics experiment tracking integrations](https://docs.ultralytics.com/integrations/). +- **Data Versioning**: Manage and access your custom training datasets with ClearML Data Versioning. See how [Ultralytics datasets](https://docs.ultralytics.com/datasets/) are structured. +- **Remote Execution**: Train and monitor your YOLO models remotely using ClearML Agent on any machine or cloud instance. Learn about [model deployment options](https://docs.ultralytics.com/guides/model-deployment-options/). +- **Hyperparameter Optimization**: Use ClearML's HPO tools to optimize your model configurations and improve [mean average precision (mAP)](https://www.ultralytics.com/glossary/mean-average-precision-map). Review the [Ultralytics Hyperparameter Tuning guide](https://docs.ultralytics.com/guides/hyperparameter-tuning/). +- **Model Deployment**: Deploy trained YOLO models as scalable APIs with ClearML Serving in just a few steps. -You can choose to use any combination of these tools to fit your project needs. +You can leverage any combination of these tools to fit your project requirements. ![ClearML scalars dashboard](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/experiment_manager_with_compare.gif) -## 🦾 Setting Things Up +## 🦾 Setting Up ClearML -To start using ClearML, you need to connect the SDK to a ClearML Server instance. You have two main options: +To use ClearML, connect the SDK to a ClearML Server instance. You have two main options: -1. **ClearML Hosted Service**: Sign up for a free account at the [ClearML Hosted Service](https://app.clear.ml/). -2. **Self-Hosted Server**: Set up your own [ClearML Server](https://clear.ml/docs/latest/docs/deploying_clearml/clearml_server). The server is also open-source, providing flexibility for data privacy concerns. +1. **ClearML Hosted Service**: Register for a free account at the [ClearML Hosted Service](https://app.clear.ml/). +2. **Self-Hosted Server**: Deploy your own [ClearML Server](https://clear.ml/docs/latest/docs/deploying_clearml/clearml_server) for full control and data privacy. Follow these steps to get started: -1. Install the `clearml` Python package using pip: +1. Install the `clearml` Python package: - ```bash - pip install clearml - ``` + ```bash + pip install clearml + ``` -2. Connect the ClearML SDK to your server. Generate credentials through the ClearML Web UI (Settings -> Workspace -> Create new credentials) and run the following command in your terminal, following the prompts: - ```bash - clearml-init - ``` +2. Connect the ClearML SDK to your server. Generate credentials in the ClearML Web UI (Settings → Workspace → Create new credentials) and run: -Once configured, ClearML is ready to integrate with your YOLOv3 workflows! 😎 + ```bash + clearml-init + ``` -## 🚀 Training YOLOv3 With ClearML + Follow the prompts to complete setup. -Enabling ClearML experiment tracking for YOLOv3 is straightforward. Simply ensure the `clearml` package is installed: +Once configured, ClearML is ready to integrate with your YOLO workflows! 😎 + +## 🚀 Training YOLO With ClearML + +Enabling ClearML experiment tracking for YOLO is simple. Ensure the `clearml` package is installed: ```bash pip install clearml > =1.2.0 ``` -With the package installed, ClearML automatically captures details for every YOLOv3 [training run](https://docs.ultralytics.com/modes/train/). +With ClearML installed, every YOLO [training run](https://docs.ultralytics.com/modes/train/) is automatically logged. -By default, experiments are logged under the `YOLOv3` project with the task name `Training`. You can customize these using the `--project` and `--name` arguments in your training command. Note that ClearML uses `/` as a delimiter for subprojects. +By default, experiments are organized under the `YOLO` project with the task name `Training`. You can customize these using the `--project` and `--name` arguments in your training command. ClearML uses `/` as a delimiter for subprojects. **Example Training Command:** @@ -70,27 +73,27 @@ python train.py --project my_yolo_project --name experiment_001 --img 640 --batc ClearML will automatically capture: -- Git repository details (URL, commit ID, entry point) and local code changes. -- Installed Python packages and versions. -- [Hyperparameters](https://www.ultralytics.com/glossary/hyperparameter-tuning) and script arguments. -- [Model checkpoints](https://www.ultralytics.com/glossary/model-weights) (use `--save-period n` to save every `n` epochs). -- Console output (stdout and stderr). -- Performance [metrics/scalars](https://docs.ultralytics.com/guides/yolo-performance-metrics/) like mAP_0.5, mAP_0.5:0.95, precision, recall, losses, and learning rates. -- Machine details, runtime, and creation date. -- Generated plots like label correlograms and [confusion matrices](https://www.ultralytics.com/glossary/confusion-matrix). -- Debug samples: images with bounding boxes, mosaic visualizations, and validation images per epoch. +- Git repository details (URL, commit ID, entry point) and local code changes +- Installed Python packages and versions +- [Hyperparameters](https://www.ultralytics.com/glossary/hyperparameter-tuning) and script arguments +- [Model checkpoints](https://www.ultralytics.com/glossary/model-weights) (use `--save-period n` to save every `n` epochs) +- Console output (stdout and stderr) +- Performance [metrics and scalars](https://docs.ultralytics.com/guides/yolo-performance-metrics/) such as mAP0.5, mAP0.5:0.95, precision, recall, losses, and learning rates +- Machine details, runtime, and creation date +- Generated plots like label correlograms and [confusion matrices](https://www.ultralytics.com/glossary/confusion-matrix) +- Debug samples: images with bounding boxes, mosaic visualizations, and validation images per epoch This comprehensive tracking allows you to visualize progress in the ClearML UI, compare experiments, and easily identify the best-performing models by sorting based on metrics like [mAP](https://www.ultralytics.com/glossary/mean-average-precision-map). ## 🔗 Dataset Version Management -Versioning datasets is crucial for reproducibility and collaboration in [machine learning](https://www.ultralytics.com/glossary/machine-learning-ml) projects. ClearML Data helps manage datasets efficiently. YOLOv3 supports using ClearML dataset IDs directly in the training command. +Versioning datasets is essential for reproducibility and collaboration in [machine learning](https://www.ultralytics.com/glossary/machine-learning-ml) projects. ClearML Data helps manage datasets efficiently. YOLO supports using ClearML dataset IDs directly in the training command. ![ClearML Dataset Interface](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/clearml_data.gif) ### Prepare Your Dataset -YOLOv3 uses YAML files to define dataset configurations. Datasets are typically expected in a specific structure, often downloaded to a `../datasets` directory relative to your repository root. For example, the [COCO128 dataset](https://docs.ultralytics.com/datasets/detect/coco128/) structure looks like this: +YOLO uses YAML files to define dataset configurations. Datasets are typically stored in a `../datasets` directory relative to your repository root. For example, the [COCO128 dataset](https://docs.ultralytics.com/datasets/detect/coco128/) structure: ``` ../ @@ -106,27 +109,27 @@ YOLOv3 uses YAML files to define dataset configurations. Datasets are typically Ensure your custom dataset follows a similar structure. -⚠️ **Important**: Copy the corresponding dataset `.yaml` configuration file into the **root directory** of your dataset folder (e.g., `datasets/coco128/coco128.yaml`). This YAML file must contain keys like `path`, `train`, `val`, `test`, `nc` (number of classes), and `names` (class names list) for ClearML integration to work correctly. +⚠️ **Important**: Copy the dataset `.yaml` configuration file into the **root directory** of your dataset folder (e.g., `datasets/coco128/coco128.yaml`). This YAML file must include keys like `path`, `train`, `val`, `test`, `nc` (number of classes), and `names` (class names list) for ClearML integration to function correctly. ### Upload Your Dataset -Navigate to your dataset's root folder in the terminal and use the `clearml-data` CLI tool to upload and version it: +Navigate to your dataset's root folder and use the `clearml-data` CLI tool to upload and version it: ```bash # Navigate to the dataset directory cd ../datasets/coco128 # Sync the dataset with ClearML (creates a versioned dataset) -clearml-data sync --project "YOLOv3 Datasets" --name coco128 --folder . +clearml-data sync --project "YOLO Datasets" --name coco128 --folder . ``` -This command creates a new ClearML dataset (or a new version if it exists) named `coco128` within the `YOLOv3 Datasets` project. +This command creates a new ClearML dataset (or a new version if it exists) named `coco128` within the `YOLO Datasets` project. -Alternatively, you can use granular commands: +Alternatively, use granular commands: ```bash # Create a new dataset task -clearml-data create --project "YOLOv3 Datasets" --name coco128 +clearml-data create --project "YOLO Datasets" --name coco128 # Add files to the dataset (use '.' for current folder) clearml-data add --files . @@ -137,7 +140,7 @@ clearml-data close ### Run Training Using a ClearML Dataset -Once your dataset is versioned in ClearML, you can reference it directly in your YOLOv3 training command using its unique ID. ClearML will automatically download the dataset if it's not present locally. +Once your dataset is versioned in ClearML, you can reference it directly in your YOLO training command using its unique ID. ClearML will automatically download the dataset if it's not present locally. ```bash # Replace with the actual ID from ClearML @@ -148,17 +151,18 @@ The dataset ID used will be logged as a parameter in your ClearML experiment, en ## 👀 Hyperparameter Optimization -ClearML's experiment tracking captures all necessary information (code, environment, parameters) to reproduce a run. This reproducibility is the foundation for effective [Hyperparameter Optimization (HPO)](https://docs.ultralytics.com/guides/hyperparameter-tuning/). ClearML allows you to clone experiments, modify hyperparameters, and automatically rerun them. +ClearML's experiment tracking captures all the information needed to reproduce a run, forming the foundation for effective [hyperparameter optimization (HPO)](https://docs.ultralytics.com/guides/hyperparameter-tuning/). ClearML allows you to clone experiments, modify hyperparameters, and rerun them automatically. To run HPO locally, Ultralytics provides a sample script. You'll need the ID of a previously executed training task (the "template task") to use as a base. -1. Locate the HPO script at `utils/loggers/clearml/hpo.py`. -2. Edit the script to include the `template task` ID. -3. Optionally, install [Optuna](https://optuna.org/) (`pip install optuna`) for advanced optimization strategies, or use the default `RandomSearch`. -4. Run the script: - ```bash - python utils/loggers/clearml/hpo.py - ``` +1. Locate the HPO script at `utils/loggers/clearml/hpo.py`. +2. Edit the script to include the `template task` ID. +3. Optionally, install [Optuna](https://optuna.org/) (`pip install optuna`) for advanced optimization strategies, or use the default `RandomSearch`. +4. Run the script: + + ```bash + python utils/loggers/clearml/hpo.py + ``` This script clones the template task, applies new hyperparameters suggested by the optimizer, and executes the modified task locally (`task.execute_locally()`). To run HPO remotely, change this to `task.execute()` to enqueue the tasks for a ClearML Agent. @@ -166,14 +170,14 @@ This script clones the template task, applies new hyperparameters suggested by t ## 🤯 Remote Execution (Advanced) -ClearML Agent enables running experiments on remote machines (e.g., powerful on-premises servers or cloud GPUs). The agent fetches tasks from a queue, replicates the original environment (code, packages, uncommitted changes), executes the task, and reports results back to the ClearML Server. +ClearML Agent enables running experiments on remote machines, such as on-premises servers or cloud GPUs. The agent fetches tasks from a queue, replicates the original environment (code, packages, uncommitted changes), executes the task, and reports results back to the ClearML Server. -- **Learn More**: Watch the [ClearML Agent Introduction](https://www.youtube.com/watch?v=MX3BrXnaULs) or read the [documentation](https://clear.ml/docs/latest/docs/clearml_agent). +- **Learn More**: Watch the [ClearML Agent Introduction](https://www.youtube.com/watch?v=MX3BrXnaULs) or read the [ClearML Agent documentation](https://clear.ml/docs/latest/docs/clearml_agent). -Turn any machine into a ClearML Agent by running the following command: +Turn any machine into a ClearML Agent by running: ```bash -# Replace with the name(s) of your queue(s) +# Replace with your queue(s) name(s) clearml-agent daemon --queue < queues_to_listen_to > [--docker] # Use --docker to run in a Docker container ``` @@ -181,15 +185,15 @@ clearml-agent daemon --queue < queues_to_listen_to > [--docker] # Use --docker t You can manage remote execution tasks through the ClearML Web UI: -1. **Clone**: Right-click an existing experiment to clone it. -2. **Edit**: Modify hyperparameters or other configurations in the cloned task. -3. **Enqueue**: Right-click the modified task and select "Enqueue" to assign it to a specific queue monitored by your agents. +1. **Clone**: Right-click an existing experiment to clone it. +2. **Edit**: Modify hyperparameters or other configurations in the cloned task. +3. **Enqueue**: Right-click the modified task and select "Enqueue" to assign it to a specific queue monitored by your agents. ![Enqueue a task from the ClearML UI](https://raw.githubusercontent.com/thepycoder/clearml_screenshots/main/enqueue.gif) ### Executing a Task Remotely via Code -Alternatively, you can modify your training script to automatically enqueue the task for remote execution. Add `task.execute_remotely()` after the ClearML logger is initialized in `train.py`: +Alternatively, modify your training script to automatically enqueue the task for remote execution. Add `task.execute_remotely()` after the ClearML logger is initialized in `train.py`: ```python # ... inside train.py ... @@ -208,11 +212,11 @@ if RANK in {-1, 0}: # ... rest of the script ... ``` -When you run the modified `train.py`, the script execution will pause, package the code and environment, and send the task to the specified queue (`my_default_queue` in this example). A ClearML Agent listening to that queue will then pick it up and run it. +When you run the modified `train.py`, the script execution will pause, package the code and environment, and send the task to the specified queue (`my_default_queue`). A ClearML Agent listening to that queue will then pick it up and run it. ### Autoscaling Agents -ClearML also provides **Autoscalers** that automatically provision and manage cloud instances (AWS, GCP, Azure) as ClearML Agents based on queue load. They spin up machines when tasks are pending and shut them down when idle, optimizing resource usage and cost. +ClearML also provides **Autoscalers** that automatically provision and manage cloud instances (AWS, GCP, Azure) as ClearML Agents based on queue load. Machines spin up when tasks are pending and shut down when idle, optimizing resource usage and cost. Learn how to set up autoscalers: diff --git a/utils/loggers/comet/README.md b/utils/loggers/comet/README.md index c702cd1d38..7df41899a3 100644 --- a/utils/loggers/comet/README.md +++ b/utils/loggers/comet/README.md @@ -4,19 +4,24 @@ # YOLOv3 Integration with Comet -This guide details how to effectively use YOLOv3 with [Comet](https://bit.ly/yolov5-readme-comet2) for experiment tracking and model optimization. +This guide explains how to seamlessly integrate YOLOv3 with [Comet experiment tracking](https://www.comet.com/site/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) for enhanced experiment management, model optimization, and collaborative workflows. ## ℹ️ About Comet -[Comet](https://www.comet.com/site/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) provides tools designed to help data scientists, engineers, and team leaders accelerate and optimize machine learning and deep learning models. +[Comet](https://www.comet.com/site/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) is a leading platform for tracking, visualizing, and optimizing machine learning and deep learning experiments. It empowers data scientists, engineers, and teams to: -With Comet, you can track and visualize model metrics in real-time, save hyperparameters, datasets, and model checkpoints, and visualize model predictions using [Comet Custom Panels](https://www.comet.com/docs/v2/guides/comet-dashboard/code-panels/about-panels/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). Comet ensures your work is never lost and simplifies sharing results and collaboration across teams of any size. +- Monitor model metrics in real time +- Save and version hyperparameters, datasets, and model checkpoints +- Visualize predictions using [Comet Custom Panels](https://www.comet.com/docs/v2/guides/comet-dashboard/code-panels/about-panels/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) +- Collaborate and share results efficiently + +Comet ensures your work is always accessible and simplifies team collaboration. ## 🚀 Getting Started ### Install Comet -Install the necessary package using pip: +Install Comet using pip: ```shell pip install comet_ml @@ -24,84 +29,86 @@ pip install comet_ml ### Configure Comet Credentials -You can configure Comet credentials for YOLOv3 in two ways: +You can set up Comet credentials for YOLOv3 in two ways: -1. **Environment Variables**: Set your credentials directly in your environment. +1. **Environment Variables** + Set your credentials in your environment: - ```shell - export COMET_API_KEY= - export COMET_PROJECT_NAME= # Defaults to 'yolov3' if not set - ``` + ```shell + export COMET_API_KEY=YOUR_COMET_API_KEY + export COMET_PROJECT_NAME=YOUR_COMET_PROJECT_NAME # Defaults to 'yolov3' if not set + ``` -2. **Comet Configuration File**: Create a `.comet.config` file in your working directory and add your credentials there. +2. **Comet Configuration File** + Create a `.comet.config` file in your working directory: - ``` - [comet] - api_key= - project_name= # Defaults to 'yolov3' if not set - ``` + ``` + [comet] + api_key=YOUR_API_KEY + project_name=YOUR_PROJECT_NAME # Defaults to 'yolov3' if not set + ``` ### Run the Training Script -Execute the [Ultralytics training script](https://docs.ultralytics.com/modes/train/) as you normally would. Comet automatically integrates with YOLOv3. +Run the [Ultralytics training script](https://docs.ultralytics.com/modes/train/) as usual. Comet will automatically integrate with YOLOv3. ```shell # Train YOLOv3 on COCO128 for 5 epochs python train.py --img 640 --batch 16 --epochs 5 --data coco128.yaml --weights yolov3.pt ``` -That's it! Comet will automatically log your hyperparameters, command-line arguments, training metrics, and validation metrics. You can visualize and analyze your runs in the Comet UI. For more details on metrics like mAP and Recall, see the [YOLO Performance Metrics guide](https://docs.ultralytics.com/guides/yolo-performance-metrics/). +Comet will automatically log your hyperparameters, command-line arguments, training metrics, and validation metrics. You can analyze your runs in the Comet UI. For more on metrics like mAP and Recall, see the [YOLO Performance Metrics guide](https://docs.ultralytics.com/guides/yolo-performance-metrics/). Comet UI showing YOLO training run ## ✨ Try an Example! -Explore an example of a [completed run in the Comet UI](https://www.comet.com/examples/comet-example-yolov5/a0e29e0e9b984e4a822db2a62d0cb357?experiment-tab=chart&showOutliers=true&smoothing=0&transformY=smoothing&xAxis=step&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). +Explore a [completed YOLO run in the Comet UI](https://www.comet.com/examples/comet-example-yolov5/a0e29e0e9b984e4a822db2a62d0cb357?experiment-tab=chart&showOutliers=true&smoothing=0&transformY=smoothing&xAxis=step&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). -Or, try it yourself using this Colab Notebook: +Or, try it yourself in Colab: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/comet-ml/comet-examples/blob/master/integrations/model-training/yolov5/notebooks/Comet_and_YOLOv5.ipynb) ## 📊 Automatic Logging -By default, Comet automatically logs the following: +By default, Comet logs the following during YOLOv3 training: ### Metrics -- Box Loss, Object Loss, Classification Loss (Training and Validation) -- mAP_0.5, mAP_0.5:0.95 (Validation) -- Precision and Recall (Validation) +- Box Loss, Object Loss, Classification Loss (training and validation) +- mAP0.5, mAP0.5:0.95 (validation) +- Precision and Recall (validation) ### Parameters -- Model Hyperparameters -- All command-line options passed during training +- All model hyperparameters +- All command-line options used during training ### Visualizations -- Confusion Matrix of model predictions on validation data -- Plots for PR and F1 curves across all classes -- Correlogram of Class Labels +- Confusion matrix of model predictions on validation data +- PR and F1 curves for all classes +- Correlogram of class labels ## ⚙️ Configure Comet Logging -You can configure Comet to log additional data using command-line flags or environment variables. +You can customize Comet logging using environment variables: ```shell -# Environment Variables for Comet Configuration -export COMET_MODE=online # 'online' or 'offline'. Defaults to online. -export COMET_MODEL_NAME= # Name for the saved model. Defaults to yolov3. -export COMET_LOG_CONFUSION_MATRIX=false # Disable logging Confusion Matrix. Defaults to true. -export COMET_MAX_IMAGE_UPLOADS= # Max prediction images to log. Defaults to 100. -export COMET_LOG_PER_CLASS_METRICS=true # Log evaluation metrics per class. Defaults to false. -export COMET_DEFAULT_CHECKPOINT_FILENAME= # Checkpoint for resuming. Defaults to 'last.pt'. -export COMET_LOG_BATCH_LEVEL_METRICS=true # Log training metrics per batch. Defaults to false. -export COMET_LOG_PREDICTIONS=true # Set to false to disable logging model predictions. Defaults to true. +# Comet Logging Configuration +export COMET_MODE=online # 'online' or 'offline'. Defaults to online. +export COMET_MODEL_NAME=YOUR_MODEL_NAME # Name for the saved model. Defaults to yolov3. +export COMET_LOG_CONFUSION_MATRIX=false # Disable confusion matrix logging. Defaults to true. +export COMET_MAX_IMAGE_UPLOADS=NUMBER # Max prediction images to log. Defaults to 100. +export COMET_LOG_PER_CLASS_METRICS=true # Log per-class metrics. Defaults to false. +export COMET_DEFAULT_CHECKPOINT_FILENAME=your_checkpoint.pt # Checkpoint for resuming. Defaults to 'last.pt'. +export COMET_LOG_BATCH_LEVEL_METRICS=true # Log batch-level metrics. Defaults to false. +export COMET_LOG_PREDICTIONS=true # Set to false to disable prediction logging. Defaults to true. ``` ### Logging Checkpoints with Comet -Logging [model checkpoints](https://docs.ultralytics.com/guides/model-training-tips/#checkpoints) to Comet is disabled by default. Enable it by passing the `save-period` argument to the training script. Checkpoints will be saved to Comet at the specified interval. +By default, [model checkpoints](https://docs.ultralytics.com/guides/model-training-tips/#checkpoints) are not uploaded to Comet. Enable checkpoint logging by using the `--save-period` argument: ```shell python train.py \ @@ -110,16 +117,16 @@ python train.py \ --epochs 5 \ --data coco128.yaml \ --weights yolov3.pt \ - --save-period 1 # Saves checkpoints every epoch + --save-period 1 # Save checkpoints every epoch ``` ### Logging Model Predictions -Model predictions (images, ground truth labels, bounding boxes) are logged to Comet by default. Control the frequency using the `bbox_interval` argument. This value corresponds to logging every Nth batch per epoch. Predictions can be visualized using Comet's Object Detection Custom Panel. +Model predictions (images, ground truth, bounding boxes) are logged to Comet by default. Control frequency with the `--bbox_interval` argument (log every Nth batch per epoch). Visualize predictions using Comet's Object Detection Custom Panel. -**Note:** The YOLOv3 validation dataloader defaults to a batch size of 32. Adjust the logging frequency accordingly. +**Note:** The YOLOv3 validation dataloader defaults to a batch size of 32. Adjust logging frequency as needed. -See an [example project using the Panel here](https://www.comet.com/examples/comet-example-yolov5?shareable=YcwMiJaZSXfcEXpGOHDD12vA1&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). +See an [example Comet project using the Object Detection Panel](https://www.comet.com/examples/comet-example-yolov5?shareable=YcwMiJaZSXfcEXpGOHDD12vA1&utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). ```shell python train.py \ @@ -128,12 +135,12 @@ python train.py \ --epochs 5 \ --data coco128.yaml \ --weights yolov3.pt \ - --bbox_interval 2 # Logs predictions every 2nd batch per epoch + --bbox_interval 2 # Log predictions every 2nd batch per epoch ``` #### Controlling the Number of Prediction Images Logged -Comet logs images associated with predictions. The default maximum is 100 validation images. Adjust this using the `COMET_MAX_IMAGE_UPLOADS` environment variable. +Comet logs up to 100 validation images by default. Adjust this with the `COMET_MAX_IMAGE_UPLOADS` variable: ```shell env COMET_MAX_IMAGE_UPLOADS=200 python train.py \ @@ -145,9 +152,9 @@ env COMET_MAX_IMAGE_UPLOADS=200 python train.py \ --bbox_interval 1 ``` -#### Logging Class Level Metrics +#### Logging Class-Level Metrics -Use the `COMET_LOG_PER_CLASS_METRICS` environment variable to log mAP, precision, recall, and F1-score for each class. +Enable per-class mAP, precision, recall, and F1-score logging: ```shell env COMET_LOG_PER_CLASS_METRICS=true python train.py \ @@ -160,7 +167,7 @@ env COMET_LOG_PER_CLASS_METRICS=true python train.py \ ## 💾 Uploading a Dataset to Comet Artifacts -Store your [datasets](https://docs.ultralytics.com/datasets/) using [Comet Artifacts](https://www.comet.com/docs/v2/guides/data-management/using-artifacts/#learn-more?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) by using the `upload_dataset` flag. Ensure your dataset follows the structure described in the [Ultralytics dataset guide](https://docs.ultralytics.com/datasets/). The dataset config `yaml` file must match the format of `coco128.yaml`. +Store your [datasets](https://docs.ultralytics.com/datasets/) using [Comet Artifacts](https://www.comet.com/docs/v2/guides/data-management/using-artifacts/#learn-more?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github) by adding the `--upload_dataset` flag. Ensure your dataset follows the structure in the [Ultralytics dataset guide](https://docs.ultralytics.com/datasets/). The dataset config YAML file must match the format of `coco128.yaml`. ```shell python train.py \ @@ -172,28 +179,28 @@ python train.py \ --upload_dataset # Uploads the dataset specified in coco128.yaml ``` -Find the uploaded dataset in the Artifacts tab in your Comet Workspace. +Find uploaded datasets in the Artifacts tab in your Comet Workspace. Comet Artifacts tab showing uploaded dataset -Preview the data directly in the Comet UI. +Preview data directly in the Comet UI. Comet UI previewing dataset artifact -Artifacts are versioned and support metadata. Comet automatically logs metadata from your dataset `yaml` file. +Artifacts are versioned and support metadata. Comet automatically logs metadata from your dataset YAML file. Comet Artifact metadata view ### Using a Saved Artifact -To use a dataset stored in Comet Artifacts, update the `path` variable in your dataset `yaml` file to the Artifact resource URL: +To use a dataset stored in Comet Artifacts, update the `path` variable in your dataset YAML file to the Artifact resource URL: ```yaml -# contents of artifact.yaml file +# contents of artifact.yaml path: "comet:///:" train: images/train # train images (relative to 'path') val: images/val # val images (relative to 'path') # ... other dataset configurations ``` -Then, pass this configuration file to your training script: +Then, pass this config file to your training script: ```shell python train.py \ @@ -204,54 +211,51 @@ python train.py \ --weights yolov3.pt ``` -Artifacts also enable tracking data lineage throughout your experimentation workflow. The graph below shows experiments that used the uploaded dataset. +Artifacts enable tracking data lineage throughout your workflow. The graph below shows experiments using the uploaded dataset. Comet Artifact lineage graph ## ▶️ Resuming a Training Run -If a training run is interrupted, resume it using the `--resume` flag with the Comet Run Path (`comet:////`). This restores the model state, hyperparameters, training arguments, and downloads necessary Comet Artifacts. Logging continues to the existing Comet Experiment. +If your training run is interrupted, resume it with the `--resume` flag and the Comet Run Path (`comet:////`). This restores the model state, hyperparameters, arguments, and downloads necessary Comet Artifacts. Logging continues to the same Comet Experiment. ```shell python train.py \ - --resume "comet:////" + --resume "comet://YOUR_WORKSPACE/YOUR_WORKSPACE/EXPERIMENT_ID" ``` ## 🔍 Hyperparameter Search with the Comet Optimizer -YOLOv3 integrates with Comet's Optimizer for easy [hyperparameter tuning](https://docs.ultralytics.com/guides/hyperparameter-tuning/) and visualization. +YOLOv3 integrates with Comet's Optimizer for [hyperparameter tuning](https://docs.ultralytics.com/guides/hyperparameter-tuning/) and visualization. ### Configuring an Optimizer Sweep -Create a JSON configuration file for the sweep (e.g., `utils/loggers/comet/optimizer_config.json`). +Create a JSON config file for the sweep (e.g., `utils/loggers/comet/optimizer_config.json`): ```json -// Example optimizer_config.json { "spec": { - "maxCombo": 10, // Max number of experiments to run - "objective": "minimize", // "minimize" or "maximize" - "metric": "metrics/mAP_0.5", // Metric to optimize - "algorithm": "bayes", // Optimization algorithm + "maxCombo": 10, + "objective": "minimize", + "metric": "metrics/mAP_0.5", + "algorithm": "bayes", "parameters": { - // Hyperparameters to tune "lr0": { "type": "float", "min": 0.001, "max": 0.01 }, "momentum": { "type": "float", "min": 0.85, "max": 0.95 } - // Add other hyperparameters from train.py args } }, - "name": "YOLOv3 Hyperparameter Sweep", // Name of the sweep - "trials": 1 // Number of trials per experiment combination + "name": "YOLOv3 Hyperparameter Sweep", + "trials": 1 } ``` -Run the sweep using the `hpo.py` script: +Run the sweep with the `hpo.py` script: ```shell python utils/loggers/comet/hpo.py \ --comet_optimizer_config utils/loggers/comet/optimizer_config.json ``` -The `hpo.py` script accepts the same arguments as `train.py`. Add any additional arguments needed for the sweep: +The `hpo.py` script accepts the same arguments as `train.py`. Add any additional arguments as needed: ```shell python utils/loggers/comet/hpo.py \ @@ -266,15 +270,15 @@ Use the `comet optimizer` command to run the sweep with multiple workers: ```shell comet optimizer -j \ - utils/loggers/comet/hpo.py < number_of_workers > utils/loggers/comet/optimizer_config.json + utils/loggers/comet/hpo.py NUMBER_OF_WORKERS utils/loggers/comet/optimizer_config.json ``` ### Visualizing Results -Comet offers various visualizations for sweep results. Explore a [project with a completed sweep here](https://www.comet.com/examples/comet-example-yolov5/view/PrlArHGuuhDTKC1UuBmTtOSXD/panels?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). +Comet provides rich visualizations for sweep results. Explore a [project with a completed sweep](https://www.comet.com/examples/comet-example-yolov5/view/PrlArHGuuhDTKC1UuBmTtOSXD/panels?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=github). Comet UI showing hyperparameter optimization results ## 🤝 Contributing -Contributions to enhance this integration are welcome! Please see the [Ultralytics Contributing Guide](https://docs.ultralytics.com/help/contributing/) for more information on how to get involved. Thank you for helping improve the Ultralytics ecosystem! +Contributions to this integration are welcome! See the [Ultralytics Contributing Guide](https://docs.ultralytics.com/help/contributing/) for details on how to get involved. Thank you for helping improve the Ultralytics ecosystem! From fe283677b78f0ec79c55e92d26bbf0b1b0274ca0 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 17 Apr 2025 19:55:54 +0200 Subject: [PATCH 1155/1185] Update links.yml (#2328) Signed-off-by: Glenn Jocher --- .github/workflows/links.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 2235c00004..3d871f65a6 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -33,7 +33,6 @@ jobs: retry_delay_seconds: 60 retries: 2 run: | - set -o pipefail # preserve exit code from lychee command in pipeline lychee \ --scheme 'https' \ --timeout 60 \ @@ -47,6 +46,11 @@ jobs: './**/*.md' \ './**/*.html' | tee -a $GITHUB_STEP_SUMMARY + # Raise error if broken links found + if ! grep -q "0 Errors" $GITHUB_STEP_SUMMARY; then + exit 1 + fi + - name: Test Markdown, HTML, YAML, Python and Notebook links with retry if: github.event_name == 'workflow_dispatch' uses: ultralytics/actions/retry@main @@ -55,7 +59,6 @@ jobs: retry_delay_seconds: 60 retries: 2 run: | - set -o pipefail # preserve exit code from lychee command in pipeline lychee \ --scheme 'https' \ --timeout 60 \ @@ -72,3 +75,8 @@ jobs: './**/*.yaml' \ './**/*.py' \ './**/*.ipynb' | tee -a $GITHUB_STEP_SUMMARY + + # Raise error if broken links found + if ! grep -q "0 Errors" $GITHUB_STEP_SUMMARY; then + exit 1 + fi From 7dfb114628ab55bc3135e1720c2c8dfde6760cfd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 18 Apr 2025 01:01:36 +0200 Subject: [PATCH 1156/1185] Simplify tutorial.ipynb Colab notebooks (#2329) --- classify/tutorial.ipynb | 79 +-- segment/tutorial.ipynb | 99 ++-- tutorial.ipynb | 1201 ++++++++++++++++++++------------------- 3 files changed, 714 insertions(+), 665 deletions(-) diff --git a/classify/tutorial.ipynb b/classify/tutorial.ipynb index 8b819639a7..35d3654ff1 100644 --- a/classify/tutorial.ipynb +++ b/classify/tutorial.ipynb @@ -7,19 +7,41 @@ }, "source": [ "
\n", + " \n", + " \n", + " \n", "\n", - " \n", - " \n", + " [中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [Türkçe](https://docs.ultralytics.com/tr/) | [Tiếng Việt](https://docs.ultralytics.com/vi/) | [العربية](https://docs.ultralytics.com/ar/)\n", "\n", + " \"Ultralytics\n", + " \"Run\n", + " \"Open\n", + " \"Open\n", "\n", - "
\n", - " \"Run\n", - " \"Open\n", - " \"Open\n", - "
\n", + " \"Discord\"\n", + " \"Ultralytics\n", + " \"Ultralytics\n", + "
\n", + "\n", + "This **Ultralytics YOLOv5 Classification Notebook** is the easiest way to get started with [YOLO models](https://www.ultralytics.com/yolo)—no installation needed. Built by [Ultralytics](https://www.ultralytics.com/), the creators of YOLO, this notebook walks you through running **state-of-the-art** models directly in your browser.\n", + "\n", + "Ultralytics models are constantly updated for performance and flexibility. They're **fast**, **accurate**, and **easy to use**, and they excel at [object detection](https://docs.ultralytics.com/tasks/detect/), [tracking](https://docs.ultralytics.com/modes/track/), [instance segmentation](https://docs.ultralytics.com/tasks/segment/), [image classification](https://docs.ultralytics.com/tasks/classify/), and [pose estimation](https://docs.ultralytics.com/tasks/pose/).\n", + "\n", + "Find detailed documentation in the [Ultralytics Docs](https://docs.ultralytics.com/). Get support via [GitHub Issues](https://github.com/ultralytics/ultralytics/issues/new/choose). Join discussions on [Discord](https://discord.com/invite/ultralytics), [Reddit](https://www.reddit.com/r/ultralytics/), and the [Ultralytics Community Forums](https://community.ultralytics.com/)!\n", + "\n", + "Request an Enterprise License for commercial use at [Ultralytics Licensing](https://www.ultralytics.com/license).\n", "\n", - "This YOLOv5 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", + "
\n", + "
\n", + " \n", + " \"Ultralytics\n", + " \n", "\n", + "

\n", + " Watch: How to Train\n", + " Ultralytics\n", + " YOLO11 Model on Custom Dataset using Google Colab Notebook 🚀\n", + "

\n", "
" ] }, @@ -109,7 +131,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[34m\u001b[1mclassify/predict: \u001b[0mweights=['yolov5s-cls.pt'], source=data/images, data=data/coco128.yaml, imgsz=[224, 224], device=, view_img=False, save_txt=False, nosave=False, augment=False, visualize=False, update=False, project=runs/predict-cls, name=exp, exist_ok=False, half=False, dnn=False, vid_stride=1\n", + "\u001B[34m\u001B[1mclassify/predict: \u001B[0mweights=['yolov5s-cls.pt'], source=data/images, data=data/coco128.yaml, imgsz=[224, 224], device=, view_img=False, save_txt=False, nosave=False, augment=False, visualize=False, update=False, project=runs/predict-cls, name=exp, exist_ok=False, half=False, dnn=False, vid_stride=1\n", "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", "\n", "Downloading https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-cls.pt to yolov5s-cls.pt...\n", @@ -120,7 +142,7 @@ "image 1/2 /content/yolov5/data/images/bus.jpg: 224x224 minibus 0.39, police van 0.24, amphibious vehicle 0.05, recreational vehicle 0.04, trolleybus 0.03, 3.9ms\n", "image 2/2 /content/yolov5/data/images/zidane.jpg: 224x224 suit 0.38, bow tie 0.19, bridegroom 0.18, rugby ball 0.04, stage 0.02, 4.6ms\n", "Speed: 0.3ms pre-process, 4.3ms inference, 1.5ms NMS per image at shape (1, 3, 224, 224)\n", - "Results saved to \u001b[1mruns/predict-cls/exp\u001b[0m\n" + "Results saved to \u001B[1mruns/predict-cls/exp\u001B[0m\n" ] } ], @@ -198,7 +220,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[34m\u001b[1mclassify/val: \u001b[0mdata=../datasets/imagenet, weights=['yolov5s-cls.pt'], batch_size=128, imgsz=224, device=, workers=8, verbose=True, project=runs/val-cls, name=exp, exist_ok=False, half=True, dnn=False\n", + "\u001B[34m\u001B[1mclassify/val: \u001B[0mdata=../datasets/imagenet, weights=['yolov5s-cls.pt'], batch_size=128, imgsz=224, device=, workers=8, verbose=True, project=runs/val-cls, name=exp, exist_ok=False, half=True, dnn=False\n", "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", "\n", "Fusing layers... \n", @@ -1207,7 +1229,7 @@ " ear 50 0.48 0.94\n", " toilet paper 50 0.36 0.68\n", "Speed: 0.1ms pre-process, 0.3ms inference, 0.0ms post-process per image at shape (1, 3, 224, 224)\n", - "Results saved to \u001b[1mruns/val-cls/exp\u001b[0m\n" + "Results saved to \u001B[1mruns/val-cls/exp\u001B[0m\n" ] } ], @@ -1224,8 +1246,9 @@ "source": [ "# 3. Train\n", "\n", - "

\n", - "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", + "\n", + " \"Ultralytics\n", + "\n", "

\n", "\n", "Train a YOLOv5s Classification model on the [Imagenette](https://image-net.org/) dataset with `--data imagenet`, starting from pretrained `--pretrained yolov5s-cls.pt`.\n", @@ -1235,17 +1258,7 @@ "- **Training Results** are saved to `runs/train-cls/` with incrementing run directories, i.e. `runs/train-cls/exp2`, `runs/train-cls/exp3` etc.\n", "

\n", "\n", - "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic.\n", - "\n", - "## Train on Custom Data with Roboflow 🌟 NEW\n", - "\n", - "[Roboflow](https://roboflow.com/?ref=ultralytics) enables you to easily **organize, label, and prepare** a high quality dataset with your own custom data. Roboflow also makes it easy to establish an active learning pipeline, collaborate with your team on dataset improvement, and integrate directly into your model building workflow with the `roboflow` pip package.\n", - "\n", - "- Custom Training Example: [https://blog.roboflow.com/train-yolov5-classification-custom-data/](https://blog.roboflow.com/train-yolov5-classification-custom-data/?ref=ultralytics)\n", - "- Custom Training Notebook: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1KZiKUAjtARHAfZCXbJRv14-pOnIsBLPV?usp=sharing)\n", - "
\n", - "\n", - "

Label images lightning fast (including with model-assisted labeling)" + "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic." ] }, { @@ -1289,24 +1302,24 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[34m\u001b[1mclassify/train: \u001b[0mmodel=yolov5s-cls.pt, data=imagenette160, epochs=5, batch_size=64, imgsz=224, nosave=False, cache=ram, device=, workers=8, project=runs/train-cls, name=exp, exist_ok=False, pretrained=True, optimizer=Adam, lr0=0.001, decay=5e-05, label_smoothing=0.1, cutoff=None, dropout=None, verbose=False, seed=0, local_rank=-1\n", - "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", + "\u001B[34m\u001B[1mclassify/train: \u001B[0mmodel=yolov5s-cls.pt, data=imagenette160, epochs=5, batch_size=64, imgsz=224, nosave=False, cache=ram, device=, workers=8, project=runs/train-cls, name=exp, exist_ok=False, pretrained=True, optimizer=Adam, lr0=0.001, decay=5e-05, label_smoothing=0.1, cutoff=None, dropout=None, verbose=False, seed=0, local_rank=-1\n", + "\u001B[34m\u001B[1mgithub: \u001B[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", "YOLOv5 🚀 v7.0-3-g61ebf5e Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", "\n", - "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train-cls', view at http://localhost:6006/\n", + "\u001B[34m\u001B[1mTensorBoard: \u001B[0mStart with 'tensorboard --logdir runs/train-cls', view at http://localhost:6006/\n", "\n", "Dataset not found ⚠️, missing path /content/datasets/imagenette160, attempting download...\n", "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/imagenette160.zip to /content/datasets/imagenette160.zip...\n", "100% 103M/103M [00:00<00:00, 347MB/s] \n", "Unzipping /content/datasets/imagenette160.zip...\n", - "Dataset download success ✅ (3.3s), saved to \u001b[1m/content/datasets/imagenette160\u001b[0m\n", + "Dataset download success ✅ (3.3s), saved to \u001B[1m/content/datasets/imagenette160\u001B[0m\n", "\n", - "\u001b[34m\u001b[1malbumentations: \u001b[0mRandomResizedCrop(p=1.0, height=224, width=224, scale=(0.08, 1.0), ratio=(0.75, 1.3333333333333333), interpolation=1), HorizontalFlip(p=0.5), ColorJitter(p=0.5, brightness=[0.6, 1.4], contrast=[0.6, 1.4], saturation=[0.6, 1.4], hue=[0, 0]), Normalize(p=1.0, mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), max_pixel_value=255.0), ToTensorV2(always_apply=True, p=1.0, transpose_mask=False)\n", + "\u001B[34m\u001B[1malbumentations: \u001B[0mRandomResizedCrop(p=1.0, height=224, width=224, scale=(0.08, 1.0), ratio=(0.75, 1.3333333333333333), interpolation=1), HorizontalFlip(p=0.5), ColorJitter(p=0.5, brightness=[0.6, 1.4], contrast=[0.6, 1.4], saturation=[0.6, 1.4], hue=[0, 0]), Normalize(p=1.0, mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), max_pixel_value=255.0), ToTensorV2(always_apply=True, p=1.0, transpose_mask=False)\n", "Model summary: 149 layers, 4185290 parameters, 4185290 gradients, 10.5 GFLOPs\n", - "\u001b[34m\u001b[1moptimizer:\u001b[0m Adam(lr=0.001) with parameter groups 32 weight(decay=0.0), 33 weight(decay=5e-05), 33 bias\n", + "\u001B[34m\u001B[1moptimizer:\u001B[0m Adam(lr=0.001) with parameter groups 32 weight(decay=0.0), 33 weight(decay=5e-05), 33 bias\n", "Image sizes 224 train, 224 test\n", "Using 1 dataloader workers\n", - "Logging results to \u001b[1mruns/train-cls/exp\u001b[0m\n", + "Logging results to \u001B[1mruns/train-cls/exp\u001B[0m\n", "Starting yolov5s-cls.pt training on imagenette160 dataset with 10 classes for 5 epochs...\n", "\n", " Epoch GPU_mem train_loss val_loss top1_acc top5_acc\n", @@ -1317,7 +1330,7 @@ " 5/5 1.73G 0.724 0.634 0.959 0.997: 100% 148/148 [00:37<00:00, 3.94it/s]\n", "\n", "Training complete (0.052 hours)\n", - "Results saved to \u001b[1mruns/train-cls/exp\u001b[0m\n", + "Results saved to \u001B[1mruns/train-cls/exp\u001B[0m\n", "Predict: python classify/predict.py --weights runs/train-cls/exp/weights/best.pt --source im.jpg\n", "Validate: python classify/val.py --weights runs/train-cls/exp/weights/best.pt --data /content/datasets/imagenette160\n", "Export: python export.py --weights runs/train-cls/exp/weights/best.pt --include onnx\n", diff --git a/segment/tutorial.ipynb b/segment/tutorial.ipynb index 1c364d6abe..5406147ea1 100644 --- a/segment/tutorial.ipynb +++ b/segment/tutorial.ipynb @@ -7,19 +7,41 @@ }, "source": [ "
\n", + " \n", + " \n", + " \n", "\n", - " \n", - " \n", + " [中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [Türkçe](https://docs.ultralytics.com/tr/) | [Tiếng Việt](https://docs.ultralytics.com/vi/) | [العربية](https://docs.ultralytics.com/ar/)\n", "\n", + " \"Ultralytics\n", + " \"Run\n", + " \"Open\n", + " \"Open\n", "\n", - "
\n", - " \"Run\n", - " \"Open\n", - " \"Open\n", - "
\n", + " \"Discord\"\n", + " \"Ultralytics\n", + " \"Ultralytics\n", + "
\n", + "\n", + "This **Ultralytics YOLOv5 Segmentation Colab Notebook** is the easiest way to get started with [YOLO models](https://www.ultralytics.com/yolo)—no installation needed. Built by [Ultralytics](https://www.ultralytics.com/), the creators of YOLO, this notebook walks you through running **state-of-the-art** models directly in your browser.\n", "\n", - "This YOLOv5 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
See GitHub for community support or contact us for professional support.\n", + "Ultralytics models are constantly updated for performance and flexibility. They're **fast**, **accurate**, and **easy to use**, and they excel at [object detection](https://docs.ultralytics.com/tasks/detect/), [tracking](https://docs.ultralytics.com/modes/track/), [instance segmentation](https://docs.ultralytics.com/tasks/segment/), [image classification](https://docs.ultralytics.com/tasks/classify/), and [pose estimation](https://docs.ultralytics.com/tasks/pose/).\n", "\n", + "Find detailed documentation in the [Ultralytics Docs](https://docs.ultralytics.com/). Get support via [GitHub Issues](https://github.com/ultralytics/ultralytics/issues/new/choose). Join discussions on [Discord](https://discord.com/invite/ultralytics), [Reddit](https://www.reddit.com/r/ultralytics/), and the [Ultralytics Community Forums](https://community.ultralytics.com/)!\n", + "\n", + "Request an Enterprise License for commercial use at [Ultralytics Licensing](https://www.ultralytics.com/license).\n", + "\n", + "
\n", + "
\n", + " \n", + " \"Ultralytics\n", + " \n", + "\n", + "

\n", + " Watch: How to Train\n", + " Ultralytics\n", + " YOLO11 Model on Custom Dataset using Google Colab Notebook 🚀\n", + "

\n", "
" ] }, @@ -109,7 +131,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[34m\u001b[1msegment/predict: \u001b[0mweights=['yolov5s-seg.pt'], source=data/images, data=data/coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/predict-seg, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False, vid_stride=1, retina_masks=False\n", + "\u001B[34m\u001B[1msegment/predict: \u001B[0mweights=['yolov5s-seg.pt'], source=data/images, data=data/coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/predict-seg, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False, vid_stride=1, retina_masks=False\n", "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", "\n", "Downloading https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s-seg.pt to yolov5s-seg.pt...\n", @@ -120,7 +142,7 @@ "image 1/2 /content/yolov5/data/images/bus.jpg: 640x480 4 persons, 1 bus, 18.2ms\n", "image 2/2 /content/yolov5/data/images/zidane.jpg: 384x640 2 persons, 1 tie, 13.4ms\n", "Speed: 0.5ms pre-process, 15.8ms inference, 18.5ms NMS per image at shape (1, 3, 640, 640)\n", - "Results saved to \u001b[1mruns/predict-seg/exp\u001b[0m\n" + "Results saved to \u001B[1mruns/predict-seg/exp\u001B[0m\n" ] } ], @@ -191,17 +213,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[34m\u001b[1msegment/val: \u001b[0mdata=/content/yolov5/data/coco.yaml, weights=['yolov5s-seg.pt'], batch_size=32, imgsz=640, conf_thres=0.001, iou_thres=0.6, max_det=300, task=val, device=, workers=8, single_cls=False, augment=False, verbose=False, save_txt=False, save_hybrid=False, save_conf=False, save_json=False, project=runs/val-seg, name=exp, exist_ok=False, half=True, dnn=False\n", + "\u001B[34m\u001B[1msegment/val: \u001B[0mdata=/content/yolov5/data/coco.yaml, weights=['yolov5s-seg.pt'], batch_size=32, imgsz=640, conf_thres=0.001, iou_thres=0.6, max_det=300, task=val, device=, workers=8, single_cls=False, augment=False, verbose=False, save_txt=False, save_hybrid=False, save_conf=False, save_json=False, project=runs/val-seg, name=exp, exist_ok=False, half=True, dnn=False\n", "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", "\n", "Fusing layers... \n", "YOLOv5s-seg summary: 224 layers, 7611485 parameters, 0 gradients, 26.4 GFLOPs\n", - "\u001b[34m\u001b[1mval: \u001b[0mScanning /content/datasets/coco/val2017... 4952 images, 48 backgrounds, 0 corrupt: 100% 5000/5000 [00:03<00:00, 1361.31it/s]\n", - "\u001b[34m\u001b[1mval: \u001b[0mNew cache created: /content/datasets/coco/val2017.cache\n", + "\u001B[34m\u001B[1mval: \u001B[0mScanning /content/datasets/coco/val2017... 4952 images, 48 backgrounds, 0 corrupt: 100% 5000/5000 [00:03<00:00, 1361.31it/s]\n", + "\u001B[34m\u001B[1mval: \u001B[0mNew cache created: /content/datasets/coco/val2017.cache\n", " Class Images Instances Box(P R mAP50 mAP50-95) Mask(P R mAP50 mAP50-95): 100% 157/157 [01:54<00:00, 1.37it/s]\n", " all 5000 36335 0.673 0.517 0.566 0.373 0.672 0.49 0.532 0.319\n", "Speed: 0.6ms pre-process, 4.4ms inference, 2.9ms NMS per image at shape (32, 3, 640, 640)\n", - "Results saved to \u001b[1mruns/val-seg/exp\u001b[0m\n" + "Results saved to \u001B[1mruns/val-seg/exp\u001B[0m\n" ] } ], @@ -218,8 +240,9 @@ "source": [ "# 3. Train\n", "\n", - "

\n", - "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", + "\n", + " \"Ultralytics\n", + "\n", "

\n", "\n", "Train a YOLOv5s-seg model on the [COCO128](https://www.kaggle.com/datasets/ultralytics/coco128) dataset with `--data coco128-seg.yaml`, starting from pretrained `--weights yolov5s-seg.pt`, or from randomly initialized `--weights '' --cfg yolov5s-seg.yaml`.\n", @@ -230,17 +253,7 @@ "- **Training Results** are saved to `runs/train-seg/` with incrementing run directories, i.e. `runs/train-seg/exp2`, `runs/train-seg/exp3` etc.\n", "

\n", "\n", - "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic.\n", - "\n", - "## Train on Custom Data with Roboflow 🌟 NEW\n", - "\n", - "[Roboflow](https://roboflow.com/?ref=ultralytics) enables you to easily **organize, label, and prepare** a high quality dataset with your own custom data. Roboflow also makes it easy to establish an active learning pipeline, collaborate with your team on dataset improvement, and integrate directly into your model building workflow with the `roboflow` pip package.\n", - "\n", - "- Custom Training Example: [https://blog.roboflow.com/train-yolov5-instance-segmentation-custom-dataset/](https://blog.roboflow.com/train-yolov5-instance-segmentation-custom-dataset/?ref=ultralytics)\n", - "- Custom Training Notebook: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1JTz7kpmHsg-5qwVz2d2IH3AaenI1tv0N?usp=sharing)\n", - "
\n", - "\n", - "

Label images lightning fast (including with model-assisted labeling)" + "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic." ] }, { @@ -284,17 +297,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[34m\u001b[1msegment/train: \u001b[0mweights=yolov5s-seg.pt, cfg=, data=coco128-seg.yaml, hyp=data/hyps/hyp.scratch-low.yaml, epochs=3, batch_size=16, imgsz=640, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, noplots=False, evolve=None, bucket=, cache=ram, image_weights=False, device=, multi_scale=False, single_cls=False, optimizer=SGD, sync_bn=False, workers=8, project=runs/train-seg, name=exp, exist_ok=False, quad=False, cos_lr=False, label_smoothing=0.0, patience=100, freeze=[0], save_period=-1, seed=0, local_rank=-1, mask_ratio=4, no_overlap=False\n", - "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", + "\u001B[34m\u001B[1msegment/train: \u001B[0mweights=yolov5s-seg.pt, cfg=, data=coco128-seg.yaml, hyp=data/hyps/hyp.scratch-low.yaml, epochs=3, batch_size=16, imgsz=640, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, noplots=False, evolve=None, bucket=, cache=ram, image_weights=False, device=, multi_scale=False, single_cls=False, optimizer=SGD, sync_bn=False, workers=8, project=runs/train-seg, name=exp, exist_ok=False, quad=False, cos_lr=False, label_smoothing=0.0, patience=100, freeze=[0], save_period=-1, seed=0, local_rank=-1, mask_ratio=4, no_overlap=False\n", + "\u001B[34m\u001B[1mgithub: \u001B[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", "YOLOv5 🚀 v7.0-2-gc9d47ae Python-3.7.15 torch-1.12.1+cu113 CUDA:0 (Tesla T4, 15110MiB)\n", "\n", - "\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0\n", - "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train-seg', view at http://localhost:6006/\n", + "\u001B[34m\u001B[1mhyperparameters: \u001B[0mlr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0\n", + "\u001B[34m\u001B[1mTensorBoard: \u001B[0mStart with 'tensorboard --logdir runs/train-seg', view at http://localhost:6006/\n", "\n", "Dataset not found ⚠️, missing paths ['/content/datasets/coco128-seg/images/train2017']\n", "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/coco128-seg.zip to coco128-seg.zip...\n", "100% 6.79M/6.79M [00:01<00:00, 6.73MB/s]\n", - "Dataset download success ✅ (1.9s), saved to \u001b[1m/content/datasets\u001b[0m\n", + "Dataset download success ✅ (1.9s), saved to \u001B[1m/content/datasets\u001B[0m\n", "\n", " from n params module arguments \n", " 0 -1 1 3520 models.common.Conv [3, 32, 6, 2, 2] \n", @@ -325,20 +338,20 @@ "Model summary: 225 layers, 7621277 parameters, 7621277 gradients, 26.6 GFLOPs\n", "\n", "Transferred 367/367 items from yolov5s-seg.pt\n", - "\u001b[34m\u001b[1mAMP: \u001b[0mchecks passed ✅\n", - "\u001b[34m\u001b[1moptimizer:\u001b[0m SGD(lr=0.01) with parameter groups 60 weight(decay=0.0), 63 weight(decay=0.0005), 63 bias\n", - "\u001b[34m\u001b[1malbumentations: \u001b[0mBlur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01), CLAHE(p=0.01, clip_limit=(1, 4.0), tile_grid_size=(8, 8))\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mScanning /content/datasets/coco128-seg/labels/train2017... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00<00:00, 1389.59it/s]\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mNew cache created: /content/datasets/coco128-seg/labels/train2017.cache\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mCaching images (0.1GB ram): 100% 128/128 [00:00<00:00, 238.86it/s]\n", - "\u001b[34m\u001b[1mval: \u001b[0mScanning /content/datasets/coco128-seg/labels/train2017.cache... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00\n", - "\n", - " \n", - " \n", - "\n", - "\n", - "
\n", - " \"Run\n", - " \"Open\n", - " \"Open\n", - "
\n", - "\n", - "This YOLOv5 🚀 notebook by Ultralytics presents simple train, validate and predict examples to help start your AI adventure.
We hope that the resources in this notebook will help you get the most out of YOLOv5. Please browse the YOLOv5 Docs for details, raise an issue on GitHub for support, and join our Discord community for questions and discussions!\n", - "\n", - "
" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "7mGmQbAO5pQb" - }, - "source": [ - "# Setup\n", - "\n", - "Clone GitHub [repository](https://github.com/ultralytics/yolov5), install [dependencies](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) and check PyTorch and GPU." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "wbvMlHd_QwMG", - "colab": { - "base_uri": "https://localhost:8080/" - }, - "outputId": "e8225db4-e61d-4640-8b1f-8bfce3331cea" - }, - "source": [ - "!git clone https://github.com/ultralytics/yolov5 # clone\n", - "%cd yolov5\n", - "%pip install -qr requirements.txt comet_ml # install\n", - "\n", - "import torch\n", - "import utils\n", - "display = utils.notebook_init() # checks" - ], - "execution_count": 1, - "outputs": [ - { - "output_type": "stream", - "name": "stderr", - "text": [ - "YOLOv5 🚀 v7.0-136-g71244ae Python-3.9.16 torch-2.0.0+cu118 CUDA:0 (Tesla T4, 15102MiB)\n" - ] - }, - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Setup complete ✅ (2 CPUs, 12.7 GB RAM, 23.3/166.8 GB disk)\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "4JnkELT0cIJg" - }, - "source": [ - "# 1. Detect\n", - "\n", - "`detect.py` runs YOLOv5 inference on a variety of sources, downloading models automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases), and saving results to `runs/detect`. Example inference sources are:\n", - "\n", - "```shell\n", - "python detect.py --source 0 # webcam\n", - " img.jpg # image \n", - " vid.mp4 # video\n", - " screen # screenshot\n", - " path/ # directory\n", - " 'path/*.jpg' # glob\n", - " 'https://youtu.be/LNwODJXcvt4' # YouTube\n", - " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", - "```" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "zR9ZbuQCH7FX", - "colab": { - "base_uri": "https://localhost:8080/" - }, - "outputId": "284ef04b-1596-412f-88f6-948828dd2b49" - }, - "source": [ - "!python detect.py --weights yolov5s.pt --img 640 --conf 0.25 --source data/images\n", - "# display.Image(filename='runs/detect/exp/zidane.jpg', width=600)" - ], - "execution_count": 13, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "\u001b[34m\u001b[1mdetect: \u001b[0mweights=['yolov5s.pt'], source=data/images, data=data/coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False, vid_stride=1\n", - "YOLOv5 🚀 v7.0-136-g71244ae Python-3.9.16 torch-2.0.0+cu118 CUDA:0 (Tesla T4, 15102MiB)\n", - "\n", - "Downloading https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt to yolov5s.pt...\n", - "100% 14.1M/14.1M [00:00<00:00, 24.5MB/s]\n", - "\n", - "Fusing layers... \n", - "YOLOv5s summary: 213 layers, 7225885 parameters, 0 gradients\n", - "image 1/2 /content/yolov5/data/images/bus.jpg: 640x480 4 persons, 1 bus, 41.5ms\n", - "image 2/2 /content/yolov5/data/images/zidane.jpg: 384x640 2 persons, 2 ties, 60.0ms\n", - "Speed: 0.5ms pre-process, 50.8ms inference, 37.7ms NMS per image at shape (1, 3, 640, 640)\n", - "Results saved to \u001b[1mruns/detect/exp\u001b[0m\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "hkAzDWJ7cWTr" - }, - "source": [ - "        \n", - "" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "0eq1SMWl6Sfn" - }, - "source": [ - "# 2. Validate\n", - "Validate a model's accuracy on the [COCO](https://cocodataset.org/#home) dataset's `val` or `test` splits. Models are downloaded automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases). To show results by class use the `--verbose` flag." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "WQPtK1QYVaD_", - "colab": { - "base_uri": "https://localhost:8080/" - }, - "outputId": "cf7d52f0-281c-4c96-a488-79f5908f8426" - }, - "source": [ - "# Download COCO val\n", - "torch.hub.download_url_to_file('https://github.com/ultralytics/assets/releases/download/v0.0.0/coco2017val.zip', 'tmp.zip') # download (780M - 5000 images)\n", - "!unzip -q tmp.zip -d ../datasets && rm tmp.zip # unzip" - ], - "execution_count": 3, - "outputs": [ - { - "output_type": "stream", - "name": "stderr", - "text": [ - "100%|██████████| 780M/780M [00:12<00:00, 66.6MB/s]\n" - ] - } - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "X58w8JLpMnjH", - "colab": { - "base_uri": "https://localhost:8080/" - }, - "outputId": "3e234e05-ee8b-4ad1-b1a4-f6a55d5e4f3d" - }, - "source": [ - "# Validate YOLOv5s on COCO val\n", - "!python val.py --weights yolov5s.pt --data coco.yaml --img 640 --half" - ], - "execution_count": 4, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "\u001b[34m\u001b[1mval: \u001b[0mdata=/content/yolov5/data/coco.yaml, weights=['yolov5s.pt'], batch_size=32, imgsz=640, conf_thres=0.001, iou_thres=0.6, max_det=300, task=val, device=, workers=8, single_cls=False, augment=False, verbose=False, save_txt=False, save_hybrid=False, save_conf=False, save_json=True, project=runs/val, name=exp, exist_ok=False, half=True, dnn=False\n", - "YOLOv5 🚀 v7.0-136-g71244ae Python-3.9.16 torch-2.0.0+cu118 CUDA:0 (Tesla T4, 15102MiB)\n", - "\n", - "Fusing layers... \n", - "YOLOv5s summary: 213 layers, 7225885 parameters, 0 gradients\n", - "\u001b[34m\u001b[1mval: \u001b[0mScanning /content/datasets/coco/val2017... 4952 images, 48 backgrounds, 0 corrupt: 100% 5000/5000 [00:02<00:00, 2024.59it/s]\n", - "\u001b[34m\u001b[1mval: \u001b[0mNew cache created: /content/datasets/coco/val2017.cache\n", - " Class Images Instances P R mAP50 mAP50-95: 100% 157/157 [01:25<00:00, 1.84it/s]\n", - " all 5000 36335 0.671 0.519 0.566 0.371\n", - "Speed: 0.1ms pre-process, 3.1ms inference, 2.3ms NMS per image at shape (32, 3, 640, 640)\n", - "\n", - "Evaluating pycocotools mAP... saving runs/val/exp/yolov5s_predictions.json...\n", - "loading annotations into memory...\n", - "Done (t=0.43s)\n", - "creating index...\n", - "index created!\n", - "Loading and preparing results...\n", - "DONE (t=5.32s)\n", - "creating index...\n", - "index created!\n", - "Running per image evaluation...\n", - "Evaluate annotation type *bbox*\n", - "DONE (t=78.89s).\n", - "Accumulating evaluation results...\n", - "DONE (t=14.51s).\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.374\n", - " Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.572\n", - " Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.402\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.211\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.423\n", - " Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.489\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.311\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.516\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.566\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.378\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.625\n", - " Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.722\n", - "Results saved to \u001b[1mruns/val/exp\u001b[0m\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "ZY2VXXXu74w5" - }, - "source": [ - "# 3. Train\n", - "\n", - "

\n", - "Close the active learning loop by sampling images from your inference conditions with the `roboflow` pip package\n", - "

\n", - "\n", - "Train a YOLOv5s model on the [COCO128](https://www.kaggle.com/datasets/ultralytics/coco128) dataset with `--data coco128.yaml`, starting from pretrained `--weights yolov5s.pt`, or from randomly initialized `--weights '' --cfg yolov5s.yaml`.\n", - "\n", - "- **Pretrained [Models](https://github.com/ultralytics/yolov5/tree/master/models)** are downloaded\n", - "automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases)\n", - "- **[Datasets](https://github.com/ultralytics/yolov5/tree/master/data)** available for autodownload include: [COCO](https://github.com/ultralytics/yolov5/blob/master/data/coco.yaml), [COCO128](https://github.com/ultralytics/yolov5/blob/master/data/coco128.yaml), [VOC](https://github.com/ultralytics/yolov5/blob/master/data/VOC.yaml), [Argoverse](https://github.com/ultralytics/yolov5/blob/master/data/Argoverse.yaml), [VisDrone](https://github.com/ultralytics/yolov5/blob/master/data/VisDrone.yaml), [GlobalWheat](https://github.com/ultralytics/yolov5/blob/master/data/GlobalWheat2020.yaml), [xView](https://github.com/ultralytics/yolov5/blob/master/data/xView.yaml), [Objects365](https://github.com/ultralytics/yolov5/blob/master/data/Objects365.yaml), [SKU-110K](https://github.com/ultralytics/yolov5/blob/master/data/SKU-110K.yaml).\n", - "- **Training Results** are saved to `runs/train/` with incrementing run directories, i.e. `runs/train/exp2`, `runs/train/exp3` etc.\n", - "
\n", - "\n", - "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic.\n", - "\n", - "## Label a dataset on Roboflow (optional)\n", - "\n", - "[Roboflow](https://roboflow.com/?ref=ultralytics) enables you to easily **organize, label, and prepare** a high quality dataset with your own custom data. Roboflow also makes it easy to establish an active learning pipeline, collaborate with your team on dataset improvement, and integrate directly into your model building workflow with the `roboflow` pip package." - ] - }, - { - "cell_type": "code", - "source": [ - "#@title Select YOLOv5 🚀 logger {run: 'auto'}\n", - "logger = 'Comet' #@param ['Comet', 'ClearML', 'TensorBoard']\n", - "\n", - "if logger == 'Comet':\n", - " %pip install -q comet_ml\n", - " import comet_ml; comet_ml.init()\n", - "elif logger == 'ClearML':\n", - " %pip install -q clearml\n", - " import clearml; clearml.browser_login()\n", - "elif logger == 'TensorBoard':\n", - " %load_ext tensorboard\n", - " %tensorboard --logdir runs/train" - ], - "metadata": { - "id": "i3oKtE4g-aNn" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "1NcFxRcFdJ_O", - "colab": { - "base_uri": "https://localhost:8080/" - }, - "outputId": "bbeeea2b-04fc-4185-aa64-258690495b5a" - }, - "source": [ - "# Train YOLOv5s on COCO128 for 3 epochs\n", - "!python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov5s.pt --cache" - ], - "execution_count": 5, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "2023-04-09 14:11:38.063605: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", - "To enable the following instructions: AVX2 AVX512F FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", - "2023-04-09 14:11:39.026661: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mweights=yolov5s.pt, cfg=, data=coco128.yaml, hyp=data/hyps/hyp.scratch-low.yaml, epochs=3, batch_size=16, imgsz=640, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, noplots=False, evolve=None, bucket=, cache=ram, image_weights=False, device=, multi_scale=False, single_cls=False, optimizer=SGD, sync_bn=False, workers=8, project=runs/train, name=exp, exist_ok=False, quad=False, cos_lr=False, label_smoothing=0.0, patience=100, freeze=[0], save_period=-1, seed=0, local_rank=-1, entity=None, upload_dataset=False, bbox_interval=-1, artifact_alias=latest\n", - "\u001b[34m\u001b[1mgithub: \u001b[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", - "YOLOv5 🚀 v7.0-136-g71244ae Python-3.9.16 torch-2.0.0+cu118 CUDA:0 (Tesla T4, 15102MiB)\n", - "\n", - "\u001b[34m\u001b[1mhyperparameters: \u001b[0mlr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0\n", - "\u001b[34m\u001b[1mClearML: \u001b[0mrun 'pip install clearml' to automatically track, visualize and remotely train YOLOv5 🚀 in ClearML\n", - "\u001b[34m\u001b[1mComet: \u001b[0mrun 'pip install comet_ml' to automatically track and visualize YOLOv5 🚀 runs in Comet\n", - "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs/train', view at http://localhost:6006/\n", - "\n", - "Dataset not found ⚠️, missing paths ['/content/datasets/coco128/images/train2017']\n", - "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/coco128.zip to coco128.zip...\n", - "100% 6.66M/6.66M [00:00<00:00, 75.6MB/s]\n", - "Dataset download success ✅ (0.6s), saved to \u001b[1m/content/datasets\u001b[0m\n", - "\n", - " from n params module arguments \n", - " 0 -1 1 3520 models.common.Conv [3, 32, 6, 2, 2] \n", - " 1 -1 1 18560 models.common.Conv [32, 64, 3, 2] \n", - " 2 -1 1 18816 models.common.C3 [64, 64, 1] \n", - " 3 -1 1 73984 models.common.Conv [64, 128, 3, 2] \n", - " 4 -1 2 115712 models.common.C3 [128, 128, 2] \n", - " 5 -1 1 295424 models.common.Conv [128, 256, 3, 2] \n", - " 6 -1 3 625152 models.common.C3 [256, 256, 3] \n", - " 7 -1 1 1180672 models.common.Conv [256, 512, 3, 2] \n", - " 8 -1 1 1182720 models.common.C3 [512, 512, 1] \n", - " 9 -1 1 656896 models.common.SPPF [512, 512, 5] \n", - " 10 -1 1 131584 models.common.Conv [512, 256, 1, 1] \n", - " 11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", - " 12 [-1, 6] 1 0 models.common.Concat [1] \n", - " 13 -1 1 361984 models.common.C3 [512, 256, 1, False] \n", - " 14 -1 1 33024 models.common.Conv [256, 128, 1, 1] \n", - " 15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", - " 16 [-1, 4] 1 0 models.common.Concat [1] \n", - " 17 -1 1 90880 models.common.C3 [256, 128, 1, False] \n", - " 18 -1 1 147712 models.common.Conv [128, 128, 3, 2] \n", - " 19 [-1, 14] 1 0 models.common.Concat [1] \n", - " 20 -1 1 296448 models.common.C3 [256, 256, 1, False] \n", - " 21 -1 1 590336 models.common.Conv [256, 256, 3, 2] \n", - " 22 [-1, 10] 1 0 models.common.Concat [1] \n", - " 23 -1 1 1182720 models.common.C3 [512, 512, 1, False] \n", - " 24 [17, 20, 23] 1 229245 models.yolo.Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [128, 256, 512]]\n", - "Model summary: 214 layers, 7235389 parameters, 7235389 gradients, 16.6 GFLOPs\n", - "\n", - "Transferred 349/349 items from yolov5s.pt\n", - "\u001b[34m\u001b[1mAMP: \u001b[0mchecks passed ✅\n", - "\u001b[34m\u001b[1moptimizer:\u001b[0m SGD(lr=0.01) with parameter groups 57 weight(decay=0.0), 60 weight(decay=0.0005), 60 bias\n", - "\u001b[34m\u001b[1malbumentations: \u001b[0mBlur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01), CLAHE(p=0.01, clip_limit=(1, 4.0), tile_grid_size=(8, 8))\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mScanning /content/datasets/coco128/labels/train2017... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00<00:00, 1709.36it/s]\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mNew cache created: /content/datasets/coco128/labels/train2017.cache\n", - "\u001b[34m\u001b[1mtrain: \u001b[0mCaching images (0.1GB ram): 100% 128/128 [00:00<00:00, 264.35it/s]\n", - "\u001b[34m\u001b[1mval: \u001b[0mScanning /content/datasets/coco128/labels/train2017.cache... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00 # 2. paste API key\n", - "python train.py --img 640 --epochs 3 --data coco128.yaml --weights yolov5s.pt # 3. train\n", - "```\n", - "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", - "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing)\n", - "\n", - "\n", - "\"Comet" - ], - "metadata": { - "id": "nWOsI5wJR1o3" - } + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "accelerator": "GPU" + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "t6MPjfT5NrKQ" + }, + "source": [ + "
\n", + " \n", + " \n", + " \n", + "\n", + " [中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es/) | [Português](https://docs.ultralytics.com/pt/) | [Türkçe](https://docs.ultralytics.com/tr/) | [Tiếng Việt](https://docs.ultralytics.com/vi/) | [العربية](https://docs.ultralytics.com/ar/)\n", + "\n", + " \"Ultralytics\n", + " \"Run\n", + " \"Open\n", + " \"Open\n", + "\n", + " \"Discord\"\n", + " \"Ultralytics\n", + " \"Ultralytics\n", + "
\n", + "\n", + "This **Ultralytics YOLOv5 Colab Notebook** is the easiest way to get started with [YOLO models](https://www.ultralytics.com/yolo)—no installation needed. Built by [Ultralytics](https://www.ultralytics.com/), the creators of YOLO, this notebook walks you through running **state-of-the-art** models directly in your browser.\n", + "\n", + "Ultralytics models are constantly updated for performance and flexibility. They're **fast**, **accurate**, and **easy to use**, and they excel at [object detection](https://docs.ultralytics.com/tasks/detect/), [tracking](https://docs.ultralytics.com/modes/track/), [instance segmentation](https://docs.ultralytics.com/tasks/segment/), [image classification](https://docs.ultralytics.com/tasks/classify/), and [pose estimation](https://docs.ultralytics.com/tasks/pose/).\n", + "\n", + "Find detailed documentation in the [Ultralytics Docs](https://docs.ultralytics.com/). Get support via [GitHub Issues](https://github.com/ultralytics/ultralytics/issues/new/choose). Join discussions on [Discord](https://discord.com/invite/ultralytics), [Reddit](https://www.reddit.com/r/ultralytics/), and the [Ultralytics Community Forums](https://community.ultralytics.com/)!\n", + "\n", + "Request an Enterprise License for commercial use at [Ultralytics Licensing](https://www.ultralytics.com/license).\n", + "\n", + "
\n", + "
\n", + " \n", + " \"Ultralytics\n", + " \n", + "\n", + "

\n", + " Watch: How to Train\n", + " Ultralytics\n", + " YOLO11 Model on Custom Dataset using Google Colab Notebook 🚀\n", + "

\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7mGmQbAO5pQb" + }, + "source": [ + "# Setup\n", + "\n", + "Clone GitHub [repository](https://github.com/ultralytics/yolov5), install [dependencies](https://github.com/ultralytics/yolov5/blob/master/requirements.txt) and check PyTorch and GPU." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "wbvMlHd_QwMG", + "colab": { + "base_uri": "https://localhost:8080/" }, + "outputId": "e8225db4-e61d-4640-8b1f-8bfce3331cea" + }, + "source": [ + "!git clone https://github.com/ultralytics/yolov5 # clone\n", + "%cd yolov5\n", + "%pip install -qr requirements.txt comet_ml # install\n", + "\n", + "import torch\n", + "import utils\n", + "display = utils.notebook_init() # checks" + ], + "execution_count": 1, + "outputs": [ { - "cell_type": "markdown", - "source": [ - "## ClearML Logging and Automation 🌟 NEW\n", - "\n", - "[ClearML](https://cutt.ly/yolov5-notebook-clearml) is completely integrated into YOLOv5 to track your experimentation, manage dataset versions and even remotely execute training runs. To enable ClearML (check cells above):\n", - "\n", - "- `pip install clearml`\n", - "- run `clearml-init` to connect to a ClearML server (**deploy your own [open-source server](https://github.com/allegroai/clearml-server)**, or use our [free hosted server](https://cutt.ly/yolov5-notebook-clearml))\n", - "\n", - "You'll get all the great expected features from an experiment manager: live updates, model upload, experiment comparison etc. but ClearML also tracks uncommitted changes and installed packages for example. Thanks to that ClearML Tasks (which is what we call experiments) are also reproducible on different machines! With only 1 extra line, we can schedule a YOLOv5 training task on a queue to be executed by any number of ClearML Agents (workers).\n", - "\n", - "You can use ClearML Data to version your dataset and then pass it to YOLOv5 simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration) for details!\n", - "\n", - "\n", - "\"ClearML" - ], - "metadata": { - "id": "Lay2WsTjNJzP" - } + "output_type": "stream", + "name": "stderr", + "text": [ + "YOLOv5 🚀 v7.0-136-g71244ae Python-3.9.16 torch-2.0.0+cu118 CUDA:0 (Tesla T4, 15102MiB)\n" + ] }, { - "cell_type": "markdown", - "metadata": { - "id": "-WPvRbS5Swl6" - }, - "source": [ - "## Local Logging\n", - "\n", - "Training results are automatically logged with [Tensorboard](https://www.tensorflow.org/tensorboard) and [CSV](https://github.com/ultralytics/yolov5/pull/4148) loggers to `runs/train`, with a new experiment directory created for each new training as `runs/train/exp2`, `runs/train/exp3`, etc.\n", - "\n", - "This directory contains train and val statistics, mosaics, labels, predictions and augmentated mosaics, as well as metrics and charts including precision-recall (PR) curves and confusion matrices. \n", - "\n", - "\"Local\n" - ] + "output_type": "stream", + "name": "stdout", + "text": [ + "Setup complete ✅ (2 CPUs, 12.7 GB RAM, 23.3/166.8 GB disk)\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4JnkELT0cIJg" + }, + "source": [ + "# 1. Detect\n", + "\n", + "`detect.py` runs YOLOv5 inference on a variety of sources, downloading models automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases), and saving results to `runs/detect`. Example inference sources are:\n", + "\n", + "```shell\n", + "python detect.py --source 0 # webcam\n", + " img.jpg # image \n", + " vid.mp4 # video\n", + " screen # screenshot\n", + " path/ # directory\n", + " 'path/*.jpg' # glob\n", + " 'https://youtu.be/LNwODJXcvt4' # YouTube\n", + " 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream\n", + "```" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "zR9ZbuQCH7FX", + "colab": { + "base_uri": "https://localhost:8080/" }, + "outputId": "284ef04b-1596-412f-88f6-948828dd2b49" + }, + "source": [ + "!python detect.py --weights yolov5s.pt --img 640 --conf 0.25 --source data/images\n", + "# display.Image(filename='runs/detect/exp/zidane.jpg', width=600)" + ], + "execution_count": 13, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "Zelyeqbyt3GD" - }, - "source": [ - "# Environments\n", - "\n", - "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):\n", - "\n", - "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", - "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)\n", - "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)\n", - "- **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) \"Docker\n" - ] + "output_type": "stream", + "name": "stdout", + "text": [ + "\u001B[34m\u001B[1mdetect: \u001B[0mweights=['yolov5s.pt'], source=data/images, data=data/coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False, vid_stride=1\n", + "YOLOv5 🚀 v7.0-136-g71244ae Python-3.9.16 torch-2.0.0+cu118 CUDA:0 (Tesla T4, 15102MiB)\n", + "\n", + "Downloading https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt to yolov5s.pt...\n", + "100% 14.1M/14.1M [00:00<00:00, 24.5MB/s]\n", + "\n", + "Fusing layers... \n", + "YOLOv5s summary: 213 layers, 7225885 parameters, 0 gradients\n", + "image 1/2 /content/yolov5/data/images/bus.jpg: 640x480 4 persons, 1 bus, 41.5ms\n", + "image 2/2 /content/yolov5/data/images/zidane.jpg: 384x640 2 persons, 2 ties, 60.0ms\n", + "Speed: 0.5ms pre-process, 50.8ms inference, 37.7ms NMS per image at shape (1, 3, 640, 640)\n", + "Results saved to \u001B[1mruns/detect/exp\u001B[0m\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hkAzDWJ7cWTr" + }, + "source": [ + "        \n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0eq1SMWl6Sfn" + }, + "source": [ + "# 2. Validate\n", + "Validate a model's accuracy on the [COCO](https://cocodataset.org/#home) dataset's `val` or `test` splits. Models are downloaded automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases). To show results by class use the `--verbose` flag." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "WQPtK1QYVaD_", + "colab": { + "base_uri": "https://localhost:8080/" }, + "outputId": "cf7d52f0-281c-4c96-a488-79f5908f8426" + }, + "source": [ + "# Download COCO val\n", + "torch.hub.download_url_to_file('https://github.com/ultralytics/assets/releases/download/v0.0.0/coco2017val.zip', 'tmp.zip') # download (780M - 5000 images)\n", + "!unzip -q tmp.zip -d ../datasets && rm tmp.zip # unzip" + ], + "execution_count": 3, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "6Qu7Iesl0p54" - }, - "source": [ - "# Status\n", - "\n", - "![YOLOv5 CI](https://github.com/ultralytics/yolov3/actions/workflows/ci-testing.yml/badge.svg)\n", - "\n", - "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/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)), testing ([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.\n" - ] + "output_type": "stream", + "name": "stderr", + "text": [ + "100%|██████████| 780M/780M [00:12<00:00, 66.6MB/s]\n" + ] + } + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "X58w8JLpMnjH", + "colab": { + "base_uri": "https://localhost:8080/" }, + "outputId": "3e234e05-ee8b-4ad1-b1a4-f6a55d5e4f3d" + }, + "source": [ + "# Validate YOLOv5s on COCO val\n", + "!python val.py --weights yolov5s.pt --data coco.yaml --img 640 --half" + ], + "execution_count": 4, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "IEijrePND_2I" - }, - "source": [ - "# Appendix\n", - "\n", - "Additional content below." - ] + "output_type": "stream", + "name": "stdout", + "text": [ + "\u001B[34m\u001B[1mval: \u001B[0mdata=/content/yolov5/data/coco.yaml, weights=['yolov5s.pt'], batch_size=32, imgsz=640, conf_thres=0.001, iou_thres=0.6, max_det=300, task=val, device=, workers=8, single_cls=False, augment=False, verbose=False, save_txt=False, save_hybrid=False, save_conf=False, save_json=True, project=runs/val, name=exp, exist_ok=False, half=True, dnn=False\n", + "YOLOv5 🚀 v7.0-136-g71244ae Python-3.9.16 torch-2.0.0+cu118 CUDA:0 (Tesla T4, 15102MiB)\n", + "\n", + "Fusing layers... \n", + "YOLOv5s summary: 213 layers, 7225885 parameters, 0 gradients\n", + "\u001B[34m\u001B[1mval: \u001B[0mScanning /content/datasets/coco/val2017... 4952 images, 48 backgrounds, 0 corrupt: 100% 5000/5000 [00:02<00:00, 2024.59it/s]\n", + "\u001B[34m\u001B[1mval: \u001B[0mNew cache created: /content/datasets/coco/val2017.cache\n", + " Class Images Instances P R mAP50 mAP50-95: 100% 157/157 [01:25<00:00, 1.84it/s]\n", + " all 5000 36335 0.671 0.519 0.566 0.371\n", + "Speed: 0.1ms pre-process, 3.1ms inference, 2.3ms NMS per image at shape (32, 3, 640, 640)\n", + "\n", + "Evaluating pycocotools mAP... saving runs/val/exp/yolov5s_predictions.json...\n", + "loading annotations into memory...\n", + "Done (t=0.43s)\n", + "creating index...\n", + "index created!\n", + "Loading and preparing results...\n", + "DONE (t=5.32s)\n", + "creating index...\n", + "index created!\n", + "Running per image evaluation...\n", + "Evaluate annotation type *bbox*\n", + "DONE (t=78.89s).\n", + "Accumulating evaluation results...\n", + "DONE (t=14.51s).\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.374\n", + " Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.572\n", + " Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.402\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.211\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.423\n", + " Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.489\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.311\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.516\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.566\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.378\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.625\n", + " Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.722\n", + "Results saved to \u001B[1mruns/val/exp\u001B[0m\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZY2VXXXu74w5" + }, + "source": [ + "# 3. Train\n", + "\n", + "\n", + " \"Ultralytics\n", + "\n", + "

\n", + "\n", + "Train a YOLOv5s model on the [COCO128](https://www.kaggle.com/datasets/ultralytics/coco128) dataset with `--data coco128.yaml`, starting from pretrained `--weights yolov5s.pt`, or from randomly initialized `--weights '' --cfg yolov5s.yaml`.\n", + "\n", + "- **Pretrained [Models](https://github.com/ultralytics/yolov5/tree/master/models)** are downloaded\n", + "automatically from the [latest YOLOv5 release](https://github.com/ultralytics/yolov5/releases)\n", + "- **[Datasets](https://github.com/ultralytics/yolov5/tree/master/data)** available for autodownload include: [COCO](https://github.com/ultralytics/yolov5/blob/master/data/coco.yaml), [COCO128](https://github.com/ultralytics/yolov5/blob/master/data/coco128.yaml), [VOC](https://github.com/ultralytics/yolov5/blob/master/data/VOC.yaml), [Argoverse](https://github.com/ultralytics/yolov5/blob/master/data/Argoverse.yaml), [VisDrone](https://github.com/ultralytics/yolov5/blob/master/data/VisDrone.yaml), [GlobalWheat](https://github.com/ultralytics/yolov5/blob/master/data/GlobalWheat2020.yaml), [xView](https://github.com/ultralytics/yolov5/blob/master/data/xView.yaml), [Objects365](https://github.com/ultralytics/yolov5/blob/master/data/Objects365.yaml), [SKU-110K](https://github.com/ultralytics/yolov5/blob/master/data/SKU-110K.yaml).\n", + "- **Training Results** are saved to `runs/train/` with incrementing run directories, i.e. `runs/train/exp2`, `runs/train/exp3` etc.\n", + "
\n", + "\n", + "A **Mosaic Dataloader** is used for training which combines 4 images into 1 mosaic.\n", + "\n", + "## Label a dataset on Roboflow (optional)\n", + "\n", + "[Roboflow](https://roboflow.com/?ref=ultralytics) enables you to easily **organize, label, and prepare** a high quality dataset with your own custom data. Roboflow also makes it easy to establish an active learning pipeline, collaborate with your team on dataset improvement, and integrate directly into your model building workflow with the `roboflow` pip package." + ] + }, + { + "cell_type": "code", + "source": [ + "#@title Select YOLOv5 🚀 logger {run: 'auto'}\n", + "logger = 'Comet' #@param ['Comet', 'ClearML', 'TensorBoard']\n", + "\n", + "if logger == 'Comet':\n", + " %pip install -q comet_ml\n", + " import comet_ml; comet_ml.init()\n", + "elif logger == 'ClearML':\n", + " %pip install -q clearml\n", + " import clearml; clearml.browser_login()\n", + "elif logger == 'TensorBoard':\n", + " %load_ext tensorboard\n", + " %tensorboard --logdir runs/train" + ], + "metadata": { + "id": "i3oKtE4g-aNn" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "1NcFxRcFdJ_O", + "colab": { + "base_uri": "https://localhost:8080/" }, + "outputId": "bbeeea2b-04fc-4185-aa64-258690495b5a" + }, + "source": [ + "# Train YOLOv5s on COCO128 for 3 epochs\n", + "!python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov5s.pt --cache" + ], + "execution_count": 5, + "outputs": [ { - "cell_type": "code", - "metadata": { - "id": "GMusP4OAxFu6" - }, - "source": [ - "# YOLOv5 PyTorch HUB Inference (DetectionModels only)\n", - "import torch\n", - "\n", - "model = torch.hub.load('ultralytics/yolov5', 'yolov5s', force_reload=True) # yolov5n - yolov5x6 or custom\n", - "im = 'https://ultralytics.com/images/zidane.jpg' # file, Path, PIL.Image, OpenCV, nparray, list\n", - "results = model(im) # inference\n", - "results.print() # or .show(), .save(), .crop(), .pandas(), etc." - ], - "execution_count": null, - "outputs": [] + "output_type": "stream", + "name": "stdout", + "text": [ + "2023-04-09 14:11:38.063605: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX512F FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2023-04-09 14:11:39.026661: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n", + "\u001B[34m\u001B[1mtrain: \u001B[0mweights=yolov5s.pt, cfg=, data=coco128.yaml, hyp=data/hyps/hyp.scratch-low.yaml, epochs=3, batch_size=16, imgsz=640, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, noplots=False, evolve=None, bucket=, cache=ram, image_weights=False, device=, multi_scale=False, single_cls=False, optimizer=SGD, sync_bn=False, workers=8, project=runs/train, name=exp, exist_ok=False, quad=False, cos_lr=False, label_smoothing=0.0, patience=100, freeze=[0], save_period=-1, seed=0, local_rank=-1, entity=None, upload_dataset=False, bbox_interval=-1, artifact_alias=latest\n", + "\u001B[34m\u001B[1mgithub: \u001B[0mup to date with https://github.com/ultralytics/yolov5 ✅\n", + "YOLOv5 🚀 v7.0-136-g71244ae Python-3.9.16 torch-2.0.0+cu118 CUDA:0 (Tesla T4, 15102MiB)\n", + "\n", + "\u001B[34m\u001B[1mhyperparameters: \u001B[0mlr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0\n", + "\u001B[34m\u001B[1mClearML: \u001B[0mrun 'pip install clearml' to automatically track, visualize and remotely train YOLOv5 🚀 in ClearML\n", + "\u001B[34m\u001B[1mComet: \u001B[0mrun 'pip install comet_ml' to automatically track and visualize YOLOv5 🚀 runs in Comet\n", + "\u001B[34m\u001B[1mTensorBoard: \u001B[0mStart with 'tensorboard --logdir runs/train', view at http://localhost:6006/\n", + "\n", + "Dataset not found ⚠️, missing paths ['/content/datasets/coco128/images/train2017']\n", + "Downloading https://github.com/ultralytics/assets/releases/download/v0.0.0/coco128.zip to coco128.zip...\n", + "100% 6.66M/6.66M [00:00<00:00, 75.6MB/s]\n", + "Dataset download success ✅ (0.6s), saved to \u001B[1m/content/datasets\u001B[0m\n", + "\n", + " from n params module arguments \n", + " 0 -1 1 3520 models.common.Conv [3, 32, 6, 2, 2] \n", + " 1 -1 1 18560 models.common.Conv [32, 64, 3, 2] \n", + " 2 -1 1 18816 models.common.C3 [64, 64, 1] \n", + " 3 -1 1 73984 models.common.Conv [64, 128, 3, 2] \n", + " 4 -1 2 115712 models.common.C3 [128, 128, 2] \n", + " 5 -1 1 295424 models.common.Conv [128, 256, 3, 2] \n", + " 6 -1 3 625152 models.common.C3 [256, 256, 3] \n", + " 7 -1 1 1180672 models.common.Conv [256, 512, 3, 2] \n", + " 8 -1 1 1182720 models.common.C3 [512, 512, 1] \n", + " 9 -1 1 656896 models.common.SPPF [512, 512, 5] \n", + " 10 -1 1 131584 models.common.Conv [512, 256, 1, 1] \n", + " 11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 12 [-1, 6] 1 0 models.common.Concat [1] \n", + " 13 -1 1 361984 models.common.C3 [512, 256, 1, False] \n", + " 14 -1 1 33024 models.common.Conv [256, 128, 1, 1] \n", + " 15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 16 [-1, 4] 1 0 models.common.Concat [1] \n", + " 17 -1 1 90880 models.common.C3 [256, 128, 1, False] \n", + " 18 -1 1 147712 models.common.Conv [128, 128, 3, 2] \n", + " 19 [-1, 14] 1 0 models.common.Concat [1] \n", + " 20 -1 1 296448 models.common.C3 [256, 256, 1, False] \n", + " 21 -1 1 590336 models.common.Conv [256, 256, 3, 2] \n", + " 22 [-1, 10] 1 0 models.common.Concat [1] \n", + " 23 -1 1 1182720 models.common.C3 [512, 512, 1, False] \n", + " 24 [17, 20, 23] 1 229245 models.yolo.Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [128, 256, 512]]\n", + "Model summary: 214 layers, 7235389 parameters, 7235389 gradients, 16.6 GFLOPs\n", + "\n", + "Transferred 349/349 items from yolov5s.pt\n", + "\u001B[34m\u001B[1mAMP: \u001B[0mchecks passed ✅\n", + "\u001B[34m\u001B[1moptimizer:\u001B[0m SGD(lr=0.01) with parameter groups 57 weight(decay=0.0), 60 weight(decay=0.0005), 60 bias\n", + "\u001B[34m\u001B[1malbumentations: \u001B[0mBlur(p=0.01, blur_limit=(3, 7)), MedianBlur(p=0.01, blur_limit=(3, 7)), ToGray(p=0.01), CLAHE(p=0.01, clip_limit=(1, 4.0), tile_grid_size=(8, 8))\n", + "\u001B[34m\u001B[1mtrain: \u001B[0mScanning /content/datasets/coco128/labels/train2017... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00<00:00, 1709.36it/s]\n", + "\u001B[34m\u001B[1mtrain: \u001B[0mNew cache created: /content/datasets/coco128/labels/train2017.cache\n", + "\u001B[34m\u001B[1mtrain: \u001B[0mCaching images (0.1GB ram): 100% 128/128 [00:00<00:00, 264.35it/s]\n", + "\u001B[34m\u001B[1mval: \u001B[0mScanning /content/datasets/coco128/labels/train2017.cache... 126 images, 2 backgrounds, 0 corrupt: 100% 128/128 [00:00 # 2. paste API key\n", + "python train.py --img 640 --epochs 3 --data coco128.yaml --weights yolov5s.pt # 3. train\n", + "```\n", + "To learn more about all of the supported Comet features for this integration, check out the [Comet Tutorial](https://docs.ultralytics.com/yolov5/tutorials/comet_logging_integration). If you'd like to learn more about Comet, head over to our [documentation](https://www.comet.com/docs/v2/?utm_source=yolov5&utm_medium=partner&utm_campaign=partner_yolov5_2022&utm_content=yolov5_colab). Get started by trying out the Comet Colab Notebook:\n", + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1RG0WOQyxlDlo5Km8GogJpIEJlg_5lyYO?usp=sharing)\n", + "\n", + "\n", + "\"Comet" + ], + "metadata": { + "id": "nWOsI5wJR1o3" + } + }, + { + "cell_type": "markdown", + "source": [ + "## ClearML Logging and Automation 🌟 NEW\n", + "\n", + "[ClearML](https://cutt.ly/yolov5-notebook-clearml) is completely integrated into YOLOv5 to track your experimentation, manage dataset versions and even remotely execute training runs. To enable ClearML (check cells above):\n", + "\n", + "- `pip install clearml`\n", + "- run `clearml-init` to connect to a ClearML server (**deploy your own [open-source server](https://github.com/allegroai/clearml-server)**, or use our [free hosted server](https://cutt.ly/yolov5-notebook-clearml))\n", + "\n", + "You'll get all the great expected features from an experiment manager: live updates, model upload, experiment comparison etc. but ClearML also tracks uncommitted changes and installed packages for example. Thanks to that ClearML Tasks (which is what we call experiments) are also reproducible on different machines! With only 1 extra line, we can schedule a YOLOv5 training task on a queue to be executed by any number of ClearML Agents (workers).\n", + "\n", + "You can use ClearML Data to version your dataset and then pass it to YOLOv5 simply using its unique ID. This will help you keep track of your data without adding extra hassle. Explore the [ClearML Tutorial](https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration) for details!\n", + "\n", + "\n", + "\"ClearML" + ], + "metadata": { + "id": "Lay2WsTjNJzP" + } + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-WPvRbS5Swl6" + }, + "source": [ + "## Local Logging\n", + "\n", + "Training results are automatically logged with [Tensorboard](https://www.tensorflow.org/tensorboard) and [CSV](https://github.com/ultralytics/yolov5/pull/4148) loggers to `runs/train`, with a new experiment directory created for each new training as `runs/train/exp2`, `runs/train/exp3`, etc.\n", + "\n", + "This directory contains train and val statistics, mosaics, labels, predictions and augmentated mosaics, as well as metrics and charts including precision-recall (PR) curves and confusion matrices. \n", + "\n", + "\"Local\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Zelyeqbyt3GD" + }, + "source": [ + "# Environments\n", + "\n", + "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):\n", + "\n", + "- **Notebooks** with free GPU: \"Run \"Open \"Open\n", + "- **Google Cloud** Deep Learning VM. See [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)\n", + "- **Amazon** Deep Learning AMI. See [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)\n", + "- **Docker Image**. See [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) \"Docker\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6Qu7Iesl0p54" + }, + "source": [ + "# Status\n", + "\n", + "![YOLOv5 CI](https://github.com/ultralytics/yolov3/actions/workflows/ci-testing.yml/badge.svg)\n", + "\n", + "If this badge is green, all [YOLOv3 GitHub Actions](https://github.com/ultralytics/yolov3/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)), testing ([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.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IEijrePND_2I" + }, + "source": [ + "# Appendix\n", + "\n", + "Additional content below." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "GMusP4OAxFu6" + }, + "source": [ + "# YOLOv5 PyTorch HUB Inference (DetectionModels only)\n", + "import torch\n", + "\n", + "model = torch.hub.load('ultralytics/yolov5', 'yolov5s', force_reload=True) # yolov5n - yolov5x6 or custom\n", + "im = 'https://ultralytics.com/images/zidane.jpg' # file, Path, PIL.Image, OpenCV, nparray, list\n", + "results = model(im) # inference\n", + "results.print() # or .show(), .save(), .crop(), .pandas(), etc." + ], + "execution_count": null, + "outputs": [] + } + ] } From efe201c46e9d27758a73238aa3a52289dd7e6792 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 11 May 2025 02:17:57 +0200 Subject: [PATCH 1157/1185] Add Permissions to Ultralytics Actions `format.yml` (#2332) * Update Ultralytics Actions permissions * Update format.yml Signed-off-by: Glenn Jocher * Auto-format by https://ultralytics.com/actions * Update callbacks.py Signed-off-by: Glenn Jocher --------- Signed-off-by: Glenn Jocher Co-authored-by: UltralyticsAssistant --- .github/workflows/format.yml | 28 +++++++++++++++---------- benchmarks.py | 1 + classify/predict.py | 1 + classify/train.py | 1 + classify/val.py | 1 + data/scripts/download_weights.sh | 2 +- data/scripts/get_coco.sh | 8 +++---- data/scripts/get_imagenet.sh | 4 ++-- detect.py | 1 + export.py | 1 + hubconf.py | 1 + models/common.py | 1 + models/experimental.py | 1 + models/tf.py | 1 + models/yolo.py | 1 + segment/predict.py | 1 + segment/train.py | 1 + segment/val.py | 1 + train.py | 1 + utils/__init__.py | 1 + utils/activations.py | 1 + utils/augmentations.py | 1 + utils/autoanchor.py | 1 + utils/autobatch.py | 1 + utils/aws/mime.sh | 15 ++++++++----- utils/aws/userdata.sh | 2 +- utils/callbacks.py | 3 ++- utils/dataloaders.py | 1 + utils/downloads.py | 1 + utils/flask_rest_api/example_request.py | 1 + utils/flask_rest_api/restapi.py | 1 + utils/general.py | 1 + utils/loggers/__init__.py | 1 + utils/loggers/clearml/clearml_utils.py | 1 + utils/loss.py | 1 + utils/metrics.py | 1 + utils/plots.py | 1 + utils/segment/augmentations.py | 1 + utils/segment/dataloaders.py | 1 + utils/segment/metrics.py | 1 + utils/torch_utils.py | 1 + utils/triton.py | 1 + val.py | 1 + 43 files changed, 73 insertions(+), 25 deletions(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 687bc31582..ba89d938cb 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -1,7 +1,7 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license # Ultralytics Actions https://github.com/ultralytics/actions -# This workflow automatically formats code and documentation in PRs to official Ultralytics standards +# This workflow formats code and documentation in PRs to Ultralytics standards name: Ultralytics Actions @@ -12,18 +12,24 @@ on: branches: [main, master] types: [opened, closed, synchronize, review_requested] +permissions: + contents: write # Modify code in PRs + pull-requests: write # Add comments and labels to PRs + issues: write # Add comments and labels to issues + jobs: - format: + actions: runs-on: ubuntu-latest steps: - - name: Run Ultralytics Formatting + - name: Run Ultralytics Actions uses: ultralytics/actions@main with: - token: ${{ secrets._GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - labels: true # autolabel issues and PRs - python: true # format Python code and docstrings - prettier: true # format YAML, JSON, Markdown and CSS - spelling: true # check spelling - links: false # check broken links - summary: true # print PR summary with GPT4o (requires 'openai_api_key') - openai_api_key: ${{ secrets.OPENAI_API_KEY }} + token: ${{ secrets._GITHUB_TOKEN || secrets.GITHUB_TOKEN }} # Auto-generated token + labels: true # Auto-label issues/PRs using AI + python: true # Format Python with Ruff and docformatter + prettier: true # Format YAML, JSON, Markdown, CSS + spelling: true # Check spelling with codespell + links: false # Check broken links with Lychee + summary: true # Generate AI-powered PR summaries + openai_api_key: ${{ secrets.OPENAI_API_KEY }} # Powers PR summaries, labels and comments + brave_api_key: ${{ secrets.BRAVE_API_KEY }} # Used for broken link resolution diff --git a/benchmarks.py b/benchmarks.py index 7c215dede6..96c6ded691 100644 --- a/benchmarks.py +++ b/benchmarks.py @@ -1,4 +1,5 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + """ Run YOLOv3 benchmarks on all supported export formats. diff --git a/classify/predict.py b/classify/predict.py index 9e191933e9..e5c0605a73 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -1,4 +1,5 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + """ Run YOLOv3 classification inference on images, videos, directories, globs, YouTube, webcam, streams, etc. diff --git a/classify/train.py b/classify/train.py index 9eef8e0715..da76954c4d 100644 --- a/classify/train.py +++ b/classify/train.py @@ -1,4 +1,5 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + """ Train a YOLOv3 classifier model on a classification dataset. diff --git a/classify/val.py b/classify/val.py index f8079941cc..1782c83de0 100644 --- a/classify/val.py +++ b/classify/val.py @@ -1,4 +1,5 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + """ Validate a trained YOLOv3 classification model on a classification dataset. diff --git a/data/scripts/download_weights.sh b/data/scripts/download_weights.sh index 7726a9bd18..92be4847a7 100755 --- a/data/scripts/download_weights.sh +++ b/data/scripts/download_weights.sh @@ -9,7 +9,7 @@ # ├── yolov5m.pt # └── ... -python - < Date: Tue, 20 May 2025 22:11:01 +0200 Subject: [PATCH 1158/1185] [Snyk] Security upgrade setuptools from 40.5.0 to 78.1.1 (#2331) * fix: requirements.txt to reduce vulnerabilities The following vulnerabilities are fixed by pinning transitive dependencies: - https://snyk.io/vuln/SNYK-PYTHON-SETUPTOOLS-9964606 * Auto-format by https://ultralytics.com/actions * Update requirements.txt Signed-off-by: Glenn Jocher * Auto-format by https://ultralytics.com/actions --------- Signed-off-by: Glenn Jocher Co-authored-by: snyk-bot Co-authored-by: UltralyticsAssistant --- benchmarks.py | 1 - classify/predict.py | 1 - classify/train.py | 1 - classify/val.py | 1 - detect.py | 1 - export.py | 1 - hubconf.py | 1 - models/common.py | 1 - models/experimental.py | 1 - models/tf.py | 1 - models/yolo.py | 1 - segment/predict.py | 1 - segment/train.py | 1 - segment/val.py | 1 - train.py | 1 - utils/__init__.py | 1 - utils/activations.py | 1 - utils/augmentations.py | 1 - utils/autoanchor.py | 1 - utils/autobatch.py | 1 - utils/callbacks.py | 1 - utils/dataloaders.py | 1 - utils/downloads.py | 1 - utils/flask_rest_api/example_request.py | 1 - utils/flask_rest_api/restapi.py | 1 - utils/general.py | 1 - utils/loggers/__init__.py | 1 - utils/loggers/clearml/clearml_utils.py | 1 - utils/loss.py | 1 - utils/metrics.py | 1 - utils/plots.py | 1 - utils/segment/augmentations.py | 1 - utils/segment/dataloaders.py | 1 - utils/segment/metrics.py | 1 - utils/torch_utils.py | 1 - utils/triton.py | 1 - val.py | 1 - 37 files changed, 37 deletions(-) diff --git a/benchmarks.py b/benchmarks.py index 96c6ded691..7c215dede6 100644 --- a/benchmarks.py +++ b/benchmarks.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ Run YOLOv3 benchmarks on all supported export formats. diff --git a/classify/predict.py b/classify/predict.py index e5c0605a73..9e191933e9 100644 --- a/classify/predict.py +++ b/classify/predict.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ Run YOLOv3 classification inference on images, videos, directories, globs, YouTube, webcam, streams, etc. diff --git a/classify/train.py b/classify/train.py index da76954c4d..9eef8e0715 100644 --- a/classify/train.py +++ b/classify/train.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ Train a YOLOv3 classifier model on a classification dataset. diff --git a/classify/val.py b/classify/val.py index 1782c83de0..f8079941cc 100644 --- a/classify/val.py +++ b/classify/val.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ Validate a trained YOLOv3 classification model on a classification dataset. diff --git a/detect.py b/detect.py index a6a6380a62..6668a504e3 100644 --- a/detect.py +++ b/detect.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ Run YOLOv3 detection inference on images, videos, directories, globs, YouTube, webcam, streams, etc. diff --git a/export.py b/export.py index 5c3ad770e0..56ab25b3c8 100644 --- a/export.py +++ b/export.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ Export a YOLOv3 PyTorch model to other formats. TensorFlow exports authored by https://github.com/zldrobit. diff --git a/hubconf.py b/hubconf.py index caa1183a30..53fe1cfcbb 100644 --- a/hubconf.py +++ b/hubconf.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov5. diff --git a/models/common.py b/models/common.py index ec6197187a..9372150e86 100644 --- a/models/common.py +++ b/models/common.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Common modules.""" import ast diff --git a/models/experimental.py b/models/experimental.py index f13d1bed73..50d1cd0d4a 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Experimental modules.""" import math diff --git a/models/tf.py b/models/tf.py index 4048fde6de..5f6f2a6374 100644 --- a/models/tf.py +++ b/models/tf.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ TensorFlow, Keras and TFLite versions of YOLOv3 Authored by https://github.com/zldrobit in PR https://github.com/ultralytics/yolov5/pull/1127. diff --git a/models/yolo.py b/models/yolo.py index 46f72e0130..7b00e7ef67 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ YOLO-specific modules. diff --git a/segment/predict.py b/segment/predict.py index 499922ccd3..529332c12c 100644 --- a/segment/predict.py +++ b/segment/predict.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ Run YOLOv3 segmentation inference on images, videos, directories, streams, etc. diff --git a/segment/train.py b/segment/train.py index 0abb118ab7..78ade178da 100644 --- a/segment/train.py +++ b/segment/train.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ Train a YOLOv3 segment model on a segment dataset Models and datasets download automatically from the latest YOLOv3 release. diff --git a/segment/val.py b/segment/val.py index 379db21b47..2da9a7e1ac 100644 --- a/segment/val.py +++ b/segment/val.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ Validate a trained YOLOv3 segment model on a segment dataset. diff --git a/train.py b/train.py index c5795f4f24..ba4784ee90 100644 --- a/train.py +++ b/train.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ Train a YOLOv3 model on a custom dataset. Models and datasets download automatically from the latest YOLOv3 release. diff --git a/utils/__init__.py b/utils/__init__.py index 2979d2261a..a7b86410d0 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """utils/initialization.""" import contextlib diff --git a/utils/activations.py b/utils/activations.py index b764c2ddb4..0a1a79766a 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Activation functions.""" import torch diff --git a/utils/augmentations.py b/utils/augmentations.py index 7505c347b1..65a0435758 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Image augmentation functions.""" import math diff --git a/utils/autoanchor.py b/utils/autoanchor.py index 16481295b7..3599d66865 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """AutoAnchor utils.""" import random diff --git a/utils/autobatch.py b/utils/autobatch.py index de9f3517c7..915ba35575 100644 --- a/utils/autobatch.py +++ b/utils/autobatch.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Auto-batch utils.""" from copy import deepcopy diff --git a/utils/callbacks.py b/utils/callbacks.py index f46447aa54..0ef2e41ebf 100644 --- a/utils/callbacks.py +++ b/utils/callbacks.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Callback utils.""" import threading diff --git a/utils/dataloaders.py b/utils/dataloaders.py index 68e3d283eb..e3227e8470 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Dataloaders and dataset utils.""" import contextlib diff --git a/utils/downloads.py b/utils/downloads.py index f756ad6772..54d02dcaee 100644 --- a/utils/downloads.py +++ b/utils/downloads.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Download utils.""" import logging diff --git a/utils/flask_rest_api/example_request.py b/utils/flask_rest_api/example_request.py index bf4fa0ba24..db88e80407 100644 --- a/utils/flask_rest_api/example_request.py +++ b/utils/flask_rest_api/example_request.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Perform test request.""" import pprint diff --git a/utils/flask_rest_api/restapi.py b/utils/flask_rest_api/restapi.py index 98930387cf..fa8af4833c 100644 --- a/utils/flask_rest_api/restapi.py +++ b/utils/flask_rest_api/restapi.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Run a Flask REST API exposing one or more YOLOv5s models.""" import argparse diff --git a/utils/general.py b/utils/general.py index e2f30ed301..e8572419cd 100644 --- a/utils/general.py +++ b/utils/general.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """General utils.""" import contextlib diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index 9e7ecce19d..8aaafd1c52 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Logging utils.""" import os diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py index 468dce1af3..215c830cb0 100644 --- a/utils/loggers/clearml/clearml_utils.py +++ b/utils/loggers/clearml/clearml_utils.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Main Logger class for ClearML experiment tracking.""" import glob diff --git a/utils/loss.py b/utils/loss.py index ab147f34c8..b3fa859838 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Loss functions.""" import torch diff --git a/utils/metrics.py b/utils/metrics.py index e0564cdb8e..205136547e 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Model validation metrics.""" import math diff --git a/utils/plots.py b/utils/plots.py index 2793df65d7..a8fa09c882 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Plotting utils.""" import contextlib diff --git a/utils/segment/augmentations.py b/utils/segment/augmentations.py index 09220f9822..cdec000e33 100644 --- a/utils/segment/augmentations.py +++ b/utils/segment/augmentations.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Image augmentation functions.""" import math diff --git a/utils/segment/dataloaders.py b/utils/segment/dataloaders.py index f666c8b9b8..ee4ed6c49f 100644 --- a/utils/segment/dataloaders.py +++ b/utils/segment/dataloaders.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Dataloaders.""" import os diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py index 9551ac2557..3ff6c6a58c 100644 --- a/utils/segment/metrics.py +++ b/utils/segment/metrics.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Model validation metrics.""" import numpy as np diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 1cf113cece..9b0f81d76a 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """PyTorch utils.""" import math diff --git a/utils/triton.py b/utils/triton.py index c216d699c9..630292e6eb 100644 --- a/utils/triton.py +++ b/utils/triton.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """Utils to interact with the Triton Inference Server.""" import typing diff --git a/val.py b/val.py index 924c6b9f21..e33a65816f 100644 --- a/val.py +++ b/val.py @@ -1,5 +1,4 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license - """ Validate a trained YOLOv3 detection model on a detection dataset. From 7b6052cd8bb14cff54eb46a40f8e5f7899ad70be Mon Sep 17 00:00:00 2001 From: RANJITH ROSAN M <91519971+RANJITHROSAN17@users.noreply.github.com> Date: Fri, 6 Jun 2025 06:05:30 +0530 Subject: [PATCH 1159/1185] Update requirements.txt (#2333) * Update requirements.txt Signed-off-by: RANJITH ROSAN M <91519971+RANJITHROSAN17@users.noreply.github.com> * Update requirements.txt Signed-off-by: RANJITH ROSAN M <91519971+RANJITHROSAN17@users.noreply.github.com> * Update requirements.txt Signed-off-by: RANJITH ROSAN M <91519971+RANJITHROSAN17@users.noreply.github.com> --------- Signed-off-by: RANJITH ROSAN M <91519971+RANJITHROSAN17@users.noreply.github.com> --- requirements.txt | 73 ++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/requirements.txt b/requirements.txt index c2dc8a08bf..41ba78257d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,49 +1,50 @@ # YOLOv3 requirements # Usage: pip install -r requirements.txt +# Python >= 3.8 recommended # Base ------------------------------------------------------------------------ -gitpython>=3.1.30 -matplotlib>=3.3 -numpy>=1.23.5 -opencv-python>=4.1.1 -Pillow>=10.3.0 -psutil # system resources -PyYAML>=5.3.1 -requests>=2.32.2 -scipy>=1.4.1 -thop>=0.1.1 # FLOPs computation -torch>=1.8.0 # see https://pytorch.org/get-started/locally (recommended) -torchvision>=0.9.0 -tqdm>=4.66.3 -ultralytics>=8.2.34 # https://ultralytics.com -# protobuf<=3.20.1 # https://github.com/ultralytics/yolov5/issues/8012 +gitpython>=3.1.30 # Git repo interaction for training/versioning +matplotlib>=3.5.0 # Plotting results and graphs +numpy>=1.23.5 # Fundamental for array/matrix operations +opencv-python>=4.1.1 # Image/video processing +Pillow>=10.3.0 # Image reading/writing support +psutil>=5.9.0 # System monitoring (RAM, CPU, etc.) +PyYAML>=5.3.1 # Reading configs (yaml files) +requests>=2.32.2 # HTTP requests, used in model hub/downloads +scipy>=1.4.1 # Scientific computing (e.g. IoU, metrics) +thop>=0.1.1 # Model profiling - FLOPs and parameter count +torch>=1.8.0 # Core PyTorch for training/inference +torchvision>=0.9.0 # Torch utilities for vision (transforms, datasets) +tqdm>=4.66.3 # Progress bar in CLI +ultralytics>=8.2.34 # YOLO framework library (models, training, utils) +# protobuf<=3.20.1 # For ONNX/TensorFlow export compatibility # Logging --------------------------------------------------------------------- -# tensorboard>=2.4.1 -# clearml>=1.2.0 -# comet +# tensorboard>=2.4.1 # Visual logging (scalars, images) +# clearml>=1.2.0 # Experiment tracking +# comet # Another logging/monitoring tool # Plotting -------------------------------------------------------------------- -pandas>=1.1.4 -seaborn>=0.11.0 +pandas>=1.1.4 # Data handling and manipulation +seaborn>=0.11.0 # Statistical data visualization (confusion matrix, etc.) -# Export ---------------------------------------------------------------------- -# coremltools>=6.0 # CoreML export -# onnx>=1.10.0 # ONNX export -# onnx-simplifier>=0.4.1 # ONNX simplifier -# nvidia-pyindex # TensorRT export -# nvidia-tensorrt # TensorRT export -# scikit-learn<=1.1.2 # CoreML quantization -# tensorflow>=2.4.0 # TF exports (-cpu, -aarch64, -macos) -# tensorflowjs>=3.9.0 # TF.js export -# openvino-dev>=2023.0 # OpenVINO export +# Export (optional) ----------------------------------------------------------- +# coremltools>=6.0 # Apple CoreML export support +# onnx>=1.10.0 # ONNX export support +# onnx-simplifier>=0.4.1 # Optimizes ONNX models +# nvidia-pyindex # Required for installing NVIDIA TensorRT +# nvidia-tensorrt # TensorRT export and inference +# scikit-learn<=1.1.2 # Used in CoreML quantization (used in older code) +# tensorflow>=2.4.0 # TensorFlow export +# tensorflowjs>=3.9.0 # TensorFlow.js export +# openvino-dev>=2023.0 # Intel OpenVINO export # Deploy ---------------------------------------------------------------------- -setuptools>=70.0.0 # Snyk vulnerability fix -# tritonclient[all]~=2.24.0 +setuptools>=70.0.0 # Required to avoid known vulnerabilities +# tritonclient[all]~=2.24.0 # NVIDIA Triton server deployment (optional) # Extras ---------------------------------------------------------------------- -# ipython # interactive notebook -# mss # screenshots -# albumentations>=1.0.3 -# pycocotools>=2.0.6 # COCO mAP +# ipython # Enhanced interactive shell +# mss # Screenshot capturing for inference UI +# albumentations>=1.0.3 # Powerful image augmentation library +# pycocotools>=2.0.6 # COCO dataset metrics (mAP, etc.) From c7044ce2e9b072e9a7908c1d2d8cde724f4a8851 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 5 Jun 2025 18:15:54 -0700 Subject: [PATCH 1160/1185] Potential fix for code scanning alert no. 8: Workflow does not contain permissions (#2334) Signed-off-by: Glenn Jocher Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/ci-testing.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 3912e9940e..4af020c8d8 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -4,6 +4,9 @@ name: YOLOv3 CI +permissions: + contents: read + on: push: branches: [master] From 0012300e3e202ee2ce7e9907eb86807556102d58 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 12 Jun 2025 16:05:45 +0200 Subject: [PATCH 1161/1185] Update links.yml (#2335) Signed-off-by: Glenn Jocher --- .github/workflows/links.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 3d871f65a6..8227b01424 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -37,12 +37,12 @@ jobs: --scheme 'https' \ --timeout 60 \ --insecure \ - --accept 403,429,500,502,999 \ + --accept 100..=103,200..=299,401,403,429,500,502,999 \ --exclude-all-private \ --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|x\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ --exclude-path '**/ci.yaml' \ --github-token ${{ secrets.GITHUB_TOKEN }} \ - --header "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \ + --header "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \ './**/*.md' \ './**/*.html' | tee -a $GITHUB_STEP_SUMMARY @@ -63,12 +63,12 @@ jobs: --scheme 'https' \ --timeout 60 \ --insecure \ - --accept 429,999 \ + --accept 100..=103,200..=299,429,999 \ --exclude-all-private \ --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|x\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ --exclude-path '**/ci.yaml' \ --github-token ${{ secrets.GITHUB_TOKEN }} \ - --header "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \ + --header "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \ './**/*.md' \ './**/*.html' \ './**/*.yml' \ From 13fc201188df4b3137c4eab8dc383755a5062d4e Mon Sep 17 00:00:00 2001 From: Jing Qiu <61612323+Laughing-q@users.noreply.github.com> Date: Fri, 4 Jul 2025 18:08:09 +0800 Subject: [PATCH 1162/1185] FIx downstream impact by the replacement of `torch.load` in `ultralytics` package (#2338) * use torch_load * update ultralytics version * Auto-format by https://ultralytics.com/actions * Update segment/train.py * Auto-format by https://ultralytics.com/actions --------- Co-authored-by: UltralyticsAssistant --- hubconf.py | 4 ++-- models/experimental.py | 3 ++- pyproject.toml | 2 +- requirements.txt | 2 +- segment/train.py | 6 ++++-- train.py | 6 ++++-- utils/aws/resume.py | 3 ++- utils/general.py | 3 ++- 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/hubconf.py b/hubconf.py index 53fe1cfcbb..79a73a43ef 100644 --- a/hubconf.py +++ b/hubconf.py @@ -10,7 +10,7 @@ model = torch.hub.load('.', 'custom', 'yolov5s.pt', source='local') # local repo """ -import torch +from ultralytics.utils.patches import torch_load def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): @@ -79,7 +79,7 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbo cfg = list((Path(__file__).parent / "models").rglob(f"{path.stem}.yaml"))[0] # model.yaml path model = DetectionModel(cfg, channels, classes) # create model if pretrained: - ckpt = torch.load(attempt_download(path), map_location=device) # load + ckpt = torch_load(attempt_download(path), map_location=device) # load csd = ckpt["model"].float().state_dict() # checkpoint state_dict as FP32 csd = intersect_dicts(csd, model.state_dict(), exclude=["anchors"]) # intersect model.load_state_dict(csd, strict=False) # load diff --git a/models/experimental.py b/models/experimental.py index 50d1cd0d4a..990e815243 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -6,6 +6,7 @@ import numpy as np import torch import torch.nn as nn +from ultralytics.utils.patches import torch_load from utils.downloads import attempt_download @@ -97,7 +98,7 @@ def attempt_load(weights, device=None, inplace=True, fuse=True): model = Ensemble() for w in weights if isinstance(weights, list) else [weights]: - ckpt = torch.load(attempt_download(w), map_location="cpu") # load + ckpt = torch_load(attempt_download(w), map_location="cpu") # load ckpt = (ckpt.get("ema") or ckpt["model"]).to(device).float() # FP32 model # Model compatibility updates diff --git a/pyproject.toml b/pyproject.toml index 146694a176..e49c0f5709 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,7 +77,7 @@ dependencies = [ "thop>=0.1.1", # FLOPs computation "pandas>=1.1.4", "seaborn>=0.11.0", # plotting - "ultralytics>=8.0.232" + "ultralytics>=8.2.64" ] # Optional dependencies ------------------------------------------------------------------------------------------------ diff --git a/requirements.txt b/requirements.txt index 41ba78257d..cc59229b25 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,7 +16,7 @@ thop>=0.1.1 # Model profiling - FLOPs and parameter count torch>=1.8.0 # Core PyTorch for training/inference torchvision>=0.9.0 # Torch utilities for vision (transforms, datasets) tqdm>=4.66.3 # Progress bar in CLI -ultralytics>=8.2.34 # YOLO framework library (models, training, utils) +ultralytics>=8.2.64 # YOLO framework library (models, training, utils) # protobuf<=3.20.1 # For ONNX/TensorFlow export compatibility # Logging --------------------------------------------------------------------- diff --git a/segment/train.py b/segment/train.py index 78ade178da..28a9e4f0fb 100644 --- a/segment/train.py +++ b/segment/train.py @@ -40,6 +40,8 @@ sys.path.append(str(ROOT)) # add ROOT to PATH ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative +from ultralytics.utils.patches import torch_load + import segment.val as validate # for end-of-epoch mAP from models.experimental import attempt_load from models.yolo import SegmentationModel @@ -172,7 +174,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio if pretrained: with torch_distributed_zero_first(LOCAL_RANK): weights = attempt_download(weights) # download if not found locally - ckpt = torch.load(weights, map_location="cpu") # load checkpoint to CPU to avoid CUDA memory leak + ckpt = torch_load(weights, map_location="cpu") # load checkpoint to CPU to avoid CUDA memory leak model = SegmentationModel(cfg or ckpt["model"].yaml, ch=3, nc=nc, anchors=hyp.get("anchors")).to(device) exclude = ["anchor"] if (cfg or hyp.get("anchors")) and not resume else [] # exclude keys csd = ckpt["model"].float().state_dict() # checkpoint state_dict as FP32 @@ -601,7 +603,7 @@ def main(opt, callbacks=Callbacks()): with open(opt_yaml, errors="ignore") as f: d = yaml.safe_load(f) else: - d = torch.load(last, map_location="cpu")["opt"] + d = torch_load(last, map_location="cpu")["opt"] opt = argparse.Namespace(**d) # replace opt.cfg, opt.weights, opt.resume = "", str(last), True # reinstate if is_url(opt_data): diff --git a/train.py b/train.py index ba4784ee90..a2671f5d1d 100644 --- a/train.py +++ b/train.py @@ -44,6 +44,8 @@ sys.path.append(str(ROOT)) # add ROOT to PATH ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative +from ultralytics.utils.patches import torch_load + import val as validate # for end-of-epoch mAP from models.experimental import attempt_load from models.yolo import Model @@ -214,7 +216,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio if pretrained: with torch_distributed_zero_first(LOCAL_RANK): weights = attempt_download(weights) # download if not found locally - ckpt = torch.load(weights, map_location="cpu") # load checkpoint to CPU to avoid CUDA memory leak + ckpt = torch_load(weights, map_location="cpu") # load checkpoint to CPU to avoid CUDA memory leak model = Model(cfg or ckpt["model"].yaml, ch=3, nc=nc, anchors=hyp.get("anchors")).to(device) # create exclude = ["anchor"] if (cfg or hyp.get("anchors")) and not resume else [] # exclude keys csd = ckpt["model"].float().state_dict() # checkpoint state_dict as FP32 @@ -661,7 +663,7 @@ def main(opt, callbacks=Callbacks()): with open(opt_yaml, errors="ignore") as f: d = yaml.safe_load(f) else: - d = torch.load(last, map_location="cpu")["opt"] + d = torch_load(last, map_location="cpu")["opt"] opt = argparse.Namespace(**d) # replace opt.cfg, opt.weights, opt.resume = "", str(last), True # reinstate if is_url(opt_data): diff --git a/utils/aws/resume.py b/utils/aws/resume.py index 1924ea845e..805dadf4d5 100644 --- a/utils/aws/resume.py +++ b/utils/aws/resume.py @@ -9,6 +9,7 @@ import torch import yaml +from ultralytics.utils.patches import torch_load FILE = Path(__file__).resolve() ROOT = FILE.parents[2] # YOLOv3 root directory @@ -18,7 +19,7 @@ port = 0 # --master_port path = Path("").resolve() for last in path.rglob("*/**/last.pt"): - ckpt = torch.load(last) + ckpt = torch_load(last) if ckpt["optimizer"] is None: continue diff --git a/utils/general.py b/utils/general.py index e8572419cd..1c35704eaa 100644 --- a/utils/general.py +++ b/utils/general.py @@ -34,6 +34,7 @@ import torchvision import yaml from ultralytics.utils.checks import check_requirements +from ultralytics.utils.patches import torch_load from utils import TryExcept, emojis from utils.downloads import curl_download, gsutil_getsize @@ -1119,7 +1120,7 @@ def non_max_suppression( def strip_optimizer(f="best.pt", s=""): # from utils.general import *; strip_optimizer() """Strips optimizer from a checkpoint file 'f', optionally saving as 's', to finalize training.""" - x = torch.load(f, map_location=torch.device("cpu")) + x = torch_load(f, map_location=torch.device("cpu")) if x.get("ema"): x["model"] = x["ema"] # replace model with ema for k in "optimizer", "best_fitness", "ema", "updates": # keys From 136151ed6f4f55cf87385d37c989f07ce6339533 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 3 Aug 2025 17:33:52 +0800 Subject: [PATCH 1163/1185] Simplify lychee install in links.yml (#2339) Signed-off-by: Glenn Jocher --- .github/workflows/links.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 8227b01424..6d062f8107 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -21,10 +21,8 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Download and install lychee - run: | - LYCHEE_URL=$(curl -s https://api.github.com/repos/lycheeverse/lychee/releases/latest | grep "browser_download_url" | grep "x86_64-unknown-linux-gnu.tar.gz" | cut -d '"' -f 4) - curl -L $LYCHEE_URL | tar xz -C /usr/local/bin + - name: Install lychee + run: curl -sSfL "https://github.com/lycheeverse/lychee/releases/latest/download/lychee-x86_64-unknown-linux-gnu.tar.gz" | sudo tar xz -C /usr/local/bin - name: Test Markdown and HTML links with retry uses: ultralytics/actions/retry@main From 97adffd2a7675fcd8dc0fea3c009c117ade982f1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 14 Aug 2025 10:49:19 +0200 Subject: [PATCH 1164/1185] Pin `tensorflow>=2.0.0,<=2.19.0` (#2341) Signed-off-by: Glenn Jocher --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e49c0f5709..9ba98d679c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,7 @@ export = [ "onnx>=1.12.0", # ONNX export "coremltools>=7.0; platform_system != 'Windows'", # CoreML only supported on macOS and Linux "openvino-dev>=2023.0", # OpenVINO export - "tensorflow>=2.0.0", # TF bug https://github.com/ultralytics/ultralytics/issues/5161 + "tensorflow>=2.0.0,<=2.19.0", # TF bug https://github.com/ultralytics/ultralytics/issues/5161 "tensorflowjs>=3.9.0", # TF.js export, automatically installs tensorflow ] # tensorflow>=2.4.1,<=2.13.1 # TF exports (-cpu, -aarch64, -macos) From c6c2bf81f28f847c0bd1cb431c1d51a6b25d12af Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sat, 23 Aug 2025 10:49:00 +0200 Subject: [PATCH 1165/1185] Update links.yml for Lychee v0.20.0 (#2342) Update links.yml Signed-off-by: Glenn Jocher --- .github/workflows/links.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 6d062f8107..51b3783351 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -38,7 +38,7 @@ jobs: --accept 100..=103,200..=299,401,403,429,500,502,999 \ --exclude-all-private \ --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|x\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ - --exclude-path '**/ci.yaml' \ + --exclude-path './**/ci.yaml' \ --github-token ${{ secrets.GITHUB_TOKEN }} \ --header "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \ './**/*.md' \ @@ -64,7 +64,7 @@ jobs: --accept 100..=103,200..=299,429,999 \ --exclude-all-private \ --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|x\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ - --exclude-path '**/ci.yaml' \ + --exclude-path './**/ci.yaml' \ --github-token ${{ secrets.GITHUB_TOKEN }} \ --header "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \ './**/*.md' \ From 993e97bc8435a8b85f170716e2664a9da5728be0 Mon Sep 17 00:00:00 2001 From: Paula Derrenger <107626595+pderrenger@users.noreply.github.com> Date: Sun, 24 Aug 2025 17:45:07 -0700 Subject: [PATCH 1166/1185] Ultralytics Refactor https://ultralytics.com/actions (#2344) Refactor code for speed and clarity Co-authored-by: Glenn Jocher --- .github/ISSUE_TEMPLATE/bug-report.yml | 2 +- .github/ISSUE_TEMPLATE/feature-request.yml | 2 +- .github/workflows/links.yml | 4 ++-- README.md | 2 +- README.zh-CN.md | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index b55f34f14f..aa23edc76c 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -82,6 +82,6 @@ body: label: Are you willing to submit a PR? description: > (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. - See the YOLOv3 [Contributing Guide](https://docs.ultralytics.com/help/contributing) to get started. + See the YOLOv3 [Contributing Guide](https://docs.ultralytics.com/help/contributing/) to get started. options: - label: Yes I'd like to help by submitting a PR! diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index befa9d55c7..164e49e459 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -47,6 +47,6 @@ body: label: Are you willing to submit a PR? description: > (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. - See the YOLOv3 [Contributing Guide](https://docs.ultralytics.com/help/contributing) to get started. + See the YOLOv3 [Contributing Guide](https://docs.ultralytics.com/help/contributing/) to get started. options: - label: Yes I'd like to help by submitting a PR! diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 51b3783351..41cd5ca9f6 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -38,7 +38,7 @@ jobs: --accept 100..=103,200..=299,401,403,429,500,502,999 \ --exclude-all-private \ --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|x\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ - --exclude-path './**/ci.yaml' \ + --exclude-path './**/ci.yml' \ --github-token ${{ secrets.GITHUB_TOKEN }} \ --header "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \ './**/*.md' \ @@ -64,7 +64,7 @@ jobs: --accept 100..=103,200..=299,429,999 \ --exclude-all-private \ --exclude 'https?://(www\.)?(linkedin\.com|twitter\.com|x\.com|instagram\.com|kaggle\.com|fonts\.gstatic\.com|url\.com)' \ - --exclude-path './**/ci.yaml' \ + --exclude-path './**/ci.yml' \ --github-token ${{ secrets.GITHUB_TOKEN }} \ --header "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.183 Safari/537.36" \ './**/*.md' \ diff --git a/README.md b/README.md index d6b6724817..1c7fd959f3 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Ultralytics YOLOv3 banner

-[中文](https://docs.ultralytics.com/zh) | [한국어](https://docs.ultralytics.com/ko) | [日本語](https://docs.ultralytics.com/ja) | [Русский](https://docs.ultralytics.com/ru) | [Deutsch](https://docs.ultralytics.com/de) | [Français](https://docs.ultralytics.com/fr) | [Español](https://docs.ultralytics.com/es) | [Português](https://docs.ultralytics.com/pt) | [Türkçe](https://docs.ultralytics.com/tr) | [Tiếng Việt](https://docs.ultralytics.com/vi) | [العربية](https://docs.ultralytics.com/ar) +[中文](https://docs.ultralytics.com/zh/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es) | [Português](https://docs.ultralytics.com/pt/) | [Türkçe](https://docs.ultralytics.com/tr/) | [Tiếng Việt](https://docs.ultralytics.com/vi/) | [العربية](https://docs.ultralytics.com/ar/)
YOLOv3 CI diff --git a/README.zh-CN.md b/README.zh-CN.md index 72e7a0bdf8..1de8f6e410 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -6,7 +6,7 @@ Ultralytics YOLOv3 banner

-[English](https://docs.ultralytics.com/) | [한국어](https://docs.ultralytics.com/ko) | [日本語](https://docs.ultralytics.com/ja) | [Русский](https://docs.ultralytics.com/ru) | [Deutsch](https://docs.ultralytics.com/de) | [Français](https://docs.ultralytics.com/fr) | [Español](https://docs.ultralytics.com/es) | [Português](https://docs.ultralytics.com/pt) | [Türkçe](https://docs.ultralytics.com/tr) | [Tiếng Việt](https://docs.ultralytics.com/vi) | [العربية](https://docs.ultralytics.com/ar) +[English](https://docs.ultralytics.com/) | [한국어](https://docs.ultralytics.com/ko/) | [日本語](https://docs.ultralytics.com/ja/) | [Русский](https://docs.ultralytics.com/ru/) | [Deutsch](https://docs.ultralytics.com/de/) | [Français](https://docs.ultralytics.com/fr/) | [Español](https://docs.ultralytics.com/es) | [Português](https://docs.ultralytics.com/pt/) | [Türkçe](https://docs.ultralytics.com/tr/) | [Tiếng Việt](https://docs.ultralytics.com/vi/) | [العربية](https://docs.ultralytics.com/ar/)
YOLOv3 CI From 41330da42d595178c23fcc3064b88e9a3de8747d Mon Sep 17 00:00:00 2001 From: Muhammad Rizwan Munawar Date: Tue, 26 Aug 2025 14:30:19 +0500 Subject: [PATCH 1167/1185] Update banners redirect to https://www.ultralytics.com/events/yolovision (#2345) * Update YOLO event link in README Signed-off-by: Muhammad Rizwan Munawar * Update YOLO event link in Chinese README Signed-off-by: Muhammad Rizwan Munawar --------- Signed-off-by: Muhammad Rizwan Munawar --- README.md | 2 +- README.zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1c7fd959f3..812cbeca99 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- + Ultralytics YOLOv3 banner

diff --git a/README.zh-CN.md b/README.zh-CN.md index 1de8f6e410..6ca478ab55 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -2,7 +2,7 @@

- + Ultralytics YOLOv3 banner

From ecd11a6309e227cee0a83ad92fb587236810e488 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Oct 2025 14:13:18 +0200 Subject: [PATCH 1168/1185] Bump pip from 23.3 to 25.2 in /utils/google_app_engine (#2346) * Bump pip from 23.3 to 25.2 in /utils/google_app_engine Bumps [pip](https://github.com/pypa/pip) from 23.3 to 25.2. - [Changelog](https://github.com/pypa/pip/blob/main/NEWS.rst) - [Commits](https://github.com/pypa/pip/compare/23.3...25.2) --- updated-dependencies: - dependency-name: pip dependency-version: '25.2' dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Auto-format by https://ultralytics.com/actions --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: UltralyticsAssistant --- utils/google_app_engine/additional_requirements.txt | 2 +- utils/triton.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/google_app_engine/additional_requirements.txt b/utils/google_app_engine/additional_requirements.txt index bf7cf8868e..e86bac0a17 100644 --- a/utils/google_app_engine/additional_requirements.txt +++ b/utils/google_app_engine/additional_requirements.txt @@ -1,5 +1,5 @@ # add these requirements in your app on top of the existing ones -pip==23.3 +pip==25.2 Flask==2.3.2 gunicorn==23.0.0 werkzeug>=3.0.1 # not directly required, pinned by Snyk to avoid a vulnerability diff --git a/utils/triton.py b/utils/triton.py index 630292e6eb..20f317e651 100644 --- a/utils/triton.py +++ b/utils/triton.py @@ -29,7 +29,7 @@ def __init__(self, url: str): self.model_name = model_repository.models[0].name self.metadata = self.client.get_model_metadata(self.model_name, as_json=True) - def create_input_placeholders() -> typing.List[InferInput]: + def create_input_placeholders() -> list[InferInput]: return [ InferInput(i["name"], [int(s) for s in i["shape"]], i["datatype"]) for i in self.metadata["inputs"] ] @@ -42,7 +42,7 @@ def create_input_placeholders() -> typing.List[InferInput]: self.model_name = model_repository[0]["name"] self.metadata = self.client.get_model_metadata(self.model_name) - def create_input_placeholders() -> typing.List[InferInput]: + def create_input_placeholders() -> list[InferInput]: return [ InferInput(i["name"], [int(s) for s in i["shape"]], i["datatype"]) for i in self.metadata["inputs"] ] @@ -54,7 +54,7 @@ def runtime(self): """Returns the model runtime.""" return self.metadata.get("backend", self.metadata.get("platform")) - def __call__(self, *args, **kwargs) -> typing.Union[torch.Tensor, typing.Tuple[torch.Tensor, ...]]: + def __call__(self, *args, **kwargs) -> typing.Union[torch.Tensor, tuple[torch.Tensor, ...]]: """ Invokes the model. From 61cb5a37399acbadb089b186dcb351baea2c7283 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Oct 2025 15:27:20 +0200 Subject: [PATCH 1169/1185] Potential fix for code scanning alert no. 4: Workflow does not contain permissions (#2350) * Potential fix for code scanning alert no. 4: Workflow does not contain permissions Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> Signed-off-by: Glenn Jocher * Update docker.yml Signed-off-by: Glenn Jocher --------- Signed-off-by: Glenn Jocher Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/docker.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8ca4f3662c..d9a2b07254 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -4,6 +4,9 @@ name: Publish Docker Images +permissions: + contents: read + on: push: branches: [master] From 8625472ae9a282b3a0fd4b69f54c340577832f54 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Oct 2025 15:27:25 +0200 Subject: [PATCH 1170/1185] Potential fix for code scanning alert no. 7: Workflow does not contain permissions (#2349) Signed-off-by: Glenn Jocher Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/merge-main-into-prs.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/merge-main-into-prs.yml b/.github/workflows/merge-main-into-prs.yml index 0cae77e268..22f7aca454 100644 --- a/.github/workflows/merge-main-into-prs.yml +++ b/.github/workflows/merge-main-into-prs.yml @@ -15,6 +15,9 @@ jobs: Merge: if: github.repository == 'ultralytics/yolov3' runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write steps: - name: Checkout repository uses: actions/checkout@v4 From c00723deeb0e2c477f3a29c689007090bc8e86c4 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Oct 2025 15:27:39 +0200 Subject: [PATCH 1171/1185] Potential fix for code scanning alert no. 9: Workflow does not contain permissions (#2348) * Potential fix for code scanning alert no. 9: Workflow does not contain permissions Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> Signed-off-by: Glenn Jocher * Update stale.yml Signed-off-by: Glenn Jocher --------- Signed-off-by: Glenn Jocher Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/stale.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index fda092a442..6483ac2639 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,6 +1,12 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license name: Close stale issues + +permissions: + contents: read + issues: write + pull-requests: write + on: schedule: - cron: "0 0 * * *" # Runs at 00:00 UTC every day From 33924cc9ec55a3b07bc6d554c0a7e7d387a3d4dd Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 10 Oct 2025 15:28:22 +0200 Subject: [PATCH 1172/1185] Potential fix for code scanning alert no. 10: Workflow does not contain permissions (#2347) Signed-off-by: Glenn Jocher Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/links.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 41cd5ca9f6..a71e49ce5b 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -10,6 +10,9 @@ name: Check Broken links +permissions: + contents: read + on: workflow_dispatch: schedule: From b0e88bc14b1eaa2bebc4eac22fcd8fea9f66f16d Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 12 Oct 2025 23:38:14 +0200 Subject: [PATCH 1173/1185] Create dependabot.yml (#2351) Signed-off-by: Glenn Jocher --- .github/dependabot.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..56c78219fe --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,24 @@ +# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license + +# Dependabot for package version updates +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: pip + directory: "/" + schedule: + interval: weekly + time: "04:00" + open-pull-requests-limit: 10 + labels: + - dependencies + + - package-ecosystem: github-actions + directory: "/.github/workflows" + schedule: + interval: weekly + time: "04:00" + open-pull-requests-limit: 5 + labels: + - dependencies From 8a2f3716e61ad0ee2d0ae80da53077f2e030de93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 05:21:13 +0200 Subject: [PATCH 1174/1185] Bump slackapi/slack-github-action from 2.0.0 to 2.1.1 in /.github/workflows (#2355) Bump slackapi/slack-github-action in /.github/workflows Bumps [slackapi/slack-github-action](https://github.com/slackapi/slack-github-action) from 2.0.0 to 2.1.1. - [Release notes](https://github.com/slackapi/slack-github-action/releases) - [Commits](https://github.com/slackapi/slack-github-action/compare/v2.0.0...v2.1.1) --- updated-dependencies: - dependency-name: slackapi/slack-github-action dependency-version: 2.1.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 4af020c8d8..3160c182fc 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -119,7 +119,7 @@ jobs: steps: - name: Check for failure and notify if: (needs.Tests.result == 'failure' || needs.Tests.result == 'cancelled') && github.repository == 'ultralytics/yolov3' && (github.event_name == 'schedule' || github.event_name == 'push') - uses: slackapi/slack-github-action@v2.0.0 + uses: slackapi/slack-github-action@v2.1.1 with: webhook-type: incoming-webhook webhook: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }} From 1318c219b6fd8be6462f00552f41d98c5156f964 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 05:16:47 +0200 Subject: [PATCH 1175/1185] Bump actions/stale from 9 to 10 in /.github/workflows (#2354) Bumps [actions/stale](https://github.com/actions/stale) from 9 to 10. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v9...v10) --- updated-dependencies: - dependency-name: actions/stale dependency-version: '10' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 6483ac2639..81e345de61 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -15,7 +15,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v9 + - uses: actions/stale@v10 with: repo-token: ${{ secrets.GITHUB_TOKEN }} From 960324c7bf62303f54130ad27b9eddd4f9f76e12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 05:18:36 +0200 Subject: [PATCH 1176/1185] Bump actions/setup-python from 5 to 6 in /.github/workflows (#2353) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- .github/workflows/ci-testing.yml | 2 +- .github/workflows/merge-main-into-prs.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 3160c182fc..b70c844a37 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -39,7 +39,7 @@ jobs: torch: "1.8.0" # min torch version CI https://pypi.org/project/torchvision/ steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} cache: "pip" # caching pip dependencies diff --git a/.github/workflows/merge-main-into-prs.yml b/.github/workflows/merge-main-into-prs.yml index 22f7aca454..ba4482632b 100644 --- a/.github/workflows/merge-main-into-prs.yml +++ b/.github/workflows/merge-main-into-prs.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: "3.x" cache: "pip" From 4e2621d53b621a599f0e0aa54e4b38383e81759a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Oct 2025 05:18:39 +0200 Subject: [PATCH 1177/1185] Bump actions/checkout from 4 to 5 in /.github/workflows (#2352) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: Glenn Jocher Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Glenn Jocher --- .github/workflows/ci-testing.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/links.yml | 2 +- .github/workflows/merge-main-into-prs.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index b70c844a37..32fdd9180d 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -38,7 +38,7 @@ jobs: model: yolov5n torch: "1.8.0" # min torch version CI https://pypi.org/project/torchvision/ steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index d9a2b07254..298d381b1f 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up QEMU uses: docker/setup-qemu-action@v3 diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index a71e49ce5b..2b87ba6f43 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -22,7 +22,7 @@ jobs: Links: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install lychee run: curl -sSfL "https://github.com/lycheeverse/lychee/releases/latest/download/lychee-x86_64-unknown-linux-gnu.tar.gz" | sudo tar xz -C /usr/local/bin diff --git a/.github/workflows/merge-main-into-prs.yml b/.github/workflows/merge-main-into-prs.yml index ba4482632b..22e551ce4a 100644 --- a/.github/workflows/merge-main-into-prs.yml +++ b/.github/workflows/merge-main-into-prs.yml @@ -20,7 +20,7 @@ jobs: pull-requests: write steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 - uses: actions/setup-python@v6 From 5ebeb2ac7751fb0c4babd55ac37de591340be2d1 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Fri, 24 Oct 2025 12:05:16 +0200 Subject: [PATCH 1178/1185] Ruff `RUF` refactor (#2357) * Ruff `RUF` refactor Signed-off-by: Glenn Jocher * Auto-format by https://ultralytics.com/actions --------- Signed-off-by: Glenn Jocher Co-authored-by: UltralyticsAssistant --- export.py | 14 ++++++-------- hubconf.py | 2 +- models/common.py | 6 +++--- models/tf.py | 2 +- models/yolo.py | 2 +- utils/__init__.py | 2 +- utils/augmentations.py | 8 ++++---- utils/dataloaders.py | 6 +++--- utils/general.py | 7 ++++--- utils/loggers/__init__.py | 10 +++++----- utils/loggers/wandb/wandb_utils.py | 2 +- utils/metrics.py | 2 +- utils/plots.py | 12 ++++++------ utils/segment/general.py | 2 +- utils/torch_utils.py | 2 +- utils/triton.py | 5 +++-- 16 files changed, 42 insertions(+), 42 deletions(-) diff --git a/export.py b/export.py index 56ab25b3c8..7fcd37a8eb 100644 --- a/export.py +++ b/export.py @@ -114,7 +114,7 @@ def __init__(self, model, im): - Ensure the sample input image `im` provided has correct dimensions and shape for accurate model configuration. """ super().__init__() - b, c, h, w = im.shape # batch, channel, height, width + _b, _c, h, w = im.shape # batch, channel, height, width self.model = model self.nc = model.nc # number of classes if w == h: @@ -415,8 +415,8 @@ def export_openvino(file, metadata, half, int8, data, prefix=colorstr("OpenVINO: ``` """ check_requirements("openvino-dev>=2023.0") # requires openvino-dev: https://pypi.org/project/openvino-dev/ - import openvino.runtime as ov # noqa - from openvino.tools import mo # noqa + import openvino.runtime as ov + from openvino.tools import mo LOGGER.info(f"\n{prefix} starting export with openvino {ov.__version__}...") f = str(file).replace(file.suffix, f"_openvino_model{os.sep}") @@ -451,8 +451,6 @@ def gen_dataloader(yaml_path, task="train", imgsz=640, workers=4): )[0] return dataloader - # noqa: F811 - def transform_fn(data_item): """ Quantization transform function. @@ -871,7 +869,7 @@ def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=c import tensorflow as tf LOGGER.info(f"\n{prefix} starting export with tensorflow {tf.__version__}...") - batch_size, ch, *imgsz = list(im.shape) # BCHW + _batch_size, _ch, *imgsz = list(im.shape) # BCHW f = str(file).replace(".pt", "-fp16.tflite") converter = tf.lite.TFLiteConverter.from_keras_model(keras_model) @@ -1200,7 +1198,7 @@ def pipeline_coreml(model, im, file, names, y, prefix=colorstr("CoreML Pipeline: from PIL import Image print(f"{prefix} starting pipeline with coremltools {ct.__version__}...") - batch_size, ch, h, w = list(im.shape) # BCHW + _batch_size, _ch, h, w = list(im.shape) # BCHW t = time.time() # YOLOv3 Output shapes @@ -1217,7 +1215,7 @@ def pipeline_coreml(model, im, file, names, y, prefix=colorstr("CoreML Pipeline: # Checks nx, ny = spec.description.input[0].type.imageType.width, spec.description.input[0].type.imageType.height - na, nc = out0_shape + _na, nc = out0_shape # na, nc = out0.type.multiArrayType.shape # number anchors, classes assert len(names) == nc, f"{len(names)} names found for nc={nc}" # check diff --git a/hubconf.py b/hubconf.py index 79a73a43ef..a0031e4cf8 100644 --- a/hubconf.py +++ b/hubconf.py @@ -76,7 +76,7 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbo except Exception: model = attempt_load(path, device=device, fuse=False) # arbitrary model else: - cfg = list((Path(__file__).parent / "models").rglob(f"{path.stem}.yaml"))[0] # model.yaml path + cfg = next(iter((Path(__file__).parent / "models").rglob(f"{path.stem}.yaml"))) # model.yaml path model = DetectionModel(cfg, channels, classes) # create model if pretrained: ckpt = torch_load(attempt_download(path), map_location=device) # load diff --git a/models/common.py b/models/common.py index 9372150e86..c0c6511593 100644 --- a/models/common.py +++ b/models/common.py @@ -647,7 +647,7 @@ def gd_outputs(gd): def forward(self, im, augment=False, visualize=False): """Performs YOLOv3 inference on an input image tensor, optionally with augmentation and visualization.""" - b, ch, h, w = im.shape # batch, channel, height, width + _b, _ch, h, w = im.shape # batch, channel, height, width if self.fp16 and im.dtype != torch.float16: im = im.half() # to FP16 if self.nhwc: @@ -759,7 +759,7 @@ def _model_type(p="path/to/model.pt"): types = [s in Path(p).name for s in sf] types[8] &= not types[9] # tflite &= not edgetpu triton = not any(types) and all([any(s in url.scheme for s in ["http", "grpc"]), url.netloc]) - return types + [triton] + return [*types, triton] @staticmethod def _load_metadata(f=Path("path/to/meta.yaml")): @@ -998,7 +998,7 @@ def pandas(self): ca = "xmin", "ymin", "xmax", "ymax", "confidence", "class", "name" # xyxy columns cb = "xcenter", "ycenter", "width", "height", "confidence", "class", "name" # xywh columns for k, c in zip(["xyxy", "xyxyn", "xywh", "xywhn"], [ca, ca, cb, cb]): - a = [[x[:5] + [int(x[5]), self.names[int(x[5])]] for x in x.tolist()] for x in getattr(self, k)] # update + a = [[[*x[:5], int(x[5]), self.names[int(x[5])]] for x in x.tolist()] for x in getattr(self, k)] # update setattr(new, k, [pd.DataFrame(x, columns=c) for x in a]) return new diff --git a/models/tf.py b/models/tf.py index 5f6f2a6374..caa90c1ca0 100644 --- a/models/tf.py +++ b/models/tf.py @@ -546,7 +546,7 @@ def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3) t = str(m)[8:-2].replace("__main__.", "") # module type np = sum(x.numel() for x in torch_m_.parameters()) # number params m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params - LOGGER.info(f"{i:>3}{str(f):>18}{str(n):>3}{np:>10} {t:<40}{str(args):<30}") # print + LOGGER.info(f"{i:>3}{f!s:>18}{n!s:>3}{np:>10} {t:<40}{args!s:<30}") # print save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist layers.append(m_) ch.append(c2) diff --git a/models/yolo.py b/models/yolo.py index 7b00e7ef67..79942c32cb 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -410,7 +410,7 @@ def parse_model(d, ch): # model_dict, input_channels(3) t = str(m)[8:-2].replace("__main__.", "") # module type np = sum(x.numel() for x in m_.parameters()) # number params m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params - LOGGER.info(f"{i:>3}{str(f):>18}{n_:>3}{np:10.0f} {t:<40}{str(args):<30}") # print + LOGGER.info(f"{i:>3}{f!s:>18}{n_:>3}{np:10.0f} {t:<40}{args!s:<30}") # print save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist layers.append(m_) if i == 0: diff --git a/utils/__init__.py b/utils/__init__.py index a7b86410d0..71d21d5a8f 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -91,7 +91,7 @@ def notebook_init(verbose=True): if verbose: gb = 1 << 30 # bytes to GiB (1024 ** 3) ram = psutil.virtual_memory().total - total, used, free = shutil.disk_usage("/") + total, _used, free = shutil.disk_usage("/") with contextlib.suppress(Exception): # clear display if ipython is installed from IPython import display diff --git a/utils/augmentations.py b/utils/augmentations.py index 65a0435758..824066f309 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -132,7 +132,7 @@ def letterbox(im, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleF # Compute padding ratio = r, r # width, height ratios - new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) + new_unpad = round(shape[1] * r), round(shape[0] * r) dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding if auto: # minimum rectangle dw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh padding @@ -146,8 +146,8 @@ def letterbox(im, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleF if shape[::-1] != new_unpad: # resize im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR) - top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) - left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) + top, bottom = round(dh - 0.1), round(dh + 0.1) + left, right = round(dw - 0.1), round(dw + 0.1) im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border return im, ratio, (dw, dh) @@ -240,7 +240,7 @@ def copy_paste(im, labels, segments, p=0.5): """ n = len(segments) if p and n: - h, w, c = im.shape # height, width, channels + _h, w, _c = im.shape # height, width, channels im_new = np.zeros(im.shape, np.uint8) for j in random.sample(range(n), k=round(p * n)): l, s = labels[j], segments[j] diff --git a/utils/dataloaders.py b/utils/dataloaders.py index e3227e8470..f5edffaaf6 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -1008,11 +1008,11 @@ def collate_fn4(batch): # Ancillary functions -------------------------------------------------------------------------------------------------- def flatten_recursive(path=DATASETS_DIR / "coco128"): """Flattens a directory recursively by copying all files to a new top-level directory, given an input path.""" - new_path = Path(f"{str(path)}_flat") + new_path = Path(f"{path!s}_flat") if os.path.exists(new_path): shutil.rmtree(new_path) # delete output folder os.makedirs(new_path) # make new output folder - for file in tqdm(glob.glob(f"{str(Path(path))}/**/*.*", recursive=True)): + for file in tqdm(glob.glob(f"{Path(path)!s}/**/*.*", recursive=True)): shutil.copyfile(file, new_path / Path(file).name) @@ -1282,7 +1282,7 @@ def __init__(self, root, augment, imgsz, cache=False): self.album_transforms = classify_albumentations(augment, imgsz) if augment else None self.cache_ram = cache is True or cache == "ram" self.cache_disk = cache == "disk" - self.samples = [list(x) + [Path(x[0]).with_suffix(".npy"), None] for x in self.samples] # file, index, npy, im + self.samples = [[*list(x), Path(x[0]).with_suffix(".npy"), None] for x in self.samples] # file, index, npy, im def __getitem__(self, i): """Fetches the item at index `i`, applies caching and transformations, and returns image-sample and index.""" diff --git a/utils/general.py b/utils/general.py index 1c35704eaa..71f71deddb 100644 --- a/utils/general.py +++ b/utils/general.py @@ -1,6 +1,8 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """General utils.""" +from __future__ import annotations + import contextlib import glob import inspect @@ -23,7 +25,6 @@ from pathlib import Path from subprocess import check_output from tarfile import is_tarfile -from typing import Optional from zipfile import ZipFile, is_zipfile import cv2 @@ -255,7 +256,7 @@ def methods(instance): return [f for f in dir(instance) if callable(getattr(instance, f)) and not f.startswith("__")] -def print_args(args: Optional[dict] = None, show_file=True, show_func=False): +def print_args(args: dict | None = None, show_file=True, show_func=False): """Prints function arguments; optionally specify args dict, show file and/or function name.""" x = inspect.currentframe().f_back # previous frame file, _, func, _, _ = inspect.getframeinfo(x) @@ -553,7 +554,7 @@ def check_dataset(data, autodownload=True): data[k] = [str((path / x).resolve()) for x in data[k]] # Parse yaml - train, val, test, s = (data.get(x) for x in ("train", "val", "test", "download")) + _train, val, _test, s = (data.get(x) for x in ("train", "val", "test", "download")) if val: val = [Path(x).resolve() for x in (val if isinstance(val, list) else [val])] # val path if not all(x.exists() for x in val): diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index 8aaafd1c52..ce2206fca4 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -251,9 +251,9 @@ def on_fit_epoch_end(self, vals, epoch, best_fitness, fi): if self.csv: file = self.save_dir / "results.csv" n = len(x) + 1 # number of cols - s = "" if file.exists() else (("%20s," * n % tuple(["epoch"] + self.keys)).rstrip(",") + "\n") # add header + s = "" if file.exists() else (("%20s," * n % tuple(["epoch", *self.keys])).rstrip(",") + "\n") # add header with open(file, "a") as f: - f.write(s + ("%20.5g," * n % tuple([epoch] + vals)).rstrip(",") + "\n") + f.write(s + ("%20.5g," * n % tuple([epoch, *vals])).rstrip(",") + "\n") if self.tb: for k, v in x.items(): @@ -265,7 +265,7 @@ def on_fit_epoch_end(self, vals, epoch, best_fitness, fi): if self.wandb: if best_fitness == fi: - best_results = [epoch] + vals[3:7] + best_results = [epoch, *vals[3:7]] for i, name in enumerate(self.best_keys): self.wandb.wandb_run.summary[name] = best_results[i] # log best results in the summary self.wandb.log(x) @@ -373,9 +373,9 @@ def log_metrics(self, metrics, epoch): if self.csv: keys, vals = list(metrics.keys()), list(metrics.values()) n = len(metrics) + 1 # number of cols - s = "" if self.csv.exists() else (("%23s," * n % tuple(["epoch"] + keys)).rstrip(",") + "\n") # header + s = "" if self.csv.exists() else (("%23s," * n % tuple(["epoch", *keys])).rstrip(",") + "\n") # header with open(self.csv, "a") as f: - f.write(s + ("%23.5g," * n % tuple([epoch] + vals)).rstrip(",") + "\n") + f.write(s + ("%23.5g," * n % tuple([epoch, *vals])).rstrip(",") + "\n") if self.tb: for k, v in metrics.items(): diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py index af7c1d502f..9028934bd9 100644 --- a/utils/loggers/wandb/wandb_utils.py +++ b/utils/loggers/wandb/wandb_utils.py @@ -145,7 +145,7 @@ def log_model(self, path, opt, epoch, fitness_score, best_model=False): aliases=[ "latest", "last", - f"epoch {str(self.current_epoch)}", + f"epoch {self.current_epoch!s}", "best" if best_model else "", ], ) diff --git a/utils/metrics.py b/utils/metrics.py index 205136547e..1298208b22 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -198,7 +198,7 @@ def plot(self, normalize=True, save_dir="", names=()): nc, nn = self.nc, len(names) # number of classes, names sn.set(font_scale=1.0 if nc < 50 else 0.8) # for label size labels = (0 < nn < 99) and (nn == nc) # apply names to ticklabels - ticklabels = (names + ["background"]) if labels else "auto" + ticklabels = ([*names, "background"]) if labels else "auto" with warnings.catch_warnings(): warnings.simplefilter("ignore") # suppress empty matrix RuntimeWarning: All-NaN slice encountered sn.heatmap( diff --git a/utils/plots.py b/utils/plots.py index a8fa09c882..89817508e6 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -81,13 +81,13 @@ def feature_visualization(x, module_type, stage, n=32, save_dir=Path("runs/detec save_dir: Directory to save results. """ if "Detect" not in module_type: - batch, channels, height, width = x.shape # batch, channels, height, width + _batch, channels, height, width = x.shape # batch, channels, height, width if height > 1 and width > 1: f = save_dir / f"stage{stage}_{module_type.split('.')[-1]}_features.png" # filename blocks = torch.chunk(x[0].cpu(), channels, dim=0) # select batch index 0, block by channels n = min(n, channels) # number of plots - fig, ax = plt.subplots(math.ceil(n / 8), 8, tight_layout=True) # 8 rows x n/8 cols + _fig, ax = plt.subplots(math.ceil(n / 8), 8, tight_layout=True) # 8 rows x n/8 cols ax = ax.ravel() plt.subplots_adjust(wspace=0.05, hspace=0.05) for i in range(n): @@ -233,7 +233,7 @@ def plot_val_txt(): # from utils.plots import *; plot_val() ax.set_aspect("equal") plt.savefig("hist2d.png", dpi=300) - fig, ax = plt.subplots(1, 2, figsize=(12, 6), tight_layout=True) + _fig, ax = plt.subplots(1, 2, figsize=(12, 6), tight_layout=True) ax[0].hist(cx, bins=600) ax[1].hist(cy, bins=600) plt.savefig("hist1d.png", dpi=200) @@ -243,7 +243,7 @@ def plot_targets_txt(): # from utils.plots import *; plot_targets_txt() """Plots histograms for target attributes from 'targets.txt' and saves as 'targets.jpg'.""" x = np.loadtxt("targets.txt", dtype=np.float32).T s = ["x targets", "y targets", "width targets", "height targets"] - fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) + _fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) ax = ax.ravel() for i in range(4): ax[i].hist(x[i], bins=100, label=f"{x[i].mean():.3g} +/- {x[i].std():.3g}") @@ -259,7 +259,7 @@ def plot_val_study(file="", dir="", x=None): # from utils.plots import *; plot_ if plot2: ax = plt.subplots(2, 4, figsize=(10, 6), tight_layout=True)[1].ravel() - fig2, ax2 = plt.subplots(1, 1, figsize=(8, 4), tight_layout=True) + _fig2, ax2 = plt.subplots(1, 1, figsize=(8, 4), tight_layout=True) # for f in [save_dir / f'study_coco_{x}.txt' for x in ['yolov5n6', 'yolov5s6', 'yolov5m6', 'yolov5l6', 'yolov5x6']]: for f in sorted(save_dir.glob("study*.txt")): y = np.loadtxt(f, dtype=np.float32, usecols=[0, 1, 2, 3, 7, 8, 9], ndmin=2).T @@ -358,7 +358,7 @@ def imshow_cls(im, labels=None, pred=None, names=None, nmax=25, verbose=False, f ) # select batch index 0, block by channels n = min(len(blocks), nmax) # number of plots m = min(8, round(n**0.5)) # 8 x 8 default - fig, ax = plt.subplots(math.ceil(n / m), m) # 8 rows x n/8 cols + _fig, ax = plt.subplots(math.ceil(n / m), m) # 8 rows x n/8 cols ax = ax.ravel() if m > 1 else [ax] # plt.subplots_adjust(wspace=0.05, hspace=0.05) for i in range(n): diff --git a/utils/segment/general.py b/utils/segment/general.py index ecb3111f9d..ac90bffe0a 100644 --- a/utils/segment/general.py +++ b/utils/segment/general.py @@ -14,7 +14,7 @@ def crop_mask(masks, boxes): - masks should be a size [n, h, w] tensor of masks - boxes should be a size [n, 4] tensor of bbox coords in relative point form """ - n, h, w = masks.shape + _n, h, w = masks.shape x1, y1, x2, y2 = torch.chunk(boxes[:, :, None], 4, 1) # x1 shape(1,1,n) r = torch.arange(w, device=masks.device, dtype=x1.dtype)[None, None, :] # rows shape(1,w,1) c = torch.arange(h, device=masks.device, dtype=x1.dtype)[None, :, None] # cols shape(h,1,1) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index 9b0f81d76a..c7575f11ee 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -203,7 +203,7 @@ def profile(input, ops, n=10, device=None): mem = torch.cuda.memory_reserved() / 1e9 if torch.cuda.is_available() else 0 # (GB) s_in, s_out = (tuple(x.shape) if isinstance(x, torch.Tensor) else "list" for x in (x, y)) # shapes p = sum(x.numel() for x in m.parameters()) if isinstance(m, nn.Module) else 0 # parameters - print(f"{p:12}{flops:12.4g}{mem:>14.3f}{tf:14.4g}{tb:14.4g}{str(s_in):>24s}{str(s_out):>24s}") + print(f"{p:12}{flops:12.4g}{mem:>14.3f}{tf:14.4g}{tb:14.4g}{s_in!s:>24s}{s_out!s:>24s}") results.append([p, flops, mem, tf, tb, s_in, s_out]) except Exception as e: print(e) diff --git a/utils/triton.py b/utils/triton.py index 20f317e651..5006f9f216 100644 --- a/utils/triton.py +++ b/utils/triton.py @@ -1,7 +1,8 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license """Utils to interact with the Triton Inference Server.""" -import typing +from __future__ import annotations + from urllib.parse import urlparse import torch @@ -54,7 +55,7 @@ def runtime(self): """Returns the model runtime.""" return self.metadata.get("backend", self.metadata.get("platform")) - def __call__(self, *args, **kwargs) -> typing.Union[torch.Tensor, tuple[torch.Tensor, ...]]: + def __call__(self, *args, **kwargs) -> torch.Tensor | tuple[torch.Tensor, ...]: """ Invokes the model. From 2dac637a02b55adf5cdaadbfd9c2e5a1d3f3a0be Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Wed, 29 Oct 2025 17:00:06 +0800 Subject: [PATCH 1179/1185] Migrate British to US English (#2358) * Migrate British to US English Signed-off-by: Glenn Jocher * Auto-format by https://ultralytics.com/actions * Update tutorial.ipynb Signed-off-by: Glenn Jocher --------- Signed-off-by: Glenn Jocher Co-authored-by: UltralyticsAssistant --- classify/tutorial.ipynb | 2 +- data/ImageNet.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/classify/tutorial.ipynb b/classify/tutorial.ipynb index 35d3654ff1..20a6e25925 100644 --- a/classify/tutorial.ipynb +++ b/classify/tutorial.ipynb @@ -553,7 +553,7 @@ " ringlet 50 0.86 0.98\n", " monarch butterfly 50 0.9 0.92\n", " small white 50 0.9 1\n", - " sulphur butterfly 50 0.92 1\n", + " sulfur butterfly 50 0.92 1\n", "gossamer-winged butterfly 50 0.88 1\n", " starfish 50 0.88 0.92\n", " sea urchin 50 0.84 0.94\n", diff --git a/data/ImageNet.yaml b/data/ImageNet.yaml index a3cf694bc5..2dee3f8d30 100644 --- a/data/ImageNet.yaml +++ b/data/ImageNet.yaml @@ -341,7 +341,7 @@ names: 322: ringlet 323: monarch butterfly 324: small white - 325: sulphur butterfly + 325: sulfur butterfly 326: gossamer-winged butterfly 327: starfish 328: sea urchin From b61ab4e02c2db34c8f79451a1b5ead98950ada62 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 3 Nov 2025 04:46:19 +0900 Subject: [PATCH 1180/1185] Update Google-style docstrings (#2359) * Update Google-style docstrings Signed-off-by: Glenn Jocher * Auto-format by https://ultralytics.com/actions * Auto-format by https://ultralytics.com/actions --------- Signed-off-by: Glenn Jocher Co-authored-by: UltralyticsAssistant --- benchmarks.py | 34 ++-- detect.py | 30 ++-- export.py | 211 ++++++++++++------------- hubconf.py | 135 ++++++++-------- models/common.py | 31 ++-- models/experimental.py | 9 +- models/tf.py | 12 +- models/yolo.py | 6 +- segment/val.py | 10 +- train.py | 44 +++--- utils/__init__.py | 6 +- utils/activations.py | 17 +- utils/augmentations.py | 9 +- utils/autoanchor.py | 12 +- utils/callbacks.py | 9 +- utils/dataloaders.py | 44 +++--- utils/general.py | 46 ++---- utils/loggers/__init__.py | 28 ++-- utils/loggers/clearml/clearml_utils.py | 36 ++--- utils/loggers/comet/comet_utils.py | 21 +-- utils/loggers/wandb/wandb_utils.py | 60 +++---- utils/loss.py | 3 +- utils/metrics.py | 42 ++--- utils/plots.py | 15 +- utils/segment/dataloaders.py | 8 +- utils/segment/general.py | 45 ++---- utils/segment/loss.py | 6 +- utils/segment/metrics.py | 30 ++-- utils/segment/plots.py | 3 +- utils/torch_utils.py | 23 ++- utils/triton.py | 14 +- val.py | 75 +++++---- 32 files changed, 449 insertions(+), 625 deletions(-) diff --git a/benchmarks.py b/benchmarks.py index 7c215dede6..b47412614c 100644 --- a/benchmarks.py +++ b/benchmarks.py @@ -60,8 +60,7 @@ def run( pt_only=False, # test PyTorch only hard_fail=False, # throw error on benchmark failure ): - """ - Run YOLOv3 benchmarks on multiple export formats and validate performance metrics. + """Run YOLOv3 benchmarks on multiple export formats and validate performance metrics. Args: weights (str | Path): Path to the weights file. Defaults to 'yolov5s.pt'. @@ -77,11 +76,6 @@ def run( Returns: None - Notes: - This function iterates over multiple export formats, performs the export, and then validates the model's performance - using appropriate validation functions for detection and segmentation models. The results are logged, and optionally, - benchmarks can be configured to raise errors on failures using the `hard_fail` argument. - Examples: ```python # Run benchmarks on the default 'yolov5s.pt' model with an image size of 640 pixels @@ -93,6 +87,11 @@ def run( # Test only PyTorch export run(pt_only=True) ``` + + Notes: + This function iterates over multiple export formats, performs the export, and then validates the model's performance + using appropriate validation functions for detection and segmentation models. The results are logged, and optionally, + benchmarks can be configured to raise errors on failures using the `hard_fail` argument. """ y, t = [], time.time() device = select_device(device) @@ -158,8 +157,7 @@ def test( pt_only=False, # test PyTorch only hard_fail=False, # throw error on benchmark failure ): - """ - Run YOLOv3 export tests for various formats and log the results, including export success status. + """Run YOLOv3 export tests for various formats and log the results, including export success status. Args: weights (str | Path): Path to the weights file. Defaults to ROOT / "yolov5s.pt". @@ -222,8 +220,7 @@ def test( def parse_opt(): - """ - Parses command line arguments for YOLOv3 inference and export configurations. + """Parses command line arguments for YOLOv3 inference and export configurations. Args: --weights (str): Path to the weights file. Default is 'ROOT / "yolov3-tiny.pt"'. @@ -241,7 +238,7 @@ def parse_opt(): Returns: argparse.Namespace: The parsed arguments as a namespace object. - Example: + Examples: To run inference on the YOLOv3-tiny model with a different image size: ```python @@ -272,8 +269,7 @@ def parse_opt(): def main(opt): - """ - Executes the export and benchmarking pipeline for YOLOv3 models, testing multiple export formats and validating + """Executes the export and benchmarking pipeline for YOLOv3 models, testing multiple export formats and validating performance metrics. Args: @@ -287,11 +283,7 @@ def main(opt): - mAP50-95: Mean Average Precision for the model - Inference time (ms): Time taken for inference - Notes: - The function runs the main pipeline by exporting the YOLOv3 model to various formats and running benchmarks to - evaluate performance. If `opt.test` is set to True, it only tests the export process and logs the results. - - Example: + Examples: Running the function from command line with required arguments: ```python @@ -299,6 +291,10 @@ def main(opt): ``` For more details, visit the Ultralytics YOLOv3 repository on [GitHub](https://github.com/ultralytics/ultralytics). + + Notes: + The function runs the main pipeline by exporting the YOLOv3 model to various formats and running benchmarks to + evaluate performance. If `opt.test` is set to True, it only tests the export process and logs the results. """ test(**vars(opt)) if opt.test else run(**vars(opt)) diff --git a/detect.py b/detect.py index 6668a504e3..7e2798587d 100644 --- a/detect.py +++ b/detect.py @@ -95,13 +95,12 @@ def run( dnn=False, # use OpenCV DNN for ONNX inference vid_stride=1, # video frame-rate stride ): - """ - Run YOLOv3 detection inference on various input sources such as images, videos, streams, and YouTube URLs. + """Run YOLOv3 detection inference on various input sources such as images, videos, streams, and YouTube URLs. Args: weights (str | Path): Path to the model weights file or a Triton URL (default: 'yolov5s.pt'). source (str | Path): Source of input data such as a file, directory, URL, glob pattern, or device identifier - (default: 'data/images'). + (default: 'data/images'). data (str | Path): Path to the dataset YAML file (default: 'data/coco128.yaml'). imgsz (tuple[int, int]): Inference size as a tuple (height, width) (default: (640, 640)). conf_thres (float): Confidence threshold for detection (default: 0.25). @@ -120,7 +119,8 @@ def run( update (bool): Whether to update all models (default: False). project (str | Path): Path to the project directory where results will be saved (default: 'runs/detect'). name (str): Name for the specific run within the project directory (default: 'exp'). - exist_ok (bool): Whether to allow existing project/name directory without incrementing run index (default: False). + exist_ok (bool): Whether to allow existing project/name directory without incrementing run index (default: + False). line_thickness (int): Thickness of bounding box lines in pixels (default: 3). hide_labels (bool): Whether to hide labels in the results (default: False). hide_conf (bool): Whether to hide confidences in the results (default: False). @@ -131,12 +131,6 @@ def run( Returns: None - Notes: - This function supports a variety of input sources such as image files, video files, directories, URL patterns, - webcam streams, and YouTube links. It also supports multiple model formats including PyTorch, ONNX, OpenVINO, - TensorRT, CoreML, TensorFlow, PaddlePaddle, and others. The results can be visualized in real-time or saved to - specified directories. Use command-line arguments to modify the behavior of the function. - Examples: ```python # Run YOLOv3 inference on an image @@ -148,6 +142,12 @@ def run( # Run YOLOv3 inference on a webcam run(weights='yolov5s.pt', source='0', view_img=True) ``` + + Notes: + This function supports a variety of input sources such as image files, video files, directories, URL patterns, + webcam streams, and YouTube links. It also supports multiple model formats including PyTorch, ONNX, OpenVINO, + TensorRT, CoreML, TensorFlow, PaddlePaddle, and others. The results can be visualized in real-time or saved to + specified directories. Use command-line arguments to modify the behavior of the function. """ source = str(source) save_img = not nosave and not source.endswith(".txt") # save inference images @@ -286,8 +286,7 @@ def run( def parse_opt(): - """ - Parses and returns command-line options for running YOLOv3 model detection. + """Parses and returns command-line options for running YOLOv3 model detection. Args: --weights (list[str]): Model path or Triton URL. Default: ROOT / "yolov3-tiny.pt". @@ -321,7 +320,7 @@ def parse_opt(): Returns: argparse.Namespace: Parsed command-line arguments for YOLOv3 inference configurations. - Example: + Examples: ```python options = parse_opt() run(**vars(options)) @@ -364,8 +363,7 @@ def parse_opt(): def main(opt): - """ - Entry point for running the YOLO model; checks requirements and calls `run` with parsed options. + """Entry point for running the YOLO model; checks requirements and calls `run` with parsed options. Args: opt (argparse.Namespace): Parsed command-line options, which include: @@ -400,7 +398,7 @@ def main(opt): Returns: None - Example: + Examples: ```python if __name__ == "__main__": opt = parse_opt() diff --git a/export.py b/export.py index 7fcd37a8eb..7a447d8389 100644 --- a/export.py +++ b/export.py @@ -94,12 +94,11 @@ class iOSModel(torch.nn.Module): """Exports a PyTorch model to an iOS-compatible format with normalized input dimensions and class configurations.""" def __init__(self, model, im): - """ - Initializes an iOSModel with normalized input dimensions and number of classes from a PyTorch model. + """Initializes an iOSModel with normalized input dimensions and number of classes from a PyTorch model. Args: - model (torch.nn.Module): The PyTorch model from which to initialize the iOS model. This should include attributes - like `nc` (number of classes) which will be used to configure the iOS model. + model (torch.nn.Module): The PyTorch model from which to initialize the iOS model. This should include + attributes like `nc` (number of classes) which will be used to configure the iOS model. im (torch.Tensor): A Tensor representing a sample input image. The shape of this tensor should be (batch_size, channels, height, width). This is used to extract dimensions for input normalization. @@ -125,8 +124,7 @@ def __init__(self, model, im): # self.normalize = torch.tensor([1. / w, 1. / h, 1. / w, 1. / h]).expand(np, 4) # explicit (faster, larger) def forward(self, x): - """ - Performs a forward pass, returning scaled confidences and normalized coordinates given an input tensor. + """Performs a forward pass, returning scaled confidences and normalized coordinates given an input tensor. Args: x (torch.Tensor): Input tensor representing a batch of images, with dimensions [batch_size, channels, @@ -141,10 +139,6 @@ def forward(self, x): - cls (torch.Tensor): Tensor of shape [batch_size, num_detections, num_classes] containing class probabilities. - Notes: - The dimensions of `x` should match the input dimensions used during the model's initialization to ensure - proper scaling and normalization. - Examples: ```python model = iOSModel(trained_model, input_image_tensor) @@ -158,17 +152,21 @@ def forward(self, x): See Also: `export.py` for exporting a YOLOv3 PyTorch model to various formats. https://github.com/zldrobit for TensorFlow export scripts. + + Notes: + The dimensions of `x` should match the input dimensions used during the model's initialization to ensure + proper scaling and normalization. """ xywh, conf, cls = self.model(x)[0].squeeze().split((4, 1, self.nc), 1) return cls * conf, xywh * self.normalize # confidence (3780, 80), coordinates (3780, 4) def export_formats(): - """ - Lists supported YOLOv3 model export formats including file suffixes and CPU/GPU compatibility. + """Lists supported YOLOv3 model export formats including file suffixes and CPU/GPU compatibility. Returns: - list: A list of lists where each sublist contains information about a specific export format. Each sublist includes + list: A list of lists where each sublist contains information about a specific export format. Each sublist + includes the following elements: - str: The name of the format. - str: The command-line argument for including this format. @@ -201,12 +199,11 @@ def export_formats(): def try_export(inner_func): - """ - Profiles and logs the export process of YOLOv3 models, capturing success or failure details. + """Profiles and logs the export process of YOLOv3 models, capturing success or failure details. Args: - inner_func (Callable): The function that performs the actual export process and returns the model file path - and the exported model. + inner_func (Callable): The function that performs the actual export process and returns the model file path and + the exported model. Returns: Callable: A wrapped function that profiles and logs the export process, handling successes and failures. @@ -242,8 +239,7 @@ def outer_func(*args, **kwargs): @try_export def export_torchscript(model, im, file, optimize, prefix=colorstr("TorchScript:")): - """ - Export a YOLOv3 model to TorchScript format, with optional optimization for mobile deployment. + """Export a YOLOv3 model to TorchScript format, with optional optimization for mobile deployment. Args: model (torch.nn.Module): The YOLOv3 model to be exported. @@ -254,15 +250,11 @@ def export_torchscript(model, im, file, optimize, prefix=colorstr("TorchScript:" Returns: (pathlib.Path | None, torch.nn.Module | None): Tuple containing the path to the saved TorchScript model and the - model itself. Returns `(None, None)` if the export fails. + model itself. Returns `(None, None)` if the export fails. Raises: Exception: If there is an error during export, it logs the error and returns `(None, None)`. - Notes: - The function uses `torch.jit.trace` to trace the model with the input image tensor (`im`). Required metadata such as - input shape, stride, and class names are stored in an extra file included in the TorchScript model. - Examples: ```python from pathlib import Path @@ -277,6 +269,10 @@ def export_torchscript(model, im, file, optimize, prefix=colorstr("TorchScript:" ``` For more information, visit: https://ultralytics.com/. + + Notes: + The function uses `torch.jit.trace` to trace the model with the input image tensor (`im`). Required metadata such as + input shape, stride, and class names are stored in an extra file included in the TorchScript model. """ LOGGER.info(f"\n{prefix} starting export with torch {torch.__version__}...") f = file.with_suffix(".torchscript") @@ -293,8 +289,7 @@ def export_torchscript(model, im, file, optimize, prefix=colorstr("TorchScript:" @try_export def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr("ONNX:")): - """ - Export a YOLOv3 model to ONNX format with dynamic shape and simplification options. + """Export a YOLOv3 model to ONNX format with dynamic shape and simplification options. Args: model (torch.nn.Module): The YOLOv3 model to be exported. @@ -308,7 +303,7 @@ def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr("ONNX Returns: tuple[pathlib.Path, None]: The path to the saved ONNX model, None as the second tuple element (kept for consistency). - Example: + Examples: ```python from pathlib import Path import torch @@ -389,8 +384,7 @@ def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr("ONNX @try_export def export_openvino(file, metadata, half, int8, data, prefix=colorstr("OpenVINO:")): - """ - Export a YOLOv3 model to OpenVINO format with optional INT8 quantization and inference metadata. + """Export a YOLOv3 model to OpenVINO format with optional INT8 quantization and inference metadata. Args: file (Path): Path to the output file. @@ -403,16 +397,16 @@ def export_openvino(file, metadata, half, int8, data, prefix=colorstr("OpenVINO: tuple[Path | None, openvino.runtime.Model | None]: Tuple containing the path to the exported model and the OpenVINO model object, or None if the export failed. - Notes: - - Requires the `openvino-dev>=2023.0` and optional `nncf>=2.4.0` package for INT8 quantization. - - Refer to OpenVINO documentation for further details: https://docs.openvino.ai/latest/index.html. - Examples: ```python model_file = Path('/path/to/model.onnx') metadata = {'names': ['class1', 'class2'], 'stride': 32} export_openvino(model_file, metadata, half=True, int8=False, data='/path/to/dataset.yaml') ``` + + Notes: + - Requires the `openvino-dev>=2023.0` and optional `nncf>=2.4.0` package for INT8 quantization. + - Refer to OpenVINO documentation for further details: https://docs.openvino.ai/latest/index.html. """ check_requirements("openvino-dev>=2023.0") # requires openvino-dev: https://pypi.org/project/openvino-dev/ import openvino.runtime as ov @@ -452,13 +446,13 @@ def gen_dataloader(yaml_path, task="train", imgsz=640, workers=4): return dataloader def transform_fn(data_item): - """ - Quantization transform function. + """Quantization transform function. Extracts and preprocess input data from dataloader item for quantization. Parameters: data_item: Tuple with data item produced by DataLoader during iteration + Returns: input_tensor: Input data for quantization """ @@ -479,8 +473,7 @@ def transform_fn(data_item): @try_export def export_paddle(model, im, file, metadata, prefix=colorstr("PaddlePaddle:")): - """ - Export a YOLOv3 model to PaddlePaddle format using X2Paddle, saving to a specified directory and including model + """Export a YOLOv3 model to PaddlePaddle format using X2Paddle, saving to a specified directory and including model metadata. Args: @@ -492,17 +485,11 @@ def export_paddle(model, im, file, metadata, prefix=colorstr("PaddlePaddle:")): Returns: tuple: A tuple containing the directory path (str) where the PaddlePaddle model is saved, and `None`. - - Requirements: + Requirements: - paddlepaddle: Install via `pip install paddlepaddle`. - x2paddle: Install via `pip install x2paddle`. - Notes: - The function first checks for required packages `paddlepaddle` and `x2paddle`. It then uses X2Paddle to trace - the model and export it to a PaddlePaddle format, saving the resulting files in the specified directory with - included metadata in a YAML file. - - Example: + Examples: ```python from pathlib import Path import torch @@ -515,6 +502,11 @@ def export_paddle(model, im, file, metadata, prefix=colorstr("PaddlePaddle:")): export_paddle(model, im, file, metadata) ``` + + Notes: + The function first checks for required packages `paddlepaddle` and `x2paddle`. It then uses X2Paddle to trace + the model and export it to a PaddlePaddle format, saving the resulting files in the specified directory with + included metadata in a YAML file. """ check_requirements(("paddlepaddle", "x2paddle")) import x2paddle @@ -530,12 +522,12 @@ def export_paddle(model, im, file, metadata, prefix=colorstr("PaddlePaddle:")): @try_export def export_coreml(model, im, file, int8, half, nms, prefix=colorstr("CoreML:")): - """ - Export a YOLOv3 model to CoreML format with optional quantization and Non-Maximum Suppression (NMS). + """Export a YOLOv3 model to CoreML format with optional quantization and Non-Maximum Suppression (NMS). Args: model (torch.nn.Module): The YOLOv3 model to be exported. - im (torch.Tensor): Input tensor used for tracing the model. Shape should be (batch_size, channels, height, width). + im (torch.Tensor): Input tensor used for tracing the model. Shape should be (batch_size, channels, height, + width). file (pathlib.Path): Destination file path where the CoreML model will be saved. int8 (bool): Whether to use INT8 quantization. If True, quantizes the model to 8-bit integers. half (bool): Whether to use FP16 quantization. If True, converts the model to 16-bit floating point numbers. @@ -548,12 +540,7 @@ def export_coreml(model, im, file, int8, half, nms, prefix=colorstr("CoreML:")): Raises: Exception: If there is an error during export, logs the error and stops the process. - Notes: - - This function requires `coremltools` to be installed. - - If `nms` is enabled, the model is wrapped with `iOSModel` to include NMS. - - Quantization only works on macOS. - - Example: + Examples: ```python from ultralytics.utils import export_coreml from pathlib import Path @@ -564,6 +551,11 @@ def export_coreml(model, im, file, int8, half, nms, prefix=colorstr("CoreML:")): file = Path("model.mlmodel") export_coreml(model, im, file, int8=False, half=True, nms=True) ``` + + Notes: + - This function requires `coremltools` to be installed. + - If `nms` is enabled, the model is wrapped with `iOSModel` to include NMS. + - Quantization only works on macOS. """ check_requirements("coremltools") import coremltools as ct @@ -589,8 +581,7 @@ def export_coreml(model, im, file, int8, half, nms, prefix=colorstr("CoreML:")): @try_export def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose=False, prefix=colorstr("TensorRT:")): - """ - Export a YOLOv3 model to TensorRT engine format, optimizing it for GPU inference. + """Export a YOLOv3 model to TensorRT engine format, optimizing it for GPU inference. Args: model (torch.nn.Module): The YOLOv3 model to be exported. @@ -610,10 +601,7 @@ def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose AssertionError: If the model is running on CPU instead of GPU. RuntimeError: If the ONNX file failed to load. - Notes: - Requires TensorRT installation to execute. Nvidia TensorRT: https://developer.nvidia.com/tensorrt - - Example: + Examples: ```python from pathlib import Path import torch @@ -625,6 +613,9 @@ def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose # Export the model export_engine(model, im, Path("yolov3.engine"), half=True, dynamic=True, simplify=True) ``` + + Notes: + Requires TensorRT installation to execute. Nvidia TensorRT: https://developer.nvidia.com/tensorrt """ assert im.device.type != "cpu", "export running on CPU but must be on GPU, i.e. `python export.py --device 0`" try: @@ -700,8 +691,8 @@ def export_saved_model( keras=False, prefix=colorstr("TensorFlow SavedModel:"), ): - """ - Exports a YOLOv3 model to TensorFlow SavedModel format, including optional settings for Non-Max Suppression (NMS). + """Exports a YOLOv3 model to TensorFlow SavedModel format, including optional settings for Non-Max Suppression + (NMS). Args: model (torch.nn.Module): The YOLOv3 PyTorch model to be exported. @@ -784,8 +775,7 @@ def export_saved_model( @try_export def export_pb(keras_model, file, prefix=colorstr("TensorFlow GraphDef:")): - """ - Export a Keras model to TensorFlow GraphDef (*.pb) format, which is compatible with YOLOv3. + """Export a Keras model to TensorFlow GraphDef (*.pb) format, which is compatible with YOLOv3. Args: keras_model (tf.keras.Model): The trained Keras model to be exported. @@ -795,7 +785,7 @@ def export_pb(keras_model, file, prefix=colorstr("TensorFlow GraphDef:")): Returns: tuple[pathlib.Path, None]: The file path where the model is saved and None. - Example: + Examples: ```python from tensorflow.keras.models import load_model from pathlib import Path @@ -827,8 +817,7 @@ def export_pb(keras_model, file, prefix=colorstr("TensorFlow GraphDef:")): @try_export def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=colorstr("TensorFlow Lite:")): - """ - Export a YOLOv3 PyTorch model to TensorFlow Lite (TFLite) format. + """Export a YOLOv3 PyTorch model to TensorFlow Lite (TFLite) format. Args: keras_model (tf.keras.Model): The Keras model obtained after converting the PyTorch model. @@ -843,12 +832,7 @@ def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=c Returns: (str | None): File path of the saved TensorFlow Lite model file or None if export fails. - Notes: - - Ensure TensorFlow is installed to perform the export. - - INT8 quantization requires a representative dataset to provide accurate calibration for the model. - - Including Non-Max Suppression (NMS) modifies the exported model to handle post-processing. - - Example: + Examples: ```python import torch from pathlib import Path @@ -865,6 +849,11 @@ def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=c For more details, refer to: TensorFlow Lite Developer Guide: https://www.tensorflow.org/lite/guide Model Conversion Reference: https://github.com/leimao/Frozen_Graph_TensorFlow + + Notes: + - Ensure TensorFlow is installed to perform the export. + - INT8 quantization requires a representative dataset to provide accurate calibration for the model. + - Including Non-Max Suppression (NMS) modifies the exported model to handle post-processing. """ import tensorflow as tf @@ -897,8 +886,7 @@ def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=c @try_export def export_edgetpu(file, prefix=colorstr("Edge TPU:")): - """ - Export a YOLOv5 model to TensorFlow Edge TPU format with INT8 quantization. + """Export a YOLOv5 model to TensorFlow Edge TPU format with INT8 quantization. Args: file (Path): The file path for the PyTorch model to be exported, with a `.pt` suffix. @@ -910,14 +898,10 @@ def export_edgetpu(file, prefix=colorstr("Edge TPU:")): Raises: AssertionError: If the export is not executed on a Linux system. - subprocess.CalledProcessError: If there are issues with subprocess execution, particularly around Edge TPU compiler - installation or model conversion. - - Notes: - This function is designed to work exclusively on Linux systems and requires the Edge TPU compiler to be installed. - If the compiler is not found, the function attempts to install it. + subprocess.CalledProcessError: If there are issues with subprocess execution, particularly around Edge TPU + compiler installation or model conversion. - Example: + Examples: ```python from pathlib import Path from ultralytics import export_edgetpu @@ -929,6 +913,10 @@ def export_edgetpu(file, prefix=colorstr("Edge TPU:")): For additional details, visit the Edge TPU compiler documentation: https://coral.ai/docs/edgetpu/compiler/ + + Notes: + This function is designed to work exclusively on Linux systems and requires the Edge TPU compiler to be installed. + If the compiler is not found, the function attempts to install it. """ cmd = "edgetpu_compiler --version" help_url = "https://coral.ai/docs/edgetpu/compiler/" @@ -967,8 +955,7 @@ def export_edgetpu(file, prefix=colorstr("Edge TPU:")): @try_export def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): - """ - Export a YOLOv3 model to TensorFlow.js format, with an optional quantization to uint8. + """Export a YOLOv3 model to TensorFlow.js format, with an optional quantization to uint8. Args: file (Path): The path to the model file to be exported. @@ -976,28 +963,18 @@ def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): prefix (str): String prefix for logging, by default "TensorFlow.js". Returns: - (tuple[str, None]): The directory path where the TensorFlow.js model files are saved and `None` placeholder to match - the expected return type from 'try_export' decorator. + (tuple[str, None]): The directory path where the TensorFlow.js model files are saved and `None` placeholder to + match the expected return type from 'try_export' decorator. Raises: ImportError: If the required 'tensorflowjs' package is not installed. - Example: + Examples: ```python from pathlib import Path export_tfjs(file=Path("yolov5s.pt"), int8=False) ``` - Note: - Ensure that you have TensorFlow.js installed in your environment. Install the package via: - ```bash - pip install tensorflowjs - ``` - - For more details on using the converted model: - Refer to the official TensorFlow.js documentation: https://www.tensorflow.org/js. - - Usage: The converted model can be used directly in JavaScript environments using the TensorFlow.js library. For usage in web applications: @@ -1017,6 +994,15 @@ def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): ```bash npm start ``` + + Notes: + Ensure that you have TensorFlow.js installed in your environment. Install the package via: + ```bash + pip install tensorflowjs + ``` + + For more details on using the converted model: + Refer to the official TensorFlow.js documentation: https://www.tensorflow.org/js. """ check_requirements("tensorflowjs") import tensorflowjs as tfjs @@ -1054,18 +1040,18 @@ def export_tfjs(file, int8, prefix=colorstr("TensorFlow.js:")): def add_tflite_metadata(file, metadata, num_outputs): - """ - Adds metadata to a TensorFlow Lite model to enhance its usability with `tflite_support`. + """Adds metadata to a TensorFlow Lite model to enhance its usability with `tflite_support`. Args: file (str): Path to the TensorFlow Lite model file. - metadata (dict): Dictionary of metadata to add, including descriptions of inputs, outputs, and other relevant info. + metadata (dict): Dictionary of metadata to add, including descriptions of inputs, outputs, and other relevant + info. num_outputs (int): Number of output tensors in the model. Returns: None - Example: + Examples: ```python metadata = { "input": {"description": "Input image tensor"}, @@ -1074,7 +1060,7 @@ def add_tflite_metadata(file, metadata, num_outputs): add_tflite_metadata("/path/to/model.tflite", metadata, num_outputs=1) ``` - Note: + Notes: Requires the `tflite_support` library for adding metadata to the TensorFlow Lite model. Installation: `pip install tflite-support` @@ -1143,8 +1129,7 @@ def add_tflite_metadata(file, metadata, num_outputs): def pipeline_coreml(model, im, file, names, y, prefix=colorstr("CoreML Pipeline:")): - """ - Processes and exports a YOLOv3 model into the CoreML model format, applying metadata and non-maximum suppression + """Processes and exports a YOLOv3 model into the CoreML model format, applying metadata and non-maximum suppression (NMS). Args: @@ -1158,7 +1143,7 @@ def pipeline_coreml(model, im, file, names, y, prefix=colorstr("CoreML Pipeline: Returns: pathlib.Path | None: The path to the saved CoreML model if successful, otherwise None. - Example: + Examples: ```python from pathlib import Path import torch @@ -1348,8 +1333,7 @@ def run( iou_thres=0.45, # TF.js NMS: IoU threshold conf_thres=0.25, # TF.js NMS: confidence threshold ): - """ - Export a PyTorch model to various formats like ONNX, CoreML, and TensorRT. + """Export a PyTorch model to various formats like ONNX, CoreML, and TensorRT. Args: data (str | Path): Path to dataset configuration file. @@ -1378,10 +1362,6 @@ def run( Returns: None - Notes: - - Requires various packages installed for different export formats, e.g., `onnx`, `coremltools`, etc. - - Some formats have additional dependencies (e.g., TensorFlow, TensorRT, etc.) - Examples: ```python run( @@ -1396,6 +1376,10 @@ def run( opset=12 ) ``` + + Notes: + - Requires various packages installed for different export formats, e.g., `onnx`, `coremltools`, etc. + - Some formats have additional dependencies (e.g., TensorFlow, TensorRT, etc.) """ t = time.time() include = [x.lower() for x in include] # to lowercase @@ -1507,8 +1491,7 @@ def run( def parse_opt(known=False): - """ - Parse command-line arguments for model export configuration. + """Parse command-line arguments for model export configuration. Args: known (bool): If True, parse only known arguments and ignore others. Default is False. @@ -1516,7 +1499,7 @@ def parse_opt(known=False): Returns: argparse.Namespace: Namespace object containing export configuration parameters. - Example: + Examples: ```python from ultralytics.export import parse_opt diff --git a/hubconf.py b/hubconf.py index a0031e4cf8..f2d02faaa5 100644 --- a/hubconf.py +++ b/hubconf.py @@ -14,8 +14,7 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): - """ - Creates or loads a YOLOv3 model with specified configurations and optional pretrained weights. + """Creates or loads a YOLOv3 model with specified configurations and optional pretrained weights. Args: name (str): Model name such as 'yolov5s' or a path to a model checkpoint file, e.g., 'path/to/best.pt'. @@ -26,20 +25,20 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbo types. Default is True. verbose (bool): If True, print all information to the screen. Default is True. device (str | torch.device | None): Device to use for model parameters ('cpu', 'cuda', etc.). If None, defaults - to the best available device. + to the best available device. Returns: torch.nn.Module: YOLOv3 model loaded with or without pretrained weights. - Example: + Raises: + Exception: If an error occurs while loading the model, returns an error message with a helpful URL: + "https: //docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading". + + Examples: ```python import torch model = _create('yolov5s') ``` - - Raises: - Exception: If an error occurs while loading the model, returns an error message with a helpful URL: - "https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading". """ from pathlib import Path @@ -96,15 +95,15 @@ def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbo def custom(path="path/to/model.pt", autoshape=True, _verbose=True, device=None): - """ - Loads a custom or local YOLOv3 model from a specified path, with options for autoshaping and device assignment. + """Loads a custom or local YOLOv3 model from a specified path, with options for autoshaping and device assignment. Args: path (str): Path to the model file. Supports both local and URL paths. - autoshape (bool): If True, applies the YOLOv3 `.autoshape()` wrapper to allow for various input formats. Default is True. + autoshape (bool): If True, applies the YOLOv3 `.autoshape()` wrapper to allow for various input formats. Default + is True. _verbose (bool): If True, outputs detailed information. Otherwise, limits verbosity. Default is True. - device (str | torch.device | None): Device to load the model on. Default is None, which uses the available GPU if - possible. + device (str | torch.device | None): Device to load the model on. Default is None, which uses the available GPU + if possible. Returns: (torch.nn.Module): The loaded YOLOv3 model, either with or without autoshaping applied. @@ -125,24 +124,23 @@ def custom(path="path/to/model.pt", autoshape=True, _verbose=True, device=None): def yolov5n(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """ - Instantiates a YOLOv5n model with optional pretrained weights, configurable input channels, number of classes, + """Instantiates a YOLOv5n model with optional pretrained weights, configurable input channels, number of classes, autoshaping, and device selection. Args: pretrained (bool): If True, loads pretrained weights into the model. Defaults to True. channels (int): Number of input channels. Defaults to 3. classes (int): Number of detection classes. Defaults to 80. - autoshape (bool): If True, applies YOLOv5 .autoshape() wrapper to the model for various input formats like file/URI/PIL/cv2/np - and adds non-maximum suppression (NMS). Defaults to True. + autoshape (bool): If True, applies YOLOv5 .autoshape() wrapper to the model for various input formats like + file/URI/PIL/cv2/np and adds non-maximum suppression (NMS). Defaults to True. _verbose (bool): If True, prints detailed information to the screen. Defaults to True. - device (str | torch.device | None): Device to use for model computations (e.g., 'cpu', 'cuda'). If None, the best - available device is automatically selected. Defaults to None. + device (str | torch.device | None): Device to use for model computations (e.g., 'cpu', 'cuda'). If None, the + best available device is automatically selected. Defaults to None. Returns: torch.nn.Module: The instantiated YOLOv5n model. - Example: + Examples: ```python import torch model = torch.hub.load('ultralytics/yolov5', 'yolov5n') # using official model @@ -151,30 +149,30 @@ def yolov5n(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr model = torch.hub.load('.', 'custom', 'yolov5n.pt', source='local') # from local repository ``` - Note: + Notes: PyTorch Hub models can be explored at https://pytorch.org/hub/ultralytics_yolov5. This allows easy model loading and usage. """ return _create("yolov5n", pretrained, channels, classes, autoshape, _verbose, device) def yolov5s(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """ - Load the YOLOv5s model with customizable options for pretrained weights, input channels, number of classes, + """Load the YOLOv5s model with customizable options for pretrained weights, input channels, number of classes, autoshape functionality, and device selection. Args: pretrained (bool, optional): If True, loads model with pretrained weights. Default is True. channels (int, optional): Specifies the number of input channels. Default is 3. classes (int, optional): Defines the number of model classes. Default is 80. - autoshape (bool, optional): Applies YOLOv5 .autoshape() wrapper to the model for enhanced usability. Default is True. + autoshape (bool, optional): Applies YOLOv5 .autoshape() wrapper to the model for enhanced usability. Default is + True. _verbose (bool, optional): If True, prints detailed information during model loading. Default is True. - device (str | torch.device | None, optional): Specifies the device to load the model on. Accepts 'cpu', 'cuda', or - torch.device. Default is None, which automatically selects the best available option. + device (str | torch.device | None, optional): Specifies the device to load the model on. Accepts 'cpu', 'cuda', + or torch.device. Default is None, which automatically selects the best available option. Returns: torch.nn.Module: The initialized YOLOv5s model loaded with the specified options. - Example: + Examples: ```python import torch model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True) @@ -186,16 +184,15 @@ def yolov5s(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr def yolov5m(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """ - Loads the YOLOv5m model with options for pretrained weights, input channels, number of classes, autoshape + """Loads the YOLOv5m model with options for pretrained weights, input channels, number of classes, autoshape functionality, and device selection. Args: pretrained (bool, optional): If True, loads pretrained weights into the model. Default is True. channels (int, optional): Number of input channels for the model. Default is 3. classes (int, optional): Number of model classes. Default is 80. - autoshape (bool, optional): If True, applies the YOLOv5 .autoshape() wrapper for handling multiple input types and NMS. - Default is True. + autoshape (bool, optional): If True, applies the YOLOv5 .autoshape() wrapper for handling multiple input types + and NMS. Default is True. _verbose (bool, optional): If True, prints detailed information during model loading. Default is True. device (str | torch.device | None, optional): Device for model computations (e.g., 'cpu', 'cuda'). Automatically selects the best available device if None. Default is None. @@ -203,7 +200,7 @@ def yolov5m(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr Returns: torch.nn.Module: The instantiated YOLOv5m model. - Example: + Examples: ```python import torch model = torch.hub.load('ultralytics/yolov5', 'yolov5m', pretrained=True) @@ -213,24 +210,23 @@ def yolov5m(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr def yolov5l(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """ - Load the YOLOv5l model with customizable options for pretrained weights, input channels, number of classes, + """Load the YOLOv5l model with customizable options for pretrained weights, input channels, number of classes, autoshape functionality, and device selection. Args: pretrained (bool, optional): If True, load model with pretrained weights. Default is True. channels (int, optional): Specifies the number of input channels. Default is 3. classes (int, optional): Defines the number of model classes. Default is 80. - autoshape (bool, optional): Applies the YOLOv5 .autoshape() wrapper to the model for enhanced usability. Default is - True. + autoshape (bool, optional): Applies the YOLOv5 .autoshape() wrapper to the model for enhanced usability. Default + is True. _verbose (bool, optional): If True, prints detailed information during model loading. Default is True. - device (str | torch.device | None, optional): Specifies the device to load the model on. Accepts 'cpu', 'cuda', or - torch.device. Default is None, which automatically selects the best available option. + device (str | torch.device | None, optional): Specifies the device to load the model on. Accepts 'cpu', 'cuda', + or torch.device. Default is None, which automatically selects the best available option. Returns: torch.nn.Module: The initialized YOLOv5l model loaded with the specified options. - Example: + Examples: ```python import torch model = torch.hub.load('ultralytics/yolov5', 'yolov5l', pretrained=True) @@ -242,8 +238,7 @@ def yolov5l(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr def yolov5x(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """ - Load the YOLOv5x model with options for pretrained weights, number of input channels, classes, autoshaping, and + """Load the YOLOv5x model with options for pretrained weights, number of input channels, classes, autoshaping, and device selection. Args: @@ -253,8 +248,8 @@ def yolov5x(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr autoshape (bool, optional): If True, applies the YOLOv5 .autoshape() wrapper, enabling various input formats and non-maximum suppression (NMS). Defaults to True. _verbose (bool, optional): If True, prints detailed information during model loading. Defaults to True. - device (str | torch.device | None, optional): Device to use for model parameters (e.g., 'cpu', 'cuda'). Defaults to - None, selecting the best available device automatically. + device (str | torch.device | None, optional): Device to use for model parameters (e.g., 'cpu', 'cuda'). Defaults + to None, selecting the best available device automatically. Returns: torch.nn.Module: The YOLOv5x model loaded with the specified configuration. @@ -276,9 +271,8 @@ def yolov5x(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=Tr def yolov5n6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """ - Loads the YOLOv5n6 model with options for pretrained weights, input channels, classes, autoshaping, verbosity, and - device assignment. + """Loads the YOLOv5n6 model with options for pretrained weights, input channels, classes, autoshaping, verbosity, + and device assignment. Args: pretrained (bool, optional): If True, loads pretrained weights into the model. Default is True. @@ -286,26 +280,25 @@ def yolov5n6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=T classes (int, optional): Number of model classes. Default is 80. autoshape (bool, optional): If True, applies the YOLOv3 .autoshape() wrapper to the model. Default is True. _verbose (bool, optional): If True, prints all information to the screen. Default is True. - device (str | torch.device | None, optional): Device to use for model parameters, e.g., 'cpu', '0', or torch.device. - Default is None. + device (str | torch.device | None, optional): Device to use for model parameters, e.g., 'cpu', '0', or + torch.device. Default is None. Returns: torch.nn.Module: YOLOv5n6 model loaded on the specified device and configured as per the provided options. - Notes: - For more information on PyTorch Hub models, refer to: https://pytorch.org/hub/ultralytics_yolov5 - - Example: + Examples: ```python model = yolov5n6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device='cuda') ``` + + Notes: + For more information on PyTorch Hub models, refer to: https://pytorch.org/hub/ultralytics_yolov5 """ return _create("yolov5n6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5s6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """ - Loads the YOLOv5s6 model with options for weights, channels, classes, autoshaping, and device selection. + """Loads the YOLOv5s6 model with options for weights, channels, classes, autoshaping, and device selection. Args: pretrained (bool, optional): If True, loads pretrained weights into the model. Defaults to True. @@ -313,13 +306,13 @@ def yolov5s6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=T classes (int, optional): Number of model classes. Defaults to 80. autoshape (bool, optional): Apply YOLOv5 .autoshape() wrapper to the model. Defaults to True. _verbose (bool, optional): If True, prints detailed information to the screen. Defaults to True. - device (str | torch.device | None, optional): Device to use for model parameters, e.g., 'cpu', 'cuda:0'. - If None, it will select the appropriate device automatically. Defaults to None. + device (str | torch.device | None, optional): Device to use for model parameters, e.g., 'cpu', 'cuda:0'. If + None, it will select the appropriate device automatically. Defaults to None. Returns: torch.nn.Module: The YOLOv5s6 model, ready for inference or further training. - Example: + Examples: ```python import torch model = torch.hub.load('ultralytics/yolov5', 'yolov5s6', pretrained=True, channels=3, classes=80) @@ -333,9 +326,8 @@ def yolov5s6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=T def yolov5m6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """ - Loads YOLOv5m6 model with options for pretrained weights, input channels, number of classes, autoshaping, and device - selection. + """Loads YOLOv5m6 model with options for pretrained weights, input channels, number of classes, autoshaping, and + device selection. Args: pretrained (bool): Whether to load pretrained weights into the model. Default is True. @@ -343,13 +335,13 @@ def yolov5m6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=T classes (int): Number of model classes. Default is 80. autoshape (bool): Whether to apply YOLOv5 .autoshape() wrapper to the model. Default is True. _verbose (bool): Whether to print all information to the screen. Default is True. - device (str | torch.device | None): Device to use for model parameters, e.g., 'cpu', 'cuda', 'mps', or torch device. - Default is None. + device (str | torch.device | None): Device to use for model parameters, e.g., 'cpu', 'cuda', 'mps', or torch + device. Default is None. Returns: YOLOv5m6 model (torch.nn.Module): The instantiated YOLOv5m6 model with specified options. - Example: + Examples: ```python import torch @@ -367,8 +359,7 @@ def yolov5m6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=T def yolov5l6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """ - Loads the YOLOv5l6 model with options for pretrained weights, input channels, the number of classes, autoshaping, + """Loads the YOLOv5l6 model with options for pretrained weights, input channels, the number of classes, autoshaping, and device selection. Args: @@ -391,29 +382,29 @@ def yolov5l6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=T model = torch.hub.load('ultralytics/yolov5', 'yolov5l6') # Load YOLOv5l6 model ``` - Note: + Notes: For more details, visit the [Ultralytics YOLOv5 GitHub repository](https://github.com/ultralytics/yolov5). """ return _create("yolov5l6", pretrained, channels, classes, autoshape, _verbose, device) def yolov5x6(pretrained=True, channels=3, classes=80, autoshape=True, _verbose=True, device=None): - """ - Loads the YOLOv5x6 model, allowing customization for pretrained weights, input channels, and model classes. + """Loads the YOLOv5x6 model, allowing customization for pretrained weights, input channels, and model classes. Args: pretrained (bool): If True, loads the model with pretrained weights. Default is True. channels (int): Number of input channels. Default is 3. classes (int): Number of output classes for the model. Default is 80. - autoshape (bool): If True, applies the .autoshape() wrapper for inference on diverse input formats. Default is True. + autoshape (bool): If True, applies the .autoshape() wrapper for inference on diverse input formats. Default is + True. _verbose (bool): If True, prints detailed information during model loading. Default is True. - device (str | torch.device | None): Specifies the device to load the model on ('cpu', 'cuda', etc.). Default is None, - which uses the best available device. + device (str | torch.device | None): Specifies the device to load the model on ('cpu', 'cuda', etc.). Default is + None, which uses the best available device. Returns: torch.nn.Module: The YOLOv5x6 model with the specified configurations. - Example: + Examples: ```python from ultralytics import yolov5x6 diff --git a/models/common.py b/models/common.py index c0c6511593..3c46b0324e 100644 --- a/models/common.py +++ b/models/common.py @@ -161,8 +161,7 @@ def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcu self.add = shortcut and c1 == c2 def forward(self, x): - """Executes forward pass, performing convolutional ops and optional shortcut addition; expects input tensor - x. + """Executes forward pass, performing convolutional ops and optional shortcut addition; expects input tensor x. """ return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) @@ -185,8 +184,7 @@ def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, nu self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n))) def forward(self, x): - """Processes input through layers, combining outputs with activation and normalization for feature - extraction. + """Processes input through layers, combining outputs with activation and normalization for feature extraction. """ y1 = self.cv3(self.m(self.cv1(x))) y2 = self.cv2(x) @@ -215,8 +213,7 @@ class C3(nn.Module): """Implements a CSP Bottleneck with 3 convolutions, optional shortcuts, group convolutions, and expansion factor.""" def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion - """Initializes CSP Bottleneck with 3 convolutions, optional shortcuts, group convolutions, and expansion - factor. + """Initializes CSP Bottleneck with 3 convolutions, optional shortcuts, group convolutions, and expansion factor. """ super().__init__() c_ = int(c2 * e) # hidden channels @@ -274,8 +271,7 @@ class SPP(nn.Module): """Implements Spatial Pyramid Pooling (SPP) for enhanced feature extraction; see https://arxiv.org/abs/1406.4729.""" def __init__(self, c1, c2, k=(5, 9, 13)): - """ - Initializes SPP layer with specified channels and kernels. + """Initializes SPP layer with specified channels and kernels. More at https://arxiv.org/abs/1406.4729 """ @@ -286,8 +282,8 @@ def __init__(self, c1, c2, k=(5, 9, 13)): self.m = nn.ModuleList([nn.MaxPool2d(kernel_size=x, stride=1, padding=x // 2) for x in k]) def forward(self, x): - """ - Applies convolution and max pooling layers to the input tensor `x`, concatenates results for feature extraction. + """Applies convolution and max pooling layers to the input tensor `x`, concatenates results for feature + extraction. `x` is a tensor of shape [N, C, H, W]. See https://arxiv.org/abs/1406.4729 for more details. """ @@ -743,8 +739,7 @@ def warmup(self, imgsz=(1, 3, 640, 640)): @staticmethod def _model_type(p="path/to/model.pt"): - """ - Determines model type from filepath or URL, supports various formats including ONNX, PT, JIT. + """Determines model type from filepath or URL, supports various formats including ONNX, PT, JIT. See `export_formats` for all. """ @@ -958,16 +953,14 @@ def _run(self, pprint=False, show=False, save=False, crop=False, render=False, l @TryExcept("Showing images is not supported in this environment") def show(self, labels=True): - """ - Displays image results with optional labels. + """Displays image results with optional labels. Usage: `show(labels=True)` """ self._run(show=True, labels=labels) # show results def save(self, labels=True, save_dir="runs/detect/exp", exist_ok=False): - """ - Saves image results with optional labels to a specified directory. + """Saves image results with optional labels to a specified directory. Usage: `save(labels=True, save_dir='runs/detect/exp', exist_ok=False)` """ @@ -975,8 +968,7 @@ def save(self, labels=True, save_dir="runs/detect/exp", exist_ok=False): self._run(save=True, labels=labels, save_dir=save_dir) # save results def crop(self, save=True, save_dir="runs/detect/exp", exist_ok=False): - """ - Crops detection results; can save to `save_dir`. + """Crops detection results; can save to `save_dir`. Usage: `crop(save=True, save_dir='runs/detect/exp')`. """ @@ -984,8 +976,7 @@ def crop(self, save=True, save_dir="runs/detect/exp", exist_ok=False): return self._run(crop=True, save=save, save_dir=save_dir) # crop results def render(self, labels=True): - """ - Renders detection results, optionally displaying labels. + """Renders detection results, optionally displaying labels. Usage: `render(labels=True)`. """ diff --git a/models/experimental.py b/models/experimental.py index 990e815243..db0f20514e 100644 --- a/models/experimental.py +++ b/models/experimental.py @@ -15,8 +15,7 @@ class Sum(nn.Module): """Computes the weighted or unweighted sum of multiple input layers per https://arxiv.org/abs/1911.09070.""" def __init__(self, n, weight=False): # n: number of inputs - """ - Initializes a module to compute weighted/unweighted sum of n inputs, with optional learning weights. + """Initializes a module to compute weighted/unweighted sum of n inputs, with optional learning weights. https://arxiv.org/abs/1911.09070 """ @@ -27,8 +26,7 @@ def __init__(self, n, weight=False): # n: number of inputs self.w = nn.Parameter(-torch.arange(1.0, n) / 2, requires_grad=True) # layer weights def forward(self, x): - """ - Performs forward pass, blending `x` elements with optional learnable weights. + """Performs forward pass, blending `x` elements with optional learnable weights. See https://arxiv.org/abs/1911.09070 for more. """ @@ -47,8 +45,7 @@ class MixConv2d(nn.Module): """Implements mixed depth-wise convolutions for efficient neural networks; see https://arxiv.org/abs/1907.09595.""" def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): # ch_in, ch_out, kernel, stride, ch_strategy - """Initializes MixConv2d with mixed depth-wise convolution layers; details at - https://arxiv.org/abs/1907.09595. + """Initializes MixConv2d with mixed depth-wise convolution layers; details at https://arxiv.org/abs/1907.09595. """ super().__init__() n = len(k) # number of convolutions diff --git a/models/tf.py b/models/tf.py index caa90c1ca0..d3b933fea2 100644 --- a/models/tf.py +++ b/models/tf.py @@ -335,8 +335,7 @@ class TFSPPF(keras.layers.Layer): """Implements a fast spatial pyramid pooling layer for efficient multi-scale feature extraction in YOLOv3 models.""" def __init__(self, c1, c2, k=5, w=None): - """Initializes a Spatial Pyramid Pooling-Fast layer with specified channels, kernel size, and optional - weights. + """Initializes a Spatial Pyramid Pooling-Fast layer with specified channels, kernel size, and optional weights. """ super().__init__() c_ = c1 // 2 # hidden channels @@ -480,8 +479,7 @@ def call(self, inputs): def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3) - """Parses model configuration and constructs Keras model with layer connectivity, returning the model and save - list. + """Parses model configuration and constructs Keras model with layer connectivity, returning the model and save list. """ LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}") anchors, nc, gd, gw = d["anchors"], d["nc"], d["depth_multiple"], d["width_multiple"] @@ -557,8 +555,7 @@ class TFModel: """TensorFlow implementation of YOLOv3 for object detection, supporting Keras and TFLite models.""" def __init__(self, cfg="yolov5s.yaml", ch=3, nc=None, model=None, imgsz=(640, 640)): # model, channels, classes - """Initializes TF YOLOv3 model with config, channels, classes, optional pre-loaded model, and input image - size. + """Initializes TF YOLOv3 model with config, channels, classes, optional pre-loaded model, and input image size. """ super().__init__() if isinstance(cfg, dict): @@ -619,8 +616,7 @@ def predict( @staticmethod def _xywh2xyxy(xywh): - """Converts bounding boxes from [x, y, w, h] format to [x1, y1, x2, y2], where xy1=top-left, xy2=bottom- - right. + """Converts bounding boxes from [x, y, w, h] format to [x1, y1, x2, y2], where xy1=top-left, xy2=bottom- right. """ x, y, w, h = tf.split(xywh, num_or_size_splits=4, axis=-1) return tf.concat([x - w / 2, y - h / 2, x + w / 2, y + h / 2], axis=-1) diff --git a/models/yolo.py b/models/yolo.py index 79942c32cb..125395db32 100644 --- a/models/yolo.py +++ b/models/yolo.py @@ -62,8 +62,7 @@ def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer self.inplace = inplace # use inplace ops (e.g. slice assignment) def forward(self, x): - """ - Processes input through convolutional layers, reshaping output for detection. + """Processes input through convolutional layers, reshaping output for detection. Expects x as list of tensors with shape(bs, C, H, W). """ @@ -92,8 +91,7 @@ def forward(self, x): return x if self.training else (torch.cat(z, 1),) if self.export else (torch.cat(z, 1), x) def _make_grid(self, nx=20, ny=20, i=0, torch_1_10=check_version(torch.__version__, "1.10.0")): - """Generates a grid and corresponding anchor grid with shape `(1, num_anchors, ny, nx, 2)` for indexing - anchors. + """Generates a grid and corresponding anchor grid with shape `(1, num_anchors, ny, nx, 2)` for indexing anchors. """ d = self.anchors[i].device t = self.anchors[i].dtype diff --git a/segment/val.py b/segment/val.py index 2da9a7e1ac..378cdef8e7 100644 --- a/segment/val.py +++ b/segment/val.py @@ -109,11 +109,11 @@ def single_encode(x): def process_batch(detections, labels, iouv, pred_masks=None, gt_masks=None, overlap=False, masks=False): - """ - Return correct prediction matrix - Arguments: - detections (array[N, 6]), x1, y1, x2, y2, conf, class - labels (array[M, 5]), class, x1, y1, x2, y2 + """Return correct prediction matrix. + + Args: + detections (array[N, 6]), x1, y1, x2, y2, conf, class: labels (array[M, 5]), class, x1, y1, x2, y2 + Returns: correct (array[N, 10]), for 10 IoU levels. """ diff --git a/train.py b/train.py index a2671f5d1d..620c1e3af7 100644 --- a/train.py +++ b/train.py @@ -103,8 +103,7 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary - """ - Train a YOLOv3 model on a custom dataset and manage the training process. + """Train a YOLOv3 model on a custom dataset and manage the training process. Args: hyp (str | dict): Path to hyperparameters yaml file or hyperparameters dictionary. @@ -114,18 +113,15 @@ def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictio Returns: None - - Usage - Single-GPU training: + Usage - Single-GPU training: $ python train.py --data coco128.yaml --weights yolov5s.pt --img 640 # from pretrained (recommended) $ python train.py --data coco128.yaml --weights '' --cfg yolov5s.yaml --img 640 # from scratch - - Usage - Multi-GPU DDP training: + Usage - Multi-GPU DDP training: $ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 train.py --data coco128.yaml --weights yolov5s.pt --img 640 --device 0,1,2,3 - - Models: https://github.com/ultralytics/yolov5/tree/master/models - Datasets: https://github.com/ultralytics/yolov5/tree/master/data - Tutorial: https://docs.ultralytics.com/yolov5/tutorials/train_custom_data + Models: https://github.com/ultralytics/yolov5/tree/master/models + Datasets: https://github.com/ultralytics/yolov5/tree/master/data + Tutorial: https://docs.ultralytics.com/yolov5/tutorials/train_custom_data Examples: ```python @@ -546,8 +542,7 @@ def lf(x): def parse_opt(known=False): - """ - Parse command line arguments for configuring the training of a YOLO model. + """Parse command line arguments for configuring the training of a YOLO model. Args: known (bool): Flag to parse known arguments only, defaults to False. @@ -616,8 +611,7 @@ def parse_opt(known=False): def main(opt, callbacks=Callbacks()): - """ - Main training/evolution script handling model checks, DDP setup, training, and hyperparameter evolution. + """Main training/evolution script handling model checks, DDP setup, training, and hyperparameter evolution. Args: opt (argparse.Namespace): Parsed command-line options. @@ -627,12 +621,10 @@ def main(opt, callbacks=Callbacks()): None Raises: - AssertionError: If certain constraints are violated (e.g., when specific options are incompatible with DDP training). + AssertionError: If certain constraints are violated (e.g., when specific options are incompatible with DDP + training). - Notes: - - For a tutorial on using Multi-GPU with DDP: https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training - - Example: + Examples: Single-GPU training: ```python $ python train.py --data coco128.yaml --weights yolov5s.pt --img 640 # from pretrained (recommended) @@ -641,13 +633,15 @@ def main(opt, callbacks=Callbacks()): Multi-GPU DDP training: ```python - $ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 train.py --data coco128.yaml \ - --weights yolov5s.pt --img 640 --device 0,1,2,3 + $ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 train.py --data coco128.yaml --weights yolov5s.pt --img 640 --device 0,1,2,3 ``` Models: https://github.com/ultralytics/yolov5/tree/master/models Datasets: https://github.com/ultralytics/yolov5/tree/master/data Tutorial: https://docs.ultralytics.com/yolov5/tutorials/train_custom_data + + Notes: + - For a tutorial on using Multi-GPU with DDP: https://docs.ultralytics.com/yolov5/tutorials/multi_gpu_training """ if RANK in {-1, 0}: print_args(vars(opt)) @@ -814,8 +808,7 @@ def main(opt, callbacks=Callbacks()): def run(**kwargs): - """ - Run the training process for a YOLOv3 model with the specified configurations. + """Run the training process for a YOLOv3 model with the specified configurations. Args: data (str): Path to the dataset YAML file. @@ -826,7 +819,8 @@ def run(**kwargs): batch_size (int): Total batch size across all GPUs. imgsz (int): Image size for training and validation (in pixels). rect (bool): Use rectangular training for better aspect ratio preservation. - resume (bool | str): Resume most recent training if True, or resume training from a specific checkpoint if a string. + resume (bool | str): Resume most recent training if True, or resume training from a specific checkpoint if a + string. nosave (bool): Only save the final checkpoint and not the intermediate ones. noval (bool): Only validate model performance in the final epoch. noautoanchor (bool): Disable automatic anchor generation. @@ -856,7 +850,7 @@ def run(**kwargs): Returns: None - Example: + Examples: ```python from ultralytics import run run(data='coco128.yaml', weights='yolov5m.pt', imgsz=320, epochs=100, batch_size=16) diff --git a/utils/__init__.py b/utils/__init__.py index 71d21d5a8f..1d0b1c6bc3 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -36,15 +36,13 @@ def __exit__(self, exc_type, value, traceback): def threaded(func): - """ - Decorates a function to run in a separate thread, returning the thread object. + """Decorates a function to run in a separate thread, returning the thread object. Usage: @threaded. """ def wrapper(*args, **kwargs): - """ - Runs the decorated function in a separate thread and returns the thread object. + """Runs the decorated function in a separate thread and returns the thread object. Usage: @threaded. """ diff --git a/utils/activations.py b/utils/activations.py index 0a1a79766a..ca785bec79 100644 --- a/utils/activations.py +++ b/utils/activations.py @@ -33,8 +33,7 @@ class Mish(nn.Module): @staticmethod def forward(x): - """ - Applies the Mish activation function, enhancing model performance and convergence. + """Applies the Mish activation function, enhancing model performance and convergence. Reference: https://github.com/digantamisra98/Mish """ @@ -87,9 +86,8 @@ def forward(self, x): class AconC(nn.Module): - r"""ACON activation (activate or not) - AconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is a learnable parameter - according to "Activate or Not: Learning Customized Activation" . + r"""ACON activation (activate or not) AconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is a learnable + parameter according to "Activate or Not: Learning Customized Activation" . """ def __init__(self, c1): @@ -102,17 +100,16 @@ def __init__(self, c1): self.beta = nn.Parameter(torch.ones(1, c1, 1, 1)) def forward(self, x): - """Applies a parametric activation function to tensor x; see https://arxiv.org/pdf/2009.04759.pdf for - details. + """Applies a parametric activation function to tensor x; see https://arxiv.org/pdf/2009.04759.pdf for details. """ dpx = (self.p1 - self.p2) * x return dpx * torch.sigmoid(self.beta * dpx) + self.p2 * x class MetaAconC(nn.Module): - r"""ACON activation (activate or not) - MetaAconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is generated by a small network - according to "Activate or Not: Learning Customized Activation" . + r"""ACON activation (activate or not) MetaAconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is generated + by a small network according to "Activate or Not: Learning Customized + Activation" . """ def __init__(self, c1, k=1, s=1, r=16): # ch_in, kernel, stride, r diff --git a/utils/augmentations.py b/utils/augmentations.py index 824066f309..3365bebb00 100644 --- a/utils/augmentations.py +++ b/utils/augmentations.py @@ -61,8 +61,7 @@ def normalize(x, mean=IMAGENET_MEAN, std=IMAGENET_STD, inplace=False): def denormalize(x, mean=IMAGENET_MEAN, std=IMAGENET_STD): - """ - Converts normalized images back to original form using ImageNet stats; inputs in BCHW format. + """Converts normalized images back to original form using ImageNet stats; inputs in BCHW format. Example: `denormalize(tensor)`. """ @@ -72,8 +71,7 @@ def denormalize(x, mean=IMAGENET_MEAN, std=IMAGENET_STD): def augment_hsv(im, hgain=0.5, sgain=0.5, vgain=0.5): - """ - Applies HSV color-space augmentation with optional gains; expects BGR image input. + """Applies HSV color-space augmentation with optional gains; expects BGR image input. Example: `augment_hsv(image)`. """ @@ -286,8 +284,7 @@ def cutout(im, labels, p=0.5): def mixup(im, labels, im2, labels2): - """Applies MixUp augmentation by blending images and labels; see https://arxiv.org/pdf/1710.09412.pdf for - details. + """Applies MixUp augmentation by blending images and labels; see https://arxiv.org/pdf/1710.09412.pdf for details. """ r = np.random.beta(32.0, 32.0) # mixup ratio, alpha=beta=32.0 im = (im * r + im2 * (1 - r)).astype(np.uint8) diff --git a/utils/autoanchor.py b/utils/autoanchor.py index 3599d66865..e6dd98e543 100644 --- a/utils/autoanchor.py +++ b/utils/autoanchor.py @@ -33,8 +33,7 @@ def check_anchors(dataset, model, thr=4.0, imgsz=640): wh = torch.tensor(np.concatenate([l[:, 3:5] * s for s, l in zip(shapes * scale, dataset.labels)])).float() # wh def metric(k): # compute metric - """Computes and returns best possible recall (bpr) and anchors above threshold (aat) metrics for given - anchors. + """Computes and returns best possible recall (bpr) and anchors above threshold (aat) metrics for given anchors. """ r = wh[:, None] / k[None] x = torch.min(r, 1 / r).min(2)[0] # ratio metric @@ -66,10 +65,9 @@ def metric(k): # compute metric def kmean_anchors(dataset="./data/coco128.yaml", n=9, img_size=640, thr=4.0, gen=1000, verbose=True): - """ - Creates kmeans-evolved anchors from training dataset. + """Creates kmeans-evolved anchors from training dataset. - Arguments: + Args: dataset: path to data.yaml, or a loaded dataset n: number of anchors img_size: image size used for training @@ -77,10 +75,10 @@ def kmean_anchors(dataset="./data/coco128.yaml", n=9, img_size=640, thr=4.0, gen gen: generations to evolve anchors using genetic algorithm verbose: print all results - Return: + Returns: k: kmeans evolved anchors - Usage: + Examples: from utils.autoanchor import *; _ = kmean_anchors() """ from scipy.cluster.vq import kmeans diff --git a/utils/callbacks.py b/utils/callbacks.py index 0ef2e41ebf..80cfe740de 100644 --- a/utils/callbacks.py +++ b/utils/callbacks.py @@ -33,8 +33,7 @@ def __init__(self): self.stop_training = False # set True to interrupt training def register_action(self, hook, name="", callback=None): - """ - Register a new action to a callback hook. + """Register a new action to a callback hook. Args: hook: The callback hook name to register the action to @@ -46,8 +45,7 @@ def register_action(self, hook, name="", callback=None): self._callbacks[hook].append({"name": name, "callback": callback}) def get_registered_actions(self, hook=None): - """ - " Returns all the registered actions by callback hook. + """" Returns all the registered actions by callback hook. Args: hook: The name of the hook to check, defaults to all @@ -55,8 +53,7 @@ def get_registered_actions(self, hook=None): return self._callbacks[hook] if hook else self._callbacks def run(self, hook, *args, thread=False, **kwargs): - """ - Loop through the registered actions and fire all callbacks on main thread. + """Loop through the registered actions and fire all callbacks on main thread. Args: hook: The name of the hook to check, defaults to all diff --git a/utils/dataloaders.py b/utils/dataloaders.py index f5edffaaf6..766984aeee 100644 --- a/utils/dataloaders.py +++ b/utils/dataloaders.py @@ -183,8 +183,7 @@ def create_dataloader( class InfiniteDataLoader(dataloader.DataLoader): - """ - Dataloader that reuses workers. + """Dataloader that reuses workers. Uses same syntax as vanilla DataLoader """ @@ -208,8 +207,7 @@ def __iter__(self): class _RepeatSampler: - """ - Sampler that repeats forever. + """Sampler that repeats forever. Args: sampler (Sampler) @@ -486,8 +484,7 @@ def __len__(self): def img2label_paths(img_paths): - """Converts image paths to corresponding label paths by replacing `/images/` with `/labels/` and `.jpg` with - `.txt`. + """Converts image paths to corresponding label paths by replacing `/images/` with `/labels/` and `.jpg` with `.txt`. """ sa, sb = f"{os.sep}images{os.sep}", f"{os.sep}labels{os.sep}" # /images/, /labels/ substrings return [sb.join(x.rsplit(sa, 1)).rsplit(".", 1)[0] + ".txt" for x in img_paths] @@ -828,8 +825,7 @@ def cache_images_to_disk(self, i): np.save(f.as_posix(), cv2.imread(self.im_files[i])) def load_mosaic(self, index): - """Loads 4 images into a mosaic for YOLOv3 training, enhancing detection capabilities through data - augmentation. + """Loads 4 images into a mosaic for YOLOv3 training, enhancing detection capabilities through data augmentation. """ labels4, segments4 = [], [] s = self.img_size @@ -1053,13 +1049,13 @@ def extract_boxes(path=DATASETS_DIR / "coco128"): # from utils.dataloaders impo def autosplit(path=DATASETS_DIR / "coco128/images", weights=(0.9, 0.1, 0.0), annotated_only=False): - """Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files - Usage: from utils.dataloaders import *; autosplit(). + """Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files Usage: from utils.dataloaders + import *; autosplit(). - Arguments: - path: Path to images directory - weights: Train, val, test weights (list, tuple) - annotated_only: Only use images with an annotated txt file + Args: + path: Path to images directory + weights: Train, val, test weights (list, tuple) + annotated_only: Only use images with an annotated txt file """ path = Path(path) # images dir files = sorted(x for x in path.rglob("*.*") if x.suffix[1:].lower() in IMG_FORMATS) # image files only @@ -1131,14 +1127,13 @@ def verify_image_label(args): class HUBDatasetStats: - """ - Class for generating HUB dataset JSON and `-hub` dataset directory. + """Class for generating HUB dataset JSON and `-hub` dataset directory. - Arguments: - path: Path to data.yaml or data.zip (with data.yaml inside data.zip) - autodownload: Attempt to download dataset if not found locally + Args: + path: Path to data.yaml or data.zip (with data.yaml inside data.zip) + autodownload: Attempt to download dataset if not found locally - Usage + Usage from utils.dataloaders import HUBDatasetStats stats = HUBDatasetStats('coco128.yaml', autodownload=True) # usage 1 stats = HUBDatasetStats('path/to/coco128.zip') # usage 2 @@ -1264,12 +1259,11 @@ def process_images(self): # Classification dataloaders ------------------------------------------------------------------------------------------- class ClassificationDataset(torchvision.datasets.ImageFolder): - """ - YOLOv3 Classification Dataset. + """YOLOv3 Classification Dataset. - Arguments: - root: Dataset path - transform: torchvision transforms, used by default + Args: + root: Dataset path + transform: torchvision transforms, used by default album_transform: Albumentations transforms, used if installed """ diff --git a/utils/general.py b/utils/general.py index 71f71deddb..860131000e 100644 --- a/utils/general.py +++ b/utils/general.py @@ -79,8 +79,8 @@ def is_colab(): def is_jupyter(): - """ - Check if the current script is running inside a Jupyter Notebook. Verified on Colab, Jupyterlab, Kaggle, Paperspace. + """Check if the current script is running inside a Jupyter Notebook. Verified on Colab, Jupyterlab, Kaggle, + Paperspace. Returns: bool: True if running inside a Jupyter Notebook, False otherwise. @@ -180,8 +180,7 @@ class Profile(contextlib.ContextDecorator): """Profiles code execution time, usable as a context manager or decorator for performance monitoring.""" def __init__(self, t=0.0): - """Initializes a profiling context for YOLOv3 with optional timing threshold `t` and checks CUDA - availability. + """Initializes a profiling context for YOLOv3 with optional timing threshold `t` and checks CUDA availability. """ self.t = t self.cuda = torch.cuda.is_available() @@ -209,8 +208,7 @@ class Timeout(contextlib.ContextDecorator): """Enforces a timeout on code execution, raising TimeoutError on expiry.""" def __init__(self, seconds, *, timeout_msg="", suppress_timeout_errors=True): - """Initializes a timeout context/decorator with specified duration, custom message, and error handling - option. + """Initializes a timeout context/decorator with specified duration, custom message, and error handling option. """ self.seconds = int(seconds) self.timeout_message = timeout_msg @@ -302,8 +300,7 @@ def get_default_args(func): def get_latest_run(search_dir="."): - """Returns path to the most recent 'last.pt' file within 'search_dir' for resuming, or an empty string if not - found. + """Returns path to the most recent 'last.pt' file within 'search_dir' for resuming, or an empty string if not found. """ last_list = glob.glob(f"{search_dir}/**/last*.pt", recursive=True) return max(last_list, key=os.path.getctime) if last_list else "" @@ -334,8 +331,7 @@ def file_size(path): def check_online(): - """Checks internet connectivity by attempting to connect to "1.1.1.1" on port 443 twice; returns True if - successful. + """Checks internet connectivity by attempting to connect to "1.1.1.1" on port 443 twice; returns True if successful. """ import socket @@ -391,8 +387,7 @@ def check_git_status(repo="ultralytics/yolov5", branch="master"): @WorkingDirectory(ROOT) def check_git_info(path="."): - """ - Checks YOLOv3 git info (remote, branch, commit) in path, requires 'gitpython'. + """Checks YOLOv3 git info (remote, branch, commit) in path, requires 'gitpython'. Returns dict. """ @@ -643,13 +638,11 @@ def url2file(url): def download(url, dir=".", unzip=True, delete=True, curl=False, threads=1, retry=3): - """Downloads files from URLs into a specified directory, optionally unzips, and supports multithreading and - retries. + """Downloads files from URLs into a specified directory, optionally unzips, and supports multithreading and retries. """ def download_one(url, dir): - """Downloads a file from a URL into the specified directory, supporting retries and using curl or torch - methods. + """Downloads a file from a URL into the specified directory, supporting retries and using curl or torch methods. """ success = True if os.path.isfile(url): @@ -706,15 +699,14 @@ def clean_str(s): def one_cycle(y1=0.0, y2=1.0, steps=100): - """Generates a lambda for a sinusoidal ramp from y1 to y2 over 'steps'; usage: `lambda x: ((1 - math.cos(x * - math.pi / steps)) / 2) * (y2 - y1) + y1`. + """Generates a lambda for a sinusoidal ramp from y1 to y2 over 'steps'; usage: `lambda x: ((1 - math.cos(x * math.pi + / steps)) / 2) * (y2 - y1) + y1`. """ return lambda x: ((1 - math.cos(x * math.pi / steps)) / 2) * (y2 - y1) + y1 def colorstr(*input): - """ - Colors strings using ANSI escape codes; see usage example `colorstr('blue', 'hello world')`. + """Colors strings using ANSI escape codes; see usage example `colorstr('blue', 'hello world')`. [https://en.wikipedia.org/wiki/ANSI_escape_code] """ @@ -772,8 +764,7 @@ def labels_to_image_weights(labels, nc=80, class_weights=np.ones(80)): def coco80_to_coco91_class(): # converts 80-index (val2014) to 91-index (paper) - """ - Converts COCO 80-class index to COCO 91-class index. + """Converts COCO 80-class index to COCO 91-class index. Reference: https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/ """ @@ -1017,11 +1008,10 @@ def non_max_suppression( max_det=300, nm=0, # number of masks ): - """ - Non-Maximum Suppression (NMS) on inference results to reject overlapping detections. + """Non-Maximum Suppression (NMS) on inference results to reject overlapping detections. Returns: - list of detections, on (n,6) tensor per image [xyxy, conf, cls] + list of detections, on (n,6) tensor per image [xyxy, conf, cls] """ # Checks assert 0 <= conf_thres <= 1, f"Invalid Confidence threshold {conf_thres}, valid values are between 0.0 and 1.0" @@ -1226,8 +1216,7 @@ def apply_classifier(x, model, img, im0): def increment_path(path, exist_ok=False, sep="", mkdir=False): - """ - Increments file or directory path, optionally creating the directory, not thread-safe. + """Increments file or directory path, optionally creating the directory, not thread-safe. Args: path (str/Path), exist_ok (bool), sep (str), mkdir (bool). """ @@ -1266,8 +1255,7 @@ def imread(filename, flags=cv2.IMREAD_COLOR): def imwrite(filename, img): - """ - Writes an image to a file; returns True on success, False on failure. + """Writes an image to a file; returns True on success, False on failure. Args: filename (str), img (ndarray). """ diff --git a/utils/loggers/__init__.py b/utils/loggers/__init__.py index ce2206fca4..754d913ec9 100644 --- a/utils/loggers/__init__.py +++ b/utils/loggers/__init__.py @@ -66,8 +66,7 @@ class Loggers: """Manages logging for training and validation using TensorBoard, Weights & Biases, ClearML, and Comet ML.""" def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, include=LOGGERS): - """Initializes YOLOv3 logging with directory, weights, options, hyperparameters, and includes specified - loggers. + """Initializes YOLOv3 logging with directory, weights, options, hyperparameters, and includes specified loggers. """ self.save_dir = save_dir self.weights = weights @@ -166,8 +165,7 @@ def on_pretrain_routine_start(self): self.comet_logger.on_pretrain_routine_start() def on_pretrain_routine_end(self, labels, names): - """ - Logs pretrain routine end, plots labels if enabled, updates WandB/Comet with images. + """Logs pretrain routine end, plots labels if enabled, updates WandB/Comet with images. Takes `labels` (List of int), `names` (List of str). """ @@ -225,8 +223,7 @@ def on_val_image_end(self, pred, predn, path, names, im): self.clearml.log_image_with_boxes(path, pred, names, im) def on_val_batch_end(self, batch_i, im, targets, paths, shapes, out): - """ - Logs a single validation batch for Comet ML analytics (batch_i: int, im: tensor, targets: tensor, paths: + """Logs a single validation batch for Comet ML analytics (batch_i: int, im: tensor, targets: tensor, paths:. list, shapes: list, out: tensor). """ @@ -279,8 +276,7 @@ def on_fit_epoch_end(self, vals, epoch, best_fitness, fi): self.comet_logger.on_fit_epoch_end(x, epoch=epoch) def on_model_save(self, last, epoch, final_epoch, best_fitness, fi): - """Logs model to WandB/ClearML, considering save_period and if not final_epoch, also notes if best model so - far. + """Logs model to WandB/ClearML, considering save_period and if not final_epoch, also notes if best model so far. """ if (epoch + 1) % self.opt.save_period == 0 and not final_epoch and self.opt.save_period != -1: if self.wandb: @@ -338,14 +334,13 @@ def on_params_update(self, params: dict): class GenericLogger: - """ - YOLOv3 General purpose logger for non-task specific logging - Usage: from utils.loggers import GenericLogger; logger = GenericLogger(...). + """YOLOv3 General purpose logger for non-task specific logging Usage: from utils.loggers import GenericLogger; + logger = GenericLogger(...). - Arguments: - opt: Run arguments - console_logger: Console logger - include: loggers to include + Args: + opt: Run arguments + console_logger: Console logger + include: loggers to include """ def __init__(self, opt, console_logger, include=("tb", "wandb")): @@ -430,8 +425,7 @@ def log_tensorboard_graph(tb, model, imgsz=(640, 640)): def web_project_name(project): - """Converts local project name to a web-friendly format by adding a suffix based on its type (classify or - segment). + """Converts local project name to a web-friendly format by adding a suffix based on its type (classify or segment). """ if not project.startswith("runs/train"): return project diff --git a/utils/loggers/clearml/clearml_utils.py b/utils/loggers/clearml/clearml_utils.py index 215c830cb0..872b85ca8c 100644 --- a/utils/loggers/clearml/clearml_utils.py +++ b/utils/loggers/clearml/clearml_utils.py @@ -61,8 +61,7 @@ def construct_dataset(clearml_info_string): class ClearmlLogger: - """ - Log training runs, datasets, models, and predictions to ClearML. + """Log training runs, datasets, models, and predictions to ClearML. This logger sends information to ClearML at app.clear.ml or to your own hosted server. By default, this information includes hyperparameters, system configuration and metrics, model metrics, code information and basic data metrics @@ -72,14 +71,11 @@ class ClearmlLogger: """ def __init__(self, opt, hyp): - """ - - Initialize ClearML Task, this object will capture the experiment - - Upload dataset version to ClearML Data if opt.upload_dataset is True. - - Arguments: - opt (namespace) -- Commandline arguments for this run - hyp (dict) -- Hyperparameters for this run + """- Initialize ClearML Task, this object will capture the experiment - Upload dataset version to ClearML Data + if opt.upload_dataset is True. + Args: + opt (namespace) -- Commandline arguments for this run: hyp (dict) -- Hyperparameters for this run """ self.current_epoch = 0 # Keep tracked of amount of logged images to enforce a limit @@ -124,12 +120,11 @@ def __init__(self, opt, hyp): opt.data = self.data_dict def log_debug_samples(self, files, title="Debug Samples"): - """ - Log files (images) as debug samples in the ClearML task. + """Log files (images) as debug samples in the ClearML task. - Arguments: - files (List(PosixPath)) a list of file paths in PosixPath format - title (str) A title that groups together images with the same values + Args: + files (List(PosixPath)) a list of file paths in PosixPath format: title (str) A title that groups together + images with the same values """ for f in files: if f.exists(): @@ -140,14 +135,13 @@ def log_debug_samples(self, files, title="Debug Samples"): ) def log_image_with_boxes(self, image_path, boxes, class_names, image, conf_threshold=0.25): - """ - Draw the bounding boxes on a single image and report the result as a ClearML debug sample. + """Draw the bounding boxes on a single image and report the result as a ClearML debug sample. - Arguments: - image_path (PosixPath) the path the original image file - boxes (list): list of scaled predictions in the format - [xmin, ymin, xmax, ymax, confidence, class] - class_names (dict): dict containing mapping of class int to class name - image (Tensor): A torch tensor containing the actual image data + Args: + image_path (PosixPath) the path the original image file + boxes (list): list of scaled predictions in the format - [xmin, ymin, xmax, ymax, confidence, class] + class_names (dict): dict containing mapping of class int to class name + image (Tensor): A torch tensor containing the actual image data """ if ( len(self.current_epoch_logged_images) < self.max_imgs_to_log_per_epoch diff --git a/utils/loggers/comet/comet_utils.py b/utils/loggers/comet/comet_utils.py index 841e200e04..d5d26c03cf 100644 --- a/utils/loggers/comet/comet_utils.py +++ b/utils/loggers/comet/comet_utils.py @@ -67,8 +67,7 @@ def download_model_checkpoint(opt, experiment): def set_opt_parameters(opt, experiment): - """ - Update the opts Namespace with parameters from Comet's ExistingExperiment when resuming a run. + """Update the opts Namespace with parameters from Comet's ExistingExperiment when resuming a run. Args: opt (argparse.Namespace): Namespace of command line options @@ -98,16 +97,13 @@ def set_opt_parameters(opt, experiment): def check_comet_weights(opt): - """ - Downloads model weights from Comet and updates the weights path to point to saved weights location. + """Downloads model weights from Comet and updates the weights path to point to saved weights location. Args: - opt (argparse.Namespace): Command Line arguments passed - to YOLOv3 training script + opt (argparse.Namespace): Command Line arguments passed to YOLOv3 training script Returns: - None/bool: Return True if weights are successfully downloaded - else return None + None/bool: Return True if weights are successfully downloaded else return None """ if comet_ml is None: return @@ -124,16 +120,13 @@ def check_comet_weights(opt): def check_comet_resume(opt): - """ - Restores run parameters to its original state based on the model checkpoint and logged Experiment parameters. + """Restores run parameters to its original state based on the model checkpoint and logged Experiment parameters. Args: - opt (argparse.Namespace): Command Line arguments passed - to YOLOv3 training script + opt (argparse.Namespace): Command Line arguments passed to YOLOv3 training script Returns: - None/bool: Return True if the run is restored successfully - else return None + None/bool: Return True if the run is restored successfully else return None """ if comet_ml is None: return diff --git a/utils/loggers/wandb/wandb_utils.py b/utils/loggers/wandb/wandb_utils.py index 9028934bd9..c2b7626673 100644 --- a/utils/loggers/wandb/wandb_utils.py +++ b/utils/loggers/wandb/wandb_utils.py @@ -31,8 +31,7 @@ class WandbLogger: - """ - Log training runs, datasets, models, and predictions to Weights & Biases. + """Log training runs, datasets, models, and predictions to Weights & Biases. This logger sends information to W&B at wandb.ai. By default, this information includes hyperparameters, system configuration and metrics, model metrics, and basic data metrics and analyses. @@ -44,16 +43,12 @@ class WandbLogger: """ def __init__(self, opt, run_id=None, job_type="Training"): - """ - - Initialize WandbLogger instance - - Upload dataset if opt.upload_dataset is True - - Setup training processes if job_type is 'Training'. - - Arguments: - opt (namespace) -- Commandline arguments for this run - run_id (str) -- Run ID of W&B run to be resumed - job_type (str) -- To set the job_type for this run + """- Initialize WandbLogger instance - Upload dataset if opt.upload_dataset is True - Setup training processes + if job_type is 'Training'. + Args: + opt (namespace) -- Commandline arguments for this run: run_id (str) -- Run ID of W&B run to be resumed + job_type (str) -- To set the job_type for this run """ # Pre-training routine -- self.job_type = job_type @@ -84,15 +79,13 @@ def __init__(self, opt, run_id=None, job_type="Training"): self.setup_training(opt) def setup_training(self, opt): - """ - Setup the necessary processes for training YOLO models: - - Attempt to download model checkpoint and dataset artifacts if opt.resume stats with WANDB_ARTIFACT_PREFIX - - Update data_dict, to contain info of previous run if resumed and the paths of dataset artifact if downloaded - - Setup log_dict, initialize bbox_interval. - - Arguments: - opt (namespace) -- commandline arguments for this run + """Setup the necessary processes for training YOLO models: - Attempt to download model checkpoint and dataset + artifacts if opt.resume stats with WANDB_ARTIFACT_PREFIX - Update data_dict, to contain info of previous + run if resumed and the paths of dataset artifact if downloaded - Setup log_dict, + initialize bbox_interval. + Args: + opt (namespace) -- commandline arguments for this run """ self.log_dict, self.current_epoch = {}, 0 self.bbox_interval = opt.bbox_interval @@ -117,15 +110,12 @@ def setup_training(self, opt): self.bbox_interval = opt.bbox_interval = opt.epochs + 1 # disable bbox_interval def log_model(self, path, opt, epoch, fitness_score, best_model=False): - """ - Log the model checkpoint as W&B artifact. - - Arguments: - path (Path) -- Path of directory containing the checkpoints - opt (namespace) -- Command line arguments for this run - epoch (int) -- Current epoch number - fitness_score (float) -- fitness score for current epoch - best_model (boolean) -- Boolean representing if the current checkpoint is the best yet. + """Log the model checkpoint as W&B artifact. + + Args: + path (Path) -- Path of directory containing the checkpoints: opt (namespace) -- Command line arguments for + this run epoch (int) -- Current epoch number fitness_score (float) -- fitness score for current epoch + best_model (boolean) -- Boolean representing if the current checkpoint is the best yet. """ model_artifact = wandb.Artifact( f"run_{wandb.run.id}_model", @@ -156,22 +146,20 @@ def val_one_image(self, pred, predn, path, names, im): pass def log(self, log_dict): - """ - Save the metrics to the logging dictionary. + """Save the metrics to the logging dictionary. - Arguments: - log_dict (Dict) -- metrics/media to be logged in current step + Args: + log_dict (Dict) -- metrics/media to be logged in current step """ if self.wandb_run: for key, value in log_dict.items(): self.log_dict[key] = value def end_epoch(self): - """ - Commit the log_dict, model artifacts and Tables to W&B and flush the log_dict. + """Commit the log_dict, model artifacts and Tables to W&B and flush the log_dict. - Arguments: - best_result (boolean): Boolean representing if the result of this evaluation is best or not + Args: + best_result (boolean): Boolean representing if the result of this evaluation is best or not """ if self.wandb_run: with all_logging_disabled(): diff --git a/utils/loss.py b/utils/loss.py index b3fa859838..3444a081e4 100644 --- a/utils/loss.py +++ b/utils/loss.py @@ -87,8 +87,7 @@ def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): self.loss_fcn.reduction = "none" # required to apply FL to each element def forward(self, pred, true): - """Computes focal loss between predictions and true labels using configured loss function, `gamma`, and - `alpha`. + """Computes focal loss between predictions and true labels using configured loss function, `gamma`, and `alpha`. """ loss = self.loss_fcn(pred, true) diff --git a/utils/metrics.py b/utils/metrics.py index 1298208b22..72b3072ac4 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -27,11 +27,9 @@ def smooth(y, f=0.05): def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir=".", names=(), eps=1e-16, prefix=""): - """ - Compute the average precision, given the recall and precision curves. + """Compute the average precision, given the recall and precision curves. - Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. - # Arguments + Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. # Arguments tp: True positives (nparray, nx1 or nx10). conf: Objectness value from 0-1 (nparray). pred_cls: Predicted object classes (nparray). @@ -95,12 +93,8 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir=".", names def compute_ap(recall, precision): - """Compute the average precision, given the recall and precision curves - # Arguments - recall: The recall curve (list) - precision: The precision curve (list) - # Returns - Average precision, precision curve, recall curve. + """Compute the average precision, given the recall and precision curves # Arguments recall: The recall curve (list) + precision: The precision curve (list) # Returns Average precision, precision curve, recall curve. """ # Append sentinel values to beginning and end mrec = np.concatenate(([0.0], recall, [1.0])) @@ -132,14 +126,13 @@ def __init__(self, nc, conf=0.25, iou_thres=0.45): self.iou_thres = iou_thres def process_batch(self, detections, labels): - """ - Return intersection-over-union (Jaccard index) of boxes. + """Return intersection-over-union (Jaccard index) of boxes. Both sets of boxes are expected to be in (x1, y1, x2, y2) format. - Arguments: - detections (Array[N, 6]), x1, y1, x2, y2, conf, class - labels (Array[M, 5]), class, x1, y1, x2, y2 + Args: + detections (Array[N, 6]), x1, y1, x2, y2, conf, class: labels (Array[M, 5]), class, x1, y1, x2, y2 + Returns: None, updates confusion matrix accordingly """ @@ -268,18 +261,15 @@ def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7 def box_iou(box1, box2, eps=1e-7): # https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py - """ - Return intersection-over-union (Jaccard index) of boxes. + """Return intersection-over-union (Jaccard index) of boxes. Both sets of boxes are expected to be in (x1, y1, x2, y2) format. - Arguments: - box1 (Tensor[N, 4]) - box2 (Tensor[M, 4]) + Args: + box1 (Tensor[N, 4]): box2 (Tensor[M, 4]) Returns: - iou (Tensor[N, M]): the NxM matrix containing the pairwise - IoU values for every element in boxes1 and boxes2 + iou (Tensor[N, M]): the NxM matrix containing the pairwise IoU values for every element in boxes1 and boxes2 """ # inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2) (a1, a2), (b1, b2) = box1.unsqueeze(1).chunk(2, 2), box2.unsqueeze(0).chunk(2, 2) @@ -290,13 +280,9 @@ def box_iou(box1, box2, eps=1e-7): def bbox_ioa(box1, box2, eps=1e-7): - """ - Returns the intersection over box2 area given box1, box2. + """Returns the intersection over box2 area given box1, box2. - Boxes are x1y1x2y2 - box1: np.array of shape(4) - box2: np.array of shape(nx4) - returns: np.array of shape(n) + Boxes are x1y1x2y2 box1: np.array of shape(4) box2: np.array of shape(nx4) returns: np.array of shape(n) """ # Get the coordinates of bounding boxes b1_x1, b1_y1, b1_x2, b1_y2 = box1 diff --git a/utils/plots.py b/utils/plots.py index 89817508e6..7d75c9be22 100644 --- a/utils/plots.py +++ b/utils/plots.py @@ -73,12 +73,8 @@ def hex2rgb(h): # rgb order (PIL) def feature_visualization(x, module_type, stage, n=32, save_dir=Path("runs/detect/exp")): - """ - x: Features to be visualized - module_type: Module type - stage: Module stage within model - n: Maximum number of feature maps to plot - save_dir: Directory to save results. + """x: Features to be visualized module_type: Module type stage: Module stage within model n: Maximum number of + feature maps to plot save_dir: Directory to save results. """ if "Detect" not in module_type: _batch, channels, height, width = x.shape # batch, channels, height, width @@ -110,8 +106,7 @@ def hist2d(x, y, n=100): def butter_lowpass_filtfilt(data, cutoff=1500, fs=50000, order=5): - """ - Applies a low-pass Butterworth filter using forward-backward method. + """Applies a low-pass Butterworth filter using forward-backward method. See: https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy """ @@ -119,7 +114,9 @@ def butter_lowpass_filtfilt(data, cutoff=1500, fs=50000, order=5): # https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy def butter_lowpass(cutoff, fs, order): - """Applies a low-pass Butterworth filter to input data using forward-backward method; see https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy.""" + """Applies a low-pass Butterworth filter to input data using forward-backward method; see + https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy. + """ nyq = 0.5 * fs normal_cutoff = cutoff / nyq return butter(order, normal_cutoff, btype="low", analog=False) diff --git a/utils/segment/dataloaders.py b/utils/segment/dataloaders.py index ee4ed6c49f..b3ef0baaf2 100644 --- a/utils/segment/dataloaders.py +++ b/utils/segment/dataloaders.py @@ -304,8 +304,7 @@ def polygon2mask(img_size, polygons, color=1, downsample_ratio=1): """ Args: img_size (tuple): The image size. - polygons (np.ndarray): [N, M], N is the number of polygons, - M is the number of points(Be divided by 2). + polygons (np.ndarray): [N, M], N is the number of polygons, M is the number of points(Be divided by 2). """ mask = np.zeros(img_size, dtype=np.uint8) polygons = np.asarray(polygons) @@ -324,9 +323,8 @@ def polygons2masks(img_size, polygons, color, downsample_ratio=1): """ Args: img_size (tuple): The image size. - polygons (list[np.ndarray]): each polygon is [N, M], - N is the number of polygons, - M is the number of points(Be divided by 2). + polygons (list[np.ndarray]): each polygon is [N, M], N is the number of polygons, M is the number of points(Be + divided by 2). """ masks = [] for si in range(len(polygons)): diff --git a/utils/segment/general.py b/utils/segment/general.py index ac90bffe0a..4774d7b65e 100644 --- a/utils/segment/general.py +++ b/utils/segment/general.py @@ -7,8 +7,7 @@ def crop_mask(masks, boxes): - """ - "Crop" predicted masks by zeroing out everything not in the predicted bbox. Vectorized by Chong (thanks Chong). + """"Crop" predicted masks by zeroing out everything not in the predicted bbox. Vectorized by Chong (thanks Chong). Args: - masks should be a size [n, h, w] tensor of masks @@ -23,12 +22,8 @@ def crop_mask(masks, boxes): def process_mask_upsample(protos, masks_in, bboxes, shape): - """ - Crop after upsample. - protos: [mask_dim, mask_h, mask_w] - masks_in: [n, mask_dim], n is number of masks after nms - bboxes: [n, 4], n is number of masks after nms - shape: input_image_size, (h, w). + """Crop after upsample. protos: [mask_dim, mask_h, mask_w] masks_in: [n, mask_dim], n is number of masks after nms + bboxes: [n, 4], n is number of masks after nms shape: input_image_size, (h, w). return: h, w, n """ @@ -40,12 +35,8 @@ def process_mask_upsample(protos, masks_in, bboxes, shape): def process_mask(protos, masks_in, bboxes, shape, upsample=False): - """ - Crop before upsample. - proto_out: [mask_dim, mask_h, mask_w] - out_masks: [n, mask_dim], n is number of masks after nms - bboxes: [n, 4], n is number of masks after nms - shape:input_image_size, (h, w). + """Crop before upsample. proto_out: [mask_dim, mask_h, mask_w] out_masks: [n, mask_dim], n is number of masks after + nms bboxes: [n, 4], n is number of masks after nms shape:input_image_size, (h, w). return: h, w, n """ @@ -66,12 +57,8 @@ def process_mask(protos, masks_in, bboxes, shape, upsample=False): def process_mask_native(protos, masks_in, bboxes, shape): - """ - Crop after upsample. - protos: [mask_dim, mask_h, mask_w] - masks_in: [n, mask_dim], n is number of masks after nms - bboxes: [n, 4], n is number of masks after nms - shape: input_image_size, (h, w). + """Crop after upsample. protos: [mask_dim, mask_h, mask_w] masks_in: [n, mask_dim], n is number of masks after nms + bboxes: [n, 4], n is number of masks after nms shape: input_image_size, (h, w). return: h, w, n """ @@ -89,11 +76,7 @@ def process_mask_native(protos, masks_in, bboxes, shape): def scale_image(im1_shape, masks, im0_shape, ratio_pad=None): - """ - img1_shape: model input shape, [h, w] - img0_shape: origin pic shape, [h, w, 3] - masks: [h, w, num]. - """ + """Img1_shape: model input shape, [h, w] img0_shape: origin pic shape, [h, w, 3] masks: [h, w, num].""" # Rescale coordinates (xyxy) from im1_shape to im0_shape if ratio_pad is None: # calculate from im0_shape gain = min(im1_shape[0] / im0_shape[0], im1_shape[1] / im0_shape[1]) # gain = old / new @@ -117,10 +100,8 @@ def scale_image(im1_shape, masks, im0_shape, ratio_pad=None): def mask_iou(mask1, mask2, eps=1e-7): - """ - mask1: [N, n] m1 means number of predicted objects - mask2: [M, n] m2 means number of gt objects - Note: n means image_w x image_h. + """mask1: [N, n] m1 means number of predicted objects mask2: [M, n] m2 means number of gt objects Note: n means + image_w x image_h. return: masks iou, [N, M] """ @@ -130,10 +111,8 @@ def mask_iou(mask1, mask2, eps=1e-7): def masks_iou(mask1, mask2, eps=1e-7): - """ - mask1: [N, n] m1 means number of predicted objects - mask2: [N, n] m2 means number of gt objects - Note: n means image_w x image_h. + """mask1: [N, n] m1 means number of predicted objects mask2: [N, n] m2 means number of gt objects Note: n means + image_w x image_h. return: masks iou, (N, ) """ diff --git a/utils/segment/loss.py b/utils/segment/loss.py index 3bb4a6f48c..657ac15005 100644 --- a/utils/segment/loss.py +++ b/utils/segment/loss.py @@ -115,8 +115,7 @@ def __call__(self, preds, targets, masks): # predictions, targets, model return loss * bs, torch.cat((lbox, lseg, lobj, lcls)).detach() def single_mask_loss(self, gt_mask, pred, proto, xyxy, area): - """ - Computes single image mask loss using BCE, cropping based on bbox. + """Computes single image mask loss using BCE, cropping based on bbox. Args: gt_mask[n,h,w], pred[n,nm], proto[nm,h,w], xyxy[n,4], area[n]. """ @@ -125,8 +124,7 @@ def single_mask_loss(self, gt_mask, pred, proto, xyxy, area): return (crop_mask(loss, xyxy).mean(dim=(1, 2)) / area).mean() def build_targets(self, p, targets): - """Prepares targets for loss computation by appending anchor indices; supports optional target overlap - handling. + """Prepares targets for loss computation by appending anchor indices; supports optional target overlap handling. """ na, nt = self.na, targets.shape[0] # number of anchors, targets tcls, tbox, indices, anch, tidxs, xywhn = [], [], [], [], [], [] diff --git a/utils/segment/metrics.py b/utils/segment/metrics.py index 3ff6c6a58c..efc109ba03 100644 --- a/utils/segment/metrics.py +++ b/utils/segment/metrics.py @@ -66,58 +66,54 @@ def __init__(self) -> None: @property def ap50(self): - """ - AP@0.5 of all classes. + """AP@0.5 of all classes. - Return: + Returns: (nc, ) or []. """ return self.all_ap[:, 0] if len(self.all_ap) else [] @property def ap(self): - """AP@0.5:0.95 - Return: + """AP@0.5:0.95. + + Returns: (nc, ) or []. """ return self.all_ap.mean(1) if len(self.all_ap) else [] @property def mp(self): - """ - Mean precision of all classes. + """Mean precision of all classes. - Return: + Returns: float. """ return self.p.mean() if len(self.p) else 0.0 @property def mr(self): - """ - Mean recall of all classes. + """Mean recall of all classes. - Return: + Returns: float. """ return self.r.mean() if len(self.r) else 0.0 @property def map50(self): - """ - Mean AP@0.5 of all classes. + """Mean AP@0.5 of all classes. - Return: + Returns: float. """ return self.all_ap[:, 0].mean() if len(self.all_ap) else 0.0 @property def map(self): - """ - Mean AP@0.5:0.95 of all classes. + """Mean AP@0.5:0.95 of all classes. - Return: + Returns: float. """ return self.all_ap.mean() if len(self.all_ap) else 0.0 diff --git a/utils/segment/plots.py b/utils/segment/plots.py index d2e4928f96..bbaef3caae 100644 --- a/utils/segment/plots.py +++ b/utils/segment/plots.py @@ -113,8 +113,7 @@ def plot_images_and_masks(images, targets, masks, paths=None, fname="images.jpg" def plot_results_with_masks(file="path/to/results.csv", dir="", best=True): - """Plots training results from CSV, highlighting best/last metrics; supports custom file paths and directory - saving. + """Plots training results from CSV, highlighting best/last metrics; supports custom file paths and directory saving. """ save_dir = Path(file).parent if file else Path(dir) fig, ax = plt.subplots(2, 8, figsize=(18, 6), tight_layout=True) diff --git a/utils/torch_utils.py b/utils/torch_utils.py index c7575f11ee..266afde674 100644 --- a/utils/torch_utils.py +++ b/utils/torch_utils.py @@ -55,8 +55,7 @@ def smartCrossEntropyLoss(label_smoothing=0.0): def smart_DDP(model): - """ - Initializes DDP for a model with version checks; fails for torch==1.12.0 due to known issues. + """Initializes DDP for a model with version checks; fails for torch==1.12.0 due to known issues. See https://github.com/ultralytics/yolov5/issues/8395. """ @@ -160,8 +159,9 @@ def time_sync(): def profile(input, ops, n=10, device=None): - """YOLOv3 speed/memory/FLOPs profiler - Usage: + """YOLOv3 speed/memory/FLOPs profiler. + + Examples: input = torch.randn(16, 3, 640, 640) m1 = lambda x: x * torch.sigmoid(x) m2 = nn.SiLU() @@ -243,8 +243,7 @@ def find_modules(model, mclass=nn.Conv2d): def sparsity(model): - """Calculates and returns the global sparsity of a model as the ratio of zero-valued parameters to total - parameters. + """Calculates and returns the global sparsity of a model as the ratio of zero-valued parameters to total parameters. """ a, b = 0, 0 for p in model.parameters(): @@ -295,8 +294,7 @@ def fuse_conv_and_bn(conv, bn): def model_info(model, verbose=False, imgsz=640): - """ - Prints model layers, parameters, gradients, and GFLOPs if verbose; handles various `imgsz`. + """Prints model layers, parameters, gradients, and GFLOPs if verbose; handles various `imgsz`. Usage: model_info(model). """ @@ -382,8 +380,7 @@ def smart_optimizer(model, name="Adam", lr=0.001, momentum=0.9, decay=1e-5): def smart_hub_load(repo="ultralytics/yolov5", model="yolov5s", **kwargs): - """ - Loads YOLO model from Ultralytics repo with smart error handling, supports `force_reload` on failure. + """Loads YOLO model from Ultralytics repo with smart error handling, supports `force_reload` on failure. See https://github.com/ultralytics/yolov5 """ @@ -452,9 +449,9 @@ def __call__(self, epoch, fitness): class ModelEMA: - """Updated Exponential Moving Average (EMA) from https://github.com/rwightman/pytorch-image-models - Keeps a moving average of everything in the model state_dict (parameters and buffers) - For EMA details see https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage. + """Updated Exponential Moving Average (EMA) from https://github.com/rwightman/pytorch-image-models Keeps a moving + average of everything in the model state_dict (parameters and buffers) For EMA details + see https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage. """ def __init__(self, model, decay=0.9999, tau=2000, updates=0): diff --git a/utils/triton.py b/utils/triton.py index 5006f9f216..376ba4f881 100644 --- a/utils/triton.py +++ b/utils/triton.py @@ -9,18 +9,14 @@ class TritonRemoteModel: - """ - A wrapper over a model served by the Triton Inference Server. + """A wrapper over a model served by the Triton Inference Server. It can be configured to communicate over GRPC or HTTP. It accepts Torch Tensors as input and returns them as outputs. """ def __init__(self, url: str): - """ - Keyword Arguments: - url: Fully qualified address of the Triton server - for e.g. grpc://localhost:8000. - """ + """Keyword Arguments: url: Fully qualified address of the Triton server - for e.g. grpc://localhost:8000.""" parsed_url = urlparse(url) if parsed_url.scheme == "grpc": from tritonclient.grpc import InferenceServerClient, InferInput @@ -56,8 +52,7 @@ def runtime(self): return self.metadata.get("backend", self.metadata.get("platform")) def __call__(self, *args, **kwargs) -> torch.Tensor | tuple[torch.Tensor, ...]: - """ - Invokes the model. + """Invokes the model. Parameters can be provided via args or kwargs. args, if provided, are assumed to match the order of inputs of the model. kwargs are matched with the model input names. @@ -71,8 +66,7 @@ def __call__(self, *args, **kwargs) -> torch.Tensor | tuple[torch.Tensor, ...]: return result[0] if len(result) == 1 else result def _create_inputs(self, *args, **kwargs): - """Generates model inputs from args or kwargs, not allowing both; raises error if neither or both are - provided. + """Generates model inputs from args or kwargs, not allowing both; raises error if neither or both are provided. """ args_len, kwargs_len = len(args), len(kwargs) if not args_len and not kwargs_len: diff --git a/val.py b/val.py index e33a65816f..cbe70444df 100644 --- a/val.py +++ b/val.py @@ -62,11 +62,11 @@ def save_one_txt(predn, save_conf, shape, file): - """ - Saves detection results in a text format, including labels and optionally confidence scores. + """Saves detection results in a text format, including labels and optionally confidence scores. Args: - predn (torch.Tensor): A tensor containing normalized prediction results in the format (x1, y1, x2, y2, conf, cls). + predn (torch.Tensor): A tensor containing normalized prediction results in the format (x1, y1, x2, y2, conf, + cls). save_conf (bool): A flag indicating whether to save confidence scores. shape (tuple[int, int]): Original image shape in the format (height, width). file (str | Path): Path to the file where the results will be saved. @@ -74,7 +74,7 @@ def save_one_txt(predn, save_conf, shape, file): Returns: None - Example: + Examples: ```python from pathlib import Path import torch @@ -104,12 +104,11 @@ def save_one_txt(predn, save_conf, shape, file): def save_one_json(predn, jdict, path, class_map): - """ - Save detection results in JSON format containing image_id, category_id, bbox, and score per detection. + """Save detection results in JSON format containing image_id, category_id, bbox, and score per detection. Args: - predn (torch.Tensor): Normalized prediction tensor of shape (N, 6) where N is the number of detections. - Each detection should contain (x1, y1, x2, y2, confidence, class). + predn (torch.Tensor): Normalized prediction tensor of shape (N, 6) where N is the number of detections. Each + detection should contain (x1, y1, x2, y2, confidence, class). jdict (list): List to store the JSON serializable detections. path (Path): Path object representing the image file path. class_map (dict[int, int]): Dictionary mapping class indices to their respective category IDs. @@ -117,7 +116,7 @@ def save_one_json(predn, jdict, path, class_map): Returns: None - Example: + Examples: ```python predn = torch.tensor([[50, 30, 200, 150, 0.9, 0], [30, 20, 180, 150, 0.8, 1]]) jdict = [] @@ -146,23 +145,19 @@ def save_one_json(predn, jdict, path, class_map): def process_batch(detections, labels, iouv): - """ - Computes correct prediction matrix for detections against ground truth labels at various IoU thresholds. + """Computes correct prediction matrix for detections against ground truth labels at various IoU thresholds. Args: detections (np.ndarray): Array of detections with shape (N, 6), where each detection contains [x1, y1, x2, y2, confidence, class]. - labels (np.ndarray): Array of ground truth labels with shape (M, 5), where each label contains [class, x1, y1, x2, y2]. + labels (np.ndarray): Array of ground truth labels with shape (M, 5), where each label contains [class, x1, y1, + x2, y2]. iouv (np.ndarray): Array of IoU thresholds to use for evaluation. Returns: np.ndarray: Boolean array of shape (N, len(iouv)), indicating correct predictions at each IoU threshold. - Notes: - - This function compares detections and ground truth labels to establish matches based on IoU and class. - - It supports multiple IoU thresholds to evaluate prediction accuracy flexibly. - - Example: + Examples: ```python detections = np.array([[50, 50, 150, 150, 0.8, 0], [30, 30, 120, 120, 0.7, 1]]) @@ -172,6 +167,10 @@ def process_batch(detections, labels, iouv): correct = process_batch(detections, labels, iouv) ``` + + Notes: + - This function compares detections and ground truth labels to establish matches based on IoU and class. + - It supports multiple IoU thresholds to evaluate prediction accuracy flexibly. """ correct = np.zeros((detections.shape[0], iouv.shape[0])).astype(bool) iou = box_iou(labels[:, 1:], detections[:, :4]) @@ -220,8 +219,7 @@ def run( callbacks=Callbacks(), compute_loss=None, ): - """ - Validates a trained YOLO model on a dataset and saves detection results in specified formats. + """Validates a trained YOLO model on a dataset and saves detection results in specified formats. Args: data (str | dict): Path to the dataset configuration file (.yaml) or a dictionary containing the dataset paths. @@ -238,7 +236,8 @@ def run( augment (bool, optional): Whether to apply augmented inference. Default is False. verbose (bool, optional): Whether to output verbose information. Default is False. save_txt (bool, optional): Whether to save detection results in text format (*.txt). Default is False. - save_hybrid (bool, optional): Whether to save hybrid results (labels+predictions) in text format (*.txt). Default is False. + save_hybrid (bool, optional): Whether to save hybrid results (labels+predictions) in text format (*.txt). + Default is False. save_conf (bool, optional): Whether to save confidence scores in text format labels. Default is False. save_json (bool, optional): Whether to save detection results in COCO JSON format. Default is False. project (str | Path, optional): Directory path to save validation results. Default is ROOT / 'runs/val'. @@ -259,7 +258,7 @@ def run( - times (dict): Dictionary containing times for different parts of the pipeline (e.g., preprocessing, inference, NMS). - samples (torch.Tensor): Torch tensor containing validation samples. - Example: + Examples: ```python metrics, times, samples = run( data='data/coco.yaml', @@ -488,8 +487,7 @@ def run( def parse_opt(): - """ - Parses and returns command-line options for dataset paths, model parameters, and inference settings. + """Parses and returns command-line options for dataset paths, model parameters, and inference settings. Args: --data (str): Path to the dataset YAML file. Default is 'data/coco128.yaml'. @@ -506,7 +504,8 @@ def parse_opt(): --augment (bool): Apply test-time augmentation during inference. Default is False. --verbose (bool): Print mAP by class. Default is False. --save-txt (bool): Save detection results in '.txt' format. Default is False. - --save-hybrid (bool): Save hybrid results containing both label and prediction in '.txt' format. Default is False. + --save-hybrid (bool): Save hybrid results containing both label and prediction in '.txt' format. Default is + False. --save-conf (bool): Save confidence scores in the '--save-txt' labels. Default is False. --save-json (bool): Save detection results in COCO JSON format. Default is False. --project (str): Project directory to save results. Default is 'runs/val'. @@ -518,16 +517,16 @@ def parse_opt(): Returns: opt (argparse.Namespace): Parsed command-line options. - Notes: - - The function uses `argparse` to handle command-line options. - - It also modifies some options based on specific conditions, such as appending additional flags for saving - in JSON format and checking for the `coco.yaml` dataset. - - Example: + Examples: Use the following command to run validation with custom settings: ```python $ python val.py --weights yolov5s.pt --data coco128.yaml --img 640 ``` + + Notes: + - The function uses `argparse` to handle command-line options. + - It also modifies some options based on specific conditions, such as appending additional flags for saving + in JSON format and checking for the `coco.yaml` dataset. """ parser = argparse.ArgumentParser() parser.add_argument("--data", type=str, default=ROOT / "data/coco128.yaml", help="dataset.yaml path") @@ -561,20 +560,15 @@ def parse_opt(): def main(opt): - """ - Executes model tasks including training, validation, and speed or study benchmarks based on specified options. + """Executes model tasks including training, validation, and speed or study benchmarks based on specified options. Args: - opt (argparse.Namespace): Parsed command-line options for dataset paths, model parameters, and inference settings. + opt (argparse.Namespace): Parsed command-line options for dataset paths, model parameters, and inference + settings. Returns: None - Note: - This function orchestrates different tasks based on the user input provided through command-line arguments. It supports tasks - like `train`, `val`, `test`, `speed`, and `study`. Depending on the task, it validates the model on a dataset, performs speed - benchmarks, or runs mAP benchmarks. - Examples: To validate a trained YOLOv3 model: @@ -590,6 +584,11 @@ def main(opt): Links: For more information, visit the official repository: https://github.com/ultralytics/ultralytics + + Notes: + This function orchestrates different tasks based on the user input provided through command-line arguments. It supports tasks + like `train`, `val`, `test`, `speed`, and `study`. Depending on the task, it validates the model on a dataset, performs speed + benchmarks, or runs mAP benchmarks. """ check_requirements(ROOT / "requirements.txt", exclude=("tensorboard", "thop")) From 2c48b702c739f588742cda66fb5594c7e6172aed Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 9 Nov 2025 18:32:03 +0000 Subject: [PATCH 1181/1185] Change base image to PyTorch 2.8.0-cuda12.8 (#2360) Updated the base image to PyTorch 2.8.0 with CUDA 12.8. Signed-off-by: Glenn Jocher --- utils/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/docker/Dockerfile b/utils/docker/Dockerfile index 9cba96cee2..cccc71d129 100644 --- a/utils/docker/Dockerfile +++ b/utils/docker/Dockerfile @@ -4,7 +4,7 @@ # Image is CUDA-optimized for YOLOv5 single/multi-GPU training and inference # Start FROM PyTorch image https://hub.docker.com/r/pytorch/pytorch -FROM pytorch/pytorch:2.0.0-cuda11.7-cudnn8-runtime +FROM pytorch/pytorch:2.8.0-cuda12.8-cudnn9-runtime # Downloads to user config dir ADD https://ultralytics.com/assets/Arial.ttf https://ultralytics.com/assets/Arial.Unicode.ttf /root/.config/Ultralytics/ From bd5f2c2d801349b1e223cc2ee68231b54346ea5b Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Sun, 16 Nov 2025 17:53:20 +0100 Subject: [PATCH 1182/1185] Update Issue templates (#2361) * Update Issue templates * Auto-format by https://ultralytics.com/actions * Update .github/ISSUE_TEMPLATE/bug-report.yml Co-authored-by: Ultralytics Assistant <135830346+UltralyticsAssistant@users.noreply.github.com> Signed-off-by: Glenn Jocher --------- Signed-off-by: Glenn Jocher Co-authored-by: UltralyticsAssistant Co-authored-by: Ultralytics Assistant <135830346+UltralyticsAssistant@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/bug-report.yml | 54 +++++++++++----------- .github/ISSUE_TEMPLATE/config.yml | 13 ++++-- .github/ISSUE_TEMPLATE/feature-request.yml | 23 +++++---- .github/ISSUE_TEMPLATE/question.yml | 13 +++--- 4 files changed, 51 insertions(+), 52 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index aa23edc76c..34d2683ac6 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -1,40 +1,36 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license name: 🐛 Bug Report -# title: " " -description: Problems with YOLOv3 +description: "Problems with Ultralytics YOLOv3" labels: [bug, triage] +type: "bug" body: - type: markdown attributes: value: | - Thank you for submitting a YOLOv3 🐛 Bug Report! + Thank you for submitting an Ultralytics YOLOv3 🐛 Bug Report! - type: checkboxes attributes: label: Search before asking description: > - Please search the [issues](https://github.com/ultralytics/yolov3/issues) to see if a similar bug report already exists. + Please search the Ultralytics YOLOv3 [README](https://github.com/ultralytics/yolov3#readme) and [issues](https://github.com/ultralytics/yolov3/issues) to see if a similar bug report already exists. options: - label: > - I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov3/issues) and found no similar bug report. + I have searched the [issues](https://github.com/ultralytics/yolov3/issues) and did not find a similar report. required: true - type: dropdown attributes: - label: YOLOv3 Component + label: Project area description: | - Please select the part of YOLOv3 where you found the bug. + Help us route the report to the right maintainers. multiple: true options: - "Training" - - "Validation" - - "Detection" - - "Export" - - "PyTorch Hub" - - "Multi-GPU" - - "Evolution" - - "Integrations" + - "Inference" + - "Export/deployment" + - "Documentation" - "Other" validations: required: false @@ -42,35 +38,37 @@ body: - type: textarea attributes: label: Bug - description: Provide console output with error messages and/or screenshots of the bug. + description: Please describe the issue in detail so we can reproduce it in Ultralytics YOLOv3. Include logs, screenshots, console output, and any context that helps explain the problem. placeholder: | - 💡 ProTip! Include as much information as possible (screenshots, logs, tracebacks etc.) to receive the most helpful response. + 💡 ProTip! Include as much information as possible (logs, tracebacks, screenshots, etc.) to receive the most helpful response. validations: required: true - type: textarea attributes: label: Environment - description: Please specify the software and hardware you used to produce the bug. + description: Share the platform and version information relevant to your report. placeholder: | - - YOLO: YOLOv3 🚀 v6.0-67-g60e42e1 torch 1.9.0+cu111 CUDA:0 (A100-SXM4-40GB, 40536MiB) - - OS: Ubuntu 20.04 - - Python: 3.9.0 + Please include: + - OS (e.g., Ubuntu 20.04, macOS 13.5, Windows 11) + - Language or framework version (Python, Swift, Flutter, etc.) + - Package or app version + - Hardware (e.g., CPU, GPU model, device model) + - Any other environment details validations: - required: false + required: true - type: textarea attributes: label: Minimal Reproducible Example description: > - When asking a question, people will be better able to provide help if you provide code that they can easily understand and use to **reproduce** the problem. - This is referred to by community members as creating a [minimal reproducible example](https://docs.ultralytics.com/help/minimum_reproducible_example/). + Provide the smallest possible snippet, command, or steps required to reproduce the issue. This helps us pinpoint problems faster. placeholder: | - ``` - # Code to reproduce your issue here + ```python + # Code or commands to reproduce your issue here ``` validations: - required: false + required: true - type: textarea attributes: @@ -81,7 +79,7 @@ body: attributes: label: Are you willing to submit a PR? description: > - (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. - See the YOLOv3 [Contributing Guide](https://docs.ultralytics.com/help/contributing/) to get started. + (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) to help improve Ultralytics YOLOv3, especially if you know how to fix the issue. + See the Ultralytics [Contributing Guide](https://docs.ultralytics.com/help/contributing/) to get started. options: - label: Yes I'd like to help by submitting a PR! diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 7d8d1fa5f4..6abf9d02a6 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,12 +2,15 @@ blank_issues_enabled: true contact_links: - - name: 📄 Docs - url: https://docs.ultralytics.com/ - about: View Ultralytics YOLOv3 Docs + - name: 📘 YOLOv3 README + url: https://github.com/ultralytics/yolov3#readme + about: Usage guide and background for YOLOv3 - name: 💬 Forum url: https://community.ultralytics.com/ - about: Ask on Ultralytics Community Forum + about: Ask the Ultralytics community for workflow help - name: 🎧 Discord url: https://ultralytics.com/discord - about: Ask on Ultralytics Discord + about: Chat with the Ultralytics team and other builders + - name: ⌨️ Reddit + url: https://reddit.com/r/ultralytics + about: Discuss Ultralytics projects on Reddit diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index 164e49e459..1cd29f6a96 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -1,41 +1,40 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license name: 🚀 Feature Request -description: Suggest a YOLOv3 idea -# title: " " +description: "Suggest an Ultralytics YOLOv3 improvement" labels: [enhancement] +type: "feature" body: - type: markdown attributes: value: | - Thank you for submitting a YOLOv3 🚀 Feature Request! + Thank you for submitting an Ultralytics YOLOv3 🚀 Feature Request! - type: checkboxes attributes: label: Search before asking description: > - Please search the [issues](https://github.com/ultralytics/yolov3/issues) to see if a similar feature request already exists. + Please search the Ultralytics YOLOv3 [README](https://github.com/ultralytics/yolov3#readme) and [issues](https://github.com/ultralytics/yolov3/issues) to see if a similar feature request already exists. options: - label: > - I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov3/issues) and found no similar feature requests. + I have searched https://github.com/ultralytics/yolov3/issues and did not find a similar request. required: true - type: textarea attributes: label: Description - description: A short description of your feature. + description: Briefly describe the feature you would like to see added to Ultralytics YOLOv3. placeholder: | - What new feature would you like to see in YOLOv3? + What new capability or improvement are you proposing? validations: required: true - type: textarea attributes: label: Use case - description: | - Describe the use case of your feature request. It will help us understand and prioritize the feature request. + description: Explain how this feature would be used and who benefits from it. Screenshots or mockups are welcome. placeholder: | - How would this feature be used, and who would use it? + How would this feature improve your workflow? - type: textarea attributes: @@ -46,7 +45,7 @@ body: attributes: label: Are you willing to submit a PR? description: > - (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) (PR) to help improve YOLOv3 for everyone, especially if you have a good understanding of how to implement a fix or feature. - See the YOLOv3 [Contributing Guide](https://docs.ultralytics.com/help/contributing/) to get started. + (Optional) We encourage you to submit a [Pull Request](https://github.com/ultralytics/yolov3/pulls) to help improve Ultralytics YOLOv3. + See the Ultralytics [Contributing Guide](https://docs.ultralytics.com/help/contributing/) to get started. options: - label: Yes I'd like to help by submitting a PR! diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml index 2cccf8c4c1..dd4dfff6bd 100644 --- a/.github/ISSUE_TEMPLATE/question.yml +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -1,31 +1,30 @@ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license name: ❓ Question -description: Ask a YOLOv3 question -# title: " " +description: "Ask an Ultralytics YOLOv3 question" labels: [question] body: - type: markdown attributes: value: | - Thank you for asking a YOLOv3 ❓ Question! + Thank you for asking an Ultralytics YOLOv3 ❓ Question! - type: checkboxes attributes: label: Search before asking description: > - Please search the [issues](https://github.com/ultralytics/yolov3/issues) and [discussions](https://github.com/ultralytics/yolov3/discussions) to see if a similar question already exists. + Please search the Ultralytics YOLOv3 [README](https://github.com/ultralytics/yolov3#readme), [issues](https://github.com/ultralytics/yolov3/issues), and [Ultralytics discussions](https://github.com/orgs/ultralytics/discussions) to see if a similar question already exists. options: - label: > - I have searched the YOLOv3 [issues](https://github.com/ultralytics/yolov3/issues) and [discussions](https://github.com/ultralytics/yolov3/discussions) and found no similar questions. + I checked the docs, issues, and discussions and could not find an answer. required: true - type: textarea attributes: label: Question - description: What is your question? + description: What is your question? Provide as much detail as possible so we can assist with Ultralytics YOLOv3. Include code snippets, screenshots, logs, or links to notebooks/demos. placeholder: | - 💡 ProTip! Include as much information as possible (screenshots, logs, tracebacks etc.) to receive the most helpful response. + 💡 ProTip! Include as much information as possible (logs, tracebacks, screenshots, etc.) to receive the most helpful response. validations: required: true From d6ce365e46ae45d03c4afd156bf9408ab7133621 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 07:06:29 +0100 Subject: [PATCH 1183/1185] Bump actions/checkout from 5 to 6 in /.github/workflows (#2363) Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-testing.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/links.yml | 2 +- .github/workflows/merge-main-into-prs.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-testing.yml b/.github/workflows/ci-testing.yml index 32fdd9180d..1066941a88 100644 --- a/.github/workflows/ci-testing.yml +++ b/.github/workflows/ci-testing.yml @@ -38,7 +38,7 @@ jobs: model: yolov5n torch: "1.8.0" # min torch version CI https://pypi.org/project/torchvision/ steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 298d381b1f..29959c0887 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up QEMU uses: docker/setup-qemu-action@v3 diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 2b87ba6f43..3946f6b608 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -22,7 +22,7 @@ jobs: Links: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install lychee run: curl -sSfL "https://github.com/lycheeverse/lychee/releases/latest/download/lychee-x86_64-unknown-linux-gnu.tar.gz" | sudo tar xz -C /usr/local/bin diff --git a/.github/workflows/merge-main-into-prs.yml b/.github/workflows/merge-main-into-prs.yml index 22e551ce4a..095144be3f 100644 --- a/.github/workflows/merge-main-into-prs.yml +++ b/.github/workflows/merge-main-into-prs.yml @@ -20,7 +20,7 @@ jobs: pull-requests: write steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 - uses: actions/setup-python@v6 From 83804a1711a98e1b00776c5d342d016c8a297924 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 11:11:19 +0100 Subject: [PATCH 1184/1185] Bump pip from 25.2 to 25.3 in /utils/google_app_engine in the pip group across 1 directory (#2364) Bump pip in /utils/google_app_engine in the pip group across 1 directory Bumps the pip group with 1 update in the /utils/google_app_engine directory: [pip](https://github.com/pypa/pip). Updates `pip` from 25.2 to 25.3 - [Changelog](https://github.com/pypa/pip/blob/main/NEWS.rst) - [Commits](https://github.com/pypa/pip/compare/25.2...25.3) --- updated-dependencies: - dependency-name: pip dependency-version: '25.3' dependency-type: direct:production dependency-group: pip ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- utils/google_app_engine/additional_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/google_app_engine/additional_requirements.txt b/utils/google_app_engine/additional_requirements.txt index e86bac0a17..e3df3992df 100644 --- a/utils/google_app_engine/additional_requirements.txt +++ b/utils/google_app_engine/additional_requirements.txt @@ -1,5 +1,5 @@ # add these requirements in your app on top of the existing ones -pip==25.2 +pip==25.3 Flask==2.3.2 gunicorn==23.0.0 werkzeug>=3.0.1 # not directly required, pinned by Snyk to avoid a vulnerability From 5eeb19820110ec6b830a3e0eef364ac25490f857 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 19 Jan 2026 12:40:20 +0000 Subject: [PATCH 1185/1185] Fix numpy trapz (#2369) * Fix numpy trapz * Fix numpy trapz --- utils/metrics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/metrics.py b/utils/metrics.py index 72b3072ac4..f7ea2ab57e 100644 --- a/utils/metrics.py +++ b/utils/metrics.py @@ -107,7 +107,7 @@ def compute_ap(recall, precision): method = "interp" # methods: 'continuous', 'interp' if method == "interp": x = np.linspace(0, 1, 101) # 101-point interp (COCO) - ap = np.trapz(np.interp(x, mrec, mpre), x) # integrate + ap = (np.trapezoid if hasattr(np, "trapezoid") else np.trapz)(np.interp(x, mrec, mpre), x) # integrate else: # 'continuous' i = np.where(mrec[1:] != mrec[:-1])[0] # points where x axis (recall) changes ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) # area under curve